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