Encryption of data stream. Cleanup.
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@391 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
@@ -20,7 +20,7 @@ libdir = $(exec_prefix)/lib
|
||||
|
||||
ATHENA = /usr/athena
|
||||
|
||||
ftp_OBJS = cmds.o cmdtab.o ftp.o main.o ruserpass.o domacro.o globals.o
|
||||
ftp_OBJS = cmds.o cmdtab.o ftp.o krb4.o main.o ruserpass.o domacro.o globals.o kauth.o
|
||||
|
||||
all: ftp
|
||||
|
||||
|
@@ -106,6 +106,9 @@ char umaskhelp[] = "get (set) umask on remote side";
|
||||
char userhelp[] = "send new user information";
|
||||
char verbosehelp[] = "toggle verbose mode";
|
||||
|
||||
char prothelp[] = "set protection level";
|
||||
char kauthhelp[] = "get remote tokens";
|
||||
|
||||
struct cmd cmdtab[] = {
|
||||
{ "!", shellhelp, 0, 0, 0, shell },
|
||||
{ "$", domachelp, 1, 0, 0, domacro },
|
||||
@@ -179,6 +182,10 @@ struct cmd cmdtab[] = {
|
||||
{ "umask", umaskhelp, 0, 1, 1, do_umask },
|
||||
{ "verbose", verbosehelp, 0, 0, 0, setverbose },
|
||||
{ "?", helphelp, 0, 0, 1, help },
|
||||
|
||||
{ "prot", prothelp, 0, 1, 0, sec_prot },
|
||||
{ "kauth", kauthhelp, 0, 1, 0, kauth },
|
||||
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
|
@@ -165,3 +165,5 @@ extern int proxy;
|
||||
extern char reply_string[];
|
||||
extern off_t restart_point;
|
||||
extern int NCMDS;
|
||||
|
||||
extern char username[32];
|
||||
|
@@ -35,8 +35,6 @@
|
||||
|
||||
#include "ftp_locl.h"
|
||||
|
||||
|
||||
|
||||
struct sockaddr_in hisctladdr;
|
||||
struct sockaddr_in data_addr;
|
||||
int data = -1;
|
||||
@@ -159,77 +157,6 @@ bad:
|
||||
return ((char *)0);
|
||||
}
|
||||
|
||||
#include <des.h>
|
||||
#include <krb.h>
|
||||
|
||||
int krb4_auth = 0;
|
||||
KTEXT_ST krb4_adat;
|
||||
|
||||
static des_cblock key;
|
||||
static des_key_schedule schedule;
|
||||
|
||||
int do_auth(char *service, char *host)
|
||||
{
|
||||
int ret;
|
||||
CREDENTIALS cred;
|
||||
char sname[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ];
|
||||
strcpy(sname, service);
|
||||
strcpy(inst, krb_get_phost(host));
|
||||
strcpy(realm, krb_realmofhost(host));
|
||||
ret = krb_mk_req(&krb4_adat, sname, inst, realm, 0);
|
||||
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);
|
||||
memset(&cred, 0, sizeof(cred));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int do_klogin(char *host)
|
||||
{
|
||||
int ret;
|
||||
char *phost;
|
||||
char *p, *q;
|
||||
int len;
|
||||
char *serv = "ftp";
|
||||
char adat[1024];
|
||||
MSG_DAT msg_data;
|
||||
int checksum;
|
||||
|
||||
ret = command("AUTH KERBEROS_V4");
|
||||
if(ret == CONTINUE){
|
||||
ret = do_auth("ftp", host);
|
||||
if(ret == KDC_PR_UNKNOWN)
|
||||
ret = do_auth("rcmd", host);
|
||||
if(ret)
|
||||
return ret;
|
||||
base64_encode(krb4_adat.dat, krb4_adat.length, &p);
|
||||
ret = command("ADAT %s", p);
|
||||
free(p);
|
||||
if(ret == COMPLETE){
|
||||
p = strstr(reply_string, "ADAT=");
|
||||
if(p){
|
||||
p+=5;
|
||||
for(q = p; isalnum(*q) || strchr("/+=", *q); q++);
|
||||
*q = 0;
|
||||
len = base64_decode(p, adat);
|
||||
ret = krb_rd_safe(adat, len, &key,
|
||||
&hisctladdr, &myctladdr, &msg_data);
|
||||
memmove(&checksum, msg_data.app_data, 4);
|
||||
checksum = ntohl(checksum);
|
||||
}
|
||||
krb4_auth = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
login(char *host)
|
||||
{
|
||||
@@ -263,11 +190,15 @@ login(char *host)
|
||||
user = tmp;
|
||||
}
|
||||
if(strcmp(user, "ftp") && strcmp(user, "anonymous")){
|
||||
do_klogin(host);
|
||||
if(do_klogin(host) < 0)
|
||||
fprintf(stderr, "Resorting to plaintext user and password.\n");
|
||||
}
|
||||
strcpy(username, user);
|
||||
n = command("USER %s", user);
|
||||
if (n == CONTINUE) {
|
||||
if (pass == NULL)
|
||||
if(auth_complete)
|
||||
pass = user;
|
||||
else if (pass == NULL)
|
||||
pass = getpass("Password:");
|
||||
n = command("PASS %s", pass);
|
||||
}
|
||||
@@ -306,69 +237,6 @@ cmdabort(int sig)
|
||||
longjmp(ptabort,1);
|
||||
}
|
||||
|
||||
int krb4_write_enc(FILE *F, char *fmt, va_list ap)
|
||||
{
|
||||
int len;
|
||||
char *p;
|
||||
char buf[1024];
|
||||
char enc[1024];
|
||||
vsprintf(buf, fmt, ap);
|
||||
len = krb_mk_priv(buf, enc, strlen(buf), schedule, &key,
|
||||
&myctladdr, &hisctladdr);
|
||||
base64_encode(enc, len, &p);
|
||||
|
||||
fprintf(F, "ENC %s", 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, &myctladdr, &hisctladdr, &m);
|
||||
if(ret){
|
||||
fprintf(stderr, "%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);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
command(char *fmt, ...)
|
||||
{
|
||||
@@ -391,7 +259,7 @@ command(char *fmt, ...)
|
||||
printf("PASS XXXX");
|
||||
else
|
||||
vfprintf(stdout, fmt, ap);
|
||||
if(krb4_auth)
|
||||
if(auth_complete)
|
||||
krb4_write_enc(cout, fmt, ap);
|
||||
else
|
||||
vfprintf(cout, fmt, ap);
|
||||
@@ -464,8 +332,8 @@ getreply(int expecteof)
|
||||
sscanf(buf, "%d", &code);
|
||||
fprintf(stdout, "P:");
|
||||
}else if(code == 633){
|
||||
fprintf(stdout, "Confidentiality is meaningless:/n");
|
||||
}else if(krb4_auth)
|
||||
fprintf(stdout, "Confidentiality is meaningless:\n");
|
||||
}else if(auth_complete)
|
||||
fprintf(stdout, "!!"); /* clear text */
|
||||
fprintf(stdout, "%s\n", buf);
|
||||
if(buf[3] == ' '){
|
||||
@@ -484,7 +352,7 @@ getreply(int expecteof)
|
||||
return code / 100;
|
||||
}
|
||||
}else{
|
||||
if(krb4_auth)
|
||||
if(auth_complete)
|
||||
fprintf(stdout, "!!");
|
||||
fprintf(stdout, "%s\n", buf);
|
||||
}
|
||||
@@ -589,7 +457,7 @@ getreply(int expecteof)
|
||||
continue;
|
||||
}
|
||||
*cp = '\0';
|
||||
if(krb4_auth){
|
||||
if(auth_complete){
|
||||
if(code == 631)
|
||||
krb4_read_mic(reply_string);
|
||||
else
|
||||
@@ -784,7 +652,7 @@ sendrequest(char *cmd, char *local, char *remote, int printnames)
|
||||
while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
|
||||
bytes += c;
|
||||
for (bufp = buf; c > 0; c -= d, bufp += d)
|
||||
if ((d = write(fileno(dout), bufp, c)) <= 0)
|
||||
if ((d = sec_write(fileno(dout), bufp, c)) <= 0)
|
||||
break;
|
||||
if (hash) {
|
||||
while (bytes >= hashbytes) {
|
||||
@@ -794,6 +662,7 @@ sendrequest(char *cmd, char *local, char *remote, int printnames)
|
||||
(void) fflush(stdout);
|
||||
}
|
||||
}
|
||||
sec_fflush(dout);
|
||||
if (hash && bytes > 0) {
|
||||
if (bytes < HASHBYTES)
|
||||
(void) putchar('#');
|
||||
@@ -819,16 +688,13 @@ sendrequest(char *cmd, char *local, char *remote, int printnames)
|
||||
}
|
||||
if (ferror(dout))
|
||||
break;
|
||||
(void) putc('\r', dout);
|
||||
(void) sec_putc('\r', dout);
|
||||
bytes++;
|
||||
}
|
||||
(void) putc(c, dout);
|
||||
sec_putc(c, dout);
|
||||
bytes++;
|
||||
/* if (c == '\r') { */
|
||||
/* (void) putc('\0', dout); // this violates rfc */
|
||||
/* bytes++; */
|
||||
/* } */
|
||||
}
|
||||
sec_fflush(dout);
|
||||
if (hash) {
|
||||
if (bytes < hashbytes)
|
||||
(void) putchar('#');
|
||||
@@ -1048,7 +914,7 @@ recvrequest(char *cmd, char *local, char *remote, char *lmode, int printnames)
|
||||
return;
|
||||
}
|
||||
errno = d = 0;
|
||||
while ((c = read(fileno(din), buf, bufsize)) > 0) {
|
||||
while ((c = sec_read(fileno(din), buf, bufsize)) > 0) {
|
||||
if ((d = write(fileno(fout), buf, c)) != c)
|
||||
break;
|
||||
bytes += c;
|
||||
@@ -1087,7 +953,7 @@ recvrequest(char *cmd, char *local, char *remote, char *lmode, int printnames)
|
||||
goto done;
|
||||
n = restart_point;
|
||||
for (i = 0; i++ < n;) {
|
||||
if ((ch = getc(fout)) == EOF)
|
||||
if ((ch = sec_getc(fout)) == EOF)
|
||||
goto done;
|
||||
if (ch == '\n')
|
||||
i++;
|
||||
@@ -1100,7 +966,8 @@ done:
|
||||
return;
|
||||
}
|
||||
}
|
||||
while ((c = getc(din)) != EOF) {
|
||||
|
||||
while ((c = sec_getc(din)) != EOF) {
|
||||
if (c == '\n')
|
||||
bare_lfs++;
|
||||
while (c == '\r') {
|
||||
@@ -1110,7 +977,7 @@ done:
|
||||
hashbytes += HASHBYTES;
|
||||
}
|
||||
bytes++;
|
||||
if ((c = getc(din)) != '\n' || tcrflag) {
|
||||
if ((c = sec_getc(din)) != '\n' || tcrflag) {
|
||||
if (ferror(fout))
|
||||
goto break2;
|
||||
(void) putc('\r', fout);
|
||||
|
@@ -26,12 +26,15 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "extern.h"
|
||||
#include "common.h"
|
||||
#include "ftp_var.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
#include "krb4.h"
|
||||
|
||||
#if defined(__sun__) && !defined(__svr4)
|
||||
int fclose(FILE*);
|
||||
int pclose(FILE*);
|
||||
|
@@ -127,3 +127,5 @@ struct macel {
|
||||
extern int macnum; /* number of defined macros */
|
||||
extern struct macel macros[16];
|
||||
extern char macbuf[4096];
|
||||
|
||||
|
||||
|
@@ -69,3 +69,5 @@ int options; /* used during socket creation */
|
||||
int macnum; /* number of defined macros */
|
||||
struct macel macros[16];
|
||||
char macbuf[4096];
|
||||
|
||||
char username[32];
|
||||
|
75
appl/ftp/ftp/kauth.c
Normal file
75
appl/ftp/ftp/kauth.c
Normal file
@@ -0,0 +1,75 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "ftp_locl.h"
|
||||
#include <krb.h>
|
||||
|
||||
void kauth(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
char buf[1024];
|
||||
des_cblock key;
|
||||
des_key_schedule schedule;
|
||||
KTEXT_ST tkt;
|
||||
char *name;
|
||||
char *p;
|
||||
|
||||
|
||||
if(argc > 2){
|
||||
printf("usage: %s [principal]\n", argv[0]);
|
||||
code = -1;
|
||||
return;
|
||||
}
|
||||
if(argc == 2)
|
||||
name = argv[1];
|
||||
else
|
||||
name = username;
|
||||
ret = command("SITE KAUTH %s", name);
|
||||
if(ret != CONTINUE){
|
||||
code = -1;
|
||||
return;
|
||||
}
|
||||
p = strstr(reply_string, "T=");
|
||||
if(!p){
|
||||
printf("Bad reply from server.\n");
|
||||
code = -1;
|
||||
return;
|
||||
}
|
||||
p += 2;
|
||||
tkt.length = base64_decode(p, &tkt.dat);
|
||||
if(tkt.length < 0){
|
||||
printf("Failed to decode base64 in reply.\n");
|
||||
code = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
p = strstr(reply_string, "P=");
|
||||
if(!p){
|
||||
printf("Bad reply from server.\n");
|
||||
code = -1;
|
||||
return;
|
||||
}
|
||||
name = p + 2;
|
||||
for(; *p && *p != ' ' && *p != '\r' && *p != '\n'; p++);
|
||||
*p = 0;
|
||||
|
||||
|
||||
sprintf(buf, "Password for %s:", name);
|
||||
des_read_password(&key, buf, 0);
|
||||
|
||||
des_set_key(&key, schedule);
|
||||
|
||||
des_pcbc_encrypt((des_cblock*)tkt.dat, (des_cblock*)tkt.dat, tkt.length,
|
||||
schedule, &key, DES_DECRYPT);
|
||||
memset(key, 0, sizeof(key));
|
||||
memset(schedule, 0, sizeof(schedule));
|
||||
base64_encode(tkt.dat, tkt.length, &p);
|
||||
ret = command("SITE KAUTH %s %s", name, p);
|
||||
free(p);
|
||||
if(ret != COMPLETE){
|
||||
code = -1;
|
||||
return;
|
||||
}
|
||||
code = 0;
|
||||
}
|
421
appl/ftp/ftp/krb4.c
Normal file
421
appl/ftp/ftp/krb4.c
Normal file
@@ -0,0 +1,421 @@
|
||||
|
||||
#include "ftp_locl.h"
|
||||
|
||||
#include <des.h>
|
||||
#include <krb.h>
|
||||
|
||||
KTEXT_ST krb4_adat;
|
||||
|
||||
static des_cblock key;
|
||||
static des_key_schedule schedule;
|
||||
|
||||
static char *data_buffer;
|
||||
|
||||
enum { prot_clear, prot_safe, prot_confidential, prot_private };
|
||||
|
||||
extern struct sockaddr_in hisctladdr, myctladdr;
|
||||
|
||||
int auth_complete;
|
||||
|
||||
static int command_prot;
|
||||
|
||||
static int auth_pbsz;
|
||||
static int data_prot;
|
||||
|
||||
void sec_prot(int argc, char **argv)
|
||||
{
|
||||
int s;
|
||||
int ret;
|
||||
char *p;
|
||||
int level = -1;
|
||||
if(argc != 2){
|
||||
fprintf(stderr, "foo?\n");
|
||||
code = -1;
|
||||
return;
|
||||
}
|
||||
if(!auth_complete){
|
||||
fprintf(stderr, "ehu?\n");
|
||||
code = -1;
|
||||
return;
|
||||
}
|
||||
if(!strcmp(argv[1], "clear"))
|
||||
level = prot_clear;
|
||||
|
||||
if(!strcmp(argv[1], "safe"))
|
||||
level = prot_safe;
|
||||
|
||||
if(!strcmp(argv[1], "private"))
|
||||
level = prot_private;
|
||||
|
||||
if(level == -1){
|
||||
fprintf(stderr, "ehu?\n");
|
||||
code = -1;
|
||||
return;
|
||||
}
|
||||
if(level){
|
||||
s = 65536;
|
||||
ret = command("PBSZ %d", s);
|
||||
if(ret != COMPLETE){
|
||||
fprintf(stderr, "Ehu?\n");
|
||||
code = -1;
|
||||
return;
|
||||
}
|
||||
auth_pbsz = s;
|
||||
p = strstr(reply_string, "PBSZ=");
|
||||
if(p)
|
||||
sscanf(p, "PBSZ=%d", &s);
|
||||
if(s < auth_pbsz)
|
||||
auth_pbsz = s;
|
||||
if(data_buffer)
|
||||
free(data_buffer);
|
||||
data_buffer = malloc(auth_pbsz);
|
||||
}
|
||||
|
||||
ret = command("PROT %c", level["CSEP"]); /* XXX :-) */
|
||||
if(ret != COMPLETE){
|
||||
fprintf(stderr, "Ehu?\n");
|
||||
code = -1;
|
||||
return;
|
||||
}
|
||||
data_prot = level;
|
||||
code = 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)
|
||||
{
|
||||
int len;
|
||||
MSG_DAT m;
|
||||
int kerror;
|
||||
|
||||
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);
|
||||
else
|
||||
kerror = krb_rd_priv(data_buffer, len, schedule, &key,
|
||||
&hisctladdr, &myctladdr, &m);
|
||||
if(kerror){
|
||||
return -1;
|
||||
}
|
||||
memmove(data_buffer, m.app_data, m.app_length);
|
||||
return m.app_length;
|
||||
}
|
||||
|
||||
|
||||
int krb4_getc(FILE *F)
|
||||
{
|
||||
static int bytes;
|
||||
static int index;
|
||||
if(bytes == 0){
|
||||
bytes = krb4_recv(fileno(F));
|
||||
index = 0;
|
||||
}
|
||||
if(bytes){
|
||||
bytes--;
|
||||
return data_buffer[index++];
|
||||
}
|
||||
return EOF;
|
||||
}
|
||||
|
||||
int krb4_read(int fd, char *data, int length)
|
||||
{
|
||||
static int left;
|
||||
static int index;
|
||||
static int eof;
|
||||
int len = left;
|
||||
int rx = 0;
|
||||
|
||||
if(eof){
|
||||
eof = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(left){
|
||||
if(length < len)
|
||||
len = length;
|
||||
memmove(data, data_buffer + index, len);
|
||||
length -= len;
|
||||
index += len;
|
||||
rx += len;
|
||||
left -= len;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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(index){
|
||||
sec_write(fileno(F), p_buf, p_index);
|
||||
p_index = 0;
|
||||
}
|
||||
sec_send(fileno(F), NULL, 0);
|
||||
}
|
||||
fflush(F);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sec_write(int fd, char *data, int length)
|
||||
{
|
||||
int len = auth_pbsz;
|
||||
int tx = 0;
|
||||
int bytes;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int
|
||||
do_auth(char *service, char *host, int checksum)
|
||||
{
|
||||
int ret;
|
||||
CREDENTIALS cred;
|
||||
char sname[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ];
|
||||
strcpy(sname, service);
|
||||
strcpy(inst, krb_get_phost(host));
|
||||
strcpy(realm, krb_realmofhost(host));
|
||||
ret = krb_mk_req(&krb4_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);
|
||||
memset(&cred, 0, sizeof(cred));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
do_klogin(char *host)
|
||||
{
|
||||
int ret;
|
||||
char *phost;
|
||||
char *p, *q;
|
||||
int len;
|
||||
char adat[1024];
|
||||
MSG_DAT msg_data;
|
||||
int checksum;
|
||||
int tmp;
|
||||
|
||||
ret = command("AUTH KERBEROS_V4");
|
||||
if(ret != CONTINUE){
|
||||
if(code == 504){
|
||||
fprintf(stderr, "Kerberos is not supported by the server.\n");
|
||||
}else if(code == 534){
|
||||
fprintf(stderr, "KERBEROS_V4 rejected as security mechanism.\n");
|
||||
}else if(ret == ERROR)
|
||||
fprintf(stderr, "The server doesn't understand the FTP "
|
||||
"security extentions.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
checksum = getpid();
|
||||
ret = do_auth("ftp", host, checksum);
|
||||
if(ret == KDC_PR_UNKNOWN)
|
||||
ret = do_auth("rcmd", host, checksum);
|
||||
if(ret){
|
||||
fprintf(stderr, "%s\n", krb_get_err_text(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
base64_encode(krb4_adat.dat, krb4_adat.length, &p);
|
||||
ret = command("ADAT %s", p);
|
||||
free(p);
|
||||
|
||||
if(ret != COMPLETE){
|
||||
fprintf(stderr, "Server didn't accept auth data.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = strstr(reply_string, "ADAT=");
|
||||
if(!p){
|
||||
fprintf(stderr, "Remote host didn't send adat reply.");
|
||||
return -1;
|
||||
}
|
||||
p+=5;
|
||||
len = base64_decode(p, adat);
|
||||
if(len < 0){
|
||||
fprintf(stderr, "Failed to decode base64 from server.");
|
||||
return -1;
|
||||
}
|
||||
ret = krb_rd_safe(adat, len, &key,
|
||||
&hisctladdr, &myctladdr, &msg_data);
|
||||
if(ret){
|
||||
fprintf(stderr, "Error reading reply from server: %s.",
|
||||
krb_get_err_text(ret));
|
||||
return -1;
|
||||
}
|
||||
memmove(&tmp, msg_data.app_data, 4);
|
||||
tmp = ntohl(tmp);
|
||||
if(tmp - checksum != 1){
|
||||
fprintf(stderr, "Bad checksum returned from server.");
|
||||
return -1;
|
||||
}
|
||||
auth_complete = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int krb4_write_enc(FILE *F, char *fmt, va_list ap)
|
||||
{
|
||||
int len;
|
||||
char *p;
|
||||
char buf[1024];
|
||||
char enc[1024];
|
||||
vsprintf(buf, fmt, ap);
|
||||
len = krb_mk_priv(buf, enc, strlen(buf), schedule, &key,
|
||||
&myctladdr, &hisctladdr);
|
||||
base64_encode(enc, len, &p);
|
||||
|
||||
fprintf(F, "ENC %s", 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, &myctladdr, &hisctladdr, &m);
|
||||
if(ret){
|
||||
fprintf(stderr, "%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);
|
||||
}
|
||||
|
10
appl/ftp/ftp/krb4.h
Normal file
10
appl/ftp/ftp/krb4.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef __KRB4_H__
|
||||
#define __KRB4_H__
|
||||
|
||||
extern int auth_complete;
|
||||
|
||||
void sec_prot(int, char**);
|
||||
|
||||
void kauth(int, char **);
|
||||
|
||||
#endif /* __KRB4_H__ */
|
@@ -38,7 +38,7 @@
|
||||
#include "ftp_locl.h"
|
||||
|
||||
#ifndef HAVE___PROGNAME
|
||||
char *__progname;
|
||||
char *__progname = "ftp";
|
||||
#endif
|
||||
|
||||
int
|
||||
@@ -55,10 +55,6 @@ main(int argc, char **argv)
|
||||
interactive = 1;
|
||||
autologin = 1;
|
||||
|
||||
#ifndef HAVE___PROGNAME
|
||||
__progname = argv[0];
|
||||
#endif
|
||||
|
||||
while ((ch = getopt(argc, argv, "dgintv")) != EOF) {
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
|
@@ -19,18 +19,18 @@ libdir = $(exec_prefix)/lib
|
||||
|
||||
ATHENA = /usr/athena
|
||||
|
||||
ftpd_OBJS = ftpd.o ftpcmd.o logwtmp.o popen.o auth.o krb4.o
|
||||
ftpd_OBJS = ftpd.o ftpcmd.o logwtmp.o popen.o auth.o krb4.o kauth.o
|
||||
|
||||
all: ftpd
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) -I.. -I$(srcdir)/.. -I../common -I$(srcdir)/../common -I$(ATHENA)/include $(DEFS) $<
|
||||
$(CC) -c $(CFLAGS) -I. -I$(srcdir) -I.. -I$(srcdir)/.. -I../common -I$(srcdir)/../common -I$(ATHENA)/include $(DEFS) $<
|
||||
|
||||
install:
|
||||
|
||||
|
||||
ftpd: $(ftpd_OBJS) ../common/libcommon.a
|
||||
$(CC) -o ftpd $(ftpd_OBJS) ../common/libcommon.a -L$(ATHENA)/lib -lkrb -ldes
|
||||
$(CC) -o ftpd $(ftpd_OBJS) ../common/libcommon.a -L$(ATHENA)/lib -lkafs -lkrb -ldes
|
||||
|
||||
ftpcmd.c: ftpcmd.y
|
||||
$(YACC) $(YFLAGS) $<
|
||||
|
@@ -13,7 +13,8 @@
|
||||
|
||||
static struct at auth_types [] = {
|
||||
{ "KERBEROS_V4", krb4_auth, krb4_adat, krb4_pbsz, krb4_prot, krb4_ccc,
|
||||
krb4_mic, krb4_conf, krb4_enc, krb4_userok, krb4_vprintf },
|
||||
krb4_mic, krb4_conf, krb4_enc, krb4_read, krb4_write, krb4_userok,
|
||||
krb4_vprintf },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -21,9 +22,16 @@ struct at *ct;
|
||||
|
||||
int data_protection;
|
||||
int buffer_size;
|
||||
unsigned char *data_buffer;
|
||||
int auth_complete;
|
||||
|
||||
|
||||
char *protection_names[] = {
|
||||
"clear", "safe",
|
||||
"confidential", "private"
|
||||
};
|
||||
|
||||
|
||||
void auth_init(void)
|
||||
{
|
||||
}
|
||||
@@ -47,7 +55,7 @@ void delete_ftp_command(void)
|
||||
void auth(char *auth)
|
||||
{
|
||||
for(ct=auth_types; ct->name; ct++){
|
||||
if(!strcmp(auth, ct->name)){
|
||||
if(!strcasecmp(auth, ct->name)){
|
||||
ct->auth(auth);
|
||||
return;
|
||||
}
|
||||
@@ -57,61 +65,116 @@ void auth(char *auth)
|
||||
|
||||
void adat(char *auth)
|
||||
{
|
||||
if(ct)
|
||||
if(ct && !auth_complete)
|
||||
ct->adat(auth);
|
||||
else
|
||||
reply(503, "Error, error");
|
||||
reply(503, "You must (re)issue an AUTH first.");
|
||||
}
|
||||
|
||||
void pbsz(int size)
|
||||
{
|
||||
if(ct)
|
||||
int old = buffer_size;
|
||||
if(ct && auth_complete)
|
||||
ct->pbsz(size);
|
||||
else
|
||||
reply(503, "Error, error");
|
||||
reply(503, "Incomplete security data exchange.");
|
||||
if(buffer_size != old){
|
||||
if(data_buffer)
|
||||
free(data_buffer);
|
||||
data_buffer = malloc(buffer_size + 4);
|
||||
}
|
||||
}
|
||||
|
||||
void prot(char *pl)
|
||||
{
|
||||
if(ct)
|
||||
ct->prot(pl);
|
||||
else
|
||||
reply(503, "Error, error");
|
||||
int p = -1;
|
||||
|
||||
if(buffer_size == 0){
|
||||
reply(503, "No protection buffer size negotiated.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!strcasecmp(pl, "C"))
|
||||
p = prot_clear;
|
||||
|
||||
if(!strcasecmp(pl, "S"))
|
||||
p = prot_safe;
|
||||
|
||||
if(!strcasecmp(pl, "E"))
|
||||
p = prot_confidential;
|
||||
|
||||
if(!strcasecmp(pl, "P"))
|
||||
p = prot_private;
|
||||
|
||||
if(p == -1){
|
||||
reply(504, "Unrecognized protection level.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ct && auth_complete){
|
||||
if(ct->prot(p)){
|
||||
reply(536, "%s does not support %s protection.",
|
||||
ct->name, protection_names[p]);
|
||||
}else{
|
||||
data_protection = p;
|
||||
reply(200, "Data protection is %s.",
|
||||
protection_names[data_protection]);
|
||||
}
|
||||
}else{
|
||||
reply(503, "Incomplete security data exchange.");
|
||||
}
|
||||
}
|
||||
|
||||
void ccc(void)
|
||||
{
|
||||
if(ct)
|
||||
ct->ccc();
|
||||
else
|
||||
reply(503, "Error, error");
|
||||
if(ct && auth_complete){
|
||||
if(!ct->ccc())
|
||||
prot_level = prot_clear;
|
||||
}else
|
||||
reply(503, "Incomplete security data exchange.");
|
||||
}
|
||||
|
||||
void mic(char *msg)
|
||||
{
|
||||
if(ct && auth_complete){
|
||||
if(!ct->mic(msg))
|
||||
prot_level = prot_safe;
|
||||
if(ct)
|
||||
ct->mic(msg);
|
||||
else
|
||||
reply(500, "Command unrecognized");
|
||||
}else
|
||||
reply(503, "Incomplete security data exchange.");
|
||||
}
|
||||
|
||||
void conf(char *msg)
|
||||
{
|
||||
if(ct && auth_complete){
|
||||
if(!ct->conf(msg))
|
||||
prot_level = prot_confidential;
|
||||
if(ct)
|
||||
ct->conf(msg);
|
||||
else
|
||||
reply(500, "Command unrecognized");
|
||||
}else
|
||||
reply(503, "Incomplete security data exchange.");
|
||||
}
|
||||
|
||||
void enc(char *msg)
|
||||
{
|
||||
if(ct && auth_complete){
|
||||
if(!ct->enc(msg))
|
||||
prot_level = prot_private;
|
||||
if(ct)
|
||||
ct->enc(msg);
|
||||
}else
|
||||
reply(503, "Incomplete security data exchange.");
|
||||
}
|
||||
|
||||
int auth_read(int fd, void *data, int length)
|
||||
{
|
||||
if(ct && auth_complete && data_protection)
|
||||
return ct->read(fd, data, length);
|
||||
else
|
||||
reply(500, "Command unrecognized");
|
||||
return read(fd, data, length);
|
||||
}
|
||||
|
||||
int auth_write(int fd, void *data, int length)
|
||||
{
|
||||
if(ct && auth_complete && data_protection)
|
||||
return ct->write(fd, data, length);
|
||||
else
|
||||
return write(fd, data, length);
|
||||
}
|
||||
|
||||
void auth_vprintf(const char *fmt, va_list ap)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#ifndef _AUTH_H_
|
||||
#define _AUTH_H_
|
||||
#ifndef __AUTH_H__
|
||||
#define __AUTH_H__
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -8,27 +8,32 @@ struct at {
|
||||
int (*auth)(char*);
|
||||
int (*adat)(char*);
|
||||
int (*pbsz)(int);
|
||||
int (*prot)(char*);
|
||||
int (*prot)(int);
|
||||
int (*ccc)(void);
|
||||
int (*mic)(char*);
|
||||
int (*conf)(char*);
|
||||
int (*enc)(char*);
|
||||
int (*read)(int, void*, int);
|
||||
int (*write)(int, void*, int);
|
||||
int (*userok)(char*);
|
||||
int (*vprintf)(const char*, va_list);
|
||||
};
|
||||
|
||||
struct at *ct;
|
||||
extern struct at *ct;
|
||||
|
||||
enum protection_levels {
|
||||
prot_clear, prot_safe, prot_confidential, prot_private
|
||||
};
|
||||
|
||||
extern char *protection_names[];
|
||||
|
||||
extern char *ftp_command;
|
||||
extern int prot_level;
|
||||
|
||||
int data_protection;
|
||||
int buffer_size;
|
||||
int auth_complete;
|
||||
extern int data_protection;
|
||||
extern int buffer_size;
|
||||
extern unsigned char *data_buffer;
|
||||
extern int auth_complete;
|
||||
|
||||
void auth_init(void);
|
||||
|
||||
@@ -41,9 +46,12 @@ void mic(char*);
|
||||
void conf(char*);
|
||||
void enc(char*);
|
||||
|
||||
int auth_read(int, void*, int);
|
||||
int auth_write(int, void*, int);
|
||||
|
||||
void auth_vprintf(const char *fmt, va_list ap);
|
||||
void auth_printf(const char *fmt, ...);
|
||||
|
||||
void new_ftp_command(char *command);
|
||||
|
||||
#endif /* _AUTH_H_ */
|
||||
#endif /* __AUTH_H__ */
|
||||
|
@@ -77,6 +77,8 @@ void upper(char *);
|
||||
void user(char *);
|
||||
void yyerror(char *);
|
||||
|
||||
void kauth(char *, char*);
|
||||
|
||||
extern struct sockaddr_in ctrl_addr, his_addr;
|
||||
extern char hostname[];
|
||||
|
||||
@@ -102,5 +104,4 @@ extern int usedefault;
|
||||
extern int transflag;
|
||||
extern char tmpline[];
|
||||
|
||||
|
||||
#endif /* _EXTERN_H_ */
|
||||
|
@@ -107,6 +107,8 @@ char *fromname;
|
||||
AUTH ADAT PROT PBSZ CCC MIC
|
||||
CONF ENC
|
||||
|
||||
KAUTH
|
||||
|
||||
LEXERR
|
||||
|
||||
%token <s> STRING
|
||||
@@ -475,6 +477,24 @@ cmd
|
||||
timeout);
|
||||
}
|
||||
}
|
||||
|
||||
| SITE SP KAUTH SP STRING CRLF
|
||||
{
|
||||
char *p;
|
||||
size_t s;
|
||||
|
||||
p = strpbrk($5, " \t");
|
||||
if(p){
|
||||
*p++ = 0;
|
||||
s = strspn(p, " \t");
|
||||
if(s >= 0)
|
||||
kauth($5, p + s);
|
||||
else
|
||||
kauth($5, p);
|
||||
}else
|
||||
kauth($5, NULL);
|
||||
free($5);
|
||||
}
|
||||
| STOU check_login SP pathname CRLF
|
||||
{
|
||||
if ($2 && $4 != NULL)
|
||||
@@ -841,7 +861,7 @@ struct tab cmdtab[] = { /* In order defined in RFC 765 */
|
||||
{ "AUTH", AUTH, STR1, 1, "<sp> auth-type" },
|
||||
{ "ADAT", ADAT, STR1, 1, "<sp> auth-data" },
|
||||
{ "PBSZ", PBSZ, ARGS, 1, "<sp> buffer-size" },
|
||||
{ "PROT", PROT, ARGS, 1, "<sp> prot-level" },
|
||||
{ "PROT", PROT, STR1, 1, "<sp> prot-level" },
|
||||
{ "CCC", CCC, ARGS, 1, "" },
|
||||
{ "MIC", MIC, STR1, 1, "<sp> integrity command" },
|
||||
{ "CONF", CONF, STR1, 1, "<sp> confidentiality command" },
|
||||
@@ -855,6 +875,9 @@ struct tab sitetab[] = {
|
||||
{ "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" },
|
||||
{ "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" },
|
||||
{ "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" },
|
||||
|
||||
{ "KAUTH", KAUTH, STR1, 1, "<sp> principal [ <sp> ticket ]" },
|
||||
|
||||
{ NULL, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -867,9 +890,7 @@ static void toolong __P((int));
|
||||
static int yylex __P((void));
|
||||
|
||||
static struct tab *
|
||||
lookup(p, cmd)
|
||||
struct tab *p;
|
||||
char *cmd;
|
||||
lookup(struct tab *p, char *cmd)
|
||||
{
|
||||
|
||||
for (; p->name != NULL; p++)
|
||||
@@ -958,8 +979,7 @@ getline(char *s, int n)
|
||||
}
|
||||
|
||||
static void
|
||||
toolong(signo)
|
||||
int signo;
|
||||
toolong(int signo)
|
||||
{
|
||||
|
||||
reply(421,
|
||||
@@ -971,7 +991,7 @@ toolong(signo)
|
||||
}
|
||||
|
||||
static int
|
||||
yylex()
|
||||
yylex(void)
|
||||
{
|
||||
static int cpos, state;
|
||||
char *cp, *cp2;
|
||||
@@ -1189,8 +1209,7 @@ yylex()
|
||||
}
|
||||
|
||||
void
|
||||
upper(s)
|
||||
char *s;
|
||||
upper(char *s)
|
||||
{
|
||||
while (*s != '\0') {
|
||||
if (islower(*s))
|
||||
@@ -1200,8 +1219,7 @@ upper(s)
|
||||
}
|
||||
|
||||
static char *
|
||||
copy(s)
|
||||
char *s;
|
||||
copy(char *s)
|
||||
{
|
||||
char *p;
|
||||
|
||||
@@ -1213,9 +1231,7 @@ copy(s)
|
||||
}
|
||||
|
||||
static void
|
||||
help(ctab, s)
|
||||
struct tab *ctab;
|
||||
char *s;
|
||||
help(struct tab *ctab, char *s)
|
||||
{
|
||||
struct tab *c;
|
||||
int width, NCMDS;
|
||||
@@ -1278,8 +1294,7 @@ help(ctab, s)
|
||||
}
|
||||
|
||||
static void
|
||||
sizecmd(filename)
|
||||
char *filename;
|
||||
sizecmd(char *filename)
|
||||
{
|
||||
switch (type) {
|
||||
case TYPE_L:
|
||||
|
@@ -258,10 +258,16 @@ main(int argc, char **argv, char **envp)
|
||||
char *cp, line[LINE_MAX];
|
||||
FILE *fd;
|
||||
|
||||
char tkfile[1024];
|
||||
|
||||
#if 0
|
||||
conn_wait();
|
||||
#endif
|
||||
|
||||
sprintf(tkfile, "/tmp/ftp_%d", getpid());
|
||||
setenv("KRBTKFILE", tkfile);
|
||||
if(k_hasafs())
|
||||
k_setpag();
|
||||
/*
|
||||
* LOG_NDELAY sets up the logging connection immediately,
|
||||
* necessary for anonymous ftp's that chroot and can't do it later.
|
||||
@@ -988,6 +994,8 @@ send_data(FILE *instr, FILE *outstr, off_t blksize)
|
||||
{
|
||||
int c, cnt, filefd, netfd;
|
||||
char *buf;
|
||||
int i = 0;
|
||||
char s[1024];
|
||||
|
||||
transflag++;
|
||||
if (setjmp(urgcatch)) {
|
||||
@@ -999,13 +1007,17 @@ send_data(FILE *instr, FILE *outstr, off_t blksize)
|
||||
case TYPE_A:
|
||||
while ((c = getc(instr)) != EOF) {
|
||||
byte_count++;
|
||||
if (c == '\n') {
|
||||
if (ferror(outstr))
|
||||
goto data_err;
|
||||
(void) putc('\r', outstr);
|
||||
if(i > 1022){
|
||||
auth_write(fileno(outstr), s, i);
|
||||
i = 0;
|
||||
}
|
||||
(void) putc(c, outstr);
|
||||
if(c == '\n')
|
||||
s[i++] = '\r';
|
||||
s[i++] = c;
|
||||
}
|
||||
if(i)
|
||||
auth_write(fileno(outstr), s, i);
|
||||
auth_write(fileno(outstr), s, 0);
|
||||
fflush(outstr);
|
||||
transflag = 0;
|
||||
if (ferror(instr))
|
||||
@@ -1025,8 +1037,9 @@ send_data(FILE *instr, FILE *outstr, off_t blksize)
|
||||
netfd = fileno(outstr);
|
||||
filefd = fileno(instr);
|
||||
while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
|
||||
write(netfd, buf, cnt) == cnt)
|
||||
auth_write(netfd, buf, cnt) == cnt)
|
||||
byte_count += cnt;
|
||||
auth_write(netfd, buf, 0); /* to end an encrypted stream */
|
||||
transflag = 0;
|
||||
(void)free(buf);
|
||||
if (cnt != 0) {
|
||||
@@ -1074,7 +1087,7 @@ receive_data(FILE *instr, FILE *outstr)
|
||||
|
||||
case TYPE_I:
|
||||
case TYPE_L:
|
||||
while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
|
||||
while ((cnt = auth_read(fileno(instr), buf, sizeof(buf))) > 0) {
|
||||
if (write(fileno(outstr), buf, cnt) != cnt)
|
||||
goto file_err;
|
||||
byte_count += cnt;
|
||||
@@ -1090,22 +1103,33 @@ receive_data(FILE *instr, FILE *outstr)
|
||||
return (-1);
|
||||
|
||||
case TYPE_A:
|
||||
while ((c = getc(instr)) != EOF) {
|
||||
byte_count++;
|
||||
if (c == '\n')
|
||||
{
|
||||
char *p, *q;
|
||||
int cr_flag = 0;
|
||||
while ((cnt = auth_read(fileno(instr), buf+cr_flag, sizeof(buf))) > 0){
|
||||
byte_count += cnt;
|
||||
cr_flag = 0;
|
||||
for(p = buf, q = buf; p < buf + cnt;){
|
||||
if(*p == '\n')
|
||||
bare_lfs++;
|
||||
while (c == '\r') {
|
||||
if (ferror(outstr))
|
||||
goto data_err;
|
||||
if ((c = getc(instr)) != '\n') {
|
||||
(void) putc ('\r', outstr);
|
||||
if (c == '\0' || c == EOF)
|
||||
goto contin2;
|
||||
if(*p == '\r')
|
||||
if(p == buf + cnt - 1){
|
||||
cr_flag = 1;
|
||||
p++;
|
||||
continue;
|
||||
}else if(p[1] == '\n'){
|
||||
*q++ = '\n';
|
||||
p += 2;
|
||||
continue;
|
||||
}
|
||||
*q++ = *p++;
|
||||
}
|
||||
(void) putc(c, outstr);
|
||||
contin2: ;
|
||||
fwrite(buf, q - buf, 1, outstr);
|
||||
if(cr_flag)
|
||||
buf[0] = '\r';
|
||||
}
|
||||
if(cr_flag)
|
||||
putc('\r', outstr);
|
||||
fflush(outstr);
|
||||
if (ferror(instr))
|
||||
goto data_err;
|
||||
@@ -1113,12 +1137,12 @@ receive_data(FILE *instr, FILE *outstr)
|
||||
goto file_err;
|
||||
transflag = 0;
|
||||
if (bare_lfs) {
|
||||
lreply(226,
|
||||
"WARNING! %d bare linefeeds received in ASCII mode",
|
||||
lreply(226, "WARNING! %d bare linefeeds received in ASCII mode\r\n"
|
||||
" File may not have transferred correctly.\r\n",
|
||||
bare_lfs);
|
||||
(void)printf(" File may not have transferred correctly.\r\n");
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
default:
|
||||
reply(550, "Unimplemented TYPE %d in receive_data", type);
|
||||
transflag = 0;
|
||||
@@ -1417,10 +1441,9 @@ dologout(int status)
|
||||
if (logged_in) {
|
||||
(void) seteuid((uid_t)0);
|
||||
logwtmp(ttyline, "", "");
|
||||
#if defined(KERBEROS)
|
||||
if (!notickets && krbtkfile_env)
|
||||
unlink(krbtkfile_env);
|
||||
#endif
|
||||
dest_tkt();
|
||||
if(k_hasafs())
|
||||
k_unlog();
|
||||
}
|
||||
/* beware of flushing buffers after a SIGPIPE */
|
||||
_exit(status);
|
||||
|
175
appl/ftp/ftpd/kauth.c
Normal file
175
appl/ftp/ftpd/kauth.c
Normal file
@@ -0,0 +1,175 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <des.h>
|
||||
#include <krb.h>
|
||||
#include <kafs.h>
|
||||
|
||||
#include "extern.h"
|
||||
#include "krb4.h"
|
||||
#include "auth.h"
|
||||
|
||||
|
||||
static KTEXT_ST cip;
|
||||
static time_t local_time;
|
||||
|
||||
static char name[ANAME_SZ], inst[INST_SZ], realm[REALM_SZ];
|
||||
|
||||
static int
|
||||
save_tkt(char *user, char *instance, char *realm, void *arg,
|
||||
key_proc_t key_proc, KTEXT *cipp)
|
||||
{
|
||||
local_time = time(0);
|
||||
memmove(&cip, *cipp, sizeof(cip));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
store_ticket(KTEXT cip)
|
||||
{
|
||||
char *ptr;
|
||||
des_cblock session;
|
||||
char sname[SNAME_SZ];
|
||||
char sinst[INST_SZ];
|
||||
char srealm[REALM_SZ];
|
||||
unsigned char lifetime;
|
||||
unsigned char kvno;
|
||||
KTEXT_ST tkt;
|
||||
|
||||
int kerror;
|
||||
|
||||
time_t kdc_time;
|
||||
|
||||
ptr = (char *) cip->dat;
|
||||
|
||||
/* extract session key */
|
||||
memmove(session, ptr, 8);
|
||||
ptr += 8;
|
||||
|
||||
if ((strlen(ptr) + (ptr - (char *) cip->dat)) > cip->length)
|
||||
return(INTK_BADPW);
|
||||
|
||||
/* extract server's name */
|
||||
strcpy(sname,ptr);
|
||||
ptr += strlen(sname) + 1;
|
||||
|
||||
if ((strlen(ptr) + (ptr - (char *) cip->dat)) > cip->length)
|
||||
return(INTK_BADPW);
|
||||
|
||||
/* extract server's instance */
|
||||
strcpy(sinst, ptr);
|
||||
ptr += strlen(sinst) + 1;
|
||||
|
||||
if ((strlen(ptr) + (ptr - (char *) cip->dat)) > cip->length)
|
||||
return(INTK_BADPW);
|
||||
|
||||
/* extract server's realm */
|
||||
strcpy(srealm,ptr);
|
||||
ptr += strlen(srealm) + 1;
|
||||
|
||||
/* extract ticket lifetime, server key version, ticket length */
|
||||
/* be sure to avoid sign extension on lifetime! */
|
||||
lifetime = (unsigned char) ptr[0];
|
||||
kvno = (unsigned char) ptr[1];
|
||||
tkt.length = (unsigned char) ptr[2];
|
||||
ptr += 3;
|
||||
|
||||
if ((tkt.length < 0) ||
|
||||
((tkt.length + (ptr - (char *) cip->dat)) > cip->length))
|
||||
return(INTK_BADPW);
|
||||
|
||||
/* extract ticket itself */
|
||||
memmove(tkt.dat, ptr, tkt.length);
|
||||
ptr += tkt.length;
|
||||
|
||||
/* Here is where the time should be verified against the KDC.
|
||||
* Unfortunately everything is sent in host byte order (receiver
|
||||
* makes wrong) , and at this stage there is no way for us to know
|
||||
* which byteorder the KDC has. So we simply ignore the time,
|
||||
* there are no security risks with this, the only thing that can
|
||||
* happen is that we might receive a replayed ticket, which could
|
||||
* at most be useless.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
/* check KDC time stamp */
|
||||
memmove(&kdc_time, ptr, sizeof(kdc_time));
|
||||
if (swap_bytes) swap_u_long(kdc_time);
|
||||
|
||||
ptr += 4;
|
||||
|
||||
if (abs((int)(local_time - kdc_time)) > CLOCK_SKEW) {
|
||||
return(RD_AP_TIME); /* XXX should probably be better
|
||||
code */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* initialize ticket cache */
|
||||
|
||||
if (tf_create(TKT_FILE) != KSUCCESS)
|
||||
return(INTK_ERR);
|
||||
|
||||
if (tf_put_pname(name) != KSUCCESS ||
|
||||
tf_put_pinst(inst) != KSUCCESS) {
|
||||
tf_close();
|
||||
return(INTK_ERR);
|
||||
}
|
||||
|
||||
|
||||
kerror = tf_save_cred(sname, sinst, srealm, session, lifetime, kvno,
|
||||
&tkt, local_time);
|
||||
tf_close();
|
||||
|
||||
return(kerror);
|
||||
}
|
||||
|
||||
void kauth(char *principal, char *ticket)
|
||||
{
|
||||
char *p;
|
||||
int ret;
|
||||
|
||||
ret = kname_parse(name, inst, realm, principal);
|
||||
if(ret){
|
||||
reply(500, "Bad principal: %s.", krb_get_err_text(ret));
|
||||
return;
|
||||
}
|
||||
if(realm[0] == 0)
|
||||
krb_get_lrealm(realm, 0);
|
||||
|
||||
if(ticket){
|
||||
cip.length = base64_decode(ticket, &cip.dat);
|
||||
if(cip.length == -1){
|
||||
reply(500, "Failed to decode data.");
|
||||
return;
|
||||
}
|
||||
ret = store_ticket(&cip);
|
||||
if(ret){
|
||||
reply(500, "Kerberos error: %s.", krb_get_err_text(ret));
|
||||
memset(&cip, 0, sizeof(cip));
|
||||
return;
|
||||
}
|
||||
if(k_hasafs())
|
||||
k_afsklog(0, 0);
|
||||
reply(200, "OK");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = krb_get_in_tkt (name, inst, realm, "krbtgt", realm, 12,
|
||||
NULL, save_tkt, NULL);
|
||||
if(ret != INTK_BADPW){
|
||||
reply(500, "Kerberos error: %s.", krb_get_err_text(ret));
|
||||
return;
|
||||
}
|
||||
base64_encode(cip.dat, cip.length, &p);
|
||||
reply(300, "P=%s%s%s@%s T=%s", name, *inst?".":"", inst, realm, p);
|
||||
free(p);
|
||||
memset(&cip, 0, sizeof(cip));
|
||||
}
|
@@ -5,6 +5,7 @@
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -39,24 +40,33 @@ int krb4_adat(char *auth)
|
||||
memset(&tkt, 0, sizeof(tkt));
|
||||
tkt.length = base64_decode(auth, tkt.dat);
|
||||
|
||||
strcpy(inst, "*");
|
||||
if(tkt.length < 0){
|
||||
reply(501, "Failed to decode base64 data.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
k_getsockinst(0, inst);
|
||||
kerror = krb_rd_req(&tkt, "ftp", inst, 0, &auth_dat, "");
|
||||
if(kerror == RD_AP_UNDEC){
|
||||
strcpy(inst, "*");
|
||||
k_getsockinst(0, inst);
|
||||
kerror = krb_rd_req(&tkt, "rcmd", inst, 0, &auth_dat, "");
|
||||
}
|
||||
|
||||
des_key_sched(&auth_dat.session, schedule);
|
||||
|
||||
if(kerror != RD_AP_OK){
|
||||
reply(535, "%s", krb_err_txt[kerror]);
|
||||
return 1;
|
||||
if(kerror){
|
||||
reply(535, "Error reading request: %s.", krb_get_err_text(kerror));
|
||||
return -1;
|
||||
}
|
||||
|
||||
des_set_key(&auth_dat.session, schedule);
|
||||
|
||||
cs = htonl(auth_dat.checksum + 1);
|
||||
len = krb_mk_safe((u_char*)&cs, (u_char*)msg, sizeof(cs),
|
||||
&auth_dat.session, &ctrl_addr, &his_addr);
|
||||
base64_encode((unsigned char*)msg, len, &p);
|
||||
len = krb_mk_safe(&cs, msg, sizeof(cs), &auth_dat.session,
|
||||
&ctrl_addr, &his_addr);
|
||||
if(len < 0){
|
||||
reply(535, "Error creating reply: %s.", k_strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
base64_encode(msg, len, &p);
|
||||
reply(235, "ADAT=%s", p);
|
||||
auth_complete = 1;
|
||||
free(p);
|
||||
@@ -65,95 +75,202 @@ int krb4_adat(char *auth)
|
||||
|
||||
int krb4_pbsz(int size)
|
||||
{
|
||||
if(size > 1048576) /* XXX arbitrary number */
|
||||
size = 1048576;
|
||||
buffer_size = size;
|
||||
reply(200, "OK");
|
||||
reply(200, "OK PBSZ=%d", buffer_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int krb4_prot(char *type)
|
||||
int krb4_prot(int level)
|
||||
{
|
||||
if(!strcmp(type, "C")){
|
||||
data_protection = prot_clear;
|
||||
}else if(!strcmp(type, "S")){
|
||||
data_protection = prot_safe;
|
||||
}else if(!strcmp(type, "E")){
|
||||
data_protection = prot_confidential;
|
||||
}else if(!strcmp(type, "P")){
|
||||
data_protection = prot_private;
|
||||
}else{
|
||||
reply(504, "Unrecognized protection level");
|
||||
return 1;
|
||||
}
|
||||
reply(200, "OK");
|
||||
if(level == prot_confidential)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int krb4_ccc(void)
|
||||
{
|
||||
reply(500, "Gurka");
|
||||
return 1;
|
||||
reply(534, "Don't event think about it.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int krb4_mic(char *msg)
|
||||
{
|
||||
char *cmd = (char*)malloc(strlen(msg));
|
||||
int len;
|
||||
int kerror;
|
||||
MSG_DAT m_data;
|
||||
char *p;
|
||||
char tmp[1024];
|
||||
unsigned char enc[1024];
|
||||
char *tmp, *cmd;
|
||||
|
||||
cmd = strdup(msg);
|
||||
|
||||
len = base64_decode(msg, cmd);
|
||||
if(len < 0){
|
||||
reply(501, "Failed to decode base 64 data.");
|
||||
free(cmd);
|
||||
return -1;
|
||||
}
|
||||
kerror = krb_rd_safe(cmd, len, &auth_dat.session,
|
||||
&ctrl_addr, &his_addr, &m_data);
|
||||
sprintf(tmp, "%.*s\r\n", m_data.app_length, m_data.app_data);
|
||||
new_ftp_command(strdup(tmp));
|
||||
&his_addr, &ctrl_addr, &m_data);
|
||||
|
||||
if(kerror){
|
||||
reply(535, "Error reading request: %s.", krb_get_err_text(kerror));
|
||||
free(cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp = strdup(msg);
|
||||
sprintf(tmp, "%.*s", m_data.app_length, m_data.app_data);
|
||||
if(!strstr(tmp, "\r\n"))
|
||||
strcat(tmp, "\r\n");
|
||||
new_ftp_command(tmp);
|
||||
free(cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int krb4_conf(char *msg)
|
||||
{
|
||||
char tmp[1024];
|
||||
unsigned char enc[1024];
|
||||
int len;
|
||||
char *p;
|
||||
prot_level = prot_safe;
|
||||
|
||||
sprintf(tmp, "%d %s\r\n", 536,
|
||||
"Requested PROT level not supported by mechanism");
|
||||
len = krb_mk_safe((u_char*)tmp, (u_char*)enc, strlen(tmp), &auth_dat.session,
|
||||
&ctrl_addr, &his_addr);
|
||||
if(len > 0){
|
||||
base64_encode(enc, len, &p);
|
||||
fprintf(stdout, "631 %s\r\n", p);
|
||||
free(p);
|
||||
}
|
||||
return 1;
|
||||
reply(537, "Protection level not supported.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int krb4_enc(char *msg)
|
||||
{
|
||||
char *cmd = (char*)malloc(strlen(msg));
|
||||
int len;
|
||||
int kerror;
|
||||
MSG_DAT m_data;
|
||||
char *p;
|
||||
char *tmp, *cmd;
|
||||
|
||||
char tmp[1024];
|
||||
unsigned char enc[1024];
|
||||
cmd = strdup(msg);
|
||||
|
||||
len = base64_decode(msg, cmd);
|
||||
|
||||
if(len < 0){
|
||||
reply(501, "Failed to decode base 64 data.");
|
||||
free(cmd);
|
||||
return -1;
|
||||
}
|
||||
kerror = krb_rd_priv(cmd, len, schedule, &auth_dat.session,
|
||||
&ctrl_addr, &his_addr, &m_data);
|
||||
sprintf(tmp, "%.*s\r\n", m_data.app_length, m_data.app_data);
|
||||
new_ftp_command(strdup(tmp));
|
||||
&his_addr, &ctrl_addr, &m_data);
|
||||
|
||||
if(kerror){
|
||||
reply(535, "Error reading request: %s.", krb_get_err_text(kerror));
|
||||
free(cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp = strdup(msg);
|
||||
sprintf(tmp, "%.*s", m_data.app_length, m_data.app_data);
|
||||
if(!strstr(tmp, "\r\n"))
|
||||
strcat(tmp, "\r\n");
|
||||
new_ftp_command(tmp);
|
||||
free(cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int krb4_read(int fd, void *data, int length)
|
||||
{
|
||||
static int left;
|
||||
static char *extra;
|
||||
static int eof;
|
||||
int len, bytes, tx = 0;
|
||||
|
||||
MSG_DAT m_data;
|
||||
int kerror;
|
||||
|
||||
if(eof){ /* if we haven't reported an end-of-file, do so */
|
||||
eof = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(left){
|
||||
if(length > left)
|
||||
bytes = left;
|
||||
else
|
||||
bytes = length;
|
||||
memmove(data, extra, bytes);
|
||||
left -= bytes;
|
||||
if(left)
|
||||
memmove(extra, extra + bytes, left);
|
||||
else
|
||||
free(extra);
|
||||
length -= bytes;
|
||||
tx += bytes;
|
||||
}
|
||||
|
||||
while(length){
|
||||
krb_net_read(fd, &len, 4);
|
||||
len = ntohl(len);
|
||||
krb_net_read(fd, data_buffer, len);
|
||||
if(data_protection == prot_safe)
|
||||
kerror = krb_rd_safe(data_buffer, len, &auth_dat.session,
|
||||
&his_addr, &ctrl_addr, &m_data);
|
||||
else
|
||||
kerror = krb_rd_priv(data_buffer, len, schedule, &auth_dat.session,
|
||||
&his_addr, &ctrl_addr, &m_data);
|
||||
|
||||
if(kerror){
|
||||
reply(400, "Failed to read data: %s.", krb_get_err_text(kerror));
|
||||
return -1;
|
||||
}
|
||||
|
||||
bytes = m_data.app_length;
|
||||
if(bytes == 0){
|
||||
if(tx) eof = 1;
|
||||
return tx;
|
||||
}
|
||||
if(bytes > length){
|
||||
left = bytes - length;
|
||||
bytes = length;
|
||||
extra = malloc(left);
|
||||
memmove(extra, m_data.app_data + bytes, left);
|
||||
}
|
||||
memmove((unsigned char*)data + tx, m_data.app_data, bytes);
|
||||
tx += bytes;
|
||||
length -= bytes;
|
||||
}
|
||||
return tx;
|
||||
}
|
||||
|
||||
int krb4_write(int fd, void *data, int length)
|
||||
{
|
||||
int len, bytes, tx = 0;
|
||||
|
||||
len = buffer_size;
|
||||
if(data_protection == prot_safe)
|
||||
len -= 31; /* always 31 bytes overhead */
|
||||
else
|
||||
len -= 26; /* at most 26 bytes */
|
||||
|
||||
do{
|
||||
if(length < len)
|
||||
len = length;
|
||||
if(data_protection == prot_safe)
|
||||
bytes = krb_mk_safe(data, data_buffer+4, len, &auth_dat.session,
|
||||
&ctrl_addr, &his_addr);
|
||||
else
|
||||
bytes = krb_mk_priv(data, data_buffer+4, len, schedule,
|
||||
&auth_dat.session,
|
||||
&ctrl_addr, &his_addr);
|
||||
if(bytes == -1){
|
||||
reply(535, "Failed to make packet: %s.", k_strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
data_buffer[0] = (bytes >> 24) & 0xff;
|
||||
data_buffer[1] = (bytes >> 16) & 0xff;
|
||||
data_buffer[2] = (bytes >> 8) & 0xff;
|
||||
data_buffer[3] = bytes & 0xff;
|
||||
krb_net_write(fd, data_buffer, bytes+4);
|
||||
length -= len;
|
||||
data = (unsigned char*)data + len;
|
||||
tx += len;
|
||||
}while(length);
|
||||
return tx;
|
||||
}
|
||||
|
||||
int krb4_userok(char *name)
|
||||
{
|
||||
if(!kuserok(&auth_dat, name)){
|
||||
@@ -167,7 +284,7 @@ int krb4_userok(char *name)
|
||||
|
||||
int krb4_vprintf(const char *fmt, va_list ap)
|
||||
{
|
||||
char buf[10240];
|
||||
char buf[10240]; /* XXX */
|
||||
char *p;
|
||||
char *enc;
|
||||
int code;
|
||||
|
@@ -1,17 +1,21 @@
|
||||
#ifndef _KRB4_H_
|
||||
#define _KRB4_H_
|
||||
#ifndef __KRB4_H__
|
||||
#define __KRB4_H__
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
extern int krb4_auth(char * auth);
|
||||
extern int krb4_adat(char * auth);
|
||||
extern int krb4_pbsz(int size);
|
||||
extern int krb4_prot(char * type);
|
||||
extern int krb4_ccc(void );
|
||||
extern int krb4_mic(char * msg);
|
||||
extern int krb4_conf(char * msg);
|
||||
extern int krb4_enc(char * msg);
|
||||
extern int krb4_userok(char *name);
|
||||
extern int krb4_vprintf(const char *fmt, va_list ap);
|
||||
int krb4_auth(char *auth);
|
||||
int krb4_adat(char *auth);
|
||||
int krb4_pbsz(int size);
|
||||
int krb4_prot(int level);
|
||||
int krb4_ccc(void);
|
||||
int krb4_mic(char *msg);
|
||||
int krb4_conf(char *msg);
|
||||
int krb4_enc(char *msg);
|
||||
|
||||
#endif /* _KRB4_H_ */
|
||||
int krb4_read(int fd, void *data, int length);
|
||||
int krb4_write(int fd, void *data, int length);
|
||||
|
||||
int krb4_userok(char *name);
|
||||
int krb4_vprintf(const char *fmt, va_list ap);
|
||||
|
||||
#endif /* __KRB4_H__ */
|
||||
|
Reference in New Issue
Block a user