2 Unix SMB/CIFS implementation.
4 Generic Authentication Interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "auth/auth.h"
26 #include "lib/events/events.h"
28 /* the list of currently registered GENSEC backends */
29 const static struct gensec_security_ops **generic_security_ops;
30 static int gensec_num_backends;
32 const struct gensec_security_ops **gensec_security_all(void)
34 return generic_security_ops;
37 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
41 const struct gensec_security_ops **backends;
42 if (!gensec_security) {
43 backends = gensec_security_all();
45 backends = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
47 for (i=0; backends && backends[i]; i++) {
48 if (backends[i]->auth_type == auth_type) {
56 static const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
57 const char *oid_string)
60 const struct gensec_security_ops **backends;
61 if (!gensec_security) {
62 backends = gensec_security_all();
64 backends = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
66 for (i=0; backends && backends[i]; i++) {
67 if (backends[i]->oid) {
68 for (j=0; backends[i]->oid[j]; j++) {
69 if (backends[i]->oid[j] &&
70 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
80 static const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
81 const char *sasl_name)
84 const struct gensec_security_ops **backends;
85 if (!gensec_security) {
86 backends = gensec_security_all();
88 backends = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
90 for (i=0; backends && backends[i]; i++) {
91 if (backends[i]->sasl_name
92 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
100 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
104 const struct gensec_security_ops **backends;
105 if (!gensec_security) {
106 backends = gensec_security_all();
108 backends = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
110 for (i=0; backends && backends[i]; i++) {
111 if (backends[i]->name
112 && (strcmp(backends[i]->name, name) == 0)) {
121 * Return a unique list of security subsystems from those specified in
122 * the list of SASL names.
124 * Use the list of enabled GENSEC mechanisms from the credentials
125 * attached to the gensec_security, and return in our preferred order.
128 const struct gensec_security_ops **gensec_security_by_sasl(struct gensec_security *gensec_security,
130 const char **sasl_names)
132 const struct gensec_security_ops **backends_out;
133 const struct gensec_security_ops **backends;
135 int num_backends_out = 0;
141 backends = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
143 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
147 backends_out[0] = NULL;
149 /* Find backends in our preferred order, by walking our list,
150 * then looking in the supplied list */
151 for (i=0; backends && backends[i]; i++) {
152 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
153 if (!backends[i]->sasl_name ||
154 !(strcmp(backends[i]->sasl_name,
155 sasl_names[sasl_idx]) == 0)) {
159 for (k=0; backends_out[k]; k++) {
160 if (backends_out[k] == backends[i]) {
165 if (k < num_backends_out) {
166 /* already in there */
170 backends_out = talloc_realloc(mem_ctx, backends_out,
171 const struct gensec_security_ops *,
172 num_backends_out + 2);
177 backends_out[num_backends_out] = backends[i];
179 backends_out[num_backends_out] = NULL;
186 * Return a unique list of security subsystems from those specified in
187 * the OID list. That is, where two OIDs refer to the same module,
188 * return that module only once.
190 * Use the list of enabled GENSEC mechanisms from the credentials
191 * attached to the gensec_security, and return in our preferred order.
194 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
196 const char **oid_strings,
199 struct gensec_security_ops_wrapper *backends_out;
200 const struct gensec_security_ops **backends;
201 int i, j, k, oid_idx;
202 int num_backends_out = 0;
208 backends = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
210 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
214 backends_out[0].op = NULL;
215 backends_out[0].oid = NULL;
217 /* Find backends in our preferred order, by walking our list,
218 * then looking in the supplied list */
219 for (i=0; backends && backends[i]; i++) {
220 if (!backends[i]->oid) {
223 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
224 if (strcmp(oid_strings[oid_idx], skip) == 0) {
228 for (j=0; backends[i]->oid[j]; j++) {
229 if (!backends[i]->oid[j] ||
230 !(strcmp(backends[i]->oid[j],
231 oid_strings[oid_idx]) == 0)) {
235 for (k=0; backends_out[k].op; k++) {
236 if (backends_out[k].op == backends[i]) {
241 if (k < num_backends_out) {
242 /* already in there */
246 backends_out = talloc_realloc(mem_ctx, backends_out,
247 struct gensec_security_ops_wrapper,
248 num_backends_out + 2);
253 backends_out[num_backends_out].op = backends[i];
254 backends_out[num_backends_out].oid = backends[i]->oid[j];
256 backends_out[num_backends_out].op = NULL;
257 backends_out[num_backends_out].oid = NULL;
265 * Return OIDS from the security subsystems listed
268 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
269 const struct gensec_security_ops **ops,
275 const char **oid_list;
279 oid_list = talloc_array(mem_ctx, const char *, 1);
284 for (i=0; ops && ops[i]; i++) {
289 for (k = 0; ops[i]->oid[k]; k++) {
290 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
292 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
296 oid_list[j] = ops[i]->oid[k];
307 * Return OIDS from the security subsystems listed
310 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
311 const struct gensec_security_ops_wrapper *wops)
316 const char **oid_list;
320 oid_list = talloc_array(mem_ctx, const char *, 1);
325 for (i=0; wops[i].op; i++) {
326 if (!wops[i].op->oid) {
330 for (k = 0; wops[i].op->oid[k]; k++) {
331 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
335 oid_list[j] = wops[i].op->oid[k];
345 * Return all the security subsystems currently enabled on a GENSEC context.
347 * This is taken from a list attached to the cli_credentails, and
348 * skips the OID in 'skip'. (Typically the SPNEGO OID)
352 const char **gensec_security_oids(struct gensec_security *gensec_security,
356 const struct gensec_security_ops **ops
357 = cli_credentials_gensec_list(gensec_get_credentials(gensec_security));
358 return gensec_security_oids_from_ops(mem_ctx, ops, skip);
364 Start the GENSEC system, returning a context pointer.
365 @param mem_ctx The parent TALLOC memory context.
366 @param gensec_security Returned GENSEC context pointer.
367 @note The mem_ctx is only a parent and may be NULL.
369 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
370 struct gensec_security **gensec_security,
371 struct event_context *ev)
373 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
374 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
376 (*gensec_security)->ops = NULL;
378 ZERO_STRUCT((*gensec_security)->target);
380 (*gensec_security)->subcontext = False;
381 (*gensec_security)->want_features = 0;
384 ev = event_context_init(*gensec_security);
386 talloc_free(*gensec_security);
387 return NT_STATUS_NO_MEMORY;
391 (*gensec_security)->event_ctx = ev;
397 * Start a GENSEC subcontext, with a copy of the properties of the parent
398 * @param mem_ctx The parent TALLOC memory context.
399 * @param parent The parent GENSEC context
400 * @param gensec_security Returned GENSEC context pointer.
401 * @note Used by SPNEGO in particular, for the actual implementation mechanism
404 NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
405 struct gensec_security *parent,
406 struct gensec_security **gensec_security)
408 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
409 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
411 (**gensec_security) = *parent;
412 (*gensec_security)->ops = NULL;
413 (*gensec_security)->private_data = NULL;
415 (*gensec_security)->subcontext = True;
416 (*gensec_security)->event_ctx = parent->event_ctx;
422 Start the GENSEC system, in client mode, returning a context pointer.
423 @param mem_ctx The parent TALLOC memory context.
424 @param gensec_security Returned GENSEC context pointer.
425 @note The mem_ctx is only a parent and may be NULL.
427 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
428 struct gensec_security **gensec_security,
429 struct event_context *ev)
432 status = gensec_start(mem_ctx, gensec_security, ev);
433 if (!NT_STATUS_IS_OK(status)) {
436 (*gensec_security)->gensec_role = GENSEC_CLIENT;
442 Start the GENSEC system, in server mode, returning a context pointer.
443 @param mem_ctx The parent TALLOC memory context.
444 @param gensec_security Returned GENSEC context pointer.
445 @note The mem_ctx is only a parent and may be NULL.
447 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
448 struct gensec_security **gensec_security,
449 struct event_context *ev)
452 status = gensec_start(mem_ctx, gensec_security, ev);
453 if (!NT_STATUS_IS_OK(status)) {
456 (*gensec_security)->gensec_role = GENSEC_SERVER;
461 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
464 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
465 gensec_security->subcontext ? "sub" : "",
466 gensec_security->ops->name));
467 switch (gensec_security->gensec_role) {
469 if (gensec_security->ops->client_start) {
470 status = gensec_security->ops->client_start(gensec_security);
471 if (!NT_STATUS_IS_OK(status)) {
472 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
473 gensec_security->ops->name, nt_errstr(status)));
478 if (gensec_security->ops->server_start) {
479 status = gensec_security->ops->server_start(gensec_security);
480 if (!NT_STATUS_IS_OK(status)) {
481 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
482 gensec_security->ops->name, nt_errstr(status)));
487 return NT_STATUS_INVALID_PARAMETER;
491 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
492 * @param gensec_security GENSEC context pointer.
493 * @param auth_type DCERPC auth type
494 * @param auth_level DCERPC auth level
497 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
498 uint8_t auth_type, uint8_t auth_level)
500 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
501 if (!gensec_security->ops) {
502 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
503 return NT_STATUS_INVALID_PARAMETER;
505 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
506 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
507 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
508 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
509 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
510 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
511 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
512 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
513 /* Default features */
515 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
517 return NT_STATUS_INVALID_PARAMETER;
520 return gensec_start_mech(gensec_security);
523 const char *gensec_get_name_by_authtype(uint8_t authtype)
525 const struct gensec_security_ops *ops;
526 ops = gensec_security_by_authtype(NULL, authtype);
534 const char *gensec_get_name_by_oid(const char *oid_string)
536 const struct gensec_security_ops *ops;
537 ops = gensec_security_by_oid(NULL, oid_string);
546 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
550 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
551 const struct gensec_security_ops *ops)
553 gensec_security->ops = ops;
554 return gensec_start_mech(gensec_security);
558 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
560 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
561 * well-known #define to hook it in.
564 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
565 const char *mech_oid)
567 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
568 if (!gensec_security->ops) {
569 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
570 return NT_STATUS_INVALID_PARAMETER;
572 return gensec_start_mech(gensec_security);
576 * Start a GENSEC sub-mechanism by a well know SASL name
580 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
581 const char *sasl_name)
583 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
584 if (!gensec_security->ops) {
585 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
586 return NT_STATUS_INVALID_PARAMETER;
588 return gensec_start_mech(gensec_security);
592 * Start a GENSEC sub-mechanism by an internal name
596 NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
599 gensec_security->ops = gensec_security_by_name(gensec_security, name);
600 if (!gensec_security->ops) {
601 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
602 return NT_STATUS_INVALID_PARAMETER;
604 return gensec_start_mech(gensec_security);
608 wrappers for the gensec function pointers
610 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
612 uint8_t *data, size_t length,
613 const uint8_t *whole_pdu, size_t pdu_length,
614 const DATA_BLOB *sig)
616 if (!gensec_security->ops->unseal_packet) {
617 return NT_STATUS_NOT_IMPLEMENTED;
619 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
620 return NT_STATUS_INVALID_PARAMETER;
623 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
625 whole_pdu, pdu_length,
629 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
631 const uint8_t *data, size_t length,
632 const uint8_t *whole_pdu, size_t pdu_length,
633 const DATA_BLOB *sig)
635 if (!gensec_security->ops->check_packet) {
636 return NT_STATUS_NOT_IMPLEMENTED;
638 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
639 return NT_STATUS_INVALID_PARAMETER;
642 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
645 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
647 uint8_t *data, size_t length,
648 const uint8_t *whole_pdu, size_t pdu_length,
651 if (!gensec_security->ops->seal_packet) {
652 return NT_STATUS_NOT_IMPLEMENTED;
654 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
655 return NT_STATUS_INVALID_PARAMETER;
658 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
661 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
663 const uint8_t *data, size_t length,
664 const uint8_t *whole_pdu, size_t pdu_length,
667 if (!gensec_security->ops->sign_packet) {
668 return NT_STATUS_NOT_IMPLEMENTED;
670 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
671 return NT_STATUS_INVALID_PARAMETER;
674 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
677 size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
679 if (!gensec_security->ops->sig_size) {
682 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
686 return gensec_security->ops->sig_size(gensec_security, data_size);
689 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
694 if (!gensec_security->ops->wrap) {
695 return NT_STATUS_NOT_IMPLEMENTED;
697 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
700 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
705 if (!gensec_security->ops->unwrap) {
706 return NT_STATUS_NOT_IMPLEMENTED;
708 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
711 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
712 DATA_BLOB *session_key)
714 if (!gensec_security->ops->session_key) {
715 return NT_STATUS_NOT_IMPLEMENTED;
717 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
718 return NT_STATUS_NO_USER_SESSION_KEY;
721 return gensec_security->ops->session_key(gensec_security, session_key);
725 * Return the credentials of a logged on user, including session keys
728 * Only valid after a successful authentication
730 * May only be called once per authentication.
734 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
735 struct auth_session_info **session_info)
737 if (!gensec_security->ops->session_info) {
738 return NT_STATUS_NOT_IMPLEMENTED;
740 return gensec_security->ops->session_info(gensec_security, session_info);
744 * Next state function for the GENSEC state machine
746 * @param gensec_security GENSEC State
747 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
748 * @param in The request, as a DATA_BLOB
749 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
750 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
751 * or NT_STATUS_OK if the user is authenticated.
754 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
755 const DATA_BLOB in, DATA_BLOB *out)
757 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
761 * Set the requirement for a certain feature on the connection
765 void gensec_want_feature(struct gensec_security *gensec_security,
768 gensec_security->want_features |= feature;
772 * Check the requirement for a certain feature on the connection
776 BOOL gensec_have_feature(struct gensec_security *gensec_security,
779 if (!gensec_security->ops->have_feature) {
783 /* Can only 'have' a feature if you already 'want'ed it */
784 if (gensec_security->want_features & feature) {
785 return gensec_security->ops->have_feature(gensec_security, feature);
791 * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context
795 NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
797 gensec_security->credentials = talloc_reference(gensec_security, credentials);
802 * Return the credentails structure associated with a GENSEC context
806 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
808 return gensec_security->credentials;
812 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
816 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
818 gensec_security->target.service = talloc_strdup(gensec_security, service);
819 if (!gensec_security->target.service) {
820 return NT_STATUS_NO_MEMORY;
825 const char *gensec_get_target_service(struct gensec_security *gensec_security)
827 if (gensec_security->target.service) {
828 return gensec_security->target.service;
835 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
839 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
841 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
842 if (!gensec_security->target.hostname) {
843 return NT_STATUS_NO_MEMORY;
848 const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
850 if (gensec_security->target.hostname) {
851 return gensec_security->target.hostname;
854 /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
859 * Set the target principal (assuming it it known, say from the SPNEGO reply)
860 * - ensures it is talloc()ed
864 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
866 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
867 if (!gensec_security->target.principal) {
868 return NT_STATUS_NO_MEMORY;
873 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
875 if (gensec_security->target.principal) {
876 return gensec_security->target.principal;
883 register a GENSEC backend.
885 The 'name' can be later used by other backends to find the operations
886 structure for this backend.
888 NTSTATUS gensec_register(const void *_ops)
890 const struct gensec_security_ops *ops = _ops;
892 if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
893 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
897 if (gensec_security_by_name(NULL, ops->name) != NULL) {
898 /* its already registered! */
899 DEBUG(0,("GENSEC backend '%s' already registered\n",
901 return NT_STATUS_OBJECT_NAME_COLLISION;
904 generic_security_ops = realloc_p(generic_security_ops,
905 const struct gensec_security_ops *,
906 gensec_num_backends+2);
907 if (!generic_security_ops) {
908 smb_panic("out of memory in gensec_register");
911 generic_security_ops[gensec_num_backends] = ops;
912 gensec_num_backends++;
913 generic_security_ops[gensec_num_backends] = NULL;
915 DEBUG(3,("GENSEC backend '%s' registered\n",
922 return the GENSEC interface version, and the size of some critical types
923 This can be used by backends to either detect compilation errors, or provide
924 multiple implementations for different smbd compilation options in one module
926 const struct gensec_critical_sizes *gensec_interface_version(void)
928 static const struct gensec_critical_sizes critical_sizes = {
929 GENSEC_INTERFACE_VERSION,
930 sizeof(struct gensec_security_ops),
931 sizeof(struct gensec_security),
934 return &critical_sizes;
938 initialise the GENSEC subsystem
940 NTSTATUS gensec_init(void)