Annotation of embedaddon/axTLS/httpd/proc.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (c) Cameron Rich
                      3:  * 
                      4:  * All rights reserved.
                      5:  * 
                      6:  * Redistribution and use in source and binary forms, with or without 
                      7:  * modification, are permitted provided that the following conditions are met:
                      8:  *
                      9:  * * Redistributions of source code must retain the above copyright notice, 
                     10:  *   this list of conditions and the following disclaimer.
                     11:  * * Redistributions in binary form must reproduce the above copyright notice, 
                     12:  *   this list of conditions and the following disclaimer in the documentation 
                     13:  *   and/or other materials provided with the distribution.
                     14:  * * Neither the name of the axTLS project nor the names of its contributors 
                     15:  *   may be used to endorse or promote products derived from this software 
                     16:  *   without specific prior written permission.
                     17:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
                     19:  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
                     20:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
                     21:  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
                     22:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     23:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     24:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
                     25:  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
                     26:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
                     27:  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
                     28:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     29:  */
                     30: 
                     31: #include <stdio.h>
                     32: #include <stdlib.h>
                     33: #include <ctype.h>
                     34: #include <sys/types.h>
                     35: #include <sys/stat.h>
                     36: #include <fcntl.h>
                     37: #include <time.h>
                     38: #include <string.h>
                     39: #include "axhttp.h"
                     40: 
                     41: #define HTTP_VERSION        "HTTP/1.1"
                     42: 
                     43: static const char * index_file = "index.html";
                     44: static const char * rfc1123_format = "%a, %d %b %Y %H:%M:%S GMT";
                     45: 
                     46: static int special_read(struct connstruct *cn, void *buf, size_t count);
                     47: static int special_write(struct connstruct *cn, 
                     48:                                         const char *buf, size_t count);
                     49: static void send_error(struct connstruct *cn, int err);
                     50: static int hexit(char c);
                     51: static void urldecode(char *buf);
                     52: static void buildactualfile(struct connstruct *cn);
                     53: static int sanitizefile(const char *buf);
                     54: static int sanitizehost(char *buf);
                     55: static int htaccess_check(struct connstruct *cn);
                     56: static const char *getmimetype(const char *name);
                     57: 
                     58: #if defined(CONFIG_HTTP_DIRECTORIES)
                     59: static void urlencode(const uint8_t *s, char *t);
                     60: static void procdirlisting(struct connstruct *cn);
                     61: #endif
                     62: #if defined(CONFIG_HTTP_HAS_CGI)
                     63: static void proccgi(struct connstruct *cn);
                     64: static void decode_path_info(struct connstruct *cn, char *path_info);
                     65: static int init_read_post_data(char *buf, char *data, struct connstruct *cn, int old_rv);
                     66: #endif
                     67: #ifdef CONFIG_HTTP_HAS_AUTHORIZATION
                     68: static int auth_check(struct connstruct *cn);
                     69: #endif
                     70: 
                     71: #if AXDEBUG
                     72: #define AXDEBUGSTART \
                     73:        { \
                     74:                FILE *axdout; \
                     75:                axdout = fopen("/var/log/axdebug", "a"); \
                     76:        
                     77: #define AXDEBUGEND \
                     78:                fclose(axdout); \
                     79:        }
                     80: #else /* AXDEBUG */
                     81: #define AXDEBUGSTART
                     82: #define AXDEBUGEND
                     83: #endif /* AXDEBUG */
                     84: 
                     85: /* Returns 1 if elems should continue being read, 0 otherwise */
                     86: static int procheadelem(struct connstruct *cn, char *buf) 
                     87: {
                     88:     char *delim, *value;
                     89: 
                     90:     if ((delim = strchr(buf, ' ')) == NULL)
                     91:         return 0;
                     92: 
                     93:     *delim = 0;
                     94:     value = delim+1;
                     95: 
                     96:     if (strcmp(buf, "GET") == 0 || strcmp(buf, "HEAD") == 0 ||
                     97:                                             strcmp(buf, "POST") == 0) 
                     98:     {
                     99:         if (buf[0] == 'H') 
                    100:             cn->reqtype = TYPE_HEAD;
                    101:         else if (buf[0] == 'P') 
                    102:             cn->reqtype = TYPE_POST;
                    103: 
                    104:         if ((delim = strchr(value, ' ')) == NULL)       /* expect HTTP type */
                    105:             return 0;
                    106: 
                    107:         *delim++ = 0;
                    108:         urldecode(value);
                    109: 
                    110:         if (sanitizefile(value) == 0) 
                    111:         {
                    112:             send_error(cn, 403);
                    113:             return 0;
                    114:         }
                    115: 
                    116: #if defined(CONFIG_HTTP_HAS_CGI)
                    117:         decode_path_info(cn, value);
                    118: #else
                    119:         my_strncpy(cn->filereq, value, MAXREQUESTLENGTH);
                    120: #endif
                    121:         cn->if_modified_since = -1;
                    122:         if (strcmp(delim, "HTTP/1.0") == 0) /* v1.0 HTTP? */
                    123:             cn->is_v1_0 = 1;
                    124:     } 
                    125:     else if (strcasecmp(buf, "Host:") == 0) 
                    126:     {
                    127:         if (sanitizehost(value) == 0) 
                    128:         {
                    129:             removeconnection(cn);
                    130:             return 0;
                    131:         }
                    132: 
                    133:         my_strncpy(cn->server_name, value, MAXREQUESTLENGTH);
                    134:     } 
                    135:     else if (strcasecmp(buf, "Connection:") == 0 && strcmp(value, "close") == 0) 
                    136:     {
                    137:         cn->close_when_done = 1;
                    138:     } 
                    139:     else if (strcasecmp(buf, "If-Modified-Since:") == 0) 
                    140:     {
                    141:         cn->if_modified_since = tdate_parse(value);
                    142:     }
                    143:     else if (strcasecmp(buf, "Expect:") == 0)
                    144:     {
                    145:                /* supposed to be safe to ignore 100-continue */
                    146:                if (strcasecmp(value, "100-continue") != 0) {
                    147:                        send_error(cn, 417); /* expectation failed */
                    148:                        return 0;
                    149:                }
                    150:     }
                    151: #ifdef CONFIG_HTTP_HAS_AUTHORIZATION
                    152:     else if (strcasecmp(buf, "Authorization:") == 0 &&
                    153:                                     strncmp(value, "Basic ", 6) == 0)
                    154:     {
                    155:         int size = sizeof(cn->authorization);
                    156:         if (base64_decode(&value[6], strlen(&value[6]), 
                    157:                                         (uint8_t *)cn->authorization, &size))
                    158:             cn->authorization[0] = 0;   /* error */
                    159:         else
                    160:             cn->authorization[size] = 0;
                    161:     }
                    162: #endif
                    163: #if defined(CONFIG_HTTP_HAS_CGI)
                    164:     else if (strcasecmp(buf, "Content-Length:") == 0)
                    165:     {
                    166:         sscanf(value, "%d", &cn->content_length);
                    167:     }
                    168:     else if (strcasecmp(buf, "Content-Type:") == 0)
                    169:     {
                    170:         my_strncpy(cn->cgicontenttype, value, MAXREQUESTLENGTH);
                    171:     }
                    172:     else if (strcasecmp(buf, "Cookie:") == 0)
                    173:     {
                    174:         my_strncpy(cn->cookie, value, MAXREQUESTLENGTH);
                    175:     }
                    176: #endif
                    177: 
                    178:     return 1;
                    179: }
                    180: 
                    181: #if defined(CONFIG_HTTP_DIRECTORIES)
                    182: static void procdirlisting(struct connstruct *cn)
                    183: {
                    184:     char buf[MAXREQUESTLENGTH];
                    185:     char actualfile[1024];
                    186: 
                    187:     if (cn->reqtype == TYPE_HEAD) 
                    188:     {
                    189:         snprintf(buf, sizeof(buf), HTTP_VERSION
                    190:                 " 200 OK\nContent-Type: text/html\n\n");
                    191:         write(cn->networkdesc, buf, strlen(buf));
                    192:         removeconnection(cn);
                    193:         return;
                    194:     }
                    195: 
                    196:     strcpy(actualfile, cn->actualfile);
                    197: 
                    198: #ifdef WIN32
                    199:     strcat(actualfile, "*");
                    200:     cn->dirp = FindFirstFile(actualfile, &cn->file_data);
                    201: 
                    202:     if (cn->dirp == INVALID_HANDLE_VALUE) 
                    203:     {
                    204:         send_error(cn, 404);
                    205:         return;
                    206:     }
                    207: #else
                    208:     if ((cn->dirp = opendir(actualfile)) == NULL) 
                    209:     {
                    210:         send_error(cn, 404);
                    211:         return;
                    212:     }
                    213: #endif
                    214: 
                    215:     snprintf(buf, sizeof(buf), HTTP_VERSION
                    216:             " 200 OK\nContent-Type: text/html\n\n"
                    217:             "<html><body>\n<title>Directory Listing</title>\n"
                    218:             "<h3>Directory listing of %s://%s%s</h3><br />\n", 
                    219:             cn->is_ssl ? "https" : "http", cn->server_name, cn->filereq);
                    220:     special_write(cn, buf, strlen(buf));
                    221:     cn->state = STATE_DOING_DIR;
                    222: }
                    223: 
                    224: void procdodir(struct connstruct *cn) 
                    225: {
                    226: #ifndef WIN32
                    227:     struct dirent *dp;
                    228: #endif
                    229:     char buf[MAXREQUESTLENGTH];
                    230:     char encbuf[1024];
                    231:     char *file;
                    232: 
                    233:     do 
                    234:     {
                    235:        buf[0] = 0;
                    236: 
                    237: #ifdef WIN32
                    238:         if (!FindNextFile(cn->dirp, &cn->file_data)) 
                    239: #else
                    240:         if ((dp = readdir(cn->dirp)) == NULL)  
                    241: #endif
                    242:         {
                    243:             snprintf(buf, sizeof(buf), "</body></html>\n");
                    244:             special_write(cn, buf, strlen(buf));
                    245:             removeconnection(cn);
                    246: #ifndef WIN32
                    247:             closedir(cn->dirp);
                    248: #endif
                    249:             return;
                    250:         }
                    251: 
                    252: #ifdef WIN32
                    253:         file = cn->file_data.cFileName;
                    254: #else
                    255:         file = dp->d_name;
                    256: #endif
                    257: 
                    258:         /* if no index file, don't display the ".." directory */
                    259:         if (cn->filereq[0] == '/' && cn->filereq[1] == '\0' &&
                    260:                 strcmp(file, "..") == 0) 
                    261:             continue;
                    262: 
                    263:         /* don't display files beginning with "." */
                    264:         if (file[0] == '.' && file[1] != '.')
                    265:             continue;
                    266: 
                    267:         /* make sure a '/' is at the end of a directory */
                    268:         if (cn->filereq[strlen(cn->filereq)-1] != '/')
                    269:             strcat(cn->filereq, "/");
                    270: 
                    271:         /* see if the dir + file is another directory */
                    272:         snprintf(buf, sizeof(buf), "%s%s", cn->actualfile, file);
                    273:         if (isdir(buf))
                    274:             strcat(file, "/");
                    275: 
                    276:         urlencode((uint8_t *)file, encbuf);
                    277:         snprintf(buf, sizeof(buf), "<a href=\"%s%s\">%s</a><br />\n",
                    278:                 cn->filereq, encbuf, file);
                    279:     } while (special_write(cn, buf, strlen(buf)));
                    280: }
                    281: 
                    282: /* Encode funny chars -> %xx in newly allocated storage */
                    283: /* (preserves '/' !) */
                    284: static void urlencode(const uint8_t *s, char *t) 
                    285: {
                    286:     const uint8_t *p = s;
                    287:     char *tp = t;
                    288: 
                    289:     for (; *p; p++) 
                    290:     {
                    291:         if ((*p > 0x00 && *p < ',') ||
                    292:                 (*p > '9' && *p < 'A') ||
                    293:                 (*p > 'Z' && *p < '_') ||
                    294:                 (*p > '_' && *p < 'a') ||
                    295:                 (*p > 'z' && *p < 0xA1)) 
                    296:         {
                    297:             sprintf((char *)tp, "%%%02X", *p);
                    298:             tp += 3; 
                    299:         } 
                    300:         else 
                    301:         {
                    302:             *tp = *p;
                    303:             tp++;
                    304:         }
                    305:     }
                    306: 
                    307:     *tp='\0';
                    308: }
                    309: 
                    310: #endif
                    311: 
                    312: void procreadhead(struct connstruct *cn) 
                    313: {
                    314:     char buf[MAXREADLENGTH], *tp, *next;
                    315:     int rv;
                    316: 
                    317:     memset(buf, 0, sizeof(buf));
                    318:     rv = special_read(cn, buf, sizeof(buf)-1);
                    319:     if (rv <= 0) 
                    320:     {
                    321:         if (rv < 0 || !cn->is_ssl) /* really dead? */
                    322:             removeconnection(cn);
                    323:         return;
                    324:     }
                    325: 
                    326:     buf[rv] = '\0';
                    327:     next = tp = buf;
                    328: 
                    329: #ifdef CONFIG_HTTP_HAS_AUTHORIZATION
                    330:     cn->authorization[0] = 0;
                    331: #endif
                    332: 
                    333:     /* Split up lines and send to procheadelem() */
                    334:     while (*next != '\0') 
                    335:     {
                    336:         /* If we have a blank line, advance to next stage */
                    337:         if (*next == '\r' || *next == '\n') 
                    338:         {
                    339: #if defined(CONFIG_HTTP_HAS_CGI)
                    340:             if (cn->reqtype == TYPE_POST && cn->content_length > 0)
                    341:             {
                    342:                 if (init_read_post_data(buf, next, cn, rv) == 0)
                    343:                     return;
                    344:             }
                    345: #endif
                    346: 
                    347:             buildactualfile(cn);
                    348:             cn->state = STATE_WANT_TO_SEND_HEAD;
                    349:             return;
                    350:         }
                    351: 
                    352:         while (*next != '\r' && *next != '\n' && *next != '\0') 
                    353:             next++;
                    354: 
                    355:         if (*next == '\r') 
                    356:         {
                    357:             *next = '\0';
                    358:             next += 2;
                    359:         }
                    360:         else if (*next == '\n') 
                    361:             *next++ = '\0';
                    362: 
                    363:         if (procheadelem(cn, tp) == 0) 
                    364:             return;
                    365: 
                    366:         tp = next;
                    367:     }
                    368: }
                    369: 
                    370: /* In this function we assume that the file has been checked for
                    371:  * maliciousness (".."s, etc) and has been decoded
                    372:  */
                    373: void procsendhead(struct connstruct *cn) 
                    374: {
                    375:     char buf[MAXREQUESTLENGTH];
                    376:     struct stat stbuf;
                    377:     time_t t_time;
                    378:     struct tm *ptm;
                    379:     char date[32];
                    380:     char last_modified[32];
                    381:     char expires[32];
                    382:     int file_exists;
                    383: 
                    384:     /* are we trying to access a file over the HTTP connection instead of a
                    385:      * HTTPS connection? Or is this directory disabled? */
                    386:     if (htaccess_check(cn))      
                    387:     {
                    388:         send_error(cn, 403);
                    389:         return;
                    390:     }
                    391: 
                    392: #ifdef CONFIG_HTTP_HAS_AUTHORIZATION
                    393:     if (auth_check(cn))     /* see if there is a '.htpasswd' file */
                    394:     {
                    395: #ifdef CONFIG_HTTP_VERBOSE
                    396:         printf("axhttpd: access to %s denied\n", cn->filereq); TTY_FLUSH();
                    397: #endif
                    398:         removeconnection(cn);
                    399:         return;
                    400:     }
                    401: #endif
                    402: 
                    403:     file_exists = stat(cn->actualfile, &stbuf);
                    404: 
                    405: #if defined(CONFIG_HTTP_HAS_CGI)
                    406:     if (file_exists != -1 && cn->is_cgi)
                    407:     {
                    408:         proccgi(cn);
                    409:         return;
                    410:     }
                    411: #endif
                    412: 
                    413:     /* look for "index.html"? */
                    414:     if (isdir(cn->actualfile))
                    415:     {
                    416:         char tbuf[MAXREQUESTLENGTH];
                    417:         snprintf(tbuf, MAXREQUESTLENGTH, "%s%s", cn->actualfile, index_file);
                    418: 
                    419:         if ((file_exists = stat(tbuf, &stbuf)) != -1) 
                    420:             my_strncpy(cn->actualfile, tbuf, MAXREQUESTLENGTH);
                    421:         else
                    422:         {
                    423: #if defined(CONFIG_HTTP_DIRECTORIES)
                    424:             /* If not, we do a directory listing of it */
                    425:             procdirlisting(cn);
                    426: #else
                    427:             send_error(cn, 404);
                    428: #endif
                    429:             return;
                    430:         }
                    431:     }
                    432: 
                    433:     if (file_exists == -1)
                    434:     {
                    435:         send_error(cn, 404);
                    436:         return;
                    437:     }
                    438: 
                    439: 
                    440:     time(&t_time);
                    441:     ptm = gmtime(&t_time);
                    442:     strftime(date, sizeof(date), rfc1123_format, ptm);
                    443: 
                    444:     /* has the file been read before? */
                    445:     if (cn->if_modified_since != -1)  
                    446:                                        
                    447:     {
                    448:         ptm = gmtime(&stbuf.st_mtime);
                    449:         t_time = mktime(ptm);
                    450: 
                    451:         if (cn->if_modified_since >= t_time)
                    452:         {
                    453:             snprintf(buf, sizeof(buf), HTTP_VERSION" 304 Not Modified\nServer: "
                    454:                 "%s\nDate: %s\n\n", server_version, date);
                    455:             special_write(cn, buf, strlen(buf));
                    456:             cn->state = STATE_WANT_TO_READ_HEAD;
                    457:             return;
                    458:         }
                    459:     }
                    460: 
                    461:     if (cn->reqtype == TYPE_HEAD) 
                    462:     {
                    463:         removeconnection(cn);
                    464:         return;
                    465:     } 
                    466:     else 
                    467:     {
                    468:         int flags = O_RDONLY;
                    469: #if defined(WIN32) || defined(CONFIG_PLATFORM_CYGWIN)
                    470:         flags |= O_BINARY;
                    471: #endif
                    472:         cn->filedesc = open(cn->actualfile, flags);
                    473: 
                    474:         if (cn->filedesc < 0) 
                    475:         {
                    476:             send_error(cn, 404);
                    477:             return;
                    478:         }
                    479: 
                    480:         ptm = gmtime(&stbuf.st_mtime);
                    481:         strftime(last_modified, sizeof(last_modified), rfc1123_format, ptm);
                    482:         t_time += CONFIG_HTTP_TIMEOUT;
                    483:         ptm = gmtime(&t_time);
                    484:         strftime(expires, sizeof(expires), rfc1123_format, ptm);
                    485: 
                    486:         snprintf(buf, sizeof(buf), HTTP_VERSION" 200 OK\nServer: %s\n"
                    487:             "Content-Type: %s\nContent-Length: %ld\n"
                    488:             "Date: %s\nLast-Modified: %s\nExpires: %s\n\n", server_version,
                    489:             getmimetype(cn->actualfile), (long) stbuf.st_size,
                    490:             date, last_modified, expires); 
                    491: 
                    492:         special_write(cn, buf, strlen(buf));
                    493: 
                    494: #ifdef CONFIG_HTTP_VERBOSE
                    495:         printf("axhttpd: %s:/%s\n", cn->is_ssl ? "https" : "http", cn->filereq);
                    496:         TTY_FLUSH();
                    497: #endif
                    498: 
                    499: #ifdef WIN32
                    500:         for (;;)
                    501:         {
                    502:             procreadfile(cn);
                    503:             if (cn->filedesc == -1)
                    504:                 break;
                    505: 
                    506:             do 
                    507:             {
                    508:                 procsendfile(cn);
                    509:             } while (cn->state != STATE_WANT_TO_READ_FILE);
                    510:         }
                    511: #else
                    512:         cn->state = STATE_WANT_TO_READ_FILE;
                    513: #endif
                    514:     }
                    515: }
                    516: 
                    517: void procreadfile(struct connstruct *cn) 
                    518: {
                    519:     int rv = read(cn->filedesc, cn->databuf, BLOCKSIZE);
                    520: 
                    521:     if (rv <= 0) 
                    522:     {
                    523:         close(cn->filedesc);
                    524:         cn->filedesc = -1;
                    525: 
                    526:         if (cn->close_when_done)        /* close immediately */
                    527:             removeconnection(cn);
                    528:         else 
                    529:         {
                    530:             if (cn->is_v1_0)    /* die now */
                    531:                 removeconnection(cn);
                    532:             else                /* keep socket open - HTTP 1.1 */
                    533:             {
                    534:                 cn->state = STATE_WANT_TO_READ_HEAD;
                    535:                 cn->numbytes = 0;
                    536:             }
                    537:         }
                    538: 
                    539:         return;
                    540:     }
                    541: 
                    542:     cn->numbytes = rv;
                    543:     cn->state = STATE_WANT_TO_SEND_FILE;
                    544: }
                    545: 
                    546: void procsendfile(struct connstruct *cn) 
                    547: {
                    548:     int rv = special_write(cn, cn->databuf, cn->numbytes);
                    549: 
                    550:     if (rv < 0)
                    551:         removeconnection(cn);
                    552:     else if (rv == cn->numbytes)
                    553:     {
                    554:         cn->state = STATE_WANT_TO_READ_FILE;
                    555:     }
                    556:     else if (rv == 0)
                    557:     { 
                    558:         /* Do nothing */ 
                    559:     }
                    560:     else 
                    561:     {
                    562:         memmove(cn->databuf, cn->databuf + rv, cn->numbytes - rv);
                    563:         cn->numbytes -= rv;
                    564:     }
                    565: }
                    566: 
                    567: #if defined(CONFIG_HTTP_HAS_CGI)
                    568: /* Should this be a bit more dynamic? It would mean more calls to malloc etc */
                    569: #define CGI_ARG_SIZE        17
                    570: 
                    571: static void proccgi(struct connstruct *cn) 
                    572: {
                    573:     int tpipe[2], spipe[2];
                    574:     char *myargs[3];
                    575:     char cgienv[CGI_ARG_SIZE][MAXREQUESTLENGTH];
                    576:     char * cgiptr[CGI_ARG_SIZE+4];
                    577:     const char *type = "HEAD";
                    578:     int cgi_index = 0, i;
                    579:     pid_t pid;
                    580: #ifdef WIN32
                    581:     int tmp_stdout;
                    582: #endif
                    583: 
                    584:     snprintf(cgienv[0], MAXREQUESTLENGTH, 
                    585:             HTTP_VERSION" 200 OK\nServer: %s\n%s",
                    586:             server_version, (cn->reqtype == TYPE_HEAD) ? "\n" : "");
                    587:     special_write(cn, cgienv[0], strlen(cgienv[0]));
                    588: 
                    589:     if (cn->reqtype == TYPE_HEAD) 
                    590:     {
                    591:         removeconnection(cn);
                    592:         return;
                    593:     }
                    594: 
                    595: #ifdef CONFIG_HTTP_VERBOSE
                    596:     printf("[CGI]: %s:/%s\n", cn->is_ssl ? "https" : "http", cn->filereq);
                    597:     TTY_FLUSH();
                    598: #endif
                    599: 
                    600:     /* win32 cgi is a bit too painful */
                    601: #ifndef WIN32
                    602:        /* set up pipe that is used for sending POST query data to CGI script*/
                    603:     if (cn->reqtype == TYPE_POST) 
                    604:     {
                    605:         if (pipe(spipe) == -1)
                    606:         {
                    607:             printf("[CGI]: could not create pipe");
                    608:             TTY_FLUSH();
                    609:             return;
                    610:         }
                    611:     }
                    612: 
                    613:        if (pipe(tpipe) == -1)
                    614:     {
                    615:         printf("[CGI]: could not create pipe");
                    616:         TTY_FLUSH();
                    617:         return;
                    618:     }
                    619: 
                    620:     /*
                    621:      * use vfork() instead of fork() for performance 
                    622:      */
                    623:     if ((pid = vfork()) > 0)  /* parent */
                    624:     {
                    625:         /* Send POST query data to CGI script */
                    626:         if ((cn->reqtype == TYPE_POST) && (cn->content_length > 0)) 
                    627:         {
                    628:             write(spipe[1], cn->post_data, cn->content_length);
                    629:             close(spipe[0]);    
                    630:             close(spipe[1]);
                    631: 
                    632:             /* free the memory that is allocated in read_post_data() */
                    633:             free(cn->post_data); 
                    634:             cn->post_data = NULL;
                    635:         }
                    636: 
                    637:         /* Close the write descriptor */
                    638:         close(tpipe[1]);
                    639:         cn->filedesc = tpipe[0];
                    640:         cn->state = STATE_WANT_TO_READ_FILE;
                    641:         cn->close_when_done = 1;
                    642:         return;
                    643:     }
                    644: 
                    645:     if (pid < 0) /* vfork failed */
                    646:         exit(1);
                    647: 
                    648:     /* The problem child... */
                    649: 
                    650:     /* Our stdout/stderr goes to the socket */
                    651:     dup2(tpipe[1], 1);
                    652:     dup2(tpipe[1], 2);
                    653:     close(tpipe[0]);
                    654:     close(tpipe[1]);
                    655: 
                    656:     /* If it was a POST request, send the socket data to our stdin */
                    657:     if (cn->reqtype == TYPE_POST)  {
                    658:         dup2(spipe[0], 0);  
                    659:         close(spipe[0]);
                    660:         close(spipe[1]);
                    661:     } else    /* Otherwise we can shutdown the read side of the sock */
                    662:         shutdown(cn->networkdesc, 0);
                    663: 
                    664:     myargs[0] = CONFIG_HTTP_CGI_LAUNCHER;
                    665:     myargs[1] = cn->actualfile;
                    666:     myargs[2] = NULL;
                    667: 
                    668:     /* 
                    669:      * set the cgi args. A url is defined by:
                    670:      * http://$SERVER_NAME:$SERVER_PORT$SCRIPT_NAME$PATH_INFO?$QUERY_STRING
                    671:      * TODO: other CGI parameters?
                    672:      */
                    673:     sprintf(cgienv[cgi_index++], "SERVER_SOFTWARE=%s", server_version);
                    674:     strcpy(cgienv[cgi_index++], "DOCUMENT_ROOT=" CONFIG_HTTP_WEBROOT);
                    675:     snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
                    676:             "SERVER_NAME=%s", cn->server_name);
                    677:     sprintf(cgienv[cgi_index++], "SERVER_PORT=%d", 
                    678:             cn->is_ssl ? CONFIG_HTTP_HTTPS_PORT : CONFIG_HTTP_PORT);
                    679:     snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
                    680:             "REQUEST_URI=%s", cn->uri_request);
                    681:     snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
                    682:             "SCRIPT_NAME=%s", cn->filereq);
                    683:     snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
                    684:             "PATH_INFO=%s", cn->uri_path_info);
                    685:     snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
                    686:             "QUERY_STRING=%s", cn->uri_query);
                    687:     snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
                    688:             "REMOTE_ADDR=%s", cn->remote_addr);
                    689:     snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
                    690:             "HTTP_COOKIE=%s", cn->cookie);  /* note: small size */
                    691: #if defined(CONFIG_HTTP_HAS_AUTHORIZATION)
                    692:     snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
                    693:             "REMOTE_USER=%s", cn->authorization);
                    694: #endif
                    695: 
                    696:     switch (cn->reqtype)
                    697:     {
                    698:         case TYPE_GET: 
                    699:             type = "GET";
                    700:             break;
                    701: 
                    702: #if defined(CONFIG_HTTP_HAS_CGI)
                    703:         case TYPE_POST:
                    704:             type = "POST";
                    705:             sprintf(cgienv[cgi_index++], 
                    706:                         "CONTENT_LENGTH=%d", cn->content_length);
                    707:             snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
                    708:                         "CONTENT_TYPE=%s", cn->cgicontenttype);
                    709:             break;
                    710: #endif
                    711:     }
                    712: 
                    713:     sprintf(cgienv[cgi_index++], "REQUEST_METHOD=%s", type);
                    714: 
                    715:     if (cn->is_ssl)
                    716:         strcpy(cgienv[cgi_index++], "HTTPS=on");
                    717: 
                    718:     if (cgi_index >= CGI_ARG_SIZE)
                    719:     {
                    720:         printf("Content-type: text/plain\n\nToo many CGI args (%d, %d)\n",
                    721:                 cgi_index, CGI_ARG_SIZE);
                    722:         _exit(1);
                    723:     }
                    724: 
                    725:     /* copy across the pointer indexes */
                    726:     for (i = 0; i < cgi_index; i++)
                    727:         cgiptr[i] = cgienv[i];
                    728: 
                    729:     cgiptr[i++] = "AUTH_TYPE=Basic";
                    730:     cgiptr[i++] = "GATEWAY_INTERFACE=CGI/1.1";
                    731:     cgiptr[i++] = "SERVER_PROTOCOL="HTTP_VERSION;
                    732:     cgiptr[i] = NULL;
                    733: 
                    734:     execve(myargs[0], myargs, cgiptr);
                    735:     printf("Content-type: text/plain\n\nshouldn't get here\n");
                    736:     _exit(1);
                    737: #endif
                    738: }
                    739: 
                    740: static char * cgi_filetype_match(struct connstruct *cn, const char *fn)
                    741: {
                    742:     struct cgiextstruct *tp = cgiexts;
                    743: 
                    744:     while (tp != NULL) 
                    745:     {
                    746:         char *t;
                    747: 
                    748:         if ((t = strstr(fn, tp->ext)) != NULL)
                    749:         {
                    750:             t += strlen(tp->ext);
                    751: 
                    752:             if (*t == '/' || *t == '\0')
                    753:                 return t;
                    754:             else
                    755:                 return NULL;
                    756: 
                    757:         }
                    758: 
                    759:         tp = tp->next;
                    760:     }
                    761: 
                    762:     return NULL;
                    763: }
                    764: 
                    765: static void decode_path_info(struct connstruct *cn, char *path_info)
                    766: {
                    767:     char *cgi_delim;
                    768: 
                    769: #if defined(CONFIG_HTTP_HAS_CGI)
                    770:     cn->is_cgi = 0;
                    771: #endif
                    772:     *cn->uri_request = '\0';
                    773:     *cn->uri_path_info = '\0';
                    774:     *cn->uri_query = '\0';
                    775: 
                    776:     my_strncpy(cn->uri_request, path_info, MAXREQUESTLENGTH);
                    777: 
                    778:     /* query info? */
                    779:     if ((cgi_delim = strchr(path_info, '?')))
                    780:     {
                    781:         *cgi_delim = '\0';
                    782:         my_strncpy(cn->uri_query, cgi_delim+1, MAXREQUESTLENGTH);
                    783:     }
                    784: 
                    785: #if defined(CONFIG_HTTP_HAS_CGI)
                    786:     if ((cgi_delim = cgi_filetype_match(cn, path_info)) != NULL)
                    787:     {
                    788:         cn->is_cgi = 1;     /* definitely a CGI script */
                    789: 
                    790:         /* path info? */
                    791:         if (*cgi_delim != '\0')
                    792:         {
                    793:             my_strncpy(cn->uri_path_info, cgi_delim, MAXREQUESTLENGTH);
                    794:             *cgi_delim = '\0';
                    795:         }
                    796:     }
                    797: #endif
                    798: 
                    799:     /* the bit at the start must be the script name */
                    800:     my_strncpy(cn->filereq, path_info, MAXREQUESTLENGTH);
                    801: }
                    802: 
                    803: static int init_read_post_data(char *buf, char *data, 
                    804:                                 struct connstruct *cn, int old_rv)
                    805: {
                    806:    char *next = data;
                    807:    int rv = old_rv;
                    808:    char *post_data;
                    809: 
                    810:     /* Too much Post data to send. MAXPOSTDATASIZE should be 
                    811:        configured (now it can be changed in the header file) */
                    812:    if (cn->content_length > MAXPOSTDATASIZE) 
                    813:    {
                    814:        send_error(cn, 418);
                    815:        return 0;
                    816:    }
                    817:    
                    818:    /* remove CRLF */
                    819:    while ((*next == '\r' || *next == '\n') && (next < &buf[rv])) 
                    820:        next++;
                    821:    
                    822:    if (cn->post_data == NULL)
                    823:    {
                    824:        /* Allocate buffer for the POST data that will be used by proccgi 
                    825:           to send POST data to the CGI script */
                    826:        cn->post_data = (char *)ax_calloc(1, (cn->content_length + 1)); 
                    827:    }
                    828: 
                    829:    cn->post_state = 0;
                    830:    cn->post_read = 0;
                    831:    post_data = cn->post_data;
                    832: 
                    833:    while (next < &buf[rv])
                    834:    { 
                    835:        /* copy POST data to buffer */
                    836:        *post_data++ = *next++;
                    837:        cn->post_read++;
                    838:        if (cn->post_read == cn->content_length)
                    839:        { 
                    840:            /* No more POST data to be copied */
                    841:            *post_data = '\0';
                    842:            return 1;
                    843:        }
                    844:    }
                    845: 
                    846:    /* More POST data has to be read. read_post_data will continue with that */
                    847:    cn->post_state = 1;
                    848:    return 0;
                    849: }
                    850: 
                    851: void read_post_data(struct connstruct *cn)
                    852: {
                    853:     char buf[MAXREADLENGTH], *next;
                    854:     char *post_data;
                    855:     int rv;
                    856: 
                    857:     memset(buf, 0, sizeof(buf));
                    858:     rv = special_read(cn, buf, sizeof(buf)-1);
                    859:     if (rv <= 0) 
                    860:     {
                    861:         if (rv < 0 || !cn->is_ssl) /* really dead? */
                    862:             removeconnection(cn);
                    863:         return;
                    864:     }
                    865: 
                    866:     buf[rv] = '\0';
                    867:     next = buf;
                    868:     post_data = &cn->post_data[cn->post_read];
                    869: 
                    870:     while (next < &buf[rv])
                    871:     {
                    872:         *post_data++ = *next++;
                    873:         cn->post_read++;
                    874: 
                    875:         if (cn->post_read == cn->content_length)
                    876:         {  
                    877:             /* No more POST data to be copied */
                    878:             *post_data='\0';
                    879:             cn->post_state = 0;
                    880:             buildactualfile(cn);
                    881:             cn->state = STATE_WANT_TO_SEND_HEAD;
                    882:             return;
                    883:         }
                    884:     }
                    885: 
                    886:     /* More POST data to read */
                    887: }
                    888: 
                    889: #endif  /* CONFIG_HTTP_HAS_CGI */
                    890: 
                    891: /* Decode string %xx -> char (in place) */
                    892: static void urldecode(char *buf) 
                    893: {
                    894:     int v;
                    895:     char *p, *s, *w;
                    896: 
                    897:     w = p = buf;
                    898: 
                    899:     while (*p) 
                    900:     {
                    901:         v = 0;
                    902: 
                    903:         if (*p == '%') 
                    904:         {
                    905:             s = p;
                    906:             s++;
                    907: 
                    908:             if (isxdigit((int) s[0]) && isxdigit((int) s[1]))
                    909:             {
                    910:                 v = hexit(s[0])*16 + hexit(s[1]);
                    911: 
                    912:                 if (v) 
                    913:                 { 
                    914:                     /* do not decode %00 to null char */
                    915:                     *w = (char)v;
                    916:                     p = &s[1];
                    917:                 }
                    918:             }
                    919: 
                    920:         }
                    921: 
                    922:         if (!v) *w=*p;
                    923:         p++; 
                    924:         w++;
                    925:     }
                    926: 
                    927:     *w='\0';
                    928: }
                    929: 
                    930: static int hexit(char c) 
                    931: {
                    932:     if (c >= '0' && c <= '9')
                    933:         return c - '0';
                    934:     else if (c >= 'a' && c <= 'f')
                    935:         return c - 'a' + 10;
                    936:     else if (c >= 'A' && c <= 'F')
                    937:         return c - 'A' + 10;
                    938:     else
                    939:         return 0;
                    940: }
                    941: 
                    942: static void buildactualfile(struct connstruct *cn)
                    943: {
                    944:     char *cp;
                    945:     snprintf(cn->actualfile, MAXREQUESTLENGTH, ".%s", cn->filereq);
                    946: 
                    947: #ifndef WIN32
                    948:     /* Add directory slash if not there */
                    949:     if (isdir(cn->actualfile) && 
                    950:             cn->actualfile[strlen(cn->actualfile)-1] != '/')
                    951:         strcat(cn->actualfile, "/");
                    952: 
                    953:     /* work out the directory name */
                    954:     strncpy(cn->dirname, cn->actualfile, MAXREQUESTLENGTH);
                    955:     if ((cp = strrchr(cn->dirname, '/')) == NULL)
                    956:         cn->dirname[0] = 0;
                    957:     else
                    958:         *cp = 0;
                    959: #else
                    960:     {
                    961:         char curr_dir[MAXREQUESTLENGTH];
                    962:         char path[MAXREQUESTLENGTH];
                    963:         char *t = cn->actualfile;
                    964: 
                    965:         GetCurrentDirectory(MAXREQUESTLENGTH, curr_dir);
                    966: 
                    967:         /* convert all the forward slashes to back slashes */
                    968:         while ((t = strchr(t, '/')))
                    969:             *t++ = '\\';
                    970: 
                    971:         snprintf(path, MAXREQUESTLENGTH, "%s%s", curr_dir, cn->actualfile);
                    972:         memcpy(cn->actualfile, path, MAXREQUESTLENGTH);
                    973: 
                    974:         /* Add directory slash if not there */
                    975:         if (isdir(cn->actualfile) && 
                    976:                     cn->actualfile[strlen(cn->actualfile)-1] != '\\')
                    977:             strcat(cn->actualfile, "\\");
                    978: 
                    979:         /* work out the directory name */
                    980:         strncpy(cn->dirname, cn->actualfile, MAXREQUESTLENGTH);
                    981:         if ((cp = strrchr(cn->dirname, '\\')) == NULL)
                    982:             cn->dirname[0] = 0;
                    983:         else
                    984:             *cp = 0;
                    985:     }
                    986: #endif
                    987: }
                    988: 
                    989: static int sanitizefile(const char *buf) 
                    990: {
                    991:     int len, i;
                    992: 
                    993:     /* Don't accept anything not starting with a / */
                    994:     if (*buf != '/') 
                    995:         return 0;
                    996: 
                    997:     len = strlen(buf);
                    998:     for (i = 0; i < len; i++) 
                    999:     {
                   1000:         /* Check for "/." i.e. don't send files starting with a . */
                   1001:         if (buf[i] == '/' && buf[i+1] == '.') 
                   1002:             return 0;
                   1003:     }
                   1004: 
                   1005:     return 1;
                   1006: }
                   1007: 
                   1008: static int sanitizehost(char *buf)
                   1009: {
                   1010:     while (*buf != '\0') 
                   1011:     {
                   1012:         /* Handle the port */
                   1013:         if (*buf == ':') 
                   1014:         {
                   1015:             *buf = '\0';
                   1016:             return 1;
                   1017:         }
                   1018: 
                   1019:         /* Enforce some basic URL rules... */
                   1020:         if ((isalnum((int)(*buf)) == 0 && *buf != '-' && *buf != '.') ||
                   1021:                 (*buf == '.' && *(buf+1) == '.') ||
                   1022:                 (*buf == '.' && *(buf+1) == '-') ||
                   1023:                 (*buf == '-' && *(buf+1) == '.'))
                   1024:             return 0;
                   1025: 
                   1026:         buf++;
                   1027:     }
                   1028: 
                   1029:     return 1;
                   1030: }
                   1031: 
                   1032: static FILE * exist_check(struct connstruct *cn, const char *check_file)
                   1033: {
                   1034:     char pathname[MAXREQUESTLENGTH];
                   1035:     snprintf(pathname, MAXREQUESTLENGTH, "%s/%s", cn->dirname, check_file);
                   1036:     return fopen(pathname, "r");
                   1037: }
                   1038: 
                   1039: #ifdef CONFIG_HTTP_HAS_AUTHORIZATION
                   1040: static void send_authenticate(struct connstruct *cn, const char *realm)
                   1041: {
                   1042:     char buf[1024];
                   1043: 
                   1044:     snprintf(buf, sizeof(buf), HTTP_VERSION" 401 Unauthorized\n"
                   1045:          "WWW-Authenticate: Basic\n"
                   1046:                  "realm=\"%s\"\n", realm);
                   1047:     special_write(cn, buf, strlen(buf));
                   1048: }
                   1049: 
                   1050: static int check_digest(char *salt, const char *msg_passwd)
                   1051: {
                   1052:     uint8_t b256_salt[MAXREQUESTLENGTH];
                   1053:     uint8_t real_passwd[MD5_SIZE];
                   1054:     int salt_size = sizeof(b256_salt);
                   1055:     int password_size = sizeof(real_passwd);
                   1056:     char *b64_passwd;
                   1057:     uint8_t md5_result[MD5_SIZE];
                   1058:     MD5_CTX ctx;
                   1059: 
                   1060:     /* retrieve the salt */
                   1061:     if ((b64_passwd = strchr(salt, '$')) == NULL)
                   1062:         return -1;
                   1063: 
                   1064:     *b64_passwd++ = 0;
                   1065:     if (base64_decode(salt, strlen(salt), b256_salt, &salt_size))
                   1066:         return -1;
                   1067: 
                   1068:     if (base64_decode(b64_passwd, strlen(b64_passwd), real_passwd,
                   1069:                 &password_size))
                   1070:         return -1;
                   1071: 
                   1072:     /* very simple MD5 crypt algorithm, but then the salt we use is large */
                   1073:     MD5_Init(&ctx);
                   1074:     MD5_Update(&ctx, b256_salt, salt_size);           /* process the salt */
                   1075:     MD5_Update(&ctx, (uint8_t *)msg_passwd, strlen(msg_passwd)); 
                   1076:     MD5_Final(md5_result, &ctx);
                   1077:     return memcmp(md5_result, real_passwd, MD5_SIZE);/* 0 = ok */
                   1078: }
                   1079: 
                   1080: static int auth_check(struct connstruct *cn)
                   1081: {
                   1082:     char line[MAXREQUESTLENGTH];
                   1083:     FILE *fp;
                   1084:     char *cp;
                   1085: 
                   1086:     if ((fp = exist_check(cn, ".htpasswd")) == NULL)
                   1087:         return 0;               /* no .htpasswd file, so let though */
                   1088: 
                   1089:     if (cn->authorization[0] == 0)
                   1090:         goto error;
                   1091: 
                   1092:     /* cn->authorization is in form "username:password" */
                   1093:     if ((cp = strchr(cn->authorization, ':')) == NULL)
                   1094:         goto error;
                   1095:     else
                   1096:         *cp++ = 0;  /* cp becomes the password */
                   1097: 
                   1098:     while (fgets(line, sizeof(line), fp) != NULL)
                   1099:     {
                   1100:         char *b64_file_passwd;
                   1101:         int l = strlen(line);
                   1102: 
                   1103:         /* nuke newline */
                   1104:         if (line[l-1] == '\n')
                   1105:             line[l-1] = 0;
                   1106: 
                   1107:         /* line is form "username:salt(b64)$password(b64)" */
                   1108:         if ((b64_file_passwd = strchr(line, ':')) == NULL)
                   1109:             continue;
                   1110: 
                   1111:         *b64_file_passwd++ = 0;
                   1112: 
                   1113:         if (strcmp(line, cn->authorization)) /* our user? */
                   1114:             continue;
                   1115: 
                   1116:         if (check_digest(b64_file_passwd, cp) == 0)
                   1117:         {
                   1118:             fclose(fp);
                   1119:             return 0;
                   1120:         }
                   1121:     }
                   1122: 
                   1123: error:
                   1124:     fclose(fp);
                   1125:     send_authenticate(cn, cn->server_name);
                   1126:     return -1;
                   1127: }
                   1128: #endif
                   1129: 
                   1130: static int htaccess_check(struct connstruct *cn)
                   1131: {
                   1132:     char line[MAXREQUESTLENGTH];
                   1133:     FILE *fp;
                   1134:     int ret = 0;
                   1135: 
                   1136:     if ((fp = exist_check(cn, ".htaccess")) == NULL)
                   1137:         return 0;               /* no .htaccess file, so let though */
                   1138: 
                   1139:     while (fgets(line, sizeof(line), fp) != NULL)
                   1140:     {
                   1141:         if (strstr(line, "Deny all") || /* access to this dir denied */
                   1142:                     /* Access will be denied unless SSL is active */
                   1143:                     (!cn->is_ssl && strstr(line, "SSLRequireSSL")) ||
                   1144:                     /* Access will be denied if SSL is active */
                   1145:                     (cn->is_ssl && strstr(line, "SSLDenySSL")))
                   1146:         {
                   1147:             ret = -1;
                   1148:             break;
                   1149:         }
                   1150:     }
                   1151: 
                   1152:     fclose(fp);
                   1153:     return ret;
                   1154: }
                   1155: 
                   1156: static void send_error(struct connstruct *cn, int err)
                   1157: {
                   1158:     char buf[MAXREQUESTLENGTH];
                   1159:     char *title;
                   1160:     char *text;
                   1161: 
                   1162:     switch (err)
                   1163:     {
                   1164:         case 403:
                   1165:             title = "Forbidden";
                   1166:             text = "File is protected";
                   1167: #ifdef CONFIG_HTTP_VERBOSE
                   1168:             printf("axhttpd: access to %s denied\n", cn->filereq); TTY_FLUSH();
                   1169: #endif
                   1170:             break;
                   1171: 
                   1172:         case 404:
                   1173:             title = "Not Found";
                   1174:             text = title;
                   1175:             break;
                   1176: 
                   1177:         case 418:
                   1178:             title = "POST data size is too large";
                   1179:             text = title;
                   1180:             break;
                   1181: 
                   1182:         default:
                   1183:             title = "Unknown";
                   1184:             text = "Unknown";
                   1185:             break;
                   1186:     }
                   1187: 
                   1188:     snprintf(buf, sizeof(buf), HTTP_VERSION" 200 OK\n"
                   1189:             "Content-Type: text/html\n\n"
                   1190:             "<html><body>\n<title>%s</title>\n"
                   1191:             "<h1>Error %d - %s</h1>\n</body></html>\n", 
                   1192:             title, err, text);
                   1193:     special_write(cn, buf, strlen(buf));
                   1194: 
                   1195: #ifdef CONFIG_HTTP_VERBOSE
                   1196:     printf("axhttpd: http error: %s [%d]\n", title, err); TTY_FLUSH();
                   1197: #endif
                   1198:     removeconnection(cn);
                   1199: }
                   1200: 
                   1201: static const char *getmimetype(const char *name)
                   1202: {
                   1203:     /* only bother with a few mime types - let the browser figure the rest out */
                   1204:     if (strstr(name, ".htm"))
                   1205:         return "text/html";
                   1206:     else if (strstr(name, ".css"))
                   1207:         return "text/css"; 
                   1208:     else if (strstr(name, ".php"))
                   1209:         return "application/x-http-php"; 
                   1210:     else
                   1211:         return "application/octet-stream";
                   1212: }
                   1213: 
                   1214: static int special_write(struct connstruct *cn, 
                   1215:                                         const char *buf, size_t count)
                   1216: {
                   1217:     if (cn->is_ssl)
                   1218:     {
                   1219:         SSL *ssl = cn->ssl;
                   1220:         return ssl ? ssl_write(ssl, (uint8_t *)buf, count) : -1;
                   1221:     }
                   1222:     else
                   1223:         return SOCKET_WRITE(cn->networkdesc, buf, count);
                   1224: }
                   1225: 
                   1226: static int special_read(struct connstruct *cn, void *buf, size_t count)
                   1227: {
                   1228:     int res;
                   1229: 
                   1230:     if (cn->is_ssl)
                   1231:     {
                   1232:         uint8_t *read_buf;
                   1233:         if ((res = ssl_read(cn->ssl, &read_buf)) > SSL_OK)
                   1234:         {
                   1235:             memcpy(buf, read_buf, res > (int)count ? count : res);
                   1236:         }
                   1237:     }
                   1238:     else
                   1239:         res = SOCKET_READ(cn->networkdesc, buf, count);
                   1240: 
                   1241:     return res;
                   1242: }
                   1243: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>