Home | History | Annotate | Download | only in slirp
      1 /*
      2  * tftp.c - a simple, read-only tftp server for qemu
      3  *
      4  * Copyright (c) 2004 Magnus Damm <damm (at) opensource.se>
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 
     25 #include <slirp.h>
     26 #include "qemu-common.h" // for pstrcpy
     27 
     28 struct tftp_session {
     29     int in_use;
     30     unsigned char filename[TFTP_FILENAME_MAX];
     31 
     32     struct in_addr client_ip;
     33     u_int16_t client_port;
     34 
     35     int timestamp;
     36 };
     37 
     38 static struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
     39 
     40 const char *tftp_prefix;
     41 
     42 static void tftp_session_update(struct tftp_session *spt)
     43 {
     44     spt->timestamp = curtime;
     45     spt->in_use = 1;
     46 }
     47 
     48 static void tftp_session_terminate(struct tftp_session *spt)
     49 {
     50   spt->in_use = 0;
     51 }
     52 
     53 static int tftp_session_allocate(struct tftp_t *tp)
     54 {
     55   struct tftp_session *spt;
     56   int k;
     57 
     58   for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
     59     spt = &tftp_sessions[k];
     60 
     61     if (!spt->in_use)
     62         goto found;
     63 
     64     /* sessions time out after 5 inactive seconds */
     65     if ((int)(curtime - spt->timestamp) > 5000)
     66         goto found;
     67   }
     68 
     69   return -1;
     70 
     71  found:
     72   memset(spt, 0, sizeof(*spt));
     73   memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip));
     74   spt->client_port = tp->udp.uh_sport;
     75 
     76   tftp_session_update(spt);
     77 
     78   return k;
     79 }
     80 
     81 static int tftp_session_find(struct tftp_t *tp)
     82 {
     83   struct tftp_session *spt;
     84   int k;
     85 
     86   for (k = 0; k < TFTP_SESSIONS_MAX; k++) {
     87     spt = &tftp_sessions[k];
     88 
     89     if (spt->in_use) {
     90       if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) {
     91 	if (spt->client_port == tp->udp.uh_sport) {
     92 	  return k;
     93 	}
     94       }
     95     }
     96   }
     97 
     98   return -1;
     99 }
    100 
    101 static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr,
    102 			  u_int8_t *buf, int len)
    103 {
    104   int fd;
    105   int bytes_read = 0;
    106   char buffer[1024];
    107   int n;
    108 
    109   n = snprintf(buffer, sizeof(buffer), "%s/%s",
    110 	       tftp_prefix, spt->filename);
    111   if (n >= sizeof(buffer))
    112     return -1;
    113 
    114   fd = open(buffer, O_RDONLY | O_BINARY);
    115 
    116   if (fd < 0) {
    117     return -1;
    118   }
    119 
    120   if (len) {
    121     lseek(fd, block_nr * 512, SEEK_SET);
    122 
    123     bytes_read = read(fd, buf, len);
    124   }
    125 
    126   close(fd);
    127 
    128   return bytes_read;
    129 }
    130 
    131 static int tftp_send_oack(struct tftp_session *spt,
    132                           const char *key, uint32_t value,
    133                           struct tftp_t *recv_tp)
    134 {
    135     struct sockaddr_in saddr, daddr;
    136     struct mbuf *m;
    137     struct tftp_t *tp;
    138     int n = 0;
    139 
    140     m = m_get();
    141 
    142     if (!m)
    143 	return -1;
    144 
    145     memset(m->m_data, 0, m->m_size);
    146 
    147     m->m_data += IF_MAXLINKHDR;
    148     tp = (void *)m->m_data;
    149     m->m_data += sizeof(struct udpiphdr);
    150 
    151     tp->tp_op = htons(TFTP_OACK);
    152     n += snprintf((char *)tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
    153                   key) + 1;
    154     n += snprintf((char *)tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
    155                   value) + 1;
    156 
    157     saddr.sin_addr = recv_tp->ip.ip_dst;
    158     saddr.sin_port = recv_tp->udp.uh_dport;
    159 
    160     daddr.sin_addr = spt->client_ip;
    161     daddr.sin_port = spt->client_port;
    162 
    163     m->m_len = sizeof(struct tftp_t) - 514 + n -
    164         sizeof(struct ip) - sizeof(struct udphdr);
    165     udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
    166 
    167     return 0;
    168 }
    169 
    170 
    171 
    172 static int tftp_send_error(struct tftp_session *spt,
    173 			   u_int16_t errorcode, const char *msg,
    174 			   struct tftp_t *recv_tp)
    175 {
    176   struct sockaddr_in saddr, daddr;
    177   struct mbuf *m;
    178   struct tftp_t *tp;
    179   int nobytes;
    180 
    181   m = m_get();
    182 
    183   if (!m) {
    184     return -1;
    185   }
    186 
    187   memset(m->m_data, 0, m->m_size);
    188 
    189   m->m_data += IF_MAXLINKHDR;
    190   tp = (void *)m->m_data;
    191   m->m_data += sizeof(struct udpiphdr);
    192 
    193   tp->tp_op = htons(TFTP_ERROR);
    194   tp->x.tp_error.tp_error_code = htons(errorcode);
    195   pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg);
    196 
    197   saddr.sin_addr = recv_tp->ip.ip_dst;
    198   saddr.sin_port = recv_tp->udp.uh_dport;
    199 
    200   daddr.sin_addr = spt->client_ip;
    201   daddr.sin_port = spt->client_port;
    202 
    203   nobytes = 2;
    204 
    205   m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
    206         sizeof(struct ip) - sizeof(struct udphdr);
    207 
    208   udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
    209 
    210   tftp_session_terminate(spt);
    211 
    212   return 0;
    213 }
    214 
    215 static int tftp_send_data(struct tftp_session *spt,
    216 			  u_int16_t block_nr,
    217 			  struct tftp_t *recv_tp)
    218 {
    219   struct sockaddr_in saddr, daddr;
    220   struct mbuf *m;
    221   struct tftp_t *tp;
    222   int nobytes;
    223 
    224   if (block_nr < 1) {
    225     return -1;
    226   }
    227 
    228   m = m_get();
    229 
    230   if (!m) {
    231     return -1;
    232   }
    233 
    234   memset(m->m_data, 0, m->m_size);
    235 
    236   m->m_data += IF_MAXLINKHDR;
    237   tp = (void *)m->m_data;
    238   m->m_data += sizeof(struct udpiphdr);
    239 
    240   tp->tp_op = htons(TFTP_DATA);
    241   tp->x.tp_data.tp_block_nr = htons(block_nr);
    242 
    243   saddr.sin_addr = recv_tp->ip.ip_dst;
    244   saddr.sin_port = recv_tp->udp.uh_dport;
    245 
    246   daddr.sin_addr = spt->client_ip;
    247   daddr.sin_port = spt->client_port;
    248 
    249   nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512);
    250 
    251   if (nobytes < 0) {
    252     m_free(m);
    253 
    254     /* send "file not found" error back */
    255 
    256     tftp_send_error(spt, 1, "File not found", tp);
    257 
    258     return -1;
    259   }
    260 
    261   m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
    262         sizeof(struct ip) - sizeof(struct udphdr);
    263 
    264   udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
    265 
    266   if (nobytes == 512) {
    267     tftp_session_update(spt);
    268   }
    269   else {
    270     tftp_session_terminate(spt);
    271   }
    272 
    273   return 0;
    274 }
    275 
    276 static void tftp_handle_rrq(struct tftp_t *tp, int pktlen)
    277 {
    278   struct tftp_session *spt;
    279   int s, k, n;
    280   u_int8_t *src, *dst;
    281 
    282   s = tftp_session_allocate(tp);
    283 
    284   if (s < 0) {
    285     return;
    286   }
    287 
    288   spt = &tftp_sessions[s];
    289 
    290   src = tp->x.tp_buf;
    291   dst = spt->filename;
    292   n = pktlen - ((uint8_t *)&tp->x.tp_buf[0] - (uint8_t *)tp);
    293 
    294   /* get name */
    295 
    296   for (k = 0; k < n; k++) {
    297     if (k < TFTP_FILENAME_MAX) {
    298       dst[k] = src[k];
    299     }
    300     else {
    301       return;
    302     }
    303 
    304     if (src[k] == '\0') {
    305       break;
    306     }
    307   }
    308 
    309   if (k >= n) {
    310     return;
    311   }
    312 
    313   k++;
    314 
    315   /* check mode */
    316   if ((n - k) < 6) {
    317     return;
    318   }
    319 
    320   if (memcmp(&src[k], "octet\0", 6) != 0) {
    321       tftp_send_error(spt, 4, "Unsupported transfer mode", tp);
    322       return;
    323   }
    324 
    325   k += 6; /* skipping octet */
    326 
    327   /* do sanity checks on the filename */
    328 
    329   if ((spt->filename[0] != '/')
    330       || (spt->filename[strlen((char *)spt->filename) - 1] == '/')
    331       ||  strstr((char *)spt->filename, "/../")) {
    332       tftp_send_error(spt, 2, "Access violation", tp);
    333       return;
    334   }
    335 
    336   /* only allow exported prefixes */
    337 
    338   if (!tftp_prefix) {
    339       tftp_send_error(spt, 2, "Access violation", tp);
    340       return;
    341   }
    342 
    343   /* check if the file exists */
    344 
    345   if (tftp_read_data(spt, 0, spt->filename, 0) < 0) {
    346       tftp_send_error(spt, 1, "File not found", tp);
    347       return;
    348   }
    349 
    350   if (src[n - 1] != 0) {
    351       tftp_send_error(spt, 2, "Access violation", tp);
    352       return;
    353   }
    354 
    355   while (k < n) {
    356       const char *key, *value;
    357 
    358       key = (char *)src + k;
    359       k += strlen(key) + 1;
    360 
    361       if (k >= n) {
    362 	  tftp_send_error(spt, 2, "Access violation", tp);
    363 	  return;
    364       }
    365 
    366       value = (char *)src + k;
    367       k += strlen(value) + 1;
    368 
    369       if (strcmp(key, "tsize") == 0) {
    370 	  int tsize = atoi(value);
    371 	  struct stat stat_p;
    372 
    373 	  if (tsize == 0 && tftp_prefix) {
    374 	      char buffer[1024];
    375 	      int len;
    376 
    377 	      len = snprintf(buffer, sizeof(buffer), "%s/%s",
    378 			     tftp_prefix, spt->filename);
    379 
    380 	      if (stat(buffer, &stat_p) == 0)
    381 		  tsize = stat_p.st_size;
    382 	      else {
    383 		  tftp_send_error(spt, 1, "File not found", tp);
    384 		  return;
    385 	      }
    386 	  }
    387 
    388 	  tftp_send_oack(spt, "tsize", tsize, tp);
    389       }
    390   }
    391 
    392   tftp_send_data(spt, 1, tp);
    393 }
    394 
    395 static void tftp_handle_ack(struct tftp_t *tp, int pktlen)
    396 {
    397   int s;
    398 
    399   s = tftp_session_find(tp);
    400 
    401   if (s < 0) {
    402     return;
    403   }
    404 
    405   if (tftp_send_data(&tftp_sessions[s],
    406 		     ntohs(tp->x.tp_data.tp_block_nr) + 1,
    407 		     tp) < 0) {
    408     return;
    409   }
    410 }
    411 
    412 void tftp_input(struct mbuf *m)
    413 {
    414   struct tftp_t *tp = (struct tftp_t *)m->m_data;
    415 
    416   switch(ntohs(tp->tp_op)) {
    417   case TFTP_RRQ:
    418     tftp_handle_rrq(tp, m->m_len);
    419     break;
    420 
    421   case TFTP_ACK:
    422     tftp_handle_ack(tp, m->m_len);
    423     break;
    424   }
    425 }
    426