Log In
Log In
Places
All Projects
Status Monitor
Collapse sidebar
zimbra:collaboration:8.7
zimbra-cyrus-sasl
sasl-auth-zimbra-2.1.26.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File sasl-auth-zimbra-2.1.26.patch of Package zimbra-cyrus-sasl
Index: cyrus-sasl-2.1.26/saslauthd/auth_zimbra.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ cyrus-sasl-2.1.26/saslauthd/auth_zimbra.c 2016-01-10 13:31:46.002679956 +0000 @@ -0,0 +1,157 @@ +/* MODULE: auth_zimbra */ + +#include "mechanisms.h" +#include "globals.h" /* mech_option */ +#include "cfile.h" +#include <unistd.h> + +#ifdef AUTH_ZIMBRA + +#include <syslog.h> +#include "auth_zimbra.h" +#include "zmclient.h" + +static cfile config = 0; +static zmpostinfo hti; +static int initialized = 0; +static zmurl_roundrobin_t zmrr; + +int /* R: -1 on failure, else 0 */ +auth_zimbra_init( + /* PARAMETERS */ + void /* no parameters */ + /* END PARAMETERS */ + ) +{ + char *configname = 0; + unsigned int nurls; + int retry_interval; + + if (mech_option) { + configname = mech_option; + } else if (access(SASLAUTHD_CONF_FILE_DEFAULT, F_OK) == 0) { + configname = SASLAUTHD_CONF_FILE_DEFAULT; + } + + if (configname == NULL) { + syslog(LOG_ERR, + "auth_zimbra_init: no config file specificied and %s is not accessible", + SASLAUTHD_CONF_FILE_DEFAULT); + return -1; + } + + + if (!(config = cfile_read(configname, hti.error, sizeof(hti.error)))) { + syslog(LOG_ERR, "auth_zimbra_init: %s", hti.error); + return -1; + } + + /* url has to be set */ + hti.url = cfile_getstring(config, "zimbra_url", NULL); + if (hti.url == NULL) { + syslog(LOG_ERR, "auth_zimbra_init: zimbra_url not set in %s", + configname); + return 0; + } + + /* highly recommended that verifypeer is set */ + hti.certcheck = cfile_getswitch(config, "zimbra_cert_check", 1); + if (hti.certcheck == 0) { + syslog(LOG_WARNING, "auth_zimbra_init: zimbra_cert_check is off!"); + } else { + hti.certfile = cfile_getstring(config, "zimbra_cert_file", NULL); + if (hti.certfile == NULL) { + syslog(LOG_ERR, "auth_zimbra_init: zimbra_cert_file not set"); + return -1; + } + } + + hti.proxy = cfile_getstring(config, "zimbra_proxy", NULL); + + hti.ctimeout = cfile_getint(config, "zimbra_connect_timeout", 15); + if (hti.ctimeout < 0) { + syslog(LOG_ERR, "auth_zimbra_init: invalid zimbra_connect_timeout %d", + hti.ctimeout); + return -1; + } + + hti.timeout = cfile_getint(config, "zimbra_timeout", 45); + if (hti.timeout < 0) { + syslog(LOG_ERR, "auth_zimbra_init: invalid zimbra_timeout %d", + hti.timeout); + return -1; + } + + hti.dump = cfile_getswitch(config, "zimbra_dump_xml", 0); + + retry_interval = cfile_getint(config, "zimbra_retry_interval", 600); + + if (retry_interval < 0) { + syslog(LOG_ERR, "auth_zimbra_init: invalid zimbra_retry_interval %d", + retry_interval); + return -1; + } + + zmrr.retry_interval = (unsigned int) retry_interval; + + if ((nurls = initialize_zmurls (hti.url, &zmrr)) == 0) { + syslog(LOG_ERR, "auth_zimbra_init: zimbra_url='%s' contains no urls", + hti.url); + return -1; + } else { + syslog(LOG_INFO, + "auth_zimbra_init: %d auth urls initialized for round-robin", + nurls); + } + + initialized = 1; + return 0; +} + +char * /* R: allocated response string */ +auth_zimbra( + /* PARAMETERS */ + const char *user, /* I: plaintext authenticator */ + const char *password, /* I: plaintext password */ + const char *service __attribute__((unused)), + const char *realm __attribute__((unused)), + const char *clientip /* I: originating client IP */ + /* END PARAMETERS */ + ) +{ + if (!initialized) { + syslog(LOG_ERR, "auth_zimbra: not initialized"); + return strdup("NO auth_zimbra not initiailzed"); + } + + if (!user || !password) { + syslog(LOG_ERR, "auth_zimbra: NULL password or username?"); + return strdup("NO saslauthd internal NULL password or username"); + } + + if (zmauth(&zmrr, &hti, user, password, clientip)) { + syslog(LOG_INFO, "auth_zimbra: %s auth OK", user); + return strdup("OK"); + } else { + syslog(LOG_INFO, "auth_zimbra: %s auth failed: %s", user, hti.error); + return strdup("NO"); + } +} + +/* Unfortunately, the saslauthd mechanism data structure does not have a free + method, where we can clean-up the resources that were allocated in the + XXX_init method, and so there are bound to be memory leaks here + + so we write a free method in the hope that when the functionality becomes + available, we are ready for it + */ +void auth_zimbra_free () +{ + /* first free up the resources used by the round-robin structure */ + free_zmurls (&zmrr); + + /* next, free up the saslauthd config file data structure */ + if (config) { cfile_free (config); } +} + +#endif /* AUTH_ZIMBRA */ Index: cyrus-sasl-2.1.26/saslauthd/auth_zimbra.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ cyrus-sasl-2.1.26/saslauthd/auth_zimbra.h 2016-01-10 13:31:46.002679956 +0000 @@ -0,0 +1,10 @@ +#ifndef _AUTH_ZIMBRA_H_ +#define _AUTH_ZIMBRA_H_ + +extern char * +auth_zimbra(const char *, const char *, const char *, const char *, const char *); + +extern int +auth_zimbra_init(void); + +#endif /* _AUTH_ZIMBRA_H_ */ Index: cyrus-sasl-2.1.26/saslauthd/Makefile.am =================================================================== --- cyrus-sasl-2.1.26.orig/saslauthd/Makefile.am 2016-01-10 13:31:46.010679955 +0000 +++ cyrus-sasl-2.1.26/saslauthd/Makefile.am 2016-01-10 13:31:46.002679956 +0000 @@ -11,7 +11,9 @@ auth_ldap.c auth_ldap.h cache.c cache.h cfile.c cfile.h \ krbtf.c krbtf.h utils.c utils.h \ ipc_unix.c ipc_doors.c saslauthd-main.c saslauthd-main.h \ - md5.c saslauthd_md5.h md5global.h + md5.c saslauthd_md5.h md5global.h \ + auth_zimbra.h auth_zimbra.c zmpost.c zmclient.h zmauth.c \ + zmurl.h zmurl.c EXTRA_saslauthd_sources = getaddrinfo.c getnameinfo.c saslauthd_DEPENDENCIES = saslauthd-main.o @LTLIBOBJS@ saslauthd_LDADD = @SASL_KRB_LIB@ \ Index: cyrus-sasl-2.1.26/saslauthd/mechanisms.c =================================================================== --- cyrus-sasl-2.1.26.orig/saslauthd/mechanisms.c 2016-01-10 13:31:46.010679955 +0000 +++ cyrus-sasl-2.1.26/saslauthd/mechanisms.c 2016-01-10 13:31:46.002679956 +0000 @@ -60,6 +60,10 @@ #ifdef AUTH_HTTPFORM #include "auth_httpform.h" #endif +#ifdef AUTH_ZIMBRA +#include "auth_zimbra.h" +#endif + /* END PUBLIC DEPENDENCIES */ authmech_t mechanisms[] = @@ -93,6 +97,9 @@ #ifdef AUTH_HTTPFORM { "httpform", auth_httpform_init, auth_httpform }, #endif /* AUTH_LDAP */ +#ifdef AUTH_ZIMBRA + { "zimbra", auth_zimbra_init, auth_zimbra }, +#endif /* AUTH_ZIMBRA */ { 0, 0, 0 } }; Index: cyrus-sasl-2.1.26/saslauthd/zmauth.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ cyrus-sasl-2.1.26/saslauthd/zmauth.c 2016-01-10 13:31:46.002679956 +0000 @@ -0,0 +1,348 @@ +/* + * Do an auth (SOAP) request against a zimbra server. + */ +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#ifdef DARWIN +#include <malloc/malloc.h> +#else +#include <malloc.h> +#endif +#include <stdio.h> + +#include <libxml/tree.h> +#include <libxml/parser.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> +#include <libxml/xmlwriter.h> +#include <syslog.h> + +#include "zmclient.h" +#include "zmurl.h" + +#define ZIMBRA_ACCOUNT_PREFIX "la" +#define ZIMBRA_ACCOUNT_HREF "urn:zimbraAccount" +#define EXPR_AUTH_TOKEN "//la:AuthResponse/la:authToken" + +#define SOAP_PREFIX "soap" +#define SOAP_HREF "http://www.w3.org/2003/05/soap-envelope" +#define EXPR_FAULT_TEXT "//soap:Fault/soap:Reason/soap:Text" + +static int +eprintf(zmpostinfo *hti, const char *fmt, ...) +{ + int result; + va_list ap; + va_start(ap, fmt); + result = vsnprintf(hti->error, sizeof(hti->error), fmt, ap); + va_end(ap); + return result; +} + +static int +auth_parse_response(zmpostinfo *hti, zmbuffer *buffer) +{ + int auth = 0; /* not authenticated */ + xmlNodePtr iter; + xmlDocPtr doc = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlXPathObjectPtr authobj = NULL; + xmlXPathObjectPtr faultobj = NULL; + + doc = xmlReadMemory(buffer->data, buffer->length, "noname.xml", NULL, 0); + + if (doc == NULL) { + eprintf(hti, "unable to parse xml"); + goto leave; + } + + ctxt = xmlXPathNewContext(doc); + if (ctxt == NULL) { + eprintf(hti, "unable to create xpath context"); + goto leave; + } + + if (xmlXPathRegisterNs(ctxt, ZIMBRA_ACCOUNT_PREFIX, ZIMBRA_ACCOUNT_HREF) != 0) { + eprintf(hti, "unable to register namespace prefix='%s' href='%s'", + ZIMBRA_ACCOUNT_PREFIX, ZIMBRA_ACCOUNT_HREF); + goto leave; + } + + if (xmlXPathRegisterNs(ctxt, SOAP_PREFIX, SOAP_HREF) != 0) { + eprintf(hti, "unable to register namespace prefix='%s' href='%s'", + SOAP_PREFIX, SOAP_HREF); + goto leave; + } + + authobj = xmlXPathEvalExpression(EXPR_AUTH_TOKEN, ctxt); + if (authobj == NULL) { + eprintf(hti, "unable to evaluate expression %s", + EXPR_AUTH_TOKEN); + goto leave; + } + + if (authobj->nodesetval != NULL && authobj->nodesetval->nodeNr == 1) { + /* authenticated! */ + auth = 1; + goto leave; + } + + /* find the fault code for logging */ + faultobj = xmlXPathEvalExpression(EXPR_FAULT_TEXT, ctxt); + if (faultobj == NULL) { + eprintf(hti, "unable to evaluate expression %s", EXPR_FAULT_TEXT); + goto leave; + } + + if (faultobj->nodesetval == NULL) { + eprintf(hti, "no authtoken and no soap fault text in document"); + goto leave; + } + + if (faultobj->nodesetval->nodeNr != 1) { + eprintf(hti, "unexpected nodeNr=%d for expression %s", + faultobj->nodesetval->nodeNr, EXPR_FAULT_TEXT); + goto leave; + } + + /* find the error message... is there an straight xpath expr for this? */ + eprintf(hti, "unknown error"); + iter = faultobj->nodesetval->nodeTab[0]->children; + while (iter != NULL) { + if (iter->type == XML_TEXT_NODE && iter->content != NULL) { + eprintf(hti, "%s", iter->content); + break; + } + iter = iter->next; + } + + leave: + if (authobj) { + xmlXPathFreeObject(authobj); + } + if (faultobj) { + xmlXPathFreeObject(faultobj); + } + if (ctxt) { + xmlXPathFreeContext(ctxt); + } + if (doc) { + xmlFreeDoc(doc); + } + return auth; +} + +#define NULLCHK(e) if ((e) == NULL) { goto error; } + +static xmlNodePtr +new_soap_request(const char *requestName, const char *requestNs) +{ + xmlDocPtr doc; + xmlNodePtr envelope, header, context, body, request; + + NULLCHK(doc = xmlNewDoc(NULL)); + + NULLCHK(envelope = xmlNewNode(NULL, "soap:Envelope")); + xmlDocSetRootElement(doc, envelope); + NULLCHK(xmlNewNs(envelope, SOAP_HREF, SOAP_PREFIX)); + + NULLCHK(header = xmlNewChild(envelope, NULL, "soap:Header", NULL)); + NULLCHK(context = xmlNewChild(header, NULL, "context", NULL)); + NULLCHK(xmlNewProp(context, "xmlns", "urn:zimbra")); + NULLCHK(xmlNewChild(context, NULL, "nosession", NULL)); + + NULLCHK(body = xmlNewChild(envelope, NULL, "soap:Body", NULL)); + NULLCHK(request = xmlNewChild(body, NULL, requestName, NULL)); + NULLCHK(xmlNewProp(request, "xmlns", requestNs)); + + return request; + + error: + if (doc != NULL) { + xmlFreeDoc(doc); + } + return NULL; +} + +static char * +auth_build_request(zmpostinfo *hti, const char *user, const char *password, int *resultSize) +{ + xmlDocPtr doc = NULL; + xmlNodePtr account = NULL; + xmlNodePtr request = NULL; + xmlChar *result = NULL; + + request = new_soap_request("AuthRequest", ZIMBRA_ACCOUNT_HREF); + if (request == NULL) { + eprintf(hti, "could not create request XML document"); + goto error; + } + doc = request->doc; + + account = xmlNewTextChild(request, NULL, "account", user); + if (account == NULL) { + eprintf(hti, "could not create account node"); + goto error; + } + + if (xmlNewProp(account, "by", "name") == NULL) { + eprintf(hti, "could not add lookup type to document"); + goto error; + } + + if (xmlNewTextChild(request, NULL, "password", password) == NULL) { + eprintf(hti, "could not add password to document"); + goto error; + } + + xmlDocDumpFormatMemory(doc, &result, resultSize, 1); + + // fall thru... + + error: + if (doc != NULL) { + xmlFreeDoc(doc); + } + + return (char *)result; +} + +static int checked_libxml_version = 0; + +int +zmauth(zmurl_roundrobin_t *zmrr, zmpostinfo *hti, const char *user, const char *password, const char *clientipport) +{ + int auth = 0; /* not authenticated */ + + int bodysize = 0; + char *body = NULL; + zmbuffer *buffer = NULL; + zmurl_t *u, *s; + + if (checked_libxml_version == 0) { + LIBXML_TEST_VERSION; + checked_libxml_version = 1; + } + + body = auth_build_request(hti, user, password, &bodysize); + if (body == NULL) { + eprintf(hti, "request body generation failed"); + goto leave; + } + + s = NULL; + buffer = NULL; + + u = elect_zmurl (zmrr); + + /* zimbra round-robin loop begins here */ + while ((u != NULL) && (buffer == NULL)) + { + if (u == s) { + /* `s' was the url that we first elected, and + we have run the circle round, but the flaw in the plan is that + we need to rewind the good pointer back one step, otherwise it + is possible that we keep missing out one url + */ + syslog (LOG_INFO, + "Authentication cycle re-elected url %s, giving up ...", + u->url); + reelect_zmurl (u, zmrr); + break; + } + + /* here's where we keep track of our starting point `s', in order + that we do not loop infinitely + */ + if (!s) { s = u; } + + hti->url = u->url; + + syslog (LOG_INFO, "zmauth: authenticating against elected url '%s' ...", + hti->url); + + /* perform the http auth request to the elected url */ + buffer = zmpost(hti, body, bodysize, clientipport); + + if (buffer == NULL) { + /* there was an error in zmpost, so we need to re-elect */ + discard_zmurl (u, zmrr); + + syslog (LOG_WARNING, + "authentication against url '%s' caused error '%s'", + hti->url, hti->error); + + syslog (LOG_WARNING, + "url '%s' will not be used for (at least) %d seconds", + hti->url, zmrr->retry_interval); + + u = elect_zmurl (zmrr); + } else { + syslog (LOG_DEBUG, + "zmpost: url='%s' returned buffer->data='%s', hti->error='%s'", + hti->url, buffer->data, hti->error); + } + } + + if (buffer == NULL) { + /* error already written */ + goto leave; + } + + auth = auth_parse_response(hti, buffer); + + leave: + if (body) { + xmlFree(body); + } + if (buffer) { + zmbuffer_free(buffer); + } + + return auth; +} + +#ifdef ZMAUTH_TEST_MAIN + +int +main(int argc, char *argv[]) +{ + zmpostinfo hti; + zmurl_roundrobin_t zmrr; + const char *url; + const char *certfile; + const char *username; + const char *password; + + if (argc != 5) { + printf("Usage: zmauth url certfile username password\n"); + return 1; + } + + url = argv[1]; + certfile = argv[2]; + username = argv[3]; + password = argv[4]; + + initialize_zmurls (url, &zmrr); + + memset(&hti, 0, sizeof(hti)); + hti.ctimeout = ZMPOST_DEFAULT_CONNECT_TIMEOUT; + hti.timeout = ZMPOST_DEFAULT_TIMEOUT; + hti.url = url; + hti.certfile = certfile; + hti.dump = 1; + + if (zmauth(&zmrr, &hti, username, password)) { + printf("Auth: OK\n"); + } else { + printf("Auth: failed: %s\n", hti.error); + } + + xmlCleanupParser(); + free_zmurls (&zmrr); + + return 0; +} +#endif /* ZMAUTH_TEST_MAIN */ Index: cyrus-sasl-2.1.26/saslauthd/zmclient.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ cyrus-sasl-2.1.26/saslauthd/zmclient.h 2016-01-10 13:31:46.002679956 +0000 @@ -0,0 +1,66 @@ +#ifndef _ZMCLIENT_H_ +#define _ZMCLIENT_H_ + +#include "zmurl.h" + +/* + * Buffer to contain the return data of a post + */ + +typedef struct { + int length; + int capacity; + char *data; +} zmbuffer; + +extern zmbuffer * +zmbuffer_new(int initial_size); + +extern int +zmbuffer_append(zmbuffer *buffer, const char *data, int nb); + +extern void +zmbuffer_free(zmbuffer *buffer); + + +/* + * HTTP post + */ + +#define ZMPOST_URL_MAX 256 +#define ZMPOST_ERR_MAX 256 + +#define ZMPOST_DEFAULT_CONNECT_TIMEOUT 15 +#define ZMPOST_DEFAULT_TIMEOUT 45 + +#define ZMPOST_CLIENTIP_MAX 128 +#define ZMPOST_CLIENTPORT_MAX 128 + +typedef struct { + /* curl configuration */ + const char *url; + + const char *certfile; + int certcheck; + + const char *proxy; + int ctimeout; + int timeout; + + int dump; + + /* place to store error msgs */ + char error[ZMPOST_ERR_MAX]; +} zmpostinfo; + +extern zmbuffer * +zmpost(zmpostinfo *hti, const char *body, int bodylen, const char *clientipport); + + +/* + * Auth, returns non-zero on successful auth. + */ +extern int +zmauth(zmurl_roundrobin_t *zmrr, zmpostinfo *hti, const char *user, const char *password, const char *clientipport); + +#endif /* _ZMCLIENT_H_ */ Index: cyrus-sasl-2.1.26/saslauthd/zmpost.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ cyrus-sasl-2.1.26/saslauthd/zmpost.c 2016-01-10 13:31:46.022679955 +0000 @@ -0,0 +1,264 @@ +#include <curl/curl.h> +#include <curl/easy.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "zmclient.h" + +static size_t +post_gather(void *data, size_t size, size_t nmemb, zmbuffer *buffer) +{ + return zmbuffer_append(buffer, (char*)data, (int)(size * nmemb)); +} + +zmbuffer * +zmpost(zmpostinfo *hti, const char *body, int bodylen, const char *clientipport) +{ + CURL *curl = NULL; + CURLcode code; + struct curl_slist *headers = NULL; + zmbuffer *buffer = NULL; + char ebuf[CURL_ERROR_SIZE+1]; + char headerbuf[CURL_MAX_HTTP_HEADER+1]; + char clientip[ZMPOST_CLIENTIP_MAX+1]; + char clientport[ZMPOST_CLIENTPORT_MAX+1]; + char *semicolon; + + if(clientipport) { + semicolon = strchr(clientipport, ';'); + if (semicolon) { + strncpy(clientip, clientipport, semicolon - clientipport); + clientip[semicolon - clientipport] = '\0'; + strcpy(clientport, semicolon + 1); + } + else { + strcpy(clientip, clientipport); + strcpy(clientport, "unknown"); + } + } + else { + strcpy(clientip, "unknown"); + strcpy(clientport, "unknown"); + } + if (strlen(clientip) == 0) + strcpy(clientip, "unknown"); + if (strlen(clientport) == 0) + strcpy(clientport, "unknown"); + + + if (bodylen == 0) { + bodylen = strlen(body); + } + + buffer = zmbuffer_new(1024); + if (buffer == NULL) { + snprintf(hti->error, sizeof(hti->error), "zmbuffer_new failed"); + goto error; + } + + curl = curl_easy_init(); + if (curl == NULL) { + snprintf(hti->error, sizeof(hti->error), "curl_easy_init failed"); + goto error; + } + + if (hti->url == NULL) { + snprintf(hti->error, sizeof(hti->error), "url is NULL"); + goto error; + } + + curl_easy_setopt(curl, CURLOPT_URL, hti->url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, hti->ctimeout); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, hti->timeout); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, ebuf); + + if (hti->proxy != NULL) { + curl_easy_setopt(curl, CURLOPT_PROXY, hti->proxy); + } + + if (hti->certfile != NULL) { + curl_easy_setopt(curl, CURLOPT_CAINFO, hti->certfile); + } + + if (hti->certcheck == 0) { + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + fprintf(stderr, "zmpost: cert checking is off - " + "should only be done during test/development\n"); + } + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, post_gather); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer); + + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, bodylen); + + headers = curl_slist_append(headers, "Content-Type: text/xml"); + headers = curl_slist_append(headers, "X-Forwarded-Proto: smtp"); + snprintf(headerbuf, CURL_MAX_HTTP_HEADER, "X-Forwarded-For: %s", clientip); + headers = curl_slist_append(headers, headerbuf); + snprintf(headerbuf, CURL_MAX_HTTP_HEADER, "X-Forwarded-Port: %s", clientport); + headers = curl_slist_append(headers, headerbuf); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + ebuf[0] = '\0'; + + if (hti->dump) { + printf("request to %s {\n", hti->url); + fwrite(body, 1, bodylen, stdout); + printf("}\n"); + fflush(stdout); + } + + /* do it */ + code = curl_easy_perform(curl); + + curl_slist_free_all(headers); /* free the header list */ + + if (code != CURLE_OK) { + snprintf(hti->error, sizeof(hti->error), + "curl_easy_perform: error(%d): %s", code, ebuf); + goto error; + } else { + hti->error[0] = '\0'; + } + + if (hti->dump) { + printf("response from %s {\n", hti->url); + fwrite(buffer->data, 1, buffer->length, stdout); + printf("}\n"); + fflush(stdout); + } + + if (curl) { + curl_easy_cleanup(curl); + } + return buffer; + + error: + if (curl) { + curl_easy_cleanup(curl); + } + if (buffer) { + zmbuffer_free(buffer); + } + return NULL; +} + +/* + * zmbuffer + */ +zmbuffer * +zmbuffer_new(int initial_size) +{ + zmbuffer *buffer = (zmbuffer *) calloc(1, sizeof(zmbuffer)); + if (buffer == NULL) { + return NULL; + } + + buffer->data = (char *) calloc(1, initial_size); + if (buffer->data == NULL) { + return NULL; + } + + buffer->capacity = initial_size; + buffer->length = 0; + return buffer; +} + +int +zmbuffer_append(zmbuffer *buffer, const char *data, int nb) +{ + if (nb < 0) { + return 0; + } + + if ((buffer->length + nb) > buffer->capacity) { + int newcap; + + /* try to double the capacity */ + newcap = buffer->capacity * 2; + + /* but if doubling is still not enough for new bytes, then grow by + new bytes this time */ + if ((buffer->length + nb) > newcap) { + newcap = buffer->capacity + nb; + } + + buffer->data = (char *) realloc(buffer->data, newcap); + if (buffer->data == NULL) { + return 0; + } + buffer->capacity = newcap; + + /* zero out whatever we won't be writing */ + memset(buffer->data + buffer->length + nb, 0, + (buffer->capacity - buffer->length - nb)); + } + + memcpy(buffer->data + buffer->length, data, nb); + buffer->length = buffer->length + nb; + + return nb; +} + + +void +zmbuffer_free(zmbuffer *buffer) +{ + if (buffer != NULL) { + if (buffer->data != NULL) { + free(buffer->data); + } + free(buffer); + } +} + +#ifdef ZMPOST_TEST_MAIN + +#include <stdio.h> + +static void +test(int iter) +{ + int i; + long long sum; + float calculated; + zmbuffer *buffer = zmbuffer_new(1024); + + const int xlen = 127; + char x[xlen]; + for (i = 0; i < xlen; i++) { + x[i] = i + 1; + } + + for (i = 0; i < iter; i++) { + zmbuffer_append(buffer, x, xlen); + } + + calculated = iter * (xlen+1) * ((float)xlen/2); + + sum = 0; + for (i = 0; i < buffer->length; i++) { + sum += (int)(buffer->data[i]); + } + + printf("%d blen=%d bcap=%d calc=%f sum=%lld\n", iter, buffer->length, + buffer->capacity, calculated, sum); + + zmbuffer_free(buffer); +} + +int main() +{ + int i = 0; + for (i = 0; i < 2028; i++) { + test(i); + } + return 0; +} + +#endif /* ZMPOST_TEST_MAIN */ Index: cyrus-sasl-2.1.26/saslauthd/zmurl.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ cyrus-sasl-2.1.26/saslauthd/zmurl.c 2016-01-10 13:31:46.002679956 +0000 @@ -0,0 +1,305 @@ +#include "zmurl.h" +#include <stdlib.h> +#include <string.h> + +static void free_zmurl (zmurl_t *u); + +/* reads in a whitespace seprated list of urls, and initializes a round-robin + structure for use with authentication + */ +unsigned int initialize_zmurls (const char *urls, zmurl_roundrobin_t *zmrr) +{ + char *c; + zmurl_t *u; + unsigned int nurls; + + /* zero out the round-robin structure to begin with */ + zmrr->urls = NULL; + zmrr->good = NULL; + zmrr->bad = NULL; + nurls = 0; + + c = strdup (urls); + if (!c) { goto out; } + + zmrr->urls = c; + while (*c) { + while (*c && isspace (*c)) { ++c; } + if (!*c) { break; } + + u = malloc (sizeof (zmurl_t)); + if (!u) { break; } + + u->url = c; + u->when_bad = 0; + u->prev = NULL; + u->next = NULL; + + if (!zmrr->good) { + /* this is the first url */ + u->prev = u; + u->next = u; + zmrr->good = u; + } else { + /* we need to add the url to the end of the `good' list */ + u->next = zmrr->good; + u->prev = zmrr->good->prev; + zmrr->good->prev->next = u; + zmrr->good->prev = u; + } + + ++nurls; + + while (*c && !isspace (*c)) { ++c; } + if (*c) { *c = 0; ++c; } + } + +out: + return nurls; +} + +/* elects a url + + there are a few distinct possibilities here, depending on the state of + the good and the bad lists + + - the good list has members but the bad list is empty + in this case, we just elect the url at the head of the good list, and + move the head (rr::good) to the next in the list + + - the good list has members and the bad list has members + in this case, we examine the eldest of the bad list members (the eldest + is the one that's spent the most time on the bad list) - we don't need + to iterate over the bad list to find the eldest, we already know that + the head of the bad list is the eldest - so we examine the head of the + bad list (rr::bad), see if it has spent enough time on the bad list + (as defined by rr::retry_interval) - if it has, then we remove it from + the bad list, and move the head of the bad list (rr::bad) to the next + (or null if the bad list is now empty) + + but if the eldest in the bad list hasn't been bad for long enough, then + we don't remove it from the bad list, because we already have some + entries in the good list for the authentication request to proceed + + conversely, it may happen that more than one entry on the bad list has + been bad for a long enough time. even so, we do not iterate over the + bad list, moving the entries onto the end of the good list. rather, we + just pick out the eldest bad entry, and go along with that -- this is + actually more time-efficient, because the next call to this elect + function will cause the next in line on the bad list to be examined for + agedness -- meanwhile, if the next-eldest url has been bad for a long + enough time, but the url itself hasn't yet recovered, then the time delta + between this and the next call to elect() can serve as a grace period + for the url to recover (if it hasn't done so already) + + - the good list is empty and the bad list has members + in this case, we must remove the eldest from the bad list, even if it + is not old enough, because we don't have any urls in the good list to be + getting along with + + so we move the eldest (which is also the first) member out of the bad + list, and put it onto the good list, and since the good list was initially + empty, therefore this eldest bad entry is now the head (rr::good) as well + as the only member on the good list + + this is really the most severe of all the cases, because there are no + good urls to begin with, and if the bad urls are still unreachable, + then the higher level authentication function will repeatedly elect, + and so the successively-eldest bad url will keep getting elected, and + subsequently discarded, by the authentication function + + the higher level loop will need to avoid looping infinitely by + remembering the first url that was elected, so that when the same + url is re-elected (by the loop described above), then it can break out + + - the good list is empty and the bad list is empty + uhh -- this cannot ever happen (it's a config error that gets caught + at initialization) + + */ +zmurl_t *elect_zmurl (zmurl_roundrobin_t *zmrr) +{ + zmurl_t *elected, *y; + + elected = NULL; + + /* first walk the list of bad urls to see if they can be marked good */ + + if (zmrr->bad) + { + /* first, elect a candidate from the bad to put onto the good + `y' is the url elect -- also the eldest (see notes above) + */ + y = zmrr->bad; + + /* y has been selected from the bad guys */ + + if (!zmrr->good) + { + /* we're out of good urls, so we'll have to use the url that + was elected from the bad list, regardless of how long that + url has been bad + */ + + /* first move along the head of the bad list, and if necessary, + null it + */ + if ((zmrr->bad->next == zmrr->bad) && + (zmrr->bad->prev == zmrr->bad) + ) + { + zmrr->bad = NULL; + } + else { + zmrr->bad = zmrr->bad->next; + } + + zmrr->good = y; + zmrr->good->next = zmrr->good; + zmrr->good->prev = zmrr->good; + } + else + { + /* we still have some good urls, so we only need to see if + y matches the criterion for becoming good */ + + if (difftime(y->when_bad,time(NULL)) >= + (double)zmrr->retry_interval) + { + /* `y' has been bad for a while, let's pull it back in */ + y->when_bad = (time_t) 0; /* it's on the good list now */ + + /* clear the bad list if necessary */ + + if ((y->next == y) && (y->prev == y) && (y == zmrr->bad)) { + /* bad list had only one entry, so blank it out */ + zmrr->bad = NULL; + } else { + /* the head of the bad list needs to advance */ + zmrr->bad = zmrr->bad->next; + } + + /* add `y' right to the end of the good list */ + y->next = zmrr->good; + y->prev = zmrr->good->prev; + zmrr->good->prev->next = y; + zmrr->good->prev = y; + } + } + } + + /* the good list *must* have at least one entry now */ + + if (zmrr->good) { + elected = zmrr->good; + zmrr->good = zmrr->good->next; + } + + /* ... otherwise there's nothing to do, and elected is null */ + + return elected; +} + +/* this method is invoked in the extreme case when a url is re-elected after + completing the entire set of urls -- in this case we have to reconsider + the previously elected url, because otherwise we will miss out one url + all the time + */ +void reelect_zmurl (zmurl_t *u /* unused */, zmurl_roundrobin_t *zmrr) +{ + if (zmrr->good) { + zmrr->good = zmrr->good->prev; + } +} + +/* discards a url by moving it to the bad list + + it is assumed that `u' is on the good list + `u' is removed from the good list (and `good' is set to null if `u' was + the last (and only) member of the good list) + `u' is then placed at the end of the bad list, and conversely, if the bad + list was empty to begin with, then `bad' is set to `u' + */ +void discard_zmurl (zmurl_t *u, zmurl_roundrobin_t *zmrr) +{ + /* step 1 -- remove `u' from the good list */ + if ((zmrr->good) && + (zmrr->good == u) && + (zmrr->good->next == zmrr->good) && + (zmrr->good->prev == zmrr->good) + ) + { + /* `u' is at the head of, and the only member in the good list */ + zmrr->good = NULL; + } + else { + /* `u' belongs somewhere in the good list */ + + /* first advance the head of the good list if necessary */ + if (zmrr->good == u) { + zmrr->good = zmrr->good->next; + } + + /* now break the link */ + u->prev->next = u->next; + u->next->prev = u->prev; + u->prev = NULL; + u->next = NULL; + } + + /* step 2 -- mark the time when `u' went bad (which is now) */ + u->when_bad = time(NULL); + + /* step 3 -- add `u' to the end of the bad list + */ + if (!zmrr->bad) { + /* there are no urls in the bad list, so this will be the first */ + u->next = u; + u->prev = u; + zmrr->bad = u; + } else { + /* there is at least one url on the bad list, so add `u' at the end */ + u->next = zmrr->bad; + u->prev = zmrr->bad->prev; + zmrr->bad->prev->next = u; + zmrr->bad->prev = u; + } + + return; +} + +/* free the memory used by the zimbra url round-robin structure + this function first breaks the circular lists headed by the `good' and the + `bad' data members, and then recursively frees the lists + + the memory pointed to by zmrr itself is not freed (which is why we + re-initialize the `good', `bad', and the `urls' members back to null) + */ +void free_zmurls (zmurl_roundrobin_t *zmrr) +{ + if (zmrr->good) { + zmrr->good->prev->next = NULL; + free_zmurl (zmrr->good); + zmrr->good = NULL; + } + if (zmrr->bad) { + zmrr->bad->prev->next = NULL; + free_zmurl (zmrr->bad); + zmrr->bad = NULL; + } + + if (zmrr->urls) { + free (zmrr->urls); + zmrr->urls = NULL; + } +} + +static void free_zmurl (zmurl_t *u) +{ + if (!u) { return; } + else { + free_zmurl (u->next); + free (u); + } +} + Index: cyrus-sasl-2.1.26/saslauthd/zmurl.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ cyrus-sasl-2.1.26/saslauthd/zmurl.h 2016-01-10 13:31:46.006679956 +0000 @@ -0,0 +1,30 @@ +#if !defined(_ZMURL_H) +#define _ZMURL_H + +#include <time.h> + +struct zmurl_s { + const char *url; + time_t when_bad; + struct zmurl_s *prev; + struct zmurl_s *next; +}; + +struct zmurl_roundrobin_s { + const char *urls; + unsigned int retry_interval; + struct zmurl_s *good; + struct zmurl_s *bad; +}; + +typedef struct zmurl_s zmurl_t; +typedef struct zmurl_roundrobin_s zmurl_roundrobin_t; + +unsigned int initialize_zmurls (const char *urls, zmurl_roundrobin_t *zmrr); +zmurl_t *elect_zmurl (zmurl_roundrobin_t *zmrr); +void reelect_zmurl (zmurl_t *u /* unused */, zmurl_roundrobin_t *zmrr); +void discard_zmurl (zmurl_t *u, zmurl_roundrobin_t *zmrr); +void free_zmurls (zmurl_roundrobin_t *zmrr); + +#endif + Index: cyrus-sasl-2.1.26/cmulocal/curl.m4 =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ cyrus-sasl-2.1.26/cmulocal/curl.m4 2016-01-10 13:31:46.006679956 +0000 @@ -0,0 +1,46 @@ +dnl +dnl macros for configure.in to detect curl +dnl $Id: curl.m4,v 1.11 2006/05/17 18:30:19 murch Exp $ +dnl + +AC_DEFUN([CMU_HAVE_CURL], [ +AC_REQUIRE([CMU_FIND_LIB_SUBDIR]) +AC_ARG_WITH(libcurl,[ --with-libcurl=PATH use Curl from PATH], + with_curl=$withval, with_curl="yes") + + save_CPPFLAGS=$CPPFLAGS + save_LDFLAGS=$LDFLAGS + save_LIBS=$LIBS + + if test -d $with_curl; then + CPPFLAGS="${CPPFLAGS} -I${with_curl}/include" + CMU_ADD_LIBPATH(${with_curl}/$CMU_LIB_SUBDIR) + fi + if test -d $gssapi; then + CMU_ADD_LIBPATH(${gssapi}/$CMU_LIB_SUBDIR) + fi + +case "$with_curl" in + no) + with_curl="no";; + *) + dnl if curl has been compiled with the rsaref2 libraries, + dnl we need to include the rsaref libraries in the crypto check + LIB_CURL="-lcurl" + AC_CHECK_HEADER(curl/curl.h, [ + AC_CHECK_LIB(curl, curl_easy_getinfo, + with_curl="yes", + with_curl="no", $LIB_CURL)], + with_curl=no) + LIBS="$LIBS $LIB_CURL" + ;; +esac + + if test "$with_curl" != "no"; then + AC_DEFINE(HAVE_CURL,[],[Do we have Curl?]) + else + CPPFLAGS=$save_CPPFLAGS + LDFLAGS=$save_LDFLAGS + LIBS=$save_LIBS + fi +]) Index: cyrus-sasl-2.1.26/saslauthd/configure.in =================================================================== --- cyrus-sasl-2.1.26.orig/saslauthd/configure.in 2016-01-10 13:31:46.010679955 +0000 +++ cyrus-sasl-2.1.26/saslauthd/configure.in 2016-01-10 13:31:46.006679956 +0000 @@ -50,6 +50,10 @@ AC_DEFINE(HAVE_GSSAPI,[],[Include GSSAPI/Kerberos 5 Support]) fi +CMU_HAVE_CURL +AC_MSG_CHECKING(for Curl) +AC_MSG_RESULT($with_curl) + SASL2_CRYPT_CHK AC_ARG_ENABLE(sia, [ --enable-sia enable SIA authentication [no] ], @@ -87,6 +91,24 @@ AC_DEFINE(HAVE_HTTPFORM,[],[Include HTTP form Support]) fi +AC_ARG_WITH(libxml2, [ --with-libxml2=PROG script for libxml2 config [xml2-config] ], + with_libxml2=$withval, + with_libxml2=xml2-config) +AC_ARG_ENABLE(zimbra, [ --enable-zimbra enable Zimbra authentication module [yes] ], + authzimbra=$enableval, + authzimbra=yes) +if test "$authzimbra" != no; then + if test -z "$with_libxml2"; then + AC_ERROR([Zimbra authentication requires libxml2]) + fi + if test -z "$with_curl"; then + AC_ERROR([Zimbra authentication requires libcurl]) + fi + AC_DEFINE(AUTH_ZIMBRA,[],[Include Zimbra Authentication Support]) + LIBS="$LIBS `$with_libxml2 --libs`" + CPPFLAGS="$CPPFLAGS `$with_libxml2 --cflags`" +fi + AC_ARG_WITH(pam, [ --with-pam=DIR use PAM (rooted in DIR) [yes] ], with_pam=$withval, with_pam=yes) Index: cyrus-sasl-2.1.26/lib/checkpw.c =================================================================== --- cyrus-sasl-2.1.26.orig/lib/checkpw.c 2016-01-10 13:31:46.010679955 +0000 +++ cyrus-sasl-2.1.26/lib/checkpw.c 2016-01-10 13:31:46.006679956 +0000 @@ -654,9 +654,17 @@ char pwpath[sizeof(srvaddr.sun_path)]; const char *p = NULL; char *freeme = NULL; + const char *clientipport = NULL; #ifdef USE_DOORS door_arg_t arg; #endif + if(sasl_getprop(conn, SASL_IPREMOTEPORT, (const void **)&clientipport) != SASL_OK) { + _sasl_log(conn, SASL_LOG_WARN, "unabled to retrieve SASL_IPREMOTEPORT from conn"); + clientipport="unknown;unknown"; + } + + _sasl_log(conn, SASL_LOG_DEBUG, "saslauthd_verify_password: userid=%s, passwd=%s, service=%s, user_realm=%s, clientipport=%s", + userid, passwd, service, user_realm, clientipport); /* check to see if the user configured a rundir */ if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context) == SASL_OK) { @@ -691,15 +699,16 @@ * count authid count password count service count realm */ { - unsigned short max_len, req_len, u_len, p_len, s_len, r_len; - + unsigned short max_len, req_len, u_len, p_len, s_len, r_len, i_len; + max_len = (unsigned short) sizeof(query); /* prevent buffer overflow */ if ((strlen(userid) > USHRT_MAX) || (strlen(passwd) > USHRT_MAX) || (strlen(service) > USHRT_MAX) || - (user_realm && (strlen(user_realm) > USHRT_MAX))) { + (user_realm && (strlen(user_realm) > USHRT_MAX)) || + (strlen(clientipport) > USHRT_MAX)) { goto toobig; } @@ -707,6 +716,7 @@ p_len = (strlen(passwd)); s_len = (strlen(service)); r_len = ((user_realm ? strlen(user_realm) : 0)); + i_len = (strlen(clientipport)); /* prevent buffer overflow */ req_len = 30; @@ -717,11 +727,14 @@ if (max_len - req_len < s_len) goto toobig; req_len += s_len; if (max_len - req_len < r_len) goto toobig; + req_len += r_len; + if (max_len - req_len < i_len) goto toobig; u_len = htons(u_len); p_len = htons(p_len); s_len = htons(s_len); r_len = htons(r_len); + i_len = htons(i_len); memcpy(query_end, &u_len, sizeof(unsigned short)); query_end += sizeof(unsigned short); @@ -738,6 +751,10 @@ memcpy(query_end, &r_len, sizeof(unsigned short)); query_end += sizeof(unsigned short); if (user_realm) while (*user_realm) *query_end++ = *user_realm++; + + memcpy(query_end, &i_len, sizeof(unsigned short)); + query_end += sizeof(unsigned short); + while (*clientipport) *query_end++ = *clientipport++; } #ifdef USE_DOORS Index: cyrus-sasl-2.1.26/saslauthd/ipc_unix.c =================================================================== --- cyrus-sasl-2.1.26.orig/saslauthd/ipc_unix.c 2016-01-10 13:31:46.010679955 +0000 +++ cyrus-sasl-2.1.26/saslauthd/ipc_unix.c 2016-01-10 13:31:46.006679956 +0000 @@ -329,11 +329,14 @@ char password[MAX_REQ_LEN + 1]; /* password for authentication */ char service[MAX_REQ_LEN + 1]; /* service name for authentication */ char realm[MAX_REQ_LEN + 1]; /* user realm for authentication */ + /* originating client IP;PORT for auth */ + char clientipport[MAX_REQ_LEN + 1]; /************************************************************** * The input data stream consists of the login id, password, - * service name and user realm as counted length strings. + * service name, user realm and (optionally) a clientipport of + * the form ip;port as counted length strings. * We read in each string, then dispatch the data. **************************************************************/ @@ -405,6 +408,28 @@ realm[count] = '\0'; + /* optional clientipport */ + if (rx_avail(conn_fd, 2 /* ms */) == 1) { + if (rx_rec(conn_fd, (void *)&count, (size_t)sizeof(count)) != (ssize_t)sizeof(count)) + return; + + count = ntohs(count); + + if (count > MAX_REQ_LEN) { + logger(L_ERR, L_FUNC, "clientipport exceeded MAX_REQ_LEN: %d", MAX_REQ_LEN); + send_no(conn_fd, ""); + return; + } + + if (rx_rec(conn_fd, (void *)clientipport, (size_t)count) != (ssize_t)count) + return; + + clientipport[count] = '\0'; + } + else { + strcpy(clientipport, "unknown;unknown"); + } + /************************************************************** * We don't allow NULL passwords or login names **************************************************************/ @@ -423,7 +448,7 @@ /************************************************************** * Get the mechanism response from do_auth() and send it back. **************************************************************/ - response = do_auth(login, password, service, realm); + response = do_auth(login, password, service, realm, clientipport); memset(password, 0, strlen(password)); Index: cyrus-sasl-2.1.26/saslauthd/saslauthd-main.c =================================================================== --- cyrus-sasl-2.1.26.orig/saslauthd/saslauthd-main.c 2016-01-10 13:31:46.010679955 +0000 +++ cyrus-sasl-2.1.26/saslauthd/saslauthd-main.c 2016-01-10 13:31:46.006679956 +0000 @@ -378,7 +378,7 @@ * return a pointer to a string to send back to the client. * The caller is responsible for freeing the pointer. **************************************************************/ -char *do_auth(const char *_login, const char *password, const char *service, const char *realm) { +char *do_auth(const char *_login, const char *password, const char *service, const char *realm, const char *clientip) { struct cache_result lkup_result; char *response; @@ -407,7 +407,7 @@ response = strdup("OK"); cached = 1; } else { - response = auth_mech->authenticate(login, password, service, realm); + response = auth_mech->authenticate(login, password, service, realm, clientip); if (response == NULL) { logger(L_ERR, L_FUNC, "internal mechanism failure: %s", auth_mech->name); Index: cyrus-sasl-2.1.26/saslauthd/saslauthd-main.h =================================================================== --- cyrus-sasl-2.1.26.orig/saslauthd/saslauthd-main.h 2016-01-10 13:31:46.010679955 +0000 +++ cyrus-sasl-2.1.26/saslauthd/saslauthd-main.h 2016-01-10 13:31:46.006679956 +0000 @@ -88,7 +88,8 @@ /* saslauthd-main.c */ extern char *do_auth(const char *, const char *, - const char *, const char *); + const char *, const char *, + const char *); extern void set_auth_mech(const char *); extern void set_max_procs(const char *); extern void set_mech_option(const char *); Index: cyrus-sasl-2.1.26/saslauthd/mechanisms.h =================================================================== --- cyrus-sasl-2.1.26.orig/saslauthd/mechanisms.h 2016-01-10 13:31:46.010679955 +0000 +++ cyrus-sasl-2.1.26/saslauthd/mechanisms.h 2016-01-10 13:31:46.006679956 +0000 @@ -40,8 +40,8 @@ char *name; /* name of the mechanism */ int (*initialize)(void); /* initialization function */ char *(*authenticate)(const char *, const char *, - const char *, const char *); /* authentication - function */ + const char *, const char *, + const char *);/* authentication function */ } authmech_t; extern authmech_t mechanisms[]; /* array of supported auth mechs */ Index: cyrus-sasl-2.1.26/saslauthd/utils.c =================================================================== --- cyrus-sasl-2.1.26.orig/saslauthd/utils.c 2016-01-10 13:31:46.010679955 +0000 +++ cyrus-sasl-2.1.26/saslauthd/utils.c 2016-01-10 13:31:46.006679956 +0000 @@ -45,6 +45,7 @@ #include <stdio.h> #include <string.h> #include <errno.h> +#include <sys/select.h> #include <sys/types.h> #include <unistd.h> @@ -227,6 +228,26 @@ } } +/************************************************************** + * I/O wrapper to attempt to check for available data in the + * socket. + * Returns: + * -1 if error + * 0 if timeout + * 1 if data available + **************************************************************/ +int rx_avail(int filefd, int timeoutms) { + fd_set input; + FD_ZERO(&input); + FD_SET(filefd, &input); + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = timeoutms * 1000; + /* we do not need to FD_ISSET(filefd, &input) since there + is only one file descriptor involved. */ + return select(filefd + 1, &input, NULL, NULL, &timeout); +} + #ifndef HAVE_ASPRINTF # include <stdarg.h> Index: cyrus-sasl-2.1.26/saslauthd/utils.h =================================================================== --- cyrus-sasl-2.1.26.orig/saslauthd/utils.h 2016-01-10 13:31:46.010679955 +0000 +++ cyrus-sasl-2.1.26/saslauthd/utils.h 2016-01-10 13:31:46.006679956 +0000 @@ -85,6 +85,7 @@ extern ssize_t tx_rec(int filefd, void *, size_t); extern ssize_t rx_rec(int , void *, size_t); extern int retry_writev(int, struct iovec *, int); +extern int rx_avail(int filefd, int timeoutms); #endif /* _UTILS_H */ Index: cyrus-sasl-2.1.26/saslauthd/testsaslauthd.c =================================================================== --- cyrus-sasl-2.1.26.orig/saslauthd/testsaslauthd.c 2016-01-10 13:31:46.010679955 +0000 +++ cyrus-sasl-2.1.26/saslauthd/testsaslauthd.c 2016-01-10 13:31:46.006679956 +0000 @@ -96,7 +96,8 @@ const char *userid, const char *passwd, const char *service, - const char *user_realm) + const char *user_realm, + const char *cipport) { char response[1024]; char query[8192]; @@ -108,6 +109,9 @@ void *context; char pwpath[sizeof(srvaddr.sun_path)]; const char *p = NULL; + #define CLIENTIPPORT_LEN 128 + char clientipport[CLIENTIPPORT_LEN+1]; + char *colon; #ifdef USE_DOORS door_arg_t arg; #endif @@ -115,6 +119,21 @@ if(!service) service = "imap"; if(!user_realm) user_realm = ""; if(!userid || !passwd) return -1; + if(cipport) { + if (strlen(cipport) > CLIENTIPPORT_LEN) { + fprintf(stderr, "'clientip:clientport' must not exceed %d characters\n", CLIENTIPPORT_LEN); + return -1; + } + strcpy(clientipport, cipport); + colon = strchr(clientipport, ':'); + if (colon) + *colon = ';'; + else { + fprintf(stderr, "missing colon in 'clientip:clientport'\n"); + return -1; + } + } + if (saslauthd_path) { strncpy(pwpath, saslauthd_path, sizeof(pwpath)); @@ -132,13 +151,14 @@ * count authid count password count service count realm */ { - unsigned short u_len, p_len, s_len, r_len; + unsigned short u_len, p_len, s_len, r_len, c_len; struct iovec iov[8]; u_len = htons(strlen(userid)); p_len = htons(strlen(passwd)); s_len = htons(strlen(service)); r_len = htons((user_realm ? strlen(user_realm) : 0)); + c_len = cipport ? htons(strlen(clientipport)) : 0; memcpy(query_end, &u_len, sizeof(unsigned short)); query_end += sizeof(unsigned short); @@ -155,6 +175,13 @@ memcpy(query_end, &r_len, sizeof(unsigned short)); query_end += sizeof(unsigned short); if (user_realm) while (*user_realm) *query_end++ = *user_realm++; + + if (c_len) { + memcpy(query_end, &c_len, sizeof(unsigned short)); + query_end += sizeof(unsigned short); + p = clientipport; + while (*p) *query_end++ = *p++; + } } #ifdef USE_DOORS @@ -251,6 +278,7 @@ { const char *user = NULL, *password = NULL; const char *realm = NULL, *service = NULL, *path = NULL; + const char *clientipport = NULL; int c; int flag_error = 0; unsigned passlen, verifylen; @@ -259,7 +287,7 @@ char *user_domain = NULL; int repeat = 0; - while ((c = getopt(argc, argv, "p:u:r:s:f:R:")) != EOF) + while ((c = getopt(argc, argv, "p:u:r:s:f:c:R:")) != EOF) switch (c) { case 'R': repeat = atoi(optarg); @@ -279,6 +307,9 @@ case 'p': password = optarg; break; + case 'c': + clientipport = optarg; + break; default: flag_error = 1; break; @@ -291,7 +322,8 @@ (void)fprintf(stderr, "%s: usage: %s -u username -p password\n" " [-r realm] [-s servicename]\n" - " [-f socket path] [-R repeatnum]\n", + " [-f socket path] [-R repeatnum]\n" + " [-c clientip:clientport]\n", argv[0], argv[0]); exit(1); } @@ -300,7 +332,7 @@ for (c = 0; c < repeat; c++) { /* saslauthd-authenticated login */ printf("%d: ", c); - result = saslauthd_verify_password(path, user, password, service, realm); + result = saslauthd_verify_password(path, user, password, service, realm, clientipport); } return result; }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Contact
Support
@OBShq
The Open Build Service is an
openSUSE project
.
Log In
Places
Places
All Projects
Status Monitor