getutxent.c revision 302408
125184Sjkh/*- 225184Sjkh * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org> 350193Sbrian * All rights reserved. 425184Sjkh * 525184Sjkh * Redistribution and use in source and binary forms, with or without 625184Sjkh * modification, are permitted provided that the following conditions 725184Sjkh * are met: 825184Sjkh * 1. Redistributions of source code must retain the above copyright 925184Sjkh * notice, this list of conditions and the following disclaimer. 1025184Sjkh * 2. Redistributions in binary form must reproduce the above copyright 1125184Sjkh * notice, this list of conditions and the following disclaimer in the 1225184Sjkh * documentation and/or other materials provided with the distribution. 1325184Sjkh * 1425184Sjkh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1525184Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1625184Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1725184Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1825184Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1925184Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2025184Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2125184Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2225184Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2325184Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2425184Sjkh * SUCH DAMAGE. 2525184Sjkh */ 2625184Sjkh 2725184Sjkh#include <sys/cdefs.h> 2840006Sphk__FBSDID("$FreeBSD: stable/11/lib/libc/gen/getutxent.c 256537 2013-10-15 13:32:01Z glebius $"); 2940006Sphk 3040006Sphk#include "namespace.h" 3140006Sphk#include <sys/endian.h> 3240006Sphk#include <sys/param.h> 3340006Sphk#include <sys/stat.h> 3442621Shm#include <errno.h> 3542621Shm#include <stdio.h> 3642621Shm#include <string.h> 3742621Shm#include <utmpx.h> 3842621Shm#include "utxdb.h" 3942627Sjoerg#include "un-namespace.h" 4042627Sjoerg 4142627Sjoerg#ifdef __NO_TLS 4242627Sjoergstatic FILE *uf = NULL; 4342627Sjoergstatic int udb; 4442627Sjoerg#else 4542627Sjoergstatic _Thread_local FILE *uf = NULL; 4642627Sjoergstatic _Thread_local int udb; 4742627Sjoerg#endif 4842627Sjoerg 4942627Sjoergint 5042627Sjoergsetutxdb(int db, const char *file) 5142627Sjoerg{ 5242627Sjoerg struct stat sb; 5325184Sjkh 5448687Speter switch (db) { 5548687Speter case UTXDB_ACTIVE: 5648687Speter if (file == NULL) 5748687Speter file = _PATH_UTX_ACTIVE; 5848662Speter break; 5925184Sjkh case UTXDB_LASTLOGIN: 6033682Sbrian if (file == NULL) 6148662Speter file = _PATH_UTX_LASTLOGIN; 6225184Sjkh break; 6325184Sjkh case UTXDB_LOG: 6425184Sjkh if (file == NULL) 6525184Sjkh file = _PATH_UTX_LOG; 6648842Sjkh break; 6748842Sjkh default: 6848842Sjkh errno = EINVAL; 6948842Sjkh return (-1); 7048842Sjkh } 7148842Sjkh 7248662Speter if (uf != NULL) 7325184Sjkh fclose(uf); 7425184Sjkh uf = fopen(file, "re"); 7525184Sjkh if (uf == NULL) 7625184Sjkh return (-1); 7725184Sjkh 7825184Sjkh if (db != UTXDB_LOG) { 7925184Sjkh /* Safety check: never use broken files. */ 8025184Sjkh if (_fstat(fileno(uf), &sb) != -1 && 8148662Speter sb.st_size % sizeof(struct futx) != 0) { 8225184Sjkh fclose(uf); 8325184Sjkh uf = NULL; 8425184Sjkh errno = EFTYPE; 8525184Sjkh return (-1); 8625184Sjkh } 8725184Sjkh /* Prevent reading of partial records. */ 8825184Sjkh (void)setvbuf(uf, NULL, _IOFBF, 8925184Sjkh rounddown(BUFSIZ, sizeof(struct futx))); 9025184Sjkh } 9148662Speter 9225184Sjkh udb = db; 9348662Speter return (0); 9448662Speter} 9548662Speter 9648662Spetervoid 9725184Sjkhsetutxent(void) 9829300Sdanny{ 9949122Sbrian 10049122Sbrian setutxdb(UTXDB_ACTIVE, NULL); 10149122Sbrian} 10249122Sbrian 10349122Sbrianvoid 10449122Sbrianendutxent(void) 10549122Sbrian{ 10649122Sbrian 10749122Sbrian if (uf != NULL) { 10849122Sbrian fclose(uf); 10950193Sbrian uf = NULL; 11050193Sbrian } 11149122Sbrian} 11249122Sbrian 11350063Sbrianstatic int 11449122Sbriangetfutxent(struct futx *fu) 11549122Sbrian{ 11629300Sdanny 11729300Sdanny if (uf == NULL) 11829300Sdanny setutxent(); 11932382Salex if (uf == NULL) 12032382Salex return (-1); 12132382Salex 12229300Sdanny if (udb == UTXDB_LOG) { 12329300Sdanny uint16_t len; 12429300Sdanny 12529300Sdannyretry: 12641077Speter if (fread(&len, sizeof(len), 1, uf) != 1) 12729300Sdanny return (-1); 12829300Sdanny len = be16toh(len); 12929300Sdanny if (len == 0) { 13029300Sdanny /* 13129300Sdanny * XXX: Though zero-size records are valid in theory, 13229300Sdanny * they can never occur in practice. Zero-size records 13329300Sdanny * indicate file corruption. Seek one byte forward, to 13429300Sdanny * see if we can find a record there. 13529300Sdanny */ 13645542Sdes ungetc('\0', uf); 13745542Sdes goto retry; 13845542Sdes } 13945542Sdes if (len > sizeof *fu) { 14045542Sdes /* Forward compatibility. */ 14145622Sbrian if (fread(fu, sizeof(*fu), 1, uf) != 1) 14244992Sbrian return (-1); 14344992Sbrian fseek(uf, len - sizeof(*fu), SEEK_CUR); 14444992Sbrian } else { 14544992Sbrian /* Partial record. */ 14644992Sbrian memset(fu, 0, sizeof(*fu)); 14744992Sbrian if (fread(fu, len, 1, uf) != 1) 14844992Sbrian return (-1); 14944992Sbrian } 15044992Sbrian } else { 15144992Sbrian if (fread(fu, sizeof(*fu), 1, uf) != 1) 15244992Sbrian return (-1); 15344992Sbrian } 15429300Sdanny return (0); 15533337Salex} 15633337Salex 15733149Salexstruct utmpx * 15833149Salexgetutxent(void) 15933149Salex{ 16033149Salex struct futx fu; 16129300Sdanny 16225184Sjkh if (getfutxent(&fu) != 0) 16325184Sjkh return (NULL); 16440006Sphk return (futx_to_utx(&fu)); 16540006Sphk} 16640006Sphk 16740006Sphkstruct utmpx * 16840006Sphkgetutxid(const struct utmpx *id) 16929300Sdanny{ 17029300Sdanny struct futx fu; 17125184Sjkh 17225184Sjkh for (;;) { 17325184Sjkh if (getfutxent(&fu) != 0) 17425184Sjkh return (NULL); 17525184Sjkh 17625184Sjkh switch (fu.fu_type) { 17725184Sjkh case USER_PROCESS: 17825184Sjkh case INIT_PROCESS: 17925184Sjkh case LOGIN_PROCESS: 18025184Sjkh case DEAD_PROCESS: 18125184Sjkh switch (id->ut_type) { 18225184Sjkh case USER_PROCESS: 18325184Sjkh case INIT_PROCESS: 18425184Sjkh case LOGIN_PROCESS: 18527218Spst case DEAD_PROCESS: 18627218Spst if (memcmp(fu.fu_id, id->ut_id, 18747755Sbde MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) == 18827218Spst 0) 18927218Spst goto found; 19045096Simp } 19145096Simp break; 19247755Sbde default: 19347755Sbde if (fu.fu_type == id->ut_type) 19445096Simp goto found; 19545096Simp break; 19639267Sjkoshy } 19739267Sjkoshy } 19847755Sbde 19939267Sjkoshyfound: 20049603Sdes return (futx_to_utx(&fu)); 20149603Sdes} 20249603Sdes 20349603Sdesstruct utmpx * 20449603Sdesgetutxline(const struct utmpx *line) 20549603Sdes{ 20649603Sdes struct futx fu; 20749603Sdes 20849603Sdes for (;;) { 20949603Sdes if (getfutxent(&fu) != 0) 21039267Sjkoshy return (NULL); 21125184Sjkh 21225365Sjkh switch (fu.fu_type) { 21347755Sbde case USER_PROCESS: 21425184Sjkh case LOGIN_PROCESS: 21525184Sjkh if (strncmp(fu.fu_line, line->ut_line, 21633439Sguido MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) == 21733439Sguido 0) 21847755Sbde goto found; 21933439Sguido break; 22033439Sguido } 22133439Sguido } 22233439Sguido 22347755Sbdefound: 22433439Sguido return (futx_to_utx(&fu)); 22533439Sguido} 22647752Sphk 22747752Sphkstruct utmpx * 22847755Sbdegetutxuser(const char *user) 22947752Sphk{ 23047752Sphk struct futx fu; 23125184Sjkh 23225365Sjkh for (;;) { 23347755Sbde if (getfutxent(&fu) != 0) 23425184Sjkh return (NULL); 23525184Sjkh 23636174Sjkh switch (fu.fu_type) { 23747755Sbde case USER_PROCESS: 23847755Sbde if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0) 23936174Sjkh goto found; 24036174Sjkh break; 24136174Sjkh } 24236174Sjkh } 24336174Sjkh 24436174Sjkhfound: 24536174Sjkh return (futx_to_utx(&fu)); 24636174Sjkh} 24725184Sjkh