Commit | Line | Data |
---|---|---|
e3ab21d9 KM |
1 | /* |
2 | * Copyright (c) 1989 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Rick Macklem at The University of Guelph. | |
7 | * | |
70ab3c27 | 8 | * %sccs.include.redist.c% |
e3ab21d9 KM |
9 | */ |
10 | ||
11 | #ifndef lint | |
12 | char copyright[] = | |
13 | "@(#) Copyright (c) 1989 Regents of the University of California.\n\ | |
14 | All rights reserved.\n"; | |
15 | #endif not lint | |
16 | ||
17 | #ifndef lint | |
04b79a9c | 18 | static char sccsid[] = "@(#)mountd.c 5.14 (Berkeley) %G%"; |
e3ab21d9 KM |
19 | #endif not lint |
20 | ||
e3ab21d9 | 21 | #include <sys/param.h> |
e3ab21d9 KM |
22 | #include <sys/ioctl.h> |
23 | #include <sys/stat.h> | |
c2282441 | 24 | #include <sys/file.h> |
e3ab21d9 KM |
25 | #include <sys/mount.h> |
26 | #include <sys/socket.h> | |
e3ab21d9 | 27 | #include <sys/errno.h> |
38dde0cd KB |
28 | #include <sys/signal.h> |
29 | #include <stdio.h> | |
30 | #include <string.h> | |
31 | #include <syslog.h> | |
e3ab21d9 KM |
32 | #include <netdb.h> |
33 | #include <rpc/rpc.h> | |
34 | #include <rpc/pmap_clnt.h> | |
35 | #include <rpc/pmap_prot.h> | |
36 | #include <nfs/rpcv2.h> | |
37 | #include <nfs/nfsv2.h> | |
c2282441 | 38 | #include "pathnames.h" |
e3ab21d9 KM |
39 | |
40 | struct ufid { | |
41 | u_short ufid_len; | |
42 | ino_t ufid_ino; | |
43 | long ufid_gen; | |
44 | }; | |
45 | /* | |
46 | * Structures for keeping the mount list and export list | |
47 | */ | |
48 | struct mountlist { | |
e4fde528 | 49 | struct mountlist *ml_next; |
e3ab21d9 KM |
50 | char ml_host[RPCMNT_NAMELEN+1]; |
51 | char ml_dirp[RPCMNT_PATHLEN+1]; | |
52 | }; | |
53 | ||
54 | struct exportlist { | |
55 | struct exportlist *ex_next; | |
56 | struct exportlist *ex_prev; | |
57 | struct grouplist *ex_groups; | |
58 | int ex_rootuid; | |
59 | int ex_exflags; | |
e4fde528 | 60 | dev_t ex_dev; |
e3ab21d9 KM |
61 | char ex_dirp[RPCMNT_PATHLEN+1]; |
62 | }; | |
63 | ||
64 | struct grouplist { | |
65 | struct grouplist *gr_next; | |
c2282441 | 66 | struct hostent *gr_hp; |
e3ab21d9 KM |
67 | }; |
68 | ||
69 | /* Global defs */ | |
04b79a9c KB |
70 | int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist(); |
71 | void add_mlist(), del_mlist(), get_exportlist(), get_mountlist(); | |
72 | void send_umntall(); | |
e3ab21d9 | 73 | struct exportlist exphead; |
e4fde528 | 74 | struct mountlist *mlhead; |
e3ab21d9 KM |
75 | char exname[MAXPATHLEN]; |
76 | int def_rootuid = -2; | |
e4fde528 | 77 | int root_only = 1; |
e3ab21d9 KM |
78 | extern int errno; |
79 | #ifdef DEBUG | |
80 | int debug = 1; | |
81 | #else | |
82 | int debug = 0; | |
83 | #endif | |
84 | ||
85 | /* | |
86 | * Mountd server for NFS mount protocol as described in: | |
c2282441 | 87 | * NFS: Network File System Protocol Specification, RFC1094, Appendix A |
e4fde528 | 88 | * The optional arguments are the exports file name |
c2282441 | 89 | * default: _PATH_EXPORTS |
e4fde528 | 90 | * and "-n" to allow nonroot mount. |
e3ab21d9 KM |
91 | */ |
92 | main(argc, argv) | |
93 | int argc; | |
e4fde528 | 94 | char **argv; |
e3ab21d9 KM |
95 | { |
96 | SVCXPRT *transp; | |
e4fde528 KM |
97 | int c; |
98 | extern int optind; | |
99 | extern char *optarg; | |
e3ab21d9 | 100 | |
e4fde528 KM |
101 | while ((c = getopt(argc, argv, "n")) != EOF) |
102 | switch (c) { | |
103 | case 'n': | |
104 | root_only = 0; | |
105 | break; | |
106 | default: | |
107 | fprintf(stderr, "Usage: mountd [-n] [export_file]\n"); | |
108 | exit(1); | |
109 | }; | |
110 | argc -= optind; | |
111 | argv += optind; | |
112 | exphead.ex_next = exphead.ex_prev = (struct exportlist *)0; | |
113 | mlhead = (struct mountlist *)0; | |
114 | if (argc == 1) { | |
115 | strncpy(exname, *argv, MAXPATHLEN-1); | |
116 | exname[MAXPATHLEN-1] = '\0'; | |
117 | } else | |
118 | strcpy(exname, _PATH_EXPORTS); | |
91e44e87 | 119 | openlog("mountd:", LOG_PID, LOG_DAEMON); |
e4fde528 KM |
120 | get_exportlist(); |
121 | get_mountlist(); | |
e3ab21d9 | 122 | if (debug == 0) { |
43d42ac6 | 123 | daemon(0, 0); |
e3ab21d9 KM |
124 | signal(SIGINT, SIG_IGN); |
125 | signal(SIGQUIT, SIG_IGN); | |
e3ab21d9 | 126 | } |
e3ab21d9 | 127 | signal(SIGHUP, get_exportlist); |
e4fde528 | 128 | signal(SIGTERM, send_umntall); |
ccb4677f KM |
129 | { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); |
130 | if (pidfile != NULL) { | |
131 | fprintf(pidfile, "%d\n", getpid()); | |
132 | fclose(pidfile); | |
133 | } | |
134 | } | |
e3ab21d9 KM |
135 | if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) { |
136 | syslog(LOG_ERR, "Can't create socket"); | |
137 | exit(1); | |
138 | } | |
139 | pmap_unset(RPCPROG_MNT, RPCMNT_VER1); | |
140 | if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_UDP)) { | |
141 | syslog(LOG_ERR, "Can't register mount"); | |
142 | exit(1); | |
143 | } | |
144 | svc_run(); | |
145 | syslog(LOG_ERR, "Mountd died"); | |
43d42ac6 | 146 | exit(1); |
e3ab21d9 KM |
147 | } |
148 | ||
149 | /* | |
150 | * The mount rpc service | |
151 | */ | |
152 | mntsrv(rqstp, transp) | |
153 | register struct svc_req *rqstp; | |
154 | register SVCXPRT *transp; | |
155 | { | |
e3ab21d9 | 156 | register struct grouplist *grp; |
c2282441 KM |
157 | register u_long **addrp; |
158 | register struct exportlist *ep; | |
e3ab21d9 KM |
159 | nfsv2fh_t nfh; |
160 | struct authunix_parms *ucr; | |
161 | struct stat stb; | |
162 | struct hostent *hp; | |
c2282441 | 163 | u_long saddr; |
e3ab21d9 | 164 | char dirpath[RPCMNT_PATHLEN+1]; |
e3ab21d9 KM |
165 | int bad = ENOENT; |
166 | int omask; | |
c2282441 | 167 | uid_t uid = -2; |
e3ab21d9 KM |
168 | |
169 | /* Get authorization */ | |
170 | switch (rqstp->rq_cred.oa_flavor) { | |
171 | case AUTH_UNIX: | |
172 | ucr = (struct authunix_parms *)rqstp->rq_clntcred; | |
c2282441 KM |
173 | uid = ucr->aup_uid; |
174 | break; | |
e3ab21d9 KM |
175 | case AUTH_NULL: |
176 | default: | |
c2282441 | 177 | break; |
e3ab21d9 KM |
178 | } |
179 | ||
c2282441 KM |
180 | saddr = transp->xp_raddr.sin_addr.s_addr; |
181 | hp = (struct hostent *)0; | |
e3ab21d9 | 182 | switch (rqstp->rq_proc) { |
c2282441 KM |
183 | case NULLPROC: |
184 | if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) | |
185 | syslog(LOG_ERR, "Can't send reply"); | |
186 | return; | |
e3ab21d9 | 187 | case RPCMNT_MOUNT: |
e4fde528 | 188 | if (uid != 0 && root_only) { |
c2282441 | 189 | svcerr_weakauth(transp); |
e3ab21d9 KM |
190 | return; |
191 | } | |
c2282441 KM |
192 | if (!svc_getargs(transp, xdr_dir, dirpath)) { |
193 | svcerr_decode(transp); | |
e3ab21d9 KM |
194 | return; |
195 | } | |
196 | ||
e3ab21d9 KM |
197 | /* Check to see if it's a valid dirpath */ |
198 | if (stat(dirpath, &stb) < 0 || (stb.st_mode&S_IFMT) != | |
199 | S_IFDIR) { | |
200 | if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) | |
201 | syslog(LOG_ERR, "Can't send reply"); | |
202 | return; | |
203 | } | |
204 | ||
e3ab21d9 KM |
205 | /* Check in the exports list */ |
206 | omask = sigblock(sigmask(SIGHUP)); | |
207 | ep = exphead.ex_next; | |
208 | while (ep != NULL) { | |
209 | if (!strcmp(ep->ex_dirp, dirpath)) { | |
210 | grp = ep->ex_groups; | |
211 | if (grp == NULL) | |
212 | break; | |
c2282441 KM |
213 | |
214 | /* Check for a host match */ | |
215 | addrp = (u_long **)grp->gr_hp->h_addr_list; | |
216 | for (;;) { | |
217 | if (**addrp == saddr) | |
e3ab21d9 | 218 | break; |
c2282441 KM |
219 | if (*++addrp == NULL) |
220 | if (grp = grp->gr_next) { | |
221 | addrp = (u_long **) | |
222 | grp->gr_hp->h_addr_list; | |
223 | } else { | |
224 | bad = EACCES; | |
225 | if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) | |
226 | syslog(LOG_ERR, "Can't send reply"); | |
227 | sigsetmask(omask); | |
228 | return; | |
229 | } | |
e3ab21d9 | 230 | } |
c2282441 KM |
231 | hp = grp->gr_hp; |
232 | break; | |
e3ab21d9 KM |
233 | } |
234 | ep = ep->ex_next; | |
235 | } | |
236 | sigsetmask(omask); | |
237 | if (ep == NULL) { | |
238 | bad = EACCES; | |
239 | if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) | |
240 | syslog(LOG_ERR, "Can't send reply"); | |
241 | return; | |
242 | } | |
243 | ||
e3ab21d9 KM |
244 | /* Get the file handle */ |
245 | bzero((caddr_t)&nfh, sizeof(nfh)); | |
246 | if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { | |
247 | bad = errno; | |
248 | if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) | |
249 | syslog(LOG_ERR, "Can't send reply"); | |
250 | return; | |
251 | } | |
e3ab21d9 KM |
252 | if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) |
253 | syslog(LOG_ERR, "Can't send reply"); | |
c2282441 KM |
254 | if (hp == NULL) |
255 | hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); | |
e4fde528 KM |
256 | if (hp) |
257 | add_mlist(hp->h_name, dirpath); | |
e3ab21d9 KM |
258 | return; |
259 | case RPCMNT_DUMP: | |
260 | if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0)) | |
261 | syslog(LOG_ERR, "Can't send reply"); | |
262 | return; | |
263 | case RPCMNT_UMOUNT: | |
e4fde528 | 264 | if (uid != 0 && root_only) { |
c2282441 KM |
265 | svcerr_weakauth(transp); |
266 | return; | |
267 | } | |
e3ab21d9 KM |
268 | if (!svc_getargs(transp, xdr_dir, dirpath)) { |
269 | svcerr_decode(transp); | |
270 | return; | |
271 | } | |
e3ab21d9 KM |
272 | if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) |
273 | syslog(LOG_ERR, "Can't send reply"); | |
e4fde528 KM |
274 | hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); |
275 | if (hp) | |
276 | del_mlist(hp->h_name, dirpath); | |
e3ab21d9 KM |
277 | return; |
278 | case RPCMNT_UMNTALL: | |
e4fde528 | 279 | if (uid != 0 && root_only) { |
c2282441 KM |
280 | svcerr_weakauth(transp); |
281 | return; | |
282 | } | |
e3ab21d9 KM |
283 | if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) |
284 | syslog(LOG_ERR, "Can't send reply"); | |
e4fde528 KM |
285 | hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); |
286 | if (hp) | |
287 | del_mlist(hp->h_name, (char *)0); | |
e3ab21d9 KM |
288 | return; |
289 | case RPCMNT_EXPORT: | |
290 | if (!svc_sendreply(transp, xdr_explist, (caddr_t)0)) | |
291 | syslog(LOG_ERR, "Can't send reply"); | |
292 | return; | |
293 | default: | |
294 | svcerr_noproc(transp); | |
295 | return; | |
296 | } | |
297 | } | |
298 | ||
299 | /* | |
300 | * Xdr conversion for a dirpath string | |
301 | */ | |
302 | xdr_dir(xdrsp, dirp) | |
303 | XDR *xdrsp; | |
304 | char *dirp; | |
305 | { | |
306 | return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); | |
307 | } | |
308 | ||
309 | /* | |
310 | * Xdr routine to generate fhstatus | |
311 | */ | |
312 | xdr_fhs(xdrsp, nfh) | |
313 | XDR *xdrsp; | |
314 | nfsv2fh_t *nfh; | |
315 | { | |
316 | int ok = 0; | |
317 | ||
318 | if (!xdr_long(xdrsp, &ok)) | |
319 | return (0); | |
e3ab21d9 KM |
320 | return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); |
321 | } | |
322 | ||
323 | xdr_mlist(xdrsp, cp) | |
324 | XDR *xdrsp; | |
325 | caddr_t cp; | |
326 | { | |
e4fde528 | 327 | register struct mountlist *mlp; |
e3ab21d9 KM |
328 | int true = 1; |
329 | int false = 0; | |
330 | char *strp; | |
331 | ||
e4fde528 KM |
332 | mlp = mlhead; |
333 | while (mlp) { | |
334 | if (!xdr_bool(xdrsp, &true)) | |
335 | return (0); | |
336 | strp = &mlp->ml_host[0]; | |
337 | if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) | |
338 | return (0); | |
339 | strp = &mlp->ml_dirp[0]; | |
340 | if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) | |
341 | return (0); | |
342 | mlp = mlp->ml_next; | |
e3ab21d9 KM |
343 | } |
344 | if (!xdr_bool(xdrsp, &false)) | |
345 | return (0); | |
346 | return (1); | |
347 | } | |
348 | ||
349 | /* | |
350 | * Xdr conversion for export list | |
351 | */ | |
352 | xdr_explist(xdrsp, cp) | |
353 | XDR *xdrsp; | |
354 | caddr_t cp; | |
355 | { | |
356 | register struct exportlist *ep; | |
357 | register struct grouplist *grp; | |
358 | int true = 1; | |
359 | int false = 0; | |
360 | char *strp; | |
361 | int omask; | |
362 | ||
363 | omask = sigblock(sigmask(SIGHUP)); | |
364 | ep = exphead.ex_next; | |
365 | while (ep != NULL) { | |
366 | if (!xdr_bool(xdrsp, &true)) | |
367 | goto errout; | |
368 | strp = &ep->ex_dirp[0]; | |
369 | if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) | |
370 | goto errout; | |
371 | grp = ep->ex_groups; | |
372 | while (grp != NULL) { | |
373 | if (!xdr_bool(xdrsp, &true)) | |
374 | goto errout; | |
c2282441 | 375 | strp = grp->gr_hp->h_name; |
e3ab21d9 KM |
376 | if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) |
377 | goto errout; | |
378 | grp = grp->gr_next; | |
379 | } | |
380 | if (!xdr_bool(xdrsp, &false)) | |
381 | goto errout; | |
382 | ep = ep->ex_next; | |
383 | } | |
384 | sigsetmask(omask); | |
385 | if (!xdr_bool(xdrsp, &false)) | |
386 | return (0); | |
387 | return (1); | |
388 | errout: | |
389 | sigsetmask(omask); | |
390 | return (0); | |
391 | } | |
392 | ||
393 | #define LINESIZ 10240 | |
394 | char line[LINESIZ]; | |
395 | ||
396 | /* | |
397 | * Get the export list | |
398 | */ | |
04b79a9c | 399 | void |
e3ab21d9 KM |
400 | get_exportlist() |
401 | { | |
c2282441 KM |
402 | register struct hostent *hp, *nhp; |
403 | register char **addrp, **naddrp; | |
404 | register int i; | |
e4fde528 | 405 | register struct grouplist *grp; |
c2282441 | 406 | register struct exportlist *ep, *ep2; |
76bf9405 | 407 | struct statfs stfsbuf; |
dd66e524 | 408 | struct ufs_args args; |
e4fde528 | 409 | struct stat sb; |
e3ab21d9 KM |
410 | FILE *inf; |
411 | char *cp, *endcp; | |
c2282441 | 412 | char savedc; |
e4fde528 | 413 | int len, dirplen; |
e3ab21d9 | 414 | int rootuid, exflags; |
e4fde528 KM |
415 | u_long saddr; |
416 | struct exportlist *fep; | |
e3ab21d9 KM |
417 | |
418 | /* | |
419 | * First, get rid of the old list | |
420 | */ | |
421 | ep = exphead.ex_next; | |
422 | while (ep != NULL) { | |
e3ab21d9 KM |
423 | ep2 = ep; |
424 | ep = ep->ex_next; | |
e4fde528 | 425 | free_exp(ep2); |
e3ab21d9 KM |
426 | } |
427 | ||
428 | /* | |
429 | * Read in the exports file and build the list, calling | |
430 | * exportfs() as we go along | |
431 | */ | |
432 | exphead.ex_next = exphead.ex_prev = (struct exportlist *)0; | |
433 | if ((inf = fopen(exname, "r")) == NULL) { | |
434 | syslog(LOG_ERR, "Can't open %s", exname); | |
435 | exit(2); | |
436 | } | |
437 | while (fgets(line, LINESIZ, inf)) { | |
b5cedeb3 | 438 | exflags = MNT_EXPORTED; |
e3ab21d9 KM |
439 | rootuid = def_rootuid; |
440 | cp = line; | |
441 | nextfield(&cp, &endcp); | |
e4fde528 KM |
442 | |
443 | /* | |
444 | * Get file system devno and see if an entry for this | |
445 | * file system already exists. | |
446 | */ | |
447 | savedc = *endcp; | |
448 | *endcp = '\0'; | |
5b83dcdd KM |
449 | if (stat(cp, &sb) < 0 || (sb.st_mode & S_IFMT) != S_IFDIR) { |
450 | syslog(LOG_ERR, | |
451 | "Bad Exports File, %s: %s, mountd Failed", | |
452 | cp, "Not a directory"); | |
453 | exit(2); | |
454 | } | |
e4fde528 KM |
455 | fep = (struct exportlist *)0; |
456 | ep = exphead.ex_next; | |
457 | while (ep) { | |
458 | if (ep->ex_dev == sb.st_dev) { | |
459 | fep = ep; | |
460 | break; | |
461 | } | |
462 | ep = ep->ex_next; | |
463 | } | |
464 | *endcp = savedc; | |
465 | ||
466 | /* | |
467 | * Create new exports list entry | |
468 | */ | |
e3ab21d9 KM |
469 | len = endcp-cp; |
470 | if (len <= RPCMNT_PATHLEN && len > 0) { | |
471 | ep = (struct exportlist *)malloc(sizeof(*ep)); | |
5b83dcdd KM |
472 | if (ep == NULL) |
473 | goto err; | |
e3ab21d9 KM |
474 | ep->ex_next = ep->ex_prev = (struct exportlist *)0; |
475 | ep->ex_groups = (struct grouplist *)0; | |
476 | bcopy(cp, ep->ex_dirp, len); | |
477 | ep->ex_dirp[len] = '\0'; | |
e4fde528 | 478 | dirplen = len; |
5b83dcdd KM |
479 | } else { |
480 | syslog(LOG_ERR, "Bad Exports File, mountd Failed"); | |
481 | exit(2); | |
482 | } | |
e3ab21d9 KM |
483 | cp = endcp; |
484 | nextfield(&cp, &endcp); | |
485 | len = endcp-cp; | |
486 | while (len > 0) { | |
c2282441 KM |
487 | savedc = *endcp; |
488 | *endcp = '\0'; | |
5b83dcdd KM |
489 | if (len > RPCMNT_NAMELEN) |
490 | goto more; | |
491 | if (*cp == '-') { | |
492 | do_opt(cp + 1, fep, ep, &exflags, &rootuid); | |
493 | goto more; | |
494 | } | |
495 | if (isdigit(*cp)) { | |
496 | saddr = inet_addr(cp); | |
497 | if (saddr == -1 || | |
498 | (hp = gethostbyaddr((caddr_t)&saddr, | |
499 | sizeof(saddr), AF_INET)) == NULL) { | |
500 | syslog(LOG_ERR, | |
501 | "Bad Exports File, %s: %s", cp, | |
502 | "Gethostbyaddr failed, ignored"); | |
503 | goto more; | |
e3ab21d9 | 504 | } |
5b83dcdd KM |
505 | } else if ((hp = gethostbyname(cp)) == NULL) { |
506 | syslog(LOG_ERR, "Bad Exports File, %s: %s", | |
507 | cp, "Gethostbyname failed, ignored"); | |
508 | goto more; | |
509 | } | |
510 | grp = (struct grouplist *) | |
511 | malloc(sizeof(struct grouplist)); | |
512 | if (grp == NULL) | |
513 | goto err; | |
514 | nhp = grp->gr_hp = (struct hostent *) | |
515 | malloc(sizeof(struct hostent)); | |
516 | if (nhp == NULL) | |
517 | goto err; | |
518 | bcopy((caddr_t)hp, (caddr_t)nhp, | |
519 | sizeof(struct hostent)); | |
520 | i = strlen(hp->h_name)+1; | |
521 | nhp->h_name = (char *)malloc(i); | |
522 | if (nhp->h_name == NULL) | |
523 | goto err; | |
524 | bcopy(hp->h_name, nhp->h_name, i); | |
525 | addrp = hp->h_addr_list; | |
526 | i = 1; | |
527 | while (*addrp++) | |
528 | i++; | |
529 | naddrp = nhp->h_addr_list = (char **) | |
530 | malloc(i*sizeof(char *)); | |
531 | if (naddrp == NULL) | |
532 | goto err; | |
533 | addrp = hp->h_addr_list; | |
534 | while (*addrp) { | |
535 | *naddrp = (char *) | |
536 | malloc(hp->h_length); | |
537 | if (*naddrp == NULL) | |
538 | goto err; | |
539 | bcopy(*addrp, *naddrp, | |
540 | hp->h_length); | |
541 | addrp++; | |
542 | naddrp++; | |
e3ab21d9 | 543 | } |
5b83dcdd KM |
544 | *naddrp = (char *)0; |
545 | grp->gr_next = ep->ex_groups; | |
546 | ep->ex_groups = grp; | |
547 | more: | |
e3ab21d9 | 548 | cp = endcp; |
c2282441 | 549 | *cp = savedc; |
e3ab21d9 | 550 | nextfield(&cp, &endcp); |
5b83dcdd | 551 | len = endcp - cp; |
e3ab21d9 | 552 | } |
e4fde528 KM |
553 | if (fep == NULL) { |
554 | args.fspec = 0; | |
555 | args.exflags = exflags; | |
556 | args.exroot = rootuid; | |
557 | cp = (char *)0; | |
76bf9405 KM |
558 | while (statfs(ep->ex_dirp, &stfsbuf) < 0 || |
559 | mount(MOUNT_UFS, ep->ex_dirp, | |
560 | stfsbuf.f_flags|MNT_UPDATE, &args) < 0) { | |
e4fde528 KM |
561 | if (cp == NULL) |
562 | cp = ep->ex_dirp + dirplen - 1; | |
563 | else | |
564 | *cp = savedc; | |
565 | /* back up over the last component */ | |
566 | while (*cp == '/' && cp > ep->ex_dirp) | |
567 | cp--; | |
568 | while (*(cp - 1) != '/' && cp > ep->ex_dirp) | |
569 | cp--; | |
570 | if (cp == ep->ex_dirp) { | |
571 | syslog(LOG_WARNING, | |
572 | "Can't export %s", ep->ex_dirp); | |
573 | free_exp(ep); | |
574 | goto nextline; | |
575 | } | |
576 | savedc = *cp; | |
577 | *cp = '\0'; | |
578 | } | |
579 | if (cp) | |
580 | *cp = savedc; | |
e3ab21d9 KM |
581 | ep->ex_rootuid = rootuid; |
582 | ep->ex_exflags = exflags; | |
e4fde528 KM |
583 | } else { |
584 | ep->ex_rootuid = fep->ex_rootuid; | |
585 | ep->ex_exflags = fep->ex_exflags; | |
e3ab21d9 | 586 | } |
e4fde528 KM |
587 | ep->ex_dev = sb.st_dev; |
588 | ep->ex_next = exphead.ex_next; | |
589 | ep->ex_prev = &exphead; | |
590 | if (ep->ex_next != NULL) | |
591 | ep->ex_next->ex_prev = ep; | |
592 | exphead.ex_next = ep; | |
593 | nextline: | |
594 | ; | |
e3ab21d9 KM |
595 | } |
596 | fclose(inf); | |
597 | return; | |
598 | err: | |
5b83dcdd | 599 | syslog(LOG_ERR, "No more memory: mountd Failed"); |
e3ab21d9 KM |
600 | exit(2); |
601 | } | |
602 | ||
603 | /* | |
604 | * Parse out the next white space separated field | |
605 | */ | |
606 | nextfield(cp, endcp) | |
607 | char **cp; | |
608 | char **endcp; | |
609 | { | |
610 | register char *p; | |
611 | ||
612 | p = *cp; | |
613 | while (*p == ' ' || *p == '\t') | |
614 | p++; | |
615 | if (*p == '\n' || *p == '\0') { | |
616 | *cp = *endcp = p; | |
617 | return; | |
618 | } | |
619 | *cp = p++; | |
620 | while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') | |
621 | p++; | |
622 | *endcp = p; | |
623 | } | |
c2282441 KM |
624 | |
625 | /* | |
e4fde528 | 626 | * Parse the option string |
c2282441 | 627 | */ |
e4fde528 KM |
628 | do_opt(cpopt, fep, ep, exflagsp, rootuidp) |
629 | register char *cpopt; | |
630 | struct exportlist *fep, *ep; | |
631 | int *exflagsp, *rootuidp; | |
c2282441 | 632 | { |
e4fde528 KM |
633 | register char *cpoptarg, *cpoptend; |
634 | ||
635 | while (cpopt && *cpopt) { | |
636 | if (cpoptend = index(cpopt, ',')) | |
637 | *cpoptend++ = '\0'; | |
638 | if (cpoptarg = index(cpopt, '=')) | |
639 | *cpoptarg++ = '\0'; | |
640 | if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { | |
641 | if (fep && (fep->ex_exflags & MNT_EXRDONLY) == 0) | |
642 | syslog(LOG_WARNING, "ro failed for %s", | |
643 | ep->ex_dirp); | |
644 | else | |
645 | *exflagsp |= MNT_EXRDONLY; | |
646 | } else if (!strcmp(cpopt, "root") || !strcmp(cpopt, "r")) { | |
647 | if (cpoptarg && isdigit(*cpoptarg)) { | |
648 | *rootuidp = atoi(cpoptarg); | |
649 | if (fep && fep->ex_rootuid != *rootuidp) | |
650 | syslog(LOG_WARNING, | |
651 | "uid failed for %s", | |
652 | ep->ex_dirp); | |
653 | } else | |
654 | syslog(LOG_WARNING, | |
655 | "uid failed for %s", | |
656 | ep->ex_dirp); | |
657 | } else | |
658 | syslog(LOG_WARNING, "opt %s ignored for %s", cpopt, | |
659 | ep->ex_dirp); | |
660 | cpopt = cpoptend; | |
661 | } | |
662 | } | |
663 | ||
664 | #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) | |
665 | /* | |
666 | * Routines that maintain the remote mounttab | |
667 | */ | |
668 | void get_mountlist() | |
669 | { | |
670 | register struct mountlist *mlp, **mlpp; | |
671 | register char *eos, *dirp; | |
672 | int len; | |
673 | char str[STRSIZ]; | |
674 | FILE *mlfile; | |
675 | ||
91e44e87 KM |
676 | if (((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) && |
677 | ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL)) { | |
e4fde528 KM |
678 | syslog(LOG_WARNING, "Can't open %s", _PATH_RMOUNTLIST); |
679 | return; | |
680 | } | |
681 | mlpp = &mlhead; | |
682 | while (fgets(str, STRSIZ, mlfile) != NULL) { | |
683 | if ((dirp = index(str, '\t')) == NULL && | |
684 | (dirp = index(str, ' ')) == NULL) | |
685 | continue; | |
686 | mlp = (struct mountlist *)malloc(sizeof (*mlp)); | |
687 | len = dirp-str; | |
688 | if (len > RPCMNT_NAMELEN) | |
689 | len = RPCMNT_NAMELEN; | |
690 | bcopy(str, mlp->ml_host, len); | |
691 | mlp->ml_host[len] = '\0'; | |
692 | while (*dirp == '\t' || *dirp == ' ') | |
693 | dirp++; | |
694 | if ((eos = index(dirp, '\t')) == NULL && | |
695 | (eos = index(dirp, ' ')) == NULL && | |
696 | (eos = index(dirp, '\n')) == NULL) | |
697 | len = strlen(dirp); | |
698 | else | |
699 | len = eos-dirp; | |
700 | if (len > RPCMNT_PATHLEN) | |
701 | len = RPCMNT_PATHLEN; | |
702 | bcopy(dirp, mlp->ml_dirp, len); | |
703 | mlp->ml_dirp[len] = '\0'; | |
704 | mlp->ml_next = (struct mountlist *)0; | |
705 | *mlpp = mlp; | |
706 | mlpp = &mlp->ml_next; | |
707 | } | |
708 | fclose(mlfile); | |
709 | } | |
710 | ||
711 | void del_mlist(hostp, dirp) | |
712 | register char *hostp, *dirp; | |
713 | { | |
714 | register struct mountlist *mlp, **mlpp; | |
715 | FILE *mlfile; | |
716 | int fnd = 0; | |
717 | ||
718 | mlpp = &mlhead; | |
719 | mlp = mlhead; | |
720 | while (mlp) { | |
721 | if (!strcmp(mlp->ml_host, hostp) && | |
722 | (!dirp || !strcmp(mlp->ml_dirp, dirp))) { | |
723 | fnd = 1; | |
724 | *mlpp = mlp->ml_next; | |
725 | free((caddr_t)mlp); | |
726 | } | |
727 | mlpp = &mlp->ml_next; | |
728 | mlp = mlp->ml_next; | |
729 | } | |
730 | if (fnd) { | |
731 | if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { | |
732 | syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST); | |
733 | return; | |
734 | } | |
735 | mlp = mlhead; | |
736 | while (mlp) { | |
737 | fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); | |
738 | mlp = mlp->ml_next; | |
c2282441 | 739 | } |
e4fde528 KM |
740 | fclose(mlfile); |
741 | } | |
742 | } | |
743 | ||
744 | void add_mlist(hostp, dirp) | |
745 | register char *hostp, *dirp; | |
746 | { | |
747 | register struct mountlist *mlp, **mlpp; | |
748 | FILE *mlfile; | |
749 | ||
750 | mlpp = &mlhead; | |
751 | mlp = mlhead; | |
752 | while (mlp) { | |
753 | if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) | |
754 | return; | |
755 | mlpp = &mlp->ml_next; | |
756 | mlp = mlp->ml_next; | |
757 | } | |
758 | mlp = (struct mountlist *)malloc(sizeof (*mlp)); | |
759 | strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); | |
760 | mlp->ml_host[RPCMNT_NAMELEN] = '\0'; | |
761 | strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); | |
762 | mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; | |
763 | mlp->ml_next = (struct mountlist *)0; | |
764 | *mlpp = mlp; | |
765 | if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { | |
766 | syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST); | |
767 | return; | |
768 | } | |
769 | fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); | |
770 | fclose(mlfile); | |
771 | } | |
772 | ||
773 | /* | |
774 | * This function is called via. SIGTERM when the system is going down. | |
775 | * It sends a broadcast RPCMNT_UMNTALL. | |
776 | */ | |
04b79a9c | 777 | void |
e4fde528 KM |
778 | send_umntall() |
779 | { | |
780 | (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, | |
781 | xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); | |
782 | exit(); | |
783 | } | |
784 | ||
785 | umntall_each(resultsp, raddr) | |
786 | caddr_t resultsp; | |
787 | struct sockaddr_in *raddr; | |
788 | { | |
789 | return (1); | |
790 | } | |
791 | ||
792 | /* | |
793 | * Free up an exports list component | |
794 | */ | |
795 | free_exp(ep) | |
796 | register struct exportlist *ep; | |
797 | { | |
798 | register struct grouplist *grp; | |
799 | register char **addrp; | |
800 | struct grouplist *grp2; | |
801 | ||
802 | grp = ep->ex_groups; | |
803 | while (grp != NULL) { | |
804 | addrp = grp->gr_hp->h_addr_list; | |
805 | while (*addrp) | |
806 | free(*addrp++); | |
807 | free((caddr_t)grp->gr_hp->h_addr_list); | |
808 | free(grp->gr_hp->h_name); | |
809 | free((caddr_t)grp->gr_hp); | |
810 | grp2 = grp; | |
811 | grp = grp->gr_next; | |
812 | free((caddr_t)grp2); | |
c2282441 | 813 | } |
e4fde528 | 814 | free((caddr_t)ep); |
c2282441 | 815 | } |