1 /*
2  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  * Copyright (c) 2016 by Delphix. All rights reserved.
5  */
6 
7 /* DIGEST-MD5 SASL plugin
8  * Rob Siemborski
9  * Tim Martin
10  * Alexey Melnikov
11  * $Id: digestmd5.c,v 1.153 2003/03/30 22:17:06 leg Exp $
12  */
13 /*
14  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  *
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  *
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in
25  *    the documentation and/or other materials provided with the
26  *    distribution.
27  *
28  * 3. The name "Carnegie Mellon University" must not be used to
29  *    endorse or promote products derived from this software without
30  *    prior written permission. For permission or any other legal
31  *    details, please contact
32  *      Office of Technology Transfer
33  *      Carnegie Mellon University
34  *      5000 Forbes Avenue
35  *      Pittsburgh, PA  15213-3890
36  *      (412) 268-4387, fax: (412) 268-7395
37  *      tech-transfer@andrew.cmu.edu
38  *
39  * 4. Redistributions of any form whatsoever must retain the following
40  *    acknowledgment:
41  *    "This product includes software developed by Computing Services
42  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
43  *
44  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
45  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
46  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
47  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
48  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
49  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
50  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
51  */
52 
53 #include <config.h>
54 
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <string.h>
58 #ifndef macintosh
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #endif
62 #include <fcntl.h>
63 #include <ctype.h>
64 
65 /* DES support */
66 #ifdef WITH_DES
67 # ifdef WITH_SSL_DES
68 #  include <openssl/des.h>
69 # else /* system DES library */
70 #  include <des.h>
71 # endif
72 #endif /* WITH_DES */
73 
74 #ifdef WIN32
75 # include <winsock.h>
76 #else /* Unix */
77 # include <netinet/in.h>
78 #endif /* WIN32 */
79 
80 #ifdef _SUN_SDK_
81 #include <unistd.h>
82 #endif /* _SUN_SDK_ */
83 
84 #include <sasl.h>
85 #include <saslplug.h>
86 
87 #include "plugin_common.h"
88 
89 #if defined _SUN_SDK_  && defined USE_UEF
90 #include <security/cryptoki.h>
91 static int uef_init(const sasl_utils_t *utils);
92 #endif /* _SUN_SDK_ && USE_UEF */
93 
94 #ifndef WIN32
95 extern int strcasecmp(const char *s1, const char *s2);
96 #endif /* end WIN32 */
97 
98 #ifdef macintosh
99 #include <sasl_md5_plugin_decl.h>
100 #endif
101 
102 /* external definitions */
103 
104 #ifndef _SUN_SDK_
105 #ifdef sun
106 /* gotta define gethostname ourselves on suns */
107 extern int      gethostname(char *, int);
108 #endif
109 #endif /* !_SUN_SDK_ */
110 
111 #define bool int
112 
113 #ifndef TRUE
114 #define TRUE  (1)
115 #define FALSE (0)
116 #endif
117 
118 #define DEFAULT_BUFSIZE 0xFFFF
119 
120 /*****************************  Common Section  *****************************/
121 
122 #ifndef _SUN_SDK_
123 static const char plugin_id[] = "$Id: digestmd5.c,v 1.153 2003/03/30 22:17:06 leg Exp $";
124 #endif /* !_SUN_SDK_ */
125 
126 /* Definitions */
127 #define NONCE_SIZE (32)		/* arbitrary */
128 
129 /* Layer Flags */
130 #define DIGEST_NOLAYER    (1)
131 #define DIGEST_INTEGRITY  (2)
132 #define DIGEST_PRIVACY    (4)
133 
134 /* defines */
135 #define HASHLEN 16
136 typedef unsigned char HASH[HASHLEN + 1];
137 #define HASHHEXLEN 32
138 typedef unsigned char HASHHEX[HASHHEXLEN + 1];
139 
140 #define MAC_SIZE 10
141 #define MAC_OFFS 2
142 
143 const char *SEALING_CLIENT_SERVER="Digest H(A1) to client-to-server sealing key magic constant";
144 const char *SEALING_SERVER_CLIENT="Digest H(A1) to server-to-client sealing key magic constant";
145 
146 const char *SIGNING_CLIENT_SERVER="Digest session key to client-to-server signing key magic constant";
147 const char *SIGNING_SERVER_CLIENT="Digest session key to server-to-client signing key magic constant";
148 
149 #define HT	(9)
150 #define CR	(13)
151 #define LF	(10)
152 #define SP	(32)
153 #define DEL	(127)
154 
155 struct context;
156 
157 /* function definitions for cipher encode/decode */
158 typedef int cipher_function_t(struct context *,
159 			      const char *,
160 			      unsigned,
161 			      unsigned char[],
162 			      char *,
163 			      unsigned *);
164 
165 #ifdef _SUN_SDK_
166 typedef int cipher_init_t(struct context *, char [16],
167                                             char [16]);
168 #else
169 typedef int cipher_init_t(struct context *, unsigned char [16],
170                                             unsigned char [16]);
171 #endif /* _SUN_SDK_ */
172 
173 typedef void cipher_free_t(struct context *);
174 
175 enum Context_type { SERVER = 0, CLIENT = 1 };
176 
177 typedef struct cipher_context cipher_context_t;
178 
179 /* cached auth info used for fast reauth */
180 typedef struct reauth_entry {
181     char *authid;
182     char *realm;
183     unsigned char *nonce;
184     unsigned int nonce_count;
185     unsigned char *cnonce;
186 
187     union {
188 	struct {
189 	    time_t timestamp;
190 	} s; /* server stuff */
191 
192 	struct {
193 	    char *serverFQDN;
194 	    int protection;
195 	    struct digest_cipher *cipher;
196 	    unsigned int server_maxbuf;
197 	} c; /* client stuff */
198     } u;
199 } reauth_entry_t;
200 
201 typedef struct reauth_cache {
202     /* static stuff */
203     enum Context_type i_am;	/* are we the client or server? */
204     time_t timeout;
205     void *mutex;
206     size_t size;
207 
208     reauth_entry_t *e;		/* fixed-size hash table of entries */
209 } reauth_cache_t;
210 
211 /* context that stores info */
212 typedef struct context {
213     int state;			/* state in the authentication we are in */
214     enum Context_type i_am;	/* are we the client or server? */
215 
216     reauth_cache_t *reauth;
217 
218     char *authid;
219     char *realm;
220     unsigned char *nonce;
221     unsigned int nonce_count;
222     unsigned char *cnonce;
223 
224     char *response_value;
225 
226     unsigned int seqnum;
227     unsigned int rec_seqnum;	/* for checking integrity */
228 
229     HASH Ki_send;
230     HASH Ki_receive;
231 
232     HASH HA1;		/* Kcc or Kcs */
233 
234     /* copy of utils from the params structures */
235     const sasl_utils_t *utils;
236 
237     /* For general use */
238     char *out_buf;
239     unsigned out_buf_len;
240 
241     /* for encoding/decoding */
242     buffer_info_t *enc_in_buf;
243     char *encode_buf, *decode_buf, *decode_once_buf;
244     unsigned encode_buf_len, decode_buf_len, decode_once_buf_len;
245     char *decode_tmp_buf;
246     unsigned decode_tmp_buf_len;
247     char *MAC_buf;
248     unsigned MAC_buf_len;
249 
250     char *buffer;
251     char sizebuf[4];
252     int cursize;
253 
254     /* Layer info */
255     unsigned int size; /* Absolute size of buffer */
256     unsigned int needsize; /* How much of the size of the buffer is left */
257 
258     /* Server MaxBuf for Client or Client MaxBuf For Server */
259     /* INCOMING */
260     unsigned int in_maxbuf;
261 
262     /* if privacy mode is used use these functions for encode and decode */
263     cipher_function_t *cipher_enc;
264     cipher_function_t *cipher_dec;
265     cipher_init_t *cipher_init;
266     cipher_free_t *cipher_free;
267     struct cipher_context *cipher_enc_context;
268     struct cipher_context *cipher_dec_context;
269 } context_t;
270 
271 struct digest_cipher {
272     char *name;
273     sasl_ssf_t ssf;
274     int n; /* bits to make privacy key */
275     int flag; /* a bitmask to make things easier for us */
276 
277     cipher_function_t *cipher_enc;
278     cipher_function_t *cipher_dec;
279     cipher_init_t *cipher_init;
280     cipher_free_t *cipher_free;
281 };
282 
283 #ifdef _SUN_SDK_
284 static const unsigned char *COLON = (unsigned char *)":";
285 #else
286 static const unsigned char *COLON = ":";
287 #endif /* _SUN_SDK_ */
288 
289 /* Hashes a string to produce an unsigned short */
hash(const char * str)290 static unsigned hash(const char *str)
291 {
292     unsigned val = 0;
293     int i;
294 
295     while (str && *str) {
296 	i = (int) *str;
297 	val ^= i;
298 	val <<= 1;
299 	str++;
300     }
301 
302     return val;
303 }
304 
CvtHex(HASH Bin,HASHHEX Hex)305 static void CvtHex(HASH Bin, HASHHEX Hex)
306 {
307     unsigned short  i;
308     unsigned char   j;
309 
310     for (i = 0; i < HASHLEN; i++) {
311 	j = (Bin[i] >> 4) & 0xf;
312 	if (j <= 9)
313 	    Hex[i * 2] = (j + '0');
314 	else
315 	    Hex[i * 2] = (j + 'a' - 10);
316 	j = Bin[i] & 0xf;
317 	if (j <= 9)
318 	    Hex[i * 2 + 1] = (j + '0');
319 	else
320 	    Hex[i * 2 + 1] = (j + 'a' - 10);
321     }
322     Hex[HASHHEXLEN] = '\0';
323 }
324 
325 /*
326  * calculate request-digest/response-digest as per HTTP Digest spec
327  */
328 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)329 DigestCalcResponse(const sasl_utils_t * utils,
330 		   HASHHEX HA1,	/* H(A1) */
331 		   unsigned char *pszNonce,	/* nonce from server */
332 		   unsigned int pszNonceCount,	/* 8 hex digits */
333 		   unsigned char *pszCNonce,	/* client nonce */
334 		   unsigned char *pszQop,	/* qop-value: "", "auth",
335 						 * "auth-int" */
336 		   unsigned char *pszDigestUri,	/* requested URL */
337 		   unsigned char *pszMethod,
338 		   HASHHEX HEntity,	/* H(entity body) if qop="auth-int" */
339 		   HASHHEX Response	/* request-digest or response-digest */
340     )
341 {
342     MD5_CTX         Md5Ctx;
343     HASH            HA2;
344     HASH            RespHash;
345     HASHHEX         HA2Hex;
346     char ncvalue[10];
347 
348     /* calculate H(A2) */
349     utils->MD5Init(&Md5Ctx);
350 
351     if (pszMethod != NULL) {
352 	utils->MD5Update(&Md5Ctx, pszMethod, strlen((char *) pszMethod));
353     }
354     utils->MD5Update(&Md5Ctx, (unsigned char *) COLON, 1);
355 
356     /* utils->MD5Update(&Md5Ctx, (unsigned char *) "AUTHENTICATE:", 13); */
357     utils->MD5Update(&Md5Ctx, pszDigestUri, strlen((char *) pszDigestUri));
358     if (strcasecmp((char *) pszQop, "auth") != 0) {
359 	/* append ":00000000000000000000000000000000" */
360 	utils->MD5Update(&Md5Ctx, COLON, 1);
361 	utils->MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);
362     }
363     utils->MD5Final(HA2, &Md5Ctx);
364     CvtHex(HA2, HA2Hex);
365 
366     /* calculate response */
367     utils->MD5Init(&Md5Ctx);
368     utils->MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
369     utils->MD5Update(&Md5Ctx, COLON, 1);
370     utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
371     utils->MD5Update(&Md5Ctx, COLON, 1);
372     if (*pszQop) {
373 	sprintf(ncvalue, "%08x", pszNonceCount);
374 #ifdef _SUN_SDK_
375 	utils->MD5Update(&Md5Ctx, (unsigned char *)ncvalue, strlen(ncvalue));
376 #else
377 	utils->MD5Update(&Md5Ctx, ncvalue, strlen(ncvalue));
378 #endif /* _SUN_SDK_ */
379 	utils->MD5Update(&Md5Ctx, COLON, 1);
380 	utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
381 	utils->MD5Update(&Md5Ctx, COLON, 1);
382 	utils->MD5Update(&Md5Ctx, pszQop, strlen((char *) pszQop));
383 	utils->MD5Update(&Md5Ctx, COLON, 1);
384     }
385     utils->MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
386     utils->MD5Final(RespHash, &Md5Ctx);
387     CvtHex(RespHash, Response);
388 }
389 
UTF8_In_8859_1(const unsigned char * base,int len)390 static bool UTF8_In_8859_1(const unsigned char *base, int len)
391 {
392     const unsigned char *scan, *end;
393 
394     end = base + len;
395     for (scan = base; scan < end; ++scan) {
396 	if (*scan > 0xC3)
397 	    break;			/* abort if outside 8859-1 */
398 	if (*scan >= 0xC0 && *scan <= 0xC3) {
399 	    if (++scan == end || *scan < 0x80 || *scan > 0xBF)
400 		break;
401 	}
402     }
403 
404     /* if scan >= end, then this is a 8859-1 string. */
405     return (scan >= end);
406 }
407 
408 /*
409  * if the string is entirely in the 8859-1 subset of UTF-8, then translate to
410  * 8859-1 prior to MD5
411  */
MD5_UTF8_8859_1(const sasl_utils_t * utils,MD5_CTX * ctx,bool In_ISO_8859_1,const unsigned char * base,int len)412 void MD5_UTF8_8859_1(const sasl_utils_t * utils,
413 		     MD5_CTX * ctx,
414 		     bool In_ISO_8859_1,
415 		     const unsigned char *base,
416 		     int len)
417 {
418     const unsigned char *scan, *end;
419     unsigned char   cbuf;
420 
421     end = base + len;
422 
423     /* if we found a character outside 8859-1, don't alter string */
424     if (!In_ISO_8859_1) {
425 	utils->MD5Update(ctx, base, len);
426 	return;
427     }
428     /* convert to 8859-1 prior to applying hash */
429     do {
430 	for (scan = base; scan < end && *scan < 0xC0; ++scan);
431 	if (scan != base)
432 	    utils->MD5Update(ctx, base, scan - base);
433 	if (scan + 1 >= end)
434 	    break;
435 	cbuf = ((scan[0] & 0x3) << 6) | (scan[1] & 0x3f);
436 	utils->MD5Update(ctx, &cbuf, 1);
437 	base = scan + 2;
438     }
439     while (base < end);
440 }
441 
DigestCalcSecret(const sasl_utils_t * utils,unsigned char * pszUserName,unsigned char * pszRealm,unsigned char * Password,int PasswordLen,HASH HA1)442 static void DigestCalcSecret(const sasl_utils_t * utils,
443 			     unsigned char *pszUserName,
444 			     unsigned char *pszRealm,
445 			     unsigned char *Password,
446 			     int PasswordLen,
447 			     HASH HA1)
448 {
449     bool            In_8859_1;
450 
451     MD5_CTX         Md5Ctx;
452 
453     /* Chris Newman clarified that the following text in DIGEST-MD5 spec
454        is bogus: "if name and password are both in ISO 8859-1 charset"
455        We shoud use code example instead */
456 
457     utils->MD5Init(&Md5Ctx);
458 
459     /* We have to convert UTF-8 to ISO-8859-1 if possible */
460     In_8859_1 = UTF8_In_8859_1(pszUserName, strlen((char *) pszUserName));
461     MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
462 		    pszUserName, strlen((char *) pszUserName));
463 
464     utils->MD5Update(&Md5Ctx, COLON, 1);
465 
466     if (pszRealm != NULL && pszRealm[0] != '\0') {
467 	/* a NULL realm is equivalent to the empty string */
468 	utils->MD5Update(&Md5Ctx, pszRealm, strlen((char *) pszRealm));
469     }
470 
471     utils->MD5Update(&Md5Ctx, COLON, 1);
472 
473     /* We have to convert UTF-8 to ISO-8859-1 if possible */
474     In_8859_1 = UTF8_In_8859_1(Password, PasswordLen);
475     MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
476 		    Password, PasswordLen);
477 
478     utils->MD5Final(HA1, &Md5Ctx);
479 }
480 
create_nonce(const sasl_utils_t * utils)481 static unsigned char *create_nonce(const sasl_utils_t * utils)
482 {
483     unsigned char  *base64buf;
484     int             base64len;
485 
486     char           *ret = (char *) utils->malloc(NONCE_SIZE);
487     if (ret == NULL)
488 	return NULL;
489 
490 #if defined _DEV_URANDOM && defined _SUN_SDK_
491     {
492 	int fd = open(_DEV_URANDOM, O_RDONLY);
493 	int nread = 0;
494 
495 	if (fd != -1) {
496 		nread = read(fd, ret, NONCE_SIZE);
497 		close(fd);
498 	}
499 	if (nread != NONCE_SIZE)
500 	    utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
501     }
502 #else
503     utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
504 #endif /* _DEV_URANDOM && _SUN_SDK_ */
505 
506     /* base 64 encode it so it has valid chars */
507     base64len = (NONCE_SIZE * 4 / 3) + (NONCE_SIZE % 3 ? 4 : 0);
508 
509     base64buf = (unsigned char *) utils->malloc(base64len + 1);
510     if (base64buf == NULL) {
511 #ifdef _SUN_SDK_
512 	utils->log(utils->conn, SASL_LOG_ERR,
513 		   "Unable to allocate final buffer");
514 #else
515 	utils->seterror(utils->conn, 0, "Unable to allocate final buffer");
516 #endif /* _SUN_SDK_ */
517 	return NULL;
518     }
519 
520     /*
521      * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
522      */
523     if (utils->encode64(ret, NONCE_SIZE,
524 			(char *) base64buf, base64len, NULL) != SASL_OK) {
525 	utils->free(ret);
526 	return NULL;
527     }
528     utils->free(ret);
529 
530     return base64buf;
531 }
532 
add_to_challenge(const sasl_utils_t * utils,char ** str,unsigned * buflen,unsigned * curlen,char * name,unsigned char * value,bool need_quotes)533 static int add_to_challenge(const sasl_utils_t *utils,
534 			    char **str, unsigned *buflen, unsigned *curlen,
535 			    char *name,
536 			    unsigned char *value,
537 			    bool need_quotes)
538 {
539     int             namesize = strlen(name);
540     int             valuesize = strlen((char *) value);
541     int             ret;
542 
543     ret = _plug_buf_alloc(utils, str, buflen,
544 			  *curlen + 1 + namesize + 2 + valuesize + 2);
545     if(ret != SASL_OK) return ret;
546 
547     *curlen = *curlen + 1 + namesize + 2 + valuesize + 2;
548 
549     strcat(*str, ",");
550     strcat(*str, name);
551 
552     if (need_quotes) {
553 	strcat(*str, "=\"");
554 	strcat(*str, (char *) value);	/* XXX. What about quoting??? */
555 	strcat(*str, "\"");
556     } else {
557 	strcat(*str, "=");
558 	strcat(*str, (char *) value);
559     }
560 
561     return SASL_OK;
562 }
563 
skip_lws(char * s)564 static char *skip_lws (char *s)
565 {
566     if(!s) return NULL;
567 
568     /* skipping spaces: */
569     while (s[0] == ' ' || s[0] == HT || s[0] == CR || s[0] == LF) {
570 	if (s[0]=='\0') break;
571 	s++;
572     }
573 
574     return s;
575 }
576 
577 #ifdef __SUN_SDK_
skip_token(char * s,int caseinsensitive)578 static char *skip_token (char *s, int caseinsensitive  __attribute__((unused)))
579 #else
580 static char *skip_token (char *s, int caseinsensitive)
581 #endif /* _SUN_SDK_ */
582 {
583     if(!s) return NULL;
584 
585 #ifdef __SUN_SDK_
586     while (((unsigned char *)s)[0]>SP) {
587 #else
588     while (s[0]>SP) {
589 #endif /* _SUN_SDK_ */
590 	if (s[0]==DEL || s[0]=='(' || s[0]==')' || s[0]=='<' || s[0]=='>' ||
591 	    s[0]=='@' || s[0]==',' || s[0]==';' || s[0]==':' || s[0]=='\\' ||
592 	    s[0]=='\'' || s[0]=='/' || s[0]=='[' || s[0]==']' || s[0]== '?' ||
593 	    s[0]=='=' || s[0]== '{' || s[0]== '}') {
594 #ifdef __SUN_SDK_
595 	    /* the above chars are never uppercase */
596 	    break;
597 #else
598 	    if (caseinsensitive == 1) {
599 		if (!isupper((unsigned char) s[0]))
600 		    break;
601 	    } else {
602 		break;
603 	    }
604 #endif /* _SUN_SDK_ */
605 	}
606 	s++;
607     }
608     return s;
609 }
610 
611 /* NULL - error (unbalanced quotes),
612    otherwise pointer to the first character after value */
613 static char *unquote (char *qstr)
614 {
615     char *endvalue;
616     int   escaped = 0;
617     char *outptr;
618 
619     if(!qstr) return NULL;
620 
621     if (qstr[0] == '"') {
622 	qstr++;
623 	outptr = qstr;
624 
625 	for (endvalue = qstr; endvalue[0] != '\0'; endvalue++, outptr++) {
626 	    if (escaped) {
627 		outptr[0] = endvalue[0];
628 		escaped = 0;
629 	    }
630 	    else if (endvalue[0] == '\\') {
631 		escaped = 1;
632 		outptr--; /* Will be incremented at the end of the loop */
633 	    }
634 	    else if (endvalue[0] == '"') {
635 		break;
636 	    }
637 	    else {
638 		outptr[0] = endvalue[0];
639 	    }
640 	}
641 
642 	if (endvalue[0] != '"') {
643 	    return NULL;
644 	}
645 
646 	while (outptr <= endvalue) {
647 	    outptr[0] = '\0';
648 	    outptr++;
649 	}
650 	endvalue++;
651     }
652     else { /* not qouted value (token) */
653 	endvalue = skip_token(qstr,0);
654     };
655 
656     return endvalue;
657 }
658 
659 static void get_pair(char **in, char **name, char **value)
660 {
661     char  *endpair;
662     /* int    inQuotes; */
663     char  *curp = *in;
664     *name = NULL;
665     *value = NULL;
666 
667     if (curp == NULL) return;
668     if (curp[0] == '\0') return;
669 
670     /* skipping spaces: */
671     curp = skip_lws(curp);
672 
673     *name = curp;
674 
675     curp = skip_token(curp,1);
676 
677     /* strip wierd chars */
678     if (curp[0] != '=' && curp[0] != '\0') {
679 	*curp++ = '\0';
680     };
681 
682     curp = skip_lws(curp);
683 
684     if (curp[0] != '=') { /* No '=' sign */
685 	*name = NULL;
686 	return;
687     }
688 
689     curp[0] = '\0';
690     curp++;
691 
692     curp = skip_lws(curp);
693 
694     *value = (curp[0] == '"') ? curp+1 : curp;
695 
696     endpair = unquote (curp);
697     if (endpair == NULL) { /* Unbalanced quotes */
698 	*name = NULL;
699 	return;
700     }
701     if (endpair[0] != ',') {
702 	if (endpair[0]!='\0') {
703 	    *endpair++ = '\0';
704 	}
705     }
706 
707     endpair = skip_lws(endpair);
708 
709     /* syntax check: MUST be '\0' or ',' */
710     if (endpair[0] == ',') {
711 	endpair[0] = '\0';
712 	endpair++; /* skipping <,> */
713     } else if (endpair[0] != '\0') {
714 	*name = NULL;
715 	return;
716     }
717 
718     *in = endpair;
719 }
720 
721 #ifdef WITH_DES
722 struct des_context_s {
723     des_key_schedule keysched;  /* key schedule for des initialization */
724     des_cblock ivec;            /* initial vector for encoding */
725     des_key_schedule keysched2; /* key schedule for 3des initialization */
726 };
727 
728 typedef struct des_context_s des_context_t;
729 
730 /* slide the first 7 bytes of 'inbuf' into the high seven bits of the
731    first 8 bytes of 'keybuf'. 'keybuf' better be 8 bytes long or longer. */
732 static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
733 {
734     keybuf[0] = inbuf[0];
735     keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
736     keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
737     keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
738     keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
739     keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
740     keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
741     keybuf[7] = (inbuf[6]<<1);
742 }
743 
744 /******************************
745  *
746  * 3DES functions
747  *
748  *****************************/
749 
750 static int dec_3des(context_t *text,
751 		    const char *input,
752 		    unsigned inputlen,
753 		    unsigned char digest[16],
754 		    char *output,
755 		    unsigned *outputlen)
756 {
757     des_context_t *c = (des_context_t *) text->cipher_dec_context;
758     int padding, p;
759 
760     des_ede2_cbc_encrypt((void *) input,
761 			 (void *) output,
762 			 inputlen,
763 			 c->keysched,
764 			 c->keysched2,
765 			 &c->ivec,
766 			 DES_DECRYPT);
767 
768     /* now chop off the padding */
769     padding = output[inputlen - 11];
770     if (padding < 1 || padding > 8) {
771 	/* invalid padding length */
772 	return SASL_FAIL;
773     }
774     /* verify all padding is correct */
775     for (p = 1; p <= padding; p++) {
776 	if (output[inputlen - 10 - p] != padding) {
777 	    return SASL_FAIL;
778 	}
779     }
780 
781     /* chop off the padding */
782     *outputlen = inputlen - padding - 10;
783 
784     /* copy in the HMAC to digest */
785     memcpy(digest, output + inputlen - 10, 10);
786 
787     return SASL_OK;
788 }
789 
790 static int enc_3des(context_t *text,
791 		    const char *input,
792 		    unsigned inputlen,
793 		    unsigned char digest[16],
794 		    char *output,
795 		    unsigned *outputlen)
796 {
797     des_context_t *c = (des_context_t *) text->cipher_enc_context;
798     int len;
799     int paddinglen;
800 
801     /* determine padding length */
802     paddinglen = 8 - ((inputlen + 10) % 8);
803 
804     /* now construct the full stuff to be ciphered */
805     memcpy(output, input, inputlen);                /* text */
806     memset(output+inputlen, paddinglen, paddinglen);/* pad  */
807     memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
808 
809     len=inputlen+paddinglen+10;
810 
811     des_ede2_cbc_encrypt((void *) output,
812 			 (void *) output,
813 			 len,
814 			 c->keysched,
815 			 c->keysched2,
816 			 &c->ivec,
817 			 DES_ENCRYPT);
818 
819     *outputlen=len;
820 
821     return SASL_OK;
822 }
823 
824 static int init_3des(context_t *text,
825 		     unsigned char enckey[16],
826 		     unsigned char deckey[16])
827 {
828     des_context_t *c;
829     unsigned char keybuf[8];
830 
831     /* allocate enc & dec context */
832     c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
833     if (c == NULL) return SASL_NOMEM;
834 
835     /* setup enc context */
836     slidebits(keybuf, enckey);
837     if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
838 	return SASL_FAIL;
839 
840     slidebits(keybuf, enckey + 7);
841     if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
842 	return SASL_FAIL;
843     memcpy(c->ivec, ((char *) enckey) + 8, 8);
844 
845     text->cipher_enc_context = (cipher_context_t *) c;
846 
847     /* setup dec context */
848     c++;
849     slidebits(keybuf, deckey);
850     if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
851 	return SASL_FAIL;
852 
853     slidebits(keybuf, deckey + 7);
854     if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
855 	return SASL_FAIL;
856 
857     memcpy(c->ivec, ((char *) deckey) + 8, 8);
858 
859     text->cipher_dec_context = (cipher_context_t *) c;
860 
861     return SASL_OK;
862 }
863 
864 
865 /******************************
866  *
867  * DES functions
868  *
869  *****************************/
870 
871 static int dec_des(context_t *text,
872 		   const char *input,
873 		   unsigned inputlen,
874 		   unsigned char digest[16],
875 		   char *output,
876 		   unsigned *outputlen)
877 {
878     des_context_t *c = (des_context_t *) text->cipher_dec_context;
879     int p, padding = 0;
880 
881     des_cbc_encrypt((void *) input,
882 		    (void *) output,
883 		    inputlen,
884 		    c->keysched,
885 		    &c->ivec,
886 		    DES_DECRYPT);
887 
888     /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
889        this way) */
890     memcpy(c->ivec, input + (inputlen - 8), 8);
891 
892     /* now chop off the padding */
893     padding = output[inputlen - 11];
894     if (padding < 1 || padding > 8) {
895 	/* invalid padding length */
896 	return SASL_FAIL;
897     }
898     /* verify all padding is correct */
899     for (p = 1; p <= padding; p++) {
900 	if (output[inputlen - 10 - p] != padding) {
901 	    return SASL_FAIL;
902 	}
903     }
904 
905     /* chop off the padding */
906     *outputlen = inputlen - padding - 10;
907 
908     /* copy in the HMAC to digest */
909     memcpy(digest, output + inputlen - 10, 10);
910 
911     return SASL_OK;
912 }
913 
914 static int enc_des(context_t *text,
915 		   const char *input,
916 		   unsigned inputlen,
917 		   unsigned char digest[16],
918 		   char *output,
919 		   unsigned *outputlen)
920 {
921     des_context_t *c = (des_context_t *) text->cipher_enc_context;
922     int len;
923     int paddinglen;
924 
925     /* determine padding length */
926     paddinglen = 8 - ((inputlen+10) % 8);
927 
928     /* now construct the full stuff to be ciphered */
929     memcpy(output, input, inputlen);                /* text */
930     memset(output+inputlen, paddinglen, paddinglen);/* pad  */
931     memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
932 
933     len = inputlen + paddinglen + 10;
934 
935     des_cbc_encrypt((void *) output,
936                     (void *) output,
937                     len,
938                     c->keysched,
939                     &c->ivec,
940                     DES_ENCRYPT);
941 
942     /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
943        this way) */
944     memcpy(c->ivec, output + (len - 8), 8);
945 
946     *outputlen = len;
947 
948     return SASL_OK;
949 }
950 
951 static int init_des(context_t *text,
952 		    unsigned char enckey[16],
953 		    unsigned char deckey[16])
954 {
955     des_context_t *c;
956     unsigned char keybuf[8];
957 
958     /* allocate enc context */
959     c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
960     if (c == NULL) return SASL_NOMEM;
961 
962     /* setup enc context */
963     slidebits(keybuf, enckey);
964     des_key_sched((des_cblock *) keybuf, c->keysched);
965 
966     memcpy(c->ivec, ((char *) enckey) + 8, 8);
967 
968     text->cipher_enc_context = (cipher_context_t *) c;
969 
970     /* setup dec context */
971     c++;
972     slidebits(keybuf, deckey);
973     des_key_sched((des_cblock *) keybuf, c->keysched);
974 
975     memcpy(c->ivec, ((char *) deckey) + 8, 8);
976 
977     text->cipher_dec_context = (cipher_context_t *) c;
978 
979     return SASL_OK;
980 }
981 
982 static void free_des(context_t *text)
983 {
984     /* free des contextss. only cipher_enc_context needs to be free'd,
985        since cipher_dec_context was allocated at the same time. */
986     if (text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
987 }
988 
989 #endif /* WITH_DES */
990 
991 #ifdef WITH_RC4
992 /* quick generic implementation of RC4 */
993 struct rc4_context_s {
994     unsigned char sbox[256];
995     int i, j;
996 };
997 
998 typedef struct rc4_context_s rc4_context_t;
999 
1000 static void rc4_init(rc4_context_t *text,
1001 		     const unsigned char *key,
1002 		     unsigned keylen)
1003 {
1004     int i, j;
1005 
1006     /* fill in linearly s0=0 s1=1... */
1007     for (i=0;i<256;i++)
1008 	text->sbox[i]=i;
1009 
1010     j=0;
1011     for (i = 0; i < 256; i++) {
1012 	unsigned char tmp;
1013 	/* j = (j + Si + Ki) mod 256 */
1014 	j = (j + text->sbox[i] + key[i % keylen]) % 256;
1015 
1016 	/* swap Si and Sj */
1017 	tmp = text->sbox[i];
1018 	text->sbox[i] = text->sbox[j];
1019 	text->sbox[j] = tmp;
1020     }
1021 
1022     /* counters initialized to 0 */
1023     text->i = 0;
1024     text->j = 0;
1025 }
1026 
1027 static void rc4_encrypt(rc4_context_t *text,
1028 			const char *input,
1029 			char *output,
1030 			unsigned len)
1031 {
1032     int tmp;
1033     int i = text->i;
1034     int j = text->j;
1035     int t;
1036     int K;
1037     const char *input_end = input + len;
1038 
1039     while (input < input_end) {
1040 	i = (i + 1) % 256;
1041 
1042 	j = (j + text->sbox[i]) % 256;
1043 
1044 	/* swap Si and Sj */
1045 	tmp = text->sbox[i];
1046 	text->sbox[i] = text->sbox[j];
1047 	text->sbox[j] = tmp;
1048 
1049 	t = (text->sbox[i] + text->sbox[j]) % 256;
1050 
1051 	K = text->sbox[t];
1052 
1053 	/* byte K is Xor'ed with plaintext */
1054 	*output++ = *input++ ^ K;
1055     }
1056 
1057     text->i = i;
1058     text->j = j;
1059 }
1060 
1061 static void rc4_decrypt(rc4_context_t *text,
1062 			const char *input,
1063 			char *output,
1064 			unsigned len)
1065 {
1066     int tmp;
1067     int i = text->i;
1068     int j = text->j;
1069     int t;
1070     int K;
1071     const char *input_end = input + len;
1072 
1073     while (input < input_end) {
1074 	i = (i + 1) % 256;
1075 
1076 	j = (j + text->sbox[i]) % 256;
1077 
1078 	/* swap Si and Sj */
1079 	tmp = text->sbox[i];
1080 	text->sbox[i] = text->sbox[j];
1081 	text->sbox[j] = tmp;
1082 
1083 	t = (text->sbox[i] + text->sbox[j]) % 256;
1084 
1085 	K = text->sbox[t];
1086 
1087 	/* byte K is Xor'ed with plaintext */
1088 	*output++ = *input++ ^ K;
1089     }
1090 
1091     text->i = i;
1092     text->j = j;
1093 }
1094 
1095 static void free_rc4(context_t *text)
1096 {
1097     /* free rc4 context structures */
1098 
1099     if(text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
1100     if(text->cipher_dec_context) text->utils->free(text->cipher_dec_context);
1101 #ifdef _SUN_SDK_
1102     text->cipher_enc_context = NULL;
1103     text->cipher_dec_context = NULL;
1104 #endif /* _SUN_SDK_ */
1105 }
1106 
1107 static int init_rc4(context_t *text,
1108 #ifdef _SUN_SDK_
1109 		    char enckey[16],
1110 		    char deckey[16])
1111 #else
1112 		    unsigned char enckey[16],
1113 		    unsigned char deckey[16])
1114 #endif /* _SUN_SDK_ */
1115 {
1116     /* allocate rc4 context structures */
1117     text->cipher_enc_context=
1118 	(cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
1119     if (text->cipher_enc_context == NULL) return SASL_NOMEM;
1120 
1121     text->cipher_dec_context=
1122 	(cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
1123 #ifdef _SUN_SDK_
1124     if (text->cipher_dec_context == NULL) {
1125 	text->utils->free(text->cipher_enc_context);
1126 	text->cipher_enc_context = NULL;
1127 	return SASL_NOMEM;
1128     }
1129 #else
1130     if (text->cipher_dec_context == NULL) return SASL_NOMEM;
1131 #endif /* _SUN_SDK_ */
1132 
1133     /* initialize them */
1134     rc4_init((rc4_context_t *) text->cipher_enc_context,
1135              (const unsigned char *) enckey, 16);
1136     rc4_init((rc4_context_t *) text->cipher_dec_context,
1137              (const unsigned char *) deckey, 16);
1138 
1139     return SASL_OK;
1140 }
1141 
1142 static int dec_rc4(context_t *text,
1143 		   const char *input,
1144 		   unsigned inputlen,
1145 		   unsigned char digest[16],
1146 		   char *output,
1147 		   unsigned *outputlen)
1148 {
1149     /* decrypt the text part */
1150     rc4_decrypt((rc4_context_t *) text->cipher_dec_context,
1151                 input, output, inputlen-10);
1152 
1153     /* decrypt the HMAC part */
1154     rc4_decrypt((rc4_context_t *) text->cipher_dec_context,
1155 		input+(inputlen-10), (char *) digest, 10);
1156 
1157     /* no padding so we just subtract the HMAC to get the text length */
1158     *outputlen = inputlen - 10;
1159 
1160     return SASL_OK;
1161 }
1162 
1163 static int enc_rc4(context_t *text,
1164 		   const char *input,
1165 		   unsigned inputlen,
1166 		   unsigned char digest[16],
1167 		   char *output,
1168 		   unsigned *outputlen)
1169 {
1170     /* pad is zero */
1171     *outputlen = inputlen+10;
1172 
1173     /* encrypt the text part */
1174     rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
1175                 input,
1176                 output,
1177                 inputlen);
1178 
1179     /* encrypt the HMAC part */
1180     rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
1181                 (const char *) digest,
1182 		(output)+inputlen, 10);
1183 
1184     return SASL_OK;
1185 }
1186 
1187 #endif /* WITH_RC4 */
1188 
1189 struct digest_cipher available_ciphers[] =
1190 {
1191 #ifdef WITH_RC4
1192     { "rc4-40", 40, 5, 0x01, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
1193     { "rc4-56", 56, 7, 0x02, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
1194     { "rc4", 128, 16, 0x04, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
1195 #endif
1196 #ifdef WITH_DES
1197     { "des", 55, 16, 0x08, &enc_des, &dec_des, &init_des, &free_des },
1198     { "3des", 112, 16, 0x10, &enc_3des, &dec_3des, &init_3des, &free_des },
1199 #endif
1200     { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
1201 };
1202 
1203 
1204 #ifdef USE_UEF
1205 DEFINE_STATIC_MUTEX(uef_init_mutex);
1206 #define DES_CIPHER_INDEX	3
1207 #define DES3_CIPHER_INDEX	4
1208 
1209 static int got_uef_slot = FALSE;
1210 static sasl_ssf_t uef_max_ssf = 0;
1211 static CK_SLOT_ID rc4_slot_id;
1212 static CK_SLOT_ID des_slot_id;
1213 static CK_SLOT_ID des3_slot_id;
1214 
1215 struct uef_context_s {
1216     CK_SESSION_HANDLE hSession;
1217     CK_OBJECT_HANDLE hKey;
1218 };
1219 
1220 typedef struct uef_context_s uef_context_t;
1221 
1222 /*
1223  * slide the first 7 bytes of 'inbuf' into the high seven bits of the
1224  * first 8 bytes of 'keybuf'. 'inbuf' better be 8 bytes long or longer.
1225  *
1226  * This is used to compute the IV for "des" and "3des" as described in
1227  * draft-ietf-sasl-rfc2831bis-00.txt - The IV for "des"
1228  *  and "3des" is the last 8 bytes of Kcc or Kcs - the encryption keys.
1229  */
1230 
1231 static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
1232 {
1233     keybuf[0] = inbuf[0];
1234     keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
1235     keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
1236     keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
1237     keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
1238     keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
1239     keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
1240     keybuf[7] = (inbuf[6]<<1);
1241 }
1242 
1243 /*
1244  * Create encryption and decryption session handle handles for later use.
1245  * Returns SASL_OK on success - any other return indicates failure.
1246  *
1247  * free_uef is called to release associated resources by
1248  *	digestmd5_common_mech_dispose
1249  */
1250 
1251 static int init_uef(context_t *text,
1252 		    CK_KEY_TYPE keyType,
1253 		    CK_MECHANISM_TYPE mech_type,
1254 		    CK_SLOT_ID slot_id,
1255 		    char enckey[16],
1256 		    char deckey[16])
1257 {
1258     CK_RV		rv;
1259     uef_context_t	*enc_context;
1260     uef_context_t	*dec_context;
1261     CK_OBJECT_CLASS	class = CKO_SECRET_KEY;
1262     CK_BBOOL		true = TRUE;
1263     static CK_MECHANISM	mechanism = {CKM_RC4, NULL, 0};
1264     unsigned char	keybuf[24];
1265     CK_ATTRIBUTE	template[] = {
1266 				{CKA_CLASS, NULL, sizeof (class)},
1267 				{CKA_KEY_TYPE, NULL, sizeof (keyType)},
1268 				{CKA_ENCRYPT, NULL, sizeof (true)},
1269 				{CKA_VALUE, NULL, 16}};
1270 
1271     template[0].pValue = &class;
1272     template[1].pValue = &keyType;
1273     template[2].pValue = &true;
1274     if (keyType == CKK_DES || keyType == CKK_DES3) {
1275 	slidebits(keybuf, (unsigned char *)enckey);
1276 	if (keyType == CKK_DES3) {
1277 	    slidebits(keybuf + 8, (unsigned char *)enckey + 7);
1278 	    (void) memcpy(keybuf + 16, keybuf, 8);
1279 	    template[3].ulValueLen = 24;
1280 	} else {
1281 	    template[3].ulValueLen = 8;
1282 	}
1283 	template[3].pValue = keybuf;
1284 	mechanism.pParameter = enckey + 8;
1285 	mechanism.ulParameterLen = 8;
1286     } else {
1287 	template[3].pValue = enckey;
1288     }
1289     mechanism.mechanism = mech_type;
1290 
1291     /* allocate rc4 context structures */
1292     enc_context = text->utils->malloc(sizeof (uef_context_t));
1293     if (enc_context == NULL)
1294 	return SASL_NOMEM;
1295 
1296     rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
1297 		&enc_context->hSession);
1298     if (rv != CKR_OK) {
1299 	text->utils->free(enc_context);
1300 #ifdef DEBUG
1301 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1302 		"enc C_OpenSession Failed:0x%.8X\n", rv);
1303 #endif
1304 	return SASL_FAIL;
1305     }
1306 
1307     rv = C_CreateObject(enc_context->hSession, template,
1308 		sizeof (template)/sizeof (template[0]), &enc_context->hKey);
1309     if (rv != CKR_OK) {
1310 	text->utils->free(enc_context);
1311 	(void) C_CloseSession(enc_context->hSession);
1312 #ifdef DEBUG
1313 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1314 			 "enc C_CreateObject: rv = 0x%.8X\n", rv);
1315 #endif
1316 	return SASL_FAIL;
1317     }
1318 
1319     text->cipher_enc_context = (cipher_context_t *)enc_context;
1320 
1321     /* Initialize the encryption operation in the session */
1322     rv = C_EncryptInit(enc_context->hSession, &mechanism, enc_context->hKey);
1323     if (rv != CKR_OK) {
1324 #ifdef DEBUG
1325 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1326 			 "C_EncryptInit: rv = 0x%.8X\n", rv);
1327 #endif
1328 	return SASL_FAIL;
1329     }
1330 
1331     dec_context = text->utils->malloc(sizeof(uef_context_t));
1332     if (dec_context == NULL)
1333 	return SASL_NOMEM;
1334 
1335     rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
1336 		&dec_context->hSession);
1337     if (rv != CKR_OK) {
1338 #ifdef DEBUG
1339 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1340 		"dec C_OpenSession Failed:0x%.8X\n", rv);
1341 #endif
1342 	text->utils->free(dec_context);
1343 	return SASL_FAIL;
1344     }
1345 
1346     template[2].type = CKA_DECRYPT;
1347     if (keyType == CKK_DES || keyType == CKK_DES3) {
1348 	slidebits(keybuf, (unsigned char *)deckey);
1349 	if (keyType == CKK_DES3) {
1350 	    slidebits(keybuf + 8, (unsigned char *)deckey + 7);
1351 	    (void) memcpy(keybuf + 16, keybuf, 8);
1352 	}
1353 	mechanism.pParameter = deckey + 8;
1354     } else {
1355 	template[3].pValue = deckey;
1356     }
1357 
1358     rv = C_CreateObject(dec_context->hSession, template,
1359 		sizeof (template)/sizeof (template[0]), &dec_context->hKey);
1360     if (rv != CKR_OK) {
1361 #ifdef DEBUG
1362 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1363 		"dec C_CreateObject: rv = 0x%.8X\n", rv);
1364 #endif
1365 	(void) C_CloseSession(dec_context->hSession);
1366 	text->utils->free(dec_context);
1367 	return SASL_FAIL;
1368     }
1369     text->cipher_dec_context = (cipher_context_t *)dec_context;
1370 
1371     /* Initialize the decryption operation in the session */
1372     rv = C_DecryptInit(dec_context->hSession, &mechanism, dec_context->hKey);
1373     if (rv != CKR_OK) {
1374 #ifdef DEBUG
1375 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1376 			 "C_DecryptInit: rv = 0x%.8X\n", rv);
1377 #endif
1378 	return SASL_FAIL;
1379     }
1380 
1381     return SASL_OK;
1382 }
1383 
1384 static int init_rc4_uef(context_t *text,
1385 		    char enckey[16],
1386 		    char deckey[16])
1387 {
1388     return init_uef(text, CKK_RC4, CKM_RC4, rc4_slot_id, enckey, deckey);
1389 }
1390 
1391 static int init_des_uef(context_t *text,
1392 		    char enckey[16],
1393 		    char deckey[16])
1394 {
1395     return init_uef(text, CKK_DES, CKM_DES_CBC, des_slot_id, enckey, deckey);
1396 }
1397 
1398 static int init_3des_uef(context_t *text,
1399 		    char enckey[16],
1400 		    char deckey[16])
1401 {
1402     return init_uef(text, CKK_DES3, CKM_DES3_CBC, des3_slot_id, enckey, deckey);
1403 }
1404 
1405 static void
1406 free_uef(context_t *text)
1407 {
1408     uef_context_t	*enc_context =
1409 		(uef_context_t *)text->cipher_enc_context;
1410     uef_context_t	*dec_context =
1411 		(uef_context_t *)text->cipher_dec_context;
1412     CK_RV		rv;
1413     unsigned char	buf[1];
1414     CK_ULONG		ulLen = 0;
1415 
1416 
1417     if (enc_context != NULL) {
1418 	rv = C_EncryptFinal(enc_context->hSession, buf, &ulLen);
1419 	if (rv != CKR_OK) {
1420 #ifdef DEBUG
1421 	    text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1422 			     "C_EncryptFinal failed:0x%.8X\n", rv);
1423 #endif
1424 	}
1425 	rv = C_DestroyObject(enc_context->hSession, enc_context->hKey);
1426 	if (rv != CKR_OK) {
1427 #ifdef DEBUG
1428 	    text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1429 			     "C_DestroyObject failed:0x%.8X\n", rv);
1430 #endif
1431 	}
1432 	rv = C_CloseSession(enc_context->hSession);
1433 	if (rv != CKR_OK) {
1434 #ifdef DEBUG
1435 	    text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1436 			     "C_CloseSession failed:0x%.8X\n", rv);
1437 #endif
1438 	}
1439 	text->utils->free(enc_context);
1440     }
1441     if (dec_context != NULL) {
1442 	rv = C_DecryptFinal(dec_context->hSession, buf, &ulLen);
1443 	if (rv != CKR_OK) {
1444 #ifdef DEBUG
1445 	    text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1446 			     "C_DecryptFinal failed:0x%.8X\n", rv);
1447 #endif
1448 	}
1449 	rv = C_DestroyObject(dec_context->hSession, dec_context->hKey);
1450 	if (rv != CKR_OK) {
1451 #ifdef DEBUG
1452 	    text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1453 			     "C_DestroyObject failed:0x%.8X\n", rv);
1454 #endif
1455 	}
1456 
1457 	rv = C_CloseSession(dec_context->hSession);
1458 	if (rv != CKR_OK) {
1459 #ifdef DEBUG
1460 	    text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1461 			     "C_CloseSession failed:0x%.8X\n", rv);
1462 #endif
1463 	}
1464 	text->utils->free(dec_context);
1465     }
1466     text->cipher_enc_context = NULL;
1467     text->cipher_dec_context = NULL;
1468 }
1469 
1470 static int
1471 dec_rc4_uef(context_t *text,
1472 	    const char *input,
1473 	    unsigned inputlen,
1474 	    unsigned char digest[16],
1475 	    char *output,
1476 	    unsigned *outputlen)
1477 {
1478     CK_RV		rv;
1479     uef_context_t	*dec_context =
1480 		(uef_context_t *)text->cipher_dec_context;
1481     CK_ULONG		ulDataLen = *outputlen - MAC_SIZE;
1482     CK_ULONG		ulDigestLen = MAC_SIZE;
1483 
1484     rv = C_DecryptUpdate(dec_context->hSession, (CK_BYTE_PTR)input,
1485 	inputlen - MAC_SIZE, (CK_BYTE_PTR)output, &ulDataLen);
1486     if (rv != CKR_OK) {
1487 #ifdef DEBUG
1488 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1489 			 "C_DecryptUpdate failed:0x%.8X\n", rv);
1490 #endif
1491 	return SASL_FAIL;
1492     }
1493     *outputlen = (unsigned)ulDataLen;
1494 
1495     rv = C_DecryptUpdate(dec_context->hSession,
1496 	(CK_BYTE_PTR)input+(inputlen-MAC_SIZE), MAC_SIZE, (CK_BYTE_PTR)digest,
1497 	&ulDigestLen);
1498     if (rv != CKR_OK || ulDigestLen != MAC_SIZE) {
1499 #ifdef DEBUG
1500 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1501 			 "C_DecryptUpdate:0x%.8X, digestLen:%d\n",
1502 			 rv, ulDigestLen);
1503 #endif
1504 	return SASL_FAIL;
1505     }
1506 
1507     return SASL_OK;
1508 }
1509 
1510 static int
1511 enc_rc4_uef(context_t *text,
1512 	    const char *input,
1513 	    unsigned inputlen,
1514 	    unsigned char digest[16],
1515 	    char *output,
1516 	    unsigned *outputlen)
1517 {
1518     CK_RV		rv;
1519     uef_context_t	*enc_context =
1520 		(uef_context_t *)text->cipher_enc_context;
1521     CK_ULONG		ulDataLen = inputlen;
1522     CK_ULONG		ulDigestLen = MAC_SIZE;
1523 
1524     rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)input, inputlen,
1525 	(CK_BYTE_PTR)output, &ulDataLen);
1526     if (rv != CKR_OK) {
1527 #ifdef DEBUG
1528 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1529 			 "C_EncryptUpdate failed: 0x%.8X "
1530 			  "inputlen:%d outputlen:%d\n",
1531 			  rv, inputlen, ulDataLen);
1532 #endif
1533 	return SASL_FAIL;
1534     }
1535     rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)digest, MAC_SIZE,
1536 	(CK_BYTE_PTR)output + inputlen, &ulDigestLen);
1537     if (rv != CKR_OK) {
1538 #ifdef DEBUG
1539 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1540 			 "C_EncryptUpdate failed: 0x%.8X ulDigestLen:%d\n",
1541 			 rv, ulDigestLen);
1542 #endif
1543 	return SASL_FAIL;
1544     }
1545 
1546     *outputlen = ulDataLen + ulDigestLen;
1547 
1548     return SASL_OK;
1549 }
1550 
1551 static int
1552 dec_des_uef(context_t *text,
1553 	    const char *input,
1554 	    unsigned inputlen,
1555 	    unsigned char digest[16],
1556 	    char *output,
1557 	    unsigned *outputlen)
1558 {
1559     CK_RV		rv;
1560     uef_context_t	*dec_context =
1561 		(uef_context_t *)text->cipher_dec_context;
1562     CK_ULONG		ulDataLen = inputlen;
1563     int			padding, p;
1564 
1565     rv = C_DecryptUpdate(dec_context->hSession, (CK_BYTE_PTR)input,
1566 	inputlen, (CK_BYTE_PTR)output, &ulDataLen);
1567     if (rv != CKR_OK) {
1568 #ifdef DEBUG
1569 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1570 			 "C_DecryptUpdate failed:0x%.8X\n", rv);
1571 #endif
1572 	return SASL_FAIL;
1573     }
1574     if (ulDataLen != inputlen) {
1575 #ifdef DEBUG
1576 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1577 			 "C_DecryptUpdate unexpected data len:%d !=%d\n",
1578 			 inputlen, ulDataLen);
1579 #endif
1580 	return SASL_BUFOVER;
1581     }
1582 
1583     /* now chop off the padding */
1584     padding = output[inputlen - 11];
1585     if (padding < 1 || padding > 8) {
1586 	/* invalid padding length */
1587 	return SASL_BADMAC;
1588     }
1589     /* verify all padding is correct */
1590     for (p = 1; p <= padding; p++) {
1591 	if (output[inputlen - MAC_SIZE - p] != padding) {
1592 	    return SASL_BADMAC;
1593 	}
1594     }
1595 
1596     /* chop off the padding */
1597     *outputlen = inputlen - padding - MAC_SIZE;
1598 
1599     /* copy in the HMAC to digest */
1600     memcpy(digest, output + inputlen - MAC_SIZE, MAC_SIZE);
1601 
1602     return SASL_OK;
1603 }
1604 
1605 static int
1606 enc_des_uef(context_t *text,
1607 	    const char *input,
1608 	    unsigned inputlen,
1609 	    unsigned char digest[16],
1610 	    char *output,
1611 	    unsigned *outputlen)
1612 {
1613     CK_RV		rv;
1614     uef_context_t	*enc_context =
1615 		(uef_context_t *)text->cipher_enc_context;
1616     CK_ULONG		ulDataLen;
1617     int paddinglen;
1618 
1619     /* determine padding length */
1620     paddinglen = 8 - ((inputlen + MAC_SIZE) % 8);
1621 
1622     /* now construct the full stuff to be ciphered */
1623     memcpy(output, input, inputlen);                /* text */
1624     memset(output+inputlen, paddinglen, paddinglen);/* pad  */
1625     memcpy(output+inputlen+paddinglen, digest, MAC_SIZE); /* hmac */
1626 
1627     ulDataLen=inputlen+paddinglen+MAC_SIZE;
1628 
1629     rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)output, ulDataLen,
1630 	(CK_BYTE_PTR)output, &ulDataLen);
1631     if (rv != CKR_OK) {
1632 #ifdef DEBUG
1633 	text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1634 			 "C_EncryptUpdate failed: 0x%.8X "
1635 			 "inputlen:%d outputlen:%d\n",
1636 			 rv, ulDataLen, ulDataLen);
1637 #endif
1638 	return SASL_FAIL;
1639     }
1640     *outputlen = (unsigned)ulDataLen;
1641 
1642     return SASL_OK;
1643 }
1644 
1645 struct digest_cipher uef_ciphers[] =
1646 {
1647     { "rc4-40", 40, 5, 0x01, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
1648 	&free_uef },
1649     { "rc4-56", 56, 7, 0x02, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
1650 	&free_uef },
1651     { "rc4", 128, 16, 0x04, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
1652 	&free_uef },
1653     { "des", 55, 16, 0x08, &enc_des_uef, &dec_des_uef, &init_des_uef,
1654 	&free_uef },
1655     { "3des", 112, 16, 0x10, &enc_des_uef, &dec_des_uef, &init_3des_uef,
1656 	&free_uef },
1657     { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
1658 };
1659 
1660 struct digest_cipher *available_ciphers1 = uef_ciphers;
1661 #endif /* USE_UEF */
1662 
1663 static int create_layer_keys(context_t *text,
1664 			     const sasl_utils_t *utils,
1665 			     HASH key, int keylen,
1666 			     char enckey[16], char deckey[16])
1667 {
1668     MD5_CTX Md5Ctx;
1669 
1670     utils->MD5Init(&Md5Ctx);
1671     utils->MD5Update(&Md5Ctx, key, keylen);
1672     if (text->i_am == SERVER) {
1673 	utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_SERVER_CLIENT,
1674 			 strlen(SEALING_SERVER_CLIENT));
1675     } else {
1676 	utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_CLIENT_SERVER,
1677 			 strlen(SEALING_CLIENT_SERVER));
1678     }
1679     utils->MD5Final((unsigned char *) enckey, &Md5Ctx);
1680 
1681     utils->MD5Init(&Md5Ctx);
1682     utils->MD5Update(&Md5Ctx, key, keylen);
1683     if (text->i_am != SERVER) {
1684 	utils->MD5Update(&Md5Ctx, (const unsigned char *)SEALING_SERVER_CLIENT,
1685 			 strlen(SEALING_SERVER_CLIENT));
1686     } else {
1687 	utils->MD5Update(&Md5Ctx, (const unsigned char *)SEALING_CLIENT_SERVER,
1688 			 strlen(SEALING_CLIENT_SERVER));
1689     }
1690     utils->MD5Final((unsigned char *) deckey, &Md5Ctx);
1691 
1692     /* create integrity keys */
1693     /* sending */
1694     utils->MD5Init(&Md5Ctx);
1695     utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
1696     if (text->i_am == SERVER) {
1697 	utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT,
1698 			 strlen(SIGNING_SERVER_CLIENT));
1699     } else {
1700 	utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
1701 			 strlen(SIGNING_CLIENT_SERVER));
1702     }
1703     utils->MD5Final(text->Ki_send, &Md5Ctx);
1704 
1705     /* receiving */
1706     utils->MD5Init(&Md5Ctx);
1707     utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
1708     if (text->i_am != SERVER) {
1709 	utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT,
1710 			 strlen(SIGNING_SERVER_CLIENT));
1711     } else {
1712 	utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
1713 			 strlen(SIGNING_CLIENT_SERVER));
1714     }
1715     utils->MD5Final(text->Ki_receive, &Md5Ctx);
1716 
1717     return SASL_OK;
1718 }
1719 
1720 static const unsigned short version = 1;
1721 
1722 /* len, CIPHER(Kc, {msg, pag, HMAC(ki, {SeqNum, msg})[0..9]}), x0001, SeqNum */
1723 
1724 static int
1725 digestmd5_privacy_encode(void *context,
1726 			 const struct iovec *invec,
1727 			 unsigned numiov,
1728 			 const char **output,
1729 			 unsigned *outputlen)
1730 {
1731     context_t *text = (context_t *) context;
1732     int tmp;
1733     unsigned int tmpnum;
1734     unsigned short int tmpshort;
1735     int ret;
1736     char *out;
1737     unsigned char digest[16];
1738     struct buffer_info *inblob, bufinfo;
1739 
1740     if(!context || !invec || !numiov || !output || !outputlen) {
1741 	PARAMERROR(text->utils);
1742 	return SASL_BADPARAM;
1743     }
1744 
1745     if (numiov > 1) {
1746 	ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
1747 	if (ret != SASL_OK) return ret;
1748 	inblob = text->enc_in_buf;
1749     } else {
1750 	/* avoid the data copy */
1751 	bufinfo.data = invec[0].iov_base;
1752 	bufinfo.curlen = invec[0].iov_len;
1753 	inblob = &bufinfo;
1754     }
1755 
1756     /* make sure the output buffer is big enough for this blob */
1757     ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
1758 			  &(text->encode_buf_len),
1759 			  (4 +                        /* for length */
1760 			   inblob->curlen + /* for content */
1761 			   10 +                       /* for MAC */
1762 			   8 +                        /* maximum pad */
1763 			   6 +                        /* for padding */
1764 			   1));                       /* trailing null */
1765     if(ret != SASL_OK) return ret;
1766 
1767     /* skip by the length for now */
1768     out = (text->encode_buf)+4;
1769 
1770     /* construct (seqnum, msg) */
1771     /* We can just use the output buffer because it's big enough */
1772     tmpnum = htonl(text->seqnum);
1773     memcpy(text->encode_buf, &tmpnum, 4);
1774     memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
1775 
1776     /* HMAC(ki, (seqnum, msg) ) */
1777     text->utils->hmac_md5((const unsigned char *) text->encode_buf,
1778 			  inblob->curlen + 4,
1779 			  text->Ki_send, HASHLEN, digest);
1780 
1781     /* calculate the encrypted part */
1782     text->cipher_enc(text, inblob->data, inblob->curlen,
1783 		     digest, out, outputlen);
1784     out+=(*outputlen);
1785 
1786     /* copy in version */
1787     tmpshort = htons(version);
1788     memcpy(out, &tmpshort, 2);	/* 2 bytes = version */
1789 
1790     out+=2;
1791     (*outputlen)+=2; /* for version */
1792 
1793     /* put in seqnum */
1794     tmpnum = htonl(text->seqnum);
1795     memcpy(out, &tmpnum, 4);	/* 4 bytes = seq # */
1796 
1797     (*outputlen)+=4; /* for seqnum */
1798 
1799     /* put the 1st 4 bytes in */
1800     tmp=htonl(*outputlen);
1801     memcpy(text->encode_buf, &tmp, 4);
1802 
1803     (*outputlen)+=4;
1804 
1805     *output = text->encode_buf;
1806     text->seqnum++;
1807 
1808     return SASL_OK;
1809 }
1810 
1811 static int
1812 digestmd5_privacy_decode_once(void *context,
1813 			      const char **input,
1814 			      unsigned *inputlen,
1815 			      char **output,
1816 			      unsigned *outputlen)
1817 {
1818     context_t *text = (context_t *) context;
1819     unsigned int tocopy;
1820     unsigned diff;
1821     int result;
1822     unsigned char digest[16];
1823     int tmpnum;
1824     int lup;
1825 
1826     if (text->needsize>0) /* 4 bytes for how long message is */
1827 	{
1828 	    /* if less than 4 bytes just copy those we have into text->size */
1829 	    if (*inputlen<4)
1830 		tocopy=*inputlen;
1831 	    else
1832 		tocopy=4;
1833 
1834 	    if (tocopy>text->needsize)
1835 		tocopy=text->needsize;
1836 
1837 	    memcpy(text->sizebuf+4-text->needsize, *input, tocopy);
1838 	    text->needsize-=tocopy;
1839 
1840 	    *input+=tocopy;
1841 	    *inputlen-=tocopy;
1842 
1843 	    if (text->needsize==0) /* got all of size */
1844 	    {
1845 		memcpy(&(text->size), text->sizebuf, 4);
1846 		text->cursize=0;
1847 		text->size=ntohl(text->size);
1848 
1849 		if (text->size > text->in_maxbuf) {
1850 		    return SASL_FAIL; /* too big probably error */
1851 		}
1852 
1853 		if(!text->buffer)
1854 		    text->buffer=text->utils->malloc(text->size+5);
1855 		else
1856 		    text->buffer=text->utils->realloc(text->buffer,
1857 						      text->size+5);
1858 		if (text->buffer == NULL) return SASL_NOMEM;
1859 	    }
1860 
1861 	    *outputlen=0;
1862 	    *output=NULL;
1863 	    if (*inputlen==0) /* have to wait until next time for data */
1864 		return SASL_OK;
1865 
1866 	    if (text->size==0)  /* should never happen */
1867 		return SASL_FAIL;
1868 	}
1869 
1870     diff=text->size - text->cursize; /* bytes need for full message */
1871 
1872     if (! text->buffer)
1873 	return SASL_FAIL;
1874 
1875     if (*inputlen < diff) /* not enough for a decode */
1876     {
1877 	memcpy(text->buffer+text->cursize, *input, *inputlen);
1878 	text->cursize+=*inputlen;
1879 	*inputlen=0;
1880 	*outputlen=0;
1881 	*output=NULL;
1882 	return SASL_OK;
1883     } else {
1884 	memcpy(text->buffer+text->cursize, *input, diff);
1885 	*input+=diff;
1886 	*inputlen-=diff;
1887     }
1888 
1889     {
1890 	unsigned short ver;
1891 	unsigned int seqnum;
1892 	unsigned char checkdigest[16];
1893 
1894 	result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
1895 				 &text->decode_once_buf_len,
1896 				 text->size-6);
1897 	if (result != SASL_OK)
1898 	    return result;
1899 
1900 	*output = text->decode_once_buf;
1901 	*outputlen = *inputlen;
1902 
1903 	result=text->cipher_dec(text,text->buffer,text->size-6,digest,
1904 				*output, outputlen);
1905 
1906 	if (result!=SASL_OK)
1907 	    return result;
1908 
1909 	{
1910 	    int i;
1911 	    for(i=10; i; i--) {
1912 		memcpy(&ver, text->buffer+text->size-i,2);
1913 		ver=ntohs(ver);
1914 	    }
1915 	}
1916 
1917 	/* check the version number */
1918 	memcpy(&ver, text->buffer+text->size-6, 2);
1919 	ver=ntohs(ver);
1920 	if (ver != version)
1921 	{
1922 #ifdef _INTEGRATED_SOLARIS_
1923 	    text->utils->seterror(text->utils->conn, 0,
1924 		gettext("Wrong Version"));
1925 #else
1926 	    text->utils->seterror(text->utils->conn, 0, "Wrong Version");
1927 #endif /* _INTEGRATED_SOLARIS_ */
1928 	    return SASL_FAIL;
1929 	}
1930 
1931 	/* check the CMAC */
1932 
1933 	/* construct (seqnum, msg) */
1934 	result = _plug_buf_alloc(text->utils, &text->decode_tmp_buf,
1935 				 &text->decode_tmp_buf_len, *outputlen + 4);
1936 	if(result != SASL_OK) return result;
1937 
1938 	tmpnum = htonl(text->rec_seqnum);
1939 	memcpy(text->decode_tmp_buf, &tmpnum, 4);
1940 	memcpy(text->decode_tmp_buf + 4, *output, *outputlen);
1941 
1942 	/* HMAC(ki, (seqnum, msg) ) */
1943 	text->utils->hmac_md5((const unsigned char *) text->decode_tmp_buf,
1944 			      (*outputlen) + 4,
1945 			      text->Ki_receive, HASHLEN, checkdigest);
1946 
1947 	/* now check it */
1948 	for (lup=0;lup<10;lup++)
1949 	    if (checkdigest[lup]!=digest[lup])
1950 		{
1951 #ifdef _SUN_SDK_
1952 		    text->utils->log(text->utils->conn, SASL_LOG_ERR,
1953 			"CMAC doesn't match at byte %d!", lup);
1954 		    return SASL_BADMAC;
1955 #else
1956 		    text->utils->seterror(text->utils->conn, 0,
1957 					  "CMAC doesn't match at byte %d!", lup);
1958 		    return SASL_FAIL;
1959 #endif /* _SUN_SDK_ */
1960 		}
1961 
1962 	/* check the sequence number */
1963 	memcpy(&seqnum, text->buffer+text->size-4,4);
1964 	seqnum=ntohl(seqnum);
1965 
1966 	if (seqnum!=text->rec_seqnum)
1967 	    {
1968 #ifdef _SUN_SDK_
1969 		text->utils->log(text->utils->conn, SASL_LOG_ERR,
1970 				 "Incorrect Sequence Number");
1971 #else
1972 		text->utils->seterror(text->utils->conn, 0,
1973 				      "Incorrect Sequence Number");
1974 #endif /* _SUN_SDK_ */
1975 		return SASL_FAIL;
1976 	    }
1977 
1978 	text->rec_seqnum++; /* now increment it */
1979     }
1980 
1981     text->needsize=4;
1982 
1983     return SASL_OK;
1984 }
1985 
1986 static int digestmd5_privacy_decode(void *context,
1987 				    const char *input, unsigned inputlen,
1988 				    const char **output, unsigned *outputlen)
1989 {
1990     context_t *text = (context_t *) context;
1991     int ret;
1992 
1993     ret = _plug_decode(text->utils, context, input, inputlen,
1994 		       &text->decode_buf, &text->decode_buf_len, outputlen,
1995 		       digestmd5_privacy_decode_once);
1996 
1997     *output = text->decode_buf;
1998 
1999     return ret;
2000 }
2001 
2002 static int
2003 digestmd5_integrity_encode(void *context,
2004 			   const struct iovec *invec,
2005 			   unsigned numiov,
2006 			   const char **output,
2007 			   unsigned *outputlen)
2008 {
2009     context_t      *text = (context_t *) context;
2010     unsigned char   MAC[16];
2011     unsigned int    tmpnum;
2012     unsigned short int tmpshort;
2013     struct buffer_info *inblob, bufinfo;
2014     int ret;
2015 
2016     if(!context || !invec || !numiov || !output || !outputlen) {
2017 	PARAMERROR( text->utils );
2018 	return SASL_BADPARAM;
2019     }
2020 
2021     if (numiov > 1) {
2022 	ret = _plug_iovec_to_buf(text->utils, invec, numiov,
2023 				 &text->enc_in_buf);
2024 	if (ret != SASL_OK) return ret;
2025 	inblob = text->enc_in_buf;
2026     } else {
2027 	/* avoid the data copy */
2028 	bufinfo.data = invec[0].iov_base;
2029 	bufinfo.curlen = invec[0].iov_len;
2030 	inblob = &bufinfo;
2031     }
2032 
2033     /* construct output */
2034     *outputlen = 4 + inblob->curlen + 16;
2035 
2036     ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
2037 			  &(text->encode_buf_len), *outputlen);
2038     if(ret != SASL_OK) return ret;
2039 
2040     /* construct (seqnum, msg) */
2041     /* we can just use the output buffer */
2042     tmpnum = htonl(text->seqnum);
2043     memcpy(text->encode_buf, &tmpnum, 4);
2044     memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
2045 
2046     /* HMAC(ki, (seqnum, msg) ) */
2047 #ifdef _SUN_SDK_
2048     text->utils->hmac_md5((unsigned char *)text->encode_buf,
2049 			  inblob->curlen + 4,
2050 			  text->Ki_send, HASHLEN, MAC);
2051 #else
2052     text->utils->hmac_md5(text->encode_buf, inblob->curlen + 4,
2053 			  text->Ki_send, HASHLEN, MAC);
2054 #endif /* _SUN_SDK_ */
2055 
2056     /* create MAC */
2057     tmpshort = htons(version);
2058     memcpy(MAC + 10, &tmpshort, MAC_OFFS);	/* 2 bytes = version */
2059 
2060     tmpnum = htonl(text->seqnum);
2061     memcpy(MAC + 12, &tmpnum, 4);	/* 4 bytes = sequence number */
2062 
2063     /* copy into output */
2064     tmpnum = htonl((*outputlen) - 4);
2065 
2066     /* length of message in network byte order */
2067     memcpy(text->encode_buf, &tmpnum, 4);
2068     /* the message text */
2069     memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
2070     /* the MAC */
2071     memcpy(text->encode_buf + 4 + inblob->curlen, MAC, 16);
2072 
2073     text->seqnum++;		/* add one to sequence number */
2074 
2075     *output = text->encode_buf;
2076 
2077     return SASL_OK;
2078 }
2079 
2080 static int
2081 create_MAC(context_t * text,
2082 	   char *input,
2083 	   int inputlen,
2084 	   int seqnum,
2085 	   unsigned char MAC[16])
2086 {
2087     unsigned int    tmpnum;
2088     unsigned short int tmpshort;
2089     int ret;
2090 
2091     if (inputlen < 0)
2092 	return SASL_FAIL;
2093 
2094     ret = _plug_buf_alloc(text->utils, &(text->MAC_buf),
2095 			  &(text->MAC_buf_len), inputlen + 4);
2096     if(ret != SASL_OK) return ret;
2097 
2098     /* construct (seqnum, msg) */
2099     tmpnum = htonl(seqnum);
2100     memcpy(text->MAC_buf, &tmpnum, 4);
2101     memcpy(text->MAC_buf + 4, input, inputlen);
2102 
2103     /* HMAC(ki, (seqnum, msg) ) */
2104 #ifdef _SUN_SDK_
2105     text->utils->hmac_md5((unsigned char *)text->MAC_buf, inputlen + 4,
2106 			  text->Ki_receive, HASHLEN,
2107 			  MAC);
2108 #else
2109     text->utils->hmac_md5(text->MAC_buf, inputlen + 4,
2110 			  text->Ki_receive, HASHLEN,
2111 			  MAC);
2112 #endif /* _SUN_SDK_ */
2113 
2114     /* create MAC */
2115     tmpshort = htons(version);
2116     memcpy(MAC + 10, &tmpshort, 2);	/* 2 bytes = version */
2117 
2118     tmpnum = htonl(seqnum);
2119     memcpy(MAC + 12, &tmpnum, 4);	/* 4 bytes = sequence number */
2120 
2121     return SASL_OK;
2122 }
2123 
2124 static int
2125 check_integrity(context_t * text,
2126 		char *buf, int bufsize,
2127 		char **output, unsigned *outputlen)
2128 {
2129     unsigned char MAC[16];
2130     int result;
2131 
2132     result = create_MAC(text, buf, bufsize - 16, text->rec_seqnum, MAC);
2133     if (result != SASL_OK)
2134 	return result;
2135 
2136     /* make sure the MAC is right */
2137     if (strncmp((char *) MAC, buf + bufsize - 16, 16) != 0)
2138     {
2139 #ifdef _SUN_SDK_
2140 	text->utils->log(text->utils->conn, SASL_LOG_ERR,
2141 			 "MAC doesn't match");
2142 	return SASL_BADMAC;
2143 #else
2144 	text->utils->seterror(text->utils->conn, 0, "MAC doesn't match");
2145 	return SASL_FAIL;
2146 #endif /* _SUN_SDK_ */
2147     }
2148 
2149     text->rec_seqnum++;
2150 
2151     /* ok make output message */
2152     result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
2153 			     &text->decode_once_buf_len,
2154 			     bufsize - 15);
2155     if (result != SASL_OK)
2156 	return result;
2157 
2158     *output = text->decode_once_buf;
2159     memcpy(*output, buf, bufsize - 16);
2160     *outputlen = bufsize - 16;
2161     (*output)[*outputlen] = 0;
2162 
2163     return SASL_OK;
2164 }
2165 
2166 static int
2167 digestmd5_integrity_decode_once(void *context,
2168 				const char **input,
2169 				unsigned *inputlen,
2170 				char **output,
2171 				unsigned *outputlen)
2172 {
2173     context_t      *text = (context_t *) context;
2174     unsigned int    tocopy;
2175     unsigned        diff;
2176     int             result;
2177 
2178     if (text->needsize > 0) {	/* 4 bytes for how long message is */
2179 	/*
2180 	 * if less than 4 bytes just copy those we have into text->size
2181 	 */
2182 	if (*inputlen < 4)
2183 	    tocopy = *inputlen;
2184 	else
2185 	    tocopy = 4;
2186 
2187 	if (tocopy > text->needsize)
2188 	    tocopy = text->needsize;
2189 
2190 	memcpy(text->sizebuf + 4 - text->needsize, *input, tocopy);
2191 	text->needsize -= tocopy;
2192 
2193 	*input += tocopy;
2194 	*inputlen -= tocopy;
2195 
2196 	if (text->needsize == 0) {	/* got all of size */
2197 	    memcpy(&(text->size), text->sizebuf, 4);
2198 	    text->cursize = 0;
2199 	    text->size = ntohl(text->size);
2200 
2201 	    if (text->size > text->in_maxbuf)
2202 		return SASL_FAIL;	/* too big probably error */
2203 
2204 	    if(!text->buffer)
2205 		text->buffer=text->utils->malloc(text->size+5);
2206 	    else
2207 		text->buffer=text->utils->realloc(text->buffer,text->size+5);
2208 	    if (text->buffer == NULL) return SASL_NOMEM;
2209 	}
2210 	*outputlen = 0;
2211 	*output = NULL;
2212 	if (*inputlen == 0)		/* have to wait until next time for data */
2213 	    return SASL_OK;
2214 
2215 	if (text->size == 0)	/* should never happen */
2216 	    return SASL_FAIL;
2217     }
2218     diff = text->size - text->cursize;	/* bytes need for full message */
2219 
2220     if(! text->buffer)
2221 	return SASL_FAIL;
2222 
2223     if (*inputlen < diff) {	/* not enough for a decode */
2224 	memcpy(text->buffer + text->cursize, *input, *inputlen);
2225 	text->cursize += *inputlen;
2226 	*inputlen = 0;
2227 	*outputlen = 0;
2228 	*output = NULL;
2229 	return SASL_OK;
2230     } else {
2231 	memcpy(text->buffer + text->cursize, *input, diff);
2232 	*input += diff;
2233 	*inputlen -= diff;
2234     }
2235 
2236     result = check_integrity(text, text->buffer, text->size,
2237 			     output, outputlen);
2238     if (result != SASL_OK)
2239 	return result;
2240 
2241     /* Reset State */
2242     text->needsize = 4;
2243 
2244     return SASL_OK;
2245 }
2246 
2247 static int digestmd5_integrity_decode(void *context,
2248 				      const char *input, unsigned inputlen,
2249 				      const char **output, unsigned *outputlen)
2250 {
2251     context_t *text = (context_t *) context;
2252     int ret;
2253 
2254     ret = _plug_decode(text->utils, context, input, inputlen,
2255 		       &text->decode_buf, &text->decode_buf_len, outputlen,
2256 		       digestmd5_integrity_decode_once);
2257 
2258     *output = text->decode_buf;
2259 
2260     return ret;
2261 }
2262 
2263 static void
2264 digestmd5_common_mech_dispose(void *conn_context, const sasl_utils_t *utils)
2265 {
2266     context_t *text = (context_t *) conn_context;
2267 
2268     if (!text || !utils) return;
2269 
2270     if (text->authid) utils->free(text->authid);
2271     if (text->realm) utils->free(text->realm);
2272     if (text->nonce) utils->free(text->nonce);
2273     if (text->cnonce) utils->free(text->cnonce);
2274 
2275     if (text->cipher_free) text->cipher_free(text);
2276 
2277     /* free the stuff in the context */
2278     if (text->response_value) utils->free(text->response_value);
2279 
2280     if (text->buffer) utils->free(text->buffer);
2281     if (text->encode_buf) utils->free(text->encode_buf);
2282     if (text->decode_buf) utils->free(text->decode_buf);
2283     if (text->decode_once_buf) utils->free(text->decode_once_buf);
2284     if (text->decode_tmp_buf) utils->free(text->decode_tmp_buf);
2285     if (text->out_buf) utils->free(text->out_buf);
2286     if (text->MAC_buf) utils->free(text->MAC_buf);
2287 
2288     if (text->enc_in_buf) {
2289 	if (text->enc_in_buf->data) utils->free(text->enc_in_buf->data);
2290 	utils->free(text->enc_in_buf);
2291     }
2292 
2293     utils->free(conn_context);
2294 }
2295 
2296 static void
2297 clear_reauth_entry(reauth_entry_t *reauth, enum Context_type type,
2298 		   const sasl_utils_t *utils)
2299 {
2300     if (!reauth) return;
2301 
2302     if (reauth->authid) utils->free(reauth->authid);
2303     if (reauth->realm) utils->free(reauth->realm);
2304     if (reauth->nonce) utils->free(reauth->nonce);
2305     if (reauth->cnonce) utils->free(reauth->cnonce);
2306 
2307     if (type == CLIENT) {
2308 	if (reauth->u.c.serverFQDN) utils->free(reauth->u.c.serverFQDN);
2309     }
2310 
2311     memset(reauth, 0, sizeof(reauth_entry_t));
2312 }
2313 
2314 static void
2315 digestmd5_common_mech_free(void *glob_context, const sasl_utils_t *utils)
2316 {
2317     reauth_cache_t *reauth_cache = (reauth_cache_t *) glob_context;
2318     size_t n;
2319 
2320     if (!reauth_cache) return;
2321 
2322     for (n = 0; n < reauth_cache->size; n++)
2323 	clear_reauth_entry(&reauth_cache->e[n], reauth_cache->i_am, utils);
2324     if (reauth_cache->e) utils->free(reauth_cache->e);
2325 
2326     if (reauth_cache->mutex) utils->mutex_free(reauth_cache->mutex);
2327 
2328     utils->free(reauth_cache);
2329 }
2330 
2331 /*****************************  Server Section  *****************************/
2332 
2333 typedef struct server_context {
2334     context_t common;
2335 
2336     time_t timestamp;
2337     int stale;				/* last nonce is stale */
2338     sasl_ssf_t limitssf, requiressf;	/* application defined bounds */
2339 } server_context_t;
2340 
2341 static void
2342 DigestCalcHA1FromSecret(context_t * text,
2343 			const sasl_utils_t * utils,
2344 			HASH HA1,
2345 			unsigned char *authorization_id,
2346 			unsigned char *pszNonce,
2347 			unsigned char *pszCNonce,
2348 			HASHHEX SessionKey)
2349 {
2350     MD5_CTX Md5Ctx;
2351 
2352     /* calculate session key */
2353     utils->MD5Init(&Md5Ctx);
2354     utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
2355     utils->MD5Update(&Md5Ctx, COLON, 1);
2356     utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
2357     utils->MD5Update(&Md5Ctx, COLON, 1);
2358     utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
2359     if (authorization_id != NULL) {
2360 	utils->MD5Update(&Md5Ctx, COLON, 1);
2361 	utils->MD5Update(&Md5Ctx, authorization_id, strlen((char *) authorization_id));
2362     }
2363     utils->MD5Final(HA1, &Md5Ctx);
2364 
2365     CvtHex(HA1, SessionKey);
2366 
2367 
2368     /* save HA1 because we need it to make the privacy and integrity keys */
2369     memcpy(text->HA1, HA1, sizeof(HASH));
2370 }
2371 
2372 static char *create_response(context_t * text,
2373 			     const sasl_utils_t * utils,
2374 			     unsigned char *nonce,
2375 			     unsigned int ncvalue,
2376 			     unsigned char *cnonce,
2377 			     char *qop,
2378 			     char *digesturi,
2379 			     HASH Secret,
2380 			     char *authorization_id,
2381 			     char **response_value)
2382 {
2383     HASHHEX         SessionKey;
2384     HASHHEX         HEntity = "00000000000000000000000000000000";
2385     HASHHEX         Response;
2386     char           *result;
2387 
2388     if (qop == NULL)
2389 	qop = "auth";
2390 
2391     DigestCalcHA1FromSecret(text,
2392 			    utils,
2393 			    Secret,
2394 			    (unsigned char *) authorization_id,
2395 			    nonce,
2396 			    cnonce,
2397 			    SessionKey);
2398 
2399     DigestCalcResponse(utils,
2400 		       SessionKey,/* H(A1) */
2401 		       nonce,	/* nonce from server */
2402 		       ncvalue,	/* 8 hex digits */
2403 		       cnonce,	/* client nonce */
2404 		       (unsigned char *) qop,	/* qop-value: "", "auth",
2405 						 * "auth-int" */
2406 		       (unsigned char *) digesturi,	/* requested URL */
2407 		       (unsigned char *) "AUTHENTICATE",
2408 		       HEntity,	/* H(entity body) if qop="auth-int" */
2409 		       Response	/* request-digest or response-digest */
2410 	);
2411 
2412     result = utils->malloc(HASHHEXLEN + 1);
2413 #ifdef _SUN_SDK_
2414     if (result == NULL)
2415 	return NULL;
2416 #endif /* _SUN_SDK_ */
2417 /* TODO */
2418     memcpy(result, Response, HASHHEXLEN);
2419     result[HASHHEXLEN] = 0;
2420 
2421     /* response_value (used for reauth i think */
2422     if (response_value != NULL) {
2423 	DigestCalcResponse(utils,
2424 			   SessionKey,	/* H(A1) */
2425 			   nonce,	/* nonce from server */
2426 			   ncvalue,	/* 8 hex digits */
2427 			   cnonce,	/* client nonce */
2428 			   (unsigned char *) qop,	/* qop-value: "", "auth",
2429 							 * "auth-int" */
2430 			   (unsigned char *) digesturi,	/* requested URL */
2431 			   NULL,
2432 			   HEntity,	/* H(entity body) if qop="auth-int" */
2433 			   Response	/* request-digest or response-digest */
2434 	    );
2435 
2436 	*response_value = utils->malloc(HASHHEXLEN + 1);
2437 	if (*response_value == NULL)
2438 	    return NULL;
2439 	memcpy(*response_value, Response, HASHHEXLEN);
2440 	(*response_value)[HASHHEXLEN] = 0;
2441     }
2442     return result;
2443 }
2444 
2445 static int
2446 get_server_realm(sasl_server_params_t * params,
2447 		 char **realm)
2448 {
2449     /* look at user realm first */
2450     if (params->user_realm != NULL) {
2451 	if(params->user_realm[0] != '\0') {
2452 	    *realm = (char *) params->user_realm;
2453 	} else {
2454 	    /* Catch improperly converted apps */
2455 #ifdef _SUN_SDK_
2456 	    params->utils->log(params->utils->conn, SASL_LOG_ERR,
2457 			       "user_realm is an empty string!");
2458 #else
2459 	    params->utils->seterror(params->utils->conn, 0,
2460 				    "user_realm is an empty string!");
2461 #endif /* _SUN_SDK_ */
2462 	    return SASL_BADPARAM;
2463 	}
2464     } else if (params->serverFQDN != NULL) {
2465 	*realm = (char *) params->serverFQDN;
2466     } else {
2467 #ifdef _SUN_SDK_
2468 	params->utils->log(params->utils->conn, SASL_LOG_ERR,
2469 			   "no way to obtain domain");
2470 #else
2471 	params->utils->seterror(params->utils->conn, 0,
2472 				"no way to obtain domain");
2473 #endif /* _SUN_SDK_ */
2474 	return SASL_FAIL;
2475     }
2476 
2477     return SASL_OK;
2478 }
2479 
2480 /*
2481  * Convert hex string to int
2482  */
2483 static int htoi(unsigned char *hexin, unsigned int *res)
2484 {
2485     int             lup, inlen;
2486     inlen = strlen((char *) hexin);
2487 
2488     *res = 0;
2489     for (lup = 0; lup < inlen; lup++) {
2490 	switch (hexin[lup]) {
2491 	case '0':
2492 	case '1':
2493 	case '2':
2494 	case '3':
2495 	case '4':
2496 	case '5':
2497 	case '6':
2498 	case '7':
2499 	case '8':
2500 	case '9':
2501 	    *res = (*res << 4) + (hexin[lup] - '0');
2502 	    break;
2503 
2504 	case 'a':
2505 	case 'b':
2506 	case 'c':
2507 	case 'd':
2508 	case 'e':
2509 	case 'f':
2510 	    *res = (*res << 4) + (hexin[lup] - 'a' + 10);
2511 	    break;
2512 
2513 	case 'A':
2514 	case 'B':
2515 	case 'C':
2516 	case 'D':
2517 	case 'E':
2518 	case 'F':
2519 	    *res = (*res << 4) + (hexin[lup] - 'A' + 10);
2520 	    break;
2521 
2522 	default:
2523 	    return SASL_BADPARAM;
2524 	}
2525 
2526     }
2527 
2528     return SASL_OK;
2529 }
2530 
2531 static int digestmd5_server_mech_new(void *glob_context,
2532 				     sasl_server_params_t * sparams,
2533 				     const char *challenge __attribute__((unused)),
2534 				     unsigned challen __attribute__((unused)),
2535 				     void **conn_context)
2536 {
2537     context_t *text;
2538 
2539     /* holds state are in -- allocate server size */
2540     text = sparams->utils->malloc(sizeof(server_context_t));
2541     if (text == NULL)
2542 	return SASL_NOMEM;
2543     memset(text, 0, sizeof(server_context_t));
2544 
2545     text->state = 1;
2546     text->i_am = SERVER;
2547     text->reauth = glob_context;
2548 
2549     *conn_context = text;
2550     return SASL_OK;
2551 }
2552 
2553 static int
2554 digestmd5_server_mech_step1(server_context_t *stext,
2555 			    sasl_server_params_t *sparams,
2556 			    const char *clientin __attribute__((unused)),
2557 			    unsigned clientinlen __attribute__((unused)),
2558 			    const char **serverout,
2559 			    unsigned *serveroutlen,
2560 			    sasl_out_params_t * oparams __attribute__((unused)))
2561 {
2562     context_t *text = (context_t *) stext;
2563     int             result;
2564     char           *realm;
2565     unsigned char  *nonce;
2566     char           *charset = "utf-8";
2567     char qop[1024], cipheropts[1024];
2568     struct digest_cipher *cipher;
2569     unsigned       resplen;
2570     int added_conf = 0;
2571     char maxbufstr[64];
2572 
2573     sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
2574 			"DIGEST-MD5 server step 1");
2575 
2576     /* get realm */
2577     result = get_server_realm(sparams, &realm);
2578     if(result != SASL_OK) return result;
2579 
2580     /* what options should we offer the client? */
2581     qop[0] = '\0';
2582     cipheropts[0] = '\0';
2583     if (stext->requiressf == 0) {
2584 	if (*qop) strcat(qop, ",");
2585 	strcat(qop, "auth");
2586     }
2587     if (stext->requiressf <= 1 && stext->limitssf >= 1) {
2588 	if (*qop) strcat(qop, ",");
2589 	strcat(qop, "auth-int");
2590     }
2591 
2592 #ifdef USE_UEF_SERVER
2593     cipher = available_ciphers1;
2594 #else
2595     cipher = available_ciphers;
2596 #endif
2597     while (cipher->name) {
2598 	/* do we allow this particular cipher? */
2599 	if (stext->requiressf <= cipher->ssf &&
2600 	    stext->limitssf >= cipher->ssf) {
2601 	    if (!added_conf) {
2602 		if (*qop) strcat(qop, ",");
2603 		strcat(qop, "auth-conf");
2604 		added_conf = 1;
2605 	    }
2606 #ifdef _SUN_SDK_
2607 	    if(strlen(cipheropts) + strlen(cipher->name) + 1 >=
2608 			sizeof (cipheropts)) {
2609 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2610 		    "internal error: cipheropts too big");
2611 		return SASL_FAIL;
2612 	    }
2613 #endif /* _SUN_SDK_ */
2614 	    if (*cipheropts) strcat(cipheropts, ",");
2615 	    strcat(cipheropts, cipher->name);
2616 	}
2617 	cipher++;
2618     }
2619 
2620     if (*qop == '\0') {
2621 	/* we didn't allow anything?!? we'll return SASL_TOOWEAK, since
2622 	   that's close enough */
2623 	return SASL_TOOWEAK;
2624     }
2625 
2626     /*
2627      * digest-challenge  = 1#( realm | nonce | qop-options | stale | maxbuf |
2628      * charset | cipher-opts | auth-param )
2629      */
2630 
2631 #ifndef _SUN_SDK_
2632     /* FIXME: get nonce XXX have to clean up after self if fail */
2633 #endif /* !_SUN_SDK_ */
2634     nonce = create_nonce(sparams->utils);
2635     if (nonce == NULL) {
2636 #ifdef _SUN_SDK_
2637 	/* Note typo below */
2638 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2639 			    "internal error: failed creating a nonce");
2640 #else
2641 	SETERROR(sparams->utils, "internal erorr: failed creating a nonce");
2642 #endif /* _SUN_SDK_ */
2643 	return SASL_FAIL;
2644     }
2645 
2646 #ifdef _SUN_SDK_
2647     resplen = strlen((char *)nonce) + strlen("nonce") + 5;
2648 #else
2649     resplen = strlen(nonce) + strlen("nonce") + 5;
2650 #endif /* _SUN_SDK_ */
2651     result = _plug_buf_alloc(sparams->utils, &(text->out_buf),
2652 			     &(text->out_buf_len), resplen);
2653 #ifdef _SUN_SDK_
2654     if(result != SASL_OK) {
2655 	sparams->utils->free(nonce);
2656 	return result;
2657     }
2658 #else
2659     if(result != SASL_OK) return result;
2660 #endif /* _SUN_SDK_ */
2661 
2662     sprintf(text->out_buf, "nonce=\"%s\"", nonce);
2663 
2664     /* add to challenge; if we chose not to specify a realm, we won't
2665      * send one to the client */
2666     if (realm && add_to_challenge(sparams->utils,
2667 				  &text->out_buf, &text->out_buf_len, &resplen,
2668 				  "realm", (unsigned char *) realm,
2669 				  TRUE) != SASL_OK) {
2670 #ifdef _SUN_SDK_
2671 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2672 			    "internal error: add_to_challenge failed");
2673 	sparams->utils->free(nonce);
2674 #else
2675 	SETERROR(sparams->utils, "internal error: add_to_challenge failed");
2676 #endif /* _SUN_SDK_ */
2677 	return SASL_FAIL;
2678     }
2679     /*
2680      * qop-options A quoted string of one or more tokens indicating the
2681      * "quality of protection" values supported by the server.  The value
2682      * "auth" indicates authentication; the value "auth-int" indicates
2683      * authentication with integrity protection; the value "auth-conf"
2684      * indicates authentication with integrity protection and encryption.
2685      */
2686 
2687     /* add qop to challenge */
2688     if (add_to_challenge(sparams->utils,
2689 			 &text->out_buf, &text->out_buf_len, &resplen,
2690 			 "qop",
2691 			 (unsigned char *) qop, TRUE) != SASL_OK) {
2692 #ifdef _SUN_SDK_
2693 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2694 		 "internal error: add_to_challenge 3 failed");
2695 	sparams->utils->free(nonce);
2696 #else
2697 	SETERROR(sparams->utils, "internal error: add_to_challenge 3 failed");
2698 #endif /* _SUN_SDK_ */
2699 	return SASL_FAIL;
2700     }
2701 
2702     /*
2703      *  Cipheropts - list of ciphers server supports
2704      */
2705     /* add cipher-opts to challenge; only add if there are some */
2706     if (strcmp(cipheropts,"")!=0)
2707 	{
2708 	    if (add_to_challenge(sparams->utils,
2709 				 &text->out_buf, &text->out_buf_len, &resplen,
2710 				 "cipher", (unsigned char *) cipheropts,
2711 				 TRUE) != SASL_OK) {
2712 #ifdef _SUN_SDK_
2713 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2714 			"internal error: add_to_challenge 4 failed");
2715 		sparams->utils->free(nonce);
2716 #else
2717 		SETERROR(sparams->utils,
2718 			 "internal error: add_to_challenge 4 failed");
2719 #endif /* _SUN_SDK_ */
2720 		return SASL_FAIL;
2721 	    }
2722 	}
2723 
2724     /* "stale" is true if a reauth failed because of a nonce timeout */
2725     if (stext->stale &&
2726 	add_to_challenge(sparams->utils,
2727 			 &text->out_buf, &text->out_buf_len, &resplen,
2728 #ifdef _SUN_SDK_
2729 			 "stale", (unsigned char *)"true", FALSE) != SASL_OK) {
2730 	sparams->utils->free(nonce);
2731 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2732 			    "internal error: add_to_challenge failed");
2733 #else
2734 			 "stale", "true", FALSE) != SASL_OK) {
2735 	SETERROR(sparams->utils, "internal error: add_to_challenge failed");
2736 #endif /* _SUN_SDK_ */
2737 	return SASL_FAIL;
2738     }
2739 
2740     /*
2741      * maxbuf A number indicating the size of the largest buffer the server
2742      * is able to receive when using "auth-int". If this directive is
2743      * missing, the default value is 65536. This directive may appear at most
2744      * once; if multiple instances are present, the client should abort the
2745      * authentication exchange.
2746      */
2747     if(sparams->props.maxbufsize) {
2748 	snprintf(maxbufstr, sizeof(maxbufstr), "%d",
2749 		 sparams->props.maxbufsize);
2750 	if (add_to_challenge(sparams->utils,
2751 			     &text->out_buf, &text->out_buf_len, &resplen,
2752 			     "maxbuf",
2753 			     (unsigned char *) maxbufstr, FALSE) != SASL_OK) {
2754 #ifdef _SUN_SDK_
2755 	    sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2756 				"internal error: add_to_challenge 5 failed");
2757 #else
2758 	    SETERROR(sparams->utils,
2759 		     "internal error: add_to_challenge 5 failed");
2760 #endif /* _SUN_SDK_ */
2761 	    return SASL_FAIL;
2762 	}
2763     }
2764 
2765 
2766     if (add_to_challenge(sparams->utils,
2767 			 &text->out_buf, &text->out_buf_len, &resplen,
2768 			 "charset",
2769 			 (unsigned char *) charset, FALSE) != SASL_OK) {
2770 #ifdef _SUN_SDK_
2771 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2772 			    "internal error: add_to_challenge 6 failed");
2773 	sparams->utils->free(nonce);
2774 #else
2775 	SETERROR(sparams->utils, "internal error: add_to_challenge 6 failed");
2776 #endif /* _SUN_SDK_ */
2777 	return SASL_FAIL;
2778     }
2779 
2780 
2781     /*
2782      * algorithm
2783      *  This directive is required for backwards compatibility with HTTP
2784      *  Digest., which supports other algorithms. . This directive is
2785      *  required and MUST appear exactly once; if not present, or if multiple
2786      *  instances are present, the client should abort the authentication
2787      *  exchange.
2788      *
2789      * algorithm         = "algorithm" "=" "md5-sess"
2790      */
2791 
2792     if (add_to_challenge(sparams->utils,
2793 			 &text->out_buf, &text->out_buf_len, &resplen,
2794 			 "algorithm",
2795 			 (unsigned char *) "md5-sess", FALSE)!=SASL_OK) {
2796 #ifdef _SUN_SDK_
2797 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2798 			    "internal error: add_to_challenge 7 failed");
2799 	sparams->utils->free(nonce);
2800 #else
2801 	SETERROR(sparams->utils, "internal error: add_to_challenge 7 failed");
2802 #endif /* _SUN_SDK_ */
2803 	return SASL_FAIL;
2804     }
2805 
2806     /*
2807      * The size of a digest-challenge MUST be less than 2048 bytes!!!
2808      */
2809     if (*serveroutlen > 2048) {
2810 #ifdef _SUN_SDK_
2811 	sparams->utils->free(nonce);
2812 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2813 			    "internal error: challenge larger than 2048 bytes");
2814 #else
2815 	SETERROR(sparams->utils,
2816 		 "internal error: challenge larger than 2048 bytes");
2817 #endif /* _SUN_SDK_ */
2818 	return SASL_FAIL;
2819     }
2820 
2821     text->authid = NULL;
2822     _plug_strdup(sparams->utils, realm, &text->realm, NULL);
2823     text->nonce = nonce;
2824     text->nonce_count = 1;
2825     text->cnonce = NULL;
2826     stext->timestamp = time(0);
2827 
2828     *serveroutlen = strlen(text->out_buf);
2829     *serverout = text->out_buf;
2830 
2831     text->state = 2;
2832 
2833     return SASL_CONTINUE;
2834 }
2835 
2836 static int
2837 digestmd5_server_mech_step2(server_context_t *stext,
2838 			    sasl_server_params_t *sparams,
2839 			    const char *clientin,
2840 			    unsigned clientinlen,
2841 			    const char **serverout,
2842 			    unsigned *serveroutlen,
2843 			    sasl_out_params_t * oparams)
2844 {
2845     context_t *text = (context_t *) stext;
2846     /* verify digest */
2847     sasl_secret_t  *sec = NULL;
2848     int             result;
2849     char           *serverresponse = NULL;
2850     char           *username = NULL;
2851     char           *authorization_id = NULL;
2852     char           *realm = NULL;
2853     unsigned char  *nonce = NULL, *cnonce = NULL;
2854     unsigned int   noncecount = 0;
2855     char           *qop = NULL;
2856     char           *digesturi = NULL;
2857     char           *response = NULL;
2858 
2859     /* setting the default value (65536) */
2860     unsigned int    client_maxbuf = 65536;
2861     int             maxbuf_count = 0;  /* How many maxbuf instaces was found */
2862 
2863     char           *charset = NULL;
2864     char           *cipher = NULL;
2865     unsigned int   n=0;
2866 
2867     HASH            A1;
2868 
2869     /* password prop_request */
2870     const char *password_request[] = { SASL_AUX_PASSWORD,
2871 				       "*cmusaslsecretDIGEST-MD5",
2872 				       NULL };
2873     unsigned len;
2874     struct propval auxprop_values[2];
2875 
2876     /* can we mess with clientin? copy it to be safe */
2877     char           *in_start = NULL;
2878     char           *in = NULL;
2879 
2880     sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
2881 			"DIGEST-MD5 server step 2");
2882 
2883     in = sparams->utils->malloc(clientinlen + 1);
2884 #ifdef _SUN_SDK_
2885     if (!in) return SASL_NOMEM;
2886 #endif /* _SUN_SDK_ */
2887 
2888     memcpy(in, clientin, clientinlen);
2889     in[clientinlen] = 0;
2890 
2891     in_start = in;
2892 
2893 
2894     /* parse what we got */
2895     while (in[0] != '\0') {
2896 	char           *name = NULL, *value = NULL;
2897 	get_pair(&in, &name, &value);
2898 
2899 	if (name == NULL)
2900 	    break;
2901 
2902 	/* Extracting parameters */
2903 
2904 	/*
2905 	 * digest-response  = 1#( username | realm | nonce | cnonce |
2906 	 * nonce-count | qop | digest-uri | response | maxbuf | charset |
2907 	 * cipher | auth-param )
2908 	 */
2909 
2910 	if (strcasecmp(name, "username") == 0) {
2911 	    _plug_strdup(sparams->utils, value, &username, NULL);
2912 	} else if (strcasecmp(name, "authzid") == 0) {
2913 	    _plug_strdup(sparams->utils, value, &authorization_id, NULL);
2914 	} else if (strcasecmp(name, "cnonce") == 0) {
2915 	    _plug_strdup(sparams->utils, value, (char **) &cnonce, NULL);
2916 	} else if (strcasecmp(name, "nc") == 0) {
2917 	    if (htoi((unsigned char *) value, &noncecount) != SASL_OK) {
2918 #ifdef _SUN_SDK_
2919 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2920 			 "error converting hex to int");
2921 #else
2922 		SETERROR(sparams->utils,
2923 			 "error converting hex to int");
2924 #endif /* _SUN_SDK_ */
2925 		result = SASL_BADAUTH;
2926 		goto FreeAllMem;
2927 	    }
2928 	} else if (strcasecmp(name, "realm") == 0) {
2929 	    if (realm) {
2930 #ifdef _SUN_SDK_
2931 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2932 				    "duplicate realm: authentication aborted");
2933 #else
2934 		SETERROR(sparams->utils,
2935 			 "duplicate realm: authentication aborted");
2936 #endif /* _SUN_SDK_ */
2937 		result = SASL_FAIL;
2938 		goto FreeAllMem;
2939 	    }
2940 	    _plug_strdup(sparams->utils, value, &realm, NULL);
2941 	} else if (strcasecmp(name, "nonce") == 0) {
2942 	    _plug_strdup(sparams->utils, value, (char **) &nonce, NULL);
2943 	} else if (strcasecmp(name, "qop") == 0) {
2944 	    _plug_strdup(sparams->utils, value, &qop, NULL);
2945 	} else if (strcasecmp(name, "digest-uri") == 0) {
2946             size_t service_len;
2947 
2948 	    /*
2949 	     * digest-uri-value  = serv-type "/" host [ "/" serv-name ]
2950 	     */
2951 
2952 	    _plug_strdup(sparams->utils, value, &digesturi, NULL);
2953 
2954 	    /* verify digest-uri format */
2955 
2956             /* make sure it's the service that we're expecting */
2957             service_len = strlen(sparams->service);
2958             if (strncasecmp(digesturi, sparams->service, service_len) ||
2959                 digesturi[service_len] != '/') {
2960                 result = SASL_BADAUTH;
2961 #ifdef _SUN_SDK_
2962 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2963 				    "bad digest-uri: doesn't match service");
2964 #else
2965                 SETERROR(sparams->utils,
2966                          "bad digest-uri: doesn't match service");
2967 #endif /* _SUN_SDK_ */
2968                 goto FreeAllMem;
2969             }
2970 
2971             /* xxx we don't verify the hostname component */
2972 
2973 	} else if (strcasecmp(name, "response") == 0) {
2974 	    _plug_strdup(sparams->utils, value, &response, NULL);
2975 	} else if (strcasecmp(name, "cipher") == 0) {
2976 	    _plug_strdup(sparams->utils, value, &cipher, NULL);
2977 	} else if (strcasecmp(name, "maxbuf") == 0) {
2978 	    maxbuf_count++;
2979 	    if (maxbuf_count != 1) {
2980 		result = SASL_BADAUTH;
2981 #ifdef _SUN_SDK_
2982 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2983 				    "duplicate maxbuf: authentication aborted");
2984 #else
2985 		SETERROR(sparams->utils,
2986 			 "duplicate maxbuf: authentication aborted");
2987 #endif /* _SUN_SDK_ */
2988 		goto FreeAllMem;
2989 	    } else if (sscanf(value, "%u", &client_maxbuf) != 1) {
2990 		result = SASL_BADAUTH;
2991 #ifdef _SUN_SDK_
2992 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2993 			"invalid maxbuf parameter");
2994 #else
2995 		SETERROR(sparams->utils, "invalid maxbuf parameter");
2996 #endif /* _SUN_SDK_ */
2997 		goto FreeAllMem;
2998 	    } else {
2999 		if (client_maxbuf <= 16) {
3000 		    result = SASL_BADAUTH;
3001 #ifdef _SUN_SDK_
3002 		    sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3003 					"maxbuf parameter too small");
3004 #else
3005 		    SETERROR(sparams->utils,
3006 			     "maxbuf parameter too small");
3007 #endif /* _SUN_SDK_ */
3008 		    goto FreeAllMem;
3009 		}
3010 	    }
3011 	} else if (strcasecmp(name, "charset") == 0) {
3012 	    if (strcasecmp(value, "utf-8") != 0) {
3013 #ifdef _SUN_SDK_
3014 		sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3015 				    "client doesn't support UTF-8");
3016 #else
3017 		SETERROR(sparams->utils, "client doesn't support UTF-8");
3018 #endif /* _SUN_SDK_ */
3019 		result = SASL_FAIL;
3020 		goto FreeAllMem;
3021 	    }
3022 	    _plug_strdup(sparams->utils, value, &charset, NULL);
3023 	} else {
3024 	    sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
3025 				"DIGEST-MD5 unrecognized pair %s/%s: ignoring",
3026 				name, value);
3027 	}
3028     }
3029 
3030     /*
3031      * username         = "username" "=" <"> username-value <">
3032      * username-value   = qdstr-val cnonce           = "cnonce" "=" <">
3033      * cnonce-value <"> cnonce-value     = qdstr-val nonce-count      = "nc"
3034      * "=" nc-value nc-value         = 8LHEX qop              = "qop" "="
3035      * qop-value digest-uri = "digest-uri" "=" digest-uri-value
3036      * digest-uri-value  = serv-type "/" host [ "/" serv-name ] serv-type
3037      * = 1*ALPHA host             = 1*( ALPHA | DIGIT | "-" | "." ) service
3038      * = host response         = "response" "=" <"> response-value <">
3039      * response-value   = 32LHEX LHEX = "0" | "1" | "2" | "3" | "4" | "5" |
3040      * "6" | "7" | "8" | "9" | "a" | "b" | "c" | "d" | "e" | "f" cipher =
3041      * "cipher" "=" cipher-value
3042      */
3043     /* Verifing that all parameters was defined */
3044     if ((username == NULL) ||
3045 	(nonce == NULL) ||
3046 	(noncecount == 0) ||
3047 	(cnonce == NULL) ||
3048 	(digesturi == NULL) ||
3049 	(response == NULL)) {
3050 #ifdef _SUN_SDK_
3051 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3052 		"required parameters missing");
3053 #else
3054 	SETERROR(sparams->utils, "required parameters missing");
3055 #endif /* _SUN_SDK_ */
3056 	result = SASL_BADAUTH;
3057 	goto FreeAllMem;
3058     }
3059 
3060     if (text->state == 1) {
3061 	unsigned val = hash(username) % text->reauth->size;
3062 
3063 	/* reauth attempt, see if we have any info for this user */
3064 	if (sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
3065 	    if (text->reauth->e[val].authid &&
3066 		!strcmp(username, text->reauth->e[val].authid)) {
3067 
3068 		_plug_strdup(sparams->utils, text->reauth->e[val].realm,
3069 			     &text->realm, NULL);
3070 #ifdef _SUN_SDK_
3071 		_plug_strdup(sparams->utils, (char *)text->reauth->e[val].nonce,
3072 			     (char **) &text->nonce, NULL);
3073 #else
3074 		_plug_strdup(sparams->utils, text->reauth->e[val].nonce,
3075 			     (char **) &text->nonce, NULL);
3076 #endif /* _SUN_SDK_ */
3077 		text->nonce_count = ++text->reauth->e[val].nonce_count;
3078 #ifdef _SUN_SDK_
3079 		_plug_strdup(sparams->utils, (char *)text->reauth->e[val].cnonce,
3080 			     (char **) &text->cnonce, NULL);
3081 #else
3082 		_plug_strdup(sparams->utils, text->reauth->e[val].cnonce,
3083 			     (char **) &text->cnonce, NULL);
3084 #endif /* _SUN_SDK_ */
3085 		stext->timestamp = text->reauth->e[val].u.s.timestamp;
3086 	    }
3087 	    sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
3088 	}
3089 
3090 	if (!text->nonce) {
3091 	    /* we don't have any reauth info, so bail */
3092 	    result = SASL_FAIL;
3093 	    goto FreeAllMem;
3094 	}
3095     }
3096 
3097     /* Sanity check the parameters */
3098 #ifdef _SUN_SDK_
3099     if ((realm != NULL && text->realm != NULL &&
3100 		strcmp(realm, text->realm) != 0) ||
3101 	    (realm == NULL && text->realm != NULL) ||
3102 	    (realm != NULL && text->realm == NULL)) {
3103 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3104 			    "realm changed: authentication aborted");
3105 #else
3106     if (strcmp(realm, text->realm) != 0) {
3107 	SETERROR(sparams->utils,
3108 		 "realm changed: authentication aborted");
3109 #endif /* _SUN_SDK_ */
3110 	result = SASL_BADAUTH;
3111 	goto FreeAllMem;
3112     }
3113 #ifdef _SUN_SDK_
3114     if (strcmp((char *)nonce, (char *) text->nonce) != 0) {
3115 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3116 			    "nonce changed: authentication aborted");
3117 #else
3118     if (strcmp(nonce, (char *) text->nonce) != 0) {
3119 	SETERROR(sparams->utils,
3120 		 "nonce changed: authentication aborted");
3121 #endif /* _SUN_SKD_ */
3122 	result = SASL_BADAUTH;
3123 	goto FreeAllMem;
3124     }
3125     if (noncecount != text->nonce_count) {
3126 #ifdef _SUN_SDK_
3127 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3128 			    "incorrect nonce-count: authentication aborted");
3129 #else
3130 	SETERROR(sparams->utils,
3131 		 "incorrect nonce-count: authentication aborted");
3132 #endif /* _SUN_SDK_ */
3133 	result = SASL_BADAUTH;
3134 	goto FreeAllMem;
3135     }
3136 #ifdef _SUN_SDK_
3137     if (text->cnonce && strcmp((char *)cnonce, (char *)text->cnonce) != 0) {
3138 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3139 			    "cnonce changed: authentication aborted");
3140 #else
3141     if (text->cnonce && strcmp(cnonce, text->cnonce) != 0) {
3142 	SETERROR(sparams->utils,
3143 		 "cnonce changed: authentication aborted");
3144 #endif /* _SUN_SDK_ */
3145 	result = SASL_BADAUTH;
3146 	goto FreeAllMem;
3147     }
3148 
3149     result = sparams->utils->prop_request(sparams->propctx, password_request);
3150     if(result != SASL_OK) {
3151 #ifdef _SUN_SDK_
3152 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3153 			    "unable to request user password");
3154 #else
3155 	SETERROR(sparams->utils, "unable to resquest user password");
3156 #endif /* _SUN_SDK_ */
3157 	goto FreeAllMem;
3158     }
3159 
3160     /* this will trigger the getting of the aux properties */
3161     /* Note that if we don't have an authorization id, we don't use it... */
3162     result = sparams->canon_user(sparams->utils->conn,
3163 				 username, 0, SASL_CU_AUTHID, oparams);
3164     if (result != SASL_OK) {
3165 #ifdef _SUN_SDK_
3166 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3167 			    "unable canonify user and get auxprops");
3168 #else
3169 	SETERROR(sparams->utils, "unable canonify user and get auxprops");
3170 #endif /* _SUN_SDK_ */
3171 	goto FreeAllMem;
3172     }
3173 
3174     if (!authorization_id || !*authorization_id) {
3175 	result = sparams->canon_user(sparams->utils->conn,
3176 				     username, 0, SASL_CU_AUTHZID, oparams);
3177     } else {
3178 	result = sparams->canon_user(sparams->utils->conn,
3179 				     authorization_id, 0, SASL_CU_AUTHZID,
3180 				     oparams);
3181     }
3182 
3183     if (result != SASL_OK) {
3184 #ifdef _SUN_SDK_
3185 	sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3186 			    "unable to canonicalize authorization ID");
3187 #else
3188 	SETERROR(sparams->utils, "unable authorization ID");
3189 #endif /* _SUN_SDK_ */
3190 	goto FreeAllMem;
3191     }
3192 
3193     result = sparams->utils->prop_getnames(sparams->propctx, password_request,
3194 					   auxprop_values);
3195     if (result < 0 ||
3196        ((!auxprop_values[0].name || !auxprop_values[0].values) &&
3197 	(!auxprop_values[1].name || !auxprop_values[1].values))) {
3198 	/* We didn't find this username */
3199 #ifdef _INTEGRATED_SOLARIS_
3200 	sparams->utils->seterror(sparams->utils->conn, 0,
3201 			gettext("no secret in database"));
3202 #else
3203 	sparams->utils->seterror(sparams->utils->conn, 0,
3204 				 "no secret in database");
3205 #endif /* _INTEGRATED_SOLARIS_ */
3206 	result = SASL_NOUSER;
3207 	goto FreeAllMem;
3208     }
3209 
3210     if (auxprop_values[0].name && auxprop_values[0].values) {
3211 	len = strlen(auxprop_values[0].values[0]);
3212 	if (len == 0) {
3213 #ifdef _INTEGRATED_SOLARIS_
3214 	    sparams->utils->seterror(sparams->utils->conn,0,
3215 			gettext("empty secret"));
3216 #else
3217 	    sparams->utils->seterror(sparams->utils->conn,0,
3218 				     "empty secret");
3219 #endif /* _INTEGRATED_SOLARIS_ */
3220 	    result = SASL_FAIL;
3221 	    goto FreeAllMem;
3222 	}
3223 
3224 	sec = sparams->utils->malloc(sizeof(sasl_secret_t) + len);
3225 	if (!sec) {
3226 #ifdef _SUN_SDK_
3227 	    sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3228 				"unable to allocate secret");
3229 #else
3230 	    SETERROR(sparams->utils, "unable to allocate secret");
3231 #endif /* _SUN_SDK_ */
3232 	    result = SASL_FAIL;
3233 	    goto FreeAllMem;
3234 	}
3235 
3236 	sec->len = len;
3237 #ifdef _SUN_SDK_
3238 	strncpy((char *)sec->data, auxprop_values[0].values[0], len + 1);
3239 #else
3240 	strncpy(sec->data, auxprop_values[0].values[0], len + 1);
3241 #endif /* _SUN_SDK_ */
3242 
3243 	/*
3244 	 * Verifying response obtained from client
3245 	 *
3246 	 * H_URP = H({ username-value,":",realm-value,":",passwd}) sec->data
3247 	 * contains H_URP
3248 	 */
3249 
3250 	/* Calculate the secret from the plaintext password */
3251 	{
3252 	    HASH <