source: libabac/abac_graph.c @ 342e28f

abac0-leakabac0-meicompt_changesgec13mei-idmei-rt0-nmei_rt0mei_rt2mei_rt2_fix_1meiyap-rt1meiyap1rt2tvf-new-xml
Last change on this file since 342e28f was 342e28f, checked in by Mike Ryan <mikeryan@…>, 14 years ago

load intersection attribute certificates, do not add them to the graph

  • Property mode set to 100644
File size: 11.5 KB
RevLine 
[d4cbf71]1#include <assert.h>
[379a53f]2#include <stdlib.h>
[d4cbf71]3
[06293d1]4#include "abac_graph.h"
[cb0f2b2]5
[2fd24c7]6#include "abac_set.h"
[3c251d0]7#include "abac_util.h"
[d4cbf71]8
[f46412c]9#include "uthash.h"
10
11// vertex
[06293d1]12struct _abac_vertex_t {
[1743825]13    abac_role_t *role;
[f46412c]14    char *name;
15
[6d5623e]16    abac_list_t *edges;
[f46412c]17
18    UT_hash_handle hh;
19};
20
[ae72c5d]21// edge
[06293d1]22typedef struct _abac_edge_t {
23    abac_vertex_t *vertex;
[401a054]24    abac_credential_t *credential;
[06293d1]25} abac_edge_t;
[ae72c5d]26
[f46412c]27// derived edge
[06293d1]28typedef struct _abac_derived_key_t {
29    abac_vertex_t *head;
30    abac_edge_t *tail;
31} abac_derived_key_t;
[f46412c]32
[06293d1]33typedef struct _abac_derived_t {
34    abac_derived_key_t key;
[f46412c]35    UT_hash_handle hh;
[06293d1]36} abac_derived_t;
[f46412c]37
38// graph
[06293d1]39struct _abac_graph_t {
40    abac_vertex_t *vertices;
41    abac_derived_t *derived;
[f46412c]42    int dirty;
43};
[0ec9e25]44
45/**
46 * Create a new graph.
47 */
[06293d1]48abac_graph_t *abac_graph_new(void) {
[3c251d0]49    abac_graph_t *graph = abac_xmalloc(sizeof(abac_graph_t));
[82aeefa]50
51    graph->vertices = NULL;
[6188f4e]52    graph->derived = NULL;
[82aeefa]53    graph->dirty = 0;
54
55    return graph;
56}
[d4cbf71]57
[b26942d]58/**
59 * Deep copy a graph.
60 */
[06293d1]61abac_graph_t *abac_graph_dup(abac_graph_t *graph) {
62    abac_vertex_t *vertex;
63    abac_edge_t *edge;
[b26942d]64
[06293d1]65    abac_graph_t *clone = abac_graph_new();
[b26942d]66
67    // copy the vertices edge by edge
68    for (vertex = graph->vertices; vertex != NULL; vertex = vertex->hh.next)
[6d5623e]69        abac_list_foreach(vertex->edges, edge,
[b26942d]70            // only copy non-derived edges
[401a054]71            if (edge->credential != NULL)
72                abac_graph_add_credential(clone, edge->credential);
[b26942d]73        );
74
75    return clone;
76}
77
[d4cbf71]78/**
[401a054]79 * Add a vertex to the graph. Should only be called by abac_graph_add_credential.
[d4cbf71]80 */
[06293d1]81static abac_vertex_t *_get_vertex(abac_graph_t *graph, abac_role_t *role) {
82    abac_vertex_t *vertex;
[c28bd8b]83    char *string;
84   
[dcc1a8e]85    string = abac_role_string(role);
[82aeefa]86    HASH_FIND_STR(graph->vertices, string, vertex);
[c28bd8b]87
88    // add the vertex if it doesn't exist
89    if (vertex == NULL) {
[3c251d0]90        vertex = abac_xmalloc(sizeof(abac_vertex_t));
[dcc1a8e]91        vertex->role = abac_role_dup(role);
92        vertex->name = abac_role_string(vertex->role);
[d4cbf71]93
[379a53f]94        // create the list of edges
[6d5623e]95        vertex->edges = abac_list_new();
[d4cbf71]96
[c28bd8b]97        // add it to the vertices
[82aeefa]98        HASH_ADD_KEYPTR(hh, graph->vertices, vertex->name, strlen(vertex->name), vertex);
[c28bd8b]99    }
[d4cbf71]100
101    return vertex;
102}
103
104/**
[401a054]105 * Add a credential to the credential graph.
[d4cbf71]106 */
[401a054]107int abac_graph_add_credential(abac_graph_t *graph, abac_credential_t *cred) {
[06293d1]108    abac_vertex_t *head_vertex, *tail_vertex;
[314869f]109    abac_edge_t *edge;
[d4cbf71]110
[401a054]111    assert(cred != NULL);
[ae72c5d]112
[401a054]113    abac_role_t *head = abac_credential_head(cred);
114    abac_role_t *tail = abac_credential_tail(cred);
[d4cbf71]115
[342e28f]116    // TODO: handle intersections properly
117    if (tail == NULL)
118        return 0;
119
[401a054]120    // a valid credential must have a role for the head
[dcc1a8e]121    if (!abac_role_is_role(head)) return 0;
[d4cbf71]122
[82aeefa]123    head_vertex = _get_vertex(graph, head);
124    tail_vertex = _get_vertex(graph, tail);
[d4cbf71]125
[314869f]126    // make sure we don't insert the same edge twice (ugh)
127    abac_list_foreach(head_vertex->edges, edge,
128        if (edge->vertex == tail_vertex)
129            return 0;
130    );
131
[ae72c5d]132    // create the edge and add it
[314869f]133    edge = abac_xmalloc(sizeof(abac_edge_t));
[ae72c5d]134    edge->vertex = tail_vertex;
[401a054]135    edge->credential = abac_credential_dup(cred);
[ae72c5d]136
[6d5623e]137    abac_list_add(head_vertex->edges, edge);
[d4cbf71]138
[82aeefa]139    // must re-derive edges
140    graph->dirty = 1;
141
[d4cbf71]142    return 1;
143}
144
[ebde9dd]145// find the principals that have a role
[06293d1]146static abac_set_t *_find_principals(abac_graph_t *graph, abac_vertex_t *start_vertex) {
[2fd24c7]147    abac_set_t *principals = abac_set_new();
[d4cbf71]148
[06293d1]149    abac_list_t *traversal = abac_graph_postorder(graph, start_vertex->role);
150    abac_vertex_t *vertex;
[d4cbf71]151
[6d5623e]152    abac_list_foreach(traversal, vertex,
[dcc1a8e]153        if (abac_role_is_principal(vertex->role))
154            abac_set_add(principals, abac_role_string(vertex->role));
[ebde9dd]155    );
[d4cbf71]156
[6d5623e]157    abac_list_free(traversal);
[ebde9dd]158    return principals;
159}
[d4cbf71]160
[6188f4e]161// remove any derived edges from the graph
[06293d1]162void _clear_derived(abac_graph_t *graph) {
163    abac_derived_t *current;
[6188f4e]164
165    while (graph->derived) {
166        current = graph->derived;
167
168        HASH_DEL(graph->derived, current);
169
[06293d1]170        abac_vertex_t *head = current->key.head;
171        abac_edge_t *tail = current->key.tail;
[401a054]172        assert(tail->credential == NULL);
[6188f4e]173
174        // this can fail, but we assume the data structures are consistent
[6d5623e]175        abac_list_remove(head->edges, tail);
[6188f4e]176
177        free(current);
[186cb75]178        free(tail);
[6188f4e]179    }
180}
181
[06293d1]182void abac_graph_derive_links(abac_graph_t *graph) {
183    abac_vertex_t *vertex;
[d4cbf71]184
[ebde9dd]185    if (!graph->dirty)
186        return;
[379a53f]187
[ebde9dd]188    for (vertex = graph->vertices; vertex != NULL; vertex = vertex->hh.next) {
189        // we only care about linking roles
[dcc1a8e]190        if (!abac_role_is_linking(vertex->role))
[ebde9dd]191            continue;
192
193        // linking roles take the form A.r1.r2
[dcc1a8e]194        char *A_r1 = abac_role_linked_role(vertex->role);
195        char *r2 = abac_role_role_name(vertex->role);
[ebde9dd]196
197        // find the linked role in the graph
[06293d1]198        abac_vertex_t *A_r1_vertex;
[ebde9dd]199        HASH_FIND_STR(graph->vertices, A_r1, A_r1_vertex);
200        if (A_r1_vertex == NULL)
201            continue;
202
203        // find the principals that have A.r1
[2fd24c7]204        abac_set_t *principals = _find_principals(graph, A_r1_vertex);
[ebde9dd]205        char *B;
206
[2fd24c7]207        abac_list_t *elts = abac_set_elements(principals);
[ebde9dd]208
209        // and add a link for each B.r2 to A.r1.r2
[6d5623e]210        abac_list_foreach(elts, B,
[ebde9dd]211            int B_len = strlen(B);
212            int r2_len = strlen(r2);
213
214            // create the string B.r2, thx C
215            char *B_r2 = malloc(B_len + r2_len + 2);
216            memcpy(B_r2, B, B_len);
217            B_r2[B_len] = '.';
218            memcpy(B_r2 + B_len + 1, r2, r2_len);
219            B_r2[B_len + r2_len + 1] = 0;
220
[06293d1]221            abac_vertex_t *B_r2_vertex;
[ebde9dd]222            HASH_FIND_STR(graph->vertices, B_r2, B_r2_vertex);
223
224            // add an edge if the principal's granted it to someone
225            if (B_r2_vertex) {
[dcc1a8e]226                debug_printf("adding edge from %s to %s\n", B_r2, abac_role_string(vertex->role));
[3c251d0]227                abac_edge_t *edge = abac_xmalloc(sizeof(abac_edge_t));
[ae72c5d]228                edge->vertex = B_r2_vertex;
[401a054]229                edge->credential = NULL;
[6d5623e]230                abac_list_add(vertex->edges, edge);
[ebde9dd]231
[6188f4e]232                // add to list of derived edges
[3c251d0]233                abac_derived_t *derived = abac_xmalloc(sizeof(abac_derived_t));
[6188f4e]234                derived->key.head = vertex;
[ae72c5d]235                derived->key.tail = edge;
[06293d1]236                HASH_ADD(hh, graph->derived, key, sizeof(abac_derived_key_t), derived);
[ebde9dd]237            }
238
[dbbf777]239#ifdef DEBUG
[dcc1a8e]240            debug_printf("    incoming edges for %s\n", abac_role_string(vertex->role));
[06293d1]241            abac_edge_t *cur;
[6d5623e]242            abac_list_foreach(vertex->edges, cur,
[dcc1a8e]243                debug_printf("        %s (%s)\n", abac_role_string(cur->vertex->role), cur->vertex->name);
[379a53f]244            );
[dbbf777]245#endif
[d4cbf71]246
[ebde9dd]247            free(B_r2);
248        );
249
[6d5623e]250        abac_list_free(elts);
[2fd24c7]251        abac_set_free(principals);
[ebde9dd]252    }
[6188f4e]253
254    graph->dirty = 0;
[d4cbf71]255}
[cb0f2b2]256
[06293d1]257static void _order_recurse(abac_vertex_t *vertex, abac_set_t *seen, int preorder, abac_list_t *stack) {
258    abac_edge_t *incoming;
[cb0f2b2]259
260    // don't revisit nodes
[dcc1a8e]261    if (!abac_set_add(seen, abac_role_string(vertex->role)))
[cb0f2b2]262        return;
263
264    if (preorder)
[6d5623e]265        abac_list_add(stack, vertex);
[cb0f2b2]266
[9536712]267    // recurse along the incoming vertices
[6d5623e]268    abac_list_foreach(vertex->edges, incoming,
[ae72c5d]269        _order_recurse(incoming->vertex, seen, preorder, stack);
[379a53f]270    );
[cb0f2b2]271
272    if (!preorder)
[6d5623e]273        abac_list_add(stack, vertex);
[cb0f2b2]274}
275
[06293d1]276static abac_list_t *_order(abac_graph_t *graph, abac_role_t *start, int preorder) {
[dcc1a8e]277    debug_printf("%sorder at %s\n", preorder ? "pre" : "post", abac_role_string(start));
[ebde9dd]278
[06293d1]279    abac_vertex_t *start_vertex = _get_vertex(graph, start);
[2fd24c7]280    abac_set_t *seen = abac_set_new();
[cb0f2b2]281
[379a53f]282    // create the return list
[6d5623e]283    abac_list_t *stack = abac_list_new();
[cb0f2b2]284
285    _order_recurse(start_vertex, seen, preorder, stack);
286
[2fd24c7]287    abac_set_free(seen);
[be963dc]288
[cb0f2b2]289    return stack;
290}
291
[06293d1]292abac_list_t *abac_graph_postorder(abac_graph_t *graph, abac_role_t *start) {
[82aeefa]293    return _order(graph, start, 0);
[cb0f2b2]294}
[97a5e13]295
[4e426c9]296/**
297 * Postorder traverse the graph and return all the credentials within.
298 */
299abac_list_t *abac_graph_postorder_credentials(abac_graph_t *graph, char *start) {
300    abac_vertex_t *vertex;
301    abac_edge_t *incoming;
302
303    // get the postorder of vertices
304    abac_role_t *role = abac_role_from_string(start);
305    abac_list_t *order = abac_graph_postorder(graph, role);
306
307    // go through the list and dup all the credentials
308    abac_list_t *credentials = abac_list_new();
309    abac_list_foreach(order, vertex,
310        abac_list_foreach(vertex->edges, incoming,
311            if (incoming->credential != NULL)
312                abac_list_add(credentials, abac_credential_dup(incoming->credential));
313        );
314    );
315
316    abac_role_free(role);
317    abac_list_free(order);
318
319    return credentials;
320}
321
[401a054]322static void _query(abac_graph_t *graph, char *role_name, char *principal, abac_graph_t *return_graph) {
[06293d1]323    abac_vertex_t *vertex;
324    abac_edge_t *incoming;
[97a5e13]325
[401a054]326    abac_role_t *role = abac_role_from_string(role_name);
[dcc1a8e]327    abac_role_t *prin_role = abac_role_from_string(principal);
[97a5e13]328
[675cbea]329    // give up on bogus roles
330    if (role == NULL || prin_role == NULL) {
331        free(role);
332        free(prin_role);
333        return;
334    }
335
[2fd24c7]336    abac_set_t *on_path = abac_set_new();
[dcc1a8e]337    abac_set_add(on_path, abac_role_string(prin_role));
[97a5e13]338
[401a054]339    abac_list_t *traversal = abac_graph_postorder(graph, role);
[6d5623e]340    abac_list_foreach(traversal, vertex,
[1743825]341        abac_role_t *role = vertex->role;
[97a5e13]342
[6d5623e]343        abac_list_foreach(vertex->edges, incoming,
[1743825]344            abac_role_t *incoming_role = incoming->vertex->role;
[97a5e13]345
[dcc1a8e]346            if (!abac_set_contains(on_path, abac_role_string(incoming_role)))
[ae72c5d]347                continue;
[97a5e13]348
[dcc1a8e]349            abac_set_add(on_path, abac_role_string(role));
[97a5e13]350
351            // add non-derived edges to the proof graph
[dcc1a8e]352            if (!abac_role_is_linking(role))
[401a054]353                abac_graph_add_credential(return_graph, incoming->credential);
[97a5e13]354
355            // recursively find linked roles
356            else {
[401a054]357                char *linked_role = abac_role_linked_role(role);
[dcc1a8e]358                char *principal = abac_role_principal(incoming_role);
[97a5e13]359
[401a054]360                _query(graph, linked_role, principal, return_graph);
[97a5e13]361            }
362        );
363    );
364
[6d5623e]365    abac_list_free(traversal);
[2fd24c7]366    abac_set_free(on_path);
[401a054]367    abac_role_free(role);
[dcc1a8e]368    abac_role_free(prin_role);
[97a5e13]369}
370
[401a054]371abac_graph_t *abac_graph_query(abac_graph_t *graph, char *role, char *principal) {
[06293d1]372    abac_graph_derive_links(graph);
[97a5e13]373
[06293d1]374    abac_graph_t *return_graph = abac_graph_new();
[401a054]375    _query(graph, role, principal, return_graph);
[06293d1]376    abac_graph_derive_links(return_graph);
[97a5e13]377    return return_graph;
378}
[be963dc]379
[902d079]380/**
[401a054]381 * Get all the credentials (attribute/issuer cert pairs) from the graph.
[902d079]382 */
[401a054]383abac_list_t *abac_graph_credentials(abac_graph_t *graph) {
384    abac_list_t *credentials = abac_list_new();
[902d079]385
[06293d1]386    abac_vertex_t *vertex;
[902d079]387
388    for (vertex = graph->vertices; vertex != NULL; vertex = vertex->hh.next) {
[06293d1]389        abac_edge_t *edge;
[6d5623e]390        abac_list_foreach(vertex->edges, edge,
[401a054]391            if (edge->credential != NULL)
392                abac_list_add(credentials, abac_credential_dup(edge->credential));
[902d079]393        );
394    }
395
[401a054]396    return credentials;
[902d079]397}
398
[06293d1]399void abac_graph_free(abac_graph_t *graph) {
400    abac_vertex_t *vertex;
401    abac_edge_t *edge;
[be963dc]402
403    // kill derived edges
404    _clear_derived(graph);
405
406    // delete vertices
407    while ((vertex = graph->vertices) != NULL) {
408        HASH_DEL(graph->vertices, vertex);
409
[dcc1a8e]410        abac_role_free(vertex->role);
[186cb75]411
[6d5623e]412        abac_list_foreach(vertex->edges, edge,
[401a054]413            if (edge->credential != NULL)
414                abac_credential_free(edge->credential);
[186cb75]415            free(edge);
416        );
[6d5623e]417        abac_list_free(vertex->edges);
[be963dc]418        free(vertex);
419    }
420
421    free(graph);
422}
[f46412c]423
[06293d1]424abac_role_t *abac_vertex_role(abac_vertex_t *vertex) {
[f46412c]425    return vertex->role;
426}
Note: See TracBrowser for help on using the repository browser.