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