No issues found
 1 #include <unistd.h>
 2 #include <stdlib.h>
 3 #include <stdio.h>
 4 #include <errno.h>
 5 #include <getopt.h>
 6 #include <string.h>
 7 #include <selinux/selinux.h>
 8 #include <sepol/sepol.h>
 9 #ifdef USE_NLS
10 #include <locale.h>		/* for setlocale() */
11 #include <libintl.h>		/* for gettext() */
12 #define _(msgid) gettext (msgid)
13 #else
14 #define _(msgid) (msgid)
15 #endif
16 #ifndef PACKAGE
17 #define PACKAGE "policycoreutils"	/* the name of this package lang translation */
18 #endif
19 
20 void usage(char *progname)
21 {
22 	fprintf(stderr, _("usage:  %s [-qi]\n"), progname);
23 	exit(1);
24 }
25 
26 int main(int argc, char **argv)
27 {
28 	int ret, opt, quiet = 0, nargs, init=0, enforce=0;
29 
30 #ifdef USE_NLS
31 	setlocale(LC_ALL, "");
32 	bindtextdomain(PACKAGE, LOCALEDIR);
33 	textdomain(PACKAGE);
34 #endif
35 
36 	while ((opt = getopt(argc, argv, "bqi")) > 0) {
37 		switch (opt) {
38 		case 'b':
39 			fprintf(stderr, "%s:  Warning! The -b option is no longer supported, booleans are always preserved across reloads.  Continuing...\n",
40 				argv[0]);
41 			break;
42 		case 'q':
43 			quiet = 1;
44 			sepol_debug(0);
45 			break;
46 		case 'i':
47 			init = 1;
48 			break;
49 		default:
50 			usage(argv[0]);
51 		}
52 	}
53 
54 	nargs = argc - optind;
55 	if (nargs > 2)
56 		usage(argv[0]);
57 	if (nargs >= 1 && !quiet) {
58 			fprintf(stderr,
59 				"%s:  Warning!  Policy file argument (%s) is no longer supported, installed policy is always loaded.  Continuing...\n",
60 				argv[0], argv[optind++]);
61 	}
62 	if (nargs == 2 && ! quiet) {
63 		fprintf(stderr,
64 			"%s:  Warning!  Boolean file argument (%s) is no longer supported, installed booleans file is always used.  Continuing...\n",
65 			argv[0], argv[optind++]);
66 	}
67 	if (init) {
68 		if (is_selinux_enabled() == 1) {
69 			/* SELinux is already enabled, we should not do an initial load again */
70 			fprintf(stderr,
71 					_("%s:  Policy is already loaded and initial load requested\n"),
72 					argv[0]);
73 			exit(2);
74 		}
75 		ret = selinux_init_load_policy(&enforce);
76 		if (ret != 0 ) {
77 			if (enforce > 0) {
78 				/* SELinux in enforcing mode but load_policy failed */
79 				fprintf(stderr,
80 						_("%s:  Can't load policy and enforcing mode requested:  %s\n"),
81 						argv[0], strerror(errno));
82 				exit(3);
83 			}
84 		}
85 	}
86 	else {
87 		ret = selinux_mkload_policy(1);
88 	}
89 	if (ret < 0) {
90 		fprintf(stderr, _("%s:  Can't load policy:  %s\n"),
91 			argv[0], strerror(errno));
92 		exit(2);
93 	}
94 	exit(0);
95 }
No issues found
  1 /* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
  2 
  3 /* FLASK */
  4 
  5 /*
  6  * Implementation of the hash table type.
  7  */
  8 
  9 #include <stdlib.h>
 10 #include <string.h>
 11 #include "hashtab.h"
 12 
 13 hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h,
 14 						     const hashtab_key_t key),
 15 			 int (*keycmp) (hashtab_t h,
 16 					const hashtab_key_t key1,
 17 					const hashtab_key_t key2),
 18 			 unsigned int size)
 19 {
 20 
 21 	hashtab_t p;
 22 	unsigned int i;
 23 
 24 	p = (hashtab_t) malloc(sizeof(hashtab_val_t));
 25 	if (p == NULL)
 26 		return p;
 27 
 28 	memset(p, 0, sizeof(hashtab_val_t));
 29 	p->size = size;
 30 	p->nel = 0;
 31 	p->hash_value = hash_value;
 32 	p->keycmp = keycmp;
 33 	p->htable = (hashtab_ptr_t *) malloc(sizeof(hashtab_ptr_t) * size);
 34 	if (p->htable == NULL) {
 35 		free(p);
 36 		return NULL;
 37 	}
 38 	for (i = 0; i < size; i++)
 39 		p->htable[i] = (hashtab_ptr_t) NULL;
 40 
 41 	return p;
 42 }
 43 
 44 int hashtab_insert(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum)
 45 {
 46 	int hvalue;
 47 	hashtab_ptr_t prev, cur, newnode;
 48 
 49 	if (!h)
 50 		return HASHTAB_OVERFLOW;
 51 
 52 	hvalue = h->hash_value(h, key);
 53 	prev = NULL;
 54 	cur = h->htable[hvalue];
 55 	while (cur && h->keycmp(h, key, cur->key) > 0) {
 56 		prev = cur;
 57 		cur = cur->next;
 58 	}
 59 
 60 	if (cur && (h->keycmp(h, key, cur->key) == 0))
 61 		return HASHTAB_PRESENT;
 62 
 63 	newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t));
 64 	if (newnode == NULL)
 65 		return HASHTAB_OVERFLOW;
 66 	memset(newnode, 0, sizeof(struct hashtab_node));
 67 	newnode->key = key;
 68 	newnode->datum = datum;
 69 	if (prev) {
 70 		newnode->next = prev->next;
 71 		prev->next = newnode;
 72 	} else {
 73 		newnode->next = h->htable[hvalue];
 74 		h->htable[hvalue] = newnode;
 75 	}
 76 
 77 	h->nel++;
 78 	return HASHTAB_SUCCESS;
 79 }
 80 
 81 int hashtab_remove(hashtab_t h, hashtab_key_t key,
 82 		   void (*destroy) (hashtab_key_t k,
 83 				    hashtab_datum_t d, void *args), void *args)
 84 {
 85 	int hvalue;
 86 	hashtab_ptr_t cur, last;
 87 
 88 	if (!h)
 89 		return HASHTAB_MISSING;
 90 
 91 	hvalue = h->hash_value(h, key);
 92 	last = NULL;
 93 	cur = h->htable[hvalue];
 94 	while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
 95 		last = cur;
 96 		cur = cur->next;
 97 	}
 98 
 99 	if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
100 		return HASHTAB_MISSING;
101 
102 	if (last == NULL)
103 		h->htable[hvalue] = cur->next;
104 	else
105 		last->next = cur->next;
106 
107 	if (destroy)
108 		destroy(cur->key, cur->datum, args);
109 	free(cur);
110 	h->nel--;
111 	return HASHTAB_SUCCESS;
112 }
113 
114 int hashtab_replace(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum,
115 		    void (*destroy) (hashtab_key_t k,
116 				     hashtab_datum_t d, void *args), void *args)
117 {
118 	int hvalue;
119 	hashtab_ptr_t prev, cur, newnode;
120 
121 	if (!h)
122 		return HASHTAB_OVERFLOW;
123 
124 	hvalue = h->hash_value(h, key);
125 	prev = NULL;
126 	cur = h->htable[hvalue];
127 	while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
128 		prev = cur;
129 		cur = cur->next;
130 	}
131 
132 	if (cur && (h->keycmp(h, key, cur->key) == 0)) {
133 		if (destroy)
134 			destroy(cur->key, cur->datum, args);
135 		cur->key = key;
136 		cur->datum = datum;
137 	} else {
138 		newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t));
139 		if (newnode == NULL)
140 			return HASHTAB_OVERFLOW;
141 		memset(newnode, 0, sizeof(struct hashtab_node));
142 		newnode->key = key;
143 		newnode->datum = datum;
144 		if (prev) {
145 			newnode->next = prev->next;
146 			prev->next = newnode;
147 		} else {
148 			newnode->next = h->htable[hvalue];
149 			h->htable[hvalue] = newnode;
150 		}
151 	}
152 
153 	return HASHTAB_SUCCESS;
154 }
155 
156 hashtab_datum_t hashtab_search(hashtab_t h, const hashtab_key_t key)
157 {
158 
159 	int hvalue;
160 	hashtab_ptr_t cur;
161 
162 	if (!h)
163 		return NULL;
164 
165 	hvalue = h->hash_value(h, key);
166 	cur = h->htable[hvalue];
167 	while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
168 		cur = cur->next;
169 
170 	if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
171 		return NULL;
172 
173 	return cur->datum;
174 }
175 
176 void hashtab_destroy(hashtab_t h)
177 {
178 	unsigned int i;
179 	hashtab_ptr_t cur, temp;
180 
181 	if (!h)
182 		return;
183 
184 	for (i = 0; i < h->size; i++) {
185 		cur = h->htable[i];
186 		while (cur != NULL) {
187 			temp = cur;
188 			cur = cur->next;
189 			free(temp);
190 		}
191 		h->htable[i] = NULL;
192 	}
193 
194 	free(h->htable);
195 	h->htable = NULL;
196 
197 	free(h);
198 }
199 
200 int hashtab_map(hashtab_t h,
201 		int (*apply) (hashtab_key_t k,
202 			      hashtab_datum_t d, void *args), void *args)
203 {
204 	unsigned int i, ret;
205 	hashtab_ptr_t cur;
206 
207 	if (!h)
208 		return HASHTAB_SUCCESS;
209 
210 	for (i = 0; i < h->size; i++) {
211 		cur = h->htable[i];
212 		while (cur != NULL) {
213 			ret = apply(cur->key, cur->datum, args);
214 			if (ret)
215 				return ret;
216 			cur = cur->next;
217 		}
218 	}
219 	return HASHTAB_SUCCESS;
220 }
221 
222 void hashtab_map_remove_on_error(hashtab_t h,
223 				 int (*apply) (hashtab_key_t k,
224 					       hashtab_datum_t d,
225 					       void *args),
226 				 void (*destroy) (hashtab_key_t k,
227 						  hashtab_datum_t d,
228 						  void *args), void *args)
229 {
230 	unsigned int i;
231 	int ret;
232 	hashtab_ptr_t last, cur, temp;
233 
234 	if (!h)
235 		return;
236 
237 	for (i = 0; i < h->size; i++) {
238 		last = NULL;
239 		cur = h->htable[i];
240 		while (cur != NULL) {
241 			ret = apply(cur->key, cur->datum, args);
242 			if (ret) {
243 				if (last) {
244 					last->next = cur->next;
245 				} else {
246 					h->htable[i] = cur->next;
247 				}
248 
249 				temp = cur;
250 				cur = cur->next;
251 				if (destroy)
252 					destroy(temp->key, temp->datum, args);
253 				free(temp);
254 				h->nel--;
255 			} else {
256 				last = cur;
257 				cur = cur->next;
258 			}
259 		}
260 	}
261 
262 	return;
263 }
264 
265 void hashtab_hash_eval(hashtab_t h, char *tag)
266 {
267 	unsigned int i;
268 	int chain_len, slots_used, max_chain_len;
269 	hashtab_ptr_t cur;
270 
271 	slots_used = 0;
272 	max_chain_len = 0;
273 	for (i = 0; i < h->size; i++) {
274 		cur = h->htable[i];
275 		if (cur) {
276 			slots_used++;
277 			chain_len = 0;
278 			while (cur) {
279 				chain_len++;
280 				cur = cur->next;
281 			}
282 
283 			if (chain_len > max_chain_len)
284 				max_chain_len = chain_len;
285 		}
286 	}
287 
288 	printf
289 	    ("%s:  %d entries and %d/%d buckets used, longest chain length %d\n",
290 	     tag, h->nel, slots_used, h->size, max_chain_len);
291 }
| Location | Tool | Test ID | Issue | |
|---|---|---|---|---|
| newrole.c:327:0 | cppcheck | useClosedFile | Used file that is not opened. | 
   1 /************************************************************************
   2  *
   3  * newrole
   4  *
   5  * SYNOPSIS:
   6  *
   7  * This program allows a user to change their SELinux RBAC role and/or
   8  * SELinux TE type (domain) in a manner similar to the way the traditional
   9  * UNIX su program allows a user to change their identity.
  10  *
  11  * USAGE:
  12  *
  13  * newrole [ -r role ] [ -t type ] [ -l level ] [ -V ] [ -- args ]
  14  *
  15  * BUILD OPTIONS:
  16  *
  17  * option USE_PAM:
  18  *
  19  * Set the USE_PAM constant if you want to authenticate users via PAM.
  20  * If USE_PAM is not set, users will be authenticated via direct
  21  * access to the shadow password file.
  22  *
  23  * If you decide to use PAM must be told how to handle newrole.  A
  24  * good rule-of-thumb might be to tell PAM to handle newrole in the
  25  * same way it handles su, except that you should remove the pam_rootok.so
  26  * entry so that even root must re-authenticate to change roles. 
  27  *
  28  * If you choose not to use PAM, make sure you have a shadow passwd file
  29  * in /etc/shadow.  You can use a symlink if your shadow passwd file
  30  * lives in another directory.  Example:
  31  *   su
  32  *   cd /etc
  33  *   ln -s /etc/auth/shadow shadow
  34  *
  35  * If you decide not to use PAM, you will also have to make newrole
  36  * setuid root, so that it can read the shadow passwd file.
  37  * 
  38  *
  39  * Authors:
  40  *      Anthony Colatrella
  41  *	Tim Fraser
  42  *	Steve Grubb <sgrubb@redhat.com>
  43  *	Darrel Goeddel <DGoeddel@trustedcs.com>
  44  *	Michael Thompson <mcthomps@us.ibm.com>
  45  *	Dan Walsh <dwalsh@redhat.com>
  46  *
  47  *************************************************************************/
  48 
  49 #define _GNU_SOURCE
  50 
  51 #if defined(AUDIT_LOG_PRIV) && !defined(USE_AUDIT)
  52 #error AUDIT_LOG_PRIV needs the USE_AUDIT option
  53 #endif
  54 #if defined(NAMESPACE_PRIV) && !defined(USE_PAM)
  55 #error NAMESPACE_PRIV needs the USE_PAM option
  56 #endif
  57 
  58 #include <stdio.h>
  59 #include <stdlib.h>		/* for malloc(), realloc(), free() */
  60 #include <pwd.h>		/* for getpwuid() */
  61 #include <ctype.h>
  62 #include <sys/types.h>		/* to make getuid() and getpwuid() happy */
  63 #include <sys/wait.h>		/* for wait() */
  64 #include <getopt.h>		/* for getopt_long() form of getopt() */
  65 #include <fcntl.h>
  66 #include <string.h>
  67 #include <errno.h>
  68 #include <selinux/selinux.h>	/* for is_selinux_enabled() */
  69 #include <selinux/flask.h>	/* for SECCLASS_CHR_FILE */
  70 #include <selinux/context.h>	/* for context-mangling functions */
  71 #include <selinux/get_default_type.h>
  72 #include <selinux/get_context_list.h>	/* for SELINUX_DEFAULTUSER */
  73 #include <signal.h>
  74 #include <unistd.h>		/* for getuid(), exit(), getopt() */
  75 #ifdef USE_AUDIT
  76 #include <libaudit.h>
  77 #endif
  78 #if defined(AUDIT_LOG_PRIV) || (NAMESPACE_PRIV)
  79 #include <sys/prctl.h>
  80 #include <cap-ng.h>
  81 #endif
  82 #ifdef USE_NLS
  83 #include <locale.h>		/* for setlocale() */
  84 #include <libintl.h>		/* for gettext() */
  85 #define _(msgid) gettext (msgid)
  86 #else
  87 #define _(msgid) (msgid)
  88 #endif
  89 #ifndef PACKAGE
  90 #define PACKAGE "policycoreutils"	/* the name of this package lang translation */
  91 #endif
  92 
  93 #define TRUE 1
  94 #define FALSE 0
  95 
  96 /* USAGE_STRING describes the command-line args of this program. */
  97 #define USAGE_STRING "USAGE: newrole [ -r role ] [ -t type ] [ -l level ] [ -p ] [ -V ] [ -- args ]"
  98 
  99 #ifdef USE_PAM
 100 #define PAM_SERVICE_CONFIG "/etc/selinux/newrole_pam.conf";
 101 #endif
 102 
 103 #define DEFAULT_PATH "/usr/bin:/bin"
 104 #define DEFAULT_CONTEXT_SIZE 255	/* first guess at context size */
 105 
 106 extern char **environ;
 107 
 108 /**
 109  * Construct from the current range and specified desired level a resulting
 110  * range. If the specified level is a range, return that. If it is not, then
 111  * construct a range with level as the sensitivity and clearance of the current
 112  * context.
 113  *
 114  * newlevel - the level specified on the command line
 115  * range    - the range in the current context
 116  *
 117  * Returns malloc'd memory
 118  */
 119 static char *build_new_range(char *newlevel, const char *range)
 120 {
 121 	char *newrangep = NULL;
 122 	const char *tmpptr;
 123 	size_t len;
 124 
 125 	/* a missing or empty string */
 126 	if (!range || !strlen(range) || !newlevel || !strlen(newlevel))
 127 		return NULL;
 128 
 129 	/* if the newlevel is actually a range - just use that */
 130 	if (strchr(newlevel, '-')) {
 131 		newrangep = strdup(newlevel);
 132 		return newrangep;
 133 	}
 134 
 135 	/* look for MLS range in current context */
 136 	tmpptr = strchr(range, '-');
 137 	if (tmpptr) {
 138 		/* we are inserting into a ranged MLS context */
 139 		len = strlen(newlevel) + 1 + strlen(tmpptr + 1) + 1;
 140 		newrangep = (char *)malloc(len);
 141 		if (!newrangep)
 142 			return NULL;
 143 		snprintf(newrangep, len, "%s-%s", newlevel, tmpptr + 1);
 144 	} else {
 145 		/* we are inserting into a currently non-ranged MLS context */
 146 		if (!strcmp(newlevel, range)) {
 147 			newrangep = strdup(range);
 148 		} else {
 149 			len = strlen(newlevel) + 1 + strlen(range) + 1;
 150 			newrangep = (char *)malloc(len);
 151 			if (!newrangep)
 152 				return NULL;
 153 			snprintf(newrangep, len, "%s-%s", newlevel, range);
 154 		}
 155 	}
 156 
 157 	return newrangep;
 158 }
 159 
 160 #ifdef USE_PAM
 161 
 162 /************************************************************************
 163  *
 164  * All PAM code goes in this section.
 165  *
 166  ************************************************************************/
 167 #include <security/pam_appl.h>	/* for PAM functions */
 168 #include <security/pam_misc.h>	/* for misc_conv PAM utility function */
 169 
 170 char *service_name = "newrole";
 171 
 172 /* authenticate_via_pam()
 173  *
 174  * in:     pw - struct containing data from our user's line in 
 175  *                         the passwd file.
 176  * out:    nothing
 177  * return: value   condition
 178  *         -----   ---------
 179  *           1     PAM thinks that the user authenticated themselves properly
 180  *           0     otherwise
 181  *
 182  * This function uses PAM to authenticate the user running this
 183  * program.  This is the only function in this program that makes PAM
 184  * calls.
 185  */
 186 int authenticate_via_pam(const char *ttyn, pam_handle_t * pam_handle)
 187 {
 188 
 189 	int result = 0;		/* set to 0 (not authenticated) by default */
 190 	int pam_rc;		/* pam return code */
 191 	const char *tty_name;
 192 
 193 	if (ttyn) {
 194 		if (strncmp(ttyn, "/dev/", 5) == 0)
 195 			tty_name = ttyn + 5;
 196 		else
 197 			tty_name = ttyn;
 198 
 199 		pam_rc = pam_set_item(pam_handle, PAM_TTY, tty_name);
 200 		if (pam_rc != PAM_SUCCESS) {
 201 			fprintf(stderr, _("failed to set PAM_TTY\n"));
 202 			goto out;
 203 		}
 204 	}
 205 
 206 	/* Ask PAM to authenticate the user running this program */
 207 	pam_rc = pam_authenticate(pam_handle, 0);
 208 	if (pam_rc != PAM_SUCCESS) {
 209 		goto out;
 210 	}
 211 
 212 	/* Ask PAM to verify acct_mgmt */
 213 	pam_rc = pam_acct_mgmt(pam_handle, 0);
 214 	if (pam_rc == PAM_SUCCESS) {
 215 		result = 1;	/* user authenticated OK! */
 216 	}
 217 
 218       out:
 219 	return result;
 220 }				/* authenticate_via_pam() */
 221 
 222 #include "hashtab.h"
 223 
 224 static int free_hashtab_entry(hashtab_key_t key, hashtab_datum_t d,
 225 			      void *args __attribute__ ((unused)))
 226 {
 227 	free(key);
 228 	free(d);
 229 	return 0;
 230 }
 231 
 232 static unsigned int reqsymhash(hashtab_t h, hashtab_key_t key)
 233 {
 234 	char *p, *keyp;
 235 	size_t size;
 236 	unsigned int val;
 237 
 238 	val = 0;
 239 	keyp = (char *)key;
 240 	size = strlen(keyp);
 241 	for (p = keyp; ((size_t) (p - keyp)) < size; p++)
 242 		val =
 243 		    (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
 244 	return val & (h->size - 1);
 245 }
 246 
 247 static int reqsymcmp(hashtab_t h
 248 		     __attribute__ ((unused)), hashtab_key_t key1,
 249 		     hashtab_key_t key2)
 250 {
 251 	char *keyp1, *keyp2;
 252 
 253 	keyp1 = (char *)key1;
 254 	keyp2 = (char *)key2;
 255 	return strcmp(keyp1, keyp2);
 256 }
 257 
 258 static hashtab_t app_service_names = NULL;
 259 #define PAM_SERVICE_SLOTS 64
 260 
 261 static int process_pam_config(FILE * cfg)
 262 {
 263 	const char *config_file_path = PAM_SERVICE_CONFIG;
 264 	char *line_buf = NULL;
 265 	unsigned long lineno = 0;
 266 	size_t len = 0;
 267 	char *app = NULL;
 268 	char *service = NULL;
 269 	int ret;
 270 
 271 	while (getline(&line_buf, &len, cfg) > 0) {
 272 		char *buffer = line_buf;
 273 		lineno++;
 274 		while (isspace(*buffer))
 275 			buffer++;
 276 		if (buffer[0] == '#')
 277 			continue;
 278 		if (buffer[0] == '\n' || buffer[0] == '\0')
 279 			continue;
 280 
 281 		app = service = NULL;
 282 		ret = sscanf(buffer, "%as %as\n", &app, &service);
 283 		if (ret < 2 || !app || !service)
 284 			goto err;
 285 
 286 		ret = hashtab_insert(app_service_names, app, service);
 287 		if (ret == HASHTAB_OVERFLOW) {
 288 			fprintf(stderr,
 289 				_
 290 				("newrole: service name configuration hashtable overflow\n"));
 291 			goto err;
 292 		}
 293 	}
 294 
 295 	free(line_buf);
 296 	return 0;
 297       err:
 298 	free(app);
 299 	free(service);
 300 	fprintf(stderr, _("newrole:  %s:  error on line %lu.\n"),
 301 		config_file_path, lineno);
 302 	free(line_buf);
 303 	return -1;
 304 }
 305 
 306 /* 
 307  *  Read config file ignoring comment lines.
 308  *  Files specified one per line executable with a corresponding
 309  *  pam service name.
 310  */
 311 static int read_pam_config()
 312 {
 313 	const char *config_file_path = PAM_SERVICE_CONFIG;
 314 	FILE *cfg = NULL;
 315 	cfg = fopen(config_file_path, "r");
 316 	if (!cfg)
 317 		return 0;	/* This configuration is optional. */
 318 	app_service_names =
 319 	    hashtab_create(reqsymhash, reqsymcmp, PAM_SERVICE_SLOTS);
 320 	if (!app_service_names)
 321 		goto err;
 322 	if (process_pam_config(cfg))
 323 		goto err;
 324 	fclose(cfg);
 325 	return 0;
 326       err:
 327 	fclose(cfg);
      (emitted by cppcheck) 328 	return -1;
 329 }
 330 
 331 #else				/* else !USE_PAM */
 332 
 333 /************************************************************************
 334  *
 335  * All shadow passwd code goes in this section.
 336  *
 337  ************************************************************************/
 338 #include <shadow.h>		/* for shadow passwd functions */
 339 #include <string.h>		/* for strlen(), memset() */
 340 
 341 #define PASSWORD_PROMPT _("Password:")	/* prompt for getpass() */
 342 
 343 /* authenticate_via_shadow_passwd()
 344  *
 345  * in:     uname - the calling user's user name
 346  * out:    nothing
 347  * return: value   condition
 348  *         -----   ---------
 349  *           1     user authenticated themselves properly according to the
 350  *                 shadow passwd file.
 351  *           0     otherwise
 352  *
 353  * This function uses the shadow passwd file to thenticate the user running
 354  * this program.
 355  */
 356 int authenticate_via_shadow_passwd(const char *uname)
 357 {
 358 	struct spwd *p_shadow_line;
 359 	char *unencrypted_password_s;
 360 	char *encrypted_password_s;
 361 
 362 	setspent();
 363 	p_shadow_line = getspnam(uname);
 364 	endspent();
 365 	if (!(p_shadow_line)) {
 366 		fprintf(stderr, _("Cannot find your entry in the shadow "
 367 				  "passwd file.\n"));
 368 		return 0;
 369 	}
 370 
 371 	/* Ask user to input unencrypted password */
 372 	if (!(unencrypted_password_s = getpass(PASSWORD_PROMPT))) {
 373 		fprintf(stderr, _("getpass cannot open /dev/tty\n"));
 374 		return 0;
 375 	}
 376 
 377 	/* Use crypt() to encrypt user's input password. */
 378 	encrypted_password_s = crypt(unencrypted_password_s,
 379 				     p_shadow_line->sp_pwdp);
 380 	memset(unencrypted_password_s, 0, strlen(unencrypted_password_s));
 381 	return (!strcmp(encrypted_password_s, p_shadow_line->sp_pwdp));
 382 }
 383 #endif				/* if/else USE_PAM */
 384 
 385 /**
 386  * This function checks to see if the shell is known in /etc/shells.
 387  * If so, it returns 1. On error or illegal shell, it returns 0.
 388  */
 389 static int verify_shell(const char *shell_name)
 390 {
 391 	int found = 0;
 392 	const char *buf;
 393 
 394 	if (!(shell_name && shell_name[0]))
 395 		return found;
 396 
 397 	while ((buf = getusershell()) != NULL) {
 398 		/* ignore comments */
 399 		if (*buf == '#')
 400 			continue;
 401 
 402 		/* check the shell skipping newline char */
 403 		if (!strcmp(shell_name, buf)) {
 404 			found = 1;
 405 			break;
 406 		}
 407 	}
 408 	endusershell();
 409 	return found;
 410 }
 411 
 412 /**
 413  * Determine the Linux user identity to re-authenticate.
 414  * If supported and set, use the login uid, as this should be more stable.
 415  * Otherwise, use the real uid.
 416  *
 417  * This function assigns malloc'd memory into the pw_copy struct.
 418  * Returns zero on success, non-zero otherwise
 419  */
 420 int extract_pw_data(struct passwd *pw_copy)
 421 {
 422 	uid_t uid;
 423 	struct passwd *pw;
 424 
 425 #ifdef USE_AUDIT
 426 	uid = audit_getloginuid();
 427 	if (uid == (uid_t) - 1)
 428 		uid = getuid();
 429 #else
 430 	uid = getuid();
 431 #endif
 432 
 433 	setpwent();
 434 	pw = getpwuid(uid);
 435 	endpwent();
 436 	if (!(pw && pw->pw_name && pw->pw_name[0] && pw->pw_shell
 437 	      && pw->pw_shell[0] && pw->pw_dir && pw->pw_dir[0])) {
 438 		fprintf(stderr,
 439 			_("cannot find valid entry in the passwd file.\n"));
 440 		return -1;
 441 	}
 442 
 443 	*pw_copy = *pw;
 444 	pw = pw_copy;
 445 	pw->pw_name = strdup(pw->pw_name);
 446 	pw->pw_dir = strdup(pw->pw_dir);
 447 	pw->pw_shell = strdup(pw->pw_shell);
 448 
 449 	if (!(pw->pw_name && pw->pw_dir && pw->pw_shell)) {
 450 		fprintf(stderr, _("Out of memory!\n"));
 451 		goto out_free;
 452 	}
 453 
 454 	if (verify_shell(pw->pw_shell) == 0) {
 455 		fprintf(stderr, _("Error!  Shell is not valid.\n"));
 456 		goto out_free;
 457 	}
 458 	return 0;
 459 
 460       out_free:
 461 	free(pw->pw_name);
 462 	free(pw->pw_dir);
 463 	free(pw->pw_shell);
 464 	return -1;
 465 }
 466 
 467 /**
 468  * Either restore the original environment, or set up a minimal one.
 469  *
 470  * The minimal environment contains:
 471  * TERM, DISPLAY and XAUTHORITY - if they are set, preserve values
 472  * HOME, SHELL, USER and LOGNAME - set to contents of /etc/passwd
 473  * PATH - set to default value DEFAULT_PATH
 474  *
 475  * Returns zero on success, non-zero otherwise
 476  */
 477 static int restore_environment(int preserve_environment,
 478 			       char **old_environ, const struct passwd *pw)
 479 {
 480 	char const *term_env;
 481 	char const *display_env;
 482 	char const *xauthority_env;
 483 	char *term = NULL;	/* temporary container */
 484 	char *display = NULL;	/* temporary container */
 485 	char *xauthority = NULL;	/* temporary container */
 486 	int rc;
 487 
 488 	environ = old_environ;
 489 
 490 	if (preserve_environment)
 491 		return 0;
 492 
 493 	term_env = getenv("TERM");
 494 	display_env = getenv("DISPLAY");
 495 	xauthority_env = getenv("XAUTHORITY");
 496 
 497 	/* Save the variable values we want */
 498 	if (term_env)
 499 		term = strdup(term_env);
 500 	if (display_env)
 501 		display = strdup(display_env);
 502 	if (xauthority_env)
 503 		xauthority = strdup(xauthority_env);
 504 	if ((term_env && !term) || (display_env && !display) ||
 505 	    (xauthority_env && !xauthority)) {
 506 		rc = -1;
 507 		goto out;
 508 	}
 509 
 510 	/* Construct a new environment */
 511 	if ((rc = clearenv())) {
 512 		fprintf(stderr, _("Unable to clear environment\n"));
 513 		goto out;
 514 	}
 515 
 516 	/* Restore that which we saved */
 517 	if (term)
 518 		rc |= setenv("TERM", term, 1);
 519 	if (display)
 520 		rc |= setenv("DISPLAY", display, 1);
 521 	if (xauthority)
 522 		rc |= setenv("XAUTHORITY", xauthority, 1);
 523 	rc |= setenv("HOME", pw->pw_dir, 1);
 524 	rc |= setenv("SHELL", pw->pw_shell, 1);
 525 	rc |= setenv("USER", pw->pw_name, 1);
 526 	rc |= setenv("LOGNAME", pw->pw_name, 1);
 527 	rc |= setenv("PATH", DEFAULT_PATH, 1);
 528       out:
 529 	free(term);
 530 	free(display);
 531 	free(xauthority);
 532 	return rc;
 533 }
 534 
 535 /**
 536  * This function will drop the capabilities so that we are left
 537  * only with access to the audit system. If the user is root, we leave
 538  * the capabilities alone since they already should have access to the
 539  * audit netlink socket.
 540  *
 541  * Returns zero on success, non-zero otherwise
 542  */
 543 #if defined(AUDIT_LOG_PRIV) && !defined(NAMESPACE_PRIV)
 544 static int drop_capabilities(int full)
 545 {
 546 	uid_t uid = getuid();
 547 	if (!uid) return 0;
 548 
 549 	capng_setpid(getpid());
 550 	capng_clear(CAPNG_SELECT_BOTH);
 551 	if (capng_lock() < 0) 
 552 		return -1;
 553 
 554 	/* Change uid */
 555 	if (setresuid(uid, uid, uid)) {
 556 		fprintf(stderr, _("Error changing uid, aborting.\n"));
 557 		return -1;
 558 	}
 559 	if (! full) 
 560 		capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, CAP_AUDIT_WRITE);
 561 	return capng_apply(CAPNG_SELECT_BOTH);
 562 }
 563 #elif defined(NAMESPACE_PRIV)
 564 /**
 565  * This function will drop the capabilities so that we are left
 566  * only with access to the audit system and the ability to raise
 567  * CAP_SYS_ADMIN, CAP_DAC_OVERRIDE, CAP_FOWNER and CAP_CHOWN,
 568  * before invoking pam_namespace.  These capabilities are needed
 569  * for performing bind mounts/unmounts and to create potential new
 570  * instance directories with appropriate DAC attributes. If the
 571  * user is root, we leave the capabilities alone since they already
 572  * should have access to the audit netlink socket and should have
 573  * the ability to create/mount/unmount instance directories.
 574  *
 575  * Returns zero on success, non-zero otherwise
 576  */
 577 static int drop_capabilities(int full)
 578 {
 579 	capng_setpid(getpid());
 580 	capng_clear(CAPNG_SELECT_BOTH);
 581 	if (capng_lock() < 0) 
 582 		return -1;
 583 
 584 	uid_t uid = getuid();
 585 	/* Change uid */
 586 	if (setresuid(uid, uid, uid)) {
 587 		fprintf(stderr, _("Error changing uid, aborting.\n"));
 588 		return -1;
 589 	}
 590 	if (! full) 
 591 		capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, CAP_SYS_ADMIN , CAP_FOWNER , CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_SETPCAP, -1);
 592 	return capng_apply(CAPNG_SELECT_BOTH);
 593 }
 594 
 595 #else
 596 static inline int drop_capabilities(__attribute__ ((__unused__)) int full)
 597 {
 598 	return 0;
 599 }
 600 #endif
 601 
 602 #ifdef NAMESPACE_PRIV
 603 /**
 604  * This function will set the uid values to be that of caller's uid, and
 605  * will drop any privilages which maybe have been raised.
 606  */
 607 static int transition_to_caller_uid()
 608 {
 609 	uid_t uid = getuid();
 610 
 611 	if (prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) < 0) {
 612 		fprintf(stderr, _("Error resetting KEEPCAPS, aborting\n"));
 613 		return -1;
 614 	}
 615 
 616 	if (setresuid(uid, uid, uid)) {
 617 		fprintf(stderr, _("Error changing uid, aborting.\n"));
 618 		return -1;
 619 	}
 620 	return 0;
 621 }
 622 #endif
 623 
 624 #ifdef AUDIT_LOG_PRIV
 625 /* Send audit message */
 626 static
 627 int send_audit_message(int success, security_context_t old_context,
 628 		       security_context_t new_context, const char *ttyn)
 629 {
 630 	char *msg = NULL;
 631 	int rc;
 632 	int audit_fd = audit_open();
 633 
 634 	if (audit_fd < 0) {
 635 		fprintf(stderr, _("Error connecting to audit system.\n"));
 636 		return -1;
 637 	}
 638 	if (asprintf(&msg, "newrole: old-context=%s new-context=%s",
 639 		     old_context ? old_context : "?",
 640 		     new_context ? new_context : "?") < 0) {
 641 		fprintf(stderr, _("Error allocating memory.\n"));
 642 		rc = -1;
 643 		goto out;
 644 	}
 645 	rc = audit_log_user_message(audit_fd, AUDIT_USER_ROLE_CHANGE,
 646 				    msg, NULL, NULL, ttyn, success);
 647 	if (rc <= 0) {
 648 		fprintf(stderr, _("Error sending audit message.\n"));
 649 		rc = -1;
 650 		goto out;
 651 	}
 652 	rc = 0;
 653       out:
 654 	free(msg);
 655 	close(audit_fd);
 656 	return rc;
 657 }
 658 #else
 659 static inline
 660     int send_audit_message(int success __attribute__ ((unused)),
 661 			   security_context_t old_context
 662 			   __attribute__ ((unused)),
 663 			   security_context_t new_context
 664 			   __attribute__ ((unused)), const char *ttyn
 665 			   __attribute__ ((unused)))
 666 {
 667 	return 0;
 668 }
 669 #endif
 670 
 671 /**
 672  * This function attempts to relabel the tty. If this function fails, then
 673  * the fd is closed, the contexts are free'd and -1 is returned. On success,
 674  * a valid fd is returned and tty_context and new_tty_context are set.
 675  *
 676  * This function will not fail if it can not relabel the tty when selinux is
 677  * in permissive mode.
 678  */
 679 static int relabel_tty(const char *ttyn, security_context_t new_context,
 680 		       security_context_t * tty_context,
 681 		       security_context_t * new_tty_context)
 682 {
 683 	int fd;
 684 	int enforcing = security_getenforce();
 685 	security_context_t tty_con = NULL;
 686 	security_context_t new_tty_con = NULL;
 687 
 688 	if (!ttyn)
 689 		return 0;
 690 
 691 	if (enforcing < 0) {
 692 		fprintf(stderr, _("Could not determine enforcing mode.\n"));
 693 		return -1;
 694 	}
 695 
 696 	/* Re-open TTY descriptor */
 697 	fd = open(ttyn, O_RDWR | O_NONBLOCK);
 698 	if (fd < 0) {
 699 		fprintf(stderr, _("Error!  Could not open %s.\n"), ttyn);
 700 		return fd;
 701 	}
 702 	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
 703 
 704 	if (fgetfilecon(fd, &tty_con) < 0) {
 705 		fprintf(stderr, _("%s!  Could not get current context "
 706 				  "for %s, not relabeling tty.\n"),
 707 			enforcing ? "Error" : "Warning", ttyn);
 708 		if (enforcing)
 709 			goto close_fd;
 710 	}
 711 
 712 	if (tty_con &&
 713 	    (security_compute_relabel(new_context, tty_con,
 714 				      SECCLASS_CHR_FILE, &new_tty_con) < 0)) {
 715 		fprintf(stderr, _("%s!  Could not get new context for %s, "
 716 				  "not relabeling tty.\n"),
 717 			enforcing ? "Error" : "Warning", ttyn);
 718 		if (enforcing)
 719 			goto close_fd;
 720 	}
 721 
 722 	if (new_tty_con)
 723 		if (fsetfilecon(fd, new_tty_con) < 0) {
 724 			fprintf(stderr,
 725 				_("%s!  Could not set new context for %s\n"),
 726 				enforcing ? "Error" : "Warning", ttyn);
 727 			freecon(new_tty_con);
 728 			new_tty_con = NULL;
 729 			if (enforcing)
 730 				goto close_fd;
 731 		}
 732 
 733 	*tty_context = tty_con;
 734 	*new_tty_context = new_tty_con;
 735 	return fd;
 736 
 737       close_fd:
 738 	freecon(tty_con);
 739 	close(fd);
 740 	return -1;
 741 }
 742 
 743 /**
 744  * This function attempts to revert the relabeling done to the tty.
 745  * fd   - referencing the opened ttyn
 746  * ttyn - name of tty to restore
 747  * tty_context     - original context of the tty
 748  * new_tty_context - context tty was relabeled to
 749  *
 750  * Returns zero on success, non-zero otherwise
 751  */
 752 static int restore_tty_label(int fd, const char *ttyn,
 753 			     security_context_t tty_context,
 754 			     security_context_t new_tty_context)
 755 {
 756 	int rc = 0;
 757 	security_context_t chk_tty_context = NULL;
 758 
 759 	if (!ttyn)
 760 		goto skip_relabel;
 761 
 762 	if (!new_tty_context)
 763 		goto skip_relabel;
 764 
 765 	/* Verify that the tty still has the context set by newrole. */
 766 	if ((rc = fgetfilecon(fd, &chk_tty_context)) < 0) {
 767 		fprintf(stderr, "Could not fgetfilecon %s.\n", ttyn);
 768 		goto skip_relabel;
 769 	}
 770 
 771 	if ((rc = strcmp(chk_tty_context, new_tty_context))) {
 772 		fprintf(stderr, _("%s changed labels.\n"), ttyn);
 773 		goto skip_relabel;
 774 	}
 775 
 776 	if ((rc = fsetfilecon(fd, tty_context)) < 0)
 777 		fprintf(stderr,
 778 			_("Warning! Could not restore context for %s\n"), ttyn);
 779       skip_relabel:
 780 	freecon(chk_tty_context);
 781 	return rc;
 782 }
 783 
 784 /**
 785  * Parses and validates the provided command line options and
 786  * constructs a new context based on our old context and the
 787  * arguments specified on the command line. On success
 788  * new_context will be set to valid values, otherwise its value
 789  * is left unchanged.
 790  *
 791  * Returns zero on success, non-zero otherwise.
 792  */
 793 static int parse_command_line_arguments(int argc, char **argv, char *ttyn,
 794 					security_context_t old_context,
 795 					security_context_t * new_context,
 796 					int *preserve_environment)
 797 {
 798 	int flag_index;		/* flag index in argv[] */
 799 	int clflag;		/* holds codes for command line flags */
 800 	char *role_s = NULL;	/* role spec'd by user in argv[] */
 801 	char *type_s = NULL;	/* type spec'd by user in argv[] */
 802 	char *type_ptr = NULL;	/* stores malloc'd data from get_default_type */
 803 	char *level_s = NULL;	/* level spec'd by user in argv[] */
 804 	char *range_ptr = NULL;
 805 	security_context_t new_con = NULL;
 806 	security_context_t tty_con = NULL;
 807 	context_t context = NULL;	/* manipulatable form of new_context */
 808 	const struct option long_options[] = {
 809 		{"role", 1, 0, 'r'},
 810 		{"type", 1, 0, 't'},
 811 		{"level", 1, 0, 'l'},
 812 		{"preserve-environment", 0, 0, 'p'},
 813 		{"version", 0, 0, 'V'},
 814 		{NULL, 0, 0, 0}
 815 	};
 816 
 817 	*preserve_environment = 0;
 818 	while (1) {
 819 		clflag = getopt_long(argc, argv, "r:t:l:pV", long_options,
 820 				     &flag_index);
 821 		if (clflag == -1)
 822 			break;
 823 
 824 		switch (clflag) {
 825 		case 'V':
 826 			printf("newrole: %s version %s\n", PACKAGE, VERSION);
 827 			exit(0);
 828 			break;
 829 		case 'p':
 830 			*preserve_environment = 1;
 831 			break;
 832 		case 'r':
 833 			if (role_s) {
 834 				fprintf(stderr,
 835 					_("Error: multiple roles specified\n"));
 836 				return -1;
 837 			}
 838 			role_s = optarg;
 839 			break;
 840 		case 't':
 841 			if (type_s) {
 842 				fprintf(stderr,
 843 					_("Error: multiple types specified\n"));
 844 				return -1;
 845 			}
 846 			type_s = optarg;
 847 			break;
 848 		case 'l':
 849 			if (!is_selinux_mls_enabled()) {
 850 				fprintf(stderr, _("Sorry, -l may be used with "
 851 						  "SELinux MLS support.\n"));
 852 				return -1;
 853 			}
 854 			if (level_s) {
 855 				fprintf(stderr, _("Error: multiple levels "
 856 						  "specified\n"));
 857 				return -1;
 858 			}
 859 			if (ttyn) {
 860 				if (fgetfilecon(STDIN_FILENO, &tty_con) >= 0) {
 861 					if (selinux_check_securetty_context
 862 					    (tty_con) < 0) {
 863 						fprintf(stderr,
 864 							_
 865 							("Error: you are not allowed to change levels on a non secure terminal \n"));
 866 						freecon(tty_con);
 867 						return -1;
 868 					}
 869 					freecon(tty_con);
 870 				}
 871 			}
 872 
 873 			level_s = optarg;
 874 			break;
 875 		default:
 876 			fprintf(stderr, "%s\n", USAGE_STRING);
 877 			return -1;
 878 		}
 879 	}
 880 
 881 	/* Verify that the combination of command-line arguments are viable */
 882 	if (!(role_s || type_s || level_s)) {
 883 		fprintf(stderr, "%s\n", USAGE_STRING);
 884 		return -1;
 885 	}
 886 
 887 	/* Fill in a default type if one hasn't been specified. */
 888 	if (role_s && !type_s) {
 889 		/* get_default_type() returns malloc'd memory */
 890 		if (get_default_type(role_s, &type_ptr)) {
 891 			fprintf(stderr, _("Couldn't get default type.\n"));
 892 			send_audit_message(0, old_context, new_con, ttyn);
 893 			return -1;
 894 		}
 895 		type_s = type_ptr;
 896 	}
 897 
 898 	/* Create a temporary new context structure we extract and modify */
 899 	context = context_new(old_context);
 900 	if (!context) {
 901 		fprintf(stderr, _("failed to get new context.\n"));
 902 		goto err_free;
 903 	}
 904 
 905 	/* Modify the temporary new context */
 906 	if (role_s)
 907 		if (context_role_set(context, role_s)) {
 908 			fprintf(stderr, _("failed to set new role %s\n"),
 909 				role_s);
 910 			goto err_free;
 911 		}
 912 
 913 	if (type_s)
 914 		if (context_type_set(context, type_s)) {
 915 			fprintf(stderr, _("failed to set new type %s\n"),
 916 				type_s);
 917 			goto err_free;
 918 		}
 919 
 920 	if (level_s) {
 921 		range_ptr =
 922 		    build_new_range(level_s, context_range_get(context));
 923 		if (!range_ptr) {
 924 			fprintf(stderr,
 925 				_("failed to build new range with level %s\n"),
 926 				level_s);
 927 			goto err_free;
 928 		}
 929 		if (context_range_set(context, range_ptr)) {
 930 			fprintf(stderr, _("failed to set new range %s\n"),
 931 				range_ptr);
 932 			goto err_free;
 933 		}
 934 	}
 935 
 936 	/* Construct the final new context */
 937 	if (!(new_con = context_str(context))) {
 938 		fprintf(stderr, _("failed to convert new context to string\n"));
 939 		goto err_free;
 940 	}
 941 
 942 	if (security_check_context(new_con) < 0) {
 943 		fprintf(stderr, _("%s is not a valid context\n"), new_con);
 944 		send_audit_message(0, old_context, new_con, ttyn);
 945 		goto err_free;
 946 	}
 947 
 948 	*new_context = strdup(new_con);
 949 	if (!*new_context) {
 950 		fprintf(stderr, _("Unable to allocate memory for new_context"));
 951 		goto err_free;
 952 	}
 953 
 954 	free(type_ptr);
 955 	free(range_ptr);
 956 	context_free(context);
 957 	return 0;
 958 
 959       err_free:
 960 	free(type_ptr);
 961 	free(range_ptr);
 962 	/* Don't free new_con, context_free(context) handles this */
 963 	context_free(context);
 964 	return -1;
 965 }
 966 
 967 /**
 968  * Take care of any signal setup
 969  */
 970 static int set_signal_handles()
 971 {
 972 	sigset_t empty;
 973 
 974 	/* Empty the signal mask in case someone is blocking a signal */
 975 	if (sigemptyset(&empty)) {
 976 		fprintf(stderr, _("Unable to obtain empty signal set\n"));
 977 		return -1;
 978 	}
 979 
 980 	(void)sigprocmask(SIG_SETMASK, &empty, NULL);
 981 
 982 	/* Terminate on SIGHUP. */
 983 	if (signal(SIGHUP, SIG_DFL) == SIG_ERR) {
 984 		fprintf(stderr, _("Unable to set SIGHUP handler\n"));
 985 		return -1;
 986 	}
 987 
 988 	return 0;
 989 }
 990 
 991 /************************************************************************
 992  *
 993  * All code used for both PAM and shadow passwd goes in this section.
 994  *
 995  ************************************************************************/
 996 
 997 int main(int argc, char *argv[])
 998 {
 999 	security_context_t new_context = NULL;	/* target security context */
1000 	security_context_t old_context = NULL;	/* original securiy context */
1001 	security_context_t tty_context = NULL;	/* current context of tty */
1002 	security_context_t new_tty_context = NULL;	/* new context of tty */
1003 
1004 	struct passwd pw;	/* struct derived from passwd file line */
1005 	char *ttyn = NULL;	/* tty path */
1006 
1007 	char **old_environ;
1008 	int preserve_environment;
1009 
1010 	int fd;
1011 	pid_t childPid = 0;
1012 	char *shell_argv0 = NULL;
1013 
1014 #ifdef USE_PAM
1015 	int rc;
1016 	int pam_status;		/* pam return code */
1017 	pam_handle_t *pam_handle;	/* opaque handle used by all PAM functions */
1018 
1019 	/* This is a jump table of functions for PAM to use when it wants to *
1020 	 * communicate with the user.  We'll be using misc_conv(), which is  *
1021 	 * provided for us via pam_misc.h.                                   */
1022 	struct pam_conv pam_conversation = {
1023 		misc_conv,
1024 		NULL
1025 	};
1026 #endif
1027 
1028 	/*
1029 	 * Step 0: Setup
1030 	 *
1031 	 * Do some intial setup, including dropping capabilities, checking
1032 	 * if it makes sense to continue to run newrole, and setting up
1033 	 * a scrubbed environment.
1034 	 */
1035 	if (drop_capabilities(FALSE)) {
1036 		perror(_("Sorry, newrole failed to drop capabilities\n"));
1037 		return -1;
1038 	}
1039 	if (set_signal_handles())
1040 		return -1;
1041 
1042 #ifdef USE_NLS
1043 	setlocale(LC_ALL, "");
1044 	bindtextdomain(PACKAGE, LOCALEDIR);
1045 	textdomain(PACKAGE);
1046 #endif
1047 
1048 	old_environ = environ;
1049 	environ = NULL;
1050 
1051 	if (!is_selinux_enabled()) {
1052 		fprintf(stderr, _("Sorry, newrole may be used only on "
1053 				  "a SELinux kernel.\n"));
1054 		return -1;
1055 	}
1056 
1057 	if (security_getenforce() < 0) {
1058 		fprintf(stderr, _("Could not determine enforcing mode.\n"));
1059 		return -1;
1060 	}
1061 
1062 	/*
1063 	 * Step 1: Parse command line and valid arguments
1064 	 *
1065 	 * old_context and ttyn are required for audit logging,
1066 	 * context validation and pam
1067 	 */
1068 	if (getprevcon(&old_context)) {
1069 		fprintf(stderr, _("failed to get old_context.\n"));
1070 		return -1;
1071 	}
1072 
1073 	ttyn = ttyname(STDIN_FILENO);
1074 	if (!ttyn || *ttyn == '\0') {
1075 		fprintf(stderr,
1076 			_("Warning!  Could not retrieve tty information.\n"));
1077 	}
1078 
1079 	if (parse_command_line_arguments(argc, argv, ttyn, old_context,
1080 					 &new_context, &preserve_environment))
1081 		return -1;
1082 
1083 	/*
1084 	 * Step 2:  Authenticate the user.
1085 	 *
1086 	 * Re-authenticate the user running this program.
1087 	 * This is just to help confirm user intent (vs. invocation by
1088 	 * malicious software), not to authorize the operation (which is covered
1089 	 * by policy).  Trusted path mechanism would be preferred.
1090 	 */
1091 	if (extract_pw_data(&pw))
1092 		goto err_free;
1093 
1094 #ifdef USE_PAM
1095 	if (read_pam_config()) {
1096 		fprintf(stderr,
1097 			_("error on reading PAM service configuration.\n"));
1098 		goto err_free;
1099 	}
1100 
1101 	if (app_service_names != NULL && optind < argc) {
1102 		if (strcmp(argv[optind], "-c") == 0 && optind < (argc - 1)) {
1103 			/*
1104 			 * Check for a separate pam service name for the 
1105 			 * command when invoked by newrole.
1106 			 */
1107 			char *cmd = NULL;
1108 			rc = sscanf(argv[optind + 1], "%as", &cmd);
1109 			if (rc != EOF && cmd) {
1110 				char *app_service_name =
1111 				    (char *)hashtab_search(app_service_names,
1112 							   cmd);
1113 				free(cmd);
1114 				if (app_service_name != NULL)
1115 					service_name = app_service_name;
1116 			}
1117 		}
1118 	}
1119 
1120 	pam_status = pam_start(service_name, pw.pw_name, &pam_conversation,
1121 			       &pam_handle);
1122 	if (pam_status != PAM_SUCCESS) {
1123 		fprintf(stderr, _("failed to initialize PAM\n"));
1124 		goto err_free;
1125 	}
1126 
1127 	if (!authenticate_via_pam(ttyn, pam_handle))
1128 #else
1129 	if (!authenticate_via_shadow_passwd(pw.pw_name))
1130 #endif
1131 	{
1132 		fprintf(stderr, _("newrole: incorrect password for %s\n"),
1133 			pw.pw_name);
1134 		send_audit_message(0, old_context, new_context, ttyn);
1135 		goto err_close_pam;
1136 	}
1137 
1138 	/*
1139 	 * Step 3:  Handle relabeling of the tty.
1140 	 *
1141 	 * Once we authenticate the user, we know that we want to proceed with
1142 	 * the action. Prior to this point, no changes are made the to system.
1143 	 */
1144 	fd = relabel_tty(ttyn, new_context, &tty_context, &new_tty_context);
1145 	if (fd < 0)
1146 		goto err_close_pam;
1147 
1148 	/*
1149 	 * Step 4: Fork
1150 	 *
1151 	 * Fork, allowing parent to clean up after shell has executed.
1152 	 * Child: reopen stdin, stdout, stderr and exec shell
1153 	 * Parnet: wait for child to die and restore tty's context
1154 	 */
1155 	childPid = fork();
1156 	if (childPid < 0) {
1157 		/* fork failed, no child to worry about */
1158 		int errsv = errno;
1159 		fprintf(stderr, _("newrole: failure forking: %s"),
1160 			strerror(errsv));
1161 		if (restore_tty_label(fd, ttyn, tty_context, new_tty_context))
1162 			fprintf(stderr, _("Unable to restore tty label...\n"));
1163 		if (close(fd))
1164 			fprintf(stderr, _("Failed to close tty properly\n"));
1165 		goto err_close_pam;
1166 	} else if (childPid) {
1167 		/* PARENT
1168 		 * It doesn't make senes to exit early on errors at this point,
1169 		 * since we are doing cleanup which needs to be done.
1170 		 * We can exit with a bad rc though
1171 		 */
1172 		pid_t pid;
1173 		int exit_code = 0;
1174 		int status;
1175 
1176 		do {
1177 			pid = wait(&status);
1178 		} while (pid < 0 && errno == EINTR);
1179 
1180 		/* Preserve child exit status, unless there is another error. */
1181 		if (WIFEXITED(status))
1182 			exit_code = WEXITSTATUS(status);
1183 
1184 		if (restore_tty_label(fd, ttyn, tty_context, new_tty_context)) {
1185 			fprintf(stderr, _("Unable to restore tty label...\n"));
1186 			exit_code = -1;
1187 		}
1188 		freecon(tty_context);
1189 		freecon(new_tty_context);
1190 		if (close(fd)) {
1191 			fprintf(stderr, _("Failed to close tty properly\n"));
1192 			exit_code = -1;
1193 		}
1194 #ifdef USE_PAM
1195 #ifdef NAMESPACE_PRIV
1196 		pam_status = pam_close_session(pam_handle, 0);
1197 		if (pam_status != PAM_SUCCESS) {
1198 			fprintf(stderr, "pam_close_session failed with %s\n",
1199 				pam_strerror(pam_handle, pam_status));
1200 			exit_code = -1;
1201 		}
1202 #endif
1203 		rc = pam_end(pam_handle, pam_status);
1204 		if (rc != PAM_SUCCESS) {
1205 			fprintf(stderr, "pam_end failed with %s\n",
1206 				pam_strerror(pam_handle, rc));
1207 			exit_code = -1;
1208 		}
1209 		hashtab_map(app_service_names, free_hashtab_entry, NULL);
1210 		hashtab_destroy(app_service_names);
1211 #endif
1212 		free(pw.pw_name);
1213 		free(pw.pw_dir);
1214 		free(pw.pw_shell);
1215 		free(shell_argv0);
1216 		return exit_code;
1217 	}
1218 
1219 	/* CHILD */
1220 	/* Close the tty and reopen descriptors 0 through 2 */
1221 	if (ttyn) {
1222 		if (close(fd) || close(0) || close(1) || close(2)) {
1223 			fprintf(stderr, _("Could not close descriptors.\n"));
1224 			goto err_close_pam;
1225 		}
1226 		fd = open(ttyn, O_RDONLY | O_NONBLOCK);
1227 		if (fd != 0)
1228 			goto err_close_pam;
1229 		fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
1230 		fd = open(ttyn, O_RDWR | O_NONBLOCK);
1231 		if (fd != 1)
1232 			goto err_close_pam;
1233 		fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
1234 		fd = open(ttyn, O_RDWR | O_NONBLOCK);
1235 		if (fd != 2)
1236 			goto err_close_pam;
1237 		fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
1238 
1239 	}
1240 	/*
1241 	 * Step 5:  Execute a new shell with the new context in `new_context'. 
1242 	 *
1243 	 * Establish context, namesapce and any options for the new shell
1244 	 */
1245 	if (optind < 1)
1246 		optind = 1;
1247 
1248 	/* This is ugly, but use newrole's argv for the exec'd shells argv */
1249 	if (asprintf(&shell_argv0, "-%s", pw.pw_shell) < 0) {
1250 		fprintf(stderr, _("Error allocating shell's argv0.\n"));
1251 		shell_argv0 = NULL;
1252 		goto err_close_pam;
1253 	}
1254 	argv[optind - 1] = shell_argv0;
1255 
1256 	if (setexeccon(new_context)) {
1257 		fprintf(stderr, _("Could not set exec context to %s.\n"),
1258 			new_context);
1259 		goto err_close_pam;
1260 	}
1261 #ifdef NAMESPACE_PRIV
1262 	/* Ask PAM to setup session for user running this program */
1263 	pam_status = pam_open_session(pam_handle, 0);
1264 	if (pam_status != PAM_SUCCESS) {
1265 		fprintf(stderr, "pam_open_session failed with %s\n",
1266 			pam_strerror(pam_handle, pam_status));
1267 		goto err_close_pam;
1268 	}
1269 #endif
1270 
1271 	if (send_audit_message(1, old_context, new_context, ttyn))
1272 		goto err_close_pam_session;
1273 	freecon(old_context); old_context=NULL;
1274 	freecon(new_context); new_context=NULL;
1275 
1276 #ifdef NAMESPACE_PRIV
1277 	if (transition_to_caller_uid())
1278 		goto err_close_pam_session;
1279 #endif
1280 
1281 	if (drop_capabilities(TRUE))
1282 		goto err_close_pam_session;
1283 
1284 	/* Handle environment changes */
1285 	if (restore_environment(preserve_environment, old_environ, &pw)) {
1286 		fprintf(stderr, _("Unable to restore the environment, "
1287 				  "aborting\n"));
1288 		goto err_close_pam_session;
1289 	}
1290 	execv(pw.pw_shell, argv + optind - 1);
1291 
1292 	/*
1293 	 * Error path cleanup
1294 	 *
1295 	 * If we reach here, then we failed to exec the new shell.
1296 	 */
1297 	perror(_("failed to exec shell\n"));
1298       err_close_pam_session:
1299 #ifdef NAMESPACE_PRIV
1300 	pam_status = pam_close_session(pam_handle, 0);
1301 	if (pam_status != PAM_SUCCESS)
1302 		fprintf(stderr, "pam_close_session failed with %s\n",
1303 			pam_strerror(pam_handle, pam_status));
1304 #endif
1305       err_close_pam:
1306 #ifdef USE_PAM
1307 	rc = pam_end(pam_handle, pam_status);
1308 	if (rc != PAM_SUCCESS)
1309 		fprintf(stderr, "pam_end failed with %s\n",
1310 			pam_strerror(pam_handle, rc));
1311 #endif
1312       err_free:
1313 	freecon(tty_context);
1314 	freecon(new_tty_context);
1315 	freecon(old_context);
1316 	freecon(new_context);
1317 	free(pw.pw_name);
1318 	free(pw.pw_dir);
1319 	free(pw.pw_shell);
1320 	free(shell_argv0);
1321 #ifdef USE_PAM
1322 	if (app_service_names) {
1323 		hashtab_map(app_service_names, free_hashtab_entry, NULL);
1324 		hashtab_destroy(app_service_names);
1325 	}
1326 #endif
1327 	return -1;
1328 }				/* main() */
| Location | Tool | Test ID | Issue | |
|---|---|---|---|---|
| restorecond.c:106:2 | gcc | unused-result | write_pid_file | ignoring return value of 'write', declared with attribute warn_unused_result | 
| restorecond.c:211:12 | clang-analyzer | Access to field 'pw_dir' results in a dereference of a null pointer (loaded from variable 'pwd') | ||
| restorecond.c:224:9 | gcc | unused-result | main | ignoring return value of 'daemon', declared with attribute warn_unused_result | 
  1 /*
  2  * restorecond
  3  *
  4  * Copyright (C) 2006-2009 Red Hat 
  5  * see file 'COPYING' for use and warranty information
  6  *
  7  * This program is free software; you can redistribute it and/or
  8  * modify it under the terms of the GNU General Public License as
  9  * published by the Free Software Foundation; either version 2 of
 10  * the License, or (at your option) any later version.
 11  * 
 12  * This program is distributed in the hope that it will be useful,
 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15  * GNU General Public License for more details.
 16 .* 
 17  * You should have received a copy of the GNU General Public License
 18  * along with this program; if not, write to the Free Software
 19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA     
 20  * 02111-1307  USA
 21  *
 22  * Authors:  
 23  *   Dan Walsh <dwalsh@redhat.com>
 24  *
 25 */
 26 
 27 /* 
 28  * PURPOSE:
 29  * This daemon program watches for the creation of files listed in a config file
 30  * and makes sure that there security context matches the systems defaults
 31  *
 32  * USAGE:
 33  * restorecond [-d] [-u] [-v] [-f restorecond_file ]
 34  * 
 35  * -d   Run in debug mode
 36  * -f   Use alternative restorecond_file
 37  * -u   Run in user mode
 38  * -v   Run in verbose mode (Report missing files)
 39  *
 40  * EXAMPLE USAGE:
 41  * restorecond
 42  *
 43  */
 44 
 45 #define _GNU_SOURCE
 46 #include <sys/inotify.h>
 47 #include <errno.h>
 48 #include <stdio.h>
 49 #include <stdlib.h>
 50 #include <signal.h>
 51 #include <string.h>
 52 #include <unistd.h>
 53 #include "../setfiles/restore.h"
 54 #include <sys/types.h>
 55 #include <syslog.h>
 56 #include <limits.h>
 57 #include <pwd.h>
 58 #include <sys/stat.h>
 59 #include <string.h>
 60 #include <stdio.h>
 61 #include <fcntl.h>
 62 #include "restorecond.h"
 63 #include "utmpwatcher.h"
 64 
 65 const char *homedir;
 66 static int master_fd = -1;
 67 
 68 static char *server_watch_file  = "/etc/selinux/restorecond.conf";
 69 static char *user_watch_file  = "/etc/selinux/restorecond_user.conf";
 70 static char *watch_file;
 71 static struct restore_opts r_opts;
 72 
 73 #include <selinux/selinux.h>
 74 
 75 int debug_mode = 0;
 76 int terminate = 0;
 77 int master_wd = -1;
 78 int run_as_user = 0;
 79 
 80 static void done(void) {
 81 	watch_list_free(master_fd);
 82 	close(master_fd);
 83 	utmpwatcher_free();
 84 	matchpathcon_fini();
 85 }
 86 
 87 static const char *pidfile = "/var/run/restorecond.pid";
 88 
 89 static int write_pid_file(void)
 90 {
 91 	int pidfd, len;
 92 	char val[16];
 93 
 94 	len = snprintf(val, sizeof(val), "%u\n", getpid());
 95 	if (len < 0) {
 96 		syslog(LOG_ERR, "Pid error (%s)", strerror(errno));
 97 		pidfile = 0;
 98 		return 1;
 99 	}
100 	pidfd = open(pidfile, O_CREAT | O_TRUNC | O_NOFOLLOW | O_WRONLY, 0644);
101 	if (pidfd < 0) {
102 		syslog(LOG_ERR, "Unable to set pidfile (%s)", strerror(errno));
103 		pidfile = 0;
104 		return 1;
105 	}
106 	(void)write(pidfd, val, (unsigned int)len);
      (emitted by gcc)107 	close(pidfd);
108 	return 0;
109 }
110 
111 /*
112  * SIGTERM handler
113  */
114 static void term_handler()
115 {
116 	terminate = 1;
117 	/* trigger a failure in the watch */
118 	close(master_fd);
119 }
120 
121 static void usage(char *program)
122 {
123 	printf("%s [-d] [-f restorecond_file ] [-u] [-v] \n", program);
124 }
125 
126 void exitApp(const char *msg)
127 {
128 	perror(msg);
129 	exit(-1);
130 }
131 
132 /* 
133    Add a file to the watch list.  We are watching for file creation, so we actually
134    put the watch on the directory and then examine all files created in that directory
135    to see if it is one that we are watching.
136 */
137 
138 int main(int argc, char **argv)
139 {
140 	int opt;
141 	struct sigaction sa;
142 
143 	memset(&r_opts, 0, sizeof(r_opts));
144 
145 	r_opts.progress = 0;
146 	r_opts.count = 0;
147 	r_opts.debug = 0;
148 	r_opts.change = 1;
149 	r_opts.verbose = 0;
150 	r_opts.logging = 0;
151 	r_opts.rootpath = NULL;
152 	r_opts.rootpathlen = 0;
153 	r_opts.outfile = NULL;
154 	r_opts.force = 0;
155 	r_opts.hard_links = 0;
156 	r_opts.abort_on_error = 0;
157 	r_opts.add_assoc = 0;
158 	r_opts.expand_realpath = 0;
159 	r_opts.fts_flags = FTS_PHYSICAL;
160 	r_opts.selabel_opt_validate = NULL;
161 	r_opts.selabel_opt_path = NULL;
162 	r_opts.ignore_enoent = 1;
163 
164 	restore_init(&r_opts);
165 	/* If we are not running SELinux then just exit */
166 	if (is_selinux_enabled() != 1) return 0;
167 
168 	/* Register sighandlers */
169 	sa.sa_flags = 0;
170 	sa.sa_handler = term_handler;
171 	sigemptyset(&sa.sa_mask);
172 	sigaction(SIGTERM, &sa, NULL);
173 
174 	set_matchpathcon_flags(MATCHPATHCON_NOTRANS);
175 
176 	exclude_non_seclabel_mounts();
177 	atexit( done );
178 	while ((opt = getopt(argc, argv, "hdf:uv")) > 0) {
179 		switch (opt) {
180 		case 'd':
181 			debug_mode = 1;
182 			break;
183 		case 'f':
184 			watch_file = optarg;
185 			break;
186 		case 'u':
187 			run_as_user = 1;
188 			break;
189 		case 'h':
190 			usage(argv[0]);
191 			exit(0);
192 			break;
193 		case 'v':
194 			r_opts.verbose++;
195 			break;
196 		case '?':
197 			usage(argv[0]);
198 			exit(-1);
199 		}
200 	}
201 
202 	master_fd = inotify_init();
203 	if (master_fd < 0)
204 		exitApp("inotify_init");
205 
206 	uid_t uid = getuid();
207 	struct passwd *pwd = getpwuid(uid);
208 	if (!pwd)
209 		exitApp("getpwuid");
210 
211 	homedir = pwd->pw_dir;
      (emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
212 	if (uid != 0) {
213 		if (run_as_user)
214 			return server(master_fd, user_watch_file);
215 		if (start() != 0)
216 			return server(master_fd, user_watch_file);
217 		return 0;
218 	}
219 
220 	watch_file = server_watch_file;
221 	read_config(master_fd, watch_file);
222 
223 	if (!debug_mode)
224 		daemon(0, 0);
      (emitted by gcc)225 
226 	write_pid_file();
227 
228 	while (watch(master_fd, watch_file) == 0) {
229 	};
230 
231 	watch_list_free(master_fd);
232 	close(master_fd);
233 	matchpathcon_fini();
234 	if (pidfile)
235 		unlink(pidfile);
236 
237 	return 0;
238 }
| Location | Tool | Test ID | Issue | |
|---|---|---|---|---|
| stringslist.c:50:2 | clang-analyzer | Access to field 'string' results in a dereference of a null pointer (loaded from variable 'newptr') | 
  1 /*
  2  * Copyright (C) 2006, 2008 Red Hat 
  3  * see file 'COPYING' for use and warranty information
  4  *
  5  * This program is free software; you can redistribute it and/or
  6  * modify it under the terms of the GNU General Public License as
  7  * published by the Free Software Foundation; either version 2 of
  8  * the License, or (at your option) any later version.
  9  * 
 10  * This program is distributed in the hope that it will be useful,
 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13  * GNU General Public License for more details.
 14 .* 
 15  * You should have received a copy of the GNU General Public License
 16  * along with this program; if not, write to the Free Software
 17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA     
 18  * 02111-1307  USA
 19  *
 20  * Authors:  
 21  *   Dan Walsh <dwalsh@redhat.com>
 22  *
 23 */
 24 
 25 #include <string.h>
 26 #include <stdio.h>
 27 #include <stdlib.h>
 28 #include "stringslist.h"
 29 #include "restorecond.h"
 30 #include <fnmatch.h>
 31 
 32 /* Sorted lists */
 33 void strings_list_add(struct stringsList **list, const char *string)
 34 {
 35 	struct stringsList *ptr = *list;
 36 	struct stringsList *prev = NULL;
 37 	struct stringsList *newptr = NULL;
 38 	while (ptr) {
 39 		int cmp = strcmp(string, ptr->string);
 40 		if (cmp < 0)
 41 			break;	/* Not on list break out to add */
 42 		if (cmp == 0)
 43 			return;	/* Already on list */
 44 		prev = ptr;
 45 		ptr = ptr->next;
 46 	}
 47 	newptr = calloc(1, sizeof(struct stringsList));
 48 	if (!newptr)
 49 		exitApp("Out of Memory");
 50 	newptr->string = strdup(string);
      (emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
 51 	newptr->next = ptr;
 52 	if (prev)
 53 		prev->next = newptr;
 54 	else
 55 		*list = newptr;
 56 }
 57 
 58 int strings_list_find(struct stringsList *ptr, const char *string, int *exact)
 59 {
 60 	while (ptr) {
 61 		*exact = strcmp(ptr->string, string) == 0;
 62 		int cmp = fnmatch(ptr->string, string, 0);
 63 		if (cmp == 0) 
 64 			return 0;	/* Match found */
 65 		ptr = ptr->next;
 66 	}
 67 	return -1;
 68 }
 69 
 70 void strings_list_free(struct stringsList *ptr)
 71 {
 72 	struct stringsList *prev = NULL;
 73 	while (ptr) {
 74 		free(ptr->string);
 75 		prev = ptr;
 76 		ptr = ptr->next;
 77 		free(prev);
 78 	}
 79 }
 80 
 81 int strings_list_diff(struct stringsList *from, struct stringsList *to)
 82 {
 83 	while (from != NULL && to != NULL) {
 84 		if (strcmp(from->string, to->string) != 0)
 85 			return 1;
 86 		from = from->next;
 87 		to = to->next;
 88 	}
 89 	if (from != NULL || to != NULL)
 90 		return 1;
 91 	return 0;
 92 }
 93 
 94 void strings_list_print(struct stringsList *ptr)
 95 {
 96 	while (ptr) {
 97 		printf("%s\n", ptr->string);
 98 		ptr = ptr->next;
 99 	}
100 }
101 
102 #ifdef TEST
103 void exitApp(const char *msg)
104 {
105 	perror(msg);
106 	exit(-1);
107 }
108 
109 int main(int argc, char **argv)
110 {
111 	struct stringsList *list = NULL;
112 	struct stringsList *list1 = NULL;
113 	strings_list_add(&list, "/etc/resolv.conf");
114 	strings_list_add(&list, "/etc/walsh");
115 	strings_list_add(&list, "/etc/mtab");
116 	strings_list_add(&list, "/etc/walsh");
117 	if (strings_list_diff(list, list) != 0)
118 		printf("strings_list_diff test1 bug\n");
119 	strings_list_add(&list1, "/etc/walsh");
120 	if (strings_list_diff(list, list1) == 0)
121 		printf("strings_list_diff test2 bug\n");
122 	strings_list_add(&list1, "/etc/walsh");
123 	strings_list_add(&list1, "/etc/walsh/*");
124 	strings_list_add(&list1, "/etc/resolv.conf");
125 	strings_list_add(&list1, "/etc/mtab1");
126 	if (strings_list_diff(list, list1) == 0)
127 		printf("strings_list_diff test3 bug\n");
128 	printf("strings list\n");
129 	strings_list_print(list);
130 	printf("strings list1\n");
131 	strings_list_find(list1, "/etc/walsh/dan");
132 	strings_list_print(list1);
133 	strings_list_free(list);
134 	strings_list_free(list1);
135 }
136 #endif
No issues found
  1 /*
  2  * restorecond
  3  *
  4  * Copyright (C) 2006-2009 Red Hat
  5  * see file 'COPYING' for use and warranty information
  6  *
  7  * This program is free software; you can redistribute it and/or
  8  * modify it under the terms of the GNU General Public License as
  9  * published by the Free Software Foundation; either version 2 of
 10  * the License, or (at your option) any later version.
 11  *
 12  * This program is distributed in the hope that it will be useful,
 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15  * GNU General Public License for more details.
 16 .*
 17  * You should have received a copy of the GNU General Public License
 18  * along with this program; if not, write to the Free Software
 19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 20  * 02111-1307  USA
 21  *
 22  * Authors:
 23  *   Dan Walsh <dwalsh@redhat.com>
 24  *
 25 */
 26 
 27 #define _GNU_SOURCE
 28 #include <sys/inotify.h>
 29 #include <errno.h>
 30 #include <stdio.h>
 31 #include <stdlib.h>
 32 #include <signal.h>
 33 #include <string.h>
 34 #include <unistd.h>
 35 #include <ctype.h>
 36 #include <sys/types.h>
 37 #include <sys/stat.h>
 38 #include <syslog.h>
 39 #include <limits.h>
 40 #include <fcntl.h>
 41 
 42 #include "restorecond.h"
 43 #include "stringslist.h"
 44 #include <glib.h>
 45 #ifdef HAVE_DBUS
 46 #include <dbus/dbus.h>
 47 #include <dbus/dbus-glib.h>
 48 #include <dbus/dbus-glib-lowlevel.h>
 49 
 50 static DBusHandlerResult signal_filter (DBusConnection *connection, DBusMessage *message, void *user_data);
 51 
 52 static const char *PATH="/org/selinux/Restorecond";
 53 //static const char *BUSNAME="org.selinux.Restorecond";
 54 static const char *INTERFACE="org.selinux.RestorecondIface";
 55 static const char *RULE="type='signal',interface='org.selinux.RestorecondIface'";
 56 
 57 
 58 static DBusHandlerResult
 59 signal_filter (DBusConnection *connection  __attribute__ ((__unused__)), DBusMessage *message, void *user_data)
 60 {
 61   /* User data is the event loop we are running in */
 62   GMainLoop *loop = user_data;
 63 
 64   /* A signal from the bus saying we are about to be disconnected */
 65   if (dbus_message_is_signal
 66         (message, INTERFACE, "Stop")) {
 67 
 68       /* Tell the main loop to quit */
 69       g_main_loop_quit (loop);
 70       /* We have handled this message, don't pass it on */
 71       return DBUS_HANDLER_RESULT_HANDLED;
 72   }
 73   /* A Ping signal on the com.burtonini.dbus.Signal interface */
 74   else if (dbus_message_is_signal (message, INTERFACE, "Start")) {
 75     DBusError error;
 76     dbus_error_init (&error);
 77     g_print("Start received\n");
 78     return DBUS_HANDLER_RESULT_HANDLED;
 79   }
 80   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 81 }
 82 
 83 static int dbus_server(GMainLoop *loop) {
 84     DBusConnection *bus;
 85     DBusError error;
 86     dbus_error_init (&error);
 87     bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
 88     if (bus) {
 89 	dbus_connection_setup_with_g_main (bus, NULL);
 90 
 91 	/* listening to messages from all objects as no path is specified */
 92 	dbus_bus_add_match (bus, RULE, &error); // see signals from the given interfacey
 93 	dbus_connection_add_filter (bus, signal_filter, loop, NULL);
 94 	return 0;
 95     }
 96     return -1;
 97 }
 98 
 99 #endif
100 #include <selinux/selinux.h>
101 #include <sys/file.h>
102 
103 /* size of the event structure, not counting name */
104 #define EVENT_SIZE  (sizeof (struct inotify_event))
105 /* reasonable guess as to size of 1024 events */
106 #define BUF_LEN        (1024 * (EVENT_SIZE + 16))
107 
108 static gboolean
109 io_channel_callback
110  (GIOChannel *source,
111   GIOCondition condition,
112   gpointer data __attribute__((__unused__)))
113 {
114 
115   char buffer[BUF_LEN+1];
116   gsize bytes_read;
117   unsigned int i = 0;
118 
119   if (condition & G_IO_IN) {
120     /* Data is available. */
121     g_io_channel_read_chars
122       (source, buffer,
123        sizeof (buffer),
124        &bytes_read, NULL);
125 
126     if (! bytes_read) {
127 	    /* Sesssion/Terminal Ended */
128 	    exit(0);
129     }
130 
131     while (i < bytes_read) {
132 	    struct inotify_event *event;
133 	    event = (struct inotify_event *)&buffer[i];
134 	    if (debug_mode)
135 		    printf("wd=%d mask=%u cookie=%u len=%u\n",
136 			   event->wd, event->mask,
137 			   event->cookie, event->len);
138 	    if (event->len)
139 		    watch_list_find(event->wd, event->name);
140 
141 	    i += EVENT_SIZE + event->len;
142     }
143   }
144 
145   /* An error happened while reading
146      the file. */
147 
148   if (condition & G_IO_NVAL)
149     return FALSE;
150 
151   /* We have reached the end of the
152      file. */
153 
154   if (condition & G_IO_HUP) {
155     g_io_channel_shutdown (source, 0, NULL);
156     exit(0);
157     return FALSE;
158   }
159 
160   /* Returning TRUE will make sure
161      the callback remains associated
162      to the channel. */
163 
164   return TRUE;
165 }
166 
167 int start() {
168 #ifdef HAVE_DBUS
169 	DBusConnection *bus;
170 	DBusError error;
171 	DBusMessage *message;
172 
173 	/* Get a connection to the session bus */
174 	dbus_error_init (&error);
175 	bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
176 	if (!bus) {
177 		if (debug_mode)
178 			g_warning ("Failed to connect to the D-BUS daemon: %s", error.message);
179 		dbus_error_free (&error);
180 		return 1;
181 	}
182 
183 
184 	/* Create a new signal "Start" on the interface,
185 	 * from the object  */
186 	message = dbus_message_new_signal (PATH,
187 					   INTERFACE, "Start");
188 	/* Send the signal */
189 	dbus_connection_send (bus, message, NULL);
190 	/* Free the signal now we have finished with it */
191 	dbus_message_unref (message);
192 #endif /* HAVE_DBUS */
193 	return 0;
194 }
195 
196 static int local_server() {
197 	// ! dbus, run as local service
198 	char *ptr=NULL;
199 	if (asprintf(&ptr, "%s/.restorecond", homedir) < 0) {
200 		if (debug_mode)
201 			perror("asprintf");
202 		return -1;
203 	}
204 	int fd = open(ptr, O_CREAT | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, S_IRUSR | S_IWUSR);
205 	if (debug_mode)
206 		g_warning ("Lock file: %s", ptr);
207 
208 	free(ptr);
209 	if (fd < 0) {
210 		if (debug_mode)
211 			perror("open");
212 		return -1;
213 	}
214 	if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
215 		if (debug_mode)
216 			perror("flock");
217 		return -1;
218 	}
219 	/* watch for stdin/terminal going away */
220 	GIOChannel *in = g_io_channel_unix_new(0);
221 	g_io_add_watch_full( in,
222 			     G_PRIORITY_HIGH,
223 			     G_IO_IN|G_IO_ERR|G_IO_HUP,
224 			     io_channel_callback, NULL, NULL);
225 
226 	return 0;
227 }
228 
229 int server(int master_fd, const char *watch_file) {
230     GMainLoop *loop;
231 
232     loop = g_main_loop_new (NULL, FALSE);
233 
234 #ifdef HAVE_DBUS
235     if (dbus_server(loop) != 0)
236 #endif /* HAVE_DBUS */
237 	    if (local_server())
238 		    goto end;
239 
240     read_config(master_fd, watch_file);
241 
242     if (watch_list_isempty()) goto end;
243 
244     set_matchpathcon_flags(MATCHPATHCON_NOTRANS);
245 
246     GIOChannel *c = g_io_channel_unix_new(master_fd);
247 
248     g_io_add_watch_full( c,
249 			 G_PRIORITY_HIGH,
250 			 G_IO_IN|G_IO_ERR|G_IO_HUP,
251 			 io_channel_callback, NULL, NULL);
252 
253     g_main_loop_run (loop);
254 
255 end:
256     g_main_loop_unref (loop);
257     return 0;
258 }
No issues found
  1 /*
  2  * utmpwatcher.c
  3  *
  4  * Copyright (C) 2006 Red Hat 
  5  * see file 'COPYING' for use and warranty information
  6  *
  7  * This program is free software; you can redistribute it and/or
  8  * modify it under the terms of the GNU General Public License as
  9  * published by the Free Software Foundation; either version 2 of
 10  * the License, or (at your option) any later version.
 11  * 
 12  * This program is distributed in the hope that it will be useful,
 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15  * GNU General Public License for more details.
 16 .* 
 17  * You should have received a copy of the GNU General Public License
 18  * along with this program; if not, write to the Free Software
 19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA     
 20  * 02111-1307  USA
 21  *
 22  * Authors:  
 23  *   Dan Walsh <dwalsh@redhat.com>
 24  *
 25  *
 26 */
 27 
 28 #define _GNU_SOURCE
 29 #include <sys/inotify.h>
 30 #include <stdio.h>
 31 #include <stdlib.h>
 32 #include <string.h>
 33 #include <sys/types.h>
 34 #include <sys/stat.h>
 35 #include <syslog.h>
 36 
 37 #include <limits.h>
 38 #include <utmp.h>
 39 #include <sys/types.h>
 40 #include <pwd.h>
 41 #include "restorecond.h"
 42 #include "utmpwatcher.h"
 43 #include "stringslist.h"
 44 
 45 static struct stringsList *utmp_ptr = NULL;
 46 static int utmp_wd = -1;
 47 
 48 unsigned int utmpwatcher_handle(int inotify_fd, int wd)
 49 {
 50 	int changed = 0;
 51 	struct utmp u;
 52 	char *utmp_path = "/var/run/utmp";
 53 	struct stringsList *prev_utmp_ptr = utmp_ptr;
 54 	if (wd != utmp_wd)
 55 		return -1;
 56 
 57 	utmp_ptr = NULL;
 58 	FILE *cfg = fopen(utmp_path, "r");
 59 	if (!cfg)
 60 		exitApp("Error reading utmp file.");
 61 
 62 	while (fread(&u, sizeof(struct utmp), 1, cfg) > 0) {
 63 		if (u.ut_type == USER_PROCESS)
 64 			strings_list_add(&utmp_ptr, u.ut_user);
 65 	}
 66 	fclose(cfg);
 67 	if (utmp_wd >= 0)
 68 		inotify_rm_watch(inotify_fd, utmp_wd);
 69 
 70 	utmp_wd =
 71 	    inotify_add_watch(inotify_fd, utmp_path, IN_MOVED_FROM | IN_MODIFY);
 72 	if (utmp_wd == -1)
 73 		exitApp("Error watching utmp file.");
 74 
 75 	changed = strings_list_diff(prev_utmp_ptr, utmp_ptr);
 76 	if (prev_utmp_ptr) {
 77 		strings_list_free(prev_utmp_ptr);
 78 	}
 79 	return changed;
 80 }
 81 
 82 static void watch_file(int inotify_fd, const char *file)
 83 {
 84 	struct stringsList *ptr = utmp_ptr;
 85 
 86 	while (ptr) {
 87 		struct passwd *pwd = getpwnam(ptr->string);
 88 		if (pwd) {
 89 			char *path = NULL;
 90 			if (asprintf(&path, "%s%s", pwd->pw_dir, file) < 0)
 91 				exitApp("Error allocating memory.");
 92 			watch_list_add(inotify_fd, path);
 93 			free(path);
 94 		}
 95 		ptr = ptr->next;
 96 	}
 97 }
 98 
 99 void utmpwatcher_add(int inotify_fd, const char *path)
100 {
101 	if (utmp_ptr == NULL) {
102 		utmpwatcher_handle(inotify_fd, utmp_wd);
103 	}
104 	watch_file(inotify_fd, path);
105 }
106 
107 void utmpwatcher_free(void)
108 {
109 	if (utmp_ptr)
110 		strings_list_free(utmp_ptr);
111 }
112 
113 #ifdef TEST
114 int main(int argc, char **argv)
115 {
116 	read_utmp();
117 	return 0;
118 }
119 #endif
| Location | Tool | Test ID | Issue | |
|---|---|---|---|---|
| watch.c:82:2 | clang-analyzer | Access to field 'wd' results in a dereference of a null pointer (loaded from variable 'ptr') | 
  1 #define _GNU_SOURCE
  2 #include <sys/inotify.h>
  3 #include <errno.h>
  4 #include <stdio.h>
  5 #include <stdlib.h>
  6 #include <string.h>
  7 #include <unistd.h>
  8 #include <ctype.h>
  9 #include <sys/types.h>
 10 #include <syslog.h>
 11 #include "../setfiles/restore.h"
 12 #include <glob.h>
 13 #include <libgen.h>
 14 #include <sys/stat.h>
 15 #include <string.h>
 16 #include <stdio.h>
 17 #include <fcntl.h>
 18 #include <selinux/selinux.h>
 19 #include "restorecond.h"
 20 #include "stringslist.h"
 21 #include "utmpwatcher.h"
 22 
 23 /* size of the event structure, not counting name */
 24 #define EVENT_SIZE  (sizeof (struct inotify_event))
 25 /* reasonable guess as to size of 1024 events */
 26 #define BUF_LEN        (1024 * (EVENT_SIZE + 16))
 27 
 28 
 29 struct watchList {
 30 	struct watchList *next;
 31 	int wd;
 32 	char *dir;
 33 	struct stringsList *files;
 34 };
 35 struct watchList *firstDir = NULL;
 36 
 37 int watch_list_isempty() {
 38 	return firstDir == NULL;
 39 }
 40 
 41 void watch_list_add(int fd, const char *path)
 42 {
 43 	struct watchList *ptr = NULL;
 44 	size_t i = 0;
 45 	struct watchList *prev = NULL;
 46 	glob_t globbuf;
 47 	char *x = strdup(path);
 48 	if (!x) exitApp("Out of Memory");
 49 	char *file = basename(x);
 50 	char *dir = dirname(x);
 51 	ptr = firstDir;
 52 
 53 	if (exclude(path)) goto end;
 54 
 55 	globbuf.gl_offs = 1;
 56 	if (glob(path,
 57 		 GLOB_TILDE | GLOB_PERIOD,
 58 		 NULL,
 59 		 &globbuf) >= 0) {
 60 		for (i=0; i < globbuf.gl_pathc; i++) {
 61 		  int len = strlen(globbuf.gl_pathv[i]) -2;
 62 		  if (len > 0 && strcmp(&globbuf.gl_pathv[i][len--], "/.") == 0) continue;
 63 		  if (len > 0 && strcmp(&globbuf.gl_pathv[i][len], "/..") == 0) continue;
 64 		  if (process_one_realpath(globbuf.gl_pathv[i], 0) > 0)
 65 			  process_one_realpath(globbuf.gl_pathv[i], 1);
 66 		}
 67 		globfree(&globbuf);
 68 	}
 69 
 70 	while (ptr != NULL) {
 71 		if (strcmp(dir, ptr->dir) == 0) {
 72 			strings_list_add(&ptr->files, file);
 73 			goto end;
 74 		}
 75 		prev = ptr;
 76 		ptr = ptr->next;
 77 	}
 78 	ptr = calloc(1, sizeof(struct watchList));
 79 
 80 	if (!ptr) exitApp("Out of Memory");
 81 
 82 	ptr->wd = inotify_add_watch(fd, dir, IN_CREATE | IN_MOVED_TO);
      (emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
 83 	if (ptr->wd == -1) {
 84 		free(ptr);
 85 		if (! run_as_user)
 86 			syslog(LOG_ERR, "Unable to watch (%s) %s\n",
 87 			       path, strerror(errno));
 88 		goto end;
 89 	}
 90 
 91 	ptr->dir = strdup(dir);
 92 	if (!ptr->dir)
 93 		exitApp("Out of Memory");
 94 
 95 	strings_list_add(&ptr->files, file);
 96 	if (prev)
 97 		prev->next = ptr;
 98 	else
 99 		firstDir = ptr;
100 
101 	if (debug_mode)
102 		printf("%d: Dir=%s, File=%s\n", ptr->wd, ptr->dir, file);
103 
104 end:
105 	free(x);
106 	return;
107 }
108 
109 /*
110    A file was in a direcroty has been created. This function checks to
111    see if it is one that we are watching.
112 */
113 
114 int watch_list_find(int wd, const char *file)
115 {
116 	struct watchList *ptr = NULL;
117 	ptr = firstDir;
118 	if (debug_mode)
119 		printf("%d: File=%s\n", wd, file);
120 	while (ptr != NULL) {
121 		if (ptr->wd == wd) {
122 			int exact=0;
123 			if (strings_list_find(ptr->files, file, &exact) == 0) {
124 				char *path = NULL;
125 				if (asprintf(&path, "%s/%s", ptr->dir, file) <
126 				    0)
127 					exitApp("Error allocating memory.");
128 
129 				process_one_realpath(path, 0);
130 				free(path);
131 				return 0;
132 			}
133 			if (debug_mode)
134 				strings_list_print(ptr->files);
135 
136 			/* Not found in this directory */
137 			return -1;
138 		}
139 		ptr = ptr->next;
140 	}
141 	/* Did not find a directory */
142 	return -1;
143 }
144 
145 void watch_list_free(int fd)
146 {
147 	struct watchList *ptr = NULL;
148 	struct watchList *prev = NULL;
149 	ptr = firstDir;
150 
151 	while (ptr != NULL) {
152 		inotify_rm_watch(fd, ptr->wd);
153 		strings_list_free(ptr->files);
154 		free(ptr->dir);
155 		prev = ptr;
156 		ptr = ptr->next;
157 		free(prev);
158 	}
159 	firstDir = NULL;
160 }
161 
162 /*
163    Inotify watch loop
164 */
165 int watch(int fd, const char *watch_file)
166 {
167 	char buf[BUF_LEN];
168 	int len, i = 0;
169 	if (firstDir == NULL) return 0;
170 
171 	len = read(fd, buf, BUF_LEN);
172 	if (len < 0) {
173 		if (terminate == 0) {
174 			syslog(LOG_ERR, "Read error (%s)", strerror(errno));
175 			return 0;
176 		}
177 		syslog(LOG_ERR, "terminated");
178 		return -1;
179 	} else if (!len)
180 		/* BUF_LEN too small? */
181 		return -1;
182 	while (i < len) {
183 		struct inotify_event *event;
184 		event = (struct inotify_event *)&buf[i];
185 		if (debug_mode)
186 			printf("wd=%d mask=%u cookie=%u len=%u\n",
187 			       event->wd, event->mask,
188 			       event->cookie, event->len);
189 		if (event->mask & ~IN_IGNORED) {
190 			if (event->wd == master_wd)
191 				read_config(fd, watch_file);
192 			else {
193 				switch (utmpwatcher_handle(fd, event->wd)) {
194 				case -1:	/* Message was not for utmpwatcher */
195 					if (event->len)
196 						watch_list_find(event->wd, event->name);
197 					break;
198 				case 1:	/* utmp has changed need to reload */
199 					read_config(fd, watch_file);
200 					break;
201 
202 				default:	/* No users logged in or out */
203 					break;
204 				}
205 			}
206 		}
207 
208 		i += EVENT_SIZE + event->len;
209 	}
210 	return 0;
211 }
212 
213 static void process_config(int fd, FILE * cfg)
214 {
215 	char *line_buf = NULL;
216 	size_t len = 0;
217 
218 	while (getline(&line_buf, &len, cfg) > 0) {
219 		char *buffer = line_buf;
220 		while (isspace(*buffer))
221 			buffer++;
222 		if (buffer[0] == '#')
223 			continue;
224 		int l = strlen(buffer) - 1;
225 		if (l <= 0)
226 			continue;
227 		buffer[l] = 0;
228 		if (buffer[0] == '~') {
229 			if (run_as_user) {
230 				char *ptr=NULL;
231 				if (asprintf(&ptr, "%s%s", homedir, &buffer[1]) < 0)
232 					exitApp("Error allocating memory.");
233 
234 				watch_list_add(fd, ptr);
235 				free(ptr);
236 			} else {
237 				utmpwatcher_add(fd, &buffer[1]);
238 			}
239 		} else {
240 			watch_list_add(fd, buffer);
241 		}
242 	}
243 	free(line_buf);
244 }
245 
246 /*
247    Read config file ignoring Comment lines
248    Files specified one per line.  Files with "~" will be expanded to the logged in users
249    homedirs.
250 */
251 
252 void read_config(int fd, const char *watch_file_path)
253 {
254 
255 	FILE *cfg = NULL;
256 	if (debug_mode)
257 		printf("Read Config\n");
258 
259 	watch_list_free(fd);
260 
261 	cfg = fopen(watch_file_path, "r");
262 	if (!cfg){
263 		perror(watch_file_path);
264 		exitApp("Error reading config file");
265 	}
266 	process_config(fd, cfg);
267 	fclose(cfg);
268 
269 	inotify_rm_watch(fd, master_wd);
270 	master_wd =
271 	    inotify_add_watch(fd, watch_file_path, IN_MOVED_FROM | IN_MODIFY);
272 	if (master_wd == -1)
273 		exitApp("Error watching config file.");
274 }
No issues found
  1 /*                               -*- Mode: C -*- 
  2  * open_init_pty.c --- 
  3  * Author           : Manoj Srivastava ( srivasta@glaurung.internal.golden-gryphon.com ) 
  4  * Created On       : Fri Jan 14 10:48:28 2005
  5  * Created On Node  : glaurung.internal.golden-gryphon.com
  6  * Last Modified By : Manoj Srivastava
  7  * Last Modified On : Thu Sep 15 00:57:00 2005
  8  * Last Machine Used: glaurung.internal.golden-gryphon.com
  9  * Update Count     : 92
 10  * Status           : Unknown, Use with caution!
 11  * HISTORY          : 
 12  * Description      : 
 13  *
 14  * Distributed under the terms of the GNU General Public License v2
 15  *
 16  * open_init_pty
 17  *
 18  * SYNOPSIS:
 19  *
 20  * This program allows a systems administrator to execute daemons
 21  * which need to work in the initrc domain, and which need to have
 22  * pty's as system_u:system_r:initrc_t
 23  *
 24  * USAGE:
 25  *
 26  * * arch-tag: a5583d39-72b9-4cdf-ba1b-5678ea4cbe20
 27  */
 28 
 29 #include <stdio.h>
 30 #include <stdlib.h>
 31 #include <unistd.h>
 32 #include <signal.h>
 33 #include <errno.h>
 34 
 35 #include <sysexits.h>
 36 
 37 #include <pty.h>		/* for openpty and forkpty */
 38 #include <utmp.h>		/* for login_tty */
 39 #include <termios.h>
 40 #include <fcntl.h>
 41 
 42 #include <sys/select.h>
 43 
 44 static struct termios saved_termios;
 45 static int saved_fd = -1;
 46 static enum { RESET, RAW, CBREAK } tty_state = RESET;
 47 
 48 static int tty_semi_raw(int fd)
 49 {
 50 	struct termios buf;
 51 
 52 	if (tty_state == RESET) {
 53 		if (tcgetattr(fd, &saved_termios) < 0) {
 54 			return -1;
 55 		}
 56 	}
 57 
 58 	buf = saved_termios;
 59 	/*
 60 	 * echo off, canonical mode off, extended input processing off,
 61 	 * signal chars off 
 62 	 */
 63 	buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
 64 	/*
 65 	 * no SIGINT on break, CR-to-NL off, input parity check off, do not
 66 	 * strip 8th bit on input,output flow control off
 67 	 */
 68 	buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
 69 	/* Clear size bits, parity checking off */
 70 	buf.c_cflag &= ~(CSIZE | PARENB);
 71 	/* set 8 bits/char */
 72 	buf.c_cflag |= CS8;
 73 	/* Output processing off 
 74 	   buf.c_oflag    &= ~(OPOST); */
 75 
 76 	buf.c_cc[VMIN] = 1;	/* one byte at a time, no timer */
 77 	buf.c_cc[VTIME] = 0;
 78 	if (tcsetattr(fd, TCSANOW, &buf) < 0) {
 79 		return -1;
 80 	}			/* end of if(tcsetattr(fileno(stdin), TCSANOW, &buf) < 0) */
 81 	tty_state = RAW;
 82 	saved_fd = fd;
 83 	return 0;
 84 }
 85 
 86 void tty_atexit(void)
 87 {
 88 	if (tty_state != CBREAK && tty_state != RAW) {
 89 		return;
 90 	}
 91 
 92 	if (tcsetattr(saved_fd, TCSANOW, &saved_termios) < 0) {
 93 		return;
 94 	}			/* end of if(tcsetattr(fileno(stdin), TCSANOW, &buf) < 0) */
 95 	tty_state = RESET;
 96 	return;
 97 }
 98 
 99 int main(int argc, char *argv[])
100 {
101 	pid_t child_pid;
102 	struct termios tty_attr;
103 	struct winsize window_size;
104 	int pty_master;
105 	int retval = 0;
106 
107 	/* for select */
108 	fd_set readfds;
109 	fd_set writefds;
110 	fd_set exceptfds;
111 
112 	int err_count = 0;
113 
114 	/* for sigtimedwait() */
115 	struct timespec timeout;
116 	char buf[16384];
117 
118 	if (argc == 1) {
119 		printf("usage: %s PROGRAM [ARGS]...\n", argv[0]);
120 		exit(1);
121 	}
122 
123 	sigset_t signal_set;
124 	siginfo_t signalinfo;
125 
126 	/* set up SIGCHLD */
127 	sigemptyset(&signal_set);	/* no signals */
128 	sigaddset(&signal_set, SIGCHLD);	/* Add sig child  */
129 	sigprocmask(SIG_BLOCK, &signal_set, NULL);	/* Block the signal */
130 
131 	/* Set both to 0, so sigtimed wait just does a poll */
132 	timeout.tv_sec = 0;
133 	timeout.tv_nsec = 0;
134 
135 	if (isatty(fileno(stdin))) {
136 		/* get terminal parameters associated with stdout */
137 		if (tcgetattr(fileno(stdout), &tty_attr) < 0) {
138 			perror("tcgetattr:");
139 			exit(EX_OSERR);
140 		}
141 
142 		/* end of if(tcsetattr(&tty_attr)) */
143 		/* get window size */
144 		if (ioctl(fileno(stdout), TIOCGWINSZ, &window_size) < 0) {
145 			perror("ioctl stdout:");
146 			exit(1);
147 		}
148 
149 		child_pid = forkpty(&pty_master, NULL, &tty_attr, &window_size);
150 	} /* end of if(isatty(fileno(stdin))) */
151 	else {			/* not interactive */
152 		child_pid = forkpty(&pty_master, NULL, NULL, NULL);
153 	}
154 
155 	if (child_pid < 0) {
156 		perror("forkpty():");
157 		fflush(stdout);
158 		fflush(stderr);
159 		exit(EX_OSERR);
160 	}			/* end of if(child_pid < 0) */
161 	if (child_pid == 0) {
162 		/* in the child */
163 		struct termios s_tty_attr;
164 		if (tcgetattr(fileno(stdin), &s_tty_attr)) {
165 			perror("Child:");
166 			fflush(stdout);
167 			fflush(stderr);
168 			exit(EXIT_FAILURE);
169 		}
170 		/* Turn off echo */
171 		s_tty_attr.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
172 		/* Also turn of NL to CR?LF on output */
173 		s_tty_attr.c_oflag &= ~(ONLCR);
174 		if (tcsetattr(fileno(stdin), TCSANOW, &s_tty_attr)) {
175 			perror("Child:");
176 			exit(EXIT_FAILURE);
177 		}
178 		{		/* There is no reason to block sigchild for the process we
179 				   shall exec here */
180 			sigset_t chld_signal_set;
181 			/* release SIGCHLD */
182 			sigemptyset(&chld_signal_set);	/* no signals */
183 			sigaddset(&chld_signal_set, SIGCHLD);	/* Add sig child  */
184 			sigprocmask(SIG_UNBLOCK, &chld_signal_set, NULL);	/* Unblock the signal */
185 		}
186 
187 		if (execvp(argv[1], argv + 1)) {
188 			perror("Exec:");
189 			fflush(stdout);
190 			fflush(stderr);
191 			exit(EXIT_FAILURE);
192 		}
193 	}
194 
195 	/* end of if(child_pid == 0) */
196 	/* 
197 	 * OK. Prepare to handle IO from the child. We need to transfer
198 	 * everything from the child's stdout to ours.
199 	 */
200 	FD_ZERO(&readfds);
201 	FD_ZERO(&writefds);
202 	FD_ZERO(&exceptfds);
203 
204 	/*
205 	 * Read current file descriptor flags, preparing to do non blocking reads
206 	 */
207 	retval = fcntl(pty_master, F_GETFL);
208 	if (retval < 0) {
209 		perror("fcntl_get");
210 		fflush(stdout);
211 		fflush(stderr);
212 		exit(EX_IOERR);
213 	}
214 
215 	/* Set the connection to be non-blocking */
216 	if (fcntl(pty_master, F_SETFL, retval | O_NONBLOCK) < 0) {
217 		perror("fcnt_setFlag_nonblock:");
218 		fflush(stdout);
219 		fflush(stderr);
220 		exit(1);
221 	}
222 
223 	FD_SET(pty_master, &readfds);
224 	FD_SET(pty_master, &writefds);
225 	FD_SET(fileno(stdin), &readfds);
226 	if (isatty(fileno(stdin))) {
227 		if (tty_semi_raw(fileno(stdin)) < 0) {
228 			perror("Error: settingraw mode:");
229 			fflush(stdout);
230 			fflush(stderr);
231 		}		/* end of if(tty_raw(fileno(stdin)) < 0) */
232 		if (atexit(tty_atexit) < 0) {
233 			perror("Atexit setup:");
234 			fflush(stdout);
235 			fflush(stderr);
236 		}		/* end of if(atexit(tty_atexit) < 0) */
237 	}
238 
239 	/* ignore return from nice, but lower our priority */
240 	int ignore __attribute__ ((unused)) = nice(19);
241 
242 	/* while no signal, we loop around */
243 	int done = 0;
244 	while (!done) {
245 		struct timeval interval;
246 		fd_set t_readfds;
247 		fd_set t_writefds;
248 		fd_set t_exceptfds;
249 		/*
250 		 * We still use a blocked signal, and check for SIGCHLD every
251 		 * loop, since waiting infinitely did not really help the load
252 		 * when running, say, top. 
253 		 */
254 		interval.tv_sec = 0;
255 		interval.tv_usec = 200000;	/* so, check for signals every 200 milli
256 						   seconds */
257 
258 		t_readfds = readfds;
259 		t_writefds = writefds;
260 		t_exceptfds = exceptfds;
261 
262 		/* check for the signal */
263 		retval = sigtimedwait(&signal_set, &signalinfo, &timeout);
264 
265 		if (retval == SIGCHLD) {
266 			/* child terminated */
267 			done = 1;	/* in case they do not close off their
268 					   file descriptors */
269 		} else {
270 			if (retval < 0) {
271 				if (errno != EAGAIN) {
272 					perror("sigtimedwait");
273 					fflush(stdout);
274 					fflush(stderr);
275 					exit(EX_IOERR);
276 				} else {
277 					/* No signal in set was delivered within the timeout period specified */
278 				}
279 			}
280 		}		/* end of else */
281 
282 		if (select
283 		    (pty_master + 1, &t_readfds, &t_writefds, &t_exceptfds,
284 		     &interval) < 0) {
285 			perror("Select:");
286 			fflush(stdout);
287 			fflush(stderr);
288 			exit(EX_IOERR);
289 		}
290 
291 		if (FD_ISSET(pty_master, &t_readfds)) {
292 			retval = read(pty_master, buf, (unsigned int)16384);
293 			if (retval < 0) {
294 				if (errno != EINTR && errno != EAGAIN) {	/* Nothing left to read?  */
295 					fflush(stdout);
296 					fflush(stderr);
297 					/* fprintf(stderr, "DEBUG: %d: Nothing left to read?\n", __LINE__); */
298 					exit(EXIT_SUCCESS);
299 				}	/* end of else */
300 			} /* end of if(retval < 0) */
301 			else {
302 				if (retval == 0) {
303 					if (++err_count > 5) {	/* child closed connection */
304 						fflush(stdout);
305 						fflush(stderr);
306 						/*fprintf(stderr, "DEBUG: %d: child closed connection?\n", __LINE__); */
307 						exit(EXIT_SUCCESS);
308 					}
309 				} /* end of if(retval == 0) */
310 				else {
311 					ssize_t nleft = retval;
312 					ssize_t nwritten = 0;
313 					char *ptr = buf;
314 					while (nleft > 0) {
315 						if ((nwritten =
316 						     write(fileno(stdout), ptr,
317 							   (unsigned int)nleft))
318 						    <= 0) {
319 							if (errno == EINTR) {
320 								nwritten = 0;
321 							} /* end of if(errno == EINTR) */
322 							else {
323 								perror("write");
324 								fflush(stdout);
325 								fflush(stderr);
326 								exit(EXIT_SUCCESS);
327 							}	/* end of else */
328 						}	/* end of if((nwritten = write(sockfd, ptr, nleft)) <= 0) */
329 						nleft -= nwritten;
330 						ptr += nwritten;
331 					}	/* end of while(nleft > 0) */
332 
333 					/* fprintf(stderr, "DEBUG: %d: wrote %d\n", __LINE__, retval); */
334 					fflush(stdout);
335 				}	/* end of else */
336 			}	/* end of else */
337 		}
338 		if (FD_ISSET(fileno(stdin), &t_readfds)) {
339 			if (FD_ISSET(pty_master, &t_writefds)) {
340 				retval =
341 				    read(fileno(stdin), buf,
342 					 (unsigned int)16384);
343 				if (retval < 0) {
344 					if (errno != EINTR && errno != EAGAIN) {	/* Nothing left to read?  */
345 						fflush(stdout);
346 						fflush(stderr);
347 						exit(EXIT_SUCCESS);
348 					}	/* end of else */
349 				} /* end of if(retval < 0) */
350 				else {
351 					if (retval == 0) {
352 						if (++err_count > 5) {	/* lost controlling tty */
353 							fflush(stdout);
354 							fflush(stderr);
355 							exit(EXIT_SUCCESS);
356 						}
357 					} /* end of if(retval == 0) */
358 					else {
359 						ssize_t nleft = retval;
360 						ssize_t nwritten = 0;
361 						char *ptr = buf;
362 						while (nleft > 0) {
363 							if ((nwritten =
364 							     write(pty_master,
365 								   ptr,
366 								   (unsigned
367 								    int)nleft))
368 							    <= 0) {
369 								if (errno ==
370 								    EINTR) {
371 									nwritten
372 									    = 0;
373 								} /* end of if(errno == EINTR) */
374 								else {
375 									perror
376 									    ("write");
377 									fflush
378 									    (stdout);
379 									fflush
380 									    (stderr);
381 									exit(EXIT_SUCCESS);
382 								}	/* end of else */
383 							}	/* end of if((nwritten = write(sockfd, ptr, nleft)) <= 0) */
384 							nleft -= nwritten;
385 							ptr += nwritten;
386 						}	/* end of while(nleft > 0) */
387 
388 						fflush(stdout);
389 					}	/* end of else */
390 				}	/* end of else */
391 			}	/* end of if(FD_ISSET(pty_master, &writefds)) */
392 		}		/* something to read on stdin */
393 	}			/* Loop */
394 
395 	fflush(stdout);
396 	fflush(stderr);
397 
398 	exit(EXIT_SUCCESS);
399 }				/* end of main() */
No issues found
  1 /************************************************************************
  2  *
  3  * run_init
  4  *
  5  * SYNOPSIS:
  6  *
  7  * This program allows a user to run an /etc/init.d script in the proper context.
  8  *
  9  * USAGE:
 10  *
 11  * run_init <script> <args>
 12  *
 13  * BUILD OPTIONS:
 14  *
 15  * option USE_PAM:
 16  *
 17  * Set the USE_PAM constant if you want to authenticate users via PAM.
 18  * If USE_PAM is not set, users will be authenticated via direct
 19  * access to the shadow password file.
 20  *
 21  * If you decide to use PAM must be told how to handle run_init.  A
 22  * good rule-of-thumb might be to tell PAM to handle run_init in the
 23  * same way it handles su, except that you should remove the pam_rootok.so
 24  * entry so that even root must re-authenticate to run the init scripts
 25  * in the proper context.
 26  *
 27  * If you choose not to use PAM, make sure you have a shadow passwd file
 28  * in /etc/shadow.  You can use a simlink if your shadow passwd file
 29  * lives in another directory.  Example:
 30  *   su
 31  *   cd /etc
 32  *   ln -s /etc/auth/shadow shadow
 33  *
 34  * If you decide not to use PAM, you will also have to make run_init
 35  * setuid root, so that it can read the shadow passwd file.
 36  * 
 37  *
 38  *************************************************************************/
 39 
 40 #include <stdio.h>
 41 #include <stdlib.h>		/* for malloc(), realloc(), free() */
 42 #include <pwd.h>		/* for getpwuid() */
 43 #include <sys/types.h>		/* to make getuid() and getpwuid() happy */
 44 #include <sys/wait.h>		/* for wait() */
 45 #include <sys/stat.h>		/* for struct stat and friends */
 46 #include <getopt.h>		/* for getopt_long() form of getopt() */
 47 #include <selinux/selinux.h>
 48 #include <selinux/get_default_type.h>
 49 #include <selinux/context.h>	/* for context-mangling functions */
 50 #include <fcntl.h>
 51 #include <ctype.h>
 52 #include <limits.h>
 53 #ifdef USE_AUDIT
 54 #include <libaudit.h>
 55 #endif
 56 #ifdef USE_NLS
 57 #include <libintl.h>
 58 #include <locale.h>
 59 #define _(msgid) gettext (msgid)
 60 #else
 61 #define _(msgid) (msgid)
 62 #endif
 63 #ifndef PACKAGE
 64 #define PACKAGE "policycoreutils"	/* the name of this package lang translation */
 65 #endif
 66 /* USAGE_STRING describes the command-line args of this program. */
 67 #define USAGE_STRING _("USAGE: run_init <script> <args ...>\n\
 68   where: <script> is the name of the init script to run,\n\
 69          <args ...> are the arguments to that script.")
 70 
 71 #define CONTEXT_FILE "initrc_context"
 72 #ifdef USE_PAM
 73 
 74 /************************************************************************
 75  *
 76  * All PAM code goes in this section.
 77  *
 78  ************************************************************************/
 79 
 80 #include <unistd.h>		/* for getuid(), exit(), getopt() */
 81 
 82 #include <security/pam_appl.h>	/* for PAM functions */
 83 #include <security/pam_misc.h>	/* for misc_conv PAM utility function */
 84 
 85 #define SERVICE_NAME "run_init"	/* the name of this program for PAM */
 86 				  /* The file containing the context to run 
 87 				   * the scripts under.                     */
 88 
 89 int authenticate_via_pam(const struct passwd *);
 90 
 91 /* authenticate_via_pam()
 92  *
 93  * in:     p_passwd_line - struct containing data from our user's line in 
 94  *                         the passwd file.
 95  * out:    nothing
 96  * return: value   condition
 97  *         -----   ---------
 98  *           1     PAM thinks that the user authenticated themselves properly
 99  *           0     otherwise
100  *
101  * This function uses PAM to authenticate the user running this
102  * program.  This is the only function in this program that makes PAM
103  * calls.
104  *
105  */
106 
107 int authenticate_via_pam(const struct passwd *p_passwd_line)
108 {
109 
110 	int result = 0;		/* our result, set to 0 (not authenticated) by default */
111 	pam_handle_t *pam_handle;	/* opaque handle used by all PAM functions */
112 
113 	/* This is a jump table of functions for PAM to use when it wants to *
114 	 * communicate with the user.  We'll be using misc_conv(), which is  *
115 	 * provided for us via pam_misc.h.                                   */
116 	struct pam_conv pam_conversation = {
117 		misc_conv,
118 		NULL
119 	};
120 
121 	/* Make `p_pam_handle' a valid PAM handle so we can use it when *
122 	 * calling PAM functions.                                       */
123 	if (PAM_SUCCESS != pam_start(SERVICE_NAME,
124 				     p_passwd_line->pw_name,
125 				     &pam_conversation, &pam_handle)) {
126 		fprintf(stderr, _("failed to initialize PAM\n"));
127 		exit(-1);
128 	}
129 
130 	/* Ask PAM to authenticate the user running this program */
131 	if (PAM_SUCCESS == pam_authenticate(pam_handle, 0)) {
132 		result = 1;	/* user authenticated OK! */
133 	}
134 
135 	/* If we were successful, call pam_acct_mgmt() to reset the
136          * pam_tally failcount.
137          */
138 	if (result && (PAM_SUCCESS != pam_acct_mgmt(pam_handle, 0)) ) {
139 		fprintf(stderr, _("failed to get account information\n"));
140 		exit(-1);
141 	}	
142 
143 	/* We're done with PAM.  Free `pam_handle'. */
144 	pam_end(pam_handle, PAM_SUCCESS);
145 
146 	return (result);
147 
148 }				/* authenticate_via_pam() */
149 
150 #else				/* else !USE_PAM */
151 
152 /************************************************************************
153  *
154  * All shadow passwd code goes in this section.
155  *
156  ************************************************************************/
157 
158 #include <unistd.h>		/* for getuid(), exit(), crypt() */
159 #include <shadow.h>		/* for shadow passwd functions */
160 #include <string.h>		/* for strlen(), memset() */
161 
162 #define PASSWORD_PROMPT _("Password:")	/* prompt for getpass() */
163 
164 int authenticate_via_shadow_passwd(const struct passwd *);
165 
166 /* authenticate_via_shadow_passwd()
167  *
168  * in:     p_passwd_line - struct containing data from our user's line in 
169  *                         the passwd file.
170  * out:    nothing
171  * return: value   condition
172  *         -----   ---------
173  *           1     user authenticated themselves properly according to the
174  *                 shadow passwd file.
175  *           0     otherwise
176  *
177  * This function uses the shadow passwd file to authenticate the user running
178  * this program.
179  *
180  */
181 
182 int authenticate_via_shadow_passwd(const struct passwd *p_passwd_line)
183 {
184 
185 	struct spwd *p_shadow_line;	/* struct derived from shadow passwd file line */
186 	char *unencrypted_password_s;	/* unencrypted password input by user */
187 	char *encrypted_password_s;	/* user's password input after being crypt()ed */
188 
189 	/* Make `p_shadow_line' point to the data from the current user's *
190 	 * line in the shadow passwd file.                                */
191 	setspent();		/* Begin access to the shadow passwd file. */
192 	p_shadow_line = getspnam(p_passwd_line->pw_name);
193 	endspent();		/* End access to the shadow passwd file. */
194 	if (!(p_shadow_line)) {
195 		fprintf(stderr,
196 			_
197 			("Cannot find your entry in the shadow passwd file.\n"));
198 		exit(-1);
199 	}
200 
201 	/* Ask user to input unencrypted password */
202 	if (!(unencrypted_password_s = getpass(PASSWORD_PROMPT))) {
203 		fprintf(stderr, _("getpass cannot open /dev/tty\n"));
204 		exit(-1);
205 	}
206 
207 	/* Use crypt() to encrypt user's input password.  Clear the *
208 	 * unencrypted password as soon as we're done, so it is not * 
209 	 * visible to memory snoopers.                              */
210 	encrypted_password_s = crypt(unencrypted_password_s,
211 				     p_shadow_line->sp_pwdp);
212 	memset(unencrypted_password_s, 0, strlen(unencrypted_password_s));
213 
214 	/* Return 1 (authenticated) iff the encrypted version of the user's *
215 	 * input password matches the encrypted password stored in the      *
216 	 * shadow password file.                                            */
217 	return (!strcmp(encrypted_password_s, p_shadow_line->sp_pwdp));
218 
219 }				/* authenticate_via_shadow_passwd() */
220 
221 #endif				/* if/else USE_PAM */
222 
223 /*
224  * authenticate_user()
225  *
226  * Authenticate the user.
227  *
228  * in:		nothing
229  * out:		nothing
230  * return:	0 When success
231  *		-1 When failure
232  */
233 int authenticate_user()
234 {
235 
236 #define INITLEN 255
237 	struct passwd *p_passwd_line;	/* struct derived from passwd file line */
238 	uid_t uid;
239 
240 	/*
241 	 * Determine the Linux user identity to re-authenticate.
242 	 * If supported and set, use the login uid, as this should be more stable.
243 	 * Otherwise, use the real uid.
244 	 * The SELinux user identity is no longer used, as Linux users are now
245 	 * mapped to SELinux users via seusers and the SELinux user identity space
246 	 * is separate.
247 	 */
248 #ifdef USE_AUDIT
249 	uid = audit_getloginuid();
250 	if (uid == (uid_t) - 1)
251 		uid = getuid();
252 #else
253 	uid = getuid();
254 #endif
255 
256 	p_passwd_line = getpwuid(uid);
257 	if (!p_passwd_line) {
258 		fprintf(stderr, "cannot find your entry in the passwd file.\n");
259 		return (-1);
260 	}
261 
262 	printf("Authenticating %s.\n", p_passwd_line->pw_name);
263 
264 	/* 
265 	 * Re-authenticate the user running this program.
266 	 * This is just to help confirm user intent (vs. invocation by
267 	 * malicious software), not to authorize the operation (which is covered
268 	 * by policy).  Trusted path mechanism would be preferred.
269 	 */
270 #ifdef USE_PAM
271 	if (!authenticate_via_pam(p_passwd_line)) {
272 #else				/* !USE_PAM */
273 	if (!authenticate_via_shadow_passwd(p_passwd_line)) {
274 #endif				/* if/else USE_PAM */
275 		fprintf(stderr, _("run_init: incorrect password for %s\n"),
276 			p_passwd_line->pw_name);
277 		return (-1);
278 	}
279 
280 	/* If we reach here, then we have authenticated the user. */
281 #ifdef CANTSPELLGDB
282 	printf("You are authenticated!\n");
283 #endif
284 
285 	return 0;
286 
287 }				/* authenticate_user() */
288 
289 /*
290  * get_init_context()
291  *
292  * Get the CONTEXT associated with the context for the init scripts.             *
293  *
294  * in:		nothing
295  * out:		The CONTEXT associated with the context.
296  * return:	0 on success, -1 on failure.
297  */
298 int get_init_context(security_context_t * context)
299 {
300 
301 	FILE *fp;
302 	char buf[255], *bufp;
303 	int buf_len;
304 	char context_file[PATH_MAX];
305 	snprintf(context_file, sizeof(context_file) - 1, "%s/%s",
306 		 selinux_contexts_path(), CONTEXT_FILE);
307 	fp = fopen(context_file, "r");
308 	if (!fp) {
309 		fprintf(stderr, _("Could not open file %s\n"), context_file);
310 		return -1;
311 	}
312 
313 	while (1) {		/* loop until we find a non-empty line */
314 
315 		if (!fgets(buf, sizeof buf, fp))
316 			break;
317 
318 		buf_len = strlen(buf);
319 		if (buf[buf_len - 1] == '\n')
320 			buf[buf_len - 1] = 0;
321 
322 		bufp = buf;
323 		while (*bufp && isspace(*bufp))
324 			bufp++;
325 
326 		if (*bufp) {
327 			*context = strdup(bufp);
328 			if (!(*context))
329 				goto out;
330 			fclose(fp);
331 			return 0;
332 		}
333 	}
334       out:
335 	fclose(fp);
336 	fprintf(stderr, _("No context in file %s\n"), context_file);
337 	return -1;
338 
339 }				/* get_init_context() */
340 
341 /*****************************************************************************
342  * main()                                                                    *
343  *****************************************************************************/
344 int main(int argc, char *argv[])
345 {
346 
347 	extern char *optarg;	/* used by getopt() for arg strings */
348 	extern int opterr;	/* controls getopt() error messages */
349 	security_context_t new_context;	/* context for the init script context  */
350 
351 #ifdef USE_NLS
352 	setlocale(LC_ALL, "");
353 	bindtextdomain(PACKAGE, LOCALEDIR);
354 	textdomain(PACKAGE);
355 #endif
356 
357 	/* Verify that we are running on a flask-enabled kernel. */
358 	if (!is_selinux_enabled()) {
359 		fprintf(stderr,
360 			_
361 			("Sorry, run_init may be used only on a SELinux kernel.\n"));
362 		exit(-1);
363 	}
364 
365 	/*
366 	 * Step 1:  Handle command-line arguments. The first argument is the 
367 	 * name of the script to run. All other arguments are for the script
368 	 * itself, and will be passed directly to the script.
369 	 */
370 
371 	if (argc < 2) {
372 		fprintf(stderr, "%s\n", USAGE_STRING);
373 		exit(-1);
374 	}
375 
376 	/*
377 	 * Step 2:  Authenticate the user.
378 	 */
379 	if (authenticate_user() != 0) {
380 		fprintf(stderr, _("authentication failed.\n"));
381 		exit(-1);
382 	}
383 
384 	/*
385 	 * Step 3: Get the context for the script to be run in.
386 	 */
387 	if (get_init_context(&new_context) == 0) {
388 #ifdef CANTSPELLGDB
389 		printf("context is %s\n", new_context);
390 #endif
391 	} else {
392 		exit(-1);
393 	}
394 
395 	/*
396 	 * Step 4: Run the command in the correct context.
397 	 */
398 
399 	if (chdir("/")) {
400 		perror("chdir");
401 		exit(-1);
402 	}
403 
404 	if (setexeccon(new_context) < 0) {
405 		fprintf(stderr, _("Could not set exec context to %s.\n"),
406 			new_context);
407 		exit(-1);
408 	}
409 	if (! access("/usr/sbin/open_init_pty", X_OK)) {
410 		if (execvp(argv[1], argv + 1)) {
411 			perror("execvp");
412 			exit(-1);
413 		}
414 		return 0;
415 	}
416 	/*
417 	 * Do not execvp the command directly from run_init; since it would run
418 	 * under with a pty under sysadm_devpts_t. Instead, we call open_init_tty,
419 	 * which transitions us into initrc_t, which then spawns a new
420 	 * process, that gets a pty with context initrc_devpts_t. Just
421 	 * execvp or using a exec(1) recycles pty's, and does not open a new
422 	 * one. 
423 	 */
424 	if (execvp("/usr/sbin/open_init_pty", argv)) {
425 		perror("execvp");
426 		exit(-1);
427 	}
428 	return 0;
429 
430 }				/* main() */
| Location | Tool | Test ID | Issue | |
|---|---|---|---|---|
| seunshare.c:271:11 | clang-analyzer | The left operand to '|' is always 0 | ||
| seunshare.c:791:0 | cppcheck | memleakOnRealloc | Common realloc mistake: 'pid_table' nulled but not freed upon failure | 
   1 /*
   2  * Authors: Dan Walsh <dwalsh@redhat.com>
   3  * Authors: Thomas Liu <tliu@fedoraproject.org>
   4  */
   5 
   6 #define _GNU_SOURCE
   7 #include <signal.h>
   8 #include <sys/fsuid.h>
   9 #include <sys/stat.h>
  10 #include <sys/types.h>
  11 #include <sys/wait.h>
  12 #include <syslog.h>
  13 #include <sys/mount.h>
  14 #include <glob.h>
  15 #include <pwd.h>
  16 #include <sched.h>
  17 #include <libcgroup.h>
  18 #include <string.h>
  19 #include <stdio.h>
  20 #include <regex.h>
  21 #include <unistd.h>
  22 #include <stdlib.h>
  23 #include <cap-ng.h>
  24 #include <getopt.h>		/* for getopt_long() form of getopt() */
  25 #include <limits.h>
  26 #include <stdlib.h>
  27 #include <errno.h>
  28 #include <fcntl.h>
  29 
  30 #include <selinux/selinux.h>
  31 #include <selinux/context.h>	/* for context-mangling functions */
  32 #include <dirent.h>
  33 
  34 
  35 /*
  36  * Note setfsuid never returns an error code.  But the compiler complains if 
  37  * I do not check, so I am checking for -1, which should never happen.
  38  */
  39 
  40 #ifdef USE_NLS
  41 #include <locale.h>		/* for setlocale() */
  42 #include <libintl.h>		/* for gettext() */
  43 #define _(msgid) gettext (msgid)
  44 #else
  45 #define _(msgid) (msgid)
  46 #endif
  47 
  48 #ifndef MS_REC
  49 #define MS_REC 1<<14
  50 #endif
  51 
  52 #ifndef MS_SLAVE
  53 #define MS_SLAVE 1<<19
  54 #endif
  55 
  56 #ifndef PACKAGE
  57 #define PACKAGE "policycoreutils"	/* the name of this package lang translation */
  58 #endif
  59 
  60 #define BUF_SIZE 1024
  61 #define DEFAULT_PATH "/usr/bin:/bin"
  62 #define USAGE_STRING _("USAGE: seunshare [ -v ] [ -C ] [ -c ] [ -k ] [ -t tmpdir ] [ -h homedir ] [ -Z CONTEXT ] -- executable [args] ")
  63 
  64 static int verbose = 0;
  65 static int child = 0;
  66 
  67 static capng_select_t cap_set = CAPNG_SELECT_CAPS;
  68 
  69 /**
  70  * This function will drop all capabilities.
  71  */
  72 static int drop_caps()
  73 {
  74 	if (capng_have_capabilities(cap_set) == CAPNG_NONE)
  75 		return 0;
  76 	capng_clear(cap_set);
  77 	if (capng_lock() == -1 || capng_apply(cap_set) == -1) {
  78 		fprintf(stderr, _("Failed to drop all capabilities\n"));
  79 		return -1;
  80 	}
  81 	return 0;
  82 }
  83 
  84 /**
  85  * This function will drop all privileges.
  86  */
  87 static int drop_privs(uid_t uid)
  88 {
  89 	if (drop_caps() == -1 || setresuid(uid, uid, uid) == -1) {
  90 		fprintf(stderr, _("Failed to drop privileges\n"));
  91 		return -1;
  92 	}
  93 	return 0;
  94 }
  95 
  96 /**
  97  * If the user sends a siginto to seunshare, kill the child's session
  98  */
  99 void handler(int sig) {
 100 	if (child > 0) kill(-child,sig);
 101 }
 102 
 103 /**
 104  * Take care of any signal setup.
 105  */
 106 static int set_signal_handles(void)
 107 {
 108 	sigset_t empty;
 109 
 110 	/* Empty the signal mask in case someone is blocking a signal */
 111 	if (sigemptyset(&empty)) {
 112 		fprintf(stderr, "Unable to obtain empty signal set\n");
 113 		return -1;
 114 	}
 115 
 116 	(void)sigprocmask(SIG_SETMASK, &empty, NULL);
 117 
 118 	/* Terminate on SIGHUP */
 119 	if (signal(SIGHUP, SIG_DFL) == SIG_ERR) {
 120 		perror("Unable to set SIGHUP handler");
 121 		return -1;
 122 	}
 123 
 124 	if (signal(SIGINT, handler) == SIG_ERR) {
 125 		perror("Unable to set SIGINT handler");
 126 		return -1;
 127 	}
 128 
 129 	return 0;
 130 }
 131 
 132 #define status_to_retval(status,retval) do { \
 133 	if ((status) == -1) \
 134 		retval = -1; \
 135 	else if (WIFEXITED((status))) \
 136 		retval = WEXITSTATUS((status)); \
 137 	else if (WIFSIGNALED((status))) \
 138 		retval = 128 + WTERMSIG((status)); \
 139 	else \
 140 		retval = -1; \
 141 	} while(0)
 142 
 143 /**
 144  * Spawn external command using system() with dropped privileges.
 145  * TODO: avoid system() and use exec*() instead
 146  */
 147 static int spawn_command(const char *cmd, uid_t uid){
 148 	int child;
 149 	int status = -1;
 150 
 151 	if (verbose > 1)
 152 		printf("spawn_command: %s\n", cmd);
 153 
 154 	child = fork();
 155 	if (child == -1) {
 156 		perror(_("Unable to fork"));
 157 		return status;
 158 	}
 159 
 160 	if (child == 0) {
 161 		if (drop_privs(uid) != 0) exit(-1);
 162 
 163 		status = system(cmd);
 164 		status_to_retval(status, status);
 165 		exit(status);
 166 	}
 167 
 168 	waitpid(child, &status, 0);
 169 	status_to_retval(status, status);
 170 	return status;
 171 }
 172 
 173 /**
 174  * Check file/directory ownership, struct stat * must be passed to the
 175  * functions.
 176  */
 177 static int check_owner_uid(uid_t uid, const char *file, struct stat *st) {
 178 	if (S_ISLNK(st->st_mode)) {
 179 		fprintf(stderr, _("Error: %s must not be a symbolic link\n"), file);
 180 		return -1;
 181 	}
 182 	if (st->st_uid != uid) {
 183 		fprintf(stderr, _("Error: %s not owned by UID %d\n"), file, uid);
 184 		return -1;
 185 	}
 186 	return 0;
 187 }
 188 
 189 static int check_owner_gid(gid_t gid, const char *file, struct stat *st) {
 190 	if (S_ISLNK(st->st_mode)) {
 191 		fprintf(stderr, _("Error: %s must not be a symbolic link\n"), file);
 192 		return -1;
 193 	}
 194 	if (st->st_gid != gid) {
 195 		fprintf(stderr, _("Error: %s not owned by GID %d\n"), file, gid);
 196 		return -1;
 197 	}
 198 	return 0;
 199 }
 200 
 201 #define equal_stats(one,two) \
 202 	((one)->st_dev == (two)->st_dev && (one)->st_ino == (two)->st_ino && \
 203 	 (one)->st_uid == (two)->st_uid && (one)->st_gid == (two)->st_gid && \
 204 	 (one)->st_mode == (two)->st_mode)
 205 
 206 /**
 207  * Sanity check specified directory.  Store stat info for future comparison, or
 208  * compare with previously saved info to detect replaced directories.
 209  * Note: This function does not perform owner checks.
 210  */
 211 static int verify_directory(const char *dir, struct stat *st_in, struct stat *st_out) {
 212 	struct stat sb;
 213 
 214 	if (st_out == NULL) st_out = &sb;
 215 
 216 	if (lstat(dir, st_out) == -1) {
 217 		fprintf(stderr, _("Failed to stat %s: %s\n"), dir, strerror(errno));
 218 		return -1;
 219 	}
 220 	if (! S_ISDIR(st_out->st_mode)) {
 221 		fprintf(stderr, _("Error: %s is not a directory: %s\n"), dir, strerror(errno));
 222 		return -1;
 223 	}
 224 	if (st_in && !equal_stats(st_in, st_out)) {
 225 		fprintf(stderr, _("Error: %s was replaced by a different directory\n"), dir);
 226 		return -1;
 227 	}
 228 
 229 	return 0;
 230 }
 231 
 232 /**
 233  * This function checks to see if the shell is known in /etc/shells.
 234  * If so, it returns 0. On error or illegal shell, it returns -1.
 235  */
 236 static int verify_shell(const char *shell_name)
 237 {
 238 	int rc = -1;
 239 	const char *buf;
 240 
 241 	if (!(shell_name && shell_name[0]))
 242 		return rc;
 243 
 244 	while ((buf = getusershell()) != NULL) {
 245 		/* ignore comments */
 246 		if (*buf == '#')
 247 			continue;
 248 
 249 		/* check the shell skipping newline char */
 250 		if (!strcmp(shell_name, buf)) {
 251 			rc = 0;
 252 			break;
 253 		}
 254 	}
 255 	endusershell();
 256 	return rc;
 257 }
 258 
 259 /**
 260  * Mount directory and check that we mounted the right directory.
 261  */
 262 static int seunshare_mount(const char *src, const char *dst, struct stat *src_st)
 263 {
 264 	int flags = 0;
 265 	int is_tmp = 0;
 266 
 267 	if (verbose)
 268 		printf(_("Mounting %s on %s\n"), src, dst);
 269 
 270 	if (strcmp("/tmp", dst) == 0) {
 271 		flags = flags | MS_NODEV | MS_NOSUID | MS_NOEXEC;
      (emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
 272 		is_tmp = 1;
 273 	}
 274 
 275 	/* mount directory */
 276 	if (mount(src, dst, NULL, MS_BIND | flags, NULL) < 0) {
 277 		fprintf(stderr, _("Failed to mount %s on %s: %s\n"), src, dst, strerror(errno));
 278 		return -1;
 279 	}
 280 
 281 	/* verify whether we mounted what we expected to mount */
 282 	if (verify_directory(dst, src_st, NULL) < 0) return -1;
 283 
 284 	/* bind mount /tmp on /var/tmp too */
 285 	if (is_tmp) {
 286 		if (verbose)
 287 			printf(_("Mounting /tmp on /var/tmp\n"));
 288 
 289 		if (mount("/tmp", "/var/tmp",  NULL, MS_BIND | flags, NULL) < 0) {
 290 			fprintf(stderr, _("Failed to mount /tmp on /var/tmp: %s\n"), strerror(errno));
 291 			return -1;
 292 		}
 293 	}
 294 
 295 	return 0;
 296 
 297 }
 298 
 299 /**
 300  * Error logging used by cgroups code.
 301  */
 302 static int sandbox_error(const char *string)
 303 {
 304 	fprintf(stderr, "%s", string);
 305 	syslog(LOG_AUTHPRIV | LOG_ALERT, "%s", string);
 306 	exit(-1);
 307 }
 308 
 309 /**
 310  * Regular expression match.
 311  */
 312 static int match(const char *string, char *pattern)
 313 {
 314 	int status;
 315 	regex_t re;
 316 	if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0) {
 317 		return 0;
 318 	}
 319 	status = regexec(&re, string, (size_t)0, NULL, 0);
 320 	regfree(&re);
 321 	if (status != 0) {
 322 		return 0;
 323 	}
 324 	return 1;
 325 }
 326 
 327 /**
 328  * Apply cgroups settings from the /etc/sysconfig/sandbox config file.
 329  */
 330 static int setup_cgroups()
 331 {
 332 	char *cpus = NULL;	/* which CPUs to use */
 333 	char *cgroupname = NULL;/* name for the cgroup */
 334 	char *mem = NULL;	/* string for memory amount to pass to cgroup */
 335 	int64_t memusage = 0;	/* amount of memory to use max (percent) */
 336 	int cpupercentage = 0;  /* what percentage of cpu to allow usage */
 337 	FILE* fp;
 338 	char buf[BUF_SIZE];
 339 	char *tok = NULL;
 340 	int rc = -1;
 341 	char *str = NULL;
 342 	const char* fname = "/etc/sysconfig/sandbox";
 343 
 344 	if ((fp = fopen(fname, "rt")) == NULL) {
 345 		fprintf(stderr, "Error opening sandbox config file.");
 346 		return rc;
 347 	}
 348 	while(fgets(buf, BUF_SIZE, fp) != NULL) {
 349 		/* Skip comments */
 350 		if (buf[0] == '#') continue;
 351 
 352 		/* Copy the string, ignoring whitespace */
 353 		int len = strlen(buf);
 354 		free(str);
 355 		str = malloc((len + 1) * sizeof(char));
 356 		if (!str)
 357 			goto err;
 358 
 359 		int ind = 0;
 360 		int i;
 361 		for (i = 0; i < len; i++) {
 362 			char cur = buf[i];
 363 			if (cur != ' ' && cur != '\t') {
 364 				str[ind] = cur;
 365 				ind++;
 366 			}
 367 		}
 368 		str[ind] = '\0';
 369 
 370 		tok = strtok(str, "=\n");
 371 		if (tok != NULL) {
 372 			if (!strcmp(tok, "CPUAFFINITY")) {
 373 				tok = strtok(NULL, "=\n");
 374 				cpus = strdup(tok);
 375 				if (!strcmp(cpus, "ALL")) {
 376 					free(cpus);
 377 					cpus = NULL;
 378 				}
 379 			} else if (!strcmp(tok, "MEMUSAGE")) {
 380 				tok = strtok(NULL, "=\n");
 381 				if (match(tok, "^[0-9]+[kKmMgG%]")) {
 382 					char *ind = strchr(tok, '%');
 383 					if (ind != NULL) {
 384 						*ind = '\0';;
 385 						memusage = atoi(tok);
 386 					} else {
 387 						mem = strdup(tok);
 388 					}
 389 				} else {
 390 					fprintf(stderr, "Error parsing config file.");
 391 					goto err;
 392 				}
 393 
 394 			} else if (!strcmp(tok, "CPUUSAGE")) {
 395 				tok = strtok(NULL, "=\n");
 396 				if (match(tok, "^[0-9]+\%")) {
 397 					char* ind = strchr(tok, '%');
 398 					*ind = '\0';
 399 					cpupercentage = atoi(tok);
 400 				} else {
 401 					fprintf(stderr, "Error parsing config file.");
 402 					goto err;
 403 				}
 404 			} else if (!strcmp(tok, "NAME")) {
 405 				tok = strtok(NULL, "=\n");
 406 				cgroupname = strdup(tok);
 407 			} else {
 408 				continue;
 409 			}
 410 		}
 411 
 412 	}
 413 	if (mem == NULL) {
 414 		long phypz = sysconf(_SC_PHYS_PAGES);
 415 		long psize = sysconf(_SC_PAGE_SIZE);
 416 		memusage = phypz * psize * (float) memusage / 100.0;
 417 	}
 418 
 419 	cgroup_init();
 420 
 421 	int64_t current_runtime = 0;
 422 	int64_t current_period = 0 ;
 423 	int64_t current_mem = 0;
 424 	char *curr_cpu_path = NULL;
 425 	char *curr_mem_path = NULL;
 426 	int ret  = cgroup_get_current_controller_path(getpid(), "cpu", &curr_cpu_path);
 427 	if (ret) {
 428 		sandbox_error("Error while trying to get current controller path.\n");
 429 	} else {
 430 		struct cgroup *curr = cgroup_new_cgroup(curr_cpu_path);
 431 		cgroup_get_cgroup(curr);
 432 		cgroup_get_value_int64(cgroup_get_controller(curr, "cpu"), "cpu.rt_runtime_us", ¤t_runtime);
 433 		cgroup_get_value_int64(cgroup_get_controller(curr, "cpu"), "cpu.rt_period_us", ¤t_period);
 434 	}
 435 
 436 	ret  = cgroup_get_current_controller_path(getpid(), "memory", &curr_mem_path);
 437 	if (ret) {
 438 		sandbox_error("Error while trying to get current controller path.\n");
 439 	} else {
 440 		struct cgroup *curr = cgroup_new_cgroup(curr_mem_path);
 441 		cgroup_get_cgroup(curr);
 442 		cgroup_get_value_int64(cgroup_get_controller(curr, "memory"), "memory.limit_in_bytes", ¤t_mem);
 443 	}
 444 
 445 	if (((float) cpupercentage)  / 100.0> (float)current_runtime / (float) current_period) {
 446 		sandbox_error("CPU usage restricted!\n");
 447 		goto err;
 448 	}
 449 
 450 	if (mem == NULL) {
 451 		if (memusage > current_mem) {
 452 			sandbox_error("Attempting to use more memory than allowed!");
 453 			goto err;
 454 		}
 455 	}
 456 
 457 	long nprocs = sysconf(_SC_NPROCESSORS_ONLN);
 458 
 459 	struct sched_param sp;
 460 	sp.sched_priority = sched_get_priority_min(SCHED_FIFO);
 461 	sched_setscheduler(getpid(), SCHED_FIFO, &sp);
 462 	struct cgroup *sandbox_group = cgroup_new_cgroup(cgroupname);
 463 	cgroup_add_controller(sandbox_group, "memory");
 464 	cgroup_add_controller(sandbox_group, "cpu");
 465 
 466 	if (mem == NULL) {
 467 		if (memusage > 0) {
 468 			cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", memusage);
 469 		}
 470 	} else {
 471 		cgroup_set_value_string(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", mem);
 472 	}
 473 	if (cpupercentage > 0) {
 474 		cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "cpu"), "cpu.rt_runtime_us",
 475 					(float) cpupercentage / 100.0 * 60000);
 476 		cgroup_set_value_uint64(cgroup_get_controller(sandbox_group, "cpu"), "cpu.rt_period_us",60000 * nprocs);
 477 	}
 478 	if (cpus != NULL) {
 479 		cgroup_set_value_string(cgroup_get_controller(sandbox_group, "cpu"), "cgroup.procs",cpus);
 480 	}
 481 
 482 	uint64_t allocated_mem;
 483 	if (cgroup_get_value_uint64(cgroup_get_controller(sandbox_group, "memory"), "memory.limit_in_bytes", &allocated_mem) > current_mem) {
 484 		sandbox_error("Attempting to use more memory than allowed!\n");
 485 		goto err;
 486 	}
 487 
 488 	rc = cgroup_create_cgroup(sandbox_group, 1);
 489 	if (rc != 0) {
 490 		sandbox_error("Failed to create group.  Ensure that cgconfig service is running. \n");
 491 		goto err;
 492 	}
 493 
 494 	cgroup_attach_task(sandbox_group);
 495 
 496 	rc = 0;
 497 err:
 498 	fclose(fp);
 499 	free(str);
 500 	free(mem);
 501 	free(cgroupname);
 502 	free(cpus);
 503 	return rc;
 504 }
 505 
 506 /*
 507    If path is empy or ends with  "/." or "/.. return -1 else return 0;
 508  */
 509 static int bad_path(const char *path) {
 510 	const char *ptr;
 511 	ptr = path;
 512 	while (*ptr) ptr++;
 513 	if (ptr == path) return -1; // ptr null
 514 	ptr--;
 515 	if (ptr != path && *ptr  == '.') {
 516 		ptr--;
 517 		if (*ptr  == '/') return -1; // path ends in /.
 518 		if (*ptr  == '.') {
 519 			if (ptr != path) {
 520 				ptr--;
 521 				if (*ptr  == '/') return -1; // path ends in /..
 522 			}
 523 		}
 524 	}
 525 	return 0;
 526 }
 527 
 528 static int rsynccmd(const char * src, const char *dst, char **cmdbuf)
 529 {
 530 	char *buf = NULL;
 531 	char *newbuf = NULL;
 532 	glob_t fglob;
 533 	fglob.gl_offs = 0;
 534 	int flags = GLOB_PERIOD;
 535 	unsigned int i = 0;
 536 	int rc = -1;
 537 
 538 	/* match glob for all files in src dir */
 539 	if (asprintf(&buf, "%s/*", src) == -1) {
 540 		fprintf(stderr, "Out of memory\n");
 541 		return -1;
 542 	}
 543 
 544 	if (glob(buf, flags, NULL, &fglob) != 0) {
 545 		free(buf); buf = NULL;
 546 		return -1;
 547 	}
 548 
 549 	free(buf); buf = NULL;
 550 
 551 	for ( i=0; i < fglob.gl_pathc; i++) {
 552 		const char *path = fglob.gl_pathv[i];
 553 
 554 		if (bad_path(path)) continue;
 555 
 556 		if (!buf) {
 557 			if (asprintf(&newbuf, "\'%s\'", path) == -1) {
 558 				fprintf(stderr, "Out of memory\n");
 559 				goto err;
 560 			}
 561 		} else {
 562 			if (asprintf(&newbuf, "%s  \'%s\'", buf, path) == -1) {
 563 				fprintf(stderr, "Out of memory\n");
 564 				goto err;
 565 			}
 566 		}
 567 
 568 		free(buf); buf = newbuf;
 569 		newbuf = NULL;
 570 	}
 571 
 572 	if (buf) {
 573 		if (asprintf(&newbuf, "/usr/bin/rsync -trlHDq %s '%s'", buf, dst) == -1) {
 574 			fprintf(stderr, "Out of memory\n");
 575 			goto err;
 576 		}
 577 		*cmdbuf=newbuf;
 578 	}
 579 	else {
 580 		*cmdbuf=NULL;
 581 	}
 582 	rc = 0;
 583 
 584 err:
 585 	free(buf); buf = NULL;
 586 	globfree(&fglob);
 587 	return rc;
 588 }
 589 
 590 /**
 591  * Clean up runtime temporary directory.  Returns 0 if no problem was detected,
 592  * >0 if some error was detected, but errors here are treated as non-fatal and
 593  * left to tmpwatch to finish incomplete cleanup.
 594  */
 595 static int cleanup_tmpdir(const char *tmpdir, const char *src,
 596 	struct passwd *pwd, int copy_content)
 597 {
 598 	char *cmdbuf = NULL;
 599 	int rc = 0;
 600 
 601 	/* rsync files back */
 602 	if (copy_content) {
 603 		if (asprintf(&cmdbuf, "/usr/bin/rsync --exclude=.X11-unix -utrlHDq --delete '%s/' '%s/'", tmpdir, src) == -1) {
 604 			fprintf(stderr, _("Out of memory\n"));
 605 			cmdbuf = NULL;
 606 			rc++;
 607 		}
 608 		if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) {
 609 			fprintf(stderr, _("Failed to copy files from the runtime temporary directory\n"));
 610 			rc++;
 611 		}
 612 		free(cmdbuf); cmdbuf = NULL;
 613 	}
 614 
 615 	/* remove files from the runtime temporary directory */
 616 	if (asprintf(&cmdbuf, "/bin/rm -r '%s/' 2>/dev/null", tmpdir) == -1) {
 617 		fprintf(stderr, _("Out of memory\n"));
 618 		cmdbuf = NULL;
 619 		rc++;
 620 	}
 621 	/* this may fail if there's root-owned file left in the runtime tmpdir */
 622 	if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) rc++;
 623 	free(cmdbuf); cmdbuf = NULL;
 624 
 625 	/* remove runtime temporary directory */
 626 	if (setfsuid(0) < 0) 
 627 		rc++;
 628 
 629 	if (rmdir(tmpdir) == -1)
 630 		fprintf(stderr, _("Failed to remove directory %s: %s\n"), tmpdir, strerror(errno));
 631 	if (setfsuid(pwd->pw_uid) < 0) 
 632 		rc++;
 633 
 634 	return rc;
 635 }
 636 
 637 /**
 638  * seunshare will create a tmpdir in /tmp, with root ownership.  The parent
 639  * process waits for it child to exit to attempt to remove the directory.  If
 640  * it fails to remove the directory, we will need to rely on tmpreaper/tmpwatch
 641  * to clean it up.
 642  */
 643 static char *create_tmpdir(const char *src, struct stat *src_st,
 644 	struct stat *out_st, struct passwd *pwd, security_context_t execcon)
 645 {
 646 	char *tmpdir = NULL;
 647 	char *cmdbuf = NULL;
 648 	int fd_t = -1, fd_s = -1;
 649 	struct stat tmp_st;
 650 	security_context_t con = NULL;
 651 
 652 	/* get selinux context */
 653 	if (execcon) {
 654 		if (setfsuid(pwd->pw_uid) < 0) 
 655 			goto err;
 656 
 657 		if ((fd_s = open(src, O_RDONLY)) < 0) {
 658 			fprintf(stderr, _("Failed to open directory %s: %s\n"), src, strerror(errno));
 659 			goto err;
 660 		}
 661 		if (fstat(fd_s, &tmp_st) == -1) {
 662 			fprintf(stderr, _("Failed to stat directory %s: %s\n"), src, strerror(errno));
 663 			goto err;
 664 		}
 665 		if (!equal_stats(src_st, &tmp_st)) {
 666 			fprintf(stderr, _("Error: %s was replaced by a different directory\n"), src);
 667 			goto err;
 668 		}
 669 		if (fgetfilecon(fd_s, &con) == -1) {
 670 			fprintf(stderr, _("Failed to get context of the directory %s: %s\n"), src, strerror(errno));
 671 			goto err;
 672 		}
 673 
 674 		/* ok to not reach this if there is an error */
 675 		if (setfsuid(0) < 0) 
 676 			goto err;
 677 	}
 678 
 679 	if (asprintf(&tmpdir, "/tmp/.sandbox-%s-XXXXXX", pwd->pw_name) == -1) {
 680 		fprintf(stderr, _("Out of memory\n"));
 681 		tmpdir = NULL;
 682 		goto err;
 683 	}
 684 	if (mkdtemp(tmpdir) == NULL) {
 685 		fprintf(stderr, _("Failed to create temporary directory: %s\n"), strerror(errno));
 686 		goto err;
 687 	}
 688 
 689 	/* temporary directory must be owned by root:user */
 690 	if (verify_directory(tmpdir, NULL, out_st) < 0) {
 691 		goto err;
 692 	}
 693 
 694 	if (check_owner_uid(0, tmpdir, out_st) < 0)
 695 		goto err;
 696 
 697 	if (check_owner_gid(getgid(), tmpdir, out_st) < 0)
 698 		goto err;
 699 
 700 	/* change permissions of the temporary directory */
 701 	if ((fd_t = open(tmpdir, O_RDONLY)) < 0) {
 702 		fprintf(stderr, _("Failed to open directory %s: %s\n"), tmpdir, strerror(errno));
 703 		goto err;
 704 	}
 705 	if (fstat(fd_t, &tmp_st) == -1) {
 706 		fprintf(stderr, _("Failed to stat directory %s: %s\n"), tmpdir, strerror(errno));
 707 		goto err;
 708 	}
 709 	if (!equal_stats(out_st, &tmp_st)) {
 710 		fprintf(stderr, _("Error: %s was replaced by a different directory\n"), tmpdir);
 711 		goto err;
 712 	}
 713 	if (fchmod(fd_t, 01770) == -1) {
 714 		fprintf(stderr, _("Unable to change mode on %s: %s\n"), tmpdir, strerror(errno));
 715 		goto err;
 716 	}
 717 	/* re-stat again to pick change mode */
 718 	if (fstat(fd_t, out_st) == -1) {
 719 		fprintf(stderr, _("Failed to stat directory %s: %s\n"), tmpdir, strerror(errno));
 720 		goto err;
 721 	}
 722 
 723 	/* copy selinux context */
 724 	if (execcon) {
 725 		if (fsetfilecon(fd_t, con) == -1) {
 726 			fprintf(stderr, _("Failed to set context of the directory %s: %s\n"), tmpdir, strerror(errno));
 727 			goto err;
 728 		}
 729 	}
 730 
 731 	if (setfsuid(pwd->pw_uid) < 0) 
 732 		goto err;
 733 
 734 	if (rsynccmd(src, tmpdir, &cmdbuf) < 0) {
 735 		goto err;
 736 	}
 737 
 738 	/* ok to not reach this if there is an error */
 739 	if (setfsuid(0) < 0) 
 740 		goto err;
 741 
 742 	if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) {
 743 		fprintf(stderr, _("Failed to populate runtime temporary directory\n"));
 744 		cleanup_tmpdir(tmpdir, src, pwd, 0);
 745 		goto err;
 746 	}
 747 
 748 	goto good;
 749 err:
 750 	free(tmpdir); tmpdir = NULL;
 751 good:
 752 	free(cmdbuf); cmdbuf = NULL;
 753 	freecon(con); con = NULL;
 754 	if (fd_t >= 0) close(fd_t);
 755 	if (fd_s >= 0) close(fd_s);
 756 	return tmpdir;
 757 }
 758 
 759 #define PROC_BASE "/proc"
 760 
 761 static int
 762 killall (security_context_t execcon)
 763 {
 764 	DIR *dir;
 765 	security_context_t scon;
 766 	struct dirent *de;
 767 	pid_t *pid_table, pid, self;
 768 	int i;
 769 	int pids, max_pids;
 770 	int running = 0;
 771 	self = getpid();
 772 	if (!(dir = opendir(PROC_BASE))) {
 773 		return -1;
 774 	}
 775 	max_pids = 256;
 776 	pid_table = malloc(max_pids * sizeof (pid_t));
 777 	if (!pid_table) {
 778 		(void)closedir(dir);
 779 		return -1;
 780 	}
 781 	pids = 0;
 782 	context_t con;
 783 	con = context_new(execcon);
 784 	const char *mcs = context_range_get(con);
 785 	printf("mcs=%s\n", mcs);
 786 	while ((de = readdir (dir)) != NULL) {
 787 		if (!(pid = (pid_t)atoi(de->d_name)) || pid == self)
 788 			continue;
 789 
 790 		if (pids == max_pids) {
 791 			if (!(pid_table = realloc(pid_table, 2*pids*sizeof(pid_t)))) {
      (emitted by cppcheck) 792 				(void)closedir(dir);
 793 				return -1;
 794 			}
 795 			max_pids *= 2;
 796 		}
 797 		pid_table[pids++] = pid;
 798 	}
 799 
 800 	(void)closedir(dir);
 801 
 802 	for (i = 0; i < pids; i++) {
 803 		pid_t id = pid_table[i];
 804 
 805 		if (getpidcon(id, &scon) == 0) {
 806 
 807 			context_t pidcon = context_new(scon);
 808 			/* Attempt to kill remaining processes */
 809 			if (strcmp(context_range_get(pidcon), mcs) == 0)
 810 				kill(id, SIGKILL);
 811 
 812 			context_free(pidcon);
 813 			freecon(scon);
 814 		}
 815 		running++;
 816 	}
 817 
 818 	context_free(con);
 819 	free(pid_table);
 820 	return running;
 821 }
 822 
 823 int main(int argc, char **argv) {
 824 	int status = -1;
 825 	security_context_t execcon = NULL;
 826 
 827 	int clflag;		/* holds codes for command line flags */
 828 	int usecgroups = 0;
 829 	int kill_all = 0;
 830 
 831 	char *homedir_s = NULL;	/* homedir spec'd by user in argv[] */
 832 	char *tmpdir_s = NULL;	/* tmpdir spec'd by user in argv[] */
 833 	char *tmpdir_r = NULL;	/* tmpdir created by seunshare */
 834 
 835 	struct stat st_homedir;
 836 	struct stat st_tmpdir_s;
 837 	struct stat st_tmpdir_r;
 838 
 839 	const struct option long_options[] = {
 840 		{"homedir", 1, 0, 'h'},
 841 		{"tmpdir", 1, 0, 't'},
 842 		{"kill", 1, 0, 'k'},
 843 		{"verbose", 1, 0, 'v'},
 844 		{"cgroups", 1, 0, 'c'},
 845 		{"context", 1, 0, 'Z'},
 846 		{"capabilities", 1, 0, 'C'},
 847 		{NULL, 0, 0, 0}
 848 	};
 849 
 850 	uid_t uid = getuid();
 851 /*
 852 	if (!uid) {
 853 		fprintf(stderr, _("Must not be root"));
 854 		return -1;
 855 	}
 856 */
 857 
 858 #ifdef USE_NLS
 859 	setlocale(LC_ALL, "");
 860 	bindtextdomain(PACKAGE, LOCALEDIR);
 861 	textdomain(PACKAGE);
 862 #endif
 863 
 864 	struct passwd *pwd=getpwuid(uid);
 865 	if (!pwd) {
 866 		perror(_("getpwduid failed"));
 867 		return -1;
 868 	}
 869 
 870 	if (verify_shell(pwd->pw_shell) < 0) {
 871 		fprintf(stderr, _("Error: User shell is not valid\n"));
 872 		return -1;
 873 	}
 874 
 875 	while (1) {
 876 		clflag = getopt_long(argc, argv, "Ccvh:t:Z:", long_options, NULL);
 877 		if (clflag == -1)
 878 			break;
 879 
 880 		switch (clflag) {
 881 		case 't':
 882 			tmpdir_s = optarg;
 883 			break;
 884 		case 'k':
 885 			kill_all = 1;
 886 			break;
 887 		case 'h':
 888 			homedir_s = optarg;
 889 			break;
 890 		case 'v':
 891 			verbose++;
 892 			break;
 893 		case 'c':
 894 			usecgroups = 1;
 895 			break;
 896 		case 'C':
 897 			cap_set = CAPNG_SELECT_CAPS;
 898 			break;
 899 		case 'Z':
 900 			execcon = optarg;
 901 			break;
 902 		default:
 903 			fprintf(stderr, "%s\n", USAGE_STRING);
 904 			return -1;
 905 		}
 906 	}
 907 
 908 	if (! homedir_s && ! tmpdir_s) {
 909 		fprintf(stderr, _("Error: tmpdir and/or homedir required\n %s\n"), USAGE_STRING);
 910 		return -1;
 911 	}
 912 
 913 	if (argc - optind < 1) {
 914 		fprintf(stderr, _("Error: executable required\n %s\n"), USAGE_STRING);
 915 		return -1;
 916 	}
 917 
 918 	if (execcon && is_selinux_enabled() != 1) {
 919 		fprintf(stderr, _("Error: execution context specified, but SELinux is not enabled\n"));
 920 		return -1;
 921 	}
 922 
 923 	if (set_signal_handles())
 924 		return -1;
 925 
 926 	if (usecgroups && setup_cgroups() < 0)
 927 		return  -1;
 928 
 929 	/* set fsuid to ruid */
 930 	/* Changing fsuid is usually required when user-specified directory is
 931 	 * on an NFS mount.  It's also desired to avoid leaking info about
 932 	 * existence of the files not accessible to the user. */
 933 	if (setfsuid(uid) < 0) 
 934 		return -1;
 935 
 936 	/* verify homedir and tmpdir */
 937 	if (homedir_s && (
 938 		verify_directory(homedir_s, NULL, &st_homedir) < 0 ||
 939 		check_owner_uid(uid, homedir_s, &st_homedir))) return -1;
 940 	if (tmpdir_s && (
 941 		verify_directory(tmpdir_s, NULL, &st_tmpdir_s) < 0 ||
 942 		check_owner_uid(uid, tmpdir_s, &st_tmpdir_s))) return -1;
 943 	if (setfsuid(0) < 0) return -1;
 944 
 945 	/* create runtime tmpdir */
 946 	if (tmpdir_s && (tmpdir_r = create_tmpdir(tmpdir_s, &st_tmpdir_s,
 947 						  &st_tmpdir_r, pwd, execcon)) == NULL) {
 948 		fprintf(stderr, _("Failed to create runtime temporary directory\n"));
 949 		return -1;
 950 	}
 951 
 952 	/* spawn child process */
 953 	child = fork();
 954 	if (child == -1) {
 955 		perror(_("Unable to fork"));
 956 		goto err;
 957 	}
 958 
 959 	if (child == 0) {
 960 		char *display = NULL;
 961 		char *LANG = NULL;
 962 		int rc = -1;
 963 
 964 		if (unshare(CLONE_NEWNS) < 0) {
 965 			perror(_("Failed to unshare"));
 966 			goto childerr;
 967 		}
 968 
 969 		/* Remount / as SLAVE so that nothing mounted in the namespace 
 970 		   shows up in the parent */
 971 		if (mount("none", "/", NULL, MS_SLAVE | MS_REC , NULL) < 0) {
 972 			perror(_("Failed to make / a SLAVE mountpoint\n"));
 973 			goto childerr;
 974 		}
 975 
 976 		/* assume fsuid==ruid after this point */
 977 		if (setfsuid(uid) < 0) goto childerr;
 978 
 979 		/* mount homedir and tmpdir, in this order */
 980 		if (homedir_s && seunshare_mount(homedir_s, pwd->pw_dir,
 981 			&st_homedir) != 0) goto childerr;
 982 		if (tmpdir_s &&	seunshare_mount(tmpdir_r, "/tmp",
 983 			&st_tmpdir_r) != 0) goto childerr;
 984 
 985 		if (drop_privs(uid) != 0) goto childerr;
 986 
 987 		/* construct a new environment */
 988 		if ((display = getenv("DISPLAY")) != NULL) {
 989 			if ((display = strdup(display)) == NULL) {
 990 				perror(_("Out of memory"));
 991 				goto childerr;
 992 			}
 993 		}
 994 		
 995 		/* construct a new environment */
 996 		if ((LANG = getenv("LANG")) != NULL) {
 997 			if ((LANG = strdup(LANG)) == NULL) {
 998 				perror(_("Out of memory"));
 999 				goto childerr;
1000 			}
1001 		}
1002 		
1003 		if ((rc = clearenv()) != 0) {
1004 			perror(_("Failed to clear environment"));
1005 			goto childerr;
1006 		}
1007 		if (display)
1008 			rc |= setenv("DISPLAY", display, 1);
1009 		if (LANG) 
1010 			rc |= setenv("LANG", LANG, 1);
1011 		rc |= setenv("HOME", pwd->pw_dir, 1);
1012 		rc |= setenv("SHELL", pwd->pw_shell, 1);
1013 		rc |= setenv("USER", pwd->pw_name, 1);
1014 		rc |= setenv("LOGNAME", pwd->pw_name, 1);
1015 		rc |= setenv("PATH", DEFAULT_PATH, 1);
1016 		if (rc != 0) {
1017 			fprintf(stderr, _("Failed to construct environment\n"));
1018 			goto childerr;
1019 		}
1020 
1021 		/* selinux context */
1022 		if (execcon && setexeccon(execcon) != 0) {
1023 			fprintf(stderr, _("Could not set exec context to %s. %s\n"), execcon, strerror(errno));
1024 			goto childerr;
1025 		}
1026 
1027 		if (chdir(pwd->pw_dir)) {
1028 			perror(_("Failed to change dir to homedir"));
1029 			goto childerr;
1030 		}
1031 		setsid();
1032 		execv(argv[optind], argv + optind);
1033 		fprintf(stderr, _("Failed to execute command %s: %s\n"), argv[optind], strerror(errno));
1034 childerr:
1035 		free(display);
1036 		free(LANG);
1037 		exit(-1);
1038 	}
1039 
1040 	drop_caps();
1041 
1042 	/* parent waits for child exit to do the cleanup */
1043 	waitpid(child, &status, 0);
1044 	status_to_retval(status, status);
1045 
1046 	/* Make sure all child processes exit */
1047 	kill(-child,SIGTERM);
1048 
1049 	if (execcon && kill_all)
1050 		killall(execcon);
1051 
1052 	if (tmpdir_r) cleanup_tmpdir(tmpdir_r, tmpdir_s, pwd, 1);
1053 
1054 err:
1055 	free(tmpdir_r);
1056 	return status;
1057 }
No issues found
  1 #include <stdlib.h>
  2 #include <stdio.h>
  3 #include <assert.h>
  4 
  5 #include <string.h>
  6 
  7 #define xstreq(x, y) !strcmp(x, y)
  8 
  9 #include <err.h>
 10 
 11 #include <getopt.h>
 12 #include <sys/types.h>
 13 #include <unistd.h>
 14 #include <selinux/selinux.h>
 15 #include <selinux/context.h>
 16 
 17 #define TRUE  1
 18 #define FALSE 0
 19 
 20 #define SECON_CONF_PROG_NAME "secon"	/* default program name */
 21 #define SECON_OPTS_SM "hVurtscmPRfLp"	/* small options available, print */
 22 #define SECON_OPTS_GO "hVurtlscmPRf:L:p:"	/* small options available, getopt */
 23 
 24 #define OPTS_FROM_ARG      0
 25 #define OPTS_FROM_FILE     1
 26 #define OPTS_FROM_LINK     2
 27 #define OPTS_FROM_STDIN    3
 28 #define OPTS_FROM_CUR      4
 29 #define OPTS_FROM_CUREXE   5
 30 #define OPTS_FROM_CURFS    6
 31 #define OPTS_FROM_CURKEY   7
 32 #define OPTS_FROM_PROC     8
 33 #define OPTS_FROM_PROCEXE  9
 34 #define OPTS_FROM_PROCFS   10
 35 #define OPTS_FROM_PROCKEY  11
 36 
 37 struct {
 38 	unsigned int disp_user:1;
 39 	unsigned int disp_role:1;
 40 	unsigned int disp_type:1;
 41 	unsigned int disp_sen:1;
 42 	unsigned int disp_clr:1;
 43 	unsigned int disp_mlsr:1;
 44 
 45 	unsigned int disp_raw:1;
 46 
 47 	unsigned int disp_prompt:1;	/* no return, use : to sep */
 48 
 49 	unsigned int from_type:8;	/* 16 bits, uses 4 bits */
 50 
 51 	union {
 52 		pid_t pid;
 53 		const char *file;
 54 		const char *link;
 55 		const char *arg;
 56 	} f;
 57 } opts[1] = { {
 58 		FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
 59 		    FALSE, FALSE, OPTS_FROM_ARG, {
 60 0}}};
 61 
 62 static void usage(const char *name, int exit_code)
 63 {
 64 	fprintf(exit_code ? stderr : stdout,
 65 		"  Usage: %s [-%s] [ context | - ]\n"
 66 		"          --help        -h     Show this message.\n"
 67 		"          --version     -V     Show the version.\n"
 68 		"          --prompt      -P     Output in a format good for a prompt.\n"
 69 		"          --user        -u     Show the user of the context.\n"
 70 		"          --role        -r     Show the role of the context.\n"
 71 		"          --type        -t     Show the type of the context.\n"
 72 		"          --sensitivity -s     Show the sensitivity level of the context.\n"
 73 		"          --clearance   -c     Show the clearance level of the context.\n"
 74 		"          --mls-range   -m     Show the sensitivity to clearance range of \n"
 75 		"                               the context.\n"
 76 		"          --raw         -R     Show the context in \"raw\" format.\n"
 77 		"          --current            Get the context for the current process.\n"
 78 		"          --self               Get the context for the current process.\n"
 79 		"          --self-exec          Get the exec context for the current process.\n"
 80 		"          --self-fs            Get the fs context for the current process.\n"
 81 		"          --self-key           Get the key context for the current process.\n"
 82 		"          --parent             Get the context for the parent process.\n"
 83 		"          --parent-exec        Get the exec context for the parent process.\n"
 84 		"          --parent-fs          Get the fs context for the parent process.\n"
 85 		"          --parent-key         Get the key context for the parent process.\n"
 86 		"          --pid       -p <arg> Use the context from the specified pid.\n"
 87 		"          --pid-exec     <arg> Use the exec context from the specified pid.\n"
 88 		"          --pid-fs       <arg> Use the fs context from the specified pid.\n"
 89 		"          --pid-key      <arg> Use the key context from the specified pid.\n"
 90 		"          --file      -f <arg> Use the context from the specified file.\n"
 91 		"          --link      -L <arg> Use the context from the specified link.\n",
 92 		name, SECON_OPTS_SM);
 93 
 94 	exit(exit_code);
 95 }
 96 
 97 static const char *opt_program_name(const char *argv0, const char *def)
 98 {
 99 	if (argv0) {
100 		if ((def = strrchr(argv0, '/')))
101 			++def;
102 		else
103 			def = argv0;
104 
105 		/* hack for libtool */
106 		if ((strlen(def) > strlen("lt-"))
107 		    && !memcmp("lt-", def, strlen("lt-")))
108 			def += 3;
109 	}
110 
111 	return (def);
112 }
113 
114 static int disp_num(void)
115 {
116 	int num = 0;
117 
118 	num += opts->disp_user;
119 	num += opts->disp_role;
120 	num += opts->disp_type;
121 	num += opts->disp_sen;
122 	num += opts->disp_clr;
123 	num += opts->disp_mlsr;
124 
125 	return (num);
126 }
127 
128 static int disp_none(void)
129 {
130 	return (!disp_num());
131 }
132 
133 static int disp_multi(void)
134 {
135 	return (disp_num() > 1);
136 }
137 
138 static void cmd_line(int argc, char *argv[])
139 {
140 	int optchar = 0;
141 	const char *program_name = NULL;
142 	struct option long_options[] = {
143 		{"help", no_argument, NULL, 'h'},
144 		{"version", no_argument, NULL, 'V'},
145 
146 		{"prompt", no_argument, NULL, 'P'},
147 
148 		{"user", no_argument, NULL, 'u'},
149 		{"role", no_argument, NULL, 'r'},
150 		{"type", no_argument, NULL, 't'},
151 		{"level", no_argument, NULL, 'l'},	/* compat. */
152 		{"sensitivity", no_argument, NULL, 's'},
153 		{"range", no_argument, NULL, 'm'},
154 		{"clearance", no_argument, NULL, 'c'},
155 		{"mls-range", no_argument, NULL, 'm'},
156 
157 		{"raw", no_argument, NULL, 'R'},
158 
159 		{"current", no_argument, NULL, 1},
160 		{"self", no_argument, NULL, 1},
161 		{"current-exec", no_argument, NULL, 2},
162 		{"self-exec", no_argument, NULL, 2},
163 		{"current-fs", no_argument, NULL, 3},
164 		{"self-fs", no_argument, NULL, 3},
165 		{"current-key", no_argument, NULL, 4},
166 		{"self-key", no_argument, NULL, 4},
167 
168 		{"parent", no_argument, NULL, 5},
169 		{"parent-exec", no_argument, NULL, 6},
170 		{"parent-fs", no_argument, NULL, 7},
171 		{"parent-key", no_argument, NULL, 8},
172 
173 		{"file", required_argument, NULL, 'f'},
174 		{"link", required_argument, NULL, 'L'},
175 		{"pid", required_argument, NULL, 'p'},
176 		{"pid-exec", required_argument, NULL, 9},
177 		{"pid-fs", required_argument, NULL, 10},
178 		{"pid-key", required_argument, NULL, 11},
179 
180 		{NULL, 0, NULL, 0}
181 	};
182 	int done = FALSE;
183 
184 	program_name = opt_program_name(argv[0], SECON_CONF_PROG_NAME);
185 
186 	while ((optchar = getopt_long(argc, argv, SECON_OPTS_GO,
187 				      long_options, NULL)) != -1) {
188 		switch (optchar) {
189 		case '?':
190 			usage(program_name, EXIT_FAILURE);
191 		case 'h':
192 			usage(program_name, EXIT_SUCCESS);
193 		case 'V':
194 			fprintf(stdout,
195 				" %s version %s.\n", program_name, VERSION);
196 			exit(EXIT_SUCCESS);
197 
198 		case 'u':
199 			done = TRUE;
200 			opts->disp_user = !opts->disp_user;
201 			break;
202 		case 'r':
203 			done = TRUE;
204 			opts->disp_role = !opts->disp_role;
205 			break;
206 		case 't':
207 			done = TRUE;
208 			opts->disp_type = !opts->disp_type;
209 			break;
210 		case 'l':
211 			done = TRUE;
212 			opts->disp_sen = !opts->disp_sen;
213 			break;
214 		case 's':
215 			done = TRUE;
216 			opts->disp_sen = !opts->disp_sen;
217 			break;
218 		case 'c':
219 			done = TRUE;
220 			opts->disp_clr = !opts->disp_clr;
221 			break;
222 		case 'm':
223 			done = TRUE;
224 			opts->disp_mlsr = !opts->disp_mlsr;
225 			break;
226 
227 		case 'P':
228 			opts->disp_prompt = !opts->disp_prompt;
229 			break;
230 
231 		case 'R':
232 			opts->disp_raw = !opts->disp_raw;
233 			break;
234 		case 1:
235 			opts->from_type = OPTS_FROM_CUR;
236 			break;
237 		case 2:
238 			opts->from_type = OPTS_FROM_CUREXE;
239 			break;
240 		case 3:
241 			opts->from_type = OPTS_FROM_CURFS;
242 			break;
243 		case 4:
244 			opts->from_type = OPTS_FROM_CURKEY;
245 			break;
246 
247 		case 5:
248 			opts->from_type = OPTS_FROM_PROC;
249 			opts->f.pid = getppid();
250 			break;
251 		case 6:
252 			opts->from_type = OPTS_FROM_PROCEXE;
253 			opts->f.pid = getppid();
254 			break;
255 		case 7:
256 			opts->from_type = OPTS_FROM_PROCFS;
257 			opts->f.pid = getppid();
258 			break;
259 		case 8:
260 			opts->from_type = OPTS_FROM_PROCKEY;
261 			opts->f.pid = getppid();
262 			break;
263 
264 		case 'f':
265 			opts->from_type = OPTS_FROM_FILE;
266 			opts->f.file = optarg;
267 			break;
268 		case 'L':
269 			opts->from_type = OPTS_FROM_LINK;
270 			opts->f.link = optarg;
271 			break;
272 		case 'p':
273 			opts->from_type = OPTS_FROM_PROC;
274 			opts->f.pid = atoi(optarg);
275 			break;
276 		case 9:
277 			opts->from_type = OPTS_FROM_PROCEXE;
278 			opts->f.pid = atoi(optarg);
279 			break;
280 		case 10:
281 			opts->from_type = OPTS_FROM_PROCFS;
282 			opts->f.pid = atoi(optarg);
283 			break;
284 		case 11:
285 			opts->from_type = OPTS_FROM_PROCKEY;
286 			opts->f.pid = atoi(optarg);
287 			break;
288 
289 		default:
290 			assert(FALSE);
291 		}
292 	}
293 
294 	if (!done) {		/* defualt, if nothing specified */
295 		opts->disp_user = TRUE;
296 		opts->disp_role = TRUE;
297 		opts->disp_type = TRUE;
298 		if (!opts->disp_prompt) {	/* when displaying prompt, just output "normal" by default */
299 			opts->disp_sen = TRUE;
300 			opts->disp_clr = TRUE;
301 		}
302 		opts->disp_mlsr = TRUE;
303 	}
304 
305 	if (disp_none())
306 		err(EXIT_FAILURE, " Nothing to display");
307 
308 	argc -= optind;
309 	argv += optind;
310 
311 	if (!argc && (opts->from_type == OPTS_FROM_ARG)
312 	    && !isatty(STDIN_FILENO))
313 		opts->from_type = OPTS_FROM_STDIN;
314 	if (!argc && (opts->from_type == OPTS_FROM_ARG))
315 		opts->from_type = OPTS_FROM_CUR;
316 
317 	if (opts->from_type == OPTS_FROM_ARG) {
318 		opts->f.arg = argv[0];
319 
320 		if (xstreq(argv[0], "-"))
321 			opts->from_type = OPTS_FROM_STDIN;
322 	} else if (!is_selinux_enabled())
323 		errx(EXIT_FAILURE, "SELinux is not enabled");
324 }
325 
326 static int my_getXcon_raw(pid_t pid, security_context_t * con, const char *val)
327 {
328 	char buf[4096];
329 	FILE *fp = NULL;
330 	const char *ptr = NULL;
331 
332 	snprintf(buf, sizeof(buf), "%s/%ld/attr/%s", "/proc", (long int)pid,
333 		 val);
334 
335 	if (!(fp = fopen(buf, "rb")))
336 		return (-1);
337 
338 	ptr = fgets(buf, sizeof(buf), fp);
339 
340 	fclose(fp);
341 
342 	*con = NULL;
343 	if (ptr) {		/* return *con = NULL, when proc file is empty */
344 		char *tmp = strchr(ptr, '\n');
345 
346 		if (tmp)
347 			*tmp = 0;
348 
349 		if (*ptr && !(*con = strdup(ptr)))
350 			return (-1);
351 	}
352 
353 	return (0);
354 }
355 
356 static int my_getpidexeccon_raw(pid_t pid, security_context_t * con)
357 {
358 	return (my_getXcon_raw(pid, con, "exec"));
359 }
360 static int my_getpidfscreatecon_raw(pid_t pid, security_context_t * con)
361 {
362 	return (my_getXcon_raw(pid, con, "fscreate"));
363 }
364 static int my_getpidkeycreatecon_raw(pid_t pid, security_context_t * con)
365 {
366 	return (my_getXcon_raw(pid, con, "keycreate"));
367 }
368 
369 static security_context_t get_scon(void)
370 {
371 	static char dummy_NIL[1] = "";
372 	security_context_t con = NULL;
373 	int ret = -1;
374 	int raw = TRUE;
375 
376 	switch (opts->from_type) {
377 	case OPTS_FROM_ARG:
378 		if (!(con = strdup(opts->f.arg)))
379 			err(EXIT_FAILURE,
380 			    " Couldn't allocate security context");
381 		raw = !opts->disp_raw;	/* always do conversion */
382 		break;
383 
384 	case OPTS_FROM_STDIN:
385 		{
386 			char buf[4096] = "";
387 			char *ptr = buf;
388 
389 			while (!*ptr) {
390 				if (!(ptr = fgets(buf, sizeof(buf), stdin)))
391 					err(EXIT_FAILURE,
392 					    " Couldn't read security context");
393 
394 				ptr += strspn(ptr, " \n\t");
395 				ptr[strcspn(ptr, " \n\t")] = 0;
396 			}
397 
398 			if (!(con = strdup(ptr)))
399 				err(EXIT_FAILURE,
400 				    " Couldn't allocate security context");
401 
402 			raw = !opts->disp_raw;	/* always do conversion */
403 			break;
404 		}
405 
406 	case OPTS_FROM_CUR:
407 		ret = getcon_raw(&con);
408 
409 		if (ret == -1)
410 			err(EXIT_FAILURE,
411 			    " Couldn't get current security context");
412 		break;
413 	case OPTS_FROM_CUREXE:
414 		ret = getexeccon_raw(&con);
415 
416 		if (ret == -1)
417 			err(EXIT_FAILURE,
418 			    " Couldn't get current exec security context");
419 
420 		if (!con)
421 			con = strdup(dummy_NIL);
422 		break;
423 	case OPTS_FROM_CURFS:
424 		ret = getfscreatecon_raw(&con);
425 
426 		if (ret == -1)
427 			err(EXIT_FAILURE,
428 			    " Couldn't get current fs security context");
429 
430 		if (!con)
431 			con = strdup(dummy_NIL);
432 		break;
433 	case OPTS_FROM_CURKEY:
434 		ret = getkeycreatecon_raw(&con);
435 
436 		if (ret == -1)
437 			err(EXIT_FAILURE,
438 			    " Couldn't get current key security context");
439 
440 		if (!con)
441 			con = strdup(dummy_NIL);
442 		break;
443 
444 	case OPTS_FROM_PROC:
445 		ret = getpidcon_raw(opts->f.pid, &con);
446 
447 		if (ret == -1)
448 			err(EXIT_FAILURE,
449 			    " Couldn't get security context for pid %lu",
450 			    (unsigned long)opts->f.pid);
451 		break;
452 	case OPTS_FROM_PROCEXE:
453 		ret = my_getpidexeccon_raw(opts->f.pid, &con);
454 
455 		if (ret == -1)
456 			err(EXIT_FAILURE,
457 			    " Couldn't get security context for pid %lu",
458 			    (unsigned long)opts->f.pid);
459 
460 		if (!con)
461 			con = strdup(dummy_NIL);
462 		break;
463 	case OPTS_FROM_PROCFS:
464 		ret = my_getpidfscreatecon_raw(opts->f.pid, &con);
465 
466 		if (ret == -1)
467 			err(EXIT_FAILURE,
468 			    " Couldn't get security context for pid %lu",
469 			    (unsigned long)opts->f.pid);
470 
471 		if (!con)
472 			con = strdup(dummy_NIL);
473 		/* disabled -- override with normal context ...
474 		   {
475 		   opts->from_type = OPTS_FROM_PROC;
476 		   return (get_scon());
477 		   } */
478 		break;
479 	case OPTS_FROM_PROCKEY:
480 		ret = my_getpidkeycreatecon_raw(opts->f.pid, &con);
481 
482 		if (ret == -1)
483 			err(EXIT_FAILURE,
484 			    " Couldn't get security context for pid %lu",
485 			    (unsigned long)opts->f.pid);
486 
487 		if (!con)
488 			con = strdup(dummy_NIL);
489 		break;
490 
491 	case OPTS_FROM_FILE:
492 		ret = getfilecon_raw(opts->f.file, &con);
493 
494 		if (ret == -1)
495 			err(EXIT_FAILURE,
496 			    " Couldn't get security context for file %s",
497 			    opts->f.file);
498 		break;
499 
500 	case OPTS_FROM_LINK:
501 		ret = lgetfilecon_raw(opts->f.link, &con);
502 
503 		if (ret == -1)
504 			err(EXIT_FAILURE,
505 			    " Couldn't get security context for symlink %s",
506 			    opts->f.link);
507 		break;
508 
509 	default:
510 		assert(FALSE);
511 	}
512 
513 	if (opts->disp_raw != raw) {
514 		security_context_t ncon = NULL;
515 
516 		if (opts->disp_raw)
517 			selinux_trans_to_raw_context(con, &ncon);
518 		else
519 			selinux_raw_to_trans_context(con, &ncon);
520 
521 		freecon(con);
522 		con = ncon;
523 	}
524 
525 	return (con);
526 }
527 
528 static void disp__con_val(const char *name, const char *val)
529 {
530 	static int done = FALSE;
531 
532 	assert(name);
533 
534 	if (!val)
535 		val = "";	/* targeted has no "level" etc.,
536 				   any errors should happen at context_new() time */
537 
538 	if (opts->disp_prompt) {
539 		if (xstreq("mls-range", name) && !*val)
540 			return;	/* skip, mls-range if it's empty */
541 
542 		fprintf(stdout, "%s%s", done ? ":" : "", val);
543 	} else if (disp_multi())
544 		fprintf(stdout, "%s: %s\n", name, val);
545 	else
546 		fprintf(stdout, "%s\n", val);
547 
548 	done = TRUE;
549 }
550 
551 static void disp_con(security_context_t scon)
552 {
553 	context_t con = NULL;
554 
555 	if (!*scon) {		/* --self-exec and --self-fs etc. */
556 		if (opts->disp_user)
557 			disp__con_val("user", NULL);
558 		if (opts->disp_role)
559 			disp__con_val("role", NULL);
560 		if (opts->disp_type)
561 			disp__con_val("type", NULL);
562 		if (opts->disp_sen)
563 			disp__con_val("sensitivity", NULL);
564 		if (opts->disp_clr)
565 			disp__con_val("clearance", NULL);
566 		if (opts->disp_mlsr)
567 			disp__con_val("mls-range", NULL);
568 		return;
569 	}
570 
571 	if (!(con = context_new(scon)))
572 		errx(EXIT_FAILURE, "Couldn't create context from: %s", scon);
573 
574 	if (opts->disp_user)
575 		disp__con_val("user", context_user_get(con));
576 	if (opts->disp_role)
577 		disp__con_val("role", context_role_get(con));
578 	if (opts->disp_type)
579 		disp__con_val("type", context_type_get(con));
580 	if (opts->disp_sen) {
581 		const char *val = NULL;
582 		char *tmp = NULL;
583 
584 		val = context_range_get(con);
585 		if (!val)
586 			val = "";	/* targeted has no "level" etc.,
587 					   any errors should happen at context_new() time */
588 
589 		tmp = strdup(val);
590 		if (!tmp)
591 			errx(EXIT_FAILURE, "Couldn't create context from: %s",
592 			     scon);
593 		if (strchr(tmp, '-'))
594 			*strchr(tmp, '-') = 0;
595 
596 		disp__con_val("sensitivity", tmp);
597 
598 		free(tmp);
599 	}
600 	if (opts->disp_clr) {
601 		const char *val = NULL;
602 		char *tmp = NULL;
603 
604 		val = context_range_get(con);
605 		if (!val)
606 			val = "";	/* targeted has no "level" etc.,
607 					   any errors should happen at context_new() time */
608 
609 		tmp = strdup(val);
610 		if (!tmp)
611 			errx(EXIT_FAILURE, "Couldn't create context from: %s",
612 			     scon);
613 		if (strchr(tmp, '-'))
614 			disp__con_val("clearance", strchr(tmp, '-') + 1);
615 		else
616 			disp__con_val("clearance", tmp);
617 
618 		free(tmp);
619 	}
620 
621 	if (opts->disp_mlsr)
622 		disp__con_val("mls-range", context_range_get(con));
623 
624 	context_free(con);
625 }
626 
627 int main(int argc, char *argv[])
628 {
629 	security_context_t scon = NULL;
630 
631 	cmd_line(argc, argv);
632 
633 	scon = get_scon();
634 
635 	disp_con(scon);
636 
637 	freecon(scon);
638 
639 	exit(EXIT_SUCCESS);
640 }
| Location | Tool | Test ID | Issue | |
|---|---|---|---|---|
| default_encoding.c:37:37 | cpychecker | mismatching-type-in-format-string | setdefaultencoding | Mismatching type in call to PyArg_ParseTupleAndKeywords with format code "s:setdefaultencoding" | 
| default_encoding.c:44:1 | cpychecker | returns-NULL-without-setting-exception | setdefaultencoding | returning (PyObject*)NULL without setting an exception | 
 1 /*
 2  * Authors:
 3  *   John Dennis <jdennis@redhat.com>
 4  *
 5  * Copyright (C) 2009  Red Hat
 6  * see file 'COPYING' for use and warranty information
 7  *
 8  * This program is free software; you can redistribute it and/or
 9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 
22 #include <Python.h>
23 
24 PyDoc_STRVAR(setdefaultencoding_doc,
25 "setdefaultencoding(encoding='utf-8')\n\
26 \n\
27 Set the current default string encoding used by the Unicode implementation.\n\
28 Defaults to utf-8."
29 );
30 
31 static PyObject *
32 setdefaultencoding(PyObject *self, PyObject *args, PyObject *kwds)
33 {
34     static char *kwlist[] = {"utf-8", NULL};
35     char *encoding;
36 
37     if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:setdefaultencoding", kwlist, &encoding))
        argument 5 ("&encoding") had type
    "char * *"
  but was expecting
    "const char * *"
  for format code "s"
   (emitted by cpychecker)38         return NULL;
39 
40     if (PyUnicode_SetDefaultEncoding(encoding))
41         return NULL;
42 
43     Py_RETURN_NONE;
44 }
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
45 
46 static PyMethodDef methods[] = {
47     {"setdefaultencoding", (PyCFunction)setdefaultencoding, METH_VARARGS|METH_KEYWORDS, setdefaultencoding_doc},
48 	{NULL,		NULL}		/* sentinel */
49 };
50 
51 
52 PyMODINIT_FUNC
53 initdefault_encoding_utf8(void)
54 {
55     PyUnicode_SetDefaultEncoding("utf-8");
56     Py_InitModule3("default_encoding_utf8", methods, "Forces the default encoding to utf-8");
57 }
No issues found
  1 /* Authors: Karl MacMillan <kmacmillan@tresys.com>
  2  *          Joshua Brindle <jbrindle@tresys.com>
  3  *          Jason Tang <jtang@tresys.com>
  4  *
  5  * Copyright (C) 2004-2005 Tresys Technology, LLC
  6  *      This program is free software; you can redistribute it and/or
  7  *      modify it under the terms of the GNU General Public License as
  8  *      published by the Free Software Foundation, version 2.
  9  */
 10 
 11 #include <fcntl.h>
 12 #include <getopt.h>
 13 #include <signal.h>
 14 #include <stdio.h>
 15 #include <stdlib.h>
 16 #include <errno.h>
 17 #include <string.h>
 18 #include <unistd.h>
 19 #include <sys/mman.h>
 20 #include <sys/stat.h>
 21 #include <sys/types.h>
 22 
 23 #include <semanage/modules.h>
 24 
 25 enum client_modes { NO_MODE, INSTALL_M, UPGRADE_M, BASE_M, ENABLE_M, DISABLE_M, REMOVE_M,
 26 	LIST_M, RELOAD
 27 };
 28 /* list of modes in which one ought to commit afterwards */
 29 static const int do_commit[] = {
 30 	0, 1, 1, 1, 1, 1, 1,
 31 	0, 0
 32 };
 33 
 34 struct command {
 35 	enum client_modes mode;
 36 	char *arg;
 37 };
 38 static struct command *commands = NULL;
 39 static int num_commands = 0;
 40 
 41 /* options given on command line */
 42 static int verbose;
 43 static int reload;
 44 static int no_reload;
 45 static int create_store;
 46 static int build;
 47 static int disable_dontaudit;
 48 static int preserve_tunables;
 49 
 50 static semanage_handle_t *sh = NULL;
 51 static char *store;
 52 
 53 extern char *optarg;
 54 extern int optind;
 55 
 56 static void cleanup(void)
 57 {
 58 	while (--num_commands >= 0) {
 59 		free(commands[num_commands].arg);
 60 	}
 61 	free(commands);
 62 }
 63 
 64 /* Signal handlers. */
 65 static void handle_signal(int sig_num)
 66 {
 67 	if (sig_num == SIGINT || sig_num == SIGQUIT || sig_num == SIGTERM) {
 68 		/* catch these signals, and then drop them */
 69 	}
 70 }
 71 
 72 static void set_store(char *storename)
 73 {
 74 	/* For now this only supports a store name, later on this 
 75 	 * should support an address for a remote connection */
 76 
 77 	if ((store = strdup(storename)) == NULL) {
 78 		fprintf(stderr, "Out of memory!\n");
 79 		goto bad;
 80 	}
 81 
 82 	return;
 83 
 84       bad:
 85 	cleanup();
 86 	exit(1);
 87 }
 88 
 89 /* Establish signal handlers for the process. */
 90 static void create_signal_handlers(void)
 91 {
 92 	if (signal(SIGINT, handle_signal) == SIG_ERR ||
 93 	    signal(SIGQUIT, handle_signal) == SIG_ERR ||
 94 	    signal(SIGTERM, handle_signal) == SIG_ERR) {
 95 		fprintf(stderr, "Could not set up signal handler.\n");
 96 		exit(255);
 97 	}
 98 }
 99 
100 static void usage(char *progname)
101 {
102 	printf("usage:  %s [options]... MODE [MODES]...\n", progname);
103 	printf("Manage SELinux policy modules.\n");
104 	printf("MODES:\n");
105 	printf("  -R, --reload		    reload policy\n");
106 	printf("  -B, --build		    build and reload policy\n");
107 	printf("  -i,--install=MODULE_PKG   install a new module\n");
108 	printf("  -u,--upgrade=MODULE_PKG   upgrade existing module\n");
109 	printf("  -b,--base=MODULE_PKG      install new base module\n");
110 	printf("  -e,--enable=MODULE_PKG    enable existing module\n");
111 	printf("  -d,--disable=MODULE_PKG   disable existing module\n");
112  	printf("  -r,--remove=MODULE_NAME   remove existing module\n");
113 	printf
114 	    ("  -l,--list-modules         display list of installed modules\n");
115 	printf("Other options:\n");
116 	printf("  -s,--store	   name of the store to operate on\n");
117 	printf("  -N,-n,--noreload do not reload policy after commit\n");
118 	printf("  -h,--help        print this message and quit\n");
119 	printf("  -v,--verbose     be verbose\n");
120 	printf("  -D,--disable_dontaudit	Remove dontaudits from policy\n");
121 	printf("  -P,--preserve_tunables	Preserve tunables in policy\n");
122 	printf("  -p,--path        use an alternate path for the policy root\n");
123 }
124 
125 /* Sets the global mode variable to new_mode, but only if no other
126  * mode has been given. */
127 static void set_mode(enum client_modes new_mode, char *arg)
128 {
129 	struct command *c;
130 	char *s;
131 	if ((c = realloc(commands, sizeof(*c) * (num_commands + 1))) == NULL) {
132 		fprintf(stderr, "Out of memory!\n");
133 		cleanup();
134 		exit(1);
135 	}
136 	commands = c;
137 	commands[num_commands].mode = new_mode;
138 	commands[num_commands].arg = NULL;
139 	num_commands++;
140 	if (arg != NULL) {
141 		if ((s = strdup(arg)) == NULL) {
142 			fprintf(stderr, "Out of memory!\n");
143 			cleanup();
144 			exit(1);
145 		}
146 		commands[num_commands - 1].arg = s;
147 	}
148 }
149 
150 /* Parse command line and set global options. */
151 static void parse_command_line(int argc, char **argv)
152 {
153 	static struct option opts[] = {
154 		{"store", required_argument, NULL, 's'},
155 		{"base", required_argument, NULL, 'b'},
156 		{"help", 0, NULL, 'h'},
157 		{"install", required_argument, NULL, 'i'},
158 		{"list-modules", 0, NULL, 'l'},
159 		{"verbose", 0, NULL, 'v'},
160 		{"enable", required_argument, NULL, 'e'},
161 		{"disable", required_argument, NULL, 'd'},
162 		{"remove", required_argument, NULL, 'r'},
163 		{"upgrade", required_argument, NULL, 'u'},
164 		{"reload", 0, NULL, 'R'},
165 		{"noreload", 0, NULL, 'n'},
166 		{"build", 0, NULL, 'B'},
167 		{"disable_dontaudit", 0, NULL, 'D'},
168 		{"preserve_tunables", 0, NULL, 'P'},
169 		{"path", required_argument, NULL, 'p'},
170 		{NULL, 0, NULL, 0}
171 	};
172 	int i;
173 	verbose = 0;
174 	reload = 0;
175 	no_reload = 0;
176 	create_store = 0;
177 	while ((i =
178 		getopt_long(argc, argv, "p:s:b:hi:lvqe:d:r:u:RnNBDP", opts,
179 			    NULL)) != -1) {
180 		switch (i) {
181 		case 'b':
182 			set_mode(BASE_M, optarg);
183 			create_store = 1;
184 			break;
185 		case 'h':
186 			usage(argv[0]);
187 			exit(0);
188 		case 'i':
189 			set_mode(INSTALL_M, optarg);
190 			break;
191 		case 'l':
192 			set_mode(LIST_M, NULL);
193 			break;
194 		case 'v':
195 			verbose = 1;
196 			break;
197 		case 'e':
198 			set_mode(ENABLE_M, optarg);
199 			break;
200 		case 'd':
201 			set_mode(DISABLE_M, optarg);
202 			break;
203 		case 'r':
204 			set_mode(REMOVE_M, optarg);
205 			break;
206 		case 'p':
207 			semanage_set_root(optarg);
208 			break;
209 		case 'u':
210 			set_mode(UPGRADE_M, optarg);
211 			break;
212 		case 's':
213 			set_store(optarg);
214 			break;
215 		case 'R':
216 			reload = 1;
217 			break;
218 		case 'n':
219 			no_reload = 1;
220 			break;
221 		case 'N':
222 			no_reload = 1;
223 			break;
224 		case 'B':
225 			build = 1;
226 			break;
227 		case 'D':
228 			disable_dontaudit = 1;
229 			break;
230 		case 'P':
231 			preserve_tunables = 1;
232 			break;
233 		case '?':
234 		default:{
235 				usage(argv[0]);
236 				exit(1);
237 			}
238 		}
239 	}
240 	if ((build || reload) && num_commands) {
241 		fprintf(stderr,
242 			"build or reload should not be used with other commands\n");
243 		usage(argv[0]);
244 		exit(1);
245 	}
246 	if (num_commands == 0 && reload == 0 && build == 0) {
247 		fprintf(stderr, "At least one mode must be specified.\n");
248 		usage(argv[0]);
249 		exit(1);
250 	}
251 
252 	if (optind < argc) {
253 		int mode;
254 		/* if -i/u/r was the last command treat any remaining
255 		 * arguments as args. Will allow 'semodule -i *.pp' to
256 		 * work as expected.
257 		 */
258 
259 		if (commands && commands[num_commands - 1].mode == INSTALL_M) {
260 			mode = INSTALL_M;
261 		} else if (commands && commands[num_commands - 1].mode == UPGRADE_M) {
262 			mode = UPGRADE_M;
263 		} else if (commands && commands[num_commands - 1].mode == REMOVE_M) {
264 			mode = REMOVE_M;
265 		} else if (commands && commands[num_commands - 1].mode == ENABLE_M) {
266 			mode = ENABLE_M;
267 		} else if (commands && commands[num_commands - 1].mode == DISABLE_M) {
268 			mode = DISABLE_M;
269 		} else {
270 			fprintf(stderr, "unknown additional arguments:\n");
271 			while (optind < argc)
272 				fprintf(stderr, " %s", argv[optind++]);
273 			fprintf(stderr, "\n\n");
274 			usage(argv[0]);
275 			exit(1);
276 		}
277 		while (optind < argc)
278 			set_mode(mode, argv[optind++]);
279 	}
280 }
281 
282 int main(int argc, char *argv[])
283 {
284 	int i, commit = 0;
285 	int result;
286 	int status = EXIT_FAILURE;
287 
288 	create_signal_handlers();
289 	parse_command_line(argc, argv);
290 
291 	if (build)
292 		commit = 1;
293 
294 	sh = semanage_handle_create();
295 	if (!sh) {
296 		fprintf(stderr, "%s:  Could not create semanage handle\n",
297 			argv[0]);
298 		goto cleanup_nohandle;
299 	}
300 
301 	if (store) {
302 		/* Set the store we want to connect to, before connecting.
303 		 * this will always set a direct connection now, an additional
304 		 * option will need to be used later to specify a policy server 
305 		 * location */
306 		semanage_select_store(sh, store, SEMANAGE_CON_DIRECT);
307 	}
308 
309 	/* if installing base module create store if necessary, for bootstrapping */
310 	semanage_set_create_store(sh, create_store);
311 
312 	if (!create_store) {
313 		if (!semanage_is_managed(sh)) {
314 			fprintf(stderr,
315 				"%s: SELinux policy is not managed or store cannot be accessed.\n",
316 				argv[0]);
317 			goto cleanup;
318 		}
319 
320 		if (semanage_access_check(sh) < SEMANAGE_CAN_READ) {
321 			fprintf(stderr, "%s: Cannot read policy store.\n",
322 				argv[0]);
323 			goto cleanup;
324 		}
325 	}
326 
327 	if ((result = semanage_connect(sh)) < 0) {
328 		fprintf(stderr, "%s:  Could not connect to policy handler\n",
329 			argv[0]);
330 		goto cleanup;
331 	}
332 
333 	if (reload) {
334 		if ((result = semanage_reload_policy(sh)) < 0) {
335 			fprintf(stderr, "%s:  Could not reload policy\n",
336 				argv[0]);
337 			goto cleanup;
338 		}
339 	}
340 
341 	if (build) {
342 		if ((result = semanage_begin_transaction(sh)) < 0) {
343 			fprintf(stderr, "%s:  Could not begin transaction:  %s\n",
344 				argv[0], errno ? strerror(errno) : "");
345 			goto cleanup;
346 		}
347 	}
348 
349 	for (i = 0; i < num_commands; i++) {
350 		enum client_modes mode = commands[i].mode;
351 		char *mode_arg = commands[i].arg;
352 		switch (mode) {
353 		case INSTALL_M:{
354 				if (verbose) {
355 					printf
356 					    ("Attempting to install module '%s':\n",
357 					     mode_arg);
358 				}
359 				result =
360 				    semanage_module_install_file(sh, mode_arg);
361 				break;
362 			}
363 		case UPGRADE_M:{
364 				if (verbose) {
365 					printf
366 					    ("Attempting to upgrade module '%s':\n",
367 					     mode_arg);
368 				}
369 				result =
370 				    semanage_module_upgrade_file(sh, mode_arg);
371 				break;
372 			}
373 		case BASE_M:{
374 				if (verbose) {
375 					printf
376 					    ("Attempting to install base module '%s':\n",
377 					     mode_arg);
378 				}
379 				result =
380 				    semanage_module_install_base_file(sh, mode_arg);
381 				break;
382 			}
383 		case ENABLE_M:{
384 				if (verbose) {
385 					printf
386 					    ("Attempting to enable module '%s':\n",
387 					     mode_arg);
388 				}
389 				result = semanage_module_enable(sh, mode_arg);
390 				if ( result == -2 ) { 
391 					continue;
392 				}
393 				break;
394 			}
395 		case DISABLE_M:{
396 				if (verbose) {
397 					printf
398 					    ("Attempting to disable module '%s':\n",
399 					     mode_arg);
400 				}
401 				result = semanage_module_disable(sh, mode_arg);
402 				if ( result == -2 ) { 
403 					continue;
404 				}
405 				break;
406 			}
407 		case REMOVE_M:{
408 				if (verbose) {
409 					printf
410 					    ("Attempting to remove module '%s':\n",
411 					     mode_arg);
412 				}
413 				result = semanage_module_remove(sh, mode_arg);
414 				if ( result == -2 ) { 
415 					continue;
416 				}
417 				break;
418 			}
419 		case LIST_M:{
420 				semanage_module_info_t *modinfo;
421 				int num_modules;
422 				if (verbose) {
423 					printf
424 					    ("Attempting to list active modules:\n");
425 				}
426 				if ((result =
427 				     semanage_module_list(sh, &modinfo,
428 							  &num_modules)) >= 0) {
429 					int j;
430 					if (num_modules == 0) {
431 						printf("No modules.\n");
432 					}
433 					for (j = 0; j < num_modules; j++) {
434 						semanage_module_info_t *m =
435 						    semanage_module_list_nth
436 						    (modinfo, j);
437 						printf("%s\t%s\t%s\n",
438 						       semanage_module_get_name
439 						       (m),
440 						       semanage_module_get_version
441 						       (m), 
442 						       (semanage_module_get_enabled(m) ? "" : "Disabled"));
443 						semanage_module_info_datum_destroy
444 						    (m);
445 					}
446 					free(modinfo);
447 				}
448 				break;
449 			}
450 		default:{
451 				fprintf(stderr,
452 					"%s:  Unknown mode specified.\n",
453 					argv[0]);
454 				usage(argv[0]);
455 				goto cleanup;
456 			}
457 		}
458 		commit += do_commit[mode];
459 		if (result < 0) {
460 			fprintf(stderr, "%s:  Failed on %s!\n", argv[0],
461 				mode_arg ? : "list");
462 			goto cleanup;
463 		} else if (verbose) {
464 			printf("Ok: return value of %d.\n", result);
465 		}
466 	}
467 
468 	if (commit) {
469 		if (verbose)
470 			printf("Committing changes:\n");
471 		if (no_reload)
472 			semanage_set_reload(sh, 0);
473 		if (build)
474 			semanage_set_rebuild(sh, 1);
475 		if (disable_dontaudit)
476 			semanage_set_disable_dontaudit(sh, 1);
477 		else if (build)
478 			semanage_set_disable_dontaudit(sh, 0);
479 		if (preserve_tunables)
480 			semanage_set_preserve_tunables(sh, 1);
481 
482 		result = semanage_commit(sh);
483 	}
484 
485 	if (result < 0) {
486 		fprintf(stderr, "%s:  Failed!\n", argv[0]);
487 		goto cleanup;
488 	} else if (commit && verbose) {
489 		printf("Ok: transaction number %d.\n", result);
490 	}
491 
492 	if (semanage_disconnect(sh) < 0) {
493 		fprintf(stderr, "%s:  Error disconnecting\n", argv[0]);
494 		goto cleanup;
495 	}
496 	status = EXIT_SUCCESS;
497 
498       cleanup:
499 	if (semanage_is_connected(sh)) {
500 		if (semanage_disconnect(sh) < 0) {
501 			fprintf(stderr, "%s:  Error disconnecting\n", argv[0]);
502 		}
503 	}
504 	semanage_handle_destroy(sh);
505 
506       cleanup_nohandle:
507 	cleanup();
508 	exit(status);
509 }
No issues found
  1 /* Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
  2  *
  3  * Copyright (C) 2006 Tresys Technology, LLC
  4  * Copyright (C) 2006-2007 Red Hat, Inc.
  5  *
  6  * This program is free software; you can redistribute it and/or modify
  7  * it under the terms of the GNU General Public License as published by
  8  * the Free Software Foundation, version 2.
  9  *
 10  */
 11 
 12 /* Because we _must_ muck around in the internal representation of
 13  * the policydb (and include the internal header below) this program
 14  * must be statically linked to libsepol like checkpolicy. It is
 15  * not clear if it is worthwhile to fix this, as exposing the details
 16  * of avrule_blocks - even in an ABI safe way - seems undesirable.
 17  */
 18 #include <sepol/module.h>
 19 #include <sepol/errcodes.h>
 20 #include <sepol/policydb/policydb.h>
 21 
 22 #include <getopt.h>
 23 #include <fcntl.h>
 24 #include <stdio.h>
 25 #include <errno.h>
 26 #include <sys/mman.h>
 27 #include <sys/types.h>
 28 #include <sys/stat.h>
 29 #include <stdlib.h>
 30 #include <unistd.h>
 31 #include <string.h>
 32 #include <assert.h>
 33 
 34 /* for getopt */
 35 extern char *optarg;
 36 extern int optind;
 37 
 38 /* This is really a horrible hack, but the base module
 39  * is referred to with the following name. The same
 40  * thing is done in the linker for displaying error
 41  * messages.
 42  */
 43 #define BASE_NAME "BASE"
 44 
 45 static void usage(char *program_name)
 46 {
 47 	printf("usage: %s [-v -g -b] basemodpkg modpkg1 [modpkg2 ... ]\n",
 48 	       program_name);
 49 	exit(1);
 50 }
 51 
 52 /* Basic string hash and compare for the hashtables used in
 53  * generate_requires. Copied from symtab.c.
 54  */
 55 static unsigned int reqsymhash(hashtab_t h, hashtab_key_t key)
 56 {
 57 	char *p, *keyp;
 58 	size_t size;
 59 	unsigned int val;
 60 
 61 	val = 0;
 62 	keyp = (char *)key;
 63 	size = strlen(keyp);
 64 	for (p = keyp; ((size_t) (p - keyp)) < size; p++)
 65 		val =
 66 		    (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
 67 	return val & (h->size - 1);
 68 }
 69 
 70 static int reqsymcmp(hashtab_t h
 71 		     __attribute__ ((unused)), hashtab_key_t key1,
 72 		     hashtab_key_t key2)
 73 {
 74 	char *keyp1, *keyp2;
 75 
 76 	keyp1 = (char *)key1;
 77 	keyp2 = (char *)key2;
 78 	return strcmp(keyp1, keyp2);
 79 }
 80 
 81 /* Load a policy package from the given filename. Progname is used for
 82  * error reporting.
 83  */
 84 static sepol_module_package_t *load_module(char *filename, char *progname)
 85 {
 86 	int ret;
 87 	FILE *fp = NULL;
 88 	struct sepol_policy_file *pf = NULL;
 89 	sepol_module_package_t *p = NULL;
 90 
 91 	if (sepol_module_package_create(&p)) {
 92 		fprintf(stderr, "%s:  Out of memory\n", progname);
 93 		goto bad;
 94 	}
 95 	if (sepol_policy_file_create(&pf)) {
 96 		fprintf(stderr, "%s:  Out of memory\n", progname);
 97 		goto bad;
 98 	}
 99 	fp = fopen(filename, "r");
100 	if (!fp) {
101 		fprintf(stderr, "%s:  Could not open package %s:  %s", progname,
102 			filename, strerror(errno));
103 		goto bad;
104 	}
105 	sepol_policy_file_set_fp(pf, fp);
106 
107 	ret = sepol_module_package_read(p, pf, 0);
108 	if (ret) {
109 		fprintf(stderr, "%s:  Error while reading package from %s\n",
110 			progname, filename);
111 		goto bad;
112 	}
113 	fclose(fp);
114 	sepol_policy_file_free(pf);
115 	return p;
116       bad:
117 	sepol_module_package_free(p);
118 	sepol_policy_file_free(pf);
119 	if (fp)
120 		fclose(fp);
121 	return NULL;
122 }
123 
124 /* This function generates the requirements graph and stores it in
125  * a set of nested hashtables. The top level hash table stores modules
126  * keyed by name. The value of that module is a hashtable storing all
127  * of the requirements keyed by name. There is no value for the requirements
128  * hashtable.
129  *
130  * This only tracks symbols that are _required_ - optional symbols
131  * are completely ignored. A future version might look at this.
132  *
133  * This requirement generation only looks at booleans and types because:
134  *  - object classes: (for now) only present in bases
135  *  - roles: since they are multiply declared it is not clear how
136  *           to present these requirements as they will be satisfied
137  *           by multiple modules.
138  *  - users: same problem as roles plus they are usually defined outside
139  *           of the policy.
140  *  - levels / cats: can't be required or used in modules.
141  */
142 static hashtab_t generate_requires(policydb_t * p)
143 {
144 	avrule_block_t *block;
145 	avrule_decl_t *decl;
146 	char *mod_name, *req_name, *id;
147 	ebitmap_t *b;
148 	ebitmap_node_t *node;
149 	uint32_t i, j;
150 	int ret;
151 	scope_datum_t *scope;
152 	hashtab_t mods;
153 	hashtab_t reqs;
154 
155 	mods = hashtab_create(reqsymhash, reqsymcmp, 64);
156 	if (mods == NULL)
157 		return NULL;
158 
159 	for (block = p->global; block != NULL; block = block->next) {
160 		if (block->flags & AVRULE_OPTIONAL)
161 			continue;
162 		for (decl = block->branch_list; decl != NULL; decl = decl->next) {
163 			mod_name =
164 			    decl->module_name ? decl->module_name : BASE_NAME;
165 			for (i = 0; i < SYM_NUM; i++) {
166 				if (!(i == SYM_TYPES || i == SYM_BOOLS))
167 					continue;
168 				b = &decl->required.scope[i];
169 				ebitmap_for_each_bit(b, node, j) {
170 					if (!ebitmap_node_get_bit(node, j))
171 						continue;
172 					id = p->sym_val_to_name[i][j];
173 					scope =
174 					    (scope_datum_t *) hashtab_search(p->
175 									     scope
176 									     [i].
177 									     table,
178 									     id);
179 					/* since this is only called after a successful link,
180 					 * this should never happen */
181 					assert(scope->scope == SCOPE_DECL);
182 					req_name =
183 					    p->decl_val_to_struct[scope->
184 								  decl_ids[0]]->
185 					    module_name ? p->
186 					    decl_val_to_struct[scope->
187 							       decl_ids[0]]->
188 					    module_name : BASE_NAME;
189 
190 					reqs =
191 					    (hashtab_t) hashtab_search(mods,
192 								       mod_name);
193 					if (!reqs) {
194 						reqs =
195 						    hashtab_create(reqsymhash,
196 								   reqsymcmp,
197 								   64);
198 						if (reqs == NULL) {
199 							return NULL;
200 						}
201 						ret =
202 						    hashtab_insert(mods,
203 								   mod_name,
204 								   reqs);
205 						if (ret != SEPOL_OK)
206 							return NULL;
207 					}
208 					ret =
209 					    hashtab_insert(reqs, req_name,
210 							   NULL);
211 					if (!
212 					    (ret == SEPOL_EEXIST
213 					     || ret == SEPOL_OK))
214 						return NULL;
215 				}
216 			}
217 
218 		}
219 	}
220 
221 	return mods;
222 }
223 
224 static void free_requires(hashtab_t req)
225 {
226 	unsigned int i;
227 	hashtab_ptr_t cur;
228 
229 	/* We steal memory for everything stored in the hash tables
230 	 * from the policydb, so this only looks like it leaks.
231 	 */
232 	for (i = 0; i < req->size; i++) {
233 		cur = req->htable[i];
234 		while (cur != NULL) {
235 			hashtab_destroy((hashtab_t) cur->datum);
236 			cur = cur->next;
237 		}
238 	}
239 	hashtab_destroy(req);
240 }
241 
242 static void output_graphviz(hashtab_t mods, int exclude_base, FILE * f)
243 {
244 	unsigned int i, j;
245 	hashtab_ptr_t cur, cur2;
246 	hashtab_t reqs;
247 
248 	fprintf(f, "digraph mod_deps {\n");
249 	fprintf(f, "\toverlap=false\n");
250 
251 	for (i = 0; i < mods->size; i++) {
252 		cur = mods->htable[i];
253 		while (cur != NULL) {
254 			reqs = (hashtab_t) cur->datum;
255 			assert(reqs);
256 			for (j = 0; j < reqs->size; j++) {
257 				cur2 = reqs->htable[j];
258 				while (cur2 != NULL) {
259 					if (exclude_base
260 					    && strcmp(cur2->key,
261 						      BASE_NAME) == 0) {
262 						cur2 = cur2->next;
263 						continue;
264 					}
265 					fprintf(f, "\t%s -> %s\n", cur->key,
266 						cur2->key);
267 					cur2 = cur2->next;
268 				}
269 			}
270 			cur = cur->next;
271 		}
272 	}
273 	fprintf(f, "}\n");
274 }
275 
276 static void output_requirements(hashtab_t mods, int exclude_base, FILE * f)
277 {
278 	unsigned int i, j;
279 	hashtab_ptr_t cur, cur2;
280 	hashtab_t reqs;
281 	int found_req;
282 
283 	for (i = 0; i < mods->size; i++) {
284 		cur = mods->htable[i];
285 		while (cur != NULL) {
286 			reqs = (hashtab_t) cur->datum;
287 			assert(reqs);
288 			fprintf(f, "module: %s\n", cur->key);
289 			found_req = 0;
290 			for (j = 0; j < reqs->size; j++) {
291 				cur2 = reqs->htable[j];
292 				while (cur2 != NULL) {
293 					if (exclude_base
294 					    && strcmp(cur2->key,
295 						      BASE_NAME) == 0) {
296 						cur2 = cur2->next;
297 						continue;
298 					}
299 					found_req = 1;
300 					fprintf(f, "\t%s\n", cur2->key);
301 					cur2 = cur2->next;
302 				}
303 			}
304 			if (!found_req)
305 				fprintf(f, "\t[no dependencies]\n");
306 			cur = cur->next;
307 		}
308 	}
309 	fprintf(f, "}\n");
310 }
311 
312 /* Possible commands - see the command variable in
313  * main below and the man page for more info.
314  */
315 #define SHOW_DEPS    1
316 #define GEN_GRAPHVIZ 2
317 
318 int main(int argc, char **argv)
319 {
320 	int ch, i, num_mods;
321 	int verbose = 0, exclude_base = 1, command = SHOW_DEPS;
322 	char *basename;
323 	sepol_module_package_t *base, **mods;
324 	policydb_t *p;
325 	hashtab_t req;
326 
327 	while ((ch = getopt(argc, argv, "vgb")) != EOF) {
328 		switch (ch) {
329 		case 'v':
330 			verbose = 1;
331 			break;
332 		case 'g':
333 			command = GEN_GRAPHVIZ;
334 			break;
335 		case 'b':
336 			exclude_base = 0;
337 			break;
338 		default:
339 			usage(argv[0]);
340 		}
341 	}
342 
343 	/* check args */
344 	if (argc < 3 || !(optind != (argc - 1))) {
345 		fprintf(stderr,
346 			"%s:  You must provide the base module package and at least one other module package\n",
347 			argv[0]);
348 		usage(argv[0]);
349 	}
350 
351 	basename = argv[optind++];
352 	base = load_module(basename, argv[0]);
353 	if (!base) {
354 		fprintf(stderr,
355 			"%s:  Could not load base module from file %s\n",
356 			argv[0], basename);
357 		exit(1);
358 	}
359 
360 	num_mods = argc - optind;
361 	mods =
362 	    (sepol_module_package_t **) malloc(sizeof(sepol_module_package_t *)
363 					       * num_mods);
364 	if (!mods) {
365 		fprintf(stderr, "%s:  Out of memory\n", argv[0]);
366 		exit(1);
367 	}
368 	memset(mods, 0, sizeof(sepol_module_package_t *) * num_mods);
369 
370 	for (i = 0; optind < argc; optind++, i++) {
371 		mods[i] = load_module(argv[optind], argv[0]);
372 		if (!mods[i]) {
373 			fprintf(stderr,
374 				"%s:  Could not load module from file %s\n",
375 				argv[0], argv[optind]);
376 			exit(1);
377 		}
378 	}
379 
380 	if (sepol_link_packages(NULL, base, mods, num_mods, verbose)) {
381 		fprintf(stderr, "%s:  Error while linking packages\n", argv[0]);
382 		exit(1);
383 	}
384 
385 	p = (policydb_t *) sepol_module_package_get_policy(base);
386 	if (p == NULL)
387 		exit(1);
388 
389 	req = generate_requires(p);
390 	if (req == NULL)
391 		exit(1);
392 
393 	if (command == SHOW_DEPS)
394 		output_requirements(req, exclude_base, stdout);
395 	else
396 		output_graphviz(req, exclude_base, stdout);
397 
398 	sepol_module_package_free(base);
399 	for (i = 0; i < num_mods; i++)
400 		sepol_module_package_free(mods[i]);
401 
402 	free_requires(req);
403 
404 	exit(0);
405 }
No issues found
  1 /* Authors: Karl MacMillan <kmacmillan@tresys.com>
  2  * 	    Joshua Brindle <jbrindle@tresys.com>
  3  *
  4  * Copyright (C) 2004 Tresys Technology, LLC
  5  *	This program is free software; you can redistribute it and/or modify
  6  *  	it under the terms of the GNU General Public License as published by
  7  *	the Free Software Foundation, version 2.
  8  */
  9 
 10 #include <sepol/policydb.h>
 11 #include <sepol/module.h>
 12 
 13 #include <getopt.h>
 14 #include <fcntl.h>
 15 #include <stdio.h>
 16 #include <errno.h>
 17 #include <sys/mman.h>
 18 #include <sys/types.h>
 19 #include <sys/stat.h>
 20 #include <stdlib.h>
 21 #include <unistd.h>
 22 #include <string.h>
 23 
 24 extern char *optarg;
 25 extern int optind;
 26 
 27 int policyvers = 0;
 28 
 29 #define EXPANDPOLICY_VERSION "1.0"
 30 
 31 static void usage(char *program_name)
 32 {
 33 	printf("usage: %s [-V -a -c [version]] basemodpkg outputfile\n",
 34 	       program_name);
 35 	exit(1);
 36 }
 37 
 38 int main(int argc, char **argv)
 39 {
 40 	char *basename, *outname;
 41 	int ch, ret, show_version = 0, verbose = 0;
 42 	struct sepol_policy_file *pf;
 43 	sepol_module_package_t *base;
 44 	sepol_policydb_t *out, *p;
 45 	FILE *fp, *outfile;
 46 	int check_assertions = 1;
 47 	sepol_handle_t *handle;
 48 
 49 	while ((ch = getopt(argc, argv, "c:Vva")) != EOF) {
 50 		switch (ch) {
 51 		case 'V':
 52 			show_version = 1;
 53 			break;
 54 		case 'v':
 55 			verbose = 1;
 56 			break;
 57 		case 'c':{
 58 				long int n = strtol(optarg, NULL, 10);
 59 				if (errno) {
 60 					fprintf(stderr,
 61 						"%s:  Invalid policyvers specified: %s\n",
 62 						argv[0], optarg);
 63 					usage(argv[0]);
 64 					exit(1);
 65 				}
 66 				if (n < sepol_policy_kern_vers_min()
 67 				    || n > sepol_policy_kern_vers_max()) {
 68 					fprintf(stderr,
 69 						"%s:  policyvers value %ld not in range %d-%d\n",
 70 						argv[0], n,
 71 						sepol_policy_kern_vers_min(),
 72 						sepol_policy_kern_vers_max());
 73 					usage(argv[0]);
 74 					exit(1);
 75 				}
 76 				policyvers = n;
 77 				break;
 78 			}
 79 		case 'a':{
 80 				check_assertions = 0;
 81 				break;
 82 			}
 83 		default:
 84 			usage(argv[0]);
 85 		}
 86 	}
 87 
 88 	if (verbose) {
 89 		if (policyvers)
 90 			printf("Building version %d policy\n", policyvers);
 91 	}
 92 
 93 	if (show_version) {
 94 		printf("%s\n", EXPANDPOLICY_VERSION);
 95 		exit(0);
 96 	}
 97 
 98 	/* check args */
 99 	if (argc < 3 || !(optind != (argc - 1))) {
100 		fprintf(stderr,
101 			"%s:  You must provide the base module package and output filename\n",
102 			argv[0]);
103 		usage(argv[0]);
104 	}
105 
106 	basename = argv[optind++];
107 	outname = argv[optind];
108 
109 	handle = sepol_handle_create();
110 	if (!handle)
111 		exit(1);
112 
113 	if (sepol_policy_file_create(&pf)) {
114 		fprintf(stderr, "%s:  Out of memory\n", argv[0]);
115 		exit(1);
116 	}
117 
118 	/* read the base module */
119 	if (sepol_module_package_create(&base)) {
120 		fprintf(stderr, "%s:  Out of memory\n", argv[0]);
121 		exit(1);
122 	}
123 	fp = fopen(basename, "r");
124 	if (!fp) {
125 		fprintf(stderr, "%s:  Can't open '%s':  %s\n",
126 			argv[0], basename, strerror(errno));
127 		exit(1);
128 	}
129 	sepol_policy_file_set_fp(pf, fp);
130 	ret = sepol_module_package_read(base, pf, 0);
131 	if (ret) {
132 		fprintf(stderr, "%s:  Error in reading package from %s\n",
133 			argv[0], basename);
134 		exit(1);
135 	}
136 	fclose(fp);
137 
138 	/* linking the base takes care of enabling optional avrules */
139 	p = sepol_module_package_get_policy(base);
140 	if (sepol_link_modules(handle, p, NULL, 0, 0)) {
141 		fprintf(stderr, "%s:  Error while enabling avrules\n", argv[0]);
142 		exit(1);
143 	}
144 
145 	/* create the output policy */
146 
147 	if (sepol_policydb_create(&out)) {
148 		fprintf(stderr, "%s:  Out of memory\n", argv[0]);
149 		exit(1);
150 	}
151 
152 	sepol_set_expand_consume_base(handle, 1);
153 
154 	if (sepol_expand_module(handle, p, out, verbose, check_assertions)) {
155 		fprintf(stderr, "%s:  Error while expanding policy\n", argv[0]);
156 		exit(1);
157 	}
158 
159 	if (policyvers) {
160 		if (sepol_policydb_set_vers(out, policyvers)) {
161 			fprintf(stderr, "%s:  Invalid version %d\n", argv[0],
162 				policyvers);
163 			exit(1);
164 		}
165 	}
166 
167 	sepol_module_package_free(base);
168 
169 	outfile = fopen(outname, "w");
170 	if (!outfile) {
171 		perror(outname);
172 		exit(1);
173 	}
174 
175 	sepol_policy_file_set_fp(pf, outfile);
176 	ret = sepol_policydb_write(out, pf);
177 	if (ret) {
178 		fprintf(stderr,
179 			"%s:  Error while writing expanded policy to %s\n",
180 			argv[0], outname);
181 		exit(1);
182 	}
183 	fclose(outfile);
184 	sepol_handle_destroy(handle);
185 	sepol_policydb_free(out);
186 	sepol_policy_file_free(pf);
187 
188 	return 0;
189 }
No issues found
  1 /* Authors: Karl MacMillan <kmacmillan@tresys.com>
  2  *
  3  * Copyright (C) 2004 Tresys Technology, LLC
  4  *	This program is free software; you can redistribute it and/or modify
  5  *  	it under the terms of the GNU General Public License as published by
  6  *	the Free Software Foundation, version 2.
  7  */
  8 
  9 #include <sepol/module.h>
 10 
 11 #include <getopt.h>
 12 #include <fcntl.h>
 13 #include <stdio.h>
 14 #include <errno.h>
 15 #include <sys/mman.h>
 16 #include <sys/types.h>
 17 #include <sys/stat.h>
 18 #include <stdlib.h>
 19 #include <unistd.h>
 20 #include <string.h>
 21 
 22 #define LINKPOLICY_VERSION "1.0"
 23 
 24 char *progname;
 25 extern char *optarg;
 26 extern int optind;
 27 
 28 static void usage(char *program_name)
 29 {
 30 	printf("usage: %s [-Vv] [-o outfile] basemodpkg modpkg1 [modpkg2]...\n",
 31 	       program_name);
 32 	exit(1);
 33 }
 34 
 35 static sepol_module_package_t *load_module(char *filename)
 36 {
 37 	int ret;
 38 	FILE *fp = NULL;
 39 	struct sepol_policy_file *pf = NULL;
 40 	sepol_module_package_t *p = NULL;
 41 
 42 	if (sepol_module_package_create(&p)) {
 43 		fprintf(stderr, "%s:  Out of memory\n", progname);
 44 		goto bad;
 45 	}
 46 	if (sepol_policy_file_create(&pf)) {
 47 		fprintf(stderr, "%s:  Out of memory\n", progname);
 48 		goto bad;
 49 	}
 50 	fp = fopen(filename, "r");
 51 	if (!fp) {
 52 		fprintf(stderr, "%s:  Could not open package %s:  %s", progname,
 53 			filename, strerror(errno));
 54 		goto bad;
 55 	}
 56 	sepol_policy_file_set_fp(pf, fp);
 57 
 58 	printf("%s:  loading package from file %s\n", progname, filename);
 59 
 60 	ret = sepol_module_package_read(p, pf, 0);
 61 	if (ret) {
 62 		fprintf(stderr, "%s:  Error while reading package from %s\n",
 63 			progname, filename);
 64 		goto bad;
 65 	}
 66 	fclose(fp);
 67 	sepol_policy_file_free(pf);
 68 	return p;
 69       bad:
 70 	sepol_module_package_free(p);
 71 	sepol_policy_file_free(pf);
 72 	if (fp)
 73 		fclose(fp);
 74 	return NULL;
 75 }
 76 
 77 int main(int argc, char **argv)
 78 {
 79 	int ch, i, show_version = 0, verbose = 0, num_mods;
 80 	char *basename, *outname = NULL;
 81 	sepol_module_package_t *base, **mods;
 82 	FILE *outfile;
 83 	struct sepol_policy_file *pf;
 84 
 85 	progname = argv[0];
 86 
 87 	while ((ch = getopt(argc, argv, "o:Vv")) != EOF) {
 88 		switch (ch) {
 89 		case 'V':
 90 			show_version = 1;
 91 			break;
 92 		case 'v':
 93 			verbose = 1;
 94 			break;
 95 		case 'o':
 96 			outname = optarg;
 97 			break;
 98 		default:
 99 			usage(argv[0]);
100 		}
101 	}
102 
103 	if (show_version) {
104 		printf("%s\n", LINKPOLICY_VERSION);
105 		exit(0);
106 	}
107 
108 	/* check args */
109 	if (argc < 3 || !(optind != (argc - 1))) {
110 		fprintf(stderr,
111 			"%s:  You must provide the base module package and at least one other module package\n",
112 			argv[0]);
113 		usage(argv[0]);
114 	}
115 
116 	basename = argv[optind++];
117 	base = load_module(basename);
118 	if (!base) {
119 		fprintf(stderr,
120 			"%s:  Could not load base module from file %s\n",
121 			argv[0], basename);
122 		exit(1);
123 	}
124 
125 	num_mods = argc - optind;
126 	mods =
127 	    (sepol_module_package_t **) malloc(sizeof(sepol_module_package_t *)
128 					       * num_mods);
129 	if (!mods) {
130 		fprintf(stderr, "%s:  Out of memory\n", argv[0]);
131 		exit(1);
132 	}
133 	memset(mods, 0, sizeof(sepol_module_package_t *) * num_mods);
134 
135 	for (i = 0; optind < argc; optind++, i++) {
136 		mods[i] = load_module(argv[optind]);
137 		if (!mods[i]) {
138 			fprintf(stderr,
139 				"%s:  Could not load module from file %s\n",
140 				argv[0], argv[optind]);
141 			exit(1);
142 		}
143 	}
144 
145 	if (sepol_link_packages(NULL, base, mods, num_mods, verbose)) {
146 		fprintf(stderr, "%s:  Error while linking packages\n", argv[0]);
147 		exit(1);
148 	}
149 
150 	if (outname) {
151 		outfile = fopen(outname, "w");
152 		if (!outfile) {
153 			perror(outname);
154 			exit(1);
155 		}
156 
157 		if (sepol_policy_file_create(&pf)) {
158 			fprintf(stderr, "%s:  Out of memory\n", argv[0]);
159 			exit(1);
160 		}
161 		sepol_policy_file_set_fp(pf, outfile);
162 		if (sepol_module_package_write(base, pf)) {
163 			fprintf(stderr, "%s:  Error writing linked package.\n",
164 				argv[0]);
165 			exit(1);
166 		}
167 		sepol_policy_file_free(pf);
168 		fclose(outfile);
169 	}
170 
171 	sepol_module_package_free(base);
172 	for (i = 0; i < num_mods; i++)
173 		sepol_module_package_free(mods[i]);
174 	free(mods);
175 	exit(0);
176 }
No issues found
  1 /* Authors: Karl MacMillan <kmacmillan@tresys.com>
  2  *
  3  * Copyright (C) 2004 Tresys Technology, LLC
  4  *	This program is free software; you can redistribute it and/or modify
  5  *  	it under the terms of the GNU General Public License as published by
  6  *	the Free Software Foundation, version 2.
  7  */
  8 
  9 #include <sepol/module.h>
 10 #include <getopt.h>
 11 #include <fcntl.h>
 12 #include <stdio.h>
 13 #include <stdlib.h>
 14 #include <string.h>
 15 #include <unistd.h>
 16 #include <sys/types.h>
 17 #include <sys/stat.h>
 18 #include <sys/mman.h>
 19 #include <fcntl.h>
 20 #include <errno.h>
 21 
 22 char *progname = NULL;
 23 extern char *optarg;
 24 
 25 static void usage(char *prog)
 26 {
 27 	printf("usage: %s -o <output file> -m <module> [-f <file contexts>]\n",
 28 	       prog);
 29 	printf("Options:\n");
 30 	printf("  -o --outfile		Output file (required)\n");
 31 	printf("  -m --module		Module file (required)\n");
 32 	printf("  -f --fc		File contexts file\n");
 33 	printf("  -s --seuser		Seusers file (only valid in base)\n");
 34 	printf
 35 	    ("  -u --user_extra	user_extra file (only valid in base)\n");
 36 	printf("  -n --nc		Netfilter contexts file\n");
 37 	exit(1);
 38 }
 39 
 40 static int file_to_policy_file(char *filename, struct sepol_policy_file **pf,
 41 			       char *mode)
 42 {
 43 	FILE *f;
 44 
 45 	if (sepol_policy_file_create(pf)) {
 46 		fprintf(stderr, "%s:  Out of memory\n", progname);
 47 		return -1;
 48 	}
 49 
 50 	f = fopen(filename, mode);
 51 	if (!f) {
 52 		fprintf(stderr, "%s:  Could not open file %s:  %s\n", progname,
 53 			strerror(errno), filename);
 54 		return -1;
 55 	}
 56 	sepol_policy_file_set_fp(*pf, f);
 57 	return 0;
 58 }
 59 
 60 static int file_to_data(const char *path, char **data, size_t * len)
 61 {
 62 	int fd;
 63 	struct stat sb;
 64 	fd = open(path, O_RDONLY);
 65 	if (fd < 0) {
 66 		fprintf(stderr, "%s:  Failed to open %s:  %s\n", progname, path,
 67 			strerror(errno));
 68 		return -1;
 69 	}
 70 	if (fstat(fd, &sb) < 0) {
 71 		fprintf(stderr, "%s:  Failed to fstat %s:  %s\n", progname,
 72 			path, strerror(errno));
 73 		goto err;
 74 	}
 75 
 76 	*data = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
 77 	if (*data == MAP_FAILED) {
 78 		fprintf(stderr, "%s:  Failed to mmap %s:  %s\n", progname, path,
 79 			strerror(errno));
 80 		goto err;
 81 	}
 82 	*len = sb.st_size;
 83 	close(fd);
 84 	return 0;
 85       err:
 86 	close(fd);
 87 	return -1;
 88 }
 89 
 90 int main(int argc, char **argv)
 91 {
 92 	struct sepol_module_package *pkg;
 93 	struct sepol_policy_file *mod, *out;
 94 	char *module = NULL, *file_contexts = NULL, *seusers =
 95 	    NULL, *user_extra = NULL;
 96 	char *fcdata = NULL, *outfile = NULL, *seusersdata =
 97 	    NULL, *user_extradata = NULL;
 98 	char *netfilter_contexts = NULL, *ncdata = NULL;
 99 	size_t fclen = 0, seuserslen = 0, user_extralen = 0, nclen = 0;
100 	int i;
101 
102 	static struct option opts[] = {
103 		{"module", required_argument, NULL, 'm'},
104 		{"fc", required_argument, NULL, 'f'},
105 		{"seuser", required_argument, NULL, 's'},
106 		{"user_extra", required_argument, NULL, 'u'},
107 		{"nc", required_argument, NULL, 'n'},
108 		{"outfile", required_argument, NULL, 'o'},
109 		{"help", 0, NULL, 'h'},
110 		{NULL, 0, NULL, 0}
111 	};
112 
113 	while ((i = getopt_long(argc, argv, "m:f:s:u:o:n:h", opts, NULL)) != -1) {
114 		switch (i) {
115 		case 'h':
116 			usage(argv[0]);
117 			exit(0);
118 		case 'm':
119 			if (module) {
120 				fprintf(stderr,
121 					"May not specify more than one module\n");
122 				exit(1);
123 			}
124 			module = strdup(optarg);
125 			if (!module)
126 				exit(1);
127 			break;
128 		case 'f':
129 			if (file_contexts) {
130 				fprintf(stderr,
131 					"May not specify more than one file context file\n");
132 				exit(1);
133 			}
134 			file_contexts = strdup(optarg);
135 			if (!file_contexts)
136 				exit(1);
137 			break;
138 		case 'o':
139 			if (outfile) {
140 				fprintf(stderr,
141 					"May not specify more than one output file\n");
142 				exit(1);
143 			}
144 			outfile = strdup(optarg);
145 			if (!outfile)
146 				exit(1);
147 			break;
148 		case 's':
149 			if (seusers) {
150 				fprintf(stderr,
151 					"May not specify more than one seuser file\n");
152 				exit(1);
153 			}
154 			seusers = strdup(optarg);
155 			if (!seusers)
156 				exit(1);
157 			break;
158 		case 'u':
159 			if (user_extra) {
160 				fprintf(stderr,
161 					"May not specify more than one user_extra file\n");
162 				exit(1);
163 			}
164 			user_extra = strdup(optarg);
165 			if (!user_extra)
166 				exit(1);
167 			break;
168 		case 'n':
169 			if (netfilter_contexts) {
170 				fprintf(stderr,
171 					"May not specify more than one netfilter contexts file\n");
172 				exit(1);
173 			}
174 			netfilter_contexts = strdup(optarg);
175 			if (!netfilter_contexts)
176 				exit(1);
177 			break;
178 		}
179 	}
180 
181 	progname = argv[0];
182 
183 	if (!module || !outfile) {
184 		usage(argv[0]);
185 		exit(0);
186 	}
187 
188 	if (file_contexts) {
189 		if (file_to_data(file_contexts, &fcdata, &fclen))
190 			exit(1);
191 	}
192 
193 	if (seusers) {
194 		if (file_to_data(seusers, &seusersdata, &seuserslen))
195 			exit(1);
196 	}
197 
198 	if (user_extra) {
199 		if (file_to_data(user_extra, &user_extradata, &user_extralen))
200 			exit(1);
201 	}
202 
203 	if (netfilter_contexts) {
204 		if (file_to_data(netfilter_contexts, &ncdata, &nclen))
205 			exit(1);
206 	}
207 
208 	if (file_to_policy_file(module, &mod, "r"))
209 		exit(1);
210 
211 	if (sepol_module_package_create(&pkg)) {
212 		fprintf(stderr, "%s:  Out of memory\n", argv[0]);
213 		exit(1);
214 	}
215 
216 	if (sepol_policydb_read(sepol_module_package_get_policy(pkg), mod)) {
217 		fprintf(stderr,
218 			"%s:  Error while reading policy module from %s\n",
219 			argv[0], module);
220 		exit(1);
221 	}
222 
223 	if (fclen)
224 		sepol_module_package_set_file_contexts(pkg, fcdata, fclen);
225 
226 	if (seuserslen)
227 		sepol_module_package_set_seusers(pkg, seusersdata, seuserslen);
228 
229 	if (user_extra)
230 		sepol_module_package_set_user_extra(pkg, user_extradata,
231 						    user_extralen);
232 
233 	if (nclen)
234 		sepol_module_package_set_netfilter_contexts(pkg, ncdata, nclen);
235 
236 	if (file_to_policy_file(outfile, &out, "w"))
237 		exit(1);
238 
239 	if (sepol_module_package_write(pkg, out)) {
240 		fprintf(stderr,
241 			"%s:  Error while writing module package to %s\n",
242 			argv[0], argv[1]);
243 		exit(1);
244 	}
245 
246 	if (fclen)
247 		munmap(fcdata, fclen);
248 	if (nclen)
249 		munmap(ncdata, nclen);
250 	sepol_policy_file_free(mod);
251 	sepol_policy_file_free(out);
252 	sepol_module_package_free(pkg);
253 	free(file_contexts);
254 	free(outfile);
255 	free(module);
256 	exit(0);
257 }
No issues found
  1 #include <sepol/module.h>
  2 #include <getopt.h>
  3 #include <fcntl.h>
  4 #include <stdio.h>
  5 #include <stdlib.h>
  6 #include <string.h>
  7 #include <unistd.h>
  8 #include <sys/types.h>
  9 #include <sys/stat.h>
 10 #include <sys/mman.h>
 11 #include <fcntl.h>
 12 #include <errno.h>
 13 
 14 char *progname = NULL;
 15 extern char *optarg;
 16 
 17 static void usage(char *progname)
 18 {
 19 	printf("usage: %s ppfile modfile [fcfile]\n", progname);
 20 	exit(1);
 21 }
 22 
 23 static int file_to_policy_file(char *filename, struct sepol_policy_file **pf, char *mode)
 24 {
 25 	FILE *f;
 26 
 27 	if (sepol_policy_file_create(pf)) {
 28 		fprintf(stderr, "%s:  Out of memory\n", progname);
 29 		return -1;
 30 	}
 31 
 32 	f = fopen(filename, mode);
 33 	if (!f) {
 34 		fprintf(stderr, "%s:  Could not open file %s:  %s\n", progname, strerror(errno), filename);
 35 		return -1;
 36 	}
 37 	sepol_policy_file_set_fp(*pf, f);
 38 	return 0;
 39 }
 40 
 41 int main(int argc, char **argv)
 42 {
 43 	struct sepol_module_package *pkg;
 44 	struct sepol_policy_file *in, *out;
 45 	FILE *fp;
 46 	size_t len;
 47 	char *ppfile, *modfile, *fcfile = NULL, *fcdata;
 48 
 49 	progname = argv[0];
 50 
 51 	if (argc < 3) {
 52 		usage(progname);
 53 		exit(1);
 54 	}
 55 
 56 	ppfile = argv[1];
 57 	modfile = argv[2];
 58 	if (argc >= 3)
 59 		fcfile = argv[3];
 60 
 61 	if (file_to_policy_file(ppfile, &in, "r"))
 62 		exit(1);
 63 
 64 	if (sepol_module_package_create(&pkg)) {
 65                 fprintf(stderr, "%s:  Out of memory\n", progname);
 66                 exit(1);
 67 	}
 68 
 69 	if (sepol_module_package_read(pkg, in, 0) == -1) {
 70                 fprintf(stderr, "%s:  Error while reading policy module from %s\n",
 71 			progname, ppfile);
 72                 exit(1);
 73 	}
 74 
 75 	if (file_to_policy_file(modfile, &out, "w"))
 76 		exit(1);
 77 
 78         if (sepol_policydb_write(sepol_module_package_get_policy(pkg), out)) {
 79                 fprintf(stderr, "%s:  Error while writing module to %s\n", progname, modfile);
 80                 exit(1);
 81         }
 82 
 83 	sepol_policy_file_free(in);
 84 	sepol_policy_file_free(out);
 85 
 86 	len = sepol_module_package_get_file_contexts_len(pkg);
 87 	if (fcfile && len) {
 88 		fp = fopen(fcfile, "w");
 89 		if (!fp) {
 90 			fprintf(stderr, "%s:  Could not open file %s:  %s\n", progname, strerror(errno), fcfile);
 91 			exit(1);
 92 		}
 93 		fcdata = sepol_module_package_get_file_contexts(pkg);
 94 		if (fwrite(fcdata, 1, len, fp) != len) {
 95 			fprintf(stderr, "%s:  Could not write file %s:  %s\n", progname, strerror(errno), fcfile);
 96 			exit(1);
 97 		}
 98 		fclose(fp);
 99 	}
100 
101 	sepol_module_package_free(pkg);
102 	exit(0);
103 }
No issues found
  1 /* Authors: Frank Mayer <mayerf@tresys.com>
  2  *   and Karl MacMillan <kmacmillan@tresys.com>
  3  *
  4  * Copyright (C) 2003,2010 Tresys Technology, LLC
  5  *
  6  *	This program is free software; you can redistribute it and/or
  7  *  	modify it under the terms of the GNU General Public License as
  8  *  	published by the Free Software Foundation, version 2.
  9  *
 10  * Adapted from dispol.c.
 11  *
 12  * This program is used by sepolgen-ifgen to get the access for all of
 13  * the attributes in the policy so that it can resolve the
 14  * typeattribute statements in the interfaces.
 15  *
 16  * It outputs the attribute access in a similar format to what sepolgen
 17  * uses to store interface vectors:
 18  *   [Attribute sandbox_x_domain]
 19  *   sandbox_x_domain,samba_var_t,file,ioctl,read,getattr,lock,open
 20  *   sandbox_x_domain,samba_var_t,dir,getattr,search,open
 21  *   sandbox_x_domain,initrc_var_run_t,file,ioctl,read,getattr,lock,open
 22  *
 23  */
 24 
 25 #include <sepol/policydb/policydb.h>
 26 #include <sepol/policydb/avtab.h>
 27 #include <sepol/policydb/util.h>
 28 
 29 #include <stdio.h>
 30 #include <sys/types.h>
 31 #include <sys/stat.h>
 32 #include <fcntl.h>
 33 #include <sys/mman.h>
 34 #include <unistd.h>
 35 
 36 struct val_to_name {
 37 	unsigned int val;
 38 	char *name;
 39 };
 40 
 41 static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
 42 {
 43 	struct val_to_name *v = data;
 44 	perm_datum_t *perdatum;
 45 
 46 	perdatum = (perm_datum_t *) datum;
 47 
 48 	if (v->val == perdatum->s.value) {
 49 		v->name = key;
 50 		return 1;
 51 	}
 52 
 53 	return 0;
 54 }
 55 
 56 int render_access_mask(uint32_t av, avtab_key_t *key, policydb_t *policydbp,
 57 		       FILE *fp)
 58 {
 59 	struct val_to_name v;
 60 	class_datum_t *cladatum;
 61 	char *perm = NULL;
 62 	unsigned int i;
 63 	int rc;
 64 	uint32_t tclass = key->target_class;
 65 
 66 	cladatum = policydbp->class_val_to_struct[tclass - 1];
 67 	for (i = 0; i < cladatum->permissions.nprim; i++) {
 68 		if (av & (1 << i)) {
 69 			v.val = i + 1;
 70 			rc = hashtab_map(cladatum->permissions.table,
 71 					 perm_name, &v);
 72 			if (!rc && cladatum->comdatum) {
 73 				rc = hashtab_map(cladatum->comdatum->
 74 						 permissions.table, perm_name,
 75 						 &v);
 76 			}
 77 			if (rc)
 78 				perm = v.name;
 79 			if (perm) {
 80 				fprintf(fp, ",%s", perm);
 81 			}
 82 		}
 83 	}
 84 
 85 	return 0;
 86 }
 87 
 88 static int render_key(avtab_key_t *key, policydb_t *p, FILE *fp)
 89 {
 90 	char *stype, *ttype, *tclass;
 91 	stype = p->p_type_val_to_name[key->source_type - 1];
 92 	ttype = p->p_type_val_to_name[key->target_type - 1];
 93 	tclass = p->p_class_val_to_name[key->target_class - 1];
 94 	if (stype && ttype) {
 95 		fprintf(fp, "%s,%s,%s", stype, ttype, tclass);
 96 	} else {
 97 		fprintf(stderr, "error rendering key\n");
 98 		exit(1);
 99 	}
100 
101 	return 0;
102 }
103 
104 struct callback_data
105 {
106 	uint32_t attr;
107 	policydb_t *policy;
108 	FILE *fp;
109 };
110 
111 int output_avrule(avtab_key_t *key, avtab_datum_t *datum, void *args)
112 {
113 	struct callback_data *cb_data = (struct callback_data *)args;
114 
115 	if (key->source_type != cb_data->attr)
116 		return 0;
117 
118 	if (!(key->specified & AVTAB_AV && key->specified & AVTAB_ALLOWED))
119 		return 0;
120 
121 	render_key(key, cb_data->policy, cb_data->fp);
122 	render_access_mask(datum->data, key, cb_data->policy, cb_data->fp);
123 	fprintf(cb_data->fp, "\n");
124 
125 	return 0;
126 }
127 
128 static int attribute_callback(hashtab_key_t key, hashtab_datum_t datum, void *datap)
129 {
130 	struct callback_data *cb_data = (struct callback_data *)datap;
131 	type_datum_t *t = (type_datum_t *)datum;
132 
133 	if (t->flavor == TYPE_ATTRIB) {
134 		fprintf(cb_data->fp, "[Attribute %s]\n", key);
135 		cb_data->attr = t->s.value;
136 		if (avtab_map(&cb_data->policy->te_avtab, output_avrule, cb_data) < 0)
137 			return -1;
138 		if (avtab_map(&cb_data->policy->te_cond_avtab, output_avrule, cb_data) < 0)
139 			return -1;
140 	}
141 
142 	return 0;
143 }
144 
145 static policydb_t *load_policy(const char *filename)
146 {
147 	policydb_t *policydb;
148 	struct policy_file pf;
149 	FILE *fp;
150 	int ret;
151 
152 	fp = fopen(filename, "r");
153 	if (fp == NULL) {
154 		fprintf(stderr, "Can't open '%s':  %s\n",
155 			filename, strerror(errno));
156 		return NULL;
157 	}
158 
159 	policy_file_init(&pf);
160 	pf.type = PF_USE_STDIO;
161 	pf.fp = fp;
162 
163 	policydb = malloc(sizeof(policydb_t));
164 	if (policydb == NULL) {
165 		fprintf(stderr, "Out of memory!\n");
166 		return NULL;
167 	}
168 
169 	if (policydb_init(policydb)) {
170 		fprintf(stderr, "Out of memory!\n");
171 		free(policydb);
172 		return NULL;
173 	}
174 
175 	ret = policydb_read(policydb, &pf, 1);
176 	if (ret) {
177 		fprintf(stderr,
178 			"error(s) encountered while parsing configuration\n");
179 		free(policydb);
180 		return NULL;
181 	}
182 
183 	fclose(fp);
184 
185 	return policydb;
186 
187 }
188 
189 void usage(char *progname)
190 {
191 	printf("usage: %s policy_file out_file\n", progname);
192 }
193 
194 int main(int argc, char **argv)
195 {
196 	policydb_t *p;
197 	struct callback_data cb_data;
198 	FILE *fp;
199 
200 	if (argc != 3) {
201 		usage(argv[0]);
202 		return -1;
203 	}
204 
205 	/* Open the policy. */
206 	p = load_policy(argv[1]);
207 	if (p == NULL)
208 		return -1;
209 
210 	/* Open the output policy. */
211 	fp = fopen(argv[2], "w");
212 	if (fp == NULL) {
213 		fprintf(stderr, "error opening output file\n");
214 		policydb_destroy(p);
215 		free(p);
216 		return -1;
217 	}
218 
219 	/* Find all of the attributes and output their access. */
220 	cb_data.policy = p;
221 	cb_data.fp = fp;
222 
223 	if (hashtab_map(p->p_types.table, attribute_callback, &cb_data)) {
224 		printf("error finding attributes\n");
225 	}
226 
227 	policydb_destroy(p);
228 	free(p);
229 	fclose(fp);
230 
231 	return 0;
232 }
| Location | Tool | Test ID | Issue | |
|---|---|---|---|---|
| common.h:22:1 | cpychecker | refcount-too-high | py_append_string | ob_refcnt of '*obj' is 1 too high | 
| common.h:22:1 | cpychecker | refcount-too-high | py_append_string | ob_refcnt of '*obj' is 1 too high | 
| common.h:30:1 | cpychecker | refcount-too-high | py_append_obj | ob_refcnt of '*obj' is 1 too high | 
| common.h:30:1 | cpychecker | refcount-too-high | py_append_obj | ob_refcnt of '*obj' is 1 too high | 
 1 #include "Python.h"
 2 
 3 #ifdef UNUSED
 4 #elif defined(__GNUC__)
 5 # define UNUSED(x) UNUSED_ ## x __attribute__((unused))
 6 #elif defined(__LCLINT__)
 7 # define UNUSED(x) /*@unused@*/ x
 8 #else
 9 # define UNUSED(x) x
10 #endif
11 
12 #define py_decref(x) { if (x) 	Py_DECREF(x); }
13 
14 static int py_append_string(PyObject *list, const char* value)
15 {
16 	int rt;
17 	PyObject *obj = PyString_FromString(value);
18 	if (!obj) return -1;
19 	rt = PyList_Append(list, obj);
20 	Py_DECREF(obj);
21 	return rt;
22 }
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
23 
24 static int py_append_obj(PyObject *list, PyObject *obj)
25 {
26 	int rt;
27 	if (!obj) return -1;
28 	rt = PyList_Append(list, obj);
29 	return rt;
30 }
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
31 
32 static int py_insert_obj(PyObject *dict, const char *name, PyObject *obj)
33 {
34 	int rt;
35 	if (!obj) return -1;
36 	rt = PyDict_SetItemString(dict, name, obj);
37 	return rt;
38 }
39 
40 static int py_insert_string(PyObject *dict, const char *name, const char* value)
41 {
42 	int rt;
43 	PyObject *obj = PyString_FromString(value);
44 	if (!obj) return -1;
45 	rt = PyDict_SetItemString(dict, name, obj);
46 	Py_DECREF(obj);
47 	return rt;
48 }
| Location | Tool | Test ID | Issue | |
|---|---|---|---|---|
| info.c:875:2 | cpychecker | returns-NULL-without-setting-exception | info | returning (PyObject*)NULL without setting an exception | 
| info.c:882:26 | cpychecker | mismatching-type-in-format-string | wrap_info | Mismatching type in call to PyArg_ParseTuple with format code "iz" | 
| info.c:882:26 | cpychecker | mismatching-type-in-format-string | wrap_info | Mismatching type in call to PyArg_ParseTuple with format code "iz" | 
| info.c:886:1 | cpychecker | refcount-too-high | wrap_info | ob_refcnt of new ref from (unknown) info is 1 too high | 
  1 /**
  2  *  @file
  3  *  Command line tool to search TE rules.
  4  *
  5  *  @author Frank Mayer  mayerf@tresys.com
  6  *  @author Jeremy A. Mowery jmowery@tresys.com
  7  *  @author Paul Rosenfeld  prosenfeld@tresys.com
  8  *  @author Thomas Liu  <tliu@redhat.com>
  9  *  @author Dan Walsh  <dwalsh@redhat.com>
 10  *
 11  *  Copyright (C) 2003-2008 Tresys Technology, LLC
 12  *
 13  *  This program is free software; you can redistribute it and/or modify
 14  *  it under the terms of the GNU General Public License as published by
 15  *  the Free Software Foundation; either version 2 of the License, or
 16  *  (at your option) any later version.
 17  *
 18  *  This program is distributed in the hope that it will be useful,
 19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 21  *  GNU General Public License for more details.
 22  *
 23  *  You should have received a copy of the GNU General Public License
 24  *  along with this program; if not, write to the Free Software
 25  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 26  */
 27 
 28 /**
 29  * This is a modified version of seinfo to be used as part of a library for
 30  * Python bindings.
 31  */
 32 
 33 #include "common.h"
 34 #include "policy.h"
 35 
 36 /* libapol */
 37 #include <apol/policy-query.h>
 38 #include <apol/render.h>
 39 #include <apol/util.h>
 40 #include <apol/vector.h>
 41 
 42 /* libqpol */
 43 #include <qpol/policy.h>
 44 #include <qpol/util.h>
 45 
 46 /* other */
 47 #include <errno.h>
 48 #include <stdlib.h>
 49 #include <stdio.h>
 50 #include <string.h>
 51 #include <assert.h>
 52 
 53 #define COPYRIGHT_INFO "Copyright (C) 2003-2007 Tresys Technology, LLC"
 54 
 55 enum input
 56 {
 57 	TYPE, ATTRIBUTE, ROLE, USER, PORT, BOOLEAN,
 58 };
 59 
 60 static int py_insert_long(PyObject *dict, const char *name, int value)
 61 {
 62 	int rt;
 63 	PyObject *obj = PyInt_FromLong(value);
 64 	if (!obj) return -1;
 65 	rt = PyDict_SetItemString(dict, name, obj);
 66 	Py_DECREF(obj);
 67 	return rt;
 68 }
 69 
 70 static int py_insert_bool(PyObject *dict, const char *name, int value)
 71 {
 72 	int rt;
 73 	PyObject *obj = PyBool_FromLong(value);
 74 	if (!obj) return -1;
 75 	rt = PyDict_SetItemString(dict, name, obj);
 76 	Py_DECREF(obj);
 77 	return rt;
 78 }
 79 
 80 /**
 81  * Gets a textual representation of an attribute, and 
 82  * all of that attribute's types.
 83  *
 84  * @param type_datum Reference to sepol type_datum
 85  * @param policydb Reference to a policy
 86  */
 87 static PyObject* get_attr(const qpol_type_t * type_datum, const apol_policy_t * policydb)
 88 {
 89 	PyObject *list = NULL;
 90 	const qpol_type_t *attr_datum = NULL;
 91 	qpol_iterator_t *iter = NULL;
 92 	const char *attr_name = NULL, *type_name = NULL;
 93 	qpol_policy_t *q = apol_policy_get_qpol(policydb);
 94 	unsigned char isattr;
 95 	int error = 0;
 96 	int rt = 0;
 97 	PyObject *dict = PyDict_New(); 
 98 	if (!dict) goto err;
 99 
100 	if (qpol_type_get_name(q, type_datum, &attr_name))
101 		goto err;
102 
103 	if (py_insert_string(dict, "name", attr_name))
104 		goto err;
105 
106 	/* get an iterator over all types this attribute has */
107 	if (qpol_type_get_isattr(q, type_datum, &isattr))
108 		goto err;
109 
110 	if (isattr) {	       /* sanity check */
111 		if (qpol_type_get_type_iter(q, type_datum, &iter))
112 			goto err;
113 		list = PyList_New(0);
114 		if (!list) goto err;
115 		
116 		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
117 			if (qpol_iterator_get_item(iter, (void **)&attr_datum))
118 				goto err;
119 			if (qpol_type_get_name(q, attr_datum, &type_name))
120 				goto err;
121 			if (py_append_string(list, type_name))
122 				goto err;
123 		}
124 		qpol_iterator_destroy(&iter);
125 		rt = PyDict_SetItemString(dict, "types", list);
126 		Py_DECREF(list); list = NULL;
127 		if (rt) goto err;
128 	} else		       /* this should never happen */
129 		goto err;
130 	goto cleanup;
131 
132 err:
133 	error = errno;
134 	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
135 	py_decref(dict); dict = NULL;
136 	py_decref(list);
137 
138 cleanup:
139 	qpol_iterator_destroy(&iter);
140 	errno =	error;
141 	return dict;
142 }
143 
144 /**
145  * Gets statistics regarding a policy's attributes.
146  * If this function is given a name, it will attempt to
147  * get statistics about a particular attribute; otherwise
148  * the function gets statistics about all of the policy's
149  * attributes.
150  *
151  * @param name Reference to an attribute's name; if NULL,
152  * all object classes will be considered
153  * @param policydb Reference to a policy
154  *
155  * @return 0 on success, < 0 on error.
156  */
157 static PyObject* get_attribs(const char *name, const apol_policy_t * policydb)
158 {
159 	PyObject *obj;
160 	apol_attr_query_t *attr_query = NULL;
161 	apol_vector_t *v = NULL;
162 	const qpol_type_t *type_datum = NULL;
163 	size_t n_attrs, i;
164 	int error = 0;
165 	int rt = 0;
166 	PyObject *list = PyList_New(0);
167 	if (!list) goto err;
168 
169 	/* we are only getting information about 1 attribute */
170 	if (name != NULL) {
171 		attr_query = apol_attr_query_create();
172 		if (!attr_query)
173 			goto err;
174 		if (apol_attr_query_set_attr(policydb, attr_query, name))
175 			goto err;
176 		if (apol_attr_get_by_query(policydb, attr_query, &v))
177 			goto err;
178 		apol_attr_query_destroy(&attr_query);
179 		if (apol_vector_get_size(v) == 0) {
180 			apol_vector_destroy(&v);
181 			errno = EINVAL;
182 			goto err;
183 		}
184 
185 		type_datum = apol_vector_get_element(v, (size_t) 0);
186 		obj = get_attr(type_datum, policydb);
187 		rt = py_append_obj(list, obj);
188 		Py_DECREF(obj);
189 		if (rt) goto err;
190 	} else {
191 		attr_query = apol_attr_query_create();
192 		if (!attr_query)
193 			goto err;
194 		if (apol_attr_get_by_query(policydb, attr_query, &v))
195 			goto err;
196 		apol_attr_query_destroy(&attr_query);
197 		n_attrs = apol_vector_get_size(v);
198 
199 		for (i = 0; i < n_attrs; i++) {
200 			/* get qpol_type_t* item from vector */
201 			type_datum = (qpol_type_t *) apol_vector_get_element(v, (size_t) i);
202 			if (!type_datum)
203 				goto err;
204 			obj = get_attr(type_datum, policydb);
205 			rt = py_append_obj(list, obj);
206 			Py_DECREF(obj);
207 			if (rt) goto err;
208 		}
209 	}
210 	apol_vector_destroy(&v);
211 	goto cleanup;
212 
213 err:
214 	error = errno;
215 	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
216 	py_decref(list); list = NULL;
217 
218 cleanup:
219 	apol_attr_query_destroy(&attr_query);
220 	apol_vector_destroy(&v);
221 	errno = error;
222 	return list;
223 }
224 
225 /**
226  * Get a textual representation of a type, and
227  * all of that type's attributes.
228  *
229  * @param type_datum Reference to sepol type_datum
230  * @param policydb Reference to a policy
231  */
232 static PyObject* get_type_attrs(const qpol_type_t * type_datum, const apol_policy_t * policydb)
233 {
234 	qpol_iterator_t *iter = NULL;
235 	const char *attr_name = NULL;
236 	const qpol_type_t *attr_datum = NULL;
237 	qpol_policy_t *q = apol_policy_get_qpol(policydb);
238 	int error = 0;
239 	PyObject *list = PyList_New(0);
240 	if (!list) goto err;
241 
242 	if (qpol_type_get_attr_iter(q, type_datum, &iter))
243 		goto err;
244 
245 	for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
246 		if (qpol_iterator_get_item(iter, (void **)&attr_datum))
247 			goto err;
248 		if (qpol_type_get_name(q, attr_datum, &attr_name))
249 			goto err;
250 		if (py_append_string(list, attr_name))
251 			goto err;
252 	}
253 	goto cleanup;
254 
255 err:
256 	error = errno;
257 	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
258 	py_decref(list); list = NULL;
259 
260 cleanup:
261 	qpol_iterator_destroy(&iter);
262 	errno = error;
263 	return list;
264 }
265 
266 static PyObject* get_type( const qpol_type_t * type_datum, const apol_policy_t * policydb) {
267 
268 	PyObject *obj;
269 	qpol_policy_t *q = apol_policy_get_qpol(policydb);
270 	const char *type_name = NULL;
271 	int error = 0;
272 	int rt;
273 	unsigned char isalias, ispermissive, isattr;
274 	PyObject *dict = PyDict_New(); 
275 	if (!dict) goto err;
276 
277 	if (qpol_type_get_name(q, type_datum, &type_name))
278 		goto err;
279 	if (qpol_type_get_isalias(q, type_datum, &isalias))
280 		goto err;
281 	if (qpol_type_get_isattr(q, type_datum, &isattr))
282 		goto err;
283 	if (qpol_type_get_ispermissive(q, type_datum, &ispermissive))
284 		goto err;
285 
286 	if (py_insert_string(dict, "name", type_name))
287 		goto err;
288 
289 	if (py_insert_bool(dict, "permissive", ispermissive))
290 		goto err;
291 
292 	if (!isattr && !isalias) {
293 		obj = get_type_attrs(type_datum, policydb);
294 		rt = py_insert_obj(dict, "attributes", obj);
295 		Py_DECREF(obj);
296 		if (rt) goto err;
297 	}
298 	goto cleanup;
299 
300 err:
301 	error = errno;
302 	PyErr_SetString(PyExc_RuntimeError,strerror(error));
303 	py_decref(dict); dict = NULL;
304 
305 cleanup:
306 	errno = error; 
307 	return dict;
308 }
309 
310 /**
311  * Gets statistics regarding a policy's booleans.
312  * If this function is given a name, it will attempt to
313  * get statistics about a particular boolean; otherwise
314  * the function gets statistics about all of the policy's booleans.
315  *
316  * @param fp Reference to a file to which to print statistics
317  * @param name Reference to a boolean's name; if NULL,
318  * all booleans will be considered
319  * @param expand Flag indicating whether to print each
320  * boolean's default state
321  * @param policydb Reference to a policy
322  *
323  * @return new reference, or NULL (setting an exception)
324  */
325 static PyObject* get_booleans(const char *name, const apol_policy_t * policydb)
326 {
327 	PyObject *dict = NULL;
328 	int error = 0;
329 	int rt = 0;
330 	const char *bool_name = NULL;
331 	int state;
332 	qpol_bool_t *bool_datum = NULL;
333 	qpol_iterator_t *iter = NULL;
334 	qpol_policy_t *q = apol_policy_get_qpol(policydb);
335 	size_t n_bools = 0;
336 	PyObject *list = PyList_New(0);
337 	if (!list) goto err;
338 
339 	if (name != NULL) {
340 		if (qpol_policy_get_bool_by_name(q, name, &bool_datum))
341 			goto err;
342 		if (qpol_bool_get_state(q, bool_datum, &state))
343 			goto err;
344 
345 		dict = PyDict_New(); 
346 		if (!dict) goto err;
347 		if (py_insert_string(dict, "name", name))
348 			goto err;
349 		if (py_insert_bool(dict, "name", state))
350 			goto err;
351 		rt = py_append_obj(list, dict);
352 		Py_DECREF(dict); dict = NULL;
353 		if (rt) goto err;
354 	} else {
355 		if (qpol_policy_get_bool_iter(q, &iter))
356 			goto err;
357 		if (qpol_iterator_get_size(iter, &n_bools))
358 			goto err;
359 		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
360 			if (qpol_iterator_get_item(iter, (void **)&bool_datum))
361 				goto err;
362 			if (qpol_bool_get_name(q, bool_datum, &bool_name))
363 				goto err;
364 			if (qpol_bool_get_state(q, bool_datum, &state))
365 				goto err;
366 
367 			dict = PyDict_New(); 
368 			if (!dict) goto err;
369 			if (py_insert_string(dict, "name", bool_name))
370 				goto err;
371 			if (py_insert_bool(dict, "state", state))
372 				goto err;
373 			rt = py_append_obj(list, dict);
374 			Py_DECREF(dict); dict = NULL;
375 			if (rt) goto err;
376 		}
377 		qpol_iterator_destroy(&iter);
378 	}
379 	goto cleanup;
380 
381 err:
382 	error = errno;
383 	PyErr_SetString(PyExc_RuntimeError,strerror(error));
384 	py_decref(list); list = NULL;
385 	py_decref(dict); dict = NULL;
386 
387 cleanup:
388 	qpol_iterator_destroy(&iter);
389 	errno = error; 
390 	return list;
391 }
392 
393 /**
394  * Gets a textual representation of a user, and
395  * all of that user's roles.
396  *
397  * @param type_datum Reference to sepol type_datum
398  * @param policydb Reference to a policy
399  * roles
400  */
401 static PyObject* get_user(const qpol_user_t * user_datum, const apol_policy_t * policydb)
402 {
403 	int error = 0;
404 	int rt;
405 	const qpol_role_t *role_datum = NULL;
406 	qpol_iterator_t *iter = NULL;
407 	const qpol_mls_range_t *range = NULL;
408 	const qpol_mls_level_t *dflt_level = NULL;
409 	apol_mls_level_t *ap_lvl = NULL;
410 	apol_mls_range_t *ap_range = NULL;
411 	qpol_policy_t *q = apol_policy_get_qpol(policydb);
412 	char *tmp = NULL;
413 	const char *user_name, *role_name;
414 	PyObject *dict = NULL;
415 	PyObject *list = PyList_New(0);
416 	if (!list) goto err;
417 
418 	if (qpol_user_get_name(q, user_datum, &user_name))
419 		goto err;
420 
421 	dict = PyDict_New(); 
422 	if (!dict) goto err;
423 
424 	if (py_insert_string(dict, "name", user_name))
425 		goto err;
426 
427 	if (qpol_policy_has_capability(q, QPOL_CAP_MLS)) {
428 		if (qpol_user_get_dfltlevel(q, user_datum, &dflt_level))
429 			goto err;
430 		ap_lvl = apol_mls_level_create_from_qpol_mls_level(policydb, dflt_level);
431 		tmp = apol_mls_level_render(policydb, ap_lvl);
432 		if (!tmp) goto err;
433 		if (py_insert_string(dict, "level", tmp))
434 		    goto err;
435 		free(tmp); tmp = NULL;
436 
437 		if (qpol_user_get_range(q, user_datum, &range))
438 			goto err;
439 		ap_range = apol_mls_range_create_from_qpol_mls_range(policydb, range);
440 		tmp = apol_mls_range_render(policydb, ap_range);
441 		if (!tmp) goto err;
442 		if (py_insert_string(dict, "range", tmp))
443 		    goto err;
444 		free(tmp); tmp=NULL;
445 	}
446 	
447 	if (qpol_user_get_role_iter(q, user_datum, &iter))
448 		goto err;
449 	for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
450 		if (qpol_iterator_get_item(iter, (void **)&role_datum))
451 			goto err;
452 		if (qpol_role_get_name(q, role_datum, &role_name))
453 			goto err;
454 		if (py_append_string(list, role_name))
455 			goto err;
456 	}
457 
458 	rt = py_insert_obj(dict, "roles", list);
459 	Py_DECREF(list); list=NULL;
460 	if (rt) goto err;
461 	goto cleanup;
462 
463 err:
464 	error = errno;
465 	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
466 	py_decref(list); list=NULL;
467 	py_decref(dict); dict=NULL;
468 
469 cleanup:
470 	free(tmp);
471 	qpol_iterator_destroy(&iter);
472 	apol_mls_level_destroy(&ap_lvl);
473 	apol_mls_range_destroy(&ap_range);
474 	errno = error;
475 	return dict;
476 }
477 
478 /**
479  * Gets statistics regarding a policy's users.
480  * If this function is given a name, it will attempt to
481  * get statistics about a particular user; otherwise
482  * the function gets statistics about all of the policy's
483  * users.
484  *
485  * @param name Reference to a user's name; if NULL,
486  * all users will be considered
487  * @param policydb Reference to a policy
488  *
489  * @return 0 on success, < 0 on error.
490  */
491 static PyObject*  get_users(const char *name, const apol_policy_t * policydb)
492 {
493 	qpol_iterator_t *iter = NULL;
494 	const qpol_user_t *user_datum = NULL;
495 	qpol_policy_t *q = apol_policy_get_qpol(policydb);
496 	int error = 0;
497 	int rt;
498 	PyObject *obj;
499 	PyObject *list = PyList_New(0);
500 	if (!list) goto err;
501 
502 	if (name != NULL) {
503 		if (qpol_policy_get_user_by_name(q, name, &user_datum)) {
504 			errno = EINVAL;
505 			goto err;
506 		}
507 		obj = get_user(user_datum, policydb);
508 		rt = py_append_obj(list, obj);
509 		Py_DECREF(obj);
510 		if (rt) goto err;
511 	} else {
512 		if (qpol_policy_get_user_iter(q, &iter))
513 			goto err;
514 
515 		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
516 			if (qpol_iterator_get_item(iter, (void **)&user_datum))
517 				goto err;
518 			obj = get_user(user_datum, policydb);
519 			rt = py_append_obj(list, obj);
520 			Py_DECREF(obj);
521 			if (rt) goto err;
522 		}
523 		qpol_iterator_destroy(&iter);
524 	}
525 	goto cleanup;
526 
527 err:
528 	error = errno;
529 	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
530 	py_decref(list); list = NULL;
531 
532 cleanup:
533 	qpol_iterator_destroy(&iter);
534 	errno = error;
535 	return list;
536 }
537 
538 /**
539  * get a textual representation of a role, and 
540  * all of that role's types.
541  *
542  * @param type_datum Reference to sepol type_datum
543  * @param policydb Reference to a policy
544  * types
545  */
546 static PyObject* get_role(const qpol_role_t * role_datum, const apol_policy_t * policydb)
547 {
548 	const char *role_name = NULL, *type_name = NULL;
549 	const qpol_role_t *dom_datum = NULL;
550 	const qpol_type_t *type_datum = NULL;
551 	qpol_iterator_t *iter = NULL;
552 	qpol_policy_t *q = apol_policy_get_qpol(policydb);
553 	size_t n_dom = 0, n_types = 0;
554 	int error = 0;
555 	int rt;
556 	PyObject *list = NULL;
557 	PyObject *dict = PyDict_New();
558 	if (!dict) goto err;
559 
560 	if (qpol_role_get_name(q, role_datum, &role_name))
561 		goto err;
562 	if (py_insert_string(dict, "name", role_name))
563 		goto err;
564 
565 	if (qpol_role_get_dominate_iter(q, role_datum, &iter))
566 		goto err;
567 	if (qpol_iterator_get_size(iter, &n_dom))
568 		goto err;
569 	if ((int)n_dom > 0) {
570 		list = PyList_New(0);
571 		if (!list) goto err;
572 		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
573 			if (qpol_iterator_get_item(iter, (void **)&dom_datum))
574 				goto err;
575 			if (qpol_role_get_name(q, dom_datum, &role_name))
576 				goto err;
577 			if (py_append_string(list, role_name))
578 				goto err;
579 		}
580 		rt = py_insert_obj(dict, "roles", list);
581 		Py_DECREF(list); list = NULL;
582 		if (rt) goto err;
583 	}
584 	qpol_iterator_destroy(&iter);
585 	
586 	if (qpol_role_get_type_iter(q, role_datum, &iter))
587 		goto err;
588 	if (qpol_iterator_get_size(iter, &n_types))
589 		goto err;
590 	if ((int)n_types > 0) {
591 		list = PyList_New(0);
592 		if (!list) goto err;
593 		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
594 			if (qpol_iterator_get_item(iter, (void **)&type_datum))
595 				goto err;
596 			if (qpol_type_get_name(q, type_datum, &type_name))
597 				goto err;
598 			if (py_append_string(list, type_name))
599 				goto err;
600 		}
601 		rt = py_insert_obj(dict, "types", list);
602 		Py_DECREF(list); list = NULL;
603 		if (rt) goto err;
604 	}
605 	goto cleanup;
606 
607 err:
608 	error = errno;
609 	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
610 	py_decref(list); list = NULL;
611 	py_decref(dict); dict = NULL;
612 
613 cleanup:
614 	qpol_iterator_destroy(&iter);
615 	errno =	error;
616 	return dict;
617 }
618 
619 /**
620  * Get statistics regarding a policy's ports.
621  * If this function is given a name, it will attempt to
622  * get statistics about a particular port; otherwise
623  * the function get statistics about all of the policy's ports.
624  *
625  * @param name Reference to an port's name; if NULL,
626  * all ports will be considered
627  * @param policydb Reference to a policy
628  *
629  * @return 0 on success, < 0 on error.
630  */
631 static PyObject*  get_ports(const char *num, const apol_policy_t * policydb)
632 {
633 	const qpol_portcon_t *portcon = NULL;
634 	qpol_iterator_t *iter = NULL;
635 	uint16_t low_port, high_port;
636 	uint8_t ocon_proto;
637 	qpol_policy_t *q = apol_policy_get_qpol(policydb);
638 	const qpol_context_t *ctxt = NULL;
639 	const char *proto_str = NULL;
640 	const char *type = NULL;
641 	const apol_mls_range_t *range = NULL;
642 	char *range_str = NULL;
643 	apol_context_t *c = NULL;
644 	int error = 0;
645 	int rt = 0;
646 	PyObject *dict = NULL;
647 	PyObject *list = PyList_New(0);
648 	if (!list) goto err;
649 
650 	if (qpol_policy_get_portcon_iter(q, &iter))
651 		goto err;
652 
653 	for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
654 		if (qpol_iterator_get_item(iter, (void **)&portcon))
655 			goto err;
656 		if (qpol_portcon_get_low_port(q, portcon, &low_port))
657 			goto err;
658 		if (qpol_portcon_get_high_port(q, portcon, &high_port))
659 			goto err;
660 		if (qpol_portcon_get_protocol(q, portcon, &ocon_proto))
661 			goto err;
662 		if (num) {
663 			if (atoi(num) < low_port || atoi(num) > high_port)
664 				continue;
665 		}
666 
667 		if ((ocon_proto != IPPROTO_TCP) &&
668 		    (ocon_proto != IPPROTO_UDP)) 
669 			goto err;
670 
671 		if (qpol_portcon_get_context(q, portcon, &ctxt)) {
672 			PyErr_SetString(PyExc_RuntimeError, "Could not get for port context.");
673 			goto err;
674 		}
675 
676 		if ((proto_str = apol_protocol_to_str(ocon_proto)) == NULL) {
677 			PyErr_SetString(PyExc_RuntimeError, "Invalid protocol for port");
678 			goto err;
679 		}
680 
681 		if ((c = apol_context_create_from_qpol_context(policydb, ctxt)) == NULL) {
682 			goto err;
683 		}
684 		
685 		if((type = apol_context_get_type(c)) == NULL) {
686 			apol_context_destroy(&c);
687 			goto err;
688 		}
689 			
690 		dict = PyDict_New(); 
691 		if (!dict) goto err;
692 		if (py_insert_string(dict, "type", type))
693 			goto err;
694 
695 		if((range = apol_context_get_range(c)) == NULL) {
696 			goto err;
697 		}
698 			
699 		range_str = apol_mls_range_render(policydb, range);
700 		if (range_str == NULL) {
701 			goto err;
702 		}
703 		if (py_insert_string(dict, "range", range_str))
704 			goto err;
705 
706 		if (py_insert_string(dict, "protocol", proto_str))
707 			goto err;
708 
709 		if (py_insert_long(dict, "high", high_port))
710 			goto err;
711 
712 		if (py_insert_long(dict, "low", low_port))
713 			goto err;
714 
715 		rt = py_append_obj(list, dict);
716 		Py_DECREF(dict); dict = NULL;
717 		if (rt) goto err;
718 	}
719 	goto cleanup;
720 
721 err:
722 	error = errno;
723 	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
724 	py_decref(list); list = NULL;
725 	py_decref(dict); dict = NULL;
726 
727 cleanup:
728 	free(range_str);
729 	apol_context_destroy(&c);
730 	qpol_iterator_destroy(&iter);
731 	errno = error;
732 	return list;
733 }
734 
735 /**
736  * Get statistics regarding a policy's roles.
737  * If this function is given a name, it will attempt to
738  * get statistics about a particular role; otherwise
739  * the function get statistics about all of the policy's roles.
740  *
741  * @param name Reference to an role's name; if NULL,
742  * all roles will be considered
743  * @param policydb Reference to a policy
744  *
745  * @return 0 on success, < 0 on error.
746  */
747 static PyObject*  get_roles(const char *name, const apol_policy_t * policydb)
748 {
749 	const qpol_role_t *role_datum = NULL;
750 	qpol_iterator_t *iter = NULL;
751 	qpol_policy_t *q = apol_policy_get_qpol(policydb);
752 	int error = 0;
753 	int rt;
754 	PyObject *obj;
755 	PyObject *list = PyList_New(0);
756 	if (!list) goto err;
757 
758 	if (name != NULL) {
759 		if (qpol_policy_get_role_by_name(q, name, &role_datum)) {
760 			errno = EINVAL;
761 			goto err;
762 		}
763 		obj = get_role(role_datum, policydb);
764 		rt = py_append_obj(list, obj);
765 		Py_DECREF(obj); 
766 		if (rt) goto err;
767 	} else {
768 		if (qpol_policy_get_role_iter(q, &iter))
769 			goto err;
770 
771 		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
772 			if (qpol_iterator_get_item(iter, (void **)&role_datum))
773 				goto err;
774 			obj = get_role(role_datum, policydb);
775 			rt = py_append_obj(list, obj);
776 			Py_DECREF(obj); 
777 			if (rt) goto err;
778 		}
779 		qpol_iterator_destroy(&iter);
780 	}
781 	goto cleanup;
782 
783 err:
784 	error = errno;
785 	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
786 	py_decref(list); list = NULL;
787 
788 cleanup:
789 	qpol_iterator_destroy(&iter);
790 	errno = error;
791 	return list;
792 }
793 
794 /**
795  * Get statistics regarding a policy's types.
796  * If this function is given a name, it will attempt to
797  * print statistics about a particular type; otherwise
798  * the function prints statistics about all of the policy's types.
799  *
800  * @param name Reference to a type's name; if NULL,
801  * all object classes will be considered
802  * @param policydb Reference to a policy
803  *
804  * @return 0 on success, < 0 on error.
805  */
806 static PyObject* get_types(const char *name, const apol_policy_t * policydb)
807 {
808 	const qpol_type_t *type_datum = NULL;
809 	qpol_iterator_t *iter = NULL;
810 	qpol_policy_t *q = apol_policy_get_qpol(policydb);
811 	int error = 0;
812 	int rt;
813 	PyObject *obj;
814 	PyObject *list = PyList_New(0);
815 	if (!list) goto err;
816 	/* if name was provided, only print that name */
817 	if (name != NULL) {
818 		if (qpol_policy_get_type_by_name(q, name, &type_datum)) {
819 			errno = EINVAL;
820 			goto err;
821 		}
822 		obj = get_type(type_datum, policydb);
823 		rt = py_append_obj(list, obj);
824 		Py_DECREF(obj); 
825 		if (rt) goto err;
826 	} else {
827 		if (qpol_policy_get_type_iter(q, &iter))
828 			goto err;
829 
830 		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
831 			if (qpol_iterator_get_item(iter, (void **)&type_datum))
832 				goto err;
833 			obj = get_type(type_datum, policydb);
834 			rt = py_append_obj(list, obj);
835 			Py_DECREF(obj); 
836 			if (rt) goto err;
837 		}
838 	}
839 	goto cleanup;
840 
841 err:
842 	error = errno;
843 	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
844 	py_decref(list); list = NULL;
845 
846 cleanup:
847 	qpol_iterator_destroy(&iter);
848 	errno =	error;
849 	return list;
850 }
851 
852 PyObject* info( int type, const char *name)
853 {
854 	PyObject* output = NULL;
855 
856 	/* display requested info */
857 	if (type == TYPE)
858 		output = get_types(name, policy);
859 
860 	if (type == ATTRIBUTE)
861 		output = get_attribs(name, policy);
862 
863 	if (type == ROLE)
864 		output = get_roles(name, policy);
865 
866 	if (type == USER)
867 		output = get_users(name, policy);
868 
869 	if (type == BOOLEAN)
870 		output = get_booleans(name, policy);
871 
872 	if (type == PORT)
873 		output = get_ports(name, policy);
874 
875 	return output;
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
876 }
877 
878 PyObject *wrap_info(PyObject *UNUSED(self), PyObject *args){
879     unsigned int type;
880     char *name;
881     
882     if (!PyArg_ParseTuple(args, "iz", &type, &name))
        argument 4 ("&name") had type
    "char * *"
  but was expecting
    "const char * *"
  for format code "z"
   (emitted by cpychecker)        argument 3 ("&type") had type
    "unsigned int *" (pointing to 32 bits)
  but was expecting
    "int *" (pointing to 32 bits)
  for format code "i"
   (emitted by cpychecker)883         return NULL;
884 
885     return Py_BuildValue("N",info(type, name));
886 }
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
887 
888 void init_info (PyObject *m) {
889     PyModule_AddIntConstant(m, "ATTRIBUTE", ATTRIBUTE);
890     PyModule_AddIntConstant(m, "PORT", PORT);
891     PyModule_AddIntConstant(m, "ROLE", ROLE);
892     PyModule_AddIntConstant(m, "TYPE", TYPE);
893     PyModule_AddIntConstant(m, "USER", USER);
894     PyModule_AddIntConstant(m, "BOOLEAN", BOOLEAN);
895 }
| Location | Tool | Test ID | Issue | |
|---|---|---|---|---|
| policy.c:78:1 | cpychecker | refcount-too-low | wrap_policy | ob_refcnt of return value is 1 too low | 
 1 /**
 2  *  @file
 3  *  Python bindings to search SELinux Policy rules.
 4  *
 5  *  @author Dan Walsh  <dwalsh@redhat.com>
 6  *
 7  *  Copyright (C) 2012 Red Hat, INC
 8  *
 9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  */
23 
24 #include "Python.h"
25 
26 #ifdef UNUSED
27 #elif defined(__GNUC__)
28 # define UNUSED(x) UNUSED_ ## x __attribute__((unused))
29 #elif defined(__LCLINT__)
30 # define UNUSED(x) /*@unused@*/ x
31 #else
32 # define UNUSED(x) x
33 #endif
34 
35 #include "policy.h"
36 apol_policy_t *policy = NULL;
37 
38 /* other */
39 #include <errno.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <assert.h>
44 
45 #define COPYRIGHT_INFO "Copyright (C) 2003-2007 Tresys Technology, LLC"
46 
47 PyObject *wrap_policy(PyObject *UNUSED(self), PyObject *args){
48     const char *policy_file;
49     apol_vector_t *mod_paths = NULL;
50     apol_policy_path_type_e path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC;
51     apol_policy_path_t *pol_path = NULL;
52     
53     if (!PyArg_ParseTuple(args, "z", &policy_file))
54 	    return NULL;
55 
56     if (policy) 
57 	    apol_policy_destroy(&policy);
58 
59     int policy_load_options = 0;
60 	    
61     pol_path = apol_policy_path_create(path_type, policy_file, mod_paths);
62     if (!pol_path) {
63 	    apol_vector_destroy(&mod_paths);
64 	    PyErr_SetString(PyExc_RuntimeError,strerror(ENOMEM));
65 	    return NULL;
66     }
67     apol_vector_destroy(&mod_paths);
68     
69     policy_load_options |= QPOL_POLICY_OPTION_MATCH_SYSTEM;
70     policy = apol_policy_create_from_policy_path(pol_path, policy_load_options, NULL, NULL);
71     apol_policy_path_destroy(&pol_path);
72     if (!policy) {
73 	    PyErr_SetString(PyExc_RuntimeError,strerror(errno));
74 	    return NULL;
75     }
76 
77     return Py_None;
78 }
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
79 
80 static PyMethodDef methods[] = {
81 	{"policy", (PyCFunction) wrap_policy, METH_VARARGS,
82 		 "Initialize SELinux policy for use with search and info"},
83 	{"info", (PyCFunction) wrap_info, METH_VARARGS,
84 		 "Return SELinux policy info about types, attributes, roles, users"},
85 	{"search", (PyCFunction) wrap_search, METH_VARARGS,
86 	"Search SELinux Policy for allow, neverallow, auditallow, dontaudit and transition records"},
87 	{NULL, NULL, 0, NULL}	/* sentinel */
88 };
89 
90 void init_policy() {
91 PyObject *m;
92 m = Py_InitModule("_policy", methods);
93 init_info(m);
94 }
  1 // Author: Thomas Liu <tliu@redhat.com>
  2 
  3 /**
  4  *  @file
  5  *  Python bindings used to search TE rules.
  6  *
  7  *  @author Thomas Liu  <tliu@redhat.com>
  8  *  @author Dan Walsh  <dwalsh@redhat.com>
  9  *  Copyright (C) 2012 Red Hat, inc
 10  *
 11  *  Sections copied from sesearch.c in setools package
 12  *  @author Frank Mayer  mayerf@tresys.com
 13  *  @author Jeremy A. Mowery jmowery@tresys.com
 14  *  @author Paul Rosenfeld  prosenfeld@tresys.com
 15  *  Copyright (C) 2003-2008 Tresys Technology, LLC
 16  *
 17  *  This program is free software; you can redistribute it and/or modify
 18  *  it under the terms of the GNU General Public License as published by
 19  *  the Free Software Foundation; either version 2 of the License, or
 20  *  (at your option) any later version.
 21  *
 22  *  This program is distributed in the hope that it will be useful,
 23  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 24  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 25  *  GNU General Public License for more details.
 26  *
 27  *  You should have received a copy of the GNU General Public License
 28  *  along with this program; if not, write to the Free Software
 29  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 30  */
 31 
 32 /**
 33  * This is a modified version of sesearch to be used as part of a sepython library for
 34  * Python bindings.
 35  */
 36 
 37 #include "common.h"
 38 #include "policy.h"
 39 
 40 /* libapol */
 41 #include <apol/policy-query.h>
 42 #include <apol/render.h>
 43 #include <apol/util.h>
 44 #include <apol/vector.h>
 45 
 46 /* libqpol*/
 47 #include <qpol/policy.h>
 48 #include <qpol/policy_extend.h>
 49 #include <qpol/syn_rule_query.h>
 50 #include <qpol/util.h>
 51 
 52 /* other */
 53 #include <errno.h>
 54 #include <stdlib.h>
 55 #include <stdio.h>
 56 #include <assert.h>
 57 #include <getopt.h>
 58 #include <string.h>
 59 #include <stdbool.h>
 60 
 61 #define COPYRIGHT_INFO "Copyright (C) 2012 Red Hat, Inc, Tresys Technology, LLC"
 62 
 63 enum opt_values
 64 {
 65 	RULE_NEVERALLOW = 256, RULE_AUDIT, RULE_AUDITALLOW, RULE_DONTAUDIT,
 66 	RULE_ROLE_ALLOW, RULE_ROLE_TRANS, RULE_RANGE_TRANS, RULE_ALL,
 67 	EXPR_ROLE_SOURCE, EXPR_ROLE_TARGET
 68 };
 69 
 70 ;
 71 
 72 typedef struct options
 73 {
 74 	char *src_name;
 75 	char *tgt_name;
 76 	char *src_role_name;
 77 	char *tgt_role_name;
 78 	char *class_name;
 79 	char *permlist;
 80 	char *bool_name;
 81 	apol_vector_t *class_vector;
 82 	bool all;
 83 	bool lineno;
 84 	bool semantic;
 85 	bool indirect;
 86 	bool allow;
 87 	bool nallow;
 88 	bool auditallow;
 89 	bool dontaudit;
 90 	bool type;
 91 	bool rtrans;
 92 	bool role_allow;
 93 	bool role_trans;
 94 	bool useregex;
 95 	bool show_cond;
 96 	apol_vector_t *perm_vector;
 97 } options_t;
 98 
 99 static int py_tuple_insert_obj(PyObject *tuple, int pos, PyObject *obj)
100 {
101 	int rt;
102 	if (!obj) return -1;
103 	rt = PyTuple_SetItem(tuple, pos, obj);
104 	Py_DECREF(obj);
105 	return rt;
106 }
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
107 
108 static int perform_ra_query(const apol_policy_t * policy, const options_t * opt, apol_vector_t ** v)
109 {
110 	apol_role_allow_query_t *raq = NULL;
111 	int error = 0;
112 
113 	if (!policy || !opt || !v) {
114 		ERR(policy, "%s", strerror(EINVAL));
115 		errno = EINVAL;
116 		return -1;
117 	}
118 
119 	if (!opt->role_allow && !opt->all) {
120 		*v = NULL;
121 		return 0;	       /* no search to do */
122 	}
123 
124 	raq = apol_role_allow_query_create();
125 	if (!raq) {
126 		ERR(policy, "%s", strerror(ENOMEM));
127 		errno = ENOMEM;
128 		return -1;
129 	}
130 
131 	apol_role_allow_query_set_regex(policy, raq, opt->useregex);
132 	if (opt->src_role_name) {
133 		if (apol_role_allow_query_set_source(policy, raq, opt->src_role_name)) {
134 			error = errno;
135 			goto err;
136 		}
137 	}
138 	if (opt->tgt_role_name)
139 		if (apol_role_allow_query_set_target(policy, raq, opt->tgt_role_name)) {
140 			error = errno;
141 			goto err;
142 		}
143 
144 	if (apol_role_allow_get_by_query(policy, raq, v)) {
145 		error = errno;
146 		goto err;
147 	}
148 	apol_role_allow_query_destroy(&raq);
149 	return 0;
150 
151       err:
152 	apol_vector_destroy(v);
153 	apol_role_allow_query_destroy(&raq);
154 	ERR(policy, "%s", strerror(error));
155 	errno = error;
156 	return -1;
157 }
158 
159 static PyObject* get_ra_results(const apol_policy_t * policy, const apol_vector_t * v, PyObject *output)
160 {
161 	size_t i, num_rules = 0;
162 	qpol_policy_t *q;
163 	const qpol_role_allow_t *rule = NULL;
164 	const char *tmp;
165 	PyObject *obj, *dict=NULL;
166 	const qpol_role_t *role = NULL;
167 	int error = 0;
168 	errno = EINVAL;
169 	int rt;
170 
171 	if (!policy || !v) {
172 		errno = EINVAL;
173 		goto err;
174 	}
175 
176 	if (!(num_rules = apol_vector_get_size(v)))
177 		return NULL;
178 
179 	q = apol_policy_get_qpol(policy);
180 
181 	for (i = 0; i < num_rules; i++) {
182 		dict = PyDict_New();
183 		if (!dict) goto err;
184 		if (!(rule = apol_vector_get_element(v, i)))
185 			goto err;
186 
187 		if (qpol_role_allow_get_source_role(q, rule, &role)) {
188 			goto err;
189 		}
190 		if (qpol_role_get_name(q, role, &tmp)) {
191 			goto err;
192 		}
193 		obj = PyString_FromString(tmp);
194 		if (py_insert_obj(dict, "source", obj)) 
195 			goto err;
196 
197 		if (qpol_role_allow_get_target_role(q, rule, &role)) {
198 			goto err;
199 		}
200 		if (qpol_role_get_name(q, role, &tmp)) {
201 			goto err;
202 		}
203 		obj = PyString_FromString(tmp);
204 		if (py_insert_obj(dict, "target", obj)) 
205 			goto err;
206 
207 		rt = py_append_obj(output, dict);
208 		Py_DECREF(dict); dict=NULL;
209 		if (rt) goto err;
210 	}
211 	goto cleanup;
212 err:
213 	error = errno;
214 	PyErr_SetString(PyExc_RuntimeError,strerror(error));
215 	Py_DECREF(dict); dict=NULL;
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
      (emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
216 
217 cleanup:
218 	errno = error;
219 	return output;
220 }
221 
222 static int perform_te_query(const apol_policy_t * policy, const options_t * opt, apol_vector_t ** v)
223 {
224 	apol_terule_query_t *teq = NULL;
225 	unsigned int rules = 0;
226 	int error = 0;
227 
228 	if (!policy || !opt || !v) {
229 		PyErr_SetString(PyExc_RuntimeError,strerror(EINVAL));
230 		errno = EINVAL;
231 		return -1;
232 	}
233 
234 	if (opt->all || opt->type) {
235 		rules = (QPOL_RULE_TYPE_TRANS | QPOL_RULE_TYPE_CHANGE | QPOL_RULE_TYPE_MEMBER);
236 	} else {
237 		*v = NULL;
238 		return 0;	       /* no search to do */
239 	}
240 
241 	teq = apol_terule_query_create();
242 	if (!teq) {
243 		PyErr_SetString(PyExc_RuntimeError,strerror(ENOMEM));
244 		errno = ENOMEM;
245 		return -1;
246 	}
247 
248 	apol_terule_query_set_rules(policy, teq, rules);
249 	apol_terule_query_set_regex(policy, teq, opt->useregex);
250 
251 	if (!(opt->semantic) && qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_SYN_RULES)) {
252 		if (apol_syn_terule_get_by_query(policy, teq, v)) {
253 			goto err;
254 		}
255 	} else {
256 		if (apol_terule_get_by_query(policy, teq, v)) {
257 			goto err;
258 		}
259 	}
260 
261 	apol_terule_query_destroy(&teq);
262 	return 0;
263 
264 err:
265 	error = errno;
266 	PyErr_SetString(PyExc_RuntimeError,strerror(error));
267 	apol_vector_destroy(v);
268 	apol_terule_query_destroy(&teq);
269 	errno = error;
270 	return -1;
271 }
272 
273 static PyObject* get_te_results(const apol_policy_t * policy, const options_t * opt, const apol_vector_t * v, PyObject *output)
274 {
275 	int error = 0;
276 	int rt = 0;
277 	PyObject *obj, *dict=NULL, *tuple = NULL;
278 	qpol_policy_t *q;
279 	uint32_t rule_type = 0;
280 	const qpol_type_t *type;
281 	size_t i, num_rules = 0;
282 	const qpol_terule_t *rule = NULL;
283 	char *tmp = NULL, *rule_str = NULL, *expr = NULL;
284 	qpol_iterator_t *iter = NULL;
285 	const qpol_cond_t *cond = NULL;
286 	uint32_t enabled = 0, list = 0;
287 	const char *tmp_name;
288 	const qpol_class_t *obj_class = NULL;
289 
290 	if (!policy || !v) {
291 		errno = EINVAL;
292 		goto err;
293 	}
294 
295 	if (!(num_rules = apol_vector_get_size(v)))
296 		return NULL;
297 
298 	q = apol_policy_get_qpol(policy);
299 
300 	for (i = 0; i < num_rules; i++) {
301 		dict = PyDict_New();
302 		if (!dict) goto err;
303 		if (!(rule = apol_vector_get_element(v, i)))
304 			goto err;
305 		if (opt->show_cond) {
306 			if (qpol_terule_get_cond(q, rule, &cond))
307 				goto err;
308 			if (qpol_terule_get_is_enabled(q, rule, &enabled))
309 				goto err;
310 			if (cond) {
311 				if (qpol_terule_get_which_list(q, rule, &list))
312 					goto err;
313 				if (qpol_cond_get_expr_node_iter(q, cond, &iter))
314 					goto err;
315 
316 				qpol_iterator_destroy(&iter);
317 				tuple = PyTuple_New(2);
318 				if (!tuple) goto err;
319 				tmp_name = apol_cond_expr_render(policy, cond);
320 				obj = PyString_FromString(tmp_name);
321 				if (py_tuple_insert_obj(tuple, 1, obj))
322 					goto err;
323 				obj = PyBool_FromLong(enabled);
324 				if (py_tuple_insert_obj(tuple, 2, obj))
325 					goto err;
326 				rt = py_insert_obj(dict, "boolean", tuple);
327 				Py_DECREF(tuple); tuple = NULL;
328 				if (rt) goto err;
329 			}
330 		}
331 
332 		if (qpol_terule_get_rule_type(q, rule, &rule_type))
333 			goto err;
334 
335 		if (!(rule_type &= (QPOL_RULE_TYPE_TRANS | QPOL_RULE_TYPE_CHANGE | QPOL_RULE_TYPE_MEMBER))) {
336 			PyErr_SetString(PyExc_RuntimeError,"Invalid TE rule type");
337 			errno = EINVAL;
338 			goto err;
339 		}
340 		if (!(tmp_name = apol_rule_type_to_str(rule_type))) {
341 			PyErr_SetString(PyExc_RuntimeError, "Could not get TE rule type's string");
342 			errno = EINVAL;
343 			goto err;
344 		}
345 
346 		if (py_insert_string(dict, "type", tmp_name))
347 			goto err;
348 
349 		if (qpol_terule_get_source_type(q, rule, &type))
350 			goto err;
351 		if (qpol_type_get_name(q, type, &tmp_name))
352 			goto err;
353 		if (py_insert_string(dict, "source", tmp_name))
354 			goto err;
355 
356 		if (qpol_terule_get_target_type(q, rule, &type))
357 			goto err;
358 		if (qpol_type_get_name(q, type, &tmp_name))
359 			goto err;
360 		if (py_insert_string(dict, "target", tmp_name))
361 			goto err;
362 
363 		if (qpol_terule_get_object_class(q, rule, &obj_class))
364 			goto err;
365 		if (qpol_class_get_name(q, obj_class, &tmp_name))
366 			goto err;
367 		if (py_insert_string(dict, "class", tmp_name))
368 			goto err;
369 
370 		if (qpol_terule_get_default_type(q, rule, &type))
371 			goto err;
372 		if (qpol_type_get_name(q, type, &tmp_name))
373 			goto err;
374 		if (py_insert_string(dict, "transtype", tmp_name))
375 			goto err;
376 
377 		rt = py_append_obj(output, dict);
378 		dict = NULL;
379 		if(rt) goto err;
380 
381 		free(rule_str);	rule_str = NULL;
382 		free(expr); expr = NULL;
383 	}
384 	goto cleanup;
385 
386 err:
387 	error = errno;
388 	py_decref(dict);
389 	py_decref(tuple);
390 	PyErr_SetString(PyExc_RuntimeError,strerror(error));
391 cleanup:
392 	free(tmp);
393 	free(rule_str);
394 	free(expr);
395 	errno = error;
396 	return output;
397 }
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
398 
399 static int perform_ft_query(const apol_policy_t * policy, const options_t * opt, apol_vector_t ** v)
400 {
401 	apol_filename_trans_query_t *ftq = NULL;
402 	size_t i;
403 	int error = 0;
404 
405 	if (!policy || !opt || !v) {
406 		PyErr_SetString(PyExc_RuntimeError,strerror(EINVAL));
407 		errno = EINVAL;
408 		return -1;
409 	}
410 
411 	if (!opt->type && !opt->all) {
412 		*v = NULL;
413 		return 0;	       /* no search to do */
414 	}
415 
416 	ftq = apol_filename_trans_query_create();
417 	if (!ftq) {
418 		PyErr_SetString(PyExc_RuntimeError,strerror(ENOMEM));
419 		errno = ENOMEM;
420 		return -1;
421 	}
422 
423 	apol_filename_trans_query_set_regex(policy, ftq, opt->useregex);
424 	if (opt->src_name) {
425 		if (apol_filename_trans_query_set_source(policy, ftq, opt->src_name, opt->indirect)) {
426 			goto err;
427 		}
428 	}
429 
430 	if (opt->tgt_name) {
431 		if (apol_filename_trans_query_set_target(policy, ftq, opt->tgt_name, opt->indirect)) {
432 			goto err;
433 		}
434 	}
435 	if (opt->class_name) {
436 		if (opt->class_vector == NULL) {
437 			if (apol_filename_trans_query_append_class(policy, ftq, opt->class_name)) {
438 				goto err;
439 			}
440 		} else {
441 			for (i = 0; i < apol_vector_get_size(opt->class_vector); ++i) {
442 				char *class_name;
443 				class_name = apol_vector_get_element(opt->class_vector, i);
444 				if (!class_name)
445 					continue;
446 				if (apol_filename_trans_query_append_class(policy, ftq, class_name)) {
447 					goto err;
448 				}
449 			}
450 		}
451 	}
452 
453 	if (apol_filename_trans_get_by_query(policy, ftq, v)) {
454 		error = errno;
      (emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
455 	}
456 
457 	apol_filename_trans_query_destroy(&ftq);
458 	return 0;
459 
460 err:
461 	error = errno;
462 	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
463 	apol_vector_destroy(v);
464 	apol_filename_trans_query_destroy(&ftq);
465 	errno = error;
466 	return -1;
467 }
468 
469 static PyObject* get_ft_results(const apol_policy_t * policy, const apol_vector_t * v, PyObject *list)
470 {
471 	PyObject *dict = NULL;
472 	size_t i, num_filename_trans = 0;
473 	const char *tmp_name;
474 	int error = 0;
475 	int rt;
476 	const qpol_filename_trans_t *filename_trans = NULL;
477 	const qpol_class_t *obj_class = NULL;
478 	char *tmp = NULL, *filename_trans_str = NULL, *expr = NULL;
479 	qpol_policy_t *q;
480 	const qpol_type_t *type = NULL;
481 
482 	if (!policy || !v) {
483 		errno = EINVAL;
484 		goto err;
485 	}
486 
487 	if (!(num_filename_trans = apol_vector_get_size(v)))
488 		return NULL;
489 
490 	q = apol_policy_get_qpol(policy);
491 
492 	for (i = 0; i < num_filename_trans; i++) {
493 		if (!(filename_trans = apol_vector_get_element(v, i)))
494 			goto err;
495 
496 		dict = PyDict_New();
497 		if (!dict) goto err;
498 
499 		if (py_insert_string(dict, "type", "type_transition"))
500 			goto err;
501 
502 		/* source type */
503 		if (qpol_filename_trans_get_source_type(q, filename_trans, &type)) {
504 			goto err;
505 		}
506 		if (qpol_type_get_name(q, type, &tmp_name)) {
507 			goto err;
508 		}
509 
510 		if (py_insert_string(dict, "source", tmp_name))
511 			goto err;
512 
513 		if (qpol_filename_trans_get_target_type(q, filename_trans, &type))
514 			goto err;
515 
516 		if (qpol_type_get_name(q, type, &tmp_name))
517 			goto err;
518 
519 		if (py_insert_string(dict, "target", tmp_name))
520 			goto err;
521 
522 		if (qpol_filename_trans_get_object_class(q, filename_trans, &obj_class))
523 			goto err;
524 
525 		if (qpol_class_get_name(q, obj_class, &tmp_name))
526 			goto err;
527 
528 		if (py_insert_string(dict, "class", tmp_name))
529 			goto err;
530 
531 		if (qpol_filename_trans_get_default_type(q, filename_trans, &type))
532 			goto err;
533 		if (qpol_type_get_name(q, type, &tmp_name))
534 			goto err;
535 		if (py_insert_string(dict, "transtype", tmp_name))
536 			goto err;
537 
538 		if (! qpol_filename_trans_get_filename(q, filename_trans, &tmp_name)) {
539 			if (py_insert_string(dict, "filename", tmp_name))
540 				goto err;
541 		}
542 
543 		rt = py_append_obj(list, dict);
544 		dict = NULL;
545 		if (rt) goto err;
546 
547 		free(filename_trans_str); filename_trans_str = NULL;
548 		free(expr); expr = NULL;
549 	}
550 	goto cleanup;
551 
552 err:
553 	error = errno;
554 	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
555 	py_decref(dict);
556 cleanup:
557 	free(tmp);
558 	free(filename_trans_str);
559 	free(expr);
560 	errno = error;
561 	return list;
562 }
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
563 
564 static int perform_av_query(const apol_policy_t * policy, const options_t * opt, apol_vector_t ** v)
565 {
566 	apol_avrule_query_t *avq = NULL;
567 	unsigned int rules = 0;
568 	int error = 0;
569 	char *tmp = NULL, *tok = NULL, *s = NULL;
570 
571 	if (!policy || !opt || !v) {
572 		PyErr_SetString(PyExc_RuntimeError,strerror(EINVAL));
573 		errno = EINVAL;
574 		return -1;
575 	}
576 
577 	if (!opt->all && !opt->allow && !opt->nallow && !opt->auditallow && !opt->dontaudit) {
578 		*v = NULL;
579 		return 0;	       /* no search to do */
580 	}
581 
582 	avq = apol_avrule_query_create();
583 	if (!avq) {
584 		PyErr_SetString(PyExc_RuntimeError,strerror(ENOMEM));
585 		errno = ENOMEM;
586 		return -1;
587 	}
588 
589 	if (opt->allow || opt->all)
590 		rules |= QPOL_RULE_ALLOW;
591 	if ((opt->nallow || opt->all) && qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_NEVERALLOW))
592 		rules |= QPOL_RULE_NEVERALLOW;
593 	if (opt->auditallow || opt->all)
594 		rules |= QPOL_RULE_AUDITALLOW;
595 	if (opt->dontaudit || opt->all)
596 		rules |= QPOL_RULE_DONTAUDIT;
597 	apol_avrule_query_set_rules(policy, avq, rules);
598 	apol_avrule_query_set_regex(policy, avq, opt->useregex);
599 	if (opt->src_name)
600 		apol_avrule_query_set_source(policy, avq, opt->src_name, opt->indirect);
601 	if (opt->tgt_name)
602 		apol_avrule_query_set_target(policy, avq, opt->tgt_name, opt->indirect);
603 	if (opt->bool_name)
604 		apol_avrule_query_set_bool(policy, avq, opt->bool_name);
605 	if (opt->class_name) {
606 		if (opt->class_vector == NULL) {
607 			if (apol_avrule_query_append_class(policy, avq, opt->class_name)) {
608 				goto err;
609 			}
610 		} else {
611 			size_t i;
612 	    for (i = 0; i < apol_vector_get_size(opt->class_vector); ++i) {
613 				char *class_name;
614 				class_name = apol_vector_get_element(opt->class_vector, i);
615 				if (!class_name)
616 					continue;
617 				if (apol_avrule_query_append_class(policy, avq, class_name)) {
618 					goto err;
619 				}
620 			}
621 		}
622 	}
623 
624 	if (opt->permlist) {
625 		tmp = strdup(opt->permlist);
626 		for (tok = strtok(tmp, ","); tok; tok = strtok(NULL, ",")) {
627 			if (apol_avrule_query_append_perm(policy, avq, tok)) {
628 				goto err;
629 			}
630 			if ((s = strdup(tok)) == NULL || apol_vector_append(opt->perm_vector, s) < 0) {
631 				goto err;
632 			}
633 			s = NULL;
634 		}
635 		free(tmp);
636 	}
637 
638 	if (!(opt->semantic) && qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_SYN_RULES)) {
639 		if (apol_syn_avrule_get_by_query(policy, avq, v)) {
640 			goto err;
641 		}
642 	} else {
643 		if (apol_avrule_get_by_query(policy, avq, v)) {
644 			goto err;
645 		}
646 	}
647 
648 	apol_avrule_query_destroy(&avq);
649 	return 0;
650 
651 err:
652 	error = errno;
653 	PyErr_SetString(PyExc_RuntimeError,strerror(error));	
654 	apol_vector_destroy(v);
655 	apol_avrule_query_destroy(&avq);
656 	free(tmp);
657 	free(s);
658 	errno = error;
659 	return -1;
660 }
661 
662 static PyObject* get_av_results(const apol_policy_t * policy, const apol_vector_t * v, PyObject *output)
663 {
664 	PyObject *dict = NULL;
665 	PyObject *permlist = NULL;
666 	int rt;
667 	int error = 0;
668 	qpol_policy_t *q;
669 	size_t i, num_rules = 0;
670 	const qpol_avrule_t *rule = NULL;
671 	char *tmp = NULL, *rule_str = NULL, *expr = NULL;
672 	qpol_iterator_t *iter = NULL;
673 	uint32_t enabled = 0;
674 
675 	if (!policy || !v) {
676 		errno = EINVAL;
677 		goto err;
678 	}
679 
680 	if (!(num_rules = apol_vector_get_size(v)))
681 		return NULL;
682 
683 	q = apol_policy_get_qpol(policy);
684 
685 	for (i = 0; i < num_rules; i++) {
686 		if (!(rule = apol_vector_get_element(v, i)))
687 			goto err;
688 
689 		if (qpol_avrule_get_is_enabled(q, rule, &enabled))
690 			goto err;
691 		if (!enabled)
692 			continue;
693 
694 		const qpol_type_t *type;
695 		const char *tmp_name;
696 		uint32_t rule_type = 0;
697 
698 		const qpol_class_t *obj_class = NULL;
699 
700 		dict = PyDict_New();
701 		if (!dict) goto err;
702 
703 		if (qpol_avrule_get_rule_type(q, rule, &rule_type))
704 			goto err;
705 			
706 		if (!(tmp_name = apol_rule_type_to_str(rule_type))) {
707 			PyErr_SetString(PyExc_RuntimeError, "Could not get TE rule type's string");
708 			goto err;
709 		}
710 
711 		if (py_insert_string(dict, "type", tmp_name)) 
712 			goto err;
713 
714 		if (qpol_avrule_get_source_type(q, rule, &type)) {
715 			goto err;
716 		}
717 
718 		if (qpol_type_get_name(q, type, &tmp_name)) {
719 			goto err;
720 		}
721 
722 		if (py_insert_string(dict, "source", tmp_name)) 
723 			goto err;
724 
725 		if (qpol_avrule_get_target_type(q, rule, &type)) {
726 			goto err;
727 		}
728 		if (qpol_type_get_name(q, type, &tmp_name)) {
729 			goto err;
730 		}
731 
732 		if (py_insert_string(dict, "target", tmp_name)) 
733 			goto err;
734 
735 		if (qpol_avrule_get_object_class(q, rule, &obj_class)) {
736 			goto err;
737 		}
738 		if (qpol_class_get_name(q, obj_class, &tmp_name)) {
739 			goto err;
740 		}
741 
742 		if (py_insert_string(dict, "class", tmp_name)) 
743 			goto err;
744 
745 		if (qpol_avrule_get_perm_iter(q, rule, &iter)) {
746 			goto err;
747 		}
748 
749 		permlist = PyList_New(0);
750 		if (! permlist) goto err;
751 
752 		for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
753 			const char *perm_name = NULL;
754 			qpol_iterator_get_item(iter, (void **)&perm_name);
755 			if (py_append_string(permlist, perm_name))
756 				goto err;
757 		}
758 
759 		rt = PyDict_SetItemString(dict, "permlist", permlist);
760 		Py_DECREF(permlist); 
761 		if (rt) goto err;
762 
763 		rt = py_append_obj(output, dict);
764 		Py_DECREF(dict); dict=NULL;
765 		if (rt) goto err;
766 
767 		free(rule_str);	rule_str = NULL;
768 		free(expr); expr = NULL;
769 	}
770 	goto cleanup;
771 
772 err:
773 	error = errno;
774 	PyErr_SetString(PyExc_RuntimeError,strerror(errno));
775 	py_decref(dict);
776 	py_decref(permlist);
777 
778 cleanup:
779 	free(tmp);
780 	free(rule_str);
781 	free(expr);
782 	errno = error;
783 	return output;
784 }
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
785 
786 PyObject* search(bool allow,
787 		 bool neverallow,
788 		 bool auditallow,
789 		 bool dontaudit,
790 		 bool transition,
791 		 bool role_allow,
792 		 const char *src_name,
793 		 const char *tgt_name,
794 		 const char *class_name,
795 		 const char *permlist
796 	)
797 {
798 	options_t cmd_opts;
799 	PyObject *output = NULL;
800 	apol_vector_t *v = NULL;
801 
802 	memset(&cmd_opts, 0, sizeof(cmd_opts));
803 	cmd_opts.indirect = true;
804 	cmd_opts.allow = allow;
805 	cmd_opts.nallow = neverallow;
806 	cmd_opts.auditallow = auditallow;
807 	cmd_opts.dontaudit = dontaudit;
808 	cmd_opts.type = transition;
809 	cmd_opts.role_allow = role_allow;
810 	if (src_name)
811 		cmd_opts.src_name = strdup(src_name);
812 	if (tgt_name)
813 		cmd_opts.tgt_name = strdup(tgt_name);
814 	if (class_name)
815 		cmd_opts.class_name = strdup(class_name);
816 	if (permlist){
817 		cmd_opts.perm_vector = apol_vector_create(free);
818 		cmd_opts.permlist = strdup(permlist);
819 	}
820 	int pol_opt = 0;
821 	if (!(cmd_opts.nallow || cmd_opts.all))
822 		pol_opt |= QPOL_POLICY_OPTION_NO_NEVERALLOWS;
823 
824 	pol_opt |= QPOL_POLICY_OPTION_MATCH_SYSTEM;
      (emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
825 
826 	/* handle regex for class name */
827 	if (cmd_opts.useregex && cmd_opts.class_name != NULL) {
828 		cmd_opts.class_vector = apol_vector_create(NULL);
829 		apol_vector_t *qpol_matching_classes = NULL;
830 		apol_class_query_t *regex_match_query = apol_class_query_create();
831 		apol_class_query_set_regex(policy, regex_match_query, 1);
832 		apol_class_query_set_class(policy, regex_match_query, cmd_opts.class_name);
833 		if (apol_class_get_by_query(policy, regex_match_query, &qpol_matching_classes)) {
834 			apol_class_query_destroy(®ex_match_query);
835 			PyErr_SetString(PyExc_RuntimeError,"Query failed");
836 			goto cleanup;
837 		}
838 		const qpol_class_t *class = NULL;
839 		size_t i;
840 		for (i = 0; i < apol_vector_get_size(qpol_matching_classes); ++i) {
841 			const char *class_name;
842 			class = apol_vector_get_element(qpol_matching_classes, i);
843 			if (!class)
844 				break;
845 			qpol_class_get_name(apol_policy_get_qpol(policy), class, &class_name);
846 			apol_vector_append(cmd_opts.class_vector, (void *)class_name);
847 		}
848 		if (!apol_vector_get_size(qpol_matching_classes)) {
849 			apol_vector_destroy(&qpol_matching_classes);
850 			apol_class_query_destroy(®ex_match_query);
851 			PyErr_SetString(PyExc_RuntimeError,"No classes match expression");
852 			goto cleanup;
853 		}
854 		apol_vector_destroy(&qpol_matching_classes);
855 		apol_class_query_destroy(®ex_match_query);
856 	}
857 
858 	if (!cmd_opts.semantic && qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_SYN_RULES)) {
859 		if (qpol_policy_build_syn_rule_table(apol_policy_get_qpol(policy))) {
860 			apol_policy_destroy(&policy);
861 			PyErr_SetString(PyExc_RuntimeError,"Query failed");
862 			goto cleanup;
863 		}
864 	}
865 
866 	/* if syntactic rules are not available always do semantic search */
867 	if (!qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_SYN_RULES)) {
868 		cmd_opts.semantic = 1;
869 	}
870 
871 	/* supress line numbers if doing semantic search or not available */
872 	if (cmd_opts.semantic || !qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_LINE_NUMBERS)) {
873 		cmd_opts.lineno = 0;
874 	}
875 	if (perform_av_query(policy, &cmd_opts, &v)) {
876 		goto cleanup;
877 	}
878 	output = PyList_New(0);
879 	if (!output) 
880 		goto cleanup;
881 
882 	if (v) {
883 		get_av_results(policy, v, output);
884 	}
885 
886 	apol_vector_destroy(&v);
887 	if (perform_te_query(policy, &cmd_opts, &v)) {
888 		goto cleanup;
889 	}
890 	if (v) {
891 		get_te_results(policy, &cmd_opts, v, output);
892 	}
893 
894 	if (cmd_opts.all || cmd_opts.type) {
895 		apol_vector_destroy(&v);
896 		if (perform_ft_query(policy, &cmd_opts, &v)) {
897 			goto cleanup;
898 		}
899 
900 		if (v) {
901 			get_ft_results(policy, v, output);
902 		}
903 	}
904 
905 	if (cmd_opts.all || cmd_opts.role_allow) {
906 		apol_vector_destroy(&v);
907 		if (perform_ra_query(policy, &cmd_opts, &v)) {
908 			goto cleanup;
909 		}
910 
911 		if (v) {
912 			get_ra_results(policy, v, output);
913 		}
914 	}
915 
916 	apol_vector_destroy(&v);
917 
918       cleanup:
919 	free(cmd_opts.src_name);
920 	free(cmd_opts.tgt_name);
921 	free(cmd_opts.class_name);
922 	free(cmd_opts.permlist);
923 	free(cmd_opts.bool_name);
924 	free(cmd_opts.src_role_name);
925 	free(cmd_opts.tgt_role_name);
926 	apol_vector_destroy(&cmd_opts.perm_vector);
927 	apol_vector_destroy(&cmd_opts.class_vector);
928 
929 	if (PyList_GET_SIZE(output) == 0) {
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
      (emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
930 		Py_DECREF(output);
931 		return Py_None;
932 	}
933 	return output;
934 }
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
935 
936 static int Dict_ContainsInt(PyObject *dict, const char *key){
937     PyObject *item = PyDict_GetItemString(dict, key);
938     if (item)
939 	return PyInt_AsLong(item);
940     return false;
941 }
942 
943 static const char *Dict_ContainsString(PyObject *dict, const char *key){
944     PyObject *item = PyDict_GetItemString(dict, key);
945     if (item)
946 	return PyString_AsString(item);
947     return NULL;
948 }
949 
950 PyObject *wrap_search(PyObject *UNUSED(self), PyObject *args){
951     PyObject *dict;
952     if (!PyArg_ParseTuple(args, "O", &dict))
953 	return NULL;
954     int allow = Dict_ContainsInt(dict, "allow");
955     int neverallow = Dict_ContainsInt(dict, "neverallow");
956     int auditallow = Dict_ContainsInt(dict, "auditallow");
957     int dontaudit = Dict_ContainsInt(dict, "dontaudit");
958     int transition = Dict_ContainsInt(dict, "transition");
959     int role_allow = Dict_ContainsInt(dict, "role_allow");
960 
961     const char *src_name = Dict_ContainsString(dict, "source");
962     const char *tgt_name = Dict_ContainsString(dict, "target");
963     const char *class_name = Dict_ContainsString(dict, "class");
964     const char *permlist = Dict_ContainsString(dict, "permlist");
965 
966     return Py_BuildValue("N",search(allow, neverallow, auditallow, dontaudit, transition, role_allow, src_name, tgt_name, class_name, permlist));
967 }
      (emitted by cpychecker)TODO: a detailed trace is available in the data model (not yet rendered in this report)
No issues found
  1 /*
  2  * Copyright 1999-2004 Gentoo Technologies, Inc.
  3  * Distributed under the terms of the GNU General Public License v2
  4  * $Header: /home/cvsroot/gentoo-projects/hardened/policycoreutils-extra/src/sestatus.c,v 1.10 2004/03/26 19:25:52 pebenito Exp $
  5  * Patch provided by Steve Grubb
  6  */
  7 
  8 #include <stdio.h>
  9 #include <stdlib.h>
 10 #include <string.h>
 11 #include <errno.h>
 12 #include <selinux/selinux.h>
 13 #include <selinux/get_default_type.h>
 14 #include <sys/types.h>
 15 #include <sys/stat.h>
 16 #include <dirent.h>
 17 #include <unistd.h>
 18 #include <libgen.h>
 19 #include <ctype.h>
 20 
 21 #define PROC_BASE "/proc"
 22 #define MAX_CHECK 50
 23 #define CONF "/etc/sestatus.conf"
 24 
 25 /* conf file sections */
 26 #define PROCS "[process]"
 27 #define FILES "[files]"
 28 
 29 /* buffer size for cmp_cmdline */
 30 #define BUFSIZE 255
 31 
 32 /* column to put the output (must be a multiple of 8) */
 33 static unsigned int COL = 32;
 34 
 35 extern char *selinux_mnt;
 36 
 37 int cmp_cmdline(const char *command, int pid)
 38 {
 39 
 40 	char buf[BUFSIZE];
 41 	char filename[BUFSIZE];
 42 
 43 	memset(buf, '\0', BUFSIZE);
 44 
 45 	/* first read the proc entry */
 46 	sprintf(filename, "%s/%d/exe", PROC_BASE, pid);
 47 
 48 	if (readlink(filename, buf, BUFSIZE) < 0)
 49 		return 0;
 50 
 51 	if (buf[BUFSIZE - 1] != '\0')
 52 		buf[BUFSIZE - 1] = '\0';
 53 
 54 	/* check if this is the command we're looking for. */
 55 	if (strcmp(command, buf) == 0)
 56 		return 1;
 57 	else
 58 		return 0;
 59 }
 60 
 61 int pidof(const char *command)
 62 {
 63 /* inspired by killall5.c from psmisc */
 64 	DIR *dir;
 65 	struct dirent *de;
 66 	int pid, ret = -1, self = getpid();
 67 
 68 	if (!(dir = opendir(PROC_BASE))) {
 69 		perror(PROC_BASE);
 70 		return -1;
 71 	}
 72 
 73 	while ((de = readdir(dir)) != NULL) {
 74 		errno = 0;
 75 		pid = (int)strtol(de->d_name, (char **)NULL, 10);
 76 		if (errno || pid == 0 || pid == self)
 77 			continue;
 78 		if (cmp_cmdline(command, pid)) {
 79 			ret = pid;
 80 			break;
 81 		}
 82 	}
 83 
 84 	closedir(dir);
 85 	return ret;
 86 }
 87 
 88 void load_checks(char *pc[], int *npc, char *fc[], int *nfc)
 89 {
 90 
 91 	FILE *fp = fopen(CONF, "r");
 92 	char buf[255], *bufp;
 93 	int buf_len, section = -1;
 94 	int proclen = strlen(PROCS);
 95 	int filelen = strlen(FILES);
 96 
 97 	if (fp == NULL) {
 98 		printf("\nUnable to open %s.\n", CONF);
 99 		return;
100 	}
101 
102 	while (!feof(fp)) {
103 		if (!fgets(buf, sizeof buf, fp))
104 			break;
105 
106 		buf_len = strlen(buf);
107 		if (buf[buf_len - 1] == '\n')
108 			buf[buf_len - 1] = 0;
109 
110 		bufp = buf;
111 		while (*bufp && isspace(*bufp)) {
112 			bufp++;
113 			buf_len--;
114 		}
115 
116 		if (*bufp == '#')
117 			/* skip comments */
118 			continue;
119 
120 		if (*bufp) {
121 			if (!(*bufp))
122 				goto out;
123 
124 			if (strncmp(bufp, PROCS, proclen) == 0)
125 				section = 0;
126 			else if (strncmp(bufp, FILES, filelen) == 0)
127 				section = 1;
128 			else {
129 				switch (section) {
130 				case 0:
131 					if (*npc >= MAX_CHECK)
132 						break;
133 					pc[*npc] =
134 					    (char *)malloc((buf_len) *
135 							   sizeof(char));
136 					memcpy(pc[*npc], bufp, buf_len);
137 					(*npc)++;
138 					bufp = NULL;
139 					break;
140 				case 1:
141 					if (*nfc >= MAX_CHECK)
142 						break;
143 					fc[*nfc] =
144 					    (char *)malloc((buf_len) *
145 							   sizeof(char));
146 					memcpy(fc[*nfc], bufp, buf_len);
147 					(*nfc)++;
148 					bufp = NULL;
149 					break;
150 				default:
151 					/* ignore lines before a section */
152 					printf("Line not in a section: %s.\n",
153 					       buf);
154 					break;
155 				}
156 			}
157 		}
158 	}
159       out:
160 	fclose(fp);
161 	return;
162 }
163 
164 void printf_tab(const char *outp)
165 {
166 	char buf[20];
167 	snprintf(buf, sizeof(buf), "%%-%us", COL);
168 	printf(buf, outp);
169 
170 }
171 
172 int main(int argc, char **argv)
173 {
174 	/* these vars are reused several times */
175 	int rc, opt, i, c, size;
176 	char *context, *root_path;
177 
178 	/* files that need context checks */
179 	char *fc[MAX_CHECK];
180 	char *cterm = ttyname(0);
181 	int nfc = 0;
182 	struct stat m;
183 
184 	/* processes that need context checks */
185 	char *pc[MAX_CHECK];
186 	int npc = 0;
187 
188 	/* booleans */
189 	char **bools;
190 	int nbool;
191 
192 	int verbose = 0;
193 	int show_bools = 0;
194 
195 	/* policy */
196 	const char *pol_name, *root_dir;
197 	char *pol_path;
198 
199 
200 	while (1) {
201 		opt = getopt(argc, argv, "vb");
202 		if (opt == -1)
203 			break;
204 		switch (opt) {
205 		case 'v':
206 			verbose = 1;
207 			break;
208 		case 'b':
209 			show_bools = 1;
210 			break;
211 		default:
212 			/* invalid option */
213 			printf("\nUsage: %s [OPTION]\n\n", basename(argv[0]));
214 			printf("  -v  Verbose check of process and file contexts.\n");
215 			printf("  -b  Display current state of booleans.\n");
216 			printf("\nWithout options, show SELinux status.\n");
217 			return -1;
218 		}
219 	}
220 	printf_tab("SELinux status:");
221 	rc = is_selinux_enabled();
222 
223 	switch (rc) {
224 	case 1:
225 		printf("enabled\n");
226 		break;
227 	case 0:
228 		printf("disabled\n");
229 		return 0;
230 		break;
231 	default:
232 		printf("unknown (%s)\n", strerror(errno));
233 		return 0;
234 		break;
235 	}
236 
237 	printf_tab("SELinuxfs mount:");
238 	if (selinux_mnt != NULL) {
239 		printf("%s\n", selinux_mnt);
240 	} else {
241 		printf("not mounted\n\n");
242 		printf("Please mount selinuxfs for proper results.\n");
243 		return -1;
244 	}
245 
246 	printf_tab("SELinux root directory:");
247 	if ((root_dir = selinux_path()) != NULL) {
248 		/* The path has a trailing '/' so remove it */
249 		size = strlen(root_dir);
250 		root_path = malloc(size);
251 		if (!root_path) {
252 			printf("malloc error (%s)\n", strerror(errno));
253 			return -1;
254 		}
255 		memset(root_path, 0, size);
256 		strncpy(root_path, root_dir, (size-1)) ;
257 		printf("%s\n", root_path);
258 		free(root_path);
259 	} else {
260 			printf("error (%s)\n", strerror(errno));
261 		return -1;
262 	}
263 
264 	/* Dump all the path information */
265 	printf_tab("Loaded policy name:");
266 	pol_path = strdup(selinux_policy_root());
267 	if (pol_path) {
268 		pol_name = basename(pol_path);
269 		puts(pol_name);
270 		free(pol_path);
271 	} else {
272 		printf("error (%s)\n", strerror(errno));
273 	}
274 
275 	printf_tab("Current mode:");
276 	rc = security_getenforce();
277 	switch (rc) {
278 	case 1:
279 		printf("enforcing\n");
280 		break;
281 	case 0:
282 		printf("permissive\n");
283 		break;
284 	default:
285 		printf("unknown (%s)\n", strerror(errno));
286 		break;
287 	}
288 
289 	printf_tab("Mode from config file:");
290 	if (selinux_getenforcemode(&rc) == 0) {
291 		switch (rc) {
292 		case 1:
293 			printf("enforcing\n");
294 			break;
295 		case 0:
296 			printf("permissive\n");
297 			break;
298 		case -1:
299 			printf("disabled\n");
300 			break;
301 		}
302 	} else {
303 		printf("error (%s)\n", strerror(errno));
304 	}
305 
306 	printf_tab("Policy MLS status:");
307 	rc = is_selinux_mls_enabled();
308 	switch (rc) {
309 		case 0:
310 			printf("disabled\n");
311 			break;
312 		case 1:
313 			printf("enabled\n");
314 			break;
315 		default:
316 			printf("error (%s)\n", strerror(errno));
317 			break;
318 	}
319 
320 	printf_tab("Policy deny_unknown status:");
321 	rc = security_deny_unknown();
322 	switch (rc) {
323 		case 0:
324 			printf("allowed\n");
325 			break;
326 		case 1:
327 			printf("denied\n");
328 			break;
329 		default:
330 			printf("error (%s)\n", strerror(errno));
331 			break;
332 	}
333 
334 	rc = security_policyvers();
335 	printf_tab("Max kernel policy version:");
336 	if (rc < 0)
337 		printf("unknown (%s)\n", strerror(errno));
338 	else
339 		printf("%d\n", rc);
340 
341 
342 	if (show_bools) {
343 		/* show booleans */
344 		if (security_get_boolean_names(&bools, &nbool) >= 0) {
345 			printf("\nPolicy booleans:\n");
346 
347 			for (i = 0; i < nbool; i++) {
348 				if (strlen(bools[i]) + 1 > COL)
349 					COL = strlen(bools[i]) + 1;
350 			}
351 			for (i = 0; i < nbool; i++) {
352 				printf_tab(bools[i]);
353 
354 				rc = security_get_boolean_active(bools[i]);
355 				switch (rc) {
356 				case 1:
357 					printf("on");
358 					break;
359 				case 0:
360 					printf("off");
361 					break;
362 				default:
363 					printf("unknown (%s)", strerror(errno));
364 					break;
365 				}
366 				c = security_get_boolean_pending(bools[i]);
367 				if (c != rc)
368 					switch (c) {
369 					case 1:
370 						printf(" (activate pending)");
371 						break;
372 					case 0:
373 						printf(" (inactivate pending)");
374 						break;
375 					default:
376 						printf(" (pending error: %s)",
377 						       strerror(errno));
378 						break;
379 					}
380 				printf("\n");
381 
382 				/* free up the booleans */
383 				free(bools[i]);
384 			}
385 			free(bools);
386 		}
387 	}
388 	/* only show contexts if -v is given */
389 	if (!verbose)
390 		return 0;
391 
392 	load_checks(pc, &npc, fc, &nfc);
393 
394 	printf("\nProcess contexts:\n");
395 
396 	printf_tab("Current context:");
397 	if (getcon(&context) >= 0) {
398 		printf("%s\n", context);
399 		freecon(context);
400 	} else
401 		printf("unknown (%s)\n", strerror(errno));
402 
403 	printf_tab("Init context:");
404 	if (getpidcon(1, &context) >= 0) {
405 		printf("%s\n", context);
406 		freecon(context);
407 	} else
408 		printf("unknown (%s)\n", strerror(errno));
409 
410 	for (i = 0; i < npc; i++) {
411 		rc = pidof(pc[i]);
412 		if (rc > 0) {
413 			if (getpidcon(rc, &context) < 0)
414 				continue;
415 
416 			printf_tab(pc[i]);
417 			printf("%s\n", context);
418 			freecon(context);
419 		}
420 	}
421 
422 	printf("\nFile contexts:\n");
423 
424 	/* controlling term */
425 	printf_tab("Controlling terminal:");
426 	if (lgetfilecon(cterm, &context) >= 0) {
427 		printf("%s\n", context);
428 		freecon(context);
429 	} else {
430 		printf("unknown (%s)\n", strerror(errno));
431 	}
432 
433 	for (i = 0; i < nfc; i++) {
434 		if (lgetfilecon(fc[i], &context) >= 0) {
435 			printf_tab(fc[i]);
436 
437 			/* check if this is a symlink */
438 			if (lstat(fc[i], &m)) {
439 				printf
440 				    ("%s (could not check link status (%s)!)\n",
441 				     context, strerror(errno));
442 				freecon(context);
443 				continue;
444 			}
445 			if (S_ISLNK(m.st_mode)) {
446 				/* print link target context */
447 				printf("%s -> ", context);
448 				freecon(context);
449 
450 				if (getfilecon(fc[i], &context) >= 0) {
451 					printf("%s\n", context);
452 					freecon(context);
453 				} else {
454 					printf("unknown (%s)\n",
455 					       strerror(errno));
456 				}
457 			} else {
458 				printf("%s\n", context);
459 				freecon(context);
460 			}
461 		}
462 	}
463 
464 	return 0;
465 }
| Location | Tool | Test ID | Issue | |
|---|---|---|---|---|
| restore.c:62:3 | gcc | missing-braces | restore_init | missing braces around initializer | 
| restore.c:62:3 | gcc | missing-braces | restore_init | (near initialization for 'selinux_opts[0]. | 
    
| restore.c:684:10 | clang-analyzer | Function call argument is an uninitialized value | 
  1 #include "restore.h"
  2 #include <glob.h>
  3 #include <selinux/context.h>
  4 
  5 #define SKIP -2
  6 #define ERR -1
  7 #define MAX_EXCLUDES 1000
  8 
  9 /*
 10  * The hash table of associations, hashed by inode number.
 11  * Chaining is used for collisions, with elements ordered
 12  * by inode number in each bucket.  Each hash bucket has a dummy 
 13  * header.
 14  */
 15 #define HASH_BITS 16
 16 #define HASH_BUCKETS (1 << HASH_BITS)
 17 #define HASH_MASK (HASH_BUCKETS-1)
 18 
 19 /*
 20  * An association between an inode and a context.
 21  */
 22 typedef struct file_spec {
 23 	ino_t ino;		/* inode number */
 24 	char *con;		/* matched context */
 25 	char *file;		/* full pathname */
 26 	struct file_spec *next;	/* next association in hash bucket chain */
 27 } file_spec_t;
 28 
 29 struct edir {
 30 	char *directory;
 31 	size_t size;
 32 };
 33 
 34 
 35 static file_spec_t *fl_head;
 36 static int filespec_add(ino_t ino, const security_context_t con, const char *file);
 37 struct restore_opts *r_opts = NULL;
 38 static void filespec_destroy(void);
 39 static void filespec_eval(void);
 40 static int excludeCtr = 0;
 41 static struct edir excludeArray[MAX_EXCLUDES];
 42 
 43 void remove_exclude(const char *directory)
 44 {
 45 	int i = 0;
 46 	for (i = 0; i < excludeCtr; i++) {
 47 		if (strcmp(directory, excludeArray[i].directory) == 0) {
 48 			free(excludeArray[i].directory);
 49 			if (i != excludeCtr-1)
 50 				excludeArray[i] = excludeArray[excludeCtr-1];
 51 			excludeCtr--;
 52 			return;
 53 		}
 54 	}
 55 	return;
 56 }
 57 
 58 void restore_init(struct restore_opts *opts)
 59 {	
 60 	r_opts = opts;
 61 	struct selinux_opt selinux_opts[] = {
 62 		{ SELABEL_OPT_VALIDATE, r_opts->selabel_opt_validate },
      (emitted by gcc)      (emitted by gcc) 63 		{ SELABEL_OPT_PATH, r_opts->selabel_opt_path }
 64 	};
 65 	r_opts->hnd = selabel_open(SELABEL_CTX_FILE, selinux_opts, 2);
 66 	if (!r_opts->hnd) {
 67 		perror(r_opts->selabel_opt_path);
 68 		exit(1);
 69 	}	
 70 }
 71 
 72 void restore_finish()
 73 {
 74 	int i;
 75 	for (i = 0; i < excludeCtr; i++) {
 76 		free(excludeArray[i].directory);
 77 	}
 78 }
 79 
 80 static int match(const char *name, struct stat *sb, char **con)
 81 {
 82 	if (!(r_opts->hard_links) && !S_ISDIR(sb->st_mode) && (sb->st_nlink > 1)) {
 83 		fprintf(stderr, "Warning! %s refers to a file with more than one hard link, not fixing hard links.\n",
 84 					name);
 85 		return -1;
 86 	}
 87 	
 88 	if (NULL != r_opts->rootpath) {
 89 		if (0 != strncmp(r_opts->rootpath, name, r_opts->rootpathlen)) {
 90 			fprintf(stderr, "%s:  %s is not located in %s\n",
 91 				r_opts->progname, name, r_opts->rootpath);
 92 			return -1;
 93 		}
 94 		name += r_opts->rootpathlen;
 95 	}
 96 
 97 	if (r_opts->rootpath != NULL && name[0] == '\0')
 98 		/* this is actually the root dir of the alt root */
 99 		return selabel_lookup_raw(r_opts->hnd, con, "/", sb->st_mode);
100 	else
101 		return selabel_lookup_raw(r_opts->hnd, con, name, sb->st_mode);
102 }
103 static int restore(FTSENT *ftsent, int recurse)
104 {
105 	char *my_file = strdupa(ftsent->fts_path);
106 	int ret = -1;
107 	security_context_t curcon = NULL, newcon = NULL;
108 	float progress;
109 	if (match(my_file, ftsent->fts_statp, &newcon) < 0) {
110 		if ((errno == ENOENT) && (!recurse))
111 			fprintf(stderr, "%s:  Warning no default label for %s\n", r_opts->progname, my_file);
112 
113 		/* Check for no matching specification. */
114 		return (errno == ENOENT) ? 0 : -1;
115 	}
116 
117 	if (r_opts->progress) {
118 		r_opts->count++;
119 		if (r_opts->count % STAR_COUNT == 0) {
120 			if (r_opts->progress == 1) {
121 				fprintf(stdout, "*");
122 			} else {
123 				if (r_opts->nfile > 0) {
124 					progress = (r_opts->count < r_opts->nfile) ? (100.0 * r_opts->count / r_opts->nfile) : 100;
125 					fprintf(stdout, "\r%-.1f%%", progress);
126 				}
127 			}
128 			fflush(stdout);
129 		}
130 	}
131 
132 	/*
133 	 * Try to add an association between this inode and
134 	 * this specification.  If there is already an association
135 	 * for this inode and it conflicts with this specification,
136 	 * then use the last matching specification.
137 	 */
138 	if (r_opts->add_assoc) {
139 		ret = filespec_add(ftsent->fts_statp->st_ino, newcon, my_file);
140 		if (ret < 0)
141 			goto err;
142 
143 		if (ret > 0)
144 			/* There was already an association and it took precedence. */
145 			goto out;
146 	}
147 
148 	if (r_opts->debug) {
149 		printf("%s:  %s matched by %s\n", r_opts->progname, my_file, newcon);
150 	}
151 
152 	/*
153 	 * Do not relabel if their is no default specification for this file
154 	 */
155 
156 	if (strcmp(newcon, "<<none>>") == 0) {
157 		goto out;
158 	}
159 
160 	/* Get the current context of the file. */
161 	ret = lgetfilecon_raw(ftsent->fts_accpath, &curcon);
162 	if (ret < 0) {
163 		if (errno == ENODATA) {
164 			curcon = NULL;
165 		} else {
166 			fprintf(stderr, "%s get context on %s failed: '%s'\n",
167 				r_opts->progname, my_file, strerror(errno));
168 			goto err;
169 		}
170 	}
171 
172 	/* lgetfilecon returns number of characters and ret needs to be reset
173 	 * to 0.
174 	 */
175 	ret = 0;
176 
177 	/*
178 	 * Do not relabel the file if the file is already labeled according to
179 	 * the specification.
180 	 */
181 	if (curcon && (strcmp(curcon, newcon) == 0)) {
182 		goto out;
183 	}
184 
185 	if (!r_opts->force && curcon && (is_context_customizable(curcon) > 0)) {
186 		if (r_opts->verbose > 1) {
187 			fprintf(stderr,
188 				"%s: %s not reset customized by admin to %s\n",
189 				r_opts->progname, my_file, curcon);
190 		}
191 		goto out;
192 	}
193 
194 	/*
195 	 *  Do not change label unless this is a force or the type is different
196 	 */
197 	if (!r_opts->force && curcon) {
198 		int types_differ = 0;
199 		context_t cona;
200 		context_t conb;
201 		int err = 0;
202 		cona = context_new(curcon);
203 		if (! cona) {
204 			goto out;
205 		}
206 		conb = context_new(newcon);
207 		if (! conb) {
208 			context_free(cona);
209 			goto out;
210 		}
211 
212 		types_differ = strcmp(context_type_get(cona), context_type_get(conb));
213 		if (types_differ) {
214 			err |= context_user_set(conb, context_user_get(cona));
215 			err |= context_role_set(conb, context_role_get(cona));
216 			err |= context_range_set(conb, context_range_get(cona));
217 			if (!err) {
218 				freecon(newcon);
219 				newcon = strdup(context_str(conb));
220 			}
221 		}
222 		context_free(cona);
223 		context_free(conb);
224 
225 		if (!types_differ || err) {
226 			goto out;
227 		}
228 	}
229 
230 	if (r_opts->verbose) {
231 		printf("%s reset %s context %s->%s\n",
232 		       r_opts->progname, my_file, curcon ?: "", newcon);
233 	}
234 
235 	if (r_opts->logging && r_opts->change) {
236 		if (curcon)
237 			syslog(LOG_INFO, "relabeling %s from %s to %s\n",
238 			       my_file, curcon, newcon);
239 		else
240 			syslog(LOG_INFO, "labeling %s to %s\n",
241 			       my_file, newcon);
242 	}
243 
244 	if (r_opts->outfile)
245 		fprintf(r_opts->outfile, "%s\n", my_file);
246 
247 	/*
248 	 * Do not relabel the file if -n was used.
249 	 */
250 	if (!r_opts->change)
251 		goto out;
252 
253 	/*
254 	 * Relabel the file to the specified context.
255 	 */
256 	ret = lsetfilecon(ftsent->fts_accpath, newcon);
257 	if (ret) {
258 		fprintf(stderr, "%s set context %s->%s failed:'%s'\n",
259 			r_opts->progname, my_file, newcon, strerror(errno));
260 		goto skip;
261 	}
262 	ret = 0;
263 out:
264 	freecon(curcon);
265 	freecon(newcon);
266 	return ret;
267 skip:
268 	freecon(curcon);
269 	freecon(newcon);
270 	return SKIP;
271 err:
272 	freecon(curcon);
273 	freecon(newcon);
274 	return ERR;
275 }
276 /*
277  * Apply the last matching specification to a file.
278  * This function is called by fts on each file during
279  * the directory traversal.
280  */
281 static int apply_spec(FTSENT *ftsent, int recurse)
282 {
283 	if (ftsent->fts_info == FTS_DNR) {
284 		fprintf(stderr, "%s:  unable to read directory %s\n",
285 			r_opts->progname, ftsent->fts_path);
286 		return SKIP;
287 	}
288 	
289 	int rc = restore(ftsent, recurse);
290 	if (rc == ERR) {
291 		if (!r_opts->abort_on_error)
292 			return SKIP;
293 	}
294 	return rc;
295 }
296 
297 #include <sys/statvfs.h>
298 
299 static int process_one(char *name, int recurse_this_path)
300 {
301 	int rc = 0;
302 	const char *namelist[2] = {name, NULL};
303 	dev_t dev_num = 0;
304 	FTS *fts_handle = NULL;
305 	FTSENT *ftsent = NULL;
306 
307 	if (r_opts == NULL){
308 		fprintf(stderr,
309 			"Must call initialize first!");
310 		goto err;
311 	}
312 
313 	fts_handle = fts_open((char **)namelist, r_opts->fts_flags, NULL);
314 	if (fts_handle  == NULL) {
315 		fprintf(stderr,
316 			"%s: error while labeling %s:  %s\n",
317 			r_opts->progname, namelist[0], strerror(errno));
318 		goto err;
319 	}
320 
321 
322 	ftsent = fts_read(fts_handle);
323 	if (ftsent == NULL) {
324 		fprintf(stderr,
325 			"%s: error while labeling %s:  %s\n",
326 			r_opts->progname, namelist[0], strerror(errno));
327 		goto err;
328 	}
329 
330 	/* Keep the inode of the first one. */
331 	dev_num = ftsent->fts_statp->st_dev;
332 
333 	do {
334 		rc = 0;
335 		/* Skip the post order nodes. */
336 		if (ftsent->fts_info == FTS_DP)
337 			continue;
338 		/* If the XDEV flag is set and the device is different */
339 		if (ftsent->fts_statp->st_dev != dev_num &&
340 		    FTS_XDEV == (r_opts->fts_flags & FTS_XDEV))
341 			continue;
342 		if (excludeCtr > 0) {
343 			if (exclude(ftsent->fts_path)) {
344 				fts_set(fts_handle, ftsent, FTS_SKIP);
345 				continue;
346 			}
347 		}
348 
349 		rc = apply_spec(ftsent, recurse_this_path);
350 		if (rc == SKIP)
351 			fts_set(fts_handle, ftsent, FTS_SKIP);
352 		if (rc == ERR)
353 			goto err;
354 		if (!recurse_this_path)
355 			break;
356 	} while ((ftsent = fts_read(fts_handle)) != NULL);
357 
358 out:
359 	if (r_opts->add_assoc) {
360 		if (!r_opts->quiet)
361 			filespec_eval();
362 		filespec_destroy();
363 	}
364 	if (fts_handle)
365 		fts_close(fts_handle);
366 	return rc;
367 
368 err:
369 	rc = -1;
370 	goto out;
371 }
372 
373 int process_glob(char *name, int recurse) {
374 	glob_t globbuf;
375 	size_t i = 0;
376 	int errors;
377 	memset(&globbuf, 0, sizeof(globbuf));
378 	errors = glob(name, GLOB_TILDE | GLOB_PERIOD | GLOB_NOCHECK, NULL, &globbuf);
379 	if (errors) 
380 		return errors;
381 
382 	for (i = 0; i < globbuf.gl_pathc; i++) {
383 		int len = strlen(globbuf.gl_pathv[i]) -2;
384 		if (len > 0 && strcmp(&globbuf.gl_pathv[i][len--], "/.") == 0)
385 			continue;
386 		if (len > 0 && strcmp(&globbuf.gl_pathv[i][len], "/..") == 0)
387 			continue;
388 		int rc = process_one_realpath(globbuf.gl_pathv[i], recurse);
389 		if (rc < 0)
390 			errors = rc;
391 	}
392 	globfree(&globbuf);
393 	return errors;
394 }
395 
396 int process_one_realpath(char *name, int recurse)
397 {
398 	int rc = 0;
399 	char *p;
400 	struct stat64 sb;
401 
402 	if (r_opts == NULL){
403 		fprintf(stderr,
404 			"Must call initialize first!");
405 		return -1;
406 	}
407 
408 	if (!r_opts->expand_realpath) {
409 		return process_one(name, recurse);
410 	} else {
411 		rc = lstat64(name, &sb);
412 		if (rc < 0) {
413 			if (r_opts->ignore_enoent && errno == ENOENT)
414 				return 0;
415 			fprintf(stderr, "%s:  lstat(%s) failed:  %s\n",
416 				r_opts->progname, name,	strerror(errno));
417 			return -1;
418 		}
419 
420 		if (S_ISLNK(sb.st_mode)) {
421 			char path[PATH_MAX + 1];
422 
423 			rc = realpath_not_final(name, path);
424 			if (rc < 0)
425 				return rc;
426 			rc = process_one(path, 0);
427 			if (rc < 0)
428 				return rc;
429 
430 			p = realpath(name, NULL);
431 			if (p) {
432 				rc = process_one(p, recurse);
433 				free(p);
434 			}
435 			return rc;
436 		} else {
437 			p = realpath(name, NULL);
438 			if (!p) {
439 				fprintf(stderr, "realpath(%s) failed %s\n", name,
440 					strerror(errno));
441 				return -1;
442 			}
443 			rc = process_one(p, recurse);
444 			free(p);
445 			return rc;
446 		}
447 	}
448 }
449 
450 int exclude(const char *file)
451 {
452 	int i = 0;
453 	for (i = 0; i < excludeCtr; i++) {
454 		if (strncmp
455 		    (file, excludeArray[i].directory,
456 		     excludeArray[i].size) == 0) {
457 			if (file[excludeArray[i].size] == 0
458 			    || file[excludeArray[i].size] == '/') {
459 				return 1;
460 			}
461 		}
462 	}
463 	return 0;
464 }
465 
466 int add_exclude(const char *directory)
467 {
468 	size_t len = 0;
469 
470 	if (directory == NULL || directory[0] != '/') {
471 		fprintf(stderr, "Full path required for exclude: %s.\n",
472 			directory);
473 		return 1;
474 	}
475 	if (excludeCtr == MAX_EXCLUDES) {
476 		fprintf(stderr, "Maximum excludes %d exceeded.\n",
477 			MAX_EXCLUDES);
478 		return 1;
479 	}
480 
481 	len = strlen(directory);
482 	while (len > 1 && directory[len - 1] == '/') {
483 		len--;
484 	}
485 	excludeArray[excludeCtr].directory = strndup(directory, len);
486 
487 	if (excludeArray[excludeCtr].directory == NULL) {
488 		fprintf(stderr, "Out of memory.\n");
489 		return 1;
490 	}
491 	excludeArray[excludeCtr++].size = len;
492 
493 	return 0;
494 }
495 
496 /*
497  * Evaluate the association hash table distribution.
498  */
499 static void filespec_eval(void)
500 {
501 	file_spec_t *fl;
502 	int h, used, nel, len, longest;
503 
504 	if (!fl_head)
505 		return;
506 
507 	used = 0;
508 	longest = 0;
509 	nel = 0;
510 	for (h = 0; h < HASH_BUCKETS; h++) {
511 		len = 0;
512 		for (fl = fl_head[h].next; fl; fl = fl->next) {
513 			len++;
514 		}
515 		if (len)
516 			used++;
517 		if (len > longest)
518 			longest = len;
519 		nel += len;
520 	}
521 
522 	if (r_opts->verbose > 1)
523 		printf
524 		    ("%s:  hash table stats: %d elements, %d/%d buckets used, longest chain length %d\n",
525 		     __FUNCTION__, nel, used, HASH_BUCKETS, longest);
526 }
527 
528 /*
529  * Destroy the association hash table.
530  */
531 static void filespec_destroy(void)
532 {
533 	file_spec_t *fl, *tmp;
534 	int h;
535 
536 	if (!fl_head)
537 		return;
538 
539 	for (h = 0; h < HASH_BUCKETS; h++) {
540 		fl = fl_head[h].next;
541 		while (fl) {
542 			tmp = fl;
543 			fl = fl->next;
544 			freecon(tmp->con);
545 			free(tmp->file);
546 			free(tmp);
547 		}
548 		fl_head[h].next = NULL;
549 	}
550 	free(fl_head);
551 	fl_head = NULL;
552 }
553 /*
554  * Try to add an association between an inode and a context.
555  * If there is a different context that matched the inode,
556  * then use the first context that matched.
557  */
558 static int filespec_add(ino_t ino, const security_context_t con, const char *file)
559 {
560 	file_spec_t *prevfl, *fl;
561 	int h, ret;
562 	struct stat64 sb;
563 
564 	if (!fl_head) {
565 		fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS);
566 		if (!fl_head)
567 			goto oom;
568 		memset(fl_head, 0, sizeof(file_spec_t) * HASH_BUCKETS);
569 	}
570 
571 	h = (ino + (ino >> HASH_BITS)) & HASH_MASK;
572 	for (prevfl = &fl_head[h], fl = fl_head[h].next; fl;
573 	     prevfl = fl, fl = fl->next) {
574 		if (ino == fl->ino) {
575 			ret = lstat64(fl->file, &sb);
576 			if (ret < 0 || sb.st_ino != ino) {
577 				freecon(fl->con);
578 				free(fl->file);
579 				fl->file = strdup(file);
580 				if (!fl->file)
581 					goto oom;
582 				fl->con = strdup(con);
583 				if (!fl->con)
584 					goto oom;
585 				return 1;
586 			}
587 
588 			if (strcmp(fl->con, con) == 0)
589 				return 1;
590 
591 			fprintf(stderr,
592 				"%s:  conflicting specifications for %s and %s, using %s.\n",
593 				__FUNCTION__, file, fl->file, fl->con);
594 			free(fl->file);
595 			fl->file = strdup(file);
596 			if (!fl->file)
597 				goto oom;
598 			return 1;
599 		}
600 
601 		if (ino > fl->ino)
602 			break;
603 	}
604 
605 	fl = malloc(sizeof(file_spec_t));
606 	if (!fl)
607 		goto oom;
608 	fl->ino = ino;
609 	fl->con = strdup(con);
610 	if (!fl->con)
611 		goto oom_freefl;
612 	fl->file = strdup(file);
613 	if (!fl->file)
614 		goto oom_freefl;
615 	fl->next = prevfl->next;
616 	prevfl->next = fl;
617 	return 0;
618       oom_freefl:
619 	free(fl);
620       oom:
621 	fprintf(stderr,
622 		"%s:  insufficient memory for file label entry for %s\n",
623 		__FUNCTION__, file);
624 	return -1;
625 }
626 
627 #include <sys/utsname.h>
628 int file_system_count(char *name) {
629 	struct statvfs statvfs_buf;
630 	int nfile = 0;
631 	memset(&statvfs_buf, 0, sizeof(statvfs_buf));
632 	if (!statvfs(name, &statvfs_buf)) {
633 		nfile = statvfs_buf.f_files - statvfs_buf.f_ffree;
634 	}
635 	return nfile;
636 }
637 
638 /*
639    Search /proc/mounts for all file systems that do not support extended
640    attributes and add them to the exclude directory table.  File systems
641    that support security labels have the seclabel option, return total file count
642 */
643 int exclude_non_seclabel_mounts()
644 {
645 	struct utsname uts;
646 	FILE *fp;
647 	size_t len;
648 	ssize_t num;
649 	int index = 0, found = 0;
650 	char *mount_info[4];
651 	char *buf = NULL, *item;
652 	int nfile = 0;
653 	/* Check to see if the kernel supports seclabel */
654 	if (uname(&uts) == 0 && strverscmp(uts.release, "2.6.30") < 0)
655 		return 0;
656 	if (is_selinux_enabled() <= 0)
657 		return 0;
658 
659 	fp = fopen("/proc/mounts", "r");
660 	if (!fp)
661 		return 0;
662 
663 	while ((num = getline(&buf, &len, fp)) != -1) {
664 		found = 0;
665 		index = 0;
666 		item = strtok(buf, " ");
667 		while (item != NULL) {
668 			mount_info[index] = item;
669 			if (index == 3)
670 				break;
671 			index++;
672 			item = strtok(NULL, " ");
673 		}
674 		if (index < 3) {
675 			fprintf(stderr,
676 				"/proc/mounts record \"%s\" has incorrect format.\n",
677 				buf);
678 			continue;
679 		}
680 
681 		/* remove pre-existing entry */
682 		remove_exclude(mount_info[1]);
683 
684 		item = strtok(mount_info[3], ",");
      (emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
685 		while (item != NULL) {
686 			if (strcmp(item, "seclabel") == 0) {
687 				found = 1;
688 				nfile += file_system_count(mount_info[1]);
689 				break;
690 			}
691 			item = strtok(NULL, ",");
692 		}
693 
694 		/* exclude mount points without the seclabel option */
695 		if (!found)
696 			add_exclude(mount_info[1]);
697 	}
698 
699 	free(buf);
700 	fclose(fp);
701 	/* return estimated #Files + 5% for directories and hard links */
702 	return nfile * 1.05;
703 }
No issues found
  1 #include "restore.h"
  2 #include <unistd.h>
  3 #include <fcntl.h>
  4 #include <stdio_ext.h>
  5 #include <ctype.h>
  6 #include <regex.h>
  7 #include <sys/vfs.h>
  8 #define __USE_XOPEN_EXTENDED 1	/* nftw */
  9 #include <libgen.h>
 10 #ifdef USE_AUDIT
 11 #include <libaudit.h>
 12 
 13 #ifndef AUDIT_FS_RELABEL
 14 #define AUDIT_FS_RELABEL 2309
 15 #endif
 16 #endif
 17 
 18 
 19 /* cmdline opts*/
 20 
 21 static char *policyfile = NULL;
 22 static int warn_no_match = 0;
 23 static int null_terminated = 0;
 24 static struct restore_opts r_opts;
 25 
 26 #define STAT_BLOCK_SIZE 1
 27 
 28 /* setfiles will abort its operation after reaching the
 29  * following number of errors (e.g. invalid contexts),
 30  * unless it is used in "debug" mode (-d option).
 31  */
 32 #ifndef ABORT_ON_ERRORS
 33 #define ABORT_ON_ERRORS	10
 34 #endif
 35 
 36 #define SETFILES "setfiles"
 37 #define RESTORECON "restorecon"
 38 static int iamrestorecon;
 39 
 40 /* Behavior flags determined based on setfiles vs. restorecon */
 41 static int ctx_validate; /* Validate contexts */
 42 static const char *altpath; /* Alternate path to file_contexts */
 43 
 44 void usage(const char *const name)
 45 {
 46 	if (iamrestorecon) {
 47 		fprintf(stderr,
 48 			"usage:  %s [-iFnprRv0] [-e excludedir] [-o filename] pathname...\n"
 49 			"usage:  %s [-iFnprRv0] [-e excludedir] [-o filename] -f filename\n",
 50 			name, name);
 51 	} else {
 52 		fprintf(stderr,
 53 			"usage:  %s [-dilnpqvFW] [-e excludedir] [-o filename] [-r alt_root_path] spec_file pathname...\n"
 54 			"usage:  %s [-dilnpqvFW] [-e excludedir] [-o filename] [-r alt_root_path] spec_file -f filename\n"
 55 			"usage:  %s -s [-dilnpqvFW] [-o filename] spec_file\n"
 56 			"usage:  %s -c policyfile spec_file\n",
 57 			name, name, name, name);
 58 	}
 59 	exit(1);
 60 }
 61 
 62 static int nerr = 0;
 63 
 64 void inc_err()
 65 {
 66 	nerr++;
 67 	if (nerr > ABORT_ON_ERRORS - 1 && !r_opts.debug) {
 68 		fprintf(stderr, "Exiting after %d errors.\n", ABORT_ON_ERRORS);
 69 		exit(1);
 70 	}
 71 }
 72 
 73 
 74 
 75 void set_rootpath(const char *arg)
 76 {
 77 	int len;
 78 
 79 	r_opts.rootpath = strdup(arg);
 80 	if (NULL == r_opts.rootpath) {
 81 		fprintf(stderr, "%s:  insufficient memory for r_opts.rootpath\n",
 82 			r_opts.progname);
 83 		exit(1);
 84 	}
 85 
 86 	/* trim trailing /, if present */
 87 	len = strlen(r_opts.rootpath);
 88 	while (len && ('/' == r_opts.rootpath[len - 1]))
 89 		r_opts.rootpath[--len] = 0;
 90 	r_opts.rootpathlen = len;
 91 }
 92 
 93 int canoncon(char **contextp)
 94 {
 95 	char *context = *contextp, *tmpcon;
 96 	int rc = 0;
 97 
 98 	if (policyfile) {
 99 		if (sepol_check_context(context) < 0) {
100 			fprintf(stderr, "invalid context %s\n", context);
101 			exit(1);
102 		}
103 	} else if (security_canonicalize_context_raw(context, &tmpcon) == 0) {
104 		free(context);
105 		*contextp = tmpcon;
106 	} else if (errno != ENOENT) {
107 		rc = -1;
108 		inc_err();
109 	}
110 
111 	return rc;
112 }
113 
114 #ifndef USE_AUDIT
115 static void maybe_audit_mass_relabel(int mass_relabel __attribute__((unused)),
116 				     int mass_relabel_errs __attribute__((unused)))
117 {
118 #else
119 static void maybe_audit_mass_relabel(int mass_relabel, int mass_relabel_errs)
120 {
121 	int audit_fd = -1;
122 	int rc = 0;
123 
124 	if (!mass_relabel)		/* only audit a forced full relabel */
125 		return;
126 
127 	audit_fd = audit_open();
128 
129 	if (audit_fd < 0) {
130 		fprintf(stderr, "Error connecting to audit system.\n");
131 		exit(-1);
132 	}
133 
134 	rc = audit_log_user_message(audit_fd, AUDIT_FS_RELABEL,
135 				    "op=mass relabel", NULL, NULL, NULL, !mass_relabel_errs);
136 	if (rc <= 0) {
137 		fprintf(stderr, "Error sending audit message: %s.\n",
138 			strerror(errno));
139 		/* exit(-1); -- don't exit atm. as fix for eff_cap isn't in most kernels */
140 	}
141 	audit_close(audit_fd);
142 #endif
143 }
144 
145 int main(int argc, char **argv)
146 {
147 	struct stat sb;
148 	int opt, i = 0;
149 	char *input_filename = NULL;
150 	int use_input_file = 0;
151 	char *buf = NULL;
152 	size_t buf_len;
153 	int recurse; /* Recursive descent. */
154 	char *base;
155 	int mass_relabel = 0, errors = 0;
156 	
157 	memset(&r_opts, 0, sizeof(r_opts));
158 
159 	/* Initialize variables */
160 	r_opts.progress = 0;
161 	r_opts.count = 0;
162 	r_opts.nfile = 0;
163 	r_opts.debug = 0;
164 	r_opts.change = 1;
165 	r_opts.verbose = 0;
166 	r_opts.logging = 0;
167 	r_opts.rootpath = NULL;
168 	r_opts.rootpathlen = 0;
169 	r_opts.outfile = NULL;
170 	r_opts.force = 0;
171 	r_opts.hard_links = 1;
172 
173 	altpath = NULL;
174 
175 	r_opts.progname = strdup(argv[0]);
176 	if (!r_opts.progname) {
177 		fprintf(stderr, "%s:  Out of memory!\n", argv[0]);
178 		exit(1);
179 	}
180 	base = basename(r_opts.progname);
181 	
182 	if (!strcmp(base, SETFILES)) {
183 		/* 
184 		 * setfiles:  
185 		 * Recursive descent,
186 		 * Does not expand paths via realpath, 
187 		 * Aborts on errors during the file tree walk, 
188 		 * Try to track inode associations for conflict detection,
189 		 * Does not follow mounts,
190 		 * Validates all file contexts at init time. 
191 		 */
192 		iamrestorecon = 0;
193 		recurse = 1;
194 		r_opts.expand_realpath = 0;
195 		r_opts.abort_on_error = 1;
196 		r_opts.add_assoc = 1;
197 		r_opts.fts_flags = FTS_PHYSICAL | FTS_XDEV;
198 		ctx_validate = 1;
199 	} else {
200 		/*
201 		 * restorecon:  
202 		 * No recursive descent unless -r/-R,
203 		 * Expands paths via realpath, 
204 		 * Do not abort on errors during the file tree walk,
205 		 * Do not try to track inode associations for conflict detection,
206 		 * Follows mounts,
207 		 * Does lazy validation of contexts upon use. 
208 		 */
209 		if (strcmp(base, RESTORECON) && !r_opts.quiet) 
210 			printf("Executed with an unrecognized name (%s), defaulting to %s behavior.\n", base, RESTORECON);
211 		iamrestorecon = 1;
212 		recurse = 0;
213 		r_opts.expand_realpath = 1;
214 		r_opts.abort_on_error = 0;
215 		r_opts.add_assoc = 0;
216 		r_opts.fts_flags = FTS_PHYSICAL;
217 		ctx_validate = 0;
218 
219 		/* restorecon only:  silent exit if no SELinux.
220 		   Allows unconditional execution by scripts. */
221 		if (is_selinux_enabled() <= 0)
222 			exit(0);
223 	}
224 
225 	/* This must happen before getopt. */
226 	r_opts.nfile = exclude_non_seclabel_mounts();
227 
228 	/* Process any options. */
229 	while ((opt = getopt(argc, argv, "c:de:f:hilno:pqrsvFRW0")) > 0) {
230 		switch (opt) {
231 		case 'c':
232 			{
233 				FILE *policystream;
234 
235 				if (iamrestorecon)
236 					usage(argv[0]);
237 
238 				policyfile = optarg;
239 
240 				policystream = fopen(policyfile, "r");
241 				if (!policystream) {
242 					fprintf(stderr,
243 						"Error opening %s: %s\n",
244 						policyfile, strerror(errno));
245 					exit(1);
246 				}
247 				__fsetlocking(policystream,
248 					      FSETLOCKING_BYCALLER);
249 
250 				if (sepol_set_policydb_from_file(policystream) <
251 				    0) {
252 					fprintf(stderr,
253 						"Error reading policy %s: %s\n",
254 						policyfile, strerror(errno));
255 					exit(1);
256 				}
257 				fclose(policystream);
258 
259 				ctx_validate = 1;
260 
261 				break;
262 			}
263 		case 'e':
264 			remove_exclude(optarg);
265 			if (lstat(optarg, &sb) < 0 && errno != EACCES) {
266 				fprintf(stderr, "Can't stat exclude path \"%s\", %s - ignoring.\n",
267 					optarg, strerror(errno));
268 				break;
269 			}
270 			if (add_exclude(optarg))
271 				exit(1);
272 			break;
273 		case 'f':
274 			use_input_file = 1;
275 			input_filename = optarg;
276 			break;			
277 		case 'd':
278 			if (iamrestorecon)
279 				usage(argv[0]);
280 			r_opts.debug = 1;
281 			break;
282 		case 'i':
283 			r_opts.ignore_enoent = 1;
284 			break;
285 		case 'l':
286 			r_opts.logging = 1;
287 			break;
288 		case 'F':
289 			r_opts.force = 1;
290 			break;
291 		case 'n':
292 			r_opts.change = 0;
293 			break;
294 		case 'o':
295 			if (strcmp(optarg, "-") == 0) {
296 				r_opts.outfile = stdout;
297 				break;
298 			}
299 
300 			r_opts.outfile = fopen(optarg, "w");
301 			if (!r_opts.outfile) {
302 				fprintf(stderr, "Error opening %s: %s\n",
303 					optarg, strerror(errno));
304 
305 				usage(argv[0]);
306 			}
307 			__fsetlocking(r_opts.outfile, FSETLOCKING_BYCALLER);
308 			break;
309 		case 'q':
310 			r_opts.quiet = 1;
311 			break;
312 		case 'R':
313 		case 'r':
314 			if (iamrestorecon) {
315 				recurse = 1;
316 				break;
317 			}
318 			if (optind + 1 >= argc) {
319 				fprintf(stderr, "usage:  %s -r rootpath\n",
320 					argv[0]);
321 				exit(1);
322 			}
323 			if (NULL != r_opts.rootpath) {
324 				fprintf(stderr,
325 					"%s: only one -r can be specified\n",
326 					argv[0]);
327 				exit(1);
328 			}
329 			set_rootpath(argv[optind++]);
330 			break;
331 		case 's':
332 			use_input_file = 1;
333 			input_filename = "-";
334 			r_opts.add_assoc = 0;
335 			break;
336 		case 'v':
337 			if (r_opts.progress) {
338 				fprintf(stderr,
339 					"Progress and Verbose mutually exclusive\n");
340 				exit(1);
341 			}
342 			r_opts.verbose++;
343 			break;
344 		case 'p':
345 			if (r_opts.verbose) {
346 				fprintf(stderr,
347 					"Progress and Verbose mutually exclusive\n");
348 				usage(argv[0]);
349 			}
350 			r_opts.progress++;
351 			break;
352 		case 'W':
353 			warn_no_match = 1;
354 			break;
355 		case '0':
356 			null_terminated = 1;
357 			break;
358 		case 'h':
359 		case '?':
360 			usage(argv[0]);
361 		}
362 	}
363 
364 	for (i = optind; i < argc; i++) {
365 		if (!strcmp(argv[i], "/")) {
366 			mass_relabel = 1;
367 			if (r_opts.progress)
368 				r_opts.progress++;
369 		}
370 	}
371 
372 	if (!iamrestorecon) {
373 		if (policyfile) {
374 			if (optind != (argc - 1))
375 				usage(argv[0]);
376 		} else if (use_input_file) {
377 			if (optind != (argc - 1)) {
378 				/* Cannot mix with pathname arguments. */
379 				usage(argv[0]);
380 			}
381 		} else {
382 			if (optind > (argc - 2))
383 				usage(argv[0]);
384 		}
385 
386 		/* Use our own invalid context checking function so that
387 		   we can support either checking against the active policy or
388 		   checking against a binary policy file. */
389 		selinux_set_callback(SELINUX_CB_VALIDATE,
390 				     (union selinux_callback)&canoncon);
391 
392 		if (stat(argv[optind], &sb) < 0) {
393 			perror(argv[optind]);
394 			exit(1);
395 		}
396 		if (!S_ISREG(sb.st_mode)) {
397 			fprintf(stderr, "%s:  spec file %s is not a regular file.\n",
398 				argv[0], argv[optind]);
399 			exit(1);
400 		}
401 
402 		altpath = argv[optind];
403 		optind++;
404 	} else if (argc == 1)
405 		usage(argv[0]);
406 
407 	/* Load the file contexts configuration and check it. */
408 	r_opts.selabel_opt_validate = (ctx_validate ? (char *)1 : NULL);
409 	r_opts.selabel_opt_path = altpath;
410 
411 	if (nerr)
412 		exit(1);
413 
414 	restore_init(&r_opts);
415 	if (use_input_file) {
416 		FILE *f = stdin;
417 		ssize_t len;
418 		int delim;
419 		if (strcmp(input_filename, "-") != 0)
420 			f = fopen(input_filename, "r");
421 		if (f == NULL) {
422 			fprintf(stderr, "Unable to open %s: %s\n", input_filename,
423 				strerror(errno));
424 			usage(argv[0]);
425 		}
426 		__fsetlocking(f, FSETLOCKING_BYCALLER);
427 
428 		delim = (null_terminated != 0) ? '\0' : '\n';
429 		while ((len = getdelim(&buf, &buf_len, delim, f)) > 0) {
430 			buf[len - 1] = 0;
431 			if (!strcmp(buf, "/"))
432 				mass_relabel = 1;
433 			errors |= process_glob(buf, recurse) < 0;
434 		}
435 		if (strcmp(input_filename, "-") != 0)
436 			fclose(f);
437 	} else {
438 		for (i = optind; i < argc; i++)
439 			errors |= process_glob(argv[i], recurse) < 0;
440 	}
441 	
442 	maybe_audit_mass_relabel(mass_relabel, errors);
443 
444 	if (warn_no_match)
445 		selabel_stats(r_opts.hnd);
446 
447 	selabel_close(r_opts.hnd);
448 	restore_finish();
449 
450 	if (r_opts.outfile)
451 		fclose(r_opts.outfile);
452 
453 	if (r_opts.progress && r_opts.count >= STAR_COUNT)
454 		printf("\n");
455 	exit(errors);
456 }
No issues found
  1 #include <unistd.h>
  2 #include <stdlib.h>
  3 #include <stdio.h>
  4 #include <string.h>
  5 #include <sys/stat.h>
  6 #include <fcntl.h>
  7 #include <errno.h>
  8 #include <syslog.h>
  9 #include <getopt.h>
 10 #include <pwd.h>
 11 #include <selinux/selinux.h>
 12 #include <semanage/handle.h>
 13 #include <semanage/booleans_local.h>
 14 #include <semanage/booleans_active.h>
 15 #include <semanage/boolean_record.h>
 16 #include <errno.h>
 17 
 18 int permanent = 0;
 19 int reload = 1;
 20 
 21 int setbool(char **list, size_t start, size_t end);
 22 
 23 void usage(void)
 24 {
 25 	fputs
 26 	    ("\nUsage:  setsebool [ -NP ] boolean value | bool1=val1 bool2=val2...\n\n",
 27 	     stderr);
 28 	exit(1);
 29 }
 30 
 31 int main(int argc, char **argv)
 32 {
 33 	size_t rc;
 34 	int clflag;		/* holds codes for command line flags */
 35 	if (argc < 2)
 36 		usage();
 37 
 38 	if (is_selinux_enabled() <= 0) {
 39 		fputs("setsebool:  SELinux is disabled.\n", stderr);
 40 		return 1;
 41 	}
 42 
 43 	while (1) {
 44 		clflag = getopt(argc, argv, "PN");
 45 		if (clflag == -1)
 46 			break;
 47 
 48 		switch (clflag) {
 49 		case 'P':
 50 			permanent = 1;
 51 			break;
 52 		case 'N':
 53 		        reload = 0;
 54 			break;
 55 		default:
 56 			usage();
 57 			break;
 58 		}
 59 	}
 60 
 61 	if (argc - optind < 1) {
 62 		fprintf(stderr, "Error: boolean name required\n");
 63 		usage();
 64 	}
 65 
 66 	/* Check to see which way we are being called. If a '=' is passed,
 67 	   we'll enforce the list syntax. If not we'll enforce the original
 68 	   syntax for backward compatibility. */
 69 	if (strchr(argv[optind], '=') == 0) {
 70 		int len;
 71 		char *bool_list[1];
 72 
 73 		if ((argc - optind) != 2)
 74 			usage();
 75 
 76 		/* Add 1 for the '=' */
 77 		len = strlen(argv[optind]) + strlen(argv[optind + 1]) + 2;
 78 		bool_list[0] = (char *)malloc(len);
 79 		if (bool_list[0] == 0) {
 80 			fputs("Out of memory - aborting\n", stderr);
 81 			return 1;
 82 		}
 83 		snprintf(bool_list[0], len, "%s=%s", argv[optind],
 84 			 argv[optind + 1]);
 85 		rc = setbool(bool_list, 0, 1);
 86 		free(bool_list[0]);
 87 	} else
 88 		rc = setbool(argv, optind, argc);
 89 
 90 	return rc;
 91 }
 92 
 93 /* Apply temporal boolean changes to policy via libselinux */
 94 static int selinux_set_boolean_list(size_t boolcnt,
 95 				    SELboolean * boollist)
 96 {
 97 
 98 	if (security_set_boolean_list(boolcnt, boollist, 0)) {
 99 		if (errno == ENOENT)
100 			fprintf(stderr, "Could not change active booleans: "
101 				"Invalid boolean\n");
102 		else if (errno) {
103 			if (getuid() == 0) {
104 				perror("Could not change active booleans");
105 			} else {
106 				perror("Could not change active booleans. Please try as root");
107 			}
108 		}
109 
110 		return -1;
111 	}
112 
113 	return 0;
114 }
115 
116 /* Apply permanent boolean changes to policy via libsemanage */
117 static int semanage_set_boolean_list(size_t boolcnt,
118 				     SELboolean * boollist)
119 {
120 
121 	size_t j;
122 	semanage_handle_t *handle = NULL;
123 	semanage_bool_t *boolean = NULL;
124 	semanage_bool_key_t *bool_key = NULL;
125 	int managed;
126 
127 	handle = semanage_handle_create();
128 	if (handle == NULL) {
129 		fprintf(stderr, "Could not create semanage library handle\n");
130 		goto err;
131 	}
132 
133 	managed = semanage_is_managed(handle);
134 	if (managed < 0) {
135 		fprintf(stderr,
136 			"Error when checking whether policy is managed\n");
137 		goto err;
138 
139 	} else if (managed == 0) {
140 		if (getuid() == 0) {
141 			fprintf(stderr,
142 				"Cannot set persistent booleans without managed policy.\n");
143 		} else {
144 			fprintf(stderr,
145 				"Cannot set persistent booleans, please try as root.\n");
146 		}
147 		goto err;
148 	}
149 
150 	if (semanage_connect(handle) < 0)
151 		goto err;
152 
153 	if (semanage_begin_transaction(handle) < 0)
154 		goto err;
155 
156 	for (j = 0; j < boolcnt; j++) {
157 
158 		if (semanage_bool_create(handle, &boolean) < 0)
159 			goto err;
160 
161 		if (semanage_bool_set_name(handle, boolean, boollist[j].name) <
162 		    0)
163 			goto err;
164 
165 		semanage_bool_set_value(boolean, boollist[j].value);
166 
167 		if (semanage_bool_key_extract(handle, boolean, &bool_key) < 0)
168 			goto err;
169 
170 		if (semanage_bool_modify_local(handle, bool_key,
171 						  boolean) < 0)
172 			goto err;
173 
174 		if (semanage_bool_set_active(handle, bool_key, boolean) < 0) {
175 			fprintf(stderr, "Could not change boolean %s\n",
176 				boollist[j].name);
177 			goto err;
178 		}
179 		semanage_bool_key_free(bool_key);
180 		semanage_bool_free(boolean);
181 		bool_key = NULL;
182 		boolean = NULL;
183 	}
184 
185 	semanage_set_reload(handle, reload);
186 	if (semanage_commit(handle) < 0)
187 		goto err;
188 
189 	semanage_disconnect(handle);
190 	semanage_handle_destroy(handle);
191 	return 0;
192 
193       err:
194 	semanage_bool_key_free(bool_key);
195 	semanage_bool_free(boolean);
196 	semanage_handle_destroy(handle);
197 	fprintf(stderr, "Could not change policy booleans\n");
198 	return -1;
199 }
200 
201 /* Given an array of strings in the form "boolname=value", a start index,
202    and a finish index...walk the list and set the bool. */
203 int setbool(char **list, size_t start, size_t end)
204 {
205 	char *name, *value_ptr;
206 	int j = 0, value;
207 	size_t i = start;
208 	size_t boolcnt = end - start;
209 	struct passwd *pwd;
210 	SELboolean *vallist = calloc(boolcnt, sizeof(SELboolean));
211 	if (!vallist)
212 		goto omem;
213 
214 	while (i < end) {
215 		name = list[i];
216 		value_ptr = strchr(list[i], '=');
217 		if (value_ptr == 0) {
218 			fprintf(stderr,
219 				"setsebool: '=' not found in boolean expression %s\n",
220 				list[i]);
221 			goto err;
222 		}
223 		*value_ptr = 0;
224 		value_ptr++;
225 		if (strcmp(value_ptr, "1") == 0 ||
226 		    strcasecmp(value_ptr, "true") == 0 ||
227 		    strcasecmp(value_ptr, "on") == 0)
228 			value = 1;
229 		else if (strcmp(value_ptr, "0") == 0 ||
230 			 strcasecmp(value_ptr, "false") == 0 ||
231 			 strcasecmp(value_ptr, "off") == 0)
232 			value = 0;
233 		else {
234 			fprintf(stderr, "setsebool: illegal value "
235 				"%s for boolean %s\n", value_ptr, name);
236 			goto err;
237 		}
238 
239 		vallist[j].value = value;
240 		vallist[j].name = strdup(name);
241 		if (!vallist[j].name)
242 			goto omem;
243 		i++;
244 		j++;
245 
246 		/* Now put it back */
247 		value_ptr--;
248 		*value_ptr = '=';
249 	}
250 
251 	if (permanent) {
252 		if (semanage_set_boolean_list(boolcnt, vallist) < 0)
253 			goto err;
254 	} else {
255 		if (selinux_set_boolean_list(boolcnt, vallist) < 0)
256 			goto err;
257 	}
258 
259 	/* Now log what was done */
260 	pwd = getpwuid(getuid());
261 	i = start;
262 	while (i < end) {
263 		name = list[i];
264 		value_ptr = strchr(name, '=');
265 		*value_ptr = 0;
266 		value_ptr++;
267 		if (pwd && pwd->pw_name)
268 			syslog(LOG_NOTICE,
269 			       "The %s policy boolean was changed to %s by %s",
270 			       name, value_ptr, pwd->pw_name);
271 		else
272 			syslog(LOG_NOTICE,
273 			       "The %s policy boolean was changed to %s by uid:%d",
274 			       name, value_ptr, getuid());
275 		i++;
276 	}
277 
278 	for (i = 0; i < boolcnt; i++)
279 		free(vallist[i].name);
280 	free(vallist);
281 	return 0;
282 
283       omem:
284 	fprintf(stderr, "setsebool: out of memory");
285 
286       err:
287 	if (vallist) {
288 		for (i = 0; i < boolcnt; i++)
289 			free(vallist[i].name);
290 		free(vallist);
291 	}
292 	return -1;
293 }