Exemple #1
0
void procreadfile(struct connstruct *cn)
{
    int rv = read(cn->filedesc, cn->databuf, BLOCKSIZE);

    if (rv <= 0) {
        close(cn->filedesc);
        cn->filedesc = -1;

        if (cn->close_when_done)        /* close immediately */
            removeconnection(cn);
        else {
            if (cn->is_v1_0)    /* die now */
                removeconnection(cn);
            else {              /* keep socket open - HTTP 1.1 */
                cn->state = STATE_WANT_TO_READ_HEAD;
                cn->numbytes = 0;
            }
        }

        return;
    }

    cn->numbytes = rv;
    cn->state = STATE_WANT_TO_SEND_FILE;
}
Exemple #2
0
void read_post_data(struct connstruct *cn)
{
    char buf[MAXREADLENGTH], *next;
    char *post_data;
    int rv;

    memset(buf, 0, sizeof(buf));
    rv = special_read(cn, buf, sizeof(buf) - 1);
    if (rv <= 0) {
        if (rv < 0 || !cn->is_ssl) /* really dead? */
            removeconnection(cn);
        return;
    }

    buf[rv] = '\0';
    next = buf;
    post_data = &cn->post_data[cn->post_read];

    while (next < &buf[rv]) {
        *post_data++ = *next++;
        cn->post_read++;

        if (cn->post_read == cn->content_length) {
            /* No more POST data to be copied */
            *post_data = '\0';
            cn->post_state = 0;
            buildactualfile(cn);
            cn->state = STATE_WANT_TO_SEND_HEAD;
            return;
        }
    }

    /* More POST data to read */
}
Exemple #3
0
static void procdirlisting(struct connstruct *cn)
{
    char buf[MAXREQUESTLENGTH];
    char actualfile[1024];

    if (cn->reqtype == TYPE_HEAD) {
        snprintf(buf, sizeof(buf), HTTP_VERSION
                 " 200 OK\nContent-Type: text/html\n\n");
        if (write(cn->networkdesc, buf, strlen(buf)) < 0) {
            printf("procdirlisting: could not write");
            TTY_FLUSH();
        }

        removeconnection(cn);
        return;
    }

    strcpy(actualfile, cn->actualfile);


    if ((cn->dirp = opendir(actualfile)) == NULL) {
        send_error(cn, 404);
        return;
    }

    snprintf(buf, sizeof(buf), HTTP_VERSION
             " 200 OK\nContent-Type: text/html\n\n"
             "<html><body>\n<title>Directory Listing</title>\n"
             "<h3>Directory listing of %s://%s%s</h3><br />\n",
             cn->is_ssl ? "https" : "http", cn->server_name, cn->filereq);
    special_write(cn, buf, strlen(buf));
    cn->state = STATE_DOING_DIR;
}
Exemple #4
0
void procreadhead(struct connstruct *cn)
{
    char buf[MAXREADLENGTH], *tp, *next;
    int rv;

    memset(buf, 0, sizeof(buf));
    rv = special_read(cn, buf, sizeof(buf) - 1);
    if (rv <= 0) {
        if (rv < 0 || !cn->is_ssl) /* really dead? */
            removeconnection(cn);
        return;
    }

    buf[rv] = '\0';
    next = tp = buf;

#ifdef CONFIG_HTTP_HAS_AUTHORIZATION
    cn->authorization[0] = 0;
#endif

    /* Split up lines and send to procheadelem() */
    while (*next != '\0') {
        /* If we have a blank line, advance to next stage */
        if (*next == '\r' || *next == '\n') {
#if defined(CONFIG_HTTP_HAS_CGI)
            if (cn->reqtype == TYPE_POST && cn->content_length > 0) {
                if (init_read_post_data(buf, next, cn, rv) == 0)
                    return;
            }
#endif

            buildactualfile(cn);
            cn->state = STATE_WANT_TO_SEND_HEAD;
            return;
        }

        while (*next != '\r' && *next != '\n' && *next != '\0')
            next++;

        if (*next == '\r') {
            *next = '\0';
            next += 2;
        } else if (*next == '\n')
            *next++ = '\0';

        if (procheadelem(cn, tp) == 0)
            return;

        tp = next;
    }
}
Exemple #5
0
/*
* listenproc_cleanup
*
* Cleanup handler for the listener process.
*
* Parameters:
*     arg : pointer : A pointer to a listenerinfo_t structure containing
*                     information required by the thread.
*
* Return Value:
*     The function returns NULL.
*
* Remarks:
*     This routine was originally intended to work with the pthread_cleanup_push
*     and pthread_cleanup_pop mechanism, but support for this mechanism isn't
*     widely supported in the environments in which this code was tested.
*     Therefore this routine is called explicitly by listenproc.
*
*/
static void * listenproc_cleanup (void * arg)
{
    listenerinfo_t * myli = (listenerinfo_t *) arg;

    if (verbose >= 10)
        printf ("listenproc_cleanup: shutting down connection\n");

    removeconnection (myli->cmgr, myli->conn);
    destroyconnection (myli->conn);
    close (myli->socketfd);
    free (myli);

    return NULL;
}
Exemple #6
0
void procsendfile(struct connstruct *cn)
{
    int rv = special_write(cn, cn->databuf, cn->numbytes);

    if (rv < 0)
        removeconnection(cn);
    else if (rv == cn->numbytes) {
        cn->state = STATE_WANT_TO_READ_FILE;
    } else if (rv == 0) {
        /* Do nothing */
    } else {
        memmove(cn->databuf, cn->databuf + rv, cn->numbytes - rv);
        cn->numbytes -= rv;
    }
}
Exemple #7
0
void procdodir(struct connstruct *cn)
{

    struct dirent *dp;
    char buf[MAXREQUESTLENGTH];
    char encbuf[1024];
    char *file;

    do {
        buf[0] = 0;


        if ((dp = readdir(cn->dirp)) == NULL) {
            snprintf(buf, sizeof(buf), "</body></html>\n");
            special_write(cn, buf, strlen(buf));
            removeconnection(cn);

            closedir(cn->dirp);
            return;
        }

        file = dp->d_name;

        /* if no index file, don't display the ".." directory */
        if (cn->filereq[0] == '/' && cn->filereq[1] == '\0' &&
            strcmp(file, "..") == 0)
            continue;

        /* don't display files beginning with "." */
        if (file[0] == '.' && file[1] != '.')
            continue;

        /* make sure a '/' is at the end of a directory */
        if (cn->filereq[strlen(cn->filereq) - 1] != '/')
            strcat(cn->filereq, "/");

        /* see if the dir + file is another directory */
        snprintf(buf, sizeof(buf), "%s%s", cn->actualfile, file);
        if (isdir(buf))
            strcat(file, "/");

        urlencode((uint8_t *)file, encbuf);
        snprintf(buf, sizeof(buf), "<a href=\"%s%s\">%s</a><br />\n",
                 cn->filereq, encbuf, file);
    } while (special_write(cn, buf, strlen(buf)));
}
Exemple #8
0
static void send_error(struct connstruct *cn, int err)
{
    char buf[MAXREQUESTLENGTH];
    char *title;
    char *text;

    switch (err) {
    case 403:
        title = "Forbidden";
        text = "File is protected";
#ifdef CONFIG_HTTP_VERBOSE
        printf("axhttpd: access to %s denied\n", cn->filereq); TTY_FLUSH();
#endif
        break;

    case 404:
        title = "Not Found";
        text = title;
        break;

    case 418:
        title = "POST data size is too large";
        text = title;
        break;

    default:
        title = "Unknown";
        text = "Unknown";
        break;
    }

    snprintf(buf, sizeof(buf), HTTP_VERSION" 200 OK\n"
             "Content-Type: text/html\n\n"
             "<html><body>\n<title>%s</title>\n"
             "<h1>Error %d - %s</h1>\n</body></html>\n",
             title, err, text);
    special_write(cn, buf, strlen(buf));

#ifdef CONFIG_HTTP_VERBOSE
    printf("axhttpd: http error: %s [%d]\n", title, err); TTY_FLUSH();
#endif
    removeconnection(cn);
}
Exemple #9
0
int main(int argc, char *argv[]) 
{
    fd_set rfds, wfds;
    struct connstruct *tp, *to;
    struct serverstruct *sp;
    int rnum, wnum, active;
    int i = 1;
    time_t currtime;
    char *httpAddress = NULL;
    int httpPort = CONFIG_HTTP_PORT;
    char *httpsAddress = NULL;
    int httpsPort = CONFIG_HTTP_HTTPS_PORT;
    uint32_t options = CONFIG_HTTP_DEFAULT_SSL_OPTIONS;
    char *portStr;
    char *private_key = NULL;
    char *cert = NULL;

#ifdef WIN32
    WORD wVersionRequested = MAKEWORD(2, 2);
    WSADATA wsaData;
    WSAStartup(wVersionRequested,&wsaData);
#else
    signal(SIGPIPE, SIG_IGN);
#if defined(CONFIG_HTTP_HAS_CGI)
    signal(SIGCHLD, reaper);
#endif
#ifdef CONFIG_HTTP_VERBOSE
    signal(SIGQUIT, die);
#endif
#endif

#ifdef CONFIG_HTTP_VERBOSE
    signal(SIGTERM, die);
    signal(SIGINT, sigint_cleanup);
#endif
    tdate_init();

    /* get some command-line parameters */
    while (argv[i] != NULL)
    {
        if (strcmp(argv[i], "-p") == 0 && argv[i+1] != NULL)
        {
            if ((portStr = strchr(argv[i+1], ':')) != NULL)
            {
                httpAddress = argv[i+1];
                *portStr = 0;
                httpPort = atoi(portStr + 1);
            }
            else
                httpPort = atoi(argv[i+1]);

            i += 2;
            continue;
        }

        if (strcmp(argv[i], "-s") == 0 && argv[i+1] != NULL)
        {
            if ((portStr = strchr(argv[i+1], ':')) != NULL)
            {
                httpsAddress = argv[i+1];
                *portStr = 0;
                httpsPort = atoi(portStr + 1);
            }
            else
                httpsPort = atoi(argv[i+1]);

            i += 2;
            continue;
        }

        if (strcmp(argv[i], "-w") == 0 && argv[i+1] != NULL)
        {
            webroot = argv[i+1];
            i += 2;
            continue;
        }

        if (strcmp(argv[i], "-cert") == 0 && argv[i+1] != NULL)
        {
            cert = argv[i+1];
            i += 2;
            continue;
        }

        if (strcmp(argv[i], "-key") == 0 && argv[i+1] != NULL)
        {
            private_key = argv[i+1];
            i += 2;
            continue;
        }
        printf("%s:\n"
               "    [-p [address:]httpport]\n"
               "    [-s [address:]httpsport]\n"
               "    [-key private_key]\n"
               "    [-cert cert]\n"
               "    [-w webroot]\n", argv[0]);
        exit(1);
    }

    for (i = 0; i < INITIAL_CONNECTION_SLOTS; i++) 
    {
        tp = freeconns;
        freeconns = (struct connstruct *)calloc(1, sizeof(struct connstruct));
        freeconns->next = tp;
    }

    if ((active = openlistener(httpAddress, httpPort)) == -1) 
    {
#ifdef CONFIG_HTTP_VERBOSE
        fprintf(stderr, "ERR: Couldn't bind to port %d\n", httpPort);
#endif
        exit(1);
    }

    addtoservers(active);

    if ((active = openlistener(httpsAddress, httpsPort)) == -1) 
    {
#ifdef CONFIG_HTTP_VERBOSE
        fprintf(stderr, "ERR: Couldn't bind to port %d\n", httpsPort);
#endif
        exit(1);
    }

    addtoservers(active);

    if (cert != NULL && private_key != NULL)
        options |=  SSL_NO_DEFAULT_KEY;

    servers->ssl_ctx = ssl_ctx_new(options, CONFIG_HTTP_SESSION_CACHE_SIZE);
    servers->is_ssl = 1;

    if (cert != NULL && private_key != NULL)
    {
        printf("YEAH\n");
        if (ssl_obj_load(servers->ssl_ctx, SSL_OBJ_RSA_KEY, private_key,
                    NULL))
        {
#ifdef CONFIG_HTTP_VERBOSE
            fprintf(stderr, "ERR: Couldn't load private key %s\n", private_key);
#endif
            exit(1);
        }

        if (ssl_obj_load(servers->ssl_ctx, SSL_OBJ_X509_CERT, cert,
                    NULL))
        {
#ifdef CONFIG_HTTP_VERBOSE
            fprintf(stderr, "ERR: Couldn't load cert %s\n", cert);
#endif
            exit(1);
        }
    }

#if defined(CONFIG_HTTP_HAS_CGI)
    addcgiext(CONFIG_HTTP_CGI_EXTENSIONS);
#endif

#if defined(CONFIG_HTTP_VERBOSE)
#if defined(CONFIG_HTTP_HAS_CGI)
    printf("addcgiext %s\n", CONFIG_HTTP_CGI_EXTENSIONS); 
#endif
    printf("%s: listening on ports %d (http) and %d (https)\n", 
            server_version, httpPort, httpsPort);
    TTY_FLUSH();
#endif

    ax_chdir();

#ifdef CONFIG_HTTP_ENABLE_DIFFERENT_USER
    {
        struct passwd *pd = getpwnam(CONFIG_HTTP_USER);

        if (pd != NULL)
        {
            int res = setuid(pd->pw_uid);
            res |= setgid(pd->pw_gid);

#if defined(CONFIG_HTTP_VERBOSE)
            if (res == 0)
            {
                printf("change to '%s' successful\n", CONFIG_HTTP_USER); 
                TTY_FLUSH();
            }
#endif
        }

    }
#endif

#ifndef WIN32 
#ifdef CONFIG_HTTP_IS_DAEMON
    if (fork() > 0)  /* parent will die */
        exit(0);

    setsid();
#endif
#endif

    /* main loop */
    while (1)
    {
        struct timeval tv = { 10, 0 };
        FD_ZERO(&rfds);
        FD_ZERO(&wfds);
        rnum = wnum = -1;
        sp = servers;

        while (sp != NULL)  /* read each server port */
        {
            FD_SET(sp->sd, &rfds);

            if (sp->sd > rnum) 
                rnum = sp->sd;
            sp = sp->next;
        }

        /* Add the established sockets */
        tp = usedconns;
        currtime = time(NULL);

        while (tp != NULL) 
        {
            if (currtime > tp->timeout)     /* timed out? Kill it. */
            {
                to = tp;
                tp = tp->next;
                removeconnection(to);
                continue;
            }

            if (tp->state == STATE_WANT_TO_READ_HEAD) 
            {
                FD_SET(tp->networkdesc, &rfds);
                if (tp->networkdesc > rnum) 
                    rnum = tp->networkdesc;
            }

            if (tp->state == STATE_WANT_TO_SEND_HEAD) 
            {
                FD_SET(tp->networkdesc, &wfds);
                if (tp->networkdesc > wnum) 
                    wnum = tp->networkdesc;
            }

            if (tp->state == STATE_WANT_TO_READ_FILE) 
            {
                FD_SET(tp->filedesc, &rfds);
                if (tp->filedesc > rnum) 
                    rnum = tp->filedesc;
            }

            if (tp->state == STATE_WANT_TO_SEND_FILE) 
            {
                FD_SET(tp->networkdesc, &wfds);
                if (tp->networkdesc > wnum) 
                    wnum = tp->networkdesc;
            }

#if defined(CONFIG_HTTP_DIRECTORIES)
            if (tp->state == STATE_DOING_DIR) 
            {
                FD_SET(tp->networkdesc, &wfds);
                if (tp->networkdesc > wnum) 
                    wnum = tp->networkdesc;
            }
#endif
            tp = tp->next;
        }

        active = select(wnum > rnum ? wnum+1 : rnum+1,
                rnum != -1 ? &rfds : NULL, 
                wnum != -1 ? &wfds : NULL,
                NULL, usedconns ? &tv : NULL);

        /* timeout? */
        if (active == 0)
            continue;

        /* New connection? */
        sp = servers;
        while (active > 0 && sp != NULL) 
        {
            if (FD_ISSET(sp->sd, &rfds)) 
            {
                handlenewconnection(sp->sd, sp->is_ssl);
                active--;
            }

            sp = sp->next;
        }

        /* Handle the established sockets */
        tp = usedconns;

        while (active > 0 && tp != NULL) 
        {
            to = tp;
            tp = tp->next;

            if (to->state == STATE_WANT_TO_READ_HEAD &&
                        FD_ISSET(to->networkdesc, &rfds)) 
            {
                active--;
#if defined(CONFIG_HTTP_HAS_CGI)
                if (to->post_state)
                    read_post_data(to);
                else
#endif
                    procreadhead(to);
            } 

            if (to->state == STATE_WANT_TO_SEND_HEAD &&
                        FD_ISSET(to->networkdesc, &wfds)) 
            {
                active--;
                procsendhead(to);
            } 

            if (to->state == STATE_WANT_TO_READ_FILE && 
                        FD_ISSET(to->filedesc, &rfds)) 
            {
                active--;
                procreadfile(to);
            } 

            if (to->state == STATE_WANT_TO_SEND_FILE && 
                        FD_ISSET(to->networkdesc, &wfds)) 
            {
                active--;
                procsendfile(to);
            }

#if defined(CONFIG_HTTP_DIRECTORIES)
            if (to->state == STATE_DOING_DIR &&
                        FD_ISSET(to->networkdesc, &wfds)) 
            {
                active--;
                procdodir(to);
            }
#endif
        }
    }

    return 0;
}
Exemple #10
0
/* Returns 1 if elems should continue being read, 0 otherwise */
static int procheadelem(struct connstruct *cn, char *buf)
{
    char *delim, *value;

    if ((delim = strchr(buf, ' ')) == NULL)
        return 0;

    *delim = 0;
    value = delim + 1;

    if (strcmp(buf, "GET") == 0 || strcmp(buf, "HEAD") == 0 ||
        strcmp(buf, "POST") == 0) {
        if (buf[0] == 'H')
            cn->reqtype = TYPE_HEAD;
        else if (buf[0] == 'P')
            cn->reqtype = TYPE_POST;

        if ((delim = strchr(value, ' ')) == NULL)       /* expect HTTP type */
            return 0;

        *delim++ = 0;
        urldecode(value);

        if (sanitizefile(value) == 0) {
            send_error(cn, 403);
            return 0;
        }

#if defined(CONFIG_HTTP_HAS_CGI)
        decode_path_info(cn, value);
#else
        my_strncpy(cn->filereq, value, MAXREQUESTLENGTH);
#endif
        cn->if_modified_since = -1;
        if (strcmp(delim, "HTTP/1.0") == 0) /* v1.0 HTTP? */
            cn->is_v1_0 = 1;
    } else if (strcasecmp(buf, "Host:") == 0) {
        if (sanitizehost(value) == 0) {
            removeconnection(cn);
            return 0;
        }

        my_strncpy(cn->server_name, value, MAXREQUESTLENGTH);
    } else if (strcasecmp(buf, "Connection:") == 0 && strcmp(value, "close") == 0) {
        cn->close_when_done = 1;
    } else if (strcasecmp(buf, "If-Modified-Since:") == 0) {
        cn->if_modified_since = tdate_parse(value);
    } else if (strcasecmp(buf, "Expect:") == 0) {
        /* supposed to be safe to ignore 100-continue */
        if (strcasecmp(value, "100-continue") != 0) {
            send_error(cn, 417); /* expectation failed */
            return 0;
        }
    }
#ifdef CONFIG_HTTP_HAS_AUTHORIZATION
    else if (strcasecmp(buf, "Authorization:") == 0 &&
             strncmp(value, "Basic ", 6) == 0) {
        int size = sizeof(cn->authorization);
        if (base64_decode(&value[6], strlen(&value[6]),
                          (uint8_t *)cn->authorization, &size))
            cn->authorization[0] = 0;   /* error */
        else
            cn->authorization[size] = 0;
    }
#endif
#if defined(CONFIG_HTTP_HAS_CGI)
    else if (strcasecmp(buf, "Content-Length:") == 0) {
        sscanf(value, "%d", &cn->content_length);
    } else if (strcasecmp(buf, "Content-Type:") == 0) {
        my_strncpy(cn->cgicontenttype, value, MAXREQUESTLENGTH);
    } else if (strcasecmp(buf, "Cookie:") == 0) {
        my_strncpy(cn->cookie, value, MAXREQUESTLENGTH);
    }
#endif

    return 1;
}
Exemple #11
0
static void proccgi(struct connstruct *cn)
{
    int tpipe[2], spipe[2];
    char *myargs[3];
    char cgienv[CGI_ARG_SIZE][MAXREQUESTLENGTH];
    char * cgiptr[CGI_ARG_SIZE + 4];
    const char *type = "HEAD";
    int cgi_index = 0, i;
    pid_t pid;

    snprintf(cgienv[0], MAXREQUESTLENGTH,
             HTTP_VERSION" 200 OK\nServer: %s\n%s",
             server_version, (cn->reqtype == TYPE_HEAD) ? "\n" : "");
    special_write(cn, cgienv[0], strlen(cgienv[0]));

    if (cn->reqtype == TYPE_HEAD) {
        removeconnection(cn);
        return;
    }

#ifdef CONFIG_HTTP_VERBOSE
    printf("[CGI]: %s:/%s\n", cn->is_ssl ? "https" : "http", cn->filereq);
    TTY_FLUSH();
#endif

    /* set up pipe that is used for sending POST query data to CGI script*/
    if (cn->reqtype == TYPE_POST) {
        if (pipe(spipe) == -1) {
            printf("[CGI]: could not create pipe");
            TTY_FLUSH();
            return;
        }
    }

    if (pipe(tpipe) == -1) {
        printf("[CGI]: could not create pipe");
        TTY_FLUSH();
        return;
    }

    /*
     * use vfork() instead of fork() for performance
     */
    if ((pid = vfork()) > 0) { /* parent */
        /* Send POST query data to CGI script */
        if ((cn->reqtype == TYPE_POST) && (cn->content_length > 0)) {
            if (write(spipe[1], cn->post_data, cn->content_length) == -1) {
                printf("[CGI]: could write to pipe");
                TTY_FLUSH();
                return;
            }

            close(spipe[0]);
            close(spipe[1]);

            /* free the memory that is allocated in read_post_data() */
            free(cn->post_data);
            cn->post_data = NULL;
        }

        /* Close the write descriptor */
        close(tpipe[1]);
        cn->filedesc = tpipe[0];
        cn->state = STATE_WANT_TO_READ_FILE;
        cn->close_when_done = 1;
        return;
    }

    if (pid < 0) /* vfork failed */
        exit(1);

    /* The problem child... */

    /* Our stdout/stderr goes to the socket */
    dup2(tpipe[1], 1);
    dup2(tpipe[1], 2);
    close(tpipe[0]);
    close(tpipe[1]);

    /* If it was a POST request, send the socket data to our stdin */
    if (cn->reqtype == TYPE_POST)  {
        dup2(spipe[0], 0);
        close(spipe[0]);
        close(spipe[1]);
    } else    /* Otherwise we can shutdown the read side of the sock */
        shutdown(cn->networkdesc, 0);

    myargs[0] = CONFIG_HTTP_CGI_LAUNCHER;
    myargs[1] = cn->actualfile;
    myargs[2] = NULL;

    /*
     * set the cgi args. A url is defined by:
     * http://$SERVER_NAME:$SERVER_PORT$SCRIPT_NAME$PATH_INFO?$QUERY_STRING
     * TODO: other CGI parameters?
     */
    sprintf(cgienv[cgi_index++], "SERVER_SOFTWARE=%s", server_version);
    strcpy(cgienv[cgi_index++], "DOCUMENT_ROOT=" CONFIG_HTTP_WEBROOT);
    snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
             "SERVER_NAME=%s", cn->server_name);
    sprintf(cgienv[cgi_index++], "SERVER_PORT=%d",
            cn->is_ssl ? CONFIG_HTTP_HTTPS_PORT : CONFIG_HTTP_PORT);
    snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
             "REQUEST_URI=%s", cn->uri_request);
    snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
             "SCRIPT_NAME=%s", cn->filereq);
    snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
             "PATH_INFO=%s", cn->uri_path_info);
    snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
             "QUERY_STRING=%s", cn->uri_query);
    snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
             "REMOTE_ADDR=%s", cn->remote_addr);
    snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
             "HTTP_COOKIE=%s", cn->cookie);  /* note: small size */
