xref: /freebsd/lib/libc/gen/getutxent.c (revision a173916590ffbc512de8d0e99358e91e096f1877)
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