📄 login.c
字号:
/* login - log into the system Author: Patrick van Kleef *//* Original version by Patrick van Kleef. History of modifications: * * Peter S. Housel Jan. 1988 * - Set up $USER, $HOME and $TERM. * - Set signals to SIG_DFL. * * Terrence W. Holm June 1988 * - Allow a username as an optional argument. * - Time out if a password is not typed within 60 seconds. * - Perform a dummy delay after a bad username is entered. * - Don't allow a login if "/etc/nologin" exists. * - Cause a failure on bad "pw_shell" fields. * - Record the login in "/usr/adm/wtmp". * * Peter S. Housel Dec. 1988 * - Record the login in "/etc/utmp" also. * * F. van Kempen June 1989 * - various patches for Minix V1.4a. * * F. van Kempen September 1989 * - added login-failure administration (new utmp.h needed!). * - support arguments in pw_shell field * - adapted source text to MINIX Style Sheet * * F. van Kempen October 1989 * - adapted to new utmp database. * F. van Kempen, December 1989 * - fixed 'slot' assumption in wtmp() * - fixed all MSS-stuff * - adapted to POSIX (MINIX 1.5) * F. van Kempen, January 1990 * - made all 'bad login accounting' optional by "#ifdef BADLOG". * F. van Kempen, Februari 1990 * - fixed 'first argument' bug and added some casts. * * Andy Tanenbaum April 1990 * - if /bin/sh cannot be located, try /usr/bin/sh * * Michael A. Temari October 1990 * - handle more than single digit tty devices * * Philip Homburg - Feb 28 1992 * - use ttyname to get the name of a tty. * * Kees J. Bot - Feb 13 1993 * - putting out garbage. * - added lastlog. * * Kees J. Bot - Feb 13 1993 * - supplementary groups. * * Kees J. Bot - Jan 3 1996 * - ported back to standard Minix. */#include <sys/types.h>#include <sys/stat.h>#include <ttyent.h>#include <errno.h>#include <fcntl.h>#include <pwd.h>#include <grp.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <utmp.h>#include <time.h>#include <minix/minlib.h>char PATH_UTMP[] = "/etc/utmp"; /* current logins */char PATH_WTMP[] = "/usr/adm/wtmp"; /* login/logout history */char PATH_LASTLOG[] = "/usr/adm/lastlog"; /* last login history */char PATH_MOTD[] = "/etc/motd"; /* message of the day */#define TTY_GID 4 /* group ID of ttys */#define EXTRA_ENV 6/* Crude indication of a tty being physically secure: */#define securetty(dev) ((unsigned) ((dev) - 0x0400) < (unsigned) 8)int time_out;char *hostname;char user[32];char logname[35];char home[128];char shell[128];char term[128];char **env;extern char **environ;_PROTOTYPE(int main, (int argc, char **argv));_PROTOTYPE(void wtmp, (char *user, int uid));_PROTOTYPE(void show_file, (char *nam));_PROTOTYPE(void Time_out, (int dummy));_PROTOTYPE(void usage, (void));_PROTOTYPE(void add2env, (char **env, char *entry, int replace));void wtmp(user, uid)char *user; /* user name */int uid; /* user id */{ /* Make entries in /usr/adm/wtmp and /etc/utmp. */ struct utmp entry; register int fd= -1; int lineno; int err = 0; char *what; /* First, read the current UTMP entry. we need some of its * parameters! (like PID, ID etc...). */ what= "ttyslot()"; lineno= ttyslot(); if (lineno == 0) err= errno; /* ttyslot failed */ if (err == 0 && (fd = open(what = PATH_UTMP, O_RDONLY)) < 0) { if (errno == ENOENT) return; err= errno; } if (err == 0 && lseek(fd, (off_t) lineno * sizeof(entry), SEEK_SET) < 0) err= errno; if (err == 0 && read(fd, (char *) &entry, sizeof(entry)) != sizeof(entry)) err= errno; if (fd >= 0) close(fd); /* Enter new fields. */ strncpy(entry.ut_user, user, sizeof(entry.ut_user)); if (hostname) strncpy(entry.ut_host, hostname, sizeof(entry.ut_host)); if (entry.ut_pid == 0) entry.ut_pid = getpid(); entry.ut_type = USER_PROCESS; /* we are past login... */ time(&entry.ut_time); /* Write a WTMP record. */ if (err == 0) { if ((fd = open(what = PATH_WTMP, O_WRONLY|O_APPEND)) < 0) { if (errno != ENOENT) err= errno; } else { if (write(fd, (char *) &entry, sizeof(entry)) < 0) err= errno; close(fd); } } /* Rewrite the UTMP entry. */ if (err == 0 && (fd = open(what = PATH_UTMP, O_WRONLY)) < 0) err= errno; if (err == 0 && lseek(fd, (off_t) lineno * sizeof(entry), SEEK_SET) < 0) err= errno; if (err == 0 && write(fd, (char *) &entry, sizeof(entry)) < 0) err= errno; if (fd >= 0) close(fd); /* Write the LASTLOG entry. */ if (err == 0 && (fd = open(what = PATH_LASTLOG, O_WRONLY)) < 0) { if (errno == ENOENT) return; err= errno; } if (err == 0 && lseek(fd, (off_t) uid * sizeof(entry), SEEK_SET) < 0) err= errno; if (err == 0 && write(fd, (char *) &entry, sizeof(entry)) < 0) err= errno; if (fd >= 0) close(fd); if (err != 0) { fprintf(stderr, "login: %s: %s\n", what, strerror(err)); return; }}void show_file(nam)char *nam;{/* Read a textfile and show it on the desired terminal. */ register int fd, len; char buf[80]; if ((fd = open(nam, O_RDONLY)) > 0) { len = 1; while (len > 0) { len = read(fd, buf, 80); write(1, buf, len); } close(fd); }}int main(argc, argv)int argc;char *argv[];{ char name[30]; char *password, *cryptedpwd; char *tty_name; int n, ap, check_pw, bad, secure, i, envsiz; struct passwd *pwd; char *bp, *argx[8], **ep; /* pw_shell arguments */ char argx0[64]; /* argv[0] of the shell */ char *sh = "/bin/sh"; /* sh/pw_shell field value */ char *initialname; int c, f_flag, p_flag; char *h_arg; int authorized, preserv_env; struct ttyent *ttyp; struct stat ttystat; struct sigaction sa; /* Don't let QUIT dump core. */ sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = exit; sigaction(SIGQUIT, &sa, NULL); /* Parse options. */ f_flag= 0; p_flag= 0; h_arg= NULL; while ((c= getopt(argc, argv, "?fh:p")) != -1) { switch(c) { case 'f': if (f_flag) usage(); f_flag= 1; break; case 'h': if (h_arg) usage(); if (getuid() == 0) h_arg= optarg; break; case 'p': if (p_flag) usage(); p_flag= 1; break; case '?': usage(); default: fprintf(stderr, "login: getopt failed: '%c'\n", c); exit(1); } } if (optind < argc) initialname= argv[optind++]; else initialname= NULL; if (optind != argc) usage(); authorized= f_flag; hostname= h_arg; preserv_env= p_flag; /* Look up /dev/tty number. */ tty_name= ttyname(0); if (tty_name == NULL) { write(1, "Unable to lookup tty name\n", 26); exit(1); } /* Get login name and passwd. */ for (;;initialname= NULL) { if (initialname) strcpy(name, initialname); else { do { write(1, "login: ", 7); n = read(0, name, 30); if (n == 0) exit(1); if (n < 0) { if (errno != EINTR) fprintf(stderr, "login: read failed: %s\n", strerror(errno)); exit(1); } } while (n < 2); name[n - 1] = 0; } /* Start timer running. */ time_out = 0; sa.sa_handler = Time_out; sigaction(SIGALRM, &sa, NULL); alarm(60); /* Look up login/passwd. */ pwd = getpwnam(name); check_pw = 1; /* default is check password. */ /* For now, only console is secure. */ secure = fstat(0, &ttystat) == 0 && securetty(ttystat.st_rdev); if (pwd && authorized && initialname && (pwd->pw_uid == getuid() || getuid() == 0)) { check_pw= 0; /* Don't ask a password for * pre-authorized users. */ } else if (pwd && secure && strcmp(crypt("", pwd->pw_passwd), pwd->pw_passwd) == 0) { check_pw= 0; /* empty password */ } if (check_pw) { password = getpass("Password:"); if (time_out) exit(1); bad = 0; if (!pwd) bad = 1; if (!password) { password = ""; bad = 1; } if (!secure && pwd && strcmp(crypt("", pwd->pw_passwd), pwd->pw_passwd) == 0) bad = 1; cryptedpwd = bad ? "*" : pwd->pw_passwd; if (strcmp(crypt(password, cryptedpwd), cryptedpwd) != 0) { write(1, "Login incorrect\n", 16); continue; } } /* Check if the system is going down */ if (access("/etc/nologin", 0) == 0 && strcmp(name, "root") != 0) { write(1, "System going down\n\n", 19); continue; } /* Stop timer. */ alarm(0); /* Write login record to /usr/adm/wtmp and /etc/utmp */ wtmp(name, pwd->pw_uid); /* Create the argv[] array from the pw_shell field. */ ap = 0; argx[ap++] = argx0; /* "-sh" most likely */ if (pwd->pw_shell[0]) { sh = pwd->pw_shell; bp = sh; while (*bp) { while (*bp && *bp != ' ' && *bp != '\t') bp++; if (*bp == ' ' || *bp == '\t') { *bp++ = '\0'; /* mark end of string */ argx[ap++] = bp; } } } else argx[ap] = NULL; strcpy(argx0, "-"); /* most shells need it for their .profile */ if ((bp= strrchr(sh, '/')) == NULL) bp = sh; else bp++; strncat(argx0, bp, sizeof(argx0) - 2); /* Set the environment */ if (p_flag) { for (ep= environ; *ep; ep++) ; } else ep= environ; envsiz= ep-environ; env= calloc(envsiz + EXTRA_ENV, sizeof(*env)); if (env == NULL) { fprintf(stderr, "login: out of memory\n"); exit(1); } for (i= 0; i<envsiz; i++) env[i]= environ[i]; strcpy(user, "USER="); strcat(user, name); add2env(env, user, 1); strcpy(logname, "LOGNAME="); strcat(logname, name); add2env(env, logname, 1); strcpy(home, "HOME="); strcat(home, pwd->pw_dir); add2env(env, home, 1); strcpy(shell, "SHELL="); strcat(shell, sh); add2env(env, shell, 1); if ((ttyp = getttynam(tty_name + 5)) != NULL) { strcpy(term, "TERM="); strcat(term, ttyp->ty_type); add2env(env, term, 0); } /* Show the message-of-the-day. */ show_file(PATH_MOTD); /* Assign the terminal to this user. */ chown(tty_name, pwd->pw_uid, TTY_GID); chmod(tty_name, 0620); /* Change id. */#if __minix_vmd initgroups(pwd->pw_name, pwd->pw_gid);#endif setgid(pwd->pw_gid); setuid(pwd->pw_uid); /* cd $HOME */ chdir(pwd->pw_dir); /* Reset signals to default values. */ sa.sa_handler = SIG_DFL; for (n = 1; n <= _NSIG; ++n) sigaction(n, &sa, NULL); /* Execute the user's shell. */ execve(sh, argx, env); if (pwd->pw_gid == 0) { /* Privileged user gets /bin/sh in times of crisis. */ sh= "/bin/sh"; argx[0]= "-sh"; strcpy(shell, "SHELL="); strcat(shell, sh); execve(sh, argx, env); } write(1, "exec failure\n", 13); exit(1); } return(0);}void Time_out(dummy)int dummy; /* to keep the compiler happy */{ write(2, "\r\nLogin timed out after 60 seconds\r\n", 36); time_out = 1;}void usage(){ fprintf(stderr, "Usage: login [-h hostname] [-f] [-p] [username]\n"); exit(1);}void add2env(env, entry, replace)char **env;char *entry;int replace;{/* Replace an environment variable with entry or add entry if the environment * variable doesn't exit yet. */ char *cp; int keylen; cp= strchr(entry, '='); keylen= cp-entry+1; for(; *env; env++) { if (strncmp(*env, entry, keylen) == 0) { if (!replace) return; /* Don't replace */ break; } } *env= entry;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -