LCOV - code coverage report
Current view: top level - libcli/security - dom_sid.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 216 261 82.8 %
Date: 2024-01-11 09:59:51 Functions: 18 19 94.7 %

          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   144191203 : int dom_sid_compare_auth(const struct dom_sid *sid1,
      37             :                          const struct dom_sid *sid2)
      38             : {
      39     7875904 :         int i;
      40             : 
      41   144191203 :         if (sid1 == sid2)
      42           0 :                 return 0;
      43   144191203 :         if (!sid1)
      44           0 :                 return -1;
      45   144191203 :         if (!sid2)
      46           0 :                 return 1;
      47             : 
      48   144191203 :         if (sid1->sid_rev_num != sid2->sid_rev_num)
      49        1015 :                 return sid1->sid_rev_num - sid2->sid_rev_num;
      50             : 
      51  1007429517 :         for (i = 0; i < 6; i++)
      52   865141128 :                 if (sid1->id_auth[i] != sid2->id_auth[i])
      53     1901799 :                         return sid1->id_auth[i] - sid2->id_auth[i];
      54             : 
      55   134534446 :         return 0;
      56             : }
      57             : 
      58             : /*****************************************************************
      59             :  Compare two sids.
      60             : *****************************************************************/
      61             : 
      62  1356258765 : int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *sid2)
      63             : {
      64    66697135 :         int i;
      65             : 
      66  1356258765 :         if (sid1 == sid2)
      67       51439 :                 return 0;
      68  1356204956 :         if (!sid1)
      69          12 :                 return -1;
      70  1356204944 :         if (!sid2)
      71     5321455 :                 return 1;
      72             : 
      73             :         /* Compare most likely different rids, first: i.e start at end */
      74  1350835124 :         if (sid1->num_auths != sid2->num_auths)
      75   963716852 :                 return sid1->num_auths - sid2->num_auths;
      76             : 
      77   601614133 :         for (i = sid1->num_auths-1; i >= 0; --i) {
      78   459806473 :                 if (sid1->sub_auths[i] < sid2->sub_auths[i]) {
      79   171007368 :                         return -1;
      80             :                 }
      81   280357513 :                 if (sid1->sub_auths[i] > sid2->sub_auths[i]) {
      82    64164001 :                         return 1;
      83             :                 }
      84             :         }
      85             : 
      86   141807660 :         return dom_sid_compare_auth(sid1, sid2);
      87             : }
      88             : 
      89             : /*****************************************************************
      90             :  Compare two sids.
      91             : *****************************************************************/
      92             : 
      93  1355467913 : bool dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2)
      94             : {
      95  1355467913 :         return dom_sid_compare(sid1, sid2) == 0;
      96             : }
      97             : 
      98             : /*****************************************************************
      99             :  Add a rid to the end of a sid
     100             : *****************************************************************/
     101             : 
     102    89916288 : bool sid_append_rid(struct dom_sid *sid, uint32_t rid)
     103             : {
     104    89916288 :         if (sid->num_auths < ARRAY_SIZE(sid->sub_auths)) {
     105    89916287 :                 sid->sub_auths[sid->num_auths++] = rid;
     106    89916287 :                 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     2078194 : int dom_sid_compare_domain(const struct dom_sid *sid1,
     116             :                            const struct dom_sid *sid2)
     117             : {
     118        7524 :         int n, i;
     119             : 
     120     2078194 :         n = MIN(sid1->num_auths, sid2->num_auths);
     121             : 
     122     2911659 :         for (i = n-1; i >= 0; --i) {
     123     2568464 :                 if (sid1->sub_auths[i] < sid2->sub_auths[i]) {
     124      705410 :                         return -1;
     125             :                 }
     126     1859260 :                 if (sid1->sub_auths[i] > sid2->sub_auths[i]) {
     127     1022384 :                         return 1;
     128             :                 }
     129             :         }
     130             : 
     131      343195 :         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    21568351 : bool dom_sid_parse_endp(const char *sidstr,struct dom_sid *sidout,
     141             :                         const char **endp)
     142             : {
     143      716577 :         const char *p;
     144    21568351 :         char *q = NULL;
     145    21568351 :         char *end = NULL;
     146      716577 :         uint64_t conv;
     147    21568351 :         int error = 0;
     148             : 
     149    21568351 :         *sidout = (struct dom_sid) {};
     150             : 
     151    21568351 :         if ((sidstr[0] != 'S' && sidstr[0] != 's') || sidstr[1] != '-') {
     152        9721 :                 goto format_error;
     153             :         }
     154             : 
     155             :         /* Get the revision number. */
     156    21558630 :         p = sidstr + 2;
     157             : 
     158    21558630 :         if (!isdigit((unsigned char)*p)) {
     159           1 :                 goto format_error;
     160             :         }
     161             : 
     162    21558629 :         conv = smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
     163    21558629 :         if (error != 0 || (*q != '-') || conv > UINT8_MAX || q - p > 4) {
     164         113 :                 goto format_error;
     165             :         }
     166    21558516 :         sidout->sid_rev_num = (uint8_t) conv;
     167    21558516 :         q++;
     168             : 
     169    21558516 :         if (!isdigit((unsigned char)*q)) {
     170           0 :                 goto format_error;
     171             :         }
     172    21558736 :         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    21558516 :         conv = smb_strtoull(q, &end, 0, &error, SMB_STR_STANDARD);
     183    21558516 :         if (conv & AUTHORITY_MASK || error != 0) {
     184          22 :                 goto format_error;
     185             :         }
     186    21558494 :         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    21558494 :         sidout->id_auth[0] = (conv & 0xff0000000000ULL) >> 40;
     196    21558494 :         sidout->id_auth[1] = (conv & 0x00ff00000000ULL) >> 32;
     197    21558494 :         sidout->id_auth[2] = (conv & 0x0000ff000000ULL) >> 24;
     198    21558494 :         sidout->id_auth[3] = (conv & 0x000000ff0000ULL) >> 16;
     199    21558494 :         sidout->id_auth[4] = (conv & 0x00000000ff00ULL) >> 8;
     200    21558494 :         sidout->id_auth[5] = (conv & 0x0000000000ffULL);
     201             : 
     202    21558494 :         sidout->num_auths = 0;
     203    21558494 :         q = end;
     204    21558494 :         if (*q != '-') {
     205             :                 /* Just id_auth, no subauths */
     206       12503 :                 goto done;
     207             :         }
     208             : 
     209    21545991 :         q++;
     210             : 
     211     2801733 :         while (true) {
     212    80019525 :                 if (!isdigit((unsigned char)*q)) {
     213          22 :                         goto format_error;
     214             :                 }
     215    80019718 :                 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    80019503 :                 conv = smb_strtoull(q, &end, 0, &error, SMB_STR_STANDARD);
     224    80019503 :                 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    80019403 :                 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    80019402 :                 q = end;
     242    80019402 :                 if (*q != '-') {
     243    20829754 :                         break;
     244             :                 }
     245    58473534 :                 q += 1;
     246             :         }
     247    21557928 : done:
     248    21558371 :         if (endp != NULL) {
     249      306736 :                 *endp = q;
     250             :         }
     251    20841814 :         return true;
     252             : 
     253        9979 : format_error:
     254        9979 :         DEBUG(3, ("string_to_sid: SID %s is not in a valid format\n", sidstr));
     255        9960 :         return false;
     256             : }
     257             : 
     258     4683677 : bool string_to_sid(struct dom_sid *sidout, const char *sidstr)
     259             : {
     260     4683677 :         return dom_sid_parse(sidstr, sidout);
     261             : }
     262             : 
     263    21261499 : bool dom_sid_parse(const char *sidstr, struct dom_sid *ret)
     264             : {
     265    21261499 :         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     4462204 : struct dom_sid *dom_sid_parse_talloc(TALLOC_CTX *mem_ctx, const char *sidstr)
     272             : {
     273      356586 :         struct dom_sid *ret;
     274     4462204 :         ret = talloc(mem_ctx, struct dom_sid);
     275     4462204 :         if (!ret) {
     276           0 :                 return NULL;
     277             :         }
     278     4462204 :         if (!dom_sid_parse(sidstr, ret)) {
     279           4 :                 talloc_free(ret);
     280           4 :                 return NULL;
     281             :         }
     282             : 
     283     4105614 :         return ret;
     284             : }
     285             : 
     286             : /*
     287             :   convert a string to a dom_sid, returning a talloc'd dom_sid
     288             : */
     289           0 : struct dom_sid *dom_sid_parse_length(TALLOC_CTX *mem_ctx, const DATA_BLOB *sid)
     290           0 : {
     291           0 :         char p[sid->length+1];
     292           0 :         memcpy(p, sid->data, sid->length);
     293           0 :         p[sid->length] = '\0';
     294           0 :         return dom_sid_parse_talloc(mem_ctx, p);
     295             : }
     296             : 
     297             : /*
     298             :   copy a dom_sid structure
     299             : */
     300    13707758 : struct dom_sid *dom_sid_dup(TALLOC_CTX *mem_ctx, const struct dom_sid *dom_sid)
     301             : {
     302      988355 :         struct dom_sid *ret;
     303             : 
     304    13707758 :         if (!dom_sid) {
     305           0 :                 return NULL;
     306             :         }
     307             : 
     308    13707758 :         ret = talloc(mem_ctx, struct dom_sid);
     309    13707758 :         if (!ret) {
     310           0 :                 return NULL;
     311             :         }
     312    13707758 :         sid_copy(ret, dom_sid);
     313             : 
     314    13707758 :         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     8056634 : 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     8056634 :         sid = dom_sid_dup(mem_ctx, domain_sid);
     328     8056634 :         if (!sid) return NULL;
     329             : 
     330     8056634 :         if (!sid_append_rid(sid, rid)) {
     331           0 :                 talloc_free(sid);
     332           0 :                 return NULL;
     333             :         }
     334             : 
     335     7298332 :         return sid;
     336             : }
     337             : 
     338             : /*
     339             :   Split up a SID into its domain and RID part
     340             : */
     341     1431271 : NTSTATUS dom_sid_split_rid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
     342             :                            struct dom_sid **domain, uint32_t *rid)
     343             : {
     344     1431271 :         if (sid->num_auths == 0) {
     345      541625 :                 return NT_STATUS_INVALID_PARAMETER;
     346             :         }
     347             : 
     348      889646 :         if (domain) {
     349      220971 :                 if (!(*domain = dom_sid_dup(mem_ctx, sid))) {
     350           0 :                         return NT_STATUS_NO_MEMORY;
     351             :                 }
     352             : 
     353      220971 :                 (*domain)->num_auths -= 1;
     354             :         }
     355             : 
     356      889646 :         if (rid) {
     357      782882 :                 *rid = sid->sub_auths[sid->num_auths - 1];
     358             :         }
     359             : 
     360      889646 :         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     3727829 : bool dom_sid_in_domain(const struct dom_sid *domain_sid,
     367             :                        const struct dom_sid *sid)
     368             : {
     369      493165 :         int i;
     370             : 
     371     3727829 :         if (!domain_sid || !sid) {
     372       89707 :                 return false;
     373             :         }
     374             : 
     375     3232710 :         if (sid->num_auths < 2) {
     376      936817 :                 return false;
     377             :         }
     378             : 
     379     2276794 :         if (domain_sid->num_auths != (sid->num_auths - 1)) {
     380      414262 :                 return false;
     381             :         }
     382             : 
     383     8435820 :         for (i = domain_sid->num_auths-1; i >= 0; --i) {
     384     6746472 :                 if (domain_sid->sub_auths[i] != sid->sub_auths[i]) {
     385      156595 :                         return false;
     386             :                 }
     387             :         }
     388             : 
     389     1689348 :         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    17660995 : static int dom_sid_string_buf(const struct dom_sid *sid, char *buf, int buflen)
     498             : {
     499      384569 :         int i, ofs, ret;
     500      384569 :         uint64_t ia;
     501             : 
     502    17660995 :         if (!sid) {
     503          42 :                 return strlcpy(buf, "(NULL SID)", buflen);
     504             :         }
     505             : 
     506    17660953 :         ia = ((uint64_t)sid->id_auth[5]) +
     507    17660953 :                 ((uint64_t)sid->id_auth[4] << 8 ) +
     508    17660953 :                 ((uint64_t)sid->id_auth[3] << 16) +
     509    17660953 :                 ((uint64_t)sid->id_auth[2] << 24) +
     510    17660953 :                 ((uint64_t)sid->id_auth[1] << 32) +
     511    17660953 :                 ((uint64_t)sid->id_auth[0] << 40);
     512             : 
     513    17660953 :         ret = snprintf(buf, buflen, "S-%"PRIu8"-", sid->sid_rev_num);
     514    17660953 :         if (ret < 0) {
     515           0 :                 return ret;
     516             :         }
     517    17660953 :         ofs = ret;
     518             : 
     519    17660953 :         if (ia >= UINT32_MAX) {
     520          31 :                 ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "0x%"PRIx64, ia);
     521             :         } else {
     522    17660922 :                 ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "%"PRIu64, ia);
     523             :         }
     524    17660953 :         if (ret < 0) {
     525           0 :                 return ret;
     526             :         }
     527    17660953 :         ofs += ret;
     528             : 
     529    83239439 :         for (i = 0; i < sid->num_auths; i++) {
     530    65578486 :                 ret = snprintf(
     531             :                         buf+ofs,
     532    65578486 :                         MAX(buflen-ofs, 0),
     533             :                         "-%"PRIu32,
     534    65578486 :                         sid->sub_auths[i]);
     535    65578486 :                 if (ret < 0) {
     536           0 :                         return ret;
     537             :                 }
     538    65578486 :                 ofs += ret;
     539             :         }
     540    17276386 :         return ofs;
     541             : }
     542             : 
     543             : /*
     544             :   convert a dom_sid to a string
     545             : */
     546     8062711 : char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
     547             : {
     548      125748 :         char buf[DOM_SID_STR_BUFLEN];
     549      125748 :         char *result;
     550      125748 :         int len;
     551             : 
     552     8062711 :         len = dom_sid_string_buf(sid, buf, sizeof(buf));
     553             : 
     554     8062711 :         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     8062711 :         result = (char *)talloc_memdup(mem_ctx, buf, len+1);
     563     8062711 :         if (result == NULL) {
     564           0 :                 return NULL;
     565             :         }
     566             : 
     567             :         /*
     568             :          * beautify the talloc_report output
     569             :          */
     570     8062711 :         talloc_set_name_const(result, result);
     571     8062711 :         return result;
     572             : }
     573             : 
     574     9598284 : char *dom_sid_str_buf(const struct dom_sid *sid, struct dom_sid_buf *dst)
     575             : {
     576      258821 :         int ret;
     577     9598284 :         ret = dom_sid_string_buf(sid, dst->buf, sizeof(dst->buf));
     578     9598284 :         if ((ret < 0) || (ret >= sizeof(dst->buf))) {
     579           0 :                 strlcpy(dst->buf, "(INVALID SID)", sizeof(dst->buf));
     580             :         }
     581     9598284 :         return dst->buf;
     582             : }

Generated by: LCOV version 1.14