libcli/security: Prohibit SID formats like S-1-5-32-+545
[ira/wip.git] / libcli / security / dom_sid.c
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 "includes.h"
24 #include "librpc/gen_ndr/security.h"
25 #include "dom_sid.h"
26
27 /*****************************************************************
28  Compare the auth portion of two sids.
29 *****************************************************************/
30
31 static int dom_sid_compare_auth(const struct dom_sid *sid1,
32                                 const struct dom_sid *sid2)
33 {
34         int i;
35
36         if (sid1 == sid2)
37                 return 0;
38         if (!sid1)
39                 return -1;
40         if (!sid2)
41                 return 1;
42
43         if (sid1->sid_rev_num != sid2->sid_rev_num)
44                 return sid1->sid_rev_num - sid2->sid_rev_num;
45
46         for (i = 0; i < 6; i++)
47                 if (sid1->id_auth[i] != sid2->id_auth[i])
48                         return sid1->id_auth[i] - sid2->id_auth[i];
49
50         return 0;
51 }
52
53 /*****************************************************************
54  Compare two sids.
55 *****************************************************************/
56
57 int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *sid2)
58 {
59         int i;
60
61         if (sid1 == sid2)
62                 return 0;
63         if (!sid1)
64                 return -1;
65         if (!sid2)
66                 return 1;
67
68         /* Compare most likely different rids, first: i.e start at end */
69         if (sid1->num_auths != sid2->num_auths)
70                 return sid1->num_auths - sid2->num_auths;
71
72         for (i = sid1->num_auths-1; i >= 0; --i)
73                 if (sid1->sub_auths[i] != sid2->sub_auths[i])
74                         return sid1->sub_auths[i] - sid2->sub_auths[i];
75
76         return dom_sid_compare_auth(sid1, sid2);
77 }
78
79 /*****************************************************************
80  Compare two sids.
81 *****************************************************************/
82
83 bool dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2)
84 {
85         return dom_sid_compare(sid1, sid2) == 0;
86 }
87
88 bool dom_sid_parse(const char *sidstr, struct dom_sid *ret)
89 {
90         uint_t rev, ia, num_sub_auths, i;
91         char *p;
92
93         if ((sidstr[0] != 'S' && sidstr[0] != 's') || sidstr[1] != '-') {
94                 return false;
95         }
96
97         sidstr += 2;
98
99         if (!isdigit(sidstr[0])) {
100                 return false;
101         }
102
103         rev = strtoul(sidstr, &p, 10);
104         if (*p != '-') {
105                 return false;
106         }
107         sidstr = p+1;
108
109         if (!isdigit(sidstr[0])) {
110                 return false;
111         }
112
113         ia = strtoul(sidstr, &p, 10);
114         if (p == sidstr) {
115                 return false;
116         }
117         sidstr = p;
118
119         num_sub_auths = 0;
120         for (i=0;sidstr[i];i++) {
121                 if (sidstr[i] == '-') num_sub_auths++;
122         }
123
124         if (num_sub_auths > ARRAY_SIZE(ret->sub_auths)) {
125                 return false;
126         }
127
128         ret->sid_rev_num = rev;
129         ret->id_auth[0] = 0;
130         ret->id_auth[1] = 0;
131         ret->id_auth[2] = ia >> 24;
132         ret->id_auth[3] = ia >> 16;
133         ret->id_auth[4] = ia >> 8;
134         ret->id_auth[5] = ia;
135         ret->num_auths = num_sub_auths;
136
137         for (i=0;i<num_sub_auths;i++) {
138                 if (sidstr[0] != '-') {
139                         return false;
140                 }
141                 sidstr++;
142
143                 if (!isdigit(sidstr[0])) {
144                         return false;
145                 }
146
147                 ret->sub_auths[i] = strtoul(sidstr, &p, 10);
148                 if (p == sidstr) {
149                         return false;
150                 }
151                 sidstr = p;
152         }
153
154         return true;
155 }
156
157 /*
158   convert a string to a dom_sid, returning a talloc'd dom_sid
159 */
160 struct dom_sid *dom_sid_parse_talloc(TALLOC_CTX *mem_ctx, const char *sidstr)
161 {
162         struct dom_sid *ret;
163         ret = talloc(mem_ctx, struct dom_sid);
164         if (!ret) {
165                 return NULL;
166         }
167         if (!dom_sid_parse(sidstr, ret)) {
168                 talloc_free(ret);
169                 return NULL;
170         }
171
172         return ret;
173 }
174
175 /*
176   convert a string to a dom_sid, returning a talloc'd dom_sid
177 */
178 struct dom_sid *dom_sid_parse_length(TALLOC_CTX *mem_ctx, const DATA_BLOB *sid)
179 {
180         struct dom_sid *ret;
181         char *p = talloc_strndup(mem_ctx, (char *)sid->data, sid->length);
182         if (!p) {
183                 return NULL;
184         }
185         ret = dom_sid_parse_talloc(mem_ctx, p);
186         talloc_free(p);
187         return ret;
188 }
189
190 /*
191   copy a dom_sid structure
192 */
193 struct dom_sid *dom_sid_dup(TALLOC_CTX *mem_ctx, const struct dom_sid *dom_sid)
194 {
195         struct dom_sid *ret;
196         int i;
197
198         if (!dom_sid) {
199                 return NULL;
200         }
201
202         ret = talloc(mem_ctx, struct dom_sid);
203         if (!ret) {
204                 return NULL;
205         }
206
207         ret->sid_rev_num = dom_sid->sid_rev_num;
208         ret->id_auth[0] = dom_sid->id_auth[0];
209         ret->id_auth[1] = dom_sid->id_auth[1];
210         ret->id_auth[2] = dom_sid->id_auth[2];
211         ret->id_auth[3] = dom_sid->id_auth[3];
212         ret->id_auth[4] = dom_sid->id_auth[4];
213         ret->id_auth[5] = dom_sid->id_auth[5];
214         ret->num_auths = dom_sid->num_auths;
215
216         for (i=0;i<dom_sid->num_auths;i++) {
217                 ret->sub_auths[i] = dom_sid->sub_auths[i];
218         }
219
220         return ret;
221 }
222
223 /*
224   add a rid to a domain dom_sid to make a full dom_sid. This function
225   returns a new sid in the supplied memory context
226 */
227 struct dom_sid *dom_sid_add_rid(TALLOC_CTX *mem_ctx,
228                                 const struct dom_sid *domain_sid,
229                                 uint32_t rid)
230 {
231         struct dom_sid *sid;
232
233         sid = talloc(mem_ctx, struct dom_sid);
234         if (!sid) return NULL;
235
236         *sid = *domain_sid;
237
238         sid->sub_auths[sid->num_auths] = rid;
239         sid->num_auths++;
240
241         return sid;
242 }
243
244 /*
245   Split up a SID into its domain and RID part
246 */
247 NTSTATUS dom_sid_split_rid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
248                            struct dom_sid **domain, uint32_t *rid)
249 {
250         if (sid->num_auths == 0) {
251                 return NT_STATUS_INVALID_PARAMETER;
252         }
253
254         if (domain) {
255                 if (!(*domain = dom_sid_dup(mem_ctx, sid))) {
256                         return NT_STATUS_NO_MEMORY;
257                 }
258
259                 (*domain)->num_auths -= 1;
260         }
261
262         if (rid) {
263                 *rid = sid->sub_auths[sid->num_auths - 1];
264         }
265
266         return NT_STATUS_OK;
267 }
268
269 /*
270   return true if the 2nd sid is in the domain given by the first sid
271 */
272 bool dom_sid_in_domain(const struct dom_sid *domain_sid,
273                        const struct dom_sid *sid)
274 {
275         int i;
276
277         if (!domain_sid || !sid) {
278                 return false;
279         }
280
281         if (domain_sid->num_auths > sid->num_auths) {
282                 return false;
283         }
284
285         for (i = domain_sid->num_auths-1; i >= 0; --i) {
286                 if (domain_sid->sub_auths[i] != sid->sub_auths[i]) {
287                         return false;
288                 }
289         }
290
291         return dom_sid_compare_auth(domain_sid, sid) == 0;
292 }
293
294 /*
295   convert a dom_sid to a string
296 */
297 char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
298 {
299         int i, ofs, maxlen;
300         uint32_t ia;
301         char *ret;
302
303         if (!sid) {
304                 return talloc_strdup(mem_ctx, "(NULL SID)");
305         }
306
307         maxlen = sid->num_auths * 11 + 25;
308         ret = talloc_array(mem_ctx, char, maxlen);
309         if (!ret) return talloc_strdup(mem_ctx, "(SID ERR)");
310
311         ia = (sid->id_auth[5]) +
312                 (sid->id_auth[4] << 8 ) +
313                 (sid->id_auth[3] << 16) +
314                 (sid->id_auth[2] << 24);
315
316         ofs = snprintf(ret, maxlen, "S-%u-%lu",
317                        (unsigned int)sid->sid_rev_num, (unsigned long)ia);
318
319         for (i = 0; i < sid->num_auths; i++) {
320                 ofs += snprintf(ret + ofs, maxlen - ofs, "-%lu",
321                                 (unsigned long)sid->sub_auths[i]);
322         }
323
324         return ret;
325 }