1*d3273b5bSchristos /* $NetBSD: digest.c,v 1.2 2017/01/28 21:31:49 christos Exp $ */
2ca1c9b0cSelric
3ca1c9b0cSelric /*
4ca1c9b0cSelric * Copyright (c) 2006 Kungliga Tekniska Högskolan
5ca1c9b0cSelric * (Royal Institute of Technology, Stockholm, Sweden).
6ca1c9b0cSelric * All rights reserved.
7ca1c9b0cSelric *
8ca1c9b0cSelric * Redistribution and use in source and binary forms, with or without
9ca1c9b0cSelric * modification, are permitted provided that the following conditions
10ca1c9b0cSelric * are met:
11ca1c9b0cSelric *
12ca1c9b0cSelric * 1. Redistributions of source code must retain the above copyright
13ca1c9b0cSelric * notice, this list of conditions and the following disclaimer.
14ca1c9b0cSelric *
15ca1c9b0cSelric * 2. Redistributions in binary form must reproduce the above copyright
16ca1c9b0cSelric * notice, this list of conditions and the following disclaimer in the
17ca1c9b0cSelric * documentation and/or other materials provided with the distribution.
18ca1c9b0cSelric *
19ca1c9b0cSelric * 3. Neither the name of the Institute nor the names of its contributors
20ca1c9b0cSelric * may be used to endorse or promote products derived from this software
21ca1c9b0cSelric * without specific prior written permission.
22ca1c9b0cSelric *
23ca1c9b0cSelric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24ca1c9b0cSelric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ca1c9b0cSelric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ca1c9b0cSelric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27ca1c9b0cSelric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ca1c9b0cSelric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ca1c9b0cSelric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ca1c9b0cSelric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ca1c9b0cSelric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ca1c9b0cSelric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ca1c9b0cSelric * SUCH DAMAGE.
34ca1c9b0cSelric */
35ca1c9b0cSelric
36ca1c9b0cSelric #include "krb5_locl.h"
37ca1c9b0cSelric #include <krb5/digest_asn1.h>
38ca1c9b0cSelric
39ca1c9b0cSelric #ifndef HEIMDAL_SMALLER
40ca1c9b0cSelric
41ca1c9b0cSelric struct krb5_digest_data {
42ca1c9b0cSelric char *cbtype;
43ca1c9b0cSelric char *cbbinding;
44ca1c9b0cSelric
45ca1c9b0cSelric DigestInit init;
46ca1c9b0cSelric DigestInitReply initReply;
47ca1c9b0cSelric DigestRequest request;
48ca1c9b0cSelric DigestResponse response;
49ca1c9b0cSelric };
50ca1c9b0cSelric
51ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_alloc(krb5_context context,krb5_digest * digest)52ca1c9b0cSelric krb5_digest_alloc(krb5_context context, krb5_digest *digest)
53ca1c9b0cSelric {
54ca1c9b0cSelric krb5_digest d;
55ca1c9b0cSelric
56ca1c9b0cSelric d = calloc(1, sizeof(*d));
57ca1c9b0cSelric if (d == NULL) {
58ca1c9b0cSelric *digest = NULL;
59b9d004c6Schristos return krb5_enomem(context);
60ca1c9b0cSelric }
61ca1c9b0cSelric *digest = d;
62ca1c9b0cSelric
63ca1c9b0cSelric return 0;
64ca1c9b0cSelric }
65ca1c9b0cSelric
66ca1c9b0cSelric KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_digest_free(krb5_digest digest)67ca1c9b0cSelric krb5_digest_free(krb5_digest digest)
68ca1c9b0cSelric {
69ca1c9b0cSelric if (digest == NULL)
70ca1c9b0cSelric return;
71ca1c9b0cSelric free_DigestInit(&digest->init);
72ca1c9b0cSelric free_DigestInitReply(&digest->initReply);
73ca1c9b0cSelric free_DigestRequest(&digest->request);
74ca1c9b0cSelric free_DigestResponse(&digest->response);
75ca1c9b0cSelric memset(digest, 0, sizeof(*digest));
76ca1c9b0cSelric free(digest);
77ca1c9b0cSelric return;
78ca1c9b0cSelric }
79ca1c9b0cSelric
80ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_server_cb(krb5_context context,krb5_digest digest,const char * type,const char * binding)81ca1c9b0cSelric krb5_digest_set_server_cb(krb5_context context,
82ca1c9b0cSelric krb5_digest digest,
83ca1c9b0cSelric const char *type,
84ca1c9b0cSelric const char *binding)
85ca1c9b0cSelric {
86ca1c9b0cSelric if (digest->init.channel) {
87ca1c9b0cSelric krb5_set_error_message(context, EINVAL,
88ca1c9b0cSelric N_("server channel binding already set", ""));
89ca1c9b0cSelric return EINVAL;
90ca1c9b0cSelric }
91ca1c9b0cSelric digest->init.channel = calloc(1, sizeof(*digest->init.channel));
92ca1c9b0cSelric if (digest->init.channel == NULL)
93ca1c9b0cSelric goto error;
94ca1c9b0cSelric
95ca1c9b0cSelric digest->init.channel->cb_type = strdup(type);
96ca1c9b0cSelric if (digest->init.channel->cb_type == NULL)
97ca1c9b0cSelric goto error;
98ca1c9b0cSelric
99ca1c9b0cSelric digest->init.channel->cb_binding = strdup(binding);
100ca1c9b0cSelric if (digest->init.channel->cb_binding == NULL)
101ca1c9b0cSelric goto error;
102ca1c9b0cSelric return 0;
103ca1c9b0cSelric error:
104ca1c9b0cSelric if (digest->init.channel) {
105ca1c9b0cSelric free(digest->init.channel->cb_type);
106ca1c9b0cSelric free(digest->init.channel->cb_binding);
107ca1c9b0cSelric free(digest->init.channel);
108ca1c9b0cSelric digest->init.channel = NULL;
109ca1c9b0cSelric }
110b9d004c6Schristos return krb5_enomem(context);
111ca1c9b0cSelric }
112ca1c9b0cSelric
113ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_type(krb5_context context,krb5_digest digest,const char * type)114ca1c9b0cSelric krb5_digest_set_type(krb5_context context,
115ca1c9b0cSelric krb5_digest digest,
116ca1c9b0cSelric const char *type)
117ca1c9b0cSelric {
118ca1c9b0cSelric if (digest->init.type) {
119ca1c9b0cSelric krb5_set_error_message(context, EINVAL, "client type already set");
120ca1c9b0cSelric return EINVAL;
121ca1c9b0cSelric }
122ca1c9b0cSelric digest->init.type = strdup(type);
123b9d004c6Schristos if (digest->init.type == NULL)
124b9d004c6Schristos return krb5_enomem(context);
125ca1c9b0cSelric return 0;
126ca1c9b0cSelric }
127ca1c9b0cSelric
128ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_hostname(krb5_context context,krb5_digest digest,const char * hostname)129ca1c9b0cSelric krb5_digest_set_hostname(krb5_context context,
130ca1c9b0cSelric krb5_digest digest,
131ca1c9b0cSelric const char *hostname)
132ca1c9b0cSelric {
133ca1c9b0cSelric if (digest->init.hostname) {
134ca1c9b0cSelric krb5_set_error_message(context, EINVAL, "server hostname already set");
135ca1c9b0cSelric return EINVAL;
136ca1c9b0cSelric }
137ca1c9b0cSelric digest->init.hostname = malloc(sizeof(*digest->init.hostname));
138b9d004c6Schristos if (digest->init.hostname == NULL)
139b9d004c6Schristos return krb5_enomem(context);
140ca1c9b0cSelric *digest->init.hostname = strdup(hostname);
141ca1c9b0cSelric if (*digest->init.hostname == NULL) {
142ca1c9b0cSelric free(digest->init.hostname);
143ca1c9b0cSelric digest->init.hostname = NULL;
144b9d004c6Schristos return krb5_enomem(context);
145ca1c9b0cSelric }
146ca1c9b0cSelric return 0;
147ca1c9b0cSelric }
148ca1c9b0cSelric
149ca1c9b0cSelric KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL
krb5_digest_get_server_nonce(krb5_context context,krb5_digest digest)150ca1c9b0cSelric krb5_digest_get_server_nonce(krb5_context context,
151ca1c9b0cSelric krb5_digest digest)
152ca1c9b0cSelric {
153ca1c9b0cSelric return digest->initReply.nonce;
154ca1c9b0cSelric }
155ca1c9b0cSelric
156ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_server_nonce(krb5_context context,krb5_digest digest,const char * nonce)157ca1c9b0cSelric krb5_digest_set_server_nonce(krb5_context context,
158ca1c9b0cSelric krb5_digest digest,
159ca1c9b0cSelric const char *nonce)
160ca1c9b0cSelric {
161ca1c9b0cSelric if (digest->request.serverNonce) {
162ca1c9b0cSelric krb5_set_error_message(context, EINVAL, N_("nonce already set", ""));
163ca1c9b0cSelric return EINVAL;
164ca1c9b0cSelric }
165ca1c9b0cSelric digest->request.serverNonce = strdup(nonce);
166b9d004c6Schristos if (digest->request.serverNonce == NULL)
167b9d004c6Schristos return krb5_enomem(context);
168ca1c9b0cSelric return 0;
169ca1c9b0cSelric }
170ca1c9b0cSelric
171ca1c9b0cSelric KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL
krb5_digest_get_opaque(krb5_context context,krb5_digest digest)172ca1c9b0cSelric krb5_digest_get_opaque(krb5_context context,
173ca1c9b0cSelric krb5_digest digest)
174ca1c9b0cSelric {
175ca1c9b0cSelric return digest->initReply.opaque;
176ca1c9b0cSelric }
177ca1c9b0cSelric
178ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_opaque(krb5_context context,krb5_digest digest,const char * opaque)179ca1c9b0cSelric krb5_digest_set_opaque(krb5_context context,
180ca1c9b0cSelric krb5_digest digest,
181ca1c9b0cSelric const char *opaque)
182ca1c9b0cSelric {
183ca1c9b0cSelric if (digest->request.opaque) {
184ca1c9b0cSelric krb5_set_error_message(context, EINVAL, "opaque already set");
185ca1c9b0cSelric return EINVAL;
186ca1c9b0cSelric }
187ca1c9b0cSelric digest->request.opaque = strdup(opaque);
188b9d004c6Schristos if (digest->request.opaque == NULL)
189b9d004c6Schristos return krb5_enomem(context);
190ca1c9b0cSelric return 0;
191ca1c9b0cSelric }
192ca1c9b0cSelric
193ca1c9b0cSelric KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL
krb5_digest_get_identifier(krb5_context context,krb5_digest digest)194ca1c9b0cSelric krb5_digest_get_identifier(krb5_context context,
195ca1c9b0cSelric krb5_digest digest)
196ca1c9b0cSelric {
197ca1c9b0cSelric if (digest->initReply.identifier == NULL)
198ca1c9b0cSelric return NULL;
199ca1c9b0cSelric return *digest->initReply.identifier;
200ca1c9b0cSelric }
201ca1c9b0cSelric
202ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_identifier(krb5_context context,krb5_digest digest,const char * id)203ca1c9b0cSelric krb5_digest_set_identifier(krb5_context context,
204ca1c9b0cSelric krb5_digest digest,
205ca1c9b0cSelric const char *id)
206ca1c9b0cSelric {
207ca1c9b0cSelric if (digest->request.identifier) {
208ca1c9b0cSelric krb5_set_error_message(context, EINVAL, N_("identifier already set", ""));
209ca1c9b0cSelric return EINVAL;
210ca1c9b0cSelric }
211ca1c9b0cSelric digest->request.identifier = calloc(1, sizeof(*digest->request.identifier));
212b9d004c6Schristos if (digest->request.identifier == NULL)
213b9d004c6Schristos return krb5_enomem(context);
214ca1c9b0cSelric *digest->request.identifier = strdup(id);
215ca1c9b0cSelric if (*digest->request.identifier == NULL) {
216ca1c9b0cSelric free(digest->request.identifier);
217ca1c9b0cSelric digest->request.identifier = NULL;
218b9d004c6Schristos return krb5_enomem(context);
219ca1c9b0cSelric }
220ca1c9b0cSelric return 0;
221ca1c9b0cSelric }
222ca1c9b0cSelric
223ca1c9b0cSelric static krb5_error_code
digest_request(krb5_context context,krb5_realm realm,krb5_ccache ccache,krb5_key_usage usage,const DigestReqInner * ireq,DigestRepInner * irep)224ca1c9b0cSelric digest_request(krb5_context context,
225ca1c9b0cSelric krb5_realm realm,
226ca1c9b0cSelric krb5_ccache ccache,
227ca1c9b0cSelric krb5_key_usage usage,
228ca1c9b0cSelric const DigestReqInner *ireq,
229ca1c9b0cSelric DigestRepInner *irep)
230ca1c9b0cSelric {
231ca1c9b0cSelric DigestREQ req;
232ca1c9b0cSelric DigestREP rep;
233ca1c9b0cSelric krb5_error_code ret;
234ca1c9b0cSelric krb5_data data, data2;
2354f77a458Spettai size_t size = 0;
236ca1c9b0cSelric krb5_crypto crypto = NULL;
237ca1c9b0cSelric krb5_auth_context ac = NULL;
238ca1c9b0cSelric krb5_principal principal = NULL;
239ca1c9b0cSelric krb5_ccache id = NULL;
240ca1c9b0cSelric krb5_realm r = NULL;
241ca1c9b0cSelric
242ca1c9b0cSelric krb5_data_zero(&data);
243ca1c9b0cSelric krb5_data_zero(&data2);
244ca1c9b0cSelric memset(&req, 0, sizeof(req));
245ca1c9b0cSelric memset(&rep, 0, sizeof(rep));
246ca1c9b0cSelric
247ca1c9b0cSelric if (ccache == NULL) {
248ca1c9b0cSelric ret = krb5_cc_default(context, &id);
249ca1c9b0cSelric if (ret)
250ca1c9b0cSelric goto out;
251ca1c9b0cSelric } else
252ca1c9b0cSelric id = ccache;
253ca1c9b0cSelric
254ca1c9b0cSelric if (realm == NULL) {
255ca1c9b0cSelric ret = krb5_get_default_realm(context, &r);
256ca1c9b0cSelric if (ret)
257ca1c9b0cSelric goto out;
258ca1c9b0cSelric } else
259ca1c9b0cSelric r = realm;
260ca1c9b0cSelric
261ca1c9b0cSelric /*
262ca1c9b0cSelric *
263ca1c9b0cSelric */
264ca1c9b0cSelric
265ca1c9b0cSelric ret = krb5_make_principal(context, &principal,
266ca1c9b0cSelric r, KRB5_DIGEST_NAME, r, NULL);
267ca1c9b0cSelric if (ret)
268ca1c9b0cSelric goto out;
269ca1c9b0cSelric
270ca1c9b0cSelric ASN1_MALLOC_ENCODE(DigestReqInner, data.data, data.length,
271ca1c9b0cSelric ireq, &size, ret);
272ca1c9b0cSelric if (ret) {
273ca1c9b0cSelric krb5_set_error_message(context, ret,
274ca1c9b0cSelric N_("Failed to encode digest inner request", ""));
275ca1c9b0cSelric goto out;
276ca1c9b0cSelric }
277ca1c9b0cSelric if (size != data.length)
278ca1c9b0cSelric krb5_abortx(context, "ASN.1 internal encoder error");
279ca1c9b0cSelric
280ca1c9b0cSelric ret = krb5_mk_req_exact(context, &ac,
281ca1c9b0cSelric AP_OPTS_USE_SUBKEY|AP_OPTS_MUTUAL_REQUIRED,
282ca1c9b0cSelric principal, NULL, id, &req.apReq);
283ca1c9b0cSelric if (ret)
284ca1c9b0cSelric goto out;
285ca1c9b0cSelric
286ca1c9b0cSelric {
287ca1c9b0cSelric krb5_keyblock *key;
288ca1c9b0cSelric
289ca1c9b0cSelric ret = krb5_auth_con_getlocalsubkey(context, ac, &key);
290ca1c9b0cSelric if (ret)
291ca1c9b0cSelric goto out;
292ca1c9b0cSelric if (key == NULL) {
293ca1c9b0cSelric ret = EINVAL;
294ca1c9b0cSelric krb5_set_error_message(context, ret,
295ca1c9b0cSelric N_("Digest failed to get local subkey", ""));
296ca1c9b0cSelric goto out;
297ca1c9b0cSelric }
298ca1c9b0cSelric
299ca1c9b0cSelric ret = krb5_crypto_init(context, key, 0, &crypto);
300ca1c9b0cSelric krb5_free_keyblock (context, key);
301ca1c9b0cSelric if (ret)
302ca1c9b0cSelric goto out;
303ca1c9b0cSelric }
304ca1c9b0cSelric
305ca1c9b0cSelric ret = krb5_encrypt_EncryptedData(context, crypto, usage,
306ca1c9b0cSelric data.data, data.length, 0,
307ca1c9b0cSelric &req.innerReq);
308ca1c9b0cSelric if (ret)
309ca1c9b0cSelric goto out;
310ca1c9b0cSelric
311ca1c9b0cSelric krb5_data_free(&data);
312ca1c9b0cSelric
313ca1c9b0cSelric ASN1_MALLOC_ENCODE(DigestREQ, data.data, data.length,
314ca1c9b0cSelric &req, &size, ret);
315ca1c9b0cSelric if (ret) {
316ca1c9b0cSelric krb5_set_error_message(context, ret,
317ca1c9b0cSelric N_("Failed to encode DigestREQest", ""));
318ca1c9b0cSelric goto out;
319ca1c9b0cSelric }
320ca1c9b0cSelric if (size != data.length)
321ca1c9b0cSelric krb5_abortx(context, "ASN.1 internal encoder error");
322ca1c9b0cSelric
323ca1c9b0cSelric ret = krb5_sendto_kdc(context, &data, &r, &data2);
324ca1c9b0cSelric if (ret)
325ca1c9b0cSelric goto out;
326ca1c9b0cSelric
327ca1c9b0cSelric ret = decode_DigestREP(data2.data, data2.length, &rep, NULL);
328ca1c9b0cSelric if (ret) {
329ca1c9b0cSelric krb5_set_error_message(context, ret,
330ca1c9b0cSelric N_("Failed to parse digest response", ""));
331ca1c9b0cSelric goto out;
332ca1c9b0cSelric }
333ca1c9b0cSelric
334ca1c9b0cSelric {
335ca1c9b0cSelric krb5_ap_rep_enc_part *repl;
336ca1c9b0cSelric
337ca1c9b0cSelric ret = krb5_rd_rep(context, ac, &rep.apRep, &repl);
338ca1c9b0cSelric if (ret)
339ca1c9b0cSelric goto out;
340ca1c9b0cSelric
341ca1c9b0cSelric krb5_free_ap_rep_enc_part(context, repl);
342ca1c9b0cSelric }
343ca1c9b0cSelric {
344ca1c9b0cSelric krb5_keyblock *key;
345ca1c9b0cSelric
346ca1c9b0cSelric ret = krb5_auth_con_getremotesubkey(context, ac, &key);
347ca1c9b0cSelric if (ret)
348ca1c9b0cSelric goto out;
349ca1c9b0cSelric if (key == NULL) {
350ca1c9b0cSelric ret = EINVAL;
351ca1c9b0cSelric krb5_set_error_message(context, ret,
352ca1c9b0cSelric N_("Digest reply have no remote subkey", ""));
353ca1c9b0cSelric goto out;
354ca1c9b0cSelric }
355ca1c9b0cSelric
356ca1c9b0cSelric krb5_crypto_destroy(context, crypto);
357ca1c9b0cSelric ret = krb5_crypto_init(context, key, 0, &crypto);
358ca1c9b0cSelric krb5_free_keyblock (context, key);
359ca1c9b0cSelric if (ret)
360ca1c9b0cSelric goto out;
361ca1c9b0cSelric }
362ca1c9b0cSelric
363ca1c9b0cSelric krb5_data_free(&data);
364ca1c9b0cSelric ret = krb5_decrypt_EncryptedData(context, crypto, usage,
365ca1c9b0cSelric &rep.innerRep, &data);
366ca1c9b0cSelric if (ret)
367ca1c9b0cSelric goto out;
368ca1c9b0cSelric
369ca1c9b0cSelric ret = decode_DigestRepInner(data.data, data.length, irep, NULL);
370ca1c9b0cSelric if (ret) {
371ca1c9b0cSelric krb5_set_error_message(context, ret,
372ca1c9b0cSelric N_("Failed to decode digest inner reply", ""));
373ca1c9b0cSelric goto out;
374ca1c9b0cSelric }
375ca1c9b0cSelric
376ca1c9b0cSelric out:
377ca1c9b0cSelric if (ccache == NULL && id)
378ca1c9b0cSelric krb5_cc_close(context, id);
379ca1c9b0cSelric if (realm == NULL && r)
380ca1c9b0cSelric free(r);
381ca1c9b0cSelric if (crypto)
382ca1c9b0cSelric krb5_crypto_destroy(context, crypto);
383ca1c9b0cSelric if (ac)
384ca1c9b0cSelric krb5_auth_con_free(context, ac);
385ca1c9b0cSelric if (principal)
386ca1c9b0cSelric krb5_free_principal(context, principal);
387ca1c9b0cSelric
388ca1c9b0cSelric krb5_data_free(&data);
389ca1c9b0cSelric krb5_data_free(&data2);
390ca1c9b0cSelric
391ca1c9b0cSelric free_DigestREQ(&req);
392ca1c9b0cSelric free_DigestREP(&rep);
393ca1c9b0cSelric
394ca1c9b0cSelric return ret;
395ca1c9b0cSelric }
396ca1c9b0cSelric
397ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_init_request(krb5_context context,krb5_digest digest,krb5_realm realm,krb5_ccache ccache)398ca1c9b0cSelric krb5_digest_init_request(krb5_context context,
399ca1c9b0cSelric krb5_digest digest,
400ca1c9b0cSelric krb5_realm realm,
401ca1c9b0cSelric krb5_ccache ccache)
402ca1c9b0cSelric {
403ca1c9b0cSelric DigestReqInner ireq;
404ca1c9b0cSelric DigestRepInner irep;
405ca1c9b0cSelric krb5_error_code ret;
406ca1c9b0cSelric
407ca1c9b0cSelric memset(&ireq, 0, sizeof(ireq));
408ca1c9b0cSelric memset(&irep, 0, sizeof(irep));
409ca1c9b0cSelric
410ca1c9b0cSelric if (digest->init.type == NULL) {
411ca1c9b0cSelric krb5_set_error_message(context, EINVAL,
412ca1c9b0cSelric N_("Type missing from init req", ""));
413ca1c9b0cSelric return EINVAL;
414ca1c9b0cSelric }
415ca1c9b0cSelric
416ca1c9b0cSelric ireq.element = choice_DigestReqInner_init;
417ca1c9b0cSelric ireq.u.init = digest->init;
418ca1c9b0cSelric
419ca1c9b0cSelric ret = digest_request(context, realm, ccache,
420ca1c9b0cSelric KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
421ca1c9b0cSelric if (ret)
422ca1c9b0cSelric goto out;
423ca1c9b0cSelric
424ca1c9b0cSelric if (irep.element == choice_DigestRepInner_error) {
425ca1c9b0cSelric ret = irep.u.error.code;
426ca1c9b0cSelric krb5_set_error_message(context, ret, N_("Digest init error: %s", ""),
427ca1c9b0cSelric irep.u.error.reason);
428ca1c9b0cSelric goto out;
429ca1c9b0cSelric }
430ca1c9b0cSelric
431ca1c9b0cSelric if (irep.element != choice_DigestRepInner_initReply) {
432ca1c9b0cSelric ret = EINVAL;
433ca1c9b0cSelric krb5_set_error_message(context, ret,
434ca1c9b0cSelric N_("digest reply not an initReply", ""));
435ca1c9b0cSelric goto out;
436ca1c9b0cSelric }
437ca1c9b0cSelric
438ca1c9b0cSelric ret = copy_DigestInitReply(&irep.u.initReply, &digest->initReply);
439ca1c9b0cSelric if (ret) {
440ca1c9b0cSelric krb5_set_error_message(context, ret,
441ca1c9b0cSelric N_("Failed to copy initReply", ""));
442ca1c9b0cSelric goto out;
443ca1c9b0cSelric }
444ca1c9b0cSelric
445ca1c9b0cSelric out:
446ca1c9b0cSelric free_DigestRepInner(&irep);
447ca1c9b0cSelric
448ca1c9b0cSelric return ret;
449ca1c9b0cSelric }
450ca1c9b0cSelric
451ca1c9b0cSelric
452ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_client_nonce(krb5_context context,krb5_digest digest,const char * nonce)453ca1c9b0cSelric krb5_digest_set_client_nonce(krb5_context context,
454ca1c9b0cSelric krb5_digest digest,
455ca1c9b0cSelric const char *nonce)
456ca1c9b0cSelric {
457ca1c9b0cSelric if (digest->request.clientNonce) {
458ca1c9b0cSelric krb5_set_error_message(context, EINVAL,
459ca1c9b0cSelric N_("clientNonce already set", ""));
460ca1c9b0cSelric return EINVAL;
461ca1c9b0cSelric }
462ca1c9b0cSelric digest->request.clientNonce =
463ca1c9b0cSelric calloc(1, sizeof(*digest->request.clientNonce));
464b9d004c6Schristos if (digest->request.clientNonce == NULL)
465b9d004c6Schristos return krb5_enomem(context);
466ca1c9b0cSelric *digest->request.clientNonce = strdup(nonce);
467ca1c9b0cSelric if (*digest->request.clientNonce == NULL) {
468ca1c9b0cSelric free(digest->request.clientNonce);
469ca1c9b0cSelric digest->request.clientNonce = NULL;
470b9d004c6Schristos return krb5_enomem(context);
471ca1c9b0cSelric }
472ca1c9b0cSelric return 0;
473ca1c9b0cSelric }
474ca1c9b0cSelric
475ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_digest(krb5_context context,krb5_digest digest,const char * dgst)476ca1c9b0cSelric krb5_digest_set_digest(krb5_context context,
477ca1c9b0cSelric krb5_digest digest,
478ca1c9b0cSelric const char *dgst)
479ca1c9b0cSelric {
480ca1c9b0cSelric if (digest->request.digest) {
481ca1c9b0cSelric krb5_set_error_message(context, EINVAL,
482ca1c9b0cSelric N_("digest already set", ""));
483ca1c9b0cSelric return EINVAL;
484ca1c9b0cSelric }
485ca1c9b0cSelric digest->request.digest = strdup(dgst);
486b9d004c6Schristos if (digest->request.digest == NULL)
487b9d004c6Schristos return krb5_enomem(context);
488ca1c9b0cSelric return 0;
489ca1c9b0cSelric }
490ca1c9b0cSelric
491ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_username(krb5_context context,krb5_digest digest,const char * username)492ca1c9b0cSelric krb5_digest_set_username(krb5_context context,
493ca1c9b0cSelric krb5_digest digest,
494ca1c9b0cSelric const char *username)
495ca1c9b0cSelric {
496ca1c9b0cSelric if (digest->request.username) {
497ca1c9b0cSelric krb5_set_error_message(context, EINVAL, "username already set");
498ca1c9b0cSelric return EINVAL;
499ca1c9b0cSelric }
500ca1c9b0cSelric digest->request.username = strdup(username);
501b9d004c6Schristos if (digest->request.username == NULL)
502b9d004c6Schristos return krb5_enomem(context);
503ca1c9b0cSelric return 0;
504ca1c9b0cSelric }
505ca1c9b0cSelric
506ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_authid(krb5_context context,krb5_digest digest,const char * authid)507ca1c9b0cSelric krb5_digest_set_authid(krb5_context context,
508ca1c9b0cSelric krb5_digest digest,
509ca1c9b0cSelric const char *authid)
510ca1c9b0cSelric {
511ca1c9b0cSelric if (digest->request.authid) {
512ca1c9b0cSelric krb5_set_error_message(context, EINVAL, "authid already set");
513ca1c9b0cSelric return EINVAL;
514ca1c9b0cSelric }
515ca1c9b0cSelric digest->request.authid = malloc(sizeof(*digest->request.authid));
516b9d004c6Schristos if (digest->request.authid == NULL)
517b9d004c6Schristos return krb5_enomem(context);
518ca1c9b0cSelric *digest->request.authid = strdup(authid);
519ca1c9b0cSelric if (*digest->request.authid == NULL) {
520ca1c9b0cSelric free(digest->request.authid);
521ca1c9b0cSelric digest->request.authid = NULL;
522b9d004c6Schristos return krb5_enomem(context);
523ca1c9b0cSelric }
524ca1c9b0cSelric return 0;
525ca1c9b0cSelric }
526ca1c9b0cSelric
527ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_authentication_user(krb5_context context,krb5_digest digest,krb5_principal authentication_user)528ca1c9b0cSelric krb5_digest_set_authentication_user(krb5_context context,
529ca1c9b0cSelric krb5_digest digest,
530ca1c9b0cSelric krb5_principal authentication_user)
531ca1c9b0cSelric {
532ca1c9b0cSelric krb5_error_code ret;
533ca1c9b0cSelric
534ca1c9b0cSelric if (digest->request.authentication_user) {
535ca1c9b0cSelric krb5_set_error_message(context, EINVAL,
536ca1c9b0cSelric N_("authentication_user already set", ""));
537ca1c9b0cSelric return EINVAL;
538ca1c9b0cSelric }
539ca1c9b0cSelric ret = krb5_copy_principal(context,
540ca1c9b0cSelric authentication_user,
541ca1c9b0cSelric &digest->request.authentication_user);
542ca1c9b0cSelric if (ret)
543ca1c9b0cSelric return ret;
544ca1c9b0cSelric return 0;
545ca1c9b0cSelric }
546ca1c9b0cSelric
547ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_realm(krb5_context context,krb5_digest digest,const char * realm)548ca1c9b0cSelric krb5_digest_set_realm(krb5_context context,
549ca1c9b0cSelric krb5_digest digest,
550ca1c9b0cSelric const char *realm)
551ca1c9b0cSelric {
552ca1c9b0cSelric if (digest->request.realm) {
553ca1c9b0cSelric krb5_set_error_message(context, EINVAL, "realm already set");
554ca1c9b0cSelric return EINVAL;
555ca1c9b0cSelric }
556ca1c9b0cSelric digest->request.realm = malloc(sizeof(*digest->request.realm));
557b9d004c6Schristos if (digest->request.realm == NULL)
558b9d004c6Schristos return krb5_enomem(context);
559ca1c9b0cSelric *digest->request.realm = strdup(realm);
560ca1c9b0cSelric if (*digest->request.realm == NULL) {
561ca1c9b0cSelric free(digest->request.realm);
562ca1c9b0cSelric digest->request.realm = NULL;
563b9d004c6Schristos return krb5_enomem(context);
564ca1c9b0cSelric }
565ca1c9b0cSelric return 0;
566ca1c9b0cSelric }
567ca1c9b0cSelric
568ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_method(krb5_context context,krb5_digest digest,const char * method)569ca1c9b0cSelric krb5_digest_set_method(krb5_context context,
570ca1c9b0cSelric krb5_digest digest,
571ca1c9b0cSelric const char *method)
572ca1c9b0cSelric {
573ca1c9b0cSelric if (digest->request.method) {
574ca1c9b0cSelric krb5_set_error_message(context, EINVAL,
575ca1c9b0cSelric N_("method already set", ""));
576ca1c9b0cSelric return EINVAL;
577ca1c9b0cSelric }
578ca1c9b0cSelric digest->request.method = malloc(sizeof(*digest->request.method));
579b9d004c6Schristos if (digest->request.method == NULL)
580b9d004c6Schristos return krb5_enomem(context);
581ca1c9b0cSelric *digest->request.method = strdup(method);
582ca1c9b0cSelric if (*digest->request.method == NULL) {
583ca1c9b0cSelric free(digest->request.method);
584ca1c9b0cSelric digest->request.method = NULL;
585b9d004c6Schristos return krb5_enomem(context);
586ca1c9b0cSelric }
587ca1c9b0cSelric return 0;
588ca1c9b0cSelric }
589ca1c9b0cSelric
590ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_uri(krb5_context context,krb5_digest digest,const char * uri)591ca1c9b0cSelric krb5_digest_set_uri(krb5_context context,
592ca1c9b0cSelric krb5_digest digest,
593ca1c9b0cSelric const char *uri)
594ca1c9b0cSelric {
595ca1c9b0cSelric if (digest->request.uri) {
596ca1c9b0cSelric krb5_set_error_message(context, EINVAL, N_("uri already set", ""));
597ca1c9b0cSelric return EINVAL;
598ca1c9b0cSelric }
599ca1c9b0cSelric digest->request.uri = malloc(sizeof(*digest->request.uri));
600b9d004c6Schristos if (digest->request.uri == NULL)
601b9d004c6Schristos return krb5_enomem(context);
602ca1c9b0cSelric *digest->request.uri = strdup(uri);
603ca1c9b0cSelric if (*digest->request.uri == NULL) {
604ca1c9b0cSelric free(digest->request.uri);
605ca1c9b0cSelric digest->request.uri = NULL;
606b9d004c6Schristos return krb5_enomem(context);
607ca1c9b0cSelric }
608ca1c9b0cSelric return 0;
609ca1c9b0cSelric }
610ca1c9b0cSelric
611ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_nonceCount(krb5_context context,krb5_digest digest,const char * nonce_count)612ca1c9b0cSelric krb5_digest_set_nonceCount(krb5_context context,
613ca1c9b0cSelric krb5_digest digest,
614ca1c9b0cSelric const char *nonce_count)
615ca1c9b0cSelric {
616ca1c9b0cSelric if (digest->request.nonceCount) {
617ca1c9b0cSelric krb5_set_error_message(context, EINVAL,
618ca1c9b0cSelric N_("nonceCount already set", ""));
619ca1c9b0cSelric return EINVAL;
620ca1c9b0cSelric }
621ca1c9b0cSelric digest->request.nonceCount =
622ca1c9b0cSelric malloc(sizeof(*digest->request.nonceCount));
623b9d004c6Schristos if (digest->request.nonceCount == NULL)
624b9d004c6Schristos return krb5_enomem(context);
625ca1c9b0cSelric *digest->request.nonceCount = strdup(nonce_count);
626ca1c9b0cSelric if (*digest->request.nonceCount == NULL) {
627ca1c9b0cSelric free(digest->request.nonceCount);
628ca1c9b0cSelric digest->request.nonceCount = NULL;
629b9d004c6Schristos return krb5_enomem(context);
630ca1c9b0cSelric }
631ca1c9b0cSelric return 0;
632ca1c9b0cSelric }
633ca1c9b0cSelric
634ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_set_qop(krb5_context context,krb5_digest digest,const char * qop)635ca1c9b0cSelric krb5_digest_set_qop(krb5_context context,
636ca1c9b0cSelric krb5_digest digest,
637ca1c9b0cSelric const char *qop)
638ca1c9b0cSelric {
639ca1c9b0cSelric if (digest->request.qop) {
640ca1c9b0cSelric krb5_set_error_message(context, EINVAL, "qop already set");
641ca1c9b0cSelric return EINVAL;
642ca1c9b0cSelric }
643ca1c9b0cSelric digest->request.qop = malloc(sizeof(*digest->request.qop));
644b9d004c6Schristos if (digest->request.qop == NULL)
645b9d004c6Schristos return krb5_enomem(context);
646ca1c9b0cSelric *digest->request.qop = strdup(qop);
647ca1c9b0cSelric if (*digest->request.qop == NULL) {
648ca1c9b0cSelric free(digest->request.qop);
649ca1c9b0cSelric digest->request.qop = NULL;
650b9d004c6Schristos return krb5_enomem(context);
651ca1c9b0cSelric }
652ca1c9b0cSelric return 0;
653ca1c9b0cSelric }
654ca1c9b0cSelric
655ca1c9b0cSelric KRB5_LIB_FUNCTION int KRB5_LIB_CALL
krb5_digest_set_responseData(krb5_context context,krb5_digest digest,const char * response)656ca1c9b0cSelric krb5_digest_set_responseData(krb5_context context,
657ca1c9b0cSelric krb5_digest digest,
658ca1c9b0cSelric const char *response)
659ca1c9b0cSelric {
660ca1c9b0cSelric digest->request.responseData = strdup(response);
661b9d004c6Schristos if (digest->request.responseData == NULL)
662b9d004c6Schristos return krb5_enomem(context);
663ca1c9b0cSelric return 0;
664ca1c9b0cSelric }
665ca1c9b0cSelric
666ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_request(krb5_context context,krb5_digest digest,krb5_realm realm,krb5_ccache ccache)667ca1c9b0cSelric krb5_digest_request(krb5_context context,
668ca1c9b0cSelric krb5_digest digest,
669ca1c9b0cSelric krb5_realm realm,
670ca1c9b0cSelric krb5_ccache ccache)
671ca1c9b0cSelric {
672ca1c9b0cSelric DigestReqInner ireq;
673ca1c9b0cSelric DigestRepInner irep;
674ca1c9b0cSelric krb5_error_code ret;
675ca1c9b0cSelric
676ca1c9b0cSelric memset(&ireq, 0, sizeof(ireq));
677ca1c9b0cSelric memset(&irep, 0, sizeof(irep));
678ca1c9b0cSelric
679ca1c9b0cSelric ireq.element = choice_DigestReqInner_digestRequest;
680ca1c9b0cSelric ireq.u.digestRequest = digest->request;
681ca1c9b0cSelric
682ca1c9b0cSelric if (digest->request.type == NULL) {
683ca1c9b0cSelric if (digest->init.type == NULL) {
684ca1c9b0cSelric krb5_set_error_message(context, EINVAL,
685ca1c9b0cSelric N_("Type missing from req", ""));
686ca1c9b0cSelric return EINVAL;
687ca1c9b0cSelric }
688ca1c9b0cSelric ireq.u.digestRequest.type = digest->init.type;
689ca1c9b0cSelric }
690ca1c9b0cSelric
6914f77a458Spettai if (ireq.u.digestRequest.digest == NULL) {
6924f77a458Spettai static char md5[] = "md5";
6934f77a458Spettai ireq.u.digestRequest.digest = md5;
6944f77a458Spettai }
695ca1c9b0cSelric
696ca1c9b0cSelric ret = digest_request(context, realm, ccache,
697ca1c9b0cSelric KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
698ca1c9b0cSelric if (ret)
699ca1c9b0cSelric return ret;
700ca1c9b0cSelric
701ca1c9b0cSelric if (irep.element == choice_DigestRepInner_error) {
702ca1c9b0cSelric ret = irep.u.error.code;
703ca1c9b0cSelric krb5_set_error_message(context, ret,
704ca1c9b0cSelric N_("Digest response error: %s", ""),
705ca1c9b0cSelric irep.u.error.reason);
706ca1c9b0cSelric goto out;
707ca1c9b0cSelric }
708ca1c9b0cSelric
709ca1c9b0cSelric if (irep.element != choice_DigestRepInner_response) {
710ca1c9b0cSelric krb5_set_error_message(context, EINVAL,
711ca1c9b0cSelric N_("digest reply not an DigestResponse", ""));
712ca1c9b0cSelric ret = EINVAL;
713ca1c9b0cSelric goto out;
714ca1c9b0cSelric }
715ca1c9b0cSelric
716ca1c9b0cSelric ret = copy_DigestResponse(&irep.u.response, &digest->response);
717ca1c9b0cSelric if (ret) {
718ca1c9b0cSelric krb5_set_error_message(context, ret,
719ca1c9b0cSelric N_("Failed to copy initReply,", ""));
720ca1c9b0cSelric goto out;
721ca1c9b0cSelric }
722ca1c9b0cSelric
723ca1c9b0cSelric out:
724ca1c9b0cSelric free_DigestRepInner(&irep);
725ca1c9b0cSelric
726ca1c9b0cSelric return ret;
727ca1c9b0cSelric }
728ca1c9b0cSelric
729ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_digest_rep_get_status(krb5_context context,krb5_digest digest)730ca1c9b0cSelric krb5_digest_rep_get_status(krb5_context context,
731ca1c9b0cSelric krb5_digest digest)
732ca1c9b0cSelric {
733ca1c9b0cSelric return digest->response.success ? TRUE : FALSE;
734ca1c9b0cSelric }
735ca1c9b0cSelric
736ca1c9b0cSelric KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL
krb5_digest_get_rsp(krb5_context context,krb5_digest digest)737ca1c9b0cSelric krb5_digest_get_rsp(krb5_context context,
738ca1c9b0cSelric krb5_digest digest)
739ca1c9b0cSelric {
740ca1c9b0cSelric if (digest->response.rsp == NULL)
741ca1c9b0cSelric return NULL;
742ca1c9b0cSelric return *digest->response.rsp;
743ca1c9b0cSelric }
744ca1c9b0cSelric
745ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_get_tickets(krb5_context context,krb5_digest digest,Ticket ** tickets)746ca1c9b0cSelric krb5_digest_get_tickets(krb5_context context,
747ca1c9b0cSelric krb5_digest digest,
748ca1c9b0cSelric Ticket **tickets)
749ca1c9b0cSelric {
750ca1c9b0cSelric *tickets = NULL;
751ca1c9b0cSelric return 0;
752ca1c9b0cSelric }
753ca1c9b0cSelric
754ca1c9b0cSelric
755ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_get_client_binding(krb5_context context,krb5_digest digest,char ** type,char ** binding)756ca1c9b0cSelric krb5_digest_get_client_binding(krb5_context context,
757ca1c9b0cSelric krb5_digest digest,
758ca1c9b0cSelric char **type,
759ca1c9b0cSelric char **binding)
760ca1c9b0cSelric {
761ca1c9b0cSelric if (digest->response.channel) {
762ca1c9b0cSelric *type = strdup(digest->response.channel->cb_type);
763ca1c9b0cSelric *binding = strdup(digest->response.channel->cb_binding);
764ca1c9b0cSelric if (*type == NULL || *binding == NULL) {
765ca1c9b0cSelric free(*type);
766ca1c9b0cSelric free(*binding);
767b9d004c6Schristos return krb5_enomem(context);
768ca1c9b0cSelric }
769ca1c9b0cSelric } else {
770ca1c9b0cSelric *type = NULL;
771ca1c9b0cSelric *binding = NULL;
772ca1c9b0cSelric }
773ca1c9b0cSelric return 0;
774ca1c9b0cSelric }
775ca1c9b0cSelric
776ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_get_session_key(krb5_context context,krb5_digest digest,krb5_data * data)777ca1c9b0cSelric krb5_digest_get_session_key(krb5_context context,
778ca1c9b0cSelric krb5_digest digest,
779ca1c9b0cSelric krb5_data *data)
780ca1c9b0cSelric {
781ca1c9b0cSelric krb5_error_code ret;
782ca1c9b0cSelric
783ca1c9b0cSelric krb5_data_zero(data);
784ca1c9b0cSelric if (digest->response.session_key == NULL)
785ca1c9b0cSelric return 0;
786ca1c9b0cSelric ret = der_copy_octet_string(digest->response.session_key, data);
787ca1c9b0cSelric if (ret)
788ca1c9b0cSelric krb5_clear_error_message(context);
789ca1c9b0cSelric
790ca1c9b0cSelric return ret;
791ca1c9b0cSelric }
792ca1c9b0cSelric
793ca1c9b0cSelric struct krb5_ntlm_data {
794ca1c9b0cSelric NTLMInit init;
795ca1c9b0cSelric NTLMInitReply initReply;
796ca1c9b0cSelric NTLMRequest request;
797ca1c9b0cSelric NTLMResponse response;
798ca1c9b0cSelric };
799ca1c9b0cSelric
800ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_alloc(krb5_context context,krb5_ntlm * ntlm)801ca1c9b0cSelric krb5_ntlm_alloc(krb5_context context,
802ca1c9b0cSelric krb5_ntlm *ntlm)
803ca1c9b0cSelric {
804ca1c9b0cSelric *ntlm = calloc(1, sizeof(**ntlm));
805b9d004c6Schristos if (*ntlm == NULL)
806b9d004c6Schristos return krb5_enomem(context);
807ca1c9b0cSelric return 0;
808ca1c9b0cSelric }
809ca1c9b0cSelric
810ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_free(krb5_context context,krb5_ntlm ntlm)811ca1c9b0cSelric krb5_ntlm_free(krb5_context context, krb5_ntlm ntlm)
812ca1c9b0cSelric {
813ca1c9b0cSelric free_NTLMInit(&ntlm->init);
814ca1c9b0cSelric free_NTLMInitReply(&ntlm->initReply);
815ca1c9b0cSelric free_NTLMRequest(&ntlm->request);
816ca1c9b0cSelric free_NTLMResponse(&ntlm->response);
817ca1c9b0cSelric memset(ntlm, 0, sizeof(*ntlm));
818ca1c9b0cSelric free(ntlm);
819ca1c9b0cSelric return 0;
820ca1c9b0cSelric }
821ca1c9b0cSelric
822ca1c9b0cSelric
823ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_init_request(krb5_context context,krb5_ntlm ntlm,krb5_realm realm,krb5_ccache ccache,uint32_t flags,const char * hostname,const char * domainname)824ca1c9b0cSelric krb5_ntlm_init_request(krb5_context context,
825ca1c9b0cSelric krb5_ntlm ntlm,
826ca1c9b0cSelric krb5_realm realm,
827ca1c9b0cSelric krb5_ccache ccache,
828ca1c9b0cSelric uint32_t flags,
829ca1c9b0cSelric const char *hostname,
830ca1c9b0cSelric const char *domainname)
831ca1c9b0cSelric {
832ca1c9b0cSelric DigestReqInner ireq;
833ca1c9b0cSelric DigestRepInner irep;
834ca1c9b0cSelric krb5_error_code ret;
835ca1c9b0cSelric
836ca1c9b0cSelric memset(&ireq, 0, sizeof(ireq));
837ca1c9b0cSelric memset(&irep, 0, sizeof(irep));
838ca1c9b0cSelric
839ca1c9b0cSelric ntlm->init.flags = flags;
840ca1c9b0cSelric if (hostname) {
841ca1c9b0cSelric ALLOC(ntlm->init.hostname, 1);
842ca1c9b0cSelric *ntlm->init.hostname = strdup(hostname);
843ca1c9b0cSelric }
844ca1c9b0cSelric if (domainname) {
845ca1c9b0cSelric ALLOC(ntlm->init.domain, 1);
846ca1c9b0cSelric *ntlm->init.domain = strdup(domainname);
847ca1c9b0cSelric }
848ca1c9b0cSelric
849ca1c9b0cSelric ireq.element = choice_DigestReqInner_ntlmInit;
850ca1c9b0cSelric ireq.u.ntlmInit = ntlm->init;
851ca1c9b0cSelric
852ca1c9b0cSelric ret = digest_request(context, realm, ccache,
853ca1c9b0cSelric KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
854ca1c9b0cSelric if (ret)
855ca1c9b0cSelric goto out;
856ca1c9b0cSelric
857ca1c9b0cSelric if (irep.element == choice_DigestRepInner_error) {
858ca1c9b0cSelric ret = irep.u.error.code;
859ca1c9b0cSelric krb5_set_error_message(context, ret, N_("Digest init error: %s", ""),
860ca1c9b0cSelric irep.u.error.reason);
861ca1c9b0cSelric goto out;
862ca1c9b0cSelric }
863ca1c9b0cSelric
864ca1c9b0cSelric if (irep.element != choice_DigestRepInner_ntlmInitReply) {
865ca1c9b0cSelric ret = EINVAL;
866ca1c9b0cSelric krb5_set_error_message(context, ret,
867ca1c9b0cSelric N_("ntlm reply not an initReply", ""));
868ca1c9b0cSelric goto out;
869ca1c9b0cSelric }
870ca1c9b0cSelric
871ca1c9b0cSelric ret = copy_NTLMInitReply(&irep.u.ntlmInitReply, &ntlm->initReply);
872ca1c9b0cSelric if (ret) {
873ca1c9b0cSelric krb5_set_error_message(context, ret,
874ca1c9b0cSelric N_("Failed to copy initReply", ""));
875ca1c9b0cSelric goto out;
876ca1c9b0cSelric }
877ca1c9b0cSelric
878ca1c9b0cSelric out:
879ca1c9b0cSelric free_DigestRepInner(&irep);
880ca1c9b0cSelric
881ca1c9b0cSelric return ret;
882ca1c9b0cSelric }
883ca1c9b0cSelric
884ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_init_get_flags(krb5_context context,krb5_ntlm ntlm,uint32_t * flags)885ca1c9b0cSelric krb5_ntlm_init_get_flags(krb5_context context,
886ca1c9b0cSelric krb5_ntlm ntlm,
887ca1c9b0cSelric uint32_t *flags)
888ca1c9b0cSelric {
889ca1c9b0cSelric *flags = ntlm->initReply.flags;
890ca1c9b0cSelric return 0;
891ca1c9b0cSelric }
892ca1c9b0cSelric
893ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_init_get_challenge(krb5_context context,krb5_ntlm ntlm,krb5_data * challenge)894b9d004c6Schristos krb5_ntlm_init_get_challenge(krb5_context context,
895ca1c9b0cSelric krb5_ntlm ntlm,
896b9d004c6Schristos krb5_data *challenge)
897ca1c9b0cSelric {
898ca1c9b0cSelric krb5_error_code ret;
899ca1c9b0cSelric
900b9d004c6Schristos ret = der_copy_octet_string(&ntlm->initReply.challenge, challenge);
901ca1c9b0cSelric if (ret)
902ca1c9b0cSelric krb5_clear_error_message(context);
903ca1c9b0cSelric
904ca1c9b0cSelric return ret;
905ca1c9b0cSelric }
906ca1c9b0cSelric
907ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_init_get_opaque(krb5_context context,krb5_ntlm ntlm,krb5_data * opaque)908ca1c9b0cSelric krb5_ntlm_init_get_opaque(krb5_context context,
909ca1c9b0cSelric krb5_ntlm ntlm,
910ca1c9b0cSelric krb5_data *opaque)
911ca1c9b0cSelric {
912ca1c9b0cSelric krb5_error_code ret;
913ca1c9b0cSelric
914ca1c9b0cSelric ret = der_copy_octet_string(&ntlm->initReply.opaque, opaque);
915ca1c9b0cSelric if (ret)
916ca1c9b0cSelric krb5_clear_error_message(context);
917ca1c9b0cSelric
918ca1c9b0cSelric return ret;
919ca1c9b0cSelric }
920ca1c9b0cSelric
921ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_init_get_targetname(krb5_context context,krb5_ntlm ntlm,char ** name)922ca1c9b0cSelric krb5_ntlm_init_get_targetname(krb5_context context,
923ca1c9b0cSelric krb5_ntlm ntlm,
924ca1c9b0cSelric char **name)
925ca1c9b0cSelric {
926ca1c9b0cSelric *name = strdup(ntlm->initReply.targetname);
927b9d004c6Schristos if (*name == NULL)
928b9d004c6Schristos return krb5_enomem(context);
929ca1c9b0cSelric return 0;
930ca1c9b0cSelric }
931ca1c9b0cSelric
932ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_init_get_targetinfo(krb5_context context,krb5_ntlm ntlm,krb5_data * data)933ca1c9b0cSelric krb5_ntlm_init_get_targetinfo(krb5_context context,
934ca1c9b0cSelric krb5_ntlm ntlm,
935ca1c9b0cSelric krb5_data *data)
936ca1c9b0cSelric {
937ca1c9b0cSelric krb5_error_code ret;
938ca1c9b0cSelric
939ca1c9b0cSelric if (ntlm->initReply.targetinfo == NULL) {
940ca1c9b0cSelric krb5_data_zero(data);
941ca1c9b0cSelric return 0;
942ca1c9b0cSelric }
943ca1c9b0cSelric
944ca1c9b0cSelric ret = krb5_data_copy(data,
945ca1c9b0cSelric ntlm->initReply.targetinfo->data,
946ca1c9b0cSelric ntlm->initReply.targetinfo->length);
947ca1c9b0cSelric if (ret) {
948ca1c9b0cSelric krb5_clear_error_message(context);
949ca1c9b0cSelric return ret;
950ca1c9b0cSelric }
951ca1c9b0cSelric return 0;
952ca1c9b0cSelric }
953ca1c9b0cSelric
954ca1c9b0cSelric
955ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_request(krb5_context context,krb5_ntlm ntlm,krb5_realm realm,krb5_ccache ccache)956ca1c9b0cSelric krb5_ntlm_request(krb5_context context,
957ca1c9b0cSelric krb5_ntlm ntlm,
958ca1c9b0cSelric krb5_realm realm,
959ca1c9b0cSelric krb5_ccache ccache)
960ca1c9b0cSelric {
961ca1c9b0cSelric DigestReqInner ireq;
962ca1c9b0cSelric DigestRepInner irep;
963ca1c9b0cSelric krb5_error_code ret;
964ca1c9b0cSelric
965ca1c9b0cSelric memset(&ireq, 0, sizeof(ireq));
966ca1c9b0cSelric memset(&irep, 0, sizeof(irep));
967ca1c9b0cSelric
968ca1c9b0cSelric ireq.element = choice_DigestReqInner_ntlmRequest;
969ca1c9b0cSelric ireq.u.ntlmRequest = ntlm->request;
970ca1c9b0cSelric
971ca1c9b0cSelric ret = digest_request(context, realm, ccache,
972ca1c9b0cSelric KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
973ca1c9b0cSelric if (ret)
974ca1c9b0cSelric return ret;
975ca1c9b0cSelric
976ca1c9b0cSelric if (irep.element == choice_DigestRepInner_error) {
977ca1c9b0cSelric ret = irep.u.error.code;
978ca1c9b0cSelric krb5_set_error_message(context, ret,
979ca1c9b0cSelric N_("NTLM response error: %s", ""),
980ca1c9b0cSelric irep.u.error.reason);
981ca1c9b0cSelric goto out;
982ca1c9b0cSelric }
983ca1c9b0cSelric
984ca1c9b0cSelric if (irep.element != choice_DigestRepInner_ntlmResponse) {
985ca1c9b0cSelric ret = EINVAL;
986ca1c9b0cSelric krb5_set_error_message(context, ret,
987ca1c9b0cSelric N_("NTLM reply not an NTLMResponse", ""));
988ca1c9b0cSelric goto out;
989ca1c9b0cSelric }
990ca1c9b0cSelric
991ca1c9b0cSelric ret = copy_NTLMResponse(&irep.u.ntlmResponse, &ntlm->response);
992ca1c9b0cSelric if (ret) {
993ca1c9b0cSelric krb5_set_error_message(context, ret,
994ca1c9b0cSelric N_("Failed to copy NTLMResponse", ""));
995ca1c9b0cSelric goto out;
996ca1c9b0cSelric }
997ca1c9b0cSelric
998ca1c9b0cSelric out:
999ca1c9b0cSelric free_DigestRepInner(&irep);
1000ca1c9b0cSelric
1001ca1c9b0cSelric return ret;
1002ca1c9b0cSelric }
1003ca1c9b0cSelric
1004ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_req_set_flags(krb5_context context,krb5_ntlm ntlm,uint32_t flags)1005ca1c9b0cSelric krb5_ntlm_req_set_flags(krb5_context context,
1006ca1c9b0cSelric krb5_ntlm ntlm,
1007ca1c9b0cSelric uint32_t flags)
1008ca1c9b0cSelric {
1009ca1c9b0cSelric ntlm->request.flags = flags;
1010ca1c9b0cSelric return 0;
1011ca1c9b0cSelric }
1012ca1c9b0cSelric
1013ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_req_set_username(krb5_context context,krb5_ntlm ntlm,const char * username)1014ca1c9b0cSelric krb5_ntlm_req_set_username(krb5_context context,
1015ca1c9b0cSelric krb5_ntlm ntlm,
1016ca1c9b0cSelric const char *username)
1017ca1c9b0cSelric {
1018ca1c9b0cSelric ntlm->request.username = strdup(username);
1019b9d004c6Schristos if (ntlm->request.username == NULL)
1020b9d004c6Schristos return krb5_enomem(context);
1021ca1c9b0cSelric return 0;
1022ca1c9b0cSelric }
1023ca1c9b0cSelric
1024ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_req_set_targetname(krb5_context context,krb5_ntlm ntlm,const char * targetname)1025ca1c9b0cSelric krb5_ntlm_req_set_targetname(krb5_context context,
1026ca1c9b0cSelric krb5_ntlm ntlm,
1027ca1c9b0cSelric const char *targetname)
1028ca1c9b0cSelric {
1029ca1c9b0cSelric ntlm->request.targetname = strdup(targetname);
1030b9d004c6Schristos if (ntlm->request.targetname == NULL)
1031b9d004c6Schristos return krb5_enomem(context);
1032ca1c9b0cSelric return 0;
1033ca1c9b0cSelric }
1034ca1c9b0cSelric
1035ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_req_set_lm(krb5_context context,krb5_ntlm ntlm,void * hash,size_t len)1036ca1c9b0cSelric krb5_ntlm_req_set_lm(krb5_context context,
1037ca1c9b0cSelric krb5_ntlm ntlm,
1038ca1c9b0cSelric void *hash, size_t len)
1039ca1c9b0cSelric {
1040ca1c9b0cSelric ntlm->request.lm.data = malloc(len);
1041b9d004c6Schristos if (ntlm->request.lm.data == NULL && len != 0)
1042b9d004c6Schristos return krb5_enomem(context);
1043ca1c9b0cSelric ntlm->request.lm.length = len;
1044ca1c9b0cSelric memcpy(ntlm->request.lm.data, hash, len);
1045ca1c9b0cSelric return 0;
1046ca1c9b0cSelric }
1047ca1c9b0cSelric
1048ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_req_set_ntlm(krb5_context context,krb5_ntlm ntlm,void * hash,size_t len)1049ca1c9b0cSelric krb5_ntlm_req_set_ntlm(krb5_context context,
1050ca1c9b0cSelric krb5_ntlm ntlm,
1051ca1c9b0cSelric void *hash, size_t len)
1052ca1c9b0cSelric {
1053ca1c9b0cSelric ntlm->request.ntlm.data = malloc(len);
1054b9d004c6Schristos if (ntlm->request.ntlm.data == NULL && len != 0)
1055b9d004c6Schristos return krb5_enomem(context);
1056ca1c9b0cSelric ntlm->request.ntlm.length = len;
1057ca1c9b0cSelric memcpy(ntlm->request.ntlm.data, hash, len);
1058ca1c9b0cSelric return 0;
1059ca1c9b0cSelric }
1060ca1c9b0cSelric
1061ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_req_set_opaque(krb5_context context,krb5_ntlm ntlm,krb5_data * opaque)1062ca1c9b0cSelric krb5_ntlm_req_set_opaque(krb5_context context,
1063ca1c9b0cSelric krb5_ntlm ntlm,
1064ca1c9b0cSelric krb5_data *opaque)
1065ca1c9b0cSelric {
1066ca1c9b0cSelric ntlm->request.opaque.data = malloc(opaque->length);
1067b9d004c6Schristos if (ntlm->request.opaque.data == NULL && opaque->length != 0)
1068b9d004c6Schristos return krb5_enomem(context);
1069ca1c9b0cSelric ntlm->request.opaque.length = opaque->length;
1070ca1c9b0cSelric memcpy(ntlm->request.opaque.data, opaque->data, opaque->length);
1071ca1c9b0cSelric return 0;
1072ca1c9b0cSelric }
1073ca1c9b0cSelric
1074ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_req_set_session(krb5_context context,krb5_ntlm ntlm,void * sessionkey,size_t length)1075ca1c9b0cSelric krb5_ntlm_req_set_session(krb5_context context,
1076ca1c9b0cSelric krb5_ntlm ntlm,
1077ca1c9b0cSelric void *sessionkey, size_t length)
1078ca1c9b0cSelric {
1079ca1c9b0cSelric ntlm->request.sessionkey = calloc(1, sizeof(*ntlm->request.sessionkey));
1080b9d004c6Schristos if (ntlm->request.sessionkey == NULL)
1081b9d004c6Schristos return krb5_enomem(context);
1082ca1c9b0cSelric ntlm->request.sessionkey->data = malloc(length);
1083b9d004c6Schristos if (ntlm->request.sessionkey->data == NULL && length != 0)
1084b9d004c6Schristos return krb5_enomem(context);
1085ca1c9b0cSelric memcpy(ntlm->request.sessionkey->data, sessionkey, length);
1086ca1c9b0cSelric ntlm->request.sessionkey->length = length;
1087ca1c9b0cSelric return 0;
1088ca1c9b0cSelric }
1089ca1c9b0cSelric
1090ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_ntlm_rep_get_status(krb5_context context,krb5_ntlm ntlm)1091ca1c9b0cSelric krb5_ntlm_rep_get_status(krb5_context context,
1092ca1c9b0cSelric krb5_ntlm ntlm)
1093ca1c9b0cSelric {
1094ca1c9b0cSelric return ntlm->response.success ? TRUE : FALSE;
1095ca1c9b0cSelric }
1096ca1c9b0cSelric
1097ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_ntlm_rep_get_sessionkey(krb5_context context,krb5_ntlm ntlm,krb5_data * data)1098ca1c9b0cSelric krb5_ntlm_rep_get_sessionkey(krb5_context context,
1099ca1c9b0cSelric krb5_ntlm ntlm,
1100ca1c9b0cSelric krb5_data *data)
1101ca1c9b0cSelric {
1102ca1c9b0cSelric if (ntlm->response.sessionkey == NULL) {
1103ca1c9b0cSelric krb5_set_error_message(context, EINVAL,
1104ca1c9b0cSelric N_("no ntlm session key", ""));
1105ca1c9b0cSelric return EINVAL;
1106ca1c9b0cSelric }
1107ca1c9b0cSelric krb5_clear_error_message(context);
1108ca1c9b0cSelric return krb5_data_copy(data,
1109ca1c9b0cSelric ntlm->response.sessionkey->data,
1110ca1c9b0cSelric ntlm->response.sessionkey->length);
1111ca1c9b0cSelric }
1112ca1c9b0cSelric
1113ca1c9b0cSelric /**
1114ca1c9b0cSelric * Get the supported/allowed mechanism for this principal.
1115ca1c9b0cSelric *
1116ca1c9b0cSelric * @param context A Keberos context.
1117ca1c9b0cSelric * @param realm The realm of the KDC.
1118ca1c9b0cSelric * @param ccache The credential cache to use when talking to the KDC.
1119ca1c9b0cSelric * @param flags The supported mechanism.
1120ca1c9b0cSelric *
1121ca1c9b0cSelric * @return Return an error code or 0.
1122ca1c9b0cSelric *
1123ca1c9b0cSelric * @ingroup krb5_digest
1124ca1c9b0cSelric */
1125ca1c9b0cSelric
1126ca1c9b0cSelric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_digest_probe(krb5_context context,krb5_realm realm,krb5_ccache ccache,unsigned * flags)1127ca1c9b0cSelric krb5_digest_probe(krb5_context context,
1128ca1c9b0cSelric krb5_realm realm,
1129ca1c9b0cSelric krb5_ccache ccache,
1130ca1c9b0cSelric unsigned *flags)
1131ca1c9b0cSelric {
1132ca1c9b0cSelric DigestReqInner ireq;
1133ca1c9b0cSelric DigestRepInner irep;
1134ca1c9b0cSelric krb5_error_code ret;
1135ca1c9b0cSelric
1136ca1c9b0cSelric memset(&ireq, 0, sizeof(ireq));
1137ca1c9b0cSelric memset(&irep, 0, sizeof(irep));
1138ca1c9b0cSelric
1139ca1c9b0cSelric ireq.element = choice_DigestReqInner_supportedMechs;
1140ca1c9b0cSelric
1141ca1c9b0cSelric ret = digest_request(context, realm, ccache,
1142ca1c9b0cSelric KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep);
1143ca1c9b0cSelric if (ret)
1144ca1c9b0cSelric goto out;
1145ca1c9b0cSelric
1146ca1c9b0cSelric if (irep.element == choice_DigestRepInner_error) {
1147ca1c9b0cSelric ret = irep.u.error.code;
1148ca1c9b0cSelric krb5_set_error_message(context, ret, "Digest probe error: %s",
1149ca1c9b0cSelric irep.u.error.reason);
1150ca1c9b0cSelric goto out;
1151ca1c9b0cSelric }
1152ca1c9b0cSelric
1153ca1c9b0cSelric if (irep.element != choice_DigestRepInner_supportedMechs) {
1154ca1c9b0cSelric ret = EINVAL;
1155ca1c9b0cSelric krb5_set_error_message(context, ret, "Digest reply not an probe");
1156ca1c9b0cSelric goto out;
1157ca1c9b0cSelric }
1158ca1c9b0cSelric
1159ca1c9b0cSelric *flags = DigestTypes2int(irep.u.supportedMechs);
1160ca1c9b0cSelric
1161ca1c9b0cSelric out:
1162ca1c9b0cSelric free_DigestRepInner(&irep);
1163ca1c9b0cSelric
1164ca1c9b0cSelric return ret;
1165ca1c9b0cSelric }
1166ca1c9b0cSelric
1167ca1c9b0cSelric #endif /* HEIMDAL_SMALLER */
1168