1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <stdio_ext.h> 30 #include <stdlib.h> 31 #include <unistd.h> 32 #include <signal.h> 33 #include <sys/types.h> 34 #include <memory.h> 35 #include <stropts.h> 36 #include <netconfig.h> 37 #include <stdarg.h> 38 #include <sys/resource.h> 39 #include <sys/systeminfo.h> 40 #include <syslog.h> 41 #include <errno.h> 42 #include <sys/sockio.h> 43 #include <rpc/rpc.h> 44 #include <rpc/xdr.h> 45 #include <rpcsvc/nfs_prot.h> 46 #include <net/if.h> 47 #include <netdir.h> 48 #include <string.h> 49 #include <thread.h> 50 #include <locale.h> 51 #include "automount.h" 52 #include <sys/vfs.h> 53 #include <sys/mnttab.h> 54 #include <arpa/inet.h> 55 #include <rpc/svc.h> /* for private dupcache routines */ 56 #include <rpcsvc/daemon_utils.h> 57 #include <deflt.h> 58 #include <strings.h> 59 #include <priv.h> 60 #include <tsol/label.h> 61 62 static void autofs_prog(struct svc_req *, SVCXPRT *); 63 static void autofs_mount_1_r(struct autofs_lookupargs *, 64 struct autofs_mountres *, struct authunix_parms *); 65 static void autofs_mount_1_free_r(struct autofs_mountres *); 66 static void autofs_lookup_1_r(struct autofs_lookupargs *, 67 struct autofs_lookupres *, struct authunix_parms *); 68 static void autofs_lookup_1_free_r(struct autofs_lookupres *); 69 static void autofs_unmount_1_r(struct umntrequest *, struct umntres *, 70 struct authunix_parms *); 71 static void autofs_unmount_1_free_r(struct umntres *); 72 static void autofs_readdir_1_r(struct autofs_rddirargs *, 73 struct autofs_rddirres *, struct authunix_parms *); 74 static void autofs_readdir_1_free_r(struct autofs_rddirres *); 75 static void usage(); 76 static void warn_hup(int); 77 static void free_action_list(); 78 79 static int dupreq_nonidemp(struct svc_req *, SVCXPRT *, int, bool_t (*)(), 80 void (*)()); 81 static int dupdonereq_nonidemp(struct svc_req *, caddr_t, bool_t (*)()); 82 static int dupreq_idemp(struct svc_req *, SVCXPRT *, int, bool_t (*)(), 83 void (*)()); 84 static int dupdonereq_idemp(struct svc_req *, caddr_t, bool_t (*)()); 85 86 #define CTIME_BUF_LEN 26 87 88 /* 89 * XXX - this limit was imposed due to resource problems - even though 90 * we can and do try and set the rlimit to be able to handle more threads, 91 * fopen() doesn't allow more than 256 fp's. 92 */ 93 #define MAXTHREADS 64 94 95 #define RESOURCE_FACTOR 8 96 97 static char str_arch[32]; 98 static char str_cpu[32]; 99 100 struct autodir *dir_head; 101 struct autodir *dir_tail; 102 char self[64]; 103 104 time_t timenow; 105 int verbose = 0; 106 int trace = 0; 107 int automountd_nobrowse = 0; 108 109 int 110 main(argc, argv) 111 int argc; 112 char *argv[]; 113 114 { 115 pid_t pid; 116 int c, i, error; 117 struct rlimit rlset; 118 int rpc_svc_mode = RPC_SVC_MT_AUTO; 119 int maxthreads = MAXTHREADS; 120 int prevthreads = 0; 121 char *defval; 122 int defflags; 123 124 if (geteuid() != 0) { 125 (void) fprintf(stderr, "%s must be run as root\n", argv[0]); 126 exit(1); 127 } 128 129 /* 130 * Read in the values from config file first before we check 131 * commandline options so the options override the file. 132 */ 133 if ((defopen(AUTOFSADMIN)) == 0) { 134 if ((defval = defread("AUTOMOUNTD_VERBOSE=")) != NULL) { 135 if (strncasecmp("true", defval, 4) == 0) 136 verbose = TRUE; 137 else 138 verbose = FALSE; 139 } 140 if ((defval = defread("AUTOMOUNTD_NOBROWSE=")) != NULL) { 141 if (strncasecmp("true", defval, 4) == 0) 142 automountd_nobrowse = TRUE; 143 else 144 automountd_nobrowse = FALSE; 145 } 146 if ((defval = defread("AUTOMOUNTD_TRACE=")) != NULL) { 147 errno = 0; 148 trace = strtol(defval, (char **)NULL, 10); 149 if (errno != 0) 150 trace = 0; 151 } 152 if ((defval = defread("AUTOMOUNTD_ENV=")) != NULL) { 153 (void) putenv(strdup(defval)); 154 defflags = defcntl(DC_GETFLAGS, 0); 155 TURNON(defflags, DC_NOREWIND); 156 defflags = defcntl(DC_SETFLAGS, defflags); 157 while ((defval = defread("AUTOMOUNTD_ENV=")) != NULL) 158 (void) putenv(strdup(defval)); 159 (void) defcntl(DC_SETFLAGS, defflags); 160 } 161 162 /* close defaults file */ 163 defopen(NULL); 164 } 165 166 while ((c = getopt(argc, argv, "vnTD:")) != EOF) { 167 switch (c) { 168 case 'v': 169 verbose++; 170 break; 171 case 'n': 172 automountd_nobrowse++; 173 break; 174 case 'T': 175 trace++; 176 break; 177 case 'D': 178 (void) putenv(optarg); 179 break; 180 default: 181 usage(); 182 } 183 } 184 185 if (sysinfo(SI_HOSTNAME, self, sizeof (self)) == -1) { 186 error = errno; 187 fprintf(stderr, 188 "automountd: can't determine hostname, error: %d\n", 189 error); 190 exit(1); 191 } 192 193 #ifndef DEBUG 194 pid = fork(); 195 if (pid < 0) { 196 perror("cannot fork"); 197 exit(1); 198 } 199 if (pid) 200 exit(0); 201 #endif 202 203 (void) setsid(); 204 openlog("automountd", LOG_PID, LOG_DAEMON); 205 (void) setlocale(LC_ALL, ""); 206 207 /* 208 * Since the "arch" command no longer exists we 209 * have to rely on sysinfo(SI_MACHINE) to return the closest 210 * approximation. For backward compatibility we 211 * need to substitute "sun4" for "sun4m", "sun4c", ... 212 */ 213 if (getenv("ARCH") == NULL) { 214 char buf[16]; 215 216 if (sysinfo(SI_MACHINE, buf, sizeof (buf)) != -1) { 217 if (strncmp(buf, "sun4", 4) == 0) 218 (void) strcpy(buf, "sun4"); 219 (void) sprintf(str_arch, "ARCH=%s", buf); 220 (void) putenv(str_arch); 221 } else { 222 syslog(LOG_ERR, 223 "can't determine machine type, error: %m"); 224 } 225 } 226 if (getenv("CPU") == NULL) { 227 char buf[16]; 228 229 if (sysinfo(SI_ARCHITECTURE, buf, sizeof (buf)) != -1) { 230 (void) sprintf(str_cpu, "CPU=%s", buf); 231 (void) putenv(str_cpu); 232 } else { 233 syslog(LOG_ERR, 234 "can't determine processor type, error: %m"); 235 } 236 } 237 238 (void) rwlock_init(&cache_lock, USYNC_THREAD, NULL); 239 (void) rwlock_init(&rddir_cache_lock, USYNC_THREAD, NULL); 240 241 /* 242 * initialize the name services, use NULL arguments to ensure 243 * we don't initialize the stack of files used in file service 244 */ 245 (void) ns_setup(NULL, NULL); 246 247 /* 248 * set the maximum number of threads to be used. If it succeeds 249 * increase the number of resources the threads need. If the 250 * the resource allocation fails, return the threads value back 251 * to the default value 252 */ 253 if (((rpc_control(RPC_SVC_THRMAX_GET, &prevthreads)) == TRUE) && 254 ((rpc_control(RPC_SVC_THRMAX_SET, &maxthreads)) == TRUE)) { 255 rlset.rlim_max = RESOURCE_FACTOR * maxthreads; 256 rlset.rlim_cur = RESOURCE_FACTOR * maxthreads; 257 if ((setrlimit(RLIMIT_NOFILE, &rlset)) != 0) { 258 syslog(LOG_ERR, 259 "unable to increase system resource limit"); 260 261 /* back off changes to threads */ 262 if ((rpc_control(RPC_SVC_THRMAX_SET, &prevthreads)) 263 == FALSE) { 264 /* 265 * Exit if we have more threads than resources. 266 */ 267 syslog(LOG_ERR, 268 "unable to match threads to system resources"); 269 exit(1); 270 } 271 syslog(LOG_ERR, 272 "decreased threads to match low resources"); 273 } else { 274 /* 275 * Both are successful. Note that setrlimit 276 * allows a max setting of 1024 277 */ 278 if (trace > 3) { 279 trace_prt(1, 280 " maxthreads: %d rlim_max: %d rlim_cur: %d\n", 281 maxthreads, rlset.rlim_max, rlset.rlim_cur); 282 } 283 closefrom(3); 284 } 285 (void) enable_extended_FILE_stdio(-1, -1); 286 } else { 287 syslog(LOG_ERR, 288 "unable to increase threads - continue with default"); 289 } 290 291 /* 292 * establish our lock on the lock file and write our pid to it. 293 * exit if some other process holds the lock, or if there's any 294 * error in writing/locking the file. 295 */ 296 pid = _enter_daemon_lock(AUTOMOUNTD); 297 switch (pid) { 298 case 0: 299 break; 300 case -1: 301 syslog(LOG_ERR, "error locking for %s: %s", AUTOMOUNTD, 302 strerror(errno)); 303 exit(2); 304 default: 305 /* daemon was already running */ 306 exit(0); 307 } 308 309 /* 310 * If we coredump it'll be /core. 311 */ 312 if (chdir("/") < 0) 313 syslog(LOG_ERR, "chdir /: %m"); 314 315 /* 316 * Create cache_cleanup thread 317 */ 318 if (thr_create(NULL, 0, (void *(*)(void *))cache_cleanup, NULL, 319 THR_DETACHED | THR_DAEMON | THR_NEW_LWP, NULL)) { 320 syslog(LOG_ERR, "unable to create cache_cleanup thread"); 321 exit(1); 322 } 323 324 /* other initializations */ 325 (void) rwlock_init(&portmap_cache_lock, USYNC_THREAD, NULL); 326 327 /* on a labeled system, the automounter implements read-down policy */ 328 if (is_system_labeled()) { 329 if ((setpflags(NET_MAC_AWARE, 1) == -1) || 330 (setpflags(NET_MAC_AWARE_INHERIT, 1) == -1)) 331 syslog(LOG_ERR, "ignored failure to set MAC-aware " 332 "mode: %m"); 333 } 334 335 if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) { 336 syslog(LOG_ERR, "unable to set automatic MT mode"); 337 exit(1); 338 } 339 if (svc_create_local_service(autofs_prog, 340 AUTOFS_PROG, AUTOFS_VERS, "netpath", "autofs") == 0) { 341 syslog(LOG_ERR, "unable to create service"); 342 exit(1); 343 } 344 345 (void) signal(SIGHUP, warn_hup); 346 347 svc_run(); 348 syslog(LOG_ERR, "svc_run returned"); 349 return (1); 350 } 351 352 /* 353 * The old automounter supported a SIGHUP 354 * to allow it to resynchronize internal 355 * state with the /etc/mnttab. 356 * This is no longer relevant, but we 357 * need to catch the signal and warn 358 * the user. 359 */ 360 /* ARGSUSED */ 361 static void 362 warn_hup(i) 363 int i; 364 { 365 syslog(LOG_ERR, "SIGHUP received: ignored"); 366 (void) signal(SIGHUP, warn_hup); 367 } 368 369 static void 370 usage() 371 { 372 (void) fprintf(stderr, "Usage: automountd\n" 373 "\t[-T]\t\t(trace requests)\n" 374 "\t[-v]\t\t(verbose error msgs)\n" 375 "\t[-D n=s]\t(define env variable)\n"); 376 exit(1); 377 /* NOTREACHED */ 378 } 379 380 /* 381 * dupreq_nonidemp(struct svc_req *rqstp, SVCXPRT *transp, int res_sz, 382 * bool_t (*xdr_result)(), void (*local_free)()) 383 * check the status of nonidempotent requests in the duplicate request cache. 384 * Get result of done requests and send a reply to the kernel. Return status. 385 */ 386 static int 387 dupreq_nonidemp(struct svc_req *rqstp, SVCXPRT *transp, int res_sz, 388 bool_t (*xdr_result)(), void (*local_free)()) 389 { 390 caddr_t resp_buf; 391 uint_t resp_bufsz; 392 int dupstat; 393 XDR xdrs; 394 caddr_t res; 395 396 dupstat = __svc_vc_dup(rqstp, &resp_buf, &resp_bufsz); 397 switch (dupstat) { 398 case DUP_NEW: 399 break; 400 case DUP_DONE: 401 if (!resp_buf) { 402 if (verbose) { 403 syslog(LOG_ERR, 404 "dupreq_nonidemp: done, no cached result"); 405 } 406 break; 407 } 408 /* buffer contains xdr encoded results - decode and sendreply */ 409 if (verbose) { 410 syslog(LOG_ERR, 411 "dupreq_nonidemp: done, send reply to kernel"); 412 } 413 414 memset((caddr_t)&xdrs, 0, sizeof (XDR)); 415 xdrmem_create(&xdrs, resp_buf, resp_bufsz, XDR_DECODE); 416 417 if ((res = (caddr_t)malloc(res_sz)) == NULL) { 418 syslog(LOG_ERR, "dupreq_nonidemp: out of memory"); 419 xdr_destroy(&xdrs); 420 free(resp_buf); 421 break; 422 } 423 memset(res, 0, res_sz); 424 425 if ((*xdr_result)(&xdrs, res) == FALSE) { 426 if (verbose) 427 syslog(LOG_ERR, 428 "dupreq_nonidemp: cannot xdr decode result"); 429 xdr_destroy(&xdrs); 430 free(resp_buf); 431 free(res); 432 break; 433 } 434 435 if (!svc_sendreply(transp, xdr_result, (caddr_t)res)) { 436 xdr_destroy(&xdrs); 437 free(resp_buf); 438 (void) (*local_free)(res); 439 free(res); 440 svcerr_systemerr(transp); 441 return (DUP_ERROR); 442 } 443 xdr_destroy(&xdrs); 444 free(resp_buf); 445 (void) (*local_free)(res); 446 free(res); 447 break; 448 449 /* all other cases log the case and drop the request */ 450 case DUP_INPROGRESS: 451 if (verbose) { 452 syslog(LOG_ERR, 453 "dupreq_nonidemp: duplicate request in progress\n"); 454 } 455 break; 456 case DUP_DROP: /* should never be called in automountd */ 457 if (verbose) 458 syslog(LOG_ERR, 459 "dupreq_nonidemp: dropped duplicate request error"); 460 break; 461 case DUP_ERROR: /* fall through */ 462 default: 463 if (verbose) 464 syslog(LOG_ERR, 465 "dupreq_nonidemp: duplicate request cache error"); 466 break; 467 } 468 return (dupstat); 469 } 470 471 /* 472 * dupdonereq_nonidemp(struct svc_req *rqstp, caddr_t res, 473 * bool_t (*xdr_result)()) 474 * call the cache to indicate we are done with the nonidempotent request. 475 * xdr_result will write the encoded xdr form of results into the buffer 476 * provided in xdrmem_create. Makes a best effort to update the cache 477 * first with a buffer containing the results, and then with a NULL buffer. 478 * Return status. 479 */ 480 static int 481 dupdonereq_nonidemp(struct svc_req *rqstp, caddr_t res, bool_t (*xdr_result)()) 482 { 483 caddr_t resp_buf; 484 ulong_t resp_bufsz; 485 XDR xdrs; 486 int dupstat; 487 488 /* 489 * create a results buffer and write into the cache 490 * continue with a NULL buffer on errors. 491 */ 492 if ((resp_bufsz = xdr_sizeof(xdr_result, (void *)res)) == 0) { 493 if (verbose) 494 syslog(LOG_ERR, "dupdonereq_nonidemp: xdr error"); 495 resp_buf = NULL; 496 resp_bufsz = 0; 497 } else { 498 if ((resp_buf = (caddr_t)malloc(resp_bufsz)) == NULL) { 499 syslog(LOG_ERR, "dupdonereq_nonidemp: out of memory"); 500 resp_bufsz = 0; 501 } else { 502 memset(resp_buf, 0, resp_bufsz); 503 memset((caddr_t)&xdrs, 0, sizeof (XDR)); 504 xdrmem_create(&xdrs, resp_buf, (uint_t)resp_bufsz, 505 XDR_ENCODE); 506 if ((*xdr_result)(&xdrs, res) == FALSE) { 507 if (verbose) 508 syslog(LOG_ERR, 509 "cannot xdr encode results"); 510 xdr_destroy(&xdrs); 511 free(resp_buf); 512 resp_buf = NULL; 513 resp_bufsz = 0; 514 } else 515 xdr_destroy(&xdrs); 516 } 517 } 518 519 dupstat = __svc_vc_dupdone(rqstp, resp_buf, (uint_t)resp_bufsz, 520 DUP_DONE); 521 if (dupstat == DUP_ERROR) { 522 if (verbose) 523 syslog(LOG_ERR, "dupdonereq_nonidemp: cache error"); 524 if (resp_buf != NULL) { 525 if (verbose) 526 syslog(LOG_ERR, "dupdonereq_nonidemp: retry"); 527 dupstat = __svc_vc_dupdone(rqstp, NULL, 0, DUP_DONE); 528 if ((dupstat == DUP_ERROR) && verbose) 529 syslog(LOG_ERR, 530 "dupdonereq_nonidemp: retry failed"); 531 } 532 } 533 if (resp_buf) 534 free(resp_buf); 535 return (dupstat); 536 } 537 538 /* 539 * dupreq_idemp(struct svc_req *rqstp, SVCXPRT *transp, int res_sz; 540 * bool_t (*xdr_result)(), void (*local_free)()) 541 * check the status of idempotent requests in the duplicate request cache. 542 * treat a idempotent request like a new one if its done, but do workavoids 543 * if its a request in progress. Return status. 544 */ 545 static int 546 dupreq_idemp(struct svc_req *rqstp, SVCXPRT *transp, int res_sz, 547 bool_t (*xdr_result)(), void (*local_free)()) 548 { 549 int dupstat; 550 551 #ifdef lint 552 transp = transp; 553 res_sz = res_sz; 554 local_free = local_free; 555 xdr_result = xdr_result; 556 #endif /* lint */ 557 558 /* 559 * call the cache to check the status of the request. don't care 560 * about results in the cache. 561 */ 562 dupstat = __svc_vc_dup(rqstp, NULL, NULL); 563 switch (dupstat) { 564 case DUP_NEW: 565 break; 566 case DUP_DONE: 567 if (verbose) 568 syslog(LOG_ERR, "dupreq_idemp: done request, redo"); 569 dupstat = DUP_NEW; 570 break; 571 572 /* all other cases log the case and drop the request */ 573 case DUP_INPROGRESS: 574 if (verbose) 575 syslog(LOG_ERR, 576 "dupreq_idemp: duplicate request in progress\n"); 577 break; 578 case DUP_DROP: /* should never be called in automountd */ 579 if (verbose) 580 syslog(LOG_ERR, 581 "dupreq_idemp: dropped duplicate request error"); 582 break; 583 case DUP_ERROR: /* fall through */ 584 default: 585 if (verbose) 586 syslog(LOG_ERR, 587 "dupreq_idemp: duplicate request cache error"); 588 break; 589 } 590 return (dupstat); 591 } 592 593 /* 594 * dupdonereq_idemp(struct svc_req *rqstp, caddr_t res, bool_t (*xdr_result)()) 595 * call the cache to indicate we are done with the idempotent request - we do 596 * this to allow work avoids for in progress requests. don't bother to store 597 * any results in the cache. Return status. 598 */ 599 static int 600 dupdonereq_idemp(struct svc_req *rqstp, caddr_t res, bool_t (*xdr_result)()) 601 { 602 int dupstat; 603 604 #ifdef lint 605 res = res; 606 xdr_result = xdr_result; 607 #endif /* lint */ 608 609 dupstat = __svc_vc_dupdone(rqstp, NULL, (uint_t)0, DUP_DONE); 610 if ((dupstat == DUP_ERROR) && verbose) 611 syslog(LOG_ERR, "dupdonereq_idemp: cannot cache result"); 612 return (dupstat); 613 } 614 615 /* 616 * Returns the UID of the caller 617 */ 618 static uid_t 619 getowner(transp) 620 SVCXPRT *transp; 621 { 622 uid_t uid; 623 624 if (__rpc_get_local_uid(transp, &uid) < 0) { 625 char *err_msg = "Could not get local uid - request ignored\n"; 626 627 if (trace > 1) 628 trace_prt(1, err_msg); 629 if (verbose) 630 pr_msg(err_msg); 631 return (-1); 632 } 633 if (uid != 0) { 634 char *err_msg = 635 "Illegal access attempt by uid=%ld - request ignored\n"; 636 637 if (trace > 1) 638 trace_prt(1, err_msg, uid); 639 pr_msg(err_msg, uid); 640 } 641 return (uid); 642 } 643 644 /* 645 * Each RPC request will automatically spawn a new thread with this 646 * as its entry point. 647 * XXX - the switch statement should be changed to a table of procedures 648 * similar to that used by rfs_dispatch() in uts/common/fs/nfs/nfs_server.c. 649 * duplicate request handling should also be synced with rfs_dispatch(). 650 */ 651 static void 652 autofs_prog(rqstp, transp) 653 struct svc_req *rqstp; 654 register SVCXPRT *transp; 655 { 656 union { 657 autofs_lookupargs autofs_mount_1_arg; 658 autofs_lookupargs autofs_lookup_1_arg; 659 umntrequest autofs_umount_1_arg; 660 autofs_rddirargs autofs_readdir_1_arg; 661 } argument; 662 663 union { 664 autofs_mountres mount_res; 665 autofs_lookupres lookup_res; 666 umntres umount_res; 667 autofs_rddirres readdir_res; 668 } res; 669 670 bool_t (*xdr_argument)(); 671 bool_t (*xdr_result)(); 672 void (*local)(); 673 void (*local_free)(); 674 int (*dup_request)(); 675 int (*dupdone_request)(); 676 677 timenow = time((time_t *)NULL); 678 679 if (rqstp->rq_proc != NULLPROC && getowner(transp) != 0) { 680 /* 681 * Drop request 682 */ 683 return; 684 } 685 686 switch (rqstp->rq_proc) { 687 case NULLPROC: 688 (void) svc_sendreply(transp, xdr_void, (char *)NULL); 689 return; 690 691 #ifdef MALLOC_DEBUG 692 case AUTOFS_DUMP_DEBUG: 693 (void) svc_sendreply(transp, xdr_void, (char *)NULL); 694 check_leaks("/var/tmp/automountd.leak"); 695 return; 696 #endif 697 698 case AUTOFS_LOOKUP: 699 xdr_argument = xdr_autofs_lookupargs; 700 xdr_result = xdr_autofs_lookupres; 701 local = autofs_lookup_1_r; 702 local_free = autofs_lookup_1_free_r; 703 dup_request = dupreq_nonidemp; 704 dupdone_request = dupdonereq_nonidemp; 705 break; 706 707 case AUTOFS_MOUNT: 708 xdr_argument = xdr_autofs_lookupargs; 709 xdr_result = xdr_autofs_mountres; 710 local = autofs_mount_1_r; 711 local_free = autofs_mount_1_free_r; 712 dup_request = dupreq_nonidemp; 713 dupdone_request = dupdonereq_nonidemp; 714 break; 715 716 case AUTOFS_UNMOUNT: 717 xdr_argument = xdr_umntrequest; 718 xdr_result = xdr_umntres; 719 local = autofs_unmount_1_r; 720 local_free = autofs_unmount_1_free_r; 721 dup_request = dupreq_nonidemp; 722 dupdone_request = dupdonereq_nonidemp; 723 break; 724 725 case AUTOFS_READDIR: 726 xdr_argument = xdr_autofs_rddirargs; 727 xdr_result = xdr_autofs_rddirres; 728 local = autofs_readdir_1_r; 729 local_free = autofs_readdir_1_free_r; 730 dup_request = dupreq_idemp; 731 dupdone_request = dupdonereq_idemp; 732 break; 733 734 default: 735 svcerr_noproc(transp); 736 return; 737 } 738 739 740 if ((*dup_request)(rqstp, transp, sizeof (res), xdr_result, 741 local_free) != DUP_NEW) 742 return; 743 744 (void) memset((char *)&argument, 0, sizeof (argument)); 745 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 746 svcerr_decode(transp); 747 return; 748 } 749 750 (void) memset((char *)&res, 0, sizeof (res)); 751 (*local)(&argument, &res, rqstp->rq_clntcred); 752 753 /* update cache with done request results */ 754 (void) (*dupdone_request)(rqstp, (caddr_t)&res, xdr_result); 755 756 if (!svc_sendreply(transp, xdr_result, (caddr_t)&res)) { 757 svcerr_systemerr(transp); 758 } 759 760 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 761 syslog(LOG_ERR, "unable to free arguments"); 762 } 763 764 (*local_free)(&res); 765 766 } 767 768 static void 769 autofs_readdir_1_r(req, res, cred) 770 struct autofs_rddirargs *req; 771 struct autofs_rddirres *res; 772 struct authunix_parms *cred; 773 { 774 if (trace > 0) 775 trace_prt(1, "READDIR REQUEST : %s @ %ld\n", 776 req->rda_map, req->rda_offset); 777 778 (void) do_readdir(req, res, cred); 779 780 if (trace > 0) 781 trace_prt(1, "READDIR REPLY : status=%d\n", res->rd_status); 782 } 783 784 static void 785 autofs_readdir_1_free_r(res) 786 struct autofs_rddirres *res; 787 { 788 if (res->rd_status == AUTOFS_OK) { 789 if (res->rd_rddir.rddir_entries) 790 free(res->rd_rddir.rddir_entries); 791 } 792 } 793 794 /* ARGSUSED */ 795 static void 796 autofs_unmount_1_r(m, res, cred) 797 struct umntrequest *m; 798 struct umntres *res; 799 struct authunix_parms *cred; 800 { 801 struct umntrequest *ul; 802 803 if (trace > 0) { 804 char ctime_buf[CTIME_BUF_LEN]; 805 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) 806 ctime_buf[0] = '\0'; 807 808 trace_prt(1, "UNMOUNT REQUEST: %s", ctime_buf); 809 for (ul = m; ul; ul = ul->next) 810 trace_prt(1, " resource=%s fstype=%s mntpnt=%s" 811 " mntopts=%s %s\n", 812 ul->mntresource, 813 ul->fstype, 814 ul->mntpnt, 815 ul->mntopts, 816 ul->isdirect ? "direct" : "indirect"); 817 } 818 819 res->status = do_unmount1(m); 820 821 if (trace > 0) 822 trace_prt(1, "UNMOUNT REPLY: status=%d\n", res->status); 823 } 824 825 static void 826 autofs_unmount_1_free_r(res) 827 struct umntres *res; 828 { 829 #ifdef lint 830 res = res; 831 #endif /* lint */ 832 } 833 834 static void 835 autofs_lookup_1_r(m, res, cred) 836 struct autofs_lookupargs *m; 837 struct autofs_lookupres *res; 838 struct authunix_parms *cred; 839 { 840 enum autofs_action action; 841 struct linka link; 842 int status; 843 844 if (trace > 0) { 845 char ctime_buf[CTIME_BUF_LEN]; 846 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) 847 ctime_buf[0] = '\0'; 848 849 trace_prt(1, "LOOKUP REQUEST: %s", ctime_buf); 850 trace_prt(1, " name=%s[%s] map=%s opts=%s path=%s direct=%d\n", 851 m->name, m->subdir, m->map, m->opts, 852 m->path, m->isdirect); 853 } 854 855 status = do_lookup1(m->map, m->name, m->subdir, m->opts, m->path, 856 (uint_t)m->isdirect, &action, &link, cred); 857 if (status == 0) { 858 /* 859 * Return action list to kernel. 860 */ 861 res->lu_res = AUTOFS_OK; 862 if ((res->lu_type.action = action) == AUTOFS_LINK_RQ) 863 res->lu_type.lookup_result_type_u.lt_linka = link; 864 } else { 865 /* 866 * Entry not found 867 */ 868 res->lu_res = AUTOFS_NOENT; 869 } 870 res->lu_verbose = verbose; 871 872 if (trace > 0) 873 trace_prt(1, "LOOKUP REPLY : status=%d\n", res->lu_res); 874 } 875 876 static void 877 autofs_lookup_1_free_r(res) 878 struct autofs_lookupres *res; 879 { 880 struct linka link; 881 882 if ((res->lu_res == AUTOFS_OK) && 883 (res->lu_type.action == AUTOFS_LINK_RQ)) { 884 /* 885 * Free link information 886 */ 887 link = res->lu_type.lookup_result_type_u.lt_linka; 888 if (link.dir) 889 free(link.dir); 890 if (link.link) 891 free(link.link); 892 } 893 } 894 895 static void 896 autofs_mount_1_r(m, res, cred) 897 struct autofs_lookupargs *m; 898 struct autofs_mountres *res; 899 struct authunix_parms *cred; 900 { 901 int status; 902 action_list *alp = NULL; 903 904 if (trace > 0) { 905 char ctime_buf[CTIME_BUF_LEN]; 906 if (ctime_r(&timenow, ctime_buf, CTIME_BUF_LEN) == NULL) 907 ctime_buf[0] = '\0'; 908 909 trace_prt(1, "MOUNT REQUEST: %s", ctime_buf); 910 trace_prt(1, " name=%s[%s] map=%s opts=%s path=%s direct=%d\n", 911 m->name, m->subdir, m->map, m->opts, 912 m->path, m->isdirect); 913 } 914 915 status = do_mount1(m->map, m->name, m->subdir, m->opts, m->path, 916 (uint_t)m->isdirect, &alp, cred); 917 if (status != 0) { 918 /* 919 * An error occurred, free action list if allocated. 920 */ 921 if (alp != NULL) { 922 free_action_list(alp); 923 alp = NULL; 924 } 925 } 926 if (alp != NULL) { 927 /* 928 * Return action list to kernel. 929 */ 930 res->mr_type.status = AUTOFS_ACTION; 931 res->mr_type.mount_result_type_u.list = alp; 932 } else { 933 /* 934 * No work to do left for the kernel 935 */ 936 res->mr_type.status = AUTOFS_DONE; 937 res->mr_type.mount_result_type_u.error = status; 938 } 939 res->mr_verbose = verbose; 940 941 if (trace > 0) { 942 switch (res->mr_type.status) { 943 case AUTOFS_ACTION: 944 trace_prt(1, 945 "MOUNT REPLY : status=%d, AUTOFS_ACTION\n", 946 status); 947 break; 948 case AUTOFS_DONE: 949 trace_prt(1, 950 "MOUNT REPLY : status=%d, AUTOFS_DONE\n", 951 status); 952 break; 953 default: 954 trace_prt(1, "MOUNT REPLY : status=%d, UNKNOWN\n", 955 status); 956 } 957 } 958 959 if (status && verbose) { 960 if (m->isdirect) { 961 /* direct mount */ 962 syslog(LOG_ERR, "mount of %s failed", m->path); 963 } else { 964 /* indirect mount */ 965 syslog(LOG_ERR, 966 "mount of %s/%s failed", m->path, m->name); 967 } 968 } 969 } 970 971 static void 972 autofs_mount_1_free_r(res) 973 struct autofs_mountres *res; 974 { 975 if (res->mr_type.status == AUTOFS_ACTION) { 976 if (trace > 2) 977 trace_prt(1, "freeing action list\n"); 978 979 free_action_list(res->mr_type.mount_result_type_u.list); 980 } 981 } 982 983 /* 984 * Used for reporting messages from code shared with automount command. 985 * Formats message into a buffer and calls syslog. 986 * 987 * Print an error. Works like printf (fmt string and variable args) 988 * except that it will subsititute an error message for a "%m" string 989 * (like syslog). 990 */ 991 void 992 pr_msg(const char *fmt, ...) 993 { 994 va_list ap; 995 char fmtbuff[BUFSIZ], buff[BUFSIZ]; 996 const char *p1; 997 char *p2; 998 999 p2 = fmtbuff; 1000 fmt = gettext(fmt); 1001 1002 for (p1 = fmt; *p1; p1++) { 1003 if (*p1 == '%' && *(p1 + 1) == 'm') { 1004 (void) strcpy(p2, strerror(errno)); 1005 p2 += strlen(p2); 1006 p1++; 1007 } else { 1008 *p2++ = *p1; 1009 } 1010 } 1011 if (p2 > fmtbuff && *(p2-1) != '\n') 1012 *p2++ = '\n'; 1013 *p2 = '\0'; 1014 1015 va_start(ap, fmt); 1016 (void) vsprintf(buff, fmtbuff, ap); 1017 va_end(ap); 1018 syslog(LOG_ERR, buff); 1019 } 1020 1021 static void 1022 free_action_list(action_list *alp) 1023 { 1024 action_list *p, *next = NULL; 1025 struct mounta *mp; 1026 1027 for (p = alp; p != NULL; p = next) { 1028 switch (p->action.action) { 1029 case AUTOFS_MOUNT_RQ: 1030 mp = &(p->action.action_list_entry_u.mounta); 1031 /* LINTED pointer alignment */ 1032 free_autofs_args((autofs_args *)mp->dataptr); 1033 mp->dataptr = NULL; 1034 mp->datalen = 0; 1035 free_mounta(mp); 1036 break; 1037 case AUTOFS_LINK_RQ: 1038 syslog(LOG_ERR, 1039 "non AUTOFS_MOUNT_RQ requests not implemented\n"); 1040 break; 1041 default: 1042 syslog(LOG_ERR, 1043 "non AUTOFS_MOUNT_RQ requests not implemented\n"); 1044 break; 1045 } 1046 next = p->next; 1047 free(p); 1048 } 1049 } 1050