1178825Sdfr/*
2233294Sstas * Copyright (c) 2006 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17178825Sdfr * 3. Neither the name of KTH nor the names of its contributors may be
18178825Sdfr *    used to endorse or promote products derived from this software without
19178825Sdfr *    specific prior written permission.
20178825Sdfr *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22178825Sdfr * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24178825Sdfr * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25178825Sdfr * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26178825Sdfr * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27178825Sdfr * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28178825Sdfr * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29178825Sdfr * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30178825Sdfr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31178825Sdfr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "common.h"
35233294SstasRCSID("$Id$");
36178825Sdfr
37178825Sdfr/*
38178825Sdfr *
39178825Sdfr */
40178825Sdfr
41178825Sdfrenum handle_type { handle_context, handle_cred };
42178825Sdfr
43178825Sdfrstruct handle {
44178825Sdfr    int32_t idx;
45178825Sdfr    enum handle_type type;
46178825Sdfr    void *ptr;
47178825Sdfr    struct handle *next;
48178825Sdfr};
49178825Sdfr
50178825Sdfrstruct client {
51178825Sdfr    krb5_storage *sock;
52178825Sdfr    krb5_storage *logging;
53178825Sdfr    char *moniker;
54178825Sdfr    int32_t nHandle;
55178825Sdfr    struct handle *handles;
56178825Sdfr    struct sockaddr_storage sa;
57178825Sdfr    socklen_t salen;
58178825Sdfr    char servername[MAXHOSTNAMELEN];
59178825Sdfr};
60178825Sdfr
61178825SdfrFILE *logfile;
62178825Sdfrstatic char *targetname;
63178825Sdfrkrb5_context context;
64178825Sdfr
65178825Sdfr/*
66178825Sdfr *
67178825Sdfr */
68178825Sdfr
69178825Sdfrstatic void
70178825Sdfrlogmessage(struct client *c, const char *file, unsigned int lineno,
71178825Sdfr	   int level, const char *fmt, ...)
72178825Sdfr{
73178825Sdfr    char *message;
74178825Sdfr    va_list ap;
75178825Sdfr    int32_t ackid;
76178825Sdfr
77178825Sdfr    va_start(ap, fmt);
78178825Sdfr    vasprintf(&message, fmt, ap);
79178825Sdfr    va_end(ap);
80178825Sdfr
81178825Sdfr    if (logfile)
82178825Sdfr	fprintf(logfile, "%s:%u: %d %s\n", file, lineno, level, message);
83178825Sdfr
84178825Sdfr    if (c->logging) {
85178825Sdfr	if (krb5_store_int32(c->logging, eLogInfo) != 0)
86178825Sdfr	    errx(1, "krb5_store_int32: log level");
87178825Sdfr	if (krb5_store_string(c->logging, file) != 0)
88178825Sdfr	    errx(1, "krb5_store_string: filename");
89178825Sdfr	if (krb5_store_int32(c->logging, lineno) != 0)
90178825Sdfr	    errx(1, "krb5_store_string: filename");
91178825Sdfr	if (krb5_store_string(c->logging, message) != 0)
92178825Sdfr	    errx(1, "krb5_store_string: message");
93178825Sdfr	if (krb5_ret_int32(c->logging, &ackid) != 0)
94178825Sdfr	    errx(1, "krb5_ret_int32: ackid");
95178825Sdfr    }
96178825Sdfr    free(message);
97178825Sdfr}
98178825Sdfr
99178825Sdfr/*
100178825Sdfr *
101178825Sdfr */
102178825Sdfr
103178825Sdfrstatic int32_t
104178825Sdfradd_handle(struct client *c, enum handle_type type, void *data)
105178825Sdfr{
106178825Sdfr    struct handle *h;
107178825Sdfr
108178825Sdfr    h = ecalloc(1, sizeof(*h));
109178825Sdfr
110178825Sdfr    h->idx = ++c->nHandle;
111178825Sdfr    h->type = type;
112178825Sdfr    h->ptr = data;
113178825Sdfr    h->next = c->handles;
114178825Sdfr    c->handles = h;
115178825Sdfr
116178825Sdfr    return h->idx;
117178825Sdfr}
118178825Sdfr
119178825Sdfrstatic void
120178825Sdfrdel_handle(struct handle **h, int32_t idx)
121178825Sdfr{
122178825Sdfr    OM_uint32 min_stat;
123178825Sdfr
124178825Sdfr    if (idx == 0)
125178825Sdfr	return;
126178825Sdfr
127178825Sdfr    while (*h) {
128178825Sdfr	if ((*h)->idx == idx) {
129178825Sdfr	    struct handle *p = *h;
130178825Sdfr	    *h = (*h)->next;
131178825Sdfr	    switch(p->type) {
132178825Sdfr	    case handle_context: {
133178825Sdfr		gss_ctx_id_t c = p->ptr;
134178825Sdfr		gss_delete_sec_context(&min_stat, &c, NULL);
135178825Sdfr		break; }
136178825Sdfr	    case handle_cred: {
137178825Sdfr		gss_cred_id_t c = p->ptr;
138178825Sdfr		gss_release_cred(&min_stat, &c);
139178825Sdfr		break; }
140178825Sdfr	    }
141178825Sdfr	    free(p);
142178825Sdfr	    return;
143178825Sdfr	}
144178825Sdfr	h = &((*h)->next);
145178825Sdfr    }
146178825Sdfr    errx(1, "tried to delete an unexisting handle");
147178825Sdfr}
148178825Sdfr
149178825Sdfrstatic void *
150178825Sdfrfind_handle(struct handle *h, int32_t idx, enum handle_type type)
151178825Sdfr{
152178825Sdfr    if (idx == 0)
153178825Sdfr	return NULL;
154233294Sstas
155178825Sdfr    while (h) {
156178825Sdfr	if (h->idx == idx) {
157178825Sdfr	    if (type == h->type)
158178825Sdfr		return h->ptr;
159178825Sdfr	    errx(1, "monger switched type on handle!");
160178825Sdfr	}
161178825Sdfr	h = h->next;
162178825Sdfr    }
163233294Sstas    return NULL;
164178825Sdfr}
165178825Sdfr
166178825Sdfr
167178825Sdfrstatic int32_t
168178825Sdfrconvert_gss_to_gsm(OM_uint32 maj_stat)
169178825Sdfr{
170178825Sdfr    switch(maj_stat) {
171178825Sdfr    case 0:
172178825Sdfr	return GSMERR_OK;
173178825Sdfr    case GSS_S_CONTINUE_NEEDED:
174178825Sdfr	return GSMERR_CONTINUE_NEEDED;
175178825Sdfr    case GSS_S_DEFECTIVE_TOKEN:
176178825Sdfr        return GSMERR_INVALID_TOKEN;
177178825Sdfr    case GSS_S_BAD_MIC:
178178825Sdfr	return GSMERR_AP_MODIFIED;
179178825Sdfr    default:
180178825Sdfr	return GSMERR_ERROR;
181178825Sdfr    }
182178825Sdfr}
183178825Sdfr
184178825Sdfrstatic int32_t
185178825Sdfrconvert_krb5_to_gsm(krb5_error_code ret)
186178825Sdfr{
187178825Sdfr    switch(ret) {
188178825Sdfr    case 0:
189178825Sdfr	return GSMERR_OK;
190178825Sdfr    default:
191178825Sdfr	return GSMERR_ERROR;
192178825Sdfr    }
193178825Sdfr}
194178825Sdfr
195178825Sdfr/*
196178825Sdfr *
197178825Sdfr */
198178825Sdfr
199178825Sdfrstatic int32_t
200178825Sdfracquire_cred(struct client *c,
201178825Sdfr	     krb5_principal principal,
202178825Sdfr	     krb5_get_init_creds_opt *opt,
203178825Sdfr	     int32_t *handle)
204178825Sdfr{
205178825Sdfr    krb5_error_code ret;
206178825Sdfr    krb5_creds cred;
207178825Sdfr    krb5_ccache id;
208178825Sdfr    gss_cred_id_t gcred;
209178825Sdfr    OM_uint32 maj_stat, min_stat;
210178825Sdfr
211178825Sdfr    *handle = 0;
212178825Sdfr
213178825Sdfr    krb5_get_init_creds_opt_set_forwardable (opt, 1);
214178825Sdfr    krb5_get_init_creds_opt_set_renew_life (opt, 3600 * 24 * 30);
215178825Sdfr
216178825Sdfr    memset(&cred, 0, sizeof(cred));
217178825Sdfr
218178825Sdfr    ret = krb5_get_init_creds_password (context,
219178825Sdfr					&cred,
220178825Sdfr					principal,
221178825Sdfr					NULL,
222178825Sdfr					NULL,
223178825Sdfr					NULL,
224178825Sdfr					0,
225178825Sdfr					NULL,
226178825Sdfr					opt);
227178825Sdfr    if (ret) {
228178825Sdfr	logmessage(c, __FILE__, __LINE__, 0,
229178825Sdfr		   "krb5_get_init_creds failed: %d", ret);
230178825Sdfr	return convert_krb5_to_gsm(ret);
231178825Sdfr    }
232233294Sstas
233178825Sdfr    ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id);
234178825Sdfr    if (ret)
235178825Sdfr	krb5_err (context, 1, ret, "krb5_cc_initialize");
236178825Sdfr
237178825Sdfr    ret = krb5_cc_initialize (context, id, cred.client);
238178825Sdfr    if (ret)
239178825Sdfr	krb5_err (context, 1, ret, "krb5_cc_initialize");
240233294Sstas
241178825Sdfr    ret = krb5_cc_store_cred (context, id, &cred);
242178825Sdfr    if (ret)
243178825Sdfr	krb5_err (context, 1, ret, "krb5_cc_store_cred");
244178825Sdfr
245178825Sdfr    krb5_free_cred_contents (context, &cred);
246178825Sdfr
247178825Sdfr    maj_stat = gss_krb5_import_cred(&min_stat,
248178825Sdfr				    id,
249178825Sdfr				    NULL,
250178825Sdfr				    NULL,
251178825Sdfr				    &gcred);
252178825Sdfr    krb5_cc_close(context, id);
253178825Sdfr    if (maj_stat) {
254178825Sdfr	logmessage(c, __FILE__, __LINE__, 0,
255178825Sdfr		   "krb5 import creds failed with: %d", maj_stat);
256178825Sdfr	return convert_gss_to_gsm(maj_stat);
257178825Sdfr    }
258178825Sdfr
259178825Sdfr    *handle = add_handle(c, handle_cred, gcred);
260178825Sdfr
261178825Sdfr    return 0;
262178825Sdfr}
263178825Sdfr
264178825Sdfr
265178825Sdfr/*
266178825Sdfr *
267178825Sdfr */
268178825Sdfr
269178825Sdfr#define HandleOP(h) \
270178825Sdfrhandle##h(enum gssMaggotOp op, struct client *c)
271178825Sdfr
272178825Sdfr/*
273178825Sdfr *
274178825Sdfr */
275178825Sdfr
276178825Sdfrstatic int
277178825SdfrHandleOP(GetVersionInfo)
278178825Sdfr{
279178825Sdfr    put32(c, GSSMAGGOTPROTOCOL);
280178825Sdfr    errx(1, "GetVersionInfo");
281178825Sdfr}
282178825Sdfr
283178825Sdfrstatic int
284178825SdfrHandleOP(GoodBye)
285178825Sdfr{
286178825Sdfr    struct handle *h = c->handles;
287233294Sstas    unsigned int i = 0;
288178825Sdfr
289178825Sdfr    while (h) {
290178825Sdfr	h = h->next;
291178825Sdfr	i++;
292178825Sdfr    }
293178825Sdfr
294233294Sstas    if (i)
295178825Sdfr	logmessage(c, __FILE__, __LINE__, 0,
296178825Sdfr		   "Did not toast all resources: %d", i);
297178825Sdfr    return 1;
298178825Sdfr}
299178825Sdfr
300178825Sdfrstatic int
301178825SdfrHandleOP(InitContext)
302178825Sdfr{
303178825Sdfr    OM_uint32 maj_stat, min_stat, ret_flags;
304178825Sdfr    int32_t hContext, hCred, flags;
305178825Sdfr    krb5_data target_name, in_token;
306178825Sdfr    int32_t new_context_id = 0, gsm_error = 0;
307178825Sdfr    krb5_data out_token = { 0 , NULL };
308178825Sdfr
309178825Sdfr    gss_ctx_id_t ctx;
310178825Sdfr    gss_cred_id_t creds;
311178825Sdfr    gss_name_t gss_target_name;
312178825Sdfr    gss_buffer_desc input_token, output_token;
313178825Sdfr    gss_OID oid = GSS_C_NO_OID;
314178825Sdfr    gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER;
315178825Sdfr
316178825Sdfr    ret32(c, hContext);
317178825Sdfr    ret32(c, hCred);
318178825Sdfr    ret32(c, flags);
319178825Sdfr    retdata(c, target_name);
320178825Sdfr    retdata(c, in_token);
321178825Sdfr
322178825Sdfr    logmessage(c, __FILE__, __LINE__, 0,
323178825Sdfr	       "targetname: <%.*s>", (int)target_name.length,
324178825Sdfr	       (char *)target_name.data);
325178825Sdfr
326178825Sdfr    ctx = find_handle(c->handles, hContext, handle_context);
327178825Sdfr    if (ctx == NULL)
328178825Sdfr	hContext = 0;
329178825Sdfr    creds = find_handle(c->handles, hCred, handle_cred);
330178825Sdfr    if (creds == NULL)
331178825Sdfr	abort();
332178825Sdfr
333178825Sdfr    input_token.length = target_name.length;
334178825Sdfr    input_token.value = target_name.data;
335178825Sdfr
336178825Sdfr    maj_stat = gss_import_name(&min_stat,
337178825Sdfr			       &input_token,
338178825Sdfr			       GSS_KRB5_NT_PRINCIPAL_NAME,
339178825Sdfr			       &gss_target_name);
340178825Sdfr    if (GSS_ERROR(maj_stat)) {
341178825Sdfr	logmessage(c, __FILE__, __LINE__, 0,
342178825Sdfr		   "import name creds failed with: %d", maj_stat);
343178825Sdfr	gsm_error = convert_gss_to_gsm(maj_stat);
344178825Sdfr	goto out;
345178825Sdfr    }
346178825Sdfr
347178825Sdfr    /* oid from flags */
348178825Sdfr
349178825Sdfr    if (in_token.length) {
350178825Sdfr	input_token.length = in_token.length;
351178825Sdfr	input_token.value = in_token.data;
352178825Sdfr	input_token_ptr = &input_token;
353178825Sdfr	if (ctx == NULL)
354178825Sdfr	    krb5_errx(context, 1, "initcreds, context NULL, but not first req");
355178825Sdfr    } else {
356178825Sdfr	input_token.length = 0;
357178825Sdfr	input_token.value = NULL;
358178825Sdfr	if (ctx)
359178825Sdfr	    krb5_errx(context, 1, "initcreds, context not NULL, but first req");
360178825Sdfr    }
361233294Sstas
362178825Sdfr    if ((flags & GSS_C_DELEG_FLAG) != 0)
363178825Sdfr	logmessage(c, __FILE__, __LINE__, 0, "init_sec_context delegating");
364178825Sdfr    if ((flags & GSS_C_DCE_STYLE) != 0)
365178825Sdfr	logmessage(c, __FILE__, __LINE__, 0, "init_sec_context dce-style");
366178825Sdfr
367178825Sdfr    maj_stat = gss_init_sec_context(&min_stat,
368178825Sdfr				    creds,
369178825Sdfr				    &ctx,
370178825Sdfr				    gss_target_name,
371178825Sdfr				    oid,
372178825Sdfr				    flags & 0x7f,
373233294Sstas				    0,
374178825Sdfr				    NULL,
375178825Sdfr				    input_token_ptr,
376178825Sdfr				    NULL,
377178825Sdfr				    &output_token,
378178825Sdfr				    &ret_flags,
379178825Sdfr				    NULL);
380178825Sdfr    if (GSS_ERROR(maj_stat)) {
381178825Sdfr	if (hContext != 0)
382178825Sdfr	    del_handle(&c->handles, hContext);
383178825Sdfr	new_context_id = 0;
384178825Sdfr	logmessage(c, __FILE__, __LINE__, 0,
385233294Sstas		   "gss_init_sec_context returns code: %d/%d",
386178825Sdfr		   maj_stat, min_stat);
387178825Sdfr    } else {
388178825Sdfr	if (input_token.length == 0)
389178825Sdfr	    new_context_id = add_handle(c, handle_context, ctx);
390178825Sdfr	else
391178825Sdfr	    new_context_id = hContext;
392178825Sdfr    }
393178825Sdfr
394178825Sdfr    gsm_error = convert_gss_to_gsm(maj_stat);
395178825Sdfr
396178825Sdfr    if (output_token.length) {
397178825Sdfr	out_token.data = output_token.value;
398178825Sdfr	out_token.length = output_token.length;
399178825Sdfr    }
400178825Sdfr
401178825Sdfrout:
402178825Sdfr    logmessage(c, __FILE__, __LINE__, 0,
403178825Sdfr	       "InitContext return code: %d", gsm_error);
404178825Sdfr
405178825Sdfr    put32(c, new_context_id);
406178825Sdfr    put32(c, gsm_error);
407178825Sdfr    putdata(c, out_token);
408178825Sdfr
409178825Sdfr    gss_release_name(&min_stat, &gss_target_name);
410178825Sdfr    if (output_token.length)
411178825Sdfr	gss_release_buffer(&min_stat, &output_token);
412178825Sdfr    krb5_data_free(&in_token);
413178825Sdfr    krb5_data_free(&target_name);
414178825Sdfr
415178825Sdfr    return 0;
416178825Sdfr}
417178825Sdfr
418178825Sdfrstatic int
419178825SdfrHandleOP(AcceptContext)
420178825Sdfr{
421178825Sdfr    OM_uint32 maj_stat, min_stat, ret_flags;
422178825Sdfr    int32_t hContext, deleg_hcred, flags;
423178825Sdfr    krb5_data in_token;
424178825Sdfr    int32_t new_context_id = 0, gsm_error = 0;
425178825Sdfr    krb5_data out_token = { 0 , NULL };
426178825Sdfr
427178825Sdfr    gss_ctx_id_t ctx;
428178825Sdfr    gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL;
429178825Sdfr    gss_buffer_desc input_token, output_token;
430178825Sdfr    gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER;
431178825Sdfr
432178825Sdfr    ret32(c, hContext);
433178825Sdfr    ret32(c, flags);
434178825Sdfr    retdata(c, in_token);
435178825Sdfr
436178825Sdfr    ctx = find_handle(c->handles, hContext, handle_context);
437178825Sdfr    if (ctx == NULL)
438178825Sdfr	hContext = 0;
439178825Sdfr
440178825Sdfr    if (in_token.length) {
441178825Sdfr	input_token.length = in_token.length;
442178825Sdfr	input_token.value = in_token.data;
443178825Sdfr	input_token_ptr = &input_token;
444178825Sdfr    } else {
445178825Sdfr	input_token.length = 0;
446178825Sdfr	input_token.value = NULL;
447178825Sdfr    }
448178825Sdfr
449178825Sdfr    maj_stat = gss_accept_sec_context(&min_stat,
450178825Sdfr				      &ctx,
451178825Sdfr				      GSS_C_NO_CREDENTIAL,
452178825Sdfr				      &input_token,
453178825Sdfr				      GSS_C_NO_CHANNEL_BINDINGS,
454178825Sdfr				      NULL,
455178825Sdfr				      NULL,
456178825Sdfr				      &output_token,
457178825Sdfr				      &ret_flags,
458178825Sdfr				      NULL,
459178825Sdfr				      &deleg_cred);
460178825Sdfr    if (GSS_ERROR(maj_stat)) {
461178825Sdfr	if (hContext != 0)
462178825Sdfr	    del_handle(&c->handles, hContext);
463178825Sdfr	logmessage(c, __FILE__, __LINE__, 0,
464233294Sstas		   "gss_accept_sec_context returns code: %d/%d",
465178825Sdfr		   maj_stat, min_stat);
466178825Sdfr	new_context_id = 0;
467178825Sdfr    } else {
468178825Sdfr	if (hContext == 0)
469178825Sdfr	    new_context_id = add_handle(c, handle_context, ctx);
470178825Sdfr	else
471178825Sdfr	    new_context_id = hContext;
472178825Sdfr    }
473178825Sdfr    if (output_token.length) {
474178825Sdfr	out_token.data = output_token.value;
475178825Sdfr	out_token.length = output_token.length;
476178825Sdfr    }
477178825Sdfr    if ((ret_flags & GSS_C_DCE_STYLE) != 0)
478178825Sdfr	logmessage(c, __FILE__, __LINE__, 0, "accept_sec_context dce-style");
479178825Sdfr    if ((ret_flags & GSS_C_DELEG_FLAG) != 0) {
480178825Sdfr	deleg_hcred = add_handle(c, handle_cred, deleg_cred);
481178825Sdfr	logmessage(c, __FILE__, __LINE__, 0,
482178825Sdfr		   "accept_context delegated handle: %d", deleg_hcred);
483178825Sdfr    } else {
484178825Sdfr	gss_release_cred(&min_stat, &deleg_cred);
485178825Sdfr	deleg_hcred = 0;
486178825Sdfr    }
487233294Sstas
488233294Sstas
489178825Sdfr    gsm_error = convert_gss_to_gsm(maj_stat);
490178825Sdfr
491178825Sdfr    put32(c, new_context_id);
492178825Sdfr    put32(c, gsm_error);
493178825Sdfr    putdata(c, out_token);
494178825Sdfr    put32(c, deleg_hcred);
495178825Sdfr
496178825Sdfr    if (output_token.length)
497178825Sdfr	gss_release_buffer(&min_stat, &output_token);
498178825Sdfr    krb5_data_free(&in_token);
499178825Sdfr
500178825Sdfr    return 0;
501178825Sdfr}
502178825Sdfr
503178825Sdfrstatic int
504178825SdfrHandleOP(ToastResource)
505178825Sdfr{
506178825Sdfr    int32_t handle;
507178825Sdfr
508178825Sdfr    ret32(c, handle);
509178825Sdfr    logmessage(c, __FILE__, __LINE__, 0, "toasting %d", handle);
510178825Sdfr    del_handle(&c->handles, handle);
511178825Sdfr    put32(c, GSMERR_OK);
512178825Sdfr
513178825Sdfr    return 0;
514178825Sdfr}
515178825Sdfr
516178825Sdfrstatic int
517178825SdfrHandleOP(AcquireCreds)
518178825Sdfr{
519178825Sdfr    char *name, *password;
520178825Sdfr    int32_t gsm_error, flags, handle = 0;
521178825Sdfr    krb5_principal principal = NULL;
522178825Sdfr    krb5_get_init_creds_opt *opt = NULL;
523178825Sdfr    krb5_error_code ret;
524178825Sdfr
525178825Sdfr    retstring(c, name);
526178825Sdfr    retstring(c, password);
527178825Sdfr    ret32(c, flags);
528178825Sdfr
529178825Sdfr    logmessage(c, __FILE__, __LINE__, 0,
530178825Sdfr	       "username: %s password: %s", name, password);
531178825Sdfr
532178825Sdfr    ret = krb5_parse_name(context, name, &principal);
533178825Sdfr    if (ret) {
534178825Sdfr	gsm_error = convert_krb5_to_gsm(ret);
535178825Sdfr	goto out;
536178825Sdfr    }
537233294Sstas
538178825Sdfr    ret = krb5_get_init_creds_opt_alloc (context, &opt);
539178825Sdfr    if (ret)
540178825Sdfr	krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc");
541233294Sstas
542178825Sdfr    krb5_get_init_creds_opt_set_pa_password(context, opt, password, NULL);
543178825Sdfr
544178825Sdfr    gsm_error = acquire_cred(c, principal, opt, &handle);
545178825Sdfr
546178825Sdfrout:
547178825Sdfr    logmessage(c, __FILE__, __LINE__, 0,
548178825Sdfr	       "AcquireCreds handle: %d return code: %d", handle, gsm_error);
549178825Sdfr
550178825Sdfr    if (opt)
551178825Sdfr	krb5_get_init_creds_opt_free (context, opt);
552178825Sdfr    if (principal)
553178825Sdfr	krb5_free_principal(context, principal);
554178825Sdfr    free(name);
555178825Sdfr    free(password);
556178825Sdfr
557178825Sdfr    put32(c, gsm_error);
558178825Sdfr    put32(c, handle);
559178825Sdfr
560178825Sdfr    return 0;
561178825Sdfr}
562178825Sdfr
563178825Sdfrstatic int
564178825SdfrHandleOP(Sign)
565178825Sdfr{
566178825Sdfr    OM_uint32 maj_stat, min_stat;
567178825Sdfr    int32_t hContext, flags, seqno;
568178825Sdfr    krb5_data token;
569178825Sdfr    gss_ctx_id_t ctx;
570178825Sdfr    gss_buffer_desc input_token, output_token;
571178825Sdfr
572178825Sdfr    ret32(c, hContext);
573178825Sdfr    ret32(c, flags);
574178825Sdfr    ret32(c, seqno);
575178825Sdfr    retdata(c, token);
576178825Sdfr
577178825Sdfr    ctx = find_handle(c->handles, hContext, handle_context);
578178825Sdfr    if (ctx == NULL)
579178825Sdfr	errx(1, "sign: reference to unknown context");
580178825Sdfr
581178825Sdfr    input_token.length = token.length;
582178825Sdfr    input_token.value = token.data;
583233294Sstas
584178825Sdfr    maj_stat = gss_get_mic(&min_stat, ctx, 0, &input_token,
585178825Sdfr			   &output_token);
586178825Sdfr    if (maj_stat != GSS_S_COMPLETE)
587178825Sdfr	errx(1, "gss_get_mic failed");
588233294Sstas
589178825Sdfr    krb5_data_free(&token);
590233294Sstas
591178825Sdfr    token.data = output_token.value;
592178825Sdfr    token.length = output_token.length;
593233294Sstas
594178825Sdfr    put32(c, 0); /* XXX fix gsm_error */
595178825Sdfr    putdata(c, token);
596233294Sstas
597178825Sdfr    gss_release_buffer(&min_stat, &output_token);
598233294Sstas
599178825Sdfr    return 0;
600178825Sdfr}
601178825Sdfr
602178825Sdfrstatic int
603178825SdfrHandleOP(Verify)
604178825Sdfr{
605178825Sdfr    OM_uint32 maj_stat, min_stat;
606178825Sdfr    int32_t hContext, flags, seqno;
607178825Sdfr    krb5_data msg, mic;
608178825Sdfr    gss_ctx_id_t ctx;
609178825Sdfr    gss_buffer_desc msg_token, mic_token;
610178825Sdfr    gss_qop_t qop;
611178825Sdfr
612178825Sdfr    ret32(c, hContext);
613178825Sdfr
614178825Sdfr    ctx = find_handle(c->handles, hContext, handle_context);
615178825Sdfr    if (ctx == NULL)
616178825Sdfr	errx(1, "verify: reference to unknown context");
617178825Sdfr
618178825Sdfr    ret32(c, flags);
619178825Sdfr    ret32(c, seqno);
620178825Sdfr    retdata(c, msg);
621178825Sdfr
622178825Sdfr    msg_token.length = msg.length;
623178825Sdfr    msg_token.value = msg.data;
624233294Sstas
625178825Sdfr    retdata(c, mic);
626178825Sdfr
627178825Sdfr    mic_token.length = mic.length;
628178825Sdfr    mic_token.value = mic.data;
629178825Sdfr
630178825Sdfr    maj_stat = gss_verify_mic(&min_stat, ctx, &msg_token,
631178825Sdfr			      &mic_token, &qop);
632178825Sdfr    if (maj_stat != GSS_S_COMPLETE)
633178825Sdfr	errx(1, "gss_verify_mic failed");
634233294Sstas
635178825Sdfr    krb5_data_free(&mic);
636178825Sdfr    krb5_data_free(&msg);
637233294Sstas
638178825Sdfr    put32(c, 0); /* XXX fix gsm_error */
639233294Sstas
640178825Sdfr    return 0;
641178825Sdfr}
642178825Sdfr
643178825Sdfrstatic int
644178825SdfrHandleOP(GetVersionAndCapabilities)
645178825Sdfr{
646178825Sdfr    int32_t cap = HAS_MONIKER;
647178825Sdfr    char name[256] = "unknown", *str;
648178825Sdfr
649178825Sdfr    if (targetname)
650178825Sdfr	cap |= ISSERVER; /* is server */
651178825Sdfr
652178825Sdfr#ifdef HAVE_UNAME
653178825Sdfr    {
654178825Sdfr	struct utsname ut;
655178825Sdfr	if (uname(&ut) == 0) {
656233294Sstas	    snprintf(name, sizeof(name), "%s-%s-%s",
657178825Sdfr		     ut.sysname, ut.version, ut.machine);
658178825Sdfr	}
659178825Sdfr    }
660178825Sdfr#endif
661178825Sdfr
662178825Sdfr    asprintf(&str, "gssmask %s %s", PACKAGE_STRING, name);
663178825Sdfr
664178825Sdfr    put32(c, GSSMAGGOTPROTOCOL);
665178825Sdfr    put32(c, cap);
666233294Sstas    putstring(c, str);
667178825Sdfr    free(str);
668178825Sdfr
669178825Sdfr    return 0;
670178825Sdfr}
671178825Sdfr
672178825Sdfrstatic int
673178825SdfrHandleOP(GetTargetName)
674178825Sdfr{
675178825Sdfr    if (targetname)
676178825Sdfr	putstring(c, targetname);
677178825Sdfr    else
678178825Sdfr	putstring(c, "");
679178825Sdfr    return 0;
680178825Sdfr}
681178825Sdfr
682178825Sdfrstatic int
683178825SdfrHandleOP(SetLoggingSocket)
684178825Sdfr{
685178825Sdfr    int32_t portnum;
686178825Sdfr    int fd, ret;
687178825Sdfr
688178825Sdfr    ret32(c, portnum);
689178825Sdfr
690178825Sdfr    logmessage(c, __FILE__, __LINE__, 0,
691178825Sdfr	       "logging port on peer is: %d", (int)portnum);
692178825Sdfr
693178825Sdfr    socket_set_port((struct sockaddr *)(&c->sa), htons(portnum));
694178825Sdfr
695178825Sdfr    fd = socket(((struct sockaddr *)&c->sa)->sa_family, SOCK_STREAM, 0);
696178825Sdfr    if (fd < 0)
697178825Sdfr	return 0;
698178825Sdfr
699178825Sdfr    ret = connect(fd, (struct sockaddr *)&c->sa, c->salen);
700178825Sdfr    if (ret < 0) {
701178825Sdfr	logmessage(c, __FILE__, __LINE__, 0, "failed connect to log port: %s",
702178825Sdfr		   strerror(errno));
703178825Sdfr	close(fd);
704178825Sdfr	return 0;
705178825Sdfr    }
706178825Sdfr
707178825Sdfr    if (c->logging)
708178825Sdfr	krb5_storage_free(c->logging);
709178825Sdfr    c->logging = krb5_storage_from_fd(fd);
710178825Sdfr    close(fd);
711178825Sdfr
712178825Sdfr    krb5_store_int32(c->logging, eLogSetMoniker);
713178825Sdfr    store_string(c->logging, c->moniker);
714233294Sstas
715178825Sdfr    logmessage(c, __FILE__, __LINE__, 0, "logging turned on");
716178825Sdfr
717178825Sdfr    return 0;
718178825Sdfr}
719178825Sdfr
720233294Sstas
721178825Sdfrstatic int
722178825SdfrHandleOP(ChangePassword)
723178825Sdfr{
724178825Sdfr    errx(1, "ChangePassword");
725178825Sdfr}
726178825Sdfr
727178825Sdfrstatic int
728178825SdfrHandleOP(SetPasswordSelf)
729178825Sdfr{
730178825Sdfr    errx(1, "SetPasswordSelf");
731178825Sdfr}
732178825Sdfr
733178825Sdfrstatic int
734178825SdfrHandleOP(Wrap)
735178825Sdfr{
736178825Sdfr    OM_uint32 maj_stat, min_stat;
737178825Sdfr    int32_t hContext, flags, seqno;
738178825Sdfr    krb5_data token;
739178825Sdfr    gss_ctx_id_t ctx;
740178825Sdfr    gss_buffer_desc input_token, output_token;
741178825Sdfr    int conf_state;
742178825Sdfr
743178825Sdfr    ret32(c, hContext);
744178825Sdfr    ret32(c, flags);
745178825Sdfr    ret32(c, seqno);
746178825Sdfr    retdata(c, token);
747178825Sdfr
748178825Sdfr    ctx = find_handle(c->handles, hContext, handle_context);
749178825Sdfr    if (ctx == NULL)
750178825Sdfr	errx(1, "wrap: reference to unknown context");
751178825Sdfr
752178825Sdfr    input_token.length = token.length;
753178825Sdfr    input_token.value = token.data;
754233294Sstas
755178825Sdfr    maj_stat = gss_wrap(&min_stat, ctx, flags, 0, &input_token,
756178825Sdfr			&conf_state, &output_token);
757178825Sdfr    if (maj_stat != GSS_S_COMPLETE)
758178825Sdfr	errx(1, "gss_wrap failed");
759233294Sstas
760178825Sdfr    krb5_data_free(&token);
761233294Sstas
762178825Sdfr    token.data = output_token.value;
763178825Sdfr    token.length = output_token.length;
764233294Sstas
765178825Sdfr    put32(c, 0); /* XXX fix gsm_error */
766178825Sdfr    putdata(c, token);
767233294Sstas
768178825Sdfr    gss_release_buffer(&min_stat, &output_token);
769233294Sstas
770178825Sdfr    return 0;
771178825Sdfr}
772178825Sdfr
773178825Sdfr
774178825Sdfrstatic int
775178825SdfrHandleOP(Unwrap)
776178825Sdfr{
777178825Sdfr    OM_uint32 maj_stat, min_stat;
778178825Sdfr    int32_t hContext, flags, seqno;
779178825Sdfr    krb5_data token;
780178825Sdfr    gss_ctx_id_t ctx;
781178825Sdfr    gss_buffer_desc input_token, output_token;
782178825Sdfr    int conf_state;
783178825Sdfr    gss_qop_t qop_state;
784178825Sdfr
785178825Sdfr    ret32(c, hContext);
786178825Sdfr    ret32(c, flags);
787178825Sdfr    ret32(c, seqno);
788178825Sdfr    retdata(c, token);
789178825Sdfr
790178825Sdfr    ctx = find_handle(c->handles, hContext, handle_context);
791178825Sdfr    if (ctx == NULL)
792178825Sdfr	errx(1, "unwrap: reference to unknown context");
793178825Sdfr
794178825Sdfr    input_token.length = token.length;
795178825Sdfr    input_token.value = token.data;
796233294Sstas
797178825Sdfr    maj_stat = gss_unwrap(&min_stat, ctx, &input_token,
798178825Sdfr			  &output_token, &conf_state, &qop_state);
799233294Sstas
800178825Sdfr    if (maj_stat != GSS_S_COMPLETE)
801178825Sdfr	errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);
802233294Sstas
803178825Sdfr    krb5_data_free(&token);
804178825Sdfr    if (maj_stat == GSS_S_COMPLETE) {
805178825Sdfr	token.data = output_token.value;
806178825Sdfr	token.length = output_token.length;
807178825Sdfr    } else {
808178825Sdfr	token.data = NULL;
809178825Sdfr	token.length = 0;
810178825Sdfr    }
811178825Sdfr    put32(c, 0); /* XXX fix gsm_error */
812178825Sdfr    putdata(c, token);
813178825Sdfr
814178825Sdfr    if (maj_stat == GSS_S_COMPLETE)
815178825Sdfr	gss_release_buffer(&min_stat, &output_token);
816178825Sdfr
817178825Sdfr    return 0;
818178825Sdfr}
819178825Sdfr
820178825Sdfrstatic int
821178825SdfrHandleOP(Encrypt)
822178825Sdfr{
823178825Sdfr    return handleWrap(op, c);
824178825Sdfr}
825178825Sdfr
826178825Sdfrstatic int
827178825SdfrHandleOP(Decrypt)
828178825Sdfr{
829178825Sdfr    return handleUnwrap(op, c);
830178825Sdfr}
831178825Sdfr
832178825Sdfrstatic int
833178825SdfrHandleOP(ConnectLoggingService2)
834178825Sdfr{
835178825Sdfr    errx(1, "ConnectLoggingService2");
836178825Sdfr}
837178825Sdfr
838178825Sdfrstatic int
839178825SdfrHandleOP(GetMoniker)
840178825Sdfr{
841178825Sdfr    putstring(c, c->moniker);
842178825Sdfr    return 0;
843178825Sdfr}
844178825Sdfr
845178825Sdfrstatic int
846178825SdfrHandleOP(CallExtension)
847178825Sdfr{
848178825Sdfr    errx(1, "CallExtension");
849178825Sdfr}
850178825Sdfr
851178825Sdfrstatic int
852178825SdfrHandleOP(AcquirePKInitCreds)
853178825Sdfr{
854178825Sdfr    int32_t flags;
855178825Sdfr    krb5_data pfxdata;
856233294Sstas    char fn[] = "FILE:/tmp/pkcs12-creds-XXXXXXX";
857233294Sstas    krb5_principal principal = NULL;
858233294Sstas    int fd;
859178825Sdfr
860178825Sdfr    ret32(c, flags);
861178825Sdfr    retdata(c, pfxdata);
862178825Sdfr
863233294Sstas    fd = mkstemp(fn + 5);
864233294Sstas    if (fd < 0)
865233294Sstas	errx(1, "mkstemp");
866178825Sdfr
867233294Sstas    net_write(fd, pfxdata.data, pfxdata.length);
868178825Sdfr    krb5_data_free(&pfxdata);
869233294Sstas    close(fd);
870178825Sdfr
871233294Sstas    if (principal)
872233294Sstas	krb5_free_principal(context, principal);
873233294Sstas
874178825Sdfr    put32(c, -1); /* hResource */
875178825Sdfr    put32(c, GSMERR_NOT_SUPPORTED);
876178825Sdfr    return 0;
877178825Sdfr}
878178825Sdfr
879233294Sstasstatic int
880233294SstasHandleOP(WrapExt)
881233294Sstas{
882233294Sstas    OM_uint32 maj_stat, min_stat;
883233294Sstas    int32_t hContext, flags, bflags;
884233294Sstas    krb5_data token, header, trailer;
885233294Sstas    gss_ctx_id_t ctx;
886233294Sstas    unsigned char *p;
887233294Sstas    int conf_state, iov_len;
888233294Sstas    gss_iov_buffer_desc iov[6];
889233294Sstas
890233294Sstas    ret32(c, hContext);
891233294Sstas    ret32(c, flags);
892233294Sstas    ret32(c, bflags);
893233294Sstas    retdata(c, header);
894233294Sstas    retdata(c, token);
895233294Sstas    retdata(c, trailer);
896233294Sstas
897233294Sstas    ctx = find_handle(c->handles, hContext, handle_context);
898233294Sstas    if (ctx == NULL)
899233294Sstas	errx(1, "wrap: reference to unknown context");
900233294Sstas
901233294Sstas    memset(&iov, 0, sizeof(iov));
902233294Sstas
903233294Sstas    iov_len = sizeof(iov)/sizeof(iov[0]);
904233294Sstas
905233294Sstas    if (bflags & WRAP_EXP_ONLY_HEADER)
906233294Sstas	iov_len -= 2; /* skip trailer and padding, aka dce-style */
907233294Sstas
908233294Sstas    iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
909233294Sstas    if (header.length != 0) {
910233294Sstas	iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
911233294Sstas	iov[1].buffer.length = header.length;
912233294Sstas	iov[1].buffer.value = header.data;
913233294Sstas    } else {
914233294Sstas	iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
915233294Sstas    }
916233294Sstas    iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
917233294Sstas    iov[2].buffer.length = token.length;
918233294Sstas    iov[2].buffer.value = token.data;
919233294Sstas    if (trailer.length != 0) {
920233294Sstas	iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
921233294Sstas	iov[3].buffer.length = trailer.length;
922233294Sstas	iov[3].buffer.value = trailer.data;
923233294Sstas    } else {
924233294Sstas	iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
925233294Sstas    }
926233294Sstas    iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
927233294Sstas    iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
928233294Sstas
929233294Sstas    maj_stat = gss_wrap_iov_length(&min_stat, ctx, flags, 0, &conf_state,
930233294Sstas				   iov, iov_len);
931233294Sstas    if (maj_stat != GSS_S_COMPLETE)
932233294Sstas	errx(1, "gss_wrap_iov_length failed");
933233294Sstas
934233294Sstas    maj_stat = gss_wrap_iov(&min_stat, ctx, flags, 0, &conf_state,
935233294Sstas			    iov, iov_len);
936233294Sstas    if (maj_stat != GSS_S_COMPLETE)
937233294Sstas	errx(1, "gss_wrap_iov failed");
938233294Sstas
939233294Sstas    krb5_data_free(&token);
940233294Sstas
941233294Sstas    token.length = iov[0].buffer.length + iov[2].buffer.length + iov[4].buffer.length + iov[5].buffer.length;
942233294Sstas    token.data = malloc(token.length);
943233294Sstas
944233294Sstas    p = token.data;
945233294Sstas    memcpy(p, iov[0].buffer.value, iov[0].buffer.length);
946233294Sstas    p += iov[0].buffer.length;
947233294Sstas    memcpy(p, iov[2].buffer.value, iov[2].buffer.length);
948233294Sstas    p += iov[2].buffer.length;
949233294Sstas    memcpy(p, iov[4].buffer.value, iov[4].buffer.length);
950233294Sstas    p += iov[4].buffer.length;
951233294Sstas    memcpy(p, iov[5].buffer.value, iov[5].buffer.length);
952233294Sstas    p += iov[5].buffer.length;
953233294Sstas
954233294Sstas    gss_release_iov_buffer(NULL, iov, iov_len);
955233294Sstas
956233294Sstas    put32(c, 0); /* XXX fix gsm_error */
957233294Sstas    putdata(c, token);
958233294Sstas
959233294Sstas    free(token.data);
960233294Sstas
961233294Sstas    return 0;
962233294Sstas}
963233294Sstas
964233294Sstas
965233294Sstasstatic int
966233294SstasHandleOP(UnwrapExt)
967233294Sstas{
968233294Sstas    OM_uint32 maj_stat, min_stat;
969233294Sstas    int32_t hContext, flags, bflags;
970233294Sstas    krb5_data token, header, trailer;
971233294Sstas    gss_ctx_id_t ctx;
972233294Sstas    gss_iov_buffer_desc iov[3];
973233294Sstas    int conf_state, iov_len;
974233294Sstas    gss_qop_t qop_state;
975233294Sstas
976233294Sstas    ret32(c, hContext);
977233294Sstas    ret32(c, flags);
978233294Sstas    ret32(c, bflags);
979233294Sstas    retdata(c, header);
980233294Sstas    retdata(c, token);
981233294Sstas    retdata(c, trailer);
982233294Sstas
983233294Sstas    iov_len = sizeof(iov)/sizeof(iov[0]);
984233294Sstas
985233294Sstas    if (bflags & WRAP_EXP_ONLY_HEADER)
986233294Sstas	iov_len -= 1; /* skip trailer and padding, aka dce-style */
987233294Sstas
988233294Sstas    ctx = find_handle(c->handles, hContext, handle_context);
989233294Sstas    if (ctx == NULL)
990233294Sstas	errx(1, "unwrap: reference to unknown context");
991233294Sstas
992233294Sstas    if (header.length != 0) {
993233294Sstas	iov[0].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
994233294Sstas	iov[0].buffer.length = header.length;
995233294Sstas	iov[0].buffer.value = header.data;
996233294Sstas    } else {
997233294Sstas	iov[0].type = GSS_IOV_BUFFER_TYPE_EMPTY;
998233294Sstas    }
999233294Sstas    iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
1000233294Sstas    iov[1].buffer.length = token.length;
1001233294Sstas    iov[1].buffer.value = token.data;
1002233294Sstas
1003233294Sstas    if (trailer.length != 0) {
1004233294Sstas	iov[2].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
1005233294Sstas	iov[2].buffer.length = trailer.length;
1006233294Sstas	iov[2].buffer.value = trailer.data;
1007233294Sstas    } else {
1008233294Sstas	iov[2].type = GSS_IOV_BUFFER_TYPE_EMPTY;
1009233294Sstas    }
1010233294Sstas
1011233294Sstas    maj_stat = gss_unwrap_iov(&min_stat, ctx, &conf_state, &qop_state,
1012233294Sstas			      iov, iov_len);
1013233294Sstas
1014233294Sstas    if (maj_stat != GSS_S_COMPLETE)
1015233294Sstas	errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);
1016233294Sstas
1017233294Sstas    if (maj_stat == GSS_S_COMPLETE) {
1018233294Sstas	token.data = iov[1].buffer.value;
1019233294Sstas	token.length = iov[1].buffer.length;
1020233294Sstas    } else {
1021233294Sstas	token.data = NULL;
1022233294Sstas	token.length = 0;
1023233294Sstas    }
1024233294Sstas    put32(c, 0); /* XXX fix gsm_error */
1025233294Sstas    putdata(c, token);
1026233294Sstas
1027233294Sstas    return 0;
1028233294Sstas}
1029233294Sstas
1030178825Sdfr/*
1031178825Sdfr *
1032178825Sdfr */
1033178825Sdfr
1034178825Sdfrstruct handler {
1035178825Sdfr    enum gssMaggotOp op;
1036178825Sdfr    const char *name;
1037178825Sdfr    int (*func)(enum gssMaggotOp, struct client *);
1038178825Sdfr};
1039178825Sdfr
1040178825Sdfr#define S(a) { e##a, #a, handle##a }
1041178825Sdfr
1042178825Sdfrstruct handler handlers[] = {
1043178825Sdfr    S(GetVersionInfo),
1044178825Sdfr    S(GoodBye),
1045178825Sdfr    S(InitContext),
1046178825Sdfr    S(AcceptContext),
1047178825Sdfr    S(ToastResource),
1048178825Sdfr    S(AcquireCreds),
1049178825Sdfr    S(Encrypt),
1050178825Sdfr    S(Decrypt),
1051178825Sdfr    S(Sign),
1052178825Sdfr    S(Verify),
1053178825Sdfr    S(GetVersionAndCapabilities),
1054178825Sdfr    S(GetTargetName),
1055178825Sdfr    S(SetLoggingSocket),
1056178825Sdfr    S(ChangePassword),
1057178825Sdfr    S(SetPasswordSelf),
1058178825Sdfr    S(Wrap),
1059178825Sdfr    S(Unwrap),
1060178825Sdfr    S(ConnectLoggingService2),
1061178825Sdfr    S(GetMoniker),
1062178825Sdfr    S(CallExtension),
1063233294Sstas    S(AcquirePKInitCreds),
1064233294Sstas    S(WrapExt),
1065233294Sstas    S(UnwrapExt),
1066178825Sdfr};
1067178825Sdfr
1068178825Sdfr#undef S
1069178825Sdfr
1070178825Sdfr/*
1071178825Sdfr *
1072178825Sdfr */
1073178825Sdfr
1074178825Sdfrstatic struct handler *
1075178825Sdfrfind_op(int32_t op)
1076178825Sdfr{
1077178825Sdfr    int i;
1078178825Sdfr
1079178825Sdfr    for (i = 0; i < sizeof(handlers)/sizeof(handlers[0]); i++)
1080178825Sdfr	if (handlers[i].op == op)
1081178825Sdfr	    return &handlers[i];
1082178825Sdfr    return NULL;
1083178825Sdfr}
1084178825Sdfr
1085178825Sdfrstatic struct client *
1086178825Sdfrcreate_client(int fd, int port, const char *moniker)
1087178825Sdfr{
1088178825Sdfr    struct client *c;
1089178825Sdfr
1090178825Sdfr    c = ecalloc(1, sizeof(*c));
1091178825Sdfr
1092178825Sdfr    if (moniker) {
1093178825Sdfr	c->moniker = estrdup(moniker);
1094178825Sdfr    } else {
1095178825Sdfr	char hostname[MAXHOSTNAMELEN];
1096178825Sdfr	gethostname(hostname, sizeof(hostname));
1097178825Sdfr	asprintf(&c->moniker, "gssmask: %s:%d", hostname, port);
1098178825Sdfr    }
1099178825Sdfr
1100178825Sdfr    {
1101178825Sdfr	c->salen = sizeof(c->sa);
1102178825Sdfr	getpeername(fd, (struct sockaddr *)&c->sa, &c->salen);
1103233294Sstas
1104233294Sstas	getnameinfo((struct sockaddr *)&c->sa, c->salen,
1105233294Sstas		    c->servername, sizeof(c->servername),
1106178825Sdfr		    NULL, 0, NI_NUMERICHOST);
1107178825Sdfr    }
1108178825Sdfr
1109178825Sdfr    c->sock = krb5_storage_from_fd(fd);
1110178825Sdfr    if (c->sock == NULL)
1111178825Sdfr	errx(1, "krb5_storage_from_fd");
1112233294Sstas
1113178825Sdfr    close(fd);
1114178825Sdfr
1115178825Sdfr    return c;
1116178825Sdfr}
1117178825Sdfr
1118178825Sdfrstatic void
1119178825Sdfrfree_client(struct client *c)
1120178825Sdfr{
1121178825Sdfr    while(c->handles)
1122178825Sdfr	del_handle(&c->handles, c->handles->idx);
1123178825Sdfr
1124178825Sdfr    free(c->moniker);
1125178825Sdfr    krb5_storage_free(c->sock);
1126178825Sdfr    if (c->logging)
1127178825Sdfr	krb5_storage_free(c->logging);
1128178825Sdfr    free(c);
1129178825Sdfr}
1130178825Sdfr
1131178825Sdfr
1132178825Sdfrstatic void *
1133178825SdfrhandleServer(void *ptr)
1134178825Sdfr{
1135178825Sdfr    struct handler *handler;
1136178825Sdfr    struct client *c;
1137178825Sdfr    int32_t op;
1138178825Sdfr
1139178825Sdfr    c = (struct client *)ptr;
1140178825Sdfr
1141178825Sdfr
1142178825Sdfr    while(1) {
1143178825Sdfr	ret32(c, op);
1144178825Sdfr
1145178825Sdfr	handler = find_op(op);
1146178825Sdfr	if (handler == NULL) {
1147178825Sdfr	    logmessage(c, __FILE__, __LINE__, 0,
1148178825Sdfr		       "op %d not supported", (int)op);
1149178825Sdfr	    exit(1);
1150178825Sdfr	}
1151178825Sdfr
1152178825Sdfr	logmessage(c, __FILE__, __LINE__, 0,
1153233294Sstas		   "---> Got op %s from server %s",
1154178825Sdfr		   handler->name, c->servername);
1155178825Sdfr
1156178825Sdfr	if ((handler->func)(handler->op, c))
1157178825Sdfr	    break;
1158178825Sdfr    }
1159178825Sdfr
1160178825Sdfr    return NULL;
1161178825Sdfr}
1162178825Sdfr
1163178825Sdfr
1164178825Sdfrstatic char *port_str;
1165178825Sdfrstatic int version_flag;
1166178825Sdfrstatic int help_flag;
1167178825Sdfrstatic char *logfile_str;
1168178825Sdfrstatic char *moniker_str;
1169178825Sdfr
1170178825Sdfrstatic int port = 4711;
1171178825Sdfr
1172178825Sdfrstruct getargs args[] = {
1173178825Sdfr    { "spn",	0,   arg_string,	&targetname,	"This host's SPN",
1174178825Sdfr      "service/host@REALM" },
1175178825Sdfr    { "port",	'p', arg_string,	&port_str,	"Use this port",
1176178825Sdfr      "number-of-service" },
1177178825Sdfr    { "logfile", 0,  arg_string,	&logfile_str,	"logfile",
1178178825Sdfr      "number-of-service" },
1179178825Sdfr    { "moniker", 0,  arg_string,	&moniker_str,	"nickname",
1180178825Sdfr      "name" },
1181178825Sdfr    { "version", 0,  arg_flag,		&version_flag,	"Print version",
1182178825Sdfr      NULL },
1183178825Sdfr    { "help",	 0,  arg_flag,		&help_flag,	NULL,
1184178825Sdfr      NULL }
1185178825Sdfr};
1186178825Sdfr
1187178825Sdfrstatic void
1188178825Sdfrusage(int ret)
1189178825Sdfr{
1190178825Sdfr    arg_printusage (args,
1191178825Sdfr		    sizeof(args) / sizeof(args[0]),
1192178825Sdfr		    NULL,
1193178825Sdfr		    "");
1194178825Sdfr    exit (ret);
1195178825Sdfr}
1196178825Sdfr
1197178825Sdfrint
1198178825Sdfrmain(int argc, char **argv)
1199178825Sdfr{
1200178825Sdfr    int optidx	= 0;
1201178825Sdfr
1202178825Sdfr    setprogname (argv[0]);
1203178825Sdfr
1204178825Sdfr    if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
1205178825Sdfr	usage (1);
1206178825Sdfr
1207178825Sdfr    if (help_flag)
1208178825Sdfr	usage (0);
1209178825Sdfr
1210178825Sdfr    if (version_flag) {
1211178825Sdfr	print_version (NULL);
1212178825Sdfr	return 0;
1213178825Sdfr    }
1214178825Sdfr
1215178825Sdfr    if (optidx != argc)
1216178825Sdfr	usage (1);
1217178825Sdfr
1218178825Sdfr    if (port_str) {
1219178825Sdfr	char *ptr;
1220178825Sdfr
1221178825Sdfr	port = strtol (port_str, &ptr, 10);
1222178825Sdfr	if (port == 0 && ptr == port_str)
1223178825Sdfr	    errx (1, "Bad port `%s'", port_str);
1224178825Sdfr    }
1225178825Sdfr
1226178825Sdfr    krb5_init_context(&context);
1227178825Sdfr
1228178825Sdfr    {
1229178825Sdfr	const char *lf = logfile_str;
1230178825Sdfr	if (lf == NULL)
1231178825Sdfr	    lf = "/dev/tty";
1232178825Sdfr
1233178825Sdfr	logfile = fopen(lf, "w");
1234178825Sdfr	if (logfile == NULL)
1235178825Sdfr	    err(1, "error opening %s", lf);
1236178825Sdfr    }
1237178825Sdfr
1238233294Sstas    mini_inetd(htons(port), NULL);
1239178825Sdfr    fprintf(logfile, "connected\n");
1240178825Sdfr
1241178825Sdfr    {
1242233294Sstas	struct client *c;
1243178825Sdfr
1244178825Sdfr	c = create_client(0, port, moniker_str);
1245178825Sdfr	/* close(0); */
1246178825Sdfr
1247178825Sdfr	handleServer(c);
1248178825Sdfr
1249178825Sdfr	free_client(c);
1250178825Sdfr    }
1251178825Sdfr
1252178825Sdfr    krb5_free_context(context);
1253178825Sdfr
1254178825Sdfr    return 0;
1255178825Sdfr}
1256