1 1.137 hannken /* $NetBSD: mountd.c,v 1.137 2021/06/05 08:26:34 hannken Exp $ */ 2 1.19 cgd 3 1.1 cgd /* 4 1.62 enami * Copyright (c) 1989, 1993 5 1.12 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.12 mycroft * Herb Hasler and Rick Macklem at The University of Guelph. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.85 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.41 lukem #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.117 lukem __COPYRIGHT("@(#) Copyright (c) 1989, 1993\ 38 1.117 lukem The Regents of the University of California. All rights reserved."); 39 1.47 christos #endif /* not lint */ 40 1.1 cgd 41 1.1 cgd #ifndef lint 42 1.19 cgd #if 0 43 1.47 christos static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 44 1.19 cgd #else 45 1.137 hannken __RCSID("$NetBSD: mountd.c,v 1.137 2021/06/05 08:26:34 hannken Exp $"); 46 1.19 cgd #endif 47 1.47 christos #endif /* not lint */ 48 1.1 cgd 49 1.1 cgd #include <sys/param.h> 50 1.12 mycroft #include <sys/file.h> 51 1.1 cgd #include <sys/ioctl.h> 52 1.1 cgd #include <sys/mount.h> 53 1.1 cgd #include <sys/socket.h> 54 1.12 mycroft #include <sys/stat.h> 55 1.21 jtc #include <syslog.h> 56 1.12 mycroft #include <sys/ucred.h> 57 1.12 mycroft 58 1.1 cgd #include <rpc/rpc.h> 59 1.1 cgd #include <rpc/pmap_clnt.h> 60 1.1 cgd #include <rpc/pmap_prot.h> 61 1.45 christos #include <rpcsvc/mount.h> 62 1.12 mycroft #include <nfs/rpcv2.h> 63 1.31 fvdl #include <nfs/nfsproto.h> 64 1.43 fvdl #include <nfs/nfs.h> 65 1.43 fvdl #include <nfs/nfsmount.h> 66 1.43 fvdl 67 1.128 christos #ifdef MOUNTD_RUMP 68 1.128 christos #include <rump/rump.h> 69 1.132 kamil #include <rump/rump_syscallshotgun.h> 70 1.128 christos #include <rump/rump_syscalls.h> 71 1.128 christos #include <pthread.h> 72 1.128 christos #include <semaphore.h> 73 1.128 christos #endif 74 1.128 christos 75 1.12 mycroft #include <arpa/inet.h> 76 1.12 mycroft 77 1.12 mycroft #include <ctype.h> 78 1.12 mycroft #include <errno.h> 79 1.12 mycroft #include <grp.h> 80 1.12 mycroft #include <netdb.h> 81 1.12 mycroft #include <pwd.h> 82 1.41 lukem #include <netgroup.h> 83 1.12 mycroft #include <signal.h> 84 1.12 mycroft #include <stdio.h> 85 1.12 mycroft #include <stdlib.h> 86 1.12 mycroft #include <string.h> 87 1.12 mycroft #include <unistd.h> 88 1.80 christos #include <err.h> 89 1.47 christos #include <util.h> 90 1.1 cgd #include "pathnames.h" 91 1.1 cgd 92 1.80 christos #ifdef IPSEC 93 1.124 drochner #include <netipsec/ipsec.h> 94 1.80 christos #ifndef IPSEC_POLICY_IPSEC /* no ipsec support on old ipsec */ 95 1.80 christos #undef IPSEC 96 1.80 christos #endif 97 1.80 christos #include "ipsec.h" 98 1.80 christos #endif 99 1.80 christos 100 1.12 mycroft #include <stdarg.h> 101 1.12 mycroft 102 1.128 christos #ifdef MOUNTD_RUMP 103 1.128 christos #include "svc_fdset.h" 104 1.128 christos #define DEBUGGING 1 105 1.128 christos #else 106 1.128 christos #define DEBUGGING 0 107 1.128 christos #endif 108 1.128 christos 109 1.129 christos #include "mountd.h" 110 1.129 christos 111 1.1 cgd /* 112 1.1 cgd * Structures for keeping the mount list and export list 113 1.1 cgd */ 114 1.1 cgd struct mountlist { 115 1.1 cgd struct mountlist *ml_next; 116 1.47 christos char ml_host[RPCMNT_NAMELEN + 1]; 117 1.47 christos char ml_dirp[RPCMNT_PATHLEN + 1]; 118 1.47 christos int ml_flag;/* XXX more flags (same as dp_flag) */ 119 1.1 cgd }; 120 1.1 cgd 121 1.12 mycroft struct dirlist { 122 1.47 christos struct dirlist *dp_left; 123 1.47 christos struct dirlist *dp_right; 124 1.47 christos int dp_flag; 125 1.47 christos struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 126 1.47 christos char dp_dirp[1]; /* Actually malloc'd to size of dir */ 127 1.12 mycroft }; 128 1.12 mycroft /* dp_flag bits */ 129 1.12 mycroft #define DP_DEFSET 0x1 130 1.31 fvdl #define DP_HOSTSET 0x2 131 1.31 fvdl #define DP_KERB 0x4 132 1.37 fvdl #define DP_NORESMNT 0x8 133 1.12 mycroft 134 1.1 cgd struct exportlist { 135 1.1 cgd struct exportlist *ex_next; 136 1.47 christos struct dirlist *ex_dirl; 137 1.47 christos struct dirlist *ex_defdir; 138 1.47 christos int ex_flag; 139 1.47 christos fsid_t ex_fs; 140 1.47 christos char *ex_fsdir; 141 1.47 christos char *ex_indexfile; 142 1.12 mycroft }; 143 1.12 mycroft /* ex_flag bits */ 144 1.12 mycroft #define EX_LINKED 0x1 145 1.12 mycroft 146 1.12 mycroft union grouptypes { 147 1.64 fvdl struct addrinfo *gt_addrinfo; 148 1.47 christos struct netmsk gt_net; 149 1.1 cgd }; 150 1.1 cgd 151 1.1 cgd struct grouplist { 152 1.47 christos int gr_type; 153 1.12 mycroft union grouptypes gr_ptr; 154 1.1 cgd struct grouplist *gr_next; 155 1.12 mycroft }; 156 1.12 mycroft /* Group types */ 157 1.12 mycroft #define GT_NULL 0x0 158 1.12 mycroft #define GT_HOST 0x1 159 1.12 mycroft #define GT_NET 0x2 160 1.12 mycroft 161 1.12 mycroft struct hostlist { 162 1.47 christos int ht_flag;/* Uses DP_xx bits */ 163 1.12 mycroft struct grouplist *ht_grp; 164 1.47 christos struct hostlist *ht_next; 165 1.1 cgd }; 166 1.1 cgd 167 1.31 fvdl struct fhreturn { 168 1.47 christos int fhr_flag; 169 1.47 christos int fhr_vers; 170 1.111 yamt size_t fhr_fhsize; 171 1.111 yamt union { 172 1.111 yamt uint8_t v2[NFSX_V2FH]; 173 1.111 yamt uint8_t v3[NFSX_V3FHMAX]; 174 1.111 yamt } fhr_fh; 175 1.31 fvdl }; 176 1.31 fvdl 177 1.1 cgd /* Global defs */ 178 1.122 joerg static char *add_expdir(struct dirlist **, char *, int); 179 1.122 joerg static void add_dlist(struct dirlist **, struct dirlist *, 180 1.122 joerg struct grouplist *, int); 181 1.122 joerg static void add_mlist(char *, char *, int); 182 1.122 joerg static int check_dirpath(const char *, size_t, char *); 183 1.122 joerg static int check_options(const char *, size_t, struct dirlist *); 184 1.122 joerg static int chk_host(struct dirlist *, struct sockaddr *, int *, int *); 185 1.122 joerg static int del_mlist(char *, char *, struct sockaddr *); 186 1.122 joerg static struct dirlist *dirp_search(struct dirlist *, char *); 187 1.122 joerg static int do_nfssvc(const char *, size_t, struct exportlist *, 188 1.122 joerg struct grouplist *, int, struct uucred *, char *, int, struct statvfs *); 189 1.122 joerg static int do_opt(const char *, size_t, char **, char **, 190 1.122 joerg struct exportlist *, struct grouplist *, int *, int *, struct uucred *); 191 1.122 joerg static struct exportlist *ex_search(fsid_t *); 192 1.122 joerg static int parse_directory(const char *, size_t, struct grouplist *, 193 1.122 joerg int, char *, struct exportlist **, struct statvfs *); 194 1.122 joerg static int parse_host_netgroup(const char *, size_t, struct exportlist *, 195 1.122 joerg struct grouplist *, char *, int *, struct grouplist **); 196 1.122 joerg static struct exportlist *get_exp(void); 197 1.122 joerg static void free_dir(struct dirlist *); 198 1.122 joerg static void free_exp(struct exportlist *); 199 1.122 joerg static void free_grp(struct grouplist *); 200 1.122 joerg static void free_host(struct hostlist *); 201 1.122 joerg static void get_exportlist(int); 202 1.122 joerg static int get_host(const char *, size_t, const char *, 203 1.122 joerg struct grouplist *); 204 1.122 joerg static struct hostlist *get_ht(void); 205 1.122 joerg static void get_mountlist(void); 206 1.122 joerg static void free_exp_grp(struct exportlist *, struct grouplist *); 207 1.122 joerg static struct grouplist *get_grp(void); 208 1.122 joerg static void hang_dirp(struct dirlist *, struct grouplist *, 209 1.122 joerg struct exportlist *, int); 210 1.122 joerg static void mntsrv(struct svc_req *, SVCXPRT *); 211 1.122 joerg static void nextfield(char **, char **); 212 1.122 joerg static void parsecred(char *, struct uucred *); 213 1.122 joerg static int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *); 214 1.122 joerg static int scan_tree(struct dirlist *, struct sockaddr *); 215 1.122 joerg __dead static void send_umntall(int); 216 1.122 joerg static int xdr_dir(XDR *, char *); 217 1.122 joerg static int xdr_explist(XDR *, caddr_t); 218 1.122 joerg static int xdr_fhs(XDR *, caddr_t); 219 1.122 joerg static int xdr_mlist(XDR *, caddr_t); 220 1.122 joerg static int bitcmp(void *, void *, int); 221 1.122 joerg static int netpartcmp(struct sockaddr *, struct sockaddr *, int); 222 1.122 joerg static int sacmp(struct sockaddr *, struct sockaddr *); 223 1.122 joerg static int allones(struct sockaddr_storage *, int); 224 1.122 joerg static void bind_resv_port(int, sa_family_t, in_port_t); 225 1.122 joerg __dead static void no_nfs(int); 226 1.47 christos static struct exportlist *exphead; 227 1.47 christos static struct mountlist *mlhead; 228 1.47 christos static struct grouplist *grphead; 229 1.134 hannken static char *const exnames_default[] = { __UNCONST(_PATH_EXPORTS), NULL }; 230 1.134 hannken static char *const *exnames; 231 1.79 christos static struct uucred def_anon = { 232 1.12 mycroft 1, 233 1.79 christos (uid_t) -2, 234 1.79 christos (gid_t) -2, 235 1.23 cgd 0, 236 1.118 gmcgarry { 0 } 237 1.12 mycroft }; 238 1.136 hannken static struct mountd_exports_list *mel_tab; 239 1.136 hannken static int mel_tab_len; 240 1.64 fvdl 241 1.129 christos int opt_flags; 242 1.70 fvdl static int have_v6 = 1; 243 1.129 christos const int ninumeric = NI_NUMERICHOST; 244 1.12 mycroft 245 1.131 joerg int mountd_debug = DEBUGGING; 246 1.47 christos #if 0 247 1.122 joerg static void SYSLOG(int, const char *,...); 248 1.47 christos #endif 249 1.1 cgd 250 1.1 cgd /* 251 1.90 thorpej * If this is non-zero, -noresvport and -noresvmnt are implied for 252 1.90 thorpej * each export. 253 1.90 thorpej */ 254 1.90 thorpej static int noprivports; 255 1.90 thorpej 256 1.128 christos #ifdef MOUNTD_RUMP 257 1.128 christos #define C2FD(_c_) ((int)(uintptr_t)(_c_)) 258 1.128 christos static int 259 1.128 christos rumpread(void *cookie, char *buf, int count) 260 1.128 christos { 261 1.128 christos 262 1.128 christos return rump_sys_read(C2FD(cookie), buf, count); 263 1.128 christos } 264 1.128 christos 265 1.128 christos static int 266 1.128 christos rumpwrite(void *cookie, const char *buf, int count) 267 1.128 christos { 268 1.128 christos 269 1.128 christos return rump_sys_write(C2FD(cookie), buf, count); 270 1.128 christos } 271 1.128 christos 272 1.128 christos static off_t 273 1.128 christos rumpseek(void *cookie, off_t off, int whence) 274 1.128 christos { 275 1.128 christos 276 1.128 christos return rump_sys_lseek(C2FD(cookie), off, whence); 277 1.128 christos } 278 1.128 christos 279 1.128 christos static int 280 1.128 christos rumpclose(void *cookie) 281 1.128 christos { 282 1.128 christos 283 1.128 christos return rump_sys_close(C2FD(cookie)); 284 1.128 christos } 285 1.128 christos 286 1.128 christos int __sflags(const char *, int *); /* XXX */ 287 1.128 christos static FILE * 288 1.128 christos rumpfopen(const char *path, const char *opts) 289 1.128 christos { 290 1.128 christos int fd, oflags; 291 1.128 christos 292 1.128 christos __sflags(opts, &oflags); 293 1.128 christos fd = rump_sys_open(path, oflags, 0777); 294 1.128 christos if (fd == -1) 295 1.128 christos return NULL; 296 1.128 christos 297 1.128 christos return funopen((void *)(uintptr_t)fd, 298 1.128 christos rumpread, rumpwrite, rumpseek, rumpclose); 299 1.128 christos } 300 1.128 christos 301 1.128 christos /* 302 1.128 christos * Make sure mountd signal handler is executed from a thread context 303 1.128 christos * instead of the signal handler. This avoids the signal handler 304 1.128 christos * ruining our kernel context. 305 1.128 christos */ 306 1.128 christos static sem_t exportsem; 307 1.128 christos static void 308 1.128 christos signal_get_exportlist(int sig) 309 1.128 christos { 310 1.128 christos 311 1.128 christos sem_post(&exportsem); 312 1.128 christos } 313 1.128 christos 314 1.128 christos static void * 315 1.128 christos exportlist_thread(void *arg) 316 1.128 christos { 317 1.128 christos 318 1.128 christos for (;;) { 319 1.128 christos sem_wait(&exportsem); 320 1.128 christos get_exportlist(0); 321 1.128 christos } 322 1.128 christos 323 1.128 christos return NULL; 324 1.128 christos } 325 1.128 christos #define statvfs1(a, b, c) rump_sys_statvfs1((a), (b), (c)) 326 1.128 christos #define getfh(a, b, c) rump_sys_getfh((a), (b), (c)) 327 1.128 christos #define nfssvc(a, b) rump_sys_nfssvc((a), (b)) 328 1.128 christos #define fopen(a, b) rumpfopen((a), (b)) 329 1.128 christos #define lstat(a, b) rump_sys_lstat((a), (b)) 330 1.128 christos #define stat(a, b) rump_sys_stat((a), (b)) 331 1.128 christos 332 1.90 thorpej /* 333 1.1 cgd * Mountd server for NFS mount protocol as described in: 334 1.1 cgd * NFS: Network File System Protocol Specification, RFC1094, Appendix A 335 1.1 cgd * The optional arguments are the exports file name 336 1.1 cgd * default: _PATH_EXPORTS 337 1.28 thorpej * "-d" to enable debugging 338 1.1 cgd * and "-n" to allow nonroot mount. 339 1.1 cgd */ 340 1.128 christos void *mountd_main(void *); 341 1.128 christos void * 342 1.128 christos mountd_main(void *arg) 343 1.128 christos #else 344 1.12 mycroft int 345 1.122 joerg main(int argc, char **argv) 346 1.128 christos #endif 347 1.1 cgd { 348 1.64 fvdl SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp; 349 1.64 fvdl struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; 350 1.64 fvdl int udpsock, tcpsock, udp6sock, tcp6sock; 351 1.128 christos int xcreated = 0; 352 1.128 christos int one = 1; 353 1.81 fvdl int maxrec = RPC_MAXDATASIZE; 354 1.96 christos in_port_t forcedport = 0; 355 1.80 christos #ifdef IPSEC 356 1.80 christos char *policy = NULL; 357 1.80 christos #define ADDOPTS "P:" 358 1.80 christos #else 359 1.80 christos #define ADDOPTS 360 1.80 christos #endif 361 1.128 christos #ifndef MOUNTD_RUMP 362 1.128 christos int s, c; 363 1.96 christos while ((c = getopt(argc, argv, "dNnrp:" ADDOPTS)) != -1) 364 1.1 cgd switch (c) { 365 1.80 christos #ifdef IPSEC 366 1.80 christos case 'P': 367 1.80 christos if (ipsecsetup_test(policy = optarg)) 368 1.80 christos errx(1, "Invalid ipsec policy `%s'", policy); 369 1.80 christos break; 370 1.80 christos #endif 371 1.96 christos case 'p': 372 1.96 christos /* A forced port "0" will dynamically allocate a port */ 373 1.96 christos forcedport = atoi(optarg); 374 1.96 christos break; 375 1.28 thorpej case 'd': 376 1.131 joerg mountd_debug = 1; 377 1.28 thorpej break; 378 1.90 thorpej case 'N': 379 1.90 thorpej noprivports = 1; 380 1.90 thorpej break; 381 1.44 mrg /* Compatibility */ 382 1.1 cgd case 'n': 383 1.31 fvdl case 'r': 384 1.31 fvdl break; 385 1.1 cgd default: 386 1.123 christos fprintf(stderr, "Usage: %s [-dN]" 387 1.80 christos #ifdef IPSEC 388 1.97 wiz " [-P policy]" 389 1.80 christos #endif 390 1.134 hannken " [-p port] [exportsfile ...]\n", getprogname()); 391 1.1 cgd exit(1); 392 1.1 cgd }; 393 1.1 cgd argc -= optind; 394 1.1 cgd argv += optind; 395 1.134 hannken if (argc > 0) 396 1.134 hannken exnames = argv; 397 1.44 mrg else 398 1.134 hannken exnames = exnames_default; 399 1.70 fvdl 400 1.70 fvdl s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 401 1.70 fvdl if (s < 0) 402 1.70 fvdl have_v6 = 0; 403 1.70 fvdl else 404 1.70 fvdl close(s); 405 1.128 christos (void)signal(SIGHUP, get_exportlist); 406 1.128 christos #else 407 1.128 christos extern sem_t gensem; 408 1.128 christos pthread_t ptdummy; 409 1.128 christos 410 1.128 christos svc_fdset_init(SVC_FDSET_MT); 411 1.128 christos 412 1.128 christos sem_init(&exportsem, 0, 0); 413 1.128 christos pthread_create(&ptdummy, NULL, exportlist_thread, NULL); 414 1.134 hannken exnames = exnames_default; 415 1.128 christos have_v6 = 0; 416 1.128 christos (void)signal(SIGHUP, signal_get_exportlist); 417 1.128 christos #endif 418 1.128 christos grphead = NULL; 419 1.128 christos exphead = NULL; 420 1.128 christos mlhead = NULL; 421 1.131 joerg openlog("mountd", LOG_PID | (mountd_debug ? LOG_PERROR : 0), LOG_DAEMON); 422 1.128 christos (void)signal(SIGSYS, no_nfs); 423 1.70 fvdl 424 1.131 joerg if (mountd_debug) 425 1.47 christos (void)fprintf(stderr, "Getting export list.\n"); 426 1.45 christos get_exportlist(0); 427 1.131 joerg if (mountd_debug) 428 1.47 christos (void)fprintf(stderr, "Getting mount list.\n"); 429 1.12 mycroft get_mountlist(); 430 1.131 joerg if (mountd_debug) 431 1.47 christos (void)fprintf(stderr, "Here we go.\n"); 432 1.45 christos (void)signal(SIGTERM, send_umntall); 433 1.64 fvdl 434 1.64 fvdl rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 435 1.64 fvdl rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 436 1.64 fvdl 437 1.64 fvdl udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 438 1.64 fvdl tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 439 1.64 fvdl udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 440 1.64 fvdl tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 441 1.64 fvdl 442 1.64 fvdl /* 443 1.64 fvdl * We're doing host-based access checks here, so don't allow 444 1.64 fvdl * v4-in-v6 to confuse things. The kernel will disable it 445 1.64 fvdl * by default on NFS sockets too. 446 1.64 fvdl */ 447 1.64 fvdl if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6, 448 1.78 itojun IPV6_V6ONLY, &one, sizeof one) < 0){ 449 1.64 fvdl syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); 450 1.1 cgd exit(1); 451 1.1 cgd } 452 1.64 fvdl if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6, 453 1.78 itojun IPV6_V6ONLY, &one, sizeof one) < 0){ 454 1.64 fvdl syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket"); 455 1.1 cgd exit(1); 456 1.1 cgd } 457 1.64 fvdl 458 1.64 fvdl udpconf = getnetconfigent("udp"); 459 1.64 fvdl tcpconf = getnetconfigent("tcp"); 460 1.64 fvdl udp6conf = getnetconfigent("udp6"); 461 1.64 fvdl tcp6conf = getnetconfigent("tcp6"); 462 1.64 fvdl 463 1.81 fvdl rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 464 1.81 fvdl 465 1.64 fvdl if (udpsock != -1 && udpconf != NULL) { 466 1.96 christos bind_resv_port(udpsock, AF_INET, forcedport); 467 1.80 christos #ifdef IPSEC 468 1.80 christos if (policy) 469 1.80 christos ipsecsetup(AF_INET, udpsock, policy); 470 1.80 christos #endif 471 1.64 fvdl udptransp = svc_dg_create(udpsock, 0, 0); 472 1.64 fvdl if (udptransp != NULL) { 473 1.64 fvdl if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1, 474 1.64 fvdl mntsrv, udpconf) || 475 1.64 fvdl !svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3, 476 1.64 fvdl mntsrv, udpconf)) 477 1.64 fvdl syslog(LOG_WARNING, "can't register UDP service"); 478 1.64 fvdl else 479 1.64 fvdl xcreated++; 480 1.64 fvdl } else 481 1.64 fvdl syslog(LOG_WARNING, "can't create UDP service"); 482 1.64 fvdl 483 1.64 fvdl } 484 1.64 fvdl 485 1.64 fvdl if (tcpsock != -1 && tcpconf != NULL) { 486 1.96 christos bind_resv_port(tcpsock, AF_INET, forcedport); 487 1.80 christos #ifdef IPSEC 488 1.80 christos if (policy) 489 1.80 christos ipsecsetup(AF_INET, tcpsock, policy); 490 1.80 christos #endif 491 1.64 fvdl listen(tcpsock, SOMAXCONN); 492 1.81 fvdl tcptransp = svc_vc_create(tcpsock, RPC_MAXDATASIZE, 493 1.81 fvdl RPC_MAXDATASIZE); 494 1.64 fvdl if (tcptransp != NULL) { 495 1.64 fvdl if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1, 496 1.64 fvdl mntsrv, tcpconf) || 497 1.69 hannken !svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3, 498 1.64 fvdl mntsrv, tcpconf)) 499 1.64 fvdl syslog(LOG_WARNING, "can't register TCP service"); 500 1.64 fvdl else 501 1.64 fvdl xcreated++; 502 1.64 fvdl } else 503 1.64 fvdl syslog(LOG_WARNING, "can't create TCP service"); 504 1.64 fvdl 505 1.64 fvdl } 506 1.64 fvdl 507 1.64 fvdl if (udp6sock != -1 && udp6conf != NULL) { 508 1.96 christos bind_resv_port(udp6sock, AF_INET6, forcedport); 509 1.80 christos #ifdef IPSEC 510 1.80 christos if (policy) 511 1.80 christos ipsecsetup(AF_INET6, tcpsock, policy); 512 1.80 christos #endif 513 1.64 fvdl udp6transp = svc_dg_create(udp6sock, 0, 0); 514 1.64 fvdl if (udp6transp != NULL) { 515 1.64 fvdl if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1, 516 1.64 fvdl mntsrv, udp6conf) || 517 1.64 fvdl !svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3, 518 1.64 fvdl mntsrv, udp6conf)) 519 1.64 fvdl syslog(LOG_WARNING, "can't register UDP6 service"); 520 1.64 fvdl else 521 1.64 fvdl xcreated++; 522 1.64 fvdl } else 523 1.64 fvdl syslog(LOG_WARNING, "can't create UDP6 service"); 524 1.64 fvdl 525 1.64 fvdl } 526 1.64 fvdl 527 1.64 fvdl if (tcp6sock != -1 && tcp6conf != NULL) { 528 1.96 christos bind_resv_port(tcp6sock, AF_INET6, forcedport); 529 1.80 christos #ifdef IPSEC 530 1.80 christos if (policy) 531 1.80 christos ipsecsetup(AF_INET6, tcpsock, policy); 532 1.80 christos #endif 533 1.73 itojun listen(tcp6sock, SOMAXCONN); 534 1.81 fvdl tcp6transp = svc_vc_create(tcp6sock, RPC_MAXDATASIZE, 535 1.81 fvdl RPC_MAXDATASIZE); 536 1.64 fvdl if (tcp6transp != NULL) { 537 1.64 fvdl if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1, 538 1.64 fvdl mntsrv, tcp6conf) || 539 1.64 fvdl !svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3, 540 1.64 fvdl mntsrv, tcp6conf)) 541 1.64 fvdl syslog(LOG_WARNING, "can't register TCP6 service"); 542 1.64 fvdl else 543 1.64 fvdl xcreated++; 544 1.64 fvdl } else 545 1.64 fvdl syslog(LOG_WARNING, "can't create TCP6 service"); 546 1.64 fvdl 547 1.64 fvdl } 548 1.64 fvdl 549 1.64 fvdl if (xcreated == 0) { 550 1.64 fvdl syslog(LOG_ERR, "could not create any services"); 551 1.64 fvdl exit(1); 552 1.64 fvdl } 553 1.64 fvdl 554 1.131 joerg if (mountd_debug == 0) { 555 1.126 gson daemon(0, 0); 556 1.126 gson (void)signal(SIGINT, SIG_IGN); 557 1.126 gson (void)signal(SIGQUIT, SIG_IGN); 558 1.126 gson } 559 1.127 jnemeth pidfile(NULL); 560 1.128 christos #ifdef MOUNTD_RUMP 561 1.128 christos sem_post(&gensem); 562 1.128 christos #endif 563 1.1 cgd svc_run(); 564 1.1 cgd syslog(LOG_ERR, "Mountd died"); 565 1.1 cgd exit(1); 566 1.1 cgd } 567 1.1 cgd 568 1.1 cgd /* 569 1.1 cgd * The mount rpc service 570 1.1 cgd */ 571 1.6 brezak void 572 1.122 joerg mntsrv(struct svc_req *rqstp, SVCXPRT *transp) 573 1.1 cgd { 574 1.12 mycroft struct exportlist *ep; 575 1.12 mycroft struct dirlist *dp; 576 1.31 fvdl struct fhreturn fhr; 577 1.47 christos struct stat stb; 578 1.87 christos struct statvfs fsb; 579 1.64 fvdl char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 580 1.64 fvdl int lookup_failed = 1; 581 1.64 fvdl struct sockaddr *saddr; 582 1.47 christos u_short sport; 583 1.119 lukem char rpcpath[RPCMNT_PATHLEN + 1], rdirpath[MAXPATHLEN]; 584 1.47 christos long bad = EACCES; 585 1.47 christos int defset, hostset, ret; 586 1.47 christos sigset_t sighup_mask; 587 1.64 fvdl struct sockaddr_in6 *sin6; 588 1.64 fvdl struct sockaddr_in *sin; 589 1.107 martin size_t fh_size; 590 1.1 cgd 591 1.47 christos (void)sigemptyset(&sighup_mask); 592 1.47 christos (void)sigaddset(&sighup_mask, SIGHUP); 593 1.64 fvdl saddr = svc_getrpccaller(transp)->buf; 594 1.64 fvdl switch (saddr->sa_family) { 595 1.64 fvdl case AF_INET6: 596 1.64 fvdl sin6 = (struct sockaddr_in6 *)saddr; 597 1.64 fvdl sport = ntohs(sin6->sin6_port); 598 1.64 fvdl break; 599 1.64 fvdl case AF_INET: 600 1.64 fvdl sin = (struct sockaddr_in *)saddr; 601 1.64 fvdl sport = ntohs(sin->sin_port); 602 1.64 fvdl break; 603 1.64 fvdl default: 604 1.64 fvdl syslog(LOG_ERR, "request from unknown address family"); 605 1.64 fvdl return; 606 1.64 fvdl } 607 1.64 fvdl lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 608 1.64 fvdl NULL, 0, 0); 609 1.75 itojun if (getnameinfo(saddr, saddr->sa_len, numerichost, 610 1.75 itojun sizeof numerichost, NULL, 0, ninumeric) != 0) 611 1.75 itojun strlcpy(numerichost, "?", sizeof(numerichost)); 612 1.41 lukem ret = 0; 613 1.1 cgd switch (rqstp->rq_proc) { 614 1.1 cgd case NULLPROC: 615 1.121 plunky if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 616 1.1 cgd syslog(LOG_ERR, "Can't send reply"); 617 1.1 cgd return; 618 1.45 christos case MOUNTPROC_MNT: 619 1.131 joerg if (mountd_debug) 620 1.72 thorpej fprintf(stderr, 621 1.72 thorpej "got mount request from %s\n", numerichost); 622 1.12 mycroft if (!svc_getargs(transp, xdr_dir, rpcpath)) { 623 1.131 joerg if (mountd_debug) 624 1.72 thorpej fprintf(stderr, "-> garbage args\n"); 625 1.1 cgd svcerr_decode(transp); 626 1.1 cgd return; 627 1.1 cgd } 628 1.131 joerg if (mountd_debug) 629 1.64 fvdl fprintf(stderr, 630 1.72 thorpej "-> rpcpath: %s\n", rpcpath); 631 1.12 mycroft /* 632 1.14 cgd * Get the real pathname and make sure it is a file or 633 1.14 cgd * directory that exists. 634 1.12 mycroft */ 635 1.128 christos if ( 636 1.128 christos #ifndef MOUNTD_RUMP 637 1.128 christos realpath(rpcpath, rdirpath) == NULL || 638 1.128 christos #else 639 1.128 christos strcpy(rdirpath, rpcpath) == NULL || 640 1.128 christos #endif 641 1.119 lukem stat(rdirpath, &stb) < 0 || 642 1.12 mycroft (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) || 643 1.128 christos statvfs1(rdirpath, &fsb, ST_WAIT) < 0) { 644 1.47 christos (void)chdir("/"); /* Just in case realpath doesn't */ 645 1.131 joerg if (mountd_debug) 646 1.72 thorpej (void)fprintf(stderr, "-> stat failed on %s\n", 647 1.119 lukem rdirpath); 648 1.121 plunky if (!svc_sendreply(transp, (xdrproc_t)xdr_long, (caddr_t) &bad)) 649 1.1 cgd syslog(LOG_ERR, "Can't send reply"); 650 1.1 cgd return; 651 1.1 cgd } 652 1.131 joerg if (mountd_debug) 653 1.72 thorpej fprintf(stderr, 654 1.119 lukem "-> dirpath: %s\n", rdirpath); 655 1.1 cgd /* Check in the exports list */ 656 1.47 christos (void)sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 657 1.87 christos ep = ex_search(&fsb.f_fsidx); 658 1.31 fvdl hostset = defset = 0; 659 1.64 fvdl if (ep && (chk_host(ep->ex_defdir, saddr, &defset, 660 1.119 lukem &hostset) || ((dp = dirp_search(ep->ex_dirl, rdirpath)) && 661 1.64 fvdl chk_host(dp, saddr, &defset, &hostset)) || 662 1.64 fvdl (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 663 1.64 fvdl scan_tree(ep->ex_dirl, saddr) == 0))) { 664 1.99 yamt if ((hostset & DP_HOSTSET) == 0) { 665 1.99 yamt hostset = defset; 666 1.99 yamt } 667 1.36 fvdl if (sport >= IPPORT_RESERVED && 668 1.37 fvdl !(hostset & DP_NORESMNT)) { 669 1.36 fvdl syslog(LOG_NOTICE, 670 1.47 christos "Refused mount RPC from host %s port %d", 671 1.64 fvdl numerichost, sport); 672 1.36 fvdl svcerr_weakauth(transp); 673 1.44 mrg goto out; 674 1.36 fvdl } 675 1.99 yamt fhr.fhr_flag = hostset; 676 1.31 fvdl fhr.fhr_vers = rqstp->rq_vers; 677 1.12 mycroft /* Get the file handle */ 678 1.111 yamt memset(&fhr.fhr_fh, 0, sizeof(fhr.fhr_fh)); /* for v2 */ 679 1.111 yamt fh_size = sizeof(fhr.fhr_fh); 680 1.119 lukem if (getfh(rdirpath, &fhr.fhr_fh, &fh_size) < 0) { 681 1.12 mycroft bad = errno; 682 1.119 lukem syslog(LOG_ERR, "Can't get fh for %s", rdirpath); 683 1.121 plunky if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 684 1.47 christos (char *)&bad)) 685 1.12 mycroft syslog(LOG_ERR, "Can't send reply"); 686 1.44 mrg goto out; 687 1.1 cgd } 688 1.111 yamt if ((fhr.fhr_vers == 1 && fh_size > NFSX_V2FH) || 689 1.111 yamt fh_size > NFSX_V3FHMAX) { 690 1.111 yamt bad = EINVAL; /* XXX */ 691 1.121 plunky if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 692 1.111 yamt (char *)&bad)) 693 1.111 yamt syslog(LOG_ERR, "Can't send reply"); 694 1.111 yamt goto out; 695 1.111 yamt } 696 1.111 yamt fhr.fhr_fhsize = fh_size; 697 1.121 plunky if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, (char *) &fhr)) 698 1.12 mycroft syslog(LOG_ERR, "Can't send reply"); 699 1.64 fvdl if (!lookup_failed) 700 1.119 lukem add_mlist(host, rdirpath, hostset); 701 1.12 mycroft else 702 1.119 lukem add_mlist(numerichost, rdirpath, hostset); 703 1.131 joerg if (mountd_debug) 704 1.47 christos (void)fprintf(stderr, "Mount successful.\n"); 705 1.12 mycroft } else { 706 1.121 plunky if (!svc_sendreply(transp, (xdrproc_t)xdr_long, (caddr_t) &bad)) 707 1.1 cgd syslog(LOG_ERR, "Can't send reply"); 708 1.1 cgd } 709 1.44 mrg out: 710 1.47 christos (void)sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 711 1.1 cgd return; 712 1.45 christos case MOUNTPROC_DUMP: 713 1.121 plunky if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, NULL)) 714 1.1 cgd syslog(LOG_ERR, "Can't send reply"); 715 1.1 cgd return; 716 1.45 christos case MOUNTPROC_UMNT: 717 1.119 lukem if (!svc_getargs(transp, xdr_dir, rdirpath)) { 718 1.36 fvdl svcerr_decode(transp); 719 1.1 cgd return; 720 1.1 cgd } 721 1.64 fvdl if (!lookup_failed) 722 1.119 lukem ret = del_mlist(host, rdirpath, saddr); 723 1.119 lukem ret |= del_mlist(numerichost, rdirpath, saddr); 724 1.36 fvdl if (ret) { 725 1.36 fvdl svcerr_weakauth(transp); 726 1.1 cgd return; 727 1.1 cgd } 728 1.121 plunky if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 729 1.1 cgd syslog(LOG_ERR, "Can't send reply"); 730 1.36 fvdl return; 731 1.45 christos case MOUNTPROC_UMNTALL: 732 1.64 fvdl if (!lookup_failed) 733 1.64 fvdl ret = del_mlist(host, NULL, saddr); 734 1.64 fvdl ret |= del_mlist(numerichost, NULL, saddr); 735 1.36 fvdl if (ret) { 736 1.1 cgd svcerr_weakauth(transp); 737 1.1 cgd return; 738 1.1 cgd } 739 1.121 plunky if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 740 1.1 cgd syslog(LOG_ERR, "Can't send reply"); 741 1.1 cgd return; 742 1.45 christos case MOUNTPROC_EXPORT: 743 1.45 christos case MOUNTPROC_EXPORTALL: 744 1.121 plunky if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, NULL)) 745 1.1 cgd syslog(LOG_ERR, "Can't send reply"); 746 1.1 cgd return; 747 1.45 christos 748 1.45 christos 749 1.1 cgd default: 750 1.1 cgd svcerr_noproc(transp); 751 1.1 cgd return; 752 1.1 cgd } 753 1.1 cgd } 754 1.1 cgd 755 1.1 cgd /* 756 1.1 cgd * Xdr conversion for a dirpath string 757 1.1 cgd */ 758 1.47 christos static int 759 1.122 joerg xdr_dir(XDR *xdrsp, char *dirp) 760 1.1 cgd { 761 1.44 mrg 762 1.12 mycroft return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 763 1.1 cgd } 764 1.1 cgd 765 1.1 cgd /* 766 1.31 fvdl * Xdr routine to generate file handle reply 767 1.1 cgd */ 768 1.47 christos static int 769 1.122 joerg xdr_fhs(XDR *xdrsp, caddr_t cp) 770 1.1 cgd { 771 1.47 christos struct fhreturn *fhrp = (struct fhreturn *) cp; 772 1.31 fvdl long ok = 0, len, auth; 773 1.1 cgd 774 1.1 cgd if (!xdr_long(xdrsp, &ok)) 775 1.1 cgd return (0); 776 1.31 fvdl switch (fhrp->fhr_vers) { 777 1.31 fvdl case 1: 778 1.31 fvdl return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 779 1.31 fvdl case 3: 780 1.111 yamt len = fhrp->fhr_fhsize; 781 1.31 fvdl if (!xdr_long(xdrsp, &len)) 782 1.31 fvdl return (0); 783 1.31 fvdl if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 784 1.31 fvdl return (0); 785 1.31 fvdl if (fhrp->fhr_flag & DP_KERB) 786 1.31 fvdl auth = RPCAUTH_KERB4; 787 1.31 fvdl else 788 1.31 fvdl auth = RPCAUTH_UNIX; 789 1.31 fvdl len = 1; 790 1.31 fvdl if (!xdr_long(xdrsp, &len)) 791 1.31 fvdl return (0); 792 1.31 fvdl return (xdr_long(xdrsp, &auth)); 793 1.31 fvdl }; 794 1.31 fvdl return (0); 795 1.1 cgd } 796 1.1 cgd 797 1.12 mycroft int 798 1.122 joerg xdr_mlist(XDR *xdrsp, caddr_t cp) 799 1.1 cgd { 800 1.12 mycroft struct mountlist *mlp; 801 1.120 pooka int trueval = 1; 802 1.120 pooka int falseval = 0; 803 1.1 cgd char *strp; 804 1.1 cgd 805 1.1 cgd mlp = mlhead; 806 1.1 cgd while (mlp) { 807 1.120 pooka if (!xdr_bool(xdrsp, &trueval)) 808 1.1 cgd return (0); 809 1.1 cgd strp = &mlp->ml_host[0]; 810 1.12 mycroft if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 811 1.1 cgd return (0); 812 1.1 cgd strp = &mlp->ml_dirp[0]; 813 1.12 mycroft if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 814 1.1 cgd return (0); 815 1.1 cgd mlp = mlp->ml_next; 816 1.1 cgd } 817 1.120 pooka if (!xdr_bool(xdrsp, &falseval)) 818 1.1 cgd return (0); 819 1.1 cgd return (1); 820 1.1 cgd } 821 1.1 cgd 822 1.1 cgd /* 823 1.1 cgd * Xdr conversion for export list 824 1.1 cgd */ 825 1.12 mycroft int 826 1.122 joerg xdr_explist(XDR *xdrsp, caddr_t cp) 827 1.1 cgd { 828 1.12 mycroft struct exportlist *ep; 829 1.120 pooka int falseval = 0; 830 1.20 mycroft int putdef; 831 1.31 fvdl sigset_t sighup_mask; 832 1.1 cgd 833 1.47 christos (void)sigemptyset(&sighup_mask); 834 1.47 christos (void)sigaddset(&sighup_mask, SIGHUP); 835 1.47 christos (void)sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 836 1.12 mycroft ep = exphead; 837 1.12 mycroft while (ep) { 838 1.12 mycroft putdef = 0; 839 1.12 mycroft if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 840 1.1 cgd goto errout; 841 1.12 mycroft if (ep->ex_defdir && putdef == 0 && 842 1.47 christos put_exlist(ep->ex_defdir, xdrsp, NULL, &putdef)) 843 1.1 cgd goto errout; 844 1.1 cgd ep = ep->ex_next; 845 1.1 cgd } 846 1.47 christos (void)sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 847 1.120 pooka if (!xdr_bool(xdrsp, &falseval)) 848 1.1 cgd return (0); 849 1.1 cgd return (1); 850 1.1 cgd errout: 851 1.47 christos (void)sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 852 1.1 cgd return (0); 853 1.1 cgd } 854 1.1 cgd 855 1.12 mycroft /* 856 1.12 mycroft * Called from xdr_explist() to traverse the tree and export the 857 1.44 mrg * directory paths. Assumes SIGHUP has already been masked. 858 1.12 mycroft */ 859 1.12 mycroft int 860 1.122 joerg put_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp) 861 1.12 mycroft { 862 1.12 mycroft struct grouplist *grp; 863 1.12 mycroft struct hostlist *hp; 864 1.120 pooka int trueval = 1; 865 1.120 pooka int falseval = 0; 866 1.12 mycroft int gotalldir = 0; 867 1.12 mycroft char *strp; 868 1.12 mycroft 869 1.12 mycroft if (dp) { 870 1.12 mycroft if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) 871 1.12 mycroft return (1); 872 1.120 pooka if (!xdr_bool(xdrsp, &trueval)) 873 1.12 mycroft return (1); 874 1.12 mycroft strp = dp->dp_dirp; 875 1.12 mycroft if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 876 1.12 mycroft return (1); 877 1.12 mycroft if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 878 1.12 mycroft gotalldir = 1; 879 1.12 mycroft *putdefp = 1; 880 1.12 mycroft } 881 1.12 mycroft if ((dp->dp_flag & DP_DEFSET) == 0 && 882 1.12 mycroft (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 883 1.12 mycroft hp = dp->dp_hosts; 884 1.12 mycroft while (hp) { 885 1.12 mycroft grp = hp->ht_grp; 886 1.12 mycroft if (grp->gr_type == GT_HOST) { 887 1.120 pooka if (!xdr_bool(xdrsp, &trueval)) 888 1.12 mycroft return (1); 889 1.64 fvdl strp = 890 1.64 fvdl grp->gr_ptr.gt_addrinfo->ai_canonname; 891 1.47 christos if (!xdr_string(xdrsp, &strp, 892 1.47 christos RPCMNT_NAMELEN)) 893 1.12 mycroft return (1); 894 1.12 mycroft } else if (grp->gr_type == GT_NET) { 895 1.120 pooka if (!xdr_bool(xdrsp, &trueval)) 896 1.12 mycroft return (1); 897 1.12 mycroft strp = grp->gr_ptr.gt_net.nt_name; 898 1.47 christos if (!xdr_string(xdrsp, &strp, 899 1.47 christos RPCMNT_NAMELEN)) 900 1.12 mycroft return (1); 901 1.12 mycroft } 902 1.12 mycroft hp = hp->ht_next; 903 1.47 christos if (gotalldir && hp == NULL) { 904 1.12 mycroft hp = adp->dp_hosts; 905 1.12 mycroft gotalldir = 0; 906 1.12 mycroft } 907 1.12 mycroft } 908 1.12 mycroft } 909 1.120 pooka if (!xdr_bool(xdrsp, &falseval)) 910 1.12 mycroft return (1); 911 1.12 mycroft if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) 912 1.12 mycroft return (1); 913 1.12 mycroft } 914 1.12 mycroft return (0); 915 1.12 mycroft } 916 1.12 mycroft 917 1.47 christos static int 918 1.122 joerg parse_host_netgroup(const char *line, size_t lineno, struct exportlist *ep, 919 1.122 joerg struct grouplist *tgrp, char *cp, int *has_host, struct grouplist **grp) 920 1.47 christos { 921 1.47 christos const char *hst, *usr, *dom; 922 1.47 christos int netgrp; 923 1.47 christos 924 1.47 christos if (ep == NULL) { 925 1.52 christos syslog(LOG_ERR, "\"%s\", line %ld: No current export", 926 1.52 christos line, (unsigned long)lineno); 927 1.52 christos return 0; 928 1.47 christos } 929 1.47 christos setnetgrent(cp); 930 1.47 christos netgrp = getnetgrent(&hst, &usr, &dom); 931 1.47 christos do { 932 1.47 christos if (*has_host) { 933 1.47 christos (*grp)->gr_next = get_grp(); 934 1.47 christos *grp = (*grp)->gr_next; 935 1.47 christos } 936 1.47 christos if (netgrp) { 937 1.52 christos if (hst == NULL) { 938 1.52 christos syslog(LOG_ERR, 939 1.52 christos "\"%s\", line %ld: No host in netgroup %s", 940 1.52 christos line, (unsigned long)lineno, cp); 941 1.52 christos goto bad; 942 1.52 christos } 943 1.52 christos if (get_host(line, lineno, hst, *grp)) 944 1.52 christos goto bad; 945 1.52 christos } else if (get_host(line, lineno, cp, *grp)) 946 1.52 christos goto bad; 947 1.47 christos *has_host = TRUE; 948 1.47 christos } while (netgrp && getnetgrent(&hst, &usr, &dom)); 949 1.47 christos 950 1.47 christos endnetgrent(); 951 1.47 christos return 1; 952 1.52 christos bad: 953 1.52 christos endnetgrent(); 954 1.52 christos return 0; 955 1.52 christos 956 1.47 christos } 957 1.47 christos 958 1.47 christos static int 959 1.122 joerg parse_directory(const char *line, size_t lineno, struct grouplist *tgrp, 960 1.122 joerg int got_nondir, char *cp, struct exportlist **ep, struct statvfs *fsp) 961 1.46 ross { 962 1.52 christos if (!check_dirpath(line, lineno, cp)) 963 1.52 christos return 0; 964 1.52 christos 965 1.128 christos if (statvfs1(cp, fsp, ST_WAIT) == -1) { 966 1.87 christos syslog(LOG_ERR, "\"%s\", line %ld: statvfs for `%s' failed: %m", 967 1.52 christos line, (unsigned long)lineno, cp); 968 1.47 christos return 0; 969 1.47 christos } 970 1.52 christos 971 1.130 christos if ((fsp->f_flag & MNT_AUTOMOUNTED) != 0) 972 1.130 christos syslog(LOG_ERR, "\"%s\", line %ld: Warning: exporting of " 973 1.130 christos "automounted fs %s not supported", 974 1.130 christos line, (unsigned long)lineno, cp); 975 1.47 christos if (got_nondir) { 976 1.52 christos syslog(LOG_ERR, 977 1.52 christos "\"%s\", line %ld: Directories must precede files", 978 1.52 christos line, (unsigned long)lineno); 979 1.47 christos return 0; 980 1.47 christos } 981 1.47 christos if (*ep) { 982 1.87 christos if ((*ep)->ex_fs.__fsid_val[0] != fsp->f_fsidx.__fsid_val[0] || 983 1.87 christos (*ep)->ex_fs.__fsid_val[1] != fsp->f_fsidx.__fsid_val[1]) { 984 1.52 christos syslog(LOG_ERR, 985 1.52 christos "\"%s\", line %ld: filesystem ids disagree", 986 1.52 christos line, (unsigned long)lineno); 987 1.47 christos return 0; 988 1.47 christos } 989 1.47 christos } else { 990 1.47 christos /* 991 1.47 christos * See if this directory is already 992 1.47 christos * in the list. 993 1.47 christos */ 994 1.87 christos *ep = ex_search(&fsp->f_fsidx); 995 1.47 christos if (*ep == NULL) { 996 1.47 christos *ep = get_exp(); 997 1.87 christos (*ep)->ex_fs = fsp->f_fsidx; 998 1.49 christos (*ep)->ex_fsdir = estrdup(fsp->f_mntonname); 999 1.131 joerg if (mountd_debug) 1000 1.47 christos (void)fprintf(stderr, 1001 1.47 christos "Making new ep fs=0x%x,0x%x\n", 1002 1.87 christos fsp->f_fsidx.__fsid_val[0], fsp->f_fsidx.__fsid_val[1]); 1003 1.47 christos } else { 1004 1.131 joerg if (mountd_debug) 1005 1.47 christos (void)fprintf(stderr, 1006 1.49 christos "Found ep fs=0x%x,0x%x\n", 1007 1.87 christos fsp->f_fsidx.__fsid_val[0], fsp->f_fsidx.__fsid_val[1]); 1008 1.47 christos } 1009 1.47 christos } 1010 1.47 christos 1011 1.47 christos return 1; 1012 1.46 ross } 1013 1.46 ross 1014 1.1 cgd 1015 1.133 hannken static void 1016 1.133 hannken get_exportlist_one(FILE *exp_file) 1017 1.1 cgd { 1018 1.12 mycroft struct exportlist *ep, *ep2; 1019 1.12 mycroft struct grouplist *grp, *tgrp; 1020 1.12 mycroft struct exportlist **epp; 1021 1.12 mycroft struct dirlist *dirhead; 1022 1.133 hannken struct statvfs fsb; 1023 1.64 fvdl struct addrinfo *ai; 1024 1.79 christos struct uucred anon; 1025 1.41 lukem char *cp, *endcp, *dirp, savedc; 1026 1.133 hannken int has_host, exflags, got_nondir, dirplen; 1027 1.47 christos char *line; 1028 1.48 christos size_t lineno = 0, len; 1029 1.47 christos 1030 1.41 lukem dirp = NULL; 1031 1.47 christos dirhead = NULL; 1032 1.47 christos while ((line = fparseln(exp_file, &len, &lineno, NULL, 0)) != NULL) { 1033 1.131 joerg if (mountd_debug) 1034 1.47 christos (void)fprintf(stderr, "Got line %s\n", line); 1035 1.1 cgd cp = line; 1036 1.1 cgd nextfield(&cp, &endcp); 1037 1.51 christos if (cp == endcp) 1038 1.76 enami goto nextline; /* skip empty line */ 1039 1.1 cgd /* 1040 1.12 mycroft * Set defaults. 1041 1.1 cgd */ 1042 1.12 mycroft has_host = FALSE; 1043 1.12 mycroft anon = def_anon; 1044 1.12 mycroft exflags = MNT_EXPORTED; 1045 1.12 mycroft got_nondir = 0; 1046 1.12 mycroft opt_flags = 0; 1047 1.47 christos ep = NULL; 1048 1.1 cgd 1049 1.90 thorpej if (noprivports) { 1050 1.90 thorpej opt_flags |= OP_NORESMNT | OP_NORESPORT; 1051 1.90 thorpej exflags |= MNT_EXNORESPORT; 1052 1.90 thorpej } 1053 1.90 thorpej 1054 1.1 cgd /* 1055 1.1 cgd * Create new exports list entry 1056 1.1 cgd */ 1057 1.47 christos len = endcp - cp; 1058 1.12 mycroft tgrp = grp = get_grp(); 1059 1.1 cgd while (len > 0) { 1060 1.12 mycroft if (len > RPCMNT_NAMELEN) { 1061 1.52 christos *endcp = '\0'; 1062 1.52 christos syslog(LOG_ERR, 1063 1.52 christos "\"%s\", line %ld: name `%s' is too long", 1064 1.52 christos line, (unsigned long)lineno, cp); 1065 1.52 christos goto badline; 1066 1.12 mycroft } 1067 1.47 christos switch (*cp) { 1068 1.47 christos case '-': 1069 1.47 christos /* 1070 1.47 christos * Option 1071 1.47 christos */ 1072 1.47 christos if (ep == NULL) { 1073 1.52 christos syslog(LOG_ERR, 1074 1.52 christos "\"%s\", line %ld: No current export list", 1075 1.52 christos line, (unsigned long)lineno); 1076 1.52 christos goto badline; 1077 1.12 mycroft } 1078 1.131 joerg if (mountd_debug) 1079 1.47 christos (void)fprintf(stderr, "doing opt %s\n", 1080 1.47 christos cp); 1081 1.47 christos got_nondir = 1; 1082 1.52 christos if (do_opt(line, lineno, &cp, &endcp, ep, grp, 1083 1.52 christos &has_host, &exflags, &anon)) 1084 1.52 christos goto badline; 1085 1.47 christos break; 1086 1.12 mycroft 1087 1.47 christos case '/': 1088 1.47 christos /* 1089 1.47 christos * Directory 1090 1.47 christos */ 1091 1.47 christos savedc = *endcp; 1092 1.47 christos *endcp = '\0'; 1093 1.47 christos 1094 1.47 christos if (!parse_directory(line, lineno, tgrp, 1095 1.49 christos got_nondir, cp, &ep, &fsb)) 1096 1.52 christos goto badline; 1097 1.12 mycroft /* 1098 1.12 mycroft * Add dirpath to export mount point. 1099 1.12 mycroft */ 1100 1.12 mycroft dirp = add_expdir(&dirhead, cp, len); 1101 1.12 mycroft dirplen = len; 1102 1.12 mycroft 1103 1.47 christos *endcp = savedc; 1104 1.47 christos break; 1105 1.47 christos 1106 1.47 christos default: 1107 1.47 christos /* 1108 1.47 christos * Host or netgroup. 1109 1.47 christos */ 1110 1.47 christos savedc = *endcp; 1111 1.47 christos *endcp = '\0'; 1112 1.47 christos 1113 1.47 christos if (!parse_host_netgroup(line, lineno, ep, 1114 1.47 christos tgrp, cp, &has_host, &grp)) 1115 1.52 christos goto badline; 1116 1.47 christos 1117 1.47 christos got_nondir = 1; 1118 1.47 christos 1119 1.47 christos *endcp = savedc; 1120 1.47 christos break; 1121 1.1 cgd } 1122 1.47 christos 1123 1.1 cgd cp = endcp; 1124 1.1 cgd nextfield(&cp, &endcp); 1125 1.1 cgd len = endcp - cp; 1126 1.1 cgd } 1127 1.52 christos if (check_options(line, lineno, dirhead)) 1128 1.52 christos goto badline; 1129 1.52 christos 1130 1.12 mycroft if (!has_host) { 1131 1.12 mycroft grp->gr_type = GT_HOST; 1132 1.131 joerg if (mountd_debug) 1133 1.47 christos (void)fprintf(stderr, 1134 1.47 christos "Adding a default entry\n"); 1135 1.12 mycroft /* add a default group and make the grp list NULL */ 1136 1.64 fvdl ai = emalloc(sizeof(struct addrinfo)); 1137 1.64 fvdl ai->ai_flags = 0; 1138 1.64 fvdl ai->ai_family = AF_INET; /* XXXX */ 1139 1.64 fvdl ai->ai_socktype = SOCK_DGRAM; 1140 1.64 fvdl /* setting the length to 0 will match anything */ 1141 1.64 fvdl ai->ai_addrlen = 0; 1142 1.64 fvdl ai->ai_flags = AI_CANONNAME; 1143 1.64 fvdl ai->ai_canonname = estrdup("Default"); 1144 1.64 fvdl ai->ai_addr = NULL; 1145 1.64 fvdl ai->ai_next = NULL; 1146 1.64 fvdl grp->gr_ptr.gt_addrinfo = ai; 1147 1.12 mycroft 1148 1.12 mycroft } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 1149 1.47 christos /* 1150 1.47 christos * Don't allow a network export coincide with a list of 1151 1.47 christos * host(s) on the same line. 1152 1.47 christos */ 1153 1.52 christos syslog(LOG_ERR, 1154 1.52 christos "\"%s\", line %ld: Mixed exporting of networks and hosts is disallowed", 1155 1.52 christos line, (unsigned long)lineno); 1156 1.52 christos goto badline; 1157 1.12 mycroft } 1158 1.12 mycroft /* 1159 1.12 mycroft * Loop through hosts, pushing the exports into the kernel. 1160 1.12 mycroft * After loop, tgrp points to the start of the list and 1161 1.12 mycroft * grp points to the last entry in the list. 1162 1.12 mycroft */ 1163 1.12 mycroft grp = tgrp; 1164 1.12 mycroft do { 1165 1.98 jmmv if (do_nfssvc(line, lineno, ep, grp, exflags, &anon, 1166 1.52 christos dirp, dirplen, &fsb)) 1167 1.52 christos goto badline; 1168 1.12 mycroft } while (grp->gr_next && (grp = grp->gr_next)); 1169 1.12 mycroft 1170 1.12 mycroft /* 1171 1.12 mycroft * Success. Update the data structures. 1172 1.12 mycroft */ 1173 1.12 mycroft if (has_host) { 1174 1.31 fvdl hang_dirp(dirhead, tgrp, ep, opt_flags); 1175 1.12 mycroft grp->gr_next = grphead; 1176 1.12 mycroft grphead = tgrp; 1177 1.12 mycroft } else { 1178 1.47 christos hang_dirp(dirhead, NULL, ep, opt_flags); 1179 1.105 christos free_grp(tgrp); 1180 1.12 mycroft } 1181 1.105 christos tgrp = NULL; 1182 1.47 christos dirhead = NULL; 1183 1.12 mycroft if ((ep->ex_flag & EX_LINKED) == 0) { 1184 1.12 mycroft ep2 = exphead; 1185 1.12 mycroft epp = &exphead; 1186 1.12 mycroft 1187 1.12 mycroft /* 1188 1.12 mycroft * Insert in the list in alphabetical order. 1189 1.12 mycroft */ 1190 1.12 mycroft while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 1191 1.12 mycroft epp = &ep2->ex_next; 1192 1.12 mycroft ep2 = ep2->ex_next; 1193 1.12 mycroft } 1194 1.12 mycroft if (ep2) 1195 1.12 mycroft ep->ex_next = ep2; 1196 1.12 mycroft *epp = ep; 1197 1.12 mycroft ep->ex_flag |= EX_LINKED; 1198 1.12 mycroft } 1199 1.52 christos goto nextline; 1200 1.52 christos badline: 1201 1.52 christos free_exp_grp(ep, grp); 1202 1.12 mycroft nextline: 1203 1.12 mycroft if (dirhead) { 1204 1.12 mycroft free_dir(dirhead); 1205 1.47 christos dirhead = NULL; 1206 1.12 mycroft } 1207 1.50 christos free(line); 1208 1.12 mycroft } 1209 1.133 hannken } 1210 1.133 hannken 1211 1.133 hannken /* 1212 1.136 hannken * Compare two export lists by path. 1213 1.136 hannken */ 1214 1.136 hannken static int 1215 1.136 hannken mel_compare(const void *a, const void *b) 1216 1.136 hannken { 1217 1.136 hannken const struct mountd_exports_list *mela = a; 1218 1.136 hannken const struct mountd_exports_list *melb = b; 1219 1.136 hannken 1220 1.136 hannken return strcmp(mela->mel_path, melb->mel_path); 1221 1.136 hannken } 1222 1.136 hannken 1223 1.136 hannken /* 1224 1.133 hannken * Get the export list 1225 1.133 hannken */ 1226 1.133 hannken /* ARGSUSED */ 1227 1.133 hannken void 1228 1.133 hannken get_exportlist(int n) 1229 1.133 hannken { 1230 1.133 hannken struct exportlist *ep, *ep2; 1231 1.133 hannken struct grouplist *grp, *tgrp; 1232 1.133 hannken struct statvfs *fsp; 1233 1.136 hannken int i, j; 1234 1.133 hannken FILE *exp_file; 1235 1.133 hannken 1236 1.133 hannken 1237 1.133 hannken /* 1238 1.133 hannken * First, get rid of the old list 1239 1.133 hannken */ 1240 1.133 hannken ep = exphead; 1241 1.133 hannken while (ep) { 1242 1.133 hannken ep2 = ep; 1243 1.133 hannken ep = ep->ex_next; 1244 1.133 hannken free_exp(ep2); 1245 1.133 hannken } 1246 1.133 hannken exphead = NULL; 1247 1.133 hannken 1248 1.133 hannken grp = grphead; 1249 1.133 hannken while (grp) { 1250 1.133 hannken tgrp = grp; 1251 1.133 hannken grp = grp->gr_next; 1252 1.133 hannken free_grp(tgrp); 1253 1.133 hannken } 1254 1.133 hannken grphead = NULL; 1255 1.133 hannken 1256 1.133 hannken /* 1257 1.133 hannken * And delete exports that are in the kernel for all local 1258 1.133 hannken * file systems. 1259 1.133 hannken */ 1260 1.136 hannken mel_tab_len = getmntinfo(&fsp, MNT_NOWAIT); 1261 1.136 hannken mel_tab = ecalloc(mel_tab_len, sizeof(*mel_tab)); 1262 1.136 hannken for (i = 0; i < mel_tab_len; i++) { 1263 1.136 hannken mel_tab[i].mel_path = estrdup(fsp[i].f_mntonname); 1264 1.136 hannken mel_tab[i].mel_nexports = 0; 1265 1.136 hannken mel_tab[i].mel_exports = NULL; 1266 1.133 hannken } 1267 1.136 hannken qsort(mel_tab, mel_tab_len, sizeof(mel_tab[0]), mel_compare); 1268 1.133 hannken 1269 1.133 hannken /* 1270 1.133 hannken * Read in the exports file and build the list, calling 1271 1.133 hannken * mount() as we go along to push the export rules into the kernel. 1272 1.133 hannken */ 1273 1.134 hannken for (i = 0; exnames[i] != NULL; i++) { 1274 1.134 hannken if ((exp_file = fopen(exnames[i], "r")) == NULL) { 1275 1.134 hannken /* 1276 1.134 hannken * Don't exit here; we can still reload the config 1277 1.134 hannken * after a SIGHUP. 1278 1.134 hannken */ 1279 1.134 hannken if (mountd_debug) 1280 1.134 hannken (void)fprintf(stderr, "Can't open %s: %s\n", 1281 1.134 hannken exnames[i], strerror(errno)); 1282 1.134 hannken continue; 1283 1.134 hannken } 1284 1.133 hannken 1285 1.134 hannken get_exportlist_one(exp_file); 1286 1.133 hannken 1287 1.134 hannken (void)fclose(exp_file); 1288 1.134 hannken } 1289 1.136 hannken 1290 1.136 hannken for (i = 0; i < mel_tab_len; i++) { 1291 1.136 hannken struct mountd_exports_list *mel = &mel_tab[i]; 1292 1.136 hannken 1293 1.136 hannken if (nfssvc(NFSSVC_REPLACEEXPORTSLIST, mel) == -1 && 1294 1.136 hannken (mel->mel_nexports > 0 || errno != EOPNOTSUPP)) 1295 1.136 hannken syslog(LOG_ERR, "Can't update exports for %s (%m)", 1296 1.136 hannken mel_tab[i].mel_path); 1297 1.137 hannken for (j = 0; j < (int)mel->mel_nexports; j++) { 1298 1.136 hannken struct export_args *export = &mel->mel_exports[j]; 1299 1.136 hannken 1300 1.136 hannken if (export->ex_indexfile) 1301 1.136 hannken free(export->ex_indexfile); 1302 1.136 hannken if (export->ex_addr) 1303 1.136 hannken free(export->ex_addr); 1304 1.136 hannken if (export->ex_mask) 1305 1.136 hannken free(export->ex_mask); 1306 1.136 hannken } 1307 1.136 hannken if (mel->mel_nexports > 0) 1308 1.136 hannken free(mel->mel_exports); 1309 1.136 hannken free(__UNCONST(mel->mel_path)); 1310 1.136 hannken } 1311 1.136 hannken free(mel_tab); 1312 1.136 hannken mel_tab_len = 0; 1313 1.12 mycroft } 1314 1.12 mycroft 1315 1.12 mycroft /* 1316 1.12 mycroft * Allocate an export list element 1317 1.12 mycroft */ 1318 1.47 christos static struct exportlist * 1319 1.122 joerg get_exp(void) 1320 1.12 mycroft { 1321 1.12 mycroft struct exportlist *ep; 1322 1.12 mycroft 1323 1.47 christos ep = emalloc(sizeof(struct exportlist)); 1324 1.47 christos (void)memset(ep, 0, sizeof(struct exportlist)); 1325 1.12 mycroft return (ep); 1326 1.12 mycroft } 1327 1.12 mycroft 1328 1.12 mycroft /* 1329 1.12 mycroft * Allocate a group list element 1330 1.12 mycroft */ 1331 1.47 christos static struct grouplist * 1332 1.122 joerg get_grp(void) 1333 1.12 mycroft { 1334 1.12 mycroft struct grouplist *gp; 1335 1.12 mycroft 1336 1.47 christos gp = emalloc(sizeof(struct grouplist)); 1337 1.47 christos (void)memset(gp, 0, sizeof(struct grouplist)); 1338 1.12 mycroft return (gp); 1339 1.12 mycroft } 1340 1.12 mycroft 1341 1.12 mycroft /* 1342 1.12 mycroft * Clean up upon an error in get_exportlist(). 1343 1.12 mycroft */ 1344 1.47 christos static void 1345 1.122 joerg free_exp_grp(struct exportlist *ep, struct grouplist *grp) 1346 1.12 mycroft { 1347 1.12 mycroft struct grouplist *tgrp; 1348 1.12 mycroft 1349 1.12 mycroft if (ep && (ep->ex_flag & EX_LINKED) == 0) 1350 1.12 mycroft free_exp(ep); 1351 1.12 mycroft while (grp) { 1352 1.12 mycroft tgrp = grp; 1353 1.12 mycroft grp = grp->gr_next; 1354 1.12 mycroft free_grp(tgrp); 1355 1.12 mycroft } 1356 1.12 mycroft } 1357 1.12 mycroft 1358 1.12 mycroft /* 1359 1.12 mycroft * Search the export list for a matching fs. 1360 1.12 mycroft */ 1361 1.47 christos static struct exportlist * 1362 1.122 joerg ex_search(fsid_t *fsid) 1363 1.12 mycroft { 1364 1.128 christos #ifdef MOUNTD_RUMP 1365 1.128 christos return exphead; 1366 1.128 christos #else 1367 1.12 mycroft struct exportlist *ep; 1368 1.12 mycroft 1369 1.12 mycroft ep = exphead; 1370 1.12 mycroft while (ep) { 1371 1.87 christos if (ep->ex_fs.__fsid_val[0] == fsid->__fsid_val[0] && 1372 1.87 christos ep->ex_fs.__fsid_val[1] == fsid->__fsid_val[1]) 1373 1.12 mycroft return (ep); 1374 1.12 mycroft ep = ep->ex_next; 1375 1.12 mycroft } 1376 1.12 mycroft return (ep); 1377 1.128 christos #endif 1378 1.12 mycroft } 1379 1.12 mycroft 1380 1.12 mycroft /* 1381 1.12 mycroft * Add a directory path to the list. 1382 1.12 mycroft */ 1383 1.47 christos static char * 1384 1.122 joerg add_expdir(struct dirlist **dpp, char *cp, int len) 1385 1.12 mycroft { 1386 1.12 mycroft struct dirlist *dp; 1387 1.12 mycroft 1388 1.47 christos dp = emalloc(sizeof(struct dirlist) + len); 1389 1.12 mycroft dp->dp_left = *dpp; 1390 1.47 christos dp->dp_right = NULL; 1391 1.12 mycroft dp->dp_flag = 0; 1392 1.47 christos dp->dp_hosts = NULL; 1393 1.47 christos (void)strcpy(dp->dp_dirp, cp); 1394 1.12 mycroft *dpp = dp; 1395 1.12 mycroft return (dp->dp_dirp); 1396 1.12 mycroft } 1397 1.12 mycroft 1398 1.12 mycroft /* 1399 1.12 mycroft * Hang the dir list element off the dirpath binary tree as required 1400 1.12 mycroft * and update the entry for host. 1401 1.12 mycroft */ 1402 1.12 mycroft void 1403 1.122 joerg hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, 1404 1.122 joerg int flags) 1405 1.12 mycroft { 1406 1.12 mycroft struct hostlist *hp; 1407 1.12 mycroft struct dirlist *dp2; 1408 1.12 mycroft 1409 1.31 fvdl if (flags & OP_ALLDIRS) { 1410 1.12 mycroft if (ep->ex_defdir) 1411 1.47 christos free(dp); 1412 1.12 mycroft else 1413 1.12 mycroft ep->ex_defdir = dp; 1414 1.47 christos if (grp == NULL) { 1415 1.12 mycroft ep->ex_defdir->dp_flag |= DP_DEFSET; 1416 1.31 fvdl if (flags & OP_KERB) 1417 1.31 fvdl ep->ex_defdir->dp_flag |= DP_KERB; 1418 1.37 fvdl if (flags & OP_NORESMNT) 1419 1.37 fvdl ep->ex_defdir->dp_flag |= DP_NORESMNT; 1420 1.47 christos } else 1421 1.47 christos while (grp) { 1422 1.47 christos hp = get_ht(); 1423 1.47 christos if (flags & OP_KERB) 1424 1.47 christos hp->ht_flag |= DP_KERB; 1425 1.47 christos if (flags & OP_NORESMNT) 1426 1.47 christos hp->ht_flag |= DP_NORESMNT; 1427 1.47 christos hp->ht_grp = grp; 1428 1.47 christos hp->ht_next = ep->ex_defdir->dp_hosts; 1429 1.47 christos ep->ex_defdir->dp_hosts = hp; 1430 1.47 christos grp = grp->gr_next; 1431 1.47 christos } 1432 1.12 mycroft } else { 1433 1.12 mycroft 1434 1.12 mycroft /* 1435 1.82 wiz * Loop through the directories adding them to the tree. 1436 1.12 mycroft */ 1437 1.12 mycroft while (dp) { 1438 1.12 mycroft dp2 = dp->dp_left; 1439 1.31 fvdl add_dlist(&ep->ex_dirl, dp, grp, flags); 1440 1.12 mycroft dp = dp2; 1441 1.12 mycroft } 1442 1.12 mycroft } 1443 1.12 mycroft } 1444 1.12 mycroft 1445 1.12 mycroft /* 1446 1.12 mycroft * Traverse the binary tree either updating a node that is already there 1447 1.12 mycroft * for the new directory or adding the new node. 1448 1.12 mycroft */ 1449 1.47 christos static void 1450 1.122 joerg add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, 1451 1.122 joerg int flags) 1452 1.12 mycroft { 1453 1.12 mycroft struct dirlist *dp; 1454 1.12 mycroft struct hostlist *hp; 1455 1.12 mycroft int cmp; 1456 1.12 mycroft 1457 1.12 mycroft dp = *dpp; 1458 1.12 mycroft if (dp) { 1459 1.12 mycroft cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 1460 1.12 mycroft if (cmp > 0) { 1461 1.31 fvdl add_dlist(&dp->dp_left, newdp, grp, flags); 1462 1.12 mycroft return; 1463 1.12 mycroft } else if (cmp < 0) { 1464 1.31 fvdl add_dlist(&dp->dp_right, newdp, grp, flags); 1465 1.12 mycroft return; 1466 1.12 mycroft } else 1467 1.47 christos free(newdp); 1468 1.12 mycroft } else { 1469 1.12 mycroft dp = newdp; 1470 1.47 christos dp->dp_left = NULL; 1471 1.12 mycroft *dpp = dp; 1472 1.12 mycroft } 1473 1.12 mycroft if (grp) { 1474 1.12 mycroft 1475 1.12 mycroft /* 1476 1.12 mycroft * Hang all of the host(s) off of the directory point. 1477 1.12 mycroft */ 1478 1.12 mycroft do { 1479 1.12 mycroft hp = get_ht(); 1480 1.31 fvdl if (flags & OP_KERB) 1481 1.31 fvdl hp->ht_flag |= DP_KERB; 1482 1.37 fvdl if (flags & OP_NORESMNT) 1483 1.37 fvdl hp->ht_flag |= DP_NORESMNT; 1484 1.12 mycroft hp->ht_grp = grp; 1485 1.12 mycroft hp->ht_next = dp->dp_hosts; 1486 1.12 mycroft dp->dp_hosts = hp; 1487 1.12 mycroft grp = grp->gr_next; 1488 1.12 mycroft } while (grp); 1489 1.31 fvdl } else { 1490 1.12 mycroft dp->dp_flag |= DP_DEFSET; 1491 1.31 fvdl if (flags & OP_KERB) 1492 1.31 fvdl dp->dp_flag |= DP_KERB; 1493 1.37 fvdl if (flags & OP_NORESMNT) 1494 1.37 fvdl dp->dp_flag |= DP_NORESMNT; 1495 1.31 fvdl } 1496 1.12 mycroft } 1497 1.12 mycroft 1498 1.12 mycroft /* 1499 1.12 mycroft * Search for a dirpath on the export point. 1500 1.12 mycroft */ 1501 1.47 christos static struct dirlist * 1502 1.122 joerg dirp_search(struct dirlist *dp, char *dirp) 1503 1.12 mycroft { 1504 1.12 mycroft int cmp; 1505 1.12 mycroft 1506 1.12 mycroft if (dp) { 1507 1.45 christos cmp = strcmp(dp->dp_dirp, dirp); 1508 1.12 mycroft if (cmp > 0) 1509 1.45 christos return (dirp_search(dp->dp_left, dirp)); 1510 1.12 mycroft else if (cmp < 0) 1511 1.45 christos return (dirp_search(dp->dp_right, dirp)); 1512 1.12 mycroft else 1513 1.12 mycroft return (dp); 1514 1.12 mycroft } 1515 1.12 mycroft return (dp); 1516 1.12 mycroft } 1517 1.12 mycroft 1518 1.12 mycroft /* 1519 1.64 fvdl * Some helper functions for netmasks. They all assume masks in network 1520 1.64 fvdl * order (big endian). 1521 1.64 fvdl */ 1522 1.64 fvdl static int 1523 1.64 fvdl bitcmp(void *dst, void *src, int bitlen) 1524 1.64 fvdl { 1525 1.64 fvdl int i; 1526 1.64 fvdl u_int8_t *p1 = dst, *p2 = src; 1527 1.64 fvdl u_int8_t bitmask; 1528 1.64 fvdl int bytelen, bitsleft; 1529 1.64 fvdl 1530 1.64 fvdl bytelen = bitlen / 8; 1531 1.64 fvdl bitsleft = bitlen % 8; 1532 1.64 fvdl 1533 1.131 joerg if (mountd_debug) { 1534 1.64 fvdl printf("comparing:\n"); 1535 1.64 fvdl for (i = 0; i < (bitsleft ? bytelen + 1 : bytelen); i++) 1536 1.64 fvdl printf("%02x", p1[i]); 1537 1.64 fvdl printf("\n"); 1538 1.64 fvdl for (i = 0; i < (bitsleft ? bytelen + 1 : bytelen); i++) 1539 1.64 fvdl printf("%02x", p2[i]); 1540 1.64 fvdl printf("\n"); 1541 1.64 fvdl } 1542 1.64 fvdl 1543 1.64 fvdl for (i = 0; i < bytelen; i++) { 1544 1.64 fvdl if (*p1 != *p2) 1545 1.64 fvdl return 1; 1546 1.64 fvdl p1++; 1547 1.64 fvdl p2++; 1548 1.64 fvdl } 1549 1.64 fvdl 1550 1.64 fvdl for (i = 0; i < bitsleft; i++) { 1551 1.64 fvdl bitmask = 1 << (7 - i); 1552 1.64 fvdl if ((*p1 & bitmask) != (*p2 & bitmask)) 1553 1.64 fvdl return 1; 1554 1.64 fvdl } 1555 1.64 fvdl 1556 1.64 fvdl return 0; 1557 1.64 fvdl } 1558 1.64 fvdl 1559 1.64 fvdl static int 1560 1.64 fvdl netpartcmp(struct sockaddr *s1, struct sockaddr *s2, int bitlen) 1561 1.64 fvdl { 1562 1.64 fvdl void *src, *dst; 1563 1.64 fvdl 1564 1.64 fvdl if (s1->sa_family != s2->sa_family) 1565 1.64 fvdl return 1; 1566 1.64 fvdl 1567 1.64 fvdl switch (s1->sa_family) { 1568 1.64 fvdl case AF_INET: 1569 1.64 fvdl src = &((struct sockaddr_in *)s1)->sin_addr; 1570 1.64 fvdl dst = &((struct sockaddr_in *)s2)->sin_addr; 1571 1.119 lukem if (bitlen > (int)sizeof(((struct sockaddr_in *)s1)->sin_addr) * 8) 1572 1.66 itojun return 1; 1573 1.64 fvdl break; 1574 1.64 fvdl case AF_INET6: 1575 1.64 fvdl src = &((struct sockaddr_in6 *)s1)->sin6_addr; 1576 1.64 fvdl dst = &((struct sockaddr_in6 *)s2)->sin6_addr; 1577 1.67 itojun if (((struct sockaddr_in6 *)s1)->sin6_scope_id != 1578 1.67 itojun ((struct sockaddr_in6 *)s2)->sin6_scope_id) 1579 1.67 itojun return 1; 1580 1.119 lukem if (bitlen > (int)sizeof(((struct sockaddr_in6 *)s1)->sin6_addr) * 8) 1581 1.66 itojun return 1; 1582 1.64 fvdl break; 1583 1.64 fvdl default: 1584 1.64 fvdl return 1; 1585 1.64 fvdl } 1586 1.64 fvdl 1587 1.64 fvdl return bitcmp(src, dst, bitlen); 1588 1.64 fvdl } 1589 1.64 fvdl 1590 1.64 fvdl static int 1591 1.64 fvdl allones(struct sockaddr_storage *ssp, int bitlen) 1592 1.64 fvdl { 1593 1.64 fvdl u_int8_t *p; 1594 1.64 fvdl int bytelen, bitsleft, i; 1595 1.64 fvdl int zerolen; 1596 1.64 fvdl 1597 1.64 fvdl switch (ssp->ss_family) { 1598 1.64 fvdl case AF_INET: 1599 1.64 fvdl p = (u_int8_t *)&((struct sockaddr_in *)ssp)->sin_addr; 1600 1.64 fvdl zerolen = sizeof (((struct sockaddr_in *)ssp)->sin_addr); 1601 1.64 fvdl break; 1602 1.64 fvdl case AF_INET6: 1603 1.64 fvdl p = (u_int8_t *)&((struct sockaddr_in6 *)ssp)->sin6_addr; 1604 1.64 fvdl zerolen = sizeof (((struct sockaddr_in6 *)ssp)->sin6_addr); 1605 1.64 fvdl break; 1606 1.64 fvdl default: 1607 1.64 fvdl return -1; 1608 1.64 fvdl } 1609 1.64 fvdl 1610 1.64 fvdl memset(p, 0, zerolen); 1611 1.64 fvdl 1612 1.64 fvdl bytelen = bitlen / 8; 1613 1.64 fvdl bitsleft = bitlen % 8; 1614 1.64 fvdl 1615 1.65 itojun if (bytelen > zerolen) 1616 1.65 itojun return -1; 1617 1.65 itojun 1618 1.64 fvdl for (i = 0; i < bytelen; i++) 1619 1.64 fvdl *p++ = 0xff; 1620 1.64 fvdl 1621 1.64 fvdl for (i = 0; i < bitsleft; i++) 1622 1.64 fvdl *p |= 1 << (7 - i); 1623 1.64 fvdl 1624 1.64 fvdl return 0; 1625 1.64 fvdl } 1626 1.64 fvdl 1627 1.64 fvdl static int 1628 1.64 fvdl sacmp(struct sockaddr *sa1, struct sockaddr *sa2) 1629 1.64 fvdl { 1630 1.64 fvdl void *p1, *p2; 1631 1.64 fvdl int len; 1632 1.64 fvdl 1633 1.64 fvdl if (sa1->sa_family != sa2->sa_family) 1634 1.64 fvdl return 1; 1635 1.64 fvdl 1636 1.64 fvdl switch (sa1->sa_family) { 1637 1.64 fvdl case AF_INET: 1638 1.64 fvdl p1 = &((struct sockaddr_in *)sa1)->sin_addr; 1639 1.64 fvdl p2 = &((struct sockaddr_in *)sa2)->sin_addr; 1640 1.64 fvdl len = 4; 1641 1.64 fvdl break; 1642 1.64 fvdl case AF_INET6: 1643 1.64 fvdl p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr; 1644 1.64 fvdl p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr; 1645 1.64 fvdl len = 16; 1646 1.67 itojun if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 1647 1.67 itojun ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 1648 1.67 itojun return 1; 1649 1.64 fvdl break; 1650 1.64 fvdl default: 1651 1.64 fvdl return 1; 1652 1.64 fvdl } 1653 1.64 fvdl 1654 1.64 fvdl return memcmp(p1, p2, len); 1655 1.64 fvdl } 1656 1.64 fvdl 1657 1.64 fvdl /* 1658 1.12 mycroft * Scan for a host match in a directory tree. 1659 1.12 mycroft */ 1660 1.47 christos static int 1661 1.122 joerg chk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp, 1662 1.122 joerg int *hostsetp) 1663 1.12 mycroft { 1664 1.12 mycroft struct hostlist *hp; 1665 1.12 mycroft struct grouplist *grp; 1666 1.64 fvdl struct addrinfo *ai; 1667 1.12 mycroft 1668 1.12 mycroft if (dp) { 1669 1.12 mycroft if (dp->dp_flag & DP_DEFSET) 1670 1.31 fvdl *defsetp = dp->dp_flag; 1671 1.12 mycroft hp = dp->dp_hosts; 1672 1.12 mycroft while (hp) { 1673 1.12 mycroft grp = hp->ht_grp; 1674 1.12 mycroft switch (grp->gr_type) { 1675 1.12 mycroft case GT_HOST: 1676 1.64 fvdl ai = grp->gr_ptr.gt_addrinfo; 1677 1.64 fvdl for (; ai; ai = ai->ai_next) { 1678 1.64 fvdl if (!sacmp(ai->ai_addr, saddr)) { 1679 1.64 fvdl *hostsetp = 1680 1.64 fvdl (hp->ht_flag | DP_HOSTSET); 1681 1.64 fvdl return (1); 1682 1.64 fvdl } 1683 1.31 fvdl } 1684 1.47 christos break; 1685 1.12 mycroft case GT_NET: 1686 1.64 fvdl if (!netpartcmp(saddr, 1687 1.64 fvdl (struct sockaddr *) 1688 1.64 fvdl &grp->gr_ptr.gt_net.nt_net, 1689 1.64 fvdl grp->gr_ptr.gt_net.nt_len)) { 1690 1.47 christos *hostsetp = (hp->ht_flag | DP_HOSTSET); 1691 1.47 christos return (1); 1692 1.47 christos } 1693 1.47 christos break; 1694 1.12 mycroft }; 1695 1.12 mycroft hp = hp->ht_next; 1696 1.12 mycroft } 1697 1.12 mycroft } 1698 1.12 mycroft return (0); 1699 1.12 mycroft } 1700 1.12 mycroft 1701 1.12 mycroft /* 1702 1.12 mycroft * Scan tree for a host that matches the address. 1703 1.12 mycroft */ 1704 1.47 christos static int 1705 1.122 joerg scan_tree(struct dirlist *dp, struct sockaddr *saddr) 1706 1.12 mycroft { 1707 1.31 fvdl int defset, hostset; 1708 1.12 mycroft 1709 1.12 mycroft if (dp) { 1710 1.12 mycroft if (scan_tree(dp->dp_left, saddr)) 1711 1.12 mycroft return (1); 1712 1.31 fvdl if (chk_host(dp, saddr, &defset, &hostset)) 1713 1.12 mycroft return (1); 1714 1.12 mycroft if (scan_tree(dp->dp_right, saddr)) 1715 1.12 mycroft return (1); 1716 1.12 mycroft } 1717 1.12 mycroft return (0); 1718 1.12 mycroft } 1719 1.12 mycroft 1720 1.12 mycroft /* 1721 1.12 mycroft * Traverse the dirlist tree and free it up. 1722 1.12 mycroft */ 1723 1.47 christos static void 1724 1.122 joerg free_dir(struct dirlist *dp) 1725 1.12 mycroft { 1726 1.12 mycroft 1727 1.12 mycroft if (dp) { 1728 1.12 mycroft free_dir(dp->dp_left); 1729 1.12 mycroft free_dir(dp->dp_right); 1730 1.12 mycroft free_host(dp->dp_hosts); 1731 1.47 christos free(dp); 1732 1.12 mycroft } 1733 1.12 mycroft } 1734 1.12 mycroft 1735 1.12 mycroft /* 1736 1.12 mycroft * Parse the option string and update fields. 1737 1.12 mycroft * Option arguments may either be -<option>=<value> or 1738 1.12 mycroft * -<option> <value> 1739 1.12 mycroft */ 1740 1.47 christos static int 1741 1.122 joerg do_opt(const char *line, size_t lineno, char **cpp, char **endcpp, 1742 1.122 joerg struct exportlist *ep, struct grouplist *grp, int *has_hostp, 1743 1.122 joerg int *exflagsp, struct uucred *cr) 1744 1.12 mycroft { 1745 1.12 mycroft char *cpoptarg, *cpoptend; 1746 1.104 christos char *cp, *cpopt, savedc, savedc2; 1747 1.104 christos char *endcp = NULL; /* XXX: GCC */ 1748 1.12 mycroft int allflag, usedarg; 1749 1.12 mycroft 1750 1.12 mycroft cpopt = *cpp; 1751 1.12 mycroft cpopt++; 1752 1.12 mycroft cp = *endcpp; 1753 1.12 mycroft savedc = *cp; 1754 1.12 mycroft *cp = '\0'; 1755 1.12 mycroft while (cpopt && *cpopt) { 1756 1.12 mycroft allflag = 1; 1757 1.12 mycroft usedarg = -2; 1758 1.41 lukem savedc2 = '\0'; 1759 1.41 lukem if ((cpoptend = strchr(cpopt, ',')) != NULL) { 1760 1.12 mycroft *cpoptend++ = '\0'; 1761 1.41 lukem if ((cpoptarg = strchr(cpopt, '=')) != NULL) 1762 1.12 mycroft *cpoptarg++ = '\0'; 1763 1.12 mycroft } else { 1764 1.41 lukem if ((cpoptarg = strchr(cpopt, '=')) != NULL) 1765 1.12 mycroft *cpoptarg++ = '\0'; 1766 1.12 mycroft else { 1767 1.12 mycroft *cp = savedc; 1768 1.12 mycroft nextfield(&cp, &endcp); 1769 1.12 mycroft **endcpp = '\0'; 1770 1.12 mycroft if (endcp > cp && *cp != '-') { 1771 1.12 mycroft cpoptarg = cp; 1772 1.12 mycroft savedc2 = *endcp; 1773 1.12 mycroft *endcp = '\0'; 1774 1.12 mycroft usedarg = 0; 1775 1.1 cgd } 1776 1.1 cgd } 1777 1.12 mycroft } 1778 1.12 mycroft if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 1779 1.12 mycroft *exflagsp |= MNT_EXRDONLY; 1780 1.12 mycroft } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 1781 1.12 mycroft !(allflag = strcmp(cpopt, "mapall")) || 1782 1.12 mycroft !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 1783 1.12 mycroft usedarg++; 1784 1.12 mycroft parsecred(cpoptarg, cr); 1785 1.12 mycroft if (allflag == 0) { 1786 1.12 mycroft *exflagsp |= MNT_EXPORTANON; 1787 1.12 mycroft opt_flags |= OP_MAPALL; 1788 1.12 mycroft } else 1789 1.12 mycroft opt_flags |= OP_MAPROOT; 1790 1.12 mycroft } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 1791 1.12 mycroft *exflagsp |= MNT_EXKERB; 1792 1.12 mycroft opt_flags |= OP_KERB; 1793 1.12 mycroft } else if (cpoptarg && (!strcmp(cpopt, "mask") || 1794 1.47 christos !strcmp(cpopt, "m"))) { 1795 1.12 mycroft if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 1796 1.52 christos syslog(LOG_ERR, 1797 1.52 christos "\"%s\", line %ld: Bad mask: %s", 1798 1.52 christos line, (unsigned long)lineno, cpoptarg); 1799 1.12 mycroft return (1); 1800 1.12 mycroft } 1801 1.12 mycroft usedarg++; 1802 1.12 mycroft opt_flags |= OP_MASK; 1803 1.12 mycroft } else if (cpoptarg && (!strcmp(cpopt, "network") || 1804 1.47 christos !strcmp(cpopt, "n"))) { 1805 1.64 fvdl if (strchr(cpoptarg, '/') != NULL) { 1806 1.131 joerg if (mountd_debug) 1807 1.64 fvdl fprintf(stderr, "setting OP_MASKLEN\n"); 1808 1.64 fvdl opt_flags |= OP_MASKLEN; 1809 1.64 fvdl } 1810 1.12 mycroft if (grp->gr_type != GT_NULL) { 1811 1.52 christos syslog(LOG_ERR, 1812 1.52 christos "\"%s\", line %ld: Network/host conflict", 1813 1.52 christos line, (unsigned long)lineno); 1814 1.12 mycroft return (1); 1815 1.12 mycroft } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1816 1.52 christos syslog(LOG_ERR, 1817 1.52 christos "\"%s\", line %ld: Bad net: %s", 1818 1.52 christos line, (unsigned long)lineno, cpoptarg); 1819 1.12 mycroft return (1); 1820 1.12 mycroft } 1821 1.12 mycroft grp->gr_type = GT_NET; 1822 1.12 mycroft *has_hostp = 1; 1823 1.12 mycroft usedarg++; 1824 1.12 mycroft opt_flags |= OP_NET; 1825 1.12 mycroft } else if (!strcmp(cpopt, "alldirs")) { 1826 1.12 mycroft opt_flags |= OP_ALLDIRS; 1827 1.37 fvdl } else if (!strcmp(cpopt, "noresvmnt")) { 1828 1.37 fvdl opt_flags |= OP_NORESMNT; 1829 1.37 fvdl } else if (!strcmp(cpopt, "noresvport")) { 1830 1.36 fvdl opt_flags |= OP_NORESPORT; 1831 1.36 fvdl *exflagsp |= MNT_EXNORESPORT; 1832 1.38 fvdl } else if (!strcmp(cpopt, "public")) { 1833 1.47 christos *exflagsp |= (MNT_EXNORESPORT | MNT_EXPUBLIC); 1834 1.38 fvdl opt_flags |= OP_NORESPORT; 1835 1.38 fvdl } else if (!strcmp(cpopt, "webnfs")) { 1836 1.47 christos *exflagsp |= (MNT_EXNORESPORT | MNT_EXPUBLIC | 1837 1.47 christos MNT_EXRDONLY | MNT_EXPORTANON); 1838 1.47 christos opt_flags |= (OP_MAPALL | OP_NORESPORT); 1839 1.38 fvdl } else if (cpoptarg && !strcmp(cpopt, "index")) { 1840 1.38 fvdl ep->ex_indexfile = strdup(cpoptarg); 1841 1.12 mycroft } else { 1842 1.52 christos syslog(LOG_ERR, 1843 1.52 christos "\"%s\", line %ld: Bad opt %s", 1844 1.52 christos line, (unsigned long)lineno, cpopt); 1845 1.12 mycroft return (1); 1846 1.12 mycroft } 1847 1.12 mycroft if (usedarg >= 0) { 1848 1.12 mycroft *endcp = savedc2; 1849 1.12 mycroft **endcpp = savedc; 1850 1.12 mycroft if (usedarg > 0) { 1851 1.12 mycroft *cpp = cp; 1852 1.12 mycroft *endcpp = endcp; 1853 1.12 mycroft } 1854 1.12 mycroft return (0); 1855 1.12 mycroft } 1856 1.12 mycroft cpopt = cpoptend; 1857 1.12 mycroft } 1858 1.12 mycroft **endcpp = savedc; 1859 1.12 mycroft return (0); 1860 1.12 mycroft } 1861 1.12 mycroft 1862 1.12 mycroft /* 1863 1.12 mycroft * Translate a character string to the corresponding list of network 1864 1.12 mycroft * addresses for a hostname. 1865 1.12 mycroft */ 1866 1.47 christos static int 1867 1.122 joerg get_host(const char *line, size_t lineno, const char *cp, 1868 1.122 joerg struct grouplist *grp) 1869 1.12 mycroft { 1870 1.64 fvdl struct addrinfo *ai, hints; 1871 1.64 fvdl int ecode; 1872 1.64 fvdl char host[NI_MAXHOST]; 1873 1.12 mycroft 1874 1.52 christos if (grp->gr_type != GT_NULL) { 1875 1.52 christos syslog(LOG_ERR, 1876 1.52 christos "\"%s\", line %ld: Bad netgroup type for ip host %s", 1877 1.52 christos line, (unsigned long)lineno, cp); 1878 1.12 mycroft return (1); 1879 1.52 christos } 1880 1.64 fvdl memset(&hints, 0, sizeof hints); 1881 1.64 fvdl hints.ai_flags = AI_CANONNAME; 1882 1.64 fvdl hints.ai_protocol = IPPROTO_UDP; 1883 1.64 fvdl ecode = getaddrinfo(cp, NULL, &hints, &ai); 1884 1.64 fvdl if (ecode != 0) { 1885 1.64 fvdl syslog(LOG_ERR, "\"%s\", line %ld: can't get address info for " 1886 1.64 fvdl "host %s", 1887 1.64 fvdl line, (long)lineno, cp); 1888 1.64 fvdl return 1; 1889 1.12 mycroft } 1890 1.12 mycroft grp->gr_type = GT_HOST; 1891 1.64 fvdl grp->gr_ptr.gt_addrinfo = ai; 1892 1.64 fvdl while (ai != NULL) { 1893 1.64 fvdl if (ai->ai_canonname == NULL) { 1894 1.75 itojun if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 1895 1.75 itojun sizeof host, NULL, 0, ninumeric) != 0) 1896 1.75 itojun strlcpy(host, "?", sizeof(host)); 1897 1.64 fvdl ai->ai_canonname = estrdup(host); 1898 1.64 fvdl ai->ai_flags |= AI_CANONNAME; 1899 1.64 fvdl } else 1900 1.64 fvdl ai->ai_flags &= ~AI_CANONNAME; 1901 1.131 joerg if (mountd_debug) 1902 1.64 fvdl (void)fprintf(stderr, "got host %s\n", ai->ai_canonname); 1903 1.64 fvdl ai = ai->ai_next; 1904 1.12 mycroft } 1905 1.12 mycroft return (0); 1906 1.12 mycroft } 1907 1.12 mycroft 1908 1.12 mycroft /* 1909 1.12 mycroft * Free up an exports list component 1910 1.12 mycroft */ 1911 1.47 christos static void 1912 1.122 joerg free_exp(struct exportlist *ep) 1913 1.12 mycroft { 1914 1.12 mycroft 1915 1.12 mycroft if (ep->ex_defdir) { 1916 1.12 mycroft free_host(ep->ex_defdir->dp_hosts); 1917 1.47 christos free(ep->ex_defdir); 1918 1.12 mycroft } 1919 1.12 mycroft if (ep->ex_fsdir) 1920 1.12 mycroft free(ep->ex_fsdir); 1921 1.38 fvdl if (ep->ex_indexfile) 1922 1.38 fvdl free(ep->ex_indexfile); 1923 1.12 mycroft free_dir(ep->ex_dirl); 1924 1.47 christos free(ep); 1925 1.12 mycroft } 1926 1.12 mycroft 1927 1.12 mycroft /* 1928 1.12 mycroft * Free hosts. 1929 1.12 mycroft */ 1930 1.47 christos static void 1931 1.122 joerg free_host(struct hostlist *hp) 1932 1.12 mycroft { 1933 1.12 mycroft struct hostlist *hp2; 1934 1.12 mycroft 1935 1.12 mycroft while (hp) { 1936 1.12 mycroft hp2 = hp; 1937 1.12 mycroft hp = hp->ht_next; 1938 1.47 christos free(hp2); 1939 1.12 mycroft } 1940 1.12 mycroft } 1941 1.12 mycroft 1942 1.47 christos static struct hostlist * 1943 1.122 joerg get_ht(void) 1944 1.12 mycroft { 1945 1.12 mycroft struct hostlist *hp; 1946 1.12 mycroft 1947 1.47 christos hp = emalloc(sizeof(struct hostlist)); 1948 1.47 christos hp->ht_next = NULL; 1949 1.31 fvdl hp->ht_flag = 0; 1950 1.12 mycroft return (hp); 1951 1.12 mycroft } 1952 1.12 mycroft 1953 1.135 hannken static int 1954 1.135 hannken add_export_arg(const char *path, int exflags, struct uucred *anoncrp, 1955 1.135 hannken struct sockaddr *addrp, int addrlen, struct sockaddr *maskp, int masklen, 1956 1.135 hannken char *indexfile) 1957 1.135 hannken { 1958 1.136 hannken const struct mountd_exports_list mel_key = { .mel_path = path }; 1959 1.136 hannken struct mountd_exports_list *mel; 1960 1.136 hannken struct export_args *export; 1961 1.135 hannken 1962 1.135 hannken if (addrp != NULL && addrp->sa_family == AF_INET6 && have_v6 == 0) 1963 1.135 hannken return 0; 1964 1.135 hannken 1965 1.136 hannken mel = bsearch(&mel_key, mel_tab, mel_tab_len, sizeof(mel_tab[0]), 1966 1.136 hannken mel_compare); 1967 1.136 hannken if (mel == NULL) { 1968 1.136 hannken syslog(LOG_ERR, "Can't change attributes for %s: not found", 1969 1.136 hannken path); 1970 1.135 hannken return 1; 1971 1.135 hannken } 1972 1.136 hannken ereallocarr(&mel->mel_exports, mel->mel_nexports + 1, 1973 1.136 hannken sizeof(*mel->mel_exports)); 1974 1.136 hannken export = &mel->mel_exports[mel->mel_nexports++]; 1975 1.136 hannken memset(export, 0, sizeof(*export)); 1976 1.136 hannken 1977 1.136 hannken export->ex_flags = exflags; 1978 1.136 hannken export->ex_anon = *anoncrp; 1979 1.136 hannken if (indexfile) 1980 1.136 hannken export->ex_indexfile = estrdup(indexfile); 1981 1.136 hannken if (addrlen > 0) { 1982 1.136 hannken export->ex_addr = emalloc(addrlen); 1983 1.136 hannken export->ex_addrlen = addrlen; 1984 1.136 hannken memcpy(export->ex_addr, addrp, addrlen); 1985 1.136 hannken } 1986 1.136 hannken if (masklen > 0) { 1987 1.136 hannken export->ex_mask = emalloc(masklen); 1988 1.136 hannken export->ex_masklen = masklen; 1989 1.136 hannken memcpy(export->ex_mask, maskp, masklen); 1990 1.136 hannken } 1991 1.135 hannken 1992 1.135 hannken return 0; 1993 1.135 hannken } 1994 1.135 hannken 1995 1.12 mycroft /* 1996 1.98 jmmv * Do the nfssvc syscall to push the export info into the kernel. 1997 1.12 mycroft */ 1998 1.47 christos static int 1999 1.122 joerg do_nfssvc(const char *line, size_t lineno, struct exportlist *ep, 2000 1.122 joerg struct grouplist *grp, int exflags, struct uucred *anoncrp, 2001 1.122 joerg char *dirp, int dirplen, struct statvfs *fsb) 2002 1.12 mycroft { 2003 1.64 fvdl struct sockaddr *addrp; 2004 1.64 fvdl struct sockaddr_storage ss; 2005 1.64 fvdl struct addrinfo *ai; 2006 1.64 fvdl int addrlen; 2007 1.98 jmmv 2008 1.64 fvdl if (grp->gr_type == GT_HOST) { 2009 1.135 hannken for (ai = grp->gr_ptr.gt_addrinfo; ai; ai = ai->ai_next) { 2010 1.135 hannken addrp = ai->ai_addr; 2011 1.135 hannken addrlen = ai->ai_addrlen; 2012 1.135 hannken if (add_export_arg(fsb->f_mntonname, exflags, anoncrp, 2013 1.135 hannken addrp, addrlen, NULL, 0, ep->ex_indexfile) != 0) 2014 1.135 hannken return 1; 2015 1.135 hannken } 2016 1.135 hannken } else if (grp->gr_type == GT_NET) { 2017 1.135 hannken addrp = (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 2018 1.135 hannken addrlen = addrp->sa_len; 2019 1.135 hannken memset(&ss, 0, sizeof ss); 2020 1.135 hannken ss.ss_family = addrp->sa_family; 2021 1.135 hannken ss.ss_len = addrp->sa_len; 2022 1.135 hannken if (allones(&ss, grp->gr_ptr.gt_net.nt_len) != 0) { 2023 1.135 hannken syslog(LOG_ERR, "\"%s\", line %ld: Bad network flag", 2024 1.135 hannken line, (unsigned long)lineno); 2025 1.135 hannken return 1; 2026 1.135 hannken } 2027 1.135 hannken if (add_export_arg(fsb->f_mntonname, exflags, anoncrp, 2028 1.135 hannken addrp, addrlen, (struct sockaddr *)&ss, ss.ss_len, 2029 1.135 hannken ep->ex_indexfile) != 0) 2030 1.135 hannken return 1; 2031 1.95 lukem } else { 2032 1.135 hannken syslog(LOG_ERR, "\"%s\", line %ld: Bad netgroup type", 2033 1.135 hannken line, (unsigned long)lineno); 2034 1.135 hannken return 1; 2035 1.95 lukem } 2036 1.101 yamt 2037 1.135 hannken return 0; 2038 1.12 mycroft } 2039 1.12 mycroft 2040 1.12 mycroft /* 2041 1.1 cgd * Parse out the next white space separated field 2042 1.1 cgd */ 2043 1.47 christos static void 2044 1.122 joerg nextfield(char **cp, char **endcp) 2045 1.1 cgd { 2046 1.12 mycroft char *p; 2047 1.1 cgd 2048 1.1 cgd p = *cp; 2049 1.1 cgd while (*p == ' ' || *p == '\t') 2050 1.1 cgd p++; 2051 1.12 mycroft if (*p == '\n' || *p == '\0') 2052 1.1 cgd *cp = *endcp = p; 2053 1.12 mycroft else { 2054 1.12 mycroft *cp = p++; 2055 1.12 mycroft while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 2056 1.12 mycroft p++; 2057 1.12 mycroft *endcp = p; 2058 1.1 cgd } 2059 1.1 cgd } 2060 1.1 cgd 2061 1.1 cgd /* 2062 1.12 mycroft * Parse a description of a credential. 2063 1.1 cgd */ 2064 1.47 christos static void 2065 1.122 joerg parsecred(char *namelist, struct uucred *cr) 2066 1.1 cgd { 2067 1.119 lukem char *username; 2068 1.12 mycroft int cnt; 2069 1.12 mycroft char *names; 2070 1.12 mycroft struct passwd *pw; 2071 1.12 mycroft struct group *gr; 2072 1.103 mrg int ngroups; 2073 1.119 lukem gid_t usergroups[NGROUPS + 1]; 2074 1.1 cgd 2075 1.12 mycroft /* 2076 1.55 simonb * Set up the unprivileged user. 2077 1.12 mycroft */ 2078 1.79 christos *cr = def_anon; 2079 1.12 mycroft /* 2080 1.12 mycroft * Get the user's password table entry. 2081 1.12 mycroft */ 2082 1.12 mycroft names = strsep(&namelist, " \t\n"); 2083 1.119 lukem username = strsep(&names, ":"); 2084 1.119 lukem if (isdigit((unsigned char)*username) || *username == '-') 2085 1.119 lukem pw = getpwuid(atoi(username)); 2086 1.12 mycroft else 2087 1.119 lukem pw = getpwnam(username); 2088 1.12 mycroft /* 2089 1.12 mycroft * Credentials specified as those of a user. 2090 1.12 mycroft */ 2091 1.12 mycroft if (names == NULL) { 2092 1.12 mycroft if (pw == NULL) { 2093 1.119 lukem syslog(LOG_ERR, "Unknown user: %s", username); 2094 1.12 mycroft return; 2095 1.12 mycroft } 2096 1.12 mycroft cr->cr_uid = pw->pw_uid; 2097 1.12 mycroft ngroups = NGROUPS + 1; 2098 1.119 lukem if (getgrouplist(pw->pw_name, pw->pw_gid, usergroups, &ngroups)) 2099 1.119 lukem syslog(LOG_ERR, "Too many groups for user %s", username); 2100 1.12 mycroft /* 2101 1.12 mycroft * Convert from int's to gid_t's and compress out duplicate 2102 1.12 mycroft */ 2103 1.12 mycroft cr->cr_ngroups = ngroups - 1; 2104 1.119 lukem cr->cr_gid = usergroups[0]; 2105 1.22 mycroft for (cnt = 1; cnt < ngroups; cnt++) 2106 1.119 lukem cr->cr_groups[cnt - 1] = usergroups[cnt]; 2107 1.12 mycroft return; 2108 1.12 mycroft } 2109 1.12 mycroft /* 2110 1.12 mycroft * Explicit credential specified as a colon separated list: 2111 1.12 mycroft * uid:gid:gid:... 2112 1.12 mycroft */ 2113 1.12 mycroft if (pw != NULL) 2114 1.12 mycroft cr->cr_uid = pw->pw_uid; 2115 1.119 lukem else if (isdigit((unsigned char)*username) || *username == '-') 2116 1.119 lukem cr->cr_uid = atoi(username); 2117 1.12 mycroft else { 2118 1.119 lukem syslog(LOG_ERR, "Unknown user: %s", username); 2119 1.12 mycroft return; 2120 1.12 mycroft } 2121 1.12 mycroft cr->cr_ngroups = 0; 2122 1.12 mycroft while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 2123 1.119 lukem username = strsep(&names, ":"); 2124 1.119 lukem if (isdigit((unsigned char)*username) || *username == '-') { 2125 1.119 lukem cr->cr_groups[cr->cr_ngroups++] = atoi(username); 2126 1.12 mycroft } else { 2127 1.119 lukem if ((gr = getgrnam(username)) == NULL) { 2128 1.119 lukem syslog(LOG_ERR, "Unknown group: %s", username); 2129 1.12 mycroft continue; 2130 1.12 mycroft } 2131 1.12 mycroft cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 2132 1.12 mycroft } 2133 1.1 cgd } 2134 1.12 mycroft if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 2135 1.12 mycroft syslog(LOG_ERR, "Too many groups"); 2136 1.1 cgd } 2137 1.1 cgd 2138 1.12 mycroft #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 2139 1.1 cgd /* 2140 1.1 cgd * Routines that maintain the remote mounttab 2141 1.1 cgd */ 2142 1.47 christos static void 2143 1.122 joerg get_mountlist(void) 2144 1.1 cgd { 2145 1.12 mycroft struct mountlist *mlp, **mlpp; 2146 1.15 mycroft char *host, *dirp, *cp; 2147 1.1 cgd char str[STRSIZ]; 2148 1.1 cgd FILE *mlfile; 2149 1.1 cgd 2150 1.11 ws if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 2151 1.32 mrg syslog(LOG_ERR, "Can't open %s: %m", _PATH_RMOUNTLIST); 2152 1.1 cgd return; 2153 1.1 cgd } 2154 1.1 cgd mlpp = &mlhead; 2155 1.1 cgd while (fgets(str, STRSIZ, mlfile) != NULL) { 2156 1.15 mycroft cp = str; 2157 1.15 mycroft host = strsep(&cp, " \t\n"); 2158 1.15 mycroft dirp = strsep(&cp, " \t\n"); 2159 1.15 mycroft if (host == NULL || dirp == NULL) 2160 1.1 cgd continue; 2161 1.47 christos mlp = emalloc(sizeof(*mlp)); 2162 1.47 christos (void)strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 2163 1.15 mycroft mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 2164 1.47 christos (void)strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 2165 1.15 mycroft mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 2166 1.47 christos mlp->ml_next = NULL; 2167 1.1 cgd *mlpp = mlp; 2168 1.1 cgd mlpp = &mlp->ml_next; 2169 1.1 cgd } 2170 1.47 christos (void)fclose(mlfile); 2171 1.1 cgd } 2172 1.1 cgd 2173 1.47 christos static int 2174 1.122 joerg del_mlist(char *hostp, char *dirp, struct sockaddr *saddr) 2175 1.1 cgd { 2176 1.12 mycroft struct mountlist *mlp, **mlpp; 2177 1.12 mycroft struct mountlist *mlp2; 2178 1.75 itojun u_short sport; 2179 1.1 cgd FILE *mlfile; 2180 1.36 fvdl int fnd = 0, ret = 0; 2181 1.75 itojun char host[NI_MAXHOST]; 2182 1.1 cgd 2183 1.75 itojun switch (saddr->sa_family) { 2184 1.75 itojun case AF_INET6: 2185 1.75 itojun sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 2186 1.75 itojun break; 2187 1.75 itojun case AF_INET: 2188 1.75 itojun sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 2189 1.75 itojun break; 2190 1.75 itojun default: 2191 1.75 itojun return -1; 2192 1.75 itojun } 2193 1.1 cgd mlpp = &mlhead; 2194 1.1 cgd mlp = mlhead; 2195 1.1 cgd while (mlp) { 2196 1.1 cgd if (!strcmp(mlp->ml_host, hostp) && 2197 1.1 cgd (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 2198 1.37 fvdl if (!(mlp->ml_flag & DP_NORESMNT) && 2199 1.75 itojun sport >= IPPORT_RESERVED) { 2200 1.75 itojun if (getnameinfo(saddr, saddr->sa_len, host, 2201 1.75 itojun sizeof host, NULL, 0, ninumeric) != 0) 2202 1.75 itojun strlcpy(host, "?", sizeof(host)); 2203 1.36 fvdl syslog(LOG_NOTICE, 2204 1.47 christos "Umount request for %s:%s from %s refused\n", 2205 1.75 itojun mlp->ml_host, mlp->ml_dirp, host); 2206 1.36 fvdl ret = -1; 2207 1.42 fvdl goto cont; 2208 1.36 fvdl } 2209 1.1 cgd fnd = 1; 2210 1.12 mycroft mlp2 = mlp; 2211 1.12 mycroft *mlpp = mlp = mlp->ml_next; 2212 1.47 christos free(mlp2); 2213 1.12 mycroft } else { 2214 1.42 fvdl cont: 2215 1.12 mycroft mlpp = &mlp->ml_next; 2216 1.12 mycroft mlp = mlp->ml_next; 2217 1.1 cgd } 2218 1.1 cgd } 2219 1.1 cgd if (fnd) { 2220 1.1 cgd if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 2221 1.47 christos syslog(LOG_ERR, "Can't update %s: %m", 2222 1.47 christos _PATH_RMOUNTLIST); 2223 1.41 lukem return ret; 2224 1.1 cgd } 2225 1.1 cgd mlp = mlhead; 2226 1.1 cgd while (mlp) { 2227 1.47 christos (void)fprintf(mlfile, "%s %s\n", mlp->ml_host, 2228 1.47 christos mlp->ml_dirp); 2229 1.1 cgd mlp = mlp->ml_next; 2230 1.1 cgd } 2231 1.47 christos (void)fclose(mlfile); 2232 1.1 cgd } 2233 1.36 fvdl return ret; 2234 1.1 cgd } 2235 1.1 cgd 2236 1.47 christos static void 2237 1.122 joerg add_mlist(char *hostp, char *dirp, int flags) 2238 1.1 cgd { 2239 1.12 mycroft struct mountlist *mlp, **mlpp; 2240 1.1 cgd FILE *mlfile; 2241 1.1 cgd 2242 1.1 cgd mlpp = &mlhead; 2243 1.1 cgd mlp = mlhead; 2244 1.1 cgd while (mlp) { 2245 1.1 cgd if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 2246 1.1 cgd return; 2247 1.1 cgd mlpp = &mlp->ml_next; 2248 1.1 cgd mlp = mlp->ml_next; 2249 1.1 cgd } 2250 1.47 christos mlp = emalloc(sizeof(*mlp)); 2251 1.12 mycroft strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 2252 1.12 mycroft mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 2253 1.12 mycroft strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 2254 1.12 mycroft mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 2255 1.36 fvdl mlp->ml_flag = flags; 2256 1.47 christos mlp->ml_next = NULL; 2257 1.1 cgd *mlpp = mlp; 2258 1.1 cgd if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 2259 1.32 mrg syslog(LOG_ERR, "Can't update %s: %m", _PATH_RMOUNTLIST); 2260 1.1 cgd return; 2261 1.1 cgd } 2262 1.47 christos (void)fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 2263 1.47 christos (void)fclose(mlfile); 2264 1.1 cgd } 2265 1.1 cgd 2266 1.128 christos #ifndef MOUNTD_RUMP 2267 1.128 christos static int 2268 1.128 christos umntall_each(caddr_t resultsp, struct sockaddr_in *raddr) 2269 1.128 christos { 2270 1.128 christos return (1); 2271 1.128 christos } 2272 1.128 christos #endif 2273 1.128 christos 2274 1.1 cgd /* 2275 1.1 cgd * This function is called via. SIGTERM when the system is going down. 2276 1.1 cgd * It sends a broadcast RPCMNT_UMNTALL. 2277 1.1 cgd */ 2278 1.47 christos /* ARGSUSED */ 2279 1.47 christos static void 2280 1.122 joerg send_umntall(int n) 2281 1.1 cgd { 2282 1.128 christos #ifndef MOUNTD_RUMP 2283 1.47 christos (void)clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 2284 1.121 plunky (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_void, NULL, 2285 1.121 plunky (resultproc_t)umntall_each); 2286 1.128 christos #endif 2287 1.12 mycroft exit(0); 2288 1.1 cgd } 2289 1.1 cgd 2290 1.1 cgd 2291 1.1 cgd /* 2292 1.12 mycroft * Free up a group list. 2293 1.12 mycroft */ 2294 1.47 christos static void 2295 1.122 joerg free_grp(struct grouplist *grp) 2296 1.12 mycroft { 2297 1.12 mycroft 2298 1.12 mycroft if (grp->gr_type == GT_HOST) { 2299 1.68 itojun if (grp->gr_ptr.gt_addrinfo != NULL) 2300 1.64 fvdl freeaddrinfo(grp->gr_ptr.gt_addrinfo); 2301 1.12 mycroft } else if (grp->gr_type == GT_NET) { 2302 1.12 mycroft if (grp->gr_ptr.gt_net.nt_name) 2303 1.12 mycroft free(grp->gr_ptr.gt_net.nt_name); 2304 1.12 mycroft } 2305 1.47 christos free(grp); 2306 1.12 mycroft } 2307 1.12 mycroft 2308 1.47 christos #if 0 2309 1.47 christos static void 2310 1.47 christos SYSLOG(int pri, const char *fmt,...) 2311 1.12 mycroft { 2312 1.12 mycroft va_list ap; 2313 1.12 mycroft 2314 1.12 mycroft va_start(ap, fmt); 2315 1.28 thorpej 2316 1.131 joerg if (mountd_debug) 2317 1.28 thorpej vfprintf(stderr, fmt, ap); 2318 1.28 thorpej else 2319 1.28 thorpej vsyslog(pri, fmt, ap); 2320 1.28 thorpej 2321 1.12 mycroft va_end(ap); 2322 1.12 mycroft } 2323 1.47 christos #endif 2324 1.12 mycroft 2325 1.12 mycroft /* 2326 1.12 mycroft * Check options for consistency. 2327 1.12 mycroft */ 2328 1.47 christos static int 2329 1.122 joerg check_options(const char *line, size_t lineno, struct dirlist *dp) 2330 1.12 mycroft { 2331 1.12 mycroft 2332 1.52 christos if (dp == NULL) { 2333 1.52 christos syslog(LOG_ERR, 2334 1.52 christos "\"%s\", line %ld: missing directory list", 2335 1.52 christos line, (unsigned long)lineno); 2336 1.47 christos return (1); 2337 1.52 christos } 2338 1.47 christos if ((opt_flags & (OP_MAPROOT|OP_MAPALL)) == (OP_MAPROOT|OP_MAPALL) || 2339 1.47 christos (opt_flags & (OP_MAPROOT|OP_KERB)) == (OP_MAPROOT|OP_KERB) || 2340 1.47 christos (opt_flags & (OP_MAPALL|OP_KERB)) == (OP_MAPALL|OP_KERB)) { 2341 1.47 christos syslog(LOG_ERR, 2342 1.52 christos "\"%s\", line %ld: -mapall, -maproot and -kerb mutually exclusive", 2343 1.52 christos line, (unsigned long)lineno); 2344 1.47 christos return (1); 2345 1.12 mycroft } 2346 1.12 mycroft if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 2347 1.52 christos syslog(LOG_ERR, "\"%s\", line %ld: -mask requires -net", 2348 1.64 fvdl line, (unsigned long)lineno); 2349 1.64 fvdl return (1); 2350 1.64 fvdl } 2351 1.64 fvdl if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN) != 0) { 2352 1.77 fvdl syslog(LOG_ERR, "\"%s\", line %ld: /pref and -mask mutually" 2353 1.77 fvdl " exclusive", 2354 1.52 christos line, (unsigned long)lineno); 2355 1.47 christos return (1); 2356 1.12 mycroft } 2357 1.12 mycroft if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 2358 1.52 christos syslog(LOG_ERR, 2359 1.115 dholland "\"%s\", line %ld: -alldirs has multiple directories", 2360 1.52 christos line, (unsigned long)lineno); 2361 1.47 christos return (1); 2362 1.12 mycroft } 2363 1.12 mycroft return (0); 2364 1.12 mycroft } 2365 1.12 mycroft 2366 1.12 mycroft /* 2367 1.12 mycroft * Check an absolute directory path for any symbolic links. Return true 2368 1.12 mycroft * if no symbolic links are found. 2369 1.1 cgd */ 2370 1.47 christos static int 2371 1.122 joerg check_dirpath(const char *line, size_t lineno, char *dirp) 2372 1.1 cgd { 2373 1.12 mycroft char *cp; 2374 1.12 mycroft struct stat sb; 2375 1.119 lukem const char *file = ""; 2376 1.12 mycroft 2377 1.52 christos for (cp = dirp + 1; *cp; cp++) { 2378 1.12 mycroft if (*cp == '/') { 2379 1.12 mycroft *cp = '\0'; 2380 1.52 christos if (lstat(dirp, &sb) == -1) 2381 1.52 christos goto bad; 2382 1.52 christos if (!S_ISDIR(sb.st_mode)) 2383 1.52 christos goto bad1; 2384 1.12 mycroft *cp = '/'; 2385 1.12 mycroft } 2386 1.1 cgd } 2387 1.52 christos 2388 1.52 christos cp = NULL; 2389 1.52 christos if (lstat(dirp, &sb) == -1) 2390 1.52 christos goto bad; 2391 1.52 christos 2392 1.52 christos if (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode)) { 2393 1.52 christos file = " file or a"; 2394 1.52 christos goto bad1; 2395 1.52 christos } 2396 1.52 christos 2397 1.52 christos return 1; 2398 1.52 christos 2399 1.52 christos bad: 2400 1.52 christos syslog(LOG_ERR, 2401 1.52 christos "\"%s\", line %ld: lstat for `%s' failed: %m", 2402 1.52 christos line, (unsigned long)lineno, dirp); 2403 1.52 christos if (cp) 2404 1.52 christos *cp = '/'; 2405 1.52 christos return 0; 2406 1.52 christos 2407 1.52 christos bad1: 2408 1.52 christos syslog(LOG_ERR, 2409 1.52 christos "\"%s\", line %ld: `%s' is not a%s directory", 2410 1.56 mjl line, (unsigned long)lineno, dirp, file); 2411 1.52 christos if (cp) 2412 1.52 christos *cp = '/'; 2413 1.52 christos return 0; 2414 1.1 cgd } 2415 1.96 christos 2416 1.96 christos static void 2417 1.96 christos bind_resv_port(int sock, sa_family_t family, in_port_t port) 2418 1.96 christos { 2419 1.96 christos struct sockaddr *sa; 2420 1.96 christos struct sockaddr_in sasin; 2421 1.96 christos struct sockaddr_in6 sasin6; 2422 1.96 christos 2423 1.96 christos switch (family) { 2424 1.96 christos case AF_INET: 2425 1.96 christos (void)memset(&sasin, 0, sizeof(sasin)); 2426 1.96 christos sasin.sin_len = sizeof(sasin); 2427 1.96 christos sasin.sin_family = family; 2428 1.96 christos sasin.sin_port = htons(port); 2429 1.96 christos sa = (struct sockaddr *)(void *)&sasin; 2430 1.96 christos break; 2431 1.96 christos case AF_INET6: 2432 1.96 christos (void)memset(&sasin6, 0, sizeof(sasin6)); 2433 1.96 christos sasin6.sin6_len = sizeof(sasin6); 2434 1.96 christos sasin6.sin6_family = family; 2435 1.96 christos sasin6.sin6_port = htons(port); 2436 1.96 christos sa = (struct sockaddr *)(void *)&sasin6; 2437 1.96 christos break; 2438 1.96 christos default: 2439 1.96 christos syslog(LOG_ERR, "Unsupported address family %d", family); 2440 1.96 christos return; 2441 1.96 christos } 2442 1.96 christos if (bindresvport_sa(sock, sa) == -1) 2443 1.96 christos syslog(LOG_ERR, "Cannot bind to reserved port %d (%m)", port); 2444 1.96 christos } 2445 1.113 dholland 2446 1.113 dholland /* ARGSUSED */ 2447 1.113 dholland static void 2448 1.113 dholland no_nfs(int sig) 2449 1.113 dholland { 2450 1.113 dholland syslog(LOG_ERR, "kernel NFS support not present; exiting"); 2451 1.113 dholland exit(1); 2452 1.113 dholland } 2453