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