Home | History | Annotate | Line # | Download | only in kafs
afskrb5.c revision 1.3
      1 /*	$NetBSD: afskrb5.c,v 1.3 2023/06/19 21:41:44 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1995-2003 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * 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 "kafs_locl.h"
     37 
     38 struct krb5_kafs_data {
     39     krb5_context context;
     40     krb5_ccache id;
     41     krb5_const_realm realm;
     42 };
     43 
     44 enum {
     45     KAFS_RXKAD_2B_KVNO = 213,
     46     KAFS_RXKAD_K5_KVNO = 256
     47 };
     48 
     49 static int
     50 v5_to_kt(krb5_creds *cred, uid_t uid, struct kafs_token *kt, int local524)
     51 {
     52     int kvno, ret;
     53 
     54     kt->ticket = NULL;
     55 
     56     if (local524) {
     57 	Ticket t;
     58 	unsigned char *buf;
     59 	size_t buf_len;
     60 	size_t len;
     61 
     62 	kvno = KAFS_RXKAD_2B_KVNO;
     63 
     64 	ret = decode_Ticket(cred->ticket.data, cred->ticket.length, &t, &len);
     65 	if (ret)
     66 	    return ret;
     67 	if (t.tkt_vno != 5)
     68 	    return -1;
     69 
     70 	ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_len, &t.enc_part,
     71 			   &len, ret);
     72 	free_Ticket(&t);
     73 	if (ret)
     74 	    return ret;
     75 	if(buf_len != len) {
     76 	    free(buf);
     77 	    return KRB5KRB_ERR_GENERIC;
     78 	}
     79 
     80 	kt->ticket = buf;
     81 	kt->ticket_len = buf_len;
     82 
     83     } else {
     84 	kvno = KAFS_RXKAD_K5_KVNO;
     85 	kt->ticket = malloc(cred->ticket.length);
     86 	if (kt->ticket == NULL)
     87 	    return ENOMEM;
     88 	kt->ticket_len = cred->ticket.length;
     89 	memcpy(kt->ticket, cred->ticket.data, kt->ticket_len);
     90     }
     91 
     92 
     93     /*
     94      * Build a struct ClearToken
     95      */
     96 
     97     ret = _kafs_derive_des_key(cred->session.keytype,
     98 			       cred->session.keyvalue.data,
     99 			       cred->session.keyvalue.length,
    100 			       kt->ct.HandShakeKey);
    101     if (ret) {
    102 	free(kt->ticket);
    103 	kt->ticket = NULL;
    104 	return ret;
    105     }
    106     kt->ct.AuthHandle = kvno;
    107     kt->ct.ViceId = uid;
    108     kt->ct.BeginTimestamp = cred->times.starttime;
    109     kt->ct.EndTimestamp = cred->times.endtime;
    110 
    111     _kafs_fixup_viceid(&kt->ct, uid);
    112 
    113     return 0;
    114 }
    115 
    116 static krb5_error_code
    117 v5_convert(krb5_context context, krb5_ccache id,
    118 	   krb5_creds *cred, uid_t uid,
    119 	   const char *cell,
    120 	   struct kafs_token *kt)
    121 {
    122     krb5_error_code ret;
    123     char *c, *val;
    124 
    125     c = strdup(cell);
    126     if (c == NULL)
    127 	return ENOMEM;
    128     _kafs_foldup(c, c);
    129     krb5_appdefault_string (context, "libkafs",
    130 			    c,
    131 			    "afs-use-524", "2b", &val);
    132     free(c);
    133 
    134     if (strcasecmp(val, "local") == 0 ||
    135 	strcasecmp(val, "2b") == 0)
    136 	ret = v5_to_kt(cred, uid, kt, 1);
    137     else
    138 	ret = v5_to_kt(cred, uid, kt, 0);
    139 
    140     free(val);
    141     return ret;
    142 }
    143 
    144 
    145 /*
    146  *
    147  */
    148 
    149 static int
    150 get_cred(struct kafs_data *data, const char *name, const char *inst,
    151 	 const char *realm, uid_t uid, struct kafs_token *kt)
    152 {
    153     krb5_error_code ret;
    154     krb5_creds in_creds, *out_creds;
    155     struct krb5_kafs_data *d = data->data;
    156     int invalid;
    157 
    158     memset(&in_creds, 0, sizeof(in_creds));
    159 
    160     ret = krb5_make_principal(d->context, &in_creds.server,
    161 			      realm, name, inst, NULL);
    162     if(ret)
    163 	return ret;
    164     ret = krb5_cc_get_principal(d->context, d->id, &in_creds.client);
    165     if(ret){
    166 	krb5_free_principal(d->context, in_creds.server);
    167 	return ret;
    168     }
    169 
    170     /* check if des is disable, and in that case enable it for afs */
    171     invalid = krb5_enctype_valid(d->context, ETYPE_DES_CBC_CRC);
    172     if (invalid)
    173 	krb5_enctype_enable(d->context, ETYPE_DES_CBC_CRC);
    174 
    175     ret = krb5_get_credentials(d->context, 0, d->id, &in_creds, &out_creds);
    176 
    177     if (invalid)
    178 	krb5_enctype_disable(d->context, ETYPE_DES_CBC_CRC);
    179 
    180     krb5_free_principal(d->context, in_creds.server);
    181     krb5_free_principal(d->context, in_creds.client);
    182     if(ret)
    183 	return ret;
    184 
    185     ret = v5_convert(d->context, d->id, out_creds, uid,
    186 		     (inst != NULL && inst[0] != '\0') ? inst : realm, kt);
    187     krb5_free_creds(d->context, out_creds);
    188 
    189     return ret;
    190 }
    191 
    192 static const char *
    193 get_error(struct kafs_data *data, int error)
    194 {
    195     struct krb5_kafs_data *d = data->data;
    196     return krb5_get_error_message(d->context, error);
    197 }
    198 
    199 static void
    200 free_error(struct kafs_data *data, const char *str)
    201 {
    202     struct krb5_kafs_data *d = data->data;
    203     krb5_free_error_message(d->context, str);
    204 }
    205 
    206 static krb5_error_code
    207 afslog_uid_int(struct kafs_data *data, const char *cell, const char *rh,
    208 	       uid_t uid, const char *homedir)
    209 {
    210     krb5_error_code ret;
    211     struct kafs_token kt;
    212     krb5_principal princ;
    213     const char *trealm; /* ticket realm */
    214     struct krb5_kafs_data *d = data->data;
    215 
    216     if (cell == 0 || cell[0] == 0)
    217 	return _kafs_afslog_all_local_cells (data, uid, homedir);
    218 
    219     ret = krb5_cc_get_principal (d->context, d->id, &princ);
    220     if (ret)
    221 	return ret;
    222 
    223     trealm = krb5_principal_get_realm (d->context, princ);
    224 
    225     kt.ticket = NULL;
    226     ret = _kafs_get_cred(data, cell, d->realm, trealm, uid, &kt);
    227     krb5_free_principal (d->context, princ);
    228 
    229     if(ret == 0) {
    230 	ret = kafs_settoken_rxkad(cell, &kt.ct, kt.ticket, kt.ticket_len);
    231 	free(kt.ticket);
    232     }
    233     return ret;
    234 }
    235 
    236 static char *
    237 get_realm(struct kafs_data *data, const char *host)
    238 {
    239     struct krb5_kafs_data *d = data->data;
    240     krb5_realm *realms;
    241     char *r;
    242     if(krb5_get_host_realm(d->context, host, &realms))
    243 	return NULL;
    244     r = strdup(realms[0]);
    245     krb5_free_host_realm(d->context, realms);
    246     return r;
    247 }
    248 
    249 krb5_error_code
    250 krb5_afslog_uid_home(krb5_context context,
    251 		     krb5_ccache id,
    252 		     const char *cell,
    253 		     krb5_const_realm realm,
    254 		     uid_t uid,
    255 		     const char *homedir)
    256 {
    257     struct kafs_data kd;
    258     struct krb5_kafs_data d;
    259     krb5_error_code ret;
    260 
    261     kd.name = "krb5";
    262     kd.afslog_uid = afslog_uid_int;
    263     kd.get_cred = get_cred;
    264     kd.get_realm = get_realm;
    265     kd.get_error = get_error;
    266     kd.free_error = free_error;
    267     kd.data = &d;
    268     if (context == NULL) {
    269 	ret = krb5_init_context(&d.context);
    270 	if (ret)
    271 	    return ret;
    272     } else
    273 	d.context = context;
    274     if (id == NULL) {
    275 	ret = krb5_cc_default(d.context, &d.id);
    276 	if (ret)
    277 	    goto out;
    278     } else
    279 	d.id = id;
    280     d.realm = realm;
    281     ret = afslog_uid_int(&kd, cell, 0, uid, homedir);
    282     if (id == NULL)
    283 	krb5_cc_close(context, d.id);
    284  out:
    285     if (context == NULL)
    286 	krb5_free_context(d.context);
    287     return ret;
    288 }
    289 
    290 krb5_error_code
    291 krb5_afslog_uid(krb5_context context,
    292 		krb5_ccache id,
    293 		const char *cell,
    294 		krb5_const_realm realm,
    295 		uid_t uid)
    296 {
    297     return krb5_afslog_uid_home (context, id, cell, realm, uid, NULL);
    298 }
    299 
    300 krb5_error_code
    301 krb5_afslog(krb5_context context,
    302 	    krb5_ccache id,
    303 	    const char *cell,
    304 	    krb5_const_realm realm)
    305 {
    306     return krb5_afslog_uid (context, id, cell, realm, getuid());
    307 }
    308 
    309 krb5_error_code
    310 krb5_afslog_home(krb5_context context,
    311 		 krb5_ccache id,
    312 		 const char *cell,
    313 		 krb5_const_realm realm,
    314 		 const char *homedir)
    315 {
    316     return krb5_afslog_uid_home (context, id, cell, realm, getuid(), homedir);
    317 }
    318 
    319 /*
    320  *
    321  */
    322 
    323 krb5_error_code
    324 krb5_realm_of_cell(const char *cell, char **realm)
    325 {
    326     struct kafs_data kd;
    327 
    328     kd.name = "krb5";
    329     kd.get_realm = get_realm;
    330     kd.get_error = get_error;
    331     kd.free_error = free_error;
    332     return _kafs_realm_of_cell(&kd, cell, realm);
    333 }
    334 
    335 /*
    336  *
    337  */
    338 
    339 int
    340 kafs_settoken5(krb5_context context, const char *cell, uid_t uid,
    341 	       krb5_creds *cred)
    342 {
    343     struct kafs_token kt;
    344     int ret;
    345 
    346     ret = v5_convert(context, NULL, cred, uid, cell, &kt);
    347     if (ret)
    348 	return ret;
    349 
    350     ret = kafs_settoken_rxkad(cell, &kt.ct, kt.ticket, kt.ticket_len);
    351 
    352     free(kt.ticket);
    353 
    354     return ret;
    355 }
    356