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 }