krb4.c revision 178825
155682Smarkm/* 255682Smarkm * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 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. 1655682Smarkm * 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. 2055682Smarkm * 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#ifdef FTP_SERVER 3555682Smarkm#include "ftpd_locl.h" 3655682Smarkm#else 3755682Smarkm#include "ftp_locl.h" 3855682Smarkm#endif 3955682Smarkm#include <krb.h> 4055682Smarkm 41178825SdfrRCSID("$Id: krb4.c 17450 2006-05-05 11:11:43Z lha $"); 4255682Smarkm 4355682Smarkm#ifdef FTP_SERVER 4455682Smarkm#define LOCAL_ADDR ctrl_addr 4555682Smarkm#define REMOTE_ADDR his_addr 4655682Smarkm#else 4755682Smarkm#define LOCAL_ADDR myctladdr 4855682Smarkm#define REMOTE_ADDR hisctladdr 4955682Smarkm#endif 5055682Smarkm 5155682Smarkmextern struct sockaddr *LOCAL_ADDR, *REMOTE_ADDR; 5255682Smarkm 5355682Smarkmstruct krb4_data { 5455682Smarkm des_cblock key; 5555682Smarkm des_key_schedule schedule; 5655682Smarkm char name[ANAME_SZ]; 5755682Smarkm char instance[INST_SZ]; 5855682Smarkm char realm[REALM_SZ]; 5955682Smarkm}; 6055682Smarkm 6155682Smarkmstatic int 6255682Smarkmkrb4_check_prot(void *app_data, int level) 6355682Smarkm{ 6455682Smarkm if(level == prot_confidential) 6555682Smarkm return -1; 6655682Smarkm return 0; 6755682Smarkm} 6855682Smarkm 6955682Smarkmstatic int 7055682Smarkmkrb4_decode(void *app_data, void *buf, int len, int level) 7155682Smarkm{ 7255682Smarkm MSG_DAT m; 7355682Smarkm int e; 7455682Smarkm struct krb4_data *d = app_data; 7555682Smarkm 7655682Smarkm if(level == prot_safe) 7755682Smarkm e = krb_rd_safe(buf, len, &d->key, 7855682Smarkm (struct sockaddr_in *)REMOTE_ADDR, 7955682Smarkm (struct sockaddr_in *)LOCAL_ADDR, &m); 8055682Smarkm else 8155682Smarkm e = krb_rd_priv(buf, len, d->schedule, &d->key, 8255682Smarkm (struct sockaddr_in *)REMOTE_ADDR, 8355682Smarkm (struct sockaddr_in *)LOCAL_ADDR, &m); 8455682Smarkm if(e){ 8555682Smarkm syslog(LOG_ERR, "krb4_decode: %s", krb_get_err_text(e)); 8655682Smarkm return -1; 8755682Smarkm } 8855682Smarkm memmove(buf, m.app_data, m.app_length); 8955682Smarkm return m.app_length; 9055682Smarkm} 9155682Smarkm 9255682Smarkmstatic int 9355682Smarkmkrb4_overhead(void *app_data, int level, int len) 9455682Smarkm{ 9555682Smarkm return 31; 9655682Smarkm} 9755682Smarkm 9855682Smarkmstatic int 9955682Smarkmkrb4_encode(void *app_data, void *from, int length, int level, void **to) 10055682Smarkm{ 10155682Smarkm struct krb4_data *d = app_data; 10255682Smarkm *to = malloc(length + 31); 10355682Smarkm if(level == prot_safe) 10455682Smarkm return krb_mk_safe(from, *to, length, &d->key, 10555682Smarkm (struct sockaddr_in *)LOCAL_ADDR, 10655682Smarkm (struct sockaddr_in *)REMOTE_ADDR); 10755682Smarkm else if(level == prot_private) 10855682Smarkm return krb_mk_priv(from, *to, length, d->schedule, &d->key, 10955682Smarkm (struct sockaddr_in *)LOCAL_ADDR, 11055682Smarkm (struct sockaddr_in *)REMOTE_ADDR); 11155682Smarkm else 11255682Smarkm return -1; 11355682Smarkm} 11455682Smarkm 11555682Smarkm#ifdef FTP_SERVER 11655682Smarkm 11755682Smarkmstatic int 11855682Smarkmkrb4_adat(void *app_data, void *buf, size_t len) 11955682Smarkm{ 12055682Smarkm KTEXT_ST tkt; 12155682Smarkm AUTH_DAT auth_dat; 12255682Smarkm char *p; 12355682Smarkm int kerror; 124178825Sdfr uint32_t cs; 12555682Smarkm char msg[35]; /* size of encrypted block */ 12655682Smarkm int tmp_len; 12755682Smarkm struct krb4_data *d = app_data; 12855682Smarkm char inst[INST_SZ]; 12955682Smarkm struct sockaddr_in *his_addr_sin = (struct sockaddr_in *)his_addr; 13055682Smarkm 13155682Smarkm memcpy(tkt.dat, buf, len); 13255682Smarkm tkt.length = len; 13355682Smarkm 13455682Smarkm k_getsockinst(0, inst, sizeof(inst)); 13555682Smarkm kerror = krb_rd_req(&tkt, "ftp", inst, 13655682Smarkm his_addr_sin->sin_addr.s_addr, &auth_dat, ""); 13755682Smarkm if(kerror == RD_AP_UNDEC){ 13855682Smarkm k_getsockinst(0, inst, sizeof(inst)); 13955682Smarkm kerror = krb_rd_req(&tkt, "rcmd", inst, 14055682Smarkm his_addr_sin->sin_addr.s_addr, &auth_dat, ""); 14155682Smarkm } 14255682Smarkm 14355682Smarkm if(kerror){ 14455682Smarkm reply(535, "Error reading request: %s.", krb_get_err_text(kerror)); 14555682Smarkm return -1; 14655682Smarkm } 14755682Smarkm 14855682Smarkm memcpy(d->key, auth_dat.session, sizeof(d->key)); 14955682Smarkm des_set_key(&d->key, d->schedule); 15055682Smarkm 15155682Smarkm strlcpy(d->name, auth_dat.pname, sizeof(d->name)); 15255682Smarkm strlcpy(d->instance, auth_dat.pinst, sizeof(d->instance)); 15355682Smarkm strlcpy(d->realm, auth_dat.prealm, sizeof(d->instance)); 15455682Smarkm 15555682Smarkm cs = auth_dat.checksum + 1; 15655682Smarkm { 15755682Smarkm unsigned char tmp[4]; 15855682Smarkm KRB_PUT_INT(cs, tmp, 4, sizeof(tmp)); 15955682Smarkm tmp_len = krb_mk_safe(tmp, msg, 4, &d->key, 16055682Smarkm (struct sockaddr_in *)LOCAL_ADDR, 16155682Smarkm (struct sockaddr_in *)REMOTE_ADDR); 16255682Smarkm } 16355682Smarkm if(tmp_len < 0){ 16455682Smarkm reply(535, "Error creating reply: %s.", strerror(errno)); 16555682Smarkm return -1; 16655682Smarkm } 16755682Smarkm len = tmp_len; 16855682Smarkm if(base64_encode(msg, len, &p) < 0) { 16955682Smarkm reply(535, "Out of memory base64-encoding."); 17055682Smarkm return -1; 17155682Smarkm } 17255682Smarkm reply(235, "ADAT=%s", p); 17355682Smarkm sec_complete = 1; 17455682Smarkm free(p); 17555682Smarkm return 0; 17655682Smarkm} 17755682Smarkm 17855682Smarkmstatic int 17955682Smarkmkrb4_userok(void *app_data, char *user) 18055682Smarkm{ 18155682Smarkm struct krb4_data *d = app_data; 18255682Smarkm return krb_kuserok(d->name, d->instance, d->realm, user); 18355682Smarkm} 18455682Smarkm 18555682Smarkmstruct sec_server_mech krb4_server_mech = { 18655682Smarkm "KERBEROS_V4", 18755682Smarkm sizeof(struct krb4_data), 18855682Smarkm NULL, /* init */ 18955682Smarkm NULL, /* end */ 19055682Smarkm krb4_check_prot, 19155682Smarkm krb4_overhead, 19255682Smarkm krb4_encode, 19355682Smarkm krb4_decode, 19455682Smarkm /* */ 19555682Smarkm NULL, 19655682Smarkm krb4_adat, 19755682Smarkm NULL, /* pbsz */ 19855682Smarkm NULL, /* ccc */ 19955682Smarkm krb4_userok 20055682Smarkm}; 20155682Smarkm 20255682Smarkm#else /* FTP_SERVER */ 20355682Smarkm 20455682Smarkmstatic int 20572445Sassarkrb4_init(void *app_data) 20672445Sassar{ 20772445Sassar return !use_kerberos; 20872445Sassar} 20972445Sassar 21072445Sassarstatic int 21155682Smarkmmk_auth(struct krb4_data *d, KTEXT adat, 21255682Smarkm char *service, char *host, int checksum) 21355682Smarkm{ 21455682Smarkm int ret; 21555682Smarkm CREDENTIALS cred; 21655682Smarkm char sname[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ]; 21755682Smarkm 21855682Smarkm strlcpy(sname, service, sizeof(sname)); 21955682Smarkm strlcpy(inst, krb_get_phost(host), sizeof(inst)); 22055682Smarkm strlcpy(realm, krb_realmofhost(host), sizeof(realm)); 22155682Smarkm ret = krb_mk_req(adat, sname, inst, realm, checksum); 22255682Smarkm if(ret) 22355682Smarkm return ret; 22455682Smarkm strlcpy(sname, service, sizeof(sname)); 22555682Smarkm strlcpy(inst, krb_get_phost(host), sizeof(inst)); 22655682Smarkm strlcpy(realm, krb_realmofhost(host), sizeof(realm)); 22755682Smarkm ret = krb_get_cred(sname, inst, realm, &cred); 22855682Smarkm memmove(&d->key, &cred.session, sizeof(des_cblock)); 22955682Smarkm des_key_sched(&d->key, d->schedule); 23055682Smarkm memset(&cred, 0, sizeof(cred)); 23155682Smarkm return ret; 23255682Smarkm} 23355682Smarkm 23455682Smarkmstatic int 23555682Smarkmkrb4_auth(void *app_data, char *host) 23655682Smarkm{ 23755682Smarkm int ret; 23855682Smarkm char *p; 23955682Smarkm int len; 24055682Smarkm KTEXT_ST adat; 24155682Smarkm MSG_DAT msg_data; 24255682Smarkm int checksum; 243178825Sdfr uint32_t cs; 24455682Smarkm struct krb4_data *d = app_data; 24555682Smarkm struct sockaddr_in *localaddr = (struct sockaddr_in *)LOCAL_ADDR; 24655682Smarkm struct sockaddr_in *remoteaddr = (struct sockaddr_in *)REMOTE_ADDR; 24755682Smarkm 24855682Smarkm checksum = getpid(); 24955682Smarkm ret = mk_auth(d, &adat, "ftp", host, checksum); 25055682Smarkm if(ret == KDC_PR_UNKNOWN) 25155682Smarkm ret = mk_auth(d, &adat, "rcmd", host, checksum); 25255682Smarkm if(ret){ 25355682Smarkm printf("%s\n", krb_get_err_text(ret)); 25455682Smarkm return AUTH_CONTINUE; 25555682Smarkm } 25655682Smarkm 25755682Smarkm#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM 25855682Smarkm if (krb_get_config_bool("nat_in_use")) { 25955682Smarkm struct in_addr natAddr; 26055682Smarkm 26155682Smarkm if (krb_get_our_ip_for_realm(krb_realmofhost(host), 26255682Smarkm &natAddr) != KSUCCESS 26355682Smarkm && krb_get_our_ip_for_realm(NULL, &natAddr) != KSUCCESS) 26455682Smarkm printf("Can't get address for realm %s\n", 26555682Smarkm krb_realmofhost(host)); 26655682Smarkm else { 26755682Smarkm if (natAddr.s_addr != localaddr->sin_addr.s_addr) { 26855682Smarkm printf("Using NAT IP address (%s) for kerberos 4\n", 26955682Smarkm inet_ntoa(natAddr)); 27055682Smarkm localaddr->sin_addr = natAddr; 27155682Smarkm 27255682Smarkm /* 27355682Smarkm * This not the best place to do this, but it 27455682Smarkm * is here we know that (probably) NAT is in 27555682Smarkm * use! 27655682Smarkm */ 27755682Smarkm 27855682Smarkm passivemode = 1; 27955682Smarkm printf("Setting: Passive mode on.\n"); 28055682Smarkm } 28155682Smarkm } 28255682Smarkm } 28355682Smarkm#endif 28455682Smarkm 28555682Smarkm printf("Local address is %s\n", inet_ntoa(localaddr->sin_addr)); 28655682Smarkm printf("Remote address is %s\n", inet_ntoa(remoteaddr->sin_addr)); 28755682Smarkm 28855682Smarkm if(base64_encode(adat.dat, adat.length, &p) < 0) { 28955682Smarkm printf("Out of memory base64-encoding.\n"); 29055682Smarkm return AUTH_CONTINUE; 29155682Smarkm } 29255682Smarkm ret = command("ADAT %s", p); 29355682Smarkm free(p); 29455682Smarkm 29555682Smarkm if(ret != COMPLETE){ 29655682Smarkm printf("Server didn't accept auth data.\n"); 29755682Smarkm return AUTH_ERROR; 29855682Smarkm } 29955682Smarkm 30055682Smarkm p = strstr(reply_string, "ADAT="); 30155682Smarkm if(!p){ 30255682Smarkm printf("Remote host didn't send adat reply.\n"); 30355682Smarkm return AUTH_ERROR; 30455682Smarkm } 30555682Smarkm p += 5; 30655682Smarkm len = base64_decode(p, adat.dat); 30755682Smarkm if(len < 0){ 30855682Smarkm printf("Failed to decode base64 from server.\n"); 30955682Smarkm return AUTH_ERROR; 31055682Smarkm } 31155682Smarkm adat.length = len; 31255682Smarkm ret = krb_rd_safe(adat.dat, adat.length, &d->key, 31355682Smarkm (struct sockaddr_in *)hisctladdr, 31455682Smarkm (struct sockaddr_in *)myctladdr, &msg_data); 31555682Smarkm if(ret){ 31655682Smarkm printf("Error reading reply from server: %s.\n", 31755682Smarkm krb_get_err_text(ret)); 31855682Smarkm return AUTH_ERROR; 31955682Smarkm } 32055682Smarkm krb_get_int(msg_data.app_data, &cs, 4, 0); 32155682Smarkm if(cs - checksum != 1){ 32255682Smarkm printf("Bad checksum returned from server.\n"); 32355682Smarkm return AUTH_ERROR; 32455682Smarkm } 32555682Smarkm return AUTH_OK; 32655682Smarkm} 32755682Smarkm 32855682Smarkmstruct sec_client_mech krb4_client_mech = { 32955682Smarkm "KERBEROS_V4", 33055682Smarkm sizeof(struct krb4_data), 33172445Sassar krb4_init, /* init */ 33255682Smarkm krb4_auth, 33355682Smarkm NULL, /* end */ 33455682Smarkm krb4_check_prot, 33555682Smarkm krb4_overhead, 33655682Smarkm krb4_encode, 33755682Smarkm krb4_decode 33855682Smarkm}; 33955682Smarkm 34055682Smarkm#endif /* FTP_SERVER */ 341