2 Unix SMB/CIFS implementation.
4 fast routines for getting the wire size of security objects
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Stefan Metzmacher 2006-2008
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.
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.
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/>.
25 #include "librpc/gen_ndr/ndr_security.h"
26 #include "../libcli/security/security.h"
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()
35 static size_t ndr_size_security_ace_core(const struct security_ace
*ace
, libndr_flags flags
)
41 ret
= 8 + ndr_size_dom_sid(&ace
->trustee
, flags
);
42 if (sec_ace_object(ace
->type
)) {
43 ret
+= 4; /* uint32 bitmap ace->object.object.flags */
44 if (ace
->object
.object
.flags
& SEC_ACE_OBJECT_TYPE_PRESENT
) {
45 ret
+= 16; /* GUID ace->object.object.type.type */
47 if (ace
->object
.object
.flags
& SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT
) {
48 ret
+= 16; /* GUID ace->object.object.inherited_type.inherited_type */
56 return the wire size of a security_ace
58 size_t ndr_size_security_ace(const struct security_ace
*ace
, libndr_flags flags
)
60 size_t base
= ndr_size_security_ace_core(ace
, flags
);
62 if (sec_ace_callback(ace
->type
)) {
63 ret
+= ace
->coda
.conditions
.length
;
64 } else if (ace
->type
== SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE
) {
65 ret
+= ndr_size_security_ace_coda(&ace
->coda
, ace
->type
, flags
);
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.
73 /* round up to a multiple of 4 (MS-DTYP 2.4.4.1) */
74 ret
= (ret
+ 3ULL) & ~3ULL;
75 if (unlikely(ret
< base
)) {
76 /* overflow, and there's not much we can do anyway */
83 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
)
88 * If this is not an object ACE (as is usually common),
89 * ndr_pull_security_ace_object_ctr() will do nothing.
91 * By avoiding calling the function in that case, we avoid some
92 * tallocing and ndr token busywork.
94 bool is_object
= sec_ace_object(r
->type
);
96 NDR_CHECK(ndr_pull_set_switch_value(ndr
, &r
->object
, is_object
));
97 NDR_CHECK(ndr_pull_security_ace_object_ctr(ndr
, ndr_flags
, &r
->object
));
99 return NDR_ERR_SUCCESS
;
103 _PUBLIC_
enum ndr_err_code
ndr_pull_security_ace(struct ndr_pull
*ndr
, ndr_flags_type ndr_flags
, struct security_ace
*r
)
105 NDR_PULL_CHECK_FLAGS(ndr
, ndr_flags
);
106 if (ndr_flags
& NDR_SCALARS
) {
107 NDR_CHECK(ndr_pull_align(ndr
, 5));
108 NDR_CHECK(ndr_pull_security_ace_type(ndr
, NDR_SCALARS
, &r
->type
));
109 NDR_CHECK(ndr_pull_security_ace_flags(ndr
, NDR_SCALARS
, &r
->flags
));
110 NDR_CHECK(ndr_pull_uint16(ndr
, NDR_SCALARS
, &r
->size
));
111 NDR_CHECK(ndr_pull_uint32(ndr
, NDR_SCALARS
, &r
->access_mask
));
112 NDR_CHECK(ndr_maybe_pull_security_ace_object_ctr(ndr
, NDR_SCALARS
, r
));
113 NDR_CHECK(ndr_pull_dom_sid(ndr
, NDR_SCALARS
, &r
->trustee
));
114 if (!sec_ace_has_extra_blob(r
->type
)) {
115 r
->coda
.ignored
.data
= NULL
;
116 r
->coda
.ignored
.length
= 0;
118 struct ndr_pull
*_ndr_coda
;
119 ssize_t sub_size
= ndr_subcontext_size_of_ace_coda(r
, r
->size
, ndr
->flags
);
120 NDR_CHECK(ndr_pull_subcontext_start(ndr
, &_ndr_coda
, 0, sub_size
));
121 NDR_CHECK(ndr_pull_set_switch_value(_ndr_coda
, &r
->coda
, r
->type
));
122 NDR_CHECK(ndr_pull_security_ace_coda(_ndr_coda
, NDR_SCALARS
|NDR_BUFFERS
, &r
->coda
));
123 NDR_CHECK(ndr_pull_subcontext_end(ndr
, _ndr_coda
, 0, sub_size
));
125 NDR_CHECK(ndr_pull_trailer_align(ndr
, 5));
127 if (ndr_flags
& NDR_BUFFERS
) {
128 NDR_CHECK(ndr_maybe_pull_security_ace_object_ctr(ndr
, NDR_BUFFERS
, r
));
130 return NDR_ERR_SUCCESS
;
134 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
)
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.
143 bool is_object
= sec_ace_object(r
->type
);
145 NDR_CHECK(ndr_push_set_switch_value(ndr
, &r
->object
, is_object
));
146 NDR_CHECK(ndr_push_security_ace_object_ctr(ndr
, ndr_flags
, &r
->object
));
148 return NDR_ERR_SUCCESS
;
151 _PUBLIC_
enum ndr_err_code
ndr_push_security_ace(struct ndr_push
*ndr
, ndr_flags_type ndr_flags
, const struct security_ace
*r
)
153 NDR_PUSH_CHECK_FLAGS(ndr
, ndr_flags
);
154 if (ndr_flags
& NDR_SCALARS
) {
155 NDR_CHECK(ndr_push_align(ndr
, 5));
156 NDR_CHECK(ndr_push_security_ace_type(ndr
, NDR_SCALARS
, r
->type
));
157 NDR_CHECK(ndr_push_security_ace_flags(ndr
, NDR_SCALARS
, r
->flags
));
158 NDR_CHECK(ndr_push_uint16(ndr
, NDR_SCALARS
, ndr_size_security_ace(r
, ndr
->flags
)));
159 NDR_CHECK(ndr_push_uint32(ndr
, NDR_SCALARS
, r
->access_mask
));
160 NDR_CHECK(ndr_maybe_push_security_ace_object_ctr(ndr
, NDR_SCALARS
, r
));
161 NDR_CHECK(ndr_push_dom_sid(ndr
, NDR_SCALARS
, &r
->trustee
));
162 if (sec_ace_has_extra_blob(r
->type
)) {
163 struct ndr_push
*_ndr_coda
;
164 size_t coda_size
= ndr_subcontext_size_of_ace_coda(
166 ndr_size_security_ace(r
, ndr
->flags
),
168 NDR_CHECK(ndr_push_subcontext_start(ndr
, &_ndr_coda
, 0, coda_size
));
169 NDR_CHECK(ndr_push_set_switch_value(_ndr_coda
, &r
->coda
, r
->type
));
170 NDR_CHECK(ndr_push_security_ace_coda(_ndr_coda
, NDR_SCALARS
|NDR_BUFFERS
, &r
->coda
));
171 NDR_CHECK(ndr_push_subcontext_end(ndr
, _ndr_coda
, 0, coda_size
));
173 NDR_CHECK(ndr_push_trailer_align(ndr
, 5));
175 if (ndr_flags
& NDR_BUFFERS
) {
176 NDR_CHECK(ndr_maybe_push_security_ace_object_ctr(ndr
, NDR_BUFFERS
, r
));
178 return NDR_ERR_SUCCESS
;
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.
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.
189 * This is only used to find the size for the coda subcontext in
192 size_t ndr_subcontext_size_of_ace_coda(const struct security_ace
*ace
,
200 core_size
= ndr_size_security_ace_core(ace
, flags
);
201 if (ace_size
< core_size
) {
204 return ace_size
- core_size
;
208 return the wire size of a security_acl
210 size_t ndr_size_security_acl(const struct security_acl
*theacl
, libndr_flags flags
)
214 if (!theacl
) return 0;
216 for (i
=0;i
<theacl
->num_aces
;i
++) {
217 ret
+= ndr_size_security_ace(&theacl
->aces
[i
], flags
);
223 return the wire size of a security descriptor
225 size_t ndr_size_security_descriptor(const struct security_descriptor
*sd
, libndr_flags flags
)
231 ret
+= ndr_size_dom_sid(sd
->owner_sid
, flags
);
232 ret
+= ndr_size_dom_sid(sd
->group_sid
, flags
);
233 ret
+= ndr_size_security_acl(sd
->dacl
, flags
);
234 ret
+= ndr_size_security_acl(sd
->sacl
, flags
);
239 return the wire size of a dom_sid
241 size_t ndr_size_dom_sid(const struct dom_sid
*sid
, libndr_flags flags
)
244 return 8 + 4*sid
->num_auths
;
247 size_t ndr_size_dom_sid28(const struct dom_sid
*sid
, libndr_flags flags
)
249 if (all_zero((const uint8_t *)sid
, sizeof(struct dom_sid
))) {
252 return ndr_size_dom_sid(sid
, flags
);
255 size_t ndr_size_dom_sid0(const struct dom_sid
*sid
, libndr_flags flags
)
257 return ndr_size_dom_sid28(sid
, flags
);
263 void ndr_print_dom_sid(struct ndr_print
*ndr
, const char *name
, const struct dom_sid
*sid
)
265 struct dom_sid_buf buf
;
266 ndr
->print(ndr
, "%-25s: %s", name
, dom_sid_str_buf(sid
, &buf
));
269 void ndr_print_dom_sid2(struct ndr_print
*ndr
, const char *name
, const struct dom_sid
*sid
)
271 ndr_print_dom_sid(ndr
, name
, sid
);
274 void ndr_print_dom_sid28(struct ndr_print
*ndr
, const char *name
, const struct dom_sid
*sid
)
276 ndr_print_dom_sid(ndr
, name
, sid
);
279 void ndr_print_dom_sid0(struct ndr_print
*ndr
, const char *name
, const struct dom_sid
*sid
)
281 ndr_print_dom_sid(ndr
, name
, sid
);
286 parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
288 enum ndr_err_code
ndr_pull_dom_sid2(struct ndr_pull
*ndr
, ndr_flags_type ndr_flags
, struct dom_sid
*sid
)
291 if (!(ndr_flags
& NDR_SCALARS
)) {
292 return NDR_ERR_SUCCESS
;
294 NDR_CHECK(ndr_pull_uint3264(ndr
, NDR_SCALARS
, &num_auths
));
295 NDR_CHECK(ndr_pull_dom_sid(ndr
, ndr_flags
, sid
));
296 if (sid
->num_auths
!= num_auths
) {
297 return ndr_pull_error(ndr
, NDR_ERR_ARRAY_SIZE
,
298 "Bad num_auths %"PRIu32
"; should equal %"PRId8
,
299 num_auths
, sid
->num_auths
);
301 return NDR_ERR_SUCCESS
;
305 parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
307 enum ndr_err_code
ndr_push_dom_sid2(struct ndr_push
*ndr
, ndr_flags_type ndr_flags
, const struct dom_sid
*sid
)
309 if (!(ndr_flags
& NDR_SCALARS
)) {
310 return NDR_ERR_SUCCESS
;
312 NDR_CHECK(ndr_push_uint3264(ndr
, NDR_SCALARS
, sid
->num_auths
));
313 return ndr_push_dom_sid(ndr
, ndr_flags
, sid
);
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
319 enum ndr_err_code
ndr_pull_dom_sid28(struct ndr_pull
*ndr
, ndr_flags_type ndr_flags
, struct dom_sid
*sid
)
321 enum ndr_err_code status
;
322 struct ndr_pull
*subndr
;
324 if (!(ndr_flags
& NDR_SCALARS
)) {
325 return NDR_ERR_SUCCESS
;
328 subndr
= talloc_zero(ndr
, struct ndr_pull
);
329 NDR_ERR_HAVE_NO_MEMORY(subndr
);
330 subndr
->flags
= ndr
->flags
;
331 subndr
->current_mem_ctx
= ndr
->current_mem_ctx
;
333 subndr
->data
= ndr
->data
+ ndr
->offset
;
334 subndr
->data_size
= 28;
337 status
= ndr_pull_advance(ndr
, 28);
338 if (!NDR_ERR_CODE_IS_SUCCESS(status
)) {
343 status
= ndr_pull_dom_sid(subndr
, ndr_flags
, sid
);
344 if (!NDR_ERR_CODE_IS_SUCCESS(status
)) {
345 /* handle a w2k bug which send random data in the buffer */
347 } else if (sid
->num_auths
== 0) {
348 ZERO_STRUCT(sid
->sub_auths
);
352 return NDR_ERR_SUCCESS
;
356 push a dom_sid28 - this is a dom_sid in a 28 byte fixed buffer
358 enum ndr_err_code
ndr_push_dom_sid28(struct ndr_push
*ndr
, ndr_flags_type ndr_flags
, const struct dom_sid
*sid
)
363 if (!(ndr_flags
& NDR_SCALARS
)) {
364 return NDR_ERR_SUCCESS
;
367 if (sid
->num_auths
> 5) {
368 return ndr_push_error(ndr
, NDR_ERR_RANGE
,
369 "dom_sid28 allows only up to 5 sub auths [%"PRId8
"]",
373 old_offset
= ndr
->offset
;
374 NDR_CHECK(ndr_push_dom_sid(ndr
, ndr_flags
, sid
));
376 padding
= 28 - (ndr
->offset
- old_offset
);
379 NDR_CHECK(ndr_push_zero(ndr
, padding
));
382 return NDR_ERR_SUCCESS
;
386 parse a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty
388 enum ndr_err_code
ndr_pull_dom_sid0(struct ndr_pull
*ndr
, ndr_flags_type ndr_flags
, struct dom_sid
*sid
)
390 if (!(ndr_flags
& NDR_SCALARS
)) {
391 return NDR_ERR_SUCCESS
;
394 if (ndr
->data_size
== ndr
->offset
) {
396 return NDR_ERR_SUCCESS
;
399 return ndr_pull_dom_sid(ndr
, ndr_flags
, sid
);
403 push a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty
405 enum ndr_err_code
ndr_push_dom_sid0(struct ndr_push
*ndr
, ndr_flags_type ndr_flags
, const struct dom_sid
*sid
)
407 if (!(ndr_flags
& NDR_SCALARS
)) {
408 return NDR_ERR_SUCCESS
;
412 return NDR_ERR_SUCCESS
;
415 if (all_zero((const uint8_t *)sid
, sizeof(struct dom_sid
))) {
416 return NDR_ERR_SUCCESS
;
419 return ndr_push_dom_sid(ndr
, ndr_flags
, sid
);
422 _PUBLIC_
enum ndr_err_code
ndr_push_dom_sid(struct ndr_push
*ndr
, ndr_flags_type ndr_flags
, const struct dom_sid
*r
)
424 uint32_t cntr_sub_auths_0
;
425 if (ndr_flags
& NDR_SCALARS
) {
426 NDR_CHECK(ndr_push_align(ndr
, 4));
427 NDR_CHECK(ndr_push_uint8(ndr
, NDR_SCALARS
, r
->sid_rev_num
));
428 NDR_CHECK(ndr_push_int8(ndr
, NDR_SCALARS
, r
->num_auths
));
429 NDR_CHECK(ndr_push_array_uint8(ndr
, NDR_SCALARS
, r
->id_auth
, 6));
430 if (r
->num_auths
< 0 || r
->num_auths
> ARRAY_SIZE(r
->sub_auths
)) {
431 return ndr_push_error(ndr
, NDR_ERR_RANGE
, "value (%"PRId8
") out of range (0 - %zu)", r
->num_auths
, ARRAY_SIZE(r
->sub_auths
));
433 for (cntr_sub_auths_0
= 0; cntr_sub_auths_0
< r
->num_auths
; cntr_sub_auths_0
++) {
434 NDR_CHECK(ndr_push_uint32(ndr
, NDR_SCALARS
, r
->sub_auths
[cntr_sub_auths_0
]));
437 return NDR_ERR_SUCCESS
;
440 _PUBLIC_
enum ndr_err_code
ndr_pull_dom_sid(struct ndr_pull
*ndr
, ndr_flags_type ndr_flags
, struct dom_sid
*r
)
442 uint32_t cntr_sub_auths_0
;
443 if (ndr_flags
& NDR_SCALARS
) {
444 NDR_CHECK(ndr_pull_align(ndr
, 4));
445 NDR_CHECK(ndr_pull_uint8(ndr
, NDR_SCALARS
, &r
->sid_rev_num
));
446 NDR_CHECK(ndr_pull_int8(ndr
, NDR_SCALARS
, &r
->num_auths
));
447 if (r
->num_auths
< 0 || r
->num_auths
> ARRAY_SIZE(r
->sub_auths
)) {
448 return ndr_pull_error(ndr
, NDR_ERR_RANGE
, "value (%"PRId8
") out of range (0 - %zu)", r
->num_auths
, ARRAY_SIZE(r
->sub_auths
));
450 NDR_CHECK(ndr_pull_array_uint8(ndr
, NDR_SCALARS
, r
->id_auth
, 6));
451 ZERO_STRUCT(r
->sub_auths
);
452 for (cntr_sub_auths_0
= 0; cntr_sub_auths_0
< r
->num_auths
; cntr_sub_auths_0
++) {
453 NDR_CHECK(ndr_pull_uint32(ndr
, NDR_SCALARS
, &r
->sub_auths
[cntr_sub_auths_0
]));
456 return NDR_ERR_SUCCESS
;