summaryrefslogtreecommitdiff
path: root/usr/src/cmd/zlogin
diff options
context:
space:
mode:
authorGlenn Faden <Glenn.Faden@Sun.COM>2010-06-07 14:07:27 -0700
committerGlenn Faden <Glenn.Faden@Sun.COM>2010-06-07 14:07:27 -0700
commitcb8a054b1ab30d5caa746e6c44f29d4c9d3071c1 (patch)
tree4a37082bb4bff314d96557daae302116f1342448 /usr/src/cmd/zlogin
parent4b808d4335c4994a826d481c0af6c0ccaafbeff8 (diff)
downloadillumos-joyent-cb8a054b1ab30d5caa746e6c44f29d4c9d3071c1.tar.gz
4963290 RFE: implement flexible zone administration that doesn't require uid=0
PSARC/2010/132 Delegated Administration for Zones
Diffstat (limited to 'usr/src/cmd/zlogin')
-rw-r--r--usr/src/cmd/zlogin/Makefile5
-rw-r--r--usr/src/cmd/zlogin/zlogin.c112
2 files changed, 103 insertions, 14 deletions
diff --git a/usr/src/cmd/zlogin/Makefile b/usr/src/cmd/zlogin/Makefile
index 4a9e4d0224..2b867ac223 100644
--- a/usr/src/cmd/zlogin/Makefile
+++ b/usr/src/cmd/zlogin/Makefile
@@ -19,8 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
PROG = zlogin
@@ -28,7 +27,7 @@ PROG = zlogin
include ../Makefile.cmd
LINTFLAGS += -u
-LDLIBS += -lsocket -lzonecfg -lcontract -lbrand
+LDLIBS += -lsocket -lzonecfg -lcontract -lbrand -lsecdb
CFLAGS += $(CCVERBOSE)
FILEMODE = 0555
diff --git a/usr/src/cmd/zlogin/zlogin.c b/usr/src/cmd/zlogin/zlogin.c
index 78ce2ed394..04950a99db 100644
--- a/usr/src/cmd/zlogin/zlogin.c
+++ b/usr/src/cmd/zlogin/zlogin.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -85,6 +84,9 @@
#include <libzonecfg.h>
#include <libcontract.h>
#include <libbrand.h>
+#include <auth_list.h>
+#include <auth_attr.h>
+#include <secdb.h>
static int masterfd;
static struct termios save_termios;
@@ -103,6 +105,13 @@ static char cmdchar = '~';
static int pollerr = 0;
static const char *pname;
+static char *username;
+
+/*
+ * When forced_login is true, the user is not prompted
+ * for an authentication password in the target zone.
+ */
+static boolean_t forced_login = B_FALSE;
#if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
@@ -1022,9 +1031,16 @@ zone_login_cmd(brand_handle_t bh, const char *login)
/* Get the login command for the target zone. */
bzero(result_buf, sizeof (result_buf));
- if (brand_get_login_cmd(bh, login,
- result_buf, sizeof (result_buf)) != 0)
- return (NULL);
+
+ if (forced_login) {
+ if (brand_get_forcedlogin_cmd(bh, login,
+ result_buf, sizeof (result_buf)) != 0)
+ return (NULL);
+ } else {
+ if (brand_get_login_cmd(bh, login,
+ result_buf, sizeof (result_buf)) != 0)
+ return (NULL);
+ }
/*
* We got back a string that we'd like to execute. But since
@@ -1114,6 +1130,10 @@ prep_args(brand_handle_t bh, const char *login, char **argv)
return (NULL);
new_argv[a++] = SUPATH;
+ if (strcmp(login, "root") != 0) {
+ new_argv[a++] = "-";
+ n++;
+ }
new_argv[a++] = (char *)login;
}
new_argv[a++] = "-c";
@@ -1637,6 +1657,15 @@ noninteractive_login(char *zonename, const char *user_cmd, zoneid_t zoneid,
*/
(void) setpgid(getpid(), getpid());
+ /*
+ * The child needs to run as root to
+ * execute the su program.
+ */
+ if (setuid(0) == -1) {
+ zperror(gettext("insufficient privilege"));
+ return (1);
+ }
+
(void) execve(new_args[0], new_args, new_env);
zperror(gettext("exec failure"));
_exit(1);
@@ -1667,6 +1696,29 @@ noninteractive_login(char *zonename, const char *user_cmd, zoneid_t zoneid,
return (WEXITSTATUS(child_status));
}
+static char *
+get_username()
+{
+ uid_t uid;
+ struct passwd *nptr;
+
+ /*
+ * Authorizations are checked to restrict access based on the
+ * requested operation and zone name, It is assumed that the
+ * program is running with all privileges, but that the real
+ * user ID is that of the user or role on whose behalf we are
+ * operating. So we start by getting the username that will be
+ * used for subsequent authorization checks.
+ */
+
+ uid = getuid();
+ if ((nptr = getpwuid(uid)) == NULL) {
+ zerror(gettext("could not get user name."));
+ _exit(1);
+ }
+ return (nptr->pw_name);
+}
+
int
main(int argc, char **argv)
{
@@ -1689,11 +1741,13 @@ main(int argc, char **argv)
char kernzone[ZONENAME_MAX];
brand_handle_t bh;
char user_cmd[MAXPATHLEN];
+ char authname[MAXAUTHS];
(void) setlocale(LC_ALL, "");
(void) textdomain(TEXT_DOMAIN);
(void) getpname(argv[0]);
+ username = get_username();
while ((arg = getopt(argc, argv, "ECR:Se:l:")) != EOF) {
switch (arg) {
@@ -1800,13 +1854,8 @@ main(int argc, char **argv)
* In the console case, because we may need to startup zoneadmd.
* In the non-console case in order to do zone_enter(2), zonept()
* and other tasks.
- *
- * Future work: this solution is temporary. Ultimately, we need to
- * move to a flexible system which allows the global admin to
- * designate that a particular user can zlogin (and probably zlogin
- * -C) to a particular zone. This all-root business we have now is
- * quite sketchy.
*/
+
if ((privset = priv_allocset()) == NULL) {
zperror(gettext("priv_allocset failed"));
return (1);
@@ -1827,6 +1876,37 @@ main(int argc, char **argv)
priv_freeset(privset);
/*
+ * Check if user is authorized for requested usage of the zone
+ */
+
+ (void) snprintf(authname, MAXAUTHS, "%s%s%s",
+ ZONE_MANAGE_AUTH, KV_OBJECT, zonename);
+ if (chkauthattr(authname, username) == 0) {
+ if (console) {
+ zerror(gettext("%s is not authorized for console "
+ "access to %s zone."),
+ username, zonename);
+ return (1);
+ } else {
+ (void) snprintf(authname, MAXAUTHS, "%s%s%s",
+ ZONE_LOGIN_AUTH, KV_OBJECT, zonename);
+ if (failsafe || !interactive) {
+ zerror(gettext("%s is not authorized for "
+ "failsafe or non-interactive login "
+ "to %s zone."), username, zonename);
+ return (1);
+ } else if (chkauthattr(authname, username) == 0) {
+ zerror(gettext("%s is not authorized "
+ " to login to %s zone."),
+ username, zonename);
+ return (1);
+ }
+ }
+ } else {
+ forced_login = B_TRUE;
+ }
+
+ /*
* The console is a separate case from the rest of the code; handle
* it first.
*/
@@ -2116,10 +2196,20 @@ main(int argc, char **argv)
if (setup_utmpx(slaveshortname) == -1)
return (1);
+ /*
+ * The child needs to run as root to
+ * execute the brand's login program.
+ */
+ if (setuid(0) == -1) {
+ zperror(gettext("insufficient privilege"));
+ return (1);
+ }
+
(void) execve(new_args[0], new_args, new_env);
zperror(gettext("exec failure"));
return (1);
}
+
(void) ct_tmpl_clear(tmpl_fd);
(void) close(tmpl_fd);