Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 12 Jul 1999 10:14:34 -0400 (EDT)
From:      Dave Gillham <dagill@unx.sas.com>
To:        freebsd-current@freebsd.org
Subject:   patch: PAM hooks for rshd & rlogind
Message-ID:  <199907121414.KAA36811@frink.unx.sas.com>

next in thread | raw e-mail | index | archive | help
Attached are patches for rshd and rlogind to add a hook to use
PAM modules to handle user authentication.

Currently we have restricted compute servers that we want to keep most
users from directly logging into, but that must retain the .rhosts
functionality for the few users that are allowed to login. For this
reason we couldn't just use the -l flag with rshd.

Additionally, because our users must be able to place processes on the
servers (via a custom inetd interface), we could not just remove their
password entries.  While we could have set their shell to
/sbin/nologin this would have been inconvenient as we use a shared
password file on our network.

The following code (which originally came from login) gives us the
ability to use PAM to deny the user access before attempting to access
their .rhosts file. Without these changes, rsh and rlogin authenticate
the user by their .rhosts file without giving PAM a chance to validate
them.  With these changes, we provide the oportunity to callout to PAM
before any .rhost checking and thus deny user login based on the
policy coded into the PAM module.

Please consider these changes for review and integration into the base
system.

Thanks,

Dave Gillham
dagill@unx.sas.com



