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) {

Reply via email to