Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Samba utility functions
4 :
5 : Copyright (C) Stefan (metze) Metzmacher 2002-2004
6 : Copyright (C) Andrew Tridgell 1992-2004
7 : Copyright (C) Jeremy Allison 1999
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 : #include "replace.h"
24 : #include "lib/util/data_blob.h"
25 : #include "system/locale.h"
26 : #include "lib/util/debug.h"
27 : #include "lib/util/util.h"
28 : #include "librpc/gen_ndr/security.h"
29 : #include "dom_sid.h"
30 : #include "lib/util/smb_strtox.h"
31 :
32 : /*****************************************************************
33 : Compare the auth portion of two sids.
34 : *****************************************************************/
35 :
36 144126693 : int dom_sid_compare_auth(const struct dom_sid *sid1,
37 : const struct dom_sid *sid2)
38 : {
39 7858378 : int i;
40 :
41 144126693 : if (sid1 == sid2)
42 0 : return 0;
43 144126693 : if (!sid1)
44 0 : return -1;
45 144126693 : if (!sid2)
46 0 : return 1;
47 :
48 144126693 : if (sid1->sid_rev_num != sid2->sid_rev_num)
49 1003 : return sid1->sid_rev_num - sid2->sid_rev_num;
50 :
51 1006972350 : for (i = 0; i < 6; i++)
52 864754140 : if (sid1->id_auth[i] != sid2->id_auth[i])
53 1907480 : return sid1->id_auth[i] - sid2->id_auth[i];
54 :
55 134481793 : return 0;
56 : }
57 :
58 : /*****************************************************************
59 : Compare two sids.
60 : *****************************************************************/
61 :
62 1354806193 : int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *sid2)
63 : {
64 66531781 : int i;
65 :
66 1354806193 : if (sid1 == sid2)
67 51437 : return 0;
68 1354752408 : if (!sid1)
69 12 : return -1;
70 1354752396 : if (!sid2)
71 5708238 : return 1;
72 :
73 : /* Compare most likely different rids, first: i.e start at end */
74 1348995907 : if (sid1->num_auths != sid2->num_auths)
75 961835874 : return sid1->num_auths - sid2->num_auths;
76 :
77 600751291 : for (i = sid1->num_auths-1; i >= 0; --i) {
78 459011172 : if (sid1->sub_auths[i] < sid2->sub_auths[i]) {
79 170898344 : return -1;
80 : }
81 279690748 : if (sid1->sub_auths[i] > sid2->sub_auths[i]) {
82 64401913 : return 1;
83 : }
84 : }
85 :
86 141740119 : return dom_sid_compare_auth(sid1, sid2);
87 : }
88 :
89 : /*****************************************************************
90 : Compare two sids.
91 : *****************************************************************/
92 :
93 1354016209 : bool dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2)
94 : {
95 1354016209 : return dom_sid_compare(sid1, sid2) == 0;
96 : }
97 :
98 : /*****************************************************************
99 : Add a rid to the end of a sid
100 : *****************************************************************/
101 :
102 89513162 : bool sid_append_rid(struct dom_sid *sid, uint32_t rid)
103 : {
104 89513162 : if (sid->num_auths < ARRAY_SIZE(sid->sub_auths)) {
105 89513161 : sid->sub_auths[sid->num_auths++] = rid;
106 89513161 : return true;
107 : }
108 0 : return false;
109 : }
110 :
111 : /*
112 : See if 2 SIDs are in the same domain
113 : this just compares the leading sub-auths
114 : */
115 2118071 : int dom_sid_compare_domain(const struct dom_sid *sid1,
116 : const struct dom_sid *sid2)
117 : {
118 7524 : int n, i;
119 :
120 2118071 : n = MIN(sid1->num_auths, sid2->num_auths);
121 :
122 2959089 : for (i = n-1; i >= 0; --i) {
123 2607990 : if (sid1->sub_auths[i] < sid2->sub_auths[i]) {
124 738934 : return -1;
125 : }
126 1865262 : if (sid1->sub_auths[i] > sid2->sub_auths[i]) {
127 1020833 : return 1;
128 : }
129 : }
130 :
131 351099 : return dom_sid_compare_auth(sid1, sid2);
132 : }
133 :
134 : /*****************************************************************
135 : Convert a string to a SID. Returns True on success, False on fail.
136 : Return the first character not parsed in endp.
137 : *****************************************************************/
138 : #define AUTHORITY_MASK (~(0xffffffffffffULL))
139 :
140 21483563 : bool dom_sid_parse_endp(const char *sidstr,struct dom_sid *sidout,
141 : const char **endp)
142 : {
143 716360 : const char *p;
144 21483563 : char *q = NULL;
145 21483563 : char *end = NULL;
146 716360 : uint64_t conv;
147 21483563 : int error = 0;
148 :
149 21483563 : *sidout = (struct dom_sid) {};
150 :
151 21483563 : if ((sidstr[0] != 'S' && sidstr[0] != 's') || sidstr[1] != '-') {
152 9719 : goto format_error;
153 : }
154 :
155 : /* Get the revision number. */
156 21473844 : p = sidstr + 2;
157 :
158 21473844 : if (!isdigit((unsigned char)*p)) {
159 1 : goto format_error;
160 : }
161 :
162 21473843 : conv = smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
163 21473843 : if (error != 0 || (*q != '-') || conv > UINT8_MAX || q - p > 4) {
164 113 : goto format_error;
165 : }
166 21473730 : sidout->sid_rev_num = (uint8_t) conv;
167 21473730 : q++;
168 :
169 21473730 : if (!isdigit((unsigned char)*q)) {
170 0 : goto format_error;
171 : }
172 21473950 : while (q[0] == '0' && isdigit((unsigned char)q[1])) {
173 : /*
174 : * strtoull will think this is octal, which is not how SIDs
175 : * work! So let's walk along until there are no leading zeros
176 : * (or a single zero).
177 : */
178 220 : q++;
179 : }
180 :
181 : /* get identauth */
182 21473730 : conv = smb_strtoull(q, &end, 0, &error, SMB_STR_STANDARD);
183 21473730 : if (conv & AUTHORITY_MASK || error != 0) {
184 22 : goto format_error;
185 : }
186 21473708 : if (conv >= (1ULL << 48) || end - q > 15) {
187 : /*
188 : * This identauth looks like a big number, but resolves to a
189 : * small number after rounding.
190 : */
191 0 : goto format_error;
192 : }
193 :
194 : /* NOTE - the conv value is in big-endian format. */
195 21473708 : sidout->id_auth[0] = (conv & 0xff0000000000ULL) >> 40;
196 21473708 : sidout->id_auth[1] = (conv & 0x00ff00000000ULL) >> 32;
197 21473708 : sidout->id_auth[2] = (conv & 0x0000ff000000ULL) >> 24;
198 21473708 : sidout->id_auth[3] = (conv & 0x000000ff0000ULL) >> 16;
199 21473708 : sidout->id_auth[4] = (conv & 0x00000000ff00ULL) >> 8;
200 21473708 : sidout->id_auth[5] = (conv & 0x0000000000ffULL);
201 :
202 21473708 : sidout->num_auths = 0;
203 21473708 : q = end;
204 21473708 : if (*q != '-') {
205 : /* Just id_auth, no subauths */
206 12473 : goto done;
207 : }
208 :
209 21461235 : q++;
210 :
211 2801344 : while (true) {
212 79619320 : if (!isdigit((unsigned char)*q)) {
213 22 : goto format_error;
214 : }
215 79619513 : while (q[0] == '0' && isdigit((unsigned char)q[1])) {
216 : /*
217 : * strtoull will think this is octal, which is not how
218 : * SIDs work! So let's walk along until there are no
219 : * leading zeros (or a single zero).
220 : */
221 215 : q++;
222 : }
223 79619298 : conv = smb_strtoull(q, &end, 0, &error, SMB_STR_STANDARD);
224 79619298 : if (conv > UINT32_MAX || error != 0 || end - q > 12) {
225 : /*
226 : * This sub-auth is greater than 4294967295,
227 : * and hence invalid. Windows will treat it as
228 : * 4294967295, while we prefer to refuse (old
229 : * versions of Samba will wrap, arriving at
230 : * another number altogether).
231 : */
232 100 : DBG_NOTICE("bad sub-auth in %s\n", sidstr);
233 100 : goto format_error;
234 : }
235 :
236 79619198 : if (!sid_append_rid(sidout, conv)) {
237 1 : DEBUG(3, ("Too many sid auths in %s\n", sidstr));
238 1 : return false;
239 : }
240 :
241 79619197 : q = end;
242 79619197 : if (*q != '-') {
243 20745215 : break;
244 : }
245 58158085 : q += 1;
246 : }
247 21473142 : done:
248 21473585 : if (endp != NULL) {
249 306392 : *endp = q;
250 : }
251 20757245 : return true;
252 :
253 9977 : format_error:
254 9977 : DEBUG(3, ("string_to_sid: SID %s is not in a valid format\n", sidstr));
255 9958 : return false;
256 : }
257 :
258 4625743 : bool string_to_sid(struct dom_sid *sidout, const char *sidstr)
259 : {
260 4625743 : return dom_sid_parse(sidstr, sidout);
261 : }
262 :
263 21177055 : bool dom_sid_parse(const char *sidstr, struct dom_sid *ret)
264 : {
265 21177055 : return dom_sid_parse_endp(sidstr, ret, NULL);
266 : }
267 :
268 : /*
269 : convert a string to a dom_sid, returning a talloc'd dom_sid
270 : */
271 4470986 : struct dom_sid *dom_sid_parse_talloc(TALLOC_CTX *mem_ctx, const char *sidstr)
272 : {
273 356530 : struct dom_sid *ret;
274 4470986 : ret = talloc(mem_ctx, struct dom_sid);
275 4470986 : if (!ret) {
276 0 : return NULL;
277 : }
278 4470986 : if (!dom_sid_parse(sidstr, ret)) {
279 4 : talloc_free(ret);
280 4 : return NULL;
281 : }
282 :
283 4114452 : return ret;
284 : }
285 :
286 : /*
287 : convert a string to a dom_sid, returning a talloc'd dom_sid
288 : */
289 6 : struct dom_sid *dom_sid_parse_length(TALLOC_CTX *mem_ctx, const DATA_BLOB *sid)
290 6 : {
291 6 : char p[sid->length+1];
292 6 : memcpy(p, sid->data, sid->length);
293 6 : p[sid->length] = '\0';
294 6 : return dom_sid_parse_talloc(mem_ctx, p);
295 : }
296 :
297 : /*
298 : copy a dom_sid structure
299 : */
300 13451519 : struct dom_sid *dom_sid_dup(TALLOC_CTX *mem_ctx, const struct dom_sid *dom_sid)
301 : {
302 988279 : struct dom_sid *ret;
303 :
304 13451519 : if (!dom_sid) {
305 0 : return NULL;
306 : }
307 :
308 13451519 : ret = talloc(mem_ctx, struct dom_sid);
309 13451519 : if (!ret) {
310 0 : return NULL;
311 : }
312 13451519 : sid_copy(ret, dom_sid);
313 :
314 13451519 : return ret;
315 : }
316 :
317 : /*
318 : add a rid to a domain dom_sid to make a full dom_sid. This function
319 : returns a new sid in the supplied memory context
320 : */
321 8070480 : struct dom_sid *dom_sid_add_rid(TALLOC_CTX *mem_ctx,
322 : const struct dom_sid *domain_sid,
323 : uint32_t rid)
324 : {
325 758302 : struct dom_sid *sid;
326 :
327 8070480 : sid = dom_sid_dup(mem_ctx, domain_sid);
328 8070480 : if (!sid) return NULL;
329 :
330 8070480 : if (!sid_append_rid(sid, rid)) {
331 0 : talloc_free(sid);
332 0 : return NULL;
333 : }
334 :
335 7312178 : return sid;
336 : }
337 :
338 : /*
339 : Split up a SID into its domain and RID part
340 : */
341 1434018 : NTSTATUS dom_sid_split_rid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
342 : struct dom_sid **domain, uint32_t *rid)
343 : {
344 1434018 : if (sid->num_auths == 0) {
345 546716 : return NT_STATUS_INVALID_PARAMETER;
346 : }
347 :
348 887302 : if (domain) {
349 219892 : if (!(*domain = dom_sid_dup(mem_ctx, sid))) {
350 0 : return NT_STATUS_NO_MEMORY;
351 : }
352 :
353 219892 : (*domain)->num_auths -= 1;
354 : }
355 :
356 887302 : if (rid) {
357 780992 : *rid = sid->sub_auths[sid->num_auths - 1];
358 : }
359 :
360 887302 : return NT_STATUS_OK;
361 : }
362 :
363 : /*
364 : return true if the 2nd sid is in the domain given by the first sid
365 : */
366 3673292 : bool dom_sid_in_domain(const struct dom_sid *domain_sid,
367 : const struct dom_sid *sid)
368 : {
369 493165 : int i;
370 :
371 3673292 : if (!domain_sid || !sid) {
372 88883 : return false;
373 : }
374 :
375 3178997 : if (sid->num_auths < 2) {
376 891568 : return false;
377 : }
378 :
379 2268330 : if (domain_sid->num_auths != (sid->num_auths - 1)) {
380 411259 : return false;
381 : }
382 :
383 8412879 : for (i = domain_sid->num_auths-1; i >= 0; --i) {
384 6727979 : if (domain_sid->sub_auths[i] != sid->sub_auths[i]) {
385 155582 : return false;
386 : }
387 : }
388 :
389 1684900 : return dom_sid_compare_auth(domain_sid, sid) == 0;
390 : }
391 :
392 172 : bool dom_sid_has_account_domain(const struct dom_sid *sid)
393 : {
394 172 : if (sid == NULL) {
395 0 : return false;
396 : }
397 :
398 172 : if (sid->sid_rev_num != 1) {
399 0 : return false;
400 : }
401 172 : if (sid->num_auths != 5) {
402 102 : return false;
403 : }
404 70 : if (sid->id_auth[5] != 5) {
405 0 : return false;
406 : }
407 70 : if (sid->id_auth[4] != 0) {
408 0 : return false;
409 : }
410 70 : if (sid->id_auth[3] != 0) {
411 0 : return false;
412 : }
413 70 : if (sid->id_auth[2] != 0) {
414 0 : return false;
415 : }
416 70 : if (sid->id_auth[1] != 0) {
417 0 : return false;
418 : }
419 70 : if (sid->id_auth[0] != 0) {
420 0 : return false;
421 : }
422 70 : if (sid->sub_auths[0] != 21) {
423 2 : return false;
424 : }
425 :
426 68 : return true;
427 : }
428 :
429 135 : bool dom_sid_is_valid_account_domain(const struct dom_sid *sid)
430 : {
431 : /*
432 : * We expect S-1-5-21-9-8-7, but we don't
433 : * allow S-1-5-21-0-0-0 as this is used
434 : * for claims and compound identities.
435 : *
436 : * With this structure:
437 : *
438 : * struct dom_sid {
439 : * uint8_t sid_rev_num;
440 : * int8_t num_auths; [range(0,15)]
441 : * uint8_t id_auth[6];
442 : * uint32_t sub_auths[15];
443 : * }
444 : *
445 : * S-1-5-21-9-8-7 looks like this:
446 : * {1, 4, {0,0,0,0,0,5}, {21,9,8,7,0,0,0,0,0,0,0,0,0,0,0}};
447 : */
448 135 : if (sid == NULL) {
449 0 : return false;
450 : }
451 :
452 135 : if (sid->sid_rev_num != 1) {
453 0 : return false;
454 : }
455 135 : if (sid->num_auths != 4) {
456 0 : return false;
457 : }
458 135 : if (sid->id_auth[5] != 5) {
459 0 : return false;
460 : }
461 135 : if (sid->id_auth[4] != 0) {
462 0 : return false;
463 : }
464 135 : if (sid->id_auth[3] != 0) {
465 0 : return false;
466 : }
467 135 : if (sid->id_auth[2] != 0) {
468 0 : return false;
469 : }
470 135 : if (sid->id_auth[1] != 0) {
471 0 : return false;
472 : }
473 135 : if (sid->id_auth[0] != 0) {
474 0 : return false;
475 : }
476 135 : if (sid->sub_auths[0] != 21) {
477 0 : return false;
478 : }
479 135 : if (sid->sub_auths[1] == 0) {
480 0 : return false;
481 : }
482 135 : if (sid->sub_auths[2] == 0) {
483 0 : return false;
484 : }
485 135 : if (sid->sub_auths[3] == 0) {
486 0 : return false;
487 : }
488 :
489 135 : return true;
490 : }
491 :
492 : /*
493 : Convert a dom_sid to a string, printing into a buffer. Return the
494 : string length. If it overflows, return the string length that would
495 : result (buflen needs to be +1 for the terminating 0).
496 : */
497 17925552 : static int dom_sid_string_buf(const struct dom_sid *sid, char *buf, int buflen)
498 : {
499 384608 : int i, ofs, ret;
500 384608 : uint64_t ia;
501 :
502 17925552 : if (!sid) {
503 42 : return strlcpy(buf, "(NULL SID)", buflen);
504 : }
505 :
506 17925510 : ia = ((uint64_t)sid->id_auth[5]) +
507 17925510 : ((uint64_t)sid->id_auth[4] << 8 ) +
508 17925510 : ((uint64_t)sid->id_auth[3] << 16) +
509 17925510 : ((uint64_t)sid->id_auth[2] << 24) +
510 17925510 : ((uint64_t)sid->id_auth[1] << 32) +
511 17925510 : ((uint64_t)sid->id_auth[0] << 40);
512 :
513 17925510 : ret = snprintf(buf, buflen, "S-%"PRIu8"-", sid->sid_rev_num);
514 17925510 : if (ret < 0) {
515 0 : return ret;
516 : }
517 17925510 : ofs = ret;
518 :
519 17925510 : if (ia >= UINT32_MAX) {
520 31 : ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "0x%"PRIx64, ia);
521 : } else {
522 17925479 : ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "%"PRIu64, ia);
523 : }
524 17925510 : if (ret < 0) {
525 0 : return ret;
526 : }
527 17925510 : ofs += ret;
528 :
529 83954171 : for (i = 0; i < sid->num_auths; i++) {
530 66028661 : ret = snprintf(
531 : buf+ofs,
532 66028661 : MAX(buflen-ofs, 0),
533 : "-%"PRIu32,
534 66028661 : sid->sub_auths[i]);
535 66028661 : if (ret < 0) {
536 0 : return ret;
537 : }
538 66028661 : ofs += ret;
539 : }
540 17540904 : return ofs;
541 : }
542 :
543 : /*
544 : convert a dom_sid to a string
545 : */
546 8044906 : char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
547 : {
548 125743 : char buf[DOM_SID_STR_BUFLEN];
549 125743 : char *result;
550 125743 : int len;
551 :
552 8044906 : len = dom_sid_string_buf(sid, buf, sizeof(buf));
553 :
554 8044906 : if ((len < 0) || (len+1 > sizeof(buf))) {
555 0 : return talloc_strdup(mem_ctx, "(SID ERR)");
556 : }
557 :
558 : /*
559 : * Avoid calling strlen (via talloc_strdup), we already have
560 : * the length
561 : */
562 8044906 : result = (char *)talloc_memdup(mem_ctx, buf, len+1);
563 8044906 : if (result == NULL) {
564 0 : return NULL;
565 : }
566 :
567 : /*
568 : * beautify the talloc_report output
569 : */
570 8044906 : talloc_set_name_const(result, result);
571 8044906 : return result;
572 : }
573 :
574 9880646 : char *dom_sid_str_buf(const struct dom_sid *sid, struct dom_sid_buf *dst)
575 : {
576 258865 : int ret;
577 9880646 : ret = dom_sid_string_buf(sid, dst->buf, sizeof(dst->buf));
578 9880646 : if ((ret < 0) || (ret >= sizeof(dst->buf))) {
579 0 : strlcpy(dst->buf, "(INVALID SID)", sizeof(dst->buf));
580 : }
581 9880646 : return dst->buf;
582 : }
|