[2158] in Kerberos-V5-bugs
Re: gssftp secure.c bug
daemon@ATHENA.MIT.EDU (Sam Hartman)
Fri Aug 16 13:27:08 1996
To: Derrick J Brashear <shadow+@andrew.cmu.edu>
Cc: krb5-bugs@MIT.EDU
From: Sam Hartman <hartmans@MIT.EDU>
Date: 16 Aug 1996 13:26:46 -0400
In-Reply-To: Derrick J Brashear's message of Tue, 13 Aug 1996 15:03:50 -0400 (EDT)
>>>>> "Derrick" == Derrick J Brashear <shadow+@andrew.cmu.edu> writes:
Derrick> Erk. I was looking at the wrong 2 files. so: (outbuf =
Derrick> malloc((unsigned) (nbyte + FUDGE_FACTOR)))) { bufsize =
Derrick> out_buf.length;
Derrick> becomes (outbuf = malloc((unsigned) (nbyte +
Derrick> FUDGE_FACTOR)))) { bufsize = (unsigned) (nbyte +
Derrick> FUDGE_FACTOR);
Done along with a few other bugs in the same code; see the
following patch.
Derrick> -D
Index: ftp/ChangeLog
===================================================================
RCS file: /mit/krbdev/.cvsroot/src/appl/gssftp/ftp/ChangeLog,v
retrieving revision 1.7
retrieving revision 1.11
diff -c -r1.7 -r1.11
*** ChangeLog 1996/05/01 00:21:05 1.7
--- ChangeLog 1996/08/05 18:11:28 1.11
***************
*** 1,3 ****
--- 1,36 ----
+ Tue Jul 30 19:45:45 1996 Samuel D Hartman (hartmans@vorlon)
+
+ * ftp.c (empt resety): Use fd_set as a typedef not a struct.
+ Linux breaks.
+
+ Mon Jul 29 22:37:23 1996 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * secure.c: Do not assume sizeof(long) = 4 for sending lengths OTW
+
+ * configure.in: Determine sizeof short, int, long for secure.c
+
+ Fri Jul 26 20:55:12 1996 Sam Hartman <hartmans@tertius.mit.edu>
+
+ * secure.c (secure_putbyte): Reset nout to zero on errorso we
+ don't overflow our buffer.
+
+ * ftp.c (sendrequest): If there is an error in secure_write, break
+ out of the loop.
+
+ * secure.c(FUDGE_FACTOR): Define for GSSAPI so writes don't fail.
+ i chose a value of 64, which is larger than the apparent 52 bytes
+ of additional data but I'm not sure 52 is constant.
+
+ (secure_putbuf): Set bufsize to the size we actually allocate
+ Also, write foure bytes for net_len no matter how long it
+ actually is. I would rather declare it a 32-bit type but am not
+ sure whether to use the GSSAPI, krb4, or krb5 32-bit int.
+
+ Wed Jul 10 16:40:19 1996 Marc Horowitz <marc@mit.edu>
+
+ * cmdtab.c (cmdtab[]), cmds.c (delete_file): rename delete() to
+ delete_file() to avoid conflict with the dbm delete() function
+
Thu Mar 28 21:07:40 1996 Ken Raeburn <raeburn@cygnus.com>
* cmds.c (setpeer): Define unix for HP-UX.
***************
*** 13,19 ****
Mon Mar 18 12:12:44 1996 Ezra Peisach <epeisach@kangaroo.mit.edu>
* secure.c, ftp.c, ftp_var.h: Define STDARG if HAVE_STDARG_H is
! defined (in addition to the other tests)
* configure.in: Add AC_HEADER_STDARG
--- 46,52 ----
Mon Mar 18 12:12:44 1996 Ezra Peisach <epeisach@kangaroo.mit.edu>
* secure.c, ftp.c, ftp_var.h: Define STDARG if HAVE_STDARG_H is
! defined (in addition to the other tests)
* configure.in: Add AC_HEADER_STDARG
Index: ftp/cmds.c
===================================================================
RCS file: /mit/krbdev/.cvsroot/src/appl/gssftp/ftp/cmds.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -c -r1.4 -r1.5
*** cmds.c 1996/04/09 22:40:12 1.4
--- cmds.c 1996/07/22 20:21:32 1.5
***************
*** 1243,1249 ****
/*
* Delete a single file.
*/
! delete(argc, argv)
int argc;
char *argv[];
{
--- 1243,1249 ----
/*
* Delete a single file.
*/
! delete_file(argc, argv)
int argc;
char *argv[];
{
Index: ftp/cmdtab.c
===================================================================
RCS file: /mit/krbdev/.cvsroot/src/appl/gssftp/ftp/cmdtab.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -c -r1.1 -r1.2
*** cmdtab.c 1996/01/14 08:32:41 1.1
--- cmdtab.c 1996/07/22 20:21:34 1.2
***************
*** 50,56 ****
int setprivate();
#endif
int disconnect(), restart(), reget(), syst();
! int cd(), lcd(), delete(), mdelete(), user();
int ls(), mls(), get(), mget(), help(), append(), put(), mput();
int quit(), renamefile(), status();
int quote(), rmthelp(), shell(), site();
--- 50,56 ----
int setprivate();
#endif
int disconnect(), restart(), reget(), syst();
! int cd(), lcd(), delete_file(), mdelete(), user();
int ls(), mls(), get(), mget(), help(), append(), put(), mput();
int quit(), renamefile(), status();
int quote(), rmthelp(), shell(), site();
***************
*** 154,160 ****
{ "clear", clearhelp, 0, 1, 1, setclear },
{ "close", disconhelp, 0, 1, 1, disconnect },
{ "cr", crhelp, 0, 0, 0, setcr },
! { "delete", deletehelp, 0, 1, 1, delete },
{ "debug", debughelp, 0, 0, 0, setdebug },
{ "dir", dirhelp, 1, 1, 1, ls },
{ "disconnect", disconhelp, 0, 1, 1, disconnect },
--- 154,160 ----
{ "clear", clearhelp, 0, 1, 1, setclear },
{ "close", disconhelp, 0, 1, 1, disconnect },
{ "cr", crhelp, 0, 0, 0, setcr },
! { "delete", deletehelp, 0, 1, 1, delete_file },
{ "debug", debughelp, 0, 0, 0, setdebug },
{ "dir", dirhelp, 1, 1, 1, ls },
{ "disconnect", disconhelp, 0, 1, 1, disconnect },
Index: ftp/configure.in
===================================================================
RCS file: /mit/krbdev/.cvsroot/src/appl/gssftp/ftp/configure.in,v
retrieving revision 1.6
retrieving revision 1.7
diff -c -r1.6 -r1.7
*** configure.in 1996/03/19 02:09:58 1.6
--- configure.in 1996/07/30 02:39:18 1.7
***************
*** 7,12 ****
--- 7,15 ----
CHECK_SIGPROCMASK
CHECK_WAIT_TYPE
DECLARE_SYS_ERRLIST
+ AC_CHECK_SIZEOF(short)
+ AC_CHECK_SIZEOF(int)
+ AC_CHECK_SIZEOF(long)
AC_FUNC_VFORK
AC_HAVE_FUNCS(getcwd getdtablesize)
AC_HEADER_STDARG
Index: ftp/ftp.c
===================================================================
RCS file: /mit/krbdev/.cvsroot/src/appl/gssftp/ftp/ftp.c,v
retrieving revision 1.8
retrieving revision 1.10
diff -c -r1.8 -r1.10
*** ftp.c 1996/03/19 02:10:00 1.8
--- ftp.c 1996/08/05 18:11:31 1.10
***************
*** 696,709 ****
}
empty(mask, sec)
! struct fd_set *mask;
int sec;
{
struct timeval t;
t.tv_sec = (long) sec;
t.tv_usec = 0;
! return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
}
jmp_buf sendabort;
--- 696,709 ----
}
empty(mask, sec)
! fd_set *mask;
int sec;
{
struct timeval t;
t.tv_sec = (long) sec;
t.tv_usec = 0;
! return(select(32, mask, (fd_set *) 0, (fd_set *) 0, &t));
}
jmp_buf sendabort;
***************
*** 892,897 ****
--- 892,899 ----
}
(void) fflush(stdout);
}
+ if (d <= 0 )
+ break;
}
if (hash && bytes > 0) {
if (bytes < HASHBYTES)
***************
*** 1640,1646 ****
int secndflag = 0, prox_type, nfnd;
extern jmp_buf ptabort;
char *cmd2;
! struct fd_set mask;
sigtype abortpt();
if (strcmp(cmd, "RETR"))
--- 1642,1648 ----
int secndflag = 0, prox_type, nfnd;
extern jmp_buf ptabort;
char *cmd2;
! fd_set mask;
sigtype abortpt();
if (strcmp(cmd, "RETR"))
***************
*** 1755,1761 ****
reset()
{
! struct fd_set mask;
int nfnd = 1;
FD_ZERO(&mask);
--- 1757,1763 ----
reset()
{
! fd_set mask;
int nfnd = 1;
FD_ZERO(&mask);
***************
*** 2077,2083 ****
{
char buf[FTP_BUFSIZ];
int nfnd;
! struct fd_set mask;
/*
* send IAC in urgent mode instead of DM because 4.3BSD places oob mark
--- 2079,2085 ----
{
char buf[FTP_BUFSIZ];
int nfnd;
! fd_set mask;
/*
* send IAC in urgent mode instead of DM because 4.3BSD places oob mark
Index: ftp/secure.c
===================================================================
RCS file: /mit/krbdev/.cvsroot/src/appl/gssftp/ftp/secure.c,v
retrieving revision 1.5
retrieving revision 1.7
diff -c -r1.5 -r1.7
*** secure.c 1996/04/09 22:40:14 1.5
--- secure.c 1996/07/30 02:39:19 1.7
***************
*** 35,40 ****
--- 35,52 ----
extern char *sys_errlist[];
#endif
+ #if (SIZEOF_SHORT == 4)
+ typedef unsigned short ftp_uint32;
+ typedef short ftp_int32;
+ #elif (SIZEOF_INT == 4)
+ typedef unsigned int ftp_uint32;
+ typedef int ftp_int32;
+ #elif (SIZEOF_LONG == 4)
+ typedef unsigned long ftp_uint32;
+ typedef long ftp_int32;
+ #endif
+
+
extern struct sockaddr_in hisaddr;
extern struct sockaddr_in myaddr;
extern int level;
***************
*** 54,59 ****
--- 66,75 ----
*/
#endif /* KERBEROS */
+ #ifdef GSSAPI
+ #define FUDGE_FACTOR 64 /*It appears to add 52 byts, but I'm not usre it is a constant--hartmans*/
+ #endif /*GSSAPI*/
+
#ifndef FUDGE_FACTOR /* In case no auth types define it. */
#define FUDGE_FACTOR 0
#endif
***************
*** 136,146 ****
int ret;
ucbuf[nout++] = c;
! if (nout == MAX - FUDGE_FACTOR)
! if (ret = secure_putbuf(fd, ucbuf, nout))
! return(ret);
! else nout = 0;
! return(c);
}
/* returns:
--- 152,163 ----
int ret;
ucbuf[nout++] = c;
! if (nout == MAX - FUDGE_FACTOR) {
! ret = secure_putbuf(fd, ucbuf, nout);
! nout = 0;
! return(ret?ret:c);
! }
! return (c);
}
/* returns:
***************
*** 202,215 ****
* -2 on security error
*/
secure_putbuf(fd, buf, nbyte)
! int fd;
unsigned char *buf;
unsigned int nbyte;
{
! static char *outbuf; /* output ciphertext */
static unsigned int bufsize; /* size of outbuf */
! long length;
! u_long net_len;
/* Other auth types go here ... */
#ifdef KERBEROS
--- 219,232 ----
* -2 on security error
*/
secure_putbuf(fd, buf, nbyte)
! int fd;
unsigned char *buf;
unsigned int nbyte;
{
! static char *outbuf; /* output ciphertext */
static unsigned int bufsize; /* size of outbuf */
! ftp_int32 length;
! ftp_uint32 net_len;
/* Other auth types go here ... */
#ifdef KERBEROS
***************
*** 217,223 ****
if (outbuf?
(outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
(outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
! bufsize = nbyte + FUDGE_FACTOR;
} else {
bufsize = 0;
secure_error("%s (in malloc of PROT buffer)",
--- 234,240 ----
if (outbuf?
(outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
(outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
! bufsize = out_buf.length;
} else {
bufsize = 0;
secure_error("%s (in malloc of PROT buffer)",
***************
*** 278,284 ****
}
#endif /* GSSAPI */
net_len = htonl((u_long) length);
! if (looping_write(fd, &net_len, sizeof(net_len)) == -1) return(-1);
if (looping_write(fd, outbuf, length) != length) return(-1);
return(0);
}
--- 295,301 ----
}
#endif /* GSSAPI */
net_len = htonl((u_long) length);
! if (looping_write(fd, &net_len, 4) == -1) return(-1);
if (looping_write(fd, outbuf, length) != length) return(-1);
return(0);
}
***************
*** 290,296 ****
/* number of chars in ucbuf, pointer into ucbuf */
static unsigned int nin, bufp;
int kerror;
! u_long length;
if (nin == 0) {
if ((kerror = looping_read(fd, &length, sizeof(length)))
--- 307,313 ----
/* number of chars in ucbuf, pointer into ucbuf */
static unsigned int nin, bufp;
int kerror;
! ftp_uint32 length;
if (nin == 0) {
if ((kerror = looping_read(fd, &length, sizeof(length)))
Index: ftpd/ChangeLog
===================================================================
RCS file: /mit/krbdev/.cvsroot/src/appl/gssftp/ftpd/ChangeLog,v
retrieving revision 1.11
retrieving revision 1.15
diff -c -r1.11 -r1.15
*** ChangeLog 1996/06/03 20:16:56 1.11
--- ChangeLog 1996/07/30 02:40:08 1.15
***************
*** 1,3 ****
--- 1,25 ----
+ Mon Jul 29 22:37:05 1996 Ezra Peisach <epeisach@kangaroo.mit.edu>
+
+ * configure.in: Determine sizeof short, int, long for secure.c
+
+ Tue Jul 23 23:13:07 1996 Marc Horowitz <marc@mit.edu>
+
+ * ftpd.c (auth_data): the logic which dealt with multiple acceptor
+ names and fallback was just broken.
+
+ Wed Jul 10 16:38:01 1996 Marc Horowitz <marc@mit.edu>
+
+ * ftpd.c (store), ftpcmd.y (STOR, APPE, STOU): rename store() to
+ store_file() to avoid conflict with dbm store() function
+ * ftpd.c (delete), ftpcmd.y (DELE): rename delete() to
+ delete_file() to avoid conflict with the dbm delete() function
+
+ Thu Jun 13 18:35:19 1996 Kevin L Mitchell <klmitch@mit.edu>
+
+ * ftpd.c (authdata): misplaced braces caused server to not be able to
+ use ftp principle if it was present. Client looks for ftp
+ first, then tries host; ftpd was looking only for host.
+
Mon Jun 3 16:12:59 1996 Tom Yu <tlyu@mit.edu>
* Makefile.in, configure.in: back out previous changes and use
Index: ftpd/configure.in
===================================================================
RCS file: /mit/krbdev/.cvsroot/src/appl/gssftp/ftpd/configure.in,v
retrieving revision 1.8
retrieving revision 1.9
diff -c -r1.8 -r1.9
*** configure.in 1996/06/03 20:17:01 1.8
--- configure.in 1996/07/30 02:40:10 1.9
***************
*** 7,12 ****
--- 7,15 ----
CHECK_UTMP
CHECK_SIGPROCMASK
CHECK_WAIT_TYPE
+ AC_CHECK_SIZEOF(short)
+ AC_CHECK_SIZEOF(int)
+ AC_CHECK_SIZEOF(long)
DECLARE_SYS_ERRLIST
AC_FUNC_VFORK
AC_HEADER_STDARG
Index: ftpd/ftpcmd.y
===================================================================
RCS file: /mit/krbdev/.cvsroot/src/appl/gssftp/ftpd/ftpcmd.y,v
retrieving revision 1.4
retrieving revision 1.5
diff -c -r1.4 -r1.5
*** ftpcmd.y 1996/05/01 01:50:53 1.4
--- ftpcmd.y 1996/07/22 20:21:40 1.5
***************
*** 338,351 ****
| STOR check_login SP pathname CRLF
= {
if ($2 && $4 != NULL)
! store((char *) $4, "w", 0);
if ($4 != NULL)
free((char *) $4);
}
| APPE check_login SP pathname CRLF
= {
if ($2 && $4 != NULL)
! store((char *) $4, "a", 0);
if ($4 != NULL)
free((char *) $4);
}
--- 338,351 ----
| STOR check_login SP pathname CRLF
= {
if ($2 && $4 != NULL)
! store_file((char *) $4, "w", 0);
if ($4 != NULL)
free((char *) $4);
}
| APPE check_login SP pathname CRLF
= {
if ($2 && $4 != NULL)
! store_file((char *) $4, "a", 0);
if ($4 != NULL)
free((char *) $4);
}
***************
*** 387,393 ****
| DELE check_login SP pathname CRLF
= {
if ($2 && $4 != NULL)
! delete((char *) $4);
if ($4 != NULL)
free((char *) $4);
}
--- 387,393 ----
| DELE check_login SP pathname CRLF
= {
if ($2 && $4 != NULL)
! delete_file((char *) $4);
if ($4 != NULL)
free((char *) $4);
}
***************
*** 535,541 ****
| STOU check_login SP pathname CRLF
= {
if ($2 && $4 != NULL)
! store((char *) $4, "w", 1);
if ($4 != NULL)
free((char *) $4);
}
--- 535,541 ----
| STOU check_login SP pathname CRLF
= {
if ($2 && $4 != NULL)
! store_file((char *) $4, "w", 1);
if ($4 != NULL)
free((char *) $4);
}
Index: ftpd/ftpd.c
===================================================================
RCS file: /mit/krbdev/.cvsroot/src/appl/gssftp/ftpd/ftpd.c,v
retrieving revision 1.9
retrieving revision 1.12
diff -c -r1.9 -r1.12
*** ftpd.c 1996/04/09 22:40:18 1.9
--- ftpd.c 1996/07/24 03:15:05 1.12
***************
*** 923,929 ****
(*closefunc)(fin);
}
! store(name, mode, unique)
char *name, *mode;
int unique;
{
--- 923,929 ----
(*closefunc)(fin);
}
! store_file(name, mode, unique)
char *name, *mode;
int unique;
{
***************
*** 1549,1555 ****
reply(500, "'%s': command not understood.", cbuf);
}
! delete(name)
char *name;
{
struct stat st;
--- 1549,1555 ----
reply(500, "'%s': command not understood.", cbuf);
}
! delete_file(name)
char *name;
{
struct stat st;
***************
*** 1832,1844 ****
char buf[FTP_BUFSIZ];
u_char out_buf[sizeof(buf)];
#endif /* KERBEROS */
- #ifdef GSSAPI
- OM_uint32 maj_stat, min_stat;
- gss_OID mechid;
- gss_buffer_desc tok, out_tok;
- char gbuf[FTP_BUFSIZ];
- u_char gout_buf[sizeof(gbuf)];
- #endif
if (auth_type) {
reply(503, "Authentication already established");
--- 1832,1837 ----
***************
*** 1849,2070 ****
return(0);
}
#ifdef KERBEROS
! if (strcmp(temp_auth_type, "KERBEROS_V4") == 0) {
! if (kerror = radix_encode(data, out_buf, &length, 1)) {
! reply(501, "Couldn't decode ADAT (%s)",
! radix_error(kerror));
! syslog(LOG_ERR, "Couldn't decode ADAT (%s)",
! radix_error(kerror));
! return(0);
! }
! (void) memcpy((char *)ticket.dat, (char *)out_buf, ticket.length = length);
! strcpy(instance, "*");
! if (!service) {
! char realm[REALM_SZ];
! des_cblock key;
!
! service = "ftp";
! if (krb_get_lrealm(realm, 1) == KSUCCESS &&
! read_service_key(service, instance, realm, 0, keyfile, key))
! service = "rcmd";
! else (void) memset(key, 0, sizeof(key));
! }
! if (kerror = krb_rd_req(&ticket, service, instance,
! his_addr.sin_addr.s_addr, &kdata, keyfile)) {
! secure_error("ADAT: Kerberos V4 krb_rd_req: %s",
! krb_get_err_text(kerror));
! return(0);
! }
! /* add one to the (formerly) sealed checksum, and re-seal it */
! cksum = kdata.checksum + 1;
! cksum = htonl(cksum);
! key_sched(kdata.session,schedule);
! if ((length = krb_mk_safe((u_char *)&cksum, out_buf, sizeof(cksum),
! &kdata.session,&ctrl_addr, &his_addr)) == -1) {
! secure_error("ADAT: krb_mk_safe failed");
! return(0);
! }
! if (kerror = radix_encode(out_buf, buf, &length, 0)) {
! secure_error("Couldn't encode ADAT reply (%s)",
! radix_error(kerror));
! return(0);
}
- reply(235, "ADAT=%s", buf);
- /* Kerberos V4 authentication succeeded */
- auth_type = temp_auth_type;
- temp_auth_type = NULL;
- return(1);
- }
#endif /* KERBEROS */
#ifdef GSSAPI
! if (strcmp(temp_auth_type, "GSSAPI") == 0) {
! int replied = 0;
! int found = 0;
! gss_cred_id_t server_creds;
! gss_name_t client;
! int ret_flags;
! struct gss_channel_bindings_struct chan;
! gss_buffer_desc name_buf;
! gss_name_t server_name;
! OM_uint32 maj_stat, min_stat, save_stat;
! char localname[MAXHOSTNAMELEN];
! char service_name[MAXHOSTNAMELEN+10];
! char **service;
! struct hostent *hp;
!
! chan.initiator_addrtype = GSS_C_AF_INET;
! chan.initiator_address.length = 4;
! chan.initiator_address.value = &his_addr.sin_addr.s_addr;
! chan.acceptor_addrtype = GSS_C_AF_INET;
! chan.acceptor_address.length = 4;
! chan.acceptor_address.value = &ctrl_addr.sin_addr.s_addr;
! chan.application_data.length = 0;
! chan.application_data.value = 0;
!
! if (kerror = radix_encode(data, gout_buf, &length, 1)) {
! reply(501, "Couldn't decode ADAT (%s)",
! radix_error(kerror));
! syslog(LOG_ERR, "Couldn't decode ADAT (%s)",
! radix_error(kerror));
! return(0);
! }
! tok.value = gout_buf;
! tok.length = length;
!
! if (gethostname(localname, MAXHOSTNAMELEN)) {
! reply(501, "couldn't get local hostname (%d)\n", errno);
! syslog(LOG_ERR, "Couldn't get local hostname (%d)", errno);
! return 0;
! }
! if (!(hp = gethostbyname(localname))) {
! extern int h_errno;
! reply(501, "couldn't canonicalize local hostname (%d)\n", h_errno);
! syslog(LOG_ERR, "Couldn't canonicalize local hostname (%d)", h_errno);
! return 0;
! }
! strcpy(localname, hp->h_name);
!
! for (service = gss_services; *service; service++) {
! sprintf(service_name, "%s@%s", *service, localname);
! name_buf.value = service_name;
! name_buf.length = strlen(name_buf.value) + 1;
! if (debug) syslog(LOG_INFO, "importing <%s>", service_name);
! maj_stat = gss_import_name(&min_stat, &name_buf,
! gss_nt_service_name,
! &server_name);
! if (maj_stat != GSS_S_COMPLETE) {
! reply_gss_error(501, maj_stat, min_stat,
! "importing name");
! syslog(LOG_ERR, "gssapi error importing name");
return 0;
}
! maj_stat = gss_acquire_cred(&min_stat, server_name, 0,
! GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
! &server_creds, NULL, NULL);
! save_stat = min_stat;
! (void) gss_release_name(&min_stat, &server_name);
! if (maj_stat != GSS_S_COMPLETE)
! continue;
! found++;
! }
! if (!found && (maj_stat != GSS_S_COMPLETE))
! {
! min_stat = save_stat;
! reply_gss_error(501, maj_stat, min_stat,
"acquiring credentials");
syslog(LOG_ERR, "gssapi error acquiring credentials");
return 0;
}
- if (server_creds == GSS_C_NO_CREDENTIAL) {
- syslog(LOG_ERR, "acquire return GSS_C_NO_CREDENTIAL");
- }
-
! gcontext = GSS_C_NO_CONTEXT;
!
! maj_stat = gss_accept_sec_context(&min_stat,
! &gcontext, /* context_handle */
! server_creds, /* verifier_cred_handle */
! &tok, /* input_token */
! &chan, /* channel bindings */
! &client, /* src_name */
! &mechid, /* mech_type */
! &out_tok, /* output_token */
! &ret_flags,
! NULL, /* ignore time_rec */
! NULL /* ignore del_cred_handle */
! );
! if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
! reply_gss_error(535, maj_stat, min_stat,
! "accepting context");
! syslog(LOG_ERR, "failed accepting context");
! (void) gss_release_cred(&min_stat, &server_creds);
! return 0;
! }
!
! if (out_tok.length) {
! if (kerror = radix_encode(out_tok.value, gbuf, &out_tok.length, 0)) {
! secure_error("Couldn't encode ADAT reply (%s)",
! radix_error(kerror));
! syslog(LOG_ERR, "couldn't encode ADAT reply");
! return(0);
}
! if (maj_stat == GSS_S_COMPLETE) {
! reply(235, "ADAT=%s", gbuf);
! replied = 1;
} else {
- /* If the server accepts the security data, and
- requires additional data, it should respond with
- reply code 335. */
- reply(335, "ADAT=%s", gbuf);
- }
- (void) gss_release_buffer(&min_stat, &out_tok);
- }
- if (maj_stat == GSS_S_COMPLETE) {
- /* GSSAPI authentication succeeded */
- maj_stat = gss_display_name(&min_stat, client, &client_name,
- &mechid);
- if (maj_stat != GSS_S_COMPLETE) {
/* "If the server rejects the security data (if
! a checksum fails, for instance), it should
! respond with reply code 535." */
! reply_gss_error(535, maj_stat, min_stat,
! "extracting GSSAPI identity name");
! syslog(LOG_ERR, "gssapi error extracting identity");
! (void) gss_release_cred(&min_stat, &server_creds);
! return 0;
}
- /* If the server accepts the security data, but does
- not require any additional data (i.e., the security
- data exchange has completed successfully), it must
- respond with reply code 235. */
- if (!replied) reply(235, "GSSAPI Authentication succeeded");
-
- auth_type = temp_auth_type;
- temp_auth_type = NULL;
-
- (void) gss_release_cred(&min_stat, &server_creds);
- return(1);
- } else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
- /* If the server accepts the security data, and
- requires additional data, it should respond with
- reply code 335. */
- reply(335, "more data needed");
- (void) gss_release_cred(&min_stat, &server_creds);
- return(0);
- } else {
- /* "If the server rejects the security data (if
- a checksum fails, for instance), it should
- respond with reply code 535." */
- reply_gss_error(535, maj_stat, min_stat,
- "GSSAPI failed processing ADAT");
- syslog(LOG_ERR, "GSSAPI failed processing ADAT");
- (void) gss_release_cred(&min_stat, &server_creds);
- return(0);
}
- }
#endif /* GSSAPI */
/* Other auth types go here ... */
/* Also need to check authorization, but that is done in user() */
--- 1842,2068 ----
return(0);
}
#ifdef KERBEROS
! if (strcmp(temp_auth_type, "KERBEROS_V4") == 0) {
! if (kerror = radix_encode(data, out_buf, &length, 1)) {
! reply(501, "Couldn't decode ADAT (%s)",
! radix_error(kerror));
! syslog(LOG_ERR, "Couldn't decode ADAT (%s)",
! radix_error(kerror));
! return(0);
! }
! (void) memcpy((char *)ticket.dat, (char *)out_buf, ticket.length = length);
! strcpy(instance, "*");
! if (!service) {
! char realm[REALM_SZ];
! des_cblock key;
!
! service = "ftp";
! if (krb_get_lrealm(realm, 1) == KSUCCESS &&
! read_service_key(service, instance, realm, 0, keyfile, key))
! service = "rcmd";
! else
! (void) memset(key, 0, sizeof(key));
! }
! if (kerror = krb_rd_req(&ticket, service, instance,
! his_addr.sin_addr.s_addr, &kdata, keyfile)) {
! secure_error("ADAT: Kerberos V4 krb_rd_req: %s",
! krb_get_err_text(kerror));
! return(0);
! }
! /* add one to the (formerly) sealed checksum, and re-seal it */
! cksum = kdata.checksum + 1;
! cksum = htonl(cksum);
! key_sched(kdata.session,schedule);
! if ((length = krb_mk_safe((u_char *)&cksum, out_buf, sizeof(cksum),
! &kdata.session,&ctrl_addr, &his_addr)) == -1) {
! secure_error("ADAT: krb_mk_safe failed");
! return(0);
! }
! if (kerror = radix_encode(out_buf, buf, &length, 0)) {
! secure_error("Couldn't encode ADAT reply (%s)",
! radix_error(kerror));
! return(0);
! }
! reply(235, "ADAT=%s", buf);
! /* Kerberos V4 authentication succeeded */
! auth_type = temp_auth_type;
! temp_auth_type = NULL;
! return(1);
}
#endif /* KERBEROS */
#ifdef GSSAPI
! if (strcmp(temp_auth_type, "GSSAPI") == 0) {
! int replied = 0;
! int found = 0;
! gss_cred_id_t server_creds;
! gss_name_t client;
! int ret_flags;
! struct gss_channel_bindings_struct chan;
! gss_buffer_desc name_buf;
! gss_name_t server_name;
! OM_uint32 acquire_maj, acquire_min, accept_maj, accept_min,
! stat_maj, stat_min;
! gss_OID mechid;
! gss_buffer_desc tok, out_tok;
! char gbuf[FTP_BUFSIZ];
! u_char gout_buf[FTP_BUFSIZ];
! char localname[MAXHOSTNAMELEN];
! char service_name[MAXHOSTNAMELEN+10];
! char **service;
! struct hostent *hp;
!
! chan.initiator_addrtype = GSS_C_AF_INET;
! chan.initiator_address.length = 4;
! chan.initiator_address.value = &his_addr.sin_addr.s_addr;
! chan.acceptor_addrtype = GSS_C_AF_INET;
! chan.acceptor_address.length = 4;
! chan.acceptor_address.value = &ctrl_addr.sin_addr.s_addr;
! chan.application_data.length = 0;
! chan.application_data.value = 0;
!
! if (kerror = radix_encode(data, gout_buf, &length, 1)) {
! reply(501, "Couldn't decode ADAT (%s)",
! radix_error(kerror));
! syslog(LOG_ERR, "Couldn't decode ADAT (%s)",
! radix_error(kerror));
! return(0);
! }
! tok.value = gout_buf;
! tok.length = length;
!
! if (gethostname(localname, MAXHOSTNAMELEN)) {
! reply(501, "couldn't get local hostname (%d)\n", errno);
! syslog(LOG_ERR, "Couldn't get local hostname (%d)", errno);
! return 0;
! }
! if (!(hp = gethostbyname(localname))) {
! extern int h_errno;
! reply(501, "couldn't canonicalize local hostname (%d)\n", h_errno);
! syslog(LOG_ERR, "Couldn't canonicalize local hostname (%d)", h_errno);
return 0;
}
+ strcpy(localname, hp->h_name);
! for (service = gss_services; *service; service++) {
! sprintf(service_name, "%s@%s", *service, localname);
! name_buf.value = service_name;
! name_buf.length = strlen(name_buf.value) + 1;
! if (debug)
! syslog(LOG_INFO, "importing <%s>", service_name);
! stat_maj = gss_import_name(&stat_min, &name_buf,
! gss_nt_service_name,
! &server_name);
! if (stat_maj != GSS_S_COMPLETE) {
! reply_gss_error(501, stat_maj, stat_min,
! "importing name");
! syslog(LOG_ERR, "gssapi error importing name");
! return 0;
! }
!
! acquire_maj = gss_acquire_cred(&acquire_min, server_name, 0,
! GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
! &server_creds, NULL, NULL);
! (void) gss_release_name(&stat_min, &server_name);
!
! if (acquire_maj != GSS_S_COMPLETE)
! continue;
!
! found++;
!
! gcontext = GSS_C_NO_CONTEXT;
!
! accept_maj = gss_accept_sec_context(&accept_min,
! &gcontext, /* context_handle */
! server_creds, /* verifier_cred_handle */
! &tok, /* input_token */
! &chan, /* channel bindings */
! &client, /* src_name */
! &mechid, /* mech_type */
! &out_tok, /* output_token */
! &ret_flags,
! NULL, /* ignore time_rec */
! NULL /* ignore del_cred_handle */
! );
! if (accept_maj!=GSS_S_COMPLETE && accept_maj!=GSS_S_CONTINUE_NEEDED)
! continue;
! }
! if (found) {
! if (accept_maj!=GSS_S_COMPLETE && accept_maj!=GSS_S_CONTINUE_NEEDED) {
! reply_gss_error(535, accept_maj, accept_min,
! "accepting context");
! syslog(LOG_ERR, "failed accepting context");
! (void) gss_release_cred(&stat_min, &server_creds);
! return 0;
! }
! } else {
! reply_gss_error(501, stat_maj, stat_min,
"acquiring credentials");
syslog(LOG_ERR, "gssapi error acquiring credentials");
return 0;
}
! if (out_tok.length) {
! if (kerror = radix_encode(out_tok.value, gbuf, &out_tok.length, 0)) {
! secure_error("Couldn't encode ADAT reply (%s)",
! radix_error(kerror));
! syslog(LOG_ERR, "couldn't encode ADAT reply");
! return(0);
! }
! if (stat_maj == GSS_S_COMPLETE) {
! reply(235, "ADAT=%s", gbuf);
! replied = 1;
! } else {
! /* If the server accepts the security data, and
! requires additional data, it should respond with
! reply code 335. */
! reply(335, "ADAT=%s", gbuf);
! }
! (void) gss_release_buffer(&stat_min, &out_tok);
}
! if (stat_maj == GSS_S_COMPLETE) {
! /* GSSAPI authentication succeeded */
! stat_maj = gss_display_name(&stat_min, client, &client_name,
! &mechid);
! if (stat_maj != GSS_S_COMPLETE) {
! /* "If the server rejects the security data (if
! a checksum fails, for instance), it should
! respond with reply code 535." */
! reply_gss_error(535, stat_maj, stat_min,
! "extracting GSSAPI identity name");
! syslog(LOG_ERR, "gssapi error extracting identity");
! (void) gss_release_cred(&stat_min, &server_creds);
! return 0;
! }
! /* If the server accepts the security data, but does
! not require any additional data (i.e., the security
! data exchange has completed successfully), it must
! respond with reply code 235. */
! if (!replied) reply(235, "GSSAPI Authentication succeeded");
!
! auth_type = temp_auth_type;
! temp_auth_type = NULL;
!
! (void) gss_release_cred(&stat_min, &server_creds);
! return(1);
! } else if (stat_maj == GSS_S_CONTINUE_NEEDED) {
! /* If the server accepts the security data, and
! requires additional data, it should respond with
! reply code 335. */
! reply(335, "more data needed");
! (void) gss_release_cred(&stat_min, &server_creds);
! return(0);
} else {
/* "If the server rejects the security data (if
! a checksum fails, for instance), it should
! respond with reply code 535." */
! reply_gss_error(535, stat_maj, stat_min,
! "GSSAPI failed processing ADAT");
! syslog(LOG_ERR, "GSSAPI failed processing ADAT");
! (void) gss_release_cred(&stat_min, &server_creds);
! return(0);
}
}
#endif /* GSSAPI */
/* Other auth types go here ... */
/* Also need to check authorization, but that is done in user() */