Source file clang-analyzer cppcheck cpychecker gcc
policycoreutils-2.1.13/load_policy/load_policy.c 0 0 0 0
policycoreutils-2.1.13/newrole/hashtab.c 0 0 0 0
policycoreutils-2.1.13/newrole/newrole.c 0 1 0 0
policycoreutils-2.1.13/restorecond/restorecond.c 1 0 0 2
policycoreutils-2.1.13/restorecond/stringslist.c 1 0 0 0
policycoreutils-2.1.13/restorecond/user.c 0 0 0 0
policycoreutils-2.1.13/restorecond/utmpwatcher.c 0 0 0 0
policycoreutils-2.1.13/restorecond/watch.c 1 0 0 0
policycoreutils-2.1.13/run_init/open_init_pty.c 0 0 0 0
policycoreutils-2.1.13/run_init/run_init.c 0 0 0 0
policycoreutils-2.1.13/sandbox/seunshare.c 1 1 0 0
policycoreutils-2.1.13/secon/secon.c 0 0 0 0
policycoreutils-2.1.13/semanage/default_encoding/default_encoding.c 0 0 2 0
policycoreutils-2.1.13/semodule/semodule.c 0 0 0 0
policycoreutils-2.1.13/semodule_deps/semodule_deps.c 0 0 0 0
policycoreutils-2.1.13/semodule_expand/semodule_expand.c 0 0 0 0
policycoreutils-2.1.13/semodule_link/semodule_link.c 0 0 0 0
policycoreutils-2.1.13/semodule_package/semodule_package.c 0 0 0 0
policycoreutils-2.1.13/semodule_package/semodule_unpackage.c 0 0 0 0
policycoreutils-2.1.13/sepolgen-ifgen/sepolgen-ifgen-attr-helper.c 0 0 0 0
policycoreutils-2.1.13/sepolicy/common.h 0 0 4 0
policycoreutils-2.1.13/sepolicy/info.c 0 0 4 0
policycoreutils-2.1.13/sepolicy/policy.c 0 0 1 0
policycoreutils-2.1.13/sepolicy/search.c 4 0 9 0
policycoreutils-2.1.13/sestatus/sestatus.c 0 0 0 0
policycoreutils-2.1.13/setfiles/restore.c 1 0 0 2
policycoreutils-2.1.13/setfiles/setfiles.c 0 0 0 0
policycoreutils-2.1.13/setsebool/setsebool.c 0 0 0 0

policycoreutils-2.1.13/load_policy/load_policy.c

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 }

policycoreutils-2.1.13/newrole/hashtab.c

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 }

policycoreutils-2.1.13/newrole/newrole.c

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);
Used file that is not opened.
(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() */

policycoreutils-2.1.13/restorecond/restorecond.c

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);
ignoring return value of 'write', declared with attribute warn_unused_result
(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;
Access to field 'pw_dir' results in a dereference of a null pointer (loaded from variable 'pwd')
(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);
ignoring return value of 'daemon', declared with attribute warn_unused_result
(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 }

policycoreutils-2.1.13/restorecond/stringslist.c

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);
Access to field 'string' results in a dereference of a null pointer (loaded from variable 'newptr')
(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

policycoreutils-2.1.13/restorecond/user.c

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 }

policycoreutils-2.1.13/restorecond/utmpwatcher.c

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

policycoreutils-2.1.13/restorecond/watch.c

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);
Access to field 'wd' results in a dereference of a null pointer (loaded from variable 'ptr')
(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 }

policycoreutils-2.1.13/run_init/open_init_pty.c

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() */

policycoreutils-2.1.13/run_init/run_init.c

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() */

policycoreutils-2.1.13/sandbox/seunshare.c

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;
The left operand to '|' is always 0
(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", &current_runtime); 433 cgroup_get_value_int64(cgroup_get_controller(curr, "cpu"), "cpu.rt_period_us", &current_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", &current_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);