bugs in 4.2 and 2.9 tftp user program

satz%srijoyce at sri-unix.UUCP satz%srijoyce at sri-unix.UUCP
Sat Dec 17 19:57:26 AEST 1983


From:  Greg Satz <satz at srijoyce>


The tftp (trivial ftp) program doesn't work. It seems someone didn't
read the fine print when reading the protocol.

Index:	ucb/tftp/tftp.c ucb/tftp/main.c 4.2BSD

Description:
	The tftp program as distributed doesn't work. When trying to
	tftp a file, the first block of data is received and an ACK
	reply is sent, but subsequent data is never sent.
	Another symptom is getting an error packet from the remote
	tftp server saying last packet contained an illegal opcode.

	Since netascii format requires all line feeds to be preceeded
	by carriage return, something should be done with the carriage
	returns.

	I have only tested the get command. The only way I can get
	a file is to print out the value of sin.sin_port after it has
	been reassigned its new value. If I don't print it out, it
	acts like the assignment is never done. This seems like a C
	compile bug.

Repeat-By:
	Run tftp and try to get or put a file. Watch it loop forever
	or time-out.

Fix:
	The protocol requires that you send either a read request (RRQ)
	or write request (WRQ) to a host on port 69 (decimal). All further
	packets should be sent to the port that the tftp daemon returns not
	to port 69.

	Make the following changes to tftp.c:

*** /usr/src/ucb/tftp/tftp.c_	Thu Aug 11 22:44:53 1983
--- /usr/src/ucb/tftp/tftp.c	Sat Dec 17 00:10:25 1983
***************
*** 89,94
  				perror("tftp: recvfrom");
  				goto abort;
  			}
  			if (trace)
  				tpacket("received", tp, n);
  			/* should verify packet came from server */

--- 89,95 -----
  				perror("tftp: recvfrom");
  				goto abort;
  			}
+ 			sin.sin_port = from.sin_port;
  			if (trace)
  				tpacket("received", tp, n);
  			/* should verify packet came from server */
***************
*** 99,105
  					tp->th_msg);
  				goto abort;
  			}
! 		} while (tp->th_opcode != ACK && block != tp->th_block);
  		if (block > 0)
  			amount += size;
  		block++;

--- 100,106 -----
  					tp->th_msg);
  				goto abort;
  			}
! 		} while (tp->th_opcode != ACK || block != tp->th_block);
  		if (block > 0)
  			amount += size;
  		block++;
***************
*** 157,162
  				perror("tftp: recvfrom");
  				goto abort;
  			}
  			if (trace)
  				tpacket("received", tp, n);
  			/* should verify client address */

--- 158,164 -----
  				perror("tftp: recvfrom");
  				goto abort;
  			}
+ 			sin.sin_port = from.sin_port;
  			if (trace)
  				tpacket("received", tp, n);
  			/* should verify client address */
***************
*** 167,173
  					tp->th_msg);
  				goto abort;
  			}
! 		} while (tp->th_opcode != DATA && block != tp->th_block);
  		size = write(fd, tp->th_data, n - 4);
  		if (size < 0) {
  			nak(errno + 100);

--- 169,175 -----
  					tp->th_msg);
  				goto abort;
  			}
! 		} while (tp->th_opcode != DATA || block != tp->th_block);
  		size = write(fd, tp->th_data, n - 4);
  		if (size < 0) {
  			nak(errno + 100);


	You need to reset the original port (69 decimal) after each
	command. These changes to main.c will do that:

*** /usr/src/ucb/tftp/main.c_	Thu Aug 11 22:44:53 1983
--- /usr/src/ucb/tftp/main.c	Sat Dec 17 00:13:53 1983
***************
*** 22,27
  
  struct	sockaddr_in sin;
  int	f;
  int	trace;
  int	verbose;
  int	connected;

--- 22,28 -----
  
  struct	sockaddr_in sin;
  int	f;
+ short	port;
  int	trace;
  int	verbose;
  int	connected;
***************
*** 149,155
  		strcpy(hnamebuf, argv[1]);
  		hostname = hnamebuf;
  	}
! 	sin.sin_port = sp->s_port;
  	if (argc == 3) {
  		sin.sin_port = atoi(argv[2]);
  		if (sin.sin_port < 0) {

--- 150,156 -----
  		strcpy(hnamebuf, argv[1]);
  		hostname = hnamebuf;
  	}
! 	port = sin.sin_port = sp->s_port;
  	if (argc == 3) {
  		sin.sin_port = atoi(argv[2]);
  		if (sin.sin_port < 0) {
***************
*** 157,163
  			connected = 0;
  			return;
  		}
! 		sin.sin_port = htons((u_short)sin.sin_port);
  	}
  	connected = 1;
  }

--- 158,164 -----
  			connected = 0;
  			return;
  		}
! 		port = sin.sin_port = htons((u_short)sin.sin_port);
  	}
  	connected = 1;
  }
***************
*** 456,461
  	if (!top)
  		putchar('\n');
  	for (;;) {
  		printf("%s> ", prompt);
  		if (gets(line) == 0)
  			continue;

--- 457,463 -----
  	if (!top)
  		putchar('\n');
  	for (;;) {
+ 		sin.sin_port = port;
  		printf("%s> ", prompt);
  		if (gets(line) == 0)
  			continue;



More information about the Comp.unix.wizards mailing list