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