Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/usr.bin/su Add PAM support to su
details: https://anonhg.NetBSD.org/src/rev/c8f09e0ace12
branches: trunk
changeset: 572545:c8f09e0ace12
user: manu <manu%NetBSD.org@localhost>
date: Fri Jan 07 22:34:20 2005 +0000
description:
Add PAM support to su
diffstat:
usr.bin/su/Makefile | 7 ++-
usr.bin/su/su.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 140 insertions(+), 13 deletions(-)
diffs (258 lines):
diff -r d2a8a3d02742 -r c8f09e0ace12 usr.bin/su/Makefile
--- a/usr.bin/su/Makefile Fri Jan 07 22:22:49 2005 +0000
+++ b/usr.bin/su/Makefile Fri Jan 07 22:34:20 2005 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.34 2003/12/11 09:46:27 dyoung Exp $
+# $NetBSD: Makefile,v 1.35 2005/01/07 22:34:20 manu Exp $
# from: @(#)Makefile 8.1 (Berkeley) 7/19/93
.include <bsd.own.mk>
@@ -50,3 +50,8 @@
.ifdef SU_ROOTAUTH
CPPFLAGS+=-DSU_ROOTAUTH=\"${SU_ROOTAUTH}\"
.endif
+
+.if (${USE_PAM} != "no")
+CPPFLAGS+=-DUSE_PAM
+LDADD+= -lpam
+.endif
diff -r d2a8a3d02742 -r c8f09e0ace12 usr.bin/su/su.c
--- a/usr.bin/su/su.c Fri Jan 07 22:22:49 2005 +0000
+++ b/usr.bin/su/su.c Fri Jan 07 22:34:20 2005 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: su.c,v 1.58 2004/01/05 23:23:37 jmmv Exp $ */
+/* $NetBSD: su.c,v 1.59 2005/01/07 22:34:20 manu Exp $ */
/*
* Copyright (c) 1988 The Regents of the University of California.
@@ -40,12 +40,15 @@
#if 0
static char sccsid[] = "@(#)su.c 8.3 (Berkeley) 4/2/94";*/
#else
-__RCSID("$NetBSD: su.c,v 1.58 2004/01/05 23:23:37 jmmv Exp $");
+__RCSID("$NetBSD: su.c,v 1.59 2005/01/07 22:34:20 manu Exp $");
#endif
#endif /* not lint */
#include <sys/param.h>
#include <sys/time.h>
+#ifdef USE_PAM
+#include <sys/wait.h>
+#endif
#include <sys/resource.h>
#include <err.h>
#include <errno.h>
@@ -63,6 +66,21 @@
#include <tzfile.h>
#include <unistd.h>
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+#include <security/openpam.h> /* for openpam_ttyconv() */
+
+static pam_handle_t *pamh;
+static struct pam_conv pamc;
+
+#define fatal(x) { pam_end(pamh, pam_err); err x; }
+#define fatalx(x) { pam_end(pamh, pam_err); errx x; }
+#else
+#define fatal(x) err x
+#define fatalx(x) errx x
+
+#endif
+
#ifdef LOGIN_CAP
#include <login_cap.h>
#endif
@@ -132,6 +150,14 @@
#ifdef LOGIN_CAP
login_cap_t *lc;
#endif
+#ifdef USE_PAM
+ char **pam_envlist, **pam_env;
+ char hostname[MAXHOSTNAMELEN];
+ const char **usernamep;
+ char *tty;
+ int pam_err, status;
+ pid_t pid;
+#endif
asme = asthem = fastlogin = 0;
gohome = 1;
@@ -186,16 +212,80 @@
/* get current login name and shell */
ruid = getuid();
username = getlogin();
+
+#ifdef USE_PAM
+ pamc.conv = &openpam_ttyconv;
+ pam_start("su", username, &pamc, &pamh);
+
+ /* Fill in hostname, username and tty */
+ if ((pam_err = pam_set_item(pamh, PAM_RUSER, username)) != PAM_SUCCESS)
+ goto pam_failed;
+
+ gethostname(hostname, sizeof(hostname));
+ if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)
+ goto pam_failed;
+
+ tty = ttyname(STDERR_FILENO);
+ if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)
+ goto pam_failed;
+
+ /* authentication */
+ if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS)
+ goto pam_failed;
+
+ if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD)
+ pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+ if (pam_err != PAM_SUCCESS)
+ goto pam_failed;
+
+ /* Get user credentials */
+ if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
+ goto pam_failed;
+
+ /* Open the session */
+ if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
+ goto pam_failed;
+
+ /* New user name? */
+ usernamep = (const char **)&username;
+ pam_err = pam_get_item(pamh, PAM_USER, (const void **)usernamep);
+ if (pam_err != PAM_SUCCESS)
+ goto pam_failed;
+
+pam_failed:
+ if (pam_err != PAM_SUCCESS) {
+ warn("PAM failed, fallback to plain old authentication");
+ pam_end(pamh, pam_err);
+ username = getlogin();
+ }
+
+ /*
+ * Now any failure should use fatal/fatalx instead of err/errx
+ * so that pam_end() is called on errors.
+ */
+#endif
if (username == NULL || (pwd = getpwnam(username)) == NULL ||
pwd->pw_uid != ruid)
pwd = getpwuid(ruid);
if (pwd == NULL)
- errx(1, "who are you?");
+ fatalx((1, "who are you?"));
+
username = strdup(pwd->pw_name);
userpass = strdup(pwd->pw_passwd);
if (username == NULL || userpass == NULL)
- err(1, "strdup");
+ fatal((1, "strdup"));
+#ifdef USE_PAM
+ /* Get PAM environment */
+ if ((pam_err == PAM_SUCCESS) &&
+ ((pam_envlist = pam_getenvlist(pamh)) != NULL)) {
+ for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
+ putenv(*pam_env);
+ free(*pam_env);
+ }
+ free(pam_envlist);
+ }
+#endif
if (asme) {
if (pwd->pw_shell && *pwd->pw_shell) {
@@ -211,13 +301,13 @@
np = *argv ? argv : argv-1;
if ((pwd = getpwnam(user)) == NULL)
- errx(1, "unknown login %s", user);
+ fatalx((1, "unknown login %s", user));
#ifdef LOGIN_CAP
/* force the usage of specified class */
if (class) {
if (ruid)
- errx(1, "Only root may use -c");
+ fatalx((1, "Only root may use -c"));
pwd->pw_class = class;
}
@@ -235,6 +325,9 @@
#ifdef KERBEROS
&& (!use_kerberos || kerberos(username, user, pwd->pw_uid))
#endif
+#ifdef USE_PAM
+ && (pam_err != PAM_SUCCESS)
+#endif
) {
char *pass = pwd->pw_passwd;
int ok = pwd->pw_uid != 0;
@@ -260,17 +353,18 @@
ok = check_ingroup(-1, SU_GROUP, username, 1);
}
if (!ok)
- errx(1,
+ fatalx((1,
"you are not listed in the correct secondary group (%s) to su %s.",
- SU_GROUP, user);
+ SU_GROUP, user));
/* if target requires a password, verify it */
if (*pass) {
p = getpass("Password:");
#ifdef SKEY
if (strcasecmp(p, "s/key") == 0) {
- if (skey_haskey(user))
- errx(1, "Sorry, you have no s/key.");
- else {
+ if (skey_haskey(user)) {
+ fatalx((1,
+ "Sorry, you have no s/key."));
+ } else {
if (skey_authenticate(user)) {
goto badlogin;
}
@@ -294,7 +388,7 @@
if (asme) {
/* if asme and non-standard target shell, must be root */
if (!chshell(pwd->pw_shell) && ruid)
- errx(1,"permission denied (shell).");
+ fatalx((1,"permission denied (shell)."));
} else if (pwd->pw_shell && *pwd->pw_shell) {
shell = pwd->pw_shell;
iscsh = UNSET;
@@ -312,6 +406,34 @@
if (iscsh == UNSET)
iscsh = strstr(avshell, "csh") ? YES : NO;
+#ifdef USE_PAM
+ /*
+ * If PAM is in use, we must release PAM ressources and close
+ * the session after su child exits. That require a fork now,
+ * before we drop the root privs (needed for PAM)
+ */
+ if (pam_err == PAM_SUCCESS) {
+ switch(pid = fork()) {
+ case -1:
+ fatal((1, "fork"));
+ break;
+ case 0: /* child */
+ break;
+ default: /* parent */
+ waitpid(pid, &status, 0);
+ pam_err = pam_close_session(pamh, 0);
+ pam_end(pamh, pam_err);
+
+ exit(WEXITSTATUS(status));
+ break;
+ }
+ }
+
+ /*
+ * Everything here happens in the child, it should not
+ * do any PAM operation anymore (don't use fatal/fatalx)
+ */
+#endif
/* set permissions */
#ifdef LOGIN_CAP
if (setusercontext(lc, pwd, pwd->pw_uid,
Home |
Main Index |
Thread Index |
Old Index