Line data Source code
1 : /*
2 : SSSD
3 :
4 : LDAP Backend Module -- prime ccache with TGT in a child process
5 :
6 : Authors:
7 : Jakub Hrozek <jhrozek@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 :
25 : #include <sys/types.h>
26 : #include <unistd.h>
27 : #include <sys/stat.h>
28 : #include <popt.h>
29 :
30 : #include "util/util.h"
31 : #include "util/sss_krb5.h"
32 : #include "util/child_common.h"
33 : #include "providers/dp_backend.h"
34 : #include "providers/krb5/krb5_common.h"
35 :
36 : static krb5_context krb5_error_ctx;
37 : #define LDAP_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error)
38 :
39 : static const char *__ldap_child_krb5_error_msg;
40 : #define KRB5_SYSLOG(krb5_error) do { \
41 : __ldap_child_krb5_error_msg = sss_krb5_get_error_message(krb5_error_ctx, krb5_error); \
42 : sss_log(SSS_LOG_ERR, "%s", __ldap_child_krb5_error_msg); \
43 : sss_krb5_free_error_message(krb5_error_ctx, __ldap_child_krb5_error_msg); \
44 : } while(0)
45 :
46 : struct input_buffer {
47 : const char *realm_str;
48 : const char *princ_str;
49 : char *keytab_name;
50 : krb5_deltat lifetime;
51 : krb5_context context;
52 : uid_t uid;
53 : gid_t gid;
54 : };
55 :
56 0 : static errno_t unpack_buffer(uint8_t *buf, size_t size,
57 : struct input_buffer *ibuf)
58 : {
59 0 : size_t p = 0;
60 : uint32_t len;
61 :
62 0 : DEBUG(SSSDBG_TRACE_LIBS, "total buffer size: %zu\n", size);
63 :
64 : /* realm_str size and length */
65 0 : SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
66 :
67 0 : DEBUG(SSSDBG_TRACE_LIBS, "realm_str size: %d\n", len);
68 0 : if (len) {
69 0 : if (len > size - p) return EINVAL;
70 0 : ibuf->realm_str = talloc_strndup(ibuf, (char *)(buf + p), len);
71 0 : DEBUG(SSSDBG_TRACE_LIBS, "got realm_str: %s\n", ibuf->realm_str);
72 0 : if (ibuf->realm_str == NULL) return ENOMEM;
73 0 : p += len;
74 : }
75 :
76 : /* princ_str size and length */
77 0 : SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
78 :
79 0 : DEBUG(SSSDBG_TRACE_LIBS, "princ_str size: %d\n", len);
80 0 : if (len) {
81 0 : if (len > size - p) return EINVAL;
82 0 : ibuf->princ_str = talloc_strndup(ibuf, (char *)(buf + p), len);
83 0 : DEBUG(SSSDBG_TRACE_LIBS, "got princ_str: %s\n", ibuf->princ_str);
84 0 : if (ibuf->princ_str == NULL) return ENOMEM;
85 0 : p += len;
86 : }
87 :
88 : /* keytab_name size and length */
89 0 : SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
90 :
91 0 : DEBUG(SSSDBG_TRACE_LIBS, "keytab_name size: %d\n", len);
92 0 : if (len) {
93 0 : if (len > size - p) return EINVAL;
94 0 : ibuf->keytab_name = talloc_strndup(ibuf, (char *)(buf + p), len);
95 0 : DEBUG(SSSDBG_TRACE_LIBS, "got keytab_name: %s\n", ibuf->keytab_name);
96 0 : if (ibuf->keytab_name == NULL) return ENOMEM;
97 0 : p += len;
98 : }
99 :
100 : /* ticket lifetime */
101 0 : SAFEALIGN_COPY_UINT32_CHECK(&ibuf->lifetime, buf + p, size, &p);
102 0 : DEBUG(SSSDBG_TRACE_LIBS, "lifetime: %u\n", ibuf->lifetime);
103 :
104 : /* UID and GID to run as */
105 0 : SAFEALIGN_COPY_UINT32_CHECK(&ibuf->uid, buf + p, size, &p);
106 0 : SAFEALIGN_COPY_UINT32_CHECK(&ibuf->gid, buf + p, size, &p);
107 0 : DEBUG(SSSDBG_FUNC_DATA,
108 : "Will run as [%"SPRIuid"][%"SPRIgid"].\n", ibuf->uid, ibuf->gid);
109 :
110 0 : return EOK;
111 : }
112 :
113 0 : static int pack_buffer(struct response *r, int result, krb5_error_code krberr,
114 : const char *msg, time_t expire_time)
115 : {
116 : int len;
117 0 : size_t p = 0;
118 :
119 0 : len = strlen(msg);
120 0 : r->size = 2 * sizeof(uint32_t) + sizeof(krb5_error_code) +
121 0 : len + sizeof(time_t);
122 :
123 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "response size: %zu\n",r->size);
124 :
125 0 : r->buf = talloc_array(r, uint8_t, r->size);
126 0 : if(!r->buf) {
127 0 : return ENOMEM;
128 : }
129 :
130 0 : DEBUG(SSSDBG_TRACE_LIBS,
131 : "result [%d] krberr [%d] msgsize [%d] msg [%s]\n",
132 : result, krberr, len, msg);
133 :
134 : /* result */
135 0 : SAFEALIGN_SET_UINT32(&r->buf[p], result, &p);
136 :
137 : /* krb5 error code */
138 0 : safealign_memcpy(&r->buf[p], &krberr, sizeof(krberr), &p);
139 :
140 : /* message size */
141 0 : SAFEALIGN_SET_UINT32(&r->buf[p], len, &p);
142 :
143 : /* message itself */
144 0 : safealign_memcpy(&r->buf[p], msg, len, &p);
145 :
146 : /* ticket expiration time */
147 0 : safealign_memcpy(&r->buf[p], &expire_time, sizeof(expire_time), &p);
148 :
149 0 : return EOK;
150 : }
151 :
152 : static errno_t
153 0 : set_child_debugging(krb5_context ctx)
154 : {
155 : krb5_error_code kerr;
156 :
157 : /* Set the global error context */
158 0 : krb5_error_ctx = ctx;
159 :
160 0 : if (debug_level & SSSDBG_TRACE_ALL) {
161 0 : kerr = sss_child_set_krb5_tracing(ctx);
162 0 : if (kerr) {
163 0 : LDAP_CHILD_DEBUG(SSSDBG_MINOR_FAILURE, kerr);
164 0 : return EIO;
165 : }
166 : }
167 :
168 0 : return EOK;
169 : }
170 :
171 0 : static int lc_verify_keytab_ex(const char *principal,
172 : const char *keytab_name,
173 : krb5_context context,
174 : krb5_keytab keytab)
175 : {
176 : bool found;
177 : char *kt_principal;
178 : krb5_error_code krberr;
179 : krb5_kt_cursor cursor;
180 : krb5_keytab_entry entry;
181 :
182 0 : krberr = krb5_kt_start_seq_get(context, keytab, &cursor);
183 0 : if (krberr) {
184 0 : DEBUG(SSSDBG_FATAL_FAILURE,
185 : "Cannot read keytab [%s].\n", KEYTAB_CLEAN_NAME);
186 :
187 0 : sss_log(SSS_LOG_ERR, "Error reading keytab file [%s]: [%d][%s]. "
188 : "Unable to create GSSAPI-encrypted LDAP "
189 : "connection.",
190 : KEYTAB_CLEAN_NAME, krberr,
191 : sss_krb5_get_error_message(context, krberr));
192 :
193 0 : return EIO;
194 : }
195 :
196 0 : found = false;
197 0 : while ((krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) {
198 0 : krberr = krb5_unparse_name(context, entry.principal, &kt_principal);
199 0 : if (krberr) {
200 0 : DEBUG(SSSDBG_FATAL_FAILURE,
201 : "Could not parse keytab entry\n");
202 0 : sss_log(SSS_LOG_ERR, "Could not parse keytab entry\n");
203 0 : return EIO;
204 : }
205 :
206 0 : if (strcmp(principal, kt_principal) == 0) {
207 0 : found = true;
208 : }
209 0 : free(kt_principal);
210 0 : krberr = sss_krb5_free_keytab_entry_contents(context, &entry);
211 0 : if (krberr) {
212 : /* This should never happen. The API docs for this function
213 : * specify only success for this function
214 : */
215 0 : DEBUG(SSSDBG_CRIT_FAILURE,"Could not free keytab entry contents\n");
216 : /* This is non-fatal, so we'll continue here */
217 : }
218 :
219 0 : if (found) {
220 0 : break;
221 : }
222 : }
223 :
224 0 : krberr = krb5_kt_end_seq_get(context, keytab, &cursor);
225 0 : if (krberr) {
226 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Could not close keytab.\n");
227 0 : sss_log(SSS_LOG_ERR, "Could not close keytab file [%s].",
228 : KEYTAB_CLEAN_NAME);
229 0 : return EIO;
230 : }
231 :
232 0 : if (!found) {
233 0 : DEBUG(SSSDBG_FATAL_FAILURE,
234 : "Principal [%s] not found in keytab [%s]\n",
235 : principal,
236 : KEYTAB_CLEAN_NAME);
237 0 : sss_log(SSS_LOG_ERR, "Error processing keytab file [%s]: "
238 : "Principal [%s] was not found. "
239 : "Unable to create GSSAPI-encrypted LDAP connection.",
240 : KEYTAB_CLEAN_NAME, principal);
241 :
242 0 : return EFAULT;
243 : }
244 :
245 0 : return EOK;
246 : }
247 :
248 0 : static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx,
249 : krb5_context context,
250 : const char *realm_str,
251 : const char *princ_str,
252 : const char *keytab_name,
253 : const krb5_deltat lifetime,
254 : const char **ccname_out,
255 : time_t *expire_time_out)
256 : {
257 : char *ccname;
258 : char *ccname_dummy;
259 0 : char *realm_name = NULL;
260 0 : char *full_princ = NULL;
261 0 : char *default_realm = NULL;
262 0 : char *tmp_str = NULL;
263 0 : krb5_keytab keytab = NULL;
264 0 : krb5_ccache ccache = NULL;
265 : krb5_principal kprinc;
266 : krb5_creds my_creds;
267 : krb5_get_init_creds_opt options;
268 : krb5_error_code krberr;
269 : krb5_timestamp kdc_time_offset;
270 0 : int canonicalize = 0;
271 : int kdc_time_offset_usec;
272 : int ret;
273 : TALLOC_CTX *tmp_ctx;
274 0 : char *ccname_file_dummy = NULL;
275 : char *ccname_file;
276 :
277 0 : tmp_ctx = talloc_new(memctx);
278 0 : if (tmp_ctx == NULL) {
279 0 : krberr = KRB5KRB_ERR_GENERIC;
280 0 : goto done;
281 : }
282 :
283 0 : krberr = set_child_debugging(context);
284 0 : if (krberr != EOK) {
285 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set krb5_child debugging\n");
286 : }
287 :
288 0 : if (!realm_str) {
289 0 : krberr = krb5_get_default_realm(context, &default_realm);
290 0 : if (krberr) {
291 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to get default realm name: %s\n",
292 : sss_krb5_get_error_message(context, krberr));
293 0 : goto done;
294 : }
295 :
296 0 : realm_name = talloc_strdup(tmp_ctx, default_realm);
297 0 : krb5_free_default_realm(context, default_realm);
298 0 : if (!realm_name) {
299 0 : krberr = KRB5KRB_ERR_GENERIC;
300 0 : goto done;
301 : }
302 : } else {
303 0 : realm_name = talloc_strdup(tmp_ctx, realm_str);
304 0 : if (!realm_name) {
305 0 : krberr = KRB5KRB_ERR_GENERIC;
306 0 : goto done;
307 : }
308 : }
309 :
310 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "got realm_name: [%s]\n", realm_name);
311 :
312 0 : if (princ_str) {
313 0 : if (!strchr(princ_str, '@')) {
314 0 : full_princ = talloc_asprintf(tmp_ctx, "%s@%s",
315 : princ_str, realm_name);
316 : } else {
317 0 : full_princ = talloc_strdup(tmp_ctx, princ_str);
318 : }
319 : } else {
320 : char hostname[HOST_NAME_MAX + 1];
321 :
322 0 : ret = gethostname(hostname, HOST_NAME_MAX);
323 0 : if (ret == -1) {
324 0 : krberr = KRB5KRB_ERR_GENERIC;
325 0 : goto done;
326 : }
327 0 : hostname[HOST_NAME_MAX] = '\0';
328 :
329 0 : DEBUG(SSSDBG_TRACE_LIBS, "got hostname: [%s]\n", hostname);
330 :
331 0 : ret = select_principal_from_keytab(tmp_ctx, hostname, realm_name,
332 : keytab_name, &full_princ, NULL, NULL);
333 0 : if (ret) {
334 0 : krberr = KRB5_KT_IOERR;
335 0 : goto done;
336 : }
337 : }
338 0 : if (!full_princ) {
339 0 : krberr = KRB5KRB_ERR_GENERIC;
340 0 : goto done;
341 : }
342 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Principal name is: [%s]\n", full_princ);
343 :
344 0 : krberr = krb5_parse_name(context, full_princ, &kprinc);
345 0 : if (krberr) {
346 0 : DEBUG(SSSDBG_OP_FAILURE, "Unable to build principal: %s\n",
347 : sss_krb5_get_error_message(context, krberr));
348 0 : goto done;
349 : }
350 :
351 0 : if (keytab_name) {
352 0 : krberr = krb5_kt_resolve(context, keytab_name, &keytab);
353 : } else {
354 0 : krberr = krb5_kt_default(context, &keytab);
355 : }
356 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Using keytab [%s]\n", KEYTAB_CLEAN_NAME);
357 0 : if (krberr) {
358 0 : DEBUG(SSSDBG_FATAL_FAILURE,
359 : "Failed to read keytab file [%s]: %s\n",
360 : KEYTAB_CLEAN_NAME,
361 : sss_krb5_get_error_message(context, krberr));
362 0 : goto done;
363 : }
364 :
365 : /* Verify the keytab */
366 0 : ret = lc_verify_keytab_ex(full_princ, keytab_name, context, keytab);
367 0 : if (ret) {
368 0 : DEBUG(SSSDBG_OP_FAILURE,
369 : "Unable to verify principal is present in the keytab\n");
370 0 : krberr = KRB5_KT_IOERR;
371 0 : goto done;
372 : }
373 :
374 0 : memset(&my_creds, 0, sizeof(my_creds));
375 0 : memset(&options, 0, sizeof(options));
376 :
377 0 : krb5_get_init_creds_opt_set_address_list(&options, NULL);
378 0 : krb5_get_init_creds_opt_set_forwardable(&options, 0);
379 0 : krb5_get_init_creds_opt_set_proxiable(&options, 0);
380 0 : krb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
381 :
382 0 : tmp_str = getenv("KRB5_CANONICALIZE");
383 0 : if (tmp_str != NULL && strcasecmp(tmp_str, "true") == 0) {
384 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Will canonicalize principals\n");
385 0 : canonicalize = 1;
386 : }
387 0 : sss_krb5_get_init_creds_opt_set_canonicalize(&options, canonicalize);
388 :
389 0 : ccname_file = talloc_asprintf(tmp_ctx, "%s/ccache_%s",
390 : DB_PATH, realm_name);
391 0 : if (ccname_file == NULL) {
392 0 : krberr = ENOMEM;
393 0 : DEBUG(SSSDBG_CRIT_FAILURE,
394 : "talloc_asprintf failed: %s:[%d].\n",
395 : strerror(krberr), krberr);
396 0 : goto done;
397 : }
398 :
399 0 : ccname_file_dummy = talloc_asprintf(tmp_ctx, "%s/ccache_%s_XXXXXX",
400 : DB_PATH, realm_name);
401 0 : if (ccname_file_dummy == NULL) {
402 0 : krberr = ENOMEM;
403 0 : DEBUG(SSSDBG_CRIT_FAILURE,
404 : "talloc_asprintf failed: %s:[%d].\n",
405 : strerror(krberr), krberr);
406 0 : goto done;
407 : }
408 :
409 0 : ret = sss_unique_filename(tmp_ctx, ccname_file_dummy);
410 0 : if (ret != EOK) {
411 0 : DEBUG(SSSDBG_CRIT_FAILURE,
412 : "sss_unique_filename failed: %s:[%d].\n",
413 : strerror(ret), ret);
414 0 : krberr = KRB5KRB_ERR_GENERIC;
415 0 : goto done;
416 : }
417 :
418 0 : krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc,
419 : keytab, 0, NULL, &options);
420 0 : krb5_kt_close(context, keytab);
421 0 : keytab = NULL;
422 0 : if (krberr) {
423 0 : DEBUG(SSSDBG_FATAL_FAILURE,
424 : "Failed to init credentials: %s\n",
425 : sss_krb5_get_error_message(context, krberr));
426 0 : sss_log(SSS_LOG_ERR,
427 : "Failed to initialize credentials using keytab [%s]: %s. "
428 : "Unable to create GSSAPI-encrypted LDAP connection.",
429 : KEYTAB_CLEAN_NAME,
430 : sss_krb5_get_error_message(context, krberr));
431 0 : goto done;
432 : }
433 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "credentials initialized\n");
434 :
435 0 : ccname_dummy = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file_dummy);
436 0 : ccname = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file);
437 0 : if (ccname_dummy == NULL || ccname == NULL) {
438 0 : krberr = ENOMEM;
439 0 : goto done;
440 : }
441 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "keytab ccname: [%s]\n", ccname_dummy);
442 :
443 0 : krberr = krb5_cc_resolve(context, ccname_dummy, &ccache);
444 0 : if (krberr) {
445 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to set cache name: %s\n",
446 : sss_krb5_get_error_message(context, krberr));
447 0 : goto done;
448 : }
449 :
450 : /* Use updated principal if changed due to canonicalization. */
451 0 : krberr = krb5_cc_initialize(context, ccache, my_creds.client);
452 0 : if (krberr) {
453 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to init ccache: %s\n",
454 : sss_krb5_get_error_message(context, krberr));
455 0 : goto done;
456 : }
457 :
458 0 : krberr = krb5_cc_store_cred(context, ccache, &my_creds);
459 0 : if (krberr) {
460 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to store creds: %s\n",
461 : sss_krb5_get_error_message(context, krberr));
462 0 : goto done;
463 : }
464 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "credentials stored\n");
465 :
466 : #ifdef HAVE_KRB5_GET_TIME_OFFSETS
467 0 : krberr = krb5_get_time_offsets(context, &kdc_time_offset,
468 : &kdc_time_offset_usec);
469 0 : if (krberr) {
470 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to get KDC time offset: %s\n",
471 : sss_krb5_get_error_message(context, krberr));
472 0 : kdc_time_offset = 0;
473 : } else {
474 0 : if (kdc_time_offset_usec > 0) {
475 0 : kdc_time_offset++;
476 : }
477 : }
478 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Got KDC time offset\n");
479 : #else
480 : /* If we don't have this function, just assume no offset */
481 : kdc_time_offset = 0;
482 : #endif
483 :
484 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
485 : "Renaming [%s] to [%s]\n", ccname_file_dummy, ccname_file);
486 0 : ret = rename(ccname_file_dummy, ccname_file);
487 0 : if (ret == -1) {
488 0 : ret = errno;
489 0 : DEBUG(SSSDBG_CRIT_FAILURE,
490 : "rename failed [%d][%s].\n", ret, strerror(ret));
491 0 : goto done;
492 : }
493 :
494 0 : krberr = 0;
495 0 : *ccname_out = talloc_steal(memctx, ccname);
496 0 : *expire_time_out = my_creds.times.endtime - kdc_time_offset;
497 :
498 : done:
499 0 : if (krberr != 0) KRB5_SYSLOG(krberr);
500 0 : if (keytab) krb5_kt_close(context, keytab);
501 0 : if (context) krb5_free_context(context);
502 0 : talloc_free(tmp_ctx);
503 0 : return krberr;
504 : }
505 :
506 0 : static int prepare_response(TALLOC_CTX *mem_ctx,
507 : const char *ccname,
508 : time_t expire_time,
509 : krb5_error_code kerr,
510 : struct response **rsp)
511 : {
512 : int ret;
513 0 : struct response *r = NULL;
514 0 : const char *krb5_msg = NULL;
515 :
516 0 : r = talloc_zero(mem_ctx, struct response);
517 0 : if (!r) return ENOMEM;
518 :
519 0 : r->buf = NULL;
520 0 : r->size = 0;
521 :
522 0 : DEBUG(SSSDBG_TRACE_FUNC, "Building response for result [%d]\n", kerr);
523 :
524 0 : if (kerr == 0) {
525 0 : ret = pack_buffer(r, EOK, kerr, ccname, expire_time);
526 : } else {
527 0 : krb5_msg = sss_krb5_get_error_message(krb5_error_ctx, kerr);
528 0 : if (krb5_msg == NULL) {
529 0 : DEBUG(SSSDBG_CRIT_FAILURE,
530 : "sss_krb5_get_error_message failed.\n");
531 0 : return ENOMEM;
532 : }
533 :
534 0 : ret = pack_buffer(r, EFAULT, kerr, krb5_msg, 0);
535 0 : sss_krb5_free_error_message(krb5_error_ctx, krb5_msg);
536 : }
537 :
538 0 : if (ret != EOK) {
539 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pack_buffer failed\n");
540 0 : return ret;
541 : }
542 :
543 0 : *rsp = r;
544 0 : return EOK;
545 : }
546 :
547 0 : static krb5_error_code privileged_krb5_setup(struct input_buffer *ibuf)
548 : {
549 : krb5_error_code kerr;
550 : char *keytab_name;
551 :
552 0 : kerr = krb5_init_context(&ibuf->context);
553 0 : if (kerr != 0) {
554 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to init kerberos context\n");
555 0 : return kerr;
556 : }
557 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Kerberos context initialized\n");
558 :
559 0 : kerr = copy_keytab_into_memory(ibuf, ibuf->context, ibuf->keytab_name,
560 : &keytab_name, NULL);
561 0 : if (kerr != 0) {
562 0 : DEBUG(SSSDBG_OP_FAILURE, "copy_keytab_into_memory failed.\n");
563 0 : return kerr;
564 : }
565 0 : talloc_free(ibuf->keytab_name);
566 0 : ibuf->keytab_name = keytab_name;
567 :
568 0 : return 0;
569 : }
570 :
571 0 : int main(int argc, const char *argv[])
572 : {
573 : int ret;
574 : int kerr;
575 : int opt;
576 0 : int debug_fd = -1;
577 : poptContext pc;
578 0 : TALLOC_CTX *main_ctx = NULL;
579 0 : uint8_t *buf = NULL;
580 0 : ssize_t len = 0;
581 0 : const char *ccname = NULL;
582 0 : time_t expire_time = 0;
583 0 : struct input_buffer *ibuf = NULL;
584 0 : struct response *resp = NULL;
585 : ssize_t written;
586 :
587 0 : struct poptOption long_options[] = {
588 : POPT_AUTOHELP
589 : {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0,
590 0 : _("Debug level"), NULL},
591 : {"debug-timestamps", 0, POPT_ARG_INT, &debug_timestamps, 0,
592 0 : _("Add debug timestamps"), NULL},
593 : {"debug-microseconds", 0, POPT_ARG_INT, &debug_microseconds, 0,
594 0 : _("Show timestamps with microseconds"), NULL},
595 : {"debug-fd", 0, POPT_ARG_INT, &debug_fd, 0,
596 0 : _("An open file descriptor for the debug logs"), NULL},
597 : {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, \
598 0 : _("Send the debug output to stderr directly."), NULL }, \
599 : POPT_TABLEEND
600 : };
601 :
602 : /* Set debug level to invalid value so we can decide if -d 0 was used. */
603 0 : debug_level = SSSDBG_INVALID;
604 :
605 0 : pc = poptGetContext(argv[0], argc, argv, long_options, 0);
606 0 : while((opt = poptGetNextOpt(pc)) != -1) {
607 : switch(opt) {
608 : default:
609 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
610 : poptBadOption(pc, 0), poptStrerror(opt));
611 0 : poptPrintUsage(pc, stderr, 0);
612 0 : _exit(-1);
613 : }
614 : }
615 :
616 0 : poptFreeContext(pc);
617 :
618 0 : DEBUG_INIT(debug_level);
619 :
620 0 : debug_prg_name = talloc_asprintf(NULL, "[sssd[ldap_child[%d]]]", getpid());
621 0 : if (!debug_prg_name) {
622 0 : debug_prg_name = "[sssd[ldap_child]]";
623 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
624 0 : goto fail;
625 : }
626 :
627 0 : if (debug_fd != -1) {
628 0 : ret = set_debug_file_from_fd(debug_fd);
629 0 : if (ret != EOK) {
630 0 : DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n");
631 : }
632 : }
633 :
634 0 : DEBUG(SSSDBG_TRACE_FUNC, "ldap_child started.\n");
635 :
636 0 : main_ctx = talloc_new(NULL);
637 0 : if (main_ctx == NULL) {
638 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n");
639 0 : talloc_free(discard_const(debug_prg_name));
640 0 : goto fail;
641 : }
642 0 : talloc_steal(main_ctx, debug_prg_name);
643 :
644 0 : buf = talloc_size(main_ctx, sizeof(uint8_t)*IN_BUF_SIZE);
645 0 : if (buf == NULL) {
646 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
647 0 : goto fail;
648 : }
649 :
650 0 : ibuf = talloc_zero(main_ctx, struct input_buffer);
651 0 : if (ibuf == NULL) {
652 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
653 0 : goto fail;
654 : }
655 :
656 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "context initialized\n");
657 :
658 0 : errno = 0;
659 0 : len = sss_atomic_read_s(STDIN_FILENO, buf, IN_BUF_SIZE);
660 0 : if (len == -1) {
661 0 : ret = errno;
662 0 : DEBUG(SSSDBG_CRIT_FAILURE, "read failed [%d][%s].\n", ret, strerror(ret));
663 0 : goto fail;
664 : }
665 :
666 0 : close(STDIN_FILENO);
667 :
668 0 : ret = unpack_buffer(buf, len, ibuf);
669 0 : if (ret != EOK) {
670 0 : DEBUG(SSSDBG_CRIT_FAILURE,
671 : "unpack_buffer failed.[%d][%s].\n", ret, strerror(ret));
672 0 : goto fail;
673 : }
674 :
675 0 : kerr = privileged_krb5_setup(ibuf);
676 0 : if (kerr != EOK) {
677 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Privileged Krb5 setup failed.\n");
678 0 : goto fail;
679 : }
680 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Kerberos context initialized\n");
681 :
682 0 : kerr = become_user(ibuf->uid, ibuf->gid);
683 0 : if (kerr != 0) {
684 0 : DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
685 0 : goto fail;
686 : }
687 :
688 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
689 : "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid());
690 :
691 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "getting TGT sync\n");
692 0 : kerr = ldap_child_get_tgt_sync(main_ctx, ibuf->context,
693 : ibuf->realm_str, ibuf->princ_str,
694 0 : ibuf->keytab_name, ibuf->lifetime,
695 : &ccname, &expire_time);
696 0 : if (kerr != EOK) {
697 0 : DEBUG(SSSDBG_CRIT_FAILURE, "ldap_child_get_tgt_sync failed.\n");
698 : /* Do not return, must report failure */
699 : }
700 :
701 0 : ret = prepare_response(main_ctx, ccname, expire_time, kerr, &resp);
702 0 : if (ret != EOK) {
703 0 : DEBUG(SSSDBG_CRIT_FAILURE, "prepare_response failed. [%d][%s].\n",
704 : ret, strerror(ret));
705 0 : goto fail;
706 : }
707 :
708 0 : errno = 0;
709 0 : written = sss_atomic_write_s(STDOUT_FILENO, resp->buf, resp->size);
710 0 : if (written == -1) {
711 0 : ret = errno;
712 0 : DEBUG(SSSDBG_CRIT_FAILURE, "write failed [%d][%s].\n", ret,
713 : strerror(ret));
714 0 : goto fail;
715 : }
716 :
717 0 : if (written != resp->size) {
718 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Expected to write %zu bytes, wrote %zu\n",
719 : resp->size, written);
720 0 : goto fail;
721 : }
722 :
723 0 : DEBUG(SSSDBG_TRACE_FUNC, "ldap_child completed successfully\n");
724 0 : close(STDOUT_FILENO);
725 0 : talloc_free(main_ctx);
726 0 : _exit(0);
727 :
728 : fail:
729 0 : DEBUG(SSSDBG_CRIT_FAILURE, "ldap_child failed!\n");
730 0 : close(STDOUT_FILENO);
731 0 : talloc_free(main_ctx);
732 0 : _exit(-1);
733 : }
|