diff --git a/test/aaip_0_2.c b/test/aaip_0_2.c index 64c02592..fef33c9c 100644 --- a/test/aaip_0_2.c +++ b/test/aaip_0_2.c @@ -208,6 +208,7 @@ static ssize_t aaip_encode_acl_text(char *acl_text, @param flag Bitfield for control purposes bit0= count only bit1= use numeric qualifiers rather than names + bit2= this is a default ACL, prepend SWITCH_MARK @return >0 means ok 0 means error */ @@ -218,7 +219,7 @@ int aaip_encode_acl(char *acl_text, *result= NULL; *result_len= 0; - bytes= aaip_encode_acl_text(acl_text, (size_t) 0, NULL, 1 | (flag & 2)); + bytes= aaip_encode_acl_text(acl_text, (size_t) 0, NULL, 1 | (flag & 6)); if(bytes < 0) return(0); if(flag & 1) { @@ -230,7 +231,7 @@ int aaip_encode_acl(char *acl_text, return(-1); (*result)[bytes]= 0; *result_len= bytes; - bytes= aaip_encode_acl_text(acl_text, *result_len, *result, (flag & 2)); + bytes= aaip_encode_acl_text(acl_text, *result_len, *result, (flag & 6)); if(bytes != *result_len) { *result_len= 0; return(0); @@ -255,13 +256,12 @@ static double aaip_numeric_id(char *name, int flag) /* - @param result_len Number of bytes in the resulting value - @param result *result will point to the start of the result string. - This is malloc() memory which needs to be freed when - no longer needed + @param result_size Number of bytes to store result + @param result Pointer to the start of the result string. @param flag Bitfield for control purposes bit0= count only, do not really produce bytes bit1= use numeric qualifiers + bit2= this is a default ACL, prepend SWITCH_MARK 1 @return >=0 number of bytes produced resp. counted <0 means error */ @@ -278,6 +278,16 @@ static ssize_t aaip_encode_acl_text(char *acl_text, char name[1024]; double num; + if(flag & 4) { + /* set SWITCH_MARK to indicate a default ACL */; + if(!(flag & 1)) { + if(count >= result_size) + return(-1); + result[count]= (Aaip_SWITCH_MARK << 4) | Aaip_EXEC; + } + count++; + } + for(rpt= acl_text; *rpt != 0; rpt= npt) { npt= strchr(rpt, '\n'); if(npt == 0) @@ -362,6 +372,8 @@ group_by_name:; } else continue; + if(npt - cpt < 3) + continue; perms= 0; if(cpt[1] == 'r') perms|= Aaip_READ; @@ -370,13 +382,18 @@ group_by_name:; if(cpt[3] == 'x') perms|= Aaip_EXEC; - if(!(flag & 1)) + if(!(flag & 1)) { + if(count >= result_size) + return(-1); result[count]= perms | ((!!qualifier) << 3) | (type << 4); + } count++; if(qualifier) { num_recs= (qualifier_len / 127) + !!(qualifier_len % 127); if(!(flag & 1)) { + if(count + 1 > result_size) + return(-1); for(i= 0; i < num_recs; i++) { if(i < num_recs - 1) result[count++]= 255; @@ -385,6 +402,8 @@ group_by_name:; if(result[count - 1] == 0) result[count - 1]= 127; } + if(count + (result[count - 1] & 127) > result_size) + return(-1); memcpy(result + count, name + i * 127, result[count - 1] & 127); count+= result[count - 1] & 127; } @@ -1134,5 +1153,189 @@ unsigned int aaip_get_pairs_skipped(struct aaip_state *aaip, int flag) } -/* >>> Decoder for ACLs */; +/* ------ Decoder for ACLs ------ */ + + +static int aaip_write_acl_line(char **result, size_t *result_size, + char *tag_type, char *qualifier, + char *permissions, int flag) +{ + size_t needed, tag_len, perm_len, qualifier_len; + + tag_len= strlen(tag_type); + qualifier_len= strlen(qualifier); + perm_len= strlen(permissions); + needed= tag_len + qualifier_len + perm_len + 3; + if((flag & 1)) { + (*result_size)+= needed; + return(1); + } + if(needed + 1 > *result_size) /* +1 : want to append a trailing 0 */ + return(-1); + memcpy((*result), tag_type, tag_len); + (*result)[tag_len]= ':'; + memcpy((*result) + tag_len + 1, qualifier, qualifier_len); + (*result)[tag_len + 1 + qualifier_len]= ':'; + memcpy((*result) + tag_len + 1 + qualifier_len + 1, permissions, perm_len); + (*result)[tag_len + 1 + qualifier_len + 1 + perm_len]= '\n'; + (*result)[tag_len + 1 + qualifier_len + 1 + perm_len + 1] = 0; + (*result)+= needed; + (*result_size)-= needed; + return(1); +} + + +static int aaip_read_qualifier(unsigned char *data, size_t num_data, + char *name, size_t name_size, size_t *name_fill, + int flag) +{ + int is_done= 0, rec_len= 0; + unsigned char *rpt; + + *name_fill= 0; + for(rpt= data; !is_done; rpt+= rec_len) { + rec_len= (*rpt) & 127; + is_done= !((*rpt) & 128); + if(*name_fill + rec_len >= name_size || rpt + 1 + rec_len - data > num_data) + return(-1); + memcpy(name + *name_fill, rpt + 1, rec_len); + rpt+= 1 + rec_len; + (*name_fill)+= rec_len; + name[*name_fill]= 0; + } + return(1); +} + + +/* Convert an AAIP ACL attribute value into the long text form of ACL. + @param data The raw data to decode + @param num_data Number of data bytes provided + @param consumed Returns the number of consumed data bytes + @param acl_text Will be filled with ACL long text form + @param acl_text_size Maximum number of bytes to be written to acl_text + @param acl_text_fill Will return the number of bytes in acl_text + @param flag Bitfield for control purposes + bit0= count only, do not really produce bytes: + acl_text will not be touched, + acl_text_size will be ignored, + *acl_text_fill will return the counted number + plus 1 for a trailing zero. + bit1= expected is a default ACL (see return value 2) + @return 1 success + 2 success, begin of default/access ACL encountered, + submit data + *consumed for access/default ACL + -1 error with reading of qualifier + -2 error with writing of ACL text line + -3 version mismatch + -4 unknown tag type encountered +*/ +int 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) +{ + unsigned char *rpt; + char perm_text[4], *wpt, name[1024]; + int type, qualifier= 0, perm, ret, i, cnt; + size_t w_size, name_fill; + uid_t uid; + gid_t gid; + struct passwd *pwd; + struct group *grp; + + cnt= flag & 1; + *consumed= 0; + wpt= acl_text; + w_size= acl_text_size; + *acl_text_fill= 0; + for(rpt= data; rpt - data < num_data; ) { + perm= *rpt; + strcpy(perm_text, "---"); + if(perm & Aaip_READ) + perm_text[0]= 'r'; + if(perm & Aaip_WRITE) + perm_text[1]= 'w'; + if(perm & Aaip_EXEC) + perm_text[2]= 'x'; + + type= (*rpt) >> 4; + if(type == Aaip_FUTURE_VERSION) /* indicate to caller: version mismatch */ + return(-3); + + qualifier= !!((*rpt) & 8); + if(qualifier) { + ret= aaip_read_qualifier(rpt + 1, num_data - (rpt + 1 - data), + name, sizeof(name), &name_fill, 0); + if(ret <= 0) + return(-1); + } + + /* Advance read pointer */ + (*consumed)+= 1 + (qualifier ? name_fill + 1 : 0); + rpt+= 1 + (qualifier ? name_fill + 1 : 0); + + ret= 1; + if(type == Aaip_TRANSLATE) { + /* rightfully ignored yet */; + continue; + } else if(type == Aaip_ACL_USER_OBJ) { + /* user::rwx */ + ret= aaip_write_acl_line(&wpt, &w_size, "user", "", perm_text, cnt); + } else if(type == Aaip_ACL_USER) { + /* user::rwx */; + ret= aaip_write_acl_line(&wpt, &w_size, "user", name, perm_text, cnt); + } else if(type == Aaip_ACL_GROUP_OBJ) { + /* user::rwx */ + ret= aaip_write_acl_line(&wpt, &w_size, "group", "", perm_text, cnt); + } else if(type == Aaip_ACL_GROUP) { + /* group::rwx */; + ret= aaip_write_acl_line(&wpt, &w_size, "group", name, perm_text, cnt); + } else if(type == Aaip_ACL_MASK) { + /* mask::rwx */ + ret= aaip_write_acl_line(&wpt, &w_size, "mask", "", perm_text, cnt); + } else if(type == Aaip_ACL_OTHER) { + /* other::rwx */ + ret= aaip_write_acl_line(&wpt, &w_size, "other", "", perm_text, cnt); + } else if(type == Aaip_SWITCH_MARK) { + /* Indicate to caller: end of desired ACL type access/default */ + if((!(perm & Aaip_EXEC)) ^ (!!(flag & 2))) + return(2); + } else if(type == Aaip_ACL_USER_N) { + /* determine username from uid */ + uid= 0; + for(i= 0; i < name_fill; i++) + uid= (uid << 8) | ((unsigned char *) name)[i]; + pwd= getpwuid(uid); + if(pwd == NULL) + sprintf(name, "%.f", (double) uid); + else if(strlen(pwd->pw_name) >= sizeof(name)) + sprintf(name, "%.f", (double) uid); + else + strcpy(name, pwd->pw_name); + /* user::rwx */; + ret= aaip_write_acl_line(&wpt, &w_size, "user", name, perm_text, cnt); + } else if(type == Aaip_ACL_GROUP_N) { + /* determine username from gid */; + gid= 0; + for(i= 0; i < name_fill; i++) + gid= (gid << 8) | ((unsigned char *) name)[i]; + grp= getgrgid(gid); + if(grp == NULL) + sprintf(name, "%.f", (double) gid); + else if(strlen(grp->gr_name) >= sizeof(name)) + sprintf(name, "%.f", (double) gid); + else + strcpy(name, grp->gr_name); + /* user::rwx */; + ret= aaip_write_acl_line(&wpt, &w_size, "group", name, perm_text, cnt); + } else { + /* indicate to caller: unknown type */ + return(-4); + } + if(ret <= 0) + return(-2); + } + if(flag & 1) + *acl_text_fill= w_size + 1; + return(1); +} diff --git a/test/aaip_0_2.h b/test/aaip_0_2.h index d89d18be..26eaf6f6 100644 --- a/test/aaip_0_2.h +++ b/test/aaip_0_2.h @@ -37,7 +37,7 @@ unsigned int aaip_encode(char aa_name[2], size_t *result_len, unsigned char **result, int flag); -/* Convert an ACL text as of acl_to_text(3) into the value of an Arbitrary +/* Convert an ACL from long text form into the value of an Arbitrary Attribute. According to AAIP 0.2 this value is to be stored together with an empty name. @param acl_text The ACL in long text form @@ -199,5 +199,32 @@ int aaip_decode_pair(struct aaip_state *aaip, */ unsigned int aaip_get_pairs_skipped(struct aaip_state *aaip, int flag); + +/* Convert an AAIP 0.2 ACL attribute value into the long text form of ACL. + @param data The raw data to decode + @param num_data Number of data bytes provided + @param consumed Returns the number of consumed data bytes + @param acl_text Will be filled with ACL long text form + @param acl_text_size Maximum number of bytes to be written to acl_text + @param acl_text_fill Will return the number of bytes in acl_text + @param flag Bitfield for control purposes + bit0= count only, do not really produce bytes: + acl_text will not be touched, + acl_text_size will be ignored, + *acl_text_fill will return the counted number + bit1= expected is a default ACL (see return value 2) + @return 1 success + 2 success, begin of default/access ACL encountered, + submit data + *consumed for access/default ACL + -1 error with reading of qualifier + -2 error with writing of ACL text line + -3 version mismatch + -4 unknown tag type encountered +*/ +int 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); + + #endif /* ! Aaip_h_is_includeD */ diff --git a/test/aaip_0_2_test.c b/test/aaip_0_2_test.c index 94284b3a..53fa2361 100644 --- a/test/aaip_0_2_test.c +++ b/test/aaip_0_2_test.c @@ -57,7 +57,63 @@ static int print_result(unsigned char *result, size_t result_len, int flag) } -static int test_acl(char *path, int flag) +static int decode_acl(unsigned char *result, size_t result_len, + char *out_path, int flag) +{ + int ret; + size_t consumed, text_fill; + char *text= NULL; + acl_t out_acl= NULL; + FILE *fp; + + ret= aaip_decode_acl(result, result_len, &consumed, NULL, 0, &text_fill, 1); + if(ret <= 0) { + fprintf(stderr, "aaip_decode_acl(,1) failed: ret= %d\n", ret); + ret= 0; goto ex; + } + text= calloc(text_fill, 1); + ret= aaip_decode_acl(result, result_len, &consumed, text, text_fill, + &text_fill, 0); + if(ret <= 0) { + fprintf(stderr, "aaip_decode_acl(,0) failed: ret= %d\n", ret); + ret= 0; goto ex; + } + printf("--- ret= %d , text=\n%s--- end of text\n\n", ret, text); + + if(out_path == NULL) + {ret= 1; goto ex;} + + out_acl= acl_from_text(text); + if(out_acl == NULL) { + fprintf(stderr, "acl_from_text failed: %d %s\n", + errno, errno != 0 ? strerror(errno) : ""); + ret= 0; goto ex; + } + fp= fopen(out_path, "a"); + if(fp == NULL) { + fprintf(stderr, "fopen(\"%s\") failed: %d %s\n", + out_path, errno, errno != 0 ? strerror(errno) : ""); + ret= 0; goto ex; + } + fclose(fp); + + ret= acl_set_file(out_path, ACL_TYPE_ACCESS, out_acl); + if(ret == -1) { + fprintf(stderr, "acl_set_file(\"%s\") failed: %d %s\n", + out_path, errno, errno != 0 ? strerror(errno) : ""); + ret= 0; goto ex; + } + ret= 1; +ex: + if(out_acl != NULL) + acl_free(out_acl); + if(text != NULL) + free(text); + return(ret); +} + + +static int test_acl(char *in_path, char *out_path, int flag) { int ret; acl_t acl= NULL; @@ -65,7 +121,7 @@ static int test_acl(char *path, int flag) unsigned char *result= NULL; size_t result_len; - acl= acl_get_file(path, ACL_TYPE_ACCESS); + acl= acl_get_file(in_path, ACL_TYPE_ACCESS); if(acl == NULL) { fprintf(stderr, "acl_get_file failed: %d %s\n", errno, errno != 0 ? strerror(errno) : ""); @@ -78,23 +134,28 @@ static int test_acl(char *path, int flag) ret= 0; goto ex; } printf("--- ACL:\n%s--- end of ACL\n\n", acl_text); + ret= aaip_encode_acl(acl_text, &result_len, &result, 0); if(ret <= 0) { fprintf(stderr, "aaip_encode_acl(text) failed: ret= %d\n", ret); ret= 0; goto ex; } print_result(result, result_len, 0); + ret= decode_acl(result, result_len, out_path, 0); + if(ret <= 0) + goto ex; free(result); result= NULL; + ret= aaip_encode_acl(acl_text, &result_len, &result, 2); if(ret <= 0) { fprintf(stderr, "aaip_encode_acl(num) failed: ret= %d\n", ret); ret= 0; goto ex; } print_result(result, result_len, 0); - + ret= decode_acl(result, result_len, out_path, 0); + if(ret <= 0) + goto ex; - /* >>> */; - ret= 1; ex:; if(acl_text != NULL) @@ -126,7 +187,7 @@ int main(int argc, char **argv) unsigned int skipped, was_skipped= 0; - test_acl("/u/test/acl", 0); + test_acl("/u/test/acl", "/u/test/out_acl", 0); if(argc < 3 || (argc % 2) == 0) {