12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082 |
- /*++
- Copyright (c) 2015 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- utmpx.c
- Abstract:
- This module implements support for the user accounting database, which
- tracks user logins and other activity.
- Author:
- Evan Green 30-Jan-2015
- Environment:
- User Mode C Library
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "libcp.h"
- #include <assert.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/param.h>
- #include <sys/stat.h>
- #include <utmp.h>
- #include <utmpx.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- INT
- ClpOpenUserAccountingDatabase (
- PSTR DatabaseFile
- );
- INT
- ClpReadWriteUserAccountingEntry (
- struct utmpx *Entry,
- INT Type
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Store the file pointer to the user accounting database.
- //
- char *ClUserAccountingFilePath = NULL;
- int ClUserAccountingFile = -1;
- struct utmpx *ClUserAccountingEntry = NULL;
- //
- // ------------------------------------------------------------------ Functions
- //
- LIBC_API
- void
- setutent (
- void
- )
- /*++
- Routine Description:
- This routine resets the current pointer into the user database back to the
- beginning. This function is neither thread-safe nor reentrant. This
- function is equivalent to setutxent, and new applications should use that
- function.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- setutxent();
- return;
- }
- LIBC_API
- void
- endutent (
- void
- )
- /*++
- Routine Description:
- This routine closes the user accounting database. This function is neither
- thread-safe nor reentrant. This function is equivalent to endutxent, and
- new applications should use that function.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- endutxent();
- return;
- }
- LIBC_API
- struct utmp *
- getutent (
- void
- )
- /*++
- Routine Description:
- This routine returns the next entry in the user accounting database. If
- the database is not already open, it will open it. If it reaches the end
- of the database, it fails. This function is neither thread-safe nor
- reentrant. Since utmp and utmpx structures are the same, this function is
- equivalent to getutxent, and new applications should use that function.
- Arguments:
- None.
- Return Value:
- Returns a pointer to a copy of the user accounting information on success.
- NULL on failure, and errno may be set on error.
- --*/
- {
- return (struct utmp *)getutxent();
- }
- LIBC_API
- struct utmp *
- getutid (
- const struct utmp *Id
- )
- /*++
- Routine Description:
- This routine searches forward from the current point in the user accounting
- database. If the ut_type value of the supplied utmp structure is
- BOOT_TIME, OLD_TIME, or NEW_TIME, then it stops when it finds an entry with
- a matching ut_type value. If the ut_type is INIT_PROCESS, USER_PROCESS, or
- DEAD_PROCESS, it stops when it finds an entry whose type is one of these
- four and whose ut_id matches the one in the given structure. If the end of
- the database is reached without a match, the routine shall fail. This
- function is neither thread-safe nor reentrant. Since utmp and utmpx
- structures are the same, this function is equivalent to getutxent, and new
- applications should use that function.
- Arguments:
- Id - Supplies a pointer to a structure containing the type and possibly
- user ID to match on.
- Return Value:
- Returns a pointer to a copy of the user accounting information on success.
- NULL on failure, and errno may be set on error.
- --*/
- {
- return (struct utmp *)getutxid((struct utmpx *)Id);
- }
- LIBC_API
- struct utmp *
- getutline (
- const struct utmp *Line
- )
- /*++
- Routine Description:
- This routine searches forward from the current point in the user accounting
- database, looking for an entry of type LOGIN_PROCESS or USER_PROCESS which
- also matches the ut_line value in the given structure. If the end of the
- database is reached without a match, the routine shall fail. This function
- is neither thread-safe nor reentrant.
- This function may cache data, so to search for multiple occurrences it is
- important to zero out the static data (the return value from the previous
- result). Otherwise, the same result may be returned infinitely.
- Since utmp and utmpx structures are the same, this function is equivalent
- to getutxline, and new applications should use that function.
- Arguments:
- Line - Supplies a pointer to a structure containing the line to match.
- Return Value:
- Returns a pointer to a copy of the user accounting information on success.
- NULL on failure, and errno may be set on error.
- --*/
- {
- return (struct utmp *)getutxline((struct utmpx *)Line);
- }
- LIBC_API
- struct utmp *
- pututline (
- const struct utmp *Value
- )
- /*++
- Routine Description:
- This routine writes out the structure to the user accounting database. It
- shall use getutxid to search for a record that satisfies the request. If
- the search succeeds, then the entry will be replaced. Otherwise, a new
- entry is made at the end of the user accounting database. The caller must
- have sufficient privileges. The implicit read done by this function if it
- finds it is not already at the correct place shall not modify the static
- structure passed as a return of the other utx functions (so the application
- may use that space to write back a modified value). This function is
- neither thread-safe nor reentrant. Since utmp and utmpx structures are the
- same, this function is equivalent to getutxline, and new applications
- should use that function.
- Arguments:
- Value - Supplies a pointer to a structure containing the new data.
- Return Value:
- Returns a pointer to a copy of the written user accounting information on
- success.
- NULL on failure, and errno may be set on error.
- --*/
- {
- return (struct utmp *)pututxline((struct utmpx *)Value);
- }
- LIBC_API
- int
- utmpname (
- const char *FilePath
- )
- /*++
- Routine Description:
- This routine updates the file path that utmp* functions open and access.
- This must be called before those routines open the file. This routine does
- not check to ensure the file exists. This routine is neither thread-safe
- nor reentrant. This routine is equivalent to utmpxname, and new
- applications should call that function.
- Arguments:
- FilePath - Supplies a pointer to the new file path. A copy of this string
- will be made.
- Return Value:
- 0 on success.
- -1 on failure, and errno will be set to contain more information.
- --*/
- {
- return utmpxname(FilePath);
- }
- LIBC_API
- void
- logwtmp (
- const char *Terminal,
- const char *User,
- const char *Host
- )
- /*++
- Routine Description:
- This routine creates a new utmp entry with the given terminal line, user
- name, host name, the current process ID, and current time. It appends the
- new record using updwtmp to the wtmp file.
- Arguments:
- Terminal - Supplies an optional pointer to the terminal.
- User - Supplies an optional pointer to the user.
- Host - Supplies a pointer to the host.
- Return Value:
- None.
- --*/
- {
- struct utmp Record;
- memset(&Record, 0, sizeof(Record));
- Record.ut_pid = getpid();
- if ((User != NULL) && (User[0] != '\0')) {
- Record.ut_type = USER_PROCESS;
- strncpy(Record.ut_user, User, sizeof(Record.ut_user));
- } else {
- Record.ut_type = DEAD_PROCESS;
- }
- if (Terminal != NULL) {
- strncpy(Record.ut_line, Terminal, sizeof(Record.ut_line));
- }
- strncpy(Record.ut_host, Host, sizeof(Record.ut_host));
- gettimeofday(&(Record.ut_tv), NULL);
- updwtmp(_PATH_WTMP, (struct utmp *)&Record);
- return;
- }
- LIBC_API
- void
- updwtmp (
- const char *FileName,
- const struct utmp *Record
- )
- /*++
- Routine Description:
- This routine adds an entry into the wtmp user database.
- Arguments:
- FileName - Supplies a pointer to path of the wtmp file to open. Set this to
- WTMP_FILE by default.
- Record - Supplies a pointer to the record to append.
- Return Value:
- None.
- --*/
- {
- updwtmpx(FileName, (struct utmpx *)Record);
- return;
- }
- LIBC_API
- void
- setutxent (
- void
- )
- /*++
- Routine Description:
- This routine resets the current pointer into the user database back to the
- beginning. This function is neither thread-safe nor reentrant.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- //
- // Allocate the static space if necessary.
- //
- if (ClUserAccountingEntry == NULL) {
- ClUserAccountingEntry = malloc(sizeof(struct utmpx));
- if (ClUserAccountingEntry == NULL) {
- errno = ENOMEM;
- return;
- }
- }
- ClpOpenUserAccountingDatabase(ClUserAccountingFilePath);
- return;
- }
- LIBC_API
- void
- endutxent (
- void
- )
- /*++
- Routine Description:
- This routine closes the user accounting database. This function is neither
- thread-safe nor reentrant.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- if (ClUserAccountingFile >= 0) {
- close(ClUserAccountingFile);
- ClUserAccountingFile = -1;
- }
- return;
- }
- LIBC_API
- struct utmpx *
- getutxent (
- void
- )
- /*++
- Routine Description:
- This routine returns the next entry in the user accounting database. If
- the database is not already open, it will open it. If it reaches the end
- of the database, it fails. This function is neither thread-safe nor
- reentrant.
- Arguments:
- None.
- Return Value:
- Returns a pointer to a copy of the user accounting information on success.
- NULL on failure, and errno may be set on error.
- --*/
- {
- INT Result;
- Result = ClpReadWriteUserAccountingEntry(NULL, F_RDLCK);
- if (Result < 0) {
- return NULL;
- }
- return ClUserAccountingEntry;
- }
- LIBC_API
- struct utmpx *
- getutxid (
- const struct utmpx *Id
- )
- /*++
- Routine Description:
- This routine searches forward from the current point in the user accounting
- database. If the ut_type value of the supplied utmpx structure is
- BOOT_TIME, OLD_TIME, or NEW_TIME, then it stops when it finds an entry with
- a matching ut_type value. If the ut_type is INIT_PROCESS, USER_PROCESS, or
- DEAD_PROCESS, it stops when it finds an entry whose type is one of these
- four and whose ut_id matches the one in the given structure. If the end of
- the database is reached without a match, the routine shall fail. This
- function is neither thread-safe nor reentrant.
- Arguments:
- Id - Supplies a pointer to a structure containing the type and possibly
- user ID to match on.
- Return Value:
- Returns a pointer to a copy of the user accounting information on success.
- NULL on failure, and errno may be set on error.
- --*/
- {
- BOOL Match;
- struct utmpx Value;
- Match = FALSE;
- while (TRUE) {
- if (ClpReadWriteUserAccountingEntry(&Value, F_RDLCK) < 0) {
- return NULL;
- }
- //
- // If it's any of the one-time entries (RUN_LVL, BOOT_TIME, NEW_TIME,
- // or OLD_TIME) just match on the type.
- //
- if ((Id->ut_type != EMPTY) && (Id->ut_type <= OLD_TIME)) {
- if (Id->ut_type == Value.ut_type) {
- Match = TRUE;
- break;
- }
- //
- // If it's a process entry (INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS,
- // or DEAD_PROCESS) then find one that matches the ID.
- //
- } else if (Id->ut_type <= DEAD_PROCESS) {
- if (strncmp(Id->ut_id, Value.ut_id, sizeof(Value.ut_id)) == 0) {
- Match = TRUE;
- break;
- }
- }
- }
- if (Match == FALSE) {
- return NULL;
- }
- memcpy(ClUserAccountingEntry, &Value, sizeof(struct utmpx));
- return ClUserAccountingEntry;
- }
- LIBC_API
- struct utmpx *
- getutxline (
- const struct utmpx *Line
- )
- /*++
- Routine Description:
- This routine searches forward from the current point in the user accounting
- database, looking for an entry of type LOGIN_PROCESS or USER_PROCESS which
- also matches the ut_line value in the given structure. If the end of the
- database is reached without a match, the routine shall fail. This function
- is neither thread-safe nor reentrant.
- This function may cache data, so to search for multiple occurrences it is
- important to zero out the static data (the return value from the previous
- result). Otherwise, the same result may be returned infinitely.
- Arguments:
- Line - Supplies a pointer to a structure containing the line to match.
- Return Value:
- Returns a pointer to a copy of the user accounting information on success.
- NULL on failure, and errno may be set on error.
- --*/
- {
- struct utmpx Value;
- while (TRUE) {
- if (ClpReadWriteUserAccountingEntry(&Value, F_RDLCK) < 0) {
- return NULL;
- }
- if ((Value.ut_type == USER_PROCESS) ||
- (Value.ut_type == LOGIN_PROCESS)) {
- if (strncmp(Value.ut_line, Line->ut_line, sizeof(Value.ut_line)) ==
- 0) {
- goto getutxlineEnd;
- }
- }
- }
- getutxlineEnd:
- memcpy(ClUserAccountingEntry, &Value, sizeof(struct utmpx));
- return ClUserAccountingEntry;
- }
- LIBC_API
- struct utmpx *
- getutxuser (
- const struct utmpx *User
- )
- /*++
- Routine Description:
- This routine searches forward from the current point in the user accounting
- database, looking for an entry of type USER_PROCESS which also matches the
- ut_user value in the given structure. If the end of the database is reached
- without a match, the routine shall fail. This function is neither
- thread-safe nor reentrant.
- This function may cache data, so to search for multiple occurrences it is
- important to zero out the static data (the return value from the previous
- result). Otherwise, the same result may be returned infinitely.
- Arguments:
- User - Supplies a pointer to a structure containing the userto match.
- Return Value:
- Returns a pointer to a copy of the user accounting information on success.
- NULL on failure, and errno may be set on error.
- --*/
- {
- struct utmpx Value;
- while (TRUE) {
- if (ClpReadWriteUserAccountingEntry(&Value, F_RDLCK) < 0) {
- return NULL;
- }
- if (Value.ut_type == LOGIN_PROCESS) {
- if (strncmp(Value.ut_user, User->ut_user, sizeof(Value.ut_user)) ==
- 0) {
- goto getutxuserEnd;
- }
- }
- }
- getutxuserEnd:
- memcpy(ClUserAccountingEntry, &Value, sizeof(struct utmpx));
- return ClUserAccountingEntry;
- }
- LIBC_API
- struct utmpx *
- pututxline (
- const struct utmpx *Value
- )
- /*++
- Routine Description:
- This routine writes out the structure to the user accounting database. It
- shall use getutxid to search for a record that satisfies the request. If
- the search succeeds, then the entry will be replaced. Otherwise, a new
- entry is made at the end of the user accounting database. The caller must
- have sufficient privileges. The implicit read done by this function if it
- finds it is not already at the correct place shall not modify the static
- structure passed as a return of the other utx functions (so the application
- may use that space to write back a modified value). This function is
- neither thread-safe nor reentrant.
- Arguments:
- Value - Supplies a pointer to a structure containing the new data.
- Return Value:
- Returns a pointer to a copy of the written user accounting information on
- success.
- NULL on failure, and errno may be set on error.
- --*/
- {
- struct utmpx Copy;
- struct utmpx *Found;
- INT Result;
- //
- // Copy the passed in value in case it is the static storage.
- //
- memcpy(&Copy, Value, sizeof(struct utmpx));
- //
- // Find the entry.
- //
- Found = getutxid(&Copy);
- if (Found != NULL) {
- lseek(ClUserAccountingFile, -(off_t)sizeof(struct utmpx), SEEK_CUR);
- } else {
- lseek(ClUserAccountingFile, 0, SEEK_END);
- }
- Result = ClpReadWriteUserAccountingEntry(&Copy, F_WRLCK);
- if (Result < 0) {
- return NULL;
- }
- memcpy(ClUserAccountingEntry, &Copy, sizeof(struct utmpx));
- return (struct utmpx *)Value;
- }
- LIBC_API
- int
- utmpxname (
- const char *FilePath
- )
- /*++
- Routine Description:
- This routine updates the file path that utmpx* functions open and access.
- This must be called before those routines open the file. This routine does
- not check to ensure the file exists. This routine is neither thread-safe
- nor reentrant.
- Arguments:
- FilePath - Supplies a pointer to the new file path. A copy of this string
- will be made.
- Return Value:
- 0 on success.
- -1 on failure, and errno will be set to contain more information.
- --*/
- {
- if (ClUserAccountingFilePath != NULL) {
- free(ClUserAccountingFilePath);
- ClUserAccountingFilePath = NULL;
- }
- if (FilePath == NULL) {
- return 0;
- }
- ClUserAccountingFilePath = strdup(FilePath);
- if (ClUserAccountingFilePath != NULL) {
- return 0;
- }
- return -1;
- }
- LIBC_API
- void
- updwtmpx (
- const char *FileName,
- const struct utmpx *Record
- )
- /*++
- Routine Description:
- This routine adds an entry into the wtmp user database.
- Arguments:
- FileName - Supplies a pointer to path of the wtmp file to open. Set this to
- WTMP_FILE by default.
- Record - Supplies a pointer to the record to append.
- Return Value:
- None.
- --*/
- {
- int Descriptor;
- ssize_t Written;
- Descriptor = open(FileName, O_WRONLY | O_APPEND, 0);
- if (Descriptor < 0) {
- return;
- }
- do {
- Written = write(Descriptor, Record, sizeof(struct utmpx));
- } while ((Written <= 0) && (errno == EINTR));
- close(Descriptor);
- return;
- }
- LIBC_API
- void
- getutmpx (
- const struct utmp *ValueToConvert,
- struct utmpx *ConvertedValue
- )
- /*++
- Routine Description:
- This routine converts a utmp structure into a utmpx structure. Since the
- structures are exactly the same, this is just a straight copy.
- Arguments:
- ValueToConvert - Supplies a pointer to the utmp structure to convert.
- ConvertedValue - Supplies a pointer where the converted utmpx strucutre
- will be returned.
- Return Value:
- None.
- --*/
- {
- assert(sizeof(struct utmp) == sizeof(struct utmpx));
- memcpy(ConvertedValue, ValueToConvert, sizeof(struct utmpx));
- return;
- }
- LIBC_API
- void
- getutmp (
- const struct utmpx *ValueToConvert,
- struct utmp *ConvertedValue
- )
- /*++
- Routine Description:
- This routine converts a utmpx structure into a utmp structure. Since the
- structures are exactly the same, this is just a straight copy.
- Arguments:
- ValueToConvert - Supplies a pointer to the utmpx structure to convert.
- ConvertedValue - Supplies a pointer where the converted utmp strucutre
- will be returned.
- Return Value:
- None.
- --*/
- {
- assert(sizeof(struct utmp) == sizeof(struct utmpx));
- memcpy(ConvertedValue, ValueToConvert, sizeof(struct utmp));
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- INT
- ClpOpenUserAccountingDatabase (
- PSTR DatabaseFile
- )
- /*++
- Routine Description:
- This routine opens the user accounting database file.
- Arguments:
- DatabaseFile - Supplies an optional pointer to a string containing the
- path to open.
- Return Value:
- 0 on success.
- -1 on failure, and errno is set to contain more information.
- --*/
- {
- if (DatabaseFile == NULL) {
- DatabaseFile = UTMPX_FILE;
- }
- if (ClUserAccountingFile >= 0) {
- endutxent();
- }
- assert(ClUserAccountingFile == -1);
- ClUserAccountingFile = open(DatabaseFile, O_RDWR);
- if (ClUserAccountingFile < 0) {
- ClUserAccountingFile = open(DatabaseFile, O_RDONLY);
- }
- if (ClUserAccountingFile < 0) {
- return -1;
- }
- return 0;
- }
- INT
- ClpReadWriteUserAccountingEntry (
- struct utmpx *Entry,
- INT Type
- )
- /*++
- Routine Description:
- This routine reads from or writes to a user accounting database. It uses
- voluntary file locking to achieve synchronization.
- Arguments:
- Entry - Supplies a pointer to the entry to read or write.
- Type - Supplies the file locking operation to perform. Valid values are
- F_WRLCK or F_RDLCK.
- Return Value:
- 0 on success.
- -1 on failure, and errno is set to contain more information.
- --*/
- {
- ssize_t BytesDone;
- struct flock Lock;
- off_t Offset;
- if (Entry == NULL) {
- Entry = ClUserAccountingEntry;
- }
- //
- // Save the previous offset in case it has to be restored due to a partial
- // read or write.
- //
- Offset = lseek(ClUserAccountingFile, 0, SEEK_CUR);
- //
- // Lock the region of interest in the file.
- //
- Lock.l_start = Offset;
- Lock.l_len = sizeof(struct utmpx);
- Lock.l_pid = 0;
- Lock.l_type = Type;
- Lock.l_whence = SEEK_SET;
- if (fcntl(ClUserAccountingFile, F_SETLKW, &Lock) != 0) {
- return -1;
- }
- do {
- if (Type == F_WRLCK) {
- BytesDone = write(ClUserAccountingFile,
- Entry,
- sizeof(struct utmpx));
- } else {
- assert(Type == F_RDLCK);
- BytesDone = read(ClUserAccountingFile, Entry, sizeof(struct utmpx));
- }
- } while ((BytesDone < 0) && (errno == EINTR));
- //
- // Unlock the file.
- //
- Lock.l_type = F_UNLCK;
- fcntl(ClUserAccountingFile, F_SETLK, &Lock);
- if (BytesDone != sizeof(struct utmpx)) {
- lseek(ClUserAccountingFile, Offset, SEEK_SET);
- return -1;
- }
- return 0;
- }
|