LCOV - code coverage report
Current view: top level - libcli/security - dom_sid.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 216 261 82.8 %
Date: 2024-05-31 13:13:24 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             : #include "lib/util/tsort.h"
      32             : 
      33             : /*****************************************************************
      34             :  Compare the auth portion of two sids.
      35             : *****************************************************************/
      36             : 
      37   145391493 : int dom_sid_compare_auth(const struct dom_sid *sid1,
      38             :                          const struct dom_sid *sid2)
      39             : {
      40     7880807 :         int i;
      41             : 
      42   145391493 :         if (sid1 == sid2)
      43           0 :                 return 0;
      44   145391493 :         if (!sid1)
      45           0 :                 return -1;
      46   145391493 :         if (!sid2)
      47           0 :                 return 1;
      48             : 
      49   145391493 :         if (sid1->sid_rev_num != sid2->sid_rev_num)
      50        1036 :                 return NUMERIC_CMP(sid1->sid_rev_num, sid2->sid_rev_num);
      51             : 
      52  1015805505 :         for (i = 0; i < 6; i++)
      53   872342742 :                 if (sid1->id_auth[i] != sid2->id_auth[i]) {
      54     1927694 :                         return NUMERIC_CMP(sid1->id_auth[i], sid2->id_auth[i]);
      55             :                 }
      56             : 
      57   135703917 :         return 0;
      58             : }
      59             : 
      60             : /*****************************************************************
      61             :  Compare two sids.
      62             : *****************************************************************/
      63             : 
      64  1363645456 : int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *sid2)
      65             : {
      66    66655460 :         int i;
      67             : 
      68  1363645456 :         if (sid1 == sid2)
      69       44655 :                 return 0;
      70  1363598431 :         if (!sid1)
      71          12 :                 return -1;
      72  1363598419 :         if (!sid2)
      73     5641356 :                 return 1;
      74             : 
      75             :         /* Compare most likely different rids, first: i.e start at end */
      76  1357907790 :         if (sid1->num_auths != sid2->num_auths) {
      77   966454592 :                 return NUMERIC_CMP(sid1->num_auths, sid2->num_auths);
      78             :         }
      79   608708070 :         for (i = sid1->num_auths-1; i >= 0; --i) {
      80   465688260 :                 if (sid1->sub_auths[i] < sid2->sub_auths[i]) {
      81   172883857 :                         return -1;
      82             :                 }
      83   284368225 :                 if (sid1->sub_auths[i] > sid2->sub_auths[i]) {
      84    65414942 :                         return 1;
      85             :                 }
      86             :         }
      87             : 
      88   143019810 :         return dom_sid_compare_auth(sid1, sid2);
      89             : }
      90             : 
      91             : /*****************************************************************
      92             :  Compare two sids.
      93             : *****************************************************************/
      94             : 
      95  1362851647 : bool dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2)
      96             : {
      97  1362851647 :         return dom_sid_compare(sid1, sid2) == 0;
      98             : }
      99             : 
     100             : /*****************************************************************
     101             :  Add a rid to the end of a sid
     102             : *****************************************************************/
     103             : 
     104    90728552 : bool sid_append_rid(struct dom_sid *sid, uint32_t rid)
     105             : {
     106    90728552 :         if (sid->num_auths < ARRAY_SIZE(sid->sub_auths)) {
     107    90728551 :                 sid->sub_auths[sid->num_auths++] = rid;
     108    90728551 :                 return true;
     109             :         }
     110           0 :         return false;
     111             : }
     112             : 
     113             : /*
     114             :   See if 2 SIDs are in the same domain
     115             :   this just compares the leading sub-auths
     116             : */
     117     1990875 : int dom_sid_compare_domain(const struct dom_sid *sid1,
     118             :                            const struct dom_sid *sid2)
     119             : {
     120        7524 :         int n, i;
     121             : 
     122     1990875 :         n = MIN(sid1->num_auths, sid2->num_auths);
     123             : 
     124     2797982 :         for (i = n-1; i >= 0; --i) {
     125     2471863 :                 if (sid1->sub_auths[i] < sid2->sub_auths[i]) {
     126      631410 :                         return -1;
     127             :                 }
     128     1836659 :                 if (sid1->sub_auths[i] > sid2->sub_auths[i]) {
     129     1026141 :                         return 1;
     130             :                 }
     131             :         }
     132             : 
     133      326119 :         return dom_sid_compare_auth(sid1, sid2);
     134             : }
     135             : 
     136             : /*****************************************************************
     137             :  Convert a string to a SID. Returns True on success, False on fail.
     138             :  Return the first character not parsed in endp.
     139             : *****************************************************************/
     140             : #define AUTHORITY_MASK (~(0xffffffffffffULL))
     141             : 
     142    21760616 : bool dom_sid_parse_endp(const char *sidstr,struct dom_sid *sidout,
     143             :                         const char **endp)
     144             : {
     145      719045 :         const char *p;
     146    21760616 :         char *q = NULL;
     147    21760616 :         char *end = NULL;
     148      719045 :         uint64_t conv;
     149    21760616 :         int error = 0;
     150             : 
     151    21760616 :         *sidout = (struct dom_sid) {};
     152             : 
     153    21760616 :         if ((sidstr[0] != 'S' && sidstr[0] != 's') || sidstr[1] != '-') {
     154        9903 :                 goto format_error;
     155             :         }
     156             : 
     157             :         /* Get the revision number. */
     158    21750713 :         p = sidstr + 2;
     159             : 
     160    21750713 :         if (!isdigit((unsigned char)*p)) {
     161           1 :                 goto format_error;
     162             :         }
     163             : 
     164    21750712 :         conv = smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
     165    21750712 :         if (error != 0 || (*q != '-') || conv > UINT8_MAX || q - p > 4) {
     166         113 :                 goto format_error;
     167             :         }
     168    21750599 :         sidout->sid_rev_num = (uint8_t) conv;
     169    21750599 :         q++;
     170             : 
     171    21750599 :         if (!isdigit((unsigned char)*q)) {
     172           0 :                 goto format_error;
     173             :         }
     174    21750819 :         while (q[0] == '0' && isdigit((unsigned char)q[1])) {
     175             :                 /*
     176             :                  * strtoull will think this is octal, which is not how SIDs
     177             :                  * work! So let's walk along until there are no leading zeros
     178             :                  * (or a single zero).
     179             :                  */
     180         220 :                 q++;
     181             :         }
     182             : 
     183             :         /* get identauth */
     184    21750599 :         conv = smb_strtoull(q, &end, 0, &error, SMB_STR_STANDARD);
     185    21750599 :         if (conv & AUTHORITY_MASK || error != 0) {
     186          22 :                 goto format_error;
     187             :         }
     188    21750577 :         if (conv >= (1ULL << 48) || end - q > 15) {
     189             :                 /*
     190             :                  * This identauth looks like a big number, but resolves to a
     191             :                  * small number after rounding.
     192             :                  */
     193           0 :                 goto format_error;
     194             :         }
     195             : 
     196             :         /* NOTE - the conv value is in big-endian format. */
     197    21750577 :         sidout->id_auth[0] = (conv & 0xff0000000000ULL) >> 40;
     198    21750577 :         sidout->id_auth[1] = (conv & 0x00ff00000000ULL) >> 32;
     199    21750577 :         sidout->id_auth[2] = (conv & 0x0000ff000000ULL) >> 24;
     200    21750577 :         sidout->id_auth[3] = (conv & 0x000000ff0000ULL) >> 16;
     201    21750577 :         sidout->id_auth[4] = (conv & 0x00000000ff00ULL) >> 8;
     202    21750577 :         sidout->id_auth[5] = (conv & 0x0000000000ffULL);
     203             : 
     204    21750577 :         sidout->num_auths = 0;
     205    21750577 :         q = end;
     206    21750577 :         if (*q != '-') {
     207             :                 /* Just id_auth, no subauths */
     208       11810 :                 goto done;
     209             :         }
     210             : 
     211    21738767 :         q++;
     212             : 
     213     2818320 :         while (true) {
     214    80757647 :                 if (!isdigit((unsigned char)*q)) {
     215          22 :                         goto format_error;
     216             :                 }
     217    80757840 :                 while (q[0] == '0' && isdigit((unsigned char)q[1])) {
     218             :                         /*
     219             :                          * strtoull will think this is octal, which is not how
     220             :                          * SIDs work! So let's walk along until there are no
     221             :                          * leading zeros (or a single zero).
     222             :                          */
     223         215 :                         q++;
     224             :                 }
     225    80757625 :                 conv = smb_strtoull(q, &end, 0, &error, SMB_STR_STANDARD);
     226    80757625 :                 if (conv > UINT32_MAX || error != 0 || end - q > 12) {
     227             :                         /*
     228             :                          * This sub-auth is greater than 4294967295,
     229             :                          * and hence invalid. Windows will treat it as
     230             :                          * 4294967295, while we prefer to refuse (old
     231             :                          * versions of Samba will wrap, arriving at
     232             :                          * another number altogether).
     233             :                          */
     234         100 :                         DBG_NOTICE("bad sub-auth in %s\n", sidstr);
     235         100 :                         goto format_error;
     236             :                 }
     237             : 
     238    80757525 :                 if (!sid_append_rid(sidout, conv)) {
     239           1 :                         DEBUG(3, ("Too many sid auths in %s\n", sidstr));
     240           1 :                         return false;
     241             :                 }
     242             : 
     243    80757524 :                 q = end;
     244    80757524 :                 if (*q != '-') {
     245    21020061 :                         break;
     246             :                 }
     247    59018880 :                 q += 1;
     248             :         }
     249    21750011 : done:
     250    21750454 :         if (endp != NULL) {
     251      307549 :                 *endp = q;
     252             :         }
     253    21031428 :         return true;
     254             : 
     255       10161 : format_error:
     256       10161 :         DEBUG(3, ("string_to_sid: SID %s is not in a valid format\n", sidstr));
     257       10143 :         return false;
     258             : }
     259             : 
     260     4716273 : bool string_to_sid(struct dom_sid *sidout, const char *sidstr)
     261             : {
     262     4716273 :         return dom_sid_parse(sidstr, sidout);
     263             : }
     264             : 
     265    21452951 : bool dom_sid_parse(const char *sidstr, struct dom_sid *ret)
     266             : {
     267    21452951 :         return dom_sid_parse_endp(sidstr, ret, NULL);
     268             : }
     269             : 
     270             : /*
     271             :   convert a string to a dom_sid, returning a talloc'd dom_sid
     272             : */
     273     4494954 : struct dom_sid *dom_sid_parse_talloc(TALLOC_CTX *mem_ctx, const char *sidstr)
     274             : {
     275      356630 :         struct dom_sid *ret;
     276     4494954 :         ret = talloc(mem_ctx, struct dom_sid);
     277     4494954 :         if (!ret) {
     278           0 :                 return NULL;
     279             :         }
     280     4494954 :         if (!dom_sid_parse(sidstr, ret)) {
     281           4 :                 talloc_free(ret);
     282           4 :                 return NULL;
     283             :         }
     284             : 
     285     4138320 :         return ret;
     286             : }
     287             : 
     288             : /*
     289             :   convert a string to a dom_sid, returning a talloc'd dom_sid
     290             : */
     291           0 : struct dom_sid *dom_sid_parse_length(TALLOC_CTX *mem_ctx, const DATA_BLOB *sid)
     292           0 : {
     293           0 :         char p[sid->length+1];
     294           0 :         memcpy(p, sid->data, sid->length);
     295           0 :         p[sid->length] = '\0';
     296           0 :         return dom_sid_parse_talloc(mem_ctx, p);
     297             : }
     298             : 
     299             : /*
     300             :   copy a dom_sid structure
     301             : */
     302    13790487 : struct dom_sid *dom_sid_dup(TALLOC_CTX *mem_ctx, const struct dom_sid *dom_sid)
     303             : {
     304      988752 :         struct dom_sid *ret;
     305             : 
     306    13790487 :         if (!dom_sid) {
     307           0 :                 return NULL;
     308             :         }
     309             : 
     310    13790487 :         ret = talloc(mem_ctx, struct dom_sid);
     311    13790487 :         if (!ret) {
     312           0 :                 return NULL;
     313             :         }
     314    13790487 :         sid_copy(ret, dom_sid);
     315             : 
     316    13790487 :         return ret;
     317             : }
     318             : 
     319             : /*
     320             :   add a rid to a domain dom_sid to make a full dom_sid. This function
     321             :   returns a new sid in the supplied memory context
     322             : */
     323     8124388 : struct dom_sid *dom_sid_add_rid(TALLOC_CTX *mem_ctx,
     324             :                                 const struct dom_sid *domain_sid,
     325             :                                 uint32_t rid)
     326             : {
     327      758522 :         struct dom_sid *sid;
     328             : 
     329     8124388 :         sid = dom_sid_dup(mem_ctx, domain_sid);
     330     8124388 :         if (!sid) return NULL;
     331             : 
     332     8124388 :         if (!sid_append_rid(sid, rid)) {
     333           0 :                 talloc_free(sid);
     334           0 :                 return NULL;
     335             :         }
     336             : 
     337     7365866 :         return sid;
     338             : }
     339             : 
     340             : /*
     341             :   Split up a SID into its domain and RID part
     342             : */
     343     1453658 : NTSTATUS dom_sid_split_rid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
     344             :                            struct dom_sid **domain, uint32_t *rid)
     345             : {
     346     1453658 :         if (sid->num_auths == 0) {
     347      552847 :                 return NT_STATUS_INVALID_PARAMETER;
     348             :         }
     349             : 
     350      900811 :         if (domain) {
     351      222985 :                 if (!(*domain = dom_sid_dup(mem_ctx, sid))) {
     352           0 :                         return NT_STATUS_NO_MEMORY;
     353             :                 }
     354             : 
     355      222985 :                 (*domain)->num_auths -= 1;
     356             :         }
     357             : 
     358      900811 :         if (rid) {
     359      793329 :                 *rid = sid->sub_auths[sid->num_auths - 1];
     360             :         }
     361             : 
     362      900811 :         return NT_STATUS_OK;
     363             : }
     364             : 
     365             : /*
     366             :   return true if the 2nd sid is in the domain given by the first sid
     367             : */
     368     3724826 : bool dom_sid_in_domain(const struct dom_sid *domain_sid,
     369             :                        const struct dom_sid *sid)
     370             : {
     371      493641 :         int i;
     372             : 
     373     3724826 :         if (!domain_sid || !sid) {
     374       82398 :                 return false;
     375             :         }
     376             : 
     377     3236932 :         if (sid->num_auths < 2) {
     378      939605 :                 return false;
     379             :         }
     380             : 
     381     2278172 :         if (domain_sid->num_auths != (sid->num_auths - 1)) {
     382      409382 :                 return false;
     383             :         }
     384             : 
     385     8457972 :         for (i = domain_sid->num_auths-1; i >= 0; --i) {
     386     6764607 :                 if (domain_sid->sub_auths[i] != sid->sub_auths[i]) {
     387      158780 :                         return false;
     388             :                 }
     389             :         }
     390             : 
     391     1693365 :         return dom_sid_compare_auth(domain_sid, sid) == 0;
     392             : }
     393             : 
     394         172 : bool dom_sid_has_account_domain(const struct dom_sid *sid)
     395             : {
     396         172 :         if (sid == NULL) {
     397           0 :                 return false;
     398             :         }
     399             : 
     400         172 :         if (sid->sid_rev_num != 1) {
     401           0 :                 return false;
     402             :         }
     403         172 :         if (sid->num_auths != 5) {
     404         102 :                 return false;
     405             :         }
     406          70 :         if (sid->id_auth[5] != 5) {
     407           0 :                 return false;
     408             :         }
     409          70 :         if (sid->id_auth[4] != 0) {
     410           0 :                 return false;
     411             :         }
     412          70 :         if (sid->id_auth[3] != 0) {
     413           0 :                 return false;
     414             :         }
     415          70 :         if (sid->id_auth[2] != 0) {
     416           0 :                 return false;
     417             :         }
     418          70 :         if (sid->id_auth[1] != 0) {
     419           0 :                 return false;
     420             :         }
     421          70 :         if (sid->id_auth[0] != 0) {
     422           0 :                 return false;
     423             :         }
     424          70 :         if (sid->sub_auths[0] != 21) {
     425           2 :                 return false;
     426             :         }
     427             : 
     428          68 :         return true;
     429             : }
     430             : 
     431         176 : bool dom_sid_is_valid_account_domain(const struct dom_sid *sid)
     432             : {
     433             :         /*
     434             :          * We expect S-1-5-21-9-8-7, but we don't
     435             :          * allow S-1-5-21-0-0-0 as this is used
     436             :          * for claims and compound identities.
     437             :          *
     438             :          * With this structure:
     439             :          *
     440             :          * struct dom_sid {
     441             :          *     uint8_t sid_rev_num;
     442             :          *     int8_t num_auths; [range(0,15)]
     443             :          *     uint8_t id_auth[6];
     444             :          *     uint32_t sub_auths[15];
     445             :          * }
     446             :          *
     447             :          * S-1-5-21-9-8-7 looks like this:
     448             :          * {1, 4, {0,0,0,0,0,5}, {21,9,8,7,0,0,0,0,0,0,0,0,0,0,0}};
     449             :          */
     450         176 :         if (sid == NULL) {
     451           0 :                 return false;
     452             :         }
     453             : 
     454         176 :         if (sid->sid_rev_num != 1) {
     455           0 :                 return false;
     456             :         }
     457         176 :         if (sid->num_auths != 4) {
     458           0 :                 return false;
     459             :         }
     460         176 :         if (sid->id_auth[5] != 5) {
     461           0 :                 return false;
     462             :         }
     463         176 :         if (sid->id_auth[4] != 0) {
     464           0 :                 return false;
     465             :         }
     466         176 :         if (sid->id_auth[3] != 0) {
     467           0 :                 return false;
     468             :         }
     469         176 :         if (sid->id_auth[2] != 0) {
     470           0 :                 return false;
     471             :         }
     472         176 :         if (sid->id_auth[1] != 0) {
     473           0 :                 return false;
     474             :         }
     475         176 :         if (sid->id_auth[0] != 0) {
     476           0 :                 return false;
     477             :         }
     478         176 :         if (sid->sub_auths[0] != 21) {
     479           0 :                 return false;
     480             :         }
     481         176 :         if (sid->sub_auths[1] == 0) {
     482           0 :                 return false;
     483             :         }
     484         176 :         if (sid->sub_auths[2] == 0) {
     485           0 :                 return false;
     486             :         }
     487         176 :         if (sid->sub_auths[3] == 0) {
     488           0 :                 return false;
     489             :         }
     490             : 
     491         176 :         return true;
     492             : }
     493             : 
     494             : /*
     495             :   Convert a dom_sid to a string, printing into a buffer. Return the
     496             :   string length. If it overflows, return the string length that would
     497             :   result (buflen needs to be +1 for the terminating 0).
     498             : */
     499    17839858 : static int dom_sid_string_buf(const struct dom_sid *sid, char *buf, int buflen)
     500             : {
     501      386938 :         int i, ofs, ret;
     502      386938 :         uint64_t ia;
     503             : 
     504    17839858 :         if (!sid) {
     505          42 :                 return strlcpy(buf, "(NULL SID)", buflen);
     506             :         }
     507             : 
     508    17839816 :         ia = ((uint64_t)sid->id_auth[5]) +
     509    17839816 :                 ((uint64_t)sid->id_auth[4] << 8 ) +
     510    17839816 :                 ((uint64_t)sid->id_auth[3] << 16) +
     511    17839816 :                 ((uint64_t)sid->id_auth[2] << 24) +
     512    17839816 :                 ((uint64_t)sid->id_auth[1] << 32) +
     513    17839816 :                 ((uint64_t)sid->id_auth[0] << 40);
     514             : 
     515    17839816 :         ret = snprintf(buf, buflen, "S-%"PRIu8"-", sid->sid_rev_num);
     516    17839816 :         if (ret < 0) {
     517           0 :                 return ret;
     518             :         }
     519    17839816 :         ofs = ret;
     520             : 
     521    17839816 :         if (ia >= UINT32_MAX) {
     522          31 :                 ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "0x%"PRIx64, ia);
     523             :         } else {
     524    17839785 :                 ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "%"PRIu64, ia);
     525             :         }
     526    17839816 :         if (ret < 0) {
     527           0 :                 return ret;
     528             :         }
     529    17839816 :         ofs += ret;
     530             : 
     531    83944249 :         for (i = 0; i < sid->num_auths; i++) {
     532    66104433 :                 ret = snprintf(
     533             :                         buf+ofs,
     534    66104433 :                         MAX(buflen-ofs, 0),
     535             :                         "-%"PRIu32,
     536    66104433 :                         sid->sub_auths[i]);
     537    66104433 :                 if (ret < 0) {
     538           0 :                         return ret;
     539             :                 }
     540    66104433 :                 ofs += ret;
     541             :         }
     542    17452880 :         return ofs;
     543             : }
     544             : 
     545             : /*
     546             :   convert a dom_sid to a string
     547             : */
     548     8135799 : char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
     549             : {
     550      126878 :         char buf[DOM_SID_STR_BUFLEN];
     551      126878 :         char *result;
     552      126878 :         int len;
     553             : 
     554     8135799 :         len = dom_sid_string_buf(sid, buf, sizeof(buf));
     555             : 
     556     8135799 :         if ((len < 0) || (len+1 > sizeof(buf))) {
     557           0 :                 return talloc_strdup(mem_ctx, "(SID ERR)");
     558             :         }
     559             : 
     560             :         /*
     561             :          * Avoid calling strlen (via talloc_strdup), we already have
     562             :          * the length
     563             :          */
     564     8135799 :         result = (char *)talloc_memdup(mem_ctx, buf, len+1);
     565     8135799 :         if (result == NULL) {
     566           0 :                 return NULL;
     567             :         }
     568             : 
     569             :         /*
     570             :          * beautify the talloc_report output
     571             :          */
     572     8135799 :         talloc_set_name_const(result, result);
     573     8135799 :         return result;
     574             : }
     575             : 
     576     9704059 : char *dom_sid_str_buf(const struct dom_sid *sid, struct dom_sid_buf *dst)
     577             : {
     578      260060 :         int ret;
     579     9704059 :         ret = dom_sid_string_buf(sid, dst->buf, sizeof(dst->buf));
     580     9704059 :         if ((ret < 0) || (ret >= sizeof(dst->buf))) {
     581           0 :                 strlcpy(dst->buf, "(INVALID SID)", sizeof(dst->buf));
     582             :         }
     583     9704059 :         return dst->buf;
     584             : }

Generated by: LCOV version 1.14