Blame pynslcd/usermod.py

Packit 6bd9ab
Packit 6bd9ab
# usermod.py - functions for modifying user information
Packit 6bd9ab
#
Packit 6bd9ab
# Copyright (C) 2013 Arthur de Jong
Packit 6bd9ab
#
Packit 6bd9ab
# This library is free software; you can redistribute it and/or
Packit 6bd9ab
# modify it under the terms of the GNU Lesser General Public
Packit 6bd9ab
# License as published by the Free Software Foundation; either
Packit 6bd9ab
# version 2.1 of the License, or (at your option) any later version.
Packit 6bd9ab
#
Packit 6bd9ab
# This library is distributed in the hope that it will be useful,
Packit 6bd9ab
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6bd9ab
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6bd9ab
# Lesser General Public License for more details.
Packit 6bd9ab
#
Packit 6bd9ab
# You should have received a copy of the GNU Lesser General Public
Packit 6bd9ab
# License along with this library; if not, write to the Free Software
Packit 6bd9ab
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit 6bd9ab
# 02110-1301 USA
Packit 6bd9ab
Packit 6bd9ab
import ctypes
Packit 6bd9ab
import ctypes.util
Packit 6bd9ab
import logging
Packit 6bd9ab
import os
Packit 6bd9ab
import os.path
Packit 6bd9ab
Packit 6bd9ab
import ldap
Packit 6bd9ab
Packit 6bd9ab
import cfg
Packit 6bd9ab
import constants
Packit 6bd9ab
import pam
Packit 6bd9ab
import passwd
Packit 6bd9ab
Packit 6bd9ab
Packit 6bd9ab
def list_shells():
Packit 6bd9ab
    """List the shells from /etc/shells."""
Packit 6bd9ab
    libc = ctypes.CDLL(ctypes.util.find_library("c"))
Packit 6bd9ab
    libc.setusershell()
Packit 6bd9ab
    while True:
Packit 6bd9ab
        shell = ctypes.c_char_p(libc.getusershell()).value
Packit 6bd9ab
        if not shell:
Packit 6bd9ab
            break
Packit 6bd9ab
        yield shell
Packit 6bd9ab
    libc.endusershell()
Packit 6bd9ab
Packit 6bd9ab
Packit 6bd9ab
class UserModRequest(pam.PAMRequest):
Packit 6bd9ab
Packit 6bd9ab
    action = constants.NSLCD_ACTION_USERMOD
Packit 6bd9ab
Packit 6bd9ab
    def read_parameters(self, fp):
Packit 6bd9ab
        username = fp.read_string()
Packit 6bd9ab
        asroot = fp.read_int32()
Packit 6bd9ab
        password = fp.read_string()
Packit 6bd9ab
        mods = {}
Packit 6bd9ab
        while True:
Packit 6bd9ab
            key = fp.read_int32()
Packit 6bd9ab
            if key == constants.NSLCD_USERMOD_END:
Packit 6bd9ab
                break
Packit 6bd9ab
            mods[key] = fp.read_string()
Packit 6bd9ab
        return dict(username=username,
Packit 6bd9ab
                    asroot=asroot,
Packit 6bd9ab
                    password=password,
Packit 6bd9ab
                    mods=mods)
Packit 6bd9ab
Packit 6bd9ab
    def write_result(self, mod, message):
Packit 6bd9ab
        self.fp.write_int32(mod)
Packit 6bd9ab
        self.fp.write_string(message)
Packit 6bd9ab
Packit 6bd9ab
    def handle_request(self, parameters):
Packit 6bd9ab
        # fill in any missing userdn, etc.
Packit 6bd9ab
        self.validate(parameters)
Packit 6bd9ab
        is_root = (self.calleruid == 0) and parameters['asroot']
Packit 6bd9ab
        mods = []
Packit 6bd9ab
        # check if the the user passed the rootpwmoddn
