Bug Summary

File:daemons/ipa-kdb/ipa-print-pac.c
Warning:line 227, column 5
Value stored to 'imaj' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ipa-print-pac.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mthread-model posix -mframe-pointer=all -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/10.0.0 -D HAVE_CONFIG_H -I . -I ../.. -I . -I ../../util -D PREFIX="/usr/local" -D BINDIR="/usr/local/bin" -D LIBDIR="/usr/local/lib" -D LIBEXECDIR="/usr/local/libexec" -D DATADIR="/usr/local/share" -D LDAPIDIR="/run" -I /usr/include/samba-4.0 -D _GNU_SOURCE=1 -D HAVE_IMMEDIATE_STRUCTURES=1 -I /usr/include/nss3 -I /usr/include/nspr4 -I /usr/include/nspr4 -I /usr/include/nss3 -I /usr/include/nspr4 -I . -I ../../util -D PREFIX="/usr/local" -D BINDIR="/usr/local/bin" -D LIBDIR="/usr/local/lib" -D LIBEXECDIR="/usr/local/libexec" -D DATADIR="/usr/local/share" -D LDAPIDIR="/run" -I /usr/include/samba-4.0 -D _GNU_SOURCE=1 -D HAVE_IMMEDIATE_STRUCTURES=1 -D __STDC_WANT_LIB_EXT1__=1 -D _DEFAULT_SOURCE=1 -D _POSIX_C_SOURCE=200809L -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/10.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /home/heimes/redhat/freeipa/daemons/ipa-kdb -ferror-limit 19 -fmessage-length 0 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -faddrsig -o /home/heimes/redhat/freeipa/report/2020-06-05-101548-295465-1 -x c ipa-print-pac.c
1/*
2 * Copyright (C) 2020 FreeIPA Contributors see COPYING for license
3 */
4#include <gen_ndr/ndr_krb5pac.h>
5#include <gssapi/gssapi_ext.h>
6#include <gssapi/gssapi_krb5.h>
7#include <ndr.h>
8#include <popt.h>
9#include <stdbool.h>
10#include <stdio.h>
11#include <string.h>
12#include <strings.h>
13
14#define IPAPWD_PASSWORD_MAX_LEN1024 1024
15
16typedef enum {
17 OP_SERVICE_TICKET,
18 OP_IMPERSONATE
19} pac_operation_t;
20
21pac_operation_t operation = OP_SERVICE_TICKET;
22char *keytab_path = NULL((void*)0);
23char *ccache_path = NULL((void*)0);
24bool_Bool init_tgt = true1;
25const gss_OID *import_name_oid = &GSS_C_NT_USER_NAME;
26
27TALLOC_CTX *frame = NULL((void*)0);
28
29gss_OID_desc mech_krb5 = {9, "\052\206\110\206\367\022\001\002\002"};
30
31/* NDR printing interface passes flags but the actual public print function
32 * does not accept flags. Generated ndr helpers actually have a small wrapper
33 * but since it is a static to the generated C code unit, we have to reimplement
34 * it here.
35 */
36static void
37print_flags_PAC_DATA(struct ndr_print *ndr,
38 const char *name,
39 int unused,
40 const struct PAC_DATA *r)
41{
42 ndr_print_PAC_DATA(ndr, name, r);
43}
44
45/*
46 * Print content of a PAC buffer, annotated by the libndr helpers
47 */
48static void
49print_pac(gss_buffer_desc *pac, gss_buffer_desc *display)
50{
51 struct ndr_print *ndr = NULL((void*)0);
52 DATA_BLOB blob;
53 struct ndr_pull *ndr_pull = NULL((void*)0);
54 void *st = NULL((void*)0);
55 int flags = NDR_SCALARS0x100 | NDR_BUFFERS0x200;
56 enum ndr_err_code ndr_err;
57 struct ndr_interface_call ndr_call = {
58 .name = "PAC_DATA",
59 .struct_size = sizeof(struct PAC_DATA),
60 .ndr_push = (ndr_push_flags_fn_t)ndr_push_PAC_DATA,
61 .ndr_pull = (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA,
62 .ndr_print = (ndr_print_function_t)print_flags_PAC_DATA,
63 };
64
65 ndr = talloc_zero(frame, struct ndr_print)(struct ndr_print *)_talloc_zero(frame, sizeof(struct ndr_print
), "struct ndr_print")
;
66 ndr->print = ndr_print_string_helper;
67 ndr->depth = 0;
68
69 blob = data_blob_const(pac->value, pac->length);
70 ndr_pull = ndr_pull_init_blob(&blob, ndr);
71 ndr_pull->flags = LIBNDR_FLAG_REF_ALLOC(1U<<20);
72
73 st = talloc_zero_size(ndr, ndr_call.struct_size)_talloc_zero(ndr, ndr_call.struct_size, "ipa-print-pac.c" ":"
"73")
;
74 ndr_err = ndr_call.ndr_pull(ndr_pull, flags, st);
75 if (ndr_err) {
76 fprintf(stderrstderr,
77 "Error parsing buffer '%.*s': %s\n",
78 (int)display->length,
79 (char *)display->value,
80 ndr_map_error2string(ndr_err));
81 return;
82 }
83
84 ndr_call.ndr_print(ndr, ndr_call.name, flags, st);
85 printf("%s\n", (char *)ndr->private_data);
86 talloc_free(ndr)_talloc_free(ndr, "ipa-print-pac.c" ":" "86");
87}
88
89static void
90display_error(int type, OM_uint32 code)
91{
92 OM_uint32 min, ctx = 0;
93 gss_buffer_desc status;
94
95 do {
96 (void)gss_display_status(&min, code, type, GSS_C_NO_OID((gss_OID) 0), &ctx, &status);
97 fprintf(stderrstderr, "%.*s\n", (int)status.length, (char *)status.value);
98 gss_release_buffer(&min, &status);
99 } while (ctx != 0);
100}
101
102static void
103log_error(const char *fn, uint32_t maj, uint32_t min)
104{
105 fprintf(stderrstderr, "%s: ", fn);
106 display_error(GSS_C_GSS_CODE1, maj);
107 display_error(GSS_C_MECH_CODE2, min);
108}
109
110static gss_name_t
111import_name(const char *name)
112{
113 OM_uint32 maj, min;
114 gss_name_t gss_name;
115 gss_name = GSS_C_NO_NAME((gss_name_t) 0);
116 gss_buffer_desc buff = GSS_C_EMPTY_BUFFER{0, ((void*)0)};
117
118 buff.value = (void *)name;
119 buff.length = strlen(name);
120
121 maj = gss_import_name(&min, &buff, *import_name_oid, &gss_name);
122 if (GSS_ERROR(maj)((maj) & ((((OM_uint32) 0377ul) << 24) | (((OM_uint32
) 0377ul) << 16)))
) {
123 log_error("gss_import_name()", maj, min);
124 return GSS_C_NO_NAME((gss_name_t) 0);
125 }
126
127 return gss_name;
128}
129
130static bool_Bool
131store_creds_into_cache(gss_cred_id_t creds, const char *cache)
132{
133 OM_uint32 maj, min;
134 gss_key_value_element_desc store_elm = {"ccache", cache};
135 gss_key_value_set_desc store = {1, &store_elm};
136
137 maj = gss_store_cred_into(
138 &min, creds, GSS_C_INITIATE1, GSS_C_NO_OID((gss_OID) 0), 1, 1, &store, NULL((void*)0), NULL((void*)0));
139 if (maj != GSS_S_COMPLETE0) {
140 log_error("gss_store_cred_into()", maj, min);
141 return false0;
142 }
143
144 return true1;
145}
146
147static void
148dump_attribute(gss_name_t name, gss_buffer_t attribute)
149{
150 OM_uint32 major, minor;
151 gss_buffer_desc value;
152 gss_buffer_desc display_value;
153 int authenticated = 0;
154 int complete = 0;
155 int more = -1;
156 int whole_pac = 0;
157
158 whole_pac = attribute->length == strlen("urn:mspac:");
159 while (more != 0) {
160 value.value = NULL((void*)0);
161 display_value.value = NULL((void*)0);
162
163 major = gss_get_name_attribute(&minor,
164 name,
165 attribute,
166 &authenticated,
167 &complete,
168 &value,
169 &display_value,
170 &more);
171 if (GSS_ERROR(major)((major) & ((((OM_uint32) 0377ul) << 24) | (((OM_uint32
) 0377ul) << 16)))
) {
172 log_error("gss_get_name_attribute()", major, minor);
173 return;
174 }
175
176 if (whole_pac) {
177 print_pac(&value, attribute);
178 }
179
180 (void)gss_release_buffer(&minor, &value);
181 (void)gss_release_buffer(&minor, &display_value);
182 }
183}
184
185static void
186enumerate_attributes(gss_name_t name)
187{
188 OM_uint32 major, minor;
189 int is_mechname;
190 gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET((gss_buffer_set_t) 0);
191 size_t i;
192
193 major = gss_inquire_name(&minor, name, &is_mechname, NULL((void*)0), &attrs);
194 if (GSS_ERROR(major)((major) & ((((OM_uint32) 0377ul) << 24) | (((OM_uint32
) 0377ul) << 16)))
) {
195 log_error("gss_inquire_name()", major, minor);
196 return;
197 }
198 if (GSS_ERROR(major)((major) & ((((OM_uint32) 0377ul) << 24) | (((OM_uint32
) 0377ul) << 16)))
) {
199 printf("gss_inquire_name: (%d, %d)\n", major, minor);
200 return;
201 }
202
203 if (attrs != GSS_C_NO_BUFFER_SET((gss_buffer_set_t) 0)) {
204 for (i = 0; i < attrs->count; i++)
205 dump_attribute(name, &attrs->elements[i]);
206 }
207
208 (void)gss_release_buffer_set(&minor, &attrs);
209}
210
211static bool_Bool
212establish_contexts(gss_OID imech,
213 gss_cred_id_t icred,
214 gss_cred_id_t acred,
215 gss_name_t tname,
216 OM_uint32 flags,
217 gss_ctx_id_t *ictx,
218 gss_ctx_id_t *actx,
219 gss_name_t *src_name,
220 gss_OID *amech,
221 gss_cred_id_t *deleg_cred)
222{
223 OM_uint32 minor, imaj, amaj;
224 gss_buffer_desc itok, atok;
225
226 *ictx = *actx = GSS_C_NO_CONTEXT((gss_ctx_id_t) 0);
227 imaj = amaj = GSS_S_CONTINUE_NEEDED(1 << (0 + 0));
Value stored to 'imaj' is never read
228 itok.value = atok.value = NULL((void*)0);
229 itok.length = atok.length = 0;
230 for (;;) {
231 (void)gss_release_buffer(&minor, &itok);
232 imaj = gss_init_sec_context(&minor,
233 icred,
234 ictx,
235 tname,
236 imech,
237 flags,
238 GSS_C_INDEFINITE((OM_uint32) 0xfffffffful),
239 GSS_C_NO_CHANNEL_BINDINGS((gss_channel_bindings_t) 0),
240 &atok,
241 NULL((void*)0),
242 &itok,
243 NULL((void*)0),
244 NULL((void*)0));
245 if (GSS_ERROR(imaj)((imaj) & ((((OM_uint32) 0377ul) << 24) | (((OM_uint32
) 0377ul) << 16)))
) {
246 log_error("gss_init_sec_context()", imaj, minor);
247 return false0;
248 }
249 if (amaj == GSS_S_COMPLETE0)
250 break;
251
252 (void)gss_release_buffer(&minor, &atok);
253 amaj = gss_accept_sec_context(&minor,
254 actx,
255 acred,
256 &itok,
257 GSS_C_NO_CHANNEL_BINDINGS((gss_channel_bindings_t) 0),
258 src_name,
259 amech,
260 &atok,
261 NULL((void*)0),
262 NULL((void*)0),
263 deleg_cred);
264 if (GSS_ERROR(amaj)((amaj) & ((((OM_uint32) 0377ul) << 24) | (((OM_uint32
) 0377ul) << 16)))
) {
265 log_error("gss_accept_sec_context()", amaj, minor);
266 return false0;
267 }
268 (void)gss_release_buffer(&minor, &itok);
269 if (imaj == GSS_S_COMPLETE0) {
270 break;
271 }
272 }
273
274 if (imaj != GSS_S_COMPLETE0 || amaj != GSS_S_COMPLETE0) {
275 printf("One side wants to continue after the other is done");
276 return false0;
277 }
278
279 (void)gss_release_buffer(&minor, &itok);
280 (void)gss_release_buffer(&minor, &atok);
281
282 return true1;
283}
284
285static bool_Bool
286init_accept_sec_context(gss_cred_id_t claimant_cred_handle,
287 gss_cred_id_t verifier_cred_handle,
288 gss_cred_id_t *deleg_cred_handle)
289{
290 OM_uint32 maj, min, flags;
291 gss_name_t source_name = GSS_C_NO_NAME((gss_name_t) 0), target_name = GSS_C_NO_NAME((gss_name_t) 0);
292 gss_ctx_id_t initiator_context, acceptor_context;
293 gss_OID mech = &mech_krb5;
294 bool_Bool success = false0;
295
296 maj = gss_inquire_cred(
297 &min, verifier_cred_handle, &target_name, NULL((void*)0), NULL((void*)0), NULL((void*)0));
298 if (GSS_ERROR(maj)((maj) & ((((OM_uint32) 0377ul) << 24) | (((OM_uint32
) 0377ul) << 16)))
) {
299 log_error("gss_inquire_cred()", maj, min);
300 goto done;
301 }
302
303 flags = GSS_C_REPLAY_FLAG4 | GSS_C_SEQUENCE_FLAG8;
304 flags = GSS_C_REPLAY_FLAG4 | GSS_C_SEQUENCE_FLAG8;
305 success = establish_contexts(mech,
306 claimant_cred_handle,
307 verifier_cred_handle,
308 target_name,
309 flags,
310 &initiator_context,
311 &acceptor_context,
312 &source_name,
313 &mech,
314 deleg_cred_handle);
315 if (success)
316 enumerate_attributes(source_name);
317done:
318 if (source_name != GSS_C_NO_NAME((gss_name_t) 0))
319 (void)gss_release_name(&min, &source_name);
320
321 if (target_name != GSS_C_NO_NAME((gss_name_t) 0))
322 (void)gss_release_name(&min, &target_name);
323
324 if (initiator_context != NULL((void*)0))
325 (void)gss_delete_sec_context(&min, &initiator_context, NULL((void*)0));
326
327 if (acceptor_context != NULL((void*)0))
328 (void)gss_delete_sec_context(&min, &acceptor_context, NULL((void*)0));
329
330 return success;
331}
332
333static bool_Bool
334init_creds(gss_cred_id_t *service_creds, gss_cred_usage_t intent)
335{
336 OM_uint32 maj, min;
337 gss_key_value_element_desc keytab_elm = {"keytab", keytab_path};
338 gss_key_value_set_desc store = {1, &keytab_elm};
339
340 maj = gss_acquire_cred_from(&min,
341 GSS_C_NO_NAME((gss_name_t) 0),
342 GSS_C_INDEFINITE((OM_uint32) 0xfffffffful),
343 GSS_C_NO_OID_SET((gss_OID_set) 0),
344 intent,
345 (keytab_path != NULL((void*)0)) ? &store : NULL((void*)0),
346 service_creds,
347 NULL((void*)0),
348 NULL((void*)0));
349 if (GSS_ERROR(maj)((maj) & ((((OM_uint32) 0377ul) << 24) | (((OM_uint32
) 0377ul) << 16)))
) {
350 log_error("gss_acquire_cred", maj, min);
351 return false0;
352 }
353
354 return true1;
355}
356
357static bool_Bool
358impersonate(const char *name)
359{
360 OM_uint32 maj, min;
361 gss_name_t desired_principal = GSS_C_NO_NAME((gss_name_t) 0);
362 gss_cred_id_t client_creds = GSS_C_NO_CREDENTIAL((gss_cred_id_t) 0);
363 gss_cred_id_t service_creds = GSS_C_NO_CREDENTIAL((gss_cred_id_t) 0);
364 gss_cred_id_t delegated_creds = GSS_C_NO_CREDENTIAL((gss_cred_id_t) 0);
365 bool_Bool success = false0;
366
367 if (!init_creds(&service_creds, GSS_C_BOTH0)) {
368 goto done;
369 }
370
371 desired_principal = import_name(name);
372 if (desired_principal == GSS_C_NO_NAME((gss_name_t) 0)) {
373 goto done;
374 }
375
376 maj = gss_acquire_cred_impersonate_name(&min,
377 service_creds,
378 desired_principal,
379 GSS_C_INDEFINITE((OM_uint32) 0xfffffffful),
380 GSS_C_NO_OID_SET((gss_OID_set) 0),
381 GSS_C_INITIATE1,
382 &client_creds,
383 NULL((void*)0),
384 NULL((void*)0));
385 if (GSS_ERROR(maj)((maj) & ((((OM_uint32) 0377ul) << 24) | (((OM_uint32
) 0377ul) << 16)))
) {
386 log_error("gss_acquire_cred_impersonate_name()", maj, min);
387 goto done;
388 }
389
390 if (ccache_path != NULL((void*)0)) {
391 if (!store_creds_into_cache(client_creds, ccache_path)) {
392 fprintf(stderrstderr, "Failed to store credentials in cache\n");
393 goto done;
394 }
395 }
396
397 fprintf(stderrstderr, "Acquired credentials for %s\n", name);
398 init_accept_sec_context(client_creds, service_creds, &delegated_creds);
399
400 if (delegated_creds != GSS_C_NO_CREDENTIAL((gss_cred_id_t) 0)) {
401 gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET((gss_buffer_set_t) 0);
402 /* Inquire impersonator status. */
403 maj = gss_inquire_cred_by_oid(
404 &min, client_creds, GSS_KRB5_GET_CRED_IMPERSONATOR, &bufset);
405 if (GSS_ERROR(maj)((maj) & ((((OM_uint32) 0377ul) << 24) | (((OM_uint32
) 0377ul) << 16)))
) {
406 log_error("gss_inquire_cred_by_oid()", maj, min);
407 goto done;
408 }
409 if (bufset->count == 0) {
410 log_error("gss_inquire_cred_by_oid(user) returned NO impersonator", 0, 0);
411 goto done;
412 }
413 (void)gss_release_buffer_set(&min, &bufset);
414
415 maj = gss_inquire_cred_by_oid(
416 &min, service_creds, GSS_KRB5_GET_CRED_IMPERSONATOR, &bufset);
417 if (GSS_ERROR(maj)((maj) & ((((OM_uint32) 0377ul) << 24) | (((OM_uint32
) 0377ul) << 16)))
) {
418 log_error("gss_inquire_cred_by_oid()", maj, min);
419 goto done;
420 }
421 if (bufset->count != 0) {
422 log_error("gss_inquire_cred_by_oid(svc) returned an impersonator", 0, 0);
423 goto done;
424 }
425 (void)gss_release_buffer_set(&min, &bufset);
426 success = true1;
427 }
428
429done:
430
431 if (desired_principal != GSS_C_NO_NAME((gss_name_t) 0))
432 gss_release_name(&min, &desired_principal);
433
434 if (client_creds != GSS_C_NO_CREDENTIAL((gss_cred_id_t) 0))
435 gss_release_cred(&min, &client_creds);
436
437 if (service_creds != GSS_C_NO_CREDENTIAL((gss_cred_id_t) 0))
438 gss_release_cred(&min, &service_creds);
439
440 if (delegated_creds != GSS_C_NO_CREDENTIAL((gss_cred_id_t) 0))
441 gss_release_cred(&min, &delegated_creds);
442
443 return success;
444}
445
446static bool_Bool
447init_with_password(const char *name, const char *password)
448{
449 OM_uint32 maj, min;
450 gss_name_t desired_principal = GSS_C_NO_NAME((gss_name_t) 0);
451 gss_cred_id_t client_creds = GSS_C_NO_CREDENTIAL((gss_cred_id_t) 0);
452 gss_cred_id_t service_creds = GSS_C_NO_CREDENTIAL((gss_cred_id_t) 0);
453 gss_buffer_desc pwd_buf;
454 bool_Bool success = false0;
455
456 if (!init_creds(&service_creds, GSS_C_ACCEPT2)) {
457 goto done;
458 }
459
460 desired_principal = import_name(name);
461 if (desired_principal == GSS_C_NO_NAME((gss_name_t) 0)) {
462 goto done;
463 }
464
465 if (init_tgt && password != NULL((void*)0)) {
466 pwd_buf.value = (void *)password;
467 pwd_buf.length = strlen(password);
468 maj = gss_acquire_cred_with_password(&min,
469 desired_principal,
470 &pwd_buf,
471 GSS_C_INDEFINITE((OM_uint32) 0xfffffffful),
472 GSS_C_NO_OID_SET((gss_OID_set) 0),
473 GSS_C_INITIATE1,
474 &client_creds,
475 NULL((void*)0),
476 NULL((void*)0));
477 if (GSS_ERROR(maj)((maj) & ((((OM_uint32) 0377ul) << 24) | (((OM_uint32
) 0377ul) << 16)))
) {
478 log_error("gss_acquire_cred_with_password()", maj, min);
479 goto done;
480 }
481 }
482
483 if ((ccache_path != NULL((void*)0)) && (client_creds != GSS_C_NO_CREDENTIAL((gss_cred_id_t) 0))) {
484 if (!store_creds_into_cache(client_creds, ccache_path)) {
485 fprintf(stderrstderr, "Failed to store credentials in cache\n");
486 goto done;
487 }
488 }
489
490 if (client_creds != GSS_C_NO_CREDENTIAL((gss_cred_id_t) 0))
491 fprintf(stderrstderr, "Acquired credentials for %s\n", name);
492
493 success = init_accept_sec_context(client_creds, service_creds, NULL((void*)0));
494
495done:
496 if (service_creds != GSS_C_NO_CREDENTIAL((gss_cred_id_t) 0))
497 gss_release_cred(&min, &client_creds);
498
499 if (client_creds != GSS_C_NO_CREDENTIAL((gss_cred_id_t) 0))
500 gss_release_cred(&min, &client_creds);
501
502 if (desired_principal != GSS_C_NO_NAME((gss_name_t) 0))
503 gss_release_name(&min, &desired_principal);
504
505 return success;
506}
507
508struct poptOption popt_options[] = {
509 {
510 .longName = "enterprise",
511 .shortName = 'E',
512 .argInfo = POPT_ARG_NONE0U | POPT_ARGFLAG_OPTIONAL0x10000000U,
513 .val = 'E',
514 .descrip = "Treat the user principal as an enterprise name",
515 },
516 {
517 .longName = "ccache",
518 .shortName = 'c',
519 .argInfo = POPT_ARG_STRING1U | POPT_ARGFLAG_OPTIONAL0x10000000U,
520 .val = 'c',
521 .descrip = "Credentials cache file to save acquired tickets to. "
522 "Tickets aren't saved by default",
523 .argDescrip = "CCACHE-PATH",
524 },
525 {
526 .longName = "keytab",
527 .shortName = 'k',
528 .argInfo = POPT_ARG_STRING1U | POPT_ARGFLAG_OPTIONAL0x10000000U,
529 .val = 'k',
530 .descrip = "Keytab for a service key to acquire service ticket for. "
531 "Default keytab is used if omitted",
532 .argDescrip = "KEYTAB-PATH",
533 },
534 {
535 .longName = "reuse",
536 .shortName = 'r',
537 .argInfo = POPT_ARG_NONE0U | POPT_ARGFLAG_OPTIONAL0x10000000U,
538 .val = 'r',
539 .descrip = "Re-use user principal's TGT from a default ccache",
540 },
541 {
542 .longName = "help",
543 .shortName = 'h',
544 .argInfo = POPT_ARG_NONE0U | POPT_ARGFLAG_OPTIONAL0x10000000U,
545 .val = 'h',
546 .descrip = "Show this help message",
547 },
548
549 POPT_TABLEEND{ ((void*)0), '\0', 0, ((void*)0), 0, ((void*)0), ((void*)0) }};
550
551static void
552print_help(poptContext pc, const char *name)
553{
554 const char *help = ""
555 "Usage: %s [options] {impersonate|ticket} user@realm\n\n"
556 "Print MS-PAC structure from a service ticket.\n\n"
557 "Operation 'impersonate':\n"
558 "\tExpects a TGT for a service in the default ccache and attempts to "
559 "obtain a service\n"
560 "\tticket to itself by performing a protocol transition for the specified "
561 "user (S4U2Self).\n\n"
562 "Operation 'ticket':\n"
563 "\tExpects a user password to be provided, acquires ticket granting ticket "
564 "and attempts to \n"
565 "\tobtain a service ticket to the specified service.\n\n"
566 "Resulting service ticket can be stored in the credential cache file "
567 "specified by '-c file' option.\n\n"
568 "Defaults to the host principal service name and the host keytab.\n\n";
569 fprintf(stderrstderr, help, name);
570 poptPrintHelp(pc, stderrstderr, 0);
571}
572
573static char *
574ask_password(TALLOC_CTX *context, char *prompt1, char *prompt2, bool_Bool match)
575{
576 krb5_prompt ap_prompts[2];
577 krb5_data k5d_pw0;
578 krb5_data k5d_pw1;
579#define MAX(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b))
580#define PWD_BUFFER_SIZE((((1024 + 2)) > (1024)) ? ((1024 + 2)) : (1024)) MAX((IPAPWD_PASSWORD_MAX_LEN + 2), 1024)((((1024 + 2)) > (1024)) ? ((1024 + 2)) : (1024))
581 char pw0[PWD_BUFFER_SIZE((((1024 + 2)) > (1024)) ? ((1024 + 2)) : (1024))];
582 char pw1[PWD_BUFFER_SIZE((((1024 + 2)) > (1024)) ? ((1024 + 2)) : (1024))];
583 char *password;
584 int num_prompts = match ? 2 : 1;
585
586 k5d_pw0.length = sizeof(pw0);
587 k5d_pw0.data = pw0;
588 ap_prompts[0].prompt = prompt1;
589 ap_prompts[0].hidden = 1;
590 ap_prompts[0].reply = &k5d_pw0;
591
592 if (match) {
593 k5d_pw1.length = sizeof(pw1);
594 k5d_pw1.data = pw1;
595 ap_prompts[1].prompt = prompt2;
596 ap_prompts[1].hidden = 1;
597 ap_prompts[1].reply = &k5d_pw1;
598 }
599
600 /* krb5_prompter_posix does not use krb5_context internally */
601 krb5_prompter_posix(NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), num_prompts, ap_prompts);
602
603 if (match && (strcmp(pw0, pw1))) {
604 fprintf(stderrstderr, "Passwords do not match!\n");
605 return NULL((void*)0);
606 }
607
608 if (k5d_pw0.length > IPAPWD_PASSWORD_MAX_LEN1024) {
609 fprintf(stderrstderr, "%s\n", "Password is too long!\n");
610 return NULL((void*)0);
611 }
612
613 password = talloc_strndup(context, pw0, k5d_pw0.length);
614 if (!password)
615 return NULL((void*)0);
616 return password;
617}
618
619int main(int argc, char *argv[])
620{
621 int ret = 0, c = 0;
622 const char **argv_const = discard_const_p(const char *, argv)((const char * *)((void *)((uintptr_t)(argv))));
623 const char **args = NULL((void*)0);
624 char *password = NULL((void*)0);
625 poptContext pc;
626
627 frame = talloc_init("printpac");
628 pc = poptGetContext(
629 "printpac", argc, argv_const, popt_options, POPT_CONTEXT_KEEP_FIRST(1U << 1));
630 while ((c = poptGetNextOpt(pc)) >= 0) {
631 switch (c) {
632 case 'c':
633 ccache_path = talloc_strdup(frame, poptGetOptArg(pc));
634 break;
635 case 'E':
636 import_name_oid = &GSS_KRB5_NT_ENTERPRISE_NAME;
637 break;
638 case 'k':
639 keytab_path = talloc_strdup(frame, poptGetOptArg(pc));
640 break;
641 case 'r':
642 init_tgt = false0;
643 break;
644 case 'h':
645 print_help(pc, argv[0]);
646 ret = 0;
647 goto done;
648 }
649 }
650 if (c < -1) {
651 fprintf(stderrstderr,
652 "%s: %s\n",
653 poptBadOption(pc, POPT_BADOPTION_NOALIAS(1U << 0)),
654 poptStrerror(c));
655 ret = 1;
656 goto done;
657 }
658 args = poptGetArgs(pc);
659 for (c = 0; args && args[c]; c++)
660 ;
661
662 if (c < 3) {
663 print_help(pc, args[0]);
664 ret = 1;
665 goto done;
666 }
667
668 c -= 2;
669 if (strncasecmp("ticket", args[1], strlen("ticket")) == 0) {
670 operation = OP_SERVICE_TICKET;
671 if (init_tgt) {
672 switch (c) {
673 case 1:
674 password = ask_password(frame, "Password", NULL((void*)0), false0);
675 break;
676 case 2:
677 password = talloc_strdup(frame, args[3]);
678 break;
679 default:
680 fprintf(stderrstderr,
681 "Service ticket needs user principal and password\n\n");
682 print_help(pc, args[0]);
683 ret = 1;
684 goto done;
685 break;
686 }
687 } else {
688 if (c != 1) {
689 fprintf(stderrstderr, "Service ticket needs user principal and password\n\n");
690 print_help(pc, args[0]);
691 ret = 1;
692 goto done;
693 }
694 }
695 } else if (strncasecmp("impersonate", args[1], strlen("impersonate")) == 0) {
696 operation = OP_IMPERSONATE;
697 if (c != 1) {
698 fprintf(stderrstderr, "Impersonation ticket needs user principal\n\n");
699 print_help(pc, args[0]);
700 ret = 1;
701 goto done;
702 }
703 } else {
704 fprintf(stderrstderr, "Wrong request type: %s\n\n", args[1]);
705 print_help(pc, args[0]);
706 ret = 1;
707 goto done;
708 }
709
710 switch (operation) {
711 case OP_IMPERSONATE:
712 ret = impersonate(args[2]) != true1;
713 break;
714 case OP_SERVICE_TICKET:
715 ret = init_with_password(args[2], password) != true1;
716 break;
717 }
718
719done:
720 poptFreeContext(pc);
721 talloc_free(frame)_talloc_free(frame, "ipa-print-pac.c" ":" "721");
722 return ret;
723}