d890181b5f2fab86ce60c26978884aab25e624fb
[nfs-utils.git] / utils / mountd / v4root.c
1 /*
2  * Copyright (C) 2009 Red Hat <nfs@redhat.com>
3  *
4  * support/export/v4root.c
5  *
6  * Routines used to support NFSv4 pseudo roots
7  *
8  */
9
10 #ifdef HAVE_CONFIG_H
11 #include <config.h>
12 #endif
13
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <sys/queue.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <ctype.h>
20
21 #include <unistd.h>
22 #include <errno.h>
23
24 #include "xlog.h"
25 #include "exportfs.h"
26 #include "nfslib.h"
27 #include "misc.h"
28 #include "v4root.h"
29
30 int v4root_needed;
31
32 static nfs_export pseudo_root = {
33         .m_next = NULL,
34         .m_client = NULL,
35         .m_export = {
36                 .e_hostname = "*",
37                 .e_path = "/",
38                 .e_flags = NFSEXP_READONLY | NFSEXP_ROOTSQUASH
39                                 | NFSEXP_NOSUBTREECHECK | NFSEXP_FSID
40                                 | NFSEXP_V4ROOT,
41                 .e_anonuid = 65534,
42                 .e_anongid = 65534,
43                 .e_squids = NULL,
44                 .e_nsquids = 0,
45                 .e_sqgids = NULL,
46                 .e_nsqgids = 0,
47                 .e_fsid = 0,
48                 .e_mountpoint = NULL,
49         },
50         .m_exported = 0,
51         .m_xtabent = 1,
52         .m_mayexport = 1,
53         .m_changed = 0,
54         .m_warned = 0,
55 };
56
57 void set_pseudofs_security(struct exportent *pseudo, struct exportent *source)
58 {
59         struct sec_entry *se;
60         int i;
61
62         if (source->e_flags & NFSEXP_INSECURE_PORT)
63                 pseudo->e_flags |= NFSEXP_INSECURE_PORT;
64         for (se = source->e_secinfo; se->flav; se++) {
65                 struct sec_entry *new;
66
67                 i = secinfo_addflavor(se->flav, pseudo);
68                 new = &pseudo->e_secinfo[i];
69
70                 if (se->flags & NFSEXP_INSECURE_PORT)
71                         new->flags |= NFSEXP_INSECURE_PORT;
72         }
73 }
74
75 /*
76  * Create a pseudo export
77  */
78 static struct exportent *
79 v4root_create(char *path, nfs_export *export)
80 {
81         nfs_export *exp;
82         struct exportent eep;
83         struct exportent *curexp = &export->m_export;
84
85         dupexportent(&eep, &pseudo_root.m_export);
86         eep.e_hostname = strdup(curexp->e_hostname);
87         strncpy(eep.e_path, path, sizeof(eep.e_path));
88         if (strcmp(path, "/") != 0)
89                 eep.e_flags &= ~NFSEXP_FSID;
90         set_pseudofs_security(&eep, curexp);
91         exp = export_create(&eep, 0);
92         if (exp == NULL)
93                 return NULL;
94         xlog(D_CALL, "v4root_create: path '%s'", exp->m_export.e_path);
95         return &exp->m_export;
96 }
97
98 /*
99  * Make sure the kernel has pseudo root support.
100  */
101 static int
102 v4root_support(void)
103 {
104         struct export_features *ef;
105         static int warned = 0;
106
107         ef = get_export_features();
108
109         if (ef->flags & NFSEXP_V4ROOT)
110                 return 1;
111         if (!warned) {
112                 xlog(L_WARNING, "Kernel does not have pseudo root support.");
113                 xlog(L_WARNING, "NFS v4 mounts will be disabled unless fsid=0");
114                 xlog(L_WARNING, "is specfied in /etc/exports file.");
115                 warned++;
116         }
117         return 0;
118 }
119
120 int pseudofs_update(char *hostname, char *path, nfs_export *source)
121 {
122         nfs_export *exp;
123
124         exp = export_lookup(hostname, path, 0);
125         if (exp && !(exp->m_export.e_flags & NFSEXP_V4ROOT))
126                 return 0;
127         if (!exp) {
128                 if (v4root_create(path, source) == NULL) {
129                         xlog(L_WARNING, "v4root_set: Unable to create "
130                                         "pseudo export for '%s'", path);
131                         return -ENOMEM;
132                 }
133                 return 0;
134         }
135         /* Update an existing V4ROOT export: */
136         set_pseudofs_security(&exp->m_export, &source->m_export);
137         return 0;
138 }
139
140 /*
141  * Create pseudo exports by running through the real export
142  * looking at the components of the path that make up the export.
143  * Those path components, if not exported, will become pseudo
144  * exports allowing them to be found when the kernel does an upcall
145  * looking for components of the v4 mount.
146  */
147 void
148 v4root_set()
149 {
150         nfs_export      *exp, *nxt;
151         int     i;
152         char *path, *ptr;
153         char *hostname;
154
155         if (!v4root_needed)
156                 return;
157         if (!v4root_support())
158                 return;
159
160         for (i = 0; i < MCL_MAXTYPES; i++) {
161                 for (exp = exportlist[i].p_head; exp; exp = nxt) {
162                         nxt = exp->m_next;
163                         hostname = exp->m_export.e_hostname;
164
165                         path = strdup(exp->m_export.e_path);
166                         for (ptr = path + 1; ptr; ptr = strchr(ptr, '/')) {
167                                 int ret;
168                                 char saved;
169
170                                 saved = *ptr;
171                                 *ptr = '\0';
172                                 ret = pseudofs_update(hostname, path, exp);
173                                 /* XXX: error handling */
174                                 *ptr = saved;
175                                 ptr++;
176                         }
177                         free(path);
178                 }
179         }
180 }