util.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  *
00004  * Implementation of utility functions.
00005  *
00006  * @author Jeremy A. Mowery jmowery@tresys.com
00007  * @author Jason Tang  jtang@tresys.com
00008  *
00009  * Copyright (C) 2001-2007 Tresys Technology, LLC
00010  *
00011  *  This library is free software; you can redistribute it and/or
00012  *  modify it under the terms of the GNU Lesser General Public
00013  *  License as published by the Free Software Foundation; either
00014  *  version 2.1 of the License, or (at your option) any later version.
00015  *
00016  *  This library is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  *  Lesser General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU Lesser General Public
00022  *  License along with this library; if not, write to the Free Software
00023  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
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 /* these are needed for nodecons and IPv4 and IPv6 */
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>                /* needed for portcon's protocol */
00044 
00045 /* use 8k line size */
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;      /* value of current segment of address */
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         /* check current directory, environment variable, and then
00289          * installed directory */
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         /* didn't find it */
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         /* check current directory, environment variable, and then
00322          * installed directory */
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         /* didn't find it */
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  * Given a string, if the string begins with whitespace then allocate
00508  * a new string that does not contain those whitespaces.
00509  *
00510  * @param str String to modify.
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  * Given a mutable string, replace trailing whitespace characters with
00522  * null characters.
00523  *
00524  * @param str String to modify.
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         /* target is currently empty */
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                 /* tgt has some memory */
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         /* target is currently empty */
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                 /* tgt has some memory */
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 }