19531f299079699193ea4534144420462f980f4faAshwini Sharma/* tftpd.c - TFTP server.
29531f299079699193ea4534144420462f980f4faAshwini Sharma *
39531f299079699193ea4534144420462f980f4faAshwini Sharma * Copyright 2013 Ranjan Kumar <ranjankumar.bth@gmail.com>
49531f299079699193ea4534144420462f980f4faAshwini Sharma * Copyright 2013 Kyungwan Han <asura321@gmail.com>
59531f299079699193ea4534144420462f980f4faAshwini Sharma *
69531f299079699193ea4534144420462f980f4faAshwini Sharma * No Standard.
79531f299079699193ea4534144420462f980f4faAshwini Sharma
8c8018a263d5e67c57411477fbb1e532d7139a75eRob LandleyUSE_TFTPD(NEWTOY(tftpd, "rcu:l", TOYFLAG_BIN))
99531f299079699193ea4534144420462f980f4faAshwini Sharma
109531f299079699193ea4534144420462f980f4faAshwini Sharmaconfig TFTPD
119531f299079699193ea4534144420462f980f4faAshwini Sharma  bool "tftpd"
12f467297736e8edfa0fee9099243d167074595ab8Rob Landley  default n
139531f299079699193ea4534144420462f980f4faAshwini Sharma  help
149531f299079699193ea4534144420462f980f4faAshwini Sharma    usage: tftpd [-cr] [-u USER] [DIR]
159531f299079699193ea4534144420462f980f4faAshwini Sharma
169531f299079699193ea4534144420462f980f4faAshwini Sharma    Transfer file from/to tftp server.
179531f299079699193ea4534144420462f980f4faAshwini Sharma
18f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley    -r	read only
199531f299079699193ea4534144420462f980f4faAshwini Sharma    -c	Allow file creation via upload
20f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley    -u	run as USER
21c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley    -l	Log to syslog (inetd mode requires this)
229531f299079699193ea4534144420462f980f4faAshwini Sharma*/
23afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley
249531f299079699193ea4534144420462f980f4faAshwini Sharma#define FOR_tftpd
259531f299079699193ea4534144420462f980f4faAshwini Sharma#include "toys.h"
269531f299079699193ea4534144420462f980f4faAshwini Sharma
279531f299079699193ea4534144420462f980f4faAshwini SharmaGLOBALS(
289531f299079699193ea4534144420462f980f4faAshwini Sharma  char *user;
29afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley
309531f299079699193ea4534144420462f980f4faAshwini Sharma  long sfd;
319531f299079699193ea4534144420462f980f4faAshwini Sharma  struct passwd *pw;
329531f299079699193ea4534144420462f980f4faAshwini Sharma)
339531f299079699193ea4534144420462f980f4faAshwini Sharma
349531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_BLKSIZE 512  // as per RFC 1350.
359531f299079699193ea4534144420462f980f4faAshwini Sharma
369531f299079699193ea4534144420462f980f4faAshwini Sharma// opcodes
379531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_OP_RRQ  1  // Read Request          RFC 1350, RFC 2090
389531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_OP_WRQ  2  // Write Request         RFC 1350
399531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_OP_DATA 3  // Data chunk            RFC 1350
409531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_OP_ACK  4  // Acknowledgement       RFC 1350
419531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_OP_ERR  5  // Error Message         RFC 1350
429531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_OP_OACK 6  // Option acknowledgment RFC 2347
439531f299079699193ea4534144420462f980f4faAshwini Sharma
449531f299079699193ea4534144420462f980f4faAshwini Sharma// Error Codes:
459531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_NOSUCHFILE  1 // File not found
469531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_ACCESS      2 // Access violation
479531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_FULL        3 // Disk full or allocation exceeded
489531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_ILLEGALOP   4 // Illegal TFTP operation
499531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_UNKID       5 // Unknown transfer ID
509531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_EXISTS      6 // File already exists
519531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_UNKUSER     7 // No such user
529531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_NEGOTIATE   8 // Terminate transfer due to option negotiation
539531f299079699193ea4534144420462f980f4faAshwini Sharma
549531f299079699193ea4534144420462f980f4faAshwini Sharma/* TFTP Packet Formats
559531f299079699193ea4534144420462f980f4faAshwini Sharma *  Type   Op #     Format without header
569531f299079699193ea4534144420462f980f4faAshwini Sharma *         2 bytes    string    1 byte    string    1 byte
579531f299079699193ea4534144420462f980f4faAshwini Sharma *         -----------------------------------------------
589531f299079699193ea4534144420462f980f4faAshwini Sharma *  RRQ/  | 01/02 |  Filename  |   0  |    Mode    |   0  |
599531f299079699193ea4534144420462f980f4faAshwini Sharma *  WRQ    -----------------------------------------------
609531f299079699193ea4534144420462f980f4faAshwini Sharma *         2 bytes    2 bytes      n bytes
619531f299079699193ea4534144420462f980f4faAshwini Sharma *         ---------------------------------
629531f299079699193ea4534144420462f980f4faAshwini Sharma *  DATA  | 03    |   Block #  |    Data    |
639531f299079699193ea4534144420462f980f4faAshwini Sharma *         ---------------------------------
649531f299079699193ea4534144420462f980f4faAshwini Sharma *         2 bytes    2 bytes
659531f299079699193ea4534144420462f980f4faAshwini Sharma *         -------------------
669531f299079699193ea4534144420462f980f4faAshwini Sharma *  ACK   | 04    |   Block #  |
679531f299079699193ea4534144420462f980f4faAshwini Sharma *         --------------------
689531f299079699193ea4534144420462f980f4faAshwini Sharma *         2 bytes  2 bytes       string     1 byte
699531f299079699193ea4534144420462f980f4faAshwini Sharma *         ----------------------------------------
709531f299079699193ea4534144420462f980f4faAshwini Sharma *  ERROR | 05    |  ErrorCode |   ErrMsg   |   0  |
719531f299079699193ea4534144420462f980f4faAshwini Sharma *         ----------------------------------------
729531f299079699193ea4534144420462f980f4faAshwini Sharma */
739531f299079699193ea4534144420462f980f4faAshwini Sharma
74c8018a263d5e67c57411477fbb1e532d7139a75eRob Landleystatic char *g_errpkt = toybuf + TFTPD_BLKSIZE;
759531f299079699193ea4534144420462f980f4faAshwini Sharma
769531f299079699193ea4534144420462f980f4faAshwini Sharma// Create and send error packet.
779531f299079699193ea4534144420462f980f4faAshwini Sharmastatic void send_errpkt(struct sockaddr *dstaddr,
789531f299079699193ea4534144420462f980f4faAshwini Sharma    socklen_t socklen, char *errmsg)
799531f299079699193ea4534144420462f980f4faAshwini Sharma{
809531f299079699193ea4534144420462f980f4faAshwini Sharma  error_msg(errmsg);
819531f299079699193ea4534144420462f980f4faAshwini Sharma  g_errpkt[1] = TFTPD_OP_ERR;
829531f299079699193ea4534144420462f980f4faAshwini Sharma  strcpy(g_errpkt + 4, errmsg);
839531f299079699193ea4534144420462f980f4faAshwini Sharma  if (sendto(TT.sfd, g_errpkt, strlen(errmsg)+5, 0, dstaddr, socklen) < 0)
849531f299079699193ea4534144420462f980f4faAshwini Sharma    perror_exit("sendto failed");
859531f299079699193ea4534144420462f980f4faAshwini Sharma}
869531f299079699193ea4534144420462f980f4faAshwini Sharma
879531f299079699193ea4534144420462f980f4faAshwini Sharma// Used to send / receive packets.
889531f299079699193ea4534144420462f980f4faAshwini Sharmastatic void do_action(struct sockaddr *srcaddr, struct sockaddr *dstaddr,
899531f299079699193ea4534144420462f980f4faAshwini Sharma    socklen_t socklen, char *file, int opcode, int tsize, int blksize)
909531f299079699193ea4534144420462f980f4faAshwini Sharma{
919531f299079699193ea4534144420462f980f4faAshwini Sharma  int fd, done = 0, retry_count = 12, timeout = 100, len;
929531f299079699193ea4534144420462f980f4faAshwini Sharma  uint16_t blockno = 1, pktopcode, rblockno;
939531f299079699193ea4534144420462f980f4faAshwini Sharma  char *ptr, *spkt, *rpkt;
949531f299079699193ea4534144420462f980f4faAshwini Sharma  struct pollfd pollfds[1];
959531f299079699193ea4534144420462f980f4faAshwini Sharma
969531f299079699193ea4534144420462f980f4faAshwini Sharma  spkt = xzalloc(blksize + 4);
979531f299079699193ea4534144420462f980f4faAshwini Sharma  rpkt = xzalloc(blksize + 4);
989531f299079699193ea4534144420462f980f4faAshwini Sharma  ptr = spkt+2; //point after opcode.
999531f299079699193ea4534144420462f980f4faAshwini Sharma
1009531f299079699193ea4534144420462f980f4faAshwini Sharma  pollfds[0].fd = TT.sfd;
1019531f299079699193ea4534144420462f980f4faAshwini Sharma  // initialize groups, setgid and setuid
102afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley  if (TT.pw) xsetuser(TT.pw);
1039531f299079699193ea4534144420462f980f4faAshwini Sharma
1049531f299079699193ea4534144420462f980f4faAshwini Sharma  if (opcode == TFTPD_OP_RRQ) fd = open(file, O_RDONLY, 0666);
1059531f299079699193ea4534144420462f980f4faAshwini Sharma  else fd = open(file, ((toys.optflags & FLAG_c) ?
1069531f299079699193ea4534144420462f980f4faAshwini Sharma        (O_WRONLY|O_TRUNC|O_CREAT) : (O_WRONLY|O_TRUNC)) , 0666);
1079531f299079699193ea4534144420462f980f4faAshwini Sharma  if (fd < 0) {
1089531f299079699193ea4534144420462f980f4faAshwini Sharma    g_errpkt[3] = TFTPD_ER_NOSUCHFILE;
1099531f299079699193ea4534144420462f980f4faAshwini Sharma    send_errpkt(dstaddr, socklen, "can't open file");
1109531f299079699193ea4534144420462f980f4faAshwini Sharma    goto CLEAN_APP;
1119531f299079699193ea4534144420462f980f4faAshwini Sharma  }
1129531f299079699193ea4534144420462f980f4faAshwini Sharma  // For download -> blockno will be 1.
1139531f299079699193ea4534144420462f980f4faAshwini Sharma  // 1st ACK will be from dst,which will have blockno-=1
1149531f299079699193ea4534144420462f980f4faAshwini Sharma  // Create and send ACK packet.
1159531f299079699193ea4534144420462f980f4faAshwini Sharma  if (blksize != TFTPD_BLKSIZE || tsize) {
1169531f299079699193ea4534144420462f980f4faAshwini Sharma    pktopcode = TFTPD_OP_OACK;
1179531f299079699193ea4534144420462f980f4faAshwini Sharma    // add "blksize\000blksize_val\000" in send buffer.
1189531f299079699193ea4534144420462f980f4faAshwini Sharma    if (blksize != TFTPD_BLKSIZE) {
1199531f299079699193ea4534144420462f980f4faAshwini Sharma      strcpy(ptr, "blksize");
1209531f299079699193ea4534144420462f980f4faAshwini Sharma      ptr += strlen("blksize") + 1;
1219531f299079699193ea4534144420462f980f4faAshwini Sharma      ptr += snprintf(ptr, 6, "%d", blksize) + 1;
1229531f299079699193ea4534144420462f980f4faAshwini Sharma    }
1239531f299079699193ea4534144420462f980f4faAshwini Sharma    if (tsize) {// add "tsize\000tsize_val\000" in send buffer.
1249531f299079699193ea4534144420462f980f4faAshwini Sharma      struct stat sb;
1259531f299079699193ea4534144420462f980f4faAshwini Sharma
1269531f299079699193ea4534144420462f980f4faAshwini Sharma      sb.st_size = 0;
1279531f299079699193ea4534144420462f980f4faAshwini Sharma      fstat(fd, &sb);
1289531f299079699193ea4534144420462f980f4faAshwini Sharma      strcpy(ptr, "tsize");
1299531f299079699193ea4534144420462f980f4faAshwini Sharma      ptr += strlen("tsize") + 1;
1309531f299079699193ea4534144420462f980f4faAshwini Sharma      ptr += sprintf(ptr, "%lu", (unsigned long)sb.st_size)+1;
1319531f299079699193ea4534144420462f980f4faAshwini Sharma    }
1329531f299079699193ea4534144420462f980f4faAshwini Sharma    goto SEND_PKT;
1339531f299079699193ea4534144420462f980f4faAshwini Sharma  }
1349531f299079699193ea4534144420462f980f4faAshwini Sharma  // upload ->  ACK 1st packet with filename, as it has blockno 0.
1359531f299079699193ea4534144420462f980f4faAshwini Sharma  if (opcode == TFTPD_OP_WRQ) blockno = 0;
1369531f299079699193ea4534144420462f980f4faAshwini Sharma
1379531f299079699193ea4534144420462f980f4faAshwini Sharma  // Prepare DATA and/or ACK pkt and send it.
1389531f299079699193ea4534144420462f980f4faAshwini Sharma  for (;;) {
1399531f299079699193ea4534144420462f980f4faAshwini Sharma    int poll_ret;
1409531f299079699193ea4534144420462f980f4faAshwini Sharma
1419531f299079699193ea4534144420462f980f4faAshwini Sharma    retry_count = 12, timeout = 100, pktopcode = TFTPD_OP_ACK;
1429531f299079699193ea4534144420462f980f4faAshwini Sharma    ptr = spkt+2;
1439531f299079699193ea4534144420462f980f4faAshwini Sharma    *((uint16_t*)ptr) = htons(blockno);
1449531f299079699193ea4534144420462f980f4faAshwini Sharma    blockno++;
1459531f299079699193ea4534144420462f980f4faAshwini Sharma    ptr += 2;
1469531f299079699193ea4534144420462f980f4faAshwini Sharma    if (opcode == TFTPD_OP_RRQ) {
1479531f299079699193ea4534144420462f980f4faAshwini Sharma      pktopcode = TFTPD_OP_DATA;
1489531f299079699193ea4534144420462f980f4faAshwini Sharma      len = readall(fd, ptr, blksize);
1499531f299079699193ea4534144420462f980f4faAshwini Sharma      if (len < 0) {
1509531f299079699193ea4534144420462f980f4faAshwini Sharma        send_errpkt(dstaddr, socklen, "read-error");
1519531f299079699193ea4534144420462f980f4faAshwini Sharma        break;
1529531f299079699193ea4534144420462f980f4faAshwini Sharma      }
1539531f299079699193ea4534144420462f980f4faAshwini Sharma      if (len != blksize) done = 1; //last pkt.
1549531f299079699193ea4534144420462f980f4faAshwini Sharma      ptr += len;
1559531f299079699193ea4534144420462f980f4faAshwini Sharma    }
1569531f299079699193ea4534144420462f980f4faAshwini SharmaSEND_PKT:
1579531f299079699193ea4534144420462f980f4faAshwini Sharma    // 1st ACK will be from dst, which will have blockno-=1
1589531f299079699193ea4534144420462f980f4faAshwini Sharma    *((uint16_t*)spkt) = htons(pktopcode); //append send pkt's opcode.
1599531f299079699193ea4534144420462f980f4faAshwini SharmaRETRY_SEND:
1609531f299079699193ea4534144420462f980f4faAshwini Sharma    if (sendto(TT.sfd, spkt, (ptr - spkt), 0, dstaddr, socklen) <0)
1619531f299079699193ea4534144420462f980f4faAshwini Sharma      perror_exit("sendto failed");
1629531f299079699193ea4534144420462f980f4faAshwini Sharma    // if "block size < 512", send ACK and exit.
1639531f299079699193ea4534144420462f980f4faAshwini Sharma    if ((pktopcode == TFTPD_OP_ACK) && done) break;
1649531f299079699193ea4534144420462f980f4faAshwini Sharma
165afba5b8efdf1bac2c02ca787840a2be053c800f7Rob LandleyPOLL_INPUT:
1669531f299079699193ea4534144420462f980f4faAshwini Sharma    pollfds[0].events = POLLIN;
1679531f299079699193ea4534144420462f980f4faAshwini Sharma    pollfds[0].fd = TT.sfd;
1689531f299079699193ea4534144420462f980f4faAshwini Sharma    poll_ret = poll(pollfds, 1, timeout);
169afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley    if (poll_ret < 0 && (errno == EINTR || errno == ENOMEM)) goto POLL_INPUT;
1709531f299079699193ea4534144420462f980f4faAshwini Sharma    if (!poll_ret) {
1719531f299079699193ea4534144420462f980f4faAshwini Sharma      if (!--retry_count) {
1729531f299079699193ea4534144420462f980f4faAshwini Sharma        error_msg("timeout");
1739531f299079699193ea4534144420462f980f4faAshwini Sharma        break;
1749531f299079699193ea4534144420462f980f4faAshwini Sharma      }
1759531f299079699193ea4534144420462f980f4faAshwini Sharma      timeout += 150;
1769531f299079699193ea4534144420462f980f4faAshwini Sharma      goto RETRY_SEND;
1779531f299079699193ea4534144420462f980f4faAshwini Sharma    } else if (poll_ret == 1) {
1789531f299079699193ea4534144420462f980f4faAshwini Sharma      len = read(pollfds[0].fd, rpkt, blksize + 4);
1799531f299079699193ea4534144420462f980f4faAshwini Sharma      if (len < 0) {
1809531f299079699193ea4534144420462f980f4faAshwini Sharma        send_errpkt(dstaddr, socklen, "read-error");
1819531f299079699193ea4534144420462f980f4faAshwini Sharma        break;
1829531f299079699193ea4534144420462f980f4faAshwini Sharma      }
183afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley      if (len < 4) goto POLL_INPUT;
1849531f299079699193ea4534144420462f980f4faAshwini Sharma    } else {
1859531f299079699193ea4534144420462f980f4faAshwini Sharma      perror_msg("poll");
1869531f299079699193ea4534144420462f980f4faAshwini Sharma      break;
1879531f299079699193ea4534144420462f980f4faAshwini Sharma    }
1889531f299079699193ea4534144420462f980f4faAshwini Sharma    // Validate receive packet.
1899531f299079699193ea4534144420462f980f4faAshwini Sharma    pktopcode = ntohs(((uint16_t*)rpkt)[0]);
1909531f299079699193ea4534144420462f980f4faAshwini Sharma    rblockno = ntohs(((uint16_t*)rpkt)[1]);
1919531f299079699193ea4534144420462f980f4faAshwini Sharma    if (pktopcode == TFTPD_OP_ERR) {
192c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley      char *message = "DATA Check failure.";
193c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley      char *arr[] = {"File not found", "Access violation",
194c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley        "Disk full or allocation exceeded", "Illegal TFTP operation",
195c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley        "Unknown transfer ID", "File already exists",
196c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley        "No such user", "Terminate transfer due to option negotiation"};
197c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley
198c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley      if (rblockno && (rblockno < 9)) message = arr[rblockno - 1];
199c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley      error_msg(message);
2009531f299079699193ea4534144420462f980f4faAshwini Sharma      break; // Break the for loop.
2019531f299079699193ea4534144420462f980f4faAshwini Sharma    }
2029531f299079699193ea4534144420462f980f4faAshwini Sharma
2039531f299079699193ea4534144420462f980f4faAshwini Sharma    // if download requested by client,
2049531f299079699193ea4534144420462f980f4faAshwini Sharma    // server will send data pkt and will receive ACK pkt from client.
2059531f299079699193ea4534144420462f980f4faAshwini Sharma    if ((opcode == TFTPD_OP_RRQ) && (pktopcode == TFTPD_OP_ACK)) {
2069531f299079699193ea4534144420462f980f4faAshwini Sharma      if (rblockno == (uint16_t) (blockno - 1)) {
2079531f299079699193ea4534144420462f980f4faAshwini Sharma        if (!done) continue; // Send next chunk of data.
2089531f299079699193ea4534144420462f980f4faAshwini Sharma        break;
2099531f299079699193ea4534144420462f980f4faAshwini Sharma      }
2109531f299079699193ea4534144420462f980f4faAshwini Sharma    }
2119531f299079699193ea4534144420462f980f4faAshwini Sharma
2129531f299079699193ea4534144420462f980f4faAshwini Sharma    // server will receive DATA pkt and write the data.
2139531f299079699193ea4534144420462f980f4faAshwini Sharma    if ((opcode == TFTPD_OP_WRQ) && (pktopcode == TFTPD_OP_DATA)) {
2149531f299079699193ea4534144420462f980f4faAshwini Sharma      if (rblockno == blockno) {
2159531f299079699193ea4534144420462f980f4faAshwini Sharma        int nw = writeall(fd, &rpkt[4], len-4);
2169531f299079699193ea4534144420462f980f4faAshwini Sharma        if (nw != len-4) {
2179531f299079699193ea4534144420462f980f4faAshwini Sharma          g_errpkt[3] = TFTPD_ER_FULL;
2189531f299079699193ea4534144420462f980f4faAshwini Sharma          send_errpkt(dstaddr, socklen, "write error");
2199531f299079699193ea4534144420462f980f4faAshwini Sharma          break;
2209531f299079699193ea4534144420462f980f4faAshwini Sharma        }
2219531f299079699193ea4534144420462f980f4faAshwini Sharma
2229531f299079699193ea4534144420462f980f4faAshwini Sharma        if (nw != blksize) done = 1;
2239531f299079699193ea4534144420462f980f4faAshwini Sharma      }
2249531f299079699193ea4534144420462f980f4faAshwini Sharma      continue;
2259531f299079699193ea4534144420462f980f4faAshwini Sharma    }
226afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley    goto POLL_INPUT;
2279531f299079699193ea4534144420462f980f4faAshwini Sharma  } // end of loop
2289531f299079699193ea4534144420462f980f4faAshwini Sharma
2299531f299079699193ea4534144420462f980f4faAshwini SharmaCLEAN_APP:
2309531f299079699193ea4534144420462f980f4faAshwini Sharma  if (CFG_TOYBOX_FREE) {
2319531f299079699193ea4534144420462f980f4faAshwini Sharma    free(spkt);
2329531f299079699193ea4534144420462f980f4faAshwini Sharma    free(rpkt);
2339531f299079699193ea4534144420462f980f4faAshwini Sharma    close(fd);
2349531f299079699193ea4534144420462f980f4faAshwini Sharma  }
2359531f299079699193ea4534144420462f980f4faAshwini Sharma}
2369531f299079699193ea4534144420462f980f4faAshwini Sharma
2379531f299079699193ea4534144420462f980f4faAshwini Sharmavoid tftpd_main(void)
2389531f299079699193ea4534144420462f980f4faAshwini Sharma{
239f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley  int fd = 0, recvmsg_len, rbuflen, opcode, blksize = TFTPD_BLKSIZE, tsize = 0, set =1;
2409531f299079699193ea4534144420462f980f4faAshwini Sharma  struct sockaddr_storage srcaddr, dstaddr;
241c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley  socklen_t socklen = sizeof(struct sockaddr_storage);
242c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley  char *buf = toybuf;
2439531f299079699193ea4534144420462f980f4faAshwini Sharma
2449531f299079699193ea4534144420462f980f4faAshwini Sharma  memset(&srcaddr, 0, sizeof(srcaddr));
245afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley  if (getsockname(0, (struct sockaddr *)&srcaddr, &socklen)) {
2469531f299079699193ea4534144420462f980f4faAshwini Sharma    toys.exithelp = 1;
2479531f299079699193ea4534144420462f980f4faAshwini Sharma    error_exit(NULL);
2489531f299079699193ea4534144420462f980f4faAshwini Sharma  }
2499531f299079699193ea4534144420462f980f4faAshwini Sharma
2505ec4ab3113dcc813b6040d7ded38e297df99dc0eRob Landley  if (TT.user) TT.pw = xgetpwnam(TT.user);
251afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley  if (*toys.optargs) xchroot(*toys.optargs);
2529531f299079699193ea4534144420462f980f4faAshwini Sharma
253f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley  recvmsg_len = recvfrom(fd, toybuf, blksize, 0, (void *)&dstaddr, &socklen);
254c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley
255f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley  TT.sfd = xsocket(dstaddr.ss_family, SOCK_DGRAM, 0);
256c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley  if (setsockopt(TT.sfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&set,
257c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley        sizeof(set)) < 0) perror_exit("setsockopt failed");
258f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley  if (bind(TT.sfd, (void *)&srcaddr, socklen)) perror_exit("bind");
259f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley  if (connect(TT.sfd, (void *)&dstaddr, socklen) < 0)
260c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley    perror_exit("can't connect to remote host");
2619531f299079699193ea4534144420462f980f4faAshwini Sharma  // Error condition.
262f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley  if (recvmsg_len<4 || recvmsg_len>TFTPD_BLKSIZE || toybuf[recvmsg_len-1]) {
2639531f299079699193ea4534144420462f980f4faAshwini Sharma    send_errpkt((struct sockaddr*)&dstaddr, socklen, "packet format error");
2649531f299079699193ea4534144420462f980f4faAshwini Sharma    return;
2659531f299079699193ea4534144420462f980f4faAshwini Sharma  }
2669531f299079699193ea4534144420462f980f4faAshwini Sharma
2679531f299079699193ea4534144420462f980f4faAshwini Sharma  // request is either upload or Download.
268f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley  opcode = buf[1];
2699531f299079699193ea4534144420462f980f4faAshwini Sharma  if (((opcode != TFTPD_OP_RRQ) && (opcode != TFTPD_OP_WRQ))
2709531f299079699193ea4534144420462f980f4faAshwini Sharma      || ((opcode == TFTPD_OP_WRQ) && (toys.optflags & FLAG_r))) {
2719531f299079699193ea4534144420462f980f4faAshwini Sharma    send_errpkt((struct sockaddr*)&dstaddr, socklen,
272f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley    	(opcode == TFTPD_OP_WRQ) ? "write error" : "packet format error");
2739531f299079699193ea4534144420462f980f4faAshwini Sharma    return;
2749531f299079699193ea4534144420462f980f4faAshwini Sharma  }
2759531f299079699193ea4534144420462f980f4faAshwini Sharma
2769531f299079699193ea4534144420462f980f4faAshwini Sharma  buf += 2;
2779531f299079699193ea4534144420462f980f4faAshwini Sharma  if (*buf == '.' || strstr(buf, "/.")) {
2789531f299079699193ea4534144420462f980f4faAshwini Sharma    send_errpkt((struct sockaddr*)&dstaddr, socklen, "dot in filename");
2799531f299079699193ea4534144420462f980f4faAshwini Sharma    return;
2809531f299079699193ea4534144420462f980f4faAshwini Sharma  }
2819531f299079699193ea4534144420462f980f4faAshwini Sharma
2829531f299079699193ea4534144420462f980f4faAshwini Sharma  buf += strlen(buf) + 1; //1 '\0'.
2839531f299079699193ea4534144420462f980f4faAshwini Sharma  // As per RFC 1350, mode is case in-sensitive.
284f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley  if (buf >= toybuf+recvmsg_len || strcasecmp(buf, "octet")) {
2859531f299079699193ea4534144420462f980f4faAshwini Sharma    send_errpkt((struct sockaddr*)&dstaddr, socklen, "packet format error");
2869531f299079699193ea4534144420462f980f4faAshwini Sharma    return;
2879531f299079699193ea4534144420462f980f4faAshwini Sharma  }
2889531f299079699193ea4534144420462f980f4faAshwini Sharma
2899531f299079699193ea4534144420462f980f4faAshwini Sharma  //RFC2348. e.g. of size type: "ttype1\0ttype1_val\0...ttypeN\0ttypeN_val\0"
2909531f299079699193ea4534144420462f980f4faAshwini Sharma  buf += strlen(buf) + 1;
291c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley  rbuflen = toybuf + recvmsg_len - buf;
2929531f299079699193ea4534144420462f980f4faAshwini Sharma  if (rbuflen) {
2939531f299079699193ea4534144420462f980f4faAshwini Sharma    int jump = 0, bflag = 0;
2949531f299079699193ea4534144420462f980f4faAshwini Sharma
2959531f299079699193ea4534144420462f980f4faAshwini Sharma    for (; rbuflen; rbuflen -= jump, buf += jump) {
2969531f299079699193ea4534144420462f980f4faAshwini Sharma      if (!bflag && !strcasecmp(buf, "blksize")) { //get blksize
2979531f299079699193ea4534144420462f980f4faAshwini Sharma        errno = 0;
2989531f299079699193ea4534144420462f980f4faAshwini Sharma        blksize = strtoul(buf, NULL, 10);
2999531f299079699193ea4534144420462f980f4faAshwini Sharma        if (errno || blksize > 65564 || blksize < 8) blksize = TFTPD_BLKSIZE;
3009531f299079699193ea4534144420462f980f4faAshwini Sharma        bflag ^= 1;
3019531f299079699193ea4534144420462f980f4faAshwini Sharma      } else if (!tsize && !strcasecmp(buf, "tsize")) tsize ^= 1;
3029531f299079699193ea4534144420462f980f4faAshwini Sharma
3039531f299079699193ea4534144420462f980f4faAshwini Sharma      jump += strlen(buf) + 1;
3049531f299079699193ea4534144420462f980f4faAshwini Sharma    }
3059531f299079699193ea4534144420462f980f4faAshwini Sharma    tsize &= (opcode == TFTPD_OP_RRQ);
3069531f299079699193ea4534144420462f980f4faAshwini Sharma  }
3079531f299079699193ea4534144420462f980f4faAshwini Sharma
3089531f299079699193ea4534144420462f980f4faAshwini Sharma  //do send / receive file.
3099531f299079699193ea4534144420462f980f4faAshwini Sharma  do_action((struct sockaddr*)&srcaddr, (struct sockaddr*)&dstaddr,
310c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley      socklen, toybuf + 2, opcode, tsize, blksize);
3119531f299079699193ea4534144420462f980f4faAshwini Sharma  if (CFG_TOYBOX_FREE) close(STDIN_FILENO);
3129531f299079699193ea4534144420462f980f4faAshwini Sharma}
313