Index: usr.sbin/mountd/mountd.c =================================================================== --- usr.sbin/mountd/mountd.c +++ usr.sbin/mountd/mountd.c @@ -120,6 +120,8 @@ fsid_t ex_fs; char *ex_fsdir; char *ex_indexfile; + struct xucred ex_defanon; + int ex_defexflags; int ex_numsecflavors; int ex_secflavors[MAXSECFLAVORS]; int ex_defnumsecflavors; @@ -129,6 +131,9 @@ }; /* ex_flag bits */ #define EX_LINKED 0x1 +#define EX_DONE 0x2 +#define EX_DEFSET 0x4 +#define EX_PUBLICFH 0x8 SLIST_HEAD(exportlisthead, exportlist); @@ -147,6 +152,9 @@ int gr_type; union grouptypes gr_ptr; struct grouplist *gr_next; + struct xucred gr_anon; + int gr_exflags; + int gr_flag; int gr_numsecflavors; int gr_secflavors[MAXSECFLAVORS]; }; @@ -157,6 +165,9 @@ #define GT_DEFAULT 0x3 #define GT_IGNORE 0x5 +/* Group flags */ +#define GR_FND 0x1 + struct hostlist { int ht_flag; /* Uses DP_xx bits */ struct grouplist *ht_grp; @@ -176,7 +187,8 @@ /* Global defs */ static char *add_expdir(struct dirlist **, char *, int); static void add_dlist(struct dirlist **, struct dirlist *, - struct grouplist *, int, struct exportlist *); + struct grouplist *, int, struct exportlist *, + struct xucred *, int); static void add_mlist(char *, char *); static int check_dirpath(char *); static int check_options(struct dirlist *); @@ -189,8 +201,9 @@ static void clearout_service(void); static void del_mlist(char *hostp, char *dirp); static struct dirlist *dirp_search(struct dirlist *, char *); +static int do_export_mount(struct exportlist *, struct statfs *); static int do_mount(struct exportlist *, struct grouplist *, int, - struct xucred *, char *, int, struct statfs *); + struct xucred *, char *, int, struct statfs *, int, int *); static int do_opt(char **, char **, struct exportlist *, struct grouplist *, int *, int *, struct xucred *); static struct exportlist *ex_search(fsid_t *, struct exportlisthead *); @@ -199,10 +212,16 @@ static void free_exp(struct exportlist *); static void free_grp(struct grouplist *); static void free_host(struct hostlist *); -static void get_exportlist(void); +static void free_v4rootexp(void); +static void get_exportlist_one(int); +static void get_exportlist(int); static void insert_exports(struct exportlist *, struct exportlisthead *); static void free_exports(struct exportlisthead *); -static void read_exportfile(void); +static void read_exportfile(int); +static int compare_nmount_exportlist(struct iovec *, int, char *); +static int compare_export(struct exportlist *, struct exportlist *); +static int compare_cred(struct xucred *, struct xucred *); +static int compare_secflavor(int *, int *, int); static void delete_export(struct iovec *, int, struct statfs *, char *); static int get_host(char *, struct grouplist *, struct grouplist *); static struct hostlist *get_ht(void); @@ -212,7 +231,7 @@ static void getexp_err(struct exportlist *, struct grouplist *, const char *); static struct grouplist *get_grp(void); static void hang_dirp(struct dirlist *, struct grouplist *, - struct exportlist *, int); + struct exportlist *, int, struct xucred *, int); static void huphandler(int sig); static int makemask(struct sockaddr_storage *ssp, int bitlen); static void mntsrv(struct svc_req *, SVCXPRT *); @@ -237,6 +256,7 @@ #define EXPHASH(f) (fnv_32_buf((f), sizeof(fsid_t), 0) % exphashsize) static struct exportlisthead *exphead = NULL; +static struct exportlisthead *oldexphead = NULL; static int exphashsize = 0; static SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(&mlhead); static char *exnames_default[2] = { _PATH_EXPORTS, NULL }; @@ -269,7 +289,9 @@ static int v4root_phase = 0; static char v4root_dirpath[PATH_MAX + 1]; +static struct exportlist *v4root_ep = NULL; static int has_publicfh = 0; +static int has_set_publicfh = 0; static struct pidfh *pfh = NULL; /* Bits for opt_flags above */ @@ -293,6 +315,15 @@ #endif /* + * The LOGDEBUG() syslog() calls are always compiled into the daemon. + * To enable them, create a file at _PATH_MOUNTDDEBUG. This file can be empty. + * To disable the logging, just delete the file at _PATH_MOUNTDDEBUG. + */ +static int logdebug = 0; +#define LOGDEBUG(format, ...) \ + (logdebug ? syslog(LOG_DEBUG, format, ## __VA_ARGS__) : 0) + +/* * Similar to strsep(), but it allows for quoted strings * and escaped characters. * @@ -465,7 +496,7 @@ openlog("mountd", LOG_PID, LOG_DAEMON); if (debug) warnx("getting export list"); - get_exportlist(); + get_exportlist(0); if (debug) warnx("getting mount list"); get_mountlist(); @@ -636,7 +667,7 @@ /* Expand svc_run() here so that we can call get_exportlist(). */ for (;;) { if (got_sighup) { - get_exportlist(); + get_exportlist(1); got_sighup = 0; } readfds = svc_fdset; @@ -1426,10 +1457,10 @@ * Get the export list from one, currently open file */ static void -get_exportlist_one(void) +get_exportlist_one(int passno) { struct exportlist *ep; - struct grouplist *grp, *tgrp; + struct grouplist *grp, *tgrp, *savgrp; struct dirlist *dirhead; struct statfs fsb; struct xucred anon; @@ -1663,11 +1694,18 @@ * Loop through hosts, pushing the exports into the kernel. * After loop, tgrp points to the start of the list and * grp points to the last entry in the list. + * Do not do the do_mount() for passno == 1, since the + * second pass will do it, as required. */ grp = tgrp; do { - if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, - &fsb)) { + grp->gr_exflags = exflags; + grp->gr_anon = anon; + if (v4root_phase == 2 && passno == 0) + LOGDEBUG("do_mount v4root"); + if (passno == 0 && do_mount(ep, grp, exflags, &anon, + dirp, dirplen, &fsb, ep->ex_numsecflavors, + ep->ex_secflavors)) { getexp_err(ep, tgrp, NULL); goto nextline; } @@ -1678,9 +1716,32 @@ */ if (v4root_phase > 0 && v4root_phase <= 2) { /* - * Since these structures aren't used by mountd, + * These structures are used for the "-I" reload, + * so save them for that case. Otherwise, just * free them up now. */ + if (passno == 1 && ep != NULL) { + savgrp = tgrp; + while (tgrp != NULL) { + /* + * Save the security flavors and exflags + * for this host set in the groups. + */ + tgrp->gr_numsecflavors = + ep->ex_numsecflavors; + if (ep->ex_numsecflavors > 0) + memcpy(tgrp->gr_secflavors, + ep->ex_secflavors, + sizeof(ep->ex_secflavors)); + tgrp = tgrp->gr_next; + } + if (v4root_ep == NULL) { + v4root_ep = ep; + ep = NULL; /* Don't free below. */ + } + grp->gr_next = v4root_ep->ex_grphead; + v4root_ep->ex_grphead = savgrp; + } if (ep != NULL) free_exp(ep); while (tgrp != NULL) { @@ -1695,12 +1756,12 @@ * Success. Update the data structures. */ if (has_host) { - hang_dirp(dirhead, tgrp, ep, opt_flags); + hang_dirp(dirhead, tgrp, ep, opt_flags, &anon, exflags); grp->gr_next = ep->ex_grphead; ep->ex_grphead = tgrp; } else { hang_dirp(dirhead, (struct grouplist *)NULL, ep, - opt_flags); + opt_flags, &anon, exflags); free_grp(grp); } dirhead = (struct dirlist *)NULL; @@ -1722,7 +1783,7 @@ * Get the export list from all specified files */ static void -get_exportlist(void) +get_exportlist(int passno) { struct export_args export; struct iovec *iov; @@ -1731,24 +1792,51 @@ int num, i; int iovlen; struct nfsex_args eargs; + FILE *debug_file; - if (suspend_nfsd != 0) - (void)nfssvc(NFSSVC_SUSPENDNFSD, NULL); + if ((debug_file = fopen(_PATH_MOUNTDDEBUG, "r")) != NULL) { + fclose(debug_file); + logdebug = 1; + } else + logdebug = 0; + LOGDEBUG("passno=%d", passno); v4root_dirpath[0] = '\0'; + free_v4rootexp(); + if (passno == 1) { + /* + * Save the current lists as old ones, so that the new lists + * can be compared with the old ones in the 2nd pass. + */ + for (i = 0; i < exphashsize; i++) { + SLIST_FIRST(&oldexphead[i]) = SLIST_FIRST(&exphead[i]); + SLIST_INIT(&exphead[i]); + } + + /* Note that the public fh has not yet been set. */ + has_set_publicfh = 0; + + /* Read the export file(s) and process them */ + read_exportfile(passno); + } else { + /* + * Just make the old lists empty. + * exphashsize == 0 for the first call, before oldexphead + * has been initialized-->loop won't be executed. + */ + for (i = 0; i < exphashsize; i++) + SLIST_INIT(&oldexphead[i]); + } + bzero(&export, sizeof(export)); export.ex_flags = MNT_DELEXPORT; iov = NULL; iovlen = 0; bzero(errmsg, sizeof(errmsg)); + if (suspend_nfsd != 0) + (void)nfssvc(NFSSVC_SUSPENDNFSD, NULL); /* - * First, get rid of the old list - */ - if (exphead != NULL) - free_exports(exphead); - - /* - * and the old V4 root dir. + * Delete the old V4 root dir. */ bzero(&eargs, sizeof (eargs)); eargs.export.ex_flags = MNT_DELEXPORT; @@ -1756,44 +1844,77 @@ errno != ENOENT) syslog(LOG_ERR, "Can't delete exports for V4:"); - /* - * and clear flag that notes if a public fh has been exported. - */ - has_publicfh = 0; + build_iovec(&iov, &iovlen, "fstype", NULL, 0); + build_iovec(&iov, &iovlen, "fspath", NULL, 0); + build_iovec(&iov, &iovlen, "from", NULL, 0); + build_iovec(&iov, &iovlen, "update", NULL, 0); + build_iovec(&iov, &iovlen, "export", &export, + sizeof(export)); + build_iovec(&iov, &iovlen, "errmsg", errmsg, + sizeof(errmsg)); /* - * And delete exports that are in the kernel for all local - * filesystems. - * XXX: Should know how to handle all local exportable filesystems. + * For passno == 1, compare the old and new lists updating the kernel + * exports for any cases that have changed. + * This call is doing the second pass through the lists. + * If it fails, fall back on the bulk reload. */ - num = getmntinfo(&mntbufp, MNT_NOWAIT); + if (passno == 1 && compare_nmount_exportlist(iov, iovlen, errmsg) == + 0) { + LOGDEBUG("compareok"); + /* Free up the old lists. */ + free_exports(oldexphead); + } else { + LOGDEBUG("doing passno=0"); + /* + * Clear flag that notes if a public fh has been exported. + * It is set by do_mount() if MNT_EXPUBLIC is set for the entry. + */ + has_publicfh = 0; - /* Allocate hash tables, for first call. */ - if (exphead == NULL) { - /* Target an average linked list length of 10. */ - exphashsize = num / 10; - if (exphashsize < 1) - exphashsize = 1; - else if (exphashsize > 100000) - exphashsize = 100000; - exphead = malloc(exphashsize * sizeof(*exphead)); - if (exphead == NULL) - errx(1, "Can't malloc hash table"); + /* exphead == NULL if not yet allocated (first call). */ + if (exphead != NULL) { + /* + * First, get rid of the old lists. + */ + free_exports(exphead); + free_exports(oldexphead); + } - for (i = 0; i < exphashsize; i++) - SLIST_INIT(&exphead[i]); - } - if (num > 0) { - build_iovec(&iov, &iovlen, "fstype", NULL, 0); - build_iovec(&iov, &iovlen, "fspath", NULL, 0); - build_iovec(&iov, &iovlen, "from", NULL, 0); - build_iovec(&iov, &iovlen, "update", NULL, 0); - build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); - build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); - } + /* + * And delete exports that are in the kernel for all local + * filesystems. + * XXX: Should know how to handle all local exportable + * filesystems. + */ + num = getmntinfo(&mntbufp, MNT_NOWAIT); + + /* Allocate hash tables, for first call. */ + if (exphead == NULL) { + /* Target an average linked list length of 10. */ + exphashsize = num / 10; + if (exphashsize < 1) + exphashsize = 1; + else if (exphashsize > 100000) + exphashsize = 100000; + exphead = malloc(exphashsize * sizeof(*exphead)); + oldexphead = malloc(exphashsize * sizeof(*oldexphead)); + if (exphead == NULL || oldexphead == NULL) + errx(1, "Can't malloc hash tables"); + + for (i = 0; i < exphashsize; i++) { + SLIST_INIT(&exphead[i]); + SLIST_INIT(&oldexphead[i]); + } + } + + for (i = 0; i < num; i++) + delete_export(iov, iovlen, &mntbufp[i], errmsg); - for (i = 0; i < num; i++) - delete_export(iov, iovlen, &mntbufp[i], errmsg); + + /* Read the export file(s) and process them */ + read_exportfile(0); + } if (iov != NULL) { /* Free strings allocated by strdup() in getmntopts.c */ @@ -1809,16 +1930,17 @@ iovlen = 0; } - read_exportfile(); - /* * If there was no public fh, clear any previous one set. */ - if (has_publicfh == 0) + if (has_publicfh == 0) { + LOGDEBUG("clear public fh"); (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); + } /* Resume the nfsd. If they weren't suspended, this is harmless. */ (void)nfssvc(NFSSVC_RESUMENFSD, NULL); + LOGDEBUG("eo get_exportlist"); } /* @@ -1830,6 +1952,7 @@ uint32_t i; i = EXPHASH(&ep->ex_fs); + LOGDEBUG("fs=%s hash=%i", ep->ex_fsdir, i); SLIST_INSERT_HEAD(&exhp[i], ep, entries); } @@ -1855,7 +1978,7 @@ * Read the exports file(s) and call get_exportlist_one() for each line. */ static void -read_exportfile(void) +read_exportfile(int passno) { int done, i; @@ -1871,7 +1994,7 @@ syslog(LOG_WARNING, "can't open %s", exnames[i]); continue; } - get_exportlist_one(); + get_exportlist_one(passno); fclose(exp_file); done++; } @@ -1882,6 +2005,244 @@ } /* + * Compare the export lists against the old ones and do nmount() operations + * for any cases that have changed. This avoids doing nmount() for entries + * that have not changed. + * Return 0 upon success, 1 otherwise. + */ +static int +compare_nmount_exportlist(struct iovec *iov, int iovlen, char *errmsg) +{ + struct exportlist *ep, *oep; + struct grouplist *grp; + struct statfs fs, ofs; + int i, ret; + + /* + * Loop through the current list and look for an entry in the old + * list. + * If found, check to see if it the same. + * If it is not the same, delete and re-export. + * Then mark it done on the old list. + * else (not found) + * export it. + * Any entries left in the old list after processing must have their + * exports deleted. + */ + for (i = 0; i < exphashsize; i++) + SLIST_FOREACH(ep, &exphead[i], entries) { + LOGDEBUG("foreach ep=%s", ep->ex_fsdir); + oep = ex_search(&ep->ex_fs, oldexphead); + if (oep != NULL) { + /* + * Check the mount paths are the same. + * If not, return 1 so that the reload of the + * exports will be done in bulk, the + * passno == 0 way. + */ + LOGDEBUG("found old exp"); + if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0) + return (1); + LOGDEBUG("same fsdir"); + /* + * Test to see if the entry is the same. + * If not the same delete exports and + * re-export. + */ + if (compare_export(ep, oep) != 0) { + /* + * Clear has_publicfh if if was set + * in the old exports, but only if it + * has not been set during processing of + * the exports for this pass, as + * indicated by has_set_publicfh. + */ + if (has_set_publicfh == 0 && + (oep->ex_flag & EX_PUBLICFH) != 0) + has_publicfh = 0; + + /* Delete and re-export. */ + if (statfs(ep->ex_fsdir, &fs) < 0) + return (1); + delete_export(iov, iovlen, &fs, errmsg); + ret = do_export_mount(ep, &fs); + if (ret != 0) + return (ret); + } + oep->ex_flag |= EX_DONE; + LOGDEBUG("exdone"); + } else { + LOGDEBUG("not found so export"); + /* Not found, so do export. */ + if (statfs(ep->ex_fsdir, &fs) < 0) + return (1); + ret = do_export_mount(ep, &fs); + if (ret != 0) + return (ret); + } + } + + /* Delete exports not done. */ + for (i = 0; i < exphashsize; i++) + SLIST_FOREACH(oep, &oldexphead[i], entries) { + if ((oep->ex_flag & EX_DONE) == 0) { + LOGDEBUG("not done delete=%s", oep->ex_fsdir); + if (statfs(oep->ex_fsdir, &ofs) >= 0 && + oep->ex_fs.val[0] == ofs.f_fsid.val[0] && + oep->ex_fs.val[1] == ofs.f_fsid.val[1]) { + LOGDEBUG("do delete"); + /* + * Clear has_publicfh if if was set + * in the old exports, but only if it + * has not been set during processing of + * the exports for this pass, as + * indicated by has_set_publicfh. + */ + if (has_set_publicfh == 0 && + (oep->ex_flag & EX_PUBLICFH) != 0) + has_publicfh = 0; + + delete_export(iov, iovlen, &ofs, + errmsg); + } + } + } + + /* Do the V4 root exports, as required. */ + grp = NULL; + if (v4root_ep != NULL) + grp = v4root_ep->ex_grphead; + v4root_phase = 2; + while (v4root_ep != NULL && grp != NULL) { + LOGDEBUG("v4root expath=%s", v4root_dirpath); + ret = do_mount(v4root_ep, grp, grp->gr_exflags, &grp->gr_anon, + v4root_dirpath, strlen(v4root_dirpath), &fs, + grp->gr_numsecflavors, grp->gr_secflavors); + if (ret != 0) { + v4root_phase = 0; + return (ret); + } + grp = grp->gr_next; + } + v4root_phase = 0; + free_v4rootexp(); + return (0); +} + +/* + * Compare old and current exportlist entries for the fsid and return 0 + * if they are the same, 1 otherwise. + */ +static int +compare_export(struct exportlist *ep, struct exportlist *oep) +{ + struct grouplist *grp, *ogrp; + + if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0) + return (1); + if ((ep->ex_flag & EX_DEFSET) != (oep->ex_flag & EX_DEFSET)) + return (1); + if ((ep->ex_defdir != NULL && oep->ex_defdir == NULL) || + (ep->ex_defdir == NULL && oep->ex_defdir != NULL)) + return (1); + if (ep->ex_defdir != NULL && (ep->ex_defdir->dp_flag & DP_DEFSET) != + (oep->ex_defdir->dp_flag & DP_DEFSET)) + return (1); + if ((ep->ex_flag & EX_DEFSET) != 0 && (ep->ex_defnumsecflavors != + oep->ex_defnumsecflavors || ep->ex_defexflags != + oep->ex_defexflags || compare_cred(&ep->ex_defanon, + &oep->ex_defanon) != 0 || compare_secflavor(ep->ex_defsecflavors, + oep->ex_defsecflavors, ep->ex_defnumsecflavors) != 0)) + return (1); + + /* Now, check all the groups. */ + for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next) + ogrp->gr_flag = 0; + for (grp = ep->ex_grphead; grp != NULL; grp = grp->gr_next) { + for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = + ogrp->gr_next) + if ((ogrp->gr_flag & GR_FND) == 0 && + grp->gr_numsecflavors == ogrp->gr_numsecflavors && + grp->gr_exflags == ogrp->gr_exflags && + compare_cred(&grp->gr_anon, &ogrp->gr_anon) == 0 && + compare_secflavor(grp->gr_secflavors, + ogrp->gr_secflavors, grp->gr_numsecflavors) == 0) + break; + if (ogrp != NULL) + ogrp->gr_flag |= GR_FND; + else + return (1); + } + for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next) + if ((ogrp->gr_flag & GR_FND) == 0) + return (1); + return (0); +} + +/* + * This algorithm compares two arrays of "n" items. It returns 0 if they are + * the "same" and 1 otherwise. Although suboptimal, it is always safe to + * return 1, which makes compare_nmount_export() reload the exports entry. + * "same" refers to having the same set of values in the two arrays. + * The arrays are in no particular order and duplicates (multiple entries + * in an array with the same value) is allowed. + * The algorithm is inefficient, but the common case of indentical arrays is + * handled first and "n" is normally fairly small. + * Since the two functions need the same algorithm but for arrays of + * different types (gid_t vs int), this is done as a macro. + */ +#define COMPARE_ARRAYS(a1, a2, n) \ + do { \ + int fnd, fndarray[(n)], i, j; \ + /* Handle common case of identical arrays. */ \ + for (i = 0; i < (n); i++) \ + if ((a1)[i] != (a2)[i]) \ + break; \ + if (i == (n)) \ + return (0); \ + for (i = 0; i < (n); i++) \ + fndarray[i] = 0; \ + for (i = 0; i < (n); i++) { \ + fnd = 0; \ + for (j = 0; j < (n); j++) { \ + if ((a1)[i] == (a2)[j]) { \ + fndarray[j] = 1; \ + fnd = 1; \ + } \ + } \ + if (fnd == 0) \ + return (1); \ + } \ + for (i = 0; i < (n); i++) \ + if (fndarray[i] == 0) \ + return (1); \ + return (0); \ + } while (0) + +/* + * Compare to struct xucred's. Return 0 if the same and 1 otherwise. + */ +static int +compare_cred(struct xucred *cr0, struct xucred *cr1) +{ + + if (cr0->cr_uid != cr1->cr_uid || cr0->cr_ngroups != cr1->cr_ngroups) + return (1); + + COMPARE_ARRAYS(cr0->cr_groups, cr1->cr_groups, cr0->cr_ngroups); +} + +/* + * Compare two lists of security flavors. Return 0 if the same and 1 otherwise. + */ +static int +compare_secflavor(int *sec1, int *sec2, int nsec) +{ + + COMPARE_ARRAYS(sec1, sec2, nsec); +} + +/* * Delete an exports entry. */ static void @@ -2028,7 +2389,7 @@ */ static void hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, - int flags) + int flags, struct xucred *anoncrp, int exflags) { struct hostlist *hp; struct dirlist *dp2; @@ -2039,12 +2400,15 @@ else ep->ex_defdir = dp; if (grp == (struct grouplist *)NULL) { + ep->ex_flag |= EX_DEFSET; ep->ex_defdir->dp_flag |= DP_DEFSET; /* Save the default security flavors list. */ ep->ex_defnumsecflavors = ep->ex_numsecflavors; if (ep->ex_numsecflavors > 0) memcpy(ep->ex_defsecflavors, ep->ex_secflavors, sizeof(ep->ex_secflavors)); + ep->ex_defanon = *anoncrp; + ep->ex_defexflags = exflags; } else while (grp) { hp = get_ht(); hp->ht_grp = grp; @@ -2064,7 +2428,8 @@ */ while (dp) { dp2 = dp->dp_left; - add_dlist(&ep->ex_dirl, dp, grp, flags, ep); + add_dlist(&ep->ex_dirl, dp, grp, flags, ep, anoncrp, + exflags); dp = dp2; } } @@ -2076,7 +2441,7 @@ */ static void add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, - int flags, struct exportlist *ep) + int flags, struct exportlist *ep, struct xucred *anoncrp, int exflags) { struct dirlist *dp; struct hostlist *hp; @@ -2086,10 +2451,12 @@ if (dp) { cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); if (cmp > 0) { - add_dlist(&dp->dp_left, newdp, grp, flags, ep); + add_dlist(&dp->dp_left, newdp, grp, flags, ep, anoncrp, + exflags); return; } else if (cmp < 0) { - add_dlist(&dp->dp_right, newdp, grp, flags, ep); + add_dlist(&dp->dp_right, newdp, grp, flags, ep, anoncrp, + exflags); return; } else free((caddr_t)newdp); @@ -2116,12 +2483,15 @@ grp = grp->gr_next; } while (grp); } else { + ep->ex_flag |= EX_DEFSET; dp->dp_flag |= DP_DEFSET; /* Save the default security flavors list. */ ep->ex_defnumsecflavors = ep->ex_numsecflavors; if (ep->ex_numsecflavors > 0) memcpy(ep->ex_defsecflavors, ep->ex_secflavors, sizeof(ep->ex_secflavors)); + ep->ex_defanon = *anoncrp; + ep->ex_defexflags = exflags; } } @@ -2487,6 +2857,19 @@ } /* + * Free up the v4root exports. + */ +static void +free_v4rootexp(void) +{ + + if (v4root_ep != NULL) { + free_exp(v4root_ep); + v4root_ep = NULL; + } +} + +/* * Free hosts. */ static void @@ -2526,12 +2909,52 @@ } /* + * Call do_mount() from the struct exportlist, for each case needed. + */ +static int +do_export_mount(struct exportlist *ep, struct statfs *fsp) +{ + struct grouplist *grp, defgrp; + int ret; + size_t dirlen; + + LOGDEBUG("do_export_mount=%s", ep->ex_fsdir); + dirlen = strlen(ep->ex_fsdir); + if ((ep->ex_flag & EX_DEFSET) != 0) { + defgrp.gr_type = GT_DEFAULT; + defgrp.gr_next = NULL; + /* We have an entry for all other hosts/nets. */ + LOGDEBUG("ex_defexflags=0x%x", ep->ex_defexflags); + ret = do_mount(ep, &defgrp, ep->ex_defexflags, &ep->ex_defanon, + ep->ex_fsdir, dirlen, fsp, ep->ex_defnumsecflavors, + ep->ex_defsecflavors); + if (ret != 0) + return (ret); + } + + /* Do a mount for each group. */ + grp = ep->ex_grphead; + while (grp != NULL) { + LOGDEBUG("do mount gr_type=0x%x gr_exflags=0x%x", + grp->gr_type, grp->gr_exflags); + ret = do_mount(ep, grp, grp->gr_exflags, &grp->gr_anon, + ep->ex_fsdir, dirlen, fsp, grp->gr_numsecflavors, + grp->gr_secflavors); + if (ret != 0) + return (ret); + grp = grp->gr_next; + } + return (0); +} + +/* * Do the nmount() syscall with the update flag to push the export info into * the kernel. */ static int do_mount(struct exportlist *ep, struct grouplist *grp, int exflags, - struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) + struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb, + int numsecflavors, int *secflavors) { struct statfs fsb1; struct addrinfo *ai; @@ -2557,14 +2980,16 @@ bzero(errmsg, sizeof(errmsg)); eap->ex_flags = exflags; eap->ex_anon = *anoncrp; + LOGDEBUG("do_mount exflags=0x%x", exflags); eap->ex_indexfile = ep->ex_indexfile; if (grp->gr_type == GT_HOST) ai = grp->gr_ptr.gt_addrinfo; else ai = NULL; - eap->ex_numsecflavors = ep->ex_numsecflavors; + eap->ex_numsecflavors = numsecflavors; + LOGDEBUG("do_mount numsec=%d", numsecflavors); for (i = 0; i < eap->ex_numsecflavors; i++) - eap->ex_secflavors[i] = ep->ex_secflavors[i]; + eap->ex_secflavors[i] = secflavors[i]; if (eap->ex_numsecflavors == 0) { eap->ex_numsecflavors = 1; eap->ex_secflavors[0] = AUTH_SYS; @@ -2728,8 +3153,11 @@ else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) syslog(LOG_ERR, "Can't set public fh for %s", public_name); - else + else { has_publicfh = 1; + has_set_publicfh = 1; + ep->ex_flag |= EX_PUBLICFH; + } } skip: if (ai != NULL) Index: usr.sbin/mountd/pathnames.h =================================================================== --- usr.sbin/mountd/pathnames.h +++ usr.sbin/mountd/pathnames.h @@ -36,3 +36,4 @@ #define _PATH_EXPORTS "/etc/exports" #define _PATH_RMOUNTLIST "/var/db/mountdtab" #define _PATH_MOUNTDPID "/var/run/mountd.pid" +#define _PATH_MOUNTDDEBUG "/var/log/mountd.debug"