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:
Unknown User d91-jda
1996-04-14 15:27:21 +00:00
parent 218bd7346f
commit 5d8677ac01
20 changed files with 1304 additions and 513 deletions

View File

@@ -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

View File

@@ -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 },
};

View File

@@ -165,3 +165,5 @@ extern int proxy;
extern char reply_string[];
extern off_t restart_point;
extern int NCMDS;
extern char username[32];

View File

@@ -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);

View File

@@ -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*);

View File

@@ -127,3 +127,5 @@ struct macel {
extern int macnum; /* number of defined macros */
extern struct macel macros[16];
extern char macbuf[4096];

View File

@@ -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
View 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
View 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
View 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__ */

View File

@@ -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':

View File

@@ -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) $<

View File

@@ -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)

View File

@@ -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__ */

View File

@@ -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_ */

View File

@@ -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:

View File

@@ -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
View 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));
}

View File

@@ -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;

View File

@@ -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__ */