diff options
Diffstat (limited to 'tests/server')
-rw-r--r-- | tests/server/.gitignore | 1 | ||||
-rw-r--r-- | tests/server/Makefile.inc | 7 | ||||
-rw-r--r-- | tests/server/fake_ntlm.c | 283 | ||||
-rw-r--r-- | tests/server/getpart.c | 8 | ||||
-rw-r--r-- | tests/server/sws.c | 91 |
5 files changed, 363 insertions, 27 deletions
diff --git a/tests/server/.gitignore b/tests/server/.gitignore index 9e9dd37a2..8007bec8b 100644 --- a/tests/server/.gitignore +++ b/tests/server/.gitignore @@ -4,3 +4,4 @@ rtspd sockfilt sws tftpd +fake_ntlm diff --git a/tests/server/Makefile.inc b/tests/server/Makefile.inc index be3f06808..6b0ee72f0 100644 --- a/tests/server/Makefile.inc +++ b/tests/server/Makefile.inc @@ -1,4 +1,4 @@ -noinst_PROGRAMS = getpart resolve rtspd sockfilt sws tftpd +noinst_PROGRAMS = getpart resolve rtspd sockfilt sws tftpd fake_ntlm CURLX_SRCS = \ $(top_srcdir)/lib/mprintf.c \ @@ -63,3 +63,8 @@ tftpd_SOURCES = $(CURLX_SRCS) $(CURLX_HDRS) $(USEFUL) $(UTIL) \ tftp.h tftpd_LDADD = @TEST_SERVER_LIBS@ tftpd_CFLAGS = $(AM_CFLAGS) + +fake_ntlm_SOURCES = $(CURLX_SRCS) $(CURLX_HDRS) $(USEFUL) $(UTIL) \ + fake_ntlm.c +fake_ntlm_LDADD = @TEST_SERVER_LIBS@ +fake_ntlm_CFLAGS = $(AM_CFLAGS) diff --git a/tests/server/fake_ntlm.c b/tests/server/fake_ntlm.c new file mode 100644 index 000000000..9bed5963d --- /dev/null +++ b/tests/server/fake_ntlm.c @@ -0,0 +1,283 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2010, Mandy Wu, <mandy.wu@intel.com> + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * This is a fake ntlm_auth, which is used for testing NTLM single-sign-on. + * When DEBUGBUILD is defined, libcurl invoke this tool instead of real winbind + * daemon helper /usr/bin/ntlm_auth. This tool will accept commands and + * responses with a pre-written string saved in test case test2005. + */ + +#define CURL_NO_OLDIES + +#include "setup.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#define ENABLE_CURLX_PRINTF +#include "curlx.h" /* from the private lib dir */ +#include "getpart.h" +#include "util.h" + +/* include memdebug.h last */ +#include "memdebug.h" + +#ifndef DEFAULT_LOGFILE +#define DEFAULT_LOGFILE "log/fake_ntlm.log" +#endif + +const char *serverlogfile = DEFAULT_LOGFILE; + +/* + * Returns an allocated buffer with printable representation of input + * buffer contents or returns NULL on out of memory condition. + */ +static char *printable(char *inbuf, size_t inlength) +{ + char *outbuf; + char *newbuf; + size_t newsize; + size_t outsize; + size_t outincr = 0; + size_t i, o = 0; + +#define HEX_FMT_STR "[0x%02X]" +#define HEX_STR_LEN 6 +#define NOTHING_STR "[NOTHING]" +#define NOTHING_LEN 9 + + if(!inlength) + inlength = strlen(inbuf); + + if(inlength) { + outincr = ((inlength/2) < (HEX_STR_LEN+1)) ? HEX_STR_LEN+1 : inlength/2; + outsize = inlength + outincr; + } + else + outsize = NOTHING_LEN + 1; + + outbuf = malloc(outsize); + if(!outbuf) + return NULL; + + if(!inlength) { + sprintf(&outbuf[0], "%s", NOTHING_STR); + return outbuf; + } + + for(i=0; i<inlength; i++) { + + if(o > outsize - (HEX_STR_LEN + 1)) { + newsize = outsize + outincr; + newbuf = realloc(outbuf, newsize); + if(!newbuf) { + free(outbuf); + return NULL; + } + outbuf = newbuf; + outsize = newsize; + } + + if((inbuf[i] > 0x20) && (inbuf[i] < 0x7F)) { + outbuf[o] = inbuf[i]; + o++; + } + else { + sprintf(&outbuf[o], HEX_FMT_STR, inbuf[i]); + o += HEX_STR_LEN; + } + + } + outbuf[o] = '\0'; + + return outbuf; +} + +int main(int argc, char *argv[]) +{ + char buf[1024]; + FILE *stream; + char *filename; + int error; + char *type1_input = NULL, *type3_input = NULL; + char *type1_output = NULL, *type3_output = NULL; + size_t size = 0; + long testnum; + const char *env; + int arg = 1; + char *helper_user = (char *)"unknown"; + char *helper_proto = (char *)"unknown"; + char *helper_domain = (char *)"unknown"; + bool use_cached_creds = FALSE; + char *msgbuf; + + buf[0] = '\0'; + + while(argc > arg) { + if(!strcmp("--use-cached-creds", argv[arg])) { + use_cached_creds = TRUE; + arg++; + } + else if(!strcmp("--helper-protocol", argv[arg])) { + arg++; + if(argc > arg) + helper_proto = argv[arg++]; + } + else if(!strcmp("--username", argv[arg])) { + arg++; + if(argc > arg) + helper_user = argv[arg++]; + } + else if(!strcmp("--domain", argv[arg])) { + arg++; + if(argc > arg) + helper_domain = argv[arg++]; + } + else { + puts("Usage: fake_ntlm [option]\n" + " --use-cached-creds\n" + " --helper-protocol [protocol]\n" + " --username [username]\n" + " --domain [domain]"); + exit(1); + } + } + + logmsg("fake_ntlm (user: %s) (proto: %s) (domain: %s) (cached creds: %s)", + helper_user, helper_proto, helper_domain, + (use_cached_creds) ? "yes" : "no"); + + env = getenv("CURL_NTLM_AUTH_TESTNUM"); + if (env) { + char *endptr; + long lnum = strtol(env, &endptr, 10); + if((endptr != env + strlen(env)) || (lnum < 1L)) { + logmsg("Test number not valid in CURL_NTLM_AUTH_TESTNUM"); + exit(1); + } + testnum = lnum; + } else { + logmsg("Test number not specified in CURL_NTLM_AUTH_TESTNUM"); + exit(1); + } + + env = getenv("CURL_NTLM_AUTH_SRCDIR"); + if (env) { + path = env; + } + + filename = test2file(testnum); + stream=fopen(filename, "rb"); + if(!stream) { + error = ERRNO; + logmsg("fopen() failed with error: %d %s", error, strerror(error)); + logmsg("Error opening file: %s", filename); + logmsg("Couldn't open test file %ld", testnum); + exit(1); + } + else { + /* get the ntlm_auth input/output */ + error = getpart(&type1_input, &size, "ntlm_auth_type1", "input", stream); + fclose(stream); + if(error || size == 0) { + logmsg("getpart() type 1 input failed with error: %d", error); + exit(1); + } + } + + stream=fopen(filename, "rb"); + if(!stream) { + error = ERRNO; + logmsg("fopen() failed with error: %d %s", error, strerror(error)); + logmsg("Error opening file: %s", filename); + logmsg("Couldn't open test file %ld", testnum); + exit(1); + } + else { + size = 0; + error = getpart(&type3_input, &size, "ntlm_auth_type3", "input", stream); + fclose(stream); + if(error || size == 0) { + logmsg("getpart() type 3 input failed with error: %d", error); + exit(1); + } + } + + while(fgets(buf, sizeof(buf), stdin)) { + if(strcmp(buf, type1_input) == 0) { + stream=fopen(filename, "rb"); + if(!stream) { + error = ERRNO; + logmsg("fopen() failed with error: %d %s", error, strerror(error)); + logmsg("Error opening file: %s", filename); + logmsg("Couldn't open test file %ld", testnum); + exit(1); + } + else { + size = 0; + error = getpart(&type1_output, &size, "ntlm_auth_type1", "output", stream); + fclose(stream); + if(error || size == 0) { + logmsg("getpart() type 1 output failed with error: %d", error); + exit(1); + } + } + printf("%s", type1_output); + fflush(stdout); + } + else if(strncmp(buf, type3_input, strlen(type3_input)) == 0) { + stream=fopen(filename, "rb"); + if(!stream) { + error = ERRNO; + logmsg("fopen() failed with error: %d %s", error, strerror(error)); + logmsg("Error opening file: %s", filename); + logmsg("Couldn't open test file %ld", testnum); + exit(1); + } + else { + size = 0; + error = getpart(&type3_output, &size, "ntlm_auth_type3", "output", stream); + fclose(stream); + if(error || size == 0) { + logmsg("getpart() type 3 output failed with error: %d", error); + exit(1); + } + } + printf("%s", type3_output); + fflush(stdout); + } + else { + printf("Unknown request\n"); + msgbuf = printable(buf, 0); + if(msgbuf) { + logmsg("invalid input: '%s'\n", msgbuf); + free(msgbuf); + } + else + logmsg("OOM formatting invalid input: '%s'\n", buf); + exit(1); + } + } + return 1; +} diff --git a/tests/server/getpart.c b/tests/server/getpart.c index 743cb21b9..9384d0cb0 100644 --- a/tests/server/getpart.c +++ b/tests/server/getpart.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -49,7 +49,7 @@ struct SessionHandle { #ifdef DEBUG_GETPART #define show(x) printf x #else -#define show(x) +#define show(x) Curl_nop_stmt #endif #if defined(_MSC_VER) && defined(_DLL) @@ -166,7 +166,9 @@ static int appenddata(char **dst_buf, /* dest buffer */ if(src_b64) { /* base64 decode the given buffer */ - src_len = Curl_base64_decode(src_buf, &buf64.as_uchar); + int error = (int) Curl_base64_decode(src_buf, &buf64.as_uchar, &src_len); + if(error) + return GPE_OUT_OF_MEMORY; src_buf = buf64.as_char; if(!src_len || !src_buf) { /* diff --git a/tests/server/sws.c b/tests/server/sws.c index 949831d6c..b2d6df7a6 100644 --- a/tests/server/sws.c +++ b/tests/server/sws.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -107,7 +107,7 @@ struct httprequest { bool digest; /* Authorization digest header found */ bool ntlm; /* Authorization ntlm header found */ int writedelay; /* if non-zero, delay this number of seconds between - writes in the response */ + writes in the response */ int pipe; /* if non-zero, expect this many requests to do a "piped" request/response */ int skip; /* if non-zero, the server is instructed to not read this @@ -117,6 +117,7 @@ struct httprequest { int rcmd; /* doing a special command, see defines above */ int prot_version; /* HTTP version * 10 */ bool pipelining; /* true if request is pipelined */ + int callcount; /* times ProcessRequest() gets called */ }; static int ProcessRequest(struct httprequest *req); @@ -308,13 +309,16 @@ static int ProcessRequest(struct httprequest *req) bool chunked = FALSE; static char request[REQUEST_KEYWORD_SIZE]; static char doc[MAXDOCNAMELEN]; - char logbuf[256]; + char logbuf[456]; int prot_major, prot_minor; char *end; int error; end = strstr(line, end_of_headers); - logmsg("ProcessRequest() called"); + req->callcount++; + + logmsg("Process %d bytes request%s", req->offset, + req->callcount > 1?" [CONTINUED]":""); /* try to figure out the request characteristics as soon as possible, but only once! */ @@ -346,7 +350,7 @@ static int ProcessRequest(struct httprequest *req) FILE *stream; char *filename; - if((strlen(doc) + strlen(request)) < 200) + if((strlen(doc) + strlen(request)) < 400) sprintf(logbuf, "Got request: %s %s HTTP/%d.%d", request, doc, prot_major, prot_minor); else @@ -397,12 +401,13 @@ static int ProcessRequest(struct httprequest *req) return 1; /* done */ } else { + char *orgcmd = NULL; char *cmd = NULL; size_t cmdsize = 0; int num=0; /* get the custom server control "commands" */ - error = getpart(&cmd, &cmdsize, "reply", "servercmd", stream); + error = getpart(&orgcmd, &cmdsize, "reply", "servercmd", stream); fclose(stream); if(error) { logmsg("getpart() failed with error: %d", error); @@ -410,8 +415,9 @@ static int ProcessRequest(struct httprequest *req) return 1; /* done */ } - if(cmdsize) { - logmsg("Found a reply-servercmd section!"); + cmd = orgcmd; + while(cmd && cmdsize) { + char *check; if(!strncmp(CMD_AUTH_REQUIRED, cmd, strlen(CMD_AUTH_REQUIRED))) { logmsg("instructed to require authorization header"); @@ -445,9 +451,26 @@ static int ProcessRequest(struct httprequest *req) else { logmsg("funny instruction found: %s", cmd); } + /* try to deal with CRLF or just LF */ + check = strchr(cmd, '\r'); + if(!check) + check = strchr(cmd, '\n'); + + if(check) { + /* get to the letter following the newline */ + while((*check == '\r') || (*check == '\n')) + check++; + + if(!*check) + /* if we reached a zero, get out */ + break; + cmd = check; + } + else + break; } - if(cmd) - free(cmd); + if(orgcmd) + free(orgcmd); } } else { @@ -481,13 +504,17 @@ static int ProcessRequest(struct httprequest *req) } } } + else if((req->offset >= 3) && (req->testno == DOCNUMBER_NOTHING)) { + logmsg("** Unusual request. Starts with %02x %02x %02x", + line[0], line[1], line[2]); + } if(!end) { /* we don't have a complete request yet! */ - logmsg("ProcessRequest returned without a complete request"); + logmsg("request not complete yet"); return 0; /* not complete yet */ } - logmsg("ProcessRequest found a complete request"); + logmsg("- request found to be complete"); if(use_gopher) { /* when using gopher we cannot check the request until the entire @@ -616,10 +643,11 @@ static int ProcessRequest(struct httprequest *req) req->ntlm = TRUE; /* NTLM found */ logmsg("Received NTLM type-1, sending back data %ld", req->partno); } - else if((req->partno >= 1000) && strstr(req->reqbuf, "Authorization: Basic")) { - /* If the client is passing this Basic-header and the part number is already - >=1000, we add 1 to the part number. This allows simple Basic authentication - negotiation to work in the test suite. */ + else if((req->partno >= 1000) && + strstr(req->reqbuf, "Authorization: Basic")) { + /* If the client is passing this Basic-header and the part number is + already >=1000, we add 1 to the part number. This allows simple Basic + authentication negotiation to work in the test suite. */ req->partno += 1; logmsg("Received Basic request, sending back data %ld", req->partno); } @@ -631,6 +659,7 @@ static int ProcessRequest(struct httprequest *req) req->prot_version >= 11 && end && req->reqbuf + req->offset > end + strlen(end_of_headers) && + !req->cl && (!strncmp(req->reqbuf, "GET", strlen("GET")) || !strncmp(req->reqbuf, "HEAD", strlen("HEAD")))) { /* If we have a persistent connection, HTTP version >= 1.1 @@ -655,8 +684,10 @@ static int ProcessRequest(struct httprequest *req) makes the server NOT wait for PUT/POST data and you can then make the test case send a rejection before any such data has been sent. Test case 154 uses this.*/ - if(req->auth_req && !req->auth) + if(req->auth_req && !req->auth) { + logmsg("Return early due to auth requested by none provided"); return 1; /* done */ + } if(req->cl > 0) { if(req->cl <= req->offset - (end - req->reqbuf) - strlen(end_of_headers)) @@ -756,6 +787,7 @@ static int get_request(curl_socket_t sock, struct httprequest *req) req->rcmd = RCMD_NORMALREQ; req->prot_version = 0; req->pipelining = FALSE; + req->callcount = 0; /*** end of httprequest init ***/ @@ -767,9 +799,9 @@ static int get_request(curl_socket_t sock, struct httprequest *req) } else { if(req->skip) - /* we are instructed to not read the entire thing, so we make sure to only - read what we're supposed to and NOT read the enire thing the client - wants to send! */ + /* we are instructed to not read the entire thing, so we make sure to + only read what we're supposed to and NOT read the enire thing the + client wants to send! */ got = sread(sock, reqbuf + req->offset, req->cl); else got = sread(sock, reqbuf + req->offset, REQBUFSIZ-1 - req->offset); @@ -851,7 +883,7 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) char partbuf[80]="data"; - logmsg("Send response number %ld part %ld", req->testno, req->partno); + logmsg("Send response test%ld section <data%ld>", req->testno, req->partno); switch(req->rcmd) { default: @@ -1394,8 +1426,13 @@ int main(int argc, char *argv[]) break; } - if(req.open) - logmsg("=> persistant connection request ended, awaits new request"); + if(req.open) { + logmsg("=> persistant connection request ended, awaits new request\n"); + /* + const char *keepopen="[KEEPING CONNECTION OPEN]"; + storerequest((char *)keepopen, strlen(keepopen)); + */ + } /* if we got a CONNECT, loop and get another request as well! */ } while(req.open || (req.testno == DOCNUMBER_CONNECT)); @@ -1403,6 +1440,14 @@ int main(int argc, char *argv[]) break; logmsg("====> Client disconnect"); + + if(!req.open) + /* When instructed to close connection after server-reply we + wait a very small amount of time before doing so. If this + is not done client might get an ECONNRESET before reading + a single byte of server-reply. */ + wait_ms(50); + sclose(msgsock); msgsock = CURL_SOCKET_BAD; |