Annotation of embedaddon/axTLS/httpd/proc.c, revision 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>