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