kdigest.c revision 233294
1214455Srpaulo/*
2214455Srpaulo * Copyright (c) 2006 - 2007 Kungliga Tekniska H��gskolan
3214455Srpaulo * (Royal Institute of Technology, Stockholm, Sweden).
4214455Srpaulo * All rights reserved.
5214455Srpaulo *
6214455Srpaulo * Redistribution and use in source and binary forms, with or without
7214455Srpaulo * modification, are permitted provided that the following conditions
8214455Srpaulo * are met:
9214455Srpaulo *
10214455Srpaulo * 1. Redistributions of source code must retain the above copyright
11214455Srpaulo *    notice, this list of conditions and the following disclaimer.
12214455Srpaulo *
13214455Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
14214455Srpaulo *    notice, this list of conditions and the following disclaimer in the
15214455Srpaulo *    documentation and/or other materials provided with the distribution.
16214455Srpaulo *
17214455Srpaulo * 3. Neither the name of the Institute nor the names of its contributors
18214455Srpaulo *    may be used to endorse or promote products derived from this software
19214455Srpaulo *    without specific prior written permission.
20214455Srpaulo *
21214455Srpaulo * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22214455Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23214455Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24214455Srpaulo * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25214455Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26214455Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27214455Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28214455Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29214455Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30214455Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31214455Srpaulo * SUCH DAMAGE.
32214455Srpaulo */
33214455Srpaulo
34214455Srpaulo#define HC_DEPRECATED_CRYPTO
35214455Srpaulo
36214455Srpaulo#include "kuser_locl.h"
37214455Srpaulo
38214455Srpaulo#include <kdigest-commands.h>
39214455Srpaulo#include <hex.h>
40214455Srpaulo#include <base64.h>
41214455Srpaulo#include <heimntlm.h>
42214455Srpaulo#include "crypto-headers.h"
43214455Srpaulo
44214455Srpaulostatic int version_flag = 0;
45214455Srpaulostatic int help_flag	= 0;
46214455Srpaulostatic char *ccache_string;
47214455Srpaulostatic krb5_ccache id;
48214455Srpaulo
49214455Srpaulostatic struct getargs args[] = {
50214455Srpaulo    {"ccache",	0,	arg_string,	&ccache_string, "credential cache", NULL },
51214455Srpaulo    {"version",	0,	arg_flag,	&version_flag, "print version", NULL },
52214455Srpaulo    {"help",	0,	arg_flag,	&help_flag,  NULL, NULL }
53214455Srpaulo};
54214455Srpaulo
55214455Srpaulostatic void
56214455Srpaulousage (int ret)
57214455Srpaulo{
58214455Srpaulo    arg_printusage (args, sizeof(args)/sizeof(*args),
59214455Srpaulo		    NULL, "");
60214455Srpaulo    exit (ret);
61214455Srpaulo}
62214455Srpaulo
63214455Srpaulostatic krb5_context context;
64214455Srpaulo
65214455Srpauloint
66214455Srpaulodigest_probe(struct digest_probe_options *opt,
67214455Srpaulo	     int argc, char ** argv)
68214455Srpaulo{
69214455Srpaulo    krb5_error_code ret;
70214455Srpaulo    krb5_realm realm;
71214455Srpaulo    unsigned flags;
72214455Srpaulo
73214455Srpaulo    realm = opt->realm_string;
74214455Srpaulo
75214455Srpaulo    if (realm == NULL)
76214455Srpaulo	errx(1, "realm missing");
77214455Srpaulo
78214455Srpaulo    ret = krb5_digest_probe(context, realm, id, &flags);
79214455Srpaulo    if (ret)
80214455Srpaulo	krb5_err(context, 1, ret, "digest_probe");
81214455Srpaulo
82214455Srpaulo    printf("flags: %u\n", flags);
83214455Srpaulo
84214455Srpaulo    return 0;
85214455Srpaulo}
86214455Srpaulo
87214455Srpauloint
88214455Srpaulodigest_server_init(struct digest_server_init_options *opt,
89214455Srpaulo		   int argc, char ** argv)
90214455Srpaulo{
91214455Srpaulo    krb5_error_code ret;
92214455Srpaulo    krb5_digest digest;
93214455Srpaulo
94214455Srpaulo    ret = krb5_digest_alloc(context, &digest);
95214455Srpaulo    if (ret)
96214455Srpaulo	krb5_err(context, 1, ret, "digest_alloc");
97214455Srpaulo
98214455Srpaulo    ret = krb5_digest_set_type(context, digest, opt->type_string);
99214455Srpaulo    if (ret)
100214455Srpaulo	krb5_err(context, 1, ret, "krb5_digest_set_type");
101214455Srpaulo
102214455Srpaulo    if (opt->cb_type_string && opt->cb_value_string) {
103214455Srpaulo	ret = krb5_digest_set_server_cb(context, digest,
104214455Srpaulo					opt->cb_type_string,
105214455Srpaulo					opt->cb_value_string);
106214455Srpaulo	if (ret)
107214455Srpaulo	    krb5_err(context, 1, ret, "krb5_digest_set_server_cb");
108214455Srpaulo    }
109214455Srpaulo    ret = krb5_digest_init_request(context,
110214455Srpaulo				   digest,
111214455Srpaulo				   opt->kerberos_realm_string,
112214455Srpaulo				   id);
113214455Srpaulo    if (ret)
114214455Srpaulo	krb5_err(context, 1, ret, "krb5_digest_init_request");
115214455Srpaulo
116214455Srpaulo    printf("type=%s\n", opt->type_string);
117214455Srpaulo    printf("server-nonce=%s\n",
118214455Srpaulo	   krb5_digest_get_server_nonce(context, digest));
119214455Srpaulo    {
120214455Srpaulo	const char *s = krb5_digest_get_identifier(context, digest);
121214455Srpaulo	if (s)
122214455Srpaulo	    printf("identifier=%s\n", s);
123214455Srpaulo    }
124214455Srpaulo    printf("opaque=%s\n", krb5_digest_get_opaque(context, digest));
125214455Srpaulo
126214455Srpaulo    krb5_digest_free(digest);
127214455Srpaulo
128214455Srpaulo    return 0;
129214455Srpaulo}
130214455Srpaulo
131214455Srpauloint
132214455Srpaulodigest_server_request(struct digest_server_request_options *opt,
133214455Srpaulo		      int argc, char **argv)
134214455Srpaulo{
135214455Srpaulo    krb5_error_code ret;
136214455Srpaulo    krb5_digest digest;
137214455Srpaulo    const char *status, *rsp;
138214455Srpaulo    krb5_data session_key;
139214455Srpaulo
140214455Srpaulo    if (opt->server_nonce_string == NULL)
141214455Srpaulo	errx(1, "server nonce missing");
142214455Srpaulo    if (opt->type_string == NULL)
143214455Srpaulo	errx(1, "type missing");
144214455Srpaulo    if (opt->opaque_string == NULL)
145214455Srpaulo	errx(1, "opaque missing");
146214455Srpaulo    if (opt->client_response_string == NULL)
147214455Srpaulo	errx(1, "client response missing");
148214455Srpaulo
149214455Srpaulo    ret = krb5_digest_alloc(context, &digest);
150214455Srpaulo    if (ret)
151214455Srpaulo	krb5_err(context, 1, ret, "digest_alloc");
152214455Srpaulo
153214455Srpaulo    if (strcasecmp(opt->type_string, "CHAP") == 0) {
154214455Srpaulo	if (opt->server_identifier_string == NULL)
155214455Srpaulo	    errx(1, "server identifier missing");
156214455Srpaulo
157214455Srpaulo	ret = krb5_digest_set_identifier(context, digest,
158214455Srpaulo					 opt->server_identifier_string);
159214455Srpaulo	if (ret)
160214455Srpaulo	    krb5_err(context, 1, ret, "krb5_digest_set_type");
161214455Srpaulo    }
162214455Srpaulo
163214455Srpaulo    ret = krb5_digest_set_type(context, digest, opt->type_string);
164214455Srpaulo    if (ret)
165214455Srpaulo	krb5_err(context, 1, ret, "krb5_digest_set_type");
166214455Srpaulo
167214455Srpaulo    ret = krb5_digest_set_username(context, digest, opt->username_string);
168214455Srpaulo    if (ret)
169214455Srpaulo	krb5_err(context, 1, ret, "krb5_digest_set_username");
170214455Srpaulo
171214455Srpaulo    ret = krb5_digest_set_server_nonce(context, digest,
172214455Srpaulo				       opt->server_nonce_string);
173214455Srpaulo    if (ret)
174214455Srpaulo	krb5_err(context, 1, ret, "krb5_digest_set_server_nonce");
175214455Srpaulo
176214455Srpaulo    if(opt->client_nonce_string) {
177214455Srpaulo	ret = krb5_digest_set_client_nonce(context, digest,
178214455Srpaulo					   opt->client_nonce_string);
179214455Srpaulo	if (ret)
180214455Srpaulo	    krb5_err(context, 1, ret, "krb5_digest_set_client_nonce");
181214455Srpaulo    }
182214455Srpaulo
183214455Srpaulo
184214455Srpaulo    ret = krb5_digest_set_opaque(context, digest, opt->opaque_string);
185214455Srpaulo    if (ret)
186214455Srpaulo	krb5_err(context, 1, ret, "krb5_digest_set_opaque");
187214455Srpaulo
188214455Srpaulo    ret = krb5_digest_set_responseData(context, digest,
189214455Srpaulo				       opt->client_response_string);
190214455Srpaulo    if (ret)
191214455Srpaulo	krb5_err(context, 1, ret, "krb5_digest_set_responseData");
192214455Srpaulo
193214455Srpaulo    ret = krb5_digest_request(context, digest,
194214455Srpaulo			      opt->kerberos_realm_string, id);
195214455Srpaulo    if (ret)
196214455Srpaulo	krb5_err(context, 1, ret, "krb5_digest_request");
197214455Srpaulo
198214455Srpaulo    status = krb5_digest_rep_get_status(context, digest) ? "ok" : "failed";
199214455Srpaulo    rsp = krb5_digest_get_rsp(context, digest);
200214455Srpaulo
201214455Srpaulo    printf("status=%s\n", status);
202214455Srpaulo    if (rsp)
203214455Srpaulo	printf("rsp=%s\n", rsp);
204214455Srpaulo    printf("tickets=no\n");
205214455Srpaulo
206214455Srpaulo    ret = krb5_digest_get_session_key(context, digest, &session_key);
207214455Srpaulo    if (ret)
208214455Srpaulo	krb5_err(context, 1, ret, "krb5_digest_get_session_key");
209214455Srpaulo
210214455Srpaulo    if (session_key.length) {
211214455Srpaulo	char *key;
212214455Srpaulo	hex_encode(session_key.data, session_key.length, &key);
213214455Srpaulo	if (key == NULL)
214214455Srpaulo	    krb5_errx(context, 1, "hex_encode");
215214455Srpaulo	krb5_data_free(&session_key);
216214455Srpaulo	printf("session-key=%s\n", key);
217214455Srpaulo	free(key);
218214455Srpaulo    }
219214455Srpaulo
220214455Srpaulo    krb5_digest_free(digest);
221214455Srpaulo
222214455Srpaulo    return 0;
223214455Srpaulo}
224214455Srpaulo
225214455Srpaulostatic void
226214455Srpauloclient_chap(const void *server_nonce, size_t snoncelen,
227214455Srpaulo	    unsigned char server_identifier,
228214455Srpaulo	    const char *password)
229214455Srpaulo{
230214455Srpaulo    EVP_MD_CTX *ctx;
231214455Srpaulo    unsigned char md[MD5_DIGEST_LENGTH];
232214455Srpaulo    char *h;
233214455Srpaulo
234214455Srpaulo    ctx = EVP_MD_CTX_create();
235214455Srpaulo    EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
236214455Srpaulo
237214455Srpaulo    EVP_DigestUpdate(ctx, &server_identifier, 1);
238214455Srpaulo    EVP_DigestUpdate(ctx, password, strlen(password));
239214455Srpaulo    EVP_DigestUpdate(ctx, server_nonce, snoncelen);
240214455Srpaulo    EVP_DigestFinal_ex(ctx, md, NULL);
241214455Srpaulo
242214455Srpaulo    EVP_MD_CTX_destroy(ctx);
243214455Srpaulo
244214455Srpaulo    hex_encode(md, 16, &h);
245214455Srpaulo
246214455Srpaulo    printf("responseData=%s\n", h);
247214455Srpaulo    free(h);
248214455Srpaulo}
249214455Srpaulo
250214455Srpaulostatic const unsigned char ms_chap_v2_magic1[39] = {
251214455Srpaulo    0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
252214455Srpaulo    0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
253214455Srpaulo    0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
254214455Srpaulo    0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
255214455Srpaulo};
256214455Srpaulostatic const unsigned char ms_chap_v2_magic2[41] = {
257214455Srpaulo    0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
258214455Srpaulo    0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
259214455Srpaulo    0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
260214455Srpaulo    0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
261214455Srpaulo    0x6E
262214455Srpaulo};
263214455Srpaulostatic const unsigned char ms_rfc3079_magic1[27] = {
264214455Srpaulo    0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
265214455Srpaulo    0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
266214455Srpaulo    0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
267214455Srpaulo};
268214455Srpaulo
269214455Srpaulostatic void
270214455Srpauloclient_mschapv2(const void *server_nonce, size_t snoncelen,
271214455Srpaulo		const void *client_nonce, size_t cnoncelen,
272214455Srpaulo		const char *username,
273214455Srpaulo		const char *password)
274214455Srpaulo{
275214455Srpaulo    EVP_MD_CTX *hctx, *ctx;
276214455Srpaulo    unsigned char md[SHA_DIGEST_LENGTH], challenge[SHA_DIGEST_LENGTH];
277214455Srpaulo    unsigned char hmd[MD4_DIGEST_LENGTH];
278214455Srpaulo    struct ntlm_buf answer;
279214455Srpaulo    int i, len, ret;
280214455Srpaulo    char *h;
281214455Srpaulo
282214455Srpaulo    ctx = EVP_MD_CTX_create();
283214455Srpaulo    EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
284214455Srpaulo
285214455Srpaulo    EVP_DigestUpdate(ctx, client_nonce, cnoncelen);
286214455Srpaulo    EVP_DigestUpdate(ctx, server_nonce, snoncelen);
287214455Srpaulo    EVP_DigestUpdate(ctx, username, strlen(username));
288214455Srpaulo    EVP_DigestFinal_ex(ctx, md, NULL);
289214455Srpaulo
290214455Srpaulo
291214455Srpaulo    hctx = EVP_MD_CTX_create();
292214455Srpaulo    EVP_DigestInit_ex(hctx, EVP_md4(), NULL);
293214455Srpaulo    len = strlen(password);
294214455Srpaulo    for (i = 0; i < len; i++) {
295214455Srpaulo	EVP_DigestUpdate(hctx, &password[i], 1);
296214455Srpaulo	EVP_DigestUpdate(hctx, &password[len], 1);
297214455Srpaulo    }
298214455Srpaulo    EVP_DigestFinal_ex(hctx, hmd, NULL);
299214455Srpaulo
300214455Srpaulo
301214455Srpaulo    /* ChallengeResponse */
302214455Srpaulo    ret = heim_ntlm_calculate_ntlm1(hmd, sizeof(hmd), md, &answer);
303214455Srpaulo    if (ret)
304214455Srpaulo	errx(1, "heim_ntlm_calculate_ntlm1");
305214455Srpaulo
306214455Srpaulo    hex_encode(answer.data, answer.length, &h);
307214455Srpaulo    printf("responseData=%s\n", h);
308214455Srpaulo    free(h);
309214455Srpaulo
310214455Srpaulo    /* PasswordHash */
311214455Srpaulo    EVP_DigestInit_ex(hctx, EVP_md4(), NULL);
312214455Srpaulo    EVP_DigestUpdate(hctx, hmd, sizeof(hmd));
313214455Srpaulo    EVP_DigestFinal_ex(hctx, hmd, NULL);
314214455Srpaulo
315214455Srpaulo
316214455Srpaulo    /* GenerateAuthenticatorResponse */
317214455Srpaulo    EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
318214455Srpaulo    EVP_DigestUpdate(ctx, hmd, sizeof(hmd));
319214455Srpaulo    EVP_DigestUpdate(ctx, answer.data, answer.length);
320214455Srpaulo    EVP_DigestUpdate(ctx, ms_chap_v2_magic1, sizeof(ms_chap_v2_magic1));
321214455Srpaulo    EVP_DigestFinal_ex(ctx, md, NULL);
322214455Srpaulo
323214455Srpaulo    /* ChallengeHash */
324214455Srpaulo    EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
325214455Srpaulo    EVP_DigestUpdate(ctx, client_nonce, cnoncelen);
326214455Srpaulo    EVP_DigestUpdate(ctx, server_nonce, snoncelen);
327214455Srpaulo    EVP_DigestUpdate(ctx, username, strlen(username));
328214455Srpaulo    EVP_DigestFinal_ex(ctx, challenge, NULL);
329214455Srpaulo
330214455Srpaulo    EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
331214455Srpaulo    EVP_DigestUpdate(ctx, md, sizeof(md));
332214455Srpaulo    EVP_DigestUpdate(ctx, challenge, 8);
333214455Srpaulo    EVP_DigestUpdate(ctx, ms_chap_v2_magic2, sizeof(ms_chap_v2_magic2));
334214455Srpaulo    EVP_DigestFinal_ex(ctx, md, NULL);
335214455Srpaulo
336214455Srpaulo    hex_encode(md, sizeof(md), &h);
337214455Srpaulo    printf("AuthenticatorResponse=%s\n", h);
338214455Srpaulo    free(h);
339214455Srpaulo
340214455Srpaulo    /* get_master, rfc 3079 3.4 */
341214455Srpaulo    EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
342214455Srpaulo    EVP_DigestUpdate(ctx, hmd, sizeof(hmd));
343214455Srpaulo    EVP_DigestUpdate(ctx, answer.data, answer.length);
344214455Srpaulo    EVP_DigestUpdate(ctx, ms_rfc3079_magic1, sizeof(ms_rfc3079_magic1));
345214455Srpaulo    EVP_DigestFinal_ex(ctx, md, NULL);
346214455Srpaulo
347214455Srpaulo    free(answer.data);
348214455Srpaulo
349214455Srpaulo    hex_encode(md, 16, &h);
350214455Srpaulo    printf("session-key=%s\n", h);
351214455Srpaulo    free(h);
352214455Srpaulo
353214455Srpaulo    EVP_MD_CTX_destroy(hctx);
354214455Srpaulo    EVP_MD_CTX_destroy(ctx);
355214455Srpaulo}
356214455Srpaulo
357214455Srpaulo
358214455Srpauloint
359214455Srpaulodigest_client_request(struct digest_client_request_options *opt,
360214455Srpaulo		      int argc, char **argv)
361214455Srpaulo{
362214455Srpaulo    char *server_nonce, *client_nonce = NULL, server_identifier;
363214455Srpaulo    ssize_t snoncelen, cnoncelen = 0;
364214455Srpaulo
365214455Srpaulo    if (opt->server_nonce_string == NULL)
366214455Srpaulo	errx(1, "server nonce missing");
367214455Srpaulo    if (opt->password_string == NULL)
368214455Srpaulo	errx(1, "password missing");
369214455Srpaulo
370214455Srpaulo    if (opt->opaque_string == NULL)
371214455Srpaulo	errx(1, "opaque missing");
372214455Srpaulo
373214455Srpaulo    snoncelen = strlen(opt->server_nonce_string);
374214455Srpaulo    server_nonce = malloc(snoncelen);
375214455Srpaulo    if (server_nonce == NULL)
376214455Srpaulo	errx(1, "server_nonce");
377214455Srpaulo
378214455Srpaulo    snoncelen = hex_decode(opt->server_nonce_string, server_nonce, snoncelen);
379214455Srpaulo    if (snoncelen <= 0)
380214455Srpaulo	errx(1, "server nonce wrong");
381214455Srpaulo
382214455Srpaulo    if (opt->client_nonce_string) {
383214455Srpaulo	cnoncelen = strlen(opt->client_nonce_string);
384214455Srpaulo	client_nonce = malloc(cnoncelen);
385214455Srpaulo	if (client_nonce == NULL)
386214455Srpaulo	    errx(1, "client_nonce");
387214455Srpaulo
388214455Srpaulo	cnoncelen = hex_decode(opt->client_nonce_string,
389214455Srpaulo			       client_nonce, cnoncelen);
390214455Srpaulo	if (cnoncelen <= 0)
391214455Srpaulo	    errx(1, "client nonce wrong");
392214455Srpaulo    }
393214455Srpaulo
394214455Srpaulo    if (opt->server_identifier_string) {
395214455Srpaulo	int ret;
396214455Srpaulo
397214455Srpaulo	ret = hex_decode(opt->server_identifier_string, &server_identifier, 1);
398214455Srpaulo	if (ret != 1)
399214455Srpaulo	    errx(1, "server identifier wrong length");
400214455Srpaulo    }
401214455Srpaulo
402214455Srpaulo    if (strcasecmp(opt->type_string, "CHAP") == 0) {
403214455Srpaulo	if (opt->server_identifier_string == NULL)
404214455Srpaulo	    errx(1, "server identifier missing");
405214455Srpaulo
406214455Srpaulo	client_chap(server_nonce, snoncelen, server_identifier,
407214455Srpaulo		    opt->password_string);
408214455Srpaulo
409214455Srpaulo    } else if (strcasecmp(opt->type_string, "MS-CHAP-V2") == 0) {
410214455Srpaulo	if (opt->client_nonce_string == NULL)
411214455Srpaulo	    errx(1, "client nonce missing");
412214455Srpaulo	if (opt->username_string == NULL)
413214455Srpaulo	    errx(1, "client nonce missing");
414214455Srpaulo
415214455Srpaulo	client_mschapv2(server_nonce, snoncelen,
416214455Srpaulo			client_nonce, cnoncelen,
417214455Srpaulo			opt->username_string,
418214455Srpaulo			opt->password_string);
419214455Srpaulo    }
420214455Srpaulo    if (client_nonce)
421214455Srpaulo	free(client_nonce);
422214455Srpaulo    free(server_nonce);
423214455Srpaulo
424214455Srpaulo    return 0;
425214455Srpaulo}
426214455Srpaulo
427214455Srpaulo#include <heimntlm.h>
428214455Srpaulo
429214455Srpauloint
430214455Srpaulontlm_server_init(struct ntlm_server_init_options *opt,
431214455Srpaulo		 int argc, char ** argv)
432214455Srpaulo{
433214455Srpaulo    krb5_error_code ret;
434214455Srpaulo    krb5_ntlm ntlm;
435214455Srpaulo    struct ntlm_type2 type2;
436214455Srpaulo    krb5_data challenge, opaque;
437214455Srpaulo    struct ntlm_buf data;
438214455Srpaulo    char *s;
439214455Srpaulo    static char zero2[] = "\x00\x00";
440214455Srpaulo
441214455Srpaulo    memset(&type2, 0, sizeof(type2));
442214455Srpaulo
443214455Srpaulo    ret = krb5_ntlm_alloc(context, &ntlm);
444214455Srpaulo    if (ret)
445214455Srpaulo	krb5_err(context, 1, ret, "krb5_ntlm_alloc");
446214455Srpaulo
447214455Srpaulo    ret = krb5_ntlm_init_request(context,
448214455Srpaulo				 ntlm,
449214455Srpaulo				 opt->kerberos_realm_string,
450214455Srpaulo				 id,
451214455Srpaulo				 NTLM_NEG_UNICODE|NTLM_NEG_NTLM,
452214455Srpaulo				 "NUTCRACKER",
453214455Srpaulo				 "L");
454214455Srpaulo    if (ret)
455214455Srpaulo	krb5_err(context, 1, ret, "krb5_ntlm_init_request");
456214455Srpaulo
457214455Srpaulo    /*
458214455Srpaulo     *
459214455Srpaulo     */
460214455Srpaulo
461214455Srpaulo    ret = krb5_ntlm_init_get_challange(context, ntlm, &challenge);
462214455Srpaulo    if (ret)
463214455Srpaulo	krb5_err(context, 1, ret, "krb5_ntlm_init_get_challange");
464214455Srpaulo
465214455Srpaulo    if (challenge.length != sizeof(type2.challenge))
466214455Srpaulo	krb5_errx(context, 1, "ntlm challenge have wrong length");
467214455Srpaulo    memcpy(type2.challenge, challenge.data, sizeof(type2.challenge));
468214455Srpaulo    krb5_data_free(&challenge);
469214455Srpaulo
470214455Srpaulo    ret = krb5_ntlm_init_get_flags(context, ntlm, &type2.flags);
471214455Srpaulo    if (ret)
472214455Srpaulo	krb5_err(context, 1, ret, "krb5_ntlm_init_get_flags");
473214455Srpaulo
474214455Srpaulo    krb5_ntlm_init_get_targetname(context, ntlm, &type2.targetname);
475214455Srpaulo    type2.targetinfo.data = zero2;
476214455Srpaulo    type2.targetinfo.length = 2;
477214455Srpaulo
478214455Srpaulo    ret = heim_ntlm_encode_type2(&type2, &data);
479214455Srpaulo    if (ret)
480214455Srpaulo	krb5_errx(context, 1, "heim_ntlm_encode_type2");
481214455Srpaulo
482214455Srpaulo    free(type2.targetname);
483214455Srpaulo
484214455Srpaulo    /*
485214455Srpaulo     *
486214455Srpaulo     */
487214455Srpaulo
488214455Srpaulo    base64_encode(data.data, data.length, &s);
489214455Srpaulo    free(data.data);
490214455Srpaulo    printf("type2=%s\n", s);
491214455Srpaulo    free(s);
492214455Srpaulo
493214455Srpaulo    /*
494214455Srpaulo     *
495214455Srpaulo     */
496214455Srpaulo
497214455Srpaulo    ret = krb5_ntlm_init_get_opaque(context, ntlm, &opaque);
498214455Srpaulo    if (ret)
499214455Srpaulo	krb5_err(context, 1, ret, "krb5_ntlm_init_get_opaque");
500214455Srpaulo
501214455Srpaulo    base64_encode(opaque.data, opaque.length, &s);
502214455Srpaulo    krb5_data_free(&opaque);
503214455Srpaulo    printf("opaque=%s\n", s);
504214455Srpaulo    free(s);
505214455Srpaulo
506214455Srpaulo    /*
507214455Srpaulo     *
508214455Srpaulo     */
509214455Srpaulo
510214455Srpaulo    krb5_ntlm_free(context, ntlm);
511214455Srpaulo
512214455Srpaulo    return 0;
513214455Srpaulo}
514214455Srpaulo
515214455Srpaulo
516214455Srpaulo/*
517214455Srpaulo *
518214455Srpaulo */
519214455Srpaulo
520214455Srpauloint
521214455Srpaulohelp(void *opt, int argc, char **argv)
522214455Srpaulo{
523214455Srpaulo    sl_slc_help(commands, argc, argv);
524214455Srpaulo    return 0;
525214455Srpaulo}
526214455Srpaulo
527214455Srpauloint
528214455Srpaulomain(int argc, char **argv)
529214455Srpaulo{
530214455Srpaulo    krb5_error_code ret;
531214455Srpaulo    int optidx = 0;
532214455Srpaulo
533214455Srpaulo    setprogname(argv[0]);
534214455Srpaulo
535214455Srpaulo    ret = krb5_init_context (&context);
536214455Srpaulo    if (ret == KRB5_CONFIG_BADFORMAT)
537214455Srpaulo	errx (1, "krb5_init_context failed to parse configuration file");
538214455Srpaulo    else if (ret)
539214455Srpaulo	errx(1, "krb5_init_context failed: %d", ret);
540214455Srpaulo
541214455Srpaulo    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
542214455Srpaulo	usage(1);
543214455Srpaulo
544214455Srpaulo    if (help_flag)
545214455Srpaulo	usage (0);
546214455Srpaulo
547214455Srpaulo    if(version_flag){
548214455Srpaulo	print_version(NULL);
549214455Srpaulo	exit(0);
550214455Srpaulo    }
551214455Srpaulo
552214455Srpaulo    argc -= optidx;
553214455Srpaulo    argv += optidx;
554214455Srpaulo
555214455Srpaulo    if (argc == 0) {
556214455Srpaulo	help(NULL, argc, argv);
557214455Srpaulo	return 1;
558214455Srpaulo    }
559214455Srpaulo
560214455Srpaulo    if (ccache_string) {
561214455Srpaulo	ret = krb5_cc_resolve(context, ccache_string, &id);
562214455Srpaulo	if (ret)
563214455Srpaulo	    krb5_err(context, 1, ret, "krb5_cc_resolve");
564214455Srpaulo    }
565214455Srpaulo
566214455Srpaulo    ret = sl_command (commands, argc, argv);
567214455Srpaulo    if (ret == -1) {
568214455Srpaulo	help(NULL, argc, argv);
569214455Srpaulo	return 1;
570214455Srpaulo    }
571214455Srpaulo    return ret;
572214455Srpaulo}
573214455Srpaulo