1 /* tftpd.c 4.3 82/10/08 */ 2 3 /* 4 * Trivial file transfer protocol server. 5 */ 6 #include <sys/types.h> 7 #include <net/in.h> 8 #include <sys/socket.h> 9 #include <signal.h> 10 #include <sys/ioctl.h> 11 #include <stat.h> 12 #include <stdio.h> 13 #include <wait.h> 14 #include <errno.h> 15 #include <ctype.h> 16 #include <netdb.h> 17 #include "tftp.h" 18 19 extern int errno; 20 struct sockaddr_in sin = { AF_INET }; 21 int f; 22 int options; 23 char buf[BUFSIZ]; 24 25 main(argc, argv) 26 char *argv[]; 27 { 28 union wait status; 29 struct sockaddr_in from; 30 register struct tftphdr *tp; 31 register int n; 32 struct servent *sp; 33 34 sp = getservbyname("tftp", "udp"); 35 if (sp == 0) { 36 fprintf(stderr, "tftpd: udp/tftp: unknown service\n"); 37 exit(1); 38 } 39 sin.sin_port = htons(sp->s_port); 40 #ifndef DEBUG 41 if (fork()) 42 exit(0); 43 for (f = 0; f < 10; f++) 44 (void) close(f); 45 (void) open("/", 0); 46 (void) dup2(0, 1); 47 (void) dup2(0, 2); 48 { int t = open("/dev/tty", 2); 49 if (t >= 0) { 50 ioctl(t, TIOCNOTTY, (char *)0); 51 (void) close(t); 52 } 53 } 54 #endif 55 argc--, argv++; 56 if (argc > 0 && !strcmp(argv[0], "-d")) 57 options |= SO_DEBUG; 58 for (;;) { 59 errno = 0; 60 f = socket(SOCK_DGRAM, 0, &sin, options); 61 if (f < 0) { 62 perror("socket"); 63 sleep(5); 64 continue; 65 } 66 again: 67 n = receive(f, &from, buf, sizeof (buf)); 68 if (n <= 0) { 69 if (n < 0) 70 perror("receive"); 71 goto again; 72 } 73 tp = (struct tftphdr *)buf; 74 #if vax || pdp11 75 tp->th_opcode = ntohs(tp->th_opcode); 76 #endif 77 if (tp->th_opcode == RRQ || tp->th_opcode == WRQ) 78 if (fork() == 0) 79 tftp(&from, tp, n); 80 (void) close(f); 81 #ifdef notdef 82 while (wait3(status, WNOHANG, 0) > 0) 83 #else 84 while (wait3(status, 0, 0) > 0) 85 continue; 86 } 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 int fd; /* file being transferred */ 107 108 /* 109 * Handle initial connection protocol. 110 */ 111 tftp(client, tp, size) 112 struct sockaddr_in *client; 113 struct tftphdr *tp; 114 int size; 115 { 116 register char *cp; 117 int first = 1, ecode; 118 register struct formats *pf; 119 char *filename, *mode; 120 121 if (connect(f, client) < 0) { 122 perror("connect"); 123 exit(1); 124 } 125 filename = cp = tp->th_stuff; 126 again: 127 while (cp < buf + size) { 128 if (*cp == '\0') 129 break; 130 cp++; 131 } 132 if (*cp != '\0') { 133 nak(EBADOP); 134 exit(1); 135 } 136 if (first) { 137 mode = ++cp; 138 first = 0; 139 goto again; 140 } 141 for (cp = mode; *cp; cp++) 142 if (isupper(*cp)) 143 *cp = tolower(*cp); 144 for (pf = formats; pf->f_mode; pf++) 145 if (strcmp(pf->f_mode, mode) == 0) 146 break; 147 if (pf->f_mode == 0) { 148 nak(EBADOP); 149 exit(1); 150 } 151 ecode = (*pf->f_validate)(filename, client, tp->th_opcode); 152 if (ecode) { 153 nak(ecode); 154 exit(1); 155 } 156 if (tp->th_opcode == WRQ) 157 (*pf->f_recv)(pf); 158 else 159 (*pf->f_send)(pf); 160 exit(0); 161 } 162 163 /* 164 * Validate file access. Since we 165 * have no uid or gid, for now require 166 * file to exist and be publicly 167 * readable/writable. 168 * Note also, full path name must be 169 * given as we have no login directory. 170 */ 171 validate_access(file, client, mode) 172 char *file; 173 struct sockaddr_in *client; 174 int mode; 175 { 176 struct stat stbuf; 177 178 if (*file != '/') 179 return (EACCESS); 180 if (stat(file, &stbuf) < 0) 181 return (errno == ENOENT ? ENOTFOUND : EACCESS); 182 if (mode == RRQ) { 183 if ((stbuf.st_mode&(S_IREAD >> 6)) == 0) 184 return (EACCESS); 185 } else { 186 if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0) 187 return (EACCESS); 188 } 189 fd = open(file, mode == RRQ ? 0 : 1); 190 if (fd < 0) 191 return (errno + 100); 192 return (0); 193 } 194 195 int timeout; 196 197 timer() 198 { 199 timeout += TIMEOUT; 200 if (timeout >= MAXTIMEOUT) 201 exit(1); 202 alarm(TIMEOUT); 203 } 204 205 /* 206 * Send the requested file. 207 */ 208 sendfile(pf) 209 struct format *pf; 210 { 211 register struct tftphdr *tp; 212 register int block = 1, size, n; 213 214 sigset(SIGALRM, timer); 215 tp = (struct tftphdr *)buf; 216 do { 217 size = read(fd, tp->th_data, SEGSIZE); 218 if (size < 0) { 219 nak(errno + 100); 220 break; 221 } 222 tp->th_opcode = htons((u_short)DATA); 223 tp->th_block = htons((u_short)block); 224 timeout = 0; 225 alarm(TIMEOUT); 226 rexmt: 227 if (write(f, buf, size + 4) != size + 4) { 228 perror("send"); 229 break; 230 } 231 again: 232 n = read(f, buf, sizeof (buf)); 233 if (n <= 0) { 234 if (n == 0) 235 goto again; 236 if (errno == EINTR) 237 goto rexmt; 238 alarm(0); 239 perror("receive"); 240 break; 241 } 242 alarm(0); 243 #if vax || pdp11 244 tp->th_opcode = ntohs(tp->th_opcode); 245 tp->th_block = ntohs(tp->th_block); 246 #endif 247 if (tp->th_opcode == ERROR) 248 break; 249 if (tp->th_opcode != ACK || tp->th_block != block) 250 goto again; 251 block++; 252 } while (size == SEGSIZE); 253 (void) close(fd); 254 } 255 256 /* 257 * Receive a file. 258 */ 259 recvfile(pf) 260 struct format *pf; 261 { 262 register struct tftphdr *tp; 263 register int block = 0, n, size; 264 265 sigset(SIGALRM, timer); 266 tp = (struct tftphdr *)buf; 267 do { 268 timeout = 0; 269 alarm(TIMEOUT); 270 tp->th_opcode = htons((u_short)ACK); 271 tp->th_block = htons((u_short)block); 272 block++; 273 rexmt: 274 if (write(f, buf, 4) != 4) { 275 perror("ack"); 276 break; 277 } 278 again: 279 n = read(f, buf, sizeof (buf)); 280 if (n <= 0) { 281 if (n == 0) 282 goto again; 283 if (errno == EINTR) 284 goto rexmt; 285 alarm(0); 286 perror("receive"); 287 break; 288 } 289 alarm(0); 290 #if vax || pdp11 291 tp->th_opcode = ntohs(tp->th_opcode); 292 tp->th_block = ntohs(tp->th_block); 293 #endif 294 if (tp->th_opcode == ERROR) 295 break; 296 if (tp->th_opcode != DATA || block != tp->th_block) 297 goto again; 298 size = write(fd, tp->th_data, n - 4); 299 if (size < 0) { 300 nak(errno + 100); 301 break; 302 } 303 } while (size == SEGSIZE); 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