1 |
|
|
/* $OpenBSD: login.c,v 1.68 2016/08/21 03:26:04 beck Exp $ */ |
2 |
|
|
/* $NetBSD: login.c,v 1.13 1996/05/15 23:50:16 jtc Exp $ */ |
3 |
|
|
|
4 |
|
|
/*- |
5 |
|
|
* Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 |
6 |
|
|
* The Regents of the University of California. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
|
* modification, are permitted provided that the following conditions |
10 |
|
|
* are met: |
11 |
|
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
|
* documentation and/or other materials provided with the distribution. |
16 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
17 |
|
|
* may be used to endorse or promote products derived from this software |
18 |
|
|
* without specific prior written permission. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
21 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
24 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 |
|
|
* SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
/*- |
33 |
|
|
* Copyright (c) 1995 Berkeley Software Design, Inc. All rights reserved. |
34 |
|
|
* |
35 |
|
|
* Redistribution and use in source and binary forms, with or without |
36 |
|
|
* modification, are permitted provided that the following conditions |
37 |
|
|
* are met: |
38 |
|
|
* 1. Redistributions of source code must retain the above copyright |
39 |
|
|
* notice, this list of conditions and the following disclaimer. |
40 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
41 |
|
|
* notice, this list of conditions and the following disclaimer in the |
42 |
|
|
* documentation and/or other materials provided with the distribution. |
43 |
|
|
* 3. All advertising materials mentioning features or use of this software |
44 |
|
|
* must display the following acknowledgement: |
45 |
|
|
* This product includes software developed by Berkeley Software Design, |
46 |
|
|
* Inc. |
47 |
|
|
* 4. The name of Berkeley Software Design, Inc. may not be used to endorse |
48 |
|
|
* or promote products derived from this software without specific prior |
49 |
|
|
* written permission. |
50 |
|
|
* |
51 |
|
|
* THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND |
52 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
53 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
54 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE |
55 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
56 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
57 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
58 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
59 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
60 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
61 |
|
|
* SUCH DAMAGE. |
62 |
|
|
* |
63 |
|
|
* BSDI $From: login.c,v 2.28 1999/09/08 22:35:36 prb Exp $ |
64 |
|
|
*/ |
65 |
|
|
|
66 |
|
|
/* |
67 |
|
|
* login [ name ] |
68 |
|
|
* login -h hostname (for telnetd, etc.) |
69 |
|
|
* login -f name (for pre-authenticated login: datakit, xterm, etc.) |
70 |
|
|
* login -p (preserve existing environment; for getty) |
71 |
|
|
*/ |
72 |
|
|
|
73 |
|
|
#include <sys/socket.h> |
74 |
|
|
#include <sys/stat.h> |
75 |
|
|
#include <sys/time.h> |
76 |
|
|
#include <sys/resource.h> |
77 |
|
|
#include <sys/wait.h> |
78 |
|
|
|
79 |
|
|
#include <err.h> |
80 |
|
|
#include <errno.h> |
81 |
|
|
#include <fcntl.h> |
82 |
|
|
#include <grp.h> |
83 |
|
|
#include <login_cap.h> |
84 |
|
|
#include <netdb.h> |
85 |
|
|
#include <pwd.h> |
86 |
|
|
#include <signal.h> |
87 |
|
|
#include <stdarg.h> |
88 |
|
|
#include <stdio.h> |
89 |
|
|
#include <stdlib.h> |
90 |
|
|
#include <string.h> |
91 |
|
|
#include <syslog.h> |
92 |
|
|
#include <ttyent.h> |
93 |
|
|
#include <unistd.h> |
94 |
|
|
#include <limits.h> |
95 |
|
|
#include <utmp.h> |
96 |
|
|
#include <util.h> |
97 |
|
|
#include <bsd_auth.h> |
98 |
|
|
|
99 |
|
|
#include "pathnames.h" |
100 |
|
|
|
101 |
|
|
void badlogin(char *); |
102 |
|
|
void dolastlog(int); |
103 |
|
|
void getloginname(void); |
104 |
|
|
void motd(void); |
105 |
|
|
void quickexit(int); |
106 |
|
|
int rootterm(char *); |
107 |
|
|
void sigint(int); |
108 |
|
|
void sighup(int); |
109 |
|
|
void sleepexit(int); |
110 |
|
|
char *stypeof(char *); |
111 |
|
|
void timedout(int); |
112 |
|
|
int main(int, char **); |
113 |
|
|
|
114 |
|
|
extern int check_failedlogin(uid_t); |
115 |
|
|
extern void log_failedlogin(uid_t, char *, char *, char *); |
116 |
|
|
|
117 |
|
|
#define TTYGRPNAME "tty" /* name of group to own ttys */ |
118 |
|
|
|
119 |
|
|
#define SECSPERDAY (24 * 60 * 60) |
120 |
|
|
#define TWOWEEKS (2 * 7 * SECSPERDAY) |
121 |
|
|
|
122 |
|
|
/* |
123 |
|
|
* This bounds the time given to login; may be overridden by /etc/login.conf. |
124 |
|
|
*/ |
125 |
|
|
u_int timeout = 300; |
126 |
|
|
|
127 |
|
|
struct passwd *pwd; |
128 |
|
|
login_cap_t *lc = NULL; |
129 |
|
|
auth_session_t *as = NULL; |
130 |
|
|
int failures; |
131 |
|
|
int needbanner = 1; |
132 |
|
|
char term[64], *hostname, *tty; |
133 |
|
|
char *style; |
134 |
|
|
char *username = NULL, *rusername = NULL; |
135 |
|
|
|
136 |
|
|
extern char **environ; |
137 |
|
|
|
138 |
|
|
int |
139 |
|
|
main(int argc, char *argv[]) |
140 |
|
|
{ |
141 |
|
|
char *domain, *p, *ttyn, *shell, *fullname, *instance; |
142 |
|
|
char *lipaddr, *script, *ripaddr, *style, *type, *fqdn; |
143 |
|
|
char tbuf[PATH_MAX + 2], tname[sizeof(_PATH_TTY) + 10]; |
144 |
|
|
char localhost[HOST_NAME_MAX+1], *copyright; |
145 |
|
|
char mail[sizeof(_PATH_MAILDIR) + 1 + NAME_MAX]; |
146 |
|
|
int ask, ch, cnt, fflag, pflag, quietlog, rootlogin, lastchance; |
147 |
|
|
int error, homeless, needto, authok, tries, backoff; |
148 |
|
|
struct addrinfo *ai, hints; |
149 |
|
|
struct rlimit cds, scds; |
150 |
|
|
quad_t expire, warning; |
151 |
|
|
struct utmp utmp; |
152 |
|
|
struct group *gr; |
153 |
|
|
struct stat st; |
154 |
|
|
uid_t uid; |
155 |
|
|
|
156 |
|
|
openlog("login", LOG_ODELAY, LOG_AUTH); |
157 |
|
|
|
158 |
|
|
fqdn = lipaddr = ripaddr = fullname = type = NULL; |
159 |
|
|
authok = 0; |
160 |
|
|
tries = 10; |
161 |
|
|
backoff = 3; |
162 |
|
|
|
163 |
|
|
domain = NULL; |
164 |
|
|
if (gethostname(localhost, sizeof(localhost)) < 0) { |
165 |
|
|
syslog(LOG_ERR, "couldn't get local hostname: %m"); |
166 |
|
|
strlcpy(localhost, "localhost", sizeof(localhost)); |
167 |
|
|
} else if ((domain = strchr(localhost, '.'))) { |
168 |
|
|
domain++; |
169 |
|
|
if (*domain && strchr(domain, '.') == NULL) |
170 |
|
|
domain = localhost; |
171 |
|
|
} |
172 |
|
|
|
173 |
|
|
if ((as = auth_open()) == NULL) { |
174 |
|
|
syslog(LOG_ERR, "auth_open: %m"); |
175 |
|
|
err(1, "unable to initialize BSD authentication"); |
176 |
|
|
} |
177 |
|
|
auth_setoption(as, "login", "yes"); |
178 |
|
|
|
179 |
|
|
/* |
180 |
|
|
* -p is used by getty to tell login not to destroy the environment |
181 |
|
|
* -f is used to skip a second login authentication |
182 |
|
|
* -h is used by other servers to pass the name of the remote |
183 |
|
|
* host to login so that it may be placed in utmp and wtmp |
184 |
|
|
*/ |
185 |
|
|
fflag = pflag = 0; |
186 |
|
|
uid = getuid(); |
187 |
|
|
while ((ch = getopt(argc, argv, "fh:pu:L:R:")) != -1) |
188 |
|
|
switch (ch) { |
189 |
|
|
case 'f': |
190 |
|
|
fflag = 1; |
191 |
|
|
break; |
192 |
|
|
case 'h': |
193 |
|
|
if (uid) { |
194 |
|
|
warnc(EPERM, "-h option"); |
195 |
|
|
quickexit(1); |
196 |
|
|
} |
197 |
|
|
free(fqdn); |
198 |
|
|
if ((fqdn = strdup(optarg)) == NULL) { |
199 |
|
|
warn(NULL); |
200 |
|
|
quickexit(1); |
201 |
|
|
} |
202 |
|
|
auth_setoption(as, "fqdn", fqdn); |
203 |
|
|
if (domain && (p = strchr(optarg, '.')) && |
204 |
|
|
strcasecmp(p+1, domain) == 0) |
205 |
|
|
*p = 0; |
206 |
|
|
hostname = optarg; |
207 |
|
|
auth_setoption(as, "hostname", hostname); |
208 |
|
|
break; |
209 |
|
|
case 'L': |
210 |
|
|
if (uid) { |
211 |
|
|
warnc(EPERM, "-L option"); |
212 |
|
|
quickexit(1); |
213 |
|
|
} |
214 |
|
|
if (lipaddr) { |
215 |
|
|
warnx("duplicate -L option"); |
216 |
|
|
quickexit(1); |
217 |
|
|
} |
218 |
|
|
lipaddr = optarg; |
219 |
|
|
memset(&hints, 0, sizeof(hints)); |
220 |
|
|
hints.ai_family = PF_UNSPEC; |
221 |
|
|
hints.ai_flags = AI_CANONNAME; |
222 |
|
|
error = getaddrinfo(lipaddr, NULL, &hints, &ai); |
223 |
|
|
if (!error) { |
224 |
|
|
strlcpy(localhost, ai->ai_canonname, |
225 |
|
|
sizeof(localhost)); |
226 |
|
|
freeaddrinfo(ai); |
227 |
|
|
} else |
228 |
|
|
strlcpy(localhost, lipaddr, sizeof(localhost)); |
229 |
|
|
auth_setoption(as, "local_addr", lipaddr); |
230 |
|
|
break; |
231 |
|
|
case 'p': |
232 |
|
|
pflag = 1; |
233 |
|
|
break; |
234 |
|
|
case 'R': |
235 |
|
|
if (uid) { |
236 |
|
|
warnc(EPERM, "-R option"); |
237 |
|
|
quickexit(1); |
238 |
|
|
} |
239 |
|
|
if (ripaddr) { |
240 |
|
|
warnx("duplicate -R option"); |
241 |
|
|
quickexit(1); |
242 |
|
|
} |
243 |
|
|
ripaddr = optarg; |
244 |
|
|
auth_setoption(as, "remote_addr", ripaddr); |
245 |
|
|
break; |
246 |
|
|
case 'u': |
247 |
|
|
if (uid) { |
248 |
|
|
warnc(EPERM, "-u option"); |
249 |
|
|
quickexit(1); |
250 |
|
|
} |
251 |
|
|
rusername = optarg; |
252 |
|
|
break; |
253 |
|
|
default: |
254 |
|
|
if (!uid) |
255 |
|
|
syslog(LOG_ERR, "invalid flag %c", ch); |
256 |
|
|
(void)fprintf(stderr, |
257 |
|
|
"usage: login [-fp] [-h hostname] [-L local-addr] " |
258 |
|
|
"[-R remote-addr] [-u username]\n\t[user]\n"); |
259 |
|
|
quickexit(1); |
260 |
|
|
} |
261 |
|
|
argc -= optind; |
262 |
|
|
argv += optind; |
263 |
|
|
|
264 |
|
|
if (*argv) { |
265 |
|
|
username = *argv; |
266 |
|
|
ask = 0; |
267 |
|
|
} else |
268 |
|
|
ask = 1; |
269 |
|
|
|
270 |
|
|
/* |
271 |
|
|
* If effective user is not root, just run su(1) to emulate login(1). |
272 |
|
|
*/ |
273 |
|
|
if (geteuid() != 0) { |
274 |
|
|
char *av[5], **ap; |
275 |
|
|
|
276 |
|
|
auth_close(as); |
277 |
|
|
closelog(); |
278 |
|
|
closefrom(STDERR_FILENO + 1); |
279 |
|
|
|
280 |
|
|
ap = av; |
281 |
|
|
*ap++ = _PATH_SU; |
282 |
|
|
*ap++ = "-L"; |
283 |
|
|
if (!pflag) |
284 |
|
|
*ap++ = "-l"; |
285 |
|
|
if (!ask) |
286 |
|
|
*ap++ = username; |
287 |
|
|
*ap = NULL; |
288 |
|
|
execv(_PATH_SU, av); |
289 |
|
|
warn("unable to exec %s", _PATH_SU); |
290 |
|
|
_exit(1); |
291 |
|
|
} |
292 |
|
|
|
293 |
|
|
ttyn = ttyname(STDIN_FILENO); |
294 |
|
|
if (ttyn == NULL || *ttyn == '\0') { |
295 |
|
|
(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); |
296 |
|
|
ttyn = tname; |
297 |
|
|
} |
298 |
|
|
if ((tty = strrchr(ttyn, '/'))) |
299 |
|
|
++tty; |
300 |
|
|
else |
301 |
|
|
tty = ttyn; |
302 |
|
|
|
303 |
|
|
/* |
304 |
|
|
* Since login deals with sensitive information, turn off coredumps. |
305 |
|
|
*/ |
306 |
|
|
if (getrlimit(RLIMIT_CORE, &scds) < 0) { |
307 |
|
|
syslog(LOG_ERR, "couldn't get core dump size: %m"); |
308 |
|
|
scds.rlim_cur = scds.rlim_max = QUAD_MIN; |
309 |
|
|
} |
310 |
|
|
cds.rlim_cur = cds.rlim_max = 0; |
311 |
|
|
if (setrlimit(RLIMIT_CORE, &cds) < 0) { |
312 |
|
|
syslog(LOG_ERR, "couldn't set core dump size to 0: %m"); |
313 |
|
|
scds.rlim_cur = scds.rlim_max = QUAD_MIN; |
314 |
|
|
} |
315 |
|
|
|
316 |
|
|
(void)signal(SIGALRM, timedout); |
317 |
|
|
if (argc > 1) { |
318 |
|
|
needto = 0; |
319 |
|
|
(void)alarm(timeout); |
320 |
|
|
} else |
321 |
|
|
needto = 1; |
322 |
|
|
(void)signal(SIGQUIT, SIG_IGN); |
323 |
|
|
(void)signal(SIGINT, SIG_IGN); |
324 |
|
|
(void)signal(SIGHUP, SIG_IGN); |
325 |
|
|
(void)setpriority(PRIO_PROCESS, 0, 0); |
326 |
|
|
|
327 |
|
|
/* get the default login class */ |
328 |
|
|
if ((lc = login_getclass(0)) == NULL) { /* get the default class */ |
329 |
|
|
warnx("Failure to retrieve default class"); |
330 |
|
|
quickexit(1); |
331 |
|
|
} |
332 |
|
|
timeout = (u_int)login_getcapnum(lc, "login-timeout", 300, 300); |
333 |
|
|
if ((script = login_getcapstr(lc, "classify", NULL, NULL)) != NULL) { |
334 |
|
|
unsetenv("AUTH_TYPE"); |
335 |
|
|
unsetenv("REMOTE_NAME"); |
336 |
|
|
if (script[0] != '/') { |
337 |
|
|
syslog(LOG_ERR, "Invalid classify script: %s", script); |
338 |
|
|
warnx("Classification failure"); |
339 |
|
|
quickexit(1); |
340 |
|
|
} |
341 |
|
|
shell = strrchr(script, '/') + 1; |
342 |
|
|
auth_setstate(as, AUTH_OKAY); |
343 |
|
|
auth_call(as, script, shell, |
344 |
|
|
fflag ? "-f" : username, fflag ? username : 0, (char *)0); |
345 |
|
|
if (!(auth_getstate(as) & AUTH_ALLOW)) |
346 |
|
|
quickexit(1); |
347 |
|
|
auth_setenv(as); |
348 |
|
|
if ((p = getenv("AUTH_TYPE")) != NULL && |
349 |
|
|
strncmp(p, "auth-", 5) == 0) |
350 |
|
|
type = p; |
351 |
|
|
if ((p = getenv("REMOTE_NAME")) != NULL) |
352 |
|
|
hostname = p; |
353 |
|
|
/* |
354 |
|
|
* we may have changed some values, reset them |
355 |
|
|
*/ |
356 |
|
|
auth_clroptions(as); |
357 |
|
|
if (type) |
358 |
|
|
auth_setoption(as, "auth_type", type); |
359 |
|
|
if (fqdn) |
360 |
|
|
auth_setoption(as, "fqdn", fqdn); |
361 |
|
|
if (hostname) |
362 |
|
|
auth_setoption(as, "hostname", hostname); |
363 |
|
|
if (lipaddr) |
364 |
|
|
auth_setoption(as, "local_addr", lipaddr); |
365 |
|
|
if (ripaddr) |
366 |
|
|
auth_setoption(as, "remote_addr", ripaddr); |
367 |
|
|
} |
368 |
|
|
|
369 |
|
|
/* |
370 |
|
|
* Request the things like the approval script print things |
371 |
|
|
* to stdout (in particular, the nologins files) |
372 |
|
|
*/ |
373 |
|
|
auth_setitem(as, AUTHV_INTERACTIVE, "True"); |
374 |
|
|
|
375 |
|
|
for (cnt = 0;; ask = 1) { |
376 |
|
|
/* |
377 |
|
|
* Clean up our current authentication session. |
378 |
|
|
* Options are not cleared so we need to clear any |
379 |
|
|
* we might set below. |
380 |
|
|
*/ |
381 |
|
|
auth_clean(as); |
382 |
|
|
auth_clroption(as, "style"); |
383 |
|
|
auth_clroption(as, "lastchance"); |
384 |
|
|
|
385 |
|
|
lastchance = 0; |
386 |
|
|
|
387 |
|
|
if (ask) { |
388 |
|
|
fflag = 0; |
389 |
|
|
getloginname(); |
390 |
|
|
} |
391 |
|
|
if (needto) { |
392 |
|
|
needto = 0; |
393 |
|
|
alarm(timeout); |
394 |
|
|
} |
395 |
|
|
if ((style = strchr(username, ':')) != NULL) |
396 |
|
|
*style++ = '\0'; |
397 |
|
|
free(fullname); |
398 |
|
|
if (auth_setitem(as, AUTHV_NAME, username) < 0 || |
399 |
|
|
(fullname = strdup(username)) == NULL) { |
400 |
|
|
syslog(LOG_ERR, "%m"); |
401 |
|
|
warn(NULL); |
402 |
|
|
quickexit(1); |
403 |
|
|
} |
404 |
|
|
rootlogin = 0; |
405 |
|
|
if ((instance = strchr(username, '/')) != NULL) { |
406 |
|
|
if (strncmp(instance + 1, "root", 4) == 0) |
407 |
|
|
rootlogin = 1; |
408 |
|
|
*instance++ = '\0'; |
409 |
|
|
} else |
410 |
|
|
instance = ""; |
411 |
|
|
|
412 |
|
|
if (strlen(username) > UT_NAMESIZE) |
413 |
|
|
username[UT_NAMESIZE] = '\0'; |
414 |
|
|
|
415 |
|
|
/* |
416 |
|
|
* Note if trying multiple user names; log failures for |
417 |
|
|
* previous user name, but don't bother logging one failure |
418 |
|
|
* for nonexistent name (mistyped username). |
419 |
|
|
*/ |
420 |
|
|
if (failures && strcmp(tbuf, username)) { |
421 |
|
|
if (failures > (pwd ? 0 : 1)) |
422 |
|
|
badlogin(tbuf); |
423 |
|
|
failures = 0; |
424 |
|
|
} |
425 |
|
|
(void)strlcpy(tbuf, username, sizeof(tbuf)); |
426 |
|
|
|
427 |
|
|
if ((pwd = getpwnam(username)) != NULL && |
428 |
|
|
auth_setpwd(as, pwd) < 0) { |
429 |
|
|
syslog(LOG_ERR, "%m"); |
430 |
|
|
warn(NULL); |
431 |
|
|
quickexit(1); |
432 |
|
|
} |
433 |
|
|
|
434 |
|
|
lc = login_getclass(pwd ? pwd->pw_class : NULL); |
435 |
|
|
if (!lc) |
436 |
|
|
goto failed; |
437 |
|
|
|
438 |
|
|
style = login_getstyle(lc, style, type); |
439 |
|
|
if (!style) |
440 |
|
|
goto failed; |
441 |
|
|
|
442 |
|
|
/* |
443 |
|
|
* We allow "login-tries" attempts to login but start |
444 |
|
|
* slowing down after "login-backoff" attempts. |
445 |
|
|
*/ |
446 |
|
|
tries = (int)login_getcapnum(lc, "login-tries", 10, 10); |
447 |
|
|
backoff = (int)login_getcapnum(lc, "login-backoff", 3, 3); |
448 |
|
|
|
449 |
|
|
/* |
450 |
|
|
* Turn off the fflag if we have an invalid user |
451 |
|
|
* or we are not root and we are trying to change uids. |
452 |
|
|
*/ |
453 |
|
|
if (!pwd || (uid && uid != pwd->pw_uid)) |
454 |
|
|
fflag = 0; |
455 |
|
|
|
456 |
|
|
if (pwd && pwd->pw_uid == 0) |
457 |
|
|
rootlogin = 1; |
458 |
|
|
|
459 |
|
|
/* |
460 |
|
|
* If we do not have the force flag authenticate the user |
461 |
|
|
*/ |
462 |
|
|
if (!fflag) { |
463 |
|
|
lastchance = |
464 |
|
|
login_getcaptime(lc, "password-dead", 0, 0) != 0; |
465 |
|
|
if (lastchance) |
466 |
|
|
auth_setoption(as, "lastchance", "yes"); |
467 |
|
|
/* |
468 |
|
|
* Once we start asking for a password |
469 |
|
|
* we want to log a failure on a hup. |
470 |
|
|
*/ |
471 |
|
|
signal(SIGHUP, sighup); |
472 |
|
|
auth_verify(as, style, NULL, lc->lc_class, NULL); |
473 |
|
|
authok = auth_getstate(as); |
474 |
|
|
/* |
475 |
|
|
* If their password expired and it has not been |
476 |
|
|
* too long since then, give the user one last |
477 |
|
|
* chance to change their password |
478 |
|
|
*/ |
479 |
|
|
if ((authok & AUTH_PWEXPIRED) && lastchance) { |
480 |
|
|
authok = AUTH_OKAY; |
481 |
|
|
} else |
482 |
|
|
lastchance = 0; |
483 |
|
|
if ((authok & AUTH_ALLOW) == 0) |
484 |
|
|
goto failed; |
485 |
|
|
if (auth_setoption(as, "style", style) < 0) { |
486 |
|
|
syslog(LOG_ERR, "%m"); |
487 |
|
|
warn(NULL); |
488 |
|
|
quickexit(1); |
489 |
|
|
} |
490 |
|
|
} |
491 |
|
|
/* |
492 |
|
|
* explicitly reject users without password file entries |
493 |
|
|
*/ |
494 |
|
|
if (pwd == NULL) |
495 |
|
|
goto failed; |
496 |
|
|
|
497 |
|
|
/* |
498 |
|
|
* If trying to log in as root on an insecure terminal, |
499 |
|
|
* refuse the login attempt unless the authentication |
500 |
|
|
* style explicitly says a root login is okay. |
501 |
|
|
*/ |
502 |
|
|
if (pwd && rootlogin && !rootterm(tty)) |
503 |
|
|
goto failed; |
504 |
|
|
|
505 |
|
|
if (fflag) { |
506 |
|
|
type = 0; |
507 |
|
|
style = "forced"; |
508 |
|
|
} |
509 |
|
|
break; |
510 |
|
|
|
511 |
|
|
failed: |
512 |
|
|
if (authok & AUTH_SILENT) |
513 |
|
|
quickexit(0); |
514 |
|
|
if (rootlogin && !rootterm(tty)) { |
515 |
|
|
warnx("%s login refused on this terminal.", |
516 |
|
|
fullname); |
517 |
|
|
if (hostname) |
518 |
|
|
syslog(LOG_NOTICE, |
519 |
|
|
"LOGIN %s REFUSED FROM %s%s%s ON TTY %s", |
520 |
|
|
fullname, rusername ? rusername : "", |
521 |
|
|
rusername ? "@" : "", hostname, tty); |
522 |
|
|
else |
523 |
|
|
syslog(LOG_NOTICE, |
524 |
|
|
"LOGIN %s REFUSED ON TTY %s", |
525 |
|
|
fullname, tty); |
526 |
|
|
} else { |
527 |
|
|
if (!as || (p = auth_getvalue(as, "errormsg")) == NULL) |
528 |
|
|
p = "Login incorrect"; |
529 |
|
|
(void)printf("%s\n", p); |
530 |
|
|
} |
531 |
|
|
failures++; |
532 |
|
|
if (pwd) |
533 |
|
|
log_failedlogin(pwd->pw_uid, hostname, rusername, tty); |
534 |
|
|
/* |
535 |
|
|
* By default, we allow 10 tries, but after 3 we start |
536 |
|
|
* backing off to slow down password guessers. |
537 |
|
|
*/ |
538 |
|
|
if (++cnt > backoff) { |
539 |
|
|
if (cnt >= tries) { |
540 |
|
|
badlogin(username); |
541 |
|
|
sleepexit(1); |
542 |
|
|
} |
543 |
|
|
sleep(1); |
544 |
|
|
} |
545 |
|
|
} |
546 |
|
|
|
547 |
|
|
/* committed to login -- turn off timeout */ |
548 |
|
|
(void)alarm(0); |
549 |
|
|
|
550 |
|
|
endpwent(); |
551 |
|
|
|
552 |
|
|
shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell); |
553 |
|
|
if (*shell == '\0') |
554 |
|
|
shell = _PATH_BSHELL; |
555 |
|
|
else if (strlen(shell) >= PATH_MAX) { |
556 |
|
|
syslog(LOG_ERR, "shell path too long: %s", shell); |
557 |
|
|
warnx("invalid shell"); |
558 |
|
|
quickexit(1); |
559 |
|
|
} |
560 |
|
|
|
561 |
|
|
/* Destroy environment unless user has requested its preservation. */ |
562 |
|
|
if (!pflag) { |
563 |
|
|
if ((environ = calloc(1, sizeof (char *))) == NULL) |
564 |
|
|
err(1, "calloc"); |
565 |
|
|
} else { |
566 |
|
|
char **cpp, **cpp2; |
567 |
|
|
|
568 |
|
|
for (cpp2 = cpp = environ; *cpp; cpp++) { |
569 |
|
|
if (strncmp(*cpp, "LD_", 3) && |
570 |
|
|
strncmp(*cpp, "ENV=", 4) && |
571 |
|
|
strncmp(*cpp, "BASH_ENV=", 9) && |
572 |
|
|
strncmp(*cpp, "IFS=", 4)) |
573 |
|
|
*cpp2++ = *cpp; |
574 |
|
|
} |
575 |
|
|
*cpp2 = 0; |
576 |
|
|
} |
577 |
|
|
/* Note: setusercontext(3) will set PATH */ |
578 |
|
|
if (setenv("HOME", pwd->pw_dir, 1) == -1 || |
579 |
|
|
setenv("SHELL", pwd->pw_shell, 1) == -1) { |
580 |
|
|
warn("unable to setenv()"); |
581 |
|
|
quickexit(1); |
582 |
|
|
} |
583 |
|
|
if (term[0] == '\0') |
584 |
|
|
(void)strlcpy(term, stypeof(tty), sizeof(term)); |
585 |
|
|
(void)snprintf(mail, sizeof(mail), "%s/%s", _PATH_MAILDIR, |
586 |
|
|
pwd->pw_name); |
587 |
|
|
if (setenv("TERM", term, 0) == -1 || |
588 |
|
|
setenv("LOGNAME", pwd->pw_name, 1) == -1 || |
589 |
|
|
setenv("USER", pwd->pw_name, 1) == -1 || |
590 |
|
|
setenv("MAIL", mail, 1) == -1) { |
591 |
|
|
warn("unable to setenv()"); |
592 |
|
|
quickexit(1); |
593 |
|
|
} |
594 |
|
|
if (hostname) { |
595 |
|
|
if (setenv("REMOTEHOST", hostname, 1) == -1) { |
596 |
|
|
warn("unable to setenv()"); |
597 |
|
|
quickexit(1); |
598 |
|
|
} |
599 |
|
|
} |
600 |
|
|
if (rusername) { |
601 |
|
|
if (setenv("REMOTEUSER", rusername, 1) == -1) { |
602 |
|
|
warn("unable to setenv()"); |
603 |
|
|
quickexit(1); |
604 |
|
|
} |
605 |
|
|
} |
606 |
|
|
|
607 |
|
|
if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH)) { |
608 |
|
|
warn("unable to set user context"); |
609 |
|
|
quickexit(1); |
610 |
|
|
} |
611 |
|
|
auth_setenv(as); |
612 |
|
|
|
613 |
|
|
/* if user not super-user, check for disabled logins */ |
614 |
|
|
if (!rootlogin) |
615 |
|
|
auth_checknologin(lc); |
616 |
|
|
|
617 |
|
|
setegid(pwd->pw_gid); |
618 |
|
|
seteuid(pwd->pw_uid); |
619 |
|
|
|
620 |
|
|
homeless = chdir(pwd->pw_dir); |
621 |
|
|
if (homeless) { |
622 |
|
|
if (login_getcapbool(lc, "requirehome", 0)) { |
623 |
|
|
(void)printf("No home directory %s!\n", pwd->pw_dir); |
624 |
|
|
quickexit(1); |
625 |
|
|
} |
626 |
|
|
if (chdir("/")) |
627 |
|
|
quickexit(0); |
628 |
|
|
} |
629 |
|
|
|
630 |
|
|
quietlog = ((strcmp(pwd->pw_shell, "/sbin/nologin") == 0) || |
631 |
|
|
login_getcapbool(lc, "hushlogin", 0) || |
632 |
|
|
(access(_PATH_HUSHLOGIN, F_OK) == 0)); |
633 |
|
|
|
634 |
|
|
seteuid(0); |
635 |
|
|
setegid(0); /* XXX use a saved gid instead? */ |
636 |
|
|
|
637 |
|
|
if ((p = auth_getvalue(as, "warnmsg")) != NULL) |
638 |
|
|
(void)printf("WARNING: %s\n\n", p); |
639 |
|
|
|
640 |
|
|
expire = auth_check_expire(as); |
641 |
|
|
if (expire < 0) { |
642 |
|
|
(void)printf("Sorry -- your account has expired.\n"); |
643 |
|
|
quickexit(1); |
644 |
|
|
} else if (expire > 0 && !quietlog) { |
645 |
|
|
warning = login_getcaptime(lc, "expire-warn", |
646 |
|
|
TWOWEEKS, TWOWEEKS); |
647 |
|
|
if (expire < warning) |
648 |
|
|
(void)printf("Warning: your account expires on %s", |
649 |
|
|
ctime(&pwd->pw_expire)); |
650 |
|
|
} |
651 |
|
|
|
652 |
|
|
/* Nothing else left to fail -- really log in. */ |
653 |
|
|
(void)signal(SIGHUP, SIG_DFL); |
654 |
|
|
memset(&utmp, 0, sizeof(utmp)); |
655 |
|
|
(void)time(&utmp.ut_time); |
656 |
|
|
(void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); |
657 |
|
|
if (hostname) |
658 |
|
|
(void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); |
659 |
|
|
(void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); |
660 |
|
|
login(&utmp); |
661 |
|
|
|
662 |
|
|
if (!quietlog) |
663 |
|
|
(void)check_failedlogin(pwd->pw_uid); |
664 |
|
|
dolastlog(quietlog); |
665 |
|
|
|
666 |
|
|
login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); |
667 |
|
|
|
668 |
|
|
(void)chown(ttyn, pwd->pw_uid, |
669 |
|
|
(gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); |
670 |
|
|
|
671 |
|
|
/* If fflag is on, assume caller/authenticator has logged root login. */ |
672 |
|
|
if (rootlogin && fflag == 0) { |
673 |
|
|
if (hostname) |
674 |
|
|
syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s%s%s", |
675 |
|
|
username, tty, rusername ? rusername : "", |
676 |
|
|
rusername ? "@" : "", hostname); |
677 |
|
|
else |
678 |
|
|
syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty); |
679 |
|
|
} |
680 |
|
|
|
681 |
|
|
if (!quietlog) { |
682 |
|
|
if ((copyright = |
683 |
|
|
login_getcapstr(lc, "copyright", NULL, NULL)) != NULL) |
684 |
|
|
auth_cat(copyright); |
685 |
|
|
motd(); |
686 |
|
|
if (stat(mail, &st) == 0 && st.st_size != 0) |
687 |
|
|
(void)printf("You have %smail.\n", |
688 |
|
|
(st.st_mtime > st.st_atime) ? "new " : ""); |
689 |
|
|
} |
690 |
|
|
|
691 |
|
|
(void)signal(SIGALRM, SIG_DFL); |
692 |
|
|
(void)signal(SIGQUIT, SIG_DFL); |
693 |
|
|
(void)signal(SIGHUP, SIG_DFL); |
694 |
|
|
(void)signal(SIGINT, SIG_DFL); |
695 |
|
|
(void)signal(SIGTSTP, SIG_IGN); |
696 |
|
|
|
697 |
|
|
tbuf[0] = '-'; |
698 |
|
|
(void)strlcpy(tbuf + 1, (p = strrchr(shell, '/')) ? |
699 |
|
|
p + 1 : shell, sizeof(tbuf) - 1); |
700 |
|
|
|
701 |
|
|
if ((scds.rlim_cur != QUAD_MIN || scds.rlim_max != QUAD_MIN) && |
702 |
|
|
setrlimit(RLIMIT_CORE, &scds) < 0) |
703 |
|
|
syslog(LOG_ERR, "couldn't reset core dump size: %m"); |
704 |
|
|
|
705 |
|
|
if (lastchance) |
706 |
|
|
(void)printf("WARNING: Your password has expired." |
707 |
|
|
" You must change your password, now!\n"); |
708 |
|
|
|
709 |
|
|
if (setusercontext(lc, pwd, rootlogin ? 0 : pwd->pw_uid, |
710 |
|
|
LOGIN_SETALL & ~LOGIN_SETPATH) < 0) { |
711 |
|
|
warn("unable to set user context"); |
712 |
|
|
quickexit(1); |
713 |
|
|
} |
714 |
|
|
|
715 |
|
|
if (homeless) { |
716 |
|
|
(void)printf("No home directory %s!\n", pwd->pw_dir); |
717 |
|
|
(void)printf("Logging in with home = \"/\".\n"); |
718 |
|
|
(void)setenv("HOME", "/", 1); |
719 |
|
|
} |
720 |
|
|
|
721 |
|
|
if (auth_approval(as, lc, NULL, "login") == 0) { |
722 |
|
|
if (auth_getstate(as) & AUTH_EXPIRED) |
723 |
|
|
(void)printf("Sorry -- your account has expired.\n"); |
724 |
|
|
else |
725 |
|
|
(void)printf("approval failure\n"); |
726 |
|
|
quickexit(1); |
727 |
|
|
} |
728 |
|
|
|
729 |
|
|
/* |
730 |
|
|
* The last thing we do is discard all of the open file descriptors. |
731 |
|
|
* Last because the C library may have some open. |
732 |
|
|
*/ |
733 |
|
|
closefrom(STDERR_FILENO + 1); |
734 |
|
|
|
735 |
|
|
/* |
736 |
|
|
* Close the authentication session, make sure it is marked |
737 |
|
|
* as okay so no files are removed. |
738 |
|
|
*/ |
739 |
|
|
auth_setstate(as, AUTH_OKAY); |
740 |
|
|
auth_close(as); |
741 |
|
|
|
742 |
|
|
execlp(shell, tbuf, (char *)NULL); |
743 |
|
|
err(1, "%s", shell); |
744 |
|
|
} |
745 |
|
|
|
746 |
|
|
/* |
747 |
|
|
* Allow for a '.' and 16 characters for any instance as well as |
748 |
|
|
* space for a ':' and 16 characters defining the authentication type. |
749 |
|
|
*/ |
750 |
|
|
#define NBUFSIZ (UT_NAMESIZE + 1 + 16 + 1 + 16) |
751 |
|
|
|
752 |
|
|
void |
753 |
|
|
getloginname(void) |
754 |
|
|
{ |
755 |
|
|
static char nbuf[NBUFSIZ], *p; |
756 |
|
|
int ch; |
757 |
|
|
|
758 |
|
|
for (;;) { |
759 |
|
|
(void)printf("login: "); |
760 |
|
|
for (p = nbuf; (ch = getchar()) != '\n'; ) { |
761 |
|
|
if (ch == EOF) { |
762 |
|
|
badlogin(username); |
763 |
|
|
quickexit(0); |
764 |
|
|
} |
765 |
|
|
if (p < nbuf + (NBUFSIZ - 1)) |
766 |
|
|
*p++ = ch; |
767 |
|
|
} |
768 |
|
|
if (p > nbuf) { |
769 |
|
|
if (nbuf[0] == '-') |
770 |
|
|
(void)fprintf(stderr, |
771 |
|
|
"login names may not start with '-'.\n"); |
772 |
|
|
else { |
773 |
|
|
*p = '\0'; |
774 |
|
|
username = nbuf; |
775 |
|
|
break; |
776 |
|
|
} |
777 |
|
|
} |
778 |
|
|
} |
779 |
|
|
} |
780 |
|
|
|
781 |
|
|
int |
782 |
|
|
rootterm(char *ttyn) |
783 |
|
|
{ |
784 |
|
|
struct ttyent *t; |
785 |
|
|
|
786 |
|
|
/* XXX - stash output of getttynam() elsewhere */ |
787 |
|
|
return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); |
788 |
|
|
} |
789 |
|
|
|
790 |
|
|
void |
791 |
|
|
motd(void) |
792 |
|
|
{ |
793 |
|
|
char tbuf[8192], *motd; |
794 |
|
|
int fd, nchars; |
795 |
|
|
struct sigaction sa, osa; |
796 |
|
|
|
797 |
|
|
motd = login_getcapstr(lc, "welcome", _PATH_MOTDFILE, _PATH_MOTDFILE); |
798 |
|
|
|
799 |
|
|
if ((fd = open(motd, O_RDONLY, 0)) < 0) |
800 |
|
|
return; |
801 |
|
|
|
802 |
|
|
memset(&sa, 0, sizeof(sa)); |
803 |
|
|
sa.sa_handler = sigint; |
804 |
|
|
sigemptyset(&sa.sa_mask); |
805 |
|
|
sa.sa_flags = 0; /* don't set SA_RESTART */ |
806 |
|
|
(void)sigaction(SIGINT, &sa, &osa); |
807 |
|
|
|
808 |
|
|
/* read and spew motd until EOF, error, or SIGINT */ |
809 |
|
|
while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0 && |
810 |
|
|
write(STDOUT_FILENO, tbuf, nchars) == nchars) |
811 |
|
|
; |
812 |
|
|
|
813 |
|
|
(void)sigaction(SIGINT, &osa, NULL); |
814 |
|
|
(void)close(fd); |
815 |
|
|
} |
816 |
|
|
|
817 |
|
|
/* ARGSUSED */ |
818 |
|
|
void |
819 |
|
|
sigint(int signo) |
820 |
|
|
{ |
821 |
|
|
return; /* just interrupt syscall */ |
822 |
|
|
} |
823 |
|
|
|
824 |
|
|
/* ARGSUSED */ |
825 |
|
|
void |
826 |
|
|
timedout(int signo) |
827 |
|
|
{ |
828 |
|
|
char warn[1024]; |
829 |
|
|
|
830 |
|
|
snprintf(warn, sizeof warn, |
831 |
|
|
"Login timed out after %d seconds\n", timeout); |
832 |
|
|
write(STDERR_FILENO, warn, strlen(warn)); |
833 |
|
|
if (username) |
834 |
|
|
badlogin(username); |
835 |
|
|
_exit(0); |
836 |
|
|
} |
837 |
|
|
|
838 |
|
|
void |
839 |
|
|
dolastlog(int quiet) |
840 |
|
|
{ |
841 |
|
|
struct lastlog ll; |
842 |
|
|
off_t pos; |
843 |
|
|
int fd; |
844 |
|
|
|
845 |
|
|
if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { |
846 |
|
|
pos = (off_t)pwd->pw_uid * sizeof(ll); |
847 |
|
|
if (!quiet) { |
848 |
|
|
if (pread(fd, &ll, sizeof(ll), pos) == sizeof(ll) && |
849 |
|
|
ll.ll_time != 0) { |
850 |
|
|
(void)printf("Last login: %.*s ", |
851 |
|
|
24-5, (char *)ctime(&ll.ll_time)); |
852 |
|
|
(void)printf("on %.*s", |
853 |
|
|
(int)sizeof(ll.ll_line), |
854 |
|
|
ll.ll_line); |
855 |
|
|
if (*ll.ll_host != '\0') |
856 |
|
|
(void)printf(" from %.*s", |
857 |
|
|
(int)sizeof(ll.ll_host), |
858 |
|
|
ll.ll_host); |
859 |
|
|
(void)putchar('\n'); |
860 |
|
|
} |
861 |
|
|
} |
862 |
|
|
memset(&ll, 0, sizeof(ll)); |
863 |
|
|
(void)time(&ll.ll_time); |
864 |
|
|
(void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); |
865 |
|
|
if (hostname) |
866 |
|
|
(void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); |
867 |
|
|
(void)pwrite(fd, &ll, sizeof(ll), pos); |
868 |
|
|
(void)close(fd); |
869 |
|
|
} |
870 |
|
|
} |
871 |
|
|
|
872 |
|
|
void |
873 |
|
|
badlogin(char *name) |
874 |
|
|
{ |
875 |
|
|
struct syslog_data sdata = SYSLOG_DATA_INIT; |
876 |
|
|
|
877 |
|
|
if (failures == 0) |
878 |
|
|
return; |
879 |
|
|
if (hostname) { |
880 |
|
|
syslog_r(LOG_NOTICE, &sdata, |
881 |
|
|
"%d LOGIN FAILURE%s FROM %s%s%s", |
882 |
|
|
failures, failures > 1 ? "S" : "", |
883 |
|
|
rusername ? rusername : "", rusername ? "@" : "", hostname); |
884 |
|
|
syslog_r(LOG_AUTHPRIV|LOG_NOTICE, &sdata, |
885 |
|
|
"%d LOGIN FAILURE%s FROM %s%s%s, %s", |
886 |
|
|
failures, failures > 1 ? "S" : "", |
887 |
|
|
rusername ? rusername : "", rusername ? "@" : "", |
888 |
|
|
hostname, name); |
889 |
|
|
} else { |
890 |
|
|
syslog_r(LOG_NOTICE, &sdata, |
891 |
|
|
"%d LOGIN FAILURE%s ON %s", |
892 |
|
|
failures, failures > 1 ? "S" : "", tty); |
893 |
|
|
syslog_r(LOG_AUTHPRIV|LOG_NOTICE, &sdata, |
894 |
|
|
"%d LOGIN FAILURE%s ON %s, %s", |
895 |
|
|
failures, failures > 1 ? "S" : "", tty, name); |
896 |
|
|
} |
897 |
|
|
} |
898 |
|
|
|
899 |
|
|
#undef UNKNOWN |
900 |
|
|
#define UNKNOWN "su" |
901 |
|
|
|
902 |
|
|
char * |
903 |
|
|
stypeof(char *ttyid) |
904 |
|
|
{ |
905 |
|
|
struct ttyent *t; |
906 |
|
|
|
907 |
|
|
return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : |
908 |
|
|
login_getcapstr(lc, "term", UNKNOWN, UNKNOWN)); |
909 |
|
|
} |
910 |
|
|
|
911 |
|
|
void |
912 |
|
|
sleepexit(int eval) |
913 |
|
|
{ |
914 |
|
|
auth_close(as); |
915 |
|
|
(void)sleep(5); |
916 |
|
|
exit(eval); |
917 |
|
|
} |
918 |
|
|
|
919 |
|
|
void |
920 |
|
|
quickexit(int eval) |
921 |
|
|
{ |
922 |
|
|
if (as) |
923 |
|
|
auth_close(as); |
924 |
|
|
exit(eval); |
925 |
|
|
} |
926 |
|
|
|
927 |
|
|
|
928 |
|
|
void |
929 |
|
|
sighup(int signum) |
930 |
|
|
{ |
931 |
|
|
if (username) |
932 |
|
|
badlogin(username); |
933 |
|
|
_exit(0); |
934 |
|
|
} |