1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Herb Hasler and Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static const char copyright[] = 39 "@(#) Copyright (c) 1989, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41 #endif /*not lint*/ 42 43 #ifndef lint 44 #if 0 45 static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 46 #endif 47 static const char rcsid[] = 48 "$FreeBSD$"; 49 #endif /*not lint*/ 50 51 #include <sys/param.h> 52 #include <sys/mount.h> 53 #include <sys/stat.h> 54 #include <sys/syslog.h> 55 #include <sys/sysctl.h> 56 57 #include <rpc/rpc.h> 58 #include <rpc/pmap_clnt.h> 59 #ifdef ISO 60 #include <netiso/iso.h> 61 #endif 62 #include <nfs/rpcv2.h> 63 #include <nfs/nfsproto.h> 64 #include <nfs/nfs.h> 65 #include <ufs/ufs/ufsmount.h> 66 #include <msdosfs/msdosfsmount.h> 67 #include <isofs/cd9660/cd9660_mount.h> /* XXX need isofs in include */ 68 69 #include <arpa/inet.h> 70 71 #include <ctype.h> 72 #include <err.h> 73 #include <errno.h> 74 #include <grp.h> 75 #include <netdb.h> 76 #include <pwd.h> 77 #include <signal.h> 78 #include <stdio.h> 79 #include <stdlib.h> 80 #include <string.h> 81 #include <unistd.h> 82 #include "pathnames.h" 83 84 #ifdef DEBUG 85 #include <stdarg.h> 86 #endif 87 88 /* 89 * Structures for keeping the mount list and export list 90 */ 91 struct mountlist { 92 struct mountlist *ml_next; 93 char ml_host[RPCMNT_NAMELEN+1]; 94 char ml_dirp[RPCMNT_PATHLEN+1]; 95 }; 96 97 struct dirlist { 98 struct dirlist *dp_left; 99 struct dirlist *dp_right; 100 int dp_flag; 101 struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 102 char dp_dirp[1]; /* Actually malloc'd to size of dir */ 103 }; 104 /* dp_flag bits */ 105 #define DP_DEFSET 0x1 106 #define DP_HOSTSET 0x2 107 #define DP_KERB 0x4 108 109 struct exportlist { 110 struct exportlist *ex_next; 111 struct dirlist *ex_dirl; 112 struct dirlist *ex_defdir; 113 int ex_flag; 114 fsid_t ex_fs; 115 char *ex_fsdir; 116 char *ex_indexfile; 117 }; 118 /* ex_flag bits */ 119 #define EX_LINKED 0x1 120 121 struct netmsk { 122 u_int32_t nt_net; 123 u_int32_t nt_mask; 124 char *nt_name; 125 }; 126 127 union grouptypes { 128 struct hostent *gt_hostent; 129 struct netmsk gt_net; 130 #ifdef ISO 131 struct sockaddr_iso *gt_isoaddr; 132 #endif 133 }; 134 135 struct grouplist { 136 int gr_type; 137 union grouptypes gr_ptr; 138 struct grouplist *gr_next; 139 }; 140 /* Group types */ 141 #define GT_NULL 0x0 142 #define GT_HOST 0x1 143 #define GT_NET 0x2 144 #define GT_ISO 0x4 145 #define GT_IGNORE 0x5 146 147 struct hostlist { 148 int ht_flag; /* Uses DP_xx bits */ 149 struct grouplist *ht_grp; 150 struct hostlist *ht_next; 151 }; 152 153 struct fhreturn { 154 int fhr_flag; 155 int fhr_vers; 156 nfsfh_t fhr_fh; 157 }; 158 159 /* Global defs */ 160 char *add_expdir __P((struct dirlist **, char *, int)); 161 void add_dlist __P((struct dirlist **, struct dirlist *, 162 struct grouplist *, int)); 163 void add_mlist __P((char *, char *)); 164 int check_dirpath __P((char *)); 165 int check_options __P((struct dirlist *)); 166 int chk_host __P((struct dirlist *, u_int32_t, int *, int *)); 167 void del_mlist __P((char *, char *)); 168 struct dirlist *dirp_search __P((struct dirlist *, char *)); 169 int do_mount __P((struct exportlist *, struct grouplist *, int, 170 struct ucred *, char *, int, struct statfs *)); 171 int do_opt __P((char **, char **, struct exportlist *, struct grouplist *, 172 int *, int *, struct ucred *)); 173 struct exportlist *ex_search __P((fsid_t *)); 174 struct exportlist *get_exp __P((void)); 175 void free_dir __P((struct dirlist *)); 176 void free_exp __P((struct exportlist *)); 177 void free_grp __P((struct grouplist *)); 178 void free_host __P((struct hostlist *)); 179 void get_exportlist __P((void)); 180 int get_host __P((char *, struct grouplist *, struct grouplist *)); 181 int get_num __P((char *)); 182 struct hostlist *get_ht __P((void)); 183 int get_line __P((void)); 184 void get_mountlist __P((void)); 185 int get_net __P((char *, struct netmsk *, int)); 186 void getexp_err __P((struct exportlist *, struct grouplist *)); 187 struct grouplist *get_grp __P((void)); 188 void hang_dirp __P((struct dirlist *, struct grouplist *, 189 struct exportlist *, int)); 190 void mntsrv __P((struct svc_req *, SVCXPRT *)); 191 void nextfield __P((char **, char **)); 192 void out_of_mem __P((void)); 193 void parsecred __P((char *, struct ucred *)); 194 int put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *)); 195 int scan_tree __P((struct dirlist *, u_int32_t)); 196 void send_umntall __P((void)); 197 int umntall_each __P((caddr_t, struct sockaddr_in *)); 198 static void usage __P((void)); 199 int xdr_dir __P((XDR *, char *)); 200 int xdr_explist __P((XDR *, caddr_t)); 201 int xdr_fhs __P((XDR *, caddr_t)); 202 int xdr_mlist __P((XDR *, caddr_t)); 203 204 /* C library */ 205 int getnetgrent(); 206 void endnetgrent(); 207 void setnetgrent(); 208 209 #ifdef ISO 210 struct iso_addr *iso_addr(); 211 #endif 212 213 struct exportlist *exphead; 214 struct mountlist *mlhead; 215 struct grouplist *grphead; 216 char exname[MAXPATHLEN]; 217 struct ucred def_anon = { 218 1, 219 (uid_t) -2, 220 1, 221 { (gid_t) -2 } 222 }; 223 int force_v2 = 0; 224 int resvport_only = 1; 225 int dir_only = 1; 226 int log = 0; 227 int opt_flags; 228 /* Bits for above */ 229 #define OP_MAPROOT 0x01 230 #define OP_MAPALL 0x02 231 #define OP_KERB 0x04 232 #define OP_MASK 0x08 233 #define OP_NET 0x10 234 #define OP_ISO 0x20 235 #define OP_ALLDIRS 0x40 236 237 #ifdef DEBUG 238 int debug = 1; 239 void SYSLOG __P((int, const char *, ...)); 240 #define syslog SYSLOG 241 #else 242 int debug = 0; 243 #endif 244 245 /* 246 * Mountd server for NFS mount protocol as described in: 247 * NFS: Network File System Protocol Specification, RFC1094, Appendix A 248 * The optional arguments are the exports file name 249 * default: _PATH_EXPORTS 250 * and "-n" to allow nonroot mount. 251 */ 252 int 253 main(argc, argv) 254 int argc; 255 char **argv; 256 { 257 SVCXPRT *udptransp, *tcptransp; 258 int c, error, mib[3]; 259 struct vfsconf vfc; 260 261 error = getvfsbyname("nfs", &vfc); 262 if (error && vfsisloadable("nfs")) { 263 if(vfsload("nfs")) 264 err(1, "vfsload(nfs)"); 265 endvfsent(); /* flush cache */ 266 error = getvfsbyname("nfs", &vfc); 267 } 268 if (error) 269 errx(1, "NFS support is not available in the running kernel"); 270 271 while ((c = getopt(argc, argv, "2dlnr")) != -1) 272 switch (c) { 273 case '2': 274 force_v2 = 1; 275 break; 276 case 'n': 277 resvport_only = 0; 278 break; 279 case 'r': 280 dir_only = 0; 281 break; 282 case 'd': 283 debug = debug ? 0 : 1; 284 break; 285 case 'l': 286 log = 1; 287 break; 288 default: 289 usage(); 290 }; 291 argc -= optind; 292 argv += optind; 293 grphead = (struct grouplist *)NULL; 294 exphead = (struct exportlist *)NULL; 295 mlhead = (struct mountlist *)NULL; 296 if (argc == 1) { 297 strncpy(exname, *argv, MAXPATHLEN-1); 298 exname[MAXPATHLEN-1] = '\0'; 299 } else 300 strcpy(exname, _PATH_EXPORTS); 301 openlog("mountd", LOG_PID, LOG_DAEMON); 302 if (debug) 303 warnx("getting export list"); 304 get_exportlist(); 305 if (debug) 306 warnx("getting mount list"); 307 get_mountlist(); 308 if (debug) 309 warnx("here we go"); 310 if (debug == 0) { 311 daemon(0, 0); 312 signal(SIGINT, SIG_IGN); 313 signal(SIGQUIT, SIG_IGN); 314 } 315 signal(SIGHUP, (void (*) __P((int))) get_exportlist); 316 signal(SIGTERM, (void (*) __P((int))) send_umntall); 317 { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 318 if (pidfile != NULL) { 319 fprintf(pidfile, "%d\n", getpid()); 320 fclose(pidfile); 321 } 322 } 323 if (!resvport_only) { 324 mib[0] = CTL_VFS; 325 mib[1] = vfc.vfc_typenum; 326 mib[2] = NFS_NFSPRIVPORT; 327 if (sysctl(mib, 3, NULL, NULL, &resvport_only, 328 sizeof(resvport_only)) != 0 && errno != ENOENT) { 329 syslog(LOG_ERR, "sysctl: %m"); 330 exit(1); 331 } 332 } 333 if ((udptransp = svcudp_create(RPC_ANYSOCK)) == NULL || 334 (tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) { 335 syslog(LOG_ERR, "can't create socket"); 336 exit(1); 337 } 338 pmap_unset(RPCPROG_MNT, 1); 339 pmap_unset(RPCPROG_MNT, 3); 340 if (!force_v2) 341 if (!svc_register(udptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_UDP) || 342 !svc_register(tcptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_TCP)) { 343 syslog(LOG_ERR, "can't register mount"); 344 exit(1); 345 } 346 if (!svc_register(udptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_UDP) || 347 !svc_register(tcptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_TCP)) { 348 syslog(LOG_ERR, "can't register mount"); 349 exit(1); 350 } 351 svc_run(); 352 syslog(LOG_ERR, "mountd died"); 353 exit(1); 354 } 355 356 static void 357 usage() 358 { 359 fprintf(stderr, 360 "usage: mountd [-2] [-d] [-l] [-n] [-r] [export_file]\n"); 361 exit(1); 362 } 363 364 /* 365 * The mount rpc service 366 */ 367 void 368 mntsrv(rqstp, transp) 369 struct svc_req *rqstp; 370 SVCXPRT *transp; 371 { 372 struct exportlist *ep; 373 struct dirlist *dp; 374 struct fhreturn fhr; 375 struct stat stb; 376 struct statfs fsb; 377 struct hostent *hp; 378 struct in_addr saddrin; 379 u_int32_t saddr; 380 u_short sport; 381 char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 382 int bad = 0, defset, hostset; 383 sigset_t sighup_mask; 384 385 sigemptyset(&sighup_mask); 386 sigaddset(&sighup_mask, SIGHUP); 387 saddr = transp->xp_raddr.sin_addr.s_addr; 388 saddrin = transp->xp_raddr.sin_addr; 389 sport = ntohs(transp->xp_raddr.sin_port); 390 hp = (struct hostent *)NULL; 391 switch (rqstp->rq_proc) { 392 case NULLPROC: 393 if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 394 syslog(LOG_ERR, "can't send reply"); 395 return; 396 case RPCMNT_MOUNT: 397 if (sport >= IPPORT_RESERVED && resvport_only) { 398 syslog(LOG_NOTICE, 399 "mount request from %s from unprivileged port", 400 inet_ntoa(saddrin)); 401 svcerr_weakauth(transp); 402 return; 403 } 404 if (!svc_getargs(transp, xdr_dir, rpcpath)) { 405 syslog(LOG_NOTICE, "undecodable mount request from %s", 406 inet_ntoa(saddrin)); 407 svcerr_decode(transp); 408 return; 409 } 410 411 /* 412 * Get the real pathname and make sure it is a directory 413 * or a regular file if the -r option was specified 414 * and it exists. 415 */ 416 if (realpath(rpcpath, dirpath) == NULL || 417 stat(dirpath, &stb) < 0 || 418 (!S_ISDIR(stb.st_mode) && 419 (dir_only || !S_ISREG(stb.st_mode))) || 420 statfs(dirpath, &fsb) < 0) { 421 chdir("/"); /* Just in case realpath doesn't */ 422 syslog(LOG_NOTICE, 423 "mount request from %s for non existent path %s", 424 inet_ntoa(saddrin), dirpath); 425 if (debug) 426 warnx("stat failed on %s", dirpath); 427 bad = ENOENT; /* We will send error reply later */ 428 } 429 430 /* Check in the exports list */ 431 sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 432 ep = ex_search(&fsb.f_fsid); 433 hostset = defset = 0; 434 if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 435 ((dp = dirp_search(ep->ex_dirl, dirpath)) && 436 chk_host(dp, saddr, &defset, &hostset)) || 437 (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 438 scan_tree(ep->ex_dirl, saddr) == 0))) { 439 if (bad) { 440 if (!svc_sendreply(transp, xdr_long, 441 (caddr_t)&bad)) 442 syslog(LOG_ERR, "can't send reply"); 443 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 444 return; 445 } 446 if (hostset & DP_HOSTSET) 447 fhr.fhr_flag = hostset; 448 else 449 fhr.fhr_flag = defset; 450 fhr.fhr_vers = rqstp->rq_vers; 451 /* Get the file handle */ 452 memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 453 if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 454 bad = errno; 455 syslog(LOG_ERR, "can't get fh for %s", dirpath); 456 if (!svc_sendreply(transp, xdr_long, 457 (caddr_t)&bad)) 458 syslog(LOG_ERR, "can't send reply"); 459 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 460 return; 461 } 462 if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr)) 463 syslog(LOG_ERR, "can't send reply"); 464 if (hp == NULL) 465 hp = gethostbyaddr((caddr_t)&saddr, 466 sizeof(saddr), AF_INET); 467 if (hp) 468 add_mlist(hp->h_name, dirpath); 469 else 470 add_mlist(inet_ntoa(saddrin), 471 dirpath); 472 if (debug) 473 warnx("mount successful"); 474 if (log) 475 syslog(LOG_NOTICE, 476 "mount request succeeded from %s for %s", 477 inet_ntoa(saddrin), dirpath); 478 } else { 479 bad = EACCES; 480 syslog(LOG_NOTICE, 481 "mount request denied from %s for %s", 482 inet_ntoa(saddrin), dirpath); 483 } 484 485 if (bad && !svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 486 syslog(LOG_ERR, "can't send reply"); 487 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 488 return; 489 case RPCMNT_DUMP: 490 if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL)) 491 syslog(LOG_ERR, "can't send reply"); 492 else if (log) 493 syslog(LOG_NOTICE, 494 "dump request succeeded from %s", 495 inet_ntoa(saddrin)); 496 return; 497 case RPCMNT_UMOUNT: 498 if (sport >= IPPORT_RESERVED && resvport_only) { 499 syslog(LOG_NOTICE, 500 "umount request from %s from unprivileged port", 501 inet_ntoa(saddrin)); 502 svcerr_weakauth(transp); 503 return; 504 } 505 if (!svc_getargs(transp, xdr_dir, rpcpath)) { 506 syslog(LOG_NOTICE, "undecodable umount request from %s", 507 inet_ntoa(saddrin)); 508 svcerr_decode(transp); 509 return; 510 } 511 if (realpath(rpcpath, dirpath) == NULL) { 512 syslog(LOG_NOTICE, "umount request from %s " 513 "for non existent path %s", 514 inet_ntoa(saddrin), dirpath); 515 } 516 if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 517 syslog(LOG_ERR, "can't send reply"); 518 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 519 if (hp) 520 del_mlist(hp->h_name, dirpath); 521 del_mlist(inet_ntoa(saddrin), dirpath); 522 if (log) 523 syslog(LOG_NOTICE, 524 "umount request succeeded from %s for %s", 525 inet_ntoa(saddrin), dirpath); 526 return; 527 case RPCMNT_UMNTALL: 528 if (sport >= IPPORT_RESERVED && resvport_only) { 529 syslog(LOG_NOTICE, 530 "umountall request from %s from unprivileged port", 531 inet_ntoa(saddrin)); 532 svcerr_weakauth(transp); 533 return; 534 } 535 if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 536 syslog(LOG_ERR, "can't send reply"); 537 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 538 if (hp) 539 del_mlist(hp->h_name, (char *)NULL); 540 del_mlist(inet_ntoa(saddrin), (char *)NULL); 541 if (log) 542 syslog(LOG_NOTICE, 543 "umountall request succeeded from %s", 544 inet_ntoa(saddrin)); 545 return; 546 case RPCMNT_EXPORT: 547 if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL)) 548 syslog(LOG_ERR, "can't send reply"); 549 if (log) 550 syslog(LOG_NOTICE, 551 "export request succeeded from %s", 552 inet_ntoa(saddrin)); 553 return; 554 default: 555 svcerr_noproc(transp); 556 return; 557 } 558 } 559 560 /* 561 * Xdr conversion for a dirpath string 562 */ 563 int 564 xdr_dir(xdrsp, dirp) 565 XDR *xdrsp; 566 char *dirp; 567 { 568 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 569 } 570 571 /* 572 * Xdr routine to generate file handle reply 573 */ 574 int 575 xdr_fhs(xdrsp, cp) 576 XDR *xdrsp; 577 caddr_t cp; 578 { 579 register struct fhreturn *fhrp = (struct fhreturn *)cp; 580 u_long ok = 0, len, auth; 581 582 if (!xdr_long(xdrsp, &ok)) 583 return (0); 584 switch (fhrp->fhr_vers) { 585 case 1: 586 return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 587 case 3: 588 len = NFSX_V3FH; 589 if (!xdr_long(xdrsp, &len)) 590 return (0); 591 if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 592 return (0); 593 if (fhrp->fhr_flag & DP_KERB) 594 auth = RPCAUTH_KERB4; 595 else 596 auth = RPCAUTH_UNIX; 597 len = 1; 598 if (!xdr_long(xdrsp, &len)) 599 return (0); 600 return (xdr_long(xdrsp, &auth)); 601 }; 602 return (0); 603 } 604 605 int 606 xdr_mlist(xdrsp, cp) 607 XDR *xdrsp; 608 caddr_t cp; 609 { 610 struct mountlist *mlp; 611 int true = 1; 612 int false = 0; 613 char *strp; 614 615 mlp = mlhead; 616 while (mlp) { 617 if (!xdr_bool(xdrsp, &true)) 618 return (0); 619 strp = &mlp->ml_host[0]; 620 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 621 return (0); 622 strp = &mlp->ml_dirp[0]; 623 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 624 return (0); 625 mlp = mlp->ml_next; 626 } 627 if (!xdr_bool(xdrsp, &false)) 628 return (0); 629 return (1); 630 } 631 632 /* 633 * Xdr conversion for export list 634 */ 635 int 636 xdr_explist(xdrsp, cp) 637 XDR *xdrsp; 638 caddr_t cp; 639 { 640 struct exportlist *ep; 641 int false = 0; 642 int putdef; 643 sigset_t sighup_mask; 644 645 sigemptyset(&sighup_mask); 646 sigaddset(&sighup_mask, SIGHUP); 647 sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 648 ep = exphead; 649 while (ep) { 650 putdef = 0; 651 if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 652 goto errout; 653 if (ep->ex_defdir && putdef == 0 && 654 put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 655 &putdef)) 656 goto errout; 657 ep = ep->ex_next; 658 } 659 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 660 if (!xdr_bool(xdrsp, &false)) 661 return (0); 662 return (1); 663 errout: 664 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 665 return (0); 666 } 667 668 /* 669 * Called from xdr_explist() to traverse the tree and export the 670 * directory paths. 671 */ 672 int 673 put_exlist(dp, xdrsp, adp, putdefp) 674 struct dirlist *dp; 675 XDR *xdrsp; 676 struct dirlist *adp; 677 int *putdefp; 678 { 679 struct grouplist *grp; 680 struct hostlist *hp; 681 int true = 1; 682 int false = 0; 683 int gotalldir = 0; 684 char *strp; 685 686 if (dp) { 687 if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) 688 return (1); 689 if (!xdr_bool(xdrsp, &true)) 690 return (1); 691 strp = dp->dp_dirp; 692 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 693 return (1); 694 if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 695 gotalldir = 1; 696 *putdefp = 1; 697 } 698 if ((dp->dp_flag & DP_DEFSET) == 0 && 699 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 700 hp = dp->dp_hosts; 701 while (hp) { 702 grp = hp->ht_grp; 703 if (grp->gr_type == GT_HOST) { 704 if (!xdr_bool(xdrsp, &true)) 705 return (1); 706 strp = grp->gr_ptr.gt_hostent->h_name; 707 if (!xdr_string(xdrsp, &strp, 708 RPCMNT_NAMELEN)) 709 return (1); 710 } else if (grp->gr_type == GT_NET) { 711 if (!xdr_bool(xdrsp, &true)) 712 return (1); 713 strp = grp->gr_ptr.gt_net.nt_name; 714 if (!xdr_string(xdrsp, &strp, 715 RPCMNT_NAMELEN)) 716 return (1); 717 } 718 hp = hp->ht_next; 719 if (gotalldir && hp == (struct hostlist *)NULL) { 720 hp = adp->dp_hosts; 721 gotalldir = 0; 722 } 723 } 724 } 725 if (!xdr_bool(xdrsp, &false)) 726 return (1); 727 if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) 728 return (1); 729 } 730 return (0); 731 } 732 733 #define LINESIZ 10240 734 char line[LINESIZ]; 735 FILE *exp_file; 736 737 /* 738 * Get the export list 739 */ 740 void 741 get_exportlist() 742 { 743 struct exportlist *ep, *ep2; 744 struct grouplist *grp, *tgrp; 745 struct exportlist **epp; 746 struct dirlist *dirhead; 747 struct statfs fsb, *fsp; 748 struct hostent *hpe; 749 struct ucred anon; 750 char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 751 int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; 752 753 dirp = NULL; 754 dirplen = 0; 755 756 /* 757 * First, get rid of the old list 758 */ 759 ep = exphead; 760 while (ep) { 761 ep2 = ep; 762 ep = ep->ex_next; 763 free_exp(ep2); 764 } 765 exphead = (struct exportlist *)NULL; 766 767 grp = grphead; 768 while (grp) { 769 tgrp = grp; 770 grp = grp->gr_next; 771 free_grp(tgrp); 772 } 773 grphead = (struct grouplist *)NULL; 774 775 /* 776 * And delete exports that are in the kernel for all local 777 * file systems. 778 * XXX: Should know how to handle all local exportable file systems 779 * instead of just "ufs". 780 */ 781 num = getmntinfo(&fsp, MNT_NOWAIT); 782 for (i = 0; i < num; i++) { 783 union { 784 struct ufs_args ua; 785 struct iso_args ia; 786 struct mfs_args ma; 787 struct msdosfs_args da; 788 } targs; 789 790 if (!strcmp(fsp->f_fstypename, "mfs") || 791 !strcmp(fsp->f_fstypename, "ufs") || 792 !strcmp(fsp->f_fstypename, "msdos") || 793 !strcmp(fsp->f_fstypename, "cd9660")) { 794 targs.ua.fspec = NULL; 795 targs.ua.export.ex_flags = MNT_DELEXPORT; 796 if (mount(fsp->f_fstypename, fsp->f_mntonname, 797 fsp->f_flags | MNT_UPDATE, 798 (caddr_t)&targs) < 0) 799 syslog(LOG_ERR, "can't delete exports for %s", 800 fsp->f_mntonname); 801 } 802 fsp++; 803 } 804 805 /* 806 * Read in the exports file and build the list, calling 807 * mount() as we go along to push the export rules into the kernel. 808 */ 809 if ((exp_file = fopen(exname, "r")) == NULL) { 810 syslog(LOG_ERR, "can't open %s", exname); 811 exit(2); 812 } 813 dirhead = (struct dirlist *)NULL; 814 while (get_line()) { 815 if (debug) 816 warnx("got line %s", line); 817 cp = line; 818 nextfield(&cp, &endcp); 819 if (*cp == '#') 820 goto nextline; 821 822 /* 823 * Set defaults. 824 */ 825 has_host = FALSE; 826 anon = def_anon; 827 exflags = MNT_EXPORTED; 828 got_nondir = 0; 829 opt_flags = 0; 830 ep = (struct exportlist *)NULL; 831 832 /* 833 * Create new exports list entry 834 */ 835 len = endcp-cp; 836 tgrp = grp = get_grp(); 837 while (len > 0) { 838 if (len > RPCMNT_NAMELEN) { 839 getexp_err(ep, tgrp); 840 goto nextline; 841 } 842 if (*cp == '-') { 843 if (ep == (struct exportlist *)NULL) { 844 getexp_err(ep, tgrp); 845 goto nextline; 846 } 847 if (debug) 848 warnx("doing opt %s", cp); 849 got_nondir = 1; 850 if (do_opt(&cp, &endcp, ep, grp, &has_host, 851 &exflags, &anon)) { 852 getexp_err(ep, tgrp); 853 goto nextline; 854 } 855 } else if (*cp == '/') { 856 savedc = *endcp; 857 *endcp = '\0'; 858 if (check_dirpath(cp) && 859 statfs(cp, &fsb) >= 0) { 860 if (got_nondir) { 861 syslog(LOG_ERR, "dirs must be first"); 862 getexp_err(ep, tgrp); 863 goto nextline; 864 } 865 if (ep) { 866 if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 867 ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 868 getexp_err(ep, tgrp); 869 goto nextline; 870 } 871 } else { 872 /* 873 * See if this directory is already 874 * in the list. 875 */ 876 ep = ex_search(&fsb.f_fsid); 877 if (ep == (struct exportlist *)NULL) { 878 ep = get_exp(); 879 ep->ex_fs = fsb.f_fsid; 880 ep->ex_fsdir = (char *) 881 malloc(strlen(fsb.f_mntonname) + 1); 882 if (ep->ex_fsdir) 883 strcpy(ep->ex_fsdir, 884 fsb.f_mntonname); 885 else 886 out_of_mem(); 887 if (debug) 888 warnx("making new ep fs=0x%x,0x%x", 889 fsb.f_fsid.val[0], 890 fsb.f_fsid.val[1]); 891 } else if (debug) 892 warnx("found ep fs=0x%x,0x%x", 893 fsb.f_fsid.val[0], 894 fsb.f_fsid.val[1]); 895 } 896 897 /* 898 * Add dirpath to export mount point. 899 */ 900 dirp = add_expdir(&dirhead, cp, len); 901 dirplen = len; 902 } else { 903 getexp_err(ep, tgrp); 904 goto nextline; 905 } 906 *endcp = savedc; 907 } else { 908 savedc = *endcp; 909 *endcp = '\0'; 910 got_nondir = 1; 911 if (ep == (struct exportlist *)NULL) { 912 getexp_err(ep, tgrp); 913 goto nextline; 914 } 915 916 /* 917 * Get the host or netgroup. 918 */ 919 setnetgrent(cp); 920 netgrp = getnetgrent(&hst, &usr, &dom); 921 do { 922 if (has_host) { 923 grp->gr_next = get_grp(); 924 grp = grp->gr_next; 925 } 926 if (netgrp) { 927 if (hst == 0) { 928 syslog(LOG_ERR, 929 "null hostname in netgroup %s, skipping", cp); 930 grp->gr_type = GT_IGNORE; 931 } else if (get_host(hst, grp, tgrp)) { 932 syslog(LOG_ERR, 933 "bad host %s in netgroup %s, skipping", hst, cp); 934 grp->gr_type = GT_IGNORE; 935 } 936 } else if (get_host(cp, grp, tgrp)) { 937 syslog(LOG_ERR, "bad host %s, skipping", cp); 938 grp->gr_type = GT_IGNORE; 939 } 940 has_host = TRUE; 941 } while (netgrp && getnetgrent(&hst, &usr, &dom)); 942 endnetgrent(); 943 *endcp = savedc; 944 } 945 cp = endcp; 946 nextfield(&cp, &endcp); 947 len = endcp - cp; 948 } 949 if (check_options(dirhead)) { 950 getexp_err(ep, tgrp); 951 goto nextline; 952 } 953 if (!has_host) { 954 grp->gr_type = GT_HOST; 955 if (debug) 956 warnx("adding a default entry"); 957 /* add a default group and make the grp list NULL */ 958 hpe = (struct hostent *)malloc(sizeof(struct hostent)); 959 if (hpe == (struct hostent *)NULL) 960 out_of_mem(); 961 hpe->h_name = strdup("Default"); 962 hpe->h_addrtype = AF_INET; 963 hpe->h_length = sizeof (u_int32_t); 964 hpe->h_addr_list = (char **)NULL; 965 grp->gr_ptr.gt_hostent = hpe; 966 967 /* 968 * Don't allow a network export coincide with a list of 969 * host(s) on the same line. 970 */ 971 } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 972 getexp_err(ep, tgrp); 973 goto nextline; 974 975 /* 976 * If an export list was specified on this line, make sure 977 * that we have at least one valid entry, otherwise skip it. 978 */ 979 } else { 980 grp = tgrp; 981 while (grp && grp->gr_type == GT_IGNORE) 982 grp = grp->gr_next; 983 if (! grp) { 984 getexp_err(ep, tgrp); 985 goto nextline; 986 } 987 } 988 989 /* 990 * Loop through hosts, pushing the exports into the kernel. 991 * After loop, tgrp points to the start of the list and 992 * grp points to the last entry in the list. 993 */ 994 grp = tgrp; 995 do { 996 if (do_mount(ep, grp, exflags, &anon, dirp, 997 dirplen, &fsb)) { 998 getexp_err(ep, tgrp); 999 goto nextline; 1000 } 1001 } while (grp->gr_next && (grp = grp->gr_next)); 1002 1003 /* 1004 * Success. Update the data structures. 1005 */ 1006 if (has_host) { 1007 hang_dirp(dirhead, tgrp, ep, opt_flags); 1008 grp->gr_next = grphead; 1009 grphead = tgrp; 1010 } else { 1011 hang_dirp(dirhead, (struct grouplist *)NULL, ep, 1012 opt_flags); 1013 free_grp(grp); 1014 } 1015 dirhead = (struct dirlist *)NULL; 1016 if ((ep->ex_flag & EX_LINKED) == 0) { 1017 ep2 = exphead; 1018 epp = &exphead; 1019 1020 /* 1021 * Insert in the list in alphabetical order. 1022 */ 1023 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 1024 epp = &ep2->ex_next; 1025 ep2 = ep2->ex_next; 1026 } 1027 if (ep2) 1028 ep->ex_next = ep2; 1029 *epp = ep; 1030 ep->ex_flag |= EX_LINKED; 1031 } 1032 nextline: 1033 if (dirhead) { 1034 free_dir(dirhead); 1035 dirhead = (struct dirlist *)NULL; 1036 } 1037 } 1038 fclose(exp_file); 1039 } 1040 1041 /* 1042 * Allocate an export list element 1043 */ 1044 struct exportlist * 1045 get_exp() 1046 { 1047 struct exportlist *ep; 1048 1049 ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 1050 if (ep == (struct exportlist *)NULL) 1051 out_of_mem(); 1052 memset(ep, 0, sizeof(struct exportlist)); 1053 return (ep); 1054 } 1055 1056 /* 1057 * Allocate a group list element 1058 */ 1059 struct grouplist * 1060 get_grp() 1061 { 1062 struct grouplist *gp; 1063 1064 gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 1065 if (gp == (struct grouplist *)NULL) 1066 out_of_mem(); 1067 memset(gp, 0, sizeof(struct grouplist)); 1068 return (gp); 1069 } 1070 1071 /* 1072 * Clean up upon an error in get_exportlist(). 1073 */ 1074 void 1075 getexp_err(ep, grp) 1076 struct exportlist *ep; 1077 struct grouplist *grp; 1078 { 1079 struct grouplist *tgrp; 1080 1081 syslog(LOG_ERR, "bad exports list line %s", line); 1082 if (ep && (ep->ex_flag & EX_LINKED) == 0) 1083 free_exp(ep); 1084 while (grp) { 1085 tgrp = grp; 1086 grp = grp->gr_next; 1087 free_grp(tgrp); 1088 } 1089 } 1090 1091 /* 1092 * Search the export list for a matching fs. 1093 */ 1094 struct exportlist * 1095 ex_search(fsid) 1096 fsid_t *fsid; 1097 { 1098 struct exportlist *ep; 1099 1100 ep = exphead; 1101 while (ep) { 1102 if (ep->ex_fs.val[0] == fsid->val[0] && 1103 ep->ex_fs.val[1] == fsid->val[1]) 1104 return (ep); 1105 ep = ep->ex_next; 1106 } 1107 return (ep); 1108 } 1109 1110 /* 1111 * Add a directory path to the list. 1112 */ 1113 char * 1114 add_expdir(dpp, cp, len) 1115 struct dirlist **dpp; 1116 char *cp; 1117 int len; 1118 { 1119 struct dirlist *dp; 1120 1121 dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 1122 if (dp == (struct dirlist *)NULL) 1123 out_of_mem(); 1124 dp->dp_left = *dpp; 1125 dp->dp_right = (struct dirlist *)NULL; 1126 dp->dp_flag = 0; 1127 dp->dp_hosts = (struct hostlist *)NULL; 1128 strcpy(dp->dp_dirp, cp); 1129 *dpp = dp; 1130 return (dp->dp_dirp); 1131 } 1132 1133 /* 1134 * Hang the dir list element off the dirpath binary tree as required 1135 * and update the entry for host. 1136 */ 1137 void 1138 hang_dirp(dp, grp, ep, flags) 1139 struct dirlist *dp; 1140 struct grouplist *grp; 1141 struct exportlist *ep; 1142 int flags; 1143 { 1144 struct hostlist *hp; 1145 struct dirlist *dp2; 1146 1147 if (flags & OP_ALLDIRS) { 1148 if (ep->ex_defdir) 1149 free((caddr_t)dp); 1150 else 1151 ep->ex_defdir = dp; 1152 if (grp == (struct grouplist *)NULL) { 1153 ep->ex_defdir->dp_flag |= DP_DEFSET; 1154 if (flags & OP_KERB) 1155 ep->ex_defdir->dp_flag |= DP_KERB; 1156 } else while (grp) { 1157 hp = get_ht(); 1158 if (flags & OP_KERB) 1159 hp->ht_flag |= DP_KERB; 1160 hp->ht_grp = grp; 1161 hp->ht_next = ep->ex_defdir->dp_hosts; 1162 ep->ex_defdir->dp_hosts = hp; 1163 grp = grp->gr_next; 1164 } 1165 } else { 1166 1167 /* 1168 * Loop through the directories adding them to the tree. 1169 */ 1170 while (dp) { 1171 dp2 = dp->dp_left; 1172 add_dlist(&ep->ex_dirl, dp, grp, flags); 1173 dp = dp2; 1174 } 1175 } 1176 } 1177 1178 /* 1179 * Traverse the binary tree either updating a node that is already there 1180 * for the new directory or adding the new node. 1181 */ 1182 void 1183 add_dlist(dpp, newdp, grp, flags) 1184 struct dirlist **dpp; 1185 struct dirlist *newdp; 1186 struct grouplist *grp; 1187 int flags; 1188 { 1189 struct dirlist *dp; 1190 struct hostlist *hp; 1191 int cmp; 1192 1193 dp = *dpp; 1194 if (dp) { 1195 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 1196 if (cmp > 0) { 1197 add_dlist(&dp->dp_left, newdp, grp, flags); 1198 return; 1199 } else if (cmp < 0) { 1200 add_dlist(&dp->dp_right, newdp, grp, flags); 1201 return; 1202 } else 1203 free((caddr_t)newdp); 1204 } else { 1205 dp = newdp; 1206 dp->dp_left = (struct dirlist *)NULL; 1207 *dpp = dp; 1208 } 1209 if (grp) { 1210 1211 /* 1212 * Hang all of the host(s) off of the directory point. 1213 */ 1214 do { 1215 hp = get_ht(); 1216 if (flags & OP_KERB) 1217 hp->ht_flag |= DP_KERB; 1218 hp->ht_grp = grp; 1219 hp->ht_next = dp->dp_hosts; 1220 dp->dp_hosts = hp; 1221 grp = grp->gr_next; 1222 } while (grp); 1223 } else { 1224 dp->dp_flag |= DP_DEFSET; 1225 if (flags & OP_KERB) 1226 dp->dp_flag |= DP_KERB; 1227 } 1228 } 1229 1230 /* 1231 * Search for a dirpath on the export point. 1232 */ 1233 struct dirlist * 1234 dirp_search(dp, dirpath) 1235 struct dirlist *dp; 1236 char *dirpath; 1237 { 1238 int cmp; 1239 1240 if (dp) { 1241 cmp = strcmp(dp->dp_dirp, dirpath); 1242 if (cmp > 0) 1243 return (dirp_search(dp->dp_left, dirpath)); 1244 else if (cmp < 0) 1245 return (dirp_search(dp->dp_right, dirpath)); 1246 else 1247 return (dp); 1248 } 1249 return (dp); 1250 } 1251 1252 /* 1253 * Scan for a host match in a directory tree. 1254 */ 1255 int 1256 chk_host(dp, saddr, defsetp, hostsetp) 1257 struct dirlist *dp; 1258 u_int32_t saddr; 1259 int *defsetp; 1260 int *hostsetp; 1261 { 1262 struct hostlist *hp; 1263 struct grouplist *grp; 1264 u_int32_t **addrp; 1265 1266 if (dp) { 1267 if (dp->dp_flag & DP_DEFSET) 1268 *defsetp = dp->dp_flag; 1269 hp = dp->dp_hosts; 1270 while (hp) { 1271 grp = hp->ht_grp; 1272 switch (grp->gr_type) { 1273 case GT_HOST: 1274 addrp = (u_int32_t **) 1275 grp->gr_ptr.gt_hostent->h_addr_list; 1276 while (*addrp) { 1277 if (**addrp == saddr) { 1278 *hostsetp = (hp->ht_flag | DP_HOSTSET); 1279 return (1); 1280 } 1281 addrp++; 1282 } 1283 break; 1284 case GT_NET: 1285 if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 1286 grp->gr_ptr.gt_net.nt_net) { 1287 *hostsetp = (hp->ht_flag | DP_HOSTSET); 1288 return (1); 1289 } 1290 break; 1291 }; 1292 hp = hp->ht_next; 1293 } 1294 } 1295 return (0); 1296 } 1297 1298 /* 1299 * Scan tree for a host that matches the address. 1300 */ 1301 int 1302 scan_tree(dp, saddr) 1303 struct dirlist *dp; 1304 u_int32_t saddr; 1305 { 1306 int defset, hostset; 1307 1308 if (dp) { 1309 if (scan_tree(dp->dp_left, saddr)) 1310 return (1); 1311 if (chk_host(dp, saddr, &defset, &hostset)) 1312 return (1); 1313 if (scan_tree(dp->dp_right, saddr)) 1314 return (1); 1315 } 1316 return (0); 1317 } 1318 1319 /* 1320 * Traverse the dirlist tree and free it up. 1321 */ 1322 void 1323 free_dir(dp) 1324 struct dirlist *dp; 1325 { 1326 1327 if (dp) { 1328 free_dir(dp->dp_left); 1329 free_dir(dp->dp_right); 1330 free_host(dp->dp_hosts); 1331 free((caddr_t)dp); 1332 } 1333 } 1334 1335 /* 1336 * Parse the option string and update fields. 1337 * Option arguments may either be -<option>=<value> or 1338 * -<option> <value> 1339 */ 1340 int 1341 do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 1342 char **cpp, **endcpp; 1343 struct exportlist *ep; 1344 struct grouplist *grp; 1345 int *has_hostp; 1346 int *exflagsp; 1347 struct ucred *cr; 1348 { 1349 char *cpoptarg, *cpoptend; 1350 char *cp, *endcp, *cpopt, savedc, savedc2; 1351 int allflag, usedarg; 1352 1353 savedc2 = '\0'; 1354 cpopt = *cpp; 1355 cpopt++; 1356 cp = *endcpp; 1357 savedc = *cp; 1358 *cp = '\0'; 1359 while (cpopt && *cpopt) { 1360 allflag = 1; 1361 usedarg = -2; 1362 if ((cpoptend = strchr(cpopt, ','))) { 1363 *cpoptend++ = '\0'; 1364 if ((cpoptarg = strchr(cpopt, '='))) 1365 *cpoptarg++ = '\0'; 1366 } else { 1367 if ((cpoptarg = strchr(cpopt, '='))) 1368 *cpoptarg++ = '\0'; 1369 else { 1370 *cp = savedc; 1371 nextfield(&cp, &endcp); 1372 **endcpp = '\0'; 1373 if (endcp > cp && *cp != '-') { 1374 cpoptarg = cp; 1375 savedc2 = *endcp; 1376 *endcp = '\0'; 1377 usedarg = 0; 1378 } 1379 } 1380 } 1381 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 1382 *exflagsp |= MNT_EXRDONLY; 1383 } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 1384 !(allflag = strcmp(cpopt, "mapall")) || 1385 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 1386 usedarg++; 1387 parsecred(cpoptarg, cr); 1388 if (allflag == 0) { 1389 *exflagsp |= MNT_EXPORTANON; 1390 opt_flags |= OP_MAPALL; 1391 } else 1392 opt_flags |= OP_MAPROOT; 1393 } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 1394 *exflagsp |= MNT_EXKERB; 1395 opt_flags |= OP_KERB; 1396 } else if (cpoptarg && (!strcmp(cpopt, "mask") || 1397 !strcmp(cpopt, "m"))) { 1398 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 1399 syslog(LOG_ERR, "bad mask: %s", cpoptarg); 1400 return (1); 1401 } 1402 usedarg++; 1403 opt_flags |= OP_MASK; 1404 } else if (cpoptarg && (!strcmp(cpopt, "network") || 1405 !strcmp(cpopt, "n"))) { 1406 if (grp->gr_type != GT_NULL) { 1407 syslog(LOG_ERR, "network/host conflict"); 1408 return (1); 1409 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1410 syslog(LOG_ERR, "bad net: %s", cpoptarg); 1411 return (1); 1412 } 1413 grp->gr_type = GT_NET; 1414 *has_hostp = 1; 1415 usedarg++; 1416 opt_flags |= OP_NET; 1417 } else if (!strcmp(cpopt, "alldirs")) { 1418 opt_flags |= OP_ALLDIRS; 1419 } else if (!strcmp(cpopt, "public")) { 1420 *exflagsp |= MNT_EXPUBLIC; 1421 } else if (!strcmp(cpopt, "webnfs")) { 1422 *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 1423 opt_flags |= OP_MAPALL; 1424 } else if (cpoptarg && !strcmp(cpopt, "index")) { 1425 ep->ex_indexfile = strdup(cpoptarg); 1426 #ifdef ISO 1427 } else if (cpoptarg && !strcmp(cpopt, "iso")) { 1428 if (get_isoaddr(cpoptarg, grp)) { 1429 syslog(LOG_ERR, "bad iso addr: %s", cpoptarg); 1430 return (1); 1431 } 1432 *has_hostp = 1; 1433 usedarg++; 1434 opt_flags |= OP_ISO; 1435 #endif /* ISO */ 1436 } else { 1437 syslog(LOG_ERR, "bad opt %s", cpopt); 1438 return (1); 1439 } 1440 if (usedarg >= 0) { 1441 *endcp = savedc2; 1442 **endcpp = savedc; 1443 if (usedarg > 0) { 1444 *cpp = cp; 1445 *endcpp = endcp; 1446 } 1447 return (0); 1448 } 1449 cpopt = cpoptend; 1450 } 1451 **endcpp = savedc; 1452 return (0); 1453 } 1454 1455 /* 1456 * Translate a character string to the corresponding list of network 1457 * addresses for a hostname. 1458 */ 1459 int 1460 get_host(cp, grp, tgrp) 1461 char *cp; 1462 struct grouplist *grp; 1463 struct grouplist *tgrp; 1464 { 1465 struct grouplist *checkgrp; 1466 struct hostent *hp, *nhp; 1467 char **addrp, **naddrp; 1468 struct hostent t_host; 1469 int i; 1470 u_int32_t saddr; 1471 char *aptr[2]; 1472 1473 if (grp->gr_type != GT_NULL) 1474 return (1); 1475 if ((hp = gethostbyname(cp)) == NULL) { 1476 if (isdigit(*cp)) { 1477 saddr = inet_addr(cp); 1478 if (saddr == -1) { 1479 syslog(LOG_ERR, "inet_addr failed for %s", cp); 1480 return (1); 1481 } 1482 if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), 1483 AF_INET)) == NULL) { 1484 hp = &t_host; 1485 hp->h_name = cp; 1486 hp->h_addrtype = AF_INET; 1487 hp->h_length = sizeof (u_int32_t); 1488 hp->h_addr_list = aptr; 1489 aptr[0] = (char *)&saddr; 1490 aptr[1] = (char *)NULL; 1491 } 1492 } else { 1493 syslog(LOG_ERR, "gethostbyname failed for %s", cp); 1494 return (1); 1495 } 1496 } 1497 /* 1498 * Sanity check: make sure we don't already have an entry 1499 * for this host in the grouplist. 1500 */ 1501 checkgrp = tgrp; 1502 while (checkgrp != NULL) { 1503 if (checkgrp->gr_type == GT_HOST && 1504 checkgrp->gr_ptr.gt_hostent != NULL && 1505 (!strcmp(checkgrp->gr_ptr.gt_hostent->h_name, hp->h_name) 1506 || *(u_int32_t *)checkgrp->gr_ptr.gt_hostent->h_addr == 1507 *(u_int32_t *)hp->h_addr)) { 1508 grp->gr_type = GT_IGNORE; 1509 return(0); 1510 } 1511 checkgrp = checkgrp->gr_next; 1512 } 1513 1514 grp->gr_type = GT_HOST; 1515 nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 1516 malloc(sizeof(struct hostent)); 1517 if (nhp == (struct hostent *)NULL) 1518 out_of_mem(); 1519 memmove(nhp, hp, sizeof(struct hostent)); 1520 i = strlen(hp->h_name)+1; 1521 nhp->h_name = (char *)malloc(i); 1522 if (nhp->h_name == (char *)NULL) 1523 out_of_mem(); 1524 memmove(nhp->h_name, hp->h_name, i); 1525 addrp = hp->h_addr_list; 1526 i = 1; 1527 while (*addrp++) 1528 i++; 1529 naddrp = nhp->h_addr_list = (char **)malloc(i*sizeof(char *)); 1530 if (naddrp == (char **)NULL) 1531 out_of_mem(); 1532 addrp = hp->h_addr_list; 1533 while (*addrp) { 1534 *naddrp = (char *)malloc(hp->h_length); 1535 if (*naddrp == (char *)NULL) 1536 out_of_mem(); 1537 memmove(*naddrp, *addrp, hp->h_length); 1538 addrp++; 1539 naddrp++; 1540 } 1541 *naddrp = (char *)NULL; 1542 if (debug) 1543 warnx("got host %s", hp->h_name); 1544 return (0); 1545 } 1546 1547 /* 1548 * Free up an exports list component 1549 */ 1550 void 1551 free_exp(ep) 1552 struct exportlist *ep; 1553 { 1554 1555 if (ep->ex_defdir) { 1556 free_host(ep->ex_defdir->dp_hosts); 1557 free((caddr_t)ep->ex_defdir); 1558 } 1559 if (ep->ex_fsdir) 1560 free(ep->ex_fsdir); 1561 if (ep->ex_indexfile) 1562 free(ep->ex_indexfile); 1563 free_dir(ep->ex_dirl); 1564 free((caddr_t)ep); 1565 } 1566 1567 /* 1568 * Free hosts. 1569 */ 1570 void 1571 free_host(hp) 1572 struct hostlist *hp; 1573 { 1574 struct hostlist *hp2; 1575 1576 while (hp) { 1577 hp2 = hp; 1578 hp = hp->ht_next; 1579 free((caddr_t)hp2); 1580 } 1581 } 1582 1583 struct hostlist * 1584 get_ht() 1585 { 1586 struct hostlist *hp; 1587 1588 hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 1589 if (hp == (struct hostlist *)NULL) 1590 out_of_mem(); 1591 hp->ht_next = (struct hostlist *)NULL; 1592 hp->ht_flag = 0; 1593 return (hp); 1594 } 1595 1596 #ifdef ISO 1597 /* 1598 * Translate an iso address. 1599 */ 1600 get_isoaddr(cp, grp) 1601 char *cp; 1602 struct grouplist *grp; 1603 { 1604 struct iso_addr *isop; 1605 struct sockaddr_iso *isoaddr; 1606 1607 if (grp->gr_type != GT_NULL) 1608 return (1); 1609 if ((isop = iso_addr(cp)) == NULL) { 1610 syslog(LOG_ERR, "iso_addr failed, ignored"); 1611 return (1); 1612 } 1613 isoaddr = (struct sockaddr_iso *)malloc(sizeof (struct sockaddr_iso)); 1614 if (isoaddr == (struct sockaddr_iso *)NULL) 1615 out_of_mem(); 1616 memset(isoaddr, 0, sizeof(struct sockaddr_iso)); 1617 memmove(&isoaddr->siso_addr, isop, sizeof(struct iso_addr)); 1618 isoaddr->siso_len = sizeof(struct sockaddr_iso); 1619 isoaddr->siso_family = AF_ISO; 1620 grp->gr_type = GT_ISO; 1621 grp->gr_ptr.gt_isoaddr = isoaddr; 1622 return (0); 1623 } 1624 #endif /* ISO */ 1625 1626 /* 1627 * Out of memory, fatal 1628 */ 1629 void 1630 out_of_mem() 1631 { 1632 1633 syslog(LOG_ERR, "out of memory"); 1634 exit(2); 1635 } 1636 1637 /* 1638 * Do the mount syscall with the update flag to push the export info into 1639 * the kernel. 1640 */ 1641 int 1642 do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 1643 struct exportlist *ep; 1644 struct grouplist *grp; 1645 int exflags; 1646 struct ucred *anoncrp; 1647 char *dirp; 1648 int dirplen; 1649 struct statfs *fsb; 1650 { 1651 char *cp = (char *)NULL; 1652 u_int32_t **addrp; 1653 int done; 1654 char savedc = '\0'; 1655 struct sockaddr_in sin, imask; 1656 union { 1657 struct ufs_args ua; 1658 struct iso_args ia; 1659 struct mfs_args ma; 1660 #ifdef __NetBSD__ 1661 struct msdosfs_args da; 1662 #endif 1663 } args; 1664 u_int32_t net; 1665 1666 args.ua.fspec = 0; 1667 args.ua.export.ex_flags = exflags; 1668 args.ua.export.ex_anon = *anoncrp; 1669 args.ua.export.ex_indexfile = ep->ex_indexfile; 1670 memset(&sin, 0, sizeof(sin)); 1671 memset(&imask, 0, sizeof(imask)); 1672 sin.sin_family = AF_INET; 1673 sin.sin_len = sizeof(sin); 1674 imask.sin_family = AF_INET; 1675 imask.sin_len = sizeof(sin); 1676 if (grp->gr_type == GT_HOST) 1677 addrp = (u_int32_t **)grp->gr_ptr.gt_hostent->h_addr_list; 1678 else 1679 addrp = (u_int32_t **)NULL; 1680 done = FALSE; 1681 while (!done) { 1682 switch (grp->gr_type) { 1683 case GT_HOST: 1684 if (addrp) { 1685 sin.sin_addr.s_addr = **addrp; 1686 args.ua.export.ex_addrlen = sizeof(sin); 1687 } else 1688 args.ua.export.ex_addrlen = 0; 1689 args.ua.export.ex_addr = (struct sockaddr *)&sin; 1690 args.ua.export.ex_masklen = 0; 1691 break; 1692 case GT_NET: 1693 if (grp->gr_ptr.gt_net.nt_mask) 1694 imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 1695 else { 1696 net = ntohl(grp->gr_ptr.gt_net.nt_net); 1697 if (IN_CLASSA(net)) 1698 imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 1699 else if (IN_CLASSB(net)) 1700 imask.sin_addr.s_addr = 1701 inet_addr("255.255.0.0"); 1702 else 1703 imask.sin_addr.s_addr = 1704 inet_addr("255.255.255.0"); 1705 grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 1706 } 1707 sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 1708 args.ua.export.ex_addr = (struct sockaddr *)&sin; 1709 args.ua.export.ex_addrlen = sizeof (sin); 1710 args.ua.export.ex_mask = (struct sockaddr *)&imask; 1711 args.ua.export.ex_masklen = sizeof (imask); 1712 break; 1713 #ifdef ISO 1714 case GT_ISO: 1715 args.ua.export.ex_addr = 1716 (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 1717 args.ua.export.ex_addrlen = 1718 sizeof(struct sockaddr_iso); 1719 args.ua.export.ex_masklen = 0; 1720 break; 1721 #endif /* ISO */ 1722 case GT_IGNORE: 1723 return(0); 1724 break; 1725 default: 1726 syslog(LOG_ERR, "bad grouptype"); 1727 if (cp) 1728 *cp = savedc; 1729 return (1); 1730 }; 1731 1732 /* 1733 * XXX: 1734 * Maybe I should just use the fsb->f_mntonname path instead 1735 * of looping back up the dirp to the mount point?? 1736 * Also, needs to know how to export all types of local 1737 * exportable file systems and not just "ufs". 1738 */ 1739 while (mount(fsb->f_fstypename, dirp, 1740 fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 1741 if (cp) 1742 *cp-- = savedc; 1743 else 1744 cp = dirp + dirplen - 1; 1745 if (errno == EPERM) { 1746 syslog(LOG_ERR, 1747 "can't change attributes for %s", dirp); 1748 return (1); 1749 } 1750 if (opt_flags & OP_ALLDIRS) { 1751 syslog(LOG_ERR, "could not remount %s: %m", 1752 dirp); 1753 return (1); 1754 } 1755 /* back up over the last component */ 1756 while (*cp == '/' && cp > dirp) 1757 cp--; 1758 while (*(cp - 1) != '/' && cp > dirp) 1759 cp--; 1760 if (cp == dirp) { 1761 if (debug) 1762 warnx("mnt unsucc"); 1763 syslog(LOG_ERR, "can't export %s", dirp); 1764 return (1); 1765 } 1766 savedc = *cp; 1767 *cp = '\0'; 1768 } 1769 if (addrp) { 1770 ++addrp; 1771 if (*addrp == (u_int32_t *)NULL) 1772 done = TRUE; 1773 } else 1774 done = TRUE; 1775 } 1776 if (cp) 1777 *cp = savedc; 1778 return (0); 1779 } 1780 1781 /* 1782 * Translate a net address. 1783 */ 1784 int 1785 get_net(cp, net, maskflg) 1786 char *cp; 1787 struct netmsk *net; 1788 int maskflg; 1789 { 1790 struct netent *np; 1791 long netaddr; 1792 struct in_addr inetaddr, inetaddr2; 1793 char *name; 1794 1795 if (isdigit(*cp) && ((netaddr = inet_network(cp)) != -1)) { 1796 inetaddr = inet_makeaddr(netaddr, 0); 1797 /* 1798 * Due to arbitrary subnet masks, you don't know how many 1799 * bits to shift the address to make it into a network, 1800 * however you do know how to make a network address into 1801 * a host with host == 0 and then compare them. 1802 * (What a pest) 1803 */ 1804 if (!maskflg) { 1805 setnetent(0); 1806 while ((np = getnetent())) { 1807 inetaddr2 = inet_makeaddr(np->n_net, 0); 1808 if (inetaddr2.s_addr == inetaddr.s_addr) 1809 break; 1810 } 1811 endnetent(); 1812 } 1813 } else if ((np = getnetbyname(cp)) != NULL) { 1814 inetaddr = inet_makeaddr(np->n_net, 0); 1815 } else 1816 return (1); 1817 1818 if (maskflg) 1819 net->nt_mask = inetaddr.s_addr; 1820 else { 1821 if (np) 1822 name = np->n_name; 1823 else 1824 name = inet_ntoa(inetaddr); 1825 net->nt_name = (char *)malloc(strlen(name) + 1); 1826 if (net->nt_name == (char *)NULL) 1827 out_of_mem(); 1828 strcpy(net->nt_name, name); 1829 net->nt_net = inetaddr.s_addr; 1830 } 1831 return (0); 1832 } 1833 1834 /* 1835 * Parse out the next white space separated field 1836 */ 1837 void 1838 nextfield(cp, endcp) 1839 char **cp; 1840 char **endcp; 1841 { 1842 char *p; 1843 1844 p = *cp; 1845 while (*p == ' ' || *p == '\t') 1846 p++; 1847 if (*p == '\n' || *p == '\0') 1848 *cp = *endcp = p; 1849 else { 1850 *cp = p++; 1851 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 1852 p++; 1853 *endcp = p; 1854 } 1855 } 1856 1857 /* 1858 * Get an exports file line. Skip over blank lines and handle line 1859 * continuations. 1860 */ 1861 int 1862 get_line() 1863 { 1864 char *p, *cp; 1865 int len; 1866 int totlen, cont_line; 1867 1868 /* 1869 * Loop around ignoring blank lines and getting all continuation lines. 1870 */ 1871 p = line; 1872 totlen = 0; 1873 do { 1874 if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 1875 return (0); 1876 len = strlen(p); 1877 cp = p + len - 1; 1878 cont_line = 0; 1879 while (cp >= p && 1880 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 1881 if (*cp == '\\') 1882 cont_line = 1; 1883 cp--; 1884 len--; 1885 } 1886 *++cp = '\0'; 1887 if (len > 0) { 1888 totlen += len; 1889 if (totlen >= LINESIZ) { 1890 syslog(LOG_ERR, "exports line too long"); 1891 exit(2); 1892 } 1893 p = cp; 1894 } 1895 } while (totlen == 0 || cont_line); 1896 return (1); 1897 } 1898 1899 /* 1900 * Parse a description of a credential. 1901 */ 1902 void 1903 parsecred(namelist, cr) 1904 char *namelist; 1905 struct ucred *cr; 1906 { 1907 char *name; 1908 int cnt; 1909 char *names; 1910 struct passwd *pw; 1911 struct group *gr; 1912 int ngroups, groups[NGROUPS + 1]; 1913 1914 /* 1915 * Set up the unprivileged user. 1916 */ 1917 cr->cr_ref = 1; 1918 cr->cr_uid = -2; 1919 cr->cr_groups[0] = -2; 1920 cr->cr_ngroups = 1; 1921 /* 1922 * Get the user's password table entry. 1923 */ 1924 names = strsep(&namelist, " \t\n"); 1925 name = strsep(&names, ":"); 1926 if (isdigit(*name) || *name == '-') 1927 pw = getpwuid(atoi(name)); 1928 else 1929 pw = getpwnam(name); 1930 /* 1931 * Credentials specified as those of a user. 1932 */ 1933 if (names == NULL) { 1934 if (pw == NULL) { 1935 syslog(LOG_ERR, "unknown user: %s", name); 1936 return; 1937 } 1938 cr->cr_uid = pw->pw_uid; 1939 ngroups = NGROUPS + 1; 1940 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 1941 syslog(LOG_ERR, "too many groups"); 1942 /* 1943 * Convert from int's to gid_t's and compress out duplicate 1944 */ 1945 cr->cr_ngroups = ngroups - 1; 1946 cr->cr_groups[0] = groups[0]; 1947 for (cnt = 2; cnt < ngroups; cnt++) 1948 cr->cr_groups[cnt - 1] = groups[cnt]; 1949 return; 1950 } 1951 /* 1952 * Explicit credential specified as a colon separated list: 1953 * uid:gid:gid:... 1954 */ 1955 if (pw != NULL) 1956 cr->cr_uid = pw->pw_uid; 1957 else if (isdigit(*name) || *name == '-') 1958 cr->cr_uid = atoi(name); 1959 else { 1960 syslog(LOG_ERR, "unknown user: %s", name); 1961 return; 1962 } 1963 cr->cr_ngroups = 0; 1964 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 1965 name = strsep(&names, ":"); 1966 if (isdigit(*name) || *name == '-') { 1967 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 1968 } else { 1969 if ((gr = getgrnam(name)) == NULL) { 1970 syslog(LOG_ERR, "unknown group: %s", name); 1971 continue; 1972 } 1973 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 1974 } 1975 } 1976 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 1977 syslog(LOG_ERR, "too many groups"); 1978 } 1979 1980 #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 1981 /* 1982 * Routines that maintain the remote mounttab 1983 */ 1984 void 1985 get_mountlist() 1986 { 1987 struct mountlist *mlp, **mlpp; 1988 char *host, *dirp, *cp; 1989 char str[STRSIZ]; 1990 FILE *mlfile; 1991 1992 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 1993 syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 1994 return; 1995 } 1996 mlpp = &mlhead; 1997 while (fgets(str, STRSIZ, mlfile) != NULL) { 1998 cp = str; 1999 host = strsep(&cp, " \t\n"); 2000 dirp = strsep(&cp, " \t\n"); 2001 if (host == NULL || dirp == NULL) 2002 continue; 2003 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 2004 if (mlp == (struct mountlist *)NULL) 2005 out_of_mem(); 2006 strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 2007 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 2008 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 2009 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 2010 mlp->ml_next = (struct mountlist *)NULL; 2011 *mlpp = mlp; 2012 mlpp = &mlp->ml_next; 2013 } 2014 fclose(mlfile); 2015 } 2016 2017 void 2018 del_mlist(hostp, dirp) 2019 char *hostp, *dirp; 2020 { 2021 struct mountlist *mlp, **mlpp; 2022 struct mountlist *mlp2; 2023 FILE *mlfile; 2024 int fnd = 0; 2025 2026 mlpp = &mlhead; 2027 mlp = mlhead; 2028 while (mlp) { 2029 if (!strcmp(mlp->ml_host, hostp) && 2030 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 2031 fnd = 1; 2032 mlp2 = mlp; 2033 *mlpp = mlp = mlp->ml_next; 2034 free((caddr_t)mlp2); 2035 } else { 2036 mlpp = &mlp->ml_next; 2037 mlp = mlp->ml_next; 2038 } 2039 } 2040 if (fnd) { 2041 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 2042 syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 2043 return; 2044 } 2045 mlp = mlhead; 2046 while (mlp) { 2047 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 2048 mlp = mlp->ml_next; 2049 } 2050 fclose(mlfile); 2051 } 2052 } 2053 2054 void 2055 add_mlist(hostp, dirp) 2056 char *hostp, *dirp; 2057 { 2058 struct mountlist *mlp, **mlpp; 2059 FILE *mlfile; 2060 2061 mlpp = &mlhead; 2062 mlp = mlhead; 2063 while (mlp) { 2064 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 2065 return; 2066 mlpp = &mlp->ml_next; 2067 mlp = mlp->ml_next; 2068 } 2069 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 2070 if (mlp == (struct mountlist *)NULL) 2071 out_of_mem(); 2072 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 2073 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 2074 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 2075 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 2076 mlp->ml_next = (struct mountlist *)NULL; 2077 *mlpp = mlp; 2078 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 2079 syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 2080 return; 2081 } 2082 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 2083 fclose(mlfile); 2084 } 2085 2086 /* 2087 * This function is called via. SIGTERM when the system is going down. 2088 * It sends a broadcast RPCMNT_UMNTALL. 2089 */ 2090 void 2091 send_umntall() 2092 { 2093 (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 2094 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 2095 exit(0); 2096 } 2097 2098 int 2099 umntall_each(resultsp, raddr) 2100 caddr_t resultsp; 2101 struct sockaddr_in *raddr; 2102 { 2103 return (1); 2104 } 2105 2106 /* 2107 * Free up a group list. 2108 */ 2109 void 2110 free_grp(grp) 2111 struct grouplist *grp; 2112 { 2113 char **addrp; 2114 2115 if (grp->gr_type == GT_HOST) { 2116 if (grp->gr_ptr.gt_hostent->h_name) { 2117 addrp = grp->gr_ptr.gt_hostent->h_addr_list; 2118 while (addrp && *addrp) 2119 free(*addrp++); 2120 free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 2121 free(grp->gr_ptr.gt_hostent->h_name); 2122 } 2123 free((caddr_t)grp->gr_ptr.gt_hostent); 2124 } else if (grp->gr_type == GT_NET) { 2125 if (grp->gr_ptr.gt_net.nt_name) 2126 free(grp->gr_ptr.gt_net.nt_name); 2127 } 2128 #ifdef ISO 2129 else if (grp->gr_type == GT_ISO) 2130 free((caddr_t)grp->gr_ptr.gt_isoaddr); 2131 #endif 2132 free((caddr_t)grp); 2133 } 2134 2135 #ifdef DEBUG 2136 void 2137 SYSLOG(int pri, const char *fmt, ...) 2138 { 2139 va_list ap; 2140 2141 va_start(ap, fmt); 2142 vfprintf(stderr, fmt, ap); 2143 va_end(ap); 2144 } 2145 #endif /* DEBUG */ 2146 2147 /* 2148 * Check options for consistency. 2149 */ 2150 int 2151 check_options(dp) 2152 struct dirlist *dp; 2153 { 2154 2155 if (dp == (struct dirlist *)NULL) 2156 return (1); 2157 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 2158 (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 2159 (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 2160 syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 2161 return (1); 2162 } 2163 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 2164 syslog(LOG_ERR, "-mask requires -net"); 2165 return (1); 2166 } 2167 if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 2168 syslog(LOG_ERR, "-net and -iso mutually exclusive"); 2169 return (1); 2170 } 2171 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 2172 syslog(LOG_ERR, "-alldirs has multiple directories"); 2173 return (1); 2174 } 2175 return (0); 2176 } 2177 2178 /* 2179 * Check an absolute directory path for any symbolic links. Return true 2180 * if no symbolic links are found. 2181 */ 2182 int 2183 check_dirpath(dirp) 2184 char *dirp; 2185 { 2186 char *cp; 2187 int ret = 1; 2188 struct stat sb; 2189 2190 cp = dirp + 1; 2191 while (*cp && ret) { 2192 if (*cp == '/') { 2193 *cp = '\0'; 2194 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 2195 ret = 0; 2196 *cp = '/'; 2197 } 2198 cp++; 2199 } 2200 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 2201 ret = 0; 2202 return (ret); 2203 } 2204 2205 /* 2206 * Just translate an ascii string to an integer. 2207 */ 2208 int 2209 get_num(cp) 2210 register char *cp; 2211 { 2212 register int res = 0; 2213 2214 while (*cp) { 2215 if (*cp < '0' || *cp > '9') 2216 return (-1); 2217 res = res * 10 + (*cp++ - '0'); 2218 } 2219 return (res); 2220 } 2221