xref: /illumos-gate/usr/src/lib/sasl_plugins/digestmd5/digestmd5.c (revision 7a7d534ff7d637c8673694e0ec835c590a6697e5)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
448bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
57c478bd9Sstevel@tonic-gate  */
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate /* DIGEST-MD5 SASL plugin
87c478bd9Sstevel@tonic-gate  * Rob Siemborski
97c478bd9Sstevel@tonic-gate  * Tim Martin
107c478bd9Sstevel@tonic-gate  * Alexey Melnikov
117c478bd9Sstevel@tonic-gate  * $Id: digestmd5.c,v 1.153 2003/03/30 22:17:06 leg Exp $
127c478bd9Sstevel@tonic-gate  */
137c478bd9Sstevel@tonic-gate /*
147c478bd9Sstevel@tonic-gate  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
157c478bd9Sstevel@tonic-gate  *
167c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
177c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
187c478bd9Sstevel@tonic-gate  * are met:
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
217c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
227c478bd9Sstevel@tonic-gate  *
237c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
247c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in
257c478bd9Sstevel@tonic-gate  *    the documentation and/or other materials provided with the
267c478bd9Sstevel@tonic-gate  *    distribution.
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  * 3. The name "Carnegie Mellon University" must not be used to
297c478bd9Sstevel@tonic-gate  *    endorse or promote products derived from this software without
307c478bd9Sstevel@tonic-gate  *    prior written permission. For permission or any other legal
317c478bd9Sstevel@tonic-gate  *    details, please contact
327c478bd9Sstevel@tonic-gate  *      Office of Technology Transfer
337c478bd9Sstevel@tonic-gate  *      Carnegie Mellon University
347c478bd9Sstevel@tonic-gate  *      5000 Forbes Avenue
357c478bd9Sstevel@tonic-gate  *      Pittsburgh, PA  15213-3890
367c478bd9Sstevel@tonic-gate  *      (412) 268-4387, fax: (412) 268-7395
377c478bd9Sstevel@tonic-gate  *      tech-transfer@andrew.cmu.edu
387c478bd9Sstevel@tonic-gate  *
397c478bd9Sstevel@tonic-gate  * 4. Redistributions of any form whatsoever must retain the following
407c478bd9Sstevel@tonic-gate  *    acknowledgment:
417c478bd9Sstevel@tonic-gate  *    "This product includes software developed by Computing Services
427c478bd9Sstevel@tonic-gate  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
437c478bd9Sstevel@tonic-gate  *
447c478bd9Sstevel@tonic-gate  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
457c478bd9Sstevel@tonic-gate  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
467c478bd9Sstevel@tonic-gate  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
477c478bd9Sstevel@tonic-gate  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
487c478bd9Sstevel@tonic-gate  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
497c478bd9Sstevel@tonic-gate  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
507c478bd9Sstevel@tonic-gate  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
517c478bd9Sstevel@tonic-gate  */
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #include <config.h>
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #include <stdlib.h>
567c478bd9Sstevel@tonic-gate #include <stdio.h>
577c478bd9Sstevel@tonic-gate #include <string.h>
587c478bd9Sstevel@tonic-gate #ifndef macintosh
597c478bd9Sstevel@tonic-gate #include <sys/types.h>
607c478bd9Sstevel@tonic-gate #include <sys/stat.h>
617c478bd9Sstevel@tonic-gate #endif
627c478bd9Sstevel@tonic-gate #include <fcntl.h>
637c478bd9Sstevel@tonic-gate #include <ctype.h>
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate /* DES support */
667c478bd9Sstevel@tonic-gate #ifdef WITH_DES
677c478bd9Sstevel@tonic-gate # ifdef WITH_SSL_DES
687c478bd9Sstevel@tonic-gate #  include <openssl/des.h>
697c478bd9Sstevel@tonic-gate # else /* system DES library */
707c478bd9Sstevel@tonic-gate #  include <des.h>
717c478bd9Sstevel@tonic-gate # endif
727c478bd9Sstevel@tonic-gate #endif /* WITH_DES */
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate #ifdef WIN32
757c478bd9Sstevel@tonic-gate # include <winsock.h>
767c478bd9Sstevel@tonic-gate #else /* Unix */
777c478bd9Sstevel@tonic-gate # include <netinet/in.h>
787c478bd9Sstevel@tonic-gate #endif /* WIN32 */
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
817c478bd9Sstevel@tonic-gate #include <unistd.h>
827c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate #include <sasl.h>
857c478bd9Sstevel@tonic-gate #include <saslplug.h>
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate #include "plugin_common.h"
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate #if defined _SUN_SDK_  && defined USE_UEF
907c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
917c478bd9Sstevel@tonic-gate static int uef_init(const sasl_utils_t *utils);
927c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ && USE_UEF */
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate #ifndef WIN32
957c478bd9Sstevel@tonic-gate extern int strcasecmp(const char *s1, const char *s2);
967c478bd9Sstevel@tonic-gate #endif /* end WIN32 */
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate #ifdef macintosh
997c478bd9Sstevel@tonic-gate #include <sasl_md5_plugin_decl.h>
1007c478bd9Sstevel@tonic-gate #endif
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /* external definitions */
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
1057c478bd9Sstevel@tonic-gate #ifdef sun
1067c478bd9Sstevel@tonic-gate /* gotta define gethostname ourselves on suns */
1077c478bd9Sstevel@tonic-gate extern int      gethostname(char *, int);
1087c478bd9Sstevel@tonic-gate #endif
1097c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate #define bool int
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate #ifndef TRUE
1147c478bd9Sstevel@tonic-gate #define TRUE  (1)
1157c478bd9Sstevel@tonic-gate #define FALSE (0)
1167c478bd9Sstevel@tonic-gate #endif
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate #define DEFAULT_BUFSIZE 0xFFFF
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate /*****************************  Common Section  *****************************/
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
1237c478bd9Sstevel@tonic-gate static const char plugin_id[] = "$Id: digestmd5.c,v 1.153 2003/03/30 22:17:06 leg Exp $";
1247c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate /* Definitions */
1277c478bd9Sstevel@tonic-gate #define NONCE_SIZE (32)		/* arbitrary */
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate /* Layer Flags */
1307c478bd9Sstevel@tonic-gate #define DIGEST_NOLAYER    (1)
1317c478bd9Sstevel@tonic-gate #define DIGEST_INTEGRITY  (2)
1327c478bd9Sstevel@tonic-gate #define DIGEST_PRIVACY    (4)
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate /* defines */
1357c478bd9Sstevel@tonic-gate #define HASHLEN 16
1367c478bd9Sstevel@tonic-gate typedef unsigned char HASH[HASHLEN + 1];
1377c478bd9Sstevel@tonic-gate #define HASHHEXLEN 32
1387c478bd9Sstevel@tonic-gate typedef unsigned char HASHHEX[HASHHEXLEN + 1];
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate #define MAC_SIZE 10
1417c478bd9Sstevel@tonic-gate #define MAC_OFFS 2
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate const char *SEALING_CLIENT_SERVER="Digest H(A1) to client-to-server sealing key magic constant";
1447c478bd9Sstevel@tonic-gate const char *SEALING_SERVER_CLIENT="Digest H(A1) to server-to-client sealing key magic constant";
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate const char *SIGNING_CLIENT_SERVER="Digest session key to client-to-server signing key magic constant";
1477c478bd9Sstevel@tonic-gate const char *SIGNING_SERVER_CLIENT="Digest session key to server-to-client signing key magic constant";
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate #define HT	(9)
1507c478bd9Sstevel@tonic-gate #define CR	(13)
1517c478bd9Sstevel@tonic-gate #define LF	(10)
1527c478bd9Sstevel@tonic-gate #define SP	(32)
1537c478bd9Sstevel@tonic-gate #define DEL	(127)
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate struct context;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate /* function definitions for cipher encode/decode */
1587c478bd9Sstevel@tonic-gate typedef int cipher_function_t(struct context *,
1597c478bd9Sstevel@tonic-gate 			      const char *,
1607c478bd9Sstevel@tonic-gate 			      unsigned,
1617c478bd9Sstevel@tonic-gate 			      unsigned char[],
1627c478bd9Sstevel@tonic-gate 			      char *,
1637c478bd9Sstevel@tonic-gate 			      unsigned *);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
1667c478bd9Sstevel@tonic-gate typedef int cipher_init_t(struct context *, char [16],
1677c478bd9Sstevel@tonic-gate                                             char [16]);
1687c478bd9Sstevel@tonic-gate #else
1697c478bd9Sstevel@tonic-gate typedef int cipher_init_t(struct context *, unsigned char [16],
1707c478bd9Sstevel@tonic-gate                                             unsigned char [16]);
1717c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate typedef void cipher_free_t(struct context *);
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate enum Context_type { SERVER = 0, CLIENT = 1 };
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate typedef struct cipher_context cipher_context_t;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate /* cached auth info used for fast reauth */
1807c478bd9Sstevel@tonic-gate typedef struct reauth_entry {
1817c478bd9Sstevel@tonic-gate     char *authid;
1827c478bd9Sstevel@tonic-gate     char *realm;
1837c478bd9Sstevel@tonic-gate     unsigned char *nonce;
1847c478bd9Sstevel@tonic-gate     unsigned int nonce_count;
1857c478bd9Sstevel@tonic-gate     unsigned char *cnonce;
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate     union {
1887c478bd9Sstevel@tonic-gate 	struct {
1897c478bd9Sstevel@tonic-gate 	    time_t timestamp;
1907c478bd9Sstevel@tonic-gate 	} s; /* server stuff */
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	struct {
1937c478bd9Sstevel@tonic-gate 	    char *serverFQDN;
1947c478bd9Sstevel@tonic-gate 	    int protection;
1957c478bd9Sstevel@tonic-gate 	    struct digest_cipher *cipher;
1967c478bd9Sstevel@tonic-gate 	    unsigned int server_maxbuf;
1977c478bd9Sstevel@tonic-gate 	} c; /* client stuff */
1987c478bd9Sstevel@tonic-gate     } u;
1997c478bd9Sstevel@tonic-gate } reauth_entry_t;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate typedef struct reauth_cache {
2027c478bd9Sstevel@tonic-gate     /* static stuff */
2037c478bd9Sstevel@tonic-gate     enum Context_type i_am;	/* are we the client or server? */
2047c478bd9Sstevel@tonic-gate     time_t timeout;
2057c478bd9Sstevel@tonic-gate     void *mutex;
2067c478bd9Sstevel@tonic-gate     size_t size;
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate     reauth_entry_t *e;		/* fixed-size hash table of entries */
2097c478bd9Sstevel@tonic-gate } reauth_cache_t;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate /* context that stores info */
2127c478bd9Sstevel@tonic-gate typedef struct context {
2137c478bd9Sstevel@tonic-gate     int state;			/* state in the authentication we are in */
2147c478bd9Sstevel@tonic-gate     enum Context_type i_am;	/* are we the client or server? */
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate     reauth_cache_t *reauth;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate     char *authid;
2197c478bd9Sstevel@tonic-gate     char *realm;
2207c478bd9Sstevel@tonic-gate     unsigned char *nonce;
2217c478bd9Sstevel@tonic-gate     unsigned int nonce_count;
2227c478bd9Sstevel@tonic-gate     unsigned char *cnonce;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate     char *response_value;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate     unsigned int seqnum;
2277c478bd9Sstevel@tonic-gate     unsigned int rec_seqnum;	/* for checking integrity */
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate     HASH Ki_send;
2307c478bd9Sstevel@tonic-gate     HASH Ki_receive;
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate     HASH HA1;		/* Kcc or Kcs */
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate     /* copy of utils from the params structures */
2357c478bd9Sstevel@tonic-gate     const sasl_utils_t *utils;
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate     /* For general use */
2387c478bd9Sstevel@tonic-gate     char *out_buf;
2397c478bd9Sstevel@tonic-gate     unsigned out_buf_len;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate     /* for encoding/decoding */
2427c478bd9Sstevel@tonic-gate     buffer_info_t *enc_in_buf;
2437c478bd9Sstevel@tonic-gate     char *encode_buf, *decode_buf, *decode_once_buf;
2447c478bd9Sstevel@tonic-gate     unsigned encode_buf_len, decode_buf_len, decode_once_buf_len;
2457c478bd9Sstevel@tonic-gate     char *decode_tmp_buf;
2467c478bd9Sstevel@tonic-gate     unsigned decode_tmp_buf_len;
2477c478bd9Sstevel@tonic-gate     char *MAC_buf;
2487c478bd9Sstevel@tonic-gate     unsigned MAC_buf_len;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate     char *buffer;
2517c478bd9Sstevel@tonic-gate     char sizebuf[4];
2527c478bd9Sstevel@tonic-gate     int cursize;
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate     /* Layer info */
2557c478bd9Sstevel@tonic-gate     unsigned int size; /* Absolute size of buffer */
2567c478bd9Sstevel@tonic-gate     unsigned int needsize; /* How much of the size of the buffer is left */
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate     /* Server MaxBuf for Client or Client MaxBuf For Server */
2597c478bd9Sstevel@tonic-gate     /* INCOMING */
2607c478bd9Sstevel@tonic-gate     unsigned int in_maxbuf;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate     /* if privacy mode is used use these functions for encode and decode */
2637c478bd9Sstevel@tonic-gate     cipher_function_t *cipher_enc;
2647c478bd9Sstevel@tonic-gate     cipher_function_t *cipher_dec;
2657c478bd9Sstevel@tonic-gate     cipher_init_t *cipher_init;
2667c478bd9Sstevel@tonic-gate     cipher_free_t *cipher_free;
2677c478bd9Sstevel@tonic-gate     struct cipher_context *cipher_enc_context;
2687c478bd9Sstevel@tonic-gate     struct cipher_context *cipher_dec_context;
2697c478bd9Sstevel@tonic-gate } context_t;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate struct digest_cipher {
2727c478bd9Sstevel@tonic-gate     char *name;
2737c478bd9Sstevel@tonic-gate     sasl_ssf_t ssf;
2747c478bd9Sstevel@tonic-gate     int n; /* bits to make privacy key */
2757c478bd9Sstevel@tonic-gate     int flag; /* a bitmask to make things easier for us */
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate     cipher_function_t *cipher_enc;
2787c478bd9Sstevel@tonic-gate     cipher_function_t *cipher_dec;
2797c478bd9Sstevel@tonic-gate     cipher_init_t *cipher_init;
2807c478bd9Sstevel@tonic-gate     cipher_free_t *cipher_free;
2817c478bd9Sstevel@tonic-gate };
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
2847c478bd9Sstevel@tonic-gate static const unsigned char *COLON = (unsigned char *)":";
2857c478bd9Sstevel@tonic-gate #else
2867c478bd9Sstevel@tonic-gate static const unsigned char *COLON = ":";
2877c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate /* Hashes a string to produce an unsigned short */
hash(const char * str)2907c478bd9Sstevel@tonic-gate static unsigned hash(const char *str)
2917c478bd9Sstevel@tonic-gate {
2927c478bd9Sstevel@tonic-gate     unsigned val = 0;
2937c478bd9Sstevel@tonic-gate     int i;
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate     while (str && *str) {
2967c478bd9Sstevel@tonic-gate 	i = (int) *str;
2977c478bd9Sstevel@tonic-gate 	val ^= i;
2987c478bd9Sstevel@tonic-gate 	val <<= 1;
2997c478bd9Sstevel@tonic-gate 	str++;
3007c478bd9Sstevel@tonic-gate     }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate     return val;
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate 
CvtHex(HASH Bin,HASHHEX Hex)3057c478bd9Sstevel@tonic-gate static void CvtHex(HASH Bin, HASHHEX Hex)
3067c478bd9Sstevel@tonic-gate {
3077c478bd9Sstevel@tonic-gate     unsigned short  i;
3087c478bd9Sstevel@tonic-gate     unsigned char   j;
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate     for (i = 0; i < HASHLEN; i++) {
3117c478bd9Sstevel@tonic-gate 	j = (Bin[i] >> 4) & 0xf;
3127c478bd9Sstevel@tonic-gate 	if (j <= 9)
3137c478bd9Sstevel@tonic-gate 	    Hex[i * 2] = (j + '0');
3147c478bd9Sstevel@tonic-gate 	else
3157c478bd9Sstevel@tonic-gate 	    Hex[i * 2] = (j + 'a' - 10);
3167c478bd9Sstevel@tonic-gate 	j = Bin[i] & 0xf;
3177c478bd9Sstevel@tonic-gate 	if (j <= 9)
3187c478bd9Sstevel@tonic-gate 	    Hex[i * 2 + 1] = (j + '0');
3197c478bd9Sstevel@tonic-gate 	else
3207c478bd9Sstevel@tonic-gate 	    Hex[i * 2 + 1] = (j + 'a' - 10);
3217c478bd9Sstevel@tonic-gate     }
3227c478bd9Sstevel@tonic-gate     Hex[HASHHEXLEN] = '\0';
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate /*
3267c478bd9Sstevel@tonic-gate  * calculate request-digest/response-digest as per HTTP Digest spec
3277c478bd9Sstevel@tonic-gate  */
3287c478bd9Sstevel@tonic-gate void
DigestCalcResponse(const sasl_utils_t * utils,HASHHEX HA1,unsigned char * pszNonce,unsigned int pszNonceCount,unsigned char * pszCNonce,unsigned char * pszQop,unsigned char * pszDigestUri,unsigned char * pszMethod,HASHHEX HEntity,HASHHEX Response)3297c478bd9Sstevel@tonic-gate DigestCalcResponse(const sasl_utils_t * utils,
3307c478bd9Sstevel@tonic-gate 		   HASHHEX HA1,	/* H(A1) */
3317c478bd9Sstevel@tonic-gate 		   unsigned char *pszNonce,	/* nonce from server */
3327c478bd9Sstevel@tonic-gate 		   unsigned int pszNonceCount,	/* 8 hex digits */
3337c478bd9Sstevel@tonic-gate 		   unsigned char *pszCNonce,	/* client nonce */
3347c478bd9Sstevel@tonic-gate 		   unsigned char *pszQop,	/* qop-value: "", "auth",
3357c478bd9Sstevel@tonic-gate 						 * "auth-int" */
3367c478bd9Sstevel@tonic-gate 		   unsigned char *pszDigestUri,	/* requested URL */
3377c478bd9Sstevel@tonic-gate 		   unsigned char *pszMethod,
3387c478bd9Sstevel@tonic-gate 		   HASHHEX HEntity,	/* H(entity body) if qop="auth-int" */
3397c478bd9Sstevel@tonic-gate 		   HASHHEX Response	/* request-digest or response-digest */
3407c478bd9Sstevel@tonic-gate     )
3417c478bd9Sstevel@tonic-gate {
3427c478bd9Sstevel@tonic-gate     MD5_CTX         Md5Ctx;
3437c478bd9Sstevel@tonic-gate     HASH            HA2;
3447c478bd9Sstevel@tonic-gate     HASH            RespHash;
3457c478bd9Sstevel@tonic-gate     HASHHEX         HA2Hex;
3467c478bd9Sstevel@tonic-gate     char ncvalue[10];
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate     /* calculate H(A2) */
3497c478bd9Sstevel@tonic-gate     utils->MD5Init(&Md5Ctx);
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate     if (pszMethod != NULL) {
3527c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, pszMethod, strlen((char *) pszMethod));
3537c478bd9Sstevel@tonic-gate     }
3547c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, (unsigned char *) COLON, 1);
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate     /* utils->MD5Update(&Md5Ctx, (unsigned char *) "AUTHENTICATE:", 13); */
3577c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, pszDigestUri, strlen((char *) pszDigestUri));
3587c478bd9Sstevel@tonic-gate     if (strcasecmp((char *) pszQop, "auth") != 0) {
3597c478bd9Sstevel@tonic-gate 	/* append ":00000000000000000000000000000000" */
3607c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, COLON, 1);
3617c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);
3627c478bd9Sstevel@tonic-gate     }
3637c478bd9Sstevel@tonic-gate     utils->MD5Final(HA2, &Md5Ctx);
3647c478bd9Sstevel@tonic-gate     CvtHex(HA2, HA2Hex);
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate     /* calculate response */
3677c478bd9Sstevel@tonic-gate     utils->MD5Init(&Md5Ctx);
3687c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
3697c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, COLON, 1);
3707c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
3717c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, COLON, 1);
3727c478bd9Sstevel@tonic-gate     if (*pszQop) {
3737c478bd9Sstevel@tonic-gate 	sprintf(ncvalue, "%08x", pszNonceCount);
3747c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
3757c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, (unsigned char *)ncvalue, strlen(ncvalue));
3767c478bd9Sstevel@tonic-gate #else
3777c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, ncvalue, strlen(ncvalue));
3787c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
3797c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, COLON, 1);
3807c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
3817c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, COLON, 1);
3827c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, pszQop, strlen((char *) pszQop));
3837c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, COLON, 1);
3847c478bd9Sstevel@tonic-gate     }
3857c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
3867c478bd9Sstevel@tonic-gate     utils->MD5Final(RespHash, &Md5Ctx);
3877c478bd9Sstevel@tonic-gate     CvtHex(RespHash, Response);
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate 
UTF8_In_8859_1(const unsigned char * base,int len)3907c478bd9Sstevel@tonic-gate static bool UTF8_In_8859_1(const unsigned char *base, int len)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate     const unsigned char *scan, *end;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate     end = base + len;
3957c478bd9Sstevel@tonic-gate     for (scan = base; scan < end; ++scan) {
3967c478bd9Sstevel@tonic-gate 	if (*scan > 0xC3)
3977c478bd9Sstevel@tonic-gate 	    break;			/* abort if outside 8859-1 */
3987c478bd9Sstevel@tonic-gate 	if (*scan >= 0xC0 && *scan <= 0xC3) {
3997c478bd9Sstevel@tonic-gate 	    if (++scan == end || *scan < 0x80 || *scan > 0xBF)
4007c478bd9Sstevel@tonic-gate 		break;
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate     }
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate     /* if scan >= end, then this is a 8859-1 string. */
4057c478bd9Sstevel@tonic-gate     return (scan >= end);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate /*
4097c478bd9Sstevel@tonic-gate  * if the string is entirely in the 8859-1 subset of UTF-8, then translate to
4107c478bd9Sstevel@tonic-gate  * 8859-1 prior to MD5
4117c478bd9Sstevel@tonic-gate  */
MD5_UTF8_8859_1(const sasl_utils_t * utils,MD5_CTX * ctx,bool In_ISO_8859_1,const unsigned char * base,int len)4127c478bd9Sstevel@tonic-gate void MD5_UTF8_8859_1(const sasl_utils_t * utils,
4137c478bd9Sstevel@tonic-gate 		     MD5_CTX * ctx,
4147c478bd9Sstevel@tonic-gate 		     bool In_ISO_8859_1,
4157c478bd9Sstevel@tonic-gate 		     const unsigned char *base,
4167c478bd9Sstevel@tonic-gate 		     int len)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate     const unsigned char *scan, *end;
4197c478bd9Sstevel@tonic-gate     unsigned char   cbuf;
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate     end = base + len;
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate     /* if we found a character outside 8859-1, don't alter string */
4247c478bd9Sstevel@tonic-gate     if (!In_ISO_8859_1) {
4257c478bd9Sstevel@tonic-gate 	utils->MD5Update(ctx, base, len);
4267c478bd9Sstevel@tonic-gate 	return;
4277c478bd9Sstevel@tonic-gate     }
4287c478bd9Sstevel@tonic-gate     /* convert to 8859-1 prior to applying hash */
4297c478bd9Sstevel@tonic-gate     do {
4307c478bd9Sstevel@tonic-gate 	for (scan = base; scan < end && *scan < 0xC0; ++scan);
4317c478bd9Sstevel@tonic-gate 	if (scan != base)
4327c478bd9Sstevel@tonic-gate 	    utils->MD5Update(ctx, base, scan - base);
4337c478bd9Sstevel@tonic-gate 	if (scan + 1 >= end)
4347c478bd9Sstevel@tonic-gate 	    break;
4357c478bd9Sstevel@tonic-gate 	cbuf = ((scan[0] & 0x3) << 6) | (scan[1] & 0x3f);
4367c478bd9Sstevel@tonic-gate 	utils->MD5Update(ctx, &cbuf, 1);
4377c478bd9Sstevel@tonic-gate 	base = scan + 2;
4387c478bd9Sstevel@tonic-gate     }
4397c478bd9Sstevel@tonic-gate     while (base < end);
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
DigestCalcSecret(const sasl_utils_t * utils,unsigned char * pszUserName,unsigned char * pszRealm,unsigned char * Password,int PasswordLen,HASH HA1)4427c478bd9Sstevel@tonic-gate static void DigestCalcSecret(const sasl_utils_t * utils,
4437c478bd9Sstevel@tonic-gate 			     unsigned char *pszUserName,
4447c478bd9Sstevel@tonic-gate 			     unsigned char *pszRealm,
4457c478bd9Sstevel@tonic-gate 			     unsigned char *Password,
4467c478bd9Sstevel@tonic-gate 			     int PasswordLen,
4477c478bd9Sstevel@tonic-gate 			     HASH HA1)
4487c478bd9Sstevel@tonic-gate {
4497c478bd9Sstevel@tonic-gate     bool            In_8859_1;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate     MD5_CTX         Md5Ctx;
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate     /* Chris Newman clarified that the following text in DIGEST-MD5 spec
4547c478bd9Sstevel@tonic-gate        is bogus: "if name and password are both in ISO 8859-1 charset"
4557c478bd9Sstevel@tonic-gate        We shoud use code example instead */
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate     utils->MD5Init(&Md5Ctx);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate     /* We have to convert UTF-8 to ISO-8859-1 if possible */
4607c478bd9Sstevel@tonic-gate     In_8859_1 = UTF8_In_8859_1(pszUserName, strlen((char *) pszUserName));
4617c478bd9Sstevel@tonic-gate     MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
4627c478bd9Sstevel@tonic-gate 		    pszUserName, strlen((char *) pszUserName));
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, COLON, 1);
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate     if (pszRealm != NULL && pszRealm[0] != '\0') {
4677c478bd9Sstevel@tonic-gate 	/* a NULL realm is equivalent to the empty string */
4687c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, pszRealm, strlen((char *) pszRealm));
4697c478bd9Sstevel@tonic-gate     }
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, COLON, 1);
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate     /* We have to convert UTF-8 to ISO-8859-1 if possible */
4747c478bd9Sstevel@tonic-gate     In_8859_1 = UTF8_In_8859_1(Password, PasswordLen);
4757c478bd9Sstevel@tonic-gate     MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
4767c478bd9Sstevel@tonic-gate 		    Password, PasswordLen);
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate     utils->MD5Final(HA1, &Md5Ctx);
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate 
create_nonce(const sasl_utils_t * utils)4817c478bd9Sstevel@tonic-gate static unsigned char *create_nonce(const sasl_utils_t * utils)
4827c478bd9Sstevel@tonic-gate {
4837c478bd9Sstevel@tonic-gate     unsigned char  *base64buf;
4847c478bd9Sstevel@tonic-gate     int             base64len;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate     char           *ret = (char *) utils->malloc(NONCE_SIZE);
4877c478bd9Sstevel@tonic-gate     if (ret == NULL)
4887c478bd9Sstevel@tonic-gate 	return NULL;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate #if defined _DEV_URANDOM && defined _SUN_SDK_
4917c478bd9Sstevel@tonic-gate     {
4927c478bd9Sstevel@tonic-gate 	int fd = open(_DEV_URANDOM, O_RDONLY);
4937c478bd9Sstevel@tonic-gate 	int nread = 0;
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	if (fd != -1) {
4967c478bd9Sstevel@tonic-gate 		nread = read(fd, ret, NONCE_SIZE);
4977c478bd9Sstevel@tonic-gate 		close(fd);
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 	if (nread != NONCE_SIZE)
5007c478bd9Sstevel@tonic-gate 	    utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
5017c478bd9Sstevel@tonic-gate     }
5027c478bd9Sstevel@tonic-gate #else
5037c478bd9Sstevel@tonic-gate     utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
5047c478bd9Sstevel@tonic-gate #endif /* _DEV_URANDOM && _SUN_SDK_ */
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate     /* base 64 encode it so it has valid chars */
5077c478bd9Sstevel@tonic-gate     base64len = (NONCE_SIZE * 4 / 3) + (NONCE_SIZE % 3 ? 4 : 0);
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate     base64buf = (unsigned char *) utils->malloc(base64len + 1);
5107c478bd9Sstevel@tonic-gate     if (base64buf == NULL) {
5117c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
5127c478bd9Sstevel@tonic-gate 	utils->log(utils->conn, SASL_LOG_ERR,
5137c478bd9Sstevel@tonic-gate 		   "Unable to allocate final buffer");
5147c478bd9Sstevel@tonic-gate #else
5157c478bd9Sstevel@tonic-gate 	utils->seterror(utils->conn, 0, "Unable to allocate final buffer");
5167c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
5177c478bd9Sstevel@tonic-gate 	return NULL;
5187c478bd9Sstevel@tonic-gate     }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate     /*
5217c478bd9Sstevel@tonic-gate      * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
5227c478bd9Sstevel@tonic-gate      */
5237c478bd9Sstevel@tonic-gate     if (utils->encode64(ret, NONCE_SIZE,
5247c478bd9Sstevel@tonic-gate 			(char *) base64buf, base64len, NULL) != SASL_OK) {
5257c478bd9Sstevel@tonic-gate 	utils->free(ret);
5267c478bd9Sstevel@tonic-gate 	return NULL;
5277c478bd9Sstevel@tonic-gate     }
5287c478bd9Sstevel@tonic-gate     utils->free(ret);
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate     return base64buf;
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate 
add_to_challenge(const sasl_utils_t * utils,char ** str,unsigned * buflen,unsigned * curlen,char * name,unsigned char * value,bool need_quotes)5337c478bd9Sstevel@tonic-gate static int add_to_challenge(const sasl_utils_t *utils,
5347c478bd9Sstevel@tonic-gate 			    char **str, unsigned *buflen, unsigned *curlen,
5357c478bd9Sstevel@tonic-gate 			    char *name,
5367c478bd9Sstevel@tonic-gate 			    unsigned char *value,
5377c478bd9Sstevel@tonic-gate 			    bool need_quotes)
5387c478bd9Sstevel@tonic-gate {
5397c478bd9Sstevel@tonic-gate     int             namesize = strlen(name);
5407c478bd9Sstevel@tonic-gate     int             valuesize = strlen((char *) value);
5417c478bd9Sstevel@tonic-gate     int             ret;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate     ret = _plug_buf_alloc(utils, str, buflen,
5447c478bd9Sstevel@tonic-gate 			  *curlen + 1 + namesize + 2 + valuesize + 2);
5457c478bd9Sstevel@tonic-gate     if(ret != SASL_OK) return ret;
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate     *curlen = *curlen + 1 + namesize + 2 + valuesize + 2;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate     strcat(*str, ",");
5507c478bd9Sstevel@tonic-gate     strcat(*str, name);
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate     if (need_quotes) {
5537c478bd9Sstevel@tonic-gate 	strcat(*str, "=\"");
5547c478bd9Sstevel@tonic-gate 	strcat(*str, (char *) value);	/* XXX. What about quoting??? */
5557c478bd9Sstevel@tonic-gate 	strcat(*str, "\"");
5567c478bd9Sstevel@tonic-gate     } else {
5577c478bd9Sstevel@tonic-gate 	strcat(*str, "=");
5587c478bd9Sstevel@tonic-gate 	strcat(*str, (char *) value);
5597c478bd9Sstevel@tonic-gate     }
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate     return SASL_OK;
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate 
skip_lws(char * s)5647c478bd9Sstevel@tonic-gate static char *skip_lws (char *s)
5657c478bd9Sstevel@tonic-gate {
5667c478bd9Sstevel@tonic-gate     if(!s) return NULL;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate     /* skipping spaces: */
5697c478bd9Sstevel@tonic-gate     while (s[0] == ' ' || s[0] == HT || s[0] == CR || s[0] == LF) {
5707c478bd9Sstevel@tonic-gate 	if (s[0]=='\0') break;
5717c478bd9Sstevel@tonic-gate 	s++;
5727c478bd9Sstevel@tonic-gate     }
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate     return s;
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate #ifdef __SUN_SDK_
skip_token(char * s,int caseinsensitive)5787c478bd9Sstevel@tonic-gate static char *skip_token (char *s, int caseinsensitive  __attribute__((unused)))
5797c478bd9Sstevel@tonic-gate #else
5807c478bd9Sstevel@tonic-gate static char *skip_token (char *s, int caseinsensitive)
5817c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate     if(!s) return NULL;
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate #ifdef __SUN_SDK_
5867c478bd9Sstevel@tonic-gate     while (((unsigned char *)s)[0]>SP) {
5877c478bd9Sstevel@tonic-gate #else
5887c478bd9Sstevel@tonic-gate     while (s[0]>SP) {
5897c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
5907c478bd9Sstevel@tonic-gate 	if (s[0]==DEL || s[0]=='(' || s[0]==')' || s[0]=='<' || s[0]=='>' ||
5917c478bd9Sstevel@tonic-gate 	    s[0]=='@' || s[0]==',' || s[0]==';' || s[0]==':' || s[0]=='\\' ||
5927c478bd9Sstevel@tonic-gate 	    s[0]=='\'' || s[0]=='/' || s[0]=='[' || s[0]==']' || s[0]== '?' ||
5937c478bd9Sstevel@tonic-gate 	    s[0]=='=' || s[0]== '{' || s[0]== '}') {
5947c478bd9Sstevel@tonic-gate #ifdef __SUN_SDK_
5957c478bd9Sstevel@tonic-gate 	    /* the above chars are never uppercase */
5967c478bd9Sstevel@tonic-gate 	    break;
5977c478bd9Sstevel@tonic-gate #else
5987c478bd9Sstevel@tonic-gate 	    if (caseinsensitive == 1) {
5997c478bd9Sstevel@tonic-gate 		if (!isupper((unsigned char) s[0]))
6007c478bd9Sstevel@tonic-gate 		    break;
6017c478bd9Sstevel@tonic-gate 	    } else {
6027c478bd9Sstevel@tonic-gate 		break;
6037c478bd9Sstevel@tonic-gate 	    }
6047c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 	s++;
6077c478bd9Sstevel@tonic-gate     }
6087c478bd9Sstevel@tonic-gate     return s;
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate /* NULL - error (unbalanced quotes),
6127c478bd9Sstevel@tonic-gate    otherwise pointer to the first character after value */
6137c478bd9Sstevel@tonic-gate static char *unquote (char *qstr)
6147c478bd9Sstevel@tonic-gate {
6157c478bd9Sstevel@tonic-gate     char *endvalue;
6167c478bd9Sstevel@tonic-gate     int   escaped = 0;
6177c478bd9Sstevel@tonic-gate     char *outptr;
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate     if(!qstr) return NULL;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate     if (qstr[0] == '"') {
6227c478bd9Sstevel@tonic-gate 	qstr++;
6237c478bd9Sstevel@tonic-gate 	outptr = qstr;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	for (endvalue = qstr; endvalue[0] != '\0'; endvalue++, outptr++) {
6267c478bd9Sstevel@tonic-gate 	    if (escaped) {
6277c478bd9Sstevel@tonic-gate 		outptr[0] = endvalue[0];
6287c478bd9Sstevel@tonic-gate 		escaped = 0;
6297c478bd9Sstevel@tonic-gate 	    }
6307c478bd9Sstevel@tonic-gate 	    else if (endvalue[0] == '\\') {
6317c478bd9Sstevel@tonic-gate 		escaped = 1;
6327c478bd9Sstevel@tonic-gate 		outptr--; /* Will be incremented at the end of the loop */
6337c478bd9Sstevel@tonic-gate 	    }
6347c478bd9Sstevel@tonic-gate 	    else if (endvalue[0] == '"') {
6357c478bd9Sstevel@tonic-gate 		break;
6367c478bd9Sstevel@tonic-gate 	    }
6377c478bd9Sstevel@tonic-gate 	    else {
6387c478bd9Sstevel@tonic-gate 		outptr[0] = endvalue[0];
6397c478bd9Sstevel@tonic-gate 	    }
6407c478bd9Sstevel@tonic-gate 	}
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	if (endvalue[0] != '"') {
6437c478bd9Sstevel@tonic-gate 	    return NULL;
6447c478bd9Sstevel@tonic-gate 	}
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	while (outptr <= endvalue) {
6477c478bd9Sstevel@tonic-gate 	    outptr[0] = '\0';
6487c478bd9Sstevel@tonic-gate 	    outptr++;
6497c478bd9Sstevel@tonic-gate 	}
6507c478bd9Sstevel@tonic-gate 	endvalue++;
6517c478bd9Sstevel@tonic-gate     }
6527c478bd9Sstevel@tonic-gate     else { /* not qouted value (token) */
6537c478bd9Sstevel@tonic-gate 	endvalue = skip_token(qstr,0);
6547c478bd9Sstevel@tonic-gate     };
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate     return endvalue;
6577c478bd9Sstevel@tonic-gate }
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate static void get_pair(char **in, char **name, char **value)
6607c478bd9Sstevel@tonic-gate {
6617c478bd9Sstevel@tonic-gate     char  *endpair;
6627c478bd9Sstevel@tonic-gate     /* int    inQuotes; */
6637c478bd9Sstevel@tonic-gate     char  *curp = *in;
6647c478bd9Sstevel@tonic-gate     *name = NULL;
6657c478bd9Sstevel@tonic-gate     *value = NULL;
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate     if (curp == NULL) return;
6687c478bd9Sstevel@tonic-gate     if (curp[0] == '\0') return;
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate     /* skipping spaces: */
6717c478bd9Sstevel@tonic-gate     curp = skip_lws(curp);
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate     *name = curp;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate     curp = skip_token(curp,1);
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate     /* strip wierd chars */
6787c478bd9Sstevel@tonic-gate     if (curp[0] != '=' && curp[0] != '\0') {
6797c478bd9Sstevel@tonic-gate 	*curp++ = '\0';
6807c478bd9Sstevel@tonic-gate     };
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate     curp = skip_lws(curp);
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate     if (curp[0] != '=') { /* No '=' sign */
6857c478bd9Sstevel@tonic-gate 	*name = NULL;
6867c478bd9Sstevel@tonic-gate 	return;
6877c478bd9Sstevel@tonic-gate     }
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate     curp[0] = '\0';
6907c478bd9Sstevel@tonic-gate     curp++;
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate     curp = skip_lws(curp);
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate     *value = (curp[0] == '"') ? curp+1 : curp;
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate     endpair = unquote (curp);
6977c478bd9Sstevel@tonic-gate     if (endpair == NULL) { /* Unbalanced quotes */
6987c478bd9Sstevel@tonic-gate 	*name = NULL;
6997c478bd9Sstevel@tonic-gate 	return;
7007c478bd9Sstevel@tonic-gate     }
7017c478bd9Sstevel@tonic-gate     if (endpair[0] != ',') {
7027c478bd9Sstevel@tonic-gate 	if (endpair[0]!='\0') {
7037c478bd9Sstevel@tonic-gate 	    *endpair++ = '\0';
7047c478bd9Sstevel@tonic-gate 	}
7057c478bd9Sstevel@tonic-gate     }
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate     endpair = skip_lws(endpair);
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate     /* syntax check: MUST be '\0' or ',' */
7107c478bd9Sstevel@tonic-gate     if (endpair[0] == ',') {
7117c478bd9Sstevel@tonic-gate 	endpair[0] = '\0';
7127c478bd9Sstevel@tonic-gate 	endpair++; /* skipping <,> */
7137c478bd9Sstevel@tonic-gate     } else if (endpair[0] != '\0') {
7147c478bd9Sstevel@tonic-gate 	*name = NULL;
7157c478bd9Sstevel@tonic-gate 	return;
7167c478bd9Sstevel@tonic-gate     }
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate     *in = endpair;
7197c478bd9Sstevel@tonic-gate }
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate #ifdef WITH_DES
7227c478bd9Sstevel@tonic-gate struct des_context_s {
7237c478bd9Sstevel@tonic-gate     des_key_schedule keysched;  /* key schedule for des initialization */
7247c478bd9Sstevel@tonic-gate     des_cblock ivec;            /* initial vector for encoding */
7257c478bd9Sstevel@tonic-gate     des_key_schedule keysched2; /* key schedule for 3des initialization */
7267c478bd9Sstevel@tonic-gate };
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate typedef struct des_context_s des_context_t;
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate /* slide the first 7 bytes of 'inbuf' into the high seven bits of the
7317c478bd9Sstevel@tonic-gate    first 8 bytes of 'keybuf'. 'keybuf' better be 8 bytes long or longer. */
7327c478bd9Sstevel@tonic-gate static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
7337c478bd9Sstevel@tonic-gate {
7347c478bd9Sstevel@tonic-gate     keybuf[0] = inbuf[0];
7357c478bd9Sstevel@tonic-gate     keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
7367c478bd9Sstevel@tonic-gate     keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
7377c478bd9Sstevel@tonic-gate     keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
7387c478bd9Sstevel@tonic-gate     keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
7397c478bd9Sstevel@tonic-gate     keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
7407c478bd9Sstevel@tonic-gate     keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
7417c478bd9Sstevel@tonic-gate     keybuf[7] = (inbuf[6]<<1);
7427c478bd9Sstevel@tonic-gate }
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate /******************************
7457c478bd9Sstevel@tonic-gate  *
7467c478bd9Sstevel@tonic-gate  * 3DES functions
7477c478bd9Sstevel@tonic-gate  *
7487c478bd9Sstevel@tonic-gate  *****************************/
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate static int dec_3des(context_t *text,
7517c478bd9Sstevel@tonic-gate 		    const char *input,
7527c478bd9Sstevel@tonic-gate 		    unsigned inputlen,
7537c478bd9Sstevel@tonic-gate 		    unsigned char digest[16],
7547c478bd9Sstevel@tonic-gate 		    char *output,
7557c478bd9Sstevel@tonic-gate 		    unsigned *outputlen)
7567c478bd9Sstevel@tonic-gate {
7577c478bd9Sstevel@tonic-gate     des_context_t *c = (des_context_t *) text->cipher_dec_context;
7587c478bd9Sstevel@tonic-gate     int padding, p;
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate     des_ede2_cbc_encrypt((void *) input,
7617c478bd9Sstevel@tonic-gate 			 (void *) output,
7627c478bd9Sstevel@tonic-gate 			 inputlen,
7637c478bd9Sstevel@tonic-gate 			 c->keysched,
7647c478bd9Sstevel@tonic-gate 			 c->keysched2,
7657c478bd9Sstevel@tonic-gate 			 &c->ivec,
7667c478bd9Sstevel@tonic-gate 			 DES_DECRYPT);
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate     /* now chop off the padding */
7697c478bd9Sstevel@tonic-gate     padding = output[inputlen - 11];
7707c478bd9Sstevel@tonic-gate     if (padding < 1 || padding > 8) {
7717c478bd9Sstevel@tonic-gate 	/* invalid padding length */
7727c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
7737c478bd9Sstevel@tonic-gate     }
7747c478bd9Sstevel@tonic-gate     /* verify all padding is correct */
7757c478bd9Sstevel@tonic-gate     for (p = 1; p <= padding; p++) {
7767c478bd9Sstevel@tonic-gate 	if (output[inputlen - 10 - p] != padding) {
7777c478bd9Sstevel@tonic-gate 	    return SASL_FAIL;
7787c478bd9Sstevel@tonic-gate 	}
7797c478bd9Sstevel@tonic-gate     }
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate     /* chop off the padding */
7827c478bd9Sstevel@tonic-gate     *outputlen = inputlen - padding - 10;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate     /* copy in the HMAC to digest */
7857c478bd9Sstevel@tonic-gate     memcpy(digest, output + inputlen - 10, 10);
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate     return SASL_OK;
7887c478bd9Sstevel@tonic-gate }
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate static int enc_3des(context_t *text,
7917c478bd9Sstevel@tonic-gate 		    const char *input,
7927c478bd9Sstevel@tonic-gate 		    unsigned inputlen,
7937c478bd9Sstevel@tonic-gate 		    unsigned char digest[16],
7947c478bd9Sstevel@tonic-gate 		    char *output,
7957c478bd9Sstevel@tonic-gate 		    unsigned *outputlen)
7967c478bd9Sstevel@tonic-gate {
7977c478bd9Sstevel@tonic-gate     des_context_t *c = (des_context_t *) text->cipher_enc_context;
7987c478bd9Sstevel@tonic-gate     int len;
7997c478bd9Sstevel@tonic-gate     int paddinglen;
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate     /* determine padding length */
8027c478bd9Sstevel@tonic-gate     paddinglen = 8 - ((inputlen + 10) % 8);
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate     /* now construct the full stuff to be ciphered */
8057c478bd9Sstevel@tonic-gate     memcpy(output, input, inputlen);                /* text */
8067c478bd9Sstevel@tonic-gate     memset(output+inputlen, paddinglen, paddinglen);/* pad  */
8077c478bd9Sstevel@tonic-gate     memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate     len=inputlen+paddinglen+10;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate     des_ede2_cbc_encrypt((void *) output,
8127c478bd9Sstevel@tonic-gate 			 (void *) output,
8137c478bd9Sstevel@tonic-gate 			 len,
8147c478bd9Sstevel@tonic-gate 			 c->keysched,
8157c478bd9Sstevel@tonic-gate 			 c->keysched2,
8167c478bd9Sstevel@tonic-gate 			 &c->ivec,
8177c478bd9Sstevel@tonic-gate 			 DES_ENCRYPT);
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate     *outputlen=len;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate     return SASL_OK;
8227c478bd9Sstevel@tonic-gate }
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate static int init_3des(context_t *text,
8257c478bd9Sstevel@tonic-gate 		     unsigned char enckey[16],
8267c478bd9Sstevel@tonic-gate 		     unsigned char deckey[16])
8277c478bd9Sstevel@tonic-gate {
8287c478bd9Sstevel@tonic-gate     des_context_t *c;
8297c478bd9Sstevel@tonic-gate     unsigned char keybuf[8];
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate     /* allocate enc & dec context */
8327c478bd9Sstevel@tonic-gate     c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
8337c478bd9Sstevel@tonic-gate     if (c == NULL) return SASL_NOMEM;
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate     /* setup enc context */
8367c478bd9Sstevel@tonic-gate     slidebits(keybuf, enckey);
8377c478bd9Sstevel@tonic-gate     if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
8387c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate     slidebits(keybuf, enckey + 7);
8417c478bd9Sstevel@tonic-gate     if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
8427c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
8437c478bd9Sstevel@tonic-gate     memcpy(c->ivec, ((char *) enckey) + 8, 8);
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate     text->cipher_enc_context = (cipher_context_t *) c;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate     /* setup dec context */
8487c478bd9Sstevel@tonic-gate     c++;
8497c478bd9Sstevel@tonic-gate     slidebits(keybuf, deckey);
8507c478bd9Sstevel@tonic-gate     if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
8517c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate     slidebits(keybuf, deckey + 7);
8547c478bd9Sstevel@tonic-gate     if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
8557c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate     memcpy(c->ivec, ((char *) deckey) + 8, 8);
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate     text->cipher_dec_context = (cipher_context_t *) c;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate     return SASL_OK;
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate /******************************
8667c478bd9Sstevel@tonic-gate  *
8677c478bd9Sstevel@tonic-gate  * DES functions
8687c478bd9Sstevel@tonic-gate  *
8697c478bd9Sstevel@tonic-gate  *****************************/
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate static int dec_des(context_t *text,
8727c478bd9Sstevel@tonic-gate 		   const char *input,
8737c478bd9Sstevel@tonic-gate 		   unsigned inputlen,
8747c478bd9Sstevel@tonic-gate 		   unsigned char digest[16],
8757c478bd9Sstevel@tonic-gate 		   char *output,
8767c478bd9Sstevel@tonic-gate 		   unsigned *outputlen)
8777c478bd9Sstevel@tonic-gate {
8787c478bd9Sstevel@tonic-gate     des_context_t *c = (des_context_t *) text->cipher_dec_context;
8797c478bd9Sstevel@tonic-gate     int p, padding = 0;
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate     des_cbc_encrypt((void *) input,
8827c478bd9Sstevel@tonic-gate 		    (void *) output,
8837c478bd9Sstevel@tonic-gate 		    inputlen,
8847c478bd9Sstevel@tonic-gate 		    c->keysched,
8857c478bd9Sstevel@tonic-gate 		    &c->ivec,
8867c478bd9Sstevel@tonic-gate 		    DES_DECRYPT);
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate     /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
8897c478bd9Sstevel@tonic-gate        this way) */
8907c478bd9Sstevel@tonic-gate     memcpy(c->ivec, input + (inputlen - 8), 8);
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate     /* now chop off the padding */
8937c478bd9Sstevel@tonic-gate     padding = output[inputlen - 11];
8947c478bd9Sstevel@tonic-gate     if (padding < 1 || padding > 8) {
8957c478bd9Sstevel@tonic-gate 	/* invalid padding length */
8967c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
8977c478bd9Sstevel@tonic-gate     }
8987c478bd9Sstevel@tonic-gate     /* verify all padding is correct */
8997c478bd9Sstevel@tonic-gate     for (p = 1; p <= padding; p++) {
9007c478bd9Sstevel@tonic-gate 	if (output[inputlen - 10 - p] != padding) {
9017c478bd9Sstevel@tonic-gate 	    return SASL_FAIL;
9027c478bd9Sstevel@tonic-gate 	}
9037c478bd9Sstevel@tonic-gate     }
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate     /* chop off the padding */
9067c478bd9Sstevel@tonic-gate     *outputlen = inputlen - padding - 10;
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate     /* copy in the HMAC to digest */
9097c478bd9Sstevel@tonic-gate     memcpy(digest, output + inputlen - 10, 10);
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate     return SASL_OK;
9127c478bd9Sstevel@tonic-gate }
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate static int enc_des(context_t *text,
9157c478bd9Sstevel@tonic-gate 		   const char *input,
9167c478bd9Sstevel@tonic-gate 		   unsigned inputlen,
9177c478bd9Sstevel@tonic-gate 		   unsigned char digest[16],
9187c478bd9Sstevel@tonic-gate 		   char *output,
9197c478bd9Sstevel@tonic-gate 		   unsigned *outputlen)
9207c478bd9Sstevel@tonic-gate {
9217c478bd9Sstevel@tonic-gate     des_context_t *c = (des_context_t *) text->cipher_enc_context;
9227c478bd9Sstevel@tonic-gate     int len;
9237c478bd9Sstevel@tonic-gate     int paddinglen;
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate     /* determine padding length */
9267c478bd9Sstevel@tonic-gate     paddinglen = 8 - ((inputlen+10) % 8);
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate     /* now construct the full stuff to be ciphered */
9297c478bd9Sstevel@tonic-gate     memcpy(output, input, inputlen);                /* text */
9307c478bd9Sstevel@tonic-gate     memset(output+inputlen, paddinglen, paddinglen);/* pad  */
9317c478bd9Sstevel@tonic-gate     memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate     len = inputlen + paddinglen + 10;
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate     des_cbc_encrypt((void *) output,
9367c478bd9Sstevel@tonic-gate                     (void *) output,
9377c478bd9Sstevel@tonic-gate                     len,
9387c478bd9Sstevel@tonic-gate                     c->keysched,
9397c478bd9Sstevel@tonic-gate                     &c->ivec,
9407c478bd9Sstevel@tonic-gate                     DES_ENCRYPT);
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate     /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
9437c478bd9Sstevel@tonic-gate        this way) */
9447c478bd9Sstevel@tonic-gate     memcpy(c->ivec, output + (len - 8), 8);
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate     *outputlen = len;
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate     return SASL_OK;
9497c478bd9Sstevel@tonic-gate }
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate static int init_des(context_t *text,
9527c478bd9Sstevel@tonic-gate 		    unsigned char enckey[16],
9537c478bd9Sstevel@tonic-gate 		    unsigned char deckey[16])
9547c478bd9Sstevel@tonic-gate {
9557c478bd9Sstevel@tonic-gate     des_context_t *c;
9567c478bd9Sstevel@tonic-gate     unsigned char keybuf[8];
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate     /* allocate enc context */
9597c478bd9Sstevel@tonic-gate     c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
9607c478bd9Sstevel@tonic-gate     if (c == NULL) return SASL_NOMEM;
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate     /* setup enc context */
9637c478bd9Sstevel@tonic-gate     slidebits(keybuf, enckey);
9647c478bd9Sstevel@tonic-gate     des_key_sched((des_cblock *) keybuf, c->keysched);
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate     memcpy(c->ivec, ((char *) enckey) + 8, 8);
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate     text->cipher_enc_context = (cipher_context_t *) c;
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate     /* setup dec context */
9717c478bd9Sstevel@tonic-gate     c++;
9727c478bd9Sstevel@tonic-gate     slidebits(keybuf, deckey);
9737c478bd9Sstevel@tonic-gate     des_key_sched((des_cblock *) keybuf, c->keysched);
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate     memcpy(c->ivec, ((char *) deckey) + 8, 8);
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate     text->cipher_dec_context = (cipher_context_t *) c;
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate     return SASL_OK;
9807c478bd9Sstevel@tonic-gate }
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate static void free_des(context_t *text)
9837c478bd9Sstevel@tonic-gate {
9847c478bd9Sstevel@tonic-gate     /* free des contextss. only cipher_enc_context needs to be free'd,
9857c478bd9Sstevel@tonic-gate        since cipher_dec_context was allocated at the same time. */
9867c478bd9Sstevel@tonic-gate     if (text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
9877c478bd9Sstevel@tonic-gate }
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate #endif /* WITH_DES */
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate #ifdef WITH_RC4
9927c478bd9Sstevel@tonic-gate /* quick generic implementation of RC4 */
9937c478bd9Sstevel@tonic-gate struct rc4_context_s {
9947c478bd9Sstevel@tonic-gate     unsigned char sbox[256];
9957c478bd9Sstevel@tonic-gate     int i, j;
9967c478bd9Sstevel@tonic-gate };
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate typedef struct rc4_context_s rc4_context_t;
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate static void rc4_init(rc4_context_t *text,
10017c478bd9Sstevel@tonic-gate 		     const unsigned char *key,
10027c478bd9Sstevel@tonic-gate 		     unsigned keylen)
10037c478bd9Sstevel@tonic-gate {
10047c478bd9Sstevel@tonic-gate     int i, j;
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate     /* fill in linearly s0=0 s1=1... */
10077c478bd9Sstevel@tonic-gate     for (i=0;i<256;i++)
10087c478bd9Sstevel@tonic-gate 	text->sbox[i]=i;
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate     j=0;
10117c478bd9Sstevel@tonic-gate     for (i = 0; i < 256; i++) {
10127c478bd9Sstevel@tonic-gate 	unsigned char tmp;
10137c478bd9Sstevel@tonic-gate 	/* j = (j + Si + Ki) mod 256 */
10147c478bd9Sstevel@tonic-gate 	j = (j + text->sbox[i] + key[i % keylen]) % 256;
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 	/* swap Si and Sj */
10177c478bd9Sstevel@tonic-gate 	tmp = text->sbox[i];
10187c478bd9Sstevel@tonic-gate 	text->sbox[i] = text->sbox[j];
10197c478bd9Sstevel@tonic-gate 	text->sbox[j] = tmp;
10207c478bd9Sstevel@tonic-gate     }
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate     /* counters initialized to 0 */
10237c478bd9Sstevel@tonic-gate     text->i = 0;
10247c478bd9Sstevel@tonic-gate     text->j = 0;
10257c478bd9Sstevel@tonic-gate }
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate static void rc4_encrypt(rc4_context_t *text,
10287c478bd9Sstevel@tonic-gate 			const char *input,
10297c478bd9Sstevel@tonic-gate 			char *output,
10307c478bd9Sstevel@tonic-gate 			unsigned len)
10317c478bd9Sstevel@tonic-gate {
10327c478bd9Sstevel@tonic-gate     int tmp;
10337c478bd9Sstevel@tonic-gate     int i = text->i;
10347c478bd9Sstevel@tonic-gate     int j = text->j;
10357c478bd9Sstevel@tonic-gate     int t;
10367c478bd9Sstevel@tonic-gate     int K;
10377c478bd9Sstevel@tonic-gate     const char *input_end = input + len;
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate     while (input < input_end) {
10407c478bd9Sstevel@tonic-gate 	i = (i + 1) % 256;
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	j = (j + text->sbox[i]) % 256;
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 	/* swap Si and Sj */
10457c478bd9Sstevel@tonic-gate 	tmp = text->sbox[i];
10467c478bd9Sstevel@tonic-gate 	text->sbox[i] = text->sbox[j];
10477c478bd9Sstevel@tonic-gate 	text->sbox[j] = tmp;
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	t = (text->sbox[i] + text->sbox[j]) % 256;
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	K = text->sbox[t];
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	/* byte K is Xor'ed with plaintext */
10547c478bd9Sstevel@tonic-gate 	*output++ = *input++ ^ K;
10557c478bd9Sstevel@tonic-gate     }
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate     text->i = i;
10587c478bd9Sstevel@tonic-gate     text->j = j;
10597c478bd9Sstevel@tonic-gate }
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate static void rc4_decrypt(rc4_context_t *text,
10627c478bd9Sstevel@tonic-gate 			const char *input,
10637c478bd9Sstevel@tonic-gate 			char *output,
10647c478bd9Sstevel@tonic-gate 			unsigned len)
10657c478bd9Sstevel@tonic-gate {
10667c478bd9Sstevel@tonic-gate     int tmp;
10677c478bd9Sstevel@tonic-gate     int i = text->i;
10687c478bd9Sstevel@tonic-gate     int j = text->j;
10697c478bd9Sstevel@tonic-gate     int t;
10707c478bd9Sstevel@tonic-gate     int K;
10717c478bd9Sstevel@tonic-gate     const char *input_end = input + len;
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate     while (input < input_end) {
10747c478bd9Sstevel@tonic-gate 	i = (i + 1) % 256;
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	j = (j + text->sbox[i]) % 256;
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 	/* swap Si and Sj */
10797c478bd9Sstevel@tonic-gate 	tmp = text->sbox[i];
10807c478bd9Sstevel@tonic-gate 	text->sbox[i] = text->sbox[j];
10817c478bd9Sstevel@tonic-gate 	text->sbox[j] = tmp;
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	t = (text->sbox[i] + text->sbox[j]) % 256;
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	K = text->sbox[t];
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	/* byte K is Xor'ed with plaintext */
10887c478bd9Sstevel@tonic-gate 	*output++ = *input++ ^ K;
10897c478bd9Sstevel@tonic-gate     }
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate     text->i = i;
10927c478bd9Sstevel@tonic-gate     text->j = j;
10937c478bd9Sstevel@tonic-gate }
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate static void free_rc4(context_t *text)
10967c478bd9Sstevel@tonic-gate {
10977c478bd9Sstevel@tonic-gate     /* free rc4 context structures */
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate     if(text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
11007c478bd9Sstevel@tonic-gate     if(text->cipher_dec_context) text->utils->free(text->cipher_dec_context);
11017c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
11027c478bd9Sstevel@tonic-gate     text->cipher_enc_context = NULL;
11037c478bd9Sstevel@tonic-gate     text->cipher_dec_context = NULL;
11047c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
11057c478bd9Sstevel@tonic-gate }
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate static int init_rc4(context_t *text,
11087c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
11097c478bd9Sstevel@tonic-gate 		    char enckey[16],
11107c478bd9Sstevel@tonic-gate 		    char deckey[16])
11117c478bd9Sstevel@tonic-gate #else
11127c478bd9Sstevel@tonic-gate 		    unsigned char enckey[16],
11137c478bd9Sstevel@tonic-gate 		    unsigned char deckey[16])
11147c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
11157c478bd9Sstevel@tonic-gate {
11167c478bd9Sstevel@tonic-gate     /* allocate rc4 context structures */
11177c478bd9Sstevel@tonic-gate     text->cipher_enc_context=
11187c478bd9Sstevel@tonic-gate 	(cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
11197c478bd9Sstevel@tonic-gate     if (text->cipher_enc_context == NULL) return SASL_NOMEM;
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate     text->cipher_dec_context=
11227c478bd9Sstevel@tonic-gate 	(cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
11237c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
11247c478bd9Sstevel@tonic-gate     if (text->cipher_dec_context == NULL) {
11257c478bd9Sstevel@tonic-gate 	text->utils->free(text->cipher_enc_context);
11267c478bd9Sstevel@tonic-gate 	text->cipher_enc_context = NULL;
11277c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
11287c478bd9Sstevel@tonic-gate     }
11297c478bd9Sstevel@tonic-gate #else
11307c478bd9Sstevel@tonic-gate     if (text->cipher_dec_context == NULL) return SASL_NOMEM;
11317c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate     /* initialize them */
11347c478bd9Sstevel@tonic-gate     rc4_init((rc4_context_t *) text->cipher_enc_context,
11357c478bd9Sstevel@tonic-gate              (const unsigned char *) enckey, 16);
11367c478bd9Sstevel@tonic-gate     rc4_init((rc4_context_t *) text->cipher_dec_context,
11377c478bd9Sstevel@tonic-gate              (const unsigned char *) deckey, 16);
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate     return SASL_OK;
11407c478bd9Sstevel@tonic-gate }
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate static int dec_rc4(context_t *text,
11437c478bd9Sstevel@tonic-gate 		   const char *input,
11447c478bd9Sstevel@tonic-gate 		   unsigned inputlen,
11457c478bd9Sstevel@tonic-gate 		   unsigned char digest[16],
11467c478bd9Sstevel@tonic-gate 		   char *output,
11477c478bd9Sstevel@tonic-gate 		   unsigned *outputlen)
11487c478bd9Sstevel@tonic-gate {
11497c478bd9Sstevel@tonic-gate     /* decrypt the text part */
11507c478bd9Sstevel@tonic-gate     rc4_decrypt((rc4_context_t *) text->cipher_dec_context,
11517c478bd9Sstevel@tonic-gate                 input, output, inputlen-10);
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate     /* decrypt the HMAC part */
11547c478bd9Sstevel@tonic-gate     rc4_decrypt((rc4_context_t *) text->cipher_dec_context,
11557c478bd9Sstevel@tonic-gate 		input+(inputlen-10), (char *) digest, 10);
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate     /* no padding so we just subtract the HMAC to get the text length */
11587c478bd9Sstevel@tonic-gate     *outputlen = inputlen - 10;
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate     return SASL_OK;
11617c478bd9Sstevel@tonic-gate }
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate static int enc_rc4(context_t *text,
11647c478bd9Sstevel@tonic-gate 		   const char *input,
11657c478bd9Sstevel@tonic-gate 		   unsigned inputlen,
11667c478bd9Sstevel@tonic-gate 		   unsigned char digest[16],
11677c478bd9Sstevel@tonic-gate 		   char *output,
11687c478bd9Sstevel@tonic-gate 		   unsigned *outputlen)
11697c478bd9Sstevel@tonic-gate {
11707c478bd9Sstevel@tonic-gate     /* pad is zero */
11717c478bd9Sstevel@tonic-gate     *outputlen = inputlen+10;
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate     /* encrypt the text part */
11747c478bd9Sstevel@tonic-gate     rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
11757c478bd9Sstevel@tonic-gate                 input,
11767c478bd9Sstevel@tonic-gate                 output,
11777c478bd9Sstevel@tonic-gate                 inputlen);
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate     /* encrypt the HMAC part */
11807c478bd9Sstevel@tonic-gate     rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
11817c478bd9Sstevel@tonic-gate                 (const char *) digest,
11827c478bd9Sstevel@tonic-gate 		(output)+inputlen, 10);
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate     return SASL_OK;
11857c478bd9Sstevel@tonic-gate }
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate #endif /* WITH_RC4 */
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate struct digest_cipher available_ciphers[] =
11907c478bd9Sstevel@tonic-gate {
11917c478bd9Sstevel@tonic-gate #ifdef WITH_RC4
11927c478bd9Sstevel@tonic-gate     { "rc4-40", 40, 5, 0x01, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
11937c478bd9Sstevel@tonic-gate     { "rc4-56", 56, 7, 0x02, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
11947c478bd9Sstevel@tonic-gate     { "rc4", 128, 16, 0x04, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
11957c478bd9Sstevel@tonic-gate #endif
11967c478bd9Sstevel@tonic-gate #ifdef WITH_DES
11977c478bd9Sstevel@tonic-gate     { "des", 55, 16, 0x08, &enc_des, &dec_des, &init_des, &free_des },
11987c478bd9Sstevel@tonic-gate     { "3des", 112, 16, 0x10, &enc_3des, &dec_3des, &init_3des, &free_des },
11997c478bd9Sstevel@tonic-gate #endif
12007c478bd9Sstevel@tonic-gate     { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
12017c478bd9Sstevel@tonic-gate };
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate #ifdef USE_UEF
12057c478bd9Sstevel@tonic-gate DEFINE_STATIC_MUTEX(uef_init_mutex);
12067c478bd9Sstevel@tonic-gate #define DES_CIPHER_INDEX	3
12077c478bd9Sstevel@tonic-gate #define DES3_CIPHER_INDEX	4
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate static int got_uef_slot = FALSE;
12107c478bd9Sstevel@tonic-gate static sasl_ssf_t uef_max_ssf = 0;
12117c478bd9Sstevel@tonic-gate static CK_SLOT_ID rc4_slot_id;
12127c478bd9Sstevel@tonic-gate static CK_SLOT_ID des_slot_id;
12137c478bd9Sstevel@tonic-gate static CK_SLOT_ID des3_slot_id;
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate struct uef_context_s {
12167c478bd9Sstevel@tonic-gate     CK_SESSION_HANDLE hSession;
12177c478bd9Sstevel@tonic-gate     CK_OBJECT_HANDLE hKey;
12187c478bd9Sstevel@tonic-gate };
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate typedef struct uef_context_s uef_context_t;
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate /*
12237c478bd9Sstevel@tonic-gate  * slide the first 7 bytes of 'inbuf' into the high seven bits of the
12247c478bd9Sstevel@tonic-gate  * first 8 bytes of 'keybuf'. 'inbuf' better be 8 bytes long or longer.
12257c478bd9Sstevel@tonic-gate  *
12267c478bd9Sstevel@tonic-gate  * This is used to compute the IV for "des" and "3des" as described in
12277c478bd9Sstevel@tonic-gate  * draft-ietf-sasl-rfc2831bis-00.txt - The IV for "des"
12287c478bd9Sstevel@tonic-gate  *  and "3des" is the last 8 bytes of Kcc or Kcs - the encryption keys.
12297c478bd9Sstevel@tonic-gate  */
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
12327c478bd9Sstevel@tonic-gate {
12337c478bd9Sstevel@tonic-gate     keybuf[0] = inbuf[0];
12347c478bd9Sstevel@tonic-gate     keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
12357c478bd9Sstevel@tonic-gate     keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
12367c478bd9Sstevel@tonic-gate     keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
12377c478bd9Sstevel@tonic-gate     keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
12387c478bd9Sstevel@tonic-gate     keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
12397c478bd9Sstevel@tonic-gate     keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
12407c478bd9Sstevel@tonic-gate     keybuf[7] = (inbuf[6]<<1);
12417c478bd9Sstevel@tonic-gate }
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate /*
12447c478bd9Sstevel@tonic-gate  * Create encryption and decryption session handle handles for later use.
12457c478bd9Sstevel@tonic-gate  * Returns SASL_OK on success - any other return indicates failure.
12467c478bd9Sstevel@tonic-gate  *
12477c478bd9Sstevel@tonic-gate  * free_uef is called to release associated resources by
12487c478bd9Sstevel@tonic-gate  *	digestmd5_common_mech_dispose
12497c478bd9Sstevel@tonic-gate  */
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate static int init_uef(context_t *text,
12527c478bd9Sstevel@tonic-gate 		    CK_KEY_TYPE keyType,
12537c478bd9Sstevel@tonic-gate 		    CK_MECHANISM_TYPE mech_type,
12547c478bd9Sstevel@tonic-gate 		    CK_SLOT_ID slot_id,
12557c478bd9Sstevel@tonic-gate 		    char enckey[16],
12567c478bd9Sstevel@tonic-gate 		    char deckey[16])
12577c478bd9Sstevel@tonic-gate {
12587c478bd9Sstevel@tonic-gate     CK_RV		rv;
12597c478bd9Sstevel@tonic-gate     uef_context_t	*enc_context;
12607c478bd9Sstevel@tonic-gate     uef_context_t	*dec_context;
12617c478bd9Sstevel@tonic-gate     CK_OBJECT_CLASS	class = CKO_SECRET_KEY;
12627c478bd9Sstevel@tonic-gate     CK_BBOOL		true = TRUE;
12637c478bd9Sstevel@tonic-gate     static CK_MECHANISM	mechanism = {CKM_RC4, NULL, 0};
12647c478bd9Sstevel@tonic-gate     unsigned char	keybuf[24];
12657c478bd9Sstevel@tonic-gate     CK_ATTRIBUTE	template[] = {
12667c478bd9Sstevel@tonic-gate 				{CKA_CLASS, NULL, sizeof (class)},
12677c478bd9Sstevel@tonic-gate 				{CKA_KEY_TYPE, NULL, sizeof (keyType)},
12687c478bd9Sstevel@tonic-gate 				{CKA_ENCRYPT, NULL, sizeof (true)},
12697c478bd9Sstevel@tonic-gate 				{CKA_VALUE, NULL, 16}};
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate     template[0].pValue = &class;
12727c478bd9Sstevel@tonic-gate     template[1].pValue = &keyType;
12737c478bd9Sstevel@tonic-gate     template[2].pValue = &true;
12747c478bd9Sstevel@tonic-gate     if (keyType == CKK_DES || keyType == CKK_DES3) {
12757c478bd9Sstevel@tonic-gate 	slidebits(keybuf, (unsigned char *)enckey);
12767c478bd9Sstevel@tonic-gate 	if (keyType == CKK_DES3) {
12777c478bd9Sstevel@tonic-gate 	    slidebits(keybuf + 8, (unsigned char *)enckey + 7);
12787c478bd9Sstevel@tonic-gate 	    (void) memcpy(keybuf + 16, keybuf, 8);
12797c478bd9Sstevel@tonic-gate 	    template[3].ulValueLen = 24;
12807c478bd9Sstevel@tonic-gate 	} else {
12817c478bd9Sstevel@tonic-gate 	    template[3].ulValueLen = 8;
12827c478bd9Sstevel@tonic-gate 	}
12837c478bd9Sstevel@tonic-gate 	template[3].pValue = keybuf;
12847c478bd9Sstevel@tonic-gate 	mechanism.pParameter = enckey + 8;
12857c478bd9Sstevel@tonic-gate 	mechanism.ulParameterLen = 8;
12867c478bd9Sstevel@tonic-gate     } else {
12877c478bd9Sstevel@tonic-gate 	template[3].pValue = enckey;
12887c478bd9Sstevel@tonic-gate     }
12897c478bd9Sstevel@tonic-gate     mechanism.mechanism = mech_type;
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate     /* allocate rc4 context structures */
12927c478bd9Sstevel@tonic-gate     enc_context = text->utils->malloc(sizeof (uef_context_t));
12937c478bd9Sstevel@tonic-gate     if (enc_context == NULL)
12947c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate     rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
12977c478bd9Sstevel@tonic-gate 		&enc_context->hSession);
12987c478bd9Sstevel@tonic-gate     if (rv != CKR_OK) {
12997c478bd9Sstevel@tonic-gate 	text->utils->free(enc_context);
13007c478bd9Sstevel@tonic-gate #ifdef DEBUG
13017c478bd9Sstevel@tonic-gate 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
13027c478bd9Sstevel@tonic-gate 		"enc C_OpenSession Failed:0x%.8X\n", rv);
13037c478bd9Sstevel@tonic-gate #endif
13047c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
13057c478bd9Sstevel@tonic-gate     }
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate     rv = C_CreateObject(enc_context->hSession, template,
13087c478bd9Sstevel@tonic-gate 		sizeof (template)/sizeof (template[0]), &enc_context->hKey);
13097c478bd9Sstevel@tonic-gate     if (rv != CKR_OK) {
13107c478bd9Sstevel@tonic-gate 	text->utils->free(enc_context);
13117c478bd9Sstevel@tonic-gate 	(void) C_CloseSession(enc_context->hSession);
13127c478bd9Sstevel@tonic-gate #ifdef DEBUG
13137c478bd9Sstevel@tonic-gate 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
13147c478bd9Sstevel@tonic-gate 			 "enc C_CreateObject: rv = 0x%.8X\n", rv);
13157c478bd9Sstevel@tonic-gate #endif
13167c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
13177c478bd9Sstevel@tonic-gate     }
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate     text->cipher_enc_context = (cipher_context_t *)enc_context;
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate     /* Initialize the encryption operation in the session */
13227c478bd9Sstevel@tonic-gate     rv = C_EncryptInit(enc_context->hSession, &mechanism, enc_context->hKey);
13237c478bd9Sstevel@tonic-gate     if (rv != CKR_OK) {
13247c478bd9Sstevel@tonic-gate #ifdef DEBUG
13257c478bd9Sstevel@tonic-gate 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
13267c478bd9Sstevel@tonic-gate 			 "C_EncryptInit: rv = 0x%.8X\n", rv);
13277c478bd9Sstevel@tonic-gate #endif
13287c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
13297c478bd9Sstevel@tonic-gate     }
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate     dec_context = text->utils->malloc(sizeof(uef_context_t));
13327c478bd9Sstevel@tonic-gate     if (dec_context == NULL)
13337c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate     rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
13367c478bd9Sstevel@tonic-gate 		&dec_context->hSession);
13377c478bd9Sstevel@tonic-gate     if (rv != CKR_OK) {
13387c478bd9Sstevel@tonic-gate #ifdef DEBUG
13397c478bd9Sstevel@tonic-gate 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
13407c478bd9Sstevel@tonic-gate 		"dec C_OpenSession Failed:0x%.8X\n", rv);
13417c478bd9Sstevel@tonic-gate #endif
13427c478bd9Sstevel@tonic-gate 	text->utils->free(dec_context);
13437c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
13447c478bd9Sstevel@tonic-gate     }
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate     template[2].type = CKA_DECRYPT;
13477c478bd9Sstevel@tonic-gate     if (keyType == CKK_DES || keyType == CKK_DES3) {
13487c478bd9Sstevel@tonic-gate 	slidebits(keybuf, (unsigned char *)deckey);
13497c478bd9Sstevel@tonic-gate 	if (keyType == CKK_DES3) {
13507c478bd9Sstevel@tonic-gate 	    slidebits(keybuf + 8, (unsigned char *)deckey + 7);
13517c478bd9Sstevel@tonic-gate 	    (void) memcpy(keybuf + 16, keybuf, 8);
13527c478bd9Sstevel@tonic-gate 	}
13537c478bd9Sstevel@tonic-gate 	mechanism.pParameter = deckey + 8;
13547c478bd9Sstevel@tonic-gate     } else {
13557c478bd9Sstevel@tonic-gate 	template[3].pValue = deckey;
13567c478bd9Sstevel@tonic-gate     }
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate     rv = C_CreateObject(dec_context->hSession, template,
13597c478bd9Sstevel@tonic-gate 		sizeof (template)/sizeof (template[0]), &dec_context->hKey);
13607c478bd9Sstevel@tonic-gate     if (rv != CKR_OK) {
13617c478bd9Sstevel@tonic-gate #ifdef DEBUG
13627c478bd9Sstevel@tonic-gate 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
13637c478bd9Sstevel@tonic-gate 		"dec C_CreateObject: rv = 0x%.8X\n", rv);
13647c478bd9Sstevel@tonic-gate #endif
13657c478bd9Sstevel@tonic-gate 	(void) C_CloseSession(dec_context->hSession);
13667c478bd9Sstevel@tonic-gate 	text->utils->free(dec_context);
13677c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
13687c478bd9Sstevel@tonic-gate     }
13697c478bd9Sstevel@tonic-gate     text->cipher_dec_context = (cipher_context_t *)dec_context;
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate     /* Initialize the decryption operation in the session */
13727c478bd9Sstevel@tonic-gate     rv = C_DecryptInit(dec_context->hSession, &mechanism, dec_context->hKey);
13737c478bd9Sstevel@tonic-gate     if (rv != CKR_OK) {
13747c478bd9Sstevel@tonic-gate #ifdef DEBUG
13757c478bd9Sstevel@tonic-gate 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
13767c478bd9Sstevel@tonic-gate 			 "C_DecryptInit: rv = 0x%.8X\n", rv);
13777c478bd9Sstevel@tonic-gate #endif
13787c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
13797c478bd9Sstevel@tonic-gate     }
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate     return SASL_OK;
13827c478bd9Sstevel@tonic-gate }
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate static int init_rc4_uef(context_t *text,
13857c478bd9Sstevel@tonic-gate 		    char enckey[16],
13867c478bd9Sstevel@tonic-gate 		    char deckey[16])
13877c478bd9Sstevel@tonic-gate {
13887c478bd9Sstevel@tonic-gate     return init_uef(text, CKK_RC4, CKM_RC4, rc4_slot_id, enckey, deckey);
13897c478bd9Sstevel@tonic-gate }
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate static int init_des_uef(context_t *text,
13927c478bd9Sstevel@tonic-gate 		    char enckey[16],
13937c478bd9Sstevel@tonic-gate 		    char deckey[16])
13947c478bd9Sstevel@tonic-gate {
13957c478bd9Sstevel@tonic-gate     return init_uef(text, CKK_DES, CKM_DES_CBC, des_slot_id, enckey, deckey);
13967c478bd9Sstevel@tonic-gate }
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate static int init_3des_uef(context_t *text,
13997c478bd9Sstevel@tonic-gate 		    char enckey[16],
14007c478bd9Sstevel@tonic-gate 		    char deckey[16])
14017c478bd9Sstevel@tonic-gate {
14027c478bd9Sstevel@tonic-gate     return init_uef(text, CKK_DES3, CKM_DES3_CBC, des3_slot_id, enckey, deckey);
14037c478bd9Sstevel@tonic-gate }
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate static void
14067c478bd9Sstevel@tonic-gate free_uef(context_t *text)
14077c478bd9Sstevel@tonic-gate {
14087c478bd9Sstevel@tonic-gate     uef_context_t	*enc_context =
14097c478bd9Sstevel@tonic-gate 		(uef_context_t *)text->cipher_enc_context;
14107c478bd9Sstevel@tonic-gate     uef_context_t	*dec_context =
14117c478bd9Sstevel@tonic-gate 		(uef_context_t *)text->cipher_dec_context;
14127c478bd9Sstevel@tonic-gate     CK_RV		rv;
14137c478bd9Sstevel@tonic-gate     unsigned char	buf[1];
14147c478bd9Sstevel@tonic-gate     CK_ULONG		ulLen = 0;
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate     if (enc_context != NULL) {
14187c478bd9Sstevel@tonic-gate 	rv = C_EncryptFinal(enc_context->hSession, buf, &ulLen);
14197c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
14207c478bd9Sstevel@tonic-gate #ifdef DEBUG
14217c478bd9Sstevel@tonic-gate 	    text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
14227c478bd9Sstevel@tonic-gate 			     "C_EncryptFinal failed:0x%.8X\n", rv);
14237c478bd9Sstevel@tonic-gate #endif
14247c478bd9Sstevel@tonic-gate 	}
14257c478bd9Sstevel@tonic-gate 	rv = C_DestroyObject(enc_context->hSession, enc_context->hKey);
14267c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
14277c478bd9Sstevel@tonic-gate #ifdef DEBUG
14287c478bd9Sstevel@tonic-gate 	    text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
14297c478bd9Sstevel@tonic-gate 			     "C_DestroyObject failed:0x%.8X\n", rv);
14307c478bd9Sstevel@tonic-gate #endif
14317c478bd9Sstevel@tonic-gate 	}
14327c478bd9Sstevel@tonic-gate 	rv = C_CloseSession(enc_context->hSession);
14337c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
14347c478bd9Sstevel@tonic-gate #ifdef DEBUG
14357c478bd9Sstevel@tonic-gate 	    text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
14367c478bd9Sstevel@tonic-gate 			     "C_CloseSession failed:0x%.8X\n", rv);
14377c478bd9Sstevel@tonic-gate #endif
14387c478bd9Sstevel@tonic-gate 	}
14397c478bd9Sstevel@tonic-gate 	text->utils->free(enc_context);
14407c478bd9Sstevel@tonic-gate     }
14417c478bd9Sstevel@tonic-gate     if (dec_context != NULL) {
14427c478bd9Sstevel@tonic-gate 	rv = C_DecryptFinal(dec_context->hSession, buf, &ulLen);
14437c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
14447c478bd9Sstevel@tonic-gate #ifdef DEBUG
14457c478bd9Sstevel@tonic-gate 	    text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
14467c478bd9Sstevel@tonic-gate 			     "C_DecryptFinal failed:0x%.8X\n", rv);
14477c478bd9Sstevel@tonic-gate #endif
14487c478bd9Sstevel@tonic-gate 	}
14497c478bd9Sstevel@tonic-gate 	rv = C_DestroyObject(dec_context->hSession, dec_context->hKey);
14507c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
14517c478bd9Sstevel@tonic-gate #ifdef DEBUG
14527c478bd9Sstevel@tonic-gate 	    text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
14537c478bd9Sstevel@tonic-gate 			     "C_DestroyObject failed:0x%.8X\n", rv);
14547c478bd9Sstevel@tonic-gate #endif
14557c478bd9Sstevel@tonic-gate 	}
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 	rv = C_CloseSession(dec_context->hSession);
14587c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
14597c478bd9Sstevel@tonic-gate #ifdef DEBUG
14607c478bd9Sstevel@tonic-gate 	    text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
14617c478bd9Sstevel@tonic-gate 			     "C_CloseSession failed:0x%.8X\n", rv);
14627c478bd9Sstevel@tonic-gate #endif
14637c478bd9Sstevel@tonic-gate 	}
14647c478bd9Sstevel@tonic-gate 	text->utils->free(dec_context);
14657c478bd9Sstevel@tonic-gate     }
14667c478bd9Sstevel@tonic-gate     text->cipher_enc_context = NULL;
14677c478bd9Sstevel@tonic-gate     text->cipher_dec_context = NULL;
14687c478bd9Sstevel@tonic-gate }
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate static int
14717c478bd9Sstevel@tonic-gate dec_rc4_uef(context_t *text,
14727c478bd9Sstevel@tonic-gate 	    const char *input,
14737c478bd9Sstevel@tonic-gate 	    unsigned inputlen,
14747c478bd9Sstevel@tonic-gate 	    unsigned char digest[16],
14757c478bd9Sstevel@tonic-gate 	    char *output,
14767c478bd9Sstevel@tonic-gate 	    unsigned *outputlen)
14777c478bd9Sstevel@tonic-gate {
14787c478bd9Sstevel@tonic-gate     CK_RV		rv;
14797c478bd9Sstevel@tonic-gate     uef_context_t	*dec_context =
14807c478bd9Sstevel@tonic-gate 		(uef_context_t *)text->cipher_dec_context;
14817c478bd9Sstevel@tonic-gate     CK_ULONG		ulDataLen = *outputlen - MAC_SIZE;
14827c478bd9Sstevel@tonic-gate     CK_ULONG		ulDigestLen = MAC_SIZE;
14837c478bd9Sstevel@tonic-gate 
14847c478bd9Sstevel@tonic-gate     rv = C_DecryptUpdate(dec_context->hSession, (CK_BYTE_PTR)input,
14857c478bd9Sstevel@tonic-gate 	inputlen - MAC_SIZE, (CK_BYTE_PTR)output, &ulDataLen);
14867c478bd9Sstevel@tonic-gate     if (rv != CKR_OK) {
14877c478bd9Sstevel@tonic-gate #ifdef DEBUG
14887c478bd9Sstevel@tonic-gate 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
14897c478bd9Sstevel@tonic-gate 			 "C_DecryptUpdate failed:0x%.8X\n", rv);
14907c478bd9Sstevel@tonic-gate #endif
14917c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
14927c478bd9Sstevel@tonic-gate     }
14937c478bd9Sstevel@tonic-gate     *outputlen = (unsigned)ulDataLen;
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate     rv = C_DecryptUpdate(dec_context->hSession,
14967c478bd9Sstevel@tonic-gate 	(CK_BYTE_PTR)input+(inputlen-MAC_SIZE), MAC_SIZE, (CK_BYTE_PTR)digest,
14977c478bd9Sstevel@tonic-gate 	&ulDigestLen);
14987c478bd9Sstevel@tonic-gate     if (rv != CKR_OK || ulDigestLen != MAC_SIZE) {
14997c478bd9Sstevel@tonic-gate #ifdef DEBUG
15007c478bd9Sstevel@tonic-gate 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
15017c478bd9Sstevel@tonic-gate 			 "C_DecryptUpdate:0x%.8X, digestLen:%d\n",
15027c478bd9Sstevel@tonic-gate 			 rv, ulDigestLen);
15037c478bd9Sstevel@tonic-gate #endif
15047c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
15057c478bd9Sstevel@tonic-gate     }
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate     return SASL_OK;
15087c478bd9Sstevel@tonic-gate }
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate static int
15117c478bd9Sstevel@tonic-gate enc_rc4_uef(context_t *text,
15127c478bd9Sstevel@tonic-gate 	    const char *input,
15137c478bd9Sstevel@tonic-gate 	    unsigned inputlen,
15147c478bd9Sstevel@tonic-gate 	    unsigned char digest[16],
15157c478bd9Sstevel@tonic-gate 	    char *output,
15167c478bd9Sstevel@tonic-gate 	    unsigned *outputlen)
15177c478bd9Sstevel@tonic-gate {
15187c478bd9Sstevel@tonic-gate     CK_RV		rv;
15197c478bd9Sstevel@tonic-gate     uef_context_t	*enc_context =
15207c478bd9Sstevel@tonic-gate 		(uef_context_t *)text->cipher_enc_context;
15217c478bd9Sstevel@tonic-gate     CK_ULONG		ulDataLen = inputlen;
15227c478bd9Sstevel@tonic-gate     CK_ULONG		ulDigestLen = MAC_SIZE;
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate     rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)input, inputlen,
15257c478bd9Sstevel@tonic-gate 	(CK_BYTE_PTR)output, &ulDataLen);
15267c478bd9Sstevel@tonic-gate     if (rv != CKR_OK) {
15277c478bd9Sstevel@tonic-gate #ifdef DEBUG
15287c478bd9Sstevel@tonic-gate 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
15297c478bd9Sstevel@tonic-gate 			 "C_EncryptUpdate failed: 0x%.8X "
15307c478bd9Sstevel@tonic-gate 			  "inputlen:%d outputlen:%d\n",
15317c478bd9Sstevel@tonic-gate 			  rv, inputlen, ulDataLen);
15327c478bd9Sstevel@tonic-gate #endif
15337c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
15347c478bd9Sstevel@tonic-gate     }
15357c478bd9Sstevel@tonic-gate     rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)digest, MAC_SIZE,
15367c478bd9Sstevel@tonic-gate 	(CK_BYTE_PTR)output + inputlen, &ulDigestLen);
15377c478bd9Sstevel@tonic-gate     if (rv != CKR_OK) {
15387c478bd9Sstevel@tonic-gate #ifdef DEBUG
15397c478bd9Sstevel@tonic-gate 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
15407c478bd9Sstevel@tonic-gate 			 "C_EncryptUpdate failed: 0x%.8X ulDigestLen:%d\n",
15417c478bd9Sstevel@tonic-gate 			 rv, ulDigestLen);
15427c478bd9Sstevel@tonic-gate #endif
15437c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
15447c478bd9Sstevel@tonic-gate     }
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate     *outputlen = ulDataLen + ulDigestLen;
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate     return SASL_OK;
15497c478bd9Sstevel@tonic-gate }
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate static int
15527c478bd9Sstevel@tonic-gate dec_des_uef(context_t *text,
15537c478bd9Sstevel@tonic-gate 	    const char *input,
15547c478bd9Sstevel@tonic-gate 	    unsigned inputlen,
15557c478bd9Sstevel@tonic-gate 	    unsigned char digest[16],
15567c478bd9Sstevel@tonic-gate 	    char *output,
15577c478bd9Sstevel@tonic-gate 	    unsigned *outputlen)
15587c478bd9Sstevel@tonic-gate {
15597c478bd9Sstevel@tonic-gate     CK_RV		rv;
15607c478bd9Sstevel@tonic-gate     uef_context_t	*dec_context =
15617c478bd9Sstevel@tonic-gate 		(uef_context_t *)text->cipher_dec_context;
15627c478bd9Sstevel@tonic-gate     CK_ULONG		ulDataLen = inputlen;
15637c478bd9Sstevel@tonic-gate     int			padding, p;
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate     rv = C_DecryptUpdate(dec_context->hSession, (CK_BYTE_PTR)input,
15667c478bd9Sstevel@tonic-gate 	inputlen, (CK_BYTE_PTR)output, &ulDataLen);
15677c478bd9Sstevel@tonic-gate     if (rv != CKR_OK) {
15687c478bd9Sstevel@tonic-gate #ifdef DEBUG
15697c478bd9Sstevel@tonic-gate 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
15707c478bd9Sstevel@tonic-gate 			 "C_DecryptUpdate failed:0x%.8X\n", rv);
15717c478bd9Sstevel@tonic-gate #endif
15727c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
15737c478bd9Sstevel@tonic-gate     }
15747c478bd9Sstevel@tonic-gate     if (ulDataLen != inputlen) {
15757c478bd9Sstevel@tonic-gate #ifdef DEBUG
15767c478bd9Sstevel@tonic-gate 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
15777c478bd9Sstevel@tonic-gate 			 "C_DecryptUpdate unexpected data len:%d !=%d\n",
15787c478bd9Sstevel@tonic-gate 			 inputlen, ulDataLen);
15797c478bd9Sstevel@tonic-gate #endif
15807c478bd9Sstevel@tonic-gate 	return SASL_BUFOVER;
15817c478bd9Sstevel@tonic-gate     }
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate     /* now chop off the padding */
15847c478bd9Sstevel@tonic-gate     padding = output[inputlen - 11];
15857c478bd9Sstevel@tonic-gate     if (padding < 1 || padding > 8) {
15867c478bd9Sstevel@tonic-gate 	/* invalid padding length */
15877c478bd9Sstevel@tonic-gate 	return SASL_BADMAC;
15887c478bd9Sstevel@tonic-gate     }
15897c478bd9Sstevel@tonic-gate     /* verify all padding is correct */
15907c478bd9Sstevel@tonic-gate     for (p = 1; p <= padding; p++) {
15917c478bd9Sstevel@tonic-gate 	if (output[inputlen - MAC_SIZE - p] != padding) {
15927c478bd9Sstevel@tonic-gate 	    return SASL_BADMAC;
15937c478bd9Sstevel@tonic-gate 	}
15947c478bd9Sstevel@tonic-gate     }
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate     /* chop off the padding */
15977c478bd9Sstevel@tonic-gate     *outputlen = inputlen - padding - MAC_SIZE;
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate     /* copy in the HMAC to digest */
16007c478bd9Sstevel@tonic-gate     memcpy(digest, output + inputlen - MAC_SIZE, MAC_SIZE);
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate     return SASL_OK;
16037c478bd9Sstevel@tonic-gate }
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate static int
16067c478bd9Sstevel@tonic-gate enc_des_uef(context_t *text,
16077c478bd9Sstevel@tonic-gate 	    const char *input,
16087c478bd9Sstevel@tonic-gate 	    unsigned inputlen,
16097c478bd9Sstevel@tonic-gate 	    unsigned char digest[16],
16107c478bd9Sstevel@tonic-gate 	    char *output,
16117c478bd9Sstevel@tonic-gate 	    unsigned *outputlen)
16127c478bd9Sstevel@tonic-gate {
16137c478bd9Sstevel@tonic-gate     CK_RV		rv;
16147c478bd9Sstevel@tonic-gate     uef_context_t	*enc_context =
16157c478bd9Sstevel@tonic-gate 		(uef_context_t *)text->cipher_enc_context;
16167c478bd9Sstevel@tonic-gate     CK_ULONG		ulDataLen;
16177c478bd9Sstevel@tonic-gate     int paddinglen;
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate     /* determine padding length */
16207c478bd9Sstevel@tonic-gate     paddinglen = 8 - ((inputlen + MAC_SIZE) % 8);
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate     /* now construct the full stuff to be ciphered */
16237c478bd9Sstevel@tonic-gate     memcpy(output, input, inputlen);                /* text */
16247c478bd9Sstevel@tonic-gate     memset(output+inputlen, paddinglen, paddinglen);/* pad  */
16257c478bd9Sstevel@tonic-gate     memcpy(output+inputlen+paddinglen, digest, MAC_SIZE); /* hmac */
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate     ulDataLen=inputlen+paddinglen+MAC_SIZE;
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate     rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)output, ulDataLen,
16307c478bd9Sstevel@tonic-gate 	(CK_BYTE_PTR)output, &ulDataLen);
16317c478bd9Sstevel@tonic-gate     if (rv != CKR_OK) {
16327c478bd9Sstevel@tonic-gate #ifdef DEBUG
16337c478bd9Sstevel@tonic-gate 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
16347c478bd9Sstevel@tonic-gate 			 "C_EncryptUpdate failed: 0x%.8X "
16357c478bd9Sstevel@tonic-gate 			 "inputlen:%d outputlen:%d\n",
16367c478bd9Sstevel@tonic-gate 			 rv, ulDataLen, ulDataLen);
16377c478bd9Sstevel@tonic-gate #endif
16387c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
16397c478bd9Sstevel@tonic-gate     }
16407c478bd9Sstevel@tonic-gate     *outputlen = (unsigned)ulDataLen;
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate     return SASL_OK;
16437c478bd9Sstevel@tonic-gate }
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate struct digest_cipher uef_ciphers[] =
16467c478bd9Sstevel@tonic-gate {
16477c478bd9Sstevel@tonic-gate     { "rc4-40", 40, 5, 0x01, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
16487c478bd9Sstevel@tonic-gate 	&free_uef },
16497c478bd9Sstevel@tonic-gate     { "rc4-56", 56, 7, 0x02, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
16507c478bd9Sstevel@tonic-gate 	&free_uef },
16517c478bd9Sstevel@tonic-gate     { "rc4", 128, 16, 0x04, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
16527c478bd9Sstevel@tonic-gate 	&free_uef },
16537c478bd9Sstevel@tonic-gate     { "des", 55, 16, 0x08, &enc_des_uef, &dec_des_uef, &init_des_uef,
16547c478bd9Sstevel@tonic-gate 	&free_uef },
16557c478bd9Sstevel@tonic-gate     { "3des", 112, 16, 0x10, &enc_des_uef, &dec_des_uef, &init_3des_uef,
16567c478bd9Sstevel@tonic-gate 	&free_uef },
16577c478bd9Sstevel@tonic-gate     { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
16587c478bd9Sstevel@tonic-gate };
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate struct digest_cipher *available_ciphers1 = uef_ciphers;
16617c478bd9Sstevel@tonic-gate #endif /* USE_UEF */
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate static int create_layer_keys(context_t *text,
16647c478bd9Sstevel@tonic-gate 			     const sasl_utils_t *utils,
16657c478bd9Sstevel@tonic-gate 			     HASH key, int keylen,
16667c478bd9Sstevel@tonic-gate 			     char enckey[16], char deckey[16])
16677c478bd9Sstevel@tonic-gate {
16687c478bd9Sstevel@tonic-gate     MD5_CTX Md5Ctx;
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate     utils->MD5Init(&Md5Ctx);
16717c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, key, keylen);
16727c478bd9Sstevel@tonic-gate     if (text->i_am == SERVER) {
16737c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_SERVER_CLIENT,
16747c478bd9Sstevel@tonic-gate 			 strlen(SEALING_SERVER_CLIENT));
16757c478bd9Sstevel@tonic-gate     } else {
16767c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_CLIENT_SERVER,
16777c478bd9Sstevel@tonic-gate 			 strlen(SEALING_CLIENT_SERVER));
16787c478bd9Sstevel@tonic-gate     }
16797c478bd9Sstevel@tonic-gate     utils->MD5Final((unsigned char *) enckey, &Md5Ctx);
16807c478bd9Sstevel@tonic-gate 
16817c478bd9Sstevel@tonic-gate     utils->MD5Init(&Md5Ctx);
16827c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, key, keylen);
16837c478bd9Sstevel@tonic-gate     if (text->i_am != SERVER) {
16847c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, (const unsigned char *)SEALING_SERVER_CLIENT,
16857c478bd9Sstevel@tonic-gate 			 strlen(SEALING_SERVER_CLIENT));
16867c478bd9Sstevel@tonic-gate     } else {
16877c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, (const unsigned char *)SEALING_CLIENT_SERVER,
16887c478bd9Sstevel@tonic-gate 			 strlen(SEALING_CLIENT_SERVER));
16897c478bd9Sstevel@tonic-gate     }
16907c478bd9Sstevel@tonic-gate     utils->MD5Final((unsigned char *) deckey, &Md5Ctx);
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate     /* create integrity keys */
16937c478bd9Sstevel@tonic-gate     /* sending */
16947c478bd9Sstevel@tonic-gate     utils->MD5Init(&Md5Ctx);
16957c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
16967c478bd9Sstevel@tonic-gate     if (text->i_am == SERVER) {
16977c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT,
16987c478bd9Sstevel@tonic-gate 			 strlen(SIGNING_SERVER_CLIENT));
16997c478bd9Sstevel@tonic-gate     } else {
17007c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
17017c478bd9Sstevel@tonic-gate 			 strlen(SIGNING_CLIENT_SERVER));
17027c478bd9Sstevel@tonic-gate     }
17037c478bd9Sstevel@tonic-gate     utils->MD5Final(text->Ki_send, &Md5Ctx);
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate     /* receiving */
17067c478bd9Sstevel@tonic-gate     utils->MD5Init(&Md5Ctx);
17077c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
17087c478bd9Sstevel@tonic-gate     if (text->i_am != SERVER) {
17097c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT,
17107c478bd9Sstevel@tonic-gate 			 strlen(SIGNING_SERVER_CLIENT));
17117c478bd9Sstevel@tonic-gate     } else {
17127c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
17137c478bd9Sstevel@tonic-gate 			 strlen(SIGNING_CLIENT_SERVER));
17147c478bd9Sstevel@tonic-gate     }
17157c478bd9Sstevel@tonic-gate     utils->MD5Final(text->Ki_receive, &Md5Ctx);
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate     return SASL_OK;
17187c478bd9Sstevel@tonic-gate }
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate static const unsigned short version = 1;
17217c478bd9Sstevel@tonic-gate 
17227c478bd9Sstevel@tonic-gate /* len, CIPHER(Kc, {msg, pag, HMAC(ki, {SeqNum, msg})[0..9]}), x0001, SeqNum */
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate static int
17257c478bd9Sstevel@tonic-gate digestmd5_privacy_encode(void *context,
17267c478bd9Sstevel@tonic-gate 			 const struct iovec *invec,
17277c478bd9Sstevel@tonic-gate 			 unsigned numiov,
17287c478bd9Sstevel@tonic-gate 			 const char **output,
17297c478bd9Sstevel@tonic-gate 			 unsigned *outputlen)
17307c478bd9Sstevel@tonic-gate {
17317c478bd9Sstevel@tonic-gate     context_t *text = (context_t *) context;
17327c478bd9Sstevel@tonic-gate     int tmp;
17337c478bd9Sstevel@tonic-gate     unsigned int tmpnum;
17347c478bd9Sstevel@tonic-gate     unsigned short int tmpshort;
17357c478bd9Sstevel@tonic-gate     int ret;
17367c478bd9Sstevel@tonic-gate     char *out;
17377c478bd9Sstevel@tonic-gate     unsigned char digest[16];
17387c478bd9Sstevel@tonic-gate     struct buffer_info *inblob, bufinfo;
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate     if(!context || !invec || !numiov || !output || !outputlen) {
17417c478bd9Sstevel@tonic-gate 	PARAMERROR(text->utils);
17427c478bd9Sstevel@tonic-gate 	return SASL_BADPARAM;
17437c478bd9Sstevel@tonic-gate     }
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate     if (numiov > 1) {
17467c478bd9Sstevel@tonic-gate 	ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
17477c478bd9Sstevel@tonic-gate 	if (ret != SASL_OK) return ret;
17487c478bd9Sstevel@tonic-gate 	inblob = text->enc_in_buf;
17497c478bd9Sstevel@tonic-gate     } else {
17507c478bd9Sstevel@tonic-gate 	/* avoid the data copy */
17517c478bd9Sstevel@tonic-gate 	bufinfo.data = invec[0].iov_base;
17527c478bd9Sstevel@tonic-gate 	bufinfo.curlen = invec[0].iov_len;
17537c478bd9Sstevel@tonic-gate 	inblob = &bufinfo;
17547c478bd9Sstevel@tonic-gate     }
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate     /* make sure the output buffer is big enough for this blob */
17577c478bd9Sstevel@tonic-gate     ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
17587c478bd9Sstevel@tonic-gate 			  &(text->encode_buf_len),
17597c478bd9Sstevel@tonic-gate 			  (4 +                        /* for length */
17607c478bd9Sstevel@tonic-gate 			   inblob->curlen + /* for content */
17617c478bd9Sstevel@tonic-gate 			   10 +                       /* for MAC */
17627c478bd9Sstevel@tonic-gate 			   8 +                        /* maximum pad */
17637c478bd9Sstevel@tonic-gate 			   6 +                        /* for padding */
17647c478bd9Sstevel@tonic-gate 			   1));                       /* trailing null */
17657c478bd9Sstevel@tonic-gate     if(ret != SASL_OK) return ret;
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate     /* skip by the length for now */
17687c478bd9Sstevel@tonic-gate     out = (text->encode_buf)+4;
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate     /* construct (seqnum, msg) */
17717c478bd9Sstevel@tonic-gate     /* We can just use the output buffer because it's big enough */
17727c478bd9Sstevel@tonic-gate     tmpnum = htonl(text->seqnum);
17737c478bd9Sstevel@tonic-gate     memcpy(text->encode_buf, &tmpnum, 4);
17747c478bd9Sstevel@tonic-gate     memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate     /* HMAC(ki, (seqnum, msg) ) */
17777c478bd9Sstevel@tonic-gate     text->utils->hmac_md5((const unsigned char *) text->encode_buf,
17787c478bd9Sstevel@tonic-gate 			  inblob->curlen + 4,
17797c478bd9Sstevel@tonic-gate 			  text->Ki_send, HASHLEN, digest);
17807c478bd9Sstevel@tonic-gate 
17817c478bd9Sstevel@tonic-gate     /* calculate the encrypted part */
17827c478bd9Sstevel@tonic-gate     text->cipher_enc(text, inblob->data, inblob->curlen,
17837c478bd9Sstevel@tonic-gate 		     digest, out, outputlen);
17847c478bd9Sstevel@tonic-gate     out+=(*outputlen);
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate     /* copy in version */
17877c478bd9Sstevel@tonic-gate     tmpshort = htons(version);
17887c478bd9Sstevel@tonic-gate     memcpy(out, &tmpshort, 2);	/* 2 bytes = version */
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate     out+=2;
17917c478bd9Sstevel@tonic-gate     (*outputlen)+=2; /* for version */
17927c478bd9Sstevel@tonic-gate 
17937c478bd9Sstevel@tonic-gate     /* put in seqnum */
17947c478bd9Sstevel@tonic-gate     tmpnum = htonl(text->seqnum);
17957c478bd9Sstevel@tonic-gate     memcpy(out, &tmpnum, 4);	/* 4 bytes = seq # */
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate     (*outputlen)+=4; /* for seqnum */
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate     /* put the 1st 4 bytes in */
18007c478bd9Sstevel@tonic-gate     tmp=htonl(*outputlen);
18017c478bd9Sstevel@tonic-gate     memcpy(text->encode_buf, &tmp, 4);
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate     (*outputlen)+=4;
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate     *output = text->encode_buf;
18067c478bd9Sstevel@tonic-gate     text->seqnum++;
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate     return SASL_OK;
18097c478bd9Sstevel@tonic-gate }
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate static int
18127c478bd9Sstevel@tonic-gate digestmd5_privacy_decode_once(void *context,
18137c478bd9Sstevel@tonic-gate 			      const char **input,
18147c478bd9Sstevel@tonic-gate 			      unsigned *inputlen,
18157c478bd9Sstevel@tonic-gate 			      char **output,
18167c478bd9Sstevel@tonic-gate 			      unsigned *outputlen)
18177c478bd9Sstevel@tonic-gate {
18187c478bd9Sstevel@tonic-gate     context_t *text = (context_t *) context;
18197c478bd9Sstevel@tonic-gate     unsigned int tocopy;
18207c478bd9Sstevel@tonic-gate     unsigned diff;
18217c478bd9Sstevel@tonic-gate     int result;
18227c478bd9Sstevel@tonic-gate     unsigned char digest[16];
18237c478bd9Sstevel@tonic-gate     int tmpnum;
18247c478bd9Sstevel@tonic-gate     int lup;
18257c478bd9Sstevel@tonic-gate 
18267c478bd9Sstevel@tonic-gate     if (text->needsize>0) /* 4 bytes for how long message is */
18277c478bd9Sstevel@tonic-gate 	{
18287c478bd9Sstevel@tonic-gate 	    /* if less than 4 bytes just copy those we have into text->size */
18297c478bd9Sstevel@tonic-gate 	    if (*inputlen<4)
18307c478bd9Sstevel@tonic-gate 		tocopy=*inputlen;
18317c478bd9Sstevel@tonic-gate 	    else
18327c478bd9Sstevel@tonic-gate 		tocopy=4;
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate 	    if (tocopy>text->needsize)
18357c478bd9Sstevel@tonic-gate 		tocopy=text->needsize;
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 	    memcpy(text->sizebuf+4-text->needsize, *input, tocopy);
18387c478bd9Sstevel@tonic-gate 	    text->needsize-=tocopy;
18397c478bd9Sstevel@tonic-gate 
18407c478bd9Sstevel@tonic-gate 	    *input+=tocopy;
18417c478bd9Sstevel@tonic-gate 	    *inputlen-=tocopy;
18427c478bd9Sstevel@tonic-gate 
18437c478bd9Sstevel@tonic-gate 	    if (text->needsize==0) /* got all of size */
18447c478bd9Sstevel@tonic-gate 	    {
18457c478bd9Sstevel@tonic-gate 		memcpy(&(text->size), text->sizebuf, 4);
18467c478bd9Sstevel@tonic-gate 		text->cursize=0;
18477c478bd9Sstevel@tonic-gate 		text->size=ntohl(text->size);
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate 		if (text->size > text->in_maxbuf) {
18507c478bd9Sstevel@tonic-gate 		    return SASL_FAIL; /* too big probably error */
18517c478bd9Sstevel@tonic-gate 		}
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 		if(!text->buffer)
18547c478bd9Sstevel@tonic-gate 		    text->buffer=text->utils->malloc(text->size+5);
18557c478bd9Sstevel@tonic-gate 		else
18567c478bd9Sstevel@tonic-gate 		    text->buffer=text->utils->realloc(text->buffer,
18577c478bd9Sstevel@tonic-gate 						      text->size+5);
18587c478bd9Sstevel@tonic-gate 		if (text->buffer == NULL) return SASL_NOMEM;
18597c478bd9Sstevel@tonic-gate 	    }
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	    *outputlen=0;
18627c478bd9Sstevel@tonic-gate 	    *output=NULL;
18637c478bd9Sstevel@tonic-gate 	    if (*inputlen==0) /* have to wait until next time for data */
18647c478bd9Sstevel@tonic-gate 		return SASL_OK;
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate 	    if (text->size==0)  /* should never happen */
18677c478bd9Sstevel@tonic-gate 		return SASL_FAIL;
18687c478bd9Sstevel@tonic-gate 	}
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate     diff=text->size - text->cursize; /* bytes need for full message */
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate     if (! text->buffer)
18737c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate     if (*inputlen < diff) /* not enough for a decode */
18767c478bd9Sstevel@tonic-gate     {
18777c478bd9Sstevel@tonic-gate 	memcpy(text->buffer+text->cursize, *input, *inputlen);
18787c478bd9Sstevel@tonic-gate 	text->cursize+=*inputlen;
18797c478bd9Sstevel@tonic-gate 	*inputlen=0;
18807c478bd9Sstevel@tonic-gate 	*outputlen=0;
18817c478bd9Sstevel@tonic-gate 	*output=NULL;
18827c478bd9Sstevel@tonic-gate 	return SASL_OK;
18837c478bd9Sstevel@tonic-gate     } else {
18847c478bd9Sstevel@tonic-gate 	memcpy(text->buffer+text->cursize, *input, diff);
18857c478bd9Sstevel@tonic-gate 	*input+=diff;
18867c478bd9Sstevel@tonic-gate 	*inputlen-=diff;
18877c478bd9Sstevel@tonic-gate     }
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate     {
18907c478bd9Sstevel@tonic-gate 	unsigned short ver;
18917c478bd9Sstevel@tonic-gate 	unsigned int seqnum;
18927c478bd9Sstevel@tonic-gate 	unsigned char checkdigest[16];
18937c478bd9Sstevel@tonic-gate 
18947c478bd9Sstevel@tonic-gate 	result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
18957c478bd9Sstevel@tonic-gate 				 &text->decode_once_buf_len,
18967c478bd9Sstevel@tonic-gate 				 text->size-6);
18977c478bd9Sstevel@tonic-gate 	if (result != SASL_OK)
18987c478bd9Sstevel@tonic-gate 	    return result;
18997c478bd9Sstevel@tonic-gate 
19007c478bd9Sstevel@tonic-gate 	*output = text->decode_once_buf;
19017c478bd9Sstevel@tonic-gate 	*outputlen = *inputlen;
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate 	result=text->cipher_dec(text,text->buffer,text->size-6,digest,
19047c478bd9Sstevel@tonic-gate 				*output, outputlen);
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 	if (result!=SASL_OK)
19077c478bd9Sstevel@tonic-gate 	    return result;
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 	{
19107c478bd9Sstevel@tonic-gate 	    int i;
19117c478bd9Sstevel@tonic-gate 	    for(i=10; i; i--) {
19127c478bd9Sstevel@tonic-gate 		memcpy(&ver, text->buffer+text->size-i,2);
19137c478bd9Sstevel@tonic-gate 		ver=ntohs(ver);
19147c478bd9Sstevel@tonic-gate 	    }
19157c478bd9Sstevel@tonic-gate 	}
19167c478bd9Sstevel@tonic-gate 
19177c478bd9Sstevel@tonic-gate 	/* check the version number */
19187c478bd9Sstevel@tonic-gate 	memcpy(&ver, text->buffer+text->size-6, 2);
19197c478bd9Sstevel@tonic-gate 	ver=ntohs(ver);
19207c478bd9Sstevel@tonic-gate 	if (ver != version)
19217c478bd9Sstevel@tonic-gate 	{
19227c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
19237c478bd9Sstevel@tonic-gate 	    text->utils->seterror(text->utils->conn, 0,
19247c478bd9Sstevel@tonic-gate 		gettext("Wrong Version"));
19257c478bd9Sstevel@tonic-gate #else
19267c478bd9Sstevel@tonic-gate 	    text->utils->seterror(text->utils->conn, 0, "Wrong Version");
19277c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
19287c478bd9Sstevel@tonic-gate 	    return SASL_FAIL;
19297c478bd9Sstevel@tonic-gate 	}
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate 	/* check the CMAC */
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 	/* construct (seqnum, msg) */
19347c478bd9Sstevel@tonic-gate 	result = _plug_buf_alloc(text->utils, &text->decode_tmp_buf,
19357c478bd9Sstevel@tonic-gate 				 &text->decode_tmp_buf_len, *outputlen + 4);
19367c478bd9Sstevel@tonic-gate 	if(result != SASL_OK) return result;
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate 	tmpnum = htonl(text->rec_seqnum);
19397c478bd9Sstevel@tonic-gate 	memcpy(text->decode_tmp_buf, &tmpnum, 4);
19407c478bd9Sstevel@tonic-gate 	memcpy(text->decode_tmp_buf + 4, *output, *outputlen);
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 	/* HMAC(ki, (seqnum, msg) ) */
19437c478bd9Sstevel@tonic-gate 	text->utils->hmac_md5((const unsigned char *) text->decode_tmp_buf,
19447c478bd9Sstevel@tonic-gate 			      (*outputlen) + 4,
19457c478bd9Sstevel@tonic-gate 			      text->Ki_receive, HASHLEN, checkdigest);
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 	/* now check it */
19487c478bd9Sstevel@tonic-gate 	for (lup=0;lup<10;lup++)
19497c478bd9Sstevel@tonic-gate 	    if (checkdigest[lup]!=digest[lup])
19507c478bd9Sstevel@tonic-gate 		{
19517c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
19527c478bd9Sstevel@tonic-gate 		    text->utils->log(text->utils->conn, SASL_LOG_ERR,
19537c478bd9Sstevel@tonic-gate 			"CMAC doesn't match at byte %d!", lup);
19547c478bd9Sstevel@tonic-gate 		    return SASL_BADMAC;
19557c478bd9Sstevel@tonic-gate #else
19567c478bd9Sstevel@tonic-gate 		    text->utils->seterror(text->utils->conn, 0,
19577c478bd9Sstevel@tonic-gate 					  "CMAC doesn't match at byte %d!", lup);
19587c478bd9Sstevel@tonic-gate 		    return SASL_FAIL;
19597c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
19607c478bd9Sstevel@tonic-gate 		}
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 	/* check the sequence number */
19637c478bd9Sstevel@tonic-gate 	memcpy(&seqnum, text->buffer+text->size-4,4);
19647c478bd9Sstevel@tonic-gate 	seqnum=ntohl(seqnum);
19657c478bd9Sstevel@tonic-gate 
19667c478bd9Sstevel@tonic-gate 	if (seqnum!=text->rec_seqnum)
19677c478bd9Sstevel@tonic-gate 	    {
19687c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
19697c478bd9Sstevel@tonic-gate 		text->utils->log(text->utils->conn, SASL_LOG_ERR,
19707c478bd9Sstevel@tonic-gate 				 "Incorrect Sequence Number");
19717c478bd9Sstevel@tonic-gate #else
19727c478bd9Sstevel@tonic-gate 		text->utils->seterror(text->utils->conn, 0,
19737c478bd9Sstevel@tonic-gate 				      "Incorrect Sequence Number");
19747c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
19757c478bd9Sstevel@tonic-gate 		return SASL_FAIL;
19767c478bd9Sstevel@tonic-gate 	    }
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate 	text->rec_seqnum++; /* now increment it */
19797c478bd9Sstevel@tonic-gate     }
19807c478bd9Sstevel@tonic-gate 
19817c478bd9Sstevel@tonic-gate     text->needsize=4;
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate     return SASL_OK;
19847c478bd9Sstevel@tonic-gate }
19857c478bd9Sstevel@tonic-gate 
19867c478bd9Sstevel@tonic-gate static int digestmd5_privacy_decode(void *context,
19877c478bd9Sstevel@tonic-gate 				    const char *input, unsigned inputlen,
19887c478bd9Sstevel@tonic-gate 				    const char **output, unsigned *outputlen)
19897c478bd9Sstevel@tonic-gate {
19907c478bd9Sstevel@tonic-gate     context_t *text = (context_t *) context;
19917c478bd9Sstevel@tonic-gate     int ret;
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate     ret = _plug_decode(text->utils, context, input, inputlen,
19947c478bd9Sstevel@tonic-gate 		       &text->decode_buf, &text->decode_buf_len, outputlen,
19957c478bd9Sstevel@tonic-gate 		       digestmd5_privacy_decode_once);
19967c478bd9Sstevel@tonic-gate 
19977c478bd9Sstevel@tonic-gate     *output = text->decode_buf;
19987c478bd9Sstevel@tonic-gate 
19997c478bd9Sstevel@tonic-gate     return ret;
20007c478bd9Sstevel@tonic-gate }
20017c478bd9Sstevel@tonic-gate 
20027c478bd9Sstevel@tonic-gate static int
20037c478bd9Sstevel@tonic-gate digestmd5_integrity_encode(void *context,
20047c478bd9Sstevel@tonic-gate 			   const struct iovec *invec,
20057c478bd9Sstevel@tonic-gate 			   unsigned numiov,
20067c478bd9Sstevel@tonic-gate 			   const char **output,
20077c478bd9Sstevel@tonic-gate 			   unsigned *outputlen)
20087c478bd9Sstevel@tonic-gate {
20097c478bd9Sstevel@tonic-gate     context_t      *text = (context_t *) context;
20107c478bd9Sstevel@tonic-gate     unsigned char   MAC[16];
20117c478bd9Sstevel@tonic-gate     unsigned int    tmpnum;
20127c478bd9Sstevel@tonic-gate     unsigned short int tmpshort;
20137c478bd9Sstevel@tonic-gate     struct buffer_info *inblob, bufinfo;
20147c478bd9Sstevel@tonic-gate     int ret;
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate     if(!context || !invec || !numiov || !output || !outputlen) {
20177c478bd9Sstevel@tonic-gate 	PARAMERROR( text->utils );
20187c478bd9Sstevel@tonic-gate 	return SASL_BADPARAM;
20197c478bd9Sstevel@tonic-gate     }
20207c478bd9Sstevel@tonic-gate 
20217c478bd9Sstevel@tonic-gate     if (numiov > 1) {
20227c478bd9Sstevel@tonic-gate 	ret = _plug_iovec_to_buf(text->utils, invec, numiov,
20237c478bd9Sstevel@tonic-gate 				 &text->enc_in_buf);
20247c478bd9Sstevel@tonic-gate 	if (ret != SASL_OK) return ret;
20257c478bd9Sstevel@tonic-gate 	inblob = text->enc_in_buf;
20267c478bd9Sstevel@tonic-gate     } else {
20277c478bd9Sstevel@tonic-gate 	/* avoid the data copy */
20287c478bd9Sstevel@tonic-gate 	bufinfo.data = invec[0].iov_base;
20297c478bd9Sstevel@tonic-gate 	bufinfo.curlen = invec[0].iov_len;
20307c478bd9Sstevel@tonic-gate 	inblob = &bufinfo;
20317c478bd9Sstevel@tonic-gate     }
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate     /* construct output */
20347c478bd9Sstevel@tonic-gate     *outputlen = 4 + inblob->curlen + 16;
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate     ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
20377c478bd9Sstevel@tonic-gate 			  &(text->encode_buf_len), *outputlen);
20387c478bd9Sstevel@tonic-gate     if(ret != SASL_OK) return ret;
20397c478bd9Sstevel@tonic-gate 
20407c478bd9Sstevel@tonic-gate     /* construct (seqnum, msg) */
20417c478bd9Sstevel@tonic-gate     /* we can just use the output buffer */
20427c478bd9Sstevel@tonic-gate     tmpnum = htonl(text->seqnum);
20437c478bd9Sstevel@tonic-gate     memcpy(text->encode_buf, &tmpnum, 4);
20447c478bd9Sstevel@tonic-gate     memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
20457c478bd9Sstevel@tonic-gate 
20467c478bd9Sstevel@tonic-gate     /* HMAC(ki, (seqnum, msg) ) */
20477c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
20487c478bd9Sstevel@tonic-gate     text->utils->hmac_md5((unsigned char *)text->encode_buf,
20497c478bd9Sstevel@tonic-gate 			  inblob->curlen + 4,
20507c478bd9Sstevel@tonic-gate 			  text->Ki_send, HASHLEN, MAC);
20517c478bd9Sstevel@tonic-gate #else
20527c478bd9Sstevel@tonic-gate     text->utils->hmac_md5(text->encode_buf, inblob->curlen + 4,
20537c478bd9Sstevel@tonic-gate 			  text->Ki_send, HASHLEN, MAC);
20547c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate     /* create MAC */
20577c478bd9Sstevel@tonic-gate     tmpshort = htons(version);
20587c478bd9Sstevel@tonic-gate     memcpy(MAC + 10, &tmpshort, MAC_OFFS);	/* 2 bytes = version */
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate     tmpnum = htonl(text->seqnum);
20617c478bd9Sstevel@tonic-gate     memcpy(MAC + 12, &tmpnum, 4);	/* 4 bytes = sequence number */
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate     /* copy into output */
20647c478bd9Sstevel@tonic-gate     tmpnum = htonl((*outputlen) - 4);
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate     /* length of message in network byte order */
20677c478bd9Sstevel@tonic-gate     memcpy(text->encode_buf, &tmpnum, 4);
20687c478bd9Sstevel@tonic-gate     /* the message text */
20697c478bd9Sstevel@tonic-gate     memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
20707c478bd9Sstevel@tonic-gate     /* the MAC */
20717c478bd9Sstevel@tonic-gate     memcpy(text->encode_buf + 4 + inblob->curlen, MAC, 16);
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate     text->seqnum++;		/* add one to sequence number */
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate     *output = text->encode_buf;
20767c478bd9Sstevel@tonic-gate 
20777c478bd9Sstevel@tonic-gate     return SASL_OK;
20787c478bd9Sstevel@tonic-gate }
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate static int
20817c478bd9Sstevel@tonic-gate create_MAC(context_t * text,
20827c478bd9Sstevel@tonic-gate 	   char *input,
20837c478bd9Sstevel@tonic-gate 	   int inputlen,
20847c478bd9Sstevel@tonic-gate 	   int seqnum,
20857c478bd9Sstevel@tonic-gate 	   unsigned char MAC[16])
20867c478bd9Sstevel@tonic-gate {
20877c478bd9Sstevel@tonic-gate     unsigned int    tmpnum;
20887c478bd9Sstevel@tonic-gate     unsigned short int tmpshort;
20897c478bd9Sstevel@tonic-gate     int ret;
20907c478bd9Sstevel@tonic-gate 
20917c478bd9Sstevel@tonic-gate     if (inputlen < 0)
20927c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
20937c478bd9Sstevel@tonic-gate 
20947c478bd9Sstevel@tonic-gate     ret = _plug_buf_alloc(text->utils, &(text->MAC_buf),
20957c478bd9Sstevel@tonic-gate 			  &(text->MAC_buf_len), inputlen + 4);
20967c478bd9Sstevel@tonic-gate     if(ret != SASL_OK) return ret;
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate     /* construct (seqnum, msg) */
20997c478bd9Sstevel@tonic-gate     tmpnum = htonl(seqnum);
21007c478bd9Sstevel@tonic-gate     memcpy(text->MAC_buf, &tmpnum, 4);
21017c478bd9Sstevel@tonic-gate     memcpy(text->MAC_buf + 4, input, inputlen);
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate     /* HMAC(ki, (seqnum, msg) ) */
21047c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
21057c478bd9Sstevel@tonic-gate     text->utils->hmac_md5((unsigned char *)text->MAC_buf, inputlen + 4,
21067c478bd9Sstevel@tonic-gate 			  text->Ki_receive, HASHLEN,
21077c478bd9Sstevel@tonic-gate 			  MAC);
21087c478bd9Sstevel@tonic-gate #else
21097c478bd9Sstevel@tonic-gate     text->utils->hmac_md5(text->MAC_buf, inputlen + 4,
21107c478bd9Sstevel@tonic-gate 			  text->Ki_receive, HASHLEN,
21117c478bd9Sstevel@tonic-gate 			  MAC);
21127c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate     /* create MAC */
21157c478bd9Sstevel@tonic-gate     tmpshort = htons(version);
21167c478bd9Sstevel@tonic-gate     memcpy(MAC + 10, &tmpshort, 2);	/* 2 bytes = version */
21177c478bd9Sstevel@tonic-gate 
21187c478bd9Sstevel@tonic-gate     tmpnum = htonl(seqnum);
21197c478bd9Sstevel@tonic-gate     memcpy(MAC + 12, &tmpnum, 4);	/* 4 bytes = sequence number */
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate     return SASL_OK;
21227c478bd9Sstevel@tonic-gate }
21237c478bd9Sstevel@tonic-gate 
21247c478bd9Sstevel@tonic-gate static int
21257c478bd9Sstevel@tonic-gate check_integrity(context_t * text,
21267c478bd9Sstevel@tonic-gate 		char *buf, int bufsize,
21277c478bd9Sstevel@tonic-gate 		char **output, unsigned *outputlen)
21287c478bd9Sstevel@tonic-gate {
21297c478bd9Sstevel@tonic-gate     unsigned char MAC[16];
21307c478bd9Sstevel@tonic-gate     int result;
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate     result = create_MAC(text, buf, bufsize - 16, text->rec_seqnum, MAC);
21337c478bd9Sstevel@tonic-gate     if (result != SASL_OK)
21347c478bd9Sstevel@tonic-gate 	return result;
21357c478bd9Sstevel@tonic-gate 
21367c478bd9Sstevel@tonic-gate     /* make sure the MAC is right */
21377c478bd9Sstevel@tonic-gate     if (strncmp((char *) MAC, buf + bufsize - 16, 16) != 0)
21387c478bd9Sstevel@tonic-gate     {
21397c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
21407c478bd9Sstevel@tonic-gate 	text->utils->log(text->utils->conn, SASL_LOG_ERR,
21417c478bd9Sstevel@tonic-gate 			 "MAC doesn't match");
21427c478bd9Sstevel@tonic-gate 	return SASL_BADMAC;
21437c478bd9Sstevel@tonic-gate #else
21447c478bd9Sstevel@tonic-gate 	text->utils->seterror(text->utils->conn, 0, "MAC doesn't match");
21457c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
21467c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
21477c478bd9Sstevel@tonic-gate     }
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate     text->rec_seqnum++;
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate     /* ok make output message */
21527c478bd9Sstevel@tonic-gate     result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
21537c478bd9Sstevel@tonic-gate 			     &text->decode_once_buf_len,
21547c478bd9Sstevel@tonic-gate 			     bufsize - 15);
21557c478bd9Sstevel@tonic-gate     if (result != SASL_OK)
21567c478bd9Sstevel@tonic-gate 	return result;
21577c478bd9Sstevel@tonic-gate 
21587c478bd9Sstevel@tonic-gate     *output = text->decode_once_buf;
21597c478bd9Sstevel@tonic-gate     memcpy(*output, buf, bufsize - 16);
21607c478bd9Sstevel@tonic-gate     *outputlen = bufsize - 16;
21617c478bd9Sstevel@tonic-gate     (*output)[*outputlen] = 0;
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate     return SASL_OK;
21647c478bd9Sstevel@tonic-gate }
21657c478bd9Sstevel@tonic-gate 
21667c478bd9Sstevel@tonic-gate static int
21677c478bd9Sstevel@tonic-gate digestmd5_integrity_decode_once(void *context,
21687c478bd9Sstevel@tonic-gate 				const char **input,
21697c478bd9Sstevel@tonic-gate 				unsigned *inputlen,
21707c478bd9Sstevel@tonic-gate 				char **output,
21717c478bd9Sstevel@tonic-gate 				unsigned *outputlen)
21727c478bd9Sstevel@tonic-gate {
21737c478bd9Sstevel@tonic-gate     context_t      *text = (context_t *) context;
21747c478bd9Sstevel@tonic-gate     unsigned int    tocopy;
21757c478bd9Sstevel@tonic-gate     unsigned        diff;
21767c478bd9Sstevel@tonic-gate     int             result;
21777c478bd9Sstevel@tonic-gate 
21787c478bd9Sstevel@tonic-gate     if (text->needsize > 0) {	/* 4 bytes for how long message is */
21797c478bd9Sstevel@tonic-gate 	/*
21807c478bd9Sstevel@tonic-gate 	 * if less than 4 bytes just copy those we have into text->size
21817c478bd9Sstevel@tonic-gate 	 */
21827c478bd9Sstevel@tonic-gate 	if (*inputlen < 4)
21837c478bd9Sstevel@tonic-gate 	    tocopy = *inputlen;
21847c478bd9Sstevel@tonic-gate 	else
21857c478bd9Sstevel@tonic-gate 	    tocopy = 4;
21867c478bd9Sstevel@tonic-gate 
21877c478bd9Sstevel@tonic-gate 	if (tocopy > text->needsize)
21887c478bd9Sstevel@tonic-gate 	    tocopy = text->needsize;
21897c478bd9Sstevel@tonic-gate 
21907c478bd9Sstevel@tonic-gate 	memcpy(text->sizebuf + 4 - text->needsize, *input, tocopy);
21917c478bd9Sstevel@tonic-gate 	text->needsize -= tocopy;
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate 	*input += tocopy;
21947c478bd9Sstevel@tonic-gate 	*inputlen -= tocopy;
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate 	if (text->needsize == 0) {	/* got all of size */
21977c478bd9Sstevel@tonic-gate 	    memcpy(&(text->size), text->sizebuf, 4);
21987c478bd9Sstevel@tonic-gate 	    text->cursize = 0;
21997c478bd9Sstevel@tonic-gate 	    text->size = ntohl(text->size);
22007c478bd9Sstevel@tonic-gate 
22017c478bd9Sstevel@tonic-gate 	    if (text->size > text->in_maxbuf)
22027c478bd9Sstevel@tonic-gate 		return SASL_FAIL;	/* too big probably error */
22037c478bd9Sstevel@tonic-gate 
22047c478bd9Sstevel@tonic-gate 	    if(!text->buffer)
22057c478bd9Sstevel@tonic-gate 		text->buffer=text->utils->malloc(text->size+5);
22067c478bd9Sstevel@tonic-gate 	    else
22077c478bd9Sstevel@tonic-gate 		text->buffer=text->utils->realloc(text->buffer,text->size+5);
22087c478bd9Sstevel@tonic-gate 	    if (text->buffer == NULL) return SASL_NOMEM;
22097c478bd9Sstevel@tonic-gate 	}
22107c478bd9Sstevel@tonic-gate 	*outputlen = 0;
22117c478bd9Sstevel@tonic-gate 	*output = NULL;
22127c478bd9Sstevel@tonic-gate 	if (*inputlen == 0)		/* have to wait until next time for data */
22137c478bd9Sstevel@tonic-gate 	    return SASL_OK;
22147c478bd9Sstevel@tonic-gate 
22157c478bd9Sstevel@tonic-gate 	if (text->size == 0)	/* should never happen */
22167c478bd9Sstevel@tonic-gate 	    return SASL_FAIL;
22177c478bd9Sstevel@tonic-gate     }
22187c478bd9Sstevel@tonic-gate     diff = text->size - text->cursize;	/* bytes need for full message */
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate     if(! text->buffer)
22217c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate     if (*inputlen < diff) {	/* not enough for a decode */
22247c478bd9Sstevel@tonic-gate 	memcpy(text->buffer + text->cursize, *input, *inputlen);
22257c478bd9Sstevel@tonic-gate 	text->cursize += *inputlen;
22267c478bd9Sstevel@tonic-gate 	*inputlen = 0;
22277c478bd9Sstevel@tonic-gate 	*outputlen = 0;
22287c478bd9Sstevel@tonic-gate 	*output = NULL;
22297c478bd9Sstevel@tonic-gate 	return SASL_OK;
22307c478bd9Sstevel@tonic-gate     } else {
22317c478bd9Sstevel@tonic-gate 	memcpy(text->buffer + text->cursize, *input, diff);
22327c478bd9Sstevel@tonic-gate 	*input += diff;
22337c478bd9Sstevel@tonic-gate 	*inputlen -= diff;
22347c478bd9Sstevel@tonic-gate     }
22357c478bd9Sstevel@tonic-gate 
22367c478bd9Sstevel@tonic-gate     result = check_integrity(text, text->buffer, text->size,
22377c478bd9Sstevel@tonic-gate 			     output, outputlen);
22387c478bd9Sstevel@tonic-gate     if (result != SASL_OK)
22397c478bd9Sstevel@tonic-gate 	return result;
22407c478bd9Sstevel@tonic-gate 
22417c478bd9Sstevel@tonic-gate     /* Reset State */
22427c478bd9Sstevel@tonic-gate     text->needsize = 4;
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate     return SASL_OK;
22457c478bd9Sstevel@tonic-gate }
22467c478bd9Sstevel@tonic-gate 
22477c478bd9Sstevel@tonic-gate static int digestmd5_integrity_decode(void *context,
22487c478bd9Sstevel@tonic-gate 				      const char *input, unsigned inputlen,
22497c478bd9Sstevel@tonic-gate 				      const char **output, unsigned *outputlen)
22507c478bd9Sstevel@tonic-gate {
22517c478bd9Sstevel@tonic-gate     context_t *text = (context_t *) context;
22527c478bd9Sstevel@tonic-gate     int ret;
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate     ret = _plug_decode(text->utils, context, input, inputlen,
22557c478bd9Sstevel@tonic-gate 		       &text->decode_buf, &text->decode_buf_len, outputlen,
22567c478bd9Sstevel@tonic-gate 		       digestmd5_integrity_decode_once);
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate     *output = text->decode_buf;
22597c478bd9Sstevel@tonic-gate 
22607c478bd9Sstevel@tonic-gate     return ret;
22617c478bd9Sstevel@tonic-gate }
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate static void
22647c478bd9Sstevel@tonic-gate digestmd5_common_mech_dispose(void *conn_context, const sasl_utils_t *utils)
22657c478bd9Sstevel@tonic-gate {
22667c478bd9Sstevel@tonic-gate     context_t *text = (context_t *) conn_context;
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate     if (!text || !utils) return;
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate     if (text->authid) utils->free(text->authid);
22717c478bd9Sstevel@tonic-gate     if (text->realm) utils->free(text->realm);
22727c478bd9Sstevel@tonic-gate     if (text->nonce) utils->free(text->nonce);
22737c478bd9Sstevel@tonic-gate     if (text->cnonce) utils->free(text->cnonce);
22747c478bd9Sstevel@tonic-gate 
22757c478bd9Sstevel@tonic-gate     if (text->cipher_free) text->cipher_free(text);
22767c478bd9Sstevel@tonic-gate 
22777c478bd9Sstevel@tonic-gate     /* free the stuff in the context */
22787c478bd9Sstevel@tonic-gate     if (text->response_value) utils->free(text->response_value);
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate     if (text->buffer) utils->free(text->buffer);
22817c478bd9Sstevel@tonic-gate     if (text->encode_buf) utils->free(text->encode_buf);
22827c478bd9Sstevel@tonic-gate     if (text->decode_buf) utils->free(text->decode_buf);
22837c478bd9Sstevel@tonic-gate     if (text->decode_once_buf) utils->free(text->decode_once_buf);
22847c478bd9Sstevel@tonic-gate     if (text->decode_tmp_buf) utils->free(text->decode_tmp_buf);
22857c478bd9Sstevel@tonic-gate     if (text->out_buf) utils->free(text->out_buf);
22867c478bd9Sstevel@tonic-gate     if (text->MAC_buf) utils->free(text->MAC_buf);
22877c478bd9Sstevel@tonic-gate 
22887c478bd9Sstevel@tonic-gate     if (text->enc_in_buf) {
22897c478bd9Sstevel@tonic-gate 	if (text->enc_in_buf->data) utils->free(text->enc_in_buf->data);
22907c478bd9Sstevel@tonic-gate 	utils->free(text->enc_in_buf);
22917c478bd9Sstevel@tonic-gate     }
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate     utils->free(conn_context);
22947c478bd9Sstevel@tonic-gate }
22957c478bd9Sstevel@tonic-gate 
22967c478bd9Sstevel@tonic-gate static void
22977c478bd9Sstevel@tonic-gate clear_reauth_entry(reauth_entry_t *reauth, enum Context_type type,
22987c478bd9Sstevel@tonic-gate 		   const sasl_utils_t *utils)
22997c478bd9Sstevel@tonic-gate {
23007c478bd9Sstevel@tonic-gate     if (!reauth) return;
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate     if (reauth->authid) utils->free(reauth->authid);
23037c478bd9Sstevel@tonic-gate     if (reauth->realm) utils->free(reauth->realm);
23047c478bd9Sstevel@tonic-gate     if (reauth->nonce) utils->free(reauth->nonce);
23057c478bd9Sstevel@tonic-gate     if (reauth->cnonce) utils->free(reauth->cnonce);
23067c478bd9Sstevel@tonic-gate 
23077c478bd9Sstevel@tonic-gate     if (type == CLIENT) {
23087c478bd9Sstevel@tonic-gate 	if (reauth->u.c.serverFQDN) utils->free(reauth->u.c.serverFQDN);
23097c478bd9Sstevel@tonic-gate     }
23107c478bd9Sstevel@tonic-gate 
23117c478bd9Sstevel@tonic-gate     memset(reauth, 0, sizeof(reauth_entry_t));
23127c478bd9Sstevel@tonic-gate }
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate static void
23157c478bd9Sstevel@tonic-gate digestmd5_common_mech_free(void *glob_context, const sasl_utils_t *utils)
23167c478bd9Sstevel@tonic-gate {
23177c478bd9Sstevel@tonic-gate     reauth_cache_t *reauth_cache = (reauth_cache_t *) glob_context;
23187c478bd9Sstevel@tonic-gate     size_t n;
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate     if (!reauth_cache) return;
23217c478bd9Sstevel@tonic-gate 
23227c478bd9Sstevel@tonic-gate     for (n = 0; n < reauth_cache->size; n++)
23237c478bd9Sstevel@tonic-gate 	clear_reauth_entry(&reauth_cache->e[n], reauth_cache->i_am, utils);
23247c478bd9Sstevel@tonic-gate     if (reauth_cache->e) utils->free(reauth_cache->e);
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate     if (reauth_cache->mutex) utils->mutex_free(reauth_cache->mutex);
23277c478bd9Sstevel@tonic-gate 
23287c478bd9Sstevel@tonic-gate     utils->free(reauth_cache);
23297c478bd9Sstevel@tonic-gate }
23307c478bd9Sstevel@tonic-gate 
23317c478bd9Sstevel@tonic-gate /*****************************  Server Section  *****************************/
23327c478bd9Sstevel@tonic-gate 
23337c478bd9Sstevel@tonic-gate typedef struct server_context {
23347c478bd9Sstevel@tonic-gate     context_t common;
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate     time_t timestamp;
23377c478bd9Sstevel@tonic-gate     int stale;				/* last nonce is stale */
23387c478bd9Sstevel@tonic-gate     sasl_ssf_t limitssf, requiressf;	/* application defined bounds */
23397c478bd9Sstevel@tonic-gate } server_context_t;
23407c478bd9Sstevel@tonic-gate 
23417c478bd9Sstevel@tonic-gate static void
23427c478bd9Sstevel@tonic-gate DigestCalcHA1FromSecret(context_t * text,
23437c478bd9Sstevel@tonic-gate 			const sasl_utils_t * utils,
23447c478bd9Sstevel@tonic-gate 			HASH HA1,
23457c478bd9Sstevel@tonic-gate 			unsigned char *authorization_id,
23467c478bd9Sstevel@tonic-gate 			unsigned char *pszNonce,
23477c478bd9Sstevel@tonic-gate 			unsigned char *pszCNonce,
23487c478bd9Sstevel@tonic-gate 			HASHHEX SessionKey)
23497c478bd9Sstevel@tonic-gate {
23507c478bd9Sstevel@tonic-gate     MD5_CTX Md5Ctx;
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate     /* calculate session key */
23537c478bd9Sstevel@tonic-gate     utils->MD5Init(&Md5Ctx);
23547c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
23557c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, COLON, 1);
23567c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
23577c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, COLON, 1);
23587c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
23597c478bd9Sstevel@tonic-gate     if (authorization_id != NULL) {
23607c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, COLON, 1);
23617c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, authorization_id, strlen((char *) authorization_id));
23627c478bd9Sstevel@tonic-gate     }
23637c478bd9Sstevel@tonic-gate     utils->MD5Final(HA1, &Md5Ctx);
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate     CvtHex(HA1, SessionKey);
23667c478bd9Sstevel@tonic-gate 
23677c478bd9Sstevel@tonic-gate 
23687c478bd9Sstevel@tonic-gate     /* save HA1 because we need it to make the privacy and integrity keys */
23697c478bd9Sstevel@tonic-gate     memcpy(text->HA1, HA1, sizeof(HASH));
23707c478bd9Sstevel@tonic-gate }
23717c478bd9Sstevel@tonic-gate 
23727c478bd9Sstevel@tonic-gate static char *create_response(context_t * text,
23737c478bd9Sstevel@tonic-gate 			     const sasl_utils_t * utils,
23747c478bd9Sstevel@tonic-gate 			     unsigned char *nonce,
23757c478bd9Sstevel@tonic-gate 			     unsigned int ncvalue,
23767c478bd9Sstevel@tonic-gate 			     unsigned char *cnonce,
23777c478bd9Sstevel@tonic-gate 			     char *qop,
23787c478bd9Sstevel@tonic-gate 			     char *digesturi,
23797c478bd9Sstevel@tonic-gate 			     HASH Secret,
23807c478bd9Sstevel@tonic-gate 			     char *authorization_id,
23817c478bd9Sstevel@tonic-gate 			     char **response_value)
23827c478bd9Sstevel@tonic-gate {
23837c478bd9Sstevel@tonic-gate     HASHHEX         SessionKey;
23847c478bd9Sstevel@tonic-gate     HASHHEX         HEntity = "00000000000000000000000000000000";
23857c478bd9Sstevel@tonic-gate     HASHHEX         Response;
23867c478bd9Sstevel@tonic-gate     char           *result;
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate     if (qop == NULL)
23897c478bd9Sstevel@tonic-gate 	qop = "auth";
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate     DigestCalcHA1FromSecret(text,
23927c478bd9Sstevel@tonic-gate 			    utils,
23937c478bd9Sstevel@tonic-gate 			    Secret,
23947c478bd9Sstevel@tonic-gate 			    (unsigned char *) authorization_id,
23957c478bd9Sstevel@tonic-gate 			    nonce,
23967c478bd9Sstevel@tonic-gate 			    cnonce,
23977c478bd9Sstevel@tonic-gate 			    SessionKey);
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate     DigestCalcResponse(utils,
24007c478bd9Sstevel@tonic-gate 		       SessionKey,/* H(A1) */
24017c478bd9Sstevel@tonic-gate 		       nonce,	/* nonce from server */
24027c478bd9Sstevel@tonic-gate 		       ncvalue,	/* 8 hex digits */
24037c478bd9Sstevel@tonic-gate 		       cnonce,	/* client nonce */
24047c478bd9Sstevel@tonic-gate 		       (unsigned char *) qop,	/* qop-value: "", "auth",
24057c478bd9Sstevel@tonic-gate 						 * "auth-int" */
24067c478bd9Sstevel@tonic-gate 		       (unsigned char *) digesturi,	/* requested URL */
24077c478bd9Sstevel@tonic-gate 		       (unsigned char *) "AUTHENTICATE",
24087c478bd9Sstevel@tonic-gate 		       HEntity,	/* H(entity body) if qop="auth-int" */
24097c478bd9Sstevel@tonic-gate 		       Response	/* request-digest or response-digest */
24107c478bd9Sstevel@tonic-gate 	);
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate     result = utils->malloc(HASHHEXLEN + 1);
24137c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
24147c478bd9Sstevel@tonic-gate     if (result == NULL)
24157c478bd9Sstevel@tonic-gate 	return NULL;
24167c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
24177c478bd9Sstevel@tonic-gate /* TODO */
24187c478bd9Sstevel@tonic-gate     memcpy(result, Response, HASHHEXLEN);
24197c478bd9Sstevel@tonic-gate     result[HASHHEXLEN] = 0;
24207c478bd9Sstevel@tonic-gate 
24217c478bd9Sstevel@tonic-gate     /* response_value (used for reauth i think */
24227c478bd9Sstevel@tonic-gate     if (response_value != NULL) {
24237c478bd9Sstevel@tonic-gate 	DigestCalcResponse(utils,
24247c478bd9Sstevel@tonic-gate 			   SessionKey,	/* H(A1) */
24257c478bd9Sstevel@tonic-gate 			   nonce,	/* nonce from server */
24267c478bd9Sstevel@tonic-gate 			   ncvalue,	/* 8 hex digits */
24277c478bd9Sstevel@tonic-gate 			   cnonce,	/* client nonce */
24287c478bd9Sstevel@tonic-gate 			   (unsigned char *) qop,	/* qop-value: "", "auth",
24297c478bd9Sstevel@tonic-gate 							 * "auth-int" */
24307c478bd9Sstevel@tonic-gate 			   (unsigned char *) digesturi,	/* requested URL */
24317c478bd9Sstevel@tonic-gate 			   NULL,
24327c478bd9Sstevel@tonic-gate 			   HEntity,	/* H(entity body) if qop="auth-int" */
24337c478bd9Sstevel@tonic-gate 			   Response	/* request-digest or response-digest */
24347c478bd9Sstevel@tonic-gate 	    );
24357c478bd9Sstevel@tonic-gate 
24367c478bd9Sstevel@tonic-gate 	*response_value = utils->malloc(HASHHEXLEN + 1);
24377c478bd9Sstevel@tonic-gate 	if (*response_value == NULL)
24387c478bd9Sstevel@tonic-gate 	    return NULL;
24397c478bd9Sstevel@tonic-gate 	memcpy(*response_value, Response, HASHHEXLEN);
24407c478bd9Sstevel@tonic-gate 	(*response_value)[HASHHEXLEN] = 0;
24417c478bd9Sstevel@tonic-gate     }
24427c478bd9Sstevel@tonic-gate     return result;
24437c478bd9Sstevel@tonic-gate }
24447c478bd9Sstevel@tonic-gate 
24457c478bd9Sstevel@tonic-gate static int
24467c478bd9Sstevel@tonic-gate get_server_realm(sasl_server_params_t * params,
24477c478bd9Sstevel@tonic-gate 		 char **realm)
24487c478bd9Sstevel@tonic-gate {
24497c478bd9Sstevel@tonic-gate     /* look at user realm first */
24507c478bd9Sstevel@tonic-gate     if (params->user_realm != NULL) {
24517c478bd9Sstevel@tonic-gate 	if(params->user_realm[0] != '\0') {
24527c478bd9Sstevel@tonic-gate 	    *realm = (char *) params->user_realm;
24537c478bd9Sstevel@tonic-gate 	} else {
24547c478bd9Sstevel@tonic-gate 	    /* Catch improperly converted apps */
24557c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
24567c478bd9Sstevel@tonic-gate 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
24577c478bd9Sstevel@tonic-gate 			       "user_realm is an empty string!");
24587c478bd9Sstevel@tonic-gate #else
24597c478bd9Sstevel@tonic-gate 	    params->utils->seterror(params->utils->conn, 0,
24607c478bd9Sstevel@tonic-gate 				    "user_realm is an empty string!");
24617c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
24627c478bd9Sstevel@tonic-gate 	    return SASL_BADPARAM;
24637c478bd9Sstevel@tonic-gate 	}
24647c478bd9Sstevel@tonic-gate     } else if (params->serverFQDN != NULL) {
24657c478bd9Sstevel@tonic-gate 	*realm = (char *) params->serverFQDN;
24667c478bd9Sstevel@tonic-gate     } else {
24677c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
24687c478bd9Sstevel@tonic-gate 	params->utils->log(params->utils->conn, SASL_LOG_ERR,
24697c478bd9Sstevel@tonic-gate 			   "no way to obtain domain");
24707c478bd9Sstevel@tonic-gate #else
24717c478bd9Sstevel@tonic-gate 	params->utils->seterror(params->utils->conn, 0,
24727c478bd9Sstevel@tonic-gate 				"no way to obtain domain");
24737c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
24747c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
24757c478bd9Sstevel@tonic-gate     }
24767c478bd9Sstevel@tonic-gate 
24777c478bd9Sstevel@tonic-gate     return SASL_OK;
24787c478bd9Sstevel@tonic-gate }
24797c478bd9Sstevel@tonic-gate 
24807c478bd9Sstevel@tonic-gate /*
24817c478bd9Sstevel@tonic-gate  * Convert hex string to int
24827c478bd9Sstevel@tonic-gate  */
24837c478bd9Sstevel@tonic-gate static int htoi(unsigned char *hexin, unsigned int *res)
24847c478bd9Sstevel@tonic-gate {
24857c478bd9Sstevel@tonic-gate     int             lup, inlen;
24867c478bd9Sstevel@tonic-gate     inlen = strlen((char *) hexin);
24877c478bd9Sstevel@tonic-gate 
24887c478bd9Sstevel@tonic-gate     *res = 0;
24897c478bd9Sstevel@tonic-gate     for (lup = 0; lup < inlen; lup++) {
24907c478bd9Sstevel@tonic-gate 	switch (hexin[lup]) {
24917c478bd9Sstevel@tonic-gate 	case '0':
24927c478bd9Sstevel@tonic-gate 	case '1':
24937c478bd9Sstevel@tonic-gate 	case '2':
24947c478bd9Sstevel@tonic-gate 	case '3':
24957c478bd9Sstevel@tonic-gate 	case '4':
24967c478bd9Sstevel@tonic-gate 	case '5':
24977c478bd9Sstevel@tonic-gate 	case '6':
24987c478bd9Sstevel@tonic-gate 	case '7':
24997c478bd9Sstevel@tonic-gate 	case '8':
25007c478bd9Sstevel@tonic-gate 	case '9':
25017c478bd9Sstevel@tonic-gate 	    *res = (*res << 4) + (hexin[lup] - '0');
25027c478bd9Sstevel@tonic-gate 	    break;
25037c478bd9Sstevel@tonic-gate 
25047c478bd9Sstevel@tonic-gate 	case 'a':
25057c478bd9Sstevel@tonic-gate 	case 'b':
25067c478bd9Sstevel@tonic-gate 	case 'c':
25077c478bd9Sstevel@tonic-gate 	case 'd':
25087c478bd9Sstevel@tonic-gate 	case 'e':
25097c478bd9Sstevel@tonic-gate 	case 'f':
25107c478bd9Sstevel@tonic-gate 	    *res = (*res << 4) + (hexin[lup] - 'a' + 10);
25117c478bd9Sstevel@tonic-gate 	    break;
25127c478bd9Sstevel@tonic-gate 
25137c478bd9Sstevel@tonic-gate 	case 'A':
25147c478bd9Sstevel@tonic-gate 	case 'B':
25157c478bd9Sstevel@tonic-gate 	case 'C':
25167c478bd9Sstevel@tonic-gate 	case 'D':
25177c478bd9Sstevel@tonic-gate 	case 'E':
25187c478bd9Sstevel@tonic-gate 	case 'F':
25197c478bd9Sstevel@tonic-gate 	    *res = (*res << 4) + (hexin[lup] - 'A' + 10);
25207c478bd9Sstevel@tonic-gate 	    break;
25217c478bd9Sstevel@tonic-gate 
25227c478bd9Sstevel@tonic-gate 	default:
25237c478bd9Sstevel@tonic-gate 	    return SASL_BADPARAM;
25247c478bd9Sstevel@tonic-gate 	}
25257c478bd9Sstevel@tonic-gate 
25267c478bd9Sstevel@tonic-gate     }
25277c478bd9Sstevel@tonic-gate 
25287c478bd9Sstevel@tonic-gate     return SASL_OK;
25297c478bd9Sstevel@tonic-gate }
25307c478bd9Sstevel@tonic-gate 
25317c478bd9Sstevel@tonic-gate static int digestmd5_server_mech_new(void *glob_context,
25327c478bd9Sstevel@tonic-gate 				     sasl_server_params_t * sparams,
25337c478bd9Sstevel@tonic-gate 				     const char *challenge __attribute__((unused)),
25347c478bd9Sstevel@tonic-gate 				     unsigned challen __attribute__((unused)),
25357c478bd9Sstevel@tonic-gate 				     void **conn_context)
25367c478bd9Sstevel@tonic-gate {
25377c478bd9Sstevel@tonic-gate     context_t *text;
25387c478bd9Sstevel@tonic-gate 
25397c478bd9Sstevel@tonic-gate     /* holds state are in -- allocate server size */
25407c478bd9Sstevel@tonic-gate     text = sparams->utils->malloc(sizeof(server_context_t));
25417c478bd9Sstevel@tonic-gate     if (text == NULL)
25427c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
25437c478bd9Sstevel@tonic-gate     memset(text, 0, sizeof(server_context_t));
25447c478bd9Sstevel@tonic-gate 
25457c478bd9Sstevel@tonic-gate     text->state = 1;
25467c478bd9Sstevel@tonic-gate     text->i_am = SERVER;
25477c478bd9Sstevel@tonic-gate     text->reauth = glob_context;
25487c478bd9Sstevel@tonic-gate 
25497c478bd9Sstevel@tonic-gate     *conn_context = text;
25507c478bd9Sstevel@tonic-gate     return SASL_OK;
25517c478bd9Sstevel@tonic-gate }
25527c478bd9Sstevel@tonic-gate 
25537c478bd9Sstevel@tonic-gate static int
25547c478bd9Sstevel@tonic-gate digestmd5_server_mech_step1(server_context_t *stext,
25557c478bd9Sstevel@tonic-gate 			    sasl_server_params_t *sparams,
25567c478bd9Sstevel@tonic-gate 			    const char *clientin __attribute__((unused)),
25577c478bd9Sstevel@tonic-gate 			    unsigned clientinlen __attribute__((unused)),
25587c478bd9Sstevel@tonic-gate 			    const char **serverout,
25597c478bd9Sstevel@tonic-gate 			    unsigned *serveroutlen,
25607c478bd9Sstevel@tonic-gate 			    sasl_out_params_t * oparams __attribute__((unused)))
25617c478bd9Sstevel@tonic-gate {
25627c478bd9Sstevel@tonic-gate     context_t *text = (context_t *) stext;
25637c478bd9Sstevel@tonic-gate     int             result;
25647c478bd9Sstevel@tonic-gate     char           *realm;
25657c478bd9Sstevel@tonic-gate     unsigned char  *nonce;
25667c478bd9Sstevel@tonic-gate     char           *charset = "utf-8";
25677c478bd9Sstevel@tonic-gate     char qop[1024], cipheropts[1024];
25687c478bd9Sstevel@tonic-gate     struct digest_cipher *cipher;
25697c478bd9Sstevel@tonic-gate     unsigned       resplen;
25707c478bd9Sstevel@tonic-gate     int added_conf = 0;
25717c478bd9Sstevel@tonic-gate     char maxbufstr[64];
25727c478bd9Sstevel@tonic-gate 
25737c478bd9Sstevel@tonic-gate     sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
25747c478bd9Sstevel@tonic-gate 			"DIGEST-MD5 server step 1");
25757c478bd9Sstevel@tonic-gate 
25767c478bd9Sstevel@tonic-gate     /* get realm */
25777c478bd9Sstevel@tonic-gate     result = get_server_realm(sparams, &realm);
25787c478bd9Sstevel@tonic-gate     if(result != SASL_OK) return result;
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate     /* what options should we offer the client? */
25817c478bd9Sstevel@tonic-gate     qop[0] = '\0';
25827c478bd9Sstevel@tonic-gate     cipheropts[0] = '\0';
25837c478bd9Sstevel@tonic-gate     if (stext->requiressf == 0) {
25847c478bd9Sstevel@tonic-gate 	if (*qop) strcat(qop, ",");
25857c478bd9Sstevel@tonic-gate 	strcat(qop, "auth");
25867c478bd9Sstevel@tonic-gate     }
25877c478bd9Sstevel@tonic-gate     if (stext->requiressf <= 1 && stext->limitssf >= 1) {
25887c478bd9Sstevel@tonic-gate 	if (*qop) strcat(qop, ",");
25897c478bd9Sstevel@tonic-gate 	strcat(qop, "auth-int");
25907c478bd9Sstevel@tonic-gate     }
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate #ifdef USE_UEF_SERVER
25937c478bd9Sstevel@tonic-gate     cipher = available_ciphers1;
25947c478bd9Sstevel@tonic-gate #else
25957c478bd9Sstevel@tonic-gate     cipher = available_ciphers;
25967c478bd9Sstevel@tonic-gate #endif
25977c478bd9Sstevel@tonic-gate     while (cipher->name) {
25987c478bd9Sstevel@tonic-gate 	/* do we allow this particular cipher? */
25997c478bd9Sstevel@tonic-gate 	if (stext->requiressf <= cipher->ssf &&
26007c478bd9Sstevel@tonic-gate 	    stext->limitssf >= cipher->ssf) {
26017c478bd9Sstevel@tonic-gate 	    if (!added_conf) {
26027c478bd9Sstevel@tonic-gate 		if (*qop) strcat(qop, ",");
26037c478bd9Sstevel@tonic-gate 		strcat(qop, "auth-conf");
26047c478bd9Sstevel@tonic-gate 		added_conf = 1;
26057c478bd9Sstevel@tonic-gate 	    }
26067c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
26077c478bd9Sstevel@tonic-gate 	    if(strlen(cipheropts) + strlen(cipher->name) + 1 >=
26087c478bd9Sstevel@tonic-gate 			sizeof (cipheropts)) {
26097c478bd9Sstevel@tonic-gate 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
26107c478bd9Sstevel@tonic-gate 		    "internal error: cipheropts too big");
26117c478bd9Sstevel@tonic-gate 		return SASL_FAIL;
26127c478bd9Sstevel@tonic-gate 	    }
26137c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
26147c478bd9Sstevel@tonic-gate 	    if (*cipheropts) strcat(cipheropts, ",");
26157c478bd9Sstevel@tonic-gate 	    strcat(cipheropts, cipher->name);
26167c478bd9Sstevel@tonic-gate 	}
26177c478bd9Sstevel@tonic-gate 	cipher++;
26187c478bd9Sstevel@tonic-gate     }
26197c478bd9Sstevel@tonic-gate 
26207c478bd9Sstevel@tonic-gate     if (*qop == '\0') {
26217c478bd9Sstevel@tonic-gate 	/* we didn't allow anything?!? we'll return SASL_TOOWEAK, since
26227c478bd9Sstevel@tonic-gate 	   that's close enough */
26237c478bd9Sstevel@tonic-gate 	return SASL_TOOWEAK;
26247c478bd9Sstevel@tonic-gate     }
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate     /*
26277c478bd9Sstevel@tonic-gate      * digest-challenge  = 1#( realm | nonce | qop-options | stale | maxbuf |
26287c478bd9Sstevel@tonic-gate      * charset | cipher-opts | auth-param )
26297c478bd9Sstevel@tonic-gate      */
26307c478bd9Sstevel@tonic-gate 
26317c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
26327c478bd9Sstevel@tonic-gate     /* FIXME: get nonce XXX have to clean up after self if fail */
26337c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
26347c478bd9Sstevel@tonic-gate     nonce = create_nonce(sparams->utils);
26357c478bd9Sstevel@tonic-gate     if (nonce == NULL) {
26367c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
26377c478bd9Sstevel@tonic-gate 	/* Note typo below */
26387c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
26397c478bd9Sstevel@tonic-gate 			    "internal error: failed creating a nonce");
26407c478bd9Sstevel@tonic-gate #else
26417c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils, "internal erorr: failed creating a nonce");
26427c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
26437c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
26447c478bd9Sstevel@tonic-gate     }
26457c478bd9Sstevel@tonic-gate 
26467c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
26477c478bd9Sstevel@tonic-gate     resplen = strlen((char *)nonce) + strlen("nonce") + 5;
26487c478bd9Sstevel@tonic-gate #else
26497c478bd9Sstevel@tonic-gate     resplen = strlen(nonce) + strlen("nonce") + 5;
26507c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
26517c478bd9Sstevel@tonic-gate     result = _plug_buf_alloc(sparams->utils, &(text->out_buf),
26527c478bd9Sstevel@tonic-gate 			     &(text->out_buf_len), resplen);
26537c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
26547c478bd9Sstevel@tonic-gate     if(result != SASL_OK) {
26557c478bd9Sstevel@tonic-gate 	sparams->utils->free(nonce);
26567c478bd9Sstevel@tonic-gate 	return result;
26577c478bd9Sstevel@tonic-gate     }
26587c478bd9Sstevel@tonic-gate #else
26597c478bd9Sstevel@tonic-gate     if(result != SASL_OK) return result;
26607c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
26617c478bd9Sstevel@tonic-gate 
26627c478bd9Sstevel@tonic-gate     sprintf(text->out_buf, "nonce=\"%s\"", nonce);
26637c478bd9Sstevel@tonic-gate 
26647c478bd9Sstevel@tonic-gate     /* add to challenge; if we chose not to specify a realm, we won't
26657c478bd9Sstevel@tonic-gate      * send one to the client */
26667c478bd9Sstevel@tonic-gate     if (realm && add_to_challenge(sparams->utils,
26677c478bd9Sstevel@tonic-gate 				  &text->out_buf, &text->out_buf_len, &resplen,
26687c478bd9Sstevel@tonic-gate 				  "realm", (unsigned char *) realm,
26697c478bd9Sstevel@tonic-gate 				  TRUE) != SASL_OK) {
26707c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
26717c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
26727c478bd9Sstevel@tonic-gate 			    "internal error: add_to_challenge failed");
26737c478bd9Sstevel@tonic-gate 	sparams->utils->free(nonce);
26747c478bd9Sstevel@tonic-gate #else
26757c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils, "internal error: add_to_challenge failed");
26767c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
26777c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
26787c478bd9Sstevel@tonic-gate     }
26797c478bd9Sstevel@tonic-gate     /*
26807c478bd9Sstevel@tonic-gate      * qop-options A quoted string of one or more tokens indicating the
26817c478bd9Sstevel@tonic-gate      * "quality of protection" values supported by the server.  The value
26827c478bd9Sstevel@tonic-gate      * "auth" indicates authentication; the value "auth-int" indicates
26837c478bd9Sstevel@tonic-gate      * authentication with integrity protection; the value "auth-conf"
26847c478bd9Sstevel@tonic-gate      * indicates authentication with integrity protection and encryption.
26857c478bd9Sstevel@tonic-gate      */
26867c478bd9Sstevel@tonic-gate 
26877c478bd9Sstevel@tonic-gate     /* add qop to challenge */
26887c478bd9Sstevel@tonic-gate     if (add_to_challenge(sparams->utils,
26897c478bd9Sstevel@tonic-gate 			 &text->out_buf, &text->out_buf_len, &resplen,
26907c478bd9Sstevel@tonic-gate 			 "qop",
26917c478bd9Sstevel@tonic-gate 			 (unsigned char *) qop, TRUE) != SASL_OK) {
26927c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
26937c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
26947c478bd9Sstevel@tonic-gate 		 "internal error: add_to_challenge 3 failed");
26957c478bd9Sstevel@tonic-gate 	sparams->utils->free(nonce);
26967c478bd9Sstevel@tonic-gate #else
26977c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils, "internal error: add_to_challenge 3 failed");
26987c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
26997c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
27007c478bd9Sstevel@tonic-gate     }
27017c478bd9Sstevel@tonic-gate 
27027c478bd9Sstevel@tonic-gate     /*
27037c478bd9Sstevel@tonic-gate      *  Cipheropts - list of ciphers server supports
27047c478bd9Sstevel@tonic-gate      */
27057c478bd9Sstevel@tonic-gate     /* add cipher-opts to challenge; only add if there are some */
27067c478bd9Sstevel@tonic-gate     if (strcmp(cipheropts,"")!=0)
27077c478bd9Sstevel@tonic-gate 	{
27087c478bd9Sstevel@tonic-gate 	    if (add_to_challenge(sparams->utils,
27097c478bd9Sstevel@tonic-gate 				 &text->out_buf, &text->out_buf_len, &resplen,
27107c478bd9Sstevel@tonic-gate 				 "cipher", (unsigned char *) cipheropts,
27117c478bd9Sstevel@tonic-gate 				 TRUE) != SASL_OK) {
27127c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
27137c478bd9Sstevel@tonic-gate 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
27147c478bd9Sstevel@tonic-gate 			"internal error: add_to_challenge 4 failed");
27157c478bd9Sstevel@tonic-gate 		sparams->utils->free(nonce);
27167c478bd9Sstevel@tonic-gate #else
27177c478bd9Sstevel@tonic-gate 		SETERROR(sparams->utils,
27187c478bd9Sstevel@tonic-gate 			 "internal error: add_to_challenge 4 failed");
27197c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
27207c478bd9Sstevel@tonic-gate 		return SASL_FAIL;
27217c478bd9Sstevel@tonic-gate 	    }
27227c478bd9Sstevel@tonic-gate 	}
27237c478bd9Sstevel@tonic-gate 
27247c478bd9Sstevel@tonic-gate     /* "stale" is true if a reauth failed because of a nonce timeout */
27257c478bd9Sstevel@tonic-gate     if (stext->stale &&
27267c478bd9Sstevel@tonic-gate 	add_to_challenge(sparams->utils,
27277c478bd9Sstevel@tonic-gate 			 &text->out_buf, &text->out_buf_len, &resplen,
27287c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
27297c478bd9Sstevel@tonic-gate 			 "stale", (unsigned char *)"true", FALSE) != SASL_OK) {
27307c478bd9Sstevel@tonic-gate 	sparams->utils->free(nonce);
27317c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
27327c478bd9Sstevel@tonic-gate 			    "internal error: add_to_challenge failed");
27337c478bd9Sstevel@tonic-gate #else
27347c478bd9Sstevel@tonic-gate 			 "stale", "true", FALSE) != SASL_OK) {
27357c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils, "internal error: add_to_challenge failed");
27367c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
27377c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
27387c478bd9Sstevel@tonic-gate     }
27397c478bd9Sstevel@tonic-gate 
27407c478bd9Sstevel@tonic-gate     /*
27417c478bd9Sstevel@tonic-gate      * maxbuf A number indicating the size of the largest buffer the server
27427c478bd9Sstevel@tonic-gate      * is able to receive when using "auth-int". If this directive is
27437c478bd9Sstevel@tonic-gate      * missing, the default value is 65536. This directive may appear at most
27447c478bd9Sstevel@tonic-gate      * once; if multiple instances are present, the client should abort the
27457c478bd9Sstevel@tonic-gate      * authentication exchange.
27467c478bd9Sstevel@tonic-gate      */
27477c478bd9Sstevel@tonic-gate     if(sparams->props.maxbufsize) {
27487c478bd9Sstevel@tonic-gate 	snprintf(maxbufstr, sizeof(maxbufstr), "%d",
27497c478bd9Sstevel@tonic-gate 		 sparams->props.maxbufsize);
27507c478bd9Sstevel@tonic-gate 	if (add_to_challenge(sparams->utils,
27517c478bd9Sstevel@tonic-gate 			     &text->out_buf, &text->out_buf_len, &resplen,
27527c478bd9Sstevel@tonic-gate 			     "maxbuf",
27537c478bd9Sstevel@tonic-gate 			     (unsigned char *) maxbufstr, FALSE) != SASL_OK) {
27547c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
27557c478bd9Sstevel@tonic-gate 	    sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
27567c478bd9Sstevel@tonic-gate 				"internal error: add_to_challenge 5 failed");
27577c478bd9Sstevel@tonic-gate #else
27587c478bd9Sstevel@tonic-gate 	    SETERROR(sparams->utils,
27597c478bd9Sstevel@tonic-gate 		     "internal error: add_to_challenge 5 failed");
27607c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
27617c478bd9Sstevel@tonic-gate 	    return SASL_FAIL;
27627c478bd9Sstevel@tonic-gate 	}
27637c478bd9Sstevel@tonic-gate     }
27647c478bd9Sstevel@tonic-gate 
27657c478bd9Sstevel@tonic-gate 
27667c478bd9Sstevel@tonic-gate     if (add_to_challenge(sparams->utils,
27677c478bd9Sstevel@tonic-gate 			 &text->out_buf, &text->out_buf_len, &resplen,
27687c478bd9Sstevel@tonic-gate 			 "charset",
27697c478bd9Sstevel@tonic-gate 			 (unsigned char *) charset, FALSE) != SASL_OK) {
27707c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
27717c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
27727c478bd9Sstevel@tonic-gate 			    "internal error: add_to_challenge 6 failed");
27737c478bd9Sstevel@tonic-gate 	sparams->utils->free(nonce);
27747c478bd9Sstevel@tonic-gate #else
27757c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils, "internal error: add_to_challenge 6 failed");
27767c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
27777c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
27787c478bd9Sstevel@tonic-gate     }
27797c478bd9Sstevel@tonic-gate 
27807c478bd9Sstevel@tonic-gate 
27817c478bd9Sstevel@tonic-gate     /*
27827c478bd9Sstevel@tonic-gate      * algorithm
27837c478bd9Sstevel@tonic-gate      *  This directive is required for backwards compatibility with HTTP
27847c478bd9Sstevel@tonic-gate      *  Digest., which supports other algorithms. . This directive is
27857c478bd9Sstevel@tonic-gate      *  required and MUST appear exactly once; if not present, or if multiple
27867c478bd9Sstevel@tonic-gate      *  instances are present, the client should abort the authentication
27877c478bd9Sstevel@tonic-gate      *  exchange.
27887c478bd9Sstevel@tonic-gate      *
27897c478bd9Sstevel@tonic-gate      * algorithm         = "algorithm" "=" "md5-sess"
27907c478bd9Sstevel@tonic-gate      */
27917c478bd9Sstevel@tonic-gate 
27927c478bd9Sstevel@tonic-gate     if (add_to_challenge(sparams->utils,
27937c478bd9Sstevel@tonic-gate 			 &text->out_buf, &text->out_buf_len, &resplen,
27947c478bd9Sstevel@tonic-gate 			 "algorithm",
27957c478bd9Sstevel@tonic-gate 			 (unsigned char *) "md5-sess", FALSE)!=SASL_OK) {
27967c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
27977c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
27987c478bd9Sstevel@tonic-gate 			    "internal error: add_to_challenge 7 failed");
27997c478bd9Sstevel@tonic-gate 	sparams->utils->free(nonce);
28007c478bd9Sstevel@tonic-gate #else
28017c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils, "internal error: add_to_challenge 7 failed");
28027c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
28037c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
28047c478bd9Sstevel@tonic-gate     }
28057c478bd9Sstevel@tonic-gate 
28067c478bd9Sstevel@tonic-gate     /*
28077c478bd9Sstevel@tonic-gate      * The size of a digest-challenge MUST be less than 2048 bytes!!!
28087c478bd9Sstevel@tonic-gate      */
28097c478bd9Sstevel@tonic-gate     if (*serveroutlen > 2048) {
28107c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
28117c478bd9Sstevel@tonic-gate 	sparams->utils->free(nonce);
28127c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
28137c478bd9Sstevel@tonic-gate 			    "internal error: challenge larger than 2048 bytes");
28147c478bd9Sstevel@tonic-gate #else
28157c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils,
28167c478bd9Sstevel@tonic-gate 		 "internal error: challenge larger than 2048 bytes");
28177c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
28187c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
28197c478bd9Sstevel@tonic-gate     }
28207c478bd9Sstevel@tonic-gate 
28217c478bd9Sstevel@tonic-gate     text->authid = NULL;
28227c478bd9Sstevel@tonic-gate     _plug_strdup(sparams->utils, realm, &text->realm, NULL);
28237c478bd9Sstevel@tonic-gate     text->nonce = nonce;
28247c478bd9Sstevel@tonic-gate     text->nonce_count = 1;
28257c478bd9Sstevel@tonic-gate     text->cnonce = NULL;
28267c478bd9Sstevel@tonic-gate     stext->timestamp = time(0);
28277c478bd9Sstevel@tonic-gate 
28287c478bd9Sstevel@tonic-gate     *serveroutlen = strlen(text->out_buf);
28297c478bd9Sstevel@tonic-gate     *serverout = text->out_buf;
28307c478bd9Sstevel@tonic-gate 
28317c478bd9Sstevel@tonic-gate     text->state = 2;
28327c478bd9Sstevel@tonic-gate 
28337c478bd9Sstevel@tonic-gate     return SASL_CONTINUE;
28347c478bd9Sstevel@tonic-gate }
28357c478bd9Sstevel@tonic-gate 
28367c478bd9Sstevel@tonic-gate static int
28377c478bd9Sstevel@tonic-gate digestmd5_server_mech_step2(server_context_t *stext,
28387c478bd9Sstevel@tonic-gate 			    sasl_server_params_t *sparams,
28397c478bd9Sstevel@tonic-gate 			    const char *clientin,
28407c478bd9Sstevel@tonic-gate 			    unsigned clientinlen,
28417c478bd9Sstevel@tonic-gate 			    const char **serverout,
28427c478bd9Sstevel@tonic-gate 			    unsigned *serveroutlen,
28437c478bd9Sstevel@tonic-gate 			    sasl_out_params_t * oparams)
28447c478bd9Sstevel@tonic-gate {
28457c478bd9Sstevel@tonic-gate     context_t *text = (context_t *) stext;
28467c478bd9Sstevel@tonic-gate     /* verify digest */
28477c478bd9Sstevel@tonic-gate     sasl_secret_t  *sec = NULL;
28487c478bd9Sstevel@tonic-gate     int             result;
28497c478bd9Sstevel@tonic-gate     char           *serverresponse = NULL;
28507c478bd9Sstevel@tonic-gate     char           *username = NULL;
28517c478bd9Sstevel@tonic-gate     char           *authorization_id = NULL;
28527c478bd9Sstevel@tonic-gate     char           *realm = NULL;
28537c478bd9Sstevel@tonic-gate     unsigned char  *nonce = NULL, *cnonce = NULL;
28547c478bd9Sstevel@tonic-gate     unsigned int   noncecount = 0;
28557c478bd9Sstevel@tonic-gate     char           *qop = NULL;
28567c478bd9Sstevel@tonic-gate     char           *digesturi = NULL;
28577c478bd9Sstevel@tonic-gate     char           *response = NULL;
28587c478bd9Sstevel@tonic-gate 
28597c478bd9Sstevel@tonic-gate     /* setting the default value (65536) */
28607c478bd9Sstevel@tonic-gate     unsigned int    client_maxbuf = 65536;
28617c478bd9Sstevel@tonic-gate     int             maxbuf_count = 0;  /* How many maxbuf instaces was found */
28627c478bd9Sstevel@tonic-gate 
28637c478bd9Sstevel@tonic-gate     char           *charset = NULL;
28647c478bd9Sstevel@tonic-gate     char           *cipher = NULL;
28657c478bd9Sstevel@tonic-gate     unsigned int   n=0;
28667c478bd9Sstevel@tonic-gate 
28677c478bd9Sstevel@tonic-gate     HASH            A1;
28687c478bd9Sstevel@tonic-gate 
28697c478bd9Sstevel@tonic-gate     /* password prop_request */
28707c478bd9Sstevel@tonic-gate     const char *password_request[] = { SASL_AUX_PASSWORD,
28717c478bd9Sstevel@tonic-gate 				       "*cmusaslsecretDIGEST-MD5",
28727c478bd9Sstevel@tonic-gate 				       NULL };
28737c478bd9Sstevel@tonic-gate     unsigned len;
28747c478bd9Sstevel@tonic-gate     struct propval auxprop_values[2];
28757c478bd9Sstevel@tonic-gate 
28767c478bd9Sstevel@tonic-gate     /* can we mess with clientin? copy it to be safe */
28777c478bd9Sstevel@tonic-gate     char           *in_start = NULL;
28787c478bd9Sstevel@tonic-gate     char           *in = NULL;
28797c478bd9Sstevel@tonic-gate 
28807c478bd9Sstevel@tonic-gate     sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
28817c478bd9Sstevel@tonic-gate 			"DIGEST-MD5 server step 2");
28827c478bd9Sstevel@tonic-gate 
28837c478bd9Sstevel@tonic-gate     in = sparams->utils->malloc(clientinlen + 1);
28847c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
28857c478bd9Sstevel@tonic-gate     if (!in) return SASL_NOMEM;
28867c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
28877c478bd9Sstevel@tonic-gate 
28887c478bd9Sstevel@tonic-gate     memcpy(in, clientin, clientinlen);
28897c478bd9Sstevel@tonic-gate     in[clientinlen] = 0;
28907c478bd9Sstevel@tonic-gate 
28917c478bd9Sstevel@tonic-gate     in_start = in;
28927c478bd9Sstevel@tonic-gate 
28937c478bd9Sstevel@tonic-gate 
28947c478bd9Sstevel@tonic-gate     /* parse what we got */
28957c478bd9Sstevel@tonic-gate     while (in[0] != '\0') {
28967c478bd9Sstevel@tonic-gate 	char           *name = NULL, *value = NULL;
28977c478bd9Sstevel@tonic-gate 	get_pair(&in, &name, &value);
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate 	if (name == NULL)
29007c478bd9Sstevel@tonic-gate 	    break;
29017c478bd9Sstevel@tonic-gate 
29027c478bd9Sstevel@tonic-gate 	/* Extracting parameters */
29037c478bd9Sstevel@tonic-gate 
29047c478bd9Sstevel@tonic-gate 	/*
29057c478bd9Sstevel@tonic-gate 	 * digest-response  = 1#( username | realm | nonce | cnonce |
29067c478bd9Sstevel@tonic-gate 	 * nonce-count | qop | digest-uri | response | maxbuf | charset |
29077c478bd9Sstevel@tonic-gate 	 * cipher | auth-param )
29087c478bd9Sstevel@tonic-gate 	 */
29097c478bd9Sstevel@tonic-gate 
29107c478bd9Sstevel@tonic-gate 	if (strcasecmp(name, "username") == 0) {
29117c478bd9Sstevel@tonic-gate 	    _plug_strdup(sparams->utils, value, &username, NULL);
29127c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "authzid") == 0) {
29137c478bd9Sstevel@tonic-gate 	    _plug_strdup(sparams->utils, value, &authorization_id, NULL);
29147c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "cnonce") == 0) {
29157c478bd9Sstevel@tonic-gate 	    _plug_strdup(sparams->utils, value, (char **) &cnonce, NULL);
29167c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "nc") == 0) {
29177c478bd9Sstevel@tonic-gate 	    if (htoi((unsigned char *) value, &noncecount) != SASL_OK) {
29187c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
29197c478bd9Sstevel@tonic-gate 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
29207c478bd9Sstevel@tonic-gate 			 "error converting hex to int");
29217c478bd9Sstevel@tonic-gate #else
29227c478bd9Sstevel@tonic-gate 		SETERROR(sparams->utils,
29237c478bd9Sstevel@tonic-gate 			 "error converting hex to int");
29247c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
29257c478bd9Sstevel@tonic-gate 		result = SASL_BADAUTH;
29267c478bd9Sstevel@tonic-gate 		goto FreeAllMem;
29277c478bd9Sstevel@tonic-gate 	    }
29287c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "realm") == 0) {
29297c478bd9Sstevel@tonic-gate 	    if (realm) {
29307c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
29317c478bd9Sstevel@tonic-gate 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
29327c478bd9Sstevel@tonic-gate 				    "duplicate realm: authentication aborted");
29337c478bd9Sstevel@tonic-gate #else
29347c478bd9Sstevel@tonic-gate 		SETERROR(sparams->utils,
29357c478bd9Sstevel@tonic-gate 			 "duplicate realm: authentication aborted");
29367c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
29377c478bd9Sstevel@tonic-gate 		result = SASL_FAIL;
29387c478bd9Sstevel@tonic-gate 		goto FreeAllMem;
29397c478bd9Sstevel@tonic-gate 	    }
29407c478bd9Sstevel@tonic-gate 	    _plug_strdup(sparams->utils, value, &realm, NULL);
29417c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "nonce") == 0) {
29427c478bd9Sstevel@tonic-gate 	    _plug_strdup(sparams->utils, value, (char **) &nonce, NULL);
29437c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "qop") == 0) {
29447c478bd9Sstevel@tonic-gate 	    _plug_strdup(sparams->utils, value, &qop, NULL);
29457c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "digest-uri") == 0) {
29467c478bd9Sstevel@tonic-gate             size_t service_len;
29477c478bd9Sstevel@tonic-gate 
29487c478bd9Sstevel@tonic-gate 	    /*
29497c478bd9Sstevel@tonic-gate 	     * digest-uri-value  = serv-type "/" host [ "/" serv-name ]
29507c478bd9Sstevel@tonic-gate 	     */
29517c478bd9Sstevel@tonic-gate 
29527c478bd9Sstevel@tonic-gate 	    _plug_strdup(sparams->utils, value, &digesturi, NULL);
29537c478bd9Sstevel@tonic-gate 
29547c478bd9Sstevel@tonic-gate 	    /* verify digest-uri format */
29557c478bd9Sstevel@tonic-gate 
29567c478bd9Sstevel@tonic-gate             /* make sure it's the service that we're expecting */
29577c478bd9Sstevel@tonic-gate             service_len = strlen(sparams->service);
29587c478bd9Sstevel@tonic-gate             if (strncasecmp(digesturi, sparams->service, service_len) ||
29597c478bd9Sstevel@tonic-gate                 digesturi[service_len] != '/') {
29607c478bd9Sstevel@tonic-gate                 result = SASL_BADAUTH;
29617c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
29627c478bd9Sstevel@tonic-gate 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
29637c478bd9Sstevel@tonic-gate 				    "bad digest-uri: doesn't match service");
29647c478bd9Sstevel@tonic-gate #else
29657c478bd9Sstevel@tonic-gate                 SETERROR(sparams->utils,
29667c478bd9Sstevel@tonic-gate                          "bad digest-uri: doesn't match service");
29677c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
29687c478bd9Sstevel@tonic-gate                 goto FreeAllMem;
29697c478bd9Sstevel@tonic-gate             }
29707c478bd9Sstevel@tonic-gate 
29717c478bd9Sstevel@tonic-gate             /* xxx we don't verify the hostname component */
29727c478bd9Sstevel@tonic-gate 
29737c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "response") == 0) {
29747c478bd9Sstevel@tonic-gate 	    _plug_strdup(sparams->utils, value, &response, NULL);
29757c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "cipher") == 0) {
29767c478bd9Sstevel@tonic-gate 	    _plug_strdup(sparams->utils, value, &cipher, NULL);
29777c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "maxbuf") == 0) {
29787c478bd9Sstevel@tonic-gate 	    maxbuf_count++;
29797c478bd9Sstevel@tonic-gate 	    if (maxbuf_count != 1) {
29807c478bd9Sstevel@tonic-gate 		result = SASL_BADAUTH;
29817c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
29827c478bd9Sstevel@tonic-gate 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
29837c478bd9Sstevel@tonic-gate 				    "duplicate maxbuf: authentication aborted");
29847c478bd9Sstevel@tonic-gate #else
29857c478bd9Sstevel@tonic-gate 		SETERROR(sparams->utils,
29867c478bd9Sstevel@tonic-gate 			 "duplicate maxbuf: authentication aborted");
29877c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
29887c478bd9Sstevel@tonic-gate 		goto FreeAllMem;
29897c478bd9Sstevel@tonic-gate 	    } else if (sscanf(value, "%u", &client_maxbuf) != 1) {
29907c478bd9Sstevel@tonic-gate 		result = SASL_BADAUTH;
29917c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
29927c478bd9Sstevel@tonic-gate 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
29937c478bd9Sstevel@tonic-gate 			"invalid maxbuf parameter");
29947c478bd9Sstevel@tonic-gate #else
29957c478bd9Sstevel@tonic-gate 		SETERROR(sparams->utils, "invalid maxbuf parameter");
29967c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
29977c478bd9Sstevel@tonic-gate 		goto FreeAllMem;
29987c478bd9Sstevel@tonic-gate 	    } else {
29997c478bd9Sstevel@tonic-gate 		if (client_maxbuf <= 16) {
30007c478bd9Sstevel@tonic-gate 		    result = SASL_BADAUTH;
30017c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
30027c478bd9Sstevel@tonic-gate 		    sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
30037c478bd9Sstevel@tonic-gate 					"maxbuf parameter too small");
30047c478bd9Sstevel@tonic-gate #else
30057c478bd9Sstevel@tonic-gate 		    SETERROR(sparams->utils,
30067c478bd9Sstevel@tonic-gate 			     "maxbuf parameter too small");
30077c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
30087c478bd9Sstevel@tonic-gate 		    goto FreeAllMem;
30097c478bd9Sstevel@tonic-gate 		}
30107c478bd9Sstevel@tonic-gate 	    }
30117c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "charset") == 0) {
30127c478bd9Sstevel@tonic-gate 	    if (strcasecmp(value, "utf-8") != 0) {
30137c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
30147c478bd9Sstevel@tonic-gate 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
30157c478bd9Sstevel@tonic-gate 				    "client doesn't support UTF-8");
30167c478bd9Sstevel@tonic-gate #else
30177c478bd9Sstevel@tonic-gate 		SETERROR(sparams->utils, "client doesn't support UTF-8");
30187c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
30197c478bd9Sstevel@tonic-gate 		result = SASL_FAIL;
30207c478bd9Sstevel@tonic-gate 		goto FreeAllMem;
30217c478bd9Sstevel@tonic-gate 	    }
30227c478bd9Sstevel@tonic-gate 	    _plug_strdup(sparams->utils, value, &charset, NULL);
30237c478bd9Sstevel@tonic-gate 	} else {
30247c478bd9Sstevel@tonic-gate 	    sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
30257c478bd9Sstevel@tonic-gate 				"DIGEST-MD5 unrecognized pair %s/%s: ignoring",
30267c478bd9Sstevel@tonic-gate 				name, value);
30277c478bd9Sstevel@tonic-gate 	}
30287c478bd9Sstevel@tonic-gate     }
30297c478bd9Sstevel@tonic-gate 
30307c478bd9Sstevel@tonic-gate     /*
30317c478bd9Sstevel@tonic-gate      * username         = "username" "=" <"> username-value <">
30327c478bd9Sstevel@tonic-gate      * username-value   = qdstr-val cnonce           = "cnonce" "=" <">
30337c478bd9Sstevel@tonic-gate      * cnonce-value <"> cnonce-value     = qdstr-val nonce-count      = "nc"
30347c478bd9Sstevel@tonic-gate      * "=" nc-value nc-value         = 8LHEX qop              = "qop" "="
30357c478bd9Sstevel@tonic-gate      * qop-value digest-uri = "digest-uri" "=" digest-uri-value
30367c478bd9Sstevel@tonic-gate      * digest-uri-value  = serv-type "/" host [ "/" serv-name ] serv-type
30377c478bd9Sstevel@tonic-gate      * = 1*ALPHA host             = 1*( ALPHA | DIGIT | "-" | "." ) service
30387c478bd9Sstevel@tonic-gate      * = host response         = "response" "=" <"> response-value <">
30397c478bd9Sstevel@tonic-gate      * response-value   = 32LHEX LHEX = "0" | "1" | "2" | "3" | "4" | "5" |
30407c478bd9Sstevel@tonic-gate      * "6" | "7" | "8" | "9" | "a" | "b" | "c" | "d" | "e" | "f" cipher =
30417c478bd9Sstevel@tonic-gate      * "cipher" "=" cipher-value
30427c478bd9Sstevel@tonic-gate      */
30437c478bd9Sstevel@tonic-gate     /* Verifing that all parameters was defined */
30447c478bd9Sstevel@tonic-gate     if ((username == NULL) ||
30457c478bd9Sstevel@tonic-gate 	(nonce == NULL) ||
30467c478bd9Sstevel@tonic-gate 	(noncecount == 0) ||
30477c478bd9Sstevel@tonic-gate 	(cnonce == NULL) ||
30487c478bd9Sstevel@tonic-gate 	(digesturi == NULL) ||
30497c478bd9Sstevel@tonic-gate 	(response == NULL)) {
30507c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
30517c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
30527c478bd9Sstevel@tonic-gate 		"required parameters missing");
30537c478bd9Sstevel@tonic-gate #else
30547c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils, "required parameters missing");
30557c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
30567c478bd9Sstevel@tonic-gate 	result = SASL_BADAUTH;
30577c478bd9Sstevel@tonic-gate 	goto FreeAllMem;
30587c478bd9Sstevel@tonic-gate     }
30597c478bd9Sstevel@tonic-gate 
30607c478bd9Sstevel@tonic-gate     if (text->state == 1) {
30617c478bd9Sstevel@tonic-gate 	unsigned val = hash(username) % text->reauth->size;
30627c478bd9Sstevel@tonic-gate 
30637c478bd9Sstevel@tonic-gate 	/* reauth attempt, see if we have any info for this user */
30647c478bd9Sstevel@tonic-gate 	if (sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
30657c478bd9Sstevel@tonic-gate 	    if (text->reauth->e[val].authid &&
30667c478bd9Sstevel@tonic-gate 		!strcmp(username, text->reauth->e[val].authid)) {
30677c478bd9Sstevel@tonic-gate 
30687c478bd9Sstevel@tonic-gate 		_plug_strdup(sparams->utils, text->reauth->e[val].realm,
30697c478bd9Sstevel@tonic-gate 			     &text->realm, NULL);
30707c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
30717c478bd9Sstevel@tonic-gate 		_plug_strdup(sparams->utils, (char *)text->reauth->e[val].nonce,
30727c478bd9Sstevel@tonic-gate 			     (char **) &text->nonce, NULL);
30737c478bd9Sstevel@tonic-gate #else
30747c478bd9Sstevel@tonic-gate 		_plug_strdup(sparams->utils, text->reauth->e[val].nonce,
30757c478bd9Sstevel@tonic-gate 			     (char **) &text->nonce, NULL);
30767c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
30777c478bd9Sstevel@tonic-gate 		text->nonce_count = ++text->reauth->e[val].nonce_count;
30787c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
30797c478bd9Sstevel@tonic-gate 		_plug_strdup(sparams->utils, (char *)text->reauth->e[val].cnonce,
30807c478bd9Sstevel@tonic-gate 			     (char **) &text->cnonce, NULL);
30817c478bd9Sstevel@tonic-gate #else
30827c478bd9Sstevel@tonic-gate 		_plug_strdup(sparams->utils, text->reauth->e[val].cnonce,
30837c478bd9Sstevel@tonic-gate 			     (char **) &text->cnonce, NULL);
30847c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
30857c478bd9Sstevel@tonic-gate 		stext->timestamp = text->reauth->e[val].u.s.timestamp;
30867c478bd9Sstevel@tonic-gate 	    }
30877c478bd9Sstevel@tonic-gate 	    sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
30887c478bd9Sstevel@tonic-gate 	}
30897c478bd9Sstevel@tonic-gate 
30907c478bd9Sstevel@tonic-gate 	if (!text->nonce) {
30917c478bd9Sstevel@tonic-gate 	    /* we don't have any reauth info, so bail */
30927c478bd9Sstevel@tonic-gate 	    result = SASL_FAIL;
30937c478bd9Sstevel@tonic-gate 	    goto FreeAllMem;
30947c478bd9Sstevel@tonic-gate 	}
30957c478bd9Sstevel@tonic-gate     }
30967c478bd9Sstevel@tonic-gate 
30977c478bd9Sstevel@tonic-gate     /* Sanity check the parameters */
30987c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
30997c478bd9Sstevel@tonic-gate     if ((realm != NULL && text->realm != NULL &&
31007c478bd9Sstevel@tonic-gate 		strcmp(realm, text->realm) != 0) ||
31017c478bd9Sstevel@tonic-gate 	    (realm == NULL && text->realm != NULL) ||
31027c478bd9Sstevel@tonic-gate 	    (realm != NULL && text->realm == NULL)) {
31037c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
31047c478bd9Sstevel@tonic-gate 			    "realm changed: authentication aborted");
31057c478bd9Sstevel@tonic-gate #else
31067c478bd9Sstevel@tonic-gate     if (strcmp(realm, text->realm) != 0) {
31077c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils,
31087c478bd9Sstevel@tonic-gate 		 "realm changed: authentication aborted");
31097c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
31107c478bd9Sstevel@tonic-gate 	result = SASL_BADAUTH;
31117c478bd9Sstevel@tonic-gate 	goto FreeAllMem;
31127c478bd9Sstevel@tonic-gate     }
31137c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
31147c478bd9Sstevel@tonic-gate     if (strcmp((char *)nonce, (char *) text->nonce) != 0) {
31157c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
31167c478bd9Sstevel@tonic-gate 			    "nonce changed: authentication aborted");
31177c478bd9Sstevel@tonic-gate #else
31187c478bd9Sstevel@tonic-gate     if (strcmp(nonce, (char *) text->nonce) != 0) {
31197c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils,
31207c478bd9Sstevel@tonic-gate 		 "nonce changed: authentication aborted");
31217c478bd9Sstevel@tonic-gate #endif /* _SUN_SKD_ */
31227c478bd9Sstevel@tonic-gate 	result = SASL_BADAUTH;
31237c478bd9Sstevel@tonic-gate 	goto FreeAllMem;
31247c478bd9Sstevel@tonic-gate     }
31257c478bd9Sstevel@tonic-gate     if (noncecount != text->nonce_count) {
31267c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
31277c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
31287c478bd9Sstevel@tonic-gate 			    "incorrect nonce-count: authentication aborted");
31297c478bd9Sstevel@tonic-gate #else
31307c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils,
31317c478bd9Sstevel@tonic-gate 		 "incorrect nonce-count: authentication aborted");
31327c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
31337c478bd9Sstevel@tonic-gate 	result = SASL_BADAUTH;
31347c478bd9Sstevel@tonic-gate 	goto FreeAllMem;
31357c478bd9Sstevel@tonic-gate     }
31367c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
31377c478bd9Sstevel@tonic-gate     if (text->cnonce && strcmp((char *)cnonce, (char *)text->cnonce) != 0) {
31387c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
31397c478bd9Sstevel@tonic-gate 			    "cnonce changed: authentication aborted");
31407c478bd9Sstevel@tonic-gate #else
31417c478bd9Sstevel@tonic-gate     if (text->cnonce && strcmp(cnonce, text->cnonce) != 0) {
31427c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils,
31437c478bd9Sstevel@tonic-gate 		 "cnonce changed: authentication aborted");
31447c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
31457c478bd9Sstevel@tonic-gate 	result = SASL_BADAUTH;
31467c478bd9Sstevel@tonic-gate 	goto FreeAllMem;
31477c478bd9Sstevel@tonic-gate     }
31487c478bd9Sstevel@tonic-gate 
31497c478bd9Sstevel@tonic-gate     result = sparams->utils->prop_request(sparams->propctx, password_request);
31507c478bd9Sstevel@tonic-gate     if(result != SASL_OK) {
31517c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
31527c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
31537c478bd9Sstevel@tonic-gate 			    "unable to request user password");
31547c478bd9Sstevel@tonic-gate #else
31557c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils, "unable to resquest user password");
31567c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
31577c478bd9Sstevel@tonic-gate 	goto FreeAllMem;
31587c478bd9Sstevel@tonic-gate     }
31597c478bd9Sstevel@tonic-gate 
31607c478bd9Sstevel@tonic-gate     /* this will trigger the getting of the aux properties */
31617c478bd9Sstevel@tonic-gate     /* Note that if we don't have an authorization id, we don't use it... */
31627c478bd9Sstevel@tonic-gate     result = sparams->canon_user(sparams->utils->conn,
31637c478bd9Sstevel@tonic-gate 				 username, 0, SASL_CU_AUTHID, oparams);
31647c478bd9Sstevel@tonic-gate     if (result != SASL_OK) {
31657c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
31667c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
31677c478bd9Sstevel@tonic-gate 			    "unable canonify user and get auxprops");
31687c478bd9Sstevel@tonic-gate #else
31697c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils, "unable canonify user and get auxprops");
31707c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
31717c478bd9Sstevel@tonic-gate 	goto FreeAllMem;
31727c478bd9Sstevel@tonic-gate     }
31737c478bd9Sstevel@tonic-gate 
31747c478bd9Sstevel@tonic-gate     if (!authorization_id || !*authorization_id) {
31757c478bd9Sstevel@tonic-gate 	result = sparams->canon_user(sparams->utils->conn,
31767c478bd9Sstevel@tonic-gate 				     username, 0, SASL_CU_AUTHZID, oparams);
31777c478bd9Sstevel@tonic-gate     } else {
31787c478bd9Sstevel@tonic-gate 	result = sparams->canon_user(sparams->utils->conn,
31797c478bd9Sstevel@tonic-gate 				     authorization_id, 0, SASL_CU_AUTHZID,
31807c478bd9Sstevel@tonic-gate 				     oparams);
31817c478bd9Sstevel@tonic-gate     }
31827c478bd9Sstevel@tonic-gate 
31837c478bd9Sstevel@tonic-gate     if (result != SASL_OK) {
31847c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
31857c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
31867c478bd9Sstevel@tonic-gate 			    "unable to canonicalize authorization ID");
31877c478bd9Sstevel@tonic-gate #else
31887c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils, "unable authorization ID");
31897c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
31907c478bd9Sstevel@tonic-gate 	goto FreeAllMem;
31917c478bd9Sstevel@tonic-gate     }
31927c478bd9Sstevel@tonic-gate 
31937c478bd9Sstevel@tonic-gate     result = sparams->utils->prop_getnames(sparams->propctx, password_request,
31947c478bd9Sstevel@tonic-gate 					   auxprop_values);
31957c478bd9Sstevel@tonic-gate     if (result < 0 ||
31967c478bd9Sstevel@tonic-gate        ((!auxprop_values[0].name || !auxprop_values[0].values) &&
31977c478bd9Sstevel@tonic-gate 	(!auxprop_values[1].name || !auxprop_values[1].values))) {
31987c478bd9Sstevel@tonic-gate 	/* We didn't find this username */
31997c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
32007c478bd9Sstevel@tonic-gate 	sparams->utils->seterror(sparams->utils->conn, 0,
32017c478bd9Sstevel@tonic-gate 			gettext("no secret in database"));
32027c478bd9Sstevel@tonic-gate #else
32037c478bd9Sstevel@tonic-gate 	sparams->utils->seterror(sparams->utils->conn, 0,
32047c478bd9Sstevel@tonic-gate 				 "no secret in database");
32057c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
32067c478bd9Sstevel@tonic-gate 	result = SASL_NOUSER;
32077c478bd9Sstevel@tonic-gate 	goto FreeAllMem;
32087c478bd9Sstevel@tonic-gate     }
32097c478bd9Sstevel@tonic-gate 
32107c478bd9Sstevel@tonic-gate     if (auxprop_values[0].name && auxprop_values[0].values) {
32117c478bd9Sstevel@tonic-gate 	len = strlen(auxprop_values[0].values[0]);
32127c478bd9Sstevel@tonic-gate 	if (len == 0) {
32137c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
32147c478bd9Sstevel@tonic-gate 	    sparams->utils->seterror(sparams->utils->conn,0,
32157c478bd9Sstevel@tonic-gate 			gettext("empty secret"));
32167c478bd9Sstevel@tonic-gate #else
32177c478bd9Sstevel@tonic-gate 	    sparams->utils->seterror(sparams->utils->conn,0,
32187c478bd9Sstevel@tonic-gate 				     "empty secret");
32197c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
32207c478bd9Sstevel@tonic-gate 	    result = SASL_FAIL;
32217c478bd9Sstevel@tonic-gate 	    goto FreeAllMem;
32227c478bd9Sstevel@tonic-gate 	}
32237c478bd9Sstevel@tonic-gate 
32247c478bd9Sstevel@tonic-gate 	sec = sparams->utils->malloc(sizeof(sasl_secret_t) + len);
32257c478bd9Sstevel@tonic-gate 	if (!sec) {
32267c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
32277c478bd9Sstevel@tonic-gate 	    sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
32287c478bd9Sstevel@tonic-gate 				"unable to allocate secret");
32297c478bd9Sstevel@tonic-gate #else
32307c478bd9Sstevel@tonic-gate 	    SETERROR(sparams->utils, "unable to allocate secret");
32317c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
32327c478bd9Sstevel@tonic-gate 	    result = SASL_FAIL;
32337c478bd9Sstevel@tonic-gate 	    goto FreeAllMem;
32347c478bd9Sstevel@tonic-gate 	}
32357c478bd9Sstevel@tonic-gate 
32367c478bd9Sstevel@tonic-gate 	sec->len = len;
32377c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
32387c478bd9Sstevel@tonic-gate 	strncpy((char *)sec->data, auxprop_values[0].values[0], len + 1);
32397c478bd9Sstevel@tonic-gate #else
32407c478bd9Sstevel@tonic-gate 	strncpy(sec->data, auxprop_values[0].values[0], len + 1);
32417c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
32427c478bd9Sstevel@tonic-gate 
32437c478bd9Sstevel@tonic-gate 	/*
32447c478bd9Sstevel@tonic-gate 	 * Verifying response obtained from client
32457c478bd9Sstevel@tonic-gate 	 *
32467c478bd9Sstevel@tonic-gate 	 * H_URP = H({ username-value,":",realm-value,":",passwd}) sec->data
32477c478bd9Sstevel@tonic-gate 	 * contains H_URP
32487c478bd9Sstevel@tonic-gate 	 */
32497c478bd9Sstevel@tonic-gate 
32507c478bd9Sstevel@tonic-gate 	/* Calculate the secret from the plaintext password */
32517c478bd9Sstevel@tonic-gate 	{
32527c478bd9Sstevel@tonic-gate 	    HASH HA1;
32537c478bd9Sstevel@tonic-gate 
32547c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
32557c478bd9Sstevel@tonic-gate 	    DigestCalcSecret(sparams->utils, (unsigned char *)username,
32567c478bd9Sstevel@tonic-gate 			     (unsigned char *)text->realm, sec->data,
32577c478bd9Sstevel@tonic-gate 			     sec->len, HA1);
32587c478bd9Sstevel@tonic-gate #else
32597c478bd9Sstevel@tonic-gate 	    DigestCalcSecret(sparams->utils, username,
32607c478bd9Sstevel@tonic-gate 			     text->realm, sec->data, sec->len, HA1);
32617c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
32627c478bd9Sstevel@tonic-gate 
32637c478bd9Sstevel@tonic-gate 	    /*
32647c478bd9Sstevel@tonic-gate 	     * A1 = { H( { username-value, ":", realm-value, ":", passwd } ),
32657c478bd9Sstevel@tonic-gate 	     * ":", nonce-value, ":", cnonce-value }
32667c478bd9Sstevel@tonic-gate 	     */
32677c478bd9Sstevel@tonic-gate 
32687c478bd9Sstevel@tonic-gate 	    memcpy(A1, HA1, HASHLEN);
32697c478bd9Sstevel@tonic-gate 	    A1[HASHLEN] = '\0';
32707c478bd9Sstevel@tonic-gate 	}
32717c478bd9Sstevel@tonic-gate 
32727c478bd9Sstevel@tonic-gate 	/* We're done with sec now. Let's get rid of it */
32737c478bd9Sstevel@tonic-gate 	_plug_free_secret(sparams->utils, &sec);
32747c478bd9Sstevel@tonic-gate     } else if (auxprop_values[1].name && auxprop_values[1].values) {
32757c478bd9Sstevel@tonic-gate 	memcpy(A1, auxprop_values[1].values[0], HASHLEN);
32767c478bd9Sstevel@tonic-gate 	A1[HASHLEN] = '\0';
32777c478bd9Sstevel@tonic-gate     } else {
32787c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
32797c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
32807c478bd9Sstevel@tonic-gate 			    "Have neither type of secret");
32817c478bd9Sstevel@tonic-gate #else
32827c478bd9Sstevel@tonic-gate 	sparams->utils->seterror(sparams->utils->conn, 0,
32837c478bd9Sstevel@tonic-gate 				 "Have neither type of secret");
32847c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
32857c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
32867c478bd9Sstevel@tonic-gate 	result = SASL_FAIL;
32877c478bd9Sstevel@tonic-gate 	goto FreeAllMem;
32887c478bd9Sstevel@tonic-gate #else
32897c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
32907c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
32917c478bd9Sstevel@tonic-gate     }
32927c478bd9Sstevel@tonic-gate 
32937c478bd9Sstevel@tonic-gate     /* defaulting qop to "auth" if not specified */
32947c478bd9Sstevel@tonic-gate     if (qop == NULL) {
32957c478bd9Sstevel@tonic-gate 	_plug_strdup(sparams->utils, "auth", &qop, NULL);
32967c478bd9Sstevel@tonic-gate     }
32977c478bd9Sstevel@tonic-gate 
32987c478bd9Sstevel@tonic-gate     /* check which layer/cipher to use */
32997c478bd9Sstevel@tonic-gate     if ((!strcasecmp(qop, "auth-conf")) && (cipher != NULL)) {
33007c478bd9Sstevel@tonic-gate 	/* see what cipher was requested */
33017c478bd9Sstevel@tonic-gate 	struct digest_cipher *cptr;
33027c478bd9Sstevel@tonic-gate 
33037c478bd9Sstevel@tonic-gate #ifdef USE_UEF_SERVER
33047c478bd9Sstevel@tonic-gate 	cptr = available_ciphers1;
33057c478bd9Sstevel@tonic-gate #else
33067c478bd9Sstevel@tonic-gate 	cptr = available_ciphers;
33077c478bd9Sstevel@tonic-gate #endif
33087c478bd9Sstevel@tonic-gate 	while (cptr->name) {
33097c478bd9Sstevel@tonic-gate 	    /* find the cipher requested & make sure it's one we're happy
33107c478bd9Sstevel@tonic-gate 	       with by policy */
33117c478bd9Sstevel@tonic-gate 	    if (!strcasecmp(cipher, cptr->name) &&
33127c478bd9Sstevel@tonic-gate 		stext->requiressf <= cptr->ssf &&
33137c478bd9Sstevel@tonic-gate 		stext->limitssf >= cptr->ssf) {
33147c478bd9Sstevel@tonic-gate 		/* found it! */
33157c478bd9Sstevel@tonic-gate 		break;
33167c478bd9Sstevel@tonic-gate 	    }
33177c478bd9Sstevel@tonic-gate 	    cptr++;
33187c478bd9Sstevel@tonic-gate 	}
33197c478bd9Sstevel@tonic-gate 
33207c478bd9Sstevel@tonic-gate 	if (cptr->name) {
33217c478bd9Sstevel@tonic-gate 	    text->cipher_enc = cptr->cipher_enc;
33227c478bd9Sstevel@tonic-gate 	    text->cipher_dec = cptr->cipher_dec;
33237c478bd9Sstevel@tonic-gate 	    text->cipher_init = cptr->cipher_init;
33247c478bd9Sstevel@tonic-gate 	    text->cipher_free = cptr->cipher_free;
33257c478bd9Sstevel@tonic-gate 	    oparams->mech_ssf = cptr->ssf;
33267c478bd9Sstevel@tonic-gate 	    n = cptr->n;
33277c478bd9Sstevel@tonic-gate 	} else {
33287c478bd9Sstevel@tonic-gate 	    /* erg? client requested something we didn't advertise! */
33297c478bd9Sstevel@tonic-gate 	    sparams->utils->log(sparams->utils->conn, SASL_LOG_WARN,
33307c478bd9Sstevel@tonic-gate 				"protocol violation: client requested invalid cipher");
33317c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
33327c478bd9Sstevel@tonic-gate 	    SETERROR(sparams->utils, "client requested invalid cipher");
33337c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
33347c478bd9Sstevel@tonic-gate 	    /* Mark that we attempted security layer negotiation */
33357c478bd9Sstevel@tonic-gate 	    oparams->mech_ssf = 2;
33367c478bd9Sstevel@tonic-gate 	    result = SASL_FAIL;
33377c478bd9Sstevel@tonic-gate 	    goto FreeAllMem;
33387c478bd9Sstevel@tonic-gate 	}
33397c478bd9Sstevel@tonic-gate 
33407c478bd9Sstevel@tonic-gate 	oparams->encode=&digestmd5_privacy_encode;
33417c478bd9Sstevel@tonic-gate 	oparams->decode=&digestmd5_privacy_decode;
33427c478bd9Sstevel@tonic-gate     } else if (!strcasecmp(qop, "auth-int") &&
33437c478bd9Sstevel@tonic-gate 	       stext->requiressf <= 1 && stext->limitssf >= 1) {
33447c478bd9Sstevel@tonic-gate 	oparams->encode = &digestmd5_integrity_encode;
33457c478bd9Sstevel@tonic-gate 	oparams->decode = &digestmd5_integrity_decode;
33467c478bd9Sstevel@tonic-gate 	oparams->mech_ssf = 1;
33477c478bd9Sstevel@tonic-gate     } else if (!strcasecmp(qop, "auth") && stext->requiressf == 0) {
33487c478bd9Sstevel@tonic-gate 	oparams->encode = NULL;
33497c478bd9Sstevel@tonic-gate 	oparams->decode = NULL;
33507c478bd9Sstevel@tonic-gate 	oparams->mech_ssf = 0;
33517c478bd9Sstevel@tonic-gate     } else {
33527c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
33537c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
33547c478bd9Sstevel@tonic-gate 			    "protocol violation: client requested invalid qop");
33557c478bd9Sstevel@tonic-gate #else
33567c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils,
33577c478bd9Sstevel@tonic-gate 		 "protocol violation: client requested invalid qop");
33587c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
33597c478bd9Sstevel@tonic-gate 	result = SASL_FAIL;
33607c478bd9Sstevel@tonic-gate 	goto FreeAllMem;
33617c478bd9Sstevel@tonic-gate     }
33627c478bd9Sstevel@tonic-gate 
33637c478bd9Sstevel@tonic-gate     serverresponse = create_response(text,
33647c478bd9Sstevel@tonic-gate 				     sparams->utils,
33657c478bd9Sstevel@tonic-gate 				     text->nonce,
33667c478bd9Sstevel@tonic-gate 				     text->nonce_count,
33677c478bd9Sstevel@tonic-gate 				     cnonce,
33687c478bd9Sstevel@tonic-gate 				     qop,
33697c478bd9Sstevel@tonic-gate 				     digesturi,
33707c478bd9Sstevel@tonic-gate 				     A1,
33717c478bd9Sstevel@tonic-gate 				     authorization_id,
33727c478bd9Sstevel@tonic-gate 				     &text->response_value);
33737c478bd9Sstevel@tonic-gate 
33747c478bd9Sstevel@tonic-gate     if (serverresponse == NULL) {
33757c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
33767c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils, "internal error: unable to create response");
33777c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
33787c478bd9Sstevel@tonic-gate 	result = SASL_NOMEM;
33797c478bd9Sstevel@tonic-gate 	goto FreeAllMem;
33807c478bd9Sstevel@tonic-gate     }
33817c478bd9Sstevel@tonic-gate 
33827c478bd9Sstevel@tonic-gate     /* if ok verified */
33837c478bd9Sstevel@tonic-gate     if (strcmp(serverresponse, response) != 0) {
33847c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
33857c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils,
33867c478bd9Sstevel@tonic-gate 		 gettext("client response doesn't match what we generated"));
33877c478bd9Sstevel@tonic-gate #else
33887c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils,
33897c478bd9Sstevel@tonic-gate 		 "client response doesn't match what we generated");
33907c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
33917c478bd9Sstevel@tonic-gate 	result = SASL_BADAUTH;
33927c478bd9Sstevel@tonic-gate 
33937c478bd9Sstevel@tonic-gate 	goto FreeAllMem;
33947c478bd9Sstevel@tonic-gate     }
33957c478bd9Sstevel@tonic-gate 
33967c478bd9Sstevel@tonic-gate     /* see if our nonce expired */
33977c478bd9Sstevel@tonic-gate     if (text->reauth->timeout &&
33987c478bd9Sstevel@tonic-gate 	time(0) - stext->timestamp > text->reauth->timeout) {
33997c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
34007c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils, gettext("server nonce expired"));
34017c478bd9Sstevel@tonic-gate #else
34027c478bd9Sstevel@tonic-gate 	SETERROR(sparams->utils, "server nonce expired");
34037c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
34047c478bd9Sstevel@tonic-gate 	stext->stale = 1;
34057c478bd9Sstevel@tonic-gate 	result = SASL_BADAUTH;
34067c478bd9Sstevel@tonic-gate 
34077c478bd9Sstevel@tonic-gate 	goto FreeAllMem;
34087c478bd9Sstevel@tonic-gate      }
34097c478bd9Sstevel@tonic-gate 
34107c478bd9Sstevel@tonic-gate     /*
34117c478bd9Sstevel@tonic-gate      * nothing more to do; authenticated set oparams information
34127c478bd9Sstevel@tonic-gate      */
34137c478bd9Sstevel@tonic-gate     oparams->doneflag = 1;
34147c478bd9Sstevel@tonic-gate     oparams->maxoutbuf = client_maxbuf - 4;
34157c478bd9Sstevel@tonic-gate     if (oparams->mech_ssf > 1) {
34167c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
34177c478bd9Sstevel@tonic-gate 	if (oparams->maxoutbuf <= 25) {
34187c478bd9Sstevel@tonic-gate 	     result = SASL_BADPARAM;
34197c478bd9Sstevel@tonic-gate 	     goto FreeAllMem;
34207c478bd9Sstevel@tonic-gate 	}
34217c478bd9Sstevel@tonic-gate #endif
34227c478bd9Sstevel@tonic-gate 	/* MAC block (privacy) */
34237c478bd9Sstevel@tonic-gate 	oparams->maxoutbuf -= 25;
34247c478bd9Sstevel@tonic-gate     } else if(oparams->mech_ssf == 1) {
34257c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
34267c478bd9Sstevel@tonic-gate 	if (oparams->maxoutbuf <= 16) {
34277c478bd9Sstevel@tonic-gate 	     result = SASL_BADPARAM;
34287c478bd9Sstevel@tonic-gate 	     goto FreeAllMem;
34297c478bd9Sstevel@tonic-gate 	}
34307c478bd9Sstevel@tonic-gate #endif
34317c478bd9Sstevel@tonic-gate 	/* MAC block (integrity) */
34327c478bd9Sstevel@tonic-gate 	oparams->maxoutbuf -= 16;
34337c478bd9Sstevel@tonic-gate     }
34347c478bd9Sstevel@tonic-gate 
34357c478bd9Sstevel@tonic-gate     oparams->param_version = 0;
34367c478bd9Sstevel@tonic-gate 
34377c478bd9Sstevel@tonic-gate     text->seqnum = 0;		/* for integrity/privacy */
34387c478bd9Sstevel@tonic-gate     text->rec_seqnum = 0;	/* for integrity/privacy */
34397c478bd9Sstevel@tonic-gate     text->in_maxbuf =
34407c478bd9Sstevel@tonic-gate        sparams->props.maxbufsize ? sparams->props.maxbufsize : DEFAULT_BUFSIZE;
34417c478bd9Sstevel@tonic-gate     text->utils = sparams->utils;
34427c478bd9Sstevel@tonic-gate 
34437c478bd9Sstevel@tonic-gate     /* used by layers */
34447c478bd9Sstevel@tonic-gate     text->needsize = 4;
34457c478bd9Sstevel@tonic-gate     text->buffer = NULL;
34467c478bd9Sstevel@tonic-gate 
34477c478bd9Sstevel@tonic-gate     if (oparams->mech_ssf > 0) {
34487c478bd9Sstevel@tonic-gate 	char enckey[16];
34497c478bd9Sstevel@tonic-gate 	char deckey[16];
34507c478bd9Sstevel@tonic-gate 
34517c478bd9Sstevel@tonic-gate 	create_layer_keys(text, sparams->utils,text->HA1,n,enckey,deckey);
34527c478bd9Sstevel@tonic-gate 
34537c478bd9Sstevel@tonic-gate 	/* initialize cipher if need be */
34547c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
34557c478bd9Sstevel@tonic-gate 	if (text->cipher_init) {
34567c478bd9Sstevel@tonic-gate 	    if (text->cipher_free)
34577c478bd9Sstevel@tonic-gate 		text->cipher_free(text);
34587c478bd9Sstevel@tonic-gate 	    if ((result = text->cipher_init(text, enckey, deckey)) != SASL_OK) {
34597c478bd9Sstevel@tonic-gate 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
34607c478bd9Sstevel@tonic-gate 				"couldn't init cipher");
34617c478bd9Sstevel@tonic-gate 		goto FreeAllMem;
34627c478bd9Sstevel@tonic-gate 	    }
34637c478bd9Sstevel@tonic-gate 	}
34647c478bd9Sstevel@tonic-gate #else
34657c478bd9Sstevel@tonic-gate 	if (text->cipher_init)
34667c478bd9Sstevel@tonic-gate 	    if (text->cipher_init(text, enckey, deckey) != SASL_OK) {
34677c478bd9Sstevel@tonic-gate 		sparams->utils->seterror(sparams->utils->conn, 0,
34687c478bd9Sstevel@tonic-gate 					 "couldn't init cipher");
34697c478bd9Sstevel@tonic-gate 	    }
34707c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
34717c478bd9Sstevel@tonic-gate     }
34727c478bd9Sstevel@tonic-gate 
34737c478bd9Sstevel@tonic-gate     /*
34747c478bd9Sstevel@tonic-gate      * The server receives and validates the "digest-response". The server
34757c478bd9Sstevel@tonic-gate      * checks that the nonce-count is "00000001". If it supports subsequent
34767c478bd9Sstevel@tonic-gate      * authentication, it saves the value of the nonce and the nonce-count.
34777c478bd9Sstevel@tonic-gate      */
34787c478bd9Sstevel@tonic-gate 
34797c478bd9Sstevel@tonic-gate     /*
34807c478bd9Sstevel@tonic-gate      * The "username-value", "realm-value" and "passwd" are encoded according
34817c478bd9Sstevel@tonic-gate      * to the value of the "charset" directive. If "charset=UTF-8" is
34827c478bd9Sstevel@tonic-gate      * present, and all the characters of either "username-value" or "passwd"
34837c478bd9Sstevel@tonic-gate      * are in the ISO 8859-1 character set, then it must be converted to
34847c478bd9Sstevel@tonic-gate      * UTF-8 before being hashed. A sample implementation of this conversion
34857c478bd9Sstevel@tonic-gate      * is in section 8.
34867c478bd9Sstevel@tonic-gate      */
34877c478bd9Sstevel@tonic-gate 
34887c478bd9Sstevel@tonic-gate     /* add to challenge */
34897c478bd9Sstevel@tonic-gate     {
34907c478bd9Sstevel@tonic-gate 	unsigned resplen =
34917c478bd9Sstevel@tonic-gate 	    strlen(text->response_value) + strlen("rspauth") + 3;
34927c478bd9Sstevel@tonic-gate 
34937c478bd9Sstevel@tonic-gate 	result = _plug_buf_alloc(sparams->utils, &(text->out_buf),
34947c478bd9Sstevel@tonic-gate 				 &(text->out_buf_len), resplen);
34957c478bd9Sstevel@tonic-gate 	if(result != SASL_OK) {
34967c478bd9Sstevel@tonic-gate 	    goto FreeAllMem;
34977c478bd9Sstevel@tonic-gate 	}
34987c478bd9Sstevel@tonic-gate 
34997c478bd9Sstevel@tonic-gate 	sprintf(text->out_buf, "rspauth=%s", text->response_value);
35007c478bd9Sstevel@tonic-gate 
35017c478bd9Sstevel@tonic-gate 	/* self check */
35027c478bd9Sstevel@tonic-gate 	if (strlen(text->out_buf) > 2048) {
35037c478bd9Sstevel@tonic-gate 	    result = SASL_FAIL;
35047c478bd9Sstevel@tonic-gate 	    goto FreeAllMem;
35057c478bd9Sstevel@tonic-gate 	}
35067c478bd9Sstevel@tonic-gate     }
35077c478bd9Sstevel@tonic-gate 
35087c478bd9Sstevel@tonic-gate     *serveroutlen = strlen(text->out_buf);
35097c478bd9Sstevel@tonic-gate     *serverout = text->out_buf;
35107c478bd9Sstevel@tonic-gate 
35117c478bd9Sstevel@tonic-gate     result = SASL_OK;
35127c478bd9Sstevel@tonic-gate 
35137c478bd9Sstevel@tonic-gate   FreeAllMem:
35147c478bd9Sstevel@tonic-gate     if (text->reauth->timeout &&
35157c478bd9Sstevel@tonic-gate 	sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
35167c478bd9Sstevel@tonic-gate 	unsigned val = hash(username) % text->reauth->size;
35177c478bd9Sstevel@tonic-gate 
35187c478bd9Sstevel@tonic-gate 	switch (result) {
35197c478bd9Sstevel@tonic-gate 	case SASL_OK:
35207c478bd9Sstevel@tonic-gate 	    /* successful auth, setup for future reauth */
35217c478bd9Sstevel@tonic-gate 	    if (text->nonce_count == 1) {
35227c478bd9Sstevel@tonic-gate 		/* successful initial auth, create new entry */
35237c478bd9Sstevel@tonic-gate 		clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
35247c478bd9Sstevel@tonic-gate 		text->reauth->e[val].authid = username; username = NULL;
35257c478bd9Sstevel@tonic-gate 		text->reauth->e[val].realm = text->realm; text->realm = NULL;
35267c478bd9Sstevel@tonic-gate 		text->reauth->e[val].nonce = text->nonce; text->nonce = NULL;
35277c478bd9Sstevel@tonic-gate 		text->reauth->e[val].cnonce = cnonce; cnonce = NULL;
35287c478bd9Sstevel@tonic-gate 	    }
35297c478bd9Sstevel@tonic-gate 	    if (text->nonce_count <= text->reauth->e[val].nonce_count) {
35307c478bd9Sstevel@tonic-gate 		/* paranoia.  prevent replay attacks */
35317c478bd9Sstevel@tonic-gate 		clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
35327c478bd9Sstevel@tonic-gate 	    }
35337c478bd9Sstevel@tonic-gate 	    else {
35347c478bd9Sstevel@tonic-gate 		text->reauth->e[val].nonce_count = text->nonce_count;
35357c478bd9Sstevel@tonic-gate 		text->reauth->e[val].u.s.timestamp = time(0);
35367c478bd9Sstevel@tonic-gate 	    }
35377c478bd9Sstevel@tonic-gate 	    break;
35387c478bd9Sstevel@tonic-gate 	default:
35397c478bd9Sstevel@tonic-gate 	    if (text->nonce_count > 1) {
35407c478bd9Sstevel@tonic-gate 		/* failed reauth, clear entry */
35417c478bd9Sstevel@tonic-gate 		clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
35427c478bd9Sstevel@tonic-gate 	    }
35437c478bd9Sstevel@tonic-gate 	    else {
35447c478bd9Sstevel@tonic-gate 		/* failed initial auth, leave existing cache */
35457c478bd9Sstevel@tonic-gate 	    }
35467c478bd9Sstevel@tonic-gate 	}
35477c478bd9Sstevel@tonic-gate 	sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
35487c478bd9Sstevel@tonic-gate     }
35497c478bd9Sstevel@tonic-gate 
35507c478bd9Sstevel@tonic-gate     /* free everything */
35517c478bd9Sstevel@tonic-gate     if (in_start) sparams->utils->free (in_start);
35527c478bd9Sstevel@tonic-gate 
35537c478bd9Sstevel@tonic-gate     if (username != NULL)
35547c478bd9Sstevel@tonic-gate 	sparams->utils->free (username);
35557c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
35567c478bd9Sstevel@tonic-gate     if (authorization_id != NULL)
35577c478bd9Sstevel@tonic-gate 	sparams->utils->free (authorization_id);
35587c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
35597c478bd9Sstevel@tonic-gate     if (realm != NULL)
35607c478bd9Sstevel@tonic-gate 	sparams->utils->free (realm);
35617c478bd9Sstevel@tonic-gate     if (nonce != NULL)
35627c478bd9Sstevel@tonic-gate 	sparams->utils->free (nonce);
35637c478bd9Sstevel@tonic-gate     if (cnonce != NULL)
35647c478bd9Sstevel@tonic-gate 	sparams->utils->free (cnonce);
35657c478bd9Sstevel@tonic-gate     if (response != NULL)
35667c478bd9Sstevel@tonic-gate 	sparams->utils->free (response);
35677c478bd9Sstevel@tonic-gate     if (cipher != NULL)
35687c478bd9Sstevel@tonic-gate 	sparams->utils->free (cipher);
35697c478bd9Sstevel@tonic-gate     if (serverresponse != NULL)
35707c478bd9Sstevel@tonic-gate 	sparams->utils->free(serverresponse);
35717c478bd9Sstevel@tonic-gate     if (charset != NULL)
35727c478bd9Sstevel@tonic-gate 	sparams->utils->free (charset);
35737c478bd9Sstevel@tonic-gate     if (digesturi != NULL)
35747c478bd9Sstevel@tonic-gate 	sparams->utils->free (digesturi);
35757c478bd9Sstevel@tonic-gate     if (qop!=NULL)
35767c478bd9Sstevel@tonic-gate 	sparams->utils->free (qop);
35777c478bd9Sstevel@tonic-gate     if (sec)
35787c478bd9Sstevel@tonic-gate 	_plug_free_secret(sparams->utils, &sec);
35797c478bd9Sstevel@tonic-gate 
35807c478bd9Sstevel@tonic-gate     return result;
35817c478bd9Sstevel@tonic-gate }
35827c478bd9Sstevel@tonic-gate 
35837c478bd9Sstevel@tonic-gate static int
35847c478bd9Sstevel@tonic-gate digestmd5_server_mech_step(void *conn_context,
35857c478bd9Sstevel@tonic-gate 			   sasl_server_params_t *sparams,
35867c478bd9Sstevel@tonic-gate 			   const char *clientin,
35877c478bd9Sstevel@tonic-gate 			   unsigned clientinlen,
35887c478bd9Sstevel@tonic-gate 			   const char **serverout,
35897c478bd9Sstevel@tonic-gate 			   unsigned *serveroutlen,
35907c478bd9Sstevel@tonic-gate 			   sasl_out_params_t *oparams)
35917c478bd9Sstevel@tonic-gate {
35927c478bd9Sstevel@tonic-gate     context_t *text = (context_t *) conn_context;
35937c478bd9Sstevel@tonic-gate     server_context_t *stext = (server_context_t *) conn_context;
35947c478bd9Sstevel@tonic-gate 
35957c478bd9Sstevel@tonic-gate     if (clientinlen > 4096) return SASL_BADPROT;
35967c478bd9Sstevel@tonic-gate 
35977c478bd9Sstevel@tonic-gate     *serverout = NULL;
35987c478bd9Sstevel@tonic-gate     *serveroutlen = 0;
35997c478bd9Sstevel@tonic-gate 
36007c478bd9Sstevel@tonic-gate     switch (text->state) {
36017c478bd9Sstevel@tonic-gate 
36027c478bd9Sstevel@tonic-gate     case 1:
36037c478bd9Sstevel@tonic-gate 	/* setup SSF limits */
36047c478bd9Sstevel@tonic-gate 	if (!sparams->props.maxbufsize) {
36057c478bd9Sstevel@tonic-gate 	    stext->limitssf = 0;
36067c478bd9Sstevel@tonic-gate 	    stext->requiressf = 0;
36077c478bd9Sstevel@tonic-gate 	} else {
36087c478bd9Sstevel@tonic-gate 	    if (sparams->props.max_ssf < sparams->external_ssf) {
36097c478bd9Sstevel@tonic-gate 		stext->limitssf = 0;
36107c478bd9Sstevel@tonic-gate 	    } else {
36117c478bd9Sstevel@tonic-gate 		stext->limitssf =
36127c478bd9Sstevel@tonic-gate 		    sparams->props.max_ssf - sparams->external_ssf;
36137c478bd9Sstevel@tonic-gate 	    }
36147c478bd9Sstevel@tonic-gate 	    if (sparams->props.min_ssf < sparams->external_ssf) {
36157c478bd9Sstevel@tonic-gate 		stext->requiressf = 0;
36167c478bd9Sstevel@tonic-gate 	    } else {
36177c478bd9Sstevel@tonic-gate 		stext->requiressf =
36187c478bd9Sstevel@tonic-gate 		    sparams->props.min_ssf - sparams->external_ssf;
36197c478bd9Sstevel@tonic-gate 	    }
36207c478bd9Sstevel@tonic-gate 	}
36217c478bd9Sstevel@tonic-gate 
36227c478bd9Sstevel@tonic-gate         if (clientin && text->reauth->timeout) {
36237c478bd9Sstevel@tonic-gate 	    /* here's where we attempt fast reauth if possible */
36247c478bd9Sstevel@tonic-gate 	    if (digestmd5_server_mech_step2(stext, sparams,
36257c478bd9Sstevel@tonic-gate 					    clientin, clientinlen,
36267c478bd9Sstevel@tonic-gate 					    serverout, serveroutlen,
36277c478bd9Sstevel@tonic-gate 					    oparams) == SASL_OK) {
36287c478bd9Sstevel@tonic-gate 		return SASL_OK;
36297c478bd9Sstevel@tonic-gate 	    }
36307c478bd9Sstevel@tonic-gate 
36317c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
36327c478bd9Sstevel@tonic-gate 	    sparams->utils->log(sparams->utils->conn, SASL_LOG_WARN,
36337c478bd9Sstevel@tonic-gate 				"DIGEST-MD5 reauth failed");
36347c478bd9Sstevel@tonic-gate #else
36357c478bd9Sstevel@tonic-gate 	    sparams->utils->log(NULL, SASL_LOG_WARN,
36367c478bd9Sstevel@tonic-gate 				"DIGEST-MD5 reauth failed\n");
36377c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
36387c478bd9Sstevel@tonic-gate 
36397c478bd9Sstevel@tonic-gate 	    /* re-initialize everything for a fresh start */
36407c478bd9Sstevel@tonic-gate 	    memset(oparams, 0, sizeof(sasl_out_params_t));
36417c478bd9Sstevel@tonic-gate 
36427c478bd9Sstevel@tonic-gate 	    /* fall through and issue challenge */
36437c478bd9Sstevel@tonic-gate 	}
36447c478bd9Sstevel@tonic-gate 
36457c478bd9Sstevel@tonic-gate 	return digestmd5_server_mech_step1(stext, sparams,
36467c478bd9Sstevel@tonic-gate 					   clientin, clientinlen,
36477c478bd9Sstevel@tonic-gate 					   serverout, serveroutlen, oparams);
36487c478bd9Sstevel@tonic-gate 
36497c478bd9Sstevel@tonic-gate     case 2:
36507c478bd9Sstevel@tonic-gate 	return digestmd5_server_mech_step2(stext, sparams,
36517c478bd9Sstevel@tonic-gate 					   clientin, clientinlen,
36527c478bd9Sstevel@tonic-gate 					   serverout, serveroutlen, oparams);
36537c478bd9Sstevel@tonic-gate 
36547c478bd9Sstevel@tonic-gate     default:
36557c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
36567c478bd9Sstevel@tonic-gate 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
36577c478bd9Sstevel@tonic-gate 			    "Invalid DIGEST-MD5 server step %d", text->state);
36587c478bd9Sstevel@tonic-gate #else
36597c478bd9Sstevel@tonic-gate 	sparams->utils->log(NULL, SASL_LOG_ERR,
36607c478bd9Sstevel@tonic-gate 			    "Invalid DIGEST-MD5 server step %d\n", text->state);
36617c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
36627c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
36637c478bd9Sstevel@tonic-gate     }
36647c478bd9Sstevel@tonic-gate 
36657c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
36667c478bd9Sstevel@tonic-gate     return SASL_FAIL; /* should never get here */
36677c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
36687c478bd9Sstevel@tonic-gate }
36697c478bd9Sstevel@tonic-gate 
36707c478bd9Sstevel@tonic-gate static void
36717c478bd9Sstevel@tonic-gate digestmd5_server_mech_dispose(void *conn_context, const sasl_utils_t *utils)
36727c478bd9Sstevel@tonic-gate {
36737c478bd9Sstevel@tonic-gate     server_context_t *stext = (server_context_t *) conn_context;
36747c478bd9Sstevel@tonic-gate 
36757c478bd9Sstevel@tonic-gate     if (!stext || !utils) return;
36767c478bd9Sstevel@tonic-gate 
36777c478bd9Sstevel@tonic-gate     digestmd5_common_mech_dispose(conn_context, utils);
36787c478bd9Sstevel@tonic-gate }
36797c478bd9Sstevel@tonic-gate 
36807c478bd9Sstevel@tonic-gate static sasl_server_plug_t digestmd5_server_plugins[] =
36817c478bd9Sstevel@tonic-gate {
36827c478bd9Sstevel@tonic-gate     {
36837c478bd9Sstevel@tonic-gate 	"DIGEST-MD5",			/* mech_name */
36847c478bd9Sstevel@tonic-gate #ifdef WITH_RC4
36857c478bd9Sstevel@tonic-gate 	128,				/* max_ssf */
36867c478bd9Sstevel@tonic-gate #elif WITH_DES
36877c478bd9Sstevel@tonic-gate 	112,
36887c478bd9Sstevel@tonic-gate #else
36897c478bd9Sstevel@tonic-gate 	0,
36907c478bd9Sstevel@tonic-gate #endif
36917c478bd9Sstevel@tonic-gate 	SASL_SEC_NOPLAINTEXT
36927c478bd9Sstevel@tonic-gate 	| SASL_SEC_NOANONYMOUS
36937c478bd9Sstevel@tonic-gate 	| SASL_SEC_MUTUAL_AUTH,		/* security_flags */
36947c478bd9Sstevel@tonic-gate 	SASL_FEAT_ALLOWS_PROXY,		/* features */
36957c478bd9Sstevel@tonic-gate 	NULL,				/* glob_context */
36967c478bd9Sstevel@tonic-gate 	&digestmd5_server_mech_new,	/* mech_new */
36977c478bd9Sstevel@tonic-gate 	&digestmd5_server_mech_step,	/* mech_step */
36987c478bd9Sstevel@tonic-gate 	&digestmd5_server_mech_dispose,	/* mech_dispose */
36997c478bd9Sstevel@tonic-gate 	&digestmd5_common_mech_free,	/* mech_free */
37007c478bd9Sstevel@tonic-gate 	NULL,				/* setpass */
37017c478bd9Sstevel@tonic-gate 	NULL,				/* user_query */
37027c478bd9Sstevel@tonic-gate 	NULL,				/* idle */
37037c478bd9Sstevel@tonic-gate 	NULL,				/* mech avail */
37047c478bd9Sstevel@tonic-gate 	NULL				/* spare */
37057c478bd9Sstevel@tonic-gate     }
37067c478bd9Sstevel@tonic-gate };
37077c478bd9Sstevel@tonic-gate 
37087c478bd9Sstevel@tonic-gate int digestmd5_server_plug_init(sasl_utils_t *utils,
37097c478bd9Sstevel@tonic-gate 			       int maxversion,
37107c478bd9Sstevel@tonic-gate 			       int *out_version,
37117c478bd9Sstevel@tonic-gate 			       sasl_server_plug_t **pluglist,
37127c478bd9Sstevel@tonic-gate 			       int *plugcount)
37137c478bd9Sstevel@tonic-gate {
37147c478bd9Sstevel@tonic-gate     reauth_cache_t *reauth_cache;
37157c478bd9Sstevel@tonic-gate     const char *timeout = NULL;
37167c478bd9Sstevel@tonic-gate     unsigned int len;
37177c478bd9Sstevel@tonic-gate #if defined _SUN_SDK_  && defined USE_UEF
37187c478bd9Sstevel@tonic-gate     int ret;
37197c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ && USE_UEF */
37207c478bd9Sstevel@tonic-gate 
37217c478bd9Sstevel@tonic-gate     if (maxversion < SASL_SERVER_PLUG_VERSION)
37227c478bd9Sstevel@tonic-gate 	return SASL_BADVERS;
37237c478bd9Sstevel@tonic-gate 
37247c478bd9Sstevel@tonic-gate #if defined _SUN_SDK_  && defined USE_UEF
37257c478bd9Sstevel@tonic-gate     if ((ret = uef_init(utils)) != SASL_OK)
37267c478bd9Sstevel@tonic-gate 	return ret;
37277c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ && USE_UEF */
37287c478bd9Sstevel@tonic-gate 
37297c478bd9Sstevel@tonic-gate     /* reauth cache */
37307c478bd9Sstevel@tonic-gate     reauth_cache = utils->malloc(sizeof(reauth_cache_t));
37317c478bd9Sstevel@tonic-gate     if (reauth_cache == NULL)
37327c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
37337c478bd9Sstevel@tonic-gate     memset(reauth_cache, 0, sizeof(reauth_cache_t));
37347c478bd9Sstevel@tonic-gate     reauth_cache->i_am = SERVER;
37357c478bd9Sstevel@tonic-gate 
37367c478bd9Sstevel@tonic-gate     /* fetch and canonify the reauth_timeout */
37377c478bd9Sstevel@tonic-gate     utils->getopt(utils->getopt_context, "DIGEST-MD5", "reauth_timeout",
37387c478bd9Sstevel@tonic-gate 		  &timeout, &len);
37397c478bd9Sstevel@tonic-gate     if (timeout)
37407c478bd9Sstevel@tonic-gate 	reauth_cache->timeout = (time_t) 60 * strtol(timeout, NULL, 10);
37417c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
37427c478bd9Sstevel@tonic-gate     else
37437c478bd9Sstevel@tonic-gate 	reauth_cache->timeout = 0;
37447c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
37457c478bd9Sstevel@tonic-gate     if (reauth_cache->timeout < 0)
37467c478bd9Sstevel@tonic-gate 	reauth_cache->timeout = 0;
37477c478bd9Sstevel@tonic-gate 
37487c478bd9Sstevel@tonic-gate     if (reauth_cache->timeout) {
37497c478bd9Sstevel@tonic-gate 	/* mutex */
37507c478bd9Sstevel@tonic-gate 	reauth_cache->mutex = utils->mutex_alloc();
37517c478bd9Sstevel@tonic-gate 	if (!reauth_cache->mutex)
37527c478bd9Sstevel@tonic-gate 	    return SASL_FAIL;
37537c478bd9Sstevel@tonic-gate 
37547c478bd9Sstevel@tonic-gate 	/* entries */
37557c478bd9Sstevel@tonic-gate 	reauth_cache->size = 100;
37567c478bd9Sstevel@tonic-gate 	reauth_cache->e = utils->malloc(reauth_cache->size *
37577c478bd9Sstevel@tonic-gate 					sizeof(reauth_entry_t));
37587c478bd9Sstevel@tonic-gate 	if (reauth_cache->e == NULL)
37597c478bd9Sstevel@tonic-gate 	    return SASL_NOMEM;
37607c478bd9Sstevel@tonic-gate 	memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t));
37617c478bd9Sstevel@tonic-gate     }
37627c478bd9Sstevel@tonic-gate 
37637c478bd9Sstevel@tonic-gate     digestmd5_server_plugins[0].glob_context = reauth_cache;
37647c478bd9Sstevel@tonic-gate 
37657c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
37667c478bd9Sstevel@tonic-gate #ifdef USE_UEF_CLIENT
37677c478bd9Sstevel@tonic-gate     digestmd5_server_plugins[0].max_ssf = uef_max_ssf;
37687c478bd9Sstevel@tonic-gate #endif /* USE_UEF_CLIENT */
37697c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
37707c478bd9Sstevel@tonic-gate 
37717c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
37727c478bd9Sstevel@tonic-gate     /*
37737c478bd9Sstevel@tonic-gate      * Let libsasl know that we are a "Sun" plugin so that privacy
37747c478bd9Sstevel@tonic-gate      * and integrity will be allowed.
37757c478bd9Sstevel@tonic-gate      */
37767c478bd9Sstevel@tonic-gate     REG_PLUG("DIGEST-MD5", digestmd5_server_plugins);
37777c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
37787c478bd9Sstevel@tonic-gate 
37797c478bd9Sstevel@tonic-gate     *out_version = SASL_SERVER_PLUG_VERSION;
37807c478bd9Sstevel@tonic-gate     *pluglist = digestmd5_server_plugins;
37817c478bd9Sstevel@tonic-gate     *plugcount = 1;
37827c478bd9Sstevel@tonic-gate 
37837c478bd9Sstevel@tonic-gate     return SASL_OK;
37847c478bd9Sstevel@tonic-gate }
37857c478bd9Sstevel@tonic-gate 
37867c478bd9Sstevel@tonic-gate /*****************************  Client Section  *****************************/
37877c478bd9Sstevel@tonic-gate 
37887c478bd9Sstevel@tonic-gate typedef struct client_context {
37897c478bd9Sstevel@tonic-gate     context_t common;
37907c478bd9Sstevel@tonic-gate 
37917c478bd9Sstevel@tonic-gate     sasl_secret_t *password;	/* user password */
37927c478bd9Sstevel@tonic-gate     unsigned int free_password; /* set if we need to free password */
37937c478bd9Sstevel@tonic-gate 
37947c478bd9Sstevel@tonic-gate     int protection;
37957c478bd9Sstevel@tonic-gate     struct digest_cipher *cipher;
37967c478bd9Sstevel@tonic-gate     unsigned int server_maxbuf;
37977c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
37987c478bd9Sstevel@tonic-gate     void *h;
37997c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
38007c478bd9Sstevel@tonic-gate } client_context_t;
38017c478bd9Sstevel@tonic-gate 
38027c478bd9Sstevel@tonic-gate /* calculate H(A1) as per spec */
38037c478bd9Sstevel@tonic-gate static void
38047c478bd9Sstevel@tonic-gate DigestCalcHA1(context_t * text,
38057c478bd9Sstevel@tonic-gate 	      const sasl_utils_t * utils,
38067c478bd9Sstevel@tonic-gate 	      unsigned char *pszUserName,
38077c478bd9Sstevel@tonic-gate 	      unsigned char *pszRealm,
38087c478bd9Sstevel@tonic-gate 	      sasl_secret_t * pszPassword,
38097c478bd9Sstevel@tonic-gate 	      unsigned char *pszAuthorization_id,
38107c478bd9Sstevel@tonic-gate 	      unsigned char *pszNonce,
38117c478bd9Sstevel@tonic-gate 	      unsigned char *pszCNonce,
38127c478bd9Sstevel@tonic-gate 	      HASHHEX SessionKey)
38137c478bd9Sstevel@tonic-gate {
38147c478bd9Sstevel@tonic-gate     MD5_CTX         Md5Ctx;
38157c478bd9Sstevel@tonic-gate     HASH            HA1;
38167c478bd9Sstevel@tonic-gate 
38177c478bd9Sstevel@tonic-gate     DigestCalcSecret(utils,
38187c478bd9Sstevel@tonic-gate 		     pszUserName,
38197c478bd9Sstevel@tonic-gate 		     pszRealm,
38207c478bd9Sstevel@tonic-gate 		     (unsigned char *) pszPassword->data,
38217c478bd9Sstevel@tonic-gate 		     pszPassword->len,
38227c478bd9Sstevel@tonic-gate 		     HA1);
38237c478bd9Sstevel@tonic-gate 
38247c478bd9Sstevel@tonic-gate     /* calculate the session key */
38257c478bd9Sstevel@tonic-gate     utils->MD5Init(&Md5Ctx);
38267c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
38277c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, COLON, 1);
38287c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
38297c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, COLON, 1);
38307c478bd9Sstevel@tonic-gate     utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
38317c478bd9Sstevel@tonic-gate     if (pszAuthorization_id != NULL) {
38327c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, COLON, 1);
38337c478bd9Sstevel@tonic-gate 	utils->MD5Update(&Md5Ctx, pszAuthorization_id,
38347c478bd9Sstevel@tonic-gate 			 strlen((char *) pszAuthorization_id));
38357c478bd9Sstevel@tonic-gate     }
38367c478bd9Sstevel@tonic-gate     utils->MD5Final(HA1, &Md5Ctx);
38377c478bd9Sstevel@tonic-gate 
38387c478bd9Sstevel@tonic-gate     CvtHex(HA1, SessionKey);
38397c478bd9Sstevel@tonic-gate 
38407c478bd9Sstevel@tonic-gate     /* xxx rc-* use different n */
38417c478bd9Sstevel@tonic-gate 
38427c478bd9Sstevel@tonic-gate     /* save HA1 because we'll need it for the privacy and integrity keys */
38437c478bd9Sstevel@tonic-gate     memcpy(text->HA1, HA1, sizeof(HASH));
38447c478bd9Sstevel@tonic-gate 
38457c478bd9Sstevel@tonic-gate }
38467c478bd9Sstevel@tonic-gate 
38477c478bd9Sstevel@tonic-gate static char *calculate_response(context_t * text,
38487c478bd9Sstevel@tonic-gate 				const sasl_utils_t * utils,
38497c478bd9Sstevel@tonic-gate 				unsigned char *username,
38507c478bd9Sstevel@tonic-gate 				unsigned char *realm,
38517c478bd9Sstevel@tonic-gate 				unsigned char *nonce,
38527c478bd9Sstevel@tonic-gate 				unsigned int ncvalue,
38537c478bd9Sstevel@tonic-gate 				unsigned char *cnonce,
38547c478bd9Sstevel@tonic-gate 				char *qop,
38557c478bd9Sstevel@tonic-gate 				unsigned char *digesturi,
38567c478bd9Sstevel@tonic-gate 				sasl_secret_t * passwd,
38577c478bd9Sstevel@tonic-gate 				unsigned char *authorization_id,
38587c478bd9Sstevel@tonic-gate 				char **response_value)
38597c478bd9Sstevel@tonic-gate {
38607c478bd9Sstevel@tonic-gate     HASHHEX         SessionKey;
38617c478bd9Sstevel@tonic-gate     HASHHEX         HEntity = "00000000000000000000000000000000";
38627c478bd9Sstevel@tonic-gate     HASHHEX         Response;
38637c478bd9Sstevel@tonic-gate     char           *result;
38647c478bd9Sstevel@tonic-gate 
38657c478bd9Sstevel@tonic-gate     /* Verifing that all parameters was defined */
38667c478bd9Sstevel@tonic-gate     if(!username || !cnonce || !nonce || !ncvalue || !digesturi || !passwd) {
38677c478bd9Sstevel@tonic-gate 	PARAMERROR( utils );
38687c478bd9Sstevel@tonic-gate 	return NULL;
38697c478bd9Sstevel@tonic-gate     }
38707c478bd9Sstevel@tonic-gate 
38717c478bd9Sstevel@tonic-gate     if (realm == NULL) {
38727c478bd9Sstevel@tonic-gate 	/* a NULL realm is equivalent to the empty string */
38737c478bd9Sstevel@tonic-gate 	realm = (unsigned char *) "";
38747c478bd9Sstevel@tonic-gate     }
38757c478bd9Sstevel@tonic-gate 
38767c478bd9Sstevel@tonic-gate     if (qop == NULL) {
38777c478bd9Sstevel@tonic-gate 	/* default to a qop of just authentication */
38787c478bd9Sstevel@tonic-gate 	qop = "auth";
38797c478bd9Sstevel@tonic-gate     }
38807c478bd9Sstevel@tonic-gate 
38817c478bd9Sstevel@tonic-gate     DigestCalcHA1(text,
38827c478bd9Sstevel@tonic-gate 		  utils,
38837c478bd9Sstevel@tonic-gate 		  username,
38847c478bd9Sstevel@tonic-gate 		  realm,
38857c478bd9Sstevel@tonic-gate 		  passwd,
38867c478bd9Sstevel@tonic-gate 		  authorization_id,
38877c478bd9Sstevel@tonic-gate 		  nonce,
38887c478bd9Sstevel@tonic-gate 		  cnonce,
38897c478bd9Sstevel@tonic-gate 		  SessionKey);
38907c478bd9Sstevel@tonic-gate 
38917c478bd9Sstevel@tonic-gate     DigestCalcResponse(utils,
38927c478bd9Sstevel@tonic-gate 		       SessionKey,/* H(A1) */
38937c478bd9Sstevel@tonic-gate 		       nonce,	/* nonce from server */
38947c478bd9Sstevel@tonic-gate 		       ncvalue,	/* 8 hex digits */
38957c478bd9Sstevel@tonic-gate 		       cnonce,	/* client nonce */
38967c478bd9Sstevel@tonic-gate 		       (unsigned char *) qop,	/* qop-value: "", "auth",
38977c478bd9Sstevel@tonic-gate 						 * "auth-int" */
38987c478bd9Sstevel@tonic-gate 		       digesturi,	/* requested URL */
38997c478bd9Sstevel@tonic-gate 		       (unsigned char *) "AUTHENTICATE",
39007c478bd9Sstevel@tonic-gate 		       HEntity,	/* H(entity body) if qop="auth-int" */
39017c478bd9Sstevel@tonic-gate 		       Response	/* request-digest or response-digest */
39027c478bd9Sstevel@tonic-gate 	);
39037c478bd9Sstevel@tonic-gate 
39047c478bd9Sstevel@tonic-gate     result = utils->malloc(HASHHEXLEN + 1);
39057c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
39067c478bd9Sstevel@tonic-gate     if (result == NULL)
39077c478bd9Sstevel@tonic-gate 	return NULL;
39087c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
39097c478bd9Sstevel@tonic-gate     memcpy(result, Response, HASHHEXLEN);
39107c478bd9Sstevel@tonic-gate     result[HASHHEXLEN] = 0;
39117c478bd9Sstevel@tonic-gate 
39127c478bd9Sstevel@tonic-gate     if (response_value != NULL) {
39137c478bd9Sstevel@tonic-gate 	DigestCalcResponse(utils,
39147c478bd9Sstevel@tonic-gate 			   SessionKey,	/* H(A1) */
39157c478bd9Sstevel@tonic-gate 			   nonce,	/* nonce from server */
39167c478bd9Sstevel@tonic-gate 			   ncvalue,	/* 8 hex digits */
39177c478bd9Sstevel@tonic-gate 			   cnonce,	/* client nonce */
39187c478bd9Sstevel@tonic-gate 			   (unsigned char *) qop,	/* qop-value: "", "auth",
39197c478bd9Sstevel@tonic-gate 							 * "auth-int" */
39207c478bd9Sstevel@tonic-gate 			   (unsigned char *) digesturi,	/* requested URL */
39217c478bd9Sstevel@tonic-gate 			   NULL,
39227c478bd9Sstevel@tonic-gate 			   HEntity,	/* H(entity body) if qop="auth-int" */
39237c478bd9Sstevel@tonic-gate 			   Response	/* request-digest or response-digest */
39247c478bd9Sstevel@tonic-gate 	    );
39257c478bd9Sstevel@tonic-gate 
39267c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
39277c478bd9Sstevel@tonic-gate 	if (*response_value != NULL)
39287c478bd9Sstevel@tonic-gate 	    utils->free(*response_value);
39297c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
39307c478bd9Sstevel@tonic-gate 	*response_value = utils->malloc(HASHHEXLEN + 1);
39317c478bd9Sstevel@tonic-gate 	if (*response_value == NULL)
39327c478bd9Sstevel@tonic-gate 	    return NULL;
39337c478bd9Sstevel@tonic-gate 
39347c478bd9Sstevel@tonic-gate 	memcpy(*response_value, Response, HASHHEXLEN);
39357c478bd9Sstevel@tonic-gate 	(*response_value)[HASHHEXLEN] = 0;
39367c478bd9Sstevel@tonic-gate 
39377c478bd9Sstevel@tonic-gate     }
39387c478bd9Sstevel@tonic-gate 
39397c478bd9Sstevel@tonic-gate     return result;
39407c478bd9Sstevel@tonic-gate }
39417c478bd9Sstevel@tonic-gate 
39427c478bd9Sstevel@tonic-gate static int
39437c478bd9Sstevel@tonic-gate make_client_response(context_t *text,
39447c478bd9Sstevel@tonic-gate 		     sasl_client_params_t *params,
39457c478bd9Sstevel@tonic-gate 		     sasl_out_params_t *oparams)
39467c478bd9Sstevel@tonic-gate {
39477c478bd9Sstevel@tonic-gate     client_context_t *ctext = (client_context_t *) text;
39487c478bd9Sstevel@tonic-gate     char *qop = NULL;
39497c478bd9Sstevel@tonic-gate     unsigned nbits = 0;
39507c478bd9Sstevel@tonic-gate     unsigned char  *digesturi = NULL;
39517c478bd9Sstevel@tonic-gate     bool            IsUTF8 = FALSE;
39527c478bd9Sstevel@tonic-gate     char           ncvalue[10];
39537c478bd9Sstevel@tonic-gate     char           maxbufstr[64];
39547c478bd9Sstevel@tonic-gate     char           *response = NULL;
39557c478bd9Sstevel@tonic-gate     unsigned        resplen = 0;
39567c478bd9Sstevel@tonic-gate     int result;
39577c478bd9Sstevel@tonic-gate 
39587c478bd9Sstevel@tonic-gate     switch (ctext->protection) {
39597c478bd9Sstevel@tonic-gate     case DIGEST_PRIVACY:
39607c478bd9Sstevel@tonic-gate 	qop = "auth-conf";
39617c478bd9Sstevel@tonic-gate 	oparams->encode = &digestmd5_privacy_encode;
39627c478bd9Sstevel@tonic-gate 	oparams->decode = &digestmd5_privacy_decode;
39637c478bd9Sstevel@tonic-gate 	oparams->mech_ssf = ctext->cipher->ssf;
39647c478bd9Sstevel@tonic-gate 
39657c478bd9Sstevel@tonic-gate 	nbits = ctext->cipher->n;
39667c478bd9Sstevel@tonic-gate 	text->cipher_enc = ctext->cipher->cipher_enc;
39677c478bd9Sstevel@tonic-gate 	text->cipher_dec = ctext->cipher->cipher_dec;
39687c478bd9Sstevel@tonic-gate 	text->cipher_free = ctext->cipher->cipher_free;
39697c478bd9Sstevel@tonic-gate 	text->cipher_init = ctext->cipher->cipher_init;
39707c478bd9Sstevel@tonic-gate 	break;
39717c478bd9Sstevel@tonic-gate     case DIGEST_INTEGRITY:
39727c478bd9Sstevel@tonic-gate 	qop = "auth-int";
39737c478bd9Sstevel@tonic-gate 	oparams->encode = &digestmd5_integrity_encode;
39747c478bd9Sstevel@tonic-gate 	oparams->decode = &digestmd5_integrity_decode;
39757c478bd9Sstevel@tonic-gate 	oparams->mech_ssf = 1;
39767c478bd9Sstevel@tonic-gate 	break;
39777c478bd9Sstevel@tonic-gate     case DIGEST_NOLAYER:
39787c478bd9Sstevel@tonic-gate     default:
39797c478bd9Sstevel@tonic-gate 	qop = "auth";
39807c478bd9Sstevel@tonic-gate 	oparams->encode = NULL;
39817c478bd9Sstevel@tonic-gate 	oparams->decode = NULL;
39827c478bd9Sstevel@tonic-gate 	oparams->mech_ssf = 0;
39837c478bd9Sstevel@tonic-gate     }
39847c478bd9Sstevel@tonic-gate 
39857c478bd9Sstevel@tonic-gate     digesturi = params->utils->malloc(strlen(params->service) + 1 +
39867c478bd9Sstevel@tonic-gate 				      strlen(params->serverFQDN) + 1 +
39877c478bd9Sstevel@tonic-gate 				      1);
39887c478bd9Sstevel@tonic-gate     if (digesturi == NULL) {
39897c478bd9Sstevel@tonic-gate 	result = SASL_NOMEM;
39907c478bd9Sstevel@tonic-gate 	goto FreeAllocatedMem;
39917c478bd9Sstevel@tonic-gate     };
39927c478bd9Sstevel@tonic-gate 
39937c478bd9Sstevel@tonic-gate     /* allocated exactly this. safe */
39947c478bd9Sstevel@tonic-gate     strcpy((char *) digesturi, params->service);
39957c478bd9Sstevel@tonic-gate     strcat((char *) digesturi, "/");
39967c478bd9Sstevel@tonic-gate     strcat((char *) digesturi, params->serverFQDN);
39977c478bd9Sstevel@tonic-gate     /*
39987c478bd9Sstevel@tonic-gate      * strcat (digesturi, "/"); strcat (digesturi, params->serverFQDN);
39997c478bd9Sstevel@tonic-gate      */
40007c478bd9Sstevel@tonic-gate 
40017c478bd9Sstevel@tonic-gate     /* response */
40027c478bd9Sstevel@tonic-gate     response =
40037c478bd9Sstevel@tonic-gate 	calculate_response(text,
40047c478bd9Sstevel@tonic-gate 			   params->utils,
40057c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
40067c478bd9Sstevel@tonic-gate 			   (unsigned char *) oparams->authid,
40077c478bd9Sstevel@tonic-gate #else
40087c478bd9Sstevel@tonic-gate 			   (char *) oparams->authid,
40097c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
40107c478bd9Sstevel@tonic-gate 			   (unsigned char *) text->realm,
40117c478bd9Sstevel@tonic-gate 			   text->nonce,
40127c478bd9Sstevel@tonic-gate 			   text->nonce_count,
40137c478bd9Sstevel@tonic-gate 			   text->cnonce,
40147c478bd9Sstevel@tonic-gate 			   qop,
40157c478bd9Sstevel@tonic-gate 			   digesturi,
40167c478bd9Sstevel@tonic-gate 			   ctext->password,
40177c478bd9Sstevel@tonic-gate 			   strcmp(oparams->user, oparams->authid) ?
40187c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
40197c478bd9Sstevel@tonic-gate 			   (unsigned char *) oparams->user : NULL,
40207c478bd9Sstevel@tonic-gate #else
40217c478bd9Sstevel@tonic-gate 			   (char *) oparams->user : NULL,
40227c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
40237c478bd9Sstevel@tonic-gate 			   &text->response_value);
40247c478bd9Sstevel@tonic-gate 
40257c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
40267c478bd9Sstevel@tonic-gate     if (response == NULL) {
40277c478bd9Sstevel@tonic-gate 	result = SASL_NOMEM;
40287c478bd9Sstevel@tonic-gate 	goto FreeAllocatedMem;
40297c478bd9Sstevel@tonic-gate     }
40307c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
40317c478bd9Sstevel@tonic-gate 
40327c478bd9Sstevel@tonic-gate     resplen = strlen(oparams->authid) + strlen("username") + 5;
40337c478bd9Sstevel@tonic-gate     result =_plug_buf_alloc(params->utils, &(text->out_buf),
40347c478bd9Sstevel@tonic-gate 			    &(text->out_buf_len),
40357c478bd9Sstevel@tonic-gate 			    resplen);
40367c478bd9Sstevel@tonic-gate     if (result != SASL_OK) goto FreeAllocatedMem;
40377c478bd9Sstevel@tonic-gate 
40387c478bd9Sstevel@tonic-gate     sprintf(text->out_buf, "username=\"%s\"", oparams->authid);
40397c478bd9Sstevel@tonic-gate 
40407c478bd9Sstevel@tonic-gate     if (add_to_challenge(params->utils,
40417c478bd9Sstevel@tonic-gate 			 &text->out_buf, &text->out_buf_len, &resplen,
40427c478bd9Sstevel@tonic-gate 			 "realm", (unsigned char *) text->realm,
40437c478bd9Sstevel@tonic-gate 			 TRUE) != SASL_OK) {
40447c478bd9Sstevel@tonic-gate 	result = SASL_FAIL;
40457c478bd9Sstevel@tonic-gate 	goto FreeAllocatedMem;
40467c478bd9Sstevel@tonic-gate     }
40477c478bd9Sstevel@tonic-gate     if (strcmp(oparams->user, oparams->authid)) {
40487c478bd9Sstevel@tonic-gate 	if (add_to_challenge(params->utils,
40497c478bd9Sstevel@tonic-gate 			     &text->out_buf, &text->out_buf_len, &resplen,
40507c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
40517c478bd9Sstevel@tonic-gate 			     "authzid", (unsigned char *) oparams->user,
40527c478bd9Sstevel@tonic-gate 			     TRUE) != SASL_OK) {
40537c478bd9Sstevel@tonic-gate #else
40547c478bd9Sstevel@tonic-gate 			     "authzid", (char *) oparams->user, TRUE) != SASL_OK) {
40557c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
40567c478bd9Sstevel@tonic-gate 	    result = SASL_FAIL;
40577c478bd9Sstevel@tonic-gate 	    goto FreeAllocatedMem;
40587c478bd9Sstevel@tonic-gate 	}
40597c478bd9Sstevel@tonic-gate     }
40607c478bd9Sstevel@tonic-gate     if (add_to_challenge(params->utils,
40617c478bd9Sstevel@tonic-gate 			 &text->out_buf, &text->out_buf_len, &resplen,
40627c478bd9Sstevel@tonic-gate 			 "nonce", text->nonce, TRUE) != SASL_OK) {
40637c478bd9Sstevel@tonic-gate 	result = SASL_FAIL;
40647c478bd9Sstevel@tonic-gate 	goto FreeAllocatedMem;
40657c478bd9Sstevel@tonic-gate     }
40667c478bd9Sstevel@tonic-gate     if (add_to_challenge(params->utils,
40677c478bd9Sstevel@tonic-gate 			 &text->out_buf, &text->out_buf_len, &resplen,
40687c478bd9Sstevel@tonic-gate 			 "cnonce", text->cnonce, TRUE) != SASL_OK) {
40697c478bd9Sstevel@tonic-gate 	result = SASL_FAIL;
40707c478bd9Sstevel@tonic-gate 	goto FreeAllocatedMem;
40717c478bd9Sstevel@tonic-gate     }
40727c478bd9Sstevel@tonic-gate     snprintf(ncvalue, sizeof(ncvalue), "%08x", text->nonce_count);
40737c478bd9Sstevel@tonic-gate     if (add_to_challenge(params->utils,
40747c478bd9Sstevel@tonic-gate 			 &text->out_buf, &text->out_buf_len, &resplen,
40757c478bd9Sstevel@tonic-gate 			 "nc", (unsigned char *) ncvalue, FALSE) != SASL_OK) {
40767c478bd9Sstevel@tonic-gate 	result = SASL_FAIL;
40777c478bd9Sstevel@tonic-gate 	goto FreeAllocatedMem;
40787c478bd9Sstevel@tonic-gate     }
40797c478bd9Sstevel@tonic-gate     if (add_to_challenge(params->utils,
40807c478bd9Sstevel@tonic-gate 			 &text->out_buf, &text->out_buf_len, &resplen,
40817c478bd9Sstevel@tonic-gate 			 "qop", (unsigned char *) qop, FALSE) != SASL_OK) {
40827c478bd9Sstevel@tonic-gate 	result = SASL_FAIL;
40837c478bd9Sstevel@tonic-gate 	goto FreeAllocatedMem;
40847c478bd9Sstevel@tonic-gate     }
40857c478bd9Sstevel@tonic-gate     if (ctext->cipher != NULL) {
40867c478bd9Sstevel@tonic-gate 	if (add_to_challenge(params->utils,
40877c478bd9Sstevel@tonic-gate 			     &text->out_buf, &text->out_buf_len, &resplen,
40887c478bd9Sstevel@tonic-gate 			     "cipher",
40897c478bd9Sstevel@tonic-gate 			     (unsigned char *) ctext->cipher->name,
40907c478bd9Sstevel@tonic-gate 			     TRUE) != SASL_OK) {
40917c478bd9Sstevel@tonic-gate 	    result = SASL_FAIL;
40927c478bd9Sstevel@tonic-gate 	    goto FreeAllocatedMem;
40937c478bd9Sstevel@tonic-gate 	}
40947c478bd9Sstevel@tonic-gate     }
40957c478bd9Sstevel@tonic-gate 
40967c478bd9Sstevel@tonic-gate     if (params->props.maxbufsize) {
40977c478bd9Sstevel@tonic-gate 	snprintf(maxbufstr, sizeof(maxbufstr), "%d", params->props.maxbufsize);
40987c478bd9Sstevel@tonic-gate 	if (add_to_challenge(params->utils,
40997c478bd9Sstevel@tonic-gate 			     &text->out_buf, &text->out_buf_len, &resplen,
41007c478bd9Sstevel@tonic-gate 			     "maxbuf", (unsigned char *) maxbufstr,
41017c478bd9Sstevel@tonic-gate 			     FALSE) != SASL_OK) {
41027c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
41037c478bd9Sstevel@tonic-gate 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
41047c478bd9Sstevel@tonic-gate 		     "internal error: add_to_challenge maxbuf failed");
41057c478bd9Sstevel@tonic-gate #else
41067c478bd9Sstevel@tonic-gate 	    SETERROR(params->utils,
41077c478bd9Sstevel@tonic-gate 		     "internal error: add_to_challenge maxbuf failed");
41087c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
41097c478bd9Sstevel@tonic-gate 	    goto FreeAllocatedMem;
41107c478bd9Sstevel@tonic-gate 	}
41117c478bd9Sstevel@tonic-gate     }
41127c478bd9Sstevel@tonic-gate 
41137c478bd9Sstevel@tonic-gate     if (IsUTF8) {
41147c478bd9Sstevel@tonic-gate 	if (add_to_challenge(params->utils,
41157c478bd9Sstevel@tonic-gate 			     &text->out_buf, &text->out_buf_len, &resplen,
41167c478bd9Sstevel@tonic-gate 			     "charset", (unsigned char *) "utf-8",
41177c478bd9Sstevel@tonic-gate 			     FALSE) != SASL_OK) {
41187c478bd9Sstevel@tonic-gate 	    result = SASL_FAIL;
41197c478bd9Sstevel@tonic-gate 	    goto FreeAllocatedMem;
41207c478bd9Sstevel@tonic-gate 	}
41217c478bd9Sstevel@tonic-gate     }
41227c478bd9Sstevel@tonic-gate     if (add_to_challenge(params->utils,
41237c478bd9Sstevel@tonic-gate 			 &text->out_buf, &text->out_buf_len, &resplen,
41247c478bd9Sstevel@tonic-gate 			 "digest-uri", digesturi, TRUE) != SASL_OK) {
41257c478bd9Sstevel@tonic-gate 	result = SASL_FAIL;
41267c478bd9Sstevel@tonic-gate 	goto FreeAllocatedMem;
41277c478bd9Sstevel@tonic-gate     }
41287c478bd9Sstevel@tonic-gate     if (add_to_challenge(params->utils,
41297c478bd9Sstevel@tonic-gate 			 &text->out_buf, &text->out_buf_len, &resplen,
41307c478bd9Sstevel@tonic-gate 			 "response", (unsigned char *) response,
41317c478bd9Sstevel@tonic-gate 			 FALSE) != SASL_OK) {
41327c478bd9Sstevel@tonic-gate 
41337c478bd9Sstevel@tonic-gate 	result = SASL_FAIL;
41347c478bd9Sstevel@tonic-gate 	goto FreeAllocatedMem;
41357c478bd9Sstevel@tonic-gate     }
41367c478bd9Sstevel@tonic-gate 
41377c478bd9Sstevel@tonic-gate     /* self check */
41387c478bd9Sstevel@tonic-gate     if (strlen(text->out_buf) > 2048) {
41397c478bd9Sstevel@tonic-gate 	result = SASL_FAIL;
41407c478bd9Sstevel@tonic-gate 	goto FreeAllocatedMem;
41417c478bd9Sstevel@tonic-gate     }
41427c478bd9Sstevel@tonic-gate 
41437c478bd9Sstevel@tonic-gate     /* set oparams */
41447c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
41457c478bd9Sstevel@tonic-gate     oparams->maxoutbuf = ctext->server_maxbuf - 4;
41467c478bd9Sstevel@tonic-gate #else
41477c478bd9Sstevel@tonic-gate     oparams->maxoutbuf = ctext->server_maxbuf;
41487c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
41497c478bd9Sstevel@tonic-gate     if(oparams->mech_ssf > 1) {
41507c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
41517c478bd9Sstevel@tonic-gate 	if (oparams->maxoutbuf <= 25)
41527c478bd9Sstevel@tonic-gate 	     return (SASL_BADPARAM);
41537c478bd9Sstevel@tonic-gate #endif
41547c478bd9Sstevel@tonic-gate 	/* MAC block (privacy) */
41557c478bd9Sstevel@tonic-gate 	oparams->maxoutbuf -= 25;
41567c478bd9Sstevel@tonic-gate     } else if(oparams->mech_ssf == 1) {
41577c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
41587c478bd9Sstevel@tonic-gate 	if (oparams->maxoutbuf <= 16)
41597c478bd9Sstevel@tonic-gate 	     return (SASL_BADPARAM);
41607c478bd9Sstevel@tonic-gate #endif
41617c478bd9Sstevel@tonic-gate 	/* MAC block (integrity) */
41627c478bd9Sstevel@tonic-gate 	oparams->maxoutbuf -= 16;
41637c478bd9Sstevel@tonic-gate     }
41647c478bd9Sstevel@tonic-gate 
41657c478bd9Sstevel@tonic-gate     text->seqnum = 0;	/* for integrity/privacy */
41667c478bd9Sstevel@tonic-gate     text->rec_seqnum = 0;	/* for integrity/privacy */
41677c478bd9Sstevel@tonic-gate     text->utils = params->utils;
41687c478bd9Sstevel@tonic-gate 
41697c478bd9Sstevel@tonic-gate     text->in_maxbuf =
41707c478bd9Sstevel@tonic-gate 	params->props.maxbufsize ? params->props.maxbufsize : DEFAULT_BUFSIZE;
41717c478bd9Sstevel@tonic-gate 
41727c478bd9Sstevel@tonic-gate     /* used by layers */
41737c478bd9Sstevel@tonic-gate     text->needsize = 4;
41747c478bd9Sstevel@tonic-gate     text->buffer = NULL;
41757c478bd9Sstevel@tonic-gate 
41767c478bd9Sstevel@tonic-gate     if (oparams->mech_ssf > 0) {
41777c478bd9Sstevel@tonic-gate 	char enckey[16];
41787c478bd9Sstevel@tonic-gate 	char deckey[16];
41797c478bd9Sstevel@tonic-gate 
41807c478bd9Sstevel@tonic-gate 	create_layer_keys(text, params->utils, text->HA1, nbits,
41817c478bd9Sstevel@tonic-gate 			  enckey, deckey);
41827c478bd9Sstevel@tonic-gate 
41837c478bd9Sstevel@tonic-gate 	/* initialize cipher if need be */
41847c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
41857c478bd9Sstevel@tonic-gate 	if (text->cipher_init) {
41867c478bd9Sstevel@tonic-gate 	    if (text->cipher_free)
41877c478bd9Sstevel@tonic-gate 		text->cipher_free(text);
41887c478bd9Sstevel@tonic-gate 	    if((result = text->cipher_init(text, enckey, deckey)) != SASL_OK) {
41897c478bd9Sstevel@tonic-gate 		params->utils->log(params->utils->conn, SASL_LOG_ERR,
41907c478bd9Sstevel@tonic-gate 					"couldn't init cipher");
41917c478bd9Sstevel@tonic-gate 		goto FreeAllocatedMem;
41927c478bd9Sstevel@tonic-gate 	    }
41937c478bd9Sstevel@tonic-gate 	}
41947c478bd9Sstevel@tonic-gate #else
41957c478bd9Sstevel@tonic-gate 	if (text->cipher_init)
41967c478bd9Sstevel@tonic-gate 	    text->cipher_init(text, enckey, deckey);
41977c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
41987c478bd9Sstevel@tonic-gate     }
41997c478bd9Sstevel@tonic-gate 
42007c478bd9Sstevel@tonic-gate     result = SASL_OK;
42017c478bd9Sstevel@tonic-gate 
42027c478bd9Sstevel@tonic-gate   FreeAllocatedMem:
42037c478bd9Sstevel@tonic-gate     if (digesturi) params->utils->free(digesturi);
42047c478bd9Sstevel@tonic-gate     if (response) params->utils->free(response);
42057c478bd9Sstevel@tonic-gate 
42067c478bd9Sstevel@tonic-gate     return result;
42077c478bd9Sstevel@tonic-gate }
42087c478bd9Sstevel@tonic-gate 
42097c478bd9Sstevel@tonic-gate static int parse_server_challenge(client_context_t *ctext,
42107c478bd9Sstevel@tonic-gate 				  sasl_client_params_t *params,
42117c478bd9Sstevel@tonic-gate 				  const char *serverin, unsigned serverinlen,
42127c478bd9Sstevel@tonic-gate 				  char ***outrealms, int *noutrealm)
42137c478bd9Sstevel@tonic-gate {
42147c478bd9Sstevel@tonic-gate     context_t *text = (context_t *) ctext;
42157c478bd9Sstevel@tonic-gate     int result = SASL_OK;
42167c478bd9Sstevel@tonic-gate     char *in_start = NULL;
42177c478bd9Sstevel@tonic-gate     char *in = NULL;
42187c478bd9Sstevel@tonic-gate     char **realms = NULL;
42197c478bd9Sstevel@tonic-gate     int nrealm = 0;
42207c478bd9Sstevel@tonic-gate     sasl_ssf_t limit, musthave = 0;
42217c478bd9Sstevel@tonic-gate     sasl_ssf_t external;
42227c478bd9Sstevel@tonic-gate     int protection = 0;
42237c478bd9Sstevel@tonic-gate     int ciphers = 0;
42247c478bd9Sstevel@tonic-gate     int maxbuf_count = 0;
42257c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
42267c478bd9Sstevel@tonic-gate     bool IsUTF8 = FALSE;
42277c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
42287c478bd9Sstevel@tonic-gate     int algorithm_count = 0;
42297c478bd9Sstevel@tonic-gate 
42307c478bd9Sstevel@tonic-gate     if (!serverin || !serverinlen) {
42317c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
42327c478bd9Sstevel@tonic-gate 	params->utils->log(params->utils->conn, SASL_LOG_ERR,
42337c478bd9Sstevel@tonic-gate 				"no server challenge");
42347c478bd9Sstevel@tonic-gate #else
42357c478bd9Sstevel@tonic-gate 	params->utils->seterror(params->utils->conn, 0,
42367c478bd9Sstevel@tonic-gate 				"no server challenge");
42377c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
42387c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
42397c478bd9Sstevel@tonic-gate     }
42407c478bd9Sstevel@tonic-gate 
42417c478bd9Sstevel@tonic-gate     in_start = in = params->utils->malloc(serverinlen + 1);
42427c478bd9Sstevel@tonic-gate     if (in == NULL) return SASL_NOMEM;
42437c478bd9Sstevel@tonic-gate 
42447c478bd9Sstevel@tonic-gate     memcpy(in, serverin, serverinlen);
42457c478bd9Sstevel@tonic-gate     in[serverinlen] = 0;
42467c478bd9Sstevel@tonic-gate 
42477c478bd9Sstevel@tonic-gate     ctext->server_maxbuf = 65536; /* Default value for maxbuf */
42487c478bd9Sstevel@tonic-gate 
42497c478bd9Sstevel@tonic-gate     /* create a new cnonce */
42507c478bd9Sstevel@tonic-gate     text->cnonce = create_nonce(params->utils);
42517c478bd9Sstevel@tonic-gate     if (text->cnonce == NULL) {
42527c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
42537c478bd9Sstevel@tonic-gate 	params->utils->log(params->utils->conn, SASL_LOG_ERR,
42547c478bd9Sstevel@tonic-gate 			   "failed to create cnonce");
42557c478bd9Sstevel@tonic-gate #else
42567c478bd9Sstevel@tonic-gate 	params->utils->seterror(params->utils->conn, 0,
42577c478bd9Sstevel@tonic-gate 				"failed to create cnonce");
42587c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
42597c478bd9Sstevel@tonic-gate 	result = SASL_FAIL;
42607c478bd9Sstevel@tonic-gate 	goto FreeAllocatedMem;
42617c478bd9Sstevel@tonic-gate     }
42627c478bd9Sstevel@tonic-gate 
42637c478bd9Sstevel@tonic-gate     /* parse the challenge */
42647c478bd9Sstevel@tonic-gate     while (in[0] != '\0') {
42657c478bd9Sstevel@tonic-gate 	char *name, *value;
42667c478bd9Sstevel@tonic-gate 
42677c478bd9Sstevel@tonic-gate 	get_pair(&in, &name, &value);
42687c478bd9Sstevel@tonic-gate 
42697c478bd9Sstevel@tonic-gate 	/* if parse error */
42707c478bd9Sstevel@tonic-gate 	if (name == NULL) {
42717c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
42727c478bd9Sstevel@tonic-gate 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
42737c478bd9Sstevel@tonic-gate 			       "Parse error");
42747c478bd9Sstevel@tonic-gate #else
42757c478bd9Sstevel@tonic-gate 	    params->utils->seterror(params->utils->conn, 0, "Parse error");
42767c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
42777c478bd9Sstevel@tonic-gate 	    result = SASL_FAIL;
42787c478bd9Sstevel@tonic-gate 	    goto FreeAllocatedMem;
42797c478bd9Sstevel@tonic-gate 	}
42807c478bd9Sstevel@tonic-gate 
42817c478bd9Sstevel@tonic-gate 	if (strcasecmp(name, "realm") == 0) {
42827c478bd9Sstevel@tonic-gate 	    nrealm++;
42837c478bd9Sstevel@tonic-gate 
42847c478bd9Sstevel@tonic-gate 	    if(!realms)
42857c478bd9Sstevel@tonic-gate 		realms = params->utils->malloc(sizeof(char *) * (nrealm + 1));
42867c478bd9Sstevel@tonic-gate 	    else
42877c478bd9Sstevel@tonic-gate 		realms = params->utils->realloc(realms,
42887c478bd9Sstevel@tonic-gate 						sizeof(char *) * (nrealm + 1));
42897c478bd9Sstevel@tonic-gate 
42907c478bd9Sstevel@tonic-gate 	    if (realms == NULL) {
42917c478bd9Sstevel@tonic-gate 		result = SASL_NOMEM;
42927c478bd9Sstevel@tonic-gate 		goto FreeAllocatedMem;
42937c478bd9Sstevel@tonic-gate 	    }
42947c478bd9Sstevel@tonic-gate 
42957c478bd9Sstevel@tonic-gate 	    _plug_strdup(params->utils, value, &realms[nrealm-1], NULL);
42967c478bd9Sstevel@tonic-gate 	    realms[nrealm] = NULL;
42977c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "nonce") == 0) {
42987c478bd9Sstevel@tonic-gate 	    _plug_strdup(params->utils, value, (char **) &text->nonce,
42997c478bd9Sstevel@tonic-gate 			 NULL);
43007c478bd9Sstevel@tonic-gate 	    text->nonce_count = 1;
43017c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "qop") == 0) {
43027c478bd9Sstevel@tonic-gate 	    while (value && *value) {
43037c478bd9Sstevel@tonic-gate 		char *comma = strchr(value, ',');
43047c478bd9Sstevel@tonic-gate 		if (comma != NULL) {
43057c478bd9Sstevel@tonic-gate 		    *comma++ = '\0';
43067c478bd9Sstevel@tonic-gate 		}
43077c478bd9Sstevel@tonic-gate 
43087c478bd9Sstevel@tonic-gate 		if (strcasecmp(value, "auth-conf") == 0) {
43097c478bd9Sstevel@tonic-gate 		    protection |= DIGEST_PRIVACY;
43107c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(value, "auth-int") == 0) {
43117c478bd9Sstevel@tonic-gate 		    protection |= DIGEST_INTEGRITY;
43127c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(value, "auth") == 0) {
43137c478bd9Sstevel@tonic-gate 		    protection |= DIGEST_NOLAYER;
43147c478bd9Sstevel@tonic-gate 		} else {
43157c478bd9Sstevel@tonic-gate 		    params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
43167c478bd9Sstevel@tonic-gate 				       "Server supports unknown layer: %s\n",
43177c478bd9Sstevel@tonic-gate 				       value);
43187c478bd9Sstevel@tonic-gate 		}
43197c478bd9Sstevel@tonic-gate 
43207c478bd9Sstevel@tonic-gate 		value = comma;
43217c478bd9Sstevel@tonic-gate 	    }
43227c478bd9Sstevel@tonic-gate 
43237c478bd9Sstevel@tonic-gate 	    if (protection == 0) {
43247c478bd9Sstevel@tonic-gate 		result = SASL_BADAUTH;
43257c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
43267c478bd9Sstevel@tonic-gate 		params->utils->seterror(params->utils->conn, 0,
43277c478bd9Sstevel@tonic-gate 			gettext("Server doesn't support known qop level"));
43287c478bd9Sstevel@tonic-gate #else
43297c478bd9Sstevel@tonic-gate 		params->utils->seterror(params->utils->conn, 0,
43307c478bd9Sstevel@tonic-gate 					"Server doesn't support known qop level");
43317c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
43327c478bd9Sstevel@tonic-gate 		goto FreeAllocatedMem;
43337c478bd9Sstevel@tonic-gate 	    }
43347c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "cipher") == 0) {
43357c478bd9Sstevel@tonic-gate 	    while (value && *value) {
43367c478bd9Sstevel@tonic-gate 		char *comma = strchr(value, ',');
43377c478bd9Sstevel@tonic-gate #ifdef USE_UEF_CLIENT
43387c478bd9Sstevel@tonic-gate 		struct digest_cipher *cipher = available_ciphers1;
43397c478bd9Sstevel@tonic-gate #else
43407c478bd9Sstevel@tonic-gate 		struct digest_cipher *cipher = available_ciphers;
43417c478bd9Sstevel@tonic-gate #endif
43427c478bd9Sstevel@tonic-gate 
43437c478bd9Sstevel@tonic-gate 		if (comma != NULL) {
43447c478bd9Sstevel@tonic-gate 		    *comma++ = '\0';
43457c478bd9Sstevel@tonic-gate 		}
43467c478bd9Sstevel@tonic-gate 
43477c478bd9Sstevel@tonic-gate 		/* do we support this cipher? */
43487c478bd9Sstevel@tonic-gate 		while (cipher->name) {
43497c478bd9Sstevel@tonic-gate 		    if (!strcasecmp(value, cipher->name)) break;
43507c478bd9Sstevel@tonic-gate 		    cipher++;
43517c478bd9Sstevel@tonic-gate 		}
43527c478bd9Sstevel@tonic-gate 		if (cipher->name) {
43537c478bd9Sstevel@tonic-gate 		    ciphers |= cipher->flag;
43547c478bd9Sstevel@tonic-gate 		} else {
43557c478bd9Sstevel@tonic-gate 		    params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
43567c478bd9Sstevel@tonic-gate 				       "Server supports unknown cipher: %s\n",
43577c478bd9Sstevel@tonic-gate 				       value);
43587c478bd9Sstevel@tonic-gate 		}
43597c478bd9Sstevel@tonic-gate 
43607c478bd9Sstevel@tonic-gate 		value = comma;
43617c478bd9Sstevel@tonic-gate 	    }
43627c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "stale") == 0 && ctext->password) {
43637c478bd9Sstevel@tonic-gate 	    /* clear any cached password */
43647c478bd9Sstevel@tonic-gate 	    if (ctext->free_password)
43657c478bd9Sstevel@tonic-gate 		_plug_free_secret(params->utils, &ctext->password);
43667c478bd9Sstevel@tonic-gate 	    ctext->password = NULL;
43677c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "maxbuf") == 0) {
43687c478bd9Sstevel@tonic-gate 	    /* maxbuf A number indicating the size of the largest
43697c478bd9Sstevel@tonic-gate 	     * buffer the server is able to receive when using
43707c478bd9Sstevel@tonic-gate 	     * "auth-int". If this directive is missing, the default
43717c478bd9Sstevel@tonic-gate 	     * value is 65536. This directive may appear at most once;
43727c478bd9Sstevel@tonic-gate 	     * if multiple instances are present, the client should
43737c478bd9Sstevel@tonic-gate 	     * abort the authentication exchange.
43747c478bd9Sstevel@tonic-gate 	     */
43757c478bd9Sstevel@tonic-gate 	    maxbuf_count++;
43767c478bd9Sstevel@tonic-gate 
43777c478bd9Sstevel@tonic-gate 	    if (maxbuf_count != 1) {
43787c478bd9Sstevel@tonic-gate 		result = SASL_BADAUTH;
43797c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
43807c478bd9Sstevel@tonic-gate 		params->utils->log(params->utils->conn, SASL_LOG_ERR,
43817c478bd9Sstevel@tonic-gate 				   "At least two maxbuf directives found."
43827c478bd9Sstevel@tonic-gate 				   " Authentication aborted");
43837c478bd9Sstevel@tonic-gate #else
43847c478bd9Sstevel@tonic-gate 		params->utils->seterror(params->utils->conn, 0,
43857c478bd9Sstevel@tonic-gate 					"At least two maxbuf directives found. Authentication aborted");
43867c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
43877c478bd9Sstevel@tonic-gate 		goto FreeAllocatedMem;
43887c478bd9Sstevel@tonic-gate 	    } else if (sscanf(value, "%u", &ctext->server_maxbuf) != 1) {
43897c478bd9Sstevel@tonic-gate 		result = SASL_BADAUTH;
43907c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
43917c478bd9Sstevel@tonic-gate 		params->utils->log(params->utils->conn, SASL_LOG_ERR,
43927c478bd9Sstevel@tonic-gate 			"Invalid maxbuf parameter received from server");
43937c478bd9Sstevel@tonic-gate #else
43947c478bd9Sstevel@tonic-gate 		params->utils->seterror(params->utils->conn, 0,
43957c478bd9Sstevel@tonic-gate 					"Invalid maxbuf parameter received from server");
43967c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
43977c478bd9Sstevel@tonic-gate 		goto FreeAllocatedMem;
43987c478bd9Sstevel@tonic-gate 	    } else {
43997c478bd9Sstevel@tonic-gate 		if (ctext->server_maxbuf<=16) {
44007c478bd9Sstevel@tonic-gate 		    result = SASL_BADAUTH;
44017c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
44027c478bd9Sstevel@tonic-gate 		    params->utils->log(params->utils->conn, SASL_LOG_ERR,
44037c478bd9Sstevel@tonic-gate 			"Invalid maxbuf parameter received from server"
44047c478bd9Sstevel@tonic-gate 			" (too small: %s)", value);
44057c478bd9Sstevel@tonic-gate #else
44067c478bd9Sstevel@tonic-gate 		    params->utils->seterror(params->utils->conn, 0,
44077c478bd9Sstevel@tonic-gate 					    "Invalid maxbuf parameter received from server (too small: %s)", value);
44087c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
44097c478bd9Sstevel@tonic-gate 		    goto FreeAllocatedMem;
44107c478bd9Sstevel@tonic-gate 		}
44117c478bd9Sstevel@tonic-gate 	    }
44127c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name, "charset") == 0) {
44137c478bd9Sstevel@tonic-gate 	    if (strcasecmp(value, "utf-8") != 0) {
44147c478bd9Sstevel@tonic-gate 		result = SASL_BADAUTH;
44157c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
44167c478bd9Sstevel@tonic-gate 		params->utils->log(params->utils->conn, SASL_LOG_ERR,
44177c478bd9Sstevel@tonic-gate 				   "Charset must be UTF-8");
44187c478bd9Sstevel@tonic-gate #else
44197c478bd9Sstevel@tonic-gate 		params->utils->seterror(params->utils->conn, 0,
44207c478bd9Sstevel@tonic-gate 					"Charset must be UTF-8");
44217c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
44227c478bd9Sstevel@tonic-gate 		goto FreeAllocatedMem;
44237c478bd9Sstevel@tonic-gate 	    } else {
44247c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
44257c478bd9Sstevel@tonic-gate 		IsUTF8 = TRUE;
44267c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
44277c478bd9Sstevel@tonic-gate 	    }
44287c478bd9Sstevel@tonic-gate 	} else if (strcasecmp(name,"algorithm")==0) {
44297c478bd9Sstevel@tonic-gate 	    if (strcasecmp(value, "md5-sess") != 0)
44307c478bd9Sstevel@tonic-gate 		{
44317c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
44327c478bd9Sstevel@tonic-gate 		    params->utils->log(params->utils->conn, SASL_LOG_ERR,
44337c478bd9Sstevel@tonic-gate 				"'algorithm' isn't 'md5-sess'");
44347c478bd9Sstevel@tonic-gate #else
44357c478bd9Sstevel@tonic-gate 		    params->utils->seterror(params->utils->conn, 0,
44367c478bd9Sstevel@tonic-gate 					    "'algorithm' isn't 'md5-sess'");
44377c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
44387c478bd9Sstevel@tonic-gate 		    result = SASL_FAIL;
44397c478bd9Sstevel@tonic-gate 		    goto FreeAllocatedMem;
44407c478bd9Sstevel@tonic-gate 		}
44417c478bd9Sstevel@tonic-gate 
44427c478bd9Sstevel@tonic-gate 	    algorithm_count++;
44437c478bd9Sstevel@tonic-gate 	    if (algorithm_count > 1)
44447c478bd9Sstevel@tonic-gate 		{
44457c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
44467c478bd9Sstevel@tonic-gate 		    params->utils->log(params->utils->conn, SASL_LOG_ERR,
44477c478bd9Sstevel@tonic-gate 				       "Must see 'algorithm' only once");
44487c478bd9Sstevel@tonic-gate #else
44497c478bd9Sstevel@tonic-gate 		    params->utils->seterror(params->utils->conn, 0,
44507c478bd9Sstevel@tonic-gate 					    "Must see 'algorithm' only once");
44517c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
44527c478bd9Sstevel@tonic-gate 		    result = SASL_FAIL;
44537c478bd9Sstevel@tonic-gate 		    goto FreeAllocatedMem;
44547c478bd9Sstevel@tonic-gate 		}
44557c478bd9Sstevel@tonic-gate 	} else {
44567c478bd9Sstevel@tonic-gate 	    params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
44577c478bd9Sstevel@tonic-gate 			       "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
44587c478bd9Sstevel@tonic-gate 			       name, value);
44597c478bd9Sstevel@tonic-gate 	}
44607c478bd9Sstevel@tonic-gate     }
44617c478bd9Sstevel@tonic-gate 
44627c478bd9Sstevel@tonic-gate     if (algorithm_count != 1) {
44637c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
44647c478bd9Sstevel@tonic-gate 	params->utils->log(params->utils->conn, SASL_LOG_ERR,
44657c478bd9Sstevel@tonic-gate 		"Must see 'algorithm' once. Didn't see at all");
44667c478bd9Sstevel@tonic-gate #else
44677c478bd9Sstevel@tonic-gate 	params->utils->seterror(params->utils->conn, 0,
44687c478bd9Sstevel@tonic-gate 				"Must see 'algorithm' once. Didn't see at all");
44697c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
44707c478bd9Sstevel@tonic-gate 	result = SASL_FAIL;
44717c478bd9Sstevel@tonic-gate 	goto FreeAllocatedMem;
44727c478bd9Sstevel@tonic-gate     }
44737c478bd9Sstevel@tonic-gate 
44747c478bd9Sstevel@tonic-gate     /* make sure we have everything we require */
44757c478bd9Sstevel@tonic-gate     if (text->nonce == NULL) {
44767c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
44777c478bd9Sstevel@tonic-gate 	params->utils->log(params->utils->conn, SASL_LOG_ERR,
44787c478bd9Sstevel@tonic-gate 			   "Don't have nonce.");
44797c478bd9Sstevel@tonic-gate #else
44807c478bd9Sstevel@tonic-gate 	params->utils->seterror(params->utils->conn, 0,
44817c478bd9Sstevel@tonic-gate 				"Don't have nonce.");
44827c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
44837c478bd9Sstevel@tonic-gate 	result = SASL_FAIL;
44847c478bd9Sstevel@tonic-gate 	goto FreeAllocatedMem;
44857c478bd9Sstevel@tonic-gate     }
44867c478bd9Sstevel@tonic-gate 
44877c478bd9Sstevel@tonic-gate     /* get requested ssf */
44887c478bd9Sstevel@tonic-gate     external = params->external_ssf;
44897c478bd9Sstevel@tonic-gate 
44907c478bd9Sstevel@tonic-gate     /* what do we _need_?  how much is too much? */
44917c478bd9Sstevel@tonic-gate     if (params->props.maxbufsize == 0) {
44927c478bd9Sstevel@tonic-gate 	musthave = 0;
44937c478bd9Sstevel@tonic-gate 	limit = 0;
44947c478bd9Sstevel@tonic-gate     } else {
44957c478bd9Sstevel@tonic-gate 	if (params->props.max_ssf > external) {
44967c478bd9Sstevel@tonic-gate 	    limit = params->props.max_ssf - external;
44977c478bd9Sstevel@tonic-gate 	} else {
44987c478bd9Sstevel@tonic-gate 	    limit = 0;
44997c478bd9Sstevel@tonic-gate 	}
45007c478bd9Sstevel@tonic-gate 	if (params->props.min_ssf > external) {
45017c478bd9Sstevel@tonic-gate 	    musthave = params->props.min_ssf - external;
45027c478bd9Sstevel@tonic-gate 	} else {
45037c478bd9Sstevel@tonic-gate 	    musthave = 0;
45047c478bd9Sstevel@tonic-gate 	}
45057c478bd9Sstevel@tonic-gate     }
45067c478bd9Sstevel@tonic-gate 
45077c478bd9Sstevel@tonic-gate     /* we now go searching for an option that gives us at least "musthave"
45087c478bd9Sstevel@tonic-gate        and at most "limit" bits of ssf. */
45097c478bd9Sstevel@tonic-gate     if ((limit > 1) && (protection & DIGEST_PRIVACY)) {
45107c478bd9Sstevel@tonic-gate 	struct digest_cipher *cipher;
45117c478bd9Sstevel@tonic-gate 
45127c478bd9Sstevel@tonic-gate 	/* let's find an encryption scheme that we like */
45137c478bd9Sstevel@tonic-gate #ifdef USE_UEF_CLIENT
45147c478bd9Sstevel@tonic-gate 	cipher = available_ciphers1;
45157c478bd9Sstevel@tonic-gate #else
45167c478bd9Sstevel@tonic-gate 	cipher = available_ciphers;
45177c478bd9Sstevel@tonic-gate #endif
45187c478bd9Sstevel@tonic-gate 	while (cipher->name) {
45197c478bd9Sstevel@tonic-gate 	    /* examine each cipher we support, see if it meets our security
45207c478bd9Sstevel@tonic-gate 	       requirements, and see if the server supports it.
45217c478bd9Sstevel@tonic-gate 	       choose the best one of these */
45227c478bd9Sstevel@tonic-gate 	    if ((limit >= cipher->ssf) && (musthave <= cipher->ssf) &&
45237c478bd9Sstevel@tonic-gate 		(ciphers & cipher->flag) &&
45247c478bd9Sstevel@tonic-gate 		(!ctext->cipher || (cipher->ssf > ctext->cipher->ssf))) {
45257c478bd9Sstevel@tonic-gate 		ctext->cipher = cipher;
45267c478bd9Sstevel@tonic-gate 	    }
45277c478bd9Sstevel@tonic-gate 	    cipher++;
45287c478bd9Sstevel@tonic-gate 	}
45297c478bd9Sstevel@tonic-gate 
45307c478bd9Sstevel@tonic-gate 	if (ctext->cipher) {
45317c478bd9Sstevel@tonic-gate 	    /* we found a cipher we like */
45327c478bd9Sstevel@tonic-gate 	    ctext->protection = DIGEST_PRIVACY;
45337c478bd9Sstevel@tonic-gate 	} else {
45347c478bd9Sstevel@tonic-gate 	    /* we didn't find any ciphers we like */
45357c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
45367c478bd9Sstevel@tonic-gate 	    params->utils->seterror(params->utils->conn, 0,
45377c478bd9Sstevel@tonic-gate 				    gettext("No good privacy layers"));
45387c478bd9Sstevel@tonic-gate #else
45397c478bd9Sstevel@tonic-gate 	    params->utils->seterror(params->utils->conn, 0,
45407c478bd9Sstevel@tonic-gate 				    "No good privacy layers");
45417c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
45427c478bd9Sstevel@tonic-gate 	}
45437c478bd9Sstevel@tonic-gate     }
45447c478bd9Sstevel@tonic-gate 
45457c478bd9Sstevel@tonic-gate     if (ctext->cipher == NULL) {
45467c478bd9Sstevel@tonic-gate 	/* we failed to find an encryption layer we liked;
45477c478bd9Sstevel@tonic-gate 	   can we use integrity or nothing? */
45487c478bd9Sstevel@tonic-gate 
45497c478bd9Sstevel@tonic-gate 	if ((limit >= 1) && (musthave <= 1)
45507c478bd9Sstevel@tonic-gate 	    && (protection & DIGEST_INTEGRITY)) {
45517c478bd9Sstevel@tonic-gate 	    /* integrity */
45527c478bd9Sstevel@tonic-gate 	    ctext->protection = DIGEST_INTEGRITY;
45537c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
45547c478bd9Sstevel@tonic-gate 	} else if (musthave == 0) {
45557c478bd9Sstevel@tonic-gate #else
45567c478bd9Sstevel@tonic-gate 	} else if (musthave <= 0) {
45577c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
45587c478bd9Sstevel@tonic-gate 	    /* no layer */
45597c478bd9Sstevel@tonic-gate 	    ctext->protection = DIGEST_NOLAYER;
45607c478bd9Sstevel@tonic-gate 
45617c478bd9Sstevel@tonic-gate 	    /* See if server supports not having a layer */
45627c478bd9Sstevel@tonic-gate 	    if ((protection & DIGEST_NOLAYER) != DIGEST_NOLAYER) {
45637c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
45647c478bd9Sstevel@tonic-gate 		params->utils->seterror(params->utils->conn, 0,
45657c478bd9Sstevel@tonic-gate 			gettext("Server doesn't support \"no layer\""));
45667c478bd9Sstevel@tonic-gate #else
45677c478bd9Sstevel@tonic-gate 		params->utils->seterror(params->utils->conn, 0,
45687c478bd9Sstevel@tonic-gate 					"Server doesn't support \"no layer\"");
45697c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
45707c478bd9Sstevel@tonic-gate 		result = SASL_FAIL;
45717c478bd9Sstevel@tonic-gate 		goto FreeAllocatedMem;
45727c478bd9Sstevel@tonic-gate 	    }
45737c478bd9Sstevel@tonic-gate 	} else {
45747c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
45757c478bd9Sstevel@tonic-gate 	    params->utils->seterror(params->utils->conn, 0,
45767c478bd9Sstevel@tonic-gate 				    gettext("Can't find an acceptable layer"));
45777c478bd9Sstevel@tonic-gate #else
45787c478bd9Sstevel@tonic-gate 	    params->utils->seterror(params->utils->conn, 0,
45797c478bd9Sstevel@tonic-gate 				    "Can't find an acceptable layer");
45807c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
45817c478bd9Sstevel@tonic-gate 	    result = SASL_TOOWEAK;
45827c478bd9Sstevel@tonic-gate 	    goto FreeAllocatedMem;
45837c478bd9Sstevel@tonic-gate 	}
45847c478bd9Sstevel@tonic-gate     }
45857c478bd9Sstevel@tonic-gate 
45867c478bd9Sstevel@tonic-gate     *outrealms = realms;
45877c478bd9Sstevel@tonic-gate     *noutrealm = nrealm;
45887c478bd9Sstevel@tonic-gate 
45897c478bd9Sstevel@tonic-gate   FreeAllocatedMem:
45907c478bd9Sstevel@tonic-gate     if (in_start) params->utils->free(in_start);
45917c478bd9Sstevel@tonic-gate 
45927c478bd9Sstevel@tonic-gate     if (result != SASL_OK && realms) {
45937c478bd9Sstevel@tonic-gate 	int lup;
45947c478bd9Sstevel@tonic-gate 
45957c478bd9Sstevel@tonic-gate 	/* need to free all the realms */
45967c478bd9Sstevel@tonic-gate 	for (lup = 0;lup < nrealm; lup++)
45977c478bd9Sstevel@tonic-gate 	    params->utils->free(realms[lup]);
45987c478bd9Sstevel@tonic-gate 
45997c478bd9Sstevel@tonic-gate 	params->utils->free(realms);
46007c478bd9Sstevel@tonic-gate     }
46017c478bd9Sstevel@tonic-gate 
46027c478bd9Sstevel@tonic-gate     return result;
46037c478bd9Sstevel@tonic-gate }
46047c478bd9Sstevel@tonic-gate 
46057c478bd9Sstevel@tonic-gate static int ask_user_info(client_context_t *ctext,
46067c478bd9Sstevel@tonic-gate 			 sasl_client_params_t *params,
46077c478bd9Sstevel@tonic-gate 			 char **realms, int nrealm,
46087c478bd9Sstevel@tonic-gate 			 sasl_interact_t **prompt_need,
46097c478bd9Sstevel@tonic-gate 			 sasl_out_params_t *oparams)
46107c478bd9Sstevel@tonic-gate {
46117c478bd9Sstevel@tonic-gate     context_t *text = (context_t *) ctext;
46127c478bd9Sstevel@tonic-gate     int result = SASL_OK;
46137c478bd9Sstevel@tonic-gate     const char *authid = NULL, *userid = NULL, *realm = NULL;
46147c478bd9Sstevel@tonic-gate     char *realm_chal = NULL;
46157c478bd9Sstevel@tonic-gate     int user_result = SASL_OK;
46167c478bd9Sstevel@tonic-gate     int auth_result = SASL_OK;
46177c478bd9Sstevel@tonic-gate     int pass_result = SASL_OK;
46187c478bd9Sstevel@tonic-gate     int realm_result = SASL_FAIL;
46197c478bd9Sstevel@tonic-gate 
46207c478bd9Sstevel@tonic-gate     /* try to get the authid */
46217c478bd9Sstevel@tonic-gate     if (oparams->authid == NULL) {
46227c478bd9Sstevel@tonic-gate 	auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
46237c478bd9Sstevel@tonic-gate 
46247c478bd9Sstevel@tonic-gate 	if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT)) {
46257c478bd9Sstevel@tonic-gate 	    return auth_result;
46267c478bd9Sstevel@tonic-gate 	}
46277c478bd9Sstevel@tonic-gate     }
46287c478bd9Sstevel@tonic-gate 
46297c478bd9Sstevel@tonic-gate     /* try to get the userid */
46307c478bd9Sstevel@tonic-gate     if (oparams->user == NULL) {
46317c478bd9Sstevel@tonic-gate 	user_result = _plug_get_userid(params->utils, &userid, prompt_need);
46327c478bd9Sstevel@tonic-gate 
46337c478bd9Sstevel@tonic-gate 	if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
46347c478bd9Sstevel@tonic-gate 	    return user_result;
46357c478bd9Sstevel@tonic-gate 	}
46367c478bd9Sstevel@tonic-gate     }
46377c478bd9Sstevel@tonic-gate 
46387c478bd9Sstevel@tonic-gate     /* try to get the password */
46397c478bd9Sstevel@tonic-gate     if (ctext->password == NULL) {
46407c478bd9Sstevel@tonic-gate 	pass_result = _plug_get_password(params->utils, &ctext->password,
46417c478bd9Sstevel@tonic-gate 					 &ctext->free_password, prompt_need);
46427c478bd9Sstevel@tonic-gate 	if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT)) {
46437c478bd9Sstevel@tonic-gate 	    return pass_result;
46447c478bd9Sstevel@tonic-gate 	}
46457c478bd9Sstevel@tonic-gate     }
46467c478bd9Sstevel@tonic-gate 
46477c478bd9Sstevel@tonic-gate     /* try to get the realm */
46487c478bd9Sstevel@tonic-gate     if (text->realm == NULL) {
46497c478bd9Sstevel@tonic-gate 	if (realms) {
46507c478bd9Sstevel@tonic-gate 	    if(nrealm == 1) {
46517c478bd9Sstevel@tonic-gate 		/* only one choice */
46527c478bd9Sstevel@tonic-gate 		realm = realms[0];
46537c478bd9Sstevel@tonic-gate 		realm_result = SASL_OK;
46547c478bd9Sstevel@tonic-gate 	    } else {
46557c478bd9Sstevel@tonic-gate 		/* ask the user */
46567c478bd9Sstevel@tonic-gate 		realm_result = _plug_get_realm(params->utils,
46577c478bd9Sstevel@tonic-gate 					       (const char **) realms,
46587c478bd9Sstevel@tonic-gate 					       (const char **) &realm,
46597c478bd9Sstevel@tonic-gate 					       prompt_need);
46607c478bd9Sstevel@tonic-gate 	    }
46617c478bd9Sstevel@tonic-gate 	}
46627c478bd9Sstevel@tonic-gate 
46637c478bd9Sstevel@tonic-gate 	/* fake the realm if we must */
46647c478bd9Sstevel@tonic-gate 	if ((realm_result != SASL_OK) && (realm_result != SASL_INTERACT)) {
46657c478bd9Sstevel@tonic-gate 	    if (params->serverFQDN) {
46667c478bd9Sstevel@tonic-gate 		realm = params->serverFQDN;
46677c478bd9Sstevel@tonic-gate 	    } else {
46687c478bd9Sstevel@tonic-gate 		return realm_result;
46697c478bd9Sstevel@tonic-gate 	    }
46707c478bd9Sstevel@tonic-gate 	}
46717c478bd9Sstevel@tonic-gate     }
46727c478bd9Sstevel@tonic-gate 
46737c478bd9Sstevel@tonic-gate     /* free prompts we got */
46747c478bd9Sstevel@tonic-gate     if (prompt_need && *prompt_need) {
46757c478bd9Sstevel@tonic-gate 	params->utils->free(*prompt_need);
46767c478bd9Sstevel@tonic-gate 	*prompt_need = NULL;
46777c478bd9Sstevel@tonic-gate     }
46787c478bd9Sstevel@tonic-gate 
46797c478bd9Sstevel@tonic-gate     /* if there are prompts not filled in */
46807c478bd9Sstevel@tonic-gate     if ((user_result == SASL_INTERACT) || (auth_result == SASL_INTERACT) ||
46817c478bd9Sstevel@tonic-gate 	(pass_result == SASL_INTERACT) || (realm_result == SASL_INTERACT)) {
46827c478bd9Sstevel@tonic-gate 
46837c478bd9Sstevel@tonic-gate 	/* make our default realm */
46847c478bd9Sstevel@tonic-gate 	if ((realm_result == SASL_INTERACT) && params->serverFQDN) {
46857c478bd9Sstevel@tonic-gate 	    realm_chal = params->utils->malloc(3+strlen(params->serverFQDN));
46867c478bd9Sstevel@tonic-gate 	    if (realm_chal) {
46877c478bd9Sstevel@tonic-gate 		sprintf(realm_chal, "{%s}", params->serverFQDN);
46887c478bd9Sstevel@tonic-gate 	    } else {
46897c478bd9Sstevel@tonic-gate 		return SASL_NOMEM;
46907c478bd9Sstevel@tonic-gate 	    }
46917c478bd9Sstevel@tonic-gate 	}
46927c478bd9Sstevel@tonic-gate 
46937c478bd9Sstevel@tonic-gate 	/* make the prompt list */
46947c478bd9Sstevel@tonic-gate 	result =
46957c478bd9Sstevel@tonic-gate #if defined _INTEGRATED_SOLARIS_
46967c478bd9Sstevel@tonic-gate 	    _plug_make_prompts(params->utils, &ctext->h, prompt_need,
46977c478bd9Sstevel@tonic-gate 			       user_result == SASL_INTERACT ?
46987c478bd9Sstevel@tonic-gate 			       convert_prompt(params->utils, &ctext->h,
46997c478bd9Sstevel@tonic-gate 			       gettext("Please enter your authorization name"))
47007c478bd9Sstevel@tonic-gate 					: NULL,
47017c478bd9Sstevel@tonic-gate 			       NULL,
47027c478bd9Sstevel@tonic-gate 			       auth_result == SASL_INTERACT ?
47037c478bd9Sstevel@tonic-gate 			       convert_prompt(params->utils, &ctext->h,
47047c478bd9Sstevel@tonic-gate 			gettext("Please enter your authentication name"))
47057c478bd9Sstevel@tonic-gate 					: NULL,
47067c478bd9Sstevel@tonic-gate 			       NULL,
47077c478bd9Sstevel@tonic-gate 			       pass_result == SASL_INTERACT ?
47087c478bd9Sstevel@tonic-gate 			       convert_prompt(params->utils, &ctext->h,
47097c478bd9Sstevel@tonic-gate 					gettext("Please enter your password"))
47107c478bd9Sstevel@tonic-gate 					: NULL, NULL,
47117c478bd9Sstevel@tonic-gate 			       NULL, NULL, NULL,
47127c478bd9Sstevel@tonic-gate 			       realm_chal ? realm_chal : "{}",
47137c478bd9Sstevel@tonic-gate 			       realm_result == SASL_INTERACT ?
47147c478bd9Sstevel@tonic-gate 			       convert_prompt(params->utils, &ctext->h,
47157c478bd9Sstevel@tonic-gate 				    gettext("Please enter your realm")) : NULL,
47167c478bd9Sstevel@tonic-gate 			       params->serverFQDN ? params->serverFQDN : NULL);
47177c478bd9Sstevel@tonic-gate #else
47187c478bd9Sstevel@tonic-gate 	    _plug_make_prompts(params->utils, prompt_need,
47197c478bd9Sstevel@tonic-gate 			       user_result == SASL_INTERACT ?
47207c478bd9Sstevel@tonic-gate 			       "Please enter your authorization name" : NULL,
47217c478bd9Sstevel@tonic-gate 			       NULL,
47227c478bd9Sstevel@tonic-gate 			       auth_result == SASL_INTERACT ?
47237c478bd9Sstevel@tonic-gate 			       "Please enter your authentication name" : NULL,
47247c478bd9Sstevel@tonic-gate 			       NULL,
47257c478bd9Sstevel@tonic-gate 			       pass_result == SASL_INTERACT ?
47267c478bd9Sstevel@tonic-gate 			       "Please enter your password" : NULL, NULL,
47277c478bd9Sstevel@tonic-gate 			       NULL, NULL, NULL,
47287c478bd9Sstevel@tonic-gate 			       realm_chal ? realm_chal : "{}",
47297c478bd9Sstevel@tonic-gate 			       realm_result == SASL_INTERACT ?
47307c478bd9Sstevel@tonic-gate 			       "Please enter your realm" : NULL,
47317c478bd9Sstevel@tonic-gate 			       params->serverFQDN ? params->serverFQDN : NULL);
47327c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
47337c478bd9Sstevel@tonic-gate 
47347c478bd9Sstevel@tonic-gate 	if (result == SASL_OK) return SASL_INTERACT;
47357c478bd9Sstevel@tonic-gate 
47367c478bd9Sstevel@tonic-gate 	return result;
47377c478bd9Sstevel@tonic-gate     }
47387c478bd9Sstevel@tonic-gate 
47397c478bd9Sstevel@tonic-gate     if (oparams->authid == NULL) {
47407c478bd9Sstevel@tonic-gate 	if (!userid || !*userid) {
47417c478bd9Sstevel@tonic-gate 	    result = params->canon_user(params->utils->conn, authid, 0,
47427c478bd9Sstevel@tonic-gate 					SASL_CU_AUTHID | SASL_CU_AUTHZID,
47437c478bd9Sstevel@tonic-gate 					oparams);
47447c478bd9Sstevel@tonic-gate 	}
47457c478bd9Sstevel@tonic-gate 	else {
47467c478bd9Sstevel@tonic-gate 	    result = params->canon_user(params->utils->conn,
47477c478bd9Sstevel@tonic-gate 					authid, 0, SASL_CU_AUTHID, oparams);
47487c478bd9Sstevel@tonic-gate 	    if (result != SASL_OK) return result;
47497c478bd9Sstevel@tonic-gate 
47507c478bd9Sstevel@tonic-gate 	    result = params->canon_user(params->utils->conn,
47517c478bd9Sstevel@tonic-gate 					userid, 0, SASL_CU_AUTHZID, oparams);
47527c478bd9Sstevel@tonic-gate 	}
47537c478bd9Sstevel@tonic-gate 	if (result != SASL_OK) return result;
47547c478bd9Sstevel@tonic-gate     }
47557c478bd9Sstevel@tonic-gate 
47567c478bd9Sstevel@tonic-gate     /* Get an allocated version of the realm into the structure */
47577c478bd9Sstevel@tonic-gate     if (realm && text->realm == NULL) {
47587c478bd9Sstevel@tonic-gate 	_plug_strdup(params->utils, realm, (char **) &text->realm, NULL);
47597c478bd9Sstevel@tonic-gate     }
47607c478bd9Sstevel@tonic-gate 
47617c478bd9Sstevel@tonic-gate     return result;
47627c478bd9Sstevel@tonic-gate }
47637c478bd9Sstevel@tonic-gate 
47647c478bd9Sstevel@tonic-gate static int
47657c478bd9Sstevel@tonic-gate digestmd5_client_mech_new(void *glob_context,
47667c478bd9Sstevel@tonic-gate 			  sasl_client_params_t * params,
47677c478bd9Sstevel@tonic-gate 			  void **conn_context)
47687c478bd9Sstevel@tonic-gate {
47697c478bd9Sstevel@tonic-gate     context_t *text;
47707c478bd9Sstevel@tonic-gate 
47717c478bd9Sstevel@tonic-gate     /* holds state are in -- allocate client size */
47727c478bd9Sstevel@tonic-gate     text = params->utils->malloc(sizeof(client_context_t));
47737c478bd9Sstevel@tonic-gate     if (text == NULL)
47747c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
47757c478bd9Sstevel@tonic-gate     memset(text, 0, sizeof(client_context_t));
47767c478bd9Sstevel@tonic-gate 
47777c478bd9Sstevel@tonic-gate     text->state = 1;
47787c478bd9Sstevel@tonic-gate     text->i_am = CLIENT;
47797c478bd9Sstevel@tonic-gate     text->reauth = glob_context;
47807c478bd9Sstevel@tonic-gate 
47817c478bd9Sstevel@tonic-gate     *conn_context = text;
47827c478bd9Sstevel@tonic-gate 
47837c478bd9Sstevel@tonic-gate     return SASL_OK;
47847c478bd9Sstevel@tonic-gate }
47857c478bd9Sstevel@tonic-gate 
47867c478bd9Sstevel@tonic-gate static int
47877c478bd9Sstevel@tonic-gate digestmd5_client_mech_step1(client_context_t *ctext,
47887c478bd9Sstevel@tonic-gate 			    sasl_client_params_t *params,
47897c478bd9Sstevel@tonic-gate 			    const char *serverin __attribute__((unused)),
47907c478bd9Sstevel@tonic-gate 			    unsigned serverinlen __attribute__((unused)),
47917c478bd9Sstevel@tonic-gate 			    sasl_interact_t **prompt_need,
47927c478bd9Sstevel@tonic-gate 			    const char **clientout,
47937c478bd9Sstevel@tonic-gate 			    unsigned *clientoutlen,
47947c478bd9Sstevel@tonic-gate 			    sasl_out_params_t *oparams)
47957c478bd9Sstevel@tonic-gate {
47967c478bd9Sstevel@tonic-gate     context_t *text = (context_t *) ctext;
47977c478bd9Sstevel@tonic-gate     int result = SASL_FAIL;
47987c478bd9Sstevel@tonic-gate     unsigned val;
47997c478bd9Sstevel@tonic-gate 
48007c478bd9Sstevel@tonic-gate     params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
48017c478bd9Sstevel@tonic-gate 		       "DIGEST-MD5 client step 1");
48027c478bd9Sstevel@tonic-gate 
48037c478bd9Sstevel@tonic-gate     result = ask_user_info(ctext, params, NULL, 0, prompt_need, oparams);
48047c478bd9Sstevel@tonic-gate     if (result != SASL_OK) return result;
48057c478bd9Sstevel@tonic-gate 
48067c478bd9Sstevel@tonic-gate     /* check if we have cached info for this user on this server */
48077c478bd9Sstevel@tonic-gate     val = hash(params->serverFQDN) % text->reauth->size;
48087c478bd9Sstevel@tonic-gate     if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
48097c478bd9Sstevel@tonic-gate 	if (text->reauth->e[val].u.c.serverFQDN &&
48107c478bd9Sstevel@tonic-gate 	    !strcasecmp(text->reauth->e[val].u.c.serverFQDN,
48117c478bd9Sstevel@tonic-gate 			params->serverFQDN) &&
48127c478bd9Sstevel@tonic-gate 	    !strcmp(text->reauth->e[val].authid, oparams->authid)) {
48137c478bd9Sstevel@tonic-gate 
48147c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
48157c478bd9Sstevel@tonic-gate 	    if (text->realm) params->utils->free(text->realm);
48167c478bd9Sstevel@tonic-gate 	    if (text->nonce) params->utils->free(text->nonce);
48177c478bd9Sstevel@tonic-gate 	    if (text->cnonce) params->utils->free(text->cnonce);
48187c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
48197c478bd9Sstevel@tonic-gate 	    /* we have info, so use it */
48207c478bd9Sstevel@tonic-gate 	    _plug_strdup(params->utils, text->reauth->e[val].realm,
48217c478bd9Sstevel@tonic-gate 			 &text->realm, NULL);
48227c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
48237c478bd9Sstevel@tonic-gate 	    _plug_strdup(params->utils, (char *)text->reauth->e[val].nonce,
48247c478bd9Sstevel@tonic-gate 			 (char **) &text->nonce, NULL);
48257c478bd9Sstevel@tonic-gate #else
48267c478bd9Sstevel@tonic-gate 	    _plug_strdup(params->utils, text->reauth->e[val].nonce,
48277c478bd9Sstevel@tonic-gate 			 (char **) &text->nonce, NULL);
48287c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
48297c478bd9Sstevel@tonic-gate 	    text->nonce_count = ++text->reauth->e[val].nonce_count;
48307c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
48317c478bd9Sstevel@tonic-gate 	    _plug_strdup(params->utils, (char *)text->reauth->e[val].cnonce,
48327c478bd9Sstevel@tonic-gate 			 (char **) &text->cnonce, NULL);
48337c478bd9Sstevel@tonic-gate #else
48347c478bd9Sstevel@tonic-gate 	    _plug_strdup(params->utils, text->reauth->e[val].cnonce,
48357c478bd9Sstevel@tonic-gate 			 (char **) &text->cnonce, NULL);
48367c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
48377c478bd9Sstevel@tonic-gate 	    ctext->protection = text->reauth->e[val].u.c.protection;
48387c478bd9Sstevel@tonic-gate 	    ctext->cipher = text->reauth->e[val].u.c.cipher;
48397c478bd9Sstevel@tonic-gate 	    ctext->server_maxbuf = text->reauth->e[val].u.c.server_maxbuf;
48407c478bd9Sstevel@tonic-gate 	}
48417c478bd9Sstevel@tonic-gate 	params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
48427c478bd9Sstevel@tonic-gate     }
48437c478bd9Sstevel@tonic-gate 
48447c478bd9Sstevel@tonic-gate     if (!text->nonce) {
48457c478bd9Sstevel@tonic-gate 	/* we don't have any reauth info, so just return
48467c478bd9Sstevel@tonic-gate 	 * that there is no initial client send */
48477c478bd9Sstevel@tonic-gate 	text->state = 2;
48487c478bd9Sstevel@tonic-gate 	return SASL_CONTINUE;
48497c478bd9Sstevel@tonic-gate     }
48507c478bd9Sstevel@tonic-gate 
48517c478bd9Sstevel@tonic-gate     /*
48527c478bd9Sstevel@tonic-gate      * (username | realm | nonce | cnonce | nonce-count | qop digest-uri |
48537c478bd9Sstevel@tonic-gate      * response | maxbuf | charset | auth-param )
48547c478bd9Sstevel@tonic-gate      */
48557c478bd9Sstevel@tonic-gate 
48567c478bd9Sstevel@tonic-gate     result = make_client_response(text, params, oparams);
48577c478bd9Sstevel@tonic-gate     if (result != SASL_OK) return result;
48587c478bd9Sstevel@tonic-gate 
48597c478bd9Sstevel@tonic-gate     *clientoutlen = strlen(text->out_buf);
48607c478bd9Sstevel@tonic-gate     *clientout = text->out_buf;
48617c478bd9Sstevel@tonic-gate 
48627c478bd9Sstevel@tonic-gate     text->state = 3;
48637c478bd9Sstevel@tonic-gate     return SASL_CONTINUE;
48647c478bd9Sstevel@tonic-gate }
48657c478bd9Sstevel@tonic-gate 
48667c478bd9Sstevel@tonic-gate static int
48677c478bd9Sstevel@tonic-gate digestmd5_client_mech_step2(client_context_t *ctext,
48687c478bd9Sstevel@tonic-gate 			    sasl_client_params_t *params,
48697c478bd9Sstevel@tonic-gate 			    const char *serverin,
48707c478bd9Sstevel@tonic-gate 			    unsigned serverinlen,
48717c478bd9Sstevel@tonic-gate 			    sasl_interact_t **prompt_need,
48727c478bd9Sstevel@tonic-gate 			    const char **clientout,
48737c478bd9Sstevel@tonic-gate 			    unsigned *clientoutlen,
48747c478bd9Sstevel@tonic-gate 			    sasl_out_params_t *oparams)
48757c478bd9Sstevel@tonic-gate {
48767c478bd9Sstevel@tonic-gate     context_t *text = (context_t *) ctext;
48777c478bd9Sstevel@tonic-gate     int result = SASL_FAIL;
48787c478bd9Sstevel@tonic-gate     char **realms = NULL;
48797c478bd9Sstevel@tonic-gate     int nrealm = 0;
48807c478bd9Sstevel@tonic-gate 
48817c478bd9Sstevel@tonic-gate     params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
48827c478bd9Sstevel@tonic-gate 		       "DIGEST-MD5 client step 2");
48837c478bd9Sstevel@tonic-gate 
48847c478bd9Sstevel@tonic-gate     if (params->props.min_ssf > params->props.max_ssf) {
48857c478bd9Sstevel@tonic-gate 	return SASL_BADPARAM;
48867c478bd9Sstevel@tonic-gate     }
48877c478bd9Sstevel@tonic-gate 
48887c478bd9Sstevel@tonic-gate     /* don't bother parsing the challenge more than once */
48897c478bd9Sstevel@tonic-gate     if (text->nonce == NULL) {
48907c478bd9Sstevel@tonic-gate 	result = parse_server_challenge(ctext, params, serverin, serverinlen,
48917c478bd9Sstevel@tonic-gate 					&realms, &nrealm);
48927c478bd9Sstevel@tonic-gate 	if (result != SASL_OK) goto FreeAllocatedMem;
48937c478bd9Sstevel@tonic-gate 
48947c478bd9Sstevel@tonic-gate 	if (nrealm == 1) {
48957c478bd9Sstevel@tonic-gate 	    /* only one choice! */
48967c478bd9Sstevel@tonic-gate 	    text->realm = realms[0];
48977c478bd9Sstevel@tonic-gate 
48987c478bd9Sstevel@tonic-gate 	    /* free realms */
48997c478bd9Sstevel@tonic-gate 	    params->utils->free(realms);
49007c478bd9Sstevel@tonic-gate 	    realms = NULL;
49017c478bd9Sstevel@tonic-gate 	}
49027c478bd9Sstevel@tonic-gate     }
49037c478bd9Sstevel@tonic-gate 
49047c478bd9Sstevel@tonic-gate     result = ask_user_info(ctext, params, realms, nrealm,
49057c478bd9Sstevel@tonic-gate 			   prompt_need, oparams);
49067c478bd9Sstevel@tonic-gate     if (result != SASL_OK) goto FreeAllocatedMem;
49077c478bd9Sstevel@tonic-gate 
49087c478bd9Sstevel@tonic-gate     /*
49097c478bd9Sstevel@tonic-gate      * (username | realm | nonce | cnonce | nonce-count | qop digest-uri |
49107c478bd9Sstevel@tonic-gate      * response | maxbuf | charset | auth-param )
49117c478bd9Sstevel@tonic-gate      */
49127c478bd9Sstevel@tonic-gate 
49137c478bd9Sstevel@tonic-gate     result = make_client_response(text, params, oparams);
49147c478bd9Sstevel@tonic-gate     if (result != SASL_OK) goto FreeAllocatedMem;
49157c478bd9Sstevel@tonic-gate 
49167c478bd9Sstevel@tonic-gate     *clientoutlen = strlen(text->out_buf);
49177c478bd9Sstevel@tonic-gate     *clientout = text->out_buf;
49187c478bd9Sstevel@tonic-gate 
49197c478bd9Sstevel@tonic-gate     text->state = 3;
49207c478bd9Sstevel@tonic-gate 
49217c478bd9Sstevel@tonic-gate     result = SASL_CONTINUE;
49227c478bd9Sstevel@tonic-gate 
49237c478bd9Sstevel@tonic-gate   FreeAllocatedMem:
49247c478bd9Sstevel@tonic-gate     if (realms) {
49257c478bd9Sstevel@tonic-gate 	int lup;
49267c478bd9Sstevel@tonic-gate 
49277c478bd9Sstevel@tonic-gate 	/* need to free all the realms */
49287c478bd9Sstevel@tonic-gate 	for (lup = 0;lup < nrealm; lup++)
49297c478bd9Sstevel@tonic-gate 	    params->utils->free(realms[lup]);
49307c478bd9Sstevel@tonic-gate 
49317c478bd9Sstevel@tonic-gate 	params->utils->free(realms);
49327c478bd9Sstevel@tonic-gate     }
49337c478bd9Sstevel@tonic-gate 
49347c478bd9Sstevel@tonic-gate     return result;
49357c478bd9Sstevel@tonic-gate }
49367c478bd9Sstevel@tonic-gate 
49377c478bd9Sstevel@tonic-gate static int
49387c478bd9Sstevel@tonic-gate digestmd5_client_mech_step3(client_context_t *ctext,
49397c478bd9Sstevel@tonic-gate 			    sasl_client_params_t *params,
49407c478bd9Sstevel@tonic-gate 			    const char *serverin,
49417c478bd9Sstevel@tonic-gate 			    unsigned serverinlen,
49427c478bd9Sstevel@tonic-gate 			    sasl_interact_t **prompt_need __attribute__((unused)),
49437c478bd9Sstevel@tonic-gate 			    const char **clientout __attribute__((unused)),
49447c478bd9Sstevel@tonic-gate 			    unsigned *clientoutlen __attribute__((unused)),
49457c478bd9Sstevel@tonic-gate 			    sasl_out_params_t *oparams)
49467c478bd9Sstevel@tonic-gate {
49477c478bd9Sstevel@tonic-gate     context_t *text = (context_t *) ctext;
49487c478bd9Sstevel@tonic-gate     char           *in = NULL;
49497c478bd9Sstevel@tonic-gate     char           *in_start;
49507c478bd9Sstevel@tonic-gate     int result = SASL_FAIL;
49517c478bd9Sstevel@tonic-gate 
49527c478bd9Sstevel@tonic-gate     params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
49537c478bd9Sstevel@tonic-gate 		       "DIGEST-MD5 client step 3");
49547c478bd9Sstevel@tonic-gate 
495548bbca81SDaniel Hoffman     /* Verify that server is really what they claim to be */
49567c478bd9Sstevel@tonic-gate     in_start = in = params->utils->malloc(serverinlen + 1);
49577c478bd9Sstevel@tonic-gate     if (in == NULL) return SASL_NOMEM;
49587c478bd9Sstevel@tonic-gate 
49597c478bd9Sstevel@tonic-gate     memcpy(in, serverin, serverinlen);
49607c478bd9Sstevel@tonic-gate     in[serverinlen] = 0;
49617c478bd9Sstevel@tonic-gate 
49627c478bd9Sstevel@tonic-gate     /* parse the response */
49637c478bd9Sstevel@tonic-gate     while (in[0] != '\0') {
49647c478bd9Sstevel@tonic-gate 	char *name, *value;
49657c478bd9Sstevel@tonic-gate 	get_pair(&in, &name, &value);
49667c478bd9Sstevel@tonic-gate 
49677c478bd9Sstevel@tonic-gate 	if (name == NULL) {
49687c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
49697c478bd9Sstevel@tonic-gate 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
49707c478bd9Sstevel@tonic-gate 			       "DIGEST-MD5 Received Garbage");
49717c478bd9Sstevel@tonic-gate #else
49727c478bd9Sstevel@tonic-gate 	    params->utils->seterror(params->utils->conn, 0,
49737c478bd9Sstevel@tonic-gate 				    "DIGEST-MD5 Received Garbage");
49747c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
49757c478bd9Sstevel@tonic-gate 	    break;
49767c478bd9Sstevel@tonic-gate 	}
49777c478bd9Sstevel@tonic-gate 
49787c478bd9Sstevel@tonic-gate 	if (strcasecmp(name, "rspauth") == 0) {
49797c478bd9Sstevel@tonic-gate 
49807c478bd9Sstevel@tonic-gate 	    if (strcmp(text->response_value, value) != 0) {
49817c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
49827c478bd9Sstevel@tonic-gate 		params->utils->seterror(params->utils->conn, 0,
49837c478bd9Sstevel@tonic-gate 			gettext("Server authentication failed"));
49847c478bd9Sstevel@tonic-gate #else
49857c478bd9Sstevel@tonic-gate 		params->utils->seterror(params->utils->conn, 0,
49867c478bd9Sstevel@tonic-gate 					"DIGEST-MD5: This server wants us to believe that he knows shared secret");
49877c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
49887c478bd9Sstevel@tonic-gate 		result = SASL_FAIL;
49897c478bd9Sstevel@tonic-gate 	    } else {
49907c478bd9Sstevel@tonic-gate 		oparams->doneflag = 1;
49917c478bd9Sstevel@tonic-gate 		oparams->param_version = 0;
49927c478bd9Sstevel@tonic-gate 
49937c478bd9Sstevel@tonic-gate 		result = SASL_OK;
49947c478bd9Sstevel@tonic-gate 	    }
49957c478bd9Sstevel@tonic-gate 	    break;
49967c478bd9Sstevel@tonic-gate 	} else {
49977c478bd9Sstevel@tonic-gate 	    params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
49987c478bd9Sstevel@tonic-gate 			       "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
49997c478bd9Sstevel@tonic-gate 			       name, value);
50007c478bd9Sstevel@tonic-gate 	}
50017c478bd9Sstevel@tonic-gate     }
50027c478bd9Sstevel@tonic-gate 
50037c478bd9Sstevel@tonic-gate     params->utils->free(in_start);
50047c478bd9Sstevel@tonic-gate 
50057c478bd9Sstevel@tonic-gate     if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
50067c478bd9Sstevel@tonic-gate 	unsigned val = hash(params->serverFQDN) % text->reauth->size;
50077c478bd9Sstevel@tonic-gate 	switch (result) {
50087c478bd9Sstevel@tonic-gate 	case SASL_OK:
50097c478bd9Sstevel@tonic-gate 	    if (text->nonce_count == 1) {
50107c478bd9Sstevel@tonic-gate 		/* successful initial auth, setup for future reauth */
50117c478bd9Sstevel@tonic-gate 		clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
50127c478bd9Sstevel@tonic-gate 		_plug_strdup(params->utils, oparams->authid,
50137c478bd9Sstevel@tonic-gate 			     &text->reauth->e[val].authid, NULL);
50147c478bd9Sstevel@tonic-gate 		text->reauth->e[val].realm = text->realm; text->realm = NULL;
50157c478bd9Sstevel@tonic-gate 		text->reauth->e[val].nonce = text->nonce; text->nonce = NULL;
50167c478bd9Sstevel@tonic-gate 		text->reauth->e[val].nonce_count = text->nonce_count;
50177c478bd9Sstevel@tonic-gate 		text->reauth->e[val].cnonce = text->cnonce; text->cnonce = NULL;
50187c478bd9Sstevel@tonic-gate 		_plug_strdup(params->utils, params->serverFQDN,
50197c478bd9Sstevel@tonic-gate 			     &text->reauth->e[val].u.c.serverFQDN, NULL);
50207c478bd9Sstevel@tonic-gate 		text->reauth->e[val].u.c.protection = ctext->protection;
50217c478bd9Sstevel@tonic-gate 		text->reauth->e[val].u.c.cipher = ctext->cipher;
50227c478bd9Sstevel@tonic-gate 		text->reauth->e[val].u.c.server_maxbuf = ctext->server_maxbuf;
50237c478bd9Sstevel@tonic-gate 	    }
50247c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
50257c478bd9Sstevel@tonic-gate 	    else {
50267c478bd9Sstevel@tonic-gate 		/* reauth, we already incremented nonce_count */
50277c478bd9Sstevel@tonic-gate 	    }
50287c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
50297c478bd9Sstevel@tonic-gate 	    break;
50307c478bd9Sstevel@tonic-gate 	default:
50317c478bd9Sstevel@tonic-gate 	    if (text->nonce_count > 1) {
50327c478bd9Sstevel@tonic-gate 		/* failed reauth, clear cache */
50337c478bd9Sstevel@tonic-gate 		clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
50347c478bd9Sstevel@tonic-gate 	    }
50357c478bd9Sstevel@tonic-gate 	    else {
50367c478bd9Sstevel@tonic-gate 		/* failed initial auth, leave existing cache */
50377c478bd9Sstevel@tonic-gate 	    }
50387c478bd9Sstevel@tonic-gate 	}
50397c478bd9Sstevel@tonic-gate 	params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
50407c478bd9Sstevel@tonic-gate     }
50417c478bd9Sstevel@tonic-gate 
50427c478bd9Sstevel@tonic-gate     return result;
50437c478bd9Sstevel@tonic-gate }
50447c478bd9Sstevel@tonic-gate 
50457c478bd9Sstevel@tonic-gate static int
50467c478bd9Sstevel@tonic-gate digestmd5_client_mech_step(void *conn_context,
50477c478bd9Sstevel@tonic-gate 			   sasl_client_params_t *params,
50487c478bd9Sstevel@tonic-gate 			   const char *serverin,
50497c478bd9Sstevel@tonic-gate 			   unsigned serverinlen,
50507c478bd9Sstevel@tonic-gate 			   sasl_interact_t **prompt_need,
50517c478bd9Sstevel@tonic-gate 			   const char **clientout,
50527c478bd9Sstevel@tonic-gate 			   unsigned *clientoutlen,
50537c478bd9Sstevel@tonic-gate 			   sasl_out_params_t *oparams)
50547c478bd9Sstevel@tonic-gate {
50557c478bd9Sstevel@tonic-gate     context_t *text = (context_t *) conn_context;
50567c478bd9Sstevel@tonic-gate     client_context_t *ctext = (client_context_t *) conn_context;
50577c478bd9Sstevel@tonic-gate     unsigned val = hash(params->serverFQDN) % text->reauth->size;
50587c478bd9Sstevel@tonic-gate 
50597c478bd9Sstevel@tonic-gate     if (serverinlen > 2048) return SASL_BADPROT;
50607c478bd9Sstevel@tonic-gate 
50617c478bd9Sstevel@tonic-gate     *clientout = NULL;
50627c478bd9Sstevel@tonic-gate     *clientoutlen = 0;
50637c478bd9Sstevel@tonic-gate 
50647c478bd9Sstevel@tonic-gate     switch (text->state) {
50657c478bd9Sstevel@tonic-gate 
50667c478bd9Sstevel@tonic-gate     case 1:
50677c478bd9Sstevel@tonic-gate 	if (!serverin) {
50687c478bd9Sstevel@tonic-gate 	    /* here's where we attempt fast reauth if possible */
50697c478bd9Sstevel@tonic-gate 	    int reauth = 0;
50707c478bd9Sstevel@tonic-gate 
50717c478bd9Sstevel@tonic-gate 	    /* check if we have saved info for this server */
50727c478bd9Sstevel@tonic-gate 	    if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
50737c478bd9Sstevel@tonic-gate 		reauth = text->reauth->e[val].u.c.serverFQDN &&
50747c478bd9Sstevel@tonic-gate 		    !strcasecmp(text->reauth->e[val].u.c.serverFQDN,
50757c478bd9Sstevel@tonic-gate 				params->serverFQDN);
50767c478bd9Sstevel@tonic-gate 		params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
50777c478bd9Sstevel@tonic-gate 	    }
50787c478bd9Sstevel@tonic-gate 	    if (reauth) {
50797c478bd9Sstevel@tonic-gate 		return digestmd5_client_mech_step1(ctext, params,
50807c478bd9Sstevel@tonic-gate 						   serverin, serverinlen,
50817c478bd9Sstevel@tonic-gate 						   prompt_need,
50827c478bd9Sstevel@tonic-gate 						   clientout, clientoutlen,
50837c478bd9Sstevel@tonic-gate 						   oparams);
50847c478bd9Sstevel@tonic-gate 	    }
50857c478bd9Sstevel@tonic-gate 	    else {
50867c478bd9Sstevel@tonic-gate 		/* we don't have any reauth info, so just return
50877c478bd9Sstevel@tonic-gate 		 * that there is no initial client send */
50887c478bd9Sstevel@tonic-gate 		text->state = 2;
50897c478bd9Sstevel@tonic-gate 		return SASL_CONTINUE;
50907c478bd9Sstevel@tonic-gate 	    }
50917c478bd9Sstevel@tonic-gate 	}
50927c478bd9Sstevel@tonic-gate 
50937c478bd9Sstevel@tonic-gate 	/* fall through and respond to challenge */
5094*7a7d534fSToomas Soome 	/* FALLTHROUGH */
50957c478bd9Sstevel@tonic-gate 
50967c478bd9Sstevel@tonic-gate     case 3:
50977c478bd9Sstevel@tonic-gate 	if (serverin && !strncasecmp(serverin, "rspauth=", 8)) {
50987c478bd9Sstevel@tonic-gate 	    return digestmd5_client_mech_step3(ctext, params,
50997c478bd9Sstevel@tonic-gate 					       serverin, serverinlen,
51007c478bd9Sstevel@tonic-gate 					       prompt_need,
51017c478bd9Sstevel@tonic-gate 					       clientout, clientoutlen,
51027c478bd9Sstevel@tonic-gate 					       oparams);
51037c478bd9Sstevel@tonic-gate 	}
51047c478bd9Sstevel@tonic-gate 
51057c478bd9Sstevel@tonic-gate 	/* fall through and respond to challenge */
51067c478bd9Sstevel@tonic-gate 	text->state = 2;
51077c478bd9Sstevel@tonic-gate 
51087c478bd9Sstevel@tonic-gate 	/* cleanup after a failed reauth attempt */
51097c478bd9Sstevel@tonic-gate 	if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
51107c478bd9Sstevel@tonic-gate 	    clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
51117c478bd9Sstevel@tonic-gate 
51127c478bd9Sstevel@tonic-gate 	    params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
51137c478bd9Sstevel@tonic-gate 	}
51147c478bd9Sstevel@tonic-gate 
51157c478bd9Sstevel@tonic-gate 	if (text->realm) params->utils->free(text->realm);
51167c478bd9Sstevel@tonic-gate 	if (text->nonce) params->utils->free(text->nonce);
51177c478bd9Sstevel@tonic-gate 	if (text->cnonce) params->utils->free(text->cnonce);
51187c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
51197c478bd9Sstevel@tonic-gate 	text->realm = NULL;
51207c478bd9Sstevel@tonic-gate 	text->nonce = text->cnonce = NULL;
51217c478bd9Sstevel@tonic-gate #else
51227c478bd9Sstevel@tonic-gate 	text->realm = text->nonce = text->cnonce = NULL;
51237c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
51247c478bd9Sstevel@tonic-gate 	ctext->cipher = NULL;
5125*7a7d534fSToomas Soome 	/* FALLTHROUGH */
51267c478bd9Sstevel@tonic-gate 
51277c478bd9Sstevel@tonic-gate     case 2:
51287c478bd9Sstevel@tonic-gate 	return digestmd5_client_mech_step2(ctext, params,
51297c478bd9Sstevel@tonic-gate 					   serverin, serverinlen,
51307c478bd9Sstevel@tonic-gate 					   prompt_need,
51317c478bd9Sstevel@tonic-gate 					   clientout, clientoutlen,
51327c478bd9Sstevel@tonic-gate 					   oparams);
51337c478bd9Sstevel@tonic-gate 
51347c478bd9Sstevel@tonic-gate     default:
51357c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
51367c478bd9Sstevel@tonic-gate 	params->utils->log(params->utils->conn, SASL_LOG_ERR,
51377c478bd9Sstevel@tonic-gate 			   "Invalid DIGEST-MD5 client step %d", text->state);
51387c478bd9Sstevel@tonic-gate #else
51397c478bd9Sstevel@tonic-gate 	params->utils->log(NULL, SASL_LOG_ERR,
51407c478bd9Sstevel@tonic-gate 			   "Invalid DIGEST-MD5 client step %d\n", text->state);
51417c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
51427c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
51437c478bd9Sstevel@tonic-gate     }
51447c478bd9Sstevel@tonic-gate 
51457c478bd9Sstevel@tonic-gate     return SASL_FAIL; /* should never get here */
51467c478bd9Sstevel@tonic-gate }
51477c478bd9Sstevel@tonic-gate 
51487c478bd9Sstevel@tonic-gate static void
51497c478bd9Sstevel@tonic-gate digestmd5_client_mech_dispose(void *conn_context, const sasl_utils_t *utils)
51507c478bd9Sstevel@tonic-gate {
51517c478bd9Sstevel@tonic-gate     client_context_t *ctext = (client_context_t *) conn_context;
51527c478bd9Sstevel@tonic-gate 
51537c478bd9Sstevel@tonic-gate     if (!ctext || !utils) return;
51547c478bd9Sstevel@tonic-gate 
51557c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
51567c478bd9Sstevel@tonic-gate     convert_prompt(utils, &ctext->h, NULL);
51577c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
51587c478bd9Sstevel@tonic-gate 
51597c478bd9Sstevel@tonic-gate     if (ctext->free_password) _plug_free_secret(utils, &ctext->password);
51607c478bd9Sstevel@tonic-gate 
51617c478bd9Sstevel@tonic-gate     digestmd5_common_mech_dispose(conn_context, utils);
51627c478bd9Sstevel@tonic-gate }
51637c478bd9Sstevel@tonic-gate 
51647c478bd9Sstevel@tonic-gate static sasl_client_plug_t digestmd5_client_plugins[] =
51657c478bd9Sstevel@tonic-gate {
51667c478bd9Sstevel@tonic-gate     {
51677c478bd9Sstevel@tonic-gate 	"DIGEST-MD5",
51687c478bd9Sstevel@tonic-gate #ifdef WITH_RC4				/* mech_name */
51697c478bd9Sstevel@tonic-gate 	128,				/* max ssf */
51707c478bd9Sstevel@tonic-gate #elif WITH_DES
51717c478bd9Sstevel@tonic-gate 	112,
51727c478bd9Sstevel@tonic-gate #else
51737c478bd9Sstevel@tonic-gate 	0,
51747c478bd9Sstevel@tonic-gate #endif
51757c478bd9Sstevel@tonic-gate 	SASL_SEC_NOPLAINTEXT
51767c478bd9Sstevel@tonic-gate 	| SASL_SEC_NOANONYMOUS
51777c478bd9Sstevel@tonic-gate 	| SASL_SEC_MUTUAL_AUTH,		/* security_flags */
51787c478bd9Sstevel@tonic-gate 	SASL_FEAT_ALLOWS_PROXY,		/* features */
51797c478bd9Sstevel@tonic-gate 	NULL,				/* required_prompts */
51807c478bd9Sstevel@tonic-gate 	NULL,				/* glob_context */
51817c478bd9Sstevel@tonic-gate 	&digestmd5_client_mech_new,	/* mech_new */
51827c478bd9Sstevel@tonic-gate 	&digestmd5_client_mech_step,	/* mech_step */
51837c478bd9Sstevel@tonic-gate 	&digestmd5_client_mech_dispose,	/* mech_dispose */
51847c478bd9Sstevel@tonic-gate 	&digestmd5_common_mech_free,	/* mech_free */
51857c478bd9Sstevel@tonic-gate 	NULL,				/* idle */
51867c478bd9Sstevel@tonic-gate 	NULL,				/* spare1 */
51877c478bd9Sstevel@tonic-gate 	NULL				/* spare2 */
51887c478bd9Sstevel@tonic-gate     }
51897c478bd9Sstevel@tonic-gate };
51907c478bd9Sstevel@tonic-gate 
51917c478bd9Sstevel@tonic-gate int digestmd5_client_plug_init(sasl_utils_t *utils,
51927c478bd9Sstevel@tonic-gate 			       int maxversion,
51937c478bd9Sstevel@tonic-gate 			       int *out_version,
51947c478bd9Sstevel@tonic-gate 			       sasl_client_plug_t **pluglist,
51957c478bd9Sstevel@tonic-gate 			       int *plugcount)
51967c478bd9Sstevel@tonic-gate {
51977c478bd9Sstevel@tonic-gate     reauth_cache_t *reauth_cache;
51987c478bd9Sstevel@tonic-gate #if defined _SUN_SDK_  && defined USE_UEF
51997c478bd9Sstevel@tonic-gate     int ret;
52007c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ && USE_UEF */
52017c478bd9Sstevel@tonic-gate 
52027c478bd9Sstevel@tonic-gate     if (maxversion < SASL_CLIENT_PLUG_VERSION)
52037c478bd9Sstevel@tonic-gate 	return SASL_BADVERS;
52047c478bd9Sstevel@tonic-gate 
52057c478bd9Sstevel@tonic-gate #if defined _SUN_SDK_  && defined USE_UEF
52067c478bd9Sstevel@tonic-gate     if ((ret = uef_init(utils)) != SASL_OK)
52077c478bd9Sstevel@tonic-gate 	return ret;
52087c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ && USE_UEF */
52097c478bd9Sstevel@tonic-gate 
52107c478bd9Sstevel@tonic-gate     /* reauth cache */
52117c478bd9Sstevel@tonic-gate     reauth_cache = utils->malloc(sizeof(reauth_cache_t));
52127c478bd9Sstevel@tonic-gate     if (reauth_cache == NULL)
52137c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
52147c478bd9Sstevel@tonic-gate     memset(reauth_cache, 0, sizeof(reauth_cache_t));
52157c478bd9Sstevel@tonic-gate     reauth_cache->i_am = CLIENT;
52167c478bd9Sstevel@tonic-gate 
52177c478bd9Sstevel@tonic-gate     /* mutex */
52187c478bd9Sstevel@tonic-gate     reauth_cache->mutex = utils->mutex_alloc();
52197c478bd9Sstevel@tonic-gate     if (!reauth_cache->mutex)
52207c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
52217c478bd9Sstevel@tonic-gate 
52227c478bd9Sstevel@tonic-gate     /* entries */
52237c478bd9Sstevel@tonic-gate     reauth_cache->size = 10;
52247c478bd9Sstevel@tonic-gate     reauth_cache->e = utils->malloc(reauth_cache->size *
52257c478bd9Sstevel@tonic-gate 				    sizeof(reauth_entry_t));
52267c478bd9Sstevel@tonic-gate     if (reauth_cache->e == NULL)
52277c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
52287c478bd9Sstevel@tonic-gate     memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t));
52297c478bd9Sstevel@tonic-gate 
52307c478bd9Sstevel@tonic-gate     digestmd5_client_plugins[0].glob_context = reauth_cache;
52317c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
52327c478bd9Sstevel@tonic-gate #ifdef USE_UEF_CLIENT
52337c478bd9Sstevel@tonic-gate     digestmd5_client_plugins[0].max_ssf = uef_max_ssf;
52347c478bd9Sstevel@tonic-gate #endif /* USE_UEF_CLIENT */
52357c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
52367c478bd9Sstevel@tonic-gate 
52377c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
52387c478bd9Sstevel@tonic-gate     /*
52397c478bd9Sstevel@tonic-gate      * Let libsasl know that we are a "Sun" plugin so that privacy
52407c478bd9Sstevel@tonic-gate      * and integrity will be allowed.
52417c478bd9Sstevel@tonic-gate      */
52427c478bd9Sstevel@tonic-gate     REG_PLUG("DIGEST-MD5", digestmd5_client_plugins);
52437c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
52447c478bd9Sstevel@tonic-gate 
52457c478bd9Sstevel@tonic-gate     *out_version = SASL_CLIENT_PLUG_VERSION;
52467c478bd9Sstevel@tonic-gate     *pluglist = digestmd5_client_plugins;
52477c478bd9Sstevel@tonic-gate     *plugcount = 1;
52487c478bd9Sstevel@tonic-gate 
52497c478bd9Sstevel@tonic-gate     return SASL_OK;
52507c478bd9Sstevel@tonic-gate }
52517c478bd9Sstevel@tonic-gate 
52527c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
52537c478bd9Sstevel@tonic-gate #ifdef USE_UEF
52547c478bd9Sstevel@tonic-gate /* If we fail here - we should just not offer privacy or integrity */
52557c478bd9Sstevel@tonic-gate static int
52567c478bd9Sstevel@tonic-gate getSlotID(const sasl_utils_t *utils, CK_MECHANISM_TYPE mech_type,
52577c478bd9Sstevel@tonic-gate 	  CK_SLOT_ID *slot_id)
52587c478bd9Sstevel@tonic-gate {
52597c478bd9Sstevel@tonic-gate     CK_RV rv;
52607c478bd9Sstevel@tonic-gate     CK_ULONG ulSlotCount;
52617c478bd9Sstevel@tonic-gate     CK_ULONG ulMechTypeCount;
52627c478bd9Sstevel@tonic-gate     CK_SLOT_ID *pSlotList = NULL;
52637c478bd9Sstevel@tonic-gate     CK_SLOT_ID slotID;
52647c478bd9Sstevel@tonic-gate     CK_MECHANISM_TYPE_PTR pMechTypeList = NULL;
52657c478bd9Sstevel@tonic-gate     int i, m;
52667c478bd9Sstevel@tonic-gate 
52677c478bd9Sstevel@tonic-gate     rv = C_GetSlotList(CK_FALSE, NULL_PTR, &ulSlotCount);
52687c478bd9Sstevel@tonic-gate     if (rv != CKR_OK || ulSlotCount == 0) {
52697c478bd9Sstevel@tonic-gate #ifdef DEBUG
52707c478bd9Sstevel@tonic-gate 	utils->log(utils->conn, SASL_LOG_DEBUG,
52717c478bd9Sstevel@tonic-gate 		   "C_GetSlotList: 0x%.8X count:%d\n", rv, ulSlotCount);
52727c478bd9Sstevel@tonic-gate #endif
52737c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
52747c478bd9Sstevel@tonic-gate     }
52757c478bd9Sstevel@tonic-gate 
52767c478bd9Sstevel@tonic-gate     pSlotList = utils->calloc(sizeof (CK_SLOT_ID), ulSlotCount);
52777c478bd9Sstevel@tonic-gate     if (pSlotList == NULL)
52787c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
52797c478bd9Sstevel@tonic-gate 
52807c478bd9Sstevel@tonic-gate     rv = C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount);
52817c478bd9Sstevel@tonic-gate     if (rv != CKR_OK) {
52827c478bd9Sstevel@tonic-gate #ifdef DEBUG
52837c478bd9Sstevel@tonic-gate 	utils->log(utils->conn, SASL_LOG_DEBUG,
52847c478bd9Sstevel@tonic-gate 		   "C_GetSlotList: 0x%.8X count:%d\n", rv, ulSlotCount);
52857c478bd9Sstevel@tonic-gate #endif
52867c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
52877c478bd9Sstevel@tonic-gate     }
52887c478bd9Sstevel@tonic-gate 
52897c478bd9Sstevel@tonic-gate     for (i = 0; i < ulSlotCount; i++) {
52907c478bd9Sstevel@tonic-gate 	slotID = pSlotList[i];
52917c478bd9Sstevel@tonic-gate 	rv = C_GetMechanismList(slotID, NULL_PTR, &ulMechTypeCount);
52927c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
52937c478bd9Sstevel@tonic-gate #ifdef DEBUG
52947c478bd9Sstevel@tonic-gate 	    utils->log(utils->conn, SASL_LOG_DEBUG,
52957c478bd9Sstevel@tonic-gate 		      "C_GetMechanismList returned 0x%.8X count:%d\n", rv,
52967c478bd9Sstevel@tonic-gate 		       ulMechTypeCount);
52977c478bd9Sstevel@tonic-gate #endif
52987c478bd9Sstevel@tonic-gate 	    utils->free(pSlotList);
52997c478bd9Sstevel@tonic-gate 	    return SASL_FAIL;
53007c478bd9Sstevel@tonic-gate 	}
53017c478bd9Sstevel@tonic-gate 	pMechTypeList =
53027c478bd9Sstevel@tonic-gate 		utils->calloc(sizeof (CK_MECHANISM_TYPE), ulMechTypeCount);
53037c478bd9Sstevel@tonic-gate 	if (pMechTypeList == NULL_PTR) {
53047c478bd9Sstevel@tonic-gate 	    utils->free(pSlotList);
53057c478bd9Sstevel@tonic-gate 	    return SASL_NOMEM;
53067c478bd9Sstevel@tonic-gate 	}
53077c478bd9Sstevel@tonic-gate 	rv = C_GetMechanismList(slotID, pMechTypeList, &ulMechTypeCount);
53087c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
53097c478bd9Sstevel@tonic-gate #ifdef DEBUG
53107c478bd9Sstevel@tonic-gate 	    utils->log(utils->conn, SASL_LOG_DEBUG,
53117c478bd9Sstevel@tonic-gate 		       "C_GetMechanismList returned 0x%.8X count:%d\n", rv,
53127c478bd9Sstevel@tonic-gate 		       ulMechTypeCount);
53137c478bd9Sstevel@tonic-gate #endif
53147c478bd9Sstevel@tonic-gate 	    utils->free(pMechTypeList);
53157c478bd9Sstevel@tonic-gate 	    utils->free(pSlotList);
53167c478bd9Sstevel@tonic-gate 	    return SASL_FAIL;
53177c478bd9Sstevel@tonic-gate 	}
53187c478bd9Sstevel@tonic-gate 
53197c478bd9Sstevel@tonic-gate 	for (m = 0; m < ulMechTypeCount; m++) {
53207c478bd9Sstevel@tonic-gate 	    if (pMechTypeList[m] == mech_type)
53217c478bd9Sstevel@tonic-gate 		break;
53227c478bd9Sstevel@tonic-gate 	}
53237c478bd9Sstevel@tonic-gate 	utils->free(pMechTypeList);
53247c478bd9Sstevel@tonic-gate 	pMechTypeList = NULL;
53257c478bd9Sstevel@tonic-gate 	if (m < ulMechTypeCount)
53267c478bd9Sstevel@tonic-gate 	    break;
53277c478bd9Sstevel@tonic-gate     }
53287c478bd9Sstevel@tonic-gate     utils->free(pSlotList);
53297c478bd9Sstevel@tonic-gate     if (i < ulSlotCount) {
53307c478bd9Sstevel@tonic-gate 	*slot_id = slotID;
53317c478bd9Sstevel@tonic-gate 	return SASL_OK;
53327c478bd9Sstevel@tonic-gate     }
53337c478bd9Sstevel@tonic-gate     return SASL_FAIL;
53347c478bd9Sstevel@tonic-gate }
53357c478bd9Sstevel@tonic-gate 
53367c478bd9Sstevel@tonic-gate static int
53377c478bd9Sstevel@tonic-gate uef_init(const sasl_utils_t *utils)
53387c478bd9Sstevel@tonic-gate {
53397c478bd9Sstevel@tonic-gate     int got_rc4;
53407c478bd9Sstevel@tonic-gate     int got_des;
53417c478bd9Sstevel@tonic-gate     int got_3des;
53427c478bd9Sstevel@tonic-gate     int next_c;
53437c478bd9Sstevel@tonic-gate     CK_RV rv;
53447c478bd9Sstevel@tonic-gate 
53457c478bd9Sstevel@tonic-gate     if (got_uef_slot)
53467c478bd9Sstevel@tonic-gate 	return (SASL_OK);
53477c478bd9Sstevel@tonic-gate 
53487c478bd9Sstevel@tonic-gate     if (LOCK_MUTEX(&uef_init_mutex) < 0)
53497c478bd9Sstevel@tonic-gate 	return (SASL_FAIL);
53507c478bd9Sstevel@tonic-gate 
53517c478bd9Sstevel@tonic-gate     rv = C_Initialize(NULL_PTR);
53527c478bd9Sstevel@tonic-gate     if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
53537c478bd9Sstevel@tonic-gate #ifdef DEBUG
53547c478bd9Sstevel@tonic-gate 	utils->log(utils->conn, SASL_LOG_DEBUG,
53557c478bd9Sstevel@tonic-gate 		   "C_Initialize returned 0x%.8X\n", rv);
53567c478bd9Sstevel@tonic-gate #endif
53577c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
53587c478bd9Sstevel@tonic-gate     }
53597c478bd9Sstevel@tonic-gate 
53607c478bd9Sstevel@tonic-gate     got_rc4 = getSlotID(utils, CKM_RC4, &rc4_slot_id) == SASL_OK;
53617c478bd9Sstevel@tonic-gate     if (!got_rc4)
53627c478bd9Sstevel@tonic-gate 	utils->log(utils->conn, SASL_LOG_WARN, "Could not get rc4");
53637c478bd9Sstevel@tonic-gate 
53647c478bd9Sstevel@tonic-gate     got_des = getSlotID(utils, CKM_DES_CBC, &des_slot_id) == SASL_OK;
53657c478bd9Sstevel@tonic-gate     if (!got_des)
53667c478bd9Sstevel@tonic-gate 	utils->log(utils->conn, SASL_LOG_WARN, "Could not get des");
53677c478bd9Sstevel@tonic-gate 
53687c478bd9Sstevel@tonic-gate     got_3des = getSlotID(utils, CKM_DES3_CBC, &des3_slot_id) == SASL_OK;
53697c478bd9Sstevel@tonic-gate     if (!got_3des)
53707c478bd9Sstevel@tonic-gate 	utils->log(utils->conn, SASL_LOG_WARN, "Could not get 3des");
53717c478bd9Sstevel@tonic-gate 
53727c478bd9Sstevel@tonic-gate     uef_max_ssf = got_rc4 ? 128 : got_3des ? 112 : got_des ? 55 : 0;
53737c478bd9Sstevel@tonic-gate 
53747c478bd9Sstevel@tonic-gate     /* adjust the available ciphers */
53757c478bd9Sstevel@tonic-gate     next_c = (got_rc4) ? 3 : 0;
53767c478bd9Sstevel@tonic-gate 
53777c478bd9Sstevel@tonic-gate     if (got_des) {
53787c478bd9Sstevel@tonic-gate         uef_ciphers[next_c].name = uef_ciphers[DES_CIPHER_INDEX].name;
53797c478bd9Sstevel@tonic-gate         uef_ciphers[next_c].ssf = uef_ciphers[DES_CIPHER_INDEX].ssf;
53807c478bd9Sstevel@tonic-gate         uef_ciphers[next_c].n = uef_ciphers[DES_CIPHER_INDEX].n;
53817c478bd9Sstevel@tonic-gate         uef_ciphers[next_c].flag = uef_ciphers[DES_CIPHER_INDEX].flag;
53827c478bd9Sstevel@tonic-gate         uef_ciphers[next_c].cipher_enc =
53837c478bd9Sstevel@tonic-gate 		uef_ciphers[DES_CIPHER_INDEX].cipher_enc;
53847c478bd9Sstevel@tonic-gate         uef_ciphers[next_c].cipher_dec =
53857c478bd9Sstevel@tonic-gate 		uef_ciphers[DES_CIPHER_INDEX].cipher_dec;
53867c478bd9Sstevel@tonic-gate         uef_ciphers[next_c].cipher_init =
53877c478bd9Sstevel@tonic-gate 		uef_ciphers[DES_CIPHER_INDEX].cipher_init;
53887c478bd9Sstevel@tonic-gate 	next_c++;
53897c478bd9Sstevel@tonic-gate     }
53907c478bd9Sstevel@tonic-gate 
53917c478bd9Sstevel@tonic-gate     if (got_3des) {
53927c478bd9Sstevel@tonic-gate         uef_ciphers[next_c].name = uef_ciphers[DES3_CIPHER_INDEX].name;
53937c478bd9Sstevel@tonic-gate         uef_ciphers[next_c].ssf = uef_ciphers[DES3_CIPHER_INDEX].ssf;
53947c478bd9Sstevel@tonic-gate         uef_ciphers[next_c].n = uef_ciphers[DES3_CIPHER_INDEX].n;
53957c478bd9Sstevel@tonic-gate         uef_ciphers[next_c].flag = uef_ciphers[DES3_CIPHER_INDEX].flag;
53967c478bd9Sstevel@tonic-gate         uef_ciphers[next_c].cipher_enc =
53977c478bd9Sstevel@tonic-gate 		uef_ciphers[DES3_CIPHER_INDEX].cipher_enc;
53987c478bd9Sstevel@tonic-gate         uef_ciphers[next_c].cipher_dec =
53997c478bd9Sstevel@tonic-gate 		uef_ciphers[DES3_CIPHER_INDEX].cipher_dec;
54007c478bd9Sstevel@tonic-gate         uef_ciphers[next_c].cipher_init =
54017c478bd9Sstevel@tonic-gate 		uef_ciphers[DES3_CIPHER_INDEX].cipher_init;
54027c478bd9Sstevel@tonic-gate 	next_c++;
54037c478bd9Sstevel@tonic-gate     }
54047c478bd9Sstevel@tonic-gate     uef_ciphers[next_c].name = NULL;
54057c478bd9Sstevel@tonic-gate 
54067c478bd9Sstevel@tonic-gate     got_uef_slot = TRUE;
54077c478bd9Sstevel@tonic-gate     UNLOCK_MUTEX(&uef_init_mutex);
54087c478bd9Sstevel@tonic-gate 
54097c478bd9Sstevel@tonic-gate     return (SASL_OK);
54107c478bd9Sstevel@tonic-gate }
54117c478bd9Sstevel@tonic-gate #endif /* USE_UEF */
54127c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
5413