1 /* $NetBSD: homedir.c,v 1.3 2015/01/17 17:46:31 christos Exp $ */
2
3 /*
4 * Copyright (c) 1997-2014 Erez Zadok
5 * Copyright (c) 1989 Jan-Simon Pendry
6 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1989 The Regents of the University of California.
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 *
38 * File: am-utils/hlfsd/homedir.c
39 *
40 * HLFSD was written at Columbia University Computer Science Department, by
41 * Erez Zadok <ezk@cs.columbia.edu> and Alexander Dupuy <dupuy@cs.columbia.edu>
42 * It is being distributed under the same terms and conditions as amd does.
43 */
44
45 #ifdef HAVE_CONFIG_H
46 # include <config.h>
47 #endif /* HAVE_CONFIG_H */
48 #include <am_defs.h>
49 #include <hlfsd.h>
50
51
52 /*
53 * STATIC VARIABLES AND FUNCTIONS:
54 */
55 static FILE *passwd_fp = NULL;
56 static char pw_name[16], pw_dir[128];
57 static int cur_pwtab_num = 0, max_pwtab_num = 0;
58 static int hlfsd_diskspace(char *);
59 static int hlfsd_stat(char *, struct stat *);
60 static int passwd_line = 0;
61 static int plt_reset(void);
62 static struct passwd passwd_ent;
63 static uid2home_t *lastchild;
64 static uid2home_t *pwtab;
65 static void delay(uid2home_t *, int);
66 static void table_add(u_int, const char *, const char *);
67 static char mboxfile[MAXPATHLEN];
68 static char *root_home; /* root's home directory */
69
70 /* GLOBAL FUNCTIONS */
71 char *homeof(char *username);
72 int uidof(char *username);
73
74 /* GLOBALS VARIABLES */
75 username2uid_t *untab; /* user name table */
76
77 /*
78 * Return the home directory pathname for the user with uid "userid".
79 */
80 char *
homedir(int userid,int groupid)81 homedir(int userid, int groupid)
82 {
83 static char linkval[MAXPATHLEN + 1];
84 static struct timeval tp;
85 uid2home_t *found;
86 char *homename;
87 struct stat homestat;
88 int old_groupid, old_userid;
89
90 if ((found = plt_search(userid)) == (uid2home_t *) NULL) {
91 return alt_spooldir; /* use alt spool for unknown uid */
92 }
93 homename = found->home;
94
95 if (homename[0] != '/' || homename[1] == '\0') {
96 found->last_status = 1;
97 return alt_spooldir; /* use alt spool for / or rel. home */
98 }
99 if ((int) userid == 0) /* force all uid 0 to use root's home */
100 xsnprintf(linkval, sizeof(linkval), "%s/%s", root_home, home_subdir);
101 else
102 xsnprintf(linkval, sizeof(linkval), "%s/%s", homename, home_subdir);
103
104 if (noverify) {
105 found->last_status = 0;
106 return linkval;
107 }
108
109 /*
110 * To optimize hlfsd, we don't actually check the validity of the
111 * symlink if it has been checked in the last N seconds. It is
112 * very likely that the link, machine, and filesystem are still
113 * valid, as long as N is small. But if N is large, that may not be
114 * true. That's why the default N is 5 minutes, but we allow the
115 * user to override this value via a command line option. Note that
116 * we do not update the last_access_time each time it is accessed,
117 * but only once every N seconds.
118 */
119 if (gettimeofday(&tp, (struct timezone *) NULL) < 0) {
120 tp.tv_sec = 0;
121 } else {
122 if ((tp.tv_sec - found->last_access_time) < cache_interval) {
123 if (found->last_status == 0) {
124 return linkval;
125 } else {
126 return alt_spooldir;
127 }
128 } else {
129 found->last_access_time = tp.tv_sec;
130 }
131 }
132
133 /*
134 * Only run this forking code if ask for -D fork (default).
135 * Disable forking using -D nofork.
136 */
137 if (amuDebug(D_FORK)) {
138 /* fork child to process request if none in progress */
139 if (found->child && kill(found->child, 0))
140 found->child = 0;
141
142 if (found->child)
143 delay(found, 5); /* wait a bit if in progress */
144 if (found->child) { /* better safe than sorry - maybe */
145 found->last_status = 1;
146 return alt_spooldir;
147 }
148 if ((found->child = fork()) < 0) {
149 found->last_status = 1;
150 return alt_spooldir;
151 }
152 if (found->child) { /* PARENT */
153 if (lastchild)
154 dlog("cache spill uid = %ld, pid = %ld, home = %s",
155 (long) lastchild->uid, (long) lastchild->child,
156 lastchild->home);
157 lastchild = found;
158 return (char *) NULL; /* return NULL to parent, so it can continue */
159 }
160 }
161
162 /*
163 * CHILD: (or parent if -D fork)
164 *
165 * Check and create dir if needed.
166 * Check disk space and/or quotas too.
167 *
168 * We don't need to set the _last_status field of found after the fork
169 * in the child, b/c that information would be later determined in
170 * nfsproc_readlink_2() and the correct exit status would be returned
171 * to the parent upon SIGCHLD in interlock().
172 *
173 */
174 am_set_mypid(); /* for logging routines */
175 if ((old_groupid = setgid(groupid)) < 0) {
176 plog(XLOG_WARNING, "could not setgid to %d: %m", groupid);
177 return linkval;
178 }
179 if ((old_userid = seteuid(userid)) < 0) {
180 plog(XLOG_WARNING, "could not seteuid to %d: %m", userid);
181 setgid(old_groupid);
182 return linkval;
183 }
184 if (hlfsd_stat(linkval, &homestat) < 0) {
185 if (errno == ENOENT) { /* make the spool dir if possible */
186 /* don't use recursive mkdirs here */
187 if (mkdir(linkval, PERS_SPOOLMODE) < 0) {
188 seteuid(old_userid);
189 setgid(old_groupid);
190 plog(XLOG_WARNING, "can't make directory %s: %m", linkval);
191 return alt_spooldir;
192 }
193 /* fall through to testing the disk space / quota */
194 } else { /* the home dir itself must not exist then */
195 seteuid(old_userid);
196 setgid(old_groupid);
197 plog(XLOG_WARNING, "bad link to %s: %m", linkval);
198 return alt_spooldir;
199 }
200 }
201
202 /*
203 * If gets here, then either the spool dir in the home dir exists,
204 * or it was just created. In either case, we now need to
205 * test if we can create a small file and write at least one
206 * byte into it. This will test that we have both enough inodes
207 * and disk blocks to spare, or they fall within the user's quotas too.
208 * We are still seteuid to the user at this point.
209 */
210 if (hlfsd_diskspace(linkval) < 0) {
211 seteuid(old_userid);
212 setgid(old_groupid);
213 plog(XLOG_WARNING, "no more space in %s: %m", linkval);
214 return alt_spooldir;
215 } else {
216 seteuid(old_userid);
217 setgid(old_groupid);
218 return linkval;
219 }
220 }
221
222
223 static int
hlfsd_diskspace(char * path)224 hlfsd_diskspace(char *path)
225 {
226 char buf[MAXPATHLEN];
227 int fd, len;
228
229 xsnprintf(buf, sizeof(buf), "%s/._hlfstmp_%lu", path, (long) getpid());
230 if ((fd = open(buf, O_RDWR | O_CREAT, 0600)) < 0) {
231 plog(XLOG_ERROR, "cannot open %s: %m", buf);
232 return -1;
233 }
234 len = strlen(buf);
235 if (write(fd, buf, len) < len) {
236 plog(XLOG_ERROR, "cannot write \"%s\" (%d bytes) to %s : %m", buf, len, buf);
237 close(fd);
238 unlink(buf); /* cleanup just in case */
239 return -1;
240 }
241 if (unlink(buf) < 0) {
242 plog(XLOG_ERROR, "cannot unlink %s : %m", buf);
243 }
244 close(fd);
245 return 0;
246 }
247
248
249 static int
hlfsd_stat(char * path,struct stat * statp)250 hlfsd_stat(char *path, struct stat *statp)
251 {
252 if (stat(path, statp) < 0)
253 return -1;
254 else if (!S_ISDIR(statp->st_mode)) {
255 errno = ENOTDIR;
256 return -1;
257 }
258 return 0;
259 }
260
261
262 static void
delay(uid2home_t * found,int secs)263 delay(uid2home_t *found, int secs)
264 {
265 struct timeval tv;
266
267 if (found)
268 dlog("delaying on child %ld for %d seconds", (long) found->child, secs);
269
270 tv.tv_usec = 0;
271
272 do {
273 tv.tv_sec = secs;
274 if (select(0, NULL, NULL, NULL, &tv) == 0)
275 break;
276 } while (--secs && found->child);
277 }
278
279
280 /*
281 * This function is called when a child has terminated after
282 * servicing an nfs request. We need to check the exit status and
283 * update the last_status field of the requesting user.
284 */
285 RETSIGTYPE
interlock(int signum)286 interlock(int signum)
287 {
288 int child;
289 uid2home_t *lostchild;
290 int status;
291
292 #ifdef HAVE_WAITPID
293 while ((child = waitpid((pid_t) -1, &status, WNOHANG)) > 0) {
294 #else /* not HAVE_WAITPID */
295 while ((child = wait3(&status, WNOHANG, (struct rusage *) NULL)) > 0) {
296 #endif /* not HAVE_WAITPID */
297
298 /* high chances this was the last child forked */
299 if (lastchild && lastchild->child == child) {
300 lastchild->child = 0;
301
302 if (WIFEXITED(status))
303 lastchild->last_status = WEXITSTATUS(status);
304 lastchild = (uid2home_t *) NULL;
305 } else {
306 /* and if not, we have to search for it... */
307 for (lostchild = pwtab; lostchild < &pwtab[cur_pwtab_num]; lostchild++) {
308 if (lostchild->child == child) {
309 if (WIFEXITED(status))
310 lostchild->last_status = WEXITSTATUS(status);
311 lostchild->child = 0;
312 break;
313 }
314 }
315 }
316 }
317 }
318
319
320 /*
321 * PASSWORD AND USERNAME LOOKUP TABLES FUNCTIONS
322 */
323
324 /*
325 * get index of UserName table entry which matches username.
326 * must not return uid_t because we want to return a negative number.
327 */
328 int
329 untab_index(char *username)
330 {
331 int max, min, mid, cmp;
332
333 max = cur_pwtab_num - 1;
334 min = 0;
335
336 do {
337 mid = (max + min) / 2;
338 cmp = strcmp(untab[mid].username, username);
339 if (cmp == 0) /* record found! */
340 return mid;
341 if (cmp > 0)
342 max = mid;
343 else
344 min = mid;
345 } while (max > min + 1);
346
347 if (STREQ(untab[max].username, username))
348 return max;
349 if (STREQ(untab[min].username, username))
350 return min;
351
352 /* if gets here then record was not found */
353 return -1;
354 }
355
356
357 /*
358 * Don't make this return a uid_t, because we need to return negative
359 * numbers as well (error codes.)
360 */
361 int
362 uidof(char *username)
363 {
364 int idx;
365
366 if ((idx = untab_index(username)) < 0) /* not found */
367 return INVALIDID; /* an invalid user id */
368 return untab[idx].uid;
369 }
370
371
372 /*
373 * Don't make this return a uid_t, because we need to return negative
374 * numbers as well (error codes.)
375 */
376 char *
377 homeof(char *username)
378 {
379 int idx;
380
381 if ((idx = untab_index(username)) < 0) /* not found */
382 return (char *) NULL; /* an invalid user id */
383 return untab[idx].home;
384 }
385
386
387 char *
388 mailbox(int uid, char *username)
389 {
390 char *home;
391
392 if (uid < 0)
393 return (char *) NULL; /* not found */
394
395 if ((home = homeof(username)) == (char *) NULL)
396 return (char *) NULL;
397 if (STREQ(home, "/"))
398 xsnprintf(mboxfile, sizeof(mboxfile),
399 "/%s/%s", home_subdir, username);
400 else
401 xsnprintf(mboxfile, sizeof(mboxfile),
402 "%s/%s/%s", home, home_subdir, username);
403 return mboxfile;
404 }
405
406
407 static int
408 plt_compare_fxn(const voidp x, const voidp y)
409
410 {
411 uid2home_t *i = (uid2home_t *) x;
412 uid2home_t *j = (uid2home_t *) y;
413
414 return i->uid - j->uid;
415 }
416
417
418 static int
419 unt_compare_fxn(const voidp x, const voidp y)
420 {
421 username2uid_t *i = (username2uid_t *) x;
422 username2uid_t *j = (username2uid_t *) y;
423
424 return strcmp(i->username, j->username);
425 }
426
427
428 /* perform initialization of user passwd database */
429 static void
430 hlfsd_setpwent(void)
431 {
432 if (!passwdfile) {
433 setpwent();
434 return;
435 }
436
437 passwd_fp = fopen(passwdfile, "r");
438 if (!passwd_fp) {
439 plog(XLOG_ERROR, "unable to read passwd file %s: %m", passwdfile);
440 return;
441 }
442 plog(XLOG_INFO, "reading password entries from file %s", passwdfile);
443
444 passwd_line = 0;
445 memset((char *) &passwd_ent, 0, sizeof(struct passwd));
446 passwd_ent.pw_name = (char *) &pw_name;
447 passwd_ent.pw_dir = (char *) &pw_dir;
448 }
449
450
451 /* perform de-initialization of user passwd database */
452 static void
453 hlfsd_endpwent(void)
454 {
455 if (!passwdfile) {
456 /*
457 * Don't actually run this because we will be making more passwd calls
458 * afterwards. On Solaris 2.5.1, making getpwent() calls after calling
459 * endpwent() results in a memory leak! (and no, even Purify didn't
460 * detect it...)
461 *
462 endpwent();
463 */
464 return;
465 }
466
467 if (passwd_fp) {
468 fclose(passwd_fp);
469 }
470 }
471
472
473 /* perform record reading/parsing of individual passwd database records */
474 static struct passwd *
475 hlfsd_getpwent(void)
476 {
477 char buf[256], *cp;
478
479 /* check if to perform standard unix function */
480 if (!passwdfile) {
481 return getpwent();
482 }
483
484 /* return here to read another entry */
485 readent:
486
487 /* return NULL if reached end of file */
488 if (feof(passwd_fp))
489 return NULL;
490
491 pw_name[0] = pw_dir[0] = '\0';
492
493 /* read records */
494 buf[0] = '\0';
495 if (fgets(buf, 256, passwd_fp) == NULL)
496 return NULL;
497 passwd_line++;
498 if (buf[0] == '\0')
499 goto readent;
500
501 /* read user name */
502 cp = strtok(buf, ":");
503 if (!cp || cp[0] == '\0') {
504 plog(XLOG_ERROR, "no user name on line %d of %s", passwd_line, passwdfile);
505 goto readent;
506 }
507 /* pw_name will show up in passwd_ent.pw_name */
508 xstrlcpy(pw_name, cp, sizeof(pw_name));
509
510 /* skip passwd */
511 strtok(NULL, ":");
512
513 /* read uid */
514 cp = strtok(NULL, ":");
515 if (!cp || cp[0] == '\0') {
516 plog(XLOG_ERROR, "no uid on line %d of %s", passwd_line, passwdfile);
517 goto readent;
518 }
519 passwd_ent.pw_uid = atoi(cp);
520
521 /* skip gid and gcos */
522 strtok(NULL, ":");
523 strtok(NULL, ":");
524
525 /* read home dir */
526 cp = strtok(NULL, ":");
527 if (!cp || cp[0] == '\0') {
528 plog(XLOG_ERROR, "no home dir on line %d of %s", passwd_line, passwdfile);
529 goto readent;
530 }
531 /* pw_dir will show up in passwd_ent.pw_dir */
532 xstrlcpy(pw_dir, cp, sizeof(pw_dir));
533
534 /* the rest of the fields are unimportant and not being considered */
535
536 plog(XLOG_USER, "hlfsd_getpwent: name=%s, uid=%ld, dir=%s",
537 passwd_ent.pw_name, (long) passwd_ent.pw_uid, passwd_ent.pw_dir);
538
539 return &passwd_ent;
540 }
541
542
543 /*
544 * read and hash the passwd file or NIS map
545 */
546 void
547 plt_init(void)
548 {
549 struct passwd *pent_p;
550
551 if (plt_reset() < 0) /* could not reset table. skip. */
552 return;
553
554 plog(XLOG_INFO, "reading password map");
555
556 hlfsd_setpwent(); /* prepare to read passwd entries */
557 while ((pent_p = hlfsd_getpwent()) != (struct passwd *) NULL) {
558 table_add(pent_p->pw_uid, pent_p->pw_dir, pent_p->pw_name);
559 if (STREQ("root", pent_p->pw_name)) {
560 int len;
561 if (root_home)
562 XFREE(root_home);
563 root_home = xstrdup(pent_p->pw_dir);
564 len = strlen(root_home);
565 /* remove any trailing '/' chars from root's home (even if just one) */
566 while (len > 0 && root_home[len - 1] == '/') {
567 len--;
568 root_home[len] = '\0';
569 }
570 }
571 }
572 hlfsd_endpwent();
573
574 qsort((char *) pwtab, cur_pwtab_num, sizeof(uid2home_t),
575 plt_compare_fxn);
576 qsort((char *) untab, cur_pwtab_num, sizeof(username2uid_t),
577 unt_compare_fxn);
578
579 if (!root_home)
580 root_home = xstrdup("");
581
582 plog(XLOG_INFO, "password map read and sorted");
583 }
584
585
586 /*
587 * This is essentially so that we don't reset known good lookup tables when a
588 * YP server goes down.
589 */
590 static int
591 plt_reset(void)
592 {
593 int i;
594
595 hlfsd_setpwent();
596 if (hlfsd_getpwent() == (struct passwd *) NULL) {
597 hlfsd_endpwent();
598 return -1; /* did not reset table */
599 }
600 hlfsd_endpwent();
601
602 lastchild = (uid2home_t *) NULL;
603
604 if (max_pwtab_num > 0) /* was used already. cleanup old table */
605 for (i = 0; i < cur_pwtab_num; ++i) {
606 if (pwtab[i].home) {
607 XFREE(pwtab[i].home);
608 pwtab[i].home = (char *) NULL;
609 }
610 pwtab[i].uid = INVALIDID; /* not a valid uid (yet...) */
611 pwtab[i].child = (pid_t) 0;
612 pwtab[i].uname = (char *) NULL; /* only a ptr to untab[i].username */
613 if (untab[i].username) {
614 XFREE(untab[i].username);
615 untab[i].username = (char *) NULL;
616 }
617 untab[i].uid = INVALIDID; /* invalid uid */
618 untab[i].home = (char *) NULL; /* only a ptr to pwtab[i].home */
619 }
620 cur_pwtab_num = 0; /* zero current size */
621
622 if (root_home)
623 XFREE(root_home);
624
625 return 0; /* resetting ok */
626 }
627
628
629 /*
630 * u: uid number
631 * h: home directory
632 * n: user ID name
633 */
634 static void
635 table_add(u_int u, const char *h, const char *n)
636 {
637 int i;
638
639 if (max_pwtab_num <= 0) { /* was never initialized */
640 max_pwtab_num = 1;
641 pwtab = (uid2home_t *) xmalloc(max_pwtab_num *
642 sizeof(uid2home_t));
643 memset((char *) &pwtab[0], 0, max_pwtab_num * sizeof(uid2home_t));
644 untab = (username2uid_t *) xmalloc(max_pwtab_num *
645 sizeof(username2uid_t));
646 memset((char *) &untab[0], 0, max_pwtab_num * sizeof(username2uid_t));
647 }
648
649 /* check if need more space. */
650 if (cur_pwtab_num + 1 > max_pwtab_num) {
651 /* need more space in table */
652 max_pwtab_num *= 2;
653 plog(XLOG_INFO, "reallocating table spaces to %d entries", max_pwtab_num);
654 pwtab = (uid2home_t *) xrealloc(pwtab,
655 sizeof(uid2home_t) * max_pwtab_num);
656 untab = (username2uid_t *) xrealloc(untab,
657 sizeof(username2uid_t) *
658 max_pwtab_num);
659 /* zero out newly added entries */
660 for (i=cur_pwtab_num; i<max_pwtab_num; ++i) {
661 memset((char *) &pwtab[i], 0, sizeof(uid2home_t));
662 memset((char *) &untab[i], 0, sizeof(username2uid_t));
663 }
664 }
665
666 /* do NOT add duplicate entries (this is an O(N^2) algorithm... */
667 for (i=0; i<cur_pwtab_num; ++i)
668 if (u == pwtab[i].uid && u != 0 ) {
669 dlog("ignoring duplicate home %s for uid %d (already %s)",
670 h, u, pwtab[i].home);
671 return;
672 }
673
674 /* add new password entry */
675 pwtab[cur_pwtab_num].home = xstrdup(h);
676 pwtab[cur_pwtab_num].child = 0;
677 pwtab[cur_pwtab_num].last_access_time = 0;
678 pwtab[cur_pwtab_num].last_status = 0; /* assume best: used homedir */
679 pwtab[cur_pwtab_num].uid = u;
680
681 /* add new userhome entry */
682 untab[cur_pwtab_num].username = xstrdup(n);
683
684 /* just a second pointer */
685 pwtab[cur_pwtab_num].uname = untab[cur_pwtab_num].username;
686 untab[cur_pwtab_num].uid = u;
687 untab[cur_pwtab_num].home = pwtab[cur_pwtab_num].home; /* a ptr */
688
689 /* increment counter */
690 ++cur_pwtab_num;
691 }
692
693
694 /*
695 * return entry in lookup table
696 */
697 uid2home_t *
698 plt_search(u_int u)
699 {
700 int max, min, mid;
701
702 /*
703 * empty table should not happen,
704 * but I have a bug with signals to trace...
705 */
706 if (pwtab == (uid2home_t *) NULL)
707 return (uid2home_t *) NULL;
708
709 max = cur_pwtab_num - 1;
710 min = 0;
711
712 do {
713 mid = (max + min) / 2;
714 if (pwtab[mid].uid == u) /* record found! */
715 return &pwtab[mid];
716 if (pwtab[mid].uid > u)
717 max = mid;
718 else
719 min = mid;
720 } while (max > min + 1);
721
722 if (pwtab[max].uid == u)
723 return &pwtab[max];
724 if (pwtab[min].uid == u)
725 return &pwtab[min];
726
727 /* if gets here then record was not found */
728 return (uid2home_t *) NULL;
729 }
730
731
732 #if defined(DEBUG) || defined(DEBUG_PRINT)
733 void
734 plt_print(int signum)
735 {
736 FILE *dumpfile;
737 int dumpfd;
738 char dumptmp[] = "/usr/tmp/hlfsd.dump.XXXXXX";
739 int i;
740
741 #ifdef HAVE_MKSTEMP
742 dumpfd = mkstemp(dumptmp);
743 #else /* not HAVE_MKSTEMP */
744 mktemp(dumptmp);
745 if (!dumptmp) {
746 plog(XLOG_ERROR, "cannot create temporary dump file");
747 return;
748 }
749 dumpfd = open(dumptmp, O_RDONLY);
750 #endif /* not HAVE_MKSTEMP */
751 if (dumpfd < 0) {
752 plog(XLOG_ERROR, "cannot open temporary dump file");
753 return;
754 }
755 if ((dumpfile = fdopen(dumpfd, "a")) != NULL) {
756 plog(XLOG_INFO, "dumping internal state to file %s", dumptmp);
757 fprintf(dumpfile, "\n\nNew plt_dump():\n");
758 for (i = 0; i < cur_pwtab_num; ++i)
759 fprintf(dumpfile,
760 "%4d %5lu %10lu %1d %4lu \"%s\" uname=\"%s\"\n",
761 i,
762 (long) pwtab[i].child,
763 pwtab[i].last_access_time,
764 pwtab[i].last_status,
765 (long) pwtab[i].uid,
766 pwtab[i].home,
767 pwtab[i].uname);
768 fprintf(dumpfile, "\nUserName table by plt_print():\n");
769 for (i = 0; i < cur_pwtab_num; ++i)
770 fprintf(dumpfile, "%4d : \"%s\" %4lu \"%s\"\n", i,
771 untab[i].username, (long) untab[i].uid, untab[i].home);
772 close(dumpfd);
773 fclose(dumpfile);
774 }
775 }
776
777
778 void
779 plt_dump(uid2home_t *lastc, pid_t this)
780 {
781 FILE *dumpfile;
782 int i;
783
784 if ((dumpfile = fopen("/var/tmp/hlfsdump", "a")) != NULL) {
785 fprintf(dumpfile, "\n\nNEW PLT_DUMP -- ");
786 fprintf(dumpfile, "lastchild->child=%d ",
787 (int) (lastc ? lastc->child : -999));
788 fprintf(dumpfile, ", child from wait3=%lu:\n", (long) this);
789 for (i = 0; i < cur_pwtab_num; ++i)
790 fprintf(dumpfile, "%4d %5lu: %4lu \"%s\" uname=\"%s\"\n", i,
791 (long) pwtab[i].child, (long) pwtab[i].uid,
792 pwtab[i].home, pwtab[i].uname);
793 fprintf(dumpfile, "\nUserName table by plt_dump():\n");
794 for (i = 0; i < cur_pwtab_num; ++i)
795 fprintf(dumpfile, "%4d : \"%s\" %4lu \"%s\"\n", i,
796 untab[i].username, (long) untab[i].uid, untab[i].home);
797 fprintf(dumpfile, "ezk: ent=%d, uid=%lu, home=\"%s\"\n",
798 untab_index("ezk"),
799 (long) untab[untab_index("ezk")].uid,
800 pwtab[untab[untab_index("ezk")].uid].home);
801 fprintf(dumpfile, "rezk: ent=%d, uid=%lu, home=\"%s\"\n",
802 untab_index("rezk"),
803 (long) untab[untab_index("rezk")].uid,
804 pwtab[untab[untab_index("rezk")].uid].home);
805 fclose(dumpfile);
806 }
807 }
808 #endif /* defined(DEBUG) || defined(DEBUG_PRINT) */
809