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