zlogin.c (634e26ec75c89095090605284938356a3145f2b8) | zlogin.c (cb8a054b1ab30d5caa746e6c44f29d4c9d3071c1) |
---|---|
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE --- 5 unchanged lines hidden (view full) --- 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21/* | 1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE --- 5 unchanged lines hidden (view full) --- 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21/* |
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. | 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. |
24 */ 25 26/* 27 * zlogin provides three types of login which allow users in the global 28 * zone to access non-global zones. 29 * 30 * - "interactive login" is similar to rlogin(1); for example, the user could 31 * issue 'zlogin my-zone' or 'zlogin -e ^ -l me my-zone'. The user is --- 48 unchanged lines hidden (view full) --- 80#include <zone.h> 81#include <fcntl.h> 82#include <libdevinfo.h> 83#include <libintl.h> 84#include <locale.h> 85#include <libzonecfg.h> 86#include <libcontract.h> 87#include <libbrand.h> | 23 */ 24 25/* 26 * zlogin provides three types of login which allow users in the global 27 * zone to access non-global zones. 28 * 29 * - "interactive login" is similar to rlogin(1); for example, the user could 30 * issue 'zlogin my-zone' or 'zlogin -e ^ -l me my-zone'. The user is --- 48 unchanged lines hidden (view full) --- 79#include <zone.h> 80#include <fcntl.h> 81#include <libdevinfo.h> 82#include <libintl.h> 83#include <locale.h> 84#include <libzonecfg.h> 85#include <libcontract.h> 86#include <libbrand.h> |
87#include <auth_list.h> 88#include <auth_attr.h> 89#include <secdb.h> |
|
88 89static int masterfd; 90static struct termios save_termios; 91static struct termios effective_termios; 92static int save_fd; 93static struct winsize winsize; 94static volatile int dead; 95static volatile pid_t child_pid = -1; 96static int interactive = 0; 97static priv_set_t *dropprivs; 98 99static int nocmdchar = 0; 100static int failsafe = 0; 101static char cmdchar = '~'; 102 103static int pollerr = 0; 104 105static const char *pname; | 90 91static int masterfd; 92static struct termios save_termios; 93static struct termios effective_termios; 94static int save_fd; 95static struct winsize winsize; 96static volatile int dead; 97static volatile pid_t child_pid = -1; 98static int interactive = 0; 99static priv_set_t *dropprivs; 100 101static int nocmdchar = 0; 102static int failsafe = 0; 103static char cmdchar = '~'; 104 105static int pollerr = 0; 106 107static const char *pname; |
108static char *username; |
|
106 | 109 |
110/* 111 * When forced_login is true, the user is not prompted 112 * for an authentication password in the target zone. 113 */ 114static boolean_t forced_login = B_FALSE; 115 |
|
107#if !defined(TEXT_DOMAIN) /* should be defined by cc -D */ 108#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ 109#endif 110 111#define SUPATH "/usr/bin/su" 112#define FAILSAFESHELL "/sbin/sh" 113#define DEFAULTSHELL "/sbin/sh" 114#define DEF_PATH "/usr/sbin:/usr/bin" --- 902 unchanged lines hidden (view full) --- 1017zone_login_cmd(brand_handle_t bh, const char *login) 1018{ 1019 static char result_buf[ARG_MAX]; 1020 char **new_argv, *ptr, *lasts; 1021 int n, a; 1022 1023 /* Get the login command for the target zone. */ 1024 bzero(result_buf, sizeof (result_buf)); | 116#if !defined(TEXT_DOMAIN) /* should be defined by cc -D */ 117#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ 118#endif 119 120#define SUPATH "/usr/bin/su" 121#define FAILSAFESHELL "/sbin/sh" 122#define DEFAULTSHELL "/sbin/sh" 123#define DEF_PATH "/usr/sbin:/usr/bin" --- 902 unchanged lines hidden (view full) --- 1026zone_login_cmd(brand_handle_t bh, const char *login) 1027{ 1028 static char result_buf[ARG_MAX]; 1029 char **new_argv, *ptr, *lasts; 1030 int n, a; 1031 1032 /* Get the login command for the target zone. */ 1033 bzero(result_buf, sizeof (result_buf)); |
1025 if (brand_get_login_cmd(bh, login, 1026 result_buf, sizeof (result_buf)) != 0) 1027 return (NULL); | |
1028 | 1034 |
1035 if (forced_login) { 1036 if (brand_get_forcedlogin_cmd(bh, login, 1037 result_buf, sizeof (result_buf)) != 0) 1038 return (NULL); 1039 } else { 1040 if (brand_get_login_cmd(bh, login, 1041 result_buf, sizeof (result_buf)) != 0) 1042 return (NULL); 1043 } 1044 |
|
1029 /* 1030 * We got back a string that we'd like to execute. But since 1031 * we're not doing the execution via a shell we'll need to convert 1032 * the exec string to an array of strings. We'll do that here 1033 * but we're going to be very simplistic about it and break stuff 1034 * up based on spaces. We're not even going to support any kind 1035 * of quoting or escape characters. It's truly amazing that 1036 * there is no library function in OpenSolaris to do this for us. --- 72 unchanged lines hidden (view full) --- 1109 1110 new_argv[a++] = FAILSAFESHELL; 1111 } else { 1112 n = 5; 1113 if ((new_argv = malloc(sizeof (char *) * n)) == NULL) 1114 return (NULL); 1115 1116 new_argv[a++] = SUPATH; | 1045 /* 1046 * We got back a string that we'd like to execute. But since 1047 * we're not doing the execution via a shell we'll need to convert 1048 * the exec string to an array of strings. We'll do that here 1049 * but we're going to be very simplistic about it and break stuff 1050 * up based on spaces. We're not even going to support any kind 1051 * of quoting or escape characters. It's truly amazing that 1052 * there is no library function in OpenSolaris to do this for us. --- 72 unchanged lines hidden (view full) --- 1125 1126 new_argv[a++] = FAILSAFESHELL; 1127 } else { 1128 n = 5; 1129 if ((new_argv = malloc(sizeof (char *) * n)) == NULL) 1130 return (NULL); 1131 1132 new_argv[a++] = SUPATH; |
1133 if (strcmp(login, "root") != 0) { 1134 new_argv[a++] = "-"; 1135 n++; 1136 } |
|
1117 new_argv[a++] = (char *)login; 1118 } 1119 new_argv[a++] = "-c"; 1120 new_argv[a++] = subshell; 1121 new_argv[a++] = NULL; 1122 assert(a == n); 1123 } else { 1124 if (failsafe) { --- 507 unchanged lines hidden (view full) --- 1632 1633 /* 1634 * Move into a new process group; the zone_enter will have 1635 * placed us into zsched's session, and we want to be in 1636 * a unique process group. 1637 */ 1638 (void) setpgid(getpid(), getpid()); 1639 | 1137 new_argv[a++] = (char *)login; 1138 } 1139 new_argv[a++] = "-c"; 1140 new_argv[a++] = subshell; 1141 new_argv[a++] = NULL; 1142 assert(a == n); 1143 } else { 1144 if (failsafe) { --- 507 unchanged lines hidden (view full) --- 1652 1653 /* 1654 * Move into a new process group; the zone_enter will have 1655 * placed us into zsched's session, and we want to be in 1656 * a unique process group. 1657 */ 1658 (void) setpgid(getpid(), getpid()); 1659 |
1660 /* 1661 * The child needs to run as root to 1662 * execute the su program. 1663 */ 1664 if (setuid(0) == -1) { 1665 zperror(gettext("insufficient privilege")); 1666 return (1); 1667 } 1668 |
|
1640 (void) execve(new_args[0], new_args, new_env); 1641 zperror(gettext("exec failure")); 1642 _exit(1); 1643 } 1644 /* parent */ 1645 1646 /* close pipe sides written by child */ 1647 (void) close(stdout_pipe[1]); --- 14 unchanged lines hidden (view full) --- 1662 if (retval == -1) { 1663 child_status = 0; 1664 } 1665 } while (retval != child_pid && errno != ECHILD); 1666 1667 return (WEXITSTATUS(child_status)); 1668} 1669 | 1669 (void) execve(new_args[0], new_args, new_env); 1670 zperror(gettext("exec failure")); 1671 _exit(1); 1672 } 1673 /* parent */ 1674 1675 /* close pipe sides written by child */ 1676 (void) close(stdout_pipe[1]); --- 14 unchanged lines hidden (view full) --- 1691 if (retval == -1) { 1692 child_status = 0; 1693 } 1694 } while (retval != child_pid && errno != ECHILD); 1695 1696 return (WEXITSTATUS(child_status)); 1697} 1698 |
1699static char * 1700get_username() 1701{ 1702 uid_t uid; 1703 struct passwd *nptr; 1704 1705 /* 1706 * Authorizations are checked to restrict access based on the 1707 * requested operation and zone name, It is assumed that the 1708 * program is running with all privileges, but that the real 1709 * user ID is that of the user or role on whose behalf we are 1710 * operating. So we start by getting the username that will be 1711 * used for subsequent authorization checks. 1712 */ 1713 1714 uid = getuid(); 1715 if ((nptr = getpwuid(uid)) == NULL) { 1716 zerror(gettext("could not get user name.")); 1717 _exit(1); 1718 } 1719 return (nptr->pw_name); 1720} 1721 |
|
1670int 1671main(int argc, char **argv) 1672{ 1673 int arg, console = 0; 1674 zoneid_t zoneid; 1675 zone_state_t st; 1676 char *login = "root"; 1677 int lflag = 0; --- 6 unchanged lines hidden (view full) --- 1684 priv_set_t *privset; 1685 int tmpl_fd; 1686 char zonebrand[MAXNAMELEN]; 1687 char default_brand[MAXNAMELEN]; 1688 struct stat sb; 1689 char kernzone[ZONENAME_MAX]; 1690 brand_handle_t bh; 1691 char user_cmd[MAXPATHLEN]; | 1722int 1723main(int argc, char **argv) 1724{ 1725 int arg, console = 0; 1726 zoneid_t zoneid; 1727 zone_state_t st; 1728 char *login = "root"; 1729 int lflag = 0; --- 6 unchanged lines hidden (view full) --- 1736 priv_set_t *privset; 1737 int tmpl_fd; 1738 char zonebrand[MAXNAMELEN]; 1739 char default_brand[MAXNAMELEN]; 1740 struct stat sb; 1741 char kernzone[ZONENAME_MAX]; 1742 brand_handle_t bh; 1743 char user_cmd[MAXPATHLEN]; |
1744 char authname[MAXAUTHS]; |
|
1692 1693 (void) setlocale(LC_ALL, ""); 1694 (void) textdomain(TEXT_DOMAIN); 1695 1696 (void) getpname(argv[0]); | 1745 1746 (void) setlocale(LC_ALL, ""); 1747 (void) textdomain(TEXT_DOMAIN); 1748 1749 (void) getpname(argv[0]); |
1750 username = get_username(); |
|
1697 1698 while ((arg = getopt(argc, argv, "ECR:Se:l:")) != EOF) { 1699 switch (arg) { 1700 case 'C': 1701 console = 1; 1702 break; 1703 case 'E': 1704 nocmdchar = 1; --- 90 unchanged lines hidden (view full) --- 1795 return (1); 1796 } 1797 1798 /* 1799 * In both console and non-console cases, we require all privs. 1800 * In the console case, because we may need to startup zoneadmd. 1801 * In the non-console case in order to do zone_enter(2), zonept() 1802 * and other tasks. | 1751 1752 while ((arg = getopt(argc, argv, "ECR:Se:l:")) != EOF) { 1753 switch (arg) { 1754 case 'C': 1755 console = 1; 1756 break; 1757 case 'E': 1758 nocmdchar = 1; --- 90 unchanged lines hidden (view full) --- 1849 return (1); 1850 } 1851 1852 /* 1853 * In both console and non-console cases, we require all privs. 1854 * In the console case, because we may need to startup zoneadmd. 1855 * In the non-console case in order to do zone_enter(2), zonept() 1856 * and other tasks. |
1803 * 1804 * Future work: this solution is temporary. Ultimately, we need to 1805 * move to a flexible system which allows the global admin to 1806 * designate that a particular user can zlogin (and probably zlogin 1807 * -C) to a particular zone. This all-root business we have now is 1808 * quite sketchy. | |
1809 */ | 1857 */ |
1858 |
|
1810 if ((privset = priv_allocset()) == NULL) { 1811 zperror(gettext("priv_allocset failed")); 1812 return (1); 1813 } 1814 1815 if (getppriv(PRIV_EFFECTIVE, privset) != 0) { 1816 zperror(gettext("getppriv failed")); 1817 priv_freeset(privset); --- 4 unchanged lines hidden (view full) --- 1822 zerror(gettext("You lack sufficient privilege to run " 1823 "this command (all privs required)")); 1824 priv_freeset(privset); 1825 return (1); 1826 } 1827 priv_freeset(privset); 1828 1829 /* | 1859 if ((privset = priv_allocset()) == NULL) { 1860 zperror(gettext("priv_allocset failed")); 1861 return (1); 1862 } 1863 1864 if (getppriv(PRIV_EFFECTIVE, privset) != 0) { 1865 zperror(gettext("getppriv failed")); 1866 priv_freeset(privset); --- 4 unchanged lines hidden (view full) --- 1871 zerror(gettext("You lack sufficient privilege to run " 1872 "this command (all privs required)")); 1873 priv_freeset(privset); 1874 return (1); 1875 } 1876 priv_freeset(privset); 1877 1878 /* |
1879 * Check if user is authorized for requested usage of the zone 1880 */ 1881 1882 (void) snprintf(authname, MAXAUTHS, "%s%s%s", 1883 ZONE_MANAGE_AUTH, KV_OBJECT, zonename); 1884 if (chkauthattr(authname, username) == 0) { 1885 if (console) { 1886 zerror(gettext("%s is not authorized for console " 1887 "access to %s zone."), 1888 username, zonename); 1889 return (1); 1890 } else { 1891 (void) snprintf(authname, MAXAUTHS, "%s%s%s", 1892 ZONE_LOGIN_AUTH, KV_OBJECT, zonename); 1893 if (failsafe || !interactive) { 1894 zerror(gettext("%s is not authorized for " 1895 "failsafe or non-interactive login " 1896 "to %s zone."), username, zonename); 1897 return (1); 1898 } else if (chkauthattr(authname, username) == 0) { 1899 zerror(gettext("%s is not authorized " 1900 " to login to %s zone."), 1901 username, zonename); 1902 return (1); 1903 } 1904 } 1905 } else { 1906 forced_login = B_TRUE; 1907 } 1908 1909 /* |
|
1830 * The console is a separate case from the rest of the code; handle 1831 * it first. 1832 */ 1833 if (console) { 1834 /* 1835 * Ensure that zoneadmd for this zone is running. 1836 */ 1837 if (start_zoneadmd(zonename) == -1) --- 273 unchanged lines hidden (view full) --- 2111 * we can simply skip it. If future brands don't fall into 2112 * either category, we'll have to add a per-brand utmpx 2113 * setup hook. 2114 */ 2115 if (!failsafe && (strcmp(zonebrand, "lx") != 0)) 2116 if (setup_utmpx(slaveshortname) == -1) 2117 return (1); 2118 | 1910 * The console is a separate case from the rest of the code; handle 1911 * it first. 1912 */ 1913 if (console) { 1914 /* 1915 * Ensure that zoneadmd for this zone is running. 1916 */ 1917 if (start_zoneadmd(zonename) == -1) --- 273 unchanged lines hidden (view full) --- 2191 * we can simply skip it. If future brands don't fall into 2192 * either category, we'll have to add a per-brand utmpx 2193 * setup hook. 2194 */ 2195 if (!failsafe && (strcmp(zonebrand, "lx") != 0)) 2196 if (setup_utmpx(slaveshortname) == -1) 2197 return (1); 2198 |
2199 /* 2200 * The child needs to run as root to 2201 * execute the brand's login program. 2202 */ 2203 if (setuid(0) == -1) { 2204 zperror(gettext("insufficient privilege")); 2205 return (1); 2206 } 2207 |
|
2119 (void) execve(new_args[0], new_args, new_env); 2120 zperror(gettext("exec failure")); 2121 return (1); 2122 } | 2208 (void) execve(new_args[0], new_args, new_env); 2209 zperror(gettext("exec failure")); 2210 return (1); 2211 } |
2212 |
|
2123 (void) ct_tmpl_clear(tmpl_fd); 2124 (void) close(tmpl_fd); 2125 2126 /* 2127 * The rest is only for the parent process. 2128 */ 2129 (void) sigset(SIGWINCH, sigwinch); 2130 --- 18 unchanged lines hidden --- | 2213 (void) ct_tmpl_clear(tmpl_fd); 2214 (void) close(tmpl_fd); 2215 2216 /* 2217 * The rest is only for the parent process. 2218 */ 2219 (void) sigset(SIGWINCH, sigwinch); 2220 --- 18 unchanged lines hidden --- |