TOR: fix compilation
[tomato.git] / release / src / router / libnfsidmap / nss.c
blobf8129fecf2752c7147a950ab1ef786a0851b86a2
1 /*
2 * nss.c
4 * nsswitch idmapping functions.
6 * Copyright (c) 2004 The Regents of the University of Michigan.
7 * All rights reserved.
9 * J. Bruce Fields <bfields@umich.edu>
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <sys/types.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <pwd.h>
43 #include <grp.h>
44 #include <netdb.h>
45 #include <err.h>
46 #include <grp.h>
47 #include "nfsidmap.h"
48 #include "nfsidmap_internal.h"
49 #include "cfg.h"
50 #include <syslog.h>
53 * NSS Translation Methods
55 * These are all just wrappers around getpwnam and friends;
56 * we tack on the given domain to the results of getpwnam when looking up a uid,
57 * and ignore the domain entirely when looking up a name.
60 static int write_name(char *dest, char *localname, char *domain, size_t len)
62 if (strlen(localname) + 1 + strlen(domain) + 1 > len) {
63 return -ENOMEM; /* XXX: Is there an -ETOOLONG? */
65 strcpy(dest, localname);
66 strcat(dest, "@");
67 strcat(dest, domain);
68 return 0;
71 static int nss_uid_to_name(uid_t uid, char *domain, char *name, size_t len)
73 struct passwd *pw = NULL;
74 struct passwd pwbuf;
75 char *buf;
76 size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
77 int err = -ENOMEM;
79 buf = malloc(buflen);
80 if (!buf)
81 goto out;
82 if (domain == NULL)
83 domain = get_default_domain();
84 err = -getpwuid_r(uid, &pwbuf, buf, buflen, &pw);
85 if (pw == NULL)
86 err = -ENOENT;
87 if (err)
88 goto out_buf;
89 err = write_name(name, pw->pw_name, domain, len);
90 out_buf:
91 free(buf);
92 out:
93 return err;
96 static int nss_gid_to_name(gid_t gid, char *domain, char *name, size_t len)
98 struct group *gr = NULL;
99 struct group grbuf;
100 char *buf;
101 size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
102 int err;
104 if (domain == NULL)
105 domain = get_default_domain();
107 do {
108 err = -ENOMEM;
109 buf = malloc(buflen);
110 if (!buf)
111 goto out;
112 err = -getgrgid_r(gid, &grbuf, buf, buflen, &gr);
113 if (gr == NULL && !err)
114 err = -ENOENT;
115 if (err == -ERANGE) {
116 buflen *= 2;
117 free(buf);
119 } while (err == -ERANGE);
121 if (err)
122 goto out_buf;
123 err = write_name(name, gr->gr_name, domain, len);
124 out_buf:
125 free(buf);
126 out:
127 return err;
130 /* XXX: actually should return error, so can distinguish between
131 * memory allocation failure and failure to match domain */
132 static char *strip_domain(const char *name, const char *domain)
134 const char *c;
135 char *l = NULL;
136 int len;
138 c = strrchr(name, '@');
139 if (c == NULL && domain != NULL)
140 goto out;
141 if (c == NULL && domain == NULL) {
142 len = strlen(name) + 1;
143 } else {
144 if (domain && strcasecmp(c + 1, domain) != 0)
145 goto out;
146 len = c - name;
149 l = malloc(len + 1);
150 if (l == NULL)
151 goto out;
152 memcpy(l, name, len);
153 l[len] = '\0';
154 out:
155 return l;
158 struct pwbuf {
159 struct passwd pwbuf;
160 char buf[1];
163 static struct passwd *nss_getpwnam(const char *name, const char *domain, int *err_p)
165 struct passwd *pw;
166 struct pwbuf *buf;
167 size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
168 char *localname;
169 int err = ENOMEM;
171 buf = malloc(sizeof(*buf) + buflen);
172 if (buf == NULL)
173 goto err;
175 err = EINVAL;
176 localname = strip_domain(name, domain);
177 IDMAP_LOG(4, ("nss_getpwnam: name '%s' domain '%s': "
178 "resulting localname '%s'\n", name, domain, localname));
179 if (localname == NULL) {
180 IDMAP_LOG(0, ("nss_getpwnam: name '%s' does not map "
181 "into domain '%s'\n", name,
182 domain ? domain : "<not-provided>"));
183 goto err_free_buf;
186 err = getpwnam_r(localname, &buf->pwbuf, buf->buf, buflen, &pw);
187 if (pw == NULL && domain != NULL)
188 IDMAP_LOG(0,
189 ("nss_getpwnam: name '%s' not found in domain '%s'\n",
190 localname, domain));
191 free(localname);
192 if (err == 0 && pw != NULL) {
193 *err_p = 0;
194 return pw;
195 } else if (err == 0 && pw == NULL) {
196 err = ENOENT;
199 err_free_buf:
200 free(buf);
201 err:
202 *err_p = -err;
203 return NULL;
206 static int nss_name_to_uid(char *name, uid_t *uid)
208 struct passwd *pw = NULL;
209 char *domain;
210 int err = -ENOENT;
212 domain = get_default_domain();
213 pw = nss_getpwnam(name, domain, &err);
214 if (pw == NULL)
215 goto out;
216 *uid = pw->pw_uid;
217 free(pw);
218 err = 0;
219 out:
220 return err;
223 static int nss_name_to_gid(char *name, gid_t *gid)
225 struct group *gr = NULL;
226 struct group grbuf;
227 char *buf, *localname, *domain;
228 size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
229 int err = -EINVAL;
231 domain = get_default_domain();
232 localname = strip_domain(name, domain);
233 if (!localname)
234 goto out;
236 do {
237 err = -ENOMEM;
238 buf = malloc(buflen);
239 if (!buf)
240 goto out_name;
241 err = -getgrnam_r(localname, &grbuf, buf, buflen, &gr);
242 if (gr == NULL && !err)
243 err = -ENOENT;
244 if (err == -ERANGE) {
245 buflen *= 2;
246 free(buf);
248 } while (err == -ERANGE);
250 if (err)
251 goto out_buf;
252 *gid = gr->gr_gid;
253 out_buf:
254 free(buf);
255 out_name:
256 free(localname);
257 out:
258 return err;
261 static int nss_gss_princ_to_ids(char *secname, char *princ,
262 uid_t *uid, uid_t *gid,
263 extra_mapping_params **ex)
265 struct passwd *pw;
266 int err = 0;
267 char *princ_realm;
268 struct conf_list *realms;
269 struct conf_list_node *r;
270 int found = 0;
272 if (strcmp(secname, "spkm3") == 0)
273 return -ENOENT;
275 if (strcmp(secname, "krb5") != 0)
276 return -EINVAL;
278 /* get princ's realm */
279 princ_realm = strstr(princ, "@");
280 if (princ_realm == NULL)
281 return -EINVAL;
282 princ_realm++;
284 /* get list of "local-equivalent" realms and
285 * check against the principal's realm */
286 realms = get_local_realms();
287 TAILQ_FOREACH(r, &realms->fields, link) {
288 if (strcmp(r->field, princ_realm) == 0) {
289 found = 1;
290 break;
293 if (!found) {
294 IDMAP_LOG(1, ("nss_gss_princ_to_ids: Local-Realm '%s': NOT FOUND",
295 princ_realm));
296 return -ENOENT;
298 /* XXX: this should call something like getgssauthnam instead? */
299 pw = nss_getpwnam(princ, NULL, &err);
300 if (pw == NULL) {
301 err = -ENOENT;
302 goto out;
304 *uid = pw->pw_uid;
305 *gid = pw->pw_gid;
306 free(pw);
307 out:
308 return err;
311 int nss_gss_princ_to_grouplist(char *secname, char *princ,
312 gid_t *groups, int *ngroups,
313 extra_mapping_params **ex)
315 struct passwd *pw;
316 int ret = -EINVAL;
318 if (strcmp(secname, "krb5") != 0)
319 goto out;
320 /* XXX: not quite right? Need to know default realm? */
321 /* XXX: this should call something like getgssauthnam instead? */
322 pw = nss_getpwnam(princ, NULL, &ret);
323 if (pw == NULL) {
324 ret = -ENOENT;
325 goto out;
327 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, ngroups) < 0)
328 ret = -ERANGE;
329 free(pw);
330 out:
331 return ret;
335 struct trans_func nss_trans = {
336 .name = "nsswitch",
337 .init = NULL,
338 .princ_to_ids = nss_gss_princ_to_ids,
339 .name_to_uid = nss_name_to_uid,
340 .name_to_gid = nss_name_to_gid,
341 .uid_to_name = nss_uid_to_name,
342 .gid_to_name = nss_gid_to_name,
343 .gss_princ_to_grouplist = nss_gss_princ_to_grouplist,
346 struct trans_func *libnfsidmap_plugin_init()
348 return (&nss_trans);