From 5545ef2efa200b192569d723cdb84bdbe43f8093 Mon Sep 17 00:00:00 2001 From: Johan Danielsson Date: Thu, 26 Mar 1998 03:02:03 +0000 Subject: [PATCH] Updated for the unified security framework. git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@4674 ec53bebd-3082-4978-b11e-865c3cabbd6b --- appl/ftp/ftp/Makefile.in | 26 +- appl/ftp/ftp/krb4.c | 591 ++++++++++----------------------------- 2 files changed, 176 insertions(+), 441 deletions(-) diff --git a/appl/ftp/ftp/Makefile.in b/appl/ftp/ftp/Makefile.in index ec67be30c..15cc5cdd3 100644 --- a/appl/ftp/ftp/Makefile.in +++ b/appl/ftp/ftp/Makefile.in @@ -36,11 +36,29 @@ LIBTOP = $(top_builddir)/lib PROGS = ftp$(EXECSUFFIX) -ftp_OBJS = cmds.o cmdtab.o ftp.o krb4.o main.o ruserpass.o domacro.o \ - globals.o kauth.o +ftp_SOURCES = \ + cmds.c \ + cmdtab.c \ + domacro.c \ + ftp.c \ + globals.c \ + kauth.c + krb4.c \ + main.c \ + ruserpass.c \ + security.c \ -ftp_SOURCES = cmds.c cmdtab.c ftp.c krb4.c main.c ruserpass.c \ - domacro.c globals.c kauth.c +ftp_OBJS = \ + cmds.o \ + cmdtab.o \ + domacro.o \ + ftp.o \ + globals.o \ + kauth.o + krb4.o \ + main.o \ + ruserpass.o \ + security.o \ OBJECTS = $(ftp_OBJS) SOURCES = $(ftp_SOURCES) diff --git a/appl/ftp/ftp/krb4.c b/appl/ftp/ftp/krb4.c index 133435e1c..37b4d11f8 100644 --- a/appl/ftp/ftp/krb4.c +++ b/appl/ftp/ftp/krb4.c @@ -36,357 +36,167 @@ * SUCH DAMAGE. */ +#ifdef FTP_SERVER +#include "ftpd_locl.h" +#else #include "ftp_locl.h" +#endif +#include RCSID("$Id$"); -static KTEXT_ST krb4_adat; +#ifdef FTP_SERVER +#define LOCAL_ADDR ctrl_addr +#define REMOTE_ADDR his_addr +#else +#define LOCAL_ADDR myctladdr +#define REMOTE_ADDR hisctladdr +#endif +extern struct sockaddr_in LOCAL_ADDR, REMOTE_ADDR; -static des_cblock key; -static des_key_schedule schedule; - -static char *data_buffer; - -extern struct sockaddr_in hisctladdr, myctladdr; - -int auth_complete; - -static int command_prot; - -static int auth_pbsz; -static int data_prot; - -static int request_data_prot; - - -static struct { - int level; - char *name; -} level_names[] = { - { prot_clear, "clear" }, - { prot_safe, "safe" }, - { prot_confidential, "confidential" }, - { prot_private, "private" } +struct krb4_data { + des_cblock key; + des_key_schedule schedule; + char name[ANAME_SZ]; + char instance[INST_SZ]; + char realm[REALM_SZ]; }; -static char *level_to_name(int level) -{ - int i; - for(i = 0; i < sizeof(level_names) / sizeof(level_names[0]); i++) - if(level_names[i].level == level) - return level_names[i].name; - return "unknown"; -} - -static int name_to_level(char *name) -{ - int i; - for(i = 0; i < sizeof(level_names) / sizeof(level_names[0]); i++) - if(!strncasecmp(level_names[i].name, name, strlen(name))) - return level_names[i].level; - return -1; -} - -void sec_status(void) -{ - if(auth_complete){ - printf("Using KERBEROS_V4 for authentication.\n"); - - command_prot = prot_private; /* this variable is not used */ - - printf("Using %s command channel.\n", - level_to_name(command_prot)); - - printf("Using %s data channel.\n", - level_to_name(data_prot)); - if(auth_pbsz > 0) - printf("Protection buffer size: %d.\n", auth_pbsz); - }else{ - printf("Not using any security mechanism.\n"); - } -} - static int -sec_prot_internal(int level) +krb4_check_prot(void *app_data, int level) { - int ret; - char *p; - unsigned int s = 1048576; - - int old_verbose = verbose; - verbose = 0; - - if(!auth_complete){ - printf("No security data exchange has taken place.\n"); + if(level == prot_confidential) return -1; - } - - if(level){ - ret = command("PBSZ %u", s); - if(ret != COMPLETE){ - printf("Failed to set protection buffer size.\n"); - return -1; - } - auth_pbsz = s; - p = strstr(reply_string, "PBSZ="); - if(p) - sscanf(p, "PBSZ=%u", &s); - if(s < auth_pbsz) - auth_pbsz = s; - data_buffer = realloc(data_buffer, auth_pbsz); - } - verbose = old_verbose; - ret = command("PROT %c", level["CSEP"]); /* XXX :-) */ - if(ret != COMPLETE){ - printf("Failed to set protection level.\n"); - return -1; - } - - data_prot = level; return 0; } - -void -sec_prot(int argc, char **argv) -{ - int level = -1; - - if(argc != 2){ - printf("usage: %s (clear | safe | confidential | private)\n", - argv[0]); - code = -1; - return; - } - if(!auth_complete){ - printf("No security data exchange has taken place.\n"); - code = -1; - return; - } - level = name_to_level(argv[1]); - - if(level == -1){ - printf("usage: %s (clear | safe | confidential | private)\n", - argv[0]); - code = -1; - return; - } - - if(level == prot_confidential){ - printf("Confidential protection is not defined with Kerberos.\n"); - code = -1; - return; - } - - if(sec_prot_internal(level) < 0){ - code = -1; - return; - } - code = 0; -} - -void -sec_set_protection_level(void) -{ - if(auth_complete && data_prot != request_data_prot) - sec_prot_internal(request_data_prot); -} - - -int -sec_request_prot(char *level) -{ - int l = name_to_level(level); - if(l == -1) - return -1; - request_data_prot = l; - return 0; -} - - -int sec_getc(FILE *F) -{ - if(auth_complete && data_prot) - return krb4_getc(F); - else - return getc(F); -} - -int sec_read(int fd, void *data, int length) -{ - if(auth_complete && data_prot) - return krb4_read(fd, data, length); - else - return read(fd, data, length); -} - static int -krb4_recv(int fd) +krb4_decode(void *app_data, void *buf, int len, int level) { - int len; MSG_DAT m; - int kerror; + int e; + struct krb4_data *d = app_data; - krb_net_read(fd, &len, sizeof(len)); - len = ntohl(len); - krb_net_read(fd, data_buffer, len); - if(data_prot == prot_safe) - kerror = krb_rd_safe(data_buffer, len, &key, - &hisctladdr, &myctladdr, &m); + if(level == prot_safe) + e = krb_rd_safe(buf, len, &d->key, &REMOTE_ADDR, &LOCAL_ADDR, &m); else - kerror = krb_rd_priv(data_buffer, len, schedule, &key, - &hisctladdr, &myctladdr, &m); - if(kerror){ + e = krb_rd_priv(buf, len, d->schedule, &d->key, + &REMOTE_ADDR, &LOCAL_ADDR, &m); + if(e){ return -1; } - memmove(data_buffer, m.app_data, m.app_length); + memmove(buf, m.app_data, m.app_length); return m.app_length; } - -int krb4_getc(FILE *F) +static int +krb4_overhead(void *app_data, int level, int len) { - static int bytes; - static int index; - if(bytes == 0){ - bytes = krb4_recv(fileno(F)); - index = 0; - } - if(bytes){ - bytes--; - return (unsigned char)data_buffer[index++]; - } - return EOF; + return 31; } -int krb4_read(int fd, char *data, int length) +static int +krb4_encode(void *app_data, void *from, int length, int level, void **to) { - static int left; - static int index; - static int eof; - int len = left; - int rx = 0; + struct krb4_data *d = app_data; + *to = malloc(length + 31); + if(level == prot_safe) + return krb_mk_safe(from, *to, length, &d->key, + &LOCAL_ADDR, &REMOTE_ADDR); + else if(level == prot_private) + return krb_mk_priv(from, *to, length, d->schedule, &d->key, + &LOCAL_ADDR, &REMOTE_ADDR); + else + abort(); +} - if(eof){ - eof = 0; - return 0; +#ifdef FTP_SERVER + +static int +krb4_adat(void *app_data, void *buf, size_t len) +{ + KTEXT_ST tkt; + AUTH_DAT auth_dat; + char *p; + int kerror; + u_int32_t cs; + char msg[35]; /* size of encrypted block */ + + struct krb4_data *d = app_data; + + char inst[INST_SZ]; + + memcpy(tkt.dat, buf, len); + tkt.length = len; + + k_getsockinst(0, inst, sizeof(inst)); + kerror = krb_rd_req(&tkt, "ftp", inst, 0, &auth_dat, ""); + if(kerror == RD_AP_UNDEC){ + k_getsockinst(0, inst, sizeof(inst)); + kerror = krb_rd_req(&tkt, "rcmd", inst, 0, &auth_dat, ""); + } + + if(kerror){ + reply(535, "Error reading request: %s.", krb_get_err_text(kerror)); + return -1; } - if(left){ - if(length < len) - len = length; - memmove(data, data_buffer + index, len); - length -= len; - index += len; - rx += len; - left -= len; + memcpy(d->key, auth_dat.session, sizeof(d->key)); + des_set_key(&d->key, d->schedule); + + strcpy(d->name, auth_dat.pname); + strcpy(d->instance, auth_dat.pinst); + strcpy(d->realm, auth_dat.prealm); + + cs = auth_dat.checksum + 1; + { + unsigned char tmp[4]; + krb_put_int(cs, tmp, 4); + len = krb_mk_safe(tmp, msg, 4, &d->key, &LOCAL_ADDR, &REMOTE_ADDR); } - - while(length){ - len = krb4_recv(fd); - if(len == 0){ - if(rx) - eof = 1; - return rx; - } - if(len > length){ - left = len - length; - len = index = length; - } - memmove(data, data_buffer, len); - length -= len; - data += len; - rx += len; + if(len < 0){ + reply(535, "Error creating reply: %s.", strerror(errno)); + return -1; } - return rx; -} - - -static int -krb4_encode(char *from, char *to, int length) -{ - if(data_prot == prot_safe) - return krb_mk_safe(from, to, length, &key, - &myctladdr, &hisctladdr); - else - return krb_mk_priv(from, to, length, schedule, &key, - &myctladdr, &hisctladdr); -} - -static int -krb4_overhead(int len) -{ - if(data_prot == prot_safe) - return 31; - else - return 26; -} - -static char p_buf[1024]; -static int p_index; - -int -sec_putc(int c, FILE *F) -{ - if(data_prot){ - if((c == '\n' && p_index) || p_index == sizeof(p_buf)){ - sec_write(fileno(F), p_buf, p_index); - p_index = 0; - } - p_buf[p_index++] = c; - return c; + if(base64_encode(msg, len, &p) < 0) { + reply(535, "Out of memory base64-encoding."); + return -1; } - return putc(c, F); -} - -static int -sec_send(int fd, char *from, int length) -{ - int bytes; - bytes = krb4_encode(from, data_buffer, length); - bytes = htonl(bytes); - krb_net_write(fd, &bytes, sizeof(bytes)); - krb_net_write(fd, data_buffer, ntohl(bytes)); - return length; -} - -int -sec_fflush(FILE *F) -{ - if(data_prot){ - if(p_index){ - sec_write(fileno(F), p_buf, p_index); - p_index = 0; - } - sec_send(fileno(F), NULL, 0); - } - fflush(F); + reply(235, "ADAT=%s", p); + sec_complete = 1; + free(p); return 0; } -int -sec_write(int fd, char *data, int length) +static int +krb4_userok(void *app_data, char *user) { - int len = auth_pbsz; - int tx = 0; - - if(data_prot == prot_clear) - return write(fd, data, length); - - len -= krb4_overhead(len); - while(length){ - if(length < len) - len = length; - sec_send(fd, data, len); - length -= len; - data += len; - tx += len; - } - return tx; + struct krb4_data *d = app_data; + return krb_kuserok(d->name, d->instance, d->realm, user); } +struct sec_server_mech krb4_server_mech = { + "KERBEROS_V4", + sizeof(struct krb4_data), + NULL, /* init */ + NULL, /* end */ + krb4_check_prot, + krb4_overhead, + krb4_encode, + krb4_decode, + /* */ + NULL, + krb4_adat, + NULL, /* pbsz */ + NULL, /* ccc */ + krb4_userok +}; + +#else /* FTP_SERVER */ + static int -do_auth(char *service, char *host, int checksum) +mk_auth(struct krb4_data *d, KTEXT adat, + char *service, char *host, int checksum) { int ret; CREDENTIALS cred; @@ -394,60 +204,41 @@ do_auth(char *service, char *host, int checksum) strcpy(sname, service); strcpy(inst, krb_get_phost(host)); strcpy(realm, krb_realmofhost(host)); - ret = krb_mk_req(&krb4_adat, sname, inst, realm, checksum); + ret = krb_mk_req(adat, sname, inst, realm, checksum); if(ret) return ret; strcpy(sname, service); strcpy(inst, krb_get_phost(host)); strcpy(realm, krb_realmofhost(host)); ret = krb_get_cred(sname, inst, realm, &cred); - memmove(&key, &cred.session, sizeof(des_cblock)); - des_key_sched(&key, schedule); + memmove(&d->key, &cred.session, sizeof(des_cblock)); + des_key_sched(&d->key, d->schedule); memset(&cred, 0, sizeof(cred)); return ret; } - -int -do_klogin(char *host) +static int +krb4_auth(void *app_data, char *host) { int ret; char *p; int len; - char adat[1024]; + KTEXT_ST adat; MSG_DAT msg_data; - int checksum; + int checksum, cs; + struct krb4_data *d = app_data; - int old_verbose = verbose; - - verbose = 0; - printf("Trying KERBEROS_V4...\n"); - ret = command("AUTH KERBEROS_V4"); - if(ret != CONTINUE){ - if(code == 504){ - printf("Kerberos 4 is not supported by the server.\n"); - }else if(code == 534){ - printf("KERBEROS_V4 rejected as security mechanism.\n"); - }else if(ret == ERROR) - printf("The server doesn't understand the FTP " - "security extensions.\n"); - verbose = old_verbose; + checksum = getpid(); + ret = mk_auth(d, &adat, "ftp", host, checksum); + if(ret == KDC_PR_UNKNOWN) + ret = mk_auth(d, &adat, "rcmd", host, checksum); + if(ret){ + printf("%s\n", krb_get_err_text(ret)); return -1; } - checksum = getpid(); - ret = do_auth("ftp", host, checksum); - if(ret == KDC_PR_UNKNOWN) - ret = do_auth("rcmd", host, checksum); - if(ret){ - printf("%s\n", krb_get_err_text(ret)); - verbose = old_verbose; - return ret; - } - - if(base64_encode(krb4_adat.dat, krb4_adat.length, &p) < 0) { + if(base64_encode(adat.dat, adat.length, &p) < 0) { printf("Out of memory base64-encoding.\n"); - verbose = old_verbose; return -1; } ret = command("ADAT %s", p); @@ -455,119 +246,45 @@ do_klogin(char *host) if(ret != COMPLETE){ printf("Server didn't accept auth data.\n"); - verbose = old_verbose; return -1; } p = strstr(reply_string, "ADAT="); if(!p){ printf("Remote host didn't send adat reply.\n"); - verbose = old_verbose; return -1; } p+=5; - len = base64_decode(p, adat); + adat.length = base64_decode(p, adat.dat); if(len < 0){ printf("Failed to decode base64 from server.\n"); - verbose = old_verbose; return -1; } - ret = krb_rd_safe(adat, len, &key, + ret = krb_rd_safe(adat.dat, adat.length, &d->key, &hisctladdr, &myctladdr, &msg_data); if(ret){ printf("Error reading reply from server: %s.\n", krb_get_err_text(ret)); - verbose = old_verbose; return -1; } - { - /* the draft doesn't tell what size the return has */ - int i; - u_int32_t cs = 0; - for(i = 0; i < msg_data.app_length; i++) - cs = (cs<<8) + msg_data.app_data[i]; - if(cs - checksum != 1){ - printf("Bad checksum returned from server.\n"); - verbose = old_verbose; - return -1; - } + krb_get_int(msg_data.app_data, &cs, 4, 0); + if(cs - checksum != 1){ + printf("Bad checksum returned from server.\n"); + return -1; } - auth_complete = 1; - verbose = old_verbose; return 0; } -void -krb4_quit(void) -{ - auth_complete = 0; - data_prot = 0; -} - -int -krb4_write_enc(FILE *F, char *fmt, va_list ap) -{ - int len; - char *p; - char buf[1024]; - char enc[1024]; - - vsnprintf(buf, sizeof(buf), fmt, ap); - len = krb_mk_priv(buf, enc, strlen(buf), schedule, &key, - &myctladdr, &hisctladdr); - if(base64_encode(enc, len, &p) < 0) { - return -1; - } - - fprintf(F, "ENC %s", p); - free (p); - return 0; -} - - -int krb4_read_msg(char *s, int priv) -{ - int len; - int ret; - char buf[1024]; - MSG_DAT m; - int code; - - len = base64_decode(s + 4, buf); - if(priv) - ret = krb_rd_priv(buf, len, schedule, &key, - &hisctladdr, &myctladdr, &m); - else - ret = krb_rd_safe(buf, len, &key, &hisctladdr, &myctladdr, &m); - if(ret){ - printf("%s\n", krb_get_err_text(ret)); - return -1; - } - - m.app_data[m.app_length] = 0; - if(m.app_data[3] == '-') - code = 0; - else - sscanf((char*)m.app_data, "%d", &code); - strncpy(s, (char*)m.app_data, strlen((char*)m.app_data)); - - s[m.app_length] = 0; - len = strlen(s); - if(s[len-1] == '\n') - s[len-1] = 0; - - return code; -} - -int -krb4_read_mic(char *s) -{ - return krb4_read_msg(s, 0); -} - -int -krb4_read_enc(char *s) -{ - return krb4_read_msg(s, 1); -} +struct sec_client_mech krb4_client_mech = { + "KERBEROS_V4", + sizeof(struct krb4_data), + NULL, /* init */ + krb4_auth, + NULL, /* end */ + krb4_check_prot, + krb4_overhead, + krb4_encode, + krb4_decode +}; +#endif /* FTP_SERVER */