summaryrefslogtreecommitdiff
path: root/usr/src/cmd/ssh/libssh/common
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/ssh/libssh/common')
-rw-r--r--usr/src/cmd/ssh/libssh/common/misc.c66
-rw-r--r--usr/src/cmd/ssh/libssh/common/uidswap.c78
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);
}