[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#634829: libpam-mklocaluser: login fails when used in conjunction with sssd



Attached is a modified version of the python script which works for me. Essentially I have added some poll() calls to ensure the shell commands are completed before communicating with the subprocesses.
I have also added two lines in the runcmd subroutine to log any error messages to syslog. Hope that's OK with you.

I will now do further testing of this.

On 26/07/11 11:54, Petter Reinholdtsen wrote:
[Wolfgang Schulze-Zachau]
Would it be unfair to say we should take the route of least
resistance?
I have no problem with your proposed change, so why not.  Can you test
the new version currently available from

  svn://svn.debian.org/svn/debian-edu/trunk/src/libpam-mklocaluser

?

If it works for you, I'll upload it to unstable.

Happy hacking,

--
best regards

Wolfgang

Amino | Mob: +44 7554 457 455 | Desk: +44 1954 234 190 | skype: wszachauamino
#!/usr/bin/env python
#
# Create local user and redirected home directory.
# If the local user logging in have uid >= 1000, create primary group
# and user in /etc/passwd and /etc/group, and create a home directory
# under /home/ if none exist already.

import os
import sys
import pwd
import grp
import subprocess
import shutil
import math
import time
import syslog

def runcmd(pamh, cmd):
  proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,)
  while proc.poll() == None:
    pass
  result = proc.communicate(input=None)[0]
  if result != 0:
    syslog.syslog("Command %(command)s failed with %(msg)s" % ( cmd, proc.stderr.read()) ) 
#  print "output: %s" % output

def check_and_create_localuser(pamh, user):
  # Location of local users
  topdir = "/home"

  # Ignore users with uid below this one
  minimum_uid = 500

  # Create user entries with this shell
  shell = '/bin/bash'

  # File mode of new home directory
  dirmode = 0700

  # Last password change, use today
  pwlastchange = math.floor(time.time() / (60 * 60 * 24 ))

  pwminage = 0
  pwmaxage = 99999
  pwwarn = 7

  # Fetch current user and group info, possibly from LDAP or NIS.
  userinfo = pwd.getpwnam(user)
  uid = userinfo[2]
  gid = userinfo[3]
  gecos = userinfo[4]
  homedir =  userinfo[5]

  # Ignore users with uid < 1000
  if userinfo[2] < minimum_uid:
    return pamh.PAM_SUCCESS

  # Ignore users with existing entry in /etc/passwd
  cmd = "/bin/grep \"^%s:\" /etc/passwd >/dev/null" % user
  proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, )
  while proc.poll() == None:
    pass
  result = proc.communicate(input=None)[0]
  if proc.returncode == 0:
    return pamh.PAM_SUCCESS
  if None == homedir:
    syslog.syslog("Home directory is not set for user %s" % user)
    return pamh.PAM_USER_UNKNOWN

  newhomedir = os.path.join(topdir, user)
  if not os.path.isdir(homedir) and not os.path.isdir(newhomedir):
    try:
      groupinfo = grp.getgrgid(gid)
      groupname = groupinfo[0]
    except KeyError, e:
      syslog.syslog("Unknown primary group with gid %d" % gid)
      groupname = "[unknown]"

    syslog.syslog("Creating local passwd entry uid=%d(%s) gid=%d(%s) gecos='%s' home=%s" % (uid, user, gid, groupname, gecos, newhomedir))
    try:
      # Add user entry with overridden home directory in /etc/passwd.

      # Can not use adduser, as it refuses to add a user if it already
      # is visible via NSS.
      cmd = "/bin/echo '%s:x:%d:%d:%s:%s:%s' >> /etc/passwd" \
            % (user, uid, gid, gecos, newhomedir, shell)
      runcmd(pamh, cmd)

      # Add shadow entry too.
      # XXX Should only add it if it is missing
      cmd = "/bin/echo '%s:x:%d:%d:%d:%d:::' >> /etc/shadow" \
            % (user, pwlastchange, pwminage, pwmaxage, pwwarn)
      runcmd(pamh, cmd)

      syslog.syslog("Creating local home directory for user '%s'" % user)
      # Copy content of /etc/skel
      shutil.copytree("/etc/skel/.", newhomedir, True)

      # Change perm of new home dir
      os.chmod(newhomedir, dirmode)
      # os.chown(newhomedir, uid, gid) - not recursive
      runcmd(pamh, "/bin/chown -R %d:%d '%s'" % (uid, gid, newhomedir))

      # Flush nscd cache to get rid of original user entry
      if os.access("/usr/sbin/nscd", os.X_OK):
        runcmd(pamh, "/usr/sbin/nscd -i passwd")

      # Hook for adjusting the freshly created home directory
      # XXX Should be rewritten in python, I guess
      runcmd(pamh, "if [ -d /etc/mklocaluser.d ]; then ORIGHOMEDIR='%s' USER='%s' /bin/run-parts /etc/mklocaluser.d ; fi" % (homedir, user))

      # Let the user know what is going on
      msg = pamh.Message(pamh.PAM_TEXT_INFO,
                         "Local user created in /home/, please log in again to start using it.")
      pamh.conversation(msg)

      # Throw out user, as the log process cached the home directory
      # and need to be restarted.
      return pamh.PAM_TRY_AGAIN
    except Exception, e:
      syslog.syslog(e)
      pass

  return pamh.PAM_SUCCESS

def pam_sm_setcred(pamh, flags, argv):
  return pamh.PAM_SUCCESS

def pam_sm_authenticate(pamh, flags, argv):
  return pamh.PAM_SUCCESS

def pam_sm_acct_mgmt(pamh, flags, argv):
  return pamh.PAM_SUCCESS

def pam_sm_open_session(pamh, flags, argv):
  syslog.openlog("pam_mklocaluser", syslog.LOG_PID, syslog.LOG_AUTH)
  try:
    user = pamh.get_user(None)
  except pamh.exception, e:
    return e.pam_result
  if user == None:
    syslog.syslog("No user, ignoring pam-python for mklocaluser")
    return pamh.PAM_USER_UNKNOWN

  # Only create local users for console logins
  try:
    if pamh.rhost != None and 0 != len(pamh.rhost):
      syslog.syslog("Remote login, ignoring pam-python for mklocaluser")
      return pamh.PAM_SUCCESS
  except pamh.exception, e:
    return e.pam_result
    
  try:
    return check_and_create_localuser(pamh, user)
  except KeyError, e:
    syslog.syslog("Unknown username, should never happen: %s" % e)
    return pamh.PAM_USER_UNKNOWN
  except Exception, e:
    syslog.syslog("Unexpected exception, should never happen: %s" % e)
    return pamh.PAM_SYSTEM_ERR

def pam_sm_close_session(pamh, flags, argv):
  return pamh.PAM_SUCCESS

def pam_sm_chauthtok(pamh, flags, argv):
  return pamh.PAM_SUCCESS

# Test if the code work.  Argument is username to simulate login for.
if __name__ == '__main__':
  syslog.openlog("pam_mklocaluser", syslog.LOG_PID, syslog.LOG_AUTH)
  class pam_handler:
    PAM_SUCCESS = 1
    PAM_USER_UNKNOWN = 2
    PAM_SYSTEM_ERR = 3
    PAM_TRY_AGAIN = 4
    PAM_TEXT_INFO = 5
    def Message(tag, str):
      return
    def conversation(msg):
      return
  pamh = pam_handler()
  user = sys.argv[1]
  check_and_create_localuser(pamh, user)

Reply to: