s3-libsmb/clidfs.c: remove cli_nt_error()
[Samba/gebeck_regimport.git] / source3 / libads / sasl.c
bloba39971eafb7396e5e7308406f9fab95404fa212c
1 /*
2 Unix SMB/CIFS implementation.
3 ads sasl code
4 Copyright (C) Andrew Tridgell 2001
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "../libcli/auth/spnego.h"
22 #include "../auth/ntlmssp/ntlmssp.h"
23 #include "ads.h"
24 #include "smb_krb5.h"
26 #ifdef HAVE_LDAP
28 static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
30 struct ntlmssp_state *ntlmssp_state =
31 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
32 ADS_STATUS status;
33 NTSTATUS nt_status;
34 DATA_BLOB sig;
35 TALLOC_CTX *frame;
36 uint8 *dptr = ads->ldap.out.buf + (4 + NTLMSSP_SIG_SIZE);
38 frame = talloc_stackframe();
39 /* copy the data to the right location */
40 memcpy(dptr, buf, len);
42 /* create the signature and may encrypt the data */
43 if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
44 nt_status = ntlmssp_seal_packet(ntlmssp_state,
45 frame,
46 dptr, len,
47 dptr, len,
48 &sig);
49 } else {
50 nt_status = ntlmssp_sign_packet(ntlmssp_state,
51 frame,
52 dptr, len,
53 dptr, len,
54 &sig);
56 status = ADS_ERROR_NT(nt_status);
57 if (!ADS_ERR_OK(status)) return status;
59 /* copy the signature to the right location */
60 memcpy(ads->ldap.out.buf + 4,
61 sig.data, NTLMSSP_SIG_SIZE);
63 TALLOC_FREE(frame);
65 /* set how many bytes must be written to the underlying socket */
66 ads->ldap.out.left = 4 + NTLMSSP_SIG_SIZE + len;
68 return ADS_SUCCESS;
71 static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
73 struct ntlmssp_state *ntlmssp_state =
74 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
75 ADS_STATUS status;
76 NTSTATUS nt_status;
77 DATA_BLOB sig;
78 uint8 *dptr = ads->ldap.in.buf + (4 + NTLMSSP_SIG_SIZE);
79 uint32 dlen = ads->ldap.in.ofs - (4 + NTLMSSP_SIG_SIZE);
81 /* wrap the signature into a DATA_BLOB */
82 sig = data_blob_const(ads->ldap.in.buf + 4, NTLMSSP_SIG_SIZE);
84 /* verify the signature and maybe decrypt the data */
85 if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
86 nt_status = ntlmssp_unseal_packet(ntlmssp_state,
87 dptr, dlen,
88 dptr, dlen,
89 &sig);
90 } else {
91 nt_status = ntlmssp_check_packet(ntlmssp_state,
92 dptr, dlen,
93 dptr, dlen,
94 &sig);
96 status = ADS_ERROR_NT(nt_status);
97 if (!ADS_ERR_OK(status)) return status;
99 /* set the amount of bytes for the upper layer and set the ofs to the data */
100 ads->ldap.in.left = dlen;
101 ads->ldap.in.ofs = 4 + NTLMSSP_SIG_SIZE;
103 return ADS_SUCCESS;
106 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
108 struct ntlmssp_state *ntlmssp_state =
109 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
111 TALLOC_FREE(ntlmssp_state);
113 ads->ldap.wrap_ops = NULL;
114 ads->ldap.wrap_private_data = NULL;
117 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
118 .name = "ntlmssp",
119 .wrap = ads_sasl_ntlmssp_wrap,
120 .unwrap = ads_sasl_ntlmssp_unwrap,
121 .disconnect = ads_sasl_ntlmssp_disconnect
125 perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
126 we fit on one socket??)
128 static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
130 DATA_BLOB msg1 = data_blob_null;
131 DATA_BLOB blob = data_blob_null;
132 DATA_BLOB blob_in = data_blob_null;
133 DATA_BLOB blob_out = data_blob_null;
134 struct berval cred, *scred = NULL;
135 int rc;
136 NTSTATUS nt_status;
137 ADS_STATUS status;
138 int turn = 1;
139 uint32 features = 0;
141 struct ntlmssp_state *ntlmssp_state;
143 nt_status = ntlmssp_client_start(NULL,
144 lp_netbios_name(),
145 lp_workgroup(),
146 lp_client_ntlmv2_auth(),
147 &ntlmssp_state);
148 if (!NT_STATUS_IS_OK(nt_status)) {
149 return ADS_ERROR_NT(nt_status);
152 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) {
153 return ADS_ERROR_NT(nt_status);
155 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) {
156 return ADS_ERROR_NT(nt_status);
158 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) {
159 return ADS_ERROR_NT(nt_status);
162 switch (ads->ldap.wrap_type) {
163 case ADS_SASLWRAP_TYPE_SEAL:
164 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
165 break;
166 case ADS_SASLWRAP_TYPE_SIGN:
167 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
168 features = NTLMSSP_FEATURE_SIGN;
169 } else {
171 * windows servers are broken with sign only,
172 * so we need to use seal here too
174 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
175 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
177 break;
178 case ADS_SASLWRAP_TYPE_PLAIN:
179 break;
182 ntlmssp_want_feature(ntlmssp_state, features);
184 blob_in = data_blob_null;
186 do {
187 nt_status = ntlmssp_update(ntlmssp_state,
188 blob_in, &blob_out);
189 data_blob_free(&blob_in);
190 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
191 || NT_STATUS_IS_OK(nt_status))
192 && blob_out.length) {
193 if (turn == 1) {
194 const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
195 /* and wrap it in a SPNEGO wrapper */
196 msg1 = spnego_gen_negTokenInit(talloc_tos(),
197 OIDs_ntlm, &blob_out, NULL);
198 } else {
199 /* wrap it in SPNEGO */
200 msg1 = spnego_gen_auth(talloc_tos(), blob_out);
203 data_blob_free(&blob_out);
205 cred.bv_val = (char *)msg1.data;
206 cred.bv_len = msg1.length;
207 scred = NULL;
208 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
209 data_blob_free(&msg1);
210 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
211 if (scred) {
212 ber_bvfree(scred);
215 TALLOC_FREE(ntlmssp_state);
216 return ADS_ERROR(rc);
218 if (scred) {
219 blob = data_blob(scred->bv_val, scred->bv_len);
220 ber_bvfree(scred);
221 } else {
222 blob = data_blob_null;
225 } else {
227 TALLOC_FREE(ntlmssp_state);
228 data_blob_free(&blob_out);
229 return ADS_ERROR_NT(nt_status);
232 if ((turn == 1) &&
233 (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
234 DATA_BLOB tmp_blob = data_blob_null;
235 /* the server might give us back two challenges */
236 if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in,
237 &tmp_blob)) {
239 TALLOC_FREE(ntlmssp_state);
240 data_blob_free(&blob);
241 DEBUG(3,("Failed to parse challenges\n"));
242 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
244 data_blob_free(&tmp_blob);
245 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
246 if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP,
247 &blob_in)) {
249 TALLOC_FREE(ntlmssp_state);
250 data_blob_free(&blob);
251 DEBUG(3,("Failed to parse auth response\n"));
252 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
255 data_blob_free(&blob);
256 data_blob_free(&blob_out);
257 turn++;
258 } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
260 /* we have a reference conter on ntlmssp_state, if we are signing
261 then the state will be kept by the signing engine */
263 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
264 ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE;
265 ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
266 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
267 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
268 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
269 if (!ADS_ERR_OK(status)) {
270 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
271 ads_errstr(status)));
272 TALLOC_FREE(ntlmssp_state);
273 return status;
275 } else {
276 TALLOC_FREE(ntlmssp_state);
279 return ADS_ERROR(rc);
282 #ifdef HAVE_GSSAPI
283 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
285 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
286 ADS_STATUS status;
287 int gss_rc;
288 uint32 minor_status;
289 gss_buffer_desc unwrapped, wrapped;
290 int conf_req_flag, conf_state;
292 unwrapped.value = buf;
293 unwrapped.length = len;
295 /* for now request sign and seal */
296 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
298 gss_rc = gss_wrap(&minor_status, context_handle,
299 conf_req_flag, GSS_C_QOP_DEFAULT,
300 &unwrapped, &conf_state,
301 &wrapped);
302 status = ADS_ERROR_GSS(gss_rc, minor_status);
303 if (!ADS_ERR_OK(status)) return status;
305 if (conf_req_flag && conf_state == 0) {
306 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
309 if ((ads->ldap.out.size - 4) < wrapped.length) {
310 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
313 /* copy the wrapped blob to the right location */
314 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
316 /* set how many bytes must be written to the underlying socket */
317 ads->ldap.out.left = 4 + wrapped.length;
319 gss_release_buffer(&minor_status, &wrapped);
321 return ADS_SUCCESS;
324 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
326 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
327 ADS_STATUS status;
328 int gss_rc;
329 uint32 minor_status;
330 gss_buffer_desc unwrapped, wrapped;
331 int conf_state;
333 wrapped.value = ads->ldap.in.buf + 4;
334 wrapped.length = ads->ldap.in.ofs - 4;
336 gss_rc = gss_unwrap(&minor_status, context_handle,
337 &wrapped, &unwrapped,
338 &conf_state, GSS_C_QOP_DEFAULT);
339 status = ADS_ERROR_GSS(gss_rc, minor_status);
340 if (!ADS_ERR_OK(status)) return status;
342 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
343 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
346 if (wrapped.length < unwrapped.length) {
347 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
350 /* copy the wrapped blob to the right location */
351 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
353 /* set how many bytes must be written to the underlying socket */
354 ads->ldap.in.left = unwrapped.length;
355 ads->ldap.in.ofs = 4;
357 gss_release_buffer(&minor_status, &unwrapped);
359 return ADS_SUCCESS;
362 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
364 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
365 uint32 minor_status;
367 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
369 ads->ldap.wrap_ops = NULL;
370 ads->ldap.wrap_private_data = NULL;
373 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
374 .name = "gssapi",
375 .wrap = ads_sasl_gssapi_wrap,
376 .unwrap = ads_sasl_gssapi_unwrap,
377 .disconnect = ads_sasl_gssapi_disconnect
381 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
383 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
385 ADS_STATUS status;
386 bool ok;
387 uint32 minor_status;
388 int gss_rc, rc;
389 gss_OID_desc krb5_mech_type =
390 {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
391 gss_OID mech_type = &krb5_mech_type;
392 gss_OID actual_mech_type = GSS_C_NULL_OID;
393 const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
394 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
395 gss_buffer_desc input_token, output_token;
396 uint32 req_flags, ret_flags;
397 uint32 req_tmp, ret_tmp;
398 DATA_BLOB unwrapped;
399 DATA_BLOB wrapped;
400 struct berval cred, *scred = NULL;
402 input_token.value = NULL;
403 input_token.length = 0;
405 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
406 switch (ads->ldap.wrap_type) {
407 case ADS_SASLWRAP_TYPE_SEAL:
408 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
409 break;
410 case ADS_SASLWRAP_TYPE_SIGN:
411 req_flags |= GSS_C_INTEG_FLAG;
412 break;
413 case ADS_SASLWRAP_TYPE_PLAIN:
414 break;
417 /* Note: here we explicit ask for the krb5 mech_type */
418 gss_rc = gss_init_sec_context(&minor_status,
419 GSS_C_NO_CREDENTIAL,
420 &context_handle,
421 serv_name,
422 mech_type,
423 req_flags,
425 NULL,
426 &input_token,
427 &actual_mech_type,
428 &output_token,
429 &ret_flags,
430 NULL);
431 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
432 status = ADS_ERROR_GSS(gss_rc, minor_status);
433 goto failed;
437 * As some gssapi krb5 mech implementations
438 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
439 * to req_flags internaly, it's not possible to
440 * use plain or signing only connection via
441 * the gssapi interface.
443 * Because of this we need to check it the ret_flags
444 * has more flags as req_flags and correct the value
445 * of ads->ldap.wrap_type.
447 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
448 * we need to give an error.
450 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
451 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
453 if (req_tmp == ret_tmp) {
454 /* everythings fine... */
456 } else if (req_flags & GSS_C_CONF_FLAG) {
458 * here we wanted sealing but didn't got it
459 * from the gssapi library
461 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
462 goto failed;
464 } else if ((req_flags & GSS_C_INTEG_FLAG) &&
465 !(ret_flags & GSS_C_INTEG_FLAG)) {
467 * here we wanted siging but didn't got it
468 * from the gssapi library
470 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
471 goto failed;
473 } else if (ret_flags & GSS_C_CONF_FLAG) {
475 * here we didn't want sealing
476 * but the gssapi library forces it
477 * so correct the needed wrap_type if
478 * the caller didn't forced siging only
480 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
481 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
482 goto failed;
485 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
486 req_flags = ret_flags;
488 } else if (ret_flags & GSS_C_INTEG_FLAG) {
490 * here we didn't want signing
491 * but the gssapi library forces it
492 * so correct the needed wrap_type if
493 * the caller didn't forced plain
495 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
496 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
497 goto failed;
500 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
501 req_flags = ret_flags;
502 } else {
504 * This could (should?) not happen
506 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
507 goto failed;
511 /* and wrap that in a shiny SPNEGO wrapper */
512 unwrapped = data_blob_const(output_token.value, output_token.length);
513 wrapped = spnego_gen_negTokenInit(talloc_tos(),
514 spnego_mechs, &unwrapped, NULL);
515 gss_release_buffer(&minor_status, &output_token);
516 if (unwrapped.length > wrapped.length) {
517 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
518 goto failed;
521 cred.bv_val = (char *)wrapped.data;
522 cred.bv_len = wrapped.length;
524 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
525 &scred);
526 data_blob_free(&wrapped);
527 if (rc != LDAP_SUCCESS) {
528 status = ADS_ERROR(rc);
529 goto failed;
532 if (scred) {
533 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
534 } else {
535 wrapped = data_blob_null;
538 ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK,
539 OID_KERBEROS5_OLD,
540 &unwrapped);
541 if (scred) ber_bvfree(scred);
542 if (!ok) {
543 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
544 goto failed;
547 input_token.value = unwrapped.data;
548 input_token.length = unwrapped.length;
551 * As we asked for mutal authentication
552 * we need to pass the servers response
553 * to gssapi
555 gss_rc = gss_init_sec_context(&minor_status,
556 GSS_C_NO_CREDENTIAL,
557 &context_handle,
558 serv_name,
559 mech_type,
560 req_flags,
562 NULL,
563 &input_token,
564 &actual_mech_type,
565 &output_token,
566 &ret_flags,
567 NULL);
568 data_blob_free(&unwrapped);
569 if (gss_rc) {
570 status = ADS_ERROR_GSS(gss_rc, minor_status);
571 goto failed;
574 gss_release_buffer(&minor_status, &output_token);
577 * If we the sign and seal options
578 * doesn't match after getting the response
579 * from the server, we don't want to use the connection
581 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
582 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
584 if (req_tmp != ret_tmp) {
585 /* everythings fine... */
586 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
587 goto failed;
590 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
591 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
593 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
594 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
595 GSS_C_QOP_DEFAULT,
596 max_msg_size, &ads->ldap.out.max_unwrapped);
597 if (gss_rc) {
598 status = ADS_ERROR_GSS(gss_rc, minor_status);
599 goto failed;
602 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
603 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
604 ads->ldap.in.max_wrapped = max_msg_size;
605 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
606 if (!ADS_ERR_OK(status)) {
607 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
608 ads_errstr(status)));
609 goto failed;
611 /* make sure we don't free context_handle */
612 context_handle = GSS_C_NO_CONTEXT;
615 status = ADS_SUCCESS;
617 failed:
618 if (context_handle != GSS_C_NO_CONTEXT)
619 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
620 return status;
623 #endif /* HAVE_GSSAPI */
625 #ifdef HAVE_KRB5
626 struct ads_service_principal {
627 char *string;
628 #ifdef HAVE_GSSAPI
629 gss_name_t name;
630 #endif
633 static void ads_free_service_principal(struct ads_service_principal *p)
635 SAFE_FREE(p->string);
637 #ifdef HAVE_GSSAPI
638 if (p->name) {
639 uint32 minor_status;
640 gss_release_name(&minor_status, &p->name);
642 #endif
643 ZERO_STRUCTP(p);
647 static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
648 char **returned_principal)
650 char *princ = NULL;
652 if (ads->server.realm && ads->server.ldap_server) {
653 char *server, *server_realm;
655 server = SMB_STRDUP(ads->server.ldap_server);
656 server_realm = SMB_STRDUP(ads->server.realm);
658 if (!server || !server_realm) {
659 SAFE_FREE(server);
660 SAFE_FREE(server_realm);
661 return ADS_ERROR(LDAP_NO_MEMORY);
664 strlower_m(server);
665 strupper_m(server_realm);
666 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
667 SAFE_FREE(server);
668 SAFE_FREE(server_realm);
669 return ADS_ERROR(LDAP_NO_MEMORY);
672 SAFE_FREE(server);
673 SAFE_FREE(server_realm);
675 if (!princ) {
676 return ADS_ERROR(LDAP_NO_MEMORY);
678 } else if (ads->config.realm && ads->config.ldap_server_name) {
679 char *server, *server_realm;
681 server = SMB_STRDUP(ads->config.ldap_server_name);
682 server_realm = SMB_STRDUP(ads->config.realm);
684 if (!server || !server_realm) {
685 SAFE_FREE(server);
686 SAFE_FREE(server_realm);
687 return ADS_ERROR(LDAP_NO_MEMORY);
690 strlower_m(server);
691 strupper_m(server_realm);
692 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
693 SAFE_FREE(server);
694 SAFE_FREE(server_realm);
695 return ADS_ERROR(LDAP_NO_MEMORY);
698 SAFE_FREE(server);
699 SAFE_FREE(server_realm);
701 if (!princ) {
702 return ADS_ERROR(LDAP_NO_MEMORY);
706 if (!princ) {
707 return ADS_ERROR(LDAP_PARAM_ERROR);
710 *returned_principal = princ;
712 return ADS_SUCCESS;
715 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
716 const char *given_principal,
717 struct ads_service_principal *p)
719 ADS_STATUS status;
720 #ifdef HAVE_GSSAPI
721 gss_buffer_desc input_name;
722 /* GSS_KRB5_NT_PRINCIPAL_NAME */
723 gss_OID_desc nt_principal =
724 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
725 uint32 minor_status;
726 int gss_rc;
727 #endif
729 ZERO_STRUCTP(p);
731 /* I've seen a child Windows 2000 domain not send
732 the principal name back in the first round of
733 the SASL bind reply. So we guess based on server
734 name and realm. --jerry */
735 /* Also try best guess when we get the w2k8 ignore principal
736 back, or when we are configured to ignore it - gd,
737 abartlet */
739 if (!lp_client_use_spnego_principal() ||
740 !given_principal ||
741 strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
743 status = ads_guess_service_principal(ads, &p->string);
744 if (!ADS_ERR_OK(status)) {
745 return status;
747 } else {
748 p->string = SMB_STRDUP(given_principal);
749 if (!p->string) {
750 return ADS_ERROR(LDAP_NO_MEMORY);
754 #ifdef HAVE_GSSAPI
755 input_name.value = p->string;
756 input_name.length = strlen(p->string);
758 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
759 if (gss_rc) {
760 ads_free_service_principal(p);
761 return ADS_ERROR_GSS(gss_rc, minor_status);
763 #endif
765 return ADS_SUCCESS;
769 perform a LDAP/SASL/SPNEGO/KRB5 bind
771 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
773 DATA_BLOB blob = data_blob_null;
774 struct berval cred, *scred = NULL;
775 DATA_BLOB session_key = data_blob_null;
776 int rc;
778 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
779 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
782 rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal,
783 ads->auth.time_offset, &blob, &session_key, 0,
784 &ads->auth.tgs_expire);
786 if (rc) {
787 return ADS_ERROR_KRB5(rc);
790 /* now send the auth packet and we should be done */
791 cred.bv_val = (char *)blob.data;
792 cred.bv_len = blob.length;
794 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
796 data_blob_free(&blob);
797 data_blob_free(&session_key);
798 if(scred)
799 ber_bvfree(scred);
801 return ADS_ERROR(rc);
804 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
805 struct ads_service_principal *p)
807 #ifdef HAVE_GSSAPI
809 * we only use the gsskrb5 based implementation
810 * when sasl sign or seal is requested.
812 * This has the following reasons:
813 * - it's likely that the gssapi krb5 mech implementation
814 * doesn't support to negotiate plain connections
815 * - the ads_sasl_spnego_rawkrb5_bind is more robust
816 * against clock skew errors
818 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
819 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
821 #endif
822 return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
824 #endif /* HAVE_KRB5 */
827 this performs a SASL/SPNEGO bind
829 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
831 struct berval *scred=NULL;
832 int rc, i;
833 ADS_STATUS status;
834 DATA_BLOB blob;
835 char *given_principal = NULL;
836 char *OIDs[ASN1_MAX_OIDS];
837 #ifdef HAVE_KRB5
838 bool got_kerberos_mechanism = False;
839 #endif
841 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
843 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
844 status = ADS_ERROR(rc);
845 goto failed;
848 blob = data_blob(scred->bv_val, scred->bv_len);
850 ber_bvfree(scred);
852 #if 0
853 file_save("sasl_spnego.dat", blob.data, blob.length);
854 #endif
856 /* the server sent us the first part of the SPNEGO exchange in the negprot
857 reply */
858 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
859 OIDs[0] == NULL) {
860 data_blob_free(&blob);
861 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
862 goto failed;
864 data_blob_free(&blob);
866 /* make sure the server understands kerberos */
867 for (i=0;OIDs[i];i++) {
868 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
869 #ifdef HAVE_KRB5
870 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
871 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
872 got_kerberos_mechanism = True;
874 #endif
875 talloc_free(OIDs[i]);
877 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
879 #ifdef HAVE_KRB5
880 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
881 got_kerberos_mechanism)
883 struct ads_service_principal p;
885 status = ads_generate_service_principal(ads, given_principal, &p);
886 TALLOC_FREE(given_principal);
887 if (!ADS_ERR_OK(status)) {
888 return status;
891 status = ads_sasl_spnego_krb5_bind(ads, &p);
892 if (ADS_ERR_OK(status)) {
893 ads_free_service_principal(&p);
894 return status;
897 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
898 "calling kinit\n", ads_errstr(status)));
900 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
902 if (ADS_ERR_OK(status)) {
903 status = ads_sasl_spnego_krb5_bind(ads, &p);
904 if (!ADS_ERR_OK(status)) {
905 DEBUG(0,("kinit succeeded but "
906 "ads_sasl_spnego_krb5_bind failed: %s\n",
907 ads_errstr(status)));
911 ads_free_service_principal(&p);
913 /* only fallback to NTLMSSP if allowed */
914 if (ADS_ERR_OK(status) ||
915 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
916 return status;
918 } else
919 #endif
921 TALLOC_FREE(given_principal);
924 /* lets do NTLMSSP ... this has the big advantage that we don't need
925 to sync clocks, and we don't rely on special versions of the krb5
926 library for HMAC_MD4 encryption */
927 return ads_sasl_spnego_ntlmssp_bind(ads);
929 failed:
930 return status;
933 #ifdef HAVE_GSSAPI
934 #define MAX_GSS_PASSES 3
936 /* this performs a SASL/gssapi bind
937 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
938 is very dependent on correctly configured DNS whereas
939 this routine is much less fragile
940 see RFC2078 and RFC2222 for details
942 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
944 uint32 minor_status;
945 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
946 gss_OID mech_type = GSS_C_NULL_OID;
947 gss_buffer_desc output_token, input_token;
948 uint32 req_flags, ret_flags;
949 int conf_state;
950 struct berval cred;
951 struct berval *scred = NULL;
952 int i=0;
953 int gss_rc, rc;
954 uint8 *p;
955 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
956 uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
957 ADS_STATUS status;
959 input_token.value = NULL;
960 input_token.length = 0;
963 * Note: here we always ask the gssapi for sign and seal
964 * as this is negotiated later after the mutal
965 * authentication
967 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
969 for (i=0; i < MAX_GSS_PASSES; i++) {
970 gss_rc = gss_init_sec_context(&minor_status,
971 GSS_C_NO_CREDENTIAL,
972 &context_handle,
973 serv_name,
974 mech_type,
975 req_flags,
977 NULL,
978 &input_token,
979 NULL,
980 &output_token,
981 &ret_flags,
982 NULL);
983 if (scred) {
984 ber_bvfree(scred);
985 scred = NULL;
987 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
988 status = ADS_ERROR_GSS(gss_rc, minor_status);
989 goto failed;
992 cred.bv_val = (char *)output_token.value;
993 cred.bv_len = output_token.length;
995 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
996 &scred);
997 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
998 status = ADS_ERROR(rc);
999 goto failed;
1002 if (output_token.value) {
1003 gss_release_buffer(&minor_status, &output_token);
1006 if (scred) {
1007 input_token.value = scred->bv_val;
1008 input_token.length = scred->bv_len;
1009 } else {
1010 input_token.value = NULL;
1011 input_token.length = 0;
1014 if (gss_rc == 0) break;
1017 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
1018 &conf_state,NULL);
1019 if (scred) {
1020 ber_bvfree(scred);
1021 scred = NULL;
1023 if (gss_rc) {
1024 status = ADS_ERROR_GSS(gss_rc, minor_status);
1025 goto failed;
1028 p = (uint8 *)output_token.value;
1030 #if 0
1031 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
1032 #endif
1034 if (p) {
1035 wrap_type = CVAL(p,0);
1036 SCVAL(p,0,0);
1037 max_msg_size = RIVAL(p,0);
1040 gss_release_buffer(&minor_status, &output_token);
1042 if (!(wrap_type & ads->ldap.wrap_type)) {
1044 * the server doesn't supports the wrap
1045 * type we want :-(
1047 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
1048 ads->ldap.wrap_type, wrap_type));
1049 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
1050 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
1051 goto failed;
1054 /* 0x58 is the minimum windows accepts */
1055 if (max_msg_size < 0x58) {
1056 max_msg_size = 0x58;
1059 output_token.length = 4;
1060 output_token.value = SMB_MALLOC(output_token.length);
1061 if (!output_token.value) {
1062 output_token.length = 0;
1063 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1064 goto failed;
1066 p = (uint8 *)output_token.value;
1068 RSIVAL(p,0,max_msg_size);
1069 SCVAL(p,0,ads->ldap.wrap_type);
1072 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1073 * but using ads->config.bind_path is the wrong! It should be
1074 * the DN of the user object!
1076 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1077 * is ok and matches the information flow used in GSS-SPNEGO.
1080 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
1081 &output_token, /* used as *input* here. */
1082 &conf_state,
1083 &input_token); /* Used as *output* here. */
1084 if (gss_rc) {
1085 status = ADS_ERROR_GSS(gss_rc, minor_status);
1086 output_token.length = 0;
1087 SAFE_FREE(output_token.value);
1088 goto failed;
1091 /* We've finished with output_token. */
1092 SAFE_FREE(output_token.value);
1093 output_token.length = 0;
1095 cred.bv_val = (char *)input_token.value;
1096 cred.bv_len = input_token.length;
1098 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1099 &scred);
1100 gss_release_buffer(&minor_status, &input_token);
1101 status = ADS_ERROR(rc);
1102 if (!ADS_ERR_OK(status)) {
1103 goto failed;
1106 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1107 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1108 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1109 GSS_C_QOP_DEFAULT,
1110 max_msg_size, &ads->ldap.out.max_unwrapped);
1111 if (gss_rc) {
1112 status = ADS_ERROR_GSS(gss_rc, minor_status);
1113 goto failed;
1116 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1117 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1118 ads->ldap.in.max_wrapped = max_msg_size;
1119 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1120 if (!ADS_ERR_OK(status)) {
1121 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1122 ads_errstr(status)));
1123 goto failed;
1125 /* make sure we don't free context_handle */
1126 context_handle = GSS_C_NO_CONTEXT;
1129 failed:
1131 if (context_handle != GSS_C_NO_CONTEXT)
1132 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1134 if(scred)
1135 ber_bvfree(scred);
1136 return status;
1139 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1141 ADS_STATUS status;
1142 struct ads_service_principal p;
1144 status = ads_generate_service_principal(ads, NULL, &p);
1145 if (!ADS_ERR_OK(status)) {
1146 return status;
1149 status = ads_sasl_gssapi_do_bind(ads, p.name);
1150 if (ADS_ERR_OK(status)) {
1151 ads_free_service_principal(&p);
1152 return status;
1155 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1156 "calling kinit\n", ads_errstr(status)));
1158 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1160 if (ADS_ERR_OK(status)) {
1161 status = ads_sasl_gssapi_do_bind(ads, p.name);
1164 ads_free_service_principal(&p);
1166 return status;
1169 #endif /* HAVE_GSSAPI */
1171 /* mapping between SASL mechanisms and functions */
1172 static struct {
1173 const char *name;
1174 ADS_STATUS (*fn)(ADS_STRUCT *);
1175 } sasl_mechanisms[] = {
1176 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1177 #ifdef HAVE_GSSAPI
1178 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1179 #endif
1180 {NULL, NULL}
1183 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1185 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1186 char **values;
1187 ADS_STATUS status;
1188 int i, j;
1189 LDAPMessage *res;
1191 /* get a list of supported SASL mechanisms */
1192 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1193 if (!ADS_ERR_OK(status)) return status;
1195 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1197 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1198 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1199 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1200 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1201 } else {
1202 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1205 /* try our supported mechanisms in order */
1206 for (i=0;sasl_mechanisms[i].name;i++) {
1207 /* see if the server supports it */
1208 for (j=0;values && values[j];j++) {
1209 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1210 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1211 retry:
1212 status = sasl_mechanisms[i].fn(ads);
1213 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1214 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1215 ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1217 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1218 "retrying with signing enabled\n"));
1219 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1220 goto retry;
1222 ldap_value_free(values);
1223 ldap_msgfree(res);
1224 return status;
1229 ldap_value_free(values);
1230 ldap_msgfree(res);
1231 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1234 #endif /* HAVE_LDAP */