]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/mountd/v4root.c
mountd: make local functions in v4root.c static
[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                 .e_ttl = DEFAULT_TTL,
50         },
51         .m_exported = 0,
52         .m_xtabent = 1,
53         .m_mayexport = 1,
54         .m_changed = 0,
55         .m_warned = 0,
56 };
57
58 static void
59 set_pseudofs_security(struct exportent *pseudo, struct exportent *source)
60 {
61         struct sec_entry *se;
62         int i;
63
64         if (source->e_flags & NFSEXP_INSECURE_PORT)
65                 pseudo->e_flags |= NFSEXP_INSECURE_PORT;
66         if ((source->e_flags & NFSEXP_ROOTSQUASH) == 0)
67                 pseudo->e_flags &= ~NFSEXP_ROOTSQUASH;
68         for (se = source->e_secinfo; se->flav; se++) {
69                 struct sec_entry *new;
70
71                 i = secinfo_addflavor(se->flav, pseudo);
72                 new = &pseudo->e_secinfo[i];
73
74                 if (se->flags & NFSEXP_INSECURE_PORT)
75                         new->flags |= NFSEXP_INSECURE_PORT;
76         }
77 }
78
79 /*
80  * Create a pseudo export
81  */
82 static struct exportent *
83 v4root_create(char *path, nfs_export *export)
84 {
85         nfs_export *exp;
86         struct exportent eep;
87         struct exportent *curexp = &export->m_export;
88
89         dupexportent(&eep, &pseudo_root.m_export);
90         eep.e_hostname = curexp->e_hostname;
91         strncpy(eep.e_path, path, sizeof(eep.e_path));
92         if (strcmp(path, "/") != 0)
93                 eep.e_flags &= ~NFSEXP_FSID;
94         set_pseudofs_security(&eep, curexp);
95         exp = export_create(&eep, 0);
96         if (exp == NULL)
97                 return NULL;
98         xlog(D_CALL, "v4root_create: path '%s' flags 0x%x", 
99                 exp->m_export.e_path, exp->m_export.e_flags);
100         return &exp->m_export;
101 }
102
103 /*
104  * Make sure the kernel has pseudo root support.
105  */
106 static int
107 v4root_support(void)
108 {
109         struct export_features *ef;
110         static int warned = 0;
111
112         ef = get_export_features();
113
114         if (ef->flags & NFSEXP_V4ROOT)
115                 return 1;
116         if (!warned) {
117                 xlog(L_WARNING, "Kernel does not have pseudo root support.");
118                 xlog(L_WARNING, "NFS v4 mounts will be disabled unless fsid=0");
119                 xlog(L_WARNING, "is specfied in /etc/exports file.");
120                 warned++;
121         }
122         return 0;
123 }
124
125 static int
126 pseudofs_update(char *hostname, char *path, nfs_export *source)
127 {
128         nfs_export *exp;
129
130         exp = export_lookup(hostname, path, 0);
131         if (exp && !(exp->m_export.e_flags & NFSEXP_V4ROOT))
132                 return 0;
133         if (!exp) {
134                 if (v4root_create(path, source) == NULL) {
135                         xlog(L_WARNING, "v4root_set: Unable to create "
136                                         "pseudo export for '%s'", path);
137                         return -ENOMEM;
138                 }
139                 return 0;
140         }
141         /* Update an existing V4ROOT export: */
142         set_pseudofs_security(&exp->m_export, &source->m_export);
143         return 0;
144 }
145
146 static int v4root_add_parents(nfs_export *exp)
147 {
148         char *hostname = exp->m_export.e_hostname;
149         char *path;
150         char *ptr;
151
152         path = strdup(exp->m_export.e_path);
153         if (!path) {
154                 xlog(L_WARNING, "v4root_add_parents: Unable to create "
155                                 "pseudo export for '%s'", exp->m_export.e_path);
156                 return -ENOMEM;
157         }
158         for (ptr = path; ptr; ptr = strchr(ptr, '/')) {
159                 int ret;
160                 char saved;
161
162                 saved = *ptr;
163                 *ptr = '\0';
164                 ret = pseudofs_update(hostname, *path ? path : "/", exp);
165                 if (ret)
166                         return ret;
167                 *ptr = saved;
168                 ptr++;
169         }
170         free(path);
171         return 0;
172 }
173
174 /*
175  * Create pseudo exports by running through the real export
176  * looking at the components of the path that make up the export.
177  * Those path components, if not exported, will become pseudo
178  * exports allowing them to be found when the kernel does an upcall
179  * looking for components of the v4 mount.
180  */
181 void
182 v4root_set()
183 {
184         nfs_export      *exp;
185         int     i;
186
187         if (!v4root_needed)
188                 return;
189         if (!v4root_support())
190                 return;
191
192         for (i = 0; i < MCL_MAXTYPES; i++) {
193                 for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
194                         if (exp->m_export.e_flags & NFSEXP_V4ROOT)
195                                 /*
196                                  * We just added this one, so its
197                                  * parents are already dealt with!
198                                  */
199                                 continue;
200
201                         if (strcmp(exp->m_export.e_path, "/") == 0 &&
202                             !(exp->m_export.e_flags & NFSEXP_FSID)) {
203                                 /* Force '/' to be exported as fsid == 0*/
204                                 exp->m_export.e_flags |= NFSEXP_FSID;
205                                 exp->m_export.e_fsid = 0;
206                         }
207
208                         v4root_add_parents(exp);
209                         /* XXX: error handling! */
210                 }
211         }
212 }