pam-afs-new-features-20010907
authorCarsten Jacobi <jacobi@de.ibm.com>
Fri, 7 Sep 2001 05:36:41 +0000 (05:36 +0000)
committerDerrick Brashear <shadow@dementia.org>
Fri, 7 Sep 2001 05:36:41 +0000 (05:36 +0000)
add ignore_uid (like ignore_root) plus set_token (set token in auth step instead of setcred), refresh_token (no new pag), use_klog (fork a klog child), no_unlog, remainlifetime (sleep before deleting creds at logout)

doc/html/QuickStartUnix/auqbg007.htm
src/pam/afs_auth.c
src/pam/afs_message.c
src/pam/afs_message.h
src/pam/afs_password.c
src/pam/afs_session.c
src/pam/afs_setcred.c
src/pam/afs_util.c
src/pam/afs_util.h
src/pam/test_pam.c

index 1a6aef7..a1067da 100644 (file)
@@ -971,6 +971,7 @@ instructions specify the recommended and tested configuration.
 <P>The recommended AFS-related entries in the PAM configuration file make use
 of one or more of the following three attributes.
 <DL>
+<h4><br>Authentication Management</h4>
 <P><DT><B><TT>try_first_pass</TT>
 </B><DD>This is a standard PAM attribute that can be included on entries after the
 first one for a service; it directs the module to use the password that
@@ -979,83 +980,232 @@ authentication succeeds if the password provided to the module listed first is
 the user's correct AFS password. For further discussion of this
 attribute and its alternatives, see the operating system's PAM
 documentation.
+<P>
 <P><DT><B><TT>ignore_root</TT>
 </B><DD>This attribute, specific to the AFS PAM module, directs it to ignore not
 only the local superuser <B> root</B>, but also any user with UID 0
 (zero).
+<P><DT><B><TT>ignore_uid <i>uid</i></TT>
+</B><DD>This option is an extension of the &quot;ignore_root&quot; switch. The additional
+parameter is a limit. Users with a uid up to the given parameter are ignored
+by <i>pam_afs.so</i>. Thus, a system administrator still has the opportunity to
+add local user accounts to his system by choosing between &quot;low&quot; and
+&quot;high&quot; user ids.<br>
+An example /etc/passwd file for &quot;ignore_uid 100&quot; may have entries like these:
+<PRE>
+        .
+        .
+afsuserone:x:99:100::/afs/afscell/u/afsuserone:/bin/bash
+afsusertwo:x:100:100::/afs/afscell/u/afsusertwo:/bin/bash
+localuserone:x:101:100::/home/localuserone:/bin/bash
+localusertwo:x:102:100::/home/localusertwo:/bin/bash
+        .
+        .
+</PRE><br>
+AFS accounts should be locked in the file /etc/shadow like this:
+<PRE>
+        .
+        .
+afsuserone:!!:11500:0:99999:7:::
+afsusertwo:!!:11500:0:99999:7:::
+localuserone:&lt;thelocaluserone'skey&gt;:11500:0:99999:7:::
+localusertwo:&lt;thelocalusertwo'skey&gt;:11500:0:99999:7:::
+        .
+        .
+</PRE><br>
+There is no need to store a local key in this file since the AFS
+password is sent and verfied at the AFS cell server!
+
 <P><DT><B><TT>setenv_password_expires</TT>
 </B><DD>This attribute, specific to the AFS PAM module, sets the environment
 variable PASSWORD_EXPIRES to the expiration date of the user's AFS
 password, which is recorded in the Authentication Database.
+<P><DT><B><TT>set_token</TT>
+</B><DD>Some applications don't call <i>pam_setcred()</i> in order to retrieve the appropriate
+credentials (here the AFS token) for their session. This switch sets the credentials
+already in <i>pam_sm_authenticate()</i> obsoleting a call to <i>pam_setcred()</i>.<br>
+<b>Caution: Don't use this switch for applications which do call <i>pam_setcred()</i>!</b>
+One example for an application not calling <i>pam_setcred()</i> are older versions of
+the samba server.<br>
+Nevertheless, using applications with working pam session management is recommended as this
+setup conforms better with the PAM definitions.
+<P><DT><B><TT>refresh_token</TT>
+</B><DD>This options is identical to &quot;set_token&quot; except that no new PAG is generated.
+This is necessary to handle processes like xlock or xscreensaver. It is not enough to give
+the screen and the keyboard free for the user who reactivated his screen typing in the
+correct AFS password, but one may also need fresh tokens with full
+livetime in order to work on, and the new token must be refreshed in the already existing PAG
+for the processes that have been started. This is achieved using this option.
+<P><DT><B><TT>use_klog</TT>
+</B><DD>Activating this switch the authentication is done by calling the external program &quot;klog&quot;.
+One program requiring this is for example <i>kdm</i> of KDE 2.x.<br></DD>
+<P><DT><B><TT>dont_fork</TT>
+</B><DD>Usually, the password verification and the establishment of the token is performed
+in a sub process. Using this option pam_afs does not fork and performs all actions in a single
+process. <b>Only use this options in case you notice serious problems caused by the sub process.</b>
+This option has been developed in respect to the &quot;mod_auth_pam&quot;-project (see also
+<A HREF="http://pam.sourceforge.net/mod_auth_pam/">mod_auth_pam</A>). The mod_auth_pam
+module enables PAM authentication for the apache http server package.
+
+<h4><br>Session Management</h4>
+
+<P><DT><B><TT>no_unlog</TT>
+</B><DD>Normally the tokens are deleted (in memory) after the session ends. Using this options the tokens are left
+untouched. <b>This behaviour has been the default in pam_afs until openafs-1.1.1!</b>
+<P><DT><B><TT>remainlifetime <i>sec</i></TT>
+</B><DD>The tokens are kept active for <i>sec</i> seconds before they are deleted. X display managers
+i.e. are used to inform the applications started in the X session before the logout and then
+end themselves. If the token was deleted immediately the applications would have no chance to
+write back their settings to i.e. the user's AFS home space. This option may help to avoid the
+problem.<br>
+
 </DL>
 <P>Perform the following steps to enable AFS login.
 <OL TYPE=1>
 <P><LI>Mount the AFS CD-ROM for Linux on the <B>/cdrom</B> directory, if it
 is not already. Then change to the directory for PAM modules, which
-depends on which Linux distribution you are using. 
+depends on which Linux distribution you are using.
 <P>If you are using a Linux distribution from Red Hat Software:
-<PRE>   
-   # <B>cd /lib/security</B>   
-</PRE> 
+<PRE>
+   # <B>cd /lib/security</B>
+</PRE>
 <P>If you are using another Linux distribution:
-<PRE>   
+<PRE>
    # <B>cd /usr/lib/security</B>
-   
+
 </PRE>
 <P><LI>Copy the appropriate AFS authentication library file to the directory to
 which you changed in the previous step. Create a symbolic link whose
 name does not mention the version. Omitting the version eliminates the
 need to edit the PAM configuration file if you later update the library
-file. 
+file.
 <P>If you use the AFS Authentication Server (<B>kaserver</B>
 process):
-<PRE>   
+<PRE>
    # <B>cp /cdrom/i386_linux22/lib/pam_afs.so.1  .</B>
-   
-   # <B>ln -s pam_afs.so.1 pam_afs.so</B>   
-</PRE> 
+
+   # <B>ln -s pam_afs.so.1 pam_afs.so</B>
+</PRE>
 <P>If you use a Kerberos implementation of AFS authentication:
