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