2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Herb Hasler and Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * @(#) Copyright (c) 1989, 1993 The Regents of the University of California. All rights reserved.
37 * @(#)mountd.c 8.15 (Berkeley) 5/1/95
38 * $FreeBSD: src/sbin/mountd/mountd.c,v 1.39.2.5 2002/09/13 15:57:43 joerg Exp $
39 * $DragonFly: src/sbin/mountd/mountd.c,v 1.9 2008/02/05 20:49:51 dillon Exp $
42 #include <sys/param.h>
43 #include <sys/mount.h>
44 #include <sys/mountctl.h>
46 #include <sys/syslog.h>
47 #include <sys/sysctl.h>
50 #include <rpc/pmap_clnt.h>
51 #include <vfs/nfs/rpcv2.h>
52 #include <vfs/nfs/nfsproto.h>
53 #include <vfs/nfs/nfs.h>
54 #include <vfs/ufs/ufsmount.h>
55 #include <vfs/msdosfs/msdosfsmount.h>
56 #include <vfs/ntfs/ntfsmount.h>
57 #include <vfs/isofs/cd9660/cd9660_mount.h> /* XXX need isofs in include */
59 #include <arpa/inet.h>
72 #include "pathnames.h"
79 * Structures for keeping the mount list and export list
82 struct mountlist
*ml_next
;
83 char ml_host
[RPCMNT_NAMELEN
+1];
84 char ml_dirp
[RPCMNT_PATHLEN
+1];
88 struct dirlist
*dp_left
;
89 struct dirlist
*dp_right
;
91 struct hostlist
*dp_hosts
; /* List of hosts this dir exported to */
92 char dp_dirp
[1]; /* Actually malloc'd to size of dir */
96 #define DP_HOSTSET 0x2
100 struct exportlist
*ex_next
;
101 struct dirlist
*ex_dirl
;
102 struct dirlist
*ex_defdir
;
109 #define EX_LINKED 0x1
118 struct hostent
*gt_hostent
;
119 struct netmsk gt_net
;
124 union grouptypes gr_ptr
;
125 struct grouplist
*gr_next
;
131 #define GT_IGNORE 0x5
134 int ht_flag
; /* Uses DP_xx bits */
135 struct grouplist
*ht_grp
;
136 struct hostlist
*ht_next
;
146 char *add_expdir(struct dirlist
**, char *, int);
147 void add_dlist(struct dirlist
**, struct dirlist
*,
148 struct grouplist
*, int);
149 void add_mlist(char *, char *);
150 int check_dirpath(char *);
151 int check_options(struct dirlist
*);
152 int chk_host(struct dirlist
*, u_int32_t
, int *, int *);
153 void del_mlist(char *, char *);
154 struct dirlist
*dirp_search(struct dirlist
*, char *);
155 int do_mount(struct exportlist
*, struct grouplist
*, int,
156 struct ucred
*, char *, int, struct statfs
*);
157 int do_opt(char **, char **, struct exportlist
*, struct grouplist
*,
158 int *, int *, struct ucred
*);
159 struct exportlist
*ex_search(fsid_t
*);
160 struct exportlist
*get_exp(void);
161 void free_dir(struct dirlist
*);
162 void free_exp(struct exportlist
*);
163 void free_grp(struct grouplist
*);
164 void free_host(struct hostlist
*);
165 void get_exportlist(void);
166 int get_host(char *, struct grouplist
*, struct grouplist
*);
168 struct hostlist
*get_ht(void);
170 void get_mountlist(void);
171 int get_net(char *, struct netmsk
*, int);
172 void getexp_err(struct exportlist
*, struct grouplist
*);
173 struct grouplist
*get_grp(void);
174 void hang_dirp(struct dirlist
*, struct grouplist
*,
175 struct exportlist
*, int);
176 void mntsrv(struct svc_req
*, SVCXPRT
*);
177 void nextfield(char **, char **);
178 void out_of_mem(void);
179 void parsecred(char *, struct ucred
*);
180 int put_exlist(struct dirlist
*, XDR
*, struct dirlist
*, int *);
181 int scan_tree(struct dirlist
*, u_int32_t
);
182 static void usage(void);
183 int xdr_dir(XDR
*, char *);
184 int xdr_explist(XDR
*, caddr_t
);
185 int xdr_fhs(XDR
*, caddr_t
);
186 int xdr_mlist(XDR
*, caddr_t
);
188 struct exportlist
*exphead
;
189 struct mountlist
*mlhead
;
190 struct grouplist
*grphead
;
191 char exname
[MAXPATHLEN
];
192 struct ucred def_anon
= {
199 int resvport_only
= 1;
204 #define OP_MAPROOT 0x01
205 #define OP_MAPALL 0x02
209 #define OP_ALLDIRS 0x40
210 /* 0x80 is OP_HAVEMASK in FreeBSD 5+ */
211 #define OP_QUIET 0x100
215 void SYSLOG(int, const char *, ...);
216 #define syslog SYSLOG
222 * Mountd server for NFS mount protocol as described in:
223 * NFS: Network File System Protocol Specification, RFC1094, Appendix A
224 * The optional arguments are the exports file name
225 * default: _PATH_EXPORTS
226 * and "-n" to allow nonroot mount.
229 main(int argc
, char **argv
)
231 SVCXPRT
*udptransp
, *tcptransp
;
232 int c
, error
, mib
[3];
235 error
= getvfsbyname("nfs", &vfc
);
236 if (error
&& vfsisloadable("nfs")) {
238 err(1, "vfsload(nfs)");
239 endvfsent(); /* flush cache */
240 error
= getvfsbyname("nfs", &vfc
);
243 errx(1, "NFS support is not available in the running kernel");
245 while ((c
= getopt(argc
, argv
, "2dlnr")) != -1)
257 debug
= debug
? 0 : 1;
267 grphead
= (struct grouplist
*)NULL
;
268 exphead
= (struct exportlist
*)NULL
;
269 mlhead
= (struct mountlist
*)NULL
;
271 strncpy(exname
, *argv
, MAXPATHLEN
-1);
272 exname
[MAXPATHLEN
-1] = '\0';
274 strcpy(exname
, _PATH_EXPORTS
);
275 openlog("mountd", LOG_PID
, LOG_DAEMON
);
277 warnx("getting export list");
280 warnx("getting mount list");
286 signal(SIGINT
, SIG_IGN
);
287 signal(SIGQUIT
, SIG_IGN
);
289 signal(SIGHUP
, (void (*)(int)) get_exportlist
);
290 { FILE *pidfile
= fopen(_PATH_MOUNTDPID
, "w");
291 if (pidfile
!= NULL
) {
292 fprintf(pidfile
, "%d\n", getpid());
296 if (!resvport_only
) {
298 mib
[1] = vfc
.vfc_typenum
;
299 mib
[2] = NFS_NFSPRIVPORT
;
300 if (sysctl(mib
, 3, NULL
, NULL
, &resvport_only
,
301 sizeof(resvport_only
)) != 0 && errno
!= ENOENT
) {
302 syslog(LOG_ERR
, "sysctl: %m");
306 if ((udptransp
= svcudp_create(RPC_ANYSOCK
)) == NULL
||
307 (tcptransp
= svctcp_create(RPC_ANYSOCK
, 0, 0)) == NULL
) {
308 syslog(LOG_ERR
, "can't create socket");
311 pmap_unset(RPCPROG_MNT
, 1);
312 pmap_unset(RPCPROG_MNT
, 3);
314 if (!svc_register(udptransp
, RPCPROG_MNT
, 3, mntsrv
, IPPROTO_UDP
) ||
315 !svc_register(tcptransp
, RPCPROG_MNT
, 3, mntsrv
, IPPROTO_TCP
)) {
316 syslog(LOG_ERR
, "can't register mount");
319 if (!svc_register(udptransp
, RPCPROG_MNT
, 1, mntsrv
, IPPROTO_UDP
) ||
320 !svc_register(tcptransp
, RPCPROG_MNT
, 1, mntsrv
, IPPROTO_TCP
)) {
321 syslog(LOG_ERR
, "can't register mount");
325 syslog(LOG_ERR
, "mountd died");
333 "usage: mountd [-2] [-d] [-l] [-n] [-r] [export_file]\n");
338 * The mount rpc service
341 mntsrv(struct svc_req
*rqstp
, SVCXPRT
*transp
)
343 struct exportlist
*ep
;
349 struct in_addr saddrin
;
352 char rpcpath
[RPCMNT_PATHLEN
+ 1], dirpath
[MAXPATHLEN
];
353 int bad
= 0, defset
, hostset
;
354 sigset_t sighup_mask
;
356 sigemptyset(&sighup_mask
);
357 sigaddset(&sighup_mask
, SIGHUP
);
358 saddr
= transp
->xp_raddr
.sin_addr
.s_addr
;
359 saddrin
= transp
->xp_raddr
.sin_addr
;
360 sport
= ntohs(transp
->xp_raddr
.sin_port
);
361 hp
= (struct hostent
*)NULL
;
362 switch (rqstp
->rq_proc
) {
364 if (!svc_sendreply(transp
, xdr_void
, (caddr_t
)NULL
))
365 syslog(LOG_ERR
, "can't send reply");
368 if (sport
>= IPPORT_RESERVED
&& resvport_only
) {
370 "mount request from %s from unprivileged port",
372 svcerr_weakauth(transp
);
375 if (!svc_getargs(transp
, xdr_dir
, rpcpath
)) {
376 syslog(LOG_NOTICE
, "undecodable mount request from %s",
378 svcerr_decode(transp
);
383 * Get the real pathname and make sure it is a directory
384 * or a regular file if the -r option was specified
387 if (realpath(rpcpath
, dirpath
) == NULL
||
388 stat(dirpath
, &stb
) < 0 ||
389 (!S_ISDIR(stb
.st_mode
) &&
390 (dir_only
|| !S_ISREG(stb
.st_mode
))) ||
391 statfs(dirpath
, &fsb
) < 0) {
392 chdir("/"); /* Just in case realpath doesn't */
394 "mount request from %s for non existent path %s",
395 inet_ntoa(saddrin
), dirpath
);
397 warnx("stat failed on %s", dirpath
);
398 bad
= ENOENT
; /* We will send error reply later */
401 /* Check in the exports list */
402 sigprocmask(SIG_BLOCK
, &sighup_mask
, NULL
);
403 ep
= ex_search(&fsb
.f_fsid
);
404 hostset
= defset
= 0;
405 if (ep
&& (chk_host(ep
->ex_defdir
, saddr
, &defset
, &hostset
) ||
406 ((dp
= dirp_search(ep
->ex_dirl
, dirpath
)) &&
407 chk_host(dp
, saddr
, &defset
, &hostset
)) ||
408 (defset
&& scan_tree(ep
->ex_defdir
, saddr
) == 0 &&
409 scan_tree(ep
->ex_dirl
, saddr
) == 0))) {
411 if (!svc_sendreply(transp
, xdr_long
,
413 syslog(LOG_ERR
, "can't send reply");
414 sigprocmask(SIG_UNBLOCK
, &sighup_mask
, NULL
);
417 if (hostset
& DP_HOSTSET
)
418 fhr
.fhr_flag
= hostset
;
420 fhr
.fhr_flag
= defset
;
421 fhr
.fhr_vers
= rqstp
->rq_vers
;
422 /* Get the file handle */
423 memset(&fhr
.fhr_fh
, 0, sizeof(nfsfh_t
));
424 if (getfh(dirpath
, (fhandle_t
*)&fhr
.fhr_fh
) < 0) {
426 syslog(LOG_ERR
, "can't get fh for %s", dirpath
);
427 if (!svc_sendreply(transp
, xdr_long
,
429 syslog(LOG_ERR
, "can't send reply");
430 sigprocmask(SIG_UNBLOCK
, &sighup_mask
, NULL
);
433 if (!svc_sendreply(transp
, xdr_fhs
, (caddr_t
)&fhr
))
434 syslog(LOG_ERR
, "can't send reply");
436 hp
= gethostbyaddr((caddr_t
)&saddr
,
437 sizeof(saddr
), AF_INET
);
439 add_mlist(hp
->h_name
, dirpath
);
441 add_mlist(inet_ntoa(saddrin
),
444 warnx("mount successful");
447 "mount request succeeded from %s for %s",
448 inet_ntoa(saddrin
), dirpath
);
452 "mount request denied from %s for %s",
453 inet_ntoa(saddrin
), dirpath
);
456 if (bad
&& !svc_sendreply(transp
, xdr_long
, (caddr_t
)&bad
))
457 syslog(LOG_ERR
, "can't send reply");
458 sigprocmask(SIG_UNBLOCK
, &sighup_mask
, NULL
);
461 if (!svc_sendreply(transp
, xdr_mlist
, (caddr_t
)NULL
))
462 syslog(LOG_ERR
, "can't send reply");
465 "dump request succeeded from %s",
469 if (sport
>= IPPORT_RESERVED
&& resvport_only
) {
471 "umount request from %s from unprivileged port",
473 svcerr_weakauth(transp
);
476 if (!svc_getargs(transp
, xdr_dir
, rpcpath
)) {
477 syslog(LOG_NOTICE
, "undecodable umount request from %s",
479 svcerr_decode(transp
);
482 if (realpath(rpcpath
, dirpath
) == NULL
) {
483 syslog(LOG_NOTICE
, "umount request from %s "
484 "for non existent path %s",
485 inet_ntoa(saddrin
), dirpath
);
487 if (!svc_sendreply(transp
, xdr_void
, (caddr_t
)NULL
))
488 syslog(LOG_ERR
, "can't send reply");
489 hp
= gethostbyaddr((caddr_t
)&saddr
, sizeof(saddr
), AF_INET
);
491 del_mlist(hp
->h_name
, dirpath
);
492 del_mlist(inet_ntoa(saddrin
), dirpath
);
495 "umount request succeeded from %s for %s",
496 inet_ntoa(saddrin
), dirpath
);
499 if (sport
>= IPPORT_RESERVED
&& resvport_only
) {
501 "umountall request from %s from unprivileged port",
503 svcerr_weakauth(transp
);
506 if (!svc_sendreply(transp
, xdr_void
, (caddr_t
)NULL
))
507 syslog(LOG_ERR
, "can't send reply");
508 hp
= gethostbyaddr((caddr_t
)&saddr
, sizeof(saddr
), AF_INET
);
510 del_mlist(hp
->h_name
, (char *)NULL
);
511 del_mlist(inet_ntoa(saddrin
), (char *)NULL
);
514 "umountall request succeeded from %s",
518 if (!svc_sendreply(transp
, xdr_explist
, (caddr_t
)NULL
))
519 syslog(LOG_ERR
, "can't send reply");
522 "export request succeeded from %s",
526 svcerr_noproc(transp
);
532 * Xdr conversion for a dirpath string
535 xdr_dir(XDR
*xdrsp
, char *dirp
)
537 return (xdr_string(xdrsp
, &dirp
, RPCMNT_PATHLEN
));
541 * Xdr routine to generate file handle reply
544 xdr_fhs(XDR
*xdrsp
, caddr_t cp
)
546 struct fhreturn
*fhrp
= (struct fhreturn
*)cp
;
547 u_long ok
= 0, len
, auth
;
549 if (!xdr_long(xdrsp
, &ok
))
551 switch (fhrp
->fhr_vers
) {
553 return (xdr_opaque(xdrsp
, (caddr_t
)&fhrp
->fhr_fh
, NFSX_V2FH
));
556 if (!xdr_long(xdrsp
, &len
))
558 if (!xdr_opaque(xdrsp
, (caddr_t
)&fhrp
->fhr_fh
, len
))
560 if (fhrp
->fhr_flag
& DP_KERB
)
561 auth
= RPCAUTH_KERB4
;
565 if (!xdr_long(xdrsp
, &len
))
567 return (xdr_long(xdrsp
, &auth
));
573 xdr_mlist(XDR
*xdrsp
, caddr_t cp
)
575 struct mountlist
*mlp
;
582 if (!xdr_bool(xdrsp
, &true))
584 strp
= &mlp
->ml_host
[0];
585 if (!xdr_string(xdrsp
, &strp
, RPCMNT_NAMELEN
))
587 strp
= &mlp
->ml_dirp
[0];
588 if (!xdr_string(xdrsp
, &strp
, RPCMNT_PATHLEN
))
592 if (!xdr_bool(xdrsp
, &false))
598 * Xdr conversion for export list
601 xdr_explist(XDR
*xdrsp
, caddr_t cp
)
603 struct exportlist
*ep
;
606 sigset_t sighup_mask
;
608 sigemptyset(&sighup_mask
);
609 sigaddset(&sighup_mask
, SIGHUP
);
610 sigprocmask(SIG_BLOCK
, &sighup_mask
, NULL
);
614 if (put_exlist(ep
->ex_dirl
, xdrsp
, ep
->ex_defdir
, &putdef
))
616 if (ep
->ex_defdir
&& putdef
== 0 &&
617 put_exlist(ep
->ex_defdir
, xdrsp
, (struct dirlist
*)NULL
,
622 sigprocmask(SIG_UNBLOCK
, &sighup_mask
, NULL
);
623 if (!xdr_bool(xdrsp
, &false))
627 sigprocmask(SIG_UNBLOCK
, &sighup_mask
, NULL
);
632 * Called from xdr_explist() to traverse the tree and export the
636 put_exlist(struct dirlist
*dp
, XDR
*xdrsp
, struct dirlist
*adp
, int *putdefp
)
638 struct grouplist
*grp
;
646 if (put_exlist(dp
->dp_left
, xdrsp
, adp
, putdefp
))
648 if (!xdr_bool(xdrsp
, &true))
651 if (!xdr_string(xdrsp
, &strp
, RPCMNT_PATHLEN
))
653 if (adp
&& !strcmp(dp
->dp_dirp
, adp
->dp_dirp
)) {
657 if ((dp
->dp_flag
& DP_DEFSET
) == 0 &&
658 (gotalldir
== 0 || (adp
->dp_flag
& DP_DEFSET
) == 0)) {
662 if (grp
->gr_type
== GT_HOST
) {
663 if (!xdr_bool(xdrsp
, &true))
665 strp
= grp
->gr_ptr
.gt_hostent
->h_name
;
666 if (!xdr_string(xdrsp
, &strp
,
669 } else if (grp
->gr_type
== GT_NET
) {
670 if (!xdr_bool(xdrsp
, &true))
672 strp
= grp
->gr_ptr
.gt_net
.nt_name
;
673 if (!xdr_string(xdrsp
, &strp
,
678 if (gotalldir
&& hp
== (struct hostlist
*)NULL
) {
684 if (!xdr_bool(xdrsp
, &false))
686 if (put_exlist(dp
->dp_right
, xdrsp
, adp
, putdefp
))
692 #define LINESIZ 10240
697 * Get the export list
702 struct exportlist
*ep
, *ep2
;
703 struct grouplist
*grp
, *tgrp
;
704 struct exportlist
**epp
;
705 struct dirlist
*dirhead
;
706 struct statfs fsb
, *fsp
;
709 char *cp
, *endcp
, *dirp
, *hst
, *usr
, *dom
, savedc
;
710 int len
, has_host
, exflags
, got_nondir
, dirplen
, num
, i
, netgrp
;
716 * First, get rid of the old list
724 exphead
= (struct exportlist
*)NULL
;
732 grphead
= (struct grouplist
*)NULL
;
735 * And delete exports that are in the kernel for all local
737 * XXX: Should know how to handle all local exportable file systems
738 * instead of just "ufs".
740 num
= getmntinfo(&fsp
, MNT_NOWAIT
);
741 for (i
= 0; i
< num
; i
++) {
746 struct msdosfs_args da
;
749 struct export_args export
;
751 export
.ex_flags
= MNT_DELEXPORT
;
752 if (mountctl(fsp
->f_mntonname
, MOUNTCTL_SET_EXPORT
, -1,
753 &export
, sizeof(export
), NULL
, 0) == 0) {
754 } else if (!strcmp(fsp
->f_fstypename
, "mfs") ||
755 !strcmp(fsp
->f_fstypename
, "ufs") ||
756 !strcmp(fsp
->f_fstypename
, "msdos") ||
757 !strcmp(fsp
->f_fstypename
, "ntfs") ||
758 !strcmp(fsp
->f_fstypename
, "cd9660")) {
759 targs
.ua
.fspec
= NULL
;
760 targs
.ua
.export
.ex_flags
= MNT_DELEXPORT
;
761 if (mount(fsp
->f_fstypename
, fsp
->f_mntonname
,
762 fsp
->f_flags
| MNT_UPDATE
,
763 (caddr_t
)&targs
) < 0)
764 syslog(LOG_ERR
, "can't delete exports for %s",
771 * Read in the exports file and build the list, calling
772 * mount() as we go along to push the export rules into the kernel.
774 if ((exp_file
= fopen(exname
, "r")) == NULL
) {
775 syslog(LOG_ERR
, "can't open %s", exname
);
778 dirhead
= (struct dirlist
*)NULL
;
781 warnx("got line %s", line
);
783 nextfield(&cp
, &endcp
);
792 exflags
= MNT_EXPORTED
;
795 ep
= (struct exportlist
*)NULL
;
798 * Create new exports list entry
801 tgrp
= grp
= get_grp();
803 if (len
> RPCMNT_NAMELEN
) {
804 getexp_err(ep
, tgrp
);
808 if (ep
== (struct exportlist
*)NULL
) {
809 getexp_err(ep
, tgrp
);
813 warnx("doing opt %s", cp
);
815 if (do_opt(&cp
, &endcp
, ep
, grp
, &has_host
,
817 getexp_err(ep
, tgrp
);
820 } else if (*cp
== '/') {
823 if (check_dirpath(cp
) &&
824 statfs(cp
, &fsb
) >= 0) {
826 syslog(LOG_ERR
, "dirs must be first");
827 getexp_err(ep
, tgrp
);
831 if (ep
->ex_fs
.val
[0] != fsb
.f_fsid
.val
[0] ||
832 ep
->ex_fs
.val
[1] != fsb
.f_fsid
.val
[1]) {
833 getexp_err(ep
, tgrp
);
838 * See if this directory is already
841 ep
= ex_search(&fsb
.f_fsid
);
842 if (ep
== (struct exportlist
*)NULL
) {
844 ep
->ex_fs
= fsb
.f_fsid
;
845 ep
->ex_fsdir
= (char *)
846 malloc(strlen(fsb
.f_mntonname
) + 1);
853 warnx("making new ep fs=0x%x,0x%x",
857 warnx("found ep fs=0x%x,0x%x",
863 * Add dirpath to export mount point.
865 dirp
= add_expdir(&dirhead
, cp
, len
);
868 getexp_err(ep
, tgrp
);
876 if (ep
== (struct exportlist
*)NULL
) {
877 getexp_err(ep
, tgrp
);
882 * Get the host or netgroup.
885 netgrp
= getnetgrent(&hst
, &usr
, &dom
);
888 grp
->gr_next
= get_grp();
894 "null hostname in netgroup %s, skipping", cp
);
895 grp
->gr_type
= GT_IGNORE
;
896 } else if (get_host(hst
, grp
, tgrp
)) {
898 "bad host %s in netgroup %s, skipping", hst
, cp
);
899 grp
->gr_type
= GT_IGNORE
;
901 } else if (get_host(cp
, grp
, tgrp
)) {
902 syslog(LOG_ERR
, "bad host %s, skipping", cp
);
903 grp
->gr_type
= GT_IGNORE
;
906 } while (netgrp
&& getnetgrent(&hst
, &usr
, &dom
));
911 nextfield(&cp
, &endcp
);
914 if (check_options(dirhead
)) {
915 getexp_err(ep
, tgrp
);
919 grp
->gr_type
= GT_HOST
;
921 warnx("adding a default entry");
922 /* add a default group and make the grp list NULL */
923 hpe
= (struct hostent
*)malloc(sizeof(struct hostent
));
924 if (hpe
== (struct hostent
*)NULL
)
926 hpe
->h_name
= strdup("Default");
927 hpe
->h_addrtype
= AF_INET
;
928 hpe
->h_length
= sizeof (u_int32_t
);
929 hpe
->h_addr_list
= (char **)NULL
;
930 grp
->gr_ptr
.gt_hostent
= hpe
;
933 * Don't allow a network export coincide with a list of
934 * host(s) on the same line.
936 } else if ((opt_flags
& OP_NET
) && tgrp
->gr_next
) {
937 getexp_err(ep
, tgrp
);
941 * If an export list was specified on this line, make sure
942 * that we have at least one valid entry, otherwise skip it.
946 while (grp
&& grp
->gr_type
== GT_IGNORE
)
949 getexp_err(ep
, tgrp
);
955 * Loop through hosts, pushing the exports into the kernel.
956 * After loop, tgrp points to the start of the list and
957 * grp points to the last entry in the list.
961 if (do_mount(ep
, grp
, exflags
, &anon
, dirp
,
963 getexp_err(ep
, tgrp
);
966 } while (grp
->gr_next
&& (grp
= grp
->gr_next
));
969 * Success. Update the data structures.
972 hang_dirp(dirhead
, tgrp
, ep
, opt_flags
);
973 grp
->gr_next
= grphead
;
976 hang_dirp(dirhead
, (struct grouplist
*)NULL
, ep
,
980 dirhead
= (struct dirlist
*)NULL
;
981 if ((ep
->ex_flag
& EX_LINKED
) == 0) {
986 * Insert in the list in alphabetical order.
988 while (ep2
&& strcmp(ep2
->ex_fsdir
, ep
->ex_fsdir
) < 0) {
995 ep
->ex_flag
|= EX_LINKED
;
1000 dirhead
= (struct dirlist
*)NULL
;
1007 * Allocate an export list element
1012 struct exportlist
*ep
;
1014 ep
= (struct exportlist
*)malloc(sizeof (struct exportlist
));
1015 if (ep
== (struct exportlist
*)NULL
)
1017 memset(ep
, 0, sizeof(struct exportlist
));
1022 * Allocate a group list element
1027 struct grouplist
*gp
;
1029 gp
= (struct grouplist
*)malloc(sizeof (struct grouplist
));
1030 if (gp
== (struct grouplist
*)NULL
)
1032 memset(gp
, 0, sizeof(struct grouplist
));
1037 * Clean up upon an error in get_exportlist().
1040 getexp_err(struct exportlist
*ep
, struct grouplist
*grp
)
1042 struct grouplist
*tgrp
;
1044 if (!(opt_flags
& OP_QUIET
))
1045 syslog(LOG_ERR
, "bad exports list line %s", line
);
1046 if (ep
&& (ep
->ex_flag
& EX_LINKED
) == 0)
1056 * Search the export list for a matching fs.
1059 ex_search(fsid_t
*fsid
)
1061 struct exportlist
*ep
;
1065 if (ep
->ex_fs
.val
[0] == fsid
->val
[0] &&
1066 ep
->ex_fs
.val
[1] == fsid
->val
[1])
1074 * Add a directory path to the list.
1077 add_expdir(struct dirlist
**dpp
, char *cp
, int len
)
1081 dp
= (struct dirlist
*)malloc(sizeof (struct dirlist
) + len
);
1082 if (dp
== (struct dirlist
*)NULL
)
1085 dp
->dp_right
= (struct dirlist
*)NULL
;
1087 dp
->dp_hosts
= (struct hostlist
*)NULL
;
1088 strcpy(dp
->dp_dirp
, cp
);
1090 return (dp
->dp_dirp
);
1094 * Hang the dir list element off the dirpath binary tree as required
1095 * and update the entry for host.
1098 hang_dirp(struct dirlist
*dp
, struct grouplist
*grp
, struct exportlist
*ep
,
1101 struct hostlist
*hp
;
1102 struct dirlist
*dp2
;
1104 if (flags
& OP_ALLDIRS
) {
1109 if (grp
== (struct grouplist
*)NULL
) {
1110 ep
->ex_defdir
->dp_flag
|= DP_DEFSET
;
1111 if (flags
& OP_KERB
)
1112 ep
->ex_defdir
->dp_flag
|= DP_KERB
;
1113 } else while (grp
) {
1115 if (flags
& OP_KERB
)
1116 hp
->ht_flag
|= DP_KERB
;
1118 hp
->ht_next
= ep
->ex_defdir
->dp_hosts
;
1119 ep
->ex_defdir
->dp_hosts
= hp
;
1125 * Loop through the directories adding them to the tree.
1129 add_dlist(&ep
->ex_dirl
, dp
, grp
, flags
);
1136 * Traverse the binary tree either updating a node that is already there
1137 * for the new directory or adding the new node.
1140 add_dlist(struct dirlist
**dpp
, struct dirlist
*newdp
, struct grouplist
*grp
,
1144 struct hostlist
*hp
;
1149 cmp
= strcmp(dp
->dp_dirp
, newdp
->dp_dirp
);
1151 add_dlist(&dp
->dp_left
, newdp
, grp
, flags
);
1153 } else if (cmp
< 0) {
1154 add_dlist(&dp
->dp_right
, newdp
, grp
, flags
);
1157 free((caddr_t
)newdp
);
1160 dp
->dp_left
= (struct dirlist
*)NULL
;
1166 * Hang all of the host(s) off of the directory point.
1170 if (flags
& OP_KERB
)
1171 hp
->ht_flag
|= DP_KERB
;
1173 hp
->ht_next
= dp
->dp_hosts
;
1178 dp
->dp_flag
|= DP_DEFSET
;
1179 if (flags
& OP_KERB
)
1180 dp
->dp_flag
|= DP_KERB
;
1185 * Search for a dirpath on the export point.
1188 dirp_search(struct dirlist
*dp
, char *dirpath
)
1193 cmp
= strcmp(dp
->dp_dirp
, dirpath
);
1195 return (dirp_search(dp
->dp_left
, dirpath
));
1197 return (dirp_search(dp
->dp_right
, dirpath
));
1205 * Scan for a host match in a directory tree.
1208 chk_host(struct dirlist
*dp
, u_int32_t saddr
, int *defsetp
, int *hostsetp
)
1210 struct hostlist
*hp
;
1211 struct grouplist
*grp
;
1215 if (dp
->dp_flag
& DP_DEFSET
)
1216 *defsetp
= dp
->dp_flag
;
1220 switch (grp
->gr_type
) {
1222 addrp
= (u_int32_t
**)
1223 grp
->gr_ptr
.gt_hostent
->h_addr_list
;
1225 if (**addrp
== saddr
) {
1226 *hostsetp
= (hp
->ht_flag
| DP_HOSTSET
);
1233 if ((saddr
& grp
->gr_ptr
.gt_net
.nt_mask
) ==
1234 grp
->gr_ptr
.gt_net
.nt_net
) {
1235 *hostsetp
= (hp
->ht_flag
| DP_HOSTSET
);
1247 * Scan tree for a host that matches the address.
1250 scan_tree(struct dirlist
*dp
, u_int32_t saddr
)
1252 int defset
, hostset
;
1255 if (scan_tree(dp
->dp_left
, saddr
))
1257 if (chk_host(dp
, saddr
, &defset
, &hostset
))
1259 if (scan_tree(dp
->dp_right
, saddr
))
1266 * Traverse the dirlist tree and free it up.
1269 free_dir(struct dirlist
*dp
)
1273 free_dir(dp
->dp_left
);
1274 free_dir(dp
->dp_right
);
1275 free_host(dp
->dp_hosts
);
1281 * Parse the option string and update fields.
1282 * Option arguments may either be -<option>=<value> or
1286 do_opt(char **cpp
, char **endcpp
, struct exportlist
*ep
, struct grouplist
*grp
,
1287 int *has_hostp
, int *exflagsp
, struct ucred
*cr
)
1289 char *cpoptarg
, *cpoptend
;
1290 char *cp
, *endcp
, *cpopt
, savedc
, savedc2
;
1291 int allflag
, usedarg
;
1299 while (cpopt
&& *cpopt
) {
1302 if ((cpoptend
= strchr(cpopt
, ','))) {
1304 if ((cpoptarg
= strchr(cpopt
, '=')))
1307 if ((cpoptarg
= strchr(cpopt
, '=')))
1311 nextfield(&cp
, &endcp
);
1313 if (endcp
> cp
&& *cp
!= '-') {
1321 if (!strcmp(cpopt
, "ro") || !strcmp(cpopt
, "o")) {
1322 *exflagsp
|= MNT_EXRDONLY
;
1323 } else if (cpoptarg
&& (!strcmp(cpopt
, "maproot") ||
1324 !(allflag
= strcmp(cpopt
, "mapall")) ||
1325 !strcmp(cpopt
, "root") || !strcmp(cpopt
, "r"))) {
1327 parsecred(cpoptarg
, cr
);
1329 *exflagsp
|= MNT_EXPORTANON
;
1330 opt_flags
|= OP_MAPALL
;
1332 opt_flags
|= OP_MAPROOT
;
1333 } else if (!strcmp(cpopt
, "kerb") || !strcmp(cpopt
, "k")) {
1334 *exflagsp
|= MNT_EXKERB
;
1335 opt_flags
|= OP_KERB
;
1336 } else if (cpoptarg
&& (!strcmp(cpopt
, "mask") ||
1337 !strcmp(cpopt
, "m"))) {
1338 if (get_net(cpoptarg
, &grp
->gr_ptr
.gt_net
, 1)) {
1339 syslog(LOG_ERR
, "bad mask: %s", cpoptarg
);
1343 opt_flags
|= OP_MASK
;
1344 } else if (cpoptarg
&& (!strcmp(cpopt
, "network") ||
1345 !strcmp(cpopt
, "n"))) {
1346 if (grp
->gr_type
!= GT_NULL
) {
1347 syslog(LOG_ERR
, "network/host conflict");
1349 } else if (get_net(cpoptarg
, &grp
->gr_ptr
.gt_net
, 0)) {
1350 syslog(LOG_ERR
, "bad net: %s", cpoptarg
);
1353 grp
->gr_type
= GT_NET
;
1356 opt_flags
|= OP_NET
;
1357 } else if (!strcmp(cpopt
, "alldirs")) {
1358 opt_flags
|= OP_ALLDIRS
;
1359 } else if (!strcmp(cpopt
, "public")) {
1360 *exflagsp
|= MNT_EXPUBLIC
;
1361 } else if (!strcmp(cpopt
, "webnfs")) {
1362 *exflagsp
|= (MNT_EXPUBLIC
|MNT_EXRDONLY
|MNT_EXPORTANON
);
1363 opt_flags
|= OP_MAPALL
;
1364 } else if (cpoptarg
&& !strcmp(cpopt
, "index")) {
1365 ep
->ex_indexfile
= strdup(cpoptarg
);
1366 } else if (!strcmp(cpopt
, "quiet")) {
1367 opt_flags
|= OP_QUIET
;
1369 syslog(LOG_ERR
, "bad opt %s", cpopt
);
1388 * Translate a character string to the corresponding list of network
1389 * addresses for a hostname.
1392 get_host(char *cp
, struct grouplist
*grp
, struct grouplist
*tgrp
)
1394 struct grouplist
*checkgrp
;
1395 struct hostent
*hp
, *nhp
;
1396 char **addrp
, **naddrp
;
1397 struct hostent t_host
;
1402 if (grp
->gr_type
!= GT_NULL
)
1404 if ((hp
= gethostbyname(cp
)) == NULL
) {
1406 saddr
= inet_addr(cp
);
1408 syslog(LOG_ERR
, "inet_addr failed for %s", cp
);
1411 if ((hp
= gethostbyaddr((caddr_t
)&saddr
, sizeof (saddr
),
1412 AF_INET
)) == NULL
) {
1415 hp
->h_addrtype
= AF_INET
;
1416 hp
->h_length
= sizeof (u_int32_t
);
1417 hp
->h_addr_list
= aptr
;
1418 aptr
[0] = (char *)&saddr
;
1419 aptr
[1] = (char *)NULL
;
1422 syslog(LOG_ERR
, "gethostbyname failed for %s", cp
);
1427 * Sanity check: make sure we don't already have an entry
1428 * for this host in the grouplist.
1431 while (checkgrp
!= NULL
) {
1432 if (checkgrp
->gr_type
== GT_HOST
&&
1433 checkgrp
->gr_ptr
.gt_hostent
!= NULL
&&
1434 (!strcmp(checkgrp
->gr_ptr
.gt_hostent
->h_name
, hp
->h_name
)
1435 || *(u_int32_t
*)checkgrp
->gr_ptr
.gt_hostent
->h_addr
==
1436 *(u_int32_t
*)hp
->h_addr
)) {
1437 grp
->gr_type
= GT_IGNORE
;
1440 checkgrp
= checkgrp
->gr_next
;
1443 grp
->gr_type
= GT_HOST
;
1444 nhp
= grp
->gr_ptr
.gt_hostent
= (struct hostent
*)
1445 malloc(sizeof(struct hostent
));
1446 if (nhp
== (struct hostent
*)NULL
)
1448 memmove(nhp
, hp
, sizeof(struct hostent
));
1449 i
= strlen(hp
->h_name
)+1;
1450 nhp
->h_name
= (char *)malloc(i
);
1451 if (nhp
->h_name
== (char *)NULL
)
1453 memmove(nhp
->h_name
, hp
->h_name
, i
);
1454 addrp
= hp
->h_addr_list
;
1458 naddrp
= nhp
->h_addr_list
= (char **)malloc(i
*sizeof(char *));
1459 if (naddrp
== (char **)NULL
)
1461 addrp
= hp
->h_addr_list
;
1463 *naddrp
= (char *)malloc(hp
->h_length
);
1464 if (*naddrp
== (char *)NULL
)
1466 memmove(*naddrp
, *addrp
, hp
->h_length
);
1470 *naddrp
= (char *)NULL
;
1472 warnx("got host %s", hp
->h_name
);
1477 * Free up an exports list component
1480 free_exp(struct exportlist
*ep
)
1483 if (ep
->ex_defdir
) {
1484 free_host(ep
->ex_defdir
->dp_hosts
);
1485 free((caddr_t
)ep
->ex_defdir
);
1489 if (ep
->ex_indexfile
)
1490 free(ep
->ex_indexfile
);
1491 free_dir(ep
->ex_dirl
);
1499 free_host(struct hostlist
*hp
)
1501 struct hostlist
*hp2
;
1513 struct hostlist
*hp
;
1515 hp
= (struct hostlist
*)malloc(sizeof (struct hostlist
));
1516 if (hp
== (struct hostlist
*)NULL
)
1518 hp
->ht_next
= (struct hostlist
*)NULL
;
1524 * Out of memory, fatal
1530 syslog(LOG_ERR
, "out of memory");
1535 * Do the mount syscall with the update flag to push the export info into
1539 do_mount(struct exportlist
*ep
, struct grouplist
*grp
, int exflags
,
1540 struct ucred
*anoncrp
, char *dirp
, int dirplen
, struct statfs
*fsb
)
1547 struct sockaddr_in sin
, imask
;
1553 struct msdosfs_args da
;
1555 struct ntfs_args na
;
1560 args
.ua
.export
.ex_flags
= exflags
;
1561 args
.ua
.export
.ex_anon
= *anoncrp
;
1562 args
.ua
.export
.ex_indexfile
= ep
->ex_indexfile
;
1563 memset(&sin
, 0, sizeof(sin
));
1564 memset(&imask
, 0, sizeof(imask
));
1565 sin
.sin_family
= AF_INET
;
1566 sin
.sin_len
= sizeof(sin
);
1567 imask
.sin_family
= AF_INET
;
1568 imask
.sin_len
= sizeof(sin
);
1569 if (grp
->gr_type
== GT_HOST
)
1570 addrp
= (u_int32_t
**)grp
->gr_ptr
.gt_hostent
->h_addr_list
;
1572 addrp
= (u_int32_t
**)NULL
;
1575 switch (grp
->gr_type
) {
1578 sin
.sin_addr
.s_addr
= **addrp
;
1579 args
.ua
.export
.ex_addrlen
= sizeof(sin
);
1581 args
.ua
.export
.ex_addrlen
= 0;
1582 args
.ua
.export
.ex_addr
= (struct sockaddr
*)&sin
;
1583 args
.ua
.export
.ex_masklen
= 0;
1586 if (grp
->gr_ptr
.gt_net
.nt_mask
)
1587 imask
.sin_addr
.s_addr
= grp
->gr_ptr
.gt_net
.nt_mask
;
1589 net
= ntohl(grp
->gr_ptr
.gt_net
.nt_net
);
1591 imask
.sin_addr
.s_addr
= inet_addr("255.0.0.0");
1592 else if (IN_CLASSB(net
))
1593 imask
.sin_addr
.s_addr
=
1594 inet_addr("255.255.0.0");
1596 imask
.sin_addr
.s_addr
=
1597 inet_addr("255.255.255.0");
1598 grp
->gr_ptr
.gt_net
.nt_mask
= imask
.sin_addr
.s_addr
;
1600 sin
.sin_addr
.s_addr
= grp
->gr_ptr
.gt_net
.nt_net
;
1601 args
.ua
.export
.ex_addr
= (struct sockaddr
*)&sin
;
1602 args
.ua
.export
.ex_addrlen
= sizeof (sin
);
1603 args
.ua
.export
.ex_mask
= (struct sockaddr
*)&imask
;
1604 args
.ua
.export
.ex_masklen
= sizeof (imask
);
1610 syslog(LOG_ERR
, "bad grouptype");
1618 * Maybe I should just use the fsb->f_mntonname path instead
1619 * of looping back up the dirp to the mount point??
1620 * Also, needs to know how to export all types of local
1621 * exportable file systems and not just "ufs".
1626 r
= mountctl(fsb
->f_mntonname
, MOUNTCTL_SET_EXPORT
,
1628 &args
.ua
.export
, sizeof(args
.ua
.export
),
1630 if (r
< 0 && errno
== EOPNOTSUPP
) {
1631 r
= mount(fsb
->f_fstypename
, dirp
,
1632 fsb
->f_flags
| MNT_UPDATE
,
1640 cp
= dirp
+ dirplen
- 1;
1641 if (opt_flags
& OP_QUIET
)
1643 if (errno
== EPERM
) {
1645 "can't change attributes for %s", dirp
);
1648 if (opt_flags
& OP_ALLDIRS
) {
1649 if (errno
== EINVAL
)
1651 "-alldirs requested but %s is not a filesystem mountpoint",
1655 "could not remount %s: %m",
1659 /* back up over the last component */
1660 while (*cp
== '/' && cp
> dirp
)
1662 while (*(cp
- 1) != '/' && cp
> dirp
)
1666 warnx("mnt unsucc");
1667 syslog(LOG_ERR
, "can't export %s", dirp
);
1672 /* Check that we're still on the same filesystem. */
1673 if (statfs(dirp
, &fsb1
) != 0 || bcmp(&fsb1
.f_fsid
,
1674 &fsb
->f_fsid
, sizeof(fsb1
.f_fsid
)) != 0) {
1676 syslog(LOG_ERR
, "can't export %s", dirp
);
1682 if (*addrp
== (u_int32_t
*)NULL
)
1693 * Translate a net address.
1696 get_net(char *cp
, struct netmsk
*net
, int maskflg
)
1700 struct in_addr inetaddr
, inetaddr2
;
1703 if (isdigit(*cp
) && ((netaddr
= inet_network(cp
)) != -1)) {
1704 inetaddr
= inet_makeaddr(netaddr
, 0);
1706 * Due to arbitrary subnet masks, you don't know how many
1707 * bits to shift the address to make it into a network,
1708 * however you do know how to make a network address into
1709 * a host with host == 0 and then compare them.
1714 while ((np
= getnetent())) {
1715 inetaddr2
= inet_makeaddr(np
->n_net
, 0);
1716 if (inetaddr2
.s_addr
== inetaddr
.s_addr
)
1721 } else if ((np
= getnetbyname(cp
)) != NULL
) {
1722 inetaddr
= inet_makeaddr(np
->n_net
, 0);
1727 net
->nt_mask
= inetaddr
.s_addr
;
1732 name
= inet_ntoa(inetaddr
);
1733 net
->nt_name
= (char *)malloc(strlen(name
) + 1);
1734 if (net
->nt_name
== (char *)NULL
)
1736 strcpy(net
->nt_name
, name
);
1737 net
->nt_net
= inetaddr
.s_addr
;
1743 * Parse out the next white space separated field
1746 nextfield(char **cp
, char **endcp
)
1751 while (*p
== ' ' || *p
== '\t')
1753 if (*p
== '\n' || *p
== '\0')
1757 while (*p
!= ' ' && *p
!= '\t' && *p
!= '\n' && *p
!= '\0')
1764 * Get an exports file line. Skip over blank lines and handle line
1772 int totlen
, cont_line
;
1775 * Loop around ignoring blank lines and getting all continuation lines.
1780 if (fgets(p
, LINESIZ
- totlen
, exp_file
) == NULL
)
1786 (*cp
== ' ' || *cp
== '\t' || *cp
== '\n' || *cp
== '\\')) {
1799 if (totlen
>= LINESIZ
) {
1800 syslog(LOG_ERR
, "exports line too long");
1805 } while (totlen
== 0 || cont_line
);
1810 * Parse a description of a credential.
1813 parsecred(char *namelist
, struct ucred
*cr
)
1820 int ngroups
, groups
[NGROUPS
+ 1];
1823 * Set up the unprivileged user.
1827 cr
->cr_groups
[0] = -2;
1830 * Get the user's password table entry.
1832 names
= strsep(&namelist
, " \t\n");
1833 name
= strsep(&names
, ":");
1834 if (isdigit(*name
) || *name
== '-')
1835 pw
= getpwuid(atoi(name
));
1837 pw
= getpwnam(name
);
1839 * Credentials specified as those of a user.
1841 if (names
== NULL
) {
1843 syslog(LOG_ERR
, "unknown user: %s", name
);
1846 cr
->cr_uid
= pw
->pw_uid
;
1847 ngroups
= NGROUPS
+ 1;
1848 if (getgrouplist(pw
->pw_name
, pw
->pw_gid
, groups
, &ngroups
))
1849 syslog(LOG_ERR
, "too many groups");
1851 * Convert from int's to gid_t's and compress out duplicate
1853 cr
->cr_ngroups
= ngroups
- 1;
1854 cr
->cr_groups
[0] = groups
[0];
1855 for (cnt
= 2; cnt
< ngroups
; cnt
++)
1856 cr
->cr_groups
[cnt
- 1] = groups
[cnt
];
1860 * Explicit credential specified as a colon separated list:
1864 cr
->cr_uid
= pw
->pw_uid
;
1865 else if (isdigit(*name
) || *name
== '-')
1866 cr
->cr_uid
= atoi(name
);
1868 syslog(LOG_ERR
, "unknown user: %s", name
);
1872 while (names
!= NULL
&& *names
!= '\0' && cr
->cr_ngroups
< NGROUPS
) {
1873 name
= strsep(&names
, ":");
1874 if (isdigit(*name
) || *name
== '-') {
1875 cr
->cr_groups
[cr
->cr_ngroups
++] = atoi(name
);
1877 if ((gr
= getgrnam(name
)) == NULL
) {
1878 syslog(LOG_ERR
, "unknown group: %s", name
);
1881 cr
->cr_groups
[cr
->cr_ngroups
++] = gr
->gr_gid
;
1884 if (names
!= NULL
&& *names
!= '\0' && cr
->cr_ngroups
== NGROUPS
)
1885 syslog(LOG_ERR
, "too many groups");
1888 #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
1890 * Routines that maintain the remote mounttab
1895 struct mountlist
*mlp
, **mlpp
;
1896 char *host
, *dirp
, *cp
;
1900 if ((mlfile
= fopen(_PATH_RMOUNTLIST
, "r")) == NULL
) {
1901 if (errno
== ENOENT
)
1904 syslog(LOG_ERR
, "can't open %s", _PATH_RMOUNTLIST
);
1909 while (fgets(str
, STRSIZ
, mlfile
) != NULL
) {
1911 host
= strsep(&cp
, " \t\n");
1912 dirp
= strsep(&cp
, " \t\n");
1913 if (host
== NULL
|| dirp
== NULL
)
1915 mlp
= (struct mountlist
*)malloc(sizeof (*mlp
));
1916 if (mlp
== (struct mountlist
*)NULL
)
1918 strncpy(mlp
->ml_host
, host
, RPCMNT_NAMELEN
);
1919 mlp
->ml_host
[RPCMNT_NAMELEN
] = '\0';
1920 strncpy(mlp
->ml_dirp
, dirp
, RPCMNT_PATHLEN
);
1921 mlp
->ml_dirp
[RPCMNT_PATHLEN
] = '\0';
1922 mlp
->ml_next
= (struct mountlist
*)NULL
;
1924 mlpp
= &mlp
->ml_next
;
1930 del_mlist(char *hostp
, char *dirp
)
1932 struct mountlist
*mlp
, **mlpp
;
1933 struct mountlist
*mlp2
;
1940 if (!strcmp(mlp
->ml_host
, hostp
) &&
1941 (!dirp
|| !strcmp(mlp
->ml_dirp
, dirp
))) {
1944 *mlpp
= mlp
= mlp
->ml_next
;
1945 free((caddr_t
)mlp2
);
1947 mlpp
= &mlp
->ml_next
;
1952 if ((mlfile
= fopen(_PATH_RMOUNTLIST
, "w")) == NULL
) {
1953 syslog(LOG_ERR
,"can't update %s", _PATH_RMOUNTLIST
);
1958 fprintf(mlfile
, "%s %s\n", mlp
->ml_host
, mlp
->ml_dirp
);
1966 add_mlist(char *hostp
, char *dirp
)
1968 struct mountlist
*mlp
, **mlpp
;
1974 if (!strcmp(mlp
->ml_host
, hostp
) && !strcmp(mlp
->ml_dirp
, dirp
))
1976 mlpp
= &mlp
->ml_next
;
1979 mlp
= (struct mountlist
*)malloc(sizeof (*mlp
));
1980 if (mlp
== (struct mountlist
*)NULL
)
1982 strncpy(mlp
->ml_host
, hostp
, RPCMNT_NAMELEN
);
1983 mlp
->ml_host
[RPCMNT_NAMELEN
] = '\0';
1984 strncpy(mlp
->ml_dirp
, dirp
, RPCMNT_PATHLEN
);
1985 mlp
->ml_dirp
[RPCMNT_PATHLEN
] = '\0';
1986 mlp
->ml_next
= (struct mountlist
*)NULL
;
1988 if ((mlfile
= fopen(_PATH_RMOUNTLIST
, "a")) == NULL
) {
1989 syslog(LOG_ERR
, "can't update %s", _PATH_RMOUNTLIST
);
1992 fprintf(mlfile
, "%s %s\n", mlp
->ml_host
, mlp
->ml_dirp
);
1997 * Free up a group list.
2000 free_grp(struct grouplist
*grp
)
2004 if (grp
->gr_type
== GT_HOST
) {
2005 if (grp
->gr_ptr
.gt_hostent
->h_name
) {
2006 addrp
= grp
->gr_ptr
.gt_hostent
->h_addr_list
;
2007 while (addrp
&& *addrp
)
2009 free((caddr_t
)grp
->gr_ptr
.gt_hostent
->h_addr_list
);
2010 free(grp
->gr_ptr
.gt_hostent
->h_name
);
2012 free((caddr_t
)grp
->gr_ptr
.gt_hostent
);
2013 } else if (grp
->gr_type
== GT_NET
) {
2014 if (grp
->gr_ptr
.gt_net
.nt_name
)
2015 free(grp
->gr_ptr
.gt_net
.nt_name
);
2022 SYSLOG(int pri
, const char *fmt
, ...)
2027 vfprintf(stderr
, fmt
, ap
);
2033 * Check options for consistency.
2036 check_options(struct dirlist
*dp
)
2039 if (dp
== (struct dirlist
*)NULL
)
2041 if ((opt_flags
& (OP_MAPROOT
| OP_MAPALL
)) == (OP_MAPROOT
| OP_MAPALL
) ||
2042 (opt_flags
& (OP_MAPROOT
| OP_KERB
)) == (OP_MAPROOT
| OP_KERB
) ||
2043 (opt_flags
& (OP_MAPALL
| OP_KERB
)) == (OP_MAPALL
| OP_KERB
)) {
2044 syslog(LOG_ERR
, "-mapall, -maproot and -kerb mutually exclusive");
2047 if ((opt_flags
& OP_MASK
) && (opt_flags
& OP_NET
) == 0) {
2048 syslog(LOG_ERR
, "-mask requires -network");
2051 if ((opt_flags
& OP_ALLDIRS
) && dp
->dp_left
) {
2052 syslog(LOG_ERR
, "-alldirs has multiple directories");
2059 * Check an absolute directory path for any symbolic links. Return true
2060 * if no symbolic links are found.
2063 check_dirpath(char *dirp
)
2070 while (*cp
&& ret
) {
2073 if (lstat(dirp
, &sb
) < 0 || !S_ISDIR(sb
.st_mode
))
2079 if (lstat(dirp
, &sb
) < 0 || !S_ISDIR(sb
.st_mode
))
2085 * Just translate an ascii string to an integer.
2093 if (*cp
< '0' || *cp
> '9')
2095 res
= res
* 10 + (*cp
++ - '0');