utmpx.c revision 1.4 1 /* $NetBSD: utmpx.c,v 1.4 2002/03/11 03:29:49 simonb Exp $ */
2
3 /*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38 #include <sys/cdefs.h>
39
40 #if defined(LIBC_SCCS) && !defined(lint)
41 __RCSID("$NetBSD: utmpx.c,v 1.4 2002/03/11 03:29:49 simonb Exp $");
42 #endif /* LIBC_SCCS and not lint */
43
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/wait.h>
47 #include <sys/socket.h>
48 #include <sys/time.h>
49 #include <sys/stat.h>
50
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <vis.h>
55 #include <utmpx.h>
56 #include <unistd.h>
57 #include <fcntl.h>
58
59 static FILE *fp;
60 static struct utmpx ut;
61 static char utfile[MAXPATHLEN] = _PATH_UTMPX;
62
63 static struct utmpx *utmp_update(const struct utmpx *);
64
65 static const char vers[] = "utmpx-1.00";
66
67 void
68 setutxent()
69 {
70 (void)memset(&ut, 0, sizeof(ut));
71 if (fp == NULL)
72 return;
73 (void)fseeko(fp, (off_t)sizeof(ut), SEEK_SET);
74 }
75
76
77 void
78 endutxent()
79 {
80 (void)memset(&ut, 0, sizeof(ut));
81 if (fp != NULL)
82 (void)fclose(fp);
83 }
84
85
86 struct utmpx *
87 getutxent()
88 {
89 if (fp == NULL) {
90 struct stat st;
91
92 if ((fp = fopen(utfile, "r+")) == NULL)
93 if ((fp = fopen(utfile, "r")) == NULL)
94 goto fail;
95
96 /* get file size in order to check if new file */
97 if (fstat(fileno(fp), &st) == -1)
98 goto failclose;
99
100 if (st.st_size == 0) {
101 /* new file, add signature record */
102 (void)memset(&ut, 0, sizeof(ut));
103 ut.ut_type = SIGNATURE;
104 (void)memcpy(ut.ut_user, vers, sizeof(vers));
105 if (fwrite(&ut, sizeof(ut), 1, fp) != sizeof(ut))
106 goto failclose;
107 } else {
108 /* old file, read signature record */
109 if (fread(&ut, sizeof(ut), 1, fp) != sizeof(ut))
110 goto failclose;
111 if (memcmp(ut.ut_user, vers, sizeof(vers)) != 0 ||
112 ut.ut_type != SIGNATURE)
113 goto failclose;
114 }
115 }
116
117 if (fread(&ut, sizeof(ut), 1, fp) != sizeof(ut))
118 goto fail;
119
120 return &ut;
121 failclose:
122 (void)fclose(fp);
123 fail:
124 (void)memset(&ut, 0, sizeof(ut));
125 return NULL;
126 }
127
128
129 struct utmpx *
130 getutxid(const struct utmpx *utx)
131 {
132 if (utx->ut_type == EMPTY)
133 return NULL;
134
135 do {
136 if (ut.ut_type == EMPTY)
137 continue;
138 switch (utx->ut_type) {
139 case EMPTY:
140 return NULL;
141 case RUN_LVL:
142 case BOOT_TIME:
143 case OLD_TIME:
144 case NEW_TIME:
145 if (ut.ut_type == utx->ut_type)
146 return &ut;
147 break;
148 case INIT_PROCESS:
149 case LOGIN_PROCESS:
150 case USER_PROCESS:
151 case DEAD_PROCESS:
152 switch (ut.ut_type) {
153 case INIT_PROCESS:
154 case LOGIN_PROCESS:
155 case USER_PROCESS:
156 case DEAD_PROCESS:
157 if (memcmp(ut.ut_id, utx->ut_id,
158 sizeof(ut.ut_id)) == 0)
159 return &ut;
160 break;
161 default:
162 break;
163 }
164 break;
165 default:
166 return NULL;
167 }
168 }
169 while (getutxent() != NULL);
170 return NULL;
171 }
172
173
174 struct utmpx *
175 getutxline(const struct utmpx *utx)
176 {
177 do {
178 switch (ut.ut_type) {
179 case EMPTY:
180 break;
181 case LOGIN_PROCESS:
182 case USER_PROCESS:
183 if (strncmp(ut.ut_line, utx->ut_line,
184 sizeof(ut.ut_line)) == 0)
185 return &ut;
186 break;
187 default:
188 break;
189 }
190 }
191 while (getutxent() != NULL);
192 return NULL;
193 }
194
195
196 struct utmpx *
197 pututxline(const struct utmpx *utx)
198 {
199 struct utmpx temp, *u = NULL;
200 int gotlock = 0;
201
202 if (strcmp(_PATH_UTMPX, utfile) == 0 && geteuid() != 0)
203 return utmp_update(utx);
204
205 if (utx == NULL)
206 return NULL;
207
208 (void)memcpy(&temp, utx, sizeof(temp));
209
210 if (fp == NULL) {
211 (void)getutxent();
212 if (fp == NULL)
213 return NULL;
214 }
215
216 if (getutxid(&temp) == NULL) {
217 setutxent();
218 if (getutxid(&temp) == NULL) {
219 if (lockf(fileno(fp), F_LOCK, (off_t)0) == -1)
220 return NULL;
221 gotlock++;
222 if (fseeko(fp, (off_t)0, SEEK_END) == -1)
223 goto fail;
224 }
225 }
226
227 if (!gotlock) {
228 /* we are not appending */
229 if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1)
230 return NULL;
231 }
232
233 if (fwrite(&temp, sizeof (temp), 1, fp) != 1)
234 goto fail;
235
236 if (fflush(fp) == -1)
237 goto fail;
238
239 u = memcpy(&ut, &temp, sizeof(ut));
240 fail:
241 if (gotlock) {
242 if (lockf(fileno(fp), F_ULOCK, (off_t)0) == -1)
243 return NULL;
244 }
245 return u;
246 }
247
248
249 static struct utmpx *
250 utmp_update(const struct utmpx *utx)
251 {
252 char buf[sizeof(*utx) * 4 + 1];
253 pid_t pid;
254 int status;
255
256 (void)strvisx(buf, (const char *)(const void *)utx, sizeof(*utx),
257 VIS_WHITE);
258 switch (pid = fork()) {
259 case 0:
260 (void)execl(_PATH_UTMP_UPDATE,
261 strrchr(_PATH_UTMP_UPDATE, '/') + 1, buf);
262 exit(1);
263 /*NOTREACHED*/
264 case -1:
265 return NULL;
266 default:
267 if (waitpid(pid, &status, 0) == -1)
268 return NULL;
269 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
270 return memcpy(&ut, utx, sizeof(ut));
271 return NULL;
272 }
273
274 }
275
276 void
277 updwtmpx(const char *file, const struct utmpx *utx)
278 {
279 int fd = open(file, O_WRONLY | O_APPEND);
280 if (fd == -1) {
281 if ((fd = open(file, O_CREAT | O_WRONLY, 0644)) == -1)
282 return;
283 (void)memset(&ut, 0, sizeof(ut));
284 ut.ut_type = SIGNATURE;
285 (void)memcpy(ut.ut_user, vers, sizeof(vers));
286 (void)write(fd, &ut, sizeof(ut));
287 }
288 (void)write(fd, utx, sizeof(*utx));
289 (void)close(fd);
290 }
291
292
293 /*
294 * The following are extensions and not part of the X/Open spec
295 */
296 int
297 utmpxname(const char *fname)
298 {
299 size_t len = strlen(fname);
300
301 if (len >= sizeof(utfile))
302 return 0;
303
304 /* must end in x! */
305 if (fname[len - 1] != 'x')
306 return 0;
307
308 (void)strcpy(utfile, fname);
309 endutxent();
310 return 1;
311 }
312