xref: /freebsd/crypto/heimdal/appl/su/su.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov  * Copyright (c) 1999 - 2008 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray  * modification, are permitted provided that the following conditions
8b528cefcSMark Murray  * are met:
9b528cefcSMark Murray  *
10b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray  *
13b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray  *
17b528cefcSMark Murray  * 3. Neither the name of KTH nor the names of its contributors may be
18b528cefcSMark Murray  *    used to endorse or promote products derived from this software without
19b528cefcSMark Murray  *    specific prior written permission.
20b528cefcSMark Murray  *
21b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22b528cefcSMark Murray  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24b528cefcSMark Murray  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25b528cefcSMark Murray  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26b528cefcSMark Murray  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27b528cefcSMark Murray  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28b528cefcSMark Murray  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29b528cefcSMark Murray  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30b528cefcSMark Murray  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31b528cefcSMark Murray  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
32b528cefcSMark Murray 
33b528cefcSMark Murray #include <config.h>
34b528cefcSMark Murray 
35*ae771770SStanislav Sedov RCSID("$Id$");
36b528cefcSMark Murray 
37b528cefcSMark Murray #include <stdio.h>
38b528cefcSMark Murray #include <stdlib.h>
39b528cefcSMark Murray #include <string.h>
40b528cefcSMark Murray 
41b528cefcSMark Murray #include <syslog.h>
42b528cefcSMark Murray 
43b528cefcSMark Murray #ifdef HAVE_PATHS_H
44b528cefcSMark Murray #include <paths.h>
45b528cefcSMark Murray #endif
46b528cefcSMark Murray 
47b528cefcSMark Murray #ifdef HAVE_SHADOW_H
48b528cefcSMark Murray #include <shadow.h>
49b528cefcSMark Murray #endif
50b528cefcSMark Murray 
51b528cefcSMark Murray #include <pwd.h>
5233f12199SDoug Rabson #ifdef HAVE_CRYPT_H
5333f12199SDoug Rabson #include <crypt.h>
5433f12199SDoug Rabson #endif
55b528cefcSMark Murray 
560cadf2f4SJacques Vidrine #include "crypto-headers.h"
578373020dSJacques Vidrine #ifdef KRB5
58b528cefcSMark Murray #include <krb5.h>
598373020dSJacques Vidrine #endif
60bbd80c28SJacques Vidrine #include <kafs.h>
61b528cefcSMark Murray #include <err.h>
62b528cefcSMark Murray #include <roken.h>
63b528cefcSMark Murray #include <getarg.h>
64b528cefcSMark Murray 
6533f12199SDoug Rabson #include "supaths.h"
66b528cefcSMark Murray 
67*ae771770SStanislav Sedov #if !HAVE_DECL_ENVIRON
68*ae771770SStanislav Sedov extern char **environ;
69*ae771770SStanislav Sedov #endif
70*ae771770SStanislav Sedov 
71b528cefcSMark Murray int kerberos_flag = 1;
72b528cefcSMark Murray int csh_f_flag;
73b528cefcSMark Murray int full_login;
74b528cefcSMark Murray int env_flag;
75b528cefcSMark Murray char *kerberos_instance = "root";
76b528cefcSMark Murray int help_flag;
77b528cefcSMark Murray int version_flag;
78b528cefcSMark Murray char *cmd;
798373020dSJacques Vidrine char tkfile[256];
80b528cefcSMark Murray 
81b528cefcSMark Murray struct getargs args[] = {
82b528cefcSMark Murray     { "kerberos", 'K', arg_negative_flag, &kerberos_flag,
83b528cefcSMark Murray       "don't use kerberos" },
84b528cefcSMark Murray     { NULL,	  'f', arg_flag,	  &csh_f_flag,
85b528cefcSMark Murray       "don't read .cshrc" },
86b528cefcSMark Murray     { "full",	  'l', arg_flag,          &full_login,
87b528cefcSMark Murray       "simulate full login" },
88b528cefcSMark Murray     { NULL,	  'm', arg_flag,          &env_flag,
89b528cefcSMark Murray       "leave environment unmodified" },
90b528cefcSMark Murray     { "instance", 'i', arg_string,        &kerberos_instance,
91b528cefcSMark Murray       "root instance to use" },
92b528cefcSMark Murray     { "command",  'c', arg_string,        &cmd,
93b528cefcSMark Murray       "command to execute" },
94b528cefcSMark Murray     { "help", 	  'h', arg_flag,          &help_flag },
95b528cefcSMark Murray     { "version",  0,   arg_flag,          &version_flag },
96b528cefcSMark Murray };
97b528cefcSMark Murray 
98b528cefcSMark Murray 
99b528cefcSMark Murray static void
usage(int ret)100b528cefcSMark Murray usage (int ret)
101b528cefcSMark Murray {
102b528cefcSMark Murray     arg_printusage (args,
103b528cefcSMark Murray 		    sizeof(args)/sizeof(*args),
104b528cefcSMark Murray 		    NULL,
105b528cefcSMark Murray 		    "[login [shell arguments]]");
106b528cefcSMark Murray     exit (ret);
107b528cefcSMark Murray }
108b528cefcSMark Murray 
1094137ff4cSJacques Vidrine static void
free_info(struct passwd * p)1104137ff4cSJacques Vidrine free_info(struct passwd *p)
1114137ff4cSJacques Vidrine {
1124137ff4cSJacques Vidrine     free (p->pw_name);
1134137ff4cSJacques Vidrine     free (p->pw_passwd);
1144137ff4cSJacques Vidrine     free (p->pw_dir);
1154137ff4cSJacques Vidrine     free (p->pw_shell);
1164137ff4cSJacques Vidrine     free (p);
1174137ff4cSJacques Vidrine }
1184137ff4cSJacques Vidrine 
119b528cefcSMark Murray static struct passwd*
dup_info(const struct passwd * pwd)1204137ff4cSJacques Vidrine dup_info(const struct passwd *pwd)
121b528cefcSMark Murray {
122b528cefcSMark Murray     struct passwd *info;
1234137ff4cSJacques Vidrine 
124b528cefcSMark Murray     info = malloc(sizeof(*info));
125b528cefcSMark Murray     if(info == NULL)
126b528cefcSMark Murray 	return NULL;
127b528cefcSMark Murray     info->pw_name = strdup(pwd->pw_name);
128b528cefcSMark Murray     info->pw_passwd = strdup(pwd->pw_passwd);
129b528cefcSMark Murray     info->pw_uid = pwd->pw_uid;
130b528cefcSMark Murray     info->pw_gid = pwd->pw_gid;
131b528cefcSMark Murray     info->pw_dir = strdup(pwd->pw_dir);
132b528cefcSMark Murray     info->pw_shell = strdup(pwd->pw_shell);
133b528cefcSMark Murray     if(info->pw_name == NULL || info->pw_passwd == NULL ||
1344137ff4cSJacques Vidrine        info->pw_dir == NULL || info->pw_shell == NULL) {
1354137ff4cSJacques Vidrine 	free_info (info);
136b528cefcSMark Murray 	return NULL;
1374137ff4cSJacques Vidrine     }
138b528cefcSMark Murray     return info;
139b528cefcSMark Murray }
140b528cefcSMark Murray 
141b528cefcSMark Murray #ifdef KRB5
142b528cefcSMark Murray static krb5_context context;
143b528cefcSMark Murray static krb5_ccache ccache;
144b528cefcSMark Murray 
145b528cefcSMark Murray static int
krb5_verify(const struct passwd * login_info,const struct passwd * su_info,const char * kerberos_instance)1464137ff4cSJacques Vidrine krb5_verify(const struct passwd *login_info,
1474137ff4cSJacques Vidrine 	    const struct passwd *su_info,
148b528cefcSMark Murray 	    const char *kerberos_instance)
149b528cefcSMark Murray {
150b528cefcSMark Murray     krb5_error_code ret;
151b528cefcSMark Murray     krb5_principal p;
15233f12199SDoug Rabson     krb5_realm *realms, *r;
1535a83b025SJacques Vidrine     char *login_name = NULL;
15433f12199SDoug Rabson     int user_ok = 0;
155b528cefcSMark Murray 
1565a83b025SJacques Vidrine #if defined(HAVE_GETLOGIN) && !defined(POSIX_GETLOGIN)
1575a83b025SJacques Vidrine     login_name = getlogin();
1585a83b025SJacques Vidrine #endif
159b528cefcSMark Murray     ret = krb5_init_context (&context);
160b528cefcSMark Murray     if (ret) {
161b528cefcSMark Murray #if 0
1625e9cd1aeSAssar Westerlund 	warnx("krb5_init_context failed: %d", ret);
163b528cefcSMark Murray #endif
164b528cefcSMark Murray 	return 1;
165b528cefcSMark Murray     }
166b528cefcSMark Murray 
16733f12199SDoug Rabson     ret = krb5_get_default_realms(context, &realms);
16833f12199SDoug Rabson     if (ret)
16933f12199SDoug Rabson 	return 1;
17033f12199SDoug Rabson 
17133f12199SDoug Rabson     /* Check all local realms */
17233f12199SDoug Rabson     for (r = realms; *r != NULL && !user_ok; r++) {
17333f12199SDoug Rabson 
1745a83b025SJacques Vidrine 	if (login_name == NULL || strcmp (login_name, "root") == 0)
1755a83b025SJacques Vidrine 	    login_name = login_info->pw_name;
176b528cefcSMark Murray 	if (strcmp (su_info->pw_name, "root") == 0)
17733f12199SDoug Rabson 	    ret = krb5_make_principal(context, &p, *r,
1785a83b025SJacques Vidrine 				      login_name,
179b528cefcSMark Murray 				      kerberos_instance,
180b528cefcSMark Murray 				      NULL);
181b528cefcSMark Murray 	else
18233f12199SDoug Rabson 	    ret = krb5_make_principal(context, &p, *r,
183b528cefcSMark Murray 				      su_info->pw_name,
184b528cefcSMark Murray 				      NULL);
18533f12199SDoug Rabson 	if (ret) {
18633f12199SDoug Rabson 	    krb5_free_host_realm(context, realms);
187b528cefcSMark Murray 	    return 1;
18833f12199SDoug Rabson 	}
189b528cefcSMark Murray 
19033f12199SDoug Rabson 	/* if we are su-ing too root, check with krb5_kuserok */
19133f12199SDoug Rabson 	if (su_info->pw_uid == 0 && !krb5_kuserok(context, p, su_info->pw_name))
19233f12199SDoug Rabson 	    continue;
19333f12199SDoug Rabson 
194*ae771770SStanislav Sedov 	ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache);
195b528cefcSMark Murray 	if(ret) {
19633f12199SDoug Rabson 	    krb5_free_host_realm(context, realms);
1975e9cd1aeSAssar Westerlund 	    krb5_free_principal (context, p);
198b528cefcSMark Murray 	    return 1;
199b528cefcSMark Murray 	}
20033f12199SDoug Rabson   	ret = krb5_verify_user(context, p, ccache, NULL, TRUE, NULL);
201b528cefcSMark Murray 	krb5_free_principal (context, p);
202b528cefcSMark Murray 	switch (ret) {
20333f12199SDoug Rabson 	case 0:
20433f12199SDoug Rabson 	    user_ok = 1;
20533f12199SDoug Rabson 	    break;
2065e9cd1aeSAssar Westerlund 	case KRB5_LIBOS_PWDINTR :
20733f12199SDoug Rabson 	    krb5_cc_destroy(context, ccache);
2085e9cd1aeSAssar Westerlund 	    break;
209b528cefcSMark Murray 	case KRB5KRB_AP_ERR_BAD_INTEGRITY:
210b528cefcSMark Murray 	case KRB5KRB_AP_ERR_MODIFIED:
21133f12199SDoug Rabson 	    krb5_cc_destroy(context, ccache);
212b528cefcSMark Murray 	    krb5_warnx(context, "Password incorrect");
213b528cefcSMark Murray 	    break;
214b528cefcSMark Murray 	default :
21533f12199SDoug Rabson 	    krb5_cc_destroy(context, ccache);
216b528cefcSMark Murray 	    krb5_warn(context, ret, "krb5_verify_user");
217b528cefcSMark Murray 	    break;
218b528cefcSMark Murray 	}
219b528cefcSMark Murray     }
22033f12199SDoug Rabson     krb5_free_host_realm(context, realms);
22133f12199SDoug Rabson     if (!user_ok)
22233f12199SDoug Rabson 	return 1;
223b528cefcSMark Murray     return 0;
224b528cefcSMark Murray }
225b528cefcSMark Murray 
226b528cefcSMark Murray static int
krb5_start_session(void)227b528cefcSMark Murray krb5_start_session(void)
228b528cefcSMark Murray {
229b528cefcSMark Murray     krb5_ccache ccache2;
230b528cefcSMark Murray     char *cc_name;
231b528cefcSMark Murray     int ret;
232b528cefcSMark Murray 
233*ae771770SStanislav Sedov     ret = krb5_cc_new_unique(context, krb5_cc_type_file, NULL, &ccache2);
234b528cefcSMark Murray     if (ret) {
235b528cefcSMark Murray 	krb5_cc_destroy(context, ccache);
236b528cefcSMark Murray 	return 1;
237b528cefcSMark Murray     }
238b528cefcSMark Murray 
239b528cefcSMark Murray     ret = krb5_cc_copy_cache(context, ccache, ccache2);
240*ae771770SStanislav Sedov     if (ret) {
241*ae771770SStanislav Sedov 	krb5_cc_destroy(context, ccache);
242*ae771770SStanislav Sedov 	krb5_cc_destroy(context, ccache2);
243*ae771770SStanislav Sedov 	return 1;
244*ae771770SStanislav Sedov     }
245b528cefcSMark Murray 
24633f12199SDoug Rabson     ret = asprintf(&cc_name, "%s:%s", krb5_cc_get_type(context, ccache2),
247b528cefcSMark Murray 		   krb5_cc_get_name(context, ccache2));
248*ae771770SStanislav Sedov     if (ret == -1) {
249*ae771770SStanislav Sedov 	krb5_cc_destroy(context, ccache);
250*ae771770SStanislav Sedov 	krb5_cc_destroy(context, ccache2);
25133f12199SDoug Rabson 	errx(1, "malloc - out of memory");
252*ae771770SStanislav Sedov     }
2535e9cd1aeSAssar Westerlund     esetenv("KRB5CCNAME", cc_name, 1);
2545e9cd1aeSAssar Westerlund 
2555e9cd1aeSAssar Westerlund     /* convert creds? */
256b528cefcSMark Murray     if(k_hasafs()) {
257b528cefcSMark Murray 	if (k_setpag() == 0)
258b528cefcSMark Murray 	    krb5_afslog(context, ccache2, NULL, NULL);
259b528cefcSMark Murray     }
260b528cefcSMark Murray 
261b528cefcSMark Murray     krb5_cc_close(context, ccache2);
262b528cefcSMark Murray     krb5_cc_destroy(context, ccache);
263b528cefcSMark Murray     return 0;
264b528cefcSMark Murray }
265b528cefcSMark Murray #endif
266b528cefcSMark Murray 
2678373020dSJacques Vidrine 
26833f12199SDoug Rabson #define GROUP_MEMBER		0
26933f12199SDoug Rabson #define GROUP_MISSING		1
27033f12199SDoug Rabson #define GROUP_EMPTY		2
27133f12199SDoug Rabson #define GROUP_NOT_MEMBER	3
27233f12199SDoug Rabson 
273b528cefcSMark Murray static int
group_member_p(const char * group,const char * user)27433f12199SDoug Rabson group_member_p(const char *group, const char *user)
27533f12199SDoug Rabson {
27633f12199SDoug Rabson     struct group *g;
27733f12199SDoug Rabson     int i;
27833f12199SDoug Rabson     g = getgrnam(group);
27933f12199SDoug Rabson     if(g == NULL)
28033f12199SDoug Rabson 	return GROUP_MISSING;
28133f12199SDoug Rabson     if(g->gr_mem[0] == NULL)
28233f12199SDoug Rabson 	return GROUP_EMPTY;
28333f12199SDoug Rabson     for(i = 0; g->gr_mem[i] != NULL; i++)
28433f12199SDoug Rabson 	if(strcmp(user, g->gr_mem[i]) == 0)
28533f12199SDoug Rabson 	    return GROUP_MEMBER;
28633f12199SDoug Rabson     return GROUP_NOT_MEMBER;
28733f12199SDoug Rabson }
28833f12199SDoug Rabson 
28933f12199SDoug Rabson static int
verify_unix(struct passwd * login,struct passwd * su)29033f12199SDoug Rabson verify_unix(struct passwd *login, struct passwd *su)
291b528cefcSMark Murray {
292b528cefcSMark Murray     char prompt[128];
293b528cefcSMark Murray     char pw_buf[1024];
294b528cefcSMark Murray     char *pw;
295b528cefcSMark Murray     int r;
296b528cefcSMark Murray     if(su->pw_passwd != NULL && *su->pw_passwd != '\0') {
2975e9cd1aeSAssar Westerlund 	snprintf(prompt, sizeof(prompt), "%s's password: ", su->pw_name);
29833f12199SDoug Rabson 	r = UI_UTIL_read_pw_string(pw_buf, sizeof(pw_buf), prompt, 0);
299b528cefcSMark Murray 	if(r != 0)
300b528cefcSMark Murray 	    exit(0);
301b528cefcSMark Murray 	pw = crypt(pw_buf, su->pw_passwd);
302b528cefcSMark Murray 	memset(pw_buf, 0, sizeof(pw_buf));
30333f12199SDoug Rabson 	if(strcmp(pw, su->pw_passwd) != 0) {
30433f12199SDoug Rabson 	    syslog (LOG_ERR | LOG_AUTH, "%s to %s: incorrect password",
30533f12199SDoug Rabson 		    login->pw_name, su->pw_name);
306b528cefcSMark Murray 	    return 1;
307b528cefcSMark Murray 	}
30833f12199SDoug Rabson     }
30933f12199SDoug Rabson     /* if su:ing to root, check membership of group wheel or root; if
31033f12199SDoug Rabson        that group doesn't exist, or is empty, allow anyone to su
31133f12199SDoug Rabson        root */
31233f12199SDoug Rabson     if(su->pw_uid == 0) {
31333f12199SDoug Rabson #ifndef ROOT_GROUP
31433f12199SDoug Rabson #define ROOT_GROUP "wheel"
31533f12199SDoug Rabson #endif
31633f12199SDoug Rabson 	int gs = group_member_p(ROOT_GROUP, login->pw_name);
31733f12199SDoug Rabson 	if(gs == GROUP_NOT_MEMBER) {
31833f12199SDoug Rabson 	    syslog (LOG_ERR | LOG_AUTH, "%s to %s: not in group %s",
31933f12199SDoug Rabson 		    login->pw_name, su->pw_name, ROOT_GROUP);
32033f12199SDoug Rabson 	    return 1;
32133f12199SDoug Rabson 	}
32233f12199SDoug Rabson 	return 0;
32333f12199SDoug Rabson     }
324b528cefcSMark Murray     return 0;
325b528cefcSMark Murray }
326b528cefcSMark Murray 
327b528cefcSMark Murray int
main(int argc,char ** argv)328b528cefcSMark Murray main(int argc, char **argv)
329b528cefcSMark Murray {
330b528cefcSMark Murray     int i, optind = 0;
331b528cefcSMark Murray     char *su_user;
332b528cefcSMark Murray     struct passwd *su_info;
333b528cefcSMark Murray     struct passwd *login_info;
334b528cefcSMark Murray 
335b528cefcSMark Murray     struct passwd *pwd;
336b528cefcSMark Murray 
337b528cefcSMark Murray     char *shell;
338b528cefcSMark Murray 
339b528cefcSMark Murray     int ok = 0;
340b528cefcSMark Murray 
341adb0ddaeSAssar Westerlund     setprogname (argv[0]);
342b528cefcSMark Murray 
343b528cefcSMark Murray     if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind))
344b528cefcSMark Murray 	usage(1);
345b528cefcSMark Murray 
346b528cefcSMark Murray     for (i=0; i < optind; i++)
347b528cefcSMark Murray       if (strcmp(argv[i], "-") == 0) {
348b528cefcSMark Murray 	 full_login = 1;
349b528cefcSMark Murray 	 break;
350b528cefcSMark Murray       }
351b528cefcSMark Murray 
352b528cefcSMark Murray     if(help_flag)
353b528cefcSMark Murray 	usage(0);
354b528cefcSMark Murray     if(version_flag) {
355b528cefcSMark Murray 	print_version(NULL);
356b528cefcSMark Murray 	exit(0);
357b528cefcSMark Murray     }
358b528cefcSMark Murray     if(optind >= argc)
359b528cefcSMark Murray 	su_user = "root";
360b528cefcSMark Murray     else
361b528cefcSMark Murray 	su_user = argv[optind++];
362b528cefcSMark Murray 
36333f12199SDoug Rabson     if (!issuid() && getuid() != 0)
364*ae771770SStanislav Sedov 	warnx("Not setuid and you are not root, expect this to fail");
36533f12199SDoug Rabson 
366b528cefcSMark Murray     pwd = k_getpwnam(su_user);
367b528cefcSMark Murray     if(pwd == NULL)
368b528cefcSMark Murray 	errx (1, "unknown login %s", su_user);
369b528cefcSMark Murray     if (pwd->pw_uid == 0 && strcmp ("root", su_user) != 0) {
370b528cefcSMark Murray 	syslog (LOG_ALERT, "NIS attack, user %s has uid 0", su_user);
371b528cefcSMark Murray 	errx (1, "unknown login %s", su_user);
372b528cefcSMark Murray     }
3734137ff4cSJacques Vidrine     su_info = dup_info(pwd);
3744137ff4cSJacques Vidrine     if (su_info == NULL)
3754137ff4cSJacques Vidrine 	errx (1, "malloc: out of memory");
376b528cefcSMark Murray 
377b528cefcSMark Murray 	pwd = getpwuid(getuid());
378b528cefcSMark Murray     if(pwd == NULL)
379b528cefcSMark Murray 	errx(1, "who are you?");
3804137ff4cSJacques Vidrine     login_info = dup_info(pwd);
3814137ff4cSJacques Vidrine     if (login_info == NULL)
3824137ff4cSJacques Vidrine 	errx (1, "malloc: out of memory");
383b528cefcSMark Murray     if(env_flag)
384b528cefcSMark Murray 	shell = login_info->pw_shell;
385b528cefcSMark Murray     else
386b528cefcSMark Murray 	shell = su_info->pw_shell;
387b528cefcSMark Murray     if(shell == NULL || *shell == '\0')
388b528cefcSMark Murray 	shell = _PATH_BSHELL;
389b528cefcSMark Murray 
3908373020dSJacques Vidrine 
3918373020dSJacques Vidrine #ifdef KRB5
392b528cefcSMark Murray     if(kerberos_flag && ok == 0 &&
393*ae771770SStanislav Sedov        krb5_verify(login_info, su_info, kerberos_instance) == 0)
3948373020dSJacques Vidrine 	ok = 5;
3958373020dSJacques Vidrine #endif
396b528cefcSMark Murray 
39733f12199SDoug Rabson     if(ok == 0 && login_info->pw_uid && verify_unix(login_info, su_info) != 0) {
398b528cefcSMark Murray 	printf("Sorry!\n");
399b528cefcSMark Murray 	exit(1);
400b528cefcSMark Murray     }
401b528cefcSMark Murray 
402b528cefcSMark Murray #ifdef HAVE_GETSPNAM
403b528cefcSMark Murray    {  struct spwd *sp;
404b528cefcSMark Murray       long    today;
405b528cefcSMark Murray 
406b528cefcSMark Murray     sp = getspnam(su_info->pw_name);
4075e9cd1aeSAssar Westerlund     if (sp != NULL) {
408b528cefcSMark Murray 	today = time(0)/(24L * 60 * 60);
409b528cefcSMark Murray 	if (sp->sp_expire > 0) {
410b528cefcSMark Murray 	    if (today >= sp->sp_expire) {
411b528cefcSMark Murray 		if (login_info->pw_uid)
412b528cefcSMark Murray 		    errx(1,"Your account has expired.");
413b528cefcSMark Murray 		else
414b528cefcSMark Murray 		    printf("Your account has expired.");
415b528cefcSMark Murray             }
416b528cefcSMark Murray             else if (sp->sp_expire - today < 14)
417b528cefcSMark Murray                 printf("Your account will expire in %d days.\n",
418b528cefcSMark Murray 		       (int)(sp->sp_expire - today));
419b528cefcSMark Murray 	}
420b528cefcSMark Murray 	if (sp->sp_max > 0) {
421b528cefcSMark Murray 	    if (today >= sp->sp_lstchg + sp->sp_max) {
422b528cefcSMark Murray 		if (login_info->pw_uid)
423b528cefcSMark Murray 		    errx(1,"Your password has expired. Choose a new one.");
424b528cefcSMark Murray 		else
425b528cefcSMark Murray 		    printf("Your password has expired. Choose a new one.");
426b528cefcSMark Murray 	    }
427b528cefcSMark Murray 	    else if (today >= sp->sp_lstchg + sp->sp_max - sp->sp_warn)
428b528cefcSMark Murray 		printf("Your account will expire in %d days.\n",
429b528cefcSMark Murray 		       (int)(sp->sp_lstchg + sp->sp_max -today));
430b528cefcSMark Murray 	}
431b528cefcSMark Murray     }
4325e9cd1aeSAssar Westerlund     }
433b528cefcSMark Murray #endif
434b528cefcSMark Murray     {
435b528cefcSMark Murray 	char *tty = ttyname (STDERR_FILENO);
43633f12199SDoug Rabson 	syslog (LOG_NOTICE | LOG_AUTH, tty ? "%s to %s on %s" : "%s to %s",
437b528cefcSMark Murray 		login_info->pw_name, su_info->pw_name, tty);
438b528cefcSMark Murray     }
439b528cefcSMark Murray 
440b528cefcSMark Murray 
441b528cefcSMark Murray     if(!env_flag) {
442b528cefcSMark Murray 	if(full_login) {
443b528cefcSMark Murray 	    char *t = getenv ("TERM");
44433f12199SDoug Rabson 	    char **newenv = NULL;
44533f12199SDoug Rabson 	    int i, j;
446b528cefcSMark Murray 
44733f12199SDoug Rabson 	    i = read_environment(_PATH_ETC_ENVIRONMENT, &newenv);
44833f12199SDoug Rabson 
44933f12199SDoug Rabson 	    environ = malloc ((10 + i) * sizeof (char *));
450b528cefcSMark Murray 	    if (environ == NULL)
451b528cefcSMark Murray 		err (1, "malloc");
452b528cefcSMark Murray 	    environ[0] = NULL;
45333f12199SDoug Rabson 
45433f12199SDoug Rabson 	    for (j = 0; j < i; j++) {
45533f12199SDoug Rabson 		char *p = strchr(newenv[j], '=');
456*ae771770SStanislav Sedov 		if (p == NULL)
457*ae771770SStanislav Sedov 		    errx(1, "enviroment '%s' missing '='", newenv[j]);
45833f12199SDoug Rabson 		*p++ = 0;
45933f12199SDoug Rabson 		esetenv (newenv[j], p, 1);
46033f12199SDoug Rabson 	    }
46133f12199SDoug Rabson 	    free(newenv);
46233f12199SDoug Rabson 
4635e9cd1aeSAssar Westerlund 	    esetenv ("PATH", _PATH_DEFPATH, 1);
464b528cefcSMark Murray 	    if (t)
4655e9cd1aeSAssar Westerlund 		esetenv ("TERM", t, 1);
466b528cefcSMark Murray 	    if (chdir (su_info->pw_dir) < 0)
467b528cefcSMark Murray 		errx (1, "no directory");
468b528cefcSMark Murray 	}
469b528cefcSMark Murray 	if (full_login || su_info->pw_uid)
4705e9cd1aeSAssar Westerlund 	    esetenv ("USER", su_info->pw_name, 1);
4715e9cd1aeSAssar Westerlund 	esetenv("HOME", su_info->pw_dir, 1);
4725e9cd1aeSAssar Westerlund 	esetenv("SHELL", shell, 1);
473b528cefcSMark Murray     }
474b528cefcSMark Murray 
475b528cefcSMark Murray     {
476b528cefcSMark Murray 	int i;
477b528cefcSMark Murray 	char **args;
478b528cefcSMark Murray 	char *p;
479b528cefcSMark Murray 
480b528cefcSMark Murray 	p = strrchr(shell, '/');
481b528cefcSMark Murray 	if(p)
482b528cefcSMark Murray 	    p++;
483b528cefcSMark Murray 	else
484b528cefcSMark Murray 	    p = shell;
485b528cefcSMark Murray 
486b528cefcSMark Murray 	if (strcmp(p, "csh") != 0)
487b528cefcSMark Murray 	    csh_f_flag = 0;
488b528cefcSMark Murray 
489b528cefcSMark Murray         args = malloc(((cmd ? 2 : 0) + 1 + argc - optind + 1 + csh_f_flag) * sizeof(*args));
490b528cefcSMark Murray 	if (args == NULL)
491b528cefcSMark Murray 	    err (1, "malloc");
492b528cefcSMark Murray 	i = 0;
49333f12199SDoug Rabson 	if(full_login) {
49433f12199SDoug Rabson 	    if (asprintf(&args[i++], "-%s", p) == -1)
49533f12199SDoug Rabson 		errx (1, "malloc");
49633f12199SDoug Rabson 	} else
497b528cefcSMark Murray 	    args[i++] = p;
498b528cefcSMark Murray 	if (cmd) {
499b528cefcSMark Murray 	   args[i++] = "-c";
500b528cefcSMark Murray 	   args[i++] = cmd;
501b528cefcSMark Murray 	}
502b528cefcSMark Murray 
503b528cefcSMark Murray 	if (csh_f_flag)
504b528cefcSMark Murray 	    args[i++] = "-f";
505b528cefcSMark Murray 
506b528cefcSMark Murray 	for (argv += optind; *argv; ++argv)
507b528cefcSMark Murray 	   args[i++] = *argv;
508b528cefcSMark Murray 	args[i] = NULL;
509b528cefcSMark Murray 
510b528cefcSMark Murray 	if(setgid(su_info->pw_gid) < 0)
511b528cefcSMark Murray 	    err(1, "setgid");
512b528cefcSMark Murray 	if (initgroups (su_info->pw_name, su_info->pw_gid) < 0)
513b528cefcSMark Murray 	    err (1, "initgroups");
5145e9cd1aeSAssar Westerlund 	if(setuid(su_info->pw_uid) < 0
5155e9cd1aeSAssar Westerlund 	   || (su_info->pw_uid != 0 && setuid(0) == 0))
516b528cefcSMark Murray 	    err(1, "setuid");
517b528cefcSMark Murray 
518b528cefcSMark Murray #ifdef KRB5
5198373020dSJacques Vidrine         if (ok == 5)
520b528cefcSMark Murray            krb5_start_session();
521b528cefcSMark Murray #endif
522*ae771770SStanislav Sedov 	execve(shell, args, environ);
523b528cefcSMark Murray     }
524b528cefcSMark Murray 
525b528cefcSMark Murray     exit(1);
526b528cefcSMark Murray }
527