Module Name: src Committed By: christos Date: Tue Feb 15 18:36:08 UTC 2011
Modified Files: src/crypto/external/bsd/libsaslc/dist/man: libsaslc.3 src/crypto/external/bsd/libsaslc/dist/src: mech_digestmd5.c Log Message: >From Anon Ymous: 1) Fix a memory leak in cipher_context_create(). 2) Fix a goof in the construction of the digest-uri. 3) Allow SASLC_PROP_SERVICENAME to be a hostname qualified comma delimited list of service names to select from and update the manpage to reflect this. 4) Make libsaslc.3 pass mdoclint(1). To generate a diff of this commit: cvs rdiff -u -r1.7 -r1.8 src/crypto/external/bsd/libsaslc/dist/man/libsaslc.3 cvs rdiff -u -r1.7 -r1.8 \ src/crypto/external/bsd/libsaslc/dist/src/mech_digestmd5.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/crypto/external/bsd/libsaslc/dist/man/libsaslc.3 diff -u src/crypto/external/bsd/libsaslc/dist/man/libsaslc.3:1.7 src/crypto/external/bsd/libsaslc/dist/man/libsaslc.3:1.8 --- src/crypto/external/bsd/libsaslc/dist/man/libsaslc.3:1.7 Sat Feb 12 18:21:32 2011 +++ src/crypto/external/bsd/libsaslc/dist/man/libsaslc.3 Tue Feb 15 13:36:08 2011 @@ -1,4 +1,4 @@ -.\" $NetBSD: libsaslc.3,v 1.7 2011/02/12 23:21:32 christos Exp $ +.\" $NetBSD: libsaslc.3,v 1.8 2011/02/15 18:36:08 christos Exp $ .\" .\" Copyright (c) 2010 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -34,7 +34,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd December 31, 2010 +.Dd February 14, 2011 .Dt LIBSASLC 3 .Os .Sh NAME @@ -364,7 +364,7 @@ return 0; } .Ed -.Sh CONFIGURATION +.Ss CONFIGURATION .Nm uses three types of dictionaries: context (or global), session, and mechanism, and they are searched in that order by @@ -456,7 +456,7 @@ Any base supported by .Xr strtoll 3 is allowed. -.Sh PROPERTIES +.Ss PROPERTIES Most of the control of the .Nm behavior is done via setting various properties in the context or @@ -508,7 +508,11 @@ .Pp The default value is .Qq des,3des,rc4,rc4_40,rc4_56,aes . -.Pq Note that Qo aes Qc is not part of the official standard. +.Po +Note that +.Qq aes +is not part of the official standard. +.Pc Used by the DIGEST-MD5 mechanism. .It SASLC_PROP_DEBUG Po Qo DEBUG Qc Pc If true, then enable debug messages. @@ -526,7 +530,7 @@ section below. .Pc .It SASLC_PROP_HOSTNAME Po Qo HOSTNAME Qc Pc -The hostname. +The fully qualified domain name of the server host. Used by the DIGEST-MD5 and GSSAPI mechanisms. .It SASLC_PROP_MAXBUF Po Qo MAXBUF Qc Pc The size of the decode buffer. @@ -588,7 +592,23 @@ The service being used, e.g., smtp, imap, etc. Used by the DIGEST-MD5 and GSSAPI mechanisms. .It SASLC_PROP_SERVICENAME Po Qo SERVICENAME Qc Pc -The service name to use. +A comma delimited list of possible service names with elements of the +form +.Qq Oo Ao hostname Ac : Oc Ns Ao serv-name Ac +and with the same rules as for the SASLC_PROP_REALM list. +This should only be used if the client uses a DNS name for the service +that is different from the FQDN of the server. +For example, the service name +.Em example.com +might resolve +.Pq via SRV or MX records +into a set of other DNS names, one of which, +.Em mail3.example.com , +is the FQDN of the server. +.Po +See RFC 2831 section 2.1.2 +.Qq serv-name . +.Pc Used by the DIGEST-MD5 mechanism. .El .Pp @@ -613,7 +633,7 @@ If set, turn on debugging messages. This turns on debugging as early as possible and is a global setting. .El -.Sh GSSAPI and Kerberos +.Ss GSSAPI and Kerberos The following is a minimal .Pq Heimdal Kerberos 5 setup for use with an smtp server that has been configured @@ -742,13 +762,13 @@ .Pp to obtain a ticket for the postfix user with the postfix credential and you should be good to go! -.Sh STANDARDS -RFC 2195, RFC 2222, RFC 2245, RFC 2595, RFC 2831, RFC 4422, RFC 4505, -RFC 4616, RFC 4752. -.Sh OTHER IMPLEMENTATIONS +.Sh COMPATIBILITY There exist other SASL client library implementations including Cyrus SASL (http://asg.web.cmu.edu/sasl/sasl-library.html) and GNU SASL (http://www.gnu.org/software/gsasl/). +.Sh STANDARDS +RFC 2195, RFC 2222, RFC 2245, RFC 2595, RFC 2831, RFC 4422, RFC 4505, +RFC 4616, RFC 4752. .Sh CAVEATS The API was heavily influenced by its use with .Xr postfix 1 . Index: src/crypto/external/bsd/libsaslc/dist/src/mech_digestmd5.c diff -u src/crypto/external/bsd/libsaslc/dist/src/mech_digestmd5.c:1.7 src/crypto/external/bsd/libsaslc/dist/src/mech_digestmd5.c:1.8 --- src/crypto/external/bsd/libsaslc/dist/src/mech_digestmd5.c:1.7 Sat Feb 12 18:21:32 2011 +++ src/crypto/external/bsd/libsaslc/dist/src/mech_digestmd5.c Tue Feb 15 13:36:08 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: mech_digestmd5.c,v 1.7 2011/02/12 23:21:32 christos Exp $ */ +/* $NetBSD: mech_digestmd5.c,v 1.8 2011/02/15 18:36:08 christos Exp $ */ /* Copyright (c) 2010 The NetBSD Foundation, Inc. * All rights reserved. @@ -35,7 +35,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #include <sys/cdefs.h> -__RCSID("$NetBSD: mech_digestmd5.c,v 1.7 2011/02/12 23:21:32 christos Exp $"); +__RCSID("$NetBSD: mech_digestmd5.c,v 1.8 2011/02/15 18:36:08 christos Exp $"); #include <sys/param.h> @@ -57,7 +57,6 @@ #include "msg.h" #include "saslc_private.h" - /* See RFC 2831. */ /* @@ -220,10 +219,12 @@ /** * @brief if possible convert a UTF-8 string to a ISO8859-1 string. - * The caller is responsible for freeing memory. * @param utf8 original UTF-8 string. * @param iso8859 pointer to pointer to the malloced ISO8859-1 string. * @return -1 if the string cannot be translated. + * + * NOTE: this allocates memory for its output and the caller is + * responsible for freeing it. */ static int utf8_to_8859_1(char *utf8, char **iso8859) @@ -270,10 +271,12 @@ } /** - * @brief unquote a string by removing escapes. Allocates memory for - * new string which the caller is responsible for freeing. + * @brief unquote a string by removing escapes. * @param str string to unquote. * @return NULL on failure + * + * NOTE: this allocates memory for its output and the caller is + * responsible for freeing it. */ static char * unq(const char *str) @@ -642,25 +645,119 @@ } /** + * @brief Choose a string from a user provided host qualified list, + * i.e., a comma delimited list with possible hostname qualifiers on + * the elements. + * @param hqlist a comma delimited list with entries of the form + * "[hostname:]string". + * @param hostname the hostname to use in the selection. + * @return the best matching string or NULL if none found. + * + * NOTE: hqlist must not be NULL. + * NOTE: this allocates memory for its output and the caller is + * responsible for freeing it. + */ +static char * +choose_from_hqlist(const char *hqlist, const char *hostname) +{ + list_t *l, *list; + size_t len; + char *p; + + list = saslc__list_parse(hqlist); + if (list == NULL) + return NULL; + + /* + * If the user provided a list and the caller provided a + * hostname, pick the first string from the list that + * corresponds to the hostname. + */ + if (hostname != NULL) { + len = strlen(hostname); + for (l = list; l != NULL; l = l->next) { + p = l->value + len; + if (strncasecmp(l->value, hostname, len) != 0 || + *p != ':') + continue; + + if (*(++p) != '\0' && isalnum((unsigned char)*p)) { + p = strdup(p); + saslc__list_free(list); + return p; + } + } + } + /* + * If one couldn't be found, look for first string in the list + * without a hostname specifier. + */ + p = NULL; + for (l = list; l != NULL; l = l->next) { + if (strchr(l->value, ':') == NULL) { + p = strdup(l->value); + break; + } + } + saslc__list_free(list); + return p; +} + +/** * @brief builds digesturi string - * @param service service - * @param service_name service name - * @param realm realm + * @param serv_type type of service to use, e.g., "smtp" + * @param host fully-qualified canonical DNS name of host + * @param serv_name service name if it is replicated via DNS records; may + * be NULL. * @return digesturi string, NULL on failure. */ static char * -saslc__mech_digestmd5_digesturi(const char *service, const char *service_name, - const char *realm) +saslc__mech_digestmd5_digesturi(saslc_sess_t *sess, const char *serv_host) { + saslc__mech_digestmd5_sess_t *ms; + const char *serv_list; + char *serv_name; + const char *serv_type; char *r; int rv; - rv = service_name == NULL - ? asprintf(&r, "%s/%s", service, realm) - : asprintf(&r, "%s/%s/%s", service, realm, service_name); - if (rv == -1) - return NULL; + ms = sess->mech_sess; + serv_type = saslc_sess_getprop(sess, SASLC_DIGESTMD5_SERVICE); + if (serv_type == NULL) { + saslc__error_set(ERR(sess), ERROR_MECH, + "service is required for an authentication"); + return NULL; + } + serv_list = saslc_sess_getprop(sess, SASLC_DIGESTMD5_SERVICENAME); + serv_name = serv_list != NULL + ? choose_from_hqlist(serv_list, serv_host) : NULL; + + saslc__msg_dbg("%s: serv_name='%s'", __func__, serv_name); + + /****************************************************************/ + /* digest-uri = "digest-uri" "=" <"> digest-uri-value <"> */ + /* digest-uri-value = serv-type "/" host [ "/" serv-name ] */ + /* */ + /* If the service is not replicated, or the serv-name is */ + /* identical to the host, then the serv-name component MUST be */ + /* omitted. The service is considered to be replicated if the */ + /* client's service-location process involves resolution using */ + /* standard DNS lookup operations, and if these operations */ + /* involve DNS records (such as SRV, or MX) which resolve one */ + /* DNS name into a set of other DNS names. */ + /****************************************************************/ + + rv = serv_name == NULL || strcmp(serv_host, serv_name) == 0 + ? asprintf(&r, "%s/%s", serv_type, serv_host) + : asprintf(&r, "%s/%s/%s", serv_type, serv_host, serv_name); + if (serv_name != NULL) + free(serv_name); + if (rv == -1) { + saslc__error_set_errno(ERR(sess), ERROR_NOMEM); + return NULL; + } + saslc__msg_dbg("%s: digest-uri='%s'", __func__, r); return r; } @@ -743,60 +840,6 @@ } /** - * @brief Choose a realm from a user provided list which may have - * hostname qualifiers. - * @param user_realm a comma delimited list with entries of the form - * "[hostname:]realm". - * @param hostname the hostname of the server provided by the caller. - * @return the best matching realm or NULL - */ -static char * -choose_user_realm(const char *user_realms, const char *hostname) -{ - list_t *l, *list; - size_t len; - char *p; - - list = saslc__list_parse(user_realms); - if (list == NULL) - return NULL; - - /* - * If the user provided a realm list and the caller provided a - * hostname, pick the first realm from the list that - * corresponds to the hostname. - */ - if (hostname != NULL) { - len = strlen(hostname); - for (l = list; l != NULL; l = l->next) { - p = l->value + len; - if (strncasecmp(l->value, hostname, len) != 0 || - *p != ':') - continue; - - if (*(++p) != '\0' && isalnum((unsigned char)*p)) { - p = strdup(p); - saslc__list_free(list); - return p; - } - } - } - /* - * If one couldn't be found, look for first user provided - * realm without a hostname specifier. - */ - p = NULL; - for (l = list; l != NULL; l = l->next) { - if (strchr(l->value, ':') == NULL) { - p = strdup(l->value); - break; - } - } - saslc__list_free(list); - return p; -} - -/** * @brief choose a realm from a list of possible realms provided by the server * @param sess the session context * @param realms the list of realms @@ -804,9 +847,9 @@ * responsibility to free the memory allocated for the return string. */ static char * -choose_realm(saslc_sess_t *sess, list_t *realms) +choose_realm(saslc_sess_t *sess, const char *hostname, list_t *realms) { - const char *hostname, *user_realms; + const char *user_realms; list_t *l; char *p; @@ -819,7 +862,6 @@ /* computing A1 (see below for details). */ /*****************************************************************/ - hostname = saslc_sess_getprop(sess, SASLC_DIGESTMD5_HOSTNAME); user_realms = saslc_sess_getprop(sess, SASLC_DIGESTMD5_REALM); /* @@ -833,7 +875,7 @@ * default. */ if (user_realms != NULL) { - p = choose_user_realm(user_realms, hostname); + p = choose_from_hqlist(user_realms, hostname); if (p != NULL) return p; } @@ -851,7 +893,7 @@ * from the challenge. */ if (user_realms == NULL || - (p = choose_user_realm(user_realms, hostname)) == NULL) + (p = choose_from_hqlist(user_realms, hostname)) == NULL) return strdup(realms->value); /* @@ -985,15 +1027,18 @@ /* follows: IVs = MD5({Kcs, "aes-128"}) */ /*************************************************************************/ + assert(cipher < __arraycount(cipher_ctx_tbl)); + if (cipher >= __arraycount(cipher_ctx_tbl)) { + saslc__error_set_errno(ERR(sess), ERROR_BADARG); + return NULL; + } + ctx = malloc(sizeof(*ctx)); if (ctx == NULL) { saslc__error_set_errno(ERR(sess), ERROR_NOMEM); return NULL; } - assert(cipher < __arraycount(cipher_ctx_tbl)); - if (cipher >= __arraycount(cipher_ctx_tbl)) - return NULL; ctp = &cipher_ctx_tbl[cipher]; assert(ctp->eval == cipher); @@ -1133,7 +1178,7 @@ * @param outlen decoded output packet length * @returns 0 on success, -1 on failure * - * NOTE: this mallocs memory for its output and the caller is + * NOTE: this allocates memory for its output and the caller is * responsible for freeing it. * * integrity (auth-int): @@ -1203,7 +1248,7 @@ * @returns 0 on success, -1 on failure * * NOTE: this modifies the intput buffer! - * NOTE: this mallocs memory for its output and the caller is + * NOTE: this allocates memory for its output and the caller is * responsible for freeing it. * * integrity (auth-int): @@ -1867,10 +1912,9 @@ rdata_t *rdata; const char *authcid; const char *authzid; - const char *passwd; - const char *service; - const char *service_name; + const char *hostname; const char *maxbuf; + const char *passwd; int rv; ms = sess->mech_sess; @@ -1892,19 +1936,23 @@ rdata->cipher = rv; } - service = saslc_sess_getprop(sess, SASLC_DIGESTMD5_SERVICE); - if (service == NULL) { + hostname = saslc_sess_getprop(sess, SASLC_DIGESTMD5_HOSTNAME); + if (hostname == NULL) { saslc__error_set(ERR(sess), ERROR_MECH, - "service is required for an authentication"); + "hostname is required for authentication"); return -1; } - service_name = saslc_sess_getprop(sess, SASLC_DIGESTMD5_SERVICENAME); - - rdata->realm = choose_realm(sess, cdata->realm); + rdata->realm = choose_realm(sess, hostname, cdata->realm); + if (rdata->realm == NULL) { + saslc__error_set(ERR(sess), ERROR_MECH, + "cannot determine the realm"); + return -1; + } - rdata->digesturi = saslc__mech_digestmd5_digesturi(service, - service_name, rdata->realm); + rdata->digesturi = saslc__mech_digestmd5_digesturi(sess, hostname); + if (rdata->digesturi == NULL) + return -1; /* error message already set */ authcid = saslc_sess_getprop(sess, SASLC_DIGESTMD5_AUTHCID); if (authcid == NULL) {