Added NT_USER_TOKEN into server_info to fix extra groups problem.
[tprouty/samba.git] / source3 / libsmb / asn1.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    simple SPNEGO routines
5    Copyright (C) Andrew Tridgell 2001
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 /* free an asn1 structure */
25 void asn1_free(ASN1_DATA *data)
26 {
27         SAFE_FREE(data->data);
28 }
29
30 /* write to the ASN1 buffer, advancing the buffer pointer */
31 BOOL asn1_write(ASN1_DATA *data, const void *p, int len)
32 {
33         if (data->has_error) return False;
34         if (data->length < data->ofs+len) {
35                 uint8 *newp;
36                 newp = Realloc(data->data, data->ofs+len);
37                 if (!newp) {
38                         SAFE_FREE(data->data);
39                         data->has_error = True;
40                         return False;
41                 }
42                 data->data = newp;
43                 data->length = data->ofs+len;
44         }
45         memcpy(data->data + data->ofs, p, len);
46         data->ofs += len;
47         return True;
48 }
49
50 /* useful fn for writing a uint8 */
51 BOOL asn1_write_uint8(ASN1_DATA *data, uint8 v)
52 {
53         return asn1_write(data, &v, 1);
54 }
55
56 /* push a tag onto the asn1 data buffer. Used for nested structures */
57 BOOL asn1_push_tag(ASN1_DATA *data, uint8 tag)
58 {
59         struct nesting *nesting;
60
61         asn1_write_uint8(data, tag);
62         nesting = (struct nesting *)malloc(sizeof(struct nesting));
63         if (!nesting) {
64                 data->has_error = True;
65                 return False;
66         }
67
68         nesting->start = data->ofs;
69         nesting->next = data->nesting;
70         data->nesting = nesting;
71         return asn1_write_uint8(data, 0xff);
72 }
73
74 /* pop a tag */
75 BOOL asn1_pop_tag(ASN1_DATA *data)
76 {
77         struct nesting *nesting;
78         size_t len;
79
80         nesting = data->nesting;
81
82         if (!nesting) {
83                 data->has_error = True;
84                 return False;
85         }
86         len = data->ofs - (nesting->start+1);
87         /* yes, this is ugly. We don't know in advance how many bytes the length
88            of a tag will take, so we assumed 1 byte. If we were wrong then we 
89            need to correct our mistake */
90         if (len > 255) {
91                 data->data[nesting->start] = 0x82;
92                 if (!asn1_write_uint8(data, 0)) return False;
93                 if (!asn1_write_uint8(data, 0)) return False;
94                 memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
95                 data->data[nesting->start+1] = len>>8;
96                 data->data[nesting->start+2] = len&0xff;
97         } else if (len > 127) {
98                 data->data[nesting->start] = 0x81;
99                 if (!asn1_write_uint8(data, 0)) return False;
100                 memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
101                 data->data[nesting->start+1] = len;
102         } else {
103                 data->data[nesting->start] = len;
104         }
105
106         data->nesting = nesting->next;
107         free(nesting);
108         return True;
109 }
110
111 /* write an object ID to a ASN1 buffer */
112 BOOL asn1_write_OID(ASN1_DATA *data, const char *OID)
113 {
114         unsigned v, v2;
115         const char *p = (const char *)OID;
116         char *newp;
117
118         if (!asn1_push_tag(data, ASN1_OID))
119                 return False;
120         v = strtol(p, &newp, 10);
121         p = newp;
122         v2 = strtol(p, &newp, 10);
123         p = newp;
124         if (!asn1_write_uint8(data, 40*v + v2))
125                 return False;
126
127         while (*p) {
128                 v = strtol(p, &newp, 10);
129                 p = newp;
130                 if (v >= (1<<28)) asn1_write_uint8(data, 0x80 | ((v>>28)&0xff));
131                 if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff));
132                 if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff));
133                 if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff));
134                 if (!asn1_write_uint8(data, v&0x7f))
135                         return False;
136         }
137         return asn1_pop_tag(data);
138 }
139
140 /* write an octet string */
141 BOOL asn1_write_OctetString(ASN1_DATA *data, const void *p, size_t length)
142 {
143         asn1_push_tag(data, ASN1_OCTET_STRING);
144         asn1_write(data, p, length);
145         asn1_pop_tag(data);
146         return !data->has_error;
147 }
148
149 /* write a general string */
150 BOOL asn1_write_GeneralString(ASN1_DATA *data, const char *s)
151 {
152         asn1_push_tag(data, ASN1_GENERAL_STRING);
153         asn1_write(data, s, strlen(s));
154         asn1_pop_tag(data);
155         return !data->has_error;
156 }
157
158 /* write a BOOLEAN */
159 BOOL asn1_write_BOOLEAN(ASN1_DATA *data, BOOL v)
160 {
161         asn1_write_uint8(data, ASN1_BOOLEAN);
162         asn1_write_uint8(data, v);
163         return !data->has_error;
164 }
165
166 /* check a BOOLEAN */
167 BOOL asn1_check_BOOLEAN(ASN1_DATA *data, BOOL v)
168 {
169         uint8 b = 0;
170
171         asn1_read_uint8(data, &b);
172         if (b != ASN1_BOOLEAN) {
173                 data->has_error = True;
174                 return False;
175         }
176         asn1_read_uint8(data, &b);
177         if (b != v) {
178                 data->has_error = True;
179                 return False;
180         }
181         return !data->has_error;
182 }
183
184
185 /* load a ASN1_DATA structure with a lump of data, ready to be parsed */
186 BOOL asn1_load(ASN1_DATA *data, DATA_BLOB blob)
187 {
188         ZERO_STRUCTP(data);
189         data->data = memdup(blob.data, blob.length);
190         if (!data->data) {
191                 data->has_error = True;
192                 return False;
193         }
194         data->length = blob.length;
195         return True;
196 }
197
198 /* read from a ASN1 buffer, advancing the buffer pointer */
199 BOOL asn1_read(ASN1_DATA *data, void *p, int len)
200 {
201         if (data->ofs + len > data->length) {
202                 data->has_error = True;
203                 return False;
204         }
205         memcpy(p, data->data + data->ofs, len);
206         data->ofs += len;
207         return True;
208 }
209
210 /* read a uint8 from a ASN1 buffer */
211 BOOL asn1_read_uint8(ASN1_DATA *data, uint8 *v)
212 {
213         return asn1_read(data, v, 1);
214 }
215
216 /* start reading a nested asn1 structure */
217 BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag)
218 {
219         uint8 b;
220         struct nesting *nesting;
221         
222         asn1_read_uint8(data, &b);
223         if (b != tag) {
224                 data->has_error = True;
225                 return False;
226         }
227         nesting = (struct nesting *)malloc(sizeof(struct nesting));
228         if (!nesting) {
229                 data->has_error = True;
230                 return False;
231         }
232
233         asn1_read_uint8(data, &b);
234         if (b & 0x80) {
235                 int n = b & 0x7f;
236                 if (n > 2) {
237                         data->has_error = True;
238                         return False;
239                 }
240                 asn1_read_uint8(data, &b);
241                 nesting->taglen = b;
242                 if (n == 2) {
243                         asn1_read_uint8(data, &b);
244                         nesting->taglen = (nesting->taglen << 8) | b;
245                 }
246         } else {
247                 nesting->taglen = b;
248         }
249         nesting->start = data->ofs;
250         nesting->next = data->nesting;
251         data->nesting = nesting;
252         return !data->has_error;
253 }
254
255
256 /* stop reading a tag */
257 BOOL asn1_end_tag(ASN1_DATA *data)
258 {
259         struct nesting *nesting;
260
261         /* make sure we read it all */
262         if (asn1_tag_remaining(data) != 0) {
263                 data->has_error = True;
264                 return False;
265         }
266
267         nesting = data->nesting;
268
269         if (!nesting) {
270                 data->has_error = True;
271                 return False;
272         }
273
274         data->nesting = nesting->next;
275         free(nesting);
276         return True;
277 }
278
279 /* work out how many bytes are left in this nested tag */
280 int asn1_tag_remaining(ASN1_DATA *data)
281 {
282         if (!data->nesting) {
283                 data->has_error = True;
284                 return -1;
285         }
286         return data->nesting->taglen - (data->ofs - data->nesting->start);
287 }
288
289 /* read an object ID from a ASN1 buffer */
290 BOOL asn1_read_OID(ASN1_DATA *data, char **OID)
291 {
292         uint8 b;
293         pstring oid;
294         fstring el;
295
296         if (!asn1_start_tag(data, ASN1_OID)) return False;
297         asn1_read_uint8(data, &b);
298
299         oid[0] = 0;
300         snprintf(el, sizeof(el), "%u",  b/40);
301         pstrcat(oid, el);
302         snprintf(el, sizeof(el), " %u",  b%40);
303         pstrcat(oid, el);
304
305         while (asn1_tag_remaining(data) > 0) {
306                 unsigned v = 0;
307                 do {
308                         asn1_read_uint8(data, &b);
309                         v = (v<<7) | (b&0x7f);
310                 } while (!data->has_error && b & 0x80);
311                 snprintf(el, sizeof(el), " %u",  v);
312                 pstrcat(oid, el);
313         }
314
315         asn1_end_tag(data);
316
317         *OID = strdup(oid);
318
319         return !data->has_error;
320 }
321
322 /* check that the next object ID is correct */
323 BOOL asn1_check_OID(ASN1_DATA *data, char *OID)
324 {
325         char *id;
326
327         if (!asn1_read_OID(data, &id)) return False;
328
329         if (strcmp(id, OID) != 0) {
330                 data->has_error = True;
331                 return False;
332         }
333         free(id);
334         return True;
335 }
336
337 /* read a GeneralString from a ASN1 buffer */
338 BOOL asn1_read_GeneralString(ASN1_DATA *data, char **s)
339 {
340         int len;
341         if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return False;
342         len = asn1_tag_remaining(data);
343         *s = malloc(len+1);
344         if (! *s) {
345                 data->has_error = True;
346                 return False;
347         }
348         asn1_read(data, *s, len);
349         (*s)[len] = 0;
350         asn1_end_tag(data);
351         return !data->has_error;
352 }
353
354 /* read a octet string blob */
355 BOOL asn1_read_OctetString(ASN1_DATA *data, DATA_BLOB *blob)
356 {
357         int len;
358         if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return False;
359         len = asn1_tag_remaining(data);
360         blob->data = malloc(len);
361         if (!blob->data) {
362                 data->has_error = True;
363                 return False;
364         }
365         asn1_read(data, blob->data, len);
366         blob->length = len;
367         asn1_end_tag(data);
368         return !data->has_error;
369 }
370
371 /* check a enumarted value is correct */
372 BOOL asn1_check_enumerated(ASN1_DATA *data, int v)
373 {
374         uint8 b;
375         if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
376         asn1_read_uint8(data, &b);
377         asn1_end_tag(data);
378         return !data->has_error && (v == b);
379 }
380
381 /* check a enumarted value is correct */
382 BOOL asn1_write_enumerated(ASN1_DATA *data, uint8 v)
383 {
384         if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
385         asn1_write_uint8(data, v);
386         asn1_pop_tag(data);
387         return !data->has_error;
388 }