Line data Source code
1 : /*
2 : Authors:
3 : Simo Sorce <ssorce@redhat.com>
4 :
5 : Copyright (C) 2009 Red Hat
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "config.h"
22 : #include <ctype.h>
23 : #include <netdb.h>
24 : #include <poll.h>
25 : #include <sys/types.h>
26 : #include <sys/socket.h>
27 : #include <arpa/inet.h>
28 : #include <talloc.h>
29 : #include <dhash.h>
30 : #include <time.h>
31 :
32 : #include "util/util.h"
33 : #include "util/sss_utf8.h"
34 :
35 2597 : int split_on_separator(TALLOC_CTX *mem_ctx, const char *str,
36 : const char sep, bool trim, bool skip_empty,
37 : char ***_list, int *size)
38 : {
39 : int ret;
40 2597 : const char *substr_end = str;
41 2597 : const char *substr_begin = str;
42 2597 : const char *sep_pos = NULL;
43 : size_t substr_len;
44 2597 : char **list = NULL;
45 2597 : int num_strings = 0;
46 2597 : TALLOC_CTX *tmp_ctx = NULL;
47 :
48 2597 : if (str == NULL || *str == '\0' || _list == NULL) {
49 3 : return EINVAL;
50 : }
51 :
52 2594 : tmp_ctx = talloc_new(NULL);
53 2594 : if (tmp_ctx == NULL) {
54 0 : return ENOMEM;
55 : }
56 :
57 : do {
58 2836 : substr_len = 0;
59 :
60 : /* If this is not the first substring, then move from the separator. */
61 2836 : if (sep_pos != NULL) {
62 242 : substr_end = sep_pos + 1;
63 242 : substr_begin = sep_pos + 1;
64 : }
65 :
66 : /* Find end of the first substring */
67 27616 : while (*substr_end != sep && *substr_end != '\0') {
68 21944 : substr_end++;
69 21944 : substr_len++;
70 : }
71 :
72 2836 : sep_pos = substr_end;
73 :
74 2836 : if (trim) {
75 : /* Trim leading whitespace */
76 5757 : while (isspace(*substr_begin) && substr_begin < substr_end) {
77 191 : substr_begin++;
78 191 : substr_len--;
79 : }
80 :
81 : /* Trim trailing whitespace */
82 5580 : while (substr_end - 1 > substr_begin && isspace(*(substr_end-1))) {
83 14 : substr_end--;
84 14 : substr_len--;
85 : }
86 : }
87 :
88 : /* Copy the substring to the output list of strings */
89 2836 : if (skip_empty == false || substr_len > 0) {
90 2814 : list = talloc_realloc(tmp_ctx, list, char*, num_strings + 2);
91 2814 : if (list == NULL) {
92 0 : ret = ENOMEM;
93 0 : goto done;
94 : }
95 :
96 : /* empty string is stored for substr_len == 0 */
97 2814 : list[num_strings] = talloc_strndup(list, substr_begin, substr_len);
98 2814 : if (list[num_strings] == NULL) {
99 0 : ret = ENOMEM;
100 0 : goto done;
101 : }
102 2814 : num_strings++;
103 : }
104 :
105 2836 : } while (*sep_pos != '\0');
106 :
107 2594 : if (list == NULL) {
108 : /* No allocations were done, make space for the NULL */
109 4 : list = talloc(tmp_ctx, char *);
110 4 : if (list == NULL) {
111 0 : ret = ENOMEM;
112 0 : goto done;
113 : }
114 : }
115 2594 : list[num_strings] = NULL;
116 :
117 2594 : if (size) {
118 109 : *size = num_strings;
119 : }
120 :
121 2594 : *_list = talloc_steal(mem_ctx, list);
122 2594 : ret = EOK;
123 : done:
124 2594 : talloc_free(tmp_ctx);
125 2594 : return ret;
126 : }
127 :
128 0 : static void free_args(char **args)
129 : {
130 : int i;
131 :
132 0 : if (args) {
133 0 : for (i = 0; args[i]; i++) free(args[i]);
134 0 : free(args);
135 : }
136 0 : }
137 :
138 : /* parse a string into arguments.
139 : * arguments are separated by a space
140 : * '\' is an escape character and can be used only to escape
141 : * itself or the white space.
142 : */
143 14 : char **parse_args(const char *str)
144 : {
145 : const char *p;
146 : char **ret, **r;
147 : char *tmp;
148 : int num;
149 : int i;
150 : bool e, w;
151 :
152 14 : tmp = malloc(strlen(str) + 1);
153 14 : if (!tmp) return NULL;
154 :
155 14 : ret = NULL;
156 14 : num = 0;
157 14 : i = 0;
158 14 : e = false;
159 : /* skip leading whitespaces */
160 14 : w = true;
161 14 : p = str;
162 121 : while (*p) {
163 93 : if (*p == '\\') {
164 5 : w = false;
165 5 : if (e) {
166 : /* if we were already escaping, add a '\' literal */
167 0 : tmp[i] = '\\';
168 0 : i++;
169 0 : e = false;
170 : } else {
171 : /* otherwise just start escaping */
172 5 : e = true;
173 : }
174 88 : } else if (isspace(*p)) {
175 44 : if (e) {
176 : /* Add escaped whitespace literally */
177 4 : tmp[i] = *p;
178 4 : i++;
179 4 : e = false;
180 40 : } else if (w == false) {
181 : /* If previous character was non-whitespace, arg break */
182 18 : tmp[i] = '\0';
183 18 : i++;
184 18 : w = true;
185 : }
186 : /* previous char was whitespace as well, skip it */
187 : } else {
188 44 : w = false;
189 44 : if (e) {
190 : /* Prepend escaped chars with a literal \ */
191 1 : tmp[i] = '\\';
192 1 : i++;
193 1 : e = false;
194 : }
195 : /* Copy character from the source string */
196 44 : tmp[i] = *p;
197 44 : i++;
198 : }
199 :
200 93 : p++;
201 :
202 : /* check if this was the last char */
203 93 : if (*p == '\0') {
204 13 : if (e) {
205 0 : tmp[i] = '\\';
206 0 : i++;
207 0 : e = false;
208 : }
209 13 : tmp[i] = '\0';
210 13 : i++;
211 : }
212 :
213 : /* save token to result array */
214 93 : if (i > 1 && tmp[i-1] == '\0') {
215 24 : r = realloc(ret, (num + 2) * sizeof(char *));
216 24 : if (!r) goto fail;
217 24 : ret = r;
218 24 : ret[num+1] = NULL;
219 24 : ret[num] = strdup(tmp);
220 24 : if (!ret[num]) goto fail;
221 24 : num++;
222 24 : i = 0;
223 : }
224 : }
225 :
226 14 : free(tmp);
227 14 : return ret;
228 :
229 : fail:
230 0 : free(tmp);
231 0 : free_args(ret);
232 0 : return NULL;
233 : }
234 :
235 16 : const char **dup_string_list(TALLOC_CTX *memctx, const char **str_list)
236 : {
237 16 : int i = 0;
238 16 : int j = 0;
239 : const char **dup_list;
240 :
241 16 : if (!str_list) {
242 0 : return NULL;
243 : }
244 :
245 : /* Find the size of the list */
246 16 : while (str_list[i]) i++;
247 :
248 16 : dup_list = talloc_array(memctx, const char *, i+1);
249 16 : if (!dup_list) {
250 0 : return NULL;
251 : }
252 :
253 : /* Copy the elements */
254 256 : for (j = 0; j < i; j++) {
255 240 : dup_list[j] = talloc_strdup(dup_list, str_list[j]);
256 240 : if (!dup_list[j]) {
257 0 : talloc_free(dup_list);
258 0 : return NULL;
259 : }
260 : }
261 :
262 : /* NULL-terminate the list */
263 16 : dup_list[i] = NULL;
264 :
265 16 : return dup_list;
266 : }
267 :
268 : /* Take two string lists (terminated on a NULL char*)
269 : * and return up to three arrays of strings based on
270 : * shared ownership.
271 : *
272 : * Pass NULL to any return type you don't care about
273 : */
274 21 : errno_t diff_string_lists(TALLOC_CTX *memctx,
275 : char **_list1,
276 : char **_list2,
277 : char ***_list1_only,
278 : char ***_list2_only,
279 : char ***_both_lists)
280 : {
281 : int error;
282 : errno_t ret;
283 : int i;
284 21 : int i2 = 0;
285 21 : int i12 = 0;
286 : hash_table_t *table;
287 : hash_key_t key;
288 : hash_value_t value;
289 21 : char **list1 = NULL;
290 21 : char **list2 = NULL;
291 21 : char **list1_only = NULL;
292 21 : char **list2_only = NULL;
293 21 : char **both_lists = NULL;
294 : unsigned long count;
295 : hash_key_t *keys;
296 :
297 21 : TALLOC_CTX *tmp_ctx = talloc_new(memctx);
298 21 : if (!tmp_ctx) {
299 0 : return ENOMEM;
300 : }
301 :
302 21 : if (!_list1) {
303 3 : list1 = talloc_array(tmp_ctx, char *, 1);
304 3 : if (!list1) {
305 0 : talloc_free(tmp_ctx);
306 0 : return ENOMEM;
307 : }
308 3 : list1[0] = NULL;
309 : }
310 : else {
311 18 : list1 = _list1;
312 : }
313 :
314 21 : if (!_list2) {
315 4 : list2 = talloc_array(tmp_ctx, char *, 1);
316 4 : if (!list2) {
317 0 : talloc_free(tmp_ctx);
318 0 : return ENOMEM;
319 : }
320 4 : list2[0] = NULL;
321 : }
322 : else {
323 17 : list2 = _list2;
324 : }
325 :
326 21 : error = hash_create(10, &table, NULL, NULL);
327 21 : if (error != HASH_SUCCESS) {
328 0 : talloc_free(tmp_ctx);
329 0 : return EIO;
330 : }
331 :
332 21 : key.type = HASH_KEY_STRING;
333 21 : value.type = HASH_VALUE_UNDEF;
334 :
335 : /* Add all entries from list 1 into a hash table */
336 21 : i = 0;
337 87 : while (list1[i]) {
338 45 : key.str = talloc_strdup(tmp_ctx, list1[i]);
339 45 : error = hash_enter(table, &key, &value);
340 45 : if (error != HASH_SUCCESS) {
341 0 : ret = EIO;
342 0 : goto done;
343 : }
344 45 : i++;
345 : }
346 :
347 : /* Iterate through list 2 and remove matching items */
348 21 : i = 0;
349 84 : while (list2[i]) {
350 42 : key.str = talloc_strdup(tmp_ctx, list2[i]);
351 42 : error = hash_delete(table, &key);
352 42 : if (error == HASH_SUCCESS) {
353 35 : if (_both_lists) {
354 : /* String was present in both lists */
355 29 : i12++;
356 29 : both_lists = talloc_realloc(tmp_ctx, both_lists, char *, i12+1);
357 29 : if (!both_lists) {
358 0 : ret = ENOMEM;
359 0 : goto done;
360 : }
361 29 : both_lists[i12-1] = talloc_strdup(both_lists, list2[i]);
362 29 : if (!both_lists[i12-1]) {
363 0 : ret = ENOMEM;
364 0 : goto done;
365 : }
366 :
367 29 : both_lists[i12] = NULL;
368 : }
369 : }
370 7 : else if (error == HASH_ERROR_KEY_NOT_FOUND) {
371 7 : if (_list2_only) {
372 : /* String was present only in list2 */
373 6 : i2++;
374 6 : list2_only = talloc_realloc(tmp_ctx, list2_only,
375 : char *, i2+1);
376 6 : if (!list2_only) {
377 0 : ret = ENOMEM;
378 0 : goto done;
379 : }
380 6 : list2_only[i2-1] = talloc_strdup(list2_only, list2[i]);
381 6 : if (!list2_only[i2-1]) {
382 0 : ret = ENOMEM;
383 0 : goto done;
384 : }
385 :
386 6 : list2_only[i2] = NULL;
387 : }
388 : }
389 : else {
390 : /* An error occurred */
391 0 : ret = EIO;
392 0 : goto done;
393 : }
394 42 : i++;
395 : }
396 :
397 : /* Get the leftover entries in the hash table */
398 21 : if (_list1_only) {
399 20 : error = hash_keys(table, &count, &keys);
400 20 : if (error != HASH_SUCCESS) {
401 0 : ret = EIO;
402 0 : goto done;
403 : }
404 :
405 20 : list1_only = talloc_array(tmp_ctx, char *, count+1);
406 20 : if (!list1_only) {
407 0 : ret = ENOMEM;
408 0 : goto done;
409 : }
410 :
411 29 : for (i = 0; i < count; i++) {
412 9 : list1_only[i] = talloc_strdup(list1_only, keys[i].str);
413 9 : if (!list1_only[i]) {
414 0 : ret = ENOMEM;
415 0 : goto done;
416 : }
417 : }
418 20 : list1_only[count] = NULL;
419 :
420 20 : free(keys);
421 :
422 20 : *_list1_only = talloc_steal(memctx, list1_only);
423 : }
424 :
425 21 : if (_list2_only) {
426 20 : if (list2_only) {
427 4 : *_list2_only = talloc_steal(memctx, list2_only);
428 : }
429 : else {
430 16 : *_list2_only = talloc_array(memctx, char *, 1);
431 16 : if (!(*_list2_only)) {
432 0 : ret = ENOMEM;
433 0 : goto done;
434 : }
435 16 : *_list2_only[0] = NULL;
436 : }
437 : }
438 :
439 21 : if (_both_lists) {
440 18 : if (both_lists) {
441 13 : *_both_lists = talloc_steal(memctx, both_lists);
442 : }
443 : else {
444 5 : *_both_lists = talloc_array(memctx, char *, 1);
445 5 : if (!(*_both_lists)) {
446 0 : ret = ENOMEM;
447 0 : goto done;
448 : }
449 5 : *_both_lists[0] = NULL;
450 : }
451 : }
452 :
453 21 : ret = EOK;
454 :
455 : done:
456 21 : hash_destroy(table);
457 21 : talloc_free(tmp_ctx);
458 21 : return ret;
459 : }
460 :
461 964 : static void *hash_talloc(const size_t size, void *pvt)
462 : {
463 964 : return talloc_size(pvt, size);
464 : }
465 :
466 79 : static void hash_talloc_free(void *ptr, void *pvt)
467 : {
468 79 : talloc_free(ptr);
469 79 : }
470 :
471 236 : errno_t sss_hash_create_ex(TALLOC_CTX *mem_ctx,
472 : unsigned long count,
473 : hash_table_t **tbl,
474 : unsigned int directory_bits,
475 : unsigned int segment_bits,
476 : unsigned long min_load_factor,
477 : unsigned long max_load_factor,
478 : hash_delete_callback *delete_callback,
479 : void *delete_private_data)
480 : {
481 : errno_t ret;
482 : hash_table_t *table;
483 : int hret;
484 :
485 : TALLOC_CTX *internal_ctx;
486 236 : internal_ctx = talloc_new(NULL);
487 236 : if (!internal_ctx) {
488 0 : return ENOMEM;
489 : }
490 :
491 236 : hret = hash_create_ex(count, &table, directory_bits, segment_bits,
492 : min_load_factor, max_load_factor,
493 : hash_talloc, hash_talloc_free, internal_ctx,
494 : delete_callback, delete_private_data);
495 236 : switch (hret) {
496 : case HASH_SUCCESS:
497 : /* Steal the table pointer onto the mem_ctx,
498 : * then make the internal_ctx a child of
499 : * table.
500 : *
501 : * This way, we can clean up the values when
502 : * we talloc_free() the table
503 : */
504 236 : *tbl = talloc_steal(mem_ctx, table);
505 236 : talloc_steal(table, internal_ctx);
506 236 : return EOK;
507 :
508 : case HASH_ERROR_NO_MEMORY:
509 0 : ret = ENOMEM;
510 0 : break;
511 : default:
512 0 : ret = EIO;
513 : }
514 :
515 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Could not create hash table: [%d][%s]\n",
516 : hret, hash_error_string(hret));
517 :
518 0 : talloc_free(internal_ctx);
519 0 : return ret;
520 : }
521 :
522 233 : errno_t sss_hash_create(TALLOC_CTX *mem_ctx, unsigned long count,
523 : hash_table_t **tbl)
524 : {
525 233 : return sss_hash_create_ex(mem_ctx, count, tbl, 0, 0, 0, 0, NULL, NULL);
526 : }
527 :
528 2123 : errno_t sss_filter_sanitize_ex(TALLOC_CTX *mem_ctx,
529 : const char *input,
530 : char **sanitized,
531 : const char *ignore)
532 : {
533 : char *output;
534 2123 : size_t i = 0;
535 2123 : size_t j = 0;
536 : char *allowed;
537 :
538 : /* Assume the worst-case. We'll resize it later, once */
539 2123 : output = talloc_array(mem_ctx, char, strlen(input) * 3 + 1);
540 2123 : if (!output) {
541 0 : return ENOMEM;
542 : }
543 :
544 45229 : while (input[i]) {
545 : /* Even though this character might have a special meaning, if it's
546 : * expliticly allowed, just copy it and move on
547 : */
548 40983 : if (ignore == NULL) {
549 40971 : allowed = NULL;
550 : } else {
551 12 : allowed = strchr(ignore, input[i]);
552 : }
553 40983 : if (allowed) {
554 1 : output[j++] = input[i++];
555 1 : continue;
556 : }
557 :
558 40982 : switch(input[i]) {
559 : case '\t':
560 0 : output[j++] = '\\';
561 0 : output[j++] = '0';
562 0 : output[j++] = '9';
563 0 : break;
564 : case ' ':
565 35 : output[j++] = '\\';
566 35 : output[j++] = '2';
567 35 : output[j++] = '0';
568 35 : break;
569 : case '*':
570 35 : output[j++] = '\\';
571 35 : output[j++] = '2';
572 35 : output[j++] = 'a';
573 35 : break;
574 : case '(':
575 30 : output[j++] = '\\';
576 30 : output[j++] = '2';
577 30 : output[j++] = '8';
578 30 : break;
579 : case ')':
580 30 : output[j++] = '\\';
581 30 : output[j++] = '2';
582 30 : output[j++] = '9';
583 30 : break;
584 : case '\\':
585 46 : output[j++] = '\\';
586 46 : output[j++] = '5';
587 46 : output[j++] = 'c';
588 46 : break;
589 : default:
590 40806 : output[j++] = input[i];
591 : }
592 :
593 40982 : i++;
594 : }
595 2123 : output[j] = '\0';
596 2123 : *sanitized = talloc_realloc(mem_ctx, output, char, j+1);
597 2123 : if (!*sanitized) {
598 0 : talloc_free(output);
599 0 : return ENOMEM;
600 : }
601 :
602 2123 : return EOK;
603 : }
604 :
605 2122 : errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
606 : const char *input,
607 : char **sanitized)
608 : {
609 2122 : return sss_filter_sanitize_ex(mem_ctx, input, sanitized, NULL);
610 : }
611 :
612 : char *
613 0 : sss_escape_ip_address(TALLOC_CTX *mem_ctx, int family, const char *addr)
614 : {
615 0 : return family == AF_INET6 ? talloc_asprintf(mem_ctx, "[%s]", addr) :
616 : talloc_strdup(mem_ctx, addr);
617 : }
618 :
619 : /* out->len includes terminating '\0' */
620 155 : void to_sized_string(struct sized_string *out, const char *in)
621 : {
622 155 : out->str = in;
623 155 : if (out->str) {
624 155 : out->len = strlen(out->str) + 1;
625 : } else {
626 0 : out->len = 0;
627 : }
628 155 : }
629 :
630 : /* This function only removes first and last
631 : * character if the first character was '['.
632 : *
633 : * NOTE: This means, that ipv6addr must NOT be followed
634 : * by port number.
635 : */
636 : errno_t
637 0 : remove_ipv6_brackets(char *ipv6addr)
638 : {
639 : size_t len;
640 :
641 0 : if (ipv6addr && ipv6addr[0] == '[') {
642 0 : len = strlen(ipv6addr);
643 0 : if (len < 3) {
644 0 : return EINVAL;
645 : }
646 :
647 0 : memmove(ipv6addr, &ipv6addr[1], len - 2);
648 0 : ipv6addr[len -2] = '\0';
649 : }
650 :
651 0 : return EOK;
652 : }
653 :
654 10 : errno_t add_string_to_list(TALLOC_CTX *mem_ctx, const char *string,
655 : char ***list_p)
656 : {
657 : size_t c;
658 10 : char **old_list = NULL;
659 10 : char **new_list = NULL;
660 :
661 10 : if (string == NULL || list_p == NULL) {
662 1 : DEBUG(SSSDBG_OP_FAILURE, "Missing string or list.\n");
663 1 : return EINVAL;
664 : }
665 :
666 9 : old_list = *list_p;
667 :
668 9 : if (old_list == NULL) {
669 : /* If the input is a NULL list a new one is created with the new
670 : * string and the terminating NULL element. */
671 5 : c = 0;
672 5 : new_list = talloc_array(mem_ctx, char *, 2);
673 : } else {
674 4 : for (c = 0; old_list[c] != NULL; c++);
675 : /* Allocate one extra space for the new service and one for
676 : * the terminating NULL
677 : */
678 4 : new_list = talloc_realloc(mem_ctx, old_list, char *, c + 2);
679 : }
680 :
681 9 : if (new_list == NULL) {
682 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_array/talloc_realloc failed.\n");
683 0 : return ENOMEM;
684 : }
685 :
686 9 : new_list[c] = talloc_strdup(new_list, string);
687 9 : if (new_list[c] == NULL) {
688 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
689 0 : talloc_free(new_list);
690 0 : return ENOMEM;
691 : }
692 :
693 9 : new_list[c + 1] = NULL;
694 :
695 9 : *list_p = new_list;
696 :
697 9 : return EOK;
698 : }
699 :
700 1761 : bool string_in_list(const char *string, char **list, bool case_sensitive)
701 : {
702 : size_t c;
703 : int(*compare)(const char *s1, const char *s2);
704 :
705 1761 : if (string == NULL || list == NULL || *list == NULL) {
706 51 : return false;
707 : }
708 :
709 1710 : compare = case_sensitive ? strcmp : strcasecmp;
710 :
711 13719 : for (c = 0; list[c] != NULL; c++) {
712 12522 : if (compare(string, list[c]) == 0) {
713 513 : return true;
714 : }
715 : }
716 :
717 1197 : return false;
718 : }
719 :
720 27 : void safezero(void *data, size_t size)
721 : {
722 27 : volatile uint8_t *p = data;
723 :
724 275 : while (size--) {
725 221 : *p++ = 0;
726 : }
727 27 : }
728 :
729 23 : int domain_to_basedn(TALLOC_CTX *memctx, const char *domain, char **basedn)
730 : {
731 : const char *s;
732 : char *dn;
733 : char *p;
734 : int l;
735 :
736 23 : if (!domain || !basedn) {
737 2 : return EINVAL;
738 : }
739 :
740 21 : s = domain;
741 21 : dn = talloc_strdup(memctx, "dc=");
742 :
743 61 : while ((p = strchr(s, '.'))) {
744 19 : l = p - s;
745 19 : dn = talloc_asprintf_append_buffer(dn, "%.*s,dc=", l, s);
746 19 : if (!dn) {
747 0 : return ENOMEM;
748 : }
749 19 : s = p + 1;
750 : }
751 21 : dn = talloc_strdup_append_buffer(dn, s);
752 21 : if (!dn) {
753 0 : return ENOMEM;
754 : }
755 :
756 579 : for (p=dn; *p; ++p) {
757 558 : *p = tolower(*p);
758 : }
759 :
760 21 : *basedn = dn;
761 21 : return EOK;
762 : }
763 :
764 8 : bool is_host_in_domain(const char *host, const char *domain)
765 : {
766 8 : int diff = strlen(host) - strlen(domain);
767 :
768 8 : if (diff == 0 && strcmp(host, domain) == 0) {
769 1 : return true;
770 : }
771 :
772 7 : if (diff > 0 && strcmp(host + diff, domain) == 0 && host[diff - 1] == '.') {
773 3 : return true;
774 : }
775 :
776 4 : return false;
777 : }
778 :
779 : /* addr is in network order for both IPv4 and IPv6 versions */
780 21 : bool check_ipv4_addr(struct in_addr *addr, uint8_t flags)
781 : {
782 : char straddr[INET_ADDRSTRLEN];
783 :
784 21 : if (inet_ntop(AF_INET, addr, straddr, INET_ADDRSTRLEN) == NULL) {
785 0 : DEBUG(SSSDBG_MINOR_FAILURE,
786 : "inet_ntop failed, won't log IP addresses\n");
787 0 : snprintf(straddr, INET_ADDRSTRLEN, "unknown");
788 : }
789 :
790 21 : if ((flags & SSS_NO_MULTICAST) && IN_MULTICAST(ntohl(addr->s_addr))) {
791 1 : DEBUG(SSSDBG_FUNC_DATA, "Multicast IPv4 address %s\n", straddr);
792 1 : return false;
793 20 : } else if ((flags & SSS_NO_LOOPBACK)
794 16 : && inet_netof(*addr) == IN_LOOPBACKNET) {
795 1 : DEBUG(SSSDBG_FUNC_DATA, "Loopback IPv4 address %s\n", straddr);
796 1 : return false;
797 19 : } else if ((flags & SSS_NO_LINKLOCAL)
798 16 : && (addr->s_addr & htonl(0xffff0000)) == htonl(0xa9fe0000)) {
799 : /* 169.254.0.0/16 */
800 1 : DEBUG(SSSDBG_FUNC_DATA, "Link-local IPv4 address %s\n", straddr);
801 1 : return false;
802 18 : } else if ((flags & SSS_NO_BROADCAST)
803 16 : && addr->s_addr == htonl(INADDR_BROADCAST)) {
804 2 : DEBUG(SSSDBG_FUNC_DATA, "Broadcast IPv4 address %s\n", straddr);
805 2 : return false;
806 : }
807 :
808 16 : return true;
809 : }
810 :
811 17 : bool check_ipv6_addr(struct in6_addr *addr, uint8_t flags)
812 : {
813 : char straddr[INET6_ADDRSTRLEN];
814 :
815 17 : if (inet_ntop(AF_INET6, addr, straddr, INET6_ADDRSTRLEN) == NULL) {
816 0 : DEBUG(SSSDBG_MINOR_FAILURE,
817 : "inet_ntop failed, won't log IP addresses\n");
818 0 : snprintf(straddr, INET6_ADDRSTRLEN, "unknown");
819 : }
820 :
821 17 : if ((flags & SSS_NO_LINKLOCAL) && IN6_IS_ADDR_LINKLOCAL(addr)) {
822 2 : DEBUG(SSSDBG_FUNC_DATA, "Link local IPv6 address %s\n", straddr);
823 2 : return false;
824 15 : } else if ((flags & SSS_NO_LOOPBACK) && IN6_IS_ADDR_LOOPBACK(addr)) {
825 2 : DEBUG(SSSDBG_FUNC_DATA, "Loopback IPv6 address %s\n", straddr);
826 2 : return false;
827 13 : } else if ((flags & SSS_NO_MULTICAST) && IN6_IS_ADDR_MULTICAST(addr)) {
828 2 : DEBUG(SSSDBG_FUNC_DATA, "Multicast IPv6 address %s\n", straddr);
829 2 : return false;
830 : }
831 :
832 11 : return true;
833 : }
834 :
835 1 : const char * const * get_known_services(void)
836 : {
837 : static const char *svc[] = {"nss", "pam", "sudo", "autofs",
838 : "ssh", "pac", "ifp", NULL };
839 :
840 1 : return svc;
841 : }
842 :
843 10 : errno_t add_strings_lists(TALLOC_CTX *mem_ctx, const char **l1, const char **l2,
844 : bool copy_strings, char ***_new_list)
845 : {
846 : size_t c;
847 10 : size_t l1_count = 0;
848 10 : size_t l2_count = 0;
849 10 : size_t new_count = 0;
850 : char **new;
851 : int ret;
852 :
853 10 : if (l1 != NULL) {
854 6 : for (l1_count = 0; l1[l1_count] != NULL; l1_count++);
855 : }
856 :
857 10 : if (l2 != NULL) {
858 6 : for (l2_count = 0; l2[l2_count] != NULL; l2_count++);
859 : }
860 :
861 10 : new_count = l1_count + l2_count;
862 :
863 10 : new = talloc_array(mem_ctx, char *, new_count + 1);
864 10 : if (new == NULL) {
865 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
866 0 : return ENOMEM;
867 : }
868 10 : new [new_count] = NULL;
869 :
870 10 : if (copy_strings) {
871 10 : for(c = 0; c < l1_count; c++) {
872 6 : new[c] = talloc_strdup(new, l1[c]);
873 6 : if (new[c] == NULL) {
874 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
875 0 : ret = ENOMEM;
876 0 : goto done;
877 : }
878 : }
879 10 : for(c = 0; c < l2_count; c++) {
880 6 : new[l1_count + c] = talloc_strdup(new, l2[c]);
881 6 : if (new[l1_count + c] == NULL) {
882 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
883 0 : ret = ENOMEM;
884 0 : goto done;
885 : }
886 : }
887 : } else {
888 6 : if (l1 != NULL) {
889 4 : memcpy(new, l1, sizeof(char *) * l1_count);
890 : }
891 :
892 6 : if (l2 != NULL) {
893 4 : memcpy(&new[l1_count], l2, sizeof(char *) * l2_count);
894 : }
895 : }
896 :
897 10 : *_new_list = new;
898 10 : ret = EOK;
899 :
900 : done:
901 10 : if (ret != EOK) {
902 0 : talloc_free(new);
903 : }
904 :
905 10 : return ret;
906 : }
907 :
908 : /* Set the nonblocking flag to the fd */
909 21 : errno_t sss_fd_nonblocking(int fd)
910 : {
911 : int flags;
912 : int ret;
913 :
914 21 : flags = fcntl(fd, F_GETFL, 0);
915 21 : if (flags == -1) {
916 0 : ret = errno;
917 0 : DEBUG(SSSDBG_CRIT_FAILURE,
918 : "F_GETFL failed [%d][%s].\n", ret, strerror(ret));
919 0 : return ret;
920 : }
921 :
922 21 : if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
923 0 : ret = errno;
924 0 : DEBUG(SSSDBG_CRIT_FAILURE,
925 : "F_SETFL failed [%d][%s].\n", ret, strerror(ret));
926 0 : return ret;
927 : }
928 :
929 21 : return EOK;
930 : }
931 :
932 : /* Convert GeneralizedTime (http://en.wikipedia.org/wiki/GeneralizedTime)
933 : * to unix time (seconds since epoch). Use UTC time zone.
934 : */
935 18 : errno_t sss_utc_to_time_t(const char *str, const char *format, time_t *_unix_time)
936 : {
937 : char *end;
938 : struct tm tm;
939 : size_t len;
940 : time_t ut;
941 :
942 18 : if (str == NULL) {
943 0 : return EINVAL;
944 : }
945 :
946 18 : len = strlen(str);
947 18 : if (str[len-1] != 'Z') {
948 5 : DEBUG(SSSDBG_TRACE_INTERNAL,
949 : "%s does not seem to be in UTZ time zone.\n", str);
950 5 : return ERR_TIMESPEC_NOT_SUPPORTED;
951 : }
952 :
953 13 : memset(&tm, 0, sizeof(tm));
954 :
955 13 : end = strptime(str, format, &tm);
956 : /* not all characters from format were matched */
957 13 : if (end == NULL) {
958 2 : DEBUG(SSSDBG_TRACE_INTERNAL,
959 : "String [%s] failed to match format [%s].\n", str, format);
960 2 : return EINVAL;
961 : }
962 :
963 : /* str is 'longer' than format */
964 11 : if (*end != '\0') {
965 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
966 : "String [%s] is longer than format [%s].\n", str, format);
967 0 : return EINVAL;
968 : }
969 :
970 11 : ut = mktime(&tm);
971 11 : if (ut == -1) {
972 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
973 : "mktime failed to convert [%s].\n", str);
974 0 : return EINVAL;
975 : }
976 :
977 11 : tzset();
978 11 : ut -= timezone;
979 11 : *_unix_time = ut;
980 11 : return EOK;
981 : }
982 :
983 : struct tmpfile_watch {
984 : const char *filename;
985 : };
986 :
987 2 : static int unlink_dbg(const char *filename)
988 : {
989 : errno_t ret;
990 :
991 2 : ret = unlink(filename);
992 2 : if (ret != 0) {
993 0 : if (errno == 2) {
994 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
995 : "File already removed: [%s]\n", filename);
996 0 : return 0;
997 : } else {
998 0 : DEBUG(SSSDBG_CRIT_FAILURE,
999 : "Cannot remove temporary file [%s]\n", filename);
1000 0 : return -1;
1001 : }
1002 : }
1003 :
1004 2 : return 0;
1005 : }
1006 :
1007 2 : static int unique_filename_destructor(void *memptr)
1008 : {
1009 2 : struct tmpfile_watch *tw = talloc_get_type(memptr, struct tmpfile_watch);
1010 :
1011 2 : if (tw == NULL || tw->filename == NULL) {
1012 0 : DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Wrong private pointer\n");
1013 0 : return -1;
1014 : }
1015 :
1016 2 : DEBUG(SSSDBG_TRACE_INTERNAL, "Unlinking [%s]\n", tw->filename);
1017 :
1018 2 : return unlink_dbg(tw->filename);
1019 : }
1020 :
1021 2 : static struct tmpfile_watch *tmpfile_watch_set(TALLOC_CTX *owner,
1022 : const char *filename)
1023 : {
1024 2 : struct tmpfile_watch *tw = NULL;
1025 :
1026 2 : tw = talloc_zero(owner, struct tmpfile_watch);
1027 2 : if (tw == NULL) {
1028 0 : return NULL;
1029 : }
1030 :
1031 2 : tw->filename = talloc_strdup(tw, filename);
1032 2 : if (tw->filename == NULL) {
1033 0 : talloc_free(tw);
1034 0 : return NULL;
1035 : }
1036 :
1037 2 : talloc_set_destructor((TALLOC_CTX *) tw,
1038 : unique_filename_destructor);
1039 2 : return tw;
1040 : }
1041 :
1042 5 : int sss_unique_file_ex(TALLOC_CTX *owner,
1043 : char *path_tmpl,
1044 : mode_t file_umask,
1045 : errno_t *_err)
1046 : {
1047 : size_t tmpl_len;
1048 : errno_t ret;
1049 5 : int fd = -1;
1050 : mode_t old_umask;
1051 5 : struct tmpfile_watch *tw = NULL;
1052 :
1053 5 : tmpl_len = strlen(path_tmpl);
1054 5 : if (tmpl_len < 6 || strcmp(path_tmpl + (tmpl_len - 6), "XXXXXX") != 0) {
1055 1 : DEBUG(SSSDBG_OP_FAILURE,
1056 : "Template too short or doesn't end with XXXXXX!\n");
1057 1 : ret = EINVAL;
1058 1 : goto done;
1059 : }
1060 :
1061 4 : old_umask = umask(file_umask);
1062 4 : fd = mkstemp(path_tmpl);
1063 4 : umask(old_umask);
1064 4 : if (fd == -1) {
1065 0 : ret = errno;
1066 0 : DEBUG(SSSDBG_OP_FAILURE,
1067 : "mkstemp(\"%s\") failed [%d]: %s!\n",
1068 : path_tmpl, ret, strerror(ret));
1069 0 : goto done;
1070 : }
1071 :
1072 4 : if (owner != NULL) {
1073 2 : tw = tmpfile_watch_set(owner, path_tmpl);
1074 2 : if (tw == NULL) {
1075 0 : unlink_dbg(path_tmpl);
1076 0 : ret = ENOMEM;
1077 0 : goto done;
1078 : }
1079 : }
1080 :
1081 4 : ret = EOK;
1082 : done:
1083 5 : if (_err) {
1084 5 : *_err = ret;
1085 : }
1086 5 : return fd;
1087 : }
1088 :
1089 5 : int sss_unique_file(TALLOC_CTX *owner,
1090 : char *path_tmpl,
1091 : errno_t *_err)
1092 : {
1093 5 : return sss_unique_file_ex(owner, path_tmpl, SSS_DFL_UMASK, _err);
1094 : }
1095 :
1096 2 : errno_t sss_unique_filename(TALLOC_CTX *owner, char *path_tmpl)
1097 : {
1098 : int fd;
1099 : errno_t ret;
1100 :
1101 2 : fd = sss_unique_file(owner, path_tmpl, &ret);
1102 : /* We only care about a unique file name */
1103 2 : if (fd >= 0) {
1104 2 : close(fd);
1105 : }
1106 :
1107 2 : return ret;
1108 : }
1109 :
1110 19 : static struct cert_verify_opts *init_cert_verify_opts(TALLOC_CTX *mem_ctx)
1111 : {
1112 : struct cert_verify_opts *cert_verify_opts;
1113 :
1114 19 : cert_verify_opts = talloc_zero(mem_ctx, struct cert_verify_opts);
1115 19 : if (cert_verify_opts == NULL) {
1116 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
1117 0 : return NULL;
1118 : }
1119 :
1120 19 : cert_verify_opts->do_ocsp = true;
1121 19 : cert_verify_opts->do_verification = true;
1122 19 : cert_verify_opts->ocsp_default_responder = NULL;
1123 19 : cert_verify_opts->ocsp_default_responder_signing_cert = NULL;
1124 :
1125 19 : return cert_verify_opts;
1126 : }
1127 :
1128 : #define OCSP_DEFAUL_RESPONDER "ocsp_default_responder="
1129 : #define OCSP_DEFAUL_RESPONDER_LEN (sizeof(OCSP_DEFAUL_RESPONDER) - 1)
1130 :
1131 : #define OCSP_DEFAUL_RESPONDER_SIGNING_CERT \
1132 : "ocsp_default_responder_signing_cert="
1133 : #define OCSP_DEFAUL_RESPONDER_SIGNING_CERT_LEN \
1134 : (sizeof(OCSP_DEFAUL_RESPONDER_SIGNING_CERT) - 1)
1135 :
1136 19 : errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts,
1137 : struct cert_verify_opts **_cert_verify_opts)
1138 : {
1139 : int ret;
1140 : TALLOC_CTX *tmp_ctx;
1141 : char **opts;
1142 : size_t c;
1143 : struct cert_verify_opts *cert_verify_opts;
1144 :
1145 19 : tmp_ctx = talloc_new(NULL);
1146 19 : if (tmp_ctx == NULL) {
1147 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
1148 0 : return ENOMEM;
1149 : }
1150 :
1151 19 : cert_verify_opts = init_cert_verify_opts(tmp_ctx);
1152 19 : if (cert_verify_opts == NULL) {
1153 0 : DEBUG(SSSDBG_OP_FAILURE, "init_cert_verify_opts failed.\n");
1154 0 : ret = ENOMEM;
1155 0 : goto done;
1156 : }
1157 :
1158 19 : if (verify_opts == NULL) {
1159 1 : ret = EOK;
1160 1 : goto done;
1161 : }
1162 :
1163 18 : ret = split_on_separator(tmp_ctx, verify_opts, ',', true, true, &opts,
1164 : NULL);
1165 18 : if (ret != EOK) {
1166 0 : DEBUG(SSSDBG_OP_FAILURE, "split_on_separator failed.\n");
1167 0 : goto done;
1168 : }
1169 :
1170 36 : for (c = 0; opts[c] != NULL; c++) {
1171 20 : if (strcasecmp(opts[c], "no_ocsp") == 0) {
1172 10 : DEBUG(SSSDBG_TRACE_ALL,
1173 : "Found 'no_ocsp' option, disabling OCSP.\n");
1174 10 : cert_verify_opts->do_ocsp = false;
1175 10 : } else if (strcasecmp(opts[c], "no_verification") == 0) {
1176 3 : DEBUG(SSSDBG_CRIT_FAILURE,
1177 : "Found 'no_verification' option, "
1178 : "disabling verification completely. "
1179 : "This should not be used in production.\n");
1180 3 : cert_verify_opts->do_verification = false;
1181 7 : } else if (strncasecmp(opts[c], OCSP_DEFAUL_RESPONDER,
1182 : OCSP_DEFAUL_RESPONDER_LEN) == 0) {
1183 3 : cert_verify_opts->ocsp_default_responder =
1184 3 : talloc_strdup(cert_verify_opts,
1185 3 : &opts[c][OCSP_DEFAUL_RESPONDER_LEN]);
1186 3 : if (cert_verify_opts->ocsp_default_responder == NULL
1187 3 : || *cert_verify_opts->ocsp_default_responder == '\0') {
1188 1 : DEBUG(SSSDBG_CRIT_FAILURE,
1189 : "Failed to parse ocsp_default_responder option [%s].\n",
1190 : opts[c]);
1191 1 : ret = EINVAL;
1192 1 : goto done;
1193 : }
1194 :
1195 2 : DEBUG(SSSDBG_TRACE_ALL, "Using OCSP default responder [%s]\n",
1196 : cert_verify_opts->ocsp_default_responder);
1197 4 : } else if (strncasecmp(opts[c],
1198 : OCSP_DEFAUL_RESPONDER_SIGNING_CERT,
1199 : OCSP_DEFAUL_RESPONDER_SIGNING_CERT_LEN) == 0) {
1200 3 : cert_verify_opts->ocsp_default_responder_signing_cert =
1201 3 : talloc_strdup(cert_verify_opts,
1202 3 : &opts[c][OCSP_DEFAUL_RESPONDER_SIGNING_CERT_LEN]);
1203 3 : if (cert_verify_opts->ocsp_default_responder_signing_cert == NULL
1204 6 : || *cert_verify_opts->ocsp_default_responder_signing_cert
1205 3 : == '\0') {
1206 1 : DEBUG(SSSDBG_CRIT_FAILURE,
1207 : "Failed to parse ocsp_default_responder_signing_cert "
1208 : "option [%s].\n", opts[c]);
1209 1 : ret = EINVAL;
1210 1 : goto done;
1211 : }
1212 :
1213 2 : DEBUG(SSSDBG_TRACE_ALL,
1214 : "Using OCSP default responder signing cert nickname [%s]\n",
1215 : cert_verify_opts->ocsp_default_responder_signing_cert);
1216 : } else {
1217 1 : DEBUG(SSSDBG_CRIT_FAILURE,
1218 : "Unsupported certificate verification option [%s], " \
1219 : "skipping.\n", opts[c]);
1220 : }
1221 : }
1222 :
1223 16 : if ((cert_verify_opts->ocsp_default_responder == NULL
1224 14 : && cert_verify_opts->ocsp_default_responder_signing_cert != NULL)
1225 15 : || (cert_verify_opts->ocsp_default_responder != NULL
1226 2 : && cert_verify_opts->ocsp_default_responder_signing_cert == NULL)) {
1227 :
1228 2 : DEBUG(SSSDBG_CRIT_FAILURE,
1229 : "ocsp_default_responder and ocsp_default_responder_signing_cert "
1230 : "must be used together.\n");
1231 :
1232 2 : ret = EINVAL;
1233 2 : goto done;
1234 : }
1235 :
1236 14 : ret = EOK;
1237 :
1238 : done:
1239 19 : if (ret == EOK) {
1240 15 : *_cert_verify_opts = talloc_steal(mem_ctx, cert_verify_opts);
1241 : }
1242 :
1243 19 : talloc_free(tmp_ctx);
1244 :
1245 19 : return ret;
1246 : }
|