source: openpam/trunk/bin/su/su.c @ 221

Last change on this file since 221 was 221, checked in by des, 11 years ago

Update copyright dates for files that have changed this year. Also
change the copyright date on generated man pages from 2002 to 2001-2003
since work on this part of OpenPAM started in late 2001.

File size: 5.0 KB
Line 
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#10 $
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 <string.h>
45#include <syslog.h>
46#include <unistd.h>
47
48#include <security/pam_appl.h>
49#include <security/openpam.h>   /* for openpam_ttyconv() */
50
51extern char **environ;
52
53static pam_handle_t *pamh;
54static struct pam_conv pamc;
55
56static void
57usage(void)
58{
59
60        fprintf(stderr, "Usage: su [login [args]]\n");
61        exit(1);
62}
63
64int
65main(int argc, char *argv[])
66{
67        char hostname[MAXHOSTNAMELEN];
68        const char *user, *tty;
69        char **args, **pam_envlist, **pam_env;
70        struct passwd *pwd;
71        int o, pam_err, status;
72        pid_t pid;
73
74        while ((o = getopt(argc, argv, "h")) != -1)
75                switch (o) {
76                case 'h':
77                default:
78                        usage();
79                }
80
81        argc -= optind;
82        argv += optind;
83
84        if (argc > 0) {
85                user = *argv;
86                --argc;
87                ++argv;
88        } else {
89                user = "root";
90        }
91
92        /* initialize PAM */
93        pamc.conv = &openpam_ttyconv;
94        pam_start("su", user, &pamc, &pamh);
95
96        /* set some items */
97        gethostname(hostname, sizeof(hostname));
98        if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)
99                goto pamerr;
100        user = getlogin();
101        if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS)
102                goto pamerr;
103        tty = ttyname(STDERR_FILENO);
104        if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)
105                goto pamerr;
106
107        /* authenticate the applicant */
108        if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS)
109                goto pamerr;
110        if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD)
111                pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
112        if (pam_err != PAM_SUCCESS)
113                goto pamerr;
114
115        /* establish the requested credentials */
116        if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
117                goto pamerr;
118
119        /* authentication succeeded; open a session */
120        if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
121                goto pamerr;
122
123        /* get mapped user name; PAM may have changed it */
124        pam_err = pam_get_item(pamh, PAM_USER, (const void **)&user);
125        if (pam_err != PAM_SUCCESS || (pwd = getpwnam(user)) == NULL)
126                goto pamerr;
127
128        /* export PAM environment */
129        if ((pam_envlist = pam_getenvlist(pamh)) != NULL) {
130                for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
131                        putenv(*pam_env);
132                        free(*pam_env);
133                }
134                free(pam_envlist);
135        }
136
137        /* build argument list */
138        if ((args = calloc(argc + 2, sizeof *args)) == NULL) {
139                warn("calloc()");
140                goto err;
141        }
142        *args = pwd->pw_shell;
143        memcpy(args + 1, argv, argc * sizeof *args);
144
145        /* fork and exec */
146        switch ((pid = fork())) {
147        case -1:
148                warn("fork()");
149                goto err;
150        case 0:
151                /* child: give up privs and start a shell */
152
153                /* set uid and groups */
154                if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
155                        warn("initgroups()");
156                        _exit(1);
157                }
158                if (setgid(pwd->pw_gid) == -1) {
159                        warn("setgid()");
160                        _exit(1);
161                }
162                if (setuid(pwd->pw_uid) == -1) {
163                        warn("setuid()");
164                        _exit(1);
165                }
166                execve(*args, args, environ);
167                warn("execve()");
168                _exit(1);
169        default:
170                /* parent: wait for child to exit */
171                waitpid(pid, &status, 0);
172
173                /* close the session and release PAM resources */
174                pam_err = pam_close_session(pamh, 0);
175                pam_end(pamh, pam_err);
176
177                exit(WEXITSTATUS(status));
178        }
179
180pamerr:
181        fprintf(stderr, "Sorry\n");
182err:
183        pam_end(pamh, pam_err);
184        exit(1);
185}
Note: See TracBrowser for help on using the repository browser.