1/*
2 * Copyright (c) 2003-2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of KTH nor the names of its contributors may be
18 *    used to endorse or promote products derived from this software without
19 *    specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <config.h>
35
36#include <roken.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <stdarg.h>
41#include <gssapi.h>
42#include <gssapi_krb5.h>
43#include <gssapi_spi.h>
44#include <err.h>
45#include <getarg.h>
46#include <base64.h>
47
48#include "test_common.h"
49
50static int verbose_flag;
51
52static void
53print_time(OM_uint32 time_rec)
54{
55    if (time_rec == GSS_C_INDEFINITE) {
56	printf("cred never expire\n");
57    } else {
58	time_t t = time_rec + time(NULL);
59	printf("expiration time: %s", ctime(&t));
60    }
61}
62
63static void
64test_add(gss_const_OID mech, int flag, gss_cred_id_t cred_handle)
65{
66    OM_uint32 major_status, minor_status;
67    gss_cred_id_t copy_cred;
68    OM_uint32 time_rec;
69
70    if (verbose_flag)
71	printf("trying add cred\n");
72
73    major_status = gss_add_cred (&minor_status,
74				 cred_handle,
75				 GSS_C_NO_NAME,
76				 rk_UNCONST(mech),
77				 flag,
78				 0,
79				 0,
80				 &copy_cred,
81				 NULL,
82				 &time_rec,
83				 NULL);
84
85    if (GSS_ERROR(major_status))
86	errx(1, "add_cred failed");
87
88    if (verbose_flag)
89	print_time(time_rec);
90
91    major_status = gss_release_cred(&minor_status,
92				    &copy_cred);
93    if (GSS_ERROR(major_status))
94	errx(1, "release_cred failed");
95}
96
97#if 0
98
99static void
100copy_cred(void)
101{
102    OM_uint32 major_status, minor_status;
103    gss_cred_id_t cred_handle;
104    OM_uint32 time_rec;
105
106    major_status = gss_acquire_cred(&minor_status,
107				    GSS_C_NO_NAME,
108				    0,
109				    NULL,
110				    GSS_C_INITIATE,
111				    &cred_handle,
112				    NULL,
113				    &time_rec);
114    if (GSS_ERROR(major_status))
115	errx(1, "acquire_cred failed");
116
117    if (verbose_flag)
118	print_time(time_rec);
119
120    test_add(cred_handle);
121    test_add(cred_handle);
122    test_add(cred_handle);
123
124    major_status = gss_release_cred(&minor_status,
125				    &cred_handle);
126    if (GSS_ERROR(major_status))
127	errx(1, "release_cred failed");
128}
129#endif
130
131static gss_cred_id_t
132acquire_cred_service(gss_buffer_t name_buffer,
133		     gss_OID nametype,
134		     gss_OID_set oidset,
135		     int flags)
136{
137    OM_uint32 major_status, minor_status;
138    gss_cred_id_t cred_handle;
139    OM_uint32 time_rec;
140    gss_name_t name = GSS_C_NO_NAME;
141
142    if (name_buffer) {
143	major_status = gss_import_name(&minor_status,
144				       name_buffer,
145				       nametype,
146				       &name);
147	if (GSS_ERROR(major_status))
148	    errx(1, "import_name failed");
149    }
150
151    major_status = gss_acquire_cred(&minor_status,
152				    name,
153				    0,
154				    oidset,
155				    flags,
156				    &cred_handle,
157				    NULL,
158				    &time_rec);
159    if (GSS_ERROR(major_status)) {
160	warnx("acquire_cred failed: %s",
161	     gssapi_err(major_status, minor_status, GSS_C_NO_OID));
162    } else {
163	if (verbose_flag)
164	    print_time(time_rec);
165    }
166
167    if (name != GSS_C_NO_NAME)
168	gss_release_name(&minor_status, &name);
169
170    if (GSS_ERROR(major_status))
171	exit(1);
172
173    return cred_handle;
174}
175
176static int version_flag = 0;
177static int help_flag	= 0;
178static int kerberos_flag = 0;
179static int enctype = 0;
180static int no_ui_flag = 0;
181static char *acquire_name;
182static char *acquire_type;
183static char *cred_type;
184static char *mech_type;
185static char *target_name;
186static char *name_type;
187static char *ccache;
188static int anonymous_flag;
189static int num_loops = 1;
190
191static struct getargs args[] = {
192    {"acquire-name", 0,	arg_string,	&acquire_name, "name", NULL },
193    {"acquire-type", 0,	arg_string,	&acquire_type, "type", NULL },
194    {"enctype", 0,	arg_integer,	&enctype, "enctype-num", NULL },
195    {"loops", 0,	arg_integer,	&num_loops, "enctype-num", NULL },
196    {"kerberos", 0,	arg_flag,	&kerberos_flag, "enctype-num", NULL },
197    {"target-name", 0,	arg_string,	&target_name, "name", NULL },
198    {"ccache", 0,	arg_string,	&ccache, "name", NULL },
199    {"name-type", 0,	arg_string,	&name_type, "type", NULL },
200    {"cred-type", 0,	arg_string,	&cred_type, "mech-oid", NULL },
201    {"mech-type", 0,	arg_string,	&mech_type, "mech-oid", NULL },
202    {"no-ui", 0,	arg_flag,	&no_ui_flag, NULL },
203    {"anonymous", 0,	arg_flag,	&anonymous_flag, NULL },
204    {"verbose", 0,	arg_flag,	&verbose_flag, NULL },
205    {"version",	0,	arg_flag,	&version_flag, "print version", NULL },
206    {"help",	0,	arg_flag,	&help_flag,  NULL, NULL }
207};
208
209static void
210usage (int ret)
211{
212    arg_printusage (args, sizeof(args)/sizeof(*args), NULL, "");
213    exit (ret);
214}
215
216int
217main(int argc, char **argv)
218{
219    gss_OID_set oidset = GSS_C_NULL_OID_SET;
220    gss_const_OID mechoid = GSS_C_NO_OID;
221    gss_const_OID credoid = GSS_C_NO_OID;
222    OM_uint32 maj_stat, min_stat, isc_flags;
223    gss_cred_id_t cred;
224    gss_name_t target = GSS_C_NO_NAME;
225    int i, optidx = 0;
226    OM_uint32 flag;
227    gss_OID type;
228    gss_buffer_t acquire_name_buffer = GSS_C_NO_BUFFER;
229    gss_buffer_desc acquire_name_buffer_desc = { 0, NULL };
230    int export_name = 0;
231    uint8_t *decoded_name = NULL;
232
233    setprogname(argv[0]);
234    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
235	usage(1);
236
237    if (help_flag)
238	usage (0);
239
240    if(version_flag){
241	print_version(NULL);
242	exit(0);
243    }
244
245    argc -= optidx;
246
247    if (argc != 0)
248	usage(1);
249
250    if (acquire_type) {
251	if (strcasecmp(acquire_type, "both") == 0)
252	    flag = GSS_C_BOTH;
253	else if (strcasecmp(acquire_type, "accept") == 0)
254	    flag = GSS_C_ACCEPT;
255	else if (strcasecmp(acquire_type, "initiate") == 0)
256	    flag = GSS_C_INITIATE;
257	else
258	    errx(1, "unknown type %s", acquire_type);
259    } else
260	flag = GSS_C_INITIATE;
261
262    if (no_ui_flag)
263	flag |= GSS_C_CRED_NO_UI;
264
265    if (name_type) {
266	if (strcasecmp("hostbased-service", name_type) == 0)
267	    type = GSS_C_NT_HOSTBASED_SERVICE;
268	else if (strcasecmp("user-name", name_type) == 0)
269	    type = GSS_C_NT_USER_NAME;
270	else if (strcasecmp("krb5-principal-name", name_type) == 0)
271	    type = GSS_KRB5_NT_PRINCIPAL_NAME;
272	else if (strcasecmp("krb5-principal-name-referral", name_type) == 0)
273	    type = GSS_KRB5_NT_PRINCIPAL_NAME_REFERRAL;
274	else if (strcasecmp("anonymous", name_type) == 0) {
275	    type = GSS_C_NT_ANONYMOUS;
276	    acquire_name_buffer = &acquire_name_buffer_desc;
277	} else if (strcasecmp("export-name", name_type) == 0) {
278	    type = GSS_C_NT_EXPORT_NAME;
279	    export_name = 1;
280	} else
281	    errx(1, "unknown name type %s", name_type);
282    } else
283	type = GSS_C_NT_HOSTBASED_SERVICE;
284
285    if (ccache) {
286	maj_stat = gss_krb5_ccache_name(&min_stat, ccache, NULL);
287	if (GSS_ERROR(maj_stat))
288	    errx(1, "gss_krb5_ccache_name %s",
289		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
290    }
291
292    if (kerberos_flag)
293	mechoid = GSS_KRB5_MECHANISM;
294
295    if (mech_type)
296	mechoid = gss_name_to_oid(mech_type);
297
298    if (cred_type) {
299	credoid = gss_name_to_oid(cred_type);
300	if (credoid == NULL)
301	    errx(1, "failed to find cred type %s", cred_type);
302
303	maj_stat = gss_create_empty_oid_set(&min_stat, &oidset);
304	if (maj_stat != GSS_S_COMPLETE)
305	    errx(1, "gss_create_empty_oid_set: %s",
306		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
307
308	maj_stat = gss_add_oid_set_member(&min_stat, credoid, &oidset);
309	if (maj_stat != GSS_S_COMPLETE)
310	    errx(1, "gss_add_oid_set_member: %s",
311		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
312    }
313
314    if (target_name) {
315	gss_buffer_desc name;
316
317	name.value = target_name;
318	name.length = strlen(target_name);
319	maj_stat = gss_import_name(&min_stat, &name,
320				   GSS_C_NT_HOSTBASED_SERVICE, &target);
321	if (maj_stat != GSS_S_COMPLETE)
322	    errx(1, "gss_import_name: %s",
323		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
324    }
325
326    if (acquire_name) {
327	acquire_name_buffer = &acquire_name_buffer_desc;
328
329	if (export_name) {
330	    int len;
331
332	    decoded_name = emalloc(strlen(acquire_name));
333	    len = base64_decode(acquire_name, decoded_name);
334	    if (len < 0)
335		abort();
336
337	    acquire_name_buffer->value = decoded_name;
338	    acquire_name_buffer->length = len;
339	} else {
340	    acquire_name_buffer->value = acquire_name;
341	    acquire_name_buffer->length = strlen(acquire_name);
342	}
343    }
344
345    isc_flags = GSS_C_MUTUAL_FLAG;
346    if (anonymous_flag)
347	isc_flags |= GSS_C_ANON_FLAG;
348
349    for (i = 0; i < num_loops; i++) {
350
351	cred = acquire_cred_service(acquire_name_buffer, type, oidset, flag);
352
353	if (credoid) {
354	    int j;
355
356	    for (j = 0; j < 10; j++)
357		test_add(credoid, flag, cred);
358	}
359
360	if (enctype) {
361	    int32_t enctypelist = enctype;
362
363	    maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, cred,
364						       1, &enctypelist);
365	    if (maj_stat)
366		errx(1, "gss_krb5_set_allowable_enctypes: %s",
367		     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
368	}
369
370	if (target) {
371	    gss_ctx_id_t context = GSS_C_NO_CONTEXT;
372	    gss_buffer_desc out;
373
374	    out.length = 0;
375	    out.value = NULL;
376
377	    maj_stat = gss_init_sec_context(&min_stat,
378					    cred, &context,
379					    target, rk_UNCONST(mechoid),
380					    isc_flags, 0, NULL,
381					    GSS_C_NO_BUFFER, NULL,
382					    &out, NULL, NULL);
383	    if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
384		errx(1, "init_sec_context failed: %s",
385		     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
386
387	    gss_release_buffer(&min_stat, &out);
388	    gss_delete_sec_context(&min_stat, &context, NULL);
389	}
390	gss_release_cred(&min_stat, &cred);
391    }
392
393    cred = acquire_cred_service(acquire_name_buffer, type, NULL, flag);
394    if (cred)
395	gss_release_cred(&min_stat, &cred);
396
397    if (decoded_name)
398	free(decoded_name);
399
400    return 0;
401}
402