1184588Sdfr/*-
2184588Sdfr * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3184588Sdfr * Authors: Doug Rabson <dfr@rabson.org>
4184588Sdfr * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5184588Sdfr *
6184588Sdfr * Redistribution and use in source and binary forms, with or without
7184588Sdfr * modification, are permitted provided that the following conditions
8184588Sdfr * are met:
9184588Sdfr * 1. Redistributions of source code must retain the above copyright
10184588Sdfr *    notice, this list of conditions and the following disclaimer.
11184588Sdfr * 2. Redistributions in binary form must reproduce the above copyright
12184588Sdfr *    notice, this list of conditions and the following disclaimer in the
13184588Sdfr *    documentation and/or other materials provided with the distribution.
14184588Sdfr *
15184588Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16184588Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17184588Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18184588Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19184588Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20184588Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21184588Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22184588Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23184588Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24184588Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25184588Sdfr * SUCH DAMAGE.
26184588Sdfr *
27184588Sdfr * $FreeBSD$
28184588Sdfr */
29184588Sdfr
30184588Sdfr#include <sys/types.h>
31184588Sdfr#include <sys/syscall.h>
32184588Sdfr#include <sys/module.h>
33184588Sdfr
34184588Sdfr#include <stdio.h>
35184588Sdfr#include <string.h>
36184588Sdfr#include <err.h>
37184588Sdfr#include <unistd.h>
38184588Sdfr#include <stdlib.h>
39184588Sdfr
40184588Sdfr#include <krb5.h>
41184588Sdfr#include <gssapi/gssapi.h>
42184588Sdfr#include <gssapi/gssapi_krb5.h>
43184588Sdfr
44184588Sdfrstruct gsstest_2_args {
45184588Sdfr	int step;		/* test step number */
46184588Sdfr	gss_buffer_desc input_token; /* token from userland */
47184588Sdfr	gss_buffer_desc output_token; /* buffer to receive reply token */
48184588Sdfr};
49184588Sdfrstruct gsstest_2_res {
50184588Sdfr	OM_uint32 maj_stat;	/* maj_stat from kernel */
51184588Sdfr	OM_uint32 min_stat;	/* min_stat from kernel */
52184588Sdfr	gss_buffer_desc output_token; /* reply token (using space from gsstest_2_args.output) */
53184588Sdfr};
54184588Sdfr
55184588Sdfrstatic void
56184588Sdfrreport_error(gss_OID mech, OM_uint32 maj, OM_uint32 min)
57184588Sdfr{
58184588Sdfr	OM_uint32 maj_stat, min_stat;
59184588Sdfr	OM_uint32 message_context;
60184588Sdfr	gss_buffer_desc buf;
61184588Sdfr
62184588Sdfr	printf("major_stat=%d, minor_stat=%d\n", maj, min);
63184588Sdfr	message_context = 0;
64184588Sdfr	do {
65184588Sdfr		maj_stat = gss_display_status(&min_stat, maj,
66184588Sdfr		    GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &buf);
67184588Sdfr		printf("%.*s\n", (int)buf.length, (char *) buf.value);
68184588Sdfr		gss_release_buffer(&min_stat, &buf);
69184588Sdfr	} while (message_context);
70184588Sdfr	if (mech) {
71184588Sdfr		message_context = 0;
72184588Sdfr		do {
73184588Sdfr			maj_stat = gss_display_status(&min_stat, min,
74184588Sdfr			    GSS_C_MECH_CODE, mech, &message_context, &buf);
75184588Sdfr			printf("%.*s\n", (int)buf.length, (char *) buf.value);
76184588Sdfr			gss_release_buffer(&min_stat, &buf);
77184588Sdfr		} while (message_context);
78184588Sdfr	}
79184588Sdfr}
80184588Sdfr
81184588Sdfrint
82184588Sdfrmain(int argc, char **argv)
83184588Sdfr{
84184588Sdfr	struct module_stat stat;
85184588Sdfr	int mod;
86184588Sdfr	int syscall_num;
87184588Sdfr
88184588Sdfr	stat.version = sizeof(stat);
89184588Sdfr	mod = modfind("gsstest_syscall");
90184588Sdfr	if (mod < 0) {
91184588Sdfr		fprintf(stderr, "%s: kernel support not present\n", argv[0]);
92184588Sdfr		exit(1);
93184588Sdfr	}
94184588Sdfr	modstat(mod, &stat);
95184588Sdfr	syscall_num = stat.data.intval;
96184588Sdfr
97184588Sdfr	switch (atoi(argv[1])) {
98184588Sdfr	case 1:
99184588Sdfr		syscall(syscall_num, 1, NULL, NULL);
100184588Sdfr		break;
101184588Sdfr
102184588Sdfr	case 2: {
103184588Sdfr		struct gsstest_2_args args;
104184588Sdfr		struct gsstest_2_res res;
105184588Sdfr		char hostname[512];
106184588Sdfr		char token_buffer[8192];
107184588Sdfr		OM_uint32 maj_stat, min_stat;
108184588Sdfr		gss_ctx_id_t client_context = GSS_C_NO_CONTEXT;
109184588Sdfr		gss_cred_id_t client_cred;
110184588Sdfr		gss_OID mech_type = GSS_C_NO_OID;
111184588Sdfr		gss_buffer_desc name_buf, message_buf;
112184588Sdfr		gss_name_t name;
113184588Sdfr		int32_t enctypes[] = {
114184588Sdfr			ETYPE_DES_CBC_CRC,
115184588Sdfr			ETYPE_ARCFOUR_HMAC_MD5,
116184588Sdfr			ETYPE_ARCFOUR_HMAC_MD5_56,
117184588Sdfr			ETYPE_AES256_CTS_HMAC_SHA1_96,
118184588Sdfr			ETYPE_AES128_CTS_HMAC_SHA1_96,
119184588Sdfr			ETYPE_DES3_CBC_SHA1,
120184588Sdfr		};
121184588Sdfr		int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
122184588Sdfr		int established;
123184588Sdfr		int i;
124184588Sdfr
125184588Sdfr		for (i = 0; i < num_enctypes; i++) {
126184588Sdfr			printf("testing etype %d\n", enctypes[i]);
127184588Sdfr			args.output_token.length = sizeof(token_buffer);
128184588Sdfr			args.output_token.value = token_buffer;
129184588Sdfr
130184588Sdfr			gethostname(hostname, sizeof(hostname));
131184588Sdfr			snprintf(token_buffer, sizeof(token_buffer),
132184588Sdfr			    "nfs@%s", hostname);
133184588Sdfr			name_buf.length = strlen(token_buffer);
134184588Sdfr			name_buf.value = token_buffer;
135184588Sdfr			maj_stat = gss_import_name(&min_stat, &name_buf,
136184588Sdfr			    GSS_C_NT_HOSTBASED_SERVICE, &name);
137184588Sdfr			if (GSS_ERROR(maj_stat)) {
138184588Sdfr				printf("gss_import_name failed\n");
139184588Sdfr				report_error(mech_type, maj_stat, min_stat);
140184588Sdfr				goto out;
141184588Sdfr			}
142184588Sdfr
143184588Sdfr			maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME,
144184588Sdfr			    0, GSS_C_NO_OID_SET, GSS_C_INITIATE, &client_cred,
145184588Sdfr			    NULL, NULL);
146184588Sdfr			if (GSS_ERROR(maj_stat)) {
147184588Sdfr				printf("gss_acquire_cred (client) failed\n");
148184588Sdfr				report_error(mech_type, maj_stat, min_stat);
149184588Sdfr				goto out;
150184588Sdfr			}
151184588Sdfr
152184588Sdfr			maj_stat = gss_krb5_set_allowable_enctypes(&min_stat,
153184588Sdfr			    client_cred, 1, &enctypes[i]);
154184588Sdfr			if (GSS_ERROR(maj_stat)) {
155184588Sdfr				printf("gss_krb5_set_allowable_enctypes failed\n");
156184588Sdfr				report_error(mech_type, maj_stat, min_stat);
157184588Sdfr				goto out;
158184588Sdfr			}
159184588Sdfr
160184588Sdfr			res.output_token.length = 0;
161184588Sdfr			res.output_token.value = 0;
162184588Sdfr			established = 0;
163184588Sdfr			while (!established) {
164184588Sdfr				maj_stat = gss_init_sec_context(&min_stat,
165184588Sdfr				    client_cred,
166184588Sdfr				    &client_context,
167184588Sdfr				    name,
168184588Sdfr				    GSS_C_NO_OID,
169184588Sdfr				    (GSS_C_MUTUAL_FLAG
170184588Sdfr					|GSS_C_CONF_FLAG
171184588Sdfr					|GSS_C_INTEG_FLAG
172184588Sdfr					|GSS_C_SEQUENCE_FLAG
173184588Sdfr					|GSS_C_REPLAY_FLAG),
174184588Sdfr				    0,
175184588Sdfr				    GSS_C_NO_CHANNEL_BINDINGS,
176184588Sdfr				    &res.output_token,
177184588Sdfr				    &mech_type,
178184588Sdfr				    &args.input_token,
179184588Sdfr				    NULL,
180184588Sdfr				    NULL);
181184588Sdfr				if (GSS_ERROR(maj_stat)) {
182184588Sdfr					printf("gss_init_sec_context failed\n");
183184588Sdfr					report_error(mech_type, maj_stat, min_stat);
184184588Sdfr					goto out;
185184588Sdfr				}
186184588Sdfr				if (args.input_token.length) {
187184588Sdfr					args.step = 1;
188184588Sdfr					syscall(syscall_num, 2, &args, &res);
189184588Sdfr					gss_release_buffer(&min_stat,
190184588Sdfr					    &args.input_token);
191184588Sdfr					if (res.maj_stat != GSS_S_COMPLETE
192184588Sdfr					    && res.maj_stat != GSS_S_CONTINUE_NEEDED) {
193184588Sdfr						printf("gss_accept_sec_context (kernel) failed\n");
194184588Sdfr						report_error(mech_type, res.maj_stat,
195184588Sdfr						    res.min_stat);
196184588Sdfr						goto out;
197184588Sdfr					}
198184588Sdfr				}
199184588Sdfr				if (maj_stat == GSS_S_COMPLETE)
200184588Sdfr					established = 1;
201184588Sdfr			}
202184588Sdfr
203184588Sdfr			message_buf.value = "Hello world";
204184588Sdfr			message_buf.length = strlen((char *) message_buf.value);
205184588Sdfr
206184588Sdfr			maj_stat = gss_get_mic(&min_stat, client_context,
207184588Sdfr			    GSS_C_QOP_DEFAULT, &message_buf, &args.input_token);
208184588Sdfr			if (GSS_ERROR(maj_stat)) {
209184588Sdfr				printf("gss_get_mic failed\n");
210184588Sdfr				report_error(mech_type, maj_stat, min_stat);
211184588Sdfr				goto out;
212184588Sdfr			}
213184588Sdfr
214184588Sdfr			args.step = 2;
215184588Sdfr			syscall(syscall_num, 2, &args, &res);
216184588Sdfr			gss_release_buffer(&min_stat, &args.input_token);
217184588Sdfr			if (GSS_ERROR(res.maj_stat)) {
218184588Sdfr				printf("kernel gss_verify_mic failed\n");
219184588Sdfr				report_error(mech_type, res.maj_stat, res.min_stat);
220184588Sdfr				goto out;
221184588Sdfr			}
222184588Sdfr
223184588Sdfr			maj_stat = gss_verify_mic(&min_stat, client_context,
224184588Sdfr			    &message_buf, &res.output_token, NULL);
225184588Sdfr			if (GSS_ERROR(maj_stat)) {
226184588Sdfr				printf("gss_verify_mic failed\n");
227184588Sdfr				report_error(mech_type, maj_stat, min_stat);
228184588Sdfr				goto out;
229184588Sdfr			}
230184588Sdfr
231184588Sdfr			maj_stat = gss_wrap(&min_stat, client_context,
232184588Sdfr			    TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL,
233184588Sdfr			    &args.input_token);
234184588Sdfr			if (GSS_ERROR(maj_stat)) {
235184588Sdfr				printf("gss_wrap failed\n");
236184588Sdfr				report_error(mech_type, maj_stat, min_stat);
237184588Sdfr				goto out;
238184588Sdfr			}
239184588Sdfr
240184588Sdfr			args.step = 3;
241184588Sdfr			syscall(syscall_num, 2, &args, &res);
242184588Sdfr			gss_release_buffer(&min_stat, &args.input_token);
243184588Sdfr			if (GSS_ERROR(res.maj_stat)) {
244184588Sdfr				printf("kernel gss_unwrap failed\n");
245184588Sdfr				report_error(mech_type, res.maj_stat, res.min_stat);
246184588Sdfr				goto out;
247184588Sdfr			}
248184588Sdfr
249184588Sdfr			maj_stat = gss_unwrap(&min_stat, client_context,
250184588Sdfr			    &res.output_token, &message_buf, NULL, NULL);
251184588Sdfr			if (GSS_ERROR(maj_stat)) {
252184588Sdfr				printf("gss_unwrap failed\n");
253184588Sdfr				report_error(mech_type, maj_stat, min_stat);
254184588Sdfr				goto out;
255184588Sdfr			}
256184588Sdfr			gss_release_buffer(&min_stat, &message_buf);
257184588Sdfr
258184588Sdfr			maj_stat = gss_wrap(&min_stat, client_context,
259184588Sdfr			    FALSE, GSS_C_QOP_DEFAULT, &message_buf, NULL,
260184588Sdfr			    &args.input_token);
261184588Sdfr			if (GSS_ERROR(maj_stat)) {
262184588Sdfr				printf("gss_wrap failed\n");
263184588Sdfr				report_error(mech_type, maj_stat, min_stat);
264184588Sdfr				goto out;
265184588Sdfr			}
266184588Sdfr
267184588Sdfr			args.step = 4;
268184588Sdfr			syscall(syscall_num, 2, &args, &res);
269184588Sdfr			gss_release_buffer(&min_stat, &args.input_token);
270184588Sdfr			if (GSS_ERROR(res.maj_stat)) {
271184588Sdfr				printf("kernel gss_unwrap failed\n");
272184588Sdfr				report_error(mech_type, res.maj_stat, res.min_stat);
273184588Sdfr				goto out;
274184588Sdfr			}
275184588Sdfr
276184588Sdfr			maj_stat = gss_unwrap(&min_stat, client_context,
277184588Sdfr			    &res.output_token, &message_buf, NULL, NULL);
278184588Sdfr			if (GSS_ERROR(maj_stat)) {
279184588Sdfr				printf("gss_unwrap failed\n");
280184588Sdfr				report_error(mech_type, maj_stat, min_stat);
281184588Sdfr				goto out;
282184588Sdfr			}
283184588Sdfr			gss_release_buffer(&min_stat, &message_buf);
284184588Sdfr
285184588Sdfr			args.step = 5;
286184588Sdfr			syscall(syscall_num, 2, &args, &res);
287184588Sdfr
288184588Sdfr			gss_release_name(&min_stat, &name);
289184588Sdfr			gss_release_cred(&min_stat, &client_cred);
290184588Sdfr			gss_delete_sec_context(&min_stat, &client_context,
291184588Sdfr			    GSS_C_NO_BUFFER);
292184588Sdfr		}
293184588Sdfr
294184588Sdfr		break;
295184588Sdfr	}
296184588Sdfr	case 3:
297184588Sdfr		syscall(syscall_num, 3, NULL, NULL);
298184588Sdfr		break;
299184588Sdfr	case 4:
300184588Sdfr		syscall(syscall_num, 4, NULL, NULL);
301184588Sdfr		break;
302184588Sdfr	}
303184588Sdfr	return (0);
304184588Sdfr
305184588Sdfrout:
306184588Sdfr	return (1);
307184588Sdfr}
308