]> git.saurik.com Git - apple/system_cmds.git/blob - login.tproj/login.c
system_cmds-279.6.1.tar.gz
[apple/system_cmds.git] / login.tproj / login.c
1 /*
2 * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
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,
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."
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
57 #ifndef lint
58 static char copyright[] =
59 "@(#) Copyright (c) Apple Computer, Inc. 1997\n\n";
60 #endif /* not lint */
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>
73 #include <sys/wait.h>
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
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
99 #ifdef USE_PAM
100 #include <pam/pam_appl.h>
101 #include <pam/pam_misc.h>
102 #endif
103
104 #include "pathnames.h"
105
106 void badlogin __P((char *));
107 void checknologin __P((void));
108 void dolastlog __P((int));
109 void getloginname __P((void));
110 void motd __P((void));
111 int rootterm __P((char *));
112 void sigint __P((int));
113 void sleepexit __P((int));
114 char *stypeof __P((char *));
115 void timedout __P((int));
116 #ifdef KERBEROS
117 int klogin __P((struct passwd *, char *, char *, char *));
118 #endif
119 void au_success();
120 void au_fail(char *, int);
121
122
123 extern void login __P((struct utmp *));
124
125 #define TTYGRPNAME "tty" /* name of group to own ttys */
126
127 /*
128 * This bounds the time given to login. Not a define so it can
129 * be patched on machines where it's too small.
130 */
131 u_int timeout = 300;
132
133 #ifdef KERBEROS
134 int notickets = 1;
135 char *instance;
136 char *krbtkfile_env;
137 int authok;
138 #endif
139
140 struct passwd *pwd;
141 int failures;
142 char term[64], *hostname, *username = NULL, *tty;
143
144 #define NA_EVENT_STR_SIZE 25
145 au_tid_t tid;
146
147 int
148 main(argc, argv)
149 int argc;
150 char *argv[];
151 {
152 extern char **environ;
153 struct group *gr;
154 struct stat st;
155 struct timeval tp;
156 struct utmp utmp;
157 int ask, ch, cnt, oflag = 0, fflag, hflag, pflag, quietlog, rootlogin = 0, rval;
158 uid_t uid;
159 uid_t euid;
160 gid_t egid;
161 char *domain, *p, *salt, *ttyn;
162 char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
163 char localhost[MAXHOSTNAMELEN];
164 #ifdef USE_PAM
165 pam_handle_t *pamh = NULL;
166 struct pam_conv conv = { misc_conv, NULL };
167 char **pmenv;
168 pid_t pid;
169 #endif
170
171 char auditsuccess = 1;
172
173 (void)signal(SIGALRM, timedout);
174 (void)alarm(timeout);
175 (void)signal(SIGQUIT, SIG_IGN);
176 (void)signal(SIGINT, SIG_IGN);
177 (void)setpriority(PRIO_PROCESS, 0, 0);
178
179 openlog("login", LOG_ODELAY, LOG_AUTH);
180
181
182 /*
183 * -p is used by getty to tell login not to destroy the environment
184 * -f is used to skip a second login authentication
185 * -h is used by other servers to pass the name of the remote
186 * host to login so that it may be placed in utmp and wtmp
187 */
188 domain = NULL;
189 if (gethostname(localhost, sizeof(localhost)) < 0)
190 syslog(LOG_ERR, "couldn't get local hostname: %m");
191 else
192 domain = strchr(localhost, '.');
193
194 euid = geteuid();
195 egid = getegid();
196
197 fflag = hflag = pflag = 0;
198 uid = getuid();
199 while ((ch = getopt(argc, argv, "1fh:p")) != EOF)
200 switch (ch) {
201 case '1':
202 oflag = 1;
203 break;
204 case 'f':
205 fflag = 1;
206 break;
207 case 'h':
208 if (uid)
209 errx(1, "-h option: %s", strerror(EPERM));
210 hflag = 1;
211 if (domain && (p = strchr(optarg, '.')) &&
212 strcasecmp(p, domain) == 0)
213 *p = 0;
214 hostname = optarg;
215 break;
216 case 'p':
217 pflag = 1;
218 break;
219 case '?':
220 default:
221 if (!uid)
222 syslog(LOG_ERR, "invalid flag %c", ch);
223 (void)fprintf(stderr,
224 "usage: login [-fp] [-h hostname] [username]\n");
225 exit(1);
226 }
227 argc -= optind;
228 argv += optind;
229
230 if (*argv) {
231 username = *argv;
232 ask = 0;
233 } else
234 ask = 1;
235
236 for (cnt = getdtablesize(); cnt > 2; cnt--)
237 (void)close(cnt);
238
239 ttyn = ttyname(STDIN_FILENO);
240 if (ttyn == NULL || *ttyn == '\0') {
241 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
242 ttyn = tname;
243 }
244 if (tty = strrchr(ttyn, '/'))
245 ++tty;
246 else
247 tty = ttyn;
248
249 /* Set the terminal id */
250 audit_set_terminal_id(&tid);
251 if (fstat(STDIN_FILENO, &st) < 0) {
252 fprintf(stderr, "login: Unable to stat terminal\n");
253 au_fail("Unable to stat terminal", 1);
254 exit(-1);
255 }
256 if (S_ISCHR(st.st_mode)) {
257 tid.port = st.st_rdev;
258 } else {
259 tid.port = 0;
260 }
261
262 #ifdef USE_PAM
263 rval = pam_start("login", username, &conv, &pamh);
264 if( rval != PAM_SUCCESS ) {
265 fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, rval));
266 au_fail("PAM Error", 1);
267 exit(1);
268 }
269 rval = pam_set_item(pamh, PAM_TTY, tty);
270 if( rval != PAM_SUCCESS ) {
271 fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, rval));
272 au_fail("PAM Error", 1);
273 exit(1);
274 }
275
276 rval = pam_set_item(pamh, PAM_RHOST, hostname);
277 if( rval != PAM_SUCCESS ) {
278 fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, rval));
279 au_fail("PAM Error", 1);
280 exit(1);
281 }
282
283 rval = pam_set_item(pamh, PAM_USER_PROMPT, "login: ");
284 if( rval != PAM_SUCCESS ) {
285 fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, rval));
286 au_fail("PAM Error", 1);
287 exit(1);
288 }
289
290 if( !username )
291 getloginname();
292 pam_set_item(pamh, PAM_USER, username);
293 pwd = getpwnam(username);
294 if( (pwd != NULL) && (pwd->pw_uid == 0) )
295 rootlogin = 1;
296
297 if( (pwd != NULL) && fflag && ((uid == 0) || (uid == pwd->pw_uid)) ){
298 rval = 0;
299 auditsuccess = 0; /* we've simply opened a terminal window */
300 } else {
301
302 rval = pam_authenticate(pamh, 0);
303 while( (!oflag) && (cnt++ < 10) && ((rval == PAM_AUTH_ERR) ||
304 (rval == PAM_USER_UNKNOWN) ||
305 (rval == PAM_CRED_INSUFFICIENT) ||
306 (rval == PAM_AUTHINFO_UNAVAIL))) {
307 /*
308 * we are not exiting here, but this corresponds to
309 * a failed login event, so set exitstatus to 1
310 */
311 au_fail("Login incorrect", 1);
312 badlogin(username);
313 printf("Login incorrect\n");
314 rootlogin = 0;
315 getloginname();
316 pwd = getpwnam(username);
317 if( (pwd != NULL) && (pwd->pw_uid == 0) )
318 rootlogin = 1;
319 pam_set_item(pamh, PAM_USER, username);
320 rval = pam_authenticate(pamh, 0);
321 }
322
323 if( rval != PAM_SUCCESS ) {
324 pam_get_item(pamh, PAM_USER, (void *)&username);
325 badlogin(username);
326 printf("Login incorrect\n");
327 au_fail("Login incorrect", 1);
328 exit(1);
329 }
330
331 rval = pam_acct_mgmt(pamh, 0);
332 if( rval == PAM_NEW_AUTHTOK_REQD ) {
333 rval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
334 }
335 if( rval != PAM_SUCCESS ) {
336 fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, rval));
337 au_fail("PAM error", 1);
338 exit(1);
339 }
340
341 }
342
343 rval = pam_get_item(pamh, PAM_USER, (void *)&username);
344 if( (rval == PAM_SUCCESS) && username && *username)
345 pwd = getpwnam(username);
346
347 rval = pam_open_session(pamh, 0);
348 if( rval != PAM_SUCCESS ) {
349 fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, rval));
350 au_fail("PAM error", 1);
351 exit(1);
352 }
353
354 rval = pam_setcred(pamh, PAM_ESTABLISH_CRED);
355 if( rval != PAM_SUCCESS ) {
356 fprintf(stderr, "login: PAM Error: %s\n", pam_strerror(pamh, rval));
357 au_fail("PAM error", 1);
358 exit(1);
359 }
360
361 #else /* USE_PAM */
362 for (cnt = 0;; ask = 1) {
363 if (ask) {
364 fflag = 0;
365 getloginname();
366 }
367 rootlogin = 0;
368 #ifdef KERBEROS
369 if ((instance = strchr(username, '.')) != NULL) {
370 if (strncmp(instance, ".root", 5) == 0)
371 rootlogin = 1;
372 *instance++ = '\0';
373 } else
374 instance = "";
375 #endif
376 if (strlen(username) > UT_NAMESIZE)
377 username[UT_NAMESIZE] = '\0';
378
379 /*
380 * Note if trying multiple user names; log failures for
381 * previous user name, but don't bother logging one failure
382 * for nonexistent name (mistyped username).
383 */
384 if (failures && strcmp(tbuf, username)) {
385 if (failures > (pwd ? 0 : 1)) {
386 badlogin(tbuf);
387 }
388 failures = 0;
389 }
390 (void)strcpy(tbuf, username);
391
392 if (pwd = getpwnam(username))
393 salt = pwd->pw_passwd;
394 else
395 salt = "xx";
396
397 /*
398 * if we have a valid account name, and it doesn't have a
399 * password, or the -f option was specified and the caller
400 * is root or the caller isn't changing their uid, don't
401 * authenticate.
402 */
403 if (pwd && (*pwd->pw_passwd == '\0' ||
404 fflag && (uid == 0 || uid == pwd->pw_uid)))
405 break;
406 fflag = 0;
407 if (pwd && pwd->pw_uid == 0)
408 rootlogin = 1;
409
410 (void)setpriority(PRIO_PROCESS, 0, -4);
411
412 p = getpass("Password:");
413
414 if (pwd) {
415 #ifdef KERBEROS
416 rval = klogin(pwd, instance, localhost, p);
417 if (rval != 0 && rootlogin && pwd->pw_uid != 0)
418 rootlogin = 0;
419 if (rval == 0)
420 authok = 1;
421 else if (rval == 1)
422 rval = strcmp(crypt(p, salt), pwd->pw_passwd);
423 #else
424 rval = strcmp(crypt(p, salt), pwd->pw_passwd);
425 #endif
426 }
427 memset(p, 0, strlen(p));
428
429 (void)setpriority(PRIO_PROCESS, 0, 0);
430
431 /*
432 * If trying to log in as root without Kerberos,
433 * but with insecure terminal, refuse the login attempt.
434 */
435 #ifdef KERBEROS
436 if (authok == 0)
437 #endif
438 if (pwd && rootlogin && !rootterm(tty)) {
439 (void)fprintf(stderr,
440 "%s login refused on this terminal.\n",
441 pwd->pw_name);
442 if (hostname)
443 syslog(LOG_NOTICE,
444 "LOGIN %s REFUSED FROM %s ON TTY %s",
445 pwd->pw_name, hostname, tty);
446 else
447 syslog(LOG_NOTICE,
448 "LOGIN %s REFUSED ON TTY %s",
449 pwd->pw_name, tty);
450 au_fail("Login refused on terminal", 0);
451 continue;
452 }
453
454 if (pwd && !rval)
455 break;
456
457 (void)printf("Login incorrect\n");
458 failures++;
459 /* we allow 10 tries, but after 3 we start backing off */
460 if (++cnt > 3) {
461 if (cnt >= 10) {
462 badlogin(username);
463 au_fail("Login incorrect", 1);
464 sleepexit(1);
465 }
466 au_fail("Login incorrect", 1);
467 sleep((u_int)((cnt - 3) * 5));
468 }
469 }
470 #endif
471
472 /* committed to login -- turn off timeout */
473 (void)alarm((u_int)0);
474
475 endpwent();
476
477 /* if user not super-user, check for disabled logins */
478 if (!rootlogin)
479 checknologin();
480
481 /* Audit successful login */
482 if (auditsuccess)
483 au_success();
484
485 setegid(pwd->pw_gid);
486 seteuid(rootlogin ? 0 : pwd->pw_uid);
487
488 /* First do a stat in case the homedir is automounted */
489 stat(pwd->pw_dir,&st);
490
491 if (chdir(pwd->pw_dir) < 0) {
492 (void)printf("No home directory %s!\n", pwd->pw_dir);
493 if (chdir("/")) {
494 exit(0);
495 }
496 pwd->pw_dir = "/";
497 (void)printf("Logging in with home = \"/\".\n");
498 }
499
500 seteuid(euid);
501 setegid(egid);
502
503 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
504
505 /* Nothing else left to fail -- really log in. */
506
507 memset((void *)&utmp, 0, sizeof(utmp));
508 (void)time(&utmp.ut_time);
509 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
510 if (hostname)
511 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
512 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
513 login(&utmp);
514
515 dolastlog(quietlog);
516
517 (void)chown(ttyn, pwd->pw_uid,
518 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
519 (void)chmod(ttyn, 0620);
520 (void)setgid(pwd->pw_gid);
521
522 initgroups(username, pwd->pw_gid);
523
524 if (*pwd->pw_shell == '\0')
525 pwd->pw_shell = _PATH_BSHELL;
526
527 /* Destroy environment unless user has requested its preservation. */
528 if (!pflag) {
529 environ = malloc(sizeof(char *));
530 *environ = NULL;
531 }
532 (void)setenv("HOME", pwd->pw_dir, 1);
533 (void)setenv("SHELL", pwd->pw_shell, 1);
534 if (term[0] == '\0')
535 (void)strncpy(term, stypeof(tty), sizeof(term));
536 (void)setenv("TERM", term, 0);
537 (void)setenv("LOGNAME", pwd->pw_name, 1);
538 (void)setenv("USER", pwd->pw_name, 1);
539 (void)setenv("PATH", _PATH_DEFPATH, 0);
540 #ifdef KERBEROS
541 if (krbtkfile_env)
542 (void)setenv("KRBTKFILE", krbtkfile_env, 1);
543 #endif
544
545 #ifdef USE_PAM
546 pmenv = pam_getenvlist(pamh);
547 for( cnt = 0; pmenv && pmenv[cnt]; cnt++ )
548 putenv(pmenv[cnt]);
549
550 pid = fork();
551 if ( pid < 0 ) {
552 err(1, "fork");
553 } else if( pid != 0 ) {
554 waitpid(pid, NULL, 0);
555 pam_setcred(pamh, PAM_DELETE_CRED);
556 rval = pam_close_session(pamh, 0);
557 pam_end(pamh,rval);
558 exit(0);
559 }
560
561 #endif
562
563 if (tty[sizeof("tty")-1] == 'd')
564 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
565
566 /* If fflag is on, assume caller/authenticator has logged root login. */
567 if (rootlogin && fflag == 0)
568 if (hostname)
569 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
570 username, tty, hostname);
571 else
572 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);
573
574 #ifdef KERBEROS
575 if (!quietlog && notickets == 1)
576 (void)printf("Warning: no Kerberos tickets issued.\n");
577 #endif
578
579 if (!quietlog) {
580 motd();
581 (void)snprintf(tbuf,
582 sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
583 if (stat(tbuf, &st) == 0 && st.st_size != 0)
584 (void)printf("You have %smail.\n",
585 (st.st_mtime > st.st_atime) ? "new " : "");
586 }
587
588 (void)signal(SIGALRM, SIG_DFL);
589 (void)signal(SIGQUIT, SIG_DFL);
590 (void)signal(SIGINT, SIG_DFL);
591 (void)signal(SIGTSTP, SIG_IGN);
592
593 tbuf[0] = '-';
594 (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
595 p + 1 : pwd->pw_shell);
596
597 if (setlogin(pwd->pw_name) < 0)
598 syslog(LOG_ERR, "setlogin() failure: %m");
599
600 /* Discard permissions last so can't get killed and drop core. */
601 if (rootlogin)
602 (void) setuid(0);
603 else
604 (void) setuid(pwd->pw_uid);
605
606
607 execlp(pwd->pw_shell, tbuf, 0);
608 err(1, "%s", pwd->pw_shell);
609 }
610
611 #ifdef KERBEROS
612 #define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
613 #else
614 #define NBUFSIZ (MAXLOGNAME + 1)
615 #endif
616
617 /*
618 * The following tokens are included in the audit record for successful login attempts
619 * header
620 * subject
621 * return
622 */
623 void au_success()
624 {
625 token_t *tok;
626 int aufd;
627 au_mask_t aumask;
628 auditinfo_t auinfo;
629 uid_t uid = pwd->pw_uid;
630 gid_t gid = pwd->pw_gid;
631 pid_t pid = getpid();
632 long au_cond;
633
634 /* If we are not auditing, don't cut an audit record; just return */
635 if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
636 fprintf(stderr, "login: Could not determine audit condition\n");
637 exit(1);
638 }
639 if (au_cond == AUC_NOAUDIT)
640 return;
641
642 /* Compute and Set the user's preselection mask */
643 if(au_user_mask(pwd->pw_name, &aumask) == -1) {
644 fprintf(stderr, "login: Could not set audit mask\n");
645 exit(1);
646 }
647
648 /* Set the audit info for the user */
649 auinfo.ai_auid = uid;
650 auinfo.ai_asid = pid;
651 bcopy(&tid, &auinfo.ai_termid, sizeof(auinfo.ai_termid));
652 bcopy(&aumask, &auinfo.ai_mask, sizeof(auinfo.ai_mask));
653 if(setaudit(&auinfo) != 0) {
654 fprintf(stderr, "login: setaudit failed: %s\n", strerror(errno));
655 exit(1);
656 }
657
658 if((aufd = au_open()) == -1) {
659 fprintf(stderr, "login: Audit Error: au_open() failed\n");
660 exit(1);
661 }
662
663 /* The subject that is created (euid, egid of the current process) */
664 if((tok = au_to_subject32(uid, geteuid(), getegid(),
665 uid, gid, pid, pid, &tid)) == NULL) {
666 fprintf(stderr, "login: Audit Error: au_to_subject32() failed\n");
667 exit(1);
668 }
669 au_write(aufd, tok);
670
671 if((tok = au_to_return32(0, 0)) == NULL) {
672 fprintf(stderr, "login: Audit Error: au_to_return32() failed\n");
673 exit(1);
674 }
675 au_write(aufd, tok);
676
677 if(au_close(aufd, 1, AUE_login) == -1) {
678 fprintf(stderr, "login: Audit Record was not committed.\n");
679 exit(1);
680 }
681 }
682
683 /*
684 * The following tokens are included in the audit record for successful login attempts
685 * header
686 * subject
687 * text
688 * return
689 */
690 void au_fail(char *errmsg, int na)
691 {
692 token_t *tok;
693 int aufd;
694 long au_cond;
695 uid_t uid;
696 gid_t gid;
697 pid_t pid = getpid();
698
699 /* If we are not auditing, don't cut an audit record; just return */
700 if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
701 fprintf(stderr, "login: Could not determine audit condition\n");
702 exit(1);
703 }
704 if (au_cond == AUC_NOAUDIT)
705 return;
706
707 if((aufd = au_open()) == -1) {
708 fprintf(stderr, "login: Audit Error: au_open() failed\n");
709 exit(1);
710 }
711
712 if(na) {
713 /* Non attributable event */
714 /* Assuming that login is not called within a users' session => auid,asid == -1 */
715 if((tok = au_to_subject32(-1, geteuid(), getegid(), -1, -1,
716 pid, -1, &tid)) == NULL) {
717
718 fprintf(stderr, "login: Audit Error: au_to_subject32() failed\n");
719 exit(1);
720 }
721 }
722 else {
723 /* we know the subject -- so use its value instead */
724 uid = pwd->pw_uid;
725 gid = pwd->pw_gid;
726 if((tok = au_to_subject32(uid, geteuid(), getegid(),
727 uid, gid, pid, pid, &tid)) == NULL) {
728 fprintf(stderr, "login: Audit Error: au_to_subject32() failed\n");
729 exit(1);
730 }
731 }
732 au_write(aufd, tok);
733
734 /* Include the error message */
735 if((tok = au_to_text(errmsg)) == NULL) {
736 fprintf(stderr, "login: Audit Error: au_to_text() failed\n");
737 exit(1);
738 }
739 au_write(aufd, tok);
740
741 if((tok = au_to_return32(1, errno)) == NULL) {
742 fprintf(stderr, "login: Audit Error: au_to_return32() failed\n");
743 exit(1);
744 }
745 au_write(aufd, tok);
746
747 if(au_close(aufd, 1, AUE_login) == -1) {
748 fprintf(stderr, "login: Audit Error: au_close() was not committed\n");
749 exit(1);
750 }
751 }
752
753 void
754 getloginname()
755 {
756 int ch;
757 char *p;
758 static char nbuf[NBUFSIZ];
759
760 for (;;) {
761 (void)printf("login: ");
762 for (p = nbuf; (ch = getchar()) != '\n'; ) {
763 if (ch == EOF) {
764 badlogin(username);
765 exit(0);
766 }
767 if (p < nbuf + (NBUFSIZ - 1))
768 *p++ = ch;
769 }
770 if (p > nbuf) {
771 if (nbuf[0] == '-')
772 (void)fprintf(stderr,
773 "login names may not start with '-'.\n");
774 else {
775 *p = '\0';
776 username = nbuf;
777 break;
778 }
779 }
780 }
781 }
782
783 int
784 rootterm(ttyn)
785 char *ttyn;
786 {
787 struct ttyent *t;
788
789 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
790 }
791
792 jmp_buf motdinterrupt;
793
794 void
795 motd()
796 {
797 int fd, nchars;
798 sig_t oldint;
799 char tbuf[8192];
800
801 if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
802 return;
803 oldint = signal(SIGINT, sigint);
804 if (setjmp(motdinterrupt) == 0)
805 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
806 (void)write(fileno(stdout), tbuf, nchars);
807 (void)signal(SIGINT, oldint);
808 (void)close(fd);
809 }
810
811 /* ARGSUSED */
812 void
813 sigint(signo)
814 int signo;
815 {
816
817 longjmp(motdinterrupt, 1);
818 }
819
820 /* ARGSUSED */
821 void
822 timedout(signo)
823 int signo;
824 {
825
826 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
827 exit(0);
828 }
829
830 void
831 checknologin()
832 {
833 int fd, nchars;
834 char tbuf[8192];
835
836 if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
837 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
838 (void)write(fileno(stdout), tbuf, nchars);
839
840 au_fail("No login", 0);
841 sleepexit(0);
842 }
843 }
844
845 void
846 dolastlog(quiet)
847 int quiet;
848 {
849 struct lastlog ll;
850 int fd;
851
852 /* HACK HACK HACK: This is because HFS doesn't support sparse files
853 * and seeking into the file too far is too slow. The "solution"
854 * is to just bail if the seek time for a large uid would be too
855 * slow.
856 */
857 if(pwd->pw_uid > 100000) {
858 syslog(LOG_NOTICE, "User login %s (%d) not logged in lastlog. UID too large.", pwd->pw_name, pwd->pw_uid);
859 return;
860 }
861
862 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
863 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
864 if (!quiet) {
865 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
866 ll.ll_time != 0) {
867 (void)printf("Last login: %.*s ",
868 24-5, (char *)ctime(&ll.ll_time));
869 if (*ll.ll_host != '\0')
870 (void)printf("from %.*s\n",
871 (int)sizeof(ll.ll_host),
872 ll.ll_host);
873 else
874 (void)printf("on %.*s\n",
875 (int)sizeof(ll.ll_line),
876 ll.ll_line);
877 }
878 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
879 }
880 memset((void *)&ll, 0, sizeof(ll));
881 (void)time(&ll.ll_time);
882 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
883 if (hostname)
884 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
885 (void)write(fd, (char *)&ll, sizeof(ll));
886 (void)close(fd);
887 }
888 }
889
890 void
891 badlogin(name)
892 char *name;
893 {
894
895 if (failures == 0)
896 return;
897 if (hostname) {
898 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
899 failures, failures > 1 ? "S" : "", hostname);
900 syslog(LOG_AUTHPRIV|LOG_NOTICE,
901 "%d LOGIN FAILURE%s FROM %s, %s",
902 failures, failures > 1 ? "S" : "", hostname, name);
903 } else {
904 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
905 failures, failures > 1 ? "S" : "", tty);
906 syslog(LOG_AUTHPRIV|LOG_NOTICE,
907 "%d LOGIN FAILURE%s ON %s, %s",
908 failures, failures > 1 ? "S" : "", tty, name);
909 }
910 }
911
912 #undef UNKNOWN
913 #define UNKNOWN "su"
914
915 char *
916 stypeof(ttyid)
917 char *ttyid;
918 {
919 struct ttyent *t;
920
921 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
922 }
923
924 void
925 sleepexit(eval)
926 int eval;
927 {
928
929 (void)sleep(5);
930 exit(eval);
931 }