diff options
Diffstat (limited to 'usr/src/cmd/ssh/libssh/common')
-rw-r--r-- | usr/src/cmd/ssh/libssh/common/misc.c | 66 | ||||
-rw-r--r-- | usr/src/cmd/ssh/libssh/common/uidswap.c | 78 |
2 files changed, 133 insertions, 11 deletions
diff --git a/usr/src/cmd/ssh/libssh/common/misc.c b/usr/src/cmd/ssh/libssh/common/misc.c index dcd7902021..e73d3f364b 100644 --- a/usr/src/cmd/ssh/libssh/common/misc.c +++ b/usr/src/cmd/ssh/libssh/common/misc.c @@ -22,15 +22,13 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "includes.h" RCSID("$OpenBSD: misc.c,v 1.19 2002/03/04 17:27:39 stevesk Exp $"); -#pragma ident "%Z%%M% %I% %E% SMI" - #include "misc.h" #include "log.h" #include "xmalloc.h" @@ -439,6 +437,68 @@ freeargs(arglist *args) } /* + * Expand a string with a set of %[char] escapes. A number of escapes may be + * specified as (char *escape_chars, char *replacement) pairs. The list must + * be terminated by a NULL escape_char. Returns replaced string in memory + * allocated by xmalloc. + */ +char * +percent_expand(const char *string, ...) +{ +#define EXPAND_MAX_KEYS 16 + struct { + const char *key; + const char *repl; + } keys[EXPAND_MAX_KEYS]; + u_int num_keys, i, j; + char buf[4096]; + va_list ap; + + /* Gather keys */ + va_start(ap, string); + for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { + keys[num_keys].key = va_arg(ap, char *); + if (keys[num_keys].key == NULL) + break; + keys[num_keys].repl = va_arg(ap, char *); + if (keys[num_keys].repl == NULL) + fatal("percent_expand: NULL replacement"); + } + va_end(ap); + + if (num_keys >= EXPAND_MAX_KEYS) + fatal("percent_expand: too many keys"); + + /* Expand string */ + *buf = '\0'; + for (i = 0; *string != '\0'; string++) { + if (*string != '%') { + append: + buf[i++] = *string; + if (i >= sizeof(buf)) + fatal("percent_expand: string too long"); + buf[i] = '\0'; + continue; + } + string++; + if (*string == '%') + goto append; + for (j = 0; j < num_keys; j++) { + if (strchr(keys[j].key, *string) != NULL) { + i = strlcat(buf, keys[j].repl, sizeof(buf)); + if (i >= sizeof(buf)) + fatal("percent_expand: string too long"); + break; + } + } + if (j >= num_keys) + fatal("percent_expand: unknown key %%%c", *string); + } + return (xstrdup(buf)); +#undef EXPAND_MAX_KEYS +} + +/* * Ensure that file descriptors 0, 1 and 2 are open or directed to /dev/null, * do not touch those that are already open. */ diff --git a/usr/src/cmd/ssh/libssh/common/uidswap.c b/usr/src/cmd/ssh/libssh/common/uidswap.c index 31acab9341..f5892ee2ac 100644 --- a/usr/src/cmd/ssh/libssh/common/uidswap.c +++ b/usr/src/cmd/ssh/libssh/common/uidswap.c @@ -11,17 +11,18 @@ * called by a name other than "ssh" or "Secure Shell". */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "includes.h" RCSID("$OpenBSD: uidswap.c,v 1.23 2002/07/15 17:15:31 stevesk Exp $"); -#pragma ident "%Z%%M% %I% %E% SMI" +#include <priv.h> #include "log.h" #include "uidswap.h" +#include "servconf.h" /* * Note: all these functions must work in all of the following cases: @@ -164,21 +165,82 @@ restore_uid(void) } /* - * Permanently sets all uids to the given uid. This cannot be - * called while temporarily_use_uid is effective. + * Permanently sets all uids to the given uid. This cannot be called while + * temporarily_use_uid is effective. Note that when the ChrootDirectory option + * is in use we keep a few privileges so that we can call chroot(2) later while + * already running under UIDs of a connecting user. */ void -permanently_set_uid(struct passwd *pw) +permanently_set_uid(struct passwd *pw, char *chroot_directory) { + priv_set_t *pset; + if (temporarily_use_uid_effective) - fatal("permanently_set_uid: temporarily_use_uid effective"); - debug("permanently_set_uid: %u/%u", (u_int)pw->pw_uid, - (u_int)pw->pw_gid); + fatal("%s: temporarily_use_uid effective", __func__); + + debug("%s: %u/%u", __func__, (u_int)pw->pw_uid, (u_int)pw->pw_gid); + if (initgroups(pw->pw_name, pw->pw_gid) < 0) fatal("initgroups: %s: %.100s", pw->pw_name, strerror(errno)); + if (setgid(pw->pw_gid) < 0) fatal("setgid %u: %.100s", (u_int)pw->pw_gid, strerror(errno)); + + /* + * If root is connecting we are done now. Note that we must have called + * setgid() in case that the SSH server was run under a group other than + * root. + */ + if (pw->pw_uid == 0) + return; + + /* + * This means we will keep all privileges after the UID change. + */ + if (setpflags(PRIV_AWARE, 1) != 0) + fatal("setpflags: %s", strerror(errno)); + + /* Now we are running under UID of the user. */ if (setuid(pw->pw_uid) < 0) fatal("setuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno)); + + /* + * We will run with the privileges from the Inheritable set as + * we would have after exec(2) if we had stayed in NPA mode + * before setuid(2) call (see privileges(5), user_attr(4), and + * pam_unix_cred(5)). We want to run with P = E = I, with I as + * set by pam_unix_cred(5). We also add PRIV_PROC_CHROOT, + * obviously, and then PRIV_PROC_FORK and PRIV_PROC_EXEC, since + * those two might have been removed from the I set. Note that + * we are expected to finish the login process without them in + * the I set, the important thing is that those not be passed on + * to a shell or a subsystem later if they were not set in + * pam_unix_cred(5). + */ + if ((pset = priv_allocset()) == NULL) + fatal("priv_allocset: %s", strerror(errno)); + if (getppriv(PRIV_INHERITABLE, pset) != 0) + fatal("getppriv: %s", strerror(errno)); + + /* We do not need PRIV_PROC_CHROOT unless chroot()ing. */ + if (chroot_requested(chroot_directory) && + priv_addset(pset, PRIV_PROC_CHROOT) == -1) { + fatal("%s: priv_addset failed", __func__); + } + + if (priv_addset(pset, PRIV_PROC_FORK) == -1 || + priv_addset(pset, PRIV_PROC_EXEC) == -1) { + fatal("%s: priv_addset failed", __func__); + } + + /* Set only P; this will also set E. */ + if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) == -1) + fatal("setppriv: %s", strerror(errno)); + + /* We don't need the PA flag anymore. */ + if (setpflags(PRIV_AWARE, 0) == -1) + fatal("setpflags: %s", strerror(errno)); + + priv_freeset(pset); } |