"Fossies" - the Fresh Open Source Software Archive

Member "libisofs-1.5.4/libisofs/aaip_0_2.c" (8 Jul 2020, 71304 Bytes) of package /linux/misc/libisofs-1.5.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "aaip_0_2.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    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 */
  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 
  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 
  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 */
  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 */
  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 
  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 
  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 */
  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 
  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 */
  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 */
  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 
  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 
  977 size_t aaip_sizeof_aaip_state(void)
  978 {
  979  return((size_t) sizeof(struct aaip_state));
  980 }
  981 
  982 
  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 */
 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 */
 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 
 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 
 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 
 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 
 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 */
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 */
 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 */
 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 */
 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 */
 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 */
 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 
 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 */
 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 */
 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 */
 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 
 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 
 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 */
 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