1 /*- 2 * Copyright (c) 2002-2003 Networks Associates Technology, Inc. 3 * All rights reserved. 4 * 5 * This software was developed for the FreeBSD Project by ThinkSec AS and 6 * Network Associates Laboratories, the Security Research Division of 7 * Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 8 * ("CBOSS"), as part of the DARPA CHATS research program. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote 19 * products derived from this software without specific prior written 20 * permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $P4: //depot/projects/openpam/bin/su/su.c#12 $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/wait.h> 39 40 #include <err.h> 41 #include <grp.h> 42 #include <pwd.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <syslog.h> 47 #include <unistd.h> 48 49 #include <security/pam_appl.h> 50 #include <security/openpam.h> /* for openpam_ttyconv() */ 51 52 extern char **environ; 53 54 static pam_handle_t *pamh; 55 static struct pam_conv pamc; 56 57 static void 58 usage(void) 59 { 60 61 fprintf(stderr, "Usage: su [login [args]]\n"); 62 exit(1); 63 } 64 65 int 66 main(int argc, char *argv[]) 67 { 68 char hostname[MAXHOSTNAMELEN]; 69 const char *user, *tty; 70 char **args, **pam_envlist, **pam_env; 71 struct passwd *pwd; 72 int o, pam_err, status; 73 pid_t pid; 74 75 while ((o = getopt(argc, argv, "h")) != -1) 76 switch (o) { 77 case 'h': 78 default: 79 usage(); 80 } 81 82 argc -= optind; 83 argv += optind; 84 85 if (argc > 0) { 86 user = *argv; 87 --argc; 88 ++argv; 89 } else { 90 user = "root"; 91 } 92 93 /* initialize PAM */ 94 pamc.conv = &openpam_ttyconv; 95 pam_start("su", user, &pamc, &pamh); 96 97 /* set some items */ 98 gethostname(hostname, sizeof(hostname)); 99 if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS) 100 goto pamerr; 101 user = getlogin(); 102 if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS) 103 goto pamerr; 104 tty = ttyname(STDERR_FILENO); 105 if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS) 106 goto pamerr; 107 108 /* authenticate the applicant */ 109 if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS) 110 goto pamerr; 111 if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD) 112 pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); 113 if (pam_err != PAM_SUCCESS) 114 goto pamerr; 115 116 /* establish the requested credentials */ 117 if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) 118 goto pamerr; 119 120 /* authentication succeeded; open a session */ 121 if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS) 122 goto pamerr; 123 124 /* get mapped user name; PAM may have changed it */ 125 pam_err = pam_get_item(pamh, PAM_USER, (const void **)&user); 126 if (pam_err != PAM_SUCCESS || (pwd = getpwnam(user)) == NULL) 127 goto pamerr; 128 129 /* export PAM environment */ 130 if ((pam_envlist = pam_getenvlist(pamh)) != NULL) { 131 for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) { 132 putenv(*pam_env); 133 free(*pam_env); 134 } 135 free(pam_envlist); 136 } 137 138 /* build argument list */ 139 if ((args = calloc(argc + 2, sizeof *args)) == NULL) { 140 warn("calloc()"); 141 goto err; 142 } 143 *args = pwd->pw_shell; 144 memcpy(args + 1, argv, argc * sizeof *args); 145 146 /* fork and exec */ 147 switch ((pid = fork())) { 148 case -1: 149 warn("fork()"); 150 goto err; 151 case 0: 152 /* child: give up privs and start a shell */ 153 154 /* set uid and groups */ 155 if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) { 156 warn("initgroups()"); 157 _exit(1); 158 } 159 if (setgid(pwd->pw_gid) == -1) { 160 warn("setgid()"); 161 _exit(1); 162 } 163 if (setuid(pwd->pw_uid) == -1) { 164 warn("setuid()"); 165 _exit(1); 166 } 167 execve(*args, args, environ); 168 warn("execve()"); 169 _exit(1); 170 default: 171 /* parent: wait for child to exit */ 172 waitpid(pid, &status, 0); 173 174 /* close the session and release PAM resources */ 175 pam_err = pam_close_session(pamh, 0); 176 pam_end(pamh, pam_err); 177 178 exit(WEXITSTATUS(status)); 179 } 180 181 pamerr: 182 fprintf(stderr, "Sorry\n"); 183 err: 184 pam_end(pamh, pam_err); 185 exit(1); 186 } 187