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