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