xref: /freebsd/lib/libc/gen/getutxent.c (revision 94e3ee44c3581ff37c5e01b5ffe5eb16d30079a7)
1 /*-
2  * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
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 FILE *uf = NULL;
42 static 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, "r");
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 		if (fread(&len, sizeof(len), 1, uf) != 1)
121 			return (-1);
122 		len = be16toh(len);
123 		if (len > sizeof *fu) {
124 			/* Forward compatibility. */
125 			if (fread(fu, sizeof(*fu), 1, uf) != 1)
126 				return (-1);
127 			fseek(uf, len - sizeof(*fu), SEEK_CUR);
128 		} else {
129 			/* Partial record. */
130 			memset(fu, 0, sizeof(*fu));
131 			if (fread(fu, len, 1, uf) != 1)
132 				return (-1);
133 		}
134 	} else {
135 		if (fread(fu, sizeof(*fu), 1, uf) != 1)
136 			return (-1);
137 	}
138 	return (0);
139 }
140 
141 struct utmpx *
142 getutxent(void)
143 {
144 	struct futx fu;
145 
146 	if (getfutxent(&fu) != 0)
147 		return (NULL);
148 	return (futx_to_utx(&fu));
149 }
150 
151 struct utmpx *
152 getutxid(const struct utmpx *id)
153 {
154 	struct futx fu;
155 
156 	for (;;) {
157 		if (getfutxent(&fu) != 0)
158 			return (NULL);
159 
160 		switch (fu.fu_type) {
161 		case USER_PROCESS:
162 		case INIT_PROCESS:
163 		case LOGIN_PROCESS:
164 		case DEAD_PROCESS:
165 			switch (id->ut_type) {
166 			case USER_PROCESS:
167 			case INIT_PROCESS:
168 			case LOGIN_PROCESS:
169 			case DEAD_PROCESS:
170 				if (memcmp(fu.fu_id, id->ut_id,
171 				    MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) ==
172 				    0)
173 					goto found;
174 			}
175 			break;
176 		default:
177 			if (fu.fu_type == id->ut_type)
178 				goto found;
179 			break;
180 		}
181 	}
182 
183 found:
184 	return (futx_to_utx(&fu));
185 }
186 
187 struct utmpx *
188 getutxline(const struct utmpx *line)
189 {
190 	struct futx fu;
191 
192 	for (;;) {
193 		if (getfutxent(&fu) != 0)
194 			return (NULL);
195 
196 		switch (fu.fu_type) {
197 		case USER_PROCESS:
198 		case LOGIN_PROCESS:
199 			if (strncmp(fu.fu_line, line->ut_line,
200 			    MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) ==
201 			    0)
202 				goto found;
203 			break;
204 		}
205 	}
206 
207 found:
208 	return (futx_to_utx(&fu));
209 }
210 
211 struct utmpx *
212 getutxuser(const char *user)
213 {
214 	struct futx fu;
215 
216 	for (;;) {
217 		if (getfutxent(&fu) != 0)
218 			return (NULL);
219 
220 		switch (fu.fu_type) {
221 		case USER_PROCESS:
222 			if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0)
223 				goto found;
224 			break;
225 		}
226 	}
227 
228 found:
229 	return (futx_to_utx(&fu));
230 }
231