Line data Source code
1 : /*
2 : SSSD
3 :
4 : NFS Client
5 :
6 : Copyright (C) Noam Meltzer <noam@primarydata.com> 2013-2014
7 : Copyright (C) Noam Meltzer <tsnoam@gmail.com> 2014-
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #define _GNU_SOURCE
24 :
25 : #include <stddef.h>
26 : #include <stdlib.h>
27 : #include <sys/types.h>
28 : #include <errno.h>
29 : #include <string.h>
30 :
31 : #include <nfsidmap.h>
32 : #include "nfsidmap_internal.h"
33 :
34 : #include "sss_client/sss_cli.h"
35 : #include "sss_client/nss_mc.h"
36 :
37 :
38 : /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
39 : #define PLUGIN_NAME "sss_nfs"
40 : #define CONF_SECTION "sss_nfs"
41 : #define CONF_USE_MC "memcache"
42 : #define REPLY_ID_OFFSET (8)
43 : #define REPLY_NAME_OFFSET (REPLY_ID_OFFSET + 8)
44 : #define BUF_LEN (4096)
45 : #define USE_MC_DEFAULT true
46 :
47 :
48 : /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
49 : static char sss_nfs_plugin_name[] = PLUGIN_NAME;
50 : static char nfs_conf_sect[] = CONF_SECTION;
51 : static char nfs_conf_use_mc[] = CONF_USE_MC;
52 :
53 : static bool nfs_use_mc = USE_MC_DEFAULT;
54 :
55 :
56 : /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
57 : /* Forward declarations */
58 : static int send_recv(uint8_t **repp, size_t *rep_lenp, enum sss_cli_command cmd,
59 : const void *req, size_t req_len);
60 : static int reply_to_id(id_t *idp, uint8_t *rep, size_t rep_len);
61 : static int reply_to_name(char *name, size_t len, uint8_t *rep, size_t rep_len);
62 :
63 :
64 : /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
65 : /* get from memcache functions */
66 0 : static int get_uid_from_mc(id_t *uid, const char *name)
67 : {
68 0 : int rc = 0;
69 : struct passwd pwd;
70 0 : char *buf = NULL;
71 0 : char *p = NULL;
72 0 : size_t buflen = 0;
73 0 : size_t len = 0;
74 :
75 0 : if (!nfs_use_mc) {
76 0 : return -1;
77 : }
78 :
79 0 : sss_strnlen(name, SSS_NAME_MAX, &len);
80 :
81 : do {
82 0 : buflen += BUF_LEN;
83 0 : if ((p = realloc(buf, buflen)) == NULL) {
84 0 : rc = ENOMEM;
85 0 : goto done;
86 : }
87 0 : buf = p;
88 0 : rc = sss_nss_mc_getpwnam(name, len, &pwd, buf, buflen);
89 0 : } while (rc == ERANGE);
90 :
91 0 : if (rc == 0) {
92 0 : IDMAP_LOG(1, ("found user %s in memcache", name));
93 0 : *uid = pwd.pw_uid;
94 : } else {
95 0 : IDMAP_LOG(1, ("user %s not in memcache", name));
96 : }
97 :
98 : done:
99 0 : free(buf);
100 0 : return rc;
101 : }
102 :
103 0 : static int get_gid_from_mc(id_t *gid, const char *name)
104 : {
105 0 : int rc = 0;
106 : struct group grp;
107 0 : char *buf = NULL;
108 0 : char *p = NULL;
109 0 : size_t buflen = 0;
110 : size_t len;
111 :
112 0 : if (!nfs_use_mc) {
113 0 : return -1;
114 : }
115 :
116 0 : sss_strnlen(name, SSS_NAME_MAX, &len);
117 :
118 : do {
119 0 : buflen += BUF_LEN;
120 0 : if ((p = realloc(buf, buflen)) == NULL) {
121 0 : rc = ENOMEM;
122 0 : goto done;
123 : }
124 0 : buf = p;
125 0 : rc = sss_nss_mc_getgrnam(name, len, &grp, buf, buflen);
126 0 : } while (rc == ERANGE);
127 :
128 0 : if (rc == 0) {
129 0 : IDMAP_LOG(1, ("found group %s in memcache", name));
130 0 : *gid = grp.gr_gid;
131 : } else {
132 0 : IDMAP_LOG(1, ("group %s not in memcache", name));
133 : }
134 :
135 : done:
136 0 : free(buf);
137 0 : return rc;
138 : }
139 :
140 0 : static int get_user_from_mc(char *name, size_t len, uid_t uid)
141 : {
142 : int rc;
143 : struct passwd pwd;
144 0 : char *buf = NULL;
145 0 : char *p = NULL;
146 0 : size_t buflen = 0;
147 : size_t pw_name_len;
148 :
149 0 : if (!nfs_use_mc) {
150 0 : return -1;
151 : }
152 :
153 : do {
154 0 : buflen += BUF_LEN;
155 0 : if ((p = realloc(buf, buflen)) == NULL) {
156 0 : rc = ENOMEM;
157 0 : goto done;
158 : }
159 0 : buf = p;
160 0 : rc = sss_nss_mc_getpwuid(uid, &pwd, buf, BUF_LEN);
161 0 : } while (rc == ERANGE);
162 :
163 0 : if (rc == 0) {
164 0 : pw_name_len = strlen(pwd.pw_name) + 1;
165 0 : if (pw_name_len > len) {
166 0 : IDMAP_LOG(0, ("%s: reply too long; pw_name_len=%lu, len=%lu",
167 : __func__, pw_name_len, len));
168 0 : rc = ENOBUFS;
169 : }
170 0 : IDMAP_LOG(1, ("found uid %i in memcache", uid));
171 0 : memcpy(name, pwd.pw_name, pw_name_len);
172 : } else {
173 0 : IDMAP_LOG(1, ("uid %i not in memcache", uid));
174 : }
175 :
176 : done:
177 0 : free(buf);
178 0 : return rc;
179 : }
180 :
181 0 : static int get_group_from_mc(char *name, size_t len, id_t gid)
182 : {
183 : int rc;
184 : struct group grp;
185 0 : char *buf = NULL;
186 0 : char *p = NULL;
187 0 : size_t buflen = 0;
188 : size_t gr_name_len;
189 :
190 0 : if (!nfs_use_mc) {
191 0 : return -1;
192 : }
193 :
194 : do {
195 0 : buflen += BUF_LEN;
196 0 : if ((p = realloc(buf, buflen)) == NULL) {
197 0 : rc = ENOMEM;
198 0 : goto done;
199 : }
200 0 : buf = p;
201 0 : rc = sss_nss_mc_getgrgid(gid, &grp, buf, BUF_LEN);
202 0 : } while (rc == ERANGE);
203 :
204 0 : if (rc == 0) {
205 0 : gr_name_len = strlen(grp.gr_name) + 1;
206 0 : if (gr_name_len > len) {
207 0 : IDMAP_LOG(0, ("%s: reply too long; gr_name_len=%lu, len=%lu",
208 : __func__, gr_name_len, len));
209 0 : rc = ENOBUFS;
210 : }
211 0 : IDMAP_LOG(1, ("found gid %i in memcache", gid));
212 0 : memcpy(name, grp.gr_name, gr_name_len);
213 : } else {
214 0 : IDMAP_LOG(1, ("gid %i not in memcache", gid));
215 : }
216 :
217 : done:
218 0 : free(buf);
219 0 : return rc;
220 : }
221 :
222 : /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
223 0 : static int name_to_id(const char *name, id_t *id, enum sss_cli_command cmd)
224 : {
225 : int rc;
226 0 : uint8_t *rep = NULL;
227 0 : size_t rep_len = 0;
228 : size_t name_len;
229 :
230 0 : sss_strnlen(name, SSS_NAME_MAX, &name_len);
231 :
232 0 : rc = send_recv(&rep, &rep_len, cmd, name, name_len + 1);
233 0 : if (rc == 0) {
234 0 : rc = reply_to_id(id, rep, rep_len);
235 : }
236 :
237 0 : free(rep);
238 :
239 0 : return rc;
240 : }
241 :
242 0 : static int id_to_name(char *name, size_t len, id_t id,
243 : enum sss_cli_command cmd)
244 0 : {
245 : int rc;
246 0 : size_t rep_len = 0;
247 0 : size_t req_len = sizeof(id_t);
248 0 : uint8_t *rep = NULL;
249 0 : uint8_t req[req_len];
250 :
251 0 : memcpy(req, &id, req_len);
252 0 : rc = send_recv(&rep, &rep_len, cmd, &req, req_len);
253 0 : if (rc == 0) {
254 0 : rc = reply_to_name(name, len, rep, rep_len);
255 : }
256 :
257 0 : free(rep);
258 :
259 0 : return rc;
260 : }
261 :
262 : /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
263 0 : static int send_recv(uint8_t **rep, size_t *rep_len, enum sss_cli_command cmd,
264 : const void *req, size_t req_len)
265 : {
266 0 : int err = 0;
267 : enum nss_status req_rc;
268 : struct sss_cli_req_data rd;
269 :
270 0 : rd.data = req;
271 0 : rd.len = req_len;
272 :
273 0 : sss_nss_lock();
274 0 : req_rc = sss_nss_make_request(cmd, &rd, rep, rep_len, &err);
275 0 : sss_nss_unlock();
276 :
277 0 : if (req_rc == NSS_STATUS_NOTFOUND) {
278 0 : return ENOENT;
279 : }
280 0 : if (req_rc != NSS_STATUS_SUCCESS) {
281 0 : IDMAP_LOG(0, ("no-make-request; err=%i", err));
282 0 : return EPIPE;
283 : }
284 :
285 0 : return 0;
286 : }
287 :
288 0 : static int reply_to_id(id_t *idp, uint8_t *rep, size_t rep_len)
289 : {
290 0 : int rc = 0;
291 : id_t id;
292 0 : uint32_t num_results = 0;
293 :
294 0 : if (rep_len < sizeof(uint32_t)) {
295 0 : IDMAP_LOG(0, ("%s: reply too small; rep_len=%lu", __func__, rep_len));
296 0 : rc = EBADMSG;
297 0 : goto done;
298 : }
299 :
300 0 : SAFEALIGN_COPY_UINT32(&num_results, rep, NULL);
301 0 : if (num_results > 1) {
302 0 : IDMAP_LOG(0, ("%s: too many results (%lu)", __func__, num_results));
303 0 : rc = EBADMSG;
304 0 : goto done;
305 : }
306 0 : if (num_results == 0) {
307 0 : rc = ENOENT;
308 0 : goto done;
309 : }
310 0 : if (rep_len < sizeof(uint32_t) + REPLY_ID_OFFSET) {
311 0 : IDMAP_LOG(0, ("%s: reply too small(2); rep_len=%lu", __func__,
312 : rep_len));
313 0 : rc = EBADMSG;
314 0 : goto done;
315 : }
316 :
317 0 : SAFEALIGN_COPY_UINT32(&id, rep + REPLY_ID_OFFSET, NULL);
318 0 : *idp = id;
319 :
320 : done:
321 0 : return rc;
322 : }
323 :
324 0 : static int reply_to_name(char *name, size_t len, uint8_t *rep, size_t rep_len)
325 : {
326 0 : int rc = 0;
327 0 : uint32_t num_results = 0;
328 : const char *buf;
329 : size_t buf_len;
330 : size_t offset;
331 :
332 0 : if (rep_len < sizeof(uint32_t)) {
333 0 : IDMAP_LOG(0, ("%s: reply too small; rep_len=%lu", __func__, rep_len));
334 0 : rc = EBADMSG;
335 0 : goto done;
336 : }
337 :
338 0 : SAFEALIGN_COPY_UINT32(&num_results, rep, NULL);
339 0 : if (num_results > 1) {
340 0 : IDMAP_LOG(0, ("%s: too many results (%lu)", __func__, num_results));
341 0 : rc = EBADMSG;
342 0 : goto done;
343 : }
344 0 : if (num_results == 0) {
345 0 : rc = ENOENT;
346 0 : goto done;
347 : }
348 0 : if (rep_len < sizeof(uint32_t) + REPLY_NAME_OFFSET) {
349 0 : IDMAP_LOG(0, ("%s: reply too small(2); rep_len=%lu", __func__,
350 : rep_len));
351 0 : rc = EBADMSG;
352 0 : goto done;
353 : }
354 :
355 0 : buf = (const char *)(rep + REPLY_NAME_OFFSET);
356 0 : buf_len = rep_len - REPLY_NAME_OFFSET;
357 0 : offset = 0;
358 0 : rc = sss_readrep_copy_string(buf, &offset, &buf_len, &len, &name, NULL);
359 0 : if (rc != 0) {
360 0 : rc = -rc;
361 : }
362 :
363 : done:
364 0 : return rc;
365 : }
366 :
367 : /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
368 : /* configuration parsing aids */
369 0 : static bool str_equal(const char *s1, const char *s2)
370 : {
371 0 : bool res = false;
372 : size_t len1;
373 : size_t len2;
374 :
375 0 : len1 = strlen(s1);
376 0 : len2 = strlen(s2);
377 :
378 0 : if (len1 == len2) {
379 0 : res = (strncasecmp(s1, s2, len1) == 0);
380 : }
381 :
382 0 : return res;
383 : }
384 :
385 0 : static int nfs_conf_get_bool(char *sect, char *attr, int def)
386 : {
387 : int res;
388 : char *val;
389 :
390 0 : res = def;
391 0 : val = conf_get_str(sect, attr);
392 0 : if (val) {
393 0 : res = (str_equal("1", val) ||
394 0 : str_equal("yes", val) ||
395 0 : str_equal("true", val) ||
396 0 : str_equal("on", val));
397 : }
398 :
399 0 : return res;
400 : }
401 :
402 :
403 : /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
404 : /* libnfsidmap return-code aids */
405 :
406 : /*
407 : * we only want to return 0 or ENOENT; otherwise libnfsidmap will stop
408 : * translation instead of proceeding to the next translation plugin
409 : */
410 0 : int normalise_rc(int rc) {
411 : int res;
412 :
413 0 : res = rc;
414 0 : if (res != 0 && res != ENOENT) {
415 0 : res = ENOENT;
416 : }
417 :
418 0 : return res;
419 : }
420 :
421 : /* log the actual rc from our code (to be used before normalising the rc) */
422 0 : void log_actual_rc(const char *trans_name, int rc) {
423 : char tmp[80];
424 0 : IDMAP_LOG(1, ("%s: rc=%i msg=%s", trans_name, rc,
425 : strerror_r(rc, tmp, sizeof(tmp))));
426 0 : }
427 :
428 :
429 : /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
430 : /* The external interface */
431 0 : static int sss_nfs_init(void)
432 : {
433 0 : nfs_use_mc = nfs_conf_get_bool(nfs_conf_sect, nfs_conf_use_mc,
434 : USE_MC_DEFAULT);
435 0 : IDMAP_LOG(1, ("%s: use memcache: %i", __func__, nfs_use_mc));
436 :
437 0 : return 0;
438 : }
439 :
440 0 : static int sss_nfs_princ_to_ids(char *secname, char *princ, uid_t *uid,
441 : gid_t *gid, extra_mapping_params **ex)
442 : {
443 0 : IDMAP_LOG(0, ("%s: not implemented", __func__));
444 0 : return -ENOENT;
445 : }
446 :
447 0 : static int sss_nfs_name_to_uid(char *name, uid_t *uid)
448 : {
449 : int rc;
450 0 : size_t name_len = 0;
451 :
452 0 : if (name == NULL) {
453 0 : IDMAP_LOG(0, ("%s: name is null", __func__));
454 0 : return -EINVAL;
455 : }
456 0 : if (uid == NULL) {
457 0 : IDMAP_LOG(0, ("%s: uid is null", __func__));
458 0 : return -EINVAL;
459 : }
460 :
461 0 : rc = sss_strnlen(name, SSS_NAME_MAX, &name_len);
462 0 : if (rc != 0) {
463 0 : IDMAP_LOG(0, ("%s: no-strnlen; rc=%i", __func__, rc));
464 0 : return -rc;
465 : }
466 :
467 0 : rc = get_uid_from_mc(uid, name);
468 0 : if (rc != 0) {
469 0 : rc = name_to_id(name, uid, SSS_NSS_GETPWNAM);
470 : }
471 :
472 0 : log_actual_rc(__func__, rc);
473 0 : rc = normalise_rc(rc);
474 :
475 0 : return -rc;
476 : }
477 :
478 0 : static int sss_nfs_name_to_gid(char *name, gid_t *gid)
479 : {
480 : int rc;
481 0 : size_t name_len = 0;
482 :
483 0 : if (name == NULL) {
484 0 : IDMAP_LOG(0, ("%s: name is null", __func__));
485 0 : return -EINVAL;
486 : }
487 0 : if (gid == NULL) {
488 0 : IDMAP_LOG(0, ("%s: gid is null", __func__));
489 0 : return -EINVAL;
490 : }
491 :
492 0 : rc = sss_strnlen(name, SSS_NAME_MAX, &name_len);
493 0 : if (rc != 0) {
494 0 : IDMAP_LOG(0, ("%s: no-strnlen; rc=%i", __func__, rc));
495 0 : return -rc;
496 : }
497 :
498 0 : rc = get_gid_from_mc(gid, name);
499 0 : if (rc != 0) {
500 0 : rc = name_to_id(name, gid, SSS_NSS_GETGRNAM);
501 : }
502 :
503 0 : log_actual_rc(__func__, rc);
504 0 : rc = normalise_rc(rc);
505 :
506 0 : return -rc;
507 : }
508 :
509 0 : static int sss_nfs_uid_to_name(uid_t uid, char *domain, char *name, size_t len)
510 : {
511 : int rc;
512 :
513 0 : if (name == NULL) {
514 0 : IDMAP_LOG(0, ("%s: name is null", __func__));
515 0 : return -EINVAL;
516 : }
517 :
518 0 : rc = get_user_from_mc(name, len, uid);
519 0 : if (rc != 0) {
520 0 : rc = id_to_name(name, len, uid, SSS_NSS_GETPWUID);
521 : }
522 :
523 0 : log_actual_rc(__func__, rc);
524 0 : rc = normalise_rc(rc);
525 :
526 0 : return -rc;
527 : }
528 :
529 0 : static int sss_nfs_gid_to_name(gid_t gid, char *domain, char *name, size_t len)
530 : {
531 : int rc;
532 :
533 0 : if (name == NULL) {
534 0 : IDMAP_LOG(0, ("%s: name is null", __func__));
535 0 : return -EINVAL;
536 : }
537 :
538 0 : rc = get_group_from_mc(name, len, gid);
539 0 : if (rc != 0) {
540 0 : rc = id_to_name(name, len, gid, SSS_NSS_GETGRGID);
541 : }
542 :
543 0 : log_actual_rc(__func__, rc);
544 0 : rc = normalise_rc(rc);
545 :
546 0 : return -rc;
547 : }
548 :
549 0 : static int sss_nfs_gss_princ_to_grouplist(
550 : char *secname, char *princ, gid_t *groups, int *ngroups,
551 : extra_mapping_params **ex)
552 : {
553 0 : IDMAP_LOG(0, ("%s: not implemented", __func__));
554 0 : return -ENOENT;
555 : }
556 :
557 : static struct trans_func s_sss_nfs_trans = {
558 : .name = sss_nfs_plugin_name,
559 : .init = sss_nfs_init,
560 : .princ_to_ids = sss_nfs_princ_to_ids,
561 : .name_to_uid = sss_nfs_name_to_uid,
562 : .name_to_gid = sss_nfs_name_to_gid,
563 : .uid_to_name = sss_nfs_uid_to_name,
564 : .gid_to_name = sss_nfs_gid_to_name,
565 : .gss_princ_to_grouplist = sss_nfs_gss_princ_to_grouplist,
566 : };
567 :
568 0 : struct trans_func *libnfsidmap_plugin_init(void)
569 : {
570 0 : return (&s_sss_nfs_trans);
571 : }
|