123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385 |
- /*
- * CDE - Common Desktop Environment
- *
- * Copyright (c) 1993-2012, The Open Group. All rights reserved.
- *
- * These libraries and programs are free software; you can
- * redistribute them and/or modify them under the terms of the GNU
- * Lesser General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * These libraries and programs are distributed in the hope that
- * they will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with these libraries and programs; if not, write
- * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
- * Floor, Boston, MA 02110-1301 USA
- */
- /* $XConsortium: login.c /main/8 1996/10/29 13:49:30 drk $ */
- /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
- /* All Rights Reserved */
- /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
- /* The copyright notice above does not evidence any */
- /* actual or intended publication of such source code. */
- #ident "@(#)login.c 1.63 96/02/15 SMI" /* SVr4.0 1.43.6.26 */
- /*
- PROPRIETARY NOTICE(Combined)
- This source code is unpublished proprietary information
- constituting, or derived under license from AT&T's UNIX(r) System V.
- In addition, portions of such source code were derived from Berkeley
- 4.3 BSD under license from the Regents of the University of
- California.
- Copyright Notice
- Notice of copyright on this source code product does not indicate
- publication.
- (c) 1986, 1987, 1988, 1989, 1990, 1991, 1992 Sun Microsystems, Inc
- (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T.
- All rights reserved.
- *******************************************************************
- */
- /* Copyright (c) 1987, 1988 Microsoft Corporation */
- /* All Rights Reserved */
- /* This Module contains Proprietary Information of Microsoft */
- /* Corporation and should be treated as Confidential. */
- /*
- * Usage: login [ -d device ] [ name ] [ environment args ]
- *
- *
- */
- /*
- *
- * *** Header Files ***
- *
- *
- */
- #include <sys/types.h>
- #include <sys/param.h>
- #include <unistd.h> /* For logfile locking */
- #include <signal.h>
- #include <stdio.h>
- #include <sys/stat.h>
- #include <string.h>
- #include <deflt.h>
- #include <grp.h>
- #include <fcntl.h>
- #include <lastlog.h>
- #include <termio.h>
- #include <utmpx.h>
- #include <dirent.h>
- #include <stdlib.h>
- #include <wait.h>
- #include <errno.h>
- #include <ctype.h>
- #include <syslog.h>
- #include <ulimit.h>
- #include <libgen.h>
- #include <security/pam_appl.h>
- /*
- *
- * *** Defines, Macros, and String Constants ***
- *
- *
- */
- #define ISSUEFILE "/etc/issue" /* file to print before prompt */
- #define NOLOGIN "/etc/nologin" /* file to lock users out during shutdown */
- /*
- * These need to be defined for UTMP management.
- * If we add in the utility functions later, we
- * can remove them.
- */
- #define __UPDATE_ENTRY 1
- #define __LOGIN 2
- /*
- * Intervals to sleep after failed login
- */
- #ifndef SLEEPTIME
- #define SLEEPTIME 4 /* sleeptime before login incorrect msg */
- #endif
- static int Sleeptime = SLEEPTIME;
- /*
- * seconds login disabled after allowable number of unsuccessful attempts
- */
- #ifndef DISABLETIME
- #define DISABLETIME 20
- #endif
- #define MAXTRYS 5
- /*
- * Login logging support
- */
- #define LOGINLOG "/var/adm/loginlog" /* login log file */
- #define LNAME_SIZE 20 /* size of logged logname */
- #define TTYN_SIZE 15 /* size of logged tty name */
- #define TIME_SIZE 30 /* size of logged time string */
- #define ENT_SIZE (LNAME_SIZE + TTYN_SIZE + TIME_SIZE + 3)
- #define L_WAITTIME 5 /* waittime for log file to unlock */
- #define LOGTRYS 10 /* depth of 'try' logging */
- /*
- * String manipulation macros: SCPYN, EQN and ENVSTRNCAT
- */
- #define SCPYN(a, b) (void) strncpy(a, b, sizeof (a))
- #define EQN(a, b) (strncmp(a, b, sizeof (a)-1) == 0)
- #define ENVSTRNCAT(to, from) {int deflen; deflen = strlen(to); \
- (void) strncpy((to)+ deflen, (from), sizeof (to) - (1 + deflen)); }
- /*
- * Other macros
- */
- #define NMAX sizeof (utmp.ut_name)
- #define HMAX sizeof (utmp.ut_host)
- #define min(a, b) (((a) < (b)) ? (a) : (b))
- /*
- * Various useful files and string constants
- */
- #define SHELL "/usr/bin/sh"
- #define SHELL2 "/sbin/sh"
- #define SUBLOGIN "<!sublogin>"
- #define LASTLOG "/var/adm/lastlog"
- #define PROG_NAME "login"
- #define HUSHLOGIN ".hushlogin"
- /*
- * Array and Buffer sizes
- */
- #define PBUFSIZE 8 /* max significant characters in a password */
- #define MAXARGS 63
- #define MAXENV 1024
- #define MAXLINE 2048
- /*
- * Miscellaneous constants
- */
- #define ROOTUID 0
- #define ERROR 1
- #define OK 0
- #define LOG_ERROR 1
- #define DONT_LOG_ERROR 0
- #define TRUE 1
- #define FALSE 0
- /*
- * Counters for counting the number of failed login attempts
- */
- static int trys = 0;
- /*
- * Externs a plenty
- */
- extern int defopen(char *filename);
- extern int getsecretkey();
- /*
- * BSM hooks
- */
- extern int audit_login_save_flags(int rflag, int hflag);
- extern int audit_login_save_host(char *host);
- extern int audit_login_save_ttyn(char *ttyn);
- extern int audit_login_save_port(void);
- extern int audit_login_success(void);
- extern int audit_login_save_pw(struct passwd *pwd);
- extern int audit_login_bad_pw(void);
- extern int audit_login_maxtrys(void);
- extern int audit_login_not_console(void);
- extern int audit_login_bad_dialup(void);
- extern int audit_login_maxtrys(void);
- /*
- * utmp file variables
- */
- static struct utmpx utmp;
- /*
- * The current user name
- */
- static char user_name[64];
- static char minusnam[16] = "-";
- /*
- * locale environments to be passed to shells.
- */
- static char *localeenv[] = {
- "LANG",
- "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE",
- "LC_MONETARY", "LC_MESSAGES", "LC_ALL", 0};
- static int locale_envmatch(char *lenv, char *penv);
- /*
- * Environment variable support
- */
- static char shell[256] = { "SHELL=" };
- static char home[MAXPATHLEN] = { "HOME=" };
- static char term[64] = { "TERM=" };
- static char logname[30] = { "LOGNAME=" };
- static char timez[100] = { "TZ=" };
- static char hertz[10] = { "HZ=" };
- static char path[MAXPATHLEN] = { "PATH=" };
- static char *newenv[10+MAXARGS] =
- {home, path, logname, hertz, term, 0, 0};
- static char **envinit = newenv;
- static int basicenv;
- static char envblk[MAXENV];
- static char *zero = (char *)0;
- static char **envp;
- static char krb5ccname[256] = { "KRB5CCNAME=" };
- static char krb4ccname[256] = { "KRBTKFILE=" };
- #ifndef NO_MAIL
- static char mail[30] = { "MAIL=/var/mail/" };
- #endif
- extern char **environ;
- char inputline[MAXLINE];
- /*
- * Strings used to prompt the user.
- */
- static char loginmsg[] = "login: ";
- static char passwdmsg[] = "Password:";
- static char incorrectmsg[] = "Login incorrect\n";
- /*
- * Password file support
- */
- static struct passwd *pwd;
- static char remote_host[HMAX];
- /*
- * Illegal passwd entries.
- */
- static struct passwd nouser = { "", "no:password", ~ROOTUID };
- /*
- * Log file support
- */
- static char *log_entry[LOGTRYS];
- static int writelog = 0;
- static int lastlogok = 0;
- static struct lastlog ll;
- static int dosyslog = 0;
- /*
- * Default file toggles
- */
- static char *Pndefault = "/etc/default/login";
- static char *Altshell = NULL;
- static char *Console = NULL;
- static char *Passreq = NULL;
- #define DEFUMASK 022
- static mode_t Umask = DEFUMASK;
- static char *Def_tz = NULL;
- static char *tmp_tz = NULL;
- static char *Def_hertz = NULL;
- #define SET_FSIZ 2 /* ulimit() command arg */
- static long Def_ulimit = 0;
- #define MAX_TIMEOUT (15 * 60)
- #define DEF_TIMEOUT (5 * 60)
- static unsigned Def_timeout = DEF_TIMEOUT;
- static char *Def_path = NULL;
- static char *Def_supath = NULL;
- #define DEF_PATH "/usr/bin:" /* same as PATH */
- #define DEF_SUPATH "/usr/sbin:/usr/bin" /* same as ROOTPATH */
- /*
- * ttyprompt will point to the environment variable TTYPROMPT.
- * TTYPROMPT is set by ttymon if ttymon already wrote out the prompt.
- */
- static char *ttyprompt = NULL;
- static char *ttyn = NULL;
- static struct group *grpstr;
- static char *ttygrp = "tty";
- static char *progname = PROG_NAME;
- /*
- * Pass inherited environment. Used by telnetd in support of the telnet
- * ENVIRON option.
- */
- static int pflag;
- /*
- * Remote login support
- */
- static int hflag, rflag;
- static char rusername[NMAX+1], lusername[NMAX+1];
- static char terminal[MAXPATHLEN];
- /*
- * Pre-authentication flag support
- */
- static int fflag;
- static int login_conv(int num_msg, struct pam_message **msg,
- struct pam_response **response, void *appdata_ptr);
- static struct pam_conv pam_conv = {login_conv, NULL};
- static pam_handle_t *pamh; /* Authentication handle */
- /*
- * Function declarations
- */
- static void turn_on_logging(void);
- static void defaults(void);
- static void usage(void);
- static void process_rlogin(void);
- static void login_authenticate();
- static void setup_credentials(void);
- static void adjust_nice(void);
- static void update_utmp_entry(int sublogin);
- static void establish_user_environment(char **renvp);
- static void print_banner(void);
- static void display_last_login_time(void);
- static void exec_the_shell(void);
- static int process_chroot_logins(void);
- static int chdir_to_dir_root(void);
- static void chdir_to_dir_user(void);
- static void logindevperm(char *, uid_t, gid_t);
- static void dir_dev_acc(char *, uid_t, gid_t, mode_t, char *);
- static void check_log(void);
- static void validate_account();
- static void doremoteterm(char *term);
- static int get_options(int argc, char *argv[]);
- static void uppercaseterm(char *strp);
- static void getstr(char *buf, int cnt, char *err);
- static int legalenvvar(char *s);
- static void check_for_root_user(void);
- static void check_for_dueling_unix(char inputline[]);
- static void get_user_name(void);
- static void login_exit(int exit_code);
- static int logins_disabled(char *user_name);
- static void log_bad_attempts(void);
- /*
- * *** main ***
- *
- * The primary flow of control is directed in this routine.
- * Control moves in line from top to bottom calling subfunctions
- * which perform the bulk of the work. Many of these calls exit
- * when a fatal error is encountered and do not return to main.
- *
- *
- */
- void
- main(int argc, char *argv[], char **renvp)
- {
- int sublogin;
- /*
- * Set up Defaults and flags
- */
- defaults();
- /*
- * Set up default umask
- */
- if (Umask > ((mode_t) 0777))
- Umask = DEFUMASK;
- (void) umask(Umask);
- /*
- * Set up default timeouts and delays
- */
- if (Def_timeout > MAX_TIMEOUT)
- Def_timeout = MAX_TIMEOUT;
- if (Sleeptime < 0 || Sleeptime > 5)
- Sleeptime = SLEEPTIME;
- (void) alarm(Def_timeout);
- /*
- * Ignore SIGQUIT and SIGINT and set nice to 0
- */
- (void) signal(SIGQUIT, SIG_IGN);
- (void) signal(SIGINT, SIG_IGN);
- (void) nice(0);
- /*
- * Set flag to disable the pid check if you find that you are
- * a subsystem login.
- */
- sublogin = 0;
- if (*renvp && strcmp(*renvp, SUBLOGIN) == 0)
- sublogin = 1;
- /*
- * Parse Arguments
- */
- if (get_options(argc, argv) == -1) {
- usage();
- login_exit(1);
- }
- audit_login_save_flags(rflag, hflag);
- audit_login_save_host(remote_host);
- /*
- * if devicename is not passed as argument, call ttyname(0)
- */
- if (ttyn == NULL) {
- ttyn = ttyname(0);
- if (ttyn == NULL)
- ttyn = "/dev/???";
- }
- audit_login_save_ttyn(ttyn);
- audit_login_save_port();
- /*
- * Call pam_start to initiate a PAM authentication operation
- */
- if ((pam_start(progname, user_name, &pam_conv, &pamh))
- != PAM_SUCCESS)
- login_exit(1);
- if ((pam_set_item(pamh, PAM_TTY, ttyn)) != PAM_SUCCESS) {
- login_exit(1);
- }
- if ((pam_set_item(pamh, PAM_RHOST, remote_host)) != PAM_SUCCESS) {
- login_exit(1);
- }
- /*
- * Open the log file which contains a record of successful and failed
- * login attempts
- */
- turn_on_logging();
- /*
- * say "hi" to syslogd ..
- */
- openlog("login", 0, LOG_AUTH);
- /*
- * Do special processing for -r (rlogin) flag
- */
- if (rflag)
- process_rlogin();
- /*
- * validate user
- */
- /* we are already authenticated. fill in what we must, then continue */
- if (fflag) {
- if (pwd = getpwnam(user_name))
- audit_login_save_pw(pwd);
- else {
- audit_login_bad_pw();
- log_bad_attempts();
- login_exit(1);
- }
- } else {
- /*
- * Perform the primary login authentication activity.
- */
- login_authenticate();
- }
- /* change root login, then we exec another login and try again */
- if (process_chroot_logins() != OK)
- login_exit(1);
- /*
- * If root login and not on system console then call exit(2)
- */
- check_for_root_user();
- /*
- * Check to see if a shutdown is in progress, if it is and
- * we are not root then throw the user off the system
- */
- if (logins_disabled(user_name) == TRUE)
- login_exit(1);
- if (pwd->pw_uid == 0) {
- if (Def_supath != NULL)
- Def_path = Def_supath;
- else
- Def_path = DEF_SUPATH;
- }
- /*
- * Check account expiration and passwd aging
- */
- validate_account();
- /*
- * We only get here if we've been authenticated.
- */
- update_utmp_entry(sublogin);
- /*
- * Now we set up the environment for the new user, which includes
- * the users ulimit, nice value, ownership of this tty, uid, gid,
- * and environment variables.
- */
- if (Def_ulimit > 0L && ulimit(SET_FSIZ, Def_ulimit) < 0L)
- (void) printf("Could not set ULIMIT to %ld\n", Def_ulimit);
- /*
- * Set mode to r/w user & w group, owner to user and group to tty
- */
- (void) chmod(ttyn, S_IRUSR|S_IWUSR|S_IWGRP);
- if ((grpstr = getgrnam(ttygrp)) == NULL)
- (void) chown(ttyn, pwd->pw_uid, pwd->pw_gid);
- else
- (void) chown(ttyn, pwd->pw_uid, grpstr->gr_gid);
- logindevperm(ttyn, pwd->pw_uid, pwd->pw_gid);
- adjust_nice(); /* passwd file can specify nice value */
- /*
- * Record successful login and fork process that records logout.
- * We have to do this before setting credentials because we need
- * to be root in order do a setaudit() and an audit().
- */
- audit_login_success();
- setup_credentials(); /* Set uid/gid - exits on failure */
- pam_end(pamh, PAM_SUCCESS); /* Done using PAM */
- /*
- * Set up the basic environment for the exec. This includes
- * HOME, PATH, LOGNAME, SHELL, TERM, TZ, HZ, and MAIL.
- */
- chdir_to_dir_user();
- establish_user_environment(renvp);
- if (pwd->pw_uid == 0)
- if (remote_host[0] && dosyslog)
- syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
- ttyn, HMAX, remote_host);
- else if (dosyslog)
- syslog(LOG_NOTICE, "ROOT LOGIN %s", ttyn);
- closelog();
- (void) signal(SIGQUIT, SIG_DFL);
- (void) signal(SIGINT, SIG_DFL);
- /*
- * Display some useful information to the new user like the banner
- * and last login time if not a quiet login.
- */
- if (access(HUSHLOGIN, F_OK) != 0) {
- print_banner();
- display_last_login_time();
- }
- /*
- * Now fire off the shell of choice
- */
- exec_the_shell();
- /*
- * All done
- */
- login_exit(1);
- /* NOTREACHED */
- }
- /*
- * *** Utility functions ***
- */
- /*
- * donothing & catch - Signal catching functions
- */
- /*ARGSUSED*/
- static void
- donothing(int sig)
- {
- if (pamh)
- pam_end(pamh, PAM_ABORT);
- }
- #ifdef notdef
- static int intrupt;
- /*ARGSUSED*/
- static void
- catch(int sig)
- {
- ++intrupt;
- }
- #endif
- /*
- * *** Bad login logging support ***
- */
- /*
- * badlogin() - log to the log file 'trys'
- * unsuccessful attempts
- */
- static void
- badlogin(void)
- {
- int retval, count1, fildes;
- /*
- * Tries to open the log file. If succeed, lock it and write
- * in the failed attempts
- */
- if ((fildes = open(LOGINLOG, O_APPEND|O_WRONLY)) != -1) {
- (void) sigset(SIGALRM, donothing);
- (void) alarm(L_WAITTIME);
- retval = lockf(fildes, F_LOCK, 0L);
- (void) alarm(0);
- (void) sigset(SIGALRM, SIG_DFL);
- if (retval == 0) {
- for (count1 = 0; count1 < trys; count1++)
- (void) write(fildes, log_entry[count1],
- (unsigned) strlen(log_entry[count1]));
- (void) lockf(fildes, F_ULOCK, 0L);
- }
- (void) close(fildes);
- }
- }
- /*
- * log_bad_attempts - log each bad login attempt - called from
- * login_authenticate. Exits when the maximum attempt
- * count is exceeded.
- */
- static void
- log_bad_attempts(void)
- {
- time_t timenow;
- if (writelog == 1 && trys < LOGTRYS) {
- (void) time(&timenow);
- (void) strncat(log_entry[trys], user_name, LNAME_SIZE);
- (void) strncat(log_entry[trys], ":", (size_t) 1);
- (void) strncat(log_entry[trys], ttyn, TTYN_SIZE);
- (void) strncat(log_entry[trys], ":", (size_t) 1);
- (void) strncat(log_entry[trys], ctime(&timenow), TIME_SIZE);
- trys++;
- }
- }
- /*
- * turn_on_logging - if the logfile exist, turn on attempt logging and
- * initialize the string storage area
- */
- static void
- turn_on_logging(void)
- {
- struct stat dbuf;
- int i;
- if (stat(LOGINLOG, &dbuf) == 0) {
- writelog = 1;
- for (i = 0; i < LOGTRYS; i++) {
- if (!(log_entry[i] = malloc((size_t) ENT_SIZE))) {
- writelog = 0;
- break;
- }
- *log_entry[i] = '\0';
- }
- }
- }
- /*
- * login_conv():
- * This is the conv (conversation) function called from
- * a PAM authentication module to print error messages
- * or garner information from the user.
- */
- static int
- login_conv(int num_msg, struct pam_message **msg,
- struct pam_response **response, void *appdata_ptr)
- {
- struct pam_message *m;
- struct pam_response *r;
- char *temp;
- int k, i;
- if (num_msg <= 0)
- return (PAM_CONV_ERR);
- *response = calloc(num_msg, sizeof (struct pam_response));
- if (*response == NULL)
- return (PAM_BUF_ERR);
- k = num_msg;
- m = *msg;
- r = *response;
- while (k--) {
- switch (m->msg_style) {
- case PAM_PROMPT_ECHO_OFF:
- temp = getpass(m->msg);
- if (temp != NULL) {
- r->resp = strdup(temp);
- if (r->resp == NULL) {
- /* free responses */
- r = *response;
- for (i = 0; i < num_msg; i++, r++) {
- if (r->resp)
- free(r->resp);
- }
- free(*response);
- *response = NULL;
- return (PAM_BUF_ERR);
- }
- }
- m++;
- r++;
- break;
- case PAM_PROMPT_ECHO_ON:
- if (m->msg != NULL)
- (void) fputs(m->msg, stdout);
- r->resp = calloc(1, PAM_MAX_RESP_SIZE);
- if (r->resp == NULL) {
- /* free responses */
- r = *response;
- for (i = 0; i < num_msg; i++, r++) {
- if (r->resp)
- free(r->resp);
- }
- free(*response);
- *response = NULL;
- return (PAM_BUF_ERR);
- }
- if (fgets(r->resp, PAM_MAX_RESP_SIZE-1, stdin)) {
- int len;
- r->resp[PAM_MAX_RESP_SIZE-1] = NULL;
- len = strlen(r->resp);
- if (r->resp[len-1] == '\n')
- r->resp[len-1] = '\0';
- } else {
- login_exit(1);
- }
- m++;
- r++;
- break;
- case PAM_ERROR_MSG:
- if (m->msg != NULL) {
- (void) fputs(m->msg, stderr);
- (void) fputs("\n", stderr);
- }
- m++;
- r++;
- break;
- case PAM_TEXT_INFO:
- if (m->msg != NULL) {
- (void) fputs(m->msg, stdout);
- (void) fputs("\n", stdout);
- }
- m++;
- r++;
- break;
- default:
- break;
- }
- }
- return (PAM_SUCCESS);
- }
- /*
- * verify_passwd - Checks the users password
- * Returns: OK if password check successful,
- * ERROR if password check fails.
- */
- static int
- verify_passwd()
- {
- int flags;
- int error;
- char *user;
- /*
- * PAM authenticates the user for us.
- */
- error = pam_authenticate(pamh, 0);
- /* get the user_name from the pam handle */
- pam_get_item(pamh, PAM_USER, (void**)&user);
- SCPYN(user_name, user);
- check_for_dueling_unix(user_name);
- if (error != PAM_SUCCESS) {
- /* something bad has happended - bye bye */
- if (error == PAM_ABORT) {
- audit_login_bad_pw();
- log_bad_attempts();
- (void) sleep(DISABLETIME);
- (void) printf(incorrectmsg);
- login_exit(1);
- }
- return (error);
- }
- if ((pwd = getpwnam(user_name)) == NULL) {
- audit_login_bad_pw();
- log_bad_attempts();
- return (PAM_USER_UNKNOWN);
- }
- audit_login_save_pw(pwd);
- return (error);
- }
- /*
- * quotec - Called by getargs
- */
- static int
- quotec(void)
- {
- register int c, i, num;
- switch (c = getc(stdin)) {
- case 'n':
- c = '\n';
- break;
- case 'r':
- c = '\r';
- break;
- case 'v':
- c = '\013';
- break;
- case 'b':
- c = '\b';
- break;
- case 't':
- c = '\t';
- break;
- case 'f':
- c = '\f';
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- for (num = 0, i = 0; i < 3; i++) {
- num = num * 8 + (c - '0');
- if ((c = getc(stdin)) < '0' || c > '7')
- break;
- }
- (void) ungetc(c, stdin);
- c = num & 0377;
- break;
- default:
- break;
- }
- return (c);
- }
- /*
- * getargs - returns an input line. Exits if EOF encountered.
- */
- #define WHITESPACE 0
- #define ARGUMENT 1
- static char **
- getargs(char *in_line)
- {
- static char envbuf[MAXLINE];
- static char *args[MAXARGS];
- register char *ptr, **answer;
- register int c;
- int state;
- for (ptr = envbuf; ptr < &envbuf[sizeof (envbuf)]; /* cstyle */)
- *ptr++ = '\0';
- for (answer = args; answer < &args[MAXARGS]; /* cstyle */)
- *answer++ = (char *)NULL;
- for (ptr = envbuf, answer = &args[0], state = WHITESPACE;
- (c = getc(stdin)) != EOF; /* cstyle */) {
- *(in_line++) = c;
- switch (c) {
- case '\n':
- if (ptr == &envbuf[0])
- return ((char **)NULL);
- return (&args[0]);
- case ' ':
- case '\t':
- if (state == ARGUMENT) {
- *ptr++ = '\0';
- state = WHITESPACE;
- }
- break;
- case '\\':
- c = quotec();
- default:
- if (state == WHITESPACE) {
- *answer++ = ptr;
- state = ARGUMENT;
- }
- *ptr++ = c;
- }
- /*
- * If the buffer is full, force the next character to be read to
- * be a <newline>.
- */
- if (ptr == &envbuf[sizeof (envbuf)-1]) {
- (void) ungetc('\n', stdin);
- (void) putc('\n', stdout);
- }
- }
- /*
- * If we left loop because an EOF was received, exit immediately.
- */
- login_exit(0);
- /* NOTREACHED */
- }
- /*
- * get_user_name - Gets the user name either passed in, or from the
- * login: prompt.
- */
- static void
- get_user_name()
- {
- FILE *fp;
- int gotname = 0;
- if ((fp = fopen(ISSUEFILE, "r")) != NULL) {
- char *ptr, buffer[BUFSIZ];
- while ((ptr = fgets(buffer, sizeof (buffer),
- fp)) != NULL) {
- (void) fputs(ptr, stdout);
- }
- (void) fclose(fp);
- }
- /*
- * if TTYPROMPT is not set, use our own prompt
- * otherwise, use ttyprompt. We just set PAM_USER_PROMPT
- * and let the module do the prompting.
- */
- if ((ttyprompt == NULL) || (*ttyprompt == '\0'))
- (void) pam_set_item(pamh, PAM_USER_PROMPT, (void *)loginmsg);
- else
- (void) pam_set_item(pamh, PAM_USER_PROMPT, (void *)ttyprompt);
- envp = &zero; /* XXX: is this right? */
- }
- /*
- * Check_for_dueling_unix - Check to see if the another login is talking
- * to the line we've got open as a login port
- * Exits if we're talking to another unix system
- */
- static void
- check_for_dueling_unix(char *inputline)
- {
- if (EQN(loginmsg, inputline) || EQN(passwdmsg, inputline) ||
- EQN(incorrectmsg, inputline)) {
- (void) printf("Looking at a login line.\n");
- login_exit(8);
- }
- }
- /*
- * logins_disabled - if the file /etc/nologin exists and the user is not
- * root then do not permit them to login
- */
- static int
- logins_disabled(char *user_name)
- {
- FILE *nlfd;
- int c;
- if (!EQN("root", user_name) &&
- ((nlfd = fopen(NOLOGIN, "r")) != (FILE *)NULL)) {
- while ((c = getc(nlfd)) != EOF)
- putchar(c);
- (void) fflush(stdout);
- sleep(5);
- return (TRUE);
- }
- return (FALSE);
- }
- /*
- * check_for_root_user - Checks if we're getting a root login on the console
- * Exits if root login not on system console.
- *
- */
- static void
- check_for_root_user(void)
- {
- if (pwd->pw_uid == 0) {
- if ((Console != NULL) && (strcmp(ttyn, Console) != 0)) {
- audit_login_not_console();
- (void) printf("Not on system console\n");
- login_exit(10);
- }
- }
- }
- static char *illegal[] = {
- "SHELL=",
- "HOME=",
- "LOGNAME=",
- #ifndef NO_MAIL
- "MAIL=",
- #endif
- "CDPATH=",
- "IFS=",
- "PATH=",
- 0
- };
- /*
- * legalenvvar - Is it legal to insert this environmental variable?
- */
- static int
- legalenvvar(char *s)
- {
- register char **p;
- for (p = illegal; *p; p++)
- if (strncmp(s, *p, strlen(*p)) == 0)
- return (0);
- if (s[0] == 'L' && s[1] == 'D' && s[2] == '_')
- return (0);
- return (1);
- }
- /*
- * getstr - Get a string from standard input
- * Calls exit if read(2) fails.
- */
- static void
- getstr(char *buf, int cnt, char *err)
- {
- char c;
- do {
- if (read(0, &c, 1) != 1)
- login_exit(1);
- *buf++ = c;
- } while (cnt > 1 && c != 0);
- *buf = 0;
- err = err; /* For lint */
- }
- /*
- * uppercaseterm - if all input char are upper case
- * set the corresponding termio
- */
- static void
- uppercaseterm(char *strp)
- {
- int upper = 0;
- int lower = 0;
- char *sp;
- struct termio termio;
- for (sp = strp; *sp; sp++) {
- if (islower(*sp))
- lower++;
- else if (isupper(*sp))
- upper++;
- }
- if (upper > 0 && lower == 0) {
- (void) ioctl(0, TCGETA, &termio);
- termio.c_iflag |= IUCLC;
- termio.c_oflag |= OLCUC;
- termio.c_lflag |= XCASE;
- (void) ioctl(0, TCSETAW, &termio);
- for (sp = strp; *sp; sp++)
- if (*sp >= 'A' && *sp <= 'Z') *sp += ('a' - 'A');
- }
- }
- /*
- * defaults - read defaults
- */
- static void
- defaults(void)
- {
- extern int defcntl();
- register int flags;
- register char *ptr;
- if (defopen(Pndefault) == 0) {
- /*
- * ignore case
- */
- flags = defcntl(DC_GETFLAGS, 0);
- TURNOFF(flags, DC_CASE);
- defcntl(DC_SETFLAGS, flags);
- if ((Console = defread("CONSOLE=")) != NULL)
- Console = strdup(Console);
- if ((Altshell = defread("ALTSHELL=")) != NULL)
- Altshell = strdup(Altshell);
- if ((Passreq = defread("PASSREQ=")) != NULL)
- Passreq = strdup(Passreq);
- if ((Def_tz = defread("TIMEZONE=")) != NULL)
- Def_tz = strdup(Def_tz);
- if ((Def_hertz = defread("HZ=")) != NULL)
- Def_hertz = strdup(Def_hertz);
- if ((Def_path = defread("PATH=")) != NULL)
- Def_path = strdup(Def_path);
- if ((Def_supath = defread("SUPATH=")) != NULL)
- Def_supath = strdup(Def_supath);
- if ((ptr = defread("ULIMIT=")) != NULL)
- Def_ulimit = atol(ptr);
- if ((ptr = defread("TIMEOUT=")) != NULL)
- Def_timeout = (unsigned) atoi(ptr);
- if ((ptr = defread("UMASK=")) != NULL) {
- long long_umask;
- if (sscanf(ptr, "%lo", &long_umask) != 1)
- Umask = DEFUMASK;
- else
- Umask = (mode_t) long_umask;
- }
- if ((ptr = defread("SLEEPTIME=")) != NULL)
- Sleeptime = atoi(ptr);
- if ((ptr = defread("SYSLOG=")) != NULL)
- dosyslog = strcmp(ptr, "YES") == 0;
- (void) defopen((char *)NULL);
- }
- }
- /*
- * get_options(argc, argv)
- * - parse the cmd line.
- * - return 0 if successful, -1 if failed.
- * Calls login_exit() on misuse of -r and -h flags
- */
- static int
- get_options(int argc, char *argv[])
- {
- int c;
- int errflg = 0;
- while ((c = getopt(argc, argv, "f:h:r:pad:")) != -1) {
- switch (c) {
- case 'a':
- break;
- case 'd':
- /*
- * Must be root to pass in device name
- * otherwise we exit() as punishment for trying.
- */
- if (getuid() != 0 || geteuid() != 0) {
- login_exit(1); /* sigh */
- /*NOTREACHED*/
- }
- ttyn = optarg;
- break;
- case 'h':
- if (hflag || rflag) {
- (void) fprintf(stderr,
- "Only one of -r and -h allowed\n");
- login_exit(1);
- }
- hflag++;
- SCPYN(remote_host, optarg);
- if (argv[optind]) {
- if (argv[optind][0] != '-')
- SCPYN(terminal, argv[optind]);
- optind++;
- }
- progname = "telnet";
- break;
- case 'r':
- if (hflag || rflag) {
- (void) fprintf(stderr,
- "Only one of -r and -h allowed\n");
- login_exit(1);
- }
- rflag++;
- SCPYN(remote_host, optarg);
- progname = "rlogin";
- break;
- case 'p':
- pflag++;
- break;
- case 'f':
- /*
- * Must be root to bypass authentication
- * otherwise we exit() as punishment for trying.
- */
- if (getuid() != 0 || geteuid() != 0) {
- login_exit(1); /* sigh */
- /*NOTREACHED*/
- }
- /* save fflag user name for future use */
- SCPYN(user_name, optarg);
- fflag = 1;
- break;
- default:
- errflg++;
- break;
- } /* end switch */
- } /* end while */
- /*
- * get the prompt set by ttymon
- */
- ttyprompt = getenv("TTYPROMPT");
- if ((ttyprompt != NULL) && (*ttyprompt != '\0')) {
- /*
- * if ttyprompt is set, there should be data on
- * the stream already.
- */
- if ((envp = getargs(inputline)) != (char **)NULL) {
- uppercaseterm(*envp);
- /*
- * don't get name if name passed as argument.
- */
- SCPYN(user_name, *envp++);
- }
- } else if (optind < argc) {
- SCPYN(user_name, argv[optind]);
- (void) strcpy(inputline, user_name);
- (void) strcat(inputline, " \n");
- envp = &argv[optind+1];
- }
- if (errflg)
- return (-1);
- return (0);
- }
- /*
- * usage - Print usage message
- *
- */
- static void
- usage(void)
- {
- (void) fprintf(stderr,
- "Usage:\tlogin [-h|-r] [ name [ env-var ... ]]\n");
- }
- /*
- * *** Remote login support ***
- *
- */
- /*
- * doremoteterm - Sets the appropriate ioctls for a remote terminal
- */
- static char *speeds[] = {
- "0", "50", "75", "110", "134", "150", "200", "300",
- "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400",
- "57600", "76800", "115200", "153600", "230400", "307200", "460800"
- };
- #define NSPEEDS (sizeof (speeds) / sizeof (speeds[0]))
- static void
- doremoteterm(char *term)
- {
- struct termios tp;
- register char *cp = strchr(term, '/'), **cpp;
- char *speed;
- (void) ioctl(0, TCGETS, &tp);
- if (cp) {
- *cp++ = '\0';
- speed = cp;
- cp = strchr(speed, '/');
- if (cp)
- *cp++ = '\0';
- for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
- if (strcmp(*cpp, speed) == 0) {
- cfsetospeed(&tp, cpp-speeds);
- break;
- }
- }
- tp.c_lflag |= ECHO|ICANON;
- tp.c_iflag |= IGNPAR|ICRNL;
- (void) ioctl(0, TCSETS, &tp);
- }
- /*
- * Process_rlogin - Does the work that rlogin and telnet
- * need done
- */
- static void
- process_rlogin(void)
- {
- getstr(rusername, sizeof (rusername), "remuser");
- getstr(lusername, sizeof (lusername), "locuser");
- getstr(terminal, sizeof (terminal), "Terminal type");
- /* fflag has precedence over stuff passed by rlogind */
- if (fflag || getuid()) {
- pwd = &nouser;
- doremoteterm(terminal);
- return;
- } else {
- if (pam_set_item(pamh, PAM_USER, lusername) != PAM_SUCCESS)
- login_exit(1);
- pwd = getpwnam(lusername);
- if (pwd == NULL) {
- pwd = &nouser;
- doremoteterm(terminal);
- return;
- }
- }
- doremoteterm(terminal);
- /*
- * Update PAM on the user name
- */
- if (pam_set_item(pamh, PAM_USER, lusername) != PAM_SUCCESS)
- login_exit(1);
- if (pam_set_item(pamh, PAM_RUSER, rusername) != PAM_SUCCESS)
- login_exit(1);
- SCPYN(user_name, lusername);
- envp = &zero;
- lusername[0] = '\0';
- }
- /*
- * *** Account validation routines ***
- *
- */
- /*
- * validate_account - This is the PAM version of validate.
- */
- static void
- validate_account()
- {
- int error;
- int n;
- int flag;
- (void) alarm(0); /* give user time to come up with password */
- check_log();
- if ((Passreq != NULL) && (!strcasecmp("YES", Passreq)))
- flag = PAM_DISALLOW_NULL_AUTHTOK;
- else
- flag = 0;
- if ((error = pam_acct_mgmt(pamh, flag)) != PAM_SUCCESS) {
- if (error == PAM_AUTHTOKEN_REQD) {
- (void) printf("Choose a new password.\n");
- if ((error = pam_chauthtok(pamh, 0)) != PAM_SUCCESS) {
- if (dosyslog)
- syslog(LOG_CRIT,
- "change password failure: %s",
- pam_strerror(pamh, error));
- login_exit(1);
- }
- } else {
- (void) printf(incorrectmsg);
- if (dosyslog)
- syslog(LOG_CRIT,
- "login account failure: %s",
- pam_strerror(pamh, error));
- login_exit(1);
- }
- }
- }
- /*
- * Check_log - This is really a hack because PAM checks the log, but login
- * wants to know if the log is okay and PAM doesn't have
- * a module independent way of handing this info back.
- */
- static void
- check_log(void)
- {
- int fdl;
- long long offset;
- offset = (long long) pwd->pw_uid * (long long) sizeof (struct lastlog);
- if ((fdl = open(LASTLOG, O_RDWR|O_CREAT, 0444)) >= 0) {
- if (llseek(fdl, offset, SEEK_SET) == offset &&
- read(fdl, (char *)&ll, sizeof (ll)) == sizeof (ll) &&
- ll.ll_time != 0)
- lastlogok = 1;
- (void) close(fdl);
- }
- }
- /*
- * chdir_to_dir_root - Attempts to chdir us to the home directory.
- * defaults to "/" if it can't cd to the home
- * directory, and returns ERROR if it can't do that.
- */
- static int
- chdir_to_dir_root(void)
- {
- if (chdir(pwd->pw_dir) < 0) {
- if (chdir("/") < 0) {
- (void) printf("No directory!\n");
- return (ERROR);
- }
- }
- return (OK);
- }
- /*
- * chdir_to_dir_user - Now chdir after setuid/setgid have happened to
- * place us in the user's home directory just in
- * case it was protected and the first chdir failed.
- * No chdir errors should happen at this point because
- * all failures should have happened on the first
- * time around.
- */
- static void
- chdir_to_dir_user(void)
- {
- if (chdir(pwd->pw_dir) < 0) {
- if (chdir("/") < 0) {
- (void) printf("No directory!\n");
- /*
- * This probably won't work since we can't get to /.
- */
- if (remote_host[0] && dosyslog) {
- syslog(LOG_CRIT,
- "REPEATED LOGIN FAILURES ON %s FROM %.*s",
- ttyn, HMAX, remote_host);
- } else if (dosyslog) {
- syslog(LOG_CRIT,
- "REPEATED LOGIN FAILURES ON %s", ttyn);
- }
- closelog();
- (void) sleep(DISABLETIME);
- exit(1);
- } else {
- (void) printf("No directory! Logging in with home=/\n");
- pwd->pw_dir = "/";
- }
- }
- }
- /*
- * login_authenticate - Performs the main authentication work
- * 1. Prints the login prompt
- * 2. Requests and verifys the password
- * 3. Checks the port password
- */
- static void
- login_authenticate()
- {
- int cnt = 1;
- char *user;
- int err;
- do {
- /* if scheme broken, then nothing to do but quit */
- if (pam_get_item(pamh, PAM_USER, (void **)&user)
- != PAM_SUCCESS)
- exit(1);
- /*
- * only get name from utility if it is not already
- * supplied by pam_start or a pam_set_item.
- */
- if (!user || !user[0]) {
- /* use call back to get user name */
- get_user_name();
- }
- err = verify_passwd();
- if ((err == PAM_SUCCESS) && (chdir_to_dir_root() == OK)) {
- cnt = 0;
- break;
- }
- /* scheme has kept count of retries. time to bail */
- if (err == PAM_MAXTRIES)
- cnt = MAXTRYS;
- /* only sleep after first bad passwd */
- if (cnt)
- (void) sleep(Sleeptime);
- (void) printf(incorrectmsg);
- user_name[0] = '\0'; /* is this needed? */
- /* force name to be null in this case */
- if (pam_set_item(pamh, PAM_USER, NULL) != PAM_SUCCESS)
- login_exit(1);
- if (pam_set_item(pamh, PAM_RUSER, NULL) != PAM_SUCCESS)
- login_exit(1);
- } while (cnt++ < MAXTRYS);
- if (cnt >= MAXTRYS) {
- audit_login_maxtrys();
- /*
- * If logging is turned on, output the
- * string storage area to the log file,
- * and sleep for DISABLETIME
- * seconds before exiting.
- */
- if (writelog)
- badlogin();
- if (remote_host[0] && dosyslog) {
- syslog(LOG_CRIT,
- "REPEATED LOGIN FAILURES ON %s FROM %.*s",
- ttyn, HMAX, remote_host);
- } else if (dosyslog) {
- syslog(LOG_CRIT,
- "REPEATED LOGIN FAILURES ON %s", ttyn);
- }
- (void) sleep(DISABLETIME);
- exit(1);
- }
- }
- /*
- * *** Credential Related routines ***
- *
- */
- /*
- * setup_credentials - sets the group ID, initializes the groups
- * and sets up the secretkey.
- * Exits if a failure occurrs.
- */
- /*
- * setup_credentials - PAM does all the work for us on this one.
- */
- static void
- setup_credentials(void)
- {
- int error = 0;
- int flags;
- /* set the real (and effective) GID */
- if (setgid(pwd->pw_gid) == -1) {
- login_exit(1);
- }
- /*
- * Initialize the supplementary group access list.
- */
- if (!user_name)
- login_exit(1);
- if (initgroups(user_name, pwd->pw_gid) == -1) {
- login_exit(1);
- }
- /* XXX really should be after setgid */
- if ((error = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
- login_exit(error);
- }
- /* set the real (and effective) UID */
- if (setuid(pwd->pw_uid) == -1) {
- login_exit(1);
- }
- }
- /*
- *
- * *** Routines to get a new user set up and running ***
- *
- * Things to do when starting up a new user:
- * adjust_nice
- * update_utmp_entry
- * establish_user_environment
- * print_banner
- * display_last_login_time
- * exec_the_shell
- *
- */
- /*
- * adjust_nice - Set the nice (process priority) value if the
- * gecos value contains an appropriate value.
- */
- static void
- adjust_nice(void)
- {
- int pri, mflg, i;
- if (strncmp("pri=", pwd->pw_gecos, 4) == 0) {
- pri = 0;
- mflg = 0;
- i = 4;
- if (pwd->pw_gecos[i] == '-') {
- mflg++;
- i++;
- }
- while (pwd->pw_gecos[i] >= '0' && pwd->pw_gecos[i] <= '9')
- pri = (pri * 10) + pwd->pw_gecos[i++] - '0';
- if (mflg)
- pri = -pri;
- (void) nice(pri);
- }
- }
- /*
- * update_utmp_entry - Searchs for the correct utmp entry, making an
- * entry there if it finds one, otherwise exits.
- */
- static void
- update_utmp_entry(int sublogin)
- {
- char *user;
- int error;
- static char *errmsg = "No utmpx entry. "
- "You must exec \"login\" from the lowest level \"shell\".";
- int tmplen;
- struct utmpx *u = (struct utmpx *)0;
- struct utmpx utmp;
- char *ttyntail;
- /*
- * If we're not a sublogin then
- * we'll get an error back if our PID doesn't match the PID of the
- * entry we are updating, otherwise if its a sublogin the flags
- * field is set to 0, which means we just write a matching entry
- * (without checking the pid), or a new entry if an entry doesn't
- * exist.
- */
- if (error = pam_open_session(pamh, 0) != PAM_SUCCESS) {
- login_exit(1);
- }
- if ((error = pam_get_item(pamh, PAM_USER, (void **) &user))
- != PAM_SUCCESS) {
- login_exit(1);
- }
- (void) memset((void *)&utmp, 0, sizeof (utmp));
- (void) time(&utmp.ut_tv.tv_sec);
- utmp.ut_pid = getpid();
- if (rflag || hflag) {
- SCPYN(utmp.ut_host, remote_host);
- tmplen = strlen(remote_host) + 1;
- if (tmplen < sizeof (utmp.ut_host))
- utmp.ut_syslen = tmplen;
- else
- utmp.ut_syslen = sizeof (utmp.ut_host);
- } else {
- utmp.ut_syslen = 0;
- }
- SCPYN(utmp.ut_user, user);
- /* skip over "/dev/" */
- ttyntail = basename(ttyn);
- while ((u = getutxent()) != NULL) {
- if ((u->ut_type == INIT_PROCESS ||
- u->ut_type == LOGIN_PROCESS ||
- u->ut_type == USER_PROCESS) &&
- ((sublogin && strncmp(u->ut_line, ttyntail,
- sizeof (u->ut_line)) == 0) ||
- u->ut_pid == utmp.ut_pid)) {
- SCPYN(utmp.ut_line, (ttyn+sizeof ("/dev/")-1));
- (void) memcpy(utmp.ut_id, u->ut_id,
- sizeof (utmp.ut_id));
- utmp.ut_type = USER_PROCESS;
- pututxline(&utmp);
- break;
- }
- }
- endutxent();
- if (u == (struct utmpx *)NULL) {
- if (!sublogin) {
- /*
- * no utmp entry already setup
- * (init or rlogind/telnetd)
- */
- (void) puts(errmsg);
- login_exit(1);
- }
- } else {
- /* Now attempt to write out this entry to the wtmp file if */
- /* we were successful in getting it from the utmp file and */
- /* the wtmp file exists. */
- updwtmpx(WTMPX_FILE, &utmp);
- }
- }
- /*
- * process_chroot_logins - Chroots to the specified subdirectory and
- * re executes login.
- */
- static int
- process_chroot_logins(void)
- {
- /*
- * If the shell field starts with a '*', do a chroot to the home
- * directory and perform a new login.
- */
- if (*pwd->pw_shell == '*') {
- pam_end(pamh, PAM_SUCCESS); /* Done using PAM */
- if (chroot(pwd->pw_dir) < 0) {
- (void) printf("No Root Directory\n");
- return (ERROR);
- }
- /*
- * Set the environment flag <!sublogin> so that the next login
- * knows that it is a sublogin.
- */
- envinit[0] = SUBLOGIN;
- envinit[1] = (char *)NULL;
- (void) printf("Subsystem root: %s\n", pwd->pw_dir);
- (void) execle("/usr/bin/login", "login", (char *)0,
- &envinit[0]);
- (void) execle("/etc/login", "login", (char *)0, &envinit[0]);
- (void) printf("No /usr/bin/login or /etc/login on root\n");
- login_exit(1);
- }
- return (OK);
- }
- /*
- * establish_user_environment - Set up the new users environment
- */
- static void
- establish_user_environment(char **renvp)
- {
- int i, j, k, l_index, length;
- char *ptr;
- char *endptr;
- char **lenvp;
- char *krb5p;
- char *krb4p;
- lenvp = environ;
- while (*lenvp++)
- ;
- envinit = (char **) calloc(lenvp - environ + 10
- + MAXARGS, sizeof (char *));
- if (envinit == NULL) {
- (void) printf("Calloc failed - out of swap space.\n");
- login_exit(8);
- }
- memcpy(envinit, newenv, sizeof (newenv));
- /* Set up environment */
- if (rflag) {
- ENVSTRNCAT(term, terminal);
- } else if (hflag) {
- /* XXX: this causes an environment variable with the value */
- /* "" to be created later on, because terminal is "". */
- (void) strncpy(term, terminal, sizeof (term) - 1);
- } else {
- char *tp = getenv("TERM");
- if ((tp != NULL) && (*tp != '\0'))
- ENVSTRNCAT(term, tp);
- }
- ENVSTRNCAT(logname, pwd->pw_name);
- /*
- * There are three places to get timezone info. init.c sets
- * TZ if the file /etc/TIMEZONE contains a value for TZ.
- * login.c looks in the file /etc/default/login for a
- * variable called TIMEZONE being set. If TIMEZONE has a
- * value, TZ is set to that value; no environment variable
- * TIMEZONE is set, only TZ. If neither of these methods
- * work to set TZ, then the library routines will default
- * to using the file /usr/lib/locale/TZ/localtime.
- *
- * There is a priority set up here. If /etc/TIMEZONE has
- * a value for TZ, that value remains top priority. If the
- * file /etc/default/login has TIMEZONE set, that has second
- * highest priority not overriding the value of TZ in
- * /etc/TIMEZONE. The reason for this priority is that the
- * file /etc/TIMEZONE is supposed to be sourced by
- * /etc/profile. We are doing the "sourcing" prematurely in
- * init.c. Additionally, a login C shell doesn't source the
- * file /etc/profile thus not sourcing /etc/TIMEZONE thus not
- * allowing an administrator to globally set TZ for all users
- */
- if (Def_tz != NULL) /* Is there a TZ from defaults/login? */
- tmp_tz = Def_tz;
- if ((Def_tz = getenv("TZ")) != NULL) {
- ENVSTRNCAT(timez, Def_tz);
- } else if (tmp_tz != NULL) {
- Def_tz = tmp_tz;
- ENVSTRNCAT(timez, Def_tz);
- }
- if (Def_hertz == NULL)
- (void) sprintf(hertz + strlen(hertz), "%u", HZ);
- else
- ENVSTRNCAT(hertz, Def_hertz);
- if (Def_path == NULL)
- (void) strcat(path, DEF_PATH);
- else
- ENVSTRNCAT(path, Def_path);
- ENVSTRNCAT(home, pwd->pw_dir);
- /*
- * Find the end of the basic environment
- */
- for (basicenv = 0; envinit[basicenv] != NULL; basicenv++)
- ;
- /*
- * If TZ has a value, add it.
- */
- if (strcmp(timez, "TZ=") != 0)
- envinit[basicenv++] = timez;
- if (*pwd->pw_shell == '\0') {
- /*
- * If possible, use the primary default shell,
- * otherwise, use the secondary one.
- */
- if (access(SHELL, X_OK) == 0)
- pwd->pw_shell = SHELL;
- else
- pwd->pw_shell = SHELL2;
- } else if (Altshell != NULL && strcmp(Altshell, "YES") == 0) {
- envinit[basicenv++] = shell;
- ENVSTRNCAT(shell, pwd->pw_shell);
- }
- #ifndef NO_MAIL
- envinit[basicenv++] = mail;
- (void) strcat(mail, pwd->pw_name);
- #endif
- /*
- * Pick up locale environment variables, if any.
- */
- lenvp = renvp;
- while (*lenvp != NULL) {
- j = 0;
- while (localeenv[j] != 0) {
- /*
- * locale_envmatch() returns 1 if
- * *lenvp is localenev[j] and valid.
- */
- if (locale_envmatch(localeenv[j], *lenvp) == 1) {
- envinit[basicenv++] = *lenvp;
- break;
- }
- j++;
- }
- lenvp++;
- }
- /*
- * If '-p' flag, then try to pass on allowable environment
- * variables. Note that by processing this first, what is
- * passed on the final "login:" line may over-ride the invocation
- * values. XXX is this correct?
- */
- if (pflag) {
- for (lenvp = renvp; *lenvp; lenvp++) {
- if (!legalenvvar(*lenvp)) {
- continue;
- }
- /*
- * If this isn't 'xxx=yyy', skip it. XXX
- */
- if ((endptr = strchr(*lenvp, '=')) == NULL) {
- continue;
- }
- length = endptr + 1 - *lenvp;
- for (j = 0; j < basicenv; j++) {
- if (strncmp(envinit[j], *lenvp, length) == 0) {
- /*
- * Replace previously established value
- */
- envinit[j] = *lenvp;
- break;
- }
- }
- if (j == basicenv) {
- /*
- * It's a new definition, so add it at the end.
- */
- envinit[basicenv++] = *lenvp;
- }
- }
- }
- /*
- * Add in all the environment variables picked up from the
- * argument list to "login" or from the user response to the
- * "login" request.
- */
- for (j = 0, k = 0, l_index = 0, ptr = &envblk[0];
- *envp && j < (MAXARGS-1); j++, envp++) {
- /*
- * Scan each string provided. If it doesn't have the
- * format xxx=yyy, then add the string "Ln=" to the beginning.
- */
- if ((endptr = strchr(*envp, '=')) == NULL) {
- envinit[basicenv+k] = ptr;
- (void) sprintf(ptr, "L%d=%s", l_index, *envp);
- /*
- * Advance "ptr" to the beginning of the
- * next argument.
- */
- while (*ptr++)
- ;
- k++;
- l_index++;
- } else {
- if (!legalenvvar(*envp)) { /* this env var permited? */
- continue;
- } else {
- /*
- * Check to see whether this string replaces
- * any previously defined string
- */
- for (i = 0, length = endptr + 1 - *envp;
- i < basicenv + k; i++) {
- if (strncmp(*envp, envinit[i], length)
- == 0) {
- envinit[i] = *envp;
- break;
- }
- }
- /*
- * If it doesn't, place it at the end of
- * environment array.
- */
- if (i == basicenv+k) {
- envinit[basicenv+k] = *envp;
- k++;
- }
- }
- }
- } /* for (j = 0 ... ) */
- /*
- * Add DCE/Kerberos cred name, if any.
- * XXX - The module specific stuff should be removed from login
- * program eventually. This is better placed in DCE module.
- * So far, we haven't come up with a way to deal with these
- * environment variables.
- */
- krb5p = getenv("KRB5CCNAME");
- if ((krb5p != NULL) && (*krb5p != '\0')) {
- ENVSTRNCAT(krb5ccname, krb5p);
- envinit[basicenv++] = krb5ccname;
- }
- krb4p = getenv("KRBTKFILE");
- if ((krb4p != NULL) && (*krb4p != '\0')) {
- ENVSTRNCAT(krb4ccname, krb4p);
- envinit[basicenv++] = krb4ccname;
- }
- /*
- * Switch to the new environment.
- */
- environ = envinit;
- }
- /*
- * print_banner - Print the banner at start up
- * Do not turn on DOBANNER ifdef. This is not
- * relevant to SunOS.
- */
- static void
- print_banner(void)
- {
- #ifdef DOBANNER
- uname(&un);
- #if i386
- (void) printf("UNIX System V/386 Release %s\n%s\n"
- "Copyright (C) 1984, 1986, 1987, 1988 AT&T\n"
- "Copyright (C) 1987, 1988 Microsoft Corp.\nAll Rights Reserved\n",
- un.release, un.nodename);
- #elif sun
- (void) printf("SunOS Release %s Sun Microsystems %s\n%s\n"
- "Copyright (c) 1984, 1986, 1987, 1988 AT&T\n"
- "Copyright (c) 1988, 1989, 1990, 1991 Sun Microsystems\n"
- "All Rights Reserved\n",
- un.release, un.machine, un.nodename);
- #else
- (void) printf("UNIX System V Release %s AT&T %s\n%s\n"
- "Copyright (c) 1984, 1986, 1987, 1988 AT&T\nAll Rights Reserved\n",
- un.release, un.machine, un.nodename);
- #endif /* i386 */
- #endif /* DOBANNER */
- }
- /*
- * display_last_login_time - Advise the user the time and date
- * that this login-id was last used.
- */
- static void
- display_last_login_time(void)
- {
- if (lastlogok) {
- (void) printf("Last login: %.*s ", 24-5, ctime(&ll.ll_time));
- if (*ll.ll_host != '\0')
- (void) printf("from %.*s\n", sizeof (ll.ll_host),
- ll.ll_host);
- else
- (void) printf("on %.*s\n", sizeof (ll.ll_line),
- ll.ll_line);
- }
- }
- /*
- * exec_the_shell - invoke the specified shell or start up program
- */
- static void
- exec_the_shell(void)
- {
- char *endptr;
- int i;
- (void) strcat(minusnam, basename(pwd->pw_shell));
- /*
- * Exec the shell
- */
- (void) execl(pwd->pw_shell, minusnam, (char *)0);
- /*
- * pwd->pw_shell was not an executable object file, maybe it
- * is a shell proceedure or a command line with arguments.
- * If so, turn off the SHELL= environment variable.
- */
- for (i = 0; envinit[i] != NULL; ++i) {
- if ((envinit[i] == shell) &&
- ((endptr = strchr(shell, '=')) != NULL))
- (*++endptr) = '\0';
- }
- if (access(pwd->pw_shell, R_OK|X_OK) == 0) {
- (void) execl(SHELL, "sh", pwd->pw_shell, (char *)0);
- (void) execl(SHELL2, "sh", pwd->pw_shell, (char *)0);
- }
- (void) printf("No shell\n");
- }
- /*
- * login_exit - Call exit() and terminate.
- * This function is here for PAM so cleanup can
- * be done before the process exits.
- */
- static void
- login_exit(int exit_code)
- {
- if (pamh)
- pam_end(pamh, PAM_ABORT);
- exit(exit_code);
- /*NOTREACHED*/
- }
- /*
- * Check if lenv and penv matches or not.
- */
- static int
- locale_envmatch(char *lenv, char *penv)
- {
- while ((*lenv == *penv) && *lenv && *penv != '=') {
- lenv++;
- penv++;
- }
- /*
- * '/' is eliminated for security reason.
- */
- if (*lenv == '\0' && *penv == '=' && *(penv + 1) != '/')
- return (1);
- return (0);
- }
- /*
- * logindevperm - change owner/group/permissions of devices
- * list in /etc/logindevperm. (Code derived from set_fb_attrs()
- * in 4.x usr/src/bin/login.c and usr/src/etc/getty/main.c.)
- */
- #define MAX_LINELEN 256
- #define LOGINDEVPERM "/etc/logindevperm"
- #define DIRWILD "/*" /* directory wildcard */
- #define DIRWLDLEN 2 /* strlen(DIRWILD) */
- static void
- logindevperm(char *ttyn, uid_t uid, gid_t gid)
- {
- char *field_delims = " \t\n";
- char *permfile = LOGINDEVPERM;
- char line[MAX_LINELEN];
- char *console;
- char *mode_str;
- char *dev_list;
- char *device;
- char *ptr;
- int mode;
- FILE *fp;
- size_t l;
- int lineno;
- if ((fp = fopen(permfile, "r")) == NULL)
- return;
- lineno = 0;
- while (fgets(line, MAX_LINELEN, fp) != NULL) {
- lineno++;
- if ((ptr = strchr(line, '#')) != NULL)
- *ptr = '\0'; /* handle comments */
- if ((console = strtok(line, field_delims)) == NULL)
- continue; /* ignore blank lines */
- if (strcmp(console, ttyn) != 0)
- continue; /* not our tty, skip */
- mode_str = strtok((char *)NULL, field_delims);
- if (mode_str == NULL) {
- (void) fprintf(stderr,
- "%s: line %d, invalid entry -- %s\n", permfile,
- lineno, line);
- continue;
- }
- /* convert string to octal value */
- mode = strtol(mode_str, &ptr, 8);
- if (mode < 0 || mode > 0777 || *ptr != '\0') {
- (void) fprintf(stderr,
- "%s: line %d, invalid mode -- %s\n", permfile,
- lineno, mode_str);
- continue;
- }
- dev_list = strtok((char *)NULL, field_delims);
- if (dev_list == NULL) {
- (void) fprintf(stderr,
- "%s: line %d, %s -- empty device list\n",
- permfile, lineno, console);
- continue;
- }
- device = strtok(dev_list, ":");
- while (device != NULL) {
- l = strlen(device);
- ptr = &device[l - DIRWLDLEN];
- if ((l > DIRWLDLEN) && (strcmp(ptr, DIRWILD) == 0)) {
- *ptr = '\0'; /* chop off wildcard */
- dir_dev_acc(device, uid, gid, mode, permfile);
- } else {
- /*
- * change the owner/group/permission;
- * nonexistent devices are ignored
- */
- if (chown(device, uid, gid) == -1) {
- if (errno != ENOENT) {
- (void) fprintf(stderr, "%s: ",
- permfile);
- perror(device);
- }
- } else {
- if ((chmod(device, mode) == -1) &&
- (errno != ENOENT)) {
- (void) fprintf(stderr, "%s: ",
- permfile);
- perror(device);
- }
- }
- }
- device = strtok((char *)NULL, ":");
- }
- }
- (void) fclose(fp);
- }
- /*
- * Apply owner/group/perms to all files (except "." and "..")
- * in a directory.
- */
- static void
- dir_dev_acc(char *dir, uid_t uid, gid_t gid, mode_t mode, char *permfile)
- {
- DIR *dirp;
- struct dirent *direntp;
- char *name, path[MAX_LINELEN + MAXNAMELEN];
- dirp = opendir(dir);
- if (dirp == NULL)
- return;
- while ((direntp = readdir(dirp)) != NULL) {
- name = direntp->d_name;
- if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
- continue;
- (void) sprintf(path, "%s/%s", dir, name);
- if (chown(path, uid, gid) == -1) {
- if (errno != ENOENT) {
- (void) fprintf(stderr, "%s: ", permfile);
- perror(path);
- }
- } else {
- if ((chmod(path, mode) == -1) && (errno != ENOENT)) {
- (void) fprintf(stderr, "%s: ", permfile);
- perror(path);
- }
- }
- }
- (void) closedir(dirp);
- }
|