homedir.c revision 310490
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 <ezk@cs.columbia.edu> and Alexander Dupuy <dupuy@cs.columbia.edu> 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 */ 53static FILE *passwd_fp = NULL; 54static char pw_name[16], pw_dir[128]; 55static int cur_pwtab_num = 0, max_pwtab_num = 0; 56static int hlfsd_diskspace(char *); 57static int hlfsd_stat(char *, struct stat *); 58static int passwd_line = 0; 59static int plt_reset(void); 60static struct passwd passwd_ent; 61static uid2home_t *lastchild; 62static uid2home_t *pwtab; 63static void delay(uid2home_t *, int); 64static void table_add(u_int, const char *, const char *); 65static char mboxfile[MAXPATHLEN]; 66static char *root_home; /* root's home directory */ 67 68/* GLOBAL FUNCTIONS */ 69char *homeof(char *username); 70int uidof(char *username); 71 72/* GLOBALS VARIABLES */ 73username2uid_t *untab; /* user name table */ 74 75/* 76 * Return the home directory pathname for the user with uid "userid". 77 */ 78char * 79homedir(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 221static int 222hlfsd_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 247static int 248hlfsd_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 260static void 261delay(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 */ 283RETSIGTYPE 284interlock(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 */ 326int 327untab_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 */ 359int 360uidof(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 */ 374char * 375homeof(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 385char * 386mailbox(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 405static int 406plt_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 416static int 417unt_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 */ 427static void 428hlfsd_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 */ 450static void 451hlfsd_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 */ 472static struct passwd * 473hlfsd_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 */ 483readent: 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 fgets(buf, 256, passwd_fp); 494 passwd_line++; 495 if (buf[0] == '\0') 496 goto readent; 497 498 /* read user name */ 499 cp = strtok(buf, ":"); 500 if (!cp || cp[0] == '\0') { 501 plog(XLOG_ERROR, "no user name on line %d of %s", passwd_line, passwdfile); 502 goto readent; 503 } 504 /* pw_name will show up in passwd_ent.pw_name */ 505 xstrlcpy(pw_name, cp, sizeof(pw_name)); 506 507 /* skip passwd */ 508 strtok(NULL, ":"); 509 510 /* read uid */ 511 cp = strtok(NULL, ":"); 512 if (!cp || cp[0] == '\0') { 513 plog(XLOG_ERROR, "no uid on line %d of %s", passwd_line, passwdfile); 514 goto readent; 515 } 516 passwd_ent.pw_uid = atoi(cp); 517 518 /* skip gid and gcos */ 519 strtok(NULL, ":"); 520 strtok(NULL, ":"); 521 522 /* read home dir */ 523 cp = strtok(NULL, ":"); 524 if (!cp || cp[0] == '\0') { 525 plog(XLOG_ERROR, "no home dir on line %d of %s", passwd_line, passwdfile); 526 goto readent; 527 } 528 /* pw_dir will show up in passwd_ent.pw_dir */ 529 xstrlcpy(pw_dir, cp, sizeof(pw_dir)); 530 531 /* the rest of the fields are unimportant and not being considered */ 532 533 plog(XLOG_USER, "hlfsd_getpwent: name=%s, uid=%ld, dir=%s", 534 passwd_ent.pw_name, (long) passwd_ent.pw_uid, passwd_ent.pw_dir); 535 536 return &passwd_ent; 537} 538 539 540/* 541 * read and hash the passwd file or NIS map 542 */ 543void 544plt_init(void) 545{ 546 struct passwd *pent_p; 547 548 if (plt_reset() < 0) /* could not reset table. skip. */ 549 return; 550 551 plog(XLOG_INFO, "reading password map"); 552 553 hlfsd_setpwent(); /* prepare to read passwd entries */ 554 while ((pent_p = hlfsd_getpwent()) != (struct passwd *) NULL) { 555 table_add(pent_p->pw_uid, pent_p->pw_dir, pent_p->pw_name); 556 if (STREQ("root", pent_p->pw_name)) { 557 int len; 558 if (root_home) 559 XFREE(root_home); 560 root_home = xstrdup(pent_p->pw_dir); 561 len = strlen(root_home); 562 /* remove any trailing '/' chars from root's home (even if just one) */ 563 while (len > 0 && root_home[len - 1] == '/') { 564 len--; 565 root_home[len] = '\0'; 566 } 567 } 568 } 569 hlfsd_endpwent(); 570 571 qsort((char *) pwtab, cur_pwtab_num, sizeof(uid2home_t), 572 plt_compare_fxn); 573 qsort((char *) untab, cur_pwtab_num, sizeof(username2uid_t), 574 unt_compare_fxn); 575 576 if (!root_home) 577 root_home = xstrdup(""); 578 579 plog(XLOG_INFO, "password map read and sorted"); 580} 581 582 583/* 584 * This is essentially so that we don't reset known good lookup tables when a 585 * YP server goes down. 586 */ 587static int 588plt_reset(void) 589{ 590 int i; 591 592 hlfsd_setpwent(); 593 if (hlfsd_getpwent() == (struct passwd *) NULL) { 594 hlfsd_endpwent(); 595 return -1; /* did not reset table */ 596 } 597 hlfsd_endpwent(); 598 599 lastchild = (uid2home_t *) NULL; 600 601 if (max_pwtab_num > 0) /* was used already. cleanup old table */ 602 for (i = 0; i < cur_pwtab_num; ++i) { 603 if (pwtab[i].home) { 604 XFREE(pwtab[i].home); 605 pwtab[i].home = (char *) NULL; 606 } 607 pwtab[i].uid = INVALIDID; /* not a valid uid (yet...) */ 608 pwtab[i].child = (pid_t) 0; 609 pwtab[i].uname = (char *) NULL; /* only a ptr to untab[i].username */ 610 if (untab[i].username) { 611 XFREE(untab[i].username); 612 untab[i].username = (char *) NULL; 613 } 614 untab[i].uid = INVALIDID; /* invalid uid */ 615 untab[i].home = (char *) NULL; /* only a ptr to pwtab[i].home */ 616 } 617 cur_pwtab_num = 0; /* zero current size */ 618 619 if (root_home) 620 XFREE(root_home); 621 622 return 0; /* resetting ok */ 623} 624 625 626/* 627 * u: uid number 628 * h: home directory 629 * n: user ID name 630 */ 631static void 632table_add(u_int u, const char *h, const char *n) 633{ 634 int i; 635 636 if (max_pwtab_num <= 0) { /* was never initialized */ 637 max_pwtab_num = 1; 638 pwtab = (uid2home_t *) xmalloc(max_pwtab_num * 639 sizeof(uid2home_t)); 640 memset((char *) &pwtab[0], 0, max_pwtab_num * sizeof(uid2home_t)); 641 untab = (username2uid_t *) xmalloc(max_pwtab_num * 642 sizeof(username2uid_t)); 643 memset((char *) &untab[0], 0, max_pwtab_num * sizeof(username2uid_t)); 644 } 645 646 /* check if need more space. */ 647 if (cur_pwtab_num + 1 > max_pwtab_num) { 648 /* need more space in table */ 649 max_pwtab_num *= 2; 650 plog(XLOG_INFO, "reallocating table spaces to %d entries", max_pwtab_num); 651 pwtab = (uid2home_t *) xrealloc(pwtab, 652 sizeof(uid2home_t) * max_pwtab_num); 653 untab = (username2uid_t *) xrealloc(untab, 654 sizeof(username2uid_t) * 655 max_pwtab_num); 656 /* zero out newly added entries */ 657 for (i=cur_pwtab_num; i<max_pwtab_num; ++i) { 658 memset((char *) &pwtab[i], 0, sizeof(uid2home_t)); 659 memset((char *) &untab[i], 0, sizeof(username2uid_t)); 660 } 661 } 662 663 /* do NOT add duplicate entries (this is an O(N^2) algorithm... */ 664 for (i=0; i<cur_pwtab_num; ++i) 665 if (u == pwtab[i].uid && u != 0 ) { 666 dlog("ignoring duplicate home %s for uid %d (already %s)", 667 h, u, pwtab[i].home); 668 return; 669 } 670 671 /* add new password entry */ 672 pwtab[cur_pwtab_num].home = xstrdup(h); 673 pwtab[cur_pwtab_num].child = 0; 674 pwtab[cur_pwtab_num].last_access_time = 0; 675 pwtab[cur_pwtab_num].last_status = 0; /* assume best: used homedir */ 676 pwtab[cur_pwtab_num].uid = u; 677 678 /* add new userhome entry */ 679 untab[cur_pwtab_num].username = xstrdup(n); 680 681 /* just a second pointer */ 682 pwtab[cur_pwtab_num].uname = untab[cur_pwtab_num].username; 683 untab[cur_pwtab_num].uid = u; 684 untab[cur_pwtab_num].home = pwtab[cur_pwtab_num].home; /* a ptr */ 685 686 /* increment counter */ 687 ++cur_pwtab_num; 688} 689 690 691/* 692 * return entry in lookup table 693 */ 694uid2home_t * 695plt_search(u_int u) 696{ 697 int max, min, mid; 698 699 /* 700 * empty table should not happen, 701 * but I have a bug with signals to trace... 702 */ 703 if (pwtab == (uid2home_t *) NULL) 704 return (uid2home_t *) NULL; 705 706 max = cur_pwtab_num - 1; 707 min = 0; 708 709 do { 710 mid = (max + min) / 2; 711 if (pwtab[mid].uid == u) /* record found! */ 712 return &pwtab[mid]; 713 if (pwtab[mid].uid > u) 714 max = mid; 715 else 716 min = mid; 717 } while (max > min + 1); 718 719 if (pwtab[max].uid == u) 720 return &pwtab[max]; 721 if (pwtab[min].uid == u) 722 return &pwtab[min]; 723 724 /* if gets here then record was not found */ 725 return (uid2home_t *) NULL; 726} 727 728 729#if defined(DEBUG) || defined(DEBUG_PRINT) 730void 731plt_print(int signum) 732{ 733 FILE *dumpfile; 734 int dumpfd; 735 char dumptmp[] = "/usr/tmp/hlfsd.dump.XXXXXX"; 736 int i; 737 738#ifdef HAVE_MKSTEMP 739 dumpfd = mkstemp(dumptmp); 740#else /* not HAVE_MKSTEMP */ 741 mktemp(dumptmp); 742 if (!dumptmp) { 743 plog(XLOG_ERROR, "cannot create temporary dump file"); 744 return; 745 } 746 dumpfd = open(dumptmp, O_RDONLY); 747#endif /* not HAVE_MKSTEMP */ 748 if (dumpfd < 0) { 749 plog(XLOG_ERROR, "cannot open temporary dump file"); 750 return; 751 } 752 if ((dumpfile = fdopen(dumpfd, "a")) != NULL) { 753 plog(XLOG_INFO, "dumping internal state to file %s", dumptmp); 754 fprintf(dumpfile, "\n\nNew plt_dump():\n"); 755 for (i = 0; i < cur_pwtab_num; ++i) 756 fprintf(dumpfile, 757 "%4d %5lu %10lu %1d %4lu \"%s\" uname=\"%s\"\n", 758 i, 759 (long) pwtab[i].child, 760 pwtab[i].last_access_time, 761 pwtab[i].last_status, 762 (long) pwtab[i].uid, 763 pwtab[i].home, 764 pwtab[i].uname); 765 fprintf(dumpfile, "\nUserName table by plt_print():\n"); 766 for (i = 0; i < cur_pwtab_num; ++i) 767 fprintf(dumpfile, "%4d : \"%s\" %4lu \"%s\"\n", i, 768 untab[i].username, (long) untab[i].uid, untab[i].home); 769 close(dumpfd); 770 fclose(dumpfile); 771 } 772} 773 774 775void 776plt_dump(uid2home_t *lastc, pid_t this) 777{ 778 FILE *dumpfile; 779 int i; 780 781 if ((dumpfile = fopen("/var/tmp/hlfsdump", "a")) != NULL) { 782 fprintf(dumpfile, "\n\nNEW PLT_DUMP -- "); 783 fprintf(dumpfile, "lastchild->child=%d ", 784 (int) (lastc ? lastc->child : -999)); 785 fprintf(dumpfile, ", child from wait3=%lu:\n", (long) this); 786 for (i = 0; i < cur_pwtab_num; ++i) 787 fprintf(dumpfile, "%4d %5lu: %4lu \"%s\" uname=\"%s\"\n", i, 788 (long) pwtab[i].child, (long) pwtab[i].uid, 789 pwtab[i].home, pwtab[i].uname); 790 fprintf(dumpfile, "\nUserName table by plt_dump():\n"); 791 for (i = 0; i < cur_pwtab_num; ++i) 792 fprintf(dumpfile, "%4d : \"%s\" %4lu \"%s\"\n", i, 793 untab[i].username, (long) untab[i].uid, untab[i].home); 794 fprintf(dumpfile, "ezk: ent=%d, uid=%lu, home=\"%s\"\n", 795 untab_index("ezk"), 796 (long) untab[untab_index("ezk")].uid, 797 pwtab[untab[untab_index("ezk")].uid].home); 798 fprintf(dumpfile, "rezk: ent=%d, uid=%lu, home=\"%s\"\n", 799 untab_index("rezk"), 800 (long) untab[untab_index("rezk")].uid, 801 pwtab[untab[untab_index("rezk")].uid].home); 802 fclose(dumpfile); 803 } 804} 805#endif /* defined(DEBUG) || defined(DEBUG_PRINT) */ 806