X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fmountd%2Fmountd.c;h=b59f939ee71154e2bd1ec3535c4d7987ea26e1db;hp=8137f7f7329f40d1cbab352c23ff311e34acee06;hb=abf92485ae52bd637d544e2ac73147271b310a14;hpb=3c1bb23c0379864722e79d19f74c180edcf2c36e diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c index 8137f7f..b59f939 100644 --- a/utils/mountd/mountd.c +++ b/utils/mountd/mountd.c @@ -26,6 +26,7 @@ #include "misc.h" #include "mountd.h" #include "rpcmisc.h" +#include "pseudoflavors.h" extern void cache_open(void); extern struct nfs_fh_len *cache_get_filehandle(nfs_export *exp, int len, char *p); @@ -35,7 +36,7 @@ extern void my_svc_run(void); static void usage(const char *, int exitcode); static exports get_exportlist(void); -static struct nfs_fh_len *get_rootfh(struct svc_req *, dirpath *, mountstat3 *, int v3); +static struct nfs_fh_len *get_rootfh(struct svc_req *, dirpath *, nfs_export **, mountstat3 *, int v3); int reverse_resolve = 0; int new_cache = 0; @@ -87,6 +88,14 @@ unregister_services (void) pmap_unset (MOUNTPROG, MOUNTVERS_NFSV3); } +static void +cleanup_lockfiles (void) +{ + unlink(_PATH_XTABLCK); + unlink(_PATH_ETABLCK); + unlink(_PATH_RMTABLCK); +} + /* Wait for all worker child processes to exit and reap them */ static void wait_for_workers (void) @@ -153,6 +162,7 @@ fork_workers(void) /* in parent */ wait_for_workers(); unregister_services(); + cleanup_lockfiles(); xlog(L_NOTICE, "mountd: no more workers, exiting\n"); exit(0); } @@ -169,15 +179,16 @@ killer (int sig) kill(0, SIGTERM); wait_for_workers(); } + cleanup_lockfiles(); xlog (L_FATAL, "Caught signal %d, un-registering and exiting.", sig); } static void sig_hup (int sig) { - /* don't exit on SIGHUP */ - xlog (L_NOTICE, "Received SIGHUP... Ignoring.\n", sig); - return; + /* don't exit on SIGHUP */ + xlog (L_NOTICE, "Received SIGHUP... Ignoring.\n", sig); + return; } bool_t @@ -192,7 +203,8 @@ mount_mnt_1_svc(struct svc_req *rqstp, dirpath *path, fhstatus *res) struct nfs_fh_len *fh; xlog(D_CALL, "MNT1(%s) called", *path); - if ((fh = get_rootfh(rqstp, path, &res->fhs_status, 0)) != NULL) + fh = get_rootfh(rqstp, path, NULL, &res->fhs_status, 0); + if (fh) memcpy(&res->fhstatus_u.fhs_fhandle, fh->fh_handle, 32); return 1; } @@ -200,8 +212,7 @@ mount_mnt_1_svc(struct svc_req *rqstp, dirpath *path, fhstatus *res) bool_t mount_dump_1_svc(struct svc_req *rqstp, void *argp, mountlist *res) { - struct sockaddr_in *addr = - (struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt); + struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt); xlog(D_CALL, "dump request from %s.", inet_ntoa(addr->sin_addr)); *res = mountlist_list(); @@ -212,8 +223,7 @@ mount_dump_1_svc(struct svc_req *rqstp, void *argp, mountlist *res) bool_t mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *resp) { - struct sockaddr_in *sin - = (struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt); + struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt); nfs_export *exp; char *p = *argp; char rpath[MAXPATHLEN+1]; @@ -230,9 +240,6 @@ mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *resp) return 1; } - if (!new_cache) - export_reset (exp); - mountlist_del(inet_ntoa(sin->sin_addr), p); return 1; } @@ -243,15 +250,14 @@ mount_umntall_1_svc(struct svc_req *rqstp, void *argp, void *resp) /* Reload /etc/xtab if necessary */ auth_reload(); - mountlist_del_all((struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt)); + mountlist_del_all(nfs_getrpccaller_in(rqstp->rq_xprt)); return 1; } bool_t mount_export_1_svc(struct svc_req *rqstp, void *argp, exports *resp) { - struct sockaddr_in *addr = - (struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt); + struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt); xlog(D_CALL, "export request from %s.", inet_ntoa(addr->sin_addr)); *resp = get_exportlist(); @@ -262,8 +268,7 @@ mount_export_1_svc(struct svc_req *rqstp, void *argp, exports *resp) bool_t mount_exportall_1_svc(struct svc_req *rqstp, void *argp, exports *resp) { - struct sockaddr_in *addr = - (struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt); + struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt); xlog(D_CALL, "exportall request from %s.", inet_ntoa(addr->sin_addr)); *resp = get_exportlist(); @@ -285,8 +290,7 @@ mount_exportall_1_svc(struct svc_req *rqstp, void *argp, exports *resp) bool_t mount_pathconf_2_svc(struct svc_req *rqstp, dirpath *path, ppathcnf *res) { - struct sockaddr_in *sin - = (struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt); + struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt); struct stat stb; nfs_export *exp; char rpath[MAXPATHLEN+1]; @@ -307,12 +311,12 @@ mount_pathconf_2_svc(struct svc_req *rqstp, dirpath *path, ppathcnf *res) } /* Now authenticate the intruder... */ - if (!(exp = auth_authenticate("pathconf", sin, p))) { + exp = auth_authenticate("pathconf", sin, p); + if (!exp) { return 1; } else if (stat(p, &stb) < 0) { xlog(L_WARNING, "can't stat exported dir %s: %s", p, strerror(errno)); - export_reset (exp); return 1; } @@ -328,50 +332,66 @@ mount_pathconf_2_svc(struct svc_req *rqstp, dirpath *path, ppathcnf *res) res->pc_mask[0] = 0; res->pc_mask[1] = 0; - export_reset (exp); - return 1; } +/* + * We should advertise the preferred flavours first. (See RFC 2623 + * section 2.7.) We leave that to the administrator, by advertising + * flavours in the order they were listed in /etc/exports. AUTH_NULL is + * dropped from the list to avoid backward compatibility issue with + * older Linux clients, who inspect the list in reversed order. + * + * XXX: It might be more helpful to rearrange these so that flavors + * giving more access (as determined from readonly and id-squashing + * options) come first. (If we decide to do that we should probably do + * that when reading the exports rather than here.) + */ +static void set_authflavors(struct mountres3_ok *ok, nfs_export *exp) +{ + struct sec_entry *s; + static int flavors[SECFLAVOR_COUNT]; + int i = 0; + + for (s = exp->m_export.e_secinfo; s->flav; s++) { + if (s->flav->fnum == AUTH_NULL) + continue; + flavors[i] = s->flav->fnum; + i++; + } + ok->auth_flavors.auth_flavors_val = flavors; + ok->auth_flavors.auth_flavors_len = i; +} + /* * NFSv3 MOUNT procedure */ bool_t mount_mnt_3_svc(struct svc_req *rqstp, dirpath *path, mountres3 *res) { -#define AUTH_GSS_KRB5 390003 -#define AUTH_GSS_KRB5I 390004 -#define AUTH_GSS_KRB5P 390005 - static int flavors[] = { AUTH_UNIX, AUTH_GSS_KRB5, AUTH_GSS_KRB5I, AUTH_GSS_KRB5P}; - /* - * We should advertise the preferred flavours first. (See RFC 2623 - * section 2.7.) AUTH_UNIX is arbitrarily ranked over the GSS's. - * AUTH_NULL is dropped from the list to avoid backward compatibility - * issue with older Linux clients, who inspect the list in reversed - * order. - */ + struct mountres3_ok *ok = &res->mountres3_u.mountinfo; + nfs_export *exp; struct nfs_fh_len *fh; xlog(D_CALL, "MNT3(%s) called", *path); - if ((fh = get_rootfh(rqstp, path, &res->fhs_status, 1)) != NULL) { - struct mountres3_ok *ok = &res->mountres3_u.mountinfo; - - ok->fhandle.fhandle3_len = fh->fh_size; - ok->fhandle.fhandle3_val = (char *)fh->fh_handle; - ok->auth_flavors.auth_flavors_len - = sizeof(flavors)/sizeof(flavors[0]); - ok->auth_flavors.auth_flavors_val = flavors; - } + fh = get_rootfh(rqstp, path, &exp, &res->fhs_status, 1); + if (!fh) + return 1; + + ok->fhandle.fhandle3_len = fh->fh_size; + ok->fhandle.fhandle3_val = (char *)fh->fh_handle; + set_authflavors(ok, exp); return 1; } static struct nfs_fh_len * -get_rootfh(struct svc_req *rqstp, dirpath *path, mountstat3 *error, int v3) +get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret, + mountstat3 *error, int v3) { - struct sockaddr_in *sin = - (struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt); + struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt); struct stat stb, estb; nfs_export *exp; + struct nfs_fh_len *fh; char rpath[MAXPATHLEN+1]; char *p = *path; @@ -388,59 +408,71 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, mountstat3 *error, int v3) } /* Now authenticate the intruder... */ - if (!(exp = auth_authenticate("mount", sin, p))) { + exp = auth_authenticate("mount", sin, p); + if (!exp) { *error = NFSERR_ACCES; - } else if (stat(p, &stb) < 0) { + return NULL; + } + if (stat(p, &stb) < 0) { xlog(L_WARNING, "can't stat exported dir %s: %s", p, strerror(errno)); if (errno == ENOENT) *error = NFSERR_NOENT; else *error = NFSERR_ACCES; - } else if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) { + return NULL; + } + if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) { xlog(L_WARNING, "%s is not a directory or regular file", p); *error = NFSERR_NOTDIR; - } else if (stat(exp->m_export.e_path, &estb) < 0) { + return NULL; + } + if (stat(exp->m_export.e_path, &estb) < 0) { xlog(L_WARNING, "can't stat export point %s: %s", p, strerror(errno)); *error = NFSERR_NOENT; - } else if (estb.st_dev != stb.st_dev - && (!new_cache || !(exp->m_export.e_flags & NFSEXP_CROSSMOUNT)) - ) { + return NULL; + } + if (estb.st_dev != stb.st_dev + && (!new_cache + || !(exp->m_export.e_flags & NFSEXP_CROSSMOUNT))) { xlog(L_WARNING, "request to export directory %s below nearest filesystem %s", p, exp->m_export.e_path); *error = NFSERR_ACCES; - } else if (exp->m_export.e_mountpoint && + return NULL; + } + if (exp->m_export.e_mountpoint && !is_mountpoint(exp->m_export.e_mountpoint[0]? exp->m_export.e_mountpoint: exp->m_export.e_path)) { xlog(L_WARNING, "request to export an unmounted filesystem: %s", p); *error = NFSERR_NOENT; - } else if (new_cache) { + return NULL; + } + + if (new_cache) { /* This will be a static private nfs_export with just one * address. We feed it to kernel then extract the filehandle, * */ - struct nfs_fh_len *fh; if (cache_export(exp, p)) { *error = NFSERR_ACCES; return NULL; } fh = cache_get_filehandle(exp, v3?64:32, p); - if (fh == NULL) + if (fh == NULL) { *error = NFSERR_ACCES; - else { - *error = NFS_OK; - mountlist_add(inet_ntoa(sin->sin_addr), p); + return NULL; } - return fh; } else { - struct nfs_fh_len *fh; - - if (exp->m_exported<1) + int did_export = 0; + retry: + if (exp->m_exported<1) { export_export(exp); + did_export = 1; + } if (!exp->m_xtabent) xtab_append(exp); @@ -454,17 +486,22 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, mountstat3 *error, int v3) fh = getfh_old ((struct sockaddr *) sin, stb.st_dev, stb.st_ino); } - if (fh != NULL) { - mountlist_add(inet_ntoa(sin->sin_addr), p); - *error = NFS_OK; - export_reset (exp); - return fh; + if (fh == NULL && !did_export) { + exp->m_exported = 0; + goto retry; + } + + if (fh == NULL) { + xlog(L_WARNING, "getfh failed: %s", strerror(errno)); + *error = NFSERR_ACCES; + return NULL; } - xlog(L_WARNING, "getfh failed: %s", strerror(errno)); - *error = NFSERR_ACCES; } - export_reset (exp); - return NULL; + *error = NFS_OK; + mountlist_add(inet_ntoa(sin->sin_addr), p); + if (expret) + *expret = exp; + return fh; } static exports @@ -497,16 +534,16 @@ get_exportlist(void) elist = NULL; for (i = 0; i < MCL_MAXTYPES; i++) { - for (exp = exportlist[i]; exp; exp = exp->m_next) { + for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { for (e = elist; e != NULL; e = e->ex_next) { - if (!strcmp(exp->m_export.m_path, e->ex_dir)) + if (!strcmp(exp->m_export.e_path, e->ex_dir)) break; } if (!e) { e = (struct exportnode *) xmalloc(sizeof(*e)); e->ex_next = elist; e->ex_groups = NULL; - e->ex_dir = xstrdup(exp->m_export.m_path); + e->ex_dir = xstrdup(exp->m_export.e_path); elist = e; }