source: libabac/abac_role.c @ 9f78e4c

abac0-leakabac0-meitvf-new-xml
Last change on this file since 9f78e4c was 9f78e4c, checked in by Ted Faber <faber@…>, 11 years ago

Modify abac_split to be more safe and callers of it to use the modified interface

  • 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    num_roles = 256;
249    abac_split(string, " & ", roles, &num_roles);
250
251    // normal role:
252    if (num_roles == 1)
253        ret = _abac_single_role_from_string(string);
254
255    else {
256        prereqs = abac_list_new();
257
258        for (i = 0; i < num_roles; ++i) {
259            // make sure the tail role is valid
260            role = abac_role_from_string(roles[i]);
261            if (role == NULL)
262                goto error;
263
264            abac_list_add(prereqs, role);
265        }
266
267        ret = abac_role_intersection_new(original, prereqs);
268    }
269
270    free(string);
271    return ret;
272
273error:
274    if (prereqs != NULL) {
275        abac_list_foreach(prereqs, role,
276            abac_role_free(role);
277        );
278        abac_list_free(prereqs);
279    }
280    free(string);
281
282    return NULL;
283}
284
285
286/**
287 * Increase a role's reference count.
288 */
289abac_role_t *abac_role_dup(abac_role_t *role) {
290    assert(role != NULL);
291
292    ++role->refcount;
293    return role;
294}
295
296/**
297 * True if a role is a principal.
298 */
299int abac_role_is_principal(abac_role_t *role) {
300    assert(role != NULL);
301    return role->role_name == NULL && role->linked_role == NULL && role->prereqs == NULL;
302}
303
304/**
305 * True if a role is a role.
306 */
307int abac_role_is_role(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 linked role.
314 */
315int abac_role_is_linking(abac_role_t *role) {
316    assert(role != NULL);
317    return role->linked_role != NULL;
318}
319
320/**
321 * True if a role is an intersection.
322 */
323int abac_role_is_intersection(abac_role_t *role) {
324    assert(role != NULL);
325    return role->prereqs != NULL;
326}
327
328/**
329 * Returns the string representation of the role.
330 */
331char *abac_role_string(abac_role_t *role) {
332    assert(role != NULL);
333    return role->string;
334}
335
336/**
337 * Returns the name of a role. If the role is A.r1 then return r1. If the role
338 * is A.r1.r2 then return r2.
339 */
340char *abac_role_role_name(abac_role_t *role) {
341    assert(role != NULL);
342    return role->role_name;
343}
344
345/**
346 * Returns the linked part of a linking role. For instance, if the role is
347 * A.r1.r2, this returns A.r1.
348 */
349char *abac_role_linked_role(abac_role_t *role) {
350    assert(role != NULL);
351    return role->linked;
352}
353
354/**
355 * Returns the principal part of a role. The stuff before the first dot.
356 */
357char *abac_role_principal(abac_role_t *role) {
358    assert(role != NULL);
359    return role->principal;
360}
361
362/**
363 * Returns the prereqs of an intersection.
364 */
365abac_list_t *abac_role_prereqs(abac_role_t *role) {
366    assert(role != NULL);
367    return role->prereqs;
368}
369
370/**
371 * Build an attribute key from head and tail roles. Static.
372 */
373#define ROLE_SEPARATOR " <- "
374char *abac_role_attr_key(abac_role_t *head_role, abac_role_t *tail_role) {
375    char *head = abac_role_string(head_role);
376    int head_len = strlen(head);
377
378    char *tail = abac_role_string(tail_role);
379    int tail_len = strlen(tail);
380
381    int sep_len = sizeof(ROLE_SEPARATOR) - 1;
382
383    // "head <- tail"
384    char *ret = abac_xmalloc(head_len + tail_len + sep_len + 1);
385    memcpy(ret, head, head_len);
386    memcpy(ret + head_len, ROLE_SEPARATOR, sep_len);
387    memcpy(ret + head_len + sep_len, tail, tail_len);
388    ret[head_len + sep_len + tail_len] = 0;
389
390    return ret;
391}
Note: See TracBrowser for help on using the repository browser.