"Fossies" - the Fresh Open Source Software Archive

Member "tlswrap-1.04/parse.c" (25 Nov 2006, 13325 Bytes) of package /linux/privat/old/tlswrap-1.04.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "parse.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (c) 2002-2006 Tomas Svensson <ts@codepix.com>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. The name of the author may not be used to endorse or promote products
   14  *    derived from this software without specific prior written permission.
   15  *
   16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
   17  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
   18  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
   19  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  */
   27 
   28 #include <stdio.h>
   29 #include <string.h>
   30 #include <sys/types.h>
   31 #ifdef WIN32
   32 #define WIN32_LEAN_AND_MEAN  /* Exclude rarely-used stuff from Windows headers */
   33 #include <Winsock2.h>
   34 #define snprintf _snprintf
   35 #define strcasecmp _stricmp
   36 #define strncasecmp _strnicmp
   37 typedef   __int32 ssize_t;
   38 int write(SOCKET s, void *buf, int len);
   39 int read(SOCKET s, void *buf, int len);
   40 #else
   41 #include <unistd.h>
   42 #endif
   43 
   44 #include "parse.h"
   45 #include "misc.h"
   46 #include "network.h"
   47 #include "tls.h"
   48 
   49 extern int debug;
   50 
   51 struct ftp_cmd {
   52     char    *cmd;
   53     int     dir;
   54     };
   55 
   56 void intercept_user_buf(struct user_data *ud, char *buf, ssize_t *len)
   57 {
   58     int i;
   59 
   60     struct ftp_cmd cmd[] = {
   61      { "LIST", DATA_DOWN },
   62      { "RETR", DATA_DOWN },
   63      { "NLST", DATA_DOWN },
   64      { "STOR", DATA_UP   },
   65      { "APPE", DATA_UP   },
   66      { "PORT", DATA_PORT },
   67      { "EPRT", DATA_PORT },
   68      { (char*)NULL, 0 }
   69      };
   70 
   71     if (debug)
   72         printf("intercept_user_buf\n");
   73 
   74     if (*len < 4)
   75         return;
   76 
   77     for (i = 0; cmd[i].cmd; i++) 
   78     if (memcmp(buf, cmd[i].cmd, 4) == 0) {
   79         if (cmd[i].dir != DATA_PORT) {
   80             ud->data_direction = cmd[i].dir;
   81             if (debug)
   82                 printf("set direction for %s\n", cmd[i].cmd);
   83         } else if (!ud->active) {
   84             unsigned int port;
   85             char ip[17], *ptr;
   86             int r;
   87             struct dns_msg dns;
   88 
   89             if (debug)
   90                 printf("data port\n");
   91             if ((r = port_to_ipport(buf, ip, sizeof(ip), &port))
   92                 == 0) {
   93                 ud->active = 1;
   94                 if (debug)
   95                     printf("PORT - ip: %s port: %u\n",ip, port);
   96                 strlcpy(ud->serv_data_host, ip,
   97                     sizeof(ud->serv_data_host));
   98                 snprintf(ud->serv_data_port, sizeof(ud->serv_data_port),
   99                     "%u", port);
  100                 strlcpy(dns.hostname, ip, sizeof(dns.hostname));
  101                 strlcpy(dns.port, ud->serv_data_port, sizeof(dns.port));
  102                 ptr = (char*)memchr(buf, '\n', *len);
  103             
  104                 if (ptr != NULL)
  105                     *len = 0;
  106                 setup_connect_2(ud, &dns, 1);
  107                 if (ud->data_connected == CONN_YES)
  108                     open_local_dataport(ud);
  109             } else if (r == -1) { // unsupported EPRT network number
  110                 *len = 0;
  111                 print_to_ud(ud,"522 Network protocol not supported, use (1)\r\n");
  112             }
  113         }
  114     }
  115 }
  116 
  117 int change_serv_buf(struct user_data *ud, char *buf)
  118 {
  119     unsigned int port;
  120     char ip[17];
  121     int r;
  122     struct dns_msg dns;
  123     char *ptr, *ptr2;
  124 
  125     if (ud->prot == 'C')
  126         return 0;
  127 
  128     if (memcmp(buf,"227 ",4) == 0) { /* PASV reply detected */
  129         ud->epsv = 0;
  130         if ((r = pasv_to_ipport(buf, ip, sizeof(ip), &port))
  131             == 0) {
  132             if (debug)
  133                 printf("ip: %s port: %u\n",ip, port);
  134             strlcpy(ud->serv_data_host, ip,
  135                 sizeof(ud->serv_data_host));
  136             snprintf(ud->serv_data_port, sizeof(ud->serv_data_port),
  137                 "%u", port);
  138             strlcpy(dns.hostname, ip, sizeof(dns.hostname));
  139             strlcpy(dns.port, ud->serv_data_port, sizeof(dns.port));
  140             setup_connect_2(ud, &dns, 1);
  141             if (ud->data_connected == CONN_YES) {
  142                 open_local_dataport(ud);
  143             }
  144             return 1;
  145         }
  146         else printf("change_serv_buf failed %d (%s)\n", r, buf);
  147     } else if (memcmp(buf,"229 ",4) == 0) { /* EPSV reply detected */
  148         if (debug)
  149             printf("EPSV (%s)\n", buf);
  150         ud->epsv = 1;
  151         ptr = strstr(buf, "(|||");
  152         if (ptr == NULL)
  153             return 0;
  154         ptr += 4;
  155         if (strlen(ptr) < 3) return 0;
  156         ptr2 = strstr(ptr, "|)");
  157         if (ptr == NULL)
  158             return 0;
  159         *ptr2 = '\0';
  160         strlcpy(ud->serv_data_port, ptr, sizeof(ud->serv_data_port)); 
  161         strlcpy(ud->serv_data_host, ud->serv_host,
  162             sizeof(ud->serv_data_host));
  163         /*
  164         strlcpy(dns.hostname, ud->serv_host, sizeof(dns.hostname));
  165         */
  166         dns = ud->serv_dns;
  167         strlcpy(dns.port, ud->serv_data_port, sizeof(dns.port));
  168         setup_connect_2(ud, &dns, 1);
  169         if (ud->data_connected == CONN_YES)
  170             open_local_dataport(ud);
  171         return 1;
  172         
  173     }
  174     return 0;
  175 }
  176 
  177 void open_local_dataport(struct user_data *ud)
  178 {
  179     char    port[6];
  180     char    pasv[25];
  181     char    tmp[80], *ep;
  182     char    myip[NI_MAXHOST];
  183     
  184     port[0] = '\0';
  185     if (ud->active)
  186         get_local_ip(ud->serv_fd, myip, sizeof(myip));
  187     else
  188         get_local_ip(ud->user_fd, myip, sizeof(myip));
  189     if (debug)
  190         printf("my local ip is %s\n", myip);
  191     ud->user_data_fd = setup_listen(5, myip, port, sizeof(port));
  192     if (debug)
  193         printf("open_local_dataport: fd = %d, port = %s\n",ud->user_data_fd, port);
  194     ipport_to_pasv(pasv, sizeof(pasv), myip, strtol(port, &ep, 10));
  195     if (ud->active) {
  196         snprintf(tmp, sizeof(tmp), "PORT %s\r\n", pasv);
  197         print_to_serv(ud, tmp);
  198     } else {
  199         if (ud->epsv)
  200             snprintf(tmp, sizeof(tmp), "229 Entering Extended Passive Mode (|||%u|)\r\n",(unsigned int)strtol(port, &ep, 10));
  201         else
  202             snprintf(tmp, sizeof(tmp), "227 Entering Passive Mode (%s)\r\n",pasv);
  203         write(ud->user_fd, tmp, strlen(tmp));
  204     }
  205     if (debug)
  206         printf("sent %s",tmp);
  207     ud->data_connected = CONN_DATA_LISTEN;
  208 }
  209 
  210 int pasv_to_ipport(char *buf, char *ip, int iplen, unsigned int *port)
  211 {
  212     char    *ep, *ptr, *ptr2;
  213     int i;
  214     int     num;
  215 
  216     if ( (ptr = strchr(buf, '(')) == NULL)
  217         return 1;
  218 
  219     ptr2 = ++ptr;
  220     for (i = 0; i<4; i++) {
  221         if ((ptr = strchr(++ptr, ',') ) == NULL)
  222             return 2;
  223         *ptr = '.';
  224     }
  225     *ptr++ = '\0';
  226     strlcpy(ip, ptr2, iplen);
  227     ptr2 = ptr;
  228     if ((ptr = strchr(ptr, ',')) == NULL)
  229         return 3;
  230     *ptr++ = '\0';
  231     num = strtol(ptr2, &ep, 10);
  232     if (num < 0 || *ep != '\0')
  233         return 4;
  234     *port = num * 256;
  235     ptr2 = ptr;
  236     if ((ptr = strchr(ptr, ')')) == NULL)
  237         return 5;
  238     *ptr = '\0';
  239     num = strtol(ptr2, &ep, 10);
  240     if (num < 0 || *ep != '\0') {
  241         printf("pasv_to_ipport FAILED with %s that got changed into %d (at %s)\n", ptr2, num, ep);
  242         return 6;
  243     }
  244     *port += num;
  245 
  246     return 0;
  247 }
  248 
  249 void
  250 ipport_to_pasv(char *buf, int len, const char *ip, unsigned int port)
  251 {
  252     char    *ptr;
  253     char    tmp[16];
  254 
  255     strlcpy(tmp, ip, sizeof(tmp));
  256     while ( (ptr = strchr(tmp, '.')) )
  257         *ptr = ',';
  258     snprintf(buf, len, "%s,%d,%d", tmp, port / 256, port % 256); 
  259 }
  260 
  261 int port_to_ipport(char *buf, char *ip, int iplen, unsigned int *port)
  262 {
  263     char    *ep, *ptr, *ptr2, sep;
  264     int i;
  265     int     num;
  266 
  267     if (memcmp(buf, "PORT", 4) == 0) {
  268 
  269         if ( (ptr = strchr(buf, ' ')) == NULL)
  270             return 1;
  271 
  272         ptr2 = ++ptr;
  273         for (i = 0; i<4; i++) {
  274             if ((ptr = strchr(++ptr, ',') ) == NULL)
  275                 return 2;
  276             *ptr = '.';
  277         }
  278         *ptr++ = '\0';
  279         strlcpy(ip, ptr2, iplen);
  280         ptr2 = ptr;
  281         if ((ptr = strchr(ptr, ',')) == NULL)
  282             return 3;
  283         *ptr++ = '\0';
  284         num = strtol(ptr2, &ep, 10);
  285         if (num < 0 || *ep != '\0')
  286             return 4;
  287         *port = num * 256;
  288         ptr2 = ptr;
  289         if ((ptr = strchr(ptr, '\r')) == NULL)
  290             return 5;
  291         *ptr = '\0';
  292         num = strtol(ptr2, &ep, 10);
  293         if (num < 0 || *ep != '\0') {
  294             printf("port_to_ipport FAILED with %s that got changed into %d (at %s)\n", ptr2, num, ep);
  295             return 6;
  296         }
  297         *port += num;
  298     } else { // EPRT
  299         if ((ptr = strchr(buf, ' ')) == NULL)
  300             return 1;
  301         sep = *(++ptr);
  302         if ((ptr2 = strchr(++ptr, sep)) == NULL)
  303             return 1;
  304         *ptr2 = '\0';
  305         num = strtol(ptr, &ep, 10);
  306         if (num != 1)
  307             return -1; // unsupported network
  308         ptr2++; // ptr2 now points to beginning of the ip address
  309         if ((ptr = strchr(ptr2, sep)) == NULL)
  310             return 1;
  311         *ptr = '\0';
  312         strlcpy(ip, ptr2, iplen);
  313         ptr++; // ptr now points to beginning of the port number
  314         if ((ptr2 = strchr(ptr, sep)) == NULL)
  315             return 1;
  316         *ptr2 = '\0';       
  317         num = strtol(ptr, &ep, 10);
  318         if (num < 0 || *ep != '\0') {
  319             printf("port_to_ipport FAILED with %s that got changed into %d (at %s)\n", ptr2, num, ep);
  320             return 6;
  321         }
  322         *port = num;
  323 
  324     }
  325     return 0;
  326 }
  327 
  328 int
  329 parse_serv_buf(struct user_data *ud, int index, char *ucertspath, char *cafile)
  330 {
  331     int size;
  332     char dst[BUF_SIZE], s[100];
  333 
  334     if ( (size = extr_str(ud->serv_input, BUF_SIZE, dst, sizeof(dst))) == 0)
  335         return 1; /* Nothing could be extracted */
  336 
  337 
  338     if ((ud->serv_status == SERV_CONN) && (strncasecmp(dst,"220 ",4) == 0) ) {
  339         print_to_serv(ud, "AUTH TLS\r\n");
  340         ud->serv_status = SERV_AUTH;
  341     } else if ((ud->serv_status == SERV_AUTH) && (strncasecmp(dst,"234 ",4) == 0) ) {
  342         ud->serv_status = SERV_TLS;
  343         tls_auth(ud, 0, ucertspath, cafile);
  344     } else if ((ud->serv_status == SERV_TLS_OK) && (strncasecmp(dst,"200 ",4) == 0) ) {
  345         ud->serv_status = SERV_PBSZ;
  346         snprintf(s, sizeof(s), "PROT %c\r\n", ud->prot);
  347         if (debug)
  348             printf(s);
  349         print_to_serv(ud,s);
  350     } else if ((ud->serv_status == SERV_PBSZ) && (strncasecmp(dst,"200 ",4) == 0) ) {
  351         ud->serv_status = SERV_PROT;
  352         snprintf(s, sizeof(s), "USER %s\r\n",ud->user);
  353         print_to_serv(ud, s);
  354         ud->delay_prot = 0;
  355     } else if ((ud->serv_status == SERV_PBSZ) && (strncasecmp(dst,"530 ",4) == 0) ) {
  356         ud->serv_status = SERV_PROT;
  357         snprintf(s, sizeof(s), "USER %s\r\n",ud->user);
  358         print_to_serv(ud, s);
  359         ud->delay_prot = 1;
  360     } else if ((ud->serv_status == SERV_PROT) && (strncasecmp(dst,"331 ",4) == 0) ) {
  361         snprintf(s, sizeof(s), "PASS %s\r\n",ud->pass);
  362         print_to_serv(ud, s);
  363         if (!ud->delay_prot)
  364             ud->serv_status = SERV_FLOW;
  365     } else if (ud->delay_prot && (ud->serv_status == SERV_PROT) && (strncasecmp(dst,"230 ",4) == 0) ) {
  366         snprintf(s, sizeof(s), "PROT %c\r\n", ud->prot);
  367         if (debug)
  368             printf(s);
  369         print_to_serv(ud,s);
  370     } else if (ud->delay_prot && (ud->serv_status == SERV_PROT) && (strncasecmp(dst,"200 ",4) == 0) ) {
  371         write(ud->user_fd, "230 Bypassed login text because the ftpd can't handle PROT before USER.\r\n", 73);
  372         ud->serv_status = SERV_FLOW;
  373     }
  374     memmove(ud->serv_input, &ud->serv_input[size], BUF_SIZE - size - 1);
  375     ud->serv_ptr -= size;
  376     return 0;
  377 }
  378 
  379 
  380 int
  381 parse_buf(struct user_data *ud, int index, int dns_write_pipe, char *token)
  382 {
  383     int size, updated;
  384     char dst[BUF_SIZE], *ptr, s[100], tmp[200];
  385 
  386     if ( (size = extr_str(ud->user_input, BUF_SIZE, dst, sizeof(dst))) == 0)
  387         return 1; /* Nothing could be extracted */
  388 
  389     /* Parse starts here and is ugly */
  390 
  391     if ((ud->connected == CONN_NO) && (strncasecmp(dst,"USER ",5) == 0)) {
  392         strlcpy(tmp, dst + 5, sizeof(tmp));
  393         ptr = memchr(tmp, token[1], strlen(tmp));
  394         if (ptr != NULL) {
  395             *ptr++ = 0;
  396             if ( (strlen(tmp) > 0) && (strlen(ptr) > 0) ) {
  397                 updated = 0;
  398                 if (tmp[0] == token[0]) {
  399                     ud->prot = 'C'; /* Encrypt control only */
  400                     strlcpy(ud->user, tmp + 1, sizeof(ud->user));
  401                     memmove(tmp, tmp + 1, strlen(tmp));
  402                     updated = 1;
  403                 }
  404                 if (tmp[0] == token[3]) { // Implicit SSL crap
  405                     if (!updated)
  406                         ud->prot = 'P'; /* Encrypt everything */
  407                     strlcpy(ud->user, tmp + 1, sizeof(ud->user));
  408                     memmove(tmp, tmp + 1, strlen(tmp));
  409                     ud->issl = 1;
  410                     updated = 1;
  411                 }
  412                 if (tmp[0] == token[4]) { // + Set security level
  413                     if (!updated)
  414                         ud->prot = 'P'; /* Encrypt everything */
  415                     if ((tmp[1] - '0' >= 0) && (tmp[1] - '0' <= 4))
  416                         ud->sec_level = tmp[1] - '0';
  417                     strlcpy(ud->user, tmp + 2, sizeof(ud->user));
  418                     updated = 1;
  419                 }
  420                 if (!updated) {
  421                     ud->prot = 'P'; /* Encrypt everything */
  422                     strlcpy(ud->user, tmp, sizeof(ud->user));
  423                 }
  424                 strlcpy(ud->serv_host, ptr, sizeof(ud->serv_host));
  425                 ptr = memchr(ud->serv_host, token[2], strlen(ud->serv_host));
  426                 if (ptr != NULL) {
  427                     *ptr++ = 0;
  428                     if (strlen(ptr) > 0)
  429                         strlcpy(ud->serv_port, ptr, sizeof(ud->serv_port));
  430                     else
  431                         ptr = NULL;
  432                 }
  433 
  434                 if (ptr == NULL)
  435                     strlcpy(ud->serv_port, "21", sizeof(ud->serv_port));
  436                 ud->connected = CONN_USER;
  437                 if (debug)
  438                     printf("Username: %s, Host: %s, Port: %s\n",ud->user,
  439                         ud->serv_host, ud->serv_port);
  440                 snprintf(s, sizeof(s), "331 Password required for %s.\r\n", ud->user);
  441                 print_to_ud(ud, s);
  442             }
  443         } else {
  444             if (debug)
  445                 printf("don't find any @\n");
  446             user_close(ud);
  447         }
  448     } else
  449     
  450     /* Attempt connection directly after receiving PASS */
  451 
  452     if ((ud->connected == CONN_USER) && (strncasecmp(dst,"PASS ",5) == 0)) {
  453         strlcpy(ud->pass, dst + 5, sizeof(ud->pass));
  454         ud->connected = CONN_PASS;
  455         setup_connect_1(ud, index, ud->serv_host, ud->serv_port, dns_write_pipe);
  456     } else
  457 
  458     /* Reject AUTH stuff */
  459 
  460     if ((ud->connected == CONN_NO) && (strncasecmp(dst,"AUTH ",5) == 0)) {
  461         snprintf(s, sizeof(s), "502 RFC 2228 authentication not implemented.\r\n");
  462         print_to_ud(ud, s);
  463     }
  464 
  465     memmove(ud->user_input, &ud->user_input[size], BUF_SIZE - size - 1);
  466     ud->user_ptr -= size;
  467     return 0;
  468 }
  469