1 /*- 2 * Copyright (c) 2002 Networks Associates Technology, Inc. 3 * All rights reserved. 4 * 5 * This software was developed for the FreeBSD Project by ThinkSec AS and 6 * NAI Labs, the Security Research Division of Network Associates, Inc. 7 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 8 * 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#5 $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/wait.h> 39 40 #include <err.h> 41 #include <pwd.h> 42 #include <stdio.h> 43 #include <syslog.h> 44 #include <unistd.h> 45 46 #include <security/pam_appl.h> 47 #include <security/openpam.h> 48 49 static pam_handle_t *pamh; 50 static struct pam_conv pamc; 51 52 static void 53 usage(void) 54 { 55 56 fprintf(stderr, "Usage: su [login [args]]\n"); 57 exit(1); 58 } 59 60 static int 61 check(const char *func, int pam_err) 62 { 63 64 if (pam_err == PAM_SUCCESS || pam_err == PAM_NEW_AUTHTOK_REQD) 65 return pam_err; 66 openlog("su", LOG_CONS, LOG_AUTH); 67 syslog(LOG_ERR, "%s(): %s", func, pam_strerror(pamh, pam_err)); 68 errx(1, "Sorry."); 69 } 70 71 int 72 main(int argc, char *argv[]) 73 { 74 char hostname[MAXHOSTNAMELEN]; 75 const char *user, *tty; 76 struct passwd *pwd; 77 int o, status; 78 pid_t pid; 79 80 while ((o = getopt(argc, argv, "h")) != -1) 81 switch (o) { 82 case 'h': 83 default: 84 usage(); 85 } 86 87 argc -= optind; 88 argv += optind; 89 90 /* initialize PAM */ 91 pamc.conv = &openpam_ttyconv; 92 pam_start("su", argc ? *argv : "root", &pamc, &pamh); 93 94 /* set some items */ 95 gethostname(hostname, sizeof(hostname)); 96 check("pam_set_item", pam_set_item(pamh, PAM_RHOST, hostname)); 97 user = getlogin(); 98 check("pam_set_item", pam_set_item(pamh, PAM_RUSER, user)); 99 tty = ttyname(STDERR_FILENO); 100 check("pam_set_item", pam_set_item(pamh, PAM_TTY, tty)); 101 102 /* authenticate the applicant */ 103 check("pam_authenticate", pam_authenticate(pamh, 0)); 104 if (check("pam_acct_mgmt", pam_acct_mgmt(pamh, 0)) == 105 PAM_NEW_AUTHTOK_REQD) 106 check("pam_chauthtok", 107 pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK)); 108 109 /* establish the requested credentials */ 110 check("pam_setcred", pam_setcred(pamh, PAM_ESTABLISH_CRED)); 111 112 /* authentication succeeded; open a session */ 113 check("pam_open_session", pam_open_session(pamh, 0)); 114 115 if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) 116 err(1, "initgroups()"); 117 if (setuid(pwd->pw_uid) == -1) 118 err(1, "setuid()"); 119 120 /* XXX export environment variables */ 121 122 switch ((pid = fork())) { 123 case -1: 124 err(1, "fork()"); 125 case 0: 126 /* child: start a shell */ 127 *argv = pwd->pw_shell; 128 execvp(*argv, argv); 129 err(1, "execvp()"); 130 default: 131 /* parent: wait for child to exit */ 132 waitpid(pid, &status, 0); 133 if (WIFEXITED(status)) 134 status = WEXITSTATUS(status); 135 else 136 status = 1; 137 } 138 139 /* close the session and release PAM resources */ 140 check("pam_close_session", pam_close_session(pamh, 0)); 141 check("pam_end", pam_end(pamh, 0)); 142 143 exit(status); 144 } 145