source: libabac/abac_role.c @ b1bd0ff

0.1.7
Last change on this file since b1bd0ff was f2622ee, checked in by Mei-Hui Su <mei@…>, 11 years ago

1) ran with valgrind and did some leak patching

  • 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
203    // a role has exactly 1 dot
204    else if (num_dots == 1) {
205        char *principal = string;
206
207        // terminate the principal part
208        dot = strchr(principal, '.');
209        *dot = 0;
210
211        // role name comes after the dot
212        char *role_name = dot + 1;
213
214        // create the role (if possible)
215        ret = abac_role_role_new(string, role_name);
216    }
217
218    // a linked role has 2 dots
219    else if (num_dots == 2) {
220        char *principal = string;
221
222        // terminate the principal part
223        dot = strchr(principal, '.');
224        *dot = 0;
225
226        // linked name is next, terminate it
227        char *linked = dot + 1;
228        dot = strchr(linked, '.');
229        *dot = 0;
230
231        // role name is last, already terminated
232        char *role_name = dot + 1;
233
234        ret = abac_role_linking_new(principal, linked, role_name);
235    }
236
237    // more than two dots: return NULL
238
239    return ret;
240}
241
242/**
243 * Create a role from a string. Handles intersecting and normal roles.
244 */
245abac_role_t *abac_role_from_string(char *istring) {
246    abac_list_t *prereqs = NULL;
247    abac_role_t *ret = NULL, *role;
248    char *roles[256];
249    int num_roles, i;
250    char *string;
251
252    char *original = istring;
253
254    // make a copy so we can mess with it
255    string = abac_xstrdup(istring);
256
257    // split the string (in case of an intersection num_roles > 1)
258    num_roles = 256;
259    abac_split(string, " & ", roles, &num_roles);
260
261    // normal role:
262    if (num_roles == 1) {
263        ret = _abac_single_role_from_string(string);
264
265    } else {
266        prereqs = abac_list_new();
267
268        for (i = 0; i < num_roles; ++i) {
269            // make sure the tail role is valid
270            role = abac_role_from_string(roles[i]);
271            if (role == NULL)
272                goto error;
273
274            abac_list_add(prereqs, role);
275        }
276
277        ret = abac_role_intersection_new(original, prereqs);
278    }
279
280    free(string);
281    return ret;
282
283error:
284    if (prereqs != NULL) {
285        abac_list_foreach(prereqs, role,
286            abac_role_free(role);
287        );
288        abac_list_free(prereqs);
289    }
290    free(string);
291
292    return NULL;
293}
294
295
296/**
297 * Increase a role's reference count.
298 */
299abac_role_t *abac_role_dup(abac_role_t *role) {
300    assert(role != NULL);
301
302    ++role->refcount;
303    return role;
304}
305
306/**
307 * True if a role is a principal.
308 */
309int abac_role_is_principal(abac_role_t *role) {
310    assert(role != NULL);
311    return role->role_name == NULL && role->linked_role == NULL && role->prereqs == NULL;
312}
313
314/**
315 * True if a role is a role.
316 */
317int abac_role_is_role(abac_role_t *role) {
318    assert(role != NULL);
319    return role->role_name != NULL && role->linked_role == NULL && role->prereqs == NULL; 
320}
321
322/**
323 * True if a role is a linked role.
324 */
325int abac_role_is_linking(abac_role_t *role) {
326    assert(role != NULL);
327    return role->linked_role != NULL;
328}
329
330/**
331 * True if a role is an intersection.
332 */
333int abac_role_is_intersection(abac_role_t *role) {
334    assert(role != NULL);
335    return role->prereqs != NULL;
336}
337
338/**
339 * Returns the string representation of the role.
340 */
341char *abac_role_string(abac_role_t *role) {
342    assert(role != NULL);
343    return role->string;
344}
345
346/**
347 * Returns the string representation of the role, with keyids converted to
348 * mnemonic names where possible.  The return value must *not* be freed.
349 */
350char *abac_role_short_string(abac_role_t *role, abac_context_t *ctxt) {
351    assert(role != NULL);
352    if (!ctxt) return role->string;
353    if ( role->short_string) 
354        free(role->short_string);
355    role->short_string = abac_context_expand_key(ctxt, role->string);
356    return role->short_string;
357}
358
359/**
360 * Returns the name of a role. If the role is A.r1 then return r1. If the role
361 * is A.r1.r2 then return r2.
362 */
363char *abac_role_role_name(abac_role_t *role) {
364    assert(role != NULL);
365    return role->role_name;
366}
367
368/**
369 * Returns the linked part of a linking role. For instance, if the role is
370 * A.r1.r2, this returns A.r1.
371 */
372char *abac_role_linked_role(abac_role_t *role) {
373    assert(role != NULL);
374    return role->linked;
375}
376
377/**
378 * Returns the linkinged part of a linking role. For instance, if the role is
379 * A.r1.r2, this returns r1.
380 */
381char *abac_role_linking_role(abac_role_t *role) {
382    assert(role != NULL);
383    return role->linked_role;
384}
385
386/**
387 * Returns the principal part of a role. The stuff before the first dot.
388 */
389char *abac_role_principal(abac_role_t *role) {
390    assert(role != NULL);
391    return role->principal;
392}
393
394/**
395 * Returns the prereqs of an intersection.
396 */
397abac_list_t *abac_role_prereqs(abac_role_t *role) {
398    assert(role != NULL);
399    return role->prereqs;
400}
401
402/**
403 * Build an attribute key from head and tail roles. Static.
404 */
405#define ROLE_SEPARATOR " <- "
406char *abac_role_attr_key(abac_role_t *head_role, abac_role_t *tail_role) {
407    char *head = abac_role_string(head_role);
408    int head_len = strlen(head);
409
410    char *tail = abac_role_string(tail_role);
411    int tail_len = strlen(tail);
412
413    int sep_len = sizeof(ROLE_SEPARATOR) - 1;
414
415    // "head <- tail"
416    char *ret = abac_xmalloc(head_len + tail_len + sep_len + 1);
417    memcpy(ret, head, head_len);
418    memcpy(ret + head_len, ROLE_SEPARATOR, sep_len);
419    memcpy(ret + head_len + sep_len, tail, tail_len);
420    ret[head_len + sep_len + tail_len] = 0;
421
422    return ret;
423}
Note: See TracBrowser for help on using the repository browser.