Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : fast routines for getting the wire size of security objects
5 :
6 : Copyright (C) Andrew Tridgell 2003
7 : Copyright (C) Stefan Metzmacher 2006-2008
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 :
24 : #include "includes.h"
25 : #include "librpc/gen_ndr/ndr_security.h"
26 : #include "../libcli/security/security.h"
27 :
28 :
29 : /*
30 : * Find the wire size of a security_ace that has no trailing coda.
31 : * This is used in ndr_pull_security_ace() generated from security.idl
32 : * to work out where the coda starts (and in ndr_size_security_ace()
33 : * just below).
34 : */
35 82399039 : static size_t ndr_size_security_ace_core(const struct security_ace *ace, libndr_flags flags)
36 : {
37 3102512 : size_t ret;
38 :
39 82399039 : if (!ace) return 0;
40 :
41 82399039 : ret = 8 + ndr_size_dom_sid(&ace->trustee, flags);
42 82399039 : if (sec_ace_object(ace->type)) {
43 43489280 : ret += 4; /* uint32 bitmap ace->object.object.flags */
44 43489280 : if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
45 39434741 : ret += 16; /* GUID ace->object.object.type.type */
46 : }
47 43489280 : if (ace->object.object.flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) {
48 28610627 : ret += 16; /* GUID ace->object.object.inherited_type.inherited_type */
49 : }
50 : }
51 :
52 79296527 : return ret;
53 : }
54 :
55 : /*
56 : return the wire size of a security_ace
57 : */
58 82396266 : size_t ndr_size_security_ace(const struct security_ace *ace, libndr_flags flags)
59 : {
60 82396266 : size_t base = ndr_size_security_ace_core(ace, flags);
61 82396266 : size_t ret = base;
62 82396266 : if (sec_ace_callback(ace->type)) {
63 3213 : ret += ace->coda.conditions.length;
64 82393053 : } else if (ace->type == SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE) {
65 231 : ret += ndr_size_security_ace_coda(&ace->coda, ace->type, flags);
66 : } else {
67 : /*
68 : * Normal ACEs have a coda.ignored blob that is always or
69 : * almost always empty. We aren't going to push it (it is
70 : * ignored), so we don't add that length to the size.
71 : */
72 3101648 : }
73 : /* round up to a multiple of 4 (MS-DTYP 2.4.4.1) */
74 82396266 : ret = (ret + 3ULL) & ~3ULL;
75 82396266 : if (unlikely(ret < base)) {
76 : /* overflow, and there's not much we can do anyway */
77 0 : return 0;
78 : }
79 79294618 : return ret;
80 : }
81 :
82 :
83 361473418 : static inline enum ndr_err_code ndr_maybe_pull_security_ace_object_ctr(struct ndr_pull *ndr,
84 : ndr_flags_type ndr_flags,
85 : struct security_ace *r)
86 : {
87 : /*
88 : * If this is not an object ACE (as is usually common),
89 : * ndr_pull_security_ace_object_ctr() will do nothing.
90 : *
91 : * By avoiding calling the function in that case, we avoid some
92 : * tallocing and ndr token busywork.
93 : */
94 361473418 : bool is_object = sec_ace_object(r->type);
95 361473418 : if (is_object) {
96 245515996 : NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->object, is_object));
97 245515996 : NDR_CHECK(ndr_pull_security_ace_object_ctr(ndr, ndr_flags, &r->object));
98 : }
99 348535686 : return NDR_ERR_SUCCESS;
100 : }
101 :
102 :
103 361473418 : _PUBLIC_ enum ndr_err_code ndr_pull_security_ace(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct security_ace *r)
104 : {
105 361473418 : NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
106 361473418 : if (ndr_flags & NDR_SCALARS) {
107 180736709 : NDR_CHECK(ndr_pull_align(ndr, 5));
108 180736709 : NDR_CHECK(ndr_pull_security_ace_type(ndr, NDR_SCALARS, &r->type));
109 180736709 : NDR_CHECK(ndr_pull_security_ace_flags(ndr, NDR_SCALARS, &r->flags));
110 180736709 : NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
111 180736709 : NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->access_mask));
112 180736709 : NDR_CHECK(ndr_maybe_pull_security_ace_object_ctr(ndr, NDR_SCALARS, r));
113 180736709 : NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, &r->trustee));
114 180736709 : if (!sec_ace_has_extra_blob(r->type)) {
115 180735084 : r->coda.ignored.data = NULL;
116 180735084 : r->coda.ignored.length = 0;
117 : } else {
118 433 : struct ndr_pull *_ndr_coda;
119 1625 : ssize_t sub_size = ndr_subcontext_size_of_ace_coda(r, r->size, ndr->flags);
120 1625 : NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_coda, 0, sub_size));
121 1625 : NDR_CHECK(ndr_pull_set_switch_value(_ndr_coda, &r->coda, r->type));
122 1625 : NDR_CHECK(ndr_pull_security_ace_coda(_ndr_coda, NDR_SCALARS|NDR_BUFFERS, &r->coda));
123 1625 : NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_coda, 0, sub_size));
124 : }
125 180736709 : NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
126 : }
127 361473418 : if (ndr_flags & NDR_BUFFERS) {
128 180736709 : NDR_CHECK(ndr_maybe_pull_security_ace_object_ctr(ndr, NDR_BUFFERS, r));
129 : }
130 348535686 : return NDR_ERR_SUCCESS;
131 : }
132 :
133 :
134 76767524 : static inline enum ndr_err_code ndr_maybe_push_security_ace_object_ctr(struct ndr_push *ndr,
135 : ndr_flags_type ndr_flags,
136 : const struct security_ace *r)
137 : {
138 : /*
139 : * ndr_push_security_ace_object_ctr() does nothing (except tallocing
140 : * and ndr_token fiddling) unless the ACE is an object ACE, which is
141 : * usually very unlikely.
142 : */
143 76767524 : bool is_object = sec_ace_object(r->type);
144 76767524 : if (is_object) {
145 43479554 : NDR_CHECK(ndr_push_set_switch_value(ndr, &r->object, is_object));
146 43479554 : NDR_CHECK(ndr_push_security_ace_object_ctr(ndr, ndr_flags, &r->object));
147 : }
148 73680566 : return NDR_ERR_SUCCESS;
149 : }
150 :
151 76767524 : _PUBLIC_ enum ndr_err_code ndr_push_security_ace(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct security_ace *r)
152 : {
153 76767524 : NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
154 76767524 : if (ndr_flags & NDR_SCALARS) {
155 38383762 : NDR_CHECK(ndr_push_align(ndr, 5));
156 38383762 : NDR_CHECK(ndr_push_security_ace_type(ndr, NDR_SCALARS, r->type));
157 38383762 : NDR_CHECK(ndr_push_security_ace_flags(ndr, NDR_SCALARS, r->flags));
158 38383762 : NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, ndr_size_security_ace(r, ndr->flags)));
159 38383762 : NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->access_mask));
160 38383762 : NDR_CHECK(ndr_maybe_push_security_ace_object_ctr(ndr, NDR_SCALARS, r));
161 38383762 : NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS, &r->trustee));
162 38383762 : if (sec_ace_has_extra_blob(r->type)) {
163 431 : struct ndr_push *_ndr_coda;
164 1148 : size_t coda_size = ndr_subcontext_size_of_ace_coda(
165 : r,
166 : ndr_size_security_ace(r, ndr->flags),
167 : ndr->flags);
168 1148 : NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_coda, 0, coda_size));
169 1148 : NDR_CHECK(ndr_push_set_switch_value(_ndr_coda, &r->coda, r->type));
170 1148 : NDR_CHECK(ndr_push_security_ace_coda(_ndr_coda, NDR_SCALARS|NDR_BUFFERS, &r->coda));
171 1148 : NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_coda, 0, coda_size));
172 : }
173 38383762 : NDR_CHECK(ndr_push_trailer_align(ndr, 5));
174 : }
175 76767524 : if (ndr_flags & NDR_BUFFERS) {
176 38383762 : NDR_CHECK(ndr_maybe_push_security_ace_object_ctr(ndr, NDR_BUFFERS, r));
177 : }
178 73680566 : return NDR_ERR_SUCCESS;
179 : }
180 :
181 :
182 : /*
183 : * An ACE coda can't be bigger than the space allowed for by
184 : * ace->size, so we need to check this from the context of the ACE.
185 : *
186 : * Usually the coda also can't be any smaller than the remaining
187 : * space, because it is defined as a blob consuming everything it can.
188 : *
189 : * This is only used to find the size for the coda subcontext in
190 : * security.idl.
191 : */
192 2773 : size_t ndr_subcontext_size_of_ace_coda(const struct security_ace *ace,
193 : size_t ace_size,
194 : libndr_flags flags)
195 : {
196 864 : size_t core_size;
197 2773 : if (ace_size == 0) {
198 0 : return 0;
199 : }
200 2773 : core_size = ndr_size_security_ace_core(ace, flags);
201 2773 : if (ace_size < core_size) {
202 0 : return 0;
203 : }
204 2773 : return ace_size - core_size;
205 : }
206 :
207 : /*
208 : return the wire size of a security_acl
209 : */
210 8270173 : size_t ndr_size_security_acl(const struct security_acl *theacl, libndr_flags flags)
211 : {
212 315780 : size_t ret;
213 315780 : int i;
214 8270173 : if (!theacl) return 0;
215 6442952 : ret = 8;
216 50765217 : for (i=0;i<theacl->num_aces;i++) {
217 44011356 : ret += ndr_size_security_ace(&theacl->aces[i], flags);
218 : }
219 6442952 : return ret;
220 : }
221 :
222 : /*
223 : return the wire size of a security descriptor
224 : */
225 1516590 : size_t ndr_size_security_descriptor(const struct security_descriptor *sd, libndr_flags flags)
226 : {
227 4851 : size_t ret;
228 1516590 : if (!sd) return 0;
229 :
230 1515832 : ret = 20;
231 1515832 : ret += ndr_size_dom_sid(sd->owner_sid, flags);
232 1515832 : ret += ndr_size_dom_sid(sd->group_sid, flags);
233 1515832 : ret += ndr_size_security_acl(sd->dacl, flags);
234 1515832 : ret += ndr_size_security_acl(sd->sacl, flags);
235 1515832 : return ret;
236 : }
237 :
238 : /*
239 : return the wire size of a dom_sid
240 : */
241 105998285 : size_t ndr_size_dom_sid(const struct dom_sid *sid, libndr_flags flags)
242 : {
243 105998285 : if (!sid) return 0;
244 105652042 : return 8 + 4*sid->num_auths;
245 : }
246 :
247 3117313 : size_t ndr_size_dom_sid28(const struct dom_sid *sid, libndr_flags flags)
248 : {
249 3117313 : if (all_zero((const uint8_t *)sid, sizeof(struct dom_sid))) {
250 2781030 : return 0;
251 : }
252 336277 : return ndr_size_dom_sid(sid, flags);
253 : }
254 :
255 574 : size_t ndr_size_dom_sid0(const struct dom_sid *sid, libndr_flags flags)
256 : {
257 574 : return ndr_size_dom_sid28(sid, flags);
258 : }
259 :
260 : /*
261 : print a dom_sid
262 : */
263 45960 : void ndr_print_dom_sid(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
264 : {
265 3961 : struct dom_sid_buf buf;
266 45960 : ndr->print(ndr, "%-25s: %s", name, dom_sid_str_buf(sid, &buf));
267 45960 : }
268 :
269 23974 : void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
270 : {
271 23974 : ndr_print_dom_sid(ndr, name, sid);
272 23974 : }
273 :
274 13970 : void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
275 : {
276 13970 : ndr_print_dom_sid(ndr, name, sid);
277 13970 : }
278 :
279 2 : void ndr_print_dom_sid0(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
280 : {
281 2 : ndr_print_dom_sid(ndr, name, sid);
282 2 : }
283 :
284 :
285 : /*
286 : parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
287 : */
288 599196 : enum ndr_err_code ndr_pull_dom_sid2(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid)
289 : {
290 24143 : uint32_t num_auths;
291 599196 : if (!(ndr_flags & NDR_SCALARS)) {
292 0 : return NDR_ERR_SUCCESS;
293 : }
294 599196 : NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &num_auths));
295 599196 : NDR_CHECK(ndr_pull_dom_sid(ndr, ndr_flags, sid));
296 599196 : if (sid->num_auths != num_auths) {
297 0 : return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
298 : "Bad num_auths %"PRIu32"; should equal %"PRId8,
299 : num_auths, sid->num_auths);
300 : }
301 575053 : return NDR_ERR_SUCCESS;
302 : }
303 :
304 : /*
305 : parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
306 : */
307 437275 : enum ndr_err_code ndr_push_dom_sid2(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid)
308 : {
309 437275 : if (!(ndr_flags & NDR_SCALARS)) {
310 0 : return NDR_ERR_SUCCESS;
311 : }
312 437275 : NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, sid->num_auths));
313 437275 : return ndr_push_dom_sid(ndr, ndr_flags, sid);
314 : }
315 :
316 : /*
317 : parse a dom_sid28 - this is a dom_sid in a fixed 28 byte buffer, so we need to ensure there are only up to 5 sub_auth
318 : */
319 2736004 : enum ndr_err_code ndr_pull_dom_sid28(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid)
320 : {
321 24 : enum ndr_err_code status;
322 24 : struct ndr_pull *subndr;
323 :
324 2736004 : if (!(ndr_flags & NDR_SCALARS)) {
325 1367990 : return NDR_ERR_SUCCESS;
326 : }
327 :
328 1368002 : subndr = talloc_zero(ndr, struct ndr_pull);
329 1368002 : NDR_ERR_HAVE_NO_MEMORY(subndr);
330 1368002 : subndr->flags = ndr->flags;
331 1368002 : subndr->current_mem_ctx = ndr->current_mem_ctx;
332 :
333 1368002 : subndr->data = ndr->data + ndr->offset;
334 1368002 : subndr->data_size = 28;
335 1368002 : subndr->offset = 0;
336 :
337 1368002 : status = ndr_pull_advance(ndr, 28);
338 1368002 : if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
339 0 : talloc_free(subndr);
340 0 : return status;
341 : }
342 :
343 1368002 : status = ndr_pull_dom_sid(subndr, ndr_flags, sid);
344 1368002 : if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
345 : /* handle a w2k bug which send random data in the buffer */
346 1 : ZERO_STRUCTP(sid);
347 1368001 : } else if (sid->num_auths == 0) {
348 1234508 : ZERO_STRUCT(sid->sub_auths);
349 : }
350 :
351 1368002 : talloc_free(subndr);
352 1368002 : return NDR_ERR_SUCCESS;
353 : }
354 :
355 : /*
356 : push a dom_sid28 - this is a dom_sid in a 28 byte fixed buffer
357 : */
358 6233666 : enum ndr_err_code ndr_push_dom_sid28(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid)
359 : {
360 24 : uint32_t old_offset;
361 24 : uint32_t padding;
362 :
363 6233666 : if (!(ndr_flags & NDR_SCALARS)) {
364 3116821 : return NDR_ERR_SUCCESS;
365 : }
366 :
367 3116833 : if (sid->num_auths > 5) {
368 0 : return ndr_push_error(ndr, NDR_ERR_RANGE,
369 : "dom_sid28 allows only up to 5 sub auths [%"PRId8"]",
370 : sid->num_auths);
371 : }
372 :
373 3116833 : old_offset = ndr->offset;
374 3116833 : NDR_CHECK(ndr_push_dom_sid(ndr, ndr_flags, sid));
375 :
376 3116833 : padding = 28 - (ndr->offset - old_offset);
377 :
378 3116833 : if (padding > 0) {
379 2845998 : NDR_CHECK(ndr_push_zero(ndr, padding));
380 : }
381 :
382 3116821 : return NDR_ERR_SUCCESS;
383 : }
384 :
385 : /*
386 : parse a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty
387 : */
388 27 : enum ndr_err_code ndr_pull_dom_sid0(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid)
389 : {
390 27 : if (!(ndr_flags & NDR_SCALARS)) {
391 0 : return NDR_ERR_SUCCESS;
392 : }
393 :
394 27 : if (ndr->data_size == ndr->offset) {
395 0 : ZERO_STRUCTP(sid);
396 0 : return NDR_ERR_SUCCESS;
397 : }
398 :
399 27 : return ndr_pull_dom_sid(ndr, ndr_flags, sid);
400 : }
401 :
402 : /*
403 : push a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty
404 : */
405 16 : enum ndr_err_code ndr_push_dom_sid0(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid)
406 : {
407 16 : if (!(ndr_flags & NDR_SCALARS)) {
408 0 : return NDR_ERR_SUCCESS;
409 : }
410 :
411 16 : if (!sid) {
412 0 : return NDR_ERR_SUCCESS;
413 : }
414 :
415 16 : if (all_zero((const uint8_t *)sid, sizeof(struct dom_sid))) {
416 0 : return NDR_ERR_SUCCESS;
417 : }
418 :
419 16 : return ndr_push_dom_sid(ndr, ndr_flags, sid);
420 : }
421 :
422 115668521 : _PUBLIC_ enum ndr_err_code ndr_push_dom_sid(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *r)
423 : {
424 2495410 : uint32_t cntr_sub_auths_0;
425 115668521 : if (ndr_flags & NDR_SCALARS) {
426 115668521 : NDR_CHECK(ndr_push_align(ndr, 4));
427 115668521 : NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->sid_rev_num));
428 115668521 : NDR_CHECK(ndr_push_int8(ndr, NDR_SCALARS, r->num_auths));
429 115668521 : NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6));
430 115668521 : if (r->num_auths < 0 || r->num_auths > ARRAY_SIZE(r->sub_auths)) {
431 0 : return ndr_push_error(ndr, NDR_ERR_RANGE, "value (%"PRId8") out of range (0 - %zu)", r->num_auths, ARRAY_SIZE(r->sub_auths));
432 : }
433 427637014 : for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < r->num_auths; cntr_sub_auths_0++) {
434 311968493 : NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sub_auths[cntr_sub_auths_0]));
435 : }
436 : }
437 113173111 : return NDR_ERR_SUCCESS;
438 : }
439 :
440 271208757 : _PUBLIC_ enum ndr_err_code ndr_pull_dom_sid(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *r)
441 : {
442 8084679 : uint32_t cntr_sub_auths_0;
443 271208757 : if (ndr_flags & NDR_SCALARS) {
444 271208757 : NDR_CHECK(ndr_pull_align(ndr, 4));
445 271208757 : NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->sid_rev_num));
446 271208372 : NDR_CHECK(ndr_pull_int8(ndr, NDR_SCALARS, &r->num_auths));
447 271208322 : if (r->num_auths < 0 || r->num_auths > ARRAY_SIZE(r->sub_auths)) {
448 6 : return ndr_pull_error(ndr, NDR_ERR_RANGE, "value (%"PRId8") out of range (0 - %zu)", r->num_auths, ARRAY_SIZE(r->sub_auths));
449 : }
450 271208316 : NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6));
451 271208316 : ZERO_STRUCT(r->sub_auths);
452 974727465 : for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < r->num_auths; cntr_sub_auths_0++) {
453 695434475 : NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sub_auths[cntr_sub_auths_0]));
454 : }
455 : }
456 263123642 : return NDR_ERR_SUCCESS;
457 : }
|