source: libabac/abac_attribute.c @ 63dcd99

abac0-leak
Last change on this file since 63dcd99 was f43e42c, checked in by Mei <mei@…>, 11 years ago

Merge branch 'abac0-mei' of git://abac.deterlab.net/abac

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