]> git.saurik.com Git - apple/libc.git/blob - gen/NetBSD/utmpx.c
Libc-391.tar.gz
[apple/libc.git] / gen / NetBSD / utmpx.c
1 /* $NetBSD: utmpx.c,v 1.21 2003/09/06 16:42:10 wiz 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.21 2003/09/06 16:42:10 wiz Exp $");
42 #endif /* LIBC_SCCS and not lint */
43
44 #include "namespace.h"
45 #include <sys/types.h>
46 #include <sys/param.h>
47 #include <sys/socket.h>
48 #include <sys/stat.h>
49 #include <sys/time.h>
50 #include <sys/wait.h>
51
52 #include <assert.h>
53 #include <db.h>
54 #include <errno.h>
55 #include <fcntl.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <unistd.h>
60 #include <utmp.h>
61 /* don't define earlier, has side effects in fcntl.h */
62 #define __LIBC12_SOURCE__
63 #include <utmpx.h>
64 #include <vis.h>
65
66 __warn_references(getlastlogx,
67 "warning: reference to compatibility getlastlogx(); include <utmpx.h> for correct reference")
68 __warn_references(lastlogxname,
69 "warning: reference to deprecated lastlogxname()")
70
71 static FILE *fp;
72 static int readonly = 0;
73 static struct utmpx ut;
74 static char utfile[MAXPATHLEN] = _PATH_UTMPX;
75 static char llfile[MAXPATHLEN] = _PATH_LASTLOGX;
76
77 static struct utmpx *utmp_update(const struct utmpx *);
78
79 static const char vers[] = "utmpx-1.00";
80
81 void
82 setutxent()
83 {
84
85 (void)memset(&ut, 0, sizeof(ut));
86 if (fp == NULL)
87 return;
88 (void)fseeko(fp, (off_t)sizeof(ut), SEEK_SET);
89 }
90
91
92 void
93 endutxent()
94 {
95
96 (void)memset(&ut, 0, sizeof(ut));
97 if (fp != NULL) {
98 (void)fclose(fp);
99 fp = NULL;
100 readonly = 0;
101 }
102 }
103
104
105 struct utmpx *
106 getutxent()
107 {
108
109 if (fp == NULL) {
110 struct stat st;
111
112 if ((fp = fopen(utfile, "r+")) == NULL)
113 if ((fp = fopen(utfile, "w+")) == NULL) {
114 if ((fp = fopen(utfile, "r")) == NULL)
115 goto fail;
116 else
117 readonly = 1;
118 }
119
120
121 /* get file size in order to check if new file */
122 if (fstat(fileno(fp), &st) == -1)
123 goto failclose;
124
125 if (st.st_size == 0) {
126 /* new file, add signature record */
127 (void)memset(&ut, 0, sizeof(ut));
128 ut.ut_type = SIGNATURE;
129 (void)memcpy(ut.ut_user, vers, sizeof(vers));
130 if (fwrite(&ut, sizeof(ut), 1, fp) != 1)
131 goto failclose;
132 } else {
133 /* old file, read signature record */
134 if (fread(&ut, sizeof(ut), 1, fp) != 1)
135 goto failclose;
136 if (memcmp(ut.ut_user, vers, sizeof(vers)) != 0 ||
137 ut.ut_type != SIGNATURE)
138 goto failclose;
139 }
140 }
141
142 if (fread(&ut, sizeof(ut), 1, fp) != 1)
143 goto fail;
144
145 return &ut;
146 failclose:
147 (void)fclose(fp);
148 fail:
149 (void)memset(&ut, 0, sizeof(ut));
150 return NULL;
151 }
152
153
154 struct utmpx *
155 getutxid(const struct utmpx *utx)
156 {
157
158 _DIAGASSERT(utx != NULL);
159
160 if (utx->ut_type == EMPTY)
161 return NULL;
162
163 do {
164 if (ut.ut_type == EMPTY)
165 continue;
166 switch (utx->ut_type) {
167 case EMPTY:
168 return NULL;
169 case RUN_LVL:
170 case BOOT_TIME:
171 case OLD_TIME:
172 case NEW_TIME:
173 if (ut.ut_type == utx->ut_type)
174 return &ut;
175 break;
176 case INIT_PROCESS:
177 case LOGIN_PROCESS:
178 case USER_PROCESS:
179 case DEAD_PROCESS:
180 switch (ut.ut_type) {
181 case INIT_PROCESS:
182 case LOGIN_PROCESS:
183 case USER_PROCESS:
184 case DEAD_PROCESS:
185 if (memcmp(ut.ut_id, utx->ut_id,
186 sizeof(ut.ut_id)) == 0)
187 return &ut;
188 break;
189 default:
190 break;
191 }
192 break;
193 default:
194 return NULL;
195 }
196 } while (getutxent() != NULL);
197 return NULL;
198 }
199
200
201 struct utmpx *
202 getutxline(const struct utmpx *utx)
203 {
204
205 _DIAGASSERT(utx != NULL);
206
207 do {
208 switch (ut.ut_type) {
209 case EMPTY:
210 break;
211 case LOGIN_PROCESS:
212 case USER_PROCESS:
213 if (strncmp(ut.ut_line, utx->ut_line,
214 sizeof(ut.ut_line)) == 0)
215 return &ut;
216 break;
217 default:
218 break;
219 }
220 } while (getutxent() != NULL);
221 return NULL;
222 }
223
224
225 struct utmpx *
226 pututxline(const struct utmpx *utx)
227 {
228 struct utmpx temp, *u = NULL;
229 int gotlock = 0;
230
231 _DIAGASSERT(utx != NULL);
232
233 if (utx == NULL)
234 return NULL;
235
236 if (strcmp(_PATH_UTMPX, utfile) == 0)
237 if ((fp != NULL && readonly) || (fp == NULL && geteuid() != 0))
238 return utmp_update(utx);
239
240
241 (void)memcpy(&temp, utx, sizeof(temp));
242
243 if (fp == NULL) {
244 (void)getutxent();
245 if (fp == NULL || readonly)
246 return NULL;
247 }
248
249 if (getutxid(&temp) == NULL) {
250 setutxent();
251 if (getutxid(&temp) == NULL) {
252 if (lockf(fileno(fp), F_LOCK, (off_t)0) == -1)
253 return NULL;
254 gotlock++;
255 if (fseeko(fp, (off_t)0, SEEK_END) == -1)
256 goto fail;
257 }
258 }
259
260 if (!gotlock) {
261 /* we are not appending */
262 if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1)
263 return NULL;
264 }
265
266 if (fwrite(&temp, sizeof (temp), 1, fp) != 1)
267 goto fail;
268
269 if (fflush(fp) == -1)
270 goto fail;
271
272 u = memcpy(&ut, &temp, sizeof(ut));
273 fail:
274 if (gotlock) {
275 if (lockf(fileno(fp), F_ULOCK, (off_t)0) == -1)
276 return NULL;
277 }
278 return u;
279 }
280
281
282 static struct utmpx *
283 utmp_update(const struct utmpx *utx)
284 {
285 char buf[sizeof(*utx) * 4 + 1];
286 pid_t pid;
287 int status;
288
289 _DIAGASSERT(utx != NULL);
290
291 (void)strvisx(buf, (const char *)(const void *)utx, sizeof(*utx),
292 VIS_WHITE);
293 switch (pid = fork()) {
294 case 0:
295 (void)execl(_PATH_UTMP_UPDATE,
296 strrchr(_PATH_UTMP_UPDATE, '/') + 1, buf, NULL);
297 exit(1);
298 /*NOTREACHED*/
299 case -1:
300 return NULL;
301 default:
302 if (waitpid(pid, &status, 0) == -1)
303 return NULL;
304 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
305 return memcpy(&ut, utx, sizeof(ut));
306 return NULL;
307 }
308
309 }
310
311 /*
312 * The following are extensions and not part of the X/Open spec.
313 */
314 int
315 updwtmpx(const char *file, const struct utmpx *utx)
316 {
317 int fd;
318 int saved_errno;
319
320 _DIAGASSERT(file != NULL);
321 _DIAGASSERT(utx != NULL);
322
323 fd = open(file, O_WRONLY|O_APPEND|O_SHLOCK);
324
325 if (fd == -1) {
326 if ((fd = open(file, O_CREAT|O_WRONLY|O_EXLOCK, 0644)) == -1)
327 return -1;
328 (void)memset(&ut, 0, sizeof(ut));
329 ut.ut_type = SIGNATURE;
330 (void)memcpy(ut.ut_user, vers, sizeof(vers));
331 if (write(fd, &ut, sizeof(ut)) == -1)
332 goto failed;
333 }
334 if (write(fd, utx, sizeof(*utx)) == -1)
335 goto failed;
336 if (close(fd) == -1)
337 return -1;
338 return 0;
339
340 failed:
341 saved_errno = errno;
342 (void) close(fd);
343 errno = saved_errno;
344 return -1;
345 }
346
347
348 int
349 utmpxname(const char *fname)
350 {
351 size_t len;
352
353 _DIAGASSERT(fname != NULL);
354
355 len = strlen(fname);
356
357 if (len >= sizeof(utfile))
358 return 0;
359
360 /* must end in x! */
361 if (fname[len - 1] != 'x')
362 return 0;
363
364 (void)strlcpy(utfile, fname, sizeof(utfile));
365 endutxent();
366 return 1;
367 }
368
369
370 void
371 getutmp(const struct utmpx *ux, struct utmp *u)
372 {
373
374 _DIAGASSERT(ux != NULL);
375 _DIAGASSERT(u != NULL);
376
377 (void)memcpy(u->ut_name, ux->ut_name, sizeof(u->ut_name));
378 (void)memcpy(u->ut_line, ux->ut_line, sizeof(u->ut_line));
379 (void)memcpy(u->ut_host, ux->ut_host, sizeof(u->ut_host));
380 u->ut_time = ux->ut_tv.tv_sec;
381 }
382
383 void
384 getutmpx(const struct utmp *u, struct utmpx *ux)
385 {
386
387 _DIAGASSERT(ux != NULL);
388 _DIAGASSERT(u != NULL);
389
390 (void)memcpy(ux->ut_name, u->ut_name, sizeof(u->ut_name));
391 (void)memcpy(ux->ut_line, u->ut_line, sizeof(u->ut_line));
392 (void)memcpy(ux->ut_host, u->ut_host, sizeof(u->ut_host));
393 ux->ut_tv.tv_sec = u->ut_time;
394 ux->ut_tv.tv_usec = 0;
395 (void)memset(&ux->ut_ss, 0, sizeof(ux->ut_ss));
396 ux->ut_pid = 0;
397 ux->ut_type = USER_PROCESS;
398 ux->ut_session = 0;
399 ux->ut_exit.e_termination = 0;
400 ux->ut_exit.e_exit = 0;
401 }
402
403 int
404 lastlogxname(const char *fname)
405 {
406 size_t len;
407
408 _DIAGASSERT(fname != NULL);
409
410 len = strlen(fname);
411
412 if (len >= sizeof(llfile))
413 return 0;
414
415 /* must end in x! */
416 if (fname[len - 1] != 'x')
417 return 0;
418
419 (void)strlcpy(llfile, fname, sizeof(llfile));
420 return 1;
421 }
422
423 struct lastlogx *
424 getlastlogx(uid_t uid, struct lastlogx *ll)
425 {
426
427 return __getlastlogx13(_PATH_LASTLOGX, uid, ll);
428 }
429
430 struct lastlogx *
431 __getlastlogx13(const char *fname, uid_t uid, struct lastlogx *ll)
432 {
433 DBT key, data;
434 DB *db;
435
436 _DIAGASSERT(fname != NULL);
437 _DIAGASSERT(ll != NULL);
438
439 db = dbopen(fname, O_RDONLY|O_SHLOCK, 0, DB_HASH, NULL);
440
441 if (db == NULL)
442 return NULL;
443
444 key.data = &uid;
445 key.size = sizeof(uid);
446
447 if ((db->get)(db, &key, &data, 0) != 0)
448 goto error;
449
450 if (data.size != sizeof(*ll)) {
451 errno = EFTYPE;
452 goto error;
453 }
454
455 if (ll == NULL)
456 if ((ll = malloc(sizeof(*ll))) == NULL)
457 goto done;
458
459 (void)memcpy(ll, data.data, sizeof(*ll));
460 goto done;
461 error:
462 ll = NULL;
463 done:
464 (db->close)(db);
465 return ll;
466 }
467
468 int
469 updlastlogx(const char *fname, uid_t uid, struct lastlogx *ll)
470 {
471 DBT key, data;
472 int error = 0;
473 DB *db;
474
475 _DIAGASSERT(fname != NULL);
476 _DIAGASSERT(ll != NULL);
477
478 db = dbopen(fname, O_RDWR|O_CREAT|O_EXLOCK, 0, DB_HASH, NULL);
479
480 if (db == NULL)
481 return -1;
482
483 key.data = &uid;
484 key.size = sizeof(uid);
485 data.data = ll;
486 data.size = sizeof(*ll);
487 if ((db->put)(db, &key, &data, 0) != 0)
488 error = -1;
489
490 (db->close)(db);
491 return error;
492 }