12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955 |
- /*++
- Copyright (c) 2015 Minoca Corp. All Rights Reserved
- Module Name:
- lutil.c
- Abstract:
- This module implements utility functions for the login commands.
- Author:
- Evan Green 10-Mar-2015
- Environment:
- POSIX
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #define _GNU_SOURCE 1
- #include <minoca/lib/types.h>
- #include <assert.h>
- #include <ctype.h>
- #include <dirent.h>
- #include <dlfcn.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/utsname.h>
- #include <unistd.h>
- #include <utmp.h>
- #include <utmpx.h>
- #include "../swlib.h"
- #include "lutil.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define UPDATE_PASSWORD_WAIT 10
- #define PASSWORD_LINE_MAX 2048
- #define GROUP_LINE_MAX 4096
- #define LIBCRYPT_PATH "/lib/libcrypt.so.1"
- #define SALT_ALPHABET \
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
- #define PASSWORD_ROUNDS_MIN 1000
- #define PASSWORD_ROUNDS_MAX 999999999
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef
- char *
- (*PCRYPT_FUNCTION) (
- const char *Key,
- const char *Salt
- );
- /*++
- Routine Description:
- This routine encrypts a user's password using various encryption/hashing
- standards. The default is DES, which is fairly weak and subject to
- dictionary attacks.
- Arguments:
- Key - Supplies the key, a user's plaintext password.
- Salt - Supplies a two character salt to use to perterb the results. If this
- string starts with a $ and a number, alternate hashing algorithms are
- selected. The format is $id$salt$encrypted. ID can be 1 for MD5, 5 for
- SHA-256, or 6 for SHA-512.
- Return Value:
- Returns a pointer to the encrypted password (plus ID and salt information
- in cases where an alternate mechanism is used). This is a static buffer,
- which may be overwritten by subsequent calls to crypt.
- --*/
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- INT
- SwpPrintShadowLine (
- PSTR Line,
- UINTN LineSize,
- struct spwd *Shadow
- );
- VOID
- SwpWriteNewUtmpEntry (
- pid_t ProcessId,
- int NewType,
- PSTR TerminalName,
- PSTR UserName,
- PSTR HostName
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- extern char **environ;
- PASSWD_ALGORITHM SwPasswordAlgorithms[] = {
- {"md5", "$1$"},
- {"sha256", "$5$"},
- {"sha512", "$6$"},
- {NULL, NULL}
- };
- void *SwLibCrypt = NULL;
- PCRYPT_FUNCTION SwCryptFunction = NULL;
- PSTR SwDangerousEnvironmentVariables[] = {
- "ENV",
- "BASH_ENV",
- "HOME",
- "IFS",
- "SHELL",
- "LD_LIBRARY_PATH",
- "LD_PRELOAD",
- "LD_TRACE_LOADED_OBJECTS",
- "LD_BIND_NOW",
- "LD_AOUT_LIBRARY_PATH",
- "LD_AOUT_PRELOAD",
- "LD_NOWARN",
- "LD_KEEPDIR",
- NULL
- };
- const struct spwd SwShadowTemplate = {
- NULL,
- "*",
- 0,
- 0,
- 99999,
- 7,
- -1,
- -1,
- -1
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- INT
- SwUpdatePasswordLine (
- struct passwd *User,
- struct spwd *Shadow,
- UPDATE_PASSWORD_OPERATION Operation
- )
- /*++
- Routine Description:
- This routine adds or updates an entry in the password database.
- Arguments:
- User - Supplies a pointer to the user information structure.
- Shadow - Supplies a pointer to the shadow information.
- Operation - Supplies the operation to perform.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PSTR Gecos;
- PSTR Home;
- CHAR Line[PASSWORD_LINE_MAX];
- PSTR Password;
- int Result;
- PSTR Shell;
- assert((Operation == UpdatePasswordAddLine) ||
- (Operation == UpdatePasswordUpdateLine) ||
- (Operation == UpdatePasswordDeleteLine));
- Password = "x";
- Gecos = "";
- Home = "";
- Shell = "";
- if (User->pw_passwd != NULL) {
- Password = User->pw_passwd;
- }
- if (User->pw_gecos != NULL) {
- Gecos = User->pw_gecos;
- }
- if (User->pw_dir != NULL) {
- Home = User->pw_dir;
- }
- if (User->pw_shell != NULL) {
- Shell = User->pw_shell;
- }
- if ((User->pw_name[0] == '+') || (User->pw_name[0] == '-')) {
- Result = snprintf(Line,
- PASSWORD_LINE_MAX,
- "%s:%s:::%s:%s:%s",
- User->pw_name,
- Password,
- Gecos,
- Home,
- Shell);
- } else {
- Result = snprintf(Line,
- PASSWORD_LINE_MAX,
- "%s:%s:%lu:%lu:%s:%s:%s",
- User->pw_name,
- Password,
- (unsigned long int)(User->pw_uid),
- (unsigned long int)(User->pw_gid),
- Gecos,
- Home,
- Shell);
- }
- if ((Result >= PASSWORD_LINE_MAX) || (Result < 0)) {
- return ENAMETOOLONG;
- }
- Result = SwUpdatePasswordFile(PASSWD_FILE_PATH,
- User->pw_name,
- Line,
- NULL,
- Operation);
- if (Result != 0) {
- return Result;
- }
- //
- // Update the shadow file as well.
- //
- if (Shadow != NULL) {
- if (SwpPrintShadowLine(Line, PASSWORD_LINE_MAX, Shadow) < 0) {
- return ENAMETOOLONG;
- }
- Result = SwUpdatePasswordFile(_PATH_SHADOW,
- User->pw_name,
- Line,
- NULL,
- Operation);
- if (Result != 0) {
- return Result;
- }
- }
- return 0;
- }
- INT
- SwUpdateGroupLine (
- struct group *Group,
- UPDATE_PASSWORD_OPERATION Operation
- )
- /*++
- Routine Description:
- This routine adds or updates an entry in the group database.
- Arguments:
- Group - Supplies the group to add or update.
- Operation - Supplies the operation to perform.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PSTR CurrentLine;
- ssize_t CurrentLineSize;
- UINTN Index;
- PSTR Line;
- PSTR Password;
- ssize_t Size;
- INT Status;
- Line = malloc(GROUP_LINE_MAX);
- if (Line == NULL) {
- return ENOMEM;
- }
- Password = "";
- if (Group->gr_passwd != NULL) {
- Password = Group->gr_passwd;
- }
- Size = snprintf(Line,
- GROUP_LINE_MAX,
- "%s:%s:%lu:",
- Group->gr_name,
- Password,
- (long unsigned int)(Group->gr_gid));
- if ((Size <= 0) || (Size >= GROUP_LINE_MAX)) {
- Status = EINVAL;
- goto UpdateGroupLineEnd;
- }
- CurrentLine = Line + Size;
- CurrentLineSize = GROUP_LINE_MAX - Size;
- Index = 0;
- if (Group->gr_mem != NULL) {
- while (Group->gr_mem[Index] != NULL) {
- if (Index == 0) {
- Size = snprintf(CurrentLine,
- CurrentLineSize,
- "%s",
- Group->gr_mem[Index]);
- } else {
- Size = snprintf(CurrentLine,
- CurrentLineSize,
- ",%s",
- Group->gr_mem[Index]);
- }
- if ((Size <= 0) || (Size >= CurrentLineSize)) {
- Status = EINVAL;
- goto UpdateGroupLineEnd;
- }
- CurrentLine += Size;
- CurrentLineSize -= Size;
- Index += 1;
- }
- }
- Status = SwUpdatePasswordFile(GROUP_FILE_PATH,
- Group->gr_name,
- Line,
- NULL,
- Operation);
- UpdateGroupLineEnd:
- if (Line != NULL) {
- free(Line);
- }
- return Status;
- }
- INT
- SwUpdatePasswordFile (
- PSTR FilePath,
- PSTR Name,
- PSTR NewLine,
- PSTR GroupMember,
- UPDATE_PASSWORD_OPERATION Operation
- )
- /*++
- Routine Description:
- This routine updates a password file, usually either passwd, groups,
- shadow, or gshadow.
- Arguments:
- FilePath - Supplies a pointer to the path of the file to update.
- Name - Supplies the name of the member to update.
- NewLine - Supplies the new line to set.
- GroupMember - Supplies the group member to add or remove for group
- operations.
- Operation - Supplies the operation to perform.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PSTR AppendedPath;
- UINTN AppendedPathSize;
- UINTN ChangedLines;
- PSTR Colon;
- PSTR CurrentMember;
- char *Line;
- size_t LineBufferSize;
- ssize_t LineSize;
- struct flock Lock;
- size_t NameSize;
- FILE *NewFile;
- int NewFileDescriptor;
- PSTR NextComma;
- FILE *OldFile;
- mode_t OldUmask;
- PSTR Separator;
- UINTN Stall;
- struct stat Stat;
- INT Status;
- Line = NULL;
- LineBufferSize = 0;
- OldFile = NULL;
- OldUmask = umask(S_IWGRP | S_IWOTH | S_IROTH);
- NameSize = strlen(Name);
- NewFileDescriptor = -1;
- AppendedPathSize = strlen(FilePath) + 5;
- AppendedPath = malloc(AppendedPathSize);
- if (AppendedPath == NULL) {
- Status = ENOMEM;
- goto UpdatePasswordFileEnd;
- }
- snprintf(AppendedPath, AppendedPathSize, "%s.tmp", FilePath);
- OldFile = fopen(FilePath, "r+");
- if (OldFile == NULL) {
- Status = errno;
- SwPrintError(Status, FilePath, "Cannot open");
- goto UpdatePasswordFileEnd;
- }
- //
- // Try to open the new file, being a bit patient.
- //
- NewFileDescriptor = -1;
- for (Stall = 0; Stall < UPDATE_PASSWORD_WAIT; Stall += 1) {
- NewFileDescriptor = open(AppendedPath,
- O_WRONLY | O_CREAT | O_EXCL,
- S_IRUSR | S_IWUSR);
- if (NewFileDescriptor >= 0) {
- break;
- }
- if (errno != EEXIST) {
- Status = errno;
- SwPrintError(Status, AppendedPath, "Could not create");
- goto UpdatePasswordFileEnd;
- }
- sleep(1);
- }
- if (fstat(fileno(OldFile), &Stat) == 0) {
- fchmod(NewFileDescriptor, Stat.st_mode & ALLPERMS);
- Status = fchown(NewFileDescriptor, Stat.st_uid, Stat.st_gid);
- if (Status != 0) {
- Status = errno;
- goto UpdatePasswordFileEnd;
- }
- }
- if (NewFileDescriptor <= 0) {
- Status = errno;
- SwPrintError(Status, AppendedPath, "Could not create");
- goto UpdatePasswordFileEnd;
- }
- NewFile = fdopen(NewFileDescriptor, "w");
- if (NewFile == NULL) {
- Status = errno;
- goto UpdatePasswordFileEnd;
- }
- NewFileDescriptor = -1;
- //
- // Lock the file.
- //
- Lock.l_type = F_WRLCK;
- Lock.l_whence = SEEK_SET;
- Lock.l_start = 0;
- Lock.l_len = 0;
- if (fcntl(fileno(OldFile), F_SETLK, &Lock) < 0) {
- Status = errno;
- SwPrintError(Status, FilePath, "Cannot lock file");
- goto UpdatePasswordFileEnd;
- }
- ChangedLines = 0;
- while (TRUE) {
- LineSize = getline(&Line, &LineBufferSize, OldFile);
- if (LineSize <= 0) {
- break;
- }
- while ((LineSize > 0) && (isspace(Line[LineSize - 1]) != 0)) {
- Line[LineSize - 1] = '\0';
- LineSize -= 1;
- }
- //
- // If the line is uninteresting, spit it to the output and move on.
- //
- if ((strncmp(Line, Name, NameSize) != 0) || (Line[NameSize] != ':')) {
- fprintf(NewFile, "%s\n", Line);
- continue;
- }
- //
- // Add or remove a member from a group.
- //
- if (GroupMember != NULL) {
- if (Operation == UpdatePasswordAddGroupMember) {
- Separator = ",";
- if (Line[LineSize - 1] == ':') {
- Separator = "";
- }
- fprintf(NewFile, "%s%s%s\n", Line, Separator, GroupMember);
- ChangedLines += 1;
- //
- // Delete a user from a group.
- //
- } else {
- assert(Operation == UpdatePasswordDeleteGroupMember);
- Colon = strrchr(Line, ':');
- if (Colon == NULL) {
- fprintf(NewFile, "%s\n", Line);
- continue;
- }
- //
- // Write out everything up to the group list.
- //
- *Colon = '\0';
- fprintf(NewFile, "%s:", Line);
- //
- // Loop writing out the members, unless it's the member of
- // honor.
- //
- Separator = "";
- CurrentMember = Colon + 1;
- while (CurrentMember != NULL) {
- NextComma = strchr(CurrentMember, ',');
- if (NextComma != NULL) {
- *NextComma = '\0';
- NextComma += 1;
- }
- if (strcmp(CurrentMember, GroupMember) != 0) {
- fprintf(NewFile, "%s%s", Separator, CurrentMember);
- Separator = ",";
- } else {
- ChangedLines += 1;
- }
- CurrentMember = NextComma;
- }
- fprintf(NewFile, "\n");
- }
- //
- // There is no group member, this must be a passwd or shadow update.
- //
- } else {
- if ((Operation == UpdatePasswordAddLine) ||
- (Operation == UpdatePasswordUpdateLine)) {
- fprintf(NewFile, "%s\n", NewLine);
- ChangedLines += 1;
- //
- // For deleting an entry, just do nothing, and it won't make it to
- // the output file.
- //
- } else {
- assert(Operation == UpdatePasswordDeleteLine);
- ChangedLines += 1;
- }
- }
- }
- Status = 0;
- if (ChangedLines == 0) {
- if (Operation != UpdatePasswordAddLine) {
- SwPrintError(0, NULL, "Cannot find '%s' in '%s'", Name, FilePath);
- Status = 1;
- } else {
- fprintf(NewFile, "%s\n", NewLine);
- ChangedLines += 1;
- }
- }
- //
- // Unlock the password file.
- //
- Lock.l_type = F_UNLCK;
- fcntl(fileno(OldFile), F_SETLK, &Lock);
- errno = 0;
- fflush(NewFile);
- fsync(fileno(NewFile));
- fclose(NewFile);
- NewFile = NULL;
- if (errno != 0) {
- Status = errno;
- SwPrintError(Status, AppendedPath, "Failed to sync/close");
- goto UpdatePasswordFileEnd;
- }
- if (rename(AppendedPath, FilePath) != 0) {
- Status = errno;
- SwPrintError(Status, FilePath, "Failed to move");
- goto UpdatePasswordFileEnd;
- }
- Status = 0;
- UpdatePasswordFileEnd:
- umask(OldUmask);
- if (OldFile != NULL) {
- fclose(OldFile);
- }
- if (Status != 0) {
- if (AppendedPath != NULL) {
- unlink(AppendedPath);
- }
- }
- if (AppendedPath != NULL) {
- free(AppendedPath);
- }
- if (NewFileDescriptor >= 0) {
- close(NewFileDescriptor);
- }
- if (Line != NULL) {
- free(Line);
- }
- return Status;
- }
- PSTR
- SwCreateHashedPassword (
- PSTR Algorithm,
- int RandomSource,
- UINTN Rounds,
- PSTR Password
- )
- /*++
- Routine Description:
- This routine creates a hashed password, choosing an algorithm and a salt.
- Arguments:
- Algorithm - Supplies the algorithm to use. Valid values are something like
- "$1$", "$5$", or "$6$".
- RandomSource - Supplies an optional file descriptor sourcing random data.
- Rounds - Supplies the rounds parameter for SHA256 and SHA512 algorithms.
- Supply 0 to use a default value.
- Password - Supplies the plaintext password to encode.
- Return Value:
- Returns a pointer to the hashed password on success. This comes from a
- static buffer and may be overwritten by subsequent calls to this function.
- NULL on failure.
- --*/
- {
- ssize_t BytesRead;
- char Salt[17];
- int SaltIndex;
- CHAR SaltLine[64];
- int URandom;
- if (RandomSource >= 0) {
- URandom = RandomSource;
- } else {
- URandom = open(URANDOM_PATH, O_RDONLY);
- if (URandom < 0) {
- SwPrintError(errno, URANDOM_PATH, "Failed to open random source");
- return NULL;
- }
- }
- do {
- BytesRead = read(URandom, Salt, sizeof(Salt));
- } while ((BytesRead < 0) && (errno == EINTR));
- if (URandom != RandomSource) {
- close(URandom);
- }
- if (BytesRead != sizeof(Salt)) {
- SwPrintError(errno, URANDOM_PATH, "Failed to read random source");
- return NULL;
- }
- for (SaltIndex = 0; SaltIndex < sizeof(Salt); SaltIndex += 1) {
- Salt[SaltIndex] = SALT_ALPHABET[(UCHAR)(Salt[SaltIndex]) % 62];
- }
- Salt[sizeof(Salt) - 1] = '\0';
- //
- // Only a couple algorithms support rounds, namely SHA256 and SHA512.
- //
- if ((Rounds != 0) &&
- (strcmp(Algorithm, "$5$") != 0) &&
- (strcmp(Algorithm, "$6$") != 0)) {
- Rounds = 0;
- }
- if (Rounds == 0) {
- snprintf(SaltLine,
- sizeof(SaltLine),
- "%s%s",
- Algorithm,
- Salt);
- } else {
- if (Rounds < PASSWORD_ROUNDS_MIN) {
- Rounds = PASSWORD_ROUNDS_MIN;
- } else if (Rounds > PASSWORD_ROUNDS_MAX) {
- Rounds = PASSWORD_ROUNDS_MAX;
- }
- snprintf(SaltLine,
- sizeof(SaltLine),
- "%srounds=%d$%s",
- Algorithm,
- (int)Rounds,
- Salt);
- }
- return SwCrypt(Password, SaltLine);
- }
- INT
- SwCheckAccount (
- struct passwd *User
- )
- /*++
- Routine Description:
- This routine validates that the account is enabled and can be logged in via
- password.
- Arguments:
- User - Supplies a pointer to the user to get information for.
- Return Value:
- 0 if account is enabled.
- Non-zero if the account cannot be logged in to via password.
- --*/
- {
- PSTR HashedPassword;
- struct spwd *Shadow;
- HashedPassword = User->pw_passwd;
- Shadow = getspnam(User->pw_name);
- if ((Shadow == NULL) && (errno != ENOENT)) {
- SwPrintError(errno,
- User->pw_name,
- "Error: Could not read password information for user");
- return EACCES;
- }
- if (Shadow != NULL) {
- HashedPassword = Shadow->sp_pwdp;
- }
- if (*HashedPassword == '\0') {
- return 0;
- }
- if (*HashedPassword == '!') {
- SwPrintError(0, NULL, "Account locked");
- return EACCES;
- }
- if ((!isalnum(*HashedPassword)) &&
- (*HashedPassword != '/') &&
- (*HashedPassword != '.') &&
- (*HashedPassword != '_') &&
- (*HashedPassword != '$')) {
- SwPrintError(0, NULL, "Account disabled");
- return EACCES;
- }
- return 0;
- }
- INT
- SwGetAndCheckPassword (
- struct passwd *User,
- PSTR Prompt
- )
- /*++
- Routine Description:
- This routine asks for and validates the password for the given user.
- Arguments:
- User - Supplies a pointer to the user to get information for.
- Prompt - Supplies an optional pointer to the prompt to use. Supply NULL
- to use the prompt "Enter password:".
- Return Value:
- 0 if the password matched.
- EPERM if the password did not match.
- EACCES if the account is locked or expired.
- Other error codes on other failures.
- --*/
- {
- BOOL Correct;
- PSTR HashedPassword;
- PSTR Password;
- struct spwd *Shadow;
- HashedPassword = NULL;
- if (User != NULL) {
- HashedPassword = User->pw_passwd;
- Shadow = getspnam(User->pw_name);
- if ((Shadow == NULL) && (errno != ENOENT)) {
- SwPrintError(errno,
- User->pw_name,
- "Error: Could not read password information for user");
- return EACCES;
- }
- if (Shadow != NULL) {
- HashedPassword = Shadow->sp_pwdp;
- }
- if (*HashedPassword == '!') {
- SwPrintError(0, NULL, "Account locked");
- return EACCES;
- }
- //
- // If the password is empty just return success, no need to ask really.
- //
- if (*HashedPassword == '\0') {
- return 0;
- }
- }
- if (Prompt == NULL) {
- Prompt = "Enter password: ";
- }
- Password = getpass(Prompt);
- if (Password == NULL) {
- if (errno != 0) {
- return errno;
- }
- return EACCES;
- }
- if (User == NULL) {
- return EPERM;
- }
- Correct = SwCheckPassword(Password, HashedPassword);
- memset(Password, 0, strlen(Password));
- if (Correct != FALSE) {
- return 0;
- }
- return EPERM;
- }
- BOOL
- SwCheckPassword (
- PSTR Password,
- PSTR EncryptedPassword
- )
- /*++
- Routine Description:
- This routine checks a password against its hash.
- Arguments:
- Password - Supplies a pointer to the plaintext password to check.
- EncryptedPassword - Supplies the password hash.
- Return Value:
- TRUE if the passwords match.
- FALSE if the passwords do not match.
- --*/
- {
- PSTR Result;
- Result = SwCrypt(Password, EncryptedPassword);
- assert(Result != EncryptedPassword);
- if (strcmp(Result, EncryptedPassword) == 0) {
- return TRUE;
- }
- return FALSE;
- }
- PSTR
- SwCrypt (
- PSTR Password,
- PSTR Salt
- )
- /*++
- Routine Description:
- This routine calls the crypt function off in libcrypt.
- Arguments:
- Password - Supplies the plaintext password to encode.
- Salt - Supplies the algorithm and salt information.
- Return Value:
- Returns a pointer to the hashed password on success. This comes from a
- static buffer and may be overwritten by subsequent calls to this function.
- NULL on failure.
- --*/
- {
- //
- // Get the address of the crypt function from libcrypt if not found already.
- //
- if (SwCryptFunction == NULL) {
- if (SwLibCrypt == NULL) {
- SwLibCrypt = dlopen(LIBCRYPT_PATH, 0);
- if (SwLibCrypt == NULL) {
- SwPrintError(0,
- NULL,
- "Failed to open %s: %s",
- LIBCRYPT_PATH,
- dlerror());
- return NULL;
- }
- }
- SwCryptFunction = dlsym(SwLibCrypt, "crypt");
- if (SwCryptFunction == NULL) {
- SwPrintError(0, NULL, "Failed to find crypt in libcrypt.so");
- return NULL;
- }
- }
- if (Password == NULL) {
- return NULL;
- }
- return SwCryptFunction(Password, Salt);
- }
- BOOL
- SwIsValidUserName (
- PSTR Name
- )
- /*++
- Routine Description:
- This routine validates that the given username doesn't have any invalid
- characters.
- Arguments:
- Name - Supplies a pointer to the user name to check.
- Return Value:
- TRUE if it is valid.
- FALSE if it is not valid.
- --*/
- {
- PSTR Start;
- Start = Name;
- if ((*Name == '-') || (*Name == '.') || (*Name == '\0')) {
- return FALSE;
- }
- while (*Name != '\0') {
- if ((*Name != '_') && (!isalnum(*Name)) && (*Name != '.') &&
- (*Name != '-')) {
- return FALSE;
- }
- Name += 1;
- }
- if (*(Name - 1) == '$') {
- return FALSE;
- }
- if (Name - Start >= LOGIN_NAME_MAX) {
- return FALSE;
- }
- return TRUE;
- }
- INT
- SwBecomeUser (
- struct passwd *User
- )
- /*++
- Routine Description:
- This routine changes the current identity to that of the given user,
- including the real user ID, group ID, and supplementary groups.
- Arguments:
- User - Supplies a pointer to the user to become.
- Return Value:
- None.
- --*/
- {
- INT Result;
- INT Status;
- Status = 0;
- Result = initgroups(User->pw_name, User->pw_gid);
- if (Result < 0) {
- Status = errno;
- SwPrintError(Status, User->pw_name, "Failed to init groups for");
- if (Status == EPERM) {
- return Status;
- }
- }
- Result = setgid(User->pw_gid);
- if (Result < 0) {
- Status = errno;
- SwPrintError(Status, User->pw_name, "Failed to set gid for");
- }
- Result = setuid(User->pw_uid);
- if (Result < 0) {
- Status = errno;
- SwPrintError(Status, User->pw_name, "Failed to set uid for");
- }
- return Status;
- }
- VOID
- SwSetupUserEnvironment (
- struct passwd *User,
- PSTR Shell,
- ULONG Flags
- )
- /*++
- Routine Description:
- This routine changes the current identity to that of the given user,
- including the real user ID, group ID, and supplementary groups.
- Arguments:
- User - Supplies a pointer to the user to set up for.
- Shell - Supplies a pointer to the shell to use. If not specified
- the ever-classic /bin/sh will be used.
- Flags - Supplies a bitfield of flags. See SETUP_USER_ENVIRONMENT_*
- definitions.
- Return Value:
- None.
- --*/
- {
- PSTR Path;
- PSTR Terminal;
- if ((Shell == NULL) || (*Shell == '\0')) {
- Shell = USER_FALLBACK_SHELL;
- }
- //
- // Change the current directory to the user's home directory.
- //
- if ((Flags & SETUP_USER_ENVIRONMENT_NO_DIRECTORY) == 0) {
- if ((User->pw_dir != NULL) && (User->pw_dir[0] != '\0')) {
- if (chdir(User->pw_dir) < 0) {
- SwPrintError(errno, User->pw_dir, "Cannot change to directory");
- }
- }
- }
- //
- // If the caller wants to clear the environment, wipe out everything.
- // Preserve TERM.
- //
- if ((Flags & SETUP_USER_ENVIRONMENT_CLEAR_ENVIRONMENT) != 0) {
- Terminal = getenv("TERM");
- environ = NULL;
- if (Terminal != NULL) {
- setenv("TERM", Terminal, 1);
- }
- Path = USER_DEFAULT_PATH;
- if (User->pw_uid == 0) {
- Path = SUPERUSER_DEFAULT_PATH;
- }
- setenv("PATH", Path, 1);
- setenv("USER", User->pw_name, 1);
- setenv("LOGNAME", User->pw_name, 1);
- setenv("HOME", User->pw_dir, 1);
- setenv("SHELL", Shell, 1);
- } else if ((Flags & SETUP_USER_ENVIRONMENT_CHANGE_ENVIRONMENT) != 0) {
- if (User->pw_uid != 0) {
- setenv("USER", User->pw_name, 1);
- setenv("LOGNAME", User->pw_name, 1);
- }
- setenv("HOME", User->pw_dir, 1);
- setenv("SHELL", Shell, 1);
- }
- return;
- }
- VOID
- SwExecuteShell (
- PSTR Shell,
- BOOL LoginShell,
- PSTR Command,
- PSTR *AdditionalArguments
- )
- /*++
- Routine Description:
- This routine execs this program into a shell program with the given
- arguments.
- Arguments:
- Shell - Supplies a pointer to the shell to use. If not specified
- the ever-classic /bin/sh will be used.
- LoginShell - Supplies a boolean indicating if this is a login shell or
- not.
- Command - Supplies the command to run.
- AdditionalArguments - Supplies an array of the additional arguments.
- Return Value:
- None. On success, this routine does not return.
- --*/
- {
- UINTN ArgumentCount;
- PSTR *Arguments;
- UINTN Index;
- PSTR LastSlash;
- PSTR LoginLine;
- LoginLine = NULL;
- ArgumentCount = 0;
- if (AdditionalArguments != NULL) {
- while (AdditionalArguments[ArgumentCount] != NULL) {
- ArgumentCount += 1;
- }
- }
- //
- // Add four extra for the sh, -c, command, and NULL.
- //
- Arguments = malloc(sizeof(PSTR) * (ArgumentCount + 4));
- if (Arguments == NULL) {
- return;
- }
- if ((Shell == NULL) || (*Shell == '\0')) {
- Shell = USER_FALLBACK_SHELL;
- }
- LastSlash = strrchr(Shell, '/');
- if ((LastSlash == NULL) ||
- ((LastSlash == Shell) && (LastSlash[1] == '\0'))) {
- LastSlash = Shell;
- } else {
- LastSlash += 1;
- }
- Arguments[0] = LastSlash;
- if (LoginShell != FALSE) {
- LoginLine = malloc(strlen(LastSlash) + 2);
- if (LoginLine != NULL) {
- *LoginLine = '-';
- strcpy(LoginLine + 1, LastSlash);
- Arguments[0] = LoginLine;
- }
- }
- Index = 1;
- if (Command != NULL) {
- Arguments[Index] = "-c";
- Index += 1;
- Arguments[Index] = Command;
- Index += 1;
- }
- if (AdditionalArguments != NULL) {
- while (*AdditionalArguments != NULL) {
- Arguments[Index] = *AdditionalArguments;
- Index += 1;
- AdditionalArguments += 1;
- }
- }
- Arguments[Index] = NULL;
- assert(Index < ArgumentCount + 4);
- execv(Shell, Arguments);
- SwPrintError(errno, Shell, "Cannot execute");
- free(Arguments);
- if (LoginLine != NULL) {
- free(LoginLine);
- }
- return;
- }
- VOID
- SwSanitizeEnvironment (
- VOID
- )
- /*++
- Routine Description:
- This routine removes several dangerous environment variables from the
- environment, and resets the PATH.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- PSTR *Variable;
- Variable = &(SwDangerousEnvironmentVariables[0]);
- while (*Variable != NULL) {
- unsetenv(*Variable);
- Variable += 1;
- }
- if (geteuid() != 0) {
- setenv("PATH", USER_DEFAULT_PATH, 1);
- } else {
- setenv("PATH", SUPERUSER_DEFAULT_PATH, 1);
- }
- return;
- }
- VOID
- SwPrintLoginPrompt (
- VOID
- )
- /*++
- Routine Description:
- This routine prints the standard login prompt.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- struct utsname SystemInformation;
- memset(&SystemInformation, 0, sizeof(SystemInformation));
- uname(&SystemInformation);
- printf("%s login: ", SystemInformation.nodename);
- fflush(NULL);
- return;
- }
- VOID
- SwUpdateUtmp (
- pid_t ProcessId,
- int NewType,
- PSTR TerminalName,
- PSTR UserName,
- PSTR HostName
- )
- /*++
- Routine Description:
- This routine updates a utmp entry, and potentially wtmp as well.
- Arguments:
- ProcessId - Supplies the current process ID.
- NewType - Supplies the type of entry to add.
- TerminalName - Supplies a pointer to the terminal name.
- UserName - Supplies a pointer to the user name.
- HostName - Supplies a pointer to the host name.
- Return Value:
- None.
- --*/
- {
- struct utmpx Copy;
- int Descriptor;
- struct utmpx *Entry;
- struct utmp Utmp;
- //
- // Create the file if it does not exist.
- //
- if (access(_PATH_UTMPX, R_OK | W_OK) < 0) {
- Descriptor = open(_PATH_UTMPX,
- O_WRONLY | O_CREAT,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
- if (Descriptor >= 0) {
- close(Descriptor);
- }
- }
- setutxent();
- while (TRUE) {
- Entry = getutxent();
- if (Entry == NULL) {
- break;
- }
- if ((Entry->ut_pid == ProcessId) &&
- (Entry->ut_id[0] != 0) &&
- ((Entry->ut_type == INIT_PROCESS) ||
- (Entry->ut_type == LOGIN_PROCESS) ||
- (Entry->ut_type == USER_PROCESS) ||
- (Entry->ut_type == DEAD_PROCESS))) {
- if (Entry->ut_type == NewType) {
- memset(Entry->ut_host, 0, sizeof(Entry->ut_host));
- }
- break;
- }
- }
- if (Entry == NULL) {
- if (NewType == DEAD_PROCESS) {
- SwpWriteNewUtmpEntry(ProcessId,
- NewType,
- TerminalName,
- UserName,
- HostName);
- } else {
- endutxent();
- }
- } else {
- memcpy(&Copy, Entry, sizeof(struct utmpx));
- Copy.ut_type = NewType;
- if (TerminalName != NULL) {
- strncpy(Copy.ut_line, TerminalName, sizeof(Copy.ut_line));
- }
- if (UserName != NULL) {
- strncpy(Copy.ut_user, UserName, sizeof(Copy.ut_user));
- }
- if (HostName != NULL) {
- strncpy(Copy.ut_host, HostName, sizeof(Copy.ut_host));
- }
- Copy.ut_tv.tv_sec = time(NULL);
- pututxline(&Copy);
- endutxent();
- getutmp(&Copy, &Utmp);
- updwtmp(_PATH_WTMP, &Utmp);
- }
- return;
- }
- VOID
- SwPrintLoginIssue (
- PSTR IssuePath,
- PSTR TerminalName
- )
- /*++
- Routine Description:
- This routine prints the login issue file to standard out.
- Arguments:
- IssuePath - Supplies an optional path to the issue file. If not specified,
- the default of /etc/issue will be used.
- TerminalName - Supplies the name of this terminal, used for expanding %l
- escapes in the issue file.
- Return Value:
- None.
- --*/
- {
- CHAR Buffer[256];
- INT Character;
- FILE *Issue;
- PSTR String;
- struct utsname SystemInformation;
- time_t Time;
- if (IssuePath == NULL) {
- IssuePath = ISSUE_PATH;
- }
- Issue = fopen(IssuePath, "r");
- if (Issue == NULL) {
- return;
- }
- Time = time(NULL);
- uname(&SystemInformation);
- while (TRUE) {
- Character = fgetc(Issue);
- if (Character == EOF) {
- break;
- }
- String = Buffer;
- Buffer[0] = Character;
- Buffer[1] = '\0';
- if (Character == '\n') {
- Buffer[1] = '\r';
- Buffer[2] = '\0';
- } else if ((Character == '\\') || (Character == '%')) {
- Character = fgetc(Issue);
- if (Character == EOF) {
- break;
- }
- switch (Character) {
- case 's':
- String = SystemInformation.sysname;
- break;
- case 'n':
- case 'h':
- String = SystemInformation.nodename;
- break;
- case 'r':
- String = SystemInformation.release;
- break;
- case 'v':
- String = SystemInformation.version;
- break;
- case 'm':
- String = SystemInformation.machine;
- break;
- case 'D':
- case 'o':
- String = SystemInformation.domainname;
- break;
- case 'd':
- strftime(Buffer,
- sizeof(Buffer),
- "%A, %d %B %Y",
- localtime(&Time));
- break;
- case 't':
- strftime(Buffer, sizeof(Buffer), "%H:%M:%S", localtime(&Time));
- break;
- case 'l':
- String = TerminalName;
- break;
- default:
- Buffer[0] = Character;
- break;
- }
- }
- fputs(String, stdout);
- }
- fclose(Issue);
- fflush(NULL);
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- INT
- SwpPrintShadowLine (
- PSTR Line,
- UINTN LineSize,
- struct spwd *Shadow
- )
- /*++
- Routine Description:
- This routine prints a shadow entry to a line.
- Arguments:
- Line - Supplies the line where the entry will be returned.
- LineSize - Supplies the size of the line buffer.
- Shadow - Supplies the shadow structure.
- Return Value:
- 0 on success.
- Non-zero if the line was too small.
- --*/
- {
- ssize_t Size;
- Size = snprintf(Line, LineSize, "%s:", Shadow->sp_namp);
- if (Size > 0) {
- Line += Size;
- LineSize -= Size;
- }
- if (Shadow->sp_pwdp != NULL) {
- Size = snprintf(Line, LineSize, "%s:", Shadow->sp_pwdp);
- if (Size > 0) {
- Line += Size;
- LineSize -= Size;
- }
- } else {
- if (LineSize > 0) {
- *Line = ':';
- Line += 1;
- LineSize -= 1;
- }
- }
- if (Shadow->sp_lstchg != (long int)-1) {
- Size = snprintf(Line, LineSize, "%ld:", (long int)(Shadow->sp_lstchg));
- if (Size > 0) {
- Line += Size;
- LineSize -= Size;
- }
- } else {
- if (LineSize > 0) {
- *Line = ':';
- Line += 1;
- LineSize -= 1;
- }
- }
- if (Shadow->sp_min != (long int)-1) {
- Size = snprintf(Line, LineSize, "%ld:", Shadow->sp_min);
- if (Size > 0) {
- Line += Size;
- LineSize -= Size;
- }
- } else {
- if (LineSize > 0) {
- *Line = ':';
- Line += 1;
- LineSize -= 1;
- }
- }
- if (Shadow->sp_max != (long int)-1) {
- Size = snprintf(Line, LineSize, "%ld:", Shadow->sp_max);
- if (Size > 0) {
- Line += Size;
- LineSize -= Size;
- }
- } else {
- if (LineSize > 0) {
- *Line = ':';
- Line += 1;
- LineSize -= 1;
- }
- }
- if (Shadow->sp_warn != (long int)-1) {
- Size = snprintf(Line, LineSize, "%ld:", Shadow->sp_warn);
- if (Size > 0) {
- Line += Size;
- LineSize -= Size;
- }
- } else {
- if (LineSize > 0) {
- *Line = ':';
- Line += 1;
- LineSize -= 1;
- }
- }
- if (Shadow->sp_inact != (long int)-1) {
- Size = snprintf(Line, LineSize, "%ld:", Shadow->sp_inact);
- if (Size > 0) {
- Line += Size;
- LineSize -= Size;
- }
- } else {
- if (LineSize > 0) {
- *Line = ':';
- Line += 1;
- LineSize -= 1;
- }
- }
- if (Shadow->sp_expire!= (long int)-1) {
- Size = snprintf(Line, LineSize, "%ld:", Shadow->sp_expire);
- if (Size > 0) {
- Line += Size;
- LineSize -= Size;
- }
- } else {
- if (LineSize > 0) {
- *Line = ':';
- Line += 1;
- LineSize -= 1;
- }
- }
- if (Shadow->sp_flag != (unsigned long int)-1) {
- Size = snprintf(Line, LineSize, "%lu", Shadow->sp_flag);
- if (Size > 0) {
- Line += Size;
- LineSize -= Size;
- }
- }
- if (LineSize > 0) {
- *Line = '\0';
- return 0;
- }
- return -1;
- }
- VOID
- SwpWriteNewUtmpEntry (
- pid_t ProcessId,
- int NewType,
- PSTR TerminalName,
- PSTR UserName,
- PSTR HostName
- )
- /*++
- Routine Description:
- This routine writes a new a utmp entry.
- Arguments:
- ProcessId - Supplies the current process ID.
- NewType - Supplies the type of entry to add.
- TerminalName - Supplies a pointer to the terminal name.
- UserName - Supplies a pointer to the user name.
- HostName - Supplies a pointer to the host name.
- Return Value:
- None.
- --*/
- {
- struct utmpx Entry;
- char *Id;
- UINTN Index;
- PSTR TerminalEnd;
- UINTN Width;
- memset(&Entry, 0, sizeof(struct utmpx));
- Entry.ut_pid = ProcessId;
- Entry.ut_type = NewType;
- if (TerminalName != NULL) {
- strncpy(Entry.ut_line, TerminalName, sizeof(Entry.ut_line));
- }
- if (UserName != NULL) {
- strncpy(Entry.ut_user, UserName, sizeof(Entry.ut_user));
- }
- if (HostName != NULL) {
- strncpy(Entry.ut_host, HostName, sizeof(Entry.ut_host));
- }
- Entry.ut_tv.tv_sec = time(NULL);
- Id = Entry.ut_id;
- Width = sizeof(Entry.ut_id);
- assert(Width != 0);
- if (TerminalName != NULL) {
- //
- // Fill the ID with zero characters.
- //
- for (Index = 0; Index < Width; Index += 1) {
- Id[Index] = '0';
- }
- //
- // Add all digits on the end.
- //
- Index = Width - 1;
- TerminalEnd = TerminalName + strlen(TerminalName);
- if (TerminalEnd != TerminalName) {
- TerminalEnd -= 1;
- while (TerminalEnd >= TerminalName) {
- if (!isdigit(*TerminalEnd)) {
- break;
- }
- Id[Index] = *TerminalEnd;
- if (Index == 0) {
- break;
- }
- Index -= 1;
- TerminalEnd -= 1;
- }
- }
- }
- setutxent();
- pututxline(&Entry);
- endutxent();
- return;
- }
|