/* tftpd.c 4.8 83/05/03 */
* Trivial file transfer protocol server.
struct sockaddr_in sin
= { AF_INET
};
register struct tftphdr
*tp
;
sp
= getservbyname("tftp", "udp");
fprintf(stderr
, "tftpd: udp/tftp: unknown service\n");
sin
.sin_port
= sp
->s_port
;
{ int t
= open("/dev/tty", 2);
ioctl(t
, TIOCNOTTY
, (char *)0);
f
= socket(AF_INET
, SOCK_DGRAM
, 0, 0);
while (bind(f
, (caddr_t
)&sin
, sizeof (sin
), 0) < 0) {
n
= recvfrom(f
, buf
, sizeof (buf
), 0, (caddr_t
)&from
, &fromlen
);
perror("tftpd: recvfrom");
tp
= (struct tftphdr
*)buf
;
tp
->th_opcode
= ntohs(tp
->th_opcode
);
if (tp
->th_opcode
== RRQ
|| tp
->th_opcode
== WRQ
)
while (wait3(status
, WNOHANG
, 0) > 0)
int sendfile(), recvfile();
{ "netascii", validate_access
, sendfile
, recvfile
},
{ "octet", validate_access
, sendfile
, recvfile
},
{ "mail", validate_user
, sendmail
, recvmail
},
int fd
; /* file being transferred */
* Handle initial connection protocol.
struct sockaddr_in
*client
;
register struct formats
*pf
;
if (connect(f
, (caddr_t
)client
, sizeof (*client
), 0) < 0) {
filename
= cp
= tp
->th_stuff
;
while (cp
< buf
+ size
) {
for (cp
= mode
; *cp
; cp
++)
for (pf
= formats
; pf
->f_mode
; pf
++)
if (strcmp(pf
->f_mode
, mode
) == 0)
ecode
= (*pf
->f_validate
)(filename
, client
, tp
->th_opcode
);
if (tp
->th_opcode
== WRQ
)
* Validate file access. Since we
* have no uid or gid, for now require
* file to exist and be publicly
* Note also, full path name must be
* given as we have no login directory.
validate_access(file
, client
, mode
)
struct sockaddr_in
*client
;
if (stat(file
, &stbuf
) < 0)
return (errno
== ENOENT
? ENOTFOUND
: EACCESS
);
if ((stbuf
.st_mode
&(S_IREAD
>> 6)) == 0)
if ((stbuf
.st_mode
&(S_IWRITE
>> 6)) == 0)
fd
= open(file
, mode
== RRQ
? 0 : 1);
if (timeout
>= MAXTIMEOUT
)
* Send the requested file.
register struct tftphdr
*tp
;
register int block
= 1, size
, n
;
tp
= (struct tftphdr
*)buf
;
size
= read(fd
, tp
->th_data
, SEGSIZE
);
tp
->th_opcode
= htons((u_short
)DATA
);
tp
->th_block
= htons((u_short
)block
);
if (write(f
, buf
, size
+ 4) != size
+ 4) {
n
= read(f
, buf
, sizeof (buf
));
tp
->th_opcode
= ntohs((u_short
)tp
->th_opcode
);
tp
->th_block
= ntohs((u_short
)tp
->th_block
);
if (tp
->th_opcode
== ERROR
)
if (tp
->th_opcode
!= ACK
|| tp
->th_block
!= block
)
} while (size
== SEGSIZE
);
register struct tftphdr
*tp
;
register int block
= 0, n
, size
;
tp
= (struct tftphdr
*)buf
;
tp
->th_opcode
= htons((u_short
)ACK
);
tp
->th_block
= htons((u_short
)block
);
if (write(f
, buf
, 4) != 4) {
n
= read(f
, buf
, sizeof (buf
));
tp
->th_opcode
= ntohs((u_short
)tp
->th_opcode
);
tp
->th_block
= ntohs((u_short
)tp
->th_block
);
if (tp
->th_opcode
== ERROR
)
if (tp
->th_opcode
!= DATA
|| block
!= tp
->th_block
)
size
= write(fd
, tp
->th_data
, n
- 4);
} while (size
== SEGSIZE
);
tp
->th_opcode
= htons((u_short
)ACK
);
tp
->th_block
= htons((u_short
)(block
));
{ EUNDEF
, "Undefined error code" },
{ ENOTFOUND
, "File not found" },
{ EACCESS
, "Access violation" },
{ ENOSPACE
, "Disk full or allocation exceeded" },
{ EBADOP
, "Illegal TFTP operation" },
{ EBADID
, "Unknown transfer ID" },
{ EEXISTS
, "File already exists" },
{ ENOUSER
, "No such user" },
* Send a nak packet (error message).
* Error code passed in is one of the
* standard TFTP codes, or a UNIX errno
register struct tftphdr
*tp
;
register struct errmsg
*pe
;
extern char *sys_errlist
[];
tp
= (struct tftphdr
*)buf
;
tp
->th_opcode
= htons((u_short
)ERROR
);
tp
->th_code
= htons((u_short
)error
);
for (pe
= errmsgs
; pe
->e_code
>= 0; pe
++)
pe
->e_msg
= sys_errlist
[error
- 100];
strcpy(tp
->th_msg
, pe
->e_msg
);
length
= strlen(pe
->e_msg
);
tp
->th_msg
[length
] = '\0';
if (write(f
, buf
, length
) != length
)