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