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.
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
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>
54 #include "nfsidmap_internal.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
;
64 #define PATH_PLUGINS "/usr/lib/libnfsidmap"
66 #define PLUGIN_INIT_FUNC "libnfsidmap_plugin_init"
69 #ifndef PATH_IDMAPDCONF
70 #define PATH_IDMAPDCONF "/etc/idmapd.conf"
73 #ifndef IDMAPD_DEFAULT_DOMAIN
74 #define IDMAPD_DEFAULT_DOMAIN "localdomain"
77 /* Default logging fuction */
78 static void default_logger(const char *fmt
, ...)
83 vsyslog(LOG_WARNING
, fmt
, vp
);
86 nfs4_idmap_log_function_t idmap_log_func
= default_logger
;
88 static char * toupper_str(char *s
)
91 for (i
=0; i
< strlen(s
); i
++)
96 static int id_as_chars(char *name
, int *id
)
98 long int value
= strtol(name
, NULL
, 10);
105 static int domain_from_dns(char **domain
)
110 if (gethostname(hname
, sizeof(hname
)) == -1)
112 if ((he
= gethostbyname(hname
)) == NULL
)
114 if ((c
= strchr(he
->h_name
, '.')) == NULL
|| *++c
== '\0')
120 static int load_translation_plugin(char *method
, struct mapping_plugin
*plgn
)
123 struct trans_func
*trans
= NULL
;
124 libnfsidmap_plugin_init_t init_func
;
128 snprintf(plgname
, sizeof(plgname
), "%s/%s.so", PATH_PLUGINS
, method
);
130 dl
= dlopen(plgname
, RTLD_NOW
| RTLD_LOCAL
);
132 IDMAP_LOG(1, ("libnfsidmap: Unable to load plugin: %s\n",
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",
145 IDMAP_LOG(1, ("libnfsidmap: Failed to initialize plugin %s\n",
146 PLUGIN_INIT_FUNC
, plgname
));
153 IDMAP_LOG(1, ("libnfsidmap: Failed in %s's init(), "
154 "returned %d\n", plgname
, ret
));
159 plgn
->dl_handle
= dl
;
161 IDMAP_LOG(1, ("libnfsidmap: loaded plugin %s for method %s\n",
167 static void unload_plugins(struct mapping_plugin
**plgns
)
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
));
180 static int load_plugins(struct conf_list
*methods
,
181 struct mapping_plugin
***plugins
)
184 struct mapping_plugin
**plgns
;
185 struct conf_list_node
*m
;
187 plgns
= calloc(methods
->cnt
+ 1, sizeof(struct mapping_plugin
*));
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
)
196 if (load_translation_plugin(m
->field
, plgns
[i
]) == -1) {
197 IDMAP_LOG(0, ("libnfsidmap: requested translation "
198 "method, '%s', is not available\n",
207 unload_plugins(plgns
);
210 int nfs4_cleanup_name_mapping()
213 unload_plugins(nfs4_plugins
);
215 unload_plugins(gss_plugins
);
216 nfs4_plugins
= gss_plugins
= NULL
;
219 int nfs4_init_name_mapping(char *conffile
)
224 struct conf_list
*nfs4_methods
, *gss_methods
;
226 /* XXX: need to be able to reload configurations... */
227 if (nfs4_plugins
) /* already succesfully initialized */
230 conf_path
= conffile
;
232 conf_path
= PATH_IDMAPDCONF
;
234 default_domain
= conf_get_str("General", "Domain");
235 if (default_domain
== NULL
) {
237 ret
= domain_from_dns(&default_domain
);
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
)
260 local_realms
->cnt
= 0;
261 TAILQ_INIT(&local_realms
->fields
);
263 node
= calloc(1, sizeof *node
);
266 node
->field
= strdup(get_default_domain());
267 if (node
->field
== NULL
)
269 toupper_str(node
->field
);
271 TAILQ_INSERT_TAIL(&local_realms
->fields
, node
, link
);
275 nfs4_methods
= conf_get_list("Translation", "Method");
277 IDMAP_LOG(1, ("libnfsidmap: processing 'Method' list\n"));
278 if (load_plugins(nfs4_methods
, &nfs4_plugins
) == -1)
281 struct conf_list list
;
282 struct conf_list_node node
;
284 TAILQ_INIT(&list
.fields
);
286 node
.field
= "nsswitch";
287 TAILQ_INSERT_TAIL (&list
.fields
, &node
, link
);
289 if (load_plugins(&list
, &nfs4_plugins
) == -1)
293 gss_methods
= conf_get_list("Translation", "GSS-Methods");
295 IDMAP_LOG(1, ("libnfsidmap: processing 'GSS-Methods' list\n"));
296 if (load_plugins(gss_methods
, &gss_plugins
) == -1)
303 unload_plugins(nfs4_plugins
);
305 unload_plugins(gss_plugins
);
306 nfs4_plugins
= gss_plugins
= NULL
;
309 return ret
? -ENOENT
: 0;
312 char * get_default_domain(void)
317 return default_domain
;
318 ret
= domain_from_dns(&default_domain
);
320 IDMAP_LOG(0, ("Unable to determine a default nfsv4 domain; "
321 " consider specifying one in idmapd.conf\n"));
324 return default_domain
;
327 struct conf_list
*get_local_realms(void)
333 nfs4_get_default_domain(char *server
, char *domain
, size_t len
)
335 char *d
= get_default_domain();
337 if (strlen(d
) + 1 > len
)
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...) \
355 struct mapping_plugin **plgns; \
357 ret = nfs4_init_name_mapping(NULL); \
361 if ((prefer_gss) && gss_plugins) \
362 plgns = gss_plugins; \
364 plgns = nfs4_plugins; \
366 for (i = 0; plgns[i] != NULL; i++) { \
367 if (plgns[i]->trans->funcname == NULL) \
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, \
379 if (ret == -ENOENT) \
384 IDMAP_LOG(4, ("%s: final return value is %d\n", \
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
);
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
);
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
)
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());
432 rc
= nfs4_name_to_uid(nobody
, id
);
434 rc
= nfs4_name_to_gid(nobody
, id
);
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
))
449 rc
= set_id_to_nobody(uid
, 1);
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
))
459 rc
= set_id_to_nobody(gid
, 0);
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 *, ...))
491 idmap_log_func
= logger
;
492 idmap_verbosity
= dbg_level
;