VERSION: Bump version number up to 3.6.17.
[Samba.git] / source4 / auth / gensec / gensec.c
blobb9385debc35cad97280dc591b82afb42222bccc0
1 /*
2 Unix SMB/CIFS implementation.
4 Generic Authentication Interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2006
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "system/network.h"
25 #include "lib/events/events.h"
26 #include "lib/socket/socket.h"
27 #include "lib/tsocket/tsocket.h"
28 #include "../lib/util/tevent_ntstatus.h"
29 #include "librpc/rpc/dcerpc.h"
30 #include "auth/credentials/credentials.h"
31 #include "auth/gensec/gensec.h"
32 #include "auth/auth.h"
33 #include "auth/system_session_proto.h"
34 #include "param/param.h"
35 #include "lib/util/tsort.h"
37 /* the list of currently registered GENSEC backends */
38 static struct gensec_security_ops **generic_security_ops;
39 static int gensec_num_backends;
41 /* Return all the registered mechs. Don't modify the return pointer,
42 * but you may talloc_reference it if convient */
43 _PUBLIC_ struct gensec_security_ops **gensec_security_all(void)
45 return generic_security_ops;
48 bool gensec_security_ops_enabled(struct gensec_security_ops *ops, struct gensec_security *security)
50 return lpcfg_parm_bool(security->settings->lp_ctx, NULL, "gensec", ops->name, ops->enabled);
53 /* Sometimes we want to force only kerberos, sometimes we want to
54 * force it's avoidance. The old list could be either
55 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
56 * an existing list we have trimmed down) */
58 _PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
59 struct gensec_security_ops **old_gensec_list,
60 struct cli_credentials *creds)
62 struct gensec_security_ops **new_gensec_list;
63 int i, j, num_mechs_in;
64 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
66 if (creds) {
67 use_kerberos = cli_credentials_get_kerberos_state(creds);
70 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
71 if (!talloc_reference(mem_ctx, old_gensec_list)) {
72 return NULL;
74 return old_gensec_list;
77 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
78 /* noop */
81 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
82 if (!new_gensec_list) {
83 return NULL;
86 j = 0;
87 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
88 int oid_idx;
90 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
91 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
92 new_gensec_list[j] = old_gensec_list[i];
93 j++;
94 break;
97 switch (use_kerberos) {
98 case CRED_DONT_USE_KERBEROS:
99 if (old_gensec_list[i]->kerberos == false) {
100 new_gensec_list[j] = old_gensec_list[i];
101 j++;
103 break;
104 case CRED_MUST_USE_KERBEROS:
105 if (old_gensec_list[i]->kerberos == true) {
106 new_gensec_list[j] = old_gensec_list[i];
107 j++;
109 break;
110 default:
111 /* Can't happen or invalid parameter */
112 return NULL;
115 new_gensec_list[j] = NULL;
117 return new_gensec_list;
120 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
121 TALLOC_CTX *mem_ctx)
123 struct gensec_security_ops **backends;
124 backends = gensec_security_all();
125 if (!gensec_security) {
126 if (!talloc_reference(mem_ctx, backends)) {
127 return NULL;
129 return backends;
130 } else {
131 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
132 if (!creds) {
133 if (!talloc_reference(mem_ctx, backends)) {
134 return NULL;
136 return backends;
138 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
142 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
143 uint8_t auth_type)
145 int i;
146 struct gensec_security_ops **backends;
147 const struct gensec_security_ops *backend;
148 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
149 if (!mem_ctx) {
150 return NULL;
152 backends = gensec_security_mechs(gensec_security, mem_ctx);
153 for (i=0; backends && backends[i]; i++) {
154 if (!gensec_security_ops_enabled(backends[i], gensec_security))
155 continue;
156 if (backends[i]->auth_type == auth_type) {
157 backend = backends[i];
158 talloc_free(mem_ctx);
159 return backend;
162 talloc_free(mem_ctx);
164 return NULL;
167 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
168 const char *oid_string)
170 int i, j;
171 struct gensec_security_ops **backends;
172 const struct gensec_security_ops *backend;
173 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
174 if (!mem_ctx) {
175 return NULL;
177 backends = gensec_security_mechs(gensec_security, mem_ctx);
178 for (i=0; backends && backends[i]; i++) {
179 if (gensec_security != NULL &&
180 !gensec_security_ops_enabled(backends[i],
181 gensec_security))
182 continue;
183 if (backends[i]->oid) {
184 for (j=0; backends[i]->oid[j]; j++) {
185 if (backends[i]->oid[j] &&
186 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
187 backend = backends[i];
188 talloc_free(mem_ctx);
189 return backend;
194 talloc_free(mem_ctx);
196 return NULL;
199 const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
200 const char *sasl_name)
202 int i;
203 struct gensec_security_ops **backends;
204 const struct gensec_security_ops *backend;
205 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
206 if (!mem_ctx) {
207 return NULL;
209 backends = gensec_security_mechs(gensec_security, mem_ctx);
210 for (i=0; backends && backends[i]; i++) {
211 if (!gensec_security_ops_enabled(backends[i], gensec_security))
212 continue;
213 if (backends[i]->sasl_name
214 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
215 backend = backends[i];
216 talloc_free(mem_ctx);
217 return backend;
220 talloc_free(mem_ctx);
222 return NULL;
225 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
226 const char *name)
228 int i;
229 struct gensec_security_ops **backends;
230 const struct gensec_security_ops *backend;
231 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
232 if (!mem_ctx) {
233 return NULL;
235 backends = gensec_security_mechs(gensec_security, mem_ctx);
236 for (i=0; backends && backends[i]; i++) {
237 if (gensec_security != NULL &&
238 !gensec_security_ops_enabled(backends[i], gensec_security))
239 continue;
240 if (backends[i]->name
241 && (strcmp(backends[i]->name, name) == 0)) {
242 backend = backends[i];
243 talloc_free(mem_ctx);
244 return backend;
247 talloc_free(mem_ctx);
248 return NULL;
252 * Return a unique list of security subsystems from those specified in
253 * the list of SASL names.
255 * Use the list of enabled GENSEC mechanisms from the credentials
256 * attached to the gensec_security, and return in our preferred order.
259 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
260 TALLOC_CTX *mem_ctx,
261 const char **sasl_names)
263 const struct gensec_security_ops **backends_out;
264 struct gensec_security_ops **backends;
265 int i, k, sasl_idx;
266 int num_backends_out = 0;
268 if (!sasl_names) {
269 return NULL;
272 backends = gensec_security_mechs(gensec_security, mem_ctx);
274 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
275 if (!backends_out) {
276 return NULL;
278 backends_out[0] = NULL;
280 /* Find backends in our preferred order, by walking our list,
281 * then looking in the supplied list */
282 for (i=0; backends && backends[i]; i++) {
283 if (gensec_security != NULL &&
284 !gensec_security_ops_enabled(backends[i], gensec_security))
285 continue;
286 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
287 if (!backends[i]->sasl_name ||
288 !(strcmp(backends[i]->sasl_name,
289 sasl_names[sasl_idx]) == 0)) {
290 continue;
293 for (k=0; backends_out[k]; k++) {
294 if (backends_out[k] == backends[i]) {
295 break;
299 if (k < num_backends_out) {
300 /* already in there */
301 continue;
304 backends_out = talloc_realloc(mem_ctx, backends_out,
305 const struct gensec_security_ops *,
306 num_backends_out + 2);
307 if (!backends_out) {
308 return NULL;
311 backends_out[num_backends_out] = backends[i];
312 num_backends_out++;
313 backends_out[num_backends_out] = NULL;
316 return backends_out;
320 * Return a unique list of security subsystems from those specified in
321 * the OID list. That is, where two OIDs refer to the same module,
322 * return that module only once.
324 * Use the list of enabled GENSEC mechanisms from the credentials
325 * attached to the gensec_security, and return in our preferred order.
328 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
329 TALLOC_CTX *mem_ctx,
330 const char **oid_strings,
331 const char *skip)
333 struct gensec_security_ops_wrapper *backends_out;
334 struct gensec_security_ops **backends;
335 int i, j, k, oid_idx;
336 int num_backends_out = 0;
338 if (!oid_strings) {
339 return NULL;
342 backends = gensec_security_mechs(gensec_security, gensec_security);
344 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
345 if (!backends_out) {
346 return NULL;
348 backends_out[0].op = NULL;
349 backends_out[0].oid = NULL;
351 /* Find backends in our preferred order, by walking our list,
352 * then looking in the supplied list */
353 for (i=0; backends && backends[i]; i++) {
354 if (gensec_security != NULL &&
355 !gensec_security_ops_enabled(backends[i], gensec_security))
356 continue;
357 if (!backends[i]->oid) {
358 continue;
360 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
361 if (strcmp(oid_strings[oid_idx], skip) == 0) {
362 continue;
365 for (j=0; backends[i]->oid[j]; j++) {
366 if (!backends[i]->oid[j] ||
367 !(strcmp(backends[i]->oid[j],
368 oid_strings[oid_idx]) == 0)) {
369 continue;
372 for (k=0; backends_out[k].op; k++) {
373 if (backends_out[k].op == backends[i]) {
374 break;
378 if (k < num_backends_out) {
379 /* already in there */
380 continue;
383 backends_out = talloc_realloc(mem_ctx, backends_out,
384 struct gensec_security_ops_wrapper,
385 num_backends_out + 2);
386 if (!backends_out) {
387 return NULL;
390 backends_out[num_backends_out].op = backends[i];
391 backends_out[num_backends_out].oid = backends[i]->oid[j];
392 num_backends_out++;
393 backends_out[num_backends_out].op = NULL;
394 backends_out[num_backends_out].oid = NULL;
398 return backends_out;
402 * Return OIDS from the security subsystems listed
405 const char **gensec_security_oids_from_ops(struct gensec_security *gensec_security,
406 TALLOC_CTX *mem_ctx,
407 struct gensec_security_ops **ops,
408 const char *skip)
410 int i;
411 int j = 0;
412 int k;
413 const char **oid_list;
414 if (!ops) {
415 return NULL;
417 oid_list = talloc_array(mem_ctx, const char *, 1);
418 if (!oid_list) {
419 return NULL;
422 for (i=0; ops && ops[i]; i++) {
423 if (gensec_security != NULL &&
424 !gensec_security_ops_enabled(ops[i], gensec_security)) {
425 continue;
427 if (!ops[i]->oid) {
428 continue;
431 for (k = 0; ops[i]->oid[k]; k++) {
432 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
433 } else {
434 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
435 if (!oid_list) {
436 return NULL;
438 oid_list[j] = ops[i]->oid[k];
439 j++;
443 oid_list[j] = NULL;
444 return oid_list;
449 * Return OIDS from the security subsystems listed
452 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
453 const struct gensec_security_ops_wrapper *wops)
455 int i;
456 int j = 0;
457 int k;
458 const char **oid_list;
459 if (!wops) {
460 return NULL;
462 oid_list = talloc_array(mem_ctx, const char *, 1);
463 if (!oid_list) {
464 return NULL;
467 for (i=0; wops[i].op; i++) {
468 if (!wops[i].op->oid) {
469 continue;
472 for (k = 0; wops[i].op->oid[k]; k++) {
473 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
474 if (!oid_list) {
475 return NULL;
477 oid_list[j] = wops[i].op->oid[k];
478 j++;
481 oid_list[j] = NULL;
482 return oid_list;
487 * Return all the security subsystems currently enabled on a GENSEC context.
489 * This is taken from a list attached to the cli_credentials, and
490 * skips the OID in 'skip'. (Typically the SPNEGO OID)
494 const char **gensec_security_oids(struct gensec_security *gensec_security,
495 TALLOC_CTX *mem_ctx,
496 const char *skip)
498 struct gensec_security_ops **ops
499 = gensec_security_mechs(gensec_security, mem_ctx);
500 return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
506 Start the GENSEC system, returning a context pointer.
507 @param mem_ctx The parent TALLOC memory context.
508 @param gensec_security Returned GENSEC context pointer.
509 @note The mem_ctx is only a parent and may be NULL.
510 @note, the auth context is moved to be a referenced pointer of the
511 @ gensec_security return
513 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
514 struct tevent_context *ev,
515 struct gensec_settings *settings,
516 struct auth_context *auth_context,
517 struct gensec_security **gensec_security)
519 if (ev == NULL) {
520 DEBUG(0, ("No event context available!\n"));
521 return NT_STATUS_INTERNAL_ERROR;
524 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
525 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
527 (*gensec_security)->event_ctx = ev;
528 SMB_ASSERT(settings->lp_ctx != NULL);
529 (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
531 /* We need to reference this, not steal, as the caller may be
532 * python, which won't like it if we steal it's object away
533 * from it */
534 (*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context);
536 return NT_STATUS_OK;
539 /**
540 * Start a GENSEC subcontext, with a copy of the properties of the parent
541 * @param mem_ctx The parent TALLOC memory context.
542 * @param parent The parent GENSEC context
543 * @param gensec_security Returned GENSEC context pointer.
544 * @note Used by SPNEGO in particular, for the actual implementation mechanism
547 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
548 struct gensec_security *parent,
549 struct gensec_security **gensec_security)
551 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
552 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
554 (**gensec_security) = *parent;
555 (*gensec_security)->ops = NULL;
556 (*gensec_security)->private_data = NULL;
558 (*gensec_security)->subcontext = true;
559 (*gensec_security)->want_features = parent->want_features;
560 (*gensec_security)->event_ctx = parent->event_ctx;
561 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
562 (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
563 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
565 return NT_STATUS_OK;
569 Start the GENSEC system, in client mode, returning a context pointer.
570 @param mem_ctx The parent TALLOC memory context.
571 @param gensec_security Returned GENSEC context pointer.
572 @note The mem_ctx is only a parent and may be NULL.
574 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
575 struct gensec_security **gensec_security,
576 struct tevent_context *ev,
577 struct gensec_settings *settings)
579 NTSTATUS status;
581 if (settings == NULL) {
582 DEBUG(0,("gensec_client_start: no settings given!\n"));
583 return NT_STATUS_INTERNAL_ERROR;
586 status = gensec_start(mem_ctx, ev, settings, NULL, gensec_security);
587 if (!NT_STATUS_IS_OK(status)) {
588 return status;
590 (*gensec_security)->gensec_role = GENSEC_CLIENT;
592 return status;
598 Start the GENSEC system, in server mode, returning a context pointer.
599 @param mem_ctx The parent TALLOC memory context.
600 @param gensec_security Returned GENSEC context pointer.
601 @note The mem_ctx is only a parent and may be NULL.
603 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
604 struct tevent_context *ev,
605 struct gensec_settings *settings,
606 struct auth_context *auth_context,
607 struct gensec_security **gensec_security)
609 NTSTATUS status;
611 if (!ev) {
612 DEBUG(0,("gensec_server_start: no event context given!\n"));
613 return NT_STATUS_INTERNAL_ERROR;
616 if (!settings) {
617 DEBUG(0,("gensec_server_start: no settings given!\n"));
618 return NT_STATUS_INTERNAL_ERROR;
621 status = gensec_start(mem_ctx, ev, settings, auth_context, gensec_security);
622 if (!NT_STATUS_IS_OK(status)) {
623 return status;
625 (*gensec_security)->gensec_role = GENSEC_SERVER;
627 return status;
630 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
632 NTSTATUS status;
633 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
634 gensec_security->subcontext ? "sub" : "",
635 gensec_security->ops->name));
636 switch (gensec_security->gensec_role) {
637 case GENSEC_CLIENT:
638 if (gensec_security->ops->client_start) {
639 status = gensec_security->ops->client_start(gensec_security);
640 if (!NT_STATUS_IS_OK(status)) {
641 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
642 gensec_security->ops->name, nt_errstr(status)));
644 return status;
646 break;
647 case GENSEC_SERVER:
648 if (gensec_security->ops->server_start) {
649 status = gensec_security->ops->server_start(gensec_security);
650 if (!NT_STATUS_IS_OK(status)) {
651 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
652 gensec_security->ops->name, nt_errstr(status)));
654 return status;
656 break;
658 return NT_STATUS_INVALID_PARAMETER;
661 /**
662 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
663 * @param gensec_security GENSEC context pointer.
664 * @param auth_type DCERPC auth type
665 * @param auth_level DCERPC auth level
668 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
669 uint8_t auth_type, uint8_t auth_level)
671 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
672 if (!gensec_security->ops) {
673 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
674 return NT_STATUS_INVALID_PARAMETER;
676 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
677 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
678 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
679 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
680 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
681 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
682 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
683 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
684 /* Default features */
685 } else {
686 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
687 auth_level));
688 return NT_STATUS_INVALID_PARAMETER;
691 return gensec_start_mech(gensec_security);
694 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
696 const struct gensec_security_ops *ops;
697 ops = gensec_security_by_authtype(gensec_security, authtype);
698 if (ops) {
699 return ops->name;
701 return NULL;
705 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
706 const char *oid_string)
708 const struct gensec_security_ops *ops;
709 ops = gensec_security_by_oid(gensec_security, oid_string);
710 if (ops) {
711 return ops->name;
713 return oid_string;
717 * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO
721 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
722 const struct gensec_security_ops *ops)
724 gensec_security->ops = ops;
725 return gensec_start_mech(gensec_security);
728 /**
729 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
731 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
732 * well-known #define to hook it in.
735 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
736 const char *mech_oid)
738 SMB_ASSERT(gensec_security != NULL);
740 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
741 if (!gensec_security->ops) {
742 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
743 return NT_STATUS_INVALID_PARAMETER;
745 return gensec_start_mech(gensec_security);
748 /**
749 * Start a GENSEC sub-mechanism by a well know SASL name
753 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
754 const char *sasl_name)
756 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
757 if (!gensec_security->ops) {
758 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
759 return NT_STATUS_INVALID_PARAMETER;
761 return gensec_start_mech(gensec_security);
764 /**
765 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
769 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
770 const char **sasl_names)
772 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
773 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
774 const struct gensec_security_ops **ops;
775 int i;
776 if (!mem_ctx) {
777 return NT_STATUS_NO_MEMORY;
779 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
780 if (!ops || !*ops) {
781 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
782 str_list_join(mem_ctx,
783 sasl_names, ' ')));
784 talloc_free(mem_ctx);
785 return NT_STATUS_INVALID_PARAMETER;
787 for (i=0; ops[i]; i++) {
788 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
789 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
790 break;
793 talloc_free(mem_ctx);
794 return nt_status;
797 /**
798 * Start a GENSEC sub-mechanism by an internal name
802 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
803 const char *name)
805 gensec_security->ops = gensec_security_by_name(gensec_security, name);
806 if (!gensec_security->ops) {
807 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
808 return NT_STATUS_INVALID_PARAMETER;
810 return gensec_start_mech(gensec_security);
814 wrappers for the gensec function pointers
816 _PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
817 TALLOC_CTX *mem_ctx,
818 uint8_t *data, size_t length,
819 const uint8_t *whole_pdu, size_t pdu_length,
820 const DATA_BLOB *sig)
822 if (!gensec_security->ops->unseal_packet) {
823 return NT_STATUS_NOT_IMPLEMENTED;
825 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
826 return NT_STATUS_INVALID_PARAMETER;
829 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
830 data, length,
831 whole_pdu, pdu_length,
832 sig);
835 _PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
836 TALLOC_CTX *mem_ctx,
837 const uint8_t *data, size_t length,
838 const uint8_t *whole_pdu, size_t pdu_length,
839 const DATA_BLOB *sig)
841 if (!gensec_security->ops->check_packet) {
842 return NT_STATUS_NOT_IMPLEMENTED;
844 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
845 return NT_STATUS_INVALID_PARAMETER;
848 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
851 _PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
852 TALLOC_CTX *mem_ctx,
853 uint8_t *data, size_t length,
854 const uint8_t *whole_pdu, size_t pdu_length,
855 DATA_BLOB *sig)
857 if (!gensec_security->ops->seal_packet) {
858 return NT_STATUS_NOT_IMPLEMENTED;
860 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
861 return NT_STATUS_INVALID_PARAMETER;
864 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
867 _PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
868 TALLOC_CTX *mem_ctx,
869 const uint8_t *data, size_t length,
870 const uint8_t *whole_pdu, size_t pdu_length,
871 DATA_BLOB *sig)
873 if (!gensec_security->ops->sign_packet) {
874 return NT_STATUS_NOT_IMPLEMENTED;
876 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
877 return NT_STATUS_INVALID_PARAMETER;
880 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
883 _PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
885 if (!gensec_security->ops->sig_size) {
886 return 0;
888 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
889 return 0;
892 return gensec_security->ops->sig_size(gensec_security, data_size);
895 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
897 if (!gensec_security->ops->max_wrapped_size) {
898 return (1 << 17);
901 return gensec_security->ops->max_wrapped_size(gensec_security);
904 size_t gensec_max_input_size(struct gensec_security *gensec_security)
906 if (!gensec_security->ops->max_input_size) {
907 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
910 return gensec_security->ops->max_input_size(gensec_security);
913 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
914 TALLOC_CTX *mem_ctx,
915 const DATA_BLOB *in,
916 DATA_BLOB *out)
918 if (!gensec_security->ops->wrap) {
919 return NT_STATUS_NOT_IMPLEMENTED;
921 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
924 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
925 TALLOC_CTX *mem_ctx,
926 const DATA_BLOB *in,
927 DATA_BLOB *out)
929 if (!gensec_security->ops->unwrap) {
930 return NT_STATUS_NOT_IMPLEMENTED;
932 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
935 _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
936 DATA_BLOB *session_key)
938 if (!gensec_security->ops->session_key) {
939 return NT_STATUS_NOT_IMPLEMENTED;
941 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
942 return NT_STATUS_NO_USER_SESSION_KEY;
945 return gensec_security->ops->session_key(gensec_security, session_key);
948 /**
949 * Return the credentials of a logged on user, including session keys
950 * etc.
952 * Only valid after a successful authentication
954 * May only be called once per authentication.
958 _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
959 struct auth_session_info **session_info)
961 if (!gensec_security->ops->session_info) {
962 return NT_STATUS_NOT_IMPLEMENTED;
964 return gensec_security->ops->session_info(gensec_security, session_info);
968 * Next state function for the GENSEC state machine
970 * @param gensec_security GENSEC State
971 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
972 * @param in The request, as a DATA_BLOB
973 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
974 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
975 * or NT_STATUS_OK if the user is authenticated.
978 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
979 const DATA_BLOB in, DATA_BLOB *out)
981 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
984 struct gensec_update_state {
985 struct tevent_immediate *im;
986 struct gensec_security *gensec_security;
987 DATA_BLOB in;
988 DATA_BLOB out;
991 static void gensec_update_async_trigger(struct tevent_context *ctx,
992 struct tevent_immediate *im,
993 void *private_data);
995 * Next state function for the GENSEC state machine async version
997 * @param mem_ctx The memory context for the request
998 * @param ev The event context for the request
999 * @param gensec_security GENSEC State
1000 * @param in The request, as a DATA_BLOB
1002 * @return The request handle or NULL on no memory failure
1005 _PUBLIC_ struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx,
1006 struct tevent_context *ev,
1007 struct gensec_security *gensec_security,
1008 const DATA_BLOB in)
1010 struct tevent_req *req;
1011 struct gensec_update_state *state = NULL;
1013 req = tevent_req_create(mem_ctx, &state,
1014 struct gensec_update_state);
1015 if (req == NULL) {
1016 return NULL;
1019 state->gensec_security = gensec_security;
1020 state->in = in;
1021 state->out = data_blob(NULL, 0);
1022 state->im = tevent_create_immediate(state);
1023 if (tevent_req_nomem(state->im, req)) {
1024 return tevent_req_post(req, ev);
1027 tevent_schedule_immediate(state->im, ev,
1028 gensec_update_async_trigger,
1029 req);
1031 return req;
1034 static void gensec_update_async_trigger(struct tevent_context *ctx,
1035 struct tevent_immediate *im,
1036 void *private_data)
1038 struct tevent_req *req =
1039 talloc_get_type_abort(private_data, struct tevent_req);
1040 struct gensec_update_state *state =
1041 tevent_req_data(req, struct gensec_update_state);
1042 NTSTATUS status;
1044 status = gensec_update(state->gensec_security, state,
1045 state->in, &state->out);
1046 if (tevent_req_nterror(req, status)) {
1047 return;
1050 tevent_req_done(req);
1054 * Next state function for the GENSEC state machine
1056 * @param req request state
1057 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
1058 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
1059 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
1060 * or NT_STATUS_OK if the user is authenticated.
1062 _PUBLIC_ NTSTATUS gensec_update_recv(struct tevent_req *req,
1063 TALLOC_CTX *out_mem_ctx,
1064 DATA_BLOB *out)
1066 struct gensec_update_state *state =
1067 tevent_req_data(req, struct gensec_update_state);
1068 NTSTATUS status;
1070 if (tevent_req_is_nterror(req, &status)) {
1071 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1072 tevent_req_received(req);
1073 return status;
1075 } else {
1076 status = NT_STATUS_OK;
1079 *out = state->out;
1080 talloc_steal(out_mem_ctx, out->data);
1082 tevent_req_received(req);
1083 return status;
1086 /**
1087 * Set the requirement for a certain feature on the connection
1091 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1092 uint32_t feature)
1094 if (!gensec_security->ops || !gensec_security->ops->want_feature) {
1095 gensec_security->want_features |= feature;
1096 return;
1098 gensec_security->ops->want_feature(gensec_security, feature);
1101 /**
1102 * Check the requirement for a certain feature on the connection
1106 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
1107 uint32_t feature)
1109 if (!gensec_security->ops->have_feature) {
1110 return false;
1113 /* We might 'have' features that we don't 'want', because the
1114 * other end demanded them, or we can't neotiate them off */
1115 return gensec_security->ops->have_feature(gensec_security, feature);
1118 /**
1119 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1123 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1125 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1126 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1127 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1128 return NT_STATUS_OK;
1131 /**
1132 * Return the credentials structure associated with a GENSEC context
1136 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
1138 if (!gensec_security) {
1139 return NULL;
1141 return gensec_security->credentials;
1144 /**
1145 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
1149 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
1151 gensec_security->target.service = talloc_strdup(gensec_security, service);
1152 if (!gensec_security->target.service) {
1153 return NT_STATUS_NO_MEMORY;
1155 return NT_STATUS_OK;
1158 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
1160 if (gensec_security->target.service) {
1161 return gensec_security->target.service;
1164 return "host";
1167 /**
1168 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
1172 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
1174 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1175 if (hostname && !gensec_security->target.hostname) {
1176 return NT_STATUS_NO_MEMORY;
1178 return NT_STATUS_OK;
1181 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
1183 /* We allow the target hostname to be overriden for testing purposes */
1184 if (gensec_security->settings->target_hostname) {
1185 return gensec_security->settings->target_hostname;
1188 if (gensec_security->target.hostname) {
1189 return gensec_security->target.hostname;
1192 /* We could add use the 'set sockaddr' call, and do a reverse
1193 * lookup, but this would be both insecure (compromising the
1194 * way kerberos works) and add DNS timeouts */
1195 return NULL;
1199 * Set (and talloc_reference) local and peer socket addresses onto a socket
1200 * context on the GENSEC context.
1202 * This is so that kerberos can include these addresses in
1203 * cryptographic tokens, to avoid certain attacks.
1207 * @brief Set the local gensec address.
1209 * @param gensec_security The gensec security context to use.
1211 * @param remote The local address to set.
1213 * @return On success NT_STATUS_OK is returned or an NT_STATUS
1214 * error.
1216 _PUBLIC_ NTSTATUS gensec_set_local_address(struct gensec_security *gensec_security,
1217 const struct tsocket_address *local)
1219 TALLOC_FREE(gensec_security->local_addr);
1221 if (local == NULL) {
1222 return NT_STATUS_OK;
1225 gensec_security->local_addr = tsocket_address_copy(local, gensec_security);
1226 if (gensec_security->local_addr == NULL) {
1227 return NT_STATUS_NO_MEMORY;
1230 return NT_STATUS_OK;
1234 * @brief Set the remote gensec address.
1236 * @param gensec_security The gensec security context to use.
1238 * @param remote The remote address to set.
1240 * @return On success NT_STATUS_OK is returned or an NT_STATUS
1241 * error.
1243 _PUBLIC_ NTSTATUS gensec_set_remote_address(struct gensec_security *gensec_security,
1244 const struct tsocket_address *remote)
1246 TALLOC_FREE(gensec_security->remote_addr);
1248 if (remote == NULL) {
1249 return NT_STATUS_OK;
1252 gensec_security->remote_addr = tsocket_address_copy(remote, gensec_security);
1253 if (gensec_security->remote_addr == NULL) {
1254 return NT_STATUS_NO_MEMORY;
1257 return NT_STATUS_OK;
1261 * @brief Get the local address from a gensec security context.
1263 * @param gensec_security The security context to get the address from.
1265 * @return The address as tsocket_address which could be NULL if
1266 * no address is set.
1268 _PUBLIC_ const struct tsocket_address *gensec_get_local_address(struct gensec_security *gensec_security)
1270 if (gensec_security == NULL) {
1271 return NULL;
1273 return gensec_security->local_addr;
1277 * @brief Get the remote address from a gensec security context.
1279 * @param gensec_security The security context to get the address from.
1281 * @return The address as tsocket_address which could be NULL if
1282 * no address is set.
1284 _PUBLIC_ const struct tsocket_address *gensec_get_remote_address(struct gensec_security *gensec_security)
1286 if (gensec_security == NULL) {
1287 return NULL;
1289 return gensec_security->remote_addr;
1292 /**
1293 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1294 * - ensures it is talloc()ed
1298 _PUBLIC_ NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1300 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1301 if (!gensec_security->target.principal) {
1302 return NT_STATUS_NO_MEMORY;
1304 return NT_STATUS_OK;
1307 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1309 if (gensec_security->target.principal) {
1310 return gensec_security->target.principal;
1313 return NULL;
1316 NTSTATUS gensec_generate_session_info(TALLOC_CTX *mem_ctx,
1317 struct gensec_security *gensec_security,
1318 struct auth_user_info_dc *user_info_dc,
1319 struct auth_session_info **session_info)
1321 NTSTATUS nt_status;
1322 uint32_t flags = AUTH_SESSION_INFO_DEFAULT_GROUPS;
1323 if (user_info_dc->info->authenticated) {
1324 flags |= AUTH_SESSION_INFO_AUTHENTICATED;
1326 if (gensec_security->auth_context) {
1327 nt_status = gensec_security->auth_context->generate_session_info(mem_ctx, gensec_security->auth_context,
1328 user_info_dc,
1329 flags,
1330 session_info);
1331 } else {
1332 flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
1333 nt_status = auth_generate_session_info(mem_ctx,
1334 NULL,
1335 NULL,
1336 user_info_dc, flags,
1337 session_info);
1339 return nt_status;
1343 register a GENSEC backend.
1345 The 'name' can be later used by other backends to find the operations
1346 structure for this backend.
1348 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1350 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1351 /* its already registered! */
1352 DEBUG(0,("GENSEC backend '%s' already registered\n",
1353 ops->name));
1354 return NT_STATUS_OBJECT_NAME_COLLISION;
1357 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1358 generic_security_ops,
1359 struct gensec_security_ops *,
1360 gensec_num_backends+2);
1361 if (!generic_security_ops) {
1362 return NT_STATUS_NO_MEMORY;
1365 generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1366 gensec_num_backends++;
1367 generic_security_ops[gensec_num_backends] = NULL;
1369 DEBUG(3,("GENSEC backend '%s' registered\n",
1370 ops->name));
1372 return NT_STATUS_OK;
1376 return the GENSEC interface version, and the size of some critical types
1377 This can be used by backends to either detect compilation errors, or provide
1378 multiple implementations for different smbd compilation options in one module
1380 const struct gensec_critical_sizes *gensec_interface_version(void)
1382 static const struct gensec_critical_sizes critical_sizes = {
1383 GENSEC_INTERFACE_VERSION,
1384 sizeof(struct gensec_security_ops),
1385 sizeof(struct gensec_security),
1388 return &critical_sizes;
1391 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1392 return (*gs2)->priority - (*gs1)->priority;
1395 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
1397 return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
1400 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
1402 return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
1406 initialise the GENSEC subsystem
1408 _PUBLIC_ NTSTATUS gensec_init(struct loadparm_context *lp_ctx)
1410 static bool initialized = false;
1411 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1412 STATIC_gensec_MODULES_PROTO;
1413 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1414 init_module_fn *shared_init;
1416 if (initialized) return NT_STATUS_OK;
1417 initialized = true;
1419 shared_init = load_samba_modules(NULL, lp_ctx, "gensec");
1421 run_init_functions(static_init);
1422 run_init_functions(shared_init);
1424 talloc_free(shared_init);
1426 TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
1428 return NT_STATUS_OK;