1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 char copyright[] = 9 "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11 #endif not lint 12 13 #ifndef lint 14 static char sccsid[] = "@(#)tftpd.c 5.1 (Berkeley) 05/28/85"; 15 #endif not lint 16 17 /* 18 * Trivial file transfer protocol server. 19 */ 20 #include <sys/types.h> 21 #include <sys/socket.h> 22 #include <sys/ioctl.h> 23 #include <sys/wait.h> 24 #include <sys/stat.h> 25 26 #include <netinet/in.h> 27 28 #include <arpa/tftp.h> 29 30 #include <signal.h> 31 #include <stdio.h> 32 #include <errno.h> 33 #include <ctype.h> 34 #include <netdb.h> 35 #include <setjmp.h> 36 #include <syslog.h> 37 38 #define TIMEOUT 5 39 40 extern int errno; 41 struct sockaddr_in sin = { AF_INET }; 42 int peer; 43 int rexmtval = TIMEOUT; 44 int maxtimeout = 5*TIMEOUT; 45 char buf[BUFSIZ]; 46 struct sockaddr_in from; 47 int fromlen; 48 49 main() 50 { 51 register struct tftphdr *tp; 52 register int n; 53 54 alarm(10); 55 fromlen = sizeof (from); 56 n = recvfrom(0, buf, sizeof (buf), 0, 57 (caddr_t)&from, &fromlen); 58 if (n < 0) { 59 perror("tftpd: recvfrom"); 60 exit(1); 61 } 62 from.sin_family = AF_INET; 63 alarm(0); 64 close(0); 65 close(1); 66 peer = socket(AF_INET, SOCK_DGRAM, 0); 67 if (peer < 0) { 68 openlog("tftpd", LOG_PID, 0); 69 syslog(LOG_ERR, "socket: %m"); 70 exit(1); 71 } 72 if (bind(peer, (caddr_t)&sin, sizeof (sin)) < 0) { 73 openlog("tftpd", LOG_PID, 0); 74 syslog(LOG_ERR, "bind: %m"); 75 exit(1); 76 } 77 if (connect(peer, (caddr_t)&from, sizeof(from)) < 0) { 78 openlog("tftpd", LOG_PID, 0); 79 syslog(LOG_ERR, "connect: %m"); 80 exit(1); 81 } 82 tp = (struct tftphdr *)buf; 83 tp->th_opcode = ntohs(tp->th_opcode); 84 if (tp->th_opcode == RRQ || tp->th_opcode == WRQ) 85 tftp(tp, n); 86 exit(1); 87 } 88 89 int validate_access(); 90 int sendfile(), recvfile(); 91 92 struct formats { 93 char *f_mode; 94 int (*f_validate)(); 95 int (*f_send)(); 96 int (*f_recv)(); 97 } formats[] = { 98 { "netascii", validate_access, sendfile, recvfile }, 99 { "octet", validate_access, sendfile, recvfile }, 100 #ifdef notdef 101 { "mail", validate_user, sendmail, recvmail }, 102 #endif 103 { 0 } 104 }; 105 106 /* 107 * Handle initial connection protocol. 108 */ 109 tftp(tp, size) 110 struct tftphdr *tp; 111 int size; 112 { 113 register char *cp; 114 int first = 1, ecode; 115 register struct formats *pf; 116 char *filename, *mode; 117 118 filename = cp = tp->th_stuff; 119 again: 120 while (cp < buf + size) { 121 if (*cp == '\0') 122 break; 123 cp++; 124 } 125 if (*cp != '\0') { 126 nak(EBADOP); 127 exit(1); 128 } 129 if (first) { 130 mode = ++cp; 131 first = 0; 132 goto again; 133 } 134 for (cp = mode; *cp; cp++) 135 if (isupper(*cp)) 136 *cp = tolower(*cp); 137 for (pf = formats; pf->f_mode; pf++) 138 if (strcmp(pf->f_mode, mode) == 0) 139 break; 140 if (pf->f_mode == 0) { 141 nak(EBADOP); 142 exit(1); 143 } 144 ecode = (*pf->f_validate)(filename, tp->th_opcode); 145 if (ecode) { 146 nak(ecode); 147 exit(1); 148 } 149 if (tp->th_opcode == WRQ) 150 (*pf->f_recv)(pf); 151 else 152 (*pf->f_send)(pf); 153 exit(0); 154 } 155 156 int fd; 157 158 /* 159 * Validate file access. Since we 160 * have no uid or gid, for now require 161 * file to exist and be publicly 162 * readable/writable. 163 * Note also, full path name must be 164 * given as we have no login directory. 165 */ 166 validate_access(file, mode) 167 char *file; 168 int mode; 169 { 170 struct stat stbuf; 171 172 if (*file != '/') 173 return (EACCESS); 174 if (stat(file, &stbuf) < 0) 175 return (errno == ENOENT ? ENOTFOUND : EACCESS); 176 if (mode == RRQ) { 177 if ((stbuf.st_mode&(S_IREAD >> 6)) == 0) 178 return (EACCESS); 179 } else { 180 if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0) 181 return (EACCESS); 182 } 183 fd = open(file, mode == RRQ ? 0 : 1); 184 if (fd < 0) 185 return (errno + 100); 186 return (0); 187 } 188 189 int timeout; 190 jmp_buf timeoutbuf; 191 192 timer() 193 { 194 195 timeout += rexmtval; 196 if (timeout >= maxtimeout) 197 exit(1); 198 longjmp(timeoutbuf, 1); 199 } 200 201 /* 202 * Send the requested file. 203 */ 204 sendfile(pf) 205 struct format *pf; 206 { 207 register struct tftphdr *tp; 208 register int block = 1, size, n; 209 210 signal(SIGALRM, timer); 211 tp = (struct tftphdr *)buf; 212 do { 213 size = read(fd, tp->th_data, SEGSIZE); 214 if (size < 0) { 215 nak(errno + 100); 216 return; 217 } 218 tp->th_opcode = htons((u_short)DATA); 219 tp->th_block = htons((u_short)block); 220 timeout = 0; 221 (void) setjmp(timeoutbuf); 222 if (send(peer, buf, size + 4, 0) != size + 4) { 223 perror("tftpd: send"); 224 return; 225 } 226 do { 227 alarm(rexmtval); 228 n = recv(peer, buf, sizeof (buf), 0); 229 alarm(0); 230 if (n < 0) { 231 perror("tftpd: recv"); 232 return; 233 } 234 tp->th_opcode = ntohs((u_short)tp->th_opcode); 235 tp->th_block = ntohs((u_short)tp->th_block); 236 if (tp->th_opcode == ERROR) 237 return; 238 } while (tp->th_opcode != ACK || tp->th_block != block); 239 block++; 240 } while (size == SEGSIZE); 241 } 242 243 /* 244 * Receive a file. 245 */ 246 recvfile(pf) 247 struct format *pf; 248 { 249 register struct tftphdr *tp; 250 register int block = 0, n, size; 251 252 signal(SIGALRM, timer); 253 tp = (struct tftphdr *)buf; 254 do { 255 timeout = 0; 256 tp->th_opcode = htons((u_short)ACK); 257 tp->th_block = htons((u_short)block); 258 block++; 259 (void) setjmp(timeoutbuf); 260 if (send(peer, buf, 4, 0) != 4) { 261 perror("tftpd: send"); 262 goto abort; 263 } 264 do { 265 alarm(rexmtval); 266 n = recv(peer, buf, sizeof (buf), 0); 267 alarm(0); 268 if (n < 0) { 269 perror("tftpd: recv"); 270 goto abort; 271 } 272 tp->th_opcode = ntohs((u_short)tp->th_opcode); 273 tp->th_block = ntohs((u_short)tp->th_block); 274 if (tp->th_opcode == ERROR) 275 goto abort; 276 } while (tp->th_opcode != DATA || block != tp->th_block); 277 size = write(fd, tp->th_data, n - 4); 278 if (size < 0) { 279 nak(errno + 100); 280 goto abort; 281 } 282 } while (size == SEGSIZE); 283 abort: 284 tp->th_opcode = htons((u_short)ACK); 285 tp->th_block = htons((u_short)(block)); 286 (void) send(peer, buf, 4, 0); 287 } 288 289 struct errmsg { 290 int e_code; 291 char *e_msg; 292 } errmsgs[] = { 293 { EUNDEF, "Undefined error code" }, 294 { ENOTFOUND, "File not found" }, 295 { EACCESS, "Access violation" }, 296 { ENOSPACE, "Disk full or allocation exceeded" }, 297 { EBADOP, "Illegal TFTP operation" }, 298 { EBADID, "Unknown transfer ID" }, 299 { EEXISTS, "File already exists" }, 300 { ENOUSER, "No such user" }, 301 { -1, 0 } 302 }; 303 304 /* 305 * Send a nak packet (error message). 306 * Error code passed in is one of the 307 * standard TFTP codes, or a UNIX errno 308 * offset by 100. 309 */ 310 nak(error) 311 int error; 312 { 313 register struct tftphdr *tp; 314 int length; 315 register struct errmsg *pe; 316 extern char *sys_errlist[]; 317 318 tp = (struct tftphdr *)buf; 319 tp->th_opcode = htons((u_short)ERROR); 320 tp->th_code = htons((u_short)error); 321 for (pe = errmsgs; pe->e_code >= 0; pe++) 322 if (pe->e_code == error) 323 break; 324 if (pe->e_code < 0) 325 pe->e_msg = sys_errlist[error - 100]; 326 strcpy(tp->th_msg, pe->e_msg); 327 length = strlen(pe->e_msg); 328 tp->th_msg[length] = '\0'; 329 length += 5; 330 if (send(peer, buf, length, 0) != length) 331 perror("nak"); 332 exit(1); 333 } 334