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 | * | |
8 | * Redistribution and use in source and binary forms are permitted | |
9 | * provided that the above copyright notice and this paragraph are | |
10 | * duplicated in all such forms and that any documentation, | |
11 | * advertising materials, and other materials related to such | |
12 | * distribution and use acknowledge that the software was developed | |
13 | * by the University of California, Berkeley. The name of the | |
14 | * University may not be used to endorse or promote products derived | |
15 | * from this software without specific prior written permission. | |
16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
17 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
19 | */ | |
20 | ||
21 | #ifndef lint | |
22 | char copyright[] = | |
23 | "@(#) Copyright (c) 1989 Regents of the University of California.\n\ | |
24 | All rights reserved.\n"; | |
25 | #endif not lint | |
26 | ||
27 | #ifndef lint | |
28 | static char sccsid[] = "@(#)mountd.c 5.1 (Berkeley) %G%"; | |
29 | #endif not lint | |
30 | ||
31 | #include <stdio.h> | |
32 | #include <strings.h> | |
33 | #include <syslog.h> | |
34 | #include <signal.h> | |
35 | #include <fcntl.h> | |
36 | #include <sys/param.h> | |
37 | #include <sys/types.h> | |
38 | #include <sys/ioctl.h> | |
39 | #include <sys/stat.h> | |
40 | #include <sys/dir.h> | |
41 | #include <sys/uio.h> | |
42 | #include <sys/namei.h> | |
43 | #include <sys/mount.h> | |
44 | #include <sys/socket.h> | |
45 | #include <sys/socketvar.h> | |
46 | #include <sys/errno.h> | |
47 | #include <netdb.h> | |
48 | #include <rpc/rpc.h> | |
49 | #include <rpc/pmap_clnt.h> | |
50 | #include <rpc/pmap_prot.h> | |
51 | #include <nfs/rpcv2.h> | |
52 | #include <nfs/nfsv2.h> | |
53 | ||
54 | struct ufid { | |
55 | u_short ufid_len; | |
56 | ino_t ufid_ino; | |
57 | long ufid_gen; | |
58 | }; | |
59 | /* | |
60 | * Structures for keeping the mount list and export list | |
61 | */ | |
62 | struct mountlist { | |
63 | struct mountlist *ml_next; | |
64 | struct mountlist *ml_prev; | |
65 | char ml_host[RPCMNT_NAMELEN+1]; | |
66 | char ml_dirp[RPCMNT_PATHLEN+1]; | |
67 | }; | |
68 | ||
69 | struct exportlist { | |
70 | struct exportlist *ex_next; | |
71 | struct exportlist *ex_prev; | |
72 | struct grouplist *ex_groups; | |
73 | int ex_rootuid; | |
74 | int ex_exflags; | |
75 | char ex_dirp[RPCMNT_PATHLEN+1]; | |
76 | }; | |
77 | ||
78 | struct grouplist { | |
79 | struct grouplist *gr_next; | |
80 | char gr_name[RPCMNT_NAMELEN+1]; | |
81 | }; | |
82 | ||
83 | /* Global defs */ | |
84 | int xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist(); | |
85 | int mntsrv(), get_exportlist(); | |
86 | struct exportlist exphead; | |
87 | struct mountlist mlhead; | |
88 | char exname[MAXPATHLEN]; | |
89 | int def_rootuid = -2; | |
90 | extern int errno; | |
91 | #ifdef DEBUG | |
92 | int debug = 1; | |
93 | #else | |
94 | int debug = 0; | |
95 | #endif | |
96 | ||
97 | /* | |
98 | * Mountd server for NFS mount protocol as described in: | |
99 | * Networking on the Sun Workstation, | |
100 | * Part #800-1324-03 Rev. B | |
101 | * Network File System Protocol Specification Chap. 3 | |
102 | * The optional argument is the exports file name | |
103 | * default: /etc/exports | |
104 | */ | |
105 | main(argc, argv) | |
106 | int argc; | |
107 | char *argv[]; | |
108 | { | |
109 | SVCXPRT *transp; | |
110 | ||
111 | if (debug == 0) { | |
112 | if (fork()) | |
113 | exit(0); | |
114 | { int s; | |
115 | for (s = 0; s < 10; s++) | |
116 | (void) close(s); | |
117 | } | |
118 | (void) open("/", O_RDONLY); | |
119 | (void) dup2(0, 1); | |
120 | (void) dup2(0, 2); | |
121 | { int tt = open("/dev/tty", O_RDWR); | |
122 | if (tt > 0) { | |
123 | ioctl(tt, TIOCNOTTY, (char *)0); | |
124 | close(tt); | |
125 | } | |
126 | } | |
127 | (void) setpgrp(0, 0); | |
128 | signal(SIGTSTP, SIG_IGN); | |
129 | signal(SIGTTIN, SIG_IGN); | |
130 | signal(SIGTTOU, SIG_IGN); | |
131 | signal(SIGINT, SIG_IGN); | |
132 | signal(SIGQUIT, SIG_IGN); | |
133 | signal(SIGTERM, SIG_IGN); | |
134 | } | |
135 | openlog("mountd:", LOG_PID, LOG_DAEMON); | |
136 | mlhead.ml_next = mlhead.ml_prev = (struct mountlist *)0; | |
137 | exphead.ex_next = exphead.ex_prev = (struct exportlist *)0; | |
138 | if (argc == 2) { | |
139 | strncpy(exname, argv[1], MAXPATHLEN-1); | |
140 | exname[MAXPATHLEN-1] = '\0'; | |
141 | } else | |
142 | strcpy(exname, "/etc/exports"); | |
143 | get_exportlist(); | |
144 | signal(SIGHUP, get_exportlist); | |
145 | if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) { | |
146 | syslog(LOG_ERR, "Can't create socket"); | |
147 | exit(1); | |
148 | } | |
149 | pmap_unset(RPCPROG_MNT, RPCMNT_VER1); | |
150 | if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_UDP)) { | |
151 | syslog(LOG_ERR, "Can't register mount"); | |
152 | exit(1); | |
153 | } | |
154 | svc_run(); | |
155 | syslog(LOG_ERR, "Mountd died"); | |
156 | } | |
157 | ||
158 | /* | |
159 | * The mount rpc service | |
160 | */ | |
161 | mntsrv(rqstp, transp) | |
162 | register struct svc_req *rqstp; | |
163 | register SVCXPRT *transp; | |
164 | { | |
165 | register struct mountlist *mlp; | |
166 | register struct exportlist *ep; | |
167 | register struct grouplist *grp; | |
168 | struct mountlist *mlp2; | |
169 | nfsv2fh_t nfh; | |
170 | struct authunix_parms *ucr; | |
171 | struct stat stb; | |
172 | struct hostent *hp; | |
173 | struct sockaddr_in saddr; | |
174 | char dirpath[RPCMNT_PATHLEN+1]; | |
175 | int ok = 0; | |
176 | int bad = ENOENT; | |
177 | int omask; | |
178 | ||
179 | fprintf(stderr,"in mntsrv\n"); | |
180 | if (rqstp->rq_proc == NULLPROC) { | |
181 | if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) | |
182 | syslog(LOG_ERR, "Can't send reply"); | |
183 | return; | |
184 | } | |
185 | ||
186 | /* Get authorization */ | |
187 | switch (rqstp->rq_cred.oa_flavor) { | |
188 | case AUTH_UNIX: | |
189 | ucr = (struct authunix_parms *)rqstp->rq_clntcred; | |
190 | if (ucr->aup_uid == 0) | |
191 | break; | |
192 | /* Fall thru to */ | |
193 | fprintf(stderr,"weak auth\n"); | |
194 | case AUTH_NULL: | |
195 | default: | |
196 | svcerr_weakauth(transp); | |
197 | return; | |
198 | } | |
199 | ||
200 | saddr.sin_family = AF_INET; | |
201 | saddr.sin_addr.s_addr = ntohl(transp->xp_raddr.sin_addr.s_addr); | |
202 | saddr.sin_port = 0; | |
203 | hp = gethostbyaddr((caddr_t)&saddr, transp->xp_addrlen, AF_INET); | |
204 | fprintf(stderr,"net_addr=0x%x\n",transp->xp_raddr.sin_addr.s_addr); | |
205 | fprintf(stderr,"aft gethost hp=0x%x\n",hp); | |
206 | switch (rqstp->rq_proc) { | |
207 | case RPCMNT_MOUNT: | |
208 | fprintf(stderr,"in mnt req\n"); | |
209 | if (!svc_getargs(transp, xdr_dir, dirpath)) { | |
210 | svcerr_decode(transp); | |
211 | return; | |
212 | } | |
213 | ||
214 | fprintf(stderr,"dirpath=%s\n",dirpath); | |
215 | /* If no hostname, return err */ | |
216 | #ifdef notdef | |
217 | if (hp == NULL) { | |
218 | if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) | |
219 | syslog(LOG_ERR, "Can't send reply"); | |
220 | return; | |
221 | } | |
222 | ||
223 | #endif | |
224 | /* Check to see if it's a valid dirpath */ | |
225 | if (stat(dirpath, &stb) < 0 || (stb.st_mode&S_IFMT) != | |
226 | S_IFDIR) { | |
227 | if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) | |
228 | syslog(LOG_ERR, "Can't send reply"); | |
229 | return; | |
230 | } | |
231 | ||
232 | fprintf(stderr,"Look in exports list\n"); | |
233 | /* Check in the exports list */ | |
234 | omask = sigblock(sigmask(SIGHUP)); | |
235 | ep = exphead.ex_next; | |
236 | while (ep != NULL) { | |
237 | if (!strcmp(ep->ex_dirp, dirpath)) { | |
238 | grp = ep->ex_groups; | |
239 | if (grp == NULL) | |
240 | break; | |
241 | while (grp != NULL) { | |
242 | if (!strcmp(grp->gr_name, hp->h_name)) | |
243 | break; | |
244 | grp = grp->gr_next; | |
245 | } | |
246 | bad = EACCES; | |
247 | if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) | |
248 | syslog(LOG_ERR, "Can't send reply"); | |
249 | sigsetmask(omask); | |
250 | return; | |
251 | } | |
252 | ep = ep->ex_next; | |
253 | } | |
254 | sigsetmask(omask); | |
255 | if (ep == NULL) { | |
256 | bad = EACCES; | |
257 | if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) | |
258 | syslog(LOG_ERR, "Can't send reply"); | |
259 | return; | |
260 | } | |
261 | ||
262 | fprintf(stderr,"get file handle\n"); | |
263 | /* Get the file handle */ | |
264 | bzero((caddr_t)&nfh, sizeof(nfh)); | |
265 | if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { | |
266 | bad = errno; | |
267 | if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) | |
268 | syslog(LOG_ERR, "Can't send reply"); | |
269 | return; | |
270 | } | |
271 | { struct ufid *ufp; | |
272 | ufp = (struct ufid *)&nfh.fh_generic; | |
273 | fprintf(stderr,"ftyp=%d fnum=%d\n",nfh.fh_generic.fh_fsid.val[1], | |
274 | nfh.fh_generic.fh_fsid.val[0]); | |
275 | fprintf(stderr,"fid num=%d gen=%d\n",ufp->ufid_ino,ufp->ufid_gen); | |
276 | } | |
277 | if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) | |
278 | syslog(LOG_ERR, "Can't send reply"); | |
279 | mlp = (struct mountlist *)malloc(sizeof(struct mountlist)); | |
280 | fprintf(stderr,"add to list\n"); | |
281 | #ifdef notdef | |
282 | if (mlp != NULL) { | |
283 | strcpy(mlp->ml_host, hp->h_name); | |
284 | strcpy(mlp->ml_dirp, dirpath); | |
285 | mlp->ml_prev = &mlhead; | |
286 | mlp->ml_next = mlhead.ml_next; | |
287 | if (mlhead.ml_next != NULL) | |
288 | mlhead.ml_next->ml_prev = mlp; | |
289 | mlhead.ml_next = mlp; | |
290 | } | |
291 | #endif | |
292 | return; | |
293 | case RPCMNT_DUMP: | |
294 | if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0)) | |
295 | syslog(LOG_ERR, "Can't send reply"); | |
296 | return; | |
297 | case RPCMNT_UMOUNT: | |
298 | if (!svc_getargs(transp, xdr_dir, dirpath)) { | |
299 | svcerr_decode(transp); | |
300 | return; | |
301 | } | |
302 | if (hp != NULL) { | |
303 | mlp = mlhead.ml_next; | |
304 | while (mlp != NULL) { | |
305 | if (!strcmp(mlp->ml_host, hp->h_name) && | |
306 | !strcmp(mlp->ml_dirp, dirpath)) { | |
307 | mlp->ml_prev->ml_next = mlp->ml_next; | |
308 | if (mlp->ml_next != NULL) | |
309 | mlp->ml_next->ml_prev = | |
310 | mlp->ml_prev; | |
311 | free((caddr_t)mlp); | |
312 | break; | |
313 | } | |
314 | mlp = mlp->ml_next; | |
315 | } | |
316 | } | |
317 | if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) | |
318 | syslog(LOG_ERR, "Can't send reply"); | |
319 | return; | |
320 | case RPCMNT_UMNTALL: | |
321 | if (hp != NULL) { | |
322 | mlp = mlhead.ml_next; | |
323 | while (mlp != NULL) { | |
324 | if (!strcmp(mlp->ml_host, hp->h_name)) { | |
325 | mlp2 = mlp; | |
326 | mlp->ml_prev->ml_next = mlp->ml_next; | |
327 | if (mlp->ml_next != NULL) | |
328 | mlp->ml_next->ml_prev = | |
329 | mlp->ml_prev; | |
330 | mlp = mlp->ml_next; | |
331 | free((caddr_t)mlp2); | |
332 | } else | |
333 | mlp = mlp->ml_next; | |
334 | } | |
335 | } | |
336 | if (!svc_sendreply(transp, xdr_void, (caddr_t)0)) | |
337 | syslog(LOG_ERR, "Can't send reply"); | |
338 | return; | |
339 | case RPCMNT_EXPORT: | |
340 | if (!svc_sendreply(transp, xdr_explist, (caddr_t)0)) | |
341 | syslog(LOG_ERR, "Can't send reply"); | |
342 | return; | |
343 | default: | |
344 | svcerr_noproc(transp); | |
345 | return; | |
346 | } | |
347 | } | |
348 | ||
349 | /* | |
350 | * Xdr conversion for a dirpath string | |
351 | */ | |
352 | xdr_dir(xdrsp, dirp) | |
353 | XDR *xdrsp; | |
354 | char *dirp; | |
355 | { | |
356 | return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); | |
357 | } | |
358 | ||
359 | /* | |
360 | * Xdr routine to generate fhstatus | |
361 | */ | |
362 | xdr_fhs(xdrsp, nfh) | |
363 | XDR *xdrsp; | |
364 | nfsv2fh_t *nfh; | |
365 | { | |
366 | int ok = 0; | |
367 | ||
368 | if (!xdr_long(xdrsp, &ok)) | |
369 | return (0); | |
370 | fprintf(stderr,"eo xdr_fhs\n"); | |
371 | return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); | |
372 | } | |
373 | ||
374 | xdr_mlist(xdrsp, cp) | |
375 | XDR *xdrsp; | |
376 | caddr_t cp; | |
377 | { | |
378 | register struct mountlist *mlp; | |
379 | int true = 1; | |
380 | int false = 0; | |
381 | char *strp; | |
382 | ||
383 | mlp = mlhead.ml_next; | |
384 | while (mlp != NULL) { | |
385 | if (!xdr_bool(xdrsp, &true)) | |
386 | return (0); | |
387 | strp = &mlp->ml_host[0]; | |
388 | if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) | |
389 | return (0); | |
390 | strp = &mlp->ml_dirp[0]; | |
391 | if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) | |
392 | return (0); | |
393 | mlp = mlp->ml_next; | |
394 | } | |
395 | if (!xdr_bool(xdrsp, &false)) | |
396 | return (0); | |
397 | return (1); | |
398 | } | |
399 | ||
400 | /* | |
401 | * Xdr conversion for export list | |
402 | */ | |
403 | xdr_explist(xdrsp, cp) | |
404 | XDR *xdrsp; | |
405 | caddr_t cp; | |
406 | { | |
407 | register struct exportlist *ep; | |
408 | register struct grouplist *grp; | |
409 | int true = 1; | |
410 | int false = 0; | |
411 | char *strp; | |
412 | int omask; | |
413 | ||
414 | omask = sigblock(sigmask(SIGHUP)); | |
415 | ep = exphead.ex_next; | |
416 | while (ep != NULL) { | |
417 | if (!xdr_bool(xdrsp, &true)) | |
418 | goto errout; | |
419 | strp = &ep->ex_dirp[0]; | |
420 | if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) | |
421 | goto errout; | |
422 | grp = ep->ex_groups; | |
423 | while (grp != NULL) { | |
424 | if (!xdr_bool(xdrsp, &true)) | |
425 | goto errout; | |
426 | strp = &grp->gr_name[0]; | |
427 | if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) | |
428 | goto errout; | |
429 | grp = grp->gr_next; | |
430 | } | |
431 | if (!xdr_bool(xdrsp, &false)) | |
432 | goto errout; | |
433 | ep = ep->ex_next; | |
434 | } | |
435 | sigsetmask(omask); | |
436 | if (!xdr_bool(xdrsp, &false)) | |
437 | return (0); | |
438 | return (1); | |
439 | errout: | |
440 | sigsetmask(omask); | |
441 | return (0); | |
442 | } | |
443 | ||
444 | #define LINESIZ 10240 | |
445 | char line[LINESIZ]; | |
446 | ||
447 | /* | |
448 | * Get the export list | |
449 | */ | |
450 | get_exportlist() | |
451 | { | |
452 | register struct exportlist *ep, *ep2; | |
453 | register struct grouplist *grp, *grp2; | |
454 | FILE *inf; | |
455 | char *cp, *endcp; | |
456 | int len; | |
457 | int rootuid, exflags; | |
458 | ||
459 | /* | |
460 | * First, get rid of the old list | |
461 | */ | |
462 | ep = exphead.ex_next; | |
463 | while (ep != NULL) { | |
464 | grp = ep->ex_groups; | |
465 | while (grp != NULL) { | |
466 | grp2 = grp; | |
467 | grp = grp->gr_next; | |
468 | free((caddr_t)grp2); | |
469 | } | |
470 | ep2 = ep; | |
471 | ep = ep->ex_next; | |
472 | free((caddr_t)ep2); | |
473 | } | |
474 | ||
475 | /* | |
476 | * Read in the exports file and build the list, calling | |
477 | * exportfs() as we go along | |
478 | */ | |
479 | exphead.ex_next = exphead.ex_prev = (struct exportlist *)0; | |
480 | if ((inf = fopen(exname, "r")) == NULL) { | |
481 | syslog(LOG_ERR, "Can't open %s", exname); | |
482 | exit(2); | |
483 | } | |
484 | while (fgets(line, LINESIZ, inf)) { | |
485 | exflags = 0; | |
486 | rootuid = def_rootuid; | |
487 | cp = line; | |
488 | nextfield(&cp, &endcp); | |
489 | len = endcp-cp; | |
490 | if (len <= RPCMNT_PATHLEN && len > 0) { | |
491 | ep = (struct exportlist *)malloc(sizeof(*ep)); | |
492 | ep->ex_next = ep->ex_prev = (struct exportlist *)0; | |
493 | ep->ex_groups = (struct grouplist *)0; | |
494 | bcopy(cp, ep->ex_dirp, len); | |
495 | ep->ex_dirp[len] = '\0'; | |
496 | } else | |
497 | goto err; | |
498 | cp = endcp; | |
499 | nextfield(&cp, &endcp); | |
500 | len = endcp-cp; | |
501 | while (len > 0) { | |
502 | if (len <= RPCMNT_NAMELEN) { | |
503 | if (*cp == '-') { | |
504 | cp++; | |
505 | switch (*cp) { | |
506 | case 'o': | |
507 | exflags |= M_EXRDONLY; | |
508 | break; | |
509 | case 'r': | |
510 | if (*++cp == '=') | |
511 | rootuid = atoi(++cp); | |
512 | break; | |
513 | default: | |
514 | syslog(LOG_WARNING, | |
515 | "Bad -%c option in %s", | |
516 | *cp, exname); | |
517 | break; | |
518 | }; | |
519 | } else { | |
520 | grp = (struct grouplist *)malloc(*grp); | |
521 | if (grp == NULL) | |
522 | goto err; | |
523 | bcopy(cp, grp->gr_name, len); | |
524 | grp->gr_name[len] = '\0'; | |
525 | grp->gr_next = ep->ex_groups; | |
526 | ep->ex_groups = grp; | |
527 | } | |
528 | } | |
529 | cp = endcp; | |
530 | nextfield(&cp, &endcp); | |
531 | len = endcp-cp; | |
532 | } | |
533 | if (exportfs(ep->ex_dirp, rootuid, exflags) < 0) { | |
534 | syslog(LOG_WARNING, "Can't export %s", ep->ex_dirp); | |
535 | free((caddr_t)ep); | |
536 | } else { | |
537 | ep->ex_rootuid = rootuid; | |
538 | ep->ex_exflags = exflags; | |
539 | ep->ex_next = exphead.ex_next; | |
540 | ep->ex_prev = &exphead; | |
541 | if (ep->ex_next != NULL) | |
542 | ep->ex_next->ex_prev = ep; | |
543 | exphead.ex_next = ep; | |
544 | } | |
545 | } | |
546 | fclose(inf); | |
547 | return; | |
548 | err: | |
549 | syslog(LOG_ERR, "Bad /etc/exports, mountd Failed"); | |
550 | exit(2); | |
551 | } | |
552 | ||
553 | /* | |
554 | * Parse out the next white space separated field | |
555 | */ | |
556 | nextfield(cp, endcp) | |
557 | char **cp; | |
558 | char **endcp; | |
559 | { | |
560 | register char *p; | |
561 | ||
562 | p = *cp; | |
563 | while (*p == ' ' || *p == '\t') | |
564 | p++; | |
565 | if (*p == '\n' || *p == '\0') { | |
566 | *cp = *endcp = p; | |
567 | return; | |
568 | } | |
569 | *cp = p++; | |
570 | while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') | |
571 | p++; | |
572 | *endcp = p; | |
573 | } |