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"
27 /* the list of currently registered GENSEC backends */
28 const static struct gensec_security_ops **generic_security_ops;
29 static int gensec_num_backends;
31 static const struct gensec_security_ops *gensec_security_by_authtype(uint8_t auth_type)
34 for (i=0; i < gensec_num_backends; i++) {
35 if (generic_security_ops[i]->auth_type == auth_type) {
36 return generic_security_ops[i];
43 static const struct gensec_security_ops *gensec_security_by_oid(const char *oid_string)
46 for (i=0; i < gensec_num_backends; i++) {
47 if (generic_security_ops[i]->oid &&
48 (strcmp(generic_security_ops[i]->oid, oid_string) == 0)) {
49 return generic_security_ops[i];
56 static const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_name)
59 for (i=0; i < gensec_num_backends; i++) {
60 if (generic_security_ops[i]->sasl_name
61 && (strcmp(generic_security_ops[i]->sasl_name, sasl_name) == 0)) {
62 return generic_security_ops[i];
69 static const struct gensec_security_ops *gensec_security_by_name(const char *name)
72 for (i=0; i < gensec_num_backends; i++) {
73 if (generic_security_ops[i]->name
74 && (strcmp(generic_security_ops[i]->name, name) == 0)) {
75 return generic_security_ops[i];
82 const struct gensec_security_ops **gensec_security_all(int *num_backends_out)
84 *num_backends_out = gensec_num_backends;
85 return generic_security_ops;
88 const char **gensec_security_oids(TALLOC_CTX *mem_ctx, const char *skip)
91 const char **oid_list;
93 const struct gensec_security_ops **ops = gensec_security_all(&num_backends);
97 oid_list = talloc_array(mem_ctx, const char *, num_backends + 1);
102 for (i=0; i<num_backends; i++) {
107 if (skip && strcmp(skip, ops[i]->oid)==0) {
111 oid_list[j] = ops[i]->oid;
119 Start the GENSEC system, returning a context pointer.
120 @param mem_ctx The parent TALLOC memory context.
121 @param gensec_security Returned GENSEC context pointer.
122 @note The mem_ctx is only a parent and may be NULL.
124 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
126 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
127 if (!(*gensec_security)) {
128 return NT_STATUS_NO_MEMORY;
131 (*gensec_security)->ops = NULL;
133 ZERO_STRUCT((*gensec_security)->target);
135 (*gensec_security)->subcontext = False;
136 (*gensec_security)->want_features = 0;
141 * Start a GENSEC subcontext, with a copy of the properties of the parent
142 * @param mem_ctx The parent TALLOC memory context.
143 * @param parent The parent GENSEC context
144 * @param gensec_security Returned GENSEC context pointer.
145 * @note Used by SPNEGO in particular, for the actual implementation mechanism
148 NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
149 struct gensec_security *parent,
150 struct gensec_security **gensec_security)
152 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
153 if (!(*gensec_security)) {
154 return NT_STATUS_NO_MEMORY;
157 (**gensec_security) = *parent;
158 (*gensec_security)->ops = NULL;
159 (*gensec_security)->private_data = NULL;
161 (*gensec_security)->subcontext = True;
167 Start the GENSEC system, in client mode, returning a context pointer.
168 @param mem_ctx The parent TALLOC memory context.
169 @param gensec_security Returned GENSEC context pointer.
170 @note The mem_ctx is only a parent and may be NULL.
172 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
175 status = gensec_start(mem_ctx, gensec_security);
176 if (!NT_STATUS_IS_OK(status)) {
179 (*gensec_security)->gensec_role = GENSEC_CLIENT;
180 (*gensec_security)->password_callback = NULL;
186 Start the GENSEC system, in server mode, returning a context pointer.
187 @param mem_ctx The parent TALLOC memory context.
188 @param gensec_security Returned GENSEC context pointer.
189 @note The mem_ctx is only a parent and may be NULL.
191 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
194 status = gensec_start(mem_ctx, gensec_security);
195 if (!NT_STATUS_IS_OK(status)) {
198 (*gensec_security)->gensec_role = GENSEC_SERVER;
203 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
206 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
207 gensec_security->subcontext ? "sub" : "",
208 gensec_security->ops->name));
209 switch (gensec_security->gensec_role) {
211 if (gensec_security->ops->client_start) {
212 status = gensec_security->ops->client_start(gensec_security);
213 if (!NT_STATUS_IS_OK(status)) {
214 DEBUG(1, ("Failed to start GENSEC client mech %s: %s\n",
215 gensec_security->ops->name, nt_errstr(status)));
220 if (gensec_security->ops->server_start) {
221 status = gensec_security->ops->server_start(gensec_security);
222 if (!NT_STATUS_IS_OK(status)) {
223 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
224 gensec_security->ops->name, nt_errstr(status)));
229 return NT_STATUS_INVALID_PARAMETER;
233 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
234 * @param gensec_security GENSEC context pointer.
235 * @param auth_type DCERPC auth type
236 * @param auth_level DCERPC auth level
239 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
240 uint8_t auth_type, uint8_t auth_level)
242 gensec_security->ops = gensec_security_by_authtype(auth_type);
243 if (!gensec_security->ops) {
244 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
245 return NT_STATUS_INVALID_PARAMETER;
247 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
248 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
249 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
251 if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
252 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
253 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
256 return gensec_start_mech(gensec_security);
259 const char *gensec_get_name_by_authtype(uint8_t authtype)
261 const struct gensec_security_ops *ops;
262 ops = gensec_security_by_authtype(authtype);
270 const char *gensec_get_name_by_oid(const char *oid_string)
272 const struct gensec_security_ops *ops;
273 ops = gensec_security_by_oid(oid_string);
282 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
284 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
285 * well-known #define to hook it in.
288 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
289 const char *mech_oid)
291 gensec_security->ops = gensec_security_by_oid(mech_oid);
292 if (!gensec_security->ops) {
293 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
294 return NT_STATUS_INVALID_PARAMETER;
296 return gensec_start_mech(gensec_security);
300 * Start a GENSEC sub-mechanism by a well know SASL name
304 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
305 const char *sasl_name)
307 gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
308 if (!gensec_security->ops) {
309 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
310 return NT_STATUS_INVALID_PARAMETER;
312 return gensec_start_mech(gensec_security);
316 wrappers for the gensec function pointers
318 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
320 uint8_t *data, size_t length,
321 const uint8_t *whole_pdu, size_t pdu_length,
324 if (!gensec_security->ops->unseal_packet) {
325 return NT_STATUS_NOT_IMPLEMENTED;
327 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
328 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
329 return gensec_check_packet(gensec_security, mem_ctx,
331 whole_pdu, pdu_length,
334 return NT_STATUS_INVALID_PARAMETER;
337 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
339 whole_pdu, pdu_length,
343 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
345 const uint8_t *data, size_t length,
346 const uint8_t *whole_pdu, size_t pdu_length,
347 const DATA_BLOB *sig)
349 if (!gensec_security->ops->check_packet) {
350 return NT_STATUS_NOT_IMPLEMENTED;
352 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
353 return NT_STATUS_INVALID_PARAMETER;
356 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
359 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
361 uint8_t *data, size_t length,
362 const uint8_t *whole_pdu, size_t pdu_length,
365 if (!gensec_security->ops->seal_packet) {
366 return NT_STATUS_NOT_IMPLEMENTED;
368 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
369 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
370 return gensec_sign_packet(gensec_security, mem_ctx,
372 whole_pdu, pdu_length,
375 return NT_STATUS_INVALID_PARAMETER;
378 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
381 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
383 const uint8_t *data, size_t length,
384 const uint8_t *whole_pdu, size_t pdu_length,
387 if (!gensec_security->ops->sign_packet) {
388 return NT_STATUS_NOT_IMPLEMENTED;
390 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
391 return NT_STATUS_INVALID_PARAMETER;
394 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
397 size_t gensec_sig_size(struct gensec_security *gensec_security)
399 if (!gensec_security->ops->sig_size) {
402 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
406 return gensec_security->ops->sig_size(gensec_security);
409 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
414 if (!gensec_security->ops->wrap) {
415 return NT_STATUS_NOT_IMPLEMENTED;
417 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
420 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
425 if (!gensec_security->ops->unwrap) {
426 return NT_STATUS_NOT_IMPLEMENTED;
428 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
431 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
432 DATA_BLOB *session_key)
434 if (!gensec_security->ops->session_key) {
435 return NT_STATUS_NOT_IMPLEMENTED;
437 return gensec_security->ops->session_key(gensec_security, session_key);
441 * Return the credentials of a logged on user, including session keys
444 * Only valid after a successful authentication
446 * May only be called once per authentication.
450 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
451 struct auth_session_info **session_info)
453 if (!gensec_security->ops->session_info) {
454 return NT_STATUS_NOT_IMPLEMENTED;
456 return gensec_security->ops->session_info(gensec_security, session_info);
460 * Next state function for the GENSEC state machine
462 * @param gensec_security GENSEC State
463 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
464 * @param in The request, as a DATA_BLOB
465 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
466 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
467 * or NT_STATUS_OK if the user is authenticated.
470 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
471 const DATA_BLOB in, DATA_BLOB *out)
473 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
477 * Set the requirement for a certain feature on the connection
481 void gensec_want_feature(struct gensec_security *gensec_security,
484 gensec_security->want_features |= feature;
488 * Check the requirement for a certain feature on the connection
492 BOOL gensec_have_feature(struct gensec_security *gensec_security,
495 if (!gensec_security->ops->have_feature) {
498 return gensec_security->ops->have_feature(gensec_security, feature);
502 * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context
506 NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
508 gensec_security->credentials = talloc_reference(gensec_security, credentials);
513 * Return the credentails structure associated with a GENSEC context
517 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
519 return gensec_security->credentials;
523 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
527 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
529 gensec_security->target.service = talloc_strdup(gensec_security, service);
530 if (!gensec_security->target.service) {
531 return NT_STATUS_NO_MEMORY;
537 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
541 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
543 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
544 if (!gensec_security->target.hostname) {
545 return NT_STATUS_NO_MEMORY;
550 const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
552 if (gensec_security->target.hostname) {
553 return gensec_security->target.hostname;
556 /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
560 const char *gensec_get_target_service(struct gensec_security *gensec_security)
562 if (gensec_security->target.service) {
563 return gensec_security->target.service;
570 register a GENSEC backend.
572 The 'name' can be later used by other backends to find the operations
573 structure for this backend.
575 NTSTATUS gensec_register(const void *_ops)
577 const struct gensec_security_ops *ops = _ops;
579 if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
580 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
584 if (gensec_security_by_name(ops->name) != NULL) {
585 /* its already registered! */
586 DEBUG(0,("GENSEC backend '%s' already registered\n",
588 return NT_STATUS_OBJECT_NAME_COLLISION;
591 generic_security_ops = realloc_p(generic_security_ops,
592 const struct gensec_security_ops *,
593 gensec_num_backends+1);
594 if (!generic_security_ops) {
595 smb_panic("out of memory in gensec_register");
598 generic_security_ops[gensec_num_backends] = ops;
600 gensec_num_backends++;
602 DEBUG(3,("GENSEC backend '%s' registered\n",
609 return the GENSEC interface version, and the size of some critical types
610 This can be used by backends to either detect compilation errors, or provide
611 multiple implementations for different smbd compilation options in one module
613 const struct gensec_critical_sizes *gensec_interface_version(void)
615 static const struct gensec_critical_sizes critical_sizes = {
616 GENSEC_INTERFACE_VERSION,
617 sizeof(struct gensec_security_ops),
618 sizeof(struct gensec_security),
621 return &critical_sizes;
625 initialise the GENSEC subsystem
627 NTSTATUS gensec_init(void)