[HEIMDAL-646] malloc(0) checks for AIX
[heimdal.git] / appl / gssmask / gssmask.c
blob8cee0695b2d7081d41bbd8a0b2f66559998d61da
1 /*
2 * Copyright (c) 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "common.h"
35 RCSID("$Id$");
41 enum handle_type { handle_context, handle_cred };
43 struct handle {
44 int32_t idx;
45 enum handle_type type;
46 void *ptr;
47 struct handle *next;
50 struct 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];
61 FILE *logfile;
62 static char *targetname;
63 krb5_context context;
69 static void
70 logmessage(struct client *c, const char *file, unsigned int lineno,
71 int level, const char *fmt, ...)
73 char *message;
74 va_list ap;
75 int32_t ackid;
77 va_start(ap, fmt);
78 vasprintf(&message, fmt, ap);
79 va_end(ap);
81 if (logfile)
82 fprintf(logfile, "%s:%u: %d %s\n", file, lineno, level, message);
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");
96 free(message);
103 static int32_t
104 add_handle(struct client *c, enum handle_type type, void *data)
106 struct handle *h;
108 h = ecalloc(1, sizeof(*h));
110 h->idx = ++c->nHandle;
111 h->type = type;
112 h->ptr = data;
113 h->next = c->handles;
114 c->handles = h;
116 return h->idx;
119 static void
120 del_handle(struct handle **h, int32_t idx)
122 OM_uint32 min_stat;
124 if (idx == 0)
125 return;
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; }
141 free(p);
142 return;
144 h = &((*h)->next);
146 errx(1, "tried to delete an unexisting handle");
149 static void *
150 find_handle(struct handle *h, int32_t idx, enum handle_type type)
152 if (idx == 0)
153 return NULL;
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!");
161 h = h->next;
163 return NULL;
167 static int32_t
168 convert_gss_to_gsm(OM_uint32 maj_stat)
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;
184 static int32_t
185 convert_krb5_to_gsm(krb5_error_code ret)
187 switch(ret) {
188 case 0:
189 return GSMERR_OK;
190 default:
191 return GSMERR_ERROR;
199 static int32_t
200 acquire_cred(struct client *c,
201 krb5_principal principal,
202 krb5_get_init_creds_opt *opt,
203 int32_t *handle)
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;
211 *handle = 0;
213 krb5_get_init_creds_opt_set_forwardable (opt, 1);
214 krb5_get_init_creds_opt_set_renew_life (opt, 3600 * 24 * 30);
216 memset(&cred, 0, sizeof(cred));
218 ret = krb5_get_init_creds_password (context,
219 &cred,
220 principal,
221 NULL,
222 NULL,
223 NULL,
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);
233 ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id);
234 if (ret)
235 krb5_err (context, 1, ret, "krb5_cc_initialize");
237 ret = krb5_cc_initialize (context, id, cred.client);
238 if (ret)
239 krb5_err (context, 1, ret, "krb5_cc_initialize");
241 ret = krb5_cc_store_cred (context, id, &cred);
242 if (ret)
243 krb5_err (context, 1, ret, "krb5_cc_store_cred");
245 krb5_free_cred_contents (context, &cred);
247 maj_stat = gss_krb5_import_cred(&min_stat,
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);
259 *handle = add_handle(c, handle_cred, gcred);
261 return 0;
269 #define HandleOP(h) \
270 handle##h(enum gssMaggotOp op, struct client *c)
276 static int
277 HandleOP(GetVersionInfo)
279 put32(c, GSSMAGGOTPROTOCOL);
280 errx(1, "GetVersionInfo");
283 static int
284 HandleOP(GoodBye)
286 struct handle *h = c->handles;
287 unsigned int i = 0;
289 while (h) {
290 h = h->next;
291 i++;
294 if (i)
295 logmessage(c, __FILE__, __LINE__, 0,
296 "Did not toast all resources: %d", i);
297 return 1;
300 static int
301 HandleOP(InitContext)
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 };
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;
316 ret32(c, hContext);
317 ret32(c, hCred);
318 ret32(c, flags);
319 retdata(c, target_name);
320 retdata(c, in_token);
322 logmessage(c, __FILE__, __LINE__, 0,
323 "targetname: <%.*s>", (int)target_name.length,
324 (char *)target_name.data);
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();
333 input_token.length = target_name.length;
334 input_token.value = target_name.data;
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;
347 /* oid from flags */
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");
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");
367 maj_stat = gss_init_sec_context(&min_stat,
368 creds,
369 &ctx,
370 gss_target_name,
371 oid,
372 flags & 0x7f,
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;
394 gsm_error = convert_gss_to_gsm(maj_stat);
396 if (output_token.length) {
397 out_token.data = output_token.value;
398 out_token.length = output_token.length;
401 out:
402 logmessage(c, __FILE__, __LINE__, 0,
403 "InitContext return code: %d", gsm_error);
405 put32(c, new_context_id);
406 put32(c, gsm_error);
407 putdata(c, out_token);
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);
415 return 0;
418 static int
419 HandleOP(AcceptContext)
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 };
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;
432 ret32(c, hContext);
433 ret32(c, flags);
434 retdata(c, in_token);
436 ctx = find_handle(c->handles, hContext, handle_context);
437 if (ctx == NULL)
438 hContext = 0;
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;
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;
473 if (output_token.length) {
474 out_token.data = output_token.value;
475 out_token.length = output_token.length;
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;
489 gsm_error = convert_gss_to_gsm(maj_stat);
491 put32(c, new_context_id);
492 put32(c, gsm_error);
493 putdata(c, out_token);
494 put32(c, deleg_hcred);
496 if (output_token.length)
497 gss_release_buffer(&min_stat, &output_token);
498 krb5_data_free(&in_token);
500 return 0;
503 static int
504 HandleOP(ToastResource)
506 int32_t handle;
508 ret32(c, handle);
509 logmessage(c, __FILE__, __LINE__, 0, "toasting %d", handle);
510 del_handle(&c->handles, handle);
511 put32(c, GSMERR_OK);
513 return 0;
516 static int
517 HandleOP(AcquireCreds)
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;
525 retstring(c, name);
526 retstring(c, password);
527 ret32(c, flags);
529 logmessage(c, __FILE__, __LINE__, 0,
530 "username: %s password: %s", name, password);
532 ret = krb5_parse_name(context, name, &principal);
533 if (ret) {
534 gsm_error = convert_krb5_to_gsm(ret);
535 goto out;
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");
542 krb5_get_init_creds_opt_set_pa_password(context, opt, password, NULL);
544 gsm_error = acquire_cred(c, principal, opt, &handle);
546 out:
547 logmessage(c, __FILE__, __LINE__, 0,
548 "AcquireCreds handle: %d return code: %d", handle, gsm_error);
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);
557 put32(c, gsm_error);
558 put32(c, handle);
560 return 0;
563 static int
564 HandleOP(Sign)
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;
572 ret32(c, hContext);
573 ret32(c, flags);
574 ret32(c, seqno);
575 retdata(c, token);
577 ctx = find_handle(c->handles, hContext, handle_context);
578 if (ctx == NULL)
579 errx(1, "sign: reference to unknown context");
581 input_token.length = token.length;
582 input_token.value = token.data;
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");
589 krb5_data_free(&token);
591 token.data = output_token.value;
592 token.length = output_token.length;
594 put32(c, 0); /* XXX fix gsm_error */
595 putdata(c, token);
597 gss_release_buffer(&min_stat, &output_token);
599 return 0;
602 static int
603 HandleOP(Verify)
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;
612 ret32(c, hContext);
614 ctx = find_handle(c->handles, hContext, handle_context);
615 if (ctx == NULL)
616 errx(1, "verify: reference to unknown context");
618 ret32(c, flags);
619 ret32(c, seqno);
620 retdata(c, msg);
622 msg_token.length = msg.length;
623 msg_token.value = msg.data;
625 retdata(c, mic);
627 mic_token.length = mic.length;
628 mic_token.value = mic.data;
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");
635 krb5_data_free(&mic);
636 krb5_data_free(&msg);
638 put32(c, 0); /* XXX fix gsm_error */
640 return 0;
643 static int
644 HandleOP(GetVersionAndCapabilities)
646 int32_t cap = HAS_MONIKER;
647 char name[256] = "unknown", *str;
649 if (targetname)
650 cap |= ISSERVER; /* is server */
652 #ifdef HAVE_UNAME
654 struct utsname ut;
655 if (uname(&ut) == 0) {
656 snprintf(name, sizeof(name), "%s-%s-%s",
657 ut.sysname, ut.version, ut.machine);
660 #endif
662 asprintf(&str, "gssmask %s %s", PACKAGE_STRING, name);
664 put32(c, GSSMAGGOTPROTOCOL);
665 put32(c, cap);
666 putstring(c, str);
667 free(str);
669 return 0;
672 static int
673 HandleOP(GetTargetName)
675 if (targetname)
676 putstring(c, targetname);
677 else
678 putstring(c, "");
679 return 0;
682 static int
683 HandleOP(SetLoggingSocket)
685 int32_t portnum;
686 int fd, ret;
688 ret32(c, portnum);
690 logmessage(c, __FILE__, __LINE__, 0,
691 "logging port on peer is: %d", (int)portnum);
693 socket_set_port((struct sockaddr *)(&c->sa), htons(portnum));
695 fd = socket(((struct sockaddr *)&c->sa)->sa_family, SOCK_STREAM, 0);
696 if (fd < 0)
697 return 0;
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;
707 if (c->logging)
708 krb5_storage_free(c->logging);
709 c->logging = krb5_storage_from_fd(fd);
710 close(fd);
712 krb5_store_int32(c->logging, eLogSetMoniker);
713 store_string(c->logging, c->moniker);
715 logmessage(c, __FILE__, __LINE__, 0, "logging turned on");
717 return 0;
721 static int
722 HandleOP(ChangePassword)
724 errx(1, "ChangePassword");
727 static int
728 HandleOP(SetPasswordSelf)
730 errx(1, "SetPasswordSelf");
733 static int
734 HandleOP(Wrap)
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;
743 ret32(c, hContext);
744 ret32(c, flags);
745 ret32(c, seqno);
746 retdata(c, token);
748 ctx = find_handle(c->handles, hContext, handle_context);
749 if (ctx == NULL)
750 errx(1, "wrap: reference to unknown context");
752 input_token.length = token.length;
753 input_token.value = token.data;
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");
760 krb5_data_free(&token);
762 token.data = output_token.value;
763 token.length = output_token.length;
765 put32(c, 0); /* XXX fix gsm_error */
766 putdata(c, token);
768 gss_release_buffer(&min_stat, &output_token);
770 return 0;
774 static int
775 HandleOP(Unwrap)
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;
785 ret32(c, hContext);
786 ret32(c, flags);
787 ret32(c, seqno);
788 retdata(c, token);
790 ctx = find_handle(c->handles, hContext, handle_context);
791 if (ctx == NULL)
792 errx(1, "unwrap: reference to unknown context");
794 input_token.length = token.length;
795 input_token.value = token.data;
797 maj_stat = gss_unwrap(&min_stat, ctx, &input_token,
798 &output_token, &conf_state, &qop_state);
800 if (maj_stat != GSS_S_COMPLETE)
801 errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);
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;
811 put32(c, 0); /* XXX fix gsm_error */
812 putdata(c, token);
814 if (maj_stat == GSS_S_COMPLETE)
815 gss_release_buffer(&min_stat, &output_token);
817 return 0;
820 static int
821 HandleOP(Encrypt)
823 return handleWrap(op, c);
826 static int
827 HandleOP(Decrypt)
829 return handleUnwrap(op, c);
832 static int
833 HandleOP(ConnectLoggingService2)
835 errx(1, "ConnectLoggingService2");
838 static int
839 HandleOP(GetMoniker)
841 putstring(c, c->moniker);
842 return 0;
845 static int
846 HandleOP(CallExtension)
848 errx(1, "CallExtension");
851 krb5_error_code KRB5_LIB_FUNCTION
852 _krb5_pk_enterprise_cert (
853 krb5_context /*context*/,
854 const char */*user_id*/,
855 krb5_const_realm /*realm*/,
856 krb5_principal */*principal*/);
859 static int
860 HandleOP(AcquirePKInitCreds)
862 krb5_error_code ret;
863 int32_t flags;
864 krb5_data pfxdata;
865 char fn[] = "FILE:/tmp/pkcs12-creds-XXXXXXX";
866 const char *default_realm = "H5L.ORG";
867 krb5_principal principal = NULL;
868 int fd;
870 ret32(c, flags);
871 retdata(c, pfxdata);
873 fd = mkstemp(fn + 5);
874 if (fd < 0)
875 errx(1, "mkstemp");
877 net_write(fd, pfxdata.data, pfxdata.length);
878 krb5_data_free(&pfxdata);
879 close(fd);
881 /* get credentials */
883 ret = _krb5_pk_enterprise_cert(context, fn, default_realm, &principal);
884 if (ret)
885 krb5_err(context, 1, ret, "krb5_pk_enterprise_certs");
888 if (principal)
889 krb5_free_principal(context, principal);
891 put32(c, -1); /* hResource */
892 put32(c, GSMERR_NOT_SUPPORTED);
893 return 0;
896 static int
897 HandleOP(WrapExt)
899 OM_uint32 maj_stat, min_stat;
900 int32_t hContext, flags, bflags;
901 krb5_data token, header, trailer;
902 gss_ctx_id_t ctx;
903 unsigned char *p;
904 int conf_state, iov_len;
905 gss_iov_buffer_desc iov[6];
907 ret32(c, hContext);
908 ret32(c, flags);
909 ret32(c, bflags);
910 retdata(c, header);
911 retdata(c, token);
912 retdata(c, trailer);
914 ctx = find_handle(c->handles, hContext, handle_context);
915 if (ctx == NULL)
916 errx(1, "wrap: reference to unknown context");
918 memset(&iov, 0, sizeof(iov));
920 iov_len = sizeof(iov)/sizeof(iov[0]);
922 if (bflags & WRAP_EXP_ONLY_HEADER)
923 iov_len -= 2; /* skip trailer and padding, aka dce-style */
925 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
926 if (header.length != 0) {
927 iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
928 iov[1].buffer.length = header.length;
929 iov[1].buffer.value = header.data;
930 } else {
931 iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
933 iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
934 iov[2].buffer.length = token.length;
935 iov[2].buffer.value = token.data;
936 if (trailer.length != 0) {
937 iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
938 iov[3].buffer.length = trailer.length;
939 iov[3].buffer.value = trailer.data;
940 } else {
941 iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
943 iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
944 iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
946 maj_stat = gss_wrap_iov_length(&min_stat, ctx, flags, 0, &conf_state,
947 iov, iov_len);
948 if (maj_stat != GSS_S_COMPLETE)
949 errx(1, "gss_wrap_iov_length failed");
951 maj_stat = gss_wrap_iov(&min_stat, ctx, flags, 0, &conf_state,
952 iov, iov_len);
953 if (maj_stat != GSS_S_COMPLETE)
954 errx(1, "gss_wrap_iov failed");
956 krb5_data_free(&token);
958 token.length = iov[0].buffer.length + iov[2].buffer.length + iov[4].buffer.length + iov[5].buffer.length;
959 token.data = malloc(token.length);
961 p = token.data;
962 memcpy(p, iov[0].buffer.value, iov[0].buffer.length);
963 p += iov[0].buffer.length;
964 memcpy(p, iov[2].buffer.value, iov[2].buffer.length);
965 p += iov[2].buffer.length;
966 memcpy(p, iov[4].buffer.value, iov[4].buffer.length);
967 p += iov[4].buffer.length;
968 memcpy(p, iov[5].buffer.value, iov[5].buffer.length);
969 p += iov[5].buffer.length;
971 gss_release_iov_buffer(NULL, iov, iov_len);
973 put32(c, 0); /* XXX fix gsm_error */
974 putdata(c, token);
976 free(token.data);
978 return 0;
982 static int
983 HandleOP(UnwrapExt)
985 OM_uint32 maj_stat, min_stat;
986 int32_t hContext, flags, bflags;
987 krb5_data token, header, trailer;
988 gss_ctx_id_t ctx;
989 gss_iov_buffer_desc iov[3];
990 int conf_state, iov_len;
991 gss_qop_t qop_state;
993 ret32(c, hContext);
994 ret32(c, flags);
995 ret32(c, bflags);
996 retdata(c, header);
997 retdata(c, token);
998 retdata(c, trailer);
1000 iov_len = sizeof(iov)/sizeof(iov[0]);
1002 if (bflags & WRAP_EXP_ONLY_HEADER)
1003 iov_len -= 1; /* skip trailer and padding, aka dce-style */
1005 ctx = find_handle(c->handles, hContext, handle_context);
1006 if (ctx == NULL)
1007 errx(1, "unwrap: reference to unknown context");
1009 if (header.length != 0) {
1010 iov[0].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
1011 iov[0].buffer.length = header.length;
1012 iov[0].buffer.value = header.data;
1013 } else {
1014 iov[0].type = GSS_IOV_BUFFER_TYPE_EMPTY;
1016 iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
1017 iov[1].buffer.length = token.length;
1018 iov[1].buffer.value = token.data;
1020 if (trailer.length != 0) {
1021 iov[2].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
1022 iov[2].buffer.length = trailer.length;
1023 iov[2].buffer.value = trailer.data;
1024 } else {
1025 iov[2].type = GSS_IOV_BUFFER_TYPE_EMPTY;
1028 maj_stat = gss_unwrap_iov(&min_stat, ctx, &conf_state, &qop_state,
1029 iov, iov_len);
1031 if (maj_stat != GSS_S_COMPLETE)
1032 errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);
1034 if (maj_stat == GSS_S_COMPLETE) {
1035 token.data = iov[1].buffer.value;
1036 token.length = iov[1].buffer.length;
1037 } else {
1038 token.data = NULL;
1039 token.length = 0;
1041 put32(c, 0); /* XXX fix gsm_error */
1042 putdata(c, token);
1044 return 0;
1051 struct handler {
1052 enum gssMaggotOp op;
1053 const char *name;
1054 int (*func)(enum gssMaggotOp, struct client *);
1057 #define S(a) { e##a, #a, handle##a }
1059 struct handler handlers[] = {
1060 S(GetVersionInfo),
1061 S(GoodBye),
1062 S(InitContext),
1063 S(AcceptContext),
1064 S(ToastResource),
1065 S(AcquireCreds),
1066 S(Encrypt),
1067 S(Decrypt),
1068 S(Sign),
1069 S(Verify),
1070 S(GetVersionAndCapabilities),
1071 S(GetTargetName),
1072 S(SetLoggingSocket),
1073 S(ChangePassword),
1074 S(SetPasswordSelf),
1075 S(Wrap),
1076 S(Unwrap),
1077 S(ConnectLoggingService2),
1078 S(GetMoniker),
1079 S(CallExtension),
1080 S(AcquirePKInitCreds),
1081 S(WrapExt),
1082 S(UnwrapExt),
1085 #undef S
1091 static struct handler *
1092 find_op(int32_t op)
1094 int i;
1096 for (i = 0; i < sizeof(handlers)/sizeof(handlers[0]); i++)
1097 if (handlers[i].op == op)
1098 return &handlers[i];
1099 return NULL;
1102 static struct client *
1103 create_client(int fd, int port, const char *moniker)
1105 struct client *c;
1107 c = ecalloc(1, sizeof(*c));
1109 if (moniker) {
1110 c->moniker = estrdup(moniker);
1111 } else {
1112 char hostname[MAXHOSTNAMELEN];
1113 gethostname(hostname, sizeof(hostname));
1114 asprintf(&c->moniker, "gssmask: %s:%d", hostname, port);
1118 c->salen = sizeof(c->sa);
1119 getpeername(fd, (struct sockaddr *)&c->sa, &c->salen);
1121 getnameinfo((struct sockaddr *)&c->sa, c->salen,
1122 c->servername, sizeof(c->servername),
1123 NULL, 0, NI_NUMERICHOST);
1126 c->sock = krb5_storage_from_fd(fd);
1127 if (c->sock == NULL)
1128 errx(1, "krb5_storage_from_fd");
1130 close(fd);
1132 return c;
1135 static void
1136 free_client(struct client *c)
1138 while(c->handles)
1139 del_handle(&c->handles, c->handles->idx);
1141 free(c->moniker);
1142 krb5_storage_free(c->sock);
1143 if (c->logging)
1144 krb5_storage_free(c->logging);
1145 free(c);
1149 static void *
1150 handleServer(void *ptr)
1152 struct handler *handler;
1153 struct client *c;
1154 int32_t op;
1156 c = (struct client *)ptr;
1159 while(1) {
1160 ret32(c, op);
1162 handler = find_op(op);
1163 if (handler == NULL) {
1164 logmessage(c, __FILE__, __LINE__, 0,
1165 "op %d not supported", (int)op);
1166 exit(1);
1169 logmessage(c, __FILE__, __LINE__, 0,
1170 "---> Got op %s from server %s",
1171 handler->name, c->servername);
1173 if ((handler->func)(handler->op, c))
1174 break;
1177 return NULL;
1181 static char *port_str;
1182 static int version_flag;
1183 static int help_flag;
1184 static char *logfile_str;
1185 static char *moniker_str;
1187 static int port = 4711;
1189 struct getargs args[] = {
1190 { "spn", 0, arg_string, &targetname, "This host's SPN",
1191 "service/host@REALM" },
1192 { "port", 'p', arg_string, &port_str, "Use this port",
1193 "number-of-service" },
1194 { "logfile", 0, arg_string, &logfile_str, "logfile",
1195 "number-of-service" },
1196 { "moniker", 0, arg_string, &moniker_str, "nickname",
1197 "name" },
1198 { "version", 0, arg_flag, &version_flag, "Print version",
1199 NULL },
1200 { "help", 0, arg_flag, &help_flag, NULL,
1201 NULL }
1204 static void
1205 usage(int ret)
1207 arg_printusage (args,
1208 sizeof(args) / sizeof(args[0]),
1209 NULL,
1210 "");
1211 exit (ret);
1215 main(int argc, char **argv)
1217 int optidx = 0;
1219 setprogname (argv[0]);
1221 if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
1222 usage (1);
1224 if (help_flag)
1225 usage (0);
1227 if (version_flag) {
1228 print_version (NULL);
1229 return 0;
1232 if (optidx != argc)
1233 usage (1);
1235 if (port_str) {
1236 char *ptr;
1238 port = strtol (port_str, &ptr, 10);
1239 if (port == 0 && ptr == port_str)
1240 errx (1, "Bad port `%s'", port_str);
1243 krb5_init_context(&context);
1246 const char *lf = logfile_str;
1247 if (lf == NULL)
1248 lf = "/dev/tty";
1250 logfile = fopen(lf, "w");
1251 if (logfile == NULL)
1252 err(1, "error opening %s", lf);
1255 mini_inetd(htons(port));
1256 fprintf(logfile, "connected\n");
1259 struct client *c;
1261 c = create_client(0, port, moniker_str);
1262 /* close(0); */
1264 handleServer(c);
1266 free_client(c);
1269 krb5_free_context(context);
1271 return 0;