1 /*
2 * Copyright (C) 2015 Red Hat, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <config.h>
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <c-strcase.h>
26 #include <c-ctype.h>
27
28 #include <sec-mod-sup-config.h>
29 #include <common.h>
30 #include <vpn.h>
31 #include "common-config.h"
32
free_expanded_brackets_string(subcfg_val_st out[MAX_SUBOPTIONS],unsigned size)33 static void free_expanded_brackets_string(subcfg_val_st out[MAX_SUBOPTIONS], unsigned size)
34 {
35 unsigned i;
36 for (i=0;i<size;i++) {
37 talloc_free(out[i].name);
38 talloc_free(out[i].value);
39 }
40 }
41
42 /* Returns the number of suboptions processed.
43 */
44 static
expand_brackets_string(void * pool,const char * str,subcfg_val_st out[MAX_SUBOPTIONS])45 unsigned expand_brackets_string(void *pool, const char *str, subcfg_val_st out[MAX_SUBOPTIONS])
46 {
47 char *p, *p2, *p3;
48 unsigned len, len2;
49 unsigned pos = 0, finish = 0;
50
51 if (str == NULL)
52 return 0;
53
54 p = strchr(str, '[');
55 if (p == NULL) {
56 return 0;
57 }
58 p++;
59 while (c_isspace(*p))
60 p++;
61
62 do {
63 p2 = strchr(p, '=');
64 if (p2 == NULL) {
65 fprintf(stderr, "error parsing %s\n", str);
66 exit(1);
67 }
68 len = p2 - p;
69
70 p2++;
71 while (c_isspace(*p2))
72 p2++;
73
74 p3 = strchr(p2, ',');
75 if (p3 == NULL) {
76 p3 = strchr(p2, ']');
77 if (p3 == NULL) {
78 fprintf(stderr, "error parsing %s\n", str);
79 exit(1);
80 }
81 finish = 1;
82 }
83 len2 = p3 - p2;
84
85 if (len > 0) {
86 while (c_isspace(p[len-1]))
87 len--;
88 }
89 if (len2 > 0) {
90 while (c_isspace(p2[len2-1]))
91 len2--;
92 }
93
94 out[pos].name = talloc_strndup(pool, p, len);
95 out[pos].value = talloc_strndup(pool, p2, len2);
96 pos++;
97 p = p2+len2;
98 while (c_isspace(*p)||*p==',')
99 p++;
100 } while(finish == 0 && pos < MAX_SUBOPTIONS);
101
102 return pos;
103 }
104
105 #ifdef HAVE_GSSAPI
gssapi_get_brackets_string(void * pool,struct perm_cfg_st * config,const char * str)106 void *gssapi_get_brackets_string(void *pool, struct perm_cfg_st *config, const char *str)
107 {
108 subcfg_val_st vals[MAX_SUBOPTIONS];
109 unsigned vals_size, i;
110 gssapi_cfg_st *additional;
111
112 additional = talloc_zero(pool, gssapi_cfg_st);
113 if (additional == NULL) {
114 return NULL;
115 }
116
117 vals_size = expand_brackets_string(pool, str, vals);
118 for (i=0;i<vals_size;i++) {
119 if (c_strcasecmp(vals[i].name, "keytab") == 0) {
120 additional->keytab = vals[i].value;
121 vals[i].value = NULL;
122 } else if (c_strcasecmp(vals[i].name, "require-local-user-map") == 0) {
123 additional->no_local_map = 1-CHECK_TRUE(vals[i].value);
124 } else if (c_strcasecmp(vals[i].name, "tgt-freshness-time") == 0) {
125 additional->ticket_freshness_secs = atoi(vals[i].value);
126 if (additional->ticket_freshness_secs == 0) {
127 fprintf(stderr, "Invalid value for '%s': %s\n", vals[i].name, vals[i].value);
128 exit(1);
129 }
130 } else if (c_strcasecmp(vals[i].name, "gid-min") == 0) {
131 additional->gid_min = atoi(vals[i].value);
132 if (additional->gid_min < 0) {
133 fprintf(stderr, "error in gid-min value: %d\n", additional->gid_min);
134 exit(1);
135 }
136 } else {
137 fprintf(stderr, "unknown option '%s'\n", vals[i].name);
138 exit(1);
139 }
140 }
141 free_expanded_brackets_string(vals, vals_size);
142 return additional;
143 }
144 #endif
145
get_brackets_string1(void * pool,const char * str)146 void *get_brackets_string1(void *pool, const char *str)
147 {
148 char *p, *p2;
149 unsigned len;
150
151 p = strchr(str, '[');
152 if (p == NULL) {
153 return NULL;
154 }
155 p++;
156 while (c_isspace(*p))
157 p++;
158
159 p2 = strchr(p, ',');
160 if (p2 == NULL) {
161 p2 = strchr(p, ']');
162 if (p2 == NULL) {
163 fprintf(stderr, "error parsing %s\n", str);
164 exit(1);
165 }
166 }
167
168 len = p2 - p;
169
170 return talloc_strndup(pool, p, len);
171 }
172
173 #ifdef HAVE_RADIUS
get_brackets_string2(void * pool,const char * str)174 static void *get_brackets_string2(void *pool, const char *str)
175 {
176 char *p, *p2;
177 unsigned len;
178
179 p = strchr(str, '[');
180 if (p == NULL) {
181 return NULL;
182 }
183 p++;
184
185 p = strchr(p, ',');
186 if (p == NULL) {
187 return NULL;
188 }
189 p++;
190
191 while (c_isspace(*p))
192 p++;
193
194 p2 = strchr(p, ',');
195 if (p2 == NULL) {
196 p2 = strchr(p, ']');
197 if (p2 == NULL) {
198 fprintf(stderr, "error parsing %s\n", str);
199 exit(1);
200 }
201 }
202
203 len = p2 - p;
204
205 return talloc_strndup(pool, p, len);
206 }
207
radius_get_brackets_string(void * pool,struct perm_cfg_st * config,const char * str)208 void *radius_get_brackets_string(void *pool, struct perm_cfg_st *config, const char *str)
209 {
210 char *p;
211 subcfg_val_st vals[MAX_SUBOPTIONS];
212 unsigned vals_size, i;
213 radius_cfg_st *additional;
214
215 additional = talloc_zero(pool, radius_cfg_st);
216 if (additional == NULL) {
217 return NULL;
218 }
219
220 if (str && str[0] == '[' && (str[1] == '/' || str[1] == '.')) { /* legacy format */
221 fprintf(stderr, "Parsing radius auth method subconfig using legacy format\n");
222
223 additional->config = get_brackets_string1(pool, str);
224
225 p = get_brackets_string2(config, str);
226 if (p != NULL) {
227 if (strcasecmp(p, "groupconfig") != 0) {
228 fprintf(stderr, "No known configuration option: %s\n", p);
229 exit(1);
230 }
231 config->sup_config_type = SUP_CONFIG_RADIUS;
232 }
233 } else {
234 /* new format */
235 vals_size = expand_brackets_string(pool, str, vals);
236 for (i=0;i<vals_size;i++) {
237 if (c_strcasecmp(vals[i].name, "config") == 0) {
238 additional->config = vals[i].value;
239 vals[i].value = NULL;
240 } else if (c_strcasecmp(vals[i].name, "nas-identifier") == 0) {
241 additional->nas_identifier = vals[i].value;
242 vals[i].value = NULL;
243 } else if (c_strcasecmp(vals[i].name, "groupconfig") == 0) {
244 if (CHECK_TRUE(vals[i].value))
245 config->sup_config_type = SUP_CONFIG_RADIUS;
246 } else {
247 fprintf(stderr, "unknown option '%s'\n", vals[i].name);
248 exit(1);
249 }
250 }
251 free_expanded_brackets_string(vals, vals_size);
252 }
253
254 if (additional->config == NULL) {
255 fprintf(stderr, "No radius configuration specified: %s\n", str);
256 exit(1);
257 }
258
259 return additional;
260 }
261 #endif
262
263 #ifdef HAVE_PAM
pam_get_brackets_string(void * pool,struct perm_cfg_st * config,const char * str)264 void *pam_get_brackets_string(void *pool, struct perm_cfg_st *config, const char *str)
265 {
266 subcfg_val_st vals[MAX_SUBOPTIONS];
267 unsigned vals_size, i;
268 pam_cfg_st *additional;
269
270 additional = talloc_zero(pool, pam_cfg_st);
271 if (additional == NULL) {
272 return NULL;
273 }
274
275 /* new format */
276 vals_size = expand_brackets_string(pool, str, vals);
277 for (i=0;i<vals_size;i++) {
278 if (c_strcasecmp(vals[i].name, "gid-min") == 0) {
279 additional->gid_min = atoi(vals[i].value);
280 if (additional->gid_min < 0) {
281 fprintf(stderr, "error in gid-min value: %d\n", additional->gid_min);
282 exit(1);
283 }
284 } else {
285 fprintf(stderr, "unknown option '%s'\n", vals[i].name);
286 exit(1);
287 }
288 }
289
290 free_expanded_brackets_string(vals, vals_size);
291 return additional;
292 }
293 #endif
294
plain_get_brackets_string(void * pool,struct perm_cfg_st * config,const char * str)295 void *plain_get_brackets_string(void *pool, struct perm_cfg_st *config, const char *str)
296 {
297 subcfg_val_st vals[MAX_SUBOPTIONS];
298 unsigned vals_size, i;
299 plain_cfg_st *additional;
300
301 additional = talloc_zero(pool, plain_cfg_st);
302 if (additional == NULL) {
303 return NULL;
304 }
305
306 if (str && str[0] == '[' && (str[1] == '/' || str[1] == '.')) { /* legacy format */
307 fprintf(stderr, "Parsing plain auth method subconfig using legacy format\n");
308 additional->passwd = get_brackets_string1(pool, str);
309 } else {
310 vals_size = expand_brackets_string(pool, str, vals);
311 for (i=0;i<vals_size;i++) {
312 if (c_strcasecmp(vals[i].name, "passwd") == 0) {
313 additional->passwd = vals[i].value;
314 vals[i].value = NULL;
315 #ifdef HAVE_LIBOATH
316 } else if (c_strcasecmp(vals[i].name, "otp") == 0) {
317 additional->otp_file = vals[i].value;
318 vals[i].value = NULL;
319 #endif
320 } else {
321 fprintf(stderr, "unknown option '%s'\n", vals[i].name);
322 exit(1);
323 }
324 }
325 free_expanded_brackets_string(vals, vals_size);
326 }
327
328 if (additional->passwd == NULL && additional->otp_file == NULL) {
329 fprintf(stderr, "plain: no password or OTP file specified\n");
330 exit(1);
331 }
332
333 return additional;
334 }
335
336
oidc_get_brackets_string(void * pool,struct perm_cfg_st * config,const char * str)337 void *oidc_get_brackets_string(void * pool, struct perm_cfg_st *config, const char *str)
338 {
339 subcfg_val_st vals[MAX_SUBOPTIONS];
340 char * additional = NULL;
341
342 unsigned vals_size, i;
343
344 vals_size = expand_brackets_string(pool, str, vals);
345
346 for (i = 0; i < vals_size; i ++) {
347 if (c_strcasecmp(vals[i].name, "config") == 0) {
348 additional = talloc_strdup(pool, vals[i].value);
349 }
350 }
351
352 return additional;
353 }
354