1/*
2 * Copyright (c) 2008-2010 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Portions Copyright (c) 2008-2010 Apple Inc. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "heim.h"
37#include <string.h>
38#include <errno.h>
39
40void KRB5_CALLCONV
41krb5_get_init_creds_opt_init(mit_krb5_get_init_creds_opt *opt)
42{
43    LOG_ENTRY();
44    memset(opt, 0, sizeof(*opt));
45}
46
47mit_krb5_error_code KRB5_CALLCONV
48krb5_get_init_creds_opt_set_process_last_req(mit_krb5_context context,
49					     mit_krb5_get_init_creds_opt *opt,
50					     mit_krb5_gic_process_last_req req,
51					     void *ctx)
52{
53    LOG_ENTRY();
54    /* XXX need to implement this, its will be require for Lion
55       some time later */
56    return 0;
57}
58
59mit_krb5_error_code KRB5_CALLCONV
60krb5_get_init_creds_opt_alloc(mit_krb5_context context,
61			      mit_krb5_get_init_creds_opt **opt)
62{
63    mit_krb5_get_init_creds_opt *c;
64    LOG_ENTRY();
65    c = calloc(1, sizeof(*c));
66    if (c == NULL)
67	return ENOMEM;
68    *opt = c;
69    return 0;
70}
71
72void KRB5_CALLCONV
73krb5_get_init_creds_opt_free(mit_krb5_context context,
74			     mit_krb5_get_init_creds_opt *opt)
75{
76    LOG_ENTRY();
77    free(opt);
78}
79
80
81void KRB5_CALLCONV
82krb5_get_init_creds_opt_set_tkt_life(mit_krb5_get_init_creds_opt *opt,
83				     mit_krb5_deltat tkt_life)
84{
85    LOG_ENTRY();
86    opt->flags |= MIT_KRB5_GET_INIT_CREDS_OPT_TKT_LIFE;
87    opt->tkt_life = tkt_life;
88}
89
90void KRB5_CALLCONV
91krb5_get_init_creds_opt_set_renew_life(mit_krb5_get_init_creds_opt *opt,
92				       mit_krb5_deltat renew_life)
93{
94    LOG_ENTRY();
95    opt->flags |= MIT_KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE;
96    opt->renew_life = renew_life;
97}
98
99void KRB5_CALLCONV
100krb5_get_init_creds_opt_set_forwardable(mit_krb5_get_init_creds_opt *opt,
101					int forwardable)
102{
103    LOG_ENTRY();
104    opt->flags |= MIT_KRB5_GET_INIT_CREDS_OPT_FORWARDABLE;
105    opt->forwardable = forwardable;
106}
107
108void KRB5_CALLCONV
109krb5_get_init_creds_opt_set_proxiable(mit_krb5_get_init_creds_opt *opt,
110				      int proxiable)
111{
112    LOG_ENTRY();
113    opt->flags |= MIT_KRB5_GET_INIT_CREDS_OPT_PROXIABLE;
114    opt->proxiable = proxiable;
115}
116
117void KRB5_CALLCONV
118krb5_get_init_creds_opt_set_canonicalize(mit_krb5_get_init_creds_opt *opt,
119					 int canonicalize)
120{
121    LOG_ENTRY();
122    opt->flags |= MIT_KRB5_GET_INIT_CREDS_OPT_CANONICALIZE;
123}
124
125void KRB5_CALLCONV
126krb5_get_init_creds_opt_set_etype_list(mit_krb5_get_init_creds_opt *opt,
127				       mit_krb5_enctype *etype_list,
128				       int etype_list_length)
129{
130    LOG_ENTRY();
131    opt->flags |= KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST;
132    opt->etype_list = etype_list;
133    opt->etype_list_length = etype_list_length;
134}
135
136void KRB5_CALLCONV
137krb5_get_init_creds_opt_set_address_list(mit_krb5_get_init_creds_opt *opt,
138					 mit_krb5_address **addresses)
139{
140    LOG_UNIMPLEMENTED();
141}
142
143void KRB5_CALLCONV
144krb5_get_init_creds_opt_set_preauth_list(mit_krb5_get_init_creds_opt *opt,
145					 mit_krb5_preauthtype *preauth_list,
146					 int preauth_list_length)
147{
148    LOG_ENTRY();
149}
150
151static krb5_get_init_creds_opt *
152mshim_gic_opt(krb5_context context, mit_krb5_get_init_creds_opt *mopt)
153{
154    krb5_get_init_creds_opt *opt = NULL;
155    if (mopt) {
156	heim_krb5_get_init_creds_opt_alloc(context, &opt);
157	if (mopt->flags & MIT_KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
158	    heim_krb5_get_init_creds_opt_set_forwardable(opt, mopt->forwardable);
159	if (mopt->flags & MIT_KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
160	    heim_krb5_get_init_creds_opt_set_proxiable(opt, mopt->proxiable);
161	if (mopt->flags & MIT_KRB5_GET_INIT_CREDS_OPT_CANONICALIZE)
162	    heim_krb5_get_init_creds_opt_set_canonicalize(HC(context), opt, TRUE);
163	if (mopt->flags & MIT_KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
164	    heim_krb5_get_init_creds_opt_set_tkt_life(opt, mopt->tkt_life);
165	if (mopt->flags & MIT_KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)
166	    heim_krb5_get_init_creds_opt_set_renew_life(opt, mopt->renew_life);
167	/* XXX */
168    }
169    return opt;
170}
171
172mit_krb5_error_code KRB5_CALLCONV
173krb5_get_init_creds_password(mit_krb5_context context,
174			     mit_krb5_creds *creds,
175			     mit_krb5_principal client,
176			     char *password,
177			     mit_krb5_prompter_fct prompter,
178			     void *data,
179			     mit_krb5_deltat start_time,
180			     char *in_tkt_service,
181			     mit_krb5_get_init_creds_opt *mopt)
182{
183    struct comb_principal *p = (struct comb_principal *)client;
184    krb5_get_init_creds_opt *opt = NULL;
185    krb5_error_code ret;
186    krb5_creds hcreds;
187    krb5_prompter_fct pfct = NULL;
188
189    LOG_ENTRY();
190
191    opt = mshim_gic_opt(HC(context), mopt);
192
193    memset(creds, 0, sizeof(*creds));
194    memset(&hcreds, 0, sizeof(hcreds));
195
196    if (prompter == krb5_prompter_posix)
197	pfct = heim_krb5_prompter_posix;
198    else if (prompter == NULL)
199	pfct = NULL;
200    else {
201	if (opt)
202	    heim_krb5_get_init_creds_opt_free(HC(context), opt);
203	return EINVAL;
204    }
205
206    ret = heim_krb5_get_init_creds_password(HC(context), &hcreds, p->heim, password,
207					    pfct, NULL, start_time, in_tkt_service, opt);
208    if (opt)
209	heim_krb5_get_init_creds_opt_free(HC(context), opt);
210    if (ret)
211	return ret;
212
213    mshim_hcred2mcred(HC(context), &hcreds, creds);
214
215    heim_krb5_free_cred_contents(HC(context), &hcreds);
216
217    return ret;
218}
219
220mit_krb5_error_code KRB5_CALLCONV
221krb5_get_init_creds_keytab(mit_krb5_context context,
222			   mit_krb5_creds *creds,
223			   mit_krb5_principal client,
224			   mit_krb5_keytab arg_keytab,
225			   mit_krb5_deltat start_time,
226			   char *in_tkt_service,
227			   mit_krb5_get_init_creds_opt *mopt)
228{
229    struct comb_principal *p = (struct comb_principal *)client;
230    krb5_get_init_creds_opt *opt = NULL;
231    krb5_error_code ret;
232    krb5_creds hcreds;
233
234    LOG_ENTRY();
235
236    opt = mshim_gic_opt(HC(context), mopt);
237
238    memset(creds, 0, sizeof(*creds));
239    memset(&hcreds, 0, sizeof(hcreds));
240
241    ret = heim_krb5_get_init_creds_keytab(HC(context), &hcreds, p->heim,
242					  (krb5_keytab)arg_keytab,
243					  start_time, in_tkt_service, opt);
244    if (opt)
245	heim_krb5_get_init_creds_opt_free(HC(context), opt);
246    if (ret)
247	return ret;
248
249    mshim_hcred2mcred(HC(context), &hcreds, creds);
250
251    heim_krb5_free_cred_contents(HC(context), &hcreds);
252
253    return ret;
254}
255
256mit_krb5_error_code KRB5_CALLCONV
257krb5_get_in_tkt_with_password(mit_krb5_context context,
258			      mit_krb5_flags flags,
259			      mit_krb5_address * const *addr,
260			      mit_krb5_enctype *enctype,
261			      mit_krb5_preauthtype *preauth,
262			      const char *password,
263			      mit_krb5_ccache cache,
264			      mit_krb5_creds *cred,
265			      mit_krb5_kdc_rep **rep)
266{
267    struct comb_principal *p;
268    krb5_error_code ret;
269    krb5_creds hcreds;
270
271    LOG_ENTRY();
272
273    if (rep)
274	*rep = NULL;
275
276    if (cred->client)
277	p = (struct comb_principal *)cred->client;
278    else
279	return KRB5_PRINC_NOMATCH;
280
281    memset(&hcreds, 0, sizeof(hcreds));
282
283    ret = heim_krb5_get_init_creds_password(HC(context), &hcreds, p->heim, password,
284					    NULL, NULL, 0, NULL, NULL);
285    if (ret)
286	return ret;
287
288    if (cache)
289	heim_krb5_cc_store_cred(HC(context), (krb5_ccache)cache, &hcreds);
290
291    heim_krb5_free_cred_contents(HC(context), &hcreds);
292
293    return 0;
294}
295
296void KRB5_CALLCONV
297krb5_verify_init_creds_opt_init(mit_krb5_verify_init_creds_opt *options)
298{
299    memset(options, 0, sizeof(*options));
300}
301
302void KRB5_CALLCONV
303krb5_verify_init_creds_opt_set_ap_req_nofail(mit_krb5_verify_init_creds_opt *options,
304					     int ap_req_nofail)
305{
306    if (ap_req_nofail) {
307	options->flags |= MIT_KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL;
308    } else {
309	options->flags &= ~MIT_KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL;
310    }
311    options->ap_req_nofail = ap_req_nofail;
312}
313
314mit_krb5_error_code KRB5_CALLCONV
315krb5_verify_init_creds(mit_krb5_context context,
316		       mit_krb5_creds *creds,
317		       mit_krb5_principal ap_req_server,
318		       mit_krb5_keytab ap_req_keytab,
319		       mit_krb5_ccache *ccache,
320		       mit_krb5_verify_init_creds_opt *options)
321{
322    struct comb_principal *p = (struct comb_principal *)ap_req_server;
323    krb5_error_code ret;
324    krb5_creds hcreds;
325    krb5_verify_init_creds_opt hopts;
326
327    memset(&hcreds, 0, sizeof(hcreds));
328    heim_krb5_verify_init_creds_opt_init(&hopts);
329
330    if (options->ap_req_nofail)
331	heim_krb5_verify_init_creds_opt_set_ap_req_nofail(&hopts, options->ap_req_nofail);
332
333    mshim_mcred2hcred(HC(context), creds, &hcreds);
334
335    ret = heim_krb5_verify_init_creds(HC(context),
336				      &hcreds, p->heim,
337				      (krb5_keytab)ap_req_keytab,
338				      (krb5_ccache *)ccache,
339				      &hopts);
340    heim_krb5_free_cred_contents(HC(context), &hcreds);
341
342    return ret;
343}
344
345
346