No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / appl / gssmask / gssmask.c
blob800094c95a4ab60f7ad126aa979c52725443fc4d
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("$Heimdal: gssmask.c 21229 2007-06-20 10:19:19Z lha $"
36 "$NetBSD$");
42 enum handle_type { handle_context, handle_cred };
44 struct handle {
45 int32_t idx;
46 enum handle_type type;
47 void *ptr;
48 struct handle *next;
51 struct client {
52 krb5_storage *sock;
53 krb5_storage *logging;
54 char *moniker;
55 int32_t nHandle;
56 struct handle *handles;
57 struct sockaddr_storage sa;
58 socklen_t salen;
59 char servername[MAXHOSTNAMELEN];
62 FILE *logfile;
63 static char *targetname;
64 krb5_context context;
70 static void
71 logmessage(struct client *c, const char *file, unsigned int lineno,
72 int level, const char *fmt, ...)
74 char *message;
75 va_list ap;
76 int32_t ackid;
78 va_start(ap, fmt);
79 vasprintf(&message, fmt, ap);
80 va_end(ap);
82 if (logfile)
83 fprintf(logfile, "%s:%u: %d %s\n", file, lineno, level, message);
85 if (c->logging) {
86 if (krb5_store_int32(c->logging, eLogInfo) != 0)
87 errx(1, "krb5_store_int32: log level");
88 if (krb5_store_string(c->logging, file) != 0)
89 errx(1, "krb5_store_string: filename");
90 if (krb5_store_int32(c->logging, lineno) != 0)
91 errx(1, "krb5_store_string: filename");
92 if (krb5_store_string(c->logging, message) != 0)
93 errx(1, "krb5_store_string: message");
94 if (krb5_ret_int32(c->logging, &ackid) != 0)
95 errx(1, "krb5_ret_int32: ackid");
97 free(message);
104 static int32_t
105 add_handle(struct client *c, enum handle_type type, void *data)
107 struct handle *h;
109 h = ecalloc(1, sizeof(*h));
111 h->idx = ++c->nHandle;
112 h->type = type;
113 h->ptr = data;
114 h->next = c->handles;
115 c->handles = h;
117 return h->idx;
120 static void
121 del_handle(struct handle **h, int32_t idx)
123 OM_uint32 min_stat;
125 if (idx == 0)
126 return;
128 while (*h) {
129 if ((*h)->idx == idx) {
130 struct handle *p = *h;
131 *h = (*h)->next;
132 switch(p->type) {
133 case handle_context: {
134 gss_ctx_id_t c = p->ptr;
135 gss_delete_sec_context(&min_stat, &c, NULL);
136 break; }
137 case handle_cred: {
138 gss_cred_id_t c = p->ptr;
139 gss_release_cred(&min_stat, &c);
140 break; }
142 free(p);
143 return;
145 h = &((*h)->next);
147 errx(1, "tried to delete an unexisting handle");
150 static void *
151 find_handle(struct handle *h, int32_t idx, enum handle_type type)
153 if (idx == 0)
154 return NULL;
156 while (h) {
157 if (h->idx == idx) {
158 if (type == h->type)
159 return h->ptr;
160 errx(1, "monger switched type on handle!");
162 h = h->next;
164 return NULL;
168 static int32_t
169 convert_gss_to_gsm(OM_uint32 maj_stat)
171 switch(maj_stat) {
172 case 0:
173 return GSMERR_OK;
174 case GSS_S_CONTINUE_NEEDED:
175 return GSMERR_CONTINUE_NEEDED;
176 case GSS_S_DEFECTIVE_TOKEN:
177 return GSMERR_INVALID_TOKEN;
178 case GSS_S_BAD_MIC:
179 return GSMERR_AP_MODIFIED;
180 default:
181 return GSMERR_ERROR;
185 static int32_t
186 convert_krb5_to_gsm(krb5_error_code ret)
188 switch(ret) {
189 case 0:
190 return GSMERR_OK;
191 default:
192 return GSMERR_ERROR;
200 static int32_t
201 acquire_cred(struct client *c,
202 krb5_principal principal,
203 krb5_get_init_creds_opt *opt,
204 int32_t *handle)
206 krb5_error_code ret;
207 krb5_creds cred;
208 krb5_ccache id;
209 gss_cred_id_t gcred;
210 OM_uint32 maj_stat, min_stat;
212 *handle = 0;
214 krb5_get_init_creds_opt_set_forwardable (opt, 1);
215 krb5_get_init_creds_opt_set_renew_life (opt, 3600 * 24 * 30);
217 memset(&cred, 0, sizeof(cred));
219 ret = krb5_get_init_creds_password (context,
220 &cred,
221 principal,
222 NULL,
223 NULL,
224 NULL,
226 NULL,
227 opt);
228 if (ret) {
229 logmessage(c, __FILE__, __LINE__, 0,
230 "krb5_get_init_creds failed: %d", ret);
231 return convert_krb5_to_gsm(ret);
234 ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id);
235 if (ret)
236 krb5_err (context, 1, ret, "krb5_cc_initialize");
238 ret = krb5_cc_initialize (context, id, cred.client);
239 if (ret)
240 krb5_err (context, 1, ret, "krb5_cc_initialize");
242 ret = krb5_cc_store_cred (context, id, &cred);
243 if (ret)
244 krb5_err (context, 1, ret, "krb5_cc_store_cred");
246 krb5_free_cred_contents (context, &cred);
248 maj_stat = gss_krb5_import_cred(&min_stat,
250 NULL,
251 NULL,
252 &gcred);
253 krb5_cc_close(context, id);
254 if (maj_stat) {
255 logmessage(c, __FILE__, __LINE__, 0,
256 "krb5 import creds failed with: %d", maj_stat);
257 return convert_gss_to_gsm(maj_stat);
260 *handle = add_handle(c, handle_cred, gcred);
262 return 0;
270 #define HandleOP(h) \
271 handle##h(enum gssMaggotOp op, struct client *c)
277 static int
278 HandleOP(GetVersionInfo)
280 put32(c, GSSMAGGOTPROTOCOL);
281 errx(1, "GetVersionInfo");
284 static int
285 HandleOP(GoodBye)
287 struct handle *h = c->handles;
288 int i = 0;
290 while (h) {
291 h = h->next;
292 i++;
295 if (i != 0)
296 logmessage(c, __FILE__, __LINE__, 0,
297 "Did not toast all resources: %d", i);
298 return 1;
301 static int
302 HandleOP(InitContext)
304 OM_uint32 maj_stat, min_stat, ret_flags;
305 int32_t hContext, hCred, flags;
306 krb5_data target_name, in_token;
307 int32_t new_context_id = 0, gsm_error = 0;
308 krb5_data out_token = { 0 , NULL };
310 gss_ctx_id_t ctx;
311 gss_cred_id_t creds;
312 gss_name_t gss_target_name;
313 gss_buffer_desc input_token, output_token;
314 gss_OID oid = GSS_C_NO_OID;
315 gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER;
317 ret32(c, hContext);
318 ret32(c, hCred);
319 ret32(c, flags);
320 retdata(c, target_name);
321 retdata(c, in_token);
323 logmessage(c, __FILE__, __LINE__, 0,
324 "targetname: <%.*s>", (int)target_name.length,
325 (char *)target_name.data);
327 ctx = find_handle(c->handles, hContext, handle_context);
328 if (ctx == NULL)
329 hContext = 0;
330 creds = find_handle(c->handles, hCred, handle_cred);
331 if (creds == NULL)
332 abort();
334 input_token.length = target_name.length;
335 input_token.value = target_name.data;
337 maj_stat = gss_import_name(&min_stat,
338 &input_token,
339 GSS_KRB5_NT_PRINCIPAL_NAME,
340 &gss_target_name);
341 if (GSS_ERROR(maj_stat)) {
342 logmessage(c, __FILE__, __LINE__, 0,
343 "import name creds failed with: %d", maj_stat);
344 gsm_error = convert_gss_to_gsm(maj_stat);
345 goto out;
348 /* oid from flags */
350 if (in_token.length) {
351 input_token.length = in_token.length;
352 input_token.value = in_token.data;
353 input_token_ptr = &input_token;
354 if (ctx == NULL)
355 krb5_errx(context, 1, "initcreds, context NULL, but not first req");
356 } else {
357 input_token.length = 0;
358 input_token.value = NULL;
359 if (ctx)
360 krb5_errx(context, 1, "initcreds, context not NULL, but first req");
363 if ((flags & GSS_C_DELEG_FLAG) != 0)
364 logmessage(c, __FILE__, __LINE__, 0, "init_sec_context delegating");
365 if ((flags & GSS_C_DCE_STYLE) != 0)
366 logmessage(c, __FILE__, __LINE__, 0, "init_sec_context dce-style");
368 maj_stat = gss_init_sec_context(&min_stat,
369 creds,
370 &ctx,
371 gss_target_name,
372 oid,
373 flags & 0x7f,
375 NULL,
376 input_token_ptr,
377 NULL,
378 &output_token,
379 &ret_flags,
380 NULL);
381 if (GSS_ERROR(maj_stat)) {
382 if (hContext != 0)
383 del_handle(&c->handles, hContext);
384 new_context_id = 0;
385 logmessage(c, __FILE__, __LINE__, 0,
386 "gss_init_sec_context returns code: %d/%d",
387 maj_stat, min_stat);
388 } else {
389 if (input_token.length == 0)
390 new_context_id = add_handle(c, handle_context, ctx);
391 else
392 new_context_id = hContext;
395 gsm_error = convert_gss_to_gsm(maj_stat);
397 if (output_token.length) {
398 out_token.data = output_token.value;
399 out_token.length = output_token.length;
402 out:
403 logmessage(c, __FILE__, __LINE__, 0,
404 "InitContext return code: %d", gsm_error);
406 put32(c, new_context_id);
407 put32(c, gsm_error);
408 putdata(c, out_token);
410 gss_release_name(&min_stat, &gss_target_name);
411 if (output_token.length)
412 gss_release_buffer(&min_stat, &output_token);
413 krb5_data_free(&in_token);
414 krb5_data_free(&target_name);
416 return 0;
419 static int
420 HandleOP(AcceptContext)
422 OM_uint32 maj_stat, min_stat, ret_flags;
423 int32_t hContext, deleg_hcred, flags;
424 krb5_data in_token;
425 int32_t new_context_id = 0, gsm_error = 0;
426 krb5_data out_token = { 0 , NULL };
428 gss_ctx_id_t ctx;
429 gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL;
430 gss_buffer_desc input_token, output_token;
431 gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER;
433 ret32(c, hContext);
434 ret32(c, flags);
435 retdata(c, in_token);
437 ctx = find_handle(c->handles, hContext, handle_context);
438 if (ctx == NULL)
439 hContext = 0;
441 if (in_token.length) {
442 input_token.length = in_token.length;
443 input_token.value = in_token.data;
444 input_token_ptr = &input_token;
445 } else {
446 input_token.length = 0;
447 input_token.value = NULL;
450 maj_stat = gss_accept_sec_context(&min_stat,
451 &ctx,
452 GSS_C_NO_CREDENTIAL,
453 &input_token,
454 GSS_C_NO_CHANNEL_BINDINGS,
455 NULL,
456 NULL,
457 &output_token,
458 &ret_flags,
459 NULL,
460 &deleg_cred);
461 if (GSS_ERROR(maj_stat)) {
462 if (hContext != 0)
463 del_handle(&c->handles, hContext);
464 logmessage(c, __FILE__, __LINE__, 0,
465 "gss_accept_sec_context returns code: %d/%d",
466 maj_stat, min_stat);
467 new_context_id = 0;
468 } else {
469 if (hContext == 0)
470 new_context_id = add_handle(c, handle_context, ctx);
471 else
472 new_context_id = hContext;
474 if (output_token.length) {
475 out_token.data = output_token.value;
476 out_token.length = output_token.length;
478 if ((ret_flags & GSS_C_DCE_STYLE) != 0)
479 logmessage(c, __FILE__, __LINE__, 0, "accept_sec_context dce-style");
480 if ((ret_flags & GSS_C_DELEG_FLAG) != 0) {
481 deleg_hcred = add_handle(c, handle_cred, deleg_cred);
482 logmessage(c, __FILE__, __LINE__, 0,
483 "accept_context delegated handle: %d", deleg_hcred);
484 } else {
485 gss_release_cred(&min_stat, &deleg_cred);
486 deleg_hcred = 0;
490 gsm_error = convert_gss_to_gsm(maj_stat);
492 put32(c, new_context_id);
493 put32(c, gsm_error);
494 putdata(c, out_token);
495 put32(c, deleg_hcred);
497 if (output_token.length)
498 gss_release_buffer(&min_stat, &output_token);
499 krb5_data_free(&in_token);
501 return 0;
504 static int
505 HandleOP(ToastResource)
507 int32_t handle;
509 ret32(c, handle);
510 logmessage(c, __FILE__, __LINE__, 0, "toasting %d", handle);
511 del_handle(&c->handles, handle);
512 put32(c, GSMERR_OK);
514 return 0;
517 static int
518 HandleOP(AcquireCreds)
520 char *name, *password;
521 int32_t gsm_error, flags, handle = 0;
522 krb5_principal principal = NULL;
523 krb5_get_init_creds_opt *opt = NULL;
524 krb5_error_code ret;
526 retstring(c, name);
527 retstring(c, password);
528 ret32(c, flags);
530 logmessage(c, __FILE__, __LINE__, 0,
531 "username: %s password: %s", name, password);
533 ret = krb5_parse_name(context, name, &principal);
534 if (ret) {
535 gsm_error = convert_krb5_to_gsm(ret);
536 goto out;
539 ret = krb5_get_init_creds_opt_alloc (context, &opt);
540 if (ret)
541 krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc");
543 krb5_get_init_creds_opt_set_pa_password(context, opt, password, NULL);
545 gsm_error = acquire_cred(c, principal, opt, &handle);
547 out:
548 logmessage(c, __FILE__, __LINE__, 0,
549 "AcquireCreds handle: %d return code: %d", handle, gsm_error);
551 if (opt)
552 krb5_get_init_creds_opt_free (context, opt);
553 if (principal)
554 krb5_free_principal(context, principal);
555 free(name);
556 free(password);
558 put32(c, gsm_error);
559 put32(c, handle);
561 return 0;
564 static int
565 HandleOP(Sign)
567 OM_uint32 maj_stat, min_stat;
568 int32_t hContext, flags, seqno;
569 krb5_data token;
570 gss_ctx_id_t ctx;
571 gss_buffer_desc input_token, output_token;
573 ret32(c, hContext);
574 ret32(c, flags);
575 ret32(c, seqno);
576 retdata(c, token);
578 ctx = find_handle(c->handles, hContext, handle_context);
579 if (ctx == NULL)
580 errx(1, "sign: reference to unknown context");
582 input_token.length = token.length;
583 input_token.value = token.data;
585 maj_stat = gss_get_mic(&min_stat, ctx, 0, &input_token,
586 &output_token);
587 if (maj_stat != GSS_S_COMPLETE)
588 errx(1, "gss_get_mic failed");
590 krb5_data_free(&token);
592 token.data = output_token.value;
593 token.length = output_token.length;
595 put32(c, 0); /* XXX fix gsm_error */
596 putdata(c, token);
598 gss_release_buffer(&min_stat, &output_token);
600 return 0;
603 static int
604 HandleOP(Verify)
606 OM_uint32 maj_stat, min_stat;
607 int32_t hContext, flags, seqno;
608 krb5_data msg, mic;
609 gss_ctx_id_t ctx;
610 gss_buffer_desc msg_token, mic_token;
611 gss_qop_t qop;
613 ret32(c, hContext);
615 ctx = find_handle(c->handles, hContext, handle_context);
616 if (ctx == NULL)
617 errx(1, "verify: reference to unknown context");
619 ret32(c, flags);
620 ret32(c, seqno);
621 retdata(c, msg);
623 msg_token.length = msg.length;
624 msg_token.value = msg.data;
626 retdata(c, mic);
628 mic_token.length = mic.length;
629 mic_token.value = mic.data;
631 maj_stat = gss_verify_mic(&min_stat, ctx, &msg_token,
632 &mic_token, &qop);
633 if (maj_stat != GSS_S_COMPLETE)
634 errx(1, "gss_verify_mic failed");
636 krb5_data_free(&mic);
637 krb5_data_free(&msg);
639 put32(c, 0); /* XXX fix gsm_error */
641 return 0;
644 static int
645 HandleOP(GetVersionAndCapabilities)
647 int32_t cap = HAS_MONIKER;
648 char name[256] = "unknown", *str;
650 if (targetname)
651 cap |= ISSERVER; /* is server */
653 #ifdef HAVE_UNAME
655 struct utsname ut;
656 if (uname(&ut) == 0) {
657 snprintf(name, sizeof(name), "%s-%s-%s",
658 ut.sysname, ut.version, ut.machine);
661 #endif
663 asprintf(&str, "gssmask %s %s", PACKAGE_STRING, name);
665 put32(c, GSSMAGGOTPROTOCOL);
666 put32(c, cap);
667 putstring(c, str);
668 free(str);
670 return 0;
673 static int
674 HandleOP(GetTargetName)
676 if (targetname)
677 putstring(c, targetname);
678 else
679 putstring(c, "");
680 return 0;
683 static int
684 HandleOP(SetLoggingSocket)
686 int32_t portnum;
687 int fd, ret;
689 ret32(c, portnum);
691 logmessage(c, __FILE__, __LINE__, 0,
692 "logging port on peer is: %d", (int)portnum);
694 socket_set_port((struct sockaddr *)(&c->sa), htons(portnum));
696 fd = socket(((struct sockaddr *)&c->sa)->sa_family, SOCK_STREAM, 0);
697 if (fd < 0)
698 return 0;
700 ret = connect(fd, (struct sockaddr *)&c->sa, c->salen);
701 if (ret < 0) {
702 logmessage(c, __FILE__, __LINE__, 0, "failed connect to log port: %s",
703 strerror(errno));
704 close(fd);
705 return 0;
708 if (c->logging)
709 krb5_storage_free(c->logging);
710 c->logging = krb5_storage_from_fd(fd);
711 close(fd);
713 krb5_store_int32(c->logging, eLogSetMoniker);
714 store_string(c->logging, c->moniker);
716 logmessage(c, __FILE__, __LINE__, 0, "logging turned on");
718 return 0;
722 static int
723 HandleOP(ChangePassword)
725 errx(1, "ChangePassword");
728 static int
729 HandleOP(SetPasswordSelf)
731 errx(1, "SetPasswordSelf");
734 static int
735 HandleOP(Wrap)
737 OM_uint32 maj_stat, min_stat;
738 int32_t hContext, flags, seqno;
739 krb5_data token;
740 gss_ctx_id_t ctx;
741 gss_buffer_desc input_token, output_token;
742 int conf_state;
744 ret32(c, hContext);
745 ret32(c, flags);
746 ret32(c, seqno);
747 retdata(c, token);
749 ctx = find_handle(c->handles, hContext, handle_context);
750 if (ctx == NULL)
751 errx(1, "wrap: reference to unknown context");
753 input_token.length = token.length;
754 input_token.value = token.data;
756 maj_stat = gss_wrap(&min_stat, ctx, flags, 0, &input_token,
757 &conf_state, &output_token);
758 if (maj_stat != GSS_S_COMPLETE)
759 errx(1, "gss_wrap failed");
761 krb5_data_free(&token);
763 token.data = output_token.value;
764 token.length = output_token.length;
766 put32(c, 0); /* XXX fix gsm_error */
767 putdata(c, token);
769 gss_release_buffer(&min_stat, &output_token);
771 return 0;
775 static int
776 HandleOP(Unwrap)
778 OM_uint32 maj_stat, min_stat;
779 int32_t hContext, flags, seqno;
780 krb5_data token;
781 gss_ctx_id_t ctx;
782 gss_buffer_desc input_token, output_token;
783 int conf_state;
784 gss_qop_t qop_state;
786 ret32(c, hContext);
787 ret32(c, flags);
788 ret32(c, seqno);
789 retdata(c, token);
791 ctx = find_handle(c->handles, hContext, handle_context);
792 if (ctx == NULL)
793 errx(1, "unwrap: reference to unknown context");
795 input_token.length = token.length;
796 input_token.value = token.data;
798 maj_stat = gss_unwrap(&min_stat, ctx, &input_token,
799 &output_token, &conf_state, &qop_state);
801 if (maj_stat != GSS_S_COMPLETE)
802 errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);
804 krb5_data_free(&token);
805 if (maj_stat == GSS_S_COMPLETE) {
806 token.data = output_token.value;
807 token.length = output_token.length;
808 } else {
809 token.data = NULL;
810 token.length = 0;
812 put32(c, 0); /* XXX fix gsm_error */
813 putdata(c, token);
815 if (maj_stat == GSS_S_COMPLETE)
816 gss_release_buffer(&min_stat, &output_token);
818 return 0;
821 static int
822 HandleOP(Encrypt)
824 return handleWrap(op, c);
827 static int
828 HandleOP(Decrypt)
830 return handleUnwrap(op, c);
833 static int
834 HandleOP(ConnectLoggingService2)
836 errx(1, "ConnectLoggingService2");
839 static int
840 HandleOP(GetMoniker)
842 putstring(c, c->moniker);
843 return 0;
846 static int
847 HandleOP(CallExtension)
849 errx(1, "CallExtension");
852 static int
853 HandleOP(AcquirePKInitCreds)
855 int32_t flags;
856 krb5_data pfxdata;
858 ret32(c, flags);
859 retdata(c, pfxdata);
861 /* get credentials */
863 krb5_data_free(&pfxdata);
865 put32(c, -1); /* hResource */
866 put32(c, GSMERR_NOT_SUPPORTED);
867 return 0;
874 struct handler {
875 enum gssMaggotOp op;
876 const char *name;
877 int (*func)(enum gssMaggotOp, struct client *);
880 #define S(a) { e##a, #a, handle##a }
882 struct handler handlers[] = {
883 S(GetVersionInfo),
884 S(GoodBye),
885 S(InitContext),
886 S(AcceptContext),
887 S(ToastResource),
888 S(AcquireCreds),
889 S(Encrypt),
890 S(Decrypt),
891 S(Sign),
892 S(Verify),
893 S(GetVersionAndCapabilities),
894 S(GetTargetName),
895 S(SetLoggingSocket),
896 S(ChangePassword),
897 S(SetPasswordSelf),
898 S(Wrap),
899 S(Unwrap),
900 S(ConnectLoggingService2),
901 S(GetMoniker),
902 S(CallExtension),
903 S(AcquirePKInitCreds)
906 #undef S
912 static struct handler *
913 find_op(int32_t op)
915 int i;
917 for (i = 0; i < sizeof(handlers)/sizeof(handlers[0]); i++)
918 if (handlers[i].op == op)
919 return &handlers[i];
920 return NULL;
923 static struct client *
924 create_client(int fd, int port, const char *moniker)
926 struct client *c;
928 c = ecalloc(1, sizeof(*c));
930 if (moniker) {
931 c->moniker = estrdup(moniker);
932 } else {
933 char hostname[MAXHOSTNAMELEN];
934 gethostname(hostname, sizeof(hostname));
935 asprintf(&c->moniker, "gssmask: %s:%d", hostname, port);
939 c->salen = sizeof(c->sa);
940 getpeername(fd, (struct sockaddr *)&c->sa, &c->salen);
942 getnameinfo((struct sockaddr *)&c->sa, c->salen,
943 c->servername, sizeof(c->servername),
944 NULL, 0, NI_NUMERICHOST);
947 c->sock = krb5_storage_from_fd(fd);
948 if (c->sock == NULL)
949 errx(1, "krb5_storage_from_fd");
951 close(fd);
953 return c;
956 static void
957 free_client(struct client *c)
959 while(c->handles)
960 del_handle(&c->handles, c->handles->idx);
962 free(c->moniker);
963 krb5_storage_free(c->sock);
964 if (c->logging)
965 krb5_storage_free(c->logging);
966 free(c);
970 static void *
971 handleServer(void *ptr)
973 struct handler *handler;
974 struct client *c;
975 int32_t op;
977 c = (struct client *)ptr;
980 while(1) {
981 ret32(c, op);
983 handler = find_op(op);
984 if (handler == NULL) {
985 logmessage(c, __FILE__, __LINE__, 0,
986 "op %d not supported", (int)op);
987 exit(1);
990 logmessage(c, __FILE__, __LINE__, 0,
991 "---> Got op %s from server %s",
992 handler->name, c->servername);
994 if ((handler->func)(handler->op, c))
995 break;
998 return NULL;
1002 static char *port_str;
1003 static int version_flag;
1004 static int help_flag;
1005 static char *logfile_str;
1006 static char *moniker_str;
1008 static int port = 4711;
1010 struct getargs args[] = {
1011 { "spn", 0, arg_string, &targetname, "This host's SPN",
1012 "service/host@REALM" },
1013 { "port", 'p', arg_string, &port_str, "Use this port",
1014 "number-of-service" },
1015 { "logfile", 0, arg_string, &logfile_str, "logfile",
1016 "number-of-service" },
1017 { "moniker", 0, arg_string, &moniker_str, "nickname",
1018 "name" },
1019 { "version", 0, arg_flag, &version_flag, "Print version",
1020 NULL },
1021 { "help", 0, arg_flag, &help_flag, NULL,
1022 NULL }
1025 static void
1026 usage(int ret)
1028 arg_printusage (args,
1029 sizeof(args) / sizeof(args[0]),
1030 NULL,
1031 "");
1032 exit (ret);
1036 main(int argc, char **argv)
1038 int optidx = 0;
1040 setprogname (argv[0]);
1042 if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
1043 usage (1);
1045 if (help_flag)
1046 usage (0);
1048 if (version_flag) {
1049 print_version (NULL);
1050 return 0;
1053 if (optidx != argc)
1054 usage (1);
1056 if (port_str) {
1057 char *ptr;
1059 port = strtol (port_str, &ptr, 10);
1060 if (port == 0 && ptr == port_str)
1061 errx (1, "Bad port `%s'", port_str);
1064 krb5_init_context(&context);
1067 const char *lf = logfile_str;
1068 if (lf == NULL)
1069 lf = "/dev/tty";
1071 logfile = fopen(lf, "w");
1072 if (logfile == NULL)
1073 err(1, "error opening %s", lf);
1076 mini_inetd(htons(port));
1077 fprintf(logfile, "connected\n");
1080 struct client *c;
1082 c = create_client(0, port, moniker_str);
1083 /* close(0); */
1085 handleServer(c);
1087 free_client(c);
1090 krb5_free_context(context);
1092 return 0;