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/types.h> 30223487Srodrigc#include <sys/ioctl.h> 31223487Srodrigc#include <sys/socket.h> 32207614Simp#include <sys/stat.h> 33207614Simp 34207614Simp#include <netinet/in.h> 35207614Simp#include <arpa/tftp.h> 36207614Simp 37207614Simp#include <errno.h> 38207614Simp#include <stdio.h> 39207614Simp#include <stdlib.h> 40207614Simp#include <string.h> 41207614Simp#include <syslog.h> 42207614Simp#include <unistd.h> 43207614Simp 44207614Simp#include "tftp-file.h" 45207614Simp#include "tftp-utils.h" 46207614Simp 47207614Simpstatic FILE *file; 48207614Simpstatic int convert; 49207614Simp 50207614Simpstatic char convbuffer[66000]; 51207614Simpstatic int gotcr = 0; 52207614Simp 53207614Simpstatic size_t 54207614Simpconvert_from_net(char *buffer, size_t count) 55207614Simp{ 56207614Simp size_t i, n; 57207614Simp 58207614Simp /* 59207614Simp * Convert all CR/LF to LF and all CR,NUL to CR 60207614Simp */ 61207614Simp 62207614Simp n = 0; 63207614Simp for (i = 0; i < count; i++) { 64207614Simp 65207614Simp if (gotcr == 0) { 66207614Simp convbuffer[n++] = buffer[i]; 67207614Simp gotcr = (buffer[i] == '\r'); 68207614Simp continue; 69207614Simp } 70207614Simp 71207614Simp /* CR, NULL -> CR */ 72207614Simp if (buffer[i] == '\0') { 73207614Simp gotcr = 0; 74207614Simp continue; 75207614Simp } 76207614Simp 77207614Simp /* CR, LF -> LF */ 78207614Simp if (buffer[i] == '\n') { 79207614Simp if (n == 0) { 80207614Simp if (ftell(file) != 0) { 81207614Simp fseek(file, -1, SEEK_END); 82207614Simp convbuffer[n++] = '\n'; 83207614Simp } else { 84207614Simp /* This shouldn't happen */ 85207614Simp tftp_log(LOG_ERR, 86207614Simp "Received LF as first character"); 87207614Simp abort(); 88207614Simp } 89207614Simp } else 90207614Simp convbuffer[n-1] = '\n'; 91207614Simp gotcr = 0; 92207614Simp continue; 93207614Simp } 94207614Simp 95207614Simp /* Everything else just accept as is */ 96207614Simp convbuffer[n++] = buffer[i]; 97207614Simp gotcr = (buffer[i] == '\r'); 98207614Simp continue; 99207614Simp } 100207614Simp 101207614Simp return fwrite(convbuffer, 1, n, file); 102207614Simp} 103207614Simp 104207614Simpstatic size_t 105207614Simpconvert_to_net(char *buffer, size_t count, int init) 106207614Simp{ 107207614Simp size_t i; 108213099Smarius static size_t n = 0, in = 0; 109207614Simp static int newline = 0; 110207614Simp 111207614Simp if (init) { 112207614Simp newline = 0; 113207614Simp n = 0; 114213099Smarius in = 0; 115207614Simp return 0 ; 116207614Simp } 117207614Simp 118207614Simp /* 119207614Simp * Convert all LF to CR,LF and all CR to CR,NUL 120207614Simp */ 121207614Simp i = 0; 122207614Simp 123207614Simp if (newline) { 124207614Simp buffer[i++] = newline; 125207614Simp newline = 0; 126207614Simp } 127207614Simp 128207614Simp while (i < count) { 129213099Smarius if (n == in) { 130207614Simp /* When done we're done */ 131207614Simp if (feof(file)) break; 132207614Simp 133207614Simp /* Otherwise read another bunch */ 134213099Smarius in = fread(convbuffer, 1, count, file); 135213099Smarius if (in == 0) break; 136207614Simp n = 0; 137207614Simp } 138207614Simp 139207614Simp /* CR -> CR,NULL */ 140207614Simp if (convbuffer[n] == '\r') { 141207614Simp buffer[i++] = '\r'; 142207614Simp buffer[i++] = '\0'; 143207614Simp n++; 144207614Simp continue; 145207614Simp } 146207614Simp 147207614Simp /* LF -> CR,LF */ 148207614Simp if (convbuffer[n] == '\n') { 149207614Simp buffer[i++] = '\r'; 150207614Simp buffer[i++] = '\n'; 151207614Simp n++; 152207614Simp continue; 153207614Simp } 154207614Simp 155207614Simp buffer[i++] = convbuffer[n++]; 156207614Simp } 157207614Simp 158207614Simp if (i > count) { 159207614Simp /* 160207614Simp * Whoops... that isn't alllowed (but it will happen 161207614Simp * when there is a CR or LF at the end of the buffer) 162207614Simp */ 163207614Simp newline = buffer[i-1]; 164207614Simp } 165207614Simp 166207614Simp if (i < count) { 167207614Simp /* We are done! */ 168207614Simp return i; 169207614Simp } else 170207614Simp return count; 171207614Simp 172207614Simp} 173207614Simp 174207614Simpint 175207614Simpwrite_init(int fd, FILE *f, const char *mode) 176207614Simp{ 177207614Simp 178207614Simp if (f == NULL) { 179207614Simp file = fdopen(fd, "w"); 180207614Simp if (file == NULL) { 181207614Simp int en = errno; 182207614Simp tftp_log(LOG_ERR, "fdopen() failed: %s", 183207614Simp strerror(errno)); 184207614Simp return en; 185207614Simp } 186207614Simp } else 187207614Simp file = f; 188207614Simp convert = !strcmp(mode, "netascii"); 189207614Simp return 0; 190207614Simp} 191207614Simp 192207614Simpsize_t 193207614Simpwrite_file(char *buffer, int count) 194207614Simp{ 195207614Simp 196207614Simp if (convert == 0) 197207614Simp return fwrite(buffer, 1, count, file); 198207614Simp 199207614Simp return convert_from_net(buffer, count); 200207614Simp} 201207614Simp 202207614Simpint 203207614Simpwrite_close(void) 204207614Simp{ 205207614Simp 206207614Simp if (fclose(file) != 0) { 207207614Simp tftp_log(LOG_ERR, "fclose() failed: %s", strerror(errno)); 208207614Simp return 1; 209207614Simp } 210207614Simp return 0; 211207614Simp} 212207614Simp 213207614Simpint 214207614Simpread_init(int fd, FILE *f, const char *mode) 215207614Simp{ 216207614Simp 217207614Simp convert_to_net(NULL, 0, 1); 218207614Simp if (f == NULL) { 219207614Simp file = fdopen(fd, "r"); 220207614Simp if (file == NULL) { 221207614Simp int en = errno; 222207614Simp tftp_log(LOG_ERR, "fdopen() failed: %s", 223207614Simp strerror(errno)); 224207614Simp return en; 225207614Simp } 226207614Simp } else 227207614Simp file = f; 228207614Simp convert = !strcmp(mode, "netascii"); 229207614Simp return 0; 230207614Simp} 231207614Simp 232207614Simpsize_t 233207614Simpread_file(char *buffer, int count) 234207614Simp{ 235207614Simp 236207614Simp if (convert == 0) 237207614Simp return fread(buffer, 1, count, file); 238207614Simp 239207614Simp return convert_to_net(buffer, count, 0); 240207614Simp} 241207614Simp 242207614Simpint 243207614Simpread_close(void) 244207614Simp{ 245207614Simp 246207614Simp if (fclose(file) != 0) { 247207614Simp tftp_log(LOG_ERR, "fclose() failed: %s", strerror(errno)); 248207614Simp return 1; 249207614Simp } 250207614Simp return 0; 251207614Simp} 252207614Simp 253207614Simp 254223487Srodrigc/* When an error has occurred, it is possible that the two sides 255223487Srodrigc * are out of synch. Ie: that what I think is the other side's 256223487Srodrigc * response to packet N is really their response to packet N-1. 257223487Srodrigc * 258223487Srodrigc * So, to try to prevent that, we flush all the input queued up 259223487Srodrigc * for us on the network connection on our host. 260223487Srodrigc * 261223487Srodrigc * We return the number of packets we flushed (mostly for reporting 262223487Srodrigc * when trace is active). 263223487Srodrigc */ 264223487Srodrigc 265207614Simpint 266223487Srodrigcsynchnet(int peer) /* socket to flush */ 267207614Simp{ 268223487Srodrigc int i, j = 0; 269223487Srodrigc char rbuf[MAXPKTSIZE]; 270223487Srodrigc struct sockaddr_storage from; 271223487Srodrigc socklen_t fromlen; 272207614Simp 273223487Srodrigc while (1) { 274223487Srodrigc (void) ioctl(peer, FIONREAD, &i); 275223487Srodrigc if (i) { 276223487Srodrigc j++; 277223487Srodrigc fromlen = sizeof from; 278223487Srodrigc (void) recvfrom(peer, rbuf, sizeof (rbuf), 0, 279223487Srodrigc (struct sockaddr *)&from, &fromlen); 280223487Srodrigc } else { 281223487Srodrigc return(j); 282223487Srodrigc } 283223487Srodrigc } 284207614Simp} 285