mountd.c revision 53117
1184610Salfred/* 2184610Salfred * Copyright (c) 1989, 1993 3188412Sthompsa * The Regents of the University of California. All rights reserved. 4184610Salfred * 5184610Salfred * This code is derived from software contributed to Berkeley by 6184610Salfred * Herb Hasler and Rick Macklem at The University of Guelph. 7184610Salfred * 8184610Salfred * Redistribution and use in source and binary forms, with or without 9184610Salfred * modification, are permitted provided that the following conditions 10184610Salfred * are met: 11184610Salfred * 1. Redistributions of source code must retain the above copyright 12184610Salfred * notice, this list of conditions and the following disclaimer. 13184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 14184610Salfred * notice, this list of conditions and the following disclaimer in the 15184610Salfred * documentation and/or other materials provided with the distribution. 16184610Salfred * 3. All advertising materials mentioning features or use of this software 17184610Salfred * must display the following acknowledgement: 18184610Salfred * This product includes software developed by the University of 19184610Salfred * California, Berkeley and its contributors. 20184610Salfred * 4. Neither the name of the University nor the names of its contributors 21184610Salfred * may be used to endorse or promote products derived from this software 22184610Salfred * without specific prior written permission. 23184610Salfred * 24184610Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27226709Syongari * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28226709Syongari * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29226709Syongari * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30194677Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31194677Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32226709Syongari * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33226709Syongari * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34194677Sthompsa * SUCH DAMAGE. 35226709Syongari */ 36226709Syongari 37226709Syongari#ifndef lint 38194677Sthompsastatic const char copyright[] = 39194677Sthompsa"@(#) Copyright (c) 1989, 1993\n\ 40226709Syongari The Regents of the University of California. All rights reserved.\n"; 41226709Syongari#endif /*not lint*/ 42194677Sthompsa 43194677Sthompsa#ifndef lint 44194677Sthompsa#if 0 45226709Syongaristatic char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 46226709Syongari#endif 47226709Syongaristatic const char rcsid[] = 48226709Syongari "$FreeBSD: head/usr.sbin/mountd/mountd.c 53117 1999-11-12 21:52:10Z billf $"; 49226709Syongari#endif /*not lint*/ 50226709Syongari 51226709Syongari#include <sys/param.h> 52226709Syongari#include <sys/mount.h> 53226709Syongari#include <sys/stat.h> 54188942Sthompsa#include <sys/syslog.h> 55194677Sthompsa#include <sys/sysctl.h> 56188412Sthompsa 57188942Sthompsa#include <rpc/rpc.h> 58188942Sthompsa#include <rpc/pmap_clnt.h> 59184610Salfred#include <nfs/rpcv2.h> 60227309Sed#include <nfs/nfsproto.h> 61227309Sed#include <nfs/nfs.h> 62184610Salfred#include <ufs/ufs/ufsmount.h> 63188412Sthompsa#include <msdosfs/msdosfsmount.h> 64188412Sthompsa#include <isofs/cd9660/cd9660_mount.h> /* XXX need isofs in include */ 65188412Sthompsa 66188412Sthompsa#include <arpa/inet.h> 67188942Sthompsa 68188942Sthompsa#include <ctype.h> 69188552Sthompsa#include <err.h> 70188412Sthompsa#include <errno.h> 71188412Sthompsa#include <grp.h> 72193045Sthompsa#include <netdb.h> 73193045Sthompsa#include <pwd.h> 74193045Sthompsa#include <signal.h> 75193045Sthompsa#include <stdio.h> 76193045Sthompsa#include <stdlib.h> 77193045Sthompsa#include <string.h> 78193045Sthompsa#include <unistd.h> 79188412Sthompsa#include "pathnames.h" 80188412Sthompsa 81188412Sthompsa#ifdef DEBUG 82188412Sthompsa#include <stdarg.h> 83188412Sthompsa#endif 84188412Sthompsa 85188412Sthompsa/* 86188412Sthompsa * Structures for keeping the mount list and export list 87188412Sthompsa */ 88188412Sthompsastruct mountlist { 89188412Sthompsa struct mountlist *ml_next; 90188412Sthompsa char ml_host[RPCMNT_NAMELEN+1]; 91194228Sthompsa char ml_dirp[RPCMNT_PATHLEN+1]; 92184610Salfred}; 93194228Sthompsa 94188412Sthompsastruct dirlist { 95188412Sthompsa struct dirlist *dp_left; 96188412Sthompsa struct dirlist *dp_right; 97194228Sthompsa int dp_flag; 98188412Sthompsa struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 99188412Sthompsa char dp_dirp[1]; /* Actually malloc'd to size of dir */ 100184610Salfred}; 101188412Sthompsa/* dp_flag bits */ 102192984Sthompsa#define DP_DEFSET 0x1 103193045Sthompsa#define DP_HOSTSET 0x2 104192984Sthompsa#define DP_KERB 0x4 105188412Sthompsa 106192984Sthompsastruct exportlist { 107188412Sthompsa struct exportlist *ex_next; 108188412Sthompsa struct dirlist *ex_dirl; 109188412Sthompsa struct dirlist *ex_defdir; 110194228Sthompsa int ex_flag; 111188412Sthompsa fsid_t ex_fs; 112184610Salfred char *ex_fsdir; 113188412Sthompsa char *ex_indexfile; 114188412Sthompsa}; 115188412Sthompsa/* ex_flag bits */ 116188412Sthompsa#define EX_LINKED 0x1 117188412Sthompsa 118192984Sthompsastruct netmsk { 119194228Sthompsa u_int32_t nt_net; 120188412Sthompsa u_int32_t nt_mask; 121188412Sthompsa char *nt_name; 122188412Sthompsa}; 123188412Sthompsa 124188412Sthompsaunion grouptypes { 125188412Sthompsa struct hostent *gt_hostent; 126188412Sthompsa struct netmsk gt_net; 127188412Sthompsa}; 128188412Sthompsa 129194228Sthompsastruct grouplist { 130184610Salfred int gr_type; 131184610Salfred union grouptypes gr_ptr; 132188412Sthompsa struct grouplist *gr_next; 133194228Sthompsa}; 134184610Salfred/* Group types */ 135188412Sthompsa#define GT_NULL 0x0 136188412Sthompsa#define GT_HOST 0x1 137184610Salfred#define GT_NET 0x2 138188412Sthompsa#define GT_IGNORE 0x5 139194228Sthompsa 140188412Sthompsastruct hostlist { 141188412Sthompsa int ht_flag; /* Uses DP_xx bits */ 142188412Sthompsa struct grouplist *ht_grp; 143188412Sthompsa struct hostlist *ht_next; 144188412Sthompsa}; 145194228Sthompsa 146188412Sthompsastruct fhreturn { 147188412Sthompsa int fhr_flag; 148188412Sthompsa int fhr_vers; 149188412Sthompsa nfsfh_t fhr_fh; 150188412Sthompsa}; 151188412Sthompsa 152188412Sthompsa/* Global defs */ 153192984Sthompsachar *add_expdir __P((struct dirlist **, char *, int)); 154188412Sthompsavoid add_dlist __P((struct dirlist **, struct dirlist *, 155188412Sthompsa struct grouplist *, int)); 156188412Sthompsavoid add_mlist __P((char *, char *)); 157188412Sthompsaint check_dirpath __P((char *)); 158188412Sthompsaint check_options __P((struct dirlist *)); 159188412Sthompsaint chk_host __P((struct dirlist *, u_int32_t, int *, int *)); 160188412Sthompsavoid del_mlist __P((char *, char *)); 161194228Sthompsastruct dirlist *dirp_search __P((struct dirlist *, char *)); 162188412Sthompsaint do_mount __P((struct exportlist *, struct grouplist *, int, 163188412Sthompsa struct ucred *, char *, int, struct statfs *)); 164188412Sthompsaint do_opt __P((char **, char **, struct exportlist *, struct grouplist *, 165188412Sthompsa int *, int *, struct ucred *)); 166188412Sthompsastruct exportlist *ex_search __P((fsid_t *)); 167188412Sthompsastruct exportlist *get_exp __P((void)); 168188412Sthompsavoid free_dir __P((struct dirlist *)); 169188412Sthompsavoid free_exp __P((struct exportlist *)); 170188412Sthompsavoid free_grp __P((struct grouplist *)); 171188412Sthompsavoid free_host __P((struct hostlist *)); 172194228Sthompsavoid get_exportlist __P((void)); 173188412Sthompsaint get_host __P((char *, struct grouplist *, struct grouplist *)); 174188412Sthompsaint get_num __P((char *)); 175188412Sthompsastruct hostlist *get_ht __P((void)); 176188412Sthompsaint get_line __P((void)); 177188412Sthompsavoid get_mountlist __P((void)); 178188412Sthompsaint get_net __P((char *, struct netmsk *, int)); 179188412Sthompsavoid getexp_err __P((struct exportlist *, struct grouplist *)); 180188412Sthompsastruct grouplist *get_grp __P((void)); 181188412Sthompsavoid hang_dirp __P((struct dirlist *, struct grouplist *, 182188412Sthompsa struct exportlist *, int)); 183188412Sthompsavoid mntsrv __P((struct svc_req *, SVCXPRT *)); 184188412Sthompsavoid nextfield __P((char **, char **)); 185188412Sthompsavoid out_of_mem __P((void)); 186188412Sthompsavoid parsecred __P((char *, struct ucred *)); 187188412Sthompsaint put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *)); 188188412Sthompsaint scan_tree __P((struct dirlist *, u_int32_t)); 189188412Sthompsastatic void usage __P((void)); 190188412Sthompsaint xdr_dir __P((XDR *, char *)); 191192984Sthompsaint xdr_explist __P((XDR *, caddr_t)); 192188412Sthompsaint xdr_fhs __P((XDR *, caddr_t)); 193192984Sthompsaint xdr_mlist __P((XDR *, caddr_t)); 194192984Sthompsa 195192984Sthompsa/* C library */ 196188412Sthompsaint getnetgrent(); 197188412Sthompsavoid endnetgrent(); 198188412Sthompsavoid setnetgrent(); 199188412Sthompsa 200188412Sthompsastruct exportlist *exphead; 201188412Sthompsastruct mountlist *mlhead; 202188412Sthompsastruct grouplist *grphead; 203188412Sthompsachar exname[MAXPATHLEN]; 204188412Sthompsastruct ucred def_anon = { 205188412Sthompsa 1, 206194228Sthompsa (uid_t) -2, 207188412Sthompsa 1, 208188412Sthompsa { (gid_t) -2 } 209226709Syongari}; 210188412Sthompsaint force_v2 = 0; 211184610Salfredint resvport_only = 1; 212188412Sthompsaint dir_only = 1; 213226709Syongariint log = 0; 214184610Salfredint opt_flags; 215184610Salfred/* Bits for above */ 216188412Sthompsa#define OP_MAPROOT 0x01 217188412Sthompsa#define OP_MAPALL 0x02 218226709Syongari#define OP_KERB 0x04 219226709Syongari#define OP_MASK 0x08 220226709Syongari#define OP_NET 0x10 221226709Syongari#define OP_ALLDIRS 0x40 222226709Syongari 223226709Syongari#ifdef DEBUG 224226709Syongariint debug = 1; 225226709Syongarivoid SYSLOG __P((int, const char *, ...)); 226226709Syongari#define syslog SYSLOG 227226709Syongari#else 228226709Syongariint debug = 0; 229226709Syongari#endif 230226709Syongari 231226709Syongari/* 232226709Syongari * Mountd server for NFS mount protocol as described in: 233184610Salfred * NFS: Network File System Protocol Specification, RFC1094, Appendix A 234226709Syongari * The optional arguments are the exports file name 235226709Syongari * default: _PATH_EXPORTS 236226709Syongari * and "-n" to allow nonroot mount. 237226709Syongari */ 238226709Syongariint 239226709Syongarimain(argc, argv) 240226709Syongari int argc; 241226709Syongari char **argv; 242188412Sthompsa{ 243188412Sthompsa SVCXPRT *udptransp, *tcptransp; 244184610Salfred int c, error, mib[3]; 245226709Syongari struct vfsconf vfc; 246226709Syongari 247226709Syongari error = getvfsbyname("nfs", &vfc); 248226709Syongari if (error && vfsisloadable("nfs")) { 249226709Syongari if(vfsload("nfs")) 250188412Sthompsa err(1, "vfsload(nfs)"); 251188412Sthompsa endvfsent(); /* flush cache */ 252226709Syongari error = getvfsbyname("nfs", &vfc); 253226709Syongari } 254226709Syongari if (error) 255188412Sthompsa errx(1, "NFS support is not available in the running kernel"); 256188412Sthompsa 257188412Sthompsa while ((c = getopt(argc, argv, "2dlnr")) != -1) 258188412Sthompsa switch (c) { 259188412Sthompsa case '2': 260188412Sthompsa force_v2 = 1; 261188412Sthompsa break; 262217556Smdf case 'n': 263188412Sthompsa resvport_only = 0; 264188412Sthompsa break; 265188412Sthompsa case 'r': 266188412Sthompsa dir_only = 0; 267188412Sthompsa break; 268226709Syongari case 'd': 269188412Sthompsa debug = debug ? 0 : 1; 270188412Sthompsa break; 271188412Sthompsa case 'l': 272188412Sthompsa log = 1; 273184610Salfred break; 274188412Sthompsa default: 275188412Sthompsa usage(); 276188412Sthompsa }; 277184610Salfred argc -= optind; 278188412Sthompsa argv += optind; 279194228Sthompsa grphead = (struct grouplist *)NULL; 280188412Sthompsa exphead = (struct exportlist *)NULL; 281188412Sthompsa mlhead = (struct mountlist *)NULL; 282184610Salfred if (argc == 1) { 283188412Sthompsa strncpy(exname, *argv, MAXPATHLEN-1); 284194228Sthompsa exname[MAXPATHLEN-1] = '\0'; 285184610Salfred } else 286188412Sthompsa strcpy(exname, _PATH_EXPORTS); 287188412Sthompsa openlog("mountd", LOG_PID, LOG_DAEMON); 288184610Salfred if (debug) 289188412Sthompsa warnx("getting export list"); 290184610Salfred get_exportlist(); 291188412Sthompsa if (debug) 292188412Sthompsa warnx("getting mount list"); 293188412Sthompsa get_mountlist(); 294188412Sthompsa if (debug) 295184610Salfred warnx("here we go"); 296188412Sthompsa if (debug == 0) { 297194228Sthompsa daemon(0, 0); 298188412Sthompsa signal(SIGINT, SIG_IGN); 299188412Sthompsa signal(SIGQUIT, SIG_IGN); 300188412Sthompsa } 301196403Sjhb signal(SIGHUP, (void (*) __P((int))) get_exportlist); 302188412Sthompsa { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 303196403Sjhb if (pidfile != NULL) { 304184610Salfred fprintf(pidfile, "%d\n", getpid()); 305184610Salfred fclose(pidfile); 306188412Sthompsa } 307188412Sthompsa } 308184610Salfred if (!resvport_only) { 309188412Sthompsa mib[0] = CTL_VFS; 310188412Sthompsa mib[1] = vfc.vfc_typenum; 311188412Sthompsa mib[2] = NFS_NFSPRIVPORT; 312188412Sthompsa if (sysctl(mib, 3, NULL, NULL, &resvport_only, 313188412Sthompsa sizeof(resvport_only)) != 0 && errno != ENOENT) { 314188412Sthompsa syslog(LOG_ERR, "sysctl: %m"); 315188412Sthompsa exit(1); 316188412Sthompsa } 317188412Sthompsa } 318188412Sthompsa if ((udptransp = svcudp_create(RPC_ANYSOCK)) == NULL || 319188412Sthompsa (tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) { 320194228Sthompsa syslog(LOG_ERR, "can't create socket"); 321188412Sthompsa exit(1); 322188412Sthompsa } 323188412Sthompsa pmap_unset(RPCPROG_MNT, 1); 324194228Sthompsa pmap_unset(RPCPROG_MNT, 3); 325188412Sthompsa if (!force_v2) 326194228Sthompsa if (!svc_register(udptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_UDP) || 327188412Sthompsa !svc_register(tcptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_TCP)) { 328188412Sthompsa syslog(LOG_ERR, "can't register mount"); 329226709Syongari exit(1); 330226709Syongari } 331226709Syongari if (!svc_register(udptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_UDP) || 332226709Syongari !svc_register(tcptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_TCP)) { 333226709Syongari syslog(LOG_ERR, "can't register mount"); 334226709Syongari exit(1); 335226709Syongari } 336188412Sthompsa svc_run(); 337188412Sthompsa syslog(LOG_ERR, "mountd died"); 338188412Sthompsa exit(1); 339192984Sthompsa} 340188412Sthompsa 341188412Sthompsastatic void 342188412Sthompsausage() 343188412Sthompsa{ 344188412Sthompsa fprintf(stderr, 345188412Sthompsa "usage: mountd [-2] [-d] [-l] [-n] [-r] [export_file]\n"); 346188412Sthompsa exit(1); 347188412Sthompsa} 348188412Sthompsa 349192984Sthompsa/* 350188412Sthompsa * The mount rpc service 351192984Sthompsa */ 352192984Sthompsavoid 353192984Sthompsamntsrv(rqstp, transp) 354188412Sthompsa struct svc_req *rqstp; 355188412Sthompsa SVCXPRT *transp; 356188412Sthompsa{ 357188412Sthompsa struct exportlist *ep; 358188412Sthompsa struct dirlist *dp; 359188412Sthompsa struct fhreturn fhr; 360188412Sthompsa struct stat stb; 361188412Sthompsa struct statfs fsb; 362188412Sthompsa struct hostent *hp; 363188412Sthompsa struct in_addr saddrin; 364194228Sthompsa u_int32_t saddr; 365188412Sthompsa u_short sport; 366188412Sthompsa char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 367188412Sthompsa int bad = 0, defset, hostset; 368192984Sthompsa sigset_t sighup_mask; 369188412Sthompsa 370192984Sthompsa sigemptyset(&sighup_mask); 371192984Sthompsa sigaddset(&sighup_mask, SIGHUP); 372192984Sthompsa saddr = transp->xp_raddr.sin_addr.s_addr; 373188412Sthompsa saddrin = transp->xp_raddr.sin_addr; 374188412Sthompsa sport = ntohs(transp->xp_raddr.sin_port); 375188412Sthompsa hp = (struct hostent *)NULL; 376194228Sthompsa switch (rqstp->rq_proc) { 377188412Sthompsa case NULLPROC: 378188412Sthompsa if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 379188412Sthompsa syslog(LOG_ERR, "can't send reply"); 380188412Sthompsa return; 381226709Syongari case RPCMNT_MOUNT: 382226709Syongari if (sport >= IPPORT_RESERVED && resvport_only) { 383226709Syongari syslog(LOG_NOTICE, 384226709Syongari "mount request from %s from unprivileged port", 385226709Syongari inet_ntoa(saddrin)); 386226709Syongari svcerr_weakauth(transp); 387226709Syongari return; 388188412Sthompsa } 389188412Sthompsa if (!svc_getargs(transp, xdr_dir, rpcpath)) { 390188412Sthompsa syslog(LOG_NOTICE, "undecodable mount request from %s", 391192984Sthompsa inet_ntoa(saddrin)); 392188412Sthompsa svcerr_decode(transp); 393188412Sthompsa return; 394188412Sthompsa } 395188412Sthompsa 396188412Sthompsa /* 397188412Sthompsa * Get the real pathname and make sure it is a directory 398188412Sthompsa * or a regular file if the -r option was specified 399188412Sthompsa * and it exists. 400188412Sthompsa */ 401188412Sthompsa if (realpath(rpcpath, dirpath) == NULL || 402192984Sthompsa stat(dirpath, &stb) < 0 || 403188412Sthompsa (!S_ISDIR(stb.st_mode) && 404192984Sthompsa (dir_only || !S_ISREG(stb.st_mode))) || 405192984Sthompsa statfs(dirpath, &fsb) < 0) { 406192984Sthompsa chdir("/"); /* Just in case realpath doesn't */ 407188412Sthompsa syslog(LOG_NOTICE, 408188412Sthompsa "mount request from %s for non existent path %s", 409188412Sthompsa inet_ntoa(saddrin), dirpath); 410188412Sthompsa if (debug) 411188412Sthompsa warnx("stat failed on %s", dirpath); 412192984Sthompsa bad = ENOENT; /* We will send error reply later */ 413188412Sthompsa } 414192984Sthompsa 415192984Sthompsa /* Check in the exports list */ 416192984Sthompsa sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 417188412Sthompsa ep = ex_search(&fsb.f_fsid); 418188412Sthompsa hostset = defset = 0; 419188412Sthompsa if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 420188412Sthompsa ((dp = dirp_search(ep->ex_dirl, dirpath)) && 421226709Syongari chk_host(dp, saddr, &defset, &hostset)) || 422226709Syongari (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 423226709Syongari scan_tree(ep->ex_dirl, saddr) == 0))) { 424226709Syongari if (bad) { 425226709Syongari if (!svc_sendreply(transp, xdr_long, 426226709Syongari (caddr_t)&bad)) 427226709Syongari syslog(LOG_ERR, "can't send reply"); 428188412Sthompsa sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 429188412Sthompsa return; 430188412Sthompsa } 431192984Sthompsa if (hostset & DP_HOSTSET) 432188412Sthompsa fhr.fhr_flag = hostset; 433188412Sthompsa else 434188412Sthompsa fhr.fhr_flag = defset; 435188412Sthompsa fhr.fhr_vers = rqstp->rq_vers; 436188412Sthompsa /* Get the file handle */ 437188412Sthompsa memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 438188412Sthompsa if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 439188412Sthompsa bad = errno; 440188412Sthompsa syslog(LOG_ERR, "can't get fh for %s", dirpath); 441188412Sthompsa if (!svc_sendreply(transp, xdr_long, 442188412Sthompsa (caddr_t)&bad)) 443188412Sthompsa syslog(LOG_ERR, "can't send reply"); 444192984Sthompsa sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 445188412Sthompsa return; 446192984Sthompsa } 447192984Sthompsa if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr)) 448192984Sthompsa syslog(LOG_ERR, "can't send reply"); 449188412Sthompsa if (hp == NULL) 450188412Sthompsa hp = gethostbyaddr((caddr_t)&saddr, 451188412Sthompsa sizeof(saddr), AF_INET); 452188412Sthompsa if (hp) 453188412Sthompsa add_mlist(hp->h_name, dirpath); 454188412Sthompsa else 455188412Sthompsa add_mlist(inet_ntoa(saddrin), 456188412Sthompsa dirpath); 457192984Sthompsa if (debug) 458188412Sthompsa warnx("mount successful"); 459188412Sthompsa if (log) 460188412Sthompsa syslog(LOG_NOTICE, 461188412Sthompsa "mount request succeeded from %s for %s", 462188412Sthompsa inet_ntoa(saddrin), dirpath); 463188412Sthompsa } else { 464188412Sthompsa bad = EACCES; 465188412Sthompsa syslog(LOG_NOTICE, 466188412Sthompsa "mount request denied from %s for %s", 467194228Sthompsa inet_ntoa(saddrin), dirpath); 468188412Sthompsa } 469188412Sthompsa 470188412Sthompsa if (bad && !svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 471192984Sthompsa syslog(LOG_ERR, "can't send reply"); 472188412Sthompsa sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 473192984Sthompsa return; 474192984Sthompsa case RPCMNT_DUMP: 475192984Sthompsa if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL)) 476188412Sthompsa syslog(LOG_ERR, "can't send reply"); 477188412Sthompsa else if (log) 478188412Sthompsa syslog(LOG_NOTICE, 479188412Sthompsa "dump request succeeded from %s", 480188412Sthompsa inet_ntoa(saddrin)); 481188412Sthompsa return; 482188412Sthompsa case RPCMNT_UMOUNT: 483188412Sthompsa if (sport >= IPPORT_RESERVED && resvport_only) { 484188412Sthompsa syslog(LOG_NOTICE, 485194228Sthompsa "umount request from %s from unprivileged port", 486188412Sthompsa inet_ntoa(saddrin)); 487192984Sthompsa svcerr_weakauth(transp); 488188412Sthompsa return; 489188412Sthompsa } 490188412Sthompsa if (!svc_getargs(transp, xdr_dir, rpcpath)) { 491188412Sthompsa syslog(LOG_NOTICE, "undecodable umount request from %s", 492188412Sthompsa inet_ntoa(saddrin)); 493188412Sthompsa svcerr_decode(transp); 494188412Sthompsa return; 495188412Sthompsa } 496188412Sthompsa if (realpath(rpcpath, dirpath) == NULL) { 497188412Sthompsa syslog(LOG_NOTICE, "umount request from %s " 498188412Sthompsa "for non existent path %s", 499188412Sthompsa inet_ntoa(saddrin), dirpath); 500188412Sthompsa } 501188412Sthompsa if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 502188412Sthompsa syslog(LOG_ERR, "can't send reply"); 503188412Sthompsa hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 504188412Sthompsa if (hp) 505188412Sthompsa del_mlist(hp->h_name, dirpath); 506188412Sthompsa del_mlist(inet_ntoa(saddrin), dirpath); 507188412Sthompsa if (log) 508184610Salfred syslog(LOG_NOTICE, 509188412Sthompsa "umount request succeeded from %s for %s", 510188412Sthompsa inet_ntoa(saddrin), dirpath); 511188412Sthompsa return; 512188412Sthompsa case RPCMNT_UMNTALL: 513188412Sthompsa if (sport >= IPPORT_RESERVED && resvport_only) { 514188412Sthompsa syslog(LOG_NOTICE, 515188412Sthompsa "umountall request from %s from unprivileged port", 516188412Sthompsa inet_ntoa(saddrin)); 517188412Sthompsa svcerr_weakauth(transp); 518188412Sthompsa return; 519188412Sthompsa } 520188412Sthompsa if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 521188412Sthompsa syslog(LOG_ERR, "can't send reply"); 522188412Sthompsa hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 523188412Sthompsa if (hp) 524188412Sthompsa del_mlist(hp->h_name, (char *)NULL); 525188412Sthompsa del_mlist(inet_ntoa(saddrin), (char *)NULL); 526188412Sthompsa if (log) 527188412Sthompsa syslog(LOG_NOTICE, 528188412Sthompsa "umountall request succeeded from %s", 529188412Sthompsa inet_ntoa(saddrin)); 530184610Salfred return; 531188412Sthompsa case RPCMNT_EXPORT: 532184610Salfred if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL)) 533188412Sthompsa syslog(LOG_ERR, "can't send reply"); 534188412Sthompsa if (log) 535194228Sthompsa syslog(LOG_NOTICE, 536188412Sthompsa "export request succeeded from %s", 537188412Sthompsa inet_ntoa(saddrin)); 538188412Sthompsa return; 539188412Sthompsa default: 540188412Sthompsa svcerr_noproc(transp); 541188412Sthompsa return; 542188412Sthompsa } 543188412Sthompsa} 544188412Sthompsa 545188412Sthompsa/* 546188412Sthompsa * Xdr conversion for a dirpath string 547188412Sthompsa */ 548188412Sthompsaint 549194228Sthompsaxdr_dir(xdrsp, dirp) 550188942Sthompsa XDR *xdrsp; 551194228Sthompsa char *dirp; 552241394Skevlo{ 553188412Sthompsa return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 554188412Sthompsa} 555189528Sthompsa 556194228Sthompsa/* 557189528Sthompsa * Xdr routine to generate file handle reply 558189528Sthompsa */ 559189528Sthompsaint 560243857Sglebiusxdr_fhs(xdrsp, cp) 561189528Sthompsa XDR *xdrsp; 562189528Sthompsa caddr_t cp; 563189528Sthompsa{ 564189528Sthompsa register struct fhreturn *fhrp = (struct fhreturn *)cp; 565189528Sthompsa u_long ok = 0, len, auth; 566189528Sthompsa 567189528Sthompsa if (!xdr_long(xdrsp, &ok)) 568189528Sthompsa return (0); 569188412Sthompsa switch (fhrp->fhr_vers) { 570194228Sthompsa case 1: 571188412Sthompsa return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 572188412Sthompsa case 3: 573188412Sthompsa len = NFSX_V3FH; 574188412Sthompsa if (!xdr_long(xdrsp, &len)) 575188412Sthompsa return (0); 576188412Sthompsa if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 577188412Sthompsa return (0); 578188412Sthompsa if (fhrp->fhr_flag & DP_KERB) 579188412Sthompsa auth = RPCAUTH_KERB4; 580188412Sthompsa else 581188412Sthompsa auth = RPCAUTH_UNIX; 582188412Sthompsa len = 1; 583188412Sthompsa if (!xdr_long(xdrsp, &len)) 584188412Sthompsa return (0); 585188412Sthompsa return (xdr_long(xdrsp, &auth)); 586188412Sthompsa }; 587188412Sthompsa return (0); 588194228Sthompsa} 589188412Sthompsa 590188412Sthompsaint 591188412Sthompsaxdr_mlist(xdrsp, cp) 592188412Sthompsa XDR *xdrsp; 593188412Sthompsa caddr_t cp; 594188412Sthompsa{ 595188412Sthompsa struct mountlist *mlp; 596189528Sthompsa int true = 1; 597188412Sthompsa int false = 0; 598188412Sthompsa char *strp; 599194228Sthompsa 600188412Sthompsa mlp = mlhead; 601213438Syongari while (mlp) { 602188412Sthompsa if (!xdr_bool(xdrsp, &true)) 603188412Sthompsa return (0); 604188412Sthompsa strp = &mlp->ml_host[0]; 605194228Sthompsa if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 606188412Sthompsa return (0); 607188412Sthompsa strp = &mlp->ml_dirp[0]; 608188412Sthompsa if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 609188412Sthompsa return (0); 610188412Sthompsa mlp = mlp->ml_next; 611188412Sthompsa } 612188412Sthompsa if (!xdr_bool(xdrsp, &false)) 613188412Sthompsa return (0); 614188412Sthompsa return (1); 615188412Sthompsa} 616188412Sthompsa 617188412Sthompsa/* 618194228Sthompsa * Xdr conversion for export list 619188412Sthompsa */ 620188412Sthompsaint 621188412Sthompsaxdr_explist(xdrsp, cp) 622188412Sthompsa XDR *xdrsp; 623188412Sthompsa caddr_t cp; 624188412Sthompsa{ 625188412Sthompsa struct exportlist *ep; 626188412Sthompsa int false = 0; 627188412Sthompsa int putdef; 628188412Sthompsa sigset_t sighup_mask; 629188412Sthompsa 630188412Sthompsa sigemptyset(&sighup_mask); 631188412Sthompsa sigaddset(&sighup_mask, SIGHUP); 632188412Sthompsa sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 633188412Sthompsa ep = exphead; 634188412Sthompsa while (ep) { 635188412Sthompsa putdef = 0; 636188412Sthompsa if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 637188412Sthompsa goto errout; 638188412Sthompsa if (ep->ex_defdir && putdef == 0 && 639194228Sthompsa put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 640188942Sthompsa &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