xref: /aosp_15_r20/external/selinux/libsemanage/src/genhomedircon.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker /* Author: Mark Goldman	  <[email protected]>
2*2d543d20SAndroid Build Coastguard Worker  * 	   Paul Rosenfeld <[email protected]>
3*2d543d20SAndroid Build Coastguard Worker  * 	   Todd C. Miller <[email protected]>
4*2d543d20SAndroid Build Coastguard Worker  *
5*2d543d20SAndroid Build Coastguard Worker  * Copyright (C) 2007 Tresys Technology, LLC
6*2d543d20SAndroid Build Coastguard Worker  *
7*2d543d20SAndroid Build Coastguard Worker  *  This library is free software; you can redistribute it and/or modify
8*2d543d20SAndroid Build Coastguard Worker  *  it under the terms of the GNU Lesser General Public License as
9*2d543d20SAndroid Build Coastguard Worker  *  published by the Free Software Foundation; either version 2.1 of the
10*2d543d20SAndroid Build Coastguard Worker  *  License, or (at your option) any later version.
11*2d543d20SAndroid Build Coastguard Worker  *
12*2d543d20SAndroid Build Coastguard Worker  *  This library is distributed in the hope that it will be useful, but
13*2d543d20SAndroid Build Coastguard Worker  *  WITHOUT ANY WARRANTY; without even the implied warranty of
14*2d543d20SAndroid Build Coastguard Worker  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15*2d543d20SAndroid Build Coastguard Worker  *  Lesser General Public License for more details.
16*2d543d20SAndroid Build Coastguard Worker  *
17*2d543d20SAndroid Build Coastguard Worker  *  You should have received a copy of the GNU Lesser General Public
18*2d543d20SAndroid Build Coastguard Worker  *  License along with this library; if not, write to the Free Software
19*2d543d20SAndroid Build Coastguard Worker  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20*2d543d20SAndroid Build Coastguard Worker  *  02110-1301  USA
21*2d543d20SAndroid Build Coastguard Worker  */
22*2d543d20SAndroid Build Coastguard Worker 
23*2d543d20SAndroid Build Coastguard Worker #include <semanage/handle.h>
24*2d543d20SAndroid Build Coastguard Worker #include <semanage/seusers_policy.h>
25*2d543d20SAndroid Build Coastguard Worker #include <semanage/users_policy.h>
26*2d543d20SAndroid Build Coastguard Worker #include <semanage/user_record.h>
27*2d543d20SAndroid Build Coastguard Worker #include <semanage/fcontext_record.h>
28*2d543d20SAndroid Build Coastguard Worker #include <semanage/fcontexts_policy.h>
29*2d543d20SAndroid Build Coastguard Worker #include <sepol/context.h>
30*2d543d20SAndroid Build Coastguard Worker #include <sepol/context_record.h>
31*2d543d20SAndroid Build Coastguard Worker #include "fcontext_internal.h"
32*2d543d20SAndroid Build Coastguard Worker #include "semanage_store.h"
33*2d543d20SAndroid Build Coastguard Worker #include "seuser_internal.h"
34*2d543d20SAndroid Build Coastguard Worker #include "user_internal.h"
35*2d543d20SAndroid Build Coastguard Worker #include "debug.h"
36*2d543d20SAndroid Build Coastguard Worker 
37*2d543d20SAndroid Build Coastguard Worker #include "utilities.h"
38*2d543d20SAndroid Build Coastguard Worker #include "genhomedircon.h"
39*2d543d20SAndroid Build Coastguard Worker 
40*2d543d20SAndroid Build Coastguard Worker #include <assert.h>
41*2d543d20SAndroid Build Coastguard Worker #include <ctype.h>
42*2d543d20SAndroid Build Coastguard Worker #include <limits.h>
43*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
44*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
45*2d543d20SAndroid Build Coastguard Worker #include <string.h>
46*2d543d20SAndroid Build Coastguard Worker #include <sys/types.h>
47*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
48*2d543d20SAndroid Build Coastguard Worker #include <fcntl.h>
49*2d543d20SAndroid Build Coastguard Worker #include <pwd.h>
50*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
51*2d543d20SAndroid Build Coastguard Worker #include <unistd.h>
52*2d543d20SAndroid Build Coastguard Worker #include <regex.h>
53*2d543d20SAndroid Build Coastguard Worker #include <grp.h>
54*2d543d20SAndroid Build Coastguard Worker #include <search.h>
55*2d543d20SAndroid Build Coastguard Worker 
56*2d543d20SAndroid Build Coastguard Worker /* paths used in get_home_dirs() */
57*2d543d20SAndroid Build Coastguard Worker #define PATH_ETC_USERADD "/etc/default/useradd"
58*2d543d20SAndroid Build Coastguard Worker #define PATH_ETC_LIBUSER "/etc/libuser.conf"
59*2d543d20SAndroid Build Coastguard Worker #define PATH_DEFAULT_HOME "/home"
60*2d543d20SAndroid Build Coastguard Worker #define PATH_EXPORT_HOME "/export/home"
61*2d543d20SAndroid Build Coastguard Worker #define PATH_ETC_LOGIN_DEFS "/etc/login.defs"
62*2d543d20SAndroid Build Coastguard Worker 
63*2d543d20SAndroid Build Coastguard Worker /* other paths */
64*2d543d20SAndroid Build Coastguard Worker #define PATH_SHELLS_FILE "/etc/shells"
65*2d543d20SAndroid Build Coastguard Worker #define PATH_NOLOGIN_SHELL "/sbin/nologin"
66*2d543d20SAndroid Build Coastguard Worker 
67*2d543d20SAndroid Build Coastguard Worker /* comments written to context file */
68*2d543d20SAndroid Build Coastguard Worker #define COMMENT_FILE_CONTEXT_HEADER "#\n#\n# " \
69*2d543d20SAndroid Build Coastguard Worker 			"User-specific file contexts, generated via libsemanage\n" \
70*2d543d20SAndroid Build Coastguard Worker 			"# use semanage command to manage system users to change" \
71*2d543d20SAndroid Build Coastguard Worker 			" the file_context\n#\n#\n"
72*2d543d20SAndroid Build Coastguard Worker 
73*2d543d20SAndroid Build Coastguard Worker #define COMMENT_USER_HOME_CONTEXT "\n\n#\n# Home Context for user %s" \
74*2d543d20SAndroid Build Coastguard Worker 			"\n#\n\n"
75*2d543d20SAndroid Build Coastguard Worker 
76*2d543d20SAndroid Build Coastguard Worker /* placeholders used in the template file
77*2d543d20SAndroid Build Coastguard Worker    which are searched for and replaced */
78*2d543d20SAndroid Build Coastguard Worker #define TEMPLATE_HOME_ROOT "HOME_ROOT"
79*2d543d20SAndroid Build Coastguard Worker #define TEMPLATE_HOME_DIR "HOME_DIR"
80*2d543d20SAndroid Build Coastguard Worker /* these are legacy */
81*2d543d20SAndroid Build Coastguard Worker #define TEMPLATE_USER "USER"
82*2d543d20SAndroid Build Coastguard Worker #define TEMPLATE_ROLE "ROLE"
83*2d543d20SAndroid Build Coastguard Worker /* new names */
84*2d543d20SAndroid Build Coastguard Worker #define TEMPLATE_USERNAME "%{USERNAME}"
85*2d543d20SAndroid Build Coastguard Worker #define TEMPLATE_USERID "%{USERID}"
86*2d543d20SAndroid Build Coastguard Worker 
87*2d543d20SAndroid Build Coastguard Worker #define FALLBACK_SENAME "user_u"
88*2d543d20SAndroid Build Coastguard Worker #define FALLBACK_PREFIX "user"
89*2d543d20SAndroid Build Coastguard Worker #define FALLBACK_LEVEL "s0"
90*2d543d20SAndroid Build Coastguard Worker #define FALLBACK_NAME "[^/]+"
91*2d543d20SAndroid Build Coastguard Worker #define FALLBACK_UIDGID "[0-9]+"
92*2d543d20SAndroid Build Coastguard Worker #define DEFAULT_LOGIN "__default__"
93*2d543d20SAndroid Build Coastguard Worker 
94*2d543d20SAndroid Build Coastguard Worker #define CONTEXT_NONE "<<none>>"
95*2d543d20SAndroid Build Coastguard Worker 
96*2d543d20SAndroid Build Coastguard Worker typedef struct user_entry {
97*2d543d20SAndroid Build Coastguard Worker 	char *name;
98*2d543d20SAndroid Build Coastguard Worker 	char *uid;
99*2d543d20SAndroid Build Coastguard Worker 	char *gid;
100*2d543d20SAndroid Build Coastguard Worker 	char *sename;
101*2d543d20SAndroid Build Coastguard Worker 	char *prefix;
102*2d543d20SAndroid Build Coastguard Worker 	char *home;
103*2d543d20SAndroid Build Coastguard Worker 	char *level;
104*2d543d20SAndroid Build Coastguard Worker 	char *login;
105*2d543d20SAndroid Build Coastguard Worker 	char *homedir_role;
106*2d543d20SAndroid Build Coastguard Worker 	struct user_entry *next;
107*2d543d20SAndroid Build Coastguard Worker } genhomedircon_user_entry_t;
108*2d543d20SAndroid Build Coastguard Worker 
109*2d543d20SAndroid Build Coastguard Worker typedef struct {
110*2d543d20SAndroid Build Coastguard Worker 	const char *fcfilepath;
111*2d543d20SAndroid Build Coastguard Worker 	int usepasswd;
112*2d543d20SAndroid Build Coastguard Worker 	const char *homedir_template_path;
113*2d543d20SAndroid Build Coastguard Worker 	genhomedircon_user_entry_t *fallback;
114*2d543d20SAndroid Build Coastguard Worker 	semanage_handle_t *h_semanage;
115*2d543d20SAndroid Build Coastguard Worker 	sepol_policydb_t *policydb;
116*2d543d20SAndroid Build Coastguard Worker } genhomedircon_settings_t;
117*2d543d20SAndroid Build Coastguard Worker 
118*2d543d20SAndroid Build Coastguard Worker typedef struct {
119*2d543d20SAndroid Build Coastguard Worker 	const char *search_for;
120*2d543d20SAndroid Build Coastguard Worker 	const char *replace_with;
121*2d543d20SAndroid Build Coastguard Worker } replacement_pair_t;
122*2d543d20SAndroid Build Coastguard Worker 
123*2d543d20SAndroid Build Coastguard Worker typedef struct {
124*2d543d20SAndroid Build Coastguard Worker 	const char *dir;
125*2d543d20SAndroid Build Coastguard Worker 	int matched;
126*2d543d20SAndroid Build Coastguard Worker } fc_match_handle_t;
127*2d543d20SAndroid Build Coastguard Worker 
128*2d543d20SAndroid Build Coastguard Worker typedef struct IgnoreDir {
129*2d543d20SAndroid Build Coastguard Worker 	struct IgnoreDir *next;
130*2d543d20SAndroid Build Coastguard Worker 	char *dir;
131*2d543d20SAndroid Build Coastguard Worker } ignoredir_t;
132*2d543d20SAndroid Build Coastguard Worker 
133*2d543d20SAndroid Build Coastguard Worker ignoredir_t *ignore_head = NULL;
134*2d543d20SAndroid Build Coastguard Worker 
ignore_free(void)135*2d543d20SAndroid Build Coastguard Worker static void ignore_free(void) {
136*2d543d20SAndroid Build Coastguard Worker 	ignoredir_t *next;
137*2d543d20SAndroid Build Coastguard Worker 
138*2d543d20SAndroid Build Coastguard Worker 	while (ignore_head) {
139*2d543d20SAndroid Build Coastguard Worker 		next = ignore_head->next;
140*2d543d20SAndroid Build Coastguard Worker 		free(ignore_head->dir);
141*2d543d20SAndroid Build Coastguard Worker 		free(ignore_head);
142*2d543d20SAndroid Build Coastguard Worker 		ignore_head = next;
143*2d543d20SAndroid Build Coastguard Worker 	}
144*2d543d20SAndroid Build Coastguard Worker }
145*2d543d20SAndroid Build Coastguard Worker 
ignore_setup(char * ignoredirs)146*2d543d20SAndroid Build Coastguard Worker static int ignore_setup(char *ignoredirs) {
147*2d543d20SAndroid Build Coastguard Worker 	char *tok;
148*2d543d20SAndroid Build Coastguard Worker 	ignoredir_t *ptr = NULL;
149*2d543d20SAndroid Build Coastguard Worker 
150*2d543d20SAndroid Build Coastguard Worker 	tok = strtok(ignoredirs, ";");
151*2d543d20SAndroid Build Coastguard Worker 	while(tok) {
152*2d543d20SAndroid Build Coastguard Worker 		ptr = calloc(1, sizeof(ignoredir_t));
153*2d543d20SAndroid Build Coastguard Worker 		if (!ptr)
154*2d543d20SAndroid Build Coastguard Worker 			goto err;
155*2d543d20SAndroid Build Coastguard Worker 		ptr->dir = strdup(tok);
156*2d543d20SAndroid Build Coastguard Worker 		if (!ptr->dir)
157*2d543d20SAndroid Build Coastguard Worker 			goto err;
158*2d543d20SAndroid Build Coastguard Worker 
159*2d543d20SAndroid Build Coastguard Worker 		ptr->next = ignore_head;
160*2d543d20SAndroid Build Coastguard Worker 		ignore_head = ptr;
161*2d543d20SAndroid Build Coastguard Worker 
162*2d543d20SAndroid Build Coastguard Worker 		tok = strtok(NULL, ";");
163*2d543d20SAndroid Build Coastguard Worker 	}
164*2d543d20SAndroid Build Coastguard Worker 
165*2d543d20SAndroid Build Coastguard Worker 	return 0;
166*2d543d20SAndroid Build Coastguard Worker err:
167*2d543d20SAndroid Build Coastguard Worker 	free(ptr);
168*2d543d20SAndroid Build Coastguard Worker 	ignore_free();
169*2d543d20SAndroid Build Coastguard Worker 	return -1;
170*2d543d20SAndroid Build Coastguard Worker }
171*2d543d20SAndroid Build Coastguard Worker 
ignore(const char * homedir)172*2d543d20SAndroid Build Coastguard Worker static int ignore(const char *homedir) {
173*2d543d20SAndroid Build Coastguard Worker 	ignoredir_t *ptr = ignore_head;
174*2d543d20SAndroid Build Coastguard Worker 	while (ptr) {
175*2d543d20SAndroid Build Coastguard Worker 		if (strcmp(ptr->dir, homedir) == 0) {
176*2d543d20SAndroid Build Coastguard Worker 			return 1;
177*2d543d20SAndroid Build Coastguard Worker 		}
178*2d543d20SAndroid Build Coastguard Worker 		ptr = ptr->next;
179*2d543d20SAndroid Build Coastguard Worker 	}
180*2d543d20SAndroid Build Coastguard Worker 	return 0;
181*2d543d20SAndroid Build Coastguard Worker }
182*2d543d20SAndroid Build Coastguard Worker 
prefix_is_homedir_role(const semanage_user_t * user,const char * prefix)183*2d543d20SAndroid Build Coastguard Worker static int prefix_is_homedir_role(const semanage_user_t *user,
184*2d543d20SAndroid Build Coastguard Worker 				  const char *prefix)
185*2d543d20SAndroid Build Coastguard Worker {
186*2d543d20SAndroid Build Coastguard Worker 	return strcmp(OBJECT_R, prefix) == 0 ||
187*2d543d20SAndroid Build Coastguard Worker 		semanage_user_has_role(user, prefix);
188*2d543d20SAndroid Build Coastguard Worker }
189*2d543d20SAndroid Build Coastguard Worker 
default_shell_list(void)190*2d543d20SAndroid Build Coastguard Worker static semanage_list_t *default_shell_list(void)
191*2d543d20SAndroid Build Coastguard Worker {
192*2d543d20SAndroid Build Coastguard Worker 	semanage_list_t *list = NULL;
193*2d543d20SAndroid Build Coastguard Worker 
194*2d543d20SAndroid Build Coastguard Worker 	if (semanage_list_push(&list, "/bin/csh")
195*2d543d20SAndroid Build Coastguard Worker 	    || semanage_list_push(&list, "/bin/tcsh")
196*2d543d20SAndroid Build Coastguard Worker 	    || semanage_list_push(&list, "/bin/ksh")
197*2d543d20SAndroid Build Coastguard Worker 	    || semanage_list_push(&list, "/bin/bsh")
198*2d543d20SAndroid Build Coastguard Worker 	    || semanage_list_push(&list, "/bin/ash")
199*2d543d20SAndroid Build Coastguard Worker 	    || semanage_list_push(&list, "/usr/bin/ksh")
200*2d543d20SAndroid Build Coastguard Worker 	    || semanage_list_push(&list, "/usr/bin/pdksh")
201*2d543d20SAndroid Build Coastguard Worker 	    || semanage_list_push(&list, "/bin/zsh")
202*2d543d20SAndroid Build Coastguard Worker 	    || semanage_list_push(&list, "/bin/sh")
203*2d543d20SAndroid Build Coastguard Worker 	    || semanage_list_push(&list, "/bin/bash"))
204*2d543d20SAndroid Build Coastguard Worker 		goto fail;
205*2d543d20SAndroid Build Coastguard Worker 
206*2d543d20SAndroid Build Coastguard Worker 	return list;
207*2d543d20SAndroid Build Coastguard Worker 
208*2d543d20SAndroid Build Coastguard Worker       fail:
209*2d543d20SAndroid Build Coastguard Worker 	semanage_list_destroy(&list);
210*2d543d20SAndroid Build Coastguard Worker 	return NULL;
211*2d543d20SAndroid Build Coastguard Worker }
212*2d543d20SAndroid Build Coastguard Worker 
get_shell_list(void)213*2d543d20SAndroid Build Coastguard Worker static semanage_list_t *get_shell_list(void)
214*2d543d20SAndroid Build Coastguard Worker {
215*2d543d20SAndroid Build Coastguard Worker 	FILE *shells;
216*2d543d20SAndroid Build Coastguard Worker 	char *temp = NULL;
217*2d543d20SAndroid Build Coastguard Worker 	semanage_list_t *list = NULL;
218*2d543d20SAndroid Build Coastguard Worker 	size_t buff_len = 0;
219*2d543d20SAndroid Build Coastguard Worker 	ssize_t len;
220*2d543d20SAndroid Build Coastguard Worker 
221*2d543d20SAndroid Build Coastguard Worker 	shells = fopen(PATH_SHELLS_FILE, "r");
222*2d543d20SAndroid Build Coastguard Worker 	if (!shells)
223*2d543d20SAndroid Build Coastguard Worker 		return default_shell_list();
224*2d543d20SAndroid Build Coastguard Worker 	while ((len = getline(&temp, &buff_len, shells)) > 0) {
225*2d543d20SAndroid Build Coastguard Worker 		if (temp[len-1] == '\n') temp[len-1] = 0;
226*2d543d20SAndroid Build Coastguard Worker 		if (strcmp(temp, PATH_NOLOGIN_SHELL)) {
227*2d543d20SAndroid Build Coastguard Worker 			if (semanage_list_push(&list, temp)) {
228*2d543d20SAndroid Build Coastguard Worker 				free(temp);
229*2d543d20SAndroid Build Coastguard Worker 				semanage_list_destroy(&list);
230*2d543d20SAndroid Build Coastguard Worker 				return default_shell_list();
231*2d543d20SAndroid Build Coastguard Worker 			}
232*2d543d20SAndroid Build Coastguard Worker 		}
233*2d543d20SAndroid Build Coastguard Worker 	}
234*2d543d20SAndroid Build Coastguard Worker 	free(temp);
235*2d543d20SAndroid Build Coastguard Worker 
236*2d543d20SAndroid Build Coastguard Worker 	return list;
237*2d543d20SAndroid Build Coastguard Worker }
238*2d543d20SAndroid Build Coastguard Worker 
239*2d543d20SAndroid Build Coastguard Worker /* Helper function called via semanage_fcontext_iterate() */
fcontext_matches(const semanage_fcontext_t * fcontext,void * varg)240*2d543d20SAndroid Build Coastguard Worker static int fcontext_matches(const semanage_fcontext_t *fcontext, void *varg)
241*2d543d20SAndroid Build Coastguard Worker {
242*2d543d20SAndroid Build Coastguard Worker 	const char *oexpr = semanage_fcontext_get_expr(fcontext);
243*2d543d20SAndroid Build Coastguard Worker 	fc_match_handle_t *handp = varg;
244*2d543d20SAndroid Build Coastguard Worker 	char *expr = NULL;
245*2d543d20SAndroid Build Coastguard Worker 	regex_t re;
246*2d543d20SAndroid Build Coastguard Worker 	int type, retval = -1;
247*2d543d20SAndroid Build Coastguard Worker 	size_t len;
248*2d543d20SAndroid Build Coastguard Worker 
249*2d543d20SAndroid Build Coastguard Worker 	/* Only match ALL or DIR */
250*2d543d20SAndroid Build Coastguard Worker 	type = semanage_fcontext_get_type(fcontext);
251*2d543d20SAndroid Build Coastguard Worker 	if (type != SEMANAGE_FCONTEXT_ALL && type != SEMANAGE_FCONTEXT_DIR)
252*2d543d20SAndroid Build Coastguard Worker 		return 0;
253*2d543d20SAndroid Build Coastguard Worker 
254*2d543d20SAndroid Build Coastguard Worker 	len = strlen(oexpr);
255*2d543d20SAndroid Build Coastguard Worker 	/* Define a macro to strip a literal string from the end of oexpr */
256*2d543d20SAndroid Build Coastguard Worker #define rstrip_oexpr_len(cstr, cstrlen) \
257*2d543d20SAndroid Build Coastguard Worker 	do { \
258*2d543d20SAndroid Build Coastguard Worker 		if (len >= (cstrlen) && !strncmp(oexpr + len - (cstrlen), (cstr), (cstrlen))) \
259*2d543d20SAndroid Build Coastguard Worker 			len -= (cstrlen); \
260*2d543d20SAndroid Build Coastguard Worker 	} while (0)
261*2d543d20SAndroid Build Coastguard Worker #define rstrip_oexpr(cstr) rstrip_oexpr_len(cstr, sizeof(cstr) - 1)
262*2d543d20SAndroid Build Coastguard Worker 
263*2d543d20SAndroid Build Coastguard Worker 	rstrip_oexpr(".+");
264*2d543d20SAndroid Build Coastguard Worker 	rstrip_oexpr(".*");
265*2d543d20SAndroid Build Coastguard Worker 	rstrip_oexpr("(/.*)?");
266*2d543d20SAndroid Build Coastguard Worker 	rstrip_oexpr("/");
267*2d543d20SAndroid Build Coastguard Worker 
268*2d543d20SAndroid Build Coastguard Worker #undef rstrip_oexpr_len
269*2d543d20SAndroid Build Coastguard Worker #undef rstrip_oexpr
270*2d543d20SAndroid Build Coastguard Worker 
271*2d543d20SAndroid Build Coastguard Worker 	/* Anchor oexpr at the beginning and append pattern to eat up trailing slashes */
272*2d543d20SAndroid Build Coastguard Worker 	if (asprintf(&expr, "^%.*s/*$", (int)len, oexpr) < 0)
273*2d543d20SAndroid Build Coastguard Worker 		return -1;
274*2d543d20SAndroid Build Coastguard Worker 
275*2d543d20SAndroid Build Coastguard Worker 	/* Check dir against expr */
276*2d543d20SAndroid Build Coastguard Worker 	if (regcomp(&re, expr, REG_EXTENDED) != 0)
277*2d543d20SAndroid Build Coastguard Worker 		goto done;
278*2d543d20SAndroid Build Coastguard Worker 	if (regexec(&re, handp->dir, 0, NULL, 0) == 0)
279*2d543d20SAndroid Build Coastguard Worker 		handp->matched = 1;
280*2d543d20SAndroid Build Coastguard Worker 	regfree(&re);
281*2d543d20SAndroid Build Coastguard Worker 
282*2d543d20SAndroid Build Coastguard Worker 	retval = 0;
283*2d543d20SAndroid Build Coastguard Worker 
284*2d543d20SAndroid Build Coastguard Worker done:
285*2d543d20SAndroid Build Coastguard Worker 	free(expr);
286*2d543d20SAndroid Build Coastguard Worker 
287*2d543d20SAndroid Build Coastguard Worker 	return retval;
288*2d543d20SAndroid Build Coastguard Worker }
289*2d543d20SAndroid Build Coastguard Worker 
get_home_dirs(genhomedircon_settings_t * s)290*2d543d20SAndroid Build Coastguard Worker static semanage_list_t *get_home_dirs(genhomedircon_settings_t * s)
291*2d543d20SAndroid Build Coastguard Worker {
292*2d543d20SAndroid Build Coastguard Worker 	semanage_list_t *homedir_list = NULL;
293*2d543d20SAndroid Build Coastguard Worker 	semanage_list_t *shells = NULL;
294*2d543d20SAndroid Build Coastguard Worker 	fc_match_handle_t hand;
295*2d543d20SAndroid Build Coastguard Worker 	char *path = NULL;
296*2d543d20SAndroid Build Coastguard Worker 	uid_t temp, minuid = 500, maxuid = 60000;
297*2d543d20SAndroid Build Coastguard Worker 	int minuid_set = 0;
298*2d543d20SAndroid Build Coastguard Worker 	struct passwd *pwbuf;
299*2d543d20SAndroid Build Coastguard Worker 	struct stat buf;
300*2d543d20SAndroid Build Coastguard Worker 
301*2d543d20SAndroid Build Coastguard Worker 	path = semanage_findval(PATH_ETC_USERADD, "HOME", "=");
302*2d543d20SAndroid Build Coastguard Worker 	if (path && *path) {
303*2d543d20SAndroid Build Coastguard Worker 		if (semanage_list_push(&homedir_list, path))
304*2d543d20SAndroid Build Coastguard Worker 			goto fail;
305*2d543d20SAndroid Build Coastguard Worker 	}
306*2d543d20SAndroid Build Coastguard Worker 	free(path);
307*2d543d20SAndroid Build Coastguard Worker 
308*2d543d20SAndroid Build Coastguard Worker 	path = semanage_findval(PATH_ETC_LIBUSER, "LU_HOMEDIRECTORY", "=");
309*2d543d20SAndroid Build Coastguard Worker 	if (path && *path) {
310*2d543d20SAndroid Build Coastguard Worker 		if (semanage_list_push(&homedir_list, path))
311*2d543d20SAndroid Build Coastguard Worker 			goto fail;
312*2d543d20SAndroid Build Coastguard Worker 	}
313*2d543d20SAndroid Build Coastguard Worker 	free(path);
314*2d543d20SAndroid Build Coastguard Worker 	path = NULL;
315*2d543d20SAndroid Build Coastguard Worker 
316*2d543d20SAndroid Build Coastguard Worker 	if (!homedir_list) {
317*2d543d20SAndroid Build Coastguard Worker 		if (semanage_list_push(&homedir_list, PATH_DEFAULT_HOME)) {
318*2d543d20SAndroid Build Coastguard Worker 			goto fail;
319*2d543d20SAndroid Build Coastguard Worker 		}
320*2d543d20SAndroid Build Coastguard Worker 	}
321*2d543d20SAndroid Build Coastguard Worker 
322*2d543d20SAndroid Build Coastguard Worker 	if (!stat(PATH_EXPORT_HOME, &buf)) {
323*2d543d20SAndroid Build Coastguard Worker 		if (S_ISDIR(buf.st_mode)) {
324*2d543d20SAndroid Build Coastguard Worker 			if (semanage_list_push(&homedir_list, PATH_EXPORT_HOME)) {
325*2d543d20SAndroid Build Coastguard Worker 				goto fail;
326*2d543d20SAndroid Build Coastguard Worker 			}
327*2d543d20SAndroid Build Coastguard Worker 		}
328*2d543d20SAndroid Build Coastguard Worker 	}
329*2d543d20SAndroid Build Coastguard Worker 
330*2d543d20SAndroid Build Coastguard Worker 	if (!(s->usepasswd))
331*2d543d20SAndroid Build Coastguard Worker 		return homedir_list;
332*2d543d20SAndroid Build Coastguard Worker 
333*2d543d20SAndroid Build Coastguard Worker 	shells = get_shell_list();
334*2d543d20SAndroid Build Coastguard Worker 	assert(shells);
335*2d543d20SAndroid Build Coastguard Worker 
336*2d543d20SAndroid Build Coastguard Worker 	path = semanage_findval(PATH_ETC_LOGIN_DEFS, "UID_MIN", NULL);
337*2d543d20SAndroid Build Coastguard Worker 	if (path && *path) {
338*2d543d20SAndroid Build Coastguard Worker 		temp = atoi(path);
339*2d543d20SAndroid Build Coastguard Worker 		minuid = temp;
340*2d543d20SAndroid Build Coastguard Worker 		minuid_set = 1;
341*2d543d20SAndroid Build Coastguard Worker 	}
342*2d543d20SAndroid Build Coastguard Worker 	free(path);
343*2d543d20SAndroid Build Coastguard Worker 	path = NULL;
344*2d543d20SAndroid Build Coastguard Worker 
345*2d543d20SAndroid Build Coastguard Worker 	path = semanage_findval(PATH_ETC_LOGIN_DEFS, "UID_MAX", NULL);
346*2d543d20SAndroid Build Coastguard Worker 	if (path && *path) {
347*2d543d20SAndroid Build Coastguard Worker 		temp = atoi(path);
348*2d543d20SAndroid Build Coastguard Worker 		maxuid = temp;
349*2d543d20SAndroid Build Coastguard Worker 	}
350*2d543d20SAndroid Build Coastguard Worker 	free(path);
351*2d543d20SAndroid Build Coastguard Worker 	path = NULL;
352*2d543d20SAndroid Build Coastguard Worker 
353*2d543d20SAndroid Build Coastguard Worker 	path = semanage_findval(PATH_ETC_LIBUSER, "LU_UIDNUMBER", "=");
354*2d543d20SAndroid Build Coastguard Worker 	if (path && *path) {
355*2d543d20SAndroid Build Coastguard Worker 		temp = atoi(path);
356*2d543d20SAndroid Build Coastguard Worker 		if (!minuid_set || temp < minuid) {
357*2d543d20SAndroid Build Coastguard Worker 			minuid = temp;
358*2d543d20SAndroid Build Coastguard Worker 			minuid_set = 1;
359*2d543d20SAndroid Build Coastguard Worker 		}
360*2d543d20SAndroid Build Coastguard Worker 	}
361*2d543d20SAndroid Build Coastguard Worker 	free(path);
362*2d543d20SAndroid Build Coastguard Worker 	path = NULL;
363*2d543d20SAndroid Build Coastguard Worker 
364*2d543d20SAndroid Build Coastguard Worker 	errno = 0;
365*2d543d20SAndroid Build Coastguard Worker 	setpwent();
366*2d543d20SAndroid Build Coastguard Worker 	while (1) {
367*2d543d20SAndroid Build Coastguard Worker 		errno = 0;
368*2d543d20SAndroid Build Coastguard Worker 		pwbuf = getpwent();
369*2d543d20SAndroid Build Coastguard Worker 		if (pwbuf == NULL)
370*2d543d20SAndroid Build Coastguard Worker 			break;
371*2d543d20SAndroid Build Coastguard Worker 		if (pwbuf->pw_uid < minuid || pwbuf->pw_uid > maxuid)
372*2d543d20SAndroid Build Coastguard Worker 			continue;
373*2d543d20SAndroid Build Coastguard Worker 		if (!semanage_list_find(shells, pwbuf->pw_shell))
374*2d543d20SAndroid Build Coastguard Worker 			continue;
375*2d543d20SAndroid Build Coastguard Worker 		int len = strlen(pwbuf->pw_dir) -1;
376*2d543d20SAndroid Build Coastguard Worker 		for(; len > 0 && pwbuf->pw_dir[len] == '/'; len--) {
377*2d543d20SAndroid Build Coastguard Worker 			pwbuf->pw_dir[len] = '\0';
378*2d543d20SAndroid Build Coastguard Worker 		}
379*2d543d20SAndroid Build Coastguard Worker 		if (strcmp(pwbuf->pw_dir, "/") == 0)
380*2d543d20SAndroid Build Coastguard Worker 			continue;
381*2d543d20SAndroid Build Coastguard Worker 		if (ignore(pwbuf->pw_dir))
382*2d543d20SAndroid Build Coastguard Worker 			continue;
383*2d543d20SAndroid Build Coastguard Worker 		if (semanage_str_count(pwbuf->pw_dir, '/') <= 1)
384*2d543d20SAndroid Build Coastguard Worker 			continue;
385*2d543d20SAndroid Build Coastguard Worker 		if (!(path = strdup(pwbuf->pw_dir))) {
386*2d543d20SAndroid Build Coastguard Worker 			break;
387*2d543d20SAndroid Build Coastguard Worker 		}
388*2d543d20SAndroid Build Coastguard Worker 
389*2d543d20SAndroid Build Coastguard Worker 		semanage_rtrim(path, '/');
390*2d543d20SAndroid Build Coastguard Worker 
391*2d543d20SAndroid Build Coastguard Worker 		if (!semanage_list_find(homedir_list, path)) {
392*2d543d20SAndroid Build Coastguard Worker 			/*
393*2d543d20SAndroid Build Coastguard Worker 			 * Now check for an existing file context that matches
394*2d543d20SAndroid Build Coastguard Worker 			 * so we don't label a non-homedir as a homedir.
395*2d543d20SAndroid Build Coastguard Worker 			 */
396*2d543d20SAndroid Build Coastguard Worker 			hand.dir = path;
397*2d543d20SAndroid Build Coastguard Worker 			hand.matched = 0;
398*2d543d20SAndroid Build Coastguard Worker 			if (semanage_fcontext_iterate(s->h_semanage,
399*2d543d20SAndroid Build Coastguard Worker 			    fcontext_matches, &hand) == STATUS_ERR)
400*2d543d20SAndroid Build Coastguard Worker 				goto fail;
401*2d543d20SAndroid Build Coastguard Worker 
402*2d543d20SAndroid Build Coastguard Worker 			/* NOTE: old genhomedircon printed a warning on match */
403*2d543d20SAndroid Build Coastguard Worker 			if (hand.matched) {
404*2d543d20SAndroid Build Coastguard Worker 				WARN(s->h_semanage, "%s homedir %s or its parent directory conflicts with a file context already specified in the policy.  This usually indicates an incorrectly defined system account.  If it is a system account please make sure its uid is less than %u or greater than %u or its login shell is /sbin/nologin.", pwbuf->pw_name, pwbuf->pw_dir, minuid, maxuid);
405*2d543d20SAndroid Build Coastguard Worker 			} else {
406*2d543d20SAndroid Build Coastguard Worker 				if (semanage_list_push(&homedir_list, path))
407*2d543d20SAndroid Build Coastguard Worker 					goto fail;
408*2d543d20SAndroid Build Coastguard Worker 			}
409*2d543d20SAndroid Build Coastguard Worker 		}
410*2d543d20SAndroid Build Coastguard Worker 		free(path);
411*2d543d20SAndroid Build Coastguard Worker 		path = NULL;
412*2d543d20SAndroid Build Coastguard Worker 	}
413*2d543d20SAndroid Build Coastguard Worker 
414*2d543d20SAndroid Build Coastguard Worker 	if (errno) {
415*2d543d20SAndroid Build Coastguard Worker 		WARN(s->h_semanage, "Error while fetching users.  "
416*2d543d20SAndroid Build Coastguard Worker 		     "Returning list so far.");
417*2d543d20SAndroid Build Coastguard Worker 	}
418*2d543d20SAndroid Build Coastguard Worker 
419*2d543d20SAndroid Build Coastguard Worker 	if (semanage_list_sort(&homedir_list))
420*2d543d20SAndroid Build Coastguard Worker 		goto fail;
421*2d543d20SAndroid Build Coastguard Worker 
422*2d543d20SAndroid Build Coastguard Worker 	endpwent();
423*2d543d20SAndroid Build Coastguard Worker 	semanage_list_destroy(&shells);
424*2d543d20SAndroid Build Coastguard Worker 
425*2d543d20SAndroid Build Coastguard Worker 	return homedir_list;
426*2d543d20SAndroid Build Coastguard Worker 
427*2d543d20SAndroid Build Coastguard Worker       fail:
428*2d543d20SAndroid Build Coastguard Worker 	endpwent();
429*2d543d20SAndroid Build Coastguard Worker 	free(path);
430*2d543d20SAndroid Build Coastguard Worker 	semanage_list_destroy(&homedir_list);
431*2d543d20SAndroid Build Coastguard Worker 	semanage_list_destroy(&shells);
432*2d543d20SAndroid Build Coastguard Worker 	return NULL;
433*2d543d20SAndroid Build Coastguard Worker }
434*2d543d20SAndroid Build Coastguard Worker 
435*2d543d20SAndroid Build Coastguard Worker /**
436*2d543d20SAndroid Build Coastguard Worker  * @param	out	the FILE to put all the output in.
437*2d543d20SAndroid Build Coastguard Worker  * @return	0 on success
438*2d543d20SAndroid Build Coastguard Worker  */
write_file_context_header(FILE * out)439*2d543d20SAndroid Build Coastguard Worker static int write_file_context_header(FILE * out)
440*2d543d20SAndroid Build Coastguard Worker {
441*2d543d20SAndroid Build Coastguard Worker 	if (fprintf(out, COMMENT_FILE_CONTEXT_HEADER) < 0) {
442*2d543d20SAndroid Build Coastguard Worker 		return STATUS_ERR;
443*2d543d20SAndroid Build Coastguard Worker 	}
444*2d543d20SAndroid Build Coastguard Worker 
445*2d543d20SAndroid Build Coastguard Worker 	return STATUS_SUCCESS;
446*2d543d20SAndroid Build Coastguard Worker }
447*2d543d20SAndroid Build Coastguard Worker 
448*2d543d20SAndroid Build Coastguard Worker /* Predicates for use with semanage_slurp_file_filter() the homedir_template
449*2d543d20SAndroid Build Coastguard Worker  * file currently contains lines that serve as the template for a user's
450*2d543d20SAndroid Build Coastguard Worker  * homedir.
451*2d543d20SAndroid Build Coastguard Worker  *
452*2d543d20SAndroid Build Coastguard Worker  * It also contains lines that are the template for the parent of a
453*2d543d20SAndroid Build Coastguard Worker  * user's home directory.
454*2d543d20SAndroid Build Coastguard Worker  *
455*2d543d20SAndroid Build Coastguard Worker  * Currently, the only lines that apply to the the root of a user's home
456*2d543d20SAndroid Build Coastguard Worker  * directory are all prefixed with the string "HOME_ROOT".  All other
457*2d543d20SAndroid Build Coastguard Worker  * lines apply to a user's home directory.  If this changes the
458*2d543d20SAndroid Build Coastguard Worker  * following predicates need to change to reflect that.
459*2d543d20SAndroid Build Coastguard Worker  */
HOME_ROOT_PRED(const char * string)460*2d543d20SAndroid Build Coastguard Worker static int HOME_ROOT_PRED(const char *string)
461*2d543d20SAndroid Build Coastguard Worker {
462*2d543d20SAndroid Build Coastguard Worker 	return semanage_is_prefix(string, TEMPLATE_HOME_ROOT);
463*2d543d20SAndroid Build Coastguard Worker }
464*2d543d20SAndroid Build Coastguard Worker 
HOME_DIR_PRED(const char * string)465*2d543d20SAndroid Build Coastguard Worker static int HOME_DIR_PRED(const char *string)
466*2d543d20SAndroid Build Coastguard Worker {
467*2d543d20SAndroid Build Coastguard Worker 	return semanage_is_prefix(string, TEMPLATE_HOME_DIR);
468*2d543d20SAndroid Build Coastguard Worker }
469*2d543d20SAndroid Build Coastguard Worker 
470*2d543d20SAndroid Build Coastguard Worker /* new names */
USERNAME_CONTEXT_PRED(const char * string)471*2d543d20SAndroid Build Coastguard Worker static int USERNAME_CONTEXT_PRED(const char *string)
472*2d543d20SAndroid Build Coastguard Worker {
473*2d543d20SAndroid Build Coastguard Worker 	return (int)(
474*2d543d20SAndroid Build Coastguard Worker 		(strstr(string, TEMPLATE_USERNAME) != NULL) ||
475*2d543d20SAndroid Build Coastguard Worker 		(strstr(string, TEMPLATE_USERID) != NULL)
476*2d543d20SAndroid Build Coastguard Worker 	);
477*2d543d20SAndroid Build Coastguard Worker }
478*2d543d20SAndroid Build Coastguard Worker 
479*2d543d20SAndroid Build Coastguard Worker /* This will never match USER if USERNAME or USERID are found. */
USER_CONTEXT_PRED(const char * string)480*2d543d20SAndroid Build Coastguard Worker static int USER_CONTEXT_PRED(const char *string)
481*2d543d20SAndroid Build Coastguard Worker {
482*2d543d20SAndroid Build Coastguard Worker 	if (USERNAME_CONTEXT_PRED(string))
483*2d543d20SAndroid Build Coastguard Worker 		return 0;
484*2d543d20SAndroid Build Coastguard Worker 
485*2d543d20SAndroid Build Coastguard Worker 	return (int)(strstr(string, TEMPLATE_USER) != NULL);
486*2d543d20SAndroid Build Coastguard Worker }
487*2d543d20SAndroid Build Coastguard Worker 
STR_COMPARATOR(const void * a,const void * b)488*2d543d20SAndroid Build Coastguard Worker static int STR_COMPARATOR(const void *a, const void *b)
489*2d543d20SAndroid Build Coastguard Worker {
490*2d543d20SAndroid Build Coastguard Worker 	return strcmp((const char *) a, (const char *) b);
491*2d543d20SAndroid Build Coastguard Worker }
492*2d543d20SAndroid Build Coastguard Worker 
493*2d543d20SAndroid Build Coastguard Worker /* make_template
494*2d543d20SAndroid Build Coastguard Worker  * @param	s	  the settings holding the paths to various files
495*2d543d20SAndroid Build Coastguard Worker  * @param	pred	function pointer to function to use as filter for slurp
496*2d543d20SAndroid Build Coastguard Worker  * 					file filter
497*2d543d20SAndroid Build Coastguard Worker  * @return   a list of lines from the template file with inappropriate
498*2d543d20SAndroid Build Coastguard Worker  *	    lines filtered out.
499*2d543d20SAndroid Build Coastguard Worker  */
make_template(genhomedircon_settings_t * s,int (* pred)(const char *))500*2d543d20SAndroid Build Coastguard Worker static semanage_list_t *make_template(genhomedircon_settings_t * s,
501*2d543d20SAndroid Build Coastguard Worker 				      int (*pred) (const char *))
502*2d543d20SAndroid Build Coastguard Worker {
503*2d543d20SAndroid Build Coastguard Worker 	FILE *template_file = NULL;
504*2d543d20SAndroid Build Coastguard Worker 	semanage_list_t *template_data = NULL;
505*2d543d20SAndroid Build Coastguard Worker 
506*2d543d20SAndroid Build Coastguard Worker 	template_file = fopen(s->homedir_template_path, "r");
507*2d543d20SAndroid Build Coastguard Worker 	if (!template_file)
508*2d543d20SAndroid Build Coastguard Worker 		return NULL;
509*2d543d20SAndroid Build Coastguard Worker 	template_data = semanage_slurp_file_filter(template_file, pred);
510*2d543d20SAndroid Build Coastguard Worker 	fclose(template_file);
511*2d543d20SAndroid Build Coastguard Worker 
512*2d543d20SAndroid Build Coastguard Worker 	return template_data;
513*2d543d20SAndroid Build Coastguard Worker }
514*2d543d20SAndroid Build Coastguard Worker 
replace_all(const char * str,const replacement_pair_t * repl)515*2d543d20SAndroid Build Coastguard Worker static char *replace_all(const char *str, const replacement_pair_t * repl)
516*2d543d20SAndroid Build Coastguard Worker {
517*2d543d20SAndroid Build Coastguard Worker 	char *retval, *retval2;
518*2d543d20SAndroid Build Coastguard Worker 	int i;
519*2d543d20SAndroid Build Coastguard Worker 
520*2d543d20SAndroid Build Coastguard Worker 	if (!str || !repl)
521*2d543d20SAndroid Build Coastguard Worker 		return NULL;
522*2d543d20SAndroid Build Coastguard Worker 
523*2d543d20SAndroid Build Coastguard Worker 	retval = strdup(str);
524*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; retval != NULL && repl[i].search_for; i++) {
525*2d543d20SAndroid Build Coastguard Worker 		retval2 = semanage_str_replace(repl[i].search_for,
526*2d543d20SAndroid Build Coastguard Worker 					       repl[i].replace_with, retval, 0);
527*2d543d20SAndroid Build Coastguard Worker 		free(retval);
528*2d543d20SAndroid Build Coastguard Worker 		retval = retval2;
529*2d543d20SAndroid Build Coastguard Worker 	}
530*2d543d20SAndroid Build Coastguard Worker 	return retval;
531*2d543d20SAndroid Build Coastguard Worker }
532*2d543d20SAndroid Build Coastguard Worker 
extract_context(const char * line)533*2d543d20SAndroid Build Coastguard Worker static const char *extract_context(const char *line)
534*2d543d20SAndroid Build Coastguard Worker {
535*2d543d20SAndroid Build Coastguard Worker 	const char *p = line;
536*2d543d20SAndroid Build Coastguard Worker 	size_t off;
537*2d543d20SAndroid Build Coastguard Worker 
538*2d543d20SAndroid Build Coastguard Worker 	off = strlen(p);
539*2d543d20SAndroid Build Coastguard Worker 	p += off;
540*2d543d20SAndroid Build Coastguard Worker 	/* consider trailing whitespaces */
541*2d543d20SAndroid Build Coastguard Worker 	while (off > 0) {
542*2d543d20SAndroid Build Coastguard Worker 		p--;
543*2d543d20SAndroid Build Coastguard Worker 		off--;
544*2d543d20SAndroid Build Coastguard Worker 		if (!isspace(*p))
545*2d543d20SAndroid Build Coastguard Worker 			break;
546*2d543d20SAndroid Build Coastguard Worker 	}
547*2d543d20SAndroid Build Coastguard Worker 	if (off == 0)
548*2d543d20SAndroid Build Coastguard Worker 		return NULL;
549*2d543d20SAndroid Build Coastguard Worker 
550*2d543d20SAndroid Build Coastguard Worker 	/* find the last field in line */
551*2d543d20SAndroid Build Coastguard Worker 	while (off > 0 && !isspace(*(p - 1))) {
552*2d543d20SAndroid Build Coastguard Worker 		p--;
553*2d543d20SAndroid Build Coastguard Worker 		off--;
554*2d543d20SAndroid Build Coastguard Worker 	}
555*2d543d20SAndroid Build Coastguard Worker 	return p;
556*2d543d20SAndroid Build Coastguard Worker }
557*2d543d20SAndroid Build Coastguard Worker 
check_line(genhomedircon_settings_t * s,const char * line)558*2d543d20SAndroid Build Coastguard Worker static int check_line(genhomedircon_settings_t * s, const char *line)
559*2d543d20SAndroid Build Coastguard Worker {
560*2d543d20SAndroid Build Coastguard Worker 	sepol_context_t *ctx_record = NULL;
561*2d543d20SAndroid Build Coastguard Worker 	const char *ctx_str;
562*2d543d20SAndroid Build Coastguard Worker 	int result;
563*2d543d20SAndroid Build Coastguard Worker 
564*2d543d20SAndroid Build Coastguard Worker 	ctx_str = extract_context(line);
565*2d543d20SAndroid Build Coastguard Worker 	if (!ctx_str)
566*2d543d20SAndroid Build Coastguard Worker 		return STATUS_ERR;
567*2d543d20SAndroid Build Coastguard Worker 
568*2d543d20SAndroid Build Coastguard Worker 	result = sepol_context_from_string(s->h_semanage->sepolh,
569*2d543d20SAndroid Build Coastguard Worker 					   ctx_str, &ctx_record);
570*2d543d20SAndroid Build Coastguard Worker 	if (result == STATUS_SUCCESS && ctx_record != NULL) {
571*2d543d20SAndroid Build Coastguard Worker 		result = sepol_context_check(s->h_semanage->sepolh,
572*2d543d20SAndroid Build Coastguard Worker 					     s->policydb, ctx_record);
573*2d543d20SAndroid Build Coastguard Worker 		sepol_context_free(ctx_record);
574*2d543d20SAndroid Build Coastguard Worker 	}
575*2d543d20SAndroid Build Coastguard Worker 	return result;
576*2d543d20SAndroid Build Coastguard Worker }
577*2d543d20SAndroid Build Coastguard Worker 
write_replacements(genhomedircon_settings_t * s,FILE * out,const semanage_list_t * tpl,const replacement_pair_t * repl)578*2d543d20SAndroid Build Coastguard Worker static int write_replacements(genhomedircon_settings_t * s, FILE * out,
579*2d543d20SAndroid Build Coastguard Worker 			      const semanage_list_t * tpl,
580*2d543d20SAndroid Build Coastguard Worker 			      const replacement_pair_t *repl)
581*2d543d20SAndroid Build Coastguard Worker {
582*2d543d20SAndroid Build Coastguard Worker 	char *line;
583*2d543d20SAndroid Build Coastguard Worker 
584*2d543d20SAndroid Build Coastguard Worker 	for (; tpl; tpl = tpl->next) {
585*2d543d20SAndroid Build Coastguard Worker 		line = replace_all(tpl->data, repl);
586*2d543d20SAndroid Build Coastguard Worker 		if (!line)
587*2d543d20SAndroid Build Coastguard Worker 			goto fail;
588*2d543d20SAndroid Build Coastguard Worker 		if (check_line(s, line) == STATUS_SUCCESS) {
589*2d543d20SAndroid Build Coastguard Worker 			if (fprintf(out, "%s\n", line) < 0)
590*2d543d20SAndroid Build Coastguard Worker 				goto fail;
591*2d543d20SAndroid Build Coastguard Worker 		}
592*2d543d20SAndroid Build Coastguard Worker 		free(line);
593*2d543d20SAndroid Build Coastguard Worker 	}
594*2d543d20SAndroid Build Coastguard Worker 	return STATUS_SUCCESS;
595*2d543d20SAndroid Build Coastguard Worker 
596*2d543d20SAndroid Build Coastguard Worker       fail:
597*2d543d20SAndroid Build Coastguard Worker 	free(line);
598*2d543d20SAndroid Build Coastguard Worker 	return STATUS_ERR;
599*2d543d20SAndroid Build Coastguard Worker }
600*2d543d20SAndroid Build Coastguard Worker 
write_contexts(genhomedircon_settings_t * s,FILE * out,semanage_list_t * tpl,const replacement_pair_t * repl,const genhomedircon_user_entry_t * user)601*2d543d20SAndroid Build Coastguard Worker static int write_contexts(genhomedircon_settings_t *s, FILE *out,
602*2d543d20SAndroid Build Coastguard Worker 			  semanage_list_t *tpl, const replacement_pair_t *repl,
603*2d543d20SAndroid Build Coastguard Worker 			  const genhomedircon_user_entry_t *user)
604*2d543d20SAndroid Build Coastguard Worker {
605*2d543d20SAndroid Build Coastguard Worker 	char *line, *temp;
606*2d543d20SAndroid Build Coastguard Worker 	sepol_context_t *context;
607*2d543d20SAndroid Build Coastguard Worker 	char *new_context_str;
608*2d543d20SAndroid Build Coastguard Worker 
609*2d543d20SAndroid Build Coastguard Worker 	for (; tpl; tpl = tpl->next) {
610*2d543d20SAndroid Build Coastguard Worker 		context = NULL;
611*2d543d20SAndroid Build Coastguard Worker 		new_context_str = NULL;
612*2d543d20SAndroid Build Coastguard Worker 		line = replace_all(tpl->data, repl);
613*2d543d20SAndroid Build Coastguard Worker 		if (!line) {
614*2d543d20SAndroid Build Coastguard Worker 			goto fail;
615*2d543d20SAndroid Build Coastguard Worker 		}
616*2d543d20SAndroid Build Coastguard Worker 
617*2d543d20SAndroid Build Coastguard Worker 		const char *old_context_str = extract_context(line);
618*2d543d20SAndroid Build Coastguard Worker 		if (!old_context_str) {
619*2d543d20SAndroid Build Coastguard Worker 			goto fail;
620*2d543d20SAndroid Build Coastguard Worker 		}
621*2d543d20SAndroid Build Coastguard Worker 
622*2d543d20SAndroid Build Coastguard Worker 		if (strcmp(old_context_str, CONTEXT_NONE) == 0) {
623*2d543d20SAndroid Build Coastguard Worker 			if (check_line(s, line) == STATUS_SUCCESS &&
624*2d543d20SAndroid Build Coastguard Worker 			    fprintf(out, "%s\n", line) < 0) {
625*2d543d20SAndroid Build Coastguard Worker 				goto fail;
626*2d543d20SAndroid Build Coastguard Worker 			}
627*2d543d20SAndroid Build Coastguard Worker 			free(line);
628*2d543d20SAndroid Build Coastguard Worker 			continue;
629*2d543d20SAndroid Build Coastguard Worker 		}
630*2d543d20SAndroid Build Coastguard Worker 
631*2d543d20SAndroid Build Coastguard Worker 		sepol_handle_t *sepolh = s->h_semanage->sepolh;
632*2d543d20SAndroid Build Coastguard Worker 
633*2d543d20SAndroid Build Coastguard Worker 		if (sepol_context_from_string(sepolh, old_context_str,
634*2d543d20SAndroid Build Coastguard Worker 					      &context) < 0) {
635*2d543d20SAndroid Build Coastguard Worker 			goto fail;
636*2d543d20SAndroid Build Coastguard Worker 		}
637*2d543d20SAndroid Build Coastguard Worker 
638*2d543d20SAndroid Build Coastguard Worker 		if (sepol_context_set_user(sepolh, context, user->sename) < 0) {
639*2d543d20SAndroid Build Coastguard Worker 			goto fail;
640*2d543d20SAndroid Build Coastguard Worker 		}
641*2d543d20SAndroid Build Coastguard Worker 
642*2d543d20SAndroid Build Coastguard Worker 		if (sepol_policydb_mls_enabled(s->policydb) &&
643*2d543d20SAndroid Build Coastguard Worker 		    sepol_context_set_mls(sepolh, context, user->level) < 0) {
644*2d543d20SAndroid Build Coastguard Worker 			goto fail;
645*2d543d20SAndroid Build Coastguard Worker 		}
646*2d543d20SAndroid Build Coastguard Worker 
647*2d543d20SAndroid Build Coastguard Worker 		if (user->homedir_role &&
648*2d543d20SAndroid Build Coastguard Worker 		    sepol_context_set_role(sepolh, context, user->homedir_role) < 0) {
649*2d543d20SAndroid Build Coastguard Worker 			goto fail;
650*2d543d20SAndroid Build Coastguard Worker 		}
651*2d543d20SAndroid Build Coastguard Worker 
652*2d543d20SAndroid Build Coastguard Worker 		if (sepol_context_to_string(sepolh, context,
653*2d543d20SAndroid Build Coastguard Worker 					    &new_context_str) < 0) {
654*2d543d20SAndroid Build Coastguard Worker 			goto fail;
655*2d543d20SAndroid Build Coastguard Worker 		}
656*2d543d20SAndroid Build Coastguard Worker 
657*2d543d20SAndroid Build Coastguard Worker 		temp = semanage_str_replace(old_context_str, new_context_str,
658*2d543d20SAndroid Build Coastguard Worker 					    line, 1);
659*2d543d20SAndroid Build Coastguard Worker 		if (!temp) {
660*2d543d20SAndroid Build Coastguard Worker 			goto fail;
661*2d543d20SAndroid Build Coastguard Worker 		}
662*2d543d20SAndroid Build Coastguard Worker 		free(line);
663*2d543d20SAndroid Build Coastguard Worker 		line = temp;
664*2d543d20SAndroid Build Coastguard Worker 
665*2d543d20SAndroid Build Coastguard Worker 		if (check_line(s, line) == STATUS_SUCCESS) {
666*2d543d20SAndroid Build Coastguard Worker 			if (fprintf(out, "%s\n", line) < 0)
667*2d543d20SAndroid Build Coastguard Worker 				goto fail;
668*2d543d20SAndroid Build Coastguard Worker 		}
669*2d543d20SAndroid Build Coastguard Worker 
670*2d543d20SAndroid Build Coastguard Worker 		free(line);
671*2d543d20SAndroid Build Coastguard Worker 		sepol_context_free(context);
672*2d543d20SAndroid Build Coastguard Worker 		free(new_context_str);
673*2d543d20SAndroid Build Coastguard Worker 	}
674*2d543d20SAndroid Build Coastguard Worker 
675*2d543d20SAndroid Build Coastguard Worker 	return STATUS_SUCCESS;
676*2d543d20SAndroid Build Coastguard Worker fail:
677*2d543d20SAndroid Build Coastguard Worker 	free(line);
678*2d543d20SAndroid Build Coastguard Worker 	sepol_context_free(context);
679*2d543d20SAndroid Build Coastguard Worker 	free(new_context_str);
680*2d543d20SAndroid Build Coastguard Worker 	return STATUS_ERR;
681*2d543d20SAndroid Build Coastguard Worker }
682*2d543d20SAndroid Build Coastguard Worker 
write_home_dir_context(genhomedircon_settings_t * s,FILE * out,semanage_list_t * tpl,const genhomedircon_user_entry_t * user)683*2d543d20SAndroid Build Coastguard Worker static int write_home_dir_context(genhomedircon_settings_t * s, FILE * out,
684*2d543d20SAndroid Build Coastguard Worker 				  semanage_list_t * tpl, const genhomedircon_user_entry_t *user)
685*2d543d20SAndroid Build Coastguard Worker {
686*2d543d20SAndroid Build Coastguard Worker 	replacement_pair_t repl[] = {
687*2d543d20SAndroid Build Coastguard Worker 		{.search_for = TEMPLATE_HOME_DIR,.replace_with = user->home},
688*2d543d20SAndroid Build Coastguard Worker 		{.search_for = TEMPLATE_ROLE,.replace_with = user->prefix},
689*2d543d20SAndroid Build Coastguard Worker 		{NULL, NULL}
690*2d543d20SAndroid Build Coastguard Worker 	};
691*2d543d20SAndroid Build Coastguard Worker 
692*2d543d20SAndroid Build Coastguard Worker 	if (strcmp(user->name, FALLBACK_NAME) == 0) {
693*2d543d20SAndroid Build Coastguard Worker 		if (fprintf(out, COMMENT_USER_HOME_CONTEXT, FALLBACK_SENAME) < 0)
694*2d543d20SAndroid Build Coastguard Worker 			return STATUS_ERR;
695*2d543d20SAndroid Build Coastguard Worker 	} else {
696*2d543d20SAndroid Build Coastguard Worker 		if (fprintf(out, COMMENT_USER_HOME_CONTEXT, user->name) < 0)
697*2d543d20SAndroid Build Coastguard Worker 			return STATUS_ERR;
698*2d543d20SAndroid Build Coastguard Worker 	}
699*2d543d20SAndroid Build Coastguard Worker 
700*2d543d20SAndroid Build Coastguard Worker 	return write_contexts(s, out, tpl, repl, user);
701*2d543d20SAndroid Build Coastguard Worker }
702*2d543d20SAndroid Build Coastguard Worker 
write_home_root_context(genhomedircon_settings_t * s,FILE * out,semanage_list_t * tpl,char * homedir)703*2d543d20SAndroid Build Coastguard Worker static int write_home_root_context(genhomedircon_settings_t * s, FILE * out,
704*2d543d20SAndroid Build Coastguard Worker 				   semanage_list_t * tpl, char *homedir)
705*2d543d20SAndroid Build Coastguard Worker {
706*2d543d20SAndroid Build Coastguard Worker 	replacement_pair_t repl[] = {
707*2d543d20SAndroid Build Coastguard Worker 		{.search_for = TEMPLATE_HOME_ROOT,.replace_with = homedir},
708*2d543d20SAndroid Build Coastguard Worker 		{NULL, NULL}
709*2d543d20SAndroid Build Coastguard Worker 	};
710*2d543d20SAndroid Build Coastguard Worker 
711*2d543d20SAndroid Build Coastguard Worker 	return write_replacements(s, out, tpl, repl);
712*2d543d20SAndroid Build Coastguard Worker }
713*2d543d20SAndroid Build Coastguard Worker 
write_username_context(genhomedircon_settings_t * s,FILE * out,semanage_list_t * tpl,const genhomedircon_user_entry_t * user)714*2d543d20SAndroid Build Coastguard Worker static int write_username_context(genhomedircon_settings_t * s, FILE * out,
715*2d543d20SAndroid Build Coastguard Worker 				  semanage_list_t * tpl,
716*2d543d20SAndroid Build Coastguard Worker 				  const genhomedircon_user_entry_t *user)
717*2d543d20SAndroid Build Coastguard Worker {
718*2d543d20SAndroid Build Coastguard Worker 	replacement_pair_t repl[] = {
719*2d543d20SAndroid Build Coastguard Worker 		{.search_for = TEMPLATE_USERNAME,.replace_with = user->name},
720*2d543d20SAndroid Build Coastguard Worker 		{.search_for = TEMPLATE_USERID,.replace_with = user->uid},
721*2d543d20SAndroid Build Coastguard Worker 		{.search_for = TEMPLATE_ROLE,.replace_with = user->prefix},
722*2d543d20SAndroid Build Coastguard Worker 		{NULL, NULL}
723*2d543d20SAndroid Build Coastguard Worker 	};
724*2d543d20SAndroid Build Coastguard Worker 
725*2d543d20SAndroid Build Coastguard Worker 	return write_contexts(s, out, tpl, repl, user);
726*2d543d20SAndroid Build Coastguard Worker }
727*2d543d20SAndroid Build Coastguard Worker 
write_user_context(genhomedircon_settings_t * s,FILE * out,semanage_list_t * tpl,const genhomedircon_user_entry_t * user)728*2d543d20SAndroid Build Coastguard Worker static int write_user_context(genhomedircon_settings_t * s, FILE * out,
729*2d543d20SAndroid Build Coastguard Worker 			      semanage_list_t * tpl, const genhomedircon_user_entry_t *user)
730*2d543d20SAndroid Build Coastguard Worker {
731*2d543d20SAndroid Build Coastguard Worker 	replacement_pair_t repl[] = {
732*2d543d20SAndroid Build Coastguard Worker 		{.search_for = TEMPLATE_USER,.replace_with = user->name},
733*2d543d20SAndroid Build Coastguard Worker 		{.search_for = TEMPLATE_ROLE,.replace_with = user->prefix},
734*2d543d20SAndroid Build Coastguard Worker 		{NULL, NULL}
735*2d543d20SAndroid Build Coastguard Worker 	};
736*2d543d20SAndroid Build Coastguard Worker 
737*2d543d20SAndroid Build Coastguard Worker 	return write_contexts(s, out, tpl, repl, user);
738*2d543d20SAndroid Build Coastguard Worker }
739*2d543d20SAndroid Build Coastguard Worker 
seuser_sort_func(const void * arg1,const void * arg2)740*2d543d20SAndroid Build Coastguard Worker static int seuser_sort_func(const void *arg1, const void *arg2)
741*2d543d20SAndroid Build Coastguard Worker {
742*2d543d20SAndroid Build Coastguard Worker 	const semanage_seuser_t **u1 = (const semanage_seuser_t **) arg1;
743*2d543d20SAndroid Build Coastguard Worker 	const semanage_seuser_t **u2 = (const semanage_seuser_t **) arg2;
744*2d543d20SAndroid Build Coastguard Worker 	const char *name1 = semanage_seuser_get_name(*u1);
745*2d543d20SAndroid Build Coastguard Worker 	const char *name2 = semanage_seuser_get_name(*u2);
746*2d543d20SAndroid Build Coastguard Worker 
747*2d543d20SAndroid Build Coastguard Worker 	if (name1[0] == '%' && name2[0] == '%') {
748*2d543d20SAndroid Build Coastguard Worker 		return 0;
749*2d543d20SAndroid Build Coastguard Worker 	} else if (name1[0] == '%') {
750*2d543d20SAndroid Build Coastguard Worker 		return 1;
751*2d543d20SAndroid Build Coastguard Worker 	} else if (name2[0] == '%') {
752*2d543d20SAndroid Build Coastguard Worker 		return -1;
753*2d543d20SAndroid Build Coastguard Worker 	}
754*2d543d20SAndroid Build Coastguard Worker 
755*2d543d20SAndroid Build Coastguard Worker 	return strcmp(name1, name2);
756*2d543d20SAndroid Build Coastguard Worker }
757*2d543d20SAndroid Build Coastguard Worker 
user_sort_func(semanage_user_t ** arg1,semanage_user_t ** arg2)758*2d543d20SAndroid Build Coastguard Worker static int user_sort_func(semanage_user_t ** arg1, semanage_user_t ** arg2)
759*2d543d20SAndroid Build Coastguard Worker {
760*2d543d20SAndroid Build Coastguard Worker 	return strcmp(semanage_user_get_name(*arg1),
761*2d543d20SAndroid Build Coastguard Worker 		      semanage_user_get_name(*arg2));
762*2d543d20SAndroid Build Coastguard Worker }
763*2d543d20SAndroid Build Coastguard Worker 
name_user_cmp(char * key,semanage_user_t ** val)764*2d543d20SAndroid Build Coastguard Worker static int name_user_cmp(char *key, semanage_user_t ** val)
765*2d543d20SAndroid Build Coastguard Worker {
766*2d543d20SAndroid Build Coastguard Worker 	return strcmp(key, semanage_user_get_name(*val));
767*2d543d20SAndroid Build Coastguard Worker }
768*2d543d20SAndroid Build Coastguard Worker 
push_user_entry(genhomedircon_user_entry_t ** list,const char * n,const char * u,const char * g,const char * sen,const char * pre,const char * h,const char * l,const char * ln,const char * hd_role)769*2d543d20SAndroid Build Coastguard Worker static int push_user_entry(genhomedircon_user_entry_t ** list, const char *n,
770*2d543d20SAndroid Build Coastguard Worker 			   const char *u, const char *g, const char *sen,
771*2d543d20SAndroid Build Coastguard Worker 			   const char *pre, const char *h, const char *l,
772*2d543d20SAndroid Build Coastguard Worker 			   const char *ln, const char *hd_role)
773*2d543d20SAndroid Build Coastguard Worker {
774*2d543d20SAndroid Build Coastguard Worker 	genhomedircon_user_entry_t *temp = NULL;
775*2d543d20SAndroid Build Coastguard Worker 	char *name = NULL;
776*2d543d20SAndroid Build Coastguard Worker 	char *uid = NULL;
777*2d543d20SAndroid Build Coastguard Worker 	char *gid = NULL;
778*2d543d20SAndroid Build Coastguard Worker 	char *sename = NULL;
779*2d543d20SAndroid Build Coastguard Worker 	char *prefix = NULL;
780*2d543d20SAndroid Build Coastguard Worker 	char *home = NULL;
781*2d543d20SAndroid Build Coastguard Worker 	char *level = NULL;
782*2d543d20SAndroid Build Coastguard Worker 	char *lname = NULL;
783*2d543d20SAndroid Build Coastguard Worker 	char *homedir_role = NULL;
784*2d543d20SAndroid Build Coastguard Worker 
785*2d543d20SAndroid Build Coastguard Worker 	temp = malloc(sizeof(genhomedircon_user_entry_t));
786*2d543d20SAndroid Build Coastguard Worker 	if (!temp)
787*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
788*2d543d20SAndroid Build Coastguard Worker 	name = strdup(n);
789*2d543d20SAndroid Build Coastguard Worker 	if (!name)
790*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
791*2d543d20SAndroid Build Coastguard Worker 	uid = strdup(u);
792*2d543d20SAndroid Build Coastguard Worker 	if (!uid)
793*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
794*2d543d20SAndroid Build Coastguard Worker 	gid = strdup(g);
795*2d543d20SAndroid Build Coastguard Worker 	if (!gid)
796*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
797*2d543d20SAndroid Build Coastguard Worker 	sename = strdup(sen);
798*2d543d20SAndroid Build Coastguard Worker 	if (!sename)
799*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
800*2d543d20SAndroid Build Coastguard Worker 	prefix = strdup(pre);
801*2d543d20SAndroid Build Coastguard Worker 	if (!prefix)
802*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
803*2d543d20SAndroid Build Coastguard Worker 	home = strdup(h);
804*2d543d20SAndroid Build Coastguard Worker 	if (!home)
805*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
806*2d543d20SAndroid Build Coastguard Worker 	level = strdup(l);
807*2d543d20SAndroid Build Coastguard Worker 	if (!level)
808*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
809*2d543d20SAndroid Build Coastguard Worker 	lname = strdup(ln);
810*2d543d20SAndroid Build Coastguard Worker 	if (!lname)
811*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
812*2d543d20SAndroid Build Coastguard Worker 	if (hd_role) {
813*2d543d20SAndroid Build Coastguard Worker 		homedir_role = strdup(hd_role);
814*2d543d20SAndroid Build Coastguard Worker 		if (!homedir_role)
815*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
816*2d543d20SAndroid Build Coastguard Worker 	}
817*2d543d20SAndroid Build Coastguard Worker 
818*2d543d20SAndroid Build Coastguard Worker 	temp->name = name;
819*2d543d20SAndroid Build Coastguard Worker 	temp->uid = uid;
820*2d543d20SAndroid Build Coastguard Worker 	temp->gid = gid;
821*2d543d20SAndroid Build Coastguard Worker 	temp->sename = sename;
822*2d543d20SAndroid Build Coastguard Worker 	temp->prefix = prefix;
823*2d543d20SAndroid Build Coastguard Worker 	temp->home = home;
824*2d543d20SAndroid Build Coastguard Worker 	temp->level = level;
825*2d543d20SAndroid Build Coastguard Worker 	temp->login = lname;
826*2d543d20SAndroid Build Coastguard Worker 	temp->homedir_role = homedir_role;
827*2d543d20SAndroid Build Coastguard Worker 	temp->next = (*list);
828*2d543d20SAndroid Build Coastguard Worker 	(*list) = temp;
829*2d543d20SAndroid Build Coastguard Worker 
830*2d543d20SAndroid Build Coastguard Worker 	return STATUS_SUCCESS;
831*2d543d20SAndroid Build Coastguard Worker 
832*2d543d20SAndroid Build Coastguard Worker       cleanup:
833*2d543d20SAndroid Build Coastguard Worker 	free(name);
834*2d543d20SAndroid Build Coastguard Worker 	free(uid);
835*2d543d20SAndroid Build Coastguard Worker 	free(gid);
836*2d543d20SAndroid Build Coastguard Worker 	free(sename);
837*2d543d20SAndroid Build Coastguard Worker 	free(prefix);
838*2d543d20SAndroid Build Coastguard Worker 	free(home);
839*2d543d20SAndroid Build Coastguard Worker 	free(level);
840*2d543d20SAndroid Build Coastguard Worker 	free(lname);
841*2d543d20SAndroid Build Coastguard Worker 	free(homedir_role);
842*2d543d20SAndroid Build Coastguard Worker 	free(temp);
843*2d543d20SAndroid Build Coastguard Worker 	return STATUS_ERR;
844*2d543d20SAndroid Build Coastguard Worker }
845*2d543d20SAndroid Build Coastguard Worker 
pop_user_entry(genhomedircon_user_entry_t ** list)846*2d543d20SAndroid Build Coastguard Worker static void pop_user_entry(genhomedircon_user_entry_t ** list)
847*2d543d20SAndroid Build Coastguard Worker {
848*2d543d20SAndroid Build Coastguard Worker 	genhomedircon_user_entry_t *temp;
849*2d543d20SAndroid Build Coastguard Worker 
850*2d543d20SAndroid Build Coastguard Worker 	if (!list || !(*list))
851*2d543d20SAndroid Build Coastguard Worker 		return;
852*2d543d20SAndroid Build Coastguard Worker 
853*2d543d20SAndroid Build Coastguard Worker 	temp = *list;
854*2d543d20SAndroid Build Coastguard Worker 	*list = temp->next;
855*2d543d20SAndroid Build Coastguard Worker 	free(temp->name);
856*2d543d20SAndroid Build Coastguard Worker 	free(temp->uid);
857*2d543d20SAndroid Build Coastguard Worker 	free(temp->gid);
858*2d543d20SAndroid Build Coastguard Worker 	free(temp->sename);
859*2d543d20SAndroid Build Coastguard Worker 	free(temp->prefix);
860*2d543d20SAndroid Build Coastguard Worker 	free(temp->home);
861*2d543d20SAndroid Build Coastguard Worker 	free(temp->level);
862*2d543d20SAndroid Build Coastguard Worker 	free(temp->login);
863*2d543d20SAndroid Build Coastguard Worker 	free(temp->homedir_role);
864*2d543d20SAndroid Build Coastguard Worker 	free(temp);
865*2d543d20SAndroid Build Coastguard Worker }
866*2d543d20SAndroid Build Coastguard Worker 
setup_fallback_user(genhomedircon_settings_t * s)867*2d543d20SAndroid Build Coastguard Worker static int setup_fallback_user(genhomedircon_settings_t * s)
868*2d543d20SAndroid Build Coastguard Worker {
869*2d543d20SAndroid Build Coastguard Worker 	semanage_seuser_t **seuser_list = NULL;
870*2d543d20SAndroid Build Coastguard Worker 	unsigned int nseusers = 0;
871*2d543d20SAndroid Build Coastguard Worker 	semanage_user_key_t *key = NULL;
872*2d543d20SAndroid Build Coastguard Worker 	semanage_user_t *u = NULL;
873*2d543d20SAndroid Build Coastguard Worker 	const char *name = NULL;
874*2d543d20SAndroid Build Coastguard Worker 	const char *seuname = NULL;
875*2d543d20SAndroid Build Coastguard Worker 	const char *prefix = NULL;
876*2d543d20SAndroid Build Coastguard Worker 	const char *level = NULL;
877*2d543d20SAndroid Build Coastguard Worker 	const char *homedir_role = NULL;
878*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
879*2d543d20SAndroid Build Coastguard Worker 	int retval;
880*2d543d20SAndroid Build Coastguard Worker 	int errors = 0;
881*2d543d20SAndroid Build Coastguard Worker 
882*2d543d20SAndroid Build Coastguard Worker 	retval = semanage_seuser_list(s->h_semanage, &seuser_list, &nseusers);
883*2d543d20SAndroid Build Coastguard Worker 	if (retval < 0 || (nseusers < 1)) {
884*2d543d20SAndroid Build Coastguard Worker 		/* if there are no users, this function can't do any other work */
885*2d543d20SAndroid Build Coastguard Worker 		return errors;
886*2d543d20SAndroid Build Coastguard Worker 	}
887*2d543d20SAndroid Build Coastguard Worker 
888*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < nseusers; i++) {
889*2d543d20SAndroid Build Coastguard Worker 		name = semanage_seuser_get_name(seuser_list[i]);
890*2d543d20SAndroid Build Coastguard Worker 		if (strcmp(name, DEFAULT_LOGIN) == 0) {
891*2d543d20SAndroid Build Coastguard Worker 			seuname = semanage_seuser_get_sename(seuser_list[i]);
892*2d543d20SAndroid Build Coastguard Worker 
893*2d543d20SAndroid Build Coastguard Worker 			/* find the user structure given the name */
894*2d543d20SAndroid Build Coastguard Worker 			if (semanage_user_key_create(s->h_semanage, seuname,
895*2d543d20SAndroid Build Coastguard Worker 						     &key) < 0) {
896*2d543d20SAndroid Build Coastguard Worker 				errors = STATUS_ERR;
897*2d543d20SAndroid Build Coastguard Worker 				break;
898*2d543d20SAndroid Build Coastguard Worker 			}
899*2d543d20SAndroid Build Coastguard Worker 			if (semanage_user_query(s->h_semanage, key, &u) < 0)
900*2d543d20SAndroid Build Coastguard Worker 			{
901*2d543d20SAndroid Build Coastguard Worker 				prefix = name;
902*2d543d20SAndroid Build Coastguard Worker 				level = FALLBACK_LEVEL;
903*2d543d20SAndroid Build Coastguard Worker 			}
904*2d543d20SAndroid Build Coastguard Worker 			else
905*2d543d20SAndroid Build Coastguard Worker 			{
906*2d543d20SAndroid Build Coastguard Worker 				prefix = semanage_user_get_prefix(u);
907*2d543d20SAndroid Build Coastguard Worker 				level = semanage_user_get_mlslevel(u);
908*2d543d20SAndroid Build Coastguard Worker 				if (!level)
909*2d543d20SAndroid Build Coastguard Worker 					level = FALLBACK_LEVEL;
910*2d543d20SAndroid Build Coastguard Worker 			}
911*2d543d20SAndroid Build Coastguard Worker 
912*2d543d20SAndroid Build Coastguard Worker 			if (prefix_is_homedir_role(u, prefix)) {
913*2d543d20SAndroid Build Coastguard Worker 				homedir_role = prefix;
914*2d543d20SAndroid Build Coastguard Worker 			}
915*2d543d20SAndroid Build Coastguard Worker 
916*2d543d20SAndroid Build Coastguard Worker 			if (push_user_entry(&(s->fallback), FALLBACK_NAME,
917*2d543d20SAndroid Build Coastguard Worker 					    FALLBACK_UIDGID, FALLBACK_UIDGID,
918*2d543d20SAndroid Build Coastguard Worker 					    seuname, prefix, "", level,
919*2d543d20SAndroid Build Coastguard Worker 					    FALLBACK_NAME, homedir_role) != 0)
920*2d543d20SAndroid Build Coastguard Worker 				errors = STATUS_ERR;
921*2d543d20SAndroid Build Coastguard Worker 			semanage_user_key_free(key);
922*2d543d20SAndroid Build Coastguard Worker 			if (u)
923*2d543d20SAndroid Build Coastguard Worker 				semanage_user_free(u);
924*2d543d20SAndroid Build Coastguard Worker 			break;
925*2d543d20SAndroid Build Coastguard Worker 		}
926*2d543d20SAndroid Build Coastguard Worker 	}
927*2d543d20SAndroid Build Coastguard Worker 
928*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < nseusers; i++)
929*2d543d20SAndroid Build Coastguard Worker 		semanage_seuser_free(seuser_list[i]);
930*2d543d20SAndroid Build Coastguard Worker 	free(seuser_list);
931*2d543d20SAndroid Build Coastguard Worker 
932*2d543d20SAndroid Build Coastguard Worker 	return errors;
933*2d543d20SAndroid Build Coastguard Worker }
934*2d543d20SAndroid Build Coastguard Worker 
find_user(genhomedircon_user_entry_t * head,const char * name)935*2d543d20SAndroid Build Coastguard Worker static genhomedircon_user_entry_t *find_user(genhomedircon_user_entry_t *head,
936*2d543d20SAndroid Build Coastguard Worker 					     const char *name)
937*2d543d20SAndroid Build Coastguard Worker {
938*2d543d20SAndroid Build Coastguard Worker 	for(; head; head = head->next) {
939*2d543d20SAndroid Build Coastguard Worker 		if (strcmp(head->name, name) == 0) {
940*2d543d20SAndroid Build Coastguard Worker 			return head;
941*2d543d20SAndroid Build Coastguard Worker 		}
942*2d543d20SAndroid Build Coastguard Worker 	}
943*2d543d20SAndroid Build Coastguard Worker 
944*2d543d20SAndroid Build Coastguard Worker 	return NULL;
945*2d543d20SAndroid Build Coastguard Worker }
946*2d543d20SAndroid Build Coastguard Worker 
add_user(genhomedircon_settings_t * s,genhomedircon_user_entry_t ** head,semanage_user_t * user,const char * name,const char * sename,const char * selogin)947*2d543d20SAndroid Build Coastguard Worker static int add_user(genhomedircon_settings_t * s,
948*2d543d20SAndroid Build Coastguard Worker 		    genhomedircon_user_entry_t **head,
949*2d543d20SAndroid Build Coastguard Worker 		    semanage_user_t *user,
950*2d543d20SAndroid Build Coastguard Worker 		    const char *name,
951*2d543d20SAndroid Build Coastguard Worker 		    const char *sename,
952*2d543d20SAndroid Build Coastguard Worker 		    const char *selogin)
953*2d543d20SAndroid Build Coastguard Worker {
954*2d543d20SAndroid Build Coastguard Worker 	if (selogin[0] == '%') {
955*2d543d20SAndroid Build Coastguard Worker 		genhomedircon_user_entry_t *orig = find_user(*head, name);
956*2d543d20SAndroid Build Coastguard Worker 		if (orig != NULL && orig->login[0] == '%') {
957*2d543d20SAndroid Build Coastguard Worker 			ERR(s->h_semanage, "User %s is already mapped to"
958*2d543d20SAndroid Build Coastguard Worker 			    " group %s, but also belongs to group %s. Add an"
959*2d543d20SAndroid Build Coastguard Worker 			    " explicit mapping for this user to"
960*2d543d20SAndroid Build Coastguard Worker 			    " override group mappings.",
961*2d543d20SAndroid Build Coastguard Worker 			    name, orig->login + 1, selogin + 1);
962*2d543d20SAndroid Build Coastguard Worker 			return STATUS_ERR;
963*2d543d20SAndroid Build Coastguard Worker 		} else if (orig != NULL) {
964*2d543d20SAndroid Build Coastguard Worker 			// user mappings take precedence
965*2d543d20SAndroid Build Coastguard Worker 			return STATUS_SUCCESS;
966*2d543d20SAndroid Build Coastguard Worker 		}
967*2d543d20SAndroid Build Coastguard Worker 	}
968*2d543d20SAndroid Build Coastguard Worker 
969*2d543d20SAndroid Build Coastguard Worker 	int retval = STATUS_ERR;
970*2d543d20SAndroid Build Coastguard Worker 
971*2d543d20SAndroid Build Coastguard Worker 	char *rbuf = NULL;
972*2d543d20SAndroid Build Coastguard Worker 	long rbuflen;
973*2d543d20SAndroid Build Coastguard Worker 	struct passwd pwstorage, *pwent = NULL;
974*2d543d20SAndroid Build Coastguard Worker 	const char *prefix = NULL;
975*2d543d20SAndroid Build Coastguard Worker 	const char *level = NULL;
976*2d543d20SAndroid Build Coastguard Worker 	const char *homedir_role = NULL;
977*2d543d20SAndroid Build Coastguard Worker 	char uid[11];
978*2d543d20SAndroid Build Coastguard Worker 	char gid[11];
979*2d543d20SAndroid Build Coastguard Worker 
980*2d543d20SAndroid Build Coastguard Worker 	errno = 0;
981*2d543d20SAndroid Build Coastguard Worker 	/* Allocate space for the getpwnam_r buffer */
982*2d543d20SAndroid Build Coastguard Worker 	rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
983*2d543d20SAndroid Build Coastguard Worker 	if (rbuflen == -1 && errno == 0)
984*2d543d20SAndroid Build Coastguard Worker 		/* sysconf returning -1 with no errno means indeterminate size */
985*2d543d20SAndroid Build Coastguard Worker 		rbuflen = 1024;
986*2d543d20SAndroid Build Coastguard Worker 	else if (rbuflen <= 0)
987*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
988*2d543d20SAndroid Build Coastguard Worker 
989*2d543d20SAndroid Build Coastguard Worker 	if (user) {
990*2d543d20SAndroid Build Coastguard Worker 		prefix = semanage_user_get_prefix(user);
991*2d543d20SAndroid Build Coastguard Worker 		level = semanage_user_get_mlslevel(user);
992*2d543d20SAndroid Build Coastguard Worker 
993*2d543d20SAndroid Build Coastguard Worker 		if (!level) {
994*2d543d20SAndroid Build Coastguard Worker 			level = FALLBACK_LEVEL;
995*2d543d20SAndroid Build Coastguard Worker 		}
996*2d543d20SAndroid Build Coastguard Worker 	} else {
997*2d543d20SAndroid Build Coastguard Worker 		prefix = name;
998*2d543d20SAndroid Build Coastguard Worker 		level = FALLBACK_LEVEL;
999*2d543d20SAndroid Build Coastguard Worker 	}
1000*2d543d20SAndroid Build Coastguard Worker 
1001*2d543d20SAndroid Build Coastguard Worker 	if (prefix_is_homedir_role(user, prefix)) {
1002*2d543d20SAndroid Build Coastguard Worker 		homedir_role = prefix;
1003*2d543d20SAndroid Build Coastguard Worker 	}
1004*2d543d20SAndroid Build Coastguard Worker 
1005*2d543d20SAndroid Build Coastguard Worker retry:
1006*2d543d20SAndroid Build Coastguard Worker 	rbuf = malloc(rbuflen);
1007*2d543d20SAndroid Build Coastguard Worker 	if (rbuf == NULL)
1008*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1009*2d543d20SAndroid Build Coastguard Worker 
1010*2d543d20SAndroid Build Coastguard Worker 	retval = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent);
1011*2d543d20SAndroid Build Coastguard Worker 	if (retval == ERANGE && rbuflen < LONG_MAX / 2) {
1012*2d543d20SAndroid Build Coastguard Worker 		free(rbuf);
1013*2d543d20SAndroid Build Coastguard Worker 		rbuflen *= 2;
1014*2d543d20SAndroid Build Coastguard Worker 		goto retry;
1015*2d543d20SAndroid Build Coastguard Worker 	}
1016*2d543d20SAndroid Build Coastguard Worker 	if (retval != 0 || pwent == NULL) {
1017*2d543d20SAndroid Build Coastguard Worker 		if (retval != 0 && retval != ENOENT) {
1018*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1019*2d543d20SAndroid Build Coastguard Worker 		}
1020*2d543d20SAndroid Build Coastguard Worker 
1021*2d543d20SAndroid Build Coastguard Worker 		WARN(s->h_semanage,
1022*2d543d20SAndroid Build Coastguard Worker 		     "user %s not in password file", name);
1023*2d543d20SAndroid Build Coastguard Worker 		retval = STATUS_SUCCESS;
1024*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1025*2d543d20SAndroid Build Coastguard Worker 	}
1026*2d543d20SAndroid Build Coastguard Worker 
1027*2d543d20SAndroid Build Coastguard Worker 	int len = strlen(pwent->pw_dir) -1;
1028*2d543d20SAndroid Build Coastguard Worker 	for(; len > 0 && pwent->pw_dir[len] == '/'; len--) {
1029*2d543d20SAndroid Build Coastguard Worker 		pwent->pw_dir[len] = '\0';
1030*2d543d20SAndroid Build Coastguard Worker 	}
1031*2d543d20SAndroid Build Coastguard Worker 
1032*2d543d20SAndroid Build Coastguard Worker 	if (strcmp(pwent->pw_dir, "/") == 0) {
1033*2d543d20SAndroid Build Coastguard Worker 		/* don't relabel / genhomdircon checked to see if root
1034*2d543d20SAndroid Build Coastguard Worker 		 * was the user and if so, set his home directory to
1035*2d543d20SAndroid Build Coastguard Worker 		 * /root */
1036*2d543d20SAndroid Build Coastguard Worker 		retval = STATUS_SUCCESS;
1037*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1038*2d543d20SAndroid Build Coastguard Worker 	}
1039*2d543d20SAndroid Build Coastguard Worker 
1040*2d543d20SAndroid Build Coastguard Worker 	if (ignore(pwent->pw_dir)) {
1041*2d543d20SAndroid Build Coastguard Worker 		retval = STATUS_SUCCESS;
1042*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1043*2d543d20SAndroid Build Coastguard Worker 	}
1044*2d543d20SAndroid Build Coastguard Worker 
1045*2d543d20SAndroid Build Coastguard Worker 	len = snprintf(uid, sizeof(uid), "%u", pwent->pw_uid);
1046*2d543d20SAndroid Build Coastguard Worker 	if (len < 0 || len >= (int)sizeof(uid)) {
1047*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1048*2d543d20SAndroid Build Coastguard Worker 	}
1049*2d543d20SAndroid Build Coastguard Worker 
1050*2d543d20SAndroid Build Coastguard Worker 	len = snprintf(gid, sizeof(gid), "%u", pwent->pw_gid);
1051*2d543d20SAndroid Build Coastguard Worker 	if (len < 0 || len >= (int)sizeof(gid)) {
1052*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1053*2d543d20SAndroid Build Coastguard Worker 	}
1054*2d543d20SAndroid Build Coastguard Worker 
1055*2d543d20SAndroid Build Coastguard Worker 	retval = push_user_entry(head, name, uid, gid, sename, prefix,
1056*2d543d20SAndroid Build Coastguard Worker 				pwent->pw_dir, level, selogin, homedir_role);
1057*2d543d20SAndroid Build Coastguard Worker cleanup:
1058*2d543d20SAndroid Build Coastguard Worker 	free(rbuf);
1059*2d543d20SAndroid Build Coastguard Worker 	return retval;
1060*2d543d20SAndroid Build Coastguard Worker }
1061*2d543d20SAndroid Build Coastguard Worker 
get_group_users(genhomedircon_settings_t * s,genhomedircon_user_entry_t ** head,semanage_user_t * user,const char * sename,const char * selogin)1062*2d543d20SAndroid Build Coastguard Worker static int get_group_users(genhomedircon_settings_t * s,
1063*2d543d20SAndroid Build Coastguard Worker 			  genhomedircon_user_entry_t **head,
1064*2d543d20SAndroid Build Coastguard Worker 			  semanage_user_t *user,
1065*2d543d20SAndroid Build Coastguard Worker 			  const char *sename,
1066*2d543d20SAndroid Build Coastguard Worker 			  const char *selogin)
1067*2d543d20SAndroid Build Coastguard Worker {
1068*2d543d20SAndroid Build Coastguard Worker 	int retval = STATUS_ERR;
1069*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
1070*2d543d20SAndroid Build Coastguard Worker 
1071*2d543d20SAndroid Build Coastguard Worker 	long grbuflen;
1072*2d543d20SAndroid Build Coastguard Worker 	char *grbuf = NULL;
1073*2d543d20SAndroid Build Coastguard Worker 	struct group grstorage, *group = NULL;
1074*2d543d20SAndroid Build Coastguard Worker 	struct passwd *pw = NULL;
1075*2d543d20SAndroid Build Coastguard Worker 
1076*2d543d20SAndroid Build Coastguard Worker 	errno = 0;
1077*2d543d20SAndroid Build Coastguard Worker 	grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
1078*2d543d20SAndroid Build Coastguard Worker 	if (grbuflen == -1 && errno == 0)
1079*2d543d20SAndroid Build Coastguard Worker 		/* sysconf returning -1 with no errno means indeterminate size */
1080*2d543d20SAndroid Build Coastguard Worker 		grbuflen = 1024;
1081*2d543d20SAndroid Build Coastguard Worker 	else if (grbuflen <= 0)
1082*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1083*2d543d20SAndroid Build Coastguard Worker 	grbuf = malloc(grbuflen);
1084*2d543d20SAndroid Build Coastguard Worker 	if (grbuf == NULL)
1085*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1086*2d543d20SAndroid Build Coastguard Worker 
1087*2d543d20SAndroid Build Coastguard Worker 	const char *grname = selogin + 1;
1088*2d543d20SAndroid Build Coastguard Worker 
1089*2d543d20SAndroid Build Coastguard Worker 	errno = 0;
1090*2d543d20SAndroid Build Coastguard Worker 	while (
1091*2d543d20SAndroid Build Coastguard Worker 		(retval = getgrnam_r(grname, &grstorage, grbuf, (size_t) grbuflen, &group)) != 0 &&
1092*2d543d20SAndroid Build Coastguard Worker 		errno == ERANGE
1093*2d543d20SAndroid Build Coastguard Worker 	) {
1094*2d543d20SAndroid Build Coastguard Worker 		char *new_grbuf;
1095*2d543d20SAndroid Build Coastguard Worker 		grbuflen *= 2;
1096*2d543d20SAndroid Build Coastguard Worker 		if (grbuflen < 0)
1097*2d543d20SAndroid Build Coastguard Worker 			/* the member list could exceed 2Gb on a system with a 32-bit CPU (where
1098*2d543d20SAndroid Build Coastguard Worker 			 * sizeof(long) = 4) - if this ever happened, the loop would become infinite. */
1099*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1100*2d543d20SAndroid Build Coastguard Worker 		new_grbuf = realloc(grbuf, grbuflen);
1101*2d543d20SAndroid Build Coastguard Worker 		if (new_grbuf == NULL)
1102*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1103*2d543d20SAndroid Build Coastguard Worker 		grbuf = new_grbuf;
1104*2d543d20SAndroid Build Coastguard Worker 	}
1105*2d543d20SAndroid Build Coastguard Worker 	if (retval != 0)
1106*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1107*2d543d20SAndroid Build Coastguard Worker 
1108*2d543d20SAndroid Build Coastguard Worker 	if (group == NULL) {
1109*2d543d20SAndroid Build Coastguard Worker 		ERR(s->h_semanage, "Can't find group named %s\n", grname);
1110*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1111*2d543d20SAndroid Build Coastguard Worker 	}
1112*2d543d20SAndroid Build Coastguard Worker 
1113*2d543d20SAndroid Build Coastguard Worker 	size_t nmembers = 0;
1114*2d543d20SAndroid Build Coastguard Worker 	char **members = group->gr_mem;
1115*2d543d20SAndroid Build Coastguard Worker 
1116*2d543d20SAndroid Build Coastguard Worker 	while (*members != NULL) {
1117*2d543d20SAndroid Build Coastguard Worker 		nmembers++;
1118*2d543d20SAndroid Build Coastguard Worker 		members++;
1119*2d543d20SAndroid Build Coastguard Worker 	}
1120*2d543d20SAndroid Build Coastguard Worker 
1121*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < nmembers; i++) {
1122*2d543d20SAndroid Build Coastguard Worker 		const char *uname = group->gr_mem[i];
1123*2d543d20SAndroid Build Coastguard Worker 
1124*2d543d20SAndroid Build Coastguard Worker 		if (add_user(s, head, user, uname, sename, selogin) < 0) {
1125*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1126*2d543d20SAndroid Build Coastguard Worker 		}
1127*2d543d20SAndroid Build Coastguard Worker 	}
1128*2d543d20SAndroid Build Coastguard Worker 
1129*2d543d20SAndroid Build Coastguard Worker 	setpwent();
1130*2d543d20SAndroid Build Coastguard Worker 	while (1) {
1131*2d543d20SAndroid Build Coastguard Worker 		errno = 0;
1132*2d543d20SAndroid Build Coastguard Worker 		pw = getpwent();
1133*2d543d20SAndroid Build Coastguard Worker 		if (pw == NULL)
1134*2d543d20SAndroid Build Coastguard Worker 			break;
1135*2d543d20SAndroid Build Coastguard Worker 		// skip users who also have this group as their
1136*2d543d20SAndroid Build Coastguard Worker 		// primary group
1137*2d543d20SAndroid Build Coastguard Worker 		if (lfind(pw->pw_name, group->gr_mem, &nmembers,
1138*2d543d20SAndroid Build Coastguard Worker 			  sizeof(char *), &STR_COMPARATOR)) {
1139*2d543d20SAndroid Build Coastguard Worker 			continue;
1140*2d543d20SAndroid Build Coastguard Worker 		}
1141*2d543d20SAndroid Build Coastguard Worker 
1142*2d543d20SAndroid Build Coastguard Worker 		if (group->gr_gid == pw->pw_gid) {
1143*2d543d20SAndroid Build Coastguard Worker 			if (add_user(s, head, user, pw->pw_name,
1144*2d543d20SAndroid Build Coastguard Worker 				     sename, selogin) < 0) {
1145*2d543d20SAndroid Build Coastguard Worker 				goto cleanup;
1146*2d543d20SAndroid Build Coastguard Worker 			}
1147*2d543d20SAndroid Build Coastguard Worker 		}
1148*2d543d20SAndroid Build Coastguard Worker 	}
1149*2d543d20SAndroid Build Coastguard Worker 
1150*2d543d20SAndroid Build Coastguard Worker 	retval = STATUS_SUCCESS;
1151*2d543d20SAndroid Build Coastguard Worker cleanup:
1152*2d543d20SAndroid Build Coastguard Worker 	endpwent();
1153*2d543d20SAndroid Build Coastguard Worker 	free(grbuf);
1154*2d543d20SAndroid Build Coastguard Worker 
1155*2d543d20SAndroid Build Coastguard Worker 	return retval;
1156*2d543d20SAndroid Build Coastguard Worker }
1157*2d543d20SAndroid Build Coastguard Worker 
get_users(genhomedircon_settings_t * s,int * errors)1158*2d543d20SAndroid Build Coastguard Worker static genhomedircon_user_entry_t *get_users(genhomedircon_settings_t * s,
1159*2d543d20SAndroid Build Coastguard Worker 					     int *errors)
1160*2d543d20SAndroid Build Coastguard Worker {
1161*2d543d20SAndroid Build Coastguard Worker 	genhomedircon_user_entry_t *head = NULL;
1162*2d543d20SAndroid Build Coastguard Worker 	semanage_seuser_t **seuser_list = NULL;
1163*2d543d20SAndroid Build Coastguard Worker 	unsigned int nseusers = 0;
1164*2d543d20SAndroid Build Coastguard Worker 	semanage_user_t **user_list = NULL;
1165*2d543d20SAndroid Build Coastguard Worker 	unsigned int nusers = 0;
1166*2d543d20SAndroid Build Coastguard Worker 	semanage_user_t **u = NULL;
1167*2d543d20SAndroid Build Coastguard Worker 	const char *name = NULL;
1168*2d543d20SAndroid Build Coastguard Worker 	const char *seuname = NULL;
1169*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
1170*2d543d20SAndroid Build Coastguard Worker 	int retval;
1171*2d543d20SAndroid Build Coastguard Worker 
1172*2d543d20SAndroid Build Coastguard Worker 	*errors = 0;
1173*2d543d20SAndroid Build Coastguard Worker 	retval = semanage_seuser_list(s->h_semanage, &seuser_list, &nseusers);
1174*2d543d20SAndroid Build Coastguard Worker 	if (retval < 0 || (nseusers < 1)) {
1175*2d543d20SAndroid Build Coastguard Worker 		/* if there are no users, this function can't do any other work */
1176*2d543d20SAndroid Build Coastguard Worker 		return NULL;
1177*2d543d20SAndroid Build Coastguard Worker 	}
1178*2d543d20SAndroid Build Coastguard Worker 
1179*2d543d20SAndroid Build Coastguard Worker 	if (semanage_user_list(s->h_semanage, &user_list, &nusers) < 0) {
1180*2d543d20SAndroid Build Coastguard Worker 		nusers = 0;
1181*2d543d20SAndroid Build Coastguard Worker 	}
1182*2d543d20SAndroid Build Coastguard Worker 
1183*2d543d20SAndroid Build Coastguard Worker 	qsort(seuser_list, nseusers, sizeof(semanage_seuser_t *),
1184*2d543d20SAndroid Build Coastguard Worker 	      &seuser_sort_func);
1185*2d543d20SAndroid Build Coastguard Worker 	qsort(user_list, nusers, sizeof(semanage_user_t *),
1186*2d543d20SAndroid Build Coastguard Worker 	      (int (*)(const void *, const void *))&user_sort_func);
1187*2d543d20SAndroid Build Coastguard Worker 
1188*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < nseusers; i++) {
1189*2d543d20SAndroid Build Coastguard Worker 		seuname = semanage_seuser_get_sename(seuser_list[i]);
1190*2d543d20SAndroid Build Coastguard Worker 		name = semanage_seuser_get_name(seuser_list[i]);
1191*2d543d20SAndroid Build Coastguard Worker 
1192*2d543d20SAndroid Build Coastguard Worker 		if (strcmp(name, DEFAULT_LOGIN) == 0)
1193*2d543d20SAndroid Build Coastguard Worker 			continue;
1194*2d543d20SAndroid Build Coastguard Worker 
1195*2d543d20SAndroid Build Coastguard Worker 		/* find the user structure given the name */
1196*2d543d20SAndroid Build Coastguard Worker 		u = bsearch(seuname, user_list, nusers, sizeof(semanage_user_t *),
1197*2d543d20SAndroid Build Coastguard Worker 			    (int (*)(const void *, const void *))
1198*2d543d20SAndroid Build Coastguard Worker 			    &name_user_cmp);
1199*2d543d20SAndroid Build Coastguard Worker 
1200*2d543d20SAndroid Build Coastguard Worker 		/* %groupname syntax */
1201*2d543d20SAndroid Build Coastguard Worker 		if (name[0] == '%') {
1202*2d543d20SAndroid Build Coastguard Worker 			retval = get_group_users(s, &head, *u, seuname,
1203*2d543d20SAndroid Build Coastguard Worker 						name);
1204*2d543d20SAndroid Build Coastguard Worker 		} else {
1205*2d543d20SAndroid Build Coastguard Worker 			retval = add_user(s, &head, *u, name,
1206*2d543d20SAndroid Build Coastguard Worker 					  seuname, name);
1207*2d543d20SAndroid Build Coastguard Worker 		}
1208*2d543d20SAndroid Build Coastguard Worker 
1209*2d543d20SAndroid Build Coastguard Worker 		if (retval != 0) {
1210*2d543d20SAndroid Build Coastguard Worker 			*errors = STATUS_ERR;
1211*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1212*2d543d20SAndroid Build Coastguard Worker 		}
1213*2d543d20SAndroid Build Coastguard Worker 	}
1214*2d543d20SAndroid Build Coastguard Worker 
1215*2d543d20SAndroid Build Coastguard Worker       cleanup:
1216*2d543d20SAndroid Build Coastguard Worker 	if (*errors) {
1217*2d543d20SAndroid Build Coastguard Worker 		for (; head; pop_user_entry(&head)) {
1218*2d543d20SAndroid Build Coastguard Worker 			/* the pop function takes care of all the cleanup
1219*2d543d20SAndroid Build Coastguard Worker 			   so the loop body is just empty */
1220*2d543d20SAndroid Build Coastguard Worker 		}
1221*2d543d20SAndroid Build Coastguard Worker 	}
1222*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < nseusers; i++) {
1223*2d543d20SAndroid Build Coastguard Worker 		semanage_seuser_free(seuser_list[i]);
1224*2d543d20SAndroid Build Coastguard Worker 	}
1225*2d543d20SAndroid Build Coastguard Worker 	free(seuser_list);
1226*2d543d20SAndroid Build Coastguard Worker 
1227*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < nusers; i++) {
1228*2d543d20SAndroid Build Coastguard Worker 		semanage_user_free(user_list[i]);
1229*2d543d20SAndroid Build Coastguard Worker 	}
1230*2d543d20SAndroid Build Coastguard Worker 	free(user_list);
1231*2d543d20SAndroid Build Coastguard Worker 
1232*2d543d20SAndroid Build Coastguard Worker 	return head;
1233*2d543d20SAndroid Build Coastguard Worker }
1234*2d543d20SAndroid Build Coastguard Worker 
write_gen_home_dir_context(genhomedircon_settings_t * s,FILE * out,semanage_list_t * username_context_tpl,semanage_list_t * user_context_tpl,semanage_list_t * homedir_context_tpl)1235*2d543d20SAndroid Build Coastguard Worker static int write_gen_home_dir_context(genhomedircon_settings_t * s, FILE * out,
1236*2d543d20SAndroid Build Coastguard Worker 				      semanage_list_t * username_context_tpl,
1237*2d543d20SAndroid Build Coastguard Worker 				      semanage_list_t * user_context_tpl,
1238*2d543d20SAndroid Build Coastguard Worker 				      semanage_list_t * homedir_context_tpl)
1239*2d543d20SAndroid Build Coastguard Worker {
1240*2d543d20SAndroid Build Coastguard Worker 	genhomedircon_user_entry_t *users;
1241*2d543d20SAndroid Build Coastguard Worker 	int errors = 0;
1242*2d543d20SAndroid Build Coastguard Worker 
1243*2d543d20SAndroid Build Coastguard Worker 	users = get_users(s, &errors);
1244*2d543d20SAndroid Build Coastguard Worker 	if (!users && errors) {
1245*2d543d20SAndroid Build Coastguard Worker 		return STATUS_ERR;
1246*2d543d20SAndroid Build Coastguard Worker 	}
1247*2d543d20SAndroid Build Coastguard Worker 
1248*2d543d20SAndroid Build Coastguard Worker 	for (; users; pop_user_entry(&users)) {
1249*2d543d20SAndroid Build Coastguard Worker 		if (write_home_dir_context(s, out, homedir_context_tpl, users))
1250*2d543d20SAndroid Build Coastguard Worker 			goto err;
1251*2d543d20SAndroid Build Coastguard Worker 		if (write_username_context(s, out, username_context_tpl, users))
1252*2d543d20SAndroid Build Coastguard Worker 			goto err;
1253*2d543d20SAndroid Build Coastguard Worker 		if (write_user_context(s, out, user_context_tpl, users))
1254*2d543d20SAndroid Build Coastguard Worker 			goto err;
1255*2d543d20SAndroid Build Coastguard Worker 	}
1256*2d543d20SAndroid Build Coastguard Worker 
1257*2d543d20SAndroid Build Coastguard Worker 	return STATUS_SUCCESS;
1258*2d543d20SAndroid Build Coastguard Worker err:
1259*2d543d20SAndroid Build Coastguard Worker 	for (; users; pop_user_entry(&users)) {
1260*2d543d20SAndroid Build Coastguard Worker 	/* the pop function takes care of all the cleanup
1261*2d543d20SAndroid Build Coastguard Worker 	 * so the loop body is just empty */
1262*2d543d20SAndroid Build Coastguard Worker 	}
1263*2d543d20SAndroid Build Coastguard Worker 
1264*2d543d20SAndroid Build Coastguard Worker 	return STATUS_ERR;
1265*2d543d20SAndroid Build Coastguard Worker }
1266*2d543d20SAndroid Build Coastguard Worker 
1267*2d543d20SAndroid Build Coastguard Worker /**
1268*2d543d20SAndroid Build Coastguard Worker  * @param	s	settings structure, stores various paths etc. Must never be NULL
1269*2d543d20SAndroid Build Coastguard Worker  * @param	out	the FILE to put all the output in.
1270*2d543d20SAndroid Build Coastguard Worker  * @return	0 on success
1271*2d543d20SAndroid Build Coastguard Worker  */
write_context_file(genhomedircon_settings_t * s,FILE * out)1272*2d543d20SAndroid Build Coastguard Worker static int write_context_file(genhomedircon_settings_t * s, FILE * out)
1273*2d543d20SAndroid Build Coastguard Worker {
1274*2d543d20SAndroid Build Coastguard Worker 	semanage_list_t *homedirs = NULL;
1275*2d543d20SAndroid Build Coastguard Worker 	semanage_list_t *h = NULL;
1276*2d543d20SAndroid Build Coastguard Worker 	semanage_list_t *homedir_context_tpl = NULL;
1277*2d543d20SAndroid Build Coastguard Worker 	semanage_list_t *homeroot_context_tpl = NULL;
1278*2d543d20SAndroid Build Coastguard Worker 	semanage_list_t *username_context_tpl = NULL;
1279*2d543d20SAndroid Build Coastguard Worker 	semanage_list_t *user_context_tpl = NULL;
1280*2d543d20SAndroid Build Coastguard Worker 	int retval = STATUS_SUCCESS;
1281*2d543d20SAndroid Build Coastguard Worker 
1282*2d543d20SAndroid Build Coastguard Worker 	homedir_context_tpl = make_template(s, &HOME_DIR_PRED);
1283*2d543d20SAndroid Build Coastguard Worker 	homeroot_context_tpl = make_template(s, &HOME_ROOT_PRED);
1284*2d543d20SAndroid Build Coastguard Worker 	username_context_tpl = make_template(s, &USERNAME_CONTEXT_PRED);
1285*2d543d20SAndroid Build Coastguard Worker 	user_context_tpl = make_template(s, &USER_CONTEXT_PRED);
1286*2d543d20SAndroid Build Coastguard Worker 
1287*2d543d20SAndroid Build Coastguard Worker 	if (!homedir_context_tpl
1288*2d543d20SAndroid Build Coastguard Worker 	 && !homeroot_context_tpl
1289*2d543d20SAndroid Build Coastguard Worker 	 && !username_context_tpl
1290*2d543d20SAndroid Build Coastguard Worker 	 && !user_context_tpl)
1291*2d543d20SAndroid Build Coastguard Worker 		goto done;
1292*2d543d20SAndroid Build Coastguard Worker 
1293*2d543d20SAndroid Build Coastguard Worker 	if (write_file_context_header(out) != STATUS_SUCCESS) {
1294*2d543d20SAndroid Build Coastguard Worker 		retval = STATUS_ERR;
1295*2d543d20SAndroid Build Coastguard Worker 		goto done;
1296*2d543d20SAndroid Build Coastguard Worker 	}
1297*2d543d20SAndroid Build Coastguard Worker 
1298*2d543d20SAndroid Build Coastguard Worker 	if (setup_fallback_user(s) != 0) {
1299*2d543d20SAndroid Build Coastguard Worker 		retval = STATUS_ERR;
1300*2d543d20SAndroid Build Coastguard Worker 		goto done;
1301*2d543d20SAndroid Build Coastguard Worker 	}
1302*2d543d20SAndroid Build Coastguard Worker 
1303*2d543d20SAndroid Build Coastguard Worker 	if (homedir_context_tpl || homeroot_context_tpl) {
1304*2d543d20SAndroid Build Coastguard Worker 		homedirs = get_home_dirs(s);
1305*2d543d20SAndroid Build Coastguard Worker 		if (!homedirs) {
1306*2d543d20SAndroid Build Coastguard Worker 			WARN(s->h_semanage,
1307*2d543d20SAndroid Build Coastguard Worker 			     "no home directories were available, exiting without writing");
1308*2d543d20SAndroid Build Coastguard Worker 			goto done;
1309*2d543d20SAndroid Build Coastguard Worker 		}
1310*2d543d20SAndroid Build Coastguard Worker 
1311*2d543d20SAndroid Build Coastguard Worker 		for (h = homedirs; h; h = h->next) {
1312*2d543d20SAndroid Build Coastguard Worker 			char *temp = NULL;
1313*2d543d20SAndroid Build Coastguard Worker 
1314*2d543d20SAndroid Build Coastguard Worker 			if (asprintf(&temp, "%s/%s", h->data, FALLBACK_NAME) < 0) {
1315*2d543d20SAndroid Build Coastguard Worker 				retval = STATUS_ERR;
1316*2d543d20SAndroid Build Coastguard Worker 				goto done;
1317*2d543d20SAndroid Build Coastguard Worker 			}
1318*2d543d20SAndroid Build Coastguard Worker 
1319*2d543d20SAndroid Build Coastguard Worker 			free(s->fallback->home);
1320*2d543d20SAndroid Build Coastguard Worker 			s->fallback->home = temp;
1321*2d543d20SAndroid Build Coastguard Worker 
1322*2d543d20SAndroid Build Coastguard Worker 			if (write_home_dir_context(s, out, homedir_context_tpl,
1323*2d543d20SAndroid Build Coastguard Worker 						   s->fallback) != STATUS_SUCCESS) {
1324*2d543d20SAndroid Build Coastguard Worker 				free(temp);
1325*2d543d20SAndroid Build Coastguard Worker 				s->fallback->home = NULL;
1326*2d543d20SAndroid Build Coastguard Worker 				retval = STATUS_ERR;
1327*2d543d20SAndroid Build Coastguard Worker 				goto done;
1328*2d543d20SAndroid Build Coastguard Worker 			}
1329*2d543d20SAndroid Build Coastguard Worker 			if (write_home_root_context(s, out,
1330*2d543d20SAndroid Build Coastguard Worker 						    homeroot_context_tpl,
1331*2d543d20SAndroid Build Coastguard Worker 						    h->data) != STATUS_SUCCESS) {
1332*2d543d20SAndroid Build Coastguard Worker 				free(temp);
1333*2d543d20SAndroid Build Coastguard Worker 				s->fallback->home = NULL;
1334*2d543d20SAndroid Build Coastguard Worker 				retval = STATUS_ERR;
1335*2d543d20SAndroid Build Coastguard Worker 				goto done;
1336*2d543d20SAndroid Build Coastguard Worker 			}
1337*2d543d20SAndroid Build Coastguard Worker 
1338*2d543d20SAndroid Build Coastguard Worker 			free(temp);
1339*2d543d20SAndroid Build Coastguard Worker 			s->fallback->home = NULL;
1340*2d543d20SAndroid Build Coastguard Worker 		}
1341*2d543d20SAndroid Build Coastguard Worker 	}
1342*2d543d20SAndroid Build Coastguard Worker 	if (user_context_tpl || username_context_tpl) {
1343*2d543d20SAndroid Build Coastguard Worker 		if (write_username_context(s, out, username_context_tpl,
1344*2d543d20SAndroid Build Coastguard Worker 					   s->fallback) != STATUS_SUCCESS) {
1345*2d543d20SAndroid Build Coastguard Worker 			retval = STATUS_ERR;
1346*2d543d20SAndroid Build Coastguard Worker 			goto done;
1347*2d543d20SAndroid Build Coastguard Worker 		}
1348*2d543d20SAndroid Build Coastguard Worker 
1349*2d543d20SAndroid Build Coastguard Worker 		if (write_user_context(s, out, user_context_tpl,
1350*2d543d20SAndroid Build Coastguard Worker 				       s->fallback) != STATUS_SUCCESS) {
1351*2d543d20SAndroid Build Coastguard Worker 			retval = STATUS_ERR;
1352*2d543d20SAndroid Build Coastguard Worker 			goto done;
1353*2d543d20SAndroid Build Coastguard Worker 		}
1354*2d543d20SAndroid Build Coastguard Worker 
1355*2d543d20SAndroid Build Coastguard Worker 		if (write_gen_home_dir_context(s, out, username_context_tpl,
1356*2d543d20SAndroid Build Coastguard Worker 					       user_context_tpl, homedir_context_tpl)
1357*2d543d20SAndroid Build Coastguard Worker 				!= STATUS_SUCCESS) {
1358*2d543d20SAndroid Build Coastguard Worker 			retval = STATUS_ERR;
1359*2d543d20SAndroid Build Coastguard Worker 		}
1360*2d543d20SAndroid Build Coastguard Worker 	}
1361*2d543d20SAndroid Build Coastguard Worker 
1362*2d543d20SAndroid Build Coastguard Worker done:
1363*2d543d20SAndroid Build Coastguard Worker 	/* Cleanup */
1364*2d543d20SAndroid Build Coastguard Worker 	semanage_list_destroy(&homedirs);
1365*2d543d20SAndroid Build Coastguard Worker 	semanage_list_destroy(&username_context_tpl);
1366*2d543d20SAndroid Build Coastguard Worker 	semanage_list_destroy(&user_context_tpl);
1367*2d543d20SAndroid Build Coastguard Worker 	semanage_list_destroy(&homedir_context_tpl);
1368*2d543d20SAndroid Build Coastguard Worker 	semanage_list_destroy(&homeroot_context_tpl);
1369*2d543d20SAndroid Build Coastguard Worker 
1370*2d543d20SAndroid Build Coastguard Worker 	return retval;
1371*2d543d20SAndroid Build Coastguard Worker }
1372*2d543d20SAndroid Build Coastguard Worker 
semanage_genhomedircon(semanage_handle_t * sh,sepol_policydb_t * policydb,int usepasswd,char * ignoredirs)1373*2d543d20SAndroid Build Coastguard Worker int semanage_genhomedircon(semanage_handle_t * sh,
1374*2d543d20SAndroid Build Coastguard Worker 			   sepol_policydb_t * policydb,
1375*2d543d20SAndroid Build Coastguard Worker 			   int usepasswd,
1376*2d543d20SAndroid Build Coastguard Worker 			   char *ignoredirs)
1377*2d543d20SAndroid Build Coastguard Worker {
1378*2d543d20SAndroid Build Coastguard Worker 	genhomedircon_settings_t s;
1379*2d543d20SAndroid Build Coastguard Worker 	FILE *out = NULL;
1380*2d543d20SAndroid Build Coastguard Worker 	int retval = 0;
1381*2d543d20SAndroid Build Coastguard Worker 
1382*2d543d20SAndroid Build Coastguard Worker 	assert(sh);
1383*2d543d20SAndroid Build Coastguard Worker 
1384*2d543d20SAndroid Build Coastguard Worker 	s.homedir_template_path =
1385*2d543d20SAndroid Build Coastguard Worker 	    semanage_path(SEMANAGE_TMP, SEMANAGE_HOMEDIR_TMPL);
1386*2d543d20SAndroid Build Coastguard Worker 	s.fcfilepath =
1387*2d543d20SAndroid Build Coastguard Worker 		semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_HOMEDIRS);
1388*2d543d20SAndroid Build Coastguard Worker 
1389*2d543d20SAndroid Build Coastguard Worker 	s.fallback = calloc(1, sizeof(genhomedircon_user_entry_t));
1390*2d543d20SAndroid Build Coastguard Worker 	if (s.fallback == NULL) {
1391*2d543d20SAndroid Build Coastguard Worker 		retval = STATUS_ERR;
1392*2d543d20SAndroid Build Coastguard Worker 		goto done;
1393*2d543d20SAndroid Build Coastguard Worker 	}
1394*2d543d20SAndroid Build Coastguard Worker 
1395*2d543d20SAndroid Build Coastguard Worker 	s.fallback->name = strdup(FALLBACK_NAME);
1396*2d543d20SAndroid Build Coastguard Worker 	s.fallback->sename = strdup(FALLBACK_SENAME);
1397*2d543d20SAndroid Build Coastguard Worker 	s.fallback->prefix = strdup(FALLBACK_PREFIX);
1398*2d543d20SAndroid Build Coastguard Worker 	s.fallback->level = strdup(FALLBACK_LEVEL);
1399*2d543d20SAndroid Build Coastguard Worker 	if (s.fallback->name == NULL
1400*2d543d20SAndroid Build Coastguard Worker 	 || s.fallback->sename == NULL
1401*2d543d20SAndroid Build Coastguard Worker 	 || s.fallback->prefix == NULL
1402*2d543d20SAndroid Build Coastguard Worker 	 || s.fallback->level == NULL) {
1403*2d543d20SAndroid Build Coastguard Worker 		retval = STATUS_ERR;
1404*2d543d20SAndroid Build Coastguard Worker 		goto done;
1405*2d543d20SAndroid Build Coastguard Worker 	}
1406*2d543d20SAndroid Build Coastguard Worker 
1407*2d543d20SAndroid Build Coastguard Worker 	if (ignoredirs) ignore_setup(ignoredirs);
1408*2d543d20SAndroid Build Coastguard Worker 
1409*2d543d20SAndroid Build Coastguard Worker 	s.usepasswd = usepasswd;
1410*2d543d20SAndroid Build Coastguard Worker 	s.h_semanage = sh;
1411*2d543d20SAndroid Build Coastguard Worker 	s.policydb = policydb;
1412*2d543d20SAndroid Build Coastguard Worker 
1413*2d543d20SAndroid Build Coastguard Worker 	if (!(out = fopen(s.fcfilepath, "w"))) {
1414*2d543d20SAndroid Build Coastguard Worker 		/* couldn't open output file */
1415*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Could not open the file_context file for writing");
1416*2d543d20SAndroid Build Coastguard Worker 		retval = STATUS_ERR;
1417*2d543d20SAndroid Build Coastguard Worker 		goto done;
1418*2d543d20SAndroid Build Coastguard Worker 	}
1419*2d543d20SAndroid Build Coastguard Worker 
1420*2d543d20SAndroid Build Coastguard Worker 	retval = write_context_file(&s, out);
1421*2d543d20SAndroid Build Coastguard Worker 
1422*2d543d20SAndroid Build Coastguard Worker done:
1423*2d543d20SAndroid Build Coastguard Worker 	if (out != NULL)
1424*2d543d20SAndroid Build Coastguard Worker 		fclose(out);
1425*2d543d20SAndroid Build Coastguard Worker 
1426*2d543d20SAndroid Build Coastguard Worker 	while (s.fallback)
1427*2d543d20SAndroid Build Coastguard Worker 		pop_user_entry(&(s.fallback));
1428*2d543d20SAndroid Build Coastguard Worker 
1429*2d543d20SAndroid Build Coastguard Worker 	ignore_free();
1430*2d543d20SAndroid Build Coastguard Worker 
1431*2d543d20SAndroid Build Coastguard Worker 	return retval;
1432*2d543d20SAndroid Build Coastguard Worker }
1433