source: heimdal/trunk/appl/gssmask/gssmask.c

Last change on this file was 1, checked in by Paul Smedley, 10 years ago

Initial commit of Heimdal 1.5.3

File size: 27.1 KB
Line 
1/*
2 * Copyright (c) 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of KTH nor the names of its contributors may be
18 * used to endorse or promote products derived from this software without
19 * specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "common.h"
35RCSID("$Id$");
36
37/*
38 *
39 */
40
41enum handle_type { handle_context, handle_cred };
42
43struct handle {
44 int32_t idx;
45 enum handle_type type;
46 void *ptr;
47 struct handle *next;
48};
49
50struct client {
51 krb5_storage *sock;
52 krb5_storage *logging;
53 char *moniker;
54 int32_t nHandle;
55 struct handle *handles;
56 struct sockaddr_storage sa;
57 socklen_t salen;
58 char servername[MAXHOSTNAMELEN];
59};
60
61FILE *logfile;
62static char *targetname;
63krb5_context context;
64
65/*
66 *
67 */
68
69static void
70logmessage(struct client *c, const char *file, unsigned int lineno,
71 int level, const char *fmt, ...)
72{
73 char *message;
74 va_list ap;
75 int32_t ackid;
76
77 va_start(ap, fmt);
78 vasprintf(&message, fmt, ap);
79 va_end(ap);
80
81 if (logfile)
82 fprintf(logfile, "%s:%u: %d %s\n", file, lineno, level, message);
83
84 if (c->logging) {
85 if (krb5_store_int32(c->logging, eLogInfo) != 0)
86 errx(1, "krb5_store_int32: log level");
87 if (krb5_store_string(c->logging, file) != 0)
88 errx(1, "krb5_store_string: filename");
89 if (krb5_store_int32(c->logging, lineno) != 0)
90 errx(1, "krb5_store_string: filename");
91 if (krb5_store_string(c->logging, message) != 0)
92 errx(1, "krb5_store_string: message");
93 if (krb5_ret_int32(c->logging, &ackid) != 0)
94 errx(1, "krb5_ret_int32: ackid");
95 }
96 free(message);
97}
98
99/*
100 *
101 */
102
103static int32_t
104add_handle(struct client *c, enum handle_type type, void *data)
105{
106 struct handle *h;
107
108 h = ecalloc(1, sizeof(*h));
109
110 h->idx = ++c->nHandle;
111 h->type = type;
112 h->ptr = data;
113 h->next = c->handles;
114 c->handles = h;
115
116 return h->idx;
117}
118
119static void
120del_handle(struct handle **h, int32_t idx)
121{
122 OM_uint32 min_stat;
123
124 if (idx == 0)
125 return;
126
127 while (*h) {
128 if ((*h)->idx == idx) {
129 struct handle *p = *h;
130 *h = (*h)->next;
131 switch(p->type) {
132 case handle_context: {
133 gss_ctx_id_t c = p->ptr;
134 gss_delete_sec_context(&min_stat, &c, NULL);
135 break; }
136 case handle_cred: {
137 gss_cred_id_t c = p->ptr;
138 gss_release_cred(&min_stat, &c);
139 break; }
140 }
141 free(p);
142 return;
143 }
144 h = &((*h)->next);
145 }
146 errx(1, "tried to delete an unexisting handle");
147}
148
149static void *
150find_handle(struct handle *h, int32_t idx, enum handle_type type)
151{
152 if (idx == 0)
153 return NULL;
154
155 while (h) {
156 if (h->idx == idx) {
157 if (type == h->type)
158 return h->ptr;
159 errx(1, "monger switched type on handle!");
160 }
161 h = h->next;
162 }
163 return NULL;
164}
165
166
167static int32_t
168convert_gss_to_gsm(OM_uint32 maj_stat)
169{
170 switch(maj_stat) {
171 case 0:
172 return GSMERR_OK;
173 case GSS_S_CONTINUE_NEEDED:
174 return GSMERR_CONTINUE_NEEDED;
175 case GSS_S_DEFECTIVE_TOKEN:
176 return GSMERR_INVALID_TOKEN;
177 case GSS_S_BAD_MIC:
178 return GSMERR_AP_MODIFIED;
179 default:
180 return GSMERR_ERROR;
181 }
182}
183
184static int32_t
185convert_krb5_to_gsm(krb5_error_code ret)
186{
187 switch(ret) {
188 case 0:
189 return GSMERR_OK;
190 default:
191 return GSMERR_ERROR;
192 }
193}
194
195/*
196 *
197 */
198
199static int32_t
200acquire_cred(struct client *c,
201 krb5_principal principal,
202 krb5_get_init_creds_opt *opt,
203 int32_t *handle)
204{
205 krb5_error_code ret;
206 krb5_creds cred;
207 krb5_ccache id;
208 gss_cred_id_t gcred;
209 OM_uint32 maj_stat, min_stat;
210
211 *handle = 0;
212
213 krb5_get_init_creds_opt_set_forwardable (opt, 1);
214 krb5_get_init_creds_opt_set_renew_life (opt, 3600 * 24 * 30);
215
216 memset(&cred, 0, sizeof(cred));
217
218 ret = krb5_get_init_creds_password (context,
219 &cred,
220 principal,
221 NULL,
222 NULL,
223 NULL,
224 0,
225 NULL,
226 opt);
227 if (ret) {
228 logmessage(c, __FILE__, __LINE__, 0,
229 "krb5_get_init_creds failed: %d", ret);
230 return convert_krb5_to_gsm(ret);
231 }
232
233 ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id);
234 if (ret)
235 krb5_err (context, 1, ret, "krb5_cc_initialize");
236
237 ret = krb5_cc_initialize (context, id, cred.client);
238 if (ret)
239 krb5_err (context, 1, ret, "krb5_cc_initialize");
240
241 ret = krb5_cc_store_cred (context, id, &cred);
242 if (ret)
243 krb5_err (context, 1, ret, "krb5_cc_store_cred");
244
245 krb5_free_cred_contents (context, &cred);
246
247 maj_stat = gss_krb5_import_cred(&min_stat,
248 id,
249 NULL,
250 NULL,
251 &gcred);
252 krb5_cc_close(context, id);
253 if (maj_stat) {
254 logmessage(c, __FILE__, __LINE__, 0,
255 "krb5 import creds failed with: %d", maj_stat);
256 return convert_gss_to_gsm(maj_stat);
257 }
258
259 *handle = add_handle(c, handle_cred, gcred);
260
261 return 0;
262}
263
264
265/*
266 *
267 */
268
269#define HandleOP(h) \
270handle##h(enum gssMaggotOp op, struct client *c)
271
272/*
273 *
274 */
275
276static int
277HandleOP(GetVersionInfo)
278{
279 put32(c, GSSMAGGOTPROTOCOL);
280 errx(1, "GetVersionInfo");
281}
282
283static int
284HandleOP(GoodBye)
285{
286 struct handle *h = c->handles;
287 unsigned int i = 0;
288
289 while (h) {
290 h = h->next;
291 i++;
292 }
293
294 if (i)
295 logmessage(c, __FILE__, __LINE__, 0,
296 "Did not toast all resources: %d", i);
297 return 1;
298}
299
300static int
301HandleOP(InitContext)
302{
303 OM_uint32 maj_stat, min_stat, ret_flags;
304 int32_t hContext, hCred, flags;
305 krb5_data target_name, in_token;
306 int32_t new_context_id = 0, gsm_error = 0;
307 krb5_data out_token = { 0 , NULL };
308
309 gss_ctx_id_t ctx;
310 gss_cred_id_t creds;
311 gss_name_t gss_target_name;
312 gss_buffer_desc input_token, output_token;
313 gss_OID oid = GSS_C_NO_OID;
314 gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER;
315
316 ret32(c, hContext);
317 ret32(c, hCred);
318 ret32(c, flags);
319 retdata(c, target_name);
320 retdata(c, in_token);
321
322 logmessage(c, __FILE__, __LINE__, 0,
323 "targetname: <%.*s>", (int)target_name.length,
324 (char *)target_name.data);
325
326 ctx = find_handle(c->handles, hContext, handle_context);
327 if (ctx == NULL)
328 hContext = 0;
329 creds = find_handle(c->handles, hCred, handle_cred);
330 if (creds == NULL)
331 abort();
332
333 input_token.length = target_name.length;
334 input_token.value = target_name.data;
335
336 maj_stat = gss_import_name(&min_stat,
337 &input_token,
338 GSS_KRB5_NT_PRINCIPAL_NAME,
339 &gss_target_name);
340 if (GSS_ERROR(maj_stat)) {
341 logmessage(c, __FILE__, __LINE__, 0,
342 "import name creds failed with: %d", maj_stat);
343 gsm_error = convert_gss_to_gsm(maj_stat);
344 goto out;
345 }
346
347 /* oid from flags */
348
349 if (in_token.length) {
350 input_token.length = in_token.length;
351 input_token.value = in_token.data;
352 input_token_ptr = &input_token;
353 if (ctx == NULL)
354 krb5_errx(context, 1, "initcreds, context NULL, but not first req");
355 } else {
356 input_token.length = 0;
357 input_token.value = NULL;
358 if (ctx)
359 krb5_errx(context, 1, "initcreds, context not NULL, but first req");
360 }
361
362 if ((flags & GSS_C_DELEG_FLAG) != 0)
363 logmessage(c, __FILE__, __LINE__, 0, "init_sec_context delegating");
364 if ((flags & GSS_C_DCE_STYLE) != 0)
365 logmessage(c, __FILE__, __LINE__, 0, "init_sec_context dce-style");
366
367 maj_stat = gss_init_sec_context(&min_stat,
368 creds,
369 &ctx,
370 gss_target_name,
371 oid,
372 flags & 0x7f,
373 0,
374 NULL,
375 input_token_ptr,
376 NULL,
377 &output_token,
378 &ret_flags,
379 NULL);
380 if (GSS_ERROR(maj_stat)) {
381 if (hContext != 0)
382 del_handle(&c->handles, hContext);
383 new_context_id = 0;
384 logmessage(c, __FILE__, __LINE__, 0,
385 "gss_init_sec_context returns code: %d/%d",
386 maj_stat, min_stat);
387 } else {
388 if (input_token.length == 0)
389 new_context_id = add_handle(c, handle_context, ctx);
390 else
391 new_context_id = hContext;
392 }
393
394 gsm_error = convert_gss_to_gsm(maj_stat);
395
396 if (output_token.length) {
397 out_token.data = output_token.value;
398 out_token.length = output_token.length;
399 }
400
401out:
402 logmessage(c, __FILE__, __LINE__, 0,
403 "InitContext return code: %d", gsm_error);
404
405 put32(c, new_context_id);
406 put32(c, gsm_error);
407 putdata(c, out_token);
408
409 gss_release_name(&min_stat, &gss_target_name);
410 if (output_token.length)
411 gss_release_buffer(&min_stat, &output_token);
412 krb5_data_free(&in_token);
413 krb5_data_free(&target_name);
414
415 return 0;
416}
417
418static int
419HandleOP(AcceptContext)
420{
421 OM_uint32 maj_stat, min_stat, ret_flags;
422 int32_t hContext, deleg_hcred, flags;
423 krb5_data in_token;
424 int32_t new_context_id = 0, gsm_error = 0;
425 krb5_data out_token = { 0 , NULL };
426
427 gss_ctx_id_t ctx;
428 gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL;
429 gss_buffer_desc input_token, output_token;
430 gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER;
431
432 ret32(c, hContext);
433 ret32(c, flags);
434 retdata(c, in_token);
435
436 ctx = find_handle(c->handles, hContext, handle_context);
437 if (ctx == NULL)
438 hContext = 0;
439
440 if (in_token.length) {
441 input_token.length = in_token.length;
442 input_token.value = in_token.data;
443 input_token_ptr = &input_token;
444 } else {
445 input_token.length = 0;
446 input_token.value = NULL;
447 }
448
449 maj_stat = gss_accept_sec_context(&min_stat,
450 &ctx,
451 GSS_C_NO_CREDENTIAL,
452 &input_token,
453 GSS_C_NO_CHANNEL_BINDINGS,
454 NULL,
455 NULL,
456 &output_token,
457 &ret_flags,
458 NULL,
459 &deleg_cred);
460 if (GSS_ERROR(maj_stat)) {
461 if (hContext != 0)
462 del_handle(&c->handles, hContext);
463 logmessage(c, __FILE__, __LINE__, 0,
464 "gss_accept_sec_context returns code: %d/%d",
465 maj_stat, min_stat);
466 new_context_id = 0;
467 } else {
468 if (hContext == 0)
469 new_context_id = add_handle(c, handle_context, ctx);
470 else
471 new_context_id = hContext;
472 }
473 if (output_token.length) {
474 out_token.data = output_token.value;
475 out_token.length = output_token.length;
476 }
477 if ((ret_flags & GSS_C_DCE_STYLE) != 0)
478 logmessage(c, __FILE__, __LINE__, 0, "accept_sec_context dce-style");
479 if ((ret_flags & GSS_C_DELEG_FLAG) != 0) {
480 deleg_hcred = add_handle(c, handle_cred, deleg_cred);
481 logmessage(c, __FILE__, __LINE__, 0,
482 "accept_context delegated handle: %d", deleg_hcred);
483 } else {
484 gss_release_cred(&min_stat, &deleg_cred);
485 deleg_hcred = 0;
486 }
487
488
489 gsm_error = convert_gss_to_gsm(maj_stat);
490
491 put32(c, new_context_id);
492 put32(c, gsm_error);
493 putdata(c, out_token);
494 put32(c, deleg_hcred);
495
496 if (output_token.length)
497 gss_release_buffer(&min_stat, &output_token);
498 krb5_data_free(&in_token);
499
500 return 0;
501}
502
503static int
504HandleOP(ToastResource)
505{
506 int32_t handle;
507
508 ret32(c, handle);
509 logmessage(c, __FILE__, __LINE__, 0, "toasting %d", handle);
510 del_handle(&c->handles, handle);
511 put32(c, GSMERR_OK);
512
513 return 0;
514}
515
516static int
517HandleOP(AcquireCreds)
518{
519 char *name, *password;
520 int32_t gsm_error, flags, handle = 0;
521 krb5_principal principal = NULL;
522 krb5_get_init_creds_opt *opt = NULL;
523 krb5_error_code ret;
524
525 retstring(c, name);
526 retstring(c, password);
527 ret32(c, flags);
528
529 logmessage(c, __FILE__, __LINE__, 0,
530 "username: %s password: %s", name, password);
531
532 ret = krb5_parse_name(context, name, &principal);
533 if (ret) {
534 gsm_error = convert_krb5_to_gsm(ret);
535 goto out;
536 }
537
538 ret = krb5_get_init_creds_opt_alloc (context, &opt);
539 if (ret)
540 krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc");
541
542 krb5_get_init_creds_opt_set_pa_password(context, opt, password, NULL);
543
544 gsm_error = acquire_cred(c, principal, opt, &handle);
545
546out:
547 logmessage(c, __FILE__, __LINE__, 0,
548 "AcquireCreds handle: %d return code: %d", handle, gsm_error);
549
550 if (opt)
551 krb5_get_init_creds_opt_free (context, opt);
552 if (principal)
553 krb5_free_principal(context, principal);
554 free(name);
555 free(password);
556
557 put32(c, gsm_error);
558 put32(c, handle);
559
560 return 0;
561}
562
563static int
564HandleOP(Sign)
565{
566 OM_uint32 maj_stat, min_stat;
567 int32_t hContext, flags, seqno;
568 krb5_data token;
569 gss_ctx_id_t ctx;
570 gss_buffer_desc input_token, output_token;
571
572 ret32(c, hContext);
573 ret32(c, flags);
574 ret32(c, seqno);
575 retdata(c, token);
576
577 ctx = find_handle(c->handles, hContext, handle_context);
578 if (ctx == NULL)
579 errx(1, "sign: reference to unknown context");
580
581 input_token.length = token.length;
582 input_token.value = token.data;
583
584 maj_stat = gss_get_mic(&min_stat, ctx, 0, &input_token,
585 &output_token);
586 if (maj_stat != GSS_S_COMPLETE)
587 errx(1, "gss_get_mic failed");
588
589 krb5_data_free(&token);
590
591 token.data = output_token.value;
592 token.length = output_token.length;
593
594 put32(c, 0); /* XXX fix gsm_error */
595 putdata(c, token);
596
597 gss_release_buffer(&min_stat, &output_token);
598
599 return 0;
600}
601
602static int
603HandleOP(Verify)
604{
605 OM_uint32 maj_stat, min_stat;
606 int32_t hContext, flags, seqno;
607 krb5_data msg, mic;
608 gss_ctx_id_t ctx;
609 gss_buffer_desc msg_token, mic_token;
610 gss_qop_t qop;
611
612 ret32(c, hContext);
613
614 ctx = find_handle(c->handles, hContext, handle_context);
615 if (ctx == NULL)
616 errx(1, "verify: reference to unknown context");
617
618 ret32(c, flags);
619 ret32(c, seqno);
620 retdata(c, msg);
621
622 msg_token.length = msg.length;
623 msg_token.value = msg.data;
624
625 retdata(c, mic);
626
627 mic_token.length = mic.length;
628 mic_token.value = mic.data;
629
630 maj_stat = gss_verify_mic(&min_stat, ctx, &msg_token,
631 &mic_token, &qop);
632 if (maj_stat != GSS_S_COMPLETE)
633 errx(1, "gss_verify_mic failed");
634
635 krb5_data_free(&mic);
636 krb5_data_free(&msg);
637
638 put32(c, 0); /* XXX fix gsm_error */
639
640 return 0;
641}
642
643static int
644HandleOP(GetVersionAndCapabilities)
645{
646 int32_t cap = HAS_MONIKER;
647 char name[256] = "unknown", *str;
648
649 if (targetname)
650 cap |= ISSERVER; /* is server */
651
652#ifdef HAVE_UNAME
653 {
654 struct utsname ut;
655 if (uname(&ut) == 0) {
656 snprintf(name, sizeof(name), "%s-%s-%s",
657 ut.sysname, ut.version, ut.machine);
658 }
659 }
660#endif
661
662 asprintf(&str, "gssmask %s %s", PACKAGE_STRING, name);
663
664 put32(c, GSSMAGGOTPROTOCOL);
665 put32(c, cap);
666 putstring(c, str);
667 free(str);
668
669 return 0;
670}
671
672static int
673HandleOP(GetTargetName)
674{
675 if (targetname)
676 putstring(c, targetname);
677 else
678 putstring(c, "");
679 return 0;
680}
681
682static int
683HandleOP(SetLoggingSocket)
684{
685 int32_t portnum;
686 int fd, ret;
687
688 ret32(c, portnum);
689
690 logmessage(c, __FILE__, __LINE__, 0,
691 "logging port on peer is: %d", (int)portnum);
692
693 socket_set_port((struct sockaddr *)(&c->sa), htons(portnum));
694
695 fd = socket(((struct sockaddr *)&c->sa)->sa_family, SOCK_STREAM, 0);
696 if (fd < 0)
697 return 0;
698
699 ret = connect(fd, (struct sockaddr *)&c->sa, c->salen);
700 if (ret < 0) {
701 logmessage(c, __FILE__, __LINE__, 0, "failed connect to log port: %s",
702 strerror(errno));
703 close(fd);
704 return 0;
705 }
706
707 if (c->logging)
708 krb5_storage_free(c->logging);
709 c->logging = krb5_storage_from_fd(fd);
710 close(fd);
711
712 krb5_store_int32(c->logging, eLogSetMoniker);
713 store_string(c->logging, c->moniker);
714
715 logmessage(c, __FILE__, __LINE__, 0, "logging turned on");
716
717 return 0;
718}
719
720
721static int
722HandleOP(ChangePassword)
723{
724 errx(1, "ChangePassword");
725}
726
727static int
728HandleOP(SetPasswordSelf)
729{
730 errx(1, "SetPasswordSelf");
731}
732
733static int
734HandleOP(Wrap)
735{
736 OM_uint32 maj_stat, min_stat;
737 int32_t hContext, flags, seqno;
738 krb5_data token;
739 gss_ctx_id_t ctx;
740 gss_buffer_desc input_token, output_token;
741 int conf_state;
742
743 ret32(c, hContext);
744 ret32(c, flags);
745 ret32(c, seqno);
746 retdata(c, token);
747
748 ctx = find_handle(c->handles, hContext, handle_context);
749 if (ctx == NULL)
750 errx(1, "wrap: reference to unknown context");
751
752 input_token.length = token.length;
753 input_token.value = token.data;
754
755 maj_stat = gss_wrap(&min_stat, ctx, flags, 0, &input_token,
756 &conf_state, &output_token);
757 if (maj_stat != GSS_S_COMPLETE)
758 errx(1, "gss_wrap failed");
759
760 krb5_data_free(&token);
761
762 token.data = output_token.value;
763 token.length = output_token.length;
764
765 put32(c, 0); /* XXX fix gsm_error */
766 putdata(c, token);
767
768 gss_release_buffer(&min_stat, &output_token);
769
770 return 0;
771}
772
773
774static int
775HandleOP(Unwrap)
776{
777 OM_uint32 maj_stat, min_stat;
778 int32_t hContext, flags, seqno;
779 krb5_data token;
780 gss_ctx_id_t ctx;
781 gss_buffer_desc input_token, output_token;
782 int conf_state;
783 gss_qop_t qop_state;
784
785 ret32(c, hContext);
786 ret32(c, flags);
787 ret32(c, seqno);
788 retdata(c, token);
789
790 ctx = find_handle(c->handles, hContext, handle_context);
791 if (ctx == NULL)
792 errx(1, "unwrap: reference to unknown context");
793
794 input_token.length = token.length;
795 input_token.value = token.data;
796
797 maj_stat = gss_unwrap(&min_stat, ctx, &input_token,
798 &output_token, &conf_state, &qop_state);
799
800 if (maj_stat != GSS_S_COMPLETE)
801 errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);
802
803 krb5_data_free(&token);
804 if (maj_stat == GSS_S_COMPLETE) {
805 token.data = output_token.value;
806 token.length = output_token.length;
807 } else {
808 token.data = NULL;
809 token.length = 0;
810 }
811 put32(c, 0); /* XXX fix gsm_error */
812 putdata(c, token);
813
814 if (maj_stat == GSS_S_COMPLETE)
815 gss_release_buffer(&min_stat, &output_token);
816
817 return 0;
818}
819
820static int
821HandleOP(Encrypt)
822{
823 return handleWrap(op, c);
824}
825
826static int
827HandleOP(Decrypt)
828{
829 return handleUnwrap(op, c);
830}
831
832static int
833HandleOP(ConnectLoggingService2)
834{
835 errx(1, "ConnectLoggingService2");
836}
837
838static int
839HandleOP(GetMoniker)
840{
841 putstring(c, c->moniker);
842 return 0;
843}
844
845static int
846HandleOP(CallExtension)
847{
848 errx(1, "CallExtension");
849}
850
851static int
852HandleOP(AcquirePKInitCreds)
853{
854 int32_t flags;
855 krb5_data pfxdata;
856 char fn[] = "FILE:/tmp/pkcs12-creds-XXXXXXX";
857 krb5_principal principal = NULL;
858 int fd;
859
860 ret32(c, flags);
861 retdata(c, pfxdata);
862
863 fd = mkstemp(fn + 5);
864 if (fd < 0)
865 errx(1, "mkstemp");
866
867 net_write(fd, pfxdata.data, pfxdata.length);
868 krb5_data_free(&pfxdata);
869 close(fd);
870
871 if (principal)
872 krb5_free_principal(context, principal);
873
874 put32(c, -1); /* hResource */
875 put32(c, GSMERR_NOT_SUPPORTED);
876 return 0;
877}
878
879static int
880HandleOP(WrapExt)
881{
882 OM_uint32 maj_stat, min_stat;
883 int32_t hContext, flags, bflags;
884 krb5_data token, header, trailer;
885 gss_ctx_id_t ctx;
886 unsigned char *p;
887 int conf_state, iov_len;
888 gss_iov_buffer_desc iov[6];
889
890 ret32(c, hContext);
891 ret32(c, flags);
892 ret32(c, bflags);
893 retdata(c, header);
894 retdata(c, token);
895 retdata(c, trailer);
896
897 ctx = find_handle(c->handles, hContext, handle_context);
898 if (ctx == NULL)
899 errx(1, "wrap: reference to unknown context");
900
901 memset(&iov, 0, sizeof(iov));
902
903 iov_len = sizeof(iov)/sizeof(iov[0]);
904
905 if (bflags & WRAP_EXP_ONLY_HEADER)
906 iov_len -= 2; /* skip trailer and padding, aka dce-style */
907
908 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
909 if (header.length != 0) {
910 iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
911 iov[1].buffer.length = header.length;
912 iov[1].buffer.value = header.data;
913 } else {
914 iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
915 }
916 iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
917 iov[2].buffer.length = token.length;
918 iov[2].buffer.value = token.data;
919 if (trailer.length != 0) {
920 iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
921 iov[3].buffer.length = trailer.length;
922 iov[3].buffer.value = trailer.data;
923 } else {
924 iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
925 }
926 iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
927 iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
928
929 maj_stat = gss_wrap_iov_length(&min_stat, ctx, flags, 0, &conf_state,
930 iov, iov_len);
931 if (maj_stat != GSS_S_COMPLETE)
932 errx(1, "gss_wrap_iov_length failed");
933
934 maj_stat = gss_wrap_iov(&min_stat, ctx, flags, 0, &conf_state,
935 iov, iov_len);
936 if (maj_stat != GSS_S_COMPLETE)
937 errx(1, "gss_wrap_iov failed");
938
939 krb5_data_free(&token);
940
941 token.length = iov[0].buffer.length + iov[2].buffer.length + iov[4].buffer.length + iov[5].buffer.length;
942 token.data = malloc(token.length);
943
944 p = token.data;
945 memcpy(p, iov[0].buffer.value, iov[0].buffer.length);
946 p += iov[0].buffer.length;
947 memcpy(p, iov[2].buffer.value, iov[2].buffer.length);
948 p += iov[2].buffer.length;
949 memcpy(p, iov[4].buffer.value, iov[4].buffer.length);
950 p += iov[4].buffer.length;
951 memcpy(p, iov[5].buffer.value, iov[5].buffer.length);
952 p += iov[5].buffer.length;
953
954 gss_release_iov_buffer(NULL, iov, iov_len);
955
956 put32(c, 0); /* XXX fix gsm_error */
957 putdata(c, token);
958
959 free(token.data);
960
961 return 0;
962}
963
964
965static int
966HandleOP(UnwrapExt)
967{
968 OM_uint32 maj_stat, min_stat;
969 int32_t hContext, flags, bflags;
970 krb5_data token, header, trailer;
971 gss_ctx_id_t ctx;
972 gss_iov_buffer_desc iov[3];
973 int conf_state, iov_len;
974 gss_qop_t qop_state;
975
976 ret32(c, hContext);
977 ret32(c, flags);
978 ret32(c, bflags);
979 retdata(c, header);
980 retdata(c, token);
981 retdata(c, trailer);
982
983 iov_len = sizeof(iov)/sizeof(iov[0]);
984
985 if (bflags & WRAP_EXP_ONLY_HEADER)
986 iov_len -= 1; /* skip trailer and padding, aka dce-style */
987
988 ctx = find_handle(c->handles, hContext, handle_context);
989 if (ctx == NULL)
990 errx(1, "unwrap: reference to unknown context");
991
992 if (header.length != 0) {
993 iov[0].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
994 iov[0].buffer.length = header.length;
995 iov[0].buffer.value = header.data;
996 } else {
997 iov[0].type = GSS_IOV_BUFFER_TYPE_EMPTY;
998 }
999 iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
1000 iov[1].buffer.length = token.length;
1001 iov[1].buffer.value = token.data;
1002
1003 if (trailer.length != 0) {
1004 iov[2].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
1005 iov[2].buffer.length = trailer.length;
1006 iov[2].buffer.value = trailer.data;
1007 } else {
1008 iov[2].type = GSS_IOV_BUFFER_TYPE_EMPTY;
1009 }
1010
1011 maj_stat = gss_unwrap_iov(&min_stat, ctx, &conf_state, &qop_state,
1012 iov, iov_len);
1013
1014 if (maj_stat != GSS_S_COMPLETE)
1015 errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);
1016
1017 if (maj_stat == GSS_S_COMPLETE) {
1018 token.data = iov[1].buffer.value;
1019 token.length = iov[1].buffer.length;
1020 } else {
1021 token.data = NULL;
1022 token.length = 0;
1023 }
1024 put32(c, 0); /* XXX fix gsm_error */
1025 putdata(c, token);
1026
1027 return 0;
1028}
1029
1030/*
1031 *
1032 */
1033
1034struct handler {
1035 enum gssMaggotOp op;
1036 const char *name;
1037 int (*func)(enum gssMaggotOp, struct client *);
1038};
1039
1040#define S(a) { e##a, #a, handle##a }
1041
1042struct handler handlers[] = {
1043 S(GetVersionInfo),
1044 S(GoodBye),
1045 S(InitContext),
1046 S(AcceptContext),
1047 S(ToastResource),
1048 S(AcquireCreds),
1049 S(Encrypt),
1050 S(Decrypt),
1051 S(Sign),
1052 S(Verify),
1053 S(GetVersionAndCapabilities),
1054 S(GetTargetName),
1055 S(SetLoggingSocket),
1056 S(ChangePassword),
1057 S(SetPasswordSelf),
1058 S(Wrap),
1059 S(Unwrap),
1060 S(ConnectLoggingService2),
1061 S(GetMoniker),
1062 S(CallExtension),
1063 S(AcquirePKInitCreds),
1064 S(WrapExt),
1065 S(UnwrapExt),
1066};
1067
1068#undef S
1069
1070/*
1071 *
1072 */
1073
1074static struct handler *
1075find_op(int32_t op)
1076{
1077 int i;
1078
1079 for (i = 0; i < sizeof(handlers)/sizeof(handlers[0]); i++)
1080 if (handlers[i].op == op)
1081 return &handlers[i];
1082 return NULL;
1083}
1084
1085static struct client *
1086create_client(int fd, int port, const char *moniker)
1087{
1088 struct client *c;
1089
1090 c = ecalloc(1, sizeof(*c));
1091
1092 if (moniker) {
1093 c->moniker = estrdup(moniker);
1094 } else {
1095 char hostname[MAXHOSTNAMELEN];
1096 gethostname(hostname, sizeof(hostname));
1097 asprintf(&c->moniker, "gssmask: %s:%d", hostname, port);
1098 }
1099
1100 {
1101 c->salen = sizeof(c->sa);
1102 getpeername(fd, (struct sockaddr *)&c->sa, &c->salen);
1103
1104 getnameinfo((struct sockaddr *)&c->sa, c->salen,
1105 c->servername, sizeof(c->servername),
1106 NULL, 0, NI_NUMERICHOST);
1107 }
1108
1109 c->sock = krb5_storage_from_fd(fd);
1110 if (c->sock == NULL)
1111 errx(1, "krb5_storage_from_fd");
1112
1113 close(fd);
1114
1115 return c;
1116}
1117
1118static void
1119free_client(struct client *c)
1120{
1121 while(c->handles)
1122 del_handle(&c->handles, c->handles->idx);
1123
1124 free(c->moniker);
1125 krb5_storage_free(c->sock);
1126 if (c->logging)
1127 krb5_storage_free(c->logging);
1128 free(c);
1129}
1130
1131
1132static void *
1133handleServer(void *ptr)
1134{
1135 struct handler *handler;
1136 struct client *c;
1137 int32_t op;
1138
1139 c = (struct client *)ptr;
1140
1141
1142 while(1) {
1143 ret32(c, op);
1144
1145 handler = find_op(op);
1146 if (handler == NULL) {
1147 logmessage(c, __FILE__, __LINE__, 0,
1148 "op %d not supported", (int)op);
1149 exit(1);
1150 }
1151
1152 logmessage(c, __FILE__, __LINE__, 0,
1153 "---> Got op %s from server %s",
1154 handler->name, c->servername);
1155
1156 if ((handler->func)(handler->op, c))
1157 break;
1158 }
1159
1160 return NULL;
1161}
1162
1163
1164static char *port_str;
1165static int version_flag;
1166static int help_flag;
1167static char *logfile_str;
1168static char *moniker_str;
1169
1170static int port = 4711;
1171
1172struct getargs args[] = {
1173 { "spn", 0, arg_string, &targetname, "This host's SPN",
1174 "service/host@REALM" },
1175 { "port", 'p', arg_string, &port_str, "Use this port",
1176 "number-of-service" },
1177 { "logfile", 0, arg_string, &logfile_str, "logfile",
1178 "number-of-service" },
1179 { "moniker", 0, arg_string, &moniker_str, "nickname",
1180 "name" },
1181 { "version", 0, arg_flag, &version_flag, "Print version",
1182 NULL },
1183 { "help", 0, arg_flag, &help_flag, NULL,
1184 NULL }
1185};
1186
1187static void
1188usage(int ret)
1189{
1190 arg_printusage (args,
1191 sizeof(args) / sizeof(args[0]),
1192 NULL,
1193 "");
1194 exit (ret);
1195}
1196
1197int
1198main(int argc, char **argv)
1199{
1200 int optidx = 0;
1201
1202 setprogname (argv[0]);
1203
1204 if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
1205 usage (1);
1206
1207 if (help_flag)
1208 usage (0);
1209
1210 if (version_flag) {
1211 print_version (NULL);
1212 return 0;
1213 }
1214
1215 if (optidx != argc)
1216 usage (1);
1217
1218 if (port_str) {
1219 char *ptr;
1220
1221 port = strtol (port_str, &ptr, 10);
1222 if (port == 0 && ptr == port_str)
1223 errx (1, "Bad port `%s'", port_str);
1224 }
1225
1226 krb5_init_context(&context);
1227
1228 {
1229 const char *lf = logfile_str;
1230 if (lf == NULL)
1231 lf = "/dev/tty";
1232
1233 logfile = fopen(lf, "w");
1234 if (logfile == NULL)
1235 err(1, "error opening %s", lf);
1236 }
1237
1238 mini_inetd(htons(port), NULL);
1239 fprintf(logfile, "connected\n");
1240
1241 {
1242 struct client *c;
1243
1244 c = create_client(0, port, moniker_str);
1245 /* close(0); */
1246
1247 handleServer(c);
1248
1249 free_client(c);
1250 }
1251
1252 krb5_free_context(context);
1253
1254 return 0;
1255}
Note: See TracBrowser for help on using the repository browser.