source: libabac/abac.c @ f2622ee

abac0-leak
Last change on this file since f2622ee was f2622ee, checked in by Mei-Hui Su <mei@…>, 6 years ago

1) ran with valgrind and did some leak patching

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