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 * 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 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 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 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 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