1 /* Copyright (C) 2005 Red Hat, Inc. */
2 
3 struct semanage_user_base;
4 struct semanage_user_key;
5 typedef struct semanage_user_base record_t;
6 typedef struct semanage_user_key record_key_t;
7 #define DBASE_RECORD_DEFINED
8 
9 struct dbase_file;
10 typedef struct dbase_file dbase_t;
11 #define DBASE_DEFINED
12 
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <ctype.h>
16 #include <string.h>
17 #include <semanage/handle.h>
18 #include "user_internal.h"
19 #include "database_file.h"
20 #include "parse_utils.h"
21 #include "debug.h"
22 
user_base_print(semanage_handle_t * handle,semanage_user_base_t * user,FILE * str)23 static int user_base_print(semanage_handle_t * handle,
24 			   semanage_user_base_t * user, FILE * str)
25 {
26 
27 	const char **roles = NULL;
28 	unsigned int i, nroles;
29 
30 	const char *name = semanage_user_base_get_name(user);
31 	const char *mls_level = semanage_user_base_get_mlslevel(user);
32 	const char *mls_range = semanage_user_base_get_mlsrange(user);
33 
34 	if (fprintf(str, "user %s roles { ", name) < 0)
35 		goto err;
36 
37 	if (semanage_user_base_get_roles(handle, user, &roles, &nroles) < 0)
38 		goto err;
39 
40 	for (i = 0; i < nroles; i++) {
41 		if (fprintf(str, "%s ", roles[i]) < 0)
42 			goto err;
43 	}
44 
45 	if (fprintf(str, "} ") < 0)
46 		goto err;
47 
48 	/* MLS */
49 	if (mls_level != NULL && mls_range != NULL)
50 		if (fprintf(str, "level %s range %s", mls_level, mls_range) < 0)
51 			goto err;
52 
53 	if (fprintf(str, ";\n") < 0)
54 		goto err;
55 
56 	free(roles);
57 	return STATUS_SUCCESS;
58 
59       err:
60 	free(roles);
61 	ERR(handle, "could not print user %s to stream", name);
62 	return STATUS_ERR;
63 }
64 
user_base_parse(semanage_handle_t * handle,parse_info_t * info,semanage_user_base_t * user)65 static int user_base_parse(semanage_handle_t * handle,
66 			   parse_info_t * info, semanage_user_base_t * user)
67 {
68 
69 	int islist = 0;
70 	char *str = NULL;
71 	char *start;
72 	char *name_str = NULL;
73 
74 	if (parse_skip_space(handle, info) < 0)
75 		goto err;
76 	if (!info->ptr)
77 		goto last;
78 
79 	/* Parse user header */
80 	if (parse_assert_str(handle, info, "user") < 0)
81 		goto err;
82 	if (parse_assert_space(handle, info) < 0)
83 		goto err;
84 
85 	/* Parse user name */
86 	if (parse_fetch_string(handle, info, &name_str, ' ') < 0)
87 		goto err;
88 
89 	if (semanage_user_base_set_name(handle, user, name_str) < 0) {
90 		free(name_str);
91 		goto err;
92 	}
93 	free(name_str);
94 
95 	if (parse_assert_space(handle, info) < 0)
96 		goto err;
97 	if (parse_assert_str(handle, info, "roles") < 0)
98 		goto err;
99 	if (parse_assert_space(handle, info) < 0)
100 		goto err;
101 
102 	islist = (parse_optional_ch(info, '{') != STATUS_NODATA);
103 
104 	/* For each role, loop */
105 	do {
106 		char delim;
107 
108 		if (parse_skip_space(handle, info) < 0)
109 			goto err;
110 		if (parse_assert_noeof(handle, info) < 0)
111 			goto err;
112 
113 		start = info->ptr;
114 		while (*(info->ptr) &&
115 		       *(info->ptr) != ';' &&
116 		       *(info->ptr) != '}' && !isspace(*(info->ptr)))
117 			info->ptr++;
118 
119 		delim = *(info->ptr);
120 		*(info->ptr)++ = '\0';
121 
122 		if (semanage_user_base_add_role(handle, user, start) < 0)
123 			goto err;
124 
125 		if (delim && !isspace(delim)) {
126 			if (islist && delim == '}')
127 				break;
128 			else if (!islist && delim == ';')
129 				goto skip_semicolon;
130 			else
131 				goto err;
132 		}
133 
134 		if (parse_skip_space(handle, info) < 0)
135 			goto err;
136 		if (parse_optional_ch(info, ';') != STATUS_NODATA)
137 			goto skip_semicolon;
138 		if (parse_optional_ch(info, '}') != STATUS_NODATA)
139 			islist = 0;
140 
141 	} while (islist);
142 
143 	/* Handle mls */
144 	/* Parse level header */
145 	if (parse_skip_space(handle, info) < 0)
146 		goto err;
147 	if (parse_optional_str(info, "level") == STATUS_NODATA)
148 		goto semicolon;
149 	if (parse_assert_space(handle, info) < 0)
150 		goto err;
151 
152 	/* NOTE: does not allow spaces/multiline */
153 	if (parse_fetch_string(handle, info, &str, ' ') < 0)
154 		goto err;
155 	if (semanage_user_base_set_mlslevel(handle, user, str) < 0)
156 		goto err;
157 	free(str);
158 	str = NULL;
159 
160 	/* Parse range header */
161 	if (parse_assert_space(handle, info) < 0)
162 		goto err;
163 	if (parse_assert_str(handle, info, "range") < 0)
164 		goto err;
165 	if (parse_assert_space(handle, info) < 0)
166 		goto err;
167 
168 	/* NOTE: does not allow spaces/multiline */
169 	if (parse_fetch_string(handle, info, &str, ';') < 0)
170 		goto err;
171 	if (semanage_user_base_set_mlsrange(handle, user, str) < 0)
172 		goto err;
173 
174 	free(str);
175 	str = NULL;
176 
177 	/* Check for semicolon */
178       semicolon:
179 	if (parse_skip_space(handle, info) < 0)
180 		goto err;
181 	if (parse_assert_ch(handle, info, ';') < 0)
182 		goto err;
183 
184       skip_semicolon:
185 	return STATUS_SUCCESS;
186 
187       last:
188 	parse_dispose_line(info);
189 	return STATUS_NODATA;
190 
191       err:
192 	ERR(handle, "could not parse user record");
193 	free(str);
194 	parse_dispose_line(info);
195 	return STATUS_ERR;
196 }
197 
198 /* USER BASE record: FILE extension: method table */
199 record_file_table_t SEMANAGE_USER_BASE_FILE_RTABLE = {
200 	.parse = user_base_parse,
201 	.print = user_base_print,
202 };
203 
user_base_file_dbase_init(semanage_handle_t * handle,const char * path_ro,const char * path_rw,dbase_config_t * dconfig)204 int user_base_file_dbase_init(semanage_handle_t * handle,
205 			      const char *path_ro,
206 			      const char *path_rw,
207 			      dbase_config_t * dconfig)
208 {
209 
210 	if (dbase_file_init(handle,
211 			    path_ro,
212 			    path_rw,
213 			    &SEMANAGE_USER_BASE_RTABLE,
214 			    &SEMANAGE_USER_BASE_FILE_RTABLE,
215 			    &dconfig->dbase) < 0)
216 		return STATUS_ERR;
217 
218 	dconfig->dtable = &SEMANAGE_FILE_DTABLE;
219 	return STATUS_SUCCESS;
220 }
221 
user_base_file_dbase_release(dbase_config_t * dconfig)222 void user_base_file_dbase_release(dbase_config_t * dconfig)
223 {
224 
225 	dbase_file_release(dconfig->dbase);
226 }
227