1 1.105 aymeric /* $NetBSD: login.c,v 1.105 2014/11/12 22:23:38 aymeric Exp $ */ 2 1.12 jtc 3 1.1 cgd /*- 4 1.12 jtc * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 5 1.10 brezak * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.73 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.24 lukem #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.96 lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\ 35 1.96 lukem The Regents of the University of California. All rights reserved."); 36 1.1 cgd #endif /* not lint */ 37 1.1 cgd 38 1.1 cgd #ifndef lint 39 1.12 jtc #if 0 40 1.12 jtc static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; 41 1.12 jtc #endif 42 1.105 aymeric __RCSID("$NetBSD: login.c,v 1.105 2014/11/12 22:23:38 aymeric Exp $"); 43 1.1 cgd #endif /* not lint */ 44 1.1 cgd 45 1.1 cgd /* 46 1.1 cgd * login [ name ] 47 1.1 cgd * login -h hostname (for telnetd, etc.) 48 1.1 cgd * login -f name (for pre-authenticated login: datakit, xterm, etc.) 49 1.1 cgd */ 50 1.1 cgd 51 1.1 cgd #include <sys/param.h> 52 1.1 cgd #include <sys/stat.h> 53 1.1 cgd #include <sys/time.h> 54 1.1 cgd #include <sys/resource.h> 55 1.1 cgd #include <sys/file.h> 56 1.38 mrg #include <sys/wait.h> 57 1.67 christos #include <sys/socket.h> 58 1.1 cgd 59 1.12 jtc #include <err.h> 60 1.5 cgd #include <errno.h> 61 1.1 cgd #include <grp.h> 62 1.1 cgd #include <pwd.h> 63 1.12 jtc #include <setjmp.h> 64 1.12 jtc #include <signal.h> 65 1.19 veego #include <stdio.h> 66 1.5 cgd #include <stdlib.h> 67 1.1 cgd #include <string.h> 68 1.12 jtc #include <syslog.h> 69 1.36 kleink #include <time.h> 70 1.12 jtc #include <ttyent.h> 71 1.12 jtc #include <tzfile.h> 72 1.12 jtc #include <unistd.h> 73 1.95 christos #include <sysexits.h> 74 1.67 christos #ifdef SUPPORT_UTMP 75 1.12 jtc #include <utmp.h> 76 1.66 christos #endif 77 1.67 christos #ifdef SUPPORT_UTMPX 78 1.66 christos #include <utmpx.h> 79 1.66 christos #endif 80 1.13 jtc #include <util.h> 81 1.29 mycroft #ifdef SKEY 82 1.29 mycroft #include <skey.h> 83 1.29 mycroft #endif 84 1.25 mycroft #ifdef KERBEROS5 85 1.45 christos #include <krb5/krb5.h> 86 1.99 christos #include <krb5/com_err.h> 87 1.25 mycroft #endif 88 1.48 mjl #ifdef LOGIN_CAP 89 1.48 mjl #include <login_cap.h> 90 1.48 mjl #endif 91 1.79 christos #include <vis.h> 92 1.25 mycroft 93 1.1 cgd #include "pathnames.h" 94 1.97 christos #include "common.h" 95 1.1 cgd 96 1.57 aidan #ifdef KERBEROS5 97 1.57 aidan int login_krb5_forwardable_tgt = 0; 98 1.97 christos static int login_krb5_get_tickets = 1; 99 1.97 christos static int login_krb5_retain_ccache = 0; 100 1.57 aidan #endif 101 1.57 aidan 102 1.97 christos static void checknologin(char *); 103 1.44 aidan #ifdef KERBEROS5 104 1.81 xtraeme int k5login(struct passwd *, char *, char *, char *); 105 1.81 xtraeme void k5destroy(void); 106 1.99 christos int k5_read_creds(const char *); 107 1.81 xtraeme int k5_write_creds(void); 108 1.57 aidan #endif 109 1.89 wiz #if defined(KERBEROS5) 110 1.97 christos static void dofork(void); 111 1.44 aidan #endif 112 1.103 wiz static void usage(void) __attribute__((__noreturn__)); 113 1.12 jtc 114 1.1 cgd #define TTYGRPNAME "tty" /* name of group to own ttys */ 115 1.1 cgd 116 1.50 mjl #define DEFAULT_BACKOFF 3 117 1.50 mjl #define DEFAULT_RETRIES 10 118 1.48 mjl 119 1.89 wiz #if defined(KERBEROS5) 120 1.57 aidan int has_ccache = 0; 121 1.101 christos int notickets = 1; 122 1.25 mycroft extern krb5_context kcontext; 123 1.44 aidan extern int have_forward; 124 1.102 christos static char *instance; 125 1.57 aidan extern char *krb5tkfile_env; 126 1.60 thorpej extern int krb5_configured; 127 1.60 thorpej #endif 128 1.60 thorpej 129 1.89 wiz #if defined(KERBEROS5) 130 1.60 thorpej #define KERBEROS_CONFIGURED krb5_configured 131 1.25 mycroft #endif 132 1.1 cgd 133 1.97 christos extern char **environ; 134 1.34 thorpej 135 1.5 cgd int 136 1.80 xtraeme main(int argc, char *argv[]) 137 1.1 cgd { 138 1.5 cgd struct group *gr; 139 1.5 cgd struct stat st; 140 1.29 mycroft int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval; 141 1.33 hubertf uid_t uid, saved_uid; 142 1.35 hubertf gid_t saved_gid, saved_gids[NGROUPS_MAX]; 143 1.35 hubertf int nsaved_gids; 144 1.104 dholland #ifdef notdef 145 1.104 dholland char *domain; 146 1.104 dholland #endif 147 1.104 dholland char *p, *ttyn; 148 1.99 christos const char *pwprompt; 149 1.1 cgd char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; 150 1.37 mrg char localhost[MAXHOSTNAMELEN + 1]; 151 1.29 mycroft int need_chpass, require_chpass; 152 1.48 mjl int login_retries = DEFAULT_RETRIES, 153 1.48 mjl login_backoff = DEFAULT_BACKOFF; 154 1.48 mjl time_t pw_warntime = _PASSWORD_WARNDAYS * SECSPERDAY; 155 1.102 christos char *loginname = NULL; 156 1.25 mycroft #ifdef KERBEROS5 157 1.104 dholland int Fflag; 158 1.25 mycroft krb5_error_code kerror; 159 1.25 mycroft #endif 160 1.89 wiz #if defined(KERBEROS5) 161 1.57 aidan int got_tickets = 0; 162 1.57 aidan #endif 163 1.48 mjl #ifdef LOGIN_CAP 164 1.49 mjl char *shell = NULL; 165 1.48 mjl login_cap_t *lc = NULL; 166 1.48 mjl #endif 167 1.1 cgd 168 1.20 lukem tbuf[0] = '\0'; 169 1.20 lukem rval = 0; 170 1.20 lukem pwprompt = NULL; 171 1.70 itojun nested = NULL; 172 1.29 mycroft need_chpass = require_chpass = 0; 173 1.20 lukem 174 1.1 cgd (void)signal(SIGALRM, timedout); 175 1.12 jtc (void)alarm(timeout); 176 1.1 cgd (void)signal(SIGQUIT, SIG_IGN); 177 1.1 cgd (void)signal(SIGINT, SIG_IGN); 178 1.1 cgd (void)setpriority(PRIO_PROCESS, 0, 0); 179 1.1 cgd 180 1.63 lukem openlog("login", 0, LOG_AUTH); 181 1.1 cgd 182 1.1 cgd /* 183 1.1 cgd * -p is used by getty to tell login not to destroy the environment 184 1.5 cgd * -f is used to skip a second login authentication 185 1.66 christos * -h is used by other servers to pass the name of the remote host to 186 1.66 christos * login so that it may be placed in utmp/utmpx and wtmp/wtmpx 187 1.87 jnemeth * -a in addition to -h, a server may supply -a to pass the actual 188 1.79 christos * server address. 189 1.20 lukem * -s is used to force use of S/Key or equivalent. 190 1.1 cgd */ 191 1.104 dholland if (gethostname(localhost, sizeof(localhost)) < 0) { 192 1.1 cgd syslog(LOG_ERR, "couldn't get local hostname: %m"); 193 1.104 dholland strcpy(hostname, "amnesiac"); 194 1.104 dholland } 195 1.104 dholland #ifdef notdef 196 1.104 dholland domain = strchr(localhost, '.'); 197 1.104 dholland #endif 198 1.37 mrg localhost[sizeof(localhost) - 1] = '\0'; 199 1.1 cgd 200 1.104 dholland fflag = hflag = pflag = sflag = 0; 201 1.79 christos have_ss = 0; 202 1.44 aidan #ifdef KERBEROS5 203 1.104 dholland Fflag = 0; 204 1.44 aidan have_forward = 0; 205 1.44 aidan #endif 206 1.1 cgd uid = getuid(); 207 1.79 christos while ((ch = getopt(argc, argv, "a:Ffh:ps")) != -1) 208 1.1 cgd switch (ch) { 209 1.79 christos case 'a': 210 1.79 christos if (uid) 211 1.95 christos errx(EXIT_FAILURE, "-a option: %s", strerror(EPERM)); 212 1.79 christos decode_ss(optarg); 213 1.82 christos #ifdef notdef 214 1.82 christos (void)sockaddr_snprintf(optarg, 215 1.82 christos sizeof(struct sockaddr_storage), "%a", (void *)&ss); 216 1.82 christos #endif 217 1.79 christos break; 218 1.44 aidan case 'F': 219 1.104 dholland #ifdef KERBEROS5 220 1.44 aidan Fflag = 1; 221 1.104 dholland #endif 222 1.44 aidan /* FALLTHROUGH */ 223 1.1 cgd case 'f': 224 1.1 cgd fflag = 1; 225 1.1 cgd break; 226 1.1 cgd case 'h': 227 1.12 jtc if (uid) 228 1.95 christos errx(EXIT_FAILURE, "-h option: %s", strerror(EPERM)); 229 1.1 cgd hflag = 1; 230 1.79 christos #ifdef notdef 231 1.23 mikel if (domain && (p = strchr(optarg, '.')) != NULL && 232 1.1 cgd strcasecmp(p, domain) == 0) 233 1.79 christos *p = '\0'; 234 1.79 christos #endif 235 1.1 cgd hostname = optarg; 236 1.1 cgd break; 237 1.1 cgd case 'p': 238 1.1 cgd pflag = 1; 239 1.1 cgd break; 240 1.20 lukem case 's': 241 1.29 mycroft sflag = 1; 242 1.20 lukem break; 243 1.29 mycroft default: 244 1.1 cgd case '?': 245 1.79 christos usage(); 246 1.79 christos break; 247 1.1 cgd } 248 1.82 christos 249 1.82 christos setproctitle(NULL); 250 1.1 cgd argc -= optind; 251 1.1 cgd argv += optind; 252 1.5 cgd 253 1.1 cgd if (*argv) { 254 1.102 christos username = loginname = *argv; 255 1.1 cgd ask = 0; 256 1.1 cgd } else 257 1.1 cgd ask = 1; 258 1.1 cgd 259 1.82 christos #ifdef F_CLOSEM 260 1.82 christos (void)fcntl(3, F_CLOSEM, 0); 261 1.82 christos #else 262 1.1 cgd for (cnt = getdtablesize(); cnt > 2; cnt--) 263 1.5 cgd (void)close(cnt); 264 1.82 christos #endif 265 1.1 cgd 266 1.5 cgd ttyn = ttyname(STDIN_FILENO); 267 1.1 cgd if (ttyn == NULL || *ttyn == '\0') { 268 1.5 cgd (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); 269 1.1 cgd ttyn = tname; 270 1.1 cgd } 271 1.82 christos if ((tty = strstr(ttyn, "/pts/")) != NULL) 272 1.82 christos ++tty; 273 1.82 christos else if ((tty = strrchr(ttyn, '/')) != NULL) 274 1.1 cgd ++tty; 275 1.1 cgd else 276 1.1 cgd tty = ttyn; 277 1.25 mycroft 278 1.70 itojun if (issetugid()) { 279 1.70 itojun nested = strdup(user_from_uid(getuid(), 0)); 280 1.70 itojun if (nested == NULL) { 281 1.93 isaki syslog(LOG_ERR, "strdup: %m"); 282 1.95 christos sleepexit(EXIT_FAILURE); 283 1.70 itojun } 284 1.70 itojun } 285 1.70 itojun 286 1.48 mjl #ifdef LOGIN_CAP 287 1.48 mjl /* Get "login-retries" and "login-backoff" from default class */ 288 1.55 enami if ((lc = login_getclass(NULL)) != NULL) { 289 1.55 enami login_retries = (int)login_getcapnum(lc, "login-retries", 290 1.55 enami DEFAULT_RETRIES, DEFAULT_RETRIES); 291 1.55 enami login_backoff = (int)login_getcapnum(lc, "login-backoff", 292 1.55 enami DEFAULT_BACKOFF, DEFAULT_BACKOFF); 293 1.48 mjl login_close(lc); 294 1.48 mjl lc = NULL; 295 1.55 enami } 296 1.48 mjl #endif 297 1.48 mjl 298 1.25 mycroft #ifdef KERBEROS5 299 1.25 mycroft kerror = krb5_init_context(&kcontext); 300 1.25 mycroft if (kerror) { 301 1.61 thorpej /* 302 1.61 thorpej * If Kerberos is not configured, that is, we are 303 1.61 thorpej * not using Kerberos, do not log the error message. 304 1.61 thorpej * However, if Kerberos is configured, and the 305 1.61 thorpej * context init fails for some other reason, we need 306 1.61 thorpej * to issue a no tickets warning to the user when the 307 1.61 thorpej * login succeeds. 308 1.61 thorpej */ 309 1.61 thorpej if (kerror != ENXIO) { /* XXX NetBSD-local Heimdal hack */ 310 1.61 thorpej syslog(LOG_NOTICE, 311 1.61 thorpej "%s when initializing Kerberos context", 312 1.61 thorpej error_message(kerror)); 313 1.61 thorpej krb5_configured = 1; 314 1.61 thorpej } 315 1.57 aidan login_krb5_get_tickets = 0; 316 1.58 aidan } 317 1.64 cgd #endif /* KERBEROS5 */ 318 1.1 cgd 319 1.1 cgd for (cnt = 0;; ask = 1) { 320 1.57 aidan #if defined(KERBEROS5) 321 1.57 aidan if (login_krb5_get_tickets) 322 1.57 aidan k5destroy(); 323 1.57 aidan #endif 324 1.1 cgd if (ask) { 325 1.1 cgd fflag = 0; 326 1.102 christos loginname = getloginname(); 327 1.1 cgd } 328 1.5 cgd rootlogin = 0; 329 1.10 brezak #ifdef KERBEROS5 330 1.102 christos if ((instance = strchr(loginname, '/')) != NULL) 331 1.10 brezak *instance++ = '\0'; 332 1.29 mycroft else 333 1.99 christos instance = __UNCONST(""); 334 1.10 brezak #endif 335 1.102 christos username = trimloginname(loginname); 336 1.1 cgd /* 337 1.1 cgd * Note if trying multiple user names; log failures for 338 1.1 cgd * previous user name, but don't bother logging one failure 339 1.1 cgd * for nonexistent name (mistyped username). 340 1.1 cgd */ 341 1.1 cgd if (failures && strcmp(tbuf, username)) { 342 1.1 cgd if (failures > (pwd ? 0 : 1)) 343 1.1 cgd badlogin(tbuf); 344 1.1 cgd failures = 0; 345 1.1 cgd } 346 1.71 itojun (void)strlcpy(tbuf, username, sizeof(tbuf)); 347 1.1 cgd 348 1.90 hubertf pwd = getpwnam(username); 349 1.1 cgd 350 1.48 mjl #ifdef LOGIN_CAP 351 1.48 mjl /* 352 1.48 mjl * Establish the class now, before we might goto 353 1.48 mjl * within the next block. pwd can be NULL since it 354 1.52 mjl * falls back to the "default" class if it is. 355 1.52 mjl */ 356 1.52 mjl lc = login_getclass(pwd ? pwd->pw_class : NULL); 357 1.48 mjl #endif 358 1.1 cgd /* 359 1.1 cgd * if we have a valid account name, and it doesn't have a 360 1.1 cgd * password, or the -f option was specified and the caller 361 1.1 cgd * is root or the caller isn't changing their uid, don't 362 1.1 cgd * authenticate. 363 1.1 cgd */ 364 1.7 mycroft if (pwd) { 365 1.7 mycroft if (pwd->pw_uid == 0) 366 1.7 mycroft rootlogin = 1; 367 1.7 mycroft 368 1.8 mycroft if (fflag && (uid == 0 || uid == pwd->pw_uid)) { 369 1.7 mycroft /* already authenticated */ 370 1.44 aidan #ifdef KERBEROS5 371 1.57 aidan if (login_krb5_get_tickets && Fflag) 372 1.44 aidan k5_read_creds(username); 373 1.44 aidan #endif 374 1.7 mycroft break; 375 1.7 mycroft } else if (pwd->pw_passwd[0] == '\0') { 376 1.7 mycroft /* pretend password okay */ 377 1.7 mycroft rval = 0; 378 1.7 mycroft goto ttycheck; 379 1.7 mycroft } 380 1.7 mycroft } 381 1.7 mycroft 382 1.1 cgd fflag = 0; 383 1.1 cgd 384 1.1 cgd (void)setpriority(PRIO_PROCESS, 0, -4); 385 1.1 cgd 386 1.27 mycroft #ifdef SKEY 387 1.29 mycroft if (skey_haskey(username) == 0) { 388 1.29 mycroft static char skprompt[80]; 389 1.59 thorpej const char *skinfo = skey_keyinfo(username); 390 1.20 lukem 391 1.75 itojun (void)snprintf(skprompt, sizeof(skprompt), 392 1.83 tron "Password [ %s ]:", 393 1.29 mycroft skinfo ? skinfo : "error getting challenge"); 394 1.29 mycroft pwprompt = skprompt; 395 1.29 mycroft } else 396 1.27 mycroft #endif 397 1.29 mycroft pwprompt = "Password:"; 398 1.27 mycroft 399 1.29 mycroft p = getpass(pwprompt); 400 1.1 cgd 401 1.29 mycroft if (pwd == NULL) { 402 1.29 mycroft rval = 1; 403 1.29 mycroft goto skip; 404 1.29 mycroft } 405 1.29 mycroft #ifdef KERBEROS5 406 1.57 aidan if (login_krb5_get_tickets && 407 1.57 aidan k5login(pwd, instance, localhost, p) == 0) { 408 1.29 mycroft rval = 0; 409 1.57 aidan got_tickets = 1; 410 1.57 aidan } 411 1.57 aidan #endif 412 1.89 wiz #if defined(KERBEROS5) 413 1.57 aidan if (got_tickets) 414 1.29 mycroft goto skip; 415 1.29 mycroft #endif 416 1.20 lukem #ifdef SKEY 417 1.29 mycroft if (skey_haskey(username) == 0 && 418 1.29 mycroft skey_passcheck(username, p) != -1) { 419 1.29 mycroft rval = 0; 420 1.29 mycroft goto skip; 421 1.29 mycroft } 422 1.20 lukem #endif 423 1.29 mycroft if (!sflag && *pwd->pw_passwd != '\0' && 424 1.29 mycroft !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) { 425 1.29 mycroft rval = 0; 426 1.29 mycroft require_chpass = 1; 427 1.29 mycroft goto skip; 428 1.29 mycroft } 429 1.29 mycroft rval = 1; 430 1.29 mycroft 431 1.29 mycroft skip: 432 1.29 mycroft memset(p, 0, strlen(p)); 433 1.1 cgd 434 1.1 cgd (void)setpriority(PRIO_PROCESS, 0, 0); 435 1.1 cgd 436 1.7 mycroft ttycheck: 437 1.1 cgd /* 438 1.1 cgd * If trying to log in as root without Kerberos, 439 1.1 cgd * but with insecure terminal, refuse the login attempt. 440 1.1 cgd */ 441 1.7 mycroft if (pwd && !rval && rootlogin && !rootterm(tty)) { 442 1.87 jnemeth (void)printf("Login incorrect or refused on this " 443 1.87 jnemeth "terminal.\n"); 444 1.1 cgd if (hostname) 445 1.1 cgd syslog(LOG_NOTICE, 446 1.1 cgd "LOGIN %s REFUSED FROM %s ON TTY %s", 447 1.1 cgd pwd->pw_name, hostname, tty); 448 1.1 cgd else 449 1.1 cgd syslog(LOG_NOTICE, 450 1.1 cgd "LOGIN %s REFUSED ON TTY %s", 451 1.1 cgd pwd->pw_name, tty); 452 1.1 cgd continue; 453 1.1 cgd } 454 1.1 cgd 455 1.1 cgd if (pwd && !rval) 456 1.1 cgd break; 457 1.1 cgd 458 1.87 jnemeth (void)printf("Login incorrect or refused on this " 459 1.87 jnemeth "terminal.\n"); 460 1.1 cgd failures++; 461 1.48 mjl cnt++; 462 1.88 jnemeth /* 463 1.88 jnemeth * We allow login_retries tries, but after login_backoff 464 1.88 jnemeth * we start backing off. These default to 10 and 3 465 1.88 jnemeth * respectively. 466 1.88 jnemeth */ 467 1.50 mjl if (cnt > login_backoff) { 468 1.48 mjl if (cnt >= login_retries) { 469 1.1 cgd badlogin(username); 470 1.95 christos sleepexit(EXIT_FAILURE); 471 1.1 cgd } 472 1.88 jnemeth sleep((u_int)((cnt - login_backoff) * 5)); 473 1.1 cgd } 474 1.1 cgd } 475 1.1 cgd 476 1.1 cgd /* committed to login -- turn off timeout */ 477 1.1 cgd (void)alarm((u_int)0); 478 1.1 cgd 479 1.1 cgd endpwent(); 480 1.1 cgd 481 1.1 cgd /* if user not super-user, check for disabled logins */ 482 1.48 mjl #ifdef LOGIN_CAP 483 1.93 isaki if (!login_getcapbool(lc, "ignorenologin", rootlogin)) 484 1.52 mjl checknologin(login_getcapstr(lc, "nologin", NULL, NULL)); 485 1.48 mjl #else 486 1.93 isaki if (!rootlogin) 487 1.93 isaki checknologin(NULL); 488 1.48 mjl #endif 489 1.1 cgd 490 1.48 mjl #ifdef LOGIN_CAP 491 1.93 isaki quietlog = login_getcapbool(lc, "hushlogin", 0); 492 1.48 mjl #else 493 1.93 isaki quietlog = 0; 494 1.48 mjl #endif 495 1.33 hubertf /* Temporarily give up special privileges so we can change */ 496 1.33 hubertf /* into NFS-mounted homes that are exported for non-root */ 497 1.33 hubertf /* access and have mode 7x0 */ 498 1.33 hubertf saved_uid = geteuid(); 499 1.35 hubertf saved_gid = getegid(); 500 1.35 hubertf nsaved_gids = getgroups(NGROUPS_MAX, saved_gids); 501 1.35 hubertf 502 1.35 hubertf (void)setegid(pwd->pw_gid); 503 1.35 hubertf initgroups(username, pwd->pw_gid); 504 1.35 hubertf (void)seteuid(pwd->pw_uid); 505 1.33 hubertf 506 1.1 cgd if (chdir(pwd->pw_dir) < 0) { 507 1.48 mjl #ifdef LOGIN_CAP 508 1.93 isaki if (login_getcapbool(lc, "requirehome", 0)) { 509 1.55 enami (void)printf("Home directory %s required\n", 510 1.55 enami pwd->pw_dir); 511 1.95 christos sleepexit(EXIT_FAILURE); 512 1.48 mjl } 513 1.48 mjl #endif 514 1.1 cgd (void)printf("No home directory %s!\n", pwd->pw_dir); 515 1.95 christos if (chdir("/") == -1) 516 1.95 christos exit(EXIT_FAILURE); 517 1.99 christos pwd->pw_dir = __UNCONST("/"); 518 1.1 cgd (void)printf("Logging in with home = \"/\".\n"); 519 1.1 cgd } 520 1.1 cgd 521 1.55 enami if (!quietlog) 522 1.48 mjl quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 523 1.33 hubertf 524 1.33 hubertf /* regain special privileges */ 525 1.33 hubertf (void)seteuid(saved_uid); 526 1.35 hubertf setgroups(nsaved_gids, saved_gids); 527 1.35 hubertf (void)setegid(saved_gid); 528 1.1 cgd 529 1.48 mjl #ifdef LOGIN_CAP 530 1.93 isaki pw_warntime = login_getcaptime(lc, "password-warn", 531 1.93 isaki _PASSWORD_WARNDAYS * SECSPERDAY, 532 1.93 isaki _PASSWORD_WARNDAYS * SECSPERDAY); 533 1.48 mjl #endif 534 1.48 mjl 535 1.98 plunky (void)gettimeofday(&now, NULL); 536 1.40 ross if (pwd->pw_expire) { 537 1.66 christos if (now.tv_sec >= pwd->pw_expire) { 538 1.1 cgd (void)printf("Sorry -- your account has expired.\n"); 539 1.95 christos sleepexit(EXIT_FAILURE); 540 1.66 christos } else if (pwd->pw_expire - now.tv_sec < pw_warntime && 541 1.55 enami !quietlog) 542 1.1 cgd (void)printf("Warning: your account expires on %s", 543 1.1 cgd ctime(&pwd->pw_expire)); 544 1.40 ross } 545 1.40 ross if (pwd->pw_change) { 546 1.30 mycroft if (pwd->pw_change == _PASSWORD_CHGNOW) 547 1.30 mycroft need_chpass = 1; 548 1.66 christos else if (now.tv_sec >= pwd->pw_change) { 549 1.31 mycroft (void)printf("Sorry -- your password has expired.\n"); 550 1.95 christos sleepexit(EXIT_FAILURE); 551 1.66 christos } else if (pwd->pw_change - now.tv_sec < pw_warntime && 552 1.55 enami !quietlog) 553 1.30 mycroft (void)printf("Warning: your password expires on %s", 554 1.30 mycroft ctime(&pwd->pw_change)); 555 1.1 cgd 556 1.40 ross } 557 1.5 cgd /* Nothing else left to fail -- really log in. */ 558 1.97 christos update_db(quietlog, rootlogin, fflag); 559 1.1 cgd 560 1.1 cgd (void)chown(ttyn, pwd->pw_uid, 561 1.1 cgd (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 562 1.15 gwr 563 1.15 gwr if (ttyaction(ttyn, "login", pwd->pw_name)) 564 1.15 gwr (void)printf("Warning: ttyaction failed.\n"); 565 1.15 gwr 566 1.89 wiz #if defined(KERBEROS5) 567 1.10 brezak /* Fork so that we can call kdestroy */ 568 1.89 wiz if (! login_krb5_retain_ccache && has_ccache) 569 1.29 mycroft dofork(); 570 1.10 brezak #endif 571 1.53 mjl 572 1.53 mjl /* Destroy environment unless user has requested its preservation. */ 573 1.53 mjl if (!pflag) 574 1.53 mjl environ = envinit; 575 1.53 mjl 576 1.48 mjl #ifdef LOGIN_CAP 577 1.70 itojun if (nested == NULL && setusercontext(lc, pwd, pwd->pw_uid, 578 1.70 itojun LOGIN_SETLOGIN) != 0) { 579 1.70 itojun syslog(LOG_ERR, "setusercontext failed"); 580 1.95 christos exit(EXIT_FAILURE); 581 1.70 itojun } 582 1.70 itojun if (setusercontext(lc, pwd, pwd->pw_uid, 583 1.70 itojun (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETLOGIN))) != 0) { 584 1.52 mjl syslog(LOG_ERR, "setusercontext failed"); 585 1.95 christos exit(EXIT_FAILURE); 586 1.48 mjl } 587 1.52 mjl #else 588 1.1 cgd (void)setgid(pwd->pw_gid); 589 1.1 cgd 590 1.1 cgd initgroups(username, pwd->pw_gid); 591 1.48 mjl 592 1.70 itojun if (nested == NULL && setlogin(pwd->pw_name) < 0) 593 1.48 mjl syslog(LOG_ERR, "setlogin() failure: %m"); 594 1.48 mjl 595 1.48 mjl /* Discard permissions last so can't get killed and drop core. */ 596 1.48 mjl if (rootlogin) 597 1.48 mjl (void)setuid(0); 598 1.48 mjl else 599 1.48 mjl (void)setuid(pwd->pw_uid); 600 1.52 mjl #endif 601 1.1 cgd 602 1.1 cgd if (*pwd->pw_shell == '\0') 603 1.99 christos pwd->pw_shell = __UNCONST(_PATH_BSHELL); 604 1.48 mjl #ifdef LOGIN_CAP 605 1.55 enami if ((shell = login_getcapstr(lc, "shell", NULL, NULL)) != NULL) { 606 1.55 enami if ((shell = strdup(shell)) == NULL) { 607 1.93 isaki syslog(LOG_ERR, "Cannot alloc mem"); 608 1.95 christos sleepexit(EXIT_FAILURE); 609 1.48 mjl } 610 1.48 mjl pwd->pw_shell = shell; 611 1.48 mjl } 612 1.48 mjl #endif 613 1.48 mjl 614 1.1 cgd (void)setenv("HOME", pwd->pw_dir, 1); 615 1.1 cgd (void)setenv("SHELL", pwd->pw_shell, 1); 616 1.48 mjl if (term[0] == '\0') { 617 1.99 christos const char *tt = stypeof(tty); 618 1.48 mjl #ifdef LOGIN_CAP 619 1.55 enami if (tt == NULL) 620 1.48 mjl tt = login_getcapstr(lc, "term", NULL, NULL); 621 1.48 mjl #endif 622 1.48 mjl /* unknown term -> "su" */ 623 1.71 itojun (void)strlcpy(term, tt != NULL ? tt : "su", sizeof(term)); 624 1.55 enami } 625 1.1 cgd (void)setenv("TERM", term, 0); 626 1.1 cgd (void)setenv("LOGNAME", pwd->pw_name, 1); 627 1.1 cgd (void)setenv("USER", pwd->pw_name, 1); 628 1.51 mjl 629 1.48 mjl #ifdef LOGIN_CAP 630 1.52 mjl setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH); 631 1.48 mjl #else 632 1.1 cgd (void)setenv("PATH", _PATH_DEFPATH, 0); 633 1.48 mjl #endif 634 1.51 mjl 635 1.10 brezak #ifdef KERBEROS5 636 1.57 aidan if (krb5tkfile_env) 637 1.57 aidan (void)setenv("KRB5CCNAME", krb5tkfile_env, 1); 638 1.10 brezak #endif 639 1.1 cgd 640 1.5 cgd /* If fflag is on, assume caller/authenticator has logged root login. */ 641 1.40 ross if (rootlogin && fflag == 0) { 642 1.1 cgd if (hostname) 643 1.1 cgd syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 644 1.1 cgd username, tty, hostname); 645 1.1 cgd else 646 1.55 enami syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", 647 1.55 enami username, tty); 648 1.40 ross } 649 1.1 cgd 650 1.89 wiz #if defined(KERBEROS5) 651 1.60 thorpej if (KERBEROS_CONFIGURED && !quietlog && notickets == 1) 652 1.1 cgd (void)printf("Warning: no Kerberos tickets issued.\n"); 653 1.1 cgd #endif 654 1.1 cgd 655 1.1 cgd if (!quietlog) { 656 1.99 christos const char *fname; 657 1.48 mjl #ifdef LOGIN_CAP 658 1.48 mjl fname = login_getcapstr(lc, "copyright", NULL, NULL); 659 1.55 enami if (fname != NULL && access(fname, F_OK) == 0) 660 1.48 mjl motd(fname); 661 1.48 mjl else 662 1.55 enami #endif 663 1.69 itojun (void)printf("%s", copyrightstr); 664 1.48 mjl 665 1.48 mjl #ifdef LOGIN_CAP 666 1.93 isaki fname = login_getcapstr(lc, "welcome", NULL, NULL); 667 1.93 isaki if (fname == NULL || access(fname, F_OK) != 0) 668 1.48 mjl #endif 669 1.93 isaki fname = _PATH_MOTDFILE; 670 1.93 isaki motd(fname); 671 1.48 mjl 672 1.5 cgd (void)snprintf(tbuf, 673 1.5 cgd sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name); 674 1.1 cgd if (stat(tbuf, &st) == 0 && st.st_size != 0) 675 1.1 cgd (void)printf("You have %smail.\n", 676 1.1 cgd (st.st_mtime > st.st_atime) ? "new " : ""); 677 1.1 cgd } 678 1.1 cgd 679 1.48 mjl #ifdef LOGIN_CAP 680 1.48 mjl login_close(lc); 681 1.48 mjl #endif 682 1.48 mjl 683 1.1 cgd (void)signal(SIGALRM, SIG_DFL); 684 1.1 cgd (void)signal(SIGQUIT, SIG_DFL); 685 1.1 cgd (void)signal(SIGINT, SIG_DFL); 686 1.1 cgd (void)signal(SIGTSTP, SIG_IGN); 687 1.1 cgd 688 1.1 cgd tbuf[0] = '-'; 689 1.71 itojun (void)strlcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? 690 1.71 itojun p + 1 : pwd->pw_shell, sizeof(tbuf) - 1); 691 1.1 cgd 692 1.24 lukem /* Wait to change password until we're unprivileged */ 693 1.24 lukem if (need_chpass) { 694 1.29 mycroft if (!require_chpass) 695 1.24 lukem (void)printf( 696 1.24 lukem "Warning: your password has expired. Please change it as soon as possible.\n"); 697 1.29 mycroft else { 698 1.38 mrg int status; 699 1.38 mrg 700 1.29 mycroft (void)printf( 701 1.24 lukem "Your password has expired. Please choose a new one.\n"); 702 1.38 mrg switch (fork()) { 703 1.38 mrg case -1: 704 1.38 mrg warn("fork"); 705 1.95 christos sleepexit(EXIT_FAILURE); 706 1.38 mrg case 0: 707 1.92 mrg execl(_PATH_BINPASSWD, "passwd", NULL); 708 1.95 christos _exit(EXIT_FAILURE); 709 1.38 mrg default: 710 1.38 mrg if (wait(&status) == -1 || 711 1.38 mrg WEXITSTATUS(status)) 712 1.95 christos sleepexit(EXIT_FAILURE); 713 1.38 mrg } 714 1.29 mycroft } 715 1.24 lukem } 716 1.1 cgd 717 1.44 aidan #ifdef KERBEROS5 718 1.57 aidan if (login_krb5_get_tickets) 719 1.57 aidan k5_write_creds(); 720 1.44 aidan #endif 721 1.92 mrg execlp(pwd->pw_shell, tbuf, NULL); 722 1.95 christos err(EXIT_FAILURE, "%s", pwd->pw_shell); 723 1.1 cgd } 724 1.57 aidan 725 1.89 wiz #if defined(KERBEROS5) 726 1.10 brezak /* 727 1.10 brezak * This routine handles cleanup stuff, and the like. 728 1.10 brezak * It exists only in the child process. 729 1.10 brezak */ 730 1.97 christos static void 731 1.80 xtraeme dofork(void) 732 1.10 brezak { 733 1.95 christos pid_t child, wchild; 734 1.38 mrg 735 1.95 christos switch (child = fork()) { 736 1.95 christos case 0: 737 1.38 mrg return; /* Child process */ 738 1.95 christos case -1: 739 1.95 christos err(EXIT_FAILURE, "Can't fork"); 740 1.95 christos /*NOTREACHED*/ 741 1.95 christos default: 742 1.95 christos break; 743 1.95 christos } 744 1.38 mrg 745 1.55 enami /* 746 1.55 enami * Setup stuff? This would be things we could do in parallel 747 1.55 enami * with login 748 1.55 enami */ 749 1.95 christos if (chdir("/") == -1) /* Let's not keep the fs busy... */ 750 1.95 christos err(EXIT_FAILURE, "Can't chdir to `/'"); 751 1.10 brezak 752 1.38 mrg /* If we're the parent, watch the child until it dies */ 753 1.95 christos while ((wchild = wait(NULL)) != child) 754 1.95 christos if (wchild == -1) 755 1.95 christos err(EXIT_FAILURE, "Can't wait"); 756 1.10 brezak 757 1.38 mrg /* Cleanup stuff */ 758 1.38 mrg /* Run kdestroy to destroy tickets */ 759 1.57 aidan if (login_krb5_get_tickets) 760 1.57 aidan k5destroy(); 761 1.10 brezak 762 1.38 mrg /* Leave */ 763 1.95 christos exit(EXIT_SUCCESS); 764 1.10 brezak } 765 1.1 cgd #endif 766 1.1 cgd 767 1.97 christos static void 768 1.80 xtraeme checknologin(char *fname) 769 1.1 cgd { 770 1.12 jtc int fd, nchars; 771 1.1 cgd char tbuf[8192]; 772 1.1 cgd 773 1.48 mjl if ((fd = open(fname ? fname : _PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { 774 1.1 cgd while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 775 1.1 cgd (void)write(fileno(stdout), tbuf, nchars); 776 1.95 christos sleepexit(EXIT_SUCCESS); 777 1.1 cgd } 778 1.1 cgd } 779 1.1 cgd 780 1.66 christos static void 781 1.80 xtraeme usage(void) 782 1.79 christos { 783 1.79 christos (void)fprintf(stderr, 784 1.79 christos "Usage: %s [-Ffps] [-a address] [-h hostname] [username]\n", 785 1.79 christos getprogname()); 786 1.95 christos exit(EXIT_FAILURE); 787 1.79 christos } 788