LCOV - code coverage report
Current view: top level - libcli/security - dom_sid.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 174 219 79.5 %
Date: 2024-06-13 04:01:37 Functions: 17 18 94.4 %

          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    90119037 : int dom_sid_compare_auth(const struct dom_sid *sid1,
      37             :                          const struct dom_sid *sid2)
      38             : {
      39             :         int i;
      40             : 
      41    90119037 :         if (sid1 == sid2)
      42           0 :                 return 0;
      43    90119037 :         if (!sid1)
      44           0 :                 return -1;
      45    90119037 :         if (!sid2)
      46           0 :                 return 1;
      47             : 
      48    90119037 :         if (sid1->sid_rev_num != sid2->sid_rev_num)
      49         676 :                 return sid1->sid_rev_num - sid2->sid_rev_num;
      50             : 
      51   630096170 :         for (i = 0; i < 6; i++)
      52   540710166 :                 if (sid1->id_auth[i] != sid2->id_auth[i])
      53      732357 :                         return sid1->id_auth[i] - sid2->id_auth[i];
      54             : 
      55    89386004 :         return 0;
      56             : }
      57             : 
      58             : /*****************************************************************
      59             :  Compare two sids.
      60             : *****************************************************************/
      61             : 
      62   857323611 : int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *sid2)
      63             : {
      64             :         int i;
      65             : 
      66   857323611 :         if (sid1 == sid2)
      67        2457 :                 return 0;
      68   857321154 :         if (!sid1)
      69           0 :                 return -1;
      70   857321154 :         if (!sid2)
      71      346143 :                 return 1;
      72             : 
      73             :         /* Compare most likely different rids, first: i.e start at end */
      74   856975011 :         if (sid1->num_auths != sid2->num_auths)
      75   596390599 :                 return sid1->num_auths - sid2->num_auths;
      76             : 
      77   396143126 :         for (i = sid1->num_auths-1; i >= 0; --i)
      78   307068050 :                 if (sid1->sub_auths[i] != sid2->sub_auths[i])
      79   171509336 :                         return sid1->sub_auths[i] - sid2->sub_auths[i];
      80             : 
      81    89075076 :         return dom_sid_compare_auth(sid1, sid2);
      82             : }
      83             : 
      84             : /*****************************************************************
      85             :  Compare two sids.
      86             : *****************************************************************/
      87             : 
      88   856996461 : bool dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2)
      89             : {
      90   856996461 :         return dom_sid_compare(sid1, sid2) == 0;
      91             : }
      92             : 
      93             : /*****************************************************************
      94             :  Add a rid to the end of a sid
      95             : *****************************************************************/
      96             : 
      97    34503575 : bool sid_append_rid(struct dom_sid *sid, uint32_t rid)
      98             : {
      99    34503575 :         if (sid->num_auths < ARRAY_SIZE(sid->sub_auths)) {
     100    34503575 :                 sid->sub_auths[sid->num_auths++] = rid;
     101    34503575 :                 return true;
     102             :         }
     103           0 :         return false;
     104             : }
     105             : 
     106             : /*
     107             :   See if 2 SIDs are in the same domain
     108             :   this just compares the leading sub-auths
     109             : */
     110       59128 : int dom_sid_compare_domain(const struct dom_sid *sid1,
     111             :                            const struct dom_sid *sid2)
     112             : {
     113             :         int n, i;
     114             : 
     115       59128 :         n = MIN(sid1->num_auths, sid2->num_auths);
     116             : 
     117       73016 :         for (i = n-1; i >= 0; --i)
     118       67603 :                 if (sid1->sub_auths[i] != sid2->sub_auths[i])
     119       53715 :                         return sid1->sub_auths[i] - sid2->sub_auths[i];
     120             : 
     121        5413 :         return dom_sid_compare_auth(sid1, sid2);
     122             : }
     123             : 
     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))
     129             : 
     130    14722936 : bool dom_sid_parse_endp(const char *sidstr,struct dom_sid *sidout,
     131             :                         const char **endp)
     132             : {
     133             :         const char *p;
     134             :         char *q;
     135             :         /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
     136             :         uint64_t conv;
     137    14722936 :         int error = 0;
     138             : 
     139    14722936 :         ZERO_STRUCTP(sidout);
     140             : 
     141    14722936 :         if ((sidstr[0] != 'S' && sidstr[0] != 's') || sidstr[1] != '-') {
     142        2580 :                 goto format_error;
     143             :         }
     144             : 
     145             :         /* Get the revision number. */
     146    14716842 :         p = sidstr + 2;
     147             : 
     148    14716842 :         if (!isdigit(*p)) {
     149           0 :                 goto format_error;
     150             :         }
     151             : 
     152    14716842 :         conv = smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
     153    41294044 :         if (error != 0 || (*q != '-') || conv > UINT8_MAX) {
     154           0 :                 goto format_error;
     155             :         }
     156    14716842 :         sidout->sid_rev_num = (uint8_t) conv;
     157    14716842 :         q++;
     158             : 
     159    14716842 :         if (!isdigit(*q)) {
     160           0 :                 goto format_error;
     161             :         }
     162             : 
     163             :         /* get identauth */
     164    14716842 :         conv = smb_strtoull(q, &q, 0, &error, SMB_STR_STANDARD);
     165    28005443 :         if (conv & AUTHORITY_MASK || error != 0) {
     166           0 :                 goto format_error;
     167             :         }
     168             : 
     169             :         /* When identauth >= UINT32_MAX, it's in hex with a leading 0x */
     170             :         /* NOTE - the conv value is in big-endian format. */
     171    14716842 :         sidout->id_auth[0] = (conv & 0xff0000000000ULL) >> 40;
     172    14716842 :         sidout->id_auth[1] = (conv & 0x00ff00000000ULL) >> 32;
     173    14716842 :         sidout->id_auth[2] = (conv & 0x0000ff000000ULL) >> 24;
     174    14716842 :         sidout->id_auth[3] = (conv & 0x000000ff0000ULL) >> 16;
     175    14716842 :         sidout->id_auth[4] = (conv & 0x00000000ff00ULL) >> 8;
     176    14716842 :         sidout->id_auth[5] = (conv & 0x0000000000ffULL);
     177             : 
     178    14716842 :         sidout->num_auths = 0;
     179    14716842 :         if (*q != '-') {
     180             :                 /* Just id_auth, no subauths */
     181       10333 :                 goto done;
     182             :         }
     183             : 
     184    14706509 :         q++;
     185             : 
     186    15525401 :         while (true) {
     187             :                 char *end;
     188             : 
     189    30231910 :                 if (!isdigit(*q)) {
     190           0 :                         goto format_error;
     191             :                 }
     192             : 
     193    30231910 :                 conv = smb_strtoull(q, &end, 10, &error, SMB_STR_STANDARD);
     194    30231910 :                 if (conv > UINT32_MAX || error != 0) {
     195           0 :                         goto format_error;
     196             :                 }
     197             : 
     198    30231910 :                 if (!sid_append_rid(sidout, conv)) {
     199           0 :                         DEBUG(3, ("Too many sid auths in %s\n", sidstr));
     200           0 :                         return false;
     201             :                 }
     202             : 
     203    30231910 :                 q = end;
     204    30231910 :                 if (*q != '-') {
     205    14706509 :                         break;
     206             :                 }
     207    15525401 :                 q += 1;
     208             :         }
     209    14716842 : done:
     210    14716842 :         if (endp != NULL) {
     211       46923 :                 *endp = q;
     212             :         }
     213    14716842 :         return true;
     214             : 
     215        6094 : format_error:
     216        6094 :         DEBUG(3, ("string_to_sid: SID %s is not in a valid format\n", sidstr));
     217        6094 :         return false;
     218             : }
     219             : 
     220       49472 : bool string_to_sid(struct dom_sid *sidout, const char *sidstr)
     221             : {
     222       49472 :         return dom_sid_parse(sidstr, sidout);
     223             : }
     224             : 
     225    14676013 : bool dom_sid_parse(const char *sidstr, struct dom_sid *ret)
     226             : {
     227    14676013 :         return dom_sid_parse_endp(sidstr, ret, NULL);
     228             : }
     229             : 
     230             : /*
     231             :   convert a string to a dom_sid, returning a talloc'd dom_sid
     232             : */
     233     2319861 : struct dom_sid *dom_sid_parse_talloc(TALLOC_CTX *mem_ctx, const char *sidstr)
     234             : {
     235             :         struct dom_sid *ret;
     236     2319861 :         ret = talloc(mem_ctx, struct dom_sid);
     237     2319861 :         if (!ret) {
     238           0 :                 return NULL;
     239             :         }
     240     2319861 :         if (!dom_sid_parse(sidstr, ret)) {
     241           4 :                 talloc_free(ret);
     242           4 :                 return NULL;
     243             :         }
     244             : 
     245     2319857 :         return ret;
     246             : }
     247             : 
     248             : /*
     249             :   convert a string to a dom_sid, returning a talloc'd dom_sid
     250             : */
     251           0 : struct dom_sid *dom_sid_parse_length(TALLOC_CTX *mem_ctx, const DATA_BLOB *sid)
     252           0 : {
     253           0 :         char p[sid->length+1];
     254           0 :         memcpy(p, sid->data, sid->length);
     255           0 :         p[sid->length] = '\0';
     256           0 :         return dom_sid_parse_talloc(mem_ctx, p);
     257             : }
     258             : 
     259             : /*
     260             :   copy a dom_sid structure
     261             : */
     262     5036623 : struct dom_sid *dom_sid_dup(TALLOC_CTX *mem_ctx, const struct dom_sid *dom_sid)
     263             : {
     264             :         struct dom_sid *ret;
     265             :         int i;
     266             : 
     267     5036623 :         if (!dom_sid) {
     268           0 :                 return NULL;
     269             :         }
     270             : 
     271     5036623 :         ret = talloc(mem_ctx, struct dom_sid);
     272     5036623 :         if (!ret) {
     273           0 :                 return NULL;
     274             :         }
     275             : 
     276     5036623 :         ret->sid_rev_num = dom_sid->sid_rev_num;
     277     5036623 :         ret->id_auth[0] = dom_sid->id_auth[0];
     278     5036623 :         ret->id_auth[1] = dom_sid->id_auth[1];
     279     5036623 :         ret->id_auth[2] = dom_sid->id_auth[2];
     280     5036623 :         ret->id_auth[3] = dom_sid->id_auth[3];
     281     5036623 :         ret->id_auth[4] = dom_sid->id_auth[4];
     282     5036623 :         ret->id_auth[5] = dom_sid->id_auth[5];
     283     5036623 :         ret->num_auths = dom_sid->num_auths;
     284             : 
     285    25992354 :         for (i=0;i<dom_sid->num_auths;i++) {
     286    20955731 :                 ret->sub_auths[i] = dom_sid->sub_auths[i];
     287             :         }
     288             : 
     289     5036623 :         return ret;
     290             : }
     291             : 
     292             : /*
     293             :   add a rid to a domain dom_sid to make a full dom_sid. This function
     294             :   returns a new sid in the supplied memory context
     295             : */
     296     3732436 : struct dom_sid *dom_sid_add_rid(TALLOC_CTX *mem_ctx,
     297             :                                 const struct dom_sid *domain_sid,
     298             :                                 uint32_t rid)
     299             : {
     300             :         struct dom_sid *sid;
     301             : 
     302     3732436 :         sid = dom_sid_dup(mem_ctx, domain_sid);
     303     3732436 :         if (!sid) return NULL;
     304             : 
     305     3732436 :         if (!sid_append_rid(sid, rid)) {
     306           0 :                 talloc_free(sid);
     307           0 :                 return NULL;
     308             :         }
     309             : 
     310     3732436 :         return sid;
     311             : }
     312             : 
     313             : /*
     314             :   Split up a SID into its domain and RID part
     315             : */
     316     1041529 : NTSTATUS dom_sid_split_rid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
     317             :                            struct dom_sid **domain, uint32_t *rid)
     318             : {
     319     1041529 :         if (sid->num_auths == 0) {
     320      434392 :                 return NT_STATUS_INVALID_PARAMETER;
     321             :         }
     322             : 
     323      607137 :         if (domain) {
     324      132613 :                 if (!(*domain = dom_sid_dup(mem_ctx, sid))) {
     325           0 :                         return NT_STATUS_NO_MEMORY;
     326             :                 }
     327             : 
     328      132613 :                 (*domain)->num_auths -= 1;
     329             :         }
     330             : 
     331      607137 :         if (rid) {
     332      538446 :                 *rid = sid->sub_auths[sid->num_auths - 1];
     333             :         }
     334             : 
     335      607137 :         return NT_STATUS_OK;
     336             : }
     337             : 
     338             : /*
     339             :   return true if the 2nd sid is in the domain given by the first sid
     340             : */
     341     1049595 : bool dom_sid_in_domain(const struct dom_sid *domain_sid,
     342             :                        const struct dom_sid *sid)
     343             : {
     344             :         int i;
     345             : 
     346     1049595 :         if (!domain_sid || !sid) {
     347       45152 :                 return false;
     348             :         }
     349             : 
     350     1004443 :         if (sid->num_auths < 2) {
     351      122922 :                 return false;
     352             :         }
     353             : 
     354      881521 :         if (domain_sid->num_auths != (sid->num_auths - 1)) {
     355       17111 :                 return false;
     356             :         }
     357             : 
     358     4241057 :         for (i = domain_sid->num_auths-1; i >= 0; --i) {
     359     3378056 :                 if (domain_sid->sub_auths[i] != sid->sub_auths[i]) {
     360        1409 :                         return false;
     361             :                 }
     362             :         }
     363             : 
     364      863001 :         return dom_sid_compare_auth(domain_sid, sid) == 0;
     365             : }
     366             : 
     367         134 : bool dom_sid_is_valid_account_domain(const struct dom_sid *sid)
     368             : {
     369             :         /*
     370             :          * We expect S-1-5-21-9-8-7, but we don't
     371             :          * allow S-1-5-21-0-0-0 as this is used
     372             :          * for claims and compound identities.
     373             :          *
     374             :          * With this structure:
     375             :          *
     376             :          * struct dom_sid {
     377             :          *     uint8_t sid_rev_num;
     378             :          *     int8_t num_auths; [range(0,15)]
     379             :          *     uint8_t id_auth[6];
     380             :          *     uint32_t sub_auths[15];
     381             :          * }
     382             :          *
     383             :          * S-1-5-21-9-8-7 looks like this:
     384             :          * {1, 4, {0,0,0,0,0,5}, {21,9,8,7,0,0,0,0,0,0,0,0,0,0,0}};
     385             :          */
     386         134 :         if (sid == NULL) {
     387           0 :                 return false;
     388             :         }
     389             : 
     390         134 :         if (sid->sid_rev_num != 1) {
     391           0 :                 return false;
     392             :         }
     393         134 :         if (sid->num_auths != 4) {
     394           0 :                 return false;
     395             :         }
     396         134 :         if (sid->id_auth[5] != 5) {
     397           0 :                 return false;
     398             :         }
     399         134 :         if (sid->id_auth[4] != 0) {
     400           0 :                 return false;
     401             :         }
     402         134 :         if (sid->id_auth[3] != 0) {
     403           0 :                 return false;
     404             :         }
     405         134 :         if (sid->id_auth[2] != 0) {
     406           0 :                 return false;
     407             :         }
     408         134 :         if (sid->id_auth[1] != 0) {
     409           0 :                 return false;
     410             :         }
     411         134 :         if (sid->id_auth[0] != 0) {
     412           0 :                 return false;
     413             :         }
     414         134 :         if (sid->sub_auths[0] != 21) {
     415           0 :                 return false;
     416             :         }
     417         134 :         if (sid->sub_auths[1] == 0) {
     418           0 :                 return false;
     419             :         }
     420         134 :         if (sid->sub_auths[2] == 0) {
     421           0 :                 return false;
     422             :         }
     423         134 :         if (sid->sub_auths[3] == 0) {
     424           0 :                 return false;
     425             :         }
     426             : 
     427         134 :         return true;
     428             : }
     429             : 
     430             : /*
     431             :   Convert a dom_sid to a string, printing into a buffer. Return the
     432             :   string length. If it overflows, return the string length that would
     433             :   result (buflen needs to be +1 for the terminating 0).
     434             : */
     435     4435877 : static int dom_sid_string_buf(const struct dom_sid *sid, char *buf, int buflen)
     436             : {
     437             :         int i, ofs, ret;
     438             :         uint64_t ia;
     439             : 
     440     4435877 :         if (!sid) {
     441           1 :                 return strlcpy(buf, "(NULL SID)", buflen);
     442             :         }
     443             : 
     444    12422652 :         ia = ((uint64_t)sid->id_auth[5]) +
     445     8429264 :                 ((uint64_t)sid->id_auth[4] << 8 ) +
     446     8429264 :                 ((uint64_t)sid->id_auth[3] << 16) +
     447     8429264 :                 ((uint64_t)sid->id_auth[2] << 24) +
     448     4435876 :                 ((uint64_t)sid->id_auth[1] << 32) +
     449     4435876 :                 ((uint64_t)sid->id_auth[0] << 40);
     450             : 
     451     4435876 :         ret = snprintf(buf, buflen, "S-%"PRIu8"-", sid->sid_rev_num);
     452     4435876 :         if (ret < 0) {
     453           0 :                 return ret;
     454             :         }
     455     4435876 :         ofs = ret;
     456             : 
     457     4435876 :         if (ia >= UINT32_MAX) {
     458           0 :                 ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "0x%"PRIx64, ia);
     459             :         } else {
     460     4435876 :                 ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "%"PRIu64, ia);
     461             :         }
     462     4435876 :         if (ret < 0) {
     463           0 :                 return ret;
     464             :         }
     465     4435876 :         ofs += ret;
     466             : 
     467    21457399 :         for (i = 0; i < sid->num_auths; i++) {
     468    32305891 :                 ret = snprintf(
     469             :                         buf+ofs,
     470    17021523 :                         MAX(buflen-ofs, 0),
     471             :                         "-%"PRIu32,
     472     1737155 :                         sid->sub_auths[i]);
     473    17021523 :                 if (ret < 0) {
     474           0 :                         return ret;
     475             :                 }
     476    17021523 :                 ofs += ret;
     477             :         }
     478     4435876 :         return ofs;
     479             : }
     480             : 
     481             : /*
     482             :   convert a dom_sid to a string
     483             : */
     484     3056431 : char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
     485             : {
     486             :         char buf[DOM_SID_STR_BUFLEN];
     487             :         char *result;
     488             :         int len;
     489             : 
     490     3056431 :         len = dom_sid_string_buf(sid, buf, sizeof(buf));
     491             : 
     492     3056431 :         if ((len < 0) || (len+1 > sizeof(buf))) {
     493           0 :                 return talloc_strdup(mem_ctx, "(SID ERR)");
     494             :         }
     495             : 
     496             :         /*
     497             :          * Avoid calling strlen (via talloc_strdup), we already have
     498             :          * the length
     499             :          */
     500     3056431 :         result = (char *)talloc_memdup(mem_ctx, buf, len+1);
     501     3056431 :         if (result == NULL) {
     502           0 :                 return NULL;
     503             :         }
     504             : 
     505             :         /*
     506             :          * beautify the talloc_report output
     507             :          */
     508     3056431 :         talloc_set_name_const(result, result);
     509     3056431 :         return result;
     510             : }
     511             : 
     512     1379446 : char *dom_sid_str_buf(const struct dom_sid *sid, struct dom_sid_buf *dst)
     513             : {
     514             :         int ret;
     515     1379446 :         ret = dom_sid_string_buf(sid, dst->buf, sizeof(dst->buf));
     516     1379446 :         if ((ret < 0) || (ret >= sizeof(dst->buf))) {
     517           0 :                 strlcpy(dst->buf, "(INVALID SID)", sizeof(dst->buf));
     518             :         }
     519     1379446 :         return dst->buf;
     520             : }

Generated by: LCOV version 1.13