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