login.c 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $XConsortium: login.c /main/8 1996/10/29 13:49:30 drk $ */
  24. /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  25. /* All Rights Reserved */
  26. /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
  27. /* The copyright notice above does not evidence any */
  28. /* actual or intended publication of such source code. */
  29. #ident "@(#)login.c 1.63 96/02/15 SMI" /* SVr4.0 1.43.6.26 */
  30. /*
  31. PROPRIETARY NOTICE(Combined)
  32. This source code is unpublished proprietary information
  33. constituting, or derived under license from AT&T's UNIX(r) System V.
  34. In addition, portions of such source code were derived from Berkeley
  35. 4.3 BSD under license from the Regents of the University of
  36. California.
  37. Copyright Notice
  38. Notice of copyright on this source code product does not indicate
  39. publication.
  40. (c) 1986, 1987, 1988, 1989, 1990, 1991, 1992 Sun Microsystems, Inc
  41. (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T.
  42. All rights reserved.
  43. *******************************************************************
  44. */
  45. /* Copyright (c) 1987, 1988 Microsoft Corporation */
  46. /* All Rights Reserved */
  47. /* This Module contains Proprietary Information of Microsoft */
  48. /* Corporation and should be treated as Confidential. */
  49. /*
  50. * Usage: login [ -d device ] [ name ] [ environment args ]
  51. *
  52. *
  53. */
  54. /*
  55. *
  56. * *** Header Files ***
  57. *
  58. *
  59. */
  60. #include <sys/types.h>
  61. #include <sys/param.h>
  62. #include <unistd.h> /* For logfile locking */
  63. #include <signal.h>
  64. #include <stdio.h>
  65. #include <sys/stat.h>
  66. #include <string.h>
  67. #include <deflt.h>
  68. #include <grp.h>
  69. #include <fcntl.h>
  70. #include <lastlog.h>
  71. #include <termio.h>
  72. #include <utmpx.h>
  73. #include <dirent.h>
  74. #include <stdlib.h>
  75. #include <wait.h>
  76. #include <errno.h>
  77. #include <ctype.h>
  78. #include <syslog.h>
  79. #include <ulimit.h>
  80. #include <libgen.h>
  81. #include <security/pam_appl.h>
  82. /*
  83. *
  84. * *** Defines, Macros, and String Constants ***
  85. *
  86. *
  87. */
  88. #define ISSUEFILE "/etc/issue" /* file to print before prompt */
  89. #define NOLOGIN "/etc/nologin" /* file to lock users out during shutdown */
  90. /*
  91. * These need to be defined for UTMP management.
  92. * If we add in the utility functions later, we
  93. * can remove them.
  94. */
  95. #define __UPDATE_ENTRY 1
  96. #define __LOGIN 2
  97. /*
  98. * Intervals to sleep after failed login
  99. */
  100. #ifndef SLEEPTIME
  101. #define SLEEPTIME 4 /* sleeptime before login incorrect msg */
  102. #endif
  103. static int Sleeptime = SLEEPTIME;
  104. /*
  105. * seconds login disabled after allowable number of unsuccessful attempts
  106. */
  107. #ifndef DISABLETIME
  108. #define DISABLETIME 20
  109. #endif
  110. #define MAXTRYS 5
  111. /*
  112. * Login logging support
  113. */
  114. #define LOGINLOG "/var/adm/loginlog" /* login log file */
  115. #define LNAME_SIZE 20 /* size of logged logname */
  116. #define TTYN_SIZE 15 /* size of logged tty name */
  117. #define TIME_SIZE 30 /* size of logged time string */
  118. #define ENT_SIZE (LNAME_SIZE + TTYN_SIZE + TIME_SIZE + 3)
  119. #define L_WAITTIME 5 /* waittime for log file to unlock */
  120. #define LOGTRYS 10 /* depth of 'try' logging */
  121. /*
  122. * String manipulation macros: SCPYN, EQN and ENVSTRNCAT
  123. */
  124. #define SCPYN(a, b) (void) strncpy(a, b, sizeof (a))
  125. #define EQN(a, b) (strncmp(a, b, sizeof (a)-1) == 0)
  126. #define ENVSTRNCAT(to, from) {int deflen; deflen = strlen(to); \
  127. (void) strncpy((to)+ deflen, (from), sizeof (to) - (1 + deflen)); }
  128. /*
  129. * Other macros
  130. */
  131. #define NMAX sizeof (utmp.ut_name)
  132. #define HMAX sizeof (utmp.ut_host)
  133. #define min(a, b) (((a) < (b)) ? (a) : (b))
  134. /*
  135. * Various useful files and string constants
  136. */
  137. #define SHELL "/usr/bin/sh"
  138. #define SHELL2 "/sbin/sh"
  139. #define SUBLOGIN "<!sublogin>"
  140. #define LASTLOG "/var/adm/lastlog"
  141. #define PROG_NAME "login"
  142. #define HUSHLOGIN ".hushlogin"
  143. /*
  144. * Array and Buffer sizes
  145. */
  146. #define PBUFSIZE 8 /* max significant characters in a password */
  147. #define MAXARGS 63
  148. #define MAXENV 1024
  149. #define MAXLINE 2048
  150. /*
  151. * Miscellaneous constants
  152. */
  153. #define ROOTUID 0
  154. #define ERROR 1
  155. #define OK 0
  156. #define LOG_ERROR 1
  157. #define DONT_LOG_ERROR 0
  158. #define TRUE 1
  159. #define FALSE 0
  160. /*
  161. * Counters for counting the number of failed login attempts
  162. */
  163. static int trys = 0;
  164. /*
  165. * Externs a plenty
  166. */
  167. extern int defopen(char *filename);
  168. extern int getsecretkey();
  169. /*
  170. * BSM hooks
  171. */
  172. extern int audit_login_save_flags(int rflag, int hflag);
  173. extern int audit_login_save_host(char *host);
  174. extern int audit_login_save_ttyn(char *ttyn);
  175. extern int audit_login_save_port(void);
  176. extern int audit_login_success(void);
  177. extern int audit_login_save_pw(struct passwd *pwd);
  178. extern int audit_login_bad_pw(void);
  179. extern int audit_login_maxtrys(void);
  180. extern int audit_login_not_console(void);
  181. extern int audit_login_bad_dialup(void);
  182. extern int audit_login_maxtrys(void);
  183. /*
  184. * utmp file variables
  185. */
  186. static struct utmpx utmp;
  187. /*
  188. * The current user name
  189. */
  190. static char user_name[64];
  191. static char minusnam[16] = "-";
  192. /*
  193. * locale environments to be passed to shells.
  194. */
  195. static char *localeenv[] = {
  196. "LANG",
  197. "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE",
  198. "LC_MONETARY", "LC_MESSAGES", "LC_ALL", 0};
  199. static int locale_envmatch(char *lenv, char *penv);
  200. /*
  201. * Environment variable support
  202. */
  203. static char shell[256] = { "SHELL=" };
  204. static char home[MAXPATHLEN] = { "HOME=" };
  205. static char term[64] = { "TERM=" };
  206. static char logname[30] = { "LOGNAME=" };
  207. static char timez[100] = { "TZ=" };
  208. static char hertz[10] = { "HZ=" };
  209. static char path[MAXPATHLEN] = { "PATH=" };
  210. static char *newenv[10+MAXARGS] =
  211. {home, path, logname, hertz, term, 0, 0};
  212. static char **envinit = newenv;
  213. static int basicenv;
  214. static char envblk[MAXENV];
  215. static char *zero = (char *)0;
  216. static char **envp;
  217. static char krb5ccname[256] = { "KRB5CCNAME=" };
  218. static char krb4ccname[256] = { "KRBTKFILE=" };
  219. #ifndef NO_MAIL
  220. static char mail[30] = { "MAIL=/var/mail/" };
  221. #endif
  222. extern char **environ;
  223. char inputline[MAXLINE];
  224. /*
  225. * Strings used to prompt the user.
  226. */
  227. static char loginmsg[] = "login: ";
  228. static char passwdmsg[] = "Password:";
  229. static char incorrectmsg[] = "Login incorrect\n";
  230. /*
  231. * Password file support
  232. */
  233. static struct passwd *pwd;
  234. static char remote_host[HMAX];
  235. /*
  236. * Illegal passwd entries.
  237. */
  238. static struct passwd nouser = { "", "no:password", ~ROOTUID };
  239. /*
  240. * Log file support
  241. */
  242. static char *log_entry[LOGTRYS];
  243. static int writelog = 0;
  244. static int lastlogok = 0;
  245. static struct lastlog ll;
  246. static int dosyslog = 0;
  247. /*
  248. * Default file toggles
  249. */
  250. static char *Pndefault = "/etc/default/login";
  251. static char *Altshell = NULL;
  252. static char *Console = NULL;
  253. static char *Passreq = NULL;
  254. #define DEFUMASK 022
  255. static mode_t Umask = DEFUMASK;
  256. static char *Def_tz = NULL;
  257. static char *tmp_tz = NULL;
  258. static char *Def_hertz = NULL;
  259. #define SET_FSIZ 2 /* ulimit() command arg */
  260. static long Def_ulimit = 0;
  261. #define MAX_TIMEOUT (15 * 60)
  262. #define DEF_TIMEOUT (5 * 60)
  263. static unsigned Def_timeout = DEF_TIMEOUT;
  264. static char *Def_path = NULL;
  265. static char *Def_supath = NULL;
  266. #define DEF_PATH "/usr/bin:" /* same as PATH */
  267. #define DEF_SUPATH "/usr/sbin:/usr/bin" /* same as ROOTPATH */
  268. /*
  269. * ttyprompt will point to the environment variable TTYPROMPT.
  270. * TTYPROMPT is set by ttymon if ttymon already wrote out the prompt.
  271. */
  272. static char *ttyprompt = NULL;
  273. static char *ttyn = NULL;
  274. static struct group *grpstr;
  275. static char *ttygrp = "tty";
  276. static char *progname = PROG_NAME;
  277. /*
  278. * Pass inherited environment. Used by telnetd in support of the telnet
  279. * ENVIRON option.
  280. */
  281. static int pflag;
  282. /*
  283. * Remote login support
  284. */
  285. static int hflag, rflag;
  286. static char rusername[NMAX+1], lusername[NMAX+1];
  287. static char terminal[MAXPATHLEN];
  288. /*
  289. * Pre-authentication flag support
  290. */
  291. static int fflag;
  292. static int login_conv(int num_msg, struct pam_message **msg,
  293. struct pam_response **response, void *appdata_ptr);
  294. static struct pam_conv pam_conv = {login_conv, NULL};
  295. static pam_handle_t *pamh; /* Authentication handle */
  296. /*
  297. * Function declarations
  298. */
  299. static void turn_on_logging(void);
  300. static void defaults(void);
  301. static void usage(void);
  302. static void process_rlogin(void);
  303. static void login_authenticate();
  304. static void setup_credentials(void);
  305. static void adjust_nice(void);
  306. static void update_utmp_entry(int sublogin);
  307. static void establish_user_environment(char **renvp);
  308. static void print_banner(void);
  309. static void display_last_login_time(void);
  310. static void exec_the_shell(void);
  311. static int process_chroot_logins(void);
  312. static int chdir_to_dir_root(void);
  313. static void chdir_to_dir_user(void);
  314. static void logindevperm(char *, uid_t, gid_t);
  315. static void dir_dev_acc(char *, uid_t, gid_t, mode_t, char *);
  316. static void check_log(void);
  317. static void validate_account();
  318. static void doremoteterm(char *term);
  319. static int get_options(int argc, char *argv[]);
  320. static void uppercaseterm(char *strp);
  321. static void getstr(char *buf, int cnt, char *err);
  322. static int legalenvvar(char *s);
  323. static void check_for_root_user(void);
  324. static void check_for_dueling_unix(char inputline[]);
  325. static void get_user_name(void);
  326. static void login_exit(int exit_code);
  327. static int logins_disabled(char *user_name);
  328. static void log_bad_attempts(void);
  329. /*
  330. * *** main ***
  331. *
  332. * The primary flow of control is directed in this routine.
  333. * Control moves in line from top to bottom calling subfunctions
  334. * which perform the bulk of the work. Many of these calls exit
  335. * when a fatal error is encountered and do not return to main.
  336. *
  337. *
  338. */
  339. void
  340. main(int argc, char *argv[], char **renvp)
  341. {
  342. int sublogin;
  343. /*
  344. * Set up Defaults and flags
  345. */
  346. defaults();
  347. /*
  348. * Set up default umask
  349. */
  350. if (Umask > ((mode_t) 0777))
  351. Umask = DEFUMASK;
  352. (void) umask(Umask);
  353. /*
  354. * Set up default timeouts and delays
  355. */
  356. if (Def_timeout > MAX_TIMEOUT)
  357. Def_timeout = MAX_TIMEOUT;
  358. if (Sleeptime < 0 || Sleeptime > 5)
  359. Sleeptime = SLEEPTIME;
  360. (void) alarm(Def_timeout);
  361. /*
  362. * Ignore SIGQUIT and SIGINT and set nice to 0
  363. */
  364. (void) signal(SIGQUIT, SIG_IGN);
  365. (void) signal(SIGINT, SIG_IGN);
  366. (void) nice(0);
  367. /*
  368. * Set flag to disable the pid check if you find that you are
  369. * a subsystem login.
  370. */
  371. sublogin = 0;
  372. if (*renvp && strcmp(*renvp, SUBLOGIN) == 0)
  373. sublogin = 1;
  374. /*
  375. * Parse Arguments
  376. */
  377. if (get_options(argc, argv) == -1) {
  378. usage();
  379. login_exit(1);
  380. }
  381. audit_login_save_flags(rflag, hflag);
  382. audit_login_save_host(remote_host);
  383. /*
  384. * if devicename is not passed as argument, call ttyname(0)
  385. */
  386. if (ttyn == NULL) {
  387. ttyn = ttyname(0);
  388. if (ttyn == NULL)
  389. ttyn = "/dev/???";
  390. }
  391. audit_login_save_ttyn(ttyn);
  392. audit_login_save_port();
  393. /*
  394. * Call pam_start to initiate a PAM authentication operation
  395. */
  396. if ((pam_start(progname, user_name, &pam_conv, &pamh))
  397. != PAM_SUCCESS)
  398. login_exit(1);
  399. if ((pam_set_item(pamh, PAM_TTY, ttyn)) != PAM_SUCCESS) {
  400. login_exit(1);
  401. }
  402. if ((pam_set_item(pamh, PAM_RHOST, remote_host)) != PAM_SUCCESS) {
  403. login_exit(1);
  404. }
  405. /*
  406. * Open the log file which contains a record of successful and failed
  407. * login attempts
  408. */
  409. turn_on_logging();
  410. /*
  411. * say "hi" to syslogd ..
  412. */
  413. openlog("login", 0, LOG_AUTH);
  414. /*
  415. * Do special processing for -r (rlogin) flag
  416. */
  417. if (rflag)
  418. process_rlogin();
  419. /*
  420. * validate user
  421. */
  422. /* we are already authenticated. fill in what we must, then continue */
  423. if (fflag) {
  424. if (pwd = getpwnam(user_name))
  425. audit_login_save_pw(pwd);
  426. else {
  427. audit_login_bad_pw();
  428. log_bad_attempts();
  429. login_exit(1);
  430. }
  431. } else {
  432. /*
  433. * Perform the primary login authentication activity.
  434. */
  435. login_authenticate();
  436. }
  437. /* change root login, then we exec another login and try again */
  438. if (process_chroot_logins() != OK)
  439. login_exit(1);
  440. /*
  441. * If root login and not on system console then call exit(2)
  442. */
  443. check_for_root_user();
  444. /*
  445. * Check to see if a shutdown is in progress, if it is and
  446. * we are not root then throw the user off the system
  447. */
  448. if (logins_disabled(user_name) == TRUE)
  449. login_exit(1);
  450. if (pwd->pw_uid == 0) {
  451. if (Def_supath != NULL)
  452. Def_path = Def_supath;
  453. else
  454. Def_path = DEF_SUPATH;
  455. }
  456. /*
  457. * Check account expiration and passwd aging
  458. */
  459. validate_account();
  460. /*
  461. * We only get here if we've been authenticated.
  462. */
  463. update_utmp_entry(sublogin);
  464. /*
  465. * Now we set up the environment for the new user, which includes
  466. * the users ulimit, nice value, ownership of this tty, uid, gid,
  467. * and environment variables.
  468. */
  469. if (Def_ulimit > 0L && ulimit(SET_FSIZ, Def_ulimit) < 0L)
  470. (void) printf("Could not set ULIMIT to %ld\n", Def_ulimit);
  471. /*
  472. * Set mode to r/w user & w group, owner to user and group to tty
  473. */
  474. (void) chmod(ttyn, S_IRUSR|S_IWUSR|S_IWGRP);
  475. if ((grpstr = getgrnam(ttygrp)) == NULL)
  476. (void) chown(ttyn, pwd->pw_uid, pwd->pw_gid);
  477. else
  478. (void) chown(ttyn, pwd->pw_uid, grpstr->gr_gid);
  479. logindevperm(ttyn, pwd->pw_uid, pwd->pw_gid);
  480. adjust_nice(); /* passwd file can specify nice value */
  481. /*
  482. * Record successful login and fork process that records logout.
  483. * We have to do this before setting credentials because we need
  484. * to be root in order do a setaudit() and an audit().
  485. */
  486. audit_login_success();
  487. setup_credentials(); /* Set uid/gid - exits on failure */
  488. pam_end(pamh, PAM_SUCCESS); /* Done using PAM */
  489. /*
  490. * Set up the basic environment for the exec. This includes
  491. * HOME, PATH, LOGNAME, SHELL, TERM, TZ, HZ, and MAIL.
  492. */
  493. chdir_to_dir_user();
  494. establish_user_environment(renvp);
  495. if (pwd->pw_uid == 0)
  496. if (remote_host[0] && dosyslog)
  497. syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
  498. ttyn, HMAX, remote_host);
  499. else if (dosyslog)
  500. syslog(LOG_NOTICE, "ROOT LOGIN %s", ttyn);
  501. closelog();
  502. (void) signal(SIGQUIT, SIG_DFL);
  503. (void) signal(SIGINT, SIG_DFL);
  504. /*
  505. * Display some useful information to the new user like the banner
  506. * and last login time if not a quiet login.
  507. */
  508. if (access(HUSHLOGIN, F_OK) != 0) {
  509. print_banner();
  510. display_last_login_time();
  511. }
  512. /*
  513. * Now fire off the shell of choice
  514. */
  515. exec_the_shell();
  516. /*
  517. * All done
  518. */
  519. login_exit(1);
  520. /* NOTREACHED */
  521. }
  522. /*
  523. * *** Utility functions ***
  524. */
  525. /*
  526. * donothing & catch - Signal catching functions
  527. */
  528. /*ARGSUSED*/
  529. static void
  530. donothing(int sig)
  531. {
  532. if (pamh)
  533. pam_end(pamh, PAM_ABORT);
  534. }
  535. /*
  536. * *** Bad login logging support ***
  537. */
  538. /*
  539. * badlogin() - log to the log file 'trys'
  540. * unsuccessful attempts
  541. */
  542. static void
  543. badlogin(void)
  544. {
  545. int retval, count1, fildes;
  546. /*
  547. * Tries to open the log file. If succeed, lock it and write
  548. * in the failed attempts
  549. */
  550. if ((fildes = open(LOGINLOG, O_APPEND|O_WRONLY)) != -1) {
  551. (void) sigset(SIGALRM, donothing);
  552. (void) alarm(L_WAITTIME);
  553. retval = lockf(fildes, F_LOCK, 0L);
  554. (void) alarm(0);
  555. (void) sigset(SIGALRM, SIG_DFL);
  556. if (retval == 0) {
  557. for (count1 = 0; count1 < trys; count1++)
  558. (void) write(fildes, log_entry[count1],
  559. (unsigned) strlen(log_entry[count1]));
  560. (void) lockf(fildes, F_ULOCK, 0L);
  561. }
  562. (void) close(fildes);
  563. }
  564. }
  565. /*
  566. * log_bad_attempts - log each bad login attempt - called from
  567. * login_authenticate. Exits when the maximum attempt
  568. * count is exceeded.
  569. */
  570. static void
  571. log_bad_attempts(void)
  572. {
  573. time_t timenow;
  574. if (writelog == 1 && trys < LOGTRYS) {
  575. (void) time(&timenow);
  576. (void) strncat(log_entry[trys], user_name, LNAME_SIZE);
  577. (void) strncat(log_entry[trys], ":", (size_t) 1);
  578. (void) strncat(log_entry[trys], ttyn, TTYN_SIZE);
  579. (void) strncat(log_entry[trys], ":", (size_t) 1);
  580. (void) strncat(log_entry[trys], ctime(&timenow), TIME_SIZE);
  581. trys++;
  582. }
  583. }
  584. /*
  585. * turn_on_logging - if the logfile exist, turn on attempt logging and
  586. * initialize the string storage area
  587. */
  588. static void
  589. turn_on_logging(void)
  590. {
  591. struct stat dbuf;
  592. int i;
  593. if (stat(LOGINLOG, &dbuf) == 0) {
  594. writelog = 1;
  595. for (i = 0; i < LOGTRYS; i++) {
  596. if (!(log_entry[i] = malloc((size_t) ENT_SIZE))) {
  597. writelog = 0;
  598. break;
  599. }
  600. *log_entry[i] = '\0';
  601. }
  602. }
  603. }
  604. /*
  605. * login_conv():
  606. * This is the conv (conversation) function called from
  607. * a PAM authentication module to print error messages
  608. * or garner information from the user.
  609. */
  610. static int
  611. login_conv(int num_msg, struct pam_message **msg,
  612. struct pam_response **response, void *appdata_ptr)
  613. {
  614. struct pam_message *m;
  615. struct pam_response *r;
  616. char *temp;
  617. int k, i;
  618. if (num_msg <= 0)
  619. return (PAM_CONV_ERR);
  620. *response = calloc(num_msg, sizeof (struct pam_response));
  621. if (*response == NULL)
  622. return (PAM_BUF_ERR);
  623. k = num_msg;
  624. m = *msg;
  625. r = *response;
  626. while (k--) {
  627. switch (m->msg_style) {
  628. case PAM_PROMPT_ECHO_OFF:
  629. temp = getpass(m->msg);
  630. if (temp != NULL) {
  631. r->resp = strdup(temp);
  632. if (r->resp == NULL) {
  633. /* free responses */
  634. r = *response;
  635. for (i = 0; i < num_msg; i++, r++) {
  636. if (r->resp)
  637. free(r->resp);
  638. }
  639. free(*response);
  640. *response = NULL;
  641. return (PAM_BUF_ERR);
  642. }
  643. }
  644. m++;
  645. r++;
  646. break;
  647. case PAM_PROMPT_ECHO_ON:
  648. if (m->msg != NULL)
  649. (void) fputs(m->msg, stdout);
  650. r->resp = calloc(1, PAM_MAX_RESP_SIZE);
  651. if (r->resp == NULL) {
  652. /* free responses */
  653. r = *response;
  654. for (i = 0; i < num_msg; i++, r++) {
  655. if (r->resp)
  656. free(r->resp);
  657. }
  658. free(*response);
  659. *response = NULL;
  660. return (PAM_BUF_ERR);
  661. }
  662. if (fgets(r->resp, PAM_MAX_RESP_SIZE-1, stdin)) {
  663. int len;
  664. r->resp[PAM_MAX_RESP_SIZE-1] = NULL;
  665. len = strlen(r->resp);
  666. if (r->resp[len-1] == '\n')
  667. r->resp[len-1] = '\0';
  668. } else {
  669. login_exit(1);
  670. }
  671. m++;
  672. r++;
  673. break;
  674. case PAM_ERROR_MSG:
  675. if (m->msg != NULL) {
  676. (void) fputs(m->msg, stderr);
  677. (void) fputs("\n", stderr);
  678. }
  679. m++;
  680. r++;
  681. break;
  682. case PAM_TEXT_INFO:
  683. if (m->msg != NULL) {
  684. (void) fputs(m->msg, stdout);
  685. (void) fputs("\n", stdout);
  686. }
  687. m++;
  688. r++;
  689. break;
  690. default:
  691. break;
  692. }
  693. }
  694. return (PAM_SUCCESS);
  695. }
  696. /*
  697. * verify_passwd - Checks the users password
  698. * Returns: OK if password check successful,
  699. * ERROR if password check fails.
  700. */
  701. static int
  702. verify_passwd()
  703. {
  704. int flags;
  705. int error;
  706. char *user;
  707. /*
  708. * PAM authenticates the user for us.
  709. */
  710. error = pam_authenticate(pamh, 0);
  711. /* get the user_name from the pam handle */
  712. pam_get_item(pamh, PAM_USER, (void**)&user);
  713. SCPYN(user_name, user);
  714. check_for_dueling_unix(user_name);
  715. if (error != PAM_SUCCESS) {
  716. /* something bad has happended - bye bye */
  717. if (error == PAM_ABORT) {
  718. audit_login_bad_pw();
  719. log_bad_attempts();
  720. (void) sleep(DISABLETIME);
  721. (void) printf(incorrectmsg);
  722. login_exit(1);
  723. }
  724. return (error);
  725. }
  726. if ((pwd = getpwnam(user_name)) == NULL) {
  727. audit_login_bad_pw();
  728. log_bad_attempts();
  729. return (PAM_USER_UNKNOWN);
  730. }
  731. audit_login_save_pw(pwd);
  732. return (error);
  733. }
  734. /*
  735. * quotec - Called by getargs
  736. */
  737. static int
  738. quotec(void)
  739. {
  740. int c, i, num;
  741. switch (c = getc(stdin)) {
  742. case 'n':
  743. c = '\n';
  744. break;
  745. case 'r':
  746. c = '\r';
  747. break;
  748. case 'v':
  749. c = '\013';
  750. break;
  751. case 'b':
  752. c = '\b';
  753. break;
  754. case 't':
  755. c = '\t';
  756. break;
  757. case 'f':
  758. c = '\f';
  759. break;
  760. case '0':
  761. case '1':
  762. case '2':
  763. case '3':
  764. case '4':
  765. case '5':
  766. case '6':
  767. case '7':
  768. for (num = 0, i = 0; i < 3; i++) {
  769. num = num * 8 + (c - '0');
  770. if ((c = getc(stdin)) < '0' || c > '7')
  771. break;
  772. }
  773. (void) ungetc(c, stdin);
  774. c = num & 0377;
  775. break;
  776. default:
  777. break;
  778. }
  779. return (c);
  780. }
  781. /*
  782. * getargs - returns an input line. Exits if EOF encountered.
  783. */
  784. #define WHITESPACE 0
  785. #define ARGUMENT 1
  786. static char **
  787. getargs(char *in_line)
  788. {
  789. static char envbuf[MAXLINE];
  790. static char *args[MAXARGS];
  791. char *ptr, **answer;
  792. int c;
  793. int state;
  794. for (ptr = envbuf; ptr < &envbuf[sizeof (envbuf)]; /* cstyle */)
  795. *ptr++ = '\0';
  796. for (answer = args; answer < &args[MAXARGS]; /* cstyle */)
  797. *answer++ = (char *)NULL;
  798. for (ptr = envbuf, answer = &args[0], state = WHITESPACE;
  799. (c = getc(stdin)) != EOF; /* cstyle */) {
  800. *(in_line++) = c;
  801. switch (c) {
  802. case '\n':
  803. if (ptr == &envbuf[0])
  804. return ((char **)NULL);
  805. return (&args[0]);
  806. case ' ':
  807. case '\t':
  808. if (state == ARGUMENT) {
  809. *ptr++ = '\0';
  810. state = WHITESPACE;
  811. }
  812. break;
  813. case '\\':
  814. c = quotec();
  815. default:
  816. if (state == WHITESPACE) {
  817. *answer++ = ptr;
  818. state = ARGUMENT;
  819. }
  820. *ptr++ = c;
  821. }
  822. /*
  823. * If the buffer is full, force the next character to be read to
  824. * be a <newline>.
  825. */
  826. if (ptr == &envbuf[sizeof (envbuf)-1]) {
  827. (void) ungetc('\n', stdin);
  828. (void) putc('\n', stdout);
  829. }
  830. }
  831. /*
  832. * If we left loop because an EOF was received, exit immediately.
  833. */
  834. login_exit(0);
  835. /* NOTREACHED */
  836. }
  837. /*
  838. * get_user_name - Gets the user name either passed in, or from the
  839. * login: prompt.
  840. */
  841. static void
  842. get_user_name()
  843. {
  844. FILE *fp;
  845. int gotname = 0;
  846. if ((fp = fopen(ISSUEFILE, "r")) != NULL) {
  847. char *ptr, buffer[BUFSIZ];
  848. while ((ptr = fgets(buffer, sizeof (buffer),
  849. fp)) != NULL) {
  850. (void) fputs(ptr, stdout);
  851. }
  852. (void) fclose(fp);
  853. }
  854. /*
  855. * if TTYPROMPT is not set, use our own prompt
  856. * otherwise, use ttyprompt. We just set PAM_USER_PROMPT
  857. * and let the module do the prompting.
  858. */
  859. if ((ttyprompt == NULL) || (*ttyprompt == '\0'))
  860. (void) pam_set_item(pamh, PAM_USER_PROMPT, (void *)loginmsg);
  861. else
  862. (void) pam_set_item(pamh, PAM_USER_PROMPT, (void *)ttyprompt);
  863. envp = &zero; /* XXX: is this right? */
  864. }
  865. /*
  866. * Check_for_dueling_unix - Check to see if the another login is talking
  867. * to the line we've got open as a login port
  868. * Exits if we're talking to another unix system
  869. */
  870. static void
  871. check_for_dueling_unix(char *inputline)
  872. {
  873. if (EQN(loginmsg, inputline) || EQN(passwdmsg, inputline) ||
  874. EQN(incorrectmsg, inputline)) {
  875. (void) printf("Looking at a login line.\n");
  876. login_exit(8);
  877. }
  878. }
  879. /*
  880. * logins_disabled - if the file /etc/nologin exists and the user is not
  881. * root then do not permit them to login
  882. */
  883. static int
  884. logins_disabled(char *user_name)
  885. {
  886. FILE *nlfd;
  887. int c;
  888. if (!EQN("root", user_name) &&
  889. ((nlfd = fopen(NOLOGIN, "r")) != (FILE *)NULL)) {
  890. while ((c = getc(nlfd)) != EOF)
  891. putchar(c);
  892. (void) fflush(stdout);
  893. sleep(5);
  894. return (TRUE);
  895. }
  896. return (FALSE);
  897. }
  898. /*
  899. * check_for_root_user - Checks if we're getting a root login on the console
  900. * Exits if root login not on system console.
  901. *
  902. */
  903. static void
  904. check_for_root_user(void)
  905. {
  906. if (pwd->pw_uid == 0) {
  907. if ((Console != NULL) && (strcmp(ttyn, Console) != 0)) {
  908. audit_login_not_console();
  909. (void) printf("Not on system console\n");
  910. login_exit(10);
  911. }
  912. }
  913. }
  914. static char *illegal[] = {
  915. "SHELL=",
  916. "HOME=",
  917. "LOGNAME=",
  918. #ifndef NO_MAIL
  919. "MAIL=",
  920. #endif
  921. "CDPATH=",
  922. "IFS=",
  923. "PATH=",
  924. 0
  925. };
  926. /*
  927. * legalenvvar - Is it legal to insert this environmental variable?
  928. */
  929. static int
  930. legalenvvar(char *s)
  931. {
  932. char **p;
  933. for (p = illegal; *p; p++)
  934. if (strncmp(s, *p, strlen(*p)) == 0)
  935. return (0);
  936. if (s[0] == 'L' && s[1] == 'D' && s[2] == '_')
  937. return (0);
  938. return (1);
  939. }
  940. /*
  941. * getstr - Get a string from standard input
  942. * Calls exit if read(2) fails.
  943. */
  944. static void
  945. getstr(char *buf, int cnt, char *err)
  946. {
  947. char c;
  948. do {
  949. if (read(0, &c, 1) != 1)
  950. login_exit(1);
  951. *buf++ = c;
  952. } while (cnt > 1 && c != 0);
  953. *buf = 0;
  954. err = err; /* For lint */
  955. }
  956. /*
  957. * uppercaseterm - if all input char are upper case
  958. * set the corresponding termio
  959. */
  960. static void
  961. uppercaseterm(char *strp)
  962. {
  963. int upper = 0;
  964. int lower = 0;
  965. char *sp;
  966. struct termio termio;
  967. for (sp = strp; *sp; sp++) {
  968. if (islower(*sp))
  969. lower++;
  970. else if (isupper(*sp))
  971. upper++;
  972. }
  973. if (upper > 0 && lower == 0) {
  974. (void) ioctl(0, TCGETA, &termio);
  975. termio.c_iflag |= IUCLC;
  976. termio.c_oflag |= OLCUC;
  977. termio.c_lflag |= XCASE;
  978. (void) ioctl(0, TCSETAW, &termio);
  979. for (sp = strp; *sp; sp++)
  980. if (*sp >= 'A' && *sp <= 'Z') *sp += ('a' - 'A');
  981. }
  982. }
  983. /*
  984. * defaults - read defaults
  985. */
  986. static void
  987. defaults(void)
  988. {
  989. extern int defcntl();
  990. int flags;
  991. char *ptr;
  992. if (defopen(Pndefault) == 0) {
  993. /*
  994. * ignore case
  995. */
  996. flags = defcntl(DC_GETFLAGS, 0);
  997. TURNOFF(flags, DC_CASE);
  998. defcntl(DC_SETFLAGS, flags);
  999. if ((Console = defread("CONSOLE=")) != NULL)
  1000. Console = strdup(Console);
  1001. if ((Altshell = defread("ALTSHELL=")) != NULL)
  1002. Altshell = strdup(Altshell);
  1003. if ((Passreq = defread("PASSREQ=")) != NULL)
  1004. Passreq = strdup(Passreq);
  1005. if ((Def_tz = defread("TIMEZONE=")) != NULL)
  1006. Def_tz = strdup(Def_tz);
  1007. if ((Def_hertz = defread("HZ=")) != NULL)
  1008. Def_hertz = strdup(Def_hertz);
  1009. if ((Def_path = defread("PATH=")) != NULL)
  1010. Def_path = strdup(Def_path);
  1011. if ((Def_supath = defread("SUPATH=")) != NULL)
  1012. Def_supath = strdup(Def_supath);
  1013. if ((ptr = defread("ULIMIT=")) != NULL)
  1014. Def_ulimit = atol(ptr);
  1015. if ((ptr = defread("TIMEOUT=")) != NULL)
  1016. Def_timeout = (unsigned) atoi(ptr);
  1017. if ((ptr = defread("UMASK=")) != NULL) {
  1018. long long_umask;
  1019. if (sscanf(ptr, "%lo", &long_umask) != 1)
  1020. Umask = DEFUMASK;
  1021. else
  1022. Umask = (mode_t) long_umask;
  1023. }
  1024. if ((ptr = defread("SLEEPTIME=")) != NULL)
  1025. Sleeptime = atoi(ptr);
  1026. if ((ptr = defread("SYSLOG=")) != NULL)
  1027. dosyslog = strcmp(ptr, "YES") == 0;
  1028. (void) defopen((char *)NULL);
  1029. }
  1030. }
  1031. /*
  1032. * get_options(argc, argv)
  1033. * - parse the cmd line.
  1034. * - return 0 if successful, -1 if failed.
  1035. * Calls login_exit() on misuse of -r and -h flags
  1036. */
  1037. static int
  1038. get_options(int argc, char *argv[])
  1039. {
  1040. int c;
  1041. int errflg = 0;
  1042. while ((c = getopt(argc, argv, "f:h:r:pad:")) != -1) {
  1043. switch (c) {
  1044. case 'a':
  1045. break;
  1046. case 'd':
  1047. /*
  1048. * Must be root to pass in device name
  1049. * otherwise we exit() as punishment for trying.
  1050. */
  1051. if (getuid() != 0 || geteuid() != 0) {
  1052. login_exit(1); /* sigh */
  1053. /*NOTREACHED*/
  1054. }
  1055. ttyn = optarg;
  1056. break;
  1057. case 'h':
  1058. if (hflag || rflag) {
  1059. (void) fprintf(stderr,
  1060. "Only one of -r and -h allowed\n");
  1061. login_exit(1);
  1062. }
  1063. hflag++;
  1064. SCPYN(remote_host, optarg);
  1065. if (argv[optind]) {
  1066. if (argv[optind][0] != '-')
  1067. SCPYN(terminal, argv[optind]);
  1068. optind++;
  1069. }
  1070. progname = "telnet";
  1071. break;
  1072. case 'r':
  1073. if (hflag || rflag) {
  1074. (void) fprintf(stderr,
  1075. "Only one of -r and -h allowed\n");
  1076. login_exit(1);
  1077. }
  1078. rflag++;
  1079. SCPYN(remote_host, optarg);
  1080. progname = "rlogin";
  1081. break;
  1082. case 'p':
  1083. pflag++;
  1084. break;
  1085. case 'f':
  1086. /*
  1087. * Must be root to bypass authentication
  1088. * otherwise we exit() as punishment for trying.
  1089. */
  1090. if (getuid() != 0 || geteuid() != 0) {
  1091. login_exit(1); /* sigh */
  1092. /*NOTREACHED*/
  1093. }
  1094. /* save fflag user name for future use */
  1095. SCPYN(user_name, optarg);
  1096. fflag = 1;
  1097. break;
  1098. default:
  1099. errflg++;
  1100. break;
  1101. } /* end switch */
  1102. } /* end while */
  1103. /*
  1104. * get the prompt set by ttymon
  1105. */
  1106. ttyprompt = getenv("TTYPROMPT");
  1107. if ((ttyprompt != NULL) && (*ttyprompt != '\0')) {
  1108. /*
  1109. * if ttyprompt is set, there should be data on
  1110. * the stream already.
  1111. */
  1112. if ((envp = getargs(inputline)) != (char **)NULL) {
  1113. uppercaseterm(*envp);
  1114. /*
  1115. * don't get name if name passed as argument.
  1116. */
  1117. SCPYN(user_name, *envp++);
  1118. }
  1119. } else if (optind < argc) {
  1120. SCPYN(user_name, argv[optind]);
  1121. (void) strcpy(inputline, user_name);
  1122. (void) strcat(inputline, " \n");
  1123. envp = &argv[optind+1];
  1124. }
  1125. if (errflg)
  1126. return (-1);
  1127. return (0);
  1128. }
  1129. /*
  1130. * usage - Print usage message
  1131. *
  1132. */
  1133. static void
  1134. usage(void)
  1135. {
  1136. (void) fprintf(stderr,
  1137. "Usage:\tlogin [-h|-r] [ name [ env-var ... ]]\n");
  1138. }
  1139. /*
  1140. * *** Remote login support ***
  1141. *
  1142. */
  1143. /*
  1144. * doremoteterm - Sets the appropriate ioctls for a remote terminal
  1145. */
  1146. static char *speeds[] = {
  1147. "0", "50", "75", "110", "134", "150", "200", "300",
  1148. "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400",
  1149. "57600", "76800", "115200", "153600", "230400", "307200", "460800"
  1150. };
  1151. #define NSPEEDS (sizeof (speeds) / sizeof (speeds[0]))
  1152. static void
  1153. doremoteterm(char *term)
  1154. {
  1155. struct termios tp;
  1156. char *cp = strchr(term, '/'), **cpp;
  1157. char *speed;
  1158. (void) ioctl(0, TCGETS, &tp);
  1159. if (cp) {
  1160. *cp++ = '\0';
  1161. speed = cp;
  1162. cp = strchr(speed, '/');
  1163. if (cp)
  1164. *cp++ = '\0';
  1165. for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
  1166. if (strcmp(*cpp, speed) == 0) {
  1167. cfsetospeed(&tp, cpp-speeds);
  1168. break;
  1169. }
  1170. }
  1171. tp.c_lflag |= ECHO|ICANON;
  1172. tp.c_iflag |= IGNPAR|ICRNL;
  1173. (void) ioctl(0, TCSETS, &tp);
  1174. }
  1175. /*
  1176. * Process_rlogin - Does the work that rlogin and telnet
  1177. * need done
  1178. */
  1179. static void
  1180. process_rlogin(void)
  1181. {
  1182. getstr(rusername, sizeof (rusername), "remuser");
  1183. getstr(lusername, sizeof (lusername), "locuser");
  1184. getstr(terminal, sizeof (terminal), "Terminal type");
  1185. /* fflag has precedence over stuff passed by rlogind */
  1186. if (fflag || getuid()) {
  1187. pwd = &nouser;
  1188. doremoteterm(terminal);
  1189. return;
  1190. } else {
  1191. if (pam_set_item(pamh, PAM_USER, lusername) != PAM_SUCCESS)
  1192. login_exit(1);
  1193. pwd = getpwnam(lusername);
  1194. if (pwd == NULL) {
  1195. pwd = &nouser;
  1196. doremoteterm(terminal);
  1197. return;
  1198. }
  1199. }
  1200. doremoteterm(terminal);
  1201. /*
  1202. * Update PAM on the user name
  1203. */
  1204. if (pam_set_item(pamh, PAM_USER, lusername) != PAM_SUCCESS)
  1205. login_exit(1);
  1206. if (pam_set_item(pamh, PAM_RUSER, rusername) != PAM_SUCCESS)
  1207. login_exit(1);
  1208. SCPYN(user_name, lusername);
  1209. envp = &zero;
  1210. lusername[0] = '\0';
  1211. }
  1212. /*
  1213. * *** Account validation routines ***
  1214. *
  1215. */
  1216. /*
  1217. * validate_account - This is the PAM version of validate.
  1218. */
  1219. static void
  1220. validate_account()
  1221. {
  1222. int error;
  1223. int n;
  1224. int flag;
  1225. (void) alarm(0); /* give user time to come up with password */
  1226. check_log();
  1227. if ((Passreq != NULL) && (!strcasecmp("YES", Passreq)))
  1228. flag = PAM_DISALLOW_NULL_AUTHTOK;
  1229. else
  1230. flag = 0;
  1231. if ((error = pam_acct_mgmt(pamh, flag)) != PAM_SUCCESS) {
  1232. if (error == PAM_AUTHTOKEN_REQD) {
  1233. (void) printf("Choose a new password.\n");
  1234. if ((error = pam_chauthtok(pamh, 0)) != PAM_SUCCESS) {
  1235. if (dosyslog)
  1236. syslog(LOG_CRIT,
  1237. "change password failure: %s",
  1238. pam_strerror(pamh, error));
  1239. login_exit(1);
  1240. }
  1241. } else {
  1242. (void) printf(incorrectmsg);
  1243. if (dosyslog)
  1244. syslog(LOG_CRIT,
  1245. "login account failure: %s",
  1246. pam_strerror(pamh, error));
  1247. login_exit(1);
  1248. }
  1249. }
  1250. }
  1251. /*
  1252. * Check_log - This is really a hack because PAM checks the log, but login
  1253. * wants to know if the log is okay and PAM doesn't have
  1254. * a module independent way of handing this info back.
  1255. */
  1256. static void
  1257. check_log(void)
  1258. {
  1259. int fdl;
  1260. long long offset;
  1261. offset = (long long) pwd->pw_uid * (long long) sizeof (struct lastlog);
  1262. if ((fdl = open(LASTLOG, O_RDWR|O_CREAT, 0444)) >= 0) {
  1263. if (llseek(fdl, offset, SEEK_SET) == offset &&
  1264. read(fdl, (char *)&ll, sizeof (ll)) == sizeof (ll) &&
  1265. ll.ll_time != 0)
  1266. lastlogok = 1;
  1267. (void) close(fdl);
  1268. }
  1269. }
  1270. /*
  1271. * chdir_to_dir_root - Attempts to chdir us to the home directory.
  1272. * defaults to "/" if it can't cd to the home
  1273. * directory, and returns ERROR if it can't do that.
  1274. */
  1275. static int
  1276. chdir_to_dir_root(void)
  1277. {
  1278. if (chdir(pwd->pw_dir) < 0) {
  1279. if (chdir("/") < 0) {
  1280. (void) printf("No directory!\n");
  1281. return (ERROR);
  1282. }
  1283. }
  1284. return (OK);
  1285. }
  1286. /*
  1287. * chdir_to_dir_user - Now chdir after setuid/setgid have happened to
  1288. * place us in the user's home directory just in
  1289. * case it was protected and the first chdir failed.
  1290. * No chdir errors should happen at this point because
  1291. * all failures should have happened on the first
  1292. * time around.
  1293. */
  1294. static void
  1295. chdir_to_dir_user(void)
  1296. {
  1297. if (chdir(pwd->pw_dir) < 0) {
  1298. if (chdir("/") < 0) {
  1299. (void) printf("No directory!\n");
  1300. /*
  1301. * This probably won't work since we can't get to /.
  1302. */
  1303. if (remote_host[0] && dosyslog) {
  1304. syslog(LOG_CRIT,
  1305. "REPEATED LOGIN FAILURES ON %s FROM %.*s",
  1306. ttyn, HMAX, remote_host);
  1307. } else if (dosyslog) {
  1308. syslog(LOG_CRIT,
  1309. "REPEATED LOGIN FAILURES ON %s", ttyn);
  1310. }
  1311. closelog();
  1312. (void) sleep(DISABLETIME);
  1313. exit(1);
  1314. } else {
  1315. (void) printf("No directory! Logging in with home=/\n");
  1316. pwd->pw_dir = "/";
  1317. }
  1318. }
  1319. }
  1320. /*
  1321. * login_authenticate - Performs the main authentication work
  1322. * 1. Prints the login prompt
  1323. * 2. Requests and verifys the password
  1324. * 3. Checks the port password
  1325. */
  1326. static void
  1327. login_authenticate()
  1328. {
  1329. int cnt = 1;
  1330. char *user;
  1331. int err;
  1332. do {
  1333. /* if scheme broken, then nothing to do but quit */
  1334. if (pam_get_item(pamh, PAM_USER, (void **)&user)
  1335. != PAM_SUCCESS)
  1336. exit(1);
  1337. /*
  1338. * only get name from utility if it is not already
  1339. * supplied by pam_start or a pam_set_item.
  1340. */
  1341. if (!user || !user[0]) {
  1342. /* use call back to get user name */
  1343. get_user_name();
  1344. }
  1345. err = verify_passwd();
  1346. if ((err == PAM_SUCCESS) && (chdir_to_dir_root() == OK)) {
  1347. cnt = 0;
  1348. break;
  1349. }
  1350. /* scheme has kept count of retries. time to bail */
  1351. if (err == PAM_MAXTRIES)
  1352. cnt = MAXTRYS;
  1353. /* only sleep after first bad passwd */
  1354. if (cnt)
  1355. (void) sleep(Sleeptime);
  1356. (void) printf(incorrectmsg);
  1357. user_name[0] = '\0'; /* is this needed? */
  1358. /* force name to be null in this case */
  1359. if (pam_set_item(pamh, PAM_USER, NULL) != PAM_SUCCESS)
  1360. login_exit(1);
  1361. if (pam_set_item(pamh, PAM_RUSER, NULL) != PAM_SUCCESS)
  1362. login_exit(1);
  1363. } while (cnt++ < MAXTRYS);
  1364. if (cnt >= MAXTRYS) {
  1365. audit_login_maxtrys();
  1366. /*
  1367. * If logging is turned on, output the
  1368. * string storage area to the log file,
  1369. * and sleep for DISABLETIME
  1370. * seconds before exiting.
  1371. */
  1372. if (writelog)
  1373. badlogin();
  1374. if (remote_host[0] && dosyslog) {
  1375. syslog(LOG_CRIT,
  1376. "REPEATED LOGIN FAILURES ON %s FROM %.*s",
  1377. ttyn, HMAX, remote_host);
  1378. } else if (dosyslog) {
  1379. syslog(LOG_CRIT,
  1380. "REPEATED LOGIN FAILURES ON %s", ttyn);
  1381. }
  1382. (void) sleep(DISABLETIME);
  1383. exit(1);
  1384. }
  1385. }
  1386. /*
  1387. * *** Credential Related routines ***
  1388. *
  1389. */
  1390. /*
  1391. * setup_credentials - sets the group ID, initializes the groups
  1392. * and sets up the secretkey.
  1393. * Exits if a failure occurrs.
  1394. */
  1395. /*
  1396. * setup_credentials - PAM does all the work for us on this one.
  1397. */
  1398. static void
  1399. setup_credentials(void)
  1400. {
  1401. int error = 0;
  1402. int flags;
  1403. /* set the real (and effective) GID */
  1404. if (setgid(pwd->pw_gid) == -1) {
  1405. login_exit(1);
  1406. }
  1407. /*
  1408. * Initialize the supplementary group access list.
  1409. */
  1410. if (!user_name)
  1411. login_exit(1);
  1412. if (initgroups(user_name, pwd->pw_gid) == -1) {
  1413. login_exit(1);
  1414. }
  1415. /* XXX really should be after setgid */
  1416. if ((error = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
  1417. login_exit(error);
  1418. }
  1419. /* set the real (and effective) UID */
  1420. if (setuid(pwd->pw_uid) == -1) {
  1421. login_exit(1);
  1422. }
  1423. }
  1424. /*
  1425. *
  1426. * *** Routines to get a new user set up and running ***
  1427. *
  1428. * Things to do when starting up a new user:
  1429. * adjust_nice
  1430. * update_utmp_entry
  1431. * establish_user_environment
  1432. * print_banner
  1433. * display_last_login_time
  1434. * exec_the_shell
  1435. *
  1436. */
  1437. /*
  1438. * adjust_nice - Set the nice (process priority) value if the
  1439. * gecos value contains an appropriate value.
  1440. */
  1441. static void
  1442. adjust_nice(void)
  1443. {
  1444. int pri, mflg, i;
  1445. if (strncmp("pri=", pwd->pw_gecos, 4) == 0) {
  1446. pri = 0;
  1447. mflg = 0;
  1448. i = 4;
  1449. if (pwd->pw_gecos[i] == '-') {
  1450. mflg++;
  1451. i++;
  1452. }
  1453. while (pwd->pw_gecos[i] >= '0' && pwd->pw_gecos[i] <= '9')
  1454. pri = (pri * 10) + pwd->pw_gecos[i++] - '0';
  1455. if (mflg)
  1456. pri = -pri;
  1457. (void) nice(pri);
  1458. }
  1459. }
  1460. /*
  1461. * update_utmp_entry - Searchs for the correct utmp entry, making an
  1462. * entry there if it finds one, otherwise exits.
  1463. */
  1464. static void
  1465. update_utmp_entry(int sublogin)
  1466. {
  1467. char *user;
  1468. int error;
  1469. static char *errmsg = "No utmpx entry. "
  1470. "You must exec \"login\" from the lowest level \"shell\".";
  1471. int tmplen;
  1472. struct utmpx *u = (struct utmpx *)0;
  1473. struct utmpx utmp;
  1474. char *ttyntail;
  1475. /*
  1476. * If we're not a sublogin then
  1477. * we'll get an error back if our PID doesn't match the PID of the
  1478. * entry we are updating, otherwise if its a sublogin the flags
  1479. * field is set to 0, which means we just write a matching entry
  1480. * (without checking the pid), or a new entry if an entry doesn't
  1481. * exist.
  1482. */
  1483. if (error = pam_open_session(pamh, 0) != PAM_SUCCESS) {
  1484. login_exit(1);
  1485. }
  1486. if ((error = pam_get_item(pamh, PAM_USER, (void **) &user))
  1487. != PAM_SUCCESS) {
  1488. login_exit(1);
  1489. }
  1490. (void) memset((void *)&utmp, 0, sizeof (utmp));
  1491. (void) time(&utmp.ut_tv.tv_sec);
  1492. utmp.ut_pid = getpid();
  1493. if (rflag || hflag) {
  1494. SCPYN(utmp.ut_host, remote_host);
  1495. tmplen = strlen(remote_host) + 1;
  1496. if (tmplen < sizeof (utmp.ut_host))
  1497. utmp.ut_syslen = tmplen;
  1498. else
  1499. utmp.ut_syslen = sizeof (utmp.ut_host);
  1500. } else {
  1501. utmp.ut_syslen = 0;
  1502. }
  1503. SCPYN(utmp.ut_user, user);
  1504. /* skip over "/dev/" */
  1505. ttyntail = basename(ttyn);
  1506. while ((u = getutxent()) != NULL) {
  1507. if ((u->ut_type == INIT_PROCESS ||
  1508. u->ut_type == LOGIN_PROCESS ||
  1509. u->ut_type == USER_PROCESS) &&
  1510. ((sublogin && strncmp(u->ut_line, ttyntail,
  1511. sizeof (u->ut_line)) == 0) ||
  1512. u->ut_pid == utmp.ut_pid)) {
  1513. SCPYN(utmp.ut_line, (ttyn+sizeof ("/dev/")-1));
  1514. (void) memcpy(utmp.ut_id, u->ut_id,
  1515. sizeof (utmp.ut_id));
  1516. utmp.ut_type = USER_PROCESS;
  1517. pututxline(&utmp);
  1518. break;
  1519. }
  1520. }
  1521. endutxent();
  1522. if (u == (struct utmpx *)NULL) {
  1523. if (!sublogin) {
  1524. /*
  1525. * no utmp entry already setup
  1526. * (init or rlogind/telnetd)
  1527. */
  1528. (void) puts(errmsg);
  1529. login_exit(1);
  1530. }
  1531. } else {
  1532. /* Now attempt to write out this entry to the wtmp file if */
  1533. /* we were successful in getting it from the utmp file and */
  1534. /* the wtmp file exists. */
  1535. updwtmpx(WTMPX_FILE, &utmp);
  1536. }
  1537. }
  1538. /*
  1539. * process_chroot_logins - Chroots to the specified subdirectory and
  1540. * re executes login.
  1541. */
  1542. static int
  1543. process_chroot_logins(void)
  1544. {
  1545. /*
  1546. * If the shell field starts with a '*', do a chroot to the home
  1547. * directory and perform a new login.
  1548. */
  1549. if (*pwd->pw_shell == '*') {
  1550. pam_end(pamh, PAM_SUCCESS); /* Done using PAM */
  1551. if (chroot(pwd->pw_dir) < 0) {
  1552. (void) printf("No Root Directory\n");
  1553. return (ERROR);
  1554. }
  1555. /*
  1556. * Set the environment flag <!sublogin> so that the next login
  1557. * knows that it is a sublogin.
  1558. */
  1559. envinit[0] = SUBLOGIN;
  1560. envinit[1] = (char *)NULL;
  1561. (void) printf("Subsystem root: %s\n", pwd->pw_dir);
  1562. (void) execle("/usr/bin/login", "login", (char *)0,
  1563. &envinit[0]);
  1564. (void) execle("/etc/login", "login", (char *)0, &envinit[0]);
  1565. (void) printf("No /usr/bin/login or /etc/login on root\n");
  1566. login_exit(1);
  1567. }
  1568. return (OK);
  1569. }
  1570. /*
  1571. * establish_user_environment - Set up the new users environment
  1572. */
  1573. static void
  1574. establish_user_environment(char **renvp)
  1575. {
  1576. int i, j, k, l_index, length;
  1577. char *ptr;
  1578. char *endptr;
  1579. char **lenvp;
  1580. char *krb5p;
  1581. char *krb4p;
  1582. lenvp = environ;
  1583. while (*lenvp++)
  1584. ;
  1585. envinit = (char **) calloc(lenvp - environ + 10
  1586. + MAXARGS, sizeof (char *));
  1587. if (envinit == NULL) {
  1588. (void) printf("Calloc failed - out of swap space.\n");
  1589. login_exit(8);
  1590. }
  1591. memcpy(envinit, newenv, sizeof (newenv));
  1592. /* Set up environment */
  1593. if (rflag) {
  1594. ENVSTRNCAT(term, terminal);
  1595. } else if (hflag) {
  1596. /* XXX: this causes an environment variable with the value */
  1597. /* "" to be created later on, because terminal is "". */
  1598. (void) strncpy(term, terminal, sizeof (term) - 1);
  1599. } else {
  1600. char *tp = getenv("TERM");
  1601. if ((tp != NULL) && (*tp != '\0'))
  1602. ENVSTRNCAT(term, tp);
  1603. }
  1604. ENVSTRNCAT(logname, pwd->pw_name);
  1605. /*
  1606. * There are three places to get timezone info. init.c sets
  1607. * TZ if the file /etc/TIMEZONE contains a value for TZ.
  1608. * login.c looks in the file /etc/default/login for a
  1609. * variable called TIMEZONE being set. If TIMEZONE has a
  1610. * value, TZ is set to that value; no environment variable
  1611. * TIMEZONE is set, only TZ. If neither of these methods
  1612. * work to set TZ, then the library routines will default
  1613. * to using the file /usr/lib/locale/TZ/localtime.
  1614. *
  1615. * There is a priority set up here. If /etc/TIMEZONE has
  1616. * a value for TZ, that value remains top priority. If the
  1617. * file /etc/default/login has TIMEZONE set, that has second
  1618. * highest priority not overriding the value of TZ in
  1619. * /etc/TIMEZONE. The reason for this priority is that the
  1620. * file /etc/TIMEZONE is supposed to be sourced by
  1621. * /etc/profile. We are doing the "sourcing" prematurely in
  1622. * init.c. Additionally, a login C shell doesn't source the
  1623. * file /etc/profile thus not sourcing /etc/TIMEZONE thus not
  1624. * allowing an administrator to globally set TZ for all users
  1625. */
  1626. if (Def_tz != NULL) /* Is there a TZ from defaults/login? */
  1627. tmp_tz = Def_tz;
  1628. if ((Def_tz = getenv("TZ")) != NULL) {
  1629. ENVSTRNCAT(timez, Def_tz);
  1630. } else if (tmp_tz != NULL) {
  1631. Def_tz = tmp_tz;
  1632. ENVSTRNCAT(timez, Def_tz);
  1633. }
  1634. if (Def_hertz == NULL)
  1635. (void) sprintf(hertz + strlen(hertz), "%u", HZ);
  1636. else
  1637. ENVSTRNCAT(hertz, Def_hertz);
  1638. if (Def_path == NULL)
  1639. (void) strcat(path, DEF_PATH);
  1640. else
  1641. ENVSTRNCAT(path, Def_path);
  1642. ENVSTRNCAT(home, pwd->pw_dir);
  1643. /*
  1644. * Find the end of the basic environment
  1645. */
  1646. for (basicenv = 0; envinit[basicenv] != NULL; basicenv++)
  1647. ;
  1648. /*
  1649. * If TZ has a value, add it.
  1650. */
  1651. if (strcmp(timez, "TZ=") != 0)
  1652. envinit[basicenv++] = timez;
  1653. if (*pwd->pw_shell == '\0') {
  1654. /*
  1655. * If possible, use the primary default shell,
  1656. * otherwise, use the secondary one.
  1657. */
  1658. if (access(SHELL, X_OK) == 0)
  1659. pwd->pw_shell = SHELL;
  1660. else
  1661. pwd->pw_shell = SHELL2;
  1662. } else if (Altshell != NULL && strcmp(Altshell, "YES") == 0) {
  1663. envinit[basicenv++] = shell;
  1664. ENVSTRNCAT(shell, pwd->pw_shell);
  1665. }
  1666. #ifndef NO_MAIL
  1667. envinit[basicenv++] = mail;
  1668. (void) strcat(mail, pwd->pw_name);
  1669. #endif
  1670. /*
  1671. * Pick up locale environment variables, if any.
  1672. */
  1673. lenvp = renvp;
  1674. while (*lenvp != NULL) {
  1675. j = 0;
  1676. while (localeenv[j] != 0) {
  1677. /*
  1678. * locale_envmatch() returns 1 if
  1679. * *lenvp is localenev[j] and valid.
  1680. */
  1681. if (locale_envmatch(localeenv[j], *lenvp) == 1) {
  1682. envinit[basicenv++] = *lenvp;
  1683. break;
  1684. }
  1685. j++;
  1686. }
  1687. lenvp++;
  1688. }
  1689. /*
  1690. * If '-p' flag, then try to pass on allowable environment
  1691. * variables. Note that by processing this first, what is
  1692. * passed on the final "login:" line may over-ride the invocation
  1693. * values. XXX is this correct?
  1694. */
  1695. if (pflag) {
  1696. for (lenvp = renvp; *lenvp; lenvp++) {
  1697. if (!legalenvvar(*lenvp)) {
  1698. continue;
  1699. }
  1700. /*
  1701. * If this isn't 'xxx=yyy', skip it. XXX
  1702. */
  1703. if ((endptr = strchr(*lenvp, '=')) == NULL) {
  1704. continue;
  1705. }
  1706. length = endptr + 1 - *lenvp;
  1707. for (j = 0; j < basicenv; j++) {
  1708. if (strncmp(envinit[j], *lenvp, length) == 0) {
  1709. /*
  1710. * Replace previously established value
  1711. */
  1712. envinit[j] = *lenvp;
  1713. break;
  1714. }
  1715. }
  1716. if (j == basicenv) {
  1717. /*
  1718. * It's a new definition, so add it at the end.
  1719. */
  1720. envinit[basicenv++] = *lenvp;
  1721. }
  1722. }
  1723. }
  1724. /*
  1725. * Add in all the environment variables picked up from the
  1726. * argument list to "login" or from the user response to the
  1727. * "login" request.
  1728. */
  1729. for (j = 0, k = 0, l_index = 0, ptr = &envblk[0];
  1730. *envp && j < (MAXARGS-1); j++, envp++) {
  1731. /*
  1732. * Scan each string provided. If it doesn't have the
  1733. * format xxx=yyy, then add the string "Ln=" to the beginning.
  1734. */
  1735. if ((endptr = strchr(*envp, '=')) == NULL) {
  1736. envinit[basicenv+k] = ptr;
  1737. (void) sprintf(ptr, "L%d=%s", l_index, *envp);
  1738. /*
  1739. * Advance "ptr" to the beginning of the
  1740. * next argument.
  1741. */
  1742. while (*ptr++)
  1743. ;
  1744. k++;
  1745. l_index++;
  1746. } else {
  1747. if (!legalenvvar(*envp)) { /* this env var permited? */
  1748. continue;
  1749. } else {
  1750. /*
  1751. * Check to see whether this string replaces
  1752. * any previously defined string
  1753. */
  1754. for (i = 0, length = endptr + 1 - *envp;
  1755. i < basicenv + k; i++) {
  1756. if (strncmp(*envp, envinit[i], length)
  1757. == 0) {
  1758. envinit[i] = *envp;
  1759. break;
  1760. }
  1761. }
  1762. /*
  1763. * If it doesn't, place it at the end of
  1764. * environment array.
  1765. */
  1766. if (i == basicenv+k) {
  1767. envinit[basicenv+k] = *envp;
  1768. k++;
  1769. }
  1770. }
  1771. }
  1772. } /* for (j = 0 ... ) */
  1773. /*
  1774. * Add DCE/Kerberos cred name, if any.
  1775. * XXX - The module specific stuff should be removed from login
  1776. * program eventually. This is better placed in DCE module.
  1777. * So far, we haven't come up with a way to deal with these
  1778. * environment variables.
  1779. */
  1780. krb5p = getenv("KRB5CCNAME");
  1781. if ((krb5p != NULL) && (*krb5p != '\0')) {
  1782. ENVSTRNCAT(krb5ccname, krb5p);
  1783. envinit[basicenv++] = krb5ccname;
  1784. }
  1785. krb4p = getenv("KRBTKFILE");
  1786. if ((krb4p != NULL) && (*krb4p != '\0')) {
  1787. ENVSTRNCAT(krb4ccname, krb4p);
  1788. envinit[basicenv++] = krb4ccname;
  1789. }
  1790. /*
  1791. * Switch to the new environment.
  1792. */
  1793. environ = envinit;
  1794. }
  1795. /*
  1796. * print_banner - Print the banner at start up
  1797. * Do not turn on DOBANNER ifdef. This is not
  1798. * relevant to SunOS.
  1799. */
  1800. static void
  1801. print_banner(void)
  1802. {
  1803. #ifdef DOBANNER
  1804. uname(&un);
  1805. #if i386
  1806. (void) printf("UNIX System V/386 Release %s\n%s\n"
  1807. "Copyright (C) 1984, 1986, 1987, 1988 AT&T\n"
  1808. "Copyright (C) 1987, 1988 Microsoft Corp.\nAll Rights Reserved\n",
  1809. un.release, un.nodename);
  1810. #elif sun
  1811. (void) printf("SunOS Release %s Sun Microsystems %s\n%s\n"
  1812. "Copyright (c) 1984, 1986, 1987, 1988 AT&T\n"
  1813. "Copyright (c) 1988, 1989, 1990, 1991 Sun Microsystems\n"
  1814. "All Rights Reserved\n",
  1815. un.release, un.machine, un.nodename);
  1816. #else
  1817. (void) printf("UNIX System V Release %s AT&T %s\n%s\n"
  1818. "Copyright (c) 1984, 1986, 1987, 1988 AT&T\nAll Rights Reserved\n",
  1819. un.release, un.machine, un.nodename);
  1820. #endif /* i386 */
  1821. #endif /* DOBANNER */
  1822. }
  1823. /*
  1824. * display_last_login_time - Advise the user the time and date
  1825. * that this login-id was last used.
  1826. */
  1827. static void
  1828. display_last_login_time(void)
  1829. {
  1830. if (lastlogok) {
  1831. (void) printf("Last login: %.*s ", 24-5, ctime(&ll.ll_time));
  1832. if (*ll.ll_host != '\0')
  1833. (void) printf("from %.*s\n", sizeof (ll.ll_host),
  1834. ll.ll_host);
  1835. else
  1836. (void) printf("on %.*s\n", sizeof (ll.ll_line),
  1837. ll.ll_line);
  1838. }
  1839. }
  1840. /*
  1841. * exec_the_shell - invoke the specified shell or start up program
  1842. */
  1843. static void
  1844. exec_the_shell(void)
  1845. {
  1846. char *endptr;
  1847. int i;
  1848. (void) strcat(minusnam, basename(pwd->pw_shell));
  1849. /*
  1850. * Exec the shell
  1851. */
  1852. (void) execl(pwd->pw_shell, minusnam, (char *)0);
  1853. /*
  1854. * pwd->pw_shell was not an executable object file, maybe it
  1855. * is a shell proceedure or a command line with arguments.
  1856. * If so, turn off the SHELL= environment variable.
  1857. */
  1858. for (i = 0; envinit[i] != NULL; ++i) {
  1859. if ((envinit[i] == shell) &&
  1860. ((endptr = strchr(shell, '=')) != NULL))
  1861. (*++endptr) = '\0';
  1862. }
  1863. if (access(pwd->pw_shell, R_OK|X_OK) == 0) {
  1864. (void) execl(SHELL, "sh", pwd->pw_shell, (char *)0);
  1865. (void) execl(SHELL2, "sh", pwd->pw_shell, (char *)0);
  1866. }
  1867. (void) printf("No shell\n");
  1868. }
  1869. /*
  1870. * login_exit - Call exit() and terminate.
  1871. * This function is here for PAM so cleanup can
  1872. * be done before the process exits.
  1873. */
  1874. static void
  1875. login_exit(int exit_code)
  1876. {
  1877. if (pamh)
  1878. pam_end(pamh, PAM_ABORT);
  1879. exit(exit_code);
  1880. /*NOTREACHED*/
  1881. }
  1882. /*
  1883. * Check if lenv and penv matches or not.
  1884. */
  1885. static int
  1886. locale_envmatch(char *lenv, char *penv)
  1887. {
  1888. while ((*lenv == *penv) && *lenv && *penv != '=') {
  1889. lenv++;
  1890. penv++;
  1891. }
  1892. /*
  1893. * '/' is eliminated for security reason.
  1894. */
  1895. if (*lenv == '\0' && *penv == '=' && *(penv + 1) != '/')
  1896. return (1);
  1897. return (0);
  1898. }
  1899. /*
  1900. * logindevperm - change owner/group/permissions of devices
  1901. * list in /etc/logindevperm. (Code derived from set_fb_attrs()
  1902. * in 4.x usr/src/bin/login.c and usr/src/etc/getty/main.c.)
  1903. */
  1904. #define MAX_LINELEN 256
  1905. #define LOGINDEVPERM "/etc/logindevperm"
  1906. #define DIRWILD "/*" /* directory wildcard */
  1907. #define DIRWLDLEN 2 /* strlen(DIRWILD) */
  1908. static void
  1909. logindevperm(char *ttyn, uid_t uid, gid_t gid)
  1910. {
  1911. char *field_delims = " \t\n";
  1912. char *permfile = LOGINDEVPERM;
  1913. char line[MAX_LINELEN];
  1914. char *console;
  1915. char *mode_str;
  1916. char *dev_list;
  1917. char *device;
  1918. char *ptr;
  1919. int mode;
  1920. FILE *fp;
  1921. size_t l;
  1922. int lineno;
  1923. if ((fp = fopen(permfile, "r")) == NULL)
  1924. return;
  1925. lineno = 0;
  1926. while (fgets(line, MAX_LINELEN, fp) != NULL) {
  1927. lineno++;
  1928. if ((ptr = strchr(line, '#')) != NULL)
  1929. *ptr = '\0'; /* handle comments */
  1930. if ((console = strtok(line, field_delims)) == NULL)
  1931. continue; /* ignore blank lines */
  1932. if (strcmp(console, ttyn) != 0)
  1933. continue; /* not our tty, skip */
  1934. mode_str = strtok((char *)NULL, field_delims);
  1935. if (mode_str == NULL) {
  1936. (void) fprintf(stderr,
  1937. "%s: line %d, invalid entry -- %s\n", permfile,
  1938. lineno, line);
  1939. continue;
  1940. }
  1941. /* convert string to octal value */
  1942. mode = strtol(mode_str, &ptr, 8);
  1943. if (mode < 0 || mode > 0777 || *ptr != '\0') {
  1944. (void) fprintf(stderr,
  1945. "%s: line %d, invalid mode -- %s\n", permfile,
  1946. lineno, mode_str);
  1947. continue;
  1948. }
  1949. dev_list = strtok((char *)NULL, field_delims);
  1950. if (dev_list == NULL) {
  1951. (void) fprintf(stderr,
  1952. "%s: line %d, %s -- empty device list\n",
  1953. permfile, lineno, console);
  1954. continue;
  1955. }
  1956. device = strtok(dev_list, ":");
  1957. while (device != NULL) {
  1958. l = strlen(device);
  1959. ptr = &device[l - DIRWLDLEN];
  1960. if ((l > DIRWLDLEN) && (strcmp(ptr, DIRWILD) == 0)) {
  1961. *ptr = '\0'; /* chop off wildcard */
  1962. dir_dev_acc(device, uid, gid, mode, permfile);
  1963. } else {
  1964. /*
  1965. * change the owner/group/permission;
  1966. * nonexistent devices are ignored
  1967. */
  1968. if (chown(device, uid, gid) == -1) {
  1969. if (errno != ENOENT) {
  1970. (void) fprintf(stderr, "%s: ",
  1971. permfile);
  1972. perror(device);
  1973. }
  1974. } else {
  1975. if ((chmod(device, mode) == -1) &&
  1976. (errno != ENOENT)) {
  1977. (void) fprintf(stderr, "%s: ",
  1978. permfile);
  1979. perror(device);
  1980. }
  1981. }
  1982. }
  1983. device = strtok((char *)NULL, ":");
  1984. }
  1985. }
  1986. (void) fclose(fp);
  1987. }
  1988. /*
  1989. * Apply owner/group/perms to all files (except "." and "..")
  1990. * in a directory.
  1991. */
  1992. static void
  1993. dir_dev_acc(char *dir, uid_t uid, gid_t gid, mode_t mode, char *permfile)
  1994. {
  1995. DIR *dirp;
  1996. struct dirent *direntp;
  1997. char *name, path[MAX_LINELEN + MAXNAMELEN];
  1998. dirp = opendir(dir);
  1999. if (dirp == NULL)
  2000. return;
  2001. while ((direntp = readdir(dirp)) != NULL) {
  2002. name = direntp->d_name;
  2003. if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
  2004. continue;
  2005. (void) sprintf(path, "%s/%s", dir, name);
  2006. if (chown(path, uid, gid) == -1) {
  2007. if (errno != ENOENT) {
  2008. (void) fprintf(stderr, "%s: ", permfile);
  2009. perror(path);
  2010. }
  2011. } else {
  2012. if ((chmod(path, mode) == -1) && (errno != ENOENT)) {
  2013. (void) fprintf(stderr, "%s: ", permfile);
  2014. perror(path);
  2015. }
  2016. }
  2017. }
  2018. (void) closedir(dirp);
  2019. }