4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #ifdef LDAP_SASLIO_HOOKS
29 #include "../ber/lber-int.h"
30 #include <sasl/sasl.h>
34 #define SEARCH_TIMEOUT_SECS 120
35 #define NSLDAPI_SM_BUF 128
37 extern void *sasl_create_context(void);
38 extern void sasl_free_context(void *ctx
);
39 extern int _sasl_client_init(void *ctx
, const sasl_callback_t
*callbacks
);
40 extern int _sasl_client_new(void *ctx
, const char *service
,
41 const char *serverFQDN
, const char *iplocalport
,
42 const char *ipremoteport
,
43 const sasl_callback_t
*prompt_supp
,
44 unsigned flags
, sasl_conn_t
**pconn
);
45 extern int _sasl_server_init(void *ctx
,
46 const sasl_callback_t
*callbacks
, const char *appname
);
47 extern int _sasl_server_new(void *ctx
, const char *service
,
48 const char *serverFQDN
, const char *user_realm
,
49 const char *iplocalport
, const char *ipremoteport
,
50 const sasl_callback_t
*callbacks
,
51 unsigned flags
, sasl_conn_t
**pconn
);
53 static int nsldapi_sasl_close( LDAP
*ld
, Sockbuf
*sb
);
54 static void destroy_sasliobuf(Sockbuf
*sb
);
57 * SASL Dependent routines
59 * SASL security and integrity options are supported through the
60 * use of the extended I/O functionality. Because the extended
61 * I/O functions may already be in use prior to enabling encryption,
62 * when SASL encryption is enabled, these routine interpose themselves
63 * over the existng extended I/O routines and add an additional level
65 * IE: Before SASL: client->libldap->lber->extio
66 * After SASL: client->libldap->lber->saslio->extio
67 * Any extio functions are still used for the raw i/O [IE prldap]
68 * but SASL will decrypt before passing to lber.
69 * SASL cannot decrypt a stream so full packets must be read
73 static int nsldapi_sasl_fail()
79 * Global SASL Init data
82 static sasl_callback_t client_callbacks
[] = {
83 { SASL_CB_GETOPT
, nsldapi_sasl_fail
, NULL
},
84 { SASL_CB_GETREALM
, NULL
, NULL
},
85 { SASL_CB_USER
, NULL
, NULL
},
86 { SASL_CB_AUTHNAME
, NULL
, NULL
},
87 { SASL_CB_PASS
, NULL
, NULL
},
88 { SASL_CB_ECHOPROMPT
, NULL
, NULL
},
89 { SASL_CB_NOECHOPROMPT
, NULL
, NULL
},
90 { SASL_CB_LIST_END
, NULL
, NULL
}
92 static mutex_t sasl_mutex
= DEFAULTMUTEX
;
93 static int nsldapi_sasl_inited
= 0;
94 static void *gctx
; /* intentially not freed - avoid libsasl re-inits */
96 int nsldapi_sasl_init( void )
100 mutex_lock(&sasl_mutex
);
101 if ( nsldapi_sasl_inited
) {
102 mutex_unlock(&sasl_mutex
);
105 if ((gctx
= (void *)sasl_create_context()) != NULL
) {
106 saslrc
= _sasl_client_init(gctx
, client_callbacks
);
107 if (saslrc
== SASL_OK
) {
108 nsldapi_sasl_inited
= 1;
109 mutex_unlock(&sasl_mutex
);
113 mutex_unlock(&sasl_mutex
);
118 * SASL encryption routines
122 * Get the 4 octet header [size] for a sasl encrypted buffer.
123 * See RFC222 [section 3].
127 nsldapi_sasl_pktlen( char *buf
, int maxbufsize
)
131 #if defined( _WINDOWS ) || defined( _WIN32 )
132 size
= ntohl(*(long *)buf
);
134 size
= ntohl(*(uint32_t *)buf
);
137 if ( size
< 0 || size
> maxbufsize
) {
141 return( size
+ 4 ); /* include the first 4 bytes */
145 nsldapi_sasl_read( int s
, void *buf
, int len
,
146 struct lextiof_socket_private
*arg
)
148 Sockbuf
*sb
= (Sockbuf
*)arg
;
159 ld
= (LDAP
*)sb
->sb_sasl_prld
;
164 /* Is there anything left in the existing buffer? */
165 if ((ret
= sb
->sb_sasl_ilen
) > 0) {
166 ret
= (ret
> len
? len
: ret
);
167 SAFEMEMCPY( buf
, sb
->sb_sasl_iptr
, ret
);
168 if (ret
== sb
->sb_sasl_ilen
) {
169 sb
->sb_sasl_ilen
= 0;
170 sb
->sb_sasl_iptr
= NULL
;
172 sb
->sb_sasl_ilen
-= ret
;
173 sb
->sb_sasl_iptr
+= ret
;
178 /* buffer is empty - fill it */
179 cp
= sb
->sb_sasl_ibuf
;
182 /* Read the length of the packet */
184 if (sb
->sb_sasl_fns
.lbextiofn_read
!= NULL
) {
185 ret
= sb
->sb_sasl_fns
.lbextiofn_read(
187 sb
->sb_sasl_fns
.lbextiofn_socket_arg
);
189 ret
= read( sb
->sb_sd
, cp
, 4 - dlen
);
192 if ( ( ret
< 0 ) && ( LDAP_GET_ERRNO(ld
) == EINTR
) )
204 ret
= nsldapi_sasl_pktlen( sb
->sb_sasl_ibuf
, sb
->sb_sasl_bfsz
);
206 LDAP_SET_ERRNO(ld
, EIO
);
211 /* read the rest of the encrypted packet */
213 if (sb
->sb_sasl_fns
.lbextiofn_read
!= NULL
) {
214 ret
= sb
->sb_sasl_fns
.lbextiofn_read(
216 sb
->sb_sasl_fns
.lbextiofn_socket_arg
);
218 ret
= read( sb
->sb_sd
, cp
, dlen
);
222 if ( ( ret
< 0 ) && ( LDAP_GET_ERRNO(ld
) == EINTR
) )
233 /* Decode the packet */
234 ret
= sasl_decode( sb
->sb_sasl_ctx
,
235 sb
->sb_sasl_ibuf
, blen
,
237 if ( ret
!= SASL_OK
) {
238 /* sb_sasl_read: failed to decode packet, drop it, error */
239 sb
->sb_sasl_iptr
= NULL
;
240 sb
->sb_sasl_ilen
= 0;
241 LDAP_SET_ERRNO(ld
, EIO
);
245 /* copy decrypted packet to the input buffer */
246 SAFEMEMCPY( sb
->sb_sasl_ibuf
, dbuf
, dlen
);
247 sb
->sb_sasl_iptr
= sb
->sb_sasl_ibuf
;
248 sb
->sb_sasl_ilen
= dlen
;
250 ret
= (dlen
> (unsigned) len
? len
: dlen
);
251 SAFEMEMCPY( buf
, sb
->sb_sasl_iptr
, ret
);
252 if (ret
== sb
->sb_sasl_ilen
) {
253 sb
->sb_sasl_ilen
= 0;
254 sb
->sb_sasl_iptr
= NULL
;
256 sb
->sb_sasl_ilen
-= ret
;
257 sb
->sb_sasl_iptr
+= ret
;
263 nsldapi_sasl_write( int s
, const void *buf
, int len
,
264 struct lextiof_socket_private
*arg
)
266 Sockbuf
*sb
= (Sockbuf
*)arg
;
268 const char *obuf
, *optr
, *cbuf
= (const char *)buf
;
269 unsigned olen
, clen
, tlen
= 0;
276 ret
= sasl_getprop(sb
->sb_sasl_ctx
, SASL_MAXOUTBUF
,
277 (const void **)&maxbuf
);
278 if ( ret
!= SASL_OK
) {
279 /* just a sanity check, should never happen */
284 clen
= (len
> *maxbuf
) ? *maxbuf
: len
;
285 /* encode the next packet. */
286 ret
= sasl_encode( sb
->sb_sasl_ctx
, cbuf
, clen
, &obuf
, &olen
);
287 if ( ret
!= SASL_OK
) {
288 /* XXX Log error? "sb_sasl_write: failed to encode packet..." */
291 /* Write everything now, buffer is only good until next sasl_encode */
294 if (sb
->sb_sasl_fns
.lbextiofn_write
!= NULL
) {
295 ret
= sb
->sb_sasl_fns
.lbextiofn_write(
297 sb
->sb_sasl_fns
.lbextiofn_socket_arg
);
299 ret
= write( sb
->sb_sd
, optr
, olen
);
315 LDAP_X_PollFD fds
[], int nfds
, int timeout
,
316 struct lextiof_session_private
*arg
)
318 Sockbuf
*sb
= (Sockbuf
*)arg
;
325 ld
= (LDAP
*)sb
->sb_sasl_prld
;
330 if (fds
&& nfds
> 0) {
331 for(i
= 0; i
< nfds
; i
++) {
332 if (fds
[i
].lpoll_socketarg
==
333 (struct lextiof_socket_private
*)sb
) {
334 fds
[i
].lpoll_socketarg
=
335 (struct lextiof_socket_private
*)
336 sb
->sb_sasl_fns
.lbextiofn_socket_arg
;
341 return ( ld
->ld_sasl_io_fns
.lextiof_poll( fds
, nfds
, timeout
,
342 (void *)ld
->ld_sasl_io_fns
.lextiof_session_arg
) );
345 /* no encryption indirect routines */
348 nsldapi_sasl_ne_read( int s
, void *buf
, int len
,
349 struct lextiof_socket_private
*arg
)
351 Sockbuf
*sb
= (Sockbuf
*)arg
;
357 return( sb
->sb_sasl_fns
.lbextiofn_read( s
, buf
, len
,
358 sb
->sb_sasl_fns
.lbextiofn_socket_arg
) );
362 nsldapi_sasl_ne_write( int s
, const void *buf
, int len
,
363 struct lextiof_socket_private
*arg
)
365 Sockbuf
*sb
= (Sockbuf
*)arg
;
371 return( sb
->sb_sasl_fns
.lbextiofn_write( s
, buf
, len
,
372 sb
->sb_sasl_fns
.lbextiofn_socket_arg
) );
376 nsldapi_sasl_close_socket(int s
, struct lextiof_socket_private
*arg
)
378 Sockbuf
*sb
= (Sockbuf
*)arg
;
384 ld
= (LDAP
*)sb
->sb_sasl_prld
;
388 /* undo function pointer interposing */
389 ldap_set_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, &ld
->ld_sasl_io_fns
);
390 ber_sockbuf_set_option( sb
,
391 LBER_SOCKBUF_OPT_EXT_IO_FNS
,
392 (void *)&sb
->sb_sasl_fns
);
395 nsldapi_sasl_close( ld
, sb
);
397 return ( ld
->ld_sasl_io_fns
.lextiof_close( s
,
398 (struct lextiof_socket_private
*)
399 sb
->sb_sasl_fns
.lbextiofn_socket_arg
) );
403 * install encryption routines if security has been negotiated
406 nsldapi_sasl_install( LDAP
*ld
, Sockbuf
*sb
, void *ctx_arg
, sasl_ssf_t
*ssf
)
408 struct lber_x_ext_io_fns fns
;
409 struct ldap_x_ext_io_fns iofns
;
410 sasl_security_properties_t
*secprops
;
419 return( LDAP_LOCAL_ERROR
);
421 rc
= ber_sockbuf_get_option( sb
,
422 LBER_SOCKBUF_OPT_TO_FILE_ONLY
,
424 if (rc
!= 0 || value
!= 0)
425 return( LDAP_LOCAL_ERROR
);
428 /* initialize input buffer - use MAX SIZE to avoid reallocs */
429 sb
->sb_sasl_ctx
= (sasl_conn_t
*)ctx_arg
;
430 rc
= sasl_getprop( sb
->sb_sasl_ctx
, SASL_SEC_PROPS
,
431 (const void **)&secprops
);
433 return( LDAP_LOCAL_ERROR
);
434 bufsiz
= secprops
->maxbufsize
;
436 return( LDAP_LOCAL_ERROR
);
438 if ((sb
->sb_sasl_ibuf
= NSLDAPI_MALLOC(bufsiz
)) == NULL
) {
439 return( LDAP_LOCAL_ERROR
);
441 sb
->sb_sasl_iptr
= NULL
;
442 sb
->sb_sasl_bfsz
= bufsiz
;
443 sb
->sb_sasl_ilen
= 0;
446 /* Reset Session then Socket Args */
448 (void) memset( &sb
->sb_sasl_fns
, 0, LBER_X_EXTIO_FNS_SIZE
);
449 sb
->sb_sasl_fns
.lbextiofn_size
= LBER_X_EXTIO_FNS_SIZE
;
450 rc
= ber_sockbuf_get_option( sb
,
451 LBER_SOCKBUF_OPT_EXT_IO_FNS
,
452 (void *)&sb
->sb_sasl_fns
);
454 destroy_sasliobuf(sb
);
455 return( LDAP_LOCAL_ERROR
);
457 memset( &ld
->ld_sasl_io_fns
, 0, sizeof(iofns
));
458 ld
->ld_sasl_io_fns
.lextiof_size
= LDAP_X_EXTIO_FNS_SIZE
;
459 rc
= ldap_get_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
,
460 &ld
->ld_sasl_io_fns
);
462 destroy_sasliobuf(sb
);
463 return( LDAP_LOCAL_ERROR
);
467 if ( ld
->ld_sasl_io_fns
.lextiof_read
!= NULL
||
468 ld
->ld_sasl_io_fns
.lextiof_write
!= NULL
||
469 ld
->ld_sasl_io_fns
.lextiof_poll
!= NULL
||
470 ld
->ld_sasl_io_fns
.lextiof_connect
!= NULL
||
471 ld
->ld_sasl_io_fns
.lextiof_close
!= NULL
) {
472 memset( &iofns
, 0, sizeof(iofns
));
473 iofns
.lextiof_size
= LDAP_X_EXTIO_FNS_SIZE
;
475 iofns
.lextiof_read
= nsldapi_sasl_read
;
476 iofns
.lextiof_write
= nsldapi_sasl_write
;
477 iofns
.lextiof_poll
= nsldapi_sasl_poll
;
479 iofns
.lextiof_read
= nsldapi_sasl_ne_read
;
480 iofns
.lextiof_write
= nsldapi_sasl_ne_write
;
481 iofns
.lextiof_poll
= nsldapi_sasl_poll
;
483 iofns
.lextiof_connect
= ld
->ld_sasl_io_fns
.lextiof_connect
;
484 iofns
.lextiof_close
= nsldapi_sasl_close_socket
;
485 iofns
.lextiof_newhandle
= ld
->ld_sasl_io_fns
.lextiof_newhandle
;
486 iofns
.lextiof_disposehandle
=
487 ld
->ld_sasl_io_fns
.lextiof_disposehandle
;
488 iofns
.lextiof_session_arg
=
490 /* ld->ld_sasl_io_fns.lextiof_session_arg; */
491 rc
= ldap_set_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
,
494 destroy_sasliobuf(sb
);
495 return( LDAP_LOCAL_ERROR
);
497 sb
->sb_sasl_prld
= (void *)ld
;
501 (void) memset( &fns
, 0, LBER_X_EXTIO_FNS_SIZE
);
502 fns
.lbextiofn_size
= LBER_X_EXTIO_FNS_SIZE
;
503 fns
.lbextiofn_read
= nsldapi_sasl_read
;
504 fns
.lbextiofn_write
= nsldapi_sasl_write
;
505 fns
.lbextiofn_socket_arg
=
507 /* (void *)sb->sb_sasl_fns.lbextiofn_socket_arg; */
508 rc
= ber_sockbuf_set_option( sb
,
509 LBER_SOCKBUF_OPT_EXT_IO_FNS
,
512 destroy_sasliobuf(sb
);
513 return( LDAP_LOCAL_ERROR
);
517 return( LDAP_SUCCESS
);
521 nsldapi_sasl_cvterrno( LDAP
*ld
, int err
, char *msg
)
523 int rc
= LDAP_LOCAL_ERROR
;
530 rc
= LDAP_AUTH_UNKNOWN
;
533 rc
= LDAP_CONNECT_ERROR
;
538 case SASL_NOUSERPASS
:
544 rc
= LDAP_INAPPROPRIATE_AUTH
;
548 rc
= LDAP_INVALID_CREDENTIALS
;
554 rc
= LDAP_NO_SUCH_OBJECT
;
560 rc
= LDAP_LOCAL_ERROR
;
564 LDAP_SET_LDERRNO( ld
, rc
, NULL
, msg
);
569 nsldapi_sasl_open(LDAP
*ld
)
574 sasl_conn_t
*ctx
= NULL
;
577 return( LDAP_LOCAL_ERROR
);
580 if (ld
->ld_defconn
== NULL
) {
581 LDAP_SET_LDERRNO( ld
, LDAP_LOCAL_ERROR
, NULL
, NULL
);
582 return( LDAP_LOCAL_ERROR
);
584 sb
= ld
->ld_defconn
->lconn_sb
;
585 host
= ld
->ld_defhost
;
587 if ( sb
== NULL
|| host
== NULL
) {
588 LDAP_SET_LDERRNO( ld
, LDAP_LOCAL_ERROR
, NULL
, NULL
);
589 return( LDAP_LOCAL_ERROR
);
592 if (sb
->sb_sasl_ctx
) {
593 sasl_dispose(&sb
->sb_sasl_ctx
);
594 sb
->sb_sasl_ctx
= NULL
;
597 /* SASL is not properly initialized */
598 mutex_lock(&sasl_mutex
);
600 LDAP_SET_LDERRNO( ld
, LDAP_LOCAL_ERROR
, NULL
, NULL
);
601 mutex_unlock(&sasl_mutex
);
602 return( LDAP_LOCAL_ERROR
);
605 saslrc
= _sasl_client_new(gctx
, "ldap", host
,
606 NULL
, NULL
, /* iplocal ipremote strings currently unused */
609 if ( saslrc
!= SASL_OK
) {
610 mutex_unlock(&sasl_mutex
);
612 return( nsldapi_sasl_cvterrno( ld
, saslrc
, NULL
) );
615 sb
->sb_sasl_ctx
= (void *)ctx
;
616 mutex_unlock(&sasl_mutex
);
618 return( LDAP_SUCCESS
);
622 destroy_sasliobuf(Sockbuf
*sb
)
624 if (sb
!= NULL
&& sb
->sb_sasl_ibuf
!= NULL
) {
625 NSLDAPI_FREE(sb
->sb_sasl_ibuf
);
626 sb
->sb_sasl_ibuf
= NULL
;
627 sb
->sb_sasl_iptr
= NULL
;
628 sb
->sb_sasl_bfsz
= 0;
629 sb
->sb_sasl_ilen
= 0;
634 nsldapi_sasl_close( LDAP
*ld
, Sockbuf
*sb
)
636 sasl_conn_t
*ctx
= (sasl_conn_t
*)sb
->sb_sasl_ctx
;
638 destroy_sasliobuf(sb
);
641 sasl_dispose( &ctx
);
642 sb
->sb_sasl_ctx
= NULL
;
644 return( LDAP_SUCCESS
);
648 nsldapi_sasl_do_bind( LDAP
*ld
, const char *dn
,
649 const char *mechs
, unsigned flags
,
650 LDAP_SASL_INTERACT_PROC
*callback
, void *defaults
,
651 LDAPControl
**sctrl
, LDAPControl
**cctrl
)
653 sasl_interact_t
*prompts
= NULL
;
655 sasl_ssf_t
*ssf
= NULL
;
656 const char *mech
= NULL
;
661 char *sasl_username
= NULL
;
663 if (NSLDAPI_LDAP_VERSION( ld
) < LDAP_VERSION3
) {
664 LDAP_SET_LDERRNO( ld
, LDAP_NOT_SUPPORTED
, NULL
, NULL
);
665 return( LDAP_NOT_SUPPORTED
);
668 /* shouldn't happen */
669 if (callback
== NULL
) {
670 return( LDAP_LOCAL_ERROR
);
673 if ( ld
->ld_defconn
== NULL
||
674 ld
->ld_defconn
->lconn_status
!= LDAP_CONNST_CONNECTED
) {
675 rc
= nsldapi_open_ldap_defconn( ld
);
677 return( LDAP_GET_LDERRNO( ld
, NULL
, NULL
) );
681 /* should have a valid ld connection - now create sasl connection */
682 if ((rc
= nsldapi_sasl_open(ld
)) != LDAP_SUCCESS
) {
683 LDAP_SET_LDERRNO( ld
, rc
, NULL
, NULL
);
687 /* expect context to be initialized when connection is open */
688 ctx
= (sasl_conn_t
*)ld
->ld_defconn
->lconn_sb
->sb_sasl_ctx
;
691 LDAP_SET_LDERRNO( ld
, LDAP_LOCAL_ERROR
, NULL
, NULL
);
692 return( LDAP_LOCAL_ERROR
);
695 /* (re)set security properties */
696 sasl_setprop( ctx
, SASL_SEC_PROPS
, &ld
->ld_sasl_secprops
);
701 LDAPDebug(LDAP_DEBUG_TRACE
, "Starting SASL/%s authentication\n",
702 (mech
? mech
: ""), 0, 0 );
705 saslrc
= sasl_client_start( ctx
,
708 (const char **)&ccred
.bv_val
,
712 LDAPDebug(LDAP_DEBUG_TRACE
, "Doing step %d of client start for SASL/%s authentication\n",
713 stepnum
, (mech
? mech
: ""), 0 );
716 if( saslrc
== SASL_INTERACT
&&
717 (callback
)(ld
, flags
, defaults
, prompts
) != LDAP_SUCCESS
) {
720 } while ( saslrc
== SASL_INTERACT
);
722 ccred
.bv_len
= credlen
;
724 if ( (saslrc
!= SASL_OK
) && (saslrc
!= SASL_CONTINUE
) ) {
725 return( nsldapi_sasl_cvterrno( ld
, saslrc
, nsldapi_strdup( sasl_errdetail( ctx
) ) ) );
731 struct berval
*scred
;
732 int clientstepnum
= 1;
736 LDAPDebug(LDAP_DEBUG_TRACE
, "Doing step %d of bind for SASL/%s authentication\n",
737 stepnum
, (mech
? mech
: ""), 0 );
740 /* notify server of a sasl bind step */
741 rc
= ldap_sasl_bind_s(ld
, dn
, mech
, &ccred
,
742 sctrl
, cctrl
, &scred
);
744 if ( ccred
.bv_val
!= NULL
) {
748 if ( rc
!= LDAP_SUCCESS
&& rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
753 if( rc
== LDAP_SUCCESS
&& saslrc
== SASL_OK
) {
754 /* we're done, no need to step */
756 if (scred
->bv_len
== 0 ) { /* MS AD sends back empty screds */
757 LDAPDebug(LDAP_DEBUG_ANY
,
758 "SASL BIND complete - ignoring empty credential response\n",
762 /* but server provided us with data! */
763 LDAPDebug(LDAP_DEBUG_TRACE
,
764 "SASL BIND complete but invalid because server responded with credentials - length [%u]\n",
765 scred
->bv_len
, 0, 0);
767 LDAP_SET_LDERRNO( ld
, LDAP_LOCAL_ERROR
,
768 NULL
, nsldapi_strdup( dgettext(TEXT_DOMAIN
,
769 "Error during SASL handshake - "
770 "invalid server credential response") ));
771 return( LDAP_LOCAL_ERROR
);
777 /* perform the next step of the sasl bind */
779 LDAPDebug(LDAP_DEBUG_TRACE
, "Doing client step %d of bind step %d for SASL/%s authentication\n",
780 clientstepnum
, stepnum
, (mech
? mech
: "") );
782 saslrc
= sasl_client_step( ctx
,
783 (scred
== NULL
) ? NULL
: scred
->bv_val
,
784 (scred
== NULL
) ? 0 : scred
->bv_len
,
786 (const char **)&ccred
.bv_val
,
789 if( saslrc
== SASL_INTERACT
&&
790 (callback
)(ld
, flags
, defaults
, prompts
)
794 } while ( saslrc
== SASL_INTERACT
);
796 ccred
.bv_len
= credlen
;
799 if ( (saslrc
!= SASL_OK
) && (saslrc
!= SASL_CONTINUE
) ) {
800 return( nsldapi_sasl_cvterrno( ld
, saslrc
, nsldapi_strdup( sasl_errdetail( ctx
) ) ) );
802 } while ( rc
== LDAP_SASL_BIND_IN_PROGRESS
);
804 if ( rc
!= LDAP_SUCCESS
) {
808 if ( saslrc
!= SASL_OK
) {
809 return( nsldapi_sasl_cvterrno( ld
, saslrc
, nsldapi_strdup( sasl_errdetail( ctx
) ) ) );
812 saslrc
= sasl_getprop( ctx
, SASL_USERNAME
, (const void **) &sasl_username
);
813 if ( (saslrc
== SASL_OK
) && sasl_username
) {
814 LDAPDebug(LDAP_DEBUG_TRACE
, "SASL identity: %s\n", sasl_username
, 0, 0);
817 saslrc
= sasl_getprop( ctx
, SASL_SSF
, (const void **) &ssf
);
818 if( saslrc
== SASL_OK
) {
820 LDAPDebug(LDAP_DEBUG_TRACE
,
821 "SASL install encryption, for SSF: %lu\n",
822 (unsigned long) *ssf
, 0, 0 );
824 rc
= nsldapi_sasl_install(ld
, ld
->ld_conns
->lconn_sb
, ctx
, ssf
);
830 #ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
832 * Get available SASL Mechanisms supported by the server
836 nsldapi_get_sasl_mechs ( LDAP
*ld
, char **pmech
)
838 char *attr
[] = { "supportedSASLMechanisms", NULL
};
839 char **values
, **v
, *mech
, *m
;
840 LDAPMessage
*res
, *e
;
841 struct timeval timeout
;
844 if ( !NSLDAPI_VALID_LDAP_POINTER( ld
)) {
845 return( LDAP_PARAM_ERROR
);
848 timeout
.tv_sec
= SEARCH_TIMEOUT_SECS
;
851 rc
= ldap_search_st( ld
, "", LDAP_SCOPE_BASE
,
852 "objectclass=*", attr
, 0, &timeout
, &res
);
854 if ( rc
!= LDAP_SUCCESS
) {
855 return( LDAP_GET_LDERRNO( ld
, NULL
, NULL
) );
858 e
= ldap_first_entry( ld
, res
);
861 if ( ld
->ld_errno
== LDAP_SUCCESS
) {
862 LDAP_SET_LDERRNO( ld
, LDAP_NO_SUCH_OBJECT
, NULL
, NULL
);
864 return( LDAP_GET_LDERRNO( ld
, NULL
, NULL
) );
867 values
= ldap_get_values( ld
, e
, "supportedSASLMechanisms" );
868 if ( values
== NULL
) {
870 LDAP_SET_LDERRNO( ld
, LDAP_NO_SUCH_ATTRIBUTE
, NULL
, NULL
);
871 return( LDAP_NO_SUCH_ATTRIBUTE
);
875 for(v
= values
; *v
!= NULL
; v
++ ) {
876 slen
+= strlen(*v
) + 1;
878 if ( (mech
= NSLDAPI_CALLOC(1, slen
)) == NULL
) {
879 ldap_value_free( values
);
881 LDAP_SET_LDERRNO( ld
, LDAP_NO_MEMORY
, NULL
, NULL
);
882 return( LDAP_NO_MEMORY
);
885 for(v
= values
; *v
; v
++) {
890 strncpy(m
, *v
, slen
);
895 ldap_value_free( values
);
900 return( LDAP_SUCCESS
);
904 int nsldapi_sasl_secprops(
906 sasl_security_properties_t
*secprops
)
912 sasl_ssf_t max_ssf
= 0;
913 sasl_ssf_t min_ssf
= 0;
914 unsigned maxbufsize
= 0;
918 int got_maxbufsize
= 0;
921 return LDAP_PARAM_ERROR
;
923 inp
= nsldapi_strdup(in
);
925 return LDAP_PARAM_ERROR
;
927 props
= ldap_str2charray( inp
, "," );
930 if( props
== NULL
|| secprops
== NULL
) {
931 return LDAP_PARAM_ERROR
;
934 for( i
=0; props
[i
]; i
++ ) {
935 if( strcasecmp(props
[i
], "none") == 0 ) {
938 } else if( strcasecmp(props
[i
], "noactive") == 0 ) {
940 sflags
|= SASL_SEC_NOACTIVE
;
942 } else if( strcasecmp(props
[i
], "noanonymous") == 0 ) {
944 sflags
|= SASL_SEC_NOANONYMOUS
;
946 } else if( strcasecmp(props
[i
], "nodict") == 0 ) {
948 sflags
|= SASL_SEC_NODICTIONARY
;
950 } else if( strcasecmp(props
[i
], "noplain") == 0 ) {
952 sflags
|= SASL_SEC_NOPLAINTEXT
;
954 } else if( strcasecmp(props
[i
], "forwardsec") == 0 ) {
956 sflags
|= SASL_SEC_FORWARD_SECRECY
;
958 } else if( strcasecmp(props
[i
], "passcred") == 0 ) {
960 sflags
|= SASL_SEC_PASS_CREDENTIALS
;
962 } else if( strncasecmp(props
[i
],
963 "minssf=", sizeof("minssf")) == 0 ) {
964 if( isdigit( props
[i
][sizeof("minssf")] ) ) {
966 min_ssf
= atoi( &props
[i
][sizeof("minssf")] );
968 return LDAP_NOT_SUPPORTED
;
971 } else if( strncasecmp(props
[i
],
972 "maxssf=", sizeof("maxssf")) == 0 ) {
973 if( isdigit( props
[i
][sizeof("maxssf")] ) ) {
975 max_ssf
= atoi( &props
[i
][sizeof("maxssf")] );
977 return LDAP_NOT_SUPPORTED
;
980 } else if( strncasecmp(props
[i
],
981 "maxbufsize=", sizeof("maxbufsize")) == 0 ) {
982 if( isdigit( props
[i
][sizeof("maxbufsize")] ) ) {
984 maxbufsize
= atoi( &props
[i
][sizeof("maxbufsize")] );
986 (( maxbufsize
< SASL_MIN_BUFF_SIZE
)
987 || (maxbufsize
> SASL_MAX_BUFF_SIZE
))) {
988 return( LDAP_PARAM_ERROR
);
991 return( LDAP_NOT_SUPPORTED
);
994 return( LDAP_NOT_SUPPORTED
);
999 secprops
->security_flags
= sflags
;
1002 secprops
->min_ssf
= min_ssf
;
1005 secprops
->max_ssf
= max_ssf
;
1007 if(got_maxbufsize
) {
1008 secprops
->maxbufsize
= maxbufsize
;
1011 ldap_charray_free( props
);
1012 return( LDAP_SUCCESS
);
1016 * SASL Authentication Interface: ldap_sasl_interactive_bind_s
1018 * This routine takes a DN, SASL mech list, and a SASL callback
1019 * and performs the necessary sequencing to complete a SASL bind
1020 * to the LDAP connection ld. The user provided callback can
1021 * use an optionally provided set of default values to complete
1022 * any necessary interactions.
1024 * Currently inpose the following restrictions:
1025 * A mech list must be provided, only LDAP_SASL_INTERACTIVE
1030 ldap_sasl_interactive_bind_s( LDAP
*ld
, const char *dn
,
1031 const char *saslMechanism
,
1032 LDAPControl
**sctrl
, LDAPControl
**cctrl
, unsigned flags
,
1033 LDAP_SASL_INTERACT_PROC
*callback
, void *defaults
)
1035 #ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
1040 LDAPDebug(LDAP_DEBUG_TRACE
, "ldap_sasl_interactive_bind_s\n", 0, 0, 0);
1042 if ( !NSLDAPI_VALID_LDAP_POINTER( ld
)) {
1043 return( LDAP_PARAM_ERROR
);
1046 if (flags
!= LDAP_SASL_INTERACTIVE
|| callback
== NULL
) {
1047 return( LDAP_PARAM_ERROR
);
1050 LDAP_MUTEX_LOCK(ld
, LDAP_SASL_LOCK
);
1052 if( saslMechanism
== NULL
|| *saslMechanism
== '\0' ) {
1053 #ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
1054 rc
= nsldapi_get_sasl_mechs( ld
, &smechs
);
1055 if( rc
!= LDAP_SUCCESS
) {
1056 LDAP_MUTEX_UNLOCK(ld
, LDAP_SASL_LOCK
);
1059 saslMechanism
= smechs
;
1061 LDAP_MUTEX_UNLOCK(ld
, LDAP_SASL_LOCK
);
1062 return( LDAP_PARAM_ERROR
);
1066 /* initialize SASL library */
1067 if ( nsldapi_sasl_init() < 0 ) {
1068 return( LDAP_PARAM_ERROR
);
1071 rc
= nsldapi_sasl_do_bind( ld
, dn
, saslMechanism
,
1072 flags
, callback
, defaults
, sctrl
, cctrl
);
1074 LDAP_MUTEX_UNLOCK(ld
, LDAP_SASL_LOCK
);