1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (C) 2008 Edwin Groothuis. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/stat.h> 32 #include <sys/types.h> 33 #include <sys/socket.h> 34 35 #include <netinet/in.h> 36 #include <arpa/tftp.h> 37 #include <arpa/inet.h> 38 39 #include <errno.h> 40 #include <setjmp.h> 41 #include <signal.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <syslog.h> 46 #include <unistd.h> 47 48 #include "tftp-file.h" 49 #include "tftp-io.h" 50 #include "tftp-utils.h" 51 #include "tftp-options.h" 52 53 struct sockaddr_storage peer_sock; 54 struct sockaddr_storage me_sock; 55 56 static int send_packet(int peer, uint16_t block, char *pkt, int size); 57 58 static struct errmsg { 59 int e_code; 60 const char *e_msg; 61 } errmsgs[] = { 62 { EUNDEF, "Undefined error code" }, 63 { ENOTFOUND, "File not found" }, 64 { EACCESS, "Access violation" }, 65 { ENOSPACE, "Disk full or allocation exceeded" }, 66 { EBADOP, "Illegal TFTP operation" }, 67 { EBADID, "Unknown transfer ID" }, 68 { EEXISTS, "File already exists" }, 69 { ENOUSER, "No such user" }, 70 { EOPTNEG, "Option negotiation" }, 71 { -1, NULL } 72 }; 73 74 #define DROPPACKET(s) \ 75 if (packetdroppercentage != 0 && \ 76 random()%100 < packetdroppercentage) { \ 77 tftp_log(LOG_DEBUG, "Artificial packet drop in %s", s); \ 78 return; \ 79 } 80 #define DROPPACKETn(s,n) \ 81 if (packetdroppercentage != 0 && \ 82 random()%100 < packetdroppercentage) { \ 83 tftp_log(LOG_DEBUG, "Artificial packet drop in %s", s); \ 84 return (n); \ 85 } 86 87 const char * 88 errtomsg(int error) 89 { 90 static char ebuf[40]; 91 struct errmsg *pe; 92 93 if (error == 0) 94 return ("success"); 95 for (pe = errmsgs; pe->e_code >= 0; pe++) 96 if (pe->e_code == error) 97 return (pe->e_msg); 98 snprintf(ebuf, sizeof(ebuf), "error %d", error); 99 return (ebuf); 100 } 101 102 static int 103 send_packet(int peer, uint16_t block, char *pkt, int size) 104 { 105 int i; 106 int t = 1; 107 108 for (i = 0; i < 12 ; i++) { 109 DROPPACKETn("send_packet", 0); 110 111 if (sendto(peer, pkt, size, 0, (struct sockaddr *)&peer_sock, 112 peer_sock.ss_len) == size) { 113 if (i) 114 tftp_log(LOG_ERR, 115 "%s block %d, attempt %d successful", 116 packettype(ntohs(((struct tftphdr *) 117 (pkt))->th_opcode)), block, i); 118 return (0); 119 } 120 tftp_log(LOG_ERR, 121 "%s block %d, attempt %d failed (Error %d: %s)", 122 packettype(ntohs(((struct tftphdr *)(pkt))->th_opcode)), 123 block, i, errno, strerror(errno)); 124 sleep(t); 125 if (t < 32) 126 t <<= 1; 127 } 128 tftp_log(LOG_ERR, "send_packet: %s", strerror(errno)); 129 return (1); 130 } 131 132 /* 133 * Send an ERROR packet (error message). 134 * Error code passed in is one of the 135 * standard TFTP codes, or a UNIX errno 136 * offset by 100. 137 */ 138 void 139 send_error(int peer, int error) 140 { 141 struct tftphdr *tp; 142 int length; 143 struct errmsg *pe; 144 char buf[MAXPKTSIZE]; 145 146 if (debug&DEBUG_PACKETS) 147 tftp_log(LOG_DEBUG, "Sending ERROR %d", error); 148 149 DROPPACKET("send_error"); 150 151 tp = (struct tftphdr *)buf; 152 tp->th_opcode = htons((u_short)ERROR); 153 tp->th_code = htons((u_short)error); 154 for (pe = errmsgs; pe->e_code >= 0; pe++) 155 if (pe->e_code == error) 156 break; 157 if (pe->e_code < 0) { 158 pe->e_msg = strerror(error - 100); 159 tp->th_code = EUNDEF; /* set 'undef' errorcode */ 160 } 161 strcpy(tp->th_msg, pe->e_msg); 162 length = strlen(pe->e_msg); 163 tp->th_msg[length] = '\0'; 164 length += 5; 165 166 if (debug&DEBUG_PACKETS) 167 tftp_log(LOG_DEBUG, "Sending ERROR %d: %s", error, tp->th_msg); 168 169 if (sendto(peer, buf, length, 0, 170 (struct sockaddr *)&peer_sock, peer_sock.ss_len) != length) 171 tftp_log(LOG_ERR, "send_error: %s", strerror(errno)); 172 } 173 174 /* 175 * Send an WRQ packet (write request). 176 */ 177 int 178 send_wrq(int peer, char *filename, char *mode) 179 { 180 int n; 181 struct tftphdr *tp; 182 char *bp; 183 char buf[MAXPKTSIZE]; 184 int size; 185 186 if (debug&DEBUG_PACKETS) 187 tftp_log(LOG_DEBUG, "Sending WRQ: filename: '%s', mode '%s'", 188 filename, mode 189 ); 190 191 DROPPACKETn("send_wrq", 1); 192 193 tp = (struct tftphdr *)buf; 194 tp->th_opcode = htons((u_short)WRQ); 195 size = 2; 196 197 bp = tp->th_stuff; 198 strcpy(bp, filename); 199 bp += strlen(filename); 200 *bp = 0; 201 bp++; 202 size += strlen(filename) + 1; 203 204 strcpy(bp, mode); 205 bp += strlen(mode); 206 *bp = 0; 207 bp++; 208 size += strlen(mode) + 1; 209 210 if (options_rfc_enabled) 211 size += make_options(peer, bp, sizeof(buf) - size); 212 213 n = sendto(peer, buf, size, 0, 214 (struct sockaddr *)&peer_sock, peer_sock.ss_len); 215 if (n != size) { 216 tftp_log(LOG_ERR, "send_wrq: %s", strerror(errno)); 217 return (1); 218 } 219 return (0); 220 } 221 222 /* 223 * Send an RRQ packet (write request). 224 */ 225 int 226 send_rrq(int peer, char *filename, char *mode) 227 { 228 int n; 229 struct tftphdr *tp; 230 char *bp; 231 char buf[MAXPKTSIZE]; 232 int size; 233 234 if (debug&DEBUG_PACKETS) 235 tftp_log(LOG_DEBUG, "Sending RRQ: filename: '%s', mode '%s'", 236 filename, mode 237 ); 238 239 DROPPACKETn("send_rrq", 1); 240 241 tp = (struct tftphdr *)buf; 242 tp->th_opcode = htons((u_short)RRQ); 243 size = 2; 244 245 bp = tp->th_stuff; 246 strcpy(bp, filename); 247 bp += strlen(filename); 248 *bp = 0; 249 bp++; 250 size += strlen(filename) + 1; 251 252 strcpy(bp, mode); 253 bp += strlen(mode); 254 *bp = 0; 255 bp++; 256 size += strlen(mode) + 1; 257 258 if (options_rfc_enabled) { 259 options[OPT_TSIZE].o_request = strdup("0"); 260 size += make_options(peer, bp, sizeof(buf) - size); 261 } 262 263 n = sendto(peer, buf, size, 0, 264 (struct sockaddr *)&peer_sock, peer_sock.ss_len); 265 if (n != size) { 266 tftp_log(LOG_ERR, "send_rrq: %d %s", n, strerror(errno)); 267 return (1); 268 } 269 return (0); 270 } 271 272 /* 273 * Send an OACK packet (option acknowledgement). 274 */ 275 int 276 send_oack(int peer) 277 { 278 struct tftphdr *tp; 279 int size, i, n; 280 char *bp; 281 char buf[MAXPKTSIZE]; 282 283 if (debug&DEBUG_PACKETS) 284 tftp_log(LOG_DEBUG, "Sending OACK"); 285 286 DROPPACKETn("send_oack", 0); 287 288 /* 289 * Send back an options acknowledgement (only the ones with 290 * a reply for) 291 */ 292 tp = (struct tftphdr *)buf; 293 bp = buf + 2; 294 size = sizeof(buf) - 2; 295 tp->th_opcode = htons((u_short)OACK); 296 for (i = 0; options[i].o_type != NULL; i++) { 297 if (options[i].o_reply != NULL) { 298 n = snprintf(bp, size, "%s%c%s", options[i].o_type, 299 0, options[i].o_reply); 300 bp += n+1; 301 size -= n+1; 302 if (size < 0) { 303 tftp_log(LOG_ERR, "oack: buffer overflow"); 304 exit(1); 305 } 306 } 307 } 308 size = bp - buf; 309 310 if (sendto(peer, buf, size, 0, 311 (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) { 312 tftp_log(LOG_INFO, "send_oack: %s", strerror(errno)); 313 return (1); 314 } 315 316 return (0); 317 } 318 319 /* 320 * Send an ACK packet (acknowledgement). 321 */ 322 int 323 send_ack(int fp, uint16_t block) 324 { 325 struct tftphdr *tp; 326 int size; 327 char buf[MAXPKTSIZE]; 328 329 if (debug&DEBUG_PACKETS) 330 tftp_log(LOG_DEBUG, "Sending ACK for block %d", block); 331 332 DROPPACKETn("send_ack", 0); 333 334 tp = (struct tftphdr *)buf; 335 size = sizeof(buf) - 2; 336 tp->th_opcode = htons((u_short)ACK); 337 tp->th_block = htons((u_short)block); 338 size = 4; 339 340 if (sendto(fp, buf, size, 0, 341 (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) { 342 tftp_log(LOG_INFO, "send_ack: %s", strerror(errno)); 343 return (1); 344 } 345 346 return (0); 347 } 348 349 /* 350 * Send a DATA packet 351 */ 352 int 353 send_data(int peer, uint16_t block, char *data, int size) 354 { 355 char buf[MAXPKTSIZE]; 356 struct tftphdr *pkt; 357 int n; 358 359 if (debug&DEBUG_PACKETS) 360 tftp_log(LOG_DEBUG, "Sending DATA packet %d of %d bytes", 361 block, size); 362 363 DROPPACKETn("send_data", 0); 364 365 pkt = (struct tftphdr *)buf; 366 367 pkt->th_opcode = htons((u_short)DATA); 368 pkt->th_block = htons((u_short)block); 369 memcpy(pkt->th_data, data, size); 370 371 n = send_packet(peer, block, (char *)pkt, size + 4); 372 return (n); 373 } 374 375 376 /* 377 * Receive a packet 378 */ 379 static jmp_buf timeoutbuf; 380 381 static void 382 timeout(int sig __unused) 383 { 384 385 /* tftp_log(LOG_DEBUG, "Timeout\n"); Inside a signal handler... */ 386 longjmp(timeoutbuf, 1); 387 } 388 389 int 390 receive_packet(int peer, char *data, int size, struct sockaddr_storage *from, 391 int thistimeout) 392 { 393 struct tftphdr *pkt; 394 struct sockaddr_storage from_local; 395 struct sockaddr_storage *pfrom; 396 socklen_t fromlen; 397 int n; 398 static int waiting; 399 400 if (debug&DEBUG_PACKETS) 401 tftp_log(LOG_DEBUG, 402 "Waiting %d seconds for packet", timeoutpacket); 403 404 pkt = (struct tftphdr *)data; 405 406 waiting = 0; 407 signal(SIGALRM, timeout); 408 setjmp(timeoutbuf); 409 alarm(thistimeout); 410 411 if (waiting > 0) { 412 alarm(0); 413 return (RP_TIMEOUT); 414 } 415 416 if (waiting > 0) { 417 tftp_log(LOG_ERR, "receive_packet: timeout"); 418 alarm(0); 419 return (RP_TIMEOUT); 420 } 421 422 waiting++; 423 pfrom = (from == NULL) ? &from_local : from; 424 fromlen = sizeof(*pfrom); 425 n = recvfrom(peer, data, size, 0, (struct sockaddr *)pfrom, &fromlen); 426 427 alarm(0); 428 429 DROPPACKETn("receive_packet", RP_TIMEOUT); 430 431 if (n < 0) { 432 tftp_log(LOG_ERR, "receive_packet: timeout"); 433 return (RP_TIMEOUT); 434 } 435 436 alarm(0); 437 438 if (n < 0) { 439 /* No idea what could have happened if it isn't a timeout */ 440 tftp_log(LOG_ERR, "receive_packet: %s", strerror(errno)); 441 return (RP_RECVFROM); 442 } 443 if (n < 4) { 444 tftp_log(LOG_ERR, 445 "receive_packet: packet too small (%d bytes)", n); 446 return (RP_TOOSMALL); 447 } 448 449 pkt->th_opcode = ntohs((u_short)pkt->th_opcode); 450 if (pkt->th_opcode == DATA || 451 pkt->th_opcode == ACK) 452 pkt->th_block = ntohs((u_short)pkt->th_block); 453 454 if (pkt->th_opcode == DATA && n > pktsize) { 455 tftp_log(LOG_ERR, "receive_packet: packet too big"); 456 return (RP_TOOBIG); 457 } 458 459 if (((struct sockaddr_in *)(pfrom))->sin_addr.s_addr != 460 ((struct sockaddr_in *)(&peer_sock))->sin_addr.s_addr) { 461 tftp_log(LOG_ERR, 462 "receive_packet: received packet from wrong source"); 463 return (RP_WRONGSOURCE); 464 } 465 466 if (pkt->th_opcode == ERROR) { 467 tftp_log(pkt->th_code == EUNDEF ? LOG_DEBUG : LOG_ERR, 468 "Got ERROR packet: %s", pkt->th_msg); 469 return (RP_ERROR); 470 } 471 472 if (debug&DEBUG_PACKETS) 473 tftp_log(LOG_DEBUG, "Received %d bytes in a %s packet", 474 n, packettype(pkt->th_opcode)); 475 476 return n - 4; 477 } 478