From patchwork Thu Sep 29 11:39:17 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Janis Danisevskis X-Patchwork-Id: 9356381 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 71273600C8 for ; Thu, 29 Sep 2016 11:39:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5F2F32996F for ; Thu, 29 Sep 2016 11:39:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 538FD29971; Thu, 29 Sep 2016 11:39:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-3.6 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,RCVD_IN_SORBS_SPAM,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from emsm-gh1-uea11.nsa.gov (emsm-gh1-uea11.nsa.gov [8.44.101.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id E3AE72996F for ; Thu, 29 Sep 2016 11:39:54 +0000 (UTC) X-IronPort-AV: E=Sophos;i="5.30,414,1470700800"; d="scan'208";a="19654218" IronPort-PHdr: =?us-ascii?q?9a23=3A+zpPRR9FIXJavf9uRHKM819IXTAuvvDOBiVQ1KB8?= =?us-ascii?q?1+gcTK2v8tzYMVDF4r011RmSDN+dsqMP0LWempujcFRI2YyGvnEGfc4EfD4+ou?= =?us-ascii?q?JSoTYdBtWYA1bwNv/gYn9yNs1DUFh44yPzahANS47AblHf6ke/8SQVUk2mc1Ek?= =?us-ascii?q?fKKsS8WJ0Iye7KObw9XreQJGhT6wM/tZDS6dikHvjPQQmpZoMa0ryxHE8TNicu?= =?us-ascii?q?VSwn50dxrIx06vrvqq+NZf1wgY+7d4r48TZ579Zbg1QYZVBzU+aSh1uJWq5lH/?= =?us-ascii?q?Sl6U638dVHgGugZZCAjCqhfhV9H+tTW+/vFw0S+WJ8r3QfUwWC++x7t6Qx/vzi?= =?us-ascii?q?EcPng293+Twtd8l4pHsRmhoFp52IeSb4aLcLJ8YajUZ89AbXZQVcZWESpaC8Wz?= =?us-ascii?q?aJVcIfAGOLN6po/8vBMipB2/HgSyH+Du0XcchHP/26wh++0nHRvB3QBmFNUL5i?= =?us-ascii?q?eH5O7pPbsfBLjmhJLDyi/OOqgO1A=3D=3D?= X-IPAS-Result: =?us-ascii?q?A2H0BACU/OxX/wHyM5BdHAEBBAEBCgEBFwEBBAEBCgEBgxQ?= =?us-ascii?q?BAQEBAR6BU7pKJ4V7gWtMAQEBAQEBAQECAQJbJ4IyBAMDFQU5EFUCDWEBBAIPF?= =?us-ascii?q?RMGAQEMIAsBAgMJAhcpCAgDAS0DAQUBCxgHCwUYBAGIKwSiBoEyPjKKVoUwAQE?= =?us-ascii?q?FgQGHIwELARwIEIQXghCIaxEBhV0diDyRQI9yiVglhW+PJzGBEVSDDw4cgVFxh?= =?us-ascii?q?RkNFwdagSgBAQE?= Received: from unknown (HELO tarius.tycho.ncsc.mil) ([144.51.242.1]) by emsm-gh1-uea11.nsa.gov with ESMTP; 29 Sep 2016 11:39:52 +0000 Received: from prometheus.infosec.tycho.ncsc.mil (prometheus [192.168.25.40]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id u8TBdZjt026092; Thu, 29 Sep 2016 07:39:40 -0400 Received: from tarius.tycho.ncsc.mil (tarius.infosec.tycho.ncsc.mil [144.51.242.1]) by prometheus.infosec.tycho.ncsc.mil (8.15.2/8.15.2) with ESMTP id u8TBdYl3019151 for ; Thu, 29 Sep 2016 07:39:34 -0400 Received: from goalie.tycho.ncsc.mil (goalie [144.51.242.250]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id u8TBdVHk026058 for ; Thu, 29 Sep 2016 07:39:33 -0400 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A1B2AQD6++xXfyxSfUpdHAEBBAEBCgEBgz8BAQEBAYFxtkOEFYYegWFMAQIBAQEBAQITAQEJCwsJF4UVARUVGQEBNwGBFAEFASMSIogrBKIHgTI+MopWhTABAQWBAYcjASgIEIQXghCLZQuCah2IPJFAj3KJWIYUjycxgRGDYw4cgVFxhRkrggIBAQE X-IPAS-Result: A1B2AQD6++xXfyxSfUpdHAEBBAEBCgEBgz8BAQEBAYFxtkOEFYYegWFMAQIBAQEBAQITAQEJCwsJF4UVARUVGQEBNwGBFAEFASMSIogrBKIHgTI+MopWhTABAQWBAYcjASgIEIQXghCLZQuCah2IPJFAj3KJWIYUjycxgRGDYw4cgVFxhRkrggIBAQE X-IronPort-AV: E=Sophos;i="5.30,414,1470715200"; d="scan'208";a="5735891" Received: from emsm-gh1-uea11.corp.nsa.gov (HELO emsm-gh1-uea11.nsa.gov) ([10.208.41.37]) by goalie.tycho.ncsc.mil with ESMTP; 29 Sep 2016 07:39:32 -0400 IronPort-PHdr: =?us-ascii?q?9a23=3AAY1O+x+ZJgT2IP9uRHKM819IXTAuvvDOBiVQ1KB8?= =?us-ascii?q?0eIcTK2v8tzYMVDF4r011RmSDN+dsqMP0LWempujcFRI2YyGvnEGfc4EfD4+ou?= =?us-ascii?q?JSoTYdBtWYA1bwNv/gYn9yNs1DUFh44yPzahANS47AblHf6ke/8SQVUk2mc1Ek?= =?us-ascii?q?fKKsS8WJ0Iye7KObw9XreQJGhT6wM/tZDS6dikHvjPQQmpZoMa0ryxHE8TNicu?= =?us-ascii?q?VSwn50dxrIx06vrvGL+4R//ihqtvkg75QIEfmiPvdwcbsNFzkiMmYo9OX3pBLD?= =?us-ascii?q?Sk2J/XJaXWII1lJTDgHD4Av9X5u0tirhqsJhySKaOovwVrlyVjO8q+9wRATAlD?= =?us-ascii?q?YMNzl/9nrezMN3kuYTog2qrgZjmabIcYqVM7x4ZaqbctQEFkRbWcMEdSVHA5j0?= =?us-ascii?q?Q4IJDvEMI/1brpK181kCpB2/HiGlAu/1zT5EwHTx2PtpgKwaDQja0Vl4TJo1u3?= =?us-ascii?q?POoYCpbKo=3D?= X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A0FYAQCU/OxXfyxSfUpdHAEBBAEBCgEBF?= =?us-ascii?q?wEBBAEBCgEBgxQBAQEBAYFxtkOEFYYegWFMAQEBAQEBAQECAQIQAQEJCwsJFzG?= =?us-ascii?q?CMgoaORBVAg1hARUVGQEBNwGBFAEFASMSIogrBKIGgTI+MopWhTABAQWBAYcjA?= =?us-ascii?q?SgIEIQXghCLZQuCah2IPJFAj3KJWIYUjycxgRGDYw4cgVFxhRkrggIBAQE?= X-IPAS-Result: =?us-ascii?q?A0FYAQCU/OxXfyxSfUpdHAEBBAEBCgEBFwEBBAEBCgEBgxQ?= =?us-ascii?q?BAQEBAYFxtkOEFYYegWFMAQEBAQEBAQECAQIQAQEJCwsJFzGCMgoaORBVAg1hA?= =?us-ascii?q?RUVGQEBNwGBFAEFASMSIogrBKIGgTI+MopWhTABAQWBAYcjASgIEIQXghCLZQu?= =?us-ascii?q?Cah2IPJFAj3KJWIYUjycxgRGDYw4cgVFxhRkrggIBAQE?= X-IronPort-AV: E=Sophos;i="5.30,414,1470700800"; d="scan'208";a="19654205" Received: from mail-wm0-f44.google.com ([74.125.82.44]) by emsm-gh1-uea11.nsa.gov with ESMTP/TLS/AES128-GCM-SHA256; 29 Sep 2016 11:39:26 +0000 Received: by mail-wm0-f44.google.com with SMTP id w72so21346375wmf.1 for ; Thu, 29 Sep 2016 04:39:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=android.com; s=20120917; h=from:to:cc:subject:date:message-id; bh=ZFWP/BHLMaXlG+OLBOH5NFn+ifJKl828DmGEB+5Df4U=; b=Ls7SB07cQdlQpapdBLXBvdzPOtkoD25ulg0pnX1x7/+0twAYo4QUfHdC+pgs+Lcggp wyA9UPzI50yfWYwHuZR8WPnq5YQPWGtwZYFVkftcubR130FC3f4QIGHJijPsT6ll7mKQ BuBN44Vru60P/Fdi696GuJCzp7jLa4v7A+lysxnAHEkMahEFLNKiw6QQ5HTUYvQ4IWfk N7QawmgDWkrqVqPjSt2TzDfEZm3IRbzR5C1RQmV4lfylRvz/6yFGLHi2NFGJKSqUFaCJ lDpyf1haWCjzmaVTdlQ7y438vUqhBTZhKnoF43015dRB9wNNKHS/o5tdPEAU4fn3x35P ZfWA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=ZFWP/BHLMaXlG+OLBOH5NFn+ifJKl828DmGEB+5Df4U=; b=iNOmNNEeecGmTuR39YI1vFufy3kMVIP60L6OFHdkJZTf1BJq7S3c3Jylv/dP0I4HzP ZDm3DG9A7vlPR+pMeALqtDKQQlb3Dgmb+IQGnIrL9nLY6kOZbA1wvDKgAkLl7ohdB/pB GJWIb0Dk2+oAgfMfbXvBls8+oGSMZMF7KcDhMufyhM4S12sSrltvHTtGI9DOjJwpAY45 RrOV+oal6yzFrtbyvsXR8Zeojte9Gty8HoKQB5byopMFBhh1G6q6OJifU+g8WleHckJ6 nsZhPFw1pdbAuOIGdQCWSE+l+58AoMTBMiswlhRxzjfS78OnGsG+/3cDVBev7R/uFfO1 Y91g== X-Gm-Message-State: AA6/9RkeKmt7PFpUcY68MYxksPyJWZ6szJOPxfhaLO3tRjkD0rC/OVgm+Z5nHk3XWy5nsw== X-Received: by 10.28.14.21 with SMTP id 21mr4691164wmo.42.1475149165128; Thu, 29 Sep 2016 04:39:25 -0700 (PDT) Received: from localhost.localdomain (cpc8-nmal18-2-0-cust977.croy.cable.virginm.net. [94.174.27.210]) by smtp.gmail.com with ESMTPSA id rk14sm13660190wjb.6.2016.09.29.04.39.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 29 Sep 2016 04:39:24 -0700 (PDT) From: Janis Danisevskis To: selinux@tycho.nsa.gov, seandroid-list@tycho.nsa.gov, sds@tycho.nsa.gov, jwcart2@tycho.nsa.gov Subject: [PATCH 1/3] libselinux: renamed andriod label backend source file Date: Thu, 29 Sep 2016 12:39:17 +0100 Message-Id: <1475149159-21757-1-git-send-email-jdanis@android.com> X-Mailer: git-send-email 1.9.1 X-BeenThere: selinux@tycho.nsa.gov X-Mailman-Version: 2.1.20 Precedence: list List-Id: "Security-Enhanced Linux \(SELinux\) mailing list" List-Post: List-Help: Cc: Janis Danisevskis MIME-Version: 1.0 Errors-To: selinux-bounces@tycho.nsa.gov Sender: "Selinux" X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Janis Danisevskis --- libselinux/src/Makefile | 2 +- libselinux/src/label_android_property.c | 304 -------------------------------- libselinux/src/label_backends_android.c | 304 ++++++++++++++++++++++++++++++++ 3 files changed, 305 insertions(+), 305 deletions(-) delete mode 100644 libselinux/src/label_android_property.c create mode 100644 libselinux/src/label_backends_android.c diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile index 2c61fad..cba8383 100644 --- a/libselinux/src/Makefile +++ b/libselinux/src/Makefile @@ -85,7 +85,7 @@ ifeq ($(ANDROID_HOST),y) DISABLE_FLAGS+= -DNO_MEDIA_BACKEND -DNO_DB_BACKEND -DNO_X_BACKEND \ -DBUILD_HOST SRCS= callbacks.c freecon.c label.c label_file.c \ - label_android_property.c regex.c label_support.c \ + label_backends_android.c regex.c label_support.c \ matchpathcon.c setrans_client.c sha1.c endif diff --git a/libselinux/src/label_android_property.c b/libselinux/src/label_android_property.c deleted file mode 100644 index 290b438..0000000 --- a/libselinux/src/label_android_property.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Property Service contexts backend for labeling Android - * property keys - */ - -#include -#include -#include -#include -#include -#include -#include -#include "callbacks.h" -#include "label_internal.h" - -/* A property security context specification. */ -typedef struct spec { - struct selabel_lookup_rec lr; /* holds contexts for lookup result */ - char *property_key; /* property key string */ -} spec_t; - -/* Our stored configuration */ -struct saved_data { - /* - * The array of specifications is sorted for longest - * prefix match - */ - spec_t *spec_arr; - unsigned int nspec; /* total number of specifications */ -}; - -static int cmp(const void *A, const void *B) -{ - const struct spec *sp1 = A, *sp2 = B; - - if (strncmp(sp1->property_key, "*", 1) == 0) - return 1; - if (strncmp(sp2->property_key, "*", 1) == 0) - return -1; - - size_t L1 = strlen(sp1->property_key); - size_t L2 = strlen(sp2->property_key); - - return (L1 < L2) - (L1 > L2); -} - -/* - * Warn about duplicate specifications. - */ -static int nodups_specs(struct saved_data *data, const char *path) -{ - int rc = 0; - unsigned int ii, jj; - struct spec *curr_spec, *spec_arr = data->spec_arr; - - for (ii = 0; ii < data->nspec; ii++) { - curr_spec = &spec_arr[ii]; - for (jj = ii + 1; jj < data->nspec; jj++) { - if (!strcmp(spec_arr[jj].property_key, - curr_spec->property_key)) { - rc = -1; - errno = EINVAL; - if (strcmp(spec_arr[jj].lr.ctx_raw, - curr_spec->lr.ctx_raw)) { - selinux_log - (SELINUX_ERROR, - "%s: Multiple different specifications for %s (%s and %s).\n", - path, curr_spec->property_key, - spec_arr[jj].lr.ctx_raw, - curr_spec->lr.ctx_raw); - } else { - selinux_log - (SELINUX_ERROR, - "%s: Multiple same specifications for %s.\n", - path, curr_spec->property_key); - } - } - } - } - return rc; -} - -static int process_line(struct selabel_handle *rec, - const char *path, char *line_buf, - int pass, unsigned lineno) -{ - int items; - char *prop = NULL, *context = NULL; - struct saved_data *data = (struct saved_data *)rec->data; - spec_t *spec_arr = data->spec_arr; - unsigned int nspec = data->nspec; - const char *errbuf = NULL; - - items = read_spec_entries(line_buf, &errbuf, 2, &prop, &context); - if (items < 0) { - items = errno; - selinux_log(SELINUX_ERROR, - "%s: line %u error due to: %s\n", path, - lineno, errbuf ?: strerror(errno)); - errno = items; - return -1; - } - - if (items == 0) - return items; - - if (items != 2) { - selinux_log(SELINUX_ERROR, - "%s: line %u is missing fields\n", path, - lineno); - free(prop); - errno = EINVAL; - return -1; - } - - if (pass == 0) { - free(prop); - free(context); - } else if (pass == 1) { - /* On the second pass, process and store the specification in spec. */ - spec_arr[nspec].property_key = prop; - spec_arr[nspec].lr.ctx_raw = context; - - if (rec->validating) { - if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) { - selinux_log(SELINUX_ERROR, - "%s: line %u has invalid context %s\n", - path, lineno, spec_arr[nspec].lr.ctx_raw); - errno = EINVAL; - return -1; - } - } - } - - data->nspec = ++nspec; - return 0; -} - -static int init(struct selabel_handle *rec, const struct selinux_opt *opts, - unsigned n) -{ - struct saved_data *data = (struct saved_data *)rec->data; - const char *path = NULL; - FILE *fp; - char line_buf[BUFSIZ]; - unsigned int lineno, maxnspec, pass; - int status = -1; - struct stat sb; - - /* Process arguments */ - while (n--) - switch (opts[n].type) { - case SELABEL_OPT_PATH: - path = opts[n].value; - break; - } - - if (!path) - return -1; - - /* Open the specification file. */ - if ((fp = fopen(path, "r")) == NULL) - return -1; - - if (fstat(fileno(fp), &sb) < 0) - goto finish; - errno = EINVAL; - if (!S_ISREG(sb.st_mode)) - goto finish; - - /* - * Two passes of the specification file. First is to get the size. - * After the first pass, the spec array is malloced to the appropriate - * size. Second pass is to populate the spec array and check for - * dups. - */ - maxnspec = UINT_MAX / sizeof(spec_t); - for (pass = 0; pass < 2; pass++) { - data->nspec = 0; - lineno = 0; - - while (fgets(line_buf, sizeof(line_buf) - 1, fp) - && data->nspec < maxnspec) { - if (process_line(rec, path, line_buf, pass, ++lineno) - != 0) - goto finish; - } - - if (pass == 1) { - status = nodups_specs(data, path); - - if (status) - goto finish; - } - - if (pass == 0) { - if (data->nspec == 0) { - status = 0; - goto finish; - } - - if (NULL == (data->spec_arr = - malloc(sizeof(spec_t) * data->nspec))) - goto finish; - - memset(data->spec_arr, 0, sizeof(spec_t) * data->nspec); - maxnspec = data->nspec; - rewind(fp); - } - } - - qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp); - - status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path); - if (status) - goto finish; - - digest_gen_hash(rec->digest); - -finish: - fclose(fp); - return status; -} - -/* - * Backend interface routines - */ -static void closef(struct selabel_handle *rec) -{ - struct saved_data *data = (struct saved_data *)rec->data; - struct spec *spec; - unsigned int i; - - for (i = 0; i < data->nspec; i++) { - spec = &data->spec_arr[i]; - free(spec->property_key); - free(spec->lr.ctx_raw); - free(spec->lr.ctx_trans); - } - - if (data->spec_arr) - free(data->spec_arr); - - free(data); -} - -static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, - const char *key, - int __attribute__((unused)) type) -{ - struct saved_data *data = (struct saved_data *)rec->data; - spec_t *spec_arr = data->spec_arr; - unsigned int i; - struct selabel_lookup_rec *ret = NULL; - - if (!data->nspec) { - errno = ENOENT; - goto finish; - } - - for (i = 0; i < data->nspec; i++) { - if (strncmp(spec_arr[i].property_key, key, - strlen(spec_arr[i].property_key)) == 0) { - break; - } - if (strncmp(spec_arr[i].property_key, "*", 1) == 0) - break; - } - - if (i >= data->nspec) { - /* No matching specification. */ - errno = ENOENT; - goto finish; - } - - ret = &spec_arr[i].lr; - -finish: - return ret; -} - -static void stats(struct selabel_handle __attribute__((unused)) *rec) -{ - selinux_log(SELINUX_WARNING, "'stats' functionality not implemented.\n"); -} - -int selabel_property_init(struct selabel_handle *rec, - const struct selinux_opt *opts, - unsigned nopts) -{ - struct saved_data *data; - - data = (struct saved_data *)malloc(sizeof(*data)); - if (!data) - return -1; - memset(data, 0, sizeof(*data)); - - rec->data = data; - rec->func_close = &closef; - rec->func_stats = &stats; - rec->func_lookup = &lookup; - - return init(rec, opts, nopts); -} diff --git a/libselinux/src/label_backends_android.c b/libselinux/src/label_backends_android.c new file mode 100644 index 0000000..290b438 --- /dev/null +++ b/libselinux/src/label_backends_android.c @@ -0,0 +1,304 @@ +/* + * Property Service contexts backend for labeling Android + * property keys + */ + +#include +#include +#include +#include +#include +#include +#include +#include "callbacks.h" +#include "label_internal.h" + +/* A property security context specification. */ +typedef struct spec { + struct selabel_lookup_rec lr; /* holds contexts for lookup result */ + char *property_key; /* property key string */ +} spec_t; + +/* Our stored configuration */ +struct saved_data { + /* + * The array of specifications is sorted for longest + * prefix match + */ + spec_t *spec_arr; + unsigned int nspec; /* total number of specifications */ +}; + +static int cmp(const void *A, const void *B) +{ + const struct spec *sp1 = A, *sp2 = B; + + if (strncmp(sp1->property_key, "*", 1) == 0) + return 1; + if (strncmp(sp2->property_key, "*", 1) == 0) + return -1; + + size_t L1 = strlen(sp1->property_key); + size_t L2 = strlen(sp2->property_key); + + return (L1 < L2) - (L1 > L2); +} + +/* + * Warn about duplicate specifications. + */ +static int nodups_specs(struct saved_data *data, const char *path) +{ + int rc = 0; + unsigned int ii, jj; + struct spec *curr_spec, *spec_arr = data->spec_arr; + + for (ii = 0; ii < data->nspec; ii++) { + curr_spec = &spec_arr[ii]; + for (jj = ii + 1; jj < data->nspec; jj++) { + if (!strcmp(spec_arr[jj].property_key, + curr_spec->property_key)) { + rc = -1; + errno = EINVAL; + if (strcmp(spec_arr[jj].lr.ctx_raw, + curr_spec->lr.ctx_raw)) { + selinux_log + (SELINUX_ERROR, + "%s: Multiple different specifications for %s (%s and %s).\n", + path, curr_spec->property_key, + spec_arr[jj].lr.ctx_raw, + curr_spec->lr.ctx_raw); + } else { + selinux_log + (SELINUX_ERROR, + "%s: Multiple same specifications for %s.\n", + path, curr_spec->property_key); + } + } + } + } + return rc; +} + +static int process_line(struct selabel_handle *rec, + const char *path, char *line_buf, + int pass, unsigned lineno) +{ + int items; + char *prop = NULL, *context = NULL; + struct saved_data *data = (struct saved_data *)rec->data; + spec_t *spec_arr = data->spec_arr; + unsigned int nspec = data->nspec; + const char *errbuf = NULL; + + items = read_spec_entries(line_buf, &errbuf, 2, &prop, &context); + if (items < 0) { + items = errno; + selinux_log(SELINUX_ERROR, + "%s: line %u error due to: %s\n", path, + lineno, errbuf ?: strerror(errno)); + errno = items; + return -1; + } + + if (items == 0) + return items; + + if (items != 2) { + selinux_log(SELINUX_ERROR, + "%s: line %u is missing fields\n", path, + lineno); + free(prop); + errno = EINVAL; + return -1; + } + + if (pass == 0) { + free(prop); + free(context); + } else if (pass == 1) { + /* On the second pass, process and store the specification in spec. */ + spec_arr[nspec].property_key = prop; + spec_arr[nspec].lr.ctx_raw = context; + + if (rec->validating) { + if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) { + selinux_log(SELINUX_ERROR, + "%s: line %u has invalid context %s\n", + path, lineno, spec_arr[nspec].lr.ctx_raw); + errno = EINVAL; + return -1; + } + } + } + + data->nspec = ++nspec; + return 0; +} + +static int init(struct selabel_handle *rec, const struct selinux_opt *opts, + unsigned n) +{ + struct saved_data *data = (struct saved_data *)rec->data; + const char *path = NULL; + FILE *fp; + char line_buf[BUFSIZ]; + unsigned int lineno, maxnspec, pass; + int status = -1; + struct stat sb; + + /* Process arguments */ + while (n--) + switch (opts[n].type) { + case SELABEL_OPT_PATH: + path = opts[n].value; + break; + } + + if (!path) + return -1; + + /* Open the specification file. */ + if ((fp = fopen(path, "r")) == NULL) + return -1; + + if (fstat(fileno(fp), &sb) < 0) + goto finish; + errno = EINVAL; + if (!S_ISREG(sb.st_mode)) + goto finish; + + /* + * Two passes of the specification file. First is to get the size. + * After the first pass, the spec array is malloced to the appropriate + * size. Second pass is to populate the spec array and check for + * dups. + */ + maxnspec = UINT_MAX / sizeof(spec_t); + for (pass = 0; pass < 2; pass++) { + data->nspec = 0; + lineno = 0; + + while (fgets(line_buf, sizeof(line_buf) - 1, fp) + && data->nspec < maxnspec) { + if (process_line(rec, path, line_buf, pass, ++lineno) + != 0) + goto finish; + } + + if (pass == 1) { + status = nodups_specs(data, path); + + if (status) + goto finish; + } + + if (pass == 0) { + if (data->nspec == 0) { + status = 0; + goto finish; + } + + if (NULL == (data->spec_arr = + malloc(sizeof(spec_t) * data->nspec))) + goto finish; + + memset(data->spec_arr, 0, sizeof(spec_t) * data->nspec); + maxnspec = data->nspec; + rewind(fp); + } + } + + qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp); + + status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path); + if (status) + goto finish; + + digest_gen_hash(rec->digest); + +finish: + fclose(fp); + return status; +} + +/* + * Backend interface routines + */ +static void closef(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + struct spec *spec; + unsigned int i; + + for (i = 0; i < data->nspec; i++) { + spec = &data->spec_arr[i]; + free(spec->property_key); + free(spec->lr.ctx_raw); + free(spec->lr.ctx_trans); + } + + if (data->spec_arr) + free(data->spec_arr); + + free(data); +} + +static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, + const char *key, + int __attribute__((unused)) type) +{ + struct saved_data *data = (struct saved_data *)rec->data; + spec_t *spec_arr = data->spec_arr; + unsigned int i; + struct selabel_lookup_rec *ret = NULL; + + if (!data->nspec) { + errno = ENOENT; + goto finish; + } + + for (i = 0; i < data->nspec; i++) { + if (strncmp(spec_arr[i].property_key, key, + strlen(spec_arr[i].property_key)) == 0) { + break; + } + if (strncmp(spec_arr[i].property_key, "*", 1) == 0) + break; + } + + if (i >= data->nspec) { + /* No matching specification. */ + errno = ENOENT; + goto finish; + } + + ret = &spec_arr[i].lr; + +finish: + return ret; +} + +static void stats(struct selabel_handle __attribute__((unused)) *rec) +{ + selinux_log(SELINUX_WARNING, "'stats' functionality not implemented.\n"); +} + +int selabel_property_init(struct selabel_handle *rec, + const struct selinux_opt *opts, + unsigned nopts) +{ + struct saved_data *data; + + data = (struct saved_data *)malloc(sizeof(*data)); + if (!data) + return -1; + memset(data, 0, sizeof(*data)); + + rec->data = data; + rec->func_close = &closef; + rec->func_stats = &stats; + rec->func_lookup = &lookup; + + return init(rec, opts, nopts); +}