1 /*
   2  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 
   6 #pragma ident   "%Z%%M% %I%     %E% SMI"
   7 
   8 /* DIGEST-MD5 SASL plugin
   9  * Rob Siemborski
  10  * Tim Martin
  11  * Alexey Melnikov 
  12  * $Id: digestmd5.c,v 1.153 2003/03/30 22:17:06 leg Exp $
  13  */
  14 /* 
  15  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
  16  *
  17  * Redistribution and use in source and binary forms, with or without
  18  * modification, are permitted provided that the following conditions
  19  * are met:
  20  *
  21  * 1. Redistributions of source code must retain the above copyright
  22  *    notice, this list of conditions and the following disclaimer. 
  23  *
  24  * 2. Redistributions in binary form must reproduce the above copyright
  25  *    notice, this list of conditions and the following disclaimer in
  26  *    the documentation and/or other materials provided with the
  27  *    distribution.
  28  *
  29  * 3. The name "Carnegie Mellon University" must not be used to
  30  *    endorse or promote products derived from this software without
  31  *    prior written permission. For permission or any other legal
  32  *    details, please contact  
  33  *      Office of Technology Transfer
  34  *      Carnegie Mellon University
  35  *      5000 Forbes Avenue
  36  *      Pittsburgh, PA  15213-3890
  37  *      (412) 268-4387, fax: (412) 268-7395
  38  *      tech-transfer@andrew.cmu.edu
  39  *
  40  * 4. Redistributions of any form whatsoever must retain the following
  41  *    acknowledgment:
  42  *    "This product includes software developed by Computing Services
  43  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
  44  *
  45  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
  46  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  47  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
  48  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  49  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  50  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  51  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  52  */
  53 
  54 #include <config.h>
  55 
  56 #include <stdlib.h>
  57 #include <stdio.h>
  58 #include <string.h>
  59 #ifndef macintosh
  60 #include <sys/types.h>
  61 #include <sys/stat.h>
  62 #endif
  63 #include <fcntl.h>
  64 #include <ctype.h>
  65 
  66 /* EXPORT DELETE START */
  67 /* DES support */
  68 #ifdef WITH_DES
  69 # ifdef WITH_SSL_DES
  70 #  include <openssl/des.h>
  71 # else /* system DES library */
  72 #  include <des.h>
  73 # endif
  74 #endif /* WITH_DES */
  75 /* EXPORT DELETE END */
  76 
  77 #ifdef WIN32
  78 # include <winsock.h>
  79 #else /* Unix */
  80 # include <netinet/in.h>
  81 #endif /* WIN32 */
  82 
  83 #ifdef _SUN_SDK_
  84 #include <unistd.h>
  85 #endif /* _SUN_SDK_ */
  86 
  87 #include <sasl.h>
  88 #include <saslplug.h>
  89 
  90 #include "plugin_common.h"
  91 
  92 #if defined _SUN_SDK_  && defined USE_UEF
  93 #include <security/cryptoki.h>
  94 static int uef_init(const sasl_utils_t *utils);
  95 #endif /* _SUN_SDK_ && USE_UEF */
  96 
  97 #ifndef WIN32
  98 extern int strcasecmp(const char *s1, const char *s2);
  99 #endif /* end WIN32 */
 100 
 101 #ifdef macintosh
 102 #include <sasl_md5_plugin_decl.h>
 103 #endif
 104 
 105 /* external definitions */
 106 
 107 #ifndef _SUN_SDK_
 108 #ifdef sun
 109 /* gotta define gethostname ourselves on suns */
 110 extern int      gethostname(char *, int);
 111 #endif
 112 #endif /* !_SUN_SDK_ */
 113 
 114 #define bool int
 115 
 116 #ifndef TRUE
 117 #define TRUE  (1)
 118 #define FALSE (0)
 119 #endif
 120 
 121 #define DEFAULT_BUFSIZE 0xFFFF
 122 
 123 /*****************************  Common Section  *****************************/
 124 
 125 #ifndef _SUN_SDK_
 126 static const char plugin_id[] = "$Id: digestmd5.c,v 1.153 2003/03/30 22:17:06 leg Exp $";
 127 #endif /* !_SUN_SDK_ */
 128 
 129 /* Definitions */
 130 #define NONCE_SIZE (32)         /* arbitrary */
 131 
 132 /* Layer Flags */
 133 #define DIGEST_NOLAYER    (1)
 134 #define DIGEST_INTEGRITY  (2)
 135 #define DIGEST_PRIVACY    (4)
 136 
 137 /* defines */
 138 #define HASHLEN 16
 139 typedef unsigned char HASH[HASHLEN + 1];
 140 #define HASHHEXLEN 32
 141 typedef unsigned char HASHHEX[HASHHEXLEN + 1];
 142 
 143 #define MAC_SIZE 10
 144 #define MAC_OFFS 2
 145 
 146 const char *SEALING_CLIENT_SERVER="Digest H(A1) to client-to-server sealing key magic constant";
 147 const char *SEALING_SERVER_CLIENT="Digest H(A1) to server-to-client sealing key magic constant";
 148 
 149 const char *SIGNING_CLIENT_SERVER="Digest session key to client-to-server signing key magic constant";
 150 const char *SIGNING_SERVER_CLIENT="Digest session key to server-to-client signing key magic constant";
 151 
 152 #define HT      (9)
 153 #define CR      (13)
 154 #define LF      (10)
 155 #define SP      (32)
 156 #define DEL     (127)
 157 
 158 struct context;
 159 
 160 /* function definitions for cipher encode/decode */
 161 typedef int cipher_function_t(struct context *,
 162                               const char *,
 163                               unsigned,
 164                               unsigned char[],
 165                               char *,
 166                               unsigned *);
 167 
 168 #ifdef _SUN_SDK_
 169 typedef int cipher_init_t(struct context *, char [16], 
 170                                             char [16]);
 171 #else
 172 typedef int cipher_init_t(struct context *, unsigned char [16], 
 173                                             unsigned char [16]);
 174 #endif /* _SUN_SDK_ */
 175 
 176 typedef void cipher_free_t(struct context *);
 177 
 178 enum Context_type { SERVER = 0, CLIENT = 1 };
 179 
 180 typedef struct cipher_context cipher_context_t;
 181 
 182 /* cached auth info used for fast reauth */
 183 typedef struct reauth_entry {
 184     char *authid;
 185     char *realm;
 186     unsigned char *nonce;
 187     unsigned int nonce_count;
 188     unsigned char *cnonce;
 189 
 190     union {
 191         struct {
 192             time_t timestamp;
 193         } s; /* server stuff */
 194 
 195         struct {
 196             char *serverFQDN;
 197             int protection;
 198             struct digest_cipher *cipher;
 199             unsigned int server_maxbuf;
 200         } c; /* client stuff */
 201     } u;
 202 } reauth_entry_t;
 203 
 204 typedef struct reauth_cache {
 205     /* static stuff */
 206     enum Context_type i_am;     /* are we the client or server? */
 207     time_t timeout;
 208     void *mutex;
 209     size_t size;
 210 
 211     reauth_entry_t *e;          /* fixed-size hash table of entries */
 212 } reauth_cache_t;
 213 
 214 /* context that stores info */
 215 typedef struct context {
 216     int state;                  /* state in the authentication we are in */
 217     enum Context_type i_am;     /* are we the client or server? */
 218     
 219     reauth_cache_t *reauth;
 220 
 221     char *authid;
 222     char *realm;
 223     unsigned char *nonce;
 224     unsigned int nonce_count;
 225     unsigned char *cnonce;
 226 
 227     char *response_value;
 228     
 229     unsigned int seqnum;
 230     unsigned int rec_seqnum;    /* for checking integrity */
 231     
 232     HASH Ki_send;
 233     HASH Ki_receive;
 234     
 235     HASH HA1;           /* Kcc or Kcs */
 236     
 237     /* copy of utils from the params structures */
 238     const sasl_utils_t *utils;
 239     
 240     /* For general use */
 241     char *out_buf;
 242     unsigned out_buf_len;
 243     
 244     /* for encoding/decoding */
 245     buffer_info_t *enc_in_buf;
 246     char *encode_buf, *decode_buf, *decode_once_buf;
 247     unsigned encode_buf_len, decode_buf_len, decode_once_buf_len;
 248     char *decode_tmp_buf;
 249     unsigned decode_tmp_buf_len;
 250     char *MAC_buf;
 251     unsigned MAC_buf_len;
 252     
 253     char *buffer;
 254     char sizebuf[4];
 255     int cursize;
 256 
 257     /* Layer info */
 258     unsigned int size; /* Absolute size of buffer */
 259     unsigned int needsize; /* How much of the size of the buffer is left */
 260     
 261     /* Server MaxBuf for Client or Client MaxBuf For Server */
 262     /* INCOMING */
 263     unsigned int in_maxbuf;
 264     
 265     /* if privacy mode is used use these functions for encode and decode */
 266     cipher_function_t *cipher_enc;
 267     cipher_function_t *cipher_dec;
 268     cipher_init_t *cipher_init;
 269     cipher_free_t *cipher_free;
 270     struct cipher_context *cipher_enc_context;
 271     struct cipher_context *cipher_dec_context;
 272 } context_t;
 273 
 274 struct digest_cipher {
 275     char *name;
 276     sasl_ssf_t ssf;
 277     int n; /* bits to make privacy key */
 278     int flag; /* a bitmask to make things easier for us */
 279     
 280     cipher_function_t *cipher_enc;
 281     cipher_function_t *cipher_dec;
 282     cipher_init_t *cipher_init;
 283     cipher_free_t *cipher_free;
 284 };
 285 
 286 #ifdef _SUN_SDK_
 287 static const unsigned char *COLON = (unsigned char *)":";
 288 #else
 289 static const unsigned char *COLON = ":";
 290 #endif /* _SUN_SDK_ */
 291 
 292 /* Hashes a string to produce an unsigned short */
 293 static unsigned hash(const char *str)
 294 {
 295     unsigned val = 0;
 296     int i;
 297 
 298     while (str && *str) {
 299         i = (int) *str;
 300         val ^= i;
 301         val <<= 1;
 302         str++;
 303     }
 304 
 305     return val;
 306 }
 307 
 308 static void CvtHex(HASH Bin, HASHHEX Hex)
 309 {
 310     unsigned short  i;
 311     unsigned char   j;
 312     
 313     for (i = 0; i < HASHLEN; i++) {
 314         j = (Bin[i] >> 4) & 0xf;
 315         if (j <= 9)
 316             Hex[i * 2] = (j + '0');
 317         else
 318             Hex[i * 2] = (j + 'a' - 10);
 319         j = Bin[i] & 0xf;
 320         if (j <= 9)
 321             Hex[i * 2 + 1] = (j + '0');
 322         else
 323             Hex[i * 2 + 1] = (j + 'a' - 10);
 324     }
 325     Hex[HASHHEXLEN] = '\0';
 326 }
 327 
 328 /*
 329  * calculate request-digest/response-digest as per HTTP Digest spec
 330  */
 331 void
 332 DigestCalcResponse(const sasl_utils_t * utils,
 333                    HASHHEX HA1, /* H(A1) */
 334                    unsigned char *pszNonce,     /* nonce from server */
 335                    unsigned int pszNonceCount,  /* 8 hex digits */
 336                    unsigned char *pszCNonce,    /* client nonce */
 337                    unsigned char *pszQop,       /* qop-value: "", "auth",
 338                                                  * "auth-int" */
 339                    unsigned char *pszDigestUri, /* requested URL */
 340                    unsigned char *pszMethod,
 341                    HASHHEX HEntity,     /* H(entity body) if qop="auth-int" */
 342                    HASHHEX Response     /* request-digest or response-digest */
 343     )
 344 {
 345     MD5_CTX         Md5Ctx;
 346     HASH            HA2;
 347     HASH            RespHash;
 348     HASHHEX         HA2Hex;
 349     char ncvalue[10];
 350     
 351     /* calculate H(A2) */
 352     utils->MD5Init(&Md5Ctx);
 353     
 354     if (pszMethod != NULL) {
 355         utils->MD5Update(&Md5Ctx, pszMethod, strlen((char *) pszMethod));
 356     }
 357     utils->MD5Update(&Md5Ctx, (unsigned char *) COLON, 1);
 358     
 359     /* utils->MD5Update(&Md5Ctx, (unsigned char *) "AUTHENTICATE:", 13); */
 360     utils->MD5Update(&Md5Ctx, pszDigestUri, strlen((char *) pszDigestUri));
 361     if (strcasecmp((char *) pszQop, "auth") != 0) {
 362         /* append ":00000000000000000000000000000000" */
 363         utils->MD5Update(&Md5Ctx, COLON, 1);
 364         utils->MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);
 365     }
 366     utils->MD5Final(HA2, &Md5Ctx);
 367     CvtHex(HA2, HA2Hex);
 368     
 369     /* calculate response */
 370     utils->MD5Init(&Md5Ctx);
 371     utils->MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
 372     utils->MD5Update(&Md5Ctx, COLON, 1);
 373     utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
 374     utils->MD5Update(&Md5Ctx, COLON, 1);
 375     if (*pszQop) {
 376         sprintf(ncvalue, "%08x", pszNonceCount);
 377 #ifdef _SUN_SDK_
 378         utils->MD5Update(&Md5Ctx, (unsigned char *)ncvalue, strlen(ncvalue));
 379 #else
 380         utils->MD5Update(&Md5Ctx, ncvalue, strlen(ncvalue));
 381 #endif /* _SUN_SDK_ */
 382         utils->MD5Update(&Md5Ctx, COLON, 1);
 383         utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
 384         utils->MD5Update(&Md5Ctx, COLON, 1);
 385         utils->MD5Update(&Md5Ctx, pszQop, strlen((char *) pszQop));
 386         utils->MD5Update(&Md5Ctx, COLON, 1);
 387     }
 388     utils->MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
 389     utils->MD5Final(RespHash, &Md5Ctx);
 390     CvtHex(RespHash, Response);
 391 }
 392 
 393 static bool UTF8_In_8859_1(const unsigned char *base, int len)
 394 {
 395     const unsigned char *scan, *end;
 396     
 397     end = base + len;
 398     for (scan = base; scan < end; ++scan) {
 399         if (*scan > 0xC3)
 400             break;                      /* abort if outside 8859-1 */
 401         if (*scan >= 0xC0 && *scan <= 0xC3) {
 402             if (++scan == end || *scan < 0x80 || *scan > 0xBF)
 403                 break;
 404         }
 405     }
 406     
 407     /* if scan >= end, then this is a 8859-1 string. */
 408     return (scan >= end);
 409 }
 410 
 411 /*
 412  * if the string is entirely in the 8859-1 subset of UTF-8, then translate to
 413  * 8859-1 prior to MD5
 414  */
 415 void MD5_UTF8_8859_1(const sasl_utils_t * utils,
 416                      MD5_CTX * ctx,
 417                      bool In_ISO_8859_1,
 418                      const unsigned char *base,
 419                      int len)
 420 {
 421     const unsigned char *scan, *end;
 422     unsigned char   cbuf;
 423     
 424     end = base + len;
 425     
 426     /* if we found a character outside 8859-1, don't alter string */
 427     if (!In_ISO_8859_1) {
 428         utils->MD5Update(ctx, base, len);
 429         return;
 430     }
 431     /* convert to 8859-1 prior to applying hash */
 432     do {
 433         for (scan = base; scan < end && *scan < 0xC0; ++scan);
 434         if (scan != base)
 435             utils->MD5Update(ctx, base, scan - base);
 436         if (scan + 1 >= end)
 437             break;
 438         cbuf = ((scan[0] & 0x3) << 6) | (scan[1] & 0x3f);
 439         utils->MD5Update(ctx, &cbuf, 1);
 440         base = scan + 2;
 441     }
 442     while (base < end);
 443 }
 444 
 445 static void DigestCalcSecret(const sasl_utils_t * utils,
 446                              unsigned char *pszUserName,
 447                              unsigned char *pszRealm,
 448                              unsigned char *Password,
 449                              int PasswordLen,
 450                              HASH HA1)
 451 {
 452     bool            In_8859_1;
 453     
 454     MD5_CTX         Md5Ctx;
 455     
 456     /* Chris Newman clarified that the following text in DIGEST-MD5 spec
 457        is bogus: "if name and password are both in ISO 8859-1 charset"
 458        We shoud use code example instead */
 459     
 460     utils->MD5Init(&Md5Ctx);
 461     
 462     /* We have to convert UTF-8 to ISO-8859-1 if possible */
 463     In_8859_1 = UTF8_In_8859_1(pszUserName, strlen((char *) pszUserName));
 464     MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
 465                     pszUserName, strlen((char *) pszUserName));
 466     
 467     utils->MD5Update(&Md5Ctx, COLON, 1);
 468     
 469     if (pszRealm != NULL && pszRealm[0] != '\0') {
 470         /* a NULL realm is equivalent to the empty string */
 471         utils->MD5Update(&Md5Ctx, pszRealm, strlen((char *) pszRealm));
 472     }      
 473     
 474     utils->MD5Update(&Md5Ctx, COLON, 1);
 475     
 476     /* We have to convert UTF-8 to ISO-8859-1 if possible */
 477     In_8859_1 = UTF8_In_8859_1(Password, PasswordLen);
 478     MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
 479                     Password, PasswordLen);
 480     
 481     utils->MD5Final(HA1, &Md5Ctx);
 482 }
 483 
 484 static unsigned char *create_nonce(const sasl_utils_t * utils)
 485 {
 486     unsigned char  *base64buf;
 487     int             base64len;
 488     
 489     char           *ret = (char *) utils->malloc(NONCE_SIZE);
 490     if (ret == NULL)
 491         return NULL;
 492     
 493 #if defined _DEV_URANDOM && defined _SUN_SDK_
 494     {
 495         int fd = open(_DEV_URANDOM, O_RDONLY);
 496         int nread = 0;
 497 
 498         if (fd != -1) { 
 499                 nread = read(fd, ret, NONCE_SIZE); 
 500                 close(fd); 
 501         } 
 502         if (nread != NONCE_SIZE)
 503             utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
 504     }
 505 #else
 506     utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
 507 #endif /* _DEV_URANDOM && _SUN_SDK_ */
 508     
 509     /* base 64 encode it so it has valid chars */
 510     base64len = (NONCE_SIZE * 4 / 3) + (NONCE_SIZE % 3 ? 4 : 0);
 511     
 512     base64buf = (unsigned char *) utils->malloc(base64len + 1);
 513     if (base64buf == NULL) {
 514 #ifdef _SUN_SDK_
 515         utils->log(utils->conn, SASL_LOG_ERR,
 516                    "Unable to allocate final buffer");
 517 #else
 518         utils->seterror(utils->conn, 0, "Unable to allocate final buffer");
 519 #endif /* _SUN_SDK_ */
 520         return NULL;
 521     }
 522     
 523     /*
 524      * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
 525      */
 526     if (utils->encode64(ret, NONCE_SIZE,
 527                         (char *) base64buf, base64len, NULL) != SASL_OK) {
 528         utils->free(ret);
 529         return NULL;
 530     }
 531     utils->free(ret);
 532     
 533     return base64buf;
 534 }
 535 
 536 static int add_to_challenge(const sasl_utils_t *utils,
 537                             char **str, unsigned *buflen, unsigned *curlen,
 538                             char *name,
 539                             unsigned char *value,
 540                             bool need_quotes)
 541 {
 542     int             namesize = strlen(name);
 543     int             valuesize = strlen((char *) value);
 544     int             ret;
 545     
 546     ret = _plug_buf_alloc(utils, str, buflen,
 547                           *curlen + 1 + namesize + 2 + valuesize + 2);
 548     if(ret != SASL_OK) return ret;
 549     
 550     *curlen = *curlen + 1 + namesize + 2 + valuesize + 2;
 551     
 552     strcat(*str, ",");
 553     strcat(*str, name);
 554     
 555     if (need_quotes) {
 556         strcat(*str, "=\"");
 557         strcat(*str, (char *) value);   /* XXX. What about quoting??? */
 558         strcat(*str, "\"");
 559     } else {
 560         strcat(*str, "=");
 561         strcat(*str, (char *) value);
 562     }
 563     
 564     return SASL_OK;
 565 }
 566 
 567 static char *skip_lws (char *s)
 568 {
 569     if(!s) return NULL;
 570     
 571     /* skipping spaces: */
 572     while (s[0] == ' ' || s[0] == HT || s[0] == CR || s[0] == LF) {
 573         if (s[0]=='\0') break;
 574         s++;
 575     }  
 576     
 577     return s;
 578 }
 579 
 580 #ifdef __SUN_SDK_
 581 static char *skip_token (char *s, int caseinsensitive  __attribute__((unused)))
 582 #else
 583 static char *skip_token (char *s, int caseinsensitive)
 584 #endif /* _SUN_SDK_ */
 585 {
 586     if(!s) return NULL;
 587     
 588 #ifdef __SUN_SDK_
 589     while (((unsigned char *)s)[0]>SP) {
 590 #else
 591     while (s[0]>SP) {
 592 #endif /* _SUN_SDK_ */
 593         if (s[0]==DEL || s[0]=='(' || s[0]==')' || s[0]=='<' || s[0]=='>' ||
 594             s[0]=='@' || s[0]==',' || s[0]==';' || s[0]==':' || s[0]=='\\' ||
 595             s[0]=='\'' || s[0]=='/' || s[0]=='[' || s[0]==']' || s[0]== '?' ||
 596             s[0]=='=' || s[0]== '{' || s[0]== '}') {
 597 #ifdef __SUN_SDK_
 598             /* the above chars are never uppercase */
 599             break;
 600 #else
 601             if (caseinsensitive == 1) {
 602                 if (!isupper((unsigned char) s[0]))
 603                     break;
 604             } else {
 605                 break;
 606             }
 607 #endif /* _SUN_SDK_ */
 608         }
 609         s++;
 610     }  
 611     return s;
 612 }
 613 
 614 /* NULL - error (unbalanced quotes), 
 615    otherwise pointer to the first character after value */
 616 static char *unquote (char *qstr)
 617 {
 618     char *endvalue;
 619     int   escaped = 0;
 620     char *outptr;
 621     
 622     if(!qstr) return NULL;
 623     
 624     if (qstr[0] == '"') {
 625         qstr++;
 626         outptr = qstr;
 627         
 628         for (endvalue = qstr; endvalue[0] != '\0'; endvalue++, outptr++) {
 629             if (escaped) {
 630                 outptr[0] = endvalue[0];
 631                 escaped = 0;
 632             }
 633             else if (endvalue[0] == '\\') {
 634                 escaped = 1;
 635                 outptr--; /* Will be incremented at the end of the loop */
 636             }
 637             else if (endvalue[0] == '"') {
 638                 break;
 639             }      
 640             else {
 641                 outptr[0] = endvalue[0];      
 642             }
 643         }
 644         
 645         if (endvalue[0] != '"') {
 646             return NULL;
 647         }
 648         
 649         while (outptr <= endvalue) {
 650             outptr[0] = '\0';
 651             outptr++;
 652         }
 653         endvalue++;
 654     }
 655     else { /* not qouted value (token) */
 656         endvalue = skip_token(qstr,0);
 657     };
 658     
 659     return endvalue;  
 660 } 
 661 
 662 static void get_pair(char **in, char **name, char **value)
 663 {
 664     char  *endpair;
 665     /* int    inQuotes; */
 666     char  *curp = *in;
 667     *name = NULL;
 668     *value = NULL;
 669     
 670     if (curp == NULL) return;
 671     if (curp[0] == '\0') return;
 672     
 673     /* skipping spaces: */
 674     curp = skip_lws(curp);
 675     
 676     *name = curp;
 677     
 678     curp = skip_token(curp,1);
 679     
 680     /* strip wierd chars */
 681     if (curp[0] != '=' && curp[0] != '\0') {
 682         *curp++ = '\0';
 683     };
 684     
 685     curp = skip_lws(curp);
 686     
 687     if (curp[0] != '=') { /* No '=' sign */ 
 688         *name = NULL;
 689         return;
 690     }
 691     
 692     curp[0] = '\0';
 693     curp++;
 694     
 695     curp = skip_lws(curp);  
 696     
 697     *value = (curp[0] == '"') ? curp+1 : curp;
 698     
 699     endpair = unquote (curp);
 700     if (endpair == NULL) { /* Unbalanced quotes */ 
 701         *name = NULL;
 702         return;
 703     }
 704     if (endpair[0] != ',') {
 705         if (endpair[0]!='\0') {
 706             *endpair++ = '\0'; 
 707         }
 708     }
 709     
 710     endpair = skip_lws(endpair);
 711     
 712     /* syntax check: MUST be '\0' or ',' */  
 713     if (endpair[0] == ',') {
 714         endpair[0] = '\0';
 715         endpair++; /* skipping <,> */
 716     } else if (endpair[0] != '\0') { 
 717         *name = NULL;
 718         return;
 719     }
 720     
 721     *in = endpair;
 722 }
 723 
 724 /* EXPORT DELETE START */
 725 #ifdef WITH_DES
 726 struct des_context_s {
 727     des_key_schedule keysched;  /* key schedule for des initialization */
 728     des_cblock ivec;            /* initial vector for encoding */
 729     des_key_schedule keysched2; /* key schedule for 3des initialization */
 730 };
 731 
 732 typedef struct des_context_s des_context_t;
 733 
 734 /* slide the first 7 bytes of 'inbuf' into the high seven bits of the
 735    first 8 bytes of 'keybuf'. 'keybuf' better be 8 bytes long or longer. */
 736 static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
 737 {
 738     keybuf[0] = inbuf[0];
 739     keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
 740     keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
 741     keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
 742     keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
 743     keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
 744     keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
 745     keybuf[7] = (inbuf[6]<<1);
 746 }
 747 
 748 /******************************
 749  *
 750  * 3DES functions
 751  *
 752  *****************************/
 753 
 754 static int dec_3des(context_t *text,
 755                     const char *input,
 756                     unsigned inputlen,
 757                     unsigned char digest[16],
 758                     char *output,
 759                     unsigned *outputlen)
 760 {
 761     des_context_t *c = (des_context_t *) text->cipher_dec_context;
 762     int padding, p;
 763     
 764     des_ede2_cbc_encrypt((void *) input,
 765                          (void *) output,
 766                          inputlen,
 767                          c->keysched,
 768                          c->keysched2,
 769                          &c->ivec,
 770                          DES_DECRYPT);
 771     
 772     /* now chop off the padding */
 773     padding = output[inputlen - 11];
 774     if (padding < 1 || padding > 8) {
 775         /* invalid padding length */
 776         return SASL_FAIL;
 777     }
 778     /* verify all padding is correct */
 779     for (p = 1; p <= padding; p++) {
 780         if (output[inputlen - 10 - p] != padding) {
 781             return SASL_FAIL;
 782         }
 783     }
 784     
 785     /* chop off the padding */
 786     *outputlen = inputlen - padding - 10;
 787     
 788     /* copy in the HMAC to digest */
 789     memcpy(digest, output + inputlen - 10, 10);
 790     
 791     return SASL_OK;
 792 }
 793 
 794 static int enc_3des(context_t *text,
 795                     const char *input,
 796                     unsigned inputlen,
 797                     unsigned char digest[16],
 798                     char *output,
 799                     unsigned *outputlen)
 800 {
 801     des_context_t *c = (des_context_t *) text->cipher_enc_context;
 802     int len;
 803     int paddinglen;
 804     
 805     /* determine padding length */
 806     paddinglen = 8 - ((inputlen + 10) % 8);
 807     
 808     /* now construct the full stuff to be ciphered */
 809     memcpy(output, input, inputlen);                /* text */
 810     memset(output+inputlen, paddinglen, paddinglen);/* pad  */
 811     memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
 812     
 813     len=inputlen+paddinglen+10;
 814     
 815     des_ede2_cbc_encrypt((void *) output,
 816                          (void *) output,
 817                          len,
 818                          c->keysched,
 819                          c->keysched2,
 820                          &c->ivec,
 821                          DES_ENCRYPT);
 822     
 823     *outputlen=len;
 824     
 825     return SASL_OK;
 826 }
 827 
 828 static int init_3des(context_t *text, 
 829                      unsigned char enckey[16],
 830                      unsigned char deckey[16])
 831 {
 832     des_context_t *c;
 833     unsigned char keybuf[8];
 834 
 835     /* allocate enc & dec context */
 836     c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
 837     if (c == NULL) return SASL_NOMEM;
 838 
 839     /* setup enc context */
 840     slidebits(keybuf, enckey);
 841     if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
 842         return SASL_FAIL;
 843 
 844     slidebits(keybuf, enckey + 7);
 845     if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
 846         return SASL_FAIL;
 847     memcpy(c->ivec, ((char *) enckey) + 8, 8);
 848 
 849     text->cipher_enc_context = (cipher_context_t *) c;
 850 
 851     /* setup dec context */
 852     c++;
 853     slidebits(keybuf, deckey);
 854     if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
 855         return SASL_FAIL;
 856     
 857     slidebits(keybuf, deckey + 7);
 858     if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
 859         return SASL_FAIL;
 860     
 861     memcpy(c->ivec, ((char *) deckey) + 8, 8);
 862 
 863     text->cipher_dec_context = (cipher_context_t *) c;
 864     
 865     return SASL_OK;
 866 }
 867 
 868 
 869 /******************************
 870  *
 871  * DES functions
 872  *
 873  *****************************/
 874 
 875 static int dec_des(context_t *text, 
 876                    const char *input,
 877                    unsigned inputlen,
 878                    unsigned char digest[16],
 879                    char *output,
 880                    unsigned *outputlen)
 881 {
 882     des_context_t *c = (des_context_t *) text->cipher_dec_context;
 883     int p, padding = 0;
 884     
 885     des_cbc_encrypt((void *) input,
 886                     (void *) output,
 887                     inputlen,
 888                     c->keysched,
 889                     &c->ivec,
 890                     DES_DECRYPT);
 891 
 892     /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
 893        this way) */
 894     memcpy(c->ivec, input + (inputlen - 8), 8);
 895     
 896     /* now chop off the padding */
 897     padding = output[inputlen - 11];
 898     if (padding < 1 || padding > 8) {
 899         /* invalid padding length */
 900         return SASL_FAIL;
 901     }
 902     /* verify all padding is correct */
 903     for (p = 1; p <= padding; p++) {
 904         if (output[inputlen - 10 - p] != padding) {
 905             return SASL_FAIL;
 906         }
 907     }
 908     
 909     /* chop off the padding */
 910     *outputlen = inputlen - padding - 10;
 911     
 912     /* copy in the HMAC to digest */
 913     memcpy(digest, output + inputlen - 10, 10);
 914     
 915     return SASL_OK;
 916 }
 917 
 918 static int enc_des(context_t *text,
 919                    const char *input,
 920                    unsigned inputlen,
 921                    unsigned char digest[16],
 922                    char *output,
 923                    unsigned *outputlen)
 924 {
 925     des_context_t *c = (des_context_t *) text->cipher_enc_context;
 926     int len;
 927     int paddinglen;
 928   
 929     /* determine padding length */
 930     paddinglen = 8 - ((inputlen+10) % 8);
 931 
 932     /* now construct the full stuff to be ciphered */
 933     memcpy(output, input, inputlen);                /* text */
 934     memset(output+inputlen, paddinglen, paddinglen);/* pad  */
 935     memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
 936     
 937     len = inputlen + paddinglen + 10;
 938     
 939     des_cbc_encrypt((void *) output,
 940                     (void *) output,
 941                     len,
 942                     c->keysched,
 943                     &c->ivec,
 944                     DES_ENCRYPT);
 945     
 946     /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
 947        this way) */
 948     memcpy(c->ivec, output + (len - 8), 8);
 949     
 950     *outputlen = len;
 951     
 952     return SASL_OK;
 953 }
 954 
 955 static int init_des(context_t *text,
 956                     unsigned char enckey[16],
 957                     unsigned char deckey[16])
 958 {
 959     des_context_t *c;
 960     unsigned char keybuf[8];
 961 
 962     /* allocate enc context */
 963     c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
 964     if (c == NULL) return SASL_NOMEM;
 965     
 966     /* setup enc context */
 967     slidebits(keybuf, enckey);
 968     des_key_sched((des_cblock *) keybuf, c->keysched);
 969 
 970     memcpy(c->ivec, ((char *) enckey) + 8, 8);
 971     
 972     text->cipher_enc_context = (cipher_context_t *) c;
 973 
 974     /* setup dec context */
 975     c++;
 976     slidebits(keybuf, deckey);
 977     des_key_sched((des_cblock *) keybuf, c->keysched);
 978 
 979     memcpy(c->ivec, ((char *) deckey) + 8, 8);
 980     
 981     text->cipher_dec_context = (cipher_context_t *) c;
 982 
 983     return SASL_OK;
 984 }
 985 
 986 static void free_des(context_t *text)
 987 {
 988     /* free des contextss. only cipher_enc_context needs to be free'd,
 989        since cipher_dec_context was allocated at the same time. */
 990     if (text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
 991 }
 992 
 993 #endif /* WITH_DES */
 994 
 995 #ifdef WITH_RC4
 996 /* quick generic implementation of RC4 */
 997 struct rc4_context_s {
 998     unsigned char sbox[256];
 999     int i, j;
1000 };
1001 
1002 typedef struct rc4_context_s rc4_context_t;
1003 
1004 static void rc4_init(rc4_context_t *text,
1005                      const unsigned char *key,
1006                      unsigned keylen)
1007 {
1008     int i, j;
1009     
1010     /* fill in linearly s0=0 s1=1... */
1011     for (i=0;i<256;i++)
1012         text->sbox[i]=i;
1013     
1014     j=0;
1015     for (i = 0; i < 256; i++) {
1016         unsigned char tmp;
1017         /* j = (j + Si + Ki) mod 256 */
1018         j = (j + text->sbox[i] + key[i % keylen]) % 256;
1019         
1020         /* swap Si and Sj */
1021         tmp = text->sbox[i];
1022         text->sbox[i] = text->sbox[j];
1023         text->sbox[j] = tmp;
1024     }
1025     
1026     /* counters initialized to 0 */
1027     text->i = 0;
1028     text->j = 0;
1029 }
1030 
1031 static void rc4_encrypt(rc4_context_t *text,
1032                         const char *input,
1033                         char *output,
1034                         unsigned len)
1035 {
1036     int tmp;
1037     int i = text->i;
1038     int j = text->j;
1039     int t;
1040     int K;
1041     const char *input_end = input + len;
1042     
1043     while (input < input_end) {
1044         i = (i + 1) % 256;
1045         
1046         j = (j + text->sbox[i]) % 256;
1047         
1048         /* swap Si and Sj */
1049         tmp = text->sbox[i];
1050         text->sbox[i] = text->sbox[j];
1051         text->sbox[j] = tmp;
1052         
1053         t = (text->sbox[i] + text->sbox[j]) % 256;
1054         
1055         K = text->sbox[t];
1056         
1057         /* byte K is Xor'ed with plaintext */
1058         *output++ = *input++ ^ K;
1059     }
1060     
1061     text->i = i;
1062     text->j = j;
1063 }
1064 
1065 static void rc4_decrypt(rc4_context_t *text,
1066                         const char *input,
1067                         char *output,
1068                         unsigned len)
1069 {
1070     int tmp;
1071     int i = text->i;
1072     int j = text->j;
1073     int t;
1074     int K;
1075     const char *input_end = input + len;
1076     
1077     while (input < input_end) {
1078         i = (i + 1) % 256;
1079         
1080         j = (j + text->sbox[i]) % 256;
1081         
1082         /* swap Si and Sj */
1083         tmp = text->sbox[i];
1084         text->sbox[i] = text->sbox[j];
1085         text->sbox[j] = tmp;
1086         
1087         t = (text->sbox[i] + text->sbox[j]) % 256;
1088         
1089         K = text->sbox[t];
1090         
1091         /* byte K is Xor'ed with plaintext */
1092         *output++ = *input++ ^ K;
1093     }
1094     
1095     text->i = i;
1096     text->j = j;
1097 }
1098 
1099 static void free_rc4(context_t *text)
1100 {
1101     /* free rc4 context structures */
1102 
1103     if(text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
1104     if(text->cipher_dec_context) text->utils->free(text->cipher_dec_context);
1105 #ifdef _SUN_SDK_
1106     text->cipher_enc_context = NULL;
1107     text->cipher_dec_context = NULL;
1108 #endif /* _SUN_SDK_ */
1109 }
1110 
1111 static int init_rc4(context_t *text, 
1112 #ifdef _SUN_SDK_
1113                     char enckey[16],
1114                     char deckey[16])
1115 #else
1116                     unsigned char enckey[16],
1117                     unsigned char deckey[16])
1118 #endif /* _SUN_SDK_ */
1119 {
1120     /* allocate rc4 context structures */
1121     text->cipher_enc_context=
1122         (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
1123     if (text->cipher_enc_context == NULL) return SASL_NOMEM;
1124     
1125     text->cipher_dec_context=
1126         (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
1127 #ifdef _SUN_SDK_
1128     if (text->cipher_dec_context == NULL) {
1129         text->utils->free(text->cipher_enc_context);
1130         text->cipher_enc_context = NULL;
1131         return SASL_NOMEM;
1132     }
1133 #else
1134     if (text->cipher_dec_context == NULL) return SASL_NOMEM;
1135 #endif /* _SUN_SDK_ */
1136     
1137     /* initialize them */
1138     rc4_init((rc4_context_t *) text->cipher_enc_context,
1139              (const unsigned char *) enckey, 16);
1140     rc4_init((rc4_context_t *) text->cipher_dec_context,
1141              (const unsigned char *) deckey, 16);
1142     
1143     return SASL_OK;
1144 }
1145 
1146 static int dec_rc4(context_t *text,
1147                    const char *input,
1148                    unsigned inputlen,
1149                    unsigned char digest[16],
1150                    char *output,
1151                    unsigned *outputlen)
1152 {
1153     /* decrypt the text part */
1154     rc4_decrypt((rc4_context_t *) text->cipher_dec_context, 
1155                 input, output, inputlen-10);
1156     
1157     /* decrypt the HMAC part */
1158     rc4_decrypt((rc4_context_t *) text->cipher_dec_context, 
1159                 input+(inputlen-10), (char *) digest, 10);
1160     
1161     /* no padding so we just subtract the HMAC to get the text length */
1162     *outputlen = inputlen - 10;
1163     
1164     return SASL_OK;
1165 }
1166 
1167 static int enc_rc4(context_t *text,
1168                    const char *input,
1169                    unsigned inputlen,
1170                    unsigned char digest[16],
1171                    char *output,
1172                    unsigned *outputlen)
1173 {
1174     /* pad is zero */
1175     *outputlen = inputlen+10;
1176     
1177     /* encrypt the text part */
1178     rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
1179                 input,
1180                 output,
1181                 inputlen);
1182     
1183     /* encrypt the HMAC part */
1184     rc4_encrypt((rc4_context_t *) text->cipher_enc_context, 
1185                 (const char *) digest, 
1186                 (output)+inputlen, 10);
1187     
1188     return SASL_OK;
1189 }
1190 
1191 #endif /* WITH_RC4 */
1192 /* EXPORT DELETE END */
1193 
1194 struct digest_cipher available_ciphers[] =
1195 {
1196     /* EXPORT DELETE START */
1197 #ifdef WITH_RC4
1198     { "rc4-40", 40, 5, 0x01, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
1199     { "rc4-56", 56, 7, 0x02, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
1200     { "rc4", 128, 16, 0x04, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
1201 #endif
1202 #ifdef WITH_DES
1203     { "des", 55, 16, 0x08, &enc_des, &dec_des, &init_des, &free_des },
1204     { "3des", 112, 16, 0x10, &enc_3des, &dec_3des, &init_3des, &free_des },
1205 #endif
1206     /* EXPORT DELETE END */
1207     { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
1208 };
1209 
1210 
1211 #ifdef USE_UEF
1212 DEFINE_STATIC_MUTEX(uef_init_mutex);
1213 #define DES_CIPHER_INDEX        3
1214 #define DES3_CIPHER_INDEX       4
1215 
1216 static int got_uef_slot = FALSE;
1217 static sasl_ssf_t uef_max_ssf = 0;
1218 static CK_SLOT_ID rc4_slot_id;
1219 static CK_SLOT_ID des_slot_id;
1220 static CK_SLOT_ID des3_slot_id;
1221 
1222 struct uef_context_s {
1223     CK_SESSION_HANDLE hSession;
1224     CK_OBJECT_HANDLE hKey;
1225 };
1226 
1227 typedef struct uef_context_s uef_context_t;
1228 
1229 /*
1230  * slide the first 7 bytes of 'inbuf' into the high seven bits of the
1231  * first 8 bytes of 'keybuf'. 'inbuf' better be 8 bytes long or longer.
1232  *
1233  * This is used to compute the IV for "des" and "3des" as described in
1234  * draft-ietf-sasl-rfc2831bis-00.txt - The IV for "des"
1235  *  and "3des" is the last 8 bytes of Kcc or Kcs - the encryption keys.
1236  */
1237 
1238 static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
1239 {
1240     keybuf[0] = inbuf[0];
1241     keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
1242     keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
1243     keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
1244     keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
1245     keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
1246     keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
1247     keybuf[7] = (inbuf[6]<<1);
1248 }
1249 
1250 /*
1251  * Create encryption and decryption session handle handles for later use.
1252  * Returns SASL_OK on success - any other return indicates failure.
1253  * 
1254  * free_uef is called to release associated resources by
1255  *      digestmd5_common_mech_dispose
1256  */
1257 
1258 static int init_uef(context_t *text, 
1259                     CK_KEY_TYPE keyType,
1260                     CK_MECHANISM_TYPE mech_type,
1261                     CK_SLOT_ID slot_id,
1262                     char enckey[16],
1263                     char deckey[16])
1264 {
1265     CK_RV               rv;
1266     uef_context_t       *enc_context;
1267     uef_context_t       *dec_context;
1268     CK_OBJECT_CLASS     class = CKO_SECRET_KEY;
1269     CK_BBOOL            true = TRUE;
1270     static CK_MECHANISM mechanism = {CKM_RC4, NULL, 0};
1271     unsigned char       keybuf[24];
1272     CK_ATTRIBUTE        template[] = {
1273                                 {CKA_CLASS, NULL, sizeof (class)},
1274                                 {CKA_KEY_TYPE, NULL, sizeof (keyType)},
1275                                 {CKA_ENCRYPT, NULL, sizeof (true)},
1276                                 {CKA_VALUE, NULL, 16}};
1277 
1278     template[0].pValue = &class;
1279     template[1].pValue = &keyType;
1280     template[2].pValue = &true;
1281     if (keyType == CKK_DES || keyType == CKK_DES3) {
1282         slidebits(keybuf, (unsigned char *)enckey);
1283         if (keyType == CKK_DES3) {
1284             slidebits(keybuf + 8, (unsigned char *)enckey + 7);
1285             (void) memcpy(keybuf + 16, keybuf, 8);
1286             template[3].ulValueLen = 24;
1287         } else {
1288             template[3].ulValueLen = 8;
1289         }
1290         template[3].pValue = keybuf;
1291         mechanism.pParameter = enckey + 8;
1292         mechanism.ulParameterLen = 8;
1293     } else {
1294         template[3].pValue = enckey;
1295     }
1296     mechanism.mechanism = mech_type;
1297 
1298     /* allocate rc4 context structures */
1299     enc_context = text->utils->malloc(sizeof (uef_context_t));
1300     if (enc_context == NULL)
1301         return SASL_NOMEM;
1302     
1303     rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
1304                 &enc_context->hSession);
1305     if (rv != CKR_OK) {
1306         text->utils->free(enc_context);
1307 #ifdef DEBUG
1308         text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1309                 "enc C_OpenSession Failed:0x%.8X\n", rv);
1310 #endif
1311         return SASL_FAIL;
1312     }
1313 
1314     rv = C_CreateObject(enc_context->hSession, template,
1315                 sizeof (template)/sizeof (template[0]), &enc_context->hKey);
1316     if (rv != CKR_OK) {
1317         text->utils->free(enc_context);
1318         (void) C_CloseSession(enc_context->hSession);
1319 #ifdef DEBUG
1320         text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1321                          "enc C_CreateObject: rv = 0x%.8X\n", rv);
1322 #endif
1323         return SASL_FAIL;
1324     }
1325 
1326     text->cipher_enc_context = (cipher_context_t *)enc_context;
1327 
1328     /* Initialize the encryption operation in the session */
1329     rv = C_EncryptInit(enc_context->hSession, &mechanism, enc_context->hKey);
1330     if (rv != CKR_OK) {
1331 #ifdef DEBUG
1332         text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1333                          "C_EncryptInit: rv = 0x%.8X\n", rv);
1334 #endif
1335         return SASL_FAIL;
1336     }
1337 
1338     dec_context = text->utils->malloc(sizeof(uef_context_t));
1339     if (dec_context == NULL)
1340         return SASL_NOMEM;
1341 
1342     rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
1343                 &dec_context->hSession);
1344     if (rv != CKR_OK) {
1345 #ifdef DEBUG
1346         text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1347                 "dec C_OpenSession Failed:0x%.8X\n", rv);
1348 #endif
1349         text->utils->free(dec_context);
1350         return SASL_FAIL;
1351     }
1352 
1353     template[2].type = CKA_DECRYPT;
1354     if (keyType == CKK_DES || keyType == CKK_DES3) {
1355         slidebits(keybuf, (unsigned char *)deckey);
1356         if (keyType == CKK_DES3) {
1357             slidebits(keybuf + 8, (unsigned char *)deckey + 7);
1358             (void) memcpy(keybuf + 16, keybuf, 8);
1359         }
1360         mechanism.pParameter = deckey + 8;
1361     } else {
1362         template[3].pValue = deckey;
1363     }
1364 
1365     rv = C_CreateObject(dec_context->hSession, template,
1366                 sizeof (template)/sizeof (template[0]), &dec_context->hKey);
1367     if (rv != CKR_OK) {
1368 #ifdef DEBUG
1369         text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1370                 "dec C_CreateObject: rv = 0x%.8X\n", rv);
1371 #endif
1372         (void) C_CloseSession(dec_context->hSession);
1373         text->utils->free(dec_context);
1374         return SASL_FAIL;
1375     }
1376     text->cipher_dec_context = (cipher_context_t *)dec_context;
1377 
1378     /* Initialize the decryption operation in the session */
1379     rv = C_DecryptInit(dec_context->hSession, &mechanism, dec_context->hKey);
1380     if (rv != CKR_OK) {
1381 #ifdef DEBUG
1382         text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1383                          "C_DecryptInit: rv = 0x%.8X\n", rv);
1384 #endif
1385         return SASL_FAIL;
1386     }
1387 
1388     return SASL_OK;
1389 }
1390 
1391 static int init_rc4_uef(context_t *text, 
1392                     char enckey[16],
1393                     char deckey[16])
1394 {
1395     return init_uef(text, CKK_RC4, CKM_RC4, rc4_slot_id, enckey, deckey);
1396 }
1397 
1398 static int init_des_uef(context_t *text, 
1399                     char enckey[16],
1400                     char deckey[16])
1401 {
1402     return init_uef(text, CKK_DES, CKM_DES_CBC, des_slot_id, enckey, deckey);
1403 }
1404 
1405 static int init_3des_uef(context_t *text, 
1406                     char enckey[16],
1407                     char deckey[16])
1408 {
1409     return init_uef(text, CKK_DES3, CKM_DES3_CBC, des3_slot_id, enckey, deckey);
1410 }
1411 
1412 static void
1413 free_uef(context_t *text)
1414 {
1415     uef_context_t       *enc_context =
1416                 (uef_context_t *)text->cipher_enc_context;
1417     uef_context_t       *dec_context =
1418                 (uef_context_t *)text->cipher_dec_context;
1419     CK_RV               rv;
1420     unsigned char       buf[1];
1421     CK_ULONG            ulLen = 0;
1422     
1423 
1424     if (enc_context != NULL) {
1425         rv = C_EncryptFinal(enc_context->hSession, buf, &ulLen);
1426         if (rv != CKR_OK) {
1427 #ifdef DEBUG
1428             text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1429                              "C_EncryptFinal failed:0x%.8X\n", rv);
1430 #endif
1431         }
1432         rv = C_DestroyObject(enc_context->hSession, enc_context->hKey);
1433         if (rv != CKR_OK) {
1434 #ifdef DEBUG
1435             text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1436                              "C_DestroyObject failed:0x%.8X\n", rv);
1437 #endif
1438         }
1439         rv = C_CloseSession(enc_context->hSession);
1440         if (rv != CKR_OK) {
1441 #ifdef DEBUG
1442             text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1443                              "C_CloseSession failed:0x%.8X\n", rv);
1444 #endif
1445         }
1446         text->utils->free(enc_context);
1447     }
1448     if (dec_context != NULL) {
1449         rv = C_DecryptFinal(dec_context->hSession, buf, &ulLen);
1450         if (rv != CKR_OK) {
1451 #ifdef DEBUG
1452             text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1453                              "C_DecryptFinal failed:0x%.8X\n", rv);
1454 #endif
1455         }
1456         rv = C_DestroyObject(dec_context->hSession, dec_context->hKey);
1457         if (rv != CKR_OK) {
1458 #ifdef DEBUG
1459             text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1460                              "C_DestroyObject failed:0x%.8X\n", rv);
1461 #endif
1462         }
1463 
1464         rv = C_CloseSession(dec_context->hSession);
1465         if (rv != CKR_OK) {
1466 #ifdef DEBUG
1467             text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1468                              "C_CloseSession failed:0x%.8X\n", rv);
1469 #endif
1470         }
1471         text->utils->free(dec_context);
1472     }
1473     text->cipher_enc_context = NULL;
1474     text->cipher_dec_context = NULL;
1475 }
1476 
1477 static int
1478 dec_rc4_uef(context_t *text,
1479             const char *input,
1480             unsigned inputlen,
1481             unsigned char digest[16],
1482             char *output,
1483             unsigned *outputlen)
1484 {
1485     CK_RV               rv;
1486     uef_context_t       *dec_context =
1487                 (uef_context_t *)text->cipher_dec_context;
1488     CK_ULONG            ulDataLen = *outputlen - MAC_SIZE;
1489     CK_ULONG            ulDigestLen = MAC_SIZE;
1490 
1491     rv = C_DecryptUpdate(dec_context->hSession, (CK_BYTE_PTR)input,
1492         inputlen - MAC_SIZE, (CK_BYTE_PTR)output, &ulDataLen);
1493     if (rv != CKR_OK) {
1494 #ifdef DEBUG
1495         text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1496                          "C_DecryptUpdate failed:0x%.8X\n", rv);
1497 #endif
1498         return SASL_FAIL;
1499     }
1500     *outputlen = (unsigned)ulDataLen;
1501 
1502     rv = C_DecryptUpdate(dec_context->hSession,
1503         (CK_BYTE_PTR)input+(inputlen-MAC_SIZE), MAC_SIZE, (CK_BYTE_PTR)digest,
1504         &ulDigestLen);
1505     if (rv != CKR_OK || ulDigestLen != MAC_SIZE) {
1506 #ifdef DEBUG
1507         text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1508                          "C_DecryptUpdate:0x%.8X, digestLen:%d\n",
1509                          rv, ulDigestLen);
1510 #endif
1511         return SASL_FAIL;
1512     }
1513 
1514     return SASL_OK;
1515 }
1516 
1517 static int
1518 enc_rc4_uef(context_t *text,
1519             const char *input,
1520             unsigned inputlen,
1521             unsigned char digest[16],
1522             char *output,
1523             unsigned *outputlen)
1524 {
1525     CK_RV               rv;
1526     uef_context_t       *enc_context =
1527                 (uef_context_t *)text->cipher_enc_context;
1528     CK_ULONG            ulDataLen = inputlen;
1529     CK_ULONG            ulDigestLen = MAC_SIZE;
1530 
1531     rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)input, inputlen,
1532         (CK_BYTE_PTR)output, &ulDataLen);
1533     if (rv != CKR_OK) {
1534 #ifdef DEBUG
1535         text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1536                          "C_EncryptUpdate failed: 0x%.8X "
1537                           "inputlen:%d outputlen:%d\n",
1538                           rv, inputlen, ulDataLen);
1539 #endif
1540         return SASL_FAIL;
1541     }
1542     rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)digest, MAC_SIZE,
1543         (CK_BYTE_PTR)output + inputlen, &ulDigestLen);
1544     if (rv != CKR_OK) {
1545 #ifdef DEBUG
1546         text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1547                          "C_EncryptUpdate failed: 0x%.8X ulDigestLen:%d\n",
1548                          rv, ulDigestLen);
1549 #endif
1550         return SASL_FAIL;
1551     }
1552 
1553     *outputlen = ulDataLen + ulDigestLen;
1554 
1555     return SASL_OK;
1556 }
1557 
1558 static int
1559 dec_des_uef(context_t *text,
1560             const char *input,
1561             unsigned inputlen,
1562             unsigned char digest[16],
1563             char *output,
1564             unsigned *outputlen)
1565 {
1566     CK_RV               rv;
1567     uef_context_t       *dec_context =
1568                 (uef_context_t *)text->cipher_dec_context;
1569     CK_ULONG            ulDataLen = inputlen;
1570     int                 padding, p;
1571 
1572     rv = C_DecryptUpdate(dec_context->hSession, (CK_BYTE_PTR)input,
1573         inputlen, (CK_BYTE_PTR)output, &ulDataLen);
1574     if (rv != CKR_OK) {
1575 #ifdef DEBUG
1576         text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1577                          "C_DecryptUpdate failed:0x%.8X\n", rv);
1578 #endif
1579         return SASL_FAIL;
1580     }
1581     if (ulDataLen != inputlen) {
1582 #ifdef DEBUG
1583         text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1584                          "C_DecryptUpdate unexpected data len:%d !=%d\n",
1585                          inputlen, ulDataLen);
1586 #endif
1587         return SASL_BUFOVER;
1588     }
1589 
1590     /* now chop off the padding */
1591     padding = output[inputlen - 11];
1592     if (padding < 1 || padding > 8) {
1593         /* invalid padding length */
1594         return SASL_BADMAC;
1595     }
1596     /* verify all padding is correct */
1597     for (p = 1; p <= padding; p++) {
1598         if (output[inputlen - MAC_SIZE - p] != padding) {
1599             return SASL_BADMAC;
1600         }
1601     }
1602 
1603     /* chop off the padding */
1604     *outputlen = inputlen - padding - MAC_SIZE;
1605 
1606     /* copy in the HMAC to digest */
1607     memcpy(digest, output + inputlen - MAC_SIZE, MAC_SIZE);
1608 
1609     return SASL_OK;
1610 }
1611 
1612 static int
1613 enc_des_uef(context_t *text,
1614             const char *input,
1615             unsigned inputlen,
1616             unsigned char digest[16],
1617             char *output,
1618             unsigned *outputlen)
1619 {
1620     CK_RV               rv;
1621     uef_context_t       *enc_context =
1622                 (uef_context_t *)text->cipher_enc_context;
1623     CK_ULONG            ulDataLen;
1624     int paddinglen;
1625 
1626     /* determine padding length */
1627     paddinglen = 8 - ((inputlen + MAC_SIZE) % 8);
1628 
1629     /* now construct the full stuff to be ciphered */
1630     memcpy(output, input, inputlen);                /* text */
1631     memset(output+inputlen, paddinglen, paddinglen);/* pad  */
1632     memcpy(output+inputlen+paddinglen, digest, MAC_SIZE); /* hmac */
1633 
1634     ulDataLen=inputlen+paddinglen+MAC_SIZE;
1635 
1636     rv = C_EncryptUpdate(enc_context->hSession, (CK_BYTE_PTR)output, ulDataLen,
1637         (CK_BYTE_PTR)output, &ulDataLen);
1638     if (rv != CKR_OK) {
1639 #ifdef DEBUG
1640         text->utils->log(text->utils->conn, SASL_LOG_DEBUG,
1641                          "C_EncryptUpdate failed: 0x%.8X "
1642                          "inputlen:%d outputlen:%d\n",
1643                          rv, ulDataLen, ulDataLen);
1644 #endif
1645         return SASL_FAIL;
1646     }
1647     *outputlen = (unsigned)ulDataLen;
1648 
1649     return SASL_OK;
1650 }
1651 
1652 struct digest_cipher uef_ciphers[] =
1653 {
1654     { "rc4-40", 40, 5, 0x01, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
1655         &free_uef },
1656     { "rc4-56", 56, 7, 0x02, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
1657         &free_uef },
1658     { "rc4", 128, 16, 0x04, &enc_rc4_uef, &dec_rc4_uef, &init_rc4_uef,
1659         &free_uef },
1660     { "des", 55, 16, 0x08, &enc_des_uef, &dec_des_uef, &init_des_uef,
1661         &free_uef },
1662     { "3des", 112, 16, 0x10, &enc_des_uef, &dec_des_uef, &init_3des_uef,
1663         &free_uef },
1664     { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
1665 };
1666 
1667 struct digest_cipher *available_ciphers1 = uef_ciphers;
1668 #endif /* USE_UEF */
1669 
1670 static int create_layer_keys(context_t *text,
1671                              const sasl_utils_t *utils,
1672                              HASH key, int keylen,
1673                              char enckey[16], char deckey[16])
1674 {
1675     MD5_CTX Md5Ctx;
1676     
1677     utils->MD5Init(&Md5Ctx);
1678     utils->MD5Update(&Md5Ctx, key, keylen);
1679     if (text->i_am == SERVER) {
1680         utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_SERVER_CLIENT, 
1681                          strlen(SEALING_SERVER_CLIENT));
1682     } else {
1683         utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_CLIENT_SERVER,
1684                          strlen(SEALING_CLIENT_SERVER));
1685     }
1686     utils->MD5Final((unsigned char *) enckey, &Md5Ctx);
1687     
1688     utils->MD5Init(&Md5Ctx);
1689     utils->MD5Update(&Md5Ctx, key, keylen);
1690     if (text->i_am != SERVER) {
1691         utils->MD5Update(&Md5Ctx, (const unsigned char *)SEALING_SERVER_CLIENT, 
1692                          strlen(SEALING_SERVER_CLIENT));
1693     } else {
1694         utils->MD5Update(&Md5Ctx, (const unsigned char *)SEALING_CLIENT_SERVER,
1695                          strlen(SEALING_CLIENT_SERVER));
1696     }
1697     utils->MD5Final((unsigned char *) deckey, &Md5Ctx);
1698     
1699     /* create integrity keys */
1700     /* sending */
1701     utils->MD5Init(&Md5Ctx);
1702     utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
1703     if (text->i_am == SERVER) {
1704         utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT, 
1705                          strlen(SIGNING_SERVER_CLIENT));
1706     } else {
1707         utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
1708                          strlen(SIGNING_CLIENT_SERVER));
1709     }
1710     utils->MD5Final(text->Ki_send, &Md5Ctx);
1711     
1712     /* receiving */
1713     utils->MD5Init(&Md5Ctx);
1714     utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
1715     if (text->i_am != SERVER) {
1716         utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT, 
1717                          strlen(SIGNING_SERVER_CLIENT));
1718     } else {
1719         utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
1720                          strlen(SIGNING_CLIENT_SERVER));
1721     }
1722     utils->MD5Final(text->Ki_receive, &Md5Ctx);
1723     
1724     return SASL_OK;
1725 }
1726 
1727 static const unsigned short version = 1;
1728 
1729 /* len, CIPHER(Kc, {msg, pag, HMAC(ki, {SeqNum, msg})[0..9]}), x0001, SeqNum */
1730 
1731 static int
1732 digestmd5_privacy_encode(void *context,
1733                          const struct iovec *invec,
1734                          unsigned numiov,
1735                          const char **output,
1736                          unsigned *outputlen)
1737 {
1738     context_t *text = (context_t *) context;
1739     int tmp;
1740     unsigned int tmpnum;
1741     unsigned short int tmpshort;
1742     int ret;
1743     char *out;
1744     unsigned char digest[16];
1745     struct buffer_info *inblob, bufinfo;
1746     
1747     if(!context || !invec || !numiov || !output || !outputlen) {
1748         PARAMERROR(text->utils);
1749         return SASL_BADPARAM;
1750     }
1751     
1752     if (numiov > 1) {
1753         ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
1754         if (ret != SASL_OK) return ret;
1755         inblob = text->enc_in_buf;
1756     } else {
1757         /* avoid the data copy */
1758         bufinfo.data = invec[0].iov_base;
1759         bufinfo.curlen = invec[0].iov_len;
1760         inblob = &bufinfo;
1761     }
1762     
1763     /* make sure the output buffer is big enough for this blob */
1764     ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
1765                           &(text->encode_buf_len),
1766                           (4 +                        /* for length */
1767                            inblob->curlen + /* for content */
1768                            10 +                       /* for MAC */
1769                            8 +                        /* maximum pad */
1770                            6 +                        /* for padding */
1771                            1));                       /* trailing null */
1772     if(ret != SASL_OK) return ret;
1773     
1774     /* skip by the length for now */
1775     out = (text->encode_buf)+4;
1776     
1777     /* construct (seqnum, msg) */
1778     /* We can just use the output buffer because it's big enough */
1779     tmpnum = htonl(text->seqnum);
1780     memcpy(text->encode_buf, &tmpnum, 4);
1781     memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
1782     
1783     /* HMAC(ki, (seqnum, msg) ) */
1784     text->utils->hmac_md5((const unsigned char *) text->encode_buf,
1785                           inblob->curlen + 4, 
1786                           text->Ki_send, HASHLEN, digest);
1787     
1788     /* calculate the encrypted part */
1789     text->cipher_enc(text, inblob->data, inblob->curlen,
1790                      digest, out, outputlen);
1791     out+=(*outputlen);
1792     
1793     /* copy in version */
1794     tmpshort = htons(version);
1795     memcpy(out, &tmpshort, 2);      /* 2 bytes = version */
1796     
1797     out+=2;
1798     (*outputlen)+=2; /* for version */
1799     
1800     /* put in seqnum */
1801     tmpnum = htonl(text->seqnum);
1802     memcpy(out, &tmpnum, 4);        /* 4 bytes = seq # */  
1803     
1804     (*outputlen)+=4; /* for seqnum */
1805     
1806     /* put the 1st 4 bytes in */
1807     tmp=htonl(*outputlen);  
1808     memcpy(text->encode_buf, &tmp, 4);
1809     
1810     (*outputlen)+=4;
1811     
1812     *output = text->encode_buf;
1813     text->seqnum++;
1814     
1815     return SASL_OK;
1816 }
1817 
1818 static int
1819 digestmd5_privacy_decode_once(void *context,
1820                               const char **input,
1821                               unsigned *inputlen,
1822                               char **output,
1823                               unsigned *outputlen)
1824 {
1825     context_t *text = (context_t *) context;
1826     unsigned int tocopy;
1827     unsigned diff;
1828     int result;
1829     unsigned char digest[16];
1830     int tmpnum;
1831     int lup;
1832     
1833     if (text->needsize>0) /* 4 bytes for how long message is */
1834         {
1835             /* if less than 4 bytes just copy those we have into text->size */
1836             if (*inputlen<4) 
1837                 tocopy=*inputlen;
1838             else
1839                 tocopy=4;
1840             
1841             if (tocopy>text->needsize)
1842                 tocopy=text->needsize;
1843             
1844             memcpy(text->sizebuf+4-text->needsize, *input, tocopy);
1845             text->needsize-=tocopy;
1846             
1847             *input+=tocopy;
1848             *inputlen-=tocopy;
1849             
1850             if (text->needsize==0) /* got all of size */
1851             {
1852                 memcpy(&(text->size), text->sizebuf, 4);
1853                 text->cursize=0;
1854                 text->size=ntohl(text->size);
1855                 
1856                 if (text->size > text->in_maxbuf) {
1857                     return SASL_FAIL; /* too big probably error */
1858                 }
1859                 
1860                 if(!text->buffer)
1861                     text->buffer=text->utils->malloc(text->size+5);
1862                 else
1863                     text->buffer=text->utils->realloc(text->buffer,
1864                                                       text->size+5);     
1865                 if (text->buffer == NULL) return SASL_NOMEM;
1866             }
1867 
1868             *outputlen=0;
1869             *output=NULL;
1870             if (*inputlen==0) /* have to wait until next time for data */
1871                 return SASL_OK;
1872             
1873             if (text->size==0)  /* should never happen */
1874                 return SASL_FAIL;
1875         }
1876     
1877     diff=text->size - text->cursize; /* bytes need for full message */
1878     
1879     if (! text->buffer)
1880         return SASL_FAIL;
1881     
1882     if (*inputlen < diff) /* not enough for a decode */
1883     {
1884         memcpy(text->buffer+text->cursize, *input, *inputlen);
1885         text->cursize+=*inputlen;
1886         *inputlen=0;
1887         *outputlen=0;
1888         *output=NULL;
1889         return SASL_OK;
1890     } else {
1891         memcpy(text->buffer+text->cursize, *input, diff);
1892         *input+=diff;      
1893         *inputlen-=diff;
1894     }
1895     
1896     {
1897         unsigned short ver;
1898         unsigned int seqnum;
1899         unsigned char checkdigest[16];
1900         
1901         result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
1902                                  &text->decode_once_buf_len,
1903                                  text->size-6);
1904         if (result != SASL_OK)
1905             return result;
1906         
1907         *output = text->decode_once_buf;
1908         *outputlen = *inputlen;
1909         
1910         result=text->cipher_dec(text,text->buffer,text->size-6,digest,
1911                                 *output, outputlen);
1912         
1913         if (result!=SASL_OK)
1914             return result;
1915         
1916         {
1917             int i;
1918             for(i=10; i; i--) {
1919                 memcpy(&ver, text->buffer+text->size-i,2);
1920                 ver=ntohs(ver);
1921             }
1922         }
1923         
1924         /* check the version number */
1925         memcpy(&ver, text->buffer+text->size-6, 2);
1926         ver=ntohs(ver);
1927         if (ver != version)
1928         {
1929 #ifdef _INTEGRATED_SOLARIS_
1930             text->utils->seterror(text->utils->conn, 0,
1931                 gettext("Wrong Version"));
1932 #else
1933             text->utils->seterror(text->utils->conn, 0, "Wrong Version");
1934 #endif /* _INTEGRATED_SOLARIS_ */
1935             return SASL_FAIL;
1936         }
1937         
1938         /* check the CMAC */
1939         
1940         /* construct (seqnum, msg) */
1941         result = _plug_buf_alloc(text->utils, &text->decode_tmp_buf,
1942                                  &text->decode_tmp_buf_len, *outputlen + 4);
1943         if(result != SASL_OK) return result;
1944         
1945         tmpnum = htonl(text->rec_seqnum);
1946         memcpy(text->decode_tmp_buf, &tmpnum, 4);
1947         memcpy(text->decode_tmp_buf + 4, *output, *outputlen);
1948         
1949         /* HMAC(ki, (seqnum, msg) ) */
1950         text->utils->hmac_md5((const unsigned char *) text->decode_tmp_buf,
1951                               (*outputlen) + 4, 
1952                               text->Ki_receive, HASHLEN, checkdigest);
1953         
1954         /* now check it */
1955         for (lup=0;lup<10;lup++)
1956             if (checkdigest[lup]!=digest[lup])
1957                 {
1958 #ifdef _SUN_SDK_
1959                     text->utils->log(text->utils->conn, SASL_LOG_ERR,
1960                         "CMAC doesn't match at byte %d!", lup);
1961                     return SASL_BADMAC;
1962 #else
1963                     text->utils->seterror(text->utils->conn, 0,
1964                                           "CMAC doesn't match at byte %d!", lup);
1965                     return SASL_FAIL;
1966 #endif /* _SUN_SDK_ */
1967                 } 
1968         
1969         /* check the sequence number */
1970         memcpy(&seqnum, text->buffer+text->size-4,4);
1971         seqnum=ntohl(seqnum);
1972         
1973         if (seqnum!=text->rec_seqnum)
1974             {
1975 #ifdef _SUN_SDK_
1976                 text->utils->log(text->utils->conn, SASL_LOG_ERR,
1977                                  "Incorrect Sequence Number");
1978 #else
1979                 text->utils->seterror(text->utils->conn, 0,
1980                                       "Incorrect Sequence Number");
1981 #endif /* _SUN_SDK_ */
1982                 return SASL_FAIL;
1983             }
1984         
1985         text->rec_seqnum++; /* now increment it */
1986     }
1987     
1988     text->needsize=4;
1989     
1990     return SASL_OK;
1991 }
1992 
1993 static int digestmd5_privacy_decode(void *context,
1994                                     const char *input, unsigned inputlen,
1995                                     const char **output, unsigned *outputlen)
1996 {
1997     context_t *text = (context_t *) context;
1998     int ret;
1999     
2000     ret = _plug_decode(text->utils, context, input, inputlen,
2001                        &text->decode_buf, &text->decode_buf_len, outputlen,
2002                        digestmd5_privacy_decode_once);
2003     
2004     *output = text->decode_buf;
2005     
2006     return ret;
2007 }
2008 
2009 static int
2010 digestmd5_integrity_encode(void *context,
2011                            const struct iovec *invec,
2012                            unsigned numiov,
2013                            const char **output,
2014                            unsigned *outputlen)
2015 {
2016     context_t      *text = (context_t *) context;
2017     unsigned char   MAC[16];
2018     unsigned int    tmpnum;
2019     unsigned short int tmpshort;
2020     struct buffer_info *inblob, bufinfo;
2021     int ret;
2022     
2023     if(!context || !invec || !numiov || !output || !outputlen) {
2024         PARAMERROR( text->utils );
2025         return SASL_BADPARAM;
2026     }
2027     
2028     if (numiov > 1) {
2029         ret = _plug_iovec_to_buf(text->utils, invec, numiov,
2030                                  &text->enc_in_buf);
2031         if (ret != SASL_OK) return ret;
2032         inblob = text->enc_in_buf;
2033     } else {
2034         /* avoid the data copy */
2035         bufinfo.data = invec[0].iov_base;
2036         bufinfo.curlen = invec[0].iov_len;
2037         inblob = &bufinfo;
2038     }
2039     
2040     /* construct output */
2041     *outputlen = 4 + inblob->curlen + 16;
2042     
2043     ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
2044                           &(text->encode_buf_len), *outputlen);
2045     if(ret != SASL_OK) return ret;
2046     
2047     /* construct (seqnum, msg) */
2048     /* we can just use the output buffer */
2049     tmpnum = htonl(text->seqnum);
2050     memcpy(text->encode_buf, &tmpnum, 4);
2051     memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
2052     
2053     /* HMAC(ki, (seqnum, msg) ) */
2054 #ifdef _SUN_SDK_
2055     text->utils->hmac_md5((unsigned char *)text->encode_buf,
2056                           inblob->curlen + 4, 
2057                           text->Ki_send, HASHLEN, MAC);
2058 #else
2059     text->utils->hmac_md5(text->encode_buf, inblob->curlen + 4, 
2060                           text->Ki_send, HASHLEN, MAC);
2061 #endif /* _SUN_SDK_ */
2062     
2063     /* create MAC */
2064     tmpshort = htons(version);
2065     memcpy(MAC + 10, &tmpshort, MAC_OFFS);  /* 2 bytes = version */
2066     
2067     tmpnum = htonl(text->seqnum);
2068     memcpy(MAC + 12, &tmpnum, 4);   /* 4 bytes = sequence number */
2069     
2070     /* copy into output */
2071     tmpnum = htonl((*outputlen) - 4);
2072     
2073     /* length of message in network byte order */
2074     memcpy(text->encode_buf, &tmpnum, 4);
2075     /* the message text */
2076     memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
2077     /* the MAC */
2078     memcpy(text->encode_buf + 4 + inblob->curlen, MAC, 16);
2079     
2080     text->seqnum++;          /* add one to sequence number */
2081     
2082     *output = text->encode_buf;
2083     
2084     return SASL_OK;
2085 }
2086 
2087 static int
2088 create_MAC(context_t * text,
2089            char *input,
2090            int inputlen,
2091            int seqnum,
2092            unsigned char MAC[16])
2093 {
2094     unsigned int    tmpnum;
2095     unsigned short int tmpshort;  
2096     int ret;
2097     
2098     if (inputlen < 0)
2099         return SASL_FAIL;
2100     
2101     ret = _plug_buf_alloc(text->utils, &(text->MAC_buf),
2102                           &(text->MAC_buf_len), inputlen + 4);
2103     if(ret != SASL_OK) return ret;
2104     
2105     /* construct (seqnum, msg) */
2106     tmpnum = htonl(seqnum);
2107     memcpy(text->MAC_buf, &tmpnum, 4);
2108     memcpy(text->MAC_buf + 4, input, inputlen);
2109     
2110     /* HMAC(ki, (seqnum, msg) ) */
2111 #ifdef _SUN_SDK_
2112     text->utils->hmac_md5((unsigned char *)text->MAC_buf, inputlen + 4, 
2113                           text->Ki_receive, HASHLEN,
2114                           MAC);
2115 #else
2116     text->utils->hmac_md5(text->MAC_buf, inputlen + 4, 
2117                           text->Ki_receive, HASHLEN,
2118                           MAC);
2119 #endif /* _SUN_SDK_ */
2120     
2121     /* create MAC */
2122     tmpshort = htons(version);
2123     memcpy(MAC + 10, &tmpshort, 2); /* 2 bytes = version */
2124     
2125     tmpnum = htonl(seqnum);
2126     memcpy(MAC + 12, &tmpnum, 4);   /* 4 bytes = sequence number */
2127     
2128     return SASL_OK;
2129 }
2130 
2131 static int
2132 check_integrity(context_t * text,
2133                 char *buf, int bufsize,
2134                 char **output, unsigned *outputlen)
2135 {
2136     unsigned char MAC[16];
2137     int result;
2138     
2139     result = create_MAC(text, buf, bufsize - 16, text->rec_seqnum, MAC);
2140     if (result != SASL_OK)
2141         return result;
2142     
2143     /* make sure the MAC is right */
2144     if (strncmp((char *) MAC, buf + bufsize - 16, 16) != 0)
2145     {
2146 #ifdef _SUN_SDK_
2147         text->utils->log(text->utils->conn, SASL_LOG_ERR,
2148                          "MAC doesn't match");
2149         return SASL_BADMAC;
2150 #else
2151         text->utils->seterror(text->utils->conn, 0, "MAC doesn't match");
2152         return SASL_FAIL;
2153 #endif /* _SUN_SDK_ */
2154     }
2155     
2156     text->rec_seqnum++;
2157     
2158     /* ok make output message */
2159     result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
2160                              &text->decode_once_buf_len,
2161                              bufsize - 15);
2162     if (result != SASL_OK)
2163         return result;
2164     
2165     *output = text->decode_once_buf;
2166     memcpy(*output, buf, bufsize - 16);
2167     *outputlen = bufsize - 16;
2168     (*output)[*outputlen] = 0;
2169     
2170     return SASL_OK;
2171 }
2172 
2173 static int
2174 digestmd5_integrity_decode_once(void *context,
2175                                 const char **input,
2176                                 unsigned *inputlen,
2177                                 char **output,
2178                                 unsigned *outputlen)
2179 {
2180     context_t      *text = (context_t *) context;
2181     unsigned int    tocopy;
2182     unsigned        diff;
2183     int             result;
2184     
2185     if (text->needsize > 0) {     /* 4 bytes for how long message is */
2186         /*
2187          * if less than 4 bytes just copy those we have into text->size
2188          */
2189         if (*inputlen < 4)
2190             tocopy = *inputlen;
2191         else
2192             tocopy = 4;
2193         
2194         if (tocopy > text->needsize)
2195             tocopy = text->needsize;
2196         
2197         memcpy(text->sizebuf + 4 - text->needsize, *input, tocopy);
2198         text->needsize -= tocopy;
2199         
2200         *input += tocopy;
2201         *inputlen -= tocopy;
2202         
2203         if (text->needsize == 0) {   /* got all of size */
2204             memcpy(&(text->size), text->sizebuf, 4);
2205             text->cursize = 0;
2206             text->size = ntohl(text->size);
2207             
2208             if (text->size > text->in_maxbuf)
2209                 return SASL_FAIL;       /* too big probably error */
2210             
2211             if(!text->buffer)
2212                 text->buffer=text->utils->malloc(text->size+5);
2213             else
2214                 text->buffer=text->utils->realloc(text->buffer,text->size+5);
2215             if (text->buffer == NULL) return SASL_NOMEM;
2216         }
2217         *outputlen = 0;
2218         *output = NULL;
2219         if (*inputlen == 0)             /* have to wait until next time for data */
2220             return SASL_OK;
2221         
2222         if (text->size == 0) /* should never happen */
2223             return SASL_FAIL;
2224     }
2225     diff = text->size - text->cursize;    /* bytes need for full message */
2226     
2227     if(! text->buffer)
2228         return SASL_FAIL;
2229     
2230     if (*inputlen < diff) {  /* not enough for a decode */
2231         memcpy(text->buffer + text->cursize, *input, *inputlen);
2232         text->cursize += *inputlen;
2233         *inputlen = 0;
2234         *outputlen = 0;
2235         *output = NULL;
2236         return SASL_OK;
2237     } else {
2238         memcpy(text->buffer + text->cursize, *input, diff);
2239         *input += diff;
2240         *inputlen -= diff;
2241     }
2242     
2243     result = check_integrity(text, text->buffer, text->size,
2244                              output, outputlen);
2245     if (result != SASL_OK)
2246         return result;
2247 
2248     /* Reset State */
2249     text->needsize = 4;
2250     
2251     return SASL_OK;
2252 }
2253 
2254 static int digestmd5_integrity_decode(void *context,
2255                                       const char *input, unsigned inputlen,
2256                                       const char **output, unsigned *outputlen)
2257 {
2258     context_t *text = (context_t *) context;
2259     int ret;
2260     
2261     ret = _plug_decode(text->utils, context, input, inputlen,
2262                        &text->decode_buf, &text->decode_buf_len, outputlen,
2263                        digestmd5_integrity_decode_once);
2264     
2265     *output = text->decode_buf;
2266     
2267     return ret;
2268 }
2269 
2270 static void
2271 digestmd5_common_mech_dispose(void *conn_context, const sasl_utils_t *utils)
2272 {
2273     context_t *text = (context_t *) conn_context;
2274     
2275     if (!text || !utils) return;
2276     
2277     if (text->authid) utils->free(text->authid);
2278     if (text->realm) utils->free(text->realm);
2279     if (text->nonce) utils->free(text->nonce);
2280     if (text->cnonce) utils->free(text->cnonce);
2281 
2282     if (text->cipher_free) text->cipher_free(text);
2283     
2284     /* free the stuff in the context */
2285     if (text->response_value) utils->free(text->response_value);
2286     
2287     if (text->buffer) utils->free(text->buffer);
2288     if (text->encode_buf) utils->free(text->encode_buf);
2289     if (text->decode_buf) utils->free(text->decode_buf);
2290     if (text->decode_once_buf) utils->free(text->decode_once_buf);
2291     if (text->decode_tmp_buf) utils->free(text->decode_tmp_buf);
2292     if (text->out_buf) utils->free(text->out_buf);
2293     if (text->MAC_buf) utils->free(text->MAC_buf);
2294     
2295     if (text->enc_in_buf) {
2296         if (text->enc_in_buf->data) utils->free(text->enc_in_buf->data);
2297         utils->free(text->enc_in_buf);
2298     }
2299     
2300     utils->free(conn_context);
2301 }
2302 
2303 static void
2304 clear_reauth_entry(reauth_entry_t *reauth, enum Context_type type,
2305                    const sasl_utils_t *utils)
2306 {
2307     if (!reauth) return;
2308 
2309     if (reauth->authid) utils->free(reauth->authid);
2310     if (reauth->realm) utils->free(reauth->realm);
2311     if (reauth->nonce) utils->free(reauth->nonce);
2312     if (reauth->cnonce) utils->free(reauth->cnonce);
2313 
2314     if (type == CLIENT) {
2315         if (reauth->u.c.serverFQDN) utils->free(reauth->u.c.serverFQDN);
2316     }
2317 
2318     memset(reauth, 0, sizeof(reauth_entry_t));
2319 }
2320 
2321 static void
2322 digestmd5_common_mech_free(void *glob_context, const sasl_utils_t *utils)
2323 {
2324     reauth_cache_t *reauth_cache = (reauth_cache_t *) glob_context;
2325     size_t n;
2326     
2327     if (!reauth_cache) return;
2328 
2329     for (n = 0; n < reauth_cache->size; n++)
2330         clear_reauth_entry(&reauth_cache->e[n], reauth_cache->i_am, utils);
2331     if (reauth_cache->e) utils->free(reauth_cache->e);
2332 
2333     if (reauth_cache->mutex) utils->mutex_free(reauth_cache->mutex);
2334 
2335     utils->free(reauth_cache);
2336 }
2337 
2338 /*****************************  Server Section  *****************************/
2339 
2340 typedef struct server_context {
2341     context_t common;
2342 
2343     time_t timestamp;
2344     int stale;                          /* last nonce is stale */
2345     sasl_ssf_t limitssf, requiressf;    /* application defined bounds */
2346 } server_context_t;
2347 
2348 static void
2349 DigestCalcHA1FromSecret(context_t * text,
2350                         const sasl_utils_t * utils,
2351                         HASH HA1,
2352                         unsigned char *authorization_id,
2353                         unsigned char *pszNonce,
2354                         unsigned char *pszCNonce,
2355                         HASHHEX SessionKey)
2356 {
2357     MD5_CTX Md5Ctx;
2358     
2359     /* calculate session key */
2360     utils->MD5Init(&Md5Ctx);
2361     utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
2362     utils->MD5Update(&Md5Ctx, COLON, 1);
2363     utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
2364     utils->MD5Update(&Md5Ctx, COLON, 1);
2365     utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
2366     if (authorization_id != NULL) {
2367         utils->MD5Update(&Md5Ctx, COLON, 1);
2368         utils->MD5Update(&Md5Ctx, authorization_id, strlen((char *) authorization_id));
2369     }
2370     utils->MD5Final(HA1, &Md5Ctx);
2371     
2372     CvtHex(HA1, SessionKey);
2373     
2374     
2375     /* save HA1 because we need it to make the privacy and integrity keys */
2376     memcpy(text->HA1, HA1, sizeof(HASH));
2377 }
2378 
2379 static char *create_response(context_t * text,
2380                              const sasl_utils_t * utils,
2381                              unsigned char *nonce,
2382                              unsigned int ncvalue,
2383                              unsigned char *cnonce,
2384                              char *qop,
2385                              char *digesturi,
2386                              HASH Secret,
2387                              char *authorization_id,
2388                              char **response_value)
2389 {
2390     HASHHEX         SessionKey;
2391     HASHHEX         HEntity = "00000000000000000000000000000000";
2392     HASHHEX         Response;
2393     char           *result;
2394     
2395     if (qop == NULL)
2396         qop = "auth";
2397     
2398     DigestCalcHA1FromSecret(text,
2399                             utils,
2400                             Secret,
2401                             (unsigned char *) authorization_id,
2402                             nonce,
2403                             cnonce,
2404                             SessionKey);
2405     
2406     DigestCalcResponse(utils,
2407                        SessionKey,/* H(A1) */
2408                        nonce,   /* nonce from server */
2409                        ncvalue, /* 8 hex digits */
2410                        cnonce,  /* client nonce */
2411                        (unsigned char *) qop,   /* qop-value: "", "auth",
2412                                                  * "auth-int" */
2413                        (unsigned char *) digesturi,     /* requested URL */
2414                        (unsigned char *) "AUTHENTICATE",
2415                        HEntity, /* H(entity body) if qop="auth-int" */
2416                        Response /* request-digest or response-digest */
2417         );
2418     
2419     result = utils->malloc(HASHHEXLEN + 1);
2420 #ifdef _SUN_SDK_
2421     if (result == NULL)
2422         return NULL;
2423 #endif /* _SUN_SDK_ */
2424 /* TODO */
2425     memcpy(result, Response, HASHHEXLEN);
2426     result[HASHHEXLEN] = 0;
2427     
2428     /* response_value (used for reauth i think */
2429     if (response_value != NULL) {
2430         DigestCalcResponse(utils,
2431                            SessionKey,  /* H(A1) */
2432                            nonce,       /* nonce from server */
2433                            ncvalue,     /* 8 hex digits */
2434                            cnonce,      /* client nonce */
2435                            (unsigned char *) qop,       /* qop-value: "", "auth",
2436                                                          * "auth-int" */
2437                            (unsigned char *) digesturi, /* requested URL */
2438                            NULL,
2439                            HEntity,     /* H(entity body) if qop="auth-int" */
2440                            Response     /* request-digest or response-digest */
2441             );
2442         
2443         *response_value = utils->malloc(HASHHEXLEN + 1);
2444         if (*response_value == NULL)
2445             return NULL;
2446         memcpy(*response_value, Response, HASHHEXLEN);
2447         (*response_value)[HASHHEXLEN] = 0;
2448     }
2449     return result;
2450 }
2451 
2452 static int
2453 get_server_realm(sasl_server_params_t * params,
2454                  char **realm)
2455 {
2456     /* look at user realm first */
2457     if (params->user_realm != NULL) {
2458         if(params->user_realm[0] != '\0') {
2459             *realm = (char *) params->user_realm;
2460         } else {
2461             /* Catch improperly converted apps */
2462 #ifdef _SUN_SDK_
2463             params->utils->log(params->utils->conn, SASL_LOG_ERR,
2464                                "user_realm is an empty string!");
2465 #else
2466             params->utils->seterror(params->utils->conn, 0,
2467                                     "user_realm is an empty string!");
2468 #endif /* _SUN_SDK_ */
2469             return SASL_BADPARAM;
2470         }
2471     } else if (params->serverFQDN != NULL) {
2472         *realm = (char *) params->serverFQDN;
2473     } else {
2474 #ifdef _SUN_SDK_
2475         params->utils->log(params->utils->conn, SASL_LOG_ERR,
2476                            "no way to obtain domain");
2477 #else
2478         params->utils->seterror(params->utils->conn, 0,
2479                                 "no way to obtain domain");
2480 #endif /* _SUN_SDK_ */
2481         return SASL_FAIL;
2482     }
2483     
2484     return SASL_OK;
2485 }
2486 
2487 /*
2488  * Convert hex string to int
2489  */
2490 static int htoi(unsigned char *hexin, unsigned int *res)
2491 {
2492     int             lup, inlen;
2493     inlen = strlen((char *) hexin);
2494     
2495     *res = 0;
2496     for (lup = 0; lup < inlen; lup++) {
2497         switch (hexin[lup]) {
2498         case '0':
2499         case '1':
2500         case '2':
2501         case '3':
2502         case '4':
2503         case '5':
2504         case '6':
2505         case '7':
2506         case '8':
2507         case '9':
2508             *res = (*res << 4) + (hexin[lup] - '0');
2509             break;
2510             
2511         case 'a':
2512         case 'b':
2513         case 'c':
2514         case 'd':
2515         case 'e':
2516         case 'f':
2517             *res = (*res << 4) + (hexin[lup] - 'a' + 10);
2518             break;
2519             
2520         case 'A':
2521         case 'B':
2522         case 'C':
2523         case 'D':
2524         case 'E':
2525         case 'F':
2526             *res = (*res << 4) + (hexin[lup] - 'A' + 10);
2527             break;
2528             
2529         default:
2530             return SASL_BADPARAM;
2531         }
2532         
2533     }
2534     
2535     return SASL_OK;
2536 }
2537 
2538 static int digestmd5_server_mech_new(void *glob_context,
2539                                      sasl_server_params_t * sparams,
2540                                      const char *challenge __attribute__((unused)),
2541                                      unsigned challen __attribute__((unused)),
2542                                      void **conn_context)
2543 {
2544     context_t *text;
2545     
2546     /* holds state are in -- allocate server size */
2547     text = sparams->utils->malloc(sizeof(server_context_t));
2548     if (text == NULL)
2549         return SASL_NOMEM;
2550     memset(text, 0, sizeof(server_context_t));
2551     
2552     text->state = 1;
2553     text->i_am = SERVER;
2554     text->reauth = glob_context;
2555     
2556     *conn_context = text;
2557     return SASL_OK;
2558 }
2559 
2560 static int
2561 digestmd5_server_mech_step1(server_context_t *stext,
2562                             sasl_server_params_t *sparams,
2563                             const char *clientin __attribute__((unused)),
2564                             unsigned clientinlen __attribute__((unused)),
2565                             const char **serverout,
2566                             unsigned *serveroutlen,
2567                             sasl_out_params_t * oparams __attribute__((unused)))
2568 {
2569     context_t *text = (context_t *) stext;
2570     int             result;
2571     char           *realm;
2572     unsigned char  *nonce;
2573     char           *charset = "utf-8";
2574     char qop[1024], cipheropts[1024];
2575     struct digest_cipher *cipher;
2576     unsigned       resplen;
2577     int added_conf = 0;
2578     char maxbufstr[64];
2579     
2580     sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
2581                         "DIGEST-MD5 server step 1");
2582 
2583     /* get realm */
2584     result = get_server_realm(sparams, &realm);
2585     if(result != SASL_OK) return result;
2586     
2587     /* what options should we offer the client? */
2588     qop[0] = '\0';
2589     cipheropts[0] = '\0';
2590     if (stext->requiressf == 0) {
2591         if (*qop) strcat(qop, ",");
2592         strcat(qop, "auth");
2593     }
2594     if (stext->requiressf <= 1 && stext->limitssf >= 1) {
2595         if (*qop) strcat(qop, ",");
2596         strcat(qop, "auth-int");
2597     }
2598     
2599 #ifdef USE_UEF_SERVER
2600     cipher = available_ciphers1;
2601 #else
2602     cipher = available_ciphers;
2603 #endif
2604     while (cipher->name) {
2605         /* do we allow this particular cipher? */
2606         if (stext->requiressf <= cipher->ssf &&
2607             stext->limitssf >= cipher->ssf) {
2608             if (!added_conf) {
2609                 if (*qop) strcat(qop, ",");
2610                 strcat(qop, "auth-conf");
2611                 added_conf = 1;
2612             }
2613 #ifdef _SUN_SDK_
2614             if(strlen(cipheropts) + strlen(cipher->name) + 1 >=
2615                         sizeof (cipheropts)) {
2616                 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2617                     "internal error: cipheropts too big");
2618                 return SASL_FAIL;
2619             }
2620 #endif /* _SUN_SDK_ */
2621             if (*cipheropts) strcat(cipheropts, ",");
2622             strcat(cipheropts, cipher->name);
2623         }
2624         cipher++;
2625     }
2626     
2627     if (*qop == '\0') {
2628         /* we didn't allow anything?!? we'll return SASL_TOOWEAK, since
2629            that's close enough */
2630         return SASL_TOOWEAK;
2631     }
2632     
2633     /*
2634      * digest-challenge  = 1#( realm | nonce | qop-options | stale | maxbuf |
2635      * charset | cipher-opts | auth-param )
2636      */
2637     
2638 #ifndef _SUN_SDK_
2639     /* FIXME: get nonce XXX have to clean up after self if fail */
2640 #endif /* !_SUN_SDK_ */
2641     nonce = create_nonce(sparams->utils);
2642     if (nonce == NULL) {
2643 #ifdef _SUN_SDK_
2644         /* Note typo below */
2645         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2646                             "internal error: failed creating a nonce");
2647 #else
2648         SETERROR(sparams->utils, "internal erorr: failed creating a nonce");
2649 #endif /* _SUN_SDK_ */
2650         return SASL_FAIL;
2651     }
2652     
2653 #ifdef _SUN_SDK_
2654     resplen = strlen((char *)nonce) + strlen("nonce") + 5;
2655 #else
2656     resplen = strlen(nonce) + strlen("nonce") + 5;
2657 #endif /* _SUN_SDK_ */
2658     result = _plug_buf_alloc(sparams->utils, &(text->out_buf),
2659                              &(text->out_buf_len), resplen);
2660 #ifdef _SUN_SDK_
2661     if(result != SASL_OK) {
2662         sparams->utils->free(nonce);
2663         return result;
2664     }
2665 #else
2666     if(result != SASL_OK) return result;
2667 #endif /* _SUN_SDK_ */
2668     
2669     sprintf(text->out_buf, "nonce=\"%s\"", nonce);
2670     
2671     /* add to challenge; if we chose not to specify a realm, we won't
2672      * send one to the client */
2673     if (realm && add_to_challenge(sparams->utils,
2674                                   &text->out_buf, &text->out_buf_len, &resplen,
2675                                   "realm", (unsigned char *) realm,
2676                                   TRUE) != SASL_OK) {
2677 #ifdef _SUN_SDK_
2678         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2679                             "internal error: add_to_challenge failed");
2680         sparams->utils->free(nonce);
2681 #else
2682         SETERROR(sparams->utils, "internal error: add_to_challenge failed");
2683 #endif /* _SUN_SDK_ */
2684         return SASL_FAIL;
2685     }
2686     /*
2687      * qop-options A quoted string of one or more tokens indicating the
2688      * "quality of protection" values supported by the server.  The value
2689      * "auth" indicates authentication; the value "auth-int" indicates
2690      * authentication with integrity protection; the value "auth-conf"
2691      * indicates authentication with integrity protection and encryption.
2692      */
2693     
2694     /* add qop to challenge */
2695     if (add_to_challenge(sparams->utils,
2696                          &text->out_buf, &text->out_buf_len, &resplen,
2697                          "qop", 
2698                          (unsigned char *) qop, TRUE) != SASL_OK) {
2699 #ifdef _SUN_SDK_
2700         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2701                  "internal error: add_to_challenge 3 failed");
2702         sparams->utils->free(nonce);
2703 #else
2704         SETERROR(sparams->utils, "internal error: add_to_challenge 3 failed");
2705 #endif /* _SUN_SDK_ */
2706         return SASL_FAIL;
2707     }
2708     
2709     /*
2710      *  Cipheropts - list of ciphers server supports
2711      */
2712     /* add cipher-opts to challenge; only add if there are some */
2713     if (strcmp(cipheropts,"")!=0)
2714         {
2715             if (add_to_challenge(sparams->utils,
2716                                  &text->out_buf, &text->out_buf_len, &resplen,
2717                                  "cipher", (unsigned char *) cipheropts, 
2718                                  TRUE) != SASL_OK) {
2719 #ifdef _SUN_SDK_
2720                 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2721                         "internal error: add_to_challenge 4 failed");
2722                 sparams->utils->free(nonce);
2723 #else
2724                 SETERROR(sparams->utils,
2725                          "internal error: add_to_challenge 4 failed");
2726 #endif /* _SUN_SDK_ */
2727                 return SASL_FAIL;
2728             }
2729         }
2730     
2731     /* "stale" is true if a reauth failed because of a nonce timeout */
2732     if (stext->stale &&
2733         add_to_challenge(sparams->utils,
2734                          &text->out_buf, &text->out_buf_len, &resplen,
2735 #ifdef _SUN_SDK_
2736                          "stale", (unsigned char *)"true", FALSE) != SASL_OK) {
2737         sparams->utils->free(nonce);
2738         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2739                             "internal error: add_to_challenge failed");
2740 #else
2741                          "stale", "true", FALSE) != SASL_OK) {
2742         SETERROR(sparams->utils, "internal error: add_to_challenge failed");
2743 #endif /* _SUN_SDK_ */
2744         return SASL_FAIL;
2745     }
2746     
2747     /*
2748      * maxbuf A number indicating the size of the largest buffer the server
2749      * is able to receive when using "auth-int". If this directive is
2750      * missing, the default value is 65536. This directive may appear at most
2751      * once; if multiple instances are present, the client should abort the
2752      * authentication exchange.
2753      */
2754     if(sparams->props.maxbufsize) {
2755         snprintf(maxbufstr, sizeof(maxbufstr), "%d",
2756                  sparams->props.maxbufsize);
2757         if (add_to_challenge(sparams->utils,
2758                              &text->out_buf, &text->out_buf_len, &resplen,
2759                              "maxbuf", 
2760                              (unsigned char *) maxbufstr, FALSE) != SASL_OK) {
2761 #ifdef _SUN_SDK_
2762             sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2763                                 "internal error: add_to_challenge 5 failed");
2764 #else
2765             SETERROR(sparams->utils,
2766                      "internal error: add_to_challenge 5 failed");
2767 #endif /* _SUN_SDK_ */
2768             return SASL_FAIL;
2769         }
2770     }
2771     
2772 
2773     if (add_to_challenge(sparams->utils,
2774                          &text->out_buf, &text->out_buf_len, &resplen,
2775                          "charset", 
2776                          (unsigned char *) charset, FALSE) != SASL_OK) {
2777 #ifdef _SUN_SDK_
2778         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2779                             "internal error: add_to_challenge 6 failed");
2780         sparams->utils->free(nonce);
2781 #else
2782         SETERROR(sparams->utils, "internal error: add_to_challenge 6 failed");
2783 #endif /* _SUN_SDK_ */
2784         return SASL_FAIL;
2785     }
2786     
2787     
2788     /*
2789      * algorithm 
2790      *  This directive is required for backwards compatibility with HTTP 
2791      *  Digest., which supports other algorithms. . This directive is 
2792      *  required and MUST appear exactly once; if not present, or if multiple 
2793      *  instances are present, the client should abort the authentication 
2794      *  exchange. 
2795      *
2796      * algorithm         = "algorithm" "=" "md5-sess" 
2797      */
2798     
2799     if (add_to_challenge(sparams->utils,
2800                          &text->out_buf, &text->out_buf_len, &resplen,
2801                          "algorithm",
2802                          (unsigned char *) "md5-sess", FALSE)!=SASL_OK) {
2803 #ifdef _SUN_SDK_
2804         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2805                             "internal error: add_to_challenge 7 failed");
2806         sparams->utils->free(nonce);
2807 #else
2808         SETERROR(sparams->utils, "internal error: add_to_challenge 7 failed");
2809 #endif /* _SUN_SDK_ */
2810         return SASL_FAIL;
2811     }
2812     
2813     /*
2814      * The size of a digest-challenge MUST be less than 2048 bytes!!!
2815      */
2816     if (*serveroutlen > 2048) {
2817 #ifdef _SUN_SDK_
2818         sparams->utils->free(nonce);
2819         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2820                             "internal error: challenge larger than 2048 bytes");
2821 #else
2822         SETERROR(sparams->utils,
2823                  "internal error: challenge larger than 2048 bytes");
2824 #endif /* _SUN_SDK_ */
2825         return SASL_FAIL;
2826     }
2827 
2828     text->authid = NULL;
2829     _plug_strdup(sparams->utils, realm, &text->realm, NULL);
2830     text->nonce = nonce;
2831     text->nonce_count = 1;
2832     text->cnonce = NULL;
2833     stext->timestamp = time(0);
2834     
2835     *serveroutlen = strlen(text->out_buf);
2836     *serverout = text->out_buf;
2837     
2838     text->state = 2;
2839     
2840     return SASL_CONTINUE;
2841 }
2842 
2843 static int
2844 digestmd5_server_mech_step2(server_context_t *stext,
2845                             sasl_server_params_t *sparams,
2846                             const char *clientin,
2847                             unsigned clientinlen,
2848                             const char **serverout,
2849                             unsigned *serveroutlen,
2850                             sasl_out_params_t * oparams)
2851 {
2852     context_t *text = (context_t *) stext;
2853     /* verify digest */
2854     sasl_secret_t  *sec = NULL;
2855     int             result;
2856     char           *serverresponse = NULL;
2857     char           *username = NULL;
2858     char           *authorization_id = NULL;
2859     char           *realm = NULL;
2860     unsigned char  *nonce = NULL, *cnonce = NULL;
2861     unsigned int   noncecount = 0;
2862     char           *qop = NULL;
2863     char           *digesturi = NULL;
2864     char           *response = NULL;
2865     
2866     /* setting the default value (65536) */
2867     unsigned int    client_maxbuf = 65536;
2868     int             maxbuf_count = 0;  /* How many maxbuf instaces was found */
2869     
2870     char           *charset = NULL;
2871     char           *cipher = NULL;
2872     unsigned int   n=0;
2873     
2874     HASH            A1;
2875     
2876     /* password prop_request */
2877     const char *password_request[] = { SASL_AUX_PASSWORD,
2878                                        "*cmusaslsecretDIGEST-MD5",
2879                                        NULL };
2880     unsigned len;
2881     struct propval auxprop_values[2];
2882     
2883     /* can we mess with clientin? copy it to be safe */
2884     char           *in_start = NULL;
2885     char           *in = NULL; 
2886     
2887     sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
2888                         "DIGEST-MD5 server step 2");
2889 
2890     in = sparams->utils->malloc(clientinlen + 1);
2891 #ifdef _SUN_SDK_
2892     if (!in) return SASL_NOMEM;
2893 #endif /* _SUN_SDK_ */
2894     
2895     memcpy(in, clientin, clientinlen);
2896     in[clientinlen] = 0;
2897     
2898     in_start = in;
2899     
2900     
2901     /* parse what we got */
2902     while (in[0] != '\0') {
2903         char           *name = NULL, *value = NULL;
2904         get_pair(&in, &name, &value);
2905         
2906         if (name == NULL)
2907             break;
2908         
2909         /* Extracting parameters */
2910         
2911         /*
2912          * digest-response  = 1#( username | realm | nonce | cnonce |
2913          * nonce-count | qop | digest-uri | response | maxbuf | charset |
2914          * cipher | auth-param )
2915          */
2916         
2917         if (strcasecmp(name, "username") == 0) {
2918             _plug_strdup(sparams->utils, value, &username, NULL);
2919         } else if (strcasecmp(name, "authzid") == 0) {
2920             _plug_strdup(sparams->utils, value, &authorization_id, NULL);
2921         } else if (strcasecmp(name, "cnonce") == 0) {
2922             _plug_strdup(sparams->utils, value, (char **) &cnonce, NULL);
2923         } else if (strcasecmp(name, "nc") == 0) {
2924             if (htoi((unsigned char *) value, &noncecount) != SASL_OK) {
2925 #ifdef _SUN_SDK_
2926                 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2927                          "error converting hex to int");
2928 #else
2929                 SETERROR(sparams->utils,
2930                          "error converting hex to int");
2931 #endif /* _SUN_SDK_ */
2932                 result = SASL_BADAUTH;
2933                 goto FreeAllMem;
2934             }
2935         } else if (strcasecmp(name, "realm") == 0) {
2936             if (realm) {
2937 #ifdef _SUN_SDK_
2938                 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2939                                     "duplicate realm: authentication aborted");
2940 #else
2941                 SETERROR(sparams->utils,
2942                          "duplicate realm: authentication aborted");
2943 #endif /* _SUN_SDK_ */
2944                 result = SASL_FAIL;
2945                 goto FreeAllMem;
2946             }
2947             _plug_strdup(sparams->utils, value, &realm, NULL);
2948         } else if (strcasecmp(name, "nonce") == 0) {
2949             _plug_strdup(sparams->utils, value, (char **) &nonce, NULL);
2950         } else if (strcasecmp(name, "qop") == 0) {
2951             _plug_strdup(sparams->utils, value, &qop, NULL);
2952         } else if (strcasecmp(name, "digest-uri") == 0) {
2953             size_t service_len;
2954 
2955             /*
2956              * digest-uri-value  = serv-type "/" host [ "/" serv-name ]
2957              */
2958  
2959             _plug_strdup(sparams->utils, value, &digesturi, NULL);
2960 
2961             /* verify digest-uri format */
2962 
2963             /* make sure it's the service that we're expecting */
2964             service_len = strlen(sparams->service);
2965             if (strncasecmp(digesturi, sparams->service, service_len) ||
2966                 digesturi[service_len] != '/') {
2967                 result = SASL_BADAUTH;
2968 #ifdef _SUN_SDK_
2969                 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2970                                     "bad digest-uri: doesn't match service");
2971 #else
2972                 SETERROR(sparams->utils, 
2973                          "bad digest-uri: doesn't match service");
2974 #endif /* _SUN_SDK_ */
2975                 goto FreeAllMem;
2976             }
2977 
2978             /* xxx we don't verify the hostname component */
2979             
2980         } else if (strcasecmp(name, "response") == 0) {
2981             _plug_strdup(sparams->utils, value, &response, NULL);
2982         } else if (strcasecmp(name, "cipher") == 0) {
2983             _plug_strdup(sparams->utils, value, &cipher, NULL);
2984         } else if (strcasecmp(name, "maxbuf") == 0) {
2985             maxbuf_count++;
2986             if (maxbuf_count != 1) {
2987                 result = SASL_BADAUTH;
2988 #ifdef _SUN_SDK_
2989                 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
2990                                     "duplicate maxbuf: authentication aborted");
2991 #else
2992                 SETERROR(sparams->utils,
2993                          "duplicate maxbuf: authentication aborted");
2994 #endif /* _SUN_SDK_ */
2995                 goto FreeAllMem;
2996             } else if (sscanf(value, "%u", &client_maxbuf) != 1) {
2997                 result = SASL_BADAUTH;
2998 #ifdef _SUN_SDK_
2999                 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3000                         "invalid maxbuf parameter");
3001 #else
3002                 SETERROR(sparams->utils, "invalid maxbuf parameter");
3003 #endif /* _SUN_SDK_ */
3004                 goto FreeAllMem;
3005             } else {
3006                 if (client_maxbuf <= 16) {
3007                     result = SASL_BADAUTH;
3008 #ifdef _SUN_SDK_
3009                     sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3010                                         "maxbuf parameter too small");
3011 #else
3012                     SETERROR(sparams->utils,
3013                              "maxbuf parameter too small");
3014 #endif /* _SUN_SDK_ */
3015                     goto FreeAllMem;
3016                 }
3017             }
3018         } else if (strcasecmp(name, "charset") == 0) {
3019             if (strcasecmp(value, "utf-8") != 0) {
3020 #ifdef _SUN_SDK_
3021                 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3022                                     "client doesn't support UTF-8");
3023 #else
3024                 SETERROR(sparams->utils, "client doesn't support UTF-8");
3025 #endif /* _SUN_SDK_ */
3026                 result = SASL_FAIL;
3027                 goto FreeAllMem;
3028             }
3029             _plug_strdup(sparams->utils, value, &charset, NULL);
3030         } else {
3031             sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
3032                                 "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
3033                                 name, value);
3034         }
3035     }
3036     
3037     /*
3038      * username         = "username" "=" <"> username-value <">
3039      * username-value   = qdstr-val cnonce           = "cnonce" "=" <">
3040      * cnonce-value <"> cnonce-value     = qdstr-val nonce-count      = "nc"
3041      * "=" nc-value nc-value         = 8LHEX qop              = "qop" "="
3042      * qop-value digest-uri = "digest-uri" "=" digest-uri-value
3043      * digest-uri-value  = serv-type "/" host [ "/" serv-name ] serv-type
3044      * = 1*ALPHA host             = 1*( ALPHA | DIGIT | "-" | "." ) service
3045      * = host response         = "response" "=" <"> response-value <">
3046      * response-value   = 32LHEX LHEX = "0" | "1" | "2" | "3" | "4" | "5" |
3047      * "6" | "7" | "8" | "9" | "a" | "b" | "c" | "d" | "e" | "f" cipher =
3048      * "cipher" "=" cipher-value
3049      */
3050     /* Verifing that all parameters was defined */
3051     if ((username == NULL) ||
3052         (nonce == NULL) ||
3053         (noncecount == 0) ||
3054         (cnonce == NULL) ||
3055         (digesturi == NULL) ||
3056         (response == NULL)) {
3057 #ifdef _SUN_SDK_
3058         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3059                 "required parameters missing");
3060 #else
3061         SETERROR(sparams->utils, "required parameters missing");
3062 #endif /* _SUN_SDK_ */
3063         result = SASL_BADAUTH;
3064         goto FreeAllMem;
3065     }
3066 
3067     if (text->state == 1) {
3068         unsigned val = hash(username) % text->reauth->size;
3069 
3070         /* reauth attempt, see if we have any info for this user */
3071         if (sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
3072             if (text->reauth->e[val].authid &&
3073                 !strcmp(username, text->reauth->e[val].authid)) {
3074 
3075                 _plug_strdup(sparams->utils, text->reauth->e[val].realm,
3076                              &text->realm, NULL);
3077 #ifdef _SUN_SDK_
3078                 _plug_strdup(sparams->utils, (char *)text->reauth->e[val].nonce,
3079                              (char **) &text->nonce, NULL);
3080 #else
3081                 _plug_strdup(sparams->utils, text->reauth->e[val].nonce,
3082                              (char **) &text->nonce, NULL);
3083 #endif /* _SUN_SDK_ */
3084                 text->nonce_count = ++text->reauth->e[val].nonce_count;
3085 #ifdef _SUN_SDK_
3086                 _plug_strdup(sparams->utils, (char *)text->reauth->e[val].cnonce,
3087                              (char **) &text->cnonce, NULL);
3088 #else
3089                 _plug_strdup(sparams->utils, text->reauth->e[val].cnonce,
3090                              (char **) &text->cnonce, NULL);
3091 #endif /* _SUN_SDK_ */
3092                 stext->timestamp = text->reauth->e[val].u.s.timestamp;
3093             }
3094             sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
3095         }
3096 
3097         if (!text->nonce) {
3098             /* we don't have any reauth info, so bail */
3099             result = SASL_FAIL;
3100             goto FreeAllMem;
3101         }
3102     }
3103 
3104     /* Sanity check the parameters */
3105 #ifdef _SUN_SDK_
3106     if ((realm != NULL && text->realm != NULL &&
3107                 strcmp(realm, text->realm) != 0) ||
3108             (realm == NULL && text->realm != NULL) ||
3109             (realm != NULL && text->realm == NULL)) {
3110         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3111                             "realm changed: authentication aborted");
3112 #else
3113     if (strcmp(realm, text->realm) != 0) {
3114         SETERROR(sparams->utils,
3115                  "realm changed: authentication aborted");
3116 #endif /* _SUN_SDK_ */
3117         result = SASL_BADAUTH;
3118         goto FreeAllMem;
3119     }
3120 #ifdef _SUN_SDK_
3121     if (strcmp((char *)nonce, (char *) text->nonce) != 0) {
3122         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3123                             "nonce changed: authentication aborted");
3124 #else
3125     if (strcmp(nonce, (char *) text->nonce) != 0) {
3126         SETERROR(sparams->utils,
3127                  "nonce changed: authentication aborted");
3128 #endif /* _SUN_SKD_ */
3129         result = SASL_BADAUTH;
3130         goto FreeAllMem;
3131     }
3132     if (noncecount != text->nonce_count) {
3133 #ifdef _SUN_SDK_
3134         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3135                             "incorrect nonce-count: authentication aborted");
3136 #else
3137         SETERROR(sparams->utils,
3138                  "incorrect nonce-count: authentication aborted");
3139 #endif /* _SUN_SDK_ */
3140         result = SASL_BADAUTH;
3141         goto FreeAllMem;
3142     }
3143 #ifdef _SUN_SDK_
3144     if (text->cnonce && strcmp((char *)cnonce, (char *)text->cnonce) != 0) {
3145         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3146                             "cnonce changed: authentication aborted");
3147 #else
3148     if (text->cnonce && strcmp(cnonce, text->cnonce) != 0) {
3149         SETERROR(sparams->utils,
3150                  "cnonce changed: authentication aborted");
3151 #endif /* _SUN_SDK_ */
3152         result = SASL_BADAUTH;
3153         goto FreeAllMem;
3154     }
3155             
3156     result = sparams->utils->prop_request(sparams->propctx, password_request);
3157     if(result != SASL_OK) {
3158 #ifdef _SUN_SDK_
3159         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3160                             "unable to request user password");
3161 #else
3162         SETERROR(sparams->utils, "unable to resquest user password");
3163 #endif /* _SUN_SDK_ */
3164         goto FreeAllMem;
3165     }
3166     
3167     /* this will trigger the getting of the aux properties */
3168     /* Note that if we don't have an authorization id, we don't use it... */
3169     result = sparams->canon_user(sparams->utils->conn,
3170                                  username, 0, SASL_CU_AUTHID, oparams);
3171     if (result != SASL_OK) {
3172 #ifdef _SUN_SDK_
3173         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3174                             "unable canonify user and get auxprops");
3175 #else
3176         SETERROR(sparams->utils, "unable canonify user and get auxprops");
3177 #endif /* _SUN_SDK_ */
3178         goto FreeAllMem;
3179     }
3180     
3181     if (!authorization_id || !*authorization_id) {
3182         result = sparams->canon_user(sparams->utils->conn,
3183                                      username, 0, SASL_CU_AUTHZID, oparams);
3184     } else {
3185         result = sparams->canon_user(sparams->utils->conn,
3186                                      authorization_id, 0, SASL_CU_AUTHZID,
3187                                      oparams);
3188     }
3189     
3190     if (result != SASL_OK) {
3191 #ifdef _SUN_SDK_
3192         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3193                             "unable to canonicalize authorization ID");
3194 #else
3195         SETERROR(sparams->utils, "unable authorization ID");
3196 #endif /* _SUN_SDK_ */
3197         goto FreeAllMem;
3198     }
3199     
3200     result = sparams->utils->prop_getnames(sparams->propctx, password_request,
3201                                            auxprop_values);
3202     if (result < 0 ||
3203        ((!auxprop_values[0].name || !auxprop_values[0].values) &&
3204         (!auxprop_values[1].name || !auxprop_values[1].values))) {
3205         /* We didn't find this username */
3206 #ifdef _INTEGRATED_SOLARIS_
3207         sparams->utils->seterror(sparams->utils->conn, 0,
3208                         gettext("no secret in database"));
3209 #else
3210         sparams->utils->seterror(sparams->utils->conn, 0,
3211                                  "no secret in database");
3212 #endif /* _INTEGRATED_SOLARIS_ */
3213         result = SASL_NOUSER;
3214         goto FreeAllMem;
3215     }
3216     
3217     if (auxprop_values[0].name && auxprop_values[0].values) {
3218         len = strlen(auxprop_values[0].values[0]);
3219         if (len == 0) {
3220 #ifdef _INTEGRATED_SOLARIS_
3221             sparams->utils->seterror(sparams->utils->conn,0,
3222                         gettext("empty secret"));
3223 #else
3224             sparams->utils->seterror(sparams->utils->conn,0,
3225                                      "empty secret");
3226 #endif /* _INTEGRATED_SOLARIS_ */
3227             result = SASL_FAIL;
3228             goto FreeAllMem;
3229         }
3230         
3231         sec = sparams->utils->malloc(sizeof(sasl_secret_t) + len);
3232         if (!sec) {
3233 #ifdef _SUN_SDK_
3234             sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3235                                 "unable to allocate secret");
3236 #else
3237             SETERROR(sparams->utils, "unable to allocate secret");
3238 #endif /* _SUN_SDK_ */
3239             result = SASL_FAIL;
3240             goto FreeAllMem;
3241         }
3242         
3243         sec->len = len;
3244 #ifdef _SUN_SDK_
3245         strncpy((char *)sec->data, auxprop_values[0].values[0], len + 1); 
3246 #else
3247         strncpy(sec->data, auxprop_values[0].values[0], len + 1); 
3248 #endif /* _SUN_SDK_ */
3249         
3250         /*
3251          * Verifying response obtained from client
3252          * 
3253          * H_URP = H({ username-value,":",realm-value,":",passwd}) sec->data
3254          * contains H_URP
3255          */
3256         
3257         /* Calculate the secret from the plaintext password */
3258         {
3259             HASH HA1;
3260             
3261 #ifdef _SUN_SDK_
3262             DigestCalcSecret(sparams->utils, (unsigned char *)username,
3263                              (unsigned char *)text->realm, sec->data,
3264                              sec->len, HA1);
3265 #else
3266             DigestCalcSecret(sparams->utils, username,
3267                              text->realm, sec->data, sec->len, HA1);
3268 #endif /* _SUN_SDK_ */
3269             
3270             /*
3271              * A1 = { H( { username-value, ":", realm-value, ":", passwd } ),
3272              * ":", nonce-value, ":", cnonce-value }
3273              */
3274             
3275             memcpy(A1, HA1, HASHLEN);
3276             A1[HASHLEN] = '\0';
3277         }
3278         
3279         /* We're done with sec now. Let's get rid of it */
3280         _plug_free_secret(sparams->utils, &sec);
3281     } else if (auxprop_values[1].name && auxprop_values[1].values) {
3282         memcpy(A1, auxprop_values[1].values[0], HASHLEN);
3283         A1[HASHLEN] = '\0';
3284     } else {
3285 #ifdef _SUN_SDK_
3286         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3287                             "Have neither type of secret");
3288 #else
3289         sparams->utils->seterror(sparams->utils->conn, 0,
3290                                  "Have neither type of secret");
3291 #endif /* _SUN_SDK_ */
3292 #ifdef _SUN_SDK_
3293         result = SASL_FAIL;
3294         goto FreeAllMem;
3295 #else
3296         return SASL_FAIL;
3297 #endif /* _SUN_SDK_ */
3298     } 
3299     
3300     /* defaulting qop to "auth" if not specified */
3301     if (qop == NULL) {
3302         _plug_strdup(sparams->utils, "auth", &qop, NULL);      
3303     }
3304     
3305     /* check which layer/cipher to use */
3306     if ((!strcasecmp(qop, "auth-conf")) && (cipher != NULL)) {
3307         /* see what cipher was requested */
3308         struct digest_cipher *cptr;
3309         
3310 #ifdef USE_UEF_SERVER
3311         cptr = available_ciphers1;
3312 #else
3313         cptr = available_ciphers;
3314 #endif
3315         while (cptr->name) {
3316             /* find the cipher requested & make sure it's one we're happy
3317                with by policy */
3318             if (!strcasecmp(cipher, cptr->name) && 
3319                 stext->requiressf <= cptr->ssf &&
3320                 stext->limitssf >= cptr->ssf) {
3321                 /* found it! */
3322                 break;
3323             }
3324             cptr++;
3325         }
3326         
3327         if (cptr->name) {
3328             text->cipher_enc = cptr->cipher_enc;
3329             text->cipher_dec = cptr->cipher_dec;
3330             text->cipher_init = cptr->cipher_init;
3331             text->cipher_free = cptr->cipher_free;
3332             oparams->mech_ssf = cptr->ssf;
3333             n = cptr->n;
3334         } else {
3335             /* erg? client requested something we didn't advertise! */
3336             sparams->utils->log(sparams->utils->conn, SASL_LOG_WARN,
3337                                 "protocol violation: client requested invalid cipher");
3338 #ifndef _SUN_SDK_
3339             SETERROR(sparams->utils, "client requested invalid cipher");
3340 #endif /* !_SUN_SDK_ */
3341             /* Mark that we attempted security layer negotiation */
3342             oparams->mech_ssf = 2;
3343             result = SASL_FAIL;
3344             goto FreeAllMem;
3345         }
3346         
3347         oparams->encode=&digestmd5_privacy_encode;
3348         oparams->decode=&digestmd5_privacy_decode;
3349     } else if (!strcasecmp(qop, "auth-int") &&
3350                stext->requiressf <= 1 && stext->limitssf >= 1) {
3351         oparams->encode = &digestmd5_integrity_encode;
3352         oparams->decode = &digestmd5_integrity_decode;
3353         oparams->mech_ssf = 1;
3354     } else if (!strcasecmp(qop, "auth") && stext->requiressf == 0) {
3355         oparams->encode = NULL;
3356         oparams->decode = NULL;
3357         oparams->mech_ssf = 0;
3358     } else {
3359 #ifdef _SUN_SDK_
3360         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3361                             "protocol violation: client requested invalid qop");
3362 #else
3363         SETERROR(sparams->utils,
3364                  "protocol violation: client requested invalid qop");
3365 #endif /* _SUN_SDK_ */
3366         result = SASL_FAIL;
3367         goto FreeAllMem;
3368     }
3369     
3370     serverresponse = create_response(text,
3371                                      sparams->utils,
3372                                      text->nonce,
3373                                      text->nonce_count,
3374                                      cnonce,
3375                                      qop,
3376                                      digesturi,
3377                                      A1,
3378                                      authorization_id,
3379                                      &text->response_value);
3380     
3381     if (serverresponse == NULL) {
3382 #ifndef _SUN_SDK_
3383         SETERROR(sparams->utils, "internal error: unable to create response");
3384 #endif /* !_SUN_SDK_ */
3385         result = SASL_NOMEM;
3386         goto FreeAllMem;
3387     }
3388     
3389     /* if ok verified */
3390     if (strcmp(serverresponse, response) != 0) {
3391 #ifdef _INTEGRATED_SOLARIS_
3392         SETERROR(sparams->utils,
3393                  gettext("client response doesn't match what we generated"));
3394 #else
3395         SETERROR(sparams->utils,
3396                  "client response doesn't match what we generated");
3397 #endif /* _INTEGRATED_SOLARIS_ */
3398         result = SASL_BADAUTH;
3399         
3400         goto FreeAllMem;
3401     }
3402 
3403     /* see if our nonce expired */
3404     if (text->reauth->timeout &&
3405         time(0) - stext->timestamp > text->reauth->timeout) {
3406 #ifdef _INTEGRATED_SOLARIS_
3407         SETERROR(sparams->utils, gettext("server nonce expired"));
3408 #else
3409         SETERROR(sparams->utils, "server nonce expired");
3410 #endif /* _INTEGRATED_SOLARIS_ */
3411         stext->stale = 1;
3412         result = SASL_BADAUTH;
3413 
3414         goto FreeAllMem;
3415      }
3416 
3417     /*
3418      * nothing more to do; authenticated set oparams information
3419      */
3420     oparams->doneflag = 1;
3421     oparams->maxoutbuf = client_maxbuf - 4;
3422     if (oparams->mech_ssf > 1) {
3423 #ifdef _SUN_SDK_
3424         if (oparams->maxoutbuf <= 25) {
3425              result = SASL_BADPARAM;
3426              goto FreeAllMem;
3427         }
3428 #endif
3429         /* MAC block (privacy) */
3430         oparams->maxoutbuf -= 25;
3431     } else if(oparams->mech_ssf == 1) {
3432 #ifdef _SUN_SDK_
3433         if (oparams->maxoutbuf <= 16) {
3434              result = SASL_BADPARAM;
3435              goto FreeAllMem;
3436         }
3437 #endif
3438         /* MAC block (integrity) */
3439         oparams->maxoutbuf -= 16;
3440     }
3441     
3442     oparams->param_version = 0;
3443     
3444     text->seqnum = 0;                /* for integrity/privacy */
3445     text->rec_seqnum = 0;    /* for integrity/privacy */
3446     text->in_maxbuf =
3447        sparams->props.maxbufsize ? sparams->props.maxbufsize : DEFAULT_BUFSIZE;
3448     text->utils = sparams->utils;
3449     
3450     /* used by layers */
3451     text->needsize = 4;
3452     text->buffer = NULL;
3453     
3454     if (oparams->mech_ssf > 0) {
3455         char enckey[16];
3456         char deckey[16];
3457         
3458         create_layer_keys(text, sparams->utils,text->HA1,n,enckey,deckey);
3459         
3460         /* initialize cipher if need be */
3461 #ifdef _SUN_SDK_
3462         if (text->cipher_init) {
3463             if (text->cipher_free)
3464                 text->cipher_free(text);
3465             if ((result = text->cipher_init(text, enckey, deckey)) != SASL_OK) {
3466                 sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3467                                 "couldn't init cipher");
3468                 goto FreeAllMem;
3469             }
3470         }
3471 #else
3472         if (text->cipher_init)
3473             if (text->cipher_init(text, enckey, deckey) != SASL_OK) {
3474                 sparams->utils->seterror(sparams->utils->conn, 0,
3475                                          "couldn't init cipher");
3476             }
3477 #endif /* _SUN_SDK_ */
3478     }
3479     
3480     /*
3481      * The server receives and validates the "digest-response". The server
3482      * checks that the nonce-count is "00000001". If it supports subsequent
3483      * authentication, it saves the value of the nonce and the nonce-count.
3484      */
3485     
3486     /*
3487      * The "username-value", "realm-value" and "passwd" are encoded according
3488      * to the value of the "charset" directive. If "charset=UTF-8" is
3489      * present, and all the characters of either "username-value" or "passwd"
3490      * are in the ISO 8859-1 character set, then it must be converted to
3491      * UTF-8 before being hashed. A sample implementation of this conversion
3492      * is in section 8.
3493      */
3494     
3495     /* add to challenge */
3496     {
3497         unsigned resplen =
3498             strlen(text->response_value) + strlen("rspauth") + 3;
3499         
3500         result = _plug_buf_alloc(sparams->utils, &(text->out_buf),
3501                                  &(text->out_buf_len), resplen);
3502         if(result != SASL_OK) {
3503             goto FreeAllMem;
3504         }
3505         
3506         sprintf(text->out_buf, "rspauth=%s", text->response_value);
3507         
3508         /* self check */
3509         if (strlen(text->out_buf) > 2048) {
3510             result = SASL_FAIL;
3511             goto FreeAllMem;
3512         }
3513     }
3514     
3515     *serveroutlen = strlen(text->out_buf);
3516     *serverout = text->out_buf;
3517         
3518     result = SASL_OK;
3519 
3520   FreeAllMem:
3521     if (text->reauth->timeout &&
3522         sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
3523         unsigned val = hash(username) % text->reauth->size;
3524 
3525         switch (result) {
3526         case SASL_OK:
3527             /* successful auth, setup for future reauth */
3528             if (text->nonce_count == 1) {
3529                 /* successful initial auth, create new entry */
3530                 clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
3531                 text->reauth->e[val].authid = username; username = NULL;
3532                 text->reauth->e[val].realm = text->realm; text->realm = NULL;
3533                 text->reauth->e[val].nonce = text->nonce; text->nonce = NULL;
3534                 text->reauth->e[val].cnonce = cnonce; cnonce = NULL;
3535             }
3536             if (text->nonce_count <= text->reauth->e[val].nonce_count) {
3537                 /* paranoia.  prevent replay attacks */
3538                 clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
3539             }
3540             else {
3541                 text->reauth->e[val].nonce_count = text->nonce_count;
3542                 text->reauth->e[val].u.s.timestamp = time(0);
3543             }
3544             break;
3545         default:
3546             if (text->nonce_count > 1) {
3547                 /* failed reauth, clear entry */
3548                 clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
3549             }
3550             else {
3551                 /* failed initial auth, leave existing cache */
3552             }
3553         }
3554         sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
3555     }
3556 
3557     /* free everything */
3558     if (in_start) sparams->utils->free (in_start);
3559     
3560     if (username != NULL)
3561         sparams->utils->free (username);
3562 #ifdef _SUN_SDK_
3563     if (authorization_id != NULL)
3564         sparams->utils->free (authorization_id);
3565 #endif /* _SUN_SDK_ */
3566     if (realm != NULL)
3567         sparams->utils->free (realm);
3568     if (nonce != NULL)
3569         sparams->utils->free (nonce);
3570     if (cnonce != NULL)
3571         sparams->utils->free (cnonce);
3572     if (response != NULL)
3573         sparams->utils->free (response);
3574     if (cipher != NULL)
3575         sparams->utils->free (cipher);
3576     if (serverresponse != NULL)
3577         sparams->utils->free(serverresponse);
3578     if (charset != NULL)
3579         sparams->utils->free (charset);
3580     if (digesturi != NULL)
3581         sparams->utils->free (digesturi);
3582     if (qop!=NULL)
3583         sparams->utils->free (qop);  
3584     if (sec)
3585         _plug_free_secret(sparams->utils, &sec);
3586     
3587     return result;
3588 }
3589 
3590 static int
3591 digestmd5_server_mech_step(void *conn_context,
3592                            sasl_server_params_t *sparams,
3593                            const char *clientin,
3594                            unsigned clientinlen,
3595                            const char **serverout,
3596                            unsigned *serveroutlen,
3597                            sasl_out_params_t *oparams)
3598 {
3599     context_t *text = (context_t *) conn_context;
3600     server_context_t *stext = (server_context_t *) conn_context;
3601     
3602     if (clientinlen > 4096) return SASL_BADPROT;
3603     
3604     *serverout = NULL;
3605     *serveroutlen = 0;
3606     
3607     switch (text->state) {
3608         
3609     case 1:
3610         /* setup SSF limits */
3611         if (!sparams->props.maxbufsize) {
3612             stext->limitssf = 0;
3613             stext->requiressf = 0;
3614         } else {
3615             if (sparams->props.max_ssf < sparams->external_ssf) {
3616                 stext->limitssf = 0;
3617             } else {
3618                 stext->limitssf =
3619                     sparams->props.max_ssf - sparams->external_ssf;
3620             }
3621             if (sparams->props.min_ssf < sparams->external_ssf) {
3622                 stext->requiressf = 0;
3623             } else {
3624                 stext->requiressf =
3625                     sparams->props.min_ssf - sparams->external_ssf;
3626             }
3627         }
3628 
3629         if (clientin && text->reauth->timeout) {
3630             /* here's where we attempt fast reauth if possible */
3631             if (digestmd5_server_mech_step2(stext, sparams,
3632                                             clientin, clientinlen,
3633                                             serverout, serveroutlen,
3634                                             oparams) == SASL_OK) {
3635                 return SASL_OK;
3636             }
3637 
3638 #ifdef _SUN_SDK_
3639             sparams->utils->log(sparams->utils->conn, SASL_LOG_WARN,
3640                                 "DIGEST-MD5 reauth failed");
3641 #else
3642             sparams->utils->log(NULL, SASL_LOG_WARN,
3643                                 "DIGEST-MD5 reauth failed\n");
3644 #endif /* _SUN_SDK_ */
3645 
3646             /* re-initialize everything for a fresh start */
3647             memset(oparams, 0, sizeof(sasl_out_params_t));
3648 
3649             /* fall through and issue challenge */
3650         }
3651 
3652         return digestmd5_server_mech_step1(stext, sparams,
3653                                            clientin, clientinlen,
3654                                            serverout, serveroutlen, oparams);
3655         
3656     case 2:
3657         return digestmd5_server_mech_step2(stext, sparams,
3658                                            clientin, clientinlen,
3659                                            serverout, serveroutlen, oparams);
3660         
3661     default:
3662 #ifdef _SUN_SDK_
3663         sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR,
3664                             "Invalid DIGEST-MD5 server step %d", text->state);
3665 #else
3666         sparams->utils->log(NULL, SASL_LOG_ERR,
3667                             "Invalid DIGEST-MD5 server step %d\n", text->state);
3668 #endif /* _SUN_SDK_ */
3669         return SASL_FAIL;
3670     }
3671     
3672 #ifndef _SUN_SDK_
3673     return SASL_FAIL; /* should never get here */
3674 #endif /* !_SUN_SDK_ */
3675 }
3676 
3677 static void
3678 digestmd5_server_mech_dispose(void *conn_context, const sasl_utils_t *utils)
3679 {
3680     server_context_t *stext = (server_context_t *) conn_context;
3681     
3682     if (!stext || !utils) return;
3683     
3684     digestmd5_common_mech_dispose(conn_context, utils);
3685 }
3686 
3687 static sasl_server_plug_t digestmd5_server_plugins[] =
3688 {
3689     {
3690         "DIGEST-MD5",                   /* mech_name */
3691         /* EXPORT DELETE START */
3692 #ifdef WITH_RC4
3693         128,                            /* max_ssf */
3694 #elif WITH_DES
3695         112,
3696 #else 
3697         /* EXPORT DELETE END */
3698         0,
3699         /* EXPORT DELETE START */
3700 #endif
3701         /* EXPORT DELETE END */
3702         SASL_SEC_NOPLAINTEXT
3703         | SASL_SEC_NOANONYMOUS
3704         | SASL_SEC_MUTUAL_AUTH,         /* security_flags */
3705         SASL_FEAT_ALLOWS_PROXY,         /* features */
3706         NULL,                           /* glob_context */
3707         &digestmd5_server_mech_new, /* mech_new */
3708         &digestmd5_server_mech_step,        /* mech_step */
3709         &digestmd5_server_mech_dispose,     /* mech_dispose */
3710         &digestmd5_common_mech_free,        /* mech_free */
3711         NULL,                           /* setpass */
3712         NULL,                           /* user_query */
3713         NULL,                           /* idle */
3714         NULL,                           /* mech avail */
3715         NULL                            /* spare */
3716     }
3717 };
3718 
3719 int digestmd5_server_plug_init(sasl_utils_t *utils,
3720                                int maxversion,
3721                                int *out_version,
3722                                sasl_server_plug_t **pluglist,
3723                                int *plugcount) 
3724 {
3725     reauth_cache_t *reauth_cache;
3726     const char *timeout = NULL;
3727     unsigned int len;
3728 #if defined _SUN_SDK_  && defined USE_UEF
3729     int ret;
3730 #endif /* _SUN_SDK_ && USE_UEF */
3731 
3732     if (maxversion < SASL_SERVER_PLUG_VERSION)
3733         return SASL_BADVERS;
3734 
3735 #if defined _SUN_SDK_  && defined USE_UEF
3736     if ((ret = uef_init(utils)) != SASL_OK)
3737         return ret;
3738 #endif /* _SUN_SDK_ && USE_UEF */
3739 
3740     /* reauth cache */
3741     reauth_cache = utils->malloc(sizeof(reauth_cache_t));
3742     if (reauth_cache == NULL)
3743         return SASL_NOMEM;
3744     memset(reauth_cache, 0, sizeof(reauth_cache_t));
3745     reauth_cache->i_am = SERVER;
3746 
3747     /* fetch and canonify the reauth_timeout */
3748     utils->getopt(utils->getopt_context, "DIGEST-MD5", "reauth_timeout",
3749                   &timeout, &len);
3750     if (timeout)
3751         reauth_cache->timeout = (time_t) 60 * strtol(timeout, NULL, 10);
3752 #ifdef _SUN_SDK_
3753     else
3754         reauth_cache->timeout = 0;
3755 #endif /* _SUN_SDK_ */
3756     if (reauth_cache->timeout < 0)
3757         reauth_cache->timeout = 0;
3758 
3759     if (reauth_cache->timeout) {
3760         /* mutex */
3761         reauth_cache->mutex = utils->mutex_alloc();
3762         if (!reauth_cache->mutex)
3763             return SASL_FAIL;
3764 
3765         /* entries */
3766         reauth_cache->size = 100;
3767         reauth_cache->e = utils->malloc(reauth_cache->size *
3768                                         sizeof(reauth_entry_t));
3769         if (reauth_cache->e == NULL)
3770             return SASL_NOMEM;
3771         memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t));
3772     }
3773 
3774     digestmd5_server_plugins[0].glob_context = reauth_cache;
3775 
3776 #ifdef _SUN_SDK_
3777 #ifdef USE_UEF_CLIENT
3778     digestmd5_server_plugins[0].max_ssf = uef_max_ssf;
3779 #endif /* USE_UEF_CLIENT */
3780 #endif /* _SUN_SDK_ */
3781 
3782     /* EXPORT DELETE START */
3783     /* CRYPT DELETE START */
3784 #ifdef _INTEGRATED_SOLARIS_
3785     /*
3786      * Let libsasl know that we are a "Sun" plugin so that privacy
3787      * and integrity will be allowed.
3788      */
3789     REG_PLUG("DIGEST-MD5", digestmd5_server_plugins);
3790 #endif /* _INTEGRATED_SOLARIS_ */
3791     /* CRYPT DELETE END */
3792     /* EXPORT DELETE END */
3793 
3794     *out_version = SASL_SERVER_PLUG_VERSION;
3795     *pluglist = digestmd5_server_plugins;
3796     *plugcount = 1;
3797     
3798     return SASL_OK;
3799 }
3800 
3801 /*****************************  Client Section  *****************************/
3802 
3803 typedef struct client_context {
3804     context_t common;
3805 
3806     sasl_secret_t *password;    /* user password */
3807     unsigned int free_password; /* set if we need to free password */
3808 
3809     int protection;
3810     struct digest_cipher *cipher;
3811     unsigned int server_maxbuf;
3812 #ifdef _INTEGRATED_SOLARIS_
3813     void *h;
3814 #endif /* _INTEGRATED_SOLARIS_ */
3815 } client_context_t;
3816 
3817 /* calculate H(A1) as per spec */
3818 static void
3819 DigestCalcHA1(context_t * text,
3820               const sasl_utils_t * utils,
3821               unsigned char *pszUserName,
3822               unsigned char *pszRealm,
3823               sasl_secret_t * pszPassword,
3824               unsigned char *pszAuthorization_id,
3825               unsigned char *pszNonce,
3826               unsigned char *pszCNonce,
3827               HASHHEX SessionKey)
3828 {
3829     MD5_CTX         Md5Ctx;
3830     HASH            HA1;
3831     
3832     DigestCalcSecret(utils,
3833                      pszUserName,
3834                      pszRealm,
3835                      (unsigned char *) pszPassword->data,
3836                      pszPassword->len,
3837                      HA1);
3838     
3839     /* calculate the session key */
3840     utils->MD5Init(&Md5Ctx);
3841     utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
3842     utils->MD5Update(&Md5Ctx, COLON, 1);
3843     utils->MD5Update(&Md5Ctx, pszNonce, strlen((char *) pszNonce));
3844     utils->MD5Update(&Md5Ctx, COLON, 1);
3845     utils->MD5Update(&Md5Ctx, pszCNonce, strlen((char *) pszCNonce));
3846     if (pszAuthorization_id != NULL) {
3847         utils->MD5Update(&Md5Ctx, COLON, 1);
3848         utils->MD5Update(&Md5Ctx, pszAuthorization_id, 
3849                          strlen((char *) pszAuthorization_id));
3850     }
3851     utils->MD5Final(HA1, &Md5Ctx);
3852     
3853     CvtHex(HA1, SessionKey);
3854     
3855     /* xxx rc-* use different n */
3856     
3857     /* save HA1 because we'll need it for the privacy and integrity keys */
3858     memcpy(text->HA1, HA1, sizeof(HASH));
3859     
3860 }
3861 
3862 static char *calculate_response(context_t * text,
3863                                 const sasl_utils_t * utils,
3864                                 unsigned char *username,
3865                                 unsigned char *realm,
3866                                 unsigned char *nonce,
3867                                 unsigned int ncvalue,
3868                                 unsigned char *cnonce,
3869                                 char *qop,
3870                                 unsigned char *digesturi,
3871                                 sasl_secret_t * passwd,
3872                                 unsigned char *authorization_id,
3873                                 char **response_value)
3874 {
3875     HASHHEX         SessionKey;
3876     HASHHEX         HEntity = "00000000000000000000000000000000";
3877     HASHHEX         Response;
3878     char           *result;
3879     
3880     /* Verifing that all parameters was defined */
3881     if(!username || !cnonce || !nonce || !ncvalue || !digesturi || !passwd) {
3882         PARAMERROR( utils );
3883         return NULL;
3884     }
3885     
3886     if (realm == NULL) {
3887         /* a NULL realm is equivalent to the empty string */
3888         realm = (unsigned char *) "";
3889     }
3890     
3891     if (qop == NULL) {
3892         /* default to a qop of just authentication */
3893         qop = "auth";
3894     }
3895     
3896     DigestCalcHA1(text,
3897                   utils,
3898                   username,
3899                   realm,
3900                   passwd,
3901                   authorization_id,
3902                   nonce,
3903                   cnonce,
3904                   SessionKey);
3905     
3906     DigestCalcResponse(utils,
3907                        SessionKey,/* H(A1) */
3908                        nonce,   /* nonce from server */
3909                        ncvalue, /* 8 hex digits */
3910                        cnonce,  /* client nonce */
3911                        (unsigned char *) qop,   /* qop-value: "", "auth",
3912                                                  * "auth-int" */
3913                        digesturi,       /* requested URL */
3914                        (unsigned char *) "AUTHENTICATE",
3915                        HEntity, /* H(entity body) if qop="auth-int" */
3916                        Response /* request-digest or response-digest */
3917         );
3918     
3919     result = utils->malloc(HASHHEXLEN + 1);
3920 #ifdef _SUN_SDK_
3921     if (result == NULL)
3922         return NULL;
3923 #endif /* _SUN_SDK_ */
3924     memcpy(result, Response, HASHHEXLEN);
3925     result[HASHHEXLEN] = 0;
3926     
3927     if (response_value != NULL) {
3928         DigestCalcResponse(utils,
3929                            SessionKey,  /* H(A1) */
3930                            nonce,       /* nonce from server */
3931                            ncvalue,     /* 8 hex digits */
3932                            cnonce,      /* client nonce */
3933                            (unsigned char *) qop,       /* qop-value: "", "auth",
3934                                                          * "auth-int" */
3935                            (unsigned char *) digesturi, /* requested URL */
3936                            NULL,
3937                            HEntity,     /* H(entity body) if qop="auth-int" */
3938                            Response     /* request-digest or response-digest */
3939             );
3940         
3941 #ifdef _SUN_SDK_
3942         if (*response_value != NULL)
3943             utils->free(*response_value);
3944 #endif /* _SUN_SDK_ */
3945         *response_value = utils->malloc(HASHHEXLEN + 1);
3946         if (*response_value == NULL)
3947             return NULL;
3948         
3949         memcpy(*response_value, Response, HASHHEXLEN);
3950         (*response_value)[HASHHEXLEN] = 0;
3951         
3952     }
3953     
3954     return result;
3955 }
3956 
3957 static int
3958 make_client_response(context_t *text,
3959                      sasl_client_params_t *params,
3960                      sasl_out_params_t *oparams)
3961 {
3962     client_context_t *ctext = (client_context_t *) text;
3963     char *qop = NULL;
3964     unsigned nbits = 0;
3965     unsigned char  *digesturi = NULL;
3966     bool            IsUTF8 = FALSE;
3967     char           ncvalue[10];
3968     char           maxbufstr[64];
3969     char           *response = NULL;
3970     unsigned        resplen = 0;
3971     int result;
3972 
3973     switch (ctext->protection) {
3974     case DIGEST_PRIVACY:
3975         qop = "auth-conf";
3976         oparams->encode = &digestmd5_privacy_encode; 
3977         oparams->decode = &digestmd5_privacy_decode;
3978         oparams->mech_ssf = ctext->cipher->ssf;
3979 
3980         nbits = ctext->cipher->n;
3981         text->cipher_enc = ctext->cipher->cipher_enc;
3982         text->cipher_dec = ctext->cipher->cipher_dec;
3983         text->cipher_free = ctext->cipher->cipher_free;
3984         text->cipher_init = ctext->cipher->cipher_init;
3985         break;
3986     case DIGEST_INTEGRITY:
3987         qop = "auth-int";
3988         oparams->encode = &digestmd5_integrity_encode;
3989         oparams->decode = &digestmd5_integrity_decode;
3990         oparams->mech_ssf = 1;
3991         break;
3992     case DIGEST_NOLAYER:
3993     default:
3994         qop = "auth";
3995         oparams->encode = NULL;
3996         oparams->decode = NULL;
3997         oparams->mech_ssf = 0;
3998     }
3999 
4000     digesturi = params->utils->malloc(strlen(params->service) + 1 +
4001                                       strlen(params->serverFQDN) + 1 +
4002                                       1);
4003     if (digesturi == NULL) {
4004         result = SASL_NOMEM;
4005         goto FreeAllocatedMem;
4006     };
4007     
4008     /* allocated exactly this. safe */
4009     strcpy((char *) digesturi, params->service);
4010     strcat((char *) digesturi, "/");
4011     strcat((char *) digesturi, params->serverFQDN);
4012     /*
4013      * strcat (digesturi, "/"); strcat (digesturi, params->serverFQDN);
4014      */
4015 
4016     /* response */
4017     response =
4018         calculate_response(text,
4019                            params->utils,
4020 #ifdef _SUN_SDK_
4021                            (unsigned char *) oparams->authid,
4022 #else
4023                            (char *) oparams->authid,
4024 #endif /* _SUN_SDK_ */
4025                            (unsigned char *) text->realm,
4026                            text->nonce,
4027                            text->nonce_count,
4028                            text->cnonce,
4029                            qop,
4030                            digesturi,
4031                            ctext->password,
4032                            strcmp(oparams->user, oparams->authid) ?
4033 #ifdef _SUN_SDK_
4034                            (unsigned char *) oparams->user : NULL,
4035 #else
4036                            (char *) oparams->user : NULL,
4037 #endif /* _SUN_SDK_ */
4038                            &text->response_value);
4039     
4040 #ifdef _SUN_SDK_
4041     if (response == NULL) {
4042         result = SASL_NOMEM;
4043         goto FreeAllocatedMem;
4044     }
4045 #endif /* _SUN_SDK_ */
4046     
4047     resplen = strlen(oparams->authid) + strlen("username") + 5;
4048     result =_plug_buf_alloc(params->utils, &(text->out_buf),
4049                             &(text->out_buf_len),
4050                             resplen);
4051     if (result != SASL_OK) goto FreeAllocatedMem;
4052     
4053     sprintf(text->out_buf, "username=\"%s\"", oparams->authid);
4054     
4055     if (add_to_challenge(params->utils,
4056                          &text->out_buf, &text->out_buf_len, &resplen,
4057                          "realm", (unsigned char *) text->realm,
4058                          TRUE) != SASL_OK) {
4059         result = SASL_FAIL;
4060         goto FreeAllocatedMem;
4061     }
4062     if (strcmp(oparams->user, oparams->authid)) {
4063         if (add_to_challenge(params->utils,
4064                              &text->out_buf, &text->out_buf_len, &resplen,
4065 #ifdef _SUN_SDK_
4066                              "authzid", (unsigned char *) oparams->user,
4067                              TRUE) != SASL_OK) {
4068 #else
4069                              "authzid", (char *) oparams->user, TRUE) != SASL_OK) {
4070 #endif /* _SUN_SDK_ */
4071             result = SASL_FAIL;
4072             goto FreeAllocatedMem;
4073         }
4074     }
4075     if (add_to_challenge(params->utils,
4076                          &text->out_buf, &text->out_buf_len, &resplen,
4077                          "nonce", text->nonce, TRUE) != SASL_OK) {
4078         result = SASL_FAIL;
4079         goto FreeAllocatedMem;
4080     }
4081     if (add_to_challenge(params->utils,
4082                          &text->out_buf, &text->out_buf_len, &resplen,
4083                          "cnonce", text->cnonce, TRUE) != SASL_OK) {
4084         result = SASL_FAIL;
4085         goto FreeAllocatedMem;
4086     }
4087     snprintf(ncvalue, sizeof(ncvalue), "%08x", text->nonce_count);
4088     if (add_to_challenge(params->utils,
4089                          &text->out_buf, &text->out_buf_len, &resplen,
4090                          "nc", (unsigned char *) ncvalue, FALSE) != SASL_OK) {
4091         result = SASL_FAIL;
4092         goto FreeAllocatedMem;
4093     }
4094     if (add_to_challenge(params->utils,
4095                          &text->out_buf, &text->out_buf_len, &resplen,
4096                          "qop", (unsigned char *) qop, FALSE) != SASL_OK) {
4097         result = SASL_FAIL;
4098         goto FreeAllocatedMem;
4099     }
4100     if (ctext->cipher != NULL) {
4101         if (add_to_challenge(params->utils,
4102                              &text->out_buf, &text->out_buf_len, &resplen,
4103                              "cipher", 
4104                              (unsigned char *) ctext->cipher->name,
4105                              TRUE) != SASL_OK) {
4106             result = SASL_FAIL;
4107             goto FreeAllocatedMem;
4108         }
4109     }
4110 
4111     if (params->props.maxbufsize) {
4112         snprintf(maxbufstr, sizeof(maxbufstr), "%d", params->props.maxbufsize);
4113         if (add_to_challenge(params->utils,
4114                              &text->out_buf, &text->out_buf_len, &resplen,
4115                              "maxbuf", (unsigned char *) maxbufstr, 
4116                              FALSE) != SASL_OK) {
4117 #ifdef _SUN_SDK_
4118             params->utils->log(params->utils->conn, SASL_LOG_ERR,
4119                      "internal error: add_to_challenge maxbuf failed");
4120 #else
4121             SETERROR(params->utils,
4122                      "internal error: add_to_challenge maxbuf failed");
4123 #endif /* _SUN_SDK_ */
4124             goto FreeAllocatedMem;
4125         }
4126     }
4127     
4128     if (IsUTF8) {
4129         if (add_to_challenge(params->utils,
4130                              &text->out_buf, &text->out_buf_len, &resplen,
4131                              "charset", (unsigned char *) "utf-8",
4132                              FALSE) != SASL_OK) {
4133             result = SASL_FAIL;
4134             goto FreeAllocatedMem;
4135         }
4136     }
4137     if (add_to_challenge(params->utils,
4138                          &text->out_buf, &text->out_buf_len, &resplen,
4139                          "digest-uri", digesturi, TRUE) != SASL_OK) {
4140         result = SASL_FAIL;
4141         goto FreeAllocatedMem;
4142     }
4143     if (add_to_challenge(params->utils,
4144                          &text->out_buf, &text->out_buf_len, &resplen,
4145                          "response", (unsigned char *) response,
4146                          FALSE) != SASL_OK) {
4147         
4148         result = SASL_FAIL;
4149         goto FreeAllocatedMem;
4150     }
4151     
4152     /* self check */
4153     if (strlen(text->out_buf) > 2048) {
4154         result = SASL_FAIL;
4155         goto FreeAllocatedMem;
4156     }
4157 
4158     /* set oparams */
4159 #ifdef _SUN_SDK_
4160     oparams->maxoutbuf = ctext->server_maxbuf - 4;
4161 #else
4162     oparams->maxoutbuf = ctext->server_maxbuf;
4163 #endif /* _SUN_SDK_ */
4164     if(oparams->mech_ssf > 1) {
4165 #ifdef _SUN_SDK_
4166         if (oparams->maxoutbuf <= 25)
4167              return (SASL_BADPARAM);
4168 #endif
4169         /* MAC block (privacy) */
4170         oparams->maxoutbuf -= 25;
4171     } else if(oparams->mech_ssf == 1) {
4172 #ifdef _SUN_SDK_
4173         if (oparams->maxoutbuf <= 16)
4174              return (SASL_BADPARAM);
4175 #endif
4176         /* MAC block (integrity) */
4177         oparams->maxoutbuf -= 16;
4178     }
4179     
4180     text->seqnum = 0;        /* for integrity/privacy */
4181     text->rec_seqnum = 0;    /* for integrity/privacy */
4182     text->utils = params->utils;
4183     
4184     text->in_maxbuf =
4185         params->props.maxbufsize ? params->props.maxbufsize : DEFAULT_BUFSIZE;
4186 
4187     /* used by layers */
4188     text->needsize = 4;
4189     text->buffer = NULL;
4190     
4191     if (oparams->mech_ssf > 0) {
4192         char enckey[16];
4193         char deckey[16];
4194         
4195         create_layer_keys(text, params->utils, text->HA1, nbits,
4196                           enckey, deckey);
4197         
4198         /* initialize cipher if need be */
4199 #ifdef _SUN_SDK_
4200         if (text->cipher_init) {
4201             if (text->cipher_free)
4202                 text->cipher_free(text);
4203             if((result = text->cipher_init(text, enckey, deckey)) != SASL_OK) {
4204                 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4205                                         "couldn't init cipher");
4206                 goto FreeAllocatedMem;
4207             }
4208         }
4209 #else
4210         if (text->cipher_init)
4211             text->cipher_init(text, enckey, deckey);                
4212 #endif /* _SUN_SDK_ */
4213     }
4214     
4215     result = SASL_OK;
4216 
4217   FreeAllocatedMem:
4218     if (digesturi) params->utils->free(digesturi);
4219     if (response) params->utils->free(response);
4220 
4221     return result;
4222 }
4223 
4224 static int parse_server_challenge(client_context_t *ctext,
4225                                   sasl_client_params_t *params,
4226                                   const char *serverin, unsigned serverinlen,
4227                                   char ***outrealms, int *noutrealm)
4228 {
4229     context_t *text = (context_t *) ctext;
4230     int result = SASL_OK;
4231     char *in_start = NULL;
4232     char *in = NULL;
4233     char **realms = NULL;
4234     int nrealm = 0;
4235     sasl_ssf_t limit, musthave = 0;
4236     sasl_ssf_t external;
4237     int protection = 0;
4238     int ciphers = 0;
4239     int maxbuf_count = 0;
4240 #ifndef _SUN_SDK_
4241     bool IsUTF8 = FALSE;
4242 #endif /* !_SUN_SDK_ */
4243     int algorithm_count = 0;
4244 
4245     if (!serverin || !serverinlen) {
4246 #ifndef _SUN_SDK_
4247         params->utils->log(params->utils->conn, SASL_LOG_ERR,
4248                                 "no server challenge");
4249 #else
4250         params->utils->seterror(params->utils->conn, 0,
4251                                 "no server challenge");
4252 #endif /* _SUN_SDK_ */
4253         return SASL_FAIL;
4254     }
4255 
4256     in_start = in = params->utils->malloc(serverinlen + 1);
4257     if (in == NULL) return SASL_NOMEM;
4258     
4259     memcpy(in, serverin, serverinlen);
4260     in[serverinlen] = 0;
4261     
4262     ctext->server_maxbuf = 65536; /* Default value for maxbuf */
4263 
4264     /* create a new cnonce */
4265     text->cnonce = create_nonce(params->utils);
4266     if (text->cnonce == NULL) {
4267 #ifdef _SUN_SDK_
4268         params->utils->log(params->utils->conn, SASL_LOG_ERR,
4269                            "failed to create cnonce");
4270 #else
4271         params->utils->seterror(params->utils->conn, 0,
4272                                 "failed to create cnonce");
4273 #endif /* _SUN_SDK_ */
4274         result = SASL_FAIL;
4275         goto FreeAllocatedMem;
4276     }
4277 
4278     /* parse the challenge */
4279     while (in[0] != '\0') {
4280         char *name, *value;
4281         
4282         get_pair(&in, &name, &value);
4283         
4284         /* if parse error */
4285         if (name == NULL) {
4286 #ifdef _SUN_SDK_
4287             params->utils->log(params->utils->conn, SASL_LOG_ERR,
4288                                "Parse error");
4289 #else
4290             params->utils->seterror(params->utils->conn, 0, "Parse error");
4291 #endif /* _SUN_SDK_ */
4292             result = SASL_FAIL;
4293             goto FreeAllocatedMem;
4294         }
4295         
4296         if (strcasecmp(name, "realm") == 0) {
4297             nrealm++;
4298             
4299             if(!realms)
4300                 realms = params->utils->malloc(sizeof(char *) * (nrealm + 1));
4301             else
4302                 realms = params->utils->realloc(realms, 
4303                                                 sizeof(char *) * (nrealm + 1));
4304             
4305             if (realms == NULL) {
4306                 result = SASL_NOMEM;
4307                 goto FreeAllocatedMem;
4308             }
4309             
4310             _plug_strdup(params->utils, value, &realms[nrealm-1], NULL);
4311             realms[nrealm] = NULL;
4312         } else if (strcasecmp(name, "nonce") == 0) {
4313             _plug_strdup(params->utils, value, (char **) &text->nonce,
4314                          NULL);
4315             text->nonce_count = 1;
4316         } else if (strcasecmp(name, "qop") == 0) {
4317             while (value && *value) {
4318                 char *comma = strchr(value, ',');
4319                 if (comma != NULL) {
4320                     *comma++ = '\0';
4321                 }
4322                 
4323                 if (strcasecmp(value, "auth-conf") == 0) {
4324                     protection |= DIGEST_PRIVACY;
4325                 } else if (strcasecmp(value, "auth-int") == 0) {
4326                     protection |= DIGEST_INTEGRITY;
4327                 } else if (strcasecmp(value, "auth") == 0) {
4328                     protection |= DIGEST_NOLAYER;
4329                 } else {
4330                     params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
4331                                        "Server supports unknown layer: %s\n",
4332                                        value);
4333                 }
4334                 
4335                 value = comma;
4336             }
4337             
4338             if (protection == 0) {
4339                 result = SASL_BADAUTH;
4340 #ifdef _INTEGRATED_SOLARIS_
4341                 params->utils->seterror(params->utils->conn, 0,
4342                         gettext("Server doesn't support known qop level"));
4343 #else
4344                 params->utils->seterror(params->utils->conn, 0,
4345                                         "Server doesn't support known qop level");
4346 #endif /* _INTEGRATED_SOLARIS_ */
4347                 goto FreeAllocatedMem;
4348             }
4349         } else if (strcasecmp(name, "cipher") == 0) {
4350             while (value && *value) {
4351                 char *comma = strchr(value, ',');
4352 #ifdef USE_UEF_CLIENT
4353                 struct digest_cipher *cipher = available_ciphers1;
4354 #else
4355                 struct digest_cipher *cipher = available_ciphers;
4356 #endif
4357                 
4358                 if (comma != NULL) {
4359                     *comma++ = '\0';
4360                 }
4361                 
4362                 /* do we support this cipher? */
4363                 while (cipher->name) {
4364                     if (!strcasecmp(value, cipher->name)) break;
4365                     cipher++;
4366                 }
4367                 if (cipher->name) {
4368                     ciphers |= cipher->flag;
4369                 } else {
4370                     params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
4371                                        "Server supports unknown cipher: %s\n",
4372                                        value);
4373                 }
4374                 
4375                 value = comma;
4376             }
4377         } else if (strcasecmp(name, "stale") == 0 && ctext->password) {
4378             /* clear any cached password */
4379             if (ctext->free_password)
4380                 _plug_free_secret(params->utils, &ctext->password);
4381             ctext->password = NULL;
4382         } else if (strcasecmp(name, "maxbuf") == 0) {
4383             /* maxbuf A number indicating the size of the largest
4384              * buffer the server is able to receive when using
4385              * "auth-int". If this directive is missing, the default
4386              * value is 65536. This directive may appear at most once;
4387              * if multiple instances are present, the client should
4388              * abort the authentication exchange.  
4389              */
4390             maxbuf_count++;
4391             
4392             if (maxbuf_count != 1) {
4393                 result = SASL_BADAUTH;
4394 #ifdef _SUN_SDK_
4395                 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4396                                    "At least two maxbuf directives found."
4397                                    " Authentication aborted");
4398 #else
4399                 params->utils->seterror(params->utils->conn, 0,
4400                                         "At least two maxbuf directives found. Authentication aborted");
4401 #endif /* _SUN_SDK_ */
4402                 goto FreeAllocatedMem;
4403             } else if (sscanf(value, "%u", &ctext->server_maxbuf) != 1) {
4404                 result = SASL_BADAUTH;
4405 #ifdef _SUN_SDK_
4406                 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4407                         "Invalid maxbuf parameter received from server");
4408 #else
4409                 params->utils->seterror(params->utils->conn, 0,
4410                                         "Invalid maxbuf parameter received from server");
4411 #endif /* _SUN_SDK_ */
4412                 goto FreeAllocatedMem;
4413             } else {
4414                 if (ctext->server_maxbuf<=16) {
4415                     result = SASL_BADAUTH;
4416 #ifdef _SUN_SDK_
4417                     params->utils->log(params->utils->conn, SASL_LOG_ERR,
4418                         "Invalid maxbuf parameter received from server"
4419                         " (too small: %s)", value);
4420 #else
4421                     params->utils->seterror(params->utils->conn, 0,
4422                                             "Invalid maxbuf parameter received from server (too small: %s)", value);
4423 #endif /* _SUN_SDK_ */
4424                     goto FreeAllocatedMem;
4425                 }
4426             }
4427         } else if (strcasecmp(name, "charset") == 0) {
4428             if (strcasecmp(value, "utf-8") != 0) {
4429                 result = SASL_BADAUTH;
4430 #ifdef _SUN_SDK_
4431                 params->utils->log(params->utils->conn, SASL_LOG_ERR,
4432                                    "Charset must be UTF-8");
4433 #else
4434                 params->utils->seterror(params->utils->conn, 0,
4435                                         "Charset must be UTF-8");
4436 #endif /* _SUN_SDK_ */
4437                 goto FreeAllocatedMem;
4438             } else {
4439 #ifndef _SUN_SDK_
4440                 IsUTF8 = TRUE;
4441 #endif /* !_SUN_SDK_ */
4442             }
4443         } else if (strcasecmp(name,"algorithm")==0) {
4444             if (strcasecmp(value, "md5-sess") != 0)
4445                 {
4446 #ifdef _SUN_SDK_
4447                     params->utils->log(params->utils->conn, SASL_LOG_ERR,
4448                                 "'algorithm' isn't 'md5-sess'");
4449 #else
4450                     params->utils->seterror(params->utils->conn, 0,
4451                                             "'algorithm' isn't 'md5-sess'");
4452 #endif /* _SUN_SDK_ */
4453                     result = SASL_FAIL;
4454                     goto FreeAllocatedMem;
4455                 }
4456             
4457             algorithm_count++;
4458             if (algorithm_count > 1)
4459                 {
4460 #ifdef _SUN_SDK_
4461                     params->utils->log(params->utils->conn, SASL_LOG_ERR,
4462                                        "Must see 'algorithm' only once");
4463 #else
4464                     params->utils->seterror(params->utils->conn, 0,
4465                                             "Must see 'algorithm' only once");
4466 #endif /* _SUN_SDK_ */
4467                     result = SASL_FAIL;
4468                     goto FreeAllocatedMem;
4469                 }
4470         } else {
4471             params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
4472                                "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
4473                                name, value);
4474         }
4475     }
4476     
4477     if (algorithm_count != 1) {
4478 #ifdef _SUN_SDK_
4479         params->utils->log(params->utils->conn, SASL_LOG_ERR,
4480                 "Must see 'algorithm' once. Didn't see at all");
4481 #else
4482         params->utils->seterror(params->utils->conn, 0,
4483                                 "Must see 'algorithm' once. Didn't see at all");
4484 #endif /* _SUN_SDK_ */
4485         result = SASL_FAIL;
4486         goto FreeAllocatedMem;
4487     }
4488 
4489     /* make sure we have everything we require */
4490     if (text->nonce == NULL) {
4491 #ifdef _SUN_SDK_
4492         params->utils->log(params->utils->conn, SASL_LOG_ERR,
4493                            "Don't have nonce.");
4494 #else
4495         params->utils->seterror(params->utils->conn, 0,
4496                                 "Don't have nonce.");
4497 #endif /* _SUN_SDK_ */
4498         result = SASL_FAIL;
4499         goto FreeAllocatedMem;
4500     }
4501 
4502     /* get requested ssf */
4503     external = params->external_ssf;
4504     
4505     /* what do we _need_?  how much is too much? */
4506     if (params->props.maxbufsize == 0) {
4507         musthave = 0;
4508         limit = 0;
4509     } else {
4510         if (params->props.max_ssf > external) {
4511             limit = params->props.max_ssf - external;
4512         } else {
4513             limit = 0;
4514         }
4515         if (params->props.min_ssf > external) {
4516             musthave = params->props.min_ssf - external;
4517         } else {
4518             musthave = 0;
4519         }
4520     }
4521     
4522     /* we now go searching for an option that gives us at least "musthave"
4523        and at most "limit" bits of ssf. */
4524     if ((limit > 1) && (protection & DIGEST_PRIVACY)) {
4525         struct digest_cipher *cipher;
4526         
4527         /* let's find an encryption scheme that we like */
4528 #ifdef USE_UEF_CLIENT
4529         cipher = available_ciphers1;
4530 #else
4531         cipher = available_ciphers;
4532 #endif
4533         while (cipher->name) {
4534             /* examine each cipher we support, see if it meets our security
4535                requirements, and see if the server supports it.
4536                choose the best one of these */
4537             if ((limit >= cipher->ssf) && (musthave <= cipher->ssf) &&
4538                 (ciphers & cipher->flag) &&
4539                 (!ctext->cipher || (cipher->ssf > ctext->cipher->ssf))) {
4540                 ctext->cipher = cipher;
4541             }
4542             cipher++;
4543         }
4544         
4545         if (ctext->cipher) {
4546             /* we found a cipher we like */
4547             ctext->protection = DIGEST_PRIVACY;
4548         } else {
4549             /* we didn't find any ciphers we like */
4550 #ifdef _INTEGRATED_SOLARIS_
4551             params->utils->seterror(params->utils->conn, 0,
4552                                     gettext("No good privacy layers"));
4553 #else
4554             params->utils->seterror(params->utils->conn, 0,
4555                                     "No good privacy layers");
4556 #endif /* _INTEGRATED_SOLARIS_ */
4557         }
4558     }
4559     
4560     if (ctext->cipher == NULL) {
4561         /* we failed to find an encryption layer we liked;
4562            can we use integrity or nothing? */
4563         
4564         if ((limit >= 1) && (musthave <= 1) 
4565             && (protection & DIGEST_INTEGRITY)) {
4566             /* integrity */
4567             ctext->protection = DIGEST_INTEGRITY;
4568 #ifdef _SUN_SDK_
4569         } else if (musthave == 0) {
4570 #else
4571         } else if (musthave <= 0) {
4572 #endif /* _SUN_SDK_ */
4573             /* no layer */
4574             ctext->protection = DIGEST_NOLAYER;
4575 
4576             /* See if server supports not having a layer */
4577             if ((protection & DIGEST_NOLAYER) != DIGEST_NOLAYER) {
4578 #ifdef _INTEGRATED_SOLARIS_
4579                 params->utils->seterror(params->utils->conn, 0, 
4580                         gettext("Server doesn't support \"no layer\""));
4581 #else
4582                 params->utils->seterror(params->utils->conn, 0, 
4583                                         "Server doesn't support \"no layer\"");
4584 #endif /* _INTEGRATED_SOLARIS_ */
4585                 result = SASL_FAIL;
4586                 goto FreeAllocatedMem;
4587             }
4588         } else {
4589 #ifdef _INTEGRATED_SOLARIS_
4590             params->utils->seterror(params->utils->conn, 0,
4591                                     gettext("Can't find an acceptable layer"));
4592 #else
4593             params->utils->seterror(params->utils->conn, 0,
4594                                     "Can't find an acceptable layer");
4595 #endif /* _INTEGRATED_SOLARIS_ */
4596             result = SASL_TOOWEAK;
4597             goto FreeAllocatedMem;
4598         }
4599     }
4600 
4601     *outrealms = realms;
4602     *noutrealm = nrealm;
4603 
4604   FreeAllocatedMem:
4605     if (in_start) params->utils->free(in_start);
4606 
4607     if (result != SASL_OK && realms) {
4608         int lup;
4609         
4610         /* need to free all the realms */
4611         for (lup = 0;lup < nrealm; lup++)
4612             params->utils->free(realms[lup]);
4613         
4614         params->utils->free(realms);
4615     }
4616 
4617     return result;
4618 }
4619 
4620 static int ask_user_info(client_context_t *ctext,
4621                          sasl_client_params_t *params,
4622                          char **realms, int nrealm,
4623                          sasl_interact_t **prompt_need,
4624                          sasl_out_params_t *oparams)
4625 {
4626     context_t *text = (context_t *) ctext;
4627     int result = SASL_OK;
4628     const char *authid = NULL, *userid = NULL, *realm = NULL;
4629     char *realm_chal = NULL;
4630     int user_result = SASL_OK;
4631     int auth_result = SASL_OK;
4632     int pass_result = SASL_OK;
4633     int realm_result = SASL_FAIL;
4634 
4635     /* try to get the authid */
4636     if (oparams->authid == NULL) {
4637         auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
4638         
4639         if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT)) {
4640             return auth_result;
4641         }
4642     }
4643     
4644     /* try to get the userid */
4645     if (oparams->user == NULL) {
4646         user_result = _plug_get_userid(params->utils, &userid, prompt_need);
4647         
4648         if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
4649             return user_result;
4650         }
4651     }
4652     
4653     /* try to get the password */
4654     if (ctext->password == NULL) {
4655         pass_result = _plug_get_password(params->utils, &ctext->password,
4656                                          &ctext->free_password, prompt_need);
4657         if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT)) {
4658             return pass_result;
4659         }
4660     }
4661 
4662     /* try to get the realm */
4663     if (text->realm == NULL) {
4664         if (realms) {
4665             if(nrealm == 1) {
4666                 /* only one choice */
4667                 realm = realms[0];
4668                 realm_result = SASL_OK;
4669             } else {
4670                 /* ask the user */
4671                 realm_result = _plug_get_realm(params->utils,
4672                                                (const char **) realms,
4673                                                (const char **) &realm,
4674                                                prompt_need);
4675             }
4676         }
4677 
4678         /* fake the realm if we must */
4679         if ((realm_result != SASL_OK) && (realm_result != SASL_INTERACT)) {
4680             if (params->serverFQDN) {
4681                 realm = params->serverFQDN;
4682             } else {
4683                 return realm_result;
4684             }
4685         }    
4686     }
4687     
4688     /* free prompts we got */
4689     if (prompt_need && *prompt_need) {
4690         params->utils->free(*prompt_need);
4691         *prompt_need = NULL;
4692     }
4693     
4694     /* if there are prompts not filled in */
4695     if ((user_result == SASL_INTERACT) || (auth_result == SASL_INTERACT) ||
4696         (pass_result == SASL_INTERACT) || (realm_result == SASL_INTERACT)) {
4697 
4698         /* make our default realm */
4699         if ((realm_result == SASL_INTERACT) && params->serverFQDN) {
4700             realm_chal = params->utils->malloc(3+strlen(params->serverFQDN));
4701             if (realm_chal) {
4702                 sprintf(realm_chal, "{%s}", params->serverFQDN);
4703             } else {
4704                 return SASL_NOMEM;
4705             }
4706         }
4707 
4708         /* make the prompt list */
4709         result =
4710 #if defined _INTEGRATED_SOLARIS_
4711             _plug_make_prompts(params->utils, &ctext->h, prompt_need,
4712                                user_result == SASL_INTERACT ?
4713                                convert_prompt(params->utils, &ctext->h,
4714                                gettext("Please enter your authorization name"))
4715                                         : NULL,
4716                                NULL,
4717                                auth_result == SASL_INTERACT ?
4718                                convert_prompt(params->utils, &ctext->h,
4719                         gettext("Please enter your authentication name"))
4720                                         : NULL,
4721                                NULL,
4722                                pass_result == SASL_INTERACT ?
4723                                convert_prompt(params->utils, &ctext->h,
4724                                         gettext("Please enter your password"))
4725                                         : NULL, NULL,
4726                                NULL, NULL, NULL,
4727                                realm_chal ? realm_chal : "{}",
4728                                realm_result == SASL_INTERACT ?
4729                                convert_prompt(params->utils, &ctext->h,
4730                                     gettext("Please enter your realm")) : NULL,
4731                                params->serverFQDN ? params->serverFQDN : NULL);
4732 #else
4733             _plug_make_prompts(params->utils, prompt_need,
4734                                user_result == SASL_INTERACT ?
4735                                "Please enter your authorization name" : NULL,
4736                                NULL,
4737                                auth_result == SASL_INTERACT ?
4738                                "Please enter your authentication name" : NULL,
4739                                NULL,
4740                                pass_result == SASL_INTERACT ?
4741                                "Please enter your password" : NULL, NULL,
4742                                NULL, NULL, NULL,
4743                                realm_chal ? realm_chal : "{}",
4744                                realm_result == SASL_INTERACT ?
4745                                "Please enter your realm" : NULL,
4746                                params->serverFQDN ? params->serverFQDN : NULL);
4747 #endif /* _INTEGRATED_SOLARIS_ */
4748         
4749         if (result == SASL_OK) return SASL_INTERACT;
4750 
4751         return result;
4752     }
4753     
4754     if (oparams->authid == NULL) {
4755         if (!userid || !*userid) {
4756             result = params->canon_user(params->utils->conn, authid, 0,
4757                                         SASL_CU_AUTHID | SASL_CU_AUTHZID,
4758                                         oparams);
4759         }
4760         else {
4761             result = params->canon_user(params->utils->conn,
4762                                         authid, 0, SASL_CU_AUTHID, oparams);
4763             if (result != SASL_OK) return result;
4764 
4765             result = params->canon_user(params->utils->conn,
4766                                         userid, 0, SASL_CU_AUTHZID, oparams);
4767         }
4768         if (result != SASL_OK) return result;
4769     }
4770 
4771     /* Get an allocated version of the realm into the structure */
4772     if (realm && text->realm == NULL) {
4773         _plug_strdup(params->utils, realm, (char **) &text->realm, NULL);
4774     }
4775 
4776     return result;
4777 }
4778 
4779 static int
4780 digestmd5_client_mech_new(void *glob_context,
4781                           sasl_client_params_t * params,
4782                           void **conn_context)
4783 {
4784     context_t *text;
4785     
4786     /* holds state are in -- allocate client size */
4787     text = params->utils->malloc(sizeof(client_context_t));
4788     if (text == NULL)
4789         return SASL_NOMEM;
4790     memset(text, 0, sizeof(client_context_t));
4791     
4792     text->state = 1;
4793     text->i_am = CLIENT;
4794     text->reauth = glob_context;
4795     
4796     *conn_context = text;
4797 
4798     return SASL_OK;
4799 }
4800 
4801 static int
4802 digestmd5_client_mech_step1(client_context_t *ctext,
4803                             sasl_client_params_t *params,
4804                             const char *serverin __attribute__((unused)), 
4805                             unsigned serverinlen __attribute__((unused)), 
4806                             sasl_interact_t **prompt_need,
4807                             const char **clientout,
4808                             unsigned *clientoutlen,
4809                             sasl_out_params_t *oparams)
4810 {
4811     context_t *text = (context_t *) ctext;
4812     int result = SASL_FAIL;
4813     unsigned val;
4814 
4815     params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
4816                        "DIGEST-MD5 client step 1");
4817 
4818     result = ask_user_info(ctext, params, NULL, 0, prompt_need, oparams);
4819     if (result != SASL_OK) return result;
4820 
4821     /* check if we have cached info for this user on this server */
4822     val = hash(params->serverFQDN) % text->reauth->size;
4823     if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
4824         if (text->reauth->e[val].u.c.serverFQDN &&
4825             !strcasecmp(text->reauth->e[val].u.c.serverFQDN,
4826                         params->serverFQDN) &&
4827             !strcmp(text->reauth->e[val].authid, oparams->authid)) {
4828 
4829 #ifdef _SUN_SDK_
4830             if (text->realm) params->utils->free(text->realm);
4831             if (text->nonce) params->utils->free(text->nonce);
4832             if (text->cnonce) params->utils->free(text->cnonce);
4833 #endif /* _SUN_SDK_ */
4834             /* we have info, so use it */
4835             _plug_strdup(params->utils, text->reauth->e[val].realm,
4836                          &text->realm, NULL);
4837 #ifdef _SUN_SDK_
4838             _plug_strdup(params->utils, (char *)text->reauth->e[val].nonce,
4839                          (char **) &text->nonce, NULL);
4840 #else
4841             _plug_strdup(params->utils, text->reauth->e[val].nonce,
4842                          (char **) &text->nonce, NULL);
4843 #endif /* _SUN_SDK_ */
4844             text->nonce_count = ++text->reauth->e[val].nonce_count;
4845 #ifdef _SUN_SDK_
4846             _plug_strdup(params->utils, (char *)text->reauth->e[val].cnonce,
4847                          (char **) &text->cnonce, NULL);
4848 #else
4849             _plug_strdup(params->utils, text->reauth->e[val].cnonce,
4850                          (char **) &text->cnonce, NULL);
4851 #endif /* _SUN_SDK_ */
4852             ctext->protection = text->reauth->e[val].u.c.protection;
4853             ctext->cipher = text->reauth->e[val].u.c.cipher;
4854             ctext->server_maxbuf = text->reauth->e[val].u.c.server_maxbuf;
4855         }
4856         params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
4857     }
4858 
4859     if (!text->nonce) {
4860         /* we don't have any reauth info, so just return
4861          * that there is no initial client send */
4862         text->state = 2;
4863         return SASL_CONTINUE;
4864     }
4865 
4866     /*
4867      * (username | realm | nonce | cnonce | nonce-count | qop digest-uri |
4868      * response | maxbuf | charset | auth-param )
4869      */
4870     
4871     result = make_client_response(text, params, oparams);
4872     if (result != SASL_OK) return result;
4873 
4874     *clientoutlen = strlen(text->out_buf);
4875     *clientout = text->out_buf;
4876 
4877     text->state = 3;
4878     return SASL_CONTINUE;
4879 }
4880 
4881 static int
4882 digestmd5_client_mech_step2(client_context_t *ctext,
4883                             sasl_client_params_t *params,
4884                             const char *serverin,
4885                             unsigned serverinlen,
4886                             sasl_interact_t **prompt_need,
4887                             const char **clientout,
4888                             unsigned *clientoutlen,
4889                             sasl_out_params_t *oparams)
4890 {
4891     context_t *text = (context_t *) ctext;
4892     int result = SASL_FAIL;
4893     char **realms = NULL;
4894     int nrealm = 0;
4895 
4896     params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
4897                        "DIGEST-MD5 client step 2");
4898 
4899     if (params->props.min_ssf > params->props.max_ssf) {
4900         return SASL_BADPARAM;
4901     }
4902 
4903     /* don't bother parsing the challenge more than once */
4904     if (text->nonce == NULL) {
4905         result = parse_server_challenge(ctext, params, serverin, serverinlen,
4906                                         &realms, &nrealm);
4907         if (result != SASL_OK) goto FreeAllocatedMem;
4908     
4909         if (nrealm == 1) {
4910             /* only one choice! */
4911             text->realm = realms[0];
4912 
4913             /* free realms */
4914             params->utils->free(realms);
4915             realms = NULL;
4916         }
4917     }
4918 
4919     result = ask_user_info(ctext, params, realms, nrealm,
4920                            prompt_need, oparams);
4921     if (result != SASL_OK) goto FreeAllocatedMem;
4922 
4923     /*
4924      * (username | realm | nonce | cnonce | nonce-count | qop digest-uri |
4925      * response | maxbuf | charset | auth-param )
4926      */
4927     
4928     result = make_client_response(text, params, oparams);
4929     if (result != SASL_OK) goto FreeAllocatedMem;
4930 
4931     *clientoutlen = strlen(text->out_buf);
4932     *clientout = text->out_buf;
4933 
4934     text->state = 3;
4935     
4936     result = SASL_CONTINUE;
4937     
4938   FreeAllocatedMem:
4939     if (realms) {
4940         int lup;
4941         
4942         /* need to free all the realms */
4943         for (lup = 0;lup < nrealm; lup++)
4944             params->utils->free(realms[lup]);
4945         
4946         params->utils->free(realms);
4947     }
4948 
4949     return result;
4950 }
4951 
4952 static int
4953 digestmd5_client_mech_step3(client_context_t *ctext,
4954                             sasl_client_params_t *params,
4955                             const char *serverin,
4956                             unsigned serverinlen,
4957                             sasl_interact_t **prompt_need __attribute__((unused)),
4958                             const char **clientout __attribute__((unused)),
4959                             unsigned *clientoutlen __attribute__((unused)),
4960                             sasl_out_params_t *oparams)
4961 {
4962     context_t *text = (context_t *) ctext;
4963     char           *in = NULL;
4964     char           *in_start;
4965     int result = SASL_FAIL;
4966     
4967     params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
4968                        "DIGEST-MD5 client step 3");
4969 
4970     /* Verify that server is really what he claims to be */
4971     in_start = in = params->utils->malloc(serverinlen + 1);
4972     if (in == NULL) return SASL_NOMEM;
4973 
4974     memcpy(in, serverin, serverinlen);
4975     in[serverinlen] = 0;
4976     
4977     /* parse the response */
4978     while (in[0] != '\0') {
4979         char *name, *value;
4980         get_pair(&in, &name, &value);
4981         
4982         if (name == NULL) {
4983 #ifdef _SUN_SDK_
4984             params->utils->log(params->utils->conn, SASL_LOG_ERR,
4985                                "DIGEST-MD5 Received Garbage");
4986 #else
4987             params->utils->seterror(params->utils->conn, 0,
4988                                     "DIGEST-MD5 Received Garbage");
4989 #endif /* _SUN_SDK_ */
4990             break;
4991         }
4992         
4993         if (strcasecmp(name, "rspauth") == 0) {
4994             
4995             if (strcmp(text->response_value, value) != 0) {
4996 #ifdef _INTEGRATED_SOLARIS_
4997                 params->utils->seterror(params->utils->conn, 0,
4998                         gettext("Server authentication failed"));
4999 #else
5000                 params->utils->seterror(params->utils->conn, 0,
5001                                         "DIGEST-MD5: This server wants us to believe that he knows shared secret");
5002 #endif /* _INTEGRATED_SOLARIS_ */
5003                 result = SASL_FAIL;
5004             } else {
5005                 oparams->doneflag = 1;
5006                 oparams->param_version = 0;
5007                 
5008                 result = SASL_OK;
5009             }
5010             break;
5011         } else {
5012             params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
5013                                "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
5014                                name, value);
5015         }
5016     }
5017     
5018     params->utils->free(in_start);
5019 
5020     if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
5021         unsigned val = hash(params->serverFQDN) % text->reauth->size;
5022         switch (result) {
5023         case SASL_OK:
5024             if (text->nonce_count == 1) {
5025                 /* successful initial auth, setup for future reauth */
5026                 clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
5027                 _plug_strdup(params->utils, oparams->authid,
5028                              &text->reauth->e[val].authid, NULL);
5029                 text->reauth->e[val].realm = text->realm; text->realm = NULL;
5030                 text->reauth->e[val].nonce = text->nonce; text->nonce = NULL;
5031                 text->reauth->e[val].nonce_count = text->nonce_count;
5032                 text->reauth->e[val].cnonce = text->cnonce; text->cnonce = NULL;
5033                 _plug_strdup(params->utils, params->serverFQDN,
5034                              &text->reauth->e[val].u.c.serverFQDN, NULL);
5035                 text->reauth->e[val].u.c.protection = ctext->protection;
5036                 text->reauth->e[val].u.c.cipher = ctext->cipher;
5037                 text->reauth->e[val].u.c.server_maxbuf = ctext->server_maxbuf;
5038             }
5039 #ifndef _SUN_SDK_
5040             else {
5041                 /* reauth, we already incremented nonce_count */
5042             }
5043 #endif /* !_SUN_SDK_ */
5044             break;
5045         default:
5046             if (text->nonce_count > 1) {
5047                 /* failed reauth, clear cache */
5048                 clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
5049             }
5050             else {
5051                 /* failed initial auth, leave existing cache */
5052             }
5053         }
5054         params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
5055     }
5056 
5057     return result;
5058 }
5059 
5060 static int
5061 digestmd5_client_mech_step(void *conn_context,
5062                            sasl_client_params_t *params,
5063                            const char *serverin,
5064                            unsigned serverinlen,
5065                            sasl_interact_t **prompt_need,
5066                            const char **clientout,
5067                            unsigned *clientoutlen,
5068                            sasl_out_params_t *oparams)
5069 {
5070     context_t *text = (context_t *) conn_context;
5071     client_context_t *ctext = (client_context_t *) conn_context;
5072     unsigned val = hash(params->serverFQDN) % text->reauth->size;
5073     
5074     if (serverinlen > 2048) return SASL_BADPROT;
5075     
5076     *clientout = NULL;
5077     *clientoutlen = 0;
5078 
5079     switch (text->state) {
5080 
5081     case 1:
5082         if (!serverin) {
5083             /* here's where we attempt fast reauth if possible */
5084             int reauth = 0;
5085 
5086             /* check if we have saved info for this server */
5087             if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
5088                 reauth = text->reauth->e[val].u.c.serverFQDN &&
5089                     !strcasecmp(text->reauth->e[val].u.c.serverFQDN,
5090                                 params->serverFQDN);
5091                 params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
5092             }
5093             if (reauth) {
5094                 return digestmd5_client_mech_step1(ctext, params,
5095                                                    serverin, serverinlen,
5096                                                    prompt_need,
5097                                                    clientout, clientoutlen,
5098                                                    oparams);
5099             }
5100             else {
5101                 /* we don't have any reauth info, so just return
5102                  * that there is no initial client send */
5103                 text->state = 2;
5104                 return SASL_CONTINUE;
5105             }
5106         }
5107         
5108         /* fall through and respond to challenge */
5109         
5110     case 3:
5111         if (serverin && !strncasecmp(serverin, "rspauth=", 8)) {
5112             return digestmd5_client_mech_step3(ctext, params,
5113                                                serverin, serverinlen,
5114                                                prompt_need,
5115                                                clientout, clientoutlen,
5116                                                oparams);
5117         }
5118 
5119         /* fall through and respond to challenge */
5120         text->state = 2;
5121 
5122         /* cleanup after a failed reauth attempt */
5123         if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
5124             clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
5125 
5126             params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
5127         }
5128 
5129         if (text->realm) params->utils->free(text->realm);
5130         if (text->nonce) params->utils->free(text->nonce);
5131         if (text->cnonce) params->utils->free(text->cnonce);
5132 #ifdef _SUN_SDK_
5133         text->realm = NULL;
5134         text->nonce = text->cnonce = NULL;
5135 #else
5136         text->realm = text->nonce = text->cnonce = NULL;
5137 #endif /* _SUN_SDK_ */
5138         ctext->cipher = NULL;
5139     
5140     case 2:
5141         return digestmd5_client_mech_step2(ctext, params,
5142                                            serverin, serverinlen,
5143                                            prompt_need,
5144                                            clientout, clientoutlen,
5145                                            oparams);
5146 
5147     default:
5148 #ifdef _SUN_SDK_
5149         params->utils->log(params->utils->conn, SASL_LOG_ERR,
5150                            "Invalid DIGEST-MD5 client step %d", text->state);
5151 #else
5152         params->utils->log(NULL, SASL_LOG_ERR,
5153                            "Invalid DIGEST-MD5 client step %d\n", text->state);
5154 #endif /* _SUN_SDK_ */
5155         return SASL_FAIL;
5156     }
5157     
5158     return SASL_FAIL; /* should never get here */
5159 }
5160 
5161 static void
5162 digestmd5_client_mech_dispose(void *conn_context, const sasl_utils_t *utils)
5163 {
5164     client_context_t *ctext = (client_context_t *) conn_context;
5165     
5166     if (!ctext || !utils) return;
5167     
5168 #ifdef _INTEGRATED_SOLARIS_
5169     convert_prompt(utils, &ctext->h, NULL);
5170 #endif /* _INTEGRATED_SOLARIS_ */
5171 
5172     if (ctext->free_password) _plug_free_secret(utils, &ctext->password);
5173 
5174     digestmd5_common_mech_dispose(conn_context, utils);
5175 }
5176 
5177 static sasl_client_plug_t digestmd5_client_plugins[] =
5178 {
5179     {
5180         "DIGEST-MD5",
5181         /* EXPORT DELETE START */
5182 #ifdef WITH_RC4                         /* mech_name */
5183         128,                            /* max ssf */
5184 #elif WITH_DES
5185         112,
5186 #else
5187         /* EXPORT DELETE END */
5188         0,
5189         /* EXPORT DELETE START */
5190 #endif
5191         /* EXPORT DELETE END */
5192         SASL_SEC_NOPLAINTEXT
5193         | SASL_SEC_NOANONYMOUS
5194         | SASL_SEC_MUTUAL_AUTH,         /* security_flags */
5195         SASL_FEAT_ALLOWS_PROXY,         /* features */
5196         NULL,                           /* required_prompts */
5197         NULL,                           /* glob_context */
5198         &digestmd5_client_mech_new, /* mech_new */
5199         &digestmd5_client_mech_step,        /* mech_step */
5200         &digestmd5_client_mech_dispose,     /* mech_dispose */
5201         &digestmd5_common_mech_free,        /* mech_free */
5202         NULL,                           /* idle */
5203         NULL,                           /* spare1 */
5204         NULL                            /* spare2 */
5205     }
5206 };
5207 
5208 int digestmd5_client_plug_init(sasl_utils_t *utils,
5209                                int maxversion,
5210                                int *out_version,
5211                                sasl_client_plug_t **pluglist,
5212                                int *plugcount)
5213 {
5214     reauth_cache_t *reauth_cache;
5215 #if defined _SUN_SDK_  && defined USE_UEF
5216     int ret;
5217 #endif /* _SUN_SDK_ && USE_UEF */
5218 
5219     if (maxversion < SASL_CLIENT_PLUG_VERSION)
5220         return SASL_BADVERS;
5221     
5222 #if defined _SUN_SDK_  && defined USE_UEF
5223     if ((ret = uef_init(utils)) != SASL_OK)
5224         return ret;
5225 #endif /* _SUN_SDK_ && USE_UEF */
5226 
5227     /* reauth cache */
5228     reauth_cache = utils->malloc(sizeof(reauth_cache_t));
5229     if (reauth_cache == NULL)
5230         return SASL_NOMEM;
5231     memset(reauth_cache, 0, sizeof(reauth_cache_t));
5232     reauth_cache->i_am = CLIENT;
5233     
5234     /* mutex */
5235     reauth_cache->mutex = utils->mutex_alloc();
5236     if (!reauth_cache->mutex)
5237         return SASL_FAIL;
5238 
5239     /* entries */
5240     reauth_cache->size = 10;
5241     reauth_cache->e = utils->malloc(reauth_cache->size *
5242                                     sizeof(reauth_entry_t));
5243     if (reauth_cache->e == NULL)
5244         return SASL_NOMEM;
5245     memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t));
5246 
5247     digestmd5_client_plugins[0].glob_context = reauth_cache;
5248 #ifdef _SUN_SDK_
5249 #ifdef USE_UEF_CLIENT
5250     digestmd5_client_plugins[0].max_ssf = uef_max_ssf;
5251 #endif /* USE_UEF_CLIENT */
5252 #endif /* _SUN_SDK_ */
5253 
5254     /* EXPORT DELETE START */
5255     /* CRYPT DELETE START */
5256 #ifdef _INTEGRATED_SOLARIS_
5257     /*
5258      * Let libsasl know that we are a "Sun" plugin so that privacy
5259      * and integrity will be allowed.
5260      */
5261     REG_PLUG("DIGEST-MD5", digestmd5_client_plugins);
5262 #endif /* _INTEGRATED_SOLARIS_ */
5263     /* CRYPT DELETE END */
5264     /* EXPORT DELETE END */
5265 
5266     *out_version = SASL_CLIENT_PLUG_VERSION;
5267     *pluglist = digestmd5_client_plugins;
5268     *plugcount = 1;
5269     
5270     return SASL_OK;
5271 }
5272 
5273 #ifdef _SUN_SDK_
5274 #ifdef USE_UEF
5275 /* If we fail here - we should just not offer privacy or integrity */
5276 static int
5277 getSlotID(const sasl_utils_t *utils, CK_MECHANISM_TYPE mech_type,
5278           CK_SLOT_ID *slot_id)
5279 {
5280     CK_RV rv;
5281     CK_ULONG ulSlotCount;
5282     CK_ULONG ulMechTypeCount;
5283     CK_SLOT_ID *pSlotList = NULL;
5284     CK_SLOT_ID slotID;
5285     CK_MECHANISM_TYPE_PTR pMechTypeList = NULL;
5286     int i, m;
5287 
5288     rv = C_GetSlotList(CK_FALSE, NULL_PTR, &ulSlotCount);
5289     if (rv != CKR_OK || ulSlotCount == 0) {
5290 #ifdef DEBUG
5291         utils->log(utils->conn, SASL_LOG_DEBUG,
5292                    "C_GetSlotList: 0x%.8X count:%d\n", rv, ulSlotCount);
5293 #endif
5294         return SASL_FAIL;
5295     }
5296 
5297     pSlotList = utils->calloc(sizeof (CK_SLOT_ID), ulSlotCount);
5298     if (pSlotList == NULL)
5299         return SASL_NOMEM;
5300 
5301     rv = C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount);
5302     if (rv != CKR_OK) {
5303 #ifdef DEBUG
5304         utils->log(utils->conn, SASL_LOG_DEBUG,
5305                    "C_GetSlotList: 0x%.8X count:%d\n", rv, ulSlotCount);
5306 #endif
5307         return SASL_FAIL;
5308     }
5309 
5310     for (i = 0; i < ulSlotCount; i++) {
5311         slotID = pSlotList[i];
5312         rv = C_GetMechanismList(slotID, NULL_PTR, &ulMechTypeCount);
5313         if (rv != CKR_OK) {
5314 #ifdef DEBUG
5315             utils->log(utils->conn, SASL_LOG_DEBUG,
5316                       "C_GetMechanismList returned 0x%.8X count:%d\n", rv,
5317                        ulMechTypeCount);
5318 #endif
5319             utils->free(pSlotList);
5320             return SASL_FAIL;
5321         }
5322         pMechTypeList =
5323                 utils->calloc(sizeof (CK_MECHANISM_TYPE), ulMechTypeCount);
5324         if (pMechTypeList == NULL_PTR) {
5325             utils->free(pSlotList);
5326             return SASL_NOMEM;
5327         }
5328         rv = C_GetMechanismList(slotID, pMechTypeList, &ulMechTypeCount);
5329         if (rv != CKR_OK) {
5330 #ifdef DEBUG
5331             utils->log(utils->conn, SASL_LOG_DEBUG,
5332                        "C_GetMechanismList returned 0x%.8X count:%d\n", rv,
5333                        ulMechTypeCount);
5334 #endif
5335             utils->free(pMechTypeList);
5336             utils->free(pSlotList);
5337             return SASL_FAIL;
5338         }
5339 
5340         for (m = 0; m < ulMechTypeCount; m++) {
5341             if (pMechTypeList[m] == mech_type)
5342                 break;
5343         }
5344         utils->free(pMechTypeList);
5345         pMechTypeList = NULL;
5346         if (m < ulMechTypeCount)
5347             break;
5348     }
5349     utils->free(pSlotList);
5350     if (i < ulSlotCount) {
5351         *slot_id = slotID;
5352         return SASL_OK;
5353     }
5354     return SASL_FAIL;
5355 }
5356 
5357 static int
5358 uef_init(const sasl_utils_t *utils)
5359 {
5360     int got_rc4;
5361     int got_des;
5362     int got_3des;
5363     int next_c;
5364     CK_RV rv;
5365 
5366     if (got_uef_slot)
5367         return (SASL_OK);
5368 
5369     if (LOCK_MUTEX(&uef_init_mutex) < 0)
5370         return (SASL_FAIL);
5371 
5372     rv = C_Initialize(NULL_PTR);
5373     if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
5374 #ifdef DEBUG
5375         utils->log(utils->conn, SASL_LOG_DEBUG,
5376                    "C_Initialize returned 0x%.8X\n", rv);
5377 #endif
5378         return SASL_FAIL;
5379     }
5380 
5381     got_rc4 = getSlotID(utils, CKM_RC4, &rc4_slot_id) == SASL_OK;
5382     if (!got_rc4)
5383         utils->log(utils->conn, SASL_LOG_WARN, "Could not get rc4");
5384 
5385     got_des = getSlotID(utils, CKM_DES_CBC, &des_slot_id) == SASL_OK;
5386     if (!got_des)
5387         utils->log(utils->conn, SASL_LOG_WARN, "Could not get des");
5388 
5389     got_3des = getSlotID(utils, CKM_DES3_CBC, &des3_slot_id) == SASL_OK;
5390     if (!got_3des)
5391         utils->log(utils->conn, SASL_LOG_WARN, "Could not get 3des");
5392 
5393     uef_max_ssf = got_rc4 ? 128 : got_3des ? 112 : got_des ? 55 : 0;
5394 
5395     /* adjust the available ciphers */
5396     next_c = (got_rc4) ? 3 : 0;
5397 
5398     if (got_des) {
5399         uef_ciphers[next_c].name = uef_ciphers[DES_CIPHER_INDEX].name;
5400         uef_ciphers[next_c].ssf = uef_ciphers[DES_CIPHER_INDEX].ssf;
5401         uef_ciphers[next_c].n = uef_ciphers[DES_CIPHER_INDEX].n;
5402         uef_ciphers[next_c].flag = uef_ciphers[DES_CIPHER_INDEX].flag;
5403         uef_ciphers[next_c].cipher_enc =
5404                 uef_ciphers[DES_CIPHER_INDEX].cipher_enc;
5405         uef_ciphers[next_c].cipher_dec =
5406                 uef_ciphers[DES_CIPHER_INDEX].cipher_dec;
5407         uef_ciphers[next_c].cipher_init =
5408                 uef_ciphers[DES_CIPHER_INDEX].cipher_init;
5409         next_c++;
5410     }
5411 
5412     if (got_3des) {
5413         uef_ciphers[next_c].name = uef_ciphers[DES3_CIPHER_INDEX].name;
5414         uef_ciphers[next_c].ssf = uef_ciphers[DES3_CIPHER_INDEX].ssf;
5415         uef_ciphers[next_c].n = uef_ciphers[DES3_CIPHER_INDEX].n;
5416         uef_ciphers[next_c].flag = uef_ciphers[DES3_CIPHER_INDEX].flag;
5417         uef_ciphers[next_c].cipher_enc =
5418                 uef_ciphers[DES3_CIPHER_INDEX].cipher_enc;
5419         uef_ciphers[next_c].cipher_dec =
5420                 uef_ciphers[DES3_CIPHER_INDEX].cipher_dec;
5421         uef_ciphers[next_c].cipher_init =
5422                 uef_ciphers[DES3_CIPHER_INDEX].cipher_init;
5423         next_c++;
5424     }
5425     uef_ciphers[next_c].name = NULL;
5426 
5427     got_uef_slot = TRUE;
5428     UNLOCK_MUTEX(&uef_init_mutex);
5429 
5430     return (SASL_OK);
5431 }
5432 #endif /* USE_UEF */
5433 #endif /* _SUN_SDK_ */