[7f25a67f] | 1 | #include <assert.h> |
---|
| 2 | #include <stdlib.h> |
---|
| 3 | #include <stdio.h> |
---|
| 4 | #include <string.h> |
---|
| 5 | |
---|
[0bf0e67] | 6 | #include "abac.h" |
---|
[9a411d7] | 7 | #include "abac_list.h" |
---|
[3c251d0] | 8 | #include "abac_util.h" |
---|
[7f25a67f] | 9 | |
---|
| 10 | // typedef'd in role.h |
---|
[1743825] | 11 | struct _abac_role_t { |
---|
[7f25a67f] | 12 | char *principal; |
---|
| 13 | char *linked_role; |
---|
[9a411d7] | 14 | char *role_name; |
---|
[7e05a2f] | 15 | |
---|
| 16 | char *string; |
---|
[d4cbf71] | 17 | char *linked; |
---|
[94605f2] | 18 | /* Copy of the last string printed with abac_role_short_string */ |
---|
| 19 | char *short_string; |
---|
[fbb591e] | 20 | |
---|
[9a411d7] | 21 | abac_list_t *prereqs; |
---|
| 22 | |
---|
[fbb591e] | 23 | int refcount; |
---|
[7f25a67f] | 24 | }; |
---|
| 25 | |
---|
| 26 | /** |
---|
| 27 | * Create a new principal and initialize it. |
---|
| 28 | */ |
---|
[dcc1a8e] | 29 | abac_role_t *abac_role_principal_new(char *principal) { |
---|
[7f25a67f] | 30 | assert(principal != NULL); |
---|
| 31 | |
---|
[1743825] | 32 | abac_role_t *role; |
---|
[7f25a67f] | 33 | |
---|
| 34 | if (strlen(principal) == 0) |
---|
| 35 | return NULL; |
---|
| 36 | |
---|
[3c251d0] | 37 | role = abac_xmalloc(sizeof(abac_role_t)); |
---|
[7f25a67f] | 38 | |
---|
[3c251d0] | 39 | role->principal = abac_xstrdup(principal); |
---|
[9a411d7] | 40 | role->role_name = NULL; |
---|
[7f25a67f] | 41 | role->linked_role = NULL; |
---|
| 42 | |
---|
[3c251d0] | 43 | role->string = abac_xstrdup(principal); |
---|
[94605f2] | 44 | role->short_string = NULL; |
---|
[d4cbf71] | 45 | role->linked = NULL; |
---|
[9a411d7] | 46 | role->prereqs = NULL; |
---|
[7e05a2f] | 47 | |
---|
[fbb591e] | 48 | role->refcount = 1; |
---|
| 49 | |
---|
[7f25a67f] | 50 | return role; |
---|
| 51 | } |
---|
| 52 | |
---|
| 53 | /** |
---|
| 54 | * Create a new role and initialize it. |
---|
| 55 | */ |
---|
[9a411d7] | 56 | abac_role_t *abac_role_role_new(char *principal, char *role_name) { |
---|
[7f25a67f] | 57 | assert(principal != NULL); |
---|
[9a411d7] | 58 | assert(role_name != NULL); |
---|
[7f25a67f] | 59 | |
---|
[1743825] | 60 | abac_role_t *role; |
---|
[7f25a67f] | 61 | |
---|
[9a411d7] | 62 | if (strlen(principal) == 0 || strlen(role_name) == 0) |
---|
[7f25a67f] | 63 | return NULL; |
---|
| 64 | |
---|
[3c251d0] | 65 | role = abac_xmalloc(sizeof(abac_role_t)); |
---|
[7f25a67f] | 66 | |
---|
[3c251d0] | 67 | role->principal = abac_xstrdup(principal); |
---|
[9a411d7] | 68 | role->role_name = abac_xstrdup(role_name); |
---|
[7f25a67f] | 69 | role->linked_role = NULL; |
---|
| 70 | |
---|
[7e05a2f] | 71 | int prin_len = strlen(principal); |
---|
[9a411d7] | 72 | int role_len = strlen(role_name); |
---|
[7e05a2f] | 73 | |
---|
[9a411d7] | 74 | role->string = abac_xmalloc(prin_len + 1 + role_len + 1); |
---|
[7e05a2f] | 75 | memcpy(role->string, principal, prin_len); |
---|
| 76 | role->string[prin_len] = '.'; |
---|
[9a411d7] | 77 | memcpy(role->string + prin_len + 1, role_name, role_len); |
---|
| 78 | role->string[prin_len + 1 + role_len] = 0; |
---|
[94605f2] | 79 | role->short_string = NULL; |
---|
[7e05a2f] | 80 | |
---|
[d4cbf71] | 81 | role->linked = NULL; |
---|
[9a411d7] | 82 | role->prereqs = NULL; |
---|
[d4cbf71] | 83 | |
---|
[fbb591e] | 84 | role->refcount = 1; |
---|
| 85 | |
---|
[7f25a67f] | 86 | return role; |
---|
| 87 | } |
---|
| 88 | |
---|
| 89 | /** |
---|
| 90 | * Created a new linking role and initialize it. |
---|
| 91 | */ |
---|
[9a411d7] | 92 | abac_role_t *abac_role_linking_new(char *principal, char *linked, char *role_name) { |
---|
[7f25a67f] | 93 | assert(principal != NULL); |
---|
| 94 | assert(linked != NULL); |
---|
[9a411d7] | 95 | assert(role_name != NULL); |
---|
[7f25a67f] | 96 | |
---|
[1743825] | 97 | abac_role_t *role; |
---|
[7f25a67f] | 98 | |
---|
[9a411d7] | 99 | if (strlen(principal) == 0 || strlen(linked) == 0 || strlen(role_name) == 0) |
---|
[7f25a67f] | 100 | return NULL; |
---|
| 101 | |
---|
[3c251d0] | 102 | role = abac_xmalloc(sizeof(abac_role_t)); |
---|
[7f25a67f] | 103 | |
---|
[3c251d0] | 104 | role->principal = abac_xstrdup(principal); |
---|
| 105 | role->linked_role = abac_xstrdup(linked); |
---|
[9a411d7] | 106 | role->role_name = abac_xstrdup(role_name); |
---|
[7f25a67f] | 107 | |
---|
[7e05a2f] | 108 | int prin_len = strlen(principal); |
---|
| 109 | int link_len = strlen(linked); |
---|
[9a411d7] | 110 | int role_len = strlen(role_name); |
---|
[7e05a2f] | 111 | |
---|
[9a411d7] | 112 | role->string = abac_xmalloc(prin_len + 1 + link_len + 1 + role_len + 1); |
---|
[7e05a2f] | 113 | |
---|
| 114 | memcpy(role->string, principal, prin_len); |
---|
| 115 | role->string[prin_len] = '.'; |
---|
| 116 | memcpy(role->string + prin_len + 1, linked, link_len); |
---|
[d4cbf71] | 117 | role->string[prin_len + 1 + link_len] = 0; |
---|
| 118 | |
---|
| 119 | // hack: linked role is first two parts of full string |
---|
[3c251d0] | 120 | role->linked = abac_xstrdup(role->string); |
---|
[d4cbf71] | 121 | |
---|
[7e05a2f] | 122 | role->string[prin_len + 1 + link_len] = '.'; |
---|
[9a411d7] | 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; |
---|
[94605f2] | 125 | role->short_string = NULL; |
---|
[9a411d7] | 126 | |
---|
| 127 | role->prereqs = NULL; |
---|
| 128 | |
---|
| 129 | role->refcount = 1; |
---|
| 130 | |
---|
| 131 | return role; |
---|
| 132 | } |
---|
| 133 | |
---|
| 134 | /** |
---|
| 135 | * Create an intersection role. |
---|
| 136 | */ |
---|
| 137 | abac_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; |
---|
[94605f2] | 145 | role->short_string = NULL; |
---|
[7e05a2f] | 146 | |
---|
[fbb591e] | 147 | role->refcount = 1; |
---|
| 148 | |
---|
[7f25a67f] | 149 | return role; |
---|
| 150 | } |
---|
| 151 | |
---|
[c66e07c] | 152 | /** |
---|
[fbb591e] | 153 | * Decrease a role's reference count, freeing it when it reaches 0. |
---|
[c66e07c] | 154 | */ |
---|
[dcc1a8e] | 155 | void abac_role_free(abac_role_t *role) { |
---|
[c66e07c] | 156 | if (role == NULL) |
---|
| 157 | return; |
---|
| 158 | |
---|
[fbb591e] | 159 | --role->refcount; |
---|
| 160 | if (role->refcount > 0) |
---|
| 161 | return; |
---|
| 162 | |
---|
[c66e07c] | 163 | free(role->principal); |
---|
| 164 | free(role->linked_role); |
---|
[9a411d7] | 165 | free(role->role_name); |
---|
[c66e07c] | 166 | |
---|
[7e05a2f] | 167 | free(role->string); |
---|
[be963dc] | 168 | free(role->linked); |
---|
[7e05a2f] | 169 | |
---|
[9a411d7] | 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 | |
---|
[94605f2] | 178 | if ( role->short_string) |
---|
| 179 | free(role->short_string); |
---|
[c66e07c] | 180 | free(role); |
---|
| 181 | } |
---|
| 182 | |
---|
[7f25a67f] | 183 | /** |
---|
[9a411d7] | 184 | * Create a non-intersecting role from a string. Handles principals, roles, |
---|
| 185 | * and linking roles. |
---|
[7f25a67f] | 186 | */ |
---|
[9a411d7] | 187 | static abac_role_t *_abac_single_role_from_string(char *string) { |
---|
[7f25a67f] | 188 | int num_dots = 0; |
---|
| 189 | char *dot = string; |
---|
[9a411d7] | 190 | abac_role_t *ret = NULL; |
---|
[7f25a67f] | 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) |
---|
[9a411d7] | 200 | ret = abac_role_principal_new(string); |
---|
[7f25a67f] | 201 | |
---|
| 202 | // a role has exactly 1 dot |
---|
[9a411d7] | 203 | else if (num_dots == 1) { |
---|
[7f25a67f] | 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 |
---|
[9a411d7] | 211 | char *role_name = dot + 1; |
---|
[7f25a67f] | 212 | |
---|
| 213 | // create the role (if possible) |
---|
[9a411d7] | 214 | ret = abac_role_role_new(string, role_name); |
---|
[7f25a67f] | 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 |
---|
[9a411d7] | 231 | char *role_name = dot + 1; |
---|
[7f25a67f] | 232 | |
---|
[9a411d7] | 233 | ret = abac_role_linking_new(principal, linked, role_name); |
---|
[7f25a67f] | 234 | } |
---|
| 235 | |
---|
| 236 | // more than two dots: return NULL |
---|
| 237 | |
---|
[9a411d7] | 238 | return ret; |
---|
| 239 | } |
---|
| 240 | |
---|
| 241 | /** |
---|
| 242 | * Create a role from a string. Handles intersecting and normal roles. |
---|
| 243 | */ |
---|
| 244 | abac_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) |
---|
[9f78e4c] | 256 | num_roles = 256; |
---|
[9a411d7] | 257 | abac_split(string, " & ", roles, &num_roles); |
---|
| 258 | |
---|
| 259 | // normal role: |
---|
| 260 | if (num_roles == 1) |
---|
| 261 | ret = _abac_single_role_from_string(string); |
---|
[7f25a67f] | 262 | |
---|
[9a411d7] | 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); |
---|
[7f25a67f] | 279 | return ret; |
---|
[9a411d7] | 280 | |
---|
| 281 | error: |
---|
| 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; |
---|
[7f25a67f] | 291 | } |
---|
| 292 | |
---|
[9a411d7] | 293 | |
---|
[ea401bc] | 294 | /** |
---|
[fbb591e] | 295 | * Increase a role's reference count. |
---|
[ea401bc] | 296 | */ |
---|
[dcc1a8e] | 297 | abac_role_t *abac_role_dup(abac_role_t *role) { |
---|
[fbb591e] | 298 | assert(role != NULL); |
---|
[ea401bc] | 299 | |
---|
[fbb591e] | 300 | ++role->refcount; |
---|
| 301 | return role; |
---|
[ea401bc] | 302 | } |
---|
| 303 | |
---|
[7f25a67f] | 304 | /** |
---|
| 305 | * True if a role is a principal. |
---|
| 306 | */ |
---|
[dcc1a8e] | 307 | int abac_role_is_principal(abac_role_t *role) { |
---|
[7f25a67f] | 308 | assert(role != NULL); |
---|
[9a411d7] | 309 | return role->role_name == NULL && role->linked_role == NULL && role->prereqs == NULL; |
---|
[7f25a67f] | 310 | } |
---|
| 311 | |
---|
| 312 | /** |
---|
| 313 | * True if a role is a role. |
---|
| 314 | */ |
---|
[dcc1a8e] | 315 | int abac_role_is_role(abac_role_t *role) { |
---|
[7f25a67f] | 316 | assert(role != NULL); |
---|
[9a411d7] | 317 | return role->role_name != NULL && role->linked_role == NULL && role->prereqs == NULL; |
---|
[7f25a67f] | 318 | } |
---|
| 319 | |
---|
| 320 | /** |
---|
| 321 | * True if a role is a linked role. |
---|
| 322 | */ |
---|
[dcc1a8e] | 323 | int abac_role_is_linking(abac_role_t *role) { |
---|
[7f25a67f] | 324 | assert(role != NULL); |
---|
| 325 | return role->linked_role != NULL; |
---|
| 326 | } |
---|
| 327 | |
---|
[9a411d7] | 328 | /** |
---|
| 329 | * True if a role is an intersection. |
---|
| 330 | */ |
---|
| 331 | int abac_role_is_intersection(abac_role_t *role) { |
---|
| 332 | assert(role != NULL); |
---|
| 333 | return role->prereqs != NULL; |
---|
| 334 | } |
---|
| 335 | |
---|
[7e05a2f] | 336 | /** |
---|
| 337 | * Returns the string representation of the role. |
---|
| 338 | */ |
---|
[dcc1a8e] | 339 | char *abac_role_string(abac_role_t *role) { |
---|
[7e05a2f] | 340 | assert(role != NULL); |
---|
| 341 | return role->string; |
---|
[7f25a67f] | 342 | } |
---|
[d4cbf71] | 343 | |
---|
[94605f2] | 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 | */ |
---|
| 348 | char *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 | |
---|
[ebde9dd] | 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 | */ |
---|
[dcc1a8e] | 361 | char *abac_role_role_name(abac_role_t *role) { |
---|
[ebde9dd] | 362 | assert(role != NULL); |
---|
[9a411d7] | 363 | return role->role_name; |
---|
[ebde9dd] | 364 | } |
---|
| 365 | |
---|
[d4cbf71] | 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 | */ |
---|
[dcc1a8e] | 370 | char *abac_role_linked_role(abac_role_t *role) { |
---|
[d4cbf71] | 371 | assert(role != NULL); |
---|
| 372 | return role->linked; |
---|
| 373 | } |
---|
[c03fe9b] | 374 | |
---|
[e50f807] | 375 | /** |
---|
| 376 | * Returns the linkinged part of a linking role. For instance, if the role is |
---|
| 377 | * A.r1.r2, this returns r1. |
---|
| 378 | */ |
---|
| 379 | char *abac_role_linking_role(abac_role_t *role) { |
---|
| 380 | assert(role != NULL); |
---|
| 381 | return role->linked_role; |
---|
| 382 | } |
---|
| 383 | |
---|
[c03fe9b] | 384 | /** |
---|
| 385 | * Returns the principal part of a role. The stuff before the first dot. |
---|
| 386 | */ |
---|
[dcc1a8e] | 387 | char *abac_role_principal(abac_role_t *role) { |
---|
[c03fe9b] | 388 | assert(role != NULL); |
---|
| 389 | return role->principal; |
---|
| 390 | } |
---|
[85f33fd] | 391 | |
---|
[9a411d7] | 392 | /** |
---|
| 393 | * Returns the prereqs of an intersection. |
---|
| 394 | */ |
---|
| 395 | abac_list_t *abac_role_prereqs(abac_role_t *role) { |
---|
| 396 | assert(role != NULL); |
---|
| 397 | return role->prereqs; |
---|
| 398 | } |
---|
| 399 | |
---|
[85f33fd] | 400 | /** |
---|
| 401 | * Build an attribute key from head and tail roles. Static. |
---|
| 402 | */ |
---|
| 403 | #define ROLE_SEPARATOR " <- " |
---|
[dcc1a8e] | 404 | char *abac_role_attr_key(abac_role_t *head_role, abac_role_t *tail_role) { |
---|
| 405 | char *head = abac_role_string(head_role); |
---|
[85f33fd] | 406 | int head_len = strlen(head); |
---|
| 407 | |
---|
[dcc1a8e] | 408 | char *tail = abac_role_string(tail_role); |
---|
[85f33fd] | 409 | int tail_len = strlen(tail); |
---|
| 410 | |
---|
| 411 | int sep_len = sizeof(ROLE_SEPARATOR) - 1; |
---|
| 412 | |
---|
| 413 | // "head <- tail" |
---|
[3c251d0] | 414 | char *ret = abac_xmalloc(head_len + tail_len + sep_len + 1); |
---|
[85f33fd] | 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 | } |
---|