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 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37 
38 #include <roken.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <stdarg.h>
43 #include <gssapi.h>
44 #include <gssapi_krb5.h>
45 #include <gssapi_spnego.h>
46 #include <err.h>
47 #include <getarg.h>
48 
49 #include "test_common.h"
50 
51 static void
52 print_time(OM_uint32 time_rec)
53 {
54     if (time_rec == GSS_C_INDEFINITE) {
55 	printf("cred never expire\n");
56     } else {
57 	time_t t = time_rec + time(NULL);
58 	printf("expiration time: %s", ctime(&t));
59     }
60 }
61 
62 #if 0
63 
64 static void
65 test_add(gss_cred_id_t cred_handle)
66 {
67     OM_uint32 major_status, minor_status;
68     gss_cred_id_t copy_cred;
69     OM_uint32 time_rec;
70 
71     major_status = gss_add_cred (&minor_status,
72 				 cred_handle,
73 				 GSS_C_NO_NAME,
74 				 GSS_KRB5_MECHANISM,
75 				 GSS_C_INITIATE,
76 				 0,
77 				 0,
78 				 &copy_cred,
79 				 NULL,
80 				 &time_rec,
81 				 NULL);
82 
83     if (GSS_ERROR(major_status))
84 	errx(1, "add_cred failed");
85 
86     print_time(time_rec);
87 
88     major_status = gss_release_cred(&minor_status,
89 				    &copy_cred);
90     if (GSS_ERROR(major_status))
91 	errx(1, "release_cred failed");
92 }
93 
94 static void
95 copy_cred(void)
96 {
97     OM_uint32 major_status, minor_status;
98     gss_cred_id_t cred_handle;
99     OM_uint32 time_rec;
100 
101     major_status = gss_acquire_cred(&minor_status,
102 				    GSS_C_NO_NAME,
103 				    0,
104 				    NULL,
105 				    GSS_C_INITIATE,
106 				    &cred_handle,
107 				    NULL,
108 				    &time_rec);
109     if (GSS_ERROR(major_status))
110 	errx(1, "acquire_cred failed");
111 
112     print_time(time_rec);
113 
114     test_add(cred_handle);
115     test_add(cred_handle);
116     test_add(cred_handle);
117 
118     major_status = gss_release_cred(&minor_status,
119 				    &cred_handle);
120     if (GSS_ERROR(major_status))
121 	errx(1, "release_cred failed");
122 }
123 #endif
124 
125 static gss_cred_id_t
126 acquire_cred_service(const char *service,
127 		     gss_OID nametype,
128 		     gss_OID_set oidset,
129 		     int flags)
130 {
131     OM_uint32 major_status, minor_status;
132     gss_cred_id_t cred_handle;
133     OM_uint32 time_rec;
134     gss_buffer_desc name_buffer;
135     gss_name_t name = GSS_C_NO_NAME;
136 
137     if (service) {
138 	name_buffer.value = rk_UNCONST(service);
139 	name_buffer.length = strlen(service);
140 
141 	major_status = gss_import_name(&minor_status,
142 				       &name_buffer,
143 				       nametype,
144 				       &name);
145 	if (GSS_ERROR(major_status))
146 	    errx(1, "import_name failed");
147     }
148 
149     major_status = gss_acquire_cred(&minor_status,
150 				    name,
151 				    0,
152 				    oidset,
153 				    flags,
154 				    &cred_handle,
155 				    NULL,
156 				    &time_rec);
157     if (GSS_ERROR(major_status)) {
158 	warnx("acquire_cred failed: %s",
159 	     gssapi_err(major_status, minor_status, GSS_C_NO_OID));
160     } else {
161 	print_time(time_rec);
162 	gss_release_cred(&minor_status, &cred_handle);
163     }
164 
165     if (name != GSS_C_NO_NAME)
166 	gss_release_name(&minor_status, &name);
167 
168     if (GSS_ERROR(major_status))
169 	exit(1);
170 
171     return cred_handle;
172 }
173 
174 static int version_flag = 0;
175 static int help_flag	= 0;
176 static int kerberos_flag = 0;
177 static int enctype = 0;
178 static char *acquire_name;
179 static char *acquire_type;
180 static char *target_name;
181 static char *name_type;
182 static char *ccache;
183 static int num_loops = 1;
184 
185 static struct getargs args[] = {
186     {"acquire-name", 0,	arg_string,	&acquire_name, "name", NULL },
187     {"acquire-type", 0,	arg_string,	&acquire_type, "type", NULL },
188     {"enctype", 0,	arg_integer,	&enctype, "enctype-num", NULL },
189     {"loops", 0,	arg_integer,	&num_loops, "enctype-num", NULL },
190     {"kerberos", 0,	arg_flag,	&kerberos_flag, "enctype-num", NULL },
191     {"target-name", 0,	arg_string,	&target_name, "name", NULL },
192     {"ccache", 0,	arg_string,	&ccache, "name", NULL },
193     {"name-type", 0,	arg_string,	&name_type, "type", NULL },
194     {"version",	0,	arg_flag,	&version_flag, "print version", NULL },
195     {"help",	0,	arg_flag,	&help_flag,  NULL, NULL }
196 };
197 
198 static void
199 usage (int ret)
200 {
201     arg_printusage (args, sizeof(args)/sizeof(*args), NULL, "");
202     exit (ret);
203 }
204 
205 int
206 main(int argc, char **argv)
207 {
208     gss_OID_set oidset = GSS_C_NULL_OID_SET;
209     gss_OID mechoid = GSS_C_NO_OID;
210     OM_uint32 maj_stat, min_stat;
211     gss_cred_id_t cred;
212     gss_name_t target = GSS_C_NO_NAME;
213     int i, optidx = 0;
214     OM_uint32 flag;
215     gss_OID type;
216 
217     setprogname(argv[0]);
218     if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
219 	usage(1);
220 
221     if (help_flag)
222 	usage (0);
223 
224     if(version_flag){
225 	print_version(NULL);
226 	exit(0);
227     }
228 
229     argc -= optidx;
230     argv += optidx;
231 
232     if (argc != 0)
233 	usage(1);
234 
235     if (acquire_type) {
236 	if (strcasecmp(acquire_type, "both") == 0)
237 	    flag = GSS_C_BOTH;
238 	else if (strcasecmp(acquire_type, "accept") == 0)
239 	    flag = GSS_C_ACCEPT;
240 	else if (strcasecmp(acquire_type, "initiate") == 0)
241 	    flag = GSS_C_INITIATE;
242 	else
243 	    errx(1, "unknown type %s", acquire_type);
244     } else
245 	flag = GSS_C_ACCEPT;
246 
247     if (name_type) {
248 	if (strcasecmp("hostbased-service", name_type) == 0)
249 	    type = GSS_C_NT_HOSTBASED_SERVICE;
250 	else if (strcasecmp("user-name", name_type) == 0)
251 	    type = GSS_C_NT_USER_NAME;
252 	else
253 	    errx(1, "unknown name type %s", name_type);
254     } else
255 	type = GSS_C_NT_HOSTBASED_SERVICE;
256 
257     if (ccache) {
258 	maj_stat = gss_krb5_ccache_name(&min_stat, ccache, NULL);
259 	if (GSS_ERROR(maj_stat))
260 	    errx(1, "gss_krb5_ccache_name %s",
261 		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
262     }
263 
264     if (kerberos_flag) {
265 	mechoid = GSS_KRB5_MECHANISM;
266 
267 	maj_stat = gss_create_empty_oid_set(&min_stat, &oidset);
268 	if (maj_stat != GSS_S_COMPLETE)
269 	    errx(1, "gss_create_empty_oid_set: %s",
270 		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
271 
272 	maj_stat = gss_add_oid_set_member(&min_stat, GSS_KRB5_MECHANISM, &oidset);
273 	if (maj_stat != GSS_S_COMPLETE)
274 	    errx(1, "gss_add_oid_set_member: %s",
275 		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
276     }
277 
278     if (target_name) {
279 	gss_buffer_desc name;
280 
281 	name.value = target_name;
282 	name.length = strlen(target_name);
283 	maj_stat = gss_import_name(&min_stat, &name,
284 				   GSS_C_NT_HOSTBASED_SERVICE, &target);
285 	if (maj_stat != GSS_S_COMPLETE)
286 	    errx(1, "gss_import_name: %s",
287 		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
288     }
289 
290     for (i = 0; i < num_loops; i++) {
291 
292 	cred = acquire_cred_service(acquire_name, type, oidset, flag);
293 
294 	if (enctype) {
295 	    int32_t enctypelist = enctype;
296 
297 	    maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, cred,
298 						       1, &enctypelist);
299 	    if (maj_stat)
300 		errx(1, "gss_krb5_set_allowable_enctypes: %s",
301 		     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
302 	}
303 
304 	if (target) {
305 	    gss_ctx_id_t context = GSS_C_NO_CONTEXT;
306 	    gss_buffer_desc out;
307 
308 	    out.length = 0;
309 	    out.value = NULL;
310 
311 	    maj_stat = gss_init_sec_context(&min_stat,
312 					    cred, &context,
313 					    target, mechoid,
314 					    GSS_C_MUTUAL_FLAG, 0, NULL,
315 					    GSS_C_NO_BUFFER, NULL,
316 					    &out, NULL, NULL);
317 	    if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
318 		errx(1, "init_sec_context failed: %s",
319 		     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
320 
321 	    gss_release_buffer(&min_stat, &out);
322 	    gss_delete_sec_context(&min_stat, &context, NULL);
323 	}
324 	gss_release_cred(&min_stat, &cred);
325     }
326 
327 
328     return 0;
329 }
330