155682Smarkm/*
2233294Sstas * Copyright (c) 1995-2003 Kungliga Tekniska H��gskolan
355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden).
455682Smarkm * All rights reserved.
5233294Sstas *
655682Smarkm * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
9233294Sstas *
1055682Smarkm * 1. Redistributions of source code must retain the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer.
12233294Sstas *
1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer in the
1555682Smarkm *    documentation and/or other materials provided with the distribution.
16233294Sstas *
1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
20233294Sstas *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "kafs_locl.h"
3555682Smarkm
3655682Smarkmstruct krb5_kafs_data {
3755682Smarkm    krb5_context context;
3855682Smarkm    krb5_ccache id;
3955682Smarkm    krb5_const_realm realm;
4055682Smarkm};
4155682Smarkm
42233294Sstasenum {
43120945Snectar    KAFS_RXKAD_2B_KVNO = 213,
44120945Snectar    KAFS_RXKAD_K5_KVNO = 256
45120945Snectar};
46120945Snectar
4755682Smarkmstatic int
48120945Snectarv5_to_kt(krb5_creds *cred, uid_t uid, struct kafs_token *kt, int local524)
49120945Snectar{
50120945Snectar    int kvno, ret;
51120945Snectar
52120945Snectar    kt->ticket = NULL;
53120945Snectar
54120945Snectar    /* check if des key */
55120945Snectar    if (cred->session.keyvalue.length != 8)
56120945Snectar	return EINVAL;
57120945Snectar
58120945Snectar    if (local524) {
59120945Snectar	Ticket t;
60120945Snectar	unsigned char *buf;
61120945Snectar	size_t buf_len;
62120945Snectar	size_t len;
63120945Snectar
64120945Snectar	kvno = KAFS_RXKAD_2B_KVNO;
65120945Snectar
66120945Snectar	ret = decode_Ticket(cred->ticket.data, cred->ticket.length, &t, &len);
67120945Snectar	if (ret)
68120945Snectar	    return ret;
69120945Snectar	if (t.tkt_vno != 5)
70120945Snectar	    return -1;
71120945Snectar
72120945Snectar	ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_len, &t.enc_part,
73120945Snectar			   &len, ret);
74120945Snectar	free_Ticket(&t);
75120945Snectar	if (ret)
76120945Snectar	    return ret;
77120945Snectar	if(buf_len != len) {
78120945Snectar	    free(buf);
79120945Snectar	    return KRB5KRB_ERR_GENERIC;
80120945Snectar	}
81120945Snectar
82120945Snectar	kt->ticket = buf;
83120945Snectar	kt->ticket_len = buf_len;
84120945Snectar
85120945Snectar    } else {
86120945Snectar	kvno = KAFS_RXKAD_K5_KVNO;
87120945Snectar	kt->ticket = malloc(cred->ticket.length);
88120945Snectar	if (kt->ticket == NULL)
89120945Snectar	    return ENOMEM;
90120945Snectar	kt->ticket_len = cred->ticket.length;
91120945Snectar	memcpy(kt->ticket, cred->ticket.data, kt->ticket_len);
92120945Snectar
93120945Snectar	ret = 0;
94120945Snectar    }
95120945Snectar
96120945Snectar
97120945Snectar    /*
98120945Snectar     * Build a struct ClearToken
99120945Snectar     */
100120945Snectar
101120945Snectar    kt->ct.AuthHandle = kvno;
102120945Snectar    memcpy(kt->ct.HandShakeKey, cred->session.keyvalue.data, 8);
103120945Snectar    kt->ct.ViceId = uid;
104120945Snectar    kt->ct.BeginTimestamp = cred->times.starttime;
105120945Snectar    kt->ct.EndTimestamp = cred->times.endtime;
106120945Snectar
107120945Snectar    _kafs_fixup_viceid(&kt->ct, uid);
108120945Snectar
109120945Snectar    return 0;
110120945Snectar}
111120945Snectar
112120945Snectarstatic krb5_error_code
113120945Snectarv5_convert(krb5_context context, krb5_ccache id,
114233294Sstas	   krb5_creds *cred, uid_t uid,
115120945Snectar	   const char *cell,
116120945Snectar	   struct kafs_token *kt)
117120945Snectar{
118120945Snectar    krb5_error_code ret;
119120945Snectar    char *c, *val;
120120945Snectar
121120945Snectar    c = strdup(cell);
122120945Snectar    if (c == NULL)
123120945Snectar	return ENOMEM;
124120945Snectar    _kafs_foldup(c, c);
125120945Snectar    krb5_appdefault_string (context, "libkafs",
126120945Snectar			    c,
127178825Sdfr			    "afs-use-524", "2b", &val);
128120945Snectar    free(c);
129120945Snectar
130233294Sstas    if (strcasecmp(val, "local") == 0 ||
131120945Snectar	strcasecmp(val, "2b") == 0)
132120945Snectar	ret = v5_to_kt(cred, uid, kt, 1);
133233294Sstas    else
134120945Snectar	ret = v5_to_kt(cred, uid, kt, 0);
135120945Snectar
136120945Snectar    free(val);
137120945Snectar    return ret;
138120945Snectar}
139120945Snectar
140120945Snectar
141120945Snectar/*
142120945Snectar *
143120945Snectar */
144120945Snectar
145120945Snectarstatic int
146233294Sstasget_cred(struct kafs_data *data, const char *name, const char *inst,
147120945Snectar	 const char *realm, uid_t uid, struct kafs_token *kt)
14855682Smarkm{
14955682Smarkm    krb5_error_code ret;
15055682Smarkm    krb5_creds in_creds, *out_creds;
15155682Smarkm    struct krb5_kafs_data *d = data->data;
152233294Sstas    int invalid;
15355682Smarkm
15455682Smarkm    memset(&in_creds, 0, sizeof(in_creds));
155233294Sstas
156233294Sstas    ret = krb5_make_principal(d->context, &in_creds.server,
157233294Sstas			      realm, name, inst, NULL);
15855682Smarkm    if(ret)
15955682Smarkm	return ret;
16055682Smarkm    ret = krb5_cc_get_principal(d->context, d->id, &in_creds.client);
16155682Smarkm    if(ret){
16255682Smarkm	krb5_free_principal(d->context, in_creds.server);
16355682Smarkm	return ret;
16455682Smarkm    }
165233294Sstas
166178825Sdfr    in_creds.session.keytype = ETYPE_DES_CBC_CRC;
167233294Sstas
168233294Sstas    /* check if des is disable, and in that case enable it for afs */
169233294Sstas    invalid = krb5_enctype_valid(d->context, in_creds.session.keytype);
170233294Sstas    if (invalid)
171233294Sstas	krb5_enctype_enable(d->context, in_creds.session.keytype);
172233294Sstas
17355682Smarkm    ret = krb5_get_credentials(d->context, 0, d->id, &in_creds, &out_creds);
174233294Sstas    if (ret) {
175233294Sstas	in_creds.session.keytype = ETYPE_DES_CBC_MD5;
176233294Sstas	ret = krb5_get_credentials(d->context, 0, d->id, &in_creds, &out_creds);
177233294Sstas    }
178233294Sstas
179233294Sstas    if (invalid)
180233294Sstas	krb5_enctype_disable(d->context, in_creds.session.keytype);
181233294Sstas
18255682Smarkm    krb5_free_principal(d->context, in_creds.server);
18355682Smarkm    krb5_free_principal(d->context, in_creds.client);
18455682Smarkm    if(ret)
18555682Smarkm	return ret;
186120945Snectar
187233294Sstas    ret = v5_convert(d->context, d->id, out_creds, uid,
188120945Snectar		     (inst != NULL && inst[0] != '\0') ? inst : realm, kt);
18955682Smarkm    krb5_free_creds(d->context, out_creds);
190120945Snectar
19155682Smarkm    return ret;
19255682Smarkm}
19355682Smarkm
194233294Sstasstatic const char *
195233294Sstasget_error(struct kafs_data *data, int error)
196233294Sstas{
197233294Sstas    struct krb5_kafs_data *d = data->data;
198233294Sstas    return krb5_get_error_message(d->context, error);
199233294Sstas}
200233294Sstas
201233294Sstasstatic void
202233294Sstasfree_error(struct kafs_data *data, const char *str)
203233294Sstas{
204233294Sstas    struct krb5_kafs_data *d = data->data;
205233294Sstas    krb5_free_error_message(d->context, str);
206233294Sstas}
207233294Sstas
20855682Smarkmstatic krb5_error_code
209178825Sdfrafslog_uid_int(struct kafs_data *data, const char *cell, const char *rh,
210178825Sdfr	       uid_t uid, const char *homedir)
21155682Smarkm{
21255682Smarkm    krb5_error_code ret;
213120945Snectar    struct kafs_token kt;
21455682Smarkm    krb5_principal princ;
215178825Sdfr    const char *trealm; /* ticket realm */
21655682Smarkm    struct krb5_kafs_data *d = data->data;
217233294Sstas
21855682Smarkm    if (cell == 0 || cell[0] == 0)
21955682Smarkm	return _kafs_afslog_all_local_cells (data, uid, homedir);
22055682Smarkm
22155682Smarkm    ret = krb5_cc_get_principal (d->context, d->id, &princ);
22255682Smarkm    if (ret)
22355682Smarkm	return ret;
22455682Smarkm
225178825Sdfr    trealm = krb5_principal_get_realm (d->context, princ);
22655682Smarkm
227120945Snectar    kt.ticket = NULL;
228178825Sdfr    ret = _kafs_get_cred(data, cell, d->realm, trealm, uid, &kt);
229178825Sdfr    krb5_free_principal (d->context, princ);
230233294Sstas
231120945Snectar    if(ret == 0) {
232120945Snectar	ret = kafs_settoken_rxkad(cell, &kt.ct, kt.ticket, kt.ticket_len);
233120945Snectar	free(kt.ticket);
234120945Snectar    }
23555682Smarkm    return ret;
23655682Smarkm}
23755682Smarkm
23855682Smarkmstatic char *
239178825Sdfrget_realm(struct kafs_data *data, const char *host)
24055682Smarkm{
24155682Smarkm    struct krb5_kafs_data *d = data->data;
24255682Smarkm    krb5_realm *realms;
24355682Smarkm    char *r;
24455682Smarkm    if(krb5_get_host_realm(d->context, host, &realms))
24555682Smarkm	return NULL;
24655682Smarkm    r = strdup(realms[0]);
24755682Smarkm    krb5_free_host_realm(d->context, realms);
24855682Smarkm    return r;
24955682Smarkm}
25055682Smarkm
25155682Smarkmkrb5_error_code
25255682Smarkmkrb5_afslog_uid_home(krb5_context context,
25355682Smarkm		     krb5_ccache id,
25455682Smarkm		     const char *cell,
25555682Smarkm		     krb5_const_realm realm,
25655682Smarkm		     uid_t uid,
25755682Smarkm		     const char *homedir)
25855682Smarkm{
259178825Sdfr    struct kafs_data kd;
26055682Smarkm    struct krb5_kafs_data d;
261178825Sdfr    krb5_error_code ret;
262178825Sdfr
263120945Snectar    kd.name = "krb5";
26455682Smarkm    kd.afslog_uid = afslog_uid_int;
26555682Smarkm    kd.get_cred = get_cred;
26655682Smarkm    kd.get_realm = get_realm;
267233294Sstas    kd.get_error = get_error;
268233294Sstas    kd.free_error = free_error;
26955682Smarkm    kd.data = &d;
270178825Sdfr    if (context == NULL) {
271178825Sdfr	ret = krb5_init_context(&d.context);
272178825Sdfr	if (ret)
273178825Sdfr	    return ret;
274178825Sdfr    } else
275178825Sdfr	d.context = context;
276178825Sdfr    if (id == NULL) {
277178825Sdfr	ret = krb5_cc_default(d.context, &d.id);
278178825Sdfr	if (ret)
279178825Sdfr	    goto out;
280178825Sdfr    } else
281178825Sdfr	d.id = id;
28255682Smarkm    d.realm = realm;
283178825Sdfr    ret = afslog_uid_int(&kd, cell, 0, uid, homedir);
284178825Sdfr    if (id == NULL)
285178825Sdfr	krb5_cc_close(context, d.id);
286178825Sdfr out:
287178825Sdfr    if (context == NULL)
288178825Sdfr	krb5_free_context(d.context);
289178825Sdfr    return ret;
29055682Smarkm}
29155682Smarkm
29255682Smarkmkrb5_error_code
29355682Smarkmkrb5_afslog_uid(krb5_context context,
29455682Smarkm		krb5_ccache id,
29555682Smarkm		const char *cell,
29655682Smarkm		krb5_const_realm realm,
29755682Smarkm		uid_t uid)
29855682Smarkm{
29955682Smarkm    return krb5_afslog_uid_home (context, id, cell, realm, uid, NULL);
30055682Smarkm}
30155682Smarkm
30255682Smarkmkrb5_error_code
30355682Smarkmkrb5_afslog(krb5_context context,
304233294Sstas	    krb5_ccache id,
30555682Smarkm	    const char *cell,
30655682Smarkm	    krb5_const_realm realm)
30755682Smarkm{
30855682Smarkm    return krb5_afslog_uid (context, id, cell, realm, getuid());
30955682Smarkm}
31055682Smarkm
31155682Smarkmkrb5_error_code
31255682Smarkmkrb5_afslog_home(krb5_context context,
313233294Sstas		 krb5_ccache id,
31455682Smarkm		 const char *cell,
31555682Smarkm		 krb5_const_realm realm,
31655682Smarkm		 const char *homedir)
31755682Smarkm{
31855682Smarkm    return krb5_afslog_uid_home (context, id, cell, realm, getuid(), homedir);
31955682Smarkm}
32055682Smarkm
32155682Smarkm/*
32255682Smarkm *
32355682Smarkm */
32455682Smarkm
32555682Smarkmkrb5_error_code
32655682Smarkmkrb5_realm_of_cell(const char *cell, char **realm)
32755682Smarkm{
328178825Sdfr    struct kafs_data kd;
32955682Smarkm
330120945Snectar    kd.name = "krb5";
33155682Smarkm    kd.get_realm = get_realm;
332233294Sstas    kd.get_error = get_error;
333233294Sstas    kd.free_error = free_error;
33455682Smarkm    return _kafs_realm_of_cell(&kd, cell, realm);
33555682Smarkm}
336120945Snectar
337120945Snectar/*
338120945Snectar *
339120945Snectar */
340120945Snectar
341120945Snectarint
342120945Snectarkafs_settoken5(krb5_context context, const char *cell, uid_t uid,
343120945Snectar	       krb5_creds *cred)
344120945Snectar{
345120945Snectar    struct kafs_token kt;
346120945Snectar    int ret;
347120945Snectar
348120945Snectar    ret = v5_convert(context, NULL, cred, uid, cell, &kt);
349120945Snectar    if (ret)
350120945Snectar	return ret;
351120945Snectar
352120945Snectar    ret = kafs_settoken_rxkad(cell, &kt.ct, kt.ticket, kt.ticket_len);
353120945Snectar
354120945Snectar    free(kt.ticket);
355120945Snectar
356120945Snectar    return ret;
357120945Snectar}
358