source: libabac/abac_attribute.c @ 288a267

abac0-leak
Last change on this file since 288a267 was 44c8505, checked in by Ted Faber <faber@…>, 11 years ago

Make chunk operations take pointers.

  • Property mode set to 100644
File size: 13.8 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
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;
32    int ntails;
33
34    char *head_string;
35    char **tail_strings;
36    char *output_format;
37    abac_keyid_map_t *keymap;
38
39    abac_chunk_t cert; // the XML chunk
40};
41
42char *abac_attribute_role_string(abac_attribute_t *attr);
43extern abac_id_t *abac_verifier_lookup_id(abac_list_t*, char *keyid);
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
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
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) {
79    libabac_init();
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
89    if(validity == 0) validity = (long)(60*60*24*(365));
90
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;
98    int rc=asprintf(&attr->head_string,"%s.%s",abac_id_keyid(issuer_id),role);
99    attr->ntails = 0;
100    attr->tail_strings = NULL;
101    attr->keymap = 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(validity == 0)
131        return ABAC_FAILURE;
132    return ABAC_SUCCESS;
133}
134
135int abac_attribute_still_valid(abac_attribute_t *attr)
136{
137    assert(attr);
138    assert(attr->cert.ptr);
139    long v=get_validity_from_xml((char *)attr->cert.ptr);
140    if (v > 0.0)
141        return 1;
142    else return 0;
143}
144
145/* string is a malloc copy */
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++] = 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    /* already a copy */
196    char *tmp=abac_attribute_role_string(attr);
197    char *head_tail[2];
198    int ret = 2;
199    abac_split(tmp, "<-", head_tail, &ret);
200    if (ret != 2) goto err;
201    abac_split(head_tail[0], ".", head_tail, &ret);
202    if (ret != 2) goto err;
203    char *prin=strdup(head_tail[0]);
204    free(tmp);
205    return prin;
206
207err:     
208     free(tmp);
209     return NULL;
210}
211
212int abac_attribute_principal(abac_attribute_t *attr, char *keyid) {
213    char *copy = _validate_principal(keyid);
214    if (copy == NULL)
215        return 0;
216
217    return abac_attribute_add_tail(attr,copy);
218}
219
220int abac_attribute_role(abac_attribute_t *attr, char *keyid, char *role) {
221    if (!abac_clean_name(role))
222        return 0;
223
224    char *copy = _validate_principal(keyid);
225    char *newcopy=NULL;
226    if (copy == NULL)
227        return 0;
228
229    int rc=asprintf(&newcopy,"%s.%s", copy,role);
230    free(copy);
231    return abac_attribute_add_tail(attr, newcopy);
232}
233
234int abac_attribute_linking_role(abac_attribute_t *attr, char *keyid, char *role, char *linked) {
235    if (!abac_clean_name(role) || !abac_clean_name(linked))
236        return 0;
237
238    char *copy = _validate_principal(keyid);
239    if (copy == NULL)
240        return 0;
241
242    char *newcopy=NULL;
243    int rc=asprintf(&newcopy,"%s.%s.%s", copy,role,linked);
244    free(copy);
245    return abac_attribute_add_tail(attr, newcopy);
246}
247
248
249
250// 0 for fail to bake, 1 is baked okay
251int abac_attribute_bake_context(abac_attribute_t *attr, abac_context_t *ctxt) {
252    assert(attr);
253    assert(attr->head_string);
254    assert(attr->tail_strings);
255    abac_keyid_map_t *km = NULL;
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    if ( ctxt && (km = abac_context_get_keyid_map(ctxt))) {
263        if (attr->keymap) abac_keyid_map_free(attr->keymap);
264        attr->keymap = abac_keyid_map_dup(km);
265    }
266
267    /* Make an new GENI abac credential with the rt0 rule that expires secs
268     * from now.  cert is the PEM encoded X.509 of the issuer's certificate as
269     * a string.  certlen is the length of cert.  Returns the XML. Caller is
270     * responsible for freeing it. */
271    char *attr_cert=make_credential(attr, attr->validity, 
272            (char *)id_chunk.ptr, id_chunk.len);
273
274    /*MEI, free id_chunk */
275    abac_chunk_free(&id_chunk);
276
277    if (attr_cert == NULL)
278        return 0;
279
280    attr->cert.ptr = attr_cert;
281    attr->cert.len = strlen(attr_cert)+1;
282
283    return 1;
284}
285// 0 for fail to bake, 1 is baked okay
286int abac_attribute_bake(abac_attribute_t *attr) {
287    return abac_attribute_bake_context(attr, NULL);
288}
289
290/*
291 * caller is responsible to free up the chunk after use
292 */
293abac_chunk_t abac_attribute_cert_chunk(abac_attribute_t *attr) {
294    abac_chunk_t chunk= {NULL,0};
295
296    if (abac_chunk_null(&attr->cert))
297        return chunk;
298
299    /* return the xml chunk */
300    chunk.ptr=(unsigned char *) abac_xstrdup(attr->cert.ptr);
301    chunk.len = attr->cert.len;
302    return chunk;
303}
304
305int abac_attribute_baked(abac_attribute_t *attr) {
306    return (attr->cert.ptr != NULL);
307}
308
309
310static abac_attribute_t *_load_attr(abac_list_t *id_certs,char *rstring, char *xml, abac_keyid_map_t *km)
311{
312    /* make a copy of rle_string */
313    char *role_string=abac_xstrdup(rstring);
314
315    char *head_tail[2];
316    char *role_rest[2];
317    int ret = 2;
318    abac_split(role_string, "<-", head_tail, &ret);
319    if (ret != 2) return NULL; 
320
321    char *keyid=get_keyid_from_xml(xml);
322    abac_id_t *issuer_id=abac_verifier_lookup_id(id_certs,keyid);
323
324    long validity=get_validity_from_xml(xml);
325   
326    abac_attribute_t *attr = abac_xmalloc(sizeof(abac_attribute_t));
327    if(issuer_id)
328        attr->issuer_id = abac_id_dup(issuer_id);
329    else attr->issuer_id=NULL;
330    attr->validity = validity;
331    attr->ntails = 0;
332    attr->tail_strings = NULL;
333
334    /* If there is a keymap, make a reference to it. */
335    if ( km ) attr->keymap = abac_keyid_map_dup(km);
336    else attr->keymap = NULL;
337
338
339    attr->head_string = abac_xstrdup(head_tail[0]);
340    do {
341        ret = 2;
342        abac_split(head_tail[1], " & ", role_rest, &ret);
343        abac_attribute_add_tail(attr, abac_xstrdup(role_rest[0]));
344        head_tail[1] =role_rest[1];
345    } while (ret == 2);
346
347    char *tmp=strstr(attr->head_string,".");
348    attr->role =abac_xstrdup(tmp+1);
349
350    attr->cert.ptr = (unsigned char *) abac_xstrdup(xml);
351    attr->cert.len = strlen(xml)+1;
352
353    attr->output_format = NULL;
354
355    free(keyid);
356    free(role_string);
357    return attr;
358}
359
360abac_list_t *abac_attribute_certs_from_file(abac_list_t *id_certs,char *filename)
361{
362    libabac_init();
363    abac_list_t *alist=abac_list_new();
364    char *xml=NULL;
365    char *rt0=NULL;
366    abac_keyid_map_t *km = abac_keyid_map_new();
367
368    char **rt0s=read_credential((void *)id_certs,filename, &xml, km);
369    if(rt0s == NULL) { 
370        abac_keyid_map_free(km);
371        return alist;
372    }
373    if(xml == NULL || strlen(xml)==0) { 
374        abac_keyid_map_free(km);
375        return alist;
376    }
377
378    abac_attribute_t *attr;
379
380    int i=0;
381    do {
382        rt0 = rt0s[i]; 
383        if(rt0 == NULL) break;
384        attr=_load_attr(id_certs,rt0, xml, km);
385        if(attr)
386            abac_list_add(alist, attr);
387        free(rt0);
388        i++;
389    } while (rt0s[i] !=NULL);
390    abac_keyid_map_free(km);
391
392    free(rt0s);
393    free(xml);
394
395    return alist;
396}
397
398abac_list_t *abac_attribute_certs_from_chunk(abac_list_t *id_certs,abac_chunk_t chunk) {
399    libabac_init();
400
401    abac_list_t *alist=abac_list_new();
402    char *xml=(char *)chunk.ptr;
403    abac_keyid_map_t *km = abac_keyid_map_new();
404
405    if(chunk.len==0) return alist;
406
407    char **rt0s=get_rt0_from_xml((void *) id_certs, xml, km);
408    char *rt0=NULL;
409    if(rt0s==NULL) {
410        abac_keyid_map_free(km);
411        return alist;
412    }
413
414    abac_attribute_t *attr;
415    int i=0;
416    do {
417        rt0 = rt0s[i]; 
418        if(rt0 == NULL) break;
419        attr=_load_attr(id_certs,rt0, xml, km);
420        if(attr)
421            abac_list_add(alist, attr);
422        free(rt0);
423        i++;
424    } while (rt0s[i] !=NULL);
425    abac_keyid_map_free(km);
426
427    free(rt0s);
428    return alist;
429}
430
431// returns ABAC_FAILURE if the cert hasn't been baked
432int abac_attribute_write(abac_attribute_t *attr, FILE *out) {
433    assert(attr != NULL);
434
435    if (abac_chunk_null(&attr->cert))
436        return ABAC_FAILURE;
437
438    // write to file
439    fwrite(attr->cert.ptr, attr->cert.len, 1, out);
440
441    return ABAC_SUCCESS;
442}
443
444// returns ABAC_FAILURE if the cert hasn't been baked
445int abac_attribute_write_file(abac_attribute_t *attr, const char *fname) {
446    if (abac_chunk_null(&attr->cert))
447        return ABAC_FAILURE;
448
449    FILE *fp=fopen(fname,"w+");
450    if(fp) {
451         // write to file
452         fwrite(attr->cert.ptr, attr->cert.len, 1, fp);
453    } else return ABAC_FAILURE;
454    fclose(fp);
455
456    return ABAC_SUCCESS;
457}
458
459/* return a copy of the local name mappings, if any.  The returned value is not
460 * reference counted, so callers will need to call abac_keyid_map_dup on it if
461 * they need to keep a copy of the pointer.
462 */
463abac_keyid_map_t *abac_attribute_get_keyid_map(abac_attribute_t *attr) {
464    return attr->keymap;
465}
466
467
468void abac_attribute_free(abac_attribute_t *attr) {
469
470    int i = 0;
471
472    if (attr == NULL)
473        return;
474
475    if(attr->issuer_id) abac_id_free(attr->issuer_id);
476
477    free(attr->role);
478    free(attr->head_string);
479    for (i=0; i < attr->ntails; i++) 
480        free(attr->tail_strings[i]);
481    free(attr->tail_strings);
482    if ( attr->output_format ) 
483        free(attr->output_format);
484
485    if ( attr->keymap ) abac_keyid_map_free(attr->keymap);
486
487    abac_chunk_free(&attr->cert);
488
489    free(attr);
490}
491
492//
493// Helper functions below
494//
495
496// validate a princpal's name
497// makes sure it's a valid SHA1 identifier
498// return values:
499//  success: malloc'd copy with all hex digits lowercase
500//  fail: NULL
501static char *_validate_principal(char *keyid) {
502    int i;
503    char *copy = NULL;
504
505    if (strlen(keyid) != SHA1_LENGTH)
506        return NULL;
507
508    copy = abac_xstrdup(keyid);
509    for (i = 0; i < SHA1_LENGTH; ++i) {
510        copy[i] = tolower(copy[i]);
511        if (!isxdigit(copy[i]))
512            goto error;
513    }
514
515    return copy;
516
517error:
518    free(copy);
519    return NULL;
520}
521
522static int abac_attribute_role_string_size(abac_attribute_t *attr) {
523    int sz = 3; /* Start with the end of string character and <-*/
524    int i;      /* Scratch */
525
526    if ( !attr) return sz;
527    if ( attr->head_string) 
528        sz += strlen(attr->head_string);
529    for (i = 0; i < attr->ntails; i++) 
530        if ( attr->tail_strings[i]) 
531            sz += strlen(attr->tail_strings[i]);
532    /* " & " between each pair of tails */
533    sz += 3 * (attr->ntails-1);
534    return sz;
535}
536
537// combine up the attribute's rule string, explicit copy
538char *abac_attribute_role_string(abac_attribute_t *attr) {
539    assert(attr);
540
541    int sz = abac_attribute_role_string_size(attr);
542    char *role_string=abac_xmalloc(sz);
543    int i;
544
545    if ( !role_string) return NULL;
546
547    sz -= snprintf(role_string, sz, "%s<-", attr->head_string);
548    for ( i = 0 ; i < attr->ntails; i++ ) {
549        if ( i > 0 ) {
550            strncat(role_string, " & ", 3);
551            sz -= 3;
552        }
553        strncat(role_string,attr->tail_strings[i], sz); 
554
555        sz -= strlen(attr->tail_strings[i]);
556        if (sz < 0 ) return NULL;
557    }
558    return role_string;
559}
Note: See TracBrowser for help on using the repository browser.