1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 6*7c478bd9Sstevel@tonic-gate 7*7c478bd9Sstevel@tonic-gate /* CRAM-MD5 SASL plugin 8*7c478bd9Sstevel@tonic-gate * Rob Siemborski 9*7c478bd9Sstevel@tonic-gate * Tim Martin 10*7c478bd9Sstevel@tonic-gate * $Id: cram.c,v 1.79 2003/02/18 18:27:37 rjs3 Exp $ 11*7c478bd9Sstevel@tonic-gate */ 12*7c478bd9Sstevel@tonic-gate /* 13*7c478bd9Sstevel@tonic-gate * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. 14*7c478bd9Sstevel@tonic-gate * 15*7c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 16*7c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions 17*7c478bd9Sstevel@tonic-gate * are met: 18*7c478bd9Sstevel@tonic-gate * 19*7c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 20*7c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 21*7c478bd9Sstevel@tonic-gate * 22*7c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 23*7c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in 24*7c478bd9Sstevel@tonic-gate * the documentation and/or other materials provided with the 25*7c478bd9Sstevel@tonic-gate * distribution. 26*7c478bd9Sstevel@tonic-gate * 27*7c478bd9Sstevel@tonic-gate * 3. The name "Carnegie Mellon University" must not be used to 28*7c478bd9Sstevel@tonic-gate * endorse or promote products derived from this software without 29*7c478bd9Sstevel@tonic-gate * prior written permission. For permission or any other legal 30*7c478bd9Sstevel@tonic-gate * details, please contact 31*7c478bd9Sstevel@tonic-gate * Office of Technology Transfer 32*7c478bd9Sstevel@tonic-gate * Carnegie Mellon University 33*7c478bd9Sstevel@tonic-gate * 5000 Forbes Avenue 34*7c478bd9Sstevel@tonic-gate * Pittsburgh, PA 15213-3890 35*7c478bd9Sstevel@tonic-gate * (412) 268-4387, fax: (412) 268-7395 36*7c478bd9Sstevel@tonic-gate * tech-transfer@andrew.cmu.edu 37*7c478bd9Sstevel@tonic-gate * 38*7c478bd9Sstevel@tonic-gate * 4. Redistributions of any form whatsoever must retain the following 39*7c478bd9Sstevel@tonic-gate * acknowledgment: 40*7c478bd9Sstevel@tonic-gate * "This product includes software developed by Computing Services 41*7c478bd9Sstevel@tonic-gate * at Carnegie Mellon University (http://www.cmu.edu/computing/)." 42*7c478bd9Sstevel@tonic-gate * 43*7c478bd9Sstevel@tonic-gate * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO 44*7c478bd9Sstevel@tonic-gate * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 45*7c478bd9Sstevel@tonic-gate * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 46*7c478bd9Sstevel@tonic-gate * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 47*7c478bd9Sstevel@tonic-gate * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 48*7c478bd9Sstevel@tonic-gate * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 49*7c478bd9Sstevel@tonic-gate * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 50*7c478bd9Sstevel@tonic-gate */ 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate #include <config.h> 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate #include <string.h> 55*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 56*7c478bd9Sstevel@tonic-gate #include <stdio.h> 57*7c478bd9Sstevel@tonic-gate #ifndef macintosh 58*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 59*7c478bd9Sstevel@tonic-gate #endif 60*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate #include <sasl.h> 63*7c478bd9Sstevel@tonic-gate #include <saslplug.h> 64*7c478bd9Sstevel@tonic-gate #include <saslutil.h> 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_ 67*7c478bd9Sstevel@tonic-gate #include <unistd.h> 68*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate #include "plugin_common.h" 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate #ifdef macintosh 73*7c478bd9Sstevel@tonic-gate #include <sasl_cram_plugin_decl.h> 74*7c478bd9Sstevel@tonic-gate #endif 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate /***************************** Common Section *****************************/ 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_ 79*7c478bd9Sstevel@tonic-gate static const char plugin_id[] = "$Id: cram.c,v 1.79 2003/02/18 18:27:37 rjs3 Exp $"; 80*7c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */ 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate /* convert a string of 8bit chars to it's representation in hex 83*7c478bd9Sstevel@tonic-gate * using lowercase letters 84*7c478bd9Sstevel@tonic-gate */ 85*7c478bd9Sstevel@tonic-gate static char *convert16(unsigned char *in, int inlen, const sasl_utils_t *utils) 86*7c478bd9Sstevel@tonic-gate { 87*7c478bd9Sstevel@tonic-gate static char hex[]="0123456789abcdef"; 88*7c478bd9Sstevel@tonic-gate int lup; 89*7c478bd9Sstevel@tonic-gate char *out; 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate out = utils->malloc(inlen*2+1); 92*7c478bd9Sstevel@tonic-gate if (out == NULL) return NULL; 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate for (lup=0; lup < inlen; lup++) { 95*7c478bd9Sstevel@tonic-gate out[lup*2] = hex[in[lup] >> 4]; 96*7c478bd9Sstevel@tonic-gate out[lup*2+1] = hex[in[lup] & 15]; 97*7c478bd9Sstevel@tonic-gate } 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate out[lup*2] = 0; 100*7c478bd9Sstevel@tonic-gate return out; 101*7c478bd9Sstevel@tonic-gate } 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate /***************************** Server Section *****************************/ 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate typedef struct server_context { 107*7c478bd9Sstevel@tonic-gate int state; 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate char *challenge; 110*7c478bd9Sstevel@tonic-gate } server_context_t; 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate static int 113*7c478bd9Sstevel@tonic-gate crammd5_server_mech_new(void *glob_context __attribute__((unused)), 114*7c478bd9Sstevel@tonic-gate sasl_server_params_t *sparams, 115*7c478bd9Sstevel@tonic-gate const char *challenge __attribute__((unused)), 116*7c478bd9Sstevel@tonic-gate unsigned challen __attribute__((unused)), 117*7c478bd9Sstevel@tonic-gate void **conn_context) 118*7c478bd9Sstevel@tonic-gate { 119*7c478bd9Sstevel@tonic-gate server_context_t *text; 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate /* holds state are in */ 122*7c478bd9Sstevel@tonic-gate text = sparams->utils->malloc(sizeof(server_context_t)); 123*7c478bd9Sstevel@tonic-gate if (text == NULL) { 124*7c478bd9Sstevel@tonic-gate MEMERROR( sparams->utils ); 125*7c478bd9Sstevel@tonic-gate return SASL_NOMEM; 126*7c478bd9Sstevel@tonic-gate } 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate memset(text, 0, sizeof(server_context_t)); 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate text->state = 1; 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate *conn_context = text; 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate return SASL_OK; 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate /* 138*7c478bd9Sstevel@tonic-gate * Returns the current time (or part of it) in string form 139*7c478bd9Sstevel@tonic-gate * maximum length=15 140*7c478bd9Sstevel@tonic-gate */ 141*7c478bd9Sstevel@tonic-gate static char *gettime(sasl_server_params_t *sparams) 142*7c478bd9Sstevel@tonic-gate { 143*7c478bd9Sstevel@tonic-gate char *ret; 144*7c478bd9Sstevel@tonic-gate time_t t; 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate t=time(NULL); 147*7c478bd9Sstevel@tonic-gate ret= sparams->utils->malloc(15); 148*7c478bd9Sstevel@tonic-gate if (ret==NULL) return NULL; 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate /* the bottom bits are really the only random ones so if 151*7c478bd9Sstevel@tonic-gate we overflow we don't want to loose them */ 152*7c478bd9Sstevel@tonic-gate snprintf(ret,15,"%lu",t%(0xFFFFFF)); 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate return ret; 155*7c478bd9Sstevel@tonic-gate } 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate static char *randomdigits(sasl_server_params_t *sparams) 158*7c478bd9Sstevel@tonic-gate { 159*7c478bd9Sstevel@tonic-gate unsigned int num; 160*7c478bd9Sstevel@tonic-gate char *ret; 161*7c478bd9Sstevel@tonic-gate unsigned char temp[5]; /* random 32-bit number */ 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate #if defined _DEV_URANDOM && defined _SUN_SDK_ 164*7c478bd9Sstevel@tonic-gate { 165*7c478bd9Sstevel@tonic-gate int fd = open(_DEV_URANDOM, O_RDONLY); 166*7c478bd9Sstevel@tonic-gate int nread = 0; 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate if (fd != -1) { 169*7c478bd9Sstevel@tonic-gate nread = read(fd, temp, 4); 170*7c478bd9Sstevel@tonic-gate close(fd); 171*7c478bd9Sstevel@tonic-gate } 172*7c478bd9Sstevel@tonic-gate if (nread != 4) 173*7c478bd9Sstevel@tonic-gate sparams->utils->rand(sparams->utils->rpool, 174*7c478bd9Sstevel@tonic-gate (char *) temp, 4); 175*7c478bd9Sstevel@tonic-gate } 176*7c478bd9Sstevel@tonic-gate #else 177*7c478bd9Sstevel@tonic-gate sparams->utils->rand(sparams->utils->rpool,(char *) temp,4); 178*7c478bd9Sstevel@tonic-gate #endif /* _DEV_URANDOM && _SUN_SDK_ */ 179*7c478bd9Sstevel@tonic-gate num=(temp[0] * 256 * 256 * 256) + 180*7c478bd9Sstevel@tonic-gate (temp[1] * 256 * 256) + 181*7c478bd9Sstevel@tonic-gate (temp[2] * 256) + 182*7c478bd9Sstevel@tonic-gate (temp[3] ); 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate ret = sparams->utils->malloc(15); /* there's no way an unsigned can be longer than this right? */ 185*7c478bd9Sstevel@tonic-gate if (ret == NULL) return NULL; 186*7c478bd9Sstevel@tonic-gate sprintf(ret, "%u", num); 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate return ret; 189*7c478bd9Sstevel@tonic-gate } 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate static int 192*7c478bd9Sstevel@tonic-gate crammd5_server_mech_step1(server_context_t *text, 193*7c478bd9Sstevel@tonic-gate sasl_server_params_t *sparams, 194*7c478bd9Sstevel@tonic-gate const char *clientin __attribute__((unused)), 195*7c478bd9Sstevel@tonic-gate unsigned clientinlen, 196*7c478bd9Sstevel@tonic-gate const char **serverout, 197*7c478bd9Sstevel@tonic-gate unsigned *serveroutlen, 198*7c478bd9Sstevel@tonic-gate sasl_out_params_t *oparams __attribute__((unused))) 199*7c478bd9Sstevel@tonic-gate { 200*7c478bd9Sstevel@tonic-gate char *time, *randdigits; 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate /* we shouldn't have received anything */ 203*7c478bd9Sstevel@tonic-gate if (clientinlen != 0) { 204*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_ 205*7c478bd9Sstevel@tonic-gate sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR, 206*7c478bd9Sstevel@tonic-gate "CRAM-MD5 does not accept inital data"); 207*7c478bd9Sstevel@tonic-gate #else 208*7c478bd9Sstevel@tonic-gate SETERROR(sparams->utils, "CRAM-MD5 does not accpet inital data"); 209*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 210*7c478bd9Sstevel@tonic-gate return SASL_BADPROT; 211*7c478bd9Sstevel@tonic-gate } 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate /* get time and a random number for the nonce */ 214*7c478bd9Sstevel@tonic-gate time = gettime(sparams); 215*7c478bd9Sstevel@tonic-gate randdigits = randomdigits(sparams); 216*7c478bd9Sstevel@tonic-gate if ((time == NULL) || (randdigits == NULL)) { 217*7c478bd9Sstevel@tonic-gate MEMERROR( sparams->utils ); 218*7c478bd9Sstevel@tonic-gate return SASL_NOMEM; 219*7c478bd9Sstevel@tonic-gate } 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate /* allocate some space for the challenge */ 222*7c478bd9Sstevel@tonic-gate text->challenge = sparams->utils->malloc(200 + 1); 223*7c478bd9Sstevel@tonic-gate if (text->challenge == NULL) { 224*7c478bd9Sstevel@tonic-gate MEMERROR(sparams->utils); 225*7c478bd9Sstevel@tonic-gate return SASL_NOMEM; 226*7c478bd9Sstevel@tonic-gate } 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate /* create the challenge */ 229*7c478bd9Sstevel@tonic-gate snprintf(text->challenge, 200, "<%s.%s@%s>", randdigits, time, 230*7c478bd9Sstevel@tonic-gate sparams->serverFQDN); 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate *serverout = text->challenge; 233*7c478bd9Sstevel@tonic-gate *serveroutlen = strlen(text->challenge); 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate /* free stuff */ 236*7c478bd9Sstevel@tonic-gate sparams->utils->free(time); 237*7c478bd9Sstevel@tonic-gate sparams->utils->free(randdigits); 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate text->state = 2; 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate return SASL_CONTINUE; 242*7c478bd9Sstevel@tonic-gate } 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate static int 245*7c478bd9Sstevel@tonic-gate crammd5_server_mech_step2(server_context_t *text, 246*7c478bd9Sstevel@tonic-gate sasl_server_params_t *sparams, 247*7c478bd9Sstevel@tonic-gate const char *clientin, 248*7c478bd9Sstevel@tonic-gate unsigned clientinlen, 249*7c478bd9Sstevel@tonic-gate const char **serverout __attribute__((unused)), 250*7c478bd9Sstevel@tonic-gate unsigned *serveroutlen __attribute__((unused)), 251*7c478bd9Sstevel@tonic-gate sasl_out_params_t *oparams) 252*7c478bd9Sstevel@tonic-gate { 253*7c478bd9Sstevel@tonic-gate char *userid = NULL; 254*7c478bd9Sstevel@tonic-gate sasl_secret_t *sec = NULL; 255*7c478bd9Sstevel@tonic-gate int pos, len; 256*7c478bd9Sstevel@tonic-gate int result = SASL_FAIL; 257*7c478bd9Sstevel@tonic-gate const char *password_request[] = { SASL_AUX_PASSWORD, 258*7c478bd9Sstevel@tonic-gate "*cmusaslsecretCRAM-MD5", 259*7c478bd9Sstevel@tonic-gate NULL }; 260*7c478bd9Sstevel@tonic-gate struct propval auxprop_values[3]; 261*7c478bd9Sstevel@tonic-gate HMAC_MD5_CTX tmphmac; 262*7c478bd9Sstevel@tonic-gate HMAC_MD5_STATE md5state; 263*7c478bd9Sstevel@tonic-gate int clear_md5state = 0; 264*7c478bd9Sstevel@tonic-gate char *digest_str = NULL; 265*7c478bd9Sstevel@tonic-gate UINT4 digest[4]; 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate /* extract userid; everything before last space */ 268*7c478bd9Sstevel@tonic-gate pos = clientinlen-1; 269*7c478bd9Sstevel@tonic-gate while ((pos > 0) && (clientin[pos] != ' ')) pos--; 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate if (pos <= 0) { 272*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_ 273*7c478bd9Sstevel@tonic-gate sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR, 274*7c478bd9Sstevel@tonic-gate "need authentication name"); 275*7c478bd9Sstevel@tonic-gate #else 276*7c478bd9Sstevel@tonic-gate SETERROR( sparams->utils,"need authentication name"); 277*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 278*7c478bd9Sstevel@tonic-gate return SASL_BADPROT; 279*7c478bd9Sstevel@tonic-gate } 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate userid = (char *) sparams->utils->malloc(pos+1); 282*7c478bd9Sstevel@tonic-gate if (userid == NULL) { 283*7c478bd9Sstevel@tonic-gate MEMERROR( sparams->utils); 284*7c478bd9Sstevel@tonic-gate return SASL_NOMEM; 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate /* copy authstr out */ 288*7c478bd9Sstevel@tonic-gate memcpy(userid, clientin, pos); 289*7c478bd9Sstevel@tonic-gate userid[pos] = '\0'; 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate result = sparams->utils->prop_request(sparams->propctx, password_request); 292*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) goto done; 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate /* this will trigger the getting of the aux properties */ 295*7c478bd9Sstevel@tonic-gate result = sparams->canon_user(sparams->utils->conn, 296*7c478bd9Sstevel@tonic-gate userid, 0, SASL_CU_AUTHID | SASL_CU_AUTHZID, 297*7c478bd9Sstevel@tonic-gate oparams); 298*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) goto done; 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate result = sparams->utils->prop_getnames(sparams->propctx, 301*7c478bd9Sstevel@tonic-gate password_request, 302*7c478bd9Sstevel@tonic-gate auxprop_values); 303*7c478bd9Sstevel@tonic-gate if (result < 0 || 304*7c478bd9Sstevel@tonic-gate ((!auxprop_values[0].name || !auxprop_values[0].values) && 305*7c478bd9Sstevel@tonic-gate (!auxprop_values[1].name || !auxprop_values[1].values))) { 306*7c478bd9Sstevel@tonic-gate /* We didn't find this username */ 307*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_ 308*7c478bd9Sstevel@tonic-gate sparams->utils->seterror(sparams->utils->conn,0, 309*7c478bd9Sstevel@tonic-gate gettext("no secret in database")); 310*7c478bd9Sstevel@tonic-gate #else 311*7c478bd9Sstevel@tonic-gate sparams->utils->seterror(sparams->utils->conn,0, 312*7c478bd9Sstevel@tonic-gate "no secret in database"); 313*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */ 314*7c478bd9Sstevel@tonic-gate result = SASL_NOUSER; 315*7c478bd9Sstevel@tonic-gate goto done; 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate if (auxprop_values[0].name && auxprop_values[0].values) { 319*7c478bd9Sstevel@tonic-gate len = strlen(auxprop_values[0].values[0]); 320*7c478bd9Sstevel@tonic-gate if (len == 0) { 321*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_ 322*7c478bd9Sstevel@tonic-gate sparams->utils->seterror(sparams->utils->conn,0, 323*7c478bd9Sstevel@tonic-gate gettext("empty secret")); 324*7c478bd9Sstevel@tonic-gate #else 325*7c478bd9Sstevel@tonic-gate sparams->utils->seterror(sparams->utils->conn,0, 326*7c478bd9Sstevel@tonic-gate "empty secret"); 327*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */ 328*7c478bd9Sstevel@tonic-gate result = SASL_FAIL; 329*7c478bd9Sstevel@tonic-gate goto done; 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate sec = sparams->utils->malloc(sizeof(sasl_secret_t) + len); 333*7c478bd9Sstevel@tonic-gate if (!sec) goto done; 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate sec->len = len; 336*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_ 337*7c478bd9Sstevel@tonic-gate strncpy((char *)sec->data, auxprop_values[0].values[0], len + 1); 338*7c478bd9Sstevel@tonic-gate #else 339*7c478bd9Sstevel@tonic-gate strncpy(sec->data, auxprop_values[0].values[0], len + 1); 340*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate clear_md5state = 1; 343*7c478bd9Sstevel@tonic-gate /* Do precalculation on plaintext secret */ 344*7c478bd9Sstevel@tonic-gate sparams->utils->hmac_md5_precalc(&md5state, /* OUT */ 345*7c478bd9Sstevel@tonic-gate sec->data, 346*7c478bd9Sstevel@tonic-gate sec->len); 347*7c478bd9Sstevel@tonic-gate } else if (auxprop_values[1].name && auxprop_values[1].values) { 348*7c478bd9Sstevel@tonic-gate /* We have a precomputed secret */ 349*7c478bd9Sstevel@tonic-gate memcpy(&md5state, auxprop_values[1].values[0], 350*7c478bd9Sstevel@tonic-gate sizeof(HMAC_MD5_STATE)); 351*7c478bd9Sstevel@tonic-gate } else { 352*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_ 353*7c478bd9Sstevel@tonic-gate sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR, 354*7c478bd9Sstevel@tonic-gate "Have neither type of secret"); 355*7c478bd9Sstevel@tonic-gate #else 356*7c478bd9Sstevel@tonic-gate sparams->utils->seterror(sparams->utils->conn, 0, 357*7c478bd9Sstevel@tonic-gate "Have neither type of secret"); 358*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 359*7c478bd9Sstevel@tonic-gate return SASL_FAIL; 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate /* ok this is annoying: 363*7c478bd9Sstevel@tonic-gate so we have this half-way hmac transform instead of the plaintext 364*7c478bd9Sstevel@tonic-gate that means we half to: 365*7c478bd9Sstevel@tonic-gate -import it back into a md5 context 366*7c478bd9Sstevel@tonic-gate -do an md5update with the nonce 367*7c478bd9Sstevel@tonic-gate -finalize it 368*7c478bd9Sstevel@tonic-gate */ 369*7c478bd9Sstevel@tonic-gate sparams->utils->hmac_md5_import(&tmphmac, (HMAC_MD5_STATE *) &md5state); 370*7c478bd9Sstevel@tonic-gate sparams->utils->MD5Update(&(tmphmac.ictx), 371*7c478bd9Sstevel@tonic-gate (const unsigned char *) text->challenge, 372*7c478bd9Sstevel@tonic-gate strlen(text->challenge)); 373*7c478bd9Sstevel@tonic-gate sparams->utils->hmac_md5_final((unsigned char *) &digest, &tmphmac); 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate /* convert to base 16 with lower case letters */ 376*7c478bd9Sstevel@tonic-gate digest_str = convert16((unsigned char *) digest, 16, sparams->utils); 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate /* if same then verified 379*7c478bd9Sstevel@tonic-gate * - we know digest_str is null terminated but clientin might not be 380*7c478bd9Sstevel@tonic-gate */ 381*7c478bd9Sstevel@tonic-gate if (strncmp(digest_str, clientin+pos+1, strlen(digest_str)) != 0) { 382*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_ 383*7c478bd9Sstevel@tonic-gate sparams->utils->seterror(sparams->utils->conn, 0, 384*7c478bd9Sstevel@tonic-gate gettext("incorrect digest response")); 385*7c478bd9Sstevel@tonic-gate #else 386*7c478bd9Sstevel@tonic-gate sparams->utils->seterror(sparams->utils->conn, 0, 387*7c478bd9Sstevel@tonic-gate "incorrect digest response"); 388*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */ 389*7c478bd9Sstevel@tonic-gate result = SASL_BADAUTH; 390*7c478bd9Sstevel@tonic-gate goto done; 391*7c478bd9Sstevel@tonic-gate } 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate /* set oparams */ 394*7c478bd9Sstevel@tonic-gate oparams->doneflag = 1; 395*7c478bd9Sstevel@tonic-gate oparams->mech_ssf = 0; 396*7c478bd9Sstevel@tonic-gate oparams->maxoutbuf = 0; 397*7c478bd9Sstevel@tonic-gate oparams->encode_context = NULL; 398*7c478bd9Sstevel@tonic-gate oparams->encode = NULL; 399*7c478bd9Sstevel@tonic-gate oparams->decode_context = NULL; 400*7c478bd9Sstevel@tonic-gate oparams->decode = NULL; 401*7c478bd9Sstevel@tonic-gate oparams->param_version = 0; 402*7c478bd9Sstevel@tonic-gate 403*7c478bd9Sstevel@tonic-gate result = SASL_OK; 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate done: 406*7c478bd9Sstevel@tonic-gate if (userid) sparams->utils->free(userid); 407*7c478bd9Sstevel@tonic-gate if (sec) _plug_free_secret(sparams->utils, &sec); 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate if (digest_str) sparams->utils->free(digest_str); 410*7c478bd9Sstevel@tonic-gate if (clear_md5state) memset(&md5state, 0, sizeof(md5state)); 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate return result; 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate static int crammd5_server_mech_step(void *conn_context, 416*7c478bd9Sstevel@tonic-gate sasl_server_params_t *sparams, 417*7c478bd9Sstevel@tonic-gate const char *clientin, 418*7c478bd9Sstevel@tonic-gate unsigned clientinlen, 419*7c478bd9Sstevel@tonic-gate const char **serverout, 420*7c478bd9Sstevel@tonic-gate unsigned *serveroutlen, 421*7c478bd9Sstevel@tonic-gate sasl_out_params_t *oparams) 422*7c478bd9Sstevel@tonic-gate { 423*7c478bd9Sstevel@tonic-gate server_context_t *text = (server_context_t *) conn_context; 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate *serverout = NULL; 426*7c478bd9Sstevel@tonic-gate *serveroutlen = 0; 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate /* this should be well more than is ever needed */ 429*7c478bd9Sstevel@tonic-gate if (clientinlen > 1024) { 430*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_ 431*7c478bd9Sstevel@tonic-gate sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR, 432*7c478bd9Sstevel@tonic-gate "CRAM-MD5 input longer than 1024 bytes"); 433*7c478bd9Sstevel@tonic-gate #else 434*7c478bd9Sstevel@tonic-gate SETERROR(sparams->utils, "CRAM-MD5 input longer than 1024 bytes"); 435*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 436*7c478bd9Sstevel@tonic-gate return SASL_BADPROT; 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate switch (text->state) { 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate case 1: 442*7c478bd9Sstevel@tonic-gate return crammd5_server_mech_step1(text, sparams, 443*7c478bd9Sstevel@tonic-gate clientin, clientinlen, 444*7c478bd9Sstevel@tonic-gate serverout, serveroutlen, 445*7c478bd9Sstevel@tonic-gate oparams); 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate case 2: 448*7c478bd9Sstevel@tonic-gate return crammd5_server_mech_step2(text, sparams, 449*7c478bd9Sstevel@tonic-gate clientin, clientinlen, 450*7c478bd9Sstevel@tonic-gate serverout, serveroutlen, 451*7c478bd9Sstevel@tonic-gate oparams); 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate default: /* should never get here */ 454*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_ 455*7c478bd9Sstevel@tonic-gate sparams->utils->log(sparams->utils->conn, SASL_LOG_ERR, 456*7c478bd9Sstevel@tonic-gate "Invalid CRAM-MD5 server step %d", text->state); 457*7c478bd9Sstevel@tonic-gate #else 458*7c478bd9Sstevel@tonic-gate sparams->utils->log(NULL, SASL_LOG_ERR, 459*7c478bd9Sstevel@tonic-gate "Invalid CRAM-MD5 server step %d\n", text->state); 460*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 461*7c478bd9Sstevel@tonic-gate return SASL_FAIL; 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_ 465*7c478bd9Sstevel@tonic-gate return SASL_FAIL; /* should never get here */ 466*7c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */ 467*7c478bd9Sstevel@tonic-gate } 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate static void crammd5_server_mech_dispose(void *conn_context, 470*7c478bd9Sstevel@tonic-gate const sasl_utils_t *utils) 471*7c478bd9Sstevel@tonic-gate { 472*7c478bd9Sstevel@tonic-gate server_context_t *text = (server_context_t *) conn_context; 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate if (!text) return; 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate if (text->challenge) _plug_free_string(utils,&(text->challenge)); 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate utils->free(text); 479*7c478bd9Sstevel@tonic-gate } 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate static sasl_server_plug_t crammd5_server_plugins[] = 482*7c478bd9Sstevel@tonic-gate { 483*7c478bd9Sstevel@tonic-gate { 484*7c478bd9Sstevel@tonic-gate "CRAM-MD5", /* mech_name */ 485*7c478bd9Sstevel@tonic-gate 0, /* max_ssf */ 486*7c478bd9Sstevel@tonic-gate SASL_SEC_NOPLAINTEXT 487*7c478bd9Sstevel@tonic-gate | SASL_SEC_NOANONYMOUS, /* security_flags */ 488*7c478bd9Sstevel@tonic-gate SASL_FEAT_SERVER_FIRST, /* features */ 489*7c478bd9Sstevel@tonic-gate NULL, /* glob_context */ 490*7c478bd9Sstevel@tonic-gate &crammd5_server_mech_new, /* mech_new */ 491*7c478bd9Sstevel@tonic-gate &crammd5_server_mech_step, /* mech_step */ 492*7c478bd9Sstevel@tonic-gate &crammd5_server_mech_dispose, /* mech_dispose */ 493*7c478bd9Sstevel@tonic-gate NULL, /* mech_free */ 494*7c478bd9Sstevel@tonic-gate NULL, /* setpass */ 495*7c478bd9Sstevel@tonic-gate NULL, /* user_query */ 496*7c478bd9Sstevel@tonic-gate NULL, /* idle */ 497*7c478bd9Sstevel@tonic-gate NULL, /* mech avail */ 498*7c478bd9Sstevel@tonic-gate NULL /* spare */ 499*7c478bd9Sstevel@tonic-gate } 500*7c478bd9Sstevel@tonic-gate }; 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate int crammd5_server_plug_init(const sasl_utils_t *utils, 503*7c478bd9Sstevel@tonic-gate int maxversion, 504*7c478bd9Sstevel@tonic-gate int *out_version, 505*7c478bd9Sstevel@tonic-gate sasl_server_plug_t **pluglist, 506*7c478bd9Sstevel@tonic-gate int *plugcount) 507*7c478bd9Sstevel@tonic-gate { 508*7c478bd9Sstevel@tonic-gate if (maxversion < SASL_SERVER_PLUG_VERSION) { 509*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_ 510*7c478bd9Sstevel@tonic-gate utils->log(NULL, SASL_LOG_ERR, "CRAM version mismatch"); 511*7c478bd9Sstevel@tonic-gate #else 512*7c478bd9Sstevel@tonic-gate SETERROR( utils, "CRAM version mismatch"); 513*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 514*7c478bd9Sstevel@tonic-gate return SASL_BADVERS; 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate *out_version = SASL_SERVER_PLUG_VERSION; 518*7c478bd9Sstevel@tonic-gate *pluglist = crammd5_server_plugins; 519*7c478bd9Sstevel@tonic-gate *plugcount = 1; 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate return SASL_OK; 522*7c478bd9Sstevel@tonic-gate } 523*7c478bd9Sstevel@tonic-gate 524*7c478bd9Sstevel@tonic-gate /***************************** Client Section *****************************/ 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate typedef struct client_context { 527*7c478bd9Sstevel@tonic-gate char *out_buf; 528*7c478bd9Sstevel@tonic-gate unsigned out_buf_len; 529*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_ 530*7c478bd9Sstevel@tonic-gate void *h; 531*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */ 532*7c478bd9Sstevel@tonic-gate } client_context_t; 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate static int crammd5_client_mech_new(void *glob_context __attribute__((unused)), 535*7c478bd9Sstevel@tonic-gate sasl_client_params_t *params, 536*7c478bd9Sstevel@tonic-gate void **conn_context) 537*7c478bd9Sstevel@tonic-gate { 538*7c478bd9Sstevel@tonic-gate client_context_t *text; 539*7c478bd9Sstevel@tonic-gate 540*7c478bd9Sstevel@tonic-gate /* holds state are in */ 541*7c478bd9Sstevel@tonic-gate text = params->utils->malloc(sizeof(client_context_t)); 542*7c478bd9Sstevel@tonic-gate if (text == NULL) { 543*7c478bd9Sstevel@tonic-gate MEMERROR(params->utils); 544*7c478bd9Sstevel@tonic-gate return SASL_NOMEM; 545*7c478bd9Sstevel@tonic-gate } 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate memset(text, 0, sizeof(client_context_t)); 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate *conn_context = text; 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate return SASL_OK; 552*7c478bd9Sstevel@tonic-gate } 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate static char *make_hashed(sasl_secret_t *sec, char *nonce, int noncelen, 555*7c478bd9Sstevel@tonic-gate const sasl_utils_t *utils) 556*7c478bd9Sstevel@tonic-gate { 557*7c478bd9Sstevel@tonic-gate char secret[65]; 558*7c478bd9Sstevel@tonic-gate unsigned char digest[24]; 559*7c478bd9Sstevel@tonic-gate int lup; 560*7c478bd9Sstevel@tonic-gate char *in16; 561*7c478bd9Sstevel@tonic-gate 562*7c478bd9Sstevel@tonic-gate if (sec == NULL) return NULL; 563*7c478bd9Sstevel@tonic-gate 564*7c478bd9Sstevel@tonic-gate if (sec->len < 64) { 565*7c478bd9Sstevel@tonic-gate memcpy(secret, sec->data, sec->len); 566*7c478bd9Sstevel@tonic-gate 567*7c478bd9Sstevel@tonic-gate /* fill in rest with 0's */ 568*7c478bd9Sstevel@tonic-gate for (lup= sec->len; lup < 64; lup++) 569*7c478bd9Sstevel@tonic-gate secret[lup]='\0'; 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate } else { 572*7c478bd9Sstevel@tonic-gate memcpy(secret, sec->data, 64); 573*7c478bd9Sstevel@tonic-gate } 574*7c478bd9Sstevel@tonic-gate 575*7c478bd9Sstevel@tonic-gate /* do the hmac md5 hash output 128 bits */ 576*7c478bd9Sstevel@tonic-gate utils->hmac_md5((unsigned char *) nonce, noncelen, 577*7c478bd9Sstevel@tonic-gate (unsigned char *) secret, 64, digest); 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate /* convert that to hex form */ 580*7c478bd9Sstevel@tonic-gate in16 = convert16(digest, 16, utils); 581*7c478bd9Sstevel@tonic-gate if (in16 == NULL) return NULL; 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate return in16; 584*7c478bd9Sstevel@tonic-gate } 585*7c478bd9Sstevel@tonic-gate 586*7c478bd9Sstevel@tonic-gate static int crammd5_client_mech_step(void *conn_context, 587*7c478bd9Sstevel@tonic-gate sasl_client_params_t *params, 588*7c478bd9Sstevel@tonic-gate const char *serverin, 589*7c478bd9Sstevel@tonic-gate unsigned serverinlen, 590*7c478bd9Sstevel@tonic-gate sasl_interact_t **prompt_need, 591*7c478bd9Sstevel@tonic-gate const char **clientout, 592*7c478bd9Sstevel@tonic-gate unsigned *clientoutlen, 593*7c478bd9Sstevel@tonic-gate sasl_out_params_t *oparams) 594*7c478bd9Sstevel@tonic-gate { 595*7c478bd9Sstevel@tonic-gate client_context_t *text = (client_context_t *) conn_context; 596*7c478bd9Sstevel@tonic-gate const char *authid; 597*7c478bd9Sstevel@tonic-gate sasl_secret_t *password = NULL; 598*7c478bd9Sstevel@tonic-gate unsigned int free_password = 0; /* set if we need to free password */ 599*7c478bd9Sstevel@tonic-gate int auth_result = SASL_OK; 600*7c478bd9Sstevel@tonic-gate int pass_result = SASL_OK; 601*7c478bd9Sstevel@tonic-gate int result; 602*7c478bd9Sstevel@tonic-gate int maxsize; 603*7c478bd9Sstevel@tonic-gate char *in16 = NULL; 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate *clientout = NULL; 606*7c478bd9Sstevel@tonic-gate *clientoutlen = 0; 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate /* First check for absurd lengths */ 609*7c478bd9Sstevel@tonic-gate if (serverinlen > 1024) { 610*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_ 611*7c478bd9Sstevel@tonic-gate params->utils->log(params->utils->conn, SASL_LOG_ERR, 612*7c478bd9Sstevel@tonic-gate "CRAM-MD5 input longer than 1024 bytes"); 613*7c478bd9Sstevel@tonic-gate #else 614*7c478bd9Sstevel@tonic-gate params->utils->seterror(params->utils->conn, 0, 615*7c478bd9Sstevel@tonic-gate "CRAM-MD5 input longer than 1024 bytes"); 616*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 617*7c478bd9Sstevel@tonic-gate return SASL_BADPROT; 618*7c478bd9Sstevel@tonic-gate } 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate /* check if sec layer strong enough */ 621*7c478bd9Sstevel@tonic-gate if (params->props.min_ssf > params->external_ssf) { 622*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_ 623*7c478bd9Sstevel@tonic-gate params->utils->log(params->utils->conn, SASL_LOG_ERR, 624*7c478bd9Sstevel@tonic-gate "SSF requested of CRAM-MD5 plugin"); 625*7c478bd9Sstevel@tonic-gate #else 626*7c478bd9Sstevel@tonic-gate SETERROR( params->utils, "SSF requested of CRAM-MD5 plugin"); 627*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 628*7c478bd9Sstevel@tonic-gate return SASL_TOOWEAK; 629*7c478bd9Sstevel@tonic-gate } 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate /* try to get the userid */ 632*7c478bd9Sstevel@tonic-gate if (oparams->authid == NULL) { 633*7c478bd9Sstevel@tonic-gate auth_result=_plug_get_authid(params->utils, &authid, prompt_need); 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT)) 636*7c478bd9Sstevel@tonic-gate return auth_result; 637*7c478bd9Sstevel@tonic-gate } 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate /* try to get the password */ 640*7c478bd9Sstevel@tonic-gate if (password == NULL) { 641*7c478bd9Sstevel@tonic-gate pass_result=_plug_get_password(params->utils, &password, 642*7c478bd9Sstevel@tonic-gate &free_password, prompt_need); 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT)) 645*7c478bd9Sstevel@tonic-gate return pass_result; 646*7c478bd9Sstevel@tonic-gate } 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate /* free prompts we got */ 649*7c478bd9Sstevel@tonic-gate if (prompt_need && *prompt_need) { 650*7c478bd9Sstevel@tonic-gate params->utils->free(*prompt_need); 651*7c478bd9Sstevel@tonic-gate *prompt_need = NULL; 652*7c478bd9Sstevel@tonic-gate } 653*7c478bd9Sstevel@tonic-gate 654*7c478bd9Sstevel@tonic-gate /* if there are prompts not filled in */ 655*7c478bd9Sstevel@tonic-gate if ((auth_result == SASL_INTERACT) || (pass_result == SASL_INTERACT)) { 656*7c478bd9Sstevel@tonic-gate /* make the prompt list */ 657*7c478bd9Sstevel@tonic-gate result = 658*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_ 659*7c478bd9Sstevel@tonic-gate _plug_make_prompts(params->utils, &text->h, prompt_need, 660*7c478bd9Sstevel@tonic-gate NULL, NULL, 661*7c478bd9Sstevel@tonic-gate auth_result == SASL_INTERACT ? 662*7c478bd9Sstevel@tonic-gate convert_prompt(params->utils, &text->h, 663*7c478bd9Sstevel@tonic-gate gettext("Please enter your authentication name")) 664*7c478bd9Sstevel@tonic-gate : NULL, NULL, 665*7c478bd9Sstevel@tonic-gate pass_result == SASL_INTERACT ? 666*7c478bd9Sstevel@tonic-gate convert_prompt(params->utils, &text->h, 667*7c478bd9Sstevel@tonic-gate gettext("Please enter your password")) 668*7c478bd9Sstevel@tonic-gate : NULL, NULL, 669*7c478bd9Sstevel@tonic-gate NULL, NULL, NULL, 670*7c478bd9Sstevel@tonic-gate NULL, NULL, NULL); 671*7c478bd9Sstevel@tonic-gate #else 672*7c478bd9Sstevel@tonic-gate _plug_make_prompts(params->utils, prompt_need, 673*7c478bd9Sstevel@tonic-gate NULL, NULL, 674*7c478bd9Sstevel@tonic-gate auth_result == SASL_INTERACT ? 675*7c478bd9Sstevel@tonic-gate "Please enter your authentication name" : NULL, 676*7c478bd9Sstevel@tonic-gate NULL, 677*7c478bd9Sstevel@tonic-gate pass_result == SASL_INTERACT ? 678*7c478bd9Sstevel@tonic-gate "Please enter your password" : NULL, NULL, 679*7c478bd9Sstevel@tonic-gate NULL, NULL, NULL, 680*7c478bd9Sstevel@tonic-gate NULL, NULL, NULL); 681*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */ 682*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) goto cleanup; 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate return SASL_INTERACT; 685*7c478bd9Sstevel@tonic-gate } 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate if (!password) { 688*7c478bd9Sstevel@tonic-gate PARAMERROR(params->utils); 689*7c478bd9Sstevel@tonic-gate return SASL_BADPARAM; 690*7c478bd9Sstevel@tonic-gate } 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate result = params->canon_user(params->utils->conn, authid, 0, 693*7c478bd9Sstevel@tonic-gate SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams); 694*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) goto cleanup; 695*7c478bd9Sstevel@tonic-gate 696*7c478bd9Sstevel@tonic-gate /* 697*7c478bd9Sstevel@tonic-gate * username SP digest (keyed md5 where key is passwd) 698*7c478bd9Sstevel@tonic-gate */ 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate in16 = make_hashed(password, (char *) serverin, serverinlen, 701*7c478bd9Sstevel@tonic-gate params->utils); 702*7c478bd9Sstevel@tonic-gate 703*7c478bd9Sstevel@tonic-gate if (in16 == NULL) { 704*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_ 705*7c478bd9Sstevel@tonic-gate params->utils->log(params->utils->conn, SASL_LOG_ERR, 706*7c478bd9Sstevel@tonic-gate "make_hashed failed"); 707*7c478bd9Sstevel@tonic-gate #else 708*7c478bd9Sstevel@tonic-gate SETERROR(params->utils, "whoops, make_hashed failed us this time"); 709*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 710*7c478bd9Sstevel@tonic-gate result = SASL_FAIL; 711*7c478bd9Sstevel@tonic-gate goto cleanup; 712*7c478bd9Sstevel@tonic-gate } 713*7c478bd9Sstevel@tonic-gate 714*7c478bd9Sstevel@tonic-gate maxsize = 32+1+strlen(oparams->authid)+30; 715*7c478bd9Sstevel@tonic-gate result = _plug_buf_alloc(params->utils, &(text->out_buf), 716*7c478bd9Sstevel@tonic-gate &(text->out_buf_len), maxsize); 717*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) goto cleanup; 718*7c478bd9Sstevel@tonic-gate 719*7c478bd9Sstevel@tonic-gate snprintf(text->out_buf, maxsize, "%s %s", oparams->authid, in16); 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate *clientout = text->out_buf; 722*7c478bd9Sstevel@tonic-gate *clientoutlen = strlen(*clientout); 723*7c478bd9Sstevel@tonic-gate 724*7c478bd9Sstevel@tonic-gate /* set oparams */ 725*7c478bd9Sstevel@tonic-gate oparams->doneflag = 1; 726*7c478bd9Sstevel@tonic-gate oparams->mech_ssf = 0; 727*7c478bd9Sstevel@tonic-gate oparams->maxoutbuf = 0; 728*7c478bd9Sstevel@tonic-gate oparams->encode_context = NULL; 729*7c478bd9Sstevel@tonic-gate oparams->encode = NULL; 730*7c478bd9Sstevel@tonic-gate oparams->decode_context = NULL; 731*7c478bd9Sstevel@tonic-gate oparams->decode = NULL; 732*7c478bd9Sstevel@tonic-gate oparams->param_version = 0; 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate result = SASL_OK; 735*7c478bd9Sstevel@tonic-gate 736*7c478bd9Sstevel@tonic-gate cleanup: 737*7c478bd9Sstevel@tonic-gate /* get rid of private information */ 738*7c478bd9Sstevel@tonic-gate if (in16) _plug_free_string(params->utils, &in16); 739*7c478bd9Sstevel@tonic-gate 740*7c478bd9Sstevel@tonic-gate /* get rid of all sensitive info */ 741*7c478bd9Sstevel@tonic-gate if (free_password) _plug_free_secret(params-> utils, &password); 742*7c478bd9Sstevel@tonic-gate 743*7c478bd9Sstevel@tonic-gate return result; 744*7c478bd9Sstevel@tonic-gate } 745*7c478bd9Sstevel@tonic-gate 746*7c478bd9Sstevel@tonic-gate static void crammd5_client_mech_dispose(void *conn_context, 747*7c478bd9Sstevel@tonic-gate const sasl_utils_t *utils) 748*7c478bd9Sstevel@tonic-gate { 749*7c478bd9Sstevel@tonic-gate client_context_t *text = (client_context_t *) conn_context; 750*7c478bd9Sstevel@tonic-gate 751*7c478bd9Sstevel@tonic-gate if (!text) return; 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_ 754*7c478bd9Sstevel@tonic-gate convert_prompt(utils, &text->h, NULL); 755*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */ 756*7c478bd9Sstevel@tonic-gate if (text->out_buf) utils->free(text->out_buf); 757*7c478bd9Sstevel@tonic-gate 758*7c478bd9Sstevel@tonic-gate utils->free(text); 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate static sasl_client_plug_t crammd5_client_plugins[] = 762*7c478bd9Sstevel@tonic-gate { 763*7c478bd9Sstevel@tonic-gate { 764*7c478bd9Sstevel@tonic-gate "CRAM-MD5", /* mech_name */ 765*7c478bd9Sstevel@tonic-gate 0, /* max_ssf */ 766*7c478bd9Sstevel@tonic-gate SASL_SEC_NOPLAINTEXT 767*7c478bd9Sstevel@tonic-gate | SASL_SEC_NOANONYMOUS, /* security_flags */ 768*7c478bd9Sstevel@tonic-gate SASL_FEAT_SERVER_FIRST, /* features */ 769*7c478bd9Sstevel@tonic-gate NULL, /* required_prompts */ 770*7c478bd9Sstevel@tonic-gate NULL, /* glob_context */ 771*7c478bd9Sstevel@tonic-gate &crammd5_client_mech_new, /* mech_new */ 772*7c478bd9Sstevel@tonic-gate &crammd5_client_mech_step, /* mech_step */ 773*7c478bd9Sstevel@tonic-gate &crammd5_client_mech_dispose, /* mech_dispose */ 774*7c478bd9Sstevel@tonic-gate NULL, /* mech_free */ 775*7c478bd9Sstevel@tonic-gate NULL, /* idle */ 776*7c478bd9Sstevel@tonic-gate NULL, /* spare */ 777*7c478bd9Sstevel@tonic-gate NULL /* spare */ 778*7c478bd9Sstevel@tonic-gate } 779*7c478bd9Sstevel@tonic-gate }; 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate int crammd5_client_plug_init(const sasl_utils_t *utils, 782*7c478bd9Sstevel@tonic-gate int maxversion, 783*7c478bd9Sstevel@tonic-gate int *out_version, 784*7c478bd9Sstevel@tonic-gate sasl_client_plug_t **pluglist, 785*7c478bd9Sstevel@tonic-gate int *plugcount) 786*7c478bd9Sstevel@tonic-gate { 787*7c478bd9Sstevel@tonic-gate if (maxversion < SASL_CLIENT_PLUG_VERSION) { 788*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_ 789*7c478bd9Sstevel@tonic-gate utils->log(NULL, SASL_LOG_ERR, "CRAM version mismatch"); 790*7c478bd9Sstevel@tonic-gate #else 791*7c478bd9Sstevel@tonic-gate SETERROR( utils, "CRAM version mismatch"); 792*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 793*7c478bd9Sstevel@tonic-gate return SASL_BADVERS; 794*7c478bd9Sstevel@tonic-gate } 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate *out_version = SASL_CLIENT_PLUG_VERSION; 797*7c478bd9Sstevel@tonic-gate *pluglist = crammd5_client_plugins; 798*7c478bd9Sstevel@tonic-gate *plugcount = 1; 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate return SASL_OK; 801*7c478bd9Sstevel@tonic-gate } 802