tests/krb5: Refactor encryption type selection
[Samba.git] / libcli / security / dom_sid.c
blob9a91760ff6246d20f14a34da29b17ec3d7189357
1 /*
2 Unix SMB/CIFS implementation.
3 Samba utility functions
5 Copyright (C) Stefan (metze) Metzmacher 2002-2004
6 Copyright (C) Andrew Tridgell 1992-2004
7 Copyright (C) Jeremy Allison 1999
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.
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.
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/>.
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"
32 /*****************************************************************
33 Compare the auth portion of two sids.
34 *****************************************************************/
36 int dom_sid_compare_auth(const struct dom_sid *sid1,
37 const struct dom_sid *sid2)
39 int i;
41 if (sid1 == sid2)
42 return 0;
43 if (!sid1)
44 return -1;
45 if (!sid2)
46 return 1;
48 if (sid1->sid_rev_num != sid2->sid_rev_num)
49 return sid1->sid_rev_num - sid2->sid_rev_num;
51 for (i = 0; i < 6; i++)
52 if (sid1->id_auth[i] != sid2->id_auth[i])
53 return sid1->id_auth[i] - sid2->id_auth[i];
55 return 0;
58 /*****************************************************************
59 Compare two sids.
60 *****************************************************************/
62 int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *sid2)
64 int i;
66 if (sid1 == sid2)
67 return 0;
68 if (!sid1)
69 return -1;
70 if (!sid2)
71 return 1;
73 /* Compare most likely different rids, first: i.e start at end */
74 if (sid1->num_auths != sid2->num_auths)
75 return sid1->num_auths - sid2->num_auths;
77 for (i = sid1->num_auths-1; i >= 0; --i)
78 if (sid1->sub_auths[i] != sid2->sub_auths[i])
79 return sid1->sub_auths[i] - sid2->sub_auths[i];
81 return dom_sid_compare_auth(sid1, sid2);
84 /*****************************************************************
85 Compare two sids.
86 *****************************************************************/
88 bool dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2)
90 return dom_sid_compare(sid1, sid2) == 0;
93 /*****************************************************************
94 Add a rid to the end of a sid
95 *****************************************************************/
97 bool sid_append_rid(struct dom_sid *sid, uint32_t rid)
99 if (sid->num_auths < ARRAY_SIZE(sid->sub_auths)) {
100 sid->sub_auths[sid->num_auths++] = rid;
101 return true;
103 return false;
107 See if 2 SIDs are in the same domain
108 this just compares the leading sub-auths
110 int dom_sid_compare_domain(const struct dom_sid *sid1,
111 const struct dom_sid *sid2)
113 int n, i;
115 n = MIN(sid1->num_auths, sid2->num_auths);
117 for (i = n-1; i >= 0; --i)
118 if (sid1->sub_auths[i] != sid2->sub_auths[i])
119 return sid1->sub_auths[i] - sid2->sub_auths[i];
121 return dom_sid_compare_auth(sid1, sid2);
124 /*****************************************************************
125 Convert a string to a SID. Returns True on success, False on fail.
126 Return the first character not parsed in endp.
127 *****************************************************************/
128 #define AUTHORITY_MASK (~(0xffffffffffffULL))
130 bool dom_sid_parse_endp(const char *sidstr,struct dom_sid *sidout,
131 const char **endp)
133 const char *p;
134 char *q = NULL;
135 char *end = NULL;
136 uint64_t conv;
137 int error = 0;
139 ZERO_STRUCTP(sidout);
141 if ((sidstr[0] != 'S' && sidstr[0] != 's') || sidstr[1] != '-') {
142 goto format_error;
145 /* Get the revision number. */
146 p = sidstr + 2;
148 if (!isdigit((unsigned char)*p)) {
149 goto format_error;
152 conv = smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
153 if (error != 0 || (*q != '-') || conv > UINT8_MAX || q - p > 4) {
154 goto format_error;
156 sidout->sid_rev_num = (uint8_t) conv;
157 q++;
159 if (!isdigit((unsigned char)*q)) {
160 goto format_error;
162 while (q[0] == '0' && isdigit((unsigned char)q[1])) {
164 * strtoull will think this is octal, which is not how SIDs
165 * work! So let's walk along until there are no leading zeros
166 * (or a single zero).
168 q++;
171 /* get identauth */
172 conv = smb_strtoull(q, &end, 0, &error, SMB_STR_STANDARD);
173 if (conv & AUTHORITY_MASK || error != 0) {
174 goto format_error;
176 if (conv >= (1ULL << 48) || end - q > 15) {
178 * This identauth looks like a big number, but resolves to a
179 * small number after rounding.
181 goto format_error;
184 /* NOTE - the conv value is in big-endian format. */
185 sidout->id_auth[0] = (conv & 0xff0000000000ULL) >> 40;
186 sidout->id_auth[1] = (conv & 0x00ff00000000ULL) >> 32;
187 sidout->id_auth[2] = (conv & 0x0000ff000000ULL) >> 24;
188 sidout->id_auth[3] = (conv & 0x000000ff0000ULL) >> 16;
189 sidout->id_auth[4] = (conv & 0x00000000ff00ULL) >> 8;
190 sidout->id_auth[5] = (conv & 0x0000000000ffULL);
192 sidout->num_auths = 0;
193 q = end;
194 if (*q != '-') {
195 /* Just id_auth, no subauths */
196 goto done;
199 q++;
201 while (true) {
202 if (!isdigit((unsigned char)*q)) {
203 goto format_error;
205 while (q[0] == '0' && isdigit((unsigned char)q[1])) {
207 * strtoull will think this is octal, which is not how
208 * SIDs work! So let's walk along until there are no
209 * leading zeros (or a single zero).
211 q++;
213 conv = smb_strtoull(q, &end, 0, &error, SMB_STR_STANDARD);
214 if (conv > UINT32_MAX || error != 0 || end - q > 12) {
216 * This sub-auth is greater than 4294967295,
217 * and hence invalid. Windows will treat it as
218 * 4294967295, while we prefer to refuse (old
219 * versions of Samba will wrap, arriving at
220 * another number altogether).
222 DBG_NOTICE("bad sub-auth in %s\n", sidstr);
223 goto format_error;
226 if (!sid_append_rid(sidout, conv)) {
227 DEBUG(3, ("Too many sid auths in %s\n", sidstr));
228 return false;
231 q = end;
232 if (*q != '-') {
233 break;
235 q += 1;
237 done:
238 if (endp != NULL) {
239 *endp = q;
241 return true;
243 format_error:
244 DEBUG(3, ("string_to_sid: SID %s is not in a valid format\n", sidstr));
245 return false;
248 bool string_to_sid(struct dom_sid *sidout, const char *sidstr)
250 return dom_sid_parse(sidstr, sidout);
253 bool dom_sid_parse(const char *sidstr, struct dom_sid *ret)
255 return dom_sid_parse_endp(sidstr, ret, NULL);
259 convert a string to a dom_sid, returning a talloc'd dom_sid
261 struct dom_sid *dom_sid_parse_talloc(TALLOC_CTX *mem_ctx, const char *sidstr)
263 struct dom_sid *ret;
264 ret = talloc(mem_ctx, struct dom_sid);
265 if (!ret) {
266 return NULL;
268 if (!dom_sid_parse(sidstr, ret)) {
269 talloc_free(ret);
270 return NULL;
273 return ret;
277 convert a string to a dom_sid, returning a talloc'd dom_sid
279 struct dom_sid *dom_sid_parse_length(TALLOC_CTX *mem_ctx, const DATA_BLOB *sid)
281 char p[sid->length+1];
282 memcpy(p, sid->data, sid->length);
283 p[sid->length] = '\0';
284 return dom_sid_parse_talloc(mem_ctx, p);
288 copy a dom_sid structure
290 struct dom_sid *dom_sid_dup(TALLOC_CTX *mem_ctx, const struct dom_sid *dom_sid)
292 struct dom_sid *ret;
294 if (!dom_sid) {
295 return NULL;
298 ret = talloc(mem_ctx, struct dom_sid);
299 if (!ret) {
300 return NULL;
302 sid_copy(ret, dom_sid);
304 return ret;
308 add a rid to a domain dom_sid to make a full dom_sid. This function
309 returns a new sid in the supplied memory context
311 struct dom_sid *dom_sid_add_rid(TALLOC_CTX *mem_ctx,
312 const struct dom_sid *domain_sid,
313 uint32_t rid)
315 struct dom_sid *sid;
317 sid = dom_sid_dup(mem_ctx, domain_sid);
318 if (!sid) return NULL;
320 if (!sid_append_rid(sid, rid)) {
321 talloc_free(sid);
322 return NULL;
325 return sid;
329 Split up a SID into its domain and RID part
331 NTSTATUS dom_sid_split_rid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
332 struct dom_sid **domain, uint32_t *rid)
334 if (sid->num_auths == 0) {
335 return NT_STATUS_INVALID_PARAMETER;
338 if (domain) {
339 if (!(*domain = dom_sid_dup(mem_ctx, sid))) {
340 return NT_STATUS_NO_MEMORY;
343 (*domain)->num_auths -= 1;
346 if (rid) {
347 *rid = sid->sub_auths[sid->num_auths - 1];
350 return NT_STATUS_OK;
354 return true if the 2nd sid is in the domain given by the first sid
356 bool dom_sid_in_domain(const struct dom_sid *domain_sid,
357 const struct dom_sid *sid)
359 int i;
361 if (!domain_sid || !sid) {
362 return false;
365 if (sid->num_auths < 2) {
366 return false;
369 if (domain_sid->num_auths != (sid->num_auths - 1)) {
370 return false;
373 for (i = domain_sid->num_auths-1; i >= 0; --i) {
374 if (domain_sid->sub_auths[i] != sid->sub_auths[i]) {
375 return false;
379 return dom_sid_compare_auth(domain_sid, sid) == 0;
382 bool dom_sid_has_account_domain(const struct dom_sid *sid)
384 if (sid == NULL) {
385 return false;
388 if (sid->sid_rev_num != 1) {
389 return false;
391 if (sid->num_auths != 5) {
392 return false;
394 if (sid->id_auth[5] != 5) {
395 return false;
397 if (sid->id_auth[4] != 0) {
398 return false;
400 if (sid->id_auth[3] != 0) {
401 return false;
403 if (sid->id_auth[2] != 0) {
404 return false;
406 if (sid->id_auth[1] != 0) {
407 return false;
409 if (sid->id_auth[0] != 0) {
410 return false;
412 if (sid->sub_auths[0] != 21) {
413 return false;
416 return true;
419 bool dom_sid_is_valid_account_domain(const struct dom_sid *sid)
422 * We expect S-1-5-21-9-8-7, but we don't
423 * allow S-1-5-21-0-0-0 as this is used
424 * for claims and compound identities.
426 * With this structure:
428 * struct dom_sid {
429 * uint8_t sid_rev_num;
430 * int8_t num_auths; [range(0,15)]
431 * uint8_t id_auth[6];
432 * uint32_t sub_auths[15];
435 * S-1-5-21-9-8-7 looks like this:
436 * {1, 4, {0,0,0,0,0,5}, {21,9,8,7,0,0,0,0,0,0,0,0,0,0,0}};
438 if (sid == NULL) {
439 return false;
442 if (sid->sid_rev_num != 1) {
443 return false;
445 if (sid->num_auths != 4) {
446 return false;
448 if (sid->id_auth[5] != 5) {
449 return false;
451 if (sid->id_auth[4] != 0) {
452 return false;
454 if (sid->id_auth[3] != 0) {
455 return false;
457 if (sid->id_auth[2] != 0) {
458 return false;
460 if (sid->id_auth[1] != 0) {
461 return false;
463 if (sid->id_auth[0] != 0) {
464 return false;
466 if (sid->sub_auths[0] != 21) {
467 return false;
469 if (sid->sub_auths[1] == 0) {
470 return false;
472 if (sid->sub_auths[2] == 0) {
473 return false;
475 if (sid->sub_auths[3] == 0) {
476 return false;
479 return true;
483 Convert a dom_sid to a string, printing into a buffer. Return the
484 string length. If it overflows, return the string length that would
485 result (buflen needs to be +1 for the terminating 0).
487 static int dom_sid_string_buf(const struct dom_sid *sid, char *buf, int buflen)
489 int i, ofs, ret;
490 uint64_t ia;
492 if (!sid) {
493 return strlcpy(buf, "(NULL SID)", buflen);
496 ia = ((uint64_t)sid->id_auth[5]) +
497 ((uint64_t)sid->id_auth[4] << 8 ) +
498 ((uint64_t)sid->id_auth[3] << 16) +
499 ((uint64_t)sid->id_auth[2] << 24) +
500 ((uint64_t)sid->id_auth[1] << 32) +
501 ((uint64_t)sid->id_auth[0] << 40);
503 ret = snprintf(buf, buflen, "S-%"PRIu8"-", sid->sid_rev_num);
504 if (ret < 0) {
505 return ret;
507 ofs = ret;
509 if (ia >= UINT32_MAX) {
510 ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "0x%"PRIx64, ia);
511 } else {
512 ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "%"PRIu64, ia);
514 if (ret < 0) {
515 return ret;
517 ofs += ret;
519 for (i = 0; i < sid->num_auths; i++) {
520 ret = snprintf(
521 buf+ofs,
522 MAX(buflen-ofs, 0),
523 "-%"PRIu32,
524 sid->sub_auths[i]);
525 if (ret < 0) {
526 return ret;
528 ofs += ret;
530 return ofs;
534 convert a dom_sid to a string
536 char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
538 char buf[DOM_SID_STR_BUFLEN];
539 char *result;
540 int len;
542 len = dom_sid_string_buf(sid, buf, sizeof(buf));
544 if ((len < 0) || (len+1 > sizeof(buf))) {
545 return talloc_strdup(mem_ctx, "(SID ERR)");
549 * Avoid calling strlen (via talloc_strdup), we already have
550 * the length
552 result = (char *)talloc_memdup(mem_ctx, buf, len+1);
553 if (result == NULL) {
554 return NULL;
558 * beautify the talloc_report output
560 talloc_set_name_const(result, result);
561 return result;
564 char *dom_sid_str_buf(const struct dom_sid *sid, struct dom_sid_buf *dst)
566 int ret;
567 ret = dom_sid_string_buf(sid, dst->buf, sizeof(dst->buf));
568 if ((ret < 0) || (ret >= sizeof(dst->buf))) {
569 strlcpy(dst->buf, "(INVALID SID)", sizeof(dst->buf));
571 return dst->buf;