xref: /freebsd/lib/libc/gen/getutxent.c (revision 1ae6a21db9b91f153f01159a9435b6c891656e97)
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 
41a627ac61SEd Schouten static FILE *uf = NULL;
42a627ac61SEd Schouten static int udb;
43a627ac61SEd Schouten 
44a627ac61SEd Schouten int
45a627ac61SEd Schouten setutxdb(int db, const char *file)
46a627ac61SEd Schouten {
47a627ac61SEd Schouten 	struct stat sb;
48a627ac61SEd Schouten 
49a627ac61SEd Schouten 	switch (db) {
50a627ac61SEd Schouten 	case UTXDB_ACTIVE:
51a627ac61SEd Schouten 		if (file == NULL)
52a627ac61SEd Schouten 			file = _PATH_UTX_ACTIVE;
53a627ac61SEd Schouten 		break;
54a627ac61SEd Schouten 	case UTXDB_LASTLOGIN:
55a627ac61SEd Schouten 		if (file == NULL)
56a627ac61SEd Schouten 			file = _PATH_UTX_LASTLOGIN;
57a627ac61SEd Schouten 		break;
58a627ac61SEd Schouten 	case UTXDB_LOG:
59a627ac61SEd Schouten 		if (file == NULL)
60a627ac61SEd Schouten 			file = _PATH_UTX_LOG;
61a627ac61SEd Schouten 		break;
62a627ac61SEd Schouten 	default:
63a627ac61SEd Schouten 		errno = EINVAL;
64a627ac61SEd Schouten 		return (-1);
65a627ac61SEd Schouten 	}
66a627ac61SEd Schouten 
67a627ac61SEd Schouten 	if (uf != NULL)
68a627ac61SEd Schouten 		fclose(uf);
69a627ac61SEd Schouten 	uf = fopen(file, "r");
70a627ac61SEd Schouten 	if (uf == NULL)
71a627ac61SEd Schouten 		return (-1);
72a627ac61SEd Schouten 
73a627ac61SEd Schouten 	/* Safety check: never use broken files. */
74a627ac61SEd Schouten 	if (db != UTXDB_LOG && _fstat(fileno(uf), &sb) != -1 &&
75a627ac61SEd Schouten 	    sb.st_size % sizeof(struct futx) != 0) {
76a627ac61SEd Schouten 		fclose(uf);
77a627ac61SEd Schouten 		uf = NULL;
78a627ac61SEd Schouten 		errno = EFTYPE;
79a627ac61SEd Schouten 		return (-1);
80a627ac61SEd Schouten 	}
81a627ac61SEd Schouten 
82a627ac61SEd Schouten 	udb = db;
83a627ac61SEd Schouten 	return (0);
84a627ac61SEd Schouten }
85a627ac61SEd Schouten 
86a627ac61SEd Schouten void
87a627ac61SEd Schouten setutxent(void)
88a627ac61SEd Schouten {
89a627ac61SEd Schouten 
90a627ac61SEd Schouten 	setutxdb(UTXDB_ACTIVE, NULL);
91a627ac61SEd Schouten }
92a627ac61SEd Schouten 
93a627ac61SEd Schouten void
94a627ac61SEd Schouten endutxent(void)
95a627ac61SEd Schouten {
96a627ac61SEd Schouten 
97a627ac61SEd Schouten 	if (uf != NULL) {
98a627ac61SEd Schouten 		fclose(uf);
99a627ac61SEd Schouten 		uf = NULL;
100a627ac61SEd Schouten 	}
101a627ac61SEd Schouten }
102a627ac61SEd Schouten 
10398c63a48SEd Schouten static int
10498c63a48SEd Schouten getfutxent(struct futx *fu)
105a627ac61SEd Schouten {
106a627ac61SEd Schouten 
107a627ac61SEd Schouten 	if (uf == NULL)
108a627ac61SEd Schouten 		setutxent();
109a627ac61SEd Schouten 	if (uf == NULL)
11098c63a48SEd Schouten 		return (-1);
111a627ac61SEd Schouten 
112a627ac61SEd Schouten 	if (udb == UTXDB_LOG) {
113a627ac61SEd Schouten 		uint16_t len;
114a627ac61SEd Schouten 
115*1ae6a21dSEd Schouten 		if (fread(&len, sizeof(len), 1, uf) != 1)
11698c63a48SEd Schouten 			return (-1);
117a627ac61SEd Schouten 		len = be16toh(len);
11898c63a48SEd Schouten 		if (len > sizeof *fu) {
119a627ac61SEd Schouten 			/* Forward compatibility. */
120*1ae6a21dSEd Schouten 			if (fread(fu, sizeof(*fu), 1, uf) != 1)
12198c63a48SEd Schouten 				return (-1);
122*1ae6a21dSEd Schouten 			fseek(uf, len - sizeof(*fu), SEEK_CUR);
123a627ac61SEd Schouten 		} else {
124a627ac61SEd Schouten 			/* Partial record. */
125*1ae6a21dSEd Schouten 			memset(fu, 0, sizeof(*fu));
12698c63a48SEd Schouten 			if (fread(fu, len, 1, uf) != 1)
12798c63a48SEd Schouten 				return (-1);
128a627ac61SEd Schouten 		}
129a627ac61SEd Schouten 	} else {
130*1ae6a21dSEd Schouten 		if (fread(fu, sizeof(*fu), 1, uf) != 1)
13198c63a48SEd Schouten 			return (-1);
132a627ac61SEd Schouten 	}
13398c63a48SEd Schouten 	return (0);
134a627ac61SEd Schouten }
135a627ac61SEd Schouten 
136a627ac61SEd Schouten struct utmpx *
137a627ac61SEd Schouten getutxent(void)
138a627ac61SEd Schouten {
13998c63a48SEd Schouten 	struct futx fu;
140a627ac61SEd Schouten 
14198c63a48SEd Schouten 	if (getfutxent(&fu) != 0)
142a627ac61SEd Schouten 		return (NULL);
14398c63a48SEd Schouten 	return (futx_to_utx(&fu));
144a627ac61SEd Schouten }
145a627ac61SEd Schouten 
146a627ac61SEd Schouten struct utmpx *
147a627ac61SEd Schouten getutxid(const struct utmpx *id)
148a627ac61SEd Schouten {
14998c63a48SEd Schouten 	struct futx fu;
150a627ac61SEd Schouten 
151a627ac61SEd Schouten 	for (;;) {
15298c63a48SEd Schouten 		if (getfutxent(&fu) != 0)
153a627ac61SEd Schouten 			return (NULL);
154a627ac61SEd Schouten 
15598c63a48SEd Schouten 		switch (fu.fu_type) {
156a627ac61SEd Schouten 		case USER_PROCESS:
157a627ac61SEd Schouten 		case INIT_PROCESS:
158a627ac61SEd Schouten 		case LOGIN_PROCESS:
159a627ac61SEd Schouten 		case DEAD_PROCESS:
160a627ac61SEd Schouten 			switch (id->ut_type) {
161a627ac61SEd Schouten 			case USER_PROCESS:
162a627ac61SEd Schouten 			case INIT_PROCESS:
163a627ac61SEd Schouten 			case LOGIN_PROCESS:
164a627ac61SEd Schouten 			case DEAD_PROCESS:
16598c63a48SEd Schouten 				if (memcmp(fu.fu_id, id->ut_id,
166*1ae6a21dSEd Schouten 				    MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) ==
167*1ae6a21dSEd Schouten 				    0)
168a627ac61SEd Schouten 					goto found;
169a627ac61SEd Schouten 			}
170e35a88d3SEd Schouten 			break;
17198c63a48SEd Schouten 		default:
17298c63a48SEd Schouten 			if (fu.fu_type == id->ut_type)
17398c63a48SEd Schouten 				goto found;
17498c63a48SEd Schouten 			break;
175a627ac61SEd Schouten 		}
176a627ac61SEd Schouten 	}
177a627ac61SEd Schouten 
178a627ac61SEd Schouten found:
17998c63a48SEd Schouten 	return (futx_to_utx(&fu));
180a627ac61SEd Schouten }
181a627ac61SEd Schouten 
182a627ac61SEd Schouten struct utmpx *
183a627ac61SEd Schouten getutxline(const struct utmpx *line)
184a627ac61SEd Schouten {
18598c63a48SEd Schouten 	struct futx fu;
186a627ac61SEd Schouten 
187a627ac61SEd Schouten 	for (;;) {
18898c63a48SEd Schouten 		if (getfutxent(&fu) != 0)
189a627ac61SEd Schouten 			return (NULL);
190a627ac61SEd Schouten 
19198c63a48SEd Schouten 		switch (fu.fu_type) {
192a627ac61SEd Schouten 		case USER_PROCESS:
193a627ac61SEd Schouten 		case LOGIN_PROCESS:
19498c63a48SEd Schouten 			if (strncmp(fu.fu_line, line->ut_line,
195*1ae6a21dSEd Schouten 			    MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) ==
196*1ae6a21dSEd Schouten 			    0)
197a627ac61SEd Schouten 				goto found;
19898c63a48SEd Schouten 			break;
199a627ac61SEd Schouten 		}
200a627ac61SEd Schouten 	}
201a627ac61SEd Schouten 
202a627ac61SEd Schouten found:
20398c63a48SEd Schouten 	return (futx_to_utx(&fu));
204a627ac61SEd Schouten }
205a627ac61SEd Schouten 
206a627ac61SEd Schouten struct utmpx *
207a627ac61SEd Schouten getutxuser(const char *user)
208a627ac61SEd Schouten {
20998c63a48SEd Schouten 	struct futx fu;
210a627ac61SEd Schouten 
211a627ac61SEd Schouten 	for (;;) {
21298c63a48SEd Schouten 		if (getfutxent(&fu) != 0)
213a627ac61SEd Schouten 			return (NULL);
214a627ac61SEd Schouten 
21598c63a48SEd Schouten 		switch (fu.fu_type) {
216a627ac61SEd Schouten 		case USER_PROCESS:
217*1ae6a21dSEd Schouten 			if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 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 }
226