tftp-io.c revision 339060
1/* 2 * Copyright (C) 2008 Edwin Groothuis. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: stable/10/libexec/tftpd/tftp-io.c 339060 2018-10-01 16:09:20Z asomers $"); 28 29#include <sys/stat.h> 30#include <sys/types.h> 31#include <sys/socket.h> 32 33#include <netinet/in.h> 34#include <arpa/tftp.h> 35#include <arpa/inet.h> 36 37#include <assert.h> 38#include <errno.h> 39#include <setjmp.h> 40#include <signal.h> 41#include <stddef.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 53struct sockaddr_storage peer_sock; 54struct sockaddr_storage me_sock; 55 56static int send_packet(int peer, uint16_t block, char *pkt, int size); 57 58static 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 87const char * 88errtomsg(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 102static int 103send_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 */ 138void 139send_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 */ 177int 178send_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 = offsetof(struct tftphdr, th_stuff); 196 197 bp = tp->th_stuff; 198 strlcpy(bp, filename, sizeof(buf) - size); 199 bp += strlen(filename); 200 *bp = 0; 201 bp++; 202 size += strlen(filename) + 1; 203 204 strlcpy(bp, mode, sizeof(buf) - size); 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 */ 225int 226send_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 = offsetof(struct tftphdr, th_stuff); 244 245 bp = tp->th_stuff; 246 strlcpy(bp, filename, sizeof(buf) - size); 247 bp += strlen(filename); 248 *bp = 0; 249 bp++; 250 size += strlen(filename) + 1; 251 252 strlcpy(bp, mode, sizeof(buf) - size); 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 */ 275int 276send_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 */ 322int 323send_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 */ 352int 353send_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 */ 379static jmp_buf timeoutbuf; 380 381static void 382timeout(int sig __unused) 383{ 384 385 /* tftp_log(LOG_DEBUG, "Timeout\n"); Inside a signal handler... */ 386 longjmp(timeoutbuf, 1); 387} 388 389int 390receive_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 timed_out; 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 signal(SIGALRM, timeout); 407 timed_out = setjmp(timeoutbuf); 408 alarm(thistimeout); 409 410 if (timed_out != 0) { 411 tftp_log(LOG_ERR, "receive_packet: timeout"); 412 alarm(0); 413 return (RP_TIMEOUT); 414 } 415 416 pfrom = (from == NULL) ? &from_local : from; 417 fromlen = sizeof(*pfrom); 418 n = recvfrom(peer, data, size, 0, (struct sockaddr *)pfrom, &fromlen); 419 420 alarm(0); 421 422 DROPPACKETn("receive_packet", RP_TIMEOUT); 423 424 if (n < 0) { 425 tftp_log(LOG_ERR, "receive_packet: timeout"); 426 return (RP_TIMEOUT); 427 } 428 429 if (n < 0) { 430 /* No idea what could have happened if it isn't a timeout */ 431 tftp_log(LOG_ERR, "receive_packet: %s", strerror(errno)); 432 return (RP_RECVFROM); 433 } 434 if (n < 4) { 435 tftp_log(LOG_ERR, 436 "receive_packet: packet too small (%d bytes)", n); 437 return (RP_TOOSMALL); 438 } 439 440 pkt->th_opcode = ntohs((u_short)pkt->th_opcode); 441 if (pkt->th_opcode == DATA || 442 pkt->th_opcode == ACK) 443 pkt->th_block = ntohs((u_short)pkt->th_block); 444 445 if (pkt->th_opcode == DATA && n > pktsize) { 446 tftp_log(LOG_ERR, "receive_packet: packet too big"); 447 return (RP_TOOBIG); 448 } 449 450 if (((struct sockaddr_in *)(pfrom))->sin_addr.s_addr != 451 ((struct sockaddr_in *)(&peer_sock))->sin_addr.s_addr) { 452 tftp_log(LOG_ERR, 453 "receive_packet: received packet from wrong source"); 454 return (RP_WRONGSOURCE); 455 } 456 457 if (pkt->th_opcode == ERROR) { 458 tftp_log(pkt->th_code == EUNDEF ? LOG_DEBUG : LOG_ERR, 459 "Got ERROR packet: %s", pkt->th_msg); 460 return (RP_ERROR); 461 } 462 463 if (debug&DEBUG_PACKETS) 464 tftp_log(LOG_DEBUG, "Received %d bytes in a %s packet", 465 n, packettype(pkt->th_opcode)); 466 467 return n - 4; 468} 469