xref: /freebsd/lib/libc/gen/getutxent.c (revision 63f537551380d2dab29fa402ad1269feae17e594)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 #include "namespace.h"
31 #include <sys/endian.h>
32 #include <sys/param.h>
33 #include <sys/stat.h>
34 #include <errno.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <utmpx.h>
38 #include "utxdb.h"
39 #include "un-namespace.h"
40 
41 static _Thread_local FILE *uf = NULL;
42 static _Thread_local int udb;
43 
44 int
45 setutxdb(int db, const char *file)
46 {
47 	struct stat sb;
48 
49 	switch (db) {
50 	case UTXDB_ACTIVE:
51 		if (file == NULL)
52 			file = _PATH_UTX_ACTIVE;
53 		break;
54 	case UTXDB_LASTLOGIN:
55 		if (file == NULL)
56 			file = _PATH_UTX_LASTLOGIN;
57 		break;
58 	case UTXDB_LOG:
59 		if (file == NULL)
60 			file = _PATH_UTX_LOG;
61 		break;
62 	default:
63 		errno = EINVAL;
64 		return (-1);
65 	}
66 
67 	if (uf != NULL)
68 		fclose(uf);
69 	uf = fopen(file, "re");
70 	if (uf == NULL)
71 		return (-1);
72 
73 	if (db != UTXDB_LOG) {
74 		/* Safety check: never use broken files. */
75 		if (_fstat(fileno(uf), &sb) != -1 &&
76 		    sb.st_size % sizeof(struct futx) != 0) {
77 			fclose(uf);
78 			uf = NULL;
79 			errno = EFTYPE;
80 			return (-1);
81 		}
82 		/* Prevent reading of partial records. */
83 		(void)setvbuf(uf, NULL, _IOFBF,
84 		    rounddown(BUFSIZ, sizeof(struct futx)));
85 	}
86 
87 	udb = db;
88 	return (0);
89 }
90 
91 void
92 setutxent(void)
93 {
94 
95 	setutxdb(UTXDB_ACTIVE, NULL);
96 }
97 
98 void
99 endutxent(void)
100 {
101 
102 	if (uf != NULL) {
103 		fclose(uf);
104 		uf = NULL;
105 	}
106 }
107 
108 static int
109 getfutxent(struct futx *fu)
110 {
111 
112 	if (uf == NULL)
113 		setutxent();
114 	if (uf == NULL)
115 		return (-1);
116 
117 	if (udb == UTXDB_LOG) {
118 		uint16_t len;
119 
120 retry:
121 		if (fread(&len, sizeof(len), 1, uf) != 1)
122 			return (-1);
123 		len = be16toh(len);
124 		if (len == 0) {
125 			/*
126 			 * XXX: Though zero-size records are valid in theory,
127 			 * they can never occur in practice. Zero-size records
128 			 * indicate file corruption. Seek one byte forward, to
129 			 * see if we can find a record there.
130 			 */
131 			ungetc('\0', uf);
132 			goto retry;
133 		}
134 		if (len > sizeof *fu) {
135 			/* Forward compatibility. */
136 			if (fread(fu, sizeof(*fu), 1, uf) != 1)
137 				return (-1);
138 			fseek(uf, len - sizeof(*fu), SEEK_CUR);
139 		} else {
140 			/* Partial record. */
141 			memset(fu, 0, sizeof(*fu));
142 			if (fread(fu, len, 1, uf) != 1)
143 				return (-1);
144 		}
145 	} else {
146 		if (fread(fu, sizeof(*fu), 1, uf) != 1)
147 			return (-1);
148 	}
149 	return (0);
150 }
151 
152 struct utmpx *
153 getutxent(void)
154 {
155 	struct futx fu;
156 
157 	if (getfutxent(&fu) != 0)
158 		return (NULL);
159 	return (futx_to_utx(&fu));
160 }
161 
162 struct utmpx *
163 getutxid(const struct utmpx *id)
164 {
165 	struct futx fu;
166 
167 	for (;;) {
168 		if (getfutxent(&fu) != 0)
169 			return (NULL);
170 
171 		switch (fu.fu_type) {
172 		case USER_PROCESS:
173 		case INIT_PROCESS:
174 		case LOGIN_PROCESS:
175 		case DEAD_PROCESS:
176 			switch (id->ut_type) {
177 			case USER_PROCESS:
178 			case INIT_PROCESS:
179 			case LOGIN_PROCESS:
180 			case DEAD_PROCESS:
181 				if (memcmp(fu.fu_id, id->ut_id,
182 				    MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) ==
183 				    0)
184 					goto found;
185 			}
186 			break;
187 		default:
188 			if (fu.fu_type == id->ut_type)
189 				goto found;
190 			break;
191 		}
192 	}
193 
194 found:
195 	return (futx_to_utx(&fu));
196 }
197 
198 struct utmpx *
199 getutxline(const struct utmpx *line)
200 {
201 	struct futx fu;
202 
203 	for (;;) {
204 		if (getfutxent(&fu) != 0)
205 			return (NULL);
206 
207 		switch (fu.fu_type) {
208 		case USER_PROCESS:
209 		case LOGIN_PROCESS:
210 			if (strncmp(fu.fu_line, line->ut_line,
211 			    MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) ==
212 			    0)
213 				goto found;
214 			break;
215 		}
216 	}
217 
218 found:
219 	return (futx_to_utx(&fu));
220 }
221 
222 struct utmpx *
223 getutxuser(const char *user)
224 {
225 	struct futx fu;
226 
227 	for (;;) {
228 		if (getfutxent(&fu) != 0)
229 			return (NULL);
230 
231 		switch (fu.fu_type) {
232 		case USER_PROCESS:
233 			if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0)
234 				goto found;
235 			break;
236 		}
237 	}
238 
239 found:
240 	return (futx_to_utx(&fu));
241 }
242