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 41*126b6df9SEd Schouten #ifdef __NO_TLS 42a627ac61SEd Schouten static FILE *uf = NULL; 43a627ac61SEd Schouten static int udb; 44*126b6df9SEd Schouten #else 45*126b6df9SEd Schouten static _Thread_local FILE *uf = NULL; 46*126b6df9SEd Schouten static _Thread_local int udb; 47*126b6df9SEd 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); 74a627ac61SEd Schouten uf = fopen(file, "r"); 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 1251ae6a21dSEd Schouten if (fread(&len, sizeof(len), 1, uf) != 1) 12698c63a48SEd Schouten return (-1); 127a627ac61SEd Schouten len = be16toh(len); 12898c63a48SEd Schouten if (len > sizeof *fu) { 129a627ac61SEd Schouten /* Forward compatibility. */ 1301ae6a21dSEd Schouten if (fread(fu, sizeof(*fu), 1, uf) != 1) 13198c63a48SEd Schouten return (-1); 1321ae6a21dSEd Schouten fseek(uf, len - sizeof(*fu), SEEK_CUR); 133a627ac61SEd Schouten } else { 134a627ac61SEd Schouten /* Partial record. */ 1351ae6a21dSEd Schouten memset(fu, 0, sizeof(*fu)); 13698c63a48SEd Schouten if (fread(fu, len, 1, uf) != 1) 13798c63a48SEd Schouten return (-1); 138a627ac61SEd Schouten } 139a627ac61SEd Schouten } else { 1401ae6a21dSEd Schouten if (fread(fu, sizeof(*fu), 1, uf) != 1) 14198c63a48SEd Schouten return (-1); 142a627ac61SEd Schouten } 14398c63a48SEd Schouten return (0); 144a627ac61SEd Schouten } 145a627ac61SEd Schouten 146a627ac61SEd Schouten struct utmpx * 147a627ac61SEd Schouten getutxent(void) 148a627ac61SEd Schouten { 14998c63a48SEd Schouten struct futx fu; 150a627ac61SEd Schouten 15198c63a48SEd Schouten if (getfutxent(&fu) != 0) 152a627ac61SEd Schouten return (NULL); 15398c63a48SEd Schouten return (futx_to_utx(&fu)); 154a627ac61SEd Schouten } 155a627ac61SEd Schouten 156a627ac61SEd Schouten struct utmpx * 157a627ac61SEd Schouten getutxid(const struct utmpx *id) 158a627ac61SEd Schouten { 15998c63a48SEd Schouten struct futx fu; 160a627ac61SEd Schouten 161a627ac61SEd Schouten for (;;) { 16298c63a48SEd Schouten if (getfutxent(&fu) != 0) 163a627ac61SEd Schouten return (NULL); 164a627ac61SEd Schouten 16598c63a48SEd Schouten switch (fu.fu_type) { 166a627ac61SEd Schouten case USER_PROCESS: 167a627ac61SEd Schouten case INIT_PROCESS: 168a627ac61SEd Schouten case LOGIN_PROCESS: 169a627ac61SEd Schouten case DEAD_PROCESS: 170a627ac61SEd Schouten switch (id->ut_type) { 171a627ac61SEd Schouten case USER_PROCESS: 172a627ac61SEd Schouten case INIT_PROCESS: 173a627ac61SEd Schouten case LOGIN_PROCESS: 174a627ac61SEd Schouten case DEAD_PROCESS: 17598c63a48SEd Schouten if (memcmp(fu.fu_id, id->ut_id, 1761ae6a21dSEd Schouten MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) == 1771ae6a21dSEd Schouten 0) 178a627ac61SEd Schouten goto found; 179a627ac61SEd Schouten } 180e35a88d3SEd Schouten break; 18198c63a48SEd Schouten default: 18298c63a48SEd Schouten if (fu.fu_type == id->ut_type) 18398c63a48SEd Schouten goto found; 18498c63a48SEd Schouten break; 185a627ac61SEd Schouten } 186a627ac61SEd Schouten } 187a627ac61SEd Schouten 188a627ac61SEd Schouten found: 18998c63a48SEd Schouten return (futx_to_utx(&fu)); 190a627ac61SEd Schouten } 191a627ac61SEd Schouten 192a627ac61SEd Schouten struct utmpx * 193a627ac61SEd Schouten getutxline(const struct utmpx *line) 194a627ac61SEd Schouten { 19598c63a48SEd Schouten struct futx fu; 196a627ac61SEd Schouten 197a627ac61SEd Schouten for (;;) { 19898c63a48SEd Schouten if (getfutxent(&fu) != 0) 199a627ac61SEd Schouten return (NULL); 200a627ac61SEd Schouten 20198c63a48SEd Schouten switch (fu.fu_type) { 202a627ac61SEd Schouten case USER_PROCESS: 203a627ac61SEd Schouten case LOGIN_PROCESS: 20498c63a48SEd Schouten if (strncmp(fu.fu_line, line->ut_line, 2051ae6a21dSEd Schouten MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) == 2061ae6a21dSEd Schouten 0) 207a627ac61SEd Schouten goto found; 20898c63a48SEd Schouten break; 209a627ac61SEd Schouten } 210a627ac61SEd Schouten } 211a627ac61SEd Schouten 212a627ac61SEd Schouten found: 21398c63a48SEd Schouten return (futx_to_utx(&fu)); 214a627ac61SEd Schouten } 215a627ac61SEd Schouten 216a627ac61SEd Schouten struct utmpx * 217a627ac61SEd Schouten getutxuser(const char *user) 218a627ac61SEd Schouten { 21998c63a48SEd Schouten struct futx fu; 220a627ac61SEd Schouten 221a627ac61SEd Schouten for (;;) { 22298c63a48SEd Schouten if (getfutxent(&fu) != 0) 223a627ac61SEd Schouten return (NULL); 224a627ac61SEd Schouten 22598c63a48SEd Schouten switch (fu.fu_type) { 226a627ac61SEd Schouten case USER_PROCESS: 2271ae6a21dSEd Schouten if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0) 228a627ac61SEd Schouten goto found; 22998c63a48SEd Schouten break; 230a627ac61SEd Schouten } 231a627ac61SEd Schouten } 232a627ac61SEd Schouten 233a627ac61SEd Schouten found: 23498c63a48SEd Schouten return (futx_to_utx(&fu)); 235a627ac61SEd Schouten } 236