]> git.saurik.com Git - apple/system_cmds.git/blame - login.tproj/login.c
system_cmds-336.6.tar.gz
[apple/system_cmds.git] / login.tproj / login.c
CommitLineData
1815bff5 1/*
2fc1e207 2 * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved.
1815bff5
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
2fc1e207
A
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
1815bff5
A
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2fc1e207
A
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
1815bff5
A
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*-
25 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
26 * The Regents of the University of California. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
2fc1e207 57#if 0
1815bff5
A
58static char copyright[] =
59"@(#) Copyright (c) Apple Computer, Inc. 1997\n\n";
2fc1e207 60#endif
1815bff5
A
61
62/*
63 * login [ name ]
64 * login -h hostname (for telnetd, etc.)
65 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
66 */
67
68#include <sys/param.h>
69#include <sys/stat.h>
70#include <sys/time.h>
71#include <sys/resource.h>
72#include <sys/file.h>
b51d5b5f 73#include <sys/wait.h>
1815bff5
A
74
75#include <err.h>
76#include <errno.h>
77#include <grp.h>
78#include <pwd.h>
79#include <setjmp.h>
80#include <signal.h>
81#include <stdio.h>
82#include <stdlib.h>
83#include <string.h>
84#include <syslog.h>
85#include <ttyent.h>
86#include <tzfile.h>
87#include <unistd.h>
88#include <utmp.h>
89
2fc1e207
A
90#include <sys/types.h>
91#include <sys/socket.h>
92#include <netinet/in.h>
93#include <arpa/inet.h>
94#include <netdb.h>
95
96#include <bsm/libbsm.h>
97#include <bsm/audit_uevents.h>
98
b51d5b5f
A
99#ifdef USE_PAM
100#include <pam/pam_appl.h>
101#include <pam/pam_misc.h>
102#endif
103
1815bff5
A
104#include "pathnames.h"
105
106void badlogin __P((char *));
107void checknologin __P((void));
108void dolastlog __P((int));
109void getloginname __P((void));
110void motd __P((void));
111int rootterm __P((char *));
112void sigint __P((int));
113void sleepexit __P((int));
114char *stypeof __P((char *));
115void timedout __P((int));
116#ifdef KERBEROS
117int klogin __P((struct passwd *, char *, char *, char *));
118#endif
2fc1e207
A
119void au_success();
120void au_fail(char *, int);
121
1815bff5
A
122
123extern void login __P((struct utmp *));
2fc1e207
A
124static void bail(int, int);
125static void refused(const char *, const char *, int);
1815bff5
A
126
127#define TTYGRPNAME "tty" /* name of group to own ttys */
2fc1e207
A
128#define NO_SLEEP_EXIT 0
129#define SLEEP_EXIT 5
1815bff5
A
130
131/*
132 * This bounds the time given to login. Not a define so it can
133 * be patched on machines where it's too small.
134 */
135u_int timeout = 300;
136
137#ifdef KERBEROS
138int notickets = 1;
139char *instance;
140char *krbtkfile_env;
141int authok;
142#endif
143
144struct passwd *pwd;
145int failures;
b51d5b5f 146char term[64], *hostname, *username = NULL, *tty;
2fc1e207
A
147#ifdef USE_PAM
148static pam_handle_t *pamh = NULL;
149static struct pam_conv conv = { misc_conv, NULL };
150static int pam_err;
151static int pam_silent = PAM_SILENT;
152static int pam_cred_established;
153static int pam_session_established;
154#endif /* USE_PAM */
155int hflag;
156
157#define NA_EVENT_STR_SIZE 25
158au_tid_t tid;
1815bff5
A
159
160int
161main(argc, argv)
162 int argc;
163 char *argv[];
164{
165 extern char **environ;
166 struct group *gr;
167 struct stat st;
1815bff5 168 struct utmp utmp;
2fc1e207 169 int ask, ch, cnt, oflag = 0, fflag, pflag, quietlog, rootlogin = 0;
1815bff5 170 uid_t uid;
b51d5b5f
A
171 uid_t euid;
172 gid_t egid;
2fc1e207 173 char *domain, *p, *ttyn;
1815bff5
A
174 char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
175 char localhost[MAXHOSTNAMELEN];
b51d5b5f 176#ifdef USE_PAM
b51d5b5f
A
177 char **pmenv;
178 pid_t pid;
2fc1e207
A
179#else
180 int rval;
181 char *salt;
b51d5b5f 182#endif
1815bff5 183
2fc1e207
A
184 char auditsuccess = 1;
185
1815bff5
A
186 (void)signal(SIGALRM, timedout);
187 (void)alarm(timeout);
188 (void)signal(SIGQUIT, SIG_IGN);
189 (void)signal(SIGINT, SIG_IGN);
190 (void)setpriority(PRIO_PROCESS, 0, 0);
191
192 openlog("login", LOG_ODELAY, LOG_AUTH);
193
194 /*
195 * -p is used by getty to tell login not to destroy the environment
196 * -f is used to skip a second login authentication
197 * -h is used by other servers to pass the name of the remote
198 * host to login so that it may be placed in utmp and wtmp
199 */
200 domain = NULL;
201 if (gethostname(localhost, sizeof(localhost)) < 0)
202 syslog(LOG_ERR, "couldn't get local hostname: %m");
203 else
204 domain = strchr(localhost, '.');
b51d5b5f
A
205
206 euid = geteuid();
207 egid = getegid();
1815bff5
A
208
209 fflag = hflag = pflag = 0;
210 uid = getuid();
20e66415 211 while ((ch = getopt(argc, argv, "1fh:p")) != EOF)
1815bff5 212 switch (ch) {
20e66415
A
213 case '1':
214 oflag = 1;
215 break;
1815bff5
A
216 case 'f':
217 fflag = 1;
218 break;
219 case 'h':
220 if (uid)
221 errx(1, "-h option: %s", strerror(EPERM));
222 hflag = 1;
223 if (domain && (p = strchr(optarg, '.')) &&
224 strcasecmp(p, domain) == 0)
225 *p = 0;
226 hostname = optarg;
227 break;
228 case 'p':
229 pflag = 1;
230 break;
231 case '?':
232 default:
233 if (!uid)
234 syslog(LOG_ERR, "invalid flag %c", ch);
235 (void)fprintf(stderr,
236 "usage: login [-fp] [-h hostname] [username]\n");
237 exit(1);
238 }
239 argc -= optind;
240 argv += optind;
241
242 if (*argv) {
243 username = *argv;
244 ask = 0;
245 } else
246 ask = 1;
247
248 for (cnt = getdtablesize(); cnt > 2; cnt--)
249 (void)close(cnt);
250
251 ttyn = ttyname(STDIN_FILENO);
252 if (ttyn == NULL || *ttyn == '\0') {
253 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
254 ttyn = tname;
255 }
256 if (tty = strrchr(ttyn, '/'))
257 ++tty;
258 else
259 tty = ttyn;
260
2fc1e207
A
261 /* Set the terminal id */
262 audit_set_terminal_id(&tid);
263 if (fstat(STDIN_FILENO, &st) < 0) {
264 fprintf(stderr, "login: Unable to stat terminal\n");
265 au_fail("Unable to stat terminal", 1);
266 exit(-1);
267 }
268 if (S_ISCHR(st.st_mode)) {
269 tid.port = st.st_rdev;
270 } else {
271 tid.port = 0;
272 }
273
b51d5b5f 274#ifdef USE_PAM
2fc1e207
A
275 pam_err = pam_start("login", username, &conv, &pamh);
276 if( pam_err != PAM_SUCCESS ) {
277 fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, pam_err));
278 au_fail("PAM Error", 1);
b51d5b5f
A
279 exit(1);
280 }
2fc1e207
A
281 pam_err = pam_set_item(pamh, PAM_TTY, tty);
282 if( pam_err != PAM_SUCCESS ) {
283 fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, pam_err));
284 au_fail("PAM Error", 1);
b51d5b5f
A
285 exit(1);
286 }
287
2fc1e207
A
288 pam_err = pam_set_item(pamh, PAM_RHOST, hostname);
289 if( pam_err != PAM_SUCCESS ) {
290 fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, pam_err));
291 au_fail("PAM Error", 1);
b51d5b5f
A
292 exit(1);
293 }
294
2fc1e207
A
295 pam_err = pam_set_item(pamh, PAM_USER_PROMPT, "login: ");
296 if( pam_err != PAM_SUCCESS ) {
297 fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, pam_err));
298 au_fail("PAM Error", 1);
b51d5b5f
A
299 exit(1);
300 }
301
302 if( !username )
303 getloginname();
304 pam_set_item(pamh, PAM_USER, username);
305 pwd = getpwnam(username);
306 if( (pwd != NULL) && (pwd->pw_uid == 0) )
307 rootlogin = 1;
308
309 if( (pwd != NULL) && fflag && ((uid == 0) || (uid == pwd->pw_uid)) ){
2fc1e207
A
310 pam_err = 0;
311 auditsuccess = 0; /* we've simply opened a terminal window */
b51d5b5f
A
312 } else {
313
2fc1e207
A
314 pam_err = pam_authenticate(pamh, 0);
315 while( (!oflag) && (cnt++ < 10) && ((pam_err == PAM_AUTH_ERR) ||
316 (pam_err == PAM_USER_UNKNOWN) ||
317 (pam_err == PAM_CRED_INSUFFICIENT) ||
318 (pam_err == PAM_AUTHINFO_UNAVAIL))) {
319 /*
320 * we are not exiting here, but this corresponds to
321 * a failed login event, so set exitstatus to 1
322 */
323 au_fail("Login incorrect", 1);
b51d5b5f
A
324 badlogin(username);
325 printf("Login incorrect\n");
326 rootlogin = 0;
327 getloginname();
328 pwd = getpwnam(username);
329 if( (pwd != NULL) && (pwd->pw_uid == 0) )
330 rootlogin = 1;
331 pam_set_item(pamh, PAM_USER, username);
2fc1e207 332 pam_err = pam_authenticate(pamh, 0);
b51d5b5f
A
333 }
334
2fc1e207 335 if( pam_err != PAM_SUCCESS ) {
b51d5b5f
A
336 pam_get_item(pamh, PAM_USER, (void *)&username);
337 badlogin(username);
338 printf("Login incorrect\n");
2fc1e207 339 au_fail("Login incorrect", 1);
b51d5b5f
A
340 exit(1);
341 }
342
2fc1e207
A
343 pam_err = pam_acct_mgmt(pamh, 0);
344 if( pam_err == PAM_NEW_AUTHTOK_REQD ) {
345 pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
b51d5b5f 346 }
2fc1e207
A
347 if( pam_err != PAM_SUCCESS ) {
348 fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, pam_err));
349 au_fail("PAM error", 1);
b51d5b5f
A
350 exit(1);
351 }
352 }
353
2fc1e207
A
354 pam_err = pam_get_item(pamh, PAM_USER, (void *)&username);
355 if( (pam_err == PAM_SUCCESS) && username && *username)
b51d5b5f
A
356 pwd = getpwnam(username);
357
2fc1e207
A
358 pam_err = pam_open_session(pamh, 0);
359 if( pam_err != PAM_SUCCESS ) {
360 fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, pam_err));
361 au_fail("PAM error", 1);
b51d5b5f
A
362 exit(1);
363 }
364
2fc1e207
A
365 pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED);
366 if( pam_err != PAM_SUCCESS ) {
367 fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, pam_err));
368 au_fail("PAM error", 1);
b51d5b5f
A
369 exit(1);
370 }
371
372#else /* USE_PAM */
1815bff5
A
373 for (cnt = 0;; ask = 1) {
374 if (ask) {
375 fflag = 0;
376 getloginname();
377 }
378 rootlogin = 0;
379#ifdef KERBEROS
380 if ((instance = strchr(username, '.')) != NULL) {
381 if (strncmp(instance, ".root", 5) == 0)
382 rootlogin = 1;
383 *instance++ = '\0';
384 } else
385 instance = "";
386#endif
387 if (strlen(username) > UT_NAMESIZE)
388 username[UT_NAMESIZE] = '\0';
389
390 /*
391 * Note if trying multiple user names; log failures for
392 * previous user name, but don't bother logging one failure
393 * for nonexistent name (mistyped username).
394 */
395 if (failures && strcmp(tbuf, username)) {
2fc1e207 396 if (failures > (pwd ? 0 : 1)) {
1815bff5 397 badlogin(tbuf);
2fc1e207 398 }
1815bff5
A
399 failures = 0;
400 }
401 (void)strcpy(tbuf, username);
402
403 if (pwd = getpwnam(username))
404 salt = pwd->pw_passwd;
405 else
406 salt = "xx";
407
408 /*
409 * if we have a valid account name, and it doesn't have a
410 * password, or the -f option was specified and the caller
411 * is root or the caller isn't changing their uid, don't
412 * authenticate.
413 */
414 if (pwd && (*pwd->pw_passwd == '\0' ||
415 fflag && (uid == 0 || uid == pwd->pw_uid)))
416 break;
417 fflag = 0;
418 if (pwd && pwd->pw_uid == 0)
419 rootlogin = 1;
420
421 (void)setpriority(PRIO_PROCESS, 0, -4);
422
423 p = getpass("Password:");
424
425 if (pwd) {
426#ifdef KERBEROS
427 rval = klogin(pwd, instance, localhost, p);
428 if (rval != 0 && rootlogin && pwd->pw_uid != 0)
429 rootlogin = 0;
430 if (rval == 0)
431 authok = 1;
432 else if (rval == 1)
433 rval = strcmp(crypt(p, salt), pwd->pw_passwd);
434#else
435 rval = strcmp(crypt(p, salt), pwd->pw_passwd);
436#endif
437 }
438 memset(p, 0, strlen(p));
439
440 (void)setpriority(PRIO_PROCESS, 0, 0);
441
442 /*
443 * If trying to log in as root without Kerberos,
444 * but with insecure terminal, refuse the login attempt.
445 */
446#ifdef KERBEROS
447 if (authok == 0)
448#endif
449 if (pwd && rootlogin && !rootterm(tty)) {
450 (void)fprintf(stderr,
451 "%s login refused on this terminal.\n",
452 pwd->pw_name);
453 if (hostname)
454 syslog(LOG_NOTICE,
455 "LOGIN %s REFUSED FROM %s ON TTY %s",
456 pwd->pw_name, hostname, tty);
457 else
458 syslog(LOG_NOTICE,
459 "LOGIN %s REFUSED ON TTY %s",
460 pwd->pw_name, tty);
2fc1e207 461 au_fail("Login refused on terminal", 0);
1815bff5
A
462 continue;
463 }
464
465 if (pwd && !rval)
466 break;
467
468 (void)printf("Login incorrect\n");
469 failures++;
470 /* we allow 10 tries, but after 3 we start backing off */
471 if (++cnt > 3) {
472 if (cnt >= 10) {
473 badlogin(username);
2fc1e207 474 au_fail("Login incorrect", 1);
1815bff5
A
475 sleepexit(1);
476 }
2fc1e207 477 au_fail("Login incorrect", 1);
1815bff5
A
478 sleep((u_int)((cnt - 3) * 5));
479 }
480 }
b51d5b5f 481#endif
1815bff5
A
482
483 /* committed to login -- turn off timeout */
484 (void)alarm((u_int)0);
485
486 endpwent();
487
488 /* if user not super-user, check for disabled logins */
489 if (!rootlogin)
490 checknologin();
491
2fc1e207
A
492 /* Audit successful login */
493 if (auditsuccess)
494 au_success();
495
b51d5b5f
A
496 setegid(pwd->pw_gid);
497 seteuid(rootlogin ? 0 : pwd->pw_uid);
498
83f6dbe8 499 /* First do a stat in case the homedir is automounted */
2fc1e207 500 stat(pwd->pw_dir,&st);
b51d5b5f 501
2fc1e207
A
502 if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
503 printf("No home directory %s!\n", pwd->pw_dir);
504 if (chdir("/")) {
505 refused("Cannot find root directory", "HOMEDIR", 1);
506 }
507 pwd->pw_dir = strdup("/");
508 if (pwd->pw_dir == NULL) {
509 syslog(LOG_NOTICE, "strdup(): %m");
510 bail(SLEEP_EXIT, 1);
511 }
512 printf("Logging in with home = \"/\".\n");
1815bff5 513 }
b51d5b5f
A
514 seteuid(euid);
515 setegid(egid);
1815bff5
A
516
517 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
518
1815bff5
A
519 /* Nothing else left to fail -- really log in. */
520 memset((void *)&utmp, 0, sizeof(utmp));
521 (void)time(&utmp.ut_time);
522 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
523 if (hostname)
524 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
525 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
526 login(&utmp);
527
528 dolastlog(quietlog);
529
530 (void)chown(ttyn, pwd->pw_uid,
531 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
1c51fdde 532 (void)chmod(ttyn, 0620);
1815bff5
A
533 (void)setgid(pwd->pw_gid);
534
2fc1e207
A
535 if (initgroups(username, pwd->pw_gid) == -1)
536 syslog(LOG_ERR, "login: initgroups() failed");
1815bff5
A
537
538 if (*pwd->pw_shell == '\0')
2fc1e207
A
539 pwd->pw_shell = strdup(_PATH_BSHELL);
540 if (pwd->pw_shell == NULL) {
541 syslog(LOG_NOTICE, "strdup(): %m");
542 bail(SLEEP_EXIT, 1);
543 }
1815bff5
A
544
545 /* Destroy environment unless user has requested its preservation. */
b51d5b5f
A
546 if (!pflag) {
547 environ = malloc(sizeof(char *));
548 *environ = NULL;
549 }
1815bff5
A
550 (void)setenv("HOME", pwd->pw_dir, 1);
551 (void)setenv("SHELL", pwd->pw_shell, 1);
552 if (term[0] == '\0')
553 (void)strncpy(term, stypeof(tty), sizeof(term));
554 (void)setenv("TERM", term, 0);
555 (void)setenv("LOGNAME", pwd->pw_name, 1);
556 (void)setenv("USER", pwd->pw_name, 1);
557 (void)setenv("PATH", _PATH_DEFPATH, 0);
558#ifdef KERBEROS
559 if (krbtkfile_env)
560 (void)setenv("KRBTKFILE", krbtkfile_env, 1);
561#endif
562
b51d5b5f
A
563#ifdef USE_PAM
564 pmenv = pam_getenvlist(pamh);
565 for( cnt = 0; pmenv && pmenv[cnt]; cnt++ )
566 putenv(pmenv[cnt]);
567
568 pid = fork();
569 if ( pid < 0 ) {
570 err(1, "fork");
571 } else if( pid != 0 ) {
572 waitpid(pid, NULL, 0);
573 pam_setcred(pamh, PAM_DELETE_CRED);
2fc1e207
A
574 pam_err = pam_close_session(pamh, 0);
575 pam_end(pamh,pam_err);
83f6dbe8
A
576 chown(ttyn, 0, 0);
577 chmod(ttyn, 0666);
b51d5b5f
A
578 exit(0);
579 }
580
581#endif
582
1815bff5
A
583 if (tty[sizeof("tty")-1] == 'd')
584 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
585
586 /* If fflag is on, assume caller/authenticator has logged root login. */
587 if (rootlogin && fflag == 0)
588 if (hostname)
589 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
590 username, tty, hostname);
591 else
592 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);
593
594#ifdef KERBEROS
595 if (!quietlog && notickets == 1)
596 (void)printf("Warning: no Kerberos tickets issued.\n");
597#endif
598
599 if (!quietlog) {
600 motd();
601 (void)snprintf(tbuf,
602 sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
603 if (stat(tbuf, &st) == 0 && st.st_size != 0)
604 (void)printf("You have %smail.\n",
605 (st.st_mtime > st.st_atime) ? "new " : "");
606 }
607
608 (void)signal(SIGALRM, SIG_DFL);
609 (void)signal(SIGQUIT, SIG_DFL);
610 (void)signal(SIGINT, SIG_DFL);
611 (void)signal(SIGTSTP, SIG_IGN);
612
613 tbuf[0] = '-';
614 (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
615 p + 1 : pwd->pw_shell);
616
617 if (setlogin(pwd->pw_name) < 0)
618 syslog(LOG_ERR, "setlogin() failure: %m");
619
620 /* Discard permissions last so can't get killed and drop core. */
621 if (rootlogin)
622 (void) setuid(0);
623 else
624 (void) setuid(pwd->pw_uid);
625
626 execlp(pwd->pw_shell, tbuf, 0);
627 err(1, "%s", pwd->pw_shell);
628}
629
630#ifdef KERBEROS
b51d5b5f 631#define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
1815bff5 632#else
b51d5b5f 633#define NBUFSIZ (MAXLOGNAME + 1)
1815bff5
A
634#endif
635
2fc1e207
A
636/*
637 * The following tokens are included in the audit record for successful login attempts
638 * header
639 * subject
640 * return
641 */
642void au_success()
643{
644 token_t *tok;
645 int aufd;
646 au_mask_t aumask;
647 auditinfo_t auinfo;
648 uid_t uid = pwd->pw_uid;
649 gid_t gid = pwd->pw_gid;
650 pid_t pid = getpid();
651 long au_cond;
652
653 /* If we are not auditing, don't cut an audit record; just return */
654 if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
655 fprintf(stderr, "login: Could not determine audit condition\n");
656 exit(1);
657 }
658 if (au_cond == AUC_NOAUDIT)
659 return;
660
661 /* Compute and Set the user's preselection mask */
662 if(au_user_mask(pwd->pw_name, &aumask) == -1) {
663 fprintf(stderr, "login: Could not set audit mask\n");
664 exit(1);
665 }
666
667 /* Set the audit info for the user */
668 auinfo.ai_auid = uid;
669 auinfo.ai_asid = pid;
670 bcopy(&tid, &auinfo.ai_termid, sizeof(auinfo.ai_termid));
671 bcopy(&aumask, &auinfo.ai_mask, sizeof(auinfo.ai_mask));
672 if(setaudit(&auinfo) != 0) {
673 fprintf(stderr, "login: setaudit failed: %s\n", strerror(errno));
674 exit(1);
675 }
676
677 if((aufd = au_open()) == -1) {
678 fprintf(stderr, "login: Audit Error: au_open() failed\n");
679 exit(1);
680 }
681
682 /* The subject that is created (euid, egid of the current process) */
683 if((tok = au_to_subject32(uid, geteuid(), getegid(),
684 uid, gid, pid, pid, &tid)) == NULL) {
685 fprintf(stderr, "login: Audit Error: au_to_subject32() failed\n");
686 exit(1);
687 }
688 au_write(aufd, tok);
689
690 if((tok = au_to_return32(0, 0)) == NULL) {
691 fprintf(stderr, "login: Audit Error: au_to_return32() failed\n");
692 exit(1);
693 }
694 au_write(aufd, tok);
695
696 if(au_close(aufd, 1, AUE_login) == -1) {
697 fprintf(stderr, "login: Audit Record was not committed.\n");
698 exit(1);
699 }
700}
701
702/*
703 * The following tokens are included in the audit record for successful login attempts
704 * header
705 * subject
706 * text
707 * return
708 */
709void au_fail(char *errmsg, int na)
710{
711 token_t *tok;
712 int aufd;
713 long au_cond;
714 uid_t uid;
715 gid_t gid;
716 pid_t pid = getpid();
717
718 /* If we are not auditing, don't cut an audit record; just return */
719 if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
720 fprintf(stderr, "login: Could not determine audit condition\n");
721 exit(1);
722 }
723 if (au_cond == AUC_NOAUDIT)
724 return;
725
726 if((aufd = au_open()) == -1) {
727 fprintf(stderr, "login: Audit Error: au_open() failed\n");
728 exit(1);
729 }
730
731 if(na) {
732 /* Non attributable event */
733 /* Assuming that login is not called within a users' session => auid,asid == -1 */
734 if((tok = au_to_subject32(-1, geteuid(), getegid(), -1, -1,
735 pid, -1, &tid)) == NULL) {
736
737 fprintf(stderr, "login: Audit Error: au_to_subject32() failed\n");
738 exit(1);
739 }
740 }
741 else {
742 /* we know the subject -- so use its value instead */
743 uid = pwd->pw_uid;
744 gid = pwd->pw_gid;
745 if((tok = au_to_subject32(uid, geteuid(), getegid(),
746 uid, gid, pid, pid, &tid)) == NULL) {
747 fprintf(stderr, "login: Audit Error: au_to_subject32() failed\n");
748 exit(1);
749 }
750 }
751 au_write(aufd, tok);
752
753 /* Include the error message */
754 if((tok = au_to_text(errmsg)) == NULL) {
755 fprintf(stderr, "login: Audit Error: au_to_text() failed\n");
756 exit(1);
757 }
758 au_write(aufd, tok);
759
760 if((tok = au_to_return32(1, errno)) == NULL) {
761 fprintf(stderr, "login: Audit Error: au_to_return32() failed\n");
762 exit(1);
763 }
764 au_write(aufd, tok);
765
766 if(au_close(aufd, 1, AUE_login) == -1) {
767 fprintf(stderr, "login: Audit Error: au_close() was not committed\n");
768 exit(1);
769 }
770}
771
1815bff5
A
772void
773getloginname()
774{
775 int ch;
776 char *p;
777 static char nbuf[NBUFSIZ];
778
779 for (;;) {
780 (void)printf("login: ");
781 for (p = nbuf; (ch = getchar()) != '\n'; ) {
782 if (ch == EOF) {
783 badlogin(username);
784 exit(0);
785 }
786 if (p < nbuf + (NBUFSIZ - 1))
787 *p++ = ch;
788 }
b51d5b5f 789 if (p > nbuf) {
1815bff5
A
790 if (nbuf[0] == '-')
791 (void)fprintf(stderr,
792 "login names may not start with '-'.\n");
793 else {
794 *p = '\0';
795 username = nbuf;
796 break;
797 }
b51d5b5f 798 }
1815bff5
A
799 }
800}
801
802int
803rootterm(ttyn)
804 char *ttyn;
805{
806 struct ttyent *t;
807
808 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
809}
810
811jmp_buf motdinterrupt;
812
813void
814motd()
815{
816 int fd, nchars;
817 sig_t oldint;
818 char tbuf[8192];
819
820 if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
821 return;
822 oldint = signal(SIGINT, sigint);
823 if (setjmp(motdinterrupt) == 0)
824 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
825 (void)write(fileno(stdout), tbuf, nchars);
826 (void)signal(SIGINT, oldint);
827 (void)close(fd);
828}
829
830/* ARGSUSED */
831void
832sigint(signo)
833 int signo;
834{
835
836 longjmp(motdinterrupt, 1);
837}
838
839/* ARGSUSED */
840void
841timedout(signo)
842 int signo;
843{
844
845 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
846 exit(0);
847}
848
849void
850checknologin()
851{
852 int fd, nchars;
853 char tbuf[8192];
854
855 if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
856 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
857 (void)write(fileno(stdout), tbuf, nchars);
2fc1e207 858 au_fail("No login", 0);
1815bff5
A
859 sleepexit(0);
860 }
861}
862
863void
864dolastlog(quiet)
865 int quiet;
866{
867 struct lastlog ll;
868 int fd;
869
c3a08f59
A
870 /* HACK HACK HACK: This is because HFS doesn't support sparse files
871 * and seeking into the file too far is too slow. The "solution"
872 * is to just bail if the seek time for a large uid would be too
873 * slow.
874 */
875 if(pwd->pw_uid > 100000) {
876 syslog(LOG_NOTICE, "User login %s (%d) not logged in lastlog. UID too large.", pwd->pw_name, pwd->pw_uid);
877 return;
878 }
879
1815bff5
A
880 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
881 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
882 if (!quiet) {
883 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
884 ll.ll_time != 0) {
885 (void)printf("Last login: %.*s ",
886 24-5, (char *)ctime(&ll.ll_time));
887 if (*ll.ll_host != '\0')
888 (void)printf("from %.*s\n",
889 (int)sizeof(ll.ll_host),
890 ll.ll_host);
891 else
892 (void)printf("on %.*s\n",
893 (int)sizeof(ll.ll_line),
894 ll.ll_line);
895 }
896 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
897 }
898 memset((void *)&ll, 0, sizeof(ll));
899 (void)time(&ll.ll_time);
900 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
901 if (hostname)
902 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
903 (void)write(fd, (char *)&ll, sizeof(ll));
904 (void)close(fd);
905 }
906}
907
908void
909badlogin(name)
910 char *name;
911{
912
913 if (failures == 0)
914 return;
915 if (hostname) {
916 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
917 failures, failures > 1 ? "S" : "", hostname);
918 syslog(LOG_AUTHPRIV|LOG_NOTICE,
919 "%d LOGIN FAILURE%s FROM %s, %s",
920 failures, failures > 1 ? "S" : "", hostname, name);
921 } else {
922 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
923 failures, failures > 1 ? "S" : "", tty);
924 syslog(LOG_AUTHPRIV|LOG_NOTICE,
925 "%d LOGIN FAILURE%s ON %s, %s",
926 failures, failures > 1 ? "S" : "", tty, name);
927 }
928}
929
930#undef UNKNOWN
931#define UNKNOWN "su"
932
933char *
934stypeof(ttyid)
935 char *ttyid;
936{
937 struct ttyent *t;
938
939 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
940}
941
942void
943sleepexit(eval)
944 int eval;
945{
946
947 (void)sleep(5);
948 exit(eval);
949}
2fc1e207
A
950
951static void
952refused(const char *msg, const char *rtype, int lout)
953{
954
955 if (msg != NULL)
956 printf("%s.\n", msg);
957 if (hflag)
958 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
959 pwd->pw_name, rtype, hostname, tty);
960 else
961 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
962 pwd->pw_name, rtype, tty);
963 if (lout)
964 bail(SLEEP_EXIT, 1);
965}
966
967#ifdef USE_PAM
968/*
969 * Log a PAM error
970 */
971static void
972pam_syslog(const char *msg)
973{
974 syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err));
975}
976
977/*
978 * Shut down PAM
979 */
980static void
981pam_cleanup()
982{
983
984 if (pamh != NULL) {
985 if (pam_session_established) {
986 pam_err = pam_close_session(pamh, 0);
987 if (pam_err != PAM_SUCCESS)
988 pam_syslog("pam_close_session()");
989 }
990 pam_session_established = 0;
991 if (pam_cred_established) {
992 pam_err = pam_setcred(pamh, pam_silent|PAM_DELETE_CRED);
993 if (pam_err != PAM_SUCCESS)
994 pam_syslog("pam_setcred()");
995 }
996 pam_cred_established = 0;
997 pam_end(pamh, pam_err);
998 pamh = NULL;
999 }
1000}
1001#endif /* USE_PAM */
1002/*
1003 * Exit, optionally after sleeping a few seconds
1004 */
1005void
1006bail(int sec, int eval)
1007{
1008
1009 pam_cleanup();
1010 (void)sleep(sec);
1011 exit(eval);
1012}