Line data Source code
1 : /*
2 : SSSD
3 :
4 : ID-mapping library
5 :
6 : Authors:
7 : Sumit Bose <sbose@redhat.com>
8 :
9 : Copyright (C) 2012 Red Hat
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include <string.h>
26 : #include <stdio.h>
27 : #include <errno.h>
28 :
29 : #include "lib/idmap/sss_idmap.h"
30 : #include "lib/idmap/sss_idmap_private.h"
31 : #include "util/murmurhash3.h"
32 :
33 : #define SID_FMT "%s-%d"
34 : #define SID_STR_MAX_LEN 1024
35 :
36 : struct idmap_domain_info {
37 : char *name;
38 : char *sid;
39 : struct sss_idmap_range *range;
40 : struct idmap_domain_info *next;
41 : uint32_t first_rid;
42 : char *range_id;
43 : bool external_mapping;
44 : };
45 :
46 1 : static void *default_alloc(size_t size, void *pvt)
47 : {
48 1 : return malloc(size);
49 : }
50 :
51 1 : static void default_free(void *ptr, void *pvt)
52 : {
53 1 : free(ptr);
54 1 : }
55 :
56 97 : static char *idmap_strdup(struct sss_idmap_ctx *ctx, const char *str)
57 : {
58 97 : char *new = NULL;
59 : size_t len;
60 :
61 97 : CHECK_IDMAP_CTX(ctx, NULL);
62 :
63 97 : len = strlen(str) + 1;
64 :
65 97 : new = ctx->alloc_func(len, ctx->alloc_pvt);
66 97 : if (new == NULL) {
67 0 : return NULL;
68 : }
69 :
70 97 : memcpy(new, str, len);
71 :
72 97 : return new;
73 : }
74 :
75 51 : static struct sss_idmap_range *idmap_range_dup(struct sss_idmap_ctx *ctx,
76 : struct sss_idmap_range *range)
77 : {
78 51 : struct sss_idmap_range *new = NULL;
79 :
80 51 : CHECK_IDMAP_CTX(ctx, NULL);
81 :
82 :
83 51 : new = ctx->alloc_func(sizeof(struct sss_idmap_range), ctx->alloc_pvt);
84 51 : if (new == NULL) {
85 0 : return NULL;
86 : }
87 :
88 51 : memset(new, 0, sizeof(struct sss_idmap_range));
89 :
90 51 : new->min = range->min;
91 51 : new->max = range->max;
92 :
93 51 : return new;
94 : }
95 :
96 16 : static bool id_is_in_range(uint32_t id, struct idmap_domain_info *dom,
97 : uint32_t *rid)
98 : {
99 16 : if (id == 0 || dom == NULL || dom->range == NULL) {
100 0 : return false;
101 : }
102 :
103 16 : if (id >= dom->range->min && id <= dom->range->max) {
104 7 : if (rid != NULL) {
105 7 : *rid = dom->first_rid + (id - dom->range->min);
106 : }
107 :
108 7 : return true;
109 : }
110 :
111 9 : return false;
112 : }
113 :
114 0 : const char *idmap_error_string(enum idmap_error_code err)
115 : {
116 0 : switch (err) {
117 : case IDMAP_SUCCESS:
118 0 : return "IDMAP operation successful";
119 : break;
120 : case IDMAP_NOT_IMPLEMENTED:
121 0 : return "IDMAP Function is not yet implemented";
122 : break;
123 : case IDMAP_ERROR:
124 0 : return "IDMAP general error";
125 : break;
126 : case IDMAP_OUT_OF_MEMORY:
127 0 : return "IDMAP operation ran out of memory";
128 : break;
129 : case IDMAP_NO_DOMAIN:
130 0 : return "IDMAP domain not found";
131 : break;
132 : case IDMAP_CONTEXT_INVALID:
133 0 : return "IDMAP context is invalid";
134 : break;
135 : case IDMAP_SID_INVALID:
136 0 : return "IDMAP SID is invalid";
137 : break;
138 : case IDMAP_SID_UNKNOWN:
139 0 : return "IDMAP SID not found";
140 : break;
141 : case IDMAP_NO_RANGE:
142 0 : return "IDMAP range not found";
143 : default:
144 0 : return "IDMAP unknown error code";
145 : }
146 : }
147 :
148 53 : bool is_domain_sid(const char *sid)
149 : {
150 : const char *p;
151 : long long a;
152 : char *endptr;
153 : size_t c;
154 :
155 53 : if (sid == NULL || strncmp(sid, DOM_SID_PREFIX, DOM_SID_PREFIX_LEN) != 0) {
156 4 : return false;
157 : }
158 :
159 49 : p = sid + DOM_SID_PREFIX_LEN;
160 49 : c = 0;
161 :
162 : do {
163 141 : errno = 0;
164 141 : a = strtoull(p, &endptr, 10);
165 141 : if (errno != 0 || a > UINT32_MAX) {
166 1 : return false;
167 : }
168 :
169 140 : if (*endptr == '-') {
170 93 : p = endptr + 1;
171 47 : } else if (*endptr != '\0') {
172 2 : return false;
173 : }
174 138 : c++;
175 138 : } while(c < 3 && *endptr != '\0');
176 :
177 46 : if (c != 3 || *endptr != '\0') {
178 2 : return false;
179 : }
180 :
181 44 : return true;
182 : }
183 :
184 85 : enum idmap_error_code sss_idmap_init(idmap_alloc_func *alloc_func,
185 : void *alloc_pvt,
186 : idmap_free_func *free_func,
187 : struct sss_idmap_ctx **_ctx)
188 : {
189 : struct sss_idmap_ctx *ctx;
190 :
191 85 : if (alloc_func == NULL) {
192 1 : alloc_func = default_alloc;
193 : }
194 :
195 85 : ctx = alloc_func(sizeof(struct sss_idmap_ctx), alloc_pvt);
196 85 : if (ctx == NULL) {
197 0 : return IDMAP_OUT_OF_MEMORY;
198 : }
199 85 : memset(ctx, 0, sizeof(struct sss_idmap_ctx));
200 :
201 85 : ctx->alloc_func = alloc_func;
202 85 : ctx->alloc_pvt = alloc_pvt;
203 85 : ctx->free_func = (free_func == NULL) ? default_free : free_func;
204 :
205 : /* Set default values. */
206 85 : ctx->idmap_opts.autorid_mode = SSS_IDMAP_DEFAULT_AUTORID;
207 85 : ctx->idmap_opts.idmap_lower = SSS_IDMAP_DEFAULT_LOWER;
208 85 : ctx->idmap_opts.idmap_upper = SSS_IDMAP_DEFAULT_UPPER;
209 85 : ctx->idmap_opts.rangesize = SSS_IDMAP_DEFAULT_RANGESIZE;
210 :
211 85 : *_ctx = ctx;
212 :
213 85 : return IDMAP_SUCCESS;
214 : }
215 :
216 24 : static void sss_idmap_free_domain(struct sss_idmap_ctx *ctx,
217 : struct idmap_domain_info *dom)
218 : {
219 24 : if (ctx == NULL || dom == NULL) {
220 0 : return;
221 : }
222 :
223 24 : ctx->free_func(dom->range_id, ctx->alloc_pvt);
224 24 : ctx->free_func(dom->range, ctx->alloc_pvt);
225 24 : ctx->free_func(dom->name, ctx->alloc_pvt);
226 24 : ctx->free_func(dom->sid, ctx->alloc_pvt);
227 24 : ctx->free_func(dom, ctx->alloc_pvt);
228 : }
229 :
230 21 : enum idmap_error_code sss_idmap_free(struct sss_idmap_ctx *ctx)
231 : {
232 : struct idmap_domain_info *dom;
233 : struct idmap_domain_info *next;
234 :
235 21 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
236 :
237 21 : next = ctx->idmap_domain_info;
238 53 : while (next) {
239 11 : dom = next;
240 11 : next = dom->next;
241 11 : sss_idmap_free_domain(ctx, dom);
242 : }
243 :
244 21 : ctx->free_func(ctx, ctx->alloc_pvt);
245 :
246 21 : return IDMAP_SUCCESS;
247 : }
248 :
249 36 : static enum idmap_error_code sss_idmap_free_ptr(struct sss_idmap_ctx *ctx,
250 : void *ptr)
251 : {
252 36 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
253 :
254 36 : if (ptr != NULL) {
255 36 : ctx->free_func(ptr, ctx->alloc_pvt);
256 : }
257 :
258 36 : return IDMAP_SUCCESS;
259 : }
260 :
261 9 : enum idmap_error_code sss_idmap_free_sid(struct sss_idmap_ctx *ctx,
262 : char *sid)
263 : {
264 9 : return sss_idmap_free_ptr(ctx, sid);
265 : }
266 :
267 6 : enum idmap_error_code sss_idmap_free_dom_sid(struct sss_idmap_ctx *ctx,
268 : struct sss_dom_sid *dom_sid)
269 : {
270 6 : return sss_idmap_free_ptr(ctx, dom_sid);
271 : }
272 :
273 8 : enum idmap_error_code sss_idmap_free_smb_sid(struct sss_idmap_ctx *ctx,
274 : struct dom_sid *smb_sid)
275 : {
276 8 : return sss_idmap_free_ptr(ctx, smb_sid);
277 : }
278 :
279 13 : enum idmap_error_code sss_idmap_free_bin_sid(struct sss_idmap_ctx *ctx,
280 : uint8_t *bin_sid)
281 : {
282 13 : return sss_idmap_free_ptr(ctx, bin_sid);
283 : }
284 :
285 0 : enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx,
286 : const char *dom_sid,
287 : id_t *slice_num,
288 : struct sss_idmap_range *_range)
289 : {
290 : id_t max_slices;
291 : id_t orig_slice;
292 0 : id_t new_slice = 0;
293 : id_t min;
294 : id_t max;
295 : id_t idmap_lower;
296 : id_t idmap_upper;
297 : id_t rangesize;
298 : bool autorid_mode;
299 : uint32_t hash_val;
300 : struct idmap_domain_info *dom;
301 :
302 0 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
303 :
304 0 : idmap_lower = ctx->idmap_opts.idmap_lower;
305 0 : idmap_upper = ctx->idmap_opts.idmap_upper;
306 0 : rangesize = ctx->idmap_opts.rangesize;
307 0 : autorid_mode = ctx->idmap_opts.autorid_mode;
308 :
309 0 : max_slices = (idmap_upper - idmap_lower) / rangesize;
310 :
311 0 : if (slice_num && *slice_num != -1) {
312 : /* The slice is being set explicitly.
313 : * This may happen at system startup when we're loading
314 : * previously-determined slices. In the future, we may also
315 : * permit configuration to select the slice for a domain
316 : * explicitly.
317 : */
318 0 : new_slice = *slice_num;
319 : } else {
320 : /* If slice is -1, we're being asked to pick a new slice */
321 :
322 0 : if (autorid_mode) {
323 : /* In autorid compatibility mode, always start at 0 and find the
324 : * first free value.
325 : */
326 0 : orig_slice = 0;
327 : } else {
328 : /* Hash the domain sid string */
329 0 : hash_val = murmurhash3(dom_sid, strlen(dom_sid), 0xdeadbeef);
330 :
331 : /* Now get take the modulus of the hash val and the max_slices
332 : * to determine its optimal position in the range.
333 : */
334 0 : new_slice = hash_val % max_slices;
335 0 : orig_slice = new_slice;
336 : }
337 :
338 0 : min = (rangesize * new_slice) + idmap_lower;
339 0 : max = min + rangesize;
340 : /* Verify that this slice is not already in use */
341 : do {
342 0 : for (dom = ctx->idmap_domain_info; dom != NULL; dom = dom->next) {
343 0 : if ((dom->range->min <= min && dom->range->max >= max) ||
344 0 : (dom->range->min >= min && dom->range->min <= max) ||
345 0 : (dom->range->max >= min && dom->range->max <= max)) {
346 : /* This range overlaps one already registered
347 : * We'll try the next available slot
348 : */
349 0 : new_slice++;
350 0 : if (new_slice >= max_slices) {
351 : /* loop around to the beginning if necessary */
352 0 : new_slice = 0;
353 : }
354 :
355 0 : min = (rangesize * new_slice) + idmap_lower;
356 0 : max = min + rangesize;
357 0 : break;
358 : }
359 : }
360 :
361 : /* Keep trying until dom is NULL (meaning we got to the end
362 : * without matching) or we have run out of slices and gotten
363 : * back to the first one we tried.
364 : */
365 0 : } while (dom && new_slice != orig_slice);
366 :
367 0 : if (dom) {
368 : /* We looped all the way through and found no empty slots */
369 0 : return IDMAP_OUT_OF_SLICES;
370 : }
371 : }
372 :
373 0 : _range->min = (rangesize * new_slice) + idmap_lower;
374 0 : _range->max = _range->min + rangesize;
375 :
376 0 : if (slice_num) {
377 0 : *slice_num = new_slice;
378 : }
379 :
380 0 : return IDMAP_SUCCESS;
381 : }
382 :
383 43 : enum idmap_error_code sss_idmap_check_collision_ex(const char *o_name,
384 : const char *o_sid,
385 : struct sss_idmap_range *o_range,
386 : uint32_t o_first_rid,
387 : const char *o_range_id,
388 : bool o_external_mapping,
389 : const char *n_name,
390 : const char *n_sid,
391 : struct sss_idmap_range *n_range,
392 : uint32_t n_first_rid,
393 : const char *n_range_id,
394 : bool n_external_mapping)
395 : {
396 : bool names_equal;
397 : bool sids_equal;
398 :
399 : /* TODO: if both ranges have the same ID check if an update is
400 : * needed. */
401 :
402 : /* Check if ID ranges overlap.
403 : * ID ranges with external mapping may overlap. */
404 43 : if ((!n_external_mapping && !o_external_mapping)
405 19 : && ((n_range->min >= o_range->min
406 19 : && n_range->min <= o_range->max)
407 13 : || (n_range->max >= o_range->min
408 13 : && n_range->max <= o_range->max))) {
409 6 : return IDMAP_COLLISION;
410 : }
411 :
412 37 : names_equal = (strcasecmp(n_name, o_name) == 0);
413 39 : sids_equal = ((n_sid == NULL && o_sid == NULL)
414 92 : || (n_sid != NULL && o_sid != NULL
415 35 : && strcasecmp(n_sid, o_sid) == 0));
416 :
417 : /* check if domain name and SID are consistent */
418 37 : if ((names_equal && !sids_equal) || (!names_equal && sids_equal)) {
419 8 : return IDMAP_COLLISION;
420 : }
421 :
422 : /* check if external_mapping is consistent */
423 29 : if (names_equal && sids_equal
424 14 : && n_external_mapping != o_external_mapping) {
425 2 : return IDMAP_COLLISION;
426 : }
427 :
428 : /* check if RID ranges overlap */
429 27 : if (names_equal && sids_equal
430 12 : && n_external_mapping == false
431 7 : && n_first_rid >= o_first_rid
432 7 : && n_first_rid <= o_first_rid + (o_range->max - o_range->min)) {
433 2 : return IDMAP_COLLISION;
434 : }
435 :
436 25 : return IDMAP_SUCCESS;
437 : }
438 :
439 0 : enum idmap_error_code sss_idmap_check_collision(struct sss_idmap_ctx *ctx,
440 : char *n_name, char *n_sid,
441 : struct sss_idmap_range *n_range,
442 : uint32_t n_first_rid,
443 : char *n_range_id,
444 : bool n_external_mapping)
445 : {
446 : struct idmap_domain_info *dom;
447 : enum idmap_error_code err;
448 :
449 0 : for (dom = ctx->idmap_domain_info; dom != NULL; dom = dom->next) {
450 0 : err = sss_idmap_check_collision_ex(dom->name, dom->sid, dom->range,
451 0 : dom->first_rid, dom->range_id,
452 0 : dom->external_mapping,
453 : n_name, n_sid, n_range, n_first_rid,
454 : n_range_id, n_external_mapping);
455 0 : if (err != IDMAP_SUCCESS) {
456 0 : return err;
457 : }
458 : }
459 0 : return IDMAP_SUCCESS;
460 : }
461 :
462 51 : static enum idmap_error_code dom_check_collision(
463 : struct idmap_domain_info *dom_list,
464 : struct idmap_domain_info *new_dom)
465 : {
466 : struct idmap_domain_info *dom;
467 : enum idmap_error_code err;
468 :
469 72 : for (dom = dom_list; dom != NULL; dom = dom->next) {
470 136 : err = sss_idmap_check_collision_ex(dom->name, dom->sid, dom->range,
471 34 : dom->first_rid, dom->range_id,
472 34 : dom->external_mapping,
473 34 : new_dom->name, new_dom->sid,
474 : new_dom->range, new_dom->first_rid,
475 34 : new_dom->range_id,
476 34 : new_dom->external_mapping);
477 34 : if (err != IDMAP_SUCCESS) {
478 13 : return err;
479 : }
480 : }
481 38 : return IDMAP_SUCCESS;
482 : }
483 :
484 52 : enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx,
485 : const char *domain_name,
486 : const char *domain_sid,
487 : struct sss_idmap_range *range,
488 : const char *range_id,
489 : uint32_t rid,
490 : bool external_mapping)
491 : {
492 52 : struct idmap_domain_info *dom = NULL;
493 : enum idmap_error_code err;
494 :
495 52 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
496 :
497 52 : if (domain_name == NULL) {
498 0 : return IDMAP_NO_DOMAIN;
499 : }
500 :
501 52 : if (range == NULL) {
502 0 : return IDMAP_NO_RANGE;
503 : }
504 :
505 : /* For algorithmic mapping a valid domain SID is required, for external
506 : * mapping it may be NULL, but if set it should be valid. */
507 52 : if ((!external_mapping && !is_domain_sid(domain_sid))
508 51 : || (external_mapping
509 21 : && domain_sid != NULL
510 13 : && !is_domain_sid(domain_sid))) {
511 1 : return IDMAP_SID_INVALID;
512 : }
513 :
514 51 : dom = ctx->alloc_func(sizeof(struct idmap_domain_info), ctx->alloc_pvt);
515 51 : if (dom == NULL) {
516 0 : return IDMAP_OUT_OF_MEMORY;
517 : }
518 51 : memset(dom, 0, sizeof(struct idmap_domain_info));
519 :
520 51 : dom->name = idmap_strdup(ctx, domain_name);
521 51 : if (dom->name == NULL) {
522 0 : err = IDMAP_OUT_OF_MEMORY;
523 0 : goto fail;
524 : }
525 :
526 51 : if (domain_sid != NULL) {
527 43 : dom->sid = idmap_strdup(ctx, domain_sid);
528 43 : if (dom->sid == NULL) {
529 0 : err = IDMAP_OUT_OF_MEMORY;
530 0 : goto fail;
531 : }
532 : }
533 :
534 51 : dom->range = idmap_range_dup(ctx, range);
535 51 : if (dom->range == NULL) {
536 0 : err = IDMAP_OUT_OF_MEMORY;
537 0 : goto fail;
538 : }
539 :
540 51 : if (range_id != NULL) {
541 3 : dom->range_id = idmap_strdup(ctx, range_id);
542 3 : if (dom->range_id == NULL) {
543 0 : err = IDMAP_OUT_OF_MEMORY;
544 0 : goto fail;
545 : }
546 : }
547 :
548 51 : dom->first_rid = rid;
549 51 : dom->external_mapping = external_mapping;
550 :
551 51 : err = dom_check_collision(ctx->idmap_domain_info, dom);
552 51 : if (err != IDMAP_SUCCESS) {
553 13 : goto fail;
554 : }
555 :
556 38 : dom->next = ctx->idmap_domain_info;
557 38 : ctx->idmap_domain_info = dom;
558 :
559 38 : return IDMAP_SUCCESS;
560 :
561 : fail:
562 13 : sss_idmap_free_domain(ctx, dom);
563 :
564 13 : return err;
565 : }
566 :
567 14 : enum idmap_error_code sss_idmap_add_domain(struct sss_idmap_ctx *ctx,
568 : const char *domain_name,
569 : const char *domain_sid,
570 : struct sss_idmap_range *range)
571 : {
572 14 : return sss_idmap_add_domain_ex(ctx, domain_name, domain_sid, range, NULL,
573 : 0, false);
574 : }
575 :
576 23 : static bool sss_idmap_sid_is_builtin(const char *sid)
577 : {
578 23 : if (strncmp(sid, "S-1-5-32-", 9) == 0) {
579 0 : return true;
580 : }
581 :
582 23 : return false;
583 : }
584 :
585 13 : enum idmap_error_code sss_idmap_sid_to_unix(struct sss_idmap_ctx *ctx,
586 : const char *sid,
587 : uint32_t *_id)
588 : {
589 : struct idmap_domain_info *idmap_domain_info;
590 : size_t dom_len;
591 : long long rid;
592 : char *endptr;
593 : uint32_t id;
594 13 : bool no_range = false;
595 :
596 13 : if (sid == NULL || _id == NULL) {
597 0 : return IDMAP_ERROR;
598 : }
599 :
600 13 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
601 :
602 13 : idmap_domain_info = ctx->idmap_domain_info;
603 :
604 13 : if (sss_idmap_sid_is_builtin(sid)) {
605 0 : return IDMAP_BUILTIN_SID;
606 : }
607 :
608 35 : while (idmap_domain_info != NULL) {
609 17 : if (idmap_domain_info->sid != NULL) {
610 17 : dom_len = strlen(idmap_domain_info->sid);
611 17 : if (strlen(sid) > dom_len && sid[dom_len] == '-'
612 12 : && strncmp(sid, idmap_domain_info->sid, dom_len) == 0) {
613 :
614 12 : if (idmap_domain_info->external_mapping == true) {
615 3 : return IDMAP_EXTERNAL;
616 : }
617 :
618 9 : errno = 0;
619 9 : rid = strtoull(sid + dom_len + 1, &endptr, 10);
620 9 : if (errno != 0 || rid > UINT32_MAX || *endptr != '\0') {
621 0 : return IDMAP_SID_INVALID;
622 : }
623 :
624 9 : if (rid >= idmap_domain_info->first_rid) {
625 14 : id = idmap_domain_info->range->min
626 7 : + (rid - idmap_domain_info->first_rid);
627 7 : if (id <= idmap_domain_info->range->max) {
628 5 : *_id = id;
629 5 : return IDMAP_SUCCESS;
630 : }
631 : }
632 :
633 4 : no_range = true;
634 : }
635 : }
636 :
637 9 : idmap_domain_info = idmap_domain_info->next;
638 : }
639 :
640 5 : return no_range ? IDMAP_NO_RANGE : IDMAP_NO_DOMAIN;
641 : }
642 :
643 10 : enum idmap_error_code sss_idmap_check_sid_unix(struct sss_idmap_ctx *ctx,
644 : const char *sid,
645 : uint32_t id)
646 : {
647 : struct idmap_domain_info *idmap_domain_info;
648 : size_t dom_len;
649 10 : bool no_range = false;
650 :
651 10 : if (sid == NULL) {
652 0 : return IDMAP_ERROR;
653 : }
654 :
655 10 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
656 :
657 10 : if (ctx->idmap_domain_info == NULL) {
658 0 : return IDMAP_NO_DOMAIN;
659 : }
660 :
661 10 : idmap_domain_info = ctx->idmap_domain_info;
662 :
663 10 : if (sss_idmap_sid_is_builtin(sid)) {
664 0 : return IDMAP_BUILTIN_SID;
665 : }
666 :
667 34 : while (idmap_domain_info != NULL) {
668 18 : if (idmap_domain_info->sid != NULL) {
669 18 : dom_len = strlen(idmap_domain_info->sid);
670 18 : if (strlen(sid) > dom_len && sid[dom_len] == '-'
671 14 : && strncmp(sid, idmap_domain_info->sid, dom_len) == 0) {
672 :
673 14 : if (id >= idmap_domain_info->range->min
674 8 : && id <= idmap_domain_info->range->max) {
675 4 : return IDMAP_SUCCESS;
676 : }
677 :
678 10 : no_range = true;
679 : }
680 : }
681 :
682 14 : idmap_domain_info = idmap_domain_info->next;
683 : }
684 :
685 6 : return no_range ? IDMAP_NO_RANGE : IDMAP_SID_UNKNOWN;
686 : }
687 :
688 12 : enum idmap_error_code sss_idmap_unix_to_sid(struct sss_idmap_ctx *ctx,
689 : uint32_t id,
690 : char **_sid)
691 : {
692 : struct idmap_domain_info *idmap_domain_info;
693 : int len;
694 : int ret;
695 : uint32_t rid;
696 12 : char *sid = NULL;
697 :
698 12 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
699 :
700 12 : idmap_domain_info = ctx->idmap_domain_info;
701 :
702 33 : while (idmap_domain_info != NULL) {
703 16 : if (id_is_in_range(id, idmap_domain_info, &rid)) {
704 :
705 7 : if (idmap_domain_info->external_mapping == true
706 5 : || idmap_domain_info->sid == NULL) {
707 2 : return IDMAP_EXTERNAL;
708 : }
709 :
710 5 : len = snprintf(NULL, 0, SID_FMT, idmap_domain_info->sid, rid);
711 5 : if (len <= 0 || len > SID_STR_MAX_LEN) {
712 0 : return IDMAP_ERROR;
713 : }
714 :
715 5 : sid = ctx->alloc_func(len + 1, ctx->alloc_pvt);
716 5 : if (sid == NULL) {
717 0 : return IDMAP_OUT_OF_MEMORY;
718 : }
719 :
720 5 : ret = snprintf(sid, len + 1, SID_FMT, idmap_domain_info->sid, rid);
721 5 : if (ret != len) {
722 0 : ctx->free_func(sid, ctx->alloc_pvt);
723 0 : return IDMAP_ERROR;
724 : }
725 :
726 5 : *_sid = sid;
727 5 : return IDMAP_SUCCESS;
728 : }
729 :
730 9 : idmap_domain_info = idmap_domain_info->next;
731 : }
732 :
733 5 : return IDMAP_NO_DOMAIN;
734 : }
735 :
736 1 : enum idmap_error_code sss_idmap_dom_sid_to_unix(struct sss_idmap_ctx *ctx,
737 : struct sss_dom_sid *dom_sid,
738 : uint32_t *id)
739 : {
740 : enum idmap_error_code err;
741 : char *sid;
742 :
743 1 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
744 :
745 1 : err = sss_idmap_dom_sid_to_sid(ctx, dom_sid, &sid);
746 1 : if (err != IDMAP_SUCCESS) {
747 0 : goto done;
748 : }
749 :
750 1 : err = sss_idmap_sid_to_unix(ctx, sid, id);
751 :
752 : done:
753 1 : ctx->free_func(sid, ctx->alloc_pvt);
754 :
755 1 : return err;
756 : }
757 :
758 1 : enum idmap_error_code sss_idmap_bin_sid_to_unix(struct sss_idmap_ctx *ctx,
759 : uint8_t *bin_sid,
760 : size_t length,
761 : uint32_t *id)
762 : {
763 : enum idmap_error_code err;
764 : char *sid;
765 :
766 1 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
767 :
768 1 : err = sss_idmap_bin_sid_to_sid(ctx, bin_sid, length, &sid);
769 1 : if (err != IDMAP_SUCCESS) {
770 0 : goto done;
771 : }
772 :
773 1 : err = sss_idmap_sid_to_unix(ctx, sid, id);
774 :
775 : done:
776 1 : ctx->free_func(sid, ctx->alloc_pvt);
777 :
778 1 : return err;
779 : }
780 :
781 0 : enum idmap_error_code sss_idmap_smb_sid_to_unix(struct sss_idmap_ctx *ctx,
782 : struct dom_sid *smb_sid,
783 : uint32_t *id)
784 : {
785 : enum idmap_error_code err;
786 : char *sid;
787 :
788 0 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
789 :
790 0 : err = sss_idmap_smb_sid_to_sid(ctx, smb_sid, &sid);
791 0 : if (err != IDMAP_SUCCESS) {
792 0 : goto done;
793 : }
794 :
795 0 : err = sss_idmap_sid_to_unix(ctx, sid, id);
796 :
797 : done:
798 0 : ctx->free_func(sid, ctx->alloc_pvt);
799 :
800 0 : return err;
801 : }
802 :
803 0 : enum idmap_error_code sss_idmap_check_dom_sid_to_unix(struct sss_idmap_ctx *ctx,
804 : struct sss_dom_sid *dom_sid,
805 : uint32_t id)
806 : {
807 : enum idmap_error_code err;
808 : char *sid;
809 :
810 0 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
811 :
812 0 : err = sss_idmap_dom_sid_to_sid(ctx, dom_sid, &sid);
813 0 : if (err != IDMAP_SUCCESS) {
814 0 : goto done;
815 : }
816 :
817 0 : err = sss_idmap_check_sid_unix(ctx, sid, id);
818 :
819 : done:
820 0 : ctx->free_func(sid, ctx->alloc_pvt);
821 :
822 0 : return err;
823 : }
824 :
825 0 : enum idmap_error_code sss_idmap_check_bin_sid_unix(struct sss_idmap_ctx *ctx,
826 : uint8_t *bin_sid,
827 : size_t length,
828 : uint32_t id)
829 : {
830 : enum idmap_error_code err;
831 : char *sid;
832 :
833 0 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
834 :
835 0 : err = sss_idmap_bin_sid_to_sid(ctx, bin_sid, length, &sid);
836 0 : if (err != IDMAP_SUCCESS) {
837 0 : goto done;
838 : }
839 :
840 0 : err = sss_idmap_check_sid_unix(ctx, sid, id);
841 :
842 : done:
843 0 : ctx->free_func(sid, ctx->alloc_pvt);
844 :
845 0 : return err;
846 : }
847 :
848 0 : enum idmap_error_code sss_idmap_check_smb_sid_unix(struct sss_idmap_ctx *ctx,
849 : struct dom_sid *smb_sid,
850 : uint32_t id)
851 : {
852 : enum idmap_error_code err;
853 : char *sid;
854 :
855 0 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
856 :
857 0 : err = sss_idmap_smb_sid_to_sid(ctx, smb_sid, &sid);
858 0 : if (err != IDMAP_SUCCESS) {
859 0 : goto done;
860 : }
861 :
862 0 : err = sss_idmap_check_sid_unix(ctx, sid, id);
863 :
864 : done:
865 0 : ctx->free_func(sid, ctx->alloc_pvt);
866 :
867 0 : return err;
868 : }
869 2 : enum idmap_error_code sss_idmap_unix_to_dom_sid(struct sss_idmap_ctx *ctx,
870 : uint32_t id,
871 : struct sss_dom_sid **_dom_sid)
872 : {
873 : enum idmap_error_code err;
874 2 : char *sid = NULL;
875 2 : struct sss_dom_sid *dom_sid = NULL;
876 :
877 2 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
878 :
879 2 : err = sss_idmap_unix_to_sid(ctx, id, &sid);
880 2 : if (err != IDMAP_SUCCESS) {
881 1 : goto done;
882 : }
883 :
884 1 : err = sss_idmap_sid_to_dom_sid(ctx, sid, &dom_sid);
885 1 : if (err != IDMAP_SUCCESS) {
886 0 : goto done;
887 : }
888 :
889 1 : *_dom_sid = dom_sid;
890 1 : err = IDMAP_SUCCESS;
891 :
892 : done:
893 2 : ctx->free_func(sid, ctx->alloc_pvt);
894 2 : if (err != IDMAP_SUCCESS) {
895 1 : ctx->free_func(dom_sid, ctx->alloc_pvt);
896 : }
897 :
898 2 : return err;
899 : }
900 :
901 2 : enum idmap_error_code sss_idmap_unix_to_bin_sid(struct sss_idmap_ctx *ctx,
902 : uint32_t id,
903 : uint8_t **_bin_sid,
904 : size_t *_length)
905 : {
906 : enum idmap_error_code err;
907 2 : char *sid = NULL;
908 2 : uint8_t *bin_sid = NULL;
909 : size_t length;
910 :
911 2 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
912 :
913 2 : err = sss_idmap_unix_to_sid(ctx, id, &sid);
914 2 : if (err != IDMAP_SUCCESS) {
915 1 : goto done;
916 : }
917 :
918 1 : err = sss_idmap_sid_to_bin_sid(ctx, sid, &bin_sid, &length);
919 1 : if (err != IDMAP_SUCCESS) {
920 0 : goto done;
921 : }
922 :
923 1 : *_bin_sid = bin_sid;
924 1 : *_length = length;
925 1 : err = IDMAP_SUCCESS;
926 :
927 : done:
928 2 : ctx->free_func(sid, ctx->alloc_pvt);
929 2 : if (err != IDMAP_SUCCESS) {
930 1 : ctx->free_func(bin_sid, ctx->alloc_pvt);
931 : }
932 :
933 2 : return err;
934 :
935 : }
936 :
937 : enum idmap_error_code
938 7 : sss_idmap_ctx_set_autorid(struct sss_idmap_ctx *ctx, bool use_autorid)
939 : {
940 7 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
941 7 : ctx->idmap_opts.autorid_mode = use_autorid;
942 7 : return IDMAP_SUCCESS;
943 : }
944 :
945 : enum idmap_error_code
946 7 : sss_idmap_ctx_set_lower(struct sss_idmap_ctx *ctx, id_t lower)
947 : {
948 7 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
949 7 : ctx->idmap_opts.idmap_lower = lower;
950 7 : return IDMAP_SUCCESS;
951 : }
952 :
953 : enum idmap_error_code
954 7 : sss_idmap_ctx_set_upper(struct sss_idmap_ctx *ctx, id_t upper)
955 : {
956 7 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
957 7 : ctx->idmap_opts.idmap_upper = upper;
958 7 : return IDMAP_SUCCESS;
959 : }
960 :
961 : enum idmap_error_code
962 7 : sss_idmap_ctx_set_rangesize(struct sss_idmap_ctx *ctx, id_t rangesize)
963 : {
964 7 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
965 7 : ctx->idmap_opts.rangesize = rangesize;
966 7 : return IDMAP_SUCCESS;
967 : }
968 :
969 : enum idmap_error_code
970 0 : sss_idmap_ctx_get_autorid(struct sss_idmap_ctx *ctx, bool *_autorid)
971 : {
972 0 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
973 0 : *_autorid = ctx->idmap_opts.autorid_mode;
974 0 : return IDMAP_SUCCESS;
975 : }
976 :
977 : enum idmap_error_code
978 0 : sss_idmap_ctx_get_lower(struct sss_idmap_ctx *ctx, id_t *_lower)
979 : {
980 0 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
981 0 : *_lower = ctx->idmap_opts.idmap_lower;
982 0 : return IDMAP_SUCCESS;
983 : }
984 :
985 : enum idmap_error_code
986 0 : sss_idmap_ctx_get_upper(struct sss_idmap_ctx *ctx, id_t *_upper)
987 : {
988 0 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
989 0 : *_upper = ctx->idmap_opts.idmap_upper;
990 0 : return IDMAP_SUCCESS;
991 : }
992 :
993 : enum idmap_error_code
994 0 : sss_idmap_ctx_get_rangesize(struct sss_idmap_ctx *ctx, id_t *_rangesize)
995 : {
996 0 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
997 0 : *_rangesize = ctx->idmap_opts.rangesize;
998 0 : return IDMAP_SUCCESS;
999 : }
1000 :
1001 : enum idmap_error_code
1002 22 : sss_idmap_domain_has_algorithmic_mapping(struct sss_idmap_ctx *ctx,
1003 : const char *dom_sid,
1004 : bool *has_algorithmic_mapping)
1005 : {
1006 : struct idmap_domain_info *idmap_domain_info;
1007 : size_t len;
1008 : size_t dom_sid_len;
1009 :
1010 22 : if (dom_sid == NULL) {
1011 17 : return IDMAP_SID_INVALID;
1012 : }
1013 :
1014 5 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
1015 :
1016 4 : if (ctx->idmap_domain_info == NULL) {
1017 0 : return IDMAP_NO_DOMAIN;
1018 : }
1019 :
1020 4 : idmap_domain_info = ctx->idmap_domain_info;
1021 :
1022 14 : while (idmap_domain_info != NULL) {
1023 9 : if (idmap_domain_info->sid != NULL) {
1024 9 : len = strlen(idmap_domain_info->sid);
1025 9 : dom_sid_len = strlen(dom_sid);
1026 9 : if (((dom_sid_len > len && dom_sid[len] == '-')
1027 9 : || dom_sid_len == len)
1028 5 : && strncmp(dom_sid, idmap_domain_info->sid, len) == 0) {
1029 :
1030 3 : *has_algorithmic_mapping = !idmap_domain_info->external_mapping;
1031 3 : return IDMAP_SUCCESS;
1032 :
1033 : }
1034 : }
1035 :
1036 6 : idmap_domain_info = idmap_domain_info->next;
1037 : }
1038 :
1039 1 : return IDMAP_SID_UNKNOWN;
1040 : }
1041 :
1042 : enum idmap_error_code
1043 21 : sss_idmap_domain_by_name_has_algorithmic_mapping(struct sss_idmap_ctx *ctx,
1044 : const char *dom_name,
1045 : bool *has_algorithmic_mapping)
1046 : {
1047 : struct idmap_domain_info *idmap_domain_info;
1048 :
1049 21 : if (dom_name == NULL) {
1050 2 : return IDMAP_ERROR;
1051 : }
1052 :
1053 19 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
1054 :
1055 18 : if (ctx->idmap_domain_info == NULL) {
1056 0 : return IDMAP_NO_DOMAIN;
1057 : }
1058 :
1059 18 : idmap_domain_info = ctx->idmap_domain_info;
1060 :
1061 42 : while (idmap_domain_info != NULL) {
1062 23 : if (idmap_domain_info->name != NULL
1063 23 : && strcmp(dom_name, idmap_domain_info->name) == 0) {
1064 :
1065 17 : *has_algorithmic_mapping = !idmap_domain_info->external_mapping;
1066 17 : return IDMAP_SUCCESS;
1067 : }
1068 :
1069 6 : idmap_domain_info = idmap_domain_info->next;
1070 : }
1071 :
1072 1 : return IDMAP_NAME_UNKNOWN;
1073 : }
|