2 * Copyright (c) 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
41 enum handle_type { handle_context, handle_cred };
45 enum handle_type type;
52 krb5_storage *logging;
55 struct handle *handles;
56 struct sockaddr_storage sa;
58 char servername[MAXHOSTNAMELEN];
62 static char *targetname;
70 logmessage(struct client *c, const char *file, unsigned int lineno,
71 int level, const char *fmt, ...)
78 vasprintf(&message, fmt, ap);
82 fprintf(logfile, "%s:%u: %d %s\n", file, lineno, level, message);
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");
104 add_handle(struct client *c, enum handle_type type, void *data)
108 h = ecalloc(1, sizeof(*h));
110 h->idx = ++c->nHandle;
113 h->next = c->handles;
120 del_handle(struct handle **h, int32_t idx)
128 if ((*h)->idx == idx) {
129 struct handle *p = *h;
132 case handle_context: {
133 gss_ctx_id_t c = p->ptr;
134 gss_delete_sec_context(&min_stat, &c, NULL);
137 gss_cred_id_t c = p->ptr;
138 gss_release_cred(&min_stat, &c);
146 errx(1, "tried to delete an unexisting handle");
150 find_handle(struct handle *h, int32_t idx, enum handle_type type)
159 errx(1, "monger switched type on handle!");
168 convert_gss_to_gsm(OM_uint32 maj_stat)
173 case GSS_S_CONTINUE_NEEDED:
174 return GSMERR_CONTINUE_NEEDED;
175 case GSS_S_DEFECTIVE_TOKEN:
176 return GSMERR_INVALID_TOKEN;
178 return GSMERR_AP_MODIFIED;
185 convert_krb5_to_gsm(krb5_error_code ret)
200 acquire_cred(struct client *c,
201 krb5_principal principal,
202 krb5_get_init_creds_opt *opt,
209 OM_uint32 maj_stat, min_stat;
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,
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);
235 krb5_err (context, 1, ret, "krb5_cc_initialize");
237 ret = krb5_cc_initialize (context, id, cred.client);
239 krb5_err (context, 1, ret, "krb5_cc_initialize");
241 ret = krb5_cc_store_cred (context, id, &cred);
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,
252 krb5_cc_close(context, id);
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);
269 #define HandleOP(h) \
270 handle##h(enum gssMaggotOp op, struct client *c)
277 HandleOP(GetVersionInfo)
279 put32(c, GSSMAGGOTPROTOCOL);
280 errx(1, "GetVersionInfo");
286 struct handle *h = c->handles;
295 logmessage(c, __FILE__, __LINE__, 0,
296 "Did not toast all resources: %d", i);
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 };
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;
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);
329 creds = find_handle(c->handles, hCred, handle_cred);
333 input_token.length = target_name.length;
334 input_token.value = target_name.data;
336 maj_stat = gss_import_name(&min_stat,
338 GSS_KRB5_NT_PRINCIPAL_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);
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;
354 krb5_errx(context, 1, "initcreds, context NULL, but not first req");
356 input_token.length = 0;
357 input_token.value = NULL;
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,
380 if (GSS_ERROR(maj_stat)) {
382 del_handle(&c->handles, hContext);
384 logmessage(c, __FILE__, __LINE__, 0,
385 "gss_init_sec_context returns code: %d/%d",
388 if (input_token.length == 0)
389 new_context_id = add_handle(c, handle_context, ctx);
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;
402 logmessage(c, __FILE__, __LINE__, 0,
403 "InitContext return code: %d", gsm_error);
405 put32(c, new_context_id);
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);
419 HandleOP(AcceptContext)
421 OM_uint32 maj_stat, min_stat, ret_flags;
422 int32_t hContext, deleg_hcred, flags;
424 int32_t new_context_id = 0, gsm_error = 0;
425 krb5_data out_token = { 0 , NULL };
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;
434 retdata(c, in_token);
436 ctx = find_handle(c->handles, hContext, handle_context);
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;
445 input_token.length = 0;
446 input_token.value = NULL;
449 maj_stat = gss_accept_sec_context(&min_stat,
453 GSS_C_NO_CHANNEL_BINDINGS,
460 if (GSS_ERROR(maj_stat)) {
462 del_handle(&c->handles, hContext);
463 logmessage(c, __FILE__, __LINE__, 0,
464 "gss_accept_sec_context returns code: %d/%d",
469 new_context_id = add_handle(c, handle_context, ctx);
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);
484 gss_release_cred(&min_stat, &deleg_cred);
489 gsm_error = convert_gss_to_gsm(maj_stat);
491 put32(c, new_context_id);
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);
504 HandleOP(ToastResource)
509 logmessage(c, __FILE__, __LINE__, 0, "toasting %d", handle);
510 del_handle(&c->handles, handle);
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;
526 retstring(c, password);
529 logmessage(c, __FILE__, __LINE__, 0,
530 "username: %s password: %s", name, password);
532 ret = krb5_parse_name(context, name, &principal);
534 gsm_error = convert_krb5_to_gsm(ret);
538 ret = krb5_get_init_creds_opt_alloc (context, &opt);
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);
547 logmessage(c, __FILE__, __LINE__, 0,
548 "AcquireCreds handle: %d return code: %d", handle, gsm_error);
551 krb5_get_init_creds_opt_free (context, opt);
553 krb5_free_principal(context, principal);
566 OM_uint32 maj_stat, min_stat;
567 int32_t hContext, flags, seqno;
570 gss_buffer_desc input_token, output_token;
577 ctx = find_handle(c->handles, hContext, handle_context);
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,
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 */
597 gss_release_buffer(&min_stat, &output_token);
605 OM_uint32 maj_stat, min_stat;
606 int32_t hContext, flags, seqno;
609 gss_buffer_desc msg_token, mic_token;
614 ctx = find_handle(c->handles, hContext, handle_context);
616 errx(1, "verify: reference to unknown context");
622 msg_token.length = msg.length;
623 msg_token.value = msg.data;
627 mic_token.length = mic.length;
628 mic_token.value = mic.data;
630 maj_stat = gss_verify_mic(&min_stat, ctx, &msg_token,
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 */
644 HandleOP(GetVersionAndCapabilities)
646 int32_t cap = HAS_MONIKER;
647 char name[256] = "unknown", *str;
650 cap |= ISSERVER; /* is server */
655 if (uname(&ut) == 0) {
656 snprintf(name, sizeof(name), "%s-%s-%s",
657 ut.sysname, ut.version, ut.machine);
662 asprintf(&str, "gssmask %s %s", PACKAGE_STRING, name);
664 put32(c, GSSMAGGOTPROTOCOL);
673 HandleOP(GetTargetName)
676 putstring(c, targetname);
683 HandleOP(SetLoggingSocket)
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);
699 ret = connect(fd, (struct sockaddr *)&c->sa, c->salen);
701 logmessage(c, __FILE__, __LINE__, 0, "failed connect to log port: %s",
708 krb5_storage_free(c->logging);
709 c->logging = krb5_storage_from_fd(fd);
712 krb5_store_int32(c->logging, eLogSetMoniker);
713 store_string(c->logging, c->moniker);
715 logmessage(c, __FILE__, __LINE__, 0, "logging turned on");
722 HandleOP(ChangePassword)
724 errx(1, "ChangePassword");
728 HandleOP(SetPasswordSelf)
730 errx(1, "SetPasswordSelf");
736 OM_uint32 maj_stat, min_stat;
737 int32_t hContext, flags, seqno;
740 gss_buffer_desc input_token, output_token;
748 ctx = find_handle(c->handles, hContext, handle_context);
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 */
768 gss_release_buffer(&min_stat, &output_token);
777 OM_uint32 maj_stat, min_stat;
778 int32_t hContext, flags, seqno;
781 gss_buffer_desc input_token, output_token;
790 ctx = find_handle(c->handles, hContext, handle_context);
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;
811 put32(c, 0); /* XXX fix gsm_error */
814 if (maj_stat == GSS_S_COMPLETE)
815 gss_release_buffer(&min_stat, &output_token);
823 return handleWrap(op, c);
829 return handleUnwrap(op, c);
833 HandleOP(ConnectLoggingService2)
835 errx(1, "ConnectLoggingService2");
841 putstring(c, c->moniker);
846 HandleOP(CallExtension)
848 errx(1, "CallExtension");
852 HandleOP(AcquirePKInitCreds)
856 char fn[] = "FILE:/tmp/pkcs12-creds-XXXXXXX";
857 krb5_principal principal = NULL;
863 fd = mkstemp(fn + 5);
867 net_write(fd, pfxdata.data, pfxdata.length);
868 krb5_data_free(&pfxdata);
872 krb5_free_principal(context, principal);
874 put32(c, -1); /* hResource */
875 put32(c, GSMERR_NOT_SUPPORTED);
882 OM_uint32 maj_stat, min_stat;
883 int32_t hContext, flags, bflags;
884 krb5_data token, header, trailer;
887 int conf_state, iov_len;
888 gss_iov_buffer_desc iov[6];
897 ctx = find_handle(c->handles, hContext, handle_context);
899 errx(1, "wrap: reference to unknown context");
901 memset(&iov, 0, sizeof(iov));
903 iov_len = sizeof(iov)/sizeof(iov[0]);
905 if (bflags & WRAP_EXP_ONLY_HEADER)
906 iov_len -= 2; /* skip trailer and padding, aka dce-style */
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;
914 iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
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;
924 iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
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;
929 maj_stat = gss_wrap_iov_length(&min_stat, ctx, flags, 0, &conf_state,
931 if (maj_stat != GSS_S_COMPLETE)
932 errx(1, "gss_wrap_iov_length failed");
934 maj_stat = gss_wrap_iov(&min_stat, ctx, flags, 0, &conf_state,
936 if (maj_stat != GSS_S_COMPLETE)
937 errx(1, "gss_wrap_iov failed");
939 krb5_data_free(&token);
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);
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;
954 gss_release_iov_buffer(NULL, iov, iov_len);
956 put32(c, 0); /* XXX fix gsm_error */
968 OM_uint32 maj_stat, min_stat;
969 int32_t hContext, flags, bflags;
970 krb5_data token, header, trailer;
972 gss_iov_buffer_desc iov[3];
973 int conf_state, iov_len;
983 iov_len = sizeof(iov)/sizeof(iov[0]);
985 if (bflags & WRAP_EXP_ONLY_HEADER)
986 iov_len -= 1; /* skip trailer and padding, aka dce-style */
988 ctx = find_handle(c->handles, hContext, handle_context);
990 errx(1, "unwrap: reference to unknown context");
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;
997 iov[0].type = GSS_IOV_BUFFER_TYPE_EMPTY;
999 iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
1000 iov[1].buffer.length = token.length;
1001 iov[1].buffer.value = token.data;
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;
1008 iov[2].type = GSS_IOV_BUFFER_TYPE_EMPTY;
1011 maj_stat = gss_unwrap_iov(&min_stat, ctx, &conf_state, &qop_state,
1014 if (maj_stat != GSS_S_COMPLETE)
1015 errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);
1017 if (maj_stat == GSS_S_COMPLETE) {
1018 token.data = iov[1].buffer.value;
1019 token.length = iov[1].buffer.length;
1024 put32(c, 0); /* XXX fix gsm_error */
1035 enum gssMaggotOp op;
1037 int (*func)(enum gssMaggotOp, struct client *);
1040 #define S(a) { e##a, #a, handle##a }
1042 struct handler handlers[] = {
1053 S(GetVersionAndCapabilities),
1055 S(SetLoggingSocket),
1060 S(ConnectLoggingService2),
1063 S(AcquirePKInitCreds),
1074 static struct handler *
1079 for (i = 0; i < sizeof(handlers)/sizeof(handlers[0]); i++)
1080 if (handlers[i].op == op)
1081 return &handlers[i];
1085 static struct client *
1086 create_client(int fd, int port, const char *moniker)
1090 c = ecalloc(1, sizeof(*c));
1093 c->moniker = estrdup(moniker);
1095 char hostname[MAXHOSTNAMELEN];
1096 gethostname(hostname, sizeof(hostname));
1097 asprintf(&c->moniker, "gssmask: %s:%d", hostname, port);
1101 c->salen = sizeof(c->sa);
1102 getpeername(fd, (struct sockaddr *)&c->sa, &c->salen);
1104 getnameinfo((struct sockaddr *)&c->sa, c->salen,
1105 c->servername, sizeof(c->servername),
1106 NULL, 0, NI_NUMERICHOST);
1109 c->sock = krb5_storage_from_fd(fd);
1110 if (c->sock == NULL)
1111 errx(1, "krb5_storage_from_fd");
1119 free_client(struct client *c)
1122 del_handle(&c->handles, c->handles->idx);
1125 krb5_storage_free(c->sock);
1127 krb5_storage_free(c->logging);
1133 handleServer(void *ptr)
1135 struct handler *handler;
1139 c = (struct client *)ptr;
1145 handler = find_op(op);
1146 if (handler == NULL) {
1147 logmessage(c, __FILE__, __LINE__, 0,
1148 "op %d not supported", (int)op);
1152 logmessage(c, __FILE__, __LINE__, 0,
1153 "---> Got op %s from server %s",
1154 handler->name, c->servername);
1156 if ((handler->func)(handler->op, c))
1164 static char *port_str;
1165 static int version_flag;
1166 static int help_flag;
1167 static char *logfile_str;
1168 static char *moniker_str;
1170 static int port = 4711;
1172 struct 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",
1181 { "version", 0, arg_flag, &version_flag, "Print version",
1183 { "help", 0, arg_flag, &help_flag, NULL,
1190 arg_printusage (args,
1191 sizeof(args) / sizeof(args[0]),
1198 main(int argc, char **argv)
1202 setprogname (argv[0]);
1204 if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
1211 print_version (NULL);
1221 port = strtol (port_str, &ptr, 10);
1222 if (port == 0 && ptr == port_str)
1223 errx (1, "Bad port `%s'", port_str);
1226 krb5_init_context(&context);
1229 const char *lf = logfile_str;
1233 logfile = fopen(lf, "w");
1234 if (logfile == NULL)
1235 err(1, "error opening %s", lf);
1238 mini_inetd(htons(port), NULL);
1239 fprintf(logfile, "connected\n");
1244 c = create_client(0, port, moniker_str);
1252 krb5_free_context(context);