source: libabac/abac.c @ 7764378

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

1) tweak according valgrind's leak report

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