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