Module Name: src Committed By: christos Date: Tue Dec 29 19:26:13 UTC 2009
Modified Files: src/usr.bin/login: Makefile login.c login_pam.c Added Files: src/usr.bin/login: common.c common.h Log Message: PR/42540: Ed Ravin: /usr/bin/login does not log normal logins, and does not log ip addresses. - Factor out the common code in login.c and login_pam.c into common.c - Always log a login event - Check passed in sockaddr against the one from getpeername(2). To generate a diff of this commit: cvs rdiff -u -r1.50 -r1.51 src/usr.bin/login/Makefile cvs rdiff -u -r0 -r1.1 src/usr.bin/login/common.c src/usr.bin/login/common.h cvs rdiff -u -r1.96 -r1.97 src/usr.bin/login/login.c cvs rdiff -u -r1.19 -r1.20 src/usr.bin/login/login_pam.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/login/Makefile diff -u src/usr.bin/login/Makefile:1.50 src/usr.bin/login/Makefile:1.51 --- src/usr.bin/login/Makefile:1.50 Tue Apr 14 18:15:22 2009 +++ src/usr.bin/login/Makefile Tue Dec 29 14:26:13 2009 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.50 2009/04/14 22:15:22 lukem Exp $ +# $NetBSD: Makefile,v 1.51 2009/12/29 19:26:13 christos Exp $ # @(#)Makefile 8.1 (Berkeley) 7/19/93 WARNS?= 2 # XXX -Wcast-qual issues @@ -13,6 +13,7 @@ BINOWN= root BINMODE=4555 +SRCS+= common.c .if (${USE_PAM} != "no") SRCS+= login_pam.c LDADD+= -lpam ${PAM_STATIC_LDADD} Index: src/usr.bin/login/login.c diff -u src/usr.bin/login/login.c:1.96 src/usr.bin/login/login.c:1.97 --- src/usr.bin/login/login.c:1.96 Mon Jul 21 10:19:23 2008 +++ src/usr.bin/login/login.c Tue Dec 29 14:26:13 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: login.c,v 1.96 2008/07/21 14:19:23 lukem Exp $ */ +/* $NetBSD: login.c,v 1.97 2009/12/29 19:26:13 christos Exp $ */ /*- * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 @@ -39,7 +39,7 @@ #if 0 static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; #endif -__RCSID("$NetBSD: login.c,v 1.96 2008/07/21 14:19:23 lukem Exp $"); +__RCSID("$NetBSD: login.c,v 1.97 2009/12/29 19:26:13 christos Exp $"); #endif /* not lint */ /* @@ -91,31 +91,15 @@ #include <vis.h> #include "pathnames.h" +#include "common.h" #ifdef KERBEROS5 -int login_krb5_get_tickets = 1; int login_krb5_forwardable_tgt = 0; -int login_krb5_retain_ccache = 0; +static int login_krb5_get_tickets = 1; +static int login_krb5_retain_ccache = 0; #endif -void badlogin(char *); -void checknologin(char *); -#ifdef SUPPORT_UTMP -static void doutmp(void); -static void dolastlog(int); -#endif -#ifdef SUPPORT_UTMPX -static void doutmpx(void); -static void dolastlogx(int); -#endif -static void update_db(int); -void getloginname(void); -void motd(char *); -int rootterm(char *); -void sigint(int); -void sleepexit(int); -const char *stypeof(const char *); -void timedout(int); +static void checknologin(char *); #ifdef KERBEROS5 int k5login(struct passwd *, char *, char *, char *); void k5destroy(void); @@ -123,26 +107,19 @@ int k5_write_creds(void); #endif #if defined(KERBEROS5) -void dofork(void); +static void dofork(void); #endif -void decode_ss(const char *); -void usage(void); +static void usage(void); #define TTYGRPNAME "tty" /* name of group to own ttys */ #define DEFAULT_BACKOFF 3 #define DEFAULT_RETRIES 10 -/* - * This bounds the time given to login. Not a define so it can - * be patched on machines where it's too small. - */ -u_int timeout = 300; - #if defined(KERBEROS5) -int notickets = 1; -char *instance; int has_ccache = 0; +static int notickets = 1; +static char *instance; extern krb5_context kcontext; extern int have_forward; extern char *krb5tkfile_env; @@ -153,18 +130,11 @@ #define KERBEROS_CONFIGURED krb5_configured #endif -struct passwd *pwd; -int failures, have_ss; -char term[64], *envinit[1], *hostname, *username, *tty, *nested; -struct timeval now; -struct sockaddr_storage ss; - -extern const char copyrightstr[]; +extern char **environ; int main(int argc, char *argv[]) { - extern char **environ; struct group *gr; struct stat st; int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval; @@ -577,7 +547,7 @@ } /* Nothing else left to fail -- really log in. */ - update_db(quietlog); + update_db(quietlog, rootlogin, fflag); (void)chown(ttyn, pwd->pw_uid, (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); @@ -748,17 +718,11 @@ } #if defined(KERBEROS5) -#define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */ -#else -#define NBUFSIZ (MAXLOGNAME + 1) -#endif - -#if defined(KERBEROS5) /* * This routine handles cleanup stuff, and the like. * It exists only in the child process. */ -void +static void dofork(void) { pid_t child, wchild; @@ -795,81 +759,7 @@ } #endif -void -getloginname(void) -{ - int ch; - char *p; - static char nbuf[NBUFSIZ]; - - for (;;) { - (void)printf("login: "); - for (p = nbuf; (ch = getchar()) != '\n'; ) { - if (ch == EOF) { - badlogin(username); - exit(EXIT_FAILURE); - } - if (p < nbuf + (NBUFSIZ - 1)) - *p++ = ch; - } - if (p > nbuf) { - if (nbuf[0] == '-') - (void)fprintf(stderr, - "login names may not start with '-'.\n"); - else { - *p = '\0'; - username = nbuf; - break; - } - } - } -} - -int -rootterm(char *ttyn) -{ - struct ttyent *t; - - return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); -} - -jmp_buf motdinterrupt; - -void -motd(char *fname) -{ - int fd, nchars; - sig_t oldint; - char tbuf[8192]; - - if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0) - return; - oldint = signal(SIGINT, sigint); - if (setjmp(motdinterrupt) == 0) - while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) - (void)write(fileno(stdout), tbuf, nchars); - (void)signal(SIGINT, oldint); - (void)close(fd); -} - -/* ARGSUSED */ -void -sigint(int signo) -{ - - longjmp(motdinterrupt, 1); -} - -/* ARGSUSED */ -void -timedout(int signo) -{ - - (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); - exit(EXIT_FAILURE); -} - -void +static void checknologin(char *fname) { int fd, nchars; @@ -883,202 +773,6 @@ } static void -update_db(int quietlog) -{ - if (nested != NULL) { - if (hostname != NULL) - syslog(LOG_NOTICE, "%s to %s on tty %s from %s", - nested, pwd->pw_name, tty, hostname); - else - syslog(LOG_NOTICE, "%s to %s on tty %s", nested, - pwd->pw_name, tty); - - return; - } - if (hostname != NULL && have_ss == 0) { - socklen_t len = sizeof(ss); - have_ss = getpeername(STDIN_FILENO, (struct sockaddr *)&ss, - &len) != -1; - } - (void)gettimeofday(&now, NULL); -#ifdef SUPPORT_UTMPX - doutmpx(); - dolastlogx(quietlog); - quietlog = 1; -#endif -#ifdef SUPPORT_UTMP - doutmp(); - dolastlog(quietlog); -#endif -} - -#ifdef SUPPORT_UTMPX -static void -doutmpx(void) -{ - struct utmpx utmpx; - char *t; - - memset((void *)&utmpx, 0, sizeof(utmpx)); - utmpx.ut_tv = now; - (void)strncpy(utmpx.ut_name, username, sizeof(utmpx.ut_name)); - if (hostname) { - (void)strncpy(utmpx.ut_host, hostname, sizeof(utmpx.ut_host)); - utmpx.ut_ss = ss; - } - (void)strncpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line)); - utmpx.ut_type = USER_PROCESS; - utmpx.ut_pid = getpid(); - t = tty + strlen(tty); - if (t - tty >= sizeof(utmpx.ut_id)) { - (void)strncpy(utmpx.ut_id, t - sizeof(utmpx.ut_id), - sizeof(utmpx.ut_id)); - } else { - (void)strncpy(utmpx.ut_id, tty, sizeof(utmpx.ut_id)); - } - if (pututxline(&utmpx) == NULL) - syslog(LOG_NOTICE, "Cannot update utmpx: %m"); - endutxent(); - if (updwtmpx(_PATH_WTMPX, &utmpx) != 0) - syslog(LOG_NOTICE, "Cannot update wtmpx: %m"); -} - -static void -dolastlogx(int quiet) -{ - struct lastlogx ll; - if (!quiet && getlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != NULL) { - time_t t = (time_t)ll.ll_tv.tv_sec; - (void)printf("Last login: %.24s ", ctime(&t)); - if (*ll.ll_host != '\0') - (void)printf("from %.*s ", - (int)sizeof(ll.ll_host), - ll.ll_host); - (void)printf("on %.*s\n", - (int)sizeof(ll.ll_line), - ll.ll_line); - } - ll.ll_tv = now; - (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); - if (hostname) - (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); - else - (void)memset(ll.ll_host, '\0', sizeof(ll.ll_host)); - if (have_ss) - ll.ll_ss = ss; - else - (void)memset(&ll.ll_ss, 0, sizeof(ll.ll_ss)); - if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0) - syslog(LOG_NOTICE, "Cannot update lastlogx: %m"); -} -#endif - -#ifdef SUPPORT_UTMP -static void -doutmp(void) -{ - struct utmp utmp; - - (void)memset((void *)&utmp, 0, sizeof(utmp)); - utmp.ut_time = now.tv_sec; - (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); - if (hostname) - (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); - (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); - login(&utmp); -} - -static void -dolastlog(int quiet) -{ - struct lastlog ll; - int fd; - - if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { - (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET); - if (!quiet) { - if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && - ll.ll_time != 0) { - (void)printf("Last login: %.24s ", - ctime(&ll.ll_time)); - if (*ll.ll_host != '\0') - (void)printf("from %.*s ", - (int)sizeof(ll.ll_host), - ll.ll_host); - (void)printf("on %.*s\n", - (int)sizeof(ll.ll_line), ll.ll_line); - } - (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), - SEEK_SET); - } - memset((void *)&ll, 0, sizeof(ll)); - ll.ll_time = now.tv_sec; - (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); - if (hostname) - (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); - (void)write(fd, (char *)&ll, sizeof(ll)); - (void)close(fd); - } -} -#endif - -void -badlogin(char *name) -{ - - if (failures == 0) - return; - if (hostname) { - syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", - failures, failures > 1 ? "S" : "", hostname); - syslog(LOG_AUTHPRIV|LOG_NOTICE, - "%d LOGIN FAILURE%s FROM %s, %s", - failures, failures > 1 ? "S" : "", hostname, name); - } else { - syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", - failures, failures > 1 ? "S" : "", tty); - syslog(LOG_AUTHPRIV|LOG_NOTICE, - "%d LOGIN FAILURE%s ON %s, %s", - failures, failures > 1 ? "S" : "", tty, name); - } -} - -const char * -stypeof(const char *ttyid) -{ - struct ttyent *t; - - return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL); -} - -void -sleepexit(int eval) -{ - - (void)sleep(5); - exit(eval); -} - -void -decode_ss(const char *arg) -{ - struct sockaddr_storage *ssp; - size_t len = strlen(arg); - - if (len > sizeof(*ssp) * 4 + 1 || len < sizeof(*ssp)) - errx(EXIT_FAILURE, "Bad argument"); - - if ((ssp = malloc(len)) == NULL) - err(EXIT_FAILURE, NULL); - - if (strunvis((char *)ssp, arg) != sizeof(*ssp)) - errx(EXIT_FAILURE, "Decoding error"); - - (void)memcpy(&ss, ssp, sizeof(ss)); - have_ss = 1; -} - -void usage(void) { (void)fprintf(stderr, Index: src/usr.bin/login/login_pam.c diff -u src/usr.bin/login/login_pam.c:1.19 src/usr.bin/login/login_pam.c:1.20 --- src/usr.bin/login/login_pam.c:1.19 Mon Jul 21 10:19:23 2008 +++ src/usr.bin/login/login_pam.c Tue Dec 29 14:26:13 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: login_pam.c,v 1.19 2008/07/21 14:19:23 lukem Exp $ */ +/* $NetBSD: login_pam.c,v 1.20 2009/12/29 19:26:13 christos Exp $ */ /*- * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 @@ -39,7 +39,7 @@ #if 0 static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; #endif -__RCSID("$NetBSD: login_pam.c,v 1.19 2008/07/21 14:19:23 lukem Exp $"); +__RCSID("$NetBSD: login_pam.c,v 1.20 2009/12/29 19:26:13 christos Exp $"); #endif /* not lint */ /* @@ -78,19 +78,12 @@ #include <security/openpam.h> #include "pathnames.h" +#include "common.h" -void badlogin (char *); -static void update_db (int); -void getloginname (void); -int main (int, char *[]); -void motd (char *); -int rootterm (char *); -void sigint (int); -void sleepexit (int); -const char *stypeof (const char *); -void timedout (int); -void decode_ss (const char *); -void usage (void); +#if 0 +static int rootterm(char *); +#endif +static void usage(void) __attribute__((__noreturn__)); static struct pam_conv pamc = { openpam_ttyconv, NULL }; @@ -99,27 +92,15 @@ #define DEFAULT_BACKOFF 3 #define DEFAULT_RETRIES 10 -/* - * This bounds the time given to login. Not a define so it can - * be patched on machines where it's too small. - */ -u_int timeout = 300; - -struct passwd *pwd, pwres; -char pwbuf[1024]; -struct group grs, *grp; -char grbuf[1024]; -int failures, have_ss; -char term[64], *envinit[1], *hostname, *username, *tty, *nested; -struct timeval now; -struct sockaddr_storage ss; - -extern const char copyrightstr[]; +static struct passwd pwres; +static char pwbuf[1024]; +static struct group grs, *grp; +static char grbuf[1024]; +extern char **environ; int main(int argc, char *argv[]) { - extern char **environ; struct stat st; int ask, ch, cnt, fflag, pflag, quietlog, rootlogin; int auth_passed; @@ -185,10 +166,6 @@ err(EXIT_FAILURE, "-a option"); } decode_ss(optarg); -#ifdef notdef - (void)sockaddr_snprintf(optarg, - sizeof(struct sockaddr_storage), "%a", (void *)&ss); -#endif break; case 'f': fflag = 1; @@ -486,7 +463,7 @@ (void)printf("Warning: ttyaction failed.\n"); /* Nothing else left to fail -- really log in. */ - update_db(quietlog); + update_db(quietlog, rootlogin, fflag); if (nested == NULL && setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETLOGIN) != 0) { @@ -498,15 +475,6 @@ if (tty[sizeof("tty")-1] == 'd') syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); - /* If fflag is on, assume caller/authenticator has logged root login. */ - if (rootlogin && fflag == 0) { - if (hostname) - syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", - username, tty, hostname); - else - syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", - username, tty); - } /* * Establish groups @@ -687,165 +655,21 @@ err(EXIT_FAILURE, "%s", pwd->pw_shell); } -#define NBUFSIZ (MAXLOGNAME + 1) - - -void -getloginname(void) +static void +usage(void) { - int ch; - char *p; - static char nbuf[NBUFSIZ]; - - for (;;) { - (void)printf("login: "); - for (p = nbuf; (ch = getchar()) != '\n'; ) { - if (ch == EOF) { - badlogin(username); - exit(EXIT_FAILURE); - } - if (p < nbuf + (NBUFSIZ - 1)) - *p++ = ch; - } - if (p > nbuf) { - if (nbuf[0] == '-') - (void)fprintf(stderr, - "login names may not start with '-'.\n"); - else { - *p = '\0'; - username = nbuf; - break; - } - } - } + (void)fprintf(stderr, + "Usage: %s [-fp] [-a address] [-h hostname] [username]\n", + getprogname()); + exit(EXIT_FAILURE); } -int +#if 0 +static int rootterm(char *ttyn) { struct ttyent *t; return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); } - -jmp_buf motdinterrupt; - -void -motd(char *fname) -{ - int fd, nchars; - sig_t oldint; - char tbuf[8192]; - - if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0) - return; - oldint = signal(SIGINT, sigint); - if (setjmp(motdinterrupt) == 0) - while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) - (void)write(fileno(stdout), tbuf, nchars); - (void)signal(SIGINT, oldint); - (void)close(fd); -} - -/* ARGSUSED */ -void -sigint(int signo) -{ - - longjmp(motdinterrupt, 1); -} - -/* ARGSUSED */ -void -timedout(int signo) -{ - - (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); - exit(EXIT_FAILURE); -} - -static void -update_db(int quietlog) -{ - if (nested != NULL) { - if (hostname != NULL) - syslog(LOG_NOTICE, "%s to %s on tty %s from %s", - nested, pwd->pw_name, tty, hostname); - else - syslog(LOG_NOTICE, "%s to %s on tty %s", nested, - pwd->pw_name, tty); - - } - if (hostname != NULL && have_ss == 0) { - socklen_t len = sizeof(ss); - have_ss = getpeername(STDIN_FILENO, (struct sockaddr *)&ss, - &len) != -1; - } - (void)gettimeofday(&now, NULL); -} - -void -badlogin(char *name) -{ - - if (failures == 0) - return; - if (hostname) { - syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", - failures, failures > 1 ? "S" : "", hostname); - syslog(LOG_AUTHPRIV|LOG_NOTICE, - "%d LOGIN FAILURE%s FROM %s, %s", - failures, failures > 1 ? "S" : "", hostname, name); - } else { - syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", - failures, failures > 1 ? "S" : "", tty); - syslog(LOG_AUTHPRIV|LOG_NOTICE, - "%d LOGIN FAILURE%s ON %s, %s", - failures, failures > 1 ? "S" : "", tty, name); - } -} - -const char * -stypeof(const char *ttyid) -{ - struct ttyent *t; - - return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL); -} - -void -sleepexit(int eval) -{ - - (void)sleep(5); - exit(eval); -} - -void -decode_ss(const char *arg) -{ - struct sockaddr_storage *ssp; - size_t len = strlen(arg); - - if (len > sizeof(*ssp) * 4 + 1 || len < sizeof(*ssp)) - errx(EXIT_FAILURE, "Bad argument"); - - if ((ssp = malloc(len)) == NULL) - err(EXIT_FAILURE, NULL); - - if (strunvis((char *)ssp, arg) != sizeof(*ssp)) - errx(EXIT_FAILURE, "Decoding error"); - - (void)memcpy(&ss, ssp, sizeof(ss)); - have_ss = 1; - free(ssp); -} - -void -usage(void) -{ - (void)fprintf(stderr, - "Usage: %s [-fp] [-a address] [-h hostname] [username]\n", - getprogname()); - exit(EXIT_FAILURE); -} +#endif Added files: Index: src/usr.bin/login/common.c diff -u /dev/null src/usr.bin/login/common.c:1.1 --- /dev/null Tue Dec 29 14:26:13 2009 +++ src/usr.bin/login/common.c Tue Dec 29 14:26:13 2009 @@ -0,0 +1,393 @@ +/* $NetBSD: common.c,v 1.1 2009/12/29 19:26:13 christos Exp $ */ + +/*- + * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: common.c,v 1.1 2009/12/29 19:26:13 christos Exp $"); + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <syslog.h> +#include <fcntl.h> +#include <ttyent.h> +#include <setjmp.h> +#include <time.h> +#include <pwd.h> +#include <err.h> +#include <vis.h> +#include <util.h> + +#include "pathnames.h" +#include "common.h" + +#if defined(KERBEROS5) +#define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */ +#else +#define NBUFSIZ (MAXLOGNAME + 1) +#endif + +#ifdef SUPPORT_UTMP +#include <utmp.h> +static void doutmp(void); +static void dolastlog(int); +#endif +#ifdef SUPPORT_UTMPX +#include <utmpx.h> +static void doutmpx(void); +static void dolastlogx(int); +#endif + +/* + * This bounds the time given to login. Not a define so it can + * be patched on machines where it's too small. + */ +u_int timeout = 300; + +void decode_ss(const char *); +struct passwd *pwd; +int failures, have_ss; +char term[64], *envinit[1], *hostname, *username, *tty, *nested; +struct timeval now; +struct sockaddr_storage ss; + +void +getloginname(void) +{ + int ch; + char *p; + static char nbuf[NBUFSIZ]; + + for (;;) { + (void)printf("login: "); + for (p = nbuf; (ch = getchar()) != '\n'; ) { + if (ch == EOF) { + badlogin(username); + exit(EXIT_FAILURE); + } + if (p < nbuf + (NBUFSIZ - 1)) + *p++ = ch; + } + if (p > nbuf) { + if (nbuf[0] == '-') + (void)fprintf(stderr, + "login names may not start with '-'.\n"); + else { + *p = '\0'; + username = nbuf; + break; + } + } + } +} + +int +rootterm(char *ttyn) +{ + struct ttyent *t; + + return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); +} + +static jmp_buf motdinterrupt; + +void +motd(char *fname) +{ + int fd, nchars; + sig_t oldint; + char tbuf[8192]; + + if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0) + return; + oldint = signal(SIGINT, sigint); + if (setjmp(motdinterrupt) == 0) + while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) + (void)write(fileno(stdout), tbuf, nchars); + (void)signal(SIGINT, oldint); + (void)close(fd); +} + +/* ARGSUSED */ +void +sigint(int signo) +{ + + longjmp(motdinterrupt, 1); +} + +/* ARGSUSED */ +void +timedout(int signo) +{ + + (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); + exit(EXIT_FAILURE); +} + +void +update_db(int quietlog, int rootlogin, int fflag) +{ + struct sockaddr_storage ass; + char assbuf[1024]; + socklen_t alen; + const char *hname; + int remote; + + hname = (hostname == NULL) ? "?" : hostname; + if (getpeername(STDIN_FILENO, (struct sockaddr *)&ass, &alen) != -1) { + (void)sockaddr_snprintf(assbuf, + sizeof(assbuf), "%A (%a)", (void *)&ass); + if (have_ss) { + char ssbuf[1024]; + (void)sockaddr_snprintf(ssbuf, + sizeof(ssbuf), "%A (%a)", (void *)&ss); + if (memcmp(&ass, &ss, alen) != 0) + syslog(LOG_NOTICE, + "login %s on tty %s address mismatch " + "passed %s != actual %s", username, tty, + ssbuf, assbuf); + } else + ss = ass; + remote = 1; + } else if (have_ss) { + (void)sockaddr_snprintf(assbuf, + sizeof(assbuf), "%A (%a)", (void *)&ss); + remote = 1; + } else if (hostname) { + (void)snprintf(assbuf, sizeof(assbuf), "? ?"); + remote = 1; + } else + remote = 0; + + /* If fflag is on, assume caller/authenticator has logged root login. */ + if (rootlogin && fflag == 0) { + if (remote) + syslog(LOG_NOTICE, "ROOT LOGIN (%s) on tty %s from %s /" + " %s", username, tty, hname, assbuf); + else + syslog(LOG_NOTICE, "ROOT LOGIN (%s) on tty %s", + username, tty); + } else if (nested != NULL) { + if (remote) + syslog(LOG_NOTICE, "login %s to %s on tty %s from %s / " + "%s", nested, pwd->pw_name, tty, hname, assbuf); + else + syslog(LOG_NOTICE, "login %s to %s on tty %s", nested, + pwd->pw_name, tty); + } else { + if (remote) + syslog(LOG_NOTICE, "login %s on tty %s from %s / %s", + pwd->pw_name, tty, hname, assbuf); + else + syslog(LOG_NOTICE, "login %s on tty %s", + pwd->pw_name, tty); + } + (void)gettimeofday(&now, NULL); +#ifdef SUPPORT_UTMPX + doutmpx(); + dolastlogx(quietlog); + quietlog = 1; +#endif +#ifdef SUPPORT_UTMP + doutmp(); + dolastlog(quietlog); +#endif +} + +#ifdef SUPPORT_UTMPX +static void +doutmpx(void) +{ + struct utmpx utmpx; + char *t; + + memset((void *)&utmpx, 0, sizeof(utmpx)); + utmpx.ut_tv = now; + (void)strncpy(utmpx.ut_name, username, sizeof(utmpx.ut_name)); + if (hostname) { + (void)strncpy(utmpx.ut_host, hostname, sizeof(utmpx.ut_host)); + utmpx.ut_ss = ss; + } + (void)strncpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line)); + utmpx.ut_type = USER_PROCESS; + utmpx.ut_pid = getpid(); + t = tty + strlen(tty); + if (t - tty >= sizeof(utmpx.ut_id)) { + (void)strncpy(utmpx.ut_id, t - sizeof(utmpx.ut_id), + sizeof(utmpx.ut_id)); + } else { + (void)strncpy(utmpx.ut_id, tty, sizeof(utmpx.ut_id)); + } + if (pututxline(&utmpx) == NULL) + syslog(LOG_NOTICE, "Cannot update utmpx: %m"); + endutxent(); + if (updwtmpx(_PATH_WTMPX, &utmpx) != 0) + syslog(LOG_NOTICE, "Cannot update wtmpx: %m"); +} + +static void +dolastlogx(int quiet) +{ + struct lastlogx ll; + if (!quiet && getlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != NULL) { + time_t t = (time_t)ll.ll_tv.tv_sec; + (void)printf("Last login: %.24s ", ctime(&t)); + if (*ll.ll_host != '\0') + (void)printf("from %.*s ", + (int)sizeof(ll.ll_host), + ll.ll_host); + (void)printf("on %.*s\n", + (int)sizeof(ll.ll_line), + ll.ll_line); + } + ll.ll_tv = now; + (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); + if (hostname) + (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); + else + (void)memset(ll.ll_host, '\0', sizeof(ll.ll_host)); + if (have_ss) + ll.ll_ss = ss; + else + (void)memset(&ll.ll_ss, 0, sizeof(ll.ll_ss)); + if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0) + syslog(LOG_NOTICE, "Cannot update lastlogx: %m"); +} +#endif + +#ifdef SUPPORT_UTMP +static void +doutmp(void) +{ + struct utmp utmp; + + (void)memset((void *)&utmp, 0, sizeof(utmp)); + utmp.ut_time = now.tv_sec; + (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); + if (hostname) + (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); + (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); + login(&utmp); +} + +static void +dolastlog(int quiet) +{ + struct lastlog ll; + int fd; + + if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { + (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET); + if (!quiet) { + if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && + ll.ll_time != 0) { + (void)printf("Last login: %.24s ", + ctime(&ll.ll_time)); + if (*ll.ll_host != '\0') + (void)printf("from %.*s ", + (int)sizeof(ll.ll_host), + ll.ll_host); + (void)printf("on %.*s\n", + (int)sizeof(ll.ll_line), ll.ll_line); + } + (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), + SEEK_SET); + } + memset((void *)&ll, 0, sizeof(ll)); + ll.ll_time = now.tv_sec; + (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); + if (hostname) + (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); + (void)write(fd, (char *)&ll, sizeof(ll)); + (void)close(fd); + } +} +#endif + +void +badlogin(const char *name) +{ + + if (failures == 0) + return; + if (hostname) { + syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", + failures, failures > 1 ? "S" : "", hostname); + syslog(LOG_AUTHPRIV|LOG_NOTICE, + "%d LOGIN FAILURE%s FROM %s, %s", + failures, failures > 1 ? "S" : "", hostname, name); + } else { + syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", + failures, failures > 1 ? "S" : "", tty); + syslog(LOG_AUTHPRIV|LOG_NOTICE, + "%d LOGIN FAILURE%s ON %s, %s", + failures, failures > 1 ? "S" : "", tty, name); + } +} + +const char * +stypeof(const char *ttyid) +{ + struct ttyent *t; + + return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL); +} + +void +sleepexit(int eval) +{ + + (void)sleep(5); + exit(eval); +} + +void +decode_ss(const char *arg) +{ + struct sockaddr_storage *ssp; + size_t len = strlen(arg); + + if (len > sizeof(*ssp) * 4 + 1 || len < sizeof(*ssp)) + errx(EXIT_FAILURE, "Bad argument"); + + if ((ssp = malloc(len)) == NULL) + err(EXIT_FAILURE, NULL); + + if (strunvis((char *)ssp, arg) != sizeof(*ssp)) + errx(EXIT_FAILURE, "Decoding error"); + + (void)memcpy(&ss, ssp, sizeof(ss)); + free(ssp); + have_ss = 1; +} Index: src/usr.bin/login/common.h diff -u /dev/null src/usr.bin/login/common.h:1.1 --- /dev/null Tue Dec 29 14:26:13 2009 +++ src/usr.bin/login/common.h Tue Dec 29 14:26:13 2009 @@ -0,0 +1,53 @@ +/* $NetBSD: common.h,v 1.1 2009/12/29 19:26:13 christos Exp $ */ + +/*- + * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +__BEGIN_DECLS + +void badlogin(const char *); +void update_db(int, int, int); +void getloginname(void); +void motd(char *); +int rootterm(char *); +void sigint(int); +void sleepexit(int); +const char *stypeof(const char *); +void timedout(int); +void decode_ss(const char *); + +extern u_int timeout; +extern struct passwd *pwd; +extern int failures, have_ss; +extern char term[64], *envinit[1], *hostname, *username, *tty, *nested; +extern struct timeval now; +extern struct sockaddr_storage ss; +extern const char copyrightstr[]; + +__END_DECLS