xref: /illumos-gate/usr/src/lib/libsasl/lib/checkpw.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
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 /* SASL server API implementation
7*7c478bd9Sstevel@tonic-gate  * Rob Siemborski
8*7c478bd9Sstevel@tonic-gate  * Tim Martin
9*7c478bd9Sstevel@tonic-gate  * $Id: checkpw.c,v 1.62 2003/03/19 18:25:27 rjs3 Exp $
10*7c478bd9Sstevel@tonic-gate  */
11*7c478bd9Sstevel@tonic-gate /*
12*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
15*7c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
16*7c478bd9Sstevel@tonic-gate  * are met:
17*7c478bd9Sstevel@tonic-gate  *
18*7c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
19*7c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
20*7c478bd9Sstevel@tonic-gate  *
21*7c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
22*7c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in
23*7c478bd9Sstevel@tonic-gate  *    the documentation and/or other materials provided with the
24*7c478bd9Sstevel@tonic-gate  *    distribution.
25*7c478bd9Sstevel@tonic-gate  *
26*7c478bd9Sstevel@tonic-gate  * 3. The name "Carnegie Mellon University" must not be used to
27*7c478bd9Sstevel@tonic-gate  *    endorse or promote products derived from this software without
28*7c478bd9Sstevel@tonic-gate  *    prior written permission. For permission or any other legal
29*7c478bd9Sstevel@tonic-gate  *    details, please contact
30*7c478bd9Sstevel@tonic-gate  *      Office of Technology Transfer
31*7c478bd9Sstevel@tonic-gate  *      Carnegie Mellon University
32*7c478bd9Sstevel@tonic-gate  *      5000 Forbes Avenue
33*7c478bd9Sstevel@tonic-gate  *      Pittsburgh, PA  15213-3890
34*7c478bd9Sstevel@tonic-gate  *      (412) 268-4387, fax: (412) 268-7395
35*7c478bd9Sstevel@tonic-gate  *      tech-transfer@andrew.cmu.edu
36*7c478bd9Sstevel@tonic-gate  *
37*7c478bd9Sstevel@tonic-gate  * 4. Redistributions of any form whatsoever must retain the following
38*7c478bd9Sstevel@tonic-gate  *    acknowledgment:
39*7c478bd9Sstevel@tonic-gate  *    "This product includes software developed by Computing Services
40*7c478bd9Sstevel@tonic-gate  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
41*7c478bd9Sstevel@tonic-gate  *
42*7c478bd9Sstevel@tonic-gate  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
43*7c478bd9Sstevel@tonic-gate  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
44*7c478bd9Sstevel@tonic-gate  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
45*7c478bd9Sstevel@tonic-gate  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
46*7c478bd9Sstevel@tonic-gate  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
47*7c478bd9Sstevel@tonic-gate  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
48*7c478bd9Sstevel@tonic-gate  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49*7c478bd9Sstevel@tonic-gate  */
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #include <config.h>
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate /* checkpw stuff */
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate #include <stdio.h>
56*7c478bd9Sstevel@tonic-gate #include "sasl.h"
57*7c478bd9Sstevel@tonic-gate #include "saslutil.h"
58*7c478bd9Sstevel@tonic-gate #include "saslplug.h"
59*7c478bd9Sstevel@tonic-gate #include "saslint.h"
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate #include <assert.h>
62*7c478bd9Sstevel@tonic-gate #ifdef HAVE_UNISTD_H
63*7c478bd9Sstevel@tonic-gate #include <unistd.h>
64*7c478bd9Sstevel@tonic-gate #endif
65*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
66*7c478bd9Sstevel@tonic-gate #ifdef USE_DOORS
67*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
68*7c478bd9Sstevel@tonic-gate #include <door.h>
69*7c478bd9Sstevel@tonic-gate #endif
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate #ifndef WIN32
74*7c478bd9Sstevel@tonic-gate #include <strings.h>
75*7c478bd9Sstevel@tonic-gate #include <netdb.h>
76*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
77*7c478bd9Sstevel@tonic-gate #include <sys/un.h>
78*7c478bd9Sstevel@tonic-gate #else
79*7c478bd9Sstevel@tonic-gate #include <string.h>
80*7c478bd9Sstevel@tonic-gate #endif
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
83*7c478bd9Sstevel@tonic-gate #include <ctype.h>
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate #ifdef HAVE_PWD_H
86*7c478bd9Sstevel@tonic-gate #include <pwd.h>
87*7c478bd9Sstevel@tonic-gate #endif /* HAVE_PWD_H */
88*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SHADOW_H
89*7c478bd9Sstevel@tonic-gate #include <shadow.h>
90*7c478bd9Sstevel@tonic-gate #endif /* HAVE_SHADOW_H */
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate #if defined(HAVE_PWCHECK) || defined(HAVE_SASLAUTHD)
93*7c478bd9Sstevel@tonic-gate # include <errno.h>
94*7c478bd9Sstevel@tonic-gate # include <sys/types.h>
95*7c478bd9Sstevel@tonic-gate # include <sys/socket.h>
96*7c478bd9Sstevel@tonic-gate # include <sys/un.h>
97*7c478bd9Sstevel@tonic-gate # ifdef HAVE_UNISTD_H
98*7c478bd9Sstevel@tonic-gate #  include <unistd.h>
99*7c478bd9Sstevel@tonic-gate # endif
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate extern int errno;
102*7c478bd9Sstevel@tonic-gate #endif
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate /* we store the following secret to check plaintext passwords:
106*7c478bd9Sstevel@tonic-gate  *
107*7c478bd9Sstevel@tonic-gate  * <salt> \0 <secret>
108*7c478bd9Sstevel@tonic-gate  *
109*7c478bd9Sstevel@tonic-gate  * where <secret> = MD5(<salt>, "sasldb", <pass>)
110*7c478bd9Sstevel@tonic-gate  */
111*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
_sasl_make_plain_secret(const sasl_utils_t * utils,const char * salt,const char * passwd,size_t passlen,sasl_secret_t ** secret)112*7c478bd9Sstevel@tonic-gate static int _sasl_make_plain_secret(const sasl_utils_t *utils, const char *salt,
113*7c478bd9Sstevel@tonic-gate 				const char *passwd, size_t passlen,
114*7c478bd9Sstevel@tonic-gate 				sasl_secret_t **secret)
115*7c478bd9Sstevel@tonic-gate #else
116*7c478bd9Sstevel@tonic-gate static int _sasl_make_plain_secret(const char *salt,
117*7c478bd9Sstevel@tonic-gate 				   const char *passwd, size_t passlen,
118*7c478bd9Sstevel@tonic-gate 				   sasl_secret_t **secret)
119*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
120*7c478bd9Sstevel@tonic-gate {
121*7c478bd9Sstevel@tonic-gate     MD5_CTX ctx;
122*7c478bd9Sstevel@tonic-gate     unsigned sec_len = 16 + 1 + 16; /* salt + "\0" + hash */
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
125*7c478bd9Sstevel@tonic-gate     *secret = (sasl_secret_t *)utils->malloc(sizeof(sasl_secret_t) +
126*7c478bd9Sstevel@tonic-gate 					sec_len * sizeof(char));
127*7c478bd9Sstevel@tonic-gate #else
128*7c478bd9Sstevel@tonic-gate     *secret = (sasl_secret_t *) sasl_ALLOC(sizeof(sasl_secret_t) +
129*7c478bd9Sstevel@tonic-gate 					   sec_len * sizeof(char));
130*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
131*7c478bd9Sstevel@tonic-gate     if (*secret == NULL) {
132*7c478bd9Sstevel@tonic-gate 	return SASL_NOMEM;
133*7c478bd9Sstevel@tonic-gate     }
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate     _sasl_MD5Init(&ctx);
136*7c478bd9Sstevel@tonic-gate     _sasl_MD5Update(&ctx, salt, 16);
137*7c478bd9Sstevel@tonic-gate     _sasl_MD5Update(&ctx, "sasldb", 6);
138*7c478bd9Sstevel@tonic-gate     _sasl_MD5Update(&ctx, passwd, passlen);
139*7c478bd9Sstevel@tonic-gate     memcpy((*secret)->data, salt, 16);
140*7c478bd9Sstevel@tonic-gate     (*secret)->data[16] = '\0';
141*7c478bd9Sstevel@tonic-gate     _sasl_MD5Final((*secret)->data + 17, &ctx);
142*7c478bd9Sstevel@tonic-gate     (*secret)->len = sec_len;
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate     return SASL_OK;
145*7c478bd9Sstevel@tonic-gate }
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate /* erase & dispose of a sasl_secret_t
148*7c478bd9Sstevel@tonic-gate  */
auxprop_verify_password(sasl_conn_t * conn,const char * userstr,const char * passwd,const char * service,const char * user_realm)149*7c478bd9Sstevel@tonic-gate static int auxprop_verify_password(sasl_conn_t *conn,
150*7c478bd9Sstevel@tonic-gate 				   const char *userstr,
151*7c478bd9Sstevel@tonic-gate 				   const char *passwd,
152*7c478bd9Sstevel@tonic-gate 				   const char *service __attribute__((unused)),
153*7c478bd9Sstevel@tonic-gate 				   const char *user_realm __attribute__((unused)))
154*7c478bd9Sstevel@tonic-gate {
155*7c478bd9Sstevel@tonic-gate     int ret = SASL_FAIL;
156*7c478bd9Sstevel@tonic-gate     char *userid = NULL;
157*7c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
158*7c478bd9Sstevel@tonic-gate     char *realm = NULL;
159*7c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
160*7c478bd9Sstevel@tonic-gate     int result = SASL_OK;
161*7c478bd9Sstevel@tonic-gate     sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
162*7c478bd9Sstevel@tonic-gate     const char *password_request[] = { SASL_AUX_PASSWORD,
163*7c478bd9Sstevel@tonic-gate 				       "*cmusaslsecretPLAIN",
164*7c478bd9Sstevel@tonic-gate 				       NULL };
165*7c478bd9Sstevel@tonic-gate     struct propval auxprop_values[3];
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate     if (!conn || !userstr)
168*7c478bd9Sstevel@tonic-gate 	return SASL_BADPARAM;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate     /* We need to clear any previous results and re-canonify to
171*7c478bd9Sstevel@tonic-gate      * ensure correctness */
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate     prop_clear(sconn->sparams->propctx, 0);
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate     /* ensure its requested */
176*7c478bd9Sstevel@tonic-gate     result = prop_request(sconn->sparams->propctx, password_request);
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate     if(result != SASL_OK) return result;
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate     result = _sasl_canon_user(conn, userstr, 0,
181*7c478bd9Sstevel@tonic-gate 			      SASL_CU_AUTHID | SASL_CU_AUTHZID,
182*7c478bd9Sstevel@tonic-gate 			      &(conn->oparams));
183*7c478bd9Sstevel@tonic-gate     if(result != SASL_OK) return result;
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate     result = prop_getnames(sconn->sparams->propctx, password_request,
186*7c478bd9Sstevel@tonic-gate 			   auxprop_values);
187*7c478bd9Sstevel@tonic-gate     if(result < 0)
188*7c478bd9Sstevel@tonic-gate 	return result;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate     if((!auxprop_values[0].name
191*7c478bd9Sstevel@tonic-gate          || !auxprop_values[0].values || !auxprop_values[0].values[0])
192*7c478bd9Sstevel@tonic-gate        && (!auxprop_values[1].name
193*7c478bd9Sstevel@tonic-gate          || !auxprop_values[1].values || !auxprop_values[1].values[0]))
194*7c478bd9Sstevel@tonic-gate 	    return SASL_NOUSER;
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate     /* It is possible for us to get useful information out of just
197*7c478bd9Sstevel@tonic-gate      * the lookup, so we won't check that we have a password until now */
198*7c478bd9Sstevel@tonic-gate     if(!passwd) {
199*7c478bd9Sstevel@tonic-gate 	ret = SASL_BADPARAM;
200*7c478bd9Sstevel@tonic-gate 	goto done;
201*7c478bd9Sstevel@tonic-gate     }
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate     /* At the point this has been called, the username has been canonified
204*7c478bd9Sstevel@tonic-gate      * and we've done the auxprop lookup.  This should be easy. */
205*7c478bd9Sstevel@tonic-gate     if(auxprop_values[0].name
206*7c478bd9Sstevel@tonic-gate        && auxprop_values[0].values
207*7c478bd9Sstevel@tonic-gate        && auxprop_values[0].values[0]
208*7c478bd9Sstevel@tonic-gate        && !strcmp(auxprop_values[0].values[0], passwd)) {
209*7c478bd9Sstevel@tonic-gate 	/* We have a plaintext version and it matched! */
210*7c478bd9Sstevel@tonic-gate 	return SASL_OK;
211*7c478bd9Sstevel@tonic-gate     } else if(auxprop_values[1].name
212*7c478bd9Sstevel@tonic-gate 	      && auxprop_values[1].values
213*7c478bd9Sstevel@tonic-gate 	      && auxprop_values[1].values[0]) {
214*7c478bd9Sstevel@tonic-gate 	const char *db_secret = auxprop_values[1].values[0];
215*7c478bd9Sstevel@tonic-gate 	sasl_secret_t *construct;
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
218*7c478bd9Sstevel@tonic-gate 	ret = _sasl_make_plain_secret(sconn->sparams->utils, db_secret,
219*7c478bd9Sstevel@tonic-gate 				passwd, strlen(passwd),
220*7c478bd9Sstevel@tonic-gate 				&construct);
221*7c478bd9Sstevel@tonic-gate #else
222*7c478bd9Sstevel@tonic-gate 	ret = _sasl_make_plain_secret(db_secret, passwd,
223*7c478bd9Sstevel@tonic-gate 				      strlen(passwd),
224*7c478bd9Sstevel@tonic-gate 				      &construct);
225*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
226*7c478bd9Sstevel@tonic-gate 	if (ret != SASL_OK) {
227*7c478bd9Sstevel@tonic-gate 	    goto done;
228*7c478bd9Sstevel@tonic-gate 	}
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	if (!memcmp(db_secret, construct->data, construct->len)) {
231*7c478bd9Sstevel@tonic-gate 	    /* password verified! */
232*7c478bd9Sstevel@tonic-gate 	    ret = SASL_OK;
233*7c478bd9Sstevel@tonic-gate 	} else {
234*7c478bd9Sstevel@tonic-gate 	    /* passwords do not match */
235*7c478bd9Sstevel@tonic-gate 	    ret = SASL_BADAUTH;
236*7c478bd9Sstevel@tonic-gate 	}
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
239*7c478bd9Sstevel@tonic-gate 	sconn->sparams->utils->free(construct);
240*7c478bd9Sstevel@tonic-gate #else
241*7c478bd9Sstevel@tonic-gate 	sasl_FREE(construct);
242*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
243*7c478bd9Sstevel@tonic-gate     } else {
244*7c478bd9Sstevel@tonic-gate 	/* passwords do not match */
245*7c478bd9Sstevel@tonic-gate 	ret = SASL_BADAUTH;
246*7c478bd9Sstevel@tonic-gate     }
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate  done:
249*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
250*7c478bd9Sstevel@tonic-gate     if (userid) sconn->sparams->utils->free(userid);
251*7c478bd9Sstevel@tonic-gate #else
252*7c478bd9Sstevel@tonic-gate     if (userid) sasl_FREE(userid);
253*7c478bd9Sstevel@tonic-gate     if (realm)  sasl_FREE(realm);
254*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate     /* We're not going to erase the property here because other people
257*7c478bd9Sstevel@tonic-gate      * may want it */
258*7c478bd9Sstevel@tonic-gate     return ret;
259*7c478bd9Sstevel@tonic-gate }
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate #ifdef DO_SASL_CHECKAPOP
_sasl_auxprop_verify_apop(sasl_conn_t * conn,const char * userstr,const char * challenge,const char * response,const char * user_realm)262*7c478bd9Sstevel@tonic-gate int _sasl_auxprop_verify_apop(sasl_conn_t *conn,
263*7c478bd9Sstevel@tonic-gate 			      const char *userstr,
264*7c478bd9Sstevel@tonic-gate 			      const char *challenge,
265*7c478bd9Sstevel@tonic-gate 			      const char *response,
266*7c478bd9Sstevel@tonic-gate 			      const char *user_realm __attribute__((unused)))
267*7c478bd9Sstevel@tonic-gate {
268*7c478bd9Sstevel@tonic-gate     int ret = SASL_BADAUTH;
269*7c478bd9Sstevel@tonic-gate     char *userid = NULL;
270*7c478bd9Sstevel@tonic-gate #ifndef _SUN_SDK_
271*7c478bd9Sstevel@tonic-gate     char *realm = NULL;
272*7c478bd9Sstevel@tonic-gate #endif /* !_SUN_SDK_ */
273*7c478bd9Sstevel@tonic-gate     unsigned char digest[16];
274*7c478bd9Sstevel@tonic-gate     char digeststr[33];
275*7c478bd9Sstevel@tonic-gate     const char *password_request[] = { SASL_AUX_PASSWORD, NULL };
276*7c478bd9Sstevel@tonic-gate     struct propval auxprop_values[2];
277*7c478bd9Sstevel@tonic-gate     sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
278*7c478bd9Sstevel@tonic-gate     MD5_CTX ctx;
279*7c478bd9Sstevel@tonic-gate     int i;
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate     if (!conn || !userstr || !challenge || !response)
282*7c478bd9Sstevel@tonic-gate        PARAMERROR(conn)
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate     /* We've done the auxprop lookup already (in our caller) */
285*7c478bd9Sstevel@tonic-gate     /* sadly, APOP has no provision for storing secrets */
286*7c478bd9Sstevel@tonic-gate     ret = prop_getnames(sconn->sparams->propctx, password_request,
287*7c478bd9Sstevel@tonic-gate 			auxprop_values);
288*7c478bd9Sstevel@tonic-gate     if(ret < 0) {
289*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
290*7c478bd9Sstevel@tonic-gate 	_sasl_log(conn, SASL_LOG_ERR, "could not perform password lookup");
291*7c478bd9Sstevel@tonic-gate #else
292*7c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, 0, "could not perform password lookup");
293*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
294*7c478bd9Sstevel@tonic-gate 	goto done;
295*7c478bd9Sstevel@tonic-gate     }
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate     if(!auxprop_values[0].name ||
298*7c478bd9Sstevel@tonic-gate        !auxprop_values[0].values ||
299*7c478bd9Sstevel@tonic-gate        !auxprop_values[0].values[0]) {
300*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
301*7c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, 0, gettext("could not find password"));
302*7c478bd9Sstevel@tonic-gate #else
303*7c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, 0, "could not find password");
304*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
305*7c478bd9Sstevel@tonic-gate 	ret = SASL_NOUSER;
306*7c478bd9Sstevel@tonic-gate 	goto done;
307*7c478bd9Sstevel@tonic-gate     }
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate     _sasl_MD5Init(&ctx);
310*7c478bd9Sstevel@tonic-gate     _sasl_MD5Update(&ctx, challenge, strlen(challenge));
311*7c478bd9Sstevel@tonic-gate     _sasl_MD5Update(&ctx, auxprop_values[0].values[0],
312*7c478bd9Sstevel@tonic-gate 		    strlen(auxprop_values[0].values[0]));
313*7c478bd9Sstevel@tonic-gate     _sasl_MD5Final(digest, &ctx);
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate     /* convert digest from binary to ASCII hex */
316*7c478bd9Sstevel@tonic-gate     for (i = 0; i < 16; i++)
317*7c478bd9Sstevel@tonic-gate       sprintf(digeststr + (i*2), "%02x", digest[i]);
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate     if (!strncasecmp(digeststr, response, 32)) {
320*7c478bd9Sstevel@tonic-gate       /* password verified! */
321*7c478bd9Sstevel@tonic-gate       ret = SASL_OK;
322*7c478bd9Sstevel@tonic-gate     } else {
323*7c478bd9Sstevel@tonic-gate       /* passwords do not match */
324*7c478bd9Sstevel@tonic-gate       ret = SASL_BADAUTH;
325*7c478bd9Sstevel@tonic-gate     }
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate  done:
328*7c478bd9Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_
329*7c478bd9Sstevel@tonic-gate     if (ret == SASL_BADAUTH) sasl_seterror(conn, SASL_NOLOG,
330*7c478bd9Sstevel@tonic-gate 					   gettext("login incorrect"));
331*7c478bd9Sstevel@tonic-gate #else
332*7c478bd9Sstevel@tonic-gate     if (ret == SASL_BADAUTH) sasl_seterror(conn, SASL_NOLOG,
333*7c478bd9Sstevel@tonic-gate 					   "login incorrect");
334*7c478bd9Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */
335*7c478bd9Sstevel@tonic-gate #ifdef _SUN_SDK_
336*7c478bd9Sstevel@tonic-gate     if (userid) sconn->sparams->utils->free(userid);
337*7c478bd9Sstevel@tonic-gate #else
338*7c478bd9Sstevel@tonic-gate     if (userid) sasl_FREE(userid);
339*7c478bd9Sstevel@tonic-gate     if (realm)  sasl_FREE(realm);
340*7c478bd9Sstevel@tonic-gate #endif /* _SUN_SDK_ */
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate     return ret;
343*7c478bd9Sstevel@tonic-gate }
344*7c478bd9Sstevel@tonic-gate #endif /* DO_SASL_CHECKAPOP */
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate #if defined(HAVE_PWCHECK) || defined(HAVE_SASLAUTHD)
347*7c478bd9Sstevel@tonic-gate /*
348*7c478bd9Sstevel@tonic-gate  * Keep calling the writev() system call with 'fd', 'iov', and 'iovcnt'
349*7c478bd9Sstevel@tonic-gate  * until all the data is written out or an error occurs.
350*7c478bd9Sstevel@tonic-gate  */
retry_writev(int fd,struct iovec * iov,int iovcnt)351*7c478bd9Sstevel@tonic-gate static int retry_writev(int fd, struct iovec *iov, int iovcnt)
352*7c478bd9Sstevel@tonic-gate {
353*7c478bd9Sstevel@tonic-gate     int n;
354*7c478bd9Sstevel@tonic-gate     int i;
355*7c478bd9Sstevel@tonic-gate     int written = 0;
356*7c478bd9Sstevel@tonic-gate     static int iov_max =
357*7c478bd9Sstevel@tonic-gate #ifdef MAXIOV
358*7c478bd9Sstevel@tonic-gate 	MAXIOV
359*7c478bd9Sstevel@tonic-gate #else
360*7c478bd9Sstevel@tonic-gate #ifdef IOV_MAX
361*7c478bd9Sstevel@tonic-gate 	IOV_MAX
362*7c478bd9Sstevel@tonic-gate #else
363*7c478bd9Sstevel@tonic-gate 	8192
364*7c478bd9Sstevel@tonic-gate #endif
365*7c478bd9Sstevel@tonic-gate #endif
366*7c478bd9Sstevel@tonic-gate 	;
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate     for (;;) {
369*7c478bd9Sstevel@tonic-gate 	while (iovcnt && iov[0].iov_len == 0) {
370*7c478bd9Sstevel@tonic-gate 	    iov++;
371*7c478bd9Sstevel@tonic-gate 	    iovcnt--;
372*7c478bd9Sstevel@tonic-gate 	}
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	if (!iovcnt) return written;
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 	n = writev(fd, iov, iovcnt > iov_max ? iov_max : iovcnt);
377*7c478bd9Sstevel@tonic-gate 	if (n == -1) {
378*7c478bd9Sstevel@tonic-gate 	    if (errno == EINVAL && iov_max > 10) {
379*7c478bd9Sstevel@tonic-gate 		iov_max /= 2;
380*7c478bd9Sstevel@tonic-gate 		continue;
381*7c478bd9Sstevel@tonic-gate 	    }
382*7c478bd9Sstevel@tonic-gate 	    if (errno == EINTR) continue;
383*7c478bd9Sstevel@tonic-gate 	    return -1;
384*7c478bd9Sstevel@tonic-gate 	}
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	written += n;
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < iovcnt; i++) {
389*7c478bd9Sstevel@tonic-gate 	    if (iov[i].iov_len > (unsigned) n) {
390*7c478bd9Sstevel@tonic-gate 		iov[i].iov_base = (char *)iov[i].iov_base + n;
391*7c478bd9Sstevel@tonic-gate 		iov[i].iov_len -= n;
392*7c478bd9Sstevel@tonic-gate 		break;
393*7c478bd9Sstevel@tonic-gate 	    }
394*7c478bd9Sstevel@tonic-gate 	    n -= iov[i].iov_len;
395*7c478bd9Sstevel@tonic-gate 	    iov[i].iov_len = 0;
396*7c478bd9Sstevel@tonic-gate 	}
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 	if (i == iovcnt) return written;
399*7c478bd9Sstevel@tonic-gate     }
400*7c478bd9Sstevel@tonic-gate }
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate #endif
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate #ifdef HAVE_PWCHECK
405*7c478bd9Sstevel@tonic-gate /* pwcheck daemon-authenticated login */
pwcheck_verify_password(sasl_conn_t * conn,const char * userid,const char * passwd,const char * service,const char * user_realm)406*7c478bd9Sstevel@tonic-gate static int pwcheck_verify_password(sasl_conn_t *conn,
407*7c478bd9Sstevel@tonic-gate 				   const char *userid,
408*7c478bd9Sstevel@tonic-gate 				   const char *passwd,
409*7c478bd9Sstevel@tonic-gate 				   const char *service __attribute__((unused)),
410*7c478bd9Sstevel@tonic-gate 				   const char *user_realm
411*7c478bd9Sstevel@tonic-gate 				               __attribute__((unused)))
412*7c478bd9Sstevel@tonic-gate {
413*7c478bd9Sstevel@tonic-gate     int s;
414*7c478bd9Sstevel@tonic-gate     struct sockaddr_un srvaddr;
415*7c478bd9Sstevel@tonic-gate     int r;
416*7c478bd9Sstevel@tonic-gate     struct iovec iov[10];
417*7c478bd9Sstevel@tonic-gate     static char response[1024];
418*7c478bd9Sstevel@tonic-gate     unsigned start, n;
419*7c478bd9Sstevel@tonic-gate     char pwpath[1024];
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate     if (strlen(PWCHECKDIR)+8+1 > sizeof(pwpath)) return SASL_FAIL;
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate     strcpy(pwpath, PWCHECKDIR);
424*7c478bd9Sstevel@tonic-gate     strcat(pwpath, "/pwcheck");
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate     s = socket(AF_UNIX, SOCK_STREAM, 0);
427*7c478bd9Sstevel@tonic-gate     if (s == -1) return errno;
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate     memset((char *)&srvaddr, 0, sizeof(srvaddr));
430*7c478bd9Sstevel@tonic-gate     srvaddr.sun_family = AF_UNIX;
431*7c478bd9Sstevel@tonic-gate     strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path));
432*7c478bd9Sstevel@tonic-gate     r = connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
433*7c478bd9Sstevel@tonic-gate     if (r == -1) {
434*7c478bd9Sstevel@tonic-gate 	sasl_seterror(conn,0,"cannot connect to pwcheck server");
435*7c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
436*7c478bd9Sstevel@tonic-gate     }
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate     iov[0].iov_base = (char *)userid;
439*7c478bd9Sstevel@tonic-gate     iov[0].iov_len = strlen(userid)+1;
440*7c478bd9Sstevel@tonic-gate     iov[1].iov_base = (char *)passwd;
441*7c478bd9Sstevel@tonic-gate     iov[1].iov_len = strlen(passwd)+1;
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate     retry_writev(s, iov, 2);
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate     start = 0;
446*7c478bd9Sstevel@tonic-gate     while (start < sizeof(response) - 1) {
447*7c478bd9Sstevel@tonic-gate 	n = read(s, response+start, sizeof(response) - 1 - start);
448*7c478bd9Sstevel@tonic-gate 	if (n < 1) break;
449*7c478bd9Sstevel@tonic-gate 	start += n;
450*7c478bd9Sstevel@tonic-gate     }
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate     close(s);
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate     if (start > 1 && !strncmp(response, "OK", 2)) {
455*7c478bd9Sstevel@tonic-gate 	return SASL_OK;
456*7c478bd9Sstevel@tonic-gate     }
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate     response[start] = '\0';
459*7c478bd9Sstevel@tonic-gate     sasl_seterror(conn,0,response);
460*7c478bd9Sstevel@tonic-gate     return SASL_BADAUTH;
461*7c478bd9Sstevel@tonic-gate }
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate #endif
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SASLAUTHD
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate /*
468*7c478bd9Sstevel@tonic-gate  * Keep calling the read() system call with 'fd', 'buf', and 'nbyte'
469*7c478bd9Sstevel@tonic-gate  * until all the data is read in or an error occurs.
470*7c478bd9Sstevel@tonic-gate  */
retry_read(int fd,void * buf0,unsigned nbyte)471*7c478bd9Sstevel@tonic-gate static int retry_read(int fd, void *buf0, unsigned nbyte)
472*7c478bd9Sstevel@tonic-gate {
473*7c478bd9Sstevel@tonic-gate     int n;
474*7c478bd9Sstevel@tonic-gate     int nread = 0;
475*7c478bd9Sstevel@tonic-gate     char *buf = buf0;
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate     if (nbyte == 0) return 0;
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate     for (;;) {
480*7c478bd9Sstevel@tonic-gate 	n = read(fd, buf, nbyte);
481*7c478bd9Sstevel@tonic-gate 	if (n == -1 || n == 0) {
482*7c478bd9Sstevel@tonic-gate 	    if (errno == EINTR || errno == EAGAIN) continue;
483*7c478bd9Sstevel@tonic-gate 	    return -1;
484*7c478bd9Sstevel@tonic-gate 	}
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 	nread += n;
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	if (nread >= (int) nbyte) return nread;
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	buf += n;
491*7c478bd9Sstevel@tonic-gate 	nbyte -= n;
492*7c478bd9Sstevel@tonic-gate     }
493*7c478bd9Sstevel@tonic-gate }
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate /* saslauthd-authenticated login */
saslauthd_verify_password(sasl_conn_t * conn,const char * userid,const char * passwd,const char * service,const char * user_realm)496*7c478bd9Sstevel@tonic-gate static int saslauthd_verify_password(sasl_conn_t *conn,
497*7c478bd9Sstevel@tonic-gate 				     const char *userid,
498*7c478bd9Sstevel@tonic-gate 				     const char *passwd,
499*7c478bd9Sstevel@tonic-gate 				     const char *service,
500*7c478bd9Sstevel@tonic-gate 				     const char *user_realm)
501*7c478bd9Sstevel@tonic-gate {
502*7c478bd9Sstevel@tonic-gate     char response[1024];
503*7c478bd9Sstevel@tonic-gate     char query[8192];
504*7c478bd9Sstevel@tonic-gate     char *query_end = query;
505*7c478bd9Sstevel@tonic-gate     int s;
506*7c478bd9Sstevel@tonic-gate     struct sockaddr_un srvaddr;
507*7c478bd9Sstevel@tonic-gate     sasl_getopt_t *getopt;
508*7c478bd9Sstevel@tonic-gate     void *context;
509*7c478bd9Sstevel@tonic-gate     char pwpath[sizeof(srvaddr.sun_path)];
510*7c478bd9Sstevel@tonic-gate     const char *p = NULL;
511*7c478bd9Sstevel@tonic-gate #ifdef USE_DOORS
512*7c478bd9Sstevel@tonic-gate     door_arg_t arg;
513*7c478bd9Sstevel@tonic-gate #endif
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate     /* check to see if the user configured a rundir */
516*7c478bd9Sstevel@tonic-gate     if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context) == SASL_OK) {
517*7c478bd9Sstevel@tonic-gate 	getopt(context, NULL, "saslauthd_path", &p, NULL);
518*7c478bd9Sstevel@tonic-gate     }
519*7c478bd9Sstevel@tonic-gate     if (p) {
520*7c478bd9Sstevel@tonic-gate 	strncpy(pwpath, p, sizeof(pwpath));
521*7c478bd9Sstevel@tonic-gate     } else {
522*7c478bd9Sstevel@tonic-gate 	if (strlen(PATH_SASLAUTHD_RUNDIR) + 4 + 1 > sizeof(pwpath))
523*7c478bd9Sstevel@tonic-gate 	    return SASL_FAIL;
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 	strcpy(pwpath, PATH_SASLAUTHD_RUNDIR);
526*7c478bd9Sstevel@tonic-gate 	strcat(pwpath, "/mux");
527*7c478bd9Sstevel@tonic-gate     }
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate     /*
530*7c478bd9Sstevel@tonic-gate      * build request of the form:
531*7c478bd9Sstevel@tonic-gate      *
532*7c478bd9Sstevel@tonic-gate      * count authid count password count service count realm
533*7c478bd9Sstevel@tonic-gate      */
534*7c478bd9Sstevel@tonic-gate     {
535*7c478bd9Sstevel@tonic-gate  	unsigned short u_len, p_len, s_len, r_len;
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate  	u_len = (strlen(userid));
538*7c478bd9Sstevel@tonic-gate  	p_len = (strlen(passwd));
539*7c478bd9Sstevel@tonic-gate 	s_len = (strlen(service));
540*7c478bd9Sstevel@tonic-gate 	r_len = ((user_realm ? strlen(user_realm) : 0));
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	if (u_len + p_len + s_len + r_len + 30 > (unsigned short) sizeof(query)) {
543*7c478bd9Sstevel@tonic-gate 	    /* request just too damn big */
544*7c478bd9Sstevel@tonic-gate             sasl_seterror(conn, 0, "saslauthd request too large");
545*7c478bd9Sstevel@tonic-gate 	    return SASL_FAIL;
546*7c478bd9Sstevel@tonic-gate 	}
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	u_len = htons(u_len);
549*7c478bd9Sstevel@tonic-gate 	p_len = htons(p_len);
550*7c478bd9Sstevel@tonic-gate 	s_len = htons(s_len);
551*7c478bd9Sstevel@tonic-gate 	r_len = htons(r_len);
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 	memcpy(query_end, &u_len, sizeof(unsigned short));
554*7c478bd9Sstevel@tonic-gate 	query_end += sizeof(unsigned short);
555*7c478bd9Sstevel@tonic-gate 	while (*userid) *query_end++ = *userid++;
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	memcpy(query_end, &p_len, sizeof(unsigned short));
558*7c478bd9Sstevel@tonic-gate 	query_end += sizeof(unsigned short);
559*7c478bd9Sstevel@tonic-gate 	while (*passwd) *query_end++ = *passwd++;
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 	memcpy(query_end, &s_len, sizeof(unsigned short));
562*7c478bd9Sstevel@tonic-gate 	query_end += sizeof(unsigned short);
563*7c478bd9Sstevel@tonic-gate 	while (*service) *query_end++ = *service++;
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 	memcpy(query_end, &r_len, sizeof(unsigned short));
566*7c478bd9Sstevel@tonic-gate 	query_end += sizeof(unsigned short);
567*7c478bd9Sstevel@tonic-gate 	if (user_realm) while (*user_realm) *query_end++ = *user_realm++;
568*7c478bd9Sstevel@tonic-gate     }
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate #ifdef USE_DOORS
571*7c478bd9Sstevel@tonic-gate     s = open(pwpath, O_RDONLY);
572*7c478bd9Sstevel@tonic-gate     if (s < 0) {
573*7c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, 0, "cannot open door to saslauthd server: %m", errno);
574*7c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
575*7c478bd9Sstevel@tonic-gate     }
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate     arg.data_ptr = query;
578*7c478bd9Sstevel@tonic-gate     arg.data_size = query_end - query;
579*7c478bd9Sstevel@tonic-gate     arg.desc_ptr = NULL;
580*7c478bd9Sstevel@tonic-gate     arg.desc_num = 0;
581*7c478bd9Sstevel@tonic-gate     arg.rbuf = response;
582*7c478bd9Sstevel@tonic-gate     arg.rsize = sizeof(response);
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate     door_call(s, &arg);
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate     if (arg.data_ptr != response || arg.data_size >= sizeof(response)) {
587*7c478bd9Sstevel@tonic-gate 	/* oh damn, we got back a really long response */
588*7c478bd9Sstevel@tonic-gate 	munmap(arg.rbuf, arg.rsize);
589*7c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, 0, "saslauthd sent an overly long response");
590*7c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
591*7c478bd9Sstevel@tonic-gate     }
592*7c478bd9Sstevel@tonic-gate     response[arg.data_size] = '\0';
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate     close(s);
595*7c478bd9Sstevel@tonic-gate #else
596*7c478bd9Sstevel@tonic-gate     /* unix sockets */
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate     s = socket(AF_UNIX, SOCK_STREAM, 0);
599*7c478bd9Sstevel@tonic-gate     if (s == -1) {
600*7c478bd9Sstevel@tonic-gate 	sasl_seterror(conn, 0, "cannot create socket for saslauthd: %m", errno);
601*7c478bd9Sstevel@tonic-gate 	return SASL_FAIL;
602*7c478bd9Sstevel@tonic-gate     }
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate     memset((char *)&srvaddr, 0, sizeof(srvaddr));
605*7c478bd9Sstevel@tonic-gate     srvaddr.sun_family = AF_UNIX;
606*7c478bd9Sstevel@tonic-gate     strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path));
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate     {
609*7c478bd9Sstevel@tonic-gate 	int r = connect(s, (struct sockaddr *) &srvaddr, sizeof(srvaddr));
610*7c478bd9Sstevel@tonic-gate 	if (r == -1) {
611*7c478bd9Sstevel@tonic-gate 	    sasl_seterror(conn, 0, "cannot connect to saslauthd server: %m", errno);
612*7c478bd9Sstevel@tonic-gate 	    return SASL_FAIL;
613*7c478bd9Sstevel@tonic-gate 	}
614*7c478bd9Sstevel@tonic-gate     }
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate     {
617*7c478bd9Sstevel@tonic-gate  	struct iovec iov[8];
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 	iov[0].iov_len = query_end - query;
620*7c478bd9Sstevel@tonic-gate 	iov[0].iov_base = query;
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate 	if (retry_writev(s, iov, 1) == -1) {
623*7c478bd9Sstevel@tonic-gate             sasl_seterror(conn, 0, "write failed");
624*7c478bd9Sstevel@tonic-gate   	    return SASL_FAIL;
625*7c478bd9Sstevel@tonic-gate   	}
626*7c478bd9Sstevel@tonic-gate     }
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate     {
629*7c478bd9Sstevel@tonic-gate 	unsigned short count = 0;
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 	/*
632*7c478bd9Sstevel@tonic-gate 	 * read response of the form:
633*7c478bd9Sstevel@tonic-gate 	 *
634*7c478bd9Sstevel@tonic-gate 	 * count result
635*7c478bd9Sstevel@tonic-gate 	 */
636*7c478bd9Sstevel@tonic-gate 	if (retry_read(s, &count, sizeof(count)) < (int) sizeof(count)) {
637*7c478bd9Sstevel@tonic-gate 	    sasl_seterror(conn, 0, "size read failed");
638*7c478bd9Sstevel@tonic-gate 	    return SASL_FAIL;
639*7c478bd9Sstevel@tonic-gate 	}
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 	count = ntohs(count);
642*7c478bd9Sstevel@tonic-gate 	if (count < 2) { /* MUST have at least "OK" or "NO" */
643*7c478bd9Sstevel@tonic-gate 	    close(s);
644*7c478bd9Sstevel@tonic-gate 	    sasl_seterror(conn, 0, "bad response from saslauthd");
645*7c478bd9Sstevel@tonic-gate 	    return SASL_FAIL;
646*7c478bd9Sstevel@tonic-gate 	}
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate 	count = (int)sizeof(response) < count ? sizeof(response) : count;
649*7c478bd9Sstevel@tonic-gate 	if (retry_read(s, response, count) < count) {
650*7c478bd9Sstevel@tonic-gate 	    close(s);
651*7c478bd9Sstevel@tonic-gate 	    sasl_seterror(conn, 0, "read failed");
652*7c478bd9Sstevel@tonic-gate 	    return SASL_FAIL;
653*7c478bd9Sstevel@tonic-gate 	}
654*7c478bd9Sstevel@tonic-gate 	response[count] = '\0';
655*7c478bd9Sstevel@tonic-gate     }
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate     close(s);
658*7c478bd9Sstevel@tonic-gate #endif /* USE_DOORS */
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate     if (!strncmp(response, "OK", 2)) {
661*7c478bd9Sstevel@tonic-gate 	return SASL_OK;
662*7c478bd9Sstevel@tonic-gate     }
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate     sasl_seterror(conn, SASL_NOLOG, "authentication failed");
665*7c478bd9Sstevel@tonic-gate     return SASL_BADAUTH;
666*7c478bd9Sstevel@tonic-gate }
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate #endif
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate #ifdef HAVE_ALWAYSTRUE
always_true(sasl_conn_t * conn,const char * userstr,const char * passwd,const char * service,const char * user_realm)671*7c478bd9Sstevel@tonic-gate static int always_true(sasl_conn_t *conn,
672*7c478bd9Sstevel@tonic-gate 		       const char *userstr,
673*7c478bd9Sstevel@tonic-gate 		       const char *passwd __attribute__((unused)),
674*7c478bd9Sstevel@tonic-gate 		       const char *service __attribute__((unused)),
675*7c478bd9Sstevel@tonic-gate 		       const char *user_realm __attribute__((unused)))
676*7c478bd9Sstevel@tonic-gate {
677*7c478bd9Sstevel@tonic-gate     _sasl_log(conn, SASL_LOG_WARN, "AlwaysTrue Password Verifier Verified: %s",
678*7c478bd9Sstevel@tonic-gate 	      userstr);
679*7c478bd9Sstevel@tonic-gate     return SASL_OK;
680*7c478bd9Sstevel@tonic-gate }
681*7c478bd9Sstevel@tonic-gate #endif
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate struct sasl_verify_password_s _sasl_verify_password[] = {
684*7c478bd9Sstevel@tonic-gate     { "auxprop", &auxprop_verify_password },
685*7c478bd9Sstevel@tonic-gate #ifdef HAVE_PWCHECK
686*7c478bd9Sstevel@tonic-gate     { "pwcheck", &pwcheck_verify_password },
687*7c478bd9Sstevel@tonic-gate #endif
688*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SASLAUTHD
689*7c478bd9Sstevel@tonic-gate     { "saslauthd", &saslauthd_verify_password },
690*7c478bd9Sstevel@tonic-gate #endif
691*7c478bd9Sstevel@tonic-gate #ifdef HAVE_ALWAYSTRUE
692*7c478bd9Sstevel@tonic-gate     { "alwaystrue", &always_true },
693*7c478bd9Sstevel@tonic-gate #endif
694*7c478bd9Sstevel@tonic-gate     { NULL, NULL }
695*7c478bd9Sstevel@tonic-gate };
696