Line data Source code
1 : /*
2 : SSSD
3 :
4 : ID-mapping library - conversion utilities
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 : #include <ctype.h>
29 :
30 : #include "lib/idmap/sss_idmap.h"
31 : #include "lib/idmap/sss_idmap_private.h"
32 : #include "util/util.h"
33 : #include "util/sss_endian.h"
34 :
35 : #define SID_ID_AUTHS 6
36 : #define SID_SUB_AUTHS 15
37 : struct sss_dom_sid {
38 : uint8_t sid_rev_num;
39 : int8_t num_auths; /* [range(0,15)] */
40 : uint8_t id_auth[SID_ID_AUTHS]; /* highest order byte has index 0 */
41 : uint32_t sub_auths[SID_SUB_AUTHS]; /* host byte-order */
42 : };
43 :
44 5 : enum idmap_error_code sss_idmap_bin_sid_to_dom_sid(struct sss_idmap_ctx *ctx,
45 : const uint8_t *bin_sid,
46 : size_t length,
47 : struct sss_dom_sid **_dom_sid)
48 : {
49 : enum idmap_error_code err;
50 : struct sss_dom_sid *dom_sid;
51 5 : size_t i = 0;
52 5 : size_t p = 0;
53 : uint32_t val;
54 :
55 5 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
56 :
57 5 : if (length > sizeof(struct sss_dom_sid)) return IDMAP_SID_INVALID;
58 :
59 5 : dom_sid = ctx->alloc_func(sizeof(struct sss_dom_sid), ctx->alloc_pvt);
60 5 : if (dom_sid == NULL) {
61 0 : return IDMAP_OUT_OF_MEMORY;
62 : }
63 5 : memset(dom_sid, 0, sizeof(struct sss_dom_sid));
64 :
65 : /* Safely copy in the SID revision number */
66 5 : dom_sid->sid_rev_num = (uint8_t) *(bin_sid + p);
67 5 : p++;
68 :
69 : /* Safely copy in the number of sub auth values */
70 5 : dom_sid->num_auths = (uint8_t) *(bin_sid + p);
71 5 : p++;
72 :
73 : /* Make sure we aren't being told to read more bin_sid
74 : * than can fit in the structure
75 : */
76 5 : if (dom_sid->num_auths > SID_SUB_AUTHS) {
77 0 : err = IDMAP_SID_INVALID;
78 0 : goto done;
79 : }
80 :
81 : /* Safely copy in the id_auth values */
82 35 : for (i = 0; i < SID_ID_AUTHS; i++) {
83 30 : dom_sid->id_auth[i] = (uint8_t) *(bin_sid + p);
84 30 : p++;
85 : }
86 :
87 : /* Safely copy in the sub_auths values */
88 30 : for (i = 0; i < dom_sid->num_auths; i++) {
89 : /* SID sub auth values in Active Directory are stored little-endian,
90 : * we store them in host order */
91 25 : SAFEALIGN_COPY_UINT32(&val, bin_sid + p, &p);
92 25 : dom_sid->sub_auths[i] = le32toh(val);
93 : }
94 :
95 5 : *_dom_sid = dom_sid;
96 5 : err = IDMAP_SUCCESS;
97 :
98 : done:
99 5 : if (err != IDMAP_SUCCESS) {
100 0 : ctx->free_func(dom_sid, ctx->alloc_pvt);
101 : }
102 5 : return err;
103 : }
104 :
105 13 : enum idmap_error_code sss_idmap_dom_sid_to_bin_sid(struct sss_idmap_ctx *ctx,
106 : struct sss_dom_sid *dom_sid,
107 : uint8_t **_bin_sid,
108 : size_t *_length)
109 : {
110 : enum idmap_error_code err;
111 : uint8_t *bin_sid;
112 : size_t length;
113 13 : size_t i = 0;
114 13 : size_t p = 0;
115 : uint32_t val;
116 :
117 13 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
118 :
119 13 : if (dom_sid->num_auths > SID_SUB_AUTHS) {
120 0 : return IDMAP_SID_INVALID;
121 : }
122 :
123 13 : length = 2 + SID_ID_AUTHS + dom_sid->num_auths * 4;
124 :
125 13 : bin_sid = ctx->alloc_func(length, ctx->alloc_pvt);
126 13 : if (bin_sid == NULL) {
127 0 : return IDMAP_OUT_OF_MEMORY;
128 : }
129 :
130 13 : bin_sid[p] = dom_sid->sid_rev_num;
131 13 : p++;
132 :
133 13 : bin_sid[p] = dom_sid->num_auths;
134 13 : p++;
135 :
136 91 : for (i = 0; i < SID_ID_AUTHS; i++) {
137 78 : bin_sid[p] = dom_sid->id_auth[i];
138 78 : p++;
139 : }
140 :
141 65 : for (i = 0; i < dom_sid->num_auths; i++) {
142 52 : if (p + sizeof(uint32_t) > length) {
143 0 : err = IDMAP_SID_INVALID;
144 0 : goto done;
145 : }
146 52 : val = htole32(dom_sid->sub_auths[i]);
147 52 : SAFEALIGN_COPY_UINT32(bin_sid + p, &val, &p);
148 : }
149 :
150 13 : *_bin_sid = bin_sid;
151 13 : *_length = length;
152 :
153 13 : err = IDMAP_SUCCESS;
154 : done:
155 13 : if (err != IDMAP_SUCCESS) {
156 0 : ctx->free_func(bin_sid, ctx->alloc_pvt);
157 : }
158 13 : return err;
159 : }
160 :
161 8 : enum idmap_error_code sss_idmap_dom_sid_to_sid(struct sss_idmap_ctx *ctx,
162 : struct sss_dom_sid *dom_sid,
163 : char **_sid)
164 : {
165 : enum idmap_error_code err;
166 : char *sid_buf;
167 : size_t sid_buf_len;
168 : char *p;
169 : int nc;
170 : int8_t i;
171 8 : uint32_t id_auth_val = 0;
172 :
173 8 : if (dom_sid->num_auths > SID_SUB_AUTHS) {
174 0 : return IDMAP_SID_INVALID;
175 : }
176 :
177 8 : sid_buf_len = 25 + dom_sid->num_auths * 11;
178 8 : sid_buf = ctx->alloc_func(sid_buf_len, ctx->alloc_pvt);
179 8 : if (sid_buf == NULL) {
180 0 : return IDMAP_OUT_OF_MEMORY;
181 : }
182 8 : memset(sid_buf, 0, sid_buf_len);
183 :
184 : /* Only 32bits are used for the string representation */
185 24 : id_auth_val = (dom_sid->id_auth[2] << 24) +
186 16 : (dom_sid->id_auth[3] << 16) +
187 16 : (dom_sid->id_auth[4] << 8) +
188 8 : (dom_sid->id_auth[5]);
189 :
190 8 : nc = snprintf(sid_buf, sid_buf_len, "S-%u-%lu", dom_sid->sid_rev_num,
191 : (unsigned long) id_auth_val);
192 8 : if (nc < 0 || nc >= sid_buf_len) {
193 0 : err = IDMAP_SID_INVALID;
194 0 : goto done;
195 : }
196 :
197 :
198 : /* Loop through the sub-auths, if any, prepending a hyphen
199 : * for each one.
200 : */
201 8 : p = sid_buf;
202 48 : for (i = 0; i < dom_sid->num_auths ; i++) {
203 40 : p += nc;
204 40 : sid_buf_len -= nc;
205 :
206 40 : nc = snprintf(p, sid_buf_len, "-%lu",
207 40 : (unsigned long) dom_sid->sub_auths[i]);
208 40 : if (nc < 0 || nc >= sid_buf_len) {
209 0 : err = IDMAP_SID_INVALID;
210 0 : goto done;
211 : }
212 : }
213 :
214 8 : *_sid = sid_buf;
215 8 : err = IDMAP_SUCCESS;
216 :
217 : done:
218 8 : if (err != IDMAP_SUCCESS) {
219 0 : ctx->free_func(sid_buf, ctx->alloc_pvt);
220 : }
221 :
222 8 : return err;
223 : }
224 :
225 22 : enum idmap_error_code sss_idmap_sid_to_dom_sid(struct sss_idmap_ctx *ctx,
226 : const char *sid,
227 : struct sss_dom_sid **_dom_sid)
228 : {
229 : enum idmap_error_code err;
230 : unsigned long ul;
231 : char *r;
232 : char *end;
233 : struct sss_dom_sid *dom_sid;
234 :
235 22 : CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID);
236 :
237 22 : if (sid == NULL || (sid[0] != 'S' && sid[0] != 's') || sid[1] != '-') {
238 0 : return IDMAP_SID_INVALID;
239 : }
240 :
241 22 : dom_sid = ctx->alloc_func(sizeof(struct sss_dom_sid), ctx->alloc_pvt);
242 22 : if (dom_sid == NULL) {
243 0 : return IDMAP_OUT_OF_MEMORY;
244 : }
245 22 : memset(dom_sid, 0, sizeof(struct sss_dom_sid));
246 :
247 :
248 22 : if (!isdigit(sid[2])) {
249 0 : err = IDMAP_SID_INVALID;
250 0 : goto done;
251 : }
252 22 : errno = 0;
253 22 : ul = strtoul(sid + 2, &r, 10);
254 22 : if (errno != 0 || r == NULL || *r != '-' || ul > UINT8_MAX) {
255 0 : err = IDMAP_SID_INVALID;
256 0 : goto done;
257 : }
258 22 : dom_sid->sid_rev_num = (uint8_t) ul;
259 22 : r++;
260 :
261 22 : if (!isdigit(*r)) {
262 0 : err = IDMAP_SID_INVALID;
263 0 : goto done;
264 : }
265 22 : errno = 0;
266 22 : ul = strtoul(r, &r, 10);
267 22 : if (errno != 0 || r == NULL || ul > UINT32_MAX) {
268 0 : err = IDMAP_SID_INVALID;
269 0 : goto done;
270 : }
271 :
272 : /* id_auth in the string should always be <2^32 in decimal */
273 : /* store values in the same order as the binary representation */
274 22 : dom_sid->id_auth[0] = 0;
275 22 : dom_sid->id_auth[1] = 0;
276 22 : dom_sid->id_auth[2] = (ul & 0xff000000) >> 24;
277 22 : dom_sid->id_auth[3] = (ul & 0x00ff0000) >> 16;
278 22 : dom_sid->id_auth[4] = (ul & 0x0000ff00) >> 8;
279 22 : dom_sid->id_auth[5] = (ul & 0x000000ff);
280 :
281 22 : if (*r == '\0') {
282 : /* no sub auths given */
283 0 : err = IDMAP_SUCCESS;
284 0 : goto done;
285 : }
286 :
287 22 : if (*r != '-') {
288 0 : err = IDMAP_SID_INVALID;
289 0 : goto done;
290 : }
291 :
292 : do {
293 93 : if (dom_sid->num_auths >= SID_SUB_AUTHS) {
294 0 : err = IDMAP_SID_INVALID;
295 0 : goto done;
296 : }
297 :
298 93 : r++;
299 93 : if (!isdigit(*r)) {
300 0 : err = IDMAP_SID_INVALID;
301 0 : goto done;
302 : }
303 :
304 93 : errno = 0;
305 93 : ul = strtoul(r, &end, 10);
306 185 : if (errno != 0 || ul > UINT32_MAX || end == NULL ||
307 163 : (*end != '\0' && *end != '-')) {
308 1 : err = IDMAP_SID_INVALID;
309 1 : goto done;
310 : }
311 :
312 92 : dom_sid->sub_auths[dom_sid->num_auths++] = ul;
313 :
314 92 : r = end;
315 92 : } while (*r != '\0');
316 :
317 21 : err = IDMAP_SUCCESS;
318 :
319 : done:
320 22 : if (err != IDMAP_SUCCESS) {
321 1 : ctx->free_func(dom_sid, ctx->alloc_pvt);
322 : } else {
323 21 : *_dom_sid = dom_sid;
324 : }
325 :
326 22 : return err;
327 : }
328 :
329 11 : enum idmap_error_code sss_idmap_sid_to_bin_sid(struct sss_idmap_ctx *ctx,
330 : const char *sid,
331 : uint8_t **_bin_sid,
332 : size_t *_length)
333 : {
334 : enum idmap_error_code err;
335 11 : struct sss_dom_sid *dom_sid = NULL;
336 : size_t length;
337 11 : uint8_t *bin_sid = NULL;
338 :
339 11 : err = sss_idmap_sid_to_dom_sid(ctx, sid, &dom_sid);
340 11 : if (err != IDMAP_SUCCESS) {
341 0 : goto done;
342 : }
343 :
344 11 : err = sss_idmap_dom_sid_to_bin_sid(ctx, dom_sid, &bin_sid, &length);
345 11 : if (err != IDMAP_SUCCESS) {
346 0 : goto done;
347 : }
348 :
349 11 : *_length = length;
350 11 : *_bin_sid = bin_sid;
351 11 : err = IDMAP_SUCCESS;
352 :
353 : done:
354 11 : ctx->free_func(dom_sid, ctx->alloc_pvt);
355 11 : if (err != IDMAP_SUCCESS) {
356 0 : ctx->free_func(bin_sid, ctx->alloc_pvt);
357 : }
358 :
359 11 : return err;
360 : }
361 :
362 3 : enum idmap_error_code sss_idmap_bin_sid_to_sid(struct sss_idmap_ctx *ctx,
363 : const uint8_t *bin_sid,
364 : size_t length,
365 : char **_sid)
366 : {
367 : enum idmap_error_code err;
368 3 : struct sss_dom_sid *dom_sid = NULL;
369 3 : char *sid = NULL;
370 :
371 3 : err = sss_idmap_bin_sid_to_dom_sid(ctx, bin_sid, length, &dom_sid);
372 3 : if (err != IDMAP_SUCCESS) {
373 0 : goto done;
374 : }
375 :
376 3 : err = sss_idmap_dom_sid_to_sid(ctx, dom_sid, &sid);
377 3 : if (err != IDMAP_SUCCESS) {
378 0 : goto done;
379 : }
380 :
381 3 : *_sid = sid;
382 3 : err = IDMAP_SUCCESS;
383 :
384 : done:
385 3 : ctx->free_func(dom_sid, ctx->alloc_pvt);
386 3 : if (err != IDMAP_SUCCESS) {
387 0 : ctx->free_func(sid, ctx->alloc_pvt);
388 : }
389 :
390 3 : return err;
391 : }
392 :
393 6 : enum idmap_error_code sss_idmap_sid_to_smb_sid(struct sss_idmap_ctx *ctx,
394 : const char *sid,
395 : struct dom_sid **_smb_sid)
396 : {
397 : enum idmap_error_code err;
398 6 : struct sss_dom_sid *dom_sid = NULL;
399 6 : struct dom_sid *smb_sid = NULL;
400 :
401 6 : err = sss_idmap_sid_to_dom_sid(ctx, sid, &dom_sid);
402 6 : if (err != IDMAP_SUCCESS) {
403 0 : goto done;
404 : }
405 :
406 6 : err = sss_idmap_dom_sid_to_smb_sid(ctx, dom_sid, &smb_sid);
407 6 : if (err != IDMAP_SUCCESS) {
408 0 : goto done;
409 : }
410 :
411 6 : *_smb_sid = smb_sid;
412 6 : err = IDMAP_SUCCESS;
413 :
414 : done:
415 6 : ctx->free_func(dom_sid, ctx->alloc_pvt);
416 6 : if (err != IDMAP_SUCCESS) {
417 0 : ctx->free_func(smb_sid, ctx->alloc_pvt);
418 : }
419 :
420 6 : return err;
421 : }
422 :
423 1 : enum idmap_error_code sss_idmap_smb_sid_to_sid(struct sss_idmap_ctx *ctx,
424 : struct dom_sid *smb_sid,
425 : char **_sid)
426 : {
427 : enum idmap_error_code err;
428 1 : struct sss_dom_sid *dom_sid = NULL;
429 1 : char *sid = NULL;
430 :
431 1 : err = sss_idmap_smb_sid_to_dom_sid(ctx, smb_sid, &dom_sid);
432 1 : if (err != IDMAP_SUCCESS) {
433 0 : goto done;
434 : }
435 :
436 1 : err = sss_idmap_dom_sid_to_sid(ctx, dom_sid, &sid);
437 1 : if (err != IDMAP_SUCCESS) {
438 0 : goto done;
439 : }
440 :
441 1 : *_sid = sid;
442 1 : err = IDMAP_SUCCESS;
443 :
444 : done:
445 1 : ctx->free_func(dom_sid, ctx->alloc_pvt);
446 1 : if (err != IDMAP_SUCCESS) {
447 0 : ctx->free_func(sid, ctx->alloc_pvt);
448 : }
449 :
450 1 : return err;
451 : }
452 :
453 8 : enum idmap_error_code sss_idmap_dom_sid_to_smb_sid(struct sss_idmap_ctx *ctx,
454 : struct sss_dom_sid *dom_sid,
455 : struct dom_sid **_smb_sid)
456 : {
457 : struct dom_sid *smb_sid;
458 : size_t c;
459 :
460 8 : smb_sid = ctx->alloc_func(sizeof(struct dom_sid), ctx->alloc_pvt);
461 8 : if (smb_sid == NULL) {
462 0 : return IDMAP_OUT_OF_MEMORY;
463 : }
464 8 : memset(smb_sid, 0, sizeof(struct dom_sid));
465 :
466 8 : smb_sid->sid_rev_num = dom_sid->sid_rev_num;
467 8 : smb_sid->num_auths = dom_sid->num_auths;
468 56 : for (c = 0; c < SID_ID_AUTHS; c++) {
469 48 : smb_sid->id_auth[c] = dom_sid->id_auth[c];
470 : }
471 128 : for (c = 0; c < SID_SUB_AUTHS; c++) {
472 120 : smb_sid->sub_auths[c] = dom_sid->sub_auths[c];
473 : }
474 :
475 8 : *_smb_sid = smb_sid;
476 :
477 8 : return IDMAP_SUCCESS;
478 : }
479 :
480 3 : enum idmap_error_code sss_idmap_smb_sid_to_dom_sid(struct sss_idmap_ctx *ctx,
481 : struct dom_sid *smb_sid,
482 : struct sss_dom_sid **_dom_sid)
483 : {
484 : struct sss_dom_sid *dom_sid;
485 : size_t c;
486 :
487 3 : dom_sid = ctx->alloc_func(sizeof(struct sss_dom_sid), ctx->alloc_pvt);
488 3 : if (dom_sid == NULL) {
489 0 : return IDMAP_OUT_OF_MEMORY;
490 : }
491 3 : memset(dom_sid, 0, sizeof(struct sss_dom_sid));
492 :
493 3 : dom_sid->sid_rev_num = smb_sid->sid_rev_num;
494 3 : dom_sid->num_auths = smb_sid->num_auths;
495 21 : for (c = 0; c < SID_ID_AUTHS; c++) {
496 18 : dom_sid->id_auth[c] = smb_sid->id_auth[c];
497 : }
498 48 : for (c = 0; c < SID_SUB_AUTHS; c++) {
499 45 : dom_sid->sub_auths[c] = smb_sid->sub_auths[c];
500 : }
501 :
502 3 : *_dom_sid = dom_sid;
503 :
504 3 : return IDMAP_SUCCESS;
505 : }
506 :
507 1 : enum idmap_error_code sss_idmap_bin_sid_to_smb_sid(struct sss_idmap_ctx *ctx,
508 : const uint8_t *bin_sid,
509 : size_t length,
510 : struct dom_sid **_smb_sid)
511 : {
512 : enum idmap_error_code err;
513 1 : struct sss_dom_sid *dom_sid = NULL;
514 1 : struct dom_sid *smb_sid = NULL;
515 :
516 1 : err = sss_idmap_bin_sid_to_dom_sid(ctx, bin_sid, length, &dom_sid);
517 1 : if (err != IDMAP_SUCCESS) {
518 0 : goto done;
519 : }
520 :
521 1 : err = sss_idmap_dom_sid_to_smb_sid(ctx, dom_sid, &smb_sid);
522 1 : if (err != IDMAP_SUCCESS) {
523 0 : goto done;
524 : }
525 :
526 1 : *_smb_sid = smb_sid;
527 1 : err = IDMAP_SUCCESS;
528 :
529 : done:
530 1 : ctx->free_func(dom_sid, ctx->alloc_pvt);
531 1 : if (err != IDMAP_SUCCESS) {
532 0 : ctx->free_func(smb_sid, ctx->alloc_pvt);
533 : }
534 :
535 1 : return err;
536 : }
537 :
538 1 : enum idmap_error_code sss_idmap_smb_sid_to_bin_sid(struct sss_idmap_ctx *ctx,
539 : struct dom_sid *smb_sid,
540 : uint8_t **_bin_sid,
541 : size_t *_length)
542 : {
543 : enum idmap_error_code err;
544 1 : struct sss_dom_sid *dom_sid = NULL;
545 1 : uint8_t *bin_sid = NULL;
546 : size_t length;
547 :
548 1 : err = sss_idmap_smb_sid_to_dom_sid(ctx, smb_sid, &dom_sid);
549 1 : if (err != IDMAP_SUCCESS) {
550 0 : goto done;
551 : }
552 :
553 1 : err = sss_idmap_dom_sid_to_bin_sid(ctx, dom_sid, &bin_sid, &length);
554 1 : if (err != IDMAP_SUCCESS) {
555 0 : goto done;
556 : }
557 :
558 1 : *_bin_sid = bin_sid;
559 1 : *_length = length;
560 1 : err = IDMAP_SUCCESS;
561 :
562 : done:
563 1 : ctx->free_func(dom_sid, ctx->alloc_pvt);
564 1 : if (err != IDMAP_SUCCESS) {
565 0 : ctx->free_func(bin_sid, ctx->alloc_pvt);
566 : }
567 :
568 1 : return err;
569 : }
|