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