void process_serverdata(conn_t *conn) { /* * Handle data we received while talking to the Hobbit server. * We only handle the "client" message response. */ if (conn->savedata) { /* * We just sent a "client" message. So * save the response, which is the client configuration * data that we will provide to the client the next time * we contact him. */ if (conn->client->clientdata) xfree(conn->client->clientdata); conn->client->clientdata = grabstrbuffer(conn->msgbuf); conn->msgbuf = NULL; dbgprintf("Client data for %s (req %lu): %s\n", conn->client->hostname, conn->seq, (conn->client->clientdata ? conn->client->clientdata : "<Null>")); } }
void add_http_test(testitem_t *t) { http_data_t *httptest; char *dnsip = NULL; ssloptions_t *sslopt = NULL; char *sslopt_ciphers = NULL; int sslopt_version = SSLVERSION_DEFAULT; char *sslopt_clientcert = NULL; int httpversion = HTTPVER_11; cookielist_t *ck = NULL; int firstcookie = 1; char *decodedurl; strbuffer_t *httprequest = newstrbuffer(0); /* Allocate the private data and initialize it */ httptest = (http_data_t *) calloc(1, sizeof(http_data_t)); t->privdata = (void *) httptest; decodedurl = decode_url(t->testspec, &httptest->weburl); if (!decodedurl) { errprintf("Invalid URL for http check: %s\n", t->testspec); return; } httptest->url = strdup(decodedurl); httptest->contlen = -1; httptest->parsestatus = (httptest->weburl.proxyurl ? httptest->weburl.proxyurl->parseerror : httptest->weburl.desturl->parseerror); /* If there was a parse error in the URL, dont run the test */ if (httptest->parsestatus) return; if (httptest->weburl.proxyurl && (httptest->weburl.proxyurl->ip == NULL)) { dnsip = dnsresolve(httptest->weburl.proxyurl->host); if (dnsip) { httptest->weburl.proxyurl->ip = strdup(dnsip); } else { dbgprintf("Could not resolve URL hostname '%s'\n", httptest->weburl.proxyurl->host); } } else if (httptest->weburl.desturl->ip == NULL) { dnsip = dnsresolve(httptest->weburl.desturl->host); if (dnsip) { httptest->weburl.desturl->ip = strdup(dnsip); } else { dbgprintf("Could not resolve URL hostname '%s'\n", httptest->weburl.desturl->host); } } switch (httptest->weburl.testtype) { case WEBTEST_PLAIN: case WEBTEST_STATUS: httptest->contentcheck = CONTENTCHECK_NONE; break; case WEBTEST_CONTENT: { FILE *contentfd; char contentfn[PATH_MAX]; sprintf(contentfn, "%s/content/%s.substring", xgetenv("XYMONHOME"), commafy(t->host->hostname)); contentfd = fopen(contentfn, "r"); if (contentfd) { char l[MAX_LINE_LEN]; char *p; if (fgets(l, sizeof(l), contentfd)) { p = strchr(l, '\n'); if (p) { *p = '\0'; }; httptest->weburl.expdata = strdup(l); } else { httptest->contstatus = STATUS_CONTENTMATCH_NOFILE; } fclose(contentfd); } else { httptest->contstatus = STATUS_CONTENTMATCH_NOFILE; } httptest->contentcheck = CONTENTCHECK_REGEX; } break; case WEBTEST_CONT: httptest->contentcheck = ((*httptest->weburl.expdata == '#') ? CONTENTCHECK_DIGEST : CONTENTCHECK_REGEX); break; case WEBTEST_NOCONT: httptest->contentcheck = CONTENTCHECK_NOREGEX; break; case WEBTEST_POST: case WEBTEST_SOAP: if (httptest->weburl.expdata == NULL) { httptest->contentcheck = CONTENTCHECK_NONE; } else { httptest->contentcheck = ((*httptest->weburl.expdata == '#') ? CONTENTCHECK_DIGEST : CONTENTCHECK_REGEX); } break; case WEBTEST_NOPOST: case WEBTEST_NOSOAP: if (httptest->weburl.expdata == NULL) { httptest->contentcheck = CONTENTCHECK_NONE; } else { httptest->contentcheck = CONTENTCHECK_NOREGEX; } break; case WEBTEST_TYPE: httptest->contentcheck = CONTENTCHECK_CONTENTTYPE; break; } /* Compile the hashes and regex's for those tests that use it */ switch (httptest->contentcheck) { case CONTENTCHECK_DIGEST: { char *hashfunc; httptest->exp = (void *) strdup(httptest->weburl.expdata+1); hashfunc = strchr(httptest->exp, ':'); if (hashfunc) { *hashfunc = '\0'; httptest->digestctx = digest_init(httptest->exp); *hashfunc = ':'; } } break; case CONTENTCHECK_REGEX: case CONTENTCHECK_NOREGEX: { int status; httptest->exp = (void *) malloc(sizeof(regex_t)); status = regcomp((regex_t *)httptest->exp, httptest->weburl.expdata, REG_EXTENDED|REG_NOSUB); if (status) { errprintf("Failed to compile regexp '%s' for URL %s\n", httptest->weburl.expdata, httptest->url); httptest->contstatus = STATUS_CONTENTMATCH_BADREGEX; } } break; case CONTENTCHECK_CONTENTTYPE: httptest->exp = httptest->weburl.expdata; break; } if (httptest->weburl.desturl->schemeopts) { if (strstr(httptest->weburl.desturl->schemeopts, "3")) sslopt_version = SSLVERSION_V3; else if (strstr(httptest->weburl.desturl->schemeopts, "2")) sslopt_version = SSLVERSION_V2; if (strstr(httptest->weburl.desturl->schemeopts, "h")) sslopt_ciphers = ciphershigh; else if (strstr(httptest->weburl.desturl->schemeopts, "m")) sslopt_ciphers = ciphersmedium; if (strstr(httptest->weburl.desturl->schemeopts, "10")) httpversion = HTTPVER_10; else if (strstr(httptest->weburl.desturl->schemeopts, "11")) httpversion = HTTPVER_11; } /* Get any cookies */ load_cookies(); /* Generate the request */ addtobuffer(httprequest, (httptest->weburl.postdata ? "POST " : "GET ")); switch (httpversion) { case HTTPVER_10: addtobuffer(httprequest, (httptest->weburl.proxyurl ? httptest->url : httptest->weburl.desturl->relurl)); addtobuffer(httprequest, " HTTP/1.0\r\n"); break; case HTTPVER_11: /* * Experience shows that even though HTTP/1.1 says you should send the * full URL, some servers (e.g. SunOne App server 7) choke on it. * So just send the good-old relative URL unless we're proxying. */ addtobuffer(httprequest, (httptest->weburl.proxyurl ? httptest->url : httptest->weburl.desturl->relurl)); addtobuffer(httprequest, " HTTP/1.1\r\n"); addtobuffer(httprequest, "Connection: close\r\n"); break; } addtobuffer(httprequest, "Host: "); addtobuffer(httprequest, httptest->weburl.desturl->host); if ((httptest->weburl.desturl->port != 80) && (httptest->weburl.desturl->port != 443)) { char hostporthdr[20]; sprintf(hostporthdr, ":%d", httptest->weburl.desturl->port); addtobuffer(httprequest, hostporthdr); } addtobuffer(httprequest, "\r\n"); if (httptest->weburl.postdata) { char hdr[100]; int contlen = strlen(httptest->weburl.postdata); if (strncmp(httptest->weburl.postdata, "file:", 5) == 0) { /* Load the POST data from a file */ FILE *pf = fopen(httptest->weburl.postdata+5, "r"); if (pf == NULL) { errprintf("Cannot open POST data file %s\n", httptest->weburl.postdata+5); xfree(httptest->weburl.postdata); httptest->weburl.postdata = strdup(""); contlen = 0; } else { struct stat st; if (fstat(fileno(pf), &st) == 0) { int n; xfree(httptest->weburl.postdata); httptest->weburl.postdata = (char *)malloc(st.st_size + 1); *(httptest->weburl.postdata) = '\0'; n = fread(httptest->weburl.postdata, 1, st.st_size, pf); if (n == st.st_size) { *(httptest->weburl.postdata+n) = '\0'; contlen = n; } else { errprintf("Cannot read file %s: %s\n", httptest->weburl.postdata+5, strerror(errno)); contlen = 0; } } else { errprintf("Cannot stat file %s\n", httptest->weburl.postdata+5); httptest->weburl.postdata = strdup(""); contlen = 0; } fclose(pf); } } addtobuffer(httprequest, "Content-type: "); if (httptest->weburl.postcontenttype) addtobuffer(httprequest, httptest->weburl.postcontenttype); else if ((httptest->weburl.testtype == WEBTEST_SOAP) || (httptest->weburl.testtype == WEBTEST_NOSOAP)) addtobuffer(httprequest, "application/soap+xml; charset=utf-8"); else addtobuffer(httprequest, "application/x-www-form-urlencoded"); addtobuffer(httprequest, "\r\n"); sprintf(hdr, "Content-Length: %d\r\n", contlen); addtobuffer(httprequest, hdr); } { char useragent[100]; void *hinfo; char *browser = NULL; hinfo = hostinfo(t->host->hostname); if (hinfo) browser = xmh_item(hinfo, XMH_BROWSER); if (browser) { sprintf(useragent, "User-Agent: %s\r\n", browser); } else { sprintf(useragent, "User-Agent: Xymon xymonnet/%s\r\n", VERSION); } addtobuffer(httprequest, useragent); } if (httptest->weburl.desturl->auth) { if (strncmp(httptest->weburl.desturl->auth, "CERT:", 5) == 0) { sslopt_clientcert = httptest->weburl.desturl->auth+5; } else { addtobuffer(httprequest, "Authorization: Basic "); addtobuffer(httprequest, base64encode(httptest->weburl.desturl->auth)); addtobuffer(httprequest, "\r\n"); } } if (httptest->weburl.proxyurl && httptest->weburl.proxyurl->auth) { addtobuffer(httprequest, "Proxy-Authorization: Basic "); addtobuffer(httprequest, base64encode(httptest->weburl.proxyurl->auth)); addtobuffer(httprequest, "\r\n"); } for (ck = cookiehead; (ck); ck = ck->next) { int useit = 0; if (ck->tailmatch) { int startpos = strlen(httptest->weburl.desturl->host) - strlen(ck->host); if (startpos > 0) useit = (strcmp(httptest->weburl.desturl->host+startpos, ck->host) == 0); } else useit = (strcmp(httptest->weburl.desturl->host, ck->host) == 0); if (useit) useit = (strncmp(ck->path, httptest->weburl.desturl->relurl, strlen(ck->path)) == 0); if (useit) { if (firstcookie) { addtobuffer(httprequest, "Cookie: "); firstcookie = 0; } addtobuffer(httprequest, ck->name); addtobuffer(httprequest, "="); addtobuffer(httprequest, ck->value); addtobuffer(httprequest, "\r\n"); } } /* Some standard stuff */ addtobuffer(httprequest, "Accept: */*\r\n"); addtobuffer(httprequest, "Pragma: no-cache\r\n"); if ((httptest->weburl.testtype == WEBTEST_SOAP) || (httptest->weburl.testtype == WEBTEST_NOSOAP)) { /* Must provide a SOAPAction header */ addtobuffer(httprequest, "SOAPAction: "); addtobuffer(httprequest, httptest->url); addtobuffer(httprequest, "\r\n"); } /* The final blank line terminates the headers */ addtobuffer(httprequest, "\r\n"); /* Post data goes last */ if (httptest->weburl.postdata) addtobuffer(httprequest, httptest->weburl.postdata); /* Pickup any SSL options the user wants */ if (sslopt_ciphers || (sslopt_version != SSLVERSION_DEFAULT) || sslopt_clientcert){ sslopt = (ssloptions_t *) malloc(sizeof(ssloptions_t)); sslopt->cipherlist = sslopt_ciphers; sslopt->sslversion = sslopt_version; sslopt->clientcert = sslopt_clientcert; } /* Add to TCP test queue */ if (httptest->weburl.proxyurl == NULL) { httptest->tcptest = add_tcp_test(httptest->weburl.desturl->ip, httptest->weburl.desturl->port, httptest->weburl.desturl->scheme, sslopt, t->srcip, t->testspec, t->silenttest, grabstrbuffer(httprequest), httptest, tcp_http_data_callback, tcp_http_final_callback); } else { httptest->tcptest = add_tcp_test(httptest->weburl.proxyurl->ip, httptest->weburl.proxyurl->port, httptest->weburl.proxyurl->scheme, sslopt, t->srcip, t->testspec, t->silenttest, grabstrbuffer(httprequest), httptest, tcp_http_data_callback, tcp_http_final_callback); } }
int main(int argc, char *argv[]) { void *hostwalk, *clonewalk; int argi; char *envarea = NULL; strbuffer_t *outbuf; char msgline[4096]; char oneurl[10240]; int gotany = 0; enum { OP_INITIAL, OP_YES, OP_NO } gotonepage = OP_INITIAL; /* Tracks if all matches are on one page */ char *onepage = NULL; /* If gotonepage==OP_YES, then this is the page */ /*[wm] regex support */ #define BUFSIZE 256 regex_t re; char re_errstr[BUFSIZE]; int re_status; for (argi=1; (argi < argc); argi++) { if (argnmatch(argv[argi], "--env=")) { char *p = strchr(argv[argi], '='); loadenv(p+1, envarea); } else if (argnmatch(argv[argi], "--area=")) { char *p = strchr(argv[argi], '='); envarea = strdup(p+1); } } redirect_cgilog("findhost"); cgidata = cgi_request(); if (cgidata == NULL) { /* Present the query form */ sethostenv("", "", "", colorname(COL_BLUE), NULL); printf("Content-type: %s\n\n", xgetenv("HTMLCONTENTTYPE")); showform(stdout, "findhost", "findhost_form", COL_BLUE, getcurrenttime(NULL), NULL, NULL); return 0; } parse_query(); if ( (re_status = regcomp(&re, pSearchPat, re_flag)) != 0 ) { regerror(re_status, &re, re_errstr, BUFSIZE); print_header(); printf("<tr><td align=left><font color=red>%s</font></td>\n", pSearchPat); printf("<td align=left><font color=red>%s</font></td></tr>\n", re_errstr); print_footer(); return 0; } outbuf = newstrbuffer(0); load_hostnames(xgetenv("HOSTSCFG"), NULL, get_fqdn()); hostwalk = first_host(); while (hostwalk) { /* * [wm] - Allow the search to be done on the hostname * also on the "displayname" and the host comment * Maybe this should be implemented by changing the HTML form, but until than.. * we're supposing that hostname will NEVER be null */ char *hostname, *displayname, *comment, *ip; hostname = xmh_item(hostwalk, XMH_HOSTNAME); displayname = xmh_item(hostwalk, XMH_DISPLAYNAME); comment = xmh_item(hostwalk, XMH_COMMENT); ip = xmh_item(hostwalk, XMH_IP); if ( regexec (&re, hostname, (size_t)0, NULL, 0) == 0 || (regexec(&re, ip, (size_t)0, NULL, 0) == 0) || (displayname && regexec (&re, displayname, (size_t)0, NULL, 0) == 0) || (comment && regexec (&re, comment, (size_t)0, NULL, 0) == 0) ) { /* match */ addtobuffer(outbuf, "<tr>\n"); sprintf(msgline, "<td align=left> %s </td>\n", displayname ? displayname : hostname); addtobuffer(outbuf, msgline); sprintf(oneurl, "%s/%s/#%s", xgetenv("XYMONWEB"), xmh_item(hostwalk, XMH_PAGEPATH), hostname); sprintf(msgline, "<td align=left> <a href=\"%s\">%s</a>\n", oneurl, xmh_item(hostwalk, XMH_PAGEPATHTITLE)); addtobuffer(outbuf, msgline); gotany++; /* See if all of the matches so far are on one page */ switch (gotonepage) { case OP_INITIAL: gotonepage = OP_YES; onepage = xmh_item(hostwalk, XMH_PAGEPATH); break; case OP_YES: if (strcmp(onepage, xmh_item(hostwalk, XMH_PAGEPATH)) != 0) gotonepage = OP_NO; break; case OP_NO: break; } clonewalk = next_host(hostwalk, 1); while (clonewalk && (strcmp(xmh_item(hostwalk, XMH_HOSTNAME), xmh_item(clonewalk, XMH_HOSTNAME)) == 0)) { sprintf(msgline, "<br><a href=\"%s/%s/#%s\">%s</a>\n", xgetenv("XYMONWEB"), xmh_item(clonewalk, XMH_PAGEPATH), xmh_item(clonewalk, XMH_HOSTNAME), xmh_item(clonewalk, XMH_PAGEPATHTITLE)); addtobuffer(outbuf, msgline); clonewalk = next_host(clonewalk, 1); gotany++; } addtobuffer(outbuf, "</td>\n</tr>\n"); hostwalk = clonewalk; } else { hostwalk = next_host(hostwalk, 0); } } regfree (&re); /*[wm] - free regex compiled patern */ if (dojump) { if (gotany == 1) { printf("Location: %s%s\n\n", xgetenv("XYMONWEBHOST"), oneurl); return 0; } else if ((gotany > 1) && (gotonepage == OP_YES)) { printf("Location: %s%s/%s/\n\n", xgetenv("XYMONWEBHOST"), xgetenv("XYMONWEB"), onepage); return 0; } } print_header(); if (!gotany) { printf("<tr><td align=left>%s</td><td align=left>Not found</td></tr>\n", pSearchPat); } else { printf("%s", grabstrbuffer(outbuf)); } print_footer(); /* [wm] - Free the strdup allocated memory */ if (pSearchPat) xfree(pSearchPat); return 0; }
static void setup_ssl(tcptest_t *item) { static int ssl_init_complete = 0; struct servent *sp; char portinfo[100]; X509 *peercert; char *certcn, *certstart, *certend; int err; strbuffer_t *sslinfo; char msglin[2048]; item->sslrunning = 1; if (!ssl_init_complete) { /* Setup entropy */ if (RAND_status() != 1) { char path[PATH_MAX]; /* Path for the random file */ /* load entropy from files */ RAND_load_file(RAND_file_name(path, sizeof (path)), -1); /* load entropy from egd sockets */ RAND_egd("/var/run/egd-pool"); RAND_egd("/dev/egd-pool"); RAND_egd("/etc/egd-pool"); RAND_egd("/var/spool/prngd/pool"); /* shuffle $RANDFILE (or ~/.rnd if unset) */ RAND_write_file(RAND_file_name(path, sizeof (path))); if (RAND_status() != 1) { errprintf("Failed to find enough entropy on your system"); item->errcode = CONTEST_ESSL; return; } } SSL_load_error_strings(); SSL_library_init(); ssl_init_complete = 1; } if (item->sslctx == NULL) { switch (item->ssloptions->sslversion) { case SSLVERSION_V2: item->sslctx = SSL_CTX_new(SSLv2_client_method()); break; case SSLVERSION_V3: item->sslctx = SSL_CTX_new(SSLv3_client_method()); break; case SSLVERSION_TLS1: item->sslctx = SSL_CTX_new(TLSv1_client_method()); break; default: item->sslctx = SSL_CTX_new(SSLv23_client_method()); break; } if (!item->sslctx) { char sslerrmsg[256]; ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Cannot create SSL context - IP %s, service %s: %s\n", inet_ntoa(item->addr.sin_addr), item->svcinfo->svcname, sslerrmsg); item->sslrunning = 0; item->errcode = CONTEST_ESSL; return; } /* Workaround SSL bugs */ SSL_CTX_set_options(item->sslctx, SSL_OP_ALL); SSL_CTX_set_quiet_shutdown(item->sslctx, 1); /* Limit set of ciphers, if user wants to */ if (item->ssloptions->cipherlist) SSL_CTX_set_cipher_list(item->sslctx, item->ssloptions->cipherlist); if (item->ssloptions->clientcert) { int status; char certfn[PATH_MAX]; SSL_CTX_set_default_passwd_cb(item->sslctx, cert_password_cb); SSL_CTX_set_default_passwd_cb_userdata(item->sslctx, item); sprintf(certfn, "%s/certs/%s", xgetenv("XYMONHOME"), item->ssloptions->clientcert); status = SSL_CTX_use_certificate_chain_file(item->sslctx, certfn); if (status == 1) { status = SSL_CTX_use_PrivateKey_file(item->sslctx, certfn, SSL_FILETYPE_PEM); } if (status != 1) { char sslerrmsg[256]; ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Cannot load SSL client certificate/key %s: %s\n", item->ssloptions->clientcert, sslerrmsg); item->sslrunning = 0; item->errcode = CONTEST_ESSL; return; } } } if (item->ssldata == NULL) { item->ssldata = SSL_new(item->sslctx); if (!item->ssldata) { char sslerrmsg[256]; ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("SSL_new failed - IP %s, service %s: %s\n", inet_ntoa(item->addr.sin_addr), item->svcinfo->svcname, sslerrmsg); item->sslrunning = 0; SSL_CTX_free(item->sslctx); item->errcode = CONTEST_ESSL; return; } /* Verify that the client certificate is working */ if (item->ssloptions->clientcert) { X509 *x509; x509 = SSL_get_certificate(item->ssldata); if(x509 != NULL) { EVP_PKEY *pktmp = X509_get_pubkey(x509); EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(item->ssldata)); EVP_PKEY_free(pktmp); } if (!SSL_CTX_check_private_key(item->sslctx)) { errprintf("Private/public key mismatch for certificate %s\n", item->ssloptions->clientcert); item->sslrunning = 0; item->errcode = CONTEST_ESSL; return; } } /* SSL setup is done. Now attach the socket FD to the SSL protocol handler */ if (SSL_set_fd(item->ssldata, item->fd) != 1) { char sslerrmsg[256]; ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Could not initiate SSL on connection - IP %s, service %s: %s\n", inet_ntoa(item->addr.sin_addr), item->svcinfo->svcname, sslerrmsg); item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); item->errcode = CONTEST_ESSL; return; } } sp = getservbyport(item->addr.sin_port, "tcp"); if (sp) { sprintf(portinfo, "%s (%d/tcp)", sp->s_name, item->addr.sin_port); } else { sprintf(portinfo, "%d/tcp", item->addr.sin_port); } if ((err = SSL_connect(item->ssldata)) != 1) { char sslerrmsg[256]; switch (SSL_get_error (item->ssldata, err)) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: item->sslrunning = SSLSETUP_PENDING; break; case SSL_ERROR_SYSCALL: ERR_error_string(ERR_get_error(), sslerrmsg); /* Filter out the bogus SSL error */ if (strstr(sslerrmsg, "error:00000000:") == NULL) { errprintf("IO error in SSL_connect to %s on host %s: %s\n", portinfo, inet_ntoa(item->addr.sin_addr), sslerrmsg); } item->errcode = CONTEST_ESSL; item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); break; case SSL_ERROR_SSL: ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Unspecified SSL error in SSL_connect to %s on host %s: %s\n", portinfo, inet_ntoa(item->addr.sin_addr), sslerrmsg); item->errcode = CONTEST_ESSL; item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); break; default: ERR_error_string(ERR_get_error(), sslerrmsg); errprintf("Unknown error %d in SSL_connect to %s on host %s: %s\n", err, portinfo, inet_ntoa(item->addr.sin_addr), sslerrmsg); item->errcode = CONTEST_ESSL; item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); break; } return; } /* If we get this far, the SSL handshake has completed. So grab the certificate */ peercert = SSL_get_peer_certificate(item->ssldata); if (!peercert) { errprintf("Cannot get peer certificate for %s on host %s\n", portinfo, inet_ntoa(item->addr.sin_addr)); item->errcode = CONTEST_ESSL; item->sslrunning = 0; SSL_free(item->ssldata); SSL_CTX_free(item->sslctx); return; } sslinfo = newstrbuffer(0); certcn = X509_NAME_oneline(X509_get_subject_name(peercert), NULL, 0); certstart = strdup(xymon_ASN1_UTCTIME(X509_get_notBefore(peercert))); certend = strdup(xymon_ASN1_UTCTIME(X509_get_notAfter(peercert))); snprintf(msglin, sizeof(msglin), "Server certificate:\n\tsubject:%s\n\tstart date: %s\n\texpire date:%s\n", certcn, certstart, certend); addtobuffer(sslinfo, msglin); item->certsubject = strdup(certcn); item->certexpires = sslcert_expiretime(certend); xfree(certcn); xfree(certstart); xfree(certend); X509_free(peercert); /* We list the available ciphers in the SSL cert data */ { int i; STACK_OF(SSL_CIPHER) *sk; addtobuffer(sslinfo, "\nAvailable ciphers:\n"); sk = SSL_get_ciphers(item->ssldata); for (i=0; i<sk_SSL_CIPHER_num(sk); i++) { int b1, b2; char *cph; b1 = SSL_CIPHER_get_bits(sk_SSL_CIPHER_value(sk,i), &b2); cph = SSL_CIPHER_get_name(sk_SSL_CIPHER_value(sk,i)); snprintf(msglin, sizeof(msglin), "Cipher %d: %s (%d bits)\n", i, cph, b1); addtobuffer(sslinfo, msglin); if ((item->mincipherbits == 0) || (b1 < item->mincipherbits)) item->mincipherbits = b1; } } item->certinfo = grabstrbuffer(sslinfo); }
void run_ldap_tests(service_t *ldaptest, int sslcertcheck, int querytimeout) { #ifdef HAVE_LDAP ldap_data_t *req; testitem_t *t; struct timespec starttime; struct timespec endtime; /* Pick a sensible default for the timeout setting */ if (querytimeout == 0) querytimeout = 30; for (t = ldaptest->items; (t); t = t->next) { LDAPURLDesc *ludp; LDAP *ld; int rc, finished; int msgID = -1; struct timeval ldaptimeout; struct timeval openldaptimeout; LDAPMessage *result; LDAPMessage *e; strbuffer_t *response; char buf[MAX_LINE_LEN]; req = (ldap_data_t *) t->privdata; if (req->skiptest) continue; ludp = (LDAPURLDesc *) req->ldapdesc; getntimer(&starttime); /* Initiate session with the LDAP server */ dbgprintf("Initiating LDAP session for host %s port %d\n", ludp->lud_host, ludp->lud_port); if( (ld = ldap_init(ludp->lud_host, ludp->lud_port)) == NULL ) { dbgprintf("ldap_init failed\n"); req->ldapstatus = XYMON_LDAP_INITFAIL; continue; } /* * There is apparently no standard way of defining a network * timeout for the initial connection setup. */ #if (LDAP_VENDOR == OpenLDAP) && defined(LDAP_OPT_NETWORK_TIMEOUT) /* * OpenLDAP has an undocumented ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv) */ openldaptimeout.tv_sec = querytimeout; openldaptimeout.tv_usec = 0; ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &openldaptimeout); #else /* * So using an alarm() to interrupt any pending operations * seems to be the least insane way of doing this. * * Note that we must do this right after ldap_init(), as * any operation on the session handle (ld) may trigger the * network connection to be established. */ connect_timeout = 0; signal(SIGALRM, ldap_alarmhandler); alarm(querytimeout); #endif /* * This is completely undocumented in the OpenLDAP docs. * But apparently it is documented in * http://www.ietf.org/proceedings/99jul/I-D/draft-ietf-ldapext-ldap-c-api-03.txt * * Both of these routines appear in the <ldap.h> file * from OpenLDAP 2.1.22. Their use to enable TLS has * been deciphered from the ldapsearch() utility * sourcecode. * * According to Manon Goo <*****@*****.**>, recent (Jan. 2005) * OpenLDAP implementations refuse to talk LDAPv2. */ #ifdef LDAP_OPT_PROTOCOL_VERSION { int protocol = LDAP_VERSION3; dbgprintf("Attempting to select LDAPv3\n"); if ((rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &protocol)) != LDAP_SUCCESS) { dbgprintf("Failed to select LDAPv3, trying LDAPv2\n"); protocol = LDAP_VERSION2; if ((rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &protocol)) != LDAP_SUCCESS) { req->output = strdup(ldap_err2string(rc)); req->ldapstatus = XYMON_LDAP_TLSFAIL; } continue; } } #endif if (req->usetls) { dbgprintf("Trying to enable TLS for session\n"); if ((rc = ldap_start_tls_s(ld, NULL, NULL)) != LDAP_SUCCESS) { dbgprintf("ldap_start_tls failed\n"); req->output = strdup(ldap_err2string(rc)); req->ldapstatus = XYMON_LDAP_TLSFAIL; continue; } } if (!connect_timeout) { msgID = ldap_simple_bind(ld, (t->host->ldapuser ? t->host->ldapuser : ""), (t->host->ldappasswd ? t->host->ldappasswd : "")); } /* Cancel any pending alarms */ alarm(0); signal(SIGALRM, SIG_DFL); /* Did we connect? */ if (connect_timeout || (msgID == -1)) { req->ldapstatus = XYMON_LDAP_BINDFAIL; req->output = "Cannot connect to server"; continue; } /* Wait for bind to complete */ rc = 0; finished = 0; ldaptimeout.tv_sec = querytimeout; ldaptimeout.tv_usec = 0L; while( ! finished ) { int rc2; rc = ldap_result(ld, msgID, LDAP_MSG_ONE, &ldaptimeout, &result); dbgprintf("ldap_result returned %d for ldap_simple_bind()\n", rc); if(rc == -1) { finished = 1; req->ldapstatus = XYMON_LDAP_BINDFAIL; if (result == NULL) { errprintf("LDAP library problem - NULL result returned\n"); req->output = strdup("LDAP BIND failed\n"); } else { rc2 = ldap_result2error(ld, result, 1); req->output = strdup(ldap_err2string(rc2)); } ldap_unbind(ld); } else if (rc == 0) { finished = 1; req->ldapstatus = XYMON_LDAP_BINDFAIL; req->output = strdup("Connection timeout"); ldap_unbind(ld); } else if( rc > 0 ) { finished = 1; if (result == NULL) { errprintf("LDAP library problem - got a NULL resultcode for status %d\n", rc); req->ldapstatus = XYMON_LDAP_BINDFAIL; req->output = strdup("LDAP library problem: ldap_result2error returned a NULL result for status %d\n"); ldap_unbind(ld); } else { rc2 = ldap_result2error(ld, result, 1); if(rc2 != LDAP_SUCCESS) { req->ldapstatus = XYMON_LDAP_BINDFAIL; req->output = strdup(ldap_err2string(rc)); ldap_unbind(ld); } } } } /* ... while() */ /* We're done connecting. If something went wrong, go to next query. */ if (req->ldapstatus != 0) continue; /* Now do the search. With a timeout */ ldaptimeout.tv_sec = querytimeout; ldaptimeout.tv_usec = 0L; rc = ldap_search_st(ld, ludp->lud_dn, ludp->lud_scope, ludp->lud_filter, ludp->lud_attrs, 0, &ldaptimeout, &result); if(rc == LDAP_TIMEOUT) { req->ldapstatus = XYMON_LDAP_TIMEOUT; req->output = strdup(ldap_err2string(rc)); ldap_unbind(ld); continue; } if( rc != LDAP_SUCCESS ) { req->ldapstatus = XYMON_LDAP_SEARCHFAILED; req->output = strdup(ldap_err2string(rc)); ldap_unbind(ld); continue; } getntimer(&endtime); response = newstrbuffer(0); sprintf(buf, "Searching LDAP for %s yields %d results:\n\n", t->testspec, ldap_count_entries(ld, result)); addtobuffer(response, buf); for(e = ldap_first_entry(ld, result); (e != NULL); e = ldap_next_entry(ld, e) ) { char *dn; BerElement *ber; char *attribute; char **vals; dn = ldap_get_dn(ld, e); sprintf(buf, "DN: %s\n", dn); addtobuffer(response, buf); /* Addtributes and values */ for (attribute = ldap_first_attribute(ld, e, &ber); (attribute != NULL); attribute = ldap_next_attribute(ld, e, ber) ) { if ((vals = ldap_get_values(ld, e, attribute)) != NULL) { int i; for(i = 0; (vals[i] != NULL); i++) { sprintf(buf, "\t%s: %s\n", attribute, vals[i]); addtobuffer(response, buf); } } /* Free memory used to store values */ ldap_value_free(vals); } /* Free memory used to store attribute */ ldap_memfree(attribute); ldap_memfree(dn); if (ber != NULL) ber_free(ber, 0); addtobuffer(response, "\n"); } req->ldapstatus = XYMON_LDAP_OK; req->output = grabstrbuffer(response); tvdiff(&starttime, &endtime, &req->duration); ldap_msgfree(result); ldap_unbind(ld); ldap_free_urldesc(ludp); } #endif }