1a627ac61SEd Schouten /*- 2a627ac61SEd Schouten * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org> 3a627ac61SEd Schouten * All rights reserved. 4a627ac61SEd Schouten * 5a627ac61SEd Schouten * Redistribution and use in source and binary forms, with or without 6a627ac61SEd Schouten * modification, are permitted provided that the following conditions 7a627ac61SEd Schouten * are met: 8a627ac61SEd Schouten * 1. Redistributions of source code must retain the above copyright 9a627ac61SEd Schouten * notice, this list of conditions and the following disclaimer. 10a627ac61SEd Schouten * 2. Redistributions in binary form must reproduce the above copyright 11a627ac61SEd Schouten * notice, this list of conditions and the following disclaimer in the 12a627ac61SEd Schouten * documentation and/or other materials provided with the distribution. 13a627ac61SEd Schouten * 14a627ac61SEd Schouten * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15a627ac61SEd Schouten * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16a627ac61SEd Schouten * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17a627ac61SEd Schouten * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18a627ac61SEd Schouten * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19a627ac61SEd Schouten * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20a627ac61SEd Schouten * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21a627ac61SEd Schouten * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22a627ac61SEd Schouten * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23a627ac61SEd Schouten * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24a627ac61SEd Schouten * SUCH DAMAGE. 25a627ac61SEd Schouten */ 26a627ac61SEd Schouten 27a627ac61SEd Schouten #include <sys/cdefs.h> 28a627ac61SEd Schouten __FBSDID("$FreeBSD$"); 29a627ac61SEd Schouten 30a627ac61SEd Schouten #include "namespace.h" 31a627ac61SEd Schouten #include <sys/endian.h> 32a627ac61SEd Schouten #include <sys/param.h> 33a627ac61SEd Schouten #include <sys/stat.h> 34a627ac61SEd Schouten #include <errno.h> 35a627ac61SEd Schouten #include <stdio.h> 36a627ac61SEd Schouten #include <string.h> 37a627ac61SEd Schouten #include <utmpx.h> 38a627ac61SEd Schouten #include "utxdb.h" 39a627ac61SEd Schouten #include "un-namespace.h" 40a627ac61SEd Schouten 41126b6df9SEd Schouten #ifdef __NO_TLS 42a627ac61SEd Schouten static FILE *uf = NULL; 43a627ac61SEd Schouten static int udb; 44126b6df9SEd Schouten #else 45126b6df9SEd Schouten static _Thread_local FILE *uf = NULL; 46126b6df9SEd Schouten static _Thread_local int udb; 47126b6df9SEd Schouten #endif 48a627ac61SEd Schouten 49a627ac61SEd Schouten int 50a627ac61SEd Schouten setutxdb(int db, const char *file) 51a627ac61SEd Schouten { 52a627ac61SEd Schouten struct stat sb; 53a627ac61SEd Schouten 54a627ac61SEd Schouten switch (db) { 55a627ac61SEd Schouten case UTXDB_ACTIVE: 56a627ac61SEd Schouten if (file == NULL) 57a627ac61SEd Schouten file = _PATH_UTX_ACTIVE; 58a627ac61SEd Schouten break; 59a627ac61SEd Schouten case UTXDB_LASTLOGIN: 60a627ac61SEd Schouten if (file == NULL) 61a627ac61SEd Schouten file = _PATH_UTX_LASTLOGIN; 62a627ac61SEd Schouten break; 63a627ac61SEd Schouten case UTXDB_LOG: 64a627ac61SEd Schouten if (file == NULL) 65a627ac61SEd Schouten file = _PATH_UTX_LOG; 66a627ac61SEd Schouten break; 67a627ac61SEd Schouten default: 68a627ac61SEd Schouten errno = EINVAL; 69a627ac61SEd Schouten return (-1); 70a627ac61SEd Schouten } 71a627ac61SEd Schouten 72a627ac61SEd Schouten if (uf != NULL) 73a627ac61SEd Schouten fclose(uf); 741084b38bSJilles Tjoelker uf = fopen(file, "re"); 75a627ac61SEd Schouten if (uf == NULL) 76a627ac61SEd Schouten return (-1); 77a627ac61SEd Schouten 78a8f77c1fSEd Schouten if (db != UTXDB_LOG) { 79a627ac61SEd Schouten /* Safety check: never use broken files. */ 80a8f77c1fSEd Schouten if (_fstat(fileno(uf), &sb) != -1 && 81a627ac61SEd Schouten sb.st_size % sizeof(struct futx) != 0) { 82a627ac61SEd Schouten fclose(uf); 83a627ac61SEd Schouten uf = NULL; 84a627ac61SEd Schouten errno = EFTYPE; 85a627ac61SEd Schouten return (-1); 86a627ac61SEd Schouten } 87a8f77c1fSEd Schouten /* Prevent reading of partial records. */ 88a8f77c1fSEd Schouten (void)setvbuf(uf, NULL, _IOFBF, 89a8f77c1fSEd Schouten rounddown(BUFSIZ, sizeof(struct futx))); 90a8f77c1fSEd Schouten } 91a627ac61SEd Schouten 92a627ac61SEd Schouten udb = db; 93a627ac61SEd Schouten return (0); 94a627ac61SEd Schouten } 95a627ac61SEd Schouten 96a627ac61SEd Schouten void 97a627ac61SEd Schouten setutxent(void) 98a627ac61SEd Schouten { 99a627ac61SEd Schouten 100a627ac61SEd Schouten setutxdb(UTXDB_ACTIVE, NULL); 101a627ac61SEd Schouten } 102a627ac61SEd Schouten 103a627ac61SEd Schouten void 104a627ac61SEd Schouten endutxent(void) 105a627ac61SEd Schouten { 106a627ac61SEd Schouten 107a627ac61SEd Schouten if (uf != NULL) { 108a627ac61SEd Schouten fclose(uf); 109a627ac61SEd Schouten uf = NULL; 110a627ac61SEd Schouten } 111a627ac61SEd Schouten } 112a627ac61SEd Schouten 11398c63a48SEd Schouten static int 11498c63a48SEd Schouten getfutxent(struct futx *fu) 115a627ac61SEd Schouten { 116a627ac61SEd Schouten 117a627ac61SEd Schouten if (uf == NULL) 118a627ac61SEd Schouten setutxent(); 119a627ac61SEd Schouten if (uf == NULL) 12098c63a48SEd Schouten return (-1); 121a627ac61SEd Schouten 122a627ac61SEd Schouten if (udb == UTXDB_LOG) { 123a627ac61SEd Schouten uint16_t len; 124a627ac61SEd Schouten 125*a1739165SGleb Smirnoff retry: 1261ae6a21dSEd Schouten if (fread(&len, sizeof(len), 1, uf) != 1) 12798c63a48SEd Schouten return (-1); 128a627ac61SEd Schouten len = be16toh(len); 129*a1739165SGleb Smirnoff if (len == 0) { 130*a1739165SGleb Smirnoff /* 131*a1739165SGleb Smirnoff * XXX: Though zero-size records are valid in theory, 132*a1739165SGleb Smirnoff * they can never occur in practice. Zero-size records 133*a1739165SGleb Smirnoff * indicate file corruption. Seek one byte forward, to 134*a1739165SGleb Smirnoff * see if we can find a record there. 135*a1739165SGleb Smirnoff */ 136*a1739165SGleb Smirnoff ungetc('\0', uf); 137*a1739165SGleb Smirnoff goto retry; 138*a1739165SGleb Smirnoff } 13998c63a48SEd Schouten if (len > sizeof *fu) { 140a627ac61SEd Schouten /* Forward compatibility. */ 1411ae6a21dSEd Schouten if (fread(fu, sizeof(*fu), 1, uf) != 1) 14298c63a48SEd Schouten return (-1); 1431ae6a21dSEd Schouten fseek(uf, len - sizeof(*fu), SEEK_CUR); 144a627ac61SEd Schouten } else { 145a627ac61SEd Schouten /* Partial record. */ 1461ae6a21dSEd Schouten memset(fu, 0, sizeof(*fu)); 14798c63a48SEd Schouten if (fread(fu, len, 1, uf) != 1) 14898c63a48SEd Schouten return (-1); 149a627ac61SEd Schouten } 150a627ac61SEd Schouten } else { 1511ae6a21dSEd Schouten if (fread(fu, sizeof(*fu), 1, uf) != 1) 15298c63a48SEd Schouten return (-1); 153a627ac61SEd Schouten } 15498c63a48SEd Schouten return (0); 155a627ac61SEd Schouten } 156a627ac61SEd Schouten 157a627ac61SEd Schouten struct utmpx * 158a627ac61SEd Schouten getutxent(void) 159a627ac61SEd Schouten { 16098c63a48SEd Schouten struct futx fu; 161a627ac61SEd Schouten 16298c63a48SEd Schouten if (getfutxent(&fu) != 0) 163a627ac61SEd Schouten return (NULL); 16498c63a48SEd Schouten return (futx_to_utx(&fu)); 165a627ac61SEd Schouten } 166a627ac61SEd Schouten 167a627ac61SEd Schouten struct utmpx * 168a627ac61SEd Schouten getutxid(const struct utmpx *id) 169a627ac61SEd Schouten { 17098c63a48SEd Schouten struct futx fu; 171a627ac61SEd Schouten 172a627ac61SEd Schouten for (;;) { 17398c63a48SEd Schouten if (getfutxent(&fu) != 0) 174a627ac61SEd Schouten return (NULL); 175a627ac61SEd Schouten 17698c63a48SEd Schouten switch (fu.fu_type) { 177a627ac61SEd Schouten case USER_PROCESS: 178a627ac61SEd Schouten case INIT_PROCESS: 179a627ac61SEd Schouten case LOGIN_PROCESS: 180a627ac61SEd Schouten case DEAD_PROCESS: 181a627ac61SEd Schouten switch (id->ut_type) { 182a627ac61SEd Schouten case USER_PROCESS: 183a627ac61SEd Schouten case INIT_PROCESS: 184a627ac61SEd Schouten case LOGIN_PROCESS: 185a627ac61SEd Schouten case DEAD_PROCESS: 18698c63a48SEd Schouten if (memcmp(fu.fu_id, id->ut_id, 1871ae6a21dSEd Schouten MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) == 1881ae6a21dSEd Schouten 0) 189a627ac61SEd Schouten goto found; 190a627ac61SEd Schouten } 191e35a88d3SEd Schouten break; 19298c63a48SEd Schouten default: 19398c63a48SEd Schouten if (fu.fu_type == id->ut_type) 19498c63a48SEd Schouten goto found; 19598c63a48SEd Schouten break; 196a627ac61SEd Schouten } 197a627ac61SEd Schouten } 198a627ac61SEd Schouten 199a627ac61SEd Schouten found: 20098c63a48SEd Schouten return (futx_to_utx(&fu)); 201a627ac61SEd Schouten } 202a627ac61SEd Schouten 203a627ac61SEd Schouten struct utmpx * 204a627ac61SEd Schouten getutxline(const struct utmpx *line) 205a627ac61SEd Schouten { 20698c63a48SEd Schouten struct futx fu; 207a627ac61SEd Schouten 208a627ac61SEd Schouten for (;;) { 20998c63a48SEd Schouten if (getfutxent(&fu) != 0) 210a627ac61SEd Schouten return (NULL); 211a627ac61SEd Schouten 21298c63a48SEd Schouten switch (fu.fu_type) { 213a627ac61SEd Schouten case USER_PROCESS: 214a627ac61SEd Schouten case LOGIN_PROCESS: 21598c63a48SEd Schouten if (strncmp(fu.fu_line, line->ut_line, 2161ae6a21dSEd Schouten MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) == 2171ae6a21dSEd Schouten 0) 218a627ac61SEd Schouten goto found; 21998c63a48SEd Schouten break; 220a627ac61SEd Schouten } 221a627ac61SEd Schouten } 222a627ac61SEd Schouten 223a627ac61SEd Schouten found: 22498c63a48SEd Schouten return (futx_to_utx(&fu)); 225a627ac61SEd Schouten } 226a627ac61SEd Schouten 227a627ac61SEd Schouten struct utmpx * 228a627ac61SEd Schouten getutxuser(const char *user) 229a627ac61SEd Schouten { 23098c63a48SEd Schouten struct futx fu; 231a627ac61SEd Schouten 232a627ac61SEd Schouten for (;;) { 23398c63a48SEd Schouten if (getfutxent(&fu) != 0) 234a627ac61SEd Schouten return (NULL); 235a627ac61SEd Schouten 23698c63a48SEd Schouten switch (fu.fu_type) { 237a627ac61SEd Schouten case USER_PROCESS: 2381ae6a21dSEd Schouten if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0) 239a627ac61SEd Schouten goto found; 24098c63a48SEd Schouten break; 241a627ac61SEd Schouten } 242a627ac61SEd Schouten } 243a627ac61SEd Schouten 244a627ac61SEd Schouten found: 24598c63a48SEd Schouten return (futx_to_utx(&fu)); 246a627ac61SEd Schouten } 247