No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / krb5 / digest.c
blobeb9acabbaff005da795d294797dc0561cad92c79
1 /*
2 * Copyright (c) 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "krb5_locl.h"
35 __RCSID("$Heimdal: digest.c 22156 2007-12-04 20:02:49Z lha $"
36 "$NetBSD$");
37 #include "digest_asn1.h"
39 struct krb5_digest_data {
40 char *cbtype;
41 char *cbbinding;
43 DigestInit init;
44 DigestInitReply initReply;
45 DigestRequest request;
46 DigestResponse response;
49 krb5_error_code
50 krb5_digest_alloc(krb5_context context, krb5_digest *digest)
52 krb5_digest d;
54 d = calloc(1, sizeof(*d));
55 if (d == NULL) {
56 *digest = NULL;
57 krb5_set_error_string(context, "out of memory");
58 return ENOMEM;
60 *digest = d;
62 return 0;
65 void
66 krb5_digest_free(krb5_digest digest)
68 if (digest == NULL)
69 return;
70 free_DigestInit(&digest->init);
71 free_DigestInitReply(&digest->initReply);
72 free_DigestRequest(&digest->request);
73 free_DigestResponse(&digest->response);
74 memset(digest, 0, sizeof(*digest));
75 free(digest);
76 return;
79 krb5_error_code
80 krb5_digest_set_server_cb(krb5_context context,
81 krb5_digest digest,
82 const char *type,
83 const char *binding)
85 if (digest->init.channel) {
86 krb5_set_error_string(context, "server channel binding already set");
87 return EINVAL;
89 digest->init.channel = calloc(1, sizeof(*digest->init.channel));
90 if (digest->init.channel == NULL)
91 goto error;
93 digest->init.channel->cb_type = strdup(type);
94 if (digest->init.channel->cb_type == NULL)
95 goto error;
97 digest->init.channel->cb_binding = strdup(binding);
98 if (digest->init.channel->cb_binding == NULL)
99 goto error;
100 return 0;
101 error:
102 if (digest->init.channel) {
103 free(digest->init.channel->cb_type);
104 free(digest->init.channel->cb_binding);
105 free(digest->init.channel);
106 digest->init.channel = NULL;
108 krb5_set_error_string(context, "out of memory");
109 return ENOMEM;
112 krb5_error_code
113 krb5_digest_set_type(krb5_context context,
114 krb5_digest digest,
115 const char *type)
117 if (digest->init.type) {
118 krb5_set_error_string(context, "client type already set");
119 return EINVAL;
121 digest->init.type = strdup(type);
122 if (digest->init.type == NULL) {
123 krb5_set_error_string(context, "out of memory");
124 return ENOMEM;
126 return 0;
129 krb5_error_code
130 krb5_digest_set_hostname(krb5_context context,
131 krb5_digest digest,
132 const char *hostname)
134 if (digest->init.hostname) {
135 krb5_set_error_string(context, "server hostname already set");
136 return EINVAL;
138 digest->init.hostname = malloc(sizeof(*digest->init.hostname));
139 if (digest->init.hostname == NULL) {
140 krb5_set_error_string(context, "out of memory");
141 return ENOMEM;
143 *digest->init.hostname = strdup(hostname);
144 if (*digest->init.hostname == NULL) {
145 krb5_set_error_string(context, "out of memory");
146 free(digest->init.hostname);
147 digest->init.hostname = NULL;
148 return ENOMEM;
150 return 0;
153 const char *
154 krb5_digest_get_server_nonce(krb5_context context,
155 krb5_digest digest)
157 return digest->initReply.nonce;
160 krb5_error_code
161 krb5_digest_set_server_nonce(krb5_context context,
162 krb5_digest digest,
163 const char *nonce)
165 if (digest->request.serverNonce) {
166 krb5_set_error_string(context, "nonce already set");
167 return EINVAL;
169 digest->request.serverNonce = strdup(nonce);
170 if (digest->request.serverNonce == NULL) {
171 krb5_set_error_string(context, "out of memory");
172 return ENOMEM;
174 return 0;
177 const char *
178 krb5_digest_get_opaque(krb5_context context,
179 krb5_digest digest)
181 return digest->initReply.opaque;
184 krb5_error_code
185 krb5_digest_set_opaque(krb5_context context,
186 krb5_digest digest,
187 const char *opaque)
189 if (digest->request.opaque) {
190 krb5_set_error_string(context, "opaque already set");
191 return EINVAL;
193 digest->request.opaque = strdup(opaque);
194 if (digest->request.opaque == NULL) {
195 krb5_set_error_string(context, "out of memory");
196 return ENOMEM;
198 return 0;
201 const char *
202 krb5_digest_get_identifier(krb5_context context,
203 krb5_digest digest)
205 if (digest->initReply.identifier == NULL)
206 return NULL;
207 return *digest->initReply.identifier;
210 krb5_error_code
211 krb5_digest_set_identifier(krb5_context context,
212 krb5_digest digest,
213 const char *id)
215 if (digest->request.identifier) {
216 krb5_set_error_string(context, "identifier already set");
217 return EINVAL;
219 digest->request.identifier = calloc(1, sizeof(*digest->request.identifier));
220 if (digest->request.identifier == NULL) {
221 krb5_set_error_string(context, "out of memory");
222 return ENOMEM;
224 *digest->request.identifier = strdup(id);
225 if (*digest->request.identifier == NULL) {
226 krb5_set_error_string(context, "out of memory");
227 free(digest->request.identifier);
228 digest->request.identifier = NULL;
229 return ENOMEM;
231 return 0;
234 static krb5_error_code
235 digest_request(krb5_context context,
236 krb5_realm realm,
237 krb5_ccache ccache,
238 krb5_key_usage usage,
239 const DigestReqInner *ireq,
240 DigestRepInner *irep)
242 DigestREQ req;
243 DigestREP rep;
244 krb5_error_code ret;
245 krb5_data data, data2;
246 size_t size;
247 krb5_crypto crypto = NULL;
248 krb5_auth_context ac = NULL;
249 krb5_principal principal = NULL;
250 krb5_ccache id = NULL;
251 krb5_realm r = NULL;
253 krb5_data_zero(&data);
254 krb5_data_zero(&data2);
255 memset(&req, 0, sizeof(req));
256 memset(&rep, 0, sizeof(rep));
258 if (ccache == NULL) {
259 ret = krb5_cc_default(context, &id);
260 if (ret)
261 goto out;
262 } else
263 id = ccache;
265 if (realm == NULL) {
266 ret = krb5_get_default_realm(context, &r);
267 if (ret)
268 goto out;
269 } else
270 r = realm;
276 ret = krb5_make_principal(context, &principal,
277 r, KRB5_DIGEST_NAME, r, NULL);
278 if (ret)
279 goto out;
281 ASN1_MALLOC_ENCODE(DigestReqInner, data.data, data.length,
282 ireq, &size, ret);
283 if (ret) {
284 krb5_set_error_string(context,
285 "Failed to encode digest inner request");
286 goto out;
288 if (size != data.length)
289 krb5_abortx(context, "ASN.1 internal encoder error");
291 ret = krb5_mk_req_exact(context, &ac,
292 AP_OPTS_USE_SUBKEY|AP_OPTS_MUTUAL_REQUIRED,
293 principal, NULL, id, &req.apReq);
294 if (ret)
295 goto out;
298 krb5_keyblock *key;
300 ret = krb5_auth_con_getlocalsubkey(context, ac, &key);
301 if (ret)
302 goto out;
303 if (key == NULL) {
304 krb5_set_error_string(context, "Digest failed to get local subkey");
305 ret = EINVAL;
306 goto out;
309 ret = krb5_crypto_init(context, key, 0, &crypto);
310 krb5_free_keyblock (context, key);
311 if (ret)
312 goto out;
315 ret = krb5_encrypt_EncryptedData(context, crypto, usage,
316 data.data, data.length, 0,
317 &req.innerReq);
318 if (ret)
319 goto out;
321 krb5_data_free(&data);
323 ASN1_MALLOC_ENCODE(DigestREQ, data.data, data.length,
324 &req, &size, ret);
325 if (ret) {
326 krb5_set_error_string(context, "Failed to encode DigestREQest");
327 goto out;
329 if (size != data.length)
330 krb5_abortx(context, "ASN.1 internal encoder error");
332 ret = krb5_sendto_kdc(context, &data, &r, &data2);
333 if (ret)
334 goto out;
336 ret = decode_DigestREP(data2.data, data2.length, &rep, NULL);
337 if (ret) {
338 krb5_set_error_string(context, "Failed to parse digest response");
339 goto out;
343 krb5_ap_rep_enc_part *repl;
345 ret = krb5_rd_rep(context, ac, &rep.apRep, &repl);
346 if (ret)
347 goto out;
349 krb5_free_ap_rep_enc_part(context, repl);
352 krb5_keyblock *key;
354 ret = krb5_auth_con_getremotesubkey(context, ac, &key);
355 if (ret)
356 goto out;
357 if (key == NULL) {
358 ret = EINVAL;
359 krb5_set_error_string(context,
360 "Digest reply have no remote subkey");
361 goto out;
364 krb5_crypto_destroy(context, crypto);
365 ret = krb5_crypto_init(context, key, 0, &crypto);
366 krb5_free_keyblock (context, key);
367 if (ret)
368 goto out;
371 krb5_data_free(&data);
372 ret = krb5_decrypt_EncryptedData(context, crypto, usage,
373 &rep.innerRep, &data);
374 if (ret)
375 goto out;
377 ret = decode_DigestRepInner(data.data, data.length, irep, NULL);
378 if (ret) {
379 krb5_set_error_string(context, "Failed to decode digest inner reply");
380 goto out;
383 out:
384 if (ccache == NULL && id)
385 krb5_cc_close(context, id);
386 if (realm == NULL && r)
387 free(r);
388 if (crypto)
389 krb5_crypto_destroy(context, crypto);
390 if (ac)
391 krb5_auth_con_free(context, ac);
392 if (principal)
393 krb5_free_principal(context, principal);
395 krb5_data_free(&data);
396 krb5_data_free(&data2);
398 free_DigestREQ(&req);
399 free_DigestREP(&rep);
401 return ret;
404 krb5_error_code
405 krb5_digest_init_request(krb5_context context,
406 krb5_digest digest,
407 krb5_realm realm,
408 krb5_ccache ccache)
410 DigestReqInner ireq;
411 DigestRepInner irep;
412 krb5_error_code ret;
414 memset(&ireq, 0, sizeof(ireq));
415 memset(&irep, 0, sizeof(irep));
417 if (digest->init.type == NULL) {
418 krb5_set_error_string(context, "Type missing from init req");
419 return EINVAL;
422 ireq.element = choice_DigestReqInner_init;
423 ireq.u.init = digest->init;
425 ret = digest_request(context, realm, ccache,
426 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
427 if (ret)
428 goto out;
430 if (irep.element == choice_DigestRepInner_error) {
431 krb5_set_error_string(context, "Digest init error: %s",
432 irep.u.error.reason);
433 ret = irep.u.error.code;
434 goto out;
437 if (irep.element != choice_DigestRepInner_initReply) {
438 krb5_set_error_string(context, "digest reply not an initReply");
439 ret = EINVAL;
440 goto out;
443 ret = copy_DigestInitReply(&irep.u.initReply, &digest->initReply);
444 if (ret) {
445 krb5_set_error_string(context, "Failed to copy initReply");
446 goto out;
449 out:
450 free_DigestRepInner(&irep);
452 return ret;
456 krb5_error_code
457 krb5_digest_set_client_nonce(krb5_context context,
458 krb5_digest digest,
459 const char *nonce)
461 if (digest->request.clientNonce) {
462 krb5_set_error_string(context, "clientNonce already set");
463 return EINVAL;
465 digest->request.clientNonce =
466 calloc(1, sizeof(*digest->request.clientNonce));
467 if (digest->request.clientNonce == NULL) {
468 krb5_set_error_string(context, "out of memory");
469 return ENOMEM;
471 *digest->request.clientNonce = strdup(nonce);
472 if (*digest->request.clientNonce == NULL) {
473 krb5_set_error_string(context, "out of memory");
474 free(digest->request.clientNonce);
475 digest->request.clientNonce = NULL;
476 return ENOMEM;
478 return 0;
481 krb5_error_code
482 krb5_digest_set_digest(krb5_context context,
483 krb5_digest digest,
484 const char *dgst)
486 if (digest->request.digest) {
487 krb5_set_error_string(context, "digest already set");
488 return EINVAL;
490 digest->request.digest = strdup(dgst);
491 if (digest->request.digest == NULL) {
492 krb5_set_error_string(context, "out of memory");
493 return ENOMEM;
495 return 0;
498 krb5_error_code
499 krb5_digest_set_username(krb5_context context,
500 krb5_digest digest,
501 const char *username)
503 if (digest->request.username) {
504 krb5_set_error_string(context, "username already set");
505 return EINVAL;
507 digest->request.username = strdup(username);
508 if (digest->request.username == NULL) {
509 krb5_set_error_string(context, "out of memory");
510 return ENOMEM;
512 return 0;
515 krb5_error_code
516 krb5_digest_set_authid(krb5_context context,
517 krb5_digest digest,
518 const char *authid)
520 if (digest->request.authid) {
521 krb5_set_error_string(context, "authid already set");
522 return EINVAL;
524 digest->request.authid = malloc(sizeof(*digest->request.authid));
525 if (digest->request.authid == NULL) {
526 krb5_set_error_string(context, "out of memory");
527 return ENOMEM;
529 *digest->request.authid = strdup(authid);
530 if (*digest->request.authid == NULL) {
531 krb5_set_error_string(context, "out of memory");
532 free(digest->request.authid);
533 digest->request.authid = NULL;
534 return ENOMEM;
536 return 0;
539 krb5_error_code
540 krb5_digest_set_authentication_user(krb5_context context,
541 krb5_digest digest,
542 krb5_principal authentication_user)
544 krb5_error_code ret;
546 if (digest->request.authentication_user) {
547 krb5_set_error_string(context, "authentication_user already set");
548 return EINVAL;
550 ret = krb5_copy_principal(context,
551 authentication_user,
552 &digest->request.authentication_user);
553 if (digest->request.authentication_user == NULL) {
554 krb5_set_error_string(context, "out of memory");
555 return ENOMEM;
557 return 0;
560 krb5_error_code
561 krb5_digest_set_realm(krb5_context context,
562 krb5_digest digest,
563 const char *realm)
565 if (digest->request.realm) {
566 krb5_set_error_string(context, "realm already set");
567 return EINVAL;
569 digest->request.realm = malloc(sizeof(*digest->request.realm));
570 if (digest->request.realm == NULL) {
571 krb5_set_error_string(context, "out of memory");
572 return ENOMEM;
574 *digest->request.realm = strdup(realm);
575 if (*digest->request.realm == NULL) {
576 krb5_set_error_string(context, "out of memory");
577 free(digest->request.realm);
578 digest->request.realm = NULL;
579 return ENOMEM;
581 return 0;
584 krb5_error_code
585 krb5_digest_set_method(krb5_context context,
586 krb5_digest digest,
587 const char *method)
589 if (digest->request.method) {
590 krb5_set_error_string(context, "method already set");
591 return EINVAL;
593 digest->request.method = malloc(sizeof(*digest->request.method));
594 if (digest->request.method == NULL) {
595 krb5_set_error_string(context, "out of memory");
596 return ENOMEM;
598 *digest->request.method = strdup(method);
599 if (*digest->request.method == NULL) {
600 krb5_set_error_string(context, "out of memory");
601 free(digest->request.method);
602 digest->request.method = NULL;
603 return ENOMEM;
605 return 0;
608 krb5_error_code
609 krb5_digest_set_uri(krb5_context context,
610 krb5_digest digest,
611 const char *uri)
613 if (digest->request.uri) {
614 krb5_set_error_string(context, "uri already set");
615 return EINVAL;
617 digest->request.uri = malloc(sizeof(*digest->request.uri));
618 if (digest->request.uri == NULL) {
619 krb5_set_error_string(context, "out of memory");
620 return ENOMEM;
622 *digest->request.uri = strdup(uri);
623 if (*digest->request.uri == NULL) {
624 krb5_set_error_string(context, "out of memory");
625 free(digest->request.uri);
626 digest->request.uri = NULL;
627 return ENOMEM;
629 return 0;
632 krb5_error_code
633 krb5_digest_set_nonceCount(krb5_context context,
634 krb5_digest digest,
635 const char *nonce_count)
637 if (digest->request.nonceCount) {
638 krb5_set_error_string(context, "nonceCount already set");
639 return EINVAL;
641 digest->request.nonceCount =
642 malloc(sizeof(*digest->request.nonceCount));
643 if (digest->request.nonceCount == NULL) {
644 krb5_set_error_string(context, "out of memory");
645 return ENOMEM;
647 *digest->request.nonceCount = strdup(nonce_count);
648 if (*digest->request.nonceCount == NULL) {
649 krb5_set_error_string(context, "out of memory");
650 free(digest->request.nonceCount);
651 digest->request.nonceCount = NULL;
652 return ENOMEM;
654 return 0;
657 krb5_error_code
658 krb5_digest_set_qop(krb5_context context,
659 krb5_digest digest,
660 const char *qop)
662 if (digest->request.qop) {
663 krb5_set_error_string(context, "qop already set");
664 return EINVAL;
666 digest->request.qop = malloc(sizeof(*digest->request.qop));
667 if (digest->request.qop == NULL) {
668 krb5_set_error_string(context, "out of memory");
669 return ENOMEM;
671 *digest->request.qop = strdup(qop);
672 if (*digest->request.qop == NULL) {
673 krb5_set_error_string(context, "out of memory");
674 free(digest->request.qop);
675 digest->request.qop = NULL;
676 return ENOMEM;
678 return 0;
682 krb5_digest_set_responseData(krb5_context context,
683 krb5_digest digest,
684 const char *response)
686 digest->request.responseData = strdup(response);
687 if (digest->request.responseData == NULL) {
688 krb5_set_error_string(context, "out of memory");
689 return ENOMEM;
691 return 0;
694 krb5_error_code
695 krb5_digest_request(krb5_context context,
696 krb5_digest digest,
697 krb5_realm realm,
698 krb5_ccache ccache)
700 DigestReqInner ireq;
701 DigestRepInner irep;
702 krb5_error_code ret;
704 memset(&ireq, 0, sizeof(ireq));
705 memset(&irep, 0, sizeof(irep));
707 ireq.element = choice_DigestReqInner_digestRequest;
708 ireq.u.digestRequest = digest->request;
710 if (digest->request.type == NULL) {
711 if (digest->init.type == NULL) {
712 krb5_set_error_string(context, "Type missing from req");
713 return EINVAL;
715 ireq.u.digestRequest.type = digest->init.type;
718 if (ireq.u.digestRequest.digest == NULL)
719 ireq.u.digestRequest.digest = "md5";
721 ret = digest_request(context, realm, ccache,
722 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
723 if (ret)
724 return ret;
726 if (irep.element == choice_DigestRepInner_error) {
727 krb5_set_error_string(context, "Digest response error: %s",
728 irep.u.error.reason);
729 ret = irep.u.error.code;
730 goto out;
733 if (irep.element != choice_DigestRepInner_response) {
734 krb5_set_error_string(context, "digest reply not an DigestResponse");
735 ret = EINVAL;
736 goto out;
739 ret = copy_DigestResponse(&irep.u.response, &digest->response);
740 if (ret) {
741 krb5_set_error_string(context, "Failed to copy initReply");
742 goto out;
745 out:
746 free_DigestRepInner(&irep);
748 return ret;
751 krb5_boolean
752 krb5_digest_rep_get_status(krb5_context context,
753 krb5_digest digest)
755 return digest->response.success ? TRUE : FALSE;
758 const char *
759 krb5_digest_get_rsp(krb5_context context,
760 krb5_digest digest)
762 if (digest->response.rsp == NULL)
763 return NULL;
764 return *digest->response.rsp;
767 krb5_error_code
768 krb5_digest_get_tickets(krb5_context context,
769 krb5_digest digest,
770 Ticket **tickets)
772 *tickets = NULL;
773 return 0;
777 krb5_error_code
778 krb5_digest_get_client_binding(krb5_context context,
779 krb5_digest digest,
780 char **type,
781 char **binding)
783 if (digest->response.channel) {
784 *type = strdup(digest->response.channel->cb_type);
785 *binding = strdup(digest->response.channel->cb_binding);
786 if (*type == NULL || *binding == NULL) {
787 free(*type);
788 free(*binding);
789 krb5_set_error_string(context, "out of memory");
790 return ENOMEM;
792 } else {
793 *type = NULL;
794 *binding = NULL;
796 return 0;
799 krb5_error_code
800 krb5_digest_get_session_key(krb5_context context,
801 krb5_digest digest,
802 krb5_data *data)
804 krb5_error_code ret;
806 krb5_data_zero(data);
807 if (digest->response.session_key == NULL)
808 return 0;
809 ret = der_copy_octet_string(digest->response.session_key, data);
810 if (ret)
811 krb5_clear_error_string(context);
813 return ret;
816 struct krb5_ntlm_data {
817 NTLMInit init;
818 NTLMInitReply initReply;
819 NTLMRequest request;
820 NTLMResponse response;
823 krb5_error_code
824 krb5_ntlm_alloc(krb5_context context,
825 krb5_ntlm *ntlm)
827 *ntlm = calloc(1, sizeof(**ntlm));
828 if (*ntlm == NULL) {
829 krb5_set_error_string(context, "out of memory");
830 return ENOMEM;
832 return 0;
835 krb5_error_code
836 krb5_ntlm_free(krb5_context context, krb5_ntlm ntlm)
838 free_NTLMInit(&ntlm->init);
839 free_NTLMInitReply(&ntlm->initReply);
840 free_NTLMRequest(&ntlm->request);
841 free_NTLMResponse(&ntlm->response);
842 memset(ntlm, 0, sizeof(*ntlm));
843 free(ntlm);
844 return 0;
848 krb5_error_code
849 krb5_ntlm_init_request(krb5_context context,
850 krb5_ntlm ntlm,
851 krb5_realm realm,
852 krb5_ccache ccache,
853 uint32_t flags,
854 const char *hostname,
855 const char *domainname)
857 DigestReqInner ireq;
858 DigestRepInner irep;
859 krb5_error_code ret;
861 memset(&ireq, 0, sizeof(ireq));
862 memset(&irep, 0, sizeof(irep));
864 ntlm->init.flags = flags;
865 if (hostname) {
866 ALLOC(ntlm->init.hostname, 1);
867 *ntlm->init.hostname = strdup(hostname);
869 if (domainname) {
870 ALLOC(ntlm->init.domain, 1);
871 *ntlm->init.domain = strdup(domainname);
874 ireq.element = choice_DigestReqInner_ntlmInit;
875 ireq.u.ntlmInit = ntlm->init;
877 ret = digest_request(context, realm, ccache,
878 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
879 if (ret)
880 goto out;
882 if (irep.element == choice_DigestRepInner_error) {
883 krb5_set_error_string(context, "Digest init error: %s",
884 irep.u.error.reason);
885 ret = irep.u.error.code;
886 goto out;
889 if (irep.element != choice_DigestRepInner_ntlmInitReply) {
890 krb5_set_error_string(context, "ntlm reply not an initReply");
891 ret = EINVAL;
892 goto out;
895 ret = copy_NTLMInitReply(&irep.u.ntlmInitReply, &ntlm->initReply);
896 if (ret) {
897 krb5_set_error_string(context, "Failed to copy initReply");
898 goto out;
901 out:
902 free_DigestRepInner(&irep);
904 return ret;
907 krb5_error_code
908 krb5_ntlm_init_get_flags(krb5_context context,
909 krb5_ntlm ntlm,
910 uint32_t *flags)
912 *flags = ntlm->initReply.flags;
913 return 0;
916 krb5_error_code
917 krb5_ntlm_init_get_challange(krb5_context context,
918 krb5_ntlm ntlm,
919 krb5_data *challange)
921 krb5_error_code ret;
923 ret = der_copy_octet_string(&ntlm->initReply.challange, challange);
924 if (ret)
925 krb5_clear_error_string(context);
927 return ret;
930 krb5_error_code
931 krb5_ntlm_init_get_opaque(krb5_context context,
932 krb5_ntlm ntlm,
933 krb5_data *opaque)
935 krb5_error_code ret;
937 ret = der_copy_octet_string(&ntlm->initReply.opaque, opaque);
938 if (ret)
939 krb5_clear_error_string(context);
941 return ret;
944 krb5_error_code
945 krb5_ntlm_init_get_targetname(krb5_context context,
946 krb5_ntlm ntlm,
947 char **name)
949 *name = strdup(ntlm->initReply.targetname);
950 if (*name == NULL) {
951 krb5_clear_error_string(context);
952 return ENOMEM;
954 return 0;
957 krb5_error_code
958 krb5_ntlm_init_get_targetinfo(krb5_context context,
959 krb5_ntlm ntlm,
960 krb5_data *data)
962 krb5_error_code ret;
964 if (ntlm->initReply.targetinfo == NULL) {
965 krb5_data_zero(data);
966 return 0;
969 ret = krb5_data_copy(data,
970 ntlm->initReply.targetinfo->data,
971 ntlm->initReply.targetinfo->length);
972 if (ret) {
973 krb5_clear_error_string(context);
974 return ret;
976 return 0;
980 krb5_error_code
981 krb5_ntlm_request(krb5_context context,
982 krb5_ntlm ntlm,
983 krb5_realm realm,
984 krb5_ccache ccache)
986 DigestReqInner ireq;
987 DigestRepInner irep;
988 krb5_error_code ret;
990 memset(&ireq, 0, sizeof(ireq));
991 memset(&irep, 0, sizeof(irep));
993 ireq.element = choice_DigestReqInner_ntlmRequest;
994 ireq.u.ntlmRequest = ntlm->request;
996 ret = digest_request(context, realm, ccache,
997 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
998 if (ret)
999 return ret;
1001 if (irep.element == choice_DigestRepInner_error) {
1002 krb5_set_error_string(context, "NTLM response error: %s",
1003 irep.u.error.reason);
1004 ret = irep.u.error.code;
1005 goto out;
1008 if (irep.element != choice_DigestRepInner_ntlmResponse) {
1009 krb5_set_error_string(context, "NTLM reply not an NTLMResponse");
1010 ret = EINVAL;
1011 goto out;
1014 ret = copy_NTLMResponse(&irep.u.ntlmResponse, &ntlm->response);
1015 if (ret) {
1016 krb5_set_error_string(context, "Failed to copy NTLMResponse");
1017 goto out;
1020 out:
1021 free_DigestRepInner(&irep);
1023 return ret;
1026 krb5_error_code
1027 krb5_ntlm_req_set_flags(krb5_context context,
1028 krb5_ntlm ntlm,
1029 uint32_t flags)
1031 ntlm->request.flags = flags;
1032 return 0;
1035 krb5_error_code
1036 krb5_ntlm_req_set_username(krb5_context context,
1037 krb5_ntlm ntlm,
1038 const char *username)
1040 ntlm->request.username = strdup(username);
1041 if (ntlm->request.username == NULL) {
1042 krb5_set_error_string(context, "out of memory");
1043 return ENOMEM;
1045 return 0;
1048 krb5_error_code
1049 krb5_ntlm_req_set_targetname(krb5_context context,
1050 krb5_ntlm ntlm,
1051 const char *targetname)
1053 ntlm->request.targetname = strdup(targetname);
1054 if (ntlm->request.targetname == NULL) {
1055 krb5_set_error_string(context, "out of memory");
1056 return ENOMEM;
1058 return 0;
1061 krb5_error_code
1062 krb5_ntlm_req_set_lm(krb5_context context,
1063 krb5_ntlm ntlm,
1064 void *hash, size_t len)
1066 ntlm->request.lm.data = malloc(len);
1067 if (ntlm->request.lm.data == NULL) {
1068 krb5_set_error_string(context, "out of memory");
1069 return ENOMEM;
1071 ntlm->request.lm.length = len;
1072 memcpy(ntlm->request.lm.data, hash, len);
1073 return 0;
1076 krb5_error_code
1077 krb5_ntlm_req_set_ntlm(krb5_context context,
1078 krb5_ntlm ntlm,
1079 void *hash, size_t len)
1081 ntlm->request.ntlm.data = malloc(len);
1082 if (ntlm->request.ntlm.data == NULL) {
1083 krb5_set_error_string(context, "out of memory");
1084 return ENOMEM;
1086 ntlm->request.ntlm.length = len;
1087 memcpy(ntlm->request.ntlm.data, hash, len);
1088 return 0;
1091 krb5_error_code
1092 krb5_ntlm_req_set_opaque(krb5_context context,
1093 krb5_ntlm ntlm,
1094 krb5_data *opaque)
1096 ntlm->request.opaque.data = malloc(opaque->length);
1097 if (ntlm->request.opaque.data == NULL) {
1098 krb5_set_error_string(context, "out of memory");
1099 return ENOMEM;
1101 ntlm->request.opaque.length = opaque->length;
1102 memcpy(ntlm->request.opaque.data, opaque->data, opaque->length);
1103 return 0;
1106 krb5_error_code
1107 krb5_ntlm_req_set_session(krb5_context context,
1108 krb5_ntlm ntlm,
1109 void *sessionkey, size_t length)
1111 ntlm->request.sessionkey = calloc(1, sizeof(*ntlm->request.sessionkey));
1112 if (ntlm->request.sessionkey == NULL) {
1113 krb5_set_error_string(context, "out of memory");
1114 return ENOMEM;
1116 ntlm->request.sessionkey->data = malloc(length);
1117 if (ntlm->request.sessionkey->data == NULL) {
1118 krb5_set_error_string(context, "out of memory");
1119 return ENOMEM;
1121 memcpy(ntlm->request.sessionkey->data, sessionkey, length);
1122 ntlm->request.sessionkey->length = length;
1123 return 0;
1126 krb5_boolean
1127 krb5_ntlm_rep_get_status(krb5_context context,
1128 krb5_ntlm ntlm)
1130 return ntlm->response.success ? TRUE : FALSE;
1133 krb5_error_code
1134 krb5_ntlm_rep_get_sessionkey(krb5_context context,
1135 krb5_ntlm ntlm,
1136 krb5_data *data)
1138 if (ntlm->response.sessionkey == NULL) {
1139 krb5_set_error_string(context, "no ntlm session key");
1140 return EINVAL;
1142 krb5_clear_error_string(context);
1143 return krb5_data_copy(data,
1144 ntlm->response.sessionkey->data,
1145 ntlm->response.sessionkey->length);
1149 * Get the supported/allowed mechanism for this principal.
1151 * @param context A Keberos context.
1152 * @param realm The realm of the KDC.
1153 * @param ccache The credential cache to use when talking to the KDC.
1154 * @param flags The supported mechanism.
1156 * @return Return an error code or 0.
1158 * @ingroup krb5_digest
1161 krb5_error_code
1162 krb5_digest_probe(krb5_context context,
1163 krb5_realm realm,
1164 krb5_ccache ccache,
1165 unsigned *flags)
1167 DigestReqInner ireq;
1168 DigestRepInner irep;
1169 krb5_error_code ret;
1171 memset(&ireq, 0, sizeof(ireq));
1172 memset(&irep, 0, sizeof(irep));
1174 ireq.element = choice_DigestReqInner_supportedMechs;
1176 ret = digest_request(context, realm, ccache,
1177 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
1178 if (ret)
1179 goto out;
1181 if (irep.element == choice_DigestRepInner_error) {
1182 krb5_set_error_string(context, "Digest probe error: %s",
1183 irep.u.error.reason);
1184 ret = irep.u.error.code;
1185 goto out;
1188 if (irep.element != choice_DigestRepInner_supportedMechs) {
1189 krb5_set_error_string(context, "Digest reply not an probe");
1190 ret = EINVAL;
1191 goto out;
1194 *flags = DigestTypes2int(irep.u.supportedMechs);
1196 out:
1197 free_DigestRepInner(&irep);
1199 return ret;