Packit 6bd9ab
        if parameters['asroot']:
Packit 6bd9ab
            binddn = cfg.rootpwmoddn
Packit 6bd9ab
            # check if rootpwmodpw should be used
Packit 6bd9ab
            if not parameters['password'] and is_root and cfg.rootpwmodpw:
Packit 6bd9ab
                password = cfg.rootpwmodpw
Packit 6bd9ab
            else:
Packit 6bd9ab
                password = parameters['password']
Packit 6bd9ab
        else:
Packit 6bd9ab
            binddn = parameters['userdn']
Packit 6bd9ab
            password = parameters['password']
Packit 6bd9ab
        # write response header
Packit 6bd9ab
        self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
Packit 6bd9ab
        # check home directory modification
Packit 6bd9ab
        homedir = parameters['mods'].get(constants.NSLCD_USERMOD_HOMEDIR)
Packit 6bd9ab
        if homedir:
Packit 6bd9ab
            if is_root:
Packit 6bd9ab
                mods.append((ldap.MOD_REPLACE, passwd.attmap['homeDirectory'], [homedir]))
Packit 6bd9ab
            elif not os.path.isabs(homedir):
Packit 6bd9ab
                self.write_result(constants.NSLCD_USERMOD_HOMEDIR,
Packit 6bd9ab
                                  'should be an absolute path')
Packit 6bd9ab
            elif not os.path.isdir(homedir):
Packit 6bd9ab
                self.write_result(constants.NSLCD_USERMOD_HOMEDIR,
Packit 6bd9ab
                                  'not a directory')
Packit 6bd9ab
            else:
Packit 6bd9ab
                mods.append((ldap.MOD_REPLACE, passwd.attmap['homeDirectory'], [homedir]))
Packit 6bd9ab
        # check login shell modification
Packit 6bd9ab
        shell = parameters['mods'].get(constants.NSLCD_USERMOD_SHELL)
Packit 6bd9ab
        if shell:
Packit 6bd9ab
            if is_root:
Packit 6bd9ab
                mods.append((ldap.MOD_REPLACE, passwd.attmap['loginShell'], [shell]))
Packit 6bd9ab
            elif shell not in list_shells():
Packit 6bd9ab
                self.write_result(constants.NSLCD_USERMOD_SHELL,
Packit 6bd9ab
                                  'unlisted shell')
Packit 6bd9ab
            elif not os.path.isfile(shell) or not os.access(shell, os.X_OK):
Packit 6bd9ab
                self.write_result(constants.NSLCD_USERMOD_SHELL,
Packit 6bd9ab
                                  'not an executable')
Packit 6bd9ab
            else:
Packit 6bd9ab
                mods.append((ldap.MOD_REPLACE, passwd.attmap['loginShell'], [shell]))
Packit 6bd9ab
        # get a connection and perform the modification
Packit 6bd9ab
        if mods:
Packit 6bd9ab
            try:
Packit 6bd9ab
                conn, authz, msg = pam.authenticate(binddn, password)
Packit 6bd9ab
                conn.modify_s(parameters['userdn'], mods)
Packit 6bd9ab
                logging.info('changed information for %s', parameters['userdn'])
Packit 6bd9ab
            except (ldap.INVALID_CREDENTIALS, ldap.INSUFFICIENT_ACCESS), e:
Packit 6bd9ab
                try:
Packit 6bd9ab
                    msg = e[0]['desc']
Packit 6bd9ab
                except:
Packit 6bd9ab
                    msg = str(e)
Packit 6bd9ab
                logging.debug('modification failed: %s', msg)
Packit 6bd9ab
                self.write_result(constants.NSLCD_USERMOD_RESULT, msg)
Packit 6bd9ab
        # write closing statement
Packit 6bd9ab
        self.fp.write_int32(constants.NSLCD_USERMOD_END)
Packit 6bd9ab
        self.fp.write_int32(constants.NSLCD_RESULT_END)