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