* SUCH DAMAGE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#ifndef lint
static char sccsid[] = "@(#)ftp.c 5.38 (Berkeley) 4/22/91";
#endif /* not lint */
#endif /* KRB5_KRB4_COMPAT */
#ifdef GSSAPI
#include <gssapi/gssapi.h>
+/* need to include the krb5 file, because we're doing manual fallback
+ from the v2 mech to the v2 mech. Once there's real negotiation,
+ we can be generic again. */
#include <gssapi/gssapi_generic.h>
+#include <gssapi/gssapi_krb5.h>
gss_ctx_id_t gcontext;
#endif /* GSSAPI */
-
static int kerror; /* XXX needed for all auth types */
char *auth_type; /* Authentication succeeded? If so, what type? */
user = tmp;
}
n = command("USER %s", user);
- if (n == COMPLETE)
- n = command("PASS dummy");
+ if (n == COMPLETE) {
+ /* determine if we need to send a dummy password */
+ int oldverbose = verbose;
+
+ verbose = 0;
+ if (command("PWD") != COMPLETE) {
+ verbose = oldverbose;
+ command("PASS dummy");
+ } else {
+ verbose = oldverbose;
+ }
+ }
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;
+ oldclevel = clevel;
+ 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
sigtype cmdabort();
char ibuf[FTP_BUFSIZ], obuf[FTP_BUFSIZ];
int safe = 0;
- extern char *strpbrk(), *strstr();
+#ifndef strpbrk
+ extern char *strpbrk();
+#endif
+#ifndef strstr
+ extern char *strstr();
+#endif
ibuf[0] = '\0';
if (reply_parse) reply_ptr = reply_buf;
n = '5';
} else {
if (debug) printf("%c:", safe ? 'S' : 'P');
- memcpy(ibuf, msg_data.app_data,
- msg_data.app_length);
- strcpy(&ibuf[msg_data.app_length], "\r\n");
+ if(msg_data.app_length < sizeof(ibuf) - 2) {
+ memcpy(ibuf, msg_data.app_data,
+ msg_data.app_length);
+ strcpy(&ibuf[msg_data.app_length], "\r\n");
+ } else {
+ printf("Message too long!");
+ }
continue;
}
#endif
"failed unsealing reply");
n = '5';
} else {
- memcpy(ibuf, msg_buf.value,
- msg_buf.length);
- strcpy(&ibuf[msg_buf.length], "\r\n");
+ if(msg_buf.length < sizeof(ibuf) - 2 - 1) {
+ memcpy(ibuf, msg_buf.value,
+ msg_buf.length);
+ strcpy(&ibuf[msg_buf.length], "\r\n");
+ } else {
+ user_gss_error(maj_stat, min_stat,
+ "reply was too long");
+ }
gss_release_buffer(&min_stat,&msg_buf);
continue;
}
struct stat st;
struct timeval start, stop;
register int c, d;
- FILE *fin, *dout = 0, *popen();
- int (*closefunc)(), pclose(), fclose();
- sig_t oldintr, oldintp;
- long bytes = 0, hashbytes = HASHBYTES;
- char *lmode, buf[FTP_BUFSIZ], *bufp;
+ FILE *volatile fin, *volatile dout = 0, *popen();
+ int (*volatile closefunc)(), pclose(), fclose();
+ volatile sig_t oldintr, oldintp;
+ volatile long bytes = 0, hashbytes = HASHBYTES;
+ char *volatile lmode, buf[FTP_BUFSIZ], *bufp;
sigtype abortsend();
if (verbose && printnames) {
}
recvrequest(cmd, local, remote, lmode, printnames)
- char *cmd, *local, *remote, *lmode;
+ char *cmd, *volatile local, *remote, *lmode;
{
- FILE *fout, *din = 0, *popen();
- int (*closefunc)(), pclose(), fclose();
- sig_t oldintr, oldintp;
- int is_retr, tcrflag, bare_lfs = 0;
+ FILE *volatile fout, *volatile din = 0, *popen();
+ int (*volatile closefunc)(), pclose(), fclose();
+ volatile sig_t oldintr, oldintp;
+ volatile int is_retr, tcrflag, bare_lfs = 0;
char *gunique();
static int bufsize;
static char *buf;
int blksize;
- long bytes = 0, hashbytes = HASHBYTES;
+ volatile long bytes = 0, hashbytes = HASHBYTES;
register int c, d;
struct timeval start, stop;
struct stat st;
char mi[MAXPATHLEN];
char mo[MAXPATHLEN];
char *authtype;
- int lvl;
+ int clvl;
+ int dlvl;
#ifdef KRB5_KRB4_COMPAT
C_Block session;
Key_schedule schedule;
mcase = op->mcse;
ip->ntflg = ntflag;
ntflag = op->ntflg;
- (void) strncpy(ip->nti, ntin, 16);
+ (void) strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
(ip->nti)[strlen(ip->nti)] = '\0';
- (void) strcpy(ntin, op->nti);
- (void) strncpy(ip->nto, ntout, 16);
+ (void) strncpy(ntin, op->nti, sizeof(ntin) - 1);
+ ntin[sizeof(ntin) - 1] = '\0';
+ (void) strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
(ip->nto)[strlen(ip->nto)] = '\0';
- (void) strcpy(ntout, op->nto);
+ (void) strncpy(ntout, op->nto, sizeof(ntout) - 1);
+ ntout[sizeof(ntout) - 1] = '\0';
ip->mapflg = mapflag;
mapflag = op->mapflg;
(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
(ip->mi)[strlen(ip->mi)] = '\0';
- (void) strcpy(mapin, op->mi);
+ (void) strncpy(mapin, op->mi, sizeof(mapin) - 1);
+ mapin[sizeof(mapin) - 1] = '\0';
(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
(ip->mo)[strlen(ip->mo)] = '\0';
- (void) strcpy(mapout, op->mo);
+ (void) strncpy(mapout, op->mo, sizeof(mapout) - 1);
+ mapout[sizeof(mapout) - 1] = '\0';
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));
proxtrans(cmd, local, remote)
char *cmd, *local, *remote;
{
- sig_t oldintr;
- int secndflag = 0, prox_type, nfnd;
+ volatile sig_t oldintr;
+ volatile int secndflag = 0;
+ int prox_type, nfnd;
extern jmp_buf ptabort;
- char *cmd2;
+ char *volatile cmd2;
fd_set mask;
sigtype abortpt();
fprintf(stderr, "local: %s: %s\n", local, strerror(errno));
return((char *) 0);
}
- (void) strcpy(new, local);
+ (void) strncpy(new, local, sizeof(new) - 3);
+ new[sizeof(new) - 1] = '\0';
cp = new + strlen(new);
*cp++ = '.';
while (!d) {
#endif /* KRB5_KRB4_COMPAT */
#ifdef GSSAPI
-/* for testing, we don't have an ftp key yet */
-char* gss_services[] = { "ftp", "host", 0 };
+struct {
+ const gss_OID_desc * const * mech_type;
+ char *service_name;
+} gss_trials[] = {
+ { &gss_mech_krb5, "ftp" },
+ { &gss_mech_krb5, "host" },
+};
+int n_gss_trials = sizeof(gss_trials)/sizeof(gss_trials[0]);
#endif /* GSSAPI */
do_auth()
gss_name_t target_name;
gss_buffer_desc send_tok, recv_tok, *token_ptr;
char stbuf[FTP_BUFSIZ];
- char **service_name, **end_service_name;
- int comcode;
+ int comcode, trial;
struct gss_channel_bindings_struct chan;
chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */
chan.initiator_address.length = 4;
chan.application_data.length = 0;
chan.application_data.value = 0;
- for (end_service_name = gss_services; *end_service_name; )
- end_service_name++;
- end_service_name--;
-
if (verbose)
- printf("%s accepted as authentication type\n", "GSSAPI");
+ printf("GSSAPI accepted as authentication type\n");
/* blob from gss-client */
-
- for (service_name = gss_services; *service_name; service_name++) {
-
+ for (trial = 0; trial < n_gss_trials; trial++) {
/* ftp@hostname first, the host@hostname */
/* the V5 GSSAPI binding canonicalizes this for us... */
- sprintf(stbuf, "%s@%s", *service_name, hostname);
+ sprintf(stbuf, "%s@%s", gss_trials[trial].service_name, hostname);
if (debug)
fprintf(stderr, "Trying to authenticate to <%s>\n", stbuf);
GSS_C_NO_CREDENTIAL,
&gcontext,
target_name,
- GSS_C_NULL_OID,
+ *gss_trials[trial].mech_type,
GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
(forward ? GSS_C_DELEG_FLAG : 0),
0,
if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED){
- if (service_name == end_service_name)
+ if (trial == n_gss_trials-1)
user_gss_error(maj_stat, min_stat, "initializing context");
(void) gss_release_name(&min_stat, &target_name);
/* could just be that we missed on the service name */
int len = send_tok.length;
reply_parse = "ADAT="; /* for command() later */
oldverbose = verbose;
- verbose = 0;
+ verbose = (trial == n_gss_trials-1)?0:-1;
kerror = radix_encode(send_tok.value, out_buf, &len, 0);
if (kerror) {
fprintf(stderr, "Base 64 encoding failed: %s\n",
radix_error(kerror));
} else if ((comcode = command("ADAT %s", out_buf))!=COMPLETE
/* && comcode != 3 (335)*/) {
- fprintf(stderr, "GSSAPI ADAT failed\n");
- /* force out of loop */
- maj_stat = GSS_S_FAILURE;
+ if (trial == n_gss_trials-1) {
+ fprintf(stderr, "GSSAPI ADAT failed\n");
+ /* force out of loop */
+ maj_stat = GSS_S_FAILURE;
+ }
+ /* backoff to the v1 gssapi is still possible. Send
+ a new AUTH command. If that fails, terminate the
+ loop */
+ if (command("AUTH %s", "GSSAPI") != CONTINUE) {
+ fprintf(stderr,
+ "GSSAPI ADAT failed, AUTH restart failed\n");
+ /* force out of loop */
+ maj_stat = GSS_S_FAILURE;
+ }
+ goto outer_loop;
} else if (!reply_parse) {
fprintf(stderr,
"No authentication data received from server\n");
/* get out of loop clean */
gss_complete_loop:
- service_name = end_service_name;
+ trial = n_gss_trials-1;
gss_release_buffer(&min_stat, &send_tok);
gss_release_name(&min_stat, &target_name);
goto outer_loop;
}
verbose = oldverbose;
if (maj_stat == GSS_S_COMPLETE) {
- if (verbose)
- printf("GSSAPI authentication succeeded\n");
+ printf("GSSAPI authentication succeeded\n");
reply_parse = NULL;
auth_type = "GSSAPI";
return(1);
if (verbose)
printf("%s accepted as authentication type\n", "KERBEROS_V4");
- strcpy(inst, (char *) krb_get_phost(hostname));
+ strncpy(inst, (char *) krb_get_phost(hostname), sizeof(inst) - 1);
+ inst[sizeof(inst) - 1] = '\0';
if (realm[0] == '\0')
- strcpy(realm, (char *) krb_realmofhost(hostname));
+ strncpy(realm, (char *) krb_realmofhost(hostname), sizeof(realm) - 1);
+ realm[sizeof(realm) - 1] = '\0';
if ((kerror = krb_mk_req(&ticket, service = "ftp",
inst, realm, checksum))
&& (kerror != KDC_PR_UNKNOWN ||