|
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)
|