Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / libnfsidmap / libnfsidmap.c
blob5dc26524c28ee7854f0c321f3f27a14d2affa3b9
1 /*
2 * libnfsidmap.c
4 * nfs idmapping library, primarily for nfs4 client/server kernel idmapping
5 * and for userland nfs4 idmapping by acl libraries.
7 * Copyright (c) 2004 The Regents of the University of Michigan.
8 * All rights reserved.
10 * Marius Aamodt Eriksen <marius@umich.edu>
11 * J. Bruce Fields <bfields@umich.edu>
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of the University nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
33 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #include <sys/types.h>
40 #include <errno.h>
41 #include <unistd.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include <pwd.h>
47 #include <grp.h>
48 #include <netdb.h>
49 #include <err.h>
50 #include <syslog.h>
51 #include <stdarg.h>
52 #include <dlfcn.h>
53 #include "nfsidmap.h"
54 #include "nfsidmap_internal.h"
55 #include "cfg.h"
57 static char *default_domain;
58 static struct conf_list *local_realms;
59 int idmap_verbosity = 0;
60 static struct mapping_plugin **nfs4_plugins = NULL;
61 static struct mapping_plugin **gss_plugins = NULL;
63 #ifndef PATH_PLUGINS
64 #define PATH_PLUGINS "/usr/lib/libnfsidmap"
65 #endif
66 #define PLUGIN_INIT_FUNC "libnfsidmap_plugin_init"
69 #ifndef PATH_IDMAPDCONF
70 #define PATH_IDMAPDCONF "/etc/idmapd.conf"
71 #endif
73 #ifndef IDMAPD_DEFAULT_DOMAIN
74 #define IDMAPD_DEFAULT_DOMAIN "localdomain"
75 #endif
77 /* Default logging fuction */
78 static void default_logger(const char *fmt, ...)
80 va_list vp;
82 va_start(vp, fmt);
83 vsyslog(LOG_WARNING, fmt, vp);
84 va_end(vp);
86 nfs4_idmap_log_function_t idmap_log_func = default_logger;
88 static char * toupper_str(char *s)
90 int i;
91 for (i=0; i < strlen(s); i++)
92 s[i] = toupper(s[i]);
93 return s;
96 static int id_as_chars(char *name, int *id)
98 long int value = strtol(name, NULL, 10);
99 if (value == 0)
100 return 0;
101 *id = (int)value;
102 return 1;
105 static int domain_from_dns(char **domain)
107 struct hostent *he;
108 char hname[64], *c;
110 if (gethostname(hname, sizeof(hname)) == -1)
111 return -1;
112 if ((he = gethostbyname(hname)) == NULL)
113 return -1;
114 if ((c = strchr(he->h_name, '.')) == NULL || *++c == '\0')
115 return -1;
116 *domain = strdup(c);
117 return 0;
120 static int load_translation_plugin(char *method, struct mapping_plugin *plgn)
122 void *dl = NULL;
123 struct trans_func *trans = NULL;
124 libnfsidmap_plugin_init_t init_func;
125 char plgname[128];
126 int ret = 0;
128 snprintf(plgname, sizeof(plgname), "%s/%s.so", PATH_PLUGINS, method);
130 dl = dlopen(plgname, RTLD_NOW | RTLD_LOCAL);
131 if (dl == NULL) {
132 IDMAP_LOG(1, ("libnfsidmap: Unable to load plugin: %s\n",
133 dlerror()));
134 return -1;
136 init_func = (libnfsidmap_plugin_init_t) dlsym(dl, PLUGIN_INIT_FUNC);
137 if (init_func == NULL) {
138 IDMAP_LOG(1, ("libnfsidmap: Unable to get init function: %s\n",
139 dlerror()));
140 dlclose(dl);
141 return -1;
143 trans = init_func();
144 if (trans == NULL) {
145 IDMAP_LOG(1, ("libnfsidmap: Failed to initialize plugin %s\n",
146 PLUGIN_INIT_FUNC, plgname));
147 dlclose(dl);
148 return -1;
150 if (trans->init) {
151 ret = trans->init();
152 if (ret) {
153 IDMAP_LOG(1, ("libnfsidmap: Failed in %s's init(), "
154 "returned %d\n", plgname, ret));
155 dlclose(dl);
156 return -1;
159 plgn->dl_handle = dl;
160 plgn->trans = trans;
161 IDMAP_LOG(1, ("libnfsidmap: loaded plugin %s for method %s\n",
162 plgname, method));
164 return 0;
167 static void unload_plugins(struct mapping_plugin **plgns)
169 int i;
170 for (i = 0; plgns[i] != NULL; i++) {
171 if (plgns[i]->dl_handle && dlclose(plgns[i]->dl_handle))
172 IDMAP_LOG(1, ("libnfsidmap: failed to "
173 "unload plugin for method = %s\n",
174 plgns[i]->trans->name));
175 free(plgns[i]);
177 free(plgns);
180 static int load_plugins(struct conf_list *methods,
181 struct mapping_plugin ***plugins)
183 int ret = -1, i = 0;
184 struct mapping_plugin **plgns;
185 struct conf_list_node *m;
187 plgns = calloc(methods->cnt + 1, sizeof(struct mapping_plugin *));
188 if (plgns == NULL)
189 return -1;
190 plgns[methods->cnt] = NULL;
191 for (m = TAILQ_FIRST(&methods->fields), i = 0; m;
192 m = TAILQ_NEXT(m, link), i++) {
193 plgns[i] = calloc(1, sizeof(struct mapping_plugin));
194 if (plgns[i] == NULL)
195 goto out;
196 if (load_translation_plugin(m->field, plgns[i]) == -1) {
197 IDMAP_LOG(0, ("libnfsidmap: requested translation "
198 "method, '%s', is not available\n",
199 m->field));
200 goto out;
203 ret = 0;
204 *plugins = plgns;
205 out:
206 if (ret)
207 unload_plugins(plgns);
208 return ret;
210 int nfs4_cleanup_name_mapping()
212 if (nfs4_plugins)
213 unload_plugins(nfs4_plugins);
214 if (gss_plugins)
215 unload_plugins(gss_plugins);
216 nfs4_plugins = gss_plugins = NULL;
219 int nfs4_init_name_mapping(char *conffile)
221 int ret = -ENOENT;
222 char *method;
223 int dflt = 0;
224 struct conf_list *nfs4_methods, *gss_methods;
226 /* XXX: need to be able to reload configurations... */
227 if (nfs4_plugins) /* already succesfully initialized */
228 return 0;
229 if (conffile)
230 conf_path = conffile;
231 else
232 conf_path = PATH_IDMAPDCONF;
233 conf_init();
234 default_domain = conf_get_str("General", "Domain");
235 if (default_domain == NULL) {
236 dflt = 1;
237 ret = domain_from_dns(&default_domain);
238 if (ret) {
239 IDMAP_LOG(1, ("libnfsidmap: Unable to determine "
240 "the NFSv4 domain; Using '%s' as the NFSv4 domain "
241 "which means UIDs will be mapped to the 'Nobody-User' "
242 "user defined in %s\n",
243 IDMAPD_DEFAULT_DOMAIN, PATH_IDMAPDCONF));
244 default_domain = IDMAPD_DEFAULT_DOMAIN;
247 IDMAP_LOG(1, ("libnfsidmap: using%s domain: %s\n",
248 (dflt ? " (default)" : ""), default_domain));
250 /* Get list of "local equivalent" realms. Meaning the list of realms
251 * where john@REALM.A is considered the same user as john@REALM.B
252 * If not specified, default to upper-case of local domain name */
253 local_realms = conf_get_list("General", "Local-Realms");
254 if (local_realms == NULL) {
255 struct conf_list_node *node;
257 local_realms = malloc(sizeof *local_realms);
258 if (local_realms == NULL)
259 return -ENOMEM;
260 local_realms->cnt = 0;
261 TAILQ_INIT(&local_realms->fields);
263 node = calloc(1, sizeof *node);
264 if (node == NULL)
265 return -ENOMEM;
266 node->field = strdup(get_default_domain());
267 if (node->field == NULL)
268 return -ENOMEM;
269 toupper_str(node->field);
271 TAILQ_INSERT_TAIL(&local_realms->fields, node, link);
272 local_realms->cnt++;
275 nfs4_methods = conf_get_list("Translation", "Method");
276 if (nfs4_methods) {
277 IDMAP_LOG(1, ("libnfsidmap: processing 'Method' list\n"));
278 if (load_plugins(nfs4_methods, &nfs4_plugins) == -1)
279 return -ENOENT;
280 } else {
281 struct conf_list list;
282 struct conf_list_node node;
284 TAILQ_INIT(&list.fields);
285 list.cnt = 1;
286 node.field = "nsswitch";
287 TAILQ_INSERT_TAIL (&list.fields, &node, link);
289 if (load_plugins(&list, &nfs4_plugins) == -1)
290 return -ENOENT;
293 gss_methods = conf_get_list("Translation", "GSS-Methods");
294 if (gss_methods) {
295 IDMAP_LOG(1, ("libnfsidmap: processing 'GSS-Methods' list\n"));
296 if (load_plugins(gss_methods, &gss_plugins) == -1)
297 goto out;
299 ret = 0;
300 out:
301 if (ret) {
302 if (nfs4_plugins)
303 unload_plugins(nfs4_plugins);
304 if (gss_plugins)
305 unload_plugins(gss_plugins);
306 nfs4_plugins = gss_plugins = NULL;
309 return ret ? -ENOENT: 0;
312 char * get_default_domain(void)
314 int ret;
316 if (default_domain)
317 return default_domain;
318 ret = domain_from_dns(&default_domain);
319 if (ret) {
320 IDMAP_LOG(0, ("Unable to determine a default nfsv4 domain; "
321 " consider specifying one in idmapd.conf\n"));
322 default_domain = "";
324 return default_domain;
327 struct conf_list *get_local_realms(void)
329 return local_realms;
333 nfs4_get_default_domain(char *server, char *domain, size_t len)
335 char *d = get_default_domain();
337 if (strlen(d) + 1 > len)
338 return -ERANGE;
339 strcpy(domain, d);
340 return 0;
344 * Run through each configured translation method for
345 * function "funcname".
346 * If "prefer_gss" is true, then use the gss_plugins list,
347 * if present. Otherwise, use the default nfs4_plugins list.
349 * If the plugin function returns -ENOENT, then continue
350 * to the next plugin.
352 #define RUN_TRANSLATIONS(funcname, prefer_gss, args...) \
353 do { \
354 int ret, i; \
355 struct mapping_plugin **plgns; \
357 ret = nfs4_init_name_mapping(NULL); \
358 if (ret) \
359 return ret; \
361 if ((prefer_gss) && gss_plugins) \
362 plgns = gss_plugins; \
363 else \
364 plgns = nfs4_plugins; \
366 for (i = 0; plgns[i] != NULL; i++) { \
367 if (plgns[i]->trans->funcname == NULL) \
368 continue; \
370 IDMAP_LOG(4, ("%s: calling %s->%s\n", __func__, \
371 plgns[i]->trans->name, #funcname)); \
373 ret = plgns[i]->trans->funcname(args); \
375 IDMAP_LOG(4, ("%s: %s->%s returned %d\n", \
376 __func__, plgns[i]->trans->name, \
377 #funcname, ret)); \
379 if (ret == -ENOENT) \
380 continue; \
382 break; \
384 IDMAP_LOG(4, ("%s: final return value is %d\n", \
385 __func__, ret)); \
386 return ret; \
387 } while (0)
389 int nfs4_uid_to_name(uid_t uid, char *domain, char *name, size_t len)
391 RUN_TRANSLATIONS(uid_to_name, 0, uid, domain, name, len);
394 int nfs4_gid_to_name(gid_t gid, char *domain, char *name, size_t len)
396 RUN_TRANSLATIONS(gid_to_name, 0, gid, domain, name, len);
399 int nfs4_uid_to_owner(uid_t uid, char *domain, char *name, size_t len)
401 if (nfs4_uid_to_name(uid, domain, name, len))
402 sprintf(name, "%u", uid);
403 return 0;
406 int nfs4_gid_to_group_owner(gid_t gid, char *domain, char *name, size_t len)
408 if (nfs4_gid_to_name(gid, domain, name, len))
409 sprintf(name, "%u", gid);
410 return 0;
413 int nfs4_name_to_uid(char *name, uid_t *uid)
415 RUN_TRANSLATIONS(name_to_uid, 0, name, uid);
418 int nfs4_name_to_gid(char *name, gid_t *gid)
420 RUN_TRANSLATIONS(name_to_gid, 0, name, gid);
423 static int set_id_to_nobody(int *id, int is_uid)
425 int rc = 0;
426 const char name[] = "nobody@";
427 char nobody[strlen(name) + strlen(get_default_domain()) + 1];
428 strcpy(nobody, name);
429 strcat(nobody, get_default_domain());
431 if (is_uid)
432 rc = nfs4_name_to_uid(nobody, id);
433 else
434 rc = nfs4_name_to_gid(nobody, id);
436 if (rc) {
437 *id = -2;
438 rc = 0;
440 return rc;
443 int nfs4_owner_to_uid(char *name, uid_t *uid)
445 int rc = nfs4_name_to_uid(name, uid);
446 if (rc && id_as_chars(name, uid))
447 rc = 0;
448 else if (rc)
449 rc = set_id_to_nobody(uid, 1);
450 return rc;
453 int nfs4_group_owner_to_gid(char *name, gid_t *gid)
455 int rc = nfs4_name_to_gid(name, gid);
456 if (rc && id_as_chars(name, gid))
457 rc = 0;
458 else if (rc)
459 rc = set_id_to_nobody(gid, 0);
460 return rc;
463 int nfs4_gss_princ_to_ids(char *secname, char *princ, uid_t *uid, gid_t *gid)
465 RUN_TRANSLATIONS(princ_to_ids, 1, secname, princ, uid, gid, NULL);
468 int nfs4_gss_princ_to_grouplist(char *secname, char *princ,
469 gid_t *groups, int *ngroups)
471 RUN_TRANSLATIONS(gss_princ_to_grouplist, 1, secname, princ,
472 groups, ngroups, NULL);
475 int nfs4_gss_princ_to_ids_ex(char *secname, char *princ, uid_t *uid,
476 gid_t *gid, extra_mapping_params **ex)
478 RUN_TRANSLATIONS(princ_to_ids, 1, secname, princ, uid, gid, ex);
481 int nfs4_gss_princ_to_grouplist_ex(char *secname, char *princ, gid_t *groups,
482 int *ngroups, extra_mapping_params **ex)
484 RUN_TRANSLATIONS(gss_princ_to_grouplist, 1, secname, princ,
485 groups, ngroups, ex);
488 void nfs4_set_debug(int dbg_level, void (*logger)(const char *, ...))
490 if (logger)
491 idmap_log_func = logger;
492 idmap_verbosity = dbg_level;