source: libabac/abac.c @ c19da53

Last change on this file since c19da53 was 0a1ee31, checked in by Mei <mei@…>, 11 years ago

1) merged with ted's changes

  • Property mode set to 100644
File size: 11.2 KB
RevLine 
[461541a]1/* abac.c */
2
[90d20f0]3#include <assert.h>
[0bf0e67]4#include <err.h>
[bec30b5]5#include <sys/types.h>
6#include <sys/stat.h>
7#include <unistd.h>
8#include <dirent.h>
[90d20f0]9
[9efbfbf]10#include "abac.h"
[4721618]11#include "abac_list.h"
[06293d1]12#include "abac_graph.h"
[3c251d0]13#include "abac_util.h"
[43e3b71]14#include "abac_verifier.h"
[90d20f0]15
[bec30b5]16abac_id_cert_t **abac_context_principals(abac_context_t *ctx);
17void abac_context_id_credentials_free(abac_id_cert_t **id_credentials);
18
[390f749]19struct _abac_context_t {
[bec30b5]20/* list of principal id credentials, abac_id_cert_t */
21    abac_list_t *id_certs;
[06293d1]22    abac_graph_t *graph;
[94605f2]23    abac_keyid_map_t *keymap;
[90d20f0]24};
25
26/**
27 * Init the library.
28 */
29void libabac_init(void) {
[55c272b]30    void libabac_deinit(void);
31    static int has_been_init = 0;
32
33    // called every time a context is created, so only do it once
34    if (!has_been_init) {
35        abac_verifier_init();
36        atexit(libabac_deinit);
37        has_been_init = 1;
38    }
[90d20f0]39}
40
41/**
42 * Deinit the library.
43 */
44void libabac_deinit(void) {
[43e3b71]45    abac_verifier_deinit();
[90d20f0]46}
47
48/**
49 * Create a new abac context.
50 */
[390f749]51abac_context_t *abac_context_new(void) {
[55c272b]52    libabac_init();
53
[390f749]54    abac_context_t *ctx = abac_xmalloc(sizeof(abac_context_t));
55    ctx->graph = abac_graph_new();
[bec30b5]56    ctx->id_certs=abac_list_new();
[94605f2]57    ctx->keymap = abac_keyid_map_new();
[390f749]58    return ctx;
[90d20f0]59}
60
61/**
62 * Deep copy an abac context.
63 */
[390f749]64abac_context_t *abac_context_dup(abac_context_t *ctx) {
65    assert(ctx != NULL);
[bec30b5]66   
[390f749]67    abac_context_t *dup = abac_xmalloc(sizeof(abac_context_t));
68    dup->graph = abac_graph_dup(ctx->graph);
[bec30b5]69    dup->id_certs=abac_list_new();
70
71    abac_id_cert_t *id_cert;
72    abac_list_foreach(ctx->id_certs, id_cert,
73        abac_list_add(dup->id_certs, abac_id_cert_dup(id_cert));
74    );
[90d20f0]75
[d2b198c]76    dup->keymap = abac_keyid_map_clone(ctx->keymap);
[90d20f0]77    return dup;
78}
79
80/**
81 * Free an abac context.
82 */
[390f749]83void abac_context_free(abac_context_t *ctx) {
84    assert(ctx != NULL);
[90d20f0]85
[390f749]86    abac_graph_free(ctx->graph);
[bec30b5]87
88    abac_id_cert_t *id_cert;
89    abac_list_foreach(ctx->id_certs, id_cert,
90        abac_id_cert_free(id_cert);
91    );
92    abac_list_free(ctx->id_certs);
[94605f2]93    abac_keyid_map_free(ctx->keymap);
[390f749]94    free(ctx);
[90d20f0]95}
96
97/**
98 * Load an ID cert from a file.
99 */
[390f749]100int abac_context_load_id_file(abac_context_t *ctx, char *filename) {
101    assert(ctx != NULL); assert(filename != NULL);
[94605f2]102    return abac_verifier_load_id_file(ctx->id_certs,filename, ctx->keymap);
[90d20f0]103}
104
105/**
106 * Load an ID cert from a chunk.
107 */
[461541a]108int abac_context_load_id_chunk(abac_context_t *ctx, abac_chunk_t cert_chunk) {
[390f749]109    assert(ctx != NULL);
[94605f2]110    return abac_verifier_load_id_chunk(ctx->id_certs,cert_chunk, ctx->keymap);
[90d20f0]111}
112
[f2622ee]113/**
114 * Load an ID cert from a id.
115 */
[7764378]116int abac_context_load_id_id(abac_context_t *ctx, abac_id_t *id) {
[f2622ee]117    assert(ctx != NULL);
118    return abac_verifier_load_id_id(ctx->id_certs,id, ctx->keymap);
119}
120
121
[90d20f0]122/**
123 * Load an attribute cert from a file.
124 */
[390f749]125int abac_context_load_attribute_file(abac_context_t *ctx, char *filename) {
[0779c99]126    int ret, add_ret;
[461541a]127    abac_list_t *cred_list=abac_list_new(); // could be more than 1
[0779c99]128    abac_credential_t *cred;
[6dd2d1a]129
[390f749]130    assert(ctx != NULL); assert(filename != NULL);
[90d20f0]131
[d2b198c]132    ret = abac_verifier_load_attribute_cert_file(ctx->id_certs, filename, cred_list, ctx->keymap);
[461541a]133
[0779c99]134    if (ret == ABAC_CERT_SUCCESS) {
[461541a]135        int size = abac_list_size(cred_list);
136        if(size) {
137            abac_list_foreach(cred_list, cred,
138                add_ret = abac_graph_add_credential(ctx->graph, cred);
139                assert(add_ret != ABAC_GRAPH_CRED_INVALID);
140                abac_credential_free(cred);
141            );
142        }
[6dd2d1a]143    }
[7764378]144    abac_list_free(cred_list);
[6dd2d1a]145    return ret;
[90d20f0]146}
147
148/**
149 * Load an attribute cert from a chunk.
150 */
[461541a]151int abac_context_load_attribute_chunk(abac_context_t *ctx, abac_chunk_t cert_chunk) {
[0779c99]152    int ret, add_ret;
[4721618]153    abac_list_t  *cred_list=abac_list_new(); // could be more than 1
[0779c99]154    abac_credential_t *cred;
155
[390f749]156    assert(ctx != NULL);
[90d20f0]157
[d2b198c]158    ret = abac_verifier_load_attribute_cert_chunk(ctx->id_certs, cert_chunk, cred_list, ctx->keymap);
[0779c99]159    if (ret == ABAC_CERT_SUCCESS) {
[461541a]160        int size = abac_list_size(cred_list);
161        if(size) {
162            abac_list_foreach(cred_list, cred,
163                add_ret = abac_graph_add_credential(ctx->graph, cred);
164                assert(add_ret != ABAC_GRAPH_CRED_INVALID);
165                abac_credential_free(cred);
166            );
167            abac_list_free(cred_list);
168        }
[0779c99]169    }
170
171    return ret;
[90d20f0]172}
173
[50b9dc9]174#define ID_PAT "/*_ID.{der,pem}"
[461541a]175#define ATTR_PAT "/*_attr.xml"
[03b3293]176
[bec30b5]177static int is_regular_file(char *filename)
178{
179   struct stat sb;
180   if(stat(filename,&sb) == -1)
181       return 0;
182   if((sb.st_mode & S_IFMT) == S_IFREG)
183       return 1;
184   return 0;
185}
186
[03b3293]187/**
188 * Load a directory full of certs.
189 */
[390f749]190void abac_context_load_directory(abac_context_t *ctx, char *path) {
[bec30b5]191    DIR *dp;
192    struct dirent *ep;
193     
194    dp = opendir (path);
195    if (dp != NULL) {
[756011e]196        while ((ep = readdir (dp))) {
[bec30b5]197            if(is_regular_file(ep->d_name)) {
198                int ret = abac_context_load_id_file(ctx, ep->d_name);
199                if (ret == ABAC_CERT_SUCCESS) {
200                    continue;
201                }
202                ret = abac_context_load_attribute_file(ctx, ep->d_name);
203            }
204        }
205        (void) closedir (dp);
206    } else fprintf(stderr, "abac_load_directory, Couldn't open the directory\n");
[03b3293]207}
208
[90d20f0]209/**
[dc62c68]210 * Run a query on the data in an abac context. Returns a NULL-terminated array
[38782df]211 * of abac_credential_t. Success/failure in *success.
[90d20f0]212 */
[4e426c9]213abac_credential_t **abac_context_query(abac_context_t *ctx, char *role, char *principal, int *success) {
[401a054]214    abac_credential_t **credentials = NULL, *cur;
[dc62c68]215    int i = 0;
216
[3613ab8]217    assert(ctx != NULL); assert(role != NULL); assert(principal != NULL); assert(success != NULL);
[90d20f0]218
[390f749]219    abac_graph_t *result_graph = abac_graph_query(ctx->graph, role, principal);
[401a054]220    abac_list_t *result = abac_graph_credentials(result_graph);
[90d20f0]221
[06293d1]222    abac_graph_free(result_graph);
[90d20f0]223
[6d5623e]224    int size = abac_list_size(result);
[4e426c9]225    if (size > 0)
226        *success = 1;
227
228    // if there is no actual path, return everything that can reach the role
229    else {
230        *success = 0;
231        abac_list_free(result);
[d4b3b52]232
233        // TODO: This can probably be better, but it now returns an
234        // approximation of a partial proof.  It returns all the attributes the
235        // principal can reach and all the attributes that will lead to a
236        // success.
237
238        /* Get all the attributes of the principal.  This calls sub-queries to
239         * flesh out the indirect proofs. */
240        result_graph = abac_graph_principal_creds(ctx->graph, principal);
241
242        /* This gets all the attributes linked to the target en route to the
243         * principal. */
244        result = abac_graph_postorder_credentials(ctx->graph, role);
245
246        /* Merge responses */
[f6576c4]247        int add_ret;
[d4b3b52]248        abac_list_foreach(result, cur,
[f6576c4]249            add_ret=abac_graph_add_credential(result_graph, cur);
250            assert(add_ret != ABAC_GRAPH_CRED_INVALID);
251            abac_credential_free(cur);
[d4b3b52]252        );
253        abac_list_free(result);
254        abac_graph_derive_links(result_graph);
255
256        result = abac_graph_credentials(result_graph);
257        abac_graph_free(result_graph);
[4e426c9]258
259        size = abac_list_size(result);
260    }
261
[38782df]262    // make the array (leave space to NULL terminate it)
263    //      n.b., even if the list is empty, we still return an array that
264    //            only contains the NULL terminator
265    credentials = abac_xmalloc(sizeof(abac_credential_t *) * (size + 1));
266    abac_list_foreach(result, cur,
267        credentials[i++] = cur;
268    );
269    credentials[i] = NULL;
[dc62c68]270
[6d5623e]271    abac_list_free(result);
[dc62c68]272
[401a054]273    return credentials;
[90d20f0]274}
275
[bec30b5]276
[90d20f0]277/**
[3c4fd68]278 * A NULL-terminated array of all the credentials in the context.
[90d20f0]279 */
[3c4fd68]280abac_credential_t **abac_context_credentials(abac_context_t *ctx) {
281    abac_credential_t *cred;
282    int i = 0;
283
284    assert(ctx != NULL);
285
286    abac_list_t *cred_list = abac_graph_credentials(ctx->graph);
287    int size = abac_list_size(cred_list);
288
289    abac_credential_t **credentials = abac_xmalloc(sizeof(abac_credential_t *) * (size + 1));
290    abac_list_foreach(cred_list, cred,
291        credentials[i++] = cred;
292    );
293    credentials[i] = NULL;
294
295    abac_list_free(cred_list);
296
[0a1ee31]297/* EXTRA: print out a list of principal stored within the context.. */
298    if(0) {
[bec30b5]299        abac_id_cert_t **ilist=abac_context_principals(ctx);
300        abac_id_cert_t *cert;
301        if (ilist != NULL)
302            for (i = 0; ilist[i] != NULL; ++i) {
303                cert = ilist[i];
304                printf("id[%d] %s\n",i, abac_id_cert_keyid(cert));
305            }
306        abac_context_id_credentials_free(ilist);
307    }
308
[3c4fd68]309    return credentials;
310}
311
[94605f2]312/*
313 * Replace known keyids with their nicknames (mnemonic names).  If a non-NULL
314 * string is returned it needs to be freed by the caller.
315 */
316char *abac_context_expand_key(abac_context_t *ctxt, char *s ) {
317    if ( ctxt->keymap ) 
318        return abac_keyid_map_expand_key(ctxt->keymap, s);
319    else
320        return NULL;
321}
322
323/*
324 * Replace known nicknames(mnemonic names)  with their keyids.  If a non-NULL
325 * string is returned it needs to be freed by the caller.
326 */
327char *abac_context_expand_nickname(abac_context_t *ctxt, char *s ) {
328    if ( ctxt->keymap ) 
329        return abac_keyid_map_expand_nickname(ctxt->keymap, s);
330    else
331        return NULL;
332}
333
[d2b198c]334/*
335 * Add a nickname to the context.  The keyid must be known to the context.  If
336 * the nickname is in use, it is disambiguated.  Call abac_context_expand_key
337 * to see the assigned name if that is required.  Existing nickname for keyid
338 * is overwritten.  Returns true if the change was successful.
339 */
340int abac_context_set_nickname(abac_context_t *ctxt, char *key, char*nick) {
341    char *p = NULL;
342
343    if ( !ctxt->keymap) return 0;
344    /* Make sure we know the key.  Free the returned nickname */
345    if ( !(p = abac_keyid_map_key_to_nickname(ctxt->keymap, key))) return 0;
346    else free(p);
347
348    abac_keyid_map_remove_keyid(ctxt->keymap, key);
349    return abac_keyid_map_add_nickname(ctxt->keymap, key, nick);
350}
351
[afcafea]352/*
353 * Get direct access to the context's keyid mapping.  Used internally.  This
354 * does not make a reference to the map, use abac_keyid_map_dup if that is
355 * required.
356 */
357abac_keyid_map_t *abac_context_get_keyid_map(abac_context_t *ctxt) {
358    return ctxt->keymap;
359}
[d2b198c]360
361
[bec30b5]362/**
363 * A NULL-terminated array of all the principals in the context.
364 */
365abac_id_cert_t **abac_context_principals(abac_context_t *ctx)
366{
[756011e]367    abac_id_cert_t **principals = NULL;
[bec30b5]368    assert(ctx != NULL);
369
370    int size = abac_list_size(ctx->id_certs);
371
372    // make the array (leave space to NULL terminate it)
373    //      n.b., even if the list is empty, we still return an array that
374    //            only contains the NULL terminator
375    principals = abac_xmalloc(sizeof(abac_id_cert_t *) * (size + 1));
376    int i = 0;
377    abac_id_cert_t *id_cert;
378    abac_list_foreach(ctx->id_certs, id_cert,
379        principals[i]=abac_id_cert_dup(id_cert);
380        i++;
381    );
382    principals[i] = NULL;
383
384    return principals;
385}
386
387
[3c4fd68]388/**
389 * Frees a NULL-terminated list of credentials.
390 */
391void abac_context_credentials_free(abac_credential_t **credentials) {
[dc62c68]392    int i;
[90d20f0]393
[401a054]394    if (credentials == NULL)
[90d20f0]395        return;
396
[401a054]397    for (i = 0; credentials[i] != NULL; ++i)
398        abac_credential_free(credentials[i]);
399    free(credentials);
[90d20f0]400}
[bec30b5]401
402/**
403 * Frees a NULL-terminated list of id credentials
404 */
405void abac_context_id_credentials_free(abac_id_cert_t **id_credentials) {
406    int i;
407
408    if (id_credentials == NULL)
409        return;
410
411    for (i = 0; id_credentials[i] != NULL; ++i) {
412        abac_id_cert_free(id_credentials[i]);
413    }
414    free(id_credentials);
415}
416
417
Note: See TracBrowser for help on using the repository browser.