Index: rlogind/Makefile
===================================================================
RCS file: /usr/mirror/ncvs/src/libexec/rlogind/Makefile,v
retrieving revision 1.10
diff -r1.10 Makefile
23a24,30
> .if defined(NOPAM)
> CFLAGS+= -DNO_PAM
> .else
> DPADD+= ${LIBPAM}
> LDADD+= ${MINUSLPAM}
> .endif
> 
Index: rlogind/rlogind.c
===================================================================
RCS file: /usr/mirror/ncvs/src/libexec/rlogind/rlogind.c,v
retrieving revision 1.23
diff -r1.23 rlogind.c
82a83,87
> #ifndef NO_PAM
> #include <security/pam_appl.h>
> #include <security/pam_misc.h>
> #endif
> 
125a131,134
> #ifndef NO_PAM
> static int auth_pam __P((char *));
> #endif
> 
198a208,313
> #ifndef NO_PAM
> /*
>  * Attempt to authenticate the user using PAM.  Returns 0 if the user is
>  * authenticated, or 1 if not authenticated.  If some sort of PAM system
>  * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
>  * function returns -1.  This can be used as an indication that we should
>  * fall back to a different authentication mechanism.
>  */
> static int
> auth_pam(char *username)
> {
>         struct passwd *pawd;
>         pam_handle_t *pamh = NULL;
>         const char *tmpl_user;  
>         const void *item;
>         int rval;
>         char *tty, *ttyn;
>         char hostname[MAXHOSTNAMELEN];
>         char tname[sizeof(_PATH_TTY) + 10];
>         int e;
> 
>         static struct pam_conv conv = { misc_conv, NULL };
> 
>         ttyn = ttyname(STDIN_FILENO);
> 
>         if (ttyn == NULL || *ttyn == '\0') {
>                 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
>                 ttyn = tname;
>         }
>         if ((tty = strrchr(ttyn, '/')) != NULL)
>                 ++tty;
>         else
>                 tty = ttyn;
> 
>         rval = gethostname(hostname, sizeof(hostname));
> 
>         if (rval < 0) {
>                 syslog(LOG_ERR, "auth_pam: Failed to resolve local hostname");
>                 return -1;
>         }
>         if ((e = pam_start("rshd", username, &conv, &pamh)) != PAM_SUCCESS) {
>                 syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
>                 return -1;
>         }
>         if ((e = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS) {
>                 syslog(LOG_ERR, "pam_set_item(PAM_TTY): %s",
>                     pam_strerror(pamh, e));
>                 return -1;
>         }
>         if (hostname != NULL &&
>             (e = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS) {
>                 syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
>                     pam_strerror(pamh, e));
>                 return -1;
>         }
> 
>         e = pam_authenticate(pamh, 0);
> 
>         switch (e) {
>         case PAM_SUCCESS:
>                 /*
>                  * With PAM we support the concept of a "template"
>                  * user.  The user enters a login name which is
>                  * authenticated by PAM, usually via a remote service
>                  * such as RADIUS or TACACS+.  If authentication
>                  * succeeds, a different but related "template" name
>                  * is used for setting the credentials, shell, and
>                  * home directory.  The name the user enters need only
>                  * exist on the remote authentication server, but the
>                  * template name must be present in the local password
>                  * database.
>                  *
>                  * This is supported by two various mechanisms in the
>                  * individual modules.  However, from the application's
>                  * point of view, the template user is always passed
>                  * back as a changed value of the PAM_USER item.
>                  */
>                 if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
>                     PAM_SUCCESS) {
>                         tmpl_user = (const char *) item;
>                         if (strcmp(username, tmpl_user) != 0)
>                                 pawd = getpwnam(tmpl_user);
>                 } else
>                         syslog(LOG_ERR, "Couldn't get PAM_USER: %s", pam_strerror(pamh, e));
>                 rval = 0;
>                 break;
> 
>         case PAM_AUTH_ERR:
>         case PAM_USER_UNKNOWN:
>         case PAM_MAXTRIES:
>                 rval = 1;
>                 break;
> 
>         default:
>                 syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e));
>                 rval = -1;
>                 break;
>         }
>         if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
>                 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
>                 rval = -1;
>         }
>         return rval;
> }
> #endif 
> 
278a394,395
> 
> 
588a706
>         int retval;
596a715,727
> 
> #ifndef  NO_PAM
>          retval = auth_pam(lusername);
>  
>          if (retval < 0) {
>                  syslog(LOG_ERR,"PAM authentication failed");
>          }
>          else if (retval == 1) {
>                  syslog(LOG_ERR,"User %s failed PAM authentication",lusername);
>                  exit(1);
>          }  
> #endif
> 
Index: rshd/Makefile
===================================================================
RCS file: /usr/mirror/ncvs/src/libexec/rshd/Makefile,v
retrieving revision 1.10
diff -r1.10 Makefile
19a20,26
> .if defined(NOPAM)
> CFLAGS+= -DNO_PAM
> .else
> DPADD+= ${LIBPAM}
> LDADD+= ${MINUSLPAM}
> .endif
> 
Index: rshd/rshd.c
===================================================================
RCS file: /usr/mirror/ncvs/src/libexec/rshd/rshd.c,v
retrieving revision 1.25
diff -r1.25 rshd.c
82a83,87
> #ifndef NO_PAM
> #include <security/pam_appl.h>
> #include <security/pam_misc.h>
> #endif
> 
94a100,103
> #ifndef NO_PAM
> static int auth_pam __P((char *));
> #endif
> 
197a207,314
> #ifndef NO_PAM
> /*              
>  * Attempt to authenticate the user using PAM.  Returns 0 if the user is
>  * authenticated, or 1 if not authenticated.  If some sort of PAM system
>  * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
>  * function returns -1.  This can be used as an indication that we should
>  * fall back to a different authentication mechanism.
>  */
> static int       
> auth_pam(char *username)       
> {
>         struct passwd *pawd;
>         pam_handle_t *pamh = NULL;
>         const char *tmpl_user;
>         const void *item;
>         int rval;
>         char *tty, *ttyn;
>         char hostname[MAXHOSTNAMELEN];
>         char tname[sizeof(_PATH_TTY) + 10];
>         int e;
> 
>         static struct pam_conv conv = { misc_conv, NULL };
> 
>         ttyn = ttyname(STDIN_FILENO);
> 
>         if (ttyn == NULL || *ttyn == '\0') {
>                 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
>                 ttyn = tname;
>         }
>         if ((tty = strrchr(ttyn, '/')) != NULL)
>                 ++tty;  
>         else
>                 tty = ttyn;
> 
>         rval = gethostname(hostname, sizeof(hostname));
> 
>         if (rval < 0) { 
>                 syslog(LOG_ERR, "auth_pam: Failed to resolve local hostname");
>                 return -1;
>         } 
>         if ((e = pam_start("rshd", username, &conv, &pamh)) != PAM_SUCCESS) {
>                 syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
>                 return -1;
>         }       
>         if ((e = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS) {
>                 syslog(LOG_ERR, "pam_set_item(PAM_TTY): %s",
>                     pam_strerror(pamh, e));
>                 return -1;
>         }       
>         if (hostname != NULL && 
>             (e = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS) {
>                 syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
>                     pam_strerror(pamh, e));
>                 return -1; 
>         }                       
> 
>         e = pam_authenticate(pamh, 0);
> 
> 
>         switch (e) {            
> 
>         case PAM_SUCCESS:
>                 /*
>                  * With PAM we support the concept of a "template"
>                  * user.  The user enters a login name which is
>                  * authenticated by PAM, usually via a remote service
>                  * such as RADIUS or TACACS+.  If authentication
>                  * succeeds, a different but related "template" name
>                  * is used for setting the credentials, shell, and
>                  * home directory.  The name the user enters need only
>                  * exist on the remote authentication server, but the
>                  * template name must be present in the local password
>                  * database.
>                  *
>                  * This is supported by two various mechanisms in the
>                  * individual modules.  However, from the application's
>                  * point of view, the template user is always passed
>                  * back as a changed value of the PAM_USER item.
>                  */
>                 if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
>                     PAM_SUCCESS) {
>                         tmpl_user = (const char *) item;
>                         if (strcmp(username, tmpl_user) != 0)
>                                 pawd = getpwnam(tmpl_user);
>                 } else
>                         syslog(LOG_ERR, "Couldn't get PAM_USER: %s", pam_strerror(pamh, e));
>                 rval = 0;
>                 break;
> 
>         case PAM_AUTH_ERR:
>         case PAM_USER_UNKNOWN:
>         case PAM_MAXTRIES:
>                 rval = 1;
>                 break;
> 
>         default:
>                 syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e));
>                 rval = -1;
>                 break;
>         }
>         if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
>                 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
>                 rval = -1;
>         }
>         return rval;
> }
> #endif 
> 
215a333
>         int retval;
428a547,558
> 
> #ifndef  NO_PAM
>          retval = auth_pam(locuser);
> 
>          if (retval < 0) {
>                  syslog(LOG_ERR,"PAM authentication failed");
>          }
>          else if (retval == 1) {
>                  syslog(LOG_ERR,"User %s failed PAM authentication",locuser);
>                  exit(1);
>          }
> #endif 


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199907121414.KAA36811>