xref: /freebsd/tools/regression/kgssapi/gsstest.c (revision e0c4386e)
1 /*-
2  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3  * Authors: Doug Rabson <dfr@rabson.org>
4  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
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  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/types.h>
29 #include <sys/syscall.h>
30 #include <sys/module.h>
31 
32 #include <stdio.h>
33 #include <string.h>
34 #include <err.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 
38 #include <krb5.h>
39 #include <gssapi/gssapi.h>
40 #include <gssapi/gssapi_krb5.h>
41 
42 struct gsstest_2_args {
43 	int step;		/* test step number */
44 	gss_buffer_desc input_token; /* token from userland */
45 	gss_buffer_desc output_token; /* buffer to receive reply token */
46 };
47 struct gsstest_2_res {
48 	OM_uint32 maj_stat;	/* maj_stat from kernel */
49 	OM_uint32 min_stat;	/* min_stat from kernel */
50 	gss_buffer_desc output_token; /* reply token (using space from gsstest_2_args.output) */
51 };
52 
53 static void
54 report_error(gss_OID mech, OM_uint32 maj, OM_uint32 min)
55 {
56 	OM_uint32 maj_stat, min_stat;
57 	OM_uint32 message_context;
58 	gss_buffer_desc buf;
59 
60 	printf("major_stat=%d, minor_stat=%d\n", maj, min);
61 	message_context = 0;
62 	do {
63 		maj_stat = gss_display_status(&min_stat, maj,
64 		    GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &buf);
65 		printf("%.*s\n", (int)buf.length, (char *) buf.value);
66 		gss_release_buffer(&min_stat, &buf);
67 	} while (message_context);
68 	if (mech) {
69 		message_context = 0;
70 		do {
71 			maj_stat = gss_display_status(&min_stat, min,
72 			    GSS_C_MECH_CODE, mech, &message_context, &buf);
73 			printf("%.*s\n", (int)buf.length, (char *) buf.value);
74 			gss_release_buffer(&min_stat, &buf);
75 		} while (message_context);
76 	}
77 }
78 
79 int
80 main(int argc, char **argv)
81 {
82 	struct module_stat stat;
83 	int mod;
84 	int syscall_num;
85 
86 	stat.version = sizeof(stat);
87 	mod = modfind("gsstest_syscall");
88 	if (mod < 0) {
89 		fprintf(stderr, "%s: kernel support not present\n", argv[0]);
90 		exit(1);
91 	}
92 	modstat(mod, &stat);
93 	syscall_num = stat.data.intval;
94 
95 	switch (atoi(argv[1])) {
96 	case 1:
97 		syscall(syscall_num, 1, NULL, NULL);
98 		break;
99 
100 	case 2: {
101 		struct gsstest_2_args args;
102 		struct gsstest_2_res res;
103 		char hostname[512];
104 		char token_buffer[8192];
105 		OM_uint32 maj_stat, min_stat;
106 		gss_ctx_id_t client_context = GSS_C_NO_CONTEXT;
107 		gss_cred_id_t client_cred;
108 		gss_OID mech_type = GSS_C_NO_OID;
109 		gss_buffer_desc name_buf, message_buf;
110 		gss_name_t name;
111 		int32_t enctypes[] = {
112 			ETYPE_DES_CBC_CRC,
113 			ETYPE_ARCFOUR_HMAC_MD5,
114 			ETYPE_ARCFOUR_HMAC_MD5_56,
115 			ETYPE_AES256_CTS_HMAC_SHA1_96,
116 			ETYPE_AES128_CTS_HMAC_SHA1_96,
117 			ETYPE_DES3_CBC_SHA1,
118 		};
119 		int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
120 		int established;
121 		int i;
122 
123 		for (i = 0; i < num_enctypes; i++) {
124 			printf("testing etype %d\n", enctypes[i]);
125 			args.output_token.length = sizeof(token_buffer);
126 			args.output_token.value = token_buffer;
127 
128 			gethostname(hostname, sizeof(hostname));
129 			snprintf(token_buffer, sizeof(token_buffer),
130 			    "nfs@%s", hostname);
131 			name_buf.length = strlen(token_buffer);
132 			name_buf.value = token_buffer;
133 			maj_stat = gss_import_name(&min_stat, &name_buf,
134 			    GSS_C_NT_HOSTBASED_SERVICE, &name);
135 			if (GSS_ERROR(maj_stat)) {
136 				printf("gss_import_name failed\n");
137 				report_error(mech_type, maj_stat, min_stat);
138 				goto out;
139 			}
140 
141 			maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME,
142 			    0, GSS_C_NO_OID_SET, GSS_C_INITIATE, &client_cred,
143 			    NULL, NULL);
144 			if (GSS_ERROR(maj_stat)) {
145 				printf("gss_acquire_cred (client) failed\n");
146 				report_error(mech_type, maj_stat, min_stat);
147 				goto out;
148 			}
149 
150 			maj_stat = gss_krb5_set_allowable_enctypes(&min_stat,
151 			    client_cred, 1, &enctypes[i]);
152 			if (GSS_ERROR(maj_stat)) {
153 				printf("gss_krb5_set_allowable_enctypes failed\n");
154 				report_error(mech_type, maj_stat, min_stat);
155 				goto out;
156 			}
157 
158 			res.output_token.length = 0;
159 			res.output_token.value = 0;
160 			established = 0;
161 			while (!established) {
162 				maj_stat = gss_init_sec_context(&min_stat,
163 				    client_cred,
164 				    &client_context,
165 				    name,
166 				    GSS_C_NO_OID,
167 				    (GSS_C_MUTUAL_FLAG
168 					|GSS_C_CONF_FLAG
169 					|GSS_C_INTEG_FLAG
170 					|GSS_C_SEQUENCE_FLAG
171 					|GSS_C_REPLAY_FLAG),
172 				    0,
173 				    GSS_C_NO_CHANNEL_BINDINGS,
174 				    &res.output_token,
175 				    &mech_type,
176 				    &args.input_token,
177 				    NULL,
178 				    NULL);
179 				if (GSS_ERROR(maj_stat)) {
180 					printf("gss_init_sec_context failed\n");
181 					report_error(mech_type, maj_stat, min_stat);
182 					goto out;
183 				}
184 				if (args.input_token.length) {
185 					args.step = 1;
186 					syscall(syscall_num, 2, &args, &res);
187 					gss_release_buffer(&min_stat,
188 					    &args.input_token);
189 					if (res.maj_stat != GSS_S_COMPLETE
190 					    && res.maj_stat != GSS_S_CONTINUE_NEEDED) {
191 						printf("gss_accept_sec_context (kernel) failed\n");
192 						report_error(mech_type, res.maj_stat,
193 						    res.min_stat);
194 						goto out;
195 					}
196 				}
197 				if (maj_stat == GSS_S_COMPLETE)
198 					established = 1;
199 			}
200 
201 			message_buf.value = "Hello world";
202 			message_buf.length = strlen((char *) message_buf.value);
203 
204 			maj_stat = gss_get_mic(&min_stat, client_context,
205 			    GSS_C_QOP_DEFAULT, &message_buf, &args.input_token);
206 			if (GSS_ERROR(maj_stat)) {
207 				printf("gss_get_mic failed\n");
208 				report_error(mech_type, maj_stat, min_stat);
209 				goto out;
210 			}
211 
212 			args.step = 2;
213 			syscall(syscall_num, 2, &args, &res);
214 			gss_release_buffer(&min_stat, &args.input_token);
215 			if (GSS_ERROR(res.maj_stat)) {
216 				printf("kernel gss_verify_mic failed\n");
217 				report_error(mech_type, res.maj_stat, res.min_stat);
218 				goto out;
219 			}
220 
221 			maj_stat = gss_verify_mic(&min_stat, client_context,
222 			    &message_buf, &res.output_token, NULL);
223 			if (GSS_ERROR(maj_stat)) {
224 				printf("gss_verify_mic failed\n");
225 				report_error(mech_type, maj_stat, min_stat);
226 				goto out;
227 			}
228 
229 			maj_stat = gss_wrap(&min_stat, client_context,
230 			    TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL,
231 			    &args.input_token);
232 			if (GSS_ERROR(maj_stat)) {
233 				printf("gss_wrap failed\n");
234 				report_error(mech_type, maj_stat, min_stat);
235 				goto out;
236 			}
237 
238 			args.step = 3;
239 			syscall(syscall_num, 2, &args, &res);
240 			gss_release_buffer(&min_stat, &args.input_token);
241 			if (GSS_ERROR(res.maj_stat)) {
242 				printf("kernel gss_unwrap failed\n");
243 				report_error(mech_type, res.maj_stat, res.min_stat);
244 				goto out;
245 			}
246 
247 			maj_stat = gss_unwrap(&min_stat, client_context,
248 			    &res.output_token, &message_buf, NULL, NULL);
249 			if (GSS_ERROR(maj_stat)) {
250 				printf("gss_unwrap failed\n");
251 				report_error(mech_type, maj_stat, min_stat);
252 				goto out;
253 			}
254 			gss_release_buffer(&min_stat, &message_buf);
255 
256 			maj_stat = gss_wrap(&min_stat, client_context,
257 			    FALSE, GSS_C_QOP_DEFAULT, &message_buf, NULL,
258 			    &args.input_token);
259 			if (GSS_ERROR(maj_stat)) {
260 				printf("gss_wrap failed\n");
261 				report_error(mech_type, maj_stat, min_stat);
262 				goto out;
263 			}
264 
265 			args.step = 4;
266 			syscall(syscall_num, 2, &args, &res);
267 			gss_release_buffer(&min_stat, &args.input_token);
268 			if (GSS_ERROR(res.maj_stat)) {
269 				printf("kernel gss_unwrap failed\n");
270 				report_error(mech_type, res.maj_stat, res.min_stat);
271 				goto out;
272 			}
273 
274 			maj_stat = gss_unwrap(&min_stat, client_context,
275 			    &res.output_token, &message_buf, NULL, NULL);
276 			if (GSS_ERROR(maj_stat)) {
277 				printf("gss_unwrap failed\n");
278 				report_error(mech_type, maj_stat, min_stat);
279 				goto out;
280 			}
281 			gss_release_buffer(&min_stat, &message_buf);
282 
283 			args.step = 5;
284 			syscall(syscall_num, 2, &args, &res);
285 
286 			gss_release_name(&min_stat, &name);
287 			gss_release_cred(&min_stat, &client_cred);
288 			gss_delete_sec_context(&min_stat, &client_context,
289 			    GSS_C_NO_BUFFER);
290 		}
291 
292 		break;
293 	}
294 	case 3:
295 		syscall(syscall_num, 3, NULL, NULL);
296 		break;
297 	case 4:
298 		syscall(syscall_num, 4, NULL, NULL);
299 		break;
300 	}
301 	return (0);
302 
303 out:
304 	return (1);
305 }
306