summaryrefslogtreecommitdiff
path: root/usr/src/lib/sasl_plugins
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/sasl_plugins
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/sasl_plugins')
-rw-r--r--usr/src/lib/sasl_plugins/Makefile83
-rw-r--r--usr/src/lib/sasl_plugins/Makefile.com42
-rw-r--r--usr/src/lib/sasl_plugins/Makefile.subdirs27
-rw-r--r--usr/src/lib/sasl_plugins/cram/Makefile10
-rw-r--r--usr/src/lib/sasl_plugins/cram/Makefile.com13
-rw-r--r--usr/src/lib/sasl_plugins/cram/amd64/Makefile11
-rw-r--r--usr/src/lib/sasl_plugins/cram/cram.c801
-rw-r--r--usr/src/lib/sasl_plugins/cram/crammd5_init.c44
-rw-r--r--usr/src/lib/sasl_plugins/cram/i386/Makefile11
-rw-r--r--usr/src/lib/sasl_plugins/cram/sparc/Makefile11
-rw-r--r--usr/src/lib/sasl_plugins/cram/sparcv9/Makefile12
-rw-r--r--usr/src/lib/sasl_plugins/cram/spec/Makefile10
-rw-r--r--usr/src/lib/sasl_plugins/cram/spec/Makefile.targ11
-rw-r--r--usr/src/lib/sasl_plugins/cram/spec/amd64/Makefile14
-rw-r--r--usr/src/lib/sasl_plugins/cram/spec/cram.spec28
-rw-r--r--usr/src/lib/sasl_plugins/cram/spec/i386/Makefile15
-rw-r--r--usr/src/lib/sasl_plugins/cram/spec/sparc/Makefile15
-rw-r--r--usr/src/lib/sasl_plugins/cram/spec/sparcv9/Makefile16
-rw-r--r--usr/src/lib/sasl_plugins/cram/spec/versions19
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/Makefile7
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/Makefile.com16
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/amd64/Makefile11
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/digestmd5.c5433
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/digestmd5_init.c44
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/i386/Makefile11
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/sparc/Makefile11
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/sparcv9/Makefile12
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/spec/Makefile7
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/spec/Makefile.targ10
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/spec/amd64/Makefile14
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/spec/digestmd5.spec28
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/spec/i386/Makefile15
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/spec/sparc/Makefile15
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/spec/sparcv9/Makefile16
-rw-r--r--usr/src/lib/sasl_plugins/digestmd5/spec/versions19
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/Makefile7
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/Makefile.com15
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/amd64/Makefile11
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/gssapi.c2206
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/gssapiv2_init.c44
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/i386/Makefile11
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/sparc/Makefile11
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/sparcv9/Makefile12
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/spec/Makefile7
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/spec/Makefile.targ10
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/spec/amd64/Makefile14
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/spec/gssapi.spec28
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/spec/i386/Makefile15
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/spec/sparc/Makefile15
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/spec/sparcv9/Makefile16
-rw-r--r--usr/src/lib/sasl_plugins/gssapi/spec/versions19
-rw-r--r--usr/src/lib/sasl_plugins/plain/Makefile7
-rw-r--r--usr/src/lib/sasl_plugins/plain/Makefile.com13
-rw-r--r--usr/src/lib/sasl_plugins/plain/amd64/Makefile11
-rw-r--r--usr/src/lib/sasl_plugins/plain/i386/Makefile11
-rw-r--r--usr/src/lib/sasl_plugins/plain/plain.c514
-rw-r--r--usr/src/lib/sasl_plugins/plain/plain_init.c44
-rw-r--r--usr/src/lib/sasl_plugins/plain/sparc/Makefile11
-rw-r--r--usr/src/lib/sasl_plugins/plain/sparcv9/Makefile12
-rw-r--r--usr/src/lib/sasl_plugins/plain/spec/Makefile7
-rw-r--r--usr/src/lib/sasl_plugins/plain/spec/Makefile.targ10
-rw-r--r--usr/src/lib/sasl_plugins/plain/spec/amd64/Makefile14
-rw-r--r--usr/src/lib/sasl_plugins/plain/spec/i386/Makefile15
-rw-r--r--usr/src/lib/sasl_plugins/plain/spec/plain.spec28
-rw-r--r--usr/src/lib/sasl_plugins/plain/spec/sparc/Makefile15
-rw-r--r--usr/src/lib/sasl_plugins/plain/spec/sparcv9/Makefile16
-rw-r--r--usr/src/lib/sasl_plugins/plain/spec/versions19
67 files changed, 10050 insertions, 0 deletions
diff --git a/usr/src/lib/sasl_plugins/Makefile b/usr/src/lib/sasl_plugins/Makefile
new file mode 100644
index 0000000000..75276acb75
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/Makefile
@@ -0,0 +1,83 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+# Note, to build SASL msg file go to $SRC/lib/libsasl and make _msg
+# target there. Messages in sasl_plugins will be picked up from there.
+
+include ../Makefile.lib
+
+SUBDIRS = cram digestmd5 gssapi plain
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install: $(SUBDIRS)
+
+lint: $(SUBDIRS)
+
+install_h check:
+
+$(SUBDIRS) spec: FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+# EXPORT DELETE START
+# CRYPT DELETE START
+# Special target to clean up the source tree for export distribution
+# Warning: This target changes the source tree
+EXPORT_SRC:
+ $(RM) Makefile+ \
+ digestmd5/digestmd5.c+ \
+ gssapi/gssapi.c+
+
+ $(SED) -e "/^# EXPORT DELETE START/,/^# EXPORT DELETE END/d" \
+ < Makefile > Makefile+
+ $(MV) Makefile+ Makefile
+
+ $(SED) -e "/EXPORT DELETE START/,/EXPORT DELETE END/d" \
+ < digestmd5/digestmd5.c > digestmd5/digestmd5.c+
+ $(MV) digestmd5/digestmd5.c+ digestmd5/digestmd5.c
+
+ $(SED) -e "/EXPORT DELETE START/,/EXPORT DELETE END/d" \
+ < gssapi/gssapi.c > gssapi/gssapi.c+
+ $(MV) gssapi/gssapi.c+ gssapi/gssapi.c
+
+ $(CHMOD) 444 \
+ Makefile \
+ digestmd5/digestmd5.c \
+ gssapi/gssapi.c
+
+CRYPT_SRC:
+ $(RM) Makefile+
+
+ $(SED) -e "/CRYPT DELETE START/,/CRYPT DELETE END/d" \
+ < digestmd5/digestmd5.c | $(SED) -e "/EXPORT DELETE/d" \
+ > digestmd5/digestmd5.c+
+ $(MV) digestmd5/digestmd5.c+ digestmd5/digestmd5.c
+
+ $(SED) -e "/CRYPT DELETE START/,/CRYPT DELETE END/d" \
+ < gssapi/gssapi.c | $(SED) -e "/EXPORT DELETE/d" \
+ > gssapi/gssapi.c+
+ $(MV) gssapi/gssapi.c+ gssapi/gssapi.c
+
+ $(SED) -e "/^# CRYPT DELETE START/,/^# CRYPT DELETE END/d" \
+ < Makefile | $(SED) -e "/^# EXPORT DELETE/d" > Makefile+
+ $(MV) Makefile+ Makefile
+ $(CHMOD) 444 Makefile digestmd5/digestmd5.c gssapi/gssapi.c
+
+# CRYPT DELETE END
+# EXPORT DELETE END
+
+include ../Makefile.targ
+
+.PARALLEL: $(SUBDIRS)
diff --git a/usr/src/lib/sasl_plugins/Makefile.com b/usr/src/lib/sasl_plugins/Makefile.com
new file mode 100644
index 0000000000..4482f21022
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/Makefile.com
@@ -0,0 +1,42 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+COMMONOBJS= plugin_common.o
+OBJECTS= $(PLUG_OBJS) $(COMMONOBJS)
+
+include $(SRC)/lib/Makefile.lib
+
+CPPFLAGS += -I$(SRC)/lib/libsasl/include
+
+LIBS = $(DYNLIB)
+SRCS= $(PLUG_OBJS:%.o=../%.c) $(COMMONOBJS:%.o=../../%.c)
+LDLIBS += -lsocket -lc $(PLUG_LIBS)
+SRCDIR= ..
+
+MAPDIR= ../spec/$(TRANSMACH)
+SPECMAPFILE= $(MAPDIR)/mapfile
+
+ROOTLIBDIR= $(ROOT)/usr/lib/sasl
+ROOTLIBDIR64= $(ROOT)/usr/lib/sasl/$(MACH64)
+
+LINTFLAGS= $(ENC_FLAGS)
+LINTFLAGS64= -Xarch=$(MACH64:sparcv9=v9) $(ENC_FLAGS)
+
+CFLAGS += $(CCVERBOSE) $(XSTRCONST) $(ENC_FLAGS)
+CFLAGS64 += $(XSTRCONST) $(ENC_FLAGS)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+pics/%.o: $(SRC)/lib/libsasl/plugin/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/sasl_plugins/Makefile.subdirs b/usr/src/lib/sasl_plugins/Makefile.subdirs
new file mode 100644
index 0000000000..cba9aa690b
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/Makefile.subdirs
@@ -0,0 +1,27 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include $(SRC)/lib/Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+.KEEP_STATE:
+
+all clean clobber install: spec .WAIT $(SUBDIRS)
+
+lint: $(SUBDIRS)
+
+$(SUBDIRS) spec: FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/sasl_plugins/cram/Makefile b/usr/src/lib/sasl_plugins/cram/Makefile
new file mode 100644
index 0000000000..18b5b0cf5d
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/Makefile
@@ -0,0 +1,10 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/cram/Makefile
+#
+
+include ../Makefile.subdirs
diff --git a/usr/src/lib/sasl_plugins/cram/Makefile.com b/usr/src/lib/sasl_plugins/cram/Makefile.com
new file mode 100644
index 0000000000..1cda7ac555
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/Makefile.com
@@ -0,0 +1,13 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+LIBRARY= crammd5.a
+VERS= .1
+
+PLUG_OBJS= cram.o crammd5_init.o
+
+# include common definitions
+include ../../Makefile.com
diff --git a/usr/src/lib/sasl_plugins/cram/amd64/Makefile b/usr/src/lib/sasl_plugins/cram/amd64/Makefile
new file mode 100644
index 0000000000..13ae0db12d
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/amd64/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64)
diff --git a/usr/src/lib/sasl_plugins/cram/cram.c b/usr/src/lib/sasl_plugins/cram/cram.c
new file mode 100644
index 0000000000..7d4f7b430e
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/cram.c
@@ -0,0 +1,801 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* CRAM-MD5 SASL plugin
+ * Rob Siemborski
+ * Tim Martin
+ * $Id: cram.c,v 1.79 2003/02/18 18:27:37 rjs3 Exp $
+ */
+/*
+ * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Office of Technology Transfer
+ * Carnegie Mellon University
+ * 5000 Forbes Avenue
+ * Pittsburgh, PA 15213-3890
+ * (412) 268-4387, fax: (412) 268-7395
+ * tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef macintosh
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslutil.h>
+
+#ifdef _SUN_SDK_
+#include <unistd.h>
+#endif /* _SUN_SDK_ */
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#include <sasl_cram_plugin_decl.h>
+#endif
+
+/***************************** Common Section *****************************/
+
+#ifndef _SUN_SDK_
+static const char plugin_id[] = "$Id: cram.c,v 1.79 2003/02/18 18:27:37 rjs3 Exp $";
+#endif /* !_SUN_SDK_ */
+
+/* convert a string of 8bit chars to it's representation in hex
+ * using lowercase letters
+ */
+static char *convert16(unsigned char *in, int inlen, const sasl_utils_t *utils)
+{
+ static char hex[]="0123456789abcdef";
+ int lup;
+ char *out;
+
+ out = utils->malloc(inlen*2+1);
+ if (out == NULL) return NULL;
+
+ for (lup=0; lup < inlen; lup++) {
+ out[lup*2] = hex[in[lup] >> 4];
+ out[lup*2+1] = hex[in[lup] & 15];
+ }
+
+ out[lup*2] = 0;
+ return out;
+}
+
+
+/***************************** Server Section *****************************/
+
+typedef struct server_context {
+ int state;
+
+ char *challenge;
+} server_context_t;
+
+static int
+crammd5_server_mech_new(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ const char *challenge __attribute__((unused)),
+ unsigned challen __attribute__((unused)),
+ void **conn_context)
+{
+ server_context_t *text;
+
+ /* holds state are in */
+ text = sparams->utils->malloc(sizeof(server_context_t));
+ if (text == NULL) {
+ MEMERROR( sparams->utils );
+ return SASL_NOMEM;
+ }
+
+ memset(text, 0, sizeof(server_context_t));
+
+ text->state = 1;
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+/*
+ * Returns the current time (or part of it) in string form
+ * maximum length=15
+ */
+static char *gettime(sasl_server_params_t *sparams)
+{
+ char *ret;
+ time_t t;
+
+ t=time(NULL);
+ ret= sparams->utils->malloc(15);
+ if (ret==NULL) return NULL;
+
+ /* the bottom bits are really the only random ones so if
+ we overflow we don't want to loose them */
+ snprintf(ret,15,"%lu",t%(0xFFFFFF));
+
+ return ret;
+}
+
+static char *randomdigits(sasl_server_params_t *sparams)
+{
+ unsigned int num;
+ char *ret;
+ unsigned char temp[5]; /* random 32-bit number */
+
+#if defined _DEV_URANDOM && defined _SUN_SDK_
+ {
+ int fd = open(_DEV_URANDOM, O_RDONLY);
+ int nread = 0;
+
+ if (fd != -1) {
+ nread = read(fd, temp, 4);
+ close(fd);
+ }
+ if (nread != 4)
+ sparams->utils->rand(sparams->utils->rpool,
+ (char *) temp, 4);
+ }
+#else
+ sparams->utils->rand(sparams->utils->rpool,(char *) temp,4);
+#endif /* _DEV_URANDOM && _SUN_SDK_ */
+ num=(temp[0] * 256 * 256 * 256) +
+ (temp[1] * 256 * 256) +
+ (temp[2] * 256) +
+ (temp[3] );
+
+ ret = sparams->utils->malloc(15); /* there's no way an unsigned can be longer than this right? */
+ if (ret == NULL) return NULL;
+ sprintf(ret, "%u", num);
+
+ return ret;
+}
+
+static int
+crammd5_server_mech_step1(server_context_t *text,
+ sasl_server_params_t *sparams,
+ const char *clientin __attribute__((unused)),
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams __attribute__((unused)))
+{
+ char *time, *randdigits;
+
+ /* we shouldn't have received anything */
+ if (clientinlen != 0) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "CRAM-MD5 does not accept inital data");
+#else
+ SETERROR(sparams->utils, "CRAM-MD5 does not accpet inital data");
+#endif /* _SUN_SDK_ */
+ return SASL_BADPROT;
+ }
+
+ /* get time and a random number for the nonce */
+ time = gettime(sparams);
+ randdigits = randomdigits(sparams);
+ if ((time == NULL) || (randdigits == NULL)) {
+ MEMERROR( sparams->utils );
+ return SASL_NOMEM;
+ }
+
+ /* allocate some space for the challenge */
+ text->challenge = sparams->utils->malloc(200 + 1);
+ if (text->challenge == NULL) {
+ MEMERROR(sparams->utils);
+ return SASL_NOMEM;
+ }
+
+ /* create the challenge */
+ snprintf(text->challenge, 200, "<%s.%s@%s>", randdigits, time,
+ sparams->serverFQDN);
+
+ *serverout = text->challenge;
+ *serveroutlen = strlen(text->challenge);
+
+ /* free stuff */
+ sparams->utils->free(time);
+ sparams->utils->free(randdigits);
+
+ text->state = 2;
+
+ return SASL_CONTINUE;
+}
+
+static int
+crammd5_server_mech_step2(server_context_t *text,
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout __attribute__((unused)),
+ unsigned *serveroutlen __attribute__((unused)),
+ sasl_out_params_t *oparams)
+{
+ char *userid = NULL;
+ sasl_secret_t *sec = NULL;
+ int pos, len;
+ int result = SASL_FAIL;
+ const char *password_request[] = { SASL_AUX_PASSWORD,
+ "*cmusaslsecretCRAM-MD5",
+ NULL };
+ struct propval auxprop_values[3];
+ HMAC_MD5_CTX tmphmac;
+ HMAC_MD5_STATE md5state;
+ int clear_md5state = 0;
+ char *digest_str = NULL;
+ UINT4 digest[4];
+
+ /* extract userid; everything before last space */
+ pos = clientinlen-1;
+ while ((pos > 0) && (clientin[pos] != ' ')) pos--;
+
+ if (pos <= 0) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "need authentication name");
+#else
+ SETERROR( sparams->utils,"need authentication name");
+#endif /* _SUN_SDK_ */
+ return SASL_BADPROT;
+ }
+
+ userid = (char *) sparams->utils->malloc(pos+1);
+ if (userid == NULL) {
+ MEMERROR( sparams->utils);
+ return SASL_NOMEM;
+ }
+
+ /* copy authstr out */
+ memcpy(userid, clientin, pos);
+ userid[pos] = '\0';
+
+ result = sparams->utils->prop_request(sparams->propctx, password_request);
+ if (result != SASL_OK) goto done;
+
+ /* this will trigger the getting of the aux properties */
+ result = sparams->canon_user(sparams->utils->conn,
+ userid, 0, SASL_CU_AUTHID | SASL_CU_AUTHZID,
+ oparams);
+ if (result != SASL_OK) goto done;
+
+ result = sparams->utils->prop_getnames(sparams->propctx,
+ password_request,
+ auxprop_values);
+ if (result < 0 ||
+ ((!auxprop_values[0].name || !auxprop_values[0].values) &&
+ (!auxprop_values[1].name || !auxprop_values[1].values))) {
+ /* We didn't find this username */
+#ifdef _INTEGRATED_SOLARIS_
+ sparams->utils->seterror(sparams->utils->conn,0,
+ gettext("no secret in database"));
+#else
+ sparams->utils->seterror(sparams->utils->conn,0,
+ "no secret in database");
+#endif /* _INTEGRATED_SOLARIS_ */
+ result = SASL_NOUSER;
+ goto done;
+ }
+
+ if (auxprop_values[0].name && auxprop_values[0].values) {
+ len = strlen(auxprop_values[0].values[0]);
+ if (len == 0) {
+#ifdef _INTEGRATED_SOLARIS_
+ sparams->utils->seterror(sparams->utils->conn,0,
+ gettext("empty secret"));
+#else
+ sparams->utils->seterror(sparams->utils->conn,0,
+ "empty secret");
+#endif /* _INTEGRATED_SOLARIS_ */
+ result = SASL_FAIL;
+ goto done;
+ }
+
+ sec = sparams->utils->malloc(sizeof(sasl_secret_t) + len);
+ if (!sec) goto done;
+
+ sec->len = len;
+#ifdef _SUN_SDK_
+ strncpy((char *)sec->data, auxprop_values[0].values[0], len + 1);
+#else
+ strncpy(sec->data, auxprop_values[0].values[0], len + 1);
+#endif /* _SUN_SDK_ */
+
+ clear_md5state = 1;
+ /* Do precalculation on plaintext secret */
+ sparams->utils->hmac_md5_precalc(&md5state, /* OUT */
+ sec->data,
+ sec->len);
+ } else if (auxprop_values[1].name && auxprop_values[1].values) {
+ /* We have a precomputed secret */
+ memcpy(&md5state, auxprop_values[1].values[0],
+ sizeof(HMAC_MD5_STATE));
+ } else {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "Have neither type of secret");
+#else
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Have neither type of secret");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+ /* ok this is annoying:
+ so we have this half-way hmac transform instead of the plaintext
+ that means we half to:
+ -import it back into a md5 context
+ -do an md5update with the nonce
+ -finalize it
+ */
+ sparams->utils->hmac_md5_import(&tmphmac, (HMAC_MD5_STATE *) &md5state);
+ sparams->utils->MD5Update(&(tmphmac.ictx),
+ (const unsigned char *) text->challenge,
+ strlen(text->challenge));
+ sparams->utils->hmac_md5_final((unsigned char *) &digest, &tmphmac);
+
+ /* convert to base 16 with lower case letters */
+ digest_str = convert16((unsigned char *) digest, 16, sparams->utils);
+
+ /* if same then verified
+ * - we know digest_str is null terminated but clientin might not be
+ */
+ if (strncmp(digest_str, clientin+pos+1, strlen(digest_str)) != 0) {
+#ifdef _INTEGRATED_SOLARIS_
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ gettext("incorrect digest response"));
+#else
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "incorrect digest response");
+#endif /* _INTEGRATED_SOLARIS_ */
+ result = SASL_BADAUTH;
+ goto done;
+ }
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ result = SASL_OK;
+
+ done:
+ if (userid) sparams->utils->free(userid);
+ if (sec) _plug_free_secret(sparams->utils, &sec);
+
+ if (digest_str) sparams->utils->free(digest_str);
+ if (clear_md5state) memset(&md5state, 0, sizeof(md5state));
+
+ return result;
+}
+
+static int crammd5_server_mech_step(void *conn_context,
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ server_context_t *text = (server_context_t *) conn_context;
+
+ *serverout = NULL;
+ *serveroutlen = 0;
+
+ /* this should be well more than is ever needed */
+ if (clientinlen > 1024) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "CRAM-MD5 input longer than 1024 bytes");
+#else
+ SETERROR(sparams->utils, "CRAM-MD5 input longer than 1024 bytes");
+#endif /* _SUN_SDK_ */
+ return SASL_BADPROT;
+ }
+
+ switch (text->state) {
+
+ case 1:
+ return crammd5_server_mech_step1(text, sparams,
+ clientin, clientinlen,
+ serverout, serveroutlen,
+ oparams);
+
+ case 2:
+ return crammd5_server_mech_step2(text, sparams,
+ clientin, clientinlen,
+ serverout, serveroutlen,
+ oparams);
+
+ default: /* should never get here */
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "Invalid CRAM-MD5 server step %d", text->state);
+#else
+ sparams->utils->log(NULL, SASL_LOG_ERR,
+ "Invalid CRAM-MD5 server step %d\n", text->state);
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+#ifndef _SUN_SDK_
+ return SASL_FAIL; /* should never get here */
+#endif /* !_SUN_SDK_ */
+}
+
+static void crammd5_server_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ server_context_t *text = (server_context_t *) conn_context;
+
+ if (!text) return;
+
+ if (text->challenge) _plug_free_string(utils,&(text->challenge));
+
+ utils->free(text);
+}
+
+static sasl_server_plug_t crammd5_server_plugins[] =
+{
+ {
+ "CRAM-MD5", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS, /* security_flags */
+ SASL_FEAT_SERVER_FIRST, /* features */
+ NULL, /* glob_context */
+ &crammd5_server_mech_new, /* mech_new */
+ &crammd5_server_mech_step, /* mech_step */
+ &crammd5_server_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ NULL, /* mech avail */
+ NULL /* spare */
+ }
+};
+
+int crammd5_server_plug_init(const sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_SERVER_PLUG_VERSION) {
+#ifdef _SUN_SDK_
+ utils->log(NULL, SASL_LOG_ERR, "CRAM version mismatch");
+#else
+ SETERROR( utils, "CRAM version mismatch");
+#endif /* _SUN_SDK_ */
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_SERVER_PLUG_VERSION;
+ *pluglist = crammd5_server_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
+
+/***************************** Client Section *****************************/
+
+typedef struct client_context {
+ char *out_buf;
+ unsigned out_buf_len;
+#ifdef _INTEGRATED_SOLARIS_
+ void *h;
+#endif /* _INTEGRATED_SOLARIS_ */
+} client_context_t;
+
+static int crammd5_client_mech_new(void *glob_context __attribute__((unused)),
+ sasl_client_params_t *params,
+ void **conn_context)
+{
+ client_context_t *text;
+
+ /* holds state are in */
+ text = params->utils->malloc(sizeof(client_context_t));
+ if (text == NULL) {
+ MEMERROR(params->utils);
+ return SASL_NOMEM;
+ }
+
+ memset(text, 0, sizeof(client_context_t));
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+static char *make_hashed(sasl_secret_t *sec, char *nonce, int noncelen,
+ const sasl_utils_t *utils)
+{
+ char secret[65];
+ unsigned char digest[24];
+ int lup;
+ char *in16;
+
+ if (sec == NULL) return NULL;
+
+ if (sec->len < 64) {
+ memcpy(secret, sec->data, sec->len);
+
+ /* fill in rest with 0's */
+ for (lup= sec->len; lup < 64; lup++)
+ secret[lup]='\0';
+
+ } else {
+ memcpy(secret, sec->data, 64);
+ }
+
+ /* do the hmac md5 hash output 128 bits */
+ utils->hmac_md5((unsigned char *) nonce, noncelen,
+ (unsigned char *) secret, 64, digest);
+
+ /* convert that to hex form */
+ in16 = convert16(digest, 16, utils);
+ if (in16 == NULL) return NULL;
+
+ return in16;
+}
+
+static int crammd5_client_mech_step(void *conn_context,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ client_context_t *text = (client_context_t *) conn_context;
+ const char *authid;
+ sasl_secret_t *password = NULL;
+ unsigned int free_password = 0; /* set if we need to free password */
+ int auth_result = SASL_OK;
+ int pass_result = SASL_OK;
+ int result;
+ int maxsize;
+ char *in16 = NULL;
+
+ *clientout = NULL;
+ *clientoutlen = 0;
+
+ /* First check for absurd lengths */
+ if (serverinlen > 1024) {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "CRAM-MD5 input longer than 1024 bytes");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "CRAM-MD5 input longer than 1024 bytes");
+#endif /* _SUN_SDK_ */
+ return SASL_BADPROT;
+ }
+
+ /* check if sec layer strong enough */
+ if (params->props.min_ssf > params->external_ssf) {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "SSF requested of CRAM-MD5 plugin");
+#else
+ SETERROR( params->utils, "SSF requested of CRAM-MD5 plugin");
+#endif /* _SUN_SDK_ */
+ return SASL_TOOWEAK;
+ }
+
+ /* try to get the userid */
+ if (oparams->authid == NULL) {
+ auth_result=_plug_get_authid(params->utils, &authid, prompt_need);
+
+ if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT))
+ return auth_result;
+ }
+
+ /* try to get the password */
+ if (password == NULL) {
+ pass_result=_plug_get_password(params->utils, &password,
+ &free_password, prompt_need);
+
+ if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT))
+ return pass_result;
+ }
+
+ /* free prompts we got */
+ if (prompt_need && *prompt_need) {
+ params->utils->free(*prompt_need);
+ *prompt_need = NULL;
+ }
+
+ /* if there are prompts not filled in */
+ if ((auth_result == SASL_INTERACT) || (pass_result == SASL_INTERACT)) {
+ /* make the prompt list */
+ result =
+#ifdef _INTEGRATED_SOLARIS_
+ _plug_make_prompts(params->utils, &text->h, prompt_need,
+ NULL, NULL,
+ auth_result == SASL_INTERACT ?
+ convert_prompt(params->utils, &text->h,
+ gettext("Please enter your authentication name"))
+ : NULL, NULL,
+ pass_result == SASL_INTERACT ?
+ convert_prompt(params->utils, &text->h,
+ gettext("Please enter your password"))
+ : NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+#else
+ _plug_make_prompts(params->utils, prompt_need,
+ NULL, NULL,
+ auth_result == SASL_INTERACT ?
+ "Please enter your authentication name" : NULL,
+ NULL,
+ pass_result == SASL_INTERACT ?
+ "Please enter your password" : NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+#endif /* _INTEGRATED_SOLARIS_ */
+ if (result != SASL_OK) goto cleanup;
+
+ return SASL_INTERACT;
+ }
+
+ if (!password) {
+ PARAMERROR(params->utils);
+ return SASL_BADPARAM;
+ }
+
+ result = params->canon_user(params->utils->conn, authid, 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
+ if (result != SASL_OK) goto cleanup;
+
+ /*
+ * username SP digest (keyed md5 where key is passwd)
+ */
+
+ in16 = make_hashed(password, (char *) serverin, serverinlen,
+ params->utils);
+
+ if (in16 == NULL) {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "make_hashed failed");
+#else
+ SETERROR(params->utils, "whoops, make_hashed failed us this time");
+#endif /* _SUN_SDK_ */
+ result = SASL_FAIL;
+ goto cleanup;
+ }
+
+ maxsize = 32+1+strlen(oparams->authid)+30;
+ result = _plug_buf_alloc(params->utils, &(text->out_buf),
+ &(text->out_buf_len), maxsize);
+ if (result != SASL_OK) goto cleanup;
+
+ snprintf(text->out_buf, maxsize, "%s %s", oparams->authid, in16);
+
+ *clientout = text->out_buf;
+ *clientoutlen = strlen(*clientout);
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ result = SASL_OK;
+
+ cleanup:
+ /* get rid of private information */
+ if (in16) _plug_free_string(params->utils, &in16);
+
+ /* get rid of all sensitive info */
+ if (free_password) _plug_free_secret(params-> utils, &password);
+
+ return result;
+}
+
+static void crammd5_client_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ client_context_t *text = (client_context_t *) conn_context;
+
+ if (!text) return;
+
+#ifdef _INTEGRATED_SOLARIS_
+ convert_prompt(utils, &text->h, NULL);
+#endif /* _INTEGRATED_SOLARIS_ */
+ if (text->out_buf) utils->free(text->out_buf);
+
+ utils->free(text);
+}
+
+static sasl_client_plug_t crammd5_client_plugins[] =
+{
+ {
+ "CRAM-MD5", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS, /* security_flags */
+ SASL_FEAT_SERVER_FIRST, /* features */
+ NULL, /* required_prompts */
+ NULL, /* glob_context */
+ &crammd5_client_mech_new, /* mech_new */
+ &crammd5_client_mech_step, /* mech_step */
+ &crammd5_client_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare */
+ NULL /* spare */
+ }
+};
+
+int crammd5_client_plug_init(const sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_CLIENT_PLUG_VERSION) {
+#ifdef _SUN_SDK_
+ utils->log(NULL, SASL_LOG_ERR, "CRAM version mismatch");
+#else
+ SETERROR( utils, "CRAM version mismatch");
+#endif /* _SUN_SDK_ */
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_CLIENT_PLUG_VERSION;
+ *pluglist = crammd5_client_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
diff --git a/usr/src/lib/sasl_plugins/cram/crammd5_init.c b/usr/src/lib/sasl_plugins/cram/crammd5_init.c
new file mode 100644
index 0000000000..5bfe6ebb62
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/crammd5_init.c
@@ -0,0 +1,44 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef macintosh
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <assert.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslutil.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#include <sasl_crammd5_plugin_decl.h>
+#endif
+
+#ifdef WIN32
+BOOL APIENTRY DllMain( HANDLE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+#endif
+
+SASL_CLIENT_PLUG_INIT( crammd5 )
+SASL_SERVER_PLUG_INIT( crammd5 )
+
diff --git a/usr/src/lib/sasl_plugins/cram/i386/Makefile b/usr/src/lib/sasl_plugins/cram/i386/Makefile
new file mode 100644
index 0000000000..952cdf4ddd
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/i386/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/cram/i386/Makefile
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS)
diff --git a/usr/src/lib/sasl_plugins/cram/sparc/Makefile b/usr/src/lib/sasl_plugins/cram/sparc/Makefile
new file mode 100644
index 0000000000..aedaedd885
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/sparc/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/cram/sparc/Makefile
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS)
diff --git a/usr/src/lib/sasl_plugins/cram/sparcv9/Makefile b/usr/src/lib/sasl_plugins/cram/sparcv9/Makefile
new file mode 100644
index 0000000000..342bf6b8f1
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/sparcv9/Makefile
@@ -0,0 +1,12 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/cram/sparcv9/Makefile
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64)
diff --git a/usr/src/lib/sasl_plugins/cram/spec/Makefile b/usr/src/lib/sasl_plugins/cram/spec/Makefile
new file mode 100644
index 0000000000..9e331dcd31
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/spec/Makefile
@@ -0,0 +1,10 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/cram/spec/Makefile
+#
+
+include $(SRC)/lib/Makefile.spec.arch
diff --git a/usr/src/lib/sasl_plugins/cram/spec/Makefile.targ b/usr/src/lib/sasl_plugins/cram/spec/Makefile.targ
new file mode 100644
index 0000000000..66db220e45
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/spec/Makefile.targ
@@ -0,0 +1,11 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY = crammd5.a
+VERS = .1
+
+OBJECTS = cram.o
diff --git a/usr/src/lib/sasl_plugins/cram/spec/amd64/Makefile b/usr/src/lib/sasl_plugins/cram/spec/amd64/Makefile
new file mode 100644
index 0000000000..07e64367c4
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/spec/amd64/Makefile
@@ -0,0 +1,14 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/cram/spec/cram.spec b/usr/src/lib/sasl_plugins/cram/spec/cram.spec
new file mode 100644
index 0000000000..37538e788e
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/spec/cram.spec
@@ -0,0 +1,28 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugin/cram/spec/cram.spec
+#
+
+function sasl_client_plug_init
+include <sasl/saslplug.h>
+declaration int sasl_client_plug_init(const sasl_utils_t *utils, \
+ int maxversion, int *out_version, \
+ sasl_client_plug_t **pluglist, \
+ int *plugcount)
+exception $return == SASL_FAIL
+version SUNWprivate_1.1
+end
+
+function sasl_server_plug_init
+include <sasl/saslplug.h>
+declaration int sasl_server_plug_init(const sasl_utils_t *utils, \
+ int maxversion, int *out_version, \
+ sasl_server_plug_t **pluglist, \
+ int *plugcount)
+exception $return == SASL_FAIL
+version SUNWprivate_1.1
+end
diff --git a/usr/src/lib/sasl_plugins/cram/spec/i386/Makefile b/usr/src/lib/sasl_plugins/cram/spec/i386/Makefile
new file mode 100644
index 0000000000..6306093f99
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/spec/i386/Makefile
@@ -0,0 +1,15 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/cram/spec/i386/Makefile
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/cram/spec/sparc/Makefile b/usr/src/lib/sasl_plugins/cram/spec/sparc/Makefile
new file mode 100644
index 0000000000..dcbd1f7c3c
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/spec/sparc/Makefile
@@ -0,0 +1,15 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/cram/spec/sparc/Makefile
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/cram/spec/sparcv9/Makefile b/usr/src/lib/sasl_plugins/cram/spec/sparcv9/Makefile
new file mode 100644
index 0000000000..0c01722717
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/spec/sparcv9/Makefile
@@ -0,0 +1,16 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/cram/spec/sparcv9/Makefile
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/cram/spec/versions b/usr/src/lib/sasl_plugins/cram/spec/versions
new file mode 100644
index 0000000000..6a318d48a3
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/cram/spec/versions
@@ -0,0 +1,19 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+sparc {
+ SUNWprivate_1.1;
+}
+sparcv9 {
+ SUNWprivate_1.1;
+}
+i386 {
+ SUNWprivate_1.1;
+}
+amd64 {
+ SUNWprivate_1.1;
+}
diff --git a/usr/src/lib/sasl_plugins/digestmd5/Makefile b/usr/src/lib/sasl_plugins/digestmd5/Makefile
new file mode 100644
index 0000000000..4897cf88f3
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+include ../Makefile.subdirs
diff --git a/usr/src/lib/sasl_plugins/digestmd5/Makefile.com b/usr/src/lib/sasl_plugins/digestmd5/Makefile.com
new file mode 100644
index 0000000000..4bc19b7933
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/Makefile.com
@@ -0,0 +1,16 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+LIBRARY= digestmd5.a
+VERS= .1
+
+PLUG_OBJS= digestmd5.o digestmd5_init.o
+
+PLUG_LIBS= -lpkcs11
+ENC_FLAGS= -DUSE_UEF_SERVER=1 -DUSE_UEF_CLIENT=1 -DUSE_UEF=1
+
+# include common definitions
+include ../../Makefile.com
diff --git a/usr/src/lib/sasl_plugins/digestmd5/amd64/Makefile b/usr/src/lib/sasl_plugins/digestmd5/amd64/Makefile
new file mode 100644
index 0000000000..13ae0db12d
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/amd64/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64)
diff --git a/usr/src/lib/sasl_plugins/digestmd5/digestmd5.c b/usr/src/lib/sasl_plugins/digestmd5/digestmd5.c
new file mode 100644
index 0000000000..3b5733d3af
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/digestmd5.c
@@ -0,0 +1,5433 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* DIGEST-MD5 SASL plugin
+ * Rob Siemborski
+ * Tim Martin
+ * Alexey Melnikov
+ * $Id: digestmd5.c,v 1.153 2003/03/30 22:17:06 leg Exp $
+ */
+/*
+ * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Office of Technology Transfer
+ * Carnegie Mellon University
+ * 5000 Forbes Avenue
+ * Pittsburgh, PA 15213-3890
+ * (412) 268-4387, fax: (412) 268-7395
+ * tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef macintosh
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <ctype.h>
+
+/* EXPORT DELETE START */
+/* DES support */
+#ifdef WITH_DES
+# ifdef WITH_SSL_DES
+# include <openssl/des.h>
+# else /* system DES library */
+# include <des.h>
+# endif
+#endif /* WITH_DES */
+/* EXPORT DELETE END */
+
+#ifdef WIN32
+# include <winsock.h>
+#else /* Unix */
+# include <netinet/in.h>
+#endif /* WIN32 */
+
+#ifdef _SUN_SDK_
+#include <unistd.h>
+#endif /* _SUN_SDK_ */
+
+#include <sasl.h>
+#include <saslplug.h>
+
+#include "plugin_common.h"
+
+#if defined _SUN_SDK_ && defined USE_UEF
+#include <security/cryptoki.h>
+static int uef_init(const sasl_utils_t *utils);
+#endif /* _SUN_SDK_ && USE_UEF */
+
+#ifndef WIN32
+extern int strcasecmp(const char *s1, const char *s2);
+#endif /* end WIN32 */
+
+#ifdef macintosh
+#include <sasl_md5_plugin_decl.h>
+#endif
+
+/* external definitions */
+
+#ifndef _SUN_SDK_
+#ifdef sun
+/* gotta define gethostname ourselves on suns */
+extern int gethostname(char *, int);
+#endif
+#endif /* !_SUN_SDK_ */
+
+#define bool int
+
+#ifndef TRUE
+#define TRUE (1)
+#define FALSE (0)
+#endif
+
+#define DEFAULT_BUFSIZE 0xFFFF
+
+/***************************** Common Section *****************************/
+
+#ifndef _SUN_SDK_
+static const char plugin_id[] = "$Id: digestmd5.c,v 1.153 2003/03/30 22:17:06 leg Exp $";
+#endif /* !_SUN_SDK_ */
+
+/* Definitions */
+#define NONCE_SIZE (32) /* arbitrary */
+
+/* Layer Flags */
+#define DIGEST_NOLAYER (1)
+#define DIGEST_INTEGRITY (2)
+#define DIGEST_PRIVACY (4)
+
+/* defines */
+#define HASHLEN 16
+typedef unsigned char HASH[HASHLEN + 1];
+#define HASHHEXLEN 32
+typedef unsigned char HASHHEX[HASHHEXLEN + 1];
+
+#define MAC_SIZE 10
+#define MAC_OFFS 2
+
+const char *SEALING_CLIENT_SERVER="Digest H(A1) to client-to-server sealing key magic constant";
+const char *SEALING_SERVER_CLIENT="Digest H(A1) to server-to-client sealing key magic constant";
+
+const char *SIGNING_CLIENT_SERVER="Digest session key to client-to-server signing key magic constant";
+const char *SIGNING_SERVER_CLIENT="Digest session key to server-to-client signing key magic constant";
+
+#define HT (9)
+#define CR (13)
+#define LF (10)
+#define SP (32)
+#define DEL (127)
+
+struct context;
+
+/* function definitions for cipher encode/decode */
+typedef int cipher_function_t(struct context *,
+ const char *,
+ unsigned,
+ unsigned char[],
+ char *,
+ unsigned *);
+
+#ifdef _SUN_SDK_
+typedef int cipher_init_t(struct context *, char [16],
+ char [16]);
+#else
+typedef int cipher_init_t(struct context *, unsigned char [16],
+ unsigned char [16]);
+#endif /* _SUN_SDK_ */
+
+typedef void cipher_free_t(struct context *);
+
+enum Context_type { SERVER = 0, CLIENT = 1 };
+
+typedef struct cipher_context cipher_context_t;
+
+/* cached auth info used for fast reauth */
+typedef struct reauth_entry {
+ char *authid;
+ char *realm;
+ unsigned char *nonce;
+ unsigned int nonce_count;
+ unsigned char *cnonce;
+
+ union {
+ struct {
+ time_t timestamp;
+ } s; /* server stuff */
+
+ struct {
+ char *serverFQDN;
+ int protection;
+ struct digest_cipher *cipher;
+ unsigned int server_maxbuf;
+ } c; /* client stuff */
+ } u;
+} reauth_entry_t;
+
+typedef struct reauth_cache {
+ /* static stuff */
+ enum Context_type i_am; /* are we the client or server? */
+ time_t timeout;
+ void *mutex;
+ size_t size;
+
+ reauth_entry_t *e; /* fixed-size hash table of entries */
+} reauth_cache_t;
+
+/* context that stores info */
+typedef struct context {
+ int state; /* state in the authentication we are in */
+ enum Context_type i_am; /* are we the client or server? */
+
+ reauth_cache_t *reauth;
+
+ char *authid;
+ char *realm;
+ unsigned char *nonce;
+ unsigned int nonce_count;
+ unsigned char *cnonce;
+
+ char *response_value;
+
+ unsigned int seqnum;
+ unsigned int rec_seqnum; /* for checking integrity */
+
+ HASH Ki_send;
+ HASH Ki_receive;
+
+ HASH HA1; /* Kcc or Kcs */
+
+ /* copy of utils from the params structures */
+ const sasl_utils_t *utils;
+
+ /* For general use */
+ char *out_buf;
+ unsigned out_buf_len;
+
+ /* for encoding/decoding */
+ buffer_info_t *enc_in_buf;
+ char *encode_buf, *decode_buf, *decode_once_buf;
+ unsigned encode_buf_len, decode_buf_len, decode_once_buf_len;
+ char *decode_tmp_buf;
+ unsigned decode_tmp_buf_len;
+ char *MAC_buf;
+ unsigned MAC_buf_len;
+
+ char *buffer;
+ char sizebuf[4];
+ int cursize;
+
+ /* Layer info */
+ unsigned int size; /* Absolute size of buffer */
+ unsigned int needsize; /* How much of the size of the buffer is left */
+
+ /* Server MaxBuf for Client or Client MaxBuf For Server */
+ /* INCOMING */
+ unsigned int in_maxbuf;
+
+ /* if privacy mode is used use these functions for encode and decode */
+ cipher_function_t *cipher_enc;
+ cipher_function_t *cipher_dec;
+ cipher_init_t *cipher_init;
+ cipher_free_t *cipher_free;
+ struct cipher_context *cipher_enc_context;
+ struct cipher_context *cipher_dec_context;
+} context_t;
+
+struct digest_cipher {
+ char *name;
+ sasl_ssf_t ssf;
+ int n; /* bits to make privacy key */
+ int flag; /* a bitmask to make things easier for us */
+
+ cipher_function_t *cipher_enc;
+ cipher_function_t *cipher_dec;
+ cipher_init_t *cipher_init;
+ cipher_free_t *cipher_free;
+};
+
+#ifdef _SUN_SDK_
+static const unsigned char *COLON = (unsigned char *)":";
+#else
+static const unsigned char *COLON = ":";
+#endif /* _SUN_SDK_ */
+
+/* Hashes a string to produce an unsigned short */
+static unsigned hash(const char *str)
+{
+ unsigned val = 0;
+ int i;
+
+ while (str && *str) {
+ i = (int) *str;
+ val ^= i;
+ val <<= 1;
+ str++;
+ }
+
+ return val;
+}
+
+static void CvtHex(HASH Bin, HASHHEX Hex)
+{
+ unsigned short i;
+ unsigned char j;
+
+ for (i = 0; i < HASHLEN; i++) {
+ j = (Bin[i] >> 4) & 0xf;
+ if (j <= 9)
+ Hex[i * 2] = (j + '0');
+ else
+ Hex[i * 2] = (j + 'a' - 10);
+ j = Bin[i] & 0xf;
+ if (j <= 9)
+ Hex[i * 2 + 1] = (j + '0');
+ else
+ Hex[i * 2 + 1] = (j + 'a' - 10);
+ }
+ Hex[HASHHEXLEN] = '\0';
+}
+
+/*
+ * calculate request-digest/response-digest as per HTTP Digest spec
+ */
+void
+DigestCalcResponse(const sasl_utils_t * utils,
+ HASHHEX HA1, /* H(A1) */
+ unsigned char *pszNonce, /* nonce from server */
+ unsigned int pszNonceCount, /* 8 hex digits */
+ unsigned char *pszCNonce, /* client nonce */
+ unsigned char *pszQop, /* qop-value: "", "auth",
+ * "auth-int" */
+ unsigned char *pszDigestUri, /* requested URL */
+ unsigned char *pszMethod,
+ HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
+ HASHHEX Response /* request-digest or response-digest */
+ )
+{
+ MD5_CTX Md5Ctx;
+ HASH HA2;
+ HASH RespHash;
+ HASHHEX HA2Hex;
+ char ncvalue[10];
+
+ /* calculate H(A2) */
+ utils->MD5Init(&Md5Ctx);
+
+ if (pszMethod != NULL) {
+ utils->MD5Update(&Md5Ctx, pszMethod, strlen((char *) pszMethod));
+ }
+ utils->MD5Update(&Md5Ctx, (unsigned char *) COLON, 1);
+
+ /* utils->MD5Update(&Md5Ctx, (unsigned char *) "AUTHENTICATE:", 13); */
+ utils->MD5Update(&Md5Ctx, pszDigestUri, strlen((char *) pszDigestUri));
+ if (strcasecmp((char *) pszQop, "auth") != 0) {
+ /* append ":00000000000000000000000000000000" */
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);
+ }
+ utils->MD5Final(HA2, &Md5Ctx);
+ CvtHex(HA2, HA2Hex);
+
+ /* calculate response */
+ utils->MD5Init(&Md5Ctx);
+ utils->MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ if (*pszQop) {
+ sprintf(ncvalue, "%08x", pszNonceCount);
+#ifdef _SUN_SDK_
+ utils->MD5Update(&Md5Ctx, (unsigned char *)ncvalue, strlen(ncvalue));
+#else
+ utils->MD5Update(&Md5Ctx, ncvalue, strlen(ncvalue));
+#endif /* _SUN_SDK_ */
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszQop, strlen((char *) pszQop));
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ }
+ utils->MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
+ utils->MD5Final(RespHash, &Md5Ctx);
+ CvtHex(RespHash, Response);
+}
+
+static bool UTF8_In_8859_1(const unsigned char *base, int len)
+{
+ const unsigned char *scan, *end;
+
+ end = base + len;
+ for (scan = base; scan < end; ++scan) {
+ if (*scan > 0xC3)
+ break; /* abort if outside 8859-1 */
+ if (*scan >= 0xC0 && *scan <= 0xC3) {
+ if (++scan == end || *scan < 0x80 || *scan > 0xBF)
+ break;
+ }
+ }
+
+ /* if scan >= end, then this is a 8859-1 string. */
+ return (scan >= end);
+}
+
+/*
+ * if the string is entirely in the 8859-1 subset of UTF-8, then translate to
+ * 8859-1 prior to MD5
+ */
+void MD5_UTF8_8859_1(const sasl_utils_t * utils,
+ MD5_CTX * ctx,
+ bool In_ISO_8859_1,
+ const unsigned char *base,
+ int len)
+{
+ const unsigned char *scan, *end;
+ unsigned char cbuf;
+
+ end = base + len;
+
+ /* if we found a character outside 8859-1, don't alter string */
+ if (!In_ISO_8859_1) {
+ utils->MD5Update(ctx, base, len);
+ return;
+ }
+ /* convert to 8859-1 prior to applying hash */
+ do {
+ for (scan = base; scan < end && *scan < 0xC0; ++scan);
+ if (scan != base)
+ utils->MD5Update(ctx, base, scan - base);
+ if (scan + 1 >= end)
+ break;
+ cbuf = ((scan[0] & 0x3) << 6) | (scan[1] & 0x3f);
+ utils->MD5Update(ctx, &cbuf, 1);
+ base = scan + 2;
+ }
+ while (base < end);
+}
+
+static void DigestCalcSecret(const sasl_utils_t * utils,
+ unsigned char *pszUserName,
+ unsigned char *pszRealm,
+ unsigned char *Password,
+ int PasswordLen,
+ HASH HA1)
+{
+ bool In_8859_1;
+
+ MD5_CTX Md5Ctx;
+
+ /* Chris Newman clarified that the following text in DIGEST-MD5 spec
+ is bogus: "if name and password are both in ISO 8859-1 charset"
+ We shoud use code example instead */
+
+ utils->MD5Init(&Md5Ctx);
+
+ /* We have to convert UTF-8 to ISO-8859-1 if possible */
+ In_8859_1 = UTF8_In_8859_1(pszUserName, strlen((char *) pszUserName));
+ MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
+ pszUserName, strlen((char *) pszUserName));
+
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+
+ if (pszRealm != NULL && pszRealm[0] != '\0') {
+ /* a NULL realm is equivalent to the empty string */
+ utils->MD5Update(&Md5Ctx, pszRealm, strlen((char *) pszRealm));
+ }
+
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+
+ /* We have to convert UTF-8 to ISO-8859-1 if possible */
+ In_8859_1 = UTF8_In_8859_1(Password, PasswordLen);
+ MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
+ Password, PasswordLen);
+
+ utils->MD5Final(HA1, &Md5Ctx);
+}
+
+static unsigned char *create_nonce(const sasl_utils_t * utils)
+{
+ unsigned char *base64buf;
+ int base64len;
+
+ char *ret = (char *) utils->malloc(NONCE_SIZE);
+ if (ret == NULL)
+ return NULL;
+
+#if defined _DEV_URANDOM && defined _SUN_SDK_
+ {
+ int fd = open(_DEV_URANDOM, O_RDONLY);
+ int nread = 0;
+
+ if (fd != -1) {
+ nread = read(fd, ret, NONCE_SIZE);
+ close(fd);
+ }
+ if (nread != NONCE_SIZE)
+ utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
+ }
+#else
+ utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
+#endif /* _DEV_URANDOM && _SUN_SDK_ */
+
+ /* base 64 encode it so it has valid chars */
+ base64len = (NONCE_SIZE * 4 / 3) + (NONCE_SIZE % 3 ? 4 : 0);
+
+ base64buf = (unsigned char *) utils->malloc(base64len + 1);
+ if (base64buf == NULL) {
+#ifdef _SUN_SDK_
+ utils->log(utils->conn, SASL_LOG_ERR,
+ "Unable to allocate final buffer");
+#else
+ utils->seterror(utils->conn, 0, "Unable to allocate final buffer");
+#endif /* _SUN_SDK_ */
+ return NULL;
+ }
+
+ /*
+ * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
+ */
+ if (utils->encode64(ret, NONCE_SIZE,
+ (char *) base64buf, base64len, NULL) != SASL_OK) {
+ utils->free(ret);
+ return NULL;
+ }
+ utils->free(ret);
+
+ return base64buf;
+}
+
+static int add_to_challenge(const sasl_utils_t *utils,
+ char **str, unsigned *buflen, unsigned *curlen,
+ char *name,
+ unsigned char *value,
+ bool need_quotes)
+{
+ int namesize = strlen(name);
+ int valuesize = strlen((char *) value);
+ int ret;
+
+ ret = _plug_buf_alloc(utils, str, buflen,
+ *curlen + 1 + namesize + 2 + valuesize + 2);
+ if(ret != SASL_OK) return ret;
+
+ *curlen = *curlen + 1 + namesize + 2 + valuesize + 2;
+
+ strcat(*str, ",");
+ strcat(*str, name);
+
+ if (need_quotes) {
+ strcat(*str, "=\"");
+ strcat(*str, (char *) value); /* XXX. What about quoting??? */
+ strcat(*str, "\"");
+ } else {
+ strcat(*str, "=");
+ strcat(*str, (char *) value);
+ }
+
+ return SASL_OK;
+}
+
+static char *skip_lws (char *s)
+{
+ if(!s) return NULL;
+
+ /* skipping spaces: */
+ while (s[0] == ' ' || s[0] == HT || s[0] == CR || s[0] == LF) {
+ if (s[0]=='\0') break;
+ s++;
+ }
+
+ return s;
+}
+
+#ifdef __SUN_SDK_
+static char *skip_token (char *s, int caseinsensitive __attribute__((unused)))
+#else
+static char *skip_token (char *s, int caseinsensitive)
+#endif /* _SUN_SDK_ */
+{
+ if(!s) return NULL;
+
+#ifdef __SUN_SDK_
+ while (((unsigned char *)s)[0]>SP) {
+#else
+ while (s[0]>SP) {
+#endif /* _SUN_SDK_ */
+ if (s[0]==DEL || s[0]=='(' || s[0]==')' || s[0]=='<' || s[0]=='>' ||
+ s[0]=='@' || s[0]==',' || s[0]==';' || s[0]==':' || s[0]=='\\' ||
+ s[0]=='\'' || s[0]=='/' || s[0]=='[' || s[0]==']' || s[0]== '?' ||
+ s[0]=='=' || s[0]== '{' || s[0]== '}') {
+#ifdef __SUN_SDK_
+ /* the above chars are never uppercase */
+ break;
+#else
+ if (caseinsensitive == 1) {
+ if (!isupper((unsigned char) s[0]))
+ break;
+ } else {
+ break;
+ }
+#endif /* _SUN_SDK_ */
+ }
+ s++;
+ }
+ return s;
+}
+
+/* NULL - error (unbalanced quotes),
+ otherwise pointer to the first character after value */
+static char *unquote (char *qstr)
+{
+ char *endvalue;
+ int escaped = 0;
+ char *outptr;
+
+ if(!qstr) return NULL;
+
+ if (qstr[0] == '"') {
+ qstr++;
+ outptr = qstr;
+
+ for (endvalue = qstr; endvalue[0] != '\0'; endvalue++, outptr++) {
+ if (escaped) {
+ outptr[0] = endvalue[0];
+ escaped = 0;
+ }
+ else if (endvalue[0] == '\\') {
+ escaped = 1;
+ outptr--; /* Will be incremented at the end of the loop */
+ }
+ else if (endvalue[0] == '"') {
+ break;
+ }
+ else {
+ outptr[0] = endvalue[0];
+ }
+ }
+
+ if (endvalue[0] != '"') {
+ return NULL;
+ }
+
+ while (outptr <= endvalue) {
+ outptr[0] = '\0';
+ outptr++;
+ }
+ endvalue++;
+ }
+ else { /* not qouted value (token) */
+ endvalue = skip_token(qstr,0);
+ };
+
+ return endvalue;
+}
+
+static void get_pair(char **in, char **name, char **value)
+{
+ char *endpair;
+ /* int inQuotes; */
+ char *curp = *in;
+ *name = NULL;
+ *value = NULL;
+
+ if (curp == NULL) return;
+ if (curp[0] == '\0') return;
+
+ /* skipping spaces: */
+ curp = skip_lws(curp);
+
+ *name = curp;
+
+ curp = skip_token(curp,1);
+
+ /* strip wierd chars */
+ if (curp[0] != '=' && curp[0] != '\0') {
+ *curp++ = '\0';
+ };
+
+ curp = skip_lws(curp);
+
+ if (curp[0] != '=') { /* No '=' sign */
+ *name = NULL;
+ return;
+ }
+
+ curp[0] = '\0';
+ curp++;
+
+ curp = skip_lws(curp);
+
+ *value = (curp[0] == '"') ? curp+1 : curp;
+
+ endpair = unquote (curp);
+ if (endpair == NULL) { /* Unbalanced quotes */
+ *name = NULL;
+ return;
+ }
+ if (endpair[0] != ',') {
+ if (endpair[0]!='\0') {
+ *endpair++ = '\0';
+ }
+ }
+
+ endpair = skip_lws(endpair);
+
+ /* syntax check: MUST be '\0' or ',' */
+ if (endpair[0] == ',') {
+ endpair[0] = '\0';
+ endpair++; /* skipping <,> */
+ } else if (endpair[0] != '\0') {
+ *name = NULL;
+ return;
+ }
+
+ *in = endpair;
+}
+
+/* EXPORT DELETE START */
+#ifdef WITH_DES
+struct des_context_s {
+ des_key_schedule keysched; /* key schedule for des initialization */
+ des_cblock ivec; /* initial vector for encoding */
+ des_key_schedule keysched2; /* key schedule for 3des initialization */
+};
+
+typedef struct des_context_s des_context_t;
+
+/* slide the first 7 bytes of 'inbuf' into the high seven bits of the
+ first 8 bytes of 'keybuf'. 'keybuf' better be 8 bytes long or longer. */
+static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
+{
+ keybuf[0] = inbuf[0];
+ keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
+ keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
+ keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
+ keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
+ keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
+ keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
+ keybuf[7] = (inbuf[6]<<1);
+}
+
+/******************************
+ *
+ * 3DES functions
+ *
+ *****************************/
+
+static int dec_3des(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16],
+ char *output,
+ unsigned *outputlen)
+{
+ des_context_t *c = (des_context_t *) text->cipher_dec_context;
+ int padding, p;
+
+ des_ede2_cbc_encrypt((void *) input,
+ (void *) output,
+ inputlen,
+ c->keysched,
+ c->keysched2,
+ &c->ivec,
+ DES_DECRYPT);
+
+ /* now chop off the padding */
+ padding = output[inputlen - 11];
+ if (padding < 1 || padding > 8) {
+ /* invalid padding length */
+ return SASL_FAIL;
+ }
+ /* verify all padding is correct */
+ for (p = 1; p <= padding; p++) {
+ if (output[inputlen - 10 - p] != padding) {
+ return SASL_FAIL;
+ }
+ }
+
+ /* chop off the padding */
+ *outputlen = inputlen - padding - 10;
+
+ /* copy in the HMAC to digest */
+ memcpy(digest, output + inputlen - 10, 10);
+
+ return SASL_OK;
+}
+
+static int enc_3des(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16],
+ char *output,
+ unsigned *outputlen)
+{
+ des_context_t *c = (des_context_t *) text->cipher_enc_context;
+ int len;
+ int paddinglen;
+
+ /* determine padding length */
+ paddinglen = 8 - ((inputlen + 10) % 8);
+
+ /* now construct the full stuff to be ciphered */
+ memcpy(output, input, inputlen); /* text */
+ memset(output+inputlen, paddinglen, paddinglen);/* pad */
+ memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
+
+ len=inputlen+paddinglen+10;
+
+ des_ede2_cbc_encrypt((void *) output,
+ (void *) output,
+ len,
+ c->keysched,
+ c->keysched2,
+ &c->ivec,
+ DES_ENCRYPT);
+
+ *outputlen=len;
+
+ return SASL_OK;
+}
+
+static int init_3des(context_t *text,
+ unsigned char enckey[16],
+ unsigned char deckey[16])
+{
+ des_context_t *c;
+ unsigned char keybuf[8];
+
+ /* allocate enc & dec context */
+ c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
+ if (c == NULL) return SASL_NOMEM;
+
+ /* setup enc context */
+ slidebits(keybuf, enckey);
+ if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
+ return SASL_FAIL;
+
+ slidebits(keybuf, enckey + 7);
+ if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
+ return SASL_FAIL;
+ memcpy(c->ivec, ((char *) enckey) + 8, 8);
+
+ text->cipher_enc_context = (cipher_context_t *) c;
+
+ /* setup dec context */
+ c++;
+ slidebits(keybuf, deckey);
+ if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
+ return SASL_FAIL;
+
+ slidebits(keybuf, deckey + 7);
+ if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
+ return SASL_FAIL;
+
+ memcpy(c->ivec, ((char *) deckey) + 8, 8);
+
+ text->cipher_dec_context = (cipher_context_t *) c;
+
+ return SASL_OK;
+}
+
+
+/******************************
+ *
+ * DES functions
+ *
+ *****************************/
+
+static int dec_des(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16],
+ char *output,
+ unsigned *outputlen)
+{
+ des_context_t *c = (des_context_t *) text->cipher_dec_context;
+ int p, padding = 0;
+
+ des_cbc_encrypt((void *) input,
+ (void *) output,
+ inputlen,
+ c->keysched,
+ &c->ivec,
+ DES_DECRYPT);
+
+ /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
+ this way) */
+ memcpy(c->ivec, input + (inputlen - 8), 8);
+
+ /* now chop off the padding */
+ padding = output[inputlen - 11];
+ if (padding < 1 || padding > 8) {
+ /* invalid padding length */
+ return SASL_FAIL;
+ }
+ /* verify all padding is correct */
+ for (p = 1; p <= padding; p++) {
+ if (output[inputlen - 10 - p] != padding) {
+ return SASL_FAIL;
+ }
+ }
+
+ /* chop off the padding */
+ *outputlen = inputlen - padding - 10;
+
+ /* copy in the HMAC to digest */
+ memcpy(digest, output + inputlen - 10, 10);
+
+ return SASL_OK;
+}
+
+static int enc_des(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16],
+ char *output,
+ unsigned *outputlen)
+{
+ des_context_t *c = (des_context_t *) text->cipher_enc_context;
+ int len;
+ int paddinglen;
+
+ /* determine padding length */
+ paddinglen = 8 - ((inputlen+10) % 8);
+
+ /* now construct the full stuff to be ciphered */
+ memcpy(output, input, inputlen); /* text */
+ memset(output+inputlen, paddinglen, paddinglen);/* pad */
+ memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
+
+ len = inputlen + paddinglen + 10;
+
+ des_cbc_encrypt((void *) output,
+ (void *) output,
+ len,
+ c->keysched,
+ &c->ivec,
+ DES_ENCRYPT);
+
+ /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
+ this way) */
+ memcpy(c->ivec, output + (len - 8), 8);
+
+ *outputlen = len;
+
+ return SASL_OK;
+}
+
+static int init_des(context_t *text,
+ unsigned char enckey[16],
+ unsigned char deckey[16])
+{
+ des_context_t *c;
+ unsigned char keybuf[8];
+
+ /* allocate enc context */
+ c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
+ if (c == NULL) return SASL_NOMEM;
+
+ /* setup enc context */
+ slidebits(keybuf, enckey);
+ des_key_sched((des_cblock *) keybuf, c->keysched);
+
+ memcpy(c->ivec, ((char *) enckey) + 8, 8);
+
+ text->cipher_enc_context = (cipher_context_t *) c;
+
+ /* setup dec context */
+ c++;
+ slidebits(keybuf, deckey);
+ des_key_sched((des_cblock *) keybuf, c->keysched);
+
+ memcpy(c->ivec, ((char *) deckey) + 8, 8);
+
+ text->cipher_dec_context = (cipher_context_t *) c;
+
+ return SASL_OK;
+}
+
+static void free_des(context_t *text)
+{
+ /* free des contextss. only cipher_enc_context needs to be free'd,
+ since cipher_dec_context was allocated at the same time. */
+ if (text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
+}
+
+#endif /* WITH_DES */
+
+#ifdef WITH_RC4
+/* quick generic implementation of RC4 */
+struct rc4_context_s {
+ unsigned char sbox[256];
+ int i, j;
+};
+
+typedef struct rc4_context_s rc4_context_t;
+
+static void rc4_init(rc4_context_t *text,
+ const unsigned char *key,
+ unsigned keylen)
+{
+ int i, j;
+
+ /* fill in linearly s0=0 s1=1... */
+ for (i=0;i<256;i++)
+ text->sbox[i]=i;
+
+ j=0;
+ for (i = 0; i < 256; i++) {
+ unsigned char tmp;
+ /* j = (j + Si + Ki) mod 256 */
+ j = (j + text->sbox[i] + key[i % keylen]) % 256;
+
+ /* swap Si and Sj */
+ tmp = text->sbox[i];
+ text->sbox[i] = text->sbox[j];
+ text->sbox[j] = tmp;
+ }
+
+ /* counters initialized to 0 */
+ text->i = 0;
+ text->j = 0;
+}
+
+static void rc4_encrypt(rc4_context_t *text,
+ const char *input,
+ char *output,
+ unsigned len)
+{
+ int tmp;
+ int i = text->i;
+ int j = text->j;
+ int t;
+ int K;
+ const char *input_end = input + len;
+
+ while (input < input_end) {
+ i = (i + 1) % 256;
+
+ j = (j + text->sbox[i]) % 256;
+
+ /* swap Si and Sj */
+ tmp = text->sbox[i];
+ text->sbox[i] = text->sbox[j];
+ text->sbox[j] = tmp;
+
+ t = (text->sbox[i] + text->sbox[j]) % 256;
+
+ K = text->sbox[t];
+
+ /* byte K is Xor'ed with plaintext */
+ *output++ = *input++ ^ K;
+ }
+
+ text->i = i;
+ text->j = j;
+}
+
+static void rc4_decrypt(rc4_context_t *text,
+ const char *input,
+ char *output,
+ unsigned len)
+{
+ int tmp;
+ int i = text->i;
+ int j = text->j;
+ int t;
+ int K;
+ const char *input_end = input + len;
+
+ while (input < input_end) {
+ i = (i + 1) % 256;
+
+ j = (j + text->sbox[i]) % 256;
+
+ /* swap Si and Sj */
+ tmp = text->sbox[i];
+ text->sbox[i] = text->sbox[j];
+ text->sbox[j] = tmp;
+
+ t = (text->sbox[i] + text->sbox[j]) % 256;
+
+ K = text->sbox[t];
+
+ /* byte K is Xor'ed with plaintext */
+ *output++ = *input++ ^ K;
+ }
+
+ text->i = i;
+ text->j = j;
+}
+
+static void free_rc4(context_t *text)
+{
+ /* free rc4 context structures */
+
+ if(text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
+ if(text->cipher_dec_context) text->utils->free(text->cipher_dec_context);
+#ifdef _SUN_SDK_
+ text->cipher_enc_context = NULL;
+ text->cipher_dec_context = NULL;
+#endif /* _SUN_SDK_ */
+}
+
+static int init_rc4(context_t *text,
+#ifdef _SUN_SDK_
+ char enckey[16],
+ char deckey[16])
+#else
+ unsigned char enckey[16],
+ unsigned char deckey[16])
+#endif /* _SUN_SDK_ */
+{
+ /* allocate rc4 context structures */
+ text->cipher_enc_context=
+ (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
+ if (text->cipher_enc_context == NULL) return SASL_NOMEM;
+
+ text->cipher_dec_context=
+ (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
+#ifdef _SUN_SDK_
+ if (text->cipher_dec_context == NULL) {
+ text->utils->free(text->cipher_enc_context);
+ text->cipher_enc_context = NULL;
+ return SASL_NOMEM;
+ }
+#else
+ if (text->cipher_dec_context == NULL) return SASL_NOMEM;
+#endif /* _SUN_SDK_ */
+
+ /* initialize them */
+ rc4_init((rc4_context_t *) text->cipher_enc_context,
+ (const unsigned char *) enckey, 16);
+ rc4_init((rc4_context_t *) text->cipher_dec_context,
+ (const unsigned char *) deckey, 16);
+
+ return SASL_OK;
+}
+
+static int dec_rc4(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16],
+ char *output,
+ unsigned *outputlen)
+{
+ /* decrypt the text part */
+ rc4_decrypt((rc4_context_t *) text->cipher_dec_context,
+ input, output, inputlen-10);
+
+ /* decrypt the HMAC part */
+ rc4_decrypt((rc4_context_t *) text->cipher_dec_context,
+ input+(inputlen-10), (char *) digest, 10);
+
+ /* no padding so we just subtract the HMAC to get the text length */
+ *outputlen = inputlen - 10;
+
+ return SASL_OK;
+}
+
+static int enc_rc4(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16],
+ char *output,
+ unsigned *outputlen)
+{
+ /* pad is zero */
+ *outputlen = inputlen+10;
+
+ /* encrypt the text part */
+ rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
+ input,
+ output,
+ inputlen);
+
+ /* encrypt the HMAC part */
+ rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
+ (const char *) digest,
+ (output)+inputlen, 10);
+
+ return SASL_OK;
+}
+
+#endif /* WITH_RC4 */
+/* EXPORT DELETE END */
+
+struct digest_cipher available_ciphers[] =
+{
+ /* EXPORT DELETE START */
+#ifdef WITH_RC4
+ { "rc4-40", 40, 5, 0x01, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
+ { "rc4-56", 56, 7, 0x02, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
+ { "rc4", 128, 16, 0x04, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
+#endif
+#ifdef WITH_DES
+ { "des", 55, 16, 0x08, &enc_des, &dec_des, &init_des, &free_des },
+ { "3des", 112, 16, 0x10, &enc_3des, &dec_3des, &init_3des, &free_des },
+#endif
+ /* EXPORT DELETE END */
+ { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
+};
+
+
+#ifdef USE_UEF
+DEFINE_STATIC_MUTEX(uef_init_mutex);
+#define DES_CIPHER_INDEX 3
+#define DES3_CIPHER_INDEX 4
+
+static int got_uef_slot = FALSE;
+static sasl_ssf_t uef_max_ssf = 0;
+static CK_SLOT_ID rc4_slot_id;
+static CK_SLOT_ID des_slot_id;
+static CK_SLOT_ID des3_slot_id;
+
+struct uef_context_s {
+ CK_SESSION_HANDLE hSession;
+ CK_OBJECT_HANDLE hKey;
+};
+
+typedef struct uef_context_s uef_context_t;
+
+/*
+ * slide the first 7 bytes of 'inbuf' into the high seven bits of the
+ * first 8 bytes of 'keybuf'. 'inbuf' better be 8 bytes long or longer.
+ *
+ * This is used to compute the IV for "des" and "3des" as described in
+ * draft-ietf-sasl-rfc2831bis-00.txt - The IV for "des"
+ * and "3des" is the last 8 bytes of Kcc or Kcs - the encryption keys.
+ */
+
+static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
+{
+ keybuf[0] = inbuf[0];
+ keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
+ keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
+ keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
+ keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
+ keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
+ keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
+ keybuf[7] = (inbuf[6]<<1);
+}
+
+/*
+ * Create encryption and decryption session handle handles for later use.
+ * Returns SASL_OK on success - any other return indicates failure.
+ *
+ * free_uef is called to release associated resources by
+ * digestmd5_common_mech_dispose
+ */
+
+static int init_uef(context_t *text,
+ CK_KEY_TYPE keyType,
+ CK_MECHANISM_TYPE mech_type,
+ CK_SLOT_ID slot_id,
+ char enckey[16],
+ char deckey[16])
+{
+ CK_RV rv;
+ uef_context_t *enc_context;
+ uef_context_t *dec_context;
+ CK_OBJECT_CLASS class = CKO_SECRET_KEY;
+ CK_BBOOL true = TRUE;
+ static CK_MECHANISM mechanism = {CKM_RC4, NULL, 0};
+ unsigned char keybuf[24];
+ CK_ATTRIBUTE template[] = {
+ {CKA_CLASS, NULL, sizeof (class)},
+ {CKA_KEY_TYPE, NULL, sizeof (keyType)},
+ {CKA_ENCRYPT, NULL, sizeof (true)},
+ {CKA_VALUE, NULL, 16}};
+
+ template[0].pValue = &class;
+ template[1].pValue = &keyType;
+ template[2].pValue = &true;
+ if (keyType == CKK_DES || keyType == CKK_DES3) {
+ slidebits(keybuf, (unsigned char *)enckey);
+ if (keyType == CKK_DES3) {
+ slidebits(keybuf + 8, (unsigned char *)enckey + 7);
+ (void) memcpy(keybuf + 16, keybuf, 8);
+ template[3].ulValueLen = 24;
+ } else {
+ template[3].ulValueLen = 8;
+ }
+ template[3].pValue = keybuf;
+ mechanism.pParameter = enckey + 8;
+ mechanism.ulParameterLen = 8;
+ } else {
+ template[3].pValue = enckey;
+ }
+ mechanism.mechanism = mech_type;
+
+ /* allocate rc4 context structures */
+ enc_context = text->utils->malloc(sizeof (uef_context_t));
+ if (enc_context == NULL)
+ return SASL_NOMEM;
+
+ rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
+ &enc_context->hSession);
+ if (rv != CKR_OK) {
+ text->utils->free(enc_context);
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "enc C_OpenSession Failed:0x%.8X\n", rv);
+#endif
+ return SASL_FAIL;
+ }
+
+ rv = C_CreateObject(enc_context->hSession, template,
+ sizeof (template)/sizeof (template[0]), &enc_context->hKey);
+ if (rv != CKR_OK) {
+ text->utils->free(enc_context);
+ (void) C_CloseSession(enc_context->hSession);
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "enc C_CreateObject: rv = 0x%.8X\n", rv);
+#endif
+ return SASL_FAIL;
+ }
+
+ text->cipher_enc_context = (cipher_context_t *)enc_context;
+
+ /* Initialize the encryption operation in the session */
+ rv = C_EncryptInit(enc_context->hSession, &mechanism, enc_context->hKey);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_EncryptInit: rv = 0x%.8X\n", rv);
+#endif
+ return SASL_FAIL;
+ }
+
+ dec_context = text->utils->malloc(sizeof(uef_context_t));
+ if (dec_context == NULL)
+ return SASL_NOMEM;
+
+ rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
+ &dec_context->hSession);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "dec C_OpenSession Failed:0x%.8X\n", rv);
+#endif
+ text->utils->free(dec_context);
+ return SASL_FAIL;
+ }
+
+ template[2].type = CKA_DECRYPT;
+ if (keyType == CKK_DES || keyType == CKK_DES3) {
+ slidebits(keybuf, (unsigned char *)deckey);
+ if (keyType == CKK_DES3) {
+ slidebits(keybuf + 8, (unsigned char *)deckey + 7);
+ (void) memcpy(keybuf + 16, keybuf, 8);
+ }
+ mechanism.pParameter = deckey + 8;
+ } else {
+ template[3].pValue = deckey;
+ }
+
+ rv = C_CreateObject(dec_context->hSession, template,
+ sizeof (template)/sizeof (template[0]), &dec_context->hKey);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "dec C_CreateObject: rv = 0x%.8X\n", rv);
+#endif
+ (void) C_CloseSession(dec_context->hSession);
+ text->utils->free(dec_context);
+ return SASL_FAIL;
+ }
+ text->cipher_dec_context = (cipher_context_t *)dec_context;
+
+ /* Initialize the decryption operation in the session */
+ rv = C_DecryptInit(dec_context->hSession, &mechanism, dec_context->hKey);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_DecryptInit: rv = 0x%.8X\n", rv);
+#endif
+ return SASL_FAIL;
+ }
+
+ return SASL_OK;
+}
+
+static int init_rc4_uef(context_t *text,
+ char enckey[16],
+ char deckey[16])
+{
+ return init_uef(text, CKK_RC4, CKM_RC4, rc4_slot_id, enckey, deckey);
+}
+
+static int init_des_uef(context_t *text,
+ char enckey[16],
+ char deckey[16])
+{
+ return init_uef(text, CKK_DES, CKM_DES_CBC, des_slot_id, enckey, deckey);
+}
+
+static int init_3des_uef(context_t *text,
+ char enckey[16],
+ char deckey[16])
+{
+ return init_uef(text, CKK_DES3, CKM_DES3_CBC, des3_slot_id, enckey, deckey);
+}
+
+static void
+free_uef(context_t *text)
+{
+ uef_context_t *enc_context =
+ (uef_context_t *)text->cipher_enc_context;
+ uef_context_t *dec_context =
+ (uef_context_t *)text->cipher_dec_context;
+ CK_RV rv;
+ unsigned char buf[1];
+ CK_ULONG ulLen = 0;
+
+
+ if (enc_context != NULL) {
+ rv = C_EncryptFinal(enc_context->hSession, buf, &ulLen);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_EncryptFinal failed:0x%.8X\n", rv);
+#endif
+ }
+ rv = C_DestroyObject(enc_context->hSession, enc_context->hKey);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_DestroyObject failed:0x%.8X\n", rv);
+#endif
+ }
+ rv = C_CloseSession(enc_context->hSession);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_CloseSession failed:0x%.8X\n", rv);
+#endif
+ }
+ text->utils->free(enc_context);
+ }
+ if (dec_context != NULL) {
+ rv = C_DecryptFinal(dec_context->hSession, buf, &ulLen);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_DecryptFinal failed:0x%.8X\n", rv);
+#endif
+ }
+ rv = C_DestroyObject(dec_context->hSession, dec_context->hKey);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_DestroyObject failed:0x%.8X\n", rv);
+#endif
+ }
+
+ rv = C_CloseSession(dec_context->hSession);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_CloseSession failed:0x%.8X\n", rv);
+#endif
+ }
+ text->utils->free(dec_context);
+ }
+ text->cipher_enc_context = NULL;
+ text->cipher_dec_context = NULL;
+}
+
+static int
+dec_rc4_uef(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16],
+ char *output,
+ unsigned *outputlen)
+{
+ CK_RV rv;
+ uef_context_t *dec_context =
+ (uef_context_t *)text->cipher_dec_context;
+ CK_ULONG ulDataLen = *outputlen - MAC_SIZE;
+ CK_ULONG ulDigestLen = MAC_SIZE;
+
+ rv = C_DecryptUpdate(dec_context->hSession, (CK_BYTE_PTR)input,
+ inputlen - MAC_SIZE, (CK_BYTE_PTR)output, &ulDataLen);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_DecryptUpdate failed:0x%.8X\n", rv);
+#endif
+ return SASL_FAIL;
+ }
+ *outputlen = (unsigned)ulDataLen;
+
+ rv = C_DecryptUpdate(dec_context->hSession,
+ (CK_BYTE_PTR)input+(inputlen-MAC_SIZE), MAC_SIZE, (CK_BYTE_PTR)digest,
+ &ulDigestLen);
+ if (rv != CKR_OK || ulDigestLen != MAC_SIZE) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_DecryptUpdate:0x%.8X, digestLen:%d\n",
+ rv, ulDigestLen);
+#endif
+ return SASL_FAIL;
+ }
+
+ return SASL_OK;
+}
+
+static int
+enc_rc4_uef(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16],
+ char *output,
+ unsigned *outputlen)
+{
+ CK_RV rv;
+ uef_context_t *enc_context =
+ (uef_context_t *)text->cipher_enc_context;
+ CK_ULONG ulDataLen = inputlen;
+ CK_ULONG ulDigestLen = MAC_SIZE;
+
+ rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)input, inputlen,
+ (CK_BYTE_PTR)output, &ulDataLen);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_EncryptUpdate failed: 0x%.8X "
+ "inputlen:%d outputlen:%d\n",
+ rv, inputlen, ulDataLen);
+#endif
+ return SASL_FAIL;
+ }
+ rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)digest, MAC_SIZE,
+ (CK_BYTE_PTR)output + inputlen, &ulDigestLen);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_EncryptUpdate failed: 0x%.8X ulDigestLen:%d\n",
+ rv, ulDigestLen);
+#endif
+ return SASL_FAIL;
+ }
+
+ *outputlen = ulDataLen + ulDigestLen;
+
+ return SASL_OK;
+}
+
+static int
+dec_des_uef(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16],
+ char *output,
+ unsigned *outputlen)
+{
+ CK_RV rv;
+ uef_context_t *dec_context =
+ (uef_context_t *)text->cipher_dec_context;
+ CK_ULONG ulDataLen = inputlen;
+ int padding, p;
+
+ rv = C_DecryptUpdate(dec_context->hSession, (CK_BYTE_PTR)input,
+ inputlen, (CK_BYTE_PTR)output, &ulDataLen);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_DecryptUpdate failed:0x%.8X\n", rv);
+#endif
+ return SASL_FAIL;
+ }
+ if (ulDataLen != inputlen) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_DecryptUpdate unexpected data len:%d !=%d\n",
+ inputlen, ulDataLen);
+#endif
+ return SASL_BUFOVER;
+ }
+
+ /* now chop off the padding */
+ padding = output[inputlen - 11];
+ if (padding < 1 || padding > 8) {
+ /* invalid padding length */
+ return SASL_BADMAC;
+ }
+ /* verify all padding is correct */
+ for (p = 1; p <= padding; p++) {
+ if (output[inputlen - MAC_SIZE - p] != padding) {
+ return SASL_BADMAC;
+ }
+ }
+
+ /* chop off the padding */
+ *outputlen = inputlen - padding - MAC_SIZE;
+
+ /* copy in the HMAC to digest */
+ memcpy(digest, output + inputlen - MAC_SIZE, MAC_SIZE);
+
+ return SASL_OK;
+}
+
+static int
+enc_des_uef(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16],
+ char *output,
+ unsigned *outputlen)
+{
+ CK_RV rv;
+ uef_context_t *enc_context =
+ (uef_context_t *)text->cipher_enc_context;
+ CK_ULONG ulDataLen;
+ int paddinglen;
+
+ /* determine padding length */
+ paddinglen = 8 - ((inputlen + MAC_SIZE) % 8);
+
+ /* now construct the full stuff to be ciphered */
+ memcpy(output, input, inputlen); /* text */
+ memset(output+inputlen, paddinglen, paddinglen);/* pad */
+ memcpy(output+inputlen+paddinglen, digest, MAC_SIZE); /* hmac */
+
+ ulDataLen=inputlen+paddinglen+MAC_SIZE;
+
+ rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)output, ulDataLen,
+ (CK_BYTE_PTR)output, &ulDataLen);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
+ "C_EncryptUpdate failed: 0x%.8X "
+ "inputlen:%d outputlen:%d\n",
+ rv, ulDataLen, ulDataLen);
+#endif
+ return SASL_FAIL;
+ }
+ *outputlen = (unsigned)ulDataLen;
+
+ return SASL_OK;
+}
+
+struct digest_cipher uef_ciphers[] =
+{
+ { "rc4-40", 40, 5, 0x01, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
+ &free_uef },
+ { "rc4-56", 56, 7, 0x02, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
+ &free_uef },
+ { "rc4", 128, 16, 0x04, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
+ &free_uef },
+ { "des", 55, 16, 0x08, &enc_des_uef, &dec_des_uef, &init_des_uef,
+ &free_uef },
+ { "3des", 112, 16, 0x10, &enc_des_uef, &dec_des_uef, &init_3des_uef,
+ &free_uef },
+ { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
+};
+
+struct digest_cipher *available_ciphers1 = uef_ciphers;
+#endif /* USE_UEF */
+
+static int create_layer_keys(context_t *text,
+ const sasl_utils_t *utils,
+ HASH key, int keylen,
+ char enckey[16], char deckey[16])
+{
+ MD5_CTX Md5Ctx;
+
+ utils->MD5Init(&Md5Ctx);
+ utils->MD5Update(&Md5Ctx, key, keylen);
+ if (text->i_am == SERVER) {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_SERVER_CLIENT,
+ strlen(SEALING_SERVER_CLIENT));
+ } else {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_CLIENT_SERVER,
+ strlen(SEALING_CLIENT_SERVER));
+ }
+ utils->MD5Final((unsigned char *) enckey, &Md5Ctx);
+
+ utils->MD5Init(&Md5Ctx);
+ utils->MD5Update(&Md5Ctx, key, keylen);
+ if (text->i_am != SERVER) {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *)SEALING_SERVER_CLIENT,
+ strlen(SEALING_SERVER_CLIENT));
+ } else {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *)SEALING_CLIENT_SERVER,
+ strlen(SEALING_CLIENT_SERVER));
+ }
+ utils->MD5Final((unsigned char *) deckey, &Md5Ctx);
+
+ /* create integrity keys */
+ /* sending */
+ utils->MD5Init(&Md5Ctx);
+ utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
+ if (text->i_am == SERVER) {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT,
+ strlen(SIGNING_SERVER_CLIENT));
+ } else {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
+ strlen(SIGNING_CLIENT_SERVER));
+ }
+ utils->MD5Final(text->Ki_send, &Md5Ctx);
+
+ /* receiving */
+ utils->MD5Init(&Md5Ctx);
+ utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
+ if (text->i_am != SERVER) {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT,
+ strlen(SIGNING_SERVER_CLIENT));
+ } else {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
+ strlen(SIGNING_CLIENT_SERVER));
+ }
+ utils->MD5Final(text->Ki_receive, &Md5Ctx);
+
+ return SASL_OK;
+}
+
+static const unsigned short version = 1;
+
+/* len, CIPHER(Kc, {msg, pag, HMAC(ki, {SeqNum, msg})[0..9]}), x0001, SeqNum */
+
+static int
+digestmd5_privacy_encode(void *context,
+ const struct iovec *invec,
+ unsigned numiov,
+ const char **output,
+ unsigned *outputlen)
+{
+ context_t *text = (context_t *) context;
+ int tmp;
+ unsigned int tmpnum;
+ unsigned short int tmpshort;
+ int ret;
+ char *out;
+ unsigned char digest[16];
+ struct buffer_info *inblob, bufinfo;
+
+ if(!context || !invec || !numiov || !output || !outputlen) {
+ PARAMERROR(text->utils);
+ return SASL_BADPARAM;
+ }
+
+ if (numiov > 1) {
+ ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
+ if (ret != SASL_OK) return ret;
+ inblob = text->enc_in_buf;
+ } else {
+ /* avoid the data copy */
+ bufinfo.data = invec[0].iov_base;
+ bufinfo.curlen = invec[0].iov_len;
+ inblob = &bufinfo;
+ }
+
+ /* make sure the output buffer is big enough for this blob */
+ ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
+ &(text->encode_buf_len),
+ (4 + /* for length */
+ inblob->curlen + /* for content */
+ 10 + /* for MAC */
+ 8 + /* maximum pad */
+ 6 + /* for padding */
+ 1)); /* trailing null */
+ if(ret != SASL_OK) return ret;
+
+ /* skip by the length for now */
+ out = (text->encode_buf)+4;
+
+ /* construct (seqnum, msg) */
+ /* We can just use the output buffer because it's big enough */
+ tmpnum = htonl(text->seqnum);
+ memcpy(text->encode_buf, &tmpnum, 4);
+ memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
+
+ /* HMAC(ki, (seqnum, msg) ) */
+ text->utils->hmac_md5((const unsigned char *) text->encode_buf,
+ inblob->curlen + 4,
+ text->Ki_send, HASHLEN, digest);
+
+ /* calculate the encrypted part */
+ text->cipher_enc(text, inblob->data, inblob->curlen,
+ digest, out, outputlen);
+ out+=(*outputlen);
+
+ /* copy in version */
+ tmpshort = htons(version);
+ memcpy(out, &tmpshort, 2); /* 2 bytes = version */
+
+ out+=2;
+ (*outputlen)+=2; /* for version */
+
+ /* put in seqnum */
+ tmpnum = htonl(text->seqnum);
+ memcpy(out, &tmpnum, 4); /* 4 bytes = seq # */
+
+ (*outputlen)+=4; /* for seqnum */
+
+ /* put the 1st 4 bytes in */
+ tmp=htonl(*outputlen);
+ memcpy(text->encode_buf, &tmp, 4);
+
+ (*outputlen)+=4;
+
+ *output = text->encode_buf;
+ text->seqnum++;
+
+ return SASL_OK;
+}
+
+static int
+digestmd5_privacy_decode_once(void *context,
+ const char **input,
+ unsigned *inputlen,
+ char **output,
+ unsigned *outputlen)
+{
+ context_t *text = (context_t *) context;
+ unsigned int tocopy;
+ unsigned diff;
+ int result;
+ unsigned char digest[16];
+ int tmpnum;
+ int lup;
+
+ if (text->needsize>0) /* 4 bytes for how long message is */
+ {
+ /* if less than 4 bytes just copy those we have into text->size */
+ if (*inputlen<4)
+ tocopy=*inputlen;
+ else
+ tocopy=4;
+
+ if (tocopy>text->needsize)
+ tocopy=text->needsize;
+
+ memcpy(text->sizebuf+4-text->needsize, *input, tocopy);
+ text->needsize-=tocopy;
+
+ *input+=tocopy;
+ *inputlen-=tocopy;
+
+ if (text->needsize==0) /* got all of size */
+ {
+ memcpy(&(text->size), text->sizebuf, 4);
+ text->cursize=0;
+ text->size=ntohl(text->size);
+
+ if (text->size > text->in_maxbuf) {
+ return SASL_FAIL; /* too big probably error */
+ }
+
+ if(!text->buffer)
+ text->buffer=text->utils->malloc(text->size+5);
+ else
+ text->buffer=text->utils->realloc(text->buffer,
+ text->size+5);
+ if (text->buffer == NULL) return SASL_NOMEM;
+ }
+
+ *outputlen=0;
+ *output=NULL;
+ if (*inputlen==0) /* have to wait until next time for data */
+ return SASL_OK;
+
+ if (text->size==0) /* should never happen */
+ return SASL_FAIL;
+ }
+
+ diff=text->size - text->cursize; /* bytes need for full message */
+
+ if (! text->buffer)
+ return SASL_FAIL;
+
+ if (*inputlen < diff) /* not enough for a decode */
+ {
+ memcpy(text->buffer+text->cursize, *input, *inputlen);
+ text->cursize+=*inputlen;
+ *inputlen=0;
+ *outputlen=0;
+ *output=NULL;
+ return SASL_OK;
+ } else {
+ memcpy(text->buffer+text->cursize, *input, diff);
+ *input+=diff;
+ *inputlen-=diff;
+ }
+
+ {
+ unsigned short ver;
+ unsigned int seqnum;
+ unsigned char checkdigest[16];
+
+ result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
+ &text->decode_once_buf_len,
+ text->size-6);
+ if (result != SASL_OK)
+ return result;
+
+ *output = text->decode_once_buf;
+ *outputlen = *inputlen;
+
+ result=text->cipher_dec(text,text->buffer,text->size-6,digest,
+ *output, outputlen);
+
+ if (result!=SASL_OK)
+ return result;
+
+ {
+ int i;
+ for(i=10; i; i--) {
+ memcpy(&ver, text->buffer+text->size-i,2);
+ ver=ntohs(ver);
+ }
+ }
+
+ /* check the version number */
+ memcpy(&ver, text->buffer+text->size-6, 2);
+ ver=ntohs(ver);
+ if (ver != version)
+ {
+#ifdef _INTEGRATED_SOLARIS_
+ text->utils->seterror(text->utils->conn, 0,
+ gettext("Wrong Version"));
+#else
+ text->utils->seterror(text->utils->conn, 0, "Wrong Version");
+#endif /* _INTEGRATED_SOLARIS_ */
+ return SASL_FAIL;
+ }
+
+ /* check the CMAC */
+
+ /* construct (seqnum, msg) */
+ result = _plug_buf_alloc(text->utils, &text->decode_tmp_buf,
+ &text->decode_tmp_buf_len, *outputlen + 4);
+ if(result != SASL_OK) return result;
+
+ tmpnum = htonl(text->rec_seqnum);
+ memcpy(text->decode_tmp_buf, &tmpnum, 4);
+ memcpy(text->decode_tmp_buf + 4, *output, *outputlen);
+
+ /* HMAC(ki, (seqnum, msg) ) */
+ text->utils->hmac_md5((const unsigned char *) text->decode_tmp_buf,
+ (*outputlen) + 4,
+ text->Ki_receive, HASHLEN, checkdigest);
+
+ /* now check it */
+ for (lup=0;lup<10;lup++)
+ if (checkdigest[lup]!=digest[lup])
+ {
+#ifdef _SUN_SDK_
+ text->utils->log(text->utils->conn, SASL_LOG_ERR,
+ "CMAC doesn't match at byte %d!", lup);
+ return SASL_BADMAC;
+#else
+ text->utils->seterror(text->utils->conn, 0,
+ "CMAC doesn't match at byte %d!", lup);
+ return SASL_FAIL;
+#endif /* _SUN_SDK_ */
+ }
+
+ /* check the sequence number */
+ memcpy(&seqnum, text->buffer+text->size-4,4);
+ seqnum=ntohl(seqnum);
+
+ if (seqnum!=text->rec_seqnum)
+ {
+#ifdef _SUN_SDK_
+ text->utils->log(text->utils->conn, SASL_LOG_ERR,
+ "Incorrect Sequence Number");
+#else
+ text->utils->seterror(text->utils->conn, 0,
+ "Incorrect Sequence Number");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+ text->rec_seqnum++; /* now increment it */
+ }
+
+ text->needsize=4;
+
+ return SASL_OK;
+}
+
+static int digestmd5_privacy_decode(void *context,
+ const char *input, unsigned inputlen,
+ const char **output, unsigned *outputlen)
+{
+ context_t *text = (context_t *) context;
+ int ret;
+
+ ret = _plug_decode(text->utils, context, input, inputlen,
+ &text->decode_buf, &text->decode_buf_len, outputlen,
+ digestmd5_privacy_decode_once);
+
+ *output = text->decode_buf;
+
+ return ret;
+}
+
+static int
+digestmd5_integrity_encode(void *context,
+ const struct iovec *invec,
+ unsigned numiov,
+ const char **output,
+ unsigned *outputlen)
+{
+ context_t *text = (context_t *) context;
+ unsigned char MAC[16];
+ unsigned int tmpnum;
+ unsigned short int tmpshort;
+ struct buffer_info *inblob, bufinfo;
+ int ret;
+
+ if(!context || !invec || !numiov || !output || !outputlen) {
+ PARAMERROR( text->utils );
+ return SASL_BADPARAM;
+ }
+
+ if (numiov > 1) {
+ ret = _plug_iovec_to_buf(text->utils, invec, numiov,
+ &text->enc_in_buf);
+ if (ret != SASL_OK) return ret;
+ inblob = text->enc_in_buf;
+ } else {
+ /* avoid the data copy */
+ bufinfo.data = invec[0].iov_base;
+ bufinfo.curlen = invec[0].iov_len;
+ inblob = &bufinfo;
+ }
+
+ /* construct output */
+ *outputlen = 4 + inblob->curlen + 16;
+
+ ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
+ &(text->encode_buf_len), *outputlen);
+ if(ret != SASL_OK) return ret;
+
+ /* construct (seqnum, msg) */
+ /* we can just use the output buffer */
+ tmpnum = htonl(text->seqnum);
+ memcpy(text->encode_buf, &tmpnum, 4);
+ memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
+
+ /* HMAC(ki, (seqnum, msg) ) */
+#ifdef _SUN_SDK_
+ text->utils->hmac_md5((unsigned char *)text->encode_buf,
+ inblob->curlen + 4,
+ text->Ki_send, HASHLEN, MAC);
+#else
+ text->utils->hmac_md5(text->encode_buf, inblob->curlen + 4,
+ text->Ki_send, HASHLEN, MAC);
+#endif /* _SUN_SDK_ */
+
+ /* create MAC */
+ tmpshort = htons(version);
+ memcpy(MAC + 10, &tmpshort, MAC_OFFS); /* 2 bytes = version */
+
+ tmpnum = htonl(text->seqnum);
+ memcpy(MAC + 12, &tmpnum, 4); /* 4 bytes = sequence number */
+
+ /* copy into output */
+ tmpnum = htonl((*outputlen) - 4);
+
+ /* length of message in network byte order */
+ memcpy(text->encode_buf, &tmpnum, 4);
+ /* the message text */
+ memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
+ /* the MAC */
+ memcpy(text->encode_buf + 4 + inblob->curlen, MAC, 16);
+
+ text->seqnum++; /* add one to sequence number */
+
+ *output = text->encode_buf;
+
+ return SASL_OK;
+}
+
+static int
+create_MAC(context_t * text,
+ char *input,
+ int inputlen,
+ int seqnum,
+ unsigned char MAC[16])
+{
+ unsigned int tmpnum;
+ unsigned short int tmpshort;
+ int ret;
+
+ if (inputlen < 0)
+ return SASL_FAIL;
+
+ ret = _plug_buf_alloc(text->utils, &(text->MAC_buf),
+ &(text->MAC_buf_len), inputlen + 4);
+ if(ret != SASL_OK) return ret;
+
+ /* construct (seqnum, msg) */
+ tmpnum = htonl(seqnum);
+ memcpy(text->MAC_buf, &tmpnum, 4);
+ memcpy(text->MAC_buf + 4, input, inputlen);
+
+ /* HMAC(ki, (seqnum, msg) ) */
+#ifdef _SUN_SDK_
+ text->utils->hmac_md5((unsigned char *)text->MAC_buf, inputlen + 4,
+ text->Ki_receive, HASHLEN,
+ MAC);
+#else
+ text->utils->hmac_md5(text->MAC_buf, inputlen + 4,
+ text->Ki_receive, HASHLEN,
+ MAC);
+#endif /* _SUN_SDK_ */
+
+ /* create MAC */
+ tmpshort = htons(version);
+ memcpy(MAC + 10, &tmpshort, 2); /* 2 bytes = version */
+
+ tmpnum = htonl(seqnum);
+ memcpy(MAC + 12, &tmpnum, 4); /* 4 bytes = sequence number */
+
+ return SASL_OK;
+}
+
+static int
+check_integrity(context_t * text,
+ char *buf, int bufsize,
+ char **output, unsigned *outputlen)
+{
+ unsigned char MAC[16];
+ int result;
+
+ result = create_MAC(text, buf, bufsize - 16, text->rec_seqnum, MAC);
+ if (result != SASL_OK)
+ return result;
+
+ /* make sure the MAC is right */
+ if (strncmp((char *) MAC, buf + bufsize - 16, 16) != 0)
+ {
+#ifdef _SUN_SDK_
+ text->utils->log(text->utils->conn, SASL_LOG_ERR,
+ "MAC doesn't match");
+ return SASL_BADMAC;
+#else
+ text->utils->seterror(text->utils->conn, 0, "MAC doesn't match");
+ return SASL_FAIL;
+#endif /* _SUN_SDK_ */
+ }
+
+ text->rec_seqnum++;
+
+ /* ok make output message */
+ result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
+ &text->decode_once_buf_len,
+ bufsize - 15);
+ if (result != SASL_OK)
+ return result;
+
+ *output = text->decode_once_buf;
+ memcpy(*output, buf, bufsize - 16);
+ *outputlen = bufsize - 16;
+ (*output)[*outputlen] = 0;
+
+ return SASL_OK;
+}
+
+static int
+digestmd5_integrity_decode_once(void *context,
+ const char **input,
+ unsigned *inputlen,
+ char **output,
+ unsigned *outputlen)
+{
+ context_t *text = (context_t *) context;
+ unsigned int tocopy;
+ unsigned diff;
+ int result;
+
+ if (text->needsize > 0) { /* 4 bytes for how long message is */
+ /*
+ * if less than 4 bytes just copy those we have into text->size
+ */
+ if (*inputlen < 4)
+ tocopy = *inputlen;
+ else
+ tocopy = 4;
+
+ if (tocopy > text->needsize)
+ tocopy = text->needsize;
+
+ memcpy(text->sizebuf + 4 - text->needsize, *input, tocopy);
+ text->needsize -= tocopy;
+
+ *input += tocopy;
+ *inputlen -= tocopy;
+
+ if (text->needsize == 0) { /* got all of size */
+ memcpy(&(text->size), text->sizebuf, 4);
+ text->cursize = 0;
+ text->size = ntohl(text->size);
+
+ if (text->size > text->in_maxbuf)
+ return SASL_FAIL; /* too big probably error */
+
+ if(!text->buffer)
+ text->buffer=text->utils->malloc(text->size+5);
+ else
+ text->buffer=text->utils->realloc(text->buffer,text->size+5);
+ if (text->buffer == NULL) return SASL_NOMEM;
+ }
+ *outputlen = 0;
+ *output = NULL;
+ if (*inputlen == 0) /* have to wait until next time for data */
+ return SASL_OK;
+
+ if (text->size == 0) /* should never happen */
+ return SASL_FAIL;
+ }
+ diff = text->size - text->cursize; /* bytes need for full message */
+
+ if(! text->buffer)
+ return SASL_FAIL;
+
+ if (*inputlen < diff) { /* not enough for a decode */
+ memcpy(text->buffer + text->cursize, *input, *inputlen);
+ text->cursize += *inputlen;
+ *inputlen = 0;
+ *outputlen = 0;
+ *output = NULL;
+ return SASL_OK;
+ } else {
+ memcpy(text->buffer + text->cursize, *input, diff);
+ *input += diff;
+ *inputlen -= diff;
+ }
+
+ result = check_integrity(text, text->buffer, text->size,
+ output, outputlen);
+ if (result != SASL_OK)
+ return result;
+
+ /* Reset State */
+ text->needsize = 4;
+
+ return SASL_OK;
+}
+
+static int digestmd5_integrity_decode(void *context,
+ const char *input, unsigned inputlen,
+ const char **output, unsigned *outputlen)
+{
+ context_t *text = (context_t *) context;
+ int ret;
+
+ ret = _plug_decode(text->utils, context, input, inputlen,
+ &text->decode_buf, &text->decode_buf_len, outputlen,
+ digestmd5_integrity_decode_once);
+
+ *output = text->decode_buf;
+
+ return ret;
+}
+
+static void
+digestmd5_common_mech_dispose(void *conn_context, const sasl_utils_t *utils)
+{
+ context_t *text = (context_t *) conn_context;
+
+ if (!text || !utils) return;
+
+ if (text->authid) utils->free(text->authid);
+ if (text->realm) utils->free(text->realm);
+ if (text->nonce) utils->free(text->nonce);
+ if (text->cnonce) utils->free(text->cnonce);
+
+ if (text->cipher_free) text->cipher_free(text);
+
+ /* free the stuff in the context */
+ if (text->response_value) utils->free(text->response_value);
+
+ if (text->buffer) utils->free(text->buffer);
+ if (text->encode_buf) utils->free(text->encode_buf);
+ if (text->decode_buf) utils->free(text->decode_buf);
+ if (text->decode_once_buf) utils->free(text->decode_once_buf);
+ if (text->decode_tmp_buf) utils->free(text->decode_tmp_buf);
+ if (text->out_buf) utils->free(text->out_buf);
+ if (text->MAC_buf) utils->free(text->MAC_buf);
+
+ if (text->enc_in_buf) {
+ if (text->enc_in_buf->data) utils->free(text->enc_in_buf->data);
+ utils->free(text->enc_in_buf);
+ }
+
+ utils->free(conn_context);
+}
+
+static void
+clear_reauth_entry(reauth_entry_t *reauth, enum Context_type type,
+ const sasl_utils_t *utils)
+{
+ if (!reauth) return;
+
+ if (reauth->authid) utils->free(reauth->authid);
+ if (reauth->realm) utils->free(reauth->realm);
+ if (reauth->nonce) utils->free(reauth->nonce);
+ if (reauth->cnonce) utils->free(reauth->cnonce);
+
+ if (type == CLIENT) {
+ if (reauth->u.c.serverFQDN) utils->free(reauth->u.c.serverFQDN);
+ }
+
+ memset(reauth, 0, sizeof(reauth_entry_t));
+}
+
+static void
+digestmd5_common_mech_free(void *glob_context, const sasl_utils_t *utils)
+{
+ reauth_cache_t *reauth_cache = (reauth_cache_t *) glob_context;
+ size_t n;
+
+ if (!reauth_cache) return;
+
+ for (n = 0; n < reauth_cache->size; n++)
+ clear_reauth_entry(&reauth_cache->e[n], reauth_cache->i_am, utils);
+ if (reauth_cache->e) utils->free(reauth_cache->e);
+
+ if (reauth_cache->mutex) utils->mutex_free(reauth_cache->mutex);
+
+ utils->free(reauth_cache);
+}
+
+/***************************** Server Section *****************************/
+
+typedef struct server_context {
+ context_t common;
+
+ time_t timestamp;
+ int stale; /* last nonce is stale */
+ sasl_ssf_t limitssf, requiressf; /* application defined bounds */
+} server_context_t;
+
+static void
+DigestCalcHA1FromSecret(context_t * text,
+ const sasl_utils_t * utils,
+ HASH HA1,
+ unsigned char *authorization_id,
+ unsigned char *pszNonce,
+ unsigned char *pszCNonce,
+ HASHHEX SessionKey)
+{
+ MD5_CTX Md5Ctx;
+
+ /* calculate session key */
+ utils->MD5Init(&Md5Ctx);
+ utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
+ if (authorization_id != NULL) {
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, authorization_id, strlen((char *) authorization_id));
+ }
+ utils->MD5Final(HA1, &Md5Ctx);
+
+ CvtHex(HA1, SessionKey);
+
+
+ /* save HA1 because we need it to make the privacy and integrity keys */
+ memcpy(text->HA1, HA1, sizeof(HASH));
+}
+
+static char *create_response(context_t * text,
+ const sasl_utils_t * utils,
+ unsigned char *nonce,
+ unsigned int ncvalue,
+ unsigned char *cnonce,
+ char *qop,
+ char *digesturi,
+ HASH Secret,
+ char *authorization_id,
+ char **response_value)
+{
+ HASHHEX SessionKey;
+ HASHHEX HEntity = "00000000000000000000000000000000";
+ HASHHEX Response;
+ char *result;
+
+ if (qop == NULL)
+ qop = "auth";
+
+ DigestCalcHA1FromSecret(text,
+ utils,
+ Secret,
+ (unsigned char *) authorization_id,
+ nonce,
+ cnonce,
+ SessionKey);
+
+ DigestCalcResponse(utils,
+ SessionKey,/* H(A1) */
+ nonce, /* nonce from server */
+ ncvalue, /* 8 hex digits */
+ cnonce, /* client nonce */
+ (unsigned char *) qop, /* qop-value: "", "auth",
+ * "auth-int" */
+ (unsigned char *) digesturi, /* requested URL */
+ (unsigned char *) "AUTHENTICATE",
+ HEntity, /* H(entity body) if qop="auth-int" */
+ Response /* request-digest or response-digest */
+ );
+
+ result = utils->malloc(HASHHEXLEN + 1);
+#ifdef _SUN_SDK_
+ if (result == NULL)
+ return NULL;
+#endif /* _SUN_SDK_ */
+/* TODO */
+ memcpy(result, Response, HASHHEXLEN);
+ result[HASHHEXLEN] = 0;
+
+ /* response_value (used for reauth i think */
+ if (response_value != NULL) {
+ DigestCalcResponse(utils,
+ SessionKey, /* H(A1) */
+ nonce, /* nonce from server */
+ ncvalue, /* 8 hex digits */
+ cnonce, /* client nonce */
+ (unsigned char *) qop, /* qop-value: "", "auth",
+ * "auth-int" */
+ (unsigned char *) digesturi, /* requested URL */
+ NULL,
+ HEntity, /* H(entity body) if qop="auth-int" */
+ Response /* request-digest or response-digest */
+ );
+
+ *response_value = utils->malloc(HASHHEXLEN + 1);
+ if (*response_value == NULL)
+ return NULL;
+ memcpy(*response_value, Response, HASHHEXLEN);
+ (*response_value)[HASHHEXLEN] = 0;
+ }
+ return result;
+}
+
+static int
+get_server_realm(sasl_server_params_t * params,
+ char **realm)
+{
+ /* look at user realm first */
+ if (params->user_realm != NULL) {
+ if(params->user_realm[0] != '\0') {
+ *realm = (char *) params->user_realm;
+ } else {
+ /* Catch improperly converted apps */
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "user_realm is an empty string!");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "user_realm is an empty string!");
+#endif /* _SUN_SDK_ */
+ return SASL_BADPARAM;
+ }
+ } else if (params->serverFQDN != NULL) {
+ *realm = (char *) params->serverFQDN;
+ } else {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "no way to obtain domain");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "no way to obtain domain");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+ return SASL_OK;
+}
+
+/*
+ * Convert hex string to int
+ */
+static int htoi(unsigned char *hexin, unsigned int *res)
+{
+ int lup, inlen;
+ inlen = strlen((char *) hexin);
+
+ *res = 0;
+ for (lup = 0; lup < inlen; lup++) {
+ switch (hexin[lup]) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ *res = (*res << 4) + (hexin[lup] - '0');
+ break;
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ *res = (*res << 4) + (hexin[lup] - 'a' + 10);
+ break;
+
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ *res = (*res << 4) + (hexin[lup] - 'A' + 10);
+ break;
+
+ default:
+ return SASL_BADPARAM;
+ }
+
+ }
+
+ return SASL_OK;
+}
+
+static int digestmd5_server_mech_new(void *glob_context,
+ sasl_server_params_t * sparams,
+ const char *challenge __attribute__((unused)),
+ unsigned challen __attribute__((unused)),
+ void **conn_context)
+{
+ context_t *text;
+
+ /* holds state are in -- allocate server size */
+ text = sparams->utils->malloc(sizeof(server_context_t));
+ if (text == NULL)
+ return SASL_NOMEM;
+ memset(text, 0, sizeof(server_context_t));
+
+ text->state = 1;
+ text->i_am = SERVER;
+ text->reauth = glob_context;
+
+ *conn_context = text;
+ return SASL_OK;
+}
+
+static int
+digestmd5_server_mech_step1(server_context_t *stext,
+ sasl_server_params_t *sparams,
+ const char *clientin __attribute__((unused)),
+ unsigned clientinlen __attribute__((unused)),
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t * oparams __attribute__((unused)))
+{
+ context_t *text = (context_t *) stext;
+ int result;
+ char *realm;
+ unsigned char *nonce;
+ char *charset = "utf-8";
+ char qop[1024], cipheropts[1024];
+ struct digest_cipher *cipher;
+ unsigned resplen;
+ int added_conf = 0;
+ char maxbufstr[64];
+
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 server step 1");
+
+ /* get realm */
+ result = get_server_realm(sparams, &realm);
+ if(result != SASL_OK) return result;
+
+ /* what options should we offer the client? */
+ qop[0] = '\0';
+ cipheropts[0] = '\0';
+ if (stext->requiressf == 0) {
+ if (*qop) strcat(qop, ",");
+ strcat(qop, "auth");
+ }
+ if (stext->requiressf <= 1 && stext->limitssf >= 1) {
+ if (*qop) strcat(qop, ",");
+ strcat(qop, "auth-int");
+ }
+
+#ifdef USE_UEF_SERVER
+ cipher = available_ciphers1;
+#else
+ cipher = available_ciphers;
+#endif
+ while (cipher->name) {
+ /* do we allow this particular cipher? */
+ if (stext->requiressf <= cipher->ssf &&
+ stext->limitssf >= cipher->ssf) {
+ if (!added_conf) {
+ if (*qop) strcat(qop, ",");
+ strcat(qop, "auth-conf");
+ added_conf = 1;
+ }
+#ifdef _SUN_SDK_
+ if(strlen(cipheropts) + strlen(cipher->name) + 1 >=
+ sizeof (cipheropts)) {
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "internal error: cipheropts too big");
+ return SASL_FAIL;
+ }
+#endif /* _SUN_SDK_ */
+ if (*cipheropts) strcat(cipheropts, ",");
+ strcat(cipheropts, cipher->name);
+ }
+ cipher++;
+ }
+
+ if (*qop == '\0') {
+ /* we didn't allow anything?!? we'll return SASL_TOOWEAK, since
+ that's close enough */
+ return SASL_TOOWEAK;
+ }
+
+ /*
+ * digest-challenge = 1#( realm | nonce | qop-options | stale | maxbuf |
+ * charset | cipher-opts | auth-param )
+ */
+
+#ifndef _SUN_SDK_
+ /* FIXME: get nonce XXX have to clean up after self if fail */
+#endif /* !_SUN_SDK_ */
+ nonce = create_nonce(sparams->utils);
+ if (nonce == NULL) {
+#ifdef _SUN_SDK_
+ /* Note typo below */
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "internal error: failed creating a nonce");
+#else
+ SETERROR(sparams->utils, "internal erorr: failed creating a nonce");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+#ifdef _SUN_SDK_
+ resplen = strlen((char *)nonce) + strlen("nonce") + 5;
+#else
+ resplen = strlen(nonce) + strlen("nonce") + 5;
+#endif /* _SUN_SDK_ */
+ result = _plug_buf_alloc(sparams->utils, &(text->out_buf),
+ &(text->out_buf_len), resplen);
+#ifdef _SUN_SDK_
+ if(result != SASL_OK) {
+ sparams->utils->free(nonce);
+ return result;
+ }
+#else
+ if(result != SASL_OK) return result;
+#endif /* _SUN_SDK_ */
+
+ sprintf(text->out_buf, "nonce=\"%s\"", nonce);
+
+ /* add to challenge; if we chose not to specify a realm, we won't
+ * send one to the client */
+ if (realm && add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "realm", (unsigned char *) realm,
+ TRUE) != SASL_OK) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "internal error: add_to_challenge failed");
+ sparams->utils->free(nonce);
+#else
+ SETERROR(sparams->utils, "internal error: add_to_challenge failed");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+ /*
+ * qop-options A quoted string of one or more tokens indicating the
+ * "quality of protection" values supported by the server. The value
+ * "auth" indicates authentication; the value "auth-int" indicates
+ * authentication with integrity protection; the value "auth-conf"
+ * indicates authentication with integrity protection and encryption.
+ */
+
+ /* add qop to challenge */
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "qop",
+ (unsigned char *) qop, TRUE) != SASL_OK) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "internal error: add_to_challenge 3 failed");
+ sparams->utils->free(nonce);
+#else
+ SETERROR(sparams->utils, "internal error: add_to_challenge 3 failed");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+ /*
+ * Cipheropts - list of ciphers server supports
+ */
+ /* add cipher-opts to challenge; only add if there are some */
+ if (strcmp(cipheropts,"")!=0)
+ {
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "cipher", (unsigned char *) cipheropts,
+ TRUE) != SASL_OK) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "internal error: add_to_challenge 4 failed");
+ sparams->utils->free(nonce);
+#else
+ SETERROR(sparams->utils,
+ "internal error: add_to_challenge 4 failed");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+ }
+
+ /* "stale" is true if a reauth failed because of a nonce timeout */
+ if (stext->stale &&
+ add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+#ifdef _SUN_SDK_
+ "stale", (unsigned char *)"true", FALSE) != SASL_OK) {
+ sparams->utils->free(nonce);
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "internal error: add_to_challenge failed");
+#else
+ "stale", "true", FALSE) != SASL_OK) {
+ SETERROR(sparams->utils, "internal error: add_to_challenge failed");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+ /*
+ * maxbuf A number indicating the size of the largest buffer the server
+ * is able to receive when using "auth-int". If this directive is
+ * missing, the default value is 65536. This directive may appear at most
+ * once; if multiple instances are present, the client should abort the
+ * authentication exchange.
+ */
+ if(sparams->props.maxbufsize) {
+ snprintf(maxbufstr, sizeof(maxbufstr), "%d",
+ sparams->props.maxbufsize);
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "maxbuf",
+ (unsigned char *) maxbufstr, FALSE) != SASL_OK) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "internal error: add_to_challenge 5 failed");
+#else
+ SETERROR(sparams->utils,
+ "internal error: add_to_challenge 5 failed");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+ }
+
+
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "charset",
+ (unsigned char *) charset, FALSE) != SASL_OK) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "internal error: add_to_challenge 6 failed");
+ sparams->utils->free(nonce);
+#else
+ SETERROR(sparams->utils, "internal error: add_to_challenge 6 failed");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+
+ /*
+ * algorithm
+ * This directive is required for backwards compatibility with HTTP
+ * Digest., which supports other algorithms. . This directive is
+ * required and MUST appear exactly once; if not present, or if multiple
+ * instances are present, the client should abort the authentication
+ * exchange.
+ *
+ * algorithm = "algorithm" "=" "md5-sess"
+ */
+
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "algorithm",
+ (unsigned char *) "md5-sess", FALSE)!=SASL_OK) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "internal error: add_to_challenge 7 failed");
+ sparams->utils->free(nonce);
+#else
+ SETERROR(sparams->utils, "internal error: add_to_challenge 7 failed");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+ /*
+ * The size of a digest-challenge MUST be less than 2048 bytes!!!
+ */
+ if (*serveroutlen > 2048) {
+#ifdef _SUN_SDK_
+ sparams->utils->free(nonce);
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "internal error: challenge larger than 2048 bytes");
+#else
+ SETERROR(sparams->utils,
+ "internal error: challenge larger than 2048 bytes");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+ text->authid = NULL;
+ _plug_strdup(sparams->utils, realm, &text->realm, NULL);
+ text->nonce = nonce;
+ text->nonce_count = 1;
+ text->cnonce = NULL;
+ stext->timestamp = time(0);
+
+ *serveroutlen = strlen(text->out_buf);
+ *serverout = text->out_buf;
+
+ text->state = 2;
+
+ return SASL_CONTINUE;
+}
+
+static int
+digestmd5_server_mech_step2(server_context_t *stext,
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t * oparams)
+{
+ context_t *text = (context_t *) stext;
+ /* verify digest */
+ sasl_secret_t *sec = NULL;
+ int result;
+ char *serverresponse = NULL;
+ char *username = NULL;
+ char *authorization_id = NULL;
+ char *realm = NULL;
+ unsigned char *nonce = NULL, *cnonce = NULL;
+ unsigned int noncecount = 0;
+ char *qop = NULL;
+ char *digesturi = NULL;
+ char *response = NULL;
+
+ /* setting the default value (65536) */
+ unsigned int client_maxbuf = 65536;
+ int maxbuf_count = 0; /* How many maxbuf instaces was found */
+
+ char *charset = NULL;
+ char *cipher = NULL;
+ unsigned int n=0;
+
+ HASH A1;
+
+ /* password prop_request */
+ const char *password_request[] = { SASL_AUX_PASSWORD,
+ "*cmusaslsecretDIGEST-MD5",
+ NULL };
+ unsigned len;
+ struct propval auxprop_values[2];
+
+ /* can we mess with clientin? copy it to be safe */
+ char *in_start = NULL;
+ char *in = NULL;
+
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 server step 2");
+
+ in = sparams->utils->malloc(clientinlen + 1);
+#ifdef _SUN_SDK_
+ if (!in) return SASL_NOMEM;
+#endif /* _SUN_SDK_ */
+
+ memcpy(in, clientin, clientinlen);
+ in[clientinlen] = 0;
+
+ in_start = in;
+
+
+ /* parse what we got */
+ while (in[0] != '\0') {
+ char *name = NULL, *value = NULL;
+ get_pair(&in, &name, &value);
+
+ if (name == NULL)
+ break;
+
+ /* Extracting parameters */
+
+ /*
+ * digest-response = 1#( username | realm | nonce | cnonce |
+ * nonce-count | qop | digest-uri | response | maxbuf | charset |
+ * cipher | auth-param )
+ */
+
+ if (strcasecmp(name, "username") == 0) {
+ _plug_strdup(sparams->utils, value, &username, NULL);
+ } else if (strcasecmp(name, "authzid") == 0) {
+ _plug_strdup(sparams->utils, value, &authorization_id, NULL);
+ } else if (strcasecmp(name, "cnonce") == 0) {
+ _plug_strdup(sparams->utils, value, (char **) &cnonce, NULL);
+ } else if (strcasecmp(name, "nc") == 0) {
+ if (htoi((unsigned char *) value, &noncecount) != SASL_OK) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "error converting hex to int");
+#else
+ SETERROR(sparams->utils,
+ "error converting hex to int");
+#endif /* _SUN_SDK_ */
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+ } else if (strcasecmp(name, "realm") == 0) {
+ if (realm) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "duplicate realm: authentication aborted");
+#else
+ SETERROR(sparams->utils,
+ "duplicate realm: authentication aborted");
+#endif /* _SUN_SDK_ */
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+ _plug_strdup(sparams->utils, value, &realm, NULL);
+ } else if (strcasecmp(name, "nonce") == 0) {
+ _plug_strdup(sparams->utils, value, (char **) &nonce, NULL);
+ } else if (strcasecmp(name, "qop") == 0) {
+ _plug_strdup(sparams->utils, value, &qop, NULL);
+ } else if (strcasecmp(name, "digest-uri") == 0) {
+ size_t service_len;
+
+ /*
+ * digest-uri-value = serv-type "/" host [ "/" serv-name ]
+ */
+
+ _plug_strdup(sparams->utils, value, &digesturi, NULL);
+
+ /* verify digest-uri format */
+
+ /* make sure it's the service that we're expecting */
+ service_len = strlen(sparams->service);
+ if (strncasecmp(digesturi, sparams->service, service_len) ||
+ digesturi[service_len] != '/') {
+ result = SASL_BADAUTH;
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "bad digest-uri: doesn't match service");
+#else
+ SETERROR(sparams->utils,
+ "bad digest-uri: doesn't match service");
+#endif /* _SUN_SDK_ */
+ goto FreeAllMem;
+ }
+
+ /* xxx we don't verify the hostname component */
+
+ } else if (strcasecmp(name, "response") == 0) {
+ _plug_strdup(sparams->utils, value, &response, NULL);
+ } else if (strcasecmp(name, "cipher") == 0) {
+ _plug_strdup(sparams->utils, value, &cipher, NULL);
+ } else if (strcasecmp(name, "maxbuf") == 0) {
+ maxbuf_count++;
+ if (maxbuf_count != 1) {
+ result = SASL_BADAUTH;
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "duplicate maxbuf: authentication aborted");
+#else
+ SETERROR(sparams->utils,
+ "duplicate maxbuf: authentication aborted");
+#endif /* _SUN_SDK_ */
+ goto FreeAllMem;
+ } else if (sscanf(value, "%u", &client_maxbuf) != 1) {
+ result = SASL_BADAUTH;
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "invalid maxbuf parameter");
+#else
+ SETERROR(sparams->utils, "invalid maxbuf parameter");
+#endif /* _SUN_SDK_ */
+ goto FreeAllMem;
+ } else {
+ if (client_maxbuf <= 16) {
+ result = SASL_BADAUTH;
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "maxbuf parameter too small");
+#else
+ SETERROR(sparams->utils,
+ "maxbuf parameter too small");
+#endif /* _SUN_SDK_ */
+ goto FreeAllMem;
+ }
+ }
+ } else if (strcasecmp(name, "charset") == 0) {
+ if (strcasecmp(value, "utf-8") != 0) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "client doesn't support UTF-8");
+#else
+ SETERROR(sparams->utils, "client doesn't support UTF-8");
+#endif /* _SUN_SDK_ */
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+ _plug_strdup(sparams->utils, value, &charset, NULL);
+ } else {
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
+ name, value);
+ }
+ }
+
+ /*
+ * username = "username" "=" <"> username-value <">
+ * username-value = qdstr-val cnonce = "cnonce" "=" <">
+ * cnonce-value <"> cnonce-value = qdstr-val nonce-count = "nc"
+ * "=" nc-value nc-value = 8LHEX qop = "qop" "="
+ * qop-value digest-uri = "digest-uri" "=" digest-uri-value
+ * digest-uri-value = serv-type "/" host [ "/" serv-name ] serv-type
+ * = 1*ALPHA host = 1*( ALPHA | DIGIT | "-" | "." ) service
+ * = host response = "response" "=" <"> response-value <">
+ * response-value = 32LHEX LHEX = "0" | "1" | "2" | "3" | "4" | "5" |
+ * "6" | "7" | "8" | "9" | "a" | "b" | "c" | "d" | "e" | "f" cipher =
+ * "cipher" "=" cipher-value
+ */
+ /* Verifing that all parameters was defined */
+ if ((username == NULL) ||
+ (nonce == NULL) ||
+ (noncecount == 0) ||
+ (cnonce == NULL) ||
+ (digesturi == NULL) ||
+ (response == NULL)) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "required parameters missing");
+#else
+ SETERROR(sparams->utils, "required parameters missing");
+#endif /* _SUN_SDK_ */
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+
+ if (text->state == 1) {
+ unsigned val = hash(username) % text->reauth->size;
+
+ /* reauth attempt, see if we have any info for this user */
+ if (sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+ if (text->reauth->e[val].authid &&
+ !strcmp(username, text->reauth->e[val].authid)) {
+
+ _plug_strdup(sparams->utils, text->reauth->e[val].realm,
+ &text->realm, NULL);
+#ifdef _SUN_SDK_
+ _plug_strdup(sparams->utils, (char *)text->reauth->e[val].nonce,
+ (char **) &text->nonce, NULL);
+#else
+ _plug_strdup(sparams->utils, text->reauth->e[val].nonce,
+ (char **) &text->nonce, NULL);
+#endif /* _SUN_SDK_ */
+ text->nonce_count = ++text->reauth->e[val].nonce_count;
+#ifdef _SUN_SDK_
+ _plug_strdup(sparams->utils, (char *)text->reauth->e[val].cnonce,
+ (char **) &text->cnonce, NULL);
+#else
+ _plug_strdup(sparams->utils, text->reauth->e[val].cnonce,
+ (char **) &text->cnonce, NULL);
+#endif /* _SUN_SDK_ */
+ stext->timestamp = text->reauth->e[val].u.s.timestamp;
+ }
+ sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+ }
+
+ if (!text->nonce) {
+ /* we don't have any reauth info, so bail */
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+ }
+
+ /* Sanity check the parameters */
+#ifdef _SUN_SDK_
+ if ((realm != NULL && text->realm != NULL &&
+ strcmp(realm, text->realm) != 0) ||
+ (realm == NULL && text->realm != NULL) ||
+ (realm != NULL && text->realm == NULL)) {
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "realm changed: authentication aborted");
+#else
+ if (strcmp(realm, text->realm) != 0) {
+ SETERROR(sparams->utils,
+ "realm changed: authentication aborted");
+#endif /* _SUN_SDK_ */
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+#ifdef _SUN_SDK_
+ if (strcmp((char *)nonce, (char *) text->nonce) != 0) {
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "nonce changed: authentication aborted");
+#else
+ if (strcmp(nonce, (char *) text->nonce) != 0) {
+ SETERROR(sparams->utils,
+ "nonce changed: authentication aborted");
+#endif /* _SUN_SKD_ */
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+ if (noncecount != text->nonce_count) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "incorrect nonce-count: authentication aborted");
+#else
+ SETERROR(sparams->utils,
+ "incorrect nonce-count: authentication aborted");
+#endif /* _SUN_SDK_ */
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+#ifdef _SUN_SDK_
+ if (text->cnonce && strcmp((char *)cnonce, (char *)text->cnonce) != 0) {
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "cnonce changed: authentication aborted");
+#else
+ if (text->cnonce && strcmp(cnonce, text->cnonce) != 0) {
+ SETERROR(sparams->utils,
+ "cnonce changed: authentication aborted");
+#endif /* _SUN_SDK_ */
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+
+ result = sparams->utils->prop_request(sparams->propctx, password_request);
+ if(result != SASL_OK) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "unable to request user password");
+#else
+ SETERROR(sparams->utils, "unable to resquest user password");
+#endif /* _SUN_SDK_ */
+ goto FreeAllMem;
+ }
+
+ /* this will trigger the getting of the aux properties */
+ /* Note that if we don't have an authorization id, we don't use it... */
+ result = sparams->canon_user(sparams->utils->conn,
+ username, 0, SASL_CU_AUTHID, oparams);
+ if (result != SASL_OK) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "unable canonify user and get auxprops");
+#else
+ SETERROR(sparams->utils, "unable canonify user and get auxprops");
+#endif /* _SUN_SDK_ */
+ goto FreeAllMem;
+ }
+
+ if (!authorization_id || !*authorization_id) {
+ result = sparams->canon_user(sparams->utils->conn,
+ username, 0, SASL_CU_AUTHZID, oparams);
+ } else {
+ result = sparams->canon_user(sparams->utils->conn,
+ authorization_id, 0, SASL_CU_AUTHZID,
+ oparams);
+ }
+
+ if (result != SASL_OK) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "unable to canonicalize authorization ID");
+#else
+ SETERROR(sparams->utils, "unable authorization ID");
+#endif /* _SUN_SDK_ */
+ goto FreeAllMem;
+ }
+
+ result = sparams->utils->prop_getnames(sparams->propctx, password_request,
+ auxprop_values);
+ if (result < 0 ||
+ ((!auxprop_values[0].name || !auxprop_values[0].values) &&
+ (!auxprop_values[1].name || !auxprop_values[1].values))) {
+ /* We didn't find this username */
+#ifdef _INTEGRATED_SOLARIS_
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ gettext("no secret in database"));
+#else
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "no secret in database");
+#endif /* _INTEGRATED_SOLARIS_ */
+ result = SASL_NOUSER;
+ goto FreeAllMem;
+ }
+
+ if (auxprop_values[0].name && auxprop_values[0].values) {
+ len = strlen(auxprop_values[0].values[0]);
+ if (len == 0) {
+#ifdef _INTEGRATED_SOLARIS_
+ sparams->utils->seterror(sparams->utils->conn,0,
+ gettext("empty secret"));
+#else
+ sparams->utils->seterror(sparams->utils->conn,0,
+ "empty secret");
+#endif /* _INTEGRATED_SOLARIS_ */
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+
+ sec = sparams->utils->malloc(sizeof(sasl_secret_t) + len);
+ if (!sec) {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "unable to allocate secret");
+#else
+ SETERROR(sparams->utils, "unable to allocate secret");
+#endif /* _SUN_SDK_ */
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+
+ sec->len = len;
+#ifdef _SUN_SDK_
+ strncpy((char *)sec->data, auxprop_values[0].values[0], len + 1);
+#else
+ strncpy(sec->data, auxprop_values[0].values[0], len + 1);
+#endif /* _SUN_SDK_ */
+
+ /*
+ * Verifying response obtained from client
+ *
+ * H_URP = H({ username-value,":",realm-value,":",passwd}) sec->data
+ * contains H_URP
+ */
+
+ /* Calculate the secret from the plaintext password */
+ {
+ HASH HA1;
+
+#ifdef _SUN_SDK_
+ DigestCalcSecret(sparams->utils, (unsigned char *)username,
+ (unsigned char *)text->realm, sec->data,
+ sec->len, HA1);
+#else
+ DigestCalcSecret(sparams->utils, username,
+ text->realm, sec->data, sec->len, HA1);
+#endif /* _SUN_SDK_ */
+
+ /*
+ * A1 = { H( { username-value, ":", realm-value, ":", passwd } ),
+ * ":", nonce-value, ":", cnonce-value }
+ */
+
+ memcpy(A1, HA1, HASHLEN);
+ A1[HASHLEN] = '\0';
+ }
+
+ /* We're done with sec now. Let's get rid of it */
+ _plug_free_secret(sparams->utils, &sec);
+ } else if (auxprop_values[1].name && auxprop_values[1].values) {
+ memcpy(A1, auxprop_values[1].values[0], HASHLEN);
+ A1[HASHLEN] = '\0';
+ } else {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "Have neither type of secret");
+#else
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Have neither type of secret");
+#endif /* _SUN_SDK_ */
+#ifdef _SUN_SDK_
+ result = SASL_FAIL;
+ goto FreeAllMem;
+#else
+ return SASL_FAIL;
+#endif /* _SUN_SDK_ */
+ }
+
+ /* defaulting qop to "auth" if not specified */
+ if (qop == NULL) {
+ _plug_strdup(sparams->utils, "auth", &qop, NULL);
+ }
+
+ /* check which layer/cipher to use */
+ if ((!strcasecmp(qop, "auth-conf")) && (cipher != NULL)) {
+ /* see what cipher was requested */
+ struct digest_cipher *cptr;
+
+#ifdef USE_UEF_SERVER
+ cptr = available_ciphers1;
+#else
+ cptr = available_ciphers;
+#endif
+ while (cptr->name) {
+ /* find the cipher requested & make sure it's one we're happy
+ with by policy */
+ if (!strcasecmp(cipher, cptr->name) &&
+ stext->requiressf <= cptr->ssf &&
+ stext->limitssf >= cptr->ssf) {
+ /* found it! */
+ break;
+ }
+ cptr++;
+ }
+
+ if (cptr->name) {
+ text->cipher_enc = cptr->cipher_enc;
+ text->cipher_dec = cptr->cipher_dec;
+ text->cipher_init = cptr->cipher_init;
+ text->cipher_free = cptr->cipher_free;
+ oparams->mech_ssf = cptr->ssf;
+ n = cptr->n;
+ } else {
+ /* erg? client requested something we didn't advertise! */
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_WARN,
+ "protocol violation: client requested invalid cipher");
+#ifndef _SUN_SDK_
+ SETERROR(sparams->utils, "client requested invalid cipher");
+#endif /* !_SUN_SDK_ */
+ /* Mark that we attempted security layer negotiation */
+ oparams->mech_ssf = 2;
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+
+ oparams->encode=&digestmd5_privacy_encode;
+ oparams->decode=&digestmd5_privacy_decode;
+ } else if (!strcasecmp(qop, "auth-int") &&
+ stext->requiressf <= 1 && stext->limitssf >= 1) {
+ oparams->encode = &digestmd5_integrity_encode;
+ oparams->decode = &digestmd5_integrity_decode;
+ oparams->mech_ssf = 1;
+ } else if (!strcasecmp(qop, "auth") && stext->requiressf == 0) {
+ oparams->encode = NULL;
+ oparams->decode = NULL;
+ oparams->mech_ssf = 0;
+ } else {
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "protocol violation: client requested invalid qop");
+#else
+ SETERROR(sparams->utils,
+ "protocol violation: client requested invalid qop");
+#endif /* _SUN_SDK_ */
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+
+ serverresponse = create_response(text,
+ sparams->utils,
+ text->nonce,
+ text->nonce_count,
+ cnonce,
+ qop,
+ digesturi,
+ A1,
+ authorization_id,
+ &text->response_value);
+
+ if (serverresponse == NULL) {
+#ifndef _SUN_SDK_
+ SETERROR(sparams->utils, "internal error: unable to create response");
+#endif /* !_SUN_SDK_ */
+ result = SASL_NOMEM;
+ goto FreeAllMem;
+ }
+
+ /* if ok verified */
+ if (strcmp(serverresponse, response) != 0) {
+#ifdef _INTEGRATED_SOLARIS_
+ SETERROR(sparams->utils,
+ gettext("client response doesn't match what we generated"));
+#else
+ SETERROR(sparams->utils,
+ "client response doesn't match what we generated");
+#endif /* _INTEGRATED_SOLARIS_ */
+ result = SASL_BADAUTH;
+
+ goto FreeAllMem;
+ }
+
+ /* see if our nonce expired */
+ if (text->reauth->timeout &&
+ time(0) - stext->timestamp > text->reauth->timeout) {
+#ifdef _INTEGRATED_SOLARIS_
+ SETERROR(sparams->utils, gettext("server nonce expired"));
+#else
+ SETERROR(sparams->utils, "server nonce expired");
+#endif /* _INTEGRATED_SOLARIS_ */
+ stext->stale = 1;
+ result = SASL_BADAUTH;
+
+ goto FreeAllMem;
+ }
+
+ /*
+ * nothing more to do; authenticated set oparams information
+ */
+ oparams->doneflag = 1;
+ oparams->maxoutbuf = client_maxbuf - 4;
+ if (oparams->mech_ssf > 1) {
+#ifdef _SUN_SDK_
+ if (oparams->maxoutbuf <= 25) {
+ result = SASL_BADPARAM;
+ goto FreeAllMem;
+ }
+#endif
+ /* MAC block (privacy) */
+ oparams->maxoutbuf -= 25;
+ } else if(oparams->mech_ssf == 1) {
+#ifdef _SUN_SDK_
+ if (oparams->maxoutbuf <= 16) {
+ result = SASL_BADPARAM;
+ goto FreeAllMem;
+ }
+#endif
+ /* MAC block (integrity) */
+ oparams->maxoutbuf -= 16;
+ }
+
+ oparams->param_version = 0;
+
+ text->seqnum = 0; /* for integrity/privacy */
+ text->rec_seqnum = 0; /* for integrity/privacy */
+ text->in_maxbuf =
+ sparams->props.maxbufsize ? sparams->props.maxbufsize : DEFAULT_BUFSIZE;
+ text->utils = sparams->utils;
+
+ /* used by layers */
+ text->needsize = 4;
+ text->buffer = NULL;
+
+ if (oparams->mech_ssf > 0) {
+ char enckey[16];
+ char deckey[16];
+
+ create_layer_keys(text, sparams->utils,text->HA1,n,enckey,deckey);
+
+ /* initialize cipher if need be */
+#ifdef _SUN_SDK_
+ if (text->cipher_init) {
+ if (text->cipher_free)
+ text->cipher_free(text);
+ if ((result = text->cipher_init(text, enckey, deckey)) != SASL_OK) {
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "couldn't init cipher");
+ goto FreeAllMem;
+ }
+ }
+#else
+ if (text->cipher_init)
+ if (text->cipher_init(text, enckey, deckey) != SASL_OK) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "couldn't init cipher");
+ }
+#endif /* _SUN_SDK_ */
+ }
+
+ /*
+ * The server receives and validates the "digest-response". The server
+ * checks that the nonce-count is "00000001". If it supports subsequent
+ * authentication, it saves the value of the nonce and the nonce-count.
+ */
+
+ /*
+ * The "username-value", "realm-value" and "passwd" are encoded according
+ * to the value of the "charset" directive. If "charset=UTF-8" is
+ * present, and all the characters of either "username-value" or "passwd"
+ * are in the ISO 8859-1 character set, then it must be converted to
+ * UTF-8 before being hashed. A sample implementation of this conversion
+ * is in section 8.
+ */
+
+ /* add to challenge */
+ {
+ unsigned resplen =
+ strlen(text->response_value) + strlen("rspauth") + 3;
+
+ result = _plug_buf_alloc(sparams->utils, &(text->out_buf),
+ &(text->out_buf_len), resplen);
+ if(result != SASL_OK) {
+ goto FreeAllMem;
+ }
+
+ sprintf(text->out_buf, "rspauth=%s", text->response_value);
+
+ /* self check */
+ if (strlen(text->out_buf) > 2048) {
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+ }
+
+ *serveroutlen = strlen(text->out_buf);
+ *serverout = text->out_buf;
+
+ result = SASL_OK;
+
+ FreeAllMem:
+ if (text->reauth->timeout &&
+ sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+ unsigned val = hash(username) % text->reauth->size;
+
+ switch (result) {
+ case SASL_OK:
+ /* successful auth, setup for future reauth */
+ if (text->nonce_count == 1) {
+ /* successful initial auth, create new entry */
+ clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
+ text->reauth->e[val].authid = username; username = NULL;
+ text->reauth->e[val].realm = text->realm; text->realm = NULL;
+ text->reauth->e[val].nonce = text->nonce; text->nonce = NULL;
+ text->reauth->e[val].cnonce = cnonce; cnonce = NULL;
+ }
+ if (text->nonce_count <= text->reauth->e[val].nonce_count) {
+ /* paranoia. prevent replay attacks */
+ clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
+ }
+ else {
+ text->reauth->e[val].nonce_count = text->nonce_count;
+ text->reauth->e[val].u.s.timestamp = time(0);
+ }
+ break;
+ default:
+ if (text->nonce_count > 1) {
+ /* failed reauth, clear entry */
+ clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
+ }
+ else {
+ /* failed initial auth, leave existing cache */
+ }
+ }
+ sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+ }
+
+ /* free everything */
+ if (in_start) sparams->utils->free (in_start);
+
+ if (username != NULL)
+ sparams->utils->free (username);
+#ifdef _SUN_SDK_
+ if (authorization_id != NULL)
+ sparams->utils->free (authorization_id);
+#endif /* _SUN_SDK_ */
+ if (realm != NULL)
+ sparams->utils->free (realm);
+ if (nonce != NULL)
+ sparams->utils->free (nonce);
+ if (cnonce != NULL)
+ sparams->utils->free (cnonce);
+ if (response != NULL)
+ sparams->utils->free (response);
+ if (cipher != NULL)
+ sparams->utils->free (cipher);
+ if (serverresponse != NULL)
+ sparams->utils->free(serverresponse);
+ if (charset != NULL)
+ sparams->utils->free (charset);
+ if (digesturi != NULL)
+ sparams->utils->free (digesturi);
+ if (qop!=NULL)
+ sparams->utils->free (qop);
+ if (sec)
+ _plug_free_secret(sparams->utils, &sec);
+
+ return result;
+}
+
+static int
+digestmd5_server_mech_step(void *conn_context,
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ context_t *text = (context_t *) conn_context;
+ server_context_t *stext = (server_context_t *) conn_context;
+
+ if (clientinlen > 4096) return SASL_BADPROT;
+
+ *serverout = NULL;
+ *serveroutlen = 0;
+
+ switch (text->state) {
+
+ case 1:
+ /* setup SSF limits */
+ if (!sparams->props.maxbufsize) {
+ stext->limitssf = 0;
+ stext->requiressf = 0;
+ } else {
+ if (sparams->props.max_ssf < sparams->external_ssf) {
+ stext->limitssf = 0;
+ } else {
+ stext->limitssf =
+ sparams->props.max_ssf - sparams->external_ssf;
+ }
+ if (sparams->props.min_ssf < sparams->external_ssf) {
+ stext->requiressf = 0;
+ } else {
+ stext->requiressf =
+ sparams->props.min_ssf - sparams->external_ssf;
+ }
+ }
+
+ if (clientin && text->reauth->timeout) {
+ /* here's where we attempt fast reauth if possible */
+ if (digestmd5_server_mech_step2(stext, sparams,
+ clientin, clientinlen,
+ serverout, serveroutlen,
+ oparams) == SASL_OK) {
+ return SASL_OK;
+ }
+
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_WARN,
+ "DIGEST-MD5 reauth failed");
+#else
+ sparams->utils->log(NULL, SASL_LOG_WARN,
+ "DIGEST-MD5 reauth failed\n");
+#endif /* _SUN_SDK_ */
+
+ /* re-initialize everything for a fresh start */
+ memset(oparams, 0, sizeof(sasl_out_params_t));
+
+ /* fall through and issue challenge */
+ }
+
+ return digestmd5_server_mech_step1(stext, sparams,
+ clientin, clientinlen,
+ serverout, serveroutlen, oparams);
+
+ case 2:
+ return digestmd5_server_mech_step2(stext, sparams,
+ clientin, clientinlen,
+ serverout, serveroutlen, oparams);
+
+ default:
+#ifdef _SUN_SDK_
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
+ "Invalid DIGEST-MD5 server step %d", text->state);
+#else
+ sparams->utils->log(NULL, SASL_LOG_ERR,
+ "Invalid DIGEST-MD5 server step %d\n", text->state);
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+#ifndef _SUN_SDK_
+ return SASL_FAIL; /* should never get here */
+#endif /* !_SUN_SDK_ */
+}
+
+static void
+digestmd5_server_mech_dispose(void *conn_context, const sasl_utils_t *utils)
+{
+ server_context_t *stext = (server_context_t *) conn_context;
+
+ if (!stext || !utils) return;
+
+ digestmd5_common_mech_dispose(conn_context, utils);
+}
+
+static sasl_server_plug_t digestmd5_server_plugins[] =
+{
+ {
+ "DIGEST-MD5", /* mech_name */
+ /* EXPORT DELETE START */
+#ifdef WITH_RC4
+ 128, /* max_ssf */
+#elif WITH_DES
+ 112,
+#else
+ /* EXPORT DELETE END */
+ 0,
+ /* EXPORT DELETE START */
+#endif
+ /* EXPORT DELETE END */
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_ALLOWS_PROXY, /* features */
+ NULL, /* glob_context */
+ &digestmd5_server_mech_new, /* mech_new */
+ &digestmd5_server_mech_step, /* mech_step */
+ &digestmd5_server_mech_dispose, /* mech_dispose */
+ &digestmd5_common_mech_free, /* mech_free */
+ NULL, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ NULL, /* mech avail */
+ NULL /* spare */
+ }
+};
+
+int digestmd5_server_plug_init(sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount)
+{
+ reauth_cache_t *reauth_cache;
+ const char *timeout = NULL;
+ unsigned int len;
+#if defined _SUN_SDK_ && defined USE_UEF
+ int ret;
+#endif /* _SUN_SDK_ && USE_UEF */
+
+ if (maxversion < SASL_SERVER_PLUG_VERSION)
+ return SASL_BADVERS;
+
+#if defined _SUN_SDK_ && defined USE_UEF
+ if ((ret = uef_init(utils)) != SASL_OK)
+ return ret;
+#endif /* _SUN_SDK_ && USE_UEF */
+
+ /* reauth cache */
+ reauth_cache = utils->malloc(sizeof(reauth_cache_t));
+ if (reauth_cache == NULL)
+ return SASL_NOMEM;
+ memset(reauth_cache, 0, sizeof(reauth_cache_t));
+ reauth_cache->i_am = SERVER;
+
+ /* fetch and canonify the reauth_timeout */
+ utils->getopt(utils->getopt_context, "DIGEST-MD5", "reauth_timeout",
+ &timeout, &len);
+ if (timeout)
+ reauth_cache->timeout = (time_t) 60 * strtol(timeout, NULL, 10);
+#ifdef _SUN_SDK_
+ else
+ reauth_cache->timeout = 0;
+#endif /* _SUN_SDK_ */
+ if (reauth_cache->timeout < 0)
+ reauth_cache->timeout = 0;
+
+ if (reauth_cache->timeout) {
+ /* mutex */
+ reauth_cache->mutex = utils->mutex_alloc();
+ if (!reauth_cache->mutex)
+ return SASL_FAIL;
+
+ /* entries */
+ reauth_cache->size = 100;
+ reauth_cache->e = utils->malloc(reauth_cache->size *
+ sizeof(reauth_entry_t));
+ if (reauth_cache->e == NULL)
+ return SASL_NOMEM;
+ memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t));
+ }
+
+ digestmd5_server_plugins[0].glob_context = reauth_cache;
+
+#ifdef _SUN_SDK_
+#ifdef USE_UEF_CLIENT
+ digestmd5_server_plugins[0].max_ssf = uef_max_ssf;
+#endif /* USE_UEF_CLIENT */
+#endif /* _SUN_SDK_ */
+
+ /* EXPORT DELETE START */
+ /* CRYPT DELETE START */
+#ifdef _INTEGRATED_SOLARIS_
+ /*
+ * Let libsasl know that we are a "Sun" plugin so that privacy
+ * and integrity will be allowed.
+ */
+ REG_PLUG("DIGEST-MD5", digestmd5_server_plugins);
+#endif /* _INTEGRATED_SOLARIS_ */
+ /* CRYPT DELETE END */
+ /* EXPORT DELETE END */
+
+ *out_version = SASL_SERVER_PLUG_VERSION;
+ *pluglist = digestmd5_server_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
+
+/***************************** Client Section *****************************/
+
+typedef struct client_context {
+ context_t common;
+
+ sasl_secret_t *password; /* user password */
+ unsigned int free_password; /* set if we need to free password */
+
+ int protection;
+ struct digest_cipher *cipher;
+ unsigned int server_maxbuf;
+#ifdef _INTEGRATED_SOLARIS_
+ void *h;
+#endif /* _INTEGRATED_SOLARIS_ */
+} client_context_t;
+
+/* calculate H(A1) as per spec */
+static void
+DigestCalcHA1(context_t * text,
+ const sasl_utils_t * utils,
+ unsigned char *pszUserName,
+ unsigned char *pszRealm,
+ sasl_secret_t * pszPassword,
+ unsigned char *pszAuthorization_id,
+ unsigned char *pszNonce,
+ unsigned char *pszCNonce,
+ HASHHEX SessionKey)
+{
+ MD5_CTX Md5Ctx;
+ HASH HA1;
+
+ DigestCalcSecret(utils,
+ pszUserName,
+ pszRealm,
+ (unsigned char *) pszPassword->data,
+ pszPassword->len,
+ HA1);
+
+ /* calculate the session key */
+ utils->MD5Init(&Md5Ctx);
+ utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
+ if (pszAuthorization_id != NULL) {
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszAuthorization_id,
+ strlen((char *) pszAuthorization_id));
+ }
+ utils->MD5Final(HA1, &Md5Ctx);
+
+ CvtHex(HA1, SessionKey);
+
+ /* xxx rc-* use different n */
+
+ /* save HA1 because we'll need it for the privacy and integrity keys */
+ memcpy(text->HA1, HA1, sizeof(HASH));
+
+}
+
+static char *calculate_response(context_t * text,
+ const sasl_utils_t * utils,
+ unsigned char *username,
+ unsigned char *realm,
+ unsigned char *nonce,
+ unsigned int ncvalue,
+ unsigned char *cnonce,
+ char *qop,
+ unsigned char *digesturi,
+ sasl_secret_t * passwd,
+ unsigned char *authorization_id,
+ char **response_value)
+{
+ HASHHEX SessionKey;
+ HASHHEX HEntity = "00000000000000000000000000000000";
+ HASHHEX Response;
+ char *result;
+
+ /* Verifing that all parameters was defined */
+ if(!username || !cnonce || !nonce || !ncvalue || !digesturi || !passwd) {
+ PARAMERROR( utils );
+ return NULL;
+ }
+
+ if (realm == NULL) {
+ /* a NULL realm is equivalent to the empty string */
+ realm = (unsigned char *) "";
+ }
+
+ if (qop == NULL) {
+ /* default to a qop of just authentication */
+ qop = "auth";
+ }
+
+ DigestCalcHA1(text,
+ utils,
+ username,
+ realm,
+ passwd,
+ authorization_id,
+ nonce,
+ cnonce,
+ SessionKey);
+
+ DigestCalcResponse(utils,
+ SessionKey,/* H(A1) */
+ nonce, /* nonce from server */
+ ncvalue, /* 8 hex digits */
+ cnonce, /* client nonce */
+ (unsigned char *) qop, /* qop-value: "", "auth",
+ * "auth-int" */
+ digesturi, /* requested URL */
+ (unsigned char *) "AUTHENTICATE",
+ HEntity, /* H(entity body) if qop="auth-int" */
+ Response /* request-digest or response-digest */
+ );
+
+ result = utils->malloc(HASHHEXLEN + 1);
+#ifdef _SUN_SDK_
+ if (result == NULL)
+ return NULL;
+#endif /* _SUN_SDK_ */
+ memcpy(result, Response, HASHHEXLEN);
+ result[HASHHEXLEN] = 0;
+
+ if (response_value != NULL) {
+ DigestCalcResponse(utils,
+ SessionKey, /* H(A1) */
+ nonce, /* nonce from server */
+ ncvalue, /* 8 hex digits */
+ cnonce, /* client nonce */
+ (unsigned char *) qop, /* qop-value: "", "auth",
+ * "auth-int" */
+ (unsigned char *) digesturi, /* requested URL */
+ NULL,
+ HEntity, /* H(entity body) if qop="auth-int" */
+ Response /* request-digest or response-digest */
+ );
+
+#ifdef _SUN_SDK_
+ if (*response_value != NULL)
+ utils->free(*response_value);
+#endif /* _SUN_SDK_ */
+ *response_value = utils->malloc(HASHHEXLEN + 1);
+ if (*response_value == NULL)
+ return NULL;
+
+ memcpy(*response_value, Response, HASHHEXLEN);
+ (*response_value)[HASHHEXLEN] = 0;
+
+ }
+
+ return result;
+}
+
+static int
+make_client_response(context_t *text,
+ sasl_client_params_t *params,
+ sasl_out_params_t *oparams)
+{
+ client_context_t *ctext = (client_context_t *) text;
+ char *qop = NULL;
+ unsigned nbits = 0;
+ unsigned char *digesturi = NULL;
+ bool IsUTF8 = FALSE;
+ char ncvalue[10];
+ char maxbufstr[64];
+ char *response = NULL;
+ unsigned resplen = 0;
+ int result;
+
+ switch (ctext->protection) {
+ case DIGEST_PRIVACY:
+ qop = "auth-conf";
+ oparams->encode = &digestmd5_privacy_encode;
+ oparams->decode = &digestmd5_privacy_decode;
+ oparams->mech_ssf = ctext->cipher->ssf;
+
+ nbits = ctext->cipher->n;
+ text->cipher_enc = ctext->cipher->cipher_enc;
+ text->cipher_dec = ctext->cipher->cipher_dec;
+ text->cipher_free = ctext->cipher->cipher_free;
+ text->cipher_init = ctext->cipher->cipher_init;
+ break;
+ case DIGEST_INTEGRITY:
+ qop = "auth-int";
+ oparams->encode = &digestmd5_integrity_encode;
+ oparams->decode = &digestmd5_integrity_decode;
+ oparams->mech_ssf = 1;
+ break;
+ case DIGEST_NOLAYER:
+ default:
+ qop = "auth";
+ oparams->encode = NULL;
+ oparams->decode = NULL;
+ oparams->mech_ssf = 0;
+ }
+
+ digesturi = params->utils->malloc(strlen(params->service) + 1 +
+ strlen(params->serverFQDN) + 1 +
+ 1);
+ if (digesturi == NULL) {
+ result = SASL_NOMEM;
+ goto FreeAllocatedMem;
+ };
+
+ /* allocated exactly this. safe */
+ strcpy((char *) digesturi, params->service);
+ strcat((char *) digesturi, "/");
+ strcat((char *) digesturi, params->serverFQDN);
+ /*
+ * strcat (digesturi, "/"); strcat (digesturi, params->serverFQDN);
+ */
+
+ /* response */
+ response =
+ calculate_response(text,
+ params->utils,
+#ifdef _SUN_SDK_
+ (unsigned char *) oparams->authid,
+#else
+ (char *) oparams->authid,
+#endif /* _SUN_SDK_ */
+ (unsigned char *) text->realm,
+ text->nonce,
+ text->nonce_count,
+ text->cnonce,
+ qop,
+ digesturi,
+ ctext->password,
+ strcmp(oparams->user, oparams->authid) ?
+#ifdef _SUN_SDK_
+ (unsigned char *) oparams->user : NULL,
+#else
+ (char *) oparams->user : NULL,
+#endif /* _SUN_SDK_ */
+ &text->response_value);
+
+#ifdef _SUN_SDK_
+ if (response == NULL) {
+ result = SASL_NOMEM;
+ goto FreeAllocatedMem;
+ }
+#endif /* _SUN_SDK_ */
+
+ resplen = strlen(oparams->authid) + strlen("username") + 5;
+ result =_plug_buf_alloc(params->utils, &(text->out_buf),
+ &(text->out_buf_len),
+ resplen);
+ if (result != SASL_OK) goto FreeAllocatedMem;
+
+ sprintf(text->out_buf, "username=\"%s\"", oparams->authid);
+
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "realm", (unsigned char *) text->realm,
+ TRUE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ if (strcmp(oparams->user, oparams->authid)) {
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+#ifdef _SUN_SDK_
+ "authzid", (unsigned char *) oparams->user,
+ TRUE) != SASL_OK) {
+#else
+ "authzid", (char *) oparams->user, TRUE) != SASL_OK) {
+#endif /* _SUN_SDK_ */
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ }
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "nonce", text->nonce, TRUE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "cnonce", text->cnonce, TRUE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ snprintf(ncvalue, sizeof(ncvalue), "%08x", text->nonce_count);
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "nc", (unsigned char *) ncvalue, FALSE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "qop", (unsigned char *) qop, FALSE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ if (ctext->cipher != NULL) {
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "cipher",
+ (unsigned char *) ctext->cipher->name,
+ TRUE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ }
+
+ if (params->props.maxbufsize) {
+ snprintf(maxbufstr, sizeof(maxbufstr), "%d", params->props.maxbufsize);
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "maxbuf", (unsigned char *) maxbufstr,
+ FALSE) != SASL_OK) {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "internal error: add_to_challenge maxbuf failed");
+#else
+ SETERROR(params->utils,
+ "internal error: add_to_challenge maxbuf failed");
+#endif /* _SUN_SDK_ */
+ goto FreeAllocatedMem;
+ }
+ }
+
+ if (IsUTF8) {
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "charset", (unsigned char *) "utf-8",
+ FALSE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ }
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "digest-uri", digesturi, TRUE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "response", (unsigned char *) response,
+ FALSE) != SASL_OK) {
+
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+
+ /* self check */
+ if (strlen(text->out_buf) > 2048) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+
+ /* set oparams */
+#ifdef _SUN_SDK_
+ oparams->maxoutbuf = ctext->server_maxbuf - 4;
+#else
+ oparams->maxoutbuf = ctext->server_maxbuf;
+#endif /* _SUN_SDK_ */
+ if(oparams->mech_ssf > 1) {
+#ifdef _SUN_SDK_
+ if (oparams->maxoutbuf <= 25)
+ return (SASL_BADPARAM);
+#endif
+ /* MAC block (privacy) */
+ oparams->maxoutbuf -= 25;
+ } else if(oparams->mech_ssf == 1) {
+#ifdef _SUN_SDK_
+ if (oparams->maxoutbuf <= 16)
+ return (SASL_BADPARAM);
+#endif
+ /* MAC block (integrity) */
+ oparams->maxoutbuf -= 16;
+ }
+
+ text->seqnum = 0; /* for integrity/privacy */
+ text->rec_seqnum = 0; /* for integrity/privacy */
+ text->utils = params->utils;
+
+ text->in_maxbuf =
+ params->props.maxbufsize ? params->props.maxbufsize : DEFAULT_BUFSIZE;
+
+ /* used by layers */
+ text->needsize = 4;
+ text->buffer = NULL;
+
+ if (oparams->mech_ssf > 0) {
+ char enckey[16];
+ char deckey[16];
+
+ create_layer_keys(text, params->utils, text->HA1, nbits,
+ enckey, deckey);
+
+ /* initialize cipher if need be */
+#ifdef _SUN_SDK_
+ if (text->cipher_init) {
+ if (text->cipher_free)
+ text->cipher_free(text);
+ if((result = text->cipher_init(text, enckey, deckey)) != SASL_OK) {
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "couldn't init cipher");
+ goto FreeAllocatedMem;
+ }
+ }
+#else
+ if (text->cipher_init)
+ text->cipher_init(text, enckey, deckey);
+#endif /* _SUN_SDK_ */
+ }
+
+ result = SASL_OK;
+
+ FreeAllocatedMem:
+ if (digesturi) params->utils->free(digesturi);
+ if (response) params->utils->free(response);
+
+ return result;
+}
+
+static int parse_server_challenge(client_context_t *ctext,
+ sasl_client_params_t *params,
+ const char *serverin, unsigned serverinlen,
+ char ***outrealms, int *noutrealm)
+{
+ context_t *text = (context_t *) ctext;
+ int result = SASL_OK;
+ char *in_start = NULL;
+ char *in = NULL;
+ char **realms = NULL;
+ int nrealm = 0;
+ sasl_ssf_t limit, musthave = 0;
+ sasl_ssf_t external;
+ int protection = 0;
+ int ciphers = 0;
+ int maxbuf_count = 0;
+#ifndef _SUN_SDK_
+ bool IsUTF8 = FALSE;
+#endif /* !_SUN_SDK_ */
+ int algorithm_count = 0;
+
+ if (!serverin || !serverinlen) {
+#ifndef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "no server challenge");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "no server challenge");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+ in_start = in = params->utils->malloc(serverinlen + 1);
+ if (in == NULL) return SASL_NOMEM;
+
+ memcpy(in, serverin, serverinlen);
+ in[serverinlen] = 0;
+
+ ctext->server_maxbuf = 65536; /* Default value for maxbuf */
+
+ /* create a new cnonce */
+ text->cnonce = create_nonce(params->utils);
+ if (text->cnonce == NULL) {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "failed to create cnonce");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "failed to create cnonce");
+#endif /* _SUN_SDK_ */
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+
+ /* parse the challenge */
+ while (in[0] != '\0') {
+ char *name, *value;
+
+ get_pair(&in, &name, &value);
+
+ /* if parse error */
+ if (name == NULL) {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "Parse error");
+#else
+ params->utils->seterror(params->utils->conn, 0, "Parse error");
+#endif /* _SUN_SDK_ */
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+
+ if (strcasecmp(name, "realm") == 0) {
+ nrealm++;
+
+ if(!realms)
+ realms = params->utils->malloc(sizeof(char *) * (nrealm + 1));
+ else
+ realms = params->utils->realloc(realms,
+ sizeof(char *) * (nrealm + 1));
+
+ if (realms == NULL) {
+ result = SASL_NOMEM;
+ goto FreeAllocatedMem;
+ }
+
+ _plug_strdup(params->utils, value, &realms[nrealm-1], NULL);
+ realms[nrealm] = NULL;
+ } else if (strcasecmp(name, "nonce") == 0) {
+ _plug_strdup(params->utils, value, (char **) &text->nonce,
+ NULL);
+ text->nonce_count = 1;
+ } else if (strcasecmp(name, "qop") == 0) {
+ while (value && *value) {
+ char *comma = strchr(value, ',');
+ if (comma != NULL) {
+ *comma++ = '\0';
+ }
+
+ if (strcasecmp(value, "auth-conf") == 0) {
+ protection |= DIGEST_PRIVACY;
+ } else if (strcasecmp(value, "auth-int") == 0) {
+ protection |= DIGEST_INTEGRITY;
+ } else if (strcasecmp(value, "auth") == 0) {
+ protection |= DIGEST_NOLAYER;
+ } else {
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "Server supports unknown layer: %s\n",
+ value);
+ }
+
+ value = comma;
+ }
+
+ if (protection == 0) {
+ result = SASL_BADAUTH;
+#ifdef _INTEGRATED_SOLARIS_
+ params->utils->seterror(params->utils->conn, 0,
+ gettext("Server doesn't support known qop level"));
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "Server doesn't support known qop level");
+#endif /* _INTEGRATED_SOLARIS_ */
+ goto FreeAllocatedMem;
+ }
+ } else if (strcasecmp(name, "cipher") == 0) {
+ while (value && *value) {
+ char *comma = strchr(value, ',');
+#ifdef USE_UEF_CLIENT
+ struct digest_cipher *cipher = available_ciphers1;
+#else
+ struct digest_cipher *cipher = available_ciphers;
+#endif
+
+ if (comma != NULL) {
+ *comma++ = '\0';
+ }
+
+ /* do we support this cipher? */
+ while (cipher->name) {
+ if (!strcasecmp(value, cipher->name)) break;
+ cipher++;
+ }
+ if (cipher->name) {
+ ciphers |= cipher->flag;
+ } else {
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "Server supports unknown cipher: %s\n",
+ value);
+ }
+
+ value = comma;
+ }
+ } else if (strcasecmp(name, "stale") == 0 && ctext->password) {
+ /* clear any cached password */
+ if (ctext->free_password)
+ _plug_free_secret(params->utils, &ctext->password);
+ ctext->password = NULL;
+ } else if (strcasecmp(name, "maxbuf") == 0) {
+ /* maxbuf A number indicating the size of the largest
+ * buffer the server is able to receive when using
+ * "auth-int". If this directive is missing, the default
+ * value is 65536. This directive may appear at most once;
+ * if multiple instances are present, the client should
+ * abort the authentication exchange.
+ */
+ maxbuf_count++;
+
+ if (maxbuf_count != 1) {
+ result = SASL_BADAUTH;
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "At least two maxbuf directives found."
+ " Authentication aborted");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "At least two maxbuf directives found. Authentication aborted");
+#endif /* _SUN_SDK_ */
+ goto FreeAllocatedMem;
+ } else if (sscanf(value, "%u", &ctext->server_maxbuf) != 1) {
+ result = SASL_BADAUTH;
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "Invalid maxbuf parameter received from server");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "Invalid maxbuf parameter received from server");
+#endif /* _SUN_SDK_ */
+ goto FreeAllocatedMem;
+ } else {
+ if (ctext->server_maxbuf<=16) {
+ result = SASL_BADAUTH;
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "Invalid maxbuf parameter received from server"
+ " (too small: %s)", value);
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "Invalid maxbuf parameter received from server (too small: %s)", value);
+#endif /* _SUN_SDK_ */
+ goto FreeAllocatedMem;
+ }
+ }
+ } else if (strcasecmp(name, "charset") == 0) {
+ if (strcasecmp(value, "utf-8") != 0) {
+ result = SASL_BADAUTH;
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "Charset must be UTF-8");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "Charset must be UTF-8");
+#endif /* _SUN_SDK_ */
+ goto FreeAllocatedMem;
+ } else {
+#ifndef _SUN_SDK_
+ IsUTF8 = TRUE;
+#endif /* !_SUN_SDK_ */
+ }
+ } else if (strcasecmp(name,"algorithm")==0) {
+ if (strcasecmp(value, "md5-sess") != 0)
+ {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "'algorithm' isn't 'md5-sess'");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "'algorithm' isn't 'md5-sess'");
+#endif /* _SUN_SDK_ */
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+
+ algorithm_count++;
+ if (algorithm_count > 1)
+ {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "Must see 'algorithm' only once");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "Must see 'algorithm' only once");
+#endif /* _SUN_SDK_ */
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ } else {
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
+ name, value);
+ }
+ }
+
+ if (algorithm_count != 1) {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "Must see 'algorithm' once. Didn't see at all");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "Must see 'algorithm' once. Didn't see at all");
+#endif /* _SUN_SDK_ */
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+
+ /* make sure we have everything we require */
+ if (text->nonce == NULL) {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "Don't have nonce.");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "Don't have nonce.");
+#endif /* _SUN_SDK_ */
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+
+ /* get requested ssf */
+ external = params->external_ssf;
+
+ /* what do we _need_? how much is too much? */
+ if (params->props.maxbufsize == 0) {
+ musthave = 0;
+ limit = 0;
+ } else {
+ if (params->props.max_ssf > external) {
+ limit = params->props.max_ssf - external;
+ } else {
+ limit = 0;
+ }
+ if (params->props.min_ssf > external) {
+ musthave = params->props.min_ssf - external;
+ } else {
+ musthave = 0;
+ }
+ }
+
+ /* we now go searching for an option that gives us at least "musthave"
+ and at most "limit" bits of ssf. */
+ if ((limit > 1) && (protection & DIGEST_PRIVACY)) {
+ struct digest_cipher *cipher;
+
+ /* let's find an encryption scheme that we like */
+#ifdef USE_UEF_CLIENT
+ cipher = available_ciphers1;
+#else
+ cipher = available_ciphers;
+#endif
+ while (cipher->name) {
+ /* examine each cipher we support, see if it meets our security
+ requirements, and see if the server supports it.
+ choose the best one of these */
+ if ((limit >= cipher->ssf) && (musthave <= cipher->ssf) &&
+ (ciphers & cipher->flag) &&
+ (!ctext->cipher || (cipher->ssf > ctext->cipher->ssf))) {
+ ctext->cipher = cipher;
+ }
+ cipher++;
+ }
+
+ if (ctext->cipher) {
+ /* we found a cipher we like */
+ ctext->protection = DIGEST_PRIVACY;
+ } else {
+ /* we didn't find any ciphers we like */
+#ifdef _INTEGRATED_SOLARIS_
+ params->utils->seterror(params->utils->conn, 0,
+ gettext("No good privacy layers"));
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "No good privacy layers");
+#endif /* _INTEGRATED_SOLARIS_ */
+ }
+ }
+
+ if (ctext->cipher == NULL) {
+ /* we failed to find an encryption layer we liked;
+ can we use integrity or nothing? */
+
+ if ((limit >= 1) && (musthave <= 1)
+ && (protection & DIGEST_INTEGRITY)) {
+ /* integrity */
+ ctext->protection = DIGEST_INTEGRITY;
+#ifdef _SUN_SDK_
+ } else if (musthave == 0) {
+#else
+ } else if (musthave <= 0) {
+#endif /* _SUN_SDK_ */
+ /* no layer */
+ ctext->protection = DIGEST_NOLAYER;
+
+ /* See if server supports not having a layer */
+ if ((protection & DIGEST_NOLAYER) != DIGEST_NOLAYER) {
+#ifdef _INTEGRATED_SOLARIS_
+ params->utils->seterror(params->utils->conn, 0,
+ gettext("Server doesn't support \"no layer\""));
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "Server doesn't support \"no layer\"");
+#endif /* _INTEGRATED_SOLARIS_ */
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ } else {
+#ifdef _INTEGRATED_SOLARIS_
+ params->utils->seterror(params->utils->conn, 0,
+ gettext("Can't find an acceptable layer"));
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "Can't find an acceptable layer");
+#endif /* _INTEGRATED_SOLARIS_ */
+ result = SASL_TOOWEAK;
+ goto FreeAllocatedMem;
+ }
+ }
+
+ *outrealms = realms;
+ *noutrealm = nrealm;
+
+ FreeAllocatedMem:
+ if (in_start) params->utils->free(in_start);
+
+ if (result != SASL_OK && realms) {
+ int lup;
+
+ /* need to free all the realms */
+ for (lup = 0;lup < nrealm; lup++)
+ params->utils->free(realms[lup]);
+
+ params->utils->free(realms);
+ }
+
+ return result;
+}
+
+static int ask_user_info(client_context_t *ctext,
+ sasl_client_params_t *params,
+ char **realms, int nrealm,
+ sasl_interact_t **prompt_need,
+ sasl_out_params_t *oparams)
+{
+ context_t *text = (context_t *) ctext;
+ int result = SASL_OK;
+ const char *authid = NULL, *userid = NULL, *realm = NULL;
+ char *realm_chal = NULL;
+ int user_result = SASL_OK;
+ int auth_result = SASL_OK;
+ int pass_result = SASL_OK;
+ int realm_result = SASL_FAIL;
+
+ /* try to get the authid */
+ if (oparams->authid == NULL) {
+ auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
+
+ if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT)) {
+ return auth_result;
+ }
+ }
+
+ /* try to get the userid */
+ if (oparams->user == NULL) {
+ user_result = _plug_get_userid(params->utils, &userid, prompt_need);
+
+ if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
+ return user_result;
+ }
+ }
+
+ /* try to get the password */
+ if (ctext->password == NULL) {
+ pass_result = _plug_get_password(params->utils, &ctext->password,
+ &ctext->free_password, prompt_need);
+ if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT)) {
+ return pass_result;
+ }
+ }
+
+ /* try to get the realm */
+ if (text->realm == NULL) {
+ if (realms) {
+ if(nrealm == 1) {
+ /* only one choice */
+ realm = realms[0];
+ realm_result = SASL_OK;
+ } else {
+ /* ask the user */
+ realm_result = _plug_get_realm(params->utils,
+ (const char **) realms,
+ (const char **) &realm,
+ prompt_need);
+ }
+ }
+
+ /* fake the realm if we must */
+ if ((realm_result != SASL_OK) && (realm_result != SASL_INTERACT)) {
+ if (params->serverFQDN) {
+ realm = params->serverFQDN;
+ } else {
+ return realm_result;
+ }
+ }
+ }
+
+ /* free prompts we got */
+ if (prompt_need && *prompt_need) {
+ params->utils->free(*prompt_need);
+ *prompt_need = NULL;
+ }
+
+ /* if there are prompts not filled in */
+ if ((user_result == SASL_INTERACT) || (auth_result == SASL_INTERACT) ||
+ (pass_result == SASL_INTERACT) || (realm_result == SASL_INTERACT)) {
+
+ /* make our default realm */
+ if ((realm_result == SASL_INTERACT) && params->serverFQDN) {
+ realm_chal = params->utils->malloc(3+strlen(params->serverFQDN));
+ if (realm_chal) {
+ sprintf(realm_chal, "{%s}", params->serverFQDN);
+ } else {
+ return SASL_NOMEM;
+ }
+ }
+
+ /* make the prompt list */
+ result =
+#if defined _INTEGRATED_SOLARIS_
+ _plug_make_prompts(params->utils, &ctext->h, prompt_need,
+ user_result == SASL_INTERACT ?
+ convert_prompt(params->utils, &ctext->h,
+ gettext("Please enter your authorization name"))
+ : NULL,
+ NULL,
+ auth_result == SASL_INTERACT ?
+ convert_prompt(params->utils, &ctext->h,
+ gettext("Please enter your authentication name"))
+ : NULL,
+ NULL,
+ pass_result == SASL_INTERACT ?
+ convert_prompt(params->utils, &ctext->h,
+ gettext("Please enter your password"))
+ : NULL, NULL,
+ NULL, NULL, NULL,
+ realm_chal ? realm_chal : "{}",
+ realm_result == SASL_INTERACT ?
+ convert_prompt(params->utils, &ctext->h,
+ gettext("Please enter your realm")) : NULL,
+ params->serverFQDN ? params->serverFQDN : NULL);
+#else
+ _plug_make_prompts(params->utils, prompt_need,
+ user_result == SASL_INTERACT ?
+ "Please enter your authorization name" : NULL,
+ NULL,
+ auth_result == SASL_INTERACT ?
+ "Please enter your authentication name" : NULL,
+ NULL,
+ pass_result == SASL_INTERACT ?
+ "Please enter your password" : NULL, NULL,
+ NULL, NULL, NULL,
+ realm_chal ? realm_chal : "{}",
+ realm_result == SASL_INTERACT ?
+ "Please enter your realm" : NULL,
+ params->serverFQDN ? params->serverFQDN : NULL);
+#endif /* _INTEGRATED_SOLARIS_ */
+
+ if (result == SASL_OK) return SASL_INTERACT;
+
+ return result;
+ }
+
+ if (oparams->authid == NULL) {
+ if (!userid || !*userid) {
+ result = params->canon_user(params->utils->conn, authid, 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID,
+ oparams);
+ }
+ else {
+ result = params->canon_user(params->utils->conn,
+ authid, 0, SASL_CU_AUTHID, oparams);
+ if (result != SASL_OK) return result;
+
+ result = params->canon_user(params->utils->conn,
+ userid, 0, SASL_CU_AUTHZID, oparams);
+ }
+ if (result != SASL_OK) return result;
+ }
+
+ /* Get an allocated version of the realm into the structure */
+ if (realm && text->realm == NULL) {
+ _plug_strdup(params->utils, realm, (char **) &text->realm, NULL);
+ }
+
+ return result;
+}
+
+static int
+digestmd5_client_mech_new(void *glob_context,
+ sasl_client_params_t * params,
+ void **conn_context)
+{
+ context_t *text;
+
+ /* holds state are in -- allocate client size */
+ text = params->utils->malloc(sizeof(client_context_t));
+ if (text == NULL)
+ return SASL_NOMEM;
+ memset(text, 0, sizeof(client_context_t));
+
+ text->state = 1;
+ text->i_am = CLIENT;
+ text->reauth = glob_context;
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+static int
+digestmd5_client_mech_step1(client_context_t *ctext,
+ sasl_client_params_t *params,
+ const char *serverin __attribute__((unused)),
+ unsigned serverinlen __attribute__((unused)),
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ context_t *text = (context_t *) ctext;
+ int result = SASL_FAIL;
+ unsigned val;
+
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 client step 1");
+
+ result = ask_user_info(ctext, params, NULL, 0, prompt_need, oparams);
+ if (result != SASL_OK) return result;
+
+ /* check if we have cached info for this user on this server */
+ val = hash(params->serverFQDN) % text->reauth->size;
+ if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+ if (text->reauth->e[val].u.c.serverFQDN &&
+ !strcasecmp(text->reauth->e[val].u.c.serverFQDN,
+ params->serverFQDN) &&
+ !strcmp(text->reauth->e[val].authid, oparams->authid)) {
+
+#ifdef _SUN_SDK_
+ if (text->realm) params->utils->free(text->realm);
+ if (text->nonce) params->utils->free(text->nonce);
+ if (text->cnonce) params->utils->free(text->cnonce);
+#endif /* _SUN_SDK_ */
+ /* we have info, so use it */
+ _plug_strdup(params->utils, text->reauth->e[val].realm,
+ &text->realm, NULL);
+#ifdef _SUN_SDK_
+ _plug_strdup(params->utils, (char *)text->reauth->e[val].nonce,
+ (char **) &text->nonce, NULL);
+#else
+ _plug_strdup(params->utils, text->reauth->e[val].nonce,
+ (char **) &text->nonce, NULL);
+#endif /* _SUN_SDK_ */
+ text->nonce_count = ++text->reauth->e[val].nonce_count;
+#ifdef _SUN_SDK_
+ _plug_strdup(params->utils, (char *)text->reauth->e[val].cnonce,
+ (char **) &text->cnonce, NULL);
+#else
+ _plug_strdup(params->utils, text->reauth->e[val].cnonce,
+ (char **) &text->cnonce, NULL);
+#endif /* _SUN_SDK_ */
+ ctext->protection = text->reauth->e[val].u.c.protection;
+ ctext->cipher = text->reauth->e[val].u.c.cipher;
+ ctext->server_maxbuf = text->reauth->e[val].u.c.server_maxbuf;
+ }
+ params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+ }
+
+ if (!text->nonce) {
+ /* we don't have any reauth info, so just return
+ * that there is no initial client send */
+ text->state = 2;
+ return SASL_CONTINUE;
+ }
+
+ /*
+ * (username | realm | nonce | cnonce | nonce-count | qop digest-uri |
+ * response | maxbuf | charset | auth-param )
+ */
+
+ result = make_client_response(text, params, oparams);
+ if (result != SASL_OK) return result;
+
+ *clientoutlen = strlen(text->out_buf);
+ *clientout = text->out_buf;
+
+ text->state = 3;
+ return SASL_CONTINUE;
+}
+
+static int
+digestmd5_client_mech_step2(client_context_t *ctext,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ context_t *text = (context_t *) ctext;
+ int result = SASL_FAIL;
+ char **realms = NULL;
+ int nrealm = 0;
+
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 client step 2");
+
+ if (params->props.min_ssf > params->props.max_ssf) {
+ return SASL_BADPARAM;
+ }
+
+ /* don't bother parsing the challenge more than once */
+ if (text->nonce == NULL) {
+ result = parse_server_challenge(ctext, params, serverin, serverinlen,
+ &realms, &nrealm);
+ if (result != SASL_OK) goto FreeAllocatedMem;
+
+ if (nrealm == 1) {
+ /* only one choice! */
+ text->realm = realms[0];
+
+ /* free realms */
+ params->utils->free(realms);
+ realms = NULL;
+ }
+ }
+
+ result = ask_user_info(ctext, params, realms, nrealm,
+ prompt_need, oparams);
+ if (result != SASL_OK) goto FreeAllocatedMem;
+
+ /*
+ * (username | realm | nonce | cnonce | nonce-count | qop digest-uri |
+ * response | maxbuf | charset | auth-param )
+ */
+
+ result = make_client_response(text, params, oparams);
+ if (result != SASL_OK) goto FreeAllocatedMem;
+
+ *clientoutlen = strlen(text->out_buf);
+ *clientout = text->out_buf;
+
+ text->state = 3;
+
+ result = SASL_CONTINUE;
+
+ FreeAllocatedMem:
+ if (realms) {
+ int lup;
+
+ /* need to free all the realms */
+ for (lup = 0;lup < nrealm; lup++)
+ params->utils->free(realms[lup]);
+
+ params->utils->free(realms);
+ }
+
+ return result;
+}
+
+static int
+digestmd5_client_mech_step3(client_context_t *ctext,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need __attribute__((unused)),
+ const char **clientout __attribute__((unused)),
+ unsigned *clientoutlen __attribute__((unused)),
+ sasl_out_params_t *oparams)
+{
+ context_t *text = (context_t *) ctext;
+ char *in = NULL;
+ char *in_start;
+ int result = SASL_FAIL;
+
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 client step 3");
+
+ /* Verify that server is really what he claims to be */
+ in_start = in = params->utils->malloc(serverinlen + 1);
+ if (in == NULL) return SASL_NOMEM;
+
+ memcpy(in, serverin, serverinlen);
+ in[serverinlen] = 0;
+
+ /* parse the response */
+ while (in[0] != '\0') {
+ char *name, *value;
+ get_pair(&in, &name, &value);
+
+ if (name == NULL) {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "DIGEST-MD5 Received Garbage");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "DIGEST-MD5 Received Garbage");
+#endif /* _SUN_SDK_ */
+ break;
+ }
+
+ if (strcasecmp(name, "rspauth") == 0) {
+
+ if (strcmp(text->response_value, value) != 0) {
+#ifdef _INTEGRATED_SOLARIS_
+ params->utils->seterror(params->utils->conn, 0,
+ gettext("Server authentication failed"));
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "DIGEST-MD5: This server wants us to believe that he knows shared secret");
+#endif /* _INTEGRATED_SOLARIS_ */
+ result = SASL_FAIL;
+ } else {
+ oparams->doneflag = 1;
+ oparams->param_version = 0;
+
+ result = SASL_OK;
+ }
+ break;
+ } else {
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
+ name, value);
+ }
+ }
+
+ params->utils->free(in_start);
+
+ if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+ unsigned val = hash(params->serverFQDN) % text->reauth->size;
+ switch (result) {
+ case SASL_OK:
+ if (text->nonce_count == 1) {
+ /* successful initial auth, setup for future reauth */
+ clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
+ _plug_strdup(params->utils, oparams->authid,
+ &text->reauth->e[val].authid, NULL);
+ text->reauth->e[val].realm = text->realm; text->realm = NULL;
+ text->reauth->e[val].nonce = text->nonce; text->nonce = NULL;
+ text->reauth->e[val].nonce_count = text->nonce_count;
+ text->reauth->e[val].cnonce = text->cnonce; text->cnonce = NULL;
+ _plug_strdup(params->utils, params->serverFQDN,
+ &text->reauth->e[val].u.c.serverFQDN, NULL);
+ text->reauth->e[val].u.c.protection = ctext->protection;
+ text->reauth->e[val].u.c.cipher = ctext->cipher;
+ text->reauth->e[val].u.c.server_maxbuf = ctext->server_maxbuf;
+ }
+#ifndef _SUN_SDK_
+ else {
+ /* reauth, we already incremented nonce_count */
+ }
+#endif /* !_SUN_SDK_ */
+ break;
+ default:
+ if (text->nonce_count > 1) {
+ /* failed reauth, clear cache */
+ clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
+ }
+ else {
+ /* failed initial auth, leave existing cache */
+ }
+ }
+ params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+ }
+
+ return result;
+}
+
+static int
+digestmd5_client_mech_step(void *conn_context,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ context_t *text = (context_t *) conn_context;
+ client_context_t *ctext = (client_context_t *) conn_context;
+ unsigned val = hash(params->serverFQDN) % text->reauth->size;
+
+ if (serverinlen > 2048) return SASL_BADPROT;
+
+ *clientout = NULL;
+ *clientoutlen = 0;
+
+ switch (text->state) {
+
+ case 1:
+ if (!serverin) {
+ /* here's where we attempt fast reauth if possible */
+ int reauth = 0;
+
+ /* check if we have saved info for this server */
+ if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+ reauth = text->reauth->e[val].u.c.serverFQDN &&
+ !strcasecmp(text->reauth->e[val].u.c.serverFQDN,
+ params->serverFQDN);
+ params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+ }
+ if (reauth) {
+ return digestmd5_client_mech_step1(ctext, params,
+ serverin, serverinlen,
+ prompt_need,
+ clientout, clientoutlen,
+ oparams);
+ }
+ else {
+ /* we don't have any reauth info, so just return
+ * that there is no initial client send */
+ text->state = 2;
+ return SASL_CONTINUE;
+ }
+ }
+
+ /* fall through and respond to challenge */
+
+ case 3:
+ if (serverin && !strncasecmp(serverin, "rspauth=", 8)) {
+ return digestmd5_client_mech_step3(ctext, params,
+ serverin, serverinlen,
+ prompt_need,
+ clientout, clientoutlen,
+ oparams);
+ }
+
+ /* fall through and respond to challenge */
+ text->state = 2;
+
+ /* cleanup after a failed reauth attempt */
+ if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+ clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
+
+ params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+ }
+
+ if (text->realm) params->utils->free(text->realm);
+ if (text->nonce) params->utils->free(text->nonce);
+ if (text->cnonce) params->utils->free(text->cnonce);
+#ifdef _SUN_SDK_
+ text->realm = NULL;
+ text->nonce = text->cnonce = NULL;
+#else
+ text->realm = text->nonce = text->cnonce = NULL;
+#endif /* _SUN_SDK_ */
+ ctext->cipher = NULL;
+
+ case 2:
+ return digestmd5_client_mech_step2(ctext, params,
+ serverin, serverinlen,
+ prompt_need,
+ clientout, clientoutlen,
+ oparams);
+
+ default:
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "Invalid DIGEST-MD5 client step %d", text->state);
+#else
+ params->utils->log(NULL, SASL_LOG_ERR,
+ "Invalid DIGEST-MD5 client step %d\n", text->state);
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+ return SASL_FAIL; /* should never get here */
+}
+
+static void
+digestmd5_client_mech_dispose(void *conn_context, const sasl_utils_t *utils)
+{
+ client_context_t *ctext = (client_context_t *) conn_context;
+
+ if (!ctext || !utils) return;
+
+#ifdef _INTEGRATED_SOLARIS_
+ convert_prompt(utils, &ctext->h, NULL);
+#endif /* _INTEGRATED_SOLARIS_ */
+
+ if (ctext->free_password) _plug_free_secret(utils, &ctext->password);
+
+ digestmd5_common_mech_dispose(conn_context, utils);
+}
+
+static sasl_client_plug_t digestmd5_client_plugins[] =
+{
+ {
+ "DIGEST-MD5",
+ /* EXPORT DELETE START */
+#ifdef WITH_RC4 /* mech_name */
+ 128, /* max ssf */
+#elif WITH_DES
+ 112,
+#else
+ /* EXPORT DELETE END */
+ 0,
+ /* EXPORT DELETE START */
+#endif
+ /* EXPORT DELETE END */
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_ALLOWS_PROXY, /* features */
+ NULL, /* required_prompts */
+ NULL, /* glob_context */
+ &digestmd5_client_mech_new, /* mech_new */
+ &digestmd5_client_mech_step, /* mech_step */
+ &digestmd5_client_mech_dispose, /* mech_dispose */
+ &digestmd5_common_mech_free, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare1 */
+ NULL /* spare2 */
+ }
+};
+
+int digestmd5_client_plug_init(sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount)
+{
+ reauth_cache_t *reauth_cache;
+#if defined _SUN_SDK_ && defined USE_UEF
+ int ret;
+#endif /* _SUN_SDK_ && USE_UEF */
+
+ if (maxversion < SASL_CLIENT_PLUG_VERSION)
+ return SASL_BADVERS;
+
+#if defined _SUN_SDK_ && defined USE_UEF
+ if ((ret = uef_init(utils)) != SASL_OK)
+ return ret;
+#endif /* _SUN_SDK_ && USE_UEF */
+
+ /* reauth cache */
+ reauth_cache = utils->malloc(sizeof(reauth_cache_t));
+ if (reauth_cache == NULL)
+ return SASL_NOMEM;
+ memset(reauth_cache, 0, sizeof(reauth_cache_t));
+ reauth_cache->i_am = CLIENT;
+
+ /* mutex */
+ reauth_cache->mutex = utils->mutex_alloc();
+ if (!reauth_cache->mutex)
+ return SASL_FAIL;
+
+ /* entries */
+ reauth_cache->size = 10;
+ reauth_cache->e = utils->malloc(reauth_cache->size *
+ sizeof(reauth_entry_t));
+ if (reauth_cache->e == NULL)
+ return SASL_NOMEM;
+ memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t));
+
+ digestmd5_client_plugins[0].glob_context = reauth_cache;
+#ifdef _SUN_SDK_
+#ifdef USE_UEF_CLIENT
+ digestmd5_client_plugins[0].max_ssf = uef_max_ssf;
+#endif /* USE_UEF_CLIENT */
+#endif /* _SUN_SDK_ */
+
+ /* EXPORT DELETE START */
+ /* CRYPT DELETE START */
+#ifdef _INTEGRATED_SOLARIS_
+ /*
+ * Let libsasl know that we are a "Sun" plugin so that privacy
+ * and integrity will be allowed.
+ */
+ REG_PLUG("DIGEST-MD5", digestmd5_client_plugins);
+#endif /* _INTEGRATED_SOLARIS_ */
+ /* CRYPT DELETE END */
+ /* EXPORT DELETE END */
+
+ *out_version = SASL_CLIENT_PLUG_VERSION;
+ *pluglist = digestmd5_client_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
+
+#ifdef _SUN_SDK_
+#ifdef USE_UEF
+/* If we fail here - we should just not offer privacy or integrity */
+static int
+getSlotID(const sasl_utils_t *utils, CK_MECHANISM_TYPE mech_type,
+ CK_SLOT_ID *slot_id)
+{
+ CK_RV rv;
+ CK_ULONG ulSlotCount;
+ CK_ULONG ulMechTypeCount;
+ CK_SLOT_ID *pSlotList = NULL;
+ CK_SLOT_ID slotID;
+ CK_MECHANISM_TYPE_PTR pMechTypeList = NULL;
+ int i, m;
+
+ rv = C_GetSlotList(CK_FALSE, NULL_PTR, &ulSlotCount);
+ if (rv != CKR_OK || ulSlotCount == 0) {
+#ifdef DEBUG
+ utils->log(utils->conn, SASL_LOG_DEBUG,
+ "C_GetSlotList: 0x%.8X count:%d\n", rv, ulSlotCount);
+#endif
+ return SASL_FAIL;
+ }
+
+ pSlotList = utils->calloc(sizeof (CK_SLOT_ID), ulSlotCount);
+ if (pSlotList == NULL)
+ return SASL_NOMEM;
+
+ rv = C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ utils->log(utils->conn, SASL_LOG_DEBUG,
+ "C_GetSlotList: 0x%.8X count:%d\n", rv, ulSlotCount);
+#endif
+ return SASL_FAIL;
+ }
+
+ for (i = 0; i < ulSlotCount; i++) {
+ slotID = pSlotList[i];
+ rv = C_GetMechanismList(slotID, NULL_PTR, &ulMechTypeCount);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ utils->log(utils->conn, SASL_LOG_DEBUG,
+ "C_GetMechanismList returned 0x%.8X count:%d\n", rv,
+ ulMechTypeCount);
+#endif
+ utils->free(pSlotList);
+ return SASL_FAIL;
+ }
+ pMechTypeList =
+ utils->calloc(sizeof (CK_MECHANISM_TYPE), ulMechTypeCount);
+ if (pMechTypeList == NULL_PTR) {
+ utils->free(pSlotList);
+ return SASL_NOMEM;
+ }
+ rv = C_GetMechanismList(slotID, pMechTypeList, &ulMechTypeCount);
+ if (rv != CKR_OK) {
+#ifdef DEBUG
+ utils->log(utils->conn, SASL_LOG_DEBUG,
+ "C_GetMechanismList returned 0x%.8X count:%d\n", rv,
+ ulMechTypeCount);
+#endif
+ utils->free(pMechTypeList);
+ utils->free(pSlotList);
+ return SASL_FAIL;
+ }
+
+ for (m = 0; m < ulMechTypeCount; m++) {
+ if (pMechTypeList[m] == mech_type)
+ break;
+ }
+ utils->free(pMechTypeList);
+ pMechTypeList = NULL;
+ if (m < ulMechTypeCount)
+ break;
+ }
+ utils->free(pSlotList);
+ if (i < ulSlotCount) {
+ *slot_id = slotID;
+ return SASL_OK;
+ }
+ return SASL_FAIL;
+}
+
+static int
+uef_init(const sasl_utils_t *utils)
+{
+ int got_rc4;
+ int got_des;
+ int got_3des;
+ int next_c;
+ CK_RV rv;
+
+ if (got_uef_slot)
+ return (SASL_OK);
+
+ if (LOCK_MUTEX(&uef_init_mutex) < 0)
+ return (SASL_FAIL);
+
+ rv = C_Initialize(NULL_PTR);
+ if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
+#ifdef DEBUG
+ utils->log(utils->conn, SASL_LOG_DEBUG,
+ "C_Initialize returned 0x%.8X\n", rv);
+#endif
+ return SASL_FAIL;
+ }
+
+ got_rc4 = getSlotID(utils, CKM_RC4, &rc4_slot_id) == SASL_OK;
+ if (!got_rc4)
+ utils->log(utils->conn, SASL_LOG_WARN, "Could not get rc4");
+
+ got_des = getSlotID(utils, CKM_DES_CBC, &des_slot_id) == SASL_OK;
+ if (!got_des)
+ utils->log(utils->conn, SASL_LOG_WARN, "Could not get des");
+
+ got_3des = getSlotID(utils, CKM_DES3_CBC, &des3_slot_id) == SASL_OK;
+ if (!got_3des)
+ utils->log(utils->conn, SASL_LOG_WARN, "Could not get 3des");
+
+ uef_max_ssf = got_rc4 ? 128 : got_3des ? 112 : got_des ? 55 : 0;
+
+ /* adjust the available ciphers */
+ next_c = (got_rc4) ? 3 : 0;
+
+ if (got_des) {
+ uef_ciphers[next_c].name = uef_ciphers[DES_CIPHER_INDEX].name;
+ uef_ciphers[next_c].ssf = uef_ciphers[DES_CIPHER_INDEX].ssf;
+ uef_ciphers[next_c].n = uef_ciphers[DES_CIPHER_INDEX].n;
+ uef_ciphers[next_c].flag = uef_ciphers[DES_CIPHER_INDEX].flag;
+ uef_ciphers[next_c].cipher_enc =
+ uef_ciphers[DES_CIPHER_INDEX].cipher_enc;
+ uef_ciphers[next_c].cipher_dec =
+ uef_ciphers[DES_CIPHER_INDEX].cipher_dec;
+ uef_ciphers[next_c].cipher_init =
+ uef_ciphers[DES_CIPHER_INDEX].cipher_init;
+ next_c++;
+ }
+
+ if (got_3des) {
+ uef_ciphers[next_c].name = uef_ciphers[DES3_CIPHER_INDEX].name;
+ uef_ciphers[next_c].ssf = uef_ciphers[DES3_CIPHER_INDEX].ssf;
+ uef_ciphers[next_c].n = uef_ciphers[DES3_CIPHER_INDEX].n;
+ uef_ciphers[next_c].flag = uef_ciphers[DES3_CIPHER_INDEX].flag;
+ uef_ciphers[next_c].cipher_enc =
+ uef_ciphers[DES3_CIPHER_INDEX].cipher_enc;
+ uef_ciphers[next_c].cipher_dec =
+ uef_ciphers[DES3_CIPHER_INDEX].cipher_dec;
+ uef_ciphers[next_c].cipher_init =
+ uef_ciphers[DES3_CIPHER_INDEX].cipher_init;
+ next_c++;
+ }
+ uef_ciphers[next_c].name = NULL;
+
+ got_uef_slot = TRUE;
+ UNLOCK_MUTEX(&uef_init_mutex);
+
+ return (SASL_OK);
+}
+#endif /* USE_UEF */
+#endif /* _SUN_SDK_ */
diff --git a/usr/src/lib/sasl_plugins/digestmd5/digestmd5_init.c b/usr/src/lib/sasl_plugins/digestmd5/digestmd5_init.c
new file mode 100644
index 0000000000..ebb834a84a
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/digestmd5_init.c
@@ -0,0 +1,44 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef macintosh
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <assert.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslutil.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#include <sasl_digestmd5_plugin_decl.h>
+#endif
+
+#ifdef WIN32
+BOOL APIENTRY DllMain( HANDLE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+#endif
+
+SASL_CLIENT_PLUG_INIT( digestmd5 )
+SASL_SERVER_PLUG_INIT( digestmd5 )
+
diff --git a/usr/src/lib/sasl_plugins/digestmd5/i386/Makefile b/usr/src/lib/sasl_plugins/digestmd5/i386/Makefile
new file mode 100644
index 0000000000..c9036b2b2f
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/i386/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/digestmd5/i386/Makefile
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS)
diff --git a/usr/src/lib/sasl_plugins/digestmd5/sparc/Makefile b/usr/src/lib/sasl_plugins/digestmd5/sparc/Makefile
new file mode 100644
index 0000000000..27e10f0022
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/sparc/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/digest/sparc/Makefile
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS)
diff --git a/usr/src/lib/sasl_plugins/digestmd5/sparcv9/Makefile b/usr/src/lib/sasl_plugins/digestmd5/sparcv9/Makefile
new file mode 100644
index 0000000000..7aa0a295fa
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/sparcv9/Makefile
@@ -0,0 +1,12 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/digest/sparcv9/Makefile
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+install: all $(ROOTLIBS64)
diff --git a/usr/src/lib/sasl_plugins/digestmd5/spec/Makefile b/usr/src/lib/sasl_plugins/digestmd5/spec/Makefile
new file mode 100644
index 0000000000..78e5a082a2
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/spec/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+include $(SRC)/lib/Makefile.spec.arch
diff --git a/usr/src/lib/sasl_plugins/digestmd5/spec/Makefile.targ b/usr/src/lib/sasl_plugins/digestmd5/spec/Makefile.targ
new file mode 100644
index 0000000000..bd86aec418
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/spec/Makefile.targ
@@ -0,0 +1,10 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+LIBRARY = digestmd5.a
+VERS = .1
+
+OBJECTS = digestmd5.o
diff --git a/usr/src/lib/sasl_plugins/digestmd5/spec/amd64/Makefile b/usr/src/lib/sasl_plugins/digestmd5/spec/amd64/Makefile
new file mode 100644
index 0000000000..07e64367c4
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/spec/amd64/Makefile
@@ -0,0 +1,14 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/digestmd5/spec/digestmd5.spec b/usr/src/lib/sasl_plugins/digestmd5/spec/digestmd5.spec
new file mode 100644
index 0000000000..aaa78d87df
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/spec/digestmd5.spec
@@ -0,0 +1,28 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugin/digestmd5/spec/digestmd5.spec
+#
+
+function sasl_client_plug_init
+include <sasl/saslplug.h>
+declaration int sasl_client_plug_init(const sasl_utils_t *utils, \
+ int maxversion, int *out_version, \
+ sasl_client_plug_t **pluglist, \
+ int *plugcount)
+exception $return == SASL_FAIL
+version SUNWprivate_1.1
+end
+
+function sasl_server_plug_init
+include <sasl/saslplug.h>
+declaration int sasl_server_plug_init(const sasl_utils_t *utils, \
+ int maxversion, int *out_version, \
+ sasl_server_plug_t **pluglist, \
+ int *plugcount)
+exception $return == SASL_FAIL
+version SUNWprivate_1.1
+end
diff --git a/usr/src/lib/sasl_plugins/digestmd5/spec/i386/Makefile b/usr/src/lib/sasl_plugins/digestmd5/spec/i386/Makefile
new file mode 100644
index 0000000000..898bd186dc
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/spec/i386/Makefile
@@ -0,0 +1,15 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/digestmd5/spec/i386/Makefile
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/digestmd5/spec/sparc/Makefile b/usr/src/lib/sasl_plugins/digestmd5/spec/sparc/Makefile
new file mode 100644
index 0000000000..d98d83e258
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/spec/sparc/Makefile
@@ -0,0 +1,15 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/digestmd5/spec/sparc/Makefile
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/digestmd5/spec/sparcv9/Makefile b/usr/src/lib/sasl_plugins/digestmd5/spec/sparcv9/Makefile
new file mode 100644
index 0000000000..63a659bc17
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/spec/sparcv9/Makefile
@@ -0,0 +1,16 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/digestmd5/spec/sparcv9/Makefile
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/digestmd5/spec/versions b/usr/src/lib/sasl_plugins/digestmd5/spec/versions
new file mode 100644
index 0000000000..6a318d48a3
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/digestmd5/spec/versions
@@ -0,0 +1,19 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+sparc {
+ SUNWprivate_1.1;
+}
+sparcv9 {
+ SUNWprivate_1.1;
+}
+i386 {
+ SUNWprivate_1.1;
+}
+amd64 {
+ SUNWprivate_1.1;
+}
diff --git a/usr/src/lib/sasl_plugins/gssapi/Makefile b/usr/src/lib/sasl_plugins/gssapi/Makefile
new file mode 100644
index 0000000000..4897cf88f3
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+include ../Makefile.subdirs
diff --git a/usr/src/lib/sasl_plugins/gssapi/Makefile.com b/usr/src/lib/sasl_plugins/gssapi/Makefile.com
new file mode 100644
index 0000000000..413208d5ed
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/Makefile.com
@@ -0,0 +1,15 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+LIBRARY= gssapi.a
+VERS= .1
+
+PLUG_OBJS= gssapi.o gssapiv2_init.o
+
+PLUG_LIBS = -lgss
+
+# include common definitions
+include ../../Makefile.com
diff --git a/usr/src/lib/sasl_plugins/gssapi/amd64/Makefile b/usr/src/lib/sasl_plugins/gssapi/amd64/Makefile
new file mode 100644
index 0000000000..13ae0db12d
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/amd64/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64)
diff --git a/usr/src/lib/sasl_plugins/gssapi/gssapi.c b/usr/src/lib/sasl_plugins/gssapi/gssapi.c
new file mode 100644
index 0000000000..302d029380
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/gssapi.c
@@ -0,0 +1,2206 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* GSSAPI SASL plugin
+ * Leif Johansson
+ * Rob Siemborski (SASL v2 Conversion)
+ * $Id: gssapi.c,v 1.75 2003/07/02 13:13:42 rjs3 Exp $
+ */
+/*
+ * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Office of Technology Transfer
+ * Carnegie Mellon University
+ * 5000 Forbes Avenue
+ * Pittsburgh, PA 15213-3890
+ * (412) 268-4387, fax: (412) 268-7395
+ * tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#ifdef HAVE_GSSAPI_H
+#include <gssapi.h>
+#else
+#include <gssapi/gssapi.h>
+#endif
+
+#ifdef WIN32
+# include <winsock.h>
+
+# ifndef R_OK
+# define R_OK 04
+# endif
+/* we also need io.h for access() prototype */
+# include <io.h>
+#else
+# include <sys/param.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#endif /* WIN32 */
+#include <fcntl.h>
+#include <stdio.h>
+#include <sasl.h>
+#include <saslutil.h>
+#include <saslplug.h>
+
+#include "plugin_common.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <errno.h>
+
+#ifdef WIN32
+/* This must be after sasl.h */
+# include "saslgssapi.h"
+#endif /* WIN32 */
+
+/***************************** Common Section *****************************/
+
+#ifndef _SUN_SDK_
+static const char plugin_id[] = "$Id: gssapi.c,v 1.75 2003/07/02 13:13:42 rjs3 Exp $";
+#endif /* !_SUN_SDK_ */
+
+static const char * GSSAPI_BLANK_STRING = "";
+
+#ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE
+extern gss_OID gss_nt_service_name;
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+#endif
+
+#ifdef _SUN_SDK_
+static int
+get_oid(const sasl_utils_t *utils, gss_OID *oid);
+#ifdef GSSAPI_PROTECT
+DEFINE_STATIC_MUTEX(global_mutex);
+#endif /* GSSAPI_PROTECT */
+#endif /* _SUN_SDK_ */
+
+/* GSSAPI SASL Mechanism by Leif Johansson <leifj@matematik.su.se>
+ * inspired by the kerberos mechanism and the gssapi_server and
+ * gssapi_client from the heimdal distribution by Assar Westerlund
+ * <assar@sics.se> and Johan Danielsson <joda@pdc.kth.se>.
+ * See the configure.in file for details on dependencies.
+ * Heimdal can be obtained from http://www.pdc.kth.se/heimdal
+ *
+ * Important contributions from Sam Hartman <hartmans@fundsxpress.com>.
+ */
+
+typedef struct context {
+ int state;
+
+ gss_ctx_id_t gss_ctx;
+ gss_name_t client_name;
+ gss_name_t server_name;
+ gss_cred_id_t server_creds;
+ sasl_ssf_t limitssf, requiressf; /* application defined bounds, for the
+ server */
+#ifdef _SUN_SDK_
+ gss_cred_id_t client_creds;
+ gss_OID mech_oid;
+ int use_authid;
+#endif /* _SUN_SDK_ */
+ const sasl_utils_t *utils;
+
+ /* layers buffering */
+ char *buffer;
+#ifdef _SUN_SDK_
+ unsigned bufsize;
+#else
+ int bufsize;
+#endif /* _SUN_SDK_ */
+ char sizebuf[4];
+#ifdef _SUN_SDK_
+ unsigned cursize;
+ unsigned size;
+#else
+ int cursize;
+ int size;
+#endif /* _SUN_SDK_ */
+ unsigned needsize;
+
+ char *encode_buf; /* For encoding/decoding mem management */
+ char *decode_buf;
+ char *decode_once_buf;
+ unsigned encode_buf_len;
+ unsigned decode_buf_len;
+ unsigned decode_once_buf_len;
+ buffer_info_t *enc_in_buf;
+
+ char *out_buf; /* per-step mem management */
+ unsigned out_buf_len;
+
+ char *authid; /* hold the authid between steps - server */
+ const char *user; /* hold the userid between steps - client */
+#ifdef _SUN_SDK_
+ const char *client_authid;
+#endif /* _SUN_SDK_ */
+#ifdef _INTEGRATED_SOLARIS_
+ void *h;
+#endif /* _INTEGRATED_SOLARIS_ */
+} context_t;
+
+enum {
+ SASL_GSSAPI_STATE_AUTHNEG = 1,
+ SASL_GSSAPI_STATE_SSFCAP = 2,
+ SASL_GSSAPI_STATE_SSFREQ = 3,
+ SASL_GSSAPI_STATE_AUTHENTICATED = 4
+};
+
+#ifdef _SUN_SDK_
+/* sasl_gss_log only logs gss_display_status() error string */
+#define sasl_gss_log(x,y,z) sasl_gss_seterror_(text,y,z,1)
+#define sasl_gss_seterror(x,y,z) sasl_gss_seterror_(text,y,z,0)
+static void
+sasl_gss_seterror_(const context_t *text, OM_uint32 maj, OM_uint32 min,
+ int logonly)
+#else
+static void
+sasl_gss_seterror(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min)
+#endif /* _SUN_SDK_ */
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc msg;
+ OM_uint32 msg_ctx;
+ int ret;
+ char *out = NULL;
+#ifdef _SUN_SDK_
+ unsigned len, curlen = 0;
+ const sasl_utils_t *utils = text->utils;
+ char *prefix = dgettext(TEXT_DOMAIN, "GSSAPI Error: ");
+#else
+ size_t len, curlen = 0;
+ const char prefix[] = "GSSAPI Error: ";
+#endif /* _SUN_SDK_ */
+
+ if(!utils) return;
+
+ len = sizeof(prefix);
+ ret = _plug_buf_alloc(utils, &out, &curlen, 256);
+ if(ret != SASL_OK) return;
+
+ strcpy(out, prefix);
+
+ msg_ctx = 0;
+ while (1) {
+ maj_stat = gss_display_status(&min_stat, maj,
+#ifdef _SUN_SDK_
+ GSS_C_GSS_CODE, text->mech_oid,
+#else
+ GSS_C_GSS_CODE, GSS_C_NULL_OID,
+#endif /* _SUN_SDK_ */
+ &msg_ctx, &msg);
+ if(GSS_ERROR(maj_stat)) {
+#ifdef _SUN_SDK_
+ if (logonly) {
+ utils->log(text->utils->conn, SASL_LOG_FAIL,
+ "GSSAPI Failure: (could not get major error message)");
+ } else {
+#endif /* _SUN_SDK_ */
+#ifdef _INTEGRATED_SOLARIS_
+ utils->seterror(utils->conn, 0,
+ gettext("GSSAPI Failure "
+ "(could not get major error message)"));
+#ifdef _SUN_SDK_
+ }
+#endif /* _SUN_SDK_ */
+#else
+ utils->seterror(utils->conn, 0,
+ "GSSAPI Failure "
+ "(could not get major error message)");
+#ifdef _SUN_SDK_
+ }
+#endif /* _SUN_SDK_ */
+#endif /* _INTEGRATED_SOLARIS_ */
+ utils->free(out);
+ return;
+ }
+
+ len += len + msg.length;
+ ret = _plug_buf_alloc(utils, &out, &curlen, len);
+
+ if(ret != SASL_OK) {
+ utils->free(out);
+ return;
+ }
+
+ strcat(out, msg.value);
+
+ gss_release_buffer(&min_stat, &msg);
+
+ if (!msg_ctx)
+ break;
+ }
+
+ /* Now get the minor status */
+
+ len += 2;
+ ret = _plug_buf_alloc(utils, &out, &curlen, len);
+ if(ret != SASL_OK) {
+ utils->free(out);
+ return;
+ }
+
+ strcat(out, " (");
+
+ msg_ctx = 0;
+ while (1) {
+ maj_stat = gss_display_status(&min_stat, min,
+#ifdef _SUN_SDK_
+ GSS_C_MECH_CODE, text->mech_oid,
+#else
+ GSS_C_MECH_CODE, GSS_C_NULL_OID,
+#endif /* _SUN_SDK_ */
+ &msg_ctx, &msg);
+ if(GSS_ERROR(maj_stat)) {
+#ifdef _SUN_SDK_
+ if (logonly) {
+ utils->log(text->utils->conn, SASL_LOG_FAIL,
+ "GSSAPI Failure: (could not get minor error message)");
+ } else {
+#endif /* _SUN_SDK_ */
+#ifdef _INTEGRATED_SOLARIS_
+ utils->seterror(utils->conn, 0,
+ gettext("GSSAPI Failure "
+ "(could not get minor error message)"));
+#ifdef _SUN_SDK_
+ }
+#endif /* _SUN_SDK_ */
+#else
+ utils->seterror(utils->conn, 0,
+ "GSSAPI Failure "
+ "(could not get minor error message)");
+#ifdef _SUN_SDK_
+ }
+#endif /* _SUN_SDK_ */
+#endif /* _INTEGRATED_SOLARIS_ */
+ utils->free(out);
+ return;
+ }
+
+ len += len + msg.length;
+ ret = _plug_buf_alloc(utils, &out, &curlen, len);
+
+ if(ret != SASL_OK) {
+ utils->free(out);
+ return;
+ }
+
+ strcat(out, msg.value);
+
+ gss_release_buffer(&min_stat, &msg);
+
+ if (!msg_ctx)
+ break;
+ }
+
+ len += 1;
+ ret = _plug_buf_alloc(utils, &out, &curlen, len);
+ if(ret != SASL_OK) {
+ utils->free(out);
+ return;
+ }
+
+ strcat(out, ")");
+
+#ifdef _SUN_SDK_
+ if (logonly) {
+ utils->log(text->utils->conn, SASL_LOG_FAIL, out);
+ } else {
+ utils->seterror(utils->conn, 0, out);
+ }
+#else
+ utils->seterror(utils->conn, 0, out);
+#endif /* _SUN_SDK_ */
+ utils->free(out);
+}
+
+static int
+sasl_gss_encode(void *context, const struct iovec *invec, unsigned numiov,
+ const char **output, unsigned *outputlen, int privacy)
+{
+ context_t *text = (context_t *)context;
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_t input_token, output_token;
+ gss_buffer_desc real_input_token, real_output_token;
+ int ret;
+ struct buffer_info *inblob, bufinfo;
+
+ if(!output) return SASL_BADPARAM;
+
+ if(numiov > 1) {
+ ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
+ if(ret != SASL_OK) return ret;
+ inblob = text->enc_in_buf;
+ } else {
+ bufinfo.data = invec[0].iov_base;
+ bufinfo.curlen = invec[0].iov_len;
+ inblob = &bufinfo;
+ }
+
+ if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) return SASL_NOTDONE;
+
+ input_token = &real_input_token;
+
+ real_input_token.value = inblob->data;
+ real_input_token.length = inblob->curlen;
+
+ output_token = &real_output_token;
+ output_token->value = NULL;
+ output_token->length = 0;
+
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ if (LOCK_MUTEX(&global_mutex) < 0)
+ return (SASL_FAIL);
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+ maj_stat = gss_wrap (&min_stat,
+ text->gss_ctx,
+ privacy,
+ GSS_C_QOP_DEFAULT,
+ input_token,
+ NULL,
+ output_token);
+
+ if (GSS_ERROR(maj_stat))
+ {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ if (output_token->value)
+ gss_release_buffer(&min_stat, output_token);
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ UNLOCK_MUTEX(&global_mutex);
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+ return SASL_FAIL;
+ }
+
+ if (output_token->value && output) {
+ int len;
+
+ ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
+ &(text->encode_buf_len), output_token->length + 4);
+
+ if (ret != SASL_OK) {
+ gss_release_buffer(&min_stat, output_token);
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ UNLOCK_MUTEX(&global_mutex);
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+ return ret;
+ }
+
+ len = htonl(output_token->length);
+ memcpy(text->encode_buf, &len, 4);
+ memcpy(text->encode_buf + 4, output_token->value, output_token->length);
+ }
+
+ if (outputlen) {
+ *outputlen = output_token->length + 4;
+ }
+
+ *output = text->encode_buf;
+
+ if (output_token->value)
+ gss_release_buffer(&min_stat, output_token);
+
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ UNLOCK_MUTEX(&global_mutex);
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+
+ return SASL_OK;
+}
+
+static int gssapi_privacy_encode(void *context, const struct iovec *invec,
+ unsigned numiov, const char **output,
+ unsigned *outputlen)
+{
+ return sasl_gss_encode(context,invec,numiov,output,outputlen,1);
+}
+
+static int gssapi_integrity_encode(void *context, const struct iovec *invec,
+ unsigned numiov, const char **output,
+ unsigned *outputlen)
+{
+ return sasl_gss_encode(context,invec,numiov,output,outputlen,0);
+}
+
+#define myMIN(a,b) (((a) < (b)) ? (a) : (b))
+
+static int gssapi_decode_once(void *context,
+ const char **input, unsigned *inputlen,
+ char **output, unsigned *outputlen)
+{
+ context_t *text = (context_t *) context;
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_t input_token, output_token;
+ gss_buffer_desc real_input_token, real_output_token;
+ int result;
+ unsigned diff;
+
+ if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) {
+#ifdef _INTEGRATED_SOLARIS_
+ SETERROR(text->utils, gettext("GSSAPI Failure"));
+#else
+ SETERROR(text->utils, "GSSAPI Failure");
+#endif /* _INTEGRATED_SOLARIS_ */
+ return SASL_NOTDONE;
+ }
+
+ /* first we need to extract a packet */
+ if (text->needsize > 0) {
+ /* how long is it? */
+ int tocopy = myMIN(text->needsize, *inputlen);
+
+ memcpy(text->sizebuf + 4 - text->needsize, *input, tocopy);
+ text->needsize -= tocopy;
+ *input += tocopy;
+ *inputlen -= tocopy;
+
+ if (text->needsize == 0) {
+ /* got the entire size */
+ memcpy(&text->size, text->sizebuf, 4);
+ text->size = ntohl(text->size);
+ text->cursize = 0;
+
+#ifdef _SUN_SDK_
+ if (text->size > 0xFFFFFF) {
+ text->utils->log(text->utils->conn, SASL_LOG_ERR,
+ "Illegal size in sasl_gss_decode_once");
+#else
+ if (text->size > 0xFFFFFF || text->size <= 0) {
+ SETERROR(text->utils, "Illegal size in sasl_gss_decode_once");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+ if (text->bufsize < text->size + 5) {
+ result = _plug_buf_alloc(text->utils, &text->buffer,
+ &(text->bufsize), text->size+5);
+ if(result != SASL_OK) return result;
+ }
+ }
+ if (*inputlen == 0) {
+ /* need more data ! */
+ *outputlen = 0;
+ *output = NULL;
+
+ return SASL_OK;
+ }
+ }
+
+ diff = text->size - text->cursize;
+
+ if (*inputlen < diff) {
+ /* ok, let's queue it up; not enough data */
+ memcpy(text->buffer + text->cursize, *input, *inputlen);
+ text->cursize += *inputlen;
+ *inputlen = 0;
+ *outputlen = 0;
+ *output = NULL;
+ return SASL_OK;
+ } else {
+ memcpy(text->buffer + text->cursize, *input, diff);
+ *input += diff;
+ *inputlen -= diff;
+ }
+
+ input_token = &real_input_token;
+ real_input_token.value = text->buffer;
+ real_input_token.length = text->size;
+
+ output_token = &real_output_token;
+ output_token->value = NULL;
+ output_token->length = 0;
+
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ if (LOCK_MUTEX(&global_mutex) < 0)
+ return (SASL_FAIL);
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+
+ maj_stat = gss_unwrap (&min_stat,
+ text->gss_ctx,
+ input_token,
+ output_token,
+ NULL,
+ NULL);
+
+ if (GSS_ERROR(maj_stat))
+ {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ if (output_token->value)
+ gss_release_buffer(&min_stat, output_token);
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ UNLOCK_MUTEX(&global_mutex);
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+ return SASL_FAIL;
+ }
+
+ if (outputlen)
+ *outputlen = output_token->length;
+
+ if (output_token->value) {
+ if (output) {
+ result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
+ &text->decode_once_buf_len,
+ *outputlen);
+ if(result != SASL_OK) {
+ gss_release_buffer(&min_stat, output_token);
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ UNLOCK_MUTEX(&global_mutex);
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+ return result;
+ }
+ *output = text->decode_once_buf;
+ memcpy(*output, output_token->value, *outputlen);
+ }
+ gss_release_buffer(&min_stat, output_token);
+ }
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ UNLOCK_MUTEX(&global_mutex);
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+
+ /* reset for the next packet */
+#ifndef _SUN_SDK_
+ text->size = -1;
+#endif /* !_SUN_SDK_ */
+ text->needsize = 4;
+
+ return SASL_OK;
+}
+
+static int gssapi_decode(void *context,
+ const char *input, unsigned inputlen,
+ const char **output, unsigned *outputlen)
+{
+ context_t *text = (context_t *) context;
+ int ret;
+
+ ret = _plug_decode(text->utils, context, input, inputlen,
+ &text->decode_buf, &text->decode_buf_len, outputlen,
+ gssapi_decode_once);
+
+ *output = text->decode_buf;
+
+ return ret;
+}
+
+static context_t *gss_new_context(const sasl_utils_t *utils)
+{
+ context_t *ret;
+
+ ret = utils->malloc(sizeof(context_t));
+ if(!ret) return NULL;
+
+ memset(ret,0,sizeof(context_t));
+ ret->utils = utils;
+#ifdef _SUN_SDK_
+ ret->gss_ctx = GSS_C_NO_CONTEXT;
+ ret->client_name = GSS_C_NO_NAME;
+ ret->server_name = GSS_C_NO_NAME;
+ ret->server_creds = GSS_C_NO_CREDENTIAL;
+ ret->client_creds = GSS_C_NO_CREDENTIAL;
+ if (get_oid(utils, &ret->mech_oid) != SASL_OK) {
+ utils->free(ret);
+ return (NULL);
+ }
+#endif /* _SUN_SDK_ */
+
+ ret->needsize = 4;
+
+ return ret;
+}
+
+static void sasl_gss_free_context_contents(context_t *text)
+{
+ OM_uint32 maj_stat, min_stat;
+
+ if (!text) return;
+
+ if (text->gss_ctx != GSS_C_NO_CONTEXT) {
+ maj_stat = gss_delete_sec_context (&min_stat,&text->gss_ctx,GSS_C_NO_BUFFER);
+ text->gss_ctx = GSS_C_NO_CONTEXT;
+ }
+
+ if (text->client_name != GSS_C_NO_NAME) {
+ maj_stat = gss_release_name(&min_stat,&text->client_name);
+ text->client_name = GSS_C_NO_NAME;
+ }
+
+ if (text->server_name != GSS_C_NO_NAME) {
+ maj_stat = gss_release_name(&min_stat,&text->server_name);
+ text->server_name = GSS_C_NO_NAME;
+ }
+
+ if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
+ maj_stat = gss_release_cred(&min_stat, &text->server_creds);
+ text->server_creds = GSS_C_NO_CREDENTIAL;
+ }
+
+#ifdef _SUN_SDK_
+ if ( text->client_creds != GSS_C_NO_CREDENTIAL) {
+ maj_stat = gss_release_cred(&min_stat, &text->client_creds);
+ text->client_creds = GSS_C_NO_CREDENTIAL;
+ }
+
+ /*
+ * Note that the oid returned by rpc_gss_mech_to_oid should not
+ * be released
+ */
+#endif /* _SUN_SDK_ */
+
+ if (text->out_buf) {
+ text->utils->free(text->out_buf);
+ text->out_buf = NULL;
+ }
+
+ if (text->encode_buf) {
+ text->utils->free(text->encode_buf);
+ text->encode_buf = NULL;
+ }
+
+ if (text->decode_buf) {
+ text->utils->free(text->decode_buf);
+ text->decode_buf = NULL;
+ }
+
+ if (text->decode_once_buf) {
+ text->utils->free(text->decode_once_buf);
+ text->decode_once_buf = NULL;
+ }
+
+ if (text->enc_in_buf) {
+ if(text->enc_in_buf->data) text->utils->free(text->enc_in_buf->data);
+ text->utils->free(text->enc_in_buf);
+ text->enc_in_buf = NULL;
+ }
+
+ if (text->buffer) {
+ text->utils->free(text->buffer);
+ text->buffer = NULL;
+ }
+
+ if (text->authid) { /* works for both client and server */
+ text->utils->free(text->authid);
+ text->authid = NULL;
+ }
+}
+
+#ifdef _SUN_SDK_
+
+#ifdef HAVE_RPC_GSS_MECH_TO_OID
+#include <rpc/rpcsec_gss.h>
+#endif /* HAVE_RPC_GSS_MECH_TO_OID */
+
+static int
+get_oid(const sasl_utils_t *utils, gss_OID *oid)
+{
+#ifdef HAVE_RPC_GSS_MECH_TO_OID
+ static gss_OID_desc kerb_v5 =
+ {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
+ /* 1.2.840.113554.1.2.2 */
+ *oid = &kerb_v5;
+#endif /* HAVE_RPC_GSS_MECH_TO_OID */
+ return (SASL_OK);
+}
+
+static int
+add_mech_to_set(context_t *text, gss_OID_set *desired_mechs)
+{
+ OM_uint32 maj_stat, min_stat;
+
+ maj_stat = gss_create_empty_oid_set(&min_stat, desired_mechs);
+
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ sasl_gss_free_context_contents(text);
+ return SASL_FAIL;
+ }
+
+ maj_stat = gss_add_oid_set_member(&min_stat, text->mech_oid, desired_mechs);
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ sasl_gss_free_context_contents(text);
+ (void) gss_release_oid_set(&min_stat, desired_mechs);
+ return SASL_FAIL;
+ }
+ return SASL_OK;
+}
+#endif /* _SUN_SDK_ */
+
+static void gssapi_common_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+#ifdef _SUN_SDK_
+ if (conn_context == NULL)
+ return;
+#ifdef _INTEGRATED_SOLARIS_
+ convert_prompt(utils, &((context_t *)conn_context)->h, NULL);
+#endif /* _INTEGRATED_SOLARIS_ */
+#endif /* _SUN_SDK_ */
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ (void) LOCK_MUTEX(&global_mutex);
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+ sasl_gss_free_context_contents((context_t *)(conn_context));
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ UNLOCK_MUTEX(&global_mutex);
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+ utils->free(conn_context);
+}
+
+/***************************** Server Section *****************************/
+
+static int
+gssapi_server_mech_new(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *params,
+ const char *challenge __attribute__((unused)),
+ unsigned challen __attribute__((unused)),
+ void **conn_context)
+{
+ context_t *text;
+
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ if (LOCK_MUTEX(&global_mutex) < 0)
+ return (SASL_FAIL);
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+ text = gss_new_context(params->utils);
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ UNLOCK_MUTEX(&global_mutex);
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+ if (text == NULL) {
+#ifndef _SUN_SDK_
+ MEMERROR(params->utils);
+#endif /* !_SUN_SDK_ */
+ return SASL_NOMEM;
+ }
+
+ text->gss_ctx = GSS_C_NO_CONTEXT;
+ text->client_name = GSS_C_NO_NAME;
+ text->server_name = GSS_C_NO_NAME;
+ text->server_creds = GSS_C_NO_CREDENTIAL;
+ text->state = SASL_GSSAPI_STATE_AUTHNEG;
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+static int
+gssapi_server_mech_step(void *conn_context,
+ sasl_server_params_t *params,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ context_t *text = (context_t *)conn_context;
+ gss_buffer_t input_token, output_token;
+ gss_buffer_desc real_input_token, real_output_token;
+ OM_uint32 maj_stat, min_stat;
+#ifdef _SUN_SDK_
+ OM_uint32 max_input_size;
+ gss_OID_set desired_mechs = GSS_C_NULL_OID_SET;
+#endif /* _SUN_SDK_ */
+ gss_buffer_desc name_token;
+ int ret;
+
+ input_token = &real_input_token;
+ output_token = &real_output_token;
+ output_token->value = NULL; output_token->length = 0;
+ input_token->value = NULL; input_token->length = 0;
+
+ if(!serverout) {
+ PARAMERROR(text->utils);
+ return SASL_BADPARAM;
+ }
+
+ *serverout = NULL;
+ *serveroutlen = 0;
+
+ switch (text->state) {
+
+ case SASL_GSSAPI_STATE_AUTHNEG:
+ if (text->server_name == GSS_C_NO_NAME) { /* only once */
+ name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
+ name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
+ if (name_token.value == NULL) {
+ MEMERROR(text->utils);
+ sasl_gss_free_context_contents(text);
+ return SASL_NOMEM;
+ }
+#ifdef _SUN_SDK_
+ snprintf(name_token.value, name_token.length + 1,
+ "%s@%s", params->service, params->serverFQDN);
+#else
+ sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
+#endif /* _SUN_SDK_ */
+
+ maj_stat = gss_import_name (&min_stat,
+ &name_token,
+ GSS_C_NT_HOSTBASED_SERVICE,
+ &text->server_name);
+
+ params->utils->free(name_token.value);
+ name_token.value = NULL;
+
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ sasl_gss_free_context_contents(text);
+ return SASL_FAIL;
+ }
+
+ if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
+ maj_stat = gss_release_cred(&min_stat, &text->server_creds);
+ text->server_creds = GSS_C_NO_CREDENTIAL;
+ }
+
+#ifdef _SUN_SDK_
+ if (text->mech_oid != GSS_C_NULL_OID) {
+ ret = add_mech_to_set(text, &desired_mechs);
+ if (ret != SASL_OK)
+ return (ret);
+ }
+#endif /* _SUN_SDK_ */
+
+ maj_stat = gss_acquire_cred(&min_stat,
+ text->server_name,
+ GSS_C_INDEFINITE,
+#ifdef _SUN_SDK_
+ desired_mechs,
+#else
+ GSS_C_NO_OID_SET,
+#endif /* _SUN_SDK_ */
+ GSS_C_ACCEPT,
+ &text->server_creds,
+ NULL,
+ NULL);
+
+#ifdef _SUN_SDK_
+ if (desired_mechs != GSS_C_NULL_OID_SET) {
+ OM_uint32 min_stat2;
+ (void) gss_release_oid_set(&min_stat2, &desired_mechs);
+ }
+#endif /* _SUN_SDK_ */
+
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ sasl_gss_free_context_contents(text);
+ return SASL_FAIL;
+ }
+ }
+
+ if (clientinlen) {
+ real_input_token.value = (void *)clientin;
+ real_input_token.length = clientinlen;
+ }
+
+ maj_stat =
+ gss_accept_sec_context(&min_stat,
+ &(text->gss_ctx),
+ text->server_creds,
+ input_token,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &text->client_name,
+ NULL,
+ output_token,
+ NULL,
+ NULL,
+ NULL);
+
+ if (GSS_ERROR(maj_stat)) {
+#ifdef _SUN_SDK_
+ /* log the local error info, set a more generic error */
+ sasl_gss_log(text->utils, maj_stat, min_stat);
+ text->utils->seterror(text->utils->conn, SASL_NOLOG,
+ gettext("GSSAPI Failure: accept security context error"));
+ if (output_token->value) {
+ gss_release_buffer(&min_stat, output_token);
+ }
+#else
+ if (output_token->value) {
+ gss_release_buffer(&min_stat, output_token);
+ }
+ text->utils->seterror(text->utils->conn, SASL_NOLOG, "GSSAPI Failure: gss_accept_sec_context");
+ text->utils->log(NULL, SASL_LOG_DEBUG, "GSSAPI Failure: gss_accept_sec_context");
+#endif /* _SUN_SDK_ */
+ sasl_gss_free_context_contents(text);
+ return SASL_BADAUTH;
+ }
+
+ if (serveroutlen)
+ *serveroutlen = output_token->length;
+ if (output_token->value) {
+ if (serverout) {
+ ret = _plug_buf_alloc(text->utils, &(text->out_buf),
+ &(text->out_buf_len), *serveroutlen);
+ if(ret != SASL_OK) {
+ gss_release_buffer(&min_stat, output_token);
+ return ret;
+ }
+ memcpy(text->out_buf, output_token->value, *serveroutlen);
+ *serverout = text->out_buf;
+ }
+
+ gss_release_buffer(&min_stat, output_token);
+ } else {
+ /* No output token, send an empty string */
+ *serverout = GSSAPI_BLANK_STRING;
+#ifndef _SUN_SDK_
+ serveroutlen = 0;
+#endif /* !_SUN_SDK_ */
+ }
+
+
+ if (maj_stat == GSS_S_COMPLETE) {
+ /* Switch to ssf negotiation */
+ text->state = SASL_GSSAPI_STATE_SSFCAP;
+ }
+
+ return SASL_CONTINUE;
+
+ case SASL_GSSAPI_STATE_SSFCAP: {
+ unsigned char sasldata[4];
+ gss_buffer_desc name_token;
+#ifndef _SUN_SDK_
+ gss_buffer_desc name_without_realm;
+ gss_name_t without = NULL;
+ int equal;
+#endif /* !_SUN_SDK_ */
+
+ name_token.value = NULL;
+#ifndef _SUN_SDK_
+ name_without_realm.value = NULL;
+#endif /* !_SUN_SDK_ */
+
+ /* We ignore whatever the client sent us at this stage */
+
+ maj_stat = gss_display_name (&min_stat,
+ text->client_name,
+ &name_token,
+ NULL);
+
+ if (GSS_ERROR(maj_stat)) {
+#ifndef _SUN_SDK_
+ if (name_without_realm.value)
+ params->utils->free(name_without_realm.value);
+#endif /* !_SUN_SDK_ */
+
+ if (name_token.value)
+ gss_release_buffer(&min_stat, &name_token);
+#ifndef _SUN_SDK_
+ if (without)
+ gss_release_name(&min_stat, &without);
+#endif /* !_SUN_SDK_ */
+#ifdef _INTEGRATED_SOLARIS_
+ SETERROR(text->utils, gettext("GSSAPI Failure"));
+#else
+ SETERROR(text->utils, "GSSAPI Failure");
+#endif /* _INTEGRATED_SOLARIS_ */
+ sasl_gss_free_context_contents(text);
+ return SASL_BADAUTH;
+ }
+
+#ifndef _SUN_SDK_
+ /* If the id contains a realm get the identifier for the user
+ without the realm and see if it's the same id (i.e.
+ tmartin == tmartin@ANDREW.CMU.EDU. If this is the case we just want
+ to return the id (i.e. just "tmartin" */
+ if (strchr((char *) name_token.value, (int) '@') != NULL) {
+ /* NOTE: libc malloc, as it is freed below by a gssapi internal
+ * function! */
+ name_without_realm.value = malloc(strlen(name_token.value)+1);
+ if (name_without_realm.value == NULL) {
+ MEMERROR(text->utils);
+ return SASL_NOMEM;
+ }
+
+ strcpy(name_without_realm.value, name_token.value);
+
+ /* cut off string at '@' */
+ (strchr(name_without_realm.value,'@'))[0] = '\0';
+
+ name_without_realm.length = strlen( (char *) name_without_realm.value );
+
+ maj_stat = gss_import_name (&min_stat,
+ &name_without_realm,
+ /* Solaris 8/9 gss_import_name doesn't accept GSS_C_NULL_OID here,
+ so use GSS_C_NT_USER_NAME instead if available. */
+#ifdef HAVE_GSS_C_NT_USER_NAME
+ GSS_C_NT_USER_NAME,
+#else
+ GSS_C_NULL_OID,
+#endif
+ &without);
+
+ if (GSS_ERROR(maj_stat)) {
+ params->utils->free(name_without_realm.value);
+ if (name_token.value)
+ gss_release_buffer(&min_stat, &name_token);
+ if (without)
+ gss_release_name(&min_stat, &without);
+ SETERROR(text->utils, "GSSAPI Failure");
+ sasl_gss_free_context_contents(text);
+ return SASL_BADAUTH;
+ }
+
+ maj_stat = gss_compare_name(&min_stat,
+ text->client_name,
+ without,
+ &equal);
+
+ if (GSS_ERROR(maj_stat)) {
+ params->utils->free(name_without_realm.value);
+ if (name_token.value)
+ gss_release_buffer(&min_stat, &name_token);
+ if (without)
+ gss_release_name(&min_stat, &without);
+ SETERROR(text->utils, "GSSAPI Failure");
+ sasl_gss_free_context_contents(text);
+ return SASL_BADAUTH;
+ }
+
+ gss_release_name(&min_stat,&without);
+ } else {
+ equal = 0;
+ }
+
+ if (equal) {
+ text->authid = strdup(name_without_realm.value);
+
+ if (text->authid == NULL) {
+ MEMERROR(params->utils);
+ return SASL_NOMEM;
+ }
+ } else {
+ text->authid = strdup(name_token.value);
+
+ if (text->authid == NULL) {
+ MEMERROR(params->utils);
+ return SASL_NOMEM;
+ }
+ }
+#else
+ {
+ ret = _plug_strdup(params->utils, name_token.value,
+ &text->authid, NULL);
+ }
+#endif /* _SUN_SDK_ */
+
+ if (name_token.value)
+ gss_release_buffer(&min_stat, &name_token);
+
+#ifdef _SUN_SDK_
+ if (ret != SASL_OK)
+ return (ret);
+#else
+ if (name_without_realm.value)
+ params->utils->free(name_without_realm.value);
+#endif /* _SUN_SDK_ */
+
+
+ /* we have to decide what sort of encryption/integrity/etc.,
+ we support */
+ if (params->props.max_ssf < params->external_ssf) {
+ text->limitssf = 0;
+ } else {
+ text->limitssf = params->props.max_ssf - params->external_ssf;
+ }
+ if (params->props.min_ssf < params->external_ssf) {
+ text->requiressf = 0;
+ } else {
+ text->requiressf = params->props.min_ssf - params->external_ssf;
+ }
+
+ /* build up our security properties token */
+ if (params->props.maxbufsize > 0xFFFFFF) {
+ /* make sure maxbufsize isn't too large */
+ /* maxbufsize = 0xFFFFFF */
+ sasldata[1] = sasldata[2] = sasldata[3] = 0xFF;
+ } else {
+ sasldata[1] = (params->props.maxbufsize >> 16) & 0xFF;
+ sasldata[2] = (params->props.maxbufsize >> 8) & 0xFF;
+ sasldata[3] = (params->props.maxbufsize >> 0) & 0xFF;
+ }
+ sasldata[0] = 0;
+ if(text->requiressf != 0 && !params->props.maxbufsize) {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "GSSAPI needs a security layer but one is forbidden");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "GSSAPI needs a security layer but one is forbidden");
+#endif /* _SUN_SDK_ */
+ return SASL_TOOWEAK;
+ }
+
+ if (text->requiressf == 0) {
+ sasldata[0] |= 1; /* authentication */
+ }
+ if (text->requiressf <= 1 && text->limitssf >= 1
+ && params->props.maxbufsize) {
+ sasldata[0] |= 2;
+ }
+ if (text->requiressf <= 56 && text->limitssf >= 56
+ && params->props.maxbufsize) {
+ sasldata[0] |= 4;
+ }
+
+ real_input_token.value = (void *)sasldata;
+ real_input_token.length = 4;
+
+ maj_stat = gss_wrap(&min_stat,
+ text->gss_ctx,
+ 0, /* Just integrity checking here */
+ GSS_C_QOP_DEFAULT,
+ input_token,
+ NULL,
+ output_token);
+
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ if (output_token->value)
+ gss_release_buffer(&min_stat, output_token);
+ sasl_gss_free_context_contents(text);
+ return SASL_FAIL;
+ }
+
+
+ if (serveroutlen)
+ *serveroutlen = output_token->length;
+ if (output_token->value) {
+ if (serverout) {
+ ret = _plug_buf_alloc(text->utils, &(text->out_buf),
+ &(text->out_buf_len), *serveroutlen);
+ if(ret != SASL_OK) {
+ gss_release_buffer(&min_stat, output_token);
+ return ret;
+ }
+ memcpy(text->out_buf, output_token->value, *serveroutlen);
+ *serverout = text->out_buf;
+ }
+
+ gss_release_buffer(&min_stat, output_token);
+ }
+
+ /* Wait for ssf request and authid */
+ text->state = SASL_GSSAPI_STATE_SSFREQ;
+
+ return SASL_CONTINUE;
+ }
+
+ case SASL_GSSAPI_STATE_SSFREQ: {
+ int layerchoice;
+
+ real_input_token.value = (void *)clientin;
+ real_input_token.length = clientinlen;
+
+ maj_stat = gss_unwrap(&min_stat,
+ text->gss_ctx,
+ input_token,
+ output_token,
+ NULL,
+ NULL);
+
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ sasl_gss_free_context_contents(text);
+ return SASL_FAIL;
+ }
+
+ layerchoice = (int)(((char *)(output_token->value))[0]);
+ if (layerchoice == 1 && text->requiressf == 0) { /* no encryption */
+ oparams->encode = NULL;
+ oparams->decode = NULL;
+ oparams->mech_ssf = 0;
+ } else if (layerchoice == 2 && text->requiressf <= 1 &&
+ text->limitssf >= 1) { /* integrity */
+ oparams->encode=&gssapi_integrity_encode;
+ oparams->decode=&gssapi_decode;
+ oparams->mech_ssf=1;
+ } else if (layerchoice == 4 && text->requiressf <= 56 &&
+ text->limitssf >= 56) { /* privacy */
+ oparams->encode = &gssapi_privacy_encode;
+ oparams->decode = &gssapi_decode;
+ oparams->mech_ssf = 56;
+ } else {
+ /* not a supported encryption layer */
+#ifdef _SUN_SDK_
+ text->utils->log(text->utils->conn, SASL_LOG_ERR,
+ "protocol violation: client requested invalid layer");
+#else
+ SETERROR(text->utils,
+ "protocol violation: client requested invalid layer");
+#endif /* _SUN_SDK_ */
+ /* Mark that we attempted negotiation */
+ oparams->mech_ssf = 2;
+ if (output_token->value)
+ gss_release_buffer(&min_stat, output_token);
+ sasl_gss_free_context_contents(text);
+ return SASL_FAIL;
+ }
+
+ if (output_token->length > 4) {
+ int ret;
+
+ ret = params->canon_user(params->utils->conn,
+ ((char *) output_token->value) + 4,
+ (output_token->length - 4) * sizeof(char),
+ SASL_CU_AUTHZID, oparams);
+
+ if (ret != SASL_OK) {
+ sasl_gss_free_context_contents(text);
+ return ret;
+ }
+
+ ret = params->canon_user(params->utils->conn,
+ text->authid,
+ 0, /* strlen(text->authid) */
+ SASL_CU_AUTHID, oparams);
+ if (ret != SASL_OK) {
+ sasl_gss_free_context_contents(text);
+ return ret;
+ }
+ } else if(output_token->length == 4) {
+ /* null authzid */
+ int ret;
+
+ ret = params->canon_user(params->utils->conn,
+ text->authid,
+ 0, /* strlen(text->authid) */
+ SASL_CU_AUTHZID | SASL_CU_AUTHID,
+ oparams);
+
+ if (ret != SASL_OK) {
+ sasl_gss_free_context_contents(text);
+ return ret;
+ }
+ } else {
+#ifdef _SUN_SDK_
+ text->utils->log(text->utils->conn, SASL_LOG_ERR,
+ "token too short");
+#else
+ SETERROR(text->utils,
+ "token too short");
+#endif /* _SUN_SDK_ */
+ gss_release_buffer(&min_stat, output_token);
+ sasl_gss_free_context_contents(text);
+ return SASL_FAIL;
+ }
+
+ /* No matter what, set the rest of the oparams */
+ oparams->maxoutbuf =
+ (((unsigned char *) output_token->value)[1] << 16) |
+ (((unsigned char *) output_token->value)[2] << 8) |
+ (((unsigned char *) output_token->value)[3] << 0);
+
+#ifdef _SUN_SDK_
+ if (oparams->mech_ssf) {
+ oparams->maxoutbuf -= 4; /* Allow for 4 byte tag */
+ maj_stat = gss_wrap_size_limit(&min_stat,
+ text->gss_ctx,
+ oparams->mech_ssf > 1,
+ GSS_C_QOP_DEFAULT,
+ oparams->maxoutbuf,
+ &max_input_size);
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ (void) gss_release_buffer(&min_stat, output_token);
+ sasl_gss_free_context_contents(text);
+ return (SASL_FAIL);
+ }
+
+ /*
+ * gss_wrap_size_limit will return very big sizes for
+ * small input values
+ */
+ if (max_input_size < oparams->maxoutbuf)
+ oparams->maxoutbuf = max_input_size;
+ else {
+ oparams->maxoutbuf = 0;
+ }
+ }
+#else
+ if (oparams->mech_ssf) {
+ /* xxx this is probably too big */
+ oparams->maxoutbuf -= 50;
+ }
+#endif /* _SUN_SDK_ */
+
+ gss_release_buffer(&min_stat, output_token);
+
+ text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
+
+ oparams->doneflag = 1;
+
+ return SASL_OK;
+ }
+
+ default:
+#ifdef _SUN_SDK_
+ params->utils->log(text->utils->conn, SASL_LOG_ERR,
+ "Invalid GSSAPI server step %d", text->state);
+#else
+ params->utils->log(NULL, SASL_LOG_ERR,
+ "Invalid GSSAPI server step %d\n", text->state);
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+#ifndef _SUN_SDK_
+ return SASL_FAIL; /* should never get here */
+#endif /* !_SUN_SDK_ */
+}
+
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+static int
+_gssapi_server_mech_step(void *conn_context,
+ sasl_server_params_t *params,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ int ret;
+
+ if (LOCK_MUTEX(&global_mutex) < 0)
+ return (SASL_FAIL);
+
+ ret = gssapi_server_mech_step(conn_context, params, clientin, clientinlen,
+ serverout, serveroutlen, oparams);
+
+ UNLOCK_MUTEX(&global_mutex);
+ return (ret);
+}
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+
+static sasl_server_plug_t gssapi_server_plugins[] =
+{
+ {
+ "GSSAPI", /* mech_name */
+ 56, /* max_ssf */
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOACTIVE
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_WANT_CLIENT_FIRST
+ | SASL_FEAT_ALLOWS_PROXY, /* features */
+ NULL, /* glob_context */
+ &gssapi_server_mech_new, /* mech_new */
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ &_gssapi_server_mech_step, /* mech_step */
+#else
+ &gssapi_server_mech_step, /* mech_step */
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+ &gssapi_common_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ NULL, /* mech_avail */
+ NULL /* spare */
+ }
+};
+
+int gssapiv2_server_plug_init(
+#ifndef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
+ const sasl_utils_t *utils __attribute__((unused)),
+#else
+ const sasl_utils_t *utils,
+#endif
+ int maxversion,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount)
+{
+#ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
+ const char *keytab = NULL;
+ char keytab_path[1024];
+ unsigned int rl;
+#endif
+
+ if (maxversion < SASL_SERVER_PLUG_VERSION) {
+ return SASL_BADVERS;
+ }
+
+#ifndef _SUN_SDK_
+#ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
+ /* unfortunately, we don't check for readability of keytab if it's
+ the standard one, since we don't know where it is */
+
+ /* FIXME: This code is broken */
+
+ utils->getopt(utils->getopt_context, "GSSAPI", "keytab", &keytab, &rl);
+ if (keytab != NULL) {
+ if (access(keytab, R_OK) != 0) {
+ utils->log(NULL, SASL_LOG_ERR,
+ "Could not find keytab file: %s: %m",
+ keytab, errno);
+ return SASL_FAIL;
+ }
+
+ if(strlen(keytab) > 1024) {
+ utils->log(NULL, SASL_LOG_ERR,
+ "path to keytab is > 1024 characters");
+ return SASL_BUFOVER;
+ }
+
+ strncpy(keytab_path, keytab, 1024);
+
+ gsskrb5_register_acceptor_identity(keytab_path);
+ }
+#endif
+#endif /* !_SUN_SDK_ */
+
+ /* EXPORT DELETE START */
+ /* CRYPT DELETE START */
+#ifdef _INTEGRATED_SOLARIS_
+ /*
+ * Let libsasl know that we are a "Sun" plugin so that privacy
+ * and integrity will be allowed.
+ */
+ REG_PLUG("GSSAPI", gssapi_server_plugins);
+#endif /* _INTEGRATED_SOLARIS_ */
+ /* CRYPT DELETE END */
+ /* EXPORT DELETE END */
+
+ *out_version = SASL_SERVER_PLUG_VERSION;
+ *pluglist = gssapi_server_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
+
+/***************************** Client Section *****************************/
+
+static int gssapi_client_mech_new(void *glob_context __attribute__((unused)),
+ sasl_client_params_t *params,
+ void **conn_context)
+{
+ context_t *text;
+#ifdef _SUN_SDK_
+ const char *use_authid = NULL;
+#endif /* _SUN_SDK_ */
+
+ /* holds state are in */
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ if (LOCK_MUTEX(&global_mutex) < 0)
+ return (SASL_FAIL);
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+ text = gss_new_context(params->utils);
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ UNLOCK_MUTEX(&global_mutex);
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+ if (text == NULL) {
+#ifndef _SUN_SDK_
+ MEMERROR(params->utils);
+#endif /* !_SUN_SDK_ */
+ return SASL_NOMEM;
+ }
+
+ text->state = SASL_GSSAPI_STATE_AUTHNEG;
+ text->gss_ctx = GSS_C_NO_CONTEXT;
+ text->client_name = GSS_C_NO_NAME;
+ text->server_creds = GSS_C_NO_CREDENTIAL;
+
+#ifdef _SUN_SDK_
+ params->utils->getopt(params->utils->getopt_context,
+ "GSSAPI", "use_authid", &use_authid, NULL);
+ text->use_authid = (use_authid != NULL) &&
+ (*use_authid == 'y' || *use_authid == 'Y' || *use_authid == '1');
+#endif /* _SUN_SDK_ */
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+static int gssapi_client_mech_step(void *conn_context,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ context_t *text = (context_t *)conn_context;
+ gss_buffer_t input_token, output_token;
+ gss_buffer_desc real_input_token, real_output_token;
+ OM_uint32 maj_stat, min_stat;
+#ifdef _SUN_SDK_
+ OM_uint32 max_input_size;
+#endif /* _SUN_SDK_ */
+ gss_buffer_desc name_token;
+ int ret;
+ OM_uint32 req_flags, out_req_flags;
+ input_token = &real_input_token;
+ output_token = &real_output_token;
+ output_token->value = NULL;
+ input_token->value = NULL;
+ input_token->length = 0;
+
+ *clientout = NULL;
+ *clientoutlen = 0;
+
+ switch (text->state) {
+
+ case SASL_GSSAPI_STATE_AUTHNEG:
+ /* try to get the userid */
+#ifdef _SUN_SDK_
+ if (text->user == NULL ||
+ (text->use_authid && text->client_authid == NULL)) {
+ int auth_result = SASL_OK;
+ int user_result = SASL_OK;
+
+ if (text->use_authid && text->client_authid == NULL) {
+ auth_result = _plug_get_authid(params->utils,
+ &text->client_authid,
+ prompt_need);
+
+ if ((auth_result != SASL_OK) &&
+ (auth_result != SASL_INTERACT)) {
+ sasl_gss_free_context_contents(text);
+ return auth_result;
+ }
+ }
+ if (text->user == NULL) {
+ user_result = _plug_get_userid(params->utils, &text->user,
+ prompt_need);
+
+ if ((user_result != SASL_OK) &&
+ (user_result != SASL_INTERACT)) {
+ sasl_gss_free_context_contents(text);
+ return user_result;
+ }
+ }
+#else
+ if (text->user == NULL) {
+ int user_result = SASL_OK;
+
+ user_result = _plug_get_userid(params->utils, &text->user,
+ prompt_need);
+
+ if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
+ sasl_gss_free_context_contents(text);
+ return user_result;
+ }
+#endif /* _SUN_SDK_ */
+
+ /* free prompts we got */
+ if (prompt_need && *prompt_need) {
+ params->utils->free(*prompt_need);
+ *prompt_need = NULL;
+ }
+
+ /* if there are prompts not filled in */
+#ifdef _SUN_SDK_
+ if ((user_result == SASL_INTERACT) ||
+ (auth_result == SASL_INTERACT)) {
+ /* make the prompt list */
+#ifdef _INTEGRATED_SOLARIS_
+ int result = _plug_make_prompts(params->utils, &text->h,
+ prompt_need,
+ user_result == SASL_INTERACT ?
+ convert_prompt(params->utils, &text->h,
+ gettext("Please enter your authorization name"))
+ : NULL, NULL,
+ auth_result == SASL_INTERACT ?
+ convert_prompt(params->utils, &text->h,
+ gettext("Please enter your authentication name"))
+ : NULL, NULL,
+ NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+#else
+ int result = _plug_make_prompts(params->utils, prompt_need,
+ user_result == SASL_INTERACT ?
+ "Please enter your authorization name"
+ : NULL, NULL,
+ auth_result == SASL_INTERACT ?
+ "Please enter your authentication name"
+ : NULL, NULL,
+ NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+#endif /* _INTEGRATED_SOLARIS_ */
+
+ if (result != SASL_OK) return result;
+
+ return SASL_INTERACT;
+ }
+#else
+ if (user_result == SASL_INTERACT) {
+ /* make the prompt list */
+ int result =
+ _plug_make_prompts(params->utils, prompt_need,
+ user_result == SASL_INTERACT ?
+ "Please enter your authorization name" : NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ if (result != SASL_OK) return result;
+
+ return SASL_INTERACT;
+ }
+#endif /* _SUN_SDK_ */
+ }
+
+ if (text->server_name == GSS_C_NO_NAME) { /* only once */
+ name_token.length = strlen(params->service) + 1 + strlen(params->serverFQDN);
+ name_token.value = (char *)params->utils->malloc((name_token.length + 1) * sizeof(char));
+ if (name_token.value == NULL) {
+ sasl_gss_free_context_contents(text);
+ return SASL_NOMEM;
+ }
+ if (params->serverFQDN == NULL
+ || strlen(params->serverFQDN) == 0) {
+#ifdef _SUN_SDK_
+ text->utils->log(text->utils->conn, SASL_LOG_ERR,
+ "GSSAPI Failure: no serverFQDN");
+#else
+ SETERROR(text->utils, "GSSAPI Failure: no serverFQDN");
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+#ifdef _SUN_SDK_
+ snprintf(name_token.value, name_token.length + 1,
+ "%s@%s", params->service, params->serverFQDN);
+#else
+ sprintf(name_token.value,"%s@%s", params->service, params->serverFQDN);
+#endif /* _SUN_SDK_ */
+
+ maj_stat = gss_import_name (&min_stat,
+ &name_token,
+ GSS_C_NT_HOSTBASED_SERVICE,
+ &text->server_name);
+
+ params->utils->free(name_token.value);
+ name_token.value = NULL;
+
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ sasl_gss_free_context_contents(text);
+ return SASL_FAIL;
+ }
+ }
+
+ if (serverinlen == 0)
+ input_token = GSS_C_NO_BUFFER;
+
+ if (serverinlen) {
+ real_input_token.value = (void *)serverin;
+ real_input_token.length = serverinlen;
+ }
+ else if (text->gss_ctx != GSS_C_NO_CONTEXT ) {
+ /* This can't happen under GSSAPI: we have a non-null context
+ * and no input from the server. However, thanks to Imap,
+ * which discards our first output, this happens all the time.
+ * Throw away the context and try again. */
+ maj_stat = gss_delete_sec_context (&min_stat,&text->gss_ctx,GSS_C_NO_BUFFER);
+ text->gss_ctx = GSS_C_NO_CONTEXT;
+ }
+
+ /* Setup req_flags properly */
+ req_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
+ if(params->props.max_ssf > params->external_ssf) {
+ /* We are requesting a security layer */
+ req_flags |= GSS_C_INTEG_FLAG;
+ if(params->props.max_ssf - params->external_ssf > 56) {
+ /* We want to try for privacy */
+ req_flags |= GSS_C_CONF_FLAG;
+ }
+ }
+
+#ifdef _SUN_SDK_
+ if (text->use_authid && text->client_creds == GSS_C_NO_CREDENTIAL) {
+ gss_OID_set desired_mechs = GSS_C_NULL_OID_SET;
+ gss_buffer_desc name_token;
+
+ name_token.length = strlen(text->client_authid);
+ name_token.value = (char *)text->client_authid;
+
+ maj_stat = gss_import_name (&min_stat,
+ &name_token,
+#ifdef HAVE_GSS_C_NT_USER_NAME
+ GSS_C_NT_USER_NAME,
+#else
+ GSS_C_NULL_OID,
+#endif
+ &text->client_name);
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ sasl_gss_free_context_contents(text);
+ return SASL_FAIL;
+ }
+
+ if (text->mech_oid != GSS_C_NULL_OID) {
+ ret = add_mech_to_set(text, &desired_mechs);
+ if (ret != SASL_OK)
+ return (ret);
+ }
+
+ maj_stat = gss_acquire_cred(&min_stat,
+ text->client_name,
+ GSS_C_INDEFINITE,
+ desired_mechs,
+ GSS_C_INITIATE,
+ &text->client_creds,
+ NULL,
+ NULL);
+
+ if (desired_mechs != GSS_C_NULL_OID_SET) {
+ OM_uint32 min_stat2;
+ (void) gss_release_oid_set(&min_stat2, &desired_mechs);
+ }
+
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ sasl_gss_free_context_contents(text);
+ return SASL_FAIL;
+ }
+ }
+#endif /* _SUN_SDK_ */
+
+ maj_stat = gss_init_sec_context(&min_stat,
+#ifdef _SUN_SDK_
+ text->client_creds,
+#else
+ GSS_C_NO_CREDENTIAL,
+#endif /* _SUN_SDK_ */
+ &text->gss_ctx,
+ text->server_name,
+#ifdef _SUN_SDK_
+ text->mech_oid,
+#else
+ GSS_C_NO_OID,
+#endif /* _SUN_SDK_ */
+ req_flags,
+ 0,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ input_token,
+ NULL,
+ output_token,
+ &out_req_flags,
+ NULL);
+
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ if (output_token->value)
+ gss_release_buffer(&min_stat, output_token);
+ sasl_gss_free_context_contents(text);
+ return SASL_FAIL;
+ }
+
+ *clientoutlen = output_token->length;
+
+ if (output_token->value) {
+ if (clientout) {
+ ret = _plug_buf_alloc(text->utils, &(text->out_buf),
+ &(text->out_buf_len), *clientoutlen);
+ if(ret != SASL_OK) {
+ gss_release_buffer(&min_stat, output_token);
+ return ret;
+ }
+ memcpy(text->out_buf, output_token->value, *clientoutlen);
+ *clientout = text->out_buf;
+ }
+
+ gss_release_buffer(&min_stat, output_token);
+ }
+
+ if (maj_stat == GSS_S_COMPLETE) {
+ maj_stat = gss_inquire_context(&min_stat,
+ text->gss_ctx,
+ &text->client_name,
+ NULL, /* targ_name */
+ NULL, /* lifetime */
+ NULL, /* mech */
+ NULL, /* flags */
+ NULL, /* local init */
+ NULL); /* open */
+
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ sasl_gss_free_context_contents(text);
+ return SASL_FAIL;
+ }
+
+ name_token.length = 0;
+ maj_stat = gss_display_name(&min_stat,
+ text->client_name,
+ &name_token,
+ NULL);
+
+ if (GSS_ERROR(maj_stat)) {
+ if (name_token.value)
+ gss_release_buffer(&min_stat, &name_token);
+#ifdef _INTEGRATED_SOLARIS_
+ SETERROR(text->utils, gettext("GSSAPI Failure"));
+#else
+ SETERROR(text->utils, "GSSAPI Failure");
+#endif /* _INTEGRATED_SOLARIS_ */
+ sasl_gss_free_context_contents(text);
+ return SASL_FAIL;
+ }
+
+ if (text->user && text->user[0]) {
+ ret = params->canon_user(params->utils->conn,
+ text->user, 0,
+ SASL_CU_AUTHZID, oparams);
+ if (ret == SASL_OK)
+ ret = params->canon_user(params->utils->conn,
+ name_token.value, 0,
+ SASL_CU_AUTHID, oparams);
+ } else {
+ ret = params->canon_user(params->utils->conn,
+ name_token.value, 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID,
+ oparams);
+ }
+ gss_release_buffer(&min_stat, &name_token);
+
+ if (ret != SASL_OK) return ret;
+
+ /* Switch to ssf negotiation */
+ text->state = SASL_GSSAPI_STATE_SSFCAP;
+ }
+
+ return SASL_CONTINUE;
+
+ case SASL_GSSAPI_STATE_SSFCAP: {
+ sasl_security_properties_t *secprops = &(params->props);
+ unsigned int alen, external = params->external_ssf;
+ sasl_ssf_t need, allowed;
+ char serverhas, mychoice;
+
+ real_input_token.value = (void *) serverin;
+ real_input_token.length = serverinlen;
+
+ maj_stat = gss_unwrap(&min_stat,
+ text->gss_ctx,
+ input_token,
+ output_token,
+ NULL,
+ NULL);
+
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ sasl_gss_free_context_contents(text);
+ if (output_token->value)
+ gss_release_buffer(&min_stat, output_token);
+ return SASL_FAIL;
+ }
+
+ /* taken from kerberos.c */
+ if (secprops->min_ssf > (56 + external)) {
+ return SASL_TOOWEAK;
+ } else if (secprops->min_ssf > secprops->max_ssf) {
+ return SASL_BADPARAM;
+ }
+
+ /* need bits of layer -- sasl_ssf_t is unsigned so be careful */
+ if (secprops->max_ssf >= external) {
+ allowed = secprops->max_ssf - external;
+ } else {
+ allowed = 0;
+ }
+ if (secprops->min_ssf >= external) {
+ need = secprops->min_ssf - external;
+ } else {
+ /* good to go */
+ need = 0;
+ }
+
+ /* bit mask of server support */
+ serverhas = ((char *)output_token->value)[0];
+
+ /* if client didn't set use strongest layer available */
+ if (allowed >= 56 && need <= 56 && (serverhas & 4)) {
+ /* encryption */
+ oparams->encode = &gssapi_privacy_encode;
+ oparams->decode = &gssapi_decode;
+ oparams->mech_ssf = 56;
+ mychoice = 4;
+ } else if (allowed >= 1 && need <= 1 && (serverhas & 2)) {
+ /* integrity */
+ oparams->encode = &gssapi_integrity_encode;
+ oparams->decode = &gssapi_decode;
+ oparams->mech_ssf = 1;
+ mychoice = 2;
+#ifdef _SUN_SDK_
+ } else if (need == 0 && (serverhas & 1)) {
+#else
+ } else if (need <= 0 && (serverhas & 1)) {
+#endif /* _SUN_SDK_ */
+ /* no layer */
+ oparams->encode = NULL;
+ oparams->decode = NULL;
+ oparams->mech_ssf = 0;
+ mychoice = 1;
+ } else {
+ /* there's no appropriate layering for us! */
+ sasl_gss_free_context_contents(text);
+ return SASL_TOOWEAK;
+ }
+
+ oparams->maxoutbuf =
+ (((unsigned char *) output_token->value)[1] << 16) |
+ (((unsigned char *) output_token->value)[2] << 8) |
+ (((unsigned char *) output_token->value)[3] << 0);
+
+#ifdef _SUN_SDK_
+ if (oparams->mech_ssf > 0) {
+ oparams->maxoutbuf -= 4; /* Space for 4 byte length header */
+ maj_stat = gss_wrap_size_limit(&min_stat,
+ text->gss_ctx,
+ oparams->mech_ssf > 1,
+ GSS_C_QOP_DEFAULT,
+ oparams->maxoutbuf,
+ &max_input_size);
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ (void) gss_release_buffer(&min_stat, output_token);
+ sasl_gss_free_context_contents(text);
+ return (SASL_FAIL);
+ }
+
+ /*
+ * This is a workaround for a Solaris bug where
+ * gss_wrap_size_limit may return very big sizes for
+ * small input values
+ */
+ if (max_input_size < oparams->maxoutbuf)
+ oparams->maxoutbuf = max_input_size;
+ else {
+ oparams->maxoutbuf = 0;
+ }
+ }
+#else
+ if(oparams->mech_ssf) {
+ /* xxx probably too large */
+ oparams->maxoutbuf -= 50;
+ }
+#endif /* _SUN_SDK_ */
+
+ gss_release_buffer(&min_stat, output_token);
+
+ /* oparams->user is always set, due to canon_user requirements.
+ * Make sure the client actually requested it though, by checking
+ * if our context was set.
+ */
+ if (text->user && text->user[0])
+ alen = strlen(oparams->user);
+ else
+ alen = 0;
+
+ input_token->length = 4 + alen;
+ input_token->value =
+ (char *)params->utils->malloc((input_token->length + 1)*sizeof(char));
+ if (input_token->value == NULL) {
+ sasl_gss_free_context_contents(text);
+ return SASL_NOMEM;
+ }
+
+ if (alen)
+ memcpy((char *)input_token->value+4,oparams->user,alen);
+
+ /* build up our security properties token */
+ if (params->props.maxbufsize > 0xFFFFFF) {
+ /* make sure maxbufsize isn't too large */
+ /* maxbufsize = 0xFFFFFF */
+ ((unsigned char *)input_token->value)[1] = 0xFF;
+ ((unsigned char *)input_token->value)[2] = 0xFF;
+ ((unsigned char *)input_token->value)[3] = 0xFF;
+ } else {
+ ((unsigned char *)input_token->value)[1] =
+ (params->props.maxbufsize >> 16) & 0xFF;
+ ((unsigned char *)input_token->value)[2] =
+ (params->props.maxbufsize >> 8) & 0xFF;
+ ((unsigned char *)input_token->value)[3] =
+ (params->props.maxbufsize >> 0) & 0xFF;
+ }
+ ((unsigned char *)input_token->value)[0] = mychoice;
+
+ maj_stat = gss_wrap (&min_stat,
+ text->gss_ctx,
+ 0, /* Just integrity checking here */
+ GSS_C_QOP_DEFAULT,
+ input_token,
+ NULL,
+ output_token);
+
+ params->utils->free(input_token->value);
+ input_token->value = NULL;
+
+ if (GSS_ERROR(maj_stat)) {
+ sasl_gss_seterror(text->utils, maj_stat, min_stat);
+ if (output_token->value)
+ gss_release_buffer(&min_stat, output_token);
+ sasl_gss_free_context_contents(text);
+ return SASL_FAIL;
+ }
+
+ if (clientoutlen)
+ *clientoutlen = output_token->length;
+ if (output_token->value) {
+ if (clientout) {
+ ret = _plug_buf_alloc(text->utils, &(text->out_buf),
+ &(text->out_buf_len), *clientoutlen);
+ if (ret != SASL_OK) {
+ gss_release_buffer(&min_stat, output_token);
+ return ret;
+ }
+ memcpy(text->out_buf, output_token->value, *clientoutlen);
+ *clientout = text->out_buf;
+ }
+
+ gss_release_buffer(&min_stat, output_token);
+ }
+
+ text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
+
+ oparams->doneflag = 1;
+
+ return SASL_OK;
+ }
+
+ default:
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "Invalid GSSAPI client step %d", text->state);
+#else
+ params->utils->log(NULL, SASL_LOG_ERR,
+ "Invalid GSSAPI client step %d\n", text->state);
+#endif /* _SUN_SDK_ */
+ return SASL_FAIL;
+ }
+
+#ifndef _SUN_SDK_
+ return SASL_FAIL; /* should never get here */
+#endif /* !_SUN_SDK_ */
+}
+
+#ifdef _SUN_SDK_
+static const unsigned long gssapi_required_prompts[] = {
+#else
+static const long gssapi_required_prompts[] = {
+#endif /* _SUN_SDK_ */
+ SASL_CB_LIST_END
+};
+
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+static int _gssapi_client_mech_step(void *conn_context,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ int ret;
+
+ if (LOCK_MUTEX(&global_mutex) < 0)
+ return (SASL_FAIL);
+
+ ret = gssapi_client_mech_step(conn_context, params, serverin, serverinlen,
+ prompt_need, clientout, clientoutlen, oparams);
+
+ UNLOCK_MUTEX(&global_mutex);
+ return (ret);
+}
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+
+static sasl_client_plug_t gssapi_client_plugins[] =
+{
+ {
+ "GSSAPI", /* mech_name */
+ 56, /* max_ssf */
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOACTIVE
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_WANT_CLIENT_FIRST
+ | SASL_FEAT_ALLOWS_PROXY, /* features */
+ gssapi_required_prompts, /* required_prompts */
+ NULL, /* glob_context */
+ &gssapi_client_mech_new, /* mech_new */
+#if defined _SUN_SDK_ && defined GSSAPI_PROTECT
+ &_gssapi_client_mech_step, /* mech_step */
+#else
+ &gssapi_client_mech_step, /* mech_step */
+#endif /* _SUN_SDK_ && GSSAPI_PROTECT */
+ &gssapi_common_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare */
+ NULL /* spare */
+ }
+};
+
+int gssapiv2_client_plug_init(const sasl_utils_t *utils __attribute__((unused)),
+ int maxversion,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_CLIENT_PLUG_VERSION) {
+ SETERROR(utils, "Version mismatch in GSSAPI");
+ return SASL_BADVERS;
+ }
+
+ /* EXPORT DELETE START */
+ /* CRYPT DELETE START */
+#ifdef _INTEGRATED_SOLARIS_
+ /*
+ * Let libsasl know that we are a "Sun" plugin so that privacy
+ * and integrity will be allowed.
+ */
+ REG_PLUG("GSSAPI", gssapi_client_plugins);
+#endif /* _INTEGRATED_SOLARIS_ */
+ /* CRYPT DELETE END */
+ /* EXPORT DELETE END */
+
+ *out_version = SASL_CLIENT_PLUG_VERSION;
+ *pluglist = gssapi_client_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
diff --git a/usr/src/lib/sasl_plugins/gssapi/gssapiv2_init.c b/usr/src/lib/sasl_plugins/gssapi/gssapiv2_init.c
new file mode 100644
index 0000000000..13d92bf75f
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/gssapiv2_init.c
@@ -0,0 +1,44 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef macintosh
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <assert.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslutil.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#include <sasl_gssapiv2_plugin_decl.h>
+#endif
+
+#ifdef WIN32
+BOOL APIENTRY DllMain( HANDLE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+#endif
+
+SASL_CLIENT_PLUG_INIT( gssapiv2 )
+SASL_SERVER_PLUG_INIT( gssapiv2 )
+
diff --git a/usr/src/lib/sasl_plugins/gssapi/i386/Makefile b/usr/src/lib/sasl_plugins/gssapi/i386/Makefile
new file mode 100644
index 0000000000..ae4329fa74
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/i386/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/gssapi/i386/Makefile
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS)
diff --git a/usr/src/lib/sasl_plugins/gssapi/sparc/Makefile b/usr/src/lib/sasl_plugins/gssapi/sparc/Makefile
new file mode 100644
index 0000000000..7f4953f857
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/sparc/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/gssapi/sparc/Makefile
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS)
diff --git a/usr/src/lib/sasl_plugins/gssapi/sparcv9/Makefile b/usr/src/lib/sasl_plugins/gssapi/sparcv9/Makefile
new file mode 100644
index 0000000000..0188c0d9eb
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/sparcv9/Makefile
@@ -0,0 +1,12 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/gssapi/sparcv9/Makefile
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+install: all $(ROOTLIBS64)
diff --git a/usr/src/lib/sasl_plugins/gssapi/spec/Makefile b/usr/src/lib/sasl_plugins/gssapi/spec/Makefile
new file mode 100644
index 0000000000..78e5a082a2
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/spec/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+include $(SRC)/lib/Makefile.spec.arch
diff --git a/usr/src/lib/sasl_plugins/gssapi/spec/Makefile.targ b/usr/src/lib/sasl_plugins/gssapi/spec/Makefile.targ
new file mode 100644
index 0000000000..0093ca71ad
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/spec/Makefile.targ
@@ -0,0 +1,10 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+LIBRARY = gssapi.a
+VERS = .1
+
+OBJECTS = gssapi.o
diff --git a/usr/src/lib/sasl_plugins/gssapi/spec/amd64/Makefile b/usr/src/lib/sasl_plugins/gssapi/spec/amd64/Makefile
new file mode 100644
index 0000000000..07e64367c4
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/spec/amd64/Makefile
@@ -0,0 +1,14 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/gssapi/spec/gssapi.spec b/usr/src/lib/sasl_plugins/gssapi/spec/gssapi.spec
new file mode 100644
index 0000000000..937b4fcf47
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/spec/gssapi.spec
@@ -0,0 +1,28 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugin/gssapi/spec/gssapi.spec
+#
+
+function sasl_client_plug_init
+include <sasl/saslplug.h>
+declaration int sasl_client_plug_init(const sasl_utils_t *utils, \
+ int maxversion, int *out_version, \
+ sasl_client_plug_t **pluglist, \
+ int *plugcount)
+exception $return == SASL_FAIL
+version SUNWprivate_1.1
+end
+
+function sasl_server_plug_init
+include <sasl/saslplug.h>
+declaration int sasl_server_plug_init(const sasl_utils_t *utils, \
+ int maxversion, int *out_version, \
+ sasl_server_plug_t **pluglist, \
+ int *plugcount)
+exception $return == SASL_FAIL
+version SUNWprivate_1.1
+end
diff --git a/usr/src/lib/sasl_plugins/gssapi/spec/i386/Makefile b/usr/src/lib/sasl_plugins/gssapi/spec/i386/Makefile
new file mode 100644
index 0000000000..5d849b6467
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/spec/i386/Makefile
@@ -0,0 +1,15 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/gssapi/spec/i386/Makefile
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/gssapi/spec/sparc/Makefile b/usr/src/lib/sasl_plugins/gssapi/spec/sparc/Makefile
new file mode 100644
index 0000000000..0c9b8fa717
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/spec/sparc/Makefile
@@ -0,0 +1,15 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/gssapi/spec/sparc/Makefile
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/gssapi/spec/sparcv9/Makefile b/usr/src/lib/sasl_plugins/gssapi/spec/sparcv9/Makefile
new file mode 100644
index 0000000000..a7b2bf8e22
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/spec/sparcv9/Makefile
@@ -0,0 +1,16 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/gssapi/spec/sparcv9/Makefile
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/gssapi/spec/versions b/usr/src/lib/sasl_plugins/gssapi/spec/versions
new file mode 100644
index 0000000000..6a318d48a3
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/gssapi/spec/versions
@@ -0,0 +1,19 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+sparc {
+ SUNWprivate_1.1;
+}
+sparcv9 {
+ SUNWprivate_1.1;
+}
+i386 {
+ SUNWprivate_1.1;
+}
+amd64 {
+ SUNWprivate_1.1;
+}
diff --git a/usr/src/lib/sasl_plugins/plain/Makefile b/usr/src/lib/sasl_plugins/plain/Makefile
new file mode 100644
index 0000000000..4897cf88f3
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+include ../Makefile.subdirs
diff --git a/usr/src/lib/sasl_plugins/plain/Makefile.com b/usr/src/lib/sasl_plugins/plain/Makefile.com
new file mode 100644
index 0000000000..bd9358037c
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/Makefile.com
@@ -0,0 +1,13 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+LIBRARY= plain.a
+VERS= .1
+
+PLUG_OBJS= plain.o plain_init.o
+
+# include common definitions
+include ../../Makefile.com
diff --git a/usr/src/lib/sasl_plugins/plain/amd64/Makefile b/usr/src/lib/sasl_plugins/plain/amd64/Makefile
new file mode 100644
index 0000000000..13ae0db12d
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/amd64/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64)
diff --git a/usr/src/lib/sasl_plugins/plain/i386/Makefile b/usr/src/lib/sasl_plugins/plain/i386/Makefile
new file mode 100644
index 0000000000..661fac32f9
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/i386/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/plain/i386/Makefile
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS)
diff --git a/usr/src/lib/sasl_plugins/plain/plain.c b/usr/src/lib/sasl_plugins/plain/plain.c
new file mode 100644
index 0000000000..97194dee5b
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/plain.c
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* Plain SASL plugin
+ * Rob Siemborski
+ * Tim Martin
+ * $Id: plain.c,v 1.61 2003/03/26 17:18:04 rjs3 Exp $
+ */
+
+/*
+ * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Office of Technology Transfer
+ * Carnegie Mellon University
+ * 5000 Forbes Avenue
+ * Pittsburgh, PA 15213-3890
+ * (412) 268-4387, fax: (412) 268-7395
+ * tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <sasl.h>
+#include <saslplug.h>
+
+#include "plugin_common.h"
+
+#ifndef _SUN_SDK_
+#ifdef WIN32
+/* This must be after sasl.h */
+# include "saslPLAIN.h"
+#endif /* WIN32 */
+#endif /* !_SUN_SDK_ */
+
+#ifdef macintosh
+#include <sasl_plain_plugin_decl.h>
+#endif
+
+/***************************** Common Section *****************************/
+
+#ifndef _SUN_SDK_
+static const char plugin_id[] = "$Id: plain.c,v 1.61 2003/03/26 17:18:04 rjs3 Exp $";
+#endif /* !_SUN_SDK_ */
+
+/***************************** Server Section *****************************/
+
+static int plain_server_mech_new(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ const char *challenge __attribute__((unused)),
+ unsigned challen __attribute__((unused)),
+ void **conn_context)
+{
+ /* holds state are in */
+ if (!conn_context) {
+ PARAMERROR( sparams->utils );
+ return SASL_BADPARAM;
+ }
+
+ *conn_context = NULL;
+
+ return SASL_OK;
+}
+
+static int plain_server_mech_step(void *conn_context __attribute__((unused)),
+ sasl_server_params_t *params,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ const char *author;
+ const char *authen;
+ const char *password;
+ size_t password_len;
+ unsigned lup=0;
+ int result;
+ char *passcopy;
+
+ *serverout = NULL;
+ *serveroutlen = 0;
+
+ /* should have received author-id NUL authen-id NUL password */
+
+ /* get author */
+ author = clientin;
+ while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
+
+ if (lup >= clientinlen) {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "Can only find author (no password)");
+#else
+ SETERROR(params->utils, "Can only find author (no password)");
+#endif /* _SUN_SDK_ */
+ return SASL_BADPROT;
+ }
+
+ /* get authen */
+ ++lup;
+ authen = clientin + lup;
+ while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
+
+ if (lup >= clientinlen) {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "Can only find author/en (no password)");
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "Can only find author/en (no password)");
+#endif /* _SUN_SDK_ */
+ return SASL_BADPROT;
+ }
+
+ /* get password */
+ lup++;
+ password = clientin + lup;
+ while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
+
+ password_len = clientin + lup - password;
+
+ if (lup != clientinlen) {
+#ifdef _SUN_SDK_
+ params->utils->log(params->utils->conn, SASL_LOG_ERR,
+ "Got more data than we were expecting in the PLAIN plugin");
+#else
+ SETERROR(params->utils,
+ "Got more data than we were expecting in the PLAIN plugin\n");
+#endif /* _SUN_SDK_ */
+ return SASL_BADPROT;
+ }
+
+ /* this kinda sucks. we need password to be null terminated
+ but we can't assume there is an allocated byte at the end
+ of password so we have to copy it */
+ passcopy = params->utils->malloc(password_len + 1);
+ if (passcopy == NULL) {
+ MEMERROR(params->utils);
+ return SASL_NOMEM;
+ }
+
+ strncpy(passcopy, password, password_len);
+ passcopy[password_len] = '\0';
+
+ /* Canonicalize userid first, so that password verification is only
+ * against the canonical id */
+ if (!author || !*author)
+ author = authen;
+
+ result = params->canon_user(params->utils->conn,
+ authen, 0, SASL_CU_AUTHID, oparams);
+ if (result != SASL_OK) {
+ _plug_free_string(params->utils, &passcopy);
+ return result;
+ }
+
+ /* verify password - return sasl_ok on success*/
+ result = params->utils->checkpass(params->utils->conn,
+ oparams->authid, oparams->alen,
+ passcopy, password_len);
+
+ _plug_free_string(params->utils, &passcopy);
+
+ if (result != SASL_OK) {
+#ifdef _INTEGRATED_SOLARIS_
+ params->utils->seterror(params->utils->conn, 0,
+ gettext("Password verification failed"));
+#else
+ params->utils->seterror(params->utils->conn, 0,
+ "Password verification failed");
+#endif /* _INTEGRATED_SOLARIS_ */
+ return result;
+ }
+
+ /* Canonicalize and store the authorization ID */
+ /* We need to do this after calling verify_user just in case verify_user
+ * needed to get auxprops itself */
+ result = params->canon_user(params->utils->conn,
+ author, 0, SASL_CU_AUTHZID, oparams);
+ if (result != SASL_OK) return result;
+
+ /* Transition? */
+ if (params->transition) {
+ params->transition(params->utils->conn, password, password_len);
+ }
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ return SASL_OK;
+}
+
+static sasl_server_plug_t plain_server_plugins[] =
+{
+ {
+ "PLAIN", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOANONYMOUS, /* security_flags */
+ SASL_FEAT_WANT_CLIENT_FIRST
+ | SASL_FEAT_ALLOWS_PROXY, /* features */
+ NULL, /* glob_context */
+ &plain_server_mech_new, /* mech_new */
+ &plain_server_mech_step, /* mech_step */
+ NULL, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ NULL, /* mech_avail */
+ NULL /* spare */
+ }
+};
+
+int plain_server_plug_init(const sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_SERVER_PLUG_VERSION) {
+ SETERROR(utils, "PLAIN version mismatch");
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_SERVER_PLUG_VERSION;
+ *pluglist = plain_server_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
+
+/***************************** Client Section *****************************/
+
+typedef struct client_context {
+ char *out_buf;
+ unsigned out_buf_len;
+#ifdef _INTEGRATED_SOLARIS_
+ void *h;
+#endif /* _INTEGRATED_SOLARIS_ */
+} client_context_t;
+
+static int plain_client_mech_new(void *glob_context __attribute__((unused)),
+ sasl_client_params_t *params,
+ void **conn_context)
+{
+ client_context_t *text;
+
+ /* holds state are in */
+ text = params->utils->malloc(sizeof(client_context_t));
+ if (text == NULL) {
+ MEMERROR( params->utils );
+ return SASL_NOMEM;
+ }
+
+ memset(text, 0, sizeof(client_context_t));
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+static int plain_client_mech_step(void *conn_context,
+ sasl_client_params_t *params,
+ const char *serverin __attribute__((unused)),
+ unsigned serverinlen __attribute__((unused)),
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ client_context_t *text = (client_context_t *) conn_context;
+ const char *user = NULL, *authid = NULL;
+ sasl_secret_t *password = NULL;
+ unsigned int free_password = 0; /* set if we need to free password */
+ int user_result = SASL_OK;
+ int auth_result = SASL_OK;
+ int pass_result = SASL_OK;
+ int result;
+
+ *clientout = NULL;
+ *clientoutlen = 0;
+
+ /* doesn't really matter how the server responds */
+
+ /* check if sec layer strong enough */
+ if (params->props.min_ssf > params->external_ssf) {
+#ifdef _INTEGRATED_SOLARIS_
+ SETERROR( params->utils, gettext("SSF requested of PLAIN plugin"));
+#else
+ SETERROR( params->utils, "SSF requested of PLAIN plugin");
+#endif /* _INTEGRATED_SOLARIS_ */
+ return SASL_TOOWEAK;
+ }
+
+ /* try to get the authid */
+ if (oparams->authid == NULL) {
+ auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
+
+ if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT))
+ return auth_result;
+ }
+
+ /* try to get the userid */
+ if (oparams->user == NULL) {
+ user_result = _plug_get_userid(params->utils, &user, prompt_need);
+
+ if ((user_result != SASL_OK) && (user_result != SASL_INTERACT))
+ return user_result;
+ }
+
+ /* try to get the password */
+ if (password == NULL) {
+ pass_result = _plug_get_password(params->utils, &password,
+ &free_password, prompt_need);
+
+ if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT))
+ return pass_result;
+ }
+
+ /* free prompts we got */
+ if (prompt_need && *prompt_need) {
+ params->utils->free(*prompt_need);
+ *prompt_need = NULL;
+ }
+
+ /* if there are prompts not filled in */
+ if ((user_result == SASL_INTERACT) || (auth_result == SASL_INTERACT) ||
+ (pass_result == SASL_INTERACT)) {
+ /* make the prompt list */
+ result =
+#ifdef _INTEGRATED_SOLARIS_
+ _plug_make_prompts(params->utils, &text->h, prompt_need,
+ user_result == SASL_INTERACT ?
+ convert_prompt(params->utils, &text->h,
+ gettext("Please enter your authorization name"))
+ : NULL,
+ NULL,
+ auth_result == SASL_INTERACT ?
+ convert_prompt(params->utils, &text->h,
+ gettext("Please enter your authentication name"))
+ : NULL,
+ NULL,
+ pass_result == SASL_INTERACT ?
+ convert_prompt(params->utils, &text->h,
+ gettext("Please enter your password")) : NULL,
+ NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+#else
+ _plug_make_prompts(params->utils, prompt_need,
+ user_result == SASL_INTERACT ?
+ "Please enter your authorization name" : NULL,
+ NULL,
+ auth_result == SASL_INTERACT ?
+ "Please enter your authentication name" : NULL,
+ NULL,
+ pass_result == SASL_INTERACT ?
+ "Please enter your password" : NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+#endif /* _INTEGRATED_SOLARIS_ */
+ if (result != SASL_OK) goto cleanup;
+
+ return SASL_INTERACT;
+ }
+
+ if (!password) {
+ PARAMERROR(params->utils);
+ return SASL_BADPARAM;
+ }
+
+ if (!user || !*user) {
+ result = params->canon_user(params->utils->conn, authid, 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
+ }
+ else {
+ result = params->canon_user(params->utils->conn, user, 0,
+ SASL_CU_AUTHZID, oparams);
+ if (result != SASL_OK) goto cleanup;
+
+ result = params->canon_user(params->utils->conn, authid, 0,
+ SASL_CU_AUTHID, oparams);
+ }
+ if (result != SASL_OK) goto cleanup;
+
+ /* send authorized id NUL authentication id NUL password */
+ *clientoutlen = (oparams->ulen + 1
+ + oparams->alen + 1
+ + password->len);
+
+ /* remember the extra NUL on the end for stupid clients */
+ result = _plug_buf_alloc(params->utils, &(text->out_buf),
+ &(text->out_buf_len), *clientoutlen + 1);
+ if (result != SASL_OK) goto cleanup;
+
+ memset(text->out_buf, 0, *clientoutlen + 1);
+ memcpy(text->out_buf, oparams->user, oparams->ulen);
+ memcpy(text->out_buf + oparams->ulen + 1, oparams->authid, oparams->alen);
+ memcpy(text->out_buf + oparams->ulen + oparams->alen + 2,
+ password->data, password->len);
+
+ *clientout = text->out_buf;
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ result = SASL_OK;
+
+ cleanup:
+ /* free sensitive info */
+ if (free_password) _plug_free_secret(params->utils, &password);
+
+ return result;
+}
+
+static void plain_client_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ client_context_t *text = (client_context_t *) conn_context;
+
+ if (!text) return;
+
+ if (text->out_buf) utils->free(text->out_buf);
+#ifdef _INTEGRATED_SOLARIS_
+ convert_prompt(utils, &text->h, NULL);
+#endif /* _INTEGRATED_SOLARIS_ */
+
+ utils->free(text);
+}
+
+static sasl_client_plug_t plain_client_plugins[] =
+{
+ {
+ "PLAIN", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOANONYMOUS, /* security_flags */
+ SASL_FEAT_WANT_CLIENT_FIRST
+ | SASL_FEAT_ALLOWS_PROXY, /* features */
+ NULL, /* required_prompts */
+ NULL, /* glob_context */
+ &plain_client_mech_new, /* mech_new */
+ &plain_client_mech_step, /* mech_step */
+ &plain_client_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare */
+ NULL /* spare */
+ }
+};
+
+int plain_client_plug_init(sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_CLIENT_PLUG_VERSION) {
+ SETERROR(utils, "PLAIN version mismatch");
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_CLIENT_PLUG_VERSION;
+ *pluglist = plain_client_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
diff --git a/usr/src/lib/sasl_plugins/plain/plain_init.c b/usr/src/lib/sasl_plugins/plain/plain_init.c
new file mode 100644
index 0000000000..90c931f6e9
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/plain_init.c
@@ -0,0 +1,44 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef macintosh
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <assert.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslutil.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#include <sasl_plain_plugin_decl.h>
+#endif
+
+#ifdef WIN32
+BOOL APIENTRY DllMain( HANDLE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+#endif
+
+SASL_CLIENT_PLUG_INIT( plain )
+SASL_SERVER_PLUG_INIT( plain )
+
diff --git a/usr/src/lib/sasl_plugins/plain/sparc/Makefile b/usr/src/lib/sasl_plugins/plain/sparc/Makefile
new file mode 100644
index 0000000000..32efb790e3
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/sparc/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/login/sparc/Makefile
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS)
diff --git a/usr/src/lib/sasl_plugins/plain/sparcv9/Makefile b/usr/src/lib/sasl_plugins/plain/sparcv9/Makefile
new file mode 100644
index 0000000000..31beb8be62
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/sparcv9/Makefile
@@ -0,0 +1,12 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/login/sparcv9/Makefile
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+install: all $(ROOTLIBS64)
diff --git a/usr/src/lib/sasl_plugins/plain/spec/Makefile b/usr/src/lib/sasl_plugins/plain/spec/Makefile
new file mode 100644
index 0000000000..78e5a082a2
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/spec/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+include $(SRC)/lib/Makefile.spec.arch
diff --git a/usr/src/lib/sasl_plugins/plain/spec/Makefile.targ b/usr/src/lib/sasl_plugins/plain/spec/Makefile.targ
new file mode 100644
index 0000000000..340888b209
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/spec/Makefile.targ
@@ -0,0 +1,10 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+LIBRARY = plain.a
+VERS = .1
+
+OBJECTS = plain.o
diff --git a/usr/src/lib/sasl_plugins/plain/spec/amd64/Makefile b/usr/src/lib/sasl_plugins/plain/spec/amd64/Makefile
new file mode 100644
index 0000000000..07e64367c4
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/spec/amd64/Makefile
@@ -0,0 +1,14 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/plain/spec/i386/Makefile b/usr/src/lib/sasl_plugins/plain/spec/i386/Makefile
new file mode 100644
index 0000000000..b15851e8d3
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/spec/i386/Makefile
@@ -0,0 +1,15 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/plain/spec/i386/Makefile
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/plain/spec/plain.spec b/usr/src/lib/sasl_plugins/plain/spec/plain.spec
new file mode 100644
index 0000000000..8f6fc71926
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/spec/plain.spec
@@ -0,0 +1,28 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugin/login/spec/login.spec
+#
+
+function sasl_client_plug_init
+include <sasl/saslplug.h>
+declaration int sasl_client_plug_init(const sasl_utils_t *utils, \
+ int maxversion, int *out_version, \
+ sasl_client_plug_t **pluglist, \
+ int *plugcount)
+exception $return == SASL_FAIL
+version SUNWprivate_1.1
+end
+
+function sasl_server_plug_init
+include <sasl/saslplug.h>
+declaration int sasl_server_plug_init(const sasl_utils_t *utils, \
+ int maxversion, int *out_version, \
+ sasl_server_plug_t **pluglist, \
+ int *plugcount)
+exception $return == SASL_FAIL
+version SUNWprivate_1.1
+end
diff --git a/usr/src/lib/sasl_plugins/plain/spec/sparc/Makefile b/usr/src/lib/sasl_plugins/plain/spec/sparc/Makefile
new file mode 100644
index 0000000000..8fdc1965c6
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/spec/sparc/Makefile
@@ -0,0 +1,15 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/plain/spec/sparc/Makefile
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/plain/spec/sparcv9/Makefile b/usr/src/lib/sasl_plugins/plain/spec/sparcv9/Makefile
new file mode 100644
index 0000000000..b000497abc
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/spec/sparcv9/Makefile
@@ -0,0 +1,16 @@
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libsasl/plugins/plain/spec/sparcv9/Makefile
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+include $(SRC)/lib/Makefile.spec
diff --git a/usr/src/lib/sasl_plugins/plain/spec/versions b/usr/src/lib/sasl_plugins/plain/spec/versions
new file mode 100644
index 0000000000..6a318d48a3
--- /dev/null
+++ b/usr/src/lib/sasl_plugins/plain/spec/versions
@@ -0,0 +1,19 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+sparc {
+ SUNWprivate_1.1;
+}
+sparcv9 {
+ SUNWprivate_1.1;
+}
+i386 {
+ SUNWprivate_1.1;
+}
+amd64 {
+ SUNWprivate_1.1;
+}