#if defined(CONFIG_HTTP_HAS_AUTHORIZATION)
    snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
             "REMOTE_USER=%s", cn->authorization);
#endif

    switch (cn->reqtype) {
    case TYPE_GET:
        type = "GET";
        break;

#if defined(CONFIG_HTTP_HAS_CGI)
    case TYPE_POST:
        type = "POST";
        sprintf(cgienv[cgi_index++],
                "CONTENT_LENGTH=%d", cn->content_length);
        snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH,
                 "CONTENT_TYPE=%s", cn->cgicontenttype);
        break;
#endif
    }

    sprintf(cgienv[cgi_index++], "REQUEST_METHOD=%s", type);

    if (cn->is_ssl)
        strcpy(cgienv[cgi_index++], "HTTPS=on");

    if (cgi_index >= CGI_ARG_SIZE) {
        printf("Content-type: text/plain\n\nToo many CGI args (%d, %d)\n",
               cgi_index, CGI_ARG_SIZE);
        _exit(1);
    }

    /* copy across the pointer indexes */
    for (i = 0; i < cgi_index; i++)
        cgiptr[i] = cgienv[i];

    cgiptr[i++] = "AUTH_TYPE=Basic";
    cgiptr[i++] = "GATEWAY_INTERFACE=CGI/1.1";
    cgiptr[i++] = "SERVER_PROTOCOL="HTTP_VERSION;
    cgiptr[i] = NULL;

    execve(myargs[0], myargs, cgiptr);
    printf("Content-type: text/plain\n\nshouldn't get here\n");
    _exit(1);
}
Exemple #12
0
/* In this function we assume that the file has been checked for
 * maliciousness (".."s, etc) and has been decoded
 */
