libndr: add dom_sid0 type that can later be used for CLDAP and MAILSLOT ntlogon packets
[kai/samba.git] / source4 / 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    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22
23 #include "includes.h"
24 #include "librpc/gen_ndr/ndr_security.h"
25 #include "libcli/security/security.h"
26
27 /*
28   return the wire size of a dom_sid
29 */
30 size_t ndr_size_dom_sid(const struct dom_sid *sid, int flags)
31 {
32         if (!sid) return 0;
33         return 8 + 4*sid->num_auths;
34 }
35
36 size_t ndr_size_dom_sid28(const struct dom_sid *sid, int flags)
37 {
38         struct dom_sid zero_sid;
39
40         if (!sid) return 0;
41
42         ZERO_STRUCT(zero_sid);
43
44         if (memcmp(&zero_sid, sid, sizeof(zero_sid)) == 0) {
45                 return 0;
46         }
47
48         return 8 + 4*sid->num_auths;
49 }
50
51 size_t ndr_size_dom_sid0(const struct dom_sid *sid, int flags)
52 {
53         return ndr_size_dom_sid28(sid, flags);
54 }
55
56 /*
57   return the wire size of a security_ace
58 */
59 size_t ndr_size_security_ace(const struct security_ace *ace, int flags)
60 {
61         size_t ret;
62
63         if (!ace) return 0;
64
65         ret = 8 + ndr_size_dom_sid(&ace->trustee, flags);
66
67         switch (ace->type) {
68         case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
69         case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
70         case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT:
71         case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT:
72                 ret += 4; /* uint32 bitmap ace->object.object.flags */
73                 if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
74                         ret += 16; /* GUID ace->object.object.type.type */
75                 }
76                 if (ace->object.object.flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) {
77                         ret += 16; /* GUID ace->object.object.inherited_typeinherited_type */
78                 }
79                 break;
80         default:
81                 break;
82         }
83
84         return ret;
85 }
86
87 /*
88   return the wire size of a security_acl
89 */
90 size_t ndr_size_security_acl(const struct security_acl *acl, int flags)
91 {
92         size_t ret;
93         int i;
94         if (!acl) return 0;
95         ret = 8;
96         for (i=0;i<acl->num_aces;i++) {
97                 ret += ndr_size_security_ace(&acl->aces[i], flags);
98         }
99         return ret;
100 }
101
102 /*
103   return the wire size of a security descriptor
104 */
105 size_t ndr_size_security_descriptor(const struct security_descriptor *sd, int flags)
106 {
107         size_t ret;
108         if (!sd) return 0;
109         
110         ret = 20;
111         ret += ndr_size_dom_sid(sd->owner_sid, flags);
112         ret += ndr_size_dom_sid(sd->group_sid, flags);
113         ret += ndr_size_security_acl(sd->dacl, flags);
114         ret += ndr_size_security_acl(sd->sacl, flags);
115         return ret;
116 }
117
118 /*
119   print a dom_sid
120 */
121 void ndr_print_dom_sid(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
122 {
123         ndr->print(ndr, "%-25s: %s", name, dom_sid_string(ndr, sid));
124 }
125
126 void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
127 {
128         ndr_print_dom_sid(ndr, name, sid);
129 }
130
131 void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
132 {
133         ndr_print_dom_sid(ndr, name, sid);
134 }
135
136 void ndr_print_dom_sid0(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
137 {
138         ndr_print_dom_sid(ndr, name, sid);
139 }
140
141
142 /*
143   parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
144 */
145 enum ndr_err_code ndr_pull_dom_sid2(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid)
146 {
147         uint32_t num_auths;
148         if (!(ndr_flags & NDR_SCALARS)) {
149                 return NDR_ERR_SUCCESS;
150         }
151         NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &num_auths));
152         NDR_CHECK(ndr_pull_dom_sid(ndr, ndr_flags, sid));
153         if (sid->num_auths != num_auths) {
154                 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, 
155                                       "Bad array size %u should exceed %u", 
156                                       num_auths, sid->num_auths);
157         }
158         return NDR_ERR_SUCCESS;
159 }
160
161 /*
162   parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
163 */
164 enum ndr_err_code ndr_push_dom_sid2(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid)
165 {
166         if (!(ndr_flags & NDR_SCALARS)) {
167                 return NDR_ERR_SUCCESS;
168         }
169         NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, sid->num_auths));
170         return ndr_push_dom_sid(ndr, ndr_flags, sid);
171 }
172
173 /*
174   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
175 */
176 enum ndr_err_code ndr_pull_dom_sid28(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid)
177 {
178         enum ndr_err_code status;
179         struct ndr_pull *subndr;
180
181         if (!(ndr_flags & NDR_SCALARS)) {
182                 return NDR_ERR_SUCCESS;
183         }
184
185         subndr = talloc_zero(ndr, struct ndr_pull);
186         NDR_ERR_HAVE_NO_MEMORY(subndr);
187         subndr->flags           = ndr->flags;
188         subndr->current_mem_ctx = ndr->current_mem_ctx;
189
190         subndr->data            = ndr->data + ndr->offset;
191         subndr->data_size       = 28;
192         subndr->offset          = 0;
193
194         NDR_CHECK(ndr_pull_advance(ndr, 28));
195
196         status = ndr_pull_dom_sid(subndr, ndr_flags, sid);
197         if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
198                 /* handle a w2k bug which send random data in the buffer */
199                 ZERO_STRUCTP(sid);
200         } else if (sid->num_auths == 0 && sid->sub_auths) {
201                 talloc_free(sid->sub_auths);
202                 sid->sub_auths = NULL;
203         }
204
205         return NDR_ERR_SUCCESS;
206 }
207
208 /*
209   push a dom_sid28 - this is a dom_sid in a 28 byte fixed buffer
210 */
211 enum ndr_err_code ndr_push_dom_sid28(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid)
212 {
213         uint32_t old_offset;
214         uint32_t padding;
215
216         if (!(ndr_flags & NDR_SCALARS)) {
217                 return NDR_ERR_SUCCESS;
218         }
219
220         if (sid->num_auths > 5) {
221                 return ndr_push_error(ndr, NDR_ERR_RANGE, 
222                                       "dom_sid28 allows only upto 5 sub auth [%u]", 
223                                       sid->num_auths);
224         }
225
226         old_offset = ndr->offset;
227         NDR_CHECK(ndr_push_dom_sid(ndr, ndr_flags, sid));
228
229         padding = 28 - (ndr->offset - old_offset);
230
231         if (padding > 0) {
232                 NDR_CHECK(ndr_push_zero(ndr, padding));
233         }
234
235         return NDR_ERR_SUCCESS;
236 }
237
238 /*
239   parse a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty
240 */
241 enum ndr_err_code ndr_pull_dom_sid0(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid)
242 {
243         if (!(ndr_flags & NDR_SCALARS)) {
244                 return NDR_ERR_SUCCESS;
245         }
246
247         if (ndr->data_size == ndr->offset) {
248                 ZERO_STRUCTP(sid);
249                 return NDR_ERR_SUCCESS;
250         }
251
252         return ndr_pull_dom_sid(ndr, ndr_flags, sid);
253 }
254
255 /*
256   push a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty
257 */
258 enum ndr_err_code ndr_push_dom_sid0(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid)
259 {
260         struct dom_sid zero_sid;
261
262         if (!(ndr_flags & NDR_SCALARS)) {
263                 return NDR_ERR_SUCCESS;
264         }
265
266         if (!sid) {
267                 return NDR_ERR_SUCCESS;
268         }
269
270         ZERO_STRUCT(zero_sid);
271
272         if (memcmp(&zero_sid, sid, sizeof(zero_sid)) == 0) {
273                 return NDR_ERR_SUCCESS;
274         }
275
276         return ndr_push_dom_sid(ndr, ndr_flags, sid);
277 }
278