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