1165 lines
33 KiB
Diff
1165 lines
33 KiB
Diff
diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h
|
|
index 6b9089d..aba6e33 100644
|
|
--- a/libselinux/include/selinux/selinux.h
|
|
+++ b/libselinux/include/selinux/selinux.h
|
|
@@ -360,6 +360,8 @@ extern int selinux_set_mapping(struct security_class_mapping *map);
|
|
|
|
/* Common helpers */
|
|
|
|
+/* Convert between mode and security class values */
|
|
+extern security_class_t mode_to_security_class(mode_t mode);
|
|
/* Convert between security class values and string names */
|
|
extern security_class_t string_to_security_class(const char *name);
|
|
extern const char *security_class_to_string(security_class_t cls);
|
|
@@ -496,7 +498,9 @@ extern const char *selinux_policy_root(void);
|
|
|
|
/* These functions return the paths to specific files under the
|
|
policy root directory. */
|
|
+extern const char *selinux_current_policy_path(void);
|
|
extern const char *selinux_binary_policy_path(void);
|
|
+extern char *selinux_binary_policy_path_min_max(int min, int *max);
|
|
extern const char *selinux_failsafe_context_path(void);
|
|
extern const char *selinux_removable_context_path(void);
|
|
extern const char *selinux_default_context_path(void);
|
|
diff --git a/libselinux/man/man3/mode_to_security_class.3 b/libselinux/man/man3/mode_to_security_class.3
|
|
new file mode 100644
|
|
index 0000000..bda9daf
|
|
--- /dev/null
|
|
+++ b/libselinux/man/man3/mode_to_security_class.3
|
|
@@ -0,0 +1 @@
|
|
+.so man3/security_class_to_string.3
|
|
diff --git a/libselinux/man/man3/security_class_to_string.3 b/libselinux/man/man3/security_class_to_string.3
|
|
index 140737e..e82e1d8 100644
|
|
--- a/libselinux/man/man3/security_class_to_string.3
|
|
+++ b/libselinux/man/man3/security_class_to_string.3
|
|
@@ -3,7 +3,7 @@
|
|
.\" Author: Eamon Walsh (ewalsh@tycho.nsa.gov) 2007
|
|
.TH "security_class_to_string" "3" "30 Mar 2007" "" "SELinux API documentation"
|
|
.SH "NAME"
|
|
-security_class_to_string, security_av_perm_to_string, string_to_security_class, string_to_av_perm, security_av_string \- convert
|
|
+security_class_to_string, security_av_perm_to_string, string_to_security_class, string_to_av_perm, security_av_string, mode_to_security_class \- convert
|
|
between SELinux class and permission values and string names.
|
|
|
|
print_access_vector \- display an access vector in human-readable form.
|
|
@@ -21,6 +21,8 @@ print_access_vector \- display an access vector in human-readable form.
|
|
.sp
|
|
.BI "security_class_t string_to_security_class(const char *" name ");"
|
|
.sp
|
|
+.BI "security_class_t mode_to_security_class(mode_t " mode ");"
|
|
+.sp
|
|
.BI "access_vector_t string_to_av_perm(security_class_t " tclass ", const char *" name ");"
|
|
.sp
|
|
.BI "void print_access_vector(security_class_t " tclass ", access_vector_t " av ");"
|
|
@@ -53,6 +55,11 @@ returns the class value corresponding to the string name
|
|
.IR name ,
|
|
or zero if no such class exists.
|
|
|
|
+.B mode_to_security_class
|
|
+returns the class value corresponding to the specified
|
|
+.IR mode ,
|
|
+or zero if no such class exists.
|
|
+
|
|
.B string_to_av_perm
|
|
returns the access vector bit corresponding to the string name
|
|
.I name
|
|
@@ -88,3 +95,4 @@ Eamon Walsh <ewalsh@tycho.nsa.gov>
|
|
.BR selinux (8),
|
|
.BR getcon (3),
|
|
.BR getfilecon (3)
|
|
+.BR stat (3)
|
|
diff --git a/libselinux/man/man3/selinux_binary_policy_path.3 b/libselinux/man/man3/selinux_binary_policy_path.3
|
|
index 8ead1a4..c68ace5 100644
|
|
--- a/libselinux/man/man3/selinux_binary_policy_path.3
|
|
+++ b/libselinux/man/man3/selinux_binary_policy_path.3
|
|
@@ -17,6 +17,8 @@ extern const char *selinux_policy_root(void);
|
|
|
|
extern const char *selinux_binary_policy_path(void);
|
|
|
|
+extern const char *selinux_current_policy_path(void);
|
|
+
|
|
extern const char *selinux_failsafe_context_path(void);
|
|
|
|
extern const char *selinux_removable_context_path(void);
|
|
@@ -52,7 +54,9 @@ selinux_path() - top-level SELinux configuration directory
|
|
.sp
|
|
selinux_policy_root() - top-level policy directory
|
|
.sp
|
|
-selinux_binary_policy_path() - binary policy file loaded into kernel
|
|
+selinux_current_policy_path() - binary policy file loaded into kernel
|
|
+.sp
|
|
+selinux_binary_policy_path() - binary policy path on disk
|
|
.sp
|
|
selinux_default_type_path - context file mapping roles to default types.
|
|
.sp
|
|
diff --git a/libselinux/man/man8/selinux.8 b/libselinux/man/man8/selinux.8
|
|
index 9f16f77..4835f2f 100644
|
|
--- a/libselinux/man/man8/selinux.8
|
|
+++ b/libselinux/man/man8/selinux.8
|
|
@@ -69,14 +69,27 @@ Many domains that are protected by SELinux also include SELinux man pages explai
|
|
All files, directories, devices ... have a security context/label associated with them. These context are stored in the extended attributes of the file system.
|
|
Problems with SELinux often arise from the file system being mislabeled. This can be caused by booting the machine with a non SELinux kernel. If you see an error message containing file_t, that is usually a good indicator that you have a serious problem with file system labeling.
|
|
|
|
-The best way to relabel the file system is to create the flag file /.autorelabel and reboot. system-config-securitylevel, also has this capability. The restorcon/fixfiles commands are also available for relabeling files.
|
|
+The best way to relabel the file system is to create the flag file /.autorelabel and reboot. system-config-selinux, also has this capability. The restorcon/fixfiles commands are also available for relabeling files.
|
|
|
|
.SH AUTHOR
|
|
This manual page was written by Dan Walsh <dwalsh@redhat.com>.
|
|
|
|
.SH "SEE ALSO"
|
|
-booleans(8), setsebool(8), selinuxenabled(8), togglesebool(8), restorecon(8), setfiles(8), ftpd_selinux(8), named_selinux(8), rsync_selinux(8), httpd_selinux(8), nfs_selinux(8), samba_selinux(8), kerberos_selinux(8), nis_selinux(8), ypbind_selinux(8)
|
|
+booleans(8), setsebool(8), selinuxenabled(8), restorecon(8), setfiles(8), semanage(8), sepolicy(8)
|
|
+.br
|
|
|
|
+Every confined service on the system has a man page in the following format:
|
|
+.br
|
|
+
|
|
+.B <servicename>_selinux(8)
|
|
+
|
|
+For example, httpd has the
|
|
+.B httpd_selinux(8)
|
|
+man page.
|
|
+
|
|
+.B man -k selinux
|
|
+
|
|
+Will list all SELinux man pages.
|
|
|
|
.SH FILES
|
|
/etc/selinux/config
|
|
diff --git a/libselinux/src/audit2why.c b/libselinux/src/audit2why.c
|
|
index 02483a3..c804e84 100644
|
|
--- a/libselinux/src/audit2why.c
|
|
+++ b/libselinux/src/audit2why.c
|
|
@@ -164,6 +164,9 @@ static PyObject *finish(PyObject *self __attribute__((unused)), PyObject *args)
|
|
|
|
if (PyArg_ParseTuple(args,(char *)":finish")) {
|
|
int i = 0;
|
|
+ if (! avc)
|
|
+ Py_RETURN_NONE;
|
|
+
|
|
for (i = 0; i < boolcnt; i++) {
|
|
free(boollist[i]->name);
|
|
free(boollist[i]);
|
|
@@ -177,7 +180,7 @@ static PyObject *finish(PyObject *self __attribute__((unused)), PyObject *args)
|
|
avc = NULL;
|
|
boollist = NULL;
|
|
boolcnt = 0;
|
|
-
|
|
+
|
|
/* Boilerplate to return "None" */
|
|
Py_RETURN_NONE;
|
|
}
|
|
@@ -206,27 +209,12 @@ static int __policy_init(const char *init_path)
|
|
return 1;
|
|
}
|
|
} else {
|
|
- vers = sepol_policy_kern_vers_max();
|
|
- if (vers < 0) {
|
|
- snprintf(errormsg, sizeof(errormsg),
|
|
- "Could not get policy version: %s\n",
|
|
- strerror(errno));
|
|
- PyErr_SetString( PyExc_ValueError, errormsg);
|
|
- return 1;
|
|
- }
|
|
- snprintf(path, PATH_MAX, "%s.%d",
|
|
- selinux_binary_policy_path(), vers);
|
|
- fp = fopen(path, "r");
|
|
- while (!fp && errno == ENOENT && --vers) {
|
|
- snprintf(path, PATH_MAX, "%s.%d",
|
|
- selinux_binary_policy_path(), vers);
|
|
- fp = fopen(path, "r");
|
|
- }
|
|
+ fp = fopen(selinux_current_policy_path(), "r");
|
|
if (!fp) {
|
|
snprintf(errormsg, sizeof(errormsg),
|
|
- "unable to open %s.%d: %s\n",
|
|
- selinux_binary_policy_path(),
|
|
- security_policyvers(), strerror(errno));
|
|
+ "unable to open %s: %s\n",
|
|
+ selinux_current_policy_path(),
|
|
+ strerror(errno));
|
|
PyErr_SetString( PyExc_ValueError, errormsg);
|
|
return 1;
|
|
}
|
|
@@ -295,6 +283,10 @@ static int __policy_init(const char *init_path)
|
|
static PyObject *init(PyObject *self __attribute__((unused)), PyObject *args) {
|
|
int result;
|
|
char *init_path=NULL;
|
|
+ if (avc) {
|
|
+ PyErr_SetString( PyExc_RuntimeError, "init called multiple times");
|
|
+ return NULL;
|
|
+ }
|
|
if (!PyArg_ParseTuple(args,(char *)"|s:policy_init",&init_path))
|
|
return NULL;
|
|
result = __policy_init(init_path);
|
|
diff --git a/libselinux/src/avc.c b/libselinux/src/avc.c
|
|
index 802a07f..6ff83a7 100644
|
|
--- a/libselinux/src/avc.c
|
|
+++ b/libselinux/src/avc.c
|
|
@@ -827,6 +827,7 @@ int avc_has_perm(security_id_t ssid, security_id_t tsid,
|
|
errsave = errno;
|
|
avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
|
|
errno = errsave;
|
|
+ if (!avc_enforcing) return 0;
|
|
return rc;
|
|
}
|
|
|
|
diff --git a/libselinux/src/file_path_suffixes.h b/libselinux/src/file_path_suffixes.h
|
|
index 825f295..d11c8dc 100644
|
|
--- a/libselinux/src/file_path_suffixes.h
|
|
+++ b/libselinux/src/file_path_suffixes.h
|
|
@@ -26,4 +26,4 @@ S_(BINPOLICY, "/policy/policy")
|
|
S_(FILE_CONTEXT_SUBS, "/contexts/files/file_contexts.subs")
|
|
S_(FILE_CONTEXT_SUBS_DIST, "/contexts/files/file_contexts.subs_dist")
|
|
S_(SEPGSQL_CONTEXTS, "/contexts/sepgsql_contexts")
|
|
- S_(BOOLEAN_SUBS, "/booleans.subs")
|
|
+ S_(BOOLEAN_SUBS, "/booleans.subs_dist")
|
|
diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
|
|
index 02b3cd2..301e4d6 100644
|
|
--- a/libselinux/src/label_file.c
|
|
+++ b/libselinux/src/label_file.c
|
|
@@ -8,6 +8,7 @@
|
|
* developed by Secure Computing Corporation.
|
|
*/
|
|
|
|
+#include <assert.h>
|
|
#include <fcntl.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
@@ -16,7 +17,12 @@
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
+#include <stdint.h>
|
|
#include <pcre.h>
|
|
+
|
|
+#include <linux/limits.h>
|
|
+
|
|
+#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
@@ -229,6 +235,173 @@ static int process_line(struct selabel_handle *rec,
|
|
return 0;
|
|
}
|
|
|
|
+static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *stat)
|
|
+{
|
|
+ struct saved_data *data = (struct saved_data *)rec->data;
|
|
+ char mmap_path[PATH_MAX + 1];
|
|
+ int mmapfd;
|
|
+ int rc, i;
|
|
+ struct stat mmap_stat;
|
|
+ char *addr;
|
|
+ size_t len;
|
|
+ int stem_map_len, *stem_map;
|
|
+
|
|
+ uint32_t *magic;
|
|
+ uint32_t *section_len;
|
|
+ uint32_t *plen;
|
|
+
|
|
+ rc = snprintf(mmap_path, sizeof(mmap_path), "%s.bin", path);
|
|
+ if (rc >= sizeof(mmap_path))
|
|
+ return -1;
|
|
+
|
|
+ mmapfd = open(mmap_path, O_RDONLY | O_CLOEXEC);
|
|
+ if (!mmapfd)
|
|
+ return -1;
|
|
+
|
|
+ rc = fstat(mmapfd, &mmap_stat);
|
|
+ if (rc < 0) {
|
|
+ close(mmapfd);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ /* if mmap is old, ignore it */
|
|
+ if (mmap_stat.st_mtime < stat->st_mtime) {
|
|
+ close(mmapfd);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (mmap_stat.st_mtime == stat->st_mtime &&
|
|
+ mmap_stat.st_mtim.tv_nsec < stat->st_mtim.tv_nsec) {
|
|
+ close(mmapfd);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ /* ok, read it in... */
|
|
+ len = mmap_stat.st_size;
|
|
+ len += (sysconf(_SC_PAGE_SIZE) - 1);
|
|
+ len &= ~(sysconf(_SC_PAGE_SIZE) - 1);
|
|
+
|
|
+ addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, mmapfd, 0);
|
|
+ close(mmapfd);
|
|
+ if (addr == MAP_FAILED) {
|
|
+ perror("mmap");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ /* check if this looks like an fcontext file */
|
|
+ magic = (uint32_t *)addr;
|
|
+ if (*magic != SELINUX_MAGIC_COMPILED_FCONTEXT)
|
|
+ return -1;
|
|
+ addr += sizeof(uint32_t);
|
|
+
|
|
+ /* check if this version is higher than we understand */
|
|
+ section_len = (uint32_t *)addr;
|
|
+ if (*section_len > SELINUX_COMPILED_FCONTEXT_MAX_VERS)
|
|
+ return -1;
|
|
+ addr += sizeof(uint32_t);
|
|
+
|
|
+ /* allocate the stems_data array */
|
|
+ section_len = (uint32_t *)addr;
|
|
+ addr += sizeof(uint32_t);
|
|
+
|
|
+ /*
|
|
+ * map indexed by the stem # in the mmap file and contains the stem
|
|
+ * number in the data stem_arr
|
|
+ */
|
|
+ stem_map_len = *section_len;
|
|
+ stem_map = calloc(stem_map_len, sizeof(*stem_map));
|
|
+ if (!stem_map)
|
|
+ return -1;
|
|
+
|
|
+ for (i = 0; i < *section_len; i++) {
|
|
+ char *buf;
|
|
+ uint32_t stem_len;
|
|
+ int newid;
|
|
+
|
|
+ /* the length does not inlude the nul */
|
|
+ plen = (uint32_t *)addr;
|
|
+ addr += sizeof(uint32_t);
|
|
+
|
|
+ stem_len = *plen;
|
|
+ buf = (char *)addr;
|
|
+ addr += (stem_len + 1); // +1 is the nul
|
|
+
|
|
+ /* store the mapping between old and new */
|
|
+ newid = find_stem(data, buf, stem_len);
|
|
+ if (newid < 0) {
|
|
+ newid = store_stem(data, buf, stem_len);
|
|
+ if (newid < 0)
|
|
+ return newid;
|
|
+ data->stem_arr[newid].from_mmap = 1;
|
|
+ }
|
|
+ stem_map[i] = newid;
|
|
+ }
|
|
+
|
|
+ /* allocate the regex array */
|
|
+ section_len = (uint32_t *)addr;
|
|
+ addr += sizeof(*section_len);
|
|
+
|
|
+ for (i = 0; i < *section_len; i++) {
|
|
+ struct spec *spec;
|
|
+ int32_t stem_id;
|
|
+
|
|
+ rc = grow_specs(data);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ spec = &data->spec_arr[data->nspec];
|
|
+ spec->from_mmap = 1;
|
|
+ spec->regcomp = 1;
|
|
+
|
|
+ plen = (uint32_t *)addr;
|
|
+ addr += sizeof(uint32_t);
|
|
+ spec->lr.ctx_raw = strdup((char *)addr);
|
|
+ if (!spec->lr.ctx_raw)
|
|
+ return -1;
|
|
+ addr += *plen;
|
|
+
|
|
+ plen = (uint32_t *)addr;
|
|
+ addr += sizeof(uint32_t);
|
|
+ spec->regex_str = (char *)addr;
|
|
+ addr += *plen;
|
|
+
|
|
+ spec->mode = *(mode_t *)addr;
|
|
+ addr += sizeof(mode_t);
|
|
+
|
|
+ /* map the stem id from the mmap file to the data->stem_arr */
|
|
+ stem_id = *(int32_t *)addr;
|
|
+ if (stem_id == -1) {
|
|
+ spec->stem_id = -1;
|
|
+ } else {
|
|
+ assert(stem_id <= stem_map_len);
|
|
+ spec->stem_id = stem_map[stem_id];
|
|
+ }
|
|
+ addr += sizeof(int32_t);
|
|
+
|
|
+ /* retrieve the hasMetaChars bit */
|
|
+ spec->hasMetaChars = *(uint32_t *)addr;
|
|
+ addr += sizeof(uint32_t);
|
|
+
|
|
+ plen = (uint32_t *)addr;
|
|
+ addr += sizeof(uint32_t);
|
|
+ spec->regex = (pcre *)addr;
|
|
+ addr += *plen;
|
|
+
|
|
+ plen = (uint32_t *)addr;
|
|
+ addr += sizeof(uint32_t);
|
|
+ spec->lsd.study_data = (void *)addr;
|
|
+ spec->lsd.flags |= PCRE_EXTRA_STUDY_DATA;
|
|
+ addr += *plen;
|
|
+
|
|
+ data->nspec++;
|
|
+ }
|
|
+
|
|
+ free(stem_map);
|
|
+
|
|
+ /* win */
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int process_file(const char *path, const char *suffix, struct selabel_handle *rec, const char *prefix)
|
|
{
|
|
FILE *fp;
|
|
@@ -261,6 +434,10 @@ static int process_file(const char *path, const char *suffix, struct selabel_han
|
|
return -1;
|
|
}
|
|
|
|
+ rc = load_mmap(rec, path, &sb);
|
|
+ if (rc == 0)
|
|
+ goto out;
|
|
+
|
|
/*
|
|
* The do detailed validation of the input and fill the spec array
|
|
*/
|
|
@@ -270,6 +447,7 @@ static int process_file(const char *path, const char *suffix, struct selabel_han
|
|
if (rc)
|
|
return rc;
|
|
}
|
|
+out:
|
|
free(line_buf);
|
|
fclose(fp);
|
|
|
|
@@ -357,6 +535,8 @@ static void closef(struct selabel_handle *rec)
|
|
|
|
for (i = 0; i < data->nspec; i++) {
|
|
spec = &data->spec_arr[i];
|
|
+ if (spec->from_mmap)
|
|
+ continue;
|
|
free(spec->regex_str);
|
|
free(spec->type_str);
|
|
free(spec->lr.ctx_raw);
|
|
@@ -369,6 +549,8 @@ static void closef(struct selabel_handle *rec)
|
|
|
|
for (i = 0; i < (unsigned int)data->num_stems; i++) {
|
|
stem = &data->stem_arr[i];
|
|
+ if (stem->from_mmap)
|
|
+ continue;
|
|
free(stem->buf);
|
|
}
|
|
|
|
diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h
|
|
index cb5633b..9799bbb 100644
|
|
--- a/libselinux/src/label_file.h
|
|
+++ b/libselinux/src/label_file.h
|
|
@@ -5,24 +5,32 @@
|
|
|
|
#include "label_internal.h"
|
|
|
|
+#define SELINUX_MAGIC_COMPILED_FCONTEXT 0xf97cff8a
|
|
+#define SELINUX_COMPILED_FCONTEXT_MAX_VERS 1
|
|
+
|
|
/* A file security context specification. */
|
|
struct spec {
|
|
struct selabel_lookup_rec lr; /* holds contexts for lookup result */
|
|
char *regex_str; /* regular expession string for diagnostics */
|
|
char *type_str; /* type string for diagnostic messages */
|
|
pcre *regex; /* compiled regular expression */
|
|
- pcre_extra *sd; /* extra compiled stuff */
|
|
+ union {
|
|
+ pcre_extra *sd; /* pointer to extra compiled stuff */
|
|
+ pcre_extra lsd; /* used to hold the mmap'd version */
|
|
+ };
|
|
mode_t mode; /* mode format value */
|
|
int matches; /* number of matching pathnames */
|
|
int stem_id; /* indicates which stem-compression item */
|
|
char hasMetaChars; /* regular expression has meta-chars */
|
|
char regcomp; /* regex_str has been compiled to regex */
|
|
+ char from_mmap; /* this spec is from an mmap of the data */
|
|
};
|
|
|
|
/* A regular expression stem */
|
|
struct stem {
|
|
char *buf;
|
|
int len;
|
|
+ char from_mmap;
|
|
};
|
|
|
|
/* Our stored configuration */
|
|
@@ -45,7 +53,10 @@ struct saved_data {
|
|
|
|
static inline pcre_extra *get_pcre_extra(struct spec *spec)
|
|
{
|
|
- return spec->sd;
|
|
+ if (spec->from_mmap)
|
|
+ return &spec->lsd;
|
|
+ else
|
|
+ return spec->sd;
|
|
}
|
|
|
|
static inline mode_t string_to_mode(char *mode)
|
|
diff --git a/libselinux/src/load_policy.c b/libselinux/src/load_policy.c
|
|
index 10e29b9..888dab5 100644
|
|
--- a/libselinux/src/load_policy.c
|
|
+++ b/libselinux/src/load_policy.c
|
|
@@ -49,8 +49,9 @@ int load_setlocaldefs hidden = 1;
|
|
int selinux_mkload_policy(int preservebools)
|
|
{
|
|
int kernvers = security_policyvers();
|
|
- int maxvers = kernvers, minvers = DEFAULT_POLICY_VERSION, vers;
|
|
+ int maxvers = kernvers, minvers = DEFAULT_POLICY_VERSION;
|
|
int setlocaldefs = load_setlocaldefs;
|
|
+ char *pol_path = NULL;
|
|
char path[PATH_MAX];
|
|
struct stat sb;
|
|
struct utsname uts;
|
|
@@ -162,29 +163,24 @@ checkbool:
|
|
maxvers = max(kernvers, maxvers);
|
|
}
|
|
|
|
- vers = maxvers;
|
|
- search:
|
|
- snprintf(path, sizeof(path), "%s.%d",
|
|
- selinux_binary_policy_path(), vers);
|
|
- fd = open(path, O_RDONLY);
|
|
- while (fd < 0 && errno == ENOENT
|
|
- && --vers >= minvers) {
|
|
- /* Check prior versions to see if old policy is available */
|
|
- snprintf(path, sizeof(path), "%s.%d",
|
|
- selinux_binary_policy_path(), vers);
|
|
- fd = open(path, O_RDONLY);
|
|
+search:
|
|
+ pol_path = selinux_binary_policy_path_min_max(minvers, &maxvers);
|
|
+ if (!pol_path) {
|
|
+ fprintf(stderr, "SELinux: unable to find usable policy file: %s\n",
|
|
+ strerror(errno));
|
|
+ goto dlclose;
|
|
}
|
|
+
|
|
+ fd = open(pol_path, O_RDONLY);
|
|
if (fd < 0) {
|
|
- fprintf(stderr,
|
|
- "SELinux: Could not open policy file <= %s.%d: %s\n",
|
|
- selinux_binary_policy_path(), maxvers, strerror(errno));
|
|
+ fprintf(stderr, "SELinux: Could not open policy file %s: %s\n",
|
|
+ pol_path, strerror(errno));
|
|
goto dlclose;
|
|
}
|
|
|
|
if (fstat(fd, &sb) < 0) {
|
|
- fprintf(stderr,
|
|
- "SELinux: Could not stat policy file %s: %s\n",
|
|
- path, strerror(errno));
|
|
+ fprintf(stderr, "SELinux: Could not stat policy file %s: %s\n",
|
|
+ pol_path, strerror(errno));
|
|
goto close;
|
|
}
|
|
|
|
@@ -195,13 +191,12 @@ checkbool:
|
|
size = sb.st_size;
|
|
data = map = mmap(NULL, size, prot, MAP_PRIVATE, fd, 0);
|
|
if (map == MAP_FAILED) {
|
|
- fprintf(stderr,
|
|
- "SELinux: Could not map policy file %s: %s\n",
|
|
- path, strerror(errno));
|
|
+ fprintf(stderr, "SELinux: Could not map policy file %s: %s\n",
|
|
+ pol_path, strerror(errno));
|
|
goto close;
|
|
}
|
|
|
|
- if (vers > kernvers && usesepol) {
|
|
+ if (maxvers > kernvers && usesepol) {
|
|
/* Need to downgrade to kernel-supported version. */
|
|
if (policy_file_create(&pf))
|
|
goto unmap;
|
|
@@ -220,12 +215,12 @@ checkbool:
|
|
/* Downgrade failed, keep searching. */
|
|
fprintf(stderr,
|
|
"SELinux: Could not downgrade policy file %s, searching for an older version.\n",
|
|
- path);
|
|
+ pol_path);
|
|
policy_file_free(pf);
|
|
policydb_free(policydb);
|
|
munmap(map, sb.st_size);
|
|
close(fd);
|
|
- vers--;
|
|
+ maxvers--;
|
|
goto search;
|
|
}
|
|
policy_file_free(pf);
|
|
@@ -281,7 +276,7 @@ checkbool:
|
|
if (rc)
|
|
fprintf(stderr,
|
|
"SELinux: Could not load policy file %s: %s\n",
|
|
- path, strerror(errno));
|
|
+ pol_path, strerror(errno));
|
|
|
|
unmap:
|
|
if (data != map)
|
|
@@ -296,6 +291,7 @@ checkbool:
|
|
if (libsepolh)
|
|
dlclose(libsepolh);
|
|
#endif
|
|
+ free(pol_path);
|
|
return rc;
|
|
}
|
|
|
|
diff --git a/libselinux/src/matchpathcon.c b/libselinux/src/matchpathcon.c
|
|
index 2d7369e..2a00807 100644
|
|
--- a/libselinux/src/matchpathcon.c
|
|
+++ b/libselinux/src/matchpathcon.c
|
|
@@ -2,6 +2,7 @@
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
+#include <syslog.h>
|
|
#include "selinux_internal.h"
|
|
#include "label_internal.h"
|
|
#include "callbacks.h"
|
|
@@ -62,7 +63,7 @@ static void
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
- vfprintf(stderr, fmt, ap);
|
|
+ vsyslog(LOG_ERR, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
diff --git a/libselinux/src/selinux_config.c b/libselinux/src/selinux_config.c
|
|
index 296f357..cb65666 100644
|
|
--- a/libselinux/src/selinux_config.c
|
|
+++ b/libselinux/src/selinux_config.c
|
|
@@ -9,6 +9,7 @@
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#include "selinux_internal.h"
|
|
+#include "policy.h"
|
|
#include "get_default_type_internal.h"
|
|
|
|
#define SELINUXDIR "/etc/selinux/"
|
|
@@ -296,13 +297,57 @@ const char *selinux_removable_context_path(void)
|
|
|
|
hidden_def(selinux_removable_context_path)
|
|
|
|
+char *selinux_binary_policy_path_min_max(int min, int *max)
|
|
+{
|
|
+ int ret;
|
|
+ char *path = NULL;
|
|
+
|
|
+ while(*max >= min) {
|
|
+ ret = asprintf(&path, "%s.%d", get_path(BINPOLICY), *max);
|
|
+ if (ret < 0)
|
|
+ goto err;
|
|
+ ret = access(path, R_OK);
|
|
+ if (!ret)
|
|
+ return path;
|
|
+ free(path);
|
|
+ path = NULL;
|
|
+ *max = *max - 1;
|
|
+ }
|
|
+err:
|
|
+ free(path);
|
|
+ return NULL;
|
|
+}
|
|
+hidden_def(selinux_binary_policy_path_min_max)
|
|
+
|
|
const char *selinux_binary_policy_path(void)
|
|
{
|
|
return get_path(BINPOLICY);
|
|
}
|
|
-
|
|
hidden_def(selinux_binary_policy_path)
|
|
|
|
+const char *selinux_current_policy_path(void)
|
|
+{
|
|
+ int rc = 0;
|
|
+ int vers = 0;
|
|
+ static char policy_path[PATH_MAX];
|
|
+
|
|
+ snprintf(policy_path, sizeof(policy_path), "%s/policy", selinux_mnt);
|
|
+ if (access(policy_path, F_OK) != 0 ) {
|
|
+ vers = security_policyvers();
|
|
+ do {
|
|
+ /* Check prior versions to see if old policy is available */
|
|
+ snprintf(policy_path, sizeof(policy_path), "%s.%d",
|
|
+ selinux_binary_policy_path(), vers);
|
|
+ } while ((rc = access(policy_path, F_OK)) && --vers > 0);
|
|
+
|
|
+ if (rc) return NULL;
|
|
+ }
|
|
+
|
|
+ return policy_path;
|
|
+}
|
|
+
|
|
+hidden_def(selinux_current_policy_path)
|
|
+
|
|
const char *selinux_file_context_path(void)
|
|
{
|
|
return get_path(FILE_CONTEXTS);
|
|
diff --git a/libselinux/src/selinux_internal.h b/libselinux/src/selinux_internal.h
|
|
index 2c7c85c..75ebc88 100644
|
|
--- a/libselinux/src/selinux_internal.h
|
|
+++ b/libselinux/src/selinux_internal.h
|
|
@@ -61,7 +61,9 @@ hidden_proto(selinux_mkload_policy)
|
|
hidden_proto(security_deny_unknown)
|
|
hidden_proto(selinux_boolean_sub)
|
|
hidden_proto(selinux_binary_policy_path)
|
|
+ hidden_proto(selinux_binary_policy_path_min_max);
|
|
hidden_proto(selinux_booleans_subs_path)
|
|
+ hidden_proto(selinux_current_policy_path)
|
|
hidden_proto(selinux_default_context_path)
|
|
hidden_proto(selinux_securetty_types_path)
|
|
hidden_proto(selinux_failsafe_context_path)
|
|
diff --git a/libselinux/src/seusers.c b/libselinux/src/seusers.c
|
|
index cfea186..8b1eba6 100644
|
|
--- a/libselinux/src/seusers.c
|
|
+++ b/libselinux/src/seusers.c
|
|
@@ -125,7 +125,7 @@ static int check_group(const char *group, const char *name, const gid_t gid) {
|
|
rbuf = malloc(rbuflen);
|
|
if (rbuf == NULL)
|
|
return 0;
|
|
- int retval = getgrnam_r(group, &gbuf, rbuf,
|
|
+ int retval = getgrnam_r(group, &gbuf, rbuf,
|
|
rbuflen, &grent);
|
|
if ( retval == ERANGE )
|
|
{
|
|
@@ -198,13 +198,13 @@ int getseuserbyname(const char *name, char **r_seuser, char **r_level)
|
|
if (!strcmp(username, name))
|
|
break;
|
|
|
|
- if (username[0] == '%' &&
|
|
- !groupseuser &&
|
|
+ if (username[0] == '%' &&
|
|
+ !groupseuser &&
|
|
check_group(&username[1], name, gid)) {
|
|
groupseuser = seuser;
|
|
grouplevel = level;
|
|
} else {
|
|
- if (!defaultseuser &&
|
|
+ if (!defaultseuser &&
|
|
!strcmp(username, "__default__")) {
|
|
defaultseuser = seuser;
|
|
defaultlevel = level;
|
|
@@ -258,7 +258,7 @@ int getseuserbyname(const char *name, char **r_seuser, char **r_level)
|
|
return 0;
|
|
}
|
|
|
|
-int getseuser(const char *username, const char *service,
|
|
+int getseuser(const char *username, const char *service,
|
|
char **r_seuser, char **r_level) {
|
|
int ret = -1;
|
|
int len = 0;
|
|
diff --git a/libselinux/src/stringrep.c b/libselinux/src/stringrep.c
|
|
index 176ac34..082778e 100644
|
|
--- a/libselinux/src/stringrep.c
|
|
+++ b/libselinux/src/stringrep.c
|
|
@@ -436,6 +436,27 @@ security_class_t string_to_security_class(const char *s)
|
|
return map_class(node->value);
|
|
}
|
|
|
|
+security_class_t mode_to_security_class(mode_t m) {
|
|
+
|
|
+ if (S_ISREG(m))
|
|
+ return string_to_security_class("file");
|
|
+ if (S_ISDIR(m))
|
|
+ return string_to_security_class("dir");
|
|
+ if (S_ISCHR(m))
|
|
+ return string_to_security_class("chr_file");
|
|
+ if (S_ISBLK(m))
|
|
+ return string_to_security_class("blk_file");
|
|
+ if (S_ISFIFO(m))
|
|
+ return string_to_security_class("fifo_file");
|
|
+ if (S_ISLNK(m))
|
|
+ return string_to_security_class("lnk_file");
|
|
+ if (S_ISSOCK(m))
|
|
+ return string_to_security_class("sock_file");
|
|
+
|
|
+ errno=EINVAL;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
access_vector_t string_to_av_perm(security_class_t tclass, const char *s)
|
|
{
|
|
struct discover_class_node *node;
|
|
diff --git a/libselinux/utils/.gitignore b/libselinux/utils/.gitignore
|
|
index 8b9294d..060eaab 100644
|
|
--- a/libselinux/utils/.gitignore
|
|
+++ b/libselinux/utils/.gitignore
|
|
@@ -13,6 +13,7 @@ getsebool
|
|
getseuser
|
|
matchpathcon
|
|
policyvers
|
|
+sefcontext_compile
|
|
selinux_check_securetty_context
|
|
selinuxenabled
|
|
selinuxexeccon
|
|
diff --git a/libselinux/utils/Makefile b/libselinux/utils/Makefile
|
|
index 5f3e047..f469924 100644
|
|
--- a/libselinux/utils/Makefile
|
|
+++ b/libselinux/utils/Makefile
|
|
@@ -28,6 +28,7 @@ LDLIBS += -L../src -lselinux -L$(LIBDIR)
|
|
|
|
TARGETS=$(patsubst %.c,%,$(wildcard *.c))
|
|
|
|
+sefcontext_compile: LDLIBS += -lpcre
|
|
|
|
ifeq ($(DISABLE_AVC),y)
|
|
UNUSED_TARGETS+=compute_av compute_create compute_member compute_relabel
|
|
diff --git a/libselinux/utils/sefcontext_compile.c b/libselinux/utils/sefcontext_compile.c
|
|
new file mode 100644
|
|
index 0000000..15cc836
|
|
--- /dev/null
|
|
+++ b/libselinux/utils/sefcontext_compile.c
|
|
@@ -0,0 +1,350 @@
|
|
+#include <ctype.h>
|
|
+#include <errno.h>
|
|
+#include <pcre.h>
|
|
+#include <stdint.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include <linux/limits.h>
|
|
+
|
|
+#include "../src/label_file.h"
|
|
+
|
|
+static int process_file(struct saved_data *data, const char *filename)
|
|
+{
|
|
+ struct spec *spec;
|
|
+ unsigned int line_num;
|
|
+ char *line_buf = NULL;
|
|
+ size_t line_len;
|
|
+ ssize_t len;
|
|
+ FILE *context_file;
|
|
+
|
|
+ context_file = fopen(filename, "r");
|
|
+ if (!context_file) {
|
|
+ fprintf(stderr, "Error opening %s: %s\n", filename, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ line_num = 0;
|
|
+ while ((len = getline(&line_buf, &line_len, context_file)) != -1) {
|
|
+ char *context;
|
|
+ char *mode;
|
|
+ char *regex;
|
|
+ char *cp, *anchored_regex;
|
|
+ char *buf_p;
|
|
+ pcre *re;
|
|
+ pcre_extra *sd;
|
|
+ const char *err;
|
|
+ int items, erroff, rc;
|
|
+ size_t regex_len;
|
|
+ int32_t stem_id;
|
|
+
|
|
+ len = strlen(line_buf);
|
|
+ if (line_buf[len - 1] == '\n')
|
|
+ line_buf[len - 1] = 0;
|
|
+ buf_p = line_buf;
|
|
+ while (isspace(*buf_p))
|
|
+ buf_p++;
|
|
+ /* Skip comment lines and empty lines. */
|
|
+ if (*buf_p == '#' || *buf_p == 0)
|
|
+ continue;
|
|
+
|
|
+ items = sscanf(line_buf, "%ms %ms %ms", ®ex, &mode, &context);
|
|
+ if (items < 2 || items > 3) {
|
|
+ fprintf(stderr, "invalid entry, skipping:%s", line_buf);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (items == 2) {
|
|
+ context = mode;
|
|
+ mode = NULL;
|
|
+ }
|
|
+
|
|
+ rc = grow_specs(data);
|
|
+ if (rc) {
|
|
+ fprintf(stderr, "grow_specs failed: %s\n", strerror(errno));
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ spec = &data->spec_arr[data->nspec];
|
|
+
|
|
+ spec->lr.ctx_raw = context;
|
|
+ spec->mode = string_to_mode(mode);
|
|
+ if (spec->mode == -1) {
|
|
+ fprintf(stderr, "%s: line %d has invalid file type %s\n",
|
|
+ regex, line_num + 1, mode);
|
|
+ spec->mode = 0;
|
|
+ }
|
|
+ free(mode);
|
|
+ spec->regex_str = regex;
|
|
+
|
|
+ stem_id = find_stem_from_spec(data, regex);
|
|
+ spec->stem_id = stem_id;
|
|
+ /* skip past the fixed stem part */
|
|
+ if (stem_id != -1)
|
|
+ regex += data->stem_arr[stem_id].len;
|
|
+
|
|
+ regex_len = strlen(regex);
|
|
+ cp = anchored_regex = malloc(regex_len + 3);
|
|
+ if (!cp) {
|
|
+ fprintf(stderr, "Malloc Failed: %s\n", strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+ *cp++ = '^';
|
|
+ memcpy(cp, regex, regex_len);
|
|
+ cp += regex_len;
|
|
+ *cp++ = '$';
|
|
+ *cp = '\0';
|
|
+
|
|
+ spec_hasMetaChars(spec);
|
|
+
|
|
+ re = pcre_compile(anchored_regex, 0, &err, &erroff, NULL);
|
|
+ if (!re) {
|
|
+ fprintf(stderr, "PCRE compilation failed for %s at offset %d: %s\n", anchored_regex, erroff, err);
|
|
+ return -1;
|
|
+ }
|
|
+ spec->regex = re;
|
|
+
|
|
+ sd = pcre_study(re, 0, &err);
|
|
+ if (!sd) {
|
|
+ fprintf(stderr, "PCRE study failed for %s: %s\n", anchored_regex, err);
|
|
+ return -1;
|
|
+ }
|
|
+ free(anchored_regex);
|
|
+ spec->sd = sd;
|
|
+
|
|
+ line_num++;
|
|
+ data->nspec++;
|
|
+ }
|
|
+
|
|
+ free(line_buf);
|
|
+ fclose(context_file);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * File Format
|
|
+ *
|
|
+ * u32 - magic number
|
|
+ * u32 - version
|
|
+ * u32 - number of stems
|
|
+ * ** Stems
|
|
+ * u32 - length of stem EXCLUDING nul
|
|
+ * char - stem char array INCLUDING nul
|
|
+ * u32 - number of regexs
|
|
+ * ** Regexes
|
|
+ * u32 - length of upcoming context INCLUDING nul
|
|
+ * char - char array of the raw context
|
|
+ * u32 - length of the upcoming regex_str
|
|
+ * char - char array of the original regex string including the stem.
|
|
+ * mode_t - mode bits
|
|
+ * s32 - stemid associated with the regex
|
|
+ * u32 - spec has meta characters
|
|
+ * u32 - data length of the pcre regex
|
|
+ * char - a bufer holding the raw pcre regex info
|
|
+ * u32 - data length of the pcre regex study daya
|
|
+ * char - a buffer holding the raw pcre regex study data
|
|
+ */
|
|
+static int write_binary_file(struct saved_data *data, char *filename)
|
|
+{
|
|
+ struct spec *specs = data->spec_arr;
|
|
+ FILE *bin_file;
|
|
+ size_t len;
|
|
+ uint32_t magic = SELINUX_MAGIC_COMPILED_FCONTEXT;
|
|
+ uint32_t section_len;
|
|
+ uint32_t i;
|
|
+
|
|
+ bin_file = fopen(filename, "w");
|
|
+ if (!bin_file) {
|
|
+ perror("fopen output_file");
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+
|
|
+ /* write some magic number */
|
|
+ len = fwrite(&magic, sizeof(uint32_t), 1, bin_file);
|
|
+ if (len != 1)
|
|
+ return -1;
|
|
+
|
|
+ /* write the version */
|
|
+ section_len = SELINUX_COMPILED_FCONTEXT_MAX_VERS;
|
|
+ len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file);
|
|
+ if (len != 1)
|
|
+ return -1;
|
|
+
|
|
+ /* write the number of stems coming */
|
|
+ section_len = data->num_stems;
|
|
+ len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file);
|
|
+ if (len != 1)
|
|
+ return -1;
|
|
+
|
|
+ for (i = 0; i < section_len; i++) {
|
|
+ char *stem = data->stem_arr[i].buf;
|
|
+ uint32_t stem_len = data->stem_arr[i].len;
|
|
+
|
|
+ /* write the strlen (aka no nul) */
|
|
+ len = fwrite(&stem_len, sizeof(uint32_t), 1, bin_file);
|
|
+ if (len != 1)
|
|
+ return -1;
|
|
+
|
|
+ /* include the nul in the file */
|
|
+ stem_len += 1;
|
|
+ len = fwrite(stem, sizeof(char), stem_len, bin_file);
|
|
+ if (len != stem_len)
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ /* write the number of regexes coming */
|
|
+ section_len = data->nspec;
|
|
+ len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file);
|
|
+ if (len != 1)
|
|
+ return -1;
|
|
+
|
|
+ for (i = 0; i < section_len; i++) {
|
|
+ char *context = specs[i].lr.ctx_raw;
|
|
+ char *regex_str = specs[i].regex_str;
|
|
+ mode_t mode = specs[i].mode;
|
|
+ int32_t stem_id = specs[i].stem_id;
|
|
+ pcre *re = specs[i].regex;
|
|
+ pcre_extra *sd = get_pcre_extra(&specs[i]);
|
|
+ uint32_t to_write;
|
|
+ size_t size;
|
|
+ int rc;
|
|
+
|
|
+ /* length of the context string (including nul) */
|
|
+ to_write = strlen(context) + 1;
|
|
+ len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file);
|
|
+ if (len != 1)
|
|
+ return -1;
|
|
+
|
|
+ /* original context strin (including nul) */
|
|
+ len = fwrite(context, sizeof(char), to_write, bin_file);
|
|
+ if (len != to_write)
|
|
+ return -1;
|
|
+
|
|
+ /* length of the original regex string (including nul) */
|
|
+ to_write = strlen(regex_str) + 1;
|
|
+ len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file);
|
|
+ if (len != 1)
|
|
+ return -1;
|
|
+
|
|
+ /* original regex string */
|
|
+ len = fwrite(regex_str, sizeof(char), to_write, bin_file);
|
|
+ if (len != to_write)
|
|
+ return -1;
|
|
+
|
|
+ /* binary F_MODE bits */
|
|
+ len = fwrite(&mode, sizeof(mode), 1, bin_file);
|
|
+ if (len != 1)
|
|
+ return -1;
|
|
+
|
|
+ /* stem for this regex (could be -1) */
|
|
+ len = fwrite(&stem_id, sizeof(stem_id), 1, bin_file);
|
|
+ if (len != 1)
|
|
+ return -1;
|
|
+
|
|
+ /* does this spec have a metaChar? */
|
|
+ to_write = specs[i].hasMetaChars;
|
|
+ len = fwrite(&to_write, sizeof(to_write), 1, bin_file);
|
|
+ if (len != 1)
|
|
+ return -1;
|
|
+
|
|
+ /* determine the size of the pcre data in bytes */
|
|
+ rc = pcre_fullinfo(re, NULL, PCRE_INFO_SIZE, &size);
|
|
+ if (rc < 0)
|
|
+ return -1;
|
|
+
|
|
+ /* write the number of bytes in the pcre data */
|
|
+ to_write = size;
|
|
+ len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file);
|
|
+ if (len != 1)
|
|
+ return -1;
|
|
+
|
|
+ /* write the actual pcre data as a char array */
|
|
+ len = fwrite(re, 1, to_write, bin_file);
|
|
+ if (len != to_write)
|
|
+ return -1;
|
|
+
|
|
+ /* determine the size of the pcre study info */
|
|
+ rc = pcre_fullinfo(re, sd, PCRE_INFO_STUDYSIZE, &size);
|
|
+ if (rc < 0)
|
|
+ return -1;
|
|
+
|
|
+ /* write the number of bytes in the pcre study data */
|
|
+ to_write = size;
|
|
+ len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file);
|
|
+ if (len != 1)
|
|
+ return -1;
|
|
+
|
|
+ /* write the actual pcre study data as a char array */
|
|
+ len = fwrite(sd->study_data, 1, to_write, bin_file);
|
|
+ if (len != to_write)
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ fclose(bin_file);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int free_specs(struct saved_data *data)
|
|
+{
|
|
+ struct spec *specs = data->spec_arr;
|
|
+ unsigned int num_entries = data->nspec;
|
|
+ unsigned int i;
|
|
+
|
|
+ for (i = 0; i < num_entries; i++) {
|
|
+ free(specs[i].lr.ctx_raw);
|
|
+ free(specs[i].lr.ctx_trans);
|
|
+ free(specs[i].regex_str);
|
|
+ pcre_free(specs[i].regex);
|
|
+ pcre_free_study(specs[i].sd);
|
|
+ }
|
|
+ free(specs);
|
|
+
|
|
+ num_entries = data->num_stems;
|
|
+ for (i = 0; i < num_entries; i++) {
|
|
+ free(data->stem_arr[i].buf);
|
|
+ }
|
|
+ free(data->stem_arr);
|
|
+
|
|
+ memset(data, 0, sizeof(*data));
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int main(int argc, char *argv[])
|
|
+{
|
|
+ struct saved_data data;
|
|
+ const char *path;
|
|
+ char stack_path[PATH_MAX + 1];
|
|
+ int rc;
|
|
+
|
|
+ if (argc != 2) {
|
|
+ fprintf(stderr, "usage: %s input_file\n", argv[0]);
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+
|
|
+ memset(&data, 0, sizeof(data));
|
|
+
|
|
+ path = argv[1];
|
|
+
|
|
+ rc = process_file(&data, path);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ rc = sort_specs(&data);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ rc = snprintf(stack_path, sizeof(stack_path), "%s.bin", path);
|
|
+ if (rc < 0 || rc >= sizeof(stack_path))
|
|
+ return rc;
|
|
+ rc = write_binary_file(&data, stack_path);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ rc = free_specs(&data);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ return 0;
|
|
+}
|