source: libabac/abac_role.c @ c0fe894

abac0-leak
Last change on this file since c0fe894 was 94605f2, checked in by Ted Faber <faber@…>, 11 years ago

checkpoint Lots of the way toward mnemonic names, some parsing fixes

  • Property mode set to 100644
File size: 9.8 KB
Line 
1#include <assert.h>
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5
6#include "abac.h"
7#include "abac_list.h"
8#include "abac_util.h"
9
10// typedef'd in role.h
11struct _abac_role_t {
12    char *principal;
13    char *linked_role;
14    char *role_name;
15
16    char *string;
17    char *linked;
18    /* Copy of the last string printed with abac_role_short_string */
19    char *short_string;
20
21    abac_list_t *prereqs;
22
23    int refcount;
24};
25
26/**
27 * Create a new principal and initialize it.
28 */
29abac_role_t *abac_role_principal_new(char *principal) {
30    assert(principal != NULL);
31
32    abac_role_t *role;
33
34    if (strlen(principal) == 0)
35        return NULL;
36
37    role = abac_xmalloc(sizeof(abac_role_t));
38
39    role->principal = abac_xstrdup(principal);
40    role->role_name = NULL;
41    role->linked_role = NULL;
42
43    role->string = abac_xstrdup(principal);
44    role->short_string = NULL;
45    role->linked = NULL;
46    role->prereqs = NULL;
47
48    role->refcount = 1;
49
50    return role;
51}
52
53/**
54 * Create a new role and initialize it.
55 */
56abac_role_t *abac_role_role_new(char *principal, char *role_name) {
57    assert(principal != NULL);
58    assert(role_name != NULL);
59
60    abac_role_t *role;
61
62    if (strlen(principal) == 0 || strlen(role_name) == 0)
63        return NULL;
64
65    role = abac_xmalloc(sizeof(abac_role_t));
66
67    role->principal = abac_xstrdup(principal);
68    role->role_name = abac_xstrdup(role_name);
69    role->linked_role = NULL;
70
71    int prin_len = strlen(principal);
72    int role_len = strlen(role_name);
73
74    role->string = abac_xmalloc(prin_len + 1 + role_len + 1);
75    memcpy(role->string, principal, prin_len);
76    role->string[prin_len] = '.';
77    memcpy(role->string + prin_len + 1, role_name, role_len);
78    role->string[prin_len + 1 + role_len] = 0;
79    role->short_string = NULL;
80
81    role->linked = NULL;
82    role->prereqs = NULL;
83
84    role->refcount = 1;
85
86    return role;
87}
88
89/**
90 * Created a new linking role and initialize it.
91 */
92abac_role_t *abac_role_linking_new(char *principal, char *linked, char *role_name) {
93    assert(principal != NULL);
94    assert(linked != NULL);
95    assert(role_name != NULL);
96
97    abac_role_t *role;
98
99    if (strlen(principal) == 0 || strlen(linked) == 0 || strlen(role_name) == 0)
100        return NULL;
101
102    role = abac_xmalloc(sizeof(abac_role_t));
103
104    role->principal = abac_xstrdup(principal);
105    role->linked_role = abac_xstrdup(linked);
106    role->role_name = abac_xstrdup(role_name);
107
108    int prin_len = strlen(principal);
109    int link_len = strlen(linked);
110    int role_len = strlen(role_name);
111
112    role->string = abac_xmalloc(prin_len + 1 + link_len + 1 + role_len + 1);
113
114    memcpy(role->string, principal, prin_len);
115    role->string[prin_len] = '.';
116    memcpy(role->string + prin_len + 1, linked, link_len);
117    role->string[prin_len + 1 + link_len] = 0;
118
119    // hack: linked role is first two parts of full string
120    role->linked = abac_xstrdup(role->string);
121
122    role->string[prin_len + 1 + link_len] = '.';
123    memcpy(role->string + prin_len + 1 + link_len + 1, role_name, role_len);
124    role->string[prin_len + 1 + link_len + 1 + role_len] = 0;
125    role->short_string = NULL;
126
127    role->prereqs = NULL;
128
129    role->refcount = 1;
130
131    return role;
132}
133
134/**
135 * Create an intersection role.
136 */
137abac_role_t *abac_role_intersection_new(char *name, abac_list_t *prereqs) {
138    abac_role_t *role = abac_xmalloc(sizeof(abac_role_t));
139
140    role->principal = role->linked_role = role->role_name = NULL;
141    role->linked = NULL;
142
143    role->string = abac_xstrdup(name);
144    role->prereqs = prereqs;
145    role->short_string = NULL;
146
147    role->refcount = 1;
148
149    return role;
150}
151
152/**
153 * Decrease a role's reference count, freeing it when it reaches 0.
154 */
155void abac_role_free(abac_role_t *role) {
156    if (role == NULL)
157        return;
158
159    --role->refcount;
160    if (role->refcount > 0)
161        return;
162
163    free(role->principal);
164    free(role->linked_role);
165    free(role->role_name);
166
167    free(role->string);
168    free(role->linked);
169
170    if (role->prereqs != NULL) {
171        abac_role_t *cur;
172        abac_list_foreach(role->prereqs, cur,
173            abac_role_free(cur);
174        );
175        abac_list_free(role->prereqs);
176    }
177
178    if ( role->short_string) 
179        free(role->short_string);
180    free(role);
181}
182
183/**
184 * Create a non-intersecting role from a string. Handles principals, roles,
185 * and linking roles.
186 */
187static abac_role_t *_abac_single_role_from_string(char *string) {
188    int num_dots = 0;
189    char *dot = string;
190    abac_role_t *ret = NULL;
191
192    // count the dots
193    while ((dot = strchr(dot, '.')) != NULL) {
194        ++num_dots;
195        ++dot;
196    }
197
198    // no dots: easy case, principal
199    if (num_dots == 0)
200        ret = abac_role_principal_new(string);
201
202    // a role has exactly 1 dot
203    else if (num_dots == 1) {
204        char *principal = string;
205
206        // terminate the principal part
207        dot = strchr(principal, '.');
208        *dot = 0;
209
210        // role name comes after the dot
211        char *role_name = dot + 1;
212
213        // create the role (if possible)
214        ret = abac_role_role_new(string, role_name);
215    }
216
217    // a linked role has 2 dots
218    else if (num_dots == 2) {
219        char *principal = string;
220
221        // terminate the principal part
222        dot = strchr(principal, '.');
223        *dot = 0;
224
225        // linked name is next, terminate it
226        char *linked = dot + 1;
227        dot = strchr(linked, '.');
228        *dot = 0;
229
230        // role name is last, already terminated
231        char *role_name = dot + 1;
232
233        ret = abac_role_linking_new(principal, linked, role_name);
234    }
235
236    // more than two dots: return NULL
237
238    return ret;
239}
240
241/**
242 * Create a role from a string. Handles intersecting and normal roles.
243 */
244abac_role_t *abac_role_from_string(char *string) {
245    abac_list_t *prereqs = NULL;
246    abac_role_t *ret = NULL, *role;
247    char *roles[256];
248    int num_roles, i;
249
250    char *original = string;
251
252    // make a copy so we can mess with it
253    string = abac_xstrdup(string);
254
255    // split the string (in case of an intersection num_roles > 1)
256    num_roles = 256;
257    abac_split(string, " & ", roles, &num_roles);
258
259    // normal role:
260    if (num_roles == 1)
261        ret = _abac_single_role_from_string(string);
262
263    else {
264        prereqs = abac_list_new();
265
266        for (i = 0; i < num_roles; ++i) {
267            // make sure the tail role is valid
268            role = abac_role_from_string(roles[i]);
269            if (role == NULL)
270                goto error;
271
272            abac_list_add(prereqs, role);
273        }
274
275        ret = abac_role_intersection_new(original, prereqs);
276    }
277
278    free(string);
279    return ret;
280
281error:
282    if (prereqs != NULL) {
283        abac_list_foreach(prereqs, role,
284            abac_role_free(role);
285        );
286        abac_list_free(prereqs);
287    }
288    free(string);
289
290    return NULL;
291}
292
293
294/**
295 * Increase a role's reference count.
296 */
297abac_role_t *abac_role_dup(abac_role_t *role) {
298    assert(role != NULL);
299
300    ++role->refcount;
301    return role;
302}
303
304/**
305 * True if a role is a principal.
306 */
307int abac_role_is_principal(abac_role_t *role) {
308    assert(role != NULL);
309    return role->role_name == NULL && role->linked_role == NULL && role->prereqs == NULL;
310}
311
312/**
313 * True if a role is a role.
314 */
315int abac_role_is_role(abac_role_t *role) {
316    assert(role != NULL);
317    return role->role_name != NULL && role->linked_role == NULL && role->prereqs == NULL; 
318}
319
320/**
321 * True if a role is a linked role.
322 */
323int abac_role_is_linking(abac_role_t *role) {
324    assert(role != NULL);
325    return role->linked_role != NULL;
326}
327
328/**
329 * True if a role is an intersection.
330 */
331int abac_role_is_intersection(abac_role_t *role) {
332    assert(role != NULL);
333    return role->prereqs != NULL;
334}
335
336/**
337 * Returns the string representation of the role.
338 */
339char *abac_role_string(abac_role_t *role) {
340    assert(role != NULL);
341    return role->string;
342}
343
344/**
345 * Returns the string representation of the role, with keyids converted to
346 * mnemonic names where possible.  The return value must *not* be freed.
347 */
348char *abac_role_short_string(abac_role_t *role, abac_context_t *ctxt) {
349    assert(role != NULL);
350    if (!ctxt) return role->string;
351    if ( role->short_string) 
352        free(role->short_string);
353    role->short_string = abac_context_expand_key(ctxt, role->string);
354    return role->short_string;
355}
356
357/**
358 * Returns the name of a role. If the role is A.r1 then return r1. If the role
359 * is A.r1.r2 then return r2.
360 */
361char *abac_role_role_name(abac_role_t *role) {
362    assert(role != NULL);
363    return role->role_name;
364}
365
366/**
367 * Returns the linked part of a linking role. For instance, if the role is
368 * A.r1.r2, this returns A.r1.
369 */
370char *abac_role_linked_role(abac_role_t *role) {
371    assert(role != NULL);
372    return role->linked;
373}
374
375/**
376 * Returns the linkinged part of a linking role. For instance, if the role is
377 * A.r1.r2, this returns r1.
378 */
379char *abac_role_linking_role(abac_role_t *role) {
380    assert(role != NULL);
381    return role->linked_role;
382}
383
384/**
385 * Returns the principal part of a role. The stuff before the first dot.
386 */
387char *abac_role_principal(abac_role_t *role) {
388    assert(role != NULL);
389    return role->principal;
390}
391
392/**
393 * Returns the prereqs of an intersection.
394 */
395abac_list_t *abac_role_prereqs(abac_role_t *role) {
396    assert(role != NULL);
397    return role->prereqs;
398}
399
400/**
401 * Build an attribute key from head and tail roles. Static.
402 */
403#define ROLE_SEPARATOR " <- "
404char *abac_role_attr_key(abac_role_t *head_role, abac_role_t *tail_role) {
405    char *head = abac_role_string(head_role);
406    int head_len = strlen(head);
407
408    char *tail = abac_role_string(tail_role);
409    int tail_len = strlen(tail);
410
411    int sep_len = sizeof(ROLE_SEPARATOR) - 1;
412
413    // "head <- tail"
414    char *ret = abac_xmalloc(head_len + tail_len + sep_len + 1);
415    memcpy(ret, head, head_len);
416    memcpy(ret + head_len, ROLE_SEPARATOR, sep_len);
417    memcpy(ret + head_len + sep_len, tail, tail_len);
418    ret[head_len + sep_len + tail_len] = 0;
419
420    return ret;
421}
Note: See TracBrowser for help on using the repository browser.