1120945Snectar/*
2233294Sstas * Copyright (c) 2003-2007 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5120945Snectar *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9120945Snectar *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12120945Snectar *
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.
16120945Snectar *
17120945Snectar * 3. Neither the name of KTH nor the names of its contributors may be
18120945Snectar *    used to endorse or promote products derived from this software without
19120945Snectar *    specific prior written permission.
20120945Snectar *
21120945Snectar * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22120945Snectar * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23120945Snectar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24120945Snectar * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25120945Snectar * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26120945Snectar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27120945Snectar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28120945Snectar * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29120945Snectar * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30120945Snectar * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31178825Sdfr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32178825Sdfr */
33120945Snectar
34178825Sdfr#ifdef HAVE_CONFIG_H
35178825Sdfr#include <config.h>
36178825Sdfr#endif
37178825Sdfr
38233294Sstas#include <roken.h>
39178825Sdfr#include <stdio.h>
40178825Sdfr#include <stdlib.h>
41178825Sdfr#include <string.h>
42178825Sdfr#include <stdarg.h>
43178825Sdfr#include <gssapi.h>
44233294Sstas#include <gssapi_krb5.h>
45233294Sstas#include <gssapi_spnego.h>
46120945Snectar#include <err.h>
47178825Sdfr#include <getarg.h>
48120945Snectar
49178825Sdfr#include "test_common.h"
50120945Snectar
51120945Snectarstatic void
52120945Snectarprint_time(OM_uint32 time_rec)
53120945Snectar{
54120945Snectar    if (time_rec == GSS_C_INDEFINITE) {
55120945Snectar	printf("cred never expire\n");
56120945Snectar    } else {
57178825Sdfr	time_t t = time_rec + time(NULL);
58120945Snectar	printf("expiration time: %s", ctime(&t));
59120945Snectar    }
60120945Snectar}
61120945Snectar
62178825Sdfr#if 0
63178825Sdfr
64178825Sdfrstatic void
65178825Sdfrtest_add(gss_cred_id_t cred_handle)
66120945Snectar{
67120945Snectar    OM_uint32 major_status, minor_status;
68178825Sdfr    gss_cred_id_t copy_cred;
69120945Snectar    OM_uint32 time_rec;
70120945Snectar
71120945Snectar    major_status = gss_add_cred (&minor_status,
72120945Snectar				 cred_handle,
73120945Snectar				 GSS_C_NO_NAME,
74120945Snectar				 GSS_KRB5_MECHANISM,
75120945Snectar				 GSS_C_INITIATE,
76120945Snectar				 0,
77120945Snectar				 0,
78120945Snectar				 &copy_cred,
79120945Snectar				 NULL,
80120945Snectar				 &time_rec,
81120945Snectar				 NULL);
82233294Sstas
83120945Snectar    if (GSS_ERROR(major_status))
84120945Snectar	errx(1, "add_cred failed");
85120945Snectar
86120945Snectar    print_time(time_rec);
87120945Snectar
88120945Snectar    major_status = gss_release_cred(&minor_status,
89178825Sdfr				    &copy_cred);
90120945Snectar    if (GSS_ERROR(major_status))
91120945Snectar	errx(1, "release_cred failed");
92178825Sdfr}
93120945Snectar
94178825Sdfrstatic void
95178825Sdfrcopy_cred(void)
96178825Sdfr{
97178825Sdfr    OM_uint32 major_status, minor_status;
98178825Sdfr    gss_cred_id_t cred_handle;
99178825Sdfr    OM_uint32 time_rec;
100178825Sdfr
101233294Sstas    major_status = gss_acquire_cred(&minor_status,
102178825Sdfr				    GSS_C_NO_NAME,
103178825Sdfr				    0,
104178825Sdfr				    NULL,
105178825Sdfr				    GSS_C_INITIATE,
106178825Sdfr				    &cred_handle,
107178825Sdfr				    NULL,
108178825Sdfr				    &time_rec);
109178825Sdfr    if (GSS_ERROR(major_status))
110178825Sdfr	errx(1, "acquire_cred failed");
111233294Sstas
112178825Sdfr    print_time(time_rec);
113178825Sdfr
114178825Sdfr    test_add(cred_handle);
115178825Sdfr    test_add(cred_handle);
116178825Sdfr    test_add(cred_handle);
117178825Sdfr
118120945Snectar    major_status = gss_release_cred(&minor_status,
119178825Sdfr				    &cred_handle);
120120945Snectar    if (GSS_ERROR(major_status))
121120945Snectar	errx(1, "release_cred failed");
122178825Sdfr}
123178825Sdfr#endif
124120945Snectar
125233294Sstasstatic gss_cred_id_t
126178825Sdfracquire_cred_service(const char *service,
127178825Sdfr		     gss_OID nametype,
128233294Sstas		     gss_OID_set oidset,
129178825Sdfr		     int flags)
130178825Sdfr{
131178825Sdfr    OM_uint32 major_status, minor_status;
132178825Sdfr    gss_cred_id_t cred_handle;
133178825Sdfr    OM_uint32 time_rec;
134178825Sdfr    gss_buffer_desc name_buffer;
135178825Sdfr    gss_name_t name = GSS_C_NO_NAME;
136178825Sdfr
137178825Sdfr    if (service) {
138178825Sdfr	name_buffer.value = rk_UNCONST(service);
139178825Sdfr	name_buffer.length = strlen(service);
140233294Sstas
141178825Sdfr	major_status = gss_import_name(&minor_status,
142178825Sdfr				       &name_buffer,
143178825Sdfr				       nametype,
144178825Sdfr				       &name);
145178825Sdfr	if (GSS_ERROR(major_status))
146178825Sdfr	    errx(1, "import_name failed");
147178825Sdfr    }
148178825Sdfr
149233294Sstas    major_status = gss_acquire_cred(&minor_status,
150178825Sdfr				    name,
151178825Sdfr				    0,
152233294Sstas				    oidset,
153178825Sdfr				    flags,
154178825Sdfr				    &cred_handle,
155178825Sdfr				    NULL,
156178825Sdfr				    &time_rec);
157178825Sdfr    if (GSS_ERROR(major_status)) {
158233294Sstas	warnx("acquire_cred failed: %s",
159178825Sdfr	     gssapi_err(major_status, minor_status, GSS_C_NO_OID));
160233294Sstas    } else {
161178825Sdfr	print_time(time_rec);
162178825Sdfr	gss_release_cred(&minor_status, &cred_handle);
163178825Sdfr    }
164178825Sdfr
165178825Sdfr    if (name != GSS_C_NO_NAME)
166178825Sdfr	gss_release_name(&minor_status, &name);
167178825Sdfr
168178825Sdfr    if (GSS_ERROR(major_status))
169178825Sdfr	exit(1);
170233294Sstas
171233294Sstas    return cred_handle;
172178825Sdfr}
173178825Sdfr
174178825Sdfrstatic int version_flag = 0;
175178825Sdfrstatic int help_flag	= 0;
176233294Sstasstatic int kerberos_flag = 0;
177233294Sstasstatic int enctype = 0;
178178825Sdfrstatic char *acquire_name;
179178825Sdfrstatic char *acquire_type;
180233294Sstasstatic char *target_name;
181178825Sdfrstatic char *name_type;
182178825Sdfrstatic char *ccache;
183233294Sstasstatic int num_loops = 1;
184178825Sdfr
185178825Sdfrstatic struct getargs args[] = {
186178825Sdfr    {"acquire-name", 0,	arg_string,	&acquire_name, "name", NULL },
187178825Sdfr    {"acquire-type", 0,	arg_string,	&acquire_type, "type", NULL },
188233294Sstas    {"enctype", 0,	arg_integer,	&enctype, "enctype-num", NULL },
189233294Sstas    {"loops", 0,	arg_integer,	&num_loops, "enctype-num", NULL },
190233294Sstas    {"kerberos", 0,	arg_flag,	&kerberos_flag, "enctype-num", NULL },
191233294Sstas    {"target-name", 0,	arg_string,	&target_name, "name", NULL },
192178825Sdfr    {"ccache", 0,	arg_string,	&ccache, "name", NULL },
193178825Sdfr    {"name-type", 0,	arg_string,	&name_type, "type", NULL },
194178825Sdfr    {"version",	0,	arg_flag,	&version_flag, "print version", NULL },
195178825Sdfr    {"help",	0,	arg_flag,	&help_flag,  NULL, NULL }
196178825Sdfr};
197178825Sdfr
198178825Sdfrstatic void
199178825Sdfrusage (int ret)
200178825Sdfr{
201178825Sdfr    arg_printusage (args, sizeof(args)/sizeof(*args), NULL, "");
202178825Sdfr    exit (ret);
203178825Sdfr}
204178825Sdfr
205178825Sdfrint
206178825Sdfrmain(int argc, char **argv)
207178825Sdfr{
208233294Sstas    gss_OID_set oidset = GSS_C_NULL_OID_SET;
209233294Sstas    gss_OID mechoid = GSS_C_NO_OID;
210233294Sstas    OM_uint32 maj_stat, min_stat;
211233294Sstas    gss_cred_id_t cred;
212233294Sstas    gss_name_t target = GSS_C_NO_NAME;
213233294Sstas    int i, optidx = 0;
214178825Sdfr    OM_uint32 flag;
215178825Sdfr    gss_OID type;
216178825Sdfr
217178825Sdfr    setprogname(argv[0]);
218178825Sdfr    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
219178825Sdfr	usage(1);
220233294Sstas
221178825Sdfr    if (help_flag)
222178825Sdfr	usage (0);
223178825Sdfr
224178825Sdfr    if(version_flag){
225178825Sdfr	print_version(NULL);
226178825Sdfr	exit(0);
227178825Sdfr    }
228178825Sdfr
229178825Sdfr    argc -= optidx;
230178825Sdfr    argv += optidx;
231178825Sdfr
232178825Sdfr    if (argc != 0)
233178825Sdfr	usage(1);
234178825Sdfr
235178825Sdfr    if (acquire_type) {
236178825Sdfr	if (strcasecmp(acquire_type, "both") == 0)
237178825Sdfr	    flag = GSS_C_BOTH;
238178825Sdfr	else if (strcasecmp(acquire_type, "accept") == 0)
239178825Sdfr	    flag = GSS_C_ACCEPT;
240178825Sdfr	else if (strcasecmp(acquire_type, "initiate") == 0)
241178825Sdfr	    flag = GSS_C_INITIATE;
242178825Sdfr	else
243178825Sdfr	    errx(1, "unknown type %s", acquire_type);
244178825Sdfr    } else
245178825Sdfr	flag = GSS_C_ACCEPT;
246233294Sstas
247178825Sdfr    if (name_type) {
248178825Sdfr	if (strcasecmp("hostbased-service", name_type) == 0)
249178825Sdfr	    type = GSS_C_NT_HOSTBASED_SERVICE;
250178825Sdfr	else if (strcasecmp("user-name", name_type) == 0)
251178825Sdfr	    type = GSS_C_NT_USER_NAME;
252178825Sdfr	else
253178825Sdfr	    errx(1, "unknown name type %s", name_type);
254178825Sdfr    } else
255178825Sdfr	type = GSS_C_NT_HOSTBASED_SERVICE;
256178825Sdfr
257178825Sdfr    if (ccache) {
258233294Sstas	maj_stat = gss_krb5_ccache_name(&min_stat, ccache, NULL);
259233294Sstas	if (GSS_ERROR(maj_stat))
260233294Sstas	    errx(1, "gss_krb5_ccache_name %s",
261233294Sstas		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
262178825Sdfr    }
263178825Sdfr
264233294Sstas    if (kerberos_flag) {
265233294Sstas	mechoid = GSS_KRB5_MECHANISM;
266178825Sdfr
267233294Sstas	maj_stat = gss_create_empty_oid_set(&min_stat, &oidset);
268233294Sstas	if (maj_stat != GSS_S_COMPLETE)
269233294Sstas	    errx(1, "gss_create_empty_oid_set: %s",
270233294Sstas		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
271233294Sstas
272233294Sstas	maj_stat = gss_add_oid_set_member(&min_stat, GSS_KRB5_MECHANISM, &oidset);
273233294Sstas	if (maj_stat != GSS_S_COMPLETE)
274233294Sstas	    errx(1, "gss_add_oid_set_member: %s",
275233294Sstas		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
276233294Sstas    }
277233294Sstas
278233294Sstas    if (target_name) {
279233294Sstas	gss_buffer_desc name;
280233294Sstas
281233294Sstas	name.value = target_name;
282233294Sstas	name.length = strlen(target_name);
283233294Sstas	maj_stat = gss_import_name(&min_stat, &name,
284233294Sstas				   GSS_C_NT_HOSTBASED_SERVICE, &target);
285233294Sstas	if (maj_stat != GSS_S_COMPLETE)
286233294Sstas	    errx(1, "gss_import_name: %s",
287233294Sstas		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
288233294Sstas    }
289233294Sstas
290233294Sstas    for (i = 0; i < num_loops; i++) {
291233294Sstas
292233294Sstas	cred = acquire_cred_service(acquire_name, type, oidset, flag);
293233294Sstas
294233294Sstas	if (enctype) {
295233294Sstas	    int32_t enctypelist = enctype;
296233294Sstas
297233294Sstas	    maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, cred,
298233294Sstas						       1, &enctypelist);
299233294Sstas	    if (maj_stat)
300233294Sstas		errx(1, "gss_krb5_set_allowable_enctypes: %s",
301233294Sstas		     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
302233294Sstas	}
303233294Sstas
304233294Sstas	if (target) {
305233294Sstas	    gss_ctx_id_t context = GSS_C_NO_CONTEXT;
306233294Sstas	    gss_buffer_desc out;
307233294Sstas
308233294Sstas	    out.length = 0;
309233294Sstas	    out.value = NULL;
310233294Sstas
311233294Sstas	    maj_stat = gss_init_sec_context(&min_stat,
312233294Sstas					    cred, &context,
313233294Sstas					    target, mechoid,
314233294Sstas					    GSS_C_MUTUAL_FLAG, 0, NULL,
315233294Sstas					    GSS_C_NO_BUFFER, NULL,
316233294Sstas					    &out, NULL, NULL);
317233294Sstas	    if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
318233294Sstas		errx(1, "init_sec_context failed: %s",
319233294Sstas		     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
320233294Sstas
321233294Sstas	    gss_release_buffer(&min_stat, &out);
322233294Sstas	    gss_delete_sec_context(&min_stat, &context, NULL);
323233294Sstas	}
324233294Sstas	gss_release_cred(&min_stat, &cred);
325233294Sstas    }
326233294Sstas
327233294Sstas
328120945Snectar    return 0;
329120945Snectar}
330