1
2 /*
3
4 Arbitrary Attribute Interchange Protocol , AAIP versions 0.2 , 1.0 , 2.0.
5 Implementation of encoding and decoding xattr and ACL.
6
7 See libisofs/aaip_0_2.h
8 http://libburnia-project.org/wiki/AAIP
9
10 Copyright (c) 2009 - 2019 Thomas Schmitt
11
12 This file is part of the libisofs project; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License version 2
14 or later as published by the Free Software Foundation.
15 See COPYING file for details.
16
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include "../config.h"
21 #endif
22
23 #include <ctype.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <pwd.h>
30 #include <grp.h>
31 #include <sys/stat.h>
32
33 #include "libisofs.h"
34 #include "util.h"
35 #include "messages.h"
36
37 /*
38 #define Aaip_encode_debuG 1
39 */
40
41 #include "aaip_0_2.h"
42
43 #define Aaip_EXEC 1
44 #define Aaip_WRITE 2
45 #define Aaip_READ 4
46
47 #define Aaip_TRANSLATE 0
48 #define Aaip_ACL_USER_OBJ 1
49 #define Aaip_ACL_USER 2
50 #define Aaip_ACL_GROUP_OBJ 3
51 #define Aaip_ACL_GROUP 4
52 #define Aaip_ACL_MASK 5
53 #define Aaip_ACL_OTHER 6
54 #define Aaip_SWITCH_MARK 8
55 #define Aaip_ACL_USER_N 10
56 #define Aaip_ACL_GROUP_N 12
57 #define Aaip_FUTURE_VERSION 15
58
59 #define Aaip_with_short_namespaceS yes
60 #define Aaip_max_named_spacE 0x06
61 #define Aaip_min_named_spacE 0x02
62 #define Aaip_maxdef_namespacE 0x1f
63
64 #define Aaip_namespace_literaL 0x01
65 #define Aaip_namespace_systeM 0x02
66 #define Aaip_namespace_useR 0x03
67 #define Aaip_namespace_isofS 0x04
68 #define Aaip_namespace_trusteD 0x05
69 #define Aaip_namespace_securitY 0x06
70
71 /* maximum expansion: "security." */
72 #define Aaip_max_name_expansioN 9
73
74 static char Aaip_namespace_textS[][Aaip_max_name_expansioN + 1]=
75 {"", "", "system.", "user.", "isofs.", "trusted.", "security."};
76
77 /* --------------------------------- Encoder ---------------------------- */
78
79
80 static int aaip_encode_pair(char *name, size_t attr_length, char *attr,
81 unsigned int *num_recs, size_t *comp_size,
82 unsigned char *result, size_t result_fill,
83 int flag);
84
85
86 /* Convert an array of Arbitrary Attributes into a series of AAIP fields.
87 @param num_attrs Number of attributes
88 @param names Array of pointers to 0 terminated name strings
89 @param value_lengths Array of byte lengths for each value
90 @param values Array of pointers to the value bytes
91 @param result_len Number of bytes in the resulting SUSP field string
92 @param result *result will point to the start of the result string.
93 This is malloc() memory which needs to be freed when
94 no longer needed
95 @param flag Bitfield for control purposes
96 bit0= set CONTINUE bit of last AAIP field to 1
97 @return >= 0 is the number of SUSP fields generated,
98 < 0 means error
99 */
aaip_encode(size_t num_attrs,char ** names,size_t * value_lengths,char ** values,size_t * result_len,unsigned char ** result,int flag)100 ssize_t aaip_encode(size_t num_attrs, char **names,
101 size_t *value_lengths, char **values,
102 size_t *result_len, unsigned char **result, int flag)
103 {
104 size_t mem_size= 0, comp_size;
105 ssize_t ret;
106 unsigned int number_of_fields, i, num_recs;
107
108 /* Predict memory needs, number of SUSP fields and component records */
109 *result = NULL;
110 *result_len= 0;
111 for(i= 0; i < num_attrs; i++) {
112 ret= aaip_encode_pair(names[i], value_lengths[i], values[i],
113 &num_recs, &comp_size, NULL, (size_t) 0, 1);
114 if(ret < 0)
115 return(ret);
116 mem_size+= comp_size;
117 }
118 number_of_fields= mem_size / 250 + !!(mem_size % 250);
119 if(number_of_fields == 0)
120 return(0);
121 mem_size+= number_of_fields * 5;
122
123 #ifdef Aaip_encode_debuG
124 *result= (unsigned char *) calloc(1, mem_size + 1024000);
125 /* generous honeypot for overflows */
126 #else
127 *result= (unsigned char *) calloc(1, mem_size);
128 #endif
129
130 if(*result == NULL)
131 return ISO_OUT_OF_MEM;
132
133 /* Encode pairs into result */
134 for(i= 0; i < num_attrs; i++) {
135 ret= aaip_encode_pair(names[i], value_lengths[i], values[i],
136 &num_recs, &comp_size, *result, *result_len, 0);
137 if(ret < 0) {
138 free(*result);
139 *result = NULL;
140 *result_len = 0;
141 return(ret);
142 }
143 (*result_len)+= comp_size;
144 }
145
146 /* write the field headers */
147 for(i= 0; i < number_of_fields; i++) {
148 (*result)[i * 255 + 0]= 'A';
149 (*result)[i * 255 + 1]= 'L';
150 if(i < number_of_fields - 1 || (mem_size % 255) == 0)
151 (*result)[i * 255 + 2]= 255;
152 else
153 (*result)[i * 255 + 2]= mem_size % 255;
154 (*result)[i * 255 + 3]= 1;
155 (*result)[i * 255 + 4]= (flag & 1) || (i < number_of_fields - 1);
156 }
157 (*result_len)+= number_of_fields * 5;
158
159 #ifdef Aaip_encode_debuG
160 if(*result_len != mem_size) {
161 fprintf(stderr, "aaip_encode(): MEMORY MISMATCH BY %d BYTES\n",
162 (int) (mem_size - *result_len));
163 } else {
164 unsigned char *hpt;
165 hpt= malloc(*result_len);
166 if(hpt != NULL) {
167 memcpy(hpt, *result, *result_len);
168 free(*result);
169 *result= hpt;
170 }
171 }
172 ret= 0;
173 for(i= 0; i < *result_len; i+= ((unsigned char *) (*result))[i + 2])
174 ret++;
175 if(ret != (int) number_of_fields) {
176 fprintf(stderr, "aaip_encode(): WRONG NUMBER OF FIELDS %d <> %d\n",
177 (int) number_of_fields, ret);
178 }
179 #endif /* Aaip_encode_debuG */
180
181 return(number_of_fields);
182 }
183
184
aaip_encode_byte(unsigned char * result,size_t * result_fill,unsigned char value)185 static void aaip_encode_byte(unsigned char *result, size_t *result_fill,
186 unsigned char value)
187 {
188 result[(*result_fill / 250) * 255 + 5 + (*result_fill % 250)]= value;
189 (*result_fill)++;
190 }
191
192
aaip_encode_comp(unsigned char * result,size_t * result_fill,int prefix,char * data,size_t l,int flag)193 static int aaip_encode_comp(unsigned char *result, size_t *result_fill,
194 int prefix, char *data, size_t l, int flag)
195 {
196 size_t todo;
197 char *rpt, *comp_start;
198
199 if(l == 0 && prefix <= 0) {
200 aaip_encode_byte(result, result_fill, 0);
201 aaip_encode_byte(result, result_fill, 0);
202 return(1);
203 }
204 for(rpt= data; rpt - data < (ssize_t) l;) {
205 todo= l - (rpt - data) + (prefix > 0);
206 aaip_encode_byte(result, result_fill, (todo > 255));
207 if(todo > 255)
208 todo= 255;
209 aaip_encode_byte(result, result_fill, todo);
210 if(prefix > 0) {
211 aaip_encode_byte(result, result_fill, prefix);
212 todo--;
213 prefix= 0;
214 }
215 for(comp_start= rpt; rpt - comp_start < (ssize_t) todo; rpt++)
216 aaip_encode_byte(result, result_fill, *((unsigned char *) rpt));
217 }
218 return(1);
219 }
220
221
222 /* Write the component records for name and attr. Skip the positions of
223 AAIP field headers.
224 @param flag bit0= only count but do not produce result
225 */
aaip_encode_pair(char * name,size_t attr_length,char * attr,unsigned int * num_recs,size_t * comp_size,unsigned char * result,size_t result_fill,int flag)226 static int aaip_encode_pair(char *name, size_t attr_length, char *attr,
227 unsigned int *num_recs, size_t *comp_size,
228 unsigned char *result, size_t result_fill,
229 int flag)
230 {
231 size_t l;
232 int i, prefix= 0;
233
234 #ifdef Aaip_with_short_namespaceS
235
236 /* translate name into eventual short form */
237 for(i= Aaip_min_named_spacE; i <= Aaip_max_named_spacE; i++)
238 if(strncmp(name, Aaip_namespace_textS[i], strlen(Aaip_namespace_textS[i]))
239 == 0) {
240 name+= strlen(Aaip_namespace_textS[i]);
241 prefix= i;
242 }
243 /* Eventually prepend escape marker for strange names */
244 if(prefix <= 0 && name[0] > 0 && name[0] <= Aaip_maxdef_namespacE)
245 prefix= Aaip_namespace_literaL;
246
247 #endif /* Aaip_with_short_namespaceS */
248
249 l= strlen(name) + (prefix > 0);
250 *num_recs= l / 255 + (!!(l % 255)) + (l == 0) +
251 attr_length / 255 + (!!(attr_length % 255)) + (attr_length == 0);
252 *comp_size= l + attr_length + 2 * *num_recs;
253
254 if(flag & 1)
255 return(1);
256
257 aaip_encode_comp(result, &result_fill, prefix, name, l - (prefix > 0), 0);
258 aaip_encode_comp(result, &result_fill, 0, attr, attr_length, 0);
259 return(1);
260 }
261
262
263 /* ----------- Encoder for ACLs ----------- */
264
265 static ssize_t aaip_encode_acl_text(char *acl_text, mode_t st_mode,
266 size_t result_size, unsigned char *result, int flag);
267
268
269 /* Convert an ACL text as of acl_to_text(3) into the value of an Arbitrary
270 Attribute. According to AAIP this value is to be stored together with
271 an empty name.
272 @param acl_text The ACL in long text form
273 @param st_mode The stat(2) permission bits to be used with flag bit3
274 @param result_len Number of bytes in the resulting value
275 @param result *result will point to the start of the result string.
276 This is malloc() memory which needs to be freed when
277 no longer needed
278 @param flag Bitfield for control purposes
279 bit0= count only
280 bit1= use numeric qualifiers rather than names
281 bit2= this is a default ACL, prepend SWITCH_MARK
282 bit3= check for completeness of list and eventually
283 fill up with entries deduced from st_mode
284 bit4= be verbose about failure causes
285 @return >0 means ok
286 <=0 means error
287 -1= out of memory
288 -2= program error with prediction of result size
289 -3= error with conversion of name to uid or gid
290 ISO_AAIP_ACL_MULT_OBJ= multiple entries of user::, group::, other::
291 */
aaip_encode_acl(char * acl_text,mode_t st_mode,size_t * result_len,unsigned char ** result,int flag)292 int aaip_encode_acl(char *acl_text, mode_t st_mode,
293 size_t *result_len, unsigned char **result, int flag)
294 {
295 ssize_t bytes;
296
297 *result= NULL;
298 *result_len= 0;
299 bytes= aaip_encode_acl_text(acl_text, st_mode,
300 (size_t) 0, NULL, 1 | (flag & (2 | 4 | 8 | 16)));
301 if(bytes < -2)
302 return(bytes);
303 if(bytes < 0)
304 return((int) bytes - 1);
305 if(flag & 1) {
306 *result_len= bytes;
307 return(1);
308 }
309 *result= calloc(bytes + 1, 1);
310 if(*result == NULL)
311 return(-1);
312 (*result)[bytes]= 0;
313 *result_len= bytes;
314 bytes= aaip_encode_acl_text(acl_text, st_mode, *result_len, *result,
315 (flag & (2 | 4 | 8 | 16)));
316 if(bytes < -2)
317 return(bytes);
318 if(bytes < 0)
319 return((int) bytes - 1);
320 if((size_t) bytes != *result_len) {
321 *result_len= 0;
322 return(-2);
323 }
324 return(1);
325 }
326
327
aaip_numeric_id(char * name,int flag)328 static double aaip_numeric_id(char *name, int flag)
329 {
330 double num;
331 char *cpt;
332
333 for(cpt= name; *cpt != 0; cpt++)
334 if(*cpt < '0' || *cpt >'9')
335 break;
336 if(*cpt != 0)
337 return(-1);
338 sscanf(name, "%lf", &num);
339 return(num);
340 }
341
342
aaip_make_aaip_perms(int r,int w,int x)343 static int aaip_make_aaip_perms(int r, int w, int x)
344 {
345 int perms;
346
347 perms= 0;
348 if(r)
349 perms|= Aaip_READ;
350 if(w)
351 perms|= Aaip_WRITE;
352 if(x)
353 perms|= Aaip_EXEC;
354 return(perms);
355 }
356
357
358 /*
359 @param result_size Number of bytes to store result
360 @param result Pointer to the start of the result string.
361 @param flag Bitfield for control purposes
362 bit0= count only, do not really produce bytes
363 bit1= use numeric qualifiers
364 bit2= this is a default ACL, prepend SWITCH_MARK 1
365 bit3= check for completeness of list and eventually
366 fill up with entries deduced from st_mode
367 bit4= be verbose about failure causes
368 @return >=0 number of bytes produced resp. counted
369 <0 means error
370 -1: result size overflow
371 -2: conversion error with user name or group name
372 ISO_AAIP_ACL_MULT_OBJ: multiple entries of user::, group::, other::
373 */
aaip_encode_acl_text(char * acl_text,mode_t st_mode,size_t result_size,unsigned char * result,int flag)374 static ssize_t aaip_encode_acl_text(char *acl_text, mode_t st_mode,
375 size_t result_size, unsigned char *result, int flag)
376 {
377 char *rpt, *npt, *cpt;
378 int qualifier= 0, perms, type, i, qualifier_len= 0, num_recs, needed= 0, ret;
379 unsigned int has_u= 0, has_g= 0, has_o= 0, has_m= 0, is_trivial= 1;
380 uid_t uid, huid;
381 gid_t gid, hgid;
382 ssize_t count= 0;
383 struct passwd *pwd;
384 struct group *grp;
385 char *name = NULL;
386 int name_size= 1024;
387 double num;
388
389 LIBISO_ALLOC_MEM(name, char, name_size);
390 if(flag & 4) {
391 /* set SWITCH_MARK to indicate a default ACL */;
392 if(!(flag & 1)) {
393 if((size_t) count >= result_size)
394 goto result_size_overflow;
395 result[count]= (Aaip_SWITCH_MARK << 4) | Aaip_EXEC;
396 }
397 count++;
398 }
399
400 for(rpt= acl_text; *rpt != 0; rpt= npt) {
401 npt= strchr(rpt, '\n');
402 if(npt == 0)
403 npt= rpt + strlen(rpt);
404 else
405 npt++;
406 if(*rpt == '#')
407 continue;
408 cpt= strchr(rpt, ':');
409 if(cpt == NULL)
410 continue;
411 cpt= strchr(cpt + 1, ':');
412 if(cpt == NULL)
413 continue;
414 qualifier= 0;
415 if(strncmp(rpt, "user:", 5) == 0) {
416 if(cpt - rpt == 5) {
417 type= Aaip_ACL_USER_OBJ;
418 if (has_u) {
419
420 /* >>> Duplicate u:: entry. */;
421 /* >>> ??? If it matches the previous one: ignore */
422
423 if(flag & 16)
424 iso_msg_submit(-1, ISO_AAIP_ACL_MULT_OBJ, 0,
425 "Duplicate u:: entry detected in ACL text");
426 ret = ISO_AAIP_ACL_MULT_OBJ;
427 goto ex;
428 }
429 has_u++;
430 } else {
431 if(cpt - (rpt + 5) >= name_size)
432 continue;
433 is_trivial= 0;
434 strncpy(name, rpt + 5, cpt - (rpt + 5));
435 name[cpt - (rpt + 5)]= 0;
436 if(flag & 2) {
437 type= Aaip_ACL_USER_N;
438 pwd= getpwnam(name);
439 if(pwd == NULL) {
440 num= aaip_numeric_id(name, 0);
441 if(num <= 0) {
442 /* ACL_USER is not part of AAIP 2.0 */
443 if(flag & 16)
444 iso_msg_submit(-1, ISO_AAIP_BAD_ACL_TEXT, 0,
445 "Unknown user name found in ACL text: '%s'", name);
446 {ret= -2; goto ex;}
447 }
448 uid= huid= num;
449 } else
450 uid= huid= pwd->pw_uid;
451 /* Convert uid into Qualifier Record */
452 for(i= 0; huid != 0; i++)
453 huid= huid >> 8;
454 qualifier_len= i;
455 if(qualifier_len <= 0)
456 qualifier_len= 1;
457 for(i= 0; i < qualifier_len ; i++)
458 name[i]= uid >> (8 * (qualifier_len - i - 1));
459 } else {
460 type= Aaip_ACL_USER;
461 qualifier_len= strlen(name);
462 if(qualifier_len <= 0)
463 qualifier_len= 1;
464 }
465 qualifier= 1;
466 }
467 } else if(strncmp(rpt, "group:", 6) == 0) {
468 if(cpt - rpt == 6) {
469 type= Aaip_ACL_GROUP_OBJ;
470 if (has_g) {
471
472 /* >>> Duplicate g:: entry. */;
473 /* >>> ??? If it matches the previous one: ignore */
474
475 if(flag & 16)
476 iso_msg_submit(-1, ISO_AAIP_ACL_MULT_OBJ, 0,
477 "Duplicate g:: entry detected in ACL text");
478 ret = ISO_AAIP_ACL_MULT_OBJ;
479 goto ex;
480 }
481 has_g++;
482 } else {
483 if(cpt - (rpt + 6) >= name_size)
484 continue;
485 is_trivial= 0;
486 strncpy(name, rpt + 6, cpt - (rpt + 6));
487 name[cpt - (rpt + 6)]= 0;
488 if(flag & 2) {
489 type= Aaip_ACL_GROUP_N;
490 grp= getgrnam(name);
491 if(grp == NULL) {
492 num= aaip_numeric_id(name, 0);
493 if(num <= 0) {
494 /* ACL_GROUP is not part of AAIP 2.0 */
495 if(flag & 16)
496 iso_msg_submit(-1, ISO_AAIP_BAD_ACL_TEXT, 0,
497 "Unknown group name found in ACL text: '%s'", name);
498 {ret= -2; goto ex;}
499 }
500 gid= hgid= num;
501 } else
502 gid= hgid= grp->gr_gid;
503 /* Convert gid into Qualifier Record */
504 for(i= 0; hgid != 0; i++)
505 hgid= hgid >> 8;
506 qualifier_len= i;
507 if(qualifier_len <= 0)
508 qualifier_len= 1;
509 for(i= 0; i < qualifier_len ; i++)
510 name[i]= gid >> (8 * (qualifier_len - i - 1));
511 } else {
512 type= Aaip_ACL_GROUP;
513 qualifier_len= strlen(name);
514 if(qualifier_len <= 0)
515 qualifier_len= 1;
516 }
517 qualifier= 1;
518 }
519 } else if(strncmp(rpt, "other:", 6) == 0) {
520 type= Aaip_ACL_OTHER;
521 if (has_o) {
522
523 /* >>> Duplicate o:: entry. */;
524 /* >>> ??? If it matches the previous one: ignore */
525
526 if(flag & 16)
527 iso_msg_submit(-1, ISO_AAIP_ACL_MULT_OBJ, 0,
528 "Duplicate o:: entry detected in ACL text");
529 ret = ISO_AAIP_ACL_MULT_OBJ;
530 goto ex;
531 }
532 has_o++;
533 } else if(strncmp(rpt, "mask:", 5) == 0) {
534 type= Aaip_ACL_MASK;
535 has_m++;
536 } else
537 continue;
538
539 if(npt - cpt < 4)
540 continue;
541 perms= aaip_make_aaip_perms(cpt[1] == 'r', cpt[2] == 'w', cpt[3] == 'x');
542
543 if(!(flag & 1)) {
544 if((size_t) count >= result_size)
545 goto result_size_overflow;
546 result[count]= perms | ((!!qualifier) << 3) | (type << 4);
547 }
548 count++;
549
550 if(qualifier) {
551 num_recs= (qualifier_len / 127) + !!(qualifier_len % 127);
552 if(!(flag & 1)) {
553 if((size_t) (count + 1) > result_size)
554 goto result_size_overflow;
555 for(i= 0; i < num_recs; i++) {
556 if(i < num_recs - 1)
557 result[count++]= 255;
558 else {
559 result[count++]= (qualifier_len % 127);
560 if(result[count - 1] == 0)
561 result[count - 1]= 127;
562 }
563 if((size_t) (count + (result[count - 1] & 127)) > result_size)
564 goto result_size_overflow;
565 memcpy(result + count, name + i * 127, result[count - 1] & 127);
566 count+= result[count - 1] & 127;
567 }
568 } else
569 count+= qualifier_len + num_recs;
570 }
571 }
572 if (flag & 8) {
573 /* add eventually missing mandatory ACL entries */
574 needed= (!has_u) + (!has_g) + (!has_o) + !(is_trivial || has_m);
575 if(flag & 1)
576 count+= needed;
577 else {
578 if((size_t) (count + needed) > result_size)
579 goto result_size_overflow;
580 }
581 }
582 if ((flag & 8) && needed > 0 && !(flag & 1)) {
583 if(!has_u) {
584 perms= aaip_make_aaip_perms(st_mode & S_IRUSR, st_mode & S_IWUSR,
585 st_mode * S_IXUSR);
586 result[count++]= perms | (Aaip_ACL_USER_OBJ << 4);
587 }
588 if(!has_g) {
589 perms= aaip_make_aaip_perms(st_mode & S_IRGRP, st_mode & S_IWGRP,
590 st_mode * S_IXGRP);
591 result[count++]= perms | (Aaip_ACL_GROUP_OBJ << 4);
592 }
593 if(!has_o) {
594 perms= aaip_make_aaip_perms(st_mode & S_IROTH, st_mode & S_IWOTH,
595 st_mode * S_IXOTH);
596 result[count++]= perms | (Aaip_ACL_OTHER << 4);
597 }
598 if(!(is_trivial | has_m)) {
599 perms= aaip_make_aaip_perms(st_mode & S_IRGRP, st_mode & S_IWGRP,
600 st_mode * S_IXGRP);
601 result[count++]= perms | (Aaip_ACL_MASK << 4);
602 }
603 }
604 ret= count;
605 ex:;
606 LIBISO_FREE_MEM(name);
607 return(ret);
608
609 result_size_overflow:;
610 if(flag & 16)
611 iso_msg_submit(-1, ISO_ASSERT_FAILURE, 0,
612 "Program error: Text to ACL conversion result size overflow");
613 ret= -1;
614 goto ex;
615 }
616
617
aaip_encode_both_acl(char * a_acl_text,char * d_acl_text,mode_t st_mode,size_t * result_len,unsigned char ** result,int flag)618 int aaip_encode_both_acl(char *a_acl_text, char *d_acl_text, mode_t st_mode,
619 size_t *result_len, unsigned char **result, int flag)
620 {
621 int ret;
622 size_t a_acl_len= 0, d_acl_len= 0, acl_len= 0;
623 unsigned char *a_acl= NULL, *d_acl= NULL, *acl= NULL;
624
625 if(a_acl_text != NULL) {
626 ret= aaip_encode_acl(a_acl_text, st_mode, &a_acl_len, &a_acl,
627 flag & (1 | 2 | 8 | 16));
628 if(ret <= 0)
629 goto ex;
630 }
631 if(d_acl_text != NULL) {
632 ret= aaip_encode_acl(d_acl_text, (mode_t) 0, &d_acl_len, &d_acl,
633 (flag & (1 | 2 | 16)) | 4);
634 if(ret <= 0)
635 goto ex;
636 }
637 if(a_acl == NULL || a_acl_len == 0) {
638 acl= d_acl;
639 d_acl= NULL;
640 acl_len= d_acl_len;
641 } else if (d_acl == NULL || d_acl_len == 0) {
642 acl= a_acl;
643 a_acl= NULL;
644 acl_len= a_acl_len;
645 } else {
646 acl= calloc(a_acl_len + d_acl_len, 1);
647 if(acl == NULL)
648 {ret = -1; goto ex;}
649 memcpy(acl, a_acl, a_acl_len);
650 memcpy(acl + a_acl_len, d_acl, d_acl_len);
651 acl_len= a_acl_len + d_acl_len;
652 }
653 *result= acl;
654 *result_len= acl_len;
655 ret= 1;
656 ex:;
657 if(a_acl != NULL)
658 free(a_acl);
659 if(d_acl != NULL)
660 free(d_acl);
661 return(ret);
662 }
663
664
665 /* GNU/Linux man 5 acl says:
666 The permissions defined by ACLs are a superset of the permissions speci-
667 fied by the file permission bits. The permissions defined for the file
668 owner correspond to the permissions of the ACL_USER_OBJ entry. The per-
669 missions defined for the file group correspond to the permissions of the
670 ACL_GROUP_OBJ entry, if the ACL has no ACL_MASK entry. If the ACL has an
671 ACL_MASK entry, then the permissions defined for the file group corre-
672 spond to the permissions of the ACL_MASK entry. The permissions defined
673 for the other class correspond to the permissions of the ACL_OTHER_OBJ
674 entry.
675
676 Modification of the file permission bits results in the modification of
677 the permissions in the associated ACL entries. Modification of the per-
678 missions in the ACL entries results in the modification of the file per-
679 mission bits.
680
681 */
682 /* Analyze occurrence of ACL tag types in long text form. If not disabled by
683 parameter flag remove the entries of type "user::" , "group::" , "other::" ,
684 or "other:" from an ACL in long text form if they match the bits in st_mode
685 as described by man 2 stat and man 5 acl.
686 @param acl_text The text to be analyzed and eventually shortened.
687 @param st_mode The component of struct stat which tells POSIX permission
688 bits and eventually shall take equivalent bits as read
689 from the ACL. The caller should submit a pointer
690 to the st_mode variable which holds permissions as
691 indicated by stat(2) resp. ECMA-119 and RRIP data.
692 @param flag bit0= do not remove entries, only determine return value
693 bit1= like bit0 but return immediately if a non-st_mode
694 ACL entry is found
695 bit2= update *st_mode by acl_text
696 ("user::" -> S_IRWXU, "mask::"|"group::" -> S_IRWXG,
697 "other::" -> S_IRWXO)
698 bit3= update acl_text by *st_mode (same mapping as bit 2
699 but with reversed transfer direction)
700 bit4= map "group::" <-> S_IRWXG in any case.
701 I.e. ignore "mask::".
702 @return <0 failure
703 >=0 tells in its bits which tag types were found.
704 The first three tell which types deviate from the
705 corresponding st_mode settings:
706 bit0= "other::" overrides S_IRWXO
707 bit1= "group::" overrides S_IRWXG (no "mask::" found)
708 bit2= "user::" overrides S_IRWXU
709 The second three tell which types comply with st_mode:
710 bit3= "other::" matches S_IRWXO
711 bit4= "group::" matches S_IRWXG (no "mask::" found)
712 bit5= "user::" matches S_IRWXU
713 Given the nature of ACLs nearly all combinations are
714 possible although some would come from invalid ACLs.
715 bit6= other ACL tag types are present. Particularly:
716 bit7= "user:...:" is present
717 bit8= "group:...:" is present
718 bit9= "mask::" is present
719 */
aaip_cleanout_st_mode(char * acl_text,mode_t * in_st_mode,int flag)720 int aaip_cleanout_st_mode(char *acl_text, mode_t *in_st_mode, int flag)
721 {
722 char *rpt, *wpt, *npt, *cpt;
723 mode_t m, list_mode, st_mode;
724 int tag_types= 0, has_mask= 0, do_cleanout = 0;
725
726 list_mode= st_mode= *in_st_mode;
727 do_cleanout = !(flag & 15);
728
729 has_mask= strncmp(acl_text, "mask:", 5) == 0 ||
730 strstr(acl_text, "\nmask:") != NULL;
731 if(has_mask && (flag & 2))
732 return(64 | 512);
733
734 for(npt= wpt= rpt= acl_text; *npt != 0; rpt= npt + 1) {
735 npt= strchr(rpt, '\n');
736 if(npt == NULL)
737 npt= rpt + strlen(rpt);
738 if(strncmp(rpt, "user:", 5) == 0) {
739 if(rpt[5] == ':' && npt - rpt == 9) {
740 cpt= rpt + 6;
741 m= 0;
742 if(cpt[0] == 'r')
743 m|= S_IRUSR;
744 if(cpt[1] == 'w')
745 m|= S_IWUSR;
746 if(cpt[2] == 'x')
747 m|= S_IXUSR;
748 list_mode= (list_mode & ~S_IRWXU) | m;
749 if((st_mode & S_IRWXU) == (m & S_IRWXU)) {
750 tag_types|= 32;
751 continue;
752 }
753 if(flag & 8) {
754 cpt[0]= st_mode & S_IRUSR ? 'r' : '-';
755 cpt[1]= st_mode & S_IWUSR ? 'w' : '-';
756 cpt[2]= st_mode & S_IXUSR ? 'x' : '-';
757 }
758 tag_types|= 4;
759 } else {
760 tag_types|= 64 | 128;
761 }
762 } else if(strncmp(rpt, "group:", 6) == 0) {
763 if(rpt[6] == ':' && npt - rpt == 10 && ((flag & 16) || !has_mask)) {
764 /* oddly: mask overrides group in st_mode */
765 cpt= rpt + 7;
766 m= 0;
767 if(cpt[0] == 'r')
768 m|= S_IRGRP;
769 if(cpt[1] == 'w')
770 m|= S_IWGRP;
771 if(cpt[2] == 'x')
772 m|= S_IXGRP;
773 list_mode= (list_mode & ~S_IRWXG) | m;
774 if((st_mode & S_IRWXG) == (m & S_IRWXG)) {
775 tag_types|= 16;
776 continue;
777 }
778 if(flag & 8) {
779 cpt[0]= st_mode & S_IRGRP ? 'r' : '-';
780 cpt[1]= st_mode & S_IWGRP ? 'w' : '-';
781 cpt[2]= st_mode & S_IXGRP ? 'x' : '-';
782 }
783 tag_types|= 2;
784 } else {
785 if(rpt[6] == ':' && npt - rpt == 10)
786 tag_types|= 1024;
787 else
788 tag_types|= 64 | 256;
789 }
790 } else if(strncmp(rpt, "other::", 7) == 0 && npt - rpt == 10) {
791 cpt= rpt + 7;
792 others_st_mode:;
793 m= 0;
794 if(cpt[0] == 'r')
795 m|= S_IROTH;
796 if(cpt[1] == 'w')
797 m|= S_IWOTH;
798 if(cpt[2] == 'x')
799 m|= S_IXOTH;
800 list_mode= (list_mode & ~S_IRWXO) | m;
801 if((st_mode & S_IRWXO) == (m & S_IRWXO)) {
802 tag_types|= 8;
803 continue;
804 }
805 if(flag & 8) {
806 cpt[0]= st_mode & S_IROTH ? 'r' : '-';
807 cpt[1]= st_mode & S_IWOTH ? 'w' : '-';
808 cpt[2]= st_mode & S_IXOTH ? 'x' : '-';
809 }
810 tag_types|= 1;
811 } else if(strncmp(rpt, "other:", 6) == 0 && npt - rpt == 9) {
812 cpt= rpt + 7;
813 goto others_st_mode;
814 } else if(strncmp(rpt, "mask::", 6) == 0 && npt - rpt == 9) {
815 cpt= rpt + 6;
816 mask_st_mode:;
817 tag_types|= 64 | 512;
818 if(!(flag & 16)) {
819 /* oddly: mask overrides group in st_mode */
820 m= 0;
821 if(cpt[0] == 'r')
822 m|= S_IRGRP;
823 if(cpt[1] == 'w')
824 m|= S_IWGRP;
825 if(cpt[2] == 'x')
826 m|= S_IXGRP;
827 list_mode= (list_mode & ~S_IRWXG) | m;
828 if(flag & 8) {
829 cpt[0]= st_mode & S_IRGRP ? 'r' : '-';
830 cpt[1]= st_mode & S_IWGRP ? 'w' : '-';
831 cpt[2]= st_mode & S_IXGRP ? 'x' : '-';
832 }
833 }
834 } else if(strncmp(rpt, "mask:", 5) == 0 && npt - rpt == 8) {
835 cpt= rpt + 5;
836 goto mask_st_mode;
837 } else if(*rpt != 0) {
838 tag_types|= 64;
839 }
840 if (flag & 2)
841 goto ex;
842 if(wpt == rpt) {
843 wpt= npt + 1;
844 continue;
845 }
846 if(do_cleanout)
847 memmove(wpt, rpt, 1 + npt - rpt);
848 wpt+= 1 + npt - rpt;
849 }
850 if(do_cleanout) {
851 if(wpt == acl_text)
852 *wpt= 0;
853 else if(*(wpt - 1) != 0)
854 *wpt= 0;
855 }
856 ex:;
857 if(flag & 4)
858 *in_st_mode= list_mode;
859 return(tag_types);
860 }
861
862
863 /* Important: acl_text must provide 42 bytes more than its current length !
864 */
aaip_add_acl_st_mode(char * acl_text,mode_t st_mode,int flag)865 int aaip_add_acl_st_mode(char *acl_text, mode_t st_mode, int flag)
866 {
867 char *wpt;
868 int tag_types= 0;
869
870 tag_types = aaip_cleanout_st_mode(acl_text, &st_mode, 1);
871 if(!(tag_types & (4 | 32))) {
872 wpt= acl_text + strlen(acl_text);
873 sprintf(wpt, "user::%c%c%c\n",
874 st_mode & S_IRUSR ? 'r' : '-',
875 st_mode & S_IWUSR ? 'w' : '-',
876 st_mode & S_IXUSR ? 'x' : '-');
877 }
878 if(!(tag_types & (2 | 16 | 1024))) {
879 wpt= acl_text + strlen(acl_text);
880 sprintf(wpt, "group::%c%c%c\n",
881 st_mode & S_IRGRP ? 'r' : '-',
882 st_mode & S_IWGRP ? 'w' : '-',
883 st_mode & S_IXGRP ? 'x' : '-');
884 }
885 if(!(tag_types & (1 | 8))) {
886 wpt= acl_text + strlen(acl_text);
887 sprintf(wpt, "other::%c%c%c\n",
888 st_mode & S_IROTH ? 'r' : '-',
889 st_mode & S_IWOTH ? 'w' : '-',
890 st_mode & S_IXOTH ? 'x' : '-');
891 }
892 if((tag_types & (128 | 256)) && !(tag_types & 512)) {
893 wpt= acl_text + strlen(acl_text);
894 sprintf(wpt, "mask::%c%c%c\n",
895 st_mode & S_IRGRP ? 'r' : '-',
896 st_mode & S_IWGRP ? 'w' : '-',
897 st_mode & S_IXGRP ? 'x' : '-');
898 }
899 return(1);
900 }
901
902
903 /* --------------------------------- Decoder ---------------------------- */
904
905 /* --- private --- */
906
907 /* Not less than 2 * 2048 */
908 #define Aaip_buffer_sizE 4096
909
910 /* Enough for one full component record and three empty ones which might get
911 added in case of unclean end of attribute list.
912 */
913 #define Aaip_buffer_reservE (257 + 3 * 2)
914
915
916 struct aaip_state {
917
918 /* AAIP field status */
919 int aa_head_missing; /* number of bytes needed to complete field header */
920 int aa_missing; /* number of bytes needed to complete current field */
921 int aa_ends; /* 0= still fields expected, 1= last field being processed,
922 2= all fields processed, 3= all is delivered */
923
924 /* Buffer for component records */
925 int recs_invalid; /* number of components to skip */
926 unsigned char recs[Aaip_buffer_sizE + Aaip_buffer_reservE];
927 size_t recs_fill;
928 unsigned char *recs_start;
929 int rec_head_missing; /* number of bytes needed to complete rec header */
930 int rec_missing; /* number of bytes needed to complete current rec */
931 int rec_ends;
932
933 /* Counter for completed data */
934 unsigned int num_recs;
935 size_t ready_bytes;
936
937 /* Counter and meaning for completed components */
938 unsigned int num_components;
939 size_t end_of_components; /* start index of eventual incomplete component */
940 int first_is_name;
941
942 /* Last return value of aaip_decode_pair() */
943 int pair_status;
944 unsigned int pairs_skipped;
945
946 /* status of aaip_decode_attrs() */
947 size_t list_mem_used;
948 size_t list_size;
949 size_t list_num_attrs;
950 char **list_names;
951 size_t *list_value_lengths;
952 char **list_values;
953 char *name_buf;
954 size_t name_buf_size;
955 size_t name_buf_fill;
956 char *value_buf;
957 size_t value_buf_size;
958 size_t value_buf_fill;
959 int list_pending_pair;
960 };
961
962
963 /* ------- functions ------ */
964
965
aaip_count_bytes(unsigned char * data,int flag)966 size_t aaip_count_bytes(unsigned char *data, int flag)
967 {
968 int done = 0;
969 unsigned char *aapt;
970
971 for(aapt= data; !done; aapt += aapt[2])
972 done = !(aapt[4] & 1);
973 return((size_t) (aapt - data));
974 }
975
976
aaip_sizeof_aaip_state(void)977 size_t aaip_sizeof_aaip_state(void)
978 {
979 return((size_t) sizeof(struct aaip_state));
980 }
981
982
aaip_init_aaip_state(struct aaip_state * aaip,int flag)983 int aaip_init_aaip_state(struct aaip_state *aaip, int flag)
984 {
985 aaip->aa_head_missing= 5;
986 aaip->aa_missing= 0;
987
988 aaip->recs_invalid= 0;
989 memset(aaip->recs, 0, Aaip_buffer_sizE + Aaip_buffer_reservE);
990 aaip->recs_fill= 0;
991 aaip->recs_start= aaip->recs;
992 aaip->rec_head_missing= 2;
993 aaip->rec_missing= 0;
994 aaip->rec_ends= 0;
995
996 aaip->num_recs= 0;
997 aaip->ready_bytes= 0;
998
999 aaip->num_components= 0;
1000 aaip->end_of_components= 0;
1001 aaip->first_is_name= 1;
1002
1003 aaip->pair_status= 2;
1004 aaip->pairs_skipped= 0;
1005
1006 aaip->list_mem_used= 0;
1007 aaip->list_size= 0;
1008 aaip->list_num_attrs= 0;
1009 aaip->list_names= NULL;
1010 aaip->list_value_lengths= NULL;
1011 aaip->list_values= NULL;
1012 aaip->name_buf= NULL;
1013 aaip->name_buf_size= 0;
1014 aaip->name_buf_fill= 0;
1015 aaip->value_buf= NULL;
1016 aaip->value_buf_size= 0;
1017 aaip->value_buf_fill= 0;
1018 aaip->list_pending_pair= 0;
1019 return(1);
1020 }
1021
1022 /*
1023 */
1024 #define Aaip_with_ring_buffeR yes
1025
1026 #ifdef Aaip_with_ring_buffeR
1027
1028 /* Compute the one or two byte intervals in the ring buffer which form a
1029 given byte interval in the virtual shift fifo.
1030 @param idx The byte start index in the virtual shift fifo.
1031 @param todo Number of bytes to cover
1032 @param start_pt Will return the start address of the first interval
1033 @param at_start_pt Will return the size of the first interval
1034 @param at_recs Will return the size of the second interval which
1035 always starts at aaip->recs
1036 @param flag Bitfield for control purposes
1037 @return 1= next start_pt is *start_pt + *at_start_pt
1038 2= next start_pt is aaip->recs + *at_recs
1039 */
aaip_ring_adr(struct aaip_state * aaip,size_t idx,size_t todo,unsigned char ** start_pt,size_t * at_start_pt,size_t * at_recs,int flag)1040 static int aaip_ring_adr(struct aaip_state *aaip, size_t idx, size_t todo,
1041 unsigned char **start_pt, size_t *at_start_pt,
1042 size_t *at_recs, int flag)
1043 {
1044 size_t ahead;
1045
1046 ahead= Aaip_buffer_sizE + Aaip_buffer_reservE
1047 - (aaip->recs_start - aaip->recs);
1048 if(idx < ahead)
1049 *start_pt= (aaip->recs_start + idx);
1050 else
1051 *start_pt= aaip->recs + (idx - ahead);
1052 ahead= Aaip_buffer_sizE + Aaip_buffer_reservE - (*start_pt - aaip->recs);
1053 if(todo >= ahead) {
1054 *at_start_pt= ahead;
1055 *at_recs= todo - ahead;
1056 return(2);
1057 }
1058 *at_start_pt= todo;
1059 *at_recs= 0;
1060 return(1);
1061 }
1062
1063
1064 /*
1065 @param flag Bitfield for control purposes
1066 bit0= count as ready_bytes
1067 */
aaip_push_to_recs(struct aaip_state * aaip,unsigned char * data,size_t todo,int flag)1068 static int aaip_push_to_recs(struct aaip_state *aaip, unsigned char *data,
1069 size_t todo, int flag)
1070 {
1071 unsigned char *start_pt;
1072 size_t at_start_pt, at_recs;
1073
1074 aaip_ring_adr(aaip, aaip->recs_fill, todo,
1075 &start_pt, &at_start_pt, &at_recs, 0);
1076 if(at_start_pt > 0)
1077 memcpy(start_pt, data, at_start_pt);
1078 if(at_recs > 0)
1079 memcpy(aaip->recs, data + at_start_pt, at_recs);
1080 aaip->recs_fill+= todo;
1081 if(flag & 1)
1082 aaip->ready_bytes+= todo;
1083 return(1);
1084 }
1085
1086
aaip_read_from_recs(struct aaip_state * aaip,size_t idx,unsigned char * data,size_t num_data,int flag)1087 static int aaip_read_from_recs(struct aaip_state *aaip, size_t idx,
1088 unsigned char *data, size_t num_data, int flag)
1089 {
1090 unsigned char *start_pt;
1091 size_t at_start_pt, at_recs;
1092
1093 aaip_ring_adr(aaip, idx, num_data,
1094 &start_pt, &at_start_pt, &at_recs, 0);
1095 if(at_start_pt > 0)
1096 memcpy(data, start_pt, at_start_pt);
1097 if(at_recs > 0)
1098 memcpy(data + at_start_pt, aaip->recs, at_recs);
1099 return(1);
1100 }
1101
1102
aaip_set_buffer_byte(struct aaip_state * aaip,size_t idx,unsigned char data,int flag)1103 static int aaip_set_buffer_byte(struct aaip_state *aaip, size_t idx,
1104 unsigned char data, int flag)
1105 {
1106 unsigned char *start_pt;
1107 size_t at_start_pt, at_recs;
1108
1109 aaip_ring_adr(aaip, idx, 1,
1110 &start_pt, &at_start_pt, &at_recs, 0);
1111 *start_pt= data;
1112 return(1);
1113 }
1114
1115
aaip_get_buffer_byte(struct aaip_state * aaip,size_t idx,int flag)1116 static int aaip_get_buffer_byte(struct aaip_state *aaip, size_t idx, int flag)
1117 {
1118 unsigned char *start_pt;
1119 size_t at_start_pt, at_recs;
1120
1121 aaip_ring_adr(aaip, idx, 1,
1122 &start_pt, &at_start_pt, &at_recs, 0);
1123 return((int) *start_pt);
1124 }
1125
1126
aaip_shift_recs(struct aaip_state * aaip,size_t todo,int flag)1127 static int aaip_shift_recs(struct aaip_state *aaip, size_t todo, int flag)
1128 {
1129 int ret;
1130 unsigned char *start_pt;
1131 size_t at_start_pt, at_recs;
1132
1133 if(todo < aaip->recs_fill) {
1134 ret= aaip_ring_adr(aaip, 0, todo, &start_pt, &at_start_pt, &at_recs, 0);
1135 if(ret == 1)
1136 aaip->recs_start= start_pt + todo;
1137 else
1138 aaip->recs_start= aaip->recs + at_recs;
1139 } else {
1140 aaip->recs_start= aaip->recs;
1141 }
1142 aaip->recs_fill-= todo;
1143 if(aaip->end_of_components >= todo)
1144 aaip->end_of_components-= todo;
1145 else
1146 aaip->end_of_components= 0;
1147 return(1);
1148 }
1149
1150
1151 #else /* Aaip_with_ring_buffeR */
1152
1153
1154 /*
1155 @param flag Bitfield for control purposes
1156 bit0= count as ready_bytes
1157 */
aaip_push_to_recs(struct aaip_state * aaip,unsigned char * data,size_t todo,int flag)1158 static int aaip_push_to_recs(struct aaip_state *aaip, unsigned char *data,
1159 size_t todo, int flag)
1160 {
1161 memcpy(aaip->recs + aaip->recs_fill, data, todo);
1162 aaip->recs_fill+= todo;
1163 if(flag & 1)
1164 aaip->ready_bytes+= todo;
1165 return(1);
1166 }
1167
1168
aaip_read_from_recs(struct aaip_state * aaip,size_t idx,unsigned char * data,size_t num_data,int flag)1169 static int aaip_read_from_recs(struct aaip_state *aaip, size_t idx,
1170 unsigned char *data, size_t num_data, int flag)
1171 {
1172 memcpy(data, aaip->recs + idx, num_data);
1173 return(1);
1174 }
1175
1176
aaip_set_buffer_byte(struct aaip_state * aaip,size_t idx,unsigned char data,int flag)1177 static int aaip_set_buffer_byte(struct aaip_state *aaip, size_t idx,
1178 unsigned char data, int flag)
1179 {
1180 aaip->recs[idx]= data;
1181 return(1);
1182 }
1183
1184
aaip_get_buffer_byte(struct aaip_state * aaip,size_t idx,int flag)1185 static int aaip_get_buffer_byte(struct aaip_state *aaip, size_t idx, int flag)
1186 {
1187 return((int) aaip->recs[idx]);
1188 }
1189
1190
aaip_shift_recs(struct aaip_state * aaip,size_t todo,int flag)1191 static int aaip_shift_recs(struct aaip_state *aaip, size_t todo, int flag)
1192 {
1193 if(todo < aaip->recs_fill)
1194 memmove(aaip->recs, aaip->recs + todo, aaip->recs_fill - todo);
1195 aaip->recs_fill-= todo;
1196
1197 if(aaip->end_of_components >= todo)
1198 aaip->end_of_components-= todo;
1199 else
1200 aaip->end_of_components= 0;
1201 return(1);
1202 }
1203
1204
1205 #endif /* ! Aaip_with_ring_buffeR */
1206
1207
aaip_consume_rec_head(struct aaip_state * aaip,unsigned char ** data,size_t * num_data,int flag)1208 static int aaip_consume_rec_head(struct aaip_state *aaip,
1209 unsigned char **data, size_t *num_data, int flag)
1210 {
1211 size_t todo;
1212
1213 todo= *num_data;
1214 if(todo > (size_t) aaip->aa_missing)
1215 todo= aaip->aa_missing;
1216 if(todo >= (size_t) aaip->rec_head_missing)
1217 todo= aaip->rec_head_missing;
1218 if(!aaip->recs_invalid)
1219 aaip_push_to_recs(aaip, *data, todo, 0);
1220 aaip->rec_head_missing-= todo;
1221 if(aaip->rec_head_missing == 0) {
1222 aaip->rec_missing= aaip_get_buffer_byte(aaip, aaip->recs_fill - 1, 0);
1223 aaip->rec_ends= !(aaip_get_buffer_byte(aaip, aaip->recs_fill - 2, 0) & 1);
1224 }
1225 aaip->aa_missing-= todo;
1226 (*num_data)-= todo;
1227 (*data)+= todo;
1228 return(1);
1229 }
1230
1231
aaip_consume_rec_data(struct aaip_state * aaip,unsigned char ** data,size_t * num_data,int flag)1232 static int aaip_consume_rec_data(struct aaip_state *aaip,
1233 unsigned char **data, size_t *num_data, int flag)
1234 {
1235 size_t todo;
1236
1237 todo= *num_data;
1238 if(todo > (size_t) aaip->aa_missing)
1239 todo= aaip->aa_missing;
1240 if(todo > (size_t) aaip->rec_missing)
1241 todo= aaip->rec_missing;
1242 if(!aaip->recs_invalid)
1243 aaip_push_to_recs(aaip, *data, todo, 1);
1244 aaip->rec_missing-= todo;
1245 aaip->aa_missing-= todo;
1246 (*num_data)-= todo;
1247 (*data)+= todo;
1248 if(aaip->rec_missing <= 0) {
1249 if(aaip->recs_invalid > 0) {
1250 if(aaip->rec_ends)
1251 aaip->recs_invalid--;
1252 } else {
1253 aaip->num_recs++;
1254 if(aaip->rec_ends) {
1255 aaip->num_components++;
1256 aaip->end_of_components= aaip->recs_fill;
1257 }
1258 }
1259 aaip->rec_head_missing= 2;
1260 }
1261 return(0);
1262 }
1263
1264
aaip_consume_aa_head(struct aaip_state * aaip,unsigned char ** data,size_t * num_data,int flag)1265 static int aaip_consume_aa_head(struct aaip_state *aaip,
1266 unsigned char **data, size_t *num_data, int flag)
1267 {
1268 size_t todo;
1269 unsigned char aa_head[5];
1270
1271 todo= *num_data;
1272 if(todo >= (size_t) aaip->aa_head_missing)
1273 todo= aaip->aa_head_missing;
1274 aaip_push_to_recs(aaip, *data, todo, 0);
1275 aaip->aa_head_missing-= todo;
1276 if(aaip->aa_head_missing == 0) {
1277 aaip_read_from_recs(aaip, aaip->recs_fill - 5, aa_head, 5, 0);
1278 if(aa_head[0] != 'A' || (aa_head[1] != 'L' && aa_head[1] != 'A') ||
1279 aa_head[3] != 1)
1280 return(-1);
1281 aaip->aa_missing= aa_head[2];
1282 aaip->aa_ends= !(aa_head[4] & 1);
1283 aaip->recs_fill-= 5; /* AAIP field heads do not get delivered */
1284 if(aaip->aa_missing >= 5)
1285 aaip->aa_missing-= 5;
1286 else
1287 aaip->aa_missing= 0;
1288 }
1289 (*num_data)-= todo;
1290 (*data)+= todo;
1291 return(1);
1292 }
1293
1294
aaip_consume_aa_data(struct aaip_state * aaip,unsigned char ** data,size_t * num_data,int flag)1295 static int aaip_consume_aa_data(struct aaip_state *aaip,
1296 unsigned char **data, size_t *num_data, int flag)
1297 {
1298 size_t i;
1299 static unsigned char zero_char[2]= {0, 0};
1300
1301 while(*num_data > 0 && aaip->aa_missing > 0) {
1302 if(aaip->rec_head_missing > 0) {
1303 aaip_consume_rec_head(aaip, data, num_data, 0);
1304 if(*num_data == 0 || aaip->aa_missing <= 0)
1305 return(1);
1306 }
1307 aaip_consume_rec_data(aaip, data, num_data, 0);
1308 }
1309 if(aaip->aa_missing <= 0) {
1310 if(aaip->aa_ends) {
1311 /* Check for incomplete pair and eventually make emergency closure */
1312 if(aaip->rec_head_missing != 2) { /* incomplete record detected */
1313 if(aaip->rec_head_missing) {
1314 /* fake 0 length record */
1315 aaip_set_buffer_byte(aaip, aaip->recs_fill - 1, (unsigned char) 0, 0);
1316 aaip_push_to_recs(aaip, zero_char, 1, 0);
1317 } else {
1318 /* fill in missing btes */
1319 for(i= 0; (int) i < aaip->rec_missing; i++)
1320 aaip_push_to_recs(aaip, zero_char, 1, 1);
1321 }
1322 aaip->rec_head_missing= 2;
1323 aaip->rec_missing= 0;
1324 aaip->num_recs++;
1325 if(aaip->rec_ends) {
1326 aaip->num_components++;
1327 aaip->end_of_components= aaip->recs_fill;
1328 }
1329 }
1330 if(aaip->end_of_components != aaip->recs_fill &&
1331 aaip->end_of_components != 0) {
1332 /* incomplete component detected */
1333 /* add empty end record */
1334 aaip_push_to_recs(aaip, zero_char, 2, 0);
1335 aaip->num_recs++;
1336 aaip->num_components++;
1337 aaip->end_of_components= aaip->recs_fill;
1338 }
1339 if(!(aaip->first_is_name ^ (aaip->num_components % 2))) {
1340 /* value component is missing */
1341 /* add dummy component */
1342 aaip_push_to_recs(aaip, zero_char, 2, 0);
1343 aaip->num_recs++;
1344 aaip->num_components++;
1345 aaip->end_of_components= aaip->recs_fill;
1346 }
1347 aaip->aa_ends= 2;
1348 } else
1349 aaip->aa_head_missing= 5;
1350 }
1351 return(0);
1352 }
1353
1354
1355 /* Submit small data chunk for decoding.
1356 The return value will tell whether data are pending for being fetched.
1357 @param aaip The AAIP decoder context
1358 @param data Not more than 2048 bytes input for the decoder
1359 @parm num_data Number of bytes in data
1360 0 inquires the buffer status avoiding replies <= 0
1361 @param ready_bytes Number of decoded bytes ready for delivery
1362 @param flag Bitfield for control purposes
1363 @return -1= non-AAIP field detected
1364 *ready_bytes gives number of consumed bytes in data
1365 0= cannot accept data because buffer full
1366 1= no component record complete, submit more data
1367 2= component record complete, may be delivered
1368 3= component complete, may be delivered
1369 4= no component available, no more data expected, done
1370 */
aaip_submit_data(struct aaip_state * aaip,unsigned char * data,size_t num_data,size_t * ready_bytes,int flag)1371 int aaip_submit_data(struct aaip_state *aaip,
1372 unsigned char *data, size_t num_data,
1373 size_t *ready_bytes, int flag)
1374 {
1375 int ret;
1376 unsigned char *in_data;
1377
1378 if(aaip->aa_ends == 3)
1379 return(4);
1380 in_data= data;
1381 if(num_data == 0)
1382 goto ex;
1383 if(aaip->recs_fill + num_data > Aaip_buffer_sizE)
1384 return(0);
1385
1386 while(num_data > 0) {
1387 if(aaip->aa_head_missing > 0) {
1388 ret= aaip_consume_aa_head(aaip, &data, &num_data, 0);
1389 if(ret < 0) {
1390 *ready_bytes= data - in_data;
1391 return(-1);
1392 }
1393 if(num_data == 0 || aaip->aa_missing <= 0)
1394 goto ex;
1395 }
1396 aaip_consume_aa_data(aaip, &data, &num_data, 0);
1397 if(aaip->aa_missing)
1398 break;
1399 }
1400 ex:;
1401 *ready_bytes= aaip->ready_bytes;
1402 if(aaip->num_components > 0)
1403 return(3);
1404 if(aaip->num_recs > 0)
1405 return(2);
1406 if(aaip->aa_ends && aaip->aa_head_missing == 0 && aaip->aa_missing == 0)
1407 aaip->aa_ends= 2;
1408 if(aaip->aa_ends == 2 && aaip->num_recs == 0)
1409 aaip->aa_ends= 3;
1410 if(aaip->aa_ends == 3)
1411 return(4);
1412 return(1);
1413 }
1414
1415
1416 /* Fetch the available part of current component.
1417 The return value will tell whether it belongs to name or to value and
1418 whether that name or value is completed now.
1419 @param aaip The AAIP decoder context
1420 @param result Has to point to storage for the component data
1421 @param result_size Gives the amount of provided result storage
1422 @param num_result Will tell the number of fetched result bytes
1423 @param flag Bitfield for control purposes
1424 bit0= discard data rather than copying to result
1425 @return -2 = insufficient result_size
1426 -1 = no data ready for delivery
1427 0 = result holds the final part of a name
1428 1 = result holds an intermediate part of a name
1429 2 = result holds the final part of a value
1430 3 = result holds an intermediate part of a value
1431 */
aaip_fetch_data(struct aaip_state * aaip,char * result,size_t result_size,size_t * num_result,int flag)1432 int aaip_fetch_data(struct aaip_state *aaip,
1433 char *result, size_t result_size, size_t *num_result,
1434 int flag)
1435 {
1436 int ret= -1, complete= 0, payload;
1437 unsigned int i, num_bytes= 0, h;
1438
1439 if(aaip->num_recs == 0)
1440 return(-1);
1441
1442 /* Copy data until end of buffer or end of component */
1443 h= 0;
1444 for(i= 0; i < aaip->num_recs && !complete; i++) {
1445 payload= aaip_get_buffer_byte(aaip, h + 1, 0);
1446 if(!(flag & 1)) {
1447 if(num_bytes + payload > result_size)
1448 return(-2);
1449 aaip_read_from_recs(aaip, h + 2, (unsigned char *) (result + num_bytes),
1450 payload, 0);
1451 *num_result= num_bytes + payload;
1452 }
1453 num_bytes+= payload;
1454 if(!(aaip_get_buffer_byte(aaip, h, 0) & 1))
1455 complete= 1;
1456 h+= payload + 2;
1457 }
1458 aaip->ready_bytes-= num_bytes;
1459 aaip->num_recs-= i;
1460
1461 /* Shift buffer */
1462 aaip_shift_recs(aaip, h, 0);
1463
1464 /* Compute reply */
1465 ret= 2 * !aaip->first_is_name;
1466 if(complete) {
1467 aaip->first_is_name= !aaip->first_is_name;
1468 if(aaip->num_components > 0)
1469 aaip->num_components--;
1470 } else
1471 ret|= 1;
1472
1473 return(ret);
1474 }
1475
1476
1477 /* Skip the current component and eventually the following value component.
1478 This has to be called if fetching of a component shall be aborted
1479 but the next component resp. pair shall be fetchable again.
1480 aaip_submit_data() will not indicate readiness for fetching until all
1481 bytes of the skipped components are submitted. Those bytes get discarded.
1482 @param aaip The AAIP decoder context
1483 @param flag Bitfield for control purposes
1484 bit0= do not skip value if current component is name
1485 @return <=0 error , 1= now in skip state, 2= not in skip state
1486 */
aaip_skip_component(struct aaip_state * aaip,int flag)1487 int aaip_skip_component(struct aaip_state *aaip, int flag)
1488 {
1489 int to_skip= 1;
1490
1491 if(aaip->first_is_name && !(flag & 1))
1492 to_skip= 2;
1493 if(aaip->recs_invalid) {
1494 aaip->recs_invalid+= to_skip;
1495 return(1);
1496 }
1497
1498 if(aaip->num_components) {
1499 /* null-fetch */
1500 aaip_fetch_data(aaip, NULL, (size_t) 0, NULL, 1);
1501 to_skip--;
1502 }
1503 if(aaip->num_components && to_skip) {
1504 /* null-fetch */
1505 aaip_fetch_data(aaip, NULL, (size_t) 0, NULL, 1);
1506 to_skip--;
1507 }
1508 if(to_skip) {
1509 aaip->recs_fill= 0;
1510 aaip->num_recs= 0;
1511 aaip->ready_bytes= 0;
1512 }
1513 aaip->recs_invalid= to_skip;
1514 if(aaip->aa_ends == 2 && aaip->num_recs == 0)
1515 aaip->aa_ends= 3;
1516 return(1 + (aaip->num_recs > 0));
1517 }
1518
1519
1520 /* ------------------------- Pair Level Interface ------------------------ */
1521
1522 /*
1523 @param flag Bitfield for control purposes
1524 bit0= do not skip oversized component but return -2
1525 @return see aaip_decode_pair
1526 */
aaip_advance_pair(struct aaip_state * aaip,char * name,size_t name_size,size_t * name_fill,char * value,size_t value_size,size_t * value_fill,int flag)1527 static int aaip_advance_pair(struct aaip_state *aaip,
1528 char *name, size_t name_size, size_t *name_fill,
1529 char *value, size_t value_size, size_t *value_fill,
1530 int flag)
1531 {
1532 int ret;
1533 char *wpt;
1534 size_t size, num;
1535
1536 retry:;
1537 if(aaip->first_is_name) {
1538 wpt= name + *name_fill;
1539 size= name_size - *name_fill;
1540 } else {
1541 wpt= value + *value_fill;
1542 size= value_size - *value_fill;
1543 }
1544 ret= aaip_fetch_data(aaip, wpt, size, &num, 0);
1545 if(ret == -2) { /* insufficient result size */
1546 if(flag & 1)
1547 return(-2);
1548 ret= aaip_skip_component(aaip, 0);
1549 *name_fill= *value_fill= 0;
1550 aaip->pairs_skipped++;
1551 if(ret == 2) /* Skip performed, valid data pending */
1552 goto retry;
1553 } else if(ret == -1) { /* No data ready for delivery : may not happen */
1554 return(-1);
1555 } else if(ret == 0) { /* result holds the final part of a name */
1556 (*name_fill)+= num;
1557 /* peek for value data */
1558 ret= aaip_submit_data(aaip, NULL, (size_t) 0, &num, 0);
1559 if(ret == 2 || ret == 3) {
1560 /* fetch value data */;
1561 ret= aaip_advance_pair(aaip, name, name_size, name_fill,
1562 value, value_size, value_fill, flag);
1563 return ret;
1564 } else if(ret == 4)
1565 return(5);
1566 } else if(ret == 1) { /* result holds an intermediate part of a name */
1567 (*name_fill)+= num;
1568 } else if(ret == 2) { /* result holds the final part of a value */
1569 (*value_fill)+= num;
1570 if(aaip->num_components >= 2)
1571 return(3);
1572 if(aaip->aa_ends == 2 && aaip->num_recs == 0)
1573 aaip->aa_ends= 3;
1574 if(aaip->aa_ends == 3)
1575 return(4);
1576 return(2);
1577 } else if(ret == 3) {
1578 /* result holds an intermediate part of a value */;
1579 (*value_fill)+= num;
1580 } else {
1581 return(-1); /* unknown reply from aaip_fetch_data() */
1582 }
1583 return(1);
1584 }
1585
1586
1587 /* Accept raw input data and collect a pair of name and value.
1588 The return value will indicate whether the pair is complete, whether more
1589 pairs are complete or whether more data are desired. No input data will be
1590 accepted as long as complete pairs are pending. The end of the attribute
1591 list will be indicated.
1592 @param aaip The AAIP decoder context
1593 @param data The raw data to decode
1594 @param num_data Number of data bytes provided
1595 @param consumed Returns the number of consumed data bytes
1596 @param name Buffer to build the name string
1597 @param name_size Maximum number of bytes in name
1598 @param name_fill Holds the current buffer fill of name
1599 @param value Buffer to build the value string
1600 @param value_size Maximum number of bytes in value
1601 @param value_fill Holds the current buffer fill of value
1602 @param flag Bitfield for control purposes
1603 bit0= do not skip oversized pair but return -2
1604 @return <0 error
1605 -3 buffer full (program error)
1606 -2 insufficient result_size (only with flag bit0)
1607 -1 non-AAIP field detected
1608 0 data not accepted, first fetch pending pairs with num_data == 0
1609 1 name and value are not valid yet, submit more data
1610 2 name and value are valid, submit more data
1611 3 name and value are valid, pairs pending, fetch with num_data == 0
1612 4 name and value are valid, no more data expected
1613 5 name and value are not valid, no more data expected
1614 */
aaip_decode_pair(struct aaip_state * aaip,unsigned char * data,size_t num_data,size_t * consumed,char * name,size_t name_size,size_t * name_fill,char * value,size_t value_size,size_t * value_fill,int flag)1615 int aaip_decode_pair(struct aaip_state *aaip,
1616 unsigned char *data, size_t num_data, size_t *consumed,
1617 char *name, size_t name_size, size_t *name_fill,
1618 char *value, size_t value_size, size_t *value_fill,
1619 int flag)
1620 {
1621 int ret;
1622 size_t ready_bytes= 0;
1623
1624 #ifdef Aaip_with_short_namespaceS
1625 char prefix[Aaip_max_name_expansioN + 1];
1626 size_t nl, pl;
1627 #endif
1628
1629 *consumed= 0;
1630 if((aaip->pair_status < 0 && aaip->pair_status != -2) ||
1631 aaip->pair_status == 4 ||
1632 aaip->pair_status == 5) { /* dead ends */
1633 ret= aaip->pair_status;
1634 goto ex;
1635 } else if(aaip->pair_status == 2 || aaip->pair_status == 3) {
1636 if(aaip->pair_status == 3 && num_data > 0)
1637 {ret= 0; goto ex;}
1638 /* Start a new pair */
1639 if(!aaip->first_is_name) /* Eventually skip orphaned value */
1640 aaip_fetch_data(aaip, NULL, (size_t) 0, NULL, 1);
1641 *name_fill= *value_fill= 0;
1642 }
1643
1644 if(num_data > 0) {
1645 ret= aaip_submit_data(aaip, data, num_data, &ready_bytes, 0);
1646 } else {
1647 ret= 1;
1648 if(aaip->num_components)
1649 ret= 3;
1650 else if(aaip->num_recs)
1651 ret= 2;
1652 }
1653 if(ret < 0) { /* non-AAIP field detected */
1654 *consumed= ready_bytes;
1655 {ret= -1; goto ex;}
1656 } else if(ret == 0) { /* buffer overflow */;
1657 /* should not happen with correct usage */
1658 {ret= -3; goto ex;}
1659 } else if(ret == 1) { /* no component record complete */
1660 goto ex;
1661 } else if(ret == 2) { /* component record complete, may be delivered */
1662 ;
1663 } else if(ret == 3) { /* component complete, may be delivered */
1664 ;
1665 } else if(ret == 4) { /* no component available, no more data expected */
1666 {ret= 5; goto ex;}
1667 } else
1668 {ret= -1; goto ex;} /* unknown reply from aaip_submit_data() */
1669
1670 *consumed= num_data;
1671 ret= aaip_advance_pair(aaip, name, name_size - Aaip_max_name_expansioN,
1672 name_fill, value, value_size, value_fill, flag & 1);
1673 if(aaip->aa_ends == 3) {
1674 if(ret >= 2 && ret <= 4)
1675 ret= 4;
1676 else
1677 ret= 5;
1678 }
1679 ex:;
1680
1681 #ifdef Aaip_with_short_namespaceS
1682
1683 if(ret >= 2 && ret <= 4 && *name_fill > 0) {
1684 /* Translate name from eventual short form */
1685 nl= *name_fill;
1686 if(name[0] > 0 && name[0] <= Aaip_maxdef_namespacE) {
1687 prefix[0]= 0;
1688 if(name[0] == Aaip_namespace_literaL) {
1689 if(nl > 1) {
1690 /* Remove first character of name */
1691 memmove(name, name + 1, nl - 1);
1692 (*name_fill)--;
1693 }
1694 } else if(name[0] == Aaip_namespace_systeM ||
1695 name[0] == Aaip_namespace_useR ||
1696 name[0] == Aaip_namespace_isofS ||
1697 name[0] == Aaip_namespace_trusteD ||
1698 name[0] == Aaip_namespace_securitY
1699 ) {
1700 strcpy(prefix, Aaip_namespace_textS[(int) name[0]]);
1701 pl= strlen(prefix);
1702 memmove(name + pl, name + 1, nl - 1);
1703 memcpy(name, prefix, pl);
1704 *name_fill= pl + nl - 1;
1705 }
1706 }
1707 }
1708
1709 #endif /* Aaip_with_short_namespaceS */
1710
1711 aaip->pair_status= ret;
1712 return(ret);
1713 }
1714
1715
aaip_get_pairs_skipped(struct aaip_state * aaip,int flag)1716 unsigned int aaip_get_pairs_skipped(struct aaip_state *aaip, int flag)
1717 {
1718 return(aaip->pairs_skipped);
1719 }
1720
1721
1722 /* ------------------------- List Level Interface ------------------------ */
1723
1724
1725 #define Aaip_initial_name_leN 256
1726 #define Aaip_initial_value_leN 256
1727 #define Aaip_initial_list_sizE 2
1728 #define Aaip_list_enlargeR 1.5
1729
1730
1731 /*
1732 @param flag Bitfield for control purposes
1733 bit0= do not update *buf_size
1734 */
aaip_enlarge_buf(struct aaip_state * aaip,size_t memory_limit,size_t item_size,char ** buf,size_t * buf_size,int flag)1735 static int aaip_enlarge_buf(struct aaip_state *aaip, size_t memory_limit,
1736 size_t item_size, char **buf, size_t *buf_size, int flag)
1737 {
1738 size_t new_size;
1739 char *new_buf;
1740
1741 new_size= *buf_size * Aaip_list_enlargeR;
1742 if(aaip->list_mem_used + (new_size - *buf_size) * item_size >= memory_limit)
1743 return(3);
1744 aaip->list_mem_used+= (new_size - *buf_size) * item_size;
1745 new_buf= realloc(*buf, new_size * item_size);
1746 if(new_buf == NULL)
1747 return(-1);
1748 *buf= new_buf;
1749 if(!(flag & 1))
1750 *buf_size= new_size;
1751 return(1);
1752 }
1753
1754
1755 /* Accept raw input data and collect arrays of name pointers, value lengths
1756 and value pointers. A handle object will emerge which finally has to be
1757 be freed by a call with bit 15.
1758 @param handle The decoding context.
1759 It will be created by this call with flag bit 0 or if
1760 *handle == NULL. This handle has to be the same as long
1761 as decoding goes on and finally has to be freed by a
1762 call with bit15.
1763 @param memory_limit Maximum number of bytes to allocate
1764 @param num_attr_limit Maximum number of name-value pairs to allocate
1765 @param data The raw data to decode
1766 @param num_data Number of data bytes provided
1767 @param consumed Returns the number of consumed data bytes
1768 @param flag Bitfield for control purposes
1769 bit0= this is the first call with the given handle
1770 (also in effect if *handle is NULL)
1771 bit15= end decoding :
1772 Free handle and its intermediate list memory.
1773 @return <=0 error
1774 -4 interpretation stalled, no valid result
1775 -3 program error, unexpected reply from lower layers
1776 -2 non-AAIP-field detected, arrays are complete,
1777 call aaip_get_decoded_attrs()
1778 -1 out of memory
1779 1 not complete yet, submit more data
1780 2 arrays are complete, call aaip_get_decoded_attrs()
1781 3 limit exceeded, not complete yet,
1782 enlarge memory_limit or call with bit15 and give up
1783 4 limit exceeded, call aaip_get_decoded_attrs() and try again
1784 */
aaip_decode_attrs(struct aaip_state ** handle,size_t memory_limit,size_t num_attr_limit,unsigned char * data,size_t num_data,size_t * consumed,int flag)1785 int aaip_decode_attrs(struct aaip_state **handle,
1786 size_t memory_limit, size_t num_attr_limit,
1787 unsigned char *data, size_t num_data, size_t *consumed,
1788 int flag)
1789 {
1790 int ret;
1791 struct aaip_state *aaip;
1792 size_t h_num, *h_lengths, i, new_mem, pair_consumed= 0;
1793 char **h_names, **h_values, *hpt;
1794
1795 *consumed= 0;
1796 if(flag & (1 << 15)) {
1797 if(*handle == NULL)
1798 return(0);
1799 ret= aaip_get_decoded_attrs(handle, &h_num, &h_names, &h_lengths, &h_values,
1800 0);
1801 if(ret > 0)
1802 aaip_get_decoded_attrs(handle, &h_num, &h_names, &h_lengths, &h_values,
1803 1 << 15);
1804 if((*handle)->name_buf != NULL)
1805 free((*handle)->name_buf);
1806 if((*handle)->value_buf != NULL)
1807 free((*handle)->value_buf);
1808 free((char *) *handle);
1809 *handle= NULL;
1810 return(1);
1811 }
1812
1813 aaip= *handle;
1814 if(aaip == NULL || (flag & 1)) {
1815 aaip= *handle= calloc(1, sizeof(struct aaip_state));
1816 if(*handle == NULL)
1817 return(-1);
1818 aaip_init_aaip_state(*handle, 0);
1819 }
1820 if(aaip->list_names == NULL || aaip->list_values == NULL ||
1821 aaip->list_value_lengths == NULL) {
1822 /* Initialize arrays */
1823 aaip->list_size= Aaip_initial_list_sizE;
1824 if(num_attr_limit > 0 && num_attr_limit < aaip->list_size)
1825 aaip->list_size= num_attr_limit;
1826 new_mem= aaip->list_size * (2*sizeof(char *) + sizeof(size_t)) +
1827 Aaip_initial_name_leN + Aaip_initial_value_leN;
1828 if(aaip->list_mem_used + new_mem >= memory_limit)
1829 return(3);
1830 aaip->list_mem_used+= new_mem;
1831 aaip->list_names= calloc(sizeof(char *), aaip->list_size);
1832 aaip->list_value_lengths= calloc(sizeof(size_t), aaip->list_size);
1833 aaip->list_values= calloc(sizeof(char *), aaip->list_size);
1834 if(aaip->list_names == NULL || aaip->list_value_lengths == NULL ||
1835 aaip->list_values == NULL)
1836 return(-1);
1837 for(i= 0; i < aaip->list_size; i++) {
1838 aaip->list_names[i]= NULL;
1839 aaip->list_value_lengths[i]= 0;
1840 aaip->list_values[i]= NULL;
1841 }
1842 }
1843 if(aaip->name_buf == NULL || aaip->value_buf == NULL) {
1844 new_mem= Aaip_initial_name_leN + Aaip_initial_value_leN;
1845 if(aaip->list_mem_used >= memory_limit)
1846 return(3);
1847 aaip->list_mem_used+= new_mem;
1848 aaip->name_buf= calloc(1, Aaip_initial_name_leN);
1849 aaip->value_buf= calloc(1, Aaip_initial_value_leN);
1850 if(aaip->name_buf == NULL || aaip->value_buf == NULL)
1851 return(-1);
1852 aaip->name_buf_size= Aaip_initial_name_leN;
1853 aaip->value_buf_size= Aaip_initial_name_leN;
1854 }
1855
1856 while(1) {
1857 if(aaip->list_pending_pair > 0) {
1858 /* the buffer holds a complete pair from a previous memory limit refusal */
1859 ret= aaip->list_pending_pair;
1860 aaip->list_pending_pair= 0;
1861 } else {
1862 ret= aaip_decode_pair(aaip, data, num_data, &pair_consumed,
1863 aaip->name_buf, aaip->name_buf_size, &aaip->name_buf_fill,
1864 aaip->value_buf, aaip->value_buf_size, &aaip->value_buf_fill,
1865 1);
1866 *consumed+= pair_consumed;
1867 }
1868 if(ret == -2) { /* insufficient result_size */
1869 if(aaip->first_is_name)
1870 ret= aaip_enlarge_buf(aaip, memory_limit, (size_t) 1, &(aaip->name_buf),
1871 &(aaip->name_buf_size), 0);
1872 else
1873 ret= aaip_enlarge_buf(aaip, memory_limit, (size_t) 1,
1874 &(aaip->value_buf), &(aaip->value_buf_size), 0);
1875 if(ret != 1)
1876 return(ret);
1877
1878 } else if(ret == -1) { /* non-AAIP field detected */
1879 if(pair_consumed <= 0)
1880 return(-4); /* interpretation did not advance */
1881
1882 } else if(ret < 0) { /* other error */
1883 return(-3);
1884
1885 } else if(ret == 0) { /* first fetch pending pairs with num_data == 0 */
1886 /* should not happen, fetch more pairs */;
1887
1888 } else if(ret == 1) {
1889 /* name and value are not valid yet, submit more data */
1890 return(1);
1891
1892 } else if(ret == 2 || ret == 3 || ret == 4) {
1893 /* name and value are valid, submit more data */
1894 /* name and value are valid, pairs pending, fetch with num_data == 0 */
1895 /* name and value are valid, no more data expected */
1896 aaip->list_pending_pair= ret;
1897
1898 if(aaip->list_num_attrs >= aaip->list_size) {
1899 hpt= (char *) aaip->list_names;
1900 ret= aaip_enlarge_buf(aaip, memory_limit, sizeof(char *),
1901 &hpt, &(aaip->list_size), 1);
1902 if(ret != 1)
1903 return(ret);
1904 aaip->list_names= (char **) hpt;
1905 hpt= (char *) aaip->list_values;
1906 ret= aaip_enlarge_buf(aaip, memory_limit, sizeof(char *),
1907 &hpt, &(aaip->list_size), 1);
1908 if(ret != 1)
1909 return(ret);
1910 aaip->list_values= (char **) hpt;
1911 hpt= (char *) aaip->list_value_lengths;
1912 ret= aaip_enlarge_buf(aaip, memory_limit, sizeof(size_t),
1913 &hpt, &(aaip->list_size), 0);
1914 if(ret != 1)
1915 return(ret);
1916 aaip->list_value_lengths= (size_t *) hpt;
1917 }
1918
1919 /* Allocate name and value in list */;
1920 if(aaip->list_mem_used + aaip->name_buf_fill + aaip->value_buf_fill + 2
1921 > memory_limit) {
1922 return(3);
1923 }
1924 aaip->list_mem_used+= aaip->name_buf_fill + aaip->value_buf_fill + 2;
1925 i= aaip->list_num_attrs;
1926 aaip->list_names[i]= calloc(aaip->name_buf_fill + 1, 1);
1927 aaip->list_values[i]= calloc(aaip->value_buf_fill + 1, 1);
1928 memcpy(aaip->list_names[i], aaip->name_buf, aaip->name_buf_fill);
1929 aaip->list_names[i][aaip->name_buf_fill]= 0;
1930 memcpy(aaip->list_values[i], aaip->value_buf, aaip->value_buf_fill);
1931 aaip->list_values[i][aaip->value_buf_fill]= 0;
1932 aaip->list_value_lengths[i]= aaip->value_buf_fill;
1933 aaip->list_num_attrs++;
1934 aaip->name_buf_fill= aaip->value_buf_fill= 0;
1935
1936 ret= aaip->list_pending_pair;
1937 aaip->list_pending_pair= 0;
1938
1939 if(ret == 2)
1940 return(1);
1941 if(ret == 4)
1942 break;
1943
1944 } else if(ret == 5)
1945 break;
1946 else
1947 return(-2);
1948
1949 num_data= 0; /* consume pending pairs */
1950 }
1951 aaip->list_pending_pair= 5;
1952 return(2);
1953 }
1954
1955
1956 /* Obtain the resulting attributes when aaip_decode_attrs() indicates to
1957 be done or to have the maximum possible amount of result ready.
1958 The returned data objects finally have to be freed by a call with flag
1959 bit 15.
1960 @param handle The decoding context created by aaip_decode_attrs()
1961 @param num_attrs Will return the number of name-value pairs
1962 @param names Will return an array of pointers to 0-terminated names
1963 @param value_lengths Will return an array with the lengths of values
1964 @param values Will return an array of pointers to 8-bit values
1965 @param flag Bitfield for control purposes
1966 bit15= free memory of names, value_lengths, values
1967 @return <0 error
1968 0 no attribute list ready
1969 1 ok
1970 */
aaip_get_decoded_attrs(struct aaip_state ** handle,size_t * num_attrs,char *** names,size_t ** value_lengths,char *** values,int flag)1971 int aaip_get_decoded_attrs(struct aaip_state **handle, size_t *num_attrs,
1972 char ***names, size_t **value_lengths, char ***values,
1973 int flag)
1974 {
1975 size_t i;
1976 struct aaip_state *aaip;
1977
1978 aaip= *((struct aaip_state **) handle);
1979 if(flag & (1 << 15)) {
1980 if(*names != NULL) {
1981 for(i= 0; i < *num_attrs; i++) {
1982 if((*names)[i] != NULL)
1983 free((*names)[i]);
1984 (*names)[i]= NULL;
1985 }
1986 free(*names);
1987 *names= NULL;
1988 }
1989 if(*values != NULL) {
1990 for(i= 0; i < *num_attrs; i++) {
1991 if((*values)[i] != NULL)
1992 free((*values)[i]);
1993 (*values)[i]= NULL;
1994 }
1995 free(*values);
1996 *values= NULL;
1997 }
1998 if(*value_lengths != NULL)
1999 free(*value_lengths);
2000 *value_lengths= NULL;
2001 *num_attrs= 0;
2002 return(1);
2003 }
2004
2005 /* Check whether decoding is finished yet */
2006 if(aaip->list_pending_pair != 5)
2007 return(0);
2008
2009 *num_attrs= aaip->list_num_attrs;
2010 *names= aaip->list_names;
2011 *value_lengths= aaip->list_value_lengths;
2012 *values= aaip->list_values;
2013
2014 /* Now the memory is owned by the caller */
2015 aaip->list_num_attrs= 0;
2016 aaip->list_names= NULL;
2017 aaip->list_value_lengths= NULL;
2018 aaip->list_values= NULL;
2019 aaip->list_size= 0;
2020 aaip->list_pending_pair= 0;
2021 return(1);
2022 }
2023
2024
2025 /* ------ Decoder for ACLs ------ */
2026
2027
aaip_write_acl_line(char ** result,size_t * result_size,char * tag_type,char * qualifier,char * permissions,int flag)2028 static int aaip_write_acl_line(char **result, size_t *result_size,
2029 char *tag_type, char *qualifier,
2030 char *permissions, int flag)
2031 {
2032 size_t needed, tag_len, perm_len, qualifier_len;
2033
2034 tag_len= strlen(tag_type);
2035 qualifier_len= strlen(qualifier);
2036 perm_len= strlen(permissions);
2037 needed= tag_len + qualifier_len + perm_len + 3;
2038 if((flag & 1)) {
2039 (*result_size)+= needed;
2040 return(1);
2041 }
2042 if(needed + 1 > *result_size) /* +1 : want to append a trailing 0 */
2043 return(-1);
2044 memcpy((*result), tag_type, tag_len);
2045 (*result)[tag_len]= ':';
2046 memcpy((*result) + tag_len + 1, qualifier, qualifier_len);
2047 (*result)[tag_len + 1 + qualifier_len]= ':';
2048 memcpy((*result) + tag_len + 1 + qualifier_len + 1, permissions, perm_len);
2049 (*result)[tag_len + 1 + qualifier_len + 1 + perm_len]= '\n';
2050 (*result)[tag_len + 1 + qualifier_len + 1 + perm_len + 1] = 0;
2051 (*result)+= needed;
2052 (*result_size)-= needed;
2053 return(1);
2054 }
2055
2056
aaip_read_qualifier(unsigned char * data,size_t num_data,char * name,size_t name_size,size_t * name_fill,int flag)2057 static int aaip_read_qualifier(unsigned char *data, size_t num_data,
2058 char *name, size_t name_size, size_t *name_fill,
2059 int flag)
2060 {
2061 int is_done= 0;
2062 size_t rec_len= 0;
2063 unsigned char *rpt;
2064
2065 *name_fill= 0;
2066 for(rpt= data; !is_done; rpt+= rec_len) {
2067 rec_len= (*rpt) & 127;
2068 is_done= !((*rpt) & 128);
2069 if(*name_fill + rec_len >= name_size ||
2070 (size_t) (rpt + 1 + rec_len - data) > num_data)
2071 return(-1);
2072 memcpy(name + *name_fill, rpt + 1, rec_len);
2073 rpt+= 1 + rec_len;
2074 (*name_fill)+= rec_len;
2075 name[*name_fill]= 0;
2076 }
2077 return(1);
2078 }
2079
2080
2081 /* Convert an AAIP ACL attribute value into the long text form of ACL.
2082 @param data The raw data to decode
2083 @param num_data Number of data bytes provided
2084 @param consumed Returns the number of consumed data bytes
2085 @param acl_text Will be filled with ACL long text form
2086 @param acl_text_size Maximum number of bytes to be written to acl_text
2087 @param acl_text_fill Will return the number of bytes in acl_text
2088 @param flag Bitfield for control purposes
2089 bit0= count only, do not really produce bytes:
2090 acl_text will not be touched,
2091 acl_text_size will be ignored,
2092 *acl_text_fill will return the counted number
2093 plus 1 for a trailing zero.
2094 bit1= expected is a default ACL (see return value 2)
2095 @return 1 success
2096 2 success, begin of default/access ACL encountered,
2097 submit data + *consumed for access/default ACL
2098 -1 error with reading of qualifier
2099 -2 error with writing of ACL text line
2100 -3 version mismatch
2101 -4 unknown tag type encountered
2102 */
aaip_decode_acl(unsigned char * data,size_t num_data,size_t * consumed,char * acl_text,size_t acl_text_size,size_t * acl_text_fill,int flag)2103 int aaip_decode_acl(unsigned char *data, size_t num_data, size_t *consumed,
2104 char *acl_text, size_t acl_text_size,
2105 size_t *acl_text_fill, int flag)
2106 {
2107 unsigned char *rpt;
2108 char perm_text[4], *wpt, *name= NULL;
2109 int type, qualifier= 0, perm, ret, cnt, name_size= 1024;
2110 size_t w_size= 0, name_fill= 0, i;
2111 uid_t uid;
2112 gid_t gid;
2113 struct passwd *pwd;
2114 struct group *grp;
2115
2116 LIBISO_ALLOC_MEM(name, char, name_size);
2117 cnt= flag & 1;
2118 *consumed= 0;
2119 wpt= acl_text;
2120 w_size= acl_text_size;
2121 *acl_text_fill= 0;
2122 for(rpt= data; (size_t) (rpt - data) < num_data; ) {
2123 perm= *rpt;
2124 strcpy(perm_text, "---");
2125 if(perm & Aaip_READ)
2126 perm_text[0]= 'r';
2127 if(perm & Aaip_WRITE)
2128 perm_text[1]= 'w';
2129 if(perm & Aaip_EXEC)
2130 perm_text[2]= 'x';
2131
2132 type= (*rpt) >> 4;
2133 if(type == Aaip_FUTURE_VERSION) /* indicate to caller: version mismatch */
2134 {ret = -3; goto ex;}
2135
2136 qualifier= !!((*rpt) & 8);
2137 if(qualifier) {
2138 ret= aaip_read_qualifier(rpt + 1, num_data - (rpt + 1 - data),
2139 name, name_size, &name_fill, 0);
2140 if(ret <= 0)
2141 {ret = -1; goto ex;}
2142 }
2143
2144 /* Advance read pointer */
2145 (*consumed)+= 1 + (qualifier ? name_fill + 1 : 0);
2146 rpt+= 1 + (qualifier ? name_fill + 1 : 0);
2147
2148 ret= 1;
2149 if(type == Aaip_TRANSLATE) {
2150 /* rightfully ignored yet */;
2151 continue;
2152 } else if(type == Aaip_ACL_USER_OBJ) {
2153 /* user::rwx */
2154 ret= aaip_write_acl_line(&wpt, &w_size, "user", "", perm_text, cnt);
2155 } else if(type == Aaip_ACL_USER) {
2156 /* user:<username>:rwx */;
2157 ret= aaip_write_acl_line(&wpt, &w_size, "user", name, perm_text, cnt);
2158 } else if(type == Aaip_ACL_GROUP_OBJ) {
2159 /* user::rwx */
2160 ret= aaip_write_acl_line(&wpt, &w_size, "group", "", perm_text, cnt);
2161 } else if(type == Aaip_ACL_GROUP) {
2162 /* group:<groupname>:rwx */;
2163 ret= aaip_write_acl_line(&wpt, &w_size, "group", name, perm_text, cnt);
2164 } else if(type == Aaip_ACL_MASK) {
2165 /* mask::rwx */
2166 ret= aaip_write_acl_line(&wpt, &w_size, "mask", "", perm_text, cnt);
2167 } else if(type == Aaip_ACL_OTHER) {
2168 /* other::rwx */
2169 ret= aaip_write_acl_line(&wpt, &w_size, "other", "", perm_text, cnt);
2170 } else if(type == Aaip_SWITCH_MARK) {
2171 /* Indicate to caller: end of desired ACL type access/default */
2172 if((perm & Aaip_EXEC) ^ (!!(flag & 2)))
2173 {ret= 2; goto ex;}
2174 } else if(type == Aaip_ACL_USER_N) {
2175 /* determine username from uid */
2176 uid= 0;
2177 for(i= 0; i < name_fill; i++)
2178 uid= (uid << 8) | ((unsigned char *) name)[i];
2179 pwd= getpwuid(uid);
2180 if(pwd == NULL)
2181 sprintf(name, "%.f", (double) uid);
2182 else if(strlen(pwd->pw_name) >= (size_t) name_size)
2183 sprintf(name, "%.f", (double) uid);
2184 else
2185 strcpy(name, pwd->pw_name);
2186 /* user:<username>:rwx */;
2187 ret= aaip_write_acl_line(&wpt, &w_size, "user", name, perm_text, cnt);
2188 } else if(type == Aaip_ACL_GROUP_N) {
2189 /* determine username from gid */;
2190 gid= 0;
2191 for(i= 0; i < name_fill; i++)
2192 gid= (gid << 8) | ((unsigned char *) name)[i];
2193 grp= getgrgid(gid);
2194 if(grp == NULL)
2195 sprintf(name, "%.f", (double) gid);
2196 else if(strlen(grp->gr_name) >= (size_t) name_size)
2197 sprintf(name, "%.f", (double) gid);
2198 else
2199 strcpy(name, grp->gr_name);
2200 /* user:<username>:rwx */;
2201 ret= aaip_write_acl_line(&wpt, &w_size, "group", name, perm_text, cnt);
2202 } else {
2203 /* indicate to caller: unknown type */
2204 {ret = -4; goto ex;}
2205 }
2206 if(ret <= 0)
2207 {ret = -2; goto ex;}
2208 }
2209 ret= 1;
2210 ex:;
2211 *acl_text_fill= w_size;
2212 if(flag & 1)
2213 (*acl_text_fill)++;
2214 LIBISO_FREE_MEM(name);
2215 return(ret);
2216 }
2217
2218
2219 /* ----------------------- Adapter for operating systems ----------------- */
2220
2221
2222 #ifdef Libisofs_use_os_dummY
2223
2224 #include "aaip-os-dummy.c"
2225
2226 #else
2227 #ifdef __FreeBSD__
2228
2229 #include "aaip-os-freebsd.c"
2230
2231 #else
2232 #ifdef __FreeBSD_kernel__
2233
2234 #ifdef NIX
2235 #ifdef Libisofs_with_aaip_xattR
2236 /* ts B51213: xattr system library calls are only stubs */
2237 #include "aaip-os-linux.c"
2238 #else
2239 /* ts B51213: extattr system library calls are not even present */
2240 #include "aaip-os-freebsd.c"
2241 #endif /* ! Libisofs_with_aaip_xattR */
2242 #else /* NIX */
2243 /* ts B51213: so we still end up at the dummy */
2244 #include "aaip-os-dummy.c"
2245 #endif /* ! NIX */
2246
2247 #else
2248 #ifdef __NetBSD__
2249
2250 #include "aaip-os-freebsd.c"
2251
2252 #else
2253 #ifdef __OpenBSD__
2254
2255 #include "aaip-os-freebsd.c"
2256
2257 #else
2258 #ifdef __linux
2259
2260 #include "aaip-os-linux.c"
2261
2262 /* August 2011: aaip-os-linux.c would also work for GNU/Hurd : ifdef __GNU__
2263 Libraries and headers are present on Debian GNU/Hurd but there is no
2264 ACL or xattr support in the filesystems yet.
2265 Further, llistxattr() produces ENOSYS "Function not implemented".
2266 So it makes few sense to enable it here.
2267 */
2268
2269 #else
2270
2271 #include "aaip-os-dummy.c"
2272
2273 #endif /* ! __linux */
2274 #endif /* ! __OpenBSD__ */
2275 #endif /* ! __NetBSD__ */
2276 #endif /* ! __FreeBSD_kernel__ */
2277 #endif /* ! __FreeBSD__ */
2278 #endif /* ! Libisofs_use_os_dummY */
2279
2280