1178825Sdfr/*
2233294Sstas * Copyright (c) 2006 - 2008 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
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.
16178825Sdfr *
17178825Sdfr * 3. Neither the name of KTH nor the names of its contributors may be
18178825Sdfr *    used to endorse or promote products derived from this software without
19178825Sdfr *    specific prior written permission.
20178825Sdfr *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22178825Sdfr * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24178825Sdfr * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25178825Sdfr * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26178825Sdfr * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27178825Sdfr * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28178825Sdfr * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29178825Sdfr * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30178825Sdfr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31178825Sdfr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "config.h"
35178825Sdfr
36233294Sstas#include <roken.h>
37178825Sdfr#include <stdio.h>
38178825Sdfr#include <gssapi.h>
39178825Sdfr#include <err.h>
40178825Sdfr#include <getarg.h>
41178825Sdfr#include "test_common.h"
42178825Sdfr
43178825Sdfr#include <krb5.h>
44178825Sdfr#include <heimntlm.h>
45178825Sdfr
46178825Sdfrstatic int
47178825Sdfrtest_libntlm_v1(int flags)
48178825Sdfr{
49233294Sstas    const char *user = "foo",
50178825Sdfr	*domain = "mydomain",
51178825Sdfr	*password = "digestpassword";
52178825Sdfr    OM_uint32 maj_stat, min_stat;
53178825Sdfr    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
54178825Sdfr    gss_buffer_desc input, output;
55178825Sdfr    struct ntlm_type1 type1;
56178825Sdfr    struct ntlm_type2 type2;
57178825Sdfr    struct ntlm_type3 type3;
58178825Sdfr    struct ntlm_buf data;
59178825Sdfr    krb5_error_code ret;
60178825Sdfr    gss_name_t src_name = GSS_C_NO_NAME;
61233294Sstas
62178825Sdfr    memset(&type1, 0, sizeof(type1));
63178825Sdfr    memset(&type2, 0, sizeof(type2));
64178825Sdfr    memset(&type3, 0, sizeof(type3));
65178825Sdfr
66178825Sdfr    type1.flags = NTLM_NEG_UNICODE|NTLM_NEG_TARGET|NTLM_NEG_NTLM|flags;
67178825Sdfr    type1.domain = strdup(domain);
68178825Sdfr    type1.hostname = NULL;
69178825Sdfr    type1.os[0] = 0;
70178825Sdfr    type1.os[1] = 0;
71178825Sdfr
72178825Sdfr    ret = heim_ntlm_encode_type1(&type1, &data);
73178825Sdfr    if (ret)
74178825Sdfr	errx(1, "heim_ntlm_encode_type1");
75178825Sdfr
76178825Sdfr    input.value = data.data;
77178825Sdfr    input.length = data.length;
78178825Sdfr
79178825Sdfr    output.length = 0;
80178825Sdfr    output.value = NULL;
81178825Sdfr
82178825Sdfr    maj_stat = gss_accept_sec_context(&min_stat,
83178825Sdfr				      &ctx,
84178825Sdfr				      GSS_C_NO_CREDENTIAL,
85178825Sdfr				      &input,
86178825Sdfr				      GSS_C_NO_CHANNEL_BINDINGS,
87178825Sdfr				      NULL,
88178825Sdfr				      NULL,
89178825Sdfr				      &output,
90178825Sdfr				      NULL,
91178825Sdfr				      NULL,
92178825Sdfr				      NULL);
93178825Sdfr    free(data.data);
94178825Sdfr    if (GSS_ERROR(maj_stat))
95178825Sdfr	errx(1, "accept_sec_context v1: %s",
96178825Sdfr	     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
97178825Sdfr
98178825Sdfr    if (output.length == 0)
99178825Sdfr	errx(1, "output.length == 0");
100178825Sdfr
101178825Sdfr    data.data = output.value;
102178825Sdfr    data.length = output.length;
103178825Sdfr
104178825Sdfr    ret = heim_ntlm_decode_type2(&data, &type2);
105178825Sdfr    if (ret)
106178825Sdfr	errx(1, "heim_ntlm_decode_type2");
107178825Sdfr
108178825Sdfr    gss_release_buffer(&min_stat, &output);
109178825Sdfr
110178825Sdfr    type3.flags = type2.flags;
111178825Sdfr    type3.username = rk_UNCONST(user);
112178825Sdfr    type3.targetname = type2.targetname;
113178825Sdfr    type3.ws = rk_UNCONST("workstation");
114178825Sdfr
115178825Sdfr    {
116178825Sdfr	struct ntlm_buf key;
117178825Sdfr
118178825Sdfr	heim_ntlm_nt_key(password, &key);
119178825Sdfr
120178825Sdfr	heim_ntlm_calculate_ntlm1(key.data, key.length,
121233294Sstas				  type2.challenge,
122178825Sdfr				  &type3.ntlm);
123178825Sdfr
124178825Sdfr	if (flags & NTLM_NEG_KEYEX) {
125178825Sdfr	    struct ntlm_buf sessionkey;
126178825Sdfr	    heim_ntlm_build_ntlm1_master(key.data, key.length,
127178825Sdfr					 &sessionkey,
128178825Sdfr				     &type3.sessionkey);
129178825Sdfr	    free(sessionkey.data);
130178825Sdfr	}
131178825Sdfr	free(key.data);
132178825Sdfr    }
133178825Sdfr
134178825Sdfr    ret = heim_ntlm_encode_type3(&type3, &data);
135178825Sdfr    if (ret)
136178825Sdfr	errx(1, "heim_ntlm_encode_type3");
137178825Sdfr
138178825Sdfr    input.length = data.length;
139178825Sdfr    input.value = data.data;
140178825Sdfr
141178825Sdfr    maj_stat = gss_accept_sec_context(&min_stat,
142178825Sdfr				      &ctx,
143178825Sdfr				      GSS_C_NO_CREDENTIAL,
144178825Sdfr				      &input,
145178825Sdfr				      GSS_C_NO_CHANNEL_BINDINGS,
146178825Sdfr				      &src_name,
147178825Sdfr				      NULL,
148178825Sdfr				      &output,
149178825Sdfr				      NULL,
150178825Sdfr				      NULL,
151178825Sdfr				      NULL);
152178825Sdfr    free(input.value);
153178825Sdfr    if (maj_stat != GSS_S_COMPLETE)
154178825Sdfr	errx(1, "accept_sec_context v1 2 %s",
155178825Sdfr	     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
156178825Sdfr
157178825Sdfr    gss_release_buffer(&min_stat, &output);
158178825Sdfr    gss_delete_sec_context(&min_stat, &ctx, NULL);
159178825Sdfr
160178825Sdfr    if (src_name == GSS_C_NO_NAME)
161178825Sdfr	errx(1, "no source name!");
162178825Sdfr
163178825Sdfr    gss_display_name(&min_stat, src_name, &output, NULL);
164178825Sdfr
165178825Sdfr    printf("src_name: %.*s\n", (int)output.length, (char*)output.value);
166178825Sdfr
167178825Sdfr    gss_release_name(&min_stat, &src_name);
168178825Sdfr    gss_release_buffer(&min_stat, &output);
169178825Sdfr
170178825Sdfr    return 0;
171178825Sdfr}
172178825Sdfr
173178825Sdfrstatic int
174178825Sdfrtest_libntlm_v2(int flags)
175178825Sdfr{
176233294Sstas    const char *user = "foo",
177178825Sdfr	*domain = "mydomain",
178178825Sdfr	*password = "digestpassword";
179178825Sdfr    OM_uint32 maj_stat, min_stat;
180178825Sdfr    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
181178825Sdfr    gss_buffer_desc input, output;
182178825Sdfr    struct ntlm_type1 type1;
183178825Sdfr    struct ntlm_type2 type2;
184178825Sdfr    struct ntlm_type3 type3;
185178825Sdfr    struct ntlm_buf data;
186178825Sdfr    krb5_error_code ret;
187233294Sstas
188178825Sdfr    memset(&type1, 0, sizeof(type1));
189178825Sdfr    memset(&type2, 0, sizeof(type2));
190178825Sdfr    memset(&type3, 0, sizeof(type3));
191178825Sdfr
192178825Sdfr    type1.flags = NTLM_NEG_UNICODE|NTLM_NEG_NTLM|flags;
193178825Sdfr    type1.domain = strdup(domain);
194178825Sdfr    type1.hostname = NULL;
195178825Sdfr    type1.os[0] = 0;
196178825Sdfr    type1.os[1] = 0;
197178825Sdfr
198178825Sdfr    ret = heim_ntlm_encode_type1(&type1, &data);
199178825Sdfr    if (ret)
200178825Sdfr	errx(1, "heim_ntlm_encode_type1");
201178825Sdfr
202178825Sdfr    input.value = data.data;
203178825Sdfr    input.length = data.length;
204178825Sdfr
205178825Sdfr    output.length = 0;
206178825Sdfr    output.value = NULL;
207178825Sdfr
208178825Sdfr    maj_stat = gss_accept_sec_context(&min_stat,
209178825Sdfr				      &ctx,
210178825Sdfr				      GSS_C_NO_CREDENTIAL,
211178825Sdfr				      &input,
212178825Sdfr				      GSS_C_NO_CHANNEL_BINDINGS,
213178825Sdfr				      NULL,
214178825Sdfr				      NULL,
215178825Sdfr				      &output,
216178825Sdfr				      NULL,
217178825Sdfr				      NULL,
218178825Sdfr				      NULL);
219178825Sdfr    free(data.data);
220178825Sdfr    if (GSS_ERROR(maj_stat))
221178825Sdfr	errx(1, "accept_sec_context v2 %s",
222178825Sdfr	     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
223178825Sdfr
224178825Sdfr    if (output.length == 0)
225178825Sdfr	errx(1, "output.length == 0");
226178825Sdfr
227178825Sdfr    data.data = output.value;
228178825Sdfr    data.length = output.length;
229178825Sdfr
230178825Sdfr    ret = heim_ntlm_decode_type2(&data, &type2);
231178825Sdfr    if (ret)
232178825Sdfr	errx(1, "heim_ntlm_decode_type2");
233178825Sdfr
234178825Sdfr    type3.flags = type2.flags;
235178825Sdfr    type3.username = rk_UNCONST(user);
236178825Sdfr    type3.targetname = type2.targetname;
237178825Sdfr    type3.ws = rk_UNCONST("workstation");
238178825Sdfr
239178825Sdfr    {
240178825Sdfr	struct ntlm_buf key;
241178825Sdfr	unsigned char ntlmv2[16];
242178825Sdfr
243178825Sdfr	heim_ntlm_nt_key(password, &key);
244178825Sdfr
245178825Sdfr	heim_ntlm_calculate_ntlm2(key.data, key.length,
246178825Sdfr				  user,
247178825Sdfr				  type2.targetname,
248233294Sstas				  type2.challenge,
249178825Sdfr				  &type2.targetinfo,
250178825Sdfr				  ntlmv2,
251178825Sdfr				  &type3.ntlm);
252178825Sdfr	free(key.data);
253178825Sdfr
254178825Sdfr	if (flags & NTLM_NEG_KEYEX) {
255178825Sdfr	    struct ntlm_buf sessionkey;
256178825Sdfr	    heim_ntlm_build_ntlm1_master(ntlmv2, sizeof(ntlmv2),
257178825Sdfr					 &sessionkey,
258178825Sdfr					 &type3.sessionkey);
259178825Sdfr	    free(sessionkey.data);
260178825Sdfr	}
261178825Sdfr    }
262178825Sdfr
263178825Sdfr    ret = heim_ntlm_encode_type3(&type3, &data);
264178825Sdfr    if (ret)
265178825Sdfr	errx(1, "heim_ntlm_encode_type3");
266178825Sdfr
267178825Sdfr    input.length = data.length;
268178825Sdfr    input.value = data.data;
269178825Sdfr
270178825Sdfr    maj_stat = gss_accept_sec_context(&min_stat,
271178825Sdfr				      &ctx,
272178825Sdfr				      GSS_C_NO_CREDENTIAL,
273178825Sdfr				      &input,
274178825Sdfr				      GSS_C_NO_CHANNEL_BINDINGS,
275178825Sdfr				      NULL,
276178825Sdfr				      NULL,
277178825Sdfr				      &output,
278178825Sdfr				      NULL,
279178825Sdfr				      NULL,
280178825Sdfr				      NULL);
281178825Sdfr    free(input.value);
282178825Sdfr    if (maj_stat != GSS_S_COMPLETE)
283178825Sdfr	errx(1, "accept_sec_context v2 2 %s",
284178825Sdfr	     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
285178825Sdfr
286178825Sdfr    gss_delete_sec_context(&min_stat, &ctx, NULL);
287178825Sdfr
288178825Sdfr    return 0;
289178825Sdfr}
290178825Sdfr
291178825Sdfr
292178825Sdfr
293178825Sdfrstatic int version_flag = 0;
294178825Sdfrstatic int help_flag	= 0;
295178825Sdfr
296178825Sdfrstatic struct getargs args[] = {
297178825Sdfr    {"version",	0,	arg_flag,	&version_flag, "print version", NULL },
298178825Sdfr    {"help",	0,	arg_flag,	&help_flag,  NULL, NULL }
299178825Sdfr};
300178825Sdfr
301178825Sdfrstatic void
302178825Sdfrusage (int ret)
303178825Sdfr{
304178825Sdfr    arg_printusage (args, sizeof(args)/sizeof(*args),
305178825Sdfr		    NULL, "");
306178825Sdfr    exit (ret);
307178825Sdfr}
308178825Sdfr
309178825Sdfrint
310178825Sdfrmain(int argc, char **argv)
311178825Sdfr{
312178825Sdfr    int ret = 0, optind = 0;
313178825Sdfr
314178825Sdfr    setprogname(argv[0]);
315178825Sdfr
316178825Sdfr    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind))
317178825Sdfr	usage(1);
318233294Sstas
319178825Sdfr    if (help_flag)
320178825Sdfr	usage (0);
321178825Sdfr
322178825Sdfr    if(version_flag){
323178825Sdfr	print_version(NULL);
324178825Sdfr	exit(0);
325178825Sdfr    }
326178825Sdfr
327178825Sdfr    argc -= optind;
328178825Sdfr    argv += optind;
329178825Sdfr
330178825Sdfr    ret += test_libntlm_v1(0);
331178825Sdfr    ret += test_libntlm_v1(NTLM_NEG_KEYEX);
332178825Sdfr
333178825Sdfr    ret += test_libntlm_v2(0);
334178825Sdfr    ret += test_libntlm_v2(NTLM_NEG_KEYEX);
335178825Sdfr
336178825Sdfr    return 0;
337178825Sdfr}
338