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 "mit-krb5.h"
38#include <string.h>
39#include <errno.h>
40
41static krb5_flags
42mshim_mit_ap_rep_flags(mit_krb5_flags ap_req_options)
43{
44    krb5_flags flags = 0;
45
46    if (ap_req_options & MIT_KRB5_RECVAUTH_SKIP_VERSION)
47	flags |= KRB5_RECVAUTH_IGNORE_VERSION;
48
49    return flags;
50}
51
52
53static void
54mshim_hticket2mticket(krb5_context context, krb5_ticket *h, mit_krb5_ticket *m)
55{
56    m->server = mshim_hprinc2mprinc(context, h->server);
57    m->enc_part2 = calloc(1, sizeof(*m->enc_part2));
58
59    m->enc_part2->flags = 0;
60    if (h->ticket.flags.forwardable)
61	m->enc_part2->flags |= MIT_TKT_FLG_FORWARDABLE;
62    if (h->ticket.flags.forwarded)
63	m->enc_part2->flags |= MIT_TKT_FLG_FORWARDED;
64    if (h->ticket.flags.proxiable)
65	m->enc_part2->flags |= MIT_TKT_FLG_PROXIABLE;
66    if (h->ticket.flags.proxy)
67	m->enc_part2->flags |= MIT_TKT_FLG_PROXY;
68    if (h->ticket.flags.may_postdate)
69	m->enc_part2->flags |= MIT_TKT_FLG_MAY_POSTDATE;
70    if (h->ticket.flags.postdated)
71	m->enc_part2->flags |= MIT_TKT_FLG_POSTDATED;
72    if (h->ticket.flags.invalid)
73	m->enc_part2->flags |= MIT_TKT_FLG_INVALID;
74    if (h->ticket.flags.renewable)
75	m->enc_part2->flags |= MIT_TKT_FLG_RENEWABLE;
76    if (h->ticket.flags.initial)
77	m->enc_part2->flags |= MIT_TKT_FLG_INITIAL;
78    if (h->ticket.flags.pre_authent)
79	m->enc_part2->flags |= MIT_TKT_FLG_PRE_AUTH;
80    if (h->ticket.flags.hw_authent)
81	m->enc_part2->flags |= MIT_TKT_FLG_HW_AUTH;
82    if (h->ticket.flags.transited_policy_checked)
83	m->enc_part2->flags |= MIT_TKT_FLG_TRANSIT_POLICY_CHECKED;
84    if (h->ticket.flags.ok_as_delegate)
85	m->enc_part2->flags |= MIT_TKT_FLG_OK_AS_DELEGATE;
86    if (h->ticket.flags.anonymous)
87	m->enc_part2->flags |= MIT_TKT_FLG_ANONYMOUS;
88
89    m->enc_part2->session = mshim_malloc(sizeof(*m->enc_part2->session));
90    mshim_hkeyblock2mkeyblock(&h->ticket.key, m->enc_part2->session);
91
92    m->enc_part2->client = mshim_hprinc2mprinc(HC(context), h->client);
93    m->enc_part2->transited.tr_type = 0;
94    m->enc_part2->transited.tr_contents.data = NULL;
95    m->enc_part2->transited.tr_contents.length = 0;
96
97    m->enc_part2->times.authtime = h->ticket.authtime;
98    m->enc_part2->times.starttime =
99	h->ticket.starttime ? *h->ticket.starttime : 0 ;
100    m->enc_part2->times.endtime = h->ticket.endtime;
101    m->enc_part2->times.renew_till =
102	h->ticket.renew_till ? *h->ticket.renew_till : 0 ;
103
104    m->enc_part2->caddrs = NULL;
105    m->enc_part2->authorization_data = NULL;
106}
107
108
109
110mit_krb5_error_code KRB5_CALLCONV
111krb5_rd_req(mit_krb5_context context,
112	    mit_krb5_auth_context *ac,
113	    const mit_krb5_data *inbuf,
114	    mit_krb5_const_principal server,
115	    mit_krb5_keytab keytab,
116	    mit_krb5_flags *ap_req_options,
117	    mit_krb5_ticket **ticket)
118{
119    krb5_data idata, *d = NULL;
120    struct comb_principal *p = (struct comb_principal *)server;
121    krb5_ticket *t;
122    krb5_flags flags;
123    krb5_error_code ret;
124
125    LOG_ENTRY();
126
127    if (inbuf) {
128	d = &idata;
129	idata.data = inbuf->data;
130	idata.length = inbuf->length;
131    }
132
133    ret = heim_krb5_rd_req(HC(context), (krb5_auth_context *)ac,
134			   d, p ? p->heim : NULL, (krb5_keytab)keytab,
135			   &flags, &t);
136    if (ret == 0 && ticket != NULL) {
137	mit_krb5_ticket *mt;
138	mt = calloc(1, sizeof(*mt));
139	mshim_hticket2mticket(HC(context), t, mt);
140	heim_krb5_free_ticket(HC(context), t);
141	*ticket = mt;
142    }
143
144    return ret;
145}
146
147
148
149mit_krb5_error_code KRB5_CALLCONV
150krb5_recvauth(mit_krb5_context context,
151	      mit_krb5_auth_context *ac,
152	      mit_krb5_pointer fd,
153	      char *appl_version,
154	      mit_krb5_principal server,
155	      mit_krb5_int32 flags,
156	      mit_krb5_keytab keytab,
157	      mit_krb5_ticket **ticket)
158{
159    struct comb_principal *s = (struct comb_principal *)server;
160    krb5_ticket *hticket = NULL;
161    mit_krb5_error_code ret;
162
163    LOG_ENTRY();
164
165    ret = heim_krb5_recvauth(HC(context),
166			     (krb5_auth_context *)ac,
167			     fd,
168			     appl_version,
169			     s ? s->heim : NULL,
170			     mshim_mit_ap_rep_flags(flags),
171			     (krb5_keytab)keytab,
172			     &hticket);
173
174    if (ticket && hticket) {
175	*ticket = calloc(1, sizeof(**ticket));
176	mshim_hticket2mticket(HC(context), hticket, *ticket);
177    }
178    if (hticket)
179	heim_krb5_free_ticket(HC(context), hticket);
180
181    return ret;
182}
183
184static krb5_boolean
185match_appl_version(const void *ptr, const char *str)
186{
187    mit_krb5_data *version = (mit_krb5_data *)ptr;
188    version->magic = MIT_KV5M_DATA;
189    version->data = strdup(str);
190    version->length = strlen(str);
191    return 1;
192}
193
194mit_krb5_error_code KRB5_CALLCONV
195krb5_recvauth_version(mit_krb5_context context,
196		      mit_krb5_auth_context *ac,
197		      mit_krb5_pointer fd,
198		      mit_krb5_principal server,
199		      mit_krb5_int32 flags,
200		      mit_krb5_keytab keytab,
201		      mit_krb5_ticket **ticket,
202		      mit_krb5_data *version)
203{
204    struct comb_principal *s = (struct comb_principal *)server;
205    krb5_ticket *hticket = NULL;
206    mit_krb5_error_code ret;
207
208    LOG_ENTRY();
209
210    ret = heim_krb5_recvauth_match_version(HC(context),
211					   (krb5_auth_context *)ac,
212					   fd,
213					   match_appl_version,
214					   version,
215					   s ? s->heim : NULL,
216					   mshim_mit_ap_rep_flags(flags),
217					   (krb5_keytab)keytab,
218					   &hticket);
219
220    if (ticket && hticket) {
221	*ticket = calloc(1, sizeof(**ticket));
222	mshim_hticket2mticket(HC(context), hticket, *ticket);
223    }
224    if (hticket)
225	heim_krb5_free_ticket(HC(context), hticket);
226
227    return ret;
228}
229
230mit_krb5_error_code KRB5_CALLCONV
231krb5_rd_priv(mit_krb5_context context,
232	     mit_krb5_auth_context auth_context,
233	     const mit_krb5_data *inbuf,
234	     mit_krb5_data *outbuf,
235	     mit_krb5_replay_data *replay)
236{
237    krb5_replay_data outdata;
238    mit_krb5_error_code ret;
239
240    LOG_ENTRY();
241    krb5_data in, out;
242
243    memset(outbuf, 0, sizeof(*outbuf));
244    memset(&outdata, 0, sizeof(outdata));
245
246    in.data = inbuf->data;
247    in.length = inbuf->length;
248
249    ret = heim_krb5_rd_priv(HC(context),
250			    (krb5_auth_context)auth_context,
251			    &in,
252			    &out,
253			    &outdata);
254    if (ret)
255	return ret;
256
257    mshim_hdata2mdata(&out, outbuf);
258    heim_krb5_data_free(&out);
259
260    if (replay) {
261	memset(replay, 0, sizeof(*replay));
262	mshim_hreplay2mreplay(&outdata, replay);
263    }
264
265    return 0;
266}
267
268mit_krb5_error_code KRB5_CALLCONV
269krb5_rd_safe(mit_krb5_context context,
270	     mit_krb5_auth_context auth_context,
271	     const mit_krb5_data *inbuf,
272	     mit_krb5_data *outbuf,
273	     mit_krb5_replay_data *replay)
274{
275    krb5_replay_data outdata;
276    mit_krb5_error_code ret;
277
278    LOG_ENTRY();
279    krb5_data in, out;
280
281    memset(outbuf, 0, sizeof(*outbuf));
282    memset(&outdata, 0, sizeof(outdata));
283
284    in.data = inbuf->data;
285    in.length = inbuf->length;
286
287    ret = heim_krb5_rd_safe(HC(context),
288			    (krb5_auth_context)auth_context,
289			    &in,
290			    &out,
291			    &outdata);
292    if (ret)
293	return ret;
294
295    mshim_hdata2mdata(&out, outbuf);
296    heim_krb5_data_free(&out);
297
298    if (replay) {
299	memset(replay, 0, sizeof(*replay));
300	mshim_hreplay2mreplay(&outdata, replay);
301    }
302
303    return 0;
304}
305