📄 login.c
字号:
/* This program is derived from 4.3 BSD software and is subject to the copyright notice below. The port to HP-UX has been motivated by the incapability of 'rlogin'/'rlogind' as per HP-UX 6.5 (and 7.0) to transfer window sizes. Changes: - General HP-UX portation. Use of facilities not available in HP-UX (e.g. setpriority) has been eliminated. Utmp/wtmp handling has been ported. - The program uses BSD command line options to be used in connection with e.g. 'rlogind' i.e. 'new login'. - HP features left out: password expiry '*' as login shell, add it if you need it - BSD features left out: quota checks password expiry analysis of terminal type (tset feature) - BSD features thrown in: Security logging to syslogd. This requires you to have a (ported) syslog system -- 7.0 comes with syslog 'Lastlog' feature. - A lot of nitty gritty details have been adjusted in favour of HP-UX, e.g. /etc/securetty, default paths and the environment variables assigned by 'login'. - We do *nothing* to setup/alter tty state, under HP-UX this is to be done by getty/rlogind/telnetd/some one else. Michael Glad (glad@daimi.dk) Computer Science Department Aarhus University Denmark 1990-07-04 1991-09-24 glad@daimi.aau.dk: HP-UX 8.0 port: - now explictly sets non-blocking mode on descriptors - strcasecmp is now part of HP-UX 1992-02-05 poe@daimi.aau.dk: Ported the stuff to Linux 0.12 From 1992 till now (1997) this code for Linux has been maintained at ftp.daimi.aau.dk:/pub/linux/poe/ 1999-02-22 Arkadiusz Mi秌iewicz <misiek@pld.ORG.PL> - added Native Language Support Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - fixed strerr(errno) in gettext calls *//* * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. *//* * login [ name ] * login -h hostname (for telnetd, etc.) * login -f name (for pre-authenticated login: datakit, xterm, etc.) *//* #define TESTING */#ifdef TESTING#include "param.h"#else#include <sys/param.h>#endif#include <stdio.h>#include <ctype.h>#include <unistd.h>#include <getopt.h>#include <memory.h>#include <time.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/resource.h>#include <sys/file.h>#include <termios.h>#include <string.h>#define index strchr#define rindex strrchr#include <sys/ioctl.h>#include <sys/wait.h>#include <signal.h>#include <errno.h>#include <grp.h>#include <pwd.h>#include <utmp.h>#include <setjmp.h>#include <stdlib.h>#include <string.h>#include <sys/syslog.h>#include <sys/sysmacros.h>#include <netdb.h>#include "pathnames.h"#include "my_crypt.h"#include "login.h"#include "xstrncpy.h"#include "nls.h"#ifdef __linux__# include <sys/sysmacros.h># include <linux/major.h>#endif#ifdef TESTING# include "utmp.h"#else# include <utmp.h>#endif#ifdef SHADOW_PWD# include <shadow.h>#endif#ifdef USE_PAM# include <security/pam_appl.h># include <security/pam_misc.h># define PAM_MAX_LOGIN_TRIES 3# define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \ fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \ syslog(LOG_ERR,"%s",pam_strerror(pamh, retcode)); \ pam_end(pamh, retcode); exit(1); \ }# define PAM_END { \ pam_setcred(pamh, PAM_DELETE_CRED); \ retcode = pam_close_session(pamh,0); \ pam_end(pamh,retcode); \}#endif#ifndef __linux__# include <tzfile.h>#endif#include <lastlog.h>#define SLEEP_EXIT_TIMEOUT 5#ifdef __linux__#define DO_PS_FIDDLING#endif#ifdef DO_PS_FIDDLING#include "setproctitle.h"#endif#if 0/* from before we had a lastlog.h file in linux */struct lastlog{ long ll_time; char ll_line[12]; char ll_host[16];};#endif#ifndef USE_PAMstatic void getloginname (void);static void checknologin (void);static int rootterm (char *ttyn);#endifstatic void timedout (int);static void sigint (int);static void motd (void);static void dolastlog (int quiet);#ifdef CRYPTOCARD#include "cryptocard.h"#endif#ifdef KERBEROS#include <kerberos/krb.h>#include <sys/termios.h>char realm[REALM_SZ];int kerror = KSUCCESS, notickets = 1;#endif#ifdef USE_TTY_GROUP# define TTY_MODE 0620#else# define TTY_MODE 0600#endif#define TTYGRPNAME "tty" /* name of group to own ttys */#ifndef MAXPATHLEN# define MAXPATHLEN 1024#endif/* * This bounds the time given to login. Not a define so it can * be patched on machines where it's too small. */#ifndef __linux__int timeout = 300;#elseint timeout = 60; /* used in cryptocard.c */#endifstruct passwd *pwd; /* used in cryptocard.c */#if USE_PAMstatic struct passwd pwdcopy;#endifchar hostaddress[4]; /* used in checktty.c */char *hostname; /* idem */static char *username, *tty_name, *tty_number;static char thishost[100];static int failures = 1;static pid_t pid;#ifndef __linux__struct sgttyb sgttyb;struct tchars tc = { CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK};struct ltchars ltc = { CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT};#endif/* Nice and simple code provided by Linus Torvalds 16-Feb-93 *//* Nonblocking stuff by Maciej W. Rozycki, macro@ds2.pg.gda.pl, 1999. He writes: "Login performs open() on a tty in a blocking mode. In some cases it may make login wait in open() for carrier infinitely, for example if the line is a simplistic case of a three-wire serial connection. I believe login should open the line in the non-blocking mode leaving the decision to make a connection to getty (where it actually belongs). */static voidopentty(const char * tty) { int i, fd, flags; fd = open(tty, O_RDWR | O_NONBLOCK); if (fd == -1) { syslog(LOG_ERR, _("FATAL: can't reopen tty: %s"), strerror(errno)); sleep(1); exit(1); } flags = fcntl(fd, F_GETFL); flags &= ~O_NONBLOCK; fcntl(fd, F_SETFL, flags); for (i = 0; i < fd; i++) close(i); for (i = 0; i < 3; i++) if (fd != i) dup2(fd, i); if (fd >= 3) close(fd);}/* In case login is suid it was possible to use a hardlink as stdin and exploit races for a local root exploit. (Wojciech Purczynski). *//* More precisely, the problem is ttyn := ttyname(0); ...; chown(ttyn); here ttyname() might return "/tmp/x", a hardlink to a pseudotty. *//* All of this is a problem only when login is suid, which it isnt. */static voidcheck_ttyname(char *ttyn) { struct stat statbuf; if (lstat(ttyn, &statbuf) || !S_ISCHR(statbuf.st_mode) || (statbuf.st_nlink > 1 && strncmp(ttyn, "/dev/", 5))) { syslog(LOG_ERR, _("FATAL: bad tty")); sleep(1); exit(1); }}/* true if the filedescriptor fd is a console tty, very Linux specific */static intconsoletty(int fd) {#ifdef __linux__ struct stat stb; if ((fstat(fd, &stb) >= 0) && (major(stb.st_rdev) == TTY_MAJOR) && (minor(stb.st_rdev) < 64)) { return 1; }#endif return 0;}#if USE_PAM/* * Log failed login attempts in _PATH_BTMP if that exists. * Must be called only with username the name of an actual user. * The most common login failure is to give password instead of username. */#define _PATH_BTMP "/var/log/btmp"static voidlogbtmp(const char *line, const char *username, const char *hostname) { struct utmp ut; memset(&ut, 0, sizeof(ut)); strncpy(ut.ut_user, username ? username : "(unknown)", sizeof(ut.ut_user)); strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id)); xstrncpy(ut.ut_line, line, sizeof(ut.ut_line));#if defined(_HAVE_UT_TV) /* in <utmpbits.h> included by <utmp.h> */ gettimeofday(&ut.ut_tv, NULL);#else { time_t t; time(&t); ut.ut_time = t; /* ut_time is not always a time_t */ }#endif ut.ut_type = LOGIN_PROCESS; /* XXX doesn't matter */ ut.ut_pid = pid; if (hostname) { xstrncpy(ut.ut_host, hostname, sizeof(ut.ut_host)); if (hostaddress[0]) memcpy(&ut.ut_addr, hostaddress, sizeof(ut.ut_addr)); }#ifdef HAVE_updwtmp /* bad luck for ancient systems */ updwtmp(_PATH_BTMP, &ut);#endif}#endif /* USE_PAM */intmain(int argc, char **argv){ extern int optind; extern char *optarg, **environ; struct group *gr; register int ch; register char *p; int ask, fflag, hflag, pflag, cnt, errsv; int quietlog, passwd_req; char *domain, *ttyn; char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; char *termenv; char *childArgv[10]; char *buff; int childArgc = 0;#ifdef USE_PAM int retcode; pam_handle_t *pamh = NULL; struct pam_conv conv = { misc_conv, NULL }; pid_t childPid;#else char *salt, *pp;#endif#ifdef CHOWNVCS char vcsn[20], vcsan[20];#endif pid = getpid(); signal(SIGALRM, timedout); alarm((unsigned int)timeout); signal(SIGQUIT, SIG_IGN); signal(SIGINT, SIG_IGN); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); setpriority(PRIO_PROCESS, 0, 0);#ifdef HAVE_QUOTA quota(Q_SETUID, 0, 0, 0);#endif#ifdef DO_PS_FIDDLING initproctitle(argc, argv);#endif /* * -p is used by getty to tell login not to destroy the environment * -f is used to skip a second login authentication * -h is used by other servers to pass the name of the remote * host to login so that it may be placed in utmp and wtmp */ gethostname(tbuf, sizeof(tbuf)); xstrncpy(thishost, tbuf, sizeof(thishost)); domain = index(tbuf, '.'); username = tty_name = hostname = NULL; fflag = hflag = pflag = 0; passwd_req = 1; while ((ch = getopt(argc, argv, "fh:p")) != -1) switch (ch) { case 'f': fflag = 1; break; case 'h': if (getuid()) { fprintf(stderr, _("login: -h for super-user only.\n")); exit(1); } hflag = 1; if (domain && (p = index(optarg, '.')) && strcasecmp(p, domain) == 0) *p = 0; hostname = strdup(optarg); /* strdup: Ambrose C. Li */ { struct hostent *he = gethostbyname(hostname); /* he points to static storage; copy the part we use */ hostaddress[0] = 0; if (he && he->h_addr_list && he->h_addr_list[0]) memcpy(hostaddress, he->h_addr_list[0], sizeof(hostaddress)); } break; case 'p': pflag = 1; break; case '?': default: fprintf(stderr, _("usage: login [-fp] [username]\n")); exit(1); } argc -= optind; argv += optind; if (*argv) { char *p = *argv; username = strdup(p); ask = 0; /* wipe name - some people mistype their password here */ /* (of course we are too late, but perhaps this helps a little ..) */ while(*p) *p++ = ' '; } else ask = 1; for (cnt = getdtablesize(); cnt > 2; cnt--) close(cnt); ttyn = ttyname(0); if (ttyn == NULL || *ttyn == '\0') { /* no snprintf required - see definition of tname */ sprintf(tname, "%s??", _PATH_TTY); ttyn = tname; } check_ttyname(ttyn); if (strncmp(ttyn, "/dev/", 5) == 0) tty_name = ttyn+5; else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -