1/* 2 * tftp.c - a simple, read-only tftp server for qemu 3 * 4 * Copyright (c) 2004 Magnus Damm <damm@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 28struct tftp_session { 29 int in_use; 30 unsigned char filename[TFTP_FILENAME_MAX]; 31 32 uint32_t client_ip; 33 uint16_t client_port; 34 35 int timestamp; 36}; 37 38static struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; 39 40const char *tftp_prefix; 41 42static void tftp_session_update(struct tftp_session *spt) 43{ 44 spt->timestamp = curtime; 45 spt->in_use = 1; 46} 47 48static void tftp_session_terminate(struct tftp_session *spt) 49{ 50 spt->in_use = 0; 51} 52 53static 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 spt->client_ip = ip_geth(tp->ip.ip_src); 74 spt->client_port = port_geth(tp->udp.uh_sport); 75 76 tftp_session_update(spt); 77 78 return k; 79} 80 81static 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 (spt->client_ip == ip_geth(tp->ip.ip_src)) { 91 if (spt->client_port == port_geth(tp->udp.uh_sport)) { 92 return k; 93 } 94 } 95 } 96 } 97 98 return -1; 99} 100 101static 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 131static int tftp_send_oack(struct tftp_session *spt, 132 const char *key, uint32_t value, 133 struct tftp_t *recv_tp) 134{ 135 SockAddress 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 sock_address_init_inet( &saddr, 158 ip_geth(recv_tp->ip.ip_dst), 159 port_geth(recv_tp->udp.uh_dport) ); 160 161 sock_address_init_inet( &daddr, 162 spt->client_ip, 163 spt->client_port ); 164 165 m->m_len = sizeof(struct tftp_t) - 514 + n - 166 sizeof(struct ip) - sizeof(struct udphdr); 167 udp_output2_(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); 168 169 return 0; 170} 171 172 173 174static int tftp_send_error(struct tftp_session *spt, 175 u_int16_t errorcode, const char *msg, 176 struct tftp_t *recv_tp) 177{ 178 SockAddress saddr, daddr; 179 struct mbuf *m; 180 struct tftp_t *tp; 181 int nobytes; 182 183 m = m_get(); 184 185 if (!m) { 186 return -1; 187 } 188 189 memset(m->m_data, 0, m->m_size); 190 191 m->m_data += IF_MAXLINKHDR; 192 tp = (void *)m->m_data; 193 m->m_data += sizeof(struct udpiphdr); 194 195 tp->tp_op = htons(TFTP_ERROR); 196 tp->x.tp_error.tp_error_code = htons(errorcode); 197 pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg); 198 199 sock_address_init_inet( &saddr, 200 ip_geth(recv_tp->ip.ip_dst), 201 port_geth(recv_tp->udp.uh_dport) ); 202 203 sock_address_init_inet( &daddr, 204 spt->client_ip, 205 spt->client_port ); 206 207 nobytes = 2; 208 209 m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) - 210 sizeof(struct ip) - sizeof(struct udphdr); 211 212 udp_output2_(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); 213 214 tftp_session_terminate(spt); 215 216 return 0; 217} 218 219static int tftp_send_data(struct tftp_session *spt, 220 u_int16_t block_nr, 221 struct tftp_t *recv_tp) 222{ 223 SockAddress saddr, daddr; 224 struct mbuf *m; 225 struct tftp_t *tp; 226 int nobytes; 227 228 if (block_nr < 1) { 229 return -1; 230 } 231 232 m = m_get(); 233 234 if (!m) { 235 return -1; 236 } 237 238 memset(m->m_data, 0, m->m_size); 239 240 m->m_data += IF_MAXLINKHDR; 241 tp = (void *)m->m_data; 242 m->m_data += sizeof(struct udpiphdr); 243 244 tp->tp_op = htons(TFTP_DATA); 245 tp->x.tp_data.tp_block_nr = htons(block_nr); 246 247 sock_address_init_inet( &saddr, 248 ip_geth(recv_tp->ip.ip_dst), 249 port_geth(recv_tp->udp.uh_dport) ); 250 251 sock_address_init_inet( &daddr, 252 spt->client_ip, 253 spt->client_port ); 254 255 nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512); 256 257 if (nobytes < 0) { 258 m_free(m); 259 260 /* send "file not found" error back */ 261 262 tftp_send_error(spt, 1, "File not found", tp); 263 264 return -1; 265 } 266 267 m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - 268 sizeof(struct ip) - sizeof(struct udphdr); 269 270 udp_output2_(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); 271 272 if (nobytes == 512) { 273 tftp_session_update(spt); 274 } 275 else { 276 tftp_session_terminate(spt); 277 } 278 279 return 0; 280} 281 282static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) 283{ 284 struct tftp_session *spt; 285 int s, k, n; 286 u_int8_t *src, *dst; 287 288 s = tftp_session_allocate(tp); 289 290 if (s < 0) { 291 return; 292 } 293 294 spt = &tftp_sessions[s]; 295 296 src = tp->x.tp_buf; 297 dst = spt->filename; 298 n = pktlen - ((uint8_t *)&tp->x.tp_buf[0] - (uint8_t *)tp); 299 300 /* get name */ 301 302 for (k = 0; k < n; k++) { 303 if (k < TFTP_FILENAME_MAX) { 304 dst[k] = src[k]; 305 } 306 else { 307 return; 308 } 309 310 if (src[k] == '\0') { 311 break; 312 } 313 } 314 315 if (k >= n) { 316 return; 317 } 318 319 k++; 320 321 /* check mode */ 322 if ((n - k) < 6) { 323 return; 324 } 325 326 if (memcmp(&src[k], "octet\0", 6) != 0) { 327 tftp_send_error(spt, 4, "Unsupported transfer mode", tp); 328 return; 329 } 330 331 k += 6; /* skipping octet */ 332 333 /* do sanity checks on the filename */ 334 335 if ((spt->filename[0] != '/') 336 || (spt->filename[strlen((char *)spt->filename) - 1] == '/') 337 || strstr((char *)spt->filename, "/../")) { 338 tftp_send_error(spt, 2, "Access violation", tp); 339 return; 340 } 341 342 /* only allow exported prefixes */ 343 344 if (!tftp_prefix) { 345 tftp_send_error(spt, 2, "Access violation", tp); 346 return; 347 } 348 349 /* check if the file exists */ 350 351 if (tftp_read_data(spt, 0, spt->filename, 0) < 0) { 352 tftp_send_error(spt, 1, "File not found", tp); 353 return; 354 } 355 356 if (src[n - 1] != 0) { 357 tftp_send_error(spt, 2, "Access violation", tp); 358 return; 359 } 360 361 while (k < n) { 362 const char *key, *value; 363 364 key = (char *)src + k; 365 k += strlen(key) + 1; 366 367 if (k >= n) { 368 tftp_send_error(spt, 2, "Access violation", tp); 369 return; 370 } 371 372 value = (char *)src + k; 373 k += strlen(value) + 1; 374 375 if (strcmp(key, "tsize") == 0) { 376 int tsize = atoi(value); 377 struct stat stat_p; 378 379 if (tsize == 0 && tftp_prefix) { 380 char buffer[1024]; 381 int len; 382 383 len = snprintf(buffer, sizeof(buffer), "%s/%s", 384 tftp_prefix, spt->filename); 385 386 if (stat(buffer, &stat_p) == 0) 387 tsize = stat_p.st_size; 388 else { 389 tftp_send_error(spt, 1, "File not found", tp); 390 return; 391 } 392 } 393 394 tftp_send_oack(spt, "tsize", tsize, tp); 395 } 396 } 397 398 tftp_send_data(spt, 1, tp); 399} 400 401static void tftp_handle_ack(struct tftp_t *tp, int pktlen) 402{ 403 int s; 404 405 s = tftp_session_find(tp); 406 407 if (s < 0) { 408 return; 409 } 410 411 if (tftp_send_data(&tftp_sessions[s], 412 ntohs(tp->x.tp_data.tp_block_nr) + 1, 413 tp) < 0) { 414 return; 415 } 416} 417 418void tftp_input(struct mbuf *m) 419{ 420 struct tftp_t *tp = (struct tftp_t *)m->m_data; 421 422 switch(ntohs(tp->tp_op)) { 423 case TFTP_RRQ: 424 tftp_handle_rrq(tp, m->m_len); 425 break; 426 427 case TFTP_ACK: 428 tftp_handle_ack(tp, m->m_len); 429 break; 430 } 431} 432