Branch data Line data Source code
1 : : /*
2 : : SSSD
3 : :
4 : : User tools
5 : :
6 : : Copyright (C) Stephen Gallagher <sgallagh@redhat.com> 2009
7 : :
8 : : This program is free software; you can redistribute it and/or modify
9 : : it under the terms of the GNU General Public License as published by
10 : : the Free Software Foundation; either version 3 of the License, or
11 : : (at your option) any later version.
12 : :
13 : : This program is distributed in the hope that it will be useful,
14 : : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : : GNU General Public License for more details.
17 : :
18 : : You should have received a copy of the GNU General Public License
19 : : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : : */
21 : :
22 : : #include <pwd.h>
23 : : #include <pcre.h>
24 : : #include <errno.h>
25 : : #include <talloc.h>
26 : :
27 : : #include "confdb/confdb.h"
28 : : #include "util/util.h"
29 : :
30 : : #ifdef HAVE_LIBPCRE_LESSER_THAN_7
31 : : #define NAME_DOMAIN_PATTERN_OPTIONS (PCRE_EXTENDED)
32 : : #else
33 : : #define NAME_DOMAIN_PATTERN_OPTIONS (PCRE_DUPNAMES | PCRE_EXTENDED)
34 : : #endif
35 : :
36 : 0 : char *get_username_from_uid(TALLOC_CTX *mem_ctx, uid_t uid)
37 : : {
38 : : char *username;
39 : : struct passwd *pwd;
40 : :
41 : 0 : pwd = getpwuid(uid);
42 [ # # ]: 0 : if (!pwd) return NULL;
43 : :
44 : 0 : username = talloc_strdup(mem_ctx, pwd->pw_name);
45 : 0 : return username;
46 : : }
47 : :
48 : : /* Function returns given realm name as new uppercase string */
49 : 0 : char *get_uppercase_realm(TALLOC_CTX *memctx, const char *name)
50 : : {
51 : : char *realm;
52 : : char *c;
53 : :
54 : 0 : realm = talloc_strdup(memctx, name);
55 [ # # ]: 0 : if (!realm) {
56 : : return NULL;
57 : : }
58 : :
59 : : c = realm;
60 [ # # ]: 0 : while(*c != '\0') {
61 : 0 : *c = toupper(*c);
62 : 0 : c++;
63 : : }
64 : :
65 : : return realm;
66 : : }
67 : :
68 : :
69 : 0 : static int sss_names_ctx_destructor(struct sss_names_ctx *snctx)
70 : : {
71 [ # # ]: 0 : if (snctx->re) {
72 : 0 : pcre_free(snctx->re);
73 : 0 : snctx->re = NULL;
74 : : }
75 : 0 : return 0;
76 : : }
77 : :
78 : : #define IPA_AD_DEFAULT_RE "(((?P<domain>[^\\\\]+)\\\\(?P<name>.+$))|" \
79 : : "((?P<name>[^@]+)@(?P<domain>.+$))|" \
80 : : "(^(?P<name>[^@\\\\]+)$))"
81 : :
82 : 0 : static errno_t get_id_provider_default_re(TALLOC_CTX *mem_ctx,
83 : : struct confdb_ctx *cdb,
84 : : const char *conf_path,
85 : : char **re_pattern)
86 : : {
87 : : #ifdef HAVE_LIBPCRE_LESSER_THAN_7
88 : : DEBUG(SSSDBG_MINOR_FAILURE,
89 : : ("The libpcre version on this system is too old. Only "
90 : : "the user@DOMAIN name fully qualified name format will "
91 : : "be supported\n"));
92 : : *re_pattern = NULL;
93 : : return EOK;
94 : : #else
95 : : int ret;
96 : : size_t c;
97 : 0 : char *id_provider = NULL;
98 : :
99 : : struct provider_default_re {
100 : : const char *name;
101 : : const char *re;
102 : 0 : } provider_default_re[] = {{"ipa", IPA_AD_DEFAULT_RE},
103 : : {"ad", IPA_AD_DEFAULT_RE},
104 : : {NULL, NULL}};
105 : :
106 : 0 : ret = confdb_get_string(cdb, mem_ctx, conf_path, CONFDB_DOMAIN_ID_PROVIDER,
107 : : NULL, &id_provider);
108 [ # # ]: 0 : if (ret != EOK) {
109 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("Failed to read ID provider " \
[ # # ][ # # ]
[ # # ]
110 : : "from conf db.\n"));
111 : : goto done;
112 : : }
113 : :
114 [ # # ]: 0 : if (id_provider == NULL) {
115 : 0 : *re_pattern = NULL;
116 : : } else {
117 [ # # ]: 0 : for (c = 0; provider_default_re[c].name != NULL; c++) {
118 [ # # ]: 0 : if (strcmp(id_provider, provider_default_re[c].name) == 0) {
119 : 0 : *re_pattern = talloc_strdup(mem_ctx, provider_default_re[c].re);
120 [ # # ]: 0 : if (*re_pattern == NULL) {
121 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
[ # # ][ # # ]
[ # # ]
122 : : ret = ENOMEM;
123 : : goto done;
124 : : }
125 : : break;
126 : : }
127 : : }
128 : : }
129 : :
130 : : ret = EOK;
131 : :
132 : : done:
133 : 0 : talloc_free(id_provider);
134 : 0 : return ret;
135 : : #endif
136 : : }
137 : :
138 : 0 : int sss_names_init(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb,
139 : : const char *domain, struct sss_names_ctx **out)
140 : : {
141 : : struct sss_names_ctx *ctx;
142 : 0 : TALLOC_CTX *tmpctx = NULL;
143 : : const char *errstr;
144 : : char *conf_path;
145 : : int errval;
146 : : int errpos;
147 : : int ret;
148 : :
149 : 0 : ctx = talloc_zero(mem_ctx, struct sss_names_ctx);
150 [ # # ]: 0 : if (!ctx) return ENOMEM;
151 : 0 : talloc_set_destructor(ctx, sss_names_ctx_destructor);
152 : :
153 : 0 : tmpctx = talloc_new(NULL);
154 [ # # ]: 0 : if (tmpctx == NULL) {
155 : : ret = ENOMEM;
156 : : goto done;
157 : : }
158 : :
159 : 0 : conf_path = talloc_asprintf(tmpctx, CONFDB_DOMAIN_PATH_TMPL, domain);
160 [ # # ]: 0 : if (conf_path == NULL) {
161 : : ret = ENOMEM;
162 : : goto done;
163 : : }
164 : :
165 : 0 : ret = confdb_get_string(cdb, ctx, conf_path,
166 : : CONFDB_NAME_REGEX, NULL, &ctx->re_pattern);
167 [ # # ]: 0 : if (ret != EOK) goto done;
168 : :
169 : : /* If not found in the domain, look in globals */
170 [ # # ]: 0 : if (ctx->re_pattern == NULL) {
171 : 0 : ret = confdb_get_string(cdb, ctx, CONFDB_MONITOR_CONF_ENTRY,
172 : : CONFDB_NAME_REGEX, NULL, &ctx->re_pattern);
173 [ # # ]: 0 : if (ret != EOK) goto done;
174 : : }
175 : :
176 [ # # ]: 0 : if (ctx->re_pattern == NULL) {
177 : 0 : ret = get_id_provider_default_re(ctx, cdb, conf_path, &ctx->re_pattern);
178 [ # # ]: 0 : if (ret != EOK) {
179 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("Failed to get provider default regular " \
[ # # ][ # # ]
[ # # ]
180 : : "expression for domain [%s].\n", domain));
181 : : goto done;
182 : : }
183 : : }
184 : :
185 [ # # ]: 0 : if (!ctx->re_pattern) {
186 : 0 : ctx->re_pattern = talloc_strdup(ctx,
187 : : "(?P<name>[^@]+)@?(?P<domain>[^@]*$)");
188 [ # # ]: 0 : if (!ctx->re_pattern) {
189 : : ret = ENOMEM;
190 : : goto done;
191 : : }
192 : : #ifdef HAVE_LIBPCRE_LESSER_THAN_7
193 : : } else {
194 : : DEBUG(2, ("This binary was build with a version of libpcre that does "
195 : : "not support non-unique named subpatterns.\n"));
196 : : DEBUG(2, ("Please make sure that your pattern [%s] only contains "
197 : : "subpatterns with a unique name and uses "
198 : : "the Python syntax (?P<name>).\n", ctx->re_pattern));
199 : : #endif
200 : : }
201 : :
202 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CONF_SETTINGS, ("Using re [%s].\n", ctx->re_pattern));
[ # # ][ # # ]
[ # # ]
203 : :
204 : 0 : ret = confdb_get_string(cdb, ctx, conf_path,
205 : : CONFDB_FULL_NAME_FORMAT, NULL, &ctx->fq_fmt);
206 [ # # ]: 0 : if (ret != EOK) goto done;
207 : :
208 : : /* If not found in the domain, look in globals */
209 [ # # ]: 0 : if (ctx->fq_fmt == NULL) {
210 : 0 : ret = confdb_get_string(cdb, ctx, CONFDB_MONITOR_CONF_ENTRY,
211 : : CONFDB_FULL_NAME_FORMAT, NULL, &ctx->fq_fmt);
212 [ # # ]: 0 : if (ret != EOK) goto done;
213 : : }
214 : :
215 [ # # ]: 0 : if (!ctx->fq_fmt) {
216 : 0 : ctx->fq_fmt = talloc_strdup(ctx, "%1$s@%2$s");
217 [ # # ]: 0 : if (!ctx->fq_fmt) {
218 : : ret = ENOMEM;
219 : : goto done;
220 : : }
221 : : }
222 : :
223 : 0 : ctx->re = pcre_compile2(ctx->re_pattern,
224 : : NAME_DOMAIN_PATTERN_OPTIONS,
225 : : &errval, &errstr, &errpos, NULL);
226 [ # # ]: 0 : if (!ctx->re) {
227 [ # # ][ # # ]: 0 : DEBUG(1, ("Invalid Regular Expression pattern at position %d."
[ # # ][ # # ]
[ # # ]
228 : : " (Error: %d [%s])\n", errpos, errval, errstr));
229 : : ret = EFAULT;
230 : : goto done;
231 : : }
232 : :
233 : 0 : *out = ctx;
234 : 0 : ret = EOK;
235 : :
236 : : done:
237 : 0 : talloc_free(tmpctx);
238 [ # # ]: 0 : if (ret != EOK) {
239 : 0 : talloc_free(ctx);
240 : : }
241 : : return ret;
242 : : }
243 : :
244 : 0 : int sss_parse_name(TALLOC_CTX *memctx,
245 : : struct sss_names_ctx *snctx,
246 : : const char *orig, char **domain, char **name)
247 : : {
248 : 0 : pcre *re = snctx->re;
249 : : const char *result;
250 : : int ovec[30];
251 : : int origlen;
252 : : int ret, strnum;
253 : :
254 : 0 : origlen = strlen(orig);
255 : :
256 : 0 : ret = pcre_exec(re, NULL, orig, origlen, 0, PCRE_NOTEMPTY, ovec, 30);
257 [ # # ]: 0 : if (ret == PCRE_ERROR_NOMATCH) {
258 : : return EINVAL;
259 [ # # ]: 0 : } else if (ret < 0) {
260 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_MINOR_FAILURE, ("PCRE Matching error, %d\n", ret));
[ # # ][ # # ]
[ # # ]
261 : : return EINVAL;
262 : : }
263 : :
264 [ # # ]: 0 : if (ret == 0) {
265 [ # # ][ # # ]: 0 : DEBUG(1, ("Too many matches, the pattern is invalid.\n"));
[ # # ][ # # ]
[ # # ]
266 : : }
267 : :
268 : 0 : strnum = ret;
269 : :
270 : 0 : result = NULL;
271 : 0 : ret = pcre_get_named_substring(re, orig, ovec, strnum, "name", &result);
272 [ # # ][ # # ]: 0 : if (ret < 0 || !result) {
273 [ # # ][ # # ]: 0 : DEBUG(2, ("Name not found!\n"));
[ # # ][ # # ]
[ # # ]
274 : : return EINVAL;
275 : : }
276 : 0 : *name = talloc_strdup(memctx, result);
277 : 0 : pcre_free_substring(result);
278 [ # # ]: 0 : if (!*name) return ENOMEM;
279 : :
280 : :
281 : 0 : result = NULL;
282 : 0 : ret = pcre_get_named_substring(re, orig, ovec, strnum, "domain", &result);
283 [ # # ][ # # ]: 0 : if (ret < 0 || !result) {
284 [ # # ][ # # ]: 0 : DEBUG(4, ("Domain not provided!\n"));
[ # # ][ # # ]
[ # # ]
285 : 0 : *domain = NULL;
286 : : } else {
287 : : /* ignore "" string */
288 [ # # ]: 0 : if (*result) {
289 : 0 : *domain = talloc_strdup(memctx, result);
290 : 0 : pcre_free_substring(result);
291 [ # # ]: 0 : if (!*domain) return ENOMEM;
292 : : } else {
293 : 0 : pcre_free_substring(result);
294 : 0 : *domain = NULL;
295 : : }
296 : : }
297 : :
298 : : return EOK;
299 : : }
300 : :
301 : 0 : static struct sss_domain_info * match_any_domain_or_subdomain_name (
302 : : struct sss_domain_info *dom, const char *dmatch)
303 : : {
304 : : uint32_t i;
305 : :
306 [ # # ][ # # ]: 0 : if (strcasecmp (dom->name, dmatch) == 0 ||
307 [ # # ]: 0 : (dom->flat_name != NULL && strcasecmp(dom->flat_name, dmatch) == 0))
308 : : return dom;
309 : :
310 [ # # ]: 0 : for (i = 0; i < dom->subdomain_count; i++) {
311 [ # # ][ # # ]: 0 : if (strcasecmp(dom->subdomains[i]->name, dmatch) == 0 ||
312 [ # # ]: 0 : (dom->subdomains[i]->flat_name != NULL &&
313 : 0 : strcasecmp(dom->subdomains[i]->flat_name, dmatch) == 0)) {
314 : : return dom->subdomains[i];
315 : : }
316 : : }
317 : :
318 : : return NULL;
319 : : }
320 : :
321 : 0 : int sss_parse_name_for_domains(TALLOC_CTX *memctx,
322 : : struct sss_domain_info *domains,
323 : : const char *default_domain,
324 : : const char *orig, char **domain, char **name)
325 : : {
326 : : struct sss_domain_info *dom, *match;
327 : : char *rdomain, *rname;
328 : : char *dmatch, *nmatch;
329 : 0 : char *candidate_name = NULL;
330 : 0 : char *candidate_domain = NULL;
331 : 0 : bool name_mismatch = false;
332 : : TALLOC_CTX *tmp_ctx;
333 : : int ret;
334 : :
335 : 0 : tmp_ctx = talloc_new(NULL);
336 [ # # ]: 0 : if (tmp_ctx == NULL)
337 : : return ENOMEM;
338 : :
339 : : rname = NULL;
340 : : rdomain = NULL;
341 : :
342 [ # # ]: 0 : for (dom = domains; dom != NULL; dom = dom->next) {
343 : 0 : ret = sss_parse_name(tmp_ctx, dom->names, orig, &dmatch, &nmatch);
344 [ # # ]: 0 : if (ret == EOK) {
345 : : /*
346 : : * If the name matched without the domain part, make note of it.
347 : : * All the other domain expressions must agree on the domain-less
348 : : * name.
349 : : */
350 [ # # ]: 0 : if (dmatch == NULL) {
351 [ # # ]: 0 : if (candidate_name == NULL) {
352 : 0 : candidate_name = nmatch;
353 [ # # ]: 0 : } else if (strcasecmp(candidate_name, nmatch) != 0) {
354 : 0 : name_mismatch = true;
355 : : }
356 : :
357 : : /*
358 : : * If a domain was returned, then it must match the name of the
359 : : * domain that this expression was found on, or one of the
360 : : * subdomains.
361 : : */
362 : : } else {
363 : 0 : match = match_any_domain_or_subdomain_name (dom, dmatch);
364 [ # # ]: 0 : if (match != NULL) {
365 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_FUNC_DATA, ("name '%s' matched expression for "
[ # # ][ # # ]
[ # # ]
366 : : "domain '%s', user is %s\n",
367 : : orig, match->name, nmatch));
368 : 0 : rdomain = talloc_strdup(tmp_ctx, match->name);
369 [ # # ]: 0 : if (rdomain == NULL) {
370 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
[ # # ][ # # ]
[ # # ]
371 : : ret = ENOMEM;
372 : : goto done;
373 : : }
374 : 0 : rname = nmatch;
375 : 0 : break;
376 [ # # ]: 0 : } else if (candidate_name == NULL) {
377 : 0 : candidate_domain = dmatch;
378 : : }
379 : : }
380 : :
381 : : /* EINVAL is returned when name doesn't match */
382 [ # # ]: 0 : } else if (ret != EINVAL) {
383 : : goto done;
384 : : }
385 : : }
386 : :
387 [ # # ]: 0 : if (rdomain == NULL && rname == NULL) {
388 [ # # ]: 0 : if (candidate_name && !name_mismatch) {
389 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_FUNC_DATA, ("name '%s' matched without domain, " \
[ # # ][ # # ]
[ # # ]
390 : : "user is %s\n", orig, nmatch));
391 : 0 : rdomain = NULL;
392 [ # # ]: 0 : if (default_domain != NULL) {
393 : 0 : rdomain = talloc_strdup(tmp_ctx, default_domain);
394 [ # # ]: 0 : if (default_domain == NULL) {
395 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
[ # # ][ # # ]
[ # # ]
396 : : ret = ENOMEM;
397 : : goto done;
398 : : }
399 : :
400 [ # # ]: 0 : for (dom = domains; dom != NULL; dom = dom->next) {
401 : 0 : match = match_any_domain_or_subdomain_name(dom, rdomain);
402 [ # # ]: 0 : if (match != NULL) {
403 : : break;
404 : : }
405 : : }
406 [ # # ]: 0 : if (match == NULL) {
407 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_FUNC_DATA, ("default domain [%s] is currently " \
[ # # ][ # # ]
[ # # ]
408 : : "not know, trying to look it up.\n",
409 : : rdomain));
410 : 0 : *domain = talloc_steal(memctx, rdomain);
411 : 0 : ret = EAGAIN;
412 : 0 : goto done;
413 : : }
414 : : }
415 : :
416 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_FUNC_DATA, ("using default domain [%s]\n", rdomain));
[ # # ][ # # ]
[ # # ]
417 : :
418 : 0 : rname = candidate_name;
419 [ # # ]: 0 : } else if (candidate_domain) {
420 : 0 : *domain = talloc_steal(memctx, candidate_domain);
421 : 0 : ret = EAGAIN;
422 : 0 : goto done;
423 : : }
424 : : }
425 : :
426 [ # # ]: 0 : if (rdomain == NULL && rname == NULL) {
427 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_TRACE_FUNC,
[ # # ][ # # ]
[ # # ]
428 : : ("name '%s' did not match any domain's expression\n", orig));
429 : : ret = EINVAL;
430 : : goto done;
431 : : }
432 : :
433 [ # # ]: 0 : if (domain != NULL) {
434 : 0 : *domain = talloc_steal(memctx, rdomain);
435 : : }
436 : :
437 [ # # ]: 0 : if (name != NULL) {
438 : 0 : *name = talloc_steal(memctx, rname);
439 : : }
440 : :
441 : : ret = EOK;
442 : : done:
443 : 0 : talloc_free(tmp_ctx);
444 : :
445 : : return ret;
446 : : }
447 : :
448 : : char *
449 : 8 : sss_get_cased_name(TALLOC_CTX *mem_ctx,
450 : : const char *orig_name,
451 : : bool case_sensitive)
452 : : {
453 [ + + ]: 8 : return case_sensitive ? talloc_strdup(mem_ctx, orig_name) :
454 : : sss_tc_utf8_str_tolower(mem_ctx, orig_name);
455 : : }
456 : :
457 : : errno_t
458 : 0 : sss_get_cased_name_list(TALLOC_CTX *mem_ctx, const char * const *orig,
459 : : bool case_sensitive, const char ***_cased)
460 : : {
461 : : const char **out;
462 : : size_t num, i;
463 : :
464 [ # # ]: 0 : if (orig == NULL) {
465 : 0 : *_cased = NULL;
466 : 0 : return EOK;
467 : : }
468 : :
469 [ # # ]: 0 : for (num=0; orig[num]; num++); /* count the num of strings */
470 : :
471 [ # # ]: 0 : if (num == 0) {
472 : 0 : *_cased = NULL;
473 : 0 : return EOK;
474 : : }
475 : :
476 : 0 : out = talloc_array(mem_ctx, const char *, num + 1);
477 [ # # ]: 0 : if (out == NULL) {
478 : : return ENOMEM;
479 : : }
480 : :
481 [ # # ]: 0 : for (i = 0; i < num; i++) {
482 : 0 : out[i] = sss_get_cased_name(out, orig[i], case_sensitive);
483 [ # # ]: 0 : if (out[i] == NULL) {
484 : 0 : talloc_free(out);
485 : 0 : return ENOMEM;
486 : : }
487 : : }
488 : :
489 : 0 : out[num] = NULL;
490 : 0 : *_cased = out;
491 : 0 : return EOK;
492 : : }
|