1207614Simp/* 2207614Simp * Copyright (C) 2008 Edwin Groothuis. All rights reserved. 3207614Simp * 4207614Simp * Redistribution and use in source and binary forms, with or without 5207614Simp * modification, are permitted provided that the following conditions 6207614Simp * are met: 7207614Simp * 1. Redistributions of source code must retain the above copyright 8207614Simp * notice, this list of conditions and the following disclaimer. 9207614Simp * 2. Redistributions in binary form must reproduce the above copyright 10207614Simp * notice, this list of conditions and the following disclaimer in the 11207614Simp * documentation and/or other materials provided with the distribution. 12207614Simp * 13207614Simp * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14207614Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15207614Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16207614Simp * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17207614Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18207614Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19207614Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20207614Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21207614Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22207614Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23207614Simp * SUCH DAMAGE. 24207614Simp */ 25207614Simp 26207614Simp#include <sys/cdefs.h> 27207614Simp__FBSDID("$FreeBSD$"); 28207614Simp 29207614Simp#include <sys/stat.h> 30207614Simp#include <sys/types.h> 31207614Simp#include <sys/socket.h> 32207614Simp 33207614Simp#include <netinet/in.h> 34207614Simp#include <arpa/tftp.h> 35207614Simp#include <arpa/inet.h> 36207614Simp 37207614Simp#include <errno.h> 38207614Simp#include <setjmp.h> 39207614Simp#include <signal.h> 40207614Simp#include <stdio.h> 41207614Simp#include <stdlib.h> 42207614Simp#include <string.h> 43207614Simp#include <syslog.h> 44207614Simp#include <unistd.h> 45207614Simp 46207614Simp#include "tftp-file.h" 47207614Simp#include "tftp-io.h" 48207614Simp#include "tftp-utils.h" 49207614Simp#include "tftp-options.h" 50207614Simp 51207614Simpstruct sockaddr_storage peer_sock; 52207614Simpstruct sockaddr_storage me_sock; 53207614Simp 54207614Simpstatic int send_packet(int peer, uint16_t block, char *pkt, int size); 55207614Simp 56241720Sedstatic struct errmsg { 57207614Simp int e_code; 58207614Simp const char *e_msg; 59207614Simp} errmsgs[] = { 60207614Simp { EUNDEF, "Undefined error code" }, 61207614Simp { ENOTFOUND, "File not found" }, 62207614Simp { EACCESS, "Access violation" }, 63207614Simp { ENOSPACE, "Disk full or allocation exceeded" }, 64207614Simp { EBADOP, "Illegal TFTP operation" }, 65207614Simp { EBADID, "Unknown transfer ID" }, 66207614Simp { EEXISTS, "File already exists" }, 67207614Simp { ENOUSER, "No such user" }, 68207614Simp { EOPTNEG, "Option negotiation" }, 69207614Simp { -1, NULL } 70207614Simp}; 71207614Simp 72207614Simp#define DROPPACKET(s) \ 73207614Simp if (packetdroppercentage != 0 && \ 74207614Simp random()%100 < packetdroppercentage) { \ 75229780Suqs tftp_log(LOG_DEBUG, "Artificial packet drop in %s", s); \ 76207614Simp return; \ 77207614Simp } 78207614Simp#define DROPPACKETn(s,n) \ 79207614Simp if (packetdroppercentage != 0 && \ 80207614Simp random()%100 < packetdroppercentage) { \ 81229780Suqs tftp_log(LOG_DEBUG, "Artificial packet drop in %s", s); \ 82207614Simp return (n); \ 83207614Simp } 84207614Simp 85207614Simpconst char * 86207614Simperrtomsg(int error) 87207614Simp{ 88207614Simp static char ebuf[40]; 89207614Simp struct errmsg *pe; 90207614Simp 91207614Simp if (error == 0) 92207614Simp return ("success"); 93207614Simp for (pe = errmsgs; pe->e_code >= 0; pe++) 94207614Simp if (pe->e_code == error) 95207614Simp return (pe->e_msg); 96244686Santoine snprintf(ebuf, sizeof(ebuf), "error %d", error); 97207614Simp return (ebuf); 98207614Simp} 99207614Simp 100207614Simpstatic int 101207614Simpsend_packet(int peer, uint16_t block, char *pkt, int size) 102207614Simp{ 103207614Simp int i; 104207614Simp int t = 1; 105207614Simp 106207614Simp for (i = 0; i < 12 ; i++) { 107207614Simp DROPPACKETn("send_packet", 0); 108207614Simp 109246139Smarius if (sendto(peer, pkt, size, 0, (struct sockaddr *)&peer_sock, 110246139Smarius peer_sock.ss_len) == size) { 111207614Simp if (i) 112207614Simp tftp_log(LOG_ERR, 113207614Simp "%s block %d, attempt %d successful", 114246139Smarius packettype(ntohs(((struct tftphdr *) 115246139Smarius (pkt))->th_opcode)), block, i); 116207614Simp return (0); 117207614Simp } 118207614Simp tftp_log(LOG_ERR, 119207614Simp "%s block %d, attempt %d failed (Error %d: %s)", 120207614Simp packettype(ntohs(((struct tftphdr *)(pkt))->th_opcode)), 121207614Simp block, i, errno, strerror(errno)); 122207614Simp sleep(t); 123207614Simp if (t < 32) 124207614Simp t <<= 1; 125207614Simp } 126207614Simp tftp_log(LOG_ERR, "send_packet: %s", strerror(errno)); 127207614Simp return (1); 128207614Simp} 129207614Simp 130207614Simp/* 131207614Simp * Send an ERROR packet (error message). 132207614Simp * Error code passed in is one of the 133207614Simp * standard TFTP codes, or a UNIX errno 134207614Simp * offset by 100. 135207614Simp */ 136207614Simpvoid 137207614Simpsend_error(int peer, int error) 138207614Simp{ 139207614Simp struct tftphdr *tp; 140207614Simp int length; 141207614Simp struct errmsg *pe; 142207614Simp char buf[MAXPKTSIZE]; 143207614Simp 144207614Simp if (debug&DEBUG_PACKETS) 145246106Ssbruno tftp_log(LOG_DEBUG, "Sending ERROR %d", error); 146207614Simp 147207614Simp DROPPACKET("send_error"); 148207614Simp 149207614Simp tp = (struct tftphdr *)buf; 150207614Simp tp->th_opcode = htons((u_short)ERROR); 151207614Simp tp->th_code = htons((u_short)error); 152207614Simp for (pe = errmsgs; pe->e_code >= 0; pe++) 153207614Simp if (pe->e_code == error) 154207614Simp break; 155207614Simp if (pe->e_code < 0) { 156207614Simp pe->e_msg = strerror(error - 100); 157207614Simp tp->th_code = EUNDEF; /* set 'undef' errorcode */ 158207614Simp } 159207614Simp strcpy(tp->th_msg, pe->e_msg); 160207614Simp length = strlen(pe->e_msg); 161207614Simp tp->th_msg[length] = '\0'; 162207614Simp length += 5; 163207614Simp 164207614Simp if (debug&DEBUG_PACKETS) 165207614Simp tftp_log(LOG_DEBUG, "Sending ERROR %d: %s", error, tp->th_msg); 166207614Simp 167207614Simp if (sendto(peer, buf, length, 0, 168207614Simp (struct sockaddr *)&peer_sock, peer_sock.ss_len) != length) 169207614Simp tftp_log(LOG_ERR, "send_error: %s", strerror(errno)); 170207614Simp} 171207614Simp 172207614Simp/* 173207614Simp * Send an WRQ packet (write request). 174207614Simp */ 175207614Simpint 176207614Simpsend_wrq(int peer, char *filename, char *mode) 177207614Simp{ 178207614Simp int n; 179207614Simp struct tftphdr *tp; 180207614Simp char *bp; 181207614Simp char buf[MAXPKTSIZE]; 182207614Simp int size; 183207614Simp 184207614Simp if (debug&DEBUG_PACKETS) 185207614Simp tftp_log(LOG_DEBUG, "Sending WRQ: filename: '%s', mode '%s'", 186207614Simp filename, mode 187207614Simp ); 188207614Simp 189207614Simp DROPPACKETn("send_wrq", 1); 190207614Simp 191207614Simp tp = (struct tftphdr *)buf; 192207614Simp tp->th_opcode = htons((u_short)WRQ); 193207614Simp size = 2; 194207614Simp 195207614Simp bp = tp->th_stuff; 196207614Simp strcpy(bp, filename); 197207614Simp bp += strlen(filename); 198207614Simp *bp = 0; 199207614Simp bp++; 200207614Simp size += strlen(filename) + 1; 201207614Simp 202207614Simp strcpy(bp, mode); 203207614Simp bp += strlen(mode); 204207614Simp *bp = 0; 205207614Simp bp++; 206207614Simp size += strlen(mode) + 1; 207207614Simp 208207614Simp if (options_rfc_enabled) 209207614Simp size += make_options(peer, bp, sizeof(buf) - size); 210207614Simp 211207614Simp n = sendto(peer, buf, size, 0, 212207614Simp (struct sockaddr *)&peer_sock, peer_sock.ss_len); 213207614Simp if (n != size) { 214207614Simp tftp_log(LOG_ERR, "send_wrq: %s", strerror(errno)); 215207614Simp return (1); 216207614Simp } 217207614Simp return (0); 218207614Simp} 219207614Simp 220207614Simp/* 221207614Simp * Send an RRQ packet (write request). 222207614Simp */ 223207614Simpint 224207614Simpsend_rrq(int peer, char *filename, char *mode) 225207614Simp{ 226207614Simp int n; 227207614Simp struct tftphdr *tp; 228207614Simp char *bp; 229207614Simp char buf[MAXPKTSIZE]; 230207614Simp int size; 231207614Simp 232207614Simp if (debug&DEBUG_PACKETS) 233207614Simp tftp_log(LOG_DEBUG, "Sending RRQ: filename: '%s', mode '%s'", 234207614Simp filename, mode 235207614Simp ); 236207614Simp 237207614Simp DROPPACKETn("send_rrq", 1); 238207614Simp 239207614Simp tp = (struct tftphdr *)buf; 240207614Simp tp->th_opcode = htons((u_short)RRQ); 241207614Simp size = 2; 242207614Simp 243207614Simp bp = tp->th_stuff; 244207614Simp strcpy(bp, filename); 245207614Simp bp += strlen(filename); 246207614Simp *bp = 0; 247207614Simp bp++; 248207614Simp size += strlen(filename) + 1; 249207614Simp 250207614Simp strcpy(bp, mode); 251207614Simp bp += strlen(mode); 252207614Simp *bp = 0; 253207614Simp bp++; 254207614Simp size += strlen(mode) + 1; 255207614Simp 256207614Simp if (options_rfc_enabled) { 257207614Simp options[OPT_TSIZE].o_request = strdup("0"); 258207614Simp size += make_options(peer, bp, sizeof(buf) - size); 259207614Simp } 260207614Simp 261207614Simp n = sendto(peer, buf, size, 0, 262207614Simp (struct sockaddr *)&peer_sock, peer_sock.ss_len); 263207614Simp if (n != size) { 264222326Srodrigc tftp_log(LOG_ERR, "send_rrq: %d %s", n, strerror(errno)); 265207614Simp return (1); 266207614Simp } 267207614Simp return (0); 268207614Simp} 269207614Simp 270207614Simp/* 271207614Simp * Send an OACK packet (option acknowledgement). 272207614Simp */ 273207614Simpint 274207614Simpsend_oack(int peer) 275207614Simp{ 276207614Simp struct tftphdr *tp; 277207614Simp int size, i, n; 278207614Simp char *bp; 279207614Simp char buf[MAXPKTSIZE]; 280207614Simp 281207614Simp if (debug&DEBUG_PACKETS) 282207614Simp tftp_log(LOG_DEBUG, "Sending OACK"); 283207614Simp 284207614Simp DROPPACKETn("send_oack", 0); 285207614Simp 286207614Simp /* 287207614Simp * Send back an options acknowledgement (only the ones with 288207614Simp * a reply for) 289207614Simp */ 290207614Simp tp = (struct tftphdr *)buf; 291207614Simp bp = buf + 2; 292207614Simp size = sizeof(buf) - 2; 293207614Simp tp->th_opcode = htons((u_short)OACK); 294207614Simp for (i = 0; options[i].o_type != NULL; i++) { 295207614Simp if (options[i].o_reply != NULL) { 296207614Simp n = snprintf(bp, size, "%s%c%s", options[i].o_type, 297207614Simp 0, options[i].o_reply); 298207614Simp bp += n+1; 299207614Simp size -= n+1; 300207614Simp if (size < 0) { 301207614Simp tftp_log(LOG_ERR, "oack: buffer overflow"); 302207614Simp exit(1); 303207614Simp } 304207614Simp } 305207614Simp } 306207614Simp size = bp - buf; 307207614Simp 308207614Simp if (sendto(peer, buf, size, 0, 309207614Simp (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) { 310207614Simp tftp_log(LOG_INFO, "send_oack: %s", strerror(errno)); 311207614Simp return (1); 312207614Simp } 313207614Simp 314207614Simp return (0); 315207614Simp} 316207614Simp 317207614Simp/* 318207614Simp * Send an ACK packet (acknowledgement). 319207614Simp */ 320207614Simpint 321207614Simpsend_ack(int fp, uint16_t block) 322207614Simp{ 323207614Simp struct tftphdr *tp; 324207614Simp int size; 325207614Simp char buf[MAXPKTSIZE]; 326207614Simp 327207614Simp if (debug&DEBUG_PACKETS) 328207614Simp tftp_log(LOG_DEBUG, "Sending ACK for block %d", block); 329207614Simp 330207614Simp DROPPACKETn("send_ack", 0); 331207614Simp 332207614Simp tp = (struct tftphdr *)buf; 333207614Simp size = sizeof(buf) - 2; 334207614Simp tp->th_opcode = htons((u_short)ACK); 335207614Simp tp->th_block = htons((u_short)block); 336207614Simp size = 4; 337207614Simp 338207614Simp if (sendto(fp, buf, size, 0, 339207614Simp (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) { 340207614Simp tftp_log(LOG_INFO, "send_ack: %s", strerror(errno)); 341207614Simp return (1); 342207614Simp } 343207614Simp 344207614Simp return (0); 345207614Simp} 346207614Simp 347207614Simp/* 348207614Simp * Send a DATA packet 349207614Simp */ 350207614Simpint 351207614Simpsend_data(int peer, uint16_t block, char *data, int size) 352207614Simp{ 353207614Simp char buf[MAXPKTSIZE]; 354207614Simp struct tftphdr *pkt; 355207614Simp int n; 356207614Simp 357207614Simp if (debug&DEBUG_PACKETS) 358207614Simp tftp_log(LOG_DEBUG, "Sending DATA packet %d of %d bytes", 359207614Simp block, size); 360207614Simp 361207614Simp DROPPACKETn("send_data", 0); 362207614Simp 363207614Simp pkt = (struct tftphdr *)buf; 364207614Simp 365207614Simp pkt->th_opcode = htons((u_short)DATA); 366207614Simp pkt->th_block = htons((u_short)block); 367207614Simp memcpy(pkt->th_data, data, size); 368207614Simp 369207614Simp n = send_packet(peer, block, (char *)pkt, size + 4); 370207614Simp return (n); 371207614Simp} 372207614Simp 373207614Simp 374207614Simp/* 375207614Simp * Receive a packet 376207614Simp */ 377241720Sedstatic jmp_buf timeoutbuf; 378207614Simp 379207614Simpstatic void 380207614Simptimeout(int sig __unused) 381207614Simp{ 382207614Simp 383207614Simp /* tftp_log(LOG_DEBUG, "Timeout\n"); Inside a signal handler... */ 384207614Simp longjmp(timeoutbuf, 1); 385207614Simp} 386207614Simp 387207614Simpint 388207614Simpreceive_packet(int peer, char *data, int size, struct sockaddr_storage *from, 389207614Simp int thistimeout) 390207614Simp{ 391207614Simp struct tftphdr *pkt; 392207614Simp struct sockaddr_storage from_local; 393207614Simp struct sockaddr_storage *pfrom; 394207614Simp socklen_t fromlen; 395207614Simp int n; 396207614Simp static int waiting; 397207614Simp 398207614Simp if (debug&DEBUG_PACKETS) 399207614Simp tftp_log(LOG_DEBUG, 400207614Simp "Waiting %d seconds for packet", timeoutpacket); 401207614Simp 402207614Simp pkt = (struct tftphdr *)data; 403207614Simp 404207614Simp waiting = 0; 405207614Simp signal(SIGALRM, timeout); 406207614Simp setjmp(timeoutbuf); 407207614Simp alarm(thistimeout); 408207614Simp 409207614Simp if (waiting > 0) { 410207614Simp alarm(0); 411207614Simp return (RP_TIMEOUT); 412207614Simp } 413207614Simp 414207614Simp if (waiting > 0) { 415207614Simp tftp_log(LOG_ERR, "receive_packet: timeout"); 416207614Simp alarm(0); 417207614Simp return (RP_TIMEOUT); 418207614Simp } 419207614Simp 420207614Simp waiting++; 421212665Simp pfrom = (from == NULL) ? &from_local : from; 422207614Simp fromlen = sizeof(*pfrom); 423207614Simp n = recvfrom(peer, data, size, 0, (struct sockaddr *)pfrom, &fromlen); 424207614Simp 425207614Simp alarm(0); 426207614Simp 427207614Simp DROPPACKETn("receive_packet", RP_TIMEOUT); 428207614Simp 429207614Simp if (n < 0) { 430207614Simp tftp_log(LOG_ERR, "receive_packet: timeout"); 431207614Simp return (RP_TIMEOUT); 432207614Simp } 433207614Simp 434207614Simp alarm(0); 435207614Simp 436207614Simp if (n < 0) { 437207614Simp /* No idea what could have happened if it isn't a timeout */ 438207614Simp tftp_log(LOG_ERR, "receive_packet: %s", strerror(errno)); 439207614Simp return (RP_RECVFROM); 440207614Simp } 441207614Simp if (n < 4) { 442207614Simp tftp_log(LOG_ERR, 443207614Simp "receive_packet: packet too small (%d bytes)", n); 444207614Simp return (RP_TOOSMALL); 445207614Simp } 446207614Simp 447207614Simp pkt->th_opcode = ntohs((u_short)pkt->th_opcode); 448207614Simp if (pkt->th_opcode == DATA || 449207614Simp pkt->th_opcode == ACK) 450207614Simp pkt->th_block = ntohs((u_short)pkt->th_block); 451207614Simp 452207614Simp if (pkt->th_opcode == DATA && n > pktsize) { 453207614Simp tftp_log(LOG_ERR, "receive_packet: packet too big"); 454207614Simp return (RP_TOOBIG); 455207614Simp } 456207614Simp 457207614Simp if (((struct sockaddr_in *)(pfrom))->sin_addr.s_addr != 458207614Simp ((struct sockaddr_in *)(&peer_sock))->sin_addr.s_addr) { 459207614Simp tftp_log(LOG_ERR, 460207614Simp "receive_packet: received packet from wrong source"); 461207614Simp return (RP_WRONGSOURCE); 462207614Simp } 463207614Simp 464207614Simp if (pkt->th_opcode == ERROR) { 465231973Semaste tftp_log(pkt->th_code == EUNDEF ? LOG_DEBUG : LOG_ERR, 466231973Semaste "Got ERROR packet: %s", pkt->th_msg); 467207614Simp return (RP_ERROR); 468207614Simp } 469207614Simp 470207614Simp if (debug&DEBUG_PACKETS) 471207614Simp tftp_log(LOG_DEBUG, "Received %d bytes in a %s packet", 472207614Simp n, packettype(pkt->th_opcode)); 473207614Simp 474207614Simp return n - 4; 475207614Simp} 476