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