+Wed Aug 12 02:26:26 1998 Geoffrey King <gjking@mit.edu>
+
+ * ftp.c, cmds.c, cmdtab.c, main.c, secure.c, ftp_var.h: Replace
+ global variable level with separate variables clevel and dlevel
+ for the control channel and data channel protection levels,
+ respectively, so that the user may specify separate protection
+ levels for each channel. Similarly, functions such as getlevel
+ and setlevel are now getclevel/getdlevel, and setclevel/setdlevel.
+
+ * cmdtab.c: Add new FTP commands "cprotect" to allow the user to
+ set the control channel protection level (similar to "protect"),
+ and "ccc" (Clear Command Channel) which sets the control channel
+ protection level to clear (per the RFC).
+
Fri Aug 7 22:39:47 1998 Matthew D Hancher <mdh@mit.edu>
* ftp.c (do_auth): Make verbosity not disappear if GSSAPI fails.
/*
* Set up defaults for FTP.
*/
- level = PROT_C;
+ clevel = dlevel = PROT_C;
type = TYPE_A;
curtype = TYPE_A;
form = FORM_N;
(void) strcpy(bytename, "8"), bytesize = 8;
if (autoauth) {
if (do_auth() && autoencrypt) {
+ clevel = PROT_P;
setpbsz(1<<20);
if (command("PROT P") == COMPLETE)
- level = PROT_P;
+ dlevel = PROT_P;
else
fprintf(stderr, "ftp: couldn't enable encryption\n");
}
-
+ if(auth_type && clevel == PROT_C)
+ clevel = PROT_S;
if(autologin)
- (void) login(argv[1]);
+ (void) login(argv[1]);
}
#ifndef unix
};
char *
-getlevel()
+getclevel()
{
register struct levels *p;
- for (p = levels; p->p_level != level; p++);
+ for (p = levels; p->p_level != clevel; p++);
return(p->p_name);
}
+char *
+getdlevel()
+{
+ register struct levels *p;
+
+ for (p = levels; p->p_level != dlevel; p++);
+ return(p->p_name);
+}
+
+char *plevel[] = {
+ "protect",
+ "",
+ 0
+};
+
+/*
+ * Set control channel protection level.
+ */
+setclevel(argc, argv)
+ char *argv[];
+{
+ register struct levels *p;
+ int comret;
+
+ if (argc > 2) {
+ char *sep;
+
+ printf("usage: %s [", argv[0]);
+ sep = " ";
+ for (p = levels; p->p_name; p++) {
+ printf("%s%s", sep, p->p_name);
+ if (*sep == ' ')
+ sep = " | ";
+ }
+ printf(" ]\n");
+ code = -1;
+ return;
+ }
+ if (argc < 2) {
+ printf("Using %s protection level for commands.\n",
+ getclevel());
+ code = 0;
+ return;
+ }
+ for (p = levels; p->p_name; p++)
+ if (strcmp(argv[1], p->p_name) == 0)
+ break;
+ if (p->p_name == 0) {
+ printf("%s: unknown protection level\n", argv[1]);
+ code = -1;
+ return;
+ }
+ if (!auth_type) {
+ if (strcmp(p->p_name, "clear"))
+ printf("Cannot set protection level to %s\n", argv[1]);
+ return;
+ }
+ if (!strcmp(p->p_name, "clear")) {
+ comret = command("CCC");
+ if (comret == COMPLETE)
+ clevel = PROT_C;
+ return;
+ }
+ clevel = p->p_level;
+ printf("Control channel protection level set to %s.\n", p->p_name);
+}
+
/*
- * Set protection level.
+ * Set data channel protection level.
*/
-setlevel(argc, argv)
+setdlevel(argc, argv)
char *argv[];
{
register struct levels *p;
}
if (argc < 2) {
printf("Using %s protection level to transfer files.\n",
- getlevel());
+ getdlevel());
code = 0;
return;
}
if (p->p_level != PROT_C) setpbsz(1<<20);
comret = command("PROT %s", p->p_mode);
if (comret == COMPLETE)
- level = p->p_level;
+ dlevel = p->p_level;
}
-char *plevel[] = {
- "protect",
- "",
- 0
-};
/*
- * Set clear protection level.
+ * Set clear command protection level.
+ */
+/*VARARGS*/
+ccc()
+{
+ plevel[1] = "clear";
+ setclevel(2, plevel);
+}
+
+/*
+ * Set clear data protection level.
*/
/*VARARGS*/
setclear()
{
plevel[1] = "clear";
- setlevel(2, plevel);
+ setdlevel(2, plevel);
}
/*
- * Set safe protection level.
+ * Set safe data protection level.
*/
/*VARARGS*/
setsafe()
{
plevel[1] = "safe";
- setlevel(2, plevel);
+ setdlevel(2, plevel);
}
#ifndef NOENCRYPTION
/*
- * Set private protection level.
+ * Set private data protection level.
*/
/*VARARGS*/
setprivate()
{
plevel[1] = "private";
- setlevel(2, plevel);
+ setdlevel(2, plevel);
}
#endif
printf("Connected %sto %s.\n",
proxy ? "for proxy commands " : "", hostname);
if (auth_type) printf("Authentication type: %s\n", auth_type);
- printf("Protection Level: %s\n", getlevel());
+ printf("Control Channel Protection Level: %s\n", getclevel());
+ printf("Data Channel Protection Level: %s\n", getdlevel());
printf("Passive mode %s\n", onoff(passivemode));
printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
getmode(), gettype(), getform(), getstruct());
if (argc < 3 )
argv[2] = mygetpass("Password: "), argc++;
#ifndef NOENCRYPTION
- if ((oldlevel = level) == PROT_S) level = PROT_P;
+ if ((oldlevel = dlevel) == PROT_S) dlevel = PROT_P;
#endif
n = command("PASS %s", argv[2]);
#ifndef NOENCRYPTION
/* level may have changed */
- if (level == PROT_P) level = oldlevel;
+ if (dlevel == PROT_P) dlevel = oldlevel;
#endif
}
if (n == CONTINUE) {
macnum = 0;
}
auth_type = NULL;
- level = PROT_C;
+ dlevel = PROT_C;
}
confirm(cmd, file)
int setglob(), sethash(), setmode(), setpeer(), setport();
int setprompt(), setstruct();
int settenex(), settrace(), settype(), setverbose();
-int setlevel(), setclear(), setsafe();
+int setclevel(), setdlevel(), setclear(), setsafe(), ccc();
#ifndef NOENCRYPTION
int setprivate();
#endif
char beephelp[] = "beep when command completed";
char binaryhelp[] = "set binary transfer type";
char casehelp[] = "toggle mget upper/lower case id mapping";
+char ccchelp[] = "set clear protection level for commands";
char cdhelp[] = "change remote working directory";
char cduphelp[] = "change remote working directory to parent directory";
char chmodhelp[] = "change file permissions of remote file";
char idlehelp[] = "get (set) idle timer on remote side";
char lcdhelp[] = "change local working directory";
char levelhelp[] = "set protection level for file transfer";
+char clevelhelp[] = "set protection level for commands";
char lshelp[] = "list contents of remote directory";
char macdefhelp[] = "define a macro";
char mdeletehelp[] = "delete multiple files";
{ "binary", binaryhelp, 0, 1, 1, setbinary },
{ "bye", quithelp, 0, 0, 0, quit },
{ "case", casehelp, 0, 0, 1, setcase },
+ { "ccc", ccchelp, 0, 1, 1, ccc },
{ "cd", cdhelp, 0, 1, 1, cd },
{ "cdup", cduphelp, 0, 1, 1, cdup },
{ "chmod", chmodhelp, 0, 1, 1, do_chmod },
{ "clear", clearhelp, 0, 1, 1, setclear },
{ "close", disconhelp, 0, 1, 1, disconnect },
+ { "cprotect", clevelhelp, 0, 1, 1, setclevel },
{ "cr", crhelp, 0, 0, 0, setcr },
{ "delete", deletehelp, 0, 1, 1, delete_file },
{ "debug", debughelp, 0, 0, 0, setdebug },
{ "private", privatehelp, 0, 1, 1, setprivate },
#endif
{ "prompt", prompthelp, 0, 0, 0, setprompt },
- { "protect", levelhelp, 0, 1, 1, setlevel },
+ { "protect", levelhelp, 0, 1, 1, setdlevel },
{ "proxy", proxyhelp, 0, 0, 1, doproxy },
{ "sendport", porthelp, 0, 0, 0, setport },
{ "put", sendhelp, 1, 1, 1, put },
};
int NCMDS = (sizeof (cmdtab) / sizeof (cmdtab[0])) - 1;
+
n = command("PASS dummy");
else if (n == CONTINUE) {
#ifndef NOENCRYPTION
- int oldlevel;
+ int oldclevel;
#endif
if (pass == NULL)
pass = mygetpass("Password:");
#ifndef NOENCRYPTION
- if ((oldlevel = level) == PROT_S) level = PROT_P;
+ if ((oldclevel = clevel) == PROT_S) clevel = PROT_P;
#endif
n = command("PASS %s", pass);
#ifndef NOENCRYPTION
/* level may have changed */
- if (level == PROT_P) level = oldlevel;
+ if (clevel == PROT_P) clevel = oldclevel;
#endif
}
if (n == CONTINUE) {
char in[FTP_BUFSIZ], out[FTP_BUFSIZ];
int length;
- if (auth_type) {
- /*
- * File protection level also determines whether
- * commands are MIC or ENC. Should be independent ...
- */
+ if (auth_type && clevel != PROT_C) {
#ifdef KRB5_KRB4_COMPAT
if (strcmp(auth_type, "KERBEROS_V4") == 0)
- if ((length = level == PROT_P ?
+ if ((length = clevel == PROT_P ?
krb_mk_priv((unsigned char *)cmd, (unsigned char *)out,
strlen(cmd), schedule,
&cred.session, &myctladdr, &hisctladdr)
strlen(cmd), &cred.session,
&myctladdr, &hisctladdr)) == -1) {
fprintf(stderr, "krb_mk_%s failed for KERBEROS_V4\n",
- level == PROT_P ? "priv" : "safe");
+ clevel == PROT_P ? "priv" : "safe");
return(0);
}
#endif /* KRB5_KRB4_COMPAT */
gss_buffer_desc in_buf, out_buf;
OM_uint32 maj_stat, min_stat;
int conf_state;
-/* level = PROT_P; */
+/* clevel = PROT_P; */
in_buf.value = cmd;
in_buf.length = strlen(cmd) + 1;
maj_stat = gss_seal(&min_stat, gcontext,
- (level==PROT_P), /* confidential */
+ (clevel==PROT_P), /* private */
GSS_C_QOP_DEFAULT,
&in_buf, &conf_state,
&out_buf);
if (maj_stat != GSS_S_COMPLETE) {
/* generally need to deal */
user_gss_error(maj_stat, min_stat,
- (level==PROT_P)?
+ (clevel==PROT_P)?
"gss_seal ENC didn't complete":
"gss_seal MIC didn't complete");
- } else if ((level == PROT_P) && !conf_state) {
+ } else if ((clevel == PROT_P) && !conf_state) {
fprintf(stderr,
"GSSAPI didn't encrypt message");
} else {
if (debug)
fprintf(stderr, "sealed (%s) %d bytes\n",
- level==PROT_P?"ENC":"MIC",
+ clevel==PROT_P?"ENC":"MIC",
out_buf.length);
memcpy(out, out_buf.value,
length=out_buf.length);
radix_error(kerror));
return(0);
}
- fprintf(cout, "%s %s", level == PROT_P ? "ENC" : "MIC", in);
+ fprintf(cout, "%s %s", clevel == PROT_P ? "ENC" : "MIC", in);
if(debug)
fprintf(stderr, "secure_command(%s)\nencoding %d bytes %s %s\n",
- cmd, length, level==PROT_P ? "ENC" : "MIC", in);
+ cmd, length, clevel==PROT_P ? "ENC" : "MIC", in);
} else fputs(cmd, cout);
fprintf(cout, "\r\n");
(void) fflush(cout);
cpend = 1;
r = getreply(!strcmp(fmt, "QUIT"));
#ifndef NOENCRYPTION
- if (r == 533 && level == PROT_P) {
+ if (r == 533 && clevel == PROT_P) {
fprintf(stderr,
"ENC command not supported at server; retrying under MIC...\n");
- level = PROT_S;
+ clevel = PROT_S;
goto again;
}
#endif
char mi[MAXPATHLEN];
char mo[MAXPATHLEN];
char *authtype;
- int lvl;
+ int clvl;
+ int dlvl;
#ifdef KRB5_KRB4_COMPAT
C_Block session;
Key_schedule schedule;
(void) strcpy(mapout, op->mo);
ip->authtype = auth_type;
auth_type = op->authtype;
- ip->lvl = level;
- level = op->lvl;
- if (!level)
- level = 1;
+ ip->clvl = clevel;
+ clevel = op->clvl;
+ ip->dlvl = dlevel;
+ dlevel = op->dlvl;
+ if (!clevel)
+ clevel = PROT_C;
+ if (!dlevel)
+ dlevel = PROT_C;
#ifdef KRB5_KRB4_COMPAT
memcpy(ip->session, cred.session, sizeof(cred.session));
memcpy(cred.session, op->session, sizeof(cred.session));
#include <sys/param.h>
extern char mapin[MAXPATHLEN]; /* input map template */
extern char mapout[MAXPATHLEN]; /* output map template */
-extern int level; /* protection level */
+extern int clevel; /* command channel protection level */
+extern int dlevel; /* data channel protection level */
extern int type; /* requested file transfer type */
extern int curtype; /* current file transfer type */
extern int stru; /* file transfer structure */
extern FILE *cout;
extern int data;
extern char *auth_type;
- extern int level;
+ extern int clevel;
+ extern int dlevel;
if (connected) {
if (cout != NULL) {
}
connected = 0;
auth_type = NULL;
- level = PROT_C;
+ clevel = dlevel = PROT_C;
}
pswitch(1);
if (connected) {
}
connected = 0;
auth_type = NULL;
- level = PROT_C;
+ clevel = dlevel = PROT_C;
}
proxflag = 0;
pswitch(0);
extern struct sockaddr_in hisaddr;
extern struct sockaddr_in myaddr;
-extern int level;
+extern int dlevel;
extern char *auth_type;
#define MAX maxbuf
{
int ret;
- if (level == PROT_C)
+ if (dlevel == PROT_C)
return(0);
if (nout)
if (ret = secure_putbuf(fd, ucbuf, nout))
char c;
FILE *stream;
{
- if (level == PROT_C)
+ if (dlevel == PROT_C)
return(putc(c,stream));
return(secure_putbyte(fileno(stream), (unsigned char) c));
}
unsigned int i;
int c;
- if (level == PROT_C)
+ if (dlevel == PROT_C)
return(write(fd,buf,nbyte));
for (i=0; nbyte>0; nbyte--)
if ((c = secure_putbyte(fd, buf[i++])) < 0)
}
if (strcmp(auth_type, "KERBEROS_V4") == 0)
- if ((length = level == PROT_P ?
+ if ((length = dlevel == PROT_P ?
krb_mk_priv(buf, (unsigned char *) outbuf, nbyte, schedule,
SESSION, &myaddr, &hisaddr)
: krb_mk_safe(buf, (unsigned char *) outbuf, nbyte, SESSION,
&myaddr, &hisaddr)) == -1) {
secure_error("krb_mk_%s failed for KERBEROS_V4",
- level == PROT_P ? "priv" : "safe");
+ dlevel == PROT_P ? "priv" : "safe");
return(ERR);
}
#endif /* KRB5_KRB4_COMPAT */
in_buf.value = buf;
in_buf.length = nbyte;
maj_stat = gss_seal(&min_stat, gcontext,
- (level == PROT_P), /* confidential */
+ (dlevel == PROT_P), /* confidential */
GSS_C_QOP_DEFAULT,
&in_buf, &conf_state,
&out_buf);
/* generally need to deal */
/* ie. should loop, but for now just fail */
secure_gss_error(maj_stat, min_stat,
- level == PROT_P?
+ dlevel == PROT_P?
"GSSAPI seal failed":
"GSSAPI sign failed");
return(ERR);
/* Other auth types go here ... */
#ifdef KRB5_KRB4_COMPAT
if (strcmp(auth_type, "KERBEROS_V4") == 0) {
- if (kerror = level == PROT_P ?
+ if (kerror = dlevel == PROT_P ?
krb_rd_priv(ucbuf, length, schedule, SESSION,
&hisaddr, &myaddr, &msg_data)
: krb_rd_safe(ucbuf, length, SESSION,
&hisaddr, &myaddr, &msg_data)) {
secure_error("krb_rd_%s failed for KERBEROS_V4 (%s)",
- level == PROT_P ? "priv" : "safe",
+ dlevel == PROT_P ? "priv" : "safe",
krb_get_err_text(kerror));
return(ERR);
}
xmit_buf.value = ucbuf;
xmit_buf.length = length;
- conf_state = (level == PROT_P);
+ conf_state = (dlevel == PROT_P);
/* decrypt/verify the message */
maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
&msg_buf, &conf_state, NULL);
if (maj_stat != GSS_S_COMPLETE) {
secure_gss_error(maj_stat, min_stat,
- (level == PROT_P)?
+ (dlevel == PROT_P)?
"failed unsealing ENC message":
"failed unsealing MIC message");
return ERR;
secure_getc(stream)
FILE *stream;
{
- if (level == PROT_C)
+ if (dlevel == PROT_C)
return(getc(stream));
return(secure_getbyte(fileno(stream)));
}
static int c;
int i;
- if (level == PROT_C)
+ if (dlevel == PROT_C)
return(read(fd,buf,nbyte));
if (c == EOF)
return(c = 0);