source: libabac/abac_attribute.c @ 7cefdb4

Last change on this file since 7cefdb4 was 75fc453, checked in by Mei <mei@…>, 11 years ago

1) last missing return call

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