void procsendhead(struct connstruct *cn)
{
    char buf[MAXREQUESTLENGTH];
    struct stat stbuf;
    time_t t_time;
    struct tm *ptm;
    char date[32];
    char last_modified[32];
    char expires[32];
    int file_exists;

    /* are we trying to access a file over the HTTP connection instead of a
     * HTTPS connection? Or is this directory disabled? */
    if (htaccess_check(cn)) {
        send_error(cn, 403);
        return;
    }

#ifdef CONFIG_HTTP_HAS_AUTHORIZATION
    if (auth_check(cn)) {   /* see if there is a '.htpasswd' file */
#ifdef CONFIG_HTTP_VERBOSE
        printf("axhttpd: access to %s denied\n", cn->filereq); TTY_FLUSH();
#endif
        removeconnection(cn);
        return;
    }
#endif

    file_exists = stat(cn->actualfile, &stbuf);

#if defined(CONFIG_HTTP_HAS_CGI)
    if (file_exists != -1 && cn->is_cgi) {
        proccgi(cn);
        return;
    }
#endif

    /* look for "index.html"? */
    if (isdir(cn->actualfile)) {
        char tbuf[MAXREQUESTLENGTH];
        snprintf(tbuf, MAXREQUESTLENGTH, "%s%s", cn->actualfile, index_file);

        if ((file_exists = stat(tbuf, &stbuf)) != -1)
            my_strncpy(cn->actualfile, tbuf, MAXREQUESTLENGTH);
        else {
#if defined(CONFIG_HTTP_DIRECTORIES)
            /* If not, we do a directory listing of it */
            procdirlisting(cn);
#else
            send_error(cn, 404);
#endif
            return;
        }
    }

    if (file_exists == -1) {
        send_error(cn, 404);
        return;
    }


    time(&t_time);
    ptm = gmtime(&t_time);
    strftime(date, sizeof(date), rfc1123_format, ptm);

    /* has the file been read before? */
    if (cn->if_modified_since != -1)

    {
        ptm = gmtime(&stbuf.st_mtime);
        t_time = mktime(ptm);

        if (cn->if_modified_since >= t_time) {
            snprintf(buf, sizeof(buf), HTTP_VERSION" 304 Not Modified\nServer: "
                     "%s\nDate: %s\n\n", server_version, date);
            special_write(cn, buf, strlen(buf));
            cn->state = STATE_WANT_TO_READ_HEAD;
            return;
        }
    }

    if (cn->reqtype == TYPE_HEAD) {
        removeconnection(cn);
        return;
    } else {
        int flags = O_RDONLY;
#if defined(CONFIG_PLATFORM_CYGWIN)
        flags |= O_BINARY;
#endif
        cn->filedesc = open(cn->actualfile, flags);

        if (cn->filedesc < 0) {
            send_error(cn, 404);
            return;
        }

        ptm = gmtime(&stbuf.st_mtime);
        strftime(last_modified, sizeof(last_modified), rfc1123_format, ptm);
        t_time += CONFIG_HTTP_TIMEOUT;
        ptm = gmtime(&t_time);
        strftime(expires, sizeof(expires), rfc1123_format, ptm);

        snprintf(buf, sizeof(buf), HTTP_VERSION" 200 OK\nServer: %s\n"
                 "Content-Type: %s\nContent-Length: %ld\n"
                 "Date: %s\nLast-Modified: %s\nExpires: %s\n\n", server_version,
                 getmimetype(cn->actualfile), (long) stbuf.st_size,
                 date, last_modified, expires);

        special_write(cn, buf, strlen(buf));

#ifdef CONFIG_HTTP_VERBOSE
        printf("axhttpd: %s:/%s\n", cn->is_ssl ? "https" : "http", cn->filereq);
        TTY_FLUSH();
#endif


        cn->state = STATE_WANT_TO_READ_FILE;
    }
}