00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <config.h>
00027
00028 #include <apol/util.h>
00029
00030 #include <assert.h>
00031 #include <ctype.h>
00032 #include <errno.h>
00033 #include <stdio.h>
00034 #include <string.h>
00035 #include <unistd.h>
00036 #include <stdbool.h>
00037
00038
00039 #include <qpol/nodecon_query.h>
00040 #include <sys/types.h>
00041 #include <sys/socket.h>
00042 #include <arpa/inet.h>
00043 #include <netinet/in.h>
00044
00045
00046 #define APOL_LINE_SZ 8192
00047 #define APOL_ENVIRON_VAR_NAME "APOL_INSTALL_DIR"
00048
00049 const char *libapol_get_version(void)
00050 {
00051 return LIBAPOL_VERSION_STRING;
00052 }
00053
00054 int apol_str_to_internal_ip(const char *str, uint32_t ip[4])
00055 {
00056 bool ipv4 = false;
00057 bool ipv6 = false;
00058
00059 if (!str || !ip) {
00060 errno = EINVAL;
00061 return -1;
00062 }
00063
00064 ip[0] = ip[1] = ip[2] = ip[3] = 0;
00065
00066 if (strchr(str, '.'))
00067 ipv4 = true;
00068
00069 if (strchr(str, ':'))
00070 ipv6 = true;
00071
00072 if (ipv4 == ipv6) {
00073 errno = EINVAL;
00074 return -1;
00075 }
00076
00077 if (ipv4) {
00078 unsigned char *p = (unsigned char *)&(ip[0]);
00079 int seg = 0;
00080 uint32_t val = 0;
00081 size_t len = strlen(str), i;
00082 for (i = 0; i <= len; i++) {
00083 if (str[i] == '.' || str[i] == '\0') {
00084 if (val > 255) {
00085 errno = EINVAL;
00086 return -1;
00087 }
00088
00089 p[seg] = (unsigned char)(0xff & val);
00090 seg++;
00091 val = 0;
00092 if (seg == 4)
00093 break;
00094 } else if (isdigit(str[i])) {
00095 char tmp[2] = { str[i], 0 };
00096 val = val * 10 + atoi(tmp);
00097 } else {
00098 errno = EINVAL;
00099 return -1;
00100 }
00101 }
00102 } else {
00103 struct in6_addr addr;
00104 if (inet_pton(AF_INET6, str, &addr) <= 0) {
00105 return -1;
00106 }
00107 memcpy(ip, addr.s6_addr32, 16);
00108 }
00109
00110 return ipv4 ? QPOL_IPV4 : QPOL_IPV6;
00111 }
00112
00113 const char *apol_objclass_to_str(uint32_t objclass)
00114 {
00115 switch (objclass) {
00116 case QPOL_CLASS_BLK_FILE:
00117 return "block";
00118 case QPOL_CLASS_CHR_FILE:
00119 return "char";
00120 case QPOL_CLASS_DIR:
00121 return "dir";
00122 case QPOL_CLASS_FIFO_FILE:
00123 return "fifo";
00124 case QPOL_CLASS_FILE:
00125 return "file";
00126 case QPOL_CLASS_LNK_FILE:
00127 return "link";
00128 case QPOL_CLASS_SOCK_FILE:
00129 return "sock";
00130 case QPOL_CLASS_ALL:
00131 return "any";
00132 }
00133 return NULL;
00134 }
00135
00136 uint32_t apol_str_to_objclass(const char *objclass)
00137 {
00138 if (objclass == NULL) {
00139 errno = EINVAL;
00140 return 0;
00141 }
00142 if (strcmp(objclass, "block") == 0) {
00143 return QPOL_CLASS_BLK_FILE;
00144 }
00145 if (strcmp(objclass, "char") == 0) {
00146 return QPOL_CLASS_CHR_FILE;
00147 }
00148 if (strcmp(objclass, "dir") == 0) {
00149 return QPOL_CLASS_DIR;
00150 }
00151 if (strcmp(objclass, "fifo") == 0) {
00152 return QPOL_CLASS_FIFO_FILE;
00153 }
00154 if (strcmp(objclass, "file") == 0) {
00155 return QPOL_CLASS_FILE;
00156 }
00157 if (strcmp(objclass, "link") == 0) {
00158 return QPOL_CLASS_LNK_FILE;
00159 }
00160 if (strcmp(objclass, "sock") == 0) {
00161 return QPOL_CLASS_SOCK_FILE;
00162 }
00163 if (strcmp(objclass, "any") == 0) {
00164 return QPOL_CLASS_ALL;
00165 }
00166 return 0;
00167 }
00168
00169 const char *apol_protocol_to_str(uint8_t protocol)
00170 {
00171 switch (protocol) {
00172 case IPPROTO_TCP:
00173 return "tcp";
00174 case IPPROTO_UDP:
00175 return "udp";
00176 default:
00177 errno = EPROTONOSUPPORT;
00178 return NULL;
00179 }
00180 }
00181
00182 uint8_t apol_str_to_protocol(const char *protocol_str)
00183 {
00184 if (protocol_str == NULL) {
00185 errno = EINVAL;
00186 return 0;
00187 }
00188 if (strcmp(protocol_str, "tcp") == 0 || strcmp(protocol_str, "TCP") == 0) {
00189 return IPPROTO_TCP;
00190 }
00191 if (strcmp(protocol_str, "udp") == 0 || strcmp(protocol_str, "UDP") == 0) {
00192 return IPPROTO_UDP;
00193 }
00194 errno = EPROTONOSUPPORT;
00195 return 0;
00196 }
00197
00198 const char *apol_fs_use_behavior_to_str(uint32_t behavior)
00199 {
00200 switch (behavior) {
00201 case QPOL_FS_USE_XATTR:
00202 return "fs_use_xattr";
00203 case QPOL_FS_USE_TASK:
00204 return "fs_use_task";
00205 case QPOL_FS_USE_TRANS:
00206 return "fs_use_trans";
00207 case QPOL_FS_USE_GENFS:
00208 return "fs_use_genfs";
00209 case QPOL_FS_USE_NONE:
00210 return "fs_use_none";
00211 case QPOL_FS_USE_PSID:
00212 return "fs_use_psid";
00213 }
00214 return NULL;
00215 }
00216
00217 int apol_str_to_fs_use_behavior(const char *behavior)
00218 {
00219 if (strcmp(behavior, "fs_use_xattr") == 0) {
00220 return QPOL_FS_USE_XATTR;
00221 } else if (strcmp(behavior, "fs_use_task") == 0) {
00222 return QPOL_FS_USE_TASK;
00223 } else if (strcmp(behavior, "fs_use_trans") == 0) {
00224 return QPOL_FS_USE_TRANS;
00225 } else if (strcmp(behavior, "fs_use_genfs") == 0) {
00226 return QPOL_FS_USE_GENFS;
00227 } else if (strcmp(behavior, "fs_use_none") == 0) {
00228 return QPOL_FS_USE_NONE;
00229 } else if (strcmp(behavior, "fs_use_psid") == 0) {
00230 return QPOL_FS_USE_PSID;
00231 }
00232 return -1;
00233 }
00234
00235 const char *apol_rule_type_to_str(uint32_t rule_type)
00236 {
00237 switch (rule_type) {
00238 case QPOL_RULE_ALLOW:
00239 return "allow";
00240 case QPOL_RULE_NEVERALLOW:
00241 return "neverallow";
00242 case QPOL_RULE_AUDITALLOW:
00243 return "auditallow";
00244 case QPOL_RULE_DONTAUDIT:
00245 return "dontaudit";
00246 case QPOL_RULE_TYPE_TRANS:
00247 return "type_transition";
00248 case QPOL_RULE_TYPE_CHANGE:
00249 return "type_change";
00250 case QPOL_RULE_TYPE_MEMBER:
00251 return "type_member";
00252 }
00253 return NULL;
00254 }
00255
00256 const char *apol_cond_expr_type_to_str(uint32_t expr_type)
00257 {
00258 switch (expr_type) {
00259 case QPOL_COND_EXPR_BOOL:
00260 return "";
00261 case QPOL_COND_EXPR_NOT:
00262 return "!";
00263 case QPOL_COND_EXPR_OR:
00264 return "||";
00265 case QPOL_COND_EXPR_AND:
00266 return "&&";
00267 case QPOL_COND_EXPR_XOR:
00268 return "^";
00269 case QPOL_COND_EXPR_EQ:
00270 return "==";
00271 case QPOL_COND_EXPR_NEQ:
00272 return "!=";
00273 }
00274 return NULL;
00275 }
00276
00277 char *apol_file_find(const char *file_name)
00278 {
00279 char *file = NULL, *var = NULL, *dirs[3];
00280 size_t i;
00281 int rt;
00282
00283 if (file_name == NULL) {
00284 errno = EINVAL;
00285 return NULL;
00286 }
00287
00288
00289
00290 dirs[0] = ".";
00291 dirs[1] = getenv(APOL_ENVIRON_VAR_NAME);
00292 dirs[2] = APOL_INSTALL_DIR;
00293 for (i = 0; i < 3; i++) {
00294 if ((var = dirs[i]) != NULL) {
00295 if (asprintf(&file, "%s/%s", var, file_name) < 0) {
00296 return NULL;
00297 }
00298 rt = access(file, R_OK);
00299 free(file);
00300 if (rt == 0) {
00301 return strdup(var);
00302 }
00303 }
00304 }
00305
00306
00307 return NULL;
00308 }
00309
00310 char *apol_file_find_path(const char *file_name)
00311 {
00312 char *file = NULL, *var = NULL, *dirs[3];
00313 size_t i;
00314 int rt;
00315
00316 if (file_name == NULL) {
00317 errno = EINVAL;
00318 return NULL;
00319 }
00320
00321
00322
00323 dirs[0] = ".";
00324 dirs[1] = getenv(APOL_ENVIRON_VAR_NAME);
00325 dirs[2] = APOL_INSTALL_DIR;
00326 for (i = 0; i < 3; i++) {
00327 if ((var = dirs[i]) != NULL) {
00328 if (asprintf(&file, "%s/%s", var, file_name) < 0) {
00329 return NULL;
00330 }
00331 rt = access(file, R_OK);
00332 if (rt == 0) {
00333 return file;
00334 }
00335 free(file);
00336 }
00337 }
00338
00339
00340 return NULL;
00341 }
00342
00343 char *apol_file_find_user_config(const char *file_name)
00344 {
00345 char *file, *var;
00346 int rt;
00347
00348 if (file_name == NULL) {
00349 errno = EINVAL;
00350 return NULL;
00351 }
00352 var = getenv("HOME");
00353 if (var) {
00354 if (asprintf(&file, "%s/%s", var, file_name) < 0) {
00355 return NULL;
00356 }
00357 rt = access(file, R_OK);
00358 if (rt == 0) {
00359 return file;
00360 } else {
00361 free(file);
00362 return NULL;
00363 }
00364 }
00365 return NULL;
00366 }
00367
00368 int apol_file_read_to_buffer(const char *fname, char **buf, size_t * len)
00369 {
00370 FILE *file = NULL;
00371 const size_t BUF_SIZE = 1024;
00372 size_t size = 0, r;
00373 char *bufp, *b;
00374
00375 assert(*buf == NULL);
00376 assert(len);
00377 *len = 0;
00378 while (1) {
00379 size += BUF_SIZE;
00380 r = 0;
00381 b = (char *)realloc(*buf, size * sizeof(char));
00382 if (b == NULL) {
00383 free(*buf);
00384 *buf = NULL;
00385 *len = 0;
00386 if (file)
00387 fclose(file);
00388 return -1;
00389 }
00390 *buf = b;
00391 if (!file) {
00392 file = fopen(fname, "rb");
00393 if (!file) {
00394 free(*buf);
00395 *buf = NULL;
00396 *len = 0;
00397 return -1;
00398 }
00399 }
00400 bufp = &((*buf)[size - BUF_SIZE]);
00401 r = fread(bufp, sizeof(char), BUF_SIZE, file);
00402 *len += r;
00403 if (r < BUF_SIZE) {
00404 if (feof(file)) {
00405 fclose(file);
00406 break;
00407 } else {
00408 free(*buf);
00409 *buf = NULL;
00410 *len = 0;
00411 fclose(file);
00412 return -1;
00413 }
00414 }
00415 }
00416 return 0;
00417 }
00418
00419 char *apol_config_get_var(const char *var, FILE * fp)
00420 {
00421 char line[APOL_LINE_SZ], t1[APOL_LINE_SZ], t2[APOL_LINE_SZ];
00422 char *line_ptr = NULL;
00423
00424 if (var == NULL || fp == NULL) {
00425 errno = EINVAL;
00426 return NULL;
00427 }
00428
00429 rewind(fp);
00430 while (fgets(line, APOL_LINE_SZ, fp) != NULL) {
00431 if ((line_ptr = strdup(line)) == NULL) {
00432 return NULL;
00433 }
00434 apol_str_trim(line_ptr);
00435 if (line_ptr[0] == '#' || sscanf(line_ptr, "%s %[^\n]", t1, t2) != 2 || strcasecmp(var, t1) != 0) {
00436 free(line_ptr);
00437 continue;
00438 } else {
00439 free(line_ptr);
00440 return strdup(t2);
00441 }
00442 }
00443 return NULL;
00444 }
00445
00446 apol_vector_t *apol_str_split(const char *s, const char *delim)
00447 {
00448 char *orig_s = NULL, *dup_s = NULL, *v, *token;
00449 apol_vector_t *list = NULL;
00450 int error = 0;
00451
00452 if (s == NULL || delim == NULL) {
00453 error = EINVAL;
00454 goto cleanup;
00455 }
00456 if ((list = apol_vector_create(free)) == NULL || (orig_s = strdup(s)) == NULL) {
00457 error = errno;
00458 goto cleanup;
00459 }
00460 v = orig_s;
00461 while ((token = strsep(&v, delim)) != NULL) {
00462 if (strcmp(token, "") != 0 && !apol_str_is_only_white_space(token)) {
00463 if ((dup_s = strdup(token)) == NULL || apol_vector_append(list, dup_s) < 0) {
00464 error = errno;
00465 free(dup_s);
00466 goto cleanup;
00467 }
00468 }
00469 }
00470 cleanup:
00471 free(orig_s);
00472 if (error != 0) {
00473 apol_vector_destroy(&list);
00474 errno = error;
00475 return NULL;
00476 }
00477 return list;
00478 }
00479
00480 char *apol_str_join(const apol_vector_t * list, const char *delim)
00481 {
00482 char *val, *s;
00483 size_t i, len;
00484
00485 if (list == NULL || delim == NULL) {
00486 errno = EINVAL;
00487 return NULL;
00488 }
00489 if (apol_vector_get_size(list) == 0) {
00490 return strdup("");
00491 }
00492 s = apol_vector_get_element(list, 0);
00493 if ((val = strdup(s)) == NULL) {
00494 return NULL;
00495 }
00496 len = strlen(val) + 1;
00497 for (i = 1; i < apol_vector_get_size(list); i++) {
00498 s = apol_vector_get_element(list, i);
00499 if (apol_str_appendf(&val, &len, "%s%s", delim, s) < 0) {
00500 return NULL;
00501 }
00502 }
00503 return val;
00504 }
00505
00506
00507
00508
00509
00510
00511
00512 static void trim_leading_whitespace(char *str)
00513 {
00514 size_t i, len;
00515 for (i = 0; str[i] != '\0' && isspace(str[i]); i++) ;
00516 len = strlen(str + i);
00517 memmove(str, str + i, len + 1);
00518 }
00519
00520
00521
00522
00523
00524
00525
00526 static void trim_trailing_whitespace(char *str)
00527 {
00528 size_t length;
00529 length = strlen(str);
00530 while (length > 0 && isspace(str[length - 1])) {
00531 str[length - 1] = '\0';
00532 length--;
00533 }
00534 }
00535
00536 void apol_str_trim(char *str)
00537 {
00538 if (str == NULL) {
00539 errno = EINVAL;
00540 return;
00541 }
00542 trim_leading_whitespace(str);
00543 trim_trailing_whitespace(str);
00544 }
00545
00546 int apol_str_append(char **tgt, size_t * tgt_sz, const char *str)
00547 {
00548 size_t str_len;
00549 if (str == NULL || (str_len = strlen(str)) == 0)
00550 return 0;
00551 if (tgt == NULL) {
00552 errno = EINVAL;
00553 return -1;
00554 }
00555 str_len++;
00556
00557 if (*tgt == NULL || *tgt_sz == 0) {
00558 *tgt = (char *)malloc(str_len);
00559 if (*tgt == NULL) {
00560 *tgt_sz = 0;
00561 return -1;
00562 }
00563 *tgt_sz = str_len;
00564 strcpy(*tgt, str);
00565 return 0;
00566 } else {
00567
00568 char *t = (char *)realloc(*tgt, *tgt_sz + str_len);
00569 if (t == NULL) {
00570 int error = errno;
00571 free(*tgt);
00572 *tgt = NULL;
00573 *tgt_sz = 0;
00574 errno = error;
00575 return -1;
00576 }
00577 *tgt = t;
00578 *tgt_sz += str_len;
00579 strcat(*tgt, str);
00580 return 0;
00581 }
00582 }
00583
00584 int apol_str_appendf(char **tgt, size_t * tgt_sz, const char *fmt, ...)
00585 {
00586 va_list ap;
00587 int error;
00588 if (fmt == NULL || strlen(fmt) == 0)
00589 return 0;
00590 if (tgt == NULL) {
00591 errno = EINVAL;
00592 return -1;
00593 }
00594 va_start(ap, fmt);
00595
00596 if (*tgt == NULL || *tgt_sz == 0) {
00597 if (vasprintf(tgt, fmt, ap) < 0) {
00598 error = errno;
00599 *tgt = NULL;
00600 *tgt_sz = 0;
00601 va_end(ap);
00602 errno = error;
00603 return -1;
00604 }
00605 *tgt_sz = strlen(*tgt) + 1;
00606 va_end(ap);
00607 return 0;
00608 } else {
00609
00610 char *t, *u;
00611 size_t str_len;
00612 if (vasprintf(&t, fmt, ap) < 0) {
00613 error = errno;
00614 free(*tgt);
00615 *tgt_sz = 0;
00616 va_end(ap);
00617 errno = error;
00618 return -1;
00619 }
00620 va_end(ap);
00621 str_len = strlen(t);
00622 if ((u = (char *)realloc(*tgt, *tgt_sz + str_len)) == NULL) {
00623 error = errno;
00624 free(t);
00625 free(*tgt);
00626 *tgt_sz = 0;
00627 errno = error;
00628 return -1;
00629 }
00630 *tgt = u;
00631 *tgt_sz += str_len;
00632 strcat(*tgt, t);
00633 free(t);
00634 return 0;
00635 }
00636 }
00637
00638 int apol_str_is_only_white_space(const char *str)
00639 {
00640 size_t len, i;
00641 if (str == NULL)
00642 return 0;
00643 len = strlen(str);
00644 for (i = 0; i < len; i++) {
00645 if (!isspace(str[i]))
00646 return 0;
00647 }
00648 return 1;
00649 }
00650
00651 int apol_str_strcmp(const void *a, const void *b, void *unused __attribute__ ((unused)))
00652 {
00653 return strcmp((const char *)a, (const char *)b);
00654 }
00655
00656 void *apol_str_strdup(const void *elem, void *unused __attribute__ ((unused)))
00657 {
00658 return strdup((const char *)elem);
00659 }