From owner-freebsd-current Mon Jul 12 7:15:45 1999 Delivered-To: freebsd-current@freebsd.org Received: from lamb.sas.com (lamb.sas.com [192.35.83.8]) by hub.freebsd.org (Postfix) with ESMTP id 7A45B1507E for ; Mon, 12 Jul 1999 07:15:05 -0700 (PDT) (envelope-from dagill@unx.sas.com) Received: from mozart (mozart.unx.sas.com [192.58.184.8]) by lamb.sas.com (8.9.3/8.9.1) with SMTP id KAA16934 for ; Mon, 12 Jul 1999 10:15:04 -0400 (EDT) Received: from frink.unx.sas.com by mozart (5.65c/SAS/Domains/5-6-90) id AA14459; Mon, 12 Jul 1999 10:14:34 -0400 Received: (from dagill@localhost) by frink.unx.sas.com (8.9.3/8.9.3) id KAA36811 for freebsd-current@freebsd.org; Mon, 12 Jul 1999 10:14:34 -0400 (EDT) (envelope-from dagill) From: Dave Gillham Message-Id: <199907121414.KAA36811@frink.unx.sas.com> Subject: patch: PAM hooks for rshd & rlogind To: freebsd-current@freebsd.org Date: Mon, 12 Jul 1999 10:14:34 -0400 (EDT) X-Mailer: ELM [version 2.4ME+ PL54 (25)] Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: owner-freebsd-current@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG 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 > #include > #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 > #include > #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