diff --git a/client.c b/client.c index 52e6f91..76f821b 100644 --- a/client.c +++ b/client.c @@ -2,8 +2,9 @@ * Copyright (c) David Leadbeater 2002-2006 * Released Under the GNU GPLv2 or Later * NO WARRANTY - See GNU GPL for more - * $Id: client.c,v 1.13 2006/04/30 20:24:41 dgl Exp $ + * $Id: client.c,v 1.14 2006/05/03 06:51:16 dgl Exp $ */ +/* To compile: cc -O2 -o client.cgi client.c */ #include #include @@ -18,149 +19,203 @@ /* Change this to the tmpfile path set in the CGI:IRC Config */ #define TMPLOCATION "/tmp/cgiirc-" -int unix_connect(char *where); +/****************************************************************************** + * Stralloc (from libowfat(-ish)) + * If you'd rather use dietlibc/libowfat: + * diet -Os gcc -include stralloc.h -o client.cgi client.c -lowfat */ + +#ifndef STRALLOC_H +typedef struct stralloc { + char* s; + unsigned long int len; + unsigned long int a; +} stralloc; + +int stralloc_ready(stralloc *sa,unsigned long int len) { + register int wanted=len+(len>>3)+30; /* heuristic from djb */ + if(!sa->s || sa->as,wanted))) + return 0; + sa->a=wanted; + sa->s=tmp; + } + return 1; +} + +int stralloc_readyplus(stralloc *sa,unsigned long len) { + if (sa->s) { + if (sa->len + len < len) return 0; /* catch integer overflow */ + return stralloc_ready(sa,sa->len+len); + } else + return stralloc_ready(sa,len); +} + +int stralloc_catb(stralloc *sa,const char *buf,unsigned long int len) { + if (stralloc_readyplus(sa,len)) { + memcpy(sa->s+sa->len,buf,len); + sa->len+=len; + return 1; + } + return 0; +} + +int stralloc_cats(stralloc *sa,const char *buf) { + return stralloc_catb(sa,buf,strlen(buf)); +} + +int stralloc_cat(stralloc *sa,stralloc *sa2) { + return stralloc_catb(sa,sa2->s,sa2->len); +} + +int stralloc_append(stralloc *sa,const char *in) { + if (stralloc_readyplus(sa,1)) { + sa->s[sa->len]=*in; + ++sa->len; + return 1; + } + return 0; +} + +#define stralloc_0(sa) stralloc_append(sa,"") + +#endif +/******************************************************************************/ + +int unix_connect(stralloc *where); int error(char *error); -int readinput(char *params, size_t len); -int get_rand(char *params, char *rand, size_t len); -int get_cookie(char *cookie); +void readinput(stralloc *); +void get_rand(stralloc *, stralloc *); +void get_cookie(stralloc *); int main(void) { - int fd; - char params[2048]; /* Keep input in here */ - char rand[50]; /* Random value - used for the socket location */ - char tmp[2148]; - char cookie[100]; - - if(!readinput(params, sizeof params)) error("No input found\n"); - if(!get_rand(params, rand, sizeof rand)) error("Random Value not found\n"); - - if(get_cookie(cookie)) { - char tmp2[2148]; /* I'm sure there's a better way of doing this.. */ - strncpy(tmp2, params, sizeof tmp2); - snprintf(params, sizeof params, "COOKIE=%s&%s", cookie, tmp2); + int fd, sz; + char tmp[2048]; + stralloc params = {0}, random = {0}, cookie = {0}; + + readinput(¶ms); + + if(!params.len) + error("No input found"); + + stralloc_0(¶ms); + + get_rand(¶ms, &random); + + if(!random.len) + error("Random value not found"); + + params.len--; + + get_cookie(&cookie); + + if(cookie.len) { + stralloc_cats(¶ms, "&COOKIE="); + stralloc_cat(¶ms, &cookie); } - fd = unix_connect(rand); - send(fd, params, strlen(params), 0); + fd = unix_connect(&random); + send(fd, params.s, params.len, 0); send(fd, "\n", 1, 0); - while(read(fd, tmp, sizeof tmp) > 0) { - printf("%s",tmp); + while((sz = read(fd, tmp, sizeof tmp)) > 0) { + write(STDOUT_FILENO, tmp, sz); } - return 1; + return 0; } int error(char *error) { - printf("Content-type: text/html\n\n"); - printf("An error occurred: %s\n",error); + puts("Content-type: text/html\n"); + puts("An error occurred:"); + puts(error); exit(1); } -int readinput(char *params, size_t len) { - char request[10]; - - if(!getenv("REQUEST_METHOD")) return 0; - strncpy(request, getenv("REQUEST_METHOD"), 9); - request[9] = 0; - if(!strlen(request)) return 0; +void readinput(stralloc *input) { + char *method = getenv("REQUEST_METHOD"); + if(!method) return; - if(strncmp(request, "GET", 3) == 0) { - strncpy(params, getenv("QUERY_STRING"), 2048); - params[len - 1] = 0; - if(!strlen(params)) return 0; - return 1; - }else if(strncmp(request, "POST", 4) == 0) { + if(strcmp(method, "GET") == 0) { + char *query = getenv("QUERY_STRING"); + if(query) + stralloc_cats(input, query); + }else if(strcmp(method, "POST") == 0) { int length; - if(!getenv("CONTENT_LENGTH")) return 0; - length = atoi(getenv("CONTENT_LENGTH")); - if(!length || length == 0) return 0; - length = (length >= len ? len - 1 : length); - fread(params, length, 1, stdin); - params[length] = 0; - return 1; - }else{ - return 0; + char *ctlength = getenv("CONTENT_LENGTH"); + if(!ctlength) return; + length = atoi(ctlength); + + // Hopefully noone will need to send more than 5KB + if(length <= 0 || length > (1024*5)) return; + stralloc_ready(input, length); + size_t sz = read(STDIN_FILENO, input->s, length); + if(sz <= 0) return; + input->len = sz; } } -int get_rand(char *params, char *rand, size_t len) { - char *ptr, *end_ptr; - int r = 0, i = 0; - ptr = params; - end_ptr = ptr + strlen(ptr); - - for(;ptr < end_ptr; ptr++) { - if(r == 1) { - if(*ptr == '&') break; - if(i > len - 2) break; - if(isalpha(*ptr) || isdigit(*ptr)) { - rand[i] = *ptr; - i++; - } - }else if(*ptr == 'R' && *(++ptr) == '=') { - r = 1; - } - } - rand[i] = 0; +void get_rand(stralloc *params, stralloc *random) { + char *ptr = strstr(params->s, "R="); - if(r == 1 && strlen(rand)) return 1; - return 0; + if(!ptr) + return; + + ptr += 2; + + while(ptr < params->s + params->len) { + if(!isalpha(*ptr) && !isdigit(*ptr)) + break; + stralloc_append(random, ptr++); + } } -int get_cookie(char *cookie) { - char ctmp[1024]; +void get_cookie(stralloc *cookie) { + char *httpcookie; char *sptr, *end_ptr; - int i; - - if(!getenv("HTTP_COOKIE")) return 0; - strncpy(ctmp, getenv("HTTP_COOKIE"), sizeof ctmp - 1); - - sptr = strstr(ctmp, "cgiircauth="); - if(sptr == NULL) return 0; - if(strlen(sptr) < 12) return 0; - sptr += 11; - end_ptr = sptr + (strlen(sptr) < 99 ? strlen(sptr) : 99); - - i = 0; - while(sptr < end_ptr && *sptr != ';') { - cookie[i] = *sptr; - sptr++; - i++; - } - cookie[i] = '\0'; - return 1; + + httpcookie = getenv("HTTP_COOKIE"); + if(!httpcookie) return; + +#define COOKIE_NAME "cgiircauth=" + sptr = strstr(httpcookie, COOKIE_NAME); + if(sptr == NULL) return; + sptr += strlen(COOKIE_NAME); + if(!*sptr) return; + + end_ptr = strchr(sptr, ';'); + if(end_ptr == NULL) + end_ptr = sptr + strlen(sptr) - 1; + + stralloc_catb(cookie, sptr, 1 + end_ptr - sptr); } -int unix_connect(char *where) { - /*size_t size;*/ +#ifndef SUN_LEN +#define SUN_LEN(x) (sizeof(*(x)) - sizeof((x)->sun_path) + strlen((x)->sun_path)) +#endif + +int unix_connect(stralloc *where) { + stralloc filename = {0}, errmsg = {0}; struct sockaddr_un saddr; - int sock, len; - char filename[100], errmsg[100]; + int sock; - len = strlen(TMPLOCATION) + strlen(where) + 6; - if(len > 100) error("Too long"); - snprintf(filename, len, "%s%s/sock", TMPLOCATION, where); - filename[len] = 0; + stralloc_cats(&filename, TMPLOCATION); + stralloc_cat(&filename, where); + stralloc_cats(&filename, "/sock"); + stralloc_0(&filename); sock = socket(AF_UNIX, SOCK_STREAM, 0); - if(sock == -1) error("socket() error\n"); + if(sock == -1) error("socket() error"); saddr.sun_family = AF_UNIX; - strcpy(saddr.sun_path, filename); + strncpy(saddr.sun_path, filename.s, sizeof(saddr.sun_path)); + saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0'; if(connect(sock, (struct sockaddr *)&saddr, SUN_LEN(&saddr)) == -1) { - switch(errno) { - case EACCES: - error("Access Denied in connect()\n"); - case ECONNREFUSED: - error("Connection refused in connect()\n"); - case ENOENT: - error("No such file in connect()\n"); - default: - snprintf(errmsg, 99, "Unhandled error in connect(): %s\n", strerror(errno)); - error(errmsg); - } + stralloc_cats(&errmsg, "connect(): "); + stralloc_cats(&errmsg, strerror(errno)); + stralloc_0(&errmsg); + error(errmsg.s); } return sock;