1/* 2 * Copyright (c) 1997-2006 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. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgment: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * 40 * File: am-utils/hlfsd/homedir.c 41 * 42 * HLFSD was written at Columbia University Computer Science Department, by 43 * Erez Zadok <ezk@cs.columbia.edu> and Alexander Dupuy <dupuy@cs.columbia.edu> 44 * It is being distributed under the same terms and conditions as amd does. 45 */ 46 47#ifdef HAVE_CONFIG_H 48# include <config.h> 49#endif /* HAVE_CONFIG_H */ 50#include <am_defs.h> 51#include <hlfsd.h> 52 53 54/* 55 * STATIC VARIABLES AND FUNCTIONS: 56 */ 57static FILE *passwd_fp = NULL; 58static char pw_name[16], pw_dir[128]; 59static int cur_pwtab_num = 0, max_pwtab_num = 0; 60static int hlfsd_diskspace(char *); 61static int hlfsd_stat(char *, struct stat *); 62static int passwd_line = 0; 63static int plt_reset(void); 64static struct passwd passwd_ent; 65static uid2home_t *lastchild; 66static uid2home_t *pwtab; 67static void delay(uid2home_t *, int); 68static void table_add(u_int, const char *, const char *); 69static char mboxfile[MAXPATHLEN]; 70static char *root_home; /* root's home directory */ 71 72/* GLOBAL FUNCTIONS */ 73char *homeof(char *username); 74int uidof(char *username); 75 76/* GLOBALS VARIABLES */ 77username2uid_t *untab; /* user name table */ 78 79/* 80 * Return the home directory pathname for the user with uid "userid". 81 */ 82char * 83homedir(int userid, int groupid) 84{ 85 static char linkval[MAXPATHLEN + 1]; 86 static struct timeval tp; 87 uid2home_t *found; 88 char *homename; 89 struct stat homestat; 90 int old_groupid, old_userid; 91 92 if ((found = plt_search(userid)) == (uid2home_t *) NULL) { 93 return alt_spooldir; /* use alt spool for unknown uid */ 94 } 95 homename = found->home; 96 97 if (homename[0] != '/' || homename[1] == '\0') { 98 found->last_status = 1; 99 return alt_spooldir; /* use alt spool for / or rel. home */ 100 } 101 if ((int) userid == 0) /* force all uid 0 to use root's home */ 102 xsnprintf(linkval, sizeof(linkval), "%s/%s", root_home, home_subdir); 103 else 104 xsnprintf(linkval, sizeof(linkval), "%s/%s", homename, home_subdir); 105 106 if (noverify) { 107 found->last_status = 0; 108 return linkval; 109 } 110 111 /* 112 * To optimize hlfsd, we don't actually check the validity of the 113 * symlink if it has been checked in the last N seconds. It is 114 * very likely that the link, machine, and filesystem are still 115 * valid, as long as N is small. But if N is large, that may not be 116 * true. That's why the default N is 5 minutes, but we allow the 117 * user to override this value via a command line option. Note that 118 * we do not update the last_access_time each time it is accessed, 119 * but only once every N seconds. 120 */ 121 if (gettimeofday(&tp, (struct timezone *) NULL) < 0) { 122 tp.tv_sec = 0; 123 } else { 124 if ((tp.tv_sec - found->last_access_time) < cache_interval) { 125 if (found->last_status == 0) { 126 return linkval; 127 } else { 128 return alt_spooldir; 129 } 130 } else { 131 found->last_access_time = tp.tv_sec; 132 } 133 } 134 135 /* 136 * only run this forking code if did not ask for -D fork 137 */ 138 if (!amuDebug(D_FORK)) { 139 /* fork child to process request if none in progress */ 140 if (found->child && kill(found->child, 0)) 141 found->child = 0; 142 143 if (found->child) 144 delay(found, 5); /* wait a bit if in progress */ 145 if (found->child) { /* better safe than sorry - maybe */ 146 found->last_status = 1; 147 return alt_spooldir; 148 } 149 if ((found->child = fork()) < 0) { 150 found->last_status = 1; 151 return alt_spooldir; 152 } 153 if (found->child) { /* PARENT */ 154 if (lastchild) 155 dlog("cache spill uid = %ld, pid = %ld, home = %s", 156 (long) lastchild->uid, (long) lastchild->child, 157 lastchild->home); 158 lastchild = found; 159 return (char *) NULL; /* return NULL to parent, so it can continue */ 160 } 161 } 162 163 /* 164 * CHILD: (or parent if -D fork) 165 * 166 * Check and create dir if needed. 167 * Check disk space and/or quotas too. 168 * 169 * We don't need to set the _last_status field of found after the fork 170 * in the child, b/c that information would be later determined in 171 * nfsproc_readlink_2() and the correct exit status would be returned 172 * to the parent upon SIGCHLD in interlock(). 173 * 174 */ 175 am_set_mypid(); /* for logging routines */ 176 if ((old_groupid = setgid(groupid)) < 0) { 177 plog(XLOG_WARNING, "could not setgid to %d: %m", groupid); 178 return linkval; 179 } 180 if ((old_userid = seteuid(userid)) < 0) { 181 plog(XLOG_WARNING, "could not seteuid to %d: %m", userid); 182 setgid(old_groupid); 183 return linkval; 184 } 185 if (hlfsd_stat(linkval, &homestat) < 0) { 186 if (errno == ENOENT) { /* make the spool dir if possible */ 187 /* don't use recursive mkdirs here */ 188 if (mkdir(linkval, PERS_SPOOLMODE) < 0) { 189 seteuid(old_userid); 190 setgid(old_groupid); 191 plog(XLOG_WARNING, "can't make directory %s: %m", linkval); 192 return alt_spooldir; 193 } 194 /* fall through to testing the disk space / quota */ 195 } else { /* the home dir itself must not exist then */ 196 seteuid(old_userid); 197 setgid(old_groupid); 198 plog(XLOG_WARNING, "bad link to %s: %m", linkval); 199 return alt_spooldir; 200 } 201 } 202 203 /* 204 * If gets here, then either the spool dir in the home dir exists, 205 * or it was just created. In either case, we now need to 206 * test if we can create a small file and write at least one 207 * byte into it. This will test that we have both enough inodes 208 * and disk blocks to spare, or they fall within the user's quotas too. 209 * We are still seteuid to the user at this point. 210 */ 211 if (hlfsd_diskspace(linkval) < 0) { 212 seteuid(old_userid); 213 setgid(old_groupid); 214 plog(XLOG_WARNING, "no more space in %s: %m", linkval); 215 return alt_spooldir; 216 } else { 217 seteuid(old_userid); 218 setgid(old_groupid); 219 return linkval; 220 } 221} 222 223 224static int 225hlfsd_diskspace(char *path) 226{ 227 char buf[MAXPATHLEN]; 228 int fd, len; 229 230 xsnprintf(buf, sizeof(buf), "%s/._hlfstmp_%lu", path, (long) getpid()); 231 if ((fd = open(buf, O_RDWR | O_CREAT, 0600)) < 0) { 232 plog(XLOG_ERROR, "cannot open %s: %m", buf); 233 return -1; 234 } 235 len = strlen(buf); 236 if (write(fd, buf, len) < len) { 237 plog(XLOG_ERROR, "cannot write \"%s\" (%d bytes) to %s : %m", buf, len, buf); 238 close(fd); 239 unlink(buf); /* cleanup just in case */ 240 return -1; 241 } 242 if (unlink(buf) < 0) { 243 plog(XLOG_ERROR, "cannot unlink %s : %m", buf); 244 } 245 close(fd); 246 return 0; 247} 248 249 250static int 251hlfsd_stat(char *path, struct stat *statp) 252{ 253 if (stat(path, statp) < 0) 254 return -1; 255 else if (!S_ISDIR(statp->st_mode)) { 256 errno = ENOTDIR; 257 return -1; 258 } 259 return 0; 260} 261 262 263static void 264delay(uid2home_t *found, int secs) 265{ 266 struct timeval tv; 267 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, 0, 0, 0, &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 */ 285RETSIGTYPE 286interlock(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 *) 0)) > 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 */ 328int 329untab_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 */ 361int 362uidof(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 */ 376char * 377homeof(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 387char * 388mailbox(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 407static int 408plt_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 418static int 419unt_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 */ 429static void 430hlfsd_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 */ 452static void 453hlfsd_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 */ 474static struct passwd * 475hlfsd_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 */ 485readent: 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 fgets(buf, 256, passwd_fp); 496 passwd_line++; 497 if (!buf || buf[0] == '\0') 498 goto readent; 499 500 /* read user name */ 501 cp = strtok(buf, ":"); 502 if (!cp || cp[0] == '\0') { 503 plog(XLOG_ERROR, "no user name on line %d of %s", passwd_line, passwdfile); 504 goto readent; 505 } 506 /* pw_name will show up in passwd_ent.pw_name */ 507 xstrlcpy(pw_name, cp, sizeof(pw_name)); 508 509 /* skip passwd */ 510 strtok(NULL, ":"); 511 512 /* read uid */ 513 cp = strtok(NULL, ":"); 514 if (!cp || cp[0] == '\0') { 515 plog(XLOG_ERROR, "no uid on line %d of %s", passwd_line, passwdfile); 516 goto readent; 517 } 518 passwd_ent.pw_uid = atoi(cp); 519 520 /* skip gid and gcos */ 521 strtok(NULL, ":"); 522 strtok(NULL, ":"); 523 524 /* read home dir */ 525 cp = strtok(NULL, ":"); 526 if (!cp || cp[0] == '\0') { 527 plog(XLOG_ERROR, "no home dir on line %d of %s", passwd_line, passwdfile); 528 goto readent; 529 } 530 /* pw_dir will show up in passwd_ent.pw_dir */ 531 xstrlcpy(pw_dir, cp, sizeof(pw_dir)); 532 533 /* the rest of the fields are unimportant and not being considered */ 534 535 plog(XLOG_USER, "hlfsd_getpwent: name=%s, uid=%ld, dir=%s", 536 passwd_ent.pw_name, (long) passwd_ent.pw_uid, passwd_ent.pw_dir); 537 538 return &passwd_ent; 539} 540 541 542/* 543 * read and hash the passwd file or NIS map 544 */ 545void 546plt_init(void) 547{ 548 struct passwd *pent_p; 549 550 if (plt_reset() < 0) /* could not reset table. skip. */ 551 return; 552 553 plog(XLOG_INFO, "reading password map"); 554 555 hlfsd_setpwent(); /* prepare to read passwd entries */ 556 while ((pent_p = hlfsd_getpwent()) != (struct passwd *) NULL) { 557 table_add(pent_p->pw_uid, pent_p->pw_dir, pent_p->pw_name); 558 if (STREQ("root", pent_p->pw_name)) { 559 int len; 560 if (root_home) 561 XFREE(root_home); 562 root_home = strdup(pent_p->pw_dir); 563 len = strlen(root_home); 564 /* remove any trailing '/' chars from root's home (even if just one) */ 565 while (len > 0 && root_home[len - 1] == '/') { 566 len--; 567 root_home[len] = '\0'; 568 } 569 } 570 } 571 hlfsd_endpwent(); 572 573 qsort((char *) pwtab, cur_pwtab_num, sizeof(uid2home_t), 574 plt_compare_fxn); 575 qsort((char *) untab, cur_pwtab_num, sizeof(username2uid_t), 576 unt_compare_fxn); 577 578 if (!root_home) 579 root_home = strdup(""); 580 581 plog(XLOG_INFO, "password map read and sorted"); 582} 583 584 585/* 586 * This is essentially so that we don't reset known good lookup tables when a 587 * YP server goes down. 588 */ 589static int 590plt_reset(void) 591{ 592 int i; 593 594 hlfsd_setpwent(); 595 if (hlfsd_getpwent() == (struct passwd *) NULL) { 596 hlfsd_endpwent(); 597 return -1; /* did not reset table */ 598 } 599 hlfsd_endpwent(); 600 601 lastchild = (uid2home_t *) NULL; 602 603 if (max_pwtab_num > 0) /* was used already. cleanup old table */ 604 for (i = 0; i < cur_pwtab_num; ++i) { 605 if (pwtab[i].home) { 606 XFREE(pwtab[i].home); 607 pwtab[i].home = (char *) NULL; 608 } 609 pwtab[i].uid = INVALIDID; /* not a valid uid (yet...) */ 610 pwtab[i].child = (pid_t) 0; 611 pwtab[i].uname = (char *) NULL; /* only a ptr to untab[i].username */ 612 if (untab[i].username) { 613 XFREE(untab[i].username); 614 untab[i].username = (char *) NULL; 615 } 616 untab[i].uid = INVALIDID; /* invalid uid */ 617 untab[i].home = (char *) NULL; /* only a ptr to pwtab[i].home */ 618 } 619 cur_pwtab_num = 0; /* zero current size */ 620 621 if (root_home) 622 XFREE(root_home); 623 624 return 0; /* resetting ok */ 625} 626 627 628/* 629 * u: uid number 630 * h: home directory 631 * n: user ID name 632 */ 633static void 634table_add(u_int u, const char *h, const char *n) 635{ 636 int i; 637 638 if (max_pwtab_num <= 0) { /* was never initialized */ 639 max_pwtab_num = 1; 640 pwtab = (uid2home_t *) xmalloc(max_pwtab_num * 641 sizeof(uid2home_t)); 642 memset((char *) &pwtab[0], 0, max_pwtab_num * sizeof(uid2home_t)); 643 untab = (username2uid_t *) xmalloc(max_pwtab_num * 644 sizeof(username2uid_t)); 645 memset((char *) &untab[0], 0, max_pwtab_num * sizeof(username2uid_t)); 646 } 647 648 /* check if need more space. */ 649 if (cur_pwtab_num + 1 > max_pwtab_num) { 650 /* need more space in table */ 651 max_pwtab_num *= 2; 652 plog(XLOG_INFO, "reallocating table spaces to %d entries", max_pwtab_num); 653 pwtab = (uid2home_t *) xrealloc(pwtab, 654 sizeof(uid2home_t) * max_pwtab_num); 655 untab = (username2uid_t *) xrealloc(untab, 656 sizeof(username2uid_t) * 657 max_pwtab_num); 658 /* zero out newly added entries */ 659 for (i=cur_pwtab_num; i<max_pwtab_num; ++i) { 660 memset((char *) &pwtab[i], 0, sizeof(uid2home_t)); 661 memset((char *) &untab[i], 0, sizeof(username2uid_t)); 662 } 663 } 664 665 /* do NOT add duplicate entries (this is an O(N^2) algorithm... */ 666 for (i=0; i<cur_pwtab_num; ++i) 667 if (u == pwtab[i].uid && u != 0 ) { 668 dlog("ignoring duplicate home %s for uid %d (already %s)", 669 h, u, pwtab[i].home); 670 return; 671 } 672 673 /* add new password entry */ 674 pwtab[cur_pwtab_num].home = strdup(h); 675 pwtab[cur_pwtab_num].child = 0; 676 pwtab[cur_pwtab_num].last_access_time = 0; 677 pwtab[cur_pwtab_num].last_status = 0; /* assume best: used homedir */ 678 pwtab[cur_pwtab_num].uid = u; 679 680 /* add new userhome entry */ 681 untab[cur_pwtab_num].username = strdup(n); 682 683 /* just a second pointer */ 684 pwtab[cur_pwtab_num].uname = untab[cur_pwtab_num].username; 685 untab[cur_pwtab_num].uid = u; 686 untab[cur_pwtab_num].home = pwtab[cur_pwtab_num].home; /* a ptr */ 687 688 /* increment counter */ 689 ++cur_pwtab_num; 690} 691 692 693/* 694 * return entry in lookup table 695 */ 696uid2home_t * 697plt_search(u_int u) 698{ 699 int max, min, mid; 700 701 /* 702 * empty table should not happen, 703 * but I have a bug with signals to trace... 704 */ 705 if (pwtab == (uid2home_t *) NULL) 706 return (uid2home_t *) NULL; 707 708 max = cur_pwtab_num - 1; 709 min = 0; 710 711 do { 712 mid = (max + min) / 2; 713 if (pwtab[mid].uid == u) /* record found! */ 714 return &pwtab[mid]; 715 if (pwtab[mid].uid > u) 716 max = mid; 717 else 718 min = mid; 719 } while (max > min + 1); 720 721 if (pwtab[max].uid == u) 722 return &pwtab[max]; 723 if (pwtab[min].uid == u) 724 return &pwtab[min]; 725 726 /* if gets here then record was not found */ 727 return (uid2home_t *) NULL; 728} 729 730 731#if defined(DEBUG) || defined(DEBUG_PRINT) 732void 733plt_print(int signum) 734{ 735 FILE *dumpfile; 736 int dumpfd; 737 char dumptmp[] = "/usr/tmp/hlfsd.dump.XXXXXX"; 738 int i; 739 740#ifdef HAVE_MKSTEMP 741 dumpfd = mkstemp(dumptmp); 742#else /* not HAVE_MKSTEMP */ 743 mktemp(dumptmp); 744 if (!dumptmp) { 745 plog(XLOG_ERROR, "cannot create temporary dump file"); 746 return; 747 } 748 dumpfd = open(dumptmp, O_RDONLY); 749#endif /* not HAVE_MKSTEMP */ 750 if (dumpfd < 0) { 751 plog(XLOG_ERROR, "cannot open temporary dump file"); 752 return; 753 } 754 if ((dumpfile = fdopen(dumpfd, "a")) != NULL) { 755 plog(XLOG_INFO, "dumping internal state to file %s", dumptmp); 756 fprintf(dumpfile, "\n\nNew plt_dump():\n"); 757 for (i = 0; i < cur_pwtab_num; ++i) 758 fprintf(dumpfile, 759 "%4d %5lu %10lu %1d %4lu \"%s\" uname=\"%s\"\n", 760 i, 761 (long) pwtab[i].child, 762 pwtab[i].last_access_time, 763 pwtab[i].last_status, 764 (long) pwtab[i].uid, 765 pwtab[i].home, 766 pwtab[i].uname); 767 fprintf(dumpfile, "\nUserName table by plt_print():\n"); 768 for (i = 0; i < cur_pwtab_num; ++i) 769 fprintf(dumpfile, "%4d : \"%s\" %4lu \"%s\"\n", i, 770 untab[i].username, (long) untab[i].uid, untab[i].home); 771 close(dumpfd); 772 fclose(dumpfile); 773 } 774} 775 776 777void 778plt_dump(uid2home_t *lastc, pid_t this) 779{ 780 FILE *dumpfile; 781 int i; 782 783 if ((dumpfile = fopen("/var/tmp/hlfsdump", "a")) != NULL) { 784 fprintf(dumpfile, "\n\nNEW PLT_DUMP -- "); 785 fprintf(dumpfile, "lastchild->child=%d ", 786 (int) (lastc ? lastc->child : -999)); 787 fprintf(dumpfile, ", child from wait3=%lu:\n", (long) this); 788 for (i = 0; i < cur_pwtab_num; ++i) 789 fprintf(dumpfile, "%4d %5lu: %4lu \"%s\" uname=\"%s\"\n", i, 790 (long) pwtab[i].child, (long) pwtab[i].uid, 791 pwtab[i].home, pwtab[i].uname); 792 fprintf(dumpfile, "\nUserName table by plt_dump():\n"); 793 for (i = 0; i < cur_pwtab_num; ++i) 794 fprintf(dumpfile, "%4d : \"%s\" %4lu \"%s\"\n", i, 795 untab[i].username, (long) untab[i].uid, untab[i].home); 796 fprintf(dumpfile, "ezk: ent=%d, uid=%lu, home=\"%s\"\n", 797 untab_index("ezk"), 798 (long) untab[untab_index("ezk")].uid, 799 pwtab[untab[untab_index("ezk")].uid].home); 800 fprintf(dumpfile, "rezk: ent=%d, uid=%lu, home=\"%s\"\n", 801 untab_index("rezk"), 802 (long) untab[untab_index("rezk")].uid, 803 pwtab[untab[untab_index("rezk")].uid].home); 804 fclose(dumpfile); 805 } 806} 807#endif /* defined(DEBUG) || defined(DEBUG_PRINT) */ 808