7207c0b6bae96f60fef5ce2594ccb80f18a314bc
[kai/samba.git] / librpc / ndr / ndr_sec_helper.c
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/dom_sid.h"
27 #if _SAMBA_BUILD_ == 4
28 #include "libcli/security/security.h"
29 #endif
30
31 /*
32   return the wire size of a security_ace
33 */
34 size_t ndr_size_security_ace(const struct security_ace *ace, int flags)
35 {
36         size_t ret;
37
38         if (!ace) return 0;
39
40         ret = 8 + ndr_size_dom_sid(&ace->trustee, flags);
41
42         switch (ace->type) {
43         case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
44         case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
45         case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT:
46         case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT:
47                 ret += 4; /* uint32 bitmap ace->object.object.flags */
48                 if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
49                         ret += 16; /* GUID ace->object.object.type.type */
50                 }
51                 if (ace->object.object.flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) {
52                         ret += 16; /* GUID ace->object.object.inherited_typeinherited_type */
53                 }
54                 break;
55         default:
56                 break;
57         }
58
59         return ret;
60 }
61
62 enum ndr_err_code ndr_pull_security_ace(struct ndr_pull *ndr, int ndr_flags, struct security_ace *r)
63 {
64         if (ndr_flags & NDR_SCALARS) {
65                 uint32_t start_ofs = ndr->offset;
66                 uint32_t size = 0;
67                 uint32_t pad = 0;
68                 NDR_CHECK(ndr_pull_align(ndr, 4));
69                 NDR_CHECK(ndr_pull_security_ace_type(ndr, NDR_SCALARS, &r->type));
70                 NDR_CHECK(ndr_pull_security_ace_flags(ndr, NDR_SCALARS, &r->flags));
71                 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
72                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->access_mask));
73                 NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->object, r->type));
74                 NDR_CHECK(ndr_pull_security_ace_object_ctr(ndr, NDR_SCALARS, &r->object));
75                 NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, &r->trustee));
76                 size = ndr->offset - start_ofs;
77                 if (r->size < size) {
78                         return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
79                                               "ndr_pull_security_ace: r->size %u < size %u",
80                                               (unsigned)r->size, size);
81                 }
82                 pad = r->size - size;
83                 NDR_PULL_NEED_BYTES(ndr, pad);
84                 ndr->offset += pad;
85         }
86         if (ndr_flags & NDR_BUFFERS) {
87                 NDR_CHECK(ndr_pull_security_ace_object_ctr(ndr, NDR_BUFFERS, &r->object));
88         }
89         return NDR_ERR_SUCCESS;
90 }
91
92 /*
93   return the wire size of a security_acl
94 */
95 size_t ndr_size_security_acl(const struct security_acl *theacl, int flags)
96 {
97         size_t ret;
98         int i;
99         if (!theacl) return 0;
100         ret = 8;
101         for (i=0;i<theacl->num_aces;i++) {
102                 ret += ndr_size_security_ace(&theacl->aces[i], flags);
103         }
104         return ret;
105 }
106
107 /*
108   return the wire size of a security descriptor
109 */
110 size_t ndr_size_security_descriptor(const struct security_descriptor *sd, int flags)
111 {
112         size_t ret;
113         if (!sd) return 0;
114         
115         ret = 20;
116         ret += ndr_size_dom_sid(sd->owner_sid, flags);
117         ret += ndr_size_dom_sid(sd->group_sid, flags);
118         ret += ndr_size_security_acl(sd->dacl, flags);
119         ret += ndr_size_security_acl(sd->sacl, flags);
120         return ret;
121 }
122
123 /*
124   return the wire size of a dom_sid
125 */
126 size_t ndr_size_dom_sid(const struct dom_sid *sid, int flags)
127 {
128         if (!sid) return 0;
129         return 8 + 4*sid->num_auths;
130 }
131
132 size_t ndr_size_dom_sid28(const struct dom_sid *sid, int flags)
133 {
134         struct dom_sid zero_sid;
135
136         if (!sid) return 0;
137
138         ZERO_STRUCT(zero_sid);
139
140         if (memcmp(&zero_sid, sid, sizeof(zero_sid)) == 0) {
141                 return 0;
142         }
143
144         return 8 + 4*sid->num_auths;
145 }
146
147 size_t ndr_size_dom_sid0(const struct dom_sid *sid, int flags)
148 {
149         return ndr_size_dom_sid28(sid, flags);
150 }
151
152 /*
153   print a dom_sid
154 */
155 void ndr_print_dom_sid(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
156 {
157         ndr->print(ndr, "%-25s: %s", name, dom_sid_string(ndr, sid));
158 }
159
160 void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
161 {
162         ndr_print_dom_sid(ndr, name, sid);
163 }
164
165 void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
166 {
167         ndr_print_dom_sid(ndr, name, sid);
168 }
169
170 void ndr_print_dom_sid0(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
171 {
172         ndr_print_dom_sid(ndr, name, sid);
173 }
174
175
176 /*
177   parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
178 */
179 enum ndr_err_code ndr_pull_dom_sid2(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid)
180 {
181         uint32_t num_auths;
182         if (!(ndr_flags & NDR_SCALARS)) {
183                 return NDR_ERR_SUCCESS;
184         }
185         NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &num_auths));
186         NDR_CHECK(ndr_pull_dom_sid(ndr, ndr_flags, sid));
187         if (sid->num_auths != num_auths) {
188                 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, 
189                                       "Bad array size %u should exceed %u", 
190                                       num_auths, sid->num_auths);
191         }
192         return NDR_ERR_SUCCESS;
193 }
194
195 /*
196   parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
197 */
198 enum ndr_err_code ndr_push_dom_sid2(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid)
199 {
200         if (!(ndr_flags & NDR_SCALARS)) {
201                 return NDR_ERR_SUCCESS;
202         }
203         NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, sid->num_auths));
204         return ndr_push_dom_sid(ndr, ndr_flags, sid);
205 }
206
207 /*
208   parse a dom_sid28 - this is a dom_sid in a fixed 28 byte buffer, so we need to ensure there are only upto 5 sub_auth
209 */
210 enum ndr_err_code ndr_pull_dom_sid28(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid)
211 {
212         enum ndr_err_code status;
213         struct ndr_pull *subndr;
214
215         if (!(ndr_flags & NDR_SCALARS)) {
216                 return NDR_ERR_SUCCESS;
217         }
218
219         subndr = talloc_zero(ndr, struct ndr_pull);
220         NDR_ERR_HAVE_NO_MEMORY(subndr);
221         subndr->flags           = ndr->flags;
222         subndr->current_mem_ctx = ndr->current_mem_ctx;
223
224         subndr->data            = ndr->data + ndr->offset;
225         subndr->data_size       = 28;
226         subndr->offset          = 0;
227
228         NDR_CHECK(ndr_pull_advance(ndr, 28));
229
230         status = ndr_pull_dom_sid(subndr, ndr_flags, sid);
231         if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
232                 /* handle a w2k bug which send random data in the buffer */
233                 ZERO_STRUCTP(sid);
234         } else if (sid->num_auths == 0 && sid->sub_auths) {
235                 ZERO_STRUCT(sid->sub_auths);
236         }
237
238         return NDR_ERR_SUCCESS;
239 }
240
241 /*
242   push a dom_sid28 - this is a dom_sid in a 28 byte fixed buffer
243 */
244 enum ndr_err_code ndr_push_dom_sid28(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid)
245 {
246         uint32_t old_offset;
247         uint32_t padding;
248
249         if (!(ndr_flags & NDR_SCALARS)) {
250                 return NDR_ERR_SUCCESS;
251         }
252
253         if (sid->num_auths > 5) {
254                 return ndr_push_error(ndr, NDR_ERR_RANGE, 
255                                       "dom_sid28 allows only upto 5 sub auth [%u]", 
256                                       sid->num_auths);
257         }
258
259         old_offset = ndr->offset;
260         NDR_CHECK(ndr_push_dom_sid(ndr, ndr_flags, sid));
261
262         padding = 28 - (ndr->offset - old_offset);
263
264         if (padding > 0) {
265                 NDR_CHECK(ndr_push_zero(ndr, padding));
266         }
267
268         return NDR_ERR_SUCCESS;
269 }
270
271 /*
272   parse a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty
273 */
274 enum ndr_err_code ndr_pull_dom_sid0(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid)
275 {
276         if (!(ndr_flags & NDR_SCALARS)) {
277                 return NDR_ERR_SUCCESS;
278         }
279
280         if (ndr->data_size == ndr->offset) {
281                 ZERO_STRUCTP(sid);
282                 return NDR_ERR_SUCCESS;
283         }
284
285         return ndr_pull_dom_sid(ndr, ndr_flags, sid);
286 }
287
288 /*
289   push a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty
290 */
291 enum ndr_err_code ndr_push_dom_sid0(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid)
292 {
293         struct dom_sid zero_sid;
294
295         if (!(ndr_flags & NDR_SCALARS)) {
296                 return NDR_ERR_SUCCESS;
297         }
298
299         if (!sid) {
300                 return NDR_ERR_SUCCESS;
301         }
302
303         ZERO_STRUCT(zero_sid);
304
305         if (memcmp(&zero_sid, sid, sizeof(zero_sid)) == 0) {
306                 return NDR_ERR_SUCCESS;
307         }
308
309         return ndr_push_dom_sid(ndr, ndr_flags, sid);
310 }
311
312 _PUBLIC_ enum ndr_err_code ndr_push_dom_sid(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *r)
313 {
314         uint32_t cntr_sub_auths_0;
315         if (ndr_flags & NDR_SCALARS) {
316                 NDR_CHECK(ndr_push_align(ndr, 4));
317                 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->sid_rev_num));
318                 NDR_CHECK(ndr_push_int8(ndr, NDR_SCALARS, r->num_auths));
319                 NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6));
320                 for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < r->num_auths; cntr_sub_auths_0++) {
321                         NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sub_auths[cntr_sub_auths_0]));
322                 }
323         }
324         return NDR_ERR_SUCCESS;
325 }
326
327 _PUBLIC_ enum ndr_err_code ndr_pull_dom_sid(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *r)
328 {
329         uint32_t cntr_sub_auths_0;
330         if (ndr_flags & NDR_SCALARS) {
331                 NDR_CHECK(ndr_pull_align(ndr, 4));
332                 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->sid_rev_num));
333                 NDR_CHECK(ndr_pull_int8(ndr, NDR_SCALARS, &r->num_auths));
334                 if (r->num_auths < 0 || r->num_auths > 15) {
335                         return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range");
336                 }
337                 NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6));
338                 for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < r->num_auths; cntr_sub_auths_0++) {
339                         NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sub_auths[cntr_sub_auths_0]));
340                 }
341         }
342         return NDR_ERR_SUCCESS;
343 }