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