Branch data Line data Source code
1 : : /*
2 : : SSSD
3 : :
4 : : Kerberos 5 Backend Module -- Utilities
5 : :
6 : : Authors:
7 : : Sumit Bose <sbose@redhat.com>
8 : :
9 : : Copyright (C) 2009 Red Hat
10 : :
11 : : This program is free software; you can redistribute it and/or modify
12 : : it under the terms of the GNU General Public License as published by
13 : : the Free Software Foundation; either version 3 of the License, or
14 : : (at your option) any later version.
15 : :
16 : : This program is distributed in the hope that it will be useful,
17 : : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : GNU General Public License for more details.
20 : :
21 : : You should have received a copy of the GNU General Public License
22 : : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : : */
24 : : #include <string.h>
25 : : #include <stdlib.h>
26 : : #include <libgen.h>
27 : :
28 : : #include "providers/krb5/krb5_utils.h"
29 : : #include "providers/krb5/krb5_auth.h"
30 : : #include "src/util/find_uid.h"
31 : : #include "util/util.h"
32 : :
33 : 0 : errno_t find_or_guess_upn(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
34 : : struct krb5_ctx *krb5_ctx,
35 : : const char *domain_name, const char *user,
36 : : const char *user_dom, char **_upn)
37 : : {
38 : : const char *upn;
39 : : int ret;
40 : :
41 : 0 : upn = ldb_msg_find_attr_as_string(msg, SYSDB_UPN, NULL);
42 [ # # ]: 0 : if (upn == NULL) {
43 : 0 : ret = krb5_get_simple_upn(mem_ctx, krb5_ctx, domain_name, user,
44 : : user_dom, _upn);
45 [ # # ]: 0 : if (ret != EOK) {
46 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("krb5_get_simple_upn failed.\n"));
[ # # ][ # # ]
[ # # ]
47 : 0 : return ret;
48 : : }
49 : : } else {
50 : 0 : *_upn = talloc_strdup(mem_ctx, upn);
51 [ # # ]: 0 : if (*_upn == NULL) {
52 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
[ # # ][ # # ]
[ # # ]
53 : : return ENOMEM;
54 : : }
55 : : }
56 : :
57 : : return EOK;
58 : : }
59 : :
60 : 0 : errno_t check_if_cached_upn_needs_update(struct sysdb_ctx *sysdb,
61 : : const char *user,
62 : : const char *upn)
63 : : {
64 : : TALLOC_CTX *tmp_ctx;
65 : : int ret;
66 : : int sret;
67 : 0 : const char *attrs[] = {SYSDB_UPN, NULL};
68 : : struct sysdb_attrs *new_attrs;
69 : : struct ldb_result *res;
70 : 0 : bool in_transaction = false;
71 : : const char *cached_upn;
72 : :
73 [ # # ][ # # ]: 0 : if (sysdb == NULL || user == NULL || upn == NULL) {
74 : : return EINVAL;
75 : : }
76 : :
77 : 0 : tmp_ctx = talloc_new(NULL);
78 [ # # ]: 0 : if (tmp_ctx == NULL) {
79 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("talloc_new failed.\n"));
[ # # ][ # # ]
[ # # ]
80 : : return ENOMEM;
81 : : }
82 : :
83 : 0 : ret = sysdb_get_user_attr(tmp_ctx, sysdb, user, attrs, &res);
84 [ # # ]: 0 : if (ret != EOK) {
85 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("sysdb_get_user_attr failed.\n"));
[ # # ][ # # ]
[ # # ]
86 : : goto done;
87 : : }
88 : :
89 [ # # ]: 0 : if (res->count != 1) {
90 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("[%d] user objects for name [%s] found, " \
[ # # ][ # # ]
[ # # ]
91 : : "expected 1.\n", res->count, user));
92 : : ret = EINVAL;
93 : : goto done;
94 : : }
95 : :
96 : 0 : cached_upn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_UPN, NULL);
97 : :
98 [ # # ][ # # ]: 0 : if (cached_upn != NULL && strcmp(cached_upn, upn) == 0) {
99 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_TRACE_ALL, ("Cached UPN and new one match, "
[ # # ][ # # ]
[ # # ]
100 : : "nothing to do.\n"));
101 : : ret = EOK;
102 : : goto done;
103 : : }
104 : :
105 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_TRACE_LIBS, ("Replacing UPN [%s] with [%s] for user [%s].\n",
[ # # ][ # # ]
[ # # ]
106 : : cached_upn, upn, user));
107 : :
108 : 0 : new_attrs = sysdb_new_attrs(tmp_ctx);
109 [ # # ]: 0 : if (new_attrs == NULL) {
110 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("sysdb_new_attrs failed.\n"));
[ # # ][ # # ]
[ # # ]
111 : : ret = ENOMEM;
112 : : goto done;
113 : : }
114 : :
115 : 0 : ret = sysdb_attrs_add_string(new_attrs, SYSDB_UPN, upn);
116 [ # # ]: 0 : if (ret != EOK) {
117 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_add_string failed.\n"));
[ # # ][ # # ]
[ # # ]
118 : : goto done;
119 : : }
120 : :
121 : 0 : ret = sysdb_transaction_start(sysdb);
122 [ # # ]: 0 : if (ret != EOK) {
123 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE,
[ # # ][ # # ]
[ # # ]
124 : : ("Error %d starting transaction (%s)\n", ret, strerror(ret)));
125 : : goto done;
126 : : }
127 : 0 : in_transaction = true;
128 : :
129 : 0 : ret = sysdb_set_entry_attr(sysdb, res->msgs[0]->dn, new_attrs,
130 : : SYSDB_MOD_REP);
131 [ # # ]: 0 : if (ret != EOK) {
132 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("sysdb_set_entry_attr failed [%d][%s].\n",
[ # # ][ # # ]
[ # # ]
133 : : ret, strerror(ret)));
134 : : goto done;
135 : : }
136 : :
137 : 0 : ret = sysdb_transaction_commit(sysdb);
138 [ # # ]: 0 : if (ret != EOK) {
139 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("Failed to commit transaction!\n"));
[ # # ][ # # ]
[ # # ]
140 : : goto done;
141 : : }
142 : : in_transaction = false;
143 : :
144 : : ret = EOK;
145 : :
146 : : done:
147 [ # # ]: 0 : if (in_transaction) {
148 : 0 : sret = sysdb_transaction_cancel(sysdb);
149 [ # # ]: 0 : if (sret != EOK) {
150 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to cancel transaction\n"));
[ # # ][ # # ]
[ # # ]
151 : : }
152 : : }
153 : :
154 : 0 : talloc_free(tmp_ctx);
155 : :
156 : : return ret;
157 : : }
158 : :
159 : 35 : char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
160 : : const char *template, bool file_mode,
161 : : bool case_sensitive, bool *private_path)
162 : : {
163 : : char *copy;
164 : : char *p;
165 : : char *n;
166 : 35 : char *result = NULL;
167 : : char *dummy;
168 : : char *name;
169 : 35 : char *res = NULL;
170 : : const char *cache_dir_tmpl;
171 : 35 : TALLOC_CTX *tmp_ctx = NULL;
172 : :
173 : 35 : *private_path = false;
174 : :
175 [ + + ]: 35 : if (template == NULL) {
176 [ + - ][ + - ]: 1 : DEBUG(1, ("Missing template.\n"));
[ + - ][ + - ]
[ + - ]
177 : : return NULL;
178 : : }
179 : :
180 : 34 : tmp_ctx = talloc_new(NULL);
181 [ + - ]: 34 : if (!tmp_ctx) return NULL;
182 : :
183 : 34 : copy = talloc_strdup(tmp_ctx, template);
184 [ - + ]: 34 : if (copy == NULL) {
185 [ # # ][ # # ]: 0 : DEBUG(1, ("talloc_strdup failed.\n"));
[ # # ][ # # ]
[ # # ]
186 : : goto done;
187 : : }
188 : :
189 : 34 : result = talloc_strdup(tmp_ctx, "");
190 [ + - ]: 34 : if (result == NULL) {
191 [ # # ][ # # ]: 0 : DEBUG(1, ("talloc_strdup failed.\n"));
[ # # ][ # # ]
[ # # ]
192 : : goto done;
193 : : }
194 : :
195 : : p = copy;
196 [ + + ]: 63 : while ( (n = strchr(p, '%')) != NULL) {
197 : 36 : *n = '\0';
198 : 36 : n++;
199 [ - + ]: 36 : if ( *n == '\0' ) {
200 [ # # ][ # # ]: 0 : DEBUG(1, ("format error, single %% at the end of the template.\n"));
[ # # ][ # # ]
[ # # ]
201 : : goto done;
202 : : }
203 : :
204 [ + + + + : 36 : switch( *n ) {
+ + + +
+ ]
205 : : case 'u':
206 [ - + ]: 8 : if (kr->pd->user == NULL) {
207 [ # # ][ # # ]: 0 : DEBUG(1, ("Cannot expand user name template "
[ # # ][ # # ]
[ # # ]
208 : : "because user name is empty.\n"));
209 : : goto done;
210 : : }
211 : 8 : name = sss_get_cased_name(tmp_ctx, kr->pd->user,
212 : : case_sensitive);
213 [ - + ]: 8 : if (!name) {
214 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE,
[ # # ][ # # ]
[ # # ]
215 : : ("sss_get_cased_name failed\n"));
216 : : goto done;
217 : : }
218 : :
219 : 8 : result = talloc_asprintf_append(result, "%s%s", p,
220 : : name);
221 [ + + ]: 8 : if (!file_mode) *private_path = true;
222 : : break;
223 : : case 'U':
224 [ - + ]: 4 : if (kr->uid <= 0) {
225 [ # # ][ # # ]: 0 : DEBUG(1, ("Cannot expand uid template "
[ # # ][ # # ]
[ # # ]
226 : : "because uid is invalid.\n"));
227 : : goto done;
228 : : }
229 : 4 : result = talloc_asprintf_append(result, "%s%d", p,
230 : : kr->uid);
231 [ + + ]: 4 : if (!file_mode) *private_path = true;
232 : : break;
233 : : case 'p':
234 [ - + ]: 2 : if (kr->upn == NULL) {
235 [ # # ][ # # ]: 0 : DEBUG(1, ("Cannot expand user principal name template "
[ # # ][ # # ]
[ # # ]
236 : : "because upn is empty.\n"));
237 : : goto done;
238 : : }
239 : 2 : result = talloc_asprintf_append(result, "%s%s", p, kr->upn);
240 [ + + ]: 2 : if (!file_mode) *private_path = true;
241 : : break;
242 : : case '%':
243 : 2 : result = talloc_asprintf_append(result, "%s%%", p);
244 : 2 : break;
245 : : case 'r':
246 : 2 : dummy = dp_opt_get_string(kr->krb5_ctx->opts, KRB5_REALM);
247 [ - + ]: 2 : if (dummy == NULL) {
248 [ # # ][ # # ]: 0 : DEBUG(1, ("Missing kerberos realm.\n"));
[ # # ][ # # ]
[ # # ]
249 : : goto done;
250 : : }
251 : 2 : result = talloc_asprintf_append(result, "%s%s", p, dummy);
252 : 2 : break;
253 : : case 'h':
254 [ - + ]: 2 : if (kr->homedir == NULL) {
255 [ # # ][ # # ]: 0 : DEBUG(1, ("Cannot expand home directory template "
[ # # ][ # # ]
[ # # ]
256 : : "because the path is not available.\n"));
257 : : goto done;
258 : : }
259 : 2 : result = talloc_asprintf_append(result, "%s%s", p, kr->homedir);
260 [ + + ]: 2 : if (!file_mode) *private_path = true;
261 : : break;
262 : : case 'd':
263 [ + + ]: 12 : if (file_mode) {
264 : 11 : cache_dir_tmpl = dp_opt_get_string(kr->krb5_ctx->opts,
265 : : KRB5_CCACHEDIR);
266 [ - + ]: 11 : if (cache_dir_tmpl == NULL) {
267 [ # # ][ # # ]: 0 : DEBUG(1, ("Missing credential cache directory.\n"));
[ # # ][ # # ]
[ # # ]
268 : : goto done;
269 : : }
270 : :
271 : 11 : dummy = expand_ccname_template(tmp_ctx, kr, cache_dir_tmpl,
272 : : false, case_sensitive,
273 : : private_path);
274 [ + + ]: 11 : if (dummy == NULL) {
275 [ + - ][ + - ]: 3 : DEBUG(1, ("Expanding credential cache directory "
[ + - ][ + - ]
[ + - ]
276 : : "template failed.\n"));
277 : : goto done;
278 : : }
279 : 8 : result = talloc_asprintf_append(result, "%s%s", p, dummy);
280 : 8 : talloc_zfree(dummy);
281 : : } else {
282 [ + - ][ + - ]: 1 : DEBUG(1, ("'%%d' is not allowed in this template.\n"));
[ + - ][ + - ]
[ + - ]
283 : : goto done;
284 : : }
285 : : break;
286 : : case 'P':
287 [ + + ]: 2 : if (!file_mode) {
288 [ + - ][ + - ]: 1 : DEBUG(1, ("'%%P' is not allowed in this template.\n"));
[ + - ][ + - ]
[ + - ]
289 : : goto done;
290 : : }
291 [ - + ]: 1 : if (kr->pd->cli_pid == 0) {
292 [ # # ][ # # ]: 0 : DEBUG(1, ("Cannot expand PID template "
[ # # ][ # # ]
[ # # ]
293 : : "because PID is not available.\n"));
294 : : goto done;
295 : : }
296 : 1 : result = talloc_asprintf_append(result, "%s%d", p,
297 : : kr->pd->cli_pid);
298 : 1 : break;
299 : : default:
300 [ + - ][ + - ]: 2 : DEBUG(1, ("format error, unknown template [%%%c].\n", *n));
[ + - ][ + - ]
[ + - ]
301 : : goto done;
302 : : }
303 : :
304 [ - + ]: 29 : if (result == NULL) {
305 [ # # ][ # # ]: 0 : DEBUG(1, ("talloc_asprintf_append failed.\n"));
[ # # ][ # # ]
[ # # ]
306 : : goto done;
307 : : }
308 : :
309 : 29 : p = n + 1;
310 : : }
311 : :
312 : 27 : result = talloc_asprintf_append(result, "%s", p);
313 [ - + ]: 27 : if (result == NULL) {
314 [ # # ][ # # ]: 0 : DEBUG(1, ("talloc_asprintf_append failed.\n"));
[ # # ][ # # ]
[ # # ]
315 : : goto done;
316 : : }
317 : :
318 : 27 : res = talloc_move(mem_ctx, &result);
319 : : done:
320 : 35 : talloc_zfree(tmp_ctx);
321 : : return res;
322 : : }
323 : :
324 : 2 : static errno_t check_parent_stat(bool private_path, struct stat *parent_stat,
325 : : uid_t uid, gid_t gid)
326 : : {
327 [ + - ]: 2 : if (private_path) {
328 [ - + ][ # # ]: 2 : if (!((parent_stat->st_uid == 0 && parent_stat->st_gid == 0) ||
[ - + ]
329 : : parent_stat->st_uid == uid)) {
330 [ # # ][ # # ]: 0 : DEBUG(1, ("Private directory can only be created below a "
[ # # ][ # # ]
[ # # ]
331 : : "directory belonging to root or to [%d][%d].\n",
332 : : uid, gid));
333 : : return EINVAL;
334 : : }
335 : :
336 [ + - ]: 2 : if (parent_stat->st_uid == uid) {
337 [ - + ]: 2 : if (!(parent_stat->st_mode & S_IXUSR)) {
338 [ # # ][ # # ]: 0 : DEBUG(1, ("Parent directory does have the search bit set for "
[ # # ][ # # ]
[ # # ]
339 : : "the owner.\n"));
340 : : return EINVAL;
341 : : }
342 : : } else {
343 [ # # ]: 0 : if (!(parent_stat->st_mode & S_IXOTH)) {
344 [ # # ][ # # ]: 0 : DEBUG(1, ("Parent directory does have the search bit set for "
[ # # ][ # # ]
[ # # ]
345 : : "others.\n"));
346 : : return EINVAL;
347 : : }
348 : : }
349 : : } else {
350 [ # # ][ # # ]: 0 : if (parent_stat->st_uid != 0 || parent_stat->st_gid != 0) {
351 [ # # ][ # # ]: 0 : DEBUG(1, ("Public directory cannot be created below a user "
[ # # ][ # # ]
[ # # ]
352 : : "directory.\n"));
353 : : return EINVAL;
354 : : }
355 : :
356 [ # # ]: 0 : if (!(parent_stat->st_mode & S_IXOTH)) {
357 [ # # ][ # # ]: 2 : DEBUG(1, ("Parent directory does have the search bit set for "
[ # # ][ # # ]
[ # # ]
358 : : "others.\n"));
359 : : return EINVAL;
360 : : }
361 : : }
362 : :
363 : : return EOK;
364 : : }
365 : :
366 : : struct string_list {
367 : : struct string_list *next;
368 : : struct string_list *prev;
369 : : char *s;
370 : : };
371 : :
372 : 4 : static errno_t find_ccdir_parent_data(TALLOC_CTX *mem_ctx,
373 : : const char *ccdirname,
374 : : struct stat *parent_stat,
375 : : struct string_list **missing_parents)
376 : : {
377 : 4 : int ret = EFAULT;
378 : 4 : char *parent = NULL;
379 : : char *end;
380 : : struct string_list *li;
381 : :
382 : 4 : ret = stat(ccdirname, parent_stat);
383 [ + + ]: 4 : if (ret == EOK) {
384 [ - + ]: 2 : if ( !S_ISDIR(parent_stat->st_mode) ) {
385 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_MINOR_FAILURE,
[ # # ][ # # ]
[ # # ]
386 : : ("[%s] is not a directory.\n", ccdirname));
387 : : return EINVAL;
388 : : }
389 : : return EOK;
390 : : } else {
391 [ - + ]: 2 : if (errno != ENOENT) {
392 : 0 : ret = errno;
393 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_MINOR_FAILURE,
[ # # ][ # # ]
[ # # ]
394 : : ("stat for [%s] failed: [%d][%s].\n", ccdirname, ret,
395 : : strerror(ret)));
396 : 0 : return ret;
397 : : }
398 : : }
399 : :
400 : 2 : li = talloc_zero(mem_ctx, struct string_list);
401 [ - + ]: 2 : if (li == NULL) {
402 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE,
[ # # ][ # # ]
[ # # ]
403 : : ("talloc_zero failed.\n"));
404 : : return ENOMEM;
405 : : }
406 : :
407 : 2 : li->s = talloc_strdup(li, ccdirname);
408 [ - + ]: 2 : if (li->s == NULL) {
409 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE,
[ # # ][ # # ]
[ # # ]
410 : : ("talloc_strdup failed.\n"));
411 : : return ENOMEM;
412 : : }
413 : :
414 [ + - ]: 2 : DLIST_ADD(*missing_parents, li);
415 : :
416 : 2 : parent = talloc_strdup(mem_ctx, ccdirname);
417 [ - + ]: 2 : if (parent == NULL) {
418 [ # # ][ # # ]: 2 : DEBUG(SSSDBG_CRIT_FAILURE,
[ # # ][ # # ]
[ # # ]
419 : : ("talloc_strdup failed.\n"));
420 : : return ENOMEM;
421 : : }
422 : :
423 : : /* We'll remove all trailing slashes from the back so that
424 : : * we only pass /some/path to find_ccdir_parent_data, not
425 : : * /some/path */
426 : : do {
427 : 2 : end = strrchr(parent, '/');
428 [ - + ]: 2 : if (end == NULL || end == parent) {
429 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_MINOR_FAILURE,
[ # # ][ # # ]
[ # # ]
430 : : ("Cannot find parent directory of [%s], / is not allowed.\n",
431 : : ccdirname));
432 : : ret = EINVAL;
433 : : goto done;
434 : : }
435 : 2 : *end = '\0';
436 [ - + ]: 2 : } while (*(end+1) == '\0');
437 : :
438 : 2 : ret = find_ccdir_parent_data(mem_ctx, parent, parent_stat, missing_parents);
439 : :
440 : : done:
441 : 2 : talloc_free(parent);
442 : 4 : return ret;
443 : : }
444 : :
445 : : static errno_t
446 : 5 : check_ccache_re(const char *filename, pcre *illegal_re)
447 : : {
448 : : errno_t ret;
449 : :
450 : 5 : ret = pcre_exec(illegal_re, NULL, filename, strlen(filename),
451 : : 0, 0, NULL, 0);
452 [ + + ]: 5 : if (ret == 0) {
453 [ + - ][ + - ]: 3 : DEBUG(SSSDBG_OP_FAILURE,
[ - + ][ # # ]
[ # # ]
454 : : ("Illegal pattern in ccache directory name [%s].\n", filename));
455 : : return EINVAL;
456 [ + - ]: 2 : } else if (ret == PCRE_ERROR_NOMATCH) {
457 [ + - ][ + - ]: 2 : DEBUG(SSSDBG_TRACE_LIBS,
[ - + ][ # # ]
[ # # ]
458 : : ("Ccache directory name [%s] does not contain "
459 : : "illegal patterns.\n", filename));
460 : : return EOK;
461 : : }
462 : :
463 [ # # ][ # # ]: 5 : DEBUG(SSSDBG_CRIT_FAILURE, ("pcre_exec failed [%d].\n", ret));
[ # # ][ # # ]
[ # # ]
464 : : return EFAULT;
465 : : }
466 : :
467 : : errno_t
468 : 6 : create_ccache_dir(const char *ccdirname, pcre *illegal_re,
469 : : uid_t uid, gid_t gid, bool private_path)
470 : : {
471 : 6 : int ret = EFAULT;
472 : : struct stat parent_stat;
473 : 6 : struct string_list *missing_parents = NULL;
474 : 6 : struct string_list *li = NULL;
475 : : mode_t old_umask;
476 : : mode_t new_dir_mode;
477 : 6 : TALLOC_CTX *tmp_ctx = NULL;
478 : :
479 : 6 : tmp_ctx = talloc_new(NULL);
480 [ - + ]: 6 : if (tmp_ctx == NULL) {
481 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE,
[ # # ][ # # ]
[ # # ]
482 : : ("talloc_new failed.\n"));
483 : : return ENOMEM;
484 : : }
485 : :
486 [ + + ]: 6 : if (*ccdirname != '/') {
487 [ + - ][ + - ]: 1 : DEBUG(SSSDBG_MINOR_FAILURE,
[ - + ][ # # ]
[ # # ]
488 : : ("Only absolute paths are allowed, not [%s] .\n", ccdirname));
489 : : ret = EINVAL;
490 : : goto done;
491 : : }
492 : :
493 [ + - ]: 5 : if (illegal_re != NULL) {
494 : 5 : ret = check_ccache_re(ccdirname, illegal_re);
495 [ + + ]: 5 : if (ret != EOK) {
496 : : goto done;
497 : : }
498 : : }
499 : :
500 : 2 : ret = find_ccdir_parent_data(tmp_ctx, ccdirname, &parent_stat,
501 : : &missing_parents);
502 [ - + ]: 2 : if (ret != EOK) {
503 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_MINOR_FAILURE,
[ # # ][ # # ]
[ # # ]
504 : : ("find_ccdir_parent_data failed.\n"));
505 : : goto done;
506 : : }
507 : :
508 : 2 : ret = check_parent_stat(private_path, &parent_stat, uid, gid);
509 [ - + ]: 2 : if (ret != EOK) {
510 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_MINOR_FAILURE,
[ # # ][ # # ]
[ # # ][ # # ]
511 : : ("check_parent_stat failed for %s directory [%s].\n",
512 : : private_path ? "private" : "public", ccdirname));
513 : : goto done;
514 : : }
515 : :
516 [ + + ]: 4 : DLIST_FOR_EACH(li, missing_parents) {
517 [ + - ][ + - ]: 2 : DEBUG(SSSDBG_TRACE_INTERNAL,
[ - + ][ # # ]
[ # # ]
518 : : ("Creating directory [%s].\n", li->s));
519 [ + - ]: 2 : if (li->next == NULL) {
520 [ - + ]: 2 : new_dir_mode = private_path ? 0700 : 01777;
521 : : } else {
522 [ # # ][ # # ]: 0 : if (private_path &&
523 [ # # ]: 0 : parent_stat.st_uid == uid && parent_stat.st_gid == gid) {
524 : : new_dir_mode = 0700;
525 : : } else {
526 : 0 : new_dir_mode = 0755;
527 : : }
528 : : }
529 : :
530 : 2 : old_umask = umask(0000);
531 : 2 : ret = mkdir(li->s, new_dir_mode);
532 : 2 : umask(old_umask);
533 [ - + ]: 2 : if (ret != EOK) {
534 : 0 : ret = errno;
535 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_MINOR_FAILURE,
[ # # ][ # # ]
[ # # ]
536 : : ("mkdir [%s] failed: [%d][%s].\n", li->s, ret,
537 : : strerror(ret)));
538 : : goto done;
539 : : }
540 [ + - ][ + - ]: 2 : if (private_path &&
541 [ - + ][ # # ]: 2 : ((parent_stat.st_uid == uid && parent_stat.st_gid == gid) ||
542 : 0 : li->next == NULL)) {
543 : 2 : ret = chown(li->s, uid, gid);
544 [ - + ]: 2 : if (ret != EOK) {
545 : 0 : ret = errno;
546 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_MINOR_FAILURE,
[ # # ][ # # ]
[ # # ]
547 : : ("chown failed [%d][%s].\n", ret, strerror(ret)));
548 : : goto done;
549 : : }
550 : : }
551 : : }
552 : :
553 : : ret = EOK;
554 : :
555 : : done:
556 : 6 : talloc_free(tmp_ctx);
557 : : return ret;
558 : : }
559 : :
560 : 0 : errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
561 : : struct tgt_times *tgtt)
562 : : {
563 : : krb5_error_code kerr;
564 : 0 : krb5_context ctx = NULL;
565 : 0 : krb5_ccache cc = NULL;
566 : 0 : krb5_principal client_princ = NULL;
567 : 0 : krb5_principal server_princ = NULL;
568 : : char *server_name;
569 : : krb5_creds mcred;
570 : : krb5_creds cred;
571 : : const char *realm_name;
572 : : int realm_length;
573 : :
574 : 0 : kerr = krb5_init_context(&ctx);
575 [ # # ]: 0 : if (kerr != 0) {
576 [ # # ][ # # ]: 0 : DEBUG(1, ("krb5_init_context failed.\n"));
[ # # ][ # # ]
[ # # ]
577 : : goto done;
578 : : }
579 : :
580 : 0 : kerr = krb5_parse_name(ctx, client_name, &client_princ);
581 [ # # ]: 0 : if (kerr != 0) {
582 [ # # ][ # # ]: 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
[ # # ][ # # ]
[ # # ]
583 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_parse_name failed.\n"));
[ # # ][ # # ]
[ # # ]
584 : : goto done;
585 : : }
586 : :
587 : 0 : sss_krb5_princ_realm(ctx, client_princ, &realm_name, &realm_length);
588 : :
589 : 0 : server_name = talloc_asprintf(NULL, "krbtgt/%.*s@%.*s",
590 : : realm_length, realm_name,
591 : : realm_length, realm_name);
592 [ # # ]: 0 : if (server_name == NULL) {
593 : 0 : kerr = KRB5_CC_NOMEM;
594 [ # # ][ # # ]: 0 : DEBUG(1, ("talloc_asprintf failed.\n"));
[ # # ][ # # ]
[ # # ]
595 : : goto done;
596 : : }
597 : :
598 : 0 : kerr = krb5_parse_name(ctx, server_name, &server_princ);
599 : 0 : talloc_free(server_name);
600 [ # # ]: 0 : if (kerr != 0) {
601 [ # # ][ # # ]: 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
[ # # ][ # # ]
[ # # ]
602 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_parse_name failed.\n"));
[ # # ][ # # ]
[ # # ]
603 : : goto done;
604 : : }
605 : :
606 : 0 : kerr = krb5_cc_resolve(ctx, ccache_file, &cc);
607 [ # # ]: 0 : if (kerr != 0) {
608 [ # # ][ # # ]: 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
[ # # ][ # # ]
[ # # ]
609 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_resolve failed.\n"));
[ # # ][ # # ]
[ # # ]
610 : : goto done;
611 : : }
612 : :
613 : 0 : memset(&mcred, 0, sizeof(mcred));
614 : 0 : memset(&cred, 0, sizeof(mcred));
615 : :
616 : 0 : mcred.server = server_princ;
617 : 0 : mcred.client = client_princ;
618 : :
619 : 0 : kerr = krb5_cc_retrieve_cred(ctx, cc, 0, &mcred, &cred);
620 [ # # ]: 0 : if (kerr != 0) {
621 [ # # ][ # # ]: 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
[ # # ][ # # ]
[ # # ]
622 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_retrieve_cred failed.\n"));
[ # # ][ # # ]
[ # # ]
623 : : goto done;
624 : : }
625 : :
626 : 0 : tgtt->authtime = cred.times.authtime;
627 : 0 : tgtt->starttime = cred.times.starttime;
628 : 0 : tgtt->endtime = cred.times.endtime;
629 : 0 : tgtt->renew_till = cred.times.renew_till;
630 : :
631 : 0 : krb5_free_cred_contents(ctx, &cred);
632 : :
633 : 0 : kerr = krb5_cc_close(ctx, cc);
634 [ # # ]: 0 : if (kerr != 0) {
635 [ # # ][ # # ]: 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
[ # # ][ # # ]
[ # # ]
636 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_close failed.\n"));
[ # # ][ # # ]
[ # # ]
637 : : goto done;
638 : : }
639 : 0 : cc = NULL;
640 : :
641 : 0 : kerr = 0;
642 : :
643 : : done:
644 [ # # ]: 0 : if (cc != NULL) {
645 : 0 : krb5_cc_close(ctx, cc);
646 : : }
647 : :
648 [ # # ]: 0 : if (client_princ != NULL) {
649 : 0 : krb5_free_principal(ctx, client_princ);
650 : : }
651 : :
652 [ # # ]: 0 : if (server_princ != NULL) {
653 : 0 : krb5_free_principal(ctx, server_princ);
654 : : }
655 : :
656 [ # # ]: 0 : if (ctx != NULL) {
657 : 0 : krb5_free_context(ctx);
658 : : }
659 : :
660 [ # # ]: 0 : if (kerr != 0) {
661 : : return EIO;
662 : : }
663 : :
664 : : return EOK;
665 : : }
666 : :
667 : : static errno_t
668 : 2 : create_ccache_dir_head(const char *parent, pcre *illegal_re,
669 : : uid_t uid, gid_t gid, bool private_path)
670 : : {
671 : : char *ccdirname;
672 : 2 : TALLOC_CTX *tmp_ctx = NULL;
673 : : char *end;
674 : : errno_t ret;
675 : :
676 : 2 : tmp_ctx = talloc_new(NULL);
677 [ + - ]: 2 : if (!tmp_ctx) return ENOMEM;
678 : :
679 : 2 : ccdirname = talloc_strdup(tmp_ctx, parent);
680 [ - + ]: 2 : if (ccdirname == NULL) {
681 [ # # ][ # # ]: 2 : DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_strdup failed.\n"));
[ # # ][ # # ]
[ # # ]
682 : : ret = ENOMEM;
683 : : goto done;
684 : : }
685 : :
686 : : /* We'll remove all trailing slashes from the back so that
687 : : * we only pass /some/path to find_ccdir_parent_data, not
688 : : * /some/path/ */
689 : : do {
690 : 3 : end = strrchr(ccdirname, '/');
691 [ - + ]: 3 : if (end == NULL || end == ccdirname) {
692 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot find parent directory of [%s], "
[ # # ][ # # ]
[ # # ]
693 : : "/ is not allowed.\n", ccdirname));
694 : : ret = EINVAL;
695 : : goto done;
696 : : }
697 : 3 : *end = '\0';
698 [ + + ]: 3 : } while (*(end+1) == '\0');
699 : :
700 : 2 : ret = create_ccache_dir(ccdirname, illegal_re, uid, gid, private_path);
701 : : done:
702 : 2 : talloc_free(tmp_ctx);
703 : 2 : return ret;
704 : : }
705 : :
706 : : /*======== ccache back end utilities ========*/
707 : : struct sss_krb5_cc_be *
708 : 0 : get_cc_be_ops(enum sss_krb5_cc_type type)
709 : : {
710 [ # # ][ # # ]: 0 : struct sss_krb5_cc_be *be = NULL;
711 : :
712 : : switch (type) {
713 : : case SSS_KRB5_TYPE_FILE:
714 : : be = &file_cc;
715 : : break;
716 : :
717 : : #ifdef HAVE_KRB5_DIRCACHE
718 : : case SSS_KRB5_TYPE_DIR:
719 : : be = &dir_cc;
720 : : break;
721 : : #endif /* HAVE_KRB5_DIRCACHE */
722 : :
723 : : case SSS_KRB5_TYPE_UNKNOWN:
724 : : be = NULL;
725 : : break;
726 : : }
727 : :
728 : 0 : return be;
729 : : }
730 : :
731 : : struct sss_krb5_cc_be *
732 : 0 : get_cc_be_ops_ccache(const char *ccache)
733 : : {
734 : : enum sss_krb5_cc_type type;
735 : :
736 : 0 : type = sss_krb5_get_type(ccache);
737 : 0 : return get_cc_be_ops(type);
738 : : }
739 : :
740 : : /*======== Operations on the FILE: back end ========*/
741 : : errno_t
742 : 0 : cc_file_create(const char *location, pcre *illegal_re,
743 : : uid_t uid, gid_t gid, bool private_path)
744 : : {
745 : : const char *filename;
746 : :
747 : 0 : filename = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_FILE);
748 [ # # ]: 0 : if (filename == NULL) {
749 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("Bad ccache type %s\n", location));
[ # # ][ # # ]
[ # # ]
750 : : return EINVAL;
751 : : }
752 : :
753 : 0 : return create_ccache_dir_head(filename, illegal_re, uid, gid, private_path);
754 : : }
755 : :
756 : : static errno_t
757 : 0 : cc_residual_is_used(uid_t uid, const char *ccname,
758 : : enum sss_krb5_cc_type type, bool *result)
759 : : {
760 : : int ret;
761 : : struct stat stat_buf;
762 : : bool active;
763 : :
764 : 0 : *result = false;
765 : :
766 [ # # ][ # # ]: 0 : if (ccname == NULL || *ccname == '\0') {
767 : : return EINVAL;
768 : : }
769 : :
770 : 0 : ret = lstat(ccname, &stat_buf);
771 : :
772 [ # # ][ # # ]: 0 : if (ret == -1 && errno != ENOENT) {
773 : 0 : ret = errno;
774 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE,
[ # # ][ # # ]
[ # # ]
775 : : ("stat failed [%d][%s].\n", ret, strerror(ret)));
776 : : return ret;
777 [ # # ]: 0 : } else if (ret == EOK) {
778 [ # # ]: 0 : if (stat_buf.st_uid != uid) {
779 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE,
[ # # ][ # # ]
[ # # ]
780 : : ("Cache file [%s] exists, but is owned by [%d] instead of "
781 : : "[%d].\n", ccname, stat_buf.st_uid, uid));
782 : : return EINVAL;
783 : : }
784 : :
785 [ # # # ]: 0 : switch (type) {
786 : : #ifdef HAVE_KRB5_DIRCACHE
787 : : case SSS_KRB5_TYPE_DIR:
788 : 0 : ret = S_ISDIR(stat_buf.st_mode);
789 : 0 : break;
790 : : #endif /* HAVE_KRB5_DIRCACHE */
791 : : case SSS_KRB5_TYPE_FILE:
792 : 0 : ret = S_ISREG(stat_buf.st_mode);
793 : 0 : break;
794 : : default:
795 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("Unsupported ccache type\n"));
[ # # ][ # # ]
[ # # ]
796 : : return EINVAL;
797 : : }
798 : :
799 [ # # ]: 0 : if (ret == 0) {
800 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE,
[ # # ][ # # ]
[ # # ]
801 : : ("Cache file [%s] exists, but is not the expected type\n",
802 : : ccname));
803 : : return EINVAL;
804 : : }
805 : : }
806 : :
807 : 0 : ret = check_if_uid_is_active(uid, &active);
808 [ # # ]: 0 : if (ret != EOK) {
809 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("check_if_uid_is_active failed.\n"));
[ # # ][ # # ]
[ # # ]
810 : : return ret;
811 : : }
812 : :
813 [ # # ]: 0 : if (!active) {
814 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_TRACE_FUNC, ("User [%d] is not active\n", uid));
[ # # ][ # # ]
[ # # ]
815 : : } else {
816 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_TRACE_LIBS,
[ # # ][ # # ]
[ # # ]
817 : : ("User [%d] is still active, reusing ccache [%s].\n",
818 : : uid, ccname));
819 : 0 : *result = true;
820 : : }
821 : : return EOK;
822 : : }
823 : :
824 : : static void
825 : 0 : cc_check_template(const char *cc_template)
826 : : {
827 : : size_t template_len;
828 : :
829 : 0 : template_len = strlen(cc_template);
830 [ # # ][ # # ]: 0 : if (template_len >= 6 &&
831 : 0 : strcmp(cc_template + (template_len - 6), "XXXXXX") != 0) {
832 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CONF_SETTINGS, ("ccache file name template [%s] doesn't "
[ # # ][ # # ]
[ # # ]
833 : : "contain randomizing characters (XXXXXX), file might not "
834 : : "be rewritable\n", cc_template));
835 : : }
836 : 0 : }
837 : :
838 : : errno_t
839 : 0 : cc_file_check_existing(const char *location, uid_t uid,
840 : : const char *realm, const char *princ,
841 : : const char *cc_template, bool *_active, bool *_valid)
842 : : {
843 : : errno_t ret;
844 : : bool active;
845 : : bool valid;
846 : : const char *filename;
847 : 0 : krb5_ccache ccache = NULL;
848 : 0 : krb5_context context = NULL;
849 : : krb5_error_code kerr;
850 : :
851 : 0 : filename = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_FILE);
852 [ # # ]: 0 : if (!filename) {
853 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type FILE:\n"));
[ # # ][ # # ]
[ # # ]
854 : : return EINVAL;
855 : : }
856 : :
857 [ # # ]: 0 : if (filename[0] != '/') {
858 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("Only absolute path names are allowed.\n"));
[ # # ][ # # ]
[ # # ]
859 : : return EINVAL;
860 : : }
861 : :
862 : 0 : ret = cc_residual_is_used(uid, filename, SSS_KRB5_TYPE_FILE, &active);
863 [ # # ]: 0 : if (ret != EOK) {
864 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("Could not check if ccache is active. "
[ # # ][ # # ]
[ # # ]
865 : : "Will create a new one.\n"));
866 : 0 : cc_check_template(cc_template);
867 : 0 : active = false;
868 : : }
869 : :
870 : 0 : kerr = krb5_init_context(&context);
871 [ # # ]: 0 : if (kerr != 0) {
872 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to init kerberos context\n"));
[ # # ][ # # ]
[ # # ]
873 : : return EIO;
874 : : }
875 : :
876 : 0 : kerr = krb5_cc_resolve(context, location, &ccache);
877 [ # # ]: 0 : if (kerr != 0) {
878 [ # # ][ # # ]: 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, context, kerr);
[ # # ][ # # ]
[ # # ]
879 : 0 : krb5_free_context(context);
880 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_resolve failed.\n"));
[ # # ][ # # ]
[ # # ]
881 : : return EIO;
882 : : }
883 : :
884 : 0 : kerr = check_for_valid_tgt(context, ccache, realm, princ, &valid);
885 : 0 : krb5_free_context(context);
886 : 0 : krb5_cc_close(context, ccache);
887 [ # # ]: 0 : if (kerr != EOK) {
888 [ # # ][ # # ]: 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, context, kerr);
[ # # ][ # # ]
[ # # ]
889 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE,
[ # # ][ # # ]
[ # # ]
890 : : ("Could not check if ccache contains a valid principal\n"));
891 : : return EIO;
892 : : }
893 : :
894 : 0 : *_active = active;
895 : 0 : *_valid = valid;
896 : : return EOK;
897 : : }
898 : :
899 : : const char *
900 : 0 : cc_file_cache_for_princ(TALLOC_CTX *mem_ctx, const char *location,
901 : : const char *princ)
902 : : {
903 : 0 : return talloc_strdup(mem_ctx, location);
904 : : }
905 : :
906 : : errno_t
907 : 0 : cc_file_remove(const char *location)
908 : : {
909 : : errno_t ret;
910 : : const char *filename;
911 : :
912 : 0 : filename = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_FILE);
913 [ # # ]: 0 : if (!filename) {
914 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type FILE:\n"));
[ # # ][ # # ]
[ # # ]
915 : : return EINVAL;
916 : : }
917 : :
918 [ # # ]: 0 : if (filename[0] != '/') {
919 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE,
[ # # ][ # # ]
[ # # ]
920 : : ("Ccache file name [%s] is not an absolute path.\n", filename));
921 : : return EINVAL;
922 : : }
923 : :
924 : 0 : errno = 0;
925 : 0 : ret = unlink(filename);
926 [ # # ][ # # ]: 0 : if (ret == -1 && errno != ENOENT) {
927 : 0 : ret = errno;
928 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE,
[ # # ][ # # ]
[ # # ]
929 : : ("unlink [%s] failed [%d][%s].\n", filename, ret,
930 : : strerror(ret)));
931 : 0 : return ret;
932 : : }
933 : : return EOK;
934 : : }
935 : :
936 : : struct sss_krb5_cc_be file_cc = {
937 : : .type = SSS_KRB5_TYPE_FILE,
938 : : .create = cc_file_create,
939 : : .check_existing = cc_file_check_existing,
940 : : .ccache_for_princ = cc_file_cache_for_princ,
941 : : .remove = cc_file_remove,
942 : : };
943 : :
944 : : #ifdef HAVE_KRB5_DIRCACHE
945 : : /*======== Operations on the DIR: back end ========*/
946 : : errno_t
947 : 2 : cc_dir_create(const char *location, pcre *illegal_re,
948 : : uid_t uid, gid_t gid, bool private_path)
949 : : {
950 : : const char *dir_name;
951 : :
952 : 2 : dir_name = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_DIR);
953 [ - + ]: 2 : if (dir_name == NULL) {
954 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("Bad residual type\n"));
[ # # ][ # # ]
[ # # ]
955 : : return EINVAL;
956 : : }
957 : :
958 : 2 : return create_ccache_dir_head(dir_name, illegal_re, uid, gid, private_path);
959 : : }
960 : :
961 : : static krb5_error_code
962 : 0 : get_ccache_for_princ(krb5_context context, const char *location,
963 : : const char *princ, krb5_ccache *_ccache)
964 : : {
965 : : krb5_error_code krberr;
966 : 0 : krb5_principal client_principal = NULL;
967 : :
968 : 0 : krberr = krb5_cc_set_default_name(context, location);
969 [ # # ]: 0 : if (krberr != 0) {
970 [ # # ][ # # ]: 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
[ # # ][ # # ]
[ # # ]
971 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_resolve failed.\n"));
[ # # ][ # # ]
[ # # ]
972 : : return krberr;
973 : : }
974 : :
975 : 0 : krberr = krb5_parse_name(context, princ, &client_principal);
976 [ # # ]: 0 : if (krberr != 0) {
977 [ # # ][ # # ]: 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
[ # # ][ # # ]
[ # # ]
978 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_parse_name failed.\n"));
[ # # ][ # # ]
[ # # ]
979 : : return krberr;
980 : : }
981 : :
982 : 0 : krberr = krb5_cc_cache_match(context, client_principal, _ccache);
983 : 0 : krb5_free_principal(context, client_principal);
984 : : return krberr;
985 : : }
986 : :
987 : : errno_t
988 : 0 : cc_dir_check_existing(const char *location, uid_t uid,
989 : : const char *realm, const char *princ,
990 : : const char *cc_template, bool *_active, bool *_valid)
991 : : {
992 : 0 : bool active = false;
993 : 0 : bool valid = false;
994 : 0 : krb5_ccache ccache = NULL;
995 : 0 : krb5_context context = NULL;
996 : : krb5_error_code krberr;
997 : : enum sss_krb5_cc_type type;
998 : : const char *filename;
999 : : const char *dir;
1000 : : char *tmp;
1001 : : errno_t ret;
1002 : :
1003 : 0 : type = sss_krb5_get_type(location);
1004 [ # # ]: 0 : if (type != SSS_KRB5_TYPE_DIR) {
1005 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type DIR:\n", location));
[ # # ][ # # ]
[ # # ]
1006 : : return EINVAL;
1007 : : }
1008 : :
1009 : 0 : filename = sss_krb5_cc_file_path(location);
1010 [ # # ]: 0 : if (!filename) {
1011 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE,
[ # # ][ # # ]
[ # # ]
1012 : : ("Existing ccname does not contain path into the collection"));
1013 : : return EINVAL;
1014 : : }
1015 : :
1016 [ # # ]: 0 : if (filename[0] != '/') {
1017 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE,
[ # # ][ # # ]
[ # # ]
1018 : : ("Only absolute path names are allowed.\n"));
1019 : : return EINVAL;
1020 : : }
1021 : :
1022 : 0 : tmp = talloc_strdup(NULL, filename);
1023 [ # # ]: 0 : if (!tmp) return ENOMEM;
1024 : :
1025 : 0 : dir = dirname(tmp);
1026 [ # # ]: 0 : if (!dir) {
1027 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE,
[ # # ][ # # ]
[ # # ]
1028 : : ("Cannot base get directory of %s\n", location));
1029 : : return EINVAL;
1030 : : }
1031 : :
1032 : 0 : ret = cc_residual_is_used(uid, dir, SSS_KRB5_TYPE_DIR, &active);
1033 : 0 : talloc_free(tmp);
1034 [ # # ]: 0 : if (ret != EOK) {
1035 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("Could not check if ccache is active. "
[ # # ][ # # ]
[ # # ]
1036 : : "Will create a new one.\n"));
1037 : 0 : cc_check_template(cc_template);
1038 : 0 : active = false;
1039 : : }
1040 : :
1041 : 0 : krberr = krb5_init_context(&context);
1042 [ # # ]: 0 : if (krberr) {
1043 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to init kerberos context\n"));
[ # # ][ # # ]
[ # # ]
1044 : : return EIO;
1045 : : }
1046 : :
1047 : 0 : krberr = krb5_cc_resolve(context, location, &ccache);
1048 [ # # ][ # # ]: 0 : if (krberr == KRB5_FCC_NOFILE || ccache == NULL) {
1049 : : /* KRB5_FCC_NOFILE would be returned if the directory components
1050 : : * of the DIR cache do not exist, which is the case in /run
1051 : : * after a reboot
1052 : : */
1053 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_TRACE_FUNC,
[ # # ][ # # ]
[ # # ]
1054 : : ("ccache %s is missing or empty\n", location));
1055 : 0 : valid = false;
1056 : 0 : ret = EOK;
1057 : 0 : goto done;
1058 [ # # ]: 0 : } else if (krberr != 0) {
1059 [ # # ][ # # ]: 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
[ # # ][ # # ]
[ # # ]
1060 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_cc_resolve failed.\n"));
[ # # ][ # # ]
[ # # ]
1061 : : ret = EIO;
1062 : : goto done;
1063 : : }
1064 : :
1065 : 0 : krberr = check_for_valid_tgt(context, ccache, realm, princ, &valid);
1066 [ # # ]: 0 : if (krberr != EOK) {
1067 [ # # ][ # # ]: 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
[ # # ][ # # ]
[ # # ]
1068 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE,
[ # # ][ # # ]
[ # # ]
1069 : : ("Could not check if ccache contains a valid principal\n"));
1070 : : ret = EIO;
1071 : : goto done;
1072 : : }
1073 : :
1074 : : ret = EOK;
1075 : : done:
1076 [ # # ]: 0 : if (ccache) krb5_cc_close(context, ccache);
1077 : 0 : krb5_free_context(context);
1078 : 0 : *_active = active;
1079 : 0 : *_valid = valid;
1080 : : return ret;
1081 : : }
1082 : :
1083 : : const char *
1084 : 0 : cc_dir_cache_for_princ(TALLOC_CTX *mem_ctx, const char *location,
1085 : : const char *princ)
1086 : : {
1087 : 0 : krb5_context context = NULL;
1088 : : krb5_error_code krberr;
1089 : 0 : krb5_ccache ccache = NULL;
1090 : : char *name;
1091 : : const char *ccname;
1092 : :
1093 : 0 : ccname = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_DIR);
1094 [ # # ]: 0 : if (!ccname) {
1095 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot get ccname file from %s\n",
[ # # ][ # # ]
[ # # ]
1096 : : location));
1097 : : return NULL;
1098 : : }
1099 : :
1100 : : /* ccname already points to a subsidiary cache */
1101 [ # # ][ # # ]: 0 : if (ccname[0] == ':' && ccname[1] && ccname[1] == '/') {
[ # # ]
1102 : 0 : return talloc_strdup(mem_ctx, location);
1103 : : }
1104 : :
1105 : 0 : krberr = krb5_init_context(&context);
1106 [ # # ]: 0 : if (krberr) {
1107 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("Failed to init kerberos context\n"));
[ # # ][ # # ]
[ # # ]
1108 : : return NULL;
1109 : : }
1110 : :
1111 : 0 : krberr = get_ccache_for_princ(context, location, princ, &ccache);
1112 [ # # ]: 0 : if (krberr) {
1113 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_TRACE_FUNC, ("No principal for %s in %s\n",
[ # # ][ # # ]
[ # # ]
1114 : : princ, location));
1115 : 0 : krb5_free_context(context);
1116 : : return NULL;
1117 : : }
1118 : :
1119 : 0 : krberr = krb5_cc_get_full_name(context, ccache, &name);
1120 [ # # ]: 0 : if (ccache) krb5_cc_close(context, ccache);
1121 : 0 : krb5_free_context(context);
1122 [ # # ]: 0 : if (krberr) {
1123 [ # # ][ # # ]: 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
[ # # ][ # # ]
[ # # ]
1124 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("Could not get full name of ccache\n"));
[ # # ][ # # ]
[ # # ]
1125 : : return NULL;
1126 : : }
1127 : :
1128 : 0 : return talloc_strdup(mem_ctx, name);
1129 : : }
1130 : :
1131 : : errno_t
1132 : 0 : cc_dir_remove(const char *location)
1133 : : {
1134 : : const char *subsidiary;
1135 : :
1136 [ # # ]: 0 : if (sss_krb5_get_type(location) != SSS_KRB5_TYPE_DIR) {
1137 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("%s is not of type DIR\n", location));
[ # # ][ # # ]
[ # # ]
1138 : : return EINVAL;
1139 : : }
1140 : :
1141 : 0 : subsidiary = sss_krb5_cc_file_path(location);
1142 [ # # ]: 0 : if (!subsidiary) {
1143 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot get subsidiary cache from %s\n",
[ # # ][ # # ]
[ # # ]
1144 : : location));
1145 : : return EINVAL;
1146 : : }
1147 : :
1148 : 0 : return cc_file_remove(subsidiary);
1149 : : }
1150 : :
1151 : : struct sss_krb5_cc_be dir_cc = {
1152 : : .type = SSS_KRB5_TYPE_DIR,
1153 : : .create = cc_dir_create,
1154 : : .check_existing = cc_dir_check_existing,
1155 : : .ccache_for_princ = cc_dir_cache_for_princ,
1156 : : .remove = cc_dir_remove
1157 : : };
1158 : :
1159 : : #endif /* HAVE_KRB5_DIRCACHE */
1160 : :
1161 : 0 : errno_t get_domain_or_subdomain(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx,
1162 : : char *domain_name,
1163 : : struct sss_domain_info **dom)
1164 : : {
1165 : :
1166 [ # # ][ # # ]: 0 : if (domain_name != NULL &&
1167 : 0 : strcasecmp(domain_name, be_ctx->domain->name) != 0) {
1168 : 0 : *dom = new_subdomain(mem_ctx, be_ctx->domain, domain_name, NULL, NULL);
1169 [ # # ]: 0 : if (*dom == NULL) {
1170 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("new_subdomain failed.\n"));
[ # # ][ # # ]
[ # # ]
1171 : : return ENOMEM;
1172 : : }
1173 : : } else {
1174 : 0 : *dom = be_ctx->domain;
1175 : : }
1176 : :
1177 : : return EOK;
1178 : : }
|