Demo of the emerging Arbitrary Attribute Interchange Protocol format
This commit is contained in:
parent
9c136a59dd
commit
883fe7ff9f
537
test/aaip.c
Normal file
537
test/aaip.c
Normal file
@ -0,0 +1,537 @@
|
||||
|
||||
/*
|
||||
|
||||
Arbitrary Attribute Interchange Protocol , AAIP
|
||||
Demonstration program for encoding and decoding types PAIR and ACL1.
|
||||
|
||||
See http://libburnia-project.org/wiki/AAIP
|
||||
|
||||
Compile: cc -g -Wall -o test/aaip test/aaip.c
|
||||
|
||||
Usage: ./aaip name value
|
||||
Long parameters ./aaip -name"x100" -value"x100"
|
||||
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* <<< */
|
||||
#define Aaip_encode_debuG 1
|
||||
|
||||
|
||||
/* --------------------------------- Encoder ---------------------------- */
|
||||
|
||||
static unsigned int aaip_encode_parameter(char aa_name[2],
|
||||
char *field_start, unsigned int field_fill,
|
||||
unsigned int num_payload, char *payload,
|
||||
int flag);
|
||||
|
||||
|
||||
/* Convert the given type and parameters into a series of AAIP fields.
|
||||
|
||||
@param aa_name The 2 byte SUSP Signature Word of the fields
|
||||
(recommended is "AA")
|
||||
@param type The 4 byte Attribute Type ("ATTR" or "ACL1" for now)
|
||||
@param num_params Number of attribute parameters (>= 0)
|
||||
@param param_lengths Array of byte lengths for each parameter
|
||||
@param params Array of pointers to the parameter bytes
|
||||
@param result_len Number of bytes in the resulting SUSP field string
|
||||
@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 flag Unused yet. Submit 0
|
||||
@return >0 is the number of SUSP fields generated,
|
||||
<= 0 means error
|
||||
*/
|
||||
int aaip_encode(char aa_name[2], char type[4], unsigned int num_params,
|
||||
unsigned int *param_lengths, char **params,
|
||||
size_t *result_len, char **result, int flag)
|
||||
{
|
||||
size_t mem_size= 0;
|
||||
char *wpt, *field_start;
|
||||
unsigned char *upt;
|
||||
int ret;
|
||||
unsigned int fl= 0, follow_fields, i, payload= 0;
|
||||
unsigned int number_of_fields;
|
||||
|
||||
*result_len= 0;
|
||||
*result= NULL;
|
||||
|
||||
/* Predict memory needs and number of SUSP fields */
|
||||
mem_size= 16; /* First field up to NUM_FIELDS */
|
||||
number_of_fields= 1;
|
||||
for(i= 0; i < num_params; i++) {
|
||||
if(i == 0) {
|
||||
if(i > 239)
|
||||
fl= param_lengths[i] - 239; /* what exceeds the first field */
|
||||
else
|
||||
fl= 0;
|
||||
} else
|
||||
fl= param_lengths[i];
|
||||
follow_fields= (fl / 251) + ((fl % 251) > 0);
|
||||
number_of_fields+= follow_fields;
|
||||
mem_size+= param_lengths[i] + (follow_fields ) * 5;
|
||||
}
|
||||
|
||||
#ifdef Aaip_encode_debuG
|
||||
*result= calloc(1, mem_size + 10240); /* generous honeypot for overflows */
|
||||
#else
|
||||
*result= calloc(1, mem_size);
|
||||
#endif
|
||||
|
||||
if(*result == NULL)
|
||||
return(-1);
|
||||
wpt= *result;
|
||||
|
||||
/* ----- First SUSP field ----- */
|
||||
|
||||
field_start= wpt;
|
||||
*(wpt++)= aa_name[0];
|
||||
*(wpt++)= aa_name[1];
|
||||
/* number of bytes in first field */
|
||||
if(num_params > 0) {
|
||||
if(param_lengths[0] > 239)
|
||||
payload= 239;
|
||||
else
|
||||
payload= param_lengths[0];
|
||||
*((unsigned *) (wpt++))= payload + 16;
|
||||
} else
|
||||
*(wpt++)= 16;
|
||||
*(wpt++)= 1;
|
||||
|
||||
/* Attribute type */
|
||||
memcpy(wpt, type, 4);
|
||||
wpt+= 4;
|
||||
|
||||
/* Number of fields LSB and MSB */
|
||||
upt= (unsigned char *) wpt;
|
||||
for(i= 0; i < 4; i++)
|
||||
upt[7 - i]= upt[i]= (number_of_fields >> (8 * i)) & 0xff;
|
||||
wpt+= 8;
|
||||
|
||||
/* ----- Parameters ----- */
|
||||
/* Eventual first parameter */
|
||||
if(num_params > 0) {
|
||||
ret= aaip_encode_parameter(aa_name, field_start,
|
||||
(unsigned int) (wpt - field_start),
|
||||
param_lengths[0], params[0], 0);
|
||||
wpt+= ret;
|
||||
}
|
||||
/* Further parameters */
|
||||
for(i= 1; i < num_params; i++) {
|
||||
ret= aaip_encode_parameter(aa_name, wpt, 0, param_lengths[i], params[i], 0);
|
||||
wpt+= ret;
|
||||
}
|
||||
*result_len= wpt - *result;
|
||||
|
||||
#ifdef Aaip_encode_debuG
|
||||
if(*result_len != mem_size) {
|
||||
fprintf(stderr, "aaip_encode(): MEMORY MISMATCH BY %d BYTES\n",
|
||||
(int) (mem_size - *result_len));
|
||||
}
|
||||
ret= 0;
|
||||
for(i= 0; i < *result_len; i+= ((unsigned char *) (*result))[i + 2])
|
||||
ret++;
|
||||
if(ret != number_of_fields) {
|
||||
fprintf(stderr, "aaip_encode(): WRONG NUMBER OF FIELDS %d <> %d\n",
|
||||
number_of_fields, ret);
|
||||
}
|
||||
#endif /* Aaip_encode_debuG */
|
||||
|
||||
return(number_of_fields);
|
||||
}
|
||||
|
||||
|
||||
/* >>> Encoder for ACL */
|
||||
|
||||
|
||||
/* Helper function:
|
||||
Write the parameter into an eventually partially written field and into
|
||||
eventually necessary further fields.
|
||||
|
||||
@param aa_name The 2 byte SUSP Signature Word of the fields
|
||||
@param field_start Points to the start of the current field
|
||||
@param field_fill Number of bytes already written in field (0 or >5)
|
||||
@param num_payload Number of parameter bytes
|
||||
@param payload Points to parameter bytes
|
||||
@param flag bit0= do not write further fields
|
||||
bit1= with new field set FOLLOW bit 1
|
||||
@return Number of bytes written (payload and overhead)
|
||||
|
||||
*/
|
||||
static unsigned int aaip_encode_parameter(char aa_name[2],
|
||||
char *field_start, unsigned int field_fill,
|
||||
unsigned int num_payload, char *payload,
|
||||
int flag)
|
||||
{
|
||||
int ret;
|
||||
unsigned int num_head= 0, num_pay= 0;
|
||||
char *wpt, *rpt;
|
||||
|
||||
if(field_fill < 5) {
|
||||
field_start[0]= aa_name[0];
|
||||
field_start[1]= aa_name[1];
|
||||
field_start[2]= 5;
|
||||
field_start[3]= 1;
|
||||
field_start[4]= !!(flag & 2);
|
||||
num_head= field_fill= 5;
|
||||
}
|
||||
if(num_payload <= 0)
|
||||
return(num_head);
|
||||
if(num_payload + field_fill > 255)
|
||||
num_pay= 255 - field_fill;
|
||||
else
|
||||
num_pay= num_payload;
|
||||
memcpy(field_start + field_fill, payload, num_pay);
|
||||
|
||||
/* Update field length */
|
||||
((unsigned char *) field_start)[2]= field_fill + num_pay;
|
||||
|
||||
if(!(flag & 1)) {
|
||||
/* Write further fields */
|
||||
wpt= field_start + field_fill + num_pay;
|
||||
rpt= payload + num_pay;
|
||||
while(num_pay < num_payload) {
|
||||
ret= aaip_encode_parameter(aa_name, wpt, 0, num_payload - num_pay, rpt,
|
||||
3);
|
||||
wpt+= ret;
|
||||
num_head+= 5;
|
||||
rpt+= ret - 5;
|
||||
num_pay+= ret - 5;
|
||||
}
|
||||
}
|
||||
return(num_head + num_pay);
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------- Decoder ---------------------------- */
|
||||
|
||||
|
||||
/* A size limit for single parameters in order to prevent resource ehaustion.
|
||||
*/
|
||||
#define Aaip_param_memory_limiT 1024*1024
|
||||
|
||||
static int aaip_decode_parameter(char *start_field, unsigned int num_fields,
|
||||
char **new_pos, unsigned int *field_idx,
|
||||
size_t *result_len, char **result, int flag);
|
||||
|
||||
|
||||
/* Checks whether an encoded attribute is complete yet, or how many more fields
|
||||
need to be added, or whether the encoded bytes represent no valid attribute.
|
||||
This function assumes to get fed with complete SUSP fields, though.
|
||||
It also computes a pointer to the first byte after the fields of the
|
||||
attribute if it is valid at all.
|
||||
|
||||
@param aa_name The 2 byte SUSP Signature Word of the fields as of
|
||||
the ER field with signature "AAIP_2008A"
|
||||
@param attr_start Points to the first first field of the attribute.
|
||||
@param up_to Maximum number of bytes to be checked
|
||||
@param num_params Will tell number of parameters of the attribute
|
||||
@param num_fields Will tell number of fields of the attribute. See return.
|
||||
@param new_pos Will point to the desired byte position if return is 1
|
||||
@param flag Unused yet. Submit 0
|
||||
@return 1 ok, *new_pos and *num_fields are valid
|
||||
0 not ok, *num_fields tells number of missing fields
|
||||
-1 not ok, not an attribute start
|
||||
*/
|
||||
int aaip_decode_check(char aa_name[2], char *attr_start, size_t up_to,
|
||||
unsigned int *num_params, unsigned int *num_fields,
|
||||
char **new_pos, int flag)
|
||||
{
|
||||
unsigned int i, number_of_fields;
|
||||
char *rpt;
|
||||
unsigned char *upt;
|
||||
|
||||
/* check signature */
|
||||
if(up_to < 16)
|
||||
return(-1);
|
||||
rpt= attr_start;
|
||||
upt= (unsigned char *) rpt;
|
||||
if(rpt[0] != aa_name[0] || rpt[1] != aa_name[1] || upt[4] < 0x20)
|
||||
return(-1);
|
||||
|
||||
number_of_fields= upt[8] | (upt[9] << 8) | (upt[10] << 16) | (upt[11] << 24);
|
||||
*num_params= 1;
|
||||
for(i= 0; i < number_of_fields; i++) {
|
||||
if(i > 0) {
|
||||
if(rpt[0] != aa_name[0] || rpt[1] != aa_name[1] || upt[4] >= 0x20)
|
||||
return(-1);
|
||||
if(!(upt[4] & 1))
|
||||
(*num_params)++;
|
||||
}
|
||||
rpt+= upt[2];
|
||||
upt= (unsigned char *) rpt;
|
||||
if(rpt - attr_start >= up_to && i < number_of_fields - 1) {
|
||||
*num_fields= number_of_fields - 1 - i;
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
*new_pos= rpt;
|
||||
*num_fields= number_of_fields;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* Check whether the given fields are an attribute of type PAIR and eventually
|
||||
retrieve its name and value. *value and *name will be allocated memory which
|
||||
has to be freed when no longer needed. Both will have a trailing 0 byte
|
||||
which is not counted in their len values.
|
||||
|
||||
@param aa_name The 2 byte SUSP Signature Word of the fields as of
|
||||
the ER field with signature "AAIP_2008A"
|
||||
@param attr_start Points to the first first field of the attribute.
|
||||
@param up_to Maximum number of bytes to be checked
|
||||
@param new_pos Will point to the desired byte position if return is 1
|
||||
@param name_len Will point to the number of bytes in *name
|
||||
@param name Will point to the bytes of the pair name
|
||||
@param value_len Will point to the number of bytes in *value
|
||||
@param value Will point to the bytes of the pair value
|
||||
@param flag Unused yet. Submit 0
|
||||
|
||||
@return 1 ok, result is valid
|
||||
0 not ok, not a PAIR type attribute or not complete
|
||||
-1 not ok, other error
|
||||
*/
|
||||
int aaip_decode_pair(char aa_name[2], char *attr_start, size_t up_to,
|
||||
char **new_pos,
|
||||
size_t *name_len, char **name,
|
||||
size_t *value_len, char **value, int flag)
|
||||
{
|
||||
unsigned int num_fields, num_params, field_idx= 0;
|
||||
int ret;
|
||||
char *peek_pos;
|
||||
|
||||
*name_len= *value_len= 0;
|
||||
*name= *value= NULL;
|
||||
if(up_to < 9)
|
||||
return(0);
|
||||
if(strncmp(attr_start + 4, "PAIR", 4) != 0)
|
||||
return(0);
|
||||
ret= aaip_decode_check(aa_name, attr_start, up_to, &num_params, &num_fields,
|
||||
&peek_pos, 0);
|
||||
if(ret <= 0)
|
||||
return(ret);
|
||||
if(num_params != 2)
|
||||
return(0);
|
||||
ret= aaip_decode_parameter(attr_start, num_fields, &attr_start, &field_idx,
|
||||
name_len, name, 0);
|
||||
if(ret <= 0)
|
||||
return(-1);
|
||||
ret= aaip_decode_parameter(attr_start, num_fields, &attr_start, &field_idx,
|
||||
value_len, value, 0);
|
||||
if(ret <= 0)
|
||||
return(-1);
|
||||
*new_pos= peek_pos;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* Check whether the given fields are an attribute of type ACL1 and eventually
|
||||
retrieve its long text form ready for acl_from_text(3). This text is
|
||||
terminated by a 0 byte.
|
||||
*text will be allocated memory which has to be freed when no longer needed.
|
||||
|
||||
@param aa_name The 2 byte SUSP Signature Word of the fields as of
|
||||
the ER field with signature "AAIP_2008A"
|
||||
@param attr_start Points to the first first field of the attribute.
|
||||
@param up_to Maximum number of bytes to be checked
|
||||
@param new_pos Will point to the desired byte position if return is 1
|
||||
@param text Will point to the bytes of the ACL text form
|
||||
@param flag Unused yet. Submit 0
|
||||
|
||||
@return 1 ok, result is valid
|
||||
0 not ok, not a ACL1 type attribute or not complete
|
||||
-1 not ok, other error
|
||||
*/
|
||||
int aaip_decode_acl1(char aa_name[2], char *attr_start, size_t up_to,
|
||||
char **new_pos, char **text, int flag)
|
||||
{
|
||||
unsigned int num_fields, num_params, field_idx= 0;
|
||||
int ret;
|
||||
size_t data_len;
|
||||
char *peek_pos, *data= NULL;
|
||||
|
||||
*text= NULL;
|
||||
if(up_to < 9)
|
||||
return(0);
|
||||
if(strncmp(attr_start + 4, "ACL1", 4) != 0)
|
||||
return(0);
|
||||
ret= aaip_decode_check(aa_name, attr_start, up_to, &num_params, &num_fields,
|
||||
&peek_pos, 0);
|
||||
if(ret <= 0)
|
||||
return(ret);
|
||||
if(num_params != 1)
|
||||
return(0);
|
||||
ret= aaip_decode_parameter(attr_start, num_fields, &attr_start, &field_idx,
|
||||
&data_len, &data, 0);
|
||||
if(ret <= 0)
|
||||
return(-1);
|
||||
|
||||
/* >>> convert parameter into long text form of ACL . see man 5 acl */;
|
||||
|
||||
*new_pos= peek_pos;
|
||||
if(data != NULL)
|
||||
free(data);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* Helper function:
|
||||
Read a parameter from one or more fields and return the number of consumed
|
||||
bytes. It is assumed that the completeness of the attribute has been
|
||||
checked already.
|
||||
|
||||
@param start_field Points to the field where the parameter starts
|
||||
@param num_fields Total number of fields in the attribute
|
||||
@param new_pos Will point to the byte position after the parameter
|
||||
@param field_idx Number of fields read so far. This will be updated
|
||||
by this call.
|
||||
@param result_len Will point to the number of bytes in result
|
||||
@param result Will point to bytes of the parameter. A terminating 0
|
||||
is added for convenience but not counted in result_len
|
||||
@param flag Unused yet. Submit 0.
|
||||
@return >0 Number of bytes consumed (payload and overhead)
|
||||
This is eventually the start of the next field
|
||||
after the parameter.
|
||||
<=0 error
|
||||
*/
|
||||
static int aaip_decode_parameter(char *start_field, unsigned int num_fields,
|
||||
char **new_pos, unsigned int *field_idx,
|
||||
size_t *result_len, char **result, int flag)
|
||||
{
|
||||
int overhead, pass;
|
||||
unsigned int fi;
|
||||
char *rpt, *wpt;
|
||||
unsigned char *upt;
|
||||
size_t mem_size= 0;
|
||||
|
||||
*result_len= 0;
|
||||
*result= NULL;
|
||||
fi= *field_idx;
|
||||
|
||||
for(pass= 0; pass < 2; pass++) {
|
||||
rpt= start_field;
|
||||
upt= (unsigned char *) rpt;
|
||||
for(fi= *field_idx; fi < num_fields; fi++) {
|
||||
if(upt[4] >= 0x20)
|
||||
overhead= 16;
|
||||
else
|
||||
overhead= 5;
|
||||
if(pass == 0) {
|
||||
mem_size+= upt[2] - overhead;
|
||||
} else {
|
||||
memcpy(wpt, rpt + overhead, upt[2] - overhead);
|
||||
wpt+= upt[2] - overhead;
|
||||
}
|
||||
rpt+= upt[2];
|
||||
upt= (unsigned char *) rpt;
|
||||
if(fi < num_fields - 1)
|
||||
if(upt[4] < 0x20 && !(upt[4] & 1))
|
||||
break; /* start of next parameter found */
|
||||
}
|
||||
if(pass == 0) {
|
||||
if(mem_size >= Aaip_param_memory_limiT)
|
||||
return(-1);
|
||||
(*result)= calloc(1, mem_size + 1);
|
||||
if(*result == NULL)
|
||||
return(-1);
|
||||
*result_len= mem_size;
|
||||
wpt= *result;
|
||||
wpt[mem_size]= 0; /* a trailing zero cannot harm */
|
||||
}
|
||||
}
|
||||
*field_idx= fi;
|
||||
*new_pos= rpt;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------- Test ------------------------ */
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret, l, mult= 0, k;
|
||||
size_t result_len, i, name_len, value_len;
|
||||
char *result= NULL, *new_pos, *name= NULL, *value= NULL, *params[2], *cpt;
|
||||
unsigned int param_lengths[2];
|
||||
|
||||
if(argc != 3) {
|
||||
fprintf(stderr, "usage: %s [-]name[xNNN] [-]value[xNNN]\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
for(i= 0; i < 2; i++) {
|
||||
params[i]= argv[i + 1];
|
||||
if(argv[i + 1][0] == '-') {
|
||||
cpt= strchr(argv[i + 1], 'x');
|
||||
if(cpt != NULL) {
|
||||
l= cpt - argv[i + 1] - 1;
|
||||
if(l > 0)
|
||||
sscanf(cpt + 1, "%d", &mult);
|
||||
if(l > 0 && mult > 0) {
|
||||
params[i]= calloc(1, l * mult + 1);
|
||||
if(params[i] != NULL) {
|
||||
for(k= 0; k < mult; k++)
|
||||
memcpy(params[i] + k * l, argv[i + 1] + 1, l);
|
||||
params[i][mult * l]= 0;
|
||||
} else
|
||||
params[i]= argv[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
param_lengths[0]= strlen(params[0]);
|
||||
param_lengths[1]= strlen(params[1]);
|
||||
ret= aaip_encode("AA", "PAIR", 2, param_lengths, params,
|
||||
&result_len, &result, 0);
|
||||
if(ret <= 0) {
|
||||
fprintf(stderr, "%s : aaip_encode failed with ret= %d\n", argv[0], ret);
|
||||
exit(2);
|
||||
}
|
||||
printf(
|
||||
" - - - - - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 - - 8 - - 9\n");
|
||||
printf("\n");
|
||||
printf("%4u : ", 0);
|
||||
for(i= 0; i < result_len; i++) {
|
||||
if(result[i] >= 32 && result[i] <= 126)
|
||||
printf("'%c' ", result[i]);
|
||||
else
|
||||
printf("%3u ", (unsigned int) ((unsigned char *) result)[i]);
|
||||
if((i % 10) == 9)
|
||||
printf("\n%4u : ", (unsigned int) (i + 1));
|
||||
}
|
||||
printf("\n\n");
|
||||
printf(
|
||||
" - - - - - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 - - 8 - - 9\n");
|
||||
printf("\n");
|
||||
|
||||
ret= aaip_decode_pair("AA", result, result_len, &new_pos,
|
||||
&name_len, &name, &value_len, &value, 0);
|
||||
if(ret <= 0) {
|
||||
fprintf(stderr, "%s : aaip_decode_pair failed with ret= %d\n",
|
||||
argv[0], ret);
|
||||
exit(3);
|
||||
}
|
||||
if(mult == 0 || (name_len < 1000 && value_len < 1000)) {
|
||||
printf("name = '%s' (%lu)\n", name, (unsigned long) name_len);
|
||||
printf("value= '%s' (%lu)\n", value, (unsigned long) value_len);
|
||||
} else {
|
||||
printf("name = (%lu)\n", (unsigned long) name_len);
|
||||
printf("value= (%lu)\n", (unsigned long) value_len);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if(result != NULL)
|
||||
free(result);
|
||||
if(name != NULL)
|
||||
free(name);
|
||||
if(value != NULL)
|
||||
free(value);
|
||||
exit(0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user