| /* |
| * Copyright (C) 2009 Red Hat <nfs@redhat.com> |
| * |
| * support/export/v4root.c |
| * |
| * Routines used to support NFSv4 pseudo roots |
| * |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/queue.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <ctype.h> |
| |
| #include <unistd.h> |
| #include <errno.h> |
| |
| #include "xlog.h" |
| #include "exportfs.h" |
| #include "nfslib.h" |
| #include "misc.h" |
| #include "v4root.h" |
| |
| int v4root_needed; |
| |
| static nfs_export pseudo_root = { |
| .m_next = NULL, |
| .m_client = NULL, |
| .m_export = { |
| .e_hostname = "*", |
| .e_path = "/", |
| .e_flags = NFSEXP_READONLY | NFSEXP_ROOTSQUASH |
| | NFSEXP_NOSUBTREECHECK | NFSEXP_FSID |
| | NFSEXP_V4ROOT, |
| .e_anonuid = 65534, |
| .e_anongid = 65534, |
| .e_squids = NULL, |
| .e_nsquids = 0, |
| .e_sqgids = NULL, |
| .e_nsqgids = 0, |
| .e_fsid = 0, |
| .e_mountpoint = NULL, |
| }, |
| .m_exported = 0, |
| .m_xtabent = 1, |
| .m_mayexport = 1, |
| .m_changed = 0, |
| .m_warned = 0, |
| }; |
| |
| void set_pseudofs_security(struct exportent *pseudo, struct exportent *source) |
| { |
| struct sec_entry *se; |
| int i; |
| |
| if (source->e_flags & NFSEXP_INSECURE_PORT) |
| pseudo->e_flags |= NFSEXP_INSECURE_PORT; |
| for (se = source->e_secinfo; se->flav; se++) { |
| struct sec_entry *new; |
| |
| i = secinfo_addflavor(se->flav, pseudo); |
| new = &pseudo->e_secinfo[i]; |
| |
| if (se->flags & NFSEXP_INSECURE_PORT) |
| new->flags |= NFSEXP_INSECURE_PORT; |
| } |
| } |
| |
| /* |
| * Create a pseudo export |
| */ |
| static struct exportent * |
| v4root_create(char *path, nfs_export *export) |
| { |
| nfs_export *exp; |
| struct exportent eep; |
| struct exportent *curexp = &export->m_export; |
| |
| dupexportent(&eep, &pseudo_root.m_export); |
| eep.e_hostname = strdup(curexp->e_hostname); |
| strncpy(eep.e_path, path, sizeof(eep.e_path)); |
| if (strcmp(path, "/") != 0) |
| eep.e_flags &= ~NFSEXP_FSID; |
| set_pseudofs_security(&eep, curexp); |
| exp = export_create(&eep, 0); |
| if (exp == NULL) |
| return NULL; |
| xlog(D_CALL, "v4root_create: path '%s'", exp->m_export.e_path); |
| return &exp->m_export; |
| } |
| |
| /* |
| * Make sure the kernel has pseudo root support. |
| */ |
| static int |
| v4root_support(void) |
| { |
| struct export_features *ef; |
| static int warned = 0; |
| |
| ef = get_export_features(); |
| |
| if (ef->flags & NFSEXP_V4ROOT) |
| return 1; |
| if (!warned) { |
| xlog(L_WARNING, "Kernel does not have pseudo root support."); |
| xlog(L_WARNING, "NFS v4 mounts will be disabled unless fsid=0"); |
| xlog(L_WARNING, "is specfied in /etc/exports file."); |
| warned++; |
| } |
| return 0; |
| } |
| |
| int pseudofs_update(char *hostname, char *path, nfs_export *source) |
| { |
| nfs_export *exp; |
| |
| exp = export_lookup(hostname, path, 0); |
| if (exp && !(exp->m_export.e_flags & NFSEXP_V4ROOT)) |
| return 0; |
| if (!exp) { |
| if (v4root_create(path, source) == NULL) { |
| xlog(L_WARNING, "v4root_set: Unable to create " |
| "pseudo export for '%s'", path); |
| return -ENOMEM; |
| } |
| return 0; |
| } |
| /* Update an existing V4ROOT export: */ |
| set_pseudofs_security(&exp->m_export, &source->m_export); |
| return 0; |
| } |
| |
| static int v4root_add_parents(nfs_export *exp) |
| { |
| char *hostname = exp->m_export.e_hostname; |
| char *path; |
| char *ptr; |
| |
| path = strdup(exp->m_export.e_path); |
| if (!path) |
| return -ENOMEM; |
| for (ptr = path + 1; ptr; ptr = strchr(ptr, '/')) { |
| int ret; |
| char saved; |
| |
| saved = *ptr; |
| *ptr = '\0'; |
| ret = pseudofs_update(hostname, path, exp); |
| if (ret) |
| return ret; |
| *ptr = saved; |
| ptr++; |
| } |
| free(path); |
| return 0; |
| } |
| |
| /* |
| * Create pseudo exports by running through the real export |
| * looking at the components of the path that make up the export. |
| * Those path components, if not exported, will become pseudo |
| * exports allowing them to be found when the kernel does an upcall |
| * looking for components of the v4 mount. |
| */ |
| void |
| v4root_set() |
| { |
| nfs_export *exp; |
| int i, ret; |
| |
| if (!v4root_needed) |
| return; |
| if (!v4root_support()) |
| return; |
| |
| for (i = 0; i < MCL_MAXTYPES; i++) { |
| for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { |
| if (exp->m_export.e_flags & NFSEXP_V4ROOT) |
| /* |
| * We just added this one, so its |
| * parents are already dealt with! |
| */ |
| continue; |
| |
| ret = v4root_add_parents(exp); |
| /* XXX: error handling! */ |
| } |
| } |
| } |