Remove more event_context_init() uses from function calls within deep down the code.
[Samba/aatanasov.git] / source4 / auth / gensec / gensec.c
blobc82b719dfd87e1ca8d68f9daffa7a55ab43b15fa
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 "auth/auth.h"
25 #include "lib/events/events.h"
26 #include "build.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/gensec/gensec.h"
30 #include "auth/gensec/gensec_proto.h"
31 #include "param/param.h"
33 /* the list of currently registered GENSEC backends */
34 static struct gensec_security_ops **generic_security_ops;
35 static int gensec_num_backends;
37 /* Return all the registered mechs. Don't modify the return pointer,
38 * but you may talloc_reference it if convient */
39 _PUBLIC_ struct gensec_security_ops **gensec_security_all(void)
41 return generic_security_ops;
44 /* Sometimes we want to force only kerberos, sometimes we want to
45 * force it's avoidance. The old list could be either
46 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
47 * an existing list we have trimmed down) */
49 _PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
50 struct gensec_security_ops **old_gensec_list,
51 struct cli_credentials *creds)
53 struct gensec_security_ops **new_gensec_list;
54 int i, j, num_mechs_in;
55 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
57 if (creds) {
58 use_kerberos = cli_credentials_get_kerberos_state(creds);
61 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
62 if (!talloc_reference(mem_ctx, old_gensec_list)) {
63 return NULL;
65 return old_gensec_list;
68 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
69 /* noop */
72 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
73 if (!new_gensec_list) {
74 return NULL;
77 j = 0;
78 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
79 int oid_idx;
80 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
81 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
82 new_gensec_list[j] = old_gensec_list[i];
83 j++;
84 break;
87 switch (use_kerberos) {
88 case CRED_DONT_USE_KERBEROS:
89 if (old_gensec_list[i]->kerberos == false) {
90 new_gensec_list[j] = old_gensec_list[i];
91 j++;
93 break;
94 case CRED_MUST_USE_KERBEROS:
95 if (old_gensec_list[i]->kerberos == true) {
96 new_gensec_list[j] = old_gensec_list[i];
97 j++;
99 break;
100 default:
101 /* Can't happen or invalid parameter */
102 return NULL;
105 new_gensec_list[j] = NULL;
107 return new_gensec_list;
110 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
111 TALLOC_CTX *mem_ctx)
113 struct gensec_security_ops **backends;
114 backends = gensec_security_all();
115 if (!gensec_security) {
116 if (!talloc_reference(mem_ctx, backends)) {
117 return NULL;
119 return backends;
120 } else {
121 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
122 if (!creds) {
123 if (!talloc_reference(mem_ctx, backends)) {
124 return NULL;
126 return backends;
128 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
132 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
133 uint8_t auth_type)
135 int i;
136 struct gensec_security_ops **backends;
137 const struct gensec_security_ops *backend;
138 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
139 if (!mem_ctx) {
140 return NULL;
142 backends = gensec_security_mechs(gensec_security, mem_ctx);
143 for (i=0; backends && backends[i]; i++) {
144 if (backends[i]->auth_type == auth_type) {
145 backend = backends[i];
146 talloc_free(mem_ctx);
147 return backend;
150 talloc_free(mem_ctx);
152 return NULL;
155 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
156 const char *oid_string)
158 int i, j;
159 struct gensec_security_ops **backends;
160 const struct gensec_security_ops *backend;
161 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
162 if (!mem_ctx) {
163 return NULL;
165 backends = gensec_security_mechs(gensec_security, mem_ctx);
166 for (i=0; backends && backends[i]; i++) {
167 if (backends[i]->oid) {
168 for (j=0; backends[i]->oid[j]; j++) {
169 if (backends[i]->oid[j] &&
170 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
171 backend = backends[i];
172 talloc_free(mem_ctx);
173 return backend;
178 talloc_free(mem_ctx);
180 return NULL;
183 const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
184 const char *sasl_name)
186 int i;
187 struct gensec_security_ops **backends;
188 const struct gensec_security_ops *backend;
189 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
190 if (!mem_ctx) {
191 return NULL;
193 backends = gensec_security_mechs(gensec_security, mem_ctx);
194 for (i=0; backends && backends[i]; i++) {
195 if (backends[i]->sasl_name
196 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
197 backend = backends[i];
198 talloc_free(mem_ctx);
199 return backend;
202 talloc_free(mem_ctx);
204 return NULL;
207 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
208 const char *name)
210 int i;
211 struct gensec_security_ops **backends;
212 const struct gensec_security_ops *backend;
213 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
214 if (!mem_ctx) {
215 return NULL;
217 backends = gensec_security_mechs(gensec_security, mem_ctx);
218 for (i=0; backends && backends[i]; i++) {
219 if (backends[i]->name
220 && (strcmp(backends[i]->name, name) == 0)) {
221 backend = backends[i];
222 talloc_free(mem_ctx);
223 return backend;
226 talloc_free(mem_ctx);
227 return NULL;
231 * Return a unique list of security subsystems from those specified in
232 * the list of SASL names.
234 * Use the list of enabled GENSEC mechanisms from the credentials
235 * attached to the gensec_security, and return in our preferred order.
238 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
239 TALLOC_CTX *mem_ctx,
240 const char **sasl_names)
242 const struct gensec_security_ops **backends_out;
243 struct gensec_security_ops **backends;
244 int i, k, sasl_idx;
245 int num_backends_out = 0;
247 if (!sasl_names) {
248 return NULL;
251 backends = gensec_security_mechs(gensec_security, mem_ctx);
253 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
254 if (!backends_out) {
255 return NULL;
257 backends_out[0] = NULL;
259 /* Find backends in our preferred order, by walking our list,
260 * then looking in the supplied list */
261 for (i=0; backends && backends[i]; i++) {
262 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
263 if (!backends[i]->sasl_name ||
264 !(strcmp(backends[i]->sasl_name,
265 sasl_names[sasl_idx]) == 0)) {
266 continue;
269 for (k=0; backends_out[k]; k++) {
270 if (backends_out[k] == backends[i]) {
271 break;
275 if (k < num_backends_out) {
276 /* already in there */
277 continue;
280 backends_out = talloc_realloc(mem_ctx, backends_out,
281 const struct gensec_security_ops *,
282 num_backends_out + 2);
283 if (!backends_out) {
284 return NULL;
287 backends_out[num_backends_out] = backends[i];
288 num_backends_out++;
289 backends_out[num_backends_out] = NULL;
292 return backends_out;
296 * Return a unique list of security subsystems from those specified in
297 * the OID list. That is, where two OIDs refer to the same module,
298 * return that module only once.
300 * Use the list of enabled GENSEC mechanisms from the credentials
301 * attached to the gensec_security, and return in our preferred order.
304 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
305 TALLOC_CTX *mem_ctx,
306 const char **oid_strings,
307 const char *skip)
309 struct gensec_security_ops_wrapper *backends_out;
310 struct gensec_security_ops **backends;
311 int i, j, k, oid_idx;
312 int num_backends_out = 0;
314 if (!oid_strings) {
315 return NULL;
318 backends = gensec_security_mechs(gensec_security, gensec_security);
320 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
321 if (!backends_out) {
322 return NULL;
324 backends_out[0].op = NULL;
325 backends_out[0].oid = NULL;
327 /* Find backends in our preferred order, by walking our list,
328 * then looking in the supplied list */
329 for (i=0; backends && backends[i]; i++) {
330 if (!backends[i]->oid) {
331 continue;
333 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
334 if (strcmp(oid_strings[oid_idx], skip) == 0) {
335 continue;
338 for (j=0; backends[i]->oid[j]; j++) {
339 if (!backends[i]->oid[j] ||
340 !(strcmp(backends[i]->oid[j],
341 oid_strings[oid_idx]) == 0)) {
342 continue;
345 for (k=0; backends_out[k].op; k++) {
346 if (backends_out[k].op == backends[i]) {
347 break;
351 if (k < num_backends_out) {
352 /* already in there */
353 continue;
356 backends_out = talloc_realloc(mem_ctx, backends_out,
357 struct gensec_security_ops_wrapper,
358 num_backends_out + 2);
359 if (!backends_out) {
360 return NULL;
363 backends_out[num_backends_out].op = backends[i];
364 backends_out[num_backends_out].oid = backends[i]->oid[j];
365 num_backends_out++;
366 backends_out[num_backends_out].op = NULL;
367 backends_out[num_backends_out].oid = NULL;
371 return backends_out;
375 * Return OIDS from the security subsystems listed
378 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
379 struct gensec_security_ops **ops,
380 const char *skip)
382 int i;
383 int j = 0;
384 int k;
385 const char **oid_list;
386 if (!ops) {
387 return NULL;
389 oid_list = talloc_array(mem_ctx, const char *, 1);
390 if (!oid_list) {
391 return NULL;
394 for (i=0; ops && ops[i]; i++) {
395 if (!ops[i]->oid) {
396 continue;
399 for (k = 0; ops[i]->oid[k]; k++) {
400 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
401 } else {
402 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
403 if (!oid_list) {
404 return NULL;
406 oid_list[j] = ops[i]->oid[k];
407 j++;
411 oid_list[j] = NULL;
412 return oid_list;
417 * Return OIDS from the security subsystems listed
420 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
421 const struct gensec_security_ops_wrapper *wops)
423 int i;
424 int j = 0;
425 int k;
426 const char **oid_list;
427 if (!wops) {
428 return NULL;
430 oid_list = talloc_array(mem_ctx, const char *, 1);
431 if (!oid_list) {
432 return NULL;
435 for (i=0; wops[i].op; i++) {
436 if (!wops[i].op->oid) {
437 continue;
440 for (k = 0; wops[i].op->oid[k]; k++) {
441 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
442 if (!oid_list) {
443 return NULL;
445 oid_list[j] = wops[i].op->oid[k];
446 j++;
449 oid_list[j] = NULL;
450 return oid_list;
455 * Return all the security subsystems currently enabled on a GENSEC context.
457 * This is taken from a list attached to the cli_credentials, and
458 * skips the OID in 'skip'. (Typically the SPNEGO OID)
462 const char **gensec_security_oids(struct gensec_security *gensec_security,
463 TALLOC_CTX *mem_ctx,
464 const char *skip)
466 struct gensec_security_ops **ops
467 = gensec_security_mechs(gensec_security, mem_ctx);
468 return gensec_security_oids_from_ops(mem_ctx, ops, skip);
474 Start the GENSEC system, returning a context pointer.
475 @param mem_ctx The parent TALLOC memory context.
476 @param gensec_security Returned GENSEC context pointer.
477 @note The mem_ctx is only a parent and may be NULL.
479 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
480 struct event_context *ev,
481 struct loadparm_context *lp_ctx,
482 struct messaging_context *msg,
483 struct gensec_security **gensec_security)
485 if (ev == NULL) {
486 DEBUG(0, ("No event context available!\n"));
487 return NT_STATUS_INTERNAL_ERROR;
490 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
491 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
493 (*gensec_security)->ops = NULL;
495 ZERO_STRUCT((*gensec_security)->target);
496 ZERO_STRUCT((*gensec_security)->peer_addr);
497 ZERO_STRUCT((*gensec_security)->my_addr);
499 (*gensec_security)->subcontext = false;
500 (*gensec_security)->want_features = 0;
502 (*gensec_security)->event_ctx = ev;
503 (*gensec_security)->msg_ctx = msg;
504 (*gensec_security)->lp_ctx = lp_ctx;
506 return NT_STATUS_OK;
509 /**
510 * Start a GENSEC subcontext, with a copy of the properties of the parent
511 * @param mem_ctx The parent TALLOC memory context.
512 * @param parent The parent GENSEC context
513 * @param gensec_security Returned GENSEC context pointer.
514 * @note Used by SPNEGO in particular, for the actual implementation mechanism
517 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
518 struct gensec_security *parent,
519 struct gensec_security **gensec_security)
521 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
522 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
524 (**gensec_security) = *parent;
525 (*gensec_security)->ops = NULL;
526 (*gensec_security)->private_data = NULL;
528 (*gensec_security)->subcontext = true;
529 (*gensec_security)->event_ctx = parent->event_ctx;
530 (*gensec_security)->msg_ctx = parent->msg_ctx;
531 (*gensec_security)->lp_ctx = parent->lp_ctx;
533 return NT_STATUS_OK;
537 Start the GENSEC system, in client mode, returning a context pointer.
538 @param mem_ctx The parent TALLOC memory context.
539 @param gensec_security Returned GENSEC context pointer.
540 @note The mem_ctx is only a parent and may be NULL.
542 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
543 struct gensec_security **gensec_security,
544 struct event_context *ev,
545 struct loadparm_context *lp_ctx)
547 NTSTATUS status;
549 status = gensec_start(mem_ctx, ev, lp_ctx, NULL, gensec_security);
550 if (!NT_STATUS_IS_OK(status)) {
551 return status;
553 (*gensec_security)->gensec_role = GENSEC_CLIENT;
555 return status;
559 Start the GENSEC system, in server mode, returning a context pointer.
560 @param mem_ctx The parent TALLOC memory context.
561 @param gensec_security Returned GENSEC context pointer.
562 @note The mem_ctx is only a parent and may be NULL.
564 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
565 struct event_context *ev,
566 struct loadparm_context *lp_ctx,
567 struct messaging_context *msg,
568 struct gensec_security **gensec_security)
570 NTSTATUS status;
572 if (!ev) {
573 DEBUG(0,("gensec_server_start: no event context given!\n"));
574 return NT_STATUS_INTERNAL_ERROR;
577 if (!msg) {
578 DEBUG(0,("gensec_server_start: no messaging context given!\n"));
579 return NT_STATUS_INTERNAL_ERROR;
582 status = gensec_start(mem_ctx, ev, lp_ctx, msg, gensec_security);
583 if (!NT_STATUS_IS_OK(status)) {
584 return status;
586 (*gensec_security)->gensec_role = GENSEC_SERVER;
588 return status;
591 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
593 NTSTATUS status;
594 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
595 gensec_security->subcontext ? "sub" : "",
596 gensec_security->ops->name));
597 switch (gensec_security->gensec_role) {
598 case GENSEC_CLIENT:
599 if (gensec_security->ops->client_start) {
600 status = gensec_security->ops->client_start(gensec_security);
601 if (!NT_STATUS_IS_OK(status)) {
602 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
603 gensec_security->ops->name, nt_errstr(status)));
605 return status;
607 break;
608 case GENSEC_SERVER:
609 if (gensec_security->ops->server_start) {
610 status = gensec_security->ops->server_start(gensec_security);
611 if (!NT_STATUS_IS_OK(status)) {
612 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
613 gensec_security->ops->name, nt_errstr(status)));
615 return status;
617 break;
619 return NT_STATUS_INVALID_PARAMETER;
622 /**
623 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
624 * @param gensec_security GENSEC context pointer.
625 * @param auth_type DCERPC auth type
626 * @param auth_level DCERPC auth level
629 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
630 uint8_t auth_type, uint8_t auth_level)
632 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
633 if (!gensec_security->ops) {
634 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
635 return NT_STATUS_INVALID_PARAMETER;
637 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
638 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
639 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
640 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
641 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
642 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
643 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
644 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
645 /* Default features */
646 } else {
647 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
648 auth_level));
649 return NT_STATUS_INVALID_PARAMETER;
652 return gensec_start_mech(gensec_security);
655 _PUBLIC_ const char *gensec_get_name_by_authtype(uint8_t authtype)
657 const struct gensec_security_ops *ops;
658 ops = gensec_security_by_authtype(NULL, authtype);
659 if (ops) {
660 return ops->name;
662 return NULL;
666 _PUBLIC_ const char *gensec_get_name_by_oid(const char *oid_string)
668 const struct gensec_security_ops *ops;
669 ops = gensec_security_by_oid(NULL, oid_string);
670 if (ops) {
671 return ops->name;
673 return oid_string;
677 /**
678 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
682 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
683 const struct gensec_security_ops *ops)
685 gensec_security->ops = ops;
686 return gensec_start_mech(gensec_security);
689 /**
690 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
692 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
693 * well-known #define to hook it in.
696 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
697 const char *mech_oid)
699 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
700 if (!gensec_security->ops) {
701 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
702 return NT_STATUS_INVALID_PARAMETER;
704 return gensec_start_mech(gensec_security);
707 /**
708 * Start a GENSEC sub-mechanism by a well know SASL name
712 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
713 const char *sasl_name)
715 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
716 if (!gensec_security->ops) {
717 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
718 return NT_STATUS_INVALID_PARAMETER;
720 return gensec_start_mech(gensec_security);
723 /**
724 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
728 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
729 const char **sasl_names)
731 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
732 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
733 const struct gensec_security_ops **ops;
734 int i;
735 if (!mem_ctx) {
736 return NT_STATUS_NO_MEMORY;
738 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
739 if (!ops || !*ops) {
740 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
741 str_list_join(mem_ctx,
742 sasl_names, ' ')));
743 talloc_free(mem_ctx);
744 return NT_STATUS_INVALID_PARAMETER;
746 for (i=0; ops[i]; i++) {
747 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
748 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
749 break;
752 talloc_free(mem_ctx);
753 return nt_status;
756 /**
757 * Start a GENSEC sub-mechanism by an internal name
761 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
762 const char *name)
764 gensec_security->ops = gensec_security_by_name(gensec_security, name);
765 if (!gensec_security->ops) {
766 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
767 return NT_STATUS_INVALID_PARAMETER;
769 return gensec_start_mech(gensec_security);
773 wrappers for the gensec function pointers
775 _PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
776 TALLOC_CTX *mem_ctx,
777 uint8_t *data, size_t length,
778 const uint8_t *whole_pdu, size_t pdu_length,
779 const DATA_BLOB *sig)
781 if (!gensec_security->ops->unseal_packet) {
782 return NT_STATUS_NOT_IMPLEMENTED;
784 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
785 return NT_STATUS_INVALID_PARAMETER;
788 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
789 data, length,
790 whole_pdu, pdu_length,
791 sig);
794 _PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
795 TALLOC_CTX *mem_ctx,
796 const uint8_t *data, size_t length,
797 const uint8_t *whole_pdu, size_t pdu_length,
798 const DATA_BLOB *sig)
800 if (!gensec_security->ops->check_packet) {
801 return NT_STATUS_NOT_IMPLEMENTED;
803 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
804 return NT_STATUS_INVALID_PARAMETER;
807 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
810 _PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
811 TALLOC_CTX *mem_ctx,
812 uint8_t *data, size_t length,
813 const uint8_t *whole_pdu, size_t pdu_length,
814 DATA_BLOB *sig)
816 if (!gensec_security->ops->seal_packet) {
817 return NT_STATUS_NOT_IMPLEMENTED;
819 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
820 return NT_STATUS_INVALID_PARAMETER;
823 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
826 _PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
827 TALLOC_CTX *mem_ctx,
828 const uint8_t *data, size_t length,
829 const uint8_t *whole_pdu, size_t pdu_length,
830 DATA_BLOB *sig)
832 if (!gensec_security->ops->sign_packet) {
833 return NT_STATUS_NOT_IMPLEMENTED;
835 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
836 return NT_STATUS_INVALID_PARAMETER;
839 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
842 _PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
844 if (!gensec_security->ops->sig_size) {
845 return 0;
847 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
848 return 0;
851 return gensec_security->ops->sig_size(gensec_security, data_size);
854 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
856 if (!gensec_security->ops->max_wrapped_size) {
857 return (1 << 17);
860 return gensec_security->ops->max_wrapped_size(gensec_security);
863 size_t gensec_max_input_size(struct gensec_security *gensec_security)
865 if (!gensec_security->ops->max_input_size) {
866 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
869 return gensec_security->ops->max_input_size(gensec_security);
872 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
873 TALLOC_CTX *mem_ctx,
874 const DATA_BLOB *in,
875 DATA_BLOB *out)
877 if (!gensec_security->ops->wrap) {
878 return NT_STATUS_NOT_IMPLEMENTED;
880 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
883 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
884 TALLOC_CTX *mem_ctx,
885 const DATA_BLOB *in,
886 DATA_BLOB *out)
888 if (!gensec_security->ops->unwrap) {
889 return NT_STATUS_NOT_IMPLEMENTED;
891 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
894 _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
895 DATA_BLOB *session_key)
897 if (!gensec_security->ops->session_key) {
898 return NT_STATUS_NOT_IMPLEMENTED;
900 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
901 return NT_STATUS_NO_USER_SESSION_KEY;
904 return gensec_security->ops->session_key(gensec_security, session_key);
907 /**
908 * Return the credentials of a logged on user, including session keys
909 * etc.
911 * Only valid after a successful authentication
913 * May only be called once per authentication.
917 _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
918 struct auth_session_info **session_info)
920 if (!gensec_security->ops->session_info) {
921 return NT_STATUS_NOT_IMPLEMENTED;
923 return gensec_security->ops->session_info(gensec_security, session_info);
927 * Next state function for the GENSEC state machine
929 * @param gensec_security GENSEC State
930 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
931 * @param in The request, as a DATA_BLOB
932 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
933 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
934 * or NT_STATUS_OK if the user is authenticated.
937 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
938 const DATA_BLOB in, DATA_BLOB *out)
940 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
943 static void gensec_update_async_timed_handler(struct event_context *ev, struct timed_event *te,
944 struct timeval t, void *ptr)
946 struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
947 req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
948 req->callback.fn(req, req->callback.private_data);
952 * Next state function for the GENSEC state machine async version
954 * @param gensec_security GENSEC State
955 * @param in The request, as a DATA_BLOB
956 * @param callback The function that will be called when the operation is
957 * finished, it should return gensec_update_recv() to get output
958 * @param private_data A private pointer that will be passed to the callback function
961 _PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
962 void (*callback)(struct gensec_update_request *req, void *private_data),
963 void *private_data)
965 struct gensec_update_request *req = NULL;
966 struct timed_event *te = NULL;
968 req = talloc(gensec_security, struct gensec_update_request);
969 if (!req) goto failed;
970 req->gensec_security = gensec_security;
971 req->in = in;
972 req->out = data_blob(NULL, 0);
973 req->callback.fn = callback;
974 req->callback.private_data = private_data;
976 te = event_add_timed(gensec_security->event_ctx, req,
977 timeval_zero(),
978 gensec_update_async_timed_handler, req);
979 if (!te) goto failed;
981 return;
983 failed:
984 talloc_free(req);
985 callback(NULL, private_data);
989 * Next state function for the GENSEC state machine
991 * @param req GENSEC update request state
992 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
993 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
994 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
995 * or NT_STATUS_OK if the user is authenticated.
997 _PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
999 NTSTATUS status;
1001 NT_STATUS_HAVE_NO_MEMORY(req);
1003 *out = req->out;
1004 talloc_steal(out_mem_ctx, out->data);
1005 status = req->status;
1007 talloc_free(req);
1008 return status;
1011 /**
1012 * Set the requirement for a certain feature on the connection
1016 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1017 uint32_t feature)
1019 gensec_security->want_features |= feature;
1022 /**
1023 * Check the requirement for a certain feature on the connection
1027 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
1028 uint32_t feature)
1030 if (!gensec_security->ops->have_feature) {
1031 return false;
1034 /* We might 'have' features that we don't 'want', because the
1035 * other end demanded them, or we can't neotiate them off */
1036 return gensec_security->ops->have_feature(gensec_security, feature);
1039 /**
1040 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1044 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1046 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1047 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1048 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1049 return NT_STATUS_OK;
1052 /**
1053 * Return the credentials structure associated with a GENSEC context
1057 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
1059 if (!gensec_security) {
1060 return NULL;
1062 return gensec_security->credentials;
1065 /**
1066 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
1070 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
1072 gensec_security->target.service = talloc_strdup(gensec_security, service);
1073 if (!gensec_security->target.service) {
1074 return NT_STATUS_NO_MEMORY;
1076 return NT_STATUS_OK;
1079 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
1081 if (gensec_security->target.service) {
1082 return gensec_security->target.service;
1085 return "host";
1088 /**
1089 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
1093 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
1095 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1096 if (hostname && !gensec_security->target.hostname) {
1097 return NT_STATUS_NO_MEMORY;
1099 return NT_STATUS_OK;
1102 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
1104 /* We allow the target hostname to be overriden for testing purposes */
1105 const char *target_hostname = lp_parm_string(gensec_security->lp_ctx, NULL, "gensec", "target_hostname");
1106 if (target_hostname) {
1107 return target_hostname;
1110 if (gensec_security->target.hostname) {
1111 return gensec_security->target.hostname;
1114 /* We could add use the 'set sockaddr' call, and do a reverse
1115 * lookup, but this would be both insecure (compromising the
1116 * way kerberos works) and add DNS timeouts */
1117 return NULL;
1120 /**
1121 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
1123 * This is so that kerberos can include these addresses in
1124 * cryptographic tokens, to avoid certain attacks.
1127 _PUBLIC_ NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1129 gensec_security->my_addr = my_addr;
1130 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1131 return NT_STATUS_NO_MEMORY;
1133 return NT_STATUS_OK;
1136 _PUBLIC_ NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1138 gensec_security->peer_addr = peer_addr;
1139 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1140 return NT_STATUS_NO_MEMORY;
1142 return NT_STATUS_OK;
1145 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1147 if (gensec_security->my_addr) {
1148 return gensec_security->my_addr;
1151 /* We could add a 'set sockaddr' call, and do a lookup. This
1152 * would avoid needing to do system calls if nothing asks. */
1153 return NULL;
1156 _PUBLIC_ struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1158 if (gensec_security->peer_addr) {
1159 return gensec_security->peer_addr;
1162 /* We could add a 'set sockaddr' call, and do a lookup. This
1163 * would avoid needing to do system calls if nothing asks.
1164 * However, this is not appropriate for the peer addres on
1165 * datagram sockets */
1166 return NULL;
1171 /**
1172 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1173 * - ensures it is talloc()ed
1177 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1179 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1180 if (!gensec_security->target.principal) {
1181 return NT_STATUS_NO_MEMORY;
1183 return NT_STATUS_OK;
1186 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1188 if (gensec_security->target.principal) {
1189 return gensec_security->target.principal;
1192 return NULL;
1196 register a GENSEC backend.
1198 The 'name' can be later used by other backends to find the operations
1199 structure for this backend.
1201 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1203 if (!lp_parm_bool(global_loadparm, NULL, "gensec", ops->name, ops->enabled)) {
1204 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1205 return NT_STATUS_OK;
1208 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1209 /* its already registered! */
1210 DEBUG(0,("GENSEC backend '%s' already registered\n",
1211 ops->name));
1212 return NT_STATUS_OBJECT_NAME_COLLISION;
1215 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1216 generic_security_ops,
1217 struct gensec_security_ops *,
1218 gensec_num_backends+2);
1219 if (!generic_security_ops) {
1220 return NT_STATUS_NO_MEMORY;
1223 generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1224 gensec_num_backends++;
1225 generic_security_ops[gensec_num_backends] = NULL;
1227 DEBUG(3,("GENSEC backend '%s' registered\n",
1228 ops->name));
1230 return NT_STATUS_OK;
1234 return the GENSEC interface version, and the size of some critical types
1235 This can be used by backends to either detect compilation errors, or provide
1236 multiple implementations for different smbd compilation options in one module
1238 const struct gensec_critical_sizes *gensec_interface_version(void)
1240 static const struct gensec_critical_sizes critical_sizes = {
1241 GENSEC_INTERFACE_VERSION,
1242 sizeof(struct gensec_security_ops),
1243 sizeof(struct gensec_security),
1246 return &critical_sizes;
1249 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1250 return (*gs2)->priority - (*gs1)->priority;
1254 initialise the GENSEC subsystem
1256 _PUBLIC_ NTSTATUS gensec_init(struct loadparm_context *lp_ctx)
1258 static bool initialized = false;
1259 extern NTSTATUS gensec_sasl_init(void);
1260 extern NTSTATUS gensec_krb5_init(void);
1261 extern NTSTATUS gensec_schannel_init(void);
1262 extern NTSTATUS gensec_spnego_init(void);
1263 extern NTSTATUS gensec_gssapi_init(void);
1264 extern NTSTATUS gensec_ntlmssp_init(void);
1266 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1267 init_module_fn *shared_init;
1269 if (initialized) return NT_STATUS_OK;
1270 initialized = true;
1272 shared_init = load_samba_modules(NULL, lp_ctx, "gensec");
1274 run_init_functions(static_init);
1275 run_init_functions(shared_init);
1277 talloc_free(shared_init);
1279 qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1281 return NT_STATUS_OK;