⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tftpd.c

📁 能把所有线程的数据和环境记录到文件,方便调试.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Copyright (c) 2005, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * *     * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. *     * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. *     * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Markus Gutschke * * This file demonstrates how to add a core dump interface to an existing * service. Typically, you would want to add the call to GetCoreDump() * to an existing interface exposed by your server. But if no such interface * exists, you could also adapt the TFTP code in this module to run as a * thread in your server. * * The code in this module does not perform any type of access control. * As corefiles can expose security sensitive data (e.g. passwords), you * would need to add appropriate access controls when using this (or similar) * code in a production environment. */#include <arpa/inet.h>#include <arpa/tftp.h>#include <errno.h>#include <fcntl.h>#include <getopt.h>#include <google/coredumper.h>#include <netinet/in.h>#include <pthread.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/types.h>#include <unistd.h>#undef  NO_THREADS      /* Support only one connection at a time.            */#undef  CAN_READ_FILES  /* Supports reading files from "/tftpboot/..."       */#undef  CAN_WRITE_FILES /* Supports updating files in "/tftpboot/..."        */#define CAN_READ_CORES  /* Supports serving "core" snapshot files.           */#ifndef TFTPHDRSIZE  #define TFTPHDRSIZE 4#endif/* The "Request" structure contains all the parameters that get passed * from the main server loop to the thread that is processing a given * TFTP connection. */typedef struct Request {  int                debug;  int                id;  int                fd;  struct tftphdr     *tftp;  char               buf[TFTPHDRSIZE + SEGSIZE];  size_t             count;  struct sockaddr_in addr;  socklen_t          len;  const char         *core_name;  char               **dirs;  int                no_ack;  int                sanitize;} Request;#define DBG(...) do {                                                         \                   if (debug)                                                 \                     fprintf(stderr, __VA_ARGS__);                            \                 } while (0)/* tftp_thread() runs in its own thread (unless NO_THREADS is defined). This * function processes a single TFTP connection. */static void *tftp_thread(void *arg) {#define debug (request->debug)  Request            *request    = (Request *)arg;  struct tftphdr     *tftp       = request->tftp;  int                fd          = -1;  int                src         = -1;  int                err         = EBADOP;  int                ioerr       = 0;  struct sockaddr_in addr;  socklen_t          len;  char               *raw_file_name, *mode, *msg, msg_buf[80];  char               *file_name = NULL;  /* Create a new socket for this connection.                                */  if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {    perror("socket");    exit(1);  }  /* Connect this socket to the outgoing interface.                          */  len = sizeof(addr);  if (getsockname(request->fd, (struct sockaddr *)&addr, &len) >= 0 &&      len >= sizeof(struct sockaddr_in)) {    DBG("Responding to %s:%d\n",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));    addr.sin_port = 0;    bind(fd, (struct sockaddr *)&addr, len);  }  /* Get file name and transfer mode from the incoming TFTP packet.          */  if (!(raw_file_name = request->buf + 2, mode = memchr(raw_file_name, '\000',                       request->count - 1 - (raw_file_name - request->buf))) ||      !(++mode, memchr(mode, '\000', request->count - (mode - request->buf)))){    char *ptr;    msg = "Truncated request";  error:    /* Send error message back to client.                                    */    DBG("%s\n", msg);    ptr = strrchr(strcpy(tftp->th_msg, msg), '\000') + 1;    tftp->th_opcode = htons(ERROR);    tftp->th_code   = htons(err);    sendto(fd, tftp, ptr-request->buf, 0,           (struct sockaddr *)&request->addr, request->len);    goto done;  }  /* Only text and binary transfer modes are supported.                      */  if (strcasecmp(mode, "netascii") && strcasecmp(mode, "octet")) {    msg = "Unsupported transfer mode";    goto error;  }  /* Check whether client requested a "core" snapshot of the running process.*/  if (!strcmp(raw_file_name, request->core_name)) {    #ifdef CAN_READ_CORES      /* Core files must be transferred in binary.                           */      if (strcasecmp(mode, "octet")) {        err = EBADOP;        msg = "Core files must be transferred in binary";        goto error;      }      /* Writing core files is not a supported operation.                    */      if (ntohs(tftp->th_opcode) == WRQ) {        err = EBADOP;        msg = "Core files cannot be written";        goto error;      }      /* Here we go. Create a snapshot of this process.                      */      src = GetCoreDump();      /* If we failed to created a core file, report error to the client.    */      if (src < 0) {        err = ENOTFOUND;        *msg_buf = '\000';        msg = strerror_r(errno, msg_buf, sizeof(msg_buf));        goto error;      }    #else      err = ENOTFOUND;      msg = "Core file support is not enabled";      goto error;    #endif  } else {    #if defined(CAN_READ_FILES) || defined(CAN_WRITE_FILES)      /* TFTP is a very simple protocol, which does not support any user       * authentication/authorization. So, we have to be very conservative       * when accessing files. Unless overridden on the command line, this       * server will only access files underneath the "/tftpboot" directory.       * It only serves world-readable files, and it only allow writing to       * world-writable files.       */      static char *tftpdirs[] = { "/tftpboot", NULL };      char        **dirs      = tftpdirs;      struct stat sb;      /* Unless the user requested otherwise, restrict to "/tftpboot/..."    */      if (*request->dirs) {        dirs = request->dirs;      }      /* If "sanitize" option is set, prepend "/tftpboot" (or name of the first       * source directory listed on the command line) to any absolute file       * names.       */      if (*raw_file_name == '/' && request->sanitize) {        char *path = dirs[0];        strcat(strcat(strcpy(malloc(strlen(path) + strlen(raw_file_name) + 2),                             path), "/"), raw_file_name);              } else {        file_name = strdup(raw_file_name);      }            /* Check file attributes.                                              */      memset(&sb, 0, sizeof(sb));      if (*file_name == '/') {        int  ok = 0;        char **ptr;                /* Search for file in all source directories (normally just         * "/tftpboot")         */        for (ptr = &dirs[0]; *ptr; ptr++) {          if (!strncmp(*ptr, file_name, strlen(*ptr)) &&              stat(file_name, &sb) >= 0 && S_ISREG(sb.st_mode)) {            ok++;            break;          }        }        if (!ok) {       file_not_found:          /* Only pre-existing files can be accessed.                        */          if (request->no_ack)            goto done;          else {            err = ENOTFOUND;            msg = "File not found";            goto error;          }        }      } else {        char **ptr, *absolute_file_name = NULL;                /* Search for file in all source directories (normally just         * "/tftpboot")         */        for (ptr = &dirs[0]; *ptr; ptr++) {          absolute_file_name = strcat(strcat(strcpy(malloc(strlen(*ptr) +                                                        strlen(file_name) + 2),                                                    *ptr), "/"), file_name);          if (stat(absolute_file_name, &sb) >= 0 && S_ISREG(sb.st_mode))            break;          free(absolute_file_name);          absolute_file_name = NULL;        }        if (!absolute_file_name)          goto file_not_found;        free(file_name);        file_name = absolute_file_name;      }            /* Check whether the necessary support for reading/writing is compiled       * into this server, and whether the file is world-readable/writable.       */      if (ntohs(tftp->th_opcode) == WRQ) {        #ifdef CAN_WRITE_FILES          if (!(sb.st_mode & S_IWOTH) ||              (src = open(file_name, O_WRONLY)) < 0)        #endif        {       access_denied:          err = EACCESS;          msg = "Access denied";          goto error;        }      } else {        #ifdef CAN_READ_FILES          if (!(sb.st_mode & S_IROTH) ||              (src = open(file_name, O_RDONLY)) < 0)        #endif            goto access_denied;      }    #else      err = ENOTFOUND;      msg = "File operations are not enabled";      goto error;    #endif  }  if (ntohs(tftp->th_opcode) == RRQ) {    DBG("received RRQ <%s, %s>\n", raw_file_name, mode);    #if defined(CAN_READ_FILES) || defined(CAN_READ_CORES)      unsigned short block = 0;      int            count;      /* Mainloop for serving files to clients.                              */      do {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -