source: libabac/abac_attribute.c @ b7e77df

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

Bugfixes

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