]> git.saurik.com Git - apple/libc.git/blob - gen/utmpx-nbsd.c
Libc-763.13.tar.gz
[apple/libc.git] / gen / utmpx-nbsd.c
1 /* $NetBSD: utmpx.c,v 1.25 2008/04/28 20:22:59 martin 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 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include <sys/cdefs.h>
32
33 #if defined(LIBC_SCCS) && !defined(lint)
34 __RCSID("$NetBSD: utmpx.c,v 1.25 2008/04/28 20:22:59 martin Exp $");
35 #endif /* LIBC_SCCS and not lint */
36
37 #include "namespace.h"
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <sys/time.h>
43 #include <sys/wait.h>
44
45 #include <fcntl.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 #ifdef UNIFDEF_LEGACY_UTMP_APIS
51 #include <utmp.h>
52 #endif /* UNIFDEF_LEGACY_UTMP_APIS */
53 #include <utmpx.h>
54 #include <utmpx-darwin.h>
55 #include <errno.h>
56 #include <vis.h>
57 #include <notify.h>
58
59 /* This is the default struct _utmpx shared by the POSIX APIs */
60 __private_extern__
61 struct _utmpx __utx__ = {
62 __UTX_MAGIC__, /* magic */
63 {}, /* ut */
64 PTHREAD_MUTEX_INITIALIZER, /* utmpx_mutex */
65 _PATH_UTMPX, /* utfile */
66 NULL, /* fp */
67 1, /* utfile_system */
68 0, /* readonly */
69 };
70
71 static struct utmpx *__getutxid(struct _utmpx *, const struct utmpx *);
72
73 __private_extern__ const char _utmpx_vers[] = "utmpx-1.00";
74
75 __private_extern__ void
76 __setutxent(struct _utmpx *U)
77 {
78
79 (void)memset(&U->ut, 0, sizeof(U->ut));
80 if (U->fp == NULL)
81 return;
82 #ifdef __LP64__
83 (void)fseeko(U->fp, (off_t)sizeof(struct utmpx32), SEEK_SET);
84 #else /* __LP64__ */
85 (void)fseeko(U->fp, (off_t)sizeof(U->ut), SEEK_SET);
86 #endif /* __LP64__ */
87 }
88
89 void
90 _setutxent(struct _utmpx *U)
91 {
92
93 TEST_UTMPX_T("_setutxent", U);
94 UTMPX_LOCK(U);
95 __setutxent(U);
96 UTMPX_UNLOCK(U);
97 }
98
99
100 void
101 setutxent()
102 {
103 _setutxent(&__utx__);
104 }
105
106
107 __private_extern__ void
108 __endutxent(struct _utmpx *U)
109 {
110 (void)memset(&U->ut, 0, sizeof(U->ut));
111 if (U->fp != NULL) {
112 int saveerrno = errno;
113 (void)fclose(U->fp);
114 errno = saveerrno;
115 U->fp = NULL;
116 U->readonly = 0;
117 }
118 }
119
120
121 void
122 _endutxent(struct _utmpx *U)
123 {
124 TEST_UTMPX_T("_endutxent", U);
125 UTMPX_LOCK(U);
126 __endutxent(U);
127 UTMPX_UNLOCK(U);
128 }
129
130
131 void
132 endutxent()
133 {
134 _endutxent(&__utx__);
135 }
136
137
138 __private_extern__ struct utmpx *
139 __getutxent(struct _utmpx *U)
140 {
141 int saveerrno;
142 #ifdef __LP64__
143 struct utmpx32 ut32;
144 #endif /* __LP64__ */
145
146 if (U->fp == NULL) {
147 struct stat st;
148
149 if ((U->fp = fopen(U->utfile, "r+")) == NULL)
150 if ((U->fp = fopen(U->utfile, "w+")) == NULL) {
151 if ((U->fp = fopen(U->utfile, "r")) == NULL)
152 goto fail;
153 else
154 U->readonly = 1;
155 }
156
157 fcntl(fileno(U->fp), F_SETFD, 1); /* set close-on-exec flag */
158
159 /* get file size in order to check if new file */
160 if (fstat(fileno(U->fp), &st) == -1)
161 goto failclose;
162
163 if (st.st_size == 0) {
164 /* new file, add signature record */
165 #ifdef __LP64__
166 (void)memset(&ut32, 0, sizeof(ut32));
167 ut32.ut_type = SIGNATURE;
168 (void)memcpy(ut32.ut_user, _utmpx_vers, sizeof(_utmpx_vers));
169 if (fwrite(&ut32, sizeof(ut32), 1, U->fp) != 1)
170 #else /* __LP64__ */
171 (void)memset(&U->ut, 0, sizeof(U->ut));
172 U->ut.ut_type = SIGNATURE;
173 (void)memcpy(U->ut.ut_user, _utmpx_vers, sizeof(_utmpx_vers));
174 if (fwrite(&U->ut, sizeof(U->ut), 1, U->fp) != 1)
175 #endif /* __LP64__ */
176 goto failclose;
177 } else {
178 /* old file, read signature record */
179 #ifdef __LP64__
180 if (fread(&ut32, sizeof(ut32), 1, U->fp) != 1)
181 #else /* __LP64__ */
182 if (fread(&U->ut, sizeof(U->ut), 1, U->fp) != 1)
183 #endif /* __LP64__ */
184 goto failclose;
185 #ifdef __LP64__
186 if (memcmp(ut32.ut_user, _utmpx_vers, sizeof(_utmpx_vers)) != 0 ||
187 ut32.ut_type != SIGNATURE)
188 #else /* __LP64__ */
189 if (memcmp(U->ut.ut_user, _utmpx_vers, sizeof(_utmpx_vers)) != 0 ||
190 U->ut.ut_type != SIGNATURE)
191 #endif /* __LP64__ */
192 {
193 errno = EINVAL;
194 goto failclose;
195 }
196 }
197 }
198
199 #ifdef __LP64__
200 if (fread(&ut32, sizeof(ut32), 1, U->fp) != 1)
201 #else /* __LP64__ */
202 if (fread(&U->ut, sizeof(U->ut), 1, U->fp) != 1)
203 #endif /* __LP64__ */
204 goto fail;
205
206 #ifdef __LP64__
207 _utmpx32_64(&ut32, &U->ut);
208 #endif /* __LP64__ */
209 return &U->ut;
210 failclose:
211 saveerrno = errno;
212 (void)fclose(U->fp);
213 errno = saveerrno;
214 U->fp = NULL;
215 fail:
216 (void)memset(&U->ut, 0, sizeof(U->ut));
217 return NULL;
218 }
219
220
221 struct utmpx *
222 _getutxent(struct _utmpx *U)
223 {
224 struct utmpx *ret;
225
226 TEST_UTMPX_T("_getutxent", U);
227 UTMPX_LOCK(U);
228 ret = __getutxent(U);
229 UTMPX_UNLOCK(U);
230 return ret;
231 }
232
233
234 struct utmpx *
235 getutxent()
236 {
237 return _getutxent(&__utx__);
238 }
239
240
241 struct utmpx *
242 _getutxid(struct _utmpx *U, const struct utmpx *utx)
243 {
244 struct utmpx temp;
245 const struct utmpx *ux;
246 struct utmpx *ret;
247
248 if (utx->ut_type == EMPTY)
249 return NULL;
250
251 TEST_UTMPX_T("_getutxid", U);
252 UTMPX_LOCK(U);
253 /* make a copy as needed, and auto-fill if requested */
254 ux = _utmpx_working_copy(utx, &temp, 1);
255 if (!ux) {
256 UTMPX_UNLOCK(U);
257 return NULL;
258 }
259
260 ret = __getutxid(U, ux);
261 UTMPX_UNLOCK(U);
262 return ret;
263 }
264
265
266 struct utmpx *
267 getutxid(const struct utmpx *utx)
268 {
269 return _getutxid(&__utx__, utx);
270 }
271
272
273 static struct utmpx *
274 __getutxid(struct _utmpx *U, const struct utmpx *utx)
275 {
276
277 do {
278 if (U->ut.ut_type == EMPTY)
279 continue;
280 switch (utx->ut_type) {
281 case EMPTY:
282 return NULL;
283 case RUN_LVL:
284 case BOOT_TIME:
285 case OLD_TIME:
286 case NEW_TIME:
287 if (U->ut.ut_type == utx->ut_type)
288 return &U->ut;
289 break;
290 case INIT_PROCESS:
291 case LOGIN_PROCESS:
292 case USER_PROCESS:
293 case DEAD_PROCESS:
294 switch (U->ut.ut_type) {
295 case INIT_PROCESS:
296 case LOGIN_PROCESS:
297 case USER_PROCESS:
298 case DEAD_PROCESS:
299 if (memcmp(U->ut.ut_id, utx->ut_id,
300 sizeof(U->ut.ut_id)) == 0)
301 return &U->ut;
302 break;
303 default:
304 break;
305 }
306 break;
307 default:
308 return NULL;
309 }
310 } while (__getutxent(U) != NULL);
311 return NULL;
312 }
313
314
315 static struct utmpx *
316 __getutxline(struct _utmpx *U, const struct utmpx *utx)
317 {
318 do {
319 switch (U->ut.ut_type) {
320 case EMPTY:
321 break;
322 case LOGIN_PROCESS:
323 case USER_PROCESS:
324 if (strncmp(U->ut.ut_line, utx->ut_line,
325 sizeof(U->ut.ut_line)) == 0)
326 return &U->ut;
327 break;
328 default:
329 break;
330 }
331 } while (__getutxent(U) != NULL);
332 return NULL;
333 }
334
335
336 struct utmpx *
337 _getutxline(struct _utmpx *U, const struct utmpx *utx)
338 {
339 struct utmpx *ret;
340
341 TEST_UTMPX_T("_getutxline", U);
342 UTMPX_LOCK(U);
343 ret = __getutxline(U, utx);
344 UTMPX_UNLOCK(U);
345 return ret;
346 }
347
348
349 struct utmpx *
350 getutxline(const struct utmpx *utx)
351 {
352 return _getutxline(&__utx__, utx);
353 }
354
355
356 struct utmpx *
357 _pututxline(struct _utmpx *U, const struct utmpx *utx)
358 {
359 struct utmpx *ux;
360
361 if (utx == NULL) {
362 errno = EINVAL;
363 return NULL;
364 }
365
366 TEST_UTMPX_T("_pututxline", U);
367 UTMPX_LOCK(U);
368 if ((ux = __pututxline(&__utx__, utx)) != NULL && __utx__.utfile_system) {
369 _utmpx_asl(ux); /* the equivalent of wtmpx and lastlogx */
370 #ifdef UTMP_COMPAT
371 _write_utmp_compat(ux);
372 #endif /* UTMP_COMPAT */
373 }
374 UTMPX_UNLOCK(U);
375 return ux;
376 }
377
378
379 struct utmpx *
380 pututxline(const struct utmpx *utx)
381 {
382 return _pututxline(&__utx__, utx);
383 }
384
385 __private_extern__ struct utmpx *
386 __pututxline(struct _utmpx *U, const struct utmpx *utx)
387 {
388 struct utmpx temp, *u = NULL, *x;
389 const struct utmpx *ux;
390 #ifdef __LP64__
391 struct utmpx32 ut32;
392 #endif /* __LP64__ */
393 struct flock fl;
394 #define gotlock (fl.l_start >= 0)
395
396 fl.l_start = -1; /* also means we haven't locked */
397 if (U->utfile_system)
398 if ((U->fp != NULL && U->readonly) || (U->fp == NULL && geteuid() != 0)) {
399 errno = EPERM;
400 return NULL;
401 }
402
403 if (U->fp == NULL) {
404 (void)__getutxent(U);
405 if (U->fp == NULL || U->readonly) {
406 errno = EPERM;
407 return NULL;
408 }
409 }
410
411 /* make a copy as needed, and auto-fill if requested */
412 ux = _utmpx_working_copy(utx, &temp, 0);
413 if (!ux)
414 return NULL;
415
416 if ((x = __getutxid(U, ux)) == NULL) {
417 __setutxent(U);
418 if ((x = __getutxid(U, ux)) == NULL) {
419 /*
420 * utx->ut_type has any original mask bits, while
421 * ux->ut_type has those mask bits removed. If we
422 * are trying to record a dead process, and
423 * UTMPX_DEAD_IF_CORRESPONDING_MASK is set, then since
424 * there is no matching entry, we return NULL.
425 */
426 if (ux->ut_type == DEAD_PROCESS &&
427 (utx->ut_type & UTMPX_DEAD_IF_CORRESPONDING_MASK)) {
428 errno = EINVAL;
429 return NULL;
430 }
431 /*
432 * Replace lockf() with fcntl() and a fixed start
433 * value. We should already be at EOF.
434 */
435 if ((fl.l_start = lseek(fileno(U->fp), 0, SEEK_CUR)) < 0)
436 return NULL;
437 fl.l_len = 0;
438 fl.l_whence = SEEK_SET;
439 fl.l_type = F_WRLCK;
440 if (fcntl(fileno(U->fp), F_SETLKW, &fl) == -1)
441 return NULL;
442 if (fseeko(U->fp, (off_t)0, SEEK_END) == -1)
443 goto fail;
444 }
445 }
446
447 if (!gotlock) {
448 /*
449 * utx->ut_type has any original mask bits, while
450 * ux->ut_type has those mask bits removed. If we
451 * are trying to record a dead process, if
452 * UTMPX_DEAD_IF_CORRESPONDING_MASK is set, but the found
453 * entry is not a (matching) USER_PROCESS, then return NULL.
454 */
455 if (ux->ut_type == DEAD_PROCESS &&
456 (utx->ut_type & UTMPX_DEAD_IF_CORRESPONDING_MASK) &&
457 x->ut_type != USER_PROCESS) {
458 errno = EINVAL;
459 return NULL;
460 }
461 /* we are not appending */
462 #ifdef __LP64__
463 if (fseeko(U->fp, -(off_t)sizeof(ut32), SEEK_CUR) == -1)
464 #else /* __LP64__ */
465 if (fseeko(U->fp, -(off_t)sizeof(U->ut), SEEK_CUR) == -1)
466 #endif /* __LP64__ */
467 return NULL;
468 }
469
470 #ifdef __LP64__
471 _utmpx64_32(ux, &ut32);
472 if (fwrite(&ut32, sizeof (ut32), 1, U->fp) != 1)
473 #else /* __LP64__ */
474 if (fwrite(ux, sizeof (*ux), 1, U->fp) != 1)
475 #endif /* __LP64__ */
476 goto fail;
477
478 if (fflush(U->fp) == -1)
479 goto fail;
480
481 u = memcpy(&U->ut, ux, sizeof(U->ut));
482 notify_post(UTMPX_CHANGE_NOTIFICATION);
483 fail:
484 if (gotlock) {
485 int save = errno;
486 fl.l_type = F_UNLCK;
487 if (fcntl(fileno(U->fp), F_SETLK, &fl) == -1)
488 return NULL;
489 errno = save;
490 }
491 return u;
492 }
493
494
495 /*
496 * The following are extensions and not part of the X/Open spec.
497 */
498 __private_extern__ int
499 __utmpxname(struct _utmpx *U, const char *fname)
500 {
501 size_t len;
502
503 if (fname == NULL) {
504 if(!U->utfile_system)
505 free(U->utfile);
506 U->utfile = _PATH_UTMPX;
507 U->utfile_system = 1;
508 __endutxent(U);
509 return 1;
510 }
511
512 len = strlen(fname);
513
514 if (len >= MAXPATHLEN)
515 return 0;
516
517 /* must end in x! */
518 if (fname[len - 1] != 'x')
519 return 0;
520
521 if (U->utfile_system)
522 U->utfile = NULL;
523 U->utfile_system = 0;
524 if ((U->utfile = reallocf(U->utfile, len + 1)) == NULL)
525 return 0;
526
527 (void)strcpy(U->utfile, fname);
528 __endutxent(U);
529 return 1;
530 }
531
532 int
533 _utmpxname(struct _utmpx *U, const char *fname)
534 {
535 int ret;
536
537 TEST_UTMPX_T("_utmpxname", U);
538 UTMPX_LOCK(U);
539 ret = __utmpxname(U, fname);
540 UTMPX_UNLOCK(U);
541 return ret;
542 }
543
544 int
545 utmpxname(const char *fname)
546 {
547 return _utmpxname(&__utx__, fname);
548 }
549
550 #ifdef UNIFDEF_LEGACY_UTMP_APIS
551 void
552 getutmp(const struct utmpx *ux, struct utmp *u)
553 {
554
555 bzero(u, sizeof(*u));
556 (void)memcpy(u->ut_name, ux->ut_user, sizeof(u->ut_name));
557 (void)memcpy(u->ut_line, ux->ut_line, sizeof(u->ut_line));
558 (void)memcpy(u->ut_host, ux->ut_host, sizeof(u->ut_host));
559 u->ut_time = ux->ut_tv.tv_sec;
560 }
561
562 void
563 getutmpx(const struct utmp *u, struct utmpx *ux)
564 {
565
566 bzero(ux, sizeof(*ux));
567 (void)memcpy(ux->ut_user, u->ut_name, sizeof(u->ut_name));
568 ux->ut_user[sizeof(u->ut_name)] = 0;
569 (void)memcpy(ux->ut_line, u->ut_line, sizeof(u->ut_line));
570 ux->ut_line[sizeof(u->ut_line)] = 0;
571 (void)memcpy(ux->ut_host, u->ut_host, sizeof(u->ut_host));
572 ux->ut_host[sizeof(u->ut_host)] = 0;
573 ux->ut_tv.tv_sec = u->ut_time;
574 ux->ut_tv.tv_usec = 0;
575 ux->ut_pid = getpid();
576 ux->ut_type = USER_PROCESS;
577 }
578 #endif /* UNIFDEF_LEGACY_UTMP_APIS */