1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374 |
- /*
- * 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);
- }
- /*
- * *** 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)
- {
- 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];
- char *ptr, **answer;
- 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)
- {
- 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();
- int flags;
- 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;
- 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);
- }
|