1 /*
2    Unix SMB/CIFS implementation.
3    ads sasl code
4    Copyright (C) Andrew Tridgell 2001
5 
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.
10 
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.
15 
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/>.
18 */
19 
20 #include "includes.h"
21 #include "../libcli/auth/spnego.h"
22 #include "auth/credentials/credentials.h"
23 #include "auth/gensec/gensec.h"
24 #include "auth_generic.h"
25 #include "ads.h"
26 #include "smb_krb5.h"
27 #include "system/gssapi.h"
28 #include "lib/param/loadparm.h"
29 #include "krb5_env.h"
30 
31 #ifdef HAVE_LDAP
32 
ads_sasl_gensec_wrap(struct ads_saslwrap * wrap,uint8_t * buf,uint32_t len)33 static ADS_STATUS ads_sasl_gensec_wrap(struct ads_saslwrap *wrap,
34 				       uint8_t *buf, uint32_t len)
35 {
36 	struct gensec_security *gensec_security =
37 		talloc_get_type_abort(wrap->wrap_private_data,
38 		struct gensec_security);
39 	NTSTATUS nt_status;
40 	DATA_BLOB unwrapped, wrapped;
41 	TALLOC_CTX *frame = talloc_stackframe();
42 
43 	unwrapped = data_blob_const(buf, len);
44 
45 	nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
46 	if (!NT_STATUS_IS_OK(nt_status)) {
47 		TALLOC_FREE(frame);
48 		return ADS_ERROR_NT(nt_status);
49 	}
50 
51 	if ((wrap->out.size - 4) < wrapped.length) {
52 		TALLOC_FREE(frame);
53 		return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
54 	}
55 
56 	/* copy the wrapped blob to the right location */
57 	memcpy(wrap->out.buf + 4, wrapped.data, wrapped.length);
58 
59 	/* set how many bytes must be written to the underlying socket */
60 	wrap->out.left = 4 + wrapped.length;
61 
62 	TALLOC_FREE(frame);
63 
64 	return ADS_SUCCESS;
65 }
66 
ads_sasl_gensec_unwrap(struct ads_saslwrap * wrap)67 static ADS_STATUS ads_sasl_gensec_unwrap(struct ads_saslwrap *wrap)
68 {
69 	struct gensec_security *gensec_security =
70 		talloc_get_type_abort(wrap->wrap_private_data,
71 		struct gensec_security);
72 	NTSTATUS nt_status;
73 	DATA_BLOB unwrapped, wrapped;
74 	TALLOC_CTX *frame = talloc_stackframe();
75 
76 	wrapped = data_blob_const(wrap->in.buf + 4, wrap->in.ofs - 4);
77 
78 	nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
79 	if (!NT_STATUS_IS_OK(nt_status)) {
80 		TALLOC_FREE(frame);
81 		return ADS_ERROR_NT(nt_status);
82 	}
83 
84 	if (wrapped.length < unwrapped.length) {
85 		TALLOC_FREE(frame);
86 		return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
87 	}
88 
89 	/* copy the wrapped blob to the right location */
90 	memcpy(wrap->in.buf + 4, unwrapped.data, unwrapped.length);
91 
92 	/* set how many bytes must be written to the underlying socket */
93 	wrap->in.left	= unwrapped.length;
94 	wrap->in.ofs	= 4;
95 
96 	TALLOC_FREE(frame);
97 
98 	return ADS_SUCCESS;
99 }
100 
ads_sasl_gensec_disconnect(struct ads_saslwrap * wrap)101 static void ads_sasl_gensec_disconnect(struct ads_saslwrap *wrap)
102 {
103 	struct gensec_security *gensec_security =
104 		talloc_get_type_abort(wrap->wrap_private_data,
105 		struct gensec_security);
106 
107 	TALLOC_FREE(gensec_security);
108 
109 	wrap->wrap_ops = NULL;
110 	wrap->wrap_private_data = NULL;
111 }
112 
113 static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
114 	.name		= "gensec",
115 	.wrap		= ads_sasl_gensec_wrap,
116 	.unwrap		= ads_sasl_gensec_unwrap,
117 	.disconnect	= ads_sasl_gensec_disconnect
118 };
119 
120 /*
121    perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
122    we fit on one socket??)
123 */
ads_sasl_spnego_gensec_bind(ADS_STRUCT * ads,const char * sasl,enum credentials_use_kerberos krb5_state,const char * target_service,const char * target_hostname,const DATA_BLOB server_blob)124 static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
125 				const char *sasl,
126 				enum credentials_use_kerberos krb5_state,
127 				const char *target_service,
128 				const char *target_hostname,
129 				const DATA_BLOB server_blob)
130 {
131 	DATA_BLOB blob_in = data_blob_null;
132 	DATA_BLOB blob_out = data_blob_null;
133 	int rc;
134 	NTSTATUS nt_status;
135 	ADS_STATUS status;
136 	struct auth_generic_state *auth_generic_state;
137 	bool use_spnego_principal = lp_client_use_spnego_principal();
138 	const char *sasl_list[] = { sasl, NULL };
139 	NTTIME end_nt_time;
140 	struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
141 
142 	nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
143 	if (!NT_STATUS_IS_OK(nt_status)) {
144 		return ADS_ERROR_NT(nt_status);
145 	}
146 
147 	if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
148 		return ADS_ERROR_NT(nt_status);
149 	}
150 	if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
151 		return ADS_ERROR_NT(nt_status);
152 	}
153 	if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
154 		return ADS_ERROR_NT(nt_status);
155 	}
156 
157 	if (server_blob.length == 0) {
158 		use_spnego_principal = false;
159 	}
160 
161 	if (krb5_state == CRED_DONT_USE_KERBEROS) {
162 		use_spnego_principal = false;
163 	}
164 
165 	cli_credentials_set_kerberos_state(auth_generic_state->credentials,
166 					   krb5_state);
167 
168 	if (target_service != NULL) {
169 		nt_status = gensec_set_target_service(
170 					auth_generic_state->gensec_security,
171 					target_service);
172 		if (!NT_STATUS_IS_OK(nt_status)) {
173 			return ADS_ERROR_NT(nt_status);
174 		}
175 	}
176 
177 	if (target_hostname != NULL) {
178 		nt_status = gensec_set_target_hostname(
179 					auth_generic_state->gensec_security,
180 					target_hostname);
181 		if (!NT_STATUS_IS_OK(nt_status)) {
182 			return ADS_ERROR_NT(nt_status);
183 		}
184 	}
185 
186 	if (target_service != NULL && target_hostname != NULL) {
187 		use_spnego_principal = false;
188 	}
189 
190 	switch (wrap->wrap_type) {
191 	case ADS_SASLWRAP_TYPE_SEAL:
192 		gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
193 		gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
194 		break;
195 	case ADS_SASLWRAP_TYPE_SIGN:
196 		if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
197 			gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
198 		} else {
199 			/*
200 			 * windows servers are broken with sign only,
201 			 * so we let the NTLMSSP backend to seal here,
202 			 * via GENSEC_FEATURE_LDAP_STYLE.
203 			 */
204 			gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
205 			gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
206 		}
207 		break;
208 	case ADS_SASLWRAP_TYPE_PLAIN:
209 		break;
210 	}
211 
212 	nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
213 						      sasl_list);
214 	if (!NT_STATUS_IS_OK(nt_status)) {
215 		return ADS_ERROR_NT(nt_status);
216 	}
217 
218 	rc = LDAP_SASL_BIND_IN_PROGRESS;
219 	if (use_spnego_principal) {
220 		blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
221 		if (blob_in.length == 0) {
222 			TALLOC_FREE(auth_generic_state);
223 			return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
224 		}
225 	} else {
226 		blob_in = data_blob_null;
227 	}
228 	blob_out = data_blob_null;
229 
230 	while (true) {
231 		struct berval cred, *scred = NULL;
232 
233 		nt_status = gensec_update(auth_generic_state->gensec_security,
234 					  talloc_tos(), blob_in, &blob_out);
235 		data_blob_free(&blob_in);
236 		if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
237 		    && !NT_STATUS_IS_OK(nt_status))
238 		{
239 			TALLOC_FREE(auth_generic_state);
240 			data_blob_free(&blob_out);
241 			return ADS_ERROR_NT(nt_status);
242 		}
243 
244 		if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
245 			break;
246 		}
247 
248 		cred.bv_val = (char *)blob_out.data;
249 		cred.bv_len = blob_out.length;
250 		scred = NULL;
251 		rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
252 		data_blob_free(&blob_out);
253 		if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
254 			if (scred) {
255 				ber_bvfree(scred);
256 			}
257 
258 			TALLOC_FREE(auth_generic_state);
259 			return ADS_ERROR(rc);
260 		}
261 		if (scred) {
262 			blob_in = data_blob_talloc(talloc_tos(),
263 						   scred->bv_val,
264 						   scred->bv_len);
265 			if (blob_in.length != scred->bv_len) {
266 				ber_bvfree(scred);
267 				TALLOC_FREE(auth_generic_state);
268 				return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
269 			}
270 			ber_bvfree(scred);
271 		} else {
272 			blob_in = data_blob_null;
273 		}
274 		if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
275 			break;
276 		}
277 	}
278 
279 	data_blob_free(&blob_in);
280 	data_blob_free(&blob_out);
281 
282 	if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
283 		bool ok;
284 
285 		ok = gensec_have_feature(auth_generic_state->gensec_security,
286 					 GENSEC_FEATURE_SEAL);
287 		if (!ok) {
288 			DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
289 			TALLOC_FREE(auth_generic_state);
290 			return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
291 		}
292 
293 		ok = gensec_have_feature(auth_generic_state->gensec_security,
294 					 GENSEC_FEATURE_SIGN);
295 		if (!ok) {
296 			DEBUG(0,("The gensec feature signing request, but unavailable\n"));
297 			TALLOC_FREE(auth_generic_state);
298 			return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
299 		}
300 
301 	} else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
302 		bool ok;
303 
304 		ok = gensec_have_feature(auth_generic_state->gensec_security,
305 					 GENSEC_FEATURE_SIGN);
306 		if (!ok) {
307 			DEBUG(0,("The gensec feature signing request, but unavailable\n"));
308 			TALLOC_FREE(auth_generic_state);
309 			return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
310 		}
311 	}
312 
313 	ads->auth.tgs_expire = LONG_MAX;
314 	end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
315 	if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
316 		struct timeval tv;
317 		nttime_to_timeval(&tv, end_nt_time);
318 		ads->auth.tgs_expire = tv.tv_sec;
319 	}
320 
321 	if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
322 		size_t max_wrapped =
323 			gensec_max_wrapped_size(auth_generic_state->gensec_security);
324 		wrap->out.max_unwrapped =
325 			gensec_max_input_size(auth_generic_state->gensec_security);
326 
327 		wrap->out.sig_size = max_wrapped - wrap->out.max_unwrapped;
328 		/*
329 		 * Note that we have to truncate this to 0x2C
330 		 * (taken from a capture with LDAP unbind), as the
331 		 * signature size is not constant for Kerberos with
332 		 * arcfour-hmac-md5.
333 		 */
334 		wrap->in.min_wrapped = MIN(wrap->out.sig_size, 0x2C);
335 		wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
336 		status = ads_setup_sasl_wrapping(wrap, ads->ldap.ld,
337 						 &ads_sasl_gensec_ops,
338 						 auth_generic_state->gensec_security);
339 		if (!ADS_ERR_OK(status)) {
340 			DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
341 				ads_errstr(status)));
342 			TALLOC_FREE(auth_generic_state);
343 			return status;
344 		}
345 		/* Only keep the gensec_security element around long-term */
346 		talloc_steal(NULL, auth_generic_state->gensec_security);
347 	}
348 	TALLOC_FREE(auth_generic_state);
349 
350 	return ADS_ERROR(rc);
351 }
352 
353 #ifdef HAVE_KRB5
ads_init_gssapi_cred(ADS_STRUCT * ads,gss_cred_id_t * cred)354 static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
355 {
356 	ADS_STATUS status;
357 	krb5_context kctx;
358 	krb5_error_code kerr;
359 	krb5_ccache kccache = NULL;
360 	uint32_t maj, min;
361 
362 	*cred = GSS_C_NO_CREDENTIAL;
363 
364 	if (!ads->auth.ccache_name) {
365 		return ADS_SUCCESS;
366 	}
367 
368 	kerr = smb_krb5_init_context_common(&kctx);
369 	if (kerr) {
370 	    DBG_ERR("kerberos init context failed (%s)\n",
371 		    error_message(kerr));
372 		return ADS_ERROR_KRB5(kerr);
373 	}
374 
375 	kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
376 	if (kerr) {
377 		status = ADS_ERROR_KRB5(kerr);
378 		goto done;
379 	}
380 
381 	maj = smb_gss_krb5_import_cred(&min, kctx, kccache, NULL, NULL, cred);
382 	if (maj != GSS_S_COMPLETE) {
383 		status = ADS_ERROR_GSS(maj, min);
384 		goto done;
385 	}
386 
387 	status = ADS_SUCCESS;
388 
389 done:
390 	if (!ADS_ERR_OK(status) && kccache != NULL) {
391 		krb5_cc_close(kctx, kccache);
392 	}
393 	krb5_free_context(kctx);
394 	return status;
395 }
396 
ads_sasl_gssapi_wrap(struct ads_saslwrap * wrap,uint8_t * buf,uint32_t len)397 static ADS_STATUS ads_sasl_gssapi_wrap(struct ads_saslwrap *wrap, uint8_t *buf, uint32_t len)
398 {
399 	gss_ctx_id_t context_handle = (gss_ctx_id_t)wrap->wrap_private_data;
400 	ADS_STATUS status;
401 	int gss_rc;
402 	uint32_t minor_status;
403 	gss_buffer_desc unwrapped, wrapped;
404 	int conf_req_flag, conf_state;
405 
406 	unwrapped.value		= buf;
407 	unwrapped.length	= len;
408 
409 	/* for now request sign and seal */
410 	conf_req_flag	= (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL);
411 
412 	gss_rc = gss_wrap(&minor_status, context_handle,
413 			  conf_req_flag, GSS_C_QOP_DEFAULT,
414 			  &unwrapped, &conf_state,
415 			  &wrapped);
416 	status = ADS_ERROR_GSS(gss_rc, minor_status);
417 	if (!ADS_ERR_OK(status)) return status;
418 
419 	if (conf_req_flag && conf_state == 0) {
420 		return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
421 	}
422 
423 	if ((wrap->out.size - 4) < wrapped.length) {
424 		return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
425 	}
426 
427 	/* copy the wrapped blob to the right location */
428 	memcpy(wrap->out.buf + 4, wrapped.value, wrapped.length);
429 
430 	/* set how many bytes must be written to the underlying socket */
431 	wrap->out.left = 4 + wrapped.length;
432 
433 	gss_release_buffer(&minor_status, &wrapped);
434 
435 	return ADS_SUCCESS;
436 }
437 
ads_sasl_gssapi_unwrap(struct ads_saslwrap * wrap)438 static ADS_STATUS ads_sasl_gssapi_unwrap(struct ads_saslwrap *wrap)
439 {
440 	gss_ctx_id_t context_handle = (gss_ctx_id_t)wrap->wrap_private_data;
441 	ADS_STATUS status;
442 	int gss_rc;
443 	uint32_t minor_status;
444 	gss_buffer_desc unwrapped, wrapped;
445 	int conf_state;
446 
447 	wrapped.value	= wrap->in.buf + 4;
448 	wrapped.length	= wrap->in.ofs - 4;
449 
450 	gss_rc = gss_unwrap(&minor_status, context_handle,
451 			    &wrapped, &unwrapped,
452 			    &conf_state, GSS_C_QOP_DEFAULT);
453 	status = ADS_ERROR_GSS(gss_rc, minor_status);
454 	if (!ADS_ERR_OK(status)) return status;
455 
456 	if (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
457 		return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
458 	}
459 
460 	if (wrapped.length < unwrapped.length) {
461 		return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
462 	}
463 
464 	/* copy the wrapped blob to the right location */
465 	memcpy(wrap->in.buf + 4, unwrapped.value, unwrapped.length);
466 
467 	/* set how many bytes must be written to the underlying socket */
468 	wrap->in.left	= unwrapped.length;
469 	wrap->in.ofs	= 4;
470 
471 	gss_release_buffer(&minor_status, &unwrapped);
472 
473 	return ADS_SUCCESS;
474 }
475 
ads_sasl_gssapi_disconnect(struct ads_saslwrap * wrap)476 static void ads_sasl_gssapi_disconnect(struct ads_saslwrap *wrap)
477 {
478 	gss_ctx_id_t context_handle = (gss_ctx_id_t)wrap->wrap_private_data;
479 	uint32_t minor_status;
480 
481 	gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
482 
483 	wrap->wrap_ops = NULL;
484 	wrap->wrap_private_data = NULL;
485 }
486 
487 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
488 	.name		= "gssapi",
489 	.wrap		= ads_sasl_gssapi_wrap,
490 	.unwrap		= ads_sasl_gssapi_unwrap,
491 	.disconnect	= ads_sasl_gssapi_disconnect
492 };
493 
494 #endif /* HAVE_KRB5 */
495 
496 #ifdef HAVE_KRB5
497 struct ads_service_principal {
498 	char *service;
499 	char *hostname;
500 	char *string;
501 #ifdef HAVE_KRB5
502 	gss_name_t name;
503 #endif
504 };
505 
ads_free_service_principal(struct ads_service_principal * p)506 static void ads_free_service_principal(struct ads_service_principal *p)
507 {
508 	SAFE_FREE(p->service);
509 	SAFE_FREE(p->hostname);
510 	SAFE_FREE(p->string);
511 
512 #ifdef HAVE_KRB5
513 	if (p->name) {
514 		uint32_t minor_status;
515 		gss_release_name(&minor_status, &p->name);
516 	}
517 #endif
518 	ZERO_STRUCTP(p);
519 }
520 
ads_guess_target(ADS_STRUCT * ads,char ** service,char ** hostname,char ** principal)521 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
522 				   char **service,
523 				   char **hostname,
524 				   char **principal)
525 {
526 	ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
527 	char *princ = NULL;
528 	TALLOC_CTX *frame;
529 	char *server = NULL;
530 	char *realm = NULL;
531 	int rc;
532 
533 	frame = talloc_stackframe();
534 	if (frame == NULL) {
535 		return ADS_ERROR(LDAP_NO_MEMORY);
536 	}
537 
538 	if (ads->server.realm && ads->server.ldap_server) {
539 		server = strlower_talloc(frame, ads->server.ldap_server);
540 		if (server == NULL) {
541 			goto out;
542 		}
543 
544 		realm = strupper_talloc(frame, ads->server.realm);
545 		if (realm == NULL) {
546 			goto out;
547 		}
548 
549 		/*
550 		 * If we got a name which is bigger than a NetBIOS name,
551 		 * but isn't a FQDN, create one.
552 		 */
553 		if (strlen(server) > 15 && strstr(server, ".") == NULL) {
554 			char *dnsdomain;
555 
556 			dnsdomain = strlower_talloc(frame, ads->server.realm);
557 			if (dnsdomain == NULL) {
558 				goto out;
559 			}
560 
561 			server = talloc_asprintf(frame,
562 						 "%s.%s",
563 						 server, dnsdomain);
564 			if (server == NULL) {
565 				goto out;
566 			}
567 		}
568 	} else if (ads->config.realm && ads->config.ldap_server_name) {
569 		server = strlower_talloc(frame, ads->config.ldap_server_name);
570 		if (server == NULL) {
571 			goto out;
572 		}
573 
574 		realm = strupper_talloc(frame, ads->config.realm);
575 		if (realm == NULL) {
576 			goto out;
577 		}
578 
579 		/*
580 		 * If we got a name which is bigger than a NetBIOS name,
581 		 * but isn't a FQDN, create one.
582 		 */
583 		if (strlen(server) > 15 && strstr(server, ".") == NULL) {
584 			char *dnsdomain;
585 
586 			dnsdomain = strlower_talloc(frame, ads->server.realm);
587 			if (dnsdomain == NULL) {
588 				goto out;
589 			}
590 
591 			server = talloc_asprintf(frame,
592 						 "%s.%s",
593 						 server, dnsdomain);
594 			if (server == NULL) {
595 				goto out;
596 			}
597 		}
598 	}
599 
600 	if (server == NULL || realm == NULL) {
601 		goto out;
602 	}
603 
604 	*service = SMB_STRDUP("ldap");
605 	if (*service == NULL) {
606 		status = ADS_ERROR(LDAP_PARAM_ERROR);
607 		goto out;
608 	}
609 	*hostname = SMB_STRDUP(server);
610 	if (*hostname == NULL) {
611 		SAFE_FREE(*service);
612 		status = ADS_ERROR(LDAP_PARAM_ERROR);
613 		goto out;
614 	}
615 	rc = asprintf(&princ, "ldap/%s@%s", server, realm);
616 	if (rc == -1 || princ == NULL) {
617 		SAFE_FREE(*service);
618 		SAFE_FREE(*hostname);
619 		status = ADS_ERROR(LDAP_PARAM_ERROR);
620 		goto out;
621 	}
622 
623 	*principal = princ;
624 
625 	status = ADS_SUCCESS;
626 out:
627 	TALLOC_FREE(frame);
628 	return status;
629 }
630 
ads_generate_service_principal(ADS_STRUCT * ads,struct ads_service_principal * p)631 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
632 						 struct ads_service_principal *p)
633 {
634 	ADS_STATUS status;
635 #ifdef HAVE_KRB5
636 	gss_buffer_desc input_name;
637 	/* GSS_KRB5_NT_PRINCIPAL_NAME */
638 	gss_OID_desc nt_principal =
639 	{10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
640 	uint32_t minor_status;
641 	int gss_rc;
642 #endif
643 
644 	ZERO_STRUCTP(p);
645 
646 	status = ads_guess_target(ads,
647 				  &p->service,
648 				  &p->hostname,
649 				  &p->string);
650 	if (!ADS_ERR_OK(status)) {
651 		return status;
652 	}
653 
654 #ifdef HAVE_KRB5
655 	input_name.value = p->string;
656 	input_name.length = strlen(p->string);
657 
658 	gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
659 	if (gss_rc) {
660 		ads_free_service_principal(p);
661 		return ADS_ERROR_GSS(gss_rc, minor_status);
662 	}
663 #endif
664 
665 	return ADS_SUCCESS;
666 }
667 
668 #endif /* HAVE_KRB5 */
669 
670 /*
671    this performs a SASL/SPNEGO bind
672 */
ads_sasl_spnego_bind(ADS_STRUCT * ads)673 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
674 {
675 	TALLOC_CTX *frame = talloc_stackframe();
676 	struct ads_service_principal p = {0};
677 	struct berval *scred=NULL;
678 	int rc, i;
679 	ADS_STATUS status;
680 	DATA_BLOB blob = data_blob_null;
681 	char *given_principal = NULL;
682 	char *OIDs[ASN1_MAX_OIDS];
683 #ifdef HAVE_KRB5
684 	bool got_kerberos_mechanism = False;
685 #endif
686 	const char *mech = NULL;
687 
688 	rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
689 
690 	if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
691 		status = ADS_ERROR(rc);
692 		goto done;
693 	}
694 
695 	blob = data_blob(scred->bv_val, scred->bv_len);
696 
697 	ber_bvfree(scred);
698 
699 #if 0
700 	file_save("sasl_spnego.dat", blob.data, blob.length);
701 #endif
702 
703 	/* the server sent us the first part of the SPNEGO exchange in the negprot
704 	   reply */
705 	if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
706 			OIDs[0] == NULL) {
707 		status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
708 		goto done;
709 	}
710 	TALLOC_FREE(given_principal);
711 
712 	/* make sure the server understands kerberos */
713 	for (i=0;OIDs[i];i++) {
714 		DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
715 #ifdef HAVE_KRB5
716 		if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
717 		    strcmp(OIDs[i], OID_KERBEROS5) == 0) {
718 			got_kerberos_mechanism = True;
719 		}
720 #endif
721 		talloc_free(OIDs[i]);
722 	}
723 
724 	status = ads_generate_service_principal(ads, &p);
725 	if (!ADS_ERR_OK(status)) {
726 		goto done;
727 	}
728 
729 #ifdef HAVE_KRB5
730 	if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
731 	    got_kerberos_mechanism)
732 	{
733 		mech = "KRB5";
734 
735 		if (ads->auth.password == NULL ||
736 		    ads->auth.password[0] == '\0')
737 		{
738 
739 			status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
740 							     CRED_MUST_USE_KERBEROS,
741 							     p.service, p.hostname,
742 							     blob);
743 			if (ADS_ERR_OK(status)) {
744 				ads_free_service_principal(&p);
745 				goto done;
746 			}
747 
748 			DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
749 				  "calling kinit\n", ads_errstr(status)));
750 		}
751 
752 		status = ADS_ERROR_KRB5(ads_kinit_password(ads));
753 
754 		if (ADS_ERR_OK(status)) {
755 			status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
756 							CRED_MUST_USE_KERBEROS,
757 							p.service, p.hostname,
758 							blob);
759 			if (!ADS_ERR_OK(status)) {
760 				DEBUG(0,("kinit succeeded but "
761 					"ads_sasl_spnego_gensec_bind(KRB5) failed "
762 					"for %s/%s with user[%s] realm[%s]: %s\n",
763 					p.service, p.hostname,
764 					ads->auth.user_name,
765 					ads->auth.realm,
766 					ads_errstr(status)));
767 			}
768 		}
769 
770 		/* only fallback to NTLMSSP if allowed */
771 		if (ADS_ERR_OK(status) ||
772 		    !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
773 			goto done;
774 		}
775 
776 		DEBUG(1,("ads_sasl_spnego_gensec_bind(KRB5) failed "
777 			 "for %s/%s with user[%s] realm[%s]: %s, "
778 			 "fallback to NTLMSSP\n",
779 			 p.service, p.hostname,
780 			 ads->auth.user_name,
781 			 ads->auth.realm,
782 			 ads_errstr(status)));
783 	}
784 #endif
785 
786 	/* lets do NTLMSSP ... this has the big advantage that we don't need
787 	   to sync clocks, and we don't rely on special versions of the krb5
788 	   library for HMAC_MD4 encryption */
789 	mech = "NTLMSSP";
790 	status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
791 					     CRED_DONT_USE_KERBEROS,
792 					     p.service, p.hostname,
793 					     data_blob_null);
794 done:
795 	if (!ADS_ERR_OK(status)) {
796 		DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
797 			 "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
798 			  p.service, p.hostname,
799 			  ads->auth.user_name,
800 			  ads->auth.realm,
801 			  ads_errstr(status)));
802 	}
803 	ads_free_service_principal(&p);
804 	TALLOC_FREE(frame);
805 	if (blob.data != NULL) {
806 		data_blob_free(&blob);
807 	}
808 	return status;
809 }
810 
811 #ifdef HAVE_KRB5
812 #define MAX_GSS_PASSES 3
813 
814 /* this performs a SASL/gssapi bind
815    we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
816    is very dependent on correctly configured DNS whereas
817    this routine is much less fragile
818    see RFC2078 and RFC2222 for details
819 */
ads_sasl_gssapi_do_bind(ADS_STRUCT * ads,const gss_name_t serv_name)820 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
821 {
822 	uint32_t minor_status;
823 	gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
824 	gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
825 	gss_OID mech_type = GSS_C_NULL_OID;
826 	gss_buffer_desc output_token, input_token;
827 	uint32_t req_flags, ret_flags;
828 	int conf_state;
829 	struct berval cred;
830 	struct berval *scred = NULL;
831 	int i=0;
832 	int gss_rc, rc;
833 	uint8_t *p;
834 	uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
835 	uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
836 	ADS_STATUS status;
837 	struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
838 
839 	input_token.value = NULL;
840 	input_token.length = 0;
841 
842 	status = ads_init_gssapi_cred(ads, &gss_cred);
843 	if (!ADS_ERR_OK(status)) {
844 		goto failed;
845 	}
846 
847 	/*
848 	 * Note: here we always ask the gssapi for sign and seal
849 	 *       as this is negotiated later after the mutal
850 	 *       authentication
851 	 */
852 	req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
853 
854 	for (i=0; i < MAX_GSS_PASSES; i++) {
855 		gss_rc = gss_init_sec_context(&minor_status,
856 					  gss_cred,
857 					  &context_handle,
858 					  serv_name,
859 					  mech_type,
860 					  req_flags,
861 					  0,
862 					  NULL,
863 					  &input_token,
864 					  NULL,
865 					  &output_token,
866 					  &ret_flags,
867 					  NULL);
868 		if (scred) {
869 			ber_bvfree(scred);
870 			scred = NULL;
871 		}
872 		if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
873 			status = ADS_ERROR_GSS(gss_rc, minor_status);
874 			goto failed;
875 		}
876 
877 		cred.bv_val = (char *)output_token.value;
878 		cred.bv_len = output_token.length;
879 
880 		rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
881 				      &scred);
882 		if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
883 			status = ADS_ERROR(rc);
884 			goto failed;
885 		}
886 
887 		if (output_token.value) {
888 			gss_release_buffer(&minor_status, &output_token);
889 		}
890 
891 		if (scred) {
892 			input_token.value = scred->bv_val;
893 			input_token.length = scred->bv_len;
894 		} else {
895 			input_token.value = NULL;
896 			input_token.length = 0;
897 		}
898 
899 		if (gss_rc == 0) break;
900 	}
901 
902 	gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
903 			    &conf_state,NULL);
904 	if (scred) {
905 		ber_bvfree(scred);
906 		scred = NULL;
907 	}
908 	if (gss_rc) {
909 		status = ADS_ERROR_GSS(gss_rc, minor_status);
910 		goto failed;
911 	}
912 
913 	p = (uint8_t *)output_token.value;
914 
915 #if 0
916 	file_save("sasl_gssapi.dat", output_token.value, output_token.length);
917 #endif
918 
919 	if (p) {
920 		wrap_type = CVAL(p,0);
921 		SCVAL(p,0,0);
922 		max_msg_size = RIVAL(p,0);
923 	}
924 
925 	gss_release_buffer(&minor_status, &output_token);
926 
927 	if (!(wrap_type & wrap->wrap_type)) {
928 		/*
929 		 * the server doesn't supports the wrap
930 		 * type we want :-(
931 		 */
932 		DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
933 			wrap->wrap_type, wrap_type));
934 		DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
935 		status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
936 		goto failed;
937 	}
938 
939 	/* 0x58 is the minimum windows accepts */
940 	if (max_msg_size < 0x58) {
941 		max_msg_size = 0x58;
942 	}
943 
944 	output_token.length = 4;
945 	output_token.value = SMB_MALLOC(output_token.length);
946 	if (!output_token.value) {
947 		output_token.length = 0;
948 		status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
949 		goto failed;
950 	}
951 	p = (uint8_t *)output_token.value;
952 
953 	RSIVAL(p,0,max_msg_size);
954 	SCVAL(p,0,wrap->wrap_type);
955 
956 	/*
957 	 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
958 	 * but using ads->config.bind_path is the wrong! It should be
959 	 * the DN of the user object!
960 	 *
961 	 * w2k3 gives an error when we send an incorrect DN, but sending nothing
962 	 * is ok and matches the information flow used in GSS-SPNEGO.
963 	 */
964 
965 	gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
966 			&output_token, /* used as *input* here. */
967 			&conf_state,
968 			&input_token); /* Used as *output* here. */
969 	if (gss_rc) {
970 		status = ADS_ERROR_GSS(gss_rc, minor_status);
971 		output_token.length = 0;
972 		SAFE_FREE(output_token.value);
973 		goto failed;
974 	}
975 
976 	/* We've finished with output_token. */
977 	SAFE_FREE(output_token.value);
978 	output_token.length = 0;
979 
980 	cred.bv_val = (char *)input_token.value;
981 	cred.bv_len = input_token.length;
982 
983 	rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
984 			      &scred);
985 	gss_release_buffer(&minor_status, &input_token);
986 	status = ADS_ERROR(rc);
987 	if (!ADS_ERR_OK(status)) {
988 		goto failed;
989 	}
990 
991 	if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
992 		gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
993 					     (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL),
994 					     GSS_C_QOP_DEFAULT,
995 					     max_msg_size, &wrap->out.max_unwrapped);
996 		if (gss_rc) {
997 			status = ADS_ERROR_GSS(gss_rc, minor_status);
998 			goto failed;
999 		}
1000 
1001 		wrap->out.sig_size = max_msg_size - wrap->out.max_unwrapped;
1002 		wrap->in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1003 		wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
1004 		status = ads_setup_sasl_wrapping(wrap->wrap_private_data, ads->ldap.ld,
1005 						 &ads_sasl_gssapi_ops,
1006 						 context_handle);
1007 		if (!ADS_ERR_OK(status)) {
1008 			DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1009 				ads_errstr(status)));
1010 			goto failed;
1011 		}
1012 		/* make sure we don't free context_handle */
1013 		context_handle = GSS_C_NO_CONTEXT;
1014 	}
1015 
1016 failed:
1017 	if (gss_cred != GSS_C_NO_CREDENTIAL)
1018 		gss_release_cred(&minor_status, &gss_cred);
1019 	if (context_handle != GSS_C_NO_CONTEXT)
1020 		gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1021 
1022 	if(scred)
1023 		ber_bvfree(scred);
1024 	return status;
1025 }
1026 
ads_sasl_gssapi_bind(ADS_STRUCT * ads)1027 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1028 {
1029 	ADS_STATUS status;
1030 	struct ads_service_principal p;
1031 
1032 	status = ads_generate_service_principal(ads, &p);
1033 	if (!ADS_ERR_OK(status)) {
1034 		return status;
1035 	}
1036 
1037 	if (ads->auth.password == NULL ||
1038 	    ads->auth.password[0] == '\0') {
1039 		status = ads_sasl_gssapi_do_bind(ads, p.name);
1040 		if (ADS_ERR_OK(status)) {
1041 			ads_free_service_principal(&p);
1042 			return status;
1043 		}
1044 
1045 		DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1046 			  "calling kinit\n", ads_errstr(status)));
1047 	}
1048 
1049 	status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1050 
1051 	if (ADS_ERR_OK(status)) {
1052 		status = ads_sasl_gssapi_do_bind(ads, p.name);
1053 	}
1054 
1055 	ads_free_service_principal(&p);
1056 
1057 	return status;
1058 }
1059 
1060 #endif /* HAVE_KRB5 */
1061 
1062 /* mapping between SASL mechanisms and functions */
1063 static struct {
1064 	const char *name;
1065 	ADS_STATUS (*fn)(ADS_STRUCT *);
1066 } sasl_mechanisms[] = {
1067 	{"GSS-SPNEGO", ads_sasl_spnego_bind},
1068 #ifdef HAVE_KRB5
1069 	{"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1070 #endif
1071 	{NULL, NULL}
1072 };
1073 
ads_sasl_bind(ADS_STRUCT * ads)1074 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1075 {
1076 	const char *attrs[] = {"supportedSASLMechanisms", NULL};
1077 	char **values;
1078 	ADS_STATUS status;
1079 	int i, j;
1080 	LDAPMessage *res;
1081 	struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
1082 
1083 	/* get a list of supported SASL mechanisms */
1084 	status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1085 	if (!ADS_ERR_OK(status)) return status;
1086 
1087 	values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1088 
1089 	if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1090 		wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1091 	} else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1092 		wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1093 	} else {
1094 		wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1095 	}
1096 
1097 	/* try our supported mechanisms in order */
1098 	for (i=0;sasl_mechanisms[i].name;i++) {
1099 		/* see if the server supports it */
1100 		for (j=0;values && values[j];j++) {
1101 			if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1102 				DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1103 retry:
1104 				status = sasl_mechanisms[i].fn(ads);
1105 				if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1106 				    status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1107 				    wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1108 				{
1109 					DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1110 						 "retrying with signing enabled\n"));
1111 					wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1112 					goto retry;
1113 				}
1114 				ldap_value_free(values);
1115 				ldap_msgfree(res);
1116 				return status;
1117 			}
1118 		}
1119 	}
1120 
1121 	ldap_value_free(values);
1122 	ldap_msgfree(res);
1123 	return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1124 }
1125 
1126 #endif /* HAVE_LDAP */
1127 
1128