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 267220894 : static size_t ndr_size_security_ace_core(const struct security_ace *ace, libndr_flags flags)
36 : {
37 9571097 : size_t ret;
38 :
39 267220894 : if (!ace) return 0;
40 :
41 267220894 : ret = 8 + ndr_size_dom_sid(&ace->trustee, flags);
42 267220894 : if (sec_ace_object(ace->type)) {
43 169188247 : ret += 4; /* uint32 bitmap ace->object.object.flags */
44 169188247 : if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
45 155734287 : ret += 16; /* GUID ace->object.object.type.type */
46 : }
47 169188247 : if (ace->object.object.flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) {
48 95206744 : ret += 16; /* GUID ace->object.object.inherited_type.inherited_type */
49 : }
50 : }
51 :
52 257649797 : return ret;
53 : }
54 :
55 : /*
56 : return the wire size of a security_ace
57 : */
58 85213391 : size_t ndr_size_security_ace(const struct security_ace *ace, libndr_flags flags)
59 : {
60 85213391 : size_t base = ndr_size_security_ace_core(ace, flags);
61 85213391 : size_t ret = base;
62 85213391 : if (sec_ace_callback(ace->type)) {
63 3243 : ret += ace->coda.conditions.length;
64 85210148 : } 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 3101418 : }
73 : /* round up to a multiple of 4 (MS-DTYP 2.4.4.1) */
74 85213391 : ret = (ret + 3ULL) & ~3ULL;
75 85213391 : if (unlikely(ret < base)) {
76 : /* overflow, and there's not much we can do anyway */
77 0 : return 0;
78 : }
79 82111973 : return ret;
80 : }
81 :
82 :
83 364012690 : 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 364012690 : bool is_object = sec_ace_object(r->type);
95 364012690 : if (is_object) {
96 247106234 : NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->object, is_object));
97 247106234 : NDR_CHECK(ndr_pull_security_ace_object_ctr(ndr, ndr_flags, &r->object));
98 : }
99 351074194 : return NDR_ERR_SUCCESS;
100 : }
101 :
102 :
103 364012690 : _PUBLIC_ enum ndr_err_code ndr_pull_security_ace(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct security_ace *r)
104 : {
105 364012690 : NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
106 364012690 : if (ndr_flags & NDR_SCALARS) {
107 6469248 : ssize_t sub_size;
108 182006345 : NDR_CHECK(ndr_pull_align(ndr, 5));
109 182006345 : NDR_CHECK(ndr_pull_security_ace_type(ndr, NDR_SCALARS, &r->type));
110 182006345 : NDR_CHECK(ndr_pull_security_ace_flags(ndr, NDR_SCALARS, &r->flags));
111 182006345 : NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
112 182006345 : NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->access_mask));
113 182006345 : NDR_CHECK(ndr_maybe_pull_security_ace_object_ctr(ndr, NDR_SCALARS, r));
114 182006345 : NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, &r->trustee));
115 182006345 : sub_size = ndr_subcontext_size_of_ace_coda(r, r->size, ndr->flags);
116 182006345 : if (!sec_ace_has_extra_blob(r->type) || sub_size == 0) {
117 182004693 : r->coda.ignored.data = NULL;
118 182004693 : r->coda.ignored.length = 0;
119 : } else {
120 433 : struct ndr_pull *_ndr_coda;
121 1652 : NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_coda, 0, sub_size));
122 1652 : NDR_CHECK(ndr_pull_set_switch_value(_ndr_coda, &r->coda, r->type));
123 1652 : NDR_CHECK(ndr_pull_security_ace_coda(_ndr_coda, NDR_SCALARS|NDR_BUFFERS, &r->coda));
124 1652 : NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_coda, 0, sub_size));
125 : }
126 182006345 : NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
127 : }
128 364012690 : if (ndr_flags & NDR_BUFFERS) {
129 182006345 : NDR_CHECK(ndr_maybe_pull_security_ace_object_ctr(ndr, NDR_BUFFERS, r));
130 : }
131 351074194 : return NDR_ERR_SUCCESS;
132 : }
133 :
134 :
135 79582408 : static inline enum ndr_err_code ndr_maybe_push_security_ace_object_ctr(struct ndr_push *ndr,
136 : ndr_flags_type ndr_flags,
137 : const struct security_ace *r)
138 : {
139 : /*
140 : * ndr_push_security_ace_object_ctr() does nothing (except tallocing
141 : * and ndr_token fiddling) unless the ACE is an object ACE, which is
142 : * usually very unlikely.
143 : */
144 79582408 : bool is_object = sec_ace_object(r->type);
145 79582408 : if (is_object) {
146 45625404 : NDR_CHECK(ndr_push_set_switch_value(ndr, &r->object, is_object));
147 45625404 : NDR_CHECK(ndr_push_security_ace_object_ctr(ndr, ndr_flags, &r->object));
148 : }
149 76495680 : return NDR_ERR_SUCCESS;
150 : }
151 :
152 79582408 : _PUBLIC_ enum ndr_err_code ndr_push_security_ace(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct security_ace *r)
153 : {
154 79582408 : NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
155 79582408 : if (ndr_flags & NDR_SCALARS) {
156 39791204 : NDR_CHECK(ndr_push_align(ndr, 5));
157 39791204 : NDR_CHECK(ndr_push_security_ace_type(ndr, NDR_SCALARS, r->type));
158 39791204 : NDR_CHECK(ndr_push_security_ace_flags(ndr, NDR_SCALARS, r->flags));
159 39791204 : NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, ndr_size_security_ace(r, ndr->flags)));
160 39791204 : NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->access_mask));
161 39791204 : NDR_CHECK(ndr_maybe_push_security_ace_object_ctr(ndr, NDR_SCALARS, r));
162 39791204 : NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS, &r->trustee));
163 39791204 : if (sec_ace_has_extra_blob(r->type)) {
164 431 : struct ndr_push *_ndr_coda;
165 1158 : size_t coda_size = ndr_subcontext_size_of_ace_coda(
166 : r,
167 : ndr_size_security_ace(r, ndr->flags),
168 : ndr->flags);
169 1158 : NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_coda, 0, coda_size));
170 1158 : NDR_CHECK(ndr_push_set_switch_value(_ndr_coda, &r->coda, r->type));
171 1158 : NDR_CHECK(ndr_push_security_ace_coda(_ndr_coda, NDR_SCALARS|NDR_BUFFERS, &r->coda));
172 1158 : NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_coda, 0, coda_size));
173 : }
174 39791204 : NDR_CHECK(ndr_push_trailer_align(ndr, 5));
175 : }
176 79582408 : if (ndr_flags & NDR_BUFFERS) {
177 39791204 : NDR_CHECK(ndr_maybe_push_security_ace_object_ctr(ndr, NDR_BUFFERS, r));
178 : }
179 76495680 : return NDR_ERR_SUCCESS;
180 : }
181 :
182 :
183 : /*
184 : * An ACE coda can't be bigger than the space allowed for by
185 : * ace->size, so we need to check this from the context of the ACE.
186 : *
187 : * Usually the coda also can't be any smaller than the remaining
188 : * space, because it is defined as a blob consuming everything it can.
189 : *
190 : * This is only used to find the size for the coda subcontext in
191 : * security.idl.
192 : */
193 182007503 : size_t ndr_subcontext_size_of_ace_coda(const struct security_ace *ace,
194 : size_t ace_size,
195 : libndr_flags flags)
196 : {
197 6469679 : size_t core_size;
198 182007503 : if (ace_size == 0) {
199 0 : return 0;
200 : }
201 182007503 : core_size = ndr_size_security_ace_core(ace, flags);
202 182007503 : if (ace_size < core_size) {
203 0 : return 0;
204 : }
205 182007503 : return ace_size - core_size;
206 : }
207 :
208 : /*
209 : return the wire size of a security_acl
210 : */
211 8382225 : size_t ndr_size_security_acl(const struct security_acl *theacl, libndr_flags flags)
212 : {
213 315757 : size_t ret;
214 315757 : int i;
215 8382225 : if (!theacl) return 0;
216 6554522 : ret = 8;
217 52286437 : for (i=0;i<theacl->num_aces;i++) {
218 45421029 : ret += ndr_size_security_ace(&theacl->aces[i], flags);
219 : }
220 6554522 : return ret;
221 : }
222 :
223 : /*
224 : return the wire size of a security descriptor
225 : */
226 1517095 : size_t ndr_size_security_descriptor(const struct security_descriptor *sd, libndr_flags flags)
227 : {
228 4851 : size_t ret;
229 1517095 : if (!sd) return 0;
230 :
231 1516337 : ret = 20;
232 1516337 : ret += ndr_size_dom_sid(sd->owner_sid, flags);
233 1516337 : ret += ndr_size_dom_sid(sd->group_sid, flags);
234 1516337 : ret += ndr_size_security_acl(sd->dacl, flags);
235 1516337 : ret += ndr_size_security_acl(sd->sacl, flags);
236 1516337 : return ret;
237 : }
238 :
239 : /*
240 : return the wire size of a dom_sid
241 : */
242 290647200 : size_t ndr_size_dom_sid(const struct dom_sid *sid, libndr_flags flags)
243 : {
244 290647200 : if (!sid) return 0;
245 290300805 : return 8 + 4*sid->num_auths;
246 : }
247 :
248 3310663 : size_t ndr_size_dom_sid28(const struct dom_sid *sid, libndr_flags flags)
249 : {
250 3310663 : if (all_zero((const uint8_t *)sid, sizeof(struct dom_sid))) {
251 2935327 : return 0;
252 : }
253 375330 : return ndr_size_dom_sid(sid, flags);
254 : }
255 :
256 570 : size_t ndr_size_dom_sid0(const struct dom_sid *sid, libndr_flags flags)
257 : {
258 570 : return ndr_size_dom_sid28(sid, flags);
259 : }
260 :
261 : /*
262 : print a dom_sid
263 : */
264 45598 : void ndr_print_dom_sid(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
265 : {
266 3961 : struct dom_sid_buf buf;
267 45598 : ndr->print(ndr, "%-25s: %s", name, dom_sid_str_buf(sid, &buf));
268 45598 : }
269 :
270 23612 : void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
271 : {
272 23612 : ndr_print_dom_sid(ndr, name, sid);
273 23612 : }
274 :
275 13970 : void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
276 : {
277 13970 : ndr_print_dom_sid(ndr, name, sid);
278 13970 : }
279 :
280 2 : void ndr_print_dom_sid0(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
281 : {
282 2 : ndr_print_dom_sid(ndr, name, sid);
283 2 : }
284 :
285 :
286 : /*
287 : parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
288 : */
289 586050 : enum ndr_err_code ndr_pull_dom_sid2(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid)
290 : {
291 24143 : uint32_t num_auths;
292 586050 : if (!(ndr_flags & NDR_SCALARS)) {
293 0 : return NDR_ERR_SUCCESS;
294 : }
295 586050 : NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &num_auths));
296 586050 : NDR_CHECK(ndr_pull_dom_sid(ndr, ndr_flags, sid));
297 586050 : if (sid->num_auths != num_auths) {
298 0 : return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
299 : "Bad num_auths %"PRIu32"; should equal %"PRId8,
300 : num_auths, sid->num_auths);
301 : }
302 561907 : return NDR_ERR_SUCCESS;
303 : }
304 :
305 : /*
306 : parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
307 : */
308 429515 : enum ndr_err_code ndr_push_dom_sid2(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid)
309 : {
310 429515 : if (!(ndr_flags & NDR_SCALARS)) {
311 0 : return NDR_ERR_SUCCESS;
312 : }
313 429515 : NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, sid->num_auths));
314 429515 : return ndr_push_dom_sid(ndr, ndr_flags, sid);
315 : }
316 :
317 : /*
318 : 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
319 : */
320 2896170 : enum ndr_err_code ndr_pull_dom_sid28(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid)
321 : {
322 24 : enum ndr_err_code status;
323 24 : struct ndr_pull *subndr;
324 :
325 2896170 : if (!(ndr_flags & NDR_SCALARS)) {
326 1448073 : return NDR_ERR_SUCCESS;
327 : }
328 :
329 1448085 : subndr = talloc_zero(ndr, struct ndr_pull);
330 1448085 : NDR_ERR_HAVE_NO_MEMORY(subndr);
331 1448085 : subndr->flags = ndr->flags;
332 1448085 : subndr->current_mem_ctx = ndr->current_mem_ctx;
333 :
334 1448085 : subndr->data = ndr->data + ndr->offset;
335 1448085 : subndr->data_size = 28;
336 1448085 : subndr->offset = 0;
337 :
338 1448085 : status = ndr_pull_advance(ndr, 28);
339 1448085 : if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
340 0 : talloc_free(subndr);
341 0 : return status;
342 : }
343 :
344 1448085 : status = ndr_pull_dom_sid(subndr, ndr_flags, sid);
345 1448085 : if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
346 : /* handle a w2k bug which send random data in the buffer */
347 1 : ZERO_STRUCTP(sid);
348 1448084 : } else if (sid->num_auths == 0) {
349 1299533 : ZERO_STRUCT(sid->sub_auths);
350 : }
351 :
352 1448085 : talloc_free(subndr);
353 1448085 : return NDR_ERR_SUCCESS;
354 : }
355 :
356 : /*
357 : push a dom_sid28 - this is a dom_sid in a 28 byte fixed buffer
358 : */
359 6620374 : enum ndr_err_code ndr_push_dom_sid28(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid)
360 : {
361 24 : uint32_t old_offset;
362 24 : uint32_t padding;
363 :
364 6620374 : if (!(ndr_flags & NDR_SCALARS)) {
365 3310175 : return NDR_ERR_SUCCESS;
366 : }
367 :
368 3310187 : if (sid->num_auths > 5) {
369 0 : return ndr_push_error(ndr, NDR_ERR_RANGE,
370 : "dom_sid28 allows only up to 5 sub auths [%"PRId8"]",
371 : sid->num_auths);
372 : }
373 :
374 3310187 : old_offset = ndr->offset;
375 3310187 : NDR_CHECK(ndr_push_dom_sid(ndr, ndr_flags, sid));
376 :
377 3310187 : padding = 28 - (ndr->offset - old_offset);
378 :
379 3310187 : if (padding > 0) {
380 3003527 : NDR_CHECK(ndr_push_zero(ndr, padding));
381 : }
382 :
383 3310175 : return NDR_ERR_SUCCESS;
384 : }
385 :
386 : /*
387 : parse a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty
388 : */
389 26 : enum ndr_err_code ndr_pull_dom_sid0(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid)
390 : {
391 26 : if (!(ndr_flags & NDR_SCALARS)) {
392 0 : return NDR_ERR_SUCCESS;
393 : }
394 :
395 26 : if (ndr->data_size == ndr->offset) {
396 0 : ZERO_STRUCTP(sid);
397 0 : return NDR_ERR_SUCCESS;
398 : }
399 :
400 26 : return ndr_pull_dom_sid(ndr, ndr_flags, sid);
401 : }
402 :
403 : /*
404 : push a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty
405 : */
406 15 : enum ndr_err_code ndr_push_dom_sid0(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid)
407 : {
408 15 : if (!(ndr_flags & NDR_SCALARS)) {
409 0 : return NDR_ERR_SUCCESS;
410 : }
411 :
412 15 : if (!sid) {
413 0 : return NDR_ERR_SUCCESS;
414 : }
415 :
416 15 : if (all_zero((const uint8_t *)sid, sizeof(struct dom_sid))) {
417 0 : return NDR_ERR_SUCCESS;
418 : }
419 :
420 15 : return ndr_push_dom_sid(ndr, ndr_flags, sid);
421 : }
422 :
423 114756839 : _PUBLIC_ enum ndr_err_code ndr_push_dom_sid(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *r)
424 : {
425 2495168 : uint32_t cntr_sub_auths_0;
426 114756839 : if (ndr_flags & NDR_SCALARS) {
427 114756839 : NDR_CHECK(ndr_push_align(ndr, 4));
428 114756839 : NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->sid_rev_num));
429 114756839 : NDR_CHECK(ndr_push_int8(ndr, NDR_SCALARS, r->num_auths));
430 114756839 : NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6));
431 114756839 : if (r->num_auths < 0 || r->num_auths > ARRAY_SIZE(r->sub_auths)) {
432 0 : return ndr_push_error(ndr, NDR_ERR_RANGE, "value (%"PRId8") out of range (0 - %zu)", r->num_auths, ARRAY_SIZE(r->sub_auths));
433 : }
434 424625456 : for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < r->num_auths; cntr_sub_auths_0++) {
435 309868617 : NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sub_auths[cntr_sub_auths_0]));
436 : }
437 : }
438 112261671 : return NDR_ERR_SUCCESS;
439 : }
440 :
441 270068010 : _PUBLIC_ enum ndr_err_code ndr_pull_dom_sid(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *r)
442 : {
443 8084839 : uint32_t cntr_sub_auths_0;
444 270068010 : if (ndr_flags & NDR_SCALARS) {
445 270068010 : NDR_CHECK(ndr_pull_align(ndr, 4));
446 270068010 : NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->sid_rev_num));
447 270067625 : NDR_CHECK(ndr_pull_int8(ndr, NDR_SCALARS, &r->num_auths));
448 270067575 : if (r->num_auths < 0 || r->num_auths > ARRAY_SIZE(r->sub_auths)) {
449 8 : return ndr_pull_error(ndr, NDR_ERR_RANGE, "value (%"PRId8") out of range (0 - %zu)", r->num_auths, ARRAY_SIZE(r->sub_auths));
450 : }
451 270067567 : NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6));
452 270067567 : ZERO_STRUCT(r->sub_auths);
453 971121360 : for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < r->num_auths; cntr_sub_auths_0++) {
454 692968959 : NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sub_auths[cntr_sub_auths_0]));
455 : }
456 : }
457 261982733 : return NDR_ERR_SUCCESS;
458 : }
|