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