| #include <stdio.h> |
| #include "mls_level.h" |
| #include <sepol/policydb/ebitmap.h> |
| |
| mls_level_t *mls_level_from_string(char *mls_context) |
| { |
| char delim; |
| char *scontextp, *p, *lptr; |
| mls_level_t *l; |
| |
| if (!mls_context) { |
| return NULL; |
| } |
| |
| l = (mls_level_t *) calloc(1, sizeof(mls_level_t)); |
| |
| /* Extract low sensitivity. */ |
| scontextp = p = mls_context; |
| while (*p && *p != ':' && *p != '-') |
| p++; |
| |
| delim = *p; |
| if (delim != 0) |
| *p++ = 0; |
| |
| if (*scontextp != 's') |
| goto err; |
| l->sens = atoi(scontextp + 1); |
| |
| if (delim == ':') { |
| /* Extract category set. */ |
| while (1) { |
| scontextp = p; |
| while (*p && *p != ',' && *p != '-') |
| p++; |
| delim = *p; |
| if (delim != 0) |
| *p++ = 0; |
| |
| /* Separate into level if exists */ |
| if ((lptr = strchr(scontextp, '.')) != NULL) { |
| /* Remove '.' */ |
| *lptr++ = 0; |
| } |
| |
| if (*scontextp != 'c') |
| goto err; |
| int bit = atoi(scontextp + 1); |
| if (ebitmap_set_bit(&l->cat, bit, 1)) |
| goto err; |
| |
| /* If level, set all categories in level */ |
| if (lptr) { |
| if (*lptr != 'c') |
| goto err; |
| int ubit = atoi(lptr + 1); |
| int i; |
| for (i = bit + 1; i <= ubit; i++) { |
| if (ebitmap_set_bit |
| (&l->cat, i, 1)) |
| goto err; |
| } |
| } |
| |
| if (delim != ',') |
| break; |
| } |
| } |
| |
| return l; |
| |
| err: |
| free(l); |
| return NULL; |
| } |
| |
| /* |
| * Return the length in bytes for the MLS fields of the |
| * security context string representation of `context'. |
| */ |
| unsigned int mls_compute_string_len(mls_level_t *l) |
| { |
| unsigned int len = 0; |
| char temp[16]; |
| unsigned int i, level = 0; |
| ebitmap_node_t *cnode; |
| |
| if (!l) |
| return 0; |
| |
| len += snprintf(temp, sizeof(temp), "s%d", l->sens); |
| |
| ebitmap_for_each_bit(&l->cat, cnode, i) { |
| if (ebitmap_node_get_bit(cnode, i)) { |
| if (level) { |
| level++; |
| continue; |
| } |
| |
| len++; /* : or ,` */ |
| |
| len += snprintf(temp, sizeof(temp), "c%d", i); |
| level++; |
| } else { |
| if (level > 1) |
| len += snprintf(temp, sizeof(temp), ".c%d", i-1); |
| level = 0; |
| } |
| } |
| |
| /* Handle case where last category is the end of level */ |
| if (level > 1) |
| len += snprintf(temp, sizeof(temp), ".c%d", i-1); |
| return len; |
| } |
| |
| char *mls_level_to_string(mls_level_t *l) |
| { |
| unsigned int wrote_sep, len = mls_compute_string_len(l); |
| unsigned int i, level = 0; |
| ebitmap_node_t *cnode; |
| wrote_sep = 0; |
| |
| if (len == 0) |
| return NULL; |
| char *result = (char *)malloc(len + 1); |
| char *p = result; |
| |
| p += sprintf(p, "s%d", l->sens); |
| |
| /* categories */ |
| ebitmap_for_each_bit(&l->cat, cnode, i) { |
| if (ebitmap_node_get_bit(cnode, i)) { |
| if (level) { |
| level++; |
| continue; |
| } |
| |
| if (!wrote_sep) { |
| *p++ = ':'; |
| wrote_sep = 1; |
| } else |
| *p++ = ','; |
| p += sprintf(p, "c%d", i); |
| level++; |
| } else { |
| if (level > 1) { |
| if (level > 2) |
| *p++ = '.'; |
| else |
| *p++ = ','; |
| |
| p += sprintf(p, "c%d", i-1); |
| } |
| level = 0; |
| } |
| } |
| /* Handle case where last category is the end of level */ |
| if (level > 1) { |
| if (level > 2) |
| *p++ = '.'; |
| else |
| *p++ = ','; |
| |
| p += sprintf(p, "c%d", i-1); |
| } |
| |
| *(result + len) = 0; |
| return result; |
| } |