1 /* login - log into the system Author: Patrick van Kleef */
3 /* Original version by Patrick van Kleef. History of modifications:
5 * Peter S. Housel Jan. 1988
6 * - Set up $USER, $HOME and $TERM.
7 * - Set signals to SIG_DFL.
9 * Terrence W. Holm June 1988
10 * - Allow a username as an optional argument.
11 * - Time out if a password is not typed within 60 seconds.
12 * - Perform a dummy delay after a bad username is entered.
13 * - Don't allow a login if "/etc/nologin" exists.
14 * - Cause a failure on bad "pw_shell" fields.
15 * - Record the login in "/usr/adm/wtmp".
17 * Peter S. Housel Dec. 1988
18 * - Record the login in "/etc/utmp" also.
20 * F. van Kempen June 1989
21 * - various patches for Minix V1.4a.
23 * F. van Kempen September 1989
24 * - added login-failure administration (new utmp.h needed!).
25 * - support arguments in pw_shell field
26 * - adapted source text to MINIX Style Sheet
28 * F. van Kempen October 1989
29 * - adapted to new utmp database.
30 * F. van Kempen, December 1989
31 * - fixed 'slot' assumption in wtmp()
32 * - fixed all MSS-stuff
33 * - adapted to POSIX (MINIX 1.5)
34 * F. van Kempen, January 1990
35 * - made all 'bad login accounting' optional by "#ifdef BADLOG".
36 * F. van Kempen, Februari 1990
37 * - fixed 'first argument' bug and added some casts.
39 * Andy Tanenbaum April 1990
40 * - if /bin/sh cannot be located, try /usr/bin/sh
42 * Michael A. Temari October 1990
43 * - handle more than single digit tty devices
45 * Philip Homburg - Feb 28 1992
46 * - use ttyname to get the name of a tty.
48 * Kees J. Bot - Feb 13 1993
49 * - putting out garbage.
52 * Kees J. Bot - Feb 13 1993
53 * - supplementary groups.
55 * Kees J. Bot - Jan 3 1996
56 * - ported back to standard Minix.
60 #define _POSIX_C_SOURCE 2
62 #include <sys/types.h>
76 #include <sys/utsname.h>
77 #include <minix/minlib.h>
78 #include <minix/paths.h>
80 char PATH_UTMP
[] = _PATH_UTMP
; /* current logins */
81 char PATH_WTMP
[] = _PATH_WTMP
; /* login/logout history */
82 char PATH_LASTLOG
[] = _PATH_LASTLOG
; /* last login history */
83 char PATH_MOTD
[] = _PATH_MOTD
; /* message of the day */
85 #define TTY_GID 4 /* group ID of ttys */
89 /* Crude indication of a tty being physically secure: */
90 #define securetty(dev) ((unsigned) ((dev) - 0x0400) < (unsigned) 8)
100 extern char **environ
;
102 _PROTOTYPE(int main
, (int argc
, char **argv
));
103 _PROTOTYPE(void wtmp
, (char *user
, int uid
));
104 _PROTOTYPE(void show_file
, (char *nam
));
105 _PROTOTYPE(void Time_out
, (int dummy
));
106 _PROTOTYPE(void usage
, (void));
107 _PROTOTYPE(void add2env
, (char **env
, char *entry
, int replace
));
110 char *user
; /* user name */
111 int uid
; /* user id */
113 /* Make entries in /usr/adm/wtmp and /etc/utmp. */
120 /* First, read the current UTMP entry. we need some of its
121 * parameters! (like PID, ID etc...).
125 if (lineno
== 0) err
= errno
; /* ttyslot failed */
127 if (err
== 0 && (fd
= open(what
= PATH_UTMP
, O_RDONLY
)) < 0) {
128 if (errno
== ENOENT
) return;
131 if (err
== 0 && lseek(fd
, (off_t
) lineno
* sizeof(entry
), SEEK_SET
) < 0)
133 if (err
== 0 && read(fd
, (char *) &entry
, sizeof(entry
)) != sizeof(entry
))
135 if (fd
>= 0) close(fd
);
137 /* Enter new fields. */
138 strncpy(entry
.ut_user
, user
, sizeof(entry
.ut_user
));
139 if (hostname
) strncpy(entry
.ut_host
, hostname
, sizeof(entry
.ut_host
));
141 if (entry
.ut_pid
== 0) entry
.ut_pid
= getpid();
143 entry
.ut_type
= USER_PROCESS
; /* we are past login... */
144 time(&entry
.ut_time
);
146 /* Write a WTMP record. */
148 if ((fd
= open(what
= PATH_WTMP
, O_WRONLY
|O_APPEND
)) < 0) {
149 if (errno
!= ENOENT
) err
= errno
;
151 if (write(fd
, (char *) &entry
, sizeof(entry
)) < 0) err
= errno
;
156 /* Rewrite the UTMP entry. */
157 if (err
== 0 && (fd
= open(what
= PATH_UTMP
, O_WRONLY
)) < 0)
159 if (err
== 0 && lseek(fd
, (off_t
) lineno
* sizeof(entry
), SEEK_SET
) < 0)
161 if (err
== 0 && write(fd
, (char *) &entry
, sizeof(entry
)) < 0)
163 if (fd
>= 0) close(fd
);
165 /* Write the LASTLOG entry. */
166 if (err
== 0 && (fd
= open(what
= PATH_LASTLOG
, O_WRONLY
)) < 0) {
167 if (errno
== ENOENT
) return;
170 if (err
== 0 && lseek(fd
, (off_t
) uid
* sizeof(entry
), SEEK_SET
) < 0)
172 if (err
== 0 && write(fd
, (char *) &entry
, sizeof(entry
)) < 0)
174 if (fd
>= 0) close(fd
);
177 fprintf(stderr
, "login: %s: %s\n", what
, strerror(err
));
186 /* Read a textfile and show it on the desired terminal. */
187 register int fd
, len
;
190 if ((fd
= open(nam
, O_RDONLY
)) > 0) {
193 len
= read(fd
, buf
, 80);
206 char *password
, *cryptedpwd
;
208 int n
, ap
, check_pw
, bad
, secure
, i
, envsiz
, do_banner
;
210 char *bp
, *argx
[8], **ep
; /* pw_shell arguments */
211 char argx0
[64]; /* argv[0] of the shell */
212 char *sh
= "/bin/sh"; /* sh/pw_shell field value */
214 int c
, b_flag
, f_flag
, p_flag
;
216 int authorized
, preserv_env
;
222 /* Don't let QUIT dump core. */
223 sigemptyset(&sa
.sa_mask
);
225 sa
.sa_handler
= exit
;
226 sigaction(SIGQUIT
, &sa
, NULL
);
233 while ((c
= getopt(argc
, argv
, "?bfh:p")) != -1)
237 case 'b': b_flag
= 1; break;
238 case 'f': f_flag
= 1; break;
245 case 'p': p_flag
= 1; break;
249 fprintf(stderr
, "login: getopt failed: '%c'\n", c
);
254 initialname
= argv
[optind
++];
265 /* Look up /dev/tty number. */
266 tty_name
= ttyname(0);
267 if (tty_name
== NULL
)
269 write(1, "Unable to lookup tty name\n", 26);
277 write(1, uts
.sysname
, strlen(uts
.sysname
));
279 write(1, uts
.machine
, strlen(uts
.machine
));
280 write(1, " Release ", 9);
281 write(1, uts
.release
, strlen(uts
.release
));
282 write(1, " Version ", 9);
283 write(1, uts
.version
, strlen(uts
.version
));
285 p
= strrchr(tty_name
, '/');
290 write(1, p
, strlen(p
));
291 write(1, ")\n\n", 3);
292 write(1, uts
.nodename
, strlen(uts
.nodename
));
296 /* Get login name and passwd. */
297 for (;;initialname
= NULL
) {
299 strcpy(name
, initialname
);
302 write(1, "login: ", 7);
303 n
= read(0, name
, 30);
309 "login: read failed: %s\n",
317 /* Start timer running. */
319 sa
.sa_handler
= Time_out
;
320 sigaction(SIGALRM
, &sa
, NULL
);
324 /* Look up login/passwd. */
325 pwd
= getpwnam(name
);
327 check_pw
= 1; /* default is check password. */
329 /* For now, only console is secure. */
330 secure
= fstat(0, &ttystat
) == 0 && securetty(ttystat
.st_rdev
);
332 if (pwd
&& authorized
&& initialname
333 && (pwd
->pw_uid
== getuid() || getuid() == 0)) {
334 check_pw
= 0; /* Don't ask a password for
335 * pre-authorized users.
338 if (pwd
&& secure
&& strcmp(crypt("", pwd
->pw_passwd
),
339 pwd
->pw_passwd
) == 0) {
340 check_pw
= 0; /* empty password */
344 password
= getpass("Password:");
346 if (time_out
) exit(1);
350 if (!password
) { password
= ""; bad
= 1; }
351 if (!secure
&& pwd
&& strcmp(crypt("", pwd
->pw_passwd
),
352 pwd
->pw_passwd
) == 0) bad
= 1;
354 cryptedpwd
= bad
? "*" : pwd
->pw_passwd
;
356 if (strcmp(crypt(password
, cryptedpwd
), cryptedpwd
) != 0) {
357 write(1, "Login incorrect\n", 16);
361 /* Check if the system is going down */
362 if (access("/etc/nologin", 0) == 0 && strcmp(name
, "root") != 0) {
363 write(1, "System going down\n\n", 19);
370 /* Write login record to /usr/adm/wtmp and /etc/utmp */
371 wtmp(name
, pwd
->pw_uid
);
373 /* Create the argv[] array from the pw_shell field. */
375 argx
[ap
++] = argx0
; /* "-sh" most likely */
376 if (pwd
->pw_shell
[0]) {
380 while (*bp
&& *bp
!= ' ' && *bp
!= '\t') bp
++;
381 if (*bp
== ' ' || *bp
== '\t') {
382 *bp
++ = '\0'; /* mark end of string */
388 strcpy(argx0
, "-"); /* most shells need it for their .profile */
389 if ((bp
= strrchr(sh
, '/')) == NULL
) bp
= sh
; else bp
++;
390 strncat(argx0
, bp
, sizeof(argx0
) - 2);
392 /* Set the environment */
395 for (ep
= environ
; *ep
; ep
++)
402 env
= calloc(envsiz
+ EXTRA_ENV
, sizeof(*env
));
405 fprintf(stderr
, "login: out of memory\n");
408 for (i
= 0; i
<envsiz
; i
++)
411 strcpy(user
, "USER=");
413 add2env(env
, user
, 1);
414 strcpy(logname
, "LOGNAME=");
415 strcat(logname
, name
);
416 add2env(env
, logname
, 1);
417 strcpy(home
, "HOME=");
418 strcat(home
, pwd
->pw_dir
);
419 add2env(env
, home
, 1);
420 strcpy(shell
, "SHELL=");
422 add2env(env
, shell
, 1);
423 if ((ttyp
= getttynam(tty_name
+ 5)) != NULL
) {
424 strcpy(term
, "TERM=");
425 strcat(term
, ttyp
->ty_type
);
426 add2env(env
, term
, 0);
429 /* Show the message-of-the-day. */
430 show_file(PATH_MOTD
);
432 /* Assign the terminal to this user. */
433 chown(tty_name
, pwd
->pw_uid
, TTY_GID
);
434 chmod(tty_name
, 0620);
437 initgroups(pwd
->pw_name
, pwd
->pw_gid
);
444 /* Reset signals to default values. */
445 sa
.sa_handler
= SIG_DFL
;
446 for (n
= 1; n
< _NSIG
; ++n
) sigaction(n
, &sa
, NULL
);
448 /* Execute the user's shell. */
449 execve(sh
, argx
, env
);
451 if (pwd
->pw_gid
== 0) {
452 /* Privileged user gets /bin/sh in times of crisis. */
455 strcpy(shell
, "SHELL=");
457 execve(sh
, argx
, env
);
459 fprintf(stderr
, "login: can't execute %s: %s\n", sh
, strerror(errno
));
467 int dummy
; /* to keep the compiler happy */
469 write(2, "\r\nLogin timed out after 60 seconds\r\n", 36);
476 "Usage: login [-h hostname] [-b] [-f] [-p] [username]\n");
480 void add2env(env
, entry
, replace
)
485 /* Replace an environment variable with entry or add entry if the environment
486 * variable doesn't exit yet.
491 cp
= strchr(entry
, '=');
496 if (strncmp(*env
, entry
, keylen
) == 0) {
497 if (!replace
) return; /* Don't replace */
505 * $PchId: login.c,v 1.6 2001/07/31 14:23:28 philip Exp $