lutil.c 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. lutil.c
  5. Abstract:
  6. This module implements utility functions for the login commands.
  7. Author:
  8. Evan Green 10-Mar-2015
  9. Environment:
  10. POSIX
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #define _GNU_SOURCE 1
  16. #include <minoca/lib/types.h>
  17. #include <assert.h>
  18. #include <ctype.h>
  19. #include <dirent.h>
  20. #include <dlfcn.h>
  21. #include <errno.h>
  22. #include <fcntl.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <sys/utsname.h>
  26. #include <unistd.h>
  27. #include <utmp.h>
  28. #include <utmpx.h>
  29. #include "../swlib.h"
  30. #include "lutil.h"
  31. //
  32. // ---------------------------------------------------------------- Definitions
  33. //
  34. #define UPDATE_PASSWORD_WAIT 10
  35. #define PASSWORD_LINE_MAX 2048
  36. #define GROUP_LINE_MAX 4096
  37. #define LIBCRYPT_PATH "/lib/libcrypt.so.1"
  38. #define SALT_ALPHABET \
  39. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
  40. #define PASSWORD_ROUNDS_MIN 1000
  41. #define PASSWORD_ROUNDS_MAX 999999999
  42. //
  43. // ------------------------------------------------------ Data Type Definitions
  44. //
  45. typedef
  46. char *
  47. (*PCRYPT_FUNCTION) (
  48. const char *Key,
  49. const char *Salt
  50. );
  51. /*++
  52. Routine Description:
  53. This routine encrypts a user's password using various encryption/hashing
  54. standards. The default is DES, which is fairly weak and subject to
  55. dictionary attacks.
  56. Arguments:
  57. Key - Supplies the key, a user's plaintext password.
  58. Salt - Supplies a two character salt to use to perterb the results. If this
  59. string starts with a $ and a number, alternate hashing algorithms are
  60. selected. The format is $id$salt$encrypted. ID can be 1 for MD5, 5 for
  61. SHA-256, or 6 for SHA-512.
  62. Return Value:
  63. Returns a pointer to the encrypted password (plus ID and salt information
  64. in cases where an alternate mechanism is used). This is a static buffer,
  65. which may be overwritten by subsequent calls to crypt.
  66. --*/
  67. //
  68. // ----------------------------------------------- Internal Function Prototypes
  69. //
  70. INT
  71. SwpPrintShadowLine (
  72. PSTR Line,
  73. UINTN LineSize,
  74. struct spwd *Shadow
  75. );
  76. VOID
  77. SwpWriteNewUtmpEntry (
  78. pid_t ProcessId,
  79. int NewType,
  80. PSTR TerminalName,
  81. PSTR UserName,
  82. PSTR HostName
  83. );
  84. //
  85. // -------------------------------------------------------------------- Globals
  86. //
  87. extern char **environ;
  88. PASSWD_ALGORITHM SwPasswordAlgorithms[] = {
  89. {"md5", "$1$"},
  90. {"sha256", "$5$"},
  91. {"sha512", "$6$"},
  92. {NULL, NULL}
  93. };
  94. void *SwLibCrypt = NULL;
  95. PCRYPT_FUNCTION SwCryptFunction = NULL;
  96. PSTR SwDangerousEnvironmentVariables[] = {
  97. "ENV",
  98. "BASH_ENV",
  99. "HOME",
  100. "IFS",
  101. "SHELL",
  102. "LD_LIBRARY_PATH",
  103. "LD_PRELOAD",
  104. "LD_TRACE_LOADED_OBJECTS",
  105. "LD_BIND_NOW",
  106. "LD_AOUT_LIBRARY_PATH",
  107. "LD_AOUT_PRELOAD",
  108. "LD_NOWARN",
  109. "LD_KEEPDIR",
  110. NULL
  111. };
  112. const struct spwd SwShadowTemplate = {
  113. NULL,
  114. "*",
  115. 0,
  116. 0,
  117. 99999,
  118. 7,
  119. -1,
  120. -1,
  121. -1
  122. };
  123. //
  124. // ------------------------------------------------------------------ Functions
  125. //
  126. INT
  127. SwUpdatePasswordLine (
  128. struct passwd *User,
  129. struct spwd *Shadow,
  130. UPDATE_PASSWORD_OPERATION Operation
  131. )
  132. /*++
  133. Routine Description:
  134. This routine adds or updates an entry in the password database.
  135. Arguments:
  136. User - Supplies a pointer to the user information structure.
  137. Shadow - Supplies a pointer to the shadow information.
  138. Operation - Supplies the operation to perform.
  139. Return Value:
  140. 0 on success.
  141. Non-zero on failure.
  142. --*/
  143. {
  144. PSTR Gecos;
  145. PSTR Home;
  146. CHAR Line[PASSWORD_LINE_MAX];
  147. PSTR Password;
  148. int Result;
  149. PSTR Shell;
  150. assert((Operation == UpdatePasswordAddLine) ||
  151. (Operation == UpdatePasswordUpdateLine) ||
  152. (Operation == UpdatePasswordDeleteLine));
  153. Password = "x";
  154. Gecos = "";
  155. Home = "";
  156. Shell = "";
  157. if (User->pw_passwd != NULL) {
  158. Password = User->pw_passwd;
  159. }
  160. if (User->pw_gecos != NULL) {
  161. Gecos = User->pw_gecos;
  162. }
  163. if (User->pw_dir != NULL) {
  164. Home = User->pw_dir;
  165. }
  166. if (User->pw_shell != NULL) {
  167. Shell = User->pw_shell;
  168. }
  169. if ((User->pw_name[0] == '+') || (User->pw_name[0] == '-')) {
  170. Result = snprintf(Line,
  171. PASSWORD_LINE_MAX,
  172. "%s:%s:::%s:%s:%s",
  173. User->pw_name,
  174. Password,
  175. Gecos,
  176. Home,
  177. Shell);
  178. } else {
  179. Result = snprintf(Line,
  180. PASSWORD_LINE_MAX,
  181. "%s:%s:%lu:%lu:%s:%s:%s",
  182. User->pw_name,
  183. Password,
  184. (unsigned long int)(User->pw_uid),
  185. (unsigned long int)(User->pw_gid),
  186. Gecos,
  187. Home,
  188. Shell);
  189. }
  190. if ((Result >= PASSWORD_LINE_MAX) || (Result < 0)) {
  191. return ENAMETOOLONG;
  192. }
  193. Result = SwUpdatePasswordFile(PASSWD_FILE_PATH,
  194. User->pw_name,
  195. Line,
  196. NULL,
  197. Operation);
  198. if (Result != 0) {
  199. return Result;
  200. }
  201. //
  202. // Update the shadow file as well.
  203. //
  204. if (Shadow != NULL) {
  205. if (SwpPrintShadowLine(Line, PASSWORD_LINE_MAX, Shadow) < 0) {
  206. return ENAMETOOLONG;
  207. }
  208. Result = SwUpdatePasswordFile(_PATH_SHADOW,
  209. User->pw_name,
  210. Line,
  211. NULL,
  212. Operation);
  213. if (Result != 0) {
  214. return Result;
  215. }
  216. }
  217. return 0;
  218. }
  219. INT
  220. SwUpdateGroupLine (
  221. struct group *Group,
  222. UPDATE_PASSWORD_OPERATION Operation
  223. )
  224. /*++
  225. Routine Description:
  226. This routine adds or updates an entry in the group database.
  227. Arguments:
  228. Group - Supplies the group to add or update.
  229. Operation - Supplies the operation to perform.
  230. Return Value:
  231. 0 on success.
  232. Non-zero on failure.
  233. --*/
  234. {
  235. PSTR CurrentLine;
  236. ssize_t CurrentLineSize;
  237. UINTN Index;
  238. PSTR Line;
  239. PSTR Password;
  240. ssize_t Size;
  241. INT Status;
  242. Line = malloc(GROUP_LINE_MAX);
  243. if (Line == NULL) {
  244. return ENOMEM;
  245. }
  246. Password = "";
  247. if (Group->gr_passwd != NULL) {
  248. Password = Group->gr_passwd;
  249. }
  250. Size = snprintf(Line,
  251. GROUP_LINE_MAX,
  252. "%s:%s:%lu:",
  253. Group->gr_name,
  254. Password,
  255. (long unsigned int)(Group->gr_gid));
  256. if ((Size <= 0) || (Size >= GROUP_LINE_MAX)) {
  257. Status = EINVAL;
  258. goto UpdateGroupLineEnd;
  259. }
  260. CurrentLine = Line + Size;
  261. CurrentLineSize = GROUP_LINE_MAX - Size;
  262. Index = 0;
  263. if (Group->gr_mem != NULL) {
  264. while (Group->gr_mem[Index] != NULL) {
  265. if (Index == 0) {
  266. Size = snprintf(CurrentLine,
  267. CurrentLineSize,
  268. "%s",
  269. Group->gr_mem[Index]);
  270. } else {
  271. Size = snprintf(CurrentLine,
  272. CurrentLineSize,
  273. ",%s",
  274. Group->gr_mem[Index]);
  275. }
  276. if ((Size <= 0) || (Size >= CurrentLineSize)) {
  277. Status = EINVAL;
  278. goto UpdateGroupLineEnd;
  279. }
  280. CurrentLine += Size;
  281. CurrentLineSize -= Size;
  282. Index += 1;
  283. }
  284. }
  285. Status = SwUpdatePasswordFile(GROUP_FILE_PATH,
  286. Group->gr_name,
  287. Line,
  288. NULL,
  289. Operation);
  290. UpdateGroupLineEnd:
  291. if (Line != NULL) {
  292. free(Line);
  293. }
  294. return Status;
  295. }
  296. INT
  297. SwUpdatePasswordFile (
  298. PSTR FilePath,
  299. PSTR Name,
  300. PSTR NewLine,
  301. PSTR GroupMember,
  302. UPDATE_PASSWORD_OPERATION Operation
  303. )
  304. /*++
  305. Routine Description:
  306. This routine updates a password file, usually either passwd, groups,
  307. shadow, or gshadow.
  308. Arguments:
  309. FilePath - Supplies a pointer to the path of the file to update.
  310. Name - Supplies the name of the member to update.
  311. NewLine - Supplies the new line to set.
  312. GroupMember - Supplies the group member to add or remove for group
  313. operations.
  314. Operation - Supplies the operation to perform.
  315. Return Value:
  316. 0 on success.
  317. Non-zero on failure.
  318. --*/
  319. {
  320. PSTR AppendedPath;
  321. UINTN AppendedPathSize;
  322. UINTN ChangedLines;
  323. PSTR Colon;
  324. PSTR CurrentMember;
  325. char *Line;
  326. size_t LineBufferSize;
  327. ssize_t LineSize;
  328. struct flock Lock;
  329. size_t NameSize;
  330. FILE *NewFile;
  331. int NewFileDescriptor;
  332. PSTR NextComma;
  333. FILE *OldFile;
  334. mode_t OldUmask;
  335. PSTR Separator;
  336. UINTN Stall;
  337. struct stat Stat;
  338. INT Status;
  339. Line = NULL;
  340. LineBufferSize = 0;
  341. OldFile = NULL;
  342. OldUmask = umask(S_IWGRP | S_IWOTH | S_IROTH);
  343. NameSize = strlen(Name);
  344. NewFileDescriptor = -1;
  345. AppendedPathSize = strlen(FilePath) + 5;
  346. AppendedPath = malloc(AppendedPathSize);
  347. if (AppendedPath == NULL) {
  348. Status = ENOMEM;
  349. goto UpdatePasswordFileEnd;
  350. }
  351. snprintf(AppendedPath, AppendedPathSize, "%s.tmp", FilePath);
  352. OldFile = fopen(FilePath, "r+");
  353. if (OldFile == NULL) {
  354. Status = errno;
  355. SwPrintError(Status, FilePath, "Cannot open");
  356. goto UpdatePasswordFileEnd;
  357. }
  358. //
  359. // Try to open the new file, being a bit patient.
  360. //
  361. NewFileDescriptor = -1;
  362. for (Stall = 0; Stall < UPDATE_PASSWORD_WAIT; Stall += 1) {
  363. NewFileDescriptor = open(AppendedPath,
  364. O_WRONLY | O_CREAT | O_EXCL,
  365. S_IRUSR | S_IWUSR);
  366. if (NewFileDescriptor >= 0) {
  367. break;
  368. }
  369. if (errno != EEXIST) {
  370. Status = errno;
  371. SwPrintError(Status, AppendedPath, "Could not create");
  372. goto UpdatePasswordFileEnd;
  373. }
  374. sleep(1);
  375. }
  376. if (fstat(fileno(OldFile), &Stat) == 0) {
  377. fchmod(NewFileDescriptor, Stat.st_mode & ALLPERMS);
  378. Status = fchown(NewFileDescriptor, Stat.st_uid, Stat.st_gid);
  379. if (Status != 0) {
  380. Status = errno;
  381. goto UpdatePasswordFileEnd;
  382. }
  383. }
  384. if (NewFileDescriptor <= 0) {
  385. Status = errno;
  386. SwPrintError(Status, AppendedPath, "Could not create");
  387. goto UpdatePasswordFileEnd;
  388. }
  389. NewFile = fdopen(NewFileDescriptor, "w");
  390. if (NewFile == NULL) {
  391. Status = errno;
  392. goto UpdatePasswordFileEnd;
  393. }
  394. NewFileDescriptor = -1;
  395. //
  396. // Lock the file.
  397. //
  398. Lock.l_type = F_WRLCK;
  399. Lock.l_whence = SEEK_SET;
  400. Lock.l_start = 0;
  401. Lock.l_len = 0;
  402. if (fcntl(fileno(OldFile), F_SETLK, &Lock) < 0) {
  403. Status = errno;
  404. SwPrintError(Status, FilePath, "Cannot lock file");
  405. goto UpdatePasswordFileEnd;
  406. }
  407. ChangedLines = 0;
  408. while (TRUE) {
  409. LineSize = getline(&Line, &LineBufferSize, OldFile);
  410. if (LineSize <= 0) {
  411. break;
  412. }
  413. while ((LineSize > 0) && (isspace(Line[LineSize - 1]) != 0)) {
  414. Line[LineSize - 1] = '\0';
  415. LineSize -= 1;
  416. }
  417. //
  418. // If the line is uninteresting, spit it to the output and move on.
  419. //
  420. if ((strncmp(Line, Name, NameSize) != 0) || (Line[NameSize] != ':')) {
  421. fprintf(NewFile, "%s\n", Line);
  422. continue;
  423. }
  424. //
  425. // Add or remove a member from a group.
  426. //
  427. if (GroupMember != NULL) {
  428. if (Operation == UpdatePasswordAddGroupMember) {
  429. Separator = ",";
  430. if (Line[LineSize - 1] == ':') {
  431. Separator = "";
  432. }
  433. fprintf(NewFile, "%s%s%s\n", Line, Separator, GroupMember);
  434. ChangedLines += 1;
  435. //
  436. // Delete a user from a group.
  437. //
  438. } else {
  439. assert(Operation == UpdatePasswordDeleteGroupMember);
  440. Colon = strrchr(Line, ':');
  441. if (Colon == NULL) {
  442. fprintf(NewFile, "%s\n", Line);
  443. continue;
  444. }
  445. //
  446. // Write out everything up to the group list.
  447. //
  448. *Colon = '\0';
  449. fprintf(NewFile, "%s:", Line);
  450. //
  451. // Loop writing out the members, unless it's the member of
  452. // honor.
  453. //
  454. Separator = "";
  455. CurrentMember = Colon + 1;
  456. while (CurrentMember != NULL) {
  457. NextComma = strchr(CurrentMember, ',');
  458. if (NextComma != NULL) {
  459. *NextComma = '\0';
  460. NextComma += 1;
  461. }
  462. if (strcmp(CurrentMember, GroupMember) != 0) {
  463. fprintf(NewFile, "%s%s", Separator, CurrentMember);
  464. Separator = ",";
  465. } else {
  466. ChangedLines += 1;
  467. }
  468. CurrentMember = NextComma;
  469. }
  470. fprintf(NewFile, "\n");
  471. }
  472. //
  473. // There is no group member, this must be a passwd or shadow update.
  474. //
  475. } else {
  476. if ((Operation == UpdatePasswordAddLine) ||
  477. (Operation == UpdatePasswordUpdateLine)) {
  478. fprintf(NewFile, "%s\n", NewLine);
  479. ChangedLines += 1;
  480. //
  481. // For deleting an entry, just do nothing, and it won't make it to
  482. // the output file.
  483. //
  484. } else {
  485. assert(Operation == UpdatePasswordDeleteLine);
  486. ChangedLines += 1;
  487. }
  488. }
  489. }
  490. Status = 0;
  491. if (ChangedLines == 0) {
  492. if (Operation != UpdatePasswordAddLine) {
  493. SwPrintError(0, NULL, "Cannot find '%s' in '%s'", Name, FilePath);
  494. Status = 1;
  495. } else {
  496. fprintf(NewFile, "%s\n", NewLine);
  497. ChangedLines += 1;
  498. }
  499. }
  500. //
  501. // Unlock the password file.
  502. //
  503. Lock.l_type = F_UNLCK;
  504. fcntl(fileno(OldFile), F_SETLK, &Lock);
  505. errno = 0;
  506. fflush(NewFile);
  507. fsync(fileno(NewFile));
  508. fclose(NewFile);
  509. NewFile = NULL;
  510. if (errno != 0) {
  511. Status = errno;
  512. SwPrintError(Status, AppendedPath, "Failed to sync/close");
  513. goto UpdatePasswordFileEnd;
  514. }
  515. if (rename(AppendedPath, FilePath) != 0) {
  516. Status = errno;
  517. SwPrintError(Status, FilePath, "Failed to move");
  518. goto UpdatePasswordFileEnd;
  519. }
  520. Status = 0;
  521. UpdatePasswordFileEnd:
  522. umask(OldUmask);
  523. if (OldFile != NULL) {
  524. fclose(OldFile);
  525. }
  526. if (Status != 0) {
  527. if (AppendedPath != NULL) {
  528. unlink(AppendedPath);
  529. }
  530. }
  531. if (AppendedPath != NULL) {
  532. free(AppendedPath);
  533. }
  534. if (NewFileDescriptor >= 0) {
  535. close(NewFileDescriptor);
  536. }
  537. if (Line != NULL) {
  538. free(Line);
  539. }
  540. return Status;
  541. }
  542. PSTR
  543. SwCreateHashedPassword (
  544. PSTR Algorithm,
  545. int RandomSource,
  546. UINTN Rounds,
  547. PSTR Password
  548. )
  549. /*++
  550. Routine Description:
  551. This routine creates a hashed password, choosing an algorithm and a salt.
  552. Arguments:
  553. Algorithm - Supplies the algorithm to use. Valid values are something like
  554. "$1$", "$5$", or "$6$".
  555. RandomSource - Supplies an optional file descriptor sourcing random data.
  556. Rounds - Supplies the rounds parameter for SHA256 and SHA512 algorithms.
  557. Supply 0 to use a default value.
  558. Password - Supplies the plaintext password to encode.
  559. Return Value:
  560. Returns a pointer to the hashed password on success. This comes from a
  561. static buffer and may be overwritten by subsequent calls to this function.
  562. NULL on failure.
  563. --*/
  564. {
  565. ssize_t BytesRead;
  566. char Salt[17];
  567. int SaltIndex;
  568. CHAR SaltLine[64];
  569. int URandom;
  570. if (RandomSource >= 0) {
  571. URandom = RandomSource;
  572. } else {
  573. URandom = open(URANDOM_PATH, O_RDONLY);
  574. if (URandom < 0) {
  575. SwPrintError(errno, URANDOM_PATH, "Failed to open random source");
  576. return NULL;
  577. }
  578. }
  579. do {
  580. BytesRead = read(URandom, Salt, sizeof(Salt));
  581. } while ((BytesRead < 0) && (errno == EINTR));
  582. if (URandom != RandomSource) {
  583. close(URandom);
  584. }
  585. if (BytesRead != sizeof(Salt)) {
  586. SwPrintError(errno, URANDOM_PATH, "Failed to read random source");
  587. return NULL;
  588. }
  589. for (SaltIndex = 0; SaltIndex < sizeof(Salt); SaltIndex += 1) {
  590. Salt[SaltIndex] = SALT_ALPHABET[(UCHAR)(Salt[SaltIndex]) % 62];
  591. }
  592. Salt[sizeof(Salt) - 1] = '\0';
  593. //
  594. // Only a couple algorithms support rounds, namely SHA256 and SHA512.
  595. //
  596. if ((Rounds != 0) &&
  597. (strcmp(Algorithm, "$5$") != 0) &&
  598. (strcmp(Algorithm, "$6$") != 0)) {
  599. Rounds = 0;
  600. }
  601. if (Rounds == 0) {
  602. snprintf(SaltLine,
  603. sizeof(SaltLine),
  604. "%s%s",
  605. Algorithm,
  606. Salt);
  607. } else {
  608. if (Rounds < PASSWORD_ROUNDS_MIN) {
  609. Rounds = PASSWORD_ROUNDS_MIN;
  610. } else if (Rounds > PASSWORD_ROUNDS_MAX) {
  611. Rounds = PASSWORD_ROUNDS_MAX;
  612. }
  613. snprintf(SaltLine,
  614. sizeof(SaltLine),
  615. "%srounds=%d$%s",
  616. Algorithm,
  617. (int)Rounds,
  618. Salt);
  619. }
  620. return SwCrypt(Password, SaltLine);
  621. }
  622. INT
  623. SwCheckAccount (
  624. struct passwd *User
  625. )
  626. /*++
  627. Routine Description:
  628. This routine validates that the account is enabled and can be logged in via
  629. password.
  630. Arguments:
  631. User - Supplies a pointer to the user to get information for.
  632. Return Value:
  633. 0 if account is enabled.
  634. Non-zero if the account cannot be logged in to via password.
  635. --*/
  636. {
  637. PSTR HashedPassword;
  638. struct spwd *Shadow;
  639. HashedPassword = User->pw_passwd;
  640. Shadow = getspnam(User->pw_name);
  641. if ((Shadow == NULL) && (errno != ENOENT)) {
  642. SwPrintError(errno,
  643. User->pw_name,
  644. "Error: Could not read password information for user");
  645. return EACCES;
  646. }
  647. if (Shadow != NULL) {
  648. HashedPassword = Shadow->sp_pwdp;
  649. }
  650. if (*HashedPassword == '\0') {
  651. return 0;
  652. }
  653. if (*HashedPassword == '!') {
  654. SwPrintError(0, NULL, "Account locked");
  655. return EACCES;
  656. }
  657. if ((!isalnum(*HashedPassword)) &&
  658. (*HashedPassword != '/') &&
  659. (*HashedPassword != '.') &&
  660. (*HashedPassword != '_') &&
  661. (*HashedPassword != '$')) {
  662. SwPrintError(0, NULL, "Account disabled");
  663. return EACCES;
  664. }
  665. return 0;
  666. }
  667. INT
  668. SwGetAndCheckPassword (
  669. struct passwd *User,
  670. PSTR Prompt
  671. )
  672. /*++
  673. Routine Description:
  674. This routine asks for and validates the password for the given user.
  675. Arguments:
  676. User - Supplies a pointer to the user to get information for.
  677. Prompt - Supplies an optional pointer to the prompt to use. Supply NULL
  678. to use the prompt "Enter password:".
  679. Return Value:
  680. 0 if the password matched.
  681. EPERM if the password did not match.
  682. EACCES if the account is locked or expired.
  683. Other error codes on other failures.
  684. --*/
  685. {
  686. BOOL Correct;
  687. PSTR HashedPassword;
  688. PSTR Password;
  689. struct spwd *Shadow;
  690. HashedPassword = NULL;
  691. if (User != NULL) {
  692. HashedPassword = User->pw_passwd;
  693. Shadow = getspnam(User->pw_name);
  694. if ((Shadow == NULL) && (errno != ENOENT)) {
  695. SwPrintError(errno,
  696. User->pw_name,
  697. "Error: Could not read password information for user");
  698. return EACCES;
  699. }
  700. if (Shadow != NULL) {
  701. HashedPassword = Shadow->sp_pwdp;
  702. }
  703. if (*HashedPassword == '!') {
  704. SwPrintError(0, NULL, "Account locked");
  705. return EACCES;
  706. }
  707. //
  708. // If the password is empty just return success, no need to ask really.
  709. //
  710. if (*HashedPassword == '\0') {
  711. return 0;
  712. }
  713. }
  714. if (Prompt == NULL) {
  715. Prompt = "Enter password: ";
  716. }
  717. Password = getpass(Prompt);
  718. if (Password == NULL) {
  719. if (errno != 0) {
  720. return errno;
  721. }
  722. return EACCES;
  723. }
  724. if (User == NULL) {
  725. return EPERM;
  726. }
  727. Correct = SwCheckPassword(Password, HashedPassword);
  728. memset(Password, 0, strlen(Password));
  729. if (Correct != FALSE) {
  730. return 0;
  731. }
  732. return EPERM;
  733. }
  734. BOOL
  735. SwCheckPassword (
  736. PSTR Password,
  737. PSTR EncryptedPassword
  738. )
  739. /*++
  740. Routine Description:
  741. This routine checks a password against its hash.
  742. Arguments:
  743. Password - Supplies a pointer to the plaintext password to check.
  744. EncryptedPassword - Supplies the password hash.
  745. Return Value:
  746. TRUE if the passwords match.
  747. FALSE if the passwords do not match.
  748. --*/
  749. {
  750. PSTR Result;
  751. Result = SwCrypt(Password, EncryptedPassword);
  752. assert(Result != EncryptedPassword);
  753. if (strcmp(Result, EncryptedPassword) == 0) {
  754. return TRUE;
  755. }
  756. return FALSE;
  757. }
  758. PSTR
  759. SwCrypt (
  760. PSTR Password,
  761. PSTR Salt
  762. )
  763. /*++
  764. Routine Description:
  765. This routine calls the crypt function off in libcrypt.
  766. Arguments:
  767. Password - Supplies the plaintext password to encode.
  768. Salt - Supplies the algorithm and salt information.
  769. Return Value:
  770. Returns a pointer to the hashed password on success. This comes from a
  771. static buffer and may be overwritten by subsequent calls to this function.
  772. NULL on failure.
  773. --*/
  774. {
  775. //
  776. // Get the address of the crypt function from libcrypt if not found already.
  777. //
  778. if (SwCryptFunction == NULL) {
  779. if (SwLibCrypt == NULL) {
  780. SwLibCrypt = dlopen(LIBCRYPT_PATH, 0);
  781. if (SwLibCrypt == NULL) {
  782. SwPrintError(0,
  783. NULL,
  784. "Failed to open %s: %s",
  785. LIBCRYPT_PATH,
  786. dlerror());
  787. return NULL;
  788. }
  789. }
  790. SwCryptFunction = dlsym(SwLibCrypt, "crypt");
  791. if (SwCryptFunction == NULL) {
  792. SwPrintError(0, NULL, "Failed to find crypt in libcrypt.so");
  793. return NULL;
  794. }
  795. }
  796. if (Password == NULL) {
  797. return NULL;
  798. }
  799. return SwCryptFunction(Password, Salt);
  800. }
  801. BOOL
  802. SwIsValidUserName (
  803. PSTR Name
  804. )
  805. /*++
  806. Routine Description:
  807. This routine validates that the given username doesn't have any invalid
  808. characters.
  809. Arguments:
  810. Name - Supplies a pointer to the user name to check.
  811. Return Value:
  812. TRUE if it is valid.
  813. FALSE if it is not valid.
  814. --*/
  815. {
  816. PSTR Start;
  817. Start = Name;
  818. if ((*Name == '-') || (*Name == '.') || (*Name == '\0')) {
  819. return FALSE;
  820. }
  821. while (*Name != '\0') {
  822. if ((*Name != '_') && (!isalnum(*Name)) && (*Name != '.') &&
  823. (*Name != '-')) {
  824. return FALSE;
  825. }
  826. Name += 1;
  827. }
  828. if (*(Name - 1) == '$') {
  829. return FALSE;
  830. }
  831. if (Name - Start >= LOGIN_NAME_MAX) {
  832. return FALSE;
  833. }
  834. return TRUE;
  835. }
  836. INT
  837. SwBecomeUser (
  838. struct passwd *User
  839. )
  840. /*++
  841. Routine Description:
  842. This routine changes the current identity to that of the given user,
  843. including the real user ID, group ID, and supplementary groups.
  844. Arguments:
  845. User - Supplies a pointer to the user to become.
  846. Return Value:
  847. None.
  848. --*/
  849. {
  850. INT Result;
  851. INT Status;
  852. Status = 0;
  853. Result = initgroups(User->pw_name, User->pw_gid);
  854. if (Result < 0) {
  855. Status = errno;
  856. SwPrintError(Status, User->pw_name, "Failed to init groups for");
  857. if (Status == EPERM) {
  858. return Status;
  859. }
  860. }
  861. Result = setgid(User->pw_gid);
  862. if (Result < 0) {
  863. Status = errno;
  864. SwPrintError(Status, User->pw_name, "Failed to set gid for");
  865. }
  866. Result = setuid(User->pw_uid);
  867. if (Result < 0) {
  868. Status = errno;
  869. SwPrintError(Status, User->pw_name, "Failed to set uid for");
  870. }
  871. return Status;
  872. }
  873. VOID
  874. SwSetupUserEnvironment (
  875. struct passwd *User,
  876. PSTR Shell,
  877. ULONG Flags
  878. )
  879. /*++
  880. Routine Description:
  881. This routine changes the current identity to that of the given user,
  882. including the real user ID, group ID, and supplementary groups.
  883. Arguments:
  884. User - Supplies a pointer to the user to set up for.
  885. Shell - Supplies a pointer to the shell to use. If not specified
  886. the ever-classic /bin/sh will be used.
  887. Flags - Supplies a bitfield of flags. See SETUP_USER_ENVIRONMENT_*
  888. definitions.
  889. Return Value:
  890. None.
  891. --*/
  892. {
  893. PSTR Path;
  894. PSTR Terminal;
  895. if ((Shell == NULL) || (*Shell == '\0')) {
  896. Shell = USER_FALLBACK_SHELL;
  897. }
  898. //
  899. // Change the current directory to the user's home directory.
  900. //
  901. if ((Flags & SETUP_USER_ENVIRONMENT_NO_DIRECTORY) == 0) {
  902. if ((User->pw_dir != NULL) && (User->pw_dir[0] != '\0')) {
  903. if (chdir(User->pw_dir) < 0) {
  904. SwPrintError(errno, User->pw_dir, "Cannot change to directory");
  905. }
  906. }
  907. }
  908. //
  909. // If the caller wants to clear the environment, wipe out everything.
  910. // Preserve TERM.
  911. //
  912. if ((Flags & SETUP_USER_ENVIRONMENT_CLEAR_ENVIRONMENT) != 0) {
  913. Terminal = getenv("TERM");
  914. environ = NULL;
  915. if (Terminal != NULL) {
  916. setenv("TERM", Terminal, 1);
  917. }
  918. Path = USER_DEFAULT_PATH;
  919. if (User->pw_uid == 0) {
  920. Path = SUPERUSER_DEFAULT_PATH;
  921. }
  922. setenv("PATH", Path, 1);
  923. setenv("USER", User->pw_name, 1);
  924. setenv("LOGNAME", User->pw_name, 1);
  925. setenv("HOME", User->pw_dir, 1);
  926. setenv("SHELL", Shell, 1);
  927. } else if ((Flags & SETUP_USER_ENVIRONMENT_CHANGE_ENVIRONMENT) != 0) {
  928. if (User->pw_uid != 0) {
  929. setenv("USER", User->pw_name, 1);
  930. setenv("LOGNAME", User->pw_name, 1);
  931. }
  932. setenv("HOME", User->pw_dir, 1);
  933. setenv("SHELL", Shell, 1);
  934. }
  935. return;
  936. }
  937. VOID
  938. SwExecuteShell (
  939. PSTR Shell,
  940. BOOL LoginShell,
  941. PSTR Command,
  942. PSTR *AdditionalArguments
  943. )
  944. /*++
  945. Routine Description:
  946. This routine execs this program into a shell program with the given
  947. arguments.
  948. Arguments:
  949. Shell - Supplies a pointer to the shell to use. If not specified
  950. the ever-classic /bin/sh will be used.
  951. LoginShell - Supplies a boolean indicating if this is a login shell or
  952. not.
  953. Command - Supplies the command to run.
  954. AdditionalArguments - Supplies an array of the additional arguments.
  955. Return Value:
  956. None. On success, this routine does not return.
  957. --*/
  958. {
  959. UINTN ArgumentCount;
  960. PSTR *Arguments;
  961. UINTN Index;
  962. PSTR LastSlash;
  963. PSTR LoginLine;
  964. LoginLine = NULL;
  965. ArgumentCount = 0;
  966. if (AdditionalArguments != NULL) {
  967. while (AdditionalArguments[ArgumentCount] != NULL) {
  968. ArgumentCount += 1;
  969. }
  970. }
  971. //
  972. // Add four extra for the sh, -c, command, and NULL.
  973. //
  974. Arguments = malloc(sizeof(PSTR) * (ArgumentCount + 4));
  975. if (Arguments == NULL) {
  976. return;
  977. }
  978. if ((Shell == NULL) || (*Shell == '\0')) {
  979. Shell = USER_FALLBACK_SHELL;
  980. }
  981. LastSlash = strrchr(Shell, '/');
  982. if ((LastSlash == NULL) ||
  983. ((LastSlash == Shell) && (LastSlash[1] == '\0'))) {
  984. LastSlash = Shell;
  985. } else {
  986. LastSlash += 1;
  987. }
  988. Arguments[0] = LastSlash;
  989. if (LoginShell != FALSE) {
  990. LoginLine = malloc(strlen(LastSlash) + 2);
  991. if (LoginLine != NULL) {
  992. *LoginLine = '-';
  993. strcpy(LoginLine + 1, LastSlash);
  994. Arguments[0] = LoginLine;
  995. }
  996. }
  997. Index = 1;
  998. if (Command != NULL) {
  999. Arguments[Index] = "-c";
  1000. Index += 1;
  1001. Arguments[Index] = Command;
  1002. Index += 1;
  1003. }
  1004. if (AdditionalArguments != NULL) {
  1005. while (*AdditionalArguments != NULL) {
  1006. Arguments[Index] = *AdditionalArguments;
  1007. Index += 1;
  1008. AdditionalArguments += 1;
  1009. }
  1010. }
  1011. Arguments[Index] = NULL;
  1012. assert(Index < ArgumentCount + 4);
  1013. execv(Shell, Arguments);
  1014. SwPrintError(errno, Shell, "Cannot execute");
  1015. free(Arguments);
  1016. if (LoginLine != NULL) {
  1017. free(LoginLine);
  1018. }
  1019. return;
  1020. }
  1021. VOID
  1022. SwSanitizeEnvironment (
  1023. VOID
  1024. )
  1025. /*++
  1026. Routine Description:
  1027. This routine removes several dangerous environment variables from the
  1028. environment, and resets the PATH.
  1029. Arguments:
  1030. None.
  1031. Return Value:
  1032. None.
  1033. --*/
  1034. {
  1035. PSTR *Variable;
  1036. Variable = &(SwDangerousEnvironmentVariables[0]);
  1037. while (*Variable != NULL) {
  1038. unsetenv(*Variable);
  1039. Variable += 1;
  1040. }
  1041. if (geteuid() != 0) {
  1042. setenv("PATH", USER_DEFAULT_PATH, 1);
  1043. } else {
  1044. setenv("PATH", SUPERUSER_DEFAULT_PATH, 1);
  1045. }
  1046. return;
  1047. }
  1048. VOID
  1049. SwPrintLoginPrompt (
  1050. VOID
  1051. )
  1052. /*++
  1053. Routine Description:
  1054. This routine prints the standard login prompt.
  1055. Arguments:
  1056. None.
  1057. Return Value:
  1058. None.
  1059. --*/
  1060. {
  1061. struct utsname SystemInformation;
  1062. memset(&SystemInformation, 0, sizeof(SystemInformation));
  1063. uname(&SystemInformation);
  1064. printf("%s login: ", SystemInformation.nodename);
  1065. fflush(NULL);
  1066. return;
  1067. }
  1068. VOID
  1069. SwUpdateUtmp (
  1070. pid_t ProcessId,
  1071. int NewType,
  1072. PSTR TerminalName,
  1073. PSTR UserName,
  1074. PSTR HostName
  1075. )
  1076. /*++
  1077. Routine Description:
  1078. This routine updates a utmp entry, and potentially wtmp as well.
  1079. Arguments:
  1080. ProcessId - Supplies the current process ID.
  1081. NewType - Supplies the type of entry to add.
  1082. TerminalName - Supplies a pointer to the terminal name.
  1083. UserName - Supplies a pointer to the user name.
  1084. HostName - Supplies a pointer to the host name.
  1085. Return Value:
  1086. None.
  1087. --*/
  1088. {
  1089. struct utmpx Copy;
  1090. int Descriptor;
  1091. struct utmpx *Entry;
  1092. struct utmp Utmp;
  1093. //
  1094. // Create the file if it does not exist.
  1095. //
  1096. if (access(_PATH_UTMPX, R_OK | W_OK) < 0) {
  1097. Descriptor = open(_PATH_UTMPX,
  1098. O_WRONLY | O_CREAT,
  1099. S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  1100. if (Descriptor >= 0) {
  1101. close(Descriptor);
  1102. }
  1103. }
  1104. setutxent();
  1105. while (TRUE) {
  1106. Entry = getutxent();
  1107. if (Entry == NULL) {
  1108. break;
  1109. }
  1110. if ((Entry->ut_pid == ProcessId) &&
  1111. (Entry->ut_id[0] != 0) &&
  1112. ((Entry->ut_type == INIT_PROCESS) ||
  1113. (Entry->ut_type == LOGIN_PROCESS) ||
  1114. (Entry->ut_type == USER_PROCESS) ||
  1115. (Entry->ut_type == DEAD_PROCESS))) {
  1116. if (Entry->ut_type == NewType) {
  1117. memset(Entry->ut_host, 0, sizeof(Entry->ut_host));
  1118. }
  1119. break;
  1120. }
  1121. }
  1122. if (Entry == NULL) {
  1123. if (NewType == DEAD_PROCESS) {
  1124. SwpWriteNewUtmpEntry(ProcessId,
  1125. NewType,
  1126. TerminalName,
  1127. UserName,
  1128. HostName);
  1129. } else {
  1130. endutxent();
  1131. }
  1132. } else {
  1133. memcpy(&Copy, Entry, sizeof(struct utmpx));
  1134. Copy.ut_type = NewType;
  1135. if (TerminalName != NULL) {
  1136. strncpy(Copy.ut_line, TerminalName, sizeof(Copy.ut_line));
  1137. }
  1138. if (UserName != NULL) {
  1139. strncpy(Copy.ut_user, UserName, sizeof(Copy.ut_user));
  1140. }
  1141. if (HostName != NULL) {
  1142. strncpy(Copy.ut_host, HostName, sizeof(Copy.ut_host));
  1143. }
  1144. Copy.ut_tv.tv_sec = time(NULL);
  1145. pututxline(&Copy);
  1146. endutxent();
  1147. getutmp(&Copy, &Utmp);
  1148. updwtmp(_PATH_WTMP, &Utmp);
  1149. }
  1150. return;
  1151. }
  1152. VOID
  1153. SwPrintLoginIssue (
  1154. PSTR IssuePath,
  1155. PSTR TerminalName
  1156. )
  1157. /*++
  1158. Routine Description:
  1159. This routine prints the login issue file to standard out.
  1160. Arguments:
  1161. IssuePath - Supplies an optional path to the issue file. If not specified,
  1162. the default of /etc/issue will be used.
  1163. TerminalName - Supplies the name of this terminal, used for expanding %l
  1164. escapes in the issue file.
  1165. Return Value:
  1166. None.
  1167. --*/
  1168. {
  1169. CHAR Buffer[256];
  1170. INT Character;
  1171. FILE *Issue;
  1172. PSTR String;
  1173. struct utsname SystemInformation;
  1174. time_t Time;
  1175. if (IssuePath == NULL) {
  1176. IssuePath = ISSUE_PATH;
  1177. }
  1178. Issue = fopen(IssuePath, "r");
  1179. if (Issue == NULL) {
  1180. return;
  1181. }
  1182. Time = time(NULL);
  1183. uname(&SystemInformation);
  1184. while (TRUE) {
  1185. Character = fgetc(Issue);
  1186. if (Character == EOF) {
  1187. break;
  1188. }
  1189. String = Buffer;
  1190. Buffer[0] = Character;
  1191. Buffer[1] = '\0';
  1192. if (Character == '\n') {
  1193. Buffer[1] = '\r';
  1194. Buffer[2] = '\0';
  1195. } else if ((Character == '\\') || (Character == '%')) {
  1196. Character = fgetc(Issue);
  1197. if (Character == EOF) {
  1198. break;
  1199. }
  1200. switch (Character) {
  1201. case 's':
  1202. String = SystemInformation.sysname;
  1203. break;
  1204. case 'n':
  1205. case 'h':
  1206. String = SystemInformation.nodename;
  1207. break;
  1208. case 'r':
  1209. String = SystemInformation.release;
  1210. break;
  1211. case 'v':
  1212. String = SystemInformation.version;
  1213. break;
  1214. case 'm':
  1215. String = SystemInformation.machine;
  1216. break;
  1217. case 'D':
  1218. case 'o':
  1219. String = SystemInformation.domainname;
  1220. break;
  1221. case 'd':
  1222. strftime(Buffer,
  1223. sizeof(Buffer),
  1224. "%A, %d %B %Y",
  1225. localtime(&Time));
  1226. break;
  1227. case 't':
  1228. strftime(Buffer, sizeof(Buffer), "%H:%M:%S", localtime(&Time));
  1229. break;
  1230. case 'l':
  1231. String = TerminalName;
  1232. break;
  1233. default:
  1234. Buffer[0] = Character;
  1235. break;
  1236. }
  1237. }
  1238. fputs(String, stdout);
  1239. }
  1240. fclose(Issue);
  1241. fflush(NULL);
  1242. return;
  1243. }
  1244. //
  1245. // --------------------------------------------------------- Internal Functions
  1246. //
  1247. INT
  1248. SwpPrintShadowLine (
  1249. PSTR Line,
  1250. UINTN LineSize,
  1251. struct spwd *Shadow
  1252. )
  1253. /*++
  1254. Routine Description:
  1255. This routine prints a shadow entry to a line.
  1256. Arguments:
  1257. Line - Supplies the line where the entry will be returned.
  1258. LineSize - Supplies the size of the line buffer.
  1259. Shadow - Supplies the shadow structure.
  1260. Return Value:
  1261. 0 on success.
  1262. Non-zero if the line was too small.
  1263. --*/
  1264. {
  1265. ssize_t Size;
  1266. Size = snprintf(Line, LineSize, "%s:", Shadow->sp_namp);
  1267. if (Size > 0) {
  1268. Line += Size;
  1269. LineSize -= Size;
  1270. }
  1271. if (Shadow->sp_pwdp != NULL) {
  1272. Size = snprintf(Line, LineSize, "%s:", Shadow->sp_pwdp);
  1273. if (Size > 0) {
  1274. Line += Size;
  1275. LineSize -= Size;
  1276. }
  1277. } else {
  1278. if (LineSize > 0) {
  1279. *Line = ':';
  1280. Line += 1;
  1281. LineSize -= 1;
  1282. }
  1283. }
  1284. if (Shadow->sp_lstchg != (long int)-1) {
  1285. Size = snprintf(Line, LineSize, "%ld:", (long int)(Shadow->sp_lstchg));
  1286. if (Size > 0) {
  1287. Line += Size;
  1288. LineSize -= Size;
  1289. }
  1290. } else {
  1291. if (LineSize > 0) {
  1292. *Line = ':';
  1293. Line += 1;
  1294. LineSize -= 1;
  1295. }
  1296. }
  1297. if (Shadow->sp_min != (long int)-1) {
  1298. Size = snprintf(Line, LineSize, "%ld:", Shadow->sp_min);
  1299. if (Size > 0) {
  1300. Line += Size;
  1301. LineSize -= Size;
  1302. }
  1303. } else {
  1304. if (LineSize > 0) {
  1305. *Line = ':';
  1306. Line += 1;
  1307. LineSize -= 1;
  1308. }
  1309. }
  1310. if (Shadow->sp_max != (long int)-1) {
  1311. Size = snprintf(Line, LineSize, "%ld:", Shadow->sp_max);
  1312. if (Size > 0) {
  1313. Line += Size;
  1314. LineSize -= Size;
  1315. }
  1316. } else {
  1317. if (LineSize > 0) {
  1318. *Line = ':';
  1319. Line += 1;
  1320. LineSize -= 1;
  1321. }
  1322. }
  1323. if (Shadow->sp_warn != (long int)-1) {
  1324. Size = snprintf(Line, LineSize, "%ld:", Shadow->sp_warn);
  1325. if (Size > 0) {
  1326. Line += Size;
  1327. LineSize -= Size;
  1328. }
  1329. } else {
  1330. if (LineSize > 0) {
  1331. *Line = ':';
  1332. Line += 1;
  1333. LineSize -= 1;
  1334. }
  1335. }
  1336. if (Shadow->sp_inact != (long int)-1) {
  1337. Size = snprintf(Line, LineSize, "%ld:", Shadow->sp_inact);
  1338. if (Size > 0) {
  1339. Line += Size;
  1340. LineSize -= Size;
  1341. }
  1342. } else {
  1343. if (LineSize > 0) {
  1344. *Line = ':';
  1345. Line += 1;
  1346. LineSize -= 1;
  1347. }
  1348. }
  1349. if (Shadow->sp_expire!= (long int)-1) {
  1350. Size = snprintf(Line, LineSize, "%ld:", Shadow->sp_expire);
  1351. if (Size > 0) {
  1352. Line += Size;
  1353. LineSize -= Size;
  1354. }
  1355. } else {
  1356. if (LineSize > 0) {
  1357. *Line = ':';
  1358. Line += 1;
  1359. LineSize -= 1;
  1360. }
  1361. }
  1362. if (Shadow->sp_flag != (unsigned long int)-1) {
  1363. Size = snprintf(Line, LineSize, "%lu", Shadow->sp_flag);
  1364. if (Size > 0) {
  1365. Line += Size;
  1366. LineSize -= Size;
  1367. }
  1368. }
  1369. if (LineSize > 0) {
  1370. *Line = '\0';
  1371. return 0;
  1372. }
  1373. return -1;
  1374. }
  1375. VOID
  1376. SwpWriteNewUtmpEntry (
  1377. pid_t ProcessId,
  1378. int NewType,
  1379. PSTR TerminalName,
  1380. PSTR UserName,
  1381. PSTR HostName
  1382. )
  1383. /*++
  1384. Routine Description:
  1385. This routine writes a new a utmp entry.
  1386. Arguments:
  1387. ProcessId - Supplies the current process ID.
  1388. NewType - Supplies the type of entry to add.
  1389. TerminalName - Supplies a pointer to the terminal name.
  1390. UserName - Supplies a pointer to the user name.
  1391. HostName - Supplies a pointer to the host name.
  1392. Return Value:
  1393. None.
  1394. --*/
  1395. {
  1396. struct utmpx Entry;
  1397. char *Id;
  1398. UINTN Index;
  1399. PSTR TerminalEnd;
  1400. UINTN Width;
  1401. memset(&Entry, 0, sizeof(struct utmpx));
  1402. Entry.ut_pid = ProcessId;
  1403. Entry.ut_type = NewType;
  1404. if (TerminalName != NULL) {
  1405. strncpy(Entry.ut_line, TerminalName, sizeof(Entry.ut_line));
  1406. }
  1407. if (UserName != NULL) {
  1408. strncpy(Entry.ut_user, UserName, sizeof(Entry.ut_user));
  1409. }
  1410. if (HostName != NULL) {
  1411. strncpy(Entry.ut_host, HostName, sizeof(Entry.ut_host));
  1412. }
  1413. Entry.ut_tv.tv_sec = time(NULL);
  1414. Id = Entry.ut_id;
  1415. Width = sizeof(Entry.ut_id);
  1416. assert(Width != 0);
  1417. if (TerminalName != NULL) {
  1418. //
  1419. // Fill the ID with zero characters.
  1420. //
  1421. for (Index = 0; Index < Width; Index += 1) {
  1422. Id[Index] = '0';
  1423. }
  1424. //
  1425. // Add all digits on the end.
  1426. //
  1427. Index = Width - 1;
  1428. TerminalEnd = TerminalName + strlen(TerminalName);
  1429. if (TerminalEnd != TerminalName) {
  1430. TerminalEnd -= 1;
  1431. while (TerminalEnd >= TerminalName) {
  1432. if (!isdigit(*TerminalEnd)) {
  1433. break;
  1434. }
  1435. Id[Index] = *TerminalEnd;
  1436. if (Index == 0) {
  1437. break;
  1438. }
  1439. Index -= 1;
  1440. TerminalEnd -= 1;
  1441. }
  1442. }
  1443. }
  1444. setutxent();
  1445. pututxline(&Entry);
  1446. endutxent();
  1447. return;
  1448. }