-<PRE>   
+<PRE>
    # <B>cp /cdrom/i386_linux22/lib/pam_afs.krb.so.1   .</B>
-   
+
    # <B>ln -s pam_afs.krb.so.1 pam_afs.so</B>
-   
+
 </PRE>
 <P><LI>For each service with which you want to use AFS authentication, insert an
 entry for the AFS PAM module into the <TT>auth</TT> section of the
 service's PAM configuration file. (Linux uses a separate
 configuration file for each service, unlike some other operating systems which
 list all services in a single file.) Mark the entry as
-<TT>sufficient</TT> in the second field. 
+<TT>sufficient</TT> in the second field.
 <P>Place the AFS entry below any entries that impose conditions under which
 you want the service to fail for a user who does not meet the entry's
 requirements. Mark these entries <TT>required</TT>. Place the
 AFS entry above any entries that need to execute only if AFS authentication
-fails. 
+fails.
 <P>Insert the following AFS entry if using the Red Hat distribution:
-<PRE>   
-   auth  sufficient  /lib/security/pam_afs.so   try_first_pass  ignore_root   
-</PRE> 
+<PRE>
+   auth  sufficient  /lib/security/pam_afs.so   try_first_pass  ignore_root
+</PRE>
 <P>Insert the following AFS entry if using another distribution:
-<PRE>   
-   auth  sufficient  /usr/lib/security/pam_afs.so  try_first_pass  ignore_root   
-</PRE> 
-<P>The following example illustrates the recommended configuration of the
-configuration file for the <B>login</B> service
-(<B>/etc/pam.d/login</B>) on a machine using the Red Hat
-distribution.
-<PRE>   
+<PRE>
+   auth  sufficient  /usr/lib/security/pam_afs.so  try_first_pass  ignore_root
+</PRE>
+<P>Check the PAM config files also for &quot;session&quot; entries. If there are
+lines beginning with &quot;session&quot; then please insert this line too:
+<PRE>
+   session  optional  /lib/security/pam_afs.so
+</PRE>
+<P>or
+<PRE>
+   session  optional  /usr/lib/security/pam_afs.so
+</PRE>
+<P>This guaranties that the user's tokens are deleted from memory after his
+session ends so that no other user coincidently gets those tokens without authorization!
+The following examples illustrate the recommended configuration of the
+configuration file for several services:<br>
+
+<h4><br>Authentication Management</h4>
+
+(<B>/etc/pam.d/login</B>)
+<PRE>
    #%PAM-1.0
    auth      required   /lib/security/pam_securetty.so
    auth      required   /lib/security/pam_nologin.so
    auth      sufficient /lib/security/pam_afs.so try_first_pass ignore_root
+   #                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   #This enables AFS authentication for every user but root
    auth      required   /lib/security/pam_pwdb.so shadow nullok
    account   required   /lib/security/pam_pwdb.so
    password  required   /lib/security/pam_cracklib.so
    password  required   /lib/security/pam_pwdb.so shadow nullok use_authtok
+   session   optional   /lib/security/pam_afs.so
+   #Make sure tokens are deleted after the user logs out
    session   required   /lib/security/pam_pwdb.so
-   
-</PRE>
+
+</PRE><br>
+(<b>/etc/pam.d/samba</b>)
+<PRE>
+   auth       required     /lib/security/pam_afs.so ignore_uid 100 set_token
+   #                                                ^^^^^^^^^^^^^^^^^^^^^^^^
+   #Here, users with uid&gt;100 are considered to belong to the AFS and users
+   #with uid&lt;=100 are ignored by pam_afs. The token is retrieved already in
+   #pam_sm_authenticate() (this is an example pam config for a samba version
+   #that does not call pam_setcred(), it also does no sense to include session
+   #entries here since they would be ignored by this version of samba ).
+   account    required     /lib/security/pam_pwdb.so
+</PRE>
+(<b>/etc/pam.d/xscreensaver</b>)
+<PRE>
+   auth       sufficient   /lib/security/pam_afs.so ignore_uid 100 refresh_token
+   #                                                               ^^^^^^^^^^^^^
+   #Avoid generating a new PAG for the new tokens, use the already existing PAG and
+   #establish a fresh token in it.
+   auth       required     /lib/security/pam_pwdb.so try_first_pass
+</PRE>
+(<b>/etc/pam.d/httpd</b>)
+<PRE>
+   auth       required   /lib/security/pam_afs.so ignore_uid 100 dont_fork
+   #                                                             ^^^^^^^^^
+   #Don't fork for the verification of the password.
+</PRE>
+
+<h4><br>Session Management</h4>
+
+(<b>/etc/pam.d/su</b>)
+<PRE>
+   auth       sufficient   /lib/security/pam_afs.so ignore_uid 100
+   auth       required     /lib/security/pam_pwdb.so try_first_pass
+   account    required     /lib/security/pam_pwdb.so
+   password   required     /lib/security/pam_cracklib.so
+   password   required     /lib/security/pam_pwdb.so use_authtok
+   session    required     /lib/security/pam_pwdb.so
+   session    optional     /lib/security/pam_afs.so no_unlog
+   #                                                ^^^^^^^^
+   #Don't delete the token in this case, since the user may still
+   #need it (for example if somebody logs in and changes to root
+   #afterwards he may still want to access his home space in AFS).
+   session    required     /lib/security/pam_login_access.so
+   session    optional     /lib/security/pam_xauth.so
+</PRE>
+(<b>/etc/pam.d/xdm</b>)
+<PRE>
+   auth       required     /lib/security/pam_nologin.so
+   auth       required     /lib/security/pam_login_access.so
+   auth       sufficient   /lib/security/pam_afs.so ignore_uid 100 use_klog
+   auth       required     /lib/security/pam_pwdb.so try_first_pass
+   account    required     /lib/security/pam_pwdb.so
+   password   required     /lib/security/pam_cracklib.so
+   password   required     /lib/security/pam_pwdb.so shadow nullok use_authtok
+   session    optional     /lib/security/pam_afs.so remainlifetime 10
+   #                                                ^^^^^^^^^^^^^^^^^
+   #Wait 10 seconds before deleting the AFS tokens in order to give
+   #the programs of the X session some time to save their settings
+   #to AFS.
+   session    required     /lib/security/pam_pwdb.so
+</PRE>
+
 <P><LI>Proceed to <A HREF="#HDRWQ145">Loading and Creating Client Files</A>.
 </OL>
 <A NAME="IDX2986"></A>
index b76022b..5ce0eef 100644 (file)
@@ -29,7 +29,6 @@ RCSID("$Header$");
 
 #define RET(x) { retcode = (x); goto out; }
 
-
 extern int
 pam_sm_authenticate(
        pam_handle_t    *pamh,
@@ -45,14 +44,24 @@ pam_sm_authenticate(
     int nowarn = 0;
     int use_first_pass = 0;
     int try_first_pass = 0;
-    int ignore_root = 0;
-    int trust_root = 0;
-    int catch_su = 0;
+    int ignore_uid  = 0;
+    uid_t ignore_uid_id = 0;
+    char my_password_buf[256];
+    /*
+     * these options are added to handle stupid apps, which won't call
+     * pam_set_cred()
+     */
+    int refresh_token = 0;
+    int set_token = 0;
+    int dont_fork = 0;
+    /* satisfy kdm 2.x
+     */
+    int use_klog = 0;
     int set_expires = 0;  /* This option is only used in pam_set_cred() */
     int got_authtok = 0;       /* got PAM_AUTHTOK upon entry */
     int nouser = 0;
-    char my_password_buf[256];
     char *user = NULL, *password = NULL;
+    long password_expires = -1;
     int torch_password = 1;
     int i;
     struct pam_conv *pam_convp = NULL;
@@ -67,7 +76,7 @@ pam_sm_authenticate(
 
 
 #ifndef AFS_SUN56_ENV
-    openlog(pam_afs_ident, LOG_CONS, LOG_AUTH);
+    openlog(pam_afs_ident, LOG_CONS|LOG_PID, LOG_AUTH);
 #endif
     origmask = setlogmask(logmask);
 
@@ -85,11 +94,31 @@ pam_sm_authenticate(
        } else if (strcasecmp(argv[i], "try_first_pass") == 0) {
            try_first_pass = 1;
        } else if (strcasecmp(argv[i], "ignore_root"   ) == 0) {
-           ignore_root = 1;
-       } else if (strcasecmp(argv[i], "trust_root"   ) == 0) {
-           trust_root = 1;
-       } else if (strcasecmp(argv[i], "catch_su"   ) == 0) {
-           catch_su = 1;
+           ignore_uid = 1;
+           ignore_uid_id = 0;
+        } else if (strcasecmp(argv[i], "ignore_uid"    ) == 0) {
+           i++;
+           if (i == argc) {
+                pam_afs_syslog(LOG_ERR, PAMAFS_IGNOREUID, "ignore_uid missing argument");
+               ignore_uid = 0;
+           } else {
+               ignore_uid = 1;
+               ignore_uid_id = (uid_t) strtol(argv[i], (char**)NULL, 10);
+               if ( (ignore_uid_id  < 0) || (ignore_uid_id > IGNORE_MAX)) {
+                       ignore_uid = 0;
+                       pam_afs_syslog(LOG_ERR, PAMAFS_IGNOREUID, argv[i]);
+                }
+           }
+       } else if (strcasecmp(argv[i], "refresh_token" ) == 0) {
+           refresh_token = 1;
+       } else if (strcasecmp(argv[i], "set_token" ) == 0) {
+           set_token = 1;
+       } else if (strcasecmp(argv[i], "dont_fork" ) == 0) {
+           if (!use_klog) dont_fork = 1;
+           else pam_afs_syslog(LOG_ERR, PAMAFS_CONFLICTOPT, "dont_fork");
+       } else if (strcasecmp(argv[i], "use_klog" ) == 0) {
+           if (!dont_fork) use_klog = 1;
+           else pam_afs_syslog(LOG_ERR, PAMAFS_CONFLICTOPT, "use_klog");
        } else if (strcasecmp(argv[i], "setenv_password_expires") == 0) {
             set_expires = 1;
        } else {
@@ -102,33 +131,33 @@ pam_sm_authenticate(
     /* so turn that flag off right now.                                  */
     if (use_first_pass) try_first_pass = 0;
 
-    pam_afs_syslog(LOG_DEBUG, PAMAFS_OPTIONS, nowarn, use_first_pass, try_first_pass);
+    if (logmask && LOG_MASK(LOG_DEBUG))
+           pam_afs_syslog(LOG_DEBUG, PAMAFS_OPTIONS, nowarn, use_first_pass, try_first_pass, ignore_uid, ignore_uid_id, refresh_token, set_token, dont_fork, use_klog);
 
     /* Try to get the user-interaction info, if available. */
-    errcode = pam_get_item(pamh, PAM_CONV, (void **) &pam_convp);
+    errcode = pam_get_item(pamh, PAM_CONV, (const void **) &pam_convp);
     if (errcode != PAM_SUCCESS) {
        pam_afs_syslog(LOG_WARNING, PAMAFS_NO_USER_INT);
        pam_convp = NULL;
     }
 
     /* Who are we trying to authenticate here? */
-    if ((errcode = pam_get_user(pamh, &user, "login: ")) != PAM_SUCCESS) {
+    if ((errcode = pam_get_user(pamh, (const char **)&user, "login: ")) != PAM_SUCCESS) {
        pam_afs_syslog(LOG_ERR, PAMAFS_NOUSER, errcode);
        RET(PAM_USER_UNKNOWN);
     }
 
-    if ((!strncmp ("root", user, 4)) && trust_root) {
-       pam_afs_syslog(LOG_INFO, PAMAFS_TRUSTROOT, user);
-       RET(PAM_SUCCESS);
-    }
-
-    pam_afs_syslog(LOG_DEBUG, PAMAFS_USERNAMEDEBUG, user);
+    if (logmask && LOG_MASK(LOG_DEBUG))
+           pam_afs_syslog(LOG_DEBUG, PAMAFS_USERNAMEDEBUG, user);
 
     /*
      * If the user has a "local" (or via nss, possibly nss_dce) pwent,
      * and its uid==0, and "ignore_root" was given in pam.conf,
      * ignore the user.
      */
+    /* enhanced: use "ignore_uid <number>" to specify the largest uid
+     * which should be ignored by this module
+     */
 #if    defined(AFS_HPUX_ENV)
 #if     defined(AFS_HPUX110_ENV)
     i = getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf), &upwd);
@@ -137,7 +166,7 @@ pam_sm_authenticate(
     if ( i == 0 )                      /* getpwnam_r success */
        upwd = &unix_pwd; 
 #endif  /* else AFS_HPUX110_ENV */
-    if (ignore_root && i == 0  && upwd->pw_uid == 0) {
+    if (ignore_uid && i == 0  && upwd->pw_uid <= ignore_uid_id) {
        pam_afs_syslog(LOG_INFO, PAMAFS_IGNORINGROOT, user);
        RET(PAM_AUTH_ERR);
     }
@@ -147,31 +176,28 @@ pam_sm_authenticate(
 #else
     upwd = getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf));
 #endif
-    if (upwd != NULL && upwd->pw_uid == 0) {
-       if (ignore_root) { 
-               pam_afs_syslog(LOG_INFO, PAMAFS_IGNORINGROOT, user);
-               RET(PAM_AUTH_ERR);
-       } else if (trust_root && !catch_su) {
-               pam_afs_syslog(LOG_INFO, PAMAFS_TRUSTROOT, user);
-               RET(PAM_SUCCESS);
-       }
+    if (ignore_uid && upwd != NULL && upwd->pw_uid <= ignore_uid_id) {
+       pam_afs_syslog(LOG_INFO, PAMAFS_IGNORINGROOT, user);
+       RET(PAM_AUTH_ERR);
     }
 #endif
-    errcode = pam_get_item(pamh, PAM_AUTHTOK, (void **) &password);
+    errcode = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &password);
     if (errcode != PAM_SUCCESS || password == NULL) {
        if (use_first_pass) {
            pam_afs_syslog(LOG_ERR, PAMAFS_PASSWD_REQ, user);
            RET(PAM_AUTH_ERR);
        }
        password = NULL;        /* In case it isn't already NULL */
-       pam_afs_syslog(LOG_DEBUG, PAMAFS_NOFIRSTPASS, user);
+       if (logmask && LOG_MASK(LOG_DEBUG))
+           pam_afs_syslog(LOG_DEBUG, PAMAFS_NOFIRSTPASS, user);
     } else if (password[0] == '\0') {
        /* Actually we *did* get one but it was empty. */
        torch_password = 0;
        pam_afs_syslog(LOG_INFO, PAMAFS_NILPASSWORD, user);
        RET(PAM_NEW_AUTHTOK_REQD);
     } else {
-       pam_afs_syslog(LOG_DEBUG, PAMAFS_GOTPASS, user);
+       if (logmask && LOG_MASK(LOG_DEBUG))
+           pam_afs_syslog(LOG_DEBUG, PAMAFS_GOTPASS, user);
        torch_password = 0;
        got_authtok = 1;
     }
@@ -211,15 +237,30 @@ try_auth:
          * this storage, copy it to a buffer that won't need to be freed
          * later, and free this storage now.
          */
+
         strncpy(my_password_buf, password, sizeof(my_password_buf));
         my_password_buf[sizeof(my_password_buf)-1] = '\0';
         memset(password, 0, strlen(password));
         free(password);
         password = my_password_buf;
 
+    }
 
+    /* Be sure to allocate a PAG here if we should set a token,
+     * All of the remaining stuff to authenticate the user and to
+     * get a token is done in a child process - if not suppressed by the config,
+     * see below
+     * But dont get a PAG if the refresh_token option was set
+     * We have to do this in such a way because some
+     * apps (such as screensavers) wont call setcred but authenticate :-(
+     */
+    if (!refresh_token) {
+       setpag();
+       if (logmask && LOG_MASK(LOG_DEBUG))
+        syslog(LOG_DEBUG, "New PAG created in pam_authenticate()");
     }
 
+    if (!dont_fork) {
     /* Prepare for fork(): set SIGCHLD signal handler to default */
     sigemptyset(&newAction.sa_mask);
     newAction.sa_handler   = SIG_DFL;
@@ -234,9 +275,35 @@ try_auth:
      * memory/sockets allocated will get cleaned up when the child
      * exits: defect 11686.
      */
+       if (use_klog) { /* used by kdm 2.x */
+          if (refresh_token || set_token) {
+             i = do_klog(user, password, NULL);
+          } else {
+             i = do_klog(user, password, "00:00:01");
+             ktc_ForgetAllTokens();
+           }
+          if (logmask && LOG_MASK(LOG_DEBUG))
+            syslog(LOG_DEBUG, "do_klog returned %d", i);
+          auth_ok = i ? 0 : 1;
+       } else {
+         if (logmask && LOG_MASK(LOG_DEBUG))
+           syslog(LOG_DEBUG, "forking ...");
     cpid = fork();
     if (cpid <= 0) {     /* The child process */
-       code = ka_VerifyUserPassword(KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG,
+      if (logmask && LOG_MASK(LOG_DEBUG))
+       syslog(LOG_DEBUG, "in child");
+              if (refresh_token || set_token)
+                 code = ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION,
+                                   user, /* kerberos name */
+                                   (char *)0, /* instance */
+                                   (char *)0, /* realm */
+                                   password, /* password */
+                                   0, /* default lifetime */
+                                    &password_expires,
+                                    0, /* spare 2 */
+                                   &reason /* error string */ );
+              else
+                 code = ka_VerifyUserPassword(KA_USERAUTH_VERSION,
                                    user, /* kerberos name */
                                    (char *)0, /* instance */
                                    (char *)0, /* realm */
@@ -249,9 +316,13 @@ try_auth:
        } else {
          auth_ok = 1;
        }
+       if (logmask && LOG_MASK(LOG_DEBUG))
+        syslog(LOG_DEBUG, "child: auth_ok=%d", auth_ok);
        if (cpid == 0) exit(auth_ok);
     } else {
        do {
+        if (logmask && LOG_MASK(LOG_DEBUG))
+          syslog(LOG_DEBUG, "in parent, waiting ...");
          rcpid = waitpid(cpid, &status, 0);
        } while ((rcpid == -1) && (errno == EINTR));
        
@@ -260,13 +331,47 @@ try_auth:
        } else {
          auth_ok = 0;
        }
+       if (logmask && LOG_MASK(LOG_DEBUG))
+        syslog(LOG_DEBUG, "parent: auth_ok=%d", auth_ok);
+           }
     }
-
     /* Restore old signal handler */
     code = sigaction(SIGCHLD, &origAction, (struct sigaction *)0);
     if (code) {
        pam_afs_syslog(LOG_ERR, PAMAFS_PAMERROR, errno);
     }
+    } else { /* dont_fork, used by httpd */
+      if (logmask && LOG_MASK(LOG_DEBUG))
+        syslog(LOG_DEBUG, "dont_fork");
+        if (refresh_token || set_token)
+            code = ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION,
+                                   user, /* kerberos name */
+                                   (char *)0, /* instance */
+                                   (char *)0, /* realm */
+                                   password, /* password */
+                                   0, /* default lifetime */
+                                    &password_expires,
+                                    0, /* spare 2 */
+                                   &reason /* error string */ );
+        else
+            code = ka_VerifyUserPassword(KA_USERAUTH_VERSION,
+                                   user, /* kerberos name */
+                                   (char *)0, /* instance */
+                                   (char *)0, /* realm */
+                                   password, /* password */
+                                   0, /* spare 2 */
+                                   &reason /* error string */ );
+       if (logmask && LOG_MASK(LOG_DEBUG))
+         syslog(LOG_DEBUG, "dont_fork, code = %d",code);
+        if (code) {
+           pam_afs_syslog(LOG_ERR, PAMAFS_LOGIN_FAILED, user, reason);
+           auth_ok = 0;
+        } else {
+           auth_ok = 1;
+        }
+       if (logmask && LOG_MASK(LOG_DEBUG))
+         syslog(LOG_DEBUG, "dont_fork: auth_ok=%d", auth_ok);
+    }
 
     if (!auth_ok && try_first_pass) {
        password = NULL;
@@ -274,11 +379,18 @@ try_auth:
     }
 
     /* We don't care if this fails; all we can do is try. */
-    if (auth_ok && !got_authtok) {
+    /* It is not reasonable to store the password only if it was correct
+     * because it could satisfy another module that is called in the chain
+     * after pam_afs
+     */
+    if (!got_authtok) {
        torch_password = 0;
-        pam_set_item(pamh, PAM_AUTHTOK, password);
+        (void) pam_set_item(pamh, PAM_AUTHTOK, password);
     }
 
+    if (logmask && LOG_MASK(LOG_DEBUG))
+      syslog(LOG_DEBUG, "leaving auth: auth_ok=%d", auth_ok);
+    if (code == KANOENT) RET(PAM_USER_UNKNOWN);
     RET(auth_ok ? PAM_SUCCESS : PAM_AUTH_ERR);
        
  out:
index f7c71c5..7ba3022 100644 (file)
@@ -40,13 +40,13 @@ static char *fallback_messages[] = {
     "AFS not available",                       /* 10: AFS_UNAVAIL      */
     "AFS error code 0x%x",                     /* 11: AFS_ERROR        */
     "AFS Authentication succeeded.\n",         /* 12: LOGIN_OK         */
-    "AFS Authentication failed for user %s %s\n",
+    "AFS Authentication failed for user %s. %s\n",
                                                /* 13: LOGIN_FAILED     */
     "AFS PAM error, code=%d",                  /* 14: PAMERROR         */
     "AFS uid exceeds OS bounds.\n",            /* 15: UID_OVERFLOW     */
     "The AFS PAM module may not be used from a non-MT program.\n",
                                                /* 16: NON_MT_PROG      */
-    "AFS Options: nowarn=%d, use_first_pass=%d, try_first_pass=%d",
+    "AFS Options: nowarn=%d, use_first_pass=%d, try_first_pass=%d, ignore_uid = %d, ignore_uid_id = %d, refresh_token=%d, set_token=%d, dont_fork=%d, use_klog=%d",
                                                /* 17: OPTIONS          */
     "AFS No pam_conv conversation structure found; no user interaction",
                                                /* 18: NO_USER_INT      */
@@ -68,17 +68,23 @@ static char *fallback_messages[] = {
     "AFS ReInitializing creds for user %s\n",  /* 31: REINITCRED       */
     "AFS Failed to set PASSWORD_EXPIRES for user %s\n",
                                                /* 32: PASSEXPFAIL      */
-    "",
-                                               /* 33: */
-    "",
-                                               /* 34: */
-    "AFS blindly trusting user %s\n",          /* 35: TRUSTROOT        */
-    "New AFS Password: ",                       /* 36: NEW_PWD_PROMPT   */
-    "New AFS Password (again): ",               /* 37: VERIFY_PWD_PROMPT */
-    "Failed to change AFS password",            /* 38: KRBPASS_FAIL     */
-    "Missing PAM flag: %s",                     /* 39: FLAGS            */
-    "ka error, code=%d",                        /* 40: KAERROR          */
-    "Passwords are not equal"                   /* 41: NE_PASSWORD      */
+    "AFS Failed to chown krb ticketfile\n",     /* 33: CHOWNKRB         */
+    "AFS Failed to set KRBTKTFILE\n",           /* 34: KRBFAIL          */
+    "AFS Unknown remaining lifetime %s using default %d seconds\n",
+                                                /* 35: REMAINLIFETIME   */
+    "AFS Session closed",                       /* 36: SESSIONCLOSED1   */
+    "AFS Session closed, Tokens destroyed\n",   /* 37: SESSIONCLOSED2   */
+    "AFS Option conflict dont_fork and use_klog: %s\n",
+                                                /* 38: CONFLICTOPT      */
+    "AFS Unknown uid: %s, option ignored\n",
+                                                /* 39: IGNOREUID        */
+    "New AFS Password: ",                       /* 40: NEW_PWD_PROMPT   */
+    "New AFS Password (again): ",               /* 41: VERIFY_PWD_PROMPT */
+    "Failed to change AFS password",            /* 42: KRBPASS_FAIL     */
+    "Missing PAM flag: %s",                     /* 43: FLAGS            */
+    "ka error, code=%d",                        /* 44: KAERROR          */
+    "Passwords are not equal",                  /* 45: NE_PASSWORD      */
+    "AFS ignoring unregistered user %s\n"       /* 46: IGNORE_UNREG     */
 };
 
 static int num_fallbacks = sizeof(fallback_messages)/sizeof(char *);
index 8b211b0..6ed88e1 100644 (file)
 #define PAMAFS_PASSEXPFAIL     32 /* "Failed to set PASSWORD_EXPIRES"  */
 #define PAMAFS_CHOWNKRB                33 /* "Failed to chown krb ticketfile"  */
 #define PAMAFS_KRBFAIL         34 /* "Failed to set KRBTKTFILE"        */
-#define PAMAFS_TRUSTROOT       35 /* "Ignoring superuser %s"           */
-#define PAMAFS_NEW_PWD_PROMPT   36 /* "New AFS Password:"               */
-#define PAMAFS_VERIFY_PWD_PROMPT  37 /* "New AFS Password (again):"     */
-#define PAMAFS_KAPASS_FAIL      38 /* "Failed to change AFS password"   */
-#define PAMAFS_FLAGS            39 /* "Missing PAM flag:"               */
-#define PAMAFS_KAERROR          40 /* "ka error, code=%d"               */
-#define PAMAFS_NE_PASSWORD      41 /* "Passwords are not equal"         */  
+#define PAMAFS_REMAINLIFETIME   35 /* "Unknown remaining lifetime"      */
+#define PAMAFS_SESSIONCLOSED1   36 /* "Session closed"                  */
+#define PAMAFS_SESSIONCLOSED2   37 /* "Session closed, Tokens destroyed"*/
+#define PAMAFS_CONFLICTOPT      38 /* "Option conflict"                 */
+#define PAMAFS_IGNOREUID        39 /* "Unknown uid"                     */
+#define PAMAFS_NEW_PWD_PROMPT   40 /* "New AFS Password:"               */
+#define PAMAFS_VERIFY_PWD_PROMPT  41 /* "New AFS Password (again):"     */
+#define PAMAFS_KAPASS_FAIL      42 /* "Failed to change AFS password"   */
+#define PAMAFS_FLAGS            43 /* "Missing PAM flag:"               */
+#define PAMAFS_KAERROR          44 /* "ka error, code=%d"               */
+#define PAMAFS_NE_PASSWORD      45 /* "Passwords are not equal"         */
+#define PAMAFS_IGNORE_UNREG     46 /* "AFS ignoring unregistered user"  */
+
 
 char *pam_afs_message(int msgnum, int *freeit);
 void pam_afs_syslog(int priority, int msgid, ...);
index c78b794..043b89b 100644 (file)
@@ -93,8 +93,11 @@ pam_sm_chauthtok(
 
     if (use_first_pass) try_first_pass = 0;
 
-    pam_afs_syslog(LOG_DEBUG, PAMAFS_OPTIONS, nowarn, use_first_pass, try_first_pass);
-    pam_afs_syslog(LOG_DEBUG, PAMAFS_PAMERROR, flags);
+    if (logmask && LOG_MASK(LOG_DEBUG))
+      {
+       pam_afs_syslog(LOG_DEBUG, PAMAFS_OPTIONS, nowarn, use_first_pass, try_first_pass);
+       pam_afs_syslog(LOG_DEBUG, PAMAFS_PAMERROR, flags);
+      }
 
     /* Try to get the user-interaction info, if available. */
     errcode = pam_get_item(pamh, PAM_CONV, (const void **) &pam_convp);
@@ -109,7 +112,8 @@ pam_sm_chauthtok(
        RET(PAM_USER_UNKNOWN);
     }
 
-    pam_afs_syslog(LOG_DEBUG, PAMAFS_USERNAMEDEBUG, user);
+    if (logmask && LOG_MASK(LOG_DEBUG))
+      pam_afs_syslog(LOG_DEBUG, PAMAFS_USERNAMEDEBUG, user);
 
     /*
      * If the user has a "local" (or via nss, possibly nss_dce) pwent,
@@ -147,13 +151,15 @@ pam_sm_chauthtok(
            RET(PAM_AUTH_ERR);
        }
        password = NULL;        /* In case it isn't already NULL */
-       pam_afs_syslog(LOG_DEBUG, PAMAFS_NOFIRSTPASS, user);
+       if (logmask && LOG_MASK(LOG_DEBUG))
+         pam_afs_syslog(LOG_DEBUG, PAMAFS_NOFIRSTPASS, user);
     } else if (password[0] == '\0') {
        /* Actually we *did* get one but it was empty. */
        torch_password = 0;
        pam_afs_syslog(LOG_INFO, PAMAFS_NILPASSWORD, user);
        RET(PAM_NEW_AUTHTOK_REQD);
     } else {
+      if (logmask && LOG_MASK(LOG_DEBUG))
        pam_afs_syslog(LOG_DEBUG, PAMAFS_GOTPASS, user);
        torch_password = 0;
        got_authtok = 1;
index 1321ed0..b2b584a 100644 (file)
@@ -14,6 +14,13 @@ RCSID("$Header$");
 
 #include <security/pam_appl.h>
 #include <security/pam_modules.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include "afs_message.h"
+#include "afs_util.h"
 
 extern int
 pam_sm_open_session(
@@ -26,6 +33,8 @@ pam_sm_open_session(
 }
 
 
+#define REMAINLIFETIME 300
+
 extern int
 pam_sm_close_session(
        pam_handle_t    *pamh,
@@ -33,5 +42,68 @@ pam_sm_close_session(
        int             argc,
        const char      **argv)
 {
+    int i;
+    int logmask = LOG_UPTO(LOG_INFO);
+    int origmask;
+    int remain = 0;
+    int remainlifetime = REMAINLIFETIME;
+    int no_unlog = 0;
+
+    openlog(pam_afs_ident, LOG_CONS|LOG_PID, LOG_AUTH);
+    origmask = setlogmask(logmask);
+
+    /*
+     * Parse the user options.  Log an error for any unknown options.
+     */
+    for (i = 0; i < argc; i++) {
+        if (       strcasecmp(argv[i], "debug"         ) == 0) {
+            logmask |= LOG_MASK(LOG_DEBUG);
+            (void) setlogmask(logmask);
+        } else if (strcasecmp(argv[i], "remain"        ) == 0) {
+            remain = 1;
+        } else if (strcasecmp(argv[i], "remainlifetime") == 0) {
+            i++;
+            remain = 1;
+            remainlifetime = (int) strtol(argv[i], (char**)NULL, 10);
+            if (remainlifetime == 0)
+                if((errno == EINVAL) || (errno == ERANGE)) {
+                    remainlifetime = REMAINLIFETIME;
+                    pam_afs_syslog(LOG_ERR, PAMAFS_REMAINLIFETIME, argv[i], REMAINLIFETIME);
+                } else {
+                    no_unlog = 0;
+                    remain = 0;
+                }
+        } else if (strcmp(argv[i], "no_unlog") == 0) {
+                no_unlog = 1;
+        } else {
+            pam_afs_syslog(LOG_ERR, PAMAFS_UNKNOWNOPT, argv[i]);
+        }
+    }
+       
+    if (logmask && LOG_MASK(LOG_DEBUG))
+      syslog(LOG_DEBUG, "pam_afs_session_close: remain: %d, remainlifetime: %d, no_unlog: %d",remain,remainlifetime,no_unlog);
+    if(remain && !no_unlog) {
+        switch (fork()) {
+            case -1 : /* error */
+                 return(PAM_SESSION_ERR);
+            case 0  : /* child */
+#ifdef AFS_LINUX20_ENV 
+                setpgrp();
+#endif
+                 setsid();
+                for (i = 0; i <64; i++) close (i);
+                 sleep(remainlifetime);
+                 ktc_ForgetAllTokens();
+                 pam_afs_syslog(LOG_INFO, PAMAFS_SESSIONCLOSED2);
+                 exit(0);
+            default : /* parent */
+                 pam_afs_syslog(LOG_INFO, PAMAFS_SESSIONCLOSED1);
+                 return(PAM_SUCCESS);
+        }
+    } 
+    if (!no_unlog && ktc_ForgetAllTokens())
+           return PAM_SESSION_ERR;
+    if (logmask && LOG_MASK(LOG_DEBUG))
+      syslog(LOG_DEBUG, "pam_afs_session_close: Session closed");
     return PAM_SUCCESS;
 }
index f3b46a0..92f83be 100644 (file)
@@ -14,6 +14,7 @@
 #include <string.h>
 #include <pwd.h>
 #include <unistd.h>
+#include <errno.h>
 #include <afsconfig.h>
 #include <afs/param.h>
 
@@ -44,12 +45,15 @@ pam_sm_setcred(
     int origmask;
     int logmask = LOG_UPTO(LOG_INFO);
     int nowarn = 0;
-    int use_first_pass = 1; /* use the password passed in by auth */
+    int use_first_pass = 0; /* use the password passed in by auth */
     int try_first_pass = 0;
     int got_authtok = 0;
-    int ignore_root = 0;
-    int trust_root = 0;
+    int ignore_uid  = 0;
+    int no_unlog = 0;
+    uid_t ignore_uid_id = 0;
+    int refresh_token = 0;
     int set_expires = 0; /* the default is to not to set the env variable */
+    int use_klog = 0;
     int i;
     struct pam_conv *pam_convp = NULL;
     char my_password_buf[256];
@@ -83,11 +87,31 @@ pam_sm_setcred(
        } else if (strcasecmp(argv[i], "try_first_pass") == 0) {
            try_first_pass = 1;
         } else if (strcasecmp(argv[i], "ignore_root"   ) == 0) {
-            ignore_root = 1;
-        } else if (strcasecmp(argv[i], "trust_root"   ) == 0) {
-            trust_root = 1;
-        } else if (strcasecmp(argv[i], "catch_su"   ) == 0) {
-            use_first_pass = 0;
+            ignore_uid = 1;
+           ignore_uid_id = 0;
+       } else if (strcasecmp(argv[i], "ignore_uid"    ) == 0) {
+           i++;
+           if (i == argc) {
+                pam_afs_syslog(LOG_ERR, PAMAFS_IGNOREUID, "ignore_uid missing argument");
+               ignore_uid = 0;
+           } else {
+               ignore_uid = 1;
+               ignore_uid_id = (uid_t) strtol(argv[i], (char**)NULL, 10);
+               if ( (0 > ignore_uid_id) || (ignore_uid_id > IGNORE_MAX) ) {
+                       ignore_uid = 0;
+                       pam_afs_syslog(LOG_ERR, PAMAFS_IGNOREUID, argv[i]);
+                }
+           }
+       } else if (strcasecmp(argv[i], "no_unlog") == 0) {
+           no_unlog = 1;
+       } else if (strcasecmp(argv[i], "refresh_token" ) == 0) {
+           refresh_token = 1;
+       } else if (strcasecmp(argv[i], "set_token" ) == 0) {
+           ;
+       } else if (strcasecmp(argv[i], "dont_fork" ) == 0) {
+           ;
+       } else if (strcasecmp(argv[i], "use_klog" ) == 0) {
+           use_klog = 1;
        } else if (strcasecmp(argv[i], "setenv_password_expires")==0) {
            set_expires = 1;
        } else {
@@ -97,16 +121,18 @@ pam_sm_setcred(
 
     if (use_first_pass) try_first_pass = 0;
 
-    pam_afs_syslog(LOG_DEBUG, PAMAFS_OPTIONS, nowarn, use_first_pass, try_first_pass);
+    if (logmask && LOG_MASK(LOG_DEBUG))
+      pam_afs_syslog(LOG_DEBUG, PAMAFS_OPTIONS, nowarn, use_first_pass, try_first_pass, ignore_uid, ignore_uid_id, 8, 8, 8, 8);
     /* Try to get the user-interaction info, if available. */
-    errcode = pam_get_item(pamh, PAM_CONV, (void **) &pam_convp);
+    errcode = pam_get_item(pamh, PAM_CONV, (const void **) &pam_convp);
     if (errcode != PAM_SUCCESS) {
+      if (logmask && LOG_MASK(LOG_DEBUG))
        pam_afs_syslog(LOG_DEBUG, PAMAFS_NO_USER_INT);
        pam_convp = NULL;
     }
 
     /* Who are we trying to authenticate here? */
-    if ((errcode = pam_get_user(pamh, &user, "AFS username:")) != PAM_SUCCESS) {
+    if ((errcode = pam_get_user(pamh, (const char **)&user, "AFS username:")) != PAM_SUCCESS) {
         pam_afs_syslog(LOG_ERR, PAMAFS_NOUSER, errcode);
         RET(PAM_USER_UNKNOWN);
     }
@@ -115,6 +141,9 @@ pam_sm_setcred(
      * and its uid==0, and "ignore_root" was given in pam.conf,
      * ignore the user.
      */
+    /* enhanced: use "ignore_uid <number>" to specify the largest uid
+     * which should be ignored by this module
+     */
 #if    defined(AFS_HPUX_ENV)
 #if     defined(AFS_HPUX110_ENV)
     i = getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf), &upwd);
@@ -123,7 +152,7 @@ pam_sm_setcred(
     if ( i == 0 )                       /* getpwnam_r success */
         upwd = &unix_pwd;
 #endif  /* AFS_HPUX110_ENV */
-    if (ignore_root && i == 0 && upwd->pw_uid == 0) {
+    if (ignore_uid && i == 0 && upwd->pw_uid <= ignore_uid_id) {
         pam_afs_syslog(LOG_INFO, PAMAFS_IGNORINGROOT, user);
         RET(PAM_AUTH_ERR);
     }
@@ -133,28 +162,26 @@ pam_sm_setcred(
 #else
     upwd = getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf));
 #endif
-    if (upwd != NULL && upwd->pw_uid == 0) {
-       if (ignore_root) { 
+    if (ignore_uid && upwd != NULL && upwd->pw_uid <= ignore_uid_id) {
                pam_afs_syslog(LOG_INFO, PAMAFS_IGNORINGROOT, user);
                RET(PAM_AUTH_ERR);
-       } else if (trust_root) {
-               pam_afs_syslog(LOG_INFO, PAMAFS_TRUSTROOT, user);
-               RET(PAM_SUCCESS);
-       }
     }
 #endif
 
     if (flags & PAM_DELETE_CRED) {
+      if (logmask && LOG_MASK(LOG_DEBUG))
        pam_afs_syslog(LOG_DEBUG, PAMAFS_DELCRED, user);
 
        RET(PAM_SUCCESS);
     } else if (flags & PAM_REINITIALIZE_CRED) {
 
+      if (logmask && LOG_MASK(LOG_DEBUG))
         pam_afs_syslog(LOG_DEBUG, PAMAFS_REINITCRED, user);
         RET(PAM_SUCCESS);
 
     } else { /* flags are PAM_REFRESH_CRED, PAM_ESTABLISH_CRED, unknown */
 
+      if (logmask && LOG_MASK(LOG_DEBUG))
        pam_afs_syslog(LOG_DEBUG, PAMAFS_ESTABCRED, user);
 
        errcode = pam_get_data(pamh, pam_afs_lh, (const void **) &password);
@@ -164,7 +191,8 @@ pam_sm_setcred(
                RET(PAM_AUTH_ERR);
            }
            password = NULL;    /* In case it isn't already NULL */
-           pam_afs_syslog(LOG_DEBUG, PAMAFS_NOFIRSTPASS, user);
+           if (logmask && LOG_MASK(LOG_DEBUG))
+             pam_afs_syslog(LOG_DEBUG, PAMAFS_NOFIRSTPASS, user);
        } else if (password[0] == '\0') {
            /* Actually we *did* get one but it was empty. */
            got_authtok = 1;
@@ -175,8 +203,10 @@ pam_sm_setcred(
                pam_afs_syslog(LOG_ERR, PAMAFS_PASSWD_REQ, user);
                RET(PAM_NEW_AUTHTOK_REQD);
            }
-           pam_afs_syslog(LOG_DEBUG, PAMAFS_NILPASSWORD, user);
+           if (logmask && LOG_MASK(LOG_DEBUG))
+             pam_afs_syslog(LOG_DEBUG, PAMAFS_NILPASSWORD, user);
        } else {
+         if (logmask && LOG_MASK(LOG_DEBUG))
            pam_afs_syslog(LOG_DEBUG, PAMAFS_GOTPASS, user);
            torch_password = 0;
            got_authtok = 1;
@@ -206,6 +236,7 @@ pam_sm_setcred(
                RET(PAM_AUTH_ERR);
            }
            if (password[0] == '\0') {
+             if (logmask && LOG_MASK(LOG_DEBUG))
                pam_afs_syslog(LOG_DEBUG, PAMAFS_NILPASSWORD);
                RET(PAM_NEW_AUTHTOK_REQD);
            }
@@ -216,16 +247,30 @@ pam_sm_setcred(
             * this storage, copy it to a buffer that won't need to be freed
             * later, and free this storage now.
             */
+
            strncpy(my_password_buf, password, sizeof(my_password_buf));
            my_password_buf[sizeof(my_password_buf)-1] = '\0';
            memset(password, 0, strlen(password));
            free(password);
            password = my_password_buf;
        }
+       /*
+        * We only set a PAG here, if we haven't got one before in
+        * pam_sm_authenticate() or if it was destroyed by the application
+        */
+       if ((!refresh_token) && (getPAG() == -1)) {
+         if (logmask && LOG_MASK(LOG_DEBUG))
+           syslog(LOG_DEBUG, "New PAG created in pam_setcred()");
+          setpag();
+       }
 
        if ( flags & PAM_REFRESH_CRED ) {
+           if (use_klog) {
+               auth_ok = do_klog(user, password, "00:00:01");
+              ktc_ForgetAllTokens();
+           } else {
             if ( ka_VerifyUserPassword(
-                           KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG,
+                           KA_USERAUTH_VERSION,
                            user, /* kerberos name */
                            (char *)0, /* instance */
                            (char *)0, /* realm */
@@ -238,10 +283,13 @@ pam_sm_setcred(
                auth_ok = 1;
            }   
        }
+       }
            
        if (  flags & PAM_ESTABLISH_CRED ) {
+          if (use_klog) auth_ok = do_klog(user, password, NULL);
+          else {
            if ( ka_UserAuthenticateGeneral(
-                           KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG,
+                           KA_USERAUTH_VERSION,
                            user, /* kerberos name */
                            (char *)0, /* instance */
                            (char *)0, /* realm */
@@ -256,19 +304,22 @@ pam_sm_setcred(
               auth_ok = 1;
            }
        }
+       }
 
        if (!auth_ok && try_first_pass) {
            password = NULL;
            goto try_auth;
        }
 
-       if (auth_ok && !got_authtok) {
-           torch_password = 0;
-           (void) pam_set_item(pamh, PAM_AUTHTOK, password);
-       }
+       /* pam_sm_authenticate should have set this 
+        * if (auth_ok && !got_authtok) {
+        *     torch_password = 0;
+        *     (void) pam_set_item(pamh, PAM_AUTHTOK, password);
+         * }
+        */
 
        if (auth_ok) {
-           if (set_expires &&  (password_expires >= 0) ) {
+           if (set_expires && !use_klog &&  (password_expires >= 0) ) {
                strcpy(sbuffer, "PASSWORD_EXPIRES=");
                strcat(sbuffer, cv2string(&sbuffer[100], password_expires));
                errcode = pam_putenv( pamh, sbuffer); 
@@ -276,14 +327,15 @@ pam_sm_setcred(
                    pam_afs_syslog(LOG_ERR, PAMAFS_PASSEXPFAIL, user);
            }
 #if defined(AFS_KERBEROS_ENV)
-           if (upwd)
-           {
+           if (!use_klog) {
+               if (upwd) {
                if ( chown(ktc_tkt_string(), upwd->pw_uid, upwd->pw_gid) < 0 )
                    pam_afs_syslog(LOG_ERR, PAMAFS_CHOWNKRB, user);
                sprintf(sbuffer, "KRBTKFILE=%s", ktc_tkt_string());
                errcode = pam_putenv( pamh, sbuffer);
                 if ( errcode != PAM_SUCCESS )
                     pam_afs_syslog(LOG_ERR, PAMAFS_KRBFAIL, user);
+              }
            }
 #endif
 
index a61d8bf..e0a8dae 100644 (file)
@@ -9,9 +9,13 @@
 
 #include <stdio.h>
 #include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+#include <syslog.h>
 #include <security/pam_appl.h>
 #include <afsconfig.h>
 #include <afs/param.h>
+#include <sys/wait.h>
 
 RCSID("$Header$");
 
@@ -53,12 +57,12 @@ these facilities, we can safely define these to be null functions */
 
 #if !defined(AFS_HPUX110_ENV)
 /* For HP 11.0, this function is in util/hputil.c */
-sigvec()
+sigvec(int sig, const struct sigvec* vec, struct sigvec* ovec)
 {
        assert(0);
 }
 #endif  /* AFS_HPUX110_ENV */
-sigsetmask()
+sigsetmask(int mask)
 {
        assert(0);
 }
@@ -85,3 +89,115 @@ char *cv2string(ttp, aval)
     return tp;
 }
 
+int do_klog(const char* user, const char* password, const char* lifetime)
+{
+pid_t  pid;
+int    pipedes[2];
+int    status;
+char*   argv[32];
+int     argc = 0;
+char*   klog_prog;
+int    ret = 1;
+
+#if defined(AFS_KERBEROS_ENV) 
+   klog_prog = KLOGKRB;
+#else
+   klog_prog = KLOG;
+#endif
+   if (access(klog_prog, X_OK) != 0) {
+      syslog(LOG_ERR, "can not access klog program '%s'", KLOG);
+      goto out;
+   }
+#if defined(AFS_KERBEROS_ENV) 
+   argv[argc++] = "klog.krb";
+
+#else
+   argv[argc++] = "klog";
+#endif
+   argv[argc++] = (char*)user;
+   argv[argc++] = "-silent";
+   argv[argc++] = "-pipe";
+   if (lifetime != NULL) {
+      argv[argc++] = "-lifetime";
+      argv[argc++] = (char*)lifetime;
+   }
+   argv[argc] = NULL;
+
+   if (pipe(pipedes) != 0) {
+      syslog(LOG_ERR, "can not open pipe: %s", strerror(errno));
+      goto out;
+   }
+   pid = fork();
+   switch(pid) {
+      case (-1): /* Error: fork failed */
+         syslog(LOG_ERR, "fork failed: %s", strerror(errno));
+        goto out;
+      case (0) : /* child */
+        close(0);
+        dup(pipedes[0]);
+        close(pipedes[0]);
+        close(1);
+        dup(pipedes[1]);
+        close(pipedes[1]);
+        execv(klog_prog, argv);
+        /* notreached */
+        syslog(LOG_ERR, "execv failed: %s", strerror(errno));
+        close(0);
+        close(1);
+        goto out;
+      default :
+        write(pipedes[1], password, strlen(password));
+        write(pipedes[1], "\n", 1);
+        close(pipedes[0]);
+        close(pipedes[1]);
+        if (pid != wait(&status)) return(0);
+        if (WIFEXITED(status)) {
+            ret = WEXITSTATUS(status);
+           goto out;
+         }
+        syslog(LOG_NOTICE, "%s for %s failed", klog_prog, user) ;
+   }
+out:
+   /*   syslog(LOG_DEBUG, "do_klog returns %d", ret); */
+   return(ret);
+}
+
+/* get the current AFS pag for the calling process */
+static afs_int32 curpag()
+{
+   gid_t groups[30];
+   afs_uint32 g0, g1;
+   afs_uint32 h, l, ret;
+      
+   if (getgroups(sizeof groups/sizeof groups[0], groups) < 2) return 0;
+        
+   g0 = groups[0]  & 0xffff;
+   g1 = groups[1]  & 0xffff;
+   g0 -= 0x3f00;
+   g1 -= 0x3f00;
+   if (g0 < 0xc000 && g1 < 0xc000) {
+      l = ((g0 & 0x3fff) << 14) | (g1 & 0x3fff);
+      h = (g0 >> 14);
+      h = (g1 >> 14) + h + h + h;
+      ret = ((h << 28) | l);
+      /* Additional testing */
+      if (((ret >> 24) & 0xff) == 'A')
+         return ret;
+      else
+         return -1;
+     }
+   return -1;
+}
+
+/* Returns the AFS pag number, if any, otherwise return -1 */
+afs_int32 getPAG()
+{
+   afs_int32 pag;
+   
+   pag = curpag();
+   if (pag == 0 || pag == -1)
+      return -1;
+       
+   /* high order byte is always 'A'; actual pag value is low 24 bits */
+   return (pag & 0xFFFFFF);
+}
index 7d66bb9..ff15037 100644 (file)
@@ -27,6 +27,11 @@ void nil_cleanup(
 
 extern char*   cv2string();
 
+#define KLOG "/usr/afsws/bin/klog"
+#define KLOGKRB "/usr/afsws/bin/klog.krb"
+#define UNLOG "/usr/afsws/bin/unlog"
+#define IGNORE_MAX 1000
+
 #if    defined(AFS_HPUX_ENV)
 
 #if !defined(AFS_HPUX110_ENV)
index 77e4075..6261dc7 100644 (file)
@@ -43,6 +43,7 @@ void main(int argc, char *argv[])
     int authenticated = 0;
     int retcode;
     char *username;
+    int setcred = 1;
 
     if (argc < 2 || argc > 3) {
        fprintf(stderr, "Usage: %s [-u] <user>\n", argv[0]);
@@ -53,7 +54,8 @@ void main(int argc, char *argv[])
            fprintf(stderr, "Usage: %s [-u] <user>\n", argv[0]);
            exit(1);
        }
-       service = "unixtest";
+       /* service = "unixtest"; */
+        setcred = 0;
        username = argv[2];
     } else {
        username = argv[1];
@@ -81,12 +83,18 @@ void main(int argc, char *argv[])
 
     /* pam_open_session */
 
+    if (setcred)
     if ((retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
        fprintf(stderr, "pam_setcred returned %d.\n", retcode);
        pam_end(pamh, PAM_ABORT);
        exit(1);
     }
 
+    if ((retcode = pam_open_session(pamh, PAM_SILENT)) != PAM_SUCCESS) {
+       fprintf(stderr, "pam_open_session returned %d.\n", retcode);
+       pam_end(pamh, PAM_ABORT);
+       exit(1);
+    }
     pam_end(pamh, PAM_SUCCESS);
 
     putenv(new_envstring);