source: libabac/abac_attribute.c @ e50f807

abac0-leakabac0-meitvf-new-xml
Last change on this file since e50f807 was e50f807, checked in by Ted Faber <faber@…>, 11 years ago

Parse and produce 1.1 credentials. Small tweaks, too.

  • Property mode set to 100644
File size: 12.0 KB
RevLine 
[461541a]1
2/* abac_attribute.c */
3
4#define _GNU_SOURCE
5#include <stdio.h>
6#include <assert.h>
7#include <ctype.h>
8#include <string.h>
9#include <time.h>
10
11#include "libabac_common.h"
[4721618]12#include "abac_list.h"
[461541a]13#include "abac_util.h"
14#include "abac_xml.h"
15
16#define ROLE_SEPARATOR " <- "
17#define INTERSECTION_SEP " & "
18#define SHA1_LENGTH 40
19
20static int debug=0;
21
22// a GENI XML attribute chunk might contain multiple
23// attribute rules. It will be translate into multiple
24// abac_attribute structures but with cert ptr pointing
25// to the same xml chunk
26// issuer can be missing but then it won't be bakable
27// unless it is baked just for creddy's roles call
28struct _abac_attribute_t {
29    abac_id_t *issuer_id; 
30    char *role;
31    long validity;
[ab63ece]32    int ntails;
[461541a]33
34    char *head_string;
[ab63ece]35    char **tail_strings;
[461541a]36
37    abac_chunk_t cert; // the XML chunk
38};
39
40char *abac_attribute_role_string(abac_attribute_t *attr);
[13b087a]41extern abac_id_t *abac_verifier_lookup_id(abac_list_t*, char *keyid);
[461541a]42static char *_validate_principal(char *keyid);
43
44/************************************************************/
45abac_chunk_t abac_attribute_cert(abac_attribute_t *ptr)
46{
47    assert(ptr);
48    return ptr->cert;
49}
50
51abac_id_t *abac_attribute_issuer_id(abac_attribute_t *ptr)
52{
53    assert(ptr);
54    return ptr->issuer_id;
55}
56
57// validity is measured in seconds (as of 0.2.0)
58// Acme.customer
59int abac_attribute_create(abac_attribute_t **ret, abac_id_t *issuer_id, char *role, long validity) {
[ef68ac9]60    libabac_init();
[461541a]61    if (!abac_id_has_privkey(issuer_id))
62        return ABAC_ATTRIBUTE_ISSUER_NOKEY;
63    if (!abac_clean_name(role))
64        return ABAC_ATTRIBUTE_INVALID_ROLE;
65    if (validity < 0)
66        return ABAC_ATTRIBUTE_INVALID_VALIDITY;
67    if (!abac_id_still_valid(issuer_id))
68        return ABAC_ATTRIBUTE_INVALID_ISSUER;
69
[7e3f5e2]70    if(validity == 0) validity = (long)(60*60*24*(365));
71
[461541a]72    abac_attribute_t *attr = abac_xmalloc(sizeof(abac_attribute_t));
73    if(issuer_id) attr->issuer_id = abac_id_dup(issuer_id);
74        else attr->issuer_id = NULL;
75    attr->role = abac_xstrdup(role);
76    attr->validity = validity;
77
78    attr->head_string = NULL;
[4721618]79    asprintf(&attr->head_string,"%s.%s",abac_id_keyid(issuer_id),role);
[ab63ece]80    attr->ntails = 0;
81    attr->tail_strings = NULL;
[461541a]82
83    // NULL until baked
84    attr->cert.ptr=NULL;
85    attr->cert.len=0;
86
87    *ret = attr;
88    return ABAC_SUCCESS;
89}
90
91/**
92 * Get the validity period.(xml module returns the diff from expire time - now()
93 */
94int abac_attribute_validity(abac_attribute_t *attr,struct tm *not_before,struct tm *not_after) {
95    assert(attr);
96    memset(not_before, 0, sizeof(struct tm));
97    memset(not_after, 0, sizeof(struct tm));
98
99    time_t now;
100    time(&now);
101    gmtime_r(&now, not_before);
[9ac7fb4]102    char *xml=(char *)attr->cert.ptr;
[461541a]103    long validity=get_validity_from_xml(xml);
104
105    time_t etime = now + validity;
106    gmtime_r(&etime, not_after);
107
[7e3f5e2]108    if(debug) fprintf(stderr,"validity from the xml blob is %ld\n",validity);
[461541a]109    if(validity == 0)
110        return ABAC_FAILURE;
111    return ABAC_SUCCESS;
112}
113
114int abac_attribute_still_valid(abac_attribute_t *attr)
115{
116    assert(attr);
117    assert(attr->cert.ptr);
[9ac7fb4]118    long v=get_validity_from_xml((char *)attr->cert.ptr);
[461541a]119    if (v > 0.0)
120        return 1;
121    else return 0;
122}
123
[ab63ece]124int abac_attribute_add_tail(abac_attribute_t *attr, char *string) {
125    assert(attr);
126
127    char **old_tail = attr->tail_strings;
128    int newsize = (attr->ntails+1)*sizeof(char *);
129
130    if ( !(attr->tail_strings = realloc(attr->tail_strings, newsize))) {
131        attr->tail_strings = old_tail;
132        return 0;
133    }
134    attr->tail_strings[attr->ntails++] = abac_xstrdup(string);
135    return 1;
136}
137
138
[461541a]139void abac_attribute_set_head(abac_attribute_t *attr, char *string)
140{
141    assert(attr);
142    attr->head_string=string;
143}
144
145char *abac_attribute_get_head(abac_attribute_t *attr)
146{
147    assert(attr);
148    return attr->head_string;
149}
[e50f807]150
[ab63ece]151/*
[e50f807]152 * Return the number of tail strings
153 */
154int abac_attribute_get_ntails(abac_attribute_t *attr) {
[461541a]155    assert(attr);
[e50f807]156    return attr->ntails;
[461541a]157}
158
[e50f807]159/*
160 * Return the nth tail string or NULL if it is undefined
161 */
162
163char *abac_attribute_get_tail_n(abac_attribute_t *attr, int n) {
[461541a]164    assert(attr);
[e50f807]165    if ( n < 0 || n > attr->ntails) return NULL;
166    return attr->tail_strings[n];
[461541a]167}
[e50f807]168
[461541a]169
170/* A.b->C, return copy of a A */
171char *abac_attribute_get_principal(abac_attribute_t *attr)
172{
173    char *role_string=abac_attribute_role_string(attr);
174    /* make an copy */
175    char *tmp=strdup(role_string);
176    char *head_tail[2];
[ab63ece]177    int ret = 2;
[461541a]178    abac_split(tmp, "<-", head_tail, &ret);
179    if (ret != 2) goto err;
180    abac_split(head_tail[0], ".", head_tail, &ret);
181    if (ret != 2) goto err;
182    char *prin=strdup(head_tail[0]);
183    free(tmp);
184    return prin;
185
186err:     
187     free(tmp);
188     return NULL;
189}
190
191int abac_attribute_principal(abac_attribute_t *attr, char *keyid) {
192    char *copy = _validate_principal(keyid);
193    if (copy == NULL)
194        return 0;
195
[ab63ece]196    return abac_attribute_add_tail(attr,copy);
[461541a]197}
198
199int abac_attribute_role(abac_attribute_t *attr, char *keyid, char *role) {
200    if (!abac_clean_name(role))
201        return 0;
202
203    char *copy = _validate_principal(keyid);
[ab63ece]204    char *newcopy=NULL;
[461541a]205    if (copy == NULL)
206        return 0;
207
[ab63ece]208    asprintf(&newcopy,"%s.%s", copy,role);
[4e10a0f]209    free(copy);
[ab63ece]210    return abac_attribute_add_tail(attr, newcopy);
[461541a]211}
212
213int abac_attribute_linking_role(abac_attribute_t *attr, char *keyid, char *role, char *linked) {
214    if (!abac_clean_name(role) || !abac_clean_name(linked))
215        return 0;
216
217    char *copy = _validate_principal(keyid);
218    if (copy == NULL)
219        return 0;
220
[4e10a0f]221    char *newcopy=NULL;
[ab63ece]222    asprintf(&newcopy,"%s.%s.%s", copy,role,linked);
[4e10a0f]223    free(copy);
[ab63ece]224    return abac_attribute_add_tail(attr, newcopy);
[461541a]225}
226
227
228
229// 0 for fail to bake, 1 is baked okay
230int abac_attribute_bake(abac_attribute_t *attr) {
231    assert(attr);
232    assert(attr->head_string);
[ab63ece]233    assert(attr->tail_strings);
[461541a]234
235    abac_chunk_t id_chunk = { NULL, 0 };
236    int ret=abac_id_PEM(attr->issuer_id, &id_chunk);
237    if(ret != ABAC_CERT_SUCCESS)
238        return 0; 
239
240/* Make an new GENI abac credential with the rt0 rule that expires secs from
241 * now.  cert is the PEM encoded X.509 of the issuer's certificate as a string.
242 * certlen is the length of cert.  Returns the XML. Caller is responsible for
243 * freeing it. */
[e50f807]244    char *attr_cert=make_credential(attr, attr->validity, (char *)id_chunk.ptr, id_chunk.len);
[461541a]245
246    if (attr_cert == NULL)
247        return 0;
248
249    attr->cert.ptr = (unsigned char *)attr_cert;
250    attr->cert.len = strlen(attr_cert);
251
[e50f807]252    /* free(role_string); */
[461541a]253    return 1;
254}
255
256// make an explicit copy
[4721618]257abac_chunk_t abac_attribute_cert_chunk(abac_attribute_t *attr) {
258    abac_chunk_t chunk= {NULL,0};
[461541a]259
260    if (attr->cert.ptr == NULL)
[4721618]261        return chunk;
[461541a]262
263    /* return the xml chunk */
[4721618]264    chunk.ptr= (unsigned char *)abac_xstrdup((char *)attr->cert.ptr);
265    chunk.len=attr->cert.len;
266    return chunk;
[461541a]267}
268
269int abac_attribute_baked(abac_attribute_t *attr) {
270    return (attr->cert.ptr != NULL);
271}
272
273
[bec30b5]274static abac_attribute_t *_load_attr(abac_list_t *id_certs,char *rstring, char *xml)
[461541a]275{
[02036f4]276    /* make a copy of rle_string */
277    char *role_string=abac_xstrdup(rstring);
[461541a]278
279if(debug) fprintf(stderr,"loading -> %s \n", role_string);
280
281    char *head_tail[2];
[ab63ece]282    char *role_rest[2];
283    int ret = 2;
[461541a]284    abac_split(role_string, "<-", head_tail, &ret);
285    if (ret != 2) return NULL; 
286
287    char *keyid=get_keyid_from_xml(xml);
[bec30b5]288    abac_id_t *issuer_id=abac_verifier_lookup_id(id_certs,keyid);
[461541a]289
290    long validity=get_validity_from_xml(xml);
291   
292    abac_attribute_t *attr = abac_xmalloc(sizeof(abac_attribute_t));
293    if(issuer_id)
294        attr->issuer_id = abac_id_dup(issuer_id);
295        else attr->issuer_id=NULL;
296    attr->validity = validity;
297
298    attr->head_string = abac_xstrdup(head_tail[0]);
[ab63ece]299    do {
300        ret = 2;
301        abac_split(head_tail[1], " & ", role_rest, &ret);
302        abac_attribute_add_tail(attr, abac_xstrdup(role_rest[0]));
303        head_tail[1] =role_rest[1];
304    } while (ret == 2);
305
[461541a]306    char *tmp=strstr(attr->head_string,".");
307    attr->role =abac_xstrdup(tmp+1);
308
[9e063cb]309    attr->cert.ptr=(unsigned char *)abac_xstrdup(xml);
[461541a]310    attr->cert.len=strlen(xml);
311
312    return attr;
313}
314
[bec30b5]315abac_list_t *abac_attribute_certs_from_file(abac_list_t *id_certs,char *filename)
[461541a]316{
[ef68ac9]317    libabac_init();
[461541a]318    abac_list_t *alist=abac_list_new();
319    char *xml=NULL;
320    char *rt0=NULL;
321
[e50f807]322    char **rt0s=read_credential((void *)id_certs,filename, &xml);
[4721618]323    if(rt0s == NULL) return alist;
324    if(xml == NULL || strlen(xml)==0) return alist;
[461541a]325
326    abac_attribute_t *attr;
327
328    int i=0;
329    do {
330        rt0 = rt0s[i]; 
331        if(rt0 == NULL) break;
[bec30b5]332        attr=_load_attr(id_certs,rt0, xml);
[461541a]333        if(attr)
334            abac_list_add(alist, attr);
335        free(rt0);
336        i++;
337    } while (rt0s[i] !=NULL);
338
339    free(rt0s);
340    free(xml);
341
342    return alist;
343}
344
[bec30b5]345abac_list_t *abac_attribute_certs_from_chunk(abac_list_t *id_certs,abac_chunk_t chunk) {
[ef68ac9]346    libabac_init();
[461541a]347
348    abac_list_t *alist=abac_list_new();
349    char *xml=(char *)chunk.ptr;
[4721618]350    if(chunk.len==0) return alist;
351
[bec30b5]352    char **rt0s=get_rt0_from_xml((void *) id_certs,xml);
[461541a]353    char *rt0=NULL;
[4721618]354    if(rt0s==NULL) return alist;
[461541a]355
356    abac_attribute_t *attr;
357    int i=0;
358    do {
359        rt0 = rt0s[i]; 
360        if(rt0 == NULL) break;
[bec30b5]361        attr=_load_attr(id_certs,rt0, xml);
[461541a]362        if(attr)
363            abac_list_add(alist, attr);
364        free(rt0);
365        i++;
366    } while (rt0s[i] !=NULL);
367
368    free(rt0s);
369    return alist;
370}
371
[4721618]372// returns ABAC_FAILURE if the cert hasn't been baked
[461541a]373int abac_attribute_write(abac_attribute_t *attr, FILE *out) {
374    assert(attr != NULL);
375
376    if (attr->cert.ptr == NULL)
[4721618]377        return ABAC_FAILURE;
[461541a]378
379    // write to file
380    fwrite(attr->cert.ptr, attr->cert.len, 1, out);
381
[4721618]382    return ABAC_SUCCESS;
[461541a]383}
384
[4721618]385// returns ABAC_FAILURE if the cert hasn't been baked
386int abac_attribute_write_file(abac_attribute_t *attr, const char *fname) {
387    if (attr->cert.ptr == NULL)
388        return ABAC_FAILURE;
389
390    FILE *fp=fopen(fname,"w+");
391    if(fp) {
392         // write to file
393         fwrite(attr->cert.ptr, attr->cert.len, 1, fp);
394    } else return ABAC_FAILURE;
395    fclose(fp);
396
397    return ABAC_SUCCESS;
398}
399
400
[461541a]401void abac_attribute_free(abac_attribute_t *attr) {
402
403if(debug) fprintf(stderr,"calling abac_attribute_free on %s\n", attr->head_string);
[ab63ece]404    int i = 0;
[461541a]405
406    if (attr == NULL)
407        return;
408
409    if(attr->issuer_id) abac_id_free(attr->issuer_id);
410
411    free(attr->role);
412    free(attr->head_string);
[ab63ece]413    for (i=0; i < attr->ntails; i++) 
414        free(attr->tail_strings[i]);
415    free(attr->tail_strings);
[461541a]416
417/* XXX this can not be free as if it is a char string
418    free(attr->cert.ptr);
419*/
420
421    free(attr);
422}
423
424//
425// Helper functions below
426//
427
428// validate a princpal's name
429// makes sure it's a valid SHA1 identifier
430// return values:
431//  success: malloc'd copy with all hex digits lowercase
432//  fail: NULL
433static char *_validate_principal(char *keyid) {
434    int i;
435    char *copy = NULL;
436
437    if (strlen(keyid) != SHA1_LENGTH)
438        return NULL;
439
440    copy = abac_xstrdup(keyid);
441    for (i = 0; i < SHA1_LENGTH; ++i) {
442        copy[i] = tolower(copy[i]);
443        if (!isxdigit(copy[i]))
444            goto error;
445    }
446
447    return copy;
448
449error:
450    free(copy);
451    return NULL;
452}
453
[ab63ece]454static int abac_attribute_role_string_size(abac_attribute_t *attr) {
455    int sz = 3; /* Start with the end of string character and <-*/
456    int i;      /* Scratch */
457
458    if ( !attr) return sz;
459    if ( attr->head_string) 
460        sz += strlen(attr->head_string);
461    for (i = 0; i < attr->ntails; i++) 
462        if ( attr->tail_strings[i]) 
463            sz += strlen(attr->tail_strings[i]);
464    /* " & " between each pair of tails */
465    sz += 3 * (attr->ntails-1);
466    return sz;
467}
468
[461541a]469// combine up the attribute's rule string, explicit copy
470char *abac_attribute_role_string(abac_attribute_t *attr) {
471    assert(attr);
472
[ab63ece]473    int sz = abac_attribute_role_string_size(attr);
474    char *role_string=abac_xmalloc(sz);
475    int i;
476
477    if ( !role_string) return NULL;
[461541a]478
[ab63ece]479    sz -= snprintf(role_string, sz, "%s<-", attr->head_string);
480    for ( i = 0 ; i < attr->ntails; i++ ) {
481        if ( i > 0 ) {
482            strncat(role_string, " & ", 3);
483            sz -= 3;
484        }
485        strncat(role_string,attr->tail_strings[i], sz); 
[461541a]486
[ab63ece]487        sz -= strlen(attr->tail_strings[i]);
488        if (sz < 0 ) return NULL;
489    }
490    return role_string;
491}
Note: See TracBrowser for help on using the repository browser.