1b528cefcSMark Murray /* 2b528cefcSMark Murray * Copyright (c) 1995, 1996, 1997, 1998 Kungliga Tekniska H�gskolan 3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden). 4b528cefcSMark Murray * All rights reserved. 5b528cefcSMark Murray * 6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without 7b528cefcSMark Murray * modification, are permitted provided that the following conditions 8b528cefcSMark Murray * are met: 9b528cefcSMark Murray * 10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright 11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer. 12b528cefcSMark Murray * 13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright 14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the 15b528cefcSMark Murray * documentation and/or other materials provided with the distribution. 16b528cefcSMark Murray * 17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors 18b528cefcSMark Murray * may be used to endorse or promote products derived from this software 19b528cefcSMark Murray * without specific prior written permission. 20b528cefcSMark Murray * 21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31b528cefcSMark Murray * SUCH DAMAGE. 32b528cefcSMark Murray */ 33b528cefcSMark Murray 34b528cefcSMark Murray #include "ftpd_locl.h" 35b528cefcSMark Murray 36b528cefcSMark Murray RCSID("$Id: kauth.c,v 1.25 1999/12/02 16:58:31 joda Exp $"); 37b528cefcSMark Murray 38b528cefcSMark Murray static KTEXT_ST cip; 39b528cefcSMark Murray static unsigned int lifetime; 40b528cefcSMark Murray static time_t local_time; 41b528cefcSMark Murray 42b528cefcSMark Murray static krb_principal pr; 43b528cefcSMark Murray 44b528cefcSMark Murray static int do_destroy_tickets = 1; 45b528cefcSMark Murray 46b528cefcSMark Murray static int 47b528cefcSMark Murray save_tkt(const char *user, 48b528cefcSMark Murray const char *instance, 49b528cefcSMark Murray const char *realm, 50b528cefcSMark Murray const void *arg, 51b528cefcSMark Murray key_proc_t key_proc, 52b528cefcSMark Murray KTEXT *cipp) 53b528cefcSMark Murray { 54b528cefcSMark Murray local_time = time(0); 55b528cefcSMark Murray memmove(&cip, *cipp, sizeof(cip)); 56b528cefcSMark Murray return -1; 57b528cefcSMark Murray } 58b528cefcSMark Murray 59b528cefcSMark Murray static int 60b528cefcSMark Murray store_ticket(KTEXT cip) 61b528cefcSMark Murray { 62b528cefcSMark Murray char *ptr; 63b528cefcSMark Murray des_cblock session; 64b528cefcSMark Murray krb_principal sp; 65b528cefcSMark Murray unsigned char kvno; 66b528cefcSMark Murray KTEXT_ST tkt; 67b528cefcSMark Murray int left = cip->length; 68b528cefcSMark Murray int len; 69b528cefcSMark Murray int kerror; 70b528cefcSMark Murray 71b528cefcSMark Murray ptr = (char *) cip->dat; 72b528cefcSMark Murray 73b528cefcSMark Murray /* extract session key */ 74b528cefcSMark Murray memmove(session, ptr, 8); 75b528cefcSMark Murray ptr += 8; 76b528cefcSMark Murray left -= 8; 77b528cefcSMark Murray 78b528cefcSMark Murray len = strnlen(ptr, left); 79b528cefcSMark Murray if (len == left) 80b528cefcSMark Murray return(INTK_BADPW); 81b528cefcSMark Murray 82b528cefcSMark Murray /* extract server's name */ 83b528cefcSMark Murray strlcpy(sp.name, ptr, sizeof(sp.name)); 84b528cefcSMark Murray ptr += len + 1; 85b528cefcSMark Murray left -= len + 1; 86b528cefcSMark Murray 87b528cefcSMark Murray len = strnlen(ptr, left); 88b528cefcSMark Murray if (len == left) 89b528cefcSMark Murray return(INTK_BADPW); 90b528cefcSMark Murray 91b528cefcSMark Murray /* extract server's instance */ 92b528cefcSMark Murray strlcpy(sp.instance, ptr, sizeof(sp.instance)); 93b528cefcSMark Murray ptr += len + 1; 94b528cefcSMark Murray left -= len + 1; 95b528cefcSMark Murray 96b528cefcSMark Murray len = strnlen(ptr, left); 97b528cefcSMark Murray if (len == left) 98b528cefcSMark Murray return(INTK_BADPW); 99b528cefcSMark Murray 100b528cefcSMark Murray /* extract server's realm */ 101b528cefcSMark Murray strlcpy(sp.realm, ptr, sizeof(sp.realm)); 102b528cefcSMark Murray ptr += len + 1; 103b528cefcSMark Murray left -= len + 1; 104b528cefcSMark Murray 105b528cefcSMark Murray if(left < 3) 106b528cefcSMark Murray return INTK_BADPW; 107b528cefcSMark Murray /* extract ticket lifetime, server key version, ticket length */ 108b528cefcSMark Murray /* be sure to avoid sign extension on lifetime! */ 109b528cefcSMark Murray lifetime = (unsigned char) ptr[0]; 110b528cefcSMark Murray kvno = (unsigned char) ptr[1]; 111b528cefcSMark Murray tkt.length = (unsigned char) ptr[2]; 112b528cefcSMark Murray ptr += 3; 113b528cefcSMark Murray left -= 3; 114b528cefcSMark Murray 115b528cefcSMark Murray if (tkt.length > left) 116b528cefcSMark Murray return(INTK_BADPW); 117b528cefcSMark Murray 118b528cefcSMark Murray /* extract ticket itself */ 119b528cefcSMark Murray memmove(tkt.dat, ptr, tkt.length); 120b528cefcSMark Murray ptr += tkt.length; 121b528cefcSMark Murray left -= tkt.length; 122b528cefcSMark Murray 123b528cefcSMark Murray /* Here is where the time should be verified against the KDC. 124b528cefcSMark Murray * Unfortunately everything is sent in host byte order (receiver 125b528cefcSMark Murray * makes wrong) , and at this stage there is no way for us to know 126b528cefcSMark Murray * which byteorder the KDC has. So we simply ignore the time, 127b528cefcSMark Murray * there are no security risks with this, the only thing that can 128b528cefcSMark Murray * happen is that we might receive a replayed ticket, which could 129b528cefcSMark Murray * at most be useless. 130b528cefcSMark Murray */ 131b528cefcSMark Murray 132b528cefcSMark Murray #if 0 133b528cefcSMark Murray /* check KDC time stamp */ 134b528cefcSMark Murray { 135b528cefcSMark Murray time_t kdc_time; 136b528cefcSMark Murray 137b528cefcSMark Murray memmove(&kdc_time, ptr, sizeof(kdc_time)); 138b528cefcSMark Murray if (swap_bytes) swap_u_long(kdc_time); 139b528cefcSMark Murray 140b528cefcSMark Murray ptr += 4; 141b528cefcSMark Murray 142b528cefcSMark Murray if (abs((int)(local_time - kdc_time)) > CLOCK_SKEW) { 143b528cefcSMark Murray return(RD_AP_TIME); /* XXX should probably be better 144b528cefcSMark Murray code */ 145b528cefcSMark Murray } 146b528cefcSMark Murray } 147b528cefcSMark Murray #endif 148b528cefcSMark Murray 149b528cefcSMark Murray /* initialize ticket cache */ 150b528cefcSMark Murray 151b528cefcSMark Murray if (tf_create(TKT_FILE) != KSUCCESS) 152b528cefcSMark Murray return(INTK_ERR); 153b528cefcSMark Murray 154b528cefcSMark Murray if (tf_put_pname(pr.name) != KSUCCESS || 155b528cefcSMark Murray tf_put_pinst(pr.instance) != KSUCCESS) { 156b528cefcSMark Murray tf_close(); 157b528cefcSMark Murray return(INTK_ERR); 158b528cefcSMark Murray } 159b528cefcSMark Murray 160b528cefcSMark Murray 161b528cefcSMark Murray kerror = tf_save_cred(sp.name, sp.instance, sp.realm, session, 162b528cefcSMark Murray lifetime, kvno, &tkt, local_time); 163b528cefcSMark Murray tf_close(); 164b528cefcSMark Murray 165b528cefcSMark Murray return(kerror); 166b528cefcSMark Murray } 167b528cefcSMark Murray 168b528cefcSMark Murray void 169b528cefcSMark Murray kauth(char *principal, char *ticket) 170b528cefcSMark Murray { 171b528cefcSMark Murray char *p; 172b528cefcSMark Murray int ret; 173b528cefcSMark Murray 174b528cefcSMark Murray if(get_command_prot() != prot_private) { 175b528cefcSMark Murray reply(500, "Request denied (bad protection level)"); 176b528cefcSMark Murray return; 177b528cefcSMark Murray } 178b528cefcSMark Murray ret = krb_parse_name(principal, &pr); 179b528cefcSMark Murray if(ret){ 180b528cefcSMark Murray reply(500, "Bad principal: %s.", krb_get_err_text(ret)); 181b528cefcSMark Murray return; 182b528cefcSMark Murray } 183b528cefcSMark Murray if(pr.realm[0] == 0) 184b528cefcSMark Murray krb_get_lrealm(pr.realm, 1); 185b528cefcSMark Murray 186b528cefcSMark Murray if(ticket){ 187b528cefcSMark Murray cip.length = base64_decode(ticket, &cip.dat); 188b528cefcSMark Murray if(cip.length == -1){ 189b528cefcSMark Murray reply(500, "Failed to decode data."); 190b528cefcSMark Murray return; 191b528cefcSMark Murray } 192b528cefcSMark Murray ret = store_ticket(&cip); 193b528cefcSMark Murray if(ret){ 194b528cefcSMark Murray reply(500, "Kerberos error: %s.", krb_get_err_text(ret)); 195b528cefcSMark Murray memset(&cip, 0, sizeof(cip)); 196b528cefcSMark Murray return; 197b528cefcSMark Murray } 198b528cefcSMark Murray do_destroy_tickets = 1; 199b528cefcSMark Murray 200b528cefcSMark Murray if(k_hasafs()) 201b528cefcSMark Murray krb_afslog(0, 0); 202b528cefcSMark Murray reply(200, "Tickets will be destroyed on exit."); 203b528cefcSMark Murray return; 204b528cefcSMark Murray } 205b528cefcSMark Murray 206b528cefcSMark Murray ret = krb_get_in_tkt (pr.name, 207b528cefcSMark Murray pr.instance, 208b528cefcSMark Murray pr.realm, 209b528cefcSMark Murray KRB_TICKET_GRANTING_TICKET, 210b528cefcSMark Murray pr.realm, 211b528cefcSMark Murray DEFAULT_TKT_LIFE, 212b528cefcSMark Murray NULL, save_tkt, NULL); 213b528cefcSMark Murray if(ret != INTK_BADPW){ 214b528cefcSMark Murray reply(500, "Kerberos error: %s.", krb_get_err_text(ret)); 215b528cefcSMark Murray return; 216b528cefcSMark Murray } 217b528cefcSMark Murray if(base64_encode(cip.dat, cip.length, &p) < 0) { 218b528cefcSMark Murray reply(500, "Out of memory while base64-encoding."); 219b528cefcSMark Murray return; 220b528cefcSMark Murray } 221b528cefcSMark Murray reply(300, "P=%s T=%s", krb_unparse_name(&pr), p); 222b528cefcSMark Murray free(p); 223b528cefcSMark Murray memset(&cip, 0, sizeof(cip)); 224b528cefcSMark Murray } 225b528cefcSMark Murray 226b528cefcSMark Murray 227b528cefcSMark Murray static char * 228b528cefcSMark Murray short_date(int32_t dp) 229b528cefcSMark Murray { 230b528cefcSMark Murray char *cp; 231b528cefcSMark Murray time_t t = (time_t)dp; 232b528cefcSMark Murray 233b528cefcSMark Murray if (t == (time_t)(-1L)) return "*** Never *** "; 234b528cefcSMark Murray cp = ctime(&t) + 4; 235b528cefcSMark Murray cp[15] = '\0'; 236b528cefcSMark Murray return (cp); 237b528cefcSMark Murray } 238b528cefcSMark Murray 239b528cefcSMark Murray void 240b528cefcSMark Murray klist(void) 241b528cefcSMark Murray { 242b528cefcSMark Murray int err; 243b528cefcSMark Murray 244b528cefcSMark Murray char *file = tkt_string(); 245b528cefcSMark Murray 246b528cefcSMark Murray krb_principal pr; 247b528cefcSMark Murray 248b528cefcSMark Murray char buf1[128], buf2[128]; 249b528cefcSMark Murray int header = 1; 250b528cefcSMark Murray CREDENTIALS c; 251b528cefcSMark Murray 252b528cefcSMark Murray 253b528cefcSMark Murray 254b528cefcSMark Murray err = tf_init(file, R_TKT_FIL); 255b528cefcSMark Murray if(err != KSUCCESS){ 256b528cefcSMark Murray reply(500, "%s", krb_get_err_text(err)); 257b528cefcSMark Murray return; 258b528cefcSMark Murray } 259b528cefcSMark Murray tf_close(); 260b528cefcSMark Murray 261b528cefcSMark Murray /* 262b528cefcSMark Murray * We must find the realm of the ticket file here before calling 263b528cefcSMark Murray * tf_init because since the realm of the ticket file is not 264b528cefcSMark Murray * really stored in the principal section of the file, the 265b528cefcSMark Murray * routine we use must itself call tf_init and tf_close. 266b528cefcSMark Murray */ 267b528cefcSMark Murray err = krb_get_tf_realm(file, pr.realm); 268b528cefcSMark Murray if(err != KSUCCESS){ 269b528cefcSMark Murray reply(500, "%s", krb_get_err_text(err)); 270b528cefcSMark Murray return; 271b528cefcSMark Murray } 272b528cefcSMark Murray 273b528cefcSMark Murray err = tf_init(file, R_TKT_FIL); 274b528cefcSMark Murray if(err != KSUCCESS){ 275b528cefcSMark Murray reply(500, "%s", krb_get_err_text(err)); 276b528cefcSMark Murray return; 277b528cefcSMark Murray } 278b528cefcSMark Murray 279b528cefcSMark Murray err = tf_get_pname(pr.name); 280b528cefcSMark Murray if(err != KSUCCESS){ 281b528cefcSMark Murray reply(500, "%s", krb_get_err_text(err)); 282b528cefcSMark Murray return; 283b528cefcSMark Murray } 284b528cefcSMark Murray err = tf_get_pinst(pr.instance); 285b528cefcSMark Murray if(err != KSUCCESS){ 286b528cefcSMark Murray reply(500, "%s", krb_get_err_text(err)); 287b528cefcSMark Murray return; 288b528cefcSMark Murray } 289b528cefcSMark Murray 290b528cefcSMark Murray /* 291b528cefcSMark Murray * You may think that this is the obvious place to get the 292b528cefcSMark Murray * realm of the ticket file, but it can't be done here as the 293b528cefcSMark Murray * routine to do this must open the ticket file. This is why 294b528cefcSMark Murray * it was done before tf_init. 295b528cefcSMark Murray */ 296b528cefcSMark Murray 297b528cefcSMark Murray lreply(200, "Ticket file: %s", tkt_string()); 298b528cefcSMark Murray 299b528cefcSMark Murray lreply(200, "Principal: %s", krb_unparse_name(&pr)); 300b528cefcSMark Murray while ((err = tf_get_cred(&c)) == KSUCCESS) { 301b528cefcSMark Murray if (header) { 302b528cefcSMark Murray lreply(200, "%-15s %-15s %s", 303b528cefcSMark Murray " Issued", " Expires", " Principal (kvno)"); 304b528cefcSMark Murray header = 0; 305b528cefcSMark Murray } 306b528cefcSMark Murray strlcpy(buf1, short_date(c.issue_date), sizeof(buf1)); 307b528cefcSMark Murray c.issue_date = krb_life_to_time(c.issue_date, c.lifetime); 308b528cefcSMark Murray if (time(0) < (unsigned long) c.issue_date) 309b528cefcSMark Murray strlcpy(buf2, short_date(c.issue_date), sizeof(buf2)); 310b528cefcSMark Murray else 311b528cefcSMark Murray strlcpy(buf2, ">>> Expired <<< ", sizeof(buf2)); 312b528cefcSMark Murray lreply(200, "%s %s %s (%d)", buf1, buf2, 313b528cefcSMark Murray krb_unparse_name_long(c.service, c.instance, c.realm), c.kvno); 314b528cefcSMark Murray } 315b528cefcSMark Murray if (header && err == EOF) { 316b528cefcSMark Murray lreply(200, "No tickets in file."); 317b528cefcSMark Murray } 318b528cefcSMark Murray reply(200, " "); 319b528cefcSMark Murray } 320b528cefcSMark Murray 321b528cefcSMark Murray /* 322b528cefcSMark Murray * Only destroy if we created the tickets 323b528cefcSMark Murray */ 324b528cefcSMark Murray 325b528cefcSMark Murray void 326b528cefcSMark Murray cond_kdestroy(void) 327b528cefcSMark Murray { 328b528cefcSMark Murray if (do_destroy_tickets) 329b528cefcSMark Murray dest_tkt(); 330b528cefcSMark Murray afsunlog(); 331b528cefcSMark Murray } 332b528cefcSMark Murray 333b528cefcSMark Murray void 334b528cefcSMark Murray kdestroy(void) 335b528cefcSMark Murray { 336b528cefcSMark Murray dest_tkt(); 337b528cefcSMark Murray afsunlog(); 338b528cefcSMark Murray reply(200, "Tickets destroyed"); 339b528cefcSMark Murray } 340b528cefcSMark Murray 341b528cefcSMark Murray void 342b528cefcSMark Murray krbtkfile(const char *tkfile) 343b528cefcSMark Murray { 344b528cefcSMark Murray do_destroy_tickets = 0; 345b528cefcSMark Murray krb_set_tkt_string(tkfile); 346b528cefcSMark Murray reply(200, "Using ticket file %s", tkfile); 347b528cefcSMark Murray } 348b528cefcSMark Murray 349b528cefcSMark Murray void 350b528cefcSMark Murray afslog(const char *cell) 351b528cefcSMark Murray { 352b528cefcSMark Murray if(k_hasafs()) { 353b528cefcSMark Murray krb_afslog(cell, 0); 354b528cefcSMark Murray reply(200, "afslog done"); 355b528cefcSMark Murray } else { 356b528cefcSMark Murray reply(200, "no AFS present"); 357b528cefcSMark Murray } 358b528cefcSMark Murray } 359b528cefcSMark Murray 360b528cefcSMark Murray void 361b528cefcSMark Murray afsunlog(void) 362b528cefcSMark Murray { 363b528cefcSMark Murray if(k_hasafs()) 364b528cefcSMark Murray k_unlog(); 365b528cefcSMark Murray } 366