1202188Sed/*- 2202188Sed * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org> 3202188Sed * All rights reserved. 4202188Sed * 5202188Sed * Redistribution and use in source and binary forms, with or without 6202188Sed * modification, are permitted provided that the following conditions 7202188Sed * are met: 8202188Sed * 1. Redistributions of source code must retain the above copyright 9202188Sed * notice, this list of conditions and the following disclaimer. 10202188Sed * 2. Redistributions in binary form must reproduce the above copyright 11202188Sed * notice, this list of conditions and the following disclaimer in the 12202188Sed * documentation and/or other materials provided with the distribution. 13202188Sed * 14202188Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15202188Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16202188Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17202188Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18202188Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19202188Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20202188Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21202188Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22202188Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23202188Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24202188Sed * SUCH DAMAGE. 25202188Sed */ 26202188Sed 27202188Sed#include <sys/cdefs.h> 28202188Sed__FBSDID("$FreeBSD$"); 29202188Sed 30202188Sed#include "namespace.h" 31202188Sed#include <sys/endian.h> 32202188Sed#include <sys/param.h> 33202188Sed#include <sys/stat.h> 34202188Sed#include <errno.h> 35202188Sed#include <stdio.h> 36202188Sed#include <string.h> 37202188Sed#include <utmpx.h> 38202188Sed#include "utxdb.h" 39202188Sed#include "un-namespace.h" 40202188Sed 41233345Sed#ifdef __NO_TLS 42202188Sedstatic FILE *uf = NULL; 43202188Sedstatic int udb; 44233345Sed#else 45233345Sedstatic _Thread_local FILE *uf = NULL; 46233345Sedstatic _Thread_local int udb; 47233345Sed#endif 48202188Sed 49202188Sedint 50202188Sedsetutxdb(int db, const char *file) 51202188Sed{ 52202188Sed struct stat sb; 53202188Sed 54202188Sed switch (db) { 55202188Sed case UTXDB_ACTIVE: 56202188Sed if (file == NULL) 57202188Sed file = _PATH_UTX_ACTIVE; 58202188Sed break; 59202188Sed case UTXDB_LASTLOGIN: 60202188Sed if (file == NULL) 61202188Sed file = _PATH_UTX_LASTLOGIN; 62202188Sed break; 63202188Sed case UTXDB_LOG: 64202188Sed if (file == NULL) 65202188Sed file = _PATH_UTX_LOG; 66202188Sed break; 67202188Sed default: 68202188Sed errno = EINVAL; 69202188Sed return (-1); 70202188Sed } 71202188Sed 72202188Sed if (uf != NULL) 73202188Sed fclose(uf); 74244092Sjilles uf = fopen(file, "re"); 75202188Sed if (uf == NULL) 76202188Sed return (-1); 77202188Sed 78231514Sed if (db != UTXDB_LOG) { 79231514Sed /* Safety check: never use broken files. */ 80231514Sed if (_fstat(fileno(uf), &sb) != -1 && 81231514Sed sb.st_size % sizeof(struct futx) != 0) { 82231514Sed fclose(uf); 83231514Sed uf = NULL; 84231514Sed errno = EFTYPE; 85231514Sed return (-1); 86231514Sed } 87231514Sed /* Prevent reading of partial records. */ 88231514Sed (void)setvbuf(uf, NULL, _IOFBF, 89231514Sed rounddown(BUFSIZ, sizeof(struct futx))); 90202188Sed } 91202188Sed 92202188Sed udb = db; 93202188Sed return (0); 94202188Sed} 95202188Sed 96202188Sedvoid 97202188Sedsetutxent(void) 98202188Sed{ 99202188Sed 100202188Sed setutxdb(UTXDB_ACTIVE, NULL); 101202188Sed} 102202188Sed 103202188Sedvoid 104202188Sedendutxent(void) 105202188Sed{ 106202188Sed 107202188Sed if (uf != NULL) { 108202188Sed fclose(uf); 109202188Sed uf = NULL; 110202188Sed } 111202188Sed} 112202188Sed 113202530Sedstatic int 114202530Sedgetfutxent(struct futx *fu) 115202188Sed{ 116202188Sed 117202188Sed if (uf == NULL) 118202188Sed setutxent(); 119202188Sed if (uf == NULL) 120202530Sed return (-1); 121202188Sed 122202188Sed if (udb == UTXDB_LOG) { 123202188Sed uint16_t len; 124202188Sed 125257320Sglebiusretry: 126218846Sed if (fread(&len, sizeof(len), 1, uf) != 1) 127202530Sed return (-1); 128202188Sed len = be16toh(len); 129257320Sglebius if (len == 0) { 130257320Sglebius /* 131257320Sglebius * XXX: Though zero-size records are valid in theory, 132257320Sglebius * they can never occur in practice. Zero-size records 133257320Sglebius * indicate file corruption. Seek one byte forward, to 134257320Sglebius * see if we can find a record there. 135257320Sglebius */ 136257320Sglebius ungetc('\0', uf); 137257320Sglebius goto retry; 138257320Sglebius } 139202530Sed if (len > sizeof *fu) { 140202188Sed /* Forward compatibility. */ 141218846Sed if (fread(fu, sizeof(*fu), 1, uf) != 1) 142202530Sed return (-1); 143218846Sed fseek(uf, len - sizeof(*fu), SEEK_CUR); 144202188Sed } else { 145202188Sed /* Partial record. */ 146218846Sed memset(fu, 0, sizeof(*fu)); 147202530Sed if (fread(fu, len, 1, uf) != 1) 148202530Sed return (-1); 149202188Sed } 150202188Sed } else { 151218846Sed if (fread(fu, sizeof(*fu), 1, uf) != 1) 152202530Sed return (-1); 153202188Sed } 154202530Sed return (0); 155202188Sed} 156202188Sed 157202188Sedstruct utmpx * 158202188Sedgetutxent(void) 159202188Sed{ 160202530Sed struct futx fu; 161202188Sed 162202530Sed if (getfutxent(&fu) != 0) 163202188Sed return (NULL); 164202530Sed return (futx_to_utx(&fu)); 165202188Sed} 166202188Sed 167202188Sedstruct utmpx * 168202188Sedgetutxid(const struct utmpx *id) 169202188Sed{ 170202530Sed struct futx fu; 171202188Sed 172202188Sed for (;;) { 173202530Sed if (getfutxent(&fu) != 0) 174202188Sed return (NULL); 175202188Sed 176202530Sed switch (fu.fu_type) { 177202188Sed case USER_PROCESS: 178202188Sed case INIT_PROCESS: 179202188Sed case LOGIN_PROCESS: 180202188Sed case DEAD_PROCESS: 181202188Sed switch (id->ut_type) { 182202188Sed case USER_PROCESS: 183202188Sed case INIT_PROCESS: 184202188Sed case LOGIN_PROCESS: 185202188Sed case DEAD_PROCESS: 186202530Sed if (memcmp(fu.fu_id, id->ut_id, 187218846Sed MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) == 188218846Sed 0) 189202188Sed goto found; 190202188Sed } 191202527Sed break; 192202530Sed default: 193202530Sed if (fu.fu_type == id->ut_type) 194202530Sed goto found; 195202530Sed break; 196202188Sed } 197202188Sed } 198202188Sed 199202188Sedfound: 200202530Sed return (futx_to_utx(&fu)); 201202188Sed} 202202188Sed 203202188Sedstruct utmpx * 204202188Sedgetutxline(const struct utmpx *line) 205202188Sed{ 206202530Sed struct futx fu; 207202188Sed 208202188Sed for (;;) { 209202530Sed if (getfutxent(&fu) != 0) 210202188Sed return (NULL); 211202188Sed 212202530Sed switch (fu.fu_type) { 213202188Sed case USER_PROCESS: 214202188Sed case LOGIN_PROCESS: 215202530Sed if (strncmp(fu.fu_line, line->ut_line, 216218846Sed MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) == 217218846Sed 0) 218202188Sed goto found; 219202530Sed break; 220202188Sed } 221202188Sed } 222202188Sed 223202188Sedfound: 224202530Sed return (futx_to_utx(&fu)); 225202188Sed} 226202188Sed 227202188Sedstruct utmpx * 228202188Sedgetutxuser(const char *user) 229202188Sed{ 230202530Sed struct futx fu; 231202188Sed 232202188Sed for (;;) { 233202530Sed if (getfutxent(&fu) != 0) 234202188Sed return (NULL); 235202188Sed 236202530Sed switch (fu.fu_type) { 237202188Sed case USER_PROCESS: 238218846Sed if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0) 239202188Sed goto found; 240202530Sed break; 241202188Sed } 242202188Sed } 243202188Sed 244202188Sedfound: 245202530Sed return (futx_to_utx(&fu)); 246202188Sed} 247