/** * XML Security Library example: simple XKMS server * * Starts XKMS server on specified port. * * Usage: * ./xkms-server [--port ] [--format plain|soap-1.1|soap-1.2] * * Example: * ./xkms-server --port 8080 --format soap-1.1 keys.xml * * This is free software; see Copyright file in the source * distribution for preciese wording. * * Copyright (C) 2002-2003 Aleksey Sanin */ #include #include #include #include #include #ifdef XMLSEC_NO_XKMS int main(int argc, char** argv) { fprintf(stderr, "ERROR: XKMS is disabled.\n"); return 1; } #else /* XMLSEC_NO_XKMS */ #include #include #include #ifndef XMLSEC_NO_XSLT #include #include #endif /* XMLSEC_NO_XSLT */ #include #include #include #include #include #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING #include #endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ #ifdef UNIX_SOCKETS #include #include #include #include #include #include #include #else /* UNIX_SOCKETS */ #ifdef WIN32_SOCKETS #include #include #else /* WIN32_SOCKETS */ #error "Your operating system is not supported" #endif /* WIN32_SOCKETS */ #endif /* UNIX_SOCKETS */ #define DEFAULT_PORT 1234 #define PENDING_QUEUE_SIZE 100 #define LOG_LEVEL_SILENT 0 #define LOG_LEVEL_INFO 1 #define LOG_LEVEL_DATA 2 #define LOG_LEVEL_DEBUG 3 #ifdef UNIX_SOCKETS static int sockfd = -1; #endif /* UNIX_SOCKETS */ #ifdef WIN32_SOCKETS static SOCKET sockfd = -1; #endif /* WIN32_SOCKETS */ static int finished = 0; static int log_level = LOG_LEVEL_INFO; static int init_server(unsigned short port); static void stop_server(); static void int_signal_handler(int sig_num); static const xmlChar* my_strnstr(const xmlChar* str, xmlSecSize strLen, const xmlChar* tmpl, xmlSecSize tmplLen); static int handle_connection(int fd, xmlSecXkmsServerCtxPtr xkmsCtx, xmlSecXkmsServerFormat format); static int read_request(int fd, const char* in_ip, xmlSecBufferPtr buffer); static int send_response(int fd, const char* in_ip, int resp_code, const char* body, int body_size); static char usage[] = "[--port ] [--format plain|soap-1.1|soap-1.2] "; static char http_header[] = "HTTP/1.0 %d\n" "Server: XML Security Library: Simple XKMS Server/1.0\n" "Content-length: %d\n" "\n"; static char http_503[] = "Error 503 - Service Unavailable\n"; int main(int argc, char** argv) { int argpos; unsigned short port = DEFAULT_PORT; #ifndef XMLSEC_NO_XSLT xsltSecurityPrefsPtr xsltSecPrefs = NULL; #endif /* XMLSEC_NO_XSLT */ xmlSecKeysMngrPtr mngr = NULL; xmlSecXkmsServerCtxPtr xkmsCtx = NULL; xmlSecXkmsServerFormat format = xmlSecXkmsServerFormatPlain; int ret; fprintf(stdout, "Log: server is starting up\n"); /* Init libxml and libxslt libraries */ xmlInitParser(); LIBXML_TEST_VERSION xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; xmlSubstituteEntitiesDefault(1); #ifndef XMLSEC_NO_XSLT xmlIndentTreeOutput = 1; #endif /* XMLSEC_NO_XSLT */ /* Init libxslt */ #ifndef XMLSEC_NO_XSLT /* disable everything */ xsltSecPrefs = xsltNewSecurityPrefs(); xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid); xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid); xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid); xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid); xsltSetSecurityPrefs(xsltSecPrefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid); xsltSetDefaultSecurityPrefs(xsltSecPrefs); #endif /* XMLSEC_NO_XSLT */ /* Init xmlsec library */ if(xmlSecInit() < 0) { fprintf(stderr, "Error %d: xmlsec initialization failed.\n", errno); return(-1); } /* Check loaded library version */ if(xmlSecCheckVersion() != 1) { fprintf(stderr, "Error %d: loaded xmlsec library version is not compatible.\n", errno); return(-1); } /* Load default crypto engine if we are supporting dynamic * loading for xmlsec-crypto libraries. Use the crypto library * name ("openssl", "nss", etc.) to load corresponding * xmlsec-crypto library. */ #ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { fprintf(stderr, "Error %d: unable to load default xmlsec-crypto library. Make sure\n" "that you have it installed and check shared libraries path\n" "(LD_LIBRARY_PATH) envornment variable.\n", errno); return(-1); } #endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ /* Init crypto library */ if(xmlSecCryptoAppInit(NULL) < 0) { fprintf(stderr, "Error %d: crypto initialization failed.\n", errno); return(-1); } /* Init xmlsec-crypto library */ if(xmlSecCryptoInit() < 0) { fprintf(stderr, "Error %d: xmlsec-crypto initialization failed.\n", errno); return(-1); } /* Create and initialize keys manager */ mngr = xmlSecKeysMngrCreate(); if(mngr == NULL) { fprintf(stderr, "Error %d: failed to create keys manager.\n", errno); goto done; } if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) { fprintf(stderr, "Error %d: failed to initialize keys manager.\n", errno); goto done; } /* Create XKMS server context */ xkmsCtx = xmlSecXkmsServerCtxCreate(mngr); if(xkmsCtx == NULL) { fprintf(stderr, "Error %d: XKMS server context initialization failed\n", errno); goto done; } /* Process input parameters */ for(argpos = 1; (argpos < argc) && (argv[argpos][0] == '-'); argpos++) { if((strcmp(argv[argpos], "--port") == 0) || (strcmp(argv[argpos], "-p") == 0)) { argpos++; port = atoi(argv[argpos]); if(port == 0) { fprintf(stderr, "Error %d: invalid port number \"%s\".\nUsage: %s %s\n", errno, argv[argpos], argv[0], usage); goto done; } } else if((strcmp(argv[argpos], "--format") == 0) || (strcmp(argv[argpos], "-f") == 0)) { argpos++; format = xmlSecXkmsServerFormatFromString(BAD_CAST argv[argpos]); if(format == xmlSecXkmsServerFormatUnknown) { fprintf(stderr, "Error %d: invalid format \"%s\".\nUsage: %s %s\n", errno, argv[argpos], argv[0], usage); goto done; } } else if((strcmp(argv[argpos], "--log-level") == 0) || (strcmp(argv[argpos], "-l") == 0)) { argpos++; log_level = atoi(argv[argpos]); } else { fprintf(stderr, "Error %d: unknown parameter \"%s\".\nUsage: %s %s\n", errno, argv[argpos], argv[0], usage); goto done; } } if(argpos >= argc) { fprintf(stderr, "Error %d: keys file is not specified.\nUsage: %s %s\n", errno, argv[0], usage); goto done; } /* Load keys */ for(; argpos < argc; argpos++) { if(xmlSecCryptoAppDefaultKeysMngrLoad(mngr, argv[argpos]) < 0) { fprintf(stderr, "Error %d: failed to load xml keys file \"%s\".\nUsage: %s %s\n", errno, argv[argpos], argv[0], usage); goto done; } if(log_level >= LOG_LEVEL_INFO) { fprintf(stdout, "Log: loaded keys from \"%s\"\n", argv[argpos]); } } /* Startup TCP server */ if(init_server(port) < 0) { fprintf(stderr, "Error, errno: server initialization failed\n", errno); goto done; } assert(sockfd != -1); /* main loop: accept connections and process requests */ while(finished == 0) { fd_set fds; struct timeval timeout; /* Set up polling using select() */ FD_ZERO(&fds); FD_SET(sockfd, &fds); memset(&timeout, 0, sizeof(timeout)); timeout.tv_sec = 1; ret = select(sockfd + 1, &fds, NULL, NULL, &timeout); if((ret <= 0) || !FD_ISSET(sockfd, &fds)) { /* error, timed out or not our socket: try again */ continue; } if(handle_connection(sockfd, xkmsCtx, format) < 0) { fprintf(stderr, "Error %d: unable to accept incomming connection\n"); goto done; } } done: if(log_level >= LOG_LEVEL_INFO) { fprintf(stdout, "Log: server is shutting down\n"); } /* Shutdown TCP server */ stop_server(); /* Destroy xkms server context */ if(xkmsCtx != NULL) { xmlSecXkmsServerCtxDestroy(xkmsCtx); xkmsCtx = NULL; } /* Destroy keys manager */ if(mngr != NULL) { xmlSecKeysMngrDestroy(mngr); mngr = NULL; } /* Shutdown xmlsec-crypto library */ xmlSecCryptoShutdown(); /* Shutdown crypto library */ xmlSecCryptoAppShutdown(); /* Shutdown xmlsec library */ xmlSecShutdown(); /* Shutdown libxslt/libxml */ #ifndef XMLSEC_NO_XSLT xsltFreeSecurityPrefs(xsltSecPrefs); xsltCleanupGlobals(); #endif /* XMLSEC_NO_XSLT */ xmlCleanupParser(); fprintf(stdout, "Log: server is down, bye!\n"); return(0); } /** * init_server: * @port: the server'xmlSecBufferGetData(buffer) TCP port number. * * Starts up a TCP server listening on given @port. * * Returns 0 on success or a negative value if an error occurs. */ static int init_server(unsigned short port) { #ifdef WIN32_SOCKETS WSADATA data; #endif /* WIN32_SOCKETS */ struct sockaddr_in saddr; int flags; #ifdef WIN32_SOCKETS if(WSAStartup(MAKEWORD(1,1), &data)) { fprintf(stderr, "Error %d: WSAStartup() failed\n", errno); return(-1); } #endif /* WIN32_SOCKETS */ /* create socket */ sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); #ifdef UNIX_SOCKETS if(sockfd == -1) { #endif /* UNIX_SOCKETS */ #ifdef WIN32_SOCKETS if(sockfd == INVALID_SOCKET) { #endif /* WIN32_SOCKETS */ fprintf(stderr, "Error %d: socket() failed\n", errno); return(-1); } /* enable reuse of address */ flags = 1; if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&flags, sizeof(flags)) != 0) { fprintf(stderr, "Error %d: setsockopt(SO_REUSEADDR) failed\n", errno); return(-1); } #ifdef UNIX_SOCKETS /* set non-blocking */ flags = fcntl(sockfd, F_GETFL); if(flags < 0) { fprintf(stderr, "Error %d: fcntl(F_GETFL) failed\n", errno); return(-1); } if(fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) { fprintf(stderr, "Error %d: fcntl(F_SETFL) failed\n", errno); return(-1); } #endif /* UNIX_SOCKETS */ /* preset socket structure for socket binding */ memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = htons(port); saddr.sin_addr.s_addr = INADDR_ANY; if(bind(sockfd, (struct sockaddr *)&saddr, sizeof(struct sockaddr)) != 0) { fprintf(stderr, "Error %d: bind() failed\n", errno); return(-1); } /* prepare for listening */ if(listen(sockfd, PENDING_QUEUE_SIZE) != 0) { fprintf(stderr, "Error %d: listen() failed\n", errno); return(-1); } #ifdef UNIX_SOCKETS /* setup SIGINT handler that will stop the server */ signal(SIGINT, int_signal_handler); #endif /* UNIX_SOCKETS */ if(log_level >= LOG_LEVEL_INFO) { fprintf(stdout, "Log: server is ready and listening on port %d\n", port); } return(0); } /** * stop_server: * * Shuts down TCP server. */ static void stop_server() { #ifdef UNIX_SOCKETS if(sockfd != -1) { shutdown(sockfd, SHUT_RDWR); close(sockfd); sockfd = -1; } #endif /* UNIX_SOCKETS */ #ifdef WIN32_SOCKETS if(sockfd != -1) { close(sockfd); sockfd = -1; } #endif /* WIN32_SOCKETS */ if(log_level >= LOG_LEVEL_INFO) { fprintf(stdout, "Log: server is shutted down\n"); } } /** * int_signal_handler: * @sig_num: the signal number. * * Unix's Ctrl-C signal handler that stops the server. */ static void int_signal_handler(int sig_num) { if(log_level >= LOG_LEVEL_INFO) { fprintf(stdout, "Log: server is asked to shutdown\n"); } finished = 1; } /** * handle_connection: * @sockfd: the server's socket. * @xkmsCtx: the template XKMS server context. * @format: the expected format of XKMS requests. * * Establishs a connection, forks a child process (onUnix), reads the request, * processes it and writes back the response. * * Returns 0 on success or a negative value if an error occurs. */ static int handle_connection(int sockfd, xmlSecXkmsServerCtxPtr xkmsCtx, xmlSecXkmsServerFormat format) { #ifdef UNIX_SOCKETS int fd = -1; #endif /* UNIX_SOCKETS */ #ifdef WIN32_SOCKETS SOCKET fd = -1; #endif /* WIN32_SOCKETS */ int in_child_process = 0; struct sockaddr_in saddr; int saddr_size; xmlSecXkmsServerCtxPtr xkmsCtx2 = NULL; xmlSecBufferPtr buffer = NULL; xmlDocPtr inDoc = NULL; xmlDocPtr outDoc = NULL; xmlNodePtr result = NULL; xmlOutputBufferPtr output = NULL; int resp_ready = 0; int ret; assert(sockfd != -1); assert(xkmsCtx != NULL); /* Get the socket connection */ saddr_size = sizeof(struct sockaddr_in); fd = accept(sockfd, (struct sockaddr *)&saddr, &saddr_size); #ifdef UNIX_SOCKETS if(sockfd == -1) { #endif /* UNIX_SOCKETS */ #ifdef WIN32_SOCKETS if(sockfd == INVALID_SOCKET) { #endif /* WIN32_SOCKETS */ fprintf(stderr, "Error %d: accept() failed\n", errno); return(-1); } if(log_level >= LOG_LEVEL_INFO) { fprintf(stdout, "Log [%s]: got connection\n", inet_ntoa(saddr.sin_addr)); } /* Create a copy of XKMS server context */ xkmsCtx2 = xmlSecXkmsServerCtxCreate(NULL); if(xkmsCtx2 == NULL) { fprintf(stderr, "Error %d [%s]: a copy of XKMS server context initialization failed\n", errno, inet_ntoa(saddr.sin_addr)); goto done; } if(xmlSecXkmsServerCtxCopyUserPref(xkmsCtx2, xkmsCtx) < 0) { fprintf(stderr, "Error %d [%s]: XKMS server context copy failed\n", errno, inet_ntoa(saddr.sin_addr)); goto done; } #ifdef UNIX_SOCKETS /* on Unix we use child process to process requests */ if(fork()) { /* parent process */ return(0); } /* child process */ in_child_process = 1; close(sockfd); /* we don't need listening socket */ #endif /* UNIX_SOCKETS */ buffer = xmlSecBufferCreate(0); if(buffer == NULL) { fprintf(stderr, "Error %d [%s]: xmlSecBufferCreate() failed\n", errno, inet_ntoa(saddr.sin_addr)); goto done; } /* read input request */ ret = read_request(fd, inet_ntoa(saddr.sin_addr), buffer); if(ret < 0) { fprintf(stderr, "Error %d [%s]: read_request() failed\n", errno, inet_ntoa(saddr.sin_addr)); goto done; } /* parse request */ inDoc = xmlParseMemory(xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer) ); if((inDoc == NULL) || (xmlDocGetRootElement(inDoc) == NULL)) { fprintf(stderr, "Error %d [%s]: failed to parse request\n", errno, inet_ntoa(saddr.sin_addr)); goto done; } xmlSecBufferEmpty(buffer); /* prepare result document */ outDoc = xmlNewDoc(BAD_CAST "1.0"); if(outDoc == NULL) { fprintf(stderr, "Error %d [%s]: failed to create result doc\n", errno, inet_ntoa(saddr.sin_addr)); goto done; } result = xmlSecXkmsServerCtxProcess(xkmsCtx2, xmlDocGetRootElement(inDoc), format, outDoc); if(result == NULL) { fprintf(stderr, "Error %d [%s]: failed to process xkms server request\n", errno, inet_ntoa(saddr.sin_addr)); goto done; } /* apppend returned result node to the output document */ xmlDocSetRootElement(outDoc, result); /* create LibXML2 output buffer */ output = xmlSecBufferCreateOutputBuffer(buffer); if(output == NULL) { fprintf(stderr, "Error %d [%s]: xmlSecBufferCreateOutputBuffer() failed\n", errno, inet_ntoa(saddr.sin_addr)); goto done; } xmlNodeDumpOutput(output, result->doc, result, 0, 0, NULL); xmlOutputBufferClose(output); output = NULL; resp_ready = 1; done: /* send back response */ if((resp_ready == 1) && (xmlSecBufferGetData(buffer) != NULL)) { ret = send_response(fd, inet_ntoa(saddr.sin_addr), 200, xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer)); if(log_level >= LOG_LEVEL_INFO) { fprintf(stdout, "Log [%s]: processed request\n", inet_ntoa(saddr.sin_addr)); } } else if(fd >= 0) { ret = send_response(fd, inet_ntoa(saddr.sin_addr), 503, http_503, strlen(http_503)); if(log_level >= LOG_LEVEL_INFO) { fprintf(stdout, "Log [%s]: failed to process request\n", inet_ntoa(saddr.sin_addr)); } } else { ret = -1; } if(ret < 0) { fprintf(stderr, "Error %d [%s]: send_response() failed\n", errno, inet_ntoa(saddr.sin_addr)); } /* cleanup */ if(output != NULL) { xmlOutputBufferClose(output); output = NULL; } if(outDoc != NULL) { xmlFreeDoc(outDoc); outDoc = NULL; } if(inDoc != NULL) { xmlFreeDoc(inDoc); inDoc = NULL; } if(buffer != NULL) { xmlSecBufferDestroy(buffer); buffer = NULL; } if(xkmsCtx2 != NULL) { xmlSecXkmsServerCtxDestroy(xkmsCtx2); xkmsCtx2 = NULL; } if(fd >= 0) { #ifdef UNIX_SOCKETS shutdown(fd, SHUT_RDWR); close(fd); #endif /* UNIX_SCOKETS */ #ifdef WIN32_SOCKETS close(fd); #endif /* WIN32_SCOKETS */ fd = -1; } if(in_child_process) { exit(0); } return(0); } /** * read_request: * @fd: the request's socket. * @in_ip: the request's IP address (for logging). * @buffer: the output buffer. * * Reads the request from socket @fd and stores it in the @buffer. * * Returns 0 on success or a negative value if an error occurs. */ static int read_request(int fd, const char* in_ip, xmlSecBufferPtr buffer) { char buf[1024]; const xmlChar* s; const xmlChar* p; int nread; int length = 0; int found = 0; int counter; assert(fd != -1); assert(in_ip != NULL); assert(buffer); /* first read the http headers */ counter = 5; while(my_strnstr(xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer), BAD_CAST "\r\n\r\n", 4) == NULL) { nread = recv(fd, buf, sizeof(buf), 0); if(nread < 0) { fprintf(stderr, "Error %d [%s]: read() failed\n", errno, in_ip); return(-1); } if((nread > 0) && (xmlSecBufferAppend(buffer, buf, nread) < 0)) { fprintf(stderr, "Error %d [%s]: xmlSecBufferAppend(%d) failed\n", errno, in_ip, nread); return(-1); } if(nread < sizeof(buffer)) { counter--; if(counter <= 0) { break; } } } if(xmlSecBufferGetData(buffer) == NULL) { fprintf(stderr, "Error %d [%s]: no bytes read\n", errno, in_ip); return(-1); } if(log_level >= LOG_LEVEL_DEBUG) { xmlSecBufferAppend(buffer, BAD_CAST "\0", 1); fprintf(stdout, "Debug [%s]: request headers:\n%s\n", in_ip, xmlSecBufferGetData(buffer)); xmlSecBufferRemoveTail(buffer, 1); } /* Parse the request and extract the body. We expect the request to look * like this: * POST HTTP/1.x\r\n * \r\n * \r\n * ... * \r\n * \r\n * */ /* analyze the first line */ p = my_strnstr(xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer), BAD_CAST "\r\n", 2); if(p == NULL) { fprintf(stderr, "Error %d [%s]: there is no HTTP header\n", errno, in_ip); return(-1); } if(xmlStrncasecmp(xmlSecBufferGetData(buffer), BAD_CAST "POST ", 5) != 0) { fprintf(stderr, "Error %d [%s]: not a POST request\n", errno, in_ip); return(-1); } /* "POST " + " HTTP/1.x" == 14 */ s = xmlSecBufferGetData(buffer); if(p - s <= 14) { fprintf(stderr, "Error %d [%s]: first line has bad length\n", errno, in_ip); return(-1); } if((xmlStrncasecmp(p - 9, BAD_CAST " HTTP/1.0", 9) != 0) && (xmlStrncasecmp(p - 9, BAD_CAST " HTTP/1.1", 9) != 0)) { fprintf(stderr, "Error %d [%s]: first line does not end with \" HTTP/1.x\"\n", errno, in_ip); return(-1); } if(xmlSecBufferRemoveHead(buffer, p - xmlSecBufferGetData(buffer) + 2) < 0) { fprintf(stderr, "Error %d [%s]: failed to skip first line\n", errno, in_ip); return(-1); } /* now skip all the headers (i.e. everything until empty line) */ found = 0; while(!found) { p = my_strnstr(xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer), BAD_CAST "\r\n", 2); if(p == NULL) { fprintf(stderr, "Error %d [%s]: there is no HTTP body\n", errno, in_ip); return(-1); } if(p == xmlSecBufferGetData(buffer)) { found = 1; } else if(xmlStrncasecmp(xmlSecBufferGetData(buffer), BAD_CAST "Content-length: ", 16) == 0) { length = atoi(xmlSecBufferGetData(buffer) + 16); } if(xmlSecBufferRemoveHead(buffer, p - xmlSecBufferGetData(buffer) + 2) < 0) { fprintf(stderr, "Error %d [%s]: failed to skip header line\n", errno, in_ip); return(-1); } } /* remove the trailing \0 we added */ xmlSecBufferRemoveTail(buffer, 1); /* now read the body */ counter = 5; while(xmlSecBufferGetSize(buffer) < length) { nread = recv(fd, buf, sizeof(buf), 0); if(nread < 0) { fprintf(stderr, "Error %d [%s]: read() failed\n", errno, in_ip); return(-1); } if((nread > 0) && (xmlSecBufferAppend(buffer, buf, nread) < 0)) { fprintf(stderr, "Error %d [%s]: xmlSecBufferAppend(%d) failed\n", errno, in_ip, nread); return(-1); } if(nread < sizeof(buffer)) { counter--; if(counter <= 0) { break; } } } if(log_level >= LOG_LEVEL_INFO) { fprintf(stdout, "Log [%s]: body size is %d bytes\n", in_ip, xmlSecBufferGetSize(buffer)); } if(log_level >= LOG_LEVEL_DATA) { xmlSecBufferAppend(buffer, BAD_CAST "\0", 1); fprintf(stdout, "Log [%s]: request body:\n%s\n", in_ip, xmlSecBufferGetData(buffer)); xmlSecBufferRemoveTail(buffer, 1); } return(0); } /** * send_response: * @fd: the request's socket. * @in_ip: the request's IP address (for logging). * @resp_code: the HTTP response code. * @body: the response body. * @body_len: the response body length. * * Writes HTTP response headers and @body to the @socket. * * Returns 0 on success or a negative value if an error occurs. */ static int send_response(int fd, const char* in_ip, int resp_code, const char* body, int body_size) { char header[sizeof(http_header) + 100]; assert(fd != -1); assert(in_ip != NULL); assert(resp_code > 0); assert(body != NULL); /* prepare and send http header */ sprintf(header, http_header, resp_code, body_size); if(send(fd, header, strlen(header), 0) == -1) { fprintf(stderr, "Error %d [%s]: send(header) failed\n", errno, in_ip); return(-1); } if(log_level >= LOG_LEVEL_DATA) { xmlChar* tmp = xmlStrndup(body, body_size); fprintf(stdout, "Log [%s]: response is\n%s\n", in_ip, tmp); xmlFree(tmp); } /* send body */ if(send(fd, body, body_size, 0) == -1) { fprintf(stderr, "Error %d [%s]: send(body) failed\n", errno, in_ip); return(-1); } return(0); } /** * my_strnstr: * @str: the soruce string. * @strLen: the source string length. * @tmpl: the template string. * @tmplLen: the template string length. * * Searches for the first occurence of @tmpl in @str. * * Returns pointer to the first occurence of @tmpl in @str or NULL if it is not found. */ static const xmlChar* my_strnstr(const xmlChar* str, xmlSecSize strLen, const xmlChar* tmpl, xmlSecSize tmplLen) { xmlSecSize pos; if((str == NULL) || (tmpl == NULL)) { return(NULL); } for(pos = 0; pos + tmplLen <= strLen; pos++) { if(xmlStrncmp(str + pos, tmpl, tmplLen) == 0) { return(str + pos); } } return(NULL); } #endif /* XMLSEC_NO_XKMS */