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