source: libabac/abac_role.c @ b73c5d05

abac0-leakabac0-meimei-idtvf-new-xml
Last change on this file since b73c5d05 was 9a411d7, checked in by Mike Ryan <mikeryan@…>, 14 years ago

fold intersection into ordinary role object

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