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