Deleted Added
full compact
login.c (89970) login.c (89994)
1/*-
2 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 2002 Networks Associates Technologies, Inc.
5 * All rights reserved.
6 *
7 * Portions of this software were developed for the FreeBSD Project by
8 * ThinkSec AS and NAI Labs, the Security Research Division of Network

--- 31 unchanged lines hidden (view full) ---

40
41#if 0
42#ifndef lint
43static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
44#endif
45#endif
46
47#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 2002 Networks Associates Technologies, Inc.
5 * All rights reserved.
6 *
7 * Portions of this software were developed for the FreeBSD Project by
8 * ThinkSec AS and NAI Labs, the Security Research Division of Network

--- 31 unchanged lines hidden (view full) ---

40
41#if 0
42#ifndef lint
43static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
44#endif
45#endif
46
47#include <sys/cdefs.h>
48__FBSDID("$FreeBSD: head/usr.bin/login/login.c 89970 2002-01-29 23:27:54Z des $");
48__FBSDID("$FreeBSD: head/usr.bin/login/login.c 89994 2002-01-30 19:10:21Z des $");
49
50/*
51 * login [ name ]
52 * login -h hostname (for telnetd, etc.)
53 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
54 */
55
56#include <sys/copyright.h>
57#include <sys/param.h>
58#include <sys/file.h>
49
50/*
51 * login [ name ]
52 * login -h hostname (for telnetd, etc.)
53 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
54 */
55
56#include <sys/copyright.h>
57#include <sys/param.h>
58#include <sys/file.h>
59#include <sys/socket.h>
60#include <sys/stat.h>
61#include <sys/time.h>
62#include <sys/resource.h>
63#include <sys/wait.h>
59#include <sys/stat.h>
60#include <sys/time.h>
61#include <sys/resource.h>
62#include <sys/wait.h>
64#include <netinet/in.h>
65#include <arpa/inet.h>
66
67#include <err.h>
68#include <errno.h>
69#include <grp.h>
70#include <libutil.h>
71#include <login_cap.h>
63
64#include <err.h>
65#include <errno.h>
66#include <grp.h>
67#include <libutil.h>
68#include <login_cap.h>
72#include <netdb.h>
73#include <pwd.h>
74#include <setjmp.h>
75#include <signal.h>
76#include <stdio.h>
77#include <stdlib.h>
78#include <string.h>
79#include <syslog.h>
80#include <ttyent.h>
81#include <unistd.h>
69#include <pwd.h>
70#include <setjmp.h>
71#include <signal.h>
72#include <stdio.h>
73#include <stdlib.h>
74#include <string.h>
75#include <syslog.h>
76#include <ttyent.h>
77#include <unistd.h>
82#include <utmp.h>
83
78
84#ifndef NO_PAM
85#include <security/pam_appl.h>
86#include <security/pam_misc.h>
79#include <security/pam_appl.h>
80#include <security/pam_misc.h>
87#endif
88
89#include "login.h"
90#include "pathnames.h"
91
92/* wrapper for KAME-special getnameinfo() */
93#ifndef NI_WITHSCOPEID
94#define NI_WITHSCOPEID 0
95#endif
96
81
82#include "login.h"
83#include "pathnames.h"
84
85/* wrapper for KAME-special getnameinfo() */
86#ifndef NI_WITHSCOPEID
87#define NI_WITHSCOPEID 0
88#endif
89
97static int auth_traditional __P((void));
98static void badlogin __P((char *));
99static void dolastlog __P((int));
100static void getloginname __P((void));
101static void motd __P((const char *));
102static void refused __P((const char *,const char *,int));
103static int rootterm __P((char *));
104static void sigint __P((int));
105static void sleepexit __P((int));
106static const char *stypeof __P((char *));
107static void timedout __P((int));
108static void usage __P((void));
90static int auth_pam(void);
91static void bail(int, int);
92static int export(const char *);
93static void export_pam_environment(void);
94static int motd(const char *);
95static void badlogin(char *);
96static char *getloginname(void);
97static void pam_syslog(const char *);
98static void pam_cleanup(void);
99static void refused(const char *, const char *, int);
100static const char *stypeof(char *);
101static void sigint(int);
102static void timedout(int);
103static void usage(void);
109
104
110#ifndef NO_PAM
111static int auth_pam __P((void));
112static int export_pam_environment __P((void));
113static int ok_to_export __P((const char *));
114
115static pam_handle_t *pamh = NULL;
116static char **environ_pam;
117
118#define PAM_END { \
119 if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \
120 syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); \
121 if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS) \
122 syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pamh, e)); \
123 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) \
124 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); \
125}
126#endif /* NO_PAM */
127
128#define TTYGRPNAME "tty" /* group to own ttys */
129#define DEFAULT_BACKOFF 3
130#define DEFAULT_RETRIES 10
131#define DEFAULT_PROMPT "login: "
132#define DEFAULT_PASSWD_PROMPT "Password:"
105#define TTYGRPNAME "tty" /* group to own ttys */
106#define DEFAULT_BACKOFF 3
107#define DEFAULT_RETRIES 10
108#define DEFAULT_PROMPT "login: "
109#define DEFAULT_PASSWD_PROMPT "Password:"
133#define INVALID_HOST "invalid hostname"
134#define UNKNOWN "su"
110#define TERM_UNKNOWN "su"
135#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
111#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
136#define NBUFSIZ UT_NAMESIZE + 64
112#define NO_SLEEP_EXIT 0
113#define SLEEP_EXIT 5
137
138/*
139 * This bounds the time given to login. Not a define so it can
140 * be patched on machines where it's too small.
141 */
114
115/*
116 * This bounds the time given to login. Not a define so it can
117 * be patched on machines where it's too small.
118 */
142u_int timeout = 300;
119static u_int timeout = 300;
143
144/* Buffer for signal handling of timeout */
120
121/* Buffer for signal handling of timeout */
145jmp_buf timeout_buf;
122static jmp_buf timeout_buf;
146
123
147struct passwd *pwd;
148int failures;
149char *term, *envinit[1], *hostname, *passwd_prompt, *prompt, *tty, *username;
150char full_hostname[MAXHOSTNAMELEN];
124struct passwd *pwd;
125static int failures;
151
126
127static char *envinit[1]; /* empty environment list */
128
129/*
130 * Command line flags and arguments
131 */
132static int fflag; /* -f: do not perform authentication */
133static int hflag; /* -h: login from remote host */
134static char *hostname; /* hostname from command line */
135static int pflag; /* -p: preserve environment */
136
137/*
138 * User name
139 */
140static char *username; /* user name */
141static char *olduser; /* previous user name */
142
143/*
144 * Prompts
145 */
146static char default_prompt[] = DEFAULT_PROMPT;
147static char *prompt;
148static char default_passwd_prompt[] = DEFAULT_PASSWD_PROMPT;
149static char *passwd_prompt;
150
151static char *tty;
152
153/*
154 * PAM data
155 */
156static pam_handle_t *pamh = NULL;
157static struct pam_conv pamc = { misc_conv, NULL };
158static int pam_err;
159static int pam_silent = PAM_SILENT;
160static int pam_cred_established;
161static int pam_session_established;
162
152int
163int
153main(argc, argv)
154 int argc;
155 char *argv[];
164main(int argc, char *argv[])
156{
157 struct group *gr;
158 struct stat st;
165{
166 struct group *gr;
167 struct stat st;
159 struct timeval tp;
160 struct utmp utmp;
161 int rootok, retries, backoff;
162 int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval;
163 time_t warntime;
168 int retries, backoff;
169 int ask, ch, cnt, quietlog, rootlogin, rval;
164 uid_t uid, euid;
165 gid_t egid;
170 uid_t uid, euid;
171 gid_t egid;
172 char *term;
166 char *p, *ttyn;
173 char *p, *ttyn;
167 char tbuf[MAXPATHLEN + 2];
168 char tname[sizeof(_PATH_TTY) + 10];
174 char tname[sizeof(_PATH_TTY) + 10];
169 char *shell = NULL;
170 static char default_prompt[] = DEFAULT_PROMPT;
171 static char default_passwd_prompt[] = DEFAULT_PASSWD_PROMPT;
172 static char invalid_host[] = INVALID_HOST;
175 char *arg0, *shell = NULL;
173 login_cap_t *lc = NULL;
176 login_cap_t *lc = NULL;
174#ifndef NO_PAM
175 pid_t pid;
177 pid_t pid;
176 int e;
177#endif /* NO_PAM */
178
179 (void)signal(SIGQUIT, SIG_IGN);
180 (void)signal(SIGINT, SIG_IGN);
181 (void)signal(SIGHUP, SIG_IGN);
182 if (setjmp(timeout_buf)) {
183 if (failures)
178
179 (void)signal(SIGQUIT, SIG_IGN);
180 (void)signal(SIGINT, SIG_IGN);
181 (void)signal(SIGHUP, SIG_IGN);
182 if (setjmp(timeout_buf)) {
183 if (failures)
184 badlogin(tbuf);
184 badlogin(username);
185 (void)fprintf(stderr, "Login timed out after %d seconds\n",
186 timeout);
185 (void)fprintf(stderr, "Login timed out after %d seconds\n",
186 timeout);
187 exit(0);
187 bail(NO_SLEEP_EXIT, 0);
188 }
189 (void)signal(SIGALRM, timedout);
190 (void)alarm(timeout);
191 (void)setpriority(PRIO_PROCESS, 0, 0);
192
193 openlog("login", LOG_ODELAY, LOG_AUTH);
194
188 }
189 (void)signal(SIGALRM, timedout);
190 (void)alarm(timeout);
191 (void)setpriority(PRIO_PROCESS, 0, 0);
192
193 openlog("login", LOG_ODELAY, LOG_AUTH);
194
195 /*
196 * -p is used by getty to tell login not to destroy the environment
197 * -f is used to skip a second login authentication
198 * -h is used by other servers to pass the name of the remote
199 * host to login so that it may be placed in utmp and wtmp
200 */
201 *full_hostname = '\0';
202 term = NULL;
203
204 fflag = hflag = pflag = 0;
205 uid = getuid();
206 euid = geteuid();
207 egid = getegid();
195 uid = getuid();
196 euid = geteuid();
197 egid = getegid();
198
208 while ((ch = getopt(argc, argv, "fh:p")) != -1)
209 switch (ch) {
210 case 'f':
211 fflag = 1;
212 break;
213 case 'h':
199 while ((ch = getopt(argc, argv, "fh:p")) != -1)
200 switch (ch) {
201 case 'f':
202 fflag = 1;
203 break;
204 case 'h':
214 if (uid)
205 if (uid != 0)
215 errx(1, "-h option: %s", strerror(EPERM));
206 errx(1, "-h option: %s", strerror(EPERM));
216 hflag = 1;
217 if (strlcpy(full_hostname, optarg,
218 sizeof(full_hostname)) >= sizeof(full_hostname))
207 if (strlen(optarg) >= MAXHOSTNAMELEN)
219 errx(1, "-h option: %s: exceeds maximum "
220 "hostname size", optarg);
208 errx(1, "-h option: %s: exceeds maximum "
209 "hostname size", optarg);
221
222 trimdomain(optarg, UT_HOSTSIZE);
223
224 if (strlen(optarg) > UT_HOSTSIZE) {
225 struct addrinfo hints, *res;
226 int ga_err;
227
228 memset(&hints, 0, sizeof(hints));
229 hints.ai_family = AF_UNSPEC;
230 ga_err = getaddrinfo(optarg, NULL, &hints,
231 &res);
232 if (ga_err == 0) {
233 char hostbuf[MAXHOSTNAMELEN];
234
235 getnameinfo(res->ai_addr,
236 res->ai_addrlen,
237 hostbuf,
238 sizeof(hostbuf), NULL, 0,
239 NI_NUMERICHOST|
240 NI_WITHSCOPEID);
241 optarg = strdup(hostbuf);
242 if (optarg == NULL) {
243 syslog(LOG_NOTICE,
244 "strdup(): %m");
245 sleepexit(1);
246 }
247 } else
248 optarg = invalid_host;
249 if (res != NULL)
250 freeaddrinfo(res);
251 }
210 hflag = 1;
252 hostname = optarg;
253 break;
254 case 'p':
255 pflag = 1;
256 break;
257 case '?':
258 default:
211 hostname = optarg;
212 break;
213 case 'p':
214 pflag = 1;
215 break;
216 case '?':
217 default:
259 if (!uid)
218 if (uid == 0)
260 syslog(LOG_ERR, "invalid flag %c", ch);
261 usage();
262 }
263 argc -= optind;
264 argv += optind;
265
219 syslog(LOG_ERR, "invalid flag %c", ch);
220 usage();
221 }
222 argc -= optind;
223 argv += optind;
224
266 if (*argv) {
267 username = *argv;
225 if (argc > 0) {
226 username = strdup(*argv);
227 if (username == NULL)
228 err(1, "strdup()");
268 ask = 0;
229 ask = 0;
269 } else
230 } else {
270 ask = 1;
231 ask = 1;
232 }
271
272 for (cnt = getdtablesize(); cnt > 2; cnt--)
273 (void)close(cnt);
274
233
234 for (cnt = getdtablesize(); cnt > 2; cnt--)
235 (void)close(cnt);
236
237 /*
238 * Get current TTY
239 */
275 ttyn = ttyname(STDIN_FILENO);
276 if (ttyn == NULL || *ttyn == '\0') {
277 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
278 ttyn = tname;
279 }
280 if ((tty = strrchr(ttyn, '/')) != NULL)
281 ++tty;
282 else
283 tty = ttyn;
284
285 /*
286 * Get "login-retries" & "login-backoff" from default class
287 */
288 lc = login_getclass(NULL);
240 ttyn = ttyname(STDIN_FILENO);
241 if (ttyn == NULL || *ttyn == '\0') {
242 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
243 ttyn = tname;
244 }
245 if ((tty = strrchr(ttyn, '/')) != NULL)
246 ++tty;
247 else
248 tty = ttyn;
249
250 /*
251 * Get "login-retries" & "login-backoff" from default class
252 */
253 lc = login_getclass(NULL);
289 prompt = login_getcapstr(lc, "prompt", default_prompt, default_prompt);
254 prompt = login_getcapstr(lc, "prompt",
255 default_prompt, default_prompt);
290 passwd_prompt = login_getcapstr(lc, "passwd_prompt",
291 default_passwd_prompt, default_passwd_prompt);
256 passwd_prompt = login_getcapstr(lc, "passwd_prompt",
257 default_passwd_prompt, default_passwd_prompt);
292 retries = login_getcapnum(lc, "login-retries", DEFAULT_RETRIES,
293 DEFAULT_RETRIES);
294 backoff = login_getcapnum(lc, "login-backoff", DEFAULT_BACKOFF,
295 DEFAULT_BACKOFF);
258 retries = login_getcapnum(lc, "login-retries",
259 DEFAULT_RETRIES, DEFAULT_RETRIES);
260 backoff = login_getcapnum(lc, "login-backoff",
261 DEFAULT_BACKOFF, DEFAULT_BACKOFF);
296 login_close(lc);
297 lc = NULL;
298
262 login_close(lc);
263 lc = NULL;
264
265 /*
266 * Try to authenticate the user until we succeed or time out.
267 */
299 for (cnt = 0;; ask = 1) {
300 if (ask) {
301 fflag = 0;
268 for (cnt = 0;; ask = 1) {
269 if (ask) {
270 fflag = 0;
302 getloginname();
271 if (olduser != NULL)
272 free(olduser);
273 olduser = username;
274 username = getloginname();
303 }
304 rootlogin = 0;
275 }
276 rootlogin = 0;
305 rootok = rootterm(tty); /* Default (auth may change) */
306
277
307 if (strlen(username) > UT_NAMESIZE)
308 username[UT_NAMESIZE] = '\0';
309
310 /*
311 * Note if trying multiple user names; log failures for
312 * previous user name, but don't bother logging one failure
313 * for nonexistent name (mistyped username).
314 */
278 /*
279 * Note if trying multiple user names; log failures for
280 * previous user name, but don't bother logging one failure
281 * for nonexistent name (mistyped username).
282 */
315 if (failures && strcmp(tbuf, username)) {
283 if (failures && strcmp(olduser, username) != 0) {
316 if (failures > (pwd ? 0 : 1))
284 if (failures > (pwd ? 0 : 1))
317 badlogin(tbuf);
285 badlogin(olduser);
318 }
286 }
319 (void)strlcpy(tbuf, username, sizeof(tbuf));
287 olduser = username;
320
288
321 pwd = getpwnam(username);
322
323 /*
289 /*
324 * if we have a valid account name, and it doesn't have a
325 * password, or the -f option was specified and the caller
326 * is root or the caller isn't changing their uid, don't
327 * authenticate.
290 * Load the PAM policy and set some variables
328 */
291 */
329 if (pwd != NULL) {
330 if (pwd->pw_uid == 0)
331 rootlogin = 1;
332
333 if (fflag && (uid == (uid_t)0 ||
334 uid == (uid_t)pwd->pw_uid)) {
335 /* already authenticated */
336 break;
337 } else if (pwd->pw_passwd[0] == '\0') {
338 if (!rootlogin || rootok) {
339 /* pretend password okay */
340 rval = 0;
341 goto ttycheck;
342 }
343 }
292 pam_err = pam_start("login", username, &pamc, &pamh);
293 if (pam_err != PAM_SUCCESS) {
294 pam_syslog("pam_start()");
295 bail(NO_SLEEP_EXIT, 1);
344 }
296 }
345
346 fflag = 0;
347
348 (void)setpriority(PRIO_PROCESS, 0, -4);
349
350#ifndef NO_PAM
351 /*
352 * Try to authenticate using PAM. If a PAM system error
353 * occurs, perhaps because of a botched configuration,
354 * then fall back to using traditional Unix authentication.
355 */
356 if ((rval = auth_pam()) == -1)
357#endif /* NO_PAM */
358 rval = auth_traditional();
359
360 (void)setpriority(PRIO_PROCESS, 0, 0);
361
362 /*
363 * PAM authentication may have changed "pwd" to the
364 * entry for the template user. Check again to see if
365 * this is a root login after all.
366 */
297 pam_err = pam_set_item(pamh, PAM_TTY, tty);
298 if (pam_err != PAM_SUCCESS) {
299 pam_syslog("pam_set_item(PAM_TTY)");
300 bail(NO_SLEEP_EXIT, 1);
301 }
302 pam_err = pam_set_item(pamh, PAM_RHOST, hostname);
303 if (pam_err != PAM_SUCCESS) {
304 pam_syslog("pam_set_item(PAM_RHOST)");
305 bail(NO_SLEEP_EXIT, 1);
306 }
307
308 pwd = getpwnam(username);
367 if (pwd != NULL && pwd->pw_uid == 0)
368 rootlogin = 1;
369
309 if (pwd != NULL && pwd->pw_uid == 0)
310 rootlogin = 1;
311
370 ttycheck:
371 /*
312 /*
372 * If trying to log in as root without Kerberos,
373 * but with insecure terminal, refuse the login attempt.
313 * If the -f option was specified and the caller is
314 * root or the caller isn't changing their uid, don't
315 * authenticate.
374 */
316 */
375 if (pwd && !rval) {
376 if (rootlogin && !rootok)
377 refused(NULL, "NOROOT", 0);
378 else /* valid password & authenticated */
379 break;
317 if (pwd != NULL && fflag &&
318 (uid == (uid_t)0 || uid == (uid_t)pwd->pw_uid)) {
319 /* already authenticated */
320 rval = 0;
321 } else {
322 fflag = 0;
323 (void)setpriority(PRIO_PROCESS, 0, -4);
324 rval = auth_pam();
325 (void)setpriority(PRIO_PROCESS, 0, 0);
380 }
381
326 }
327
328 if (pwd && rval == 0)
329 break;
330
331 pam_cleanup();
332
382 (void)printf("Login incorrect\n");
383 failures++;
384
385 /*
333 (void)printf("Login incorrect\n");
334 failures++;
335
336 /*
386 * we allow up to 'retry' (10) tries,
387 * but after 'backoff' (3) we start backing off
337 * Allow up to 'retry' (10) attempts, but start
338 * backing off after 'backoff' (3) attempts.
388 */
389 if (++cnt > backoff) {
390 if (cnt >= retries) {
391 badlogin(username);
339 */
340 if (++cnt > backoff) {
341 if (cnt >= retries) {
342 badlogin(username);
392 sleepexit(1);
343 bail(SLEEP_EXIT, 1);
393 }
394 sleep((u_int)((cnt - backoff) * 5));
395 }
396 }
397
398 /* committed to login -- turn off timeout */
399 (void)alarm((u_int)0);
400 (void)signal(SIGHUP, SIG_DFL);
401
402 endpwent();
403
404 /*
405 * Establish the login class.
406 */
407 lc = login_getpwclass(pwd);
408
409 quietlog = login_getcapbool(lc, "hushlogin", 0);
344 }
345 sleep((u_int)((cnt - backoff) * 5));
346 }
347 }
348
349 /* committed to login -- turn off timeout */
350 (void)alarm((u_int)0);
351 (void)signal(SIGHUP, SIG_DFL);
352
353 endpwent();
354
355 /*
356 * Establish the login class.
357 */
358 lc = login_getpwclass(pwd);
359
360 quietlog = login_getcapbool(lc, "hushlogin", 0);
361
410 /*
411 * Switching needed for NFS with root access disabled.
412 *
413 * XXX: This change fails to modify the additional groups for the
414 * process, and as such, may restrict rights normally granted
415 * through those groups.
416 */
417 (void)setegid(pwd->pw_gid);
418 (void)seteuid(rootlogin ? 0 : pwd->pw_uid);
419 if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
420 if (login_getcapbool(lc, "requirehome", 0))
421 refused("Home directory not available", "HOMEDIR", 1);
422 if (chdir("/") < 0)
423 refused("Cannot find root directory", "ROOTDIR", 1);
424 if (!quietlog || *pwd->pw_dir)
425 printf("No home directory.\nLogging in with home = \"/\".\n");
426 pwd->pw_dir = strdup("/");
427 if (pwd->pw_dir == NULL) {
428 syslog(LOG_NOTICE, "strdup(): %m");
362 /*
363 * Switching needed for NFS with root access disabled.
364 *
365 * XXX: This change fails to modify the additional groups for the
366 * process, and as such, may restrict rights normally granted
367 * through those groups.
368 */
369 (void)setegid(pwd->pw_gid);
370 (void)seteuid(rootlogin ? 0 : pwd->pw_uid);
371 if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
372 if (login_getcapbool(lc, "requirehome", 0))
373 refused("Home directory not available", "HOMEDIR", 1);
374 if (chdir("/") < 0)
375 refused("Cannot find root directory", "ROOTDIR", 1);
376 if (!quietlog || *pwd->pw_dir)
377 printf("No home directory.\nLogging in with home = \"/\".\n");
378 pwd->pw_dir = strdup("/");
379 if (pwd->pw_dir == NULL) {
380 syslog(LOG_NOTICE, "strdup(): %m");
429 sleepexit(1);
381 bail(SLEEP_EXIT, 1);
430 }
431 }
432 (void)seteuid(euid);
433 (void)setegid(egid);
434 if (!quietlog)
435 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
382 }
383 }
384 (void)seteuid(euid);
385 (void)setegid(egid);
386 if (!quietlog)
387 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
436
437 if (pwd->pw_change || pwd->pw_expire)
438 (void)gettimeofday(&tp, (struct timezone *)NULL);
439
440 warntime = login_getcaptime(lc, "warnexpire", DEFAULT_WARN,
441 DEFAULT_WARN);
442
443 if (pwd->pw_expire) {
444 if (tp.tv_sec >= pwd->pw_expire) {
445 refused("Sorry -- your account has expired", "EXPIRED",
446 1);
447 } else if (pwd->pw_expire - tp.tv_sec < warntime && !quietlog)
448 (void)printf("Warning: your account expires on %s",
449 ctime(&pwd->pw_expire));
450 }
451
452 if (lc != NULL) {
453 if (hostname) {
454 struct addrinfo hints, *res;
455 int ga_err;
456
457 memset(&hints, 0, sizeof(hints));
458 hints.ai_family = AF_UNSPEC;
459 ga_err = getaddrinfo(full_hostname, NULL, &hints,
460 &res);
461 if (ga_err == 0) {
462 char hostbuf[MAXHOSTNAMELEN];
463
464 getnameinfo(res->ai_addr, res->ai_addrlen,
465 hostbuf, sizeof(hostbuf), NULL, 0,
466 NI_NUMERICHOST|NI_WITHSCOPEID);
467 if ((optarg = strdup(hostbuf)) == NULL) {
468 syslog(LOG_NOTICE, "strdup(): %m");
469 sleepexit(1);
470 }
471 } else
472 optarg = NULL;
473 if (res != NULL)
474 freeaddrinfo(res);
475 if (!auth_hostok(lc, full_hostname, optarg))
476 refused("Permission denied", "HOST", 1);
477 }
478
479 if (!auth_ttyok(lc, tty))
480 refused("Permission denied", "TTY", 1);
481
482 if (!auth_timeok(lc, time(NULL)))
483 refused("Logins not available right now", "TIME", 1);
484 }
388
485 shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
486 if (*pwd->pw_shell == '\0')
487 pwd->pw_shell = strdup(_PATH_BSHELL);
488 if (pwd->pw_shell == NULL) {
489 syslog(LOG_NOTICE, "strdup(): %m");
389 shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
390 if (*pwd->pw_shell == '\0')
391 pwd->pw_shell = strdup(_PATH_BSHELL);
392 if (pwd->pw_shell == NULL) {
393 syslog(LOG_NOTICE, "strdup(): %m");
490 sleepexit(1);
394 bail(SLEEP_EXIT, 1);
491 }
492 if (*shell == '\0') /* Not overridden */
493 shell = pwd->pw_shell;
494 if ((shell = strdup(shell)) == NULL) {
495 syslog(LOG_NOTICE, "strdup(): %m");
395 }
396 if (*shell == '\0') /* Not overridden */
397 shell = pwd->pw_shell;
398 if ((shell = strdup(shell)) == NULL) {
399 syslog(LOG_NOTICE, "strdup(): %m");
496 sleepexit(1);
400 bail(SLEEP_EXIT, 1);
497 }
498
401 }
402
499#ifdef LOGIN_ACCESS
500 if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0)
501 refused("Permission denied", "ACCESS", 1);
502#endif /* LOGIN_ACCESS */
503
504 /* Nothing else left to fail -- really log in. */
505 memset((void *)&utmp, 0, sizeof(utmp));
506 (void)time(&utmp.ut_time);
507 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
508 if (hostname)
509 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
510 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
511 login(&utmp);
512
513 dolastlog(quietlog);
514
515 /*
516 * Set device protections, depending on what terminal the
517 * user is logged in. This feature is used on Suns to give
518 * console users better privacy.
519 */
520 login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
521
522 /*
523 * Clear flags of the tty. None should be set, and when the
524 * user sets them otherwise, this can cause the chown to fail.
525 * Since it isn't clear that flags are useful on character
526 * devices, we just clear them.
527 */
403 /*
404 * Set device protections, depending on what terminal the
405 * user is logged in. This feature is used on Suns to give
406 * console users better privacy.
407 */
408 login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
409
410 /*
411 * Clear flags of the tty. None should be set, and when the
412 * user sets them otherwise, this can cause the chown to fail.
413 * Since it isn't clear that flags are useful on character
414 * devices, we just clear them.
415 */
528 if (chflags(ttyn, 0) && errno != EOPNOTSUPP)
529 syslog(LOG_ERR, "chmod(%s): %m", ttyn);
530 if (chown(ttyn, pwd->pw_uid,
416 if (ttyn != tname && chflags(ttyn, 0) && errno != EOPNOTSUPP)
417 syslog(LOG_ERR, "chflags(%s): %m", ttyn);
418 if (ttyn != tname && chown(ttyn, pwd->pw_uid,
531 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid))
532 syslog(LOG_ERR, "chmod(%s): %m", ttyn);
533
419 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid))
420 syslog(LOG_ERR, "chmod(%s): %m", ttyn);
421
534
535 /*
422 /*
536 * Preserve TERM if it happens to be already set.
537 */
538 if ((term = getenv("TERM")) != NULL) {
539 if ((term = strdup(term)) == NULL) {
540 syslog(LOG_NOTICE,
541 "strdup(): %m");
542 sleepexit(1);
543 }
544 }
545
546 /*
547 * Exclude cons/vt/ptys only, assume dialup otherwise
548 * TODO: Make dialup tty determination a library call
549 * for consistency (finger etc.)
550 */
423 * Exclude cons/vt/ptys only, assume dialup otherwise
424 * TODO: Make dialup tty determination a library call
425 * for consistency (finger etc.)
426 */
551 if (hostname==NULL && isdialuptty(tty))
427 if (hflag && isdialuptty(tty))
552 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
553
554#ifdef LOGALL
555 /*
428 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
429
430#ifdef LOGALL
431 /*
556 * Syslog each successful login, so we don't have to watch hundreds
557 * of wtmp or lastlogin files.
432 * Syslog each successful login, so we don't have to watch
433 * hundreds of wtmp or lastlogin files.
558 */
434 */
559 if (hostname)
435 if (hflag)
560 syslog(LOG_INFO, "login from %s on %s as %s",
436 syslog(LOG_INFO, "login from %s on %s as %s",
561 full_hostname, tty, pwd->pw_name);
437 hostname, tty, pwd->pw_name);
562 else
563 syslog(LOG_INFO, "login on %s as %s",
564 tty, pwd->pw_name);
565#endif
566
567 /*
438 else
439 syslog(LOG_INFO, "login on %s as %s",
440 tty, pwd->pw_name);
441#endif
442
443 /*
568 * If fflag is on, assume caller/authenticator has logged root login.
444 * If fflag is on, assume caller/authenticator has logged root
445 * login.
569 */
446 */
570 if (rootlogin && fflag == 0)
571 {
572 if (hostname)
447 if (rootlogin && fflag == 0) {
448 if (hflag)
573 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
449 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
574 username, tty, full_hostname);
450 username, tty, hostname);
575 else
576 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
577 username, tty);
578 }
579
580 /*
451 else
452 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
453 username, tty);
454 }
455
456 /*
581 * Destroy environment unless user has requested its preservation.
582 * We need to do this before setusercontext() because that may
583 * set or reset some environment variables.
457 * Destroy environment unless user has requested its
458 * preservation - but preserve TERM in all cases
584 */
459 */
460 term = getenv("TERM");
585 if (!pflag)
586 environ = envinit;
461 if (!pflag)
462 environ = envinit;
463 if (term != NULL)
464 setenv("TERM", term, 0);
587
588 /*
589 * PAM modules might add supplementary groups during pam_setcred().
590 */
591 if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
592 syslog(LOG_ERR, "setusercontext() failed - exiting");
465
466 /*
467 * PAM modules might add supplementary groups during pam_setcred().
468 */
469 if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
470 syslog(LOG_ERR, "setusercontext() failed - exiting");
593 exit(1);
471 bail(NO_SLEEP_EXIT, 1);
594 }
595
472 }
473
596#ifndef NO_PAM
597 if (pamh) {
598 if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
599 syslog(LOG_ERR, "pam_open_session: %s",
600 pam_strerror(pamh, e));
601 } else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED))
602 != PAM_SUCCESS) {
603 syslog(LOG_ERR, "pam_setcred: %s",
604 pam_strerror(pamh, e));
605 }
474 pam_err = pam_setcred(pamh, pam_silent|PAM_ESTABLISH_CRED);
475 if (pam_err != PAM_SUCCESS) {
476 pam_syslog("pam_setcred()");
477 bail(NO_SLEEP_EXIT, 1);
478 }
479 pam_cred_established = 1;
480
481 pam_err = pam_open_session(pamh, pam_silent);
482 if (pam_err != PAM_SUCCESS) {
483 pam_syslog("pam_open_session()");
484 bail(NO_SLEEP_EXIT, 1);
485 }
486 pam_session_established = 1;
606
487
607 /*
608 * Add any environmental variables that the
609 * PAM modules may have set.
610 * Call *after* opening session!
611 */
612 if (pamh) {
613 environ_pam = pam_getenvlist(pamh);
614 if (environ_pam)
615 export_pam_environment();
616 }
617
488 /*
489 * We must fork() before setuid() because we need to call
490 * pam_close_session() as root.
491 */
492 pid = fork();
493 if (pid < 0) {
494 err(1, "fork");
495 } else if (pid != 0) {
618 /*
496 /*
619 * We must fork() before setuid() because we need to call
620 * pam_close_session() as root.
497 * Parent: wait for child to finish, then clean up
498 * session.
621 */
499 */
622 pid = fork();
623 if (pid < 0) {
624 err(1, "fork");
625 PAM_END;
626 exit(0);
627 } else if (pid) {
628 /* parent - wait for child to finish, then cleanup
629 session */
630 wait(NULL);
631 PAM_END;
632 exit(0);
633 } else {
634 if ((e = pam_end(pamh, PAM_DATA_SILENT)) != PAM_SUCCESS)
635 syslog(LOG_ERR, "pam_end: %s",
636 pam_strerror(pamh, e));
637 }
500 wait(NULL);
501 bail(NO_SLEEP_EXIT, 0);
638 }
502 }
639#endif /* NO_PAM */
640
641 /*
503
504 /*
642 * We don't need to be root anymore, so
643 * set the user and session context
505 * NOTICE: We are now in the child process!
644 */
506 */
507
508 /*
509 * Add any environment variables the PAM modules may have set.
510 */
511 export_pam_environment();
512
513 /*
514 * We're done with PAM now; our parent will deal with the rest.
515 */
516 pam_end(pamh, PAM_DATA_SILENT);
517 pamh = NULL;
518
519 /*
520 * We don't need to be root anymore, so set the login name and
521 * the UID.
522 */
645 if (setlogin(username) != 0) {
646 syslog(LOG_ERR, "setlogin(%s): %m - exiting", username);
523 if (setlogin(username) != 0) {
524 syslog(LOG_ERR, "setlogin(%s): %m - exiting", username);
647 exit(1);
525 bail(NO_SLEEP_EXIT, 1);
648 }
649 if (setusercontext(lc, pwd, pwd->pw_uid,
650 LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) {
651 syslog(LOG_ERR, "setusercontext() failed - exiting");
652 exit(1);
653 }
654
655 (void)setenv("SHELL", pwd->pw_shell, 1);
656 (void)setenv("HOME", pwd->pw_dir, 1);
526 }
527 if (setusercontext(lc, pwd, pwd->pw_uid,
528 LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) {
529 syslog(LOG_ERR, "setusercontext() failed - exiting");
530 exit(1);
531 }
532
533 (void)setenv("SHELL", pwd->pw_shell, 1);
534 (void)setenv("HOME", pwd->pw_dir, 1);
657 if (term != NULL && *term != '\0')
658 (void)setenv("TERM", term, 1); /* Preset overrides */
659 else {
660 (void)setenv("TERM", stypeof(tty), 0); /* Fallback doesn't */
661 }
535 (void)setenv("TERM", stypeof(tty), 0);
662 (void)setenv("LOGNAME", username, 1);
663 (void)setenv("USER", username, 1);
664 (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
665
666 if (!quietlog) {
536 (void)setenv("LOGNAME", username, 1);
537 (void)setenv("USER", username, 1);
538 (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
539
540 if (!quietlog) {
667 const char *cw;
541 char *cw;
668
669 cw = login_getcapstr(lc, "copyright", NULL, NULL);
542
543 cw = login_getcapstr(lc, "copyright", NULL, NULL);
670 if (cw != NULL && access(cw, F_OK) == 0)
671 motd(cw);
672 else
673 (void)printf("%s\n\t%s %s\n",
674 "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
675 "The Regents of the University of California. ",
676 "All rights reserved.");
544 if (cw == NULL || motd(cw) == -1)
545 (void)printf("%s", copyright);
677
678 (void)printf("\n");
679
680 cw = login_getcapstr(lc, "welcome", NULL, NULL);
546
547 (void)printf("\n");
548
549 cw = login_getcapstr(lc, "welcome", NULL, NULL);
681 if (cw == NULL || access(cw, F_OK) != 0)
682 cw = _PATH_MOTDFILE;
683 motd(cw);
550 if (cw != NULL && access(cw, F_OK) == 0)
551 motd(cw);
552 else
553 motd(_PATH_MOTDFILE);
684
685 if (login_getcapbool(lc, "nocheckmail", 0) == 0) {
686 /* $MAIL may have been set by class. */
687 cw = getenv("MAIL");
554
555 if (login_getcapbool(lc, "nocheckmail", 0) == 0) {
556 /* $MAIL may have been set by class. */
557 cw = getenv("MAIL");
688 if (cw != NULL)
689 strlcpy(tbuf, cw, sizeof(tbuf));
690 else
691 snprintf(tbuf, sizeof(tbuf), "%s/%s",
558 if (cw == NULL) {
559 asprintf(&cw, "%s/%s",
692 _PATH_MAILDIR, pwd->pw_name);
560 _PATH_MAILDIR, pwd->pw_name);
693 if (stat(tbuf, &st) == 0 && st.st_size != 0)
561 }
562 if (cw && stat(cw, &st) == 0 && st.st_size != 0)
694 (void)printf("You have %smail.\n",
695 (st.st_mtime > st.st_atime) ? "new " : "");
563 (void)printf("You have %smail.\n",
564 (st.st_mtime > st.st_atime) ? "new " : "");
565 if (getenv("MAIL") == NULL)
566 free(cw);
696 }
697 }
698
699 login_close(lc);
700
701 (void)signal(SIGALRM, SIG_DFL);
702 (void)signal(SIGQUIT, SIG_DFL);
703 (void)signal(SIGINT, SIG_DFL);
704 (void)signal(SIGTSTP, SIG_IGN);
705
706 /*
707 * Login shells have a leading '-' in front of argv[0]
708 */
567 }
568 }
569
570 login_close(lc);
571
572 (void)signal(SIGALRM, SIG_DFL);
573 (void)signal(SIGQUIT, SIG_DFL);
574 (void)signal(SIGINT, SIG_DFL);
575 (void)signal(SIGTSTP, SIG_IGN);
576
577 /*
578 * Login shells have a leading '-' in front of argv[0]
579 */
709 if ((u_int)snprintf(tbuf, sizeof(tbuf), "-%s",
710 (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell) >=
711 sizeof(tbuf)) {
580 p = strrchr(pwd->pw_shell, '/');
581 if (asprintf(&arg0, "-%s", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) {
712 syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size",
713 username);
714 errx(1, "shell exceeds maximum pathname size");
582 syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size",
583 username);
584 errx(1, "shell exceeds maximum pathname size");
585 } else if (arg0 == NULL) {
586 err(1, "asprintf()");
715 }
716
587 }
588
717 execlp(shell, tbuf, (char *)0);
589 execlp(shell, arg0, (char *)0);
718 err(1, "%s", shell);
590 err(1, "%s", shell);
591
592 /*
593 * That's it, folks!
594 */
719}
720
595}
596
721static int
722auth_traditional()
723{
724 int rval;
725 char *p;
726 const char *ep;
727 const char *salt;
728
729 rval = 1;
730 salt = pwd != NULL ? pwd->pw_passwd : "xx";
731
732 p = getpass(passwd_prompt);
733 ep = crypt(p, salt);
734
735 if (pwd) {
736 if (!p[0] && pwd->pw_passwd[0])
737 ep = ":";
738 if (strcmp(ep, pwd->pw_passwd) == 0)
739 rval = 0;
740 }
741
742 /* clear entered password */
743 memset(p, 0, strlen(p));
744 return rval;
745}
746
747#ifndef NO_PAM
748/*
749 * Attempt to authenticate the user using PAM. Returns 0 if the user is
750 * authenticated, or 1 if not authenticated. If some sort of PAM system
751 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
752 * function returns -1. This can be used as an indication that we should
753 * fall back to a different authentication mechanism.
754 */
755static int
597/*
598 * Attempt to authenticate the user using PAM. Returns 0 if the user is
599 * authenticated, or 1 if not authenticated. If some sort of PAM system
600 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
601 * function returns -1. This can be used as an indication that we should
602 * fall back to a different authentication mechanism.
603 */
604static int
756auth_pam()
605auth_pam(void)
757{
758 const char *tmpl_user;
759 const void *item;
760 int rval;
606{
607 const char *tmpl_user;
608 const void *item;
609 int rval;
761 int e;
762 static struct pam_conv conv = { misc_conv, NULL };
763
610
764 if ((e = pam_start("login", username, &conv, &pamh)) != PAM_SUCCESS) {
765 syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
766 return -1;
767 }
768 if ((e = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS) {
769 syslog(LOG_ERR, "pam_set_item(PAM_TTY): %s",
770 pam_strerror(pamh, e));
771 return -1;
772 }
773 if (hostname != NULL &&
774 (e = pam_set_item(pamh, PAM_RHOST, full_hostname)) != PAM_SUCCESS) {
775 syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
776 pam_strerror(pamh, e));
777 return -1;
778 }
779 e = pam_authenticate(pamh, 0);
780 switch (e) {
611 pam_err = pam_authenticate(pamh, pam_silent);
612 switch (pam_err) {
781
782 case PAM_SUCCESS:
783 /*
784 * With PAM we support the concept of a "template"
785 * user. The user enters a login name which is
786 * authenticated by PAM, usually via a remote service
787 * such as RADIUS or TACACS+. If authentication
788 * succeeds, a different but related "template" name
789 * is used for setting the credentials, shell, and
790 * home directory. The name the user enters need only
791 * exist on the remote authentication server, but the
792 * template name must be present in the local password
793 * database.
794 *
795 * This is supported by two various mechanisms in the
796 * individual modules. However, from the application's
797 * point of view, the template user is always passed
798 * back as a changed value of the PAM_USER item.
799 */
613
614 case PAM_SUCCESS:
615 /*
616 * With PAM we support the concept of a "template"
617 * user. The user enters a login name which is
618 * authenticated by PAM, usually via a remote service
619 * such as RADIUS or TACACS+. If authentication
620 * succeeds, a different but related "template" name
621 * is used for setting the credentials, shell, and
622 * home directory. The name the user enters need only
623 * exist on the remote authentication server, but the
624 * template name must be present in the local password
625 * database.
626 *
627 * This is supported by two various mechanisms in the
628 * individual modules. However, from the application's
629 * point of view, the template user is always passed
630 * back as a changed value of the PAM_USER item.
631 */
800 if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
801 PAM_SUCCESS) {
802 tmpl_user = (const char *) item;
632 pam_err = pam_get_item(pamh, PAM_USER, &item);
633 if (pam_err == PAM_SUCCESS) {
634 tmpl_user = (const char *)item;
803 if (strcmp(username, tmpl_user) != 0)
804 pwd = getpwnam(tmpl_user);
635 if (strcmp(username, tmpl_user) != 0)
636 pwd = getpwnam(tmpl_user);
805 } else
806 syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
807 pam_strerror(pamh, e));
637 } else {
638 pam_syslog("pam_get_item(PAM_USER)");
639 }
808 rval = 0;
809 break;
810
811 case PAM_AUTH_ERR:
812 case PAM_USER_UNKNOWN:
813 case PAM_MAXTRIES:
814 rval = 1;
815 break;
816
817 default:
640 rval = 0;
641 break;
642
643 case PAM_AUTH_ERR:
644 case PAM_USER_UNKNOWN:
645 case PAM_MAXTRIES:
646 rval = 1;
647 break;
648
649 default:
818 syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e));
650 pam_syslog("pam_authenticate()");
819 rval = -1;
820 break;
821 }
822
823 if (rval == 0) {
651 rval = -1;
652 break;
653 }
654
655 if (rval == 0) {
824 e = pam_acct_mgmt(pamh, 0);
825 if (e == PAM_NEW_AUTHTOK_REQD) {
826 e = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
827 if (e != PAM_SUCCESS) {
828 syslog(LOG_ERR, "pam_chauthtok: %s",
829 pam_strerror(pamh, e));
656 pam_err = pam_acct_mgmt(pamh, pam_silent);
657 switch (pam_err) {
658 case PAM_SUCCESS:
659 break;
660 case PAM_NEW_AUTHTOK_REQD:
661 pam_err = pam_chauthtok(pamh,
662 pam_silent|PAM_CHANGE_EXPIRED_AUTHTOK);
663 if (pam_err != PAM_SUCCESS) {
664 pam_syslog("pam_chauthtok()");
830 rval = 1;
831 }
665 rval = 1;
666 }
832 } else if (e != PAM_SUCCESS) {
667 break;
668 default:
669 pam_syslog("pam_acct_mgmt()");
833 rval = 1;
670 rval = 1;
671 break;
834 }
835 }
836
837 if (rval != 0) {
672 }
673 }
674
675 if (rval != 0) {
838 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
839 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
840 }
676 pam_end(pamh, pam_err);
841 pamh = NULL;
842 }
677 pamh = NULL;
678 }
843 return rval;
679 return (rval);
844}
845
680}
681
846static int
682/*
683 * Export any environment variables PAM modules may have set
684 */
685static void
847export_pam_environment()
848{
686export_pam_environment()
687{
849 char **pp;
688 char **pam_env;
689 char **pp;
850
690
851 for (pp = environ_pam; *pp != NULL; pp++) {
852 if (ok_to_export(*pp))
853 (void) putenv(*pp);
854 free(*pp);
691 pam_env = pam_getenvlist(pamh);
692 if (pam_env != NULL) {
693 for (pp = pam_env; *pp != NULL; pp++) {
694 (void)export(*pp);
695 free(*pp);
696 }
855 }
697 }
856 return PAM_SUCCESS;
857}
858
859/*
698}
699
700/*
860 * Sanity checks on PAM environmental variables:
701 * Perform sanity checks on an environment variable:
861 * - Make sure there is an '=' in the string.
862 * - Make sure the string doesn't run on too long.
863 * - Do not export certain variables. This list was taken from the
864 * Solaris pam_putenv(3) man page.
702 * - Make sure there is an '=' in the string.
703 * - Make sure the string doesn't run on too long.
704 * - Do not export certain variables. This list was taken from the
705 * Solaris pam_putenv(3) man page.
706 * Then export it.
865 */
866static int
707 */
708static int
867ok_to_export(s)
868 const char *s;
709export(const char *s)
869{
870 static const char *noexport[] = {
871 "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
872 "IFS", "PATH", NULL
873 };
874 const char **pp;
875 size_t n;
876
877 if (strlen(s) > 1024 || strchr(s, '=') == NULL)
710{
711 static const char *noexport[] = {
712 "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
713 "IFS", "PATH", NULL
714 };
715 const char **pp;
716 size_t n;
717
718 if (strlen(s) > 1024 || strchr(s, '=') == NULL)
878 return 0;
719 return (0);
879 if (strncmp(s, "LD_", 3) == 0)
720 if (strncmp(s, "LD_", 3) == 0)
880 return 0;
721 return (0);
881 for (pp = noexport; *pp != NULL; pp++) {
882 n = strlen(*pp);
883 if (s[n] == '=' && strncmp(s, *pp, n) == 0)
722 for (pp = noexport; *pp != NULL; pp++) {
723 n = strlen(*pp);
724 if (s[n] == '=' && strncmp(s, *pp, n) == 0)
884 return 0;
725 return (0);
885 }
726 }
886 return 1;
727 (void)putenv(s);
728 return (1);
887}
729}
888#endif /* NO_PAM */
889
890static void
891usage()
892{
893
894 (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n");
895 exit(1);
896}
897
898/*
730
731static void
732usage()
733{
734
735 (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n");
736 exit(1);
737}
738
739/*
899 * Allow for authentication style and/or kerberos instance
740 * Prompt user and read login name from stdin.
900 */
741 */
901
902void
742static char *
903getloginname()
904{
743getloginname()
744{
745 char *nbuf, *p;
905 int ch;
746 int ch;
906 char *p;
907 static char nbuf[NBUFSIZ];
908
747
909 for (;;) {
748 nbuf = malloc(MAXLOGNAME);
749 if (nbuf == NULL)
750 err(1, "malloc()");
751 do {
910 (void)printf("%s", prompt);
911 for (p = nbuf; (ch = getchar()) != '\n'; ) {
912 if (ch == EOF) {
913 badlogin(username);
752 (void)printf("%s", prompt);
753 for (p = nbuf; (ch = getchar()) != '\n'; ) {
754 if (ch == EOF) {
755 badlogin(username);
914 exit(0);
756 bail(NO_SLEEP_EXIT, 0);
915 }
757 }
916 if (p < nbuf + (NBUFSIZ - 1))
758 if (p < nbuf + MAXLOGNAME - 1)
917 *p++ = ch;
918 }
759 *p++ = ch;
760 }
919 if (p > nbuf) {
920 if (nbuf[0] == '-')
921 (void)fprintf(stderr,
922 "login names may not start with '-'.\n");
923 else {
924 *p = '\0';
925 username = nbuf;
926 break;
927 }
928 }
761 } while (p == nbuf);
762
763 *p = '\0';
764 if (nbuf[0] == '-') {
765 pam_silent = 0;
766 memmove(nbuf, nbuf + 1, strlen(nbuf));
767 } else {
768 pam_silent = PAM_SILENT;
929 }
769 }
770 return nbuf;
930}
931
771}
772
932int
933rootterm(ttyn)
934 char *ttyn;
773/*
774 * SIGINT handler for motd().
775 */
776static volatile int motdinterrupt;
777static void
778sigint(int signo __unused)
935{
779{
936 struct ttyent *t;
937
938 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
939}
940
941volatile int motdinterrupt;
942
943void
944sigint(signo)
945 int signo __unused;
946{
947 motdinterrupt = 1;
948}
949
780 motdinterrupt = 1;
781}
782
950void
951motd(motdfile)
952 const char *motdfile;
783/*
784 * Display the contents of a file (such as /etc/motd).
785 */
786static int
787motd(const char *motdfile)
953{
788{
954 int fd, nchars;
955 sig_t oldint;
789 sig_t oldint;
956 char tbuf[256];
790 FILE *f;
791 int ch;
957
792
958 if ((fd = open(motdfile, O_RDONLY, 0)) < 0)
959 return;
793 if ((f = fopen(motdfile, "r")) == NULL)
794 return (-1);
960 motdinterrupt = 0;
961 oldint = signal(SIGINT, sigint);
795 motdinterrupt = 0;
796 oldint = signal(SIGINT, sigint);
962 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0 && !motdinterrupt)
963 (void)write(fileno(stdout), tbuf, nchars);
964 (void)signal(SIGINT, oldint);
965 (void)close(fd);
797 while ((ch = fgetc(f)) != EOF && !motdinterrupt)
798 putchar(ch);
799 signal(SIGINT, oldint);
800 if (ch != EOF || ferror(f)) {
801 fclose(f);
802 return (-1);
803 }
804 fclose(f);
805 return (0);
966}
967
806}
807
968/* ARGSUSED */
969void
970timedout(signo)
971 int signo;
808/*
809 * SIGALRM handler, to enforce login prompt timeout.
810 *
811 * XXX This can potentially confuse the hell out of PAM. We should
812 * XXX instead implement a conversation function that returns
813 * XXX PAM_CONV_ERR when interrupted by a signal, and have the signal
814 * XXX handler just set a flag.
815 */
816static void
817timedout(int signo __unused)
972{
973
974 longjmp(timeout_buf, signo);
975}
976
818{
819
820 longjmp(timeout_buf, signo);
821}
822
977
978void
823void
979dolastlog(quiet)
980 int quiet;
824badlogin(char *name)
981{
825{
982 struct lastlog ll;
983 int fd;
984
826
985 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
986 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
987 if (!quiet) {
988 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
989 ll.ll_time != 0) {
990 (void)printf("Last login: %.*s ",
991 24-5, (char *)ctime(&ll.ll_time));
992 if (*ll.ll_host != '\0')
993 (void)printf("from %.*s\n",
994 (int)sizeof(ll.ll_host),
995 ll.ll_host);
996 else
997 (void)printf("on %.*s\n",
998 (int)sizeof(ll.ll_line),
999 ll.ll_line);
1000 }
1001 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
1002 }
1003 memset((void *)&ll, 0, sizeof(ll));
1004 (void)time(&ll.ll_time);
1005 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
1006 if (hostname)
1007 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
1008 (void)write(fd, (char *)&ll, sizeof(ll));
1009 (void)close(fd);
1010 } else {
1011 syslog(LOG_ERR, "cannot open %s: %m", _PATH_LASTLOG);
1012 }
1013}
1014
1015void
1016badlogin(name)
1017 char *name;
1018{
1019
1020 if (failures == 0)
1021 return;
827 if (failures == 0)
828 return;
1022 if (hostname) {
829 if (hflag) {
1023 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
830 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
1024 failures, failures > 1 ? "S" : "", full_hostname);
831 failures, failures > 1 ? "S" : "", hostname);
1025 syslog(LOG_AUTHPRIV|LOG_NOTICE,
1026 "%d LOGIN FAILURE%s FROM %s, %s",
832 syslog(LOG_AUTHPRIV|LOG_NOTICE,
833 "%d LOGIN FAILURE%s FROM %s, %s",
1027 failures, failures > 1 ? "S" : "", full_hostname, name);
834 failures, failures > 1 ? "S" : "", hostname, name);
1028 } else {
1029 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
1030 failures, failures > 1 ? "S" : "", tty);
1031 syslog(LOG_AUTHPRIV|LOG_NOTICE,
1032 "%d LOGIN FAILURE%s ON %s, %s",
1033 failures, failures > 1 ? "S" : "", tty, name);
1034 }
1035 failures = 0;
1036}
1037
1038const char *
835 } else {
836 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
837 failures, failures > 1 ? "S" : "", tty);
838 syslog(LOG_AUTHPRIV|LOG_NOTICE,
839 "%d LOGIN FAILURE%s ON %s, %s",
840 failures, failures > 1 ? "S" : "", tty, name);
841 }
842 failures = 0;
843}
844
845const char *
1039stypeof(ttyid)
1040 char *ttyid;
846stypeof(char *ttyid)
1041{
1042 struct ttyent *t;
1043
1044 if (ttyid != NULL && *ttyid != '\0') {
1045 t = getttynam(ttyid);
1046 if (t != NULL && t->ty_type != NULL)
1047 return (t->ty_type);
1048 }
847{
848 struct ttyent *t;
849
850 if (ttyid != NULL && *ttyid != '\0') {
851 t = getttynam(ttyid);
852 if (t != NULL && t->ty_type != NULL)
853 return (t->ty_type);
854 }
1049 return (UNKNOWN);
855 return (TERM_UNKNOWN);
1050}
1051
1052void
856}
857
858void
1053refused(msg, rtype, lout)
1054 const char *msg;
1055 const char *rtype;
1056 int lout;
859refused(const char *msg, const char *rtype, int lout)
1057{
1058
1059 if (msg != NULL)
1060 printf("%s.\n", msg);
860{
861
862 if (msg != NULL)
863 printf("%s.\n", msg);
1061 if (hostname)
864 if (hflag)
1062 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
865 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
1063 pwd->pw_name, rtype, full_hostname, tty);
866 pwd->pw_name, rtype, hostname, tty);
1064 else
1065 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
1066 pwd->pw_name, rtype, tty);
1067 if (lout)
867 else
868 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
869 pwd->pw_name, rtype, tty);
870 if (lout)
1068 sleepexit(1);
871 bail(SLEEP_EXIT, 1);
1069}
1070
872}
873
874/*
875 * Log a PAM error
876 */
1071void
877void
1072sleepexit(eval)
1073 int eval;
878pam_syslog(const char *msg)
1074{
879{
880 syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err));
881}
1075
882
1076 (void)sleep(5);
883/*
884 * Shut down PAM
885 */
886void
887pam_cleanup()
888{
889
890 if (pamh != NULL) {
891 if (pam_session_established) {
892 pam_err = pam_close_session(pamh, 0);
893 if (pam_err != PAM_SUCCESS)
894 pam_syslog("pam_close_session()");
895 }
896 pam_session_established = 0;
897 if (pam_cred_established) {
898 pam_err = pam_setcred(pamh, pam_silent|PAM_DELETE_CRED);
899 if (pam_err != PAM_SUCCESS)
900 pam_syslog("pam_setcred()");
901 }
902 pam_cred_established = 0;
903 pam_end(pamh, pam_err);
904 pamh = NULL;
905 }
906}
907
908/*
909 * Exit, optionally after sleeping a few seconds
910 */
911void
912bail(int sec, int eval)
913{
914
915 pam_cleanup();
916 (void)sleep(sec);
1077 exit(eval);
1078}
917 exit(eval);
918}