2 Unix SMB/CIFS implementation.
4 Generic Authentication Interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
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.
26 /* the list of currently registered GENSEC backends */
27 const static struct gensec_security_ops **generic_security_ops;
28 static int num_backends;
30 static const struct gensec_security_ops *gensec_security_by_authtype(uint8_t auth_type)
33 for (i=0; i < num_backends; i++) {
34 if (generic_security_ops[i]->auth_type == auth_type) {
35 return generic_security_ops[i];
42 static const struct gensec_security_ops *gensec_security_by_oid(const char *oid)
45 for (i=0; i < num_backends; i++) {
46 if (generic_security_ops[i]->oid &&
47 (strcmp(generic_security_ops[i]->oid, oid) == 0)) {
48 return generic_security_ops[i];
55 static const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_name)
58 for (i=0; i < num_backends; i++) {
59 if (generic_security_ops[i]->sasl_name
60 && (strcmp(generic_security_ops[i]->sasl_name, sasl_name) == 0)) {
61 return generic_security_ops[i];
68 static const struct gensec_security_ops *gensec_security_by_name(const char *name)
71 for (i=0; i < num_backends; i++) {
72 if (generic_security_ops[i]->name
73 && (strcmp(generic_security_ops[i]->name, name) == 0)) {
74 return generic_security_ops[i];
81 const struct gensec_security_ops **gensec_security_all(int *num_backends_out)
83 *num_backends_out = num_backends;
84 return generic_security_ops;
87 static NTSTATUS gensec_start(struct gensec_security **gensec_security)
90 /* awaiting a correct fix from metze */
92 return NT_STATUS_INTERNAL_ERROR;
95 mem_ctx = talloc_init("gensec_security struct");
97 return NT_STATUS_NO_MEMORY;
100 (*gensec_security) = talloc_p(mem_ctx, struct gensec_security);
101 if (!(*gensec_security)) {
102 talloc_destroy(mem_ctx);
103 return NT_STATUS_NO_MEMORY;
106 (*gensec_security)->mem_ctx = mem_ctx;
107 (*gensec_security)->ops = NULL;
109 (*gensec_security)->subcontext = False;
114 * Start a GENSEC subcontext, with a copy of the properties of the parent
116 * @note Used by SPENGO in particular, for the actual implementation mechanism
119 NTSTATUS gensec_subcontext_start(struct gensec_security *parent,
120 struct gensec_security **gensec_security)
122 (*gensec_security) = talloc_p(parent->mem_ctx, struct gensec_security);
123 if (!(*gensec_security)) {
124 return NT_STATUS_NO_MEMORY;
127 (**gensec_security) = *parent;
128 (*gensec_security)->ops = NULL;
129 (*gensec_security)->private_data = NULL;
131 (*gensec_security)->subcontext = True;
136 NTSTATUS gensec_client_start(struct gensec_security **gensec_security)
139 status = gensec_start(gensec_security);
140 if (!NT_STATUS_IS_OK(status)) {
143 (*gensec_security)->gensec_role = GENSEC_CLIENT;
144 (*gensec_security)->password_callback = NULL;
146 ZERO_STRUCT((*gensec_security)->user);
151 NTSTATUS gensec_server_start(struct gensec_security **gensec_security)
154 status = gensec_start(gensec_security);
155 if (!NT_STATUS_IS_OK(status)) {
158 (*gensec_security)->gensec_role = GENSEC_SERVER;
163 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
166 switch (gensec_security->gensec_role) {
168 if (gensec_security->ops->client_start) {
169 status = gensec_security->ops->client_start(gensec_security);
170 if (!NT_STATUS_IS_OK(status)) {
171 DEBUG(1, ("Faild to start GENSEC client mech %s: %s\n",
172 gensec_security->ops->name, nt_errstr(status)));
177 if (gensec_security->ops->server_start) {
178 status = gensec_security->ops->server_start(gensec_security);
179 if (!NT_STATUS_IS_OK(status)) {
180 DEBUG(1, ("Faild to start GENSEC server mech %s: %s\n",
181 gensec_security->ops->name, nt_errstr(status)));
186 return NT_STATUS_INVALID_PARAMETER;
190 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
193 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
196 gensec_security->ops = gensec_security_by_authtype(authtype);
197 if (!gensec_security->ops) {
198 DEBUG(3, ("Could not find GENSEC backend for authtype=%d\n", (int)authtype));
199 return NT_STATUS_INVALID_PARAMETER;
201 return gensec_start_mech(gensec_security);
205 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
207 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
208 * well-known #define to hook it in.
211 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
212 const char *mech_oid)
214 gensec_security->ops = gensec_security_by_oid(mech_oid);
215 if (!gensec_security->ops) {
216 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
217 return NT_STATUS_INVALID_PARAMETER;
219 return gensec_start_mech(gensec_security);
223 * Start a GENSEC sub-mechanism by a well know SASL name
227 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
228 const char *sasl_name)
230 gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
231 if (!gensec_security->ops) {
232 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
233 return NT_STATUS_INVALID_PARAMETER;
235 return gensec_start_mech(gensec_security);
239 wrappers for the gensec function pointers
241 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
243 uint8_t *data, size_t length, DATA_BLOB *sig)
245 if (!gensec_security->ops->unseal_packet) {
246 return NT_STATUS_NOT_IMPLEMENTED;
248 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, data, length, sig);
251 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
253 const uint8_t *data, size_t length,
254 const DATA_BLOB *sig)
256 if (!gensec_security->ops->check_packet) {
257 return NT_STATUS_NOT_IMPLEMENTED;
259 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, sig);
262 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
264 uint8_t *data, size_t length,
267 if (!gensec_security->ops->seal_packet) {
268 return NT_STATUS_NOT_IMPLEMENTED;
270 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, sig);
273 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
275 const uint8_t *data, size_t length,
278 if (!gensec_security->ops->sign_packet) {
279 return NT_STATUS_NOT_IMPLEMENTED;
281 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, sig);
284 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
285 DATA_BLOB *session_key)
287 if (!gensec_security->ops->session_key) {
288 return NT_STATUS_NOT_IMPLEMENTED;
290 return gensec_security->ops->session_key(gensec_security, session_key);
294 * Return the credentials of a logged on user, including session keys
297 * Only valid after a successful authentication
299 * May only be called once per authentication.
303 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
304 struct auth_session_info **session_info)
306 return gensec_security->ops->session_info(gensec_security, session_info);
310 * Next state function for the GENSEC state machine
312 * @param gensec_security GENSEC State
313 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
314 * @param in The request, as a DATA_BLOB
315 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
316 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
317 * or NT_STATUS_OK if the user is authenticated.
320 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
321 const DATA_BLOB in, DATA_BLOB *out)
323 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
326 void gensec_end(struct gensec_security **gensec_security)
328 if ((*gensec_security)->ops) {
329 (*gensec_security)->ops->end(*gensec_security);
331 (*gensec_security)->private_data = NULL;
333 if (!(*gensec_security)->subcontext) {
334 /* don't destory this if this is a subcontext - it belongs to the parent */
335 talloc_destroy((*gensec_security)->mem_ctx);
337 gensec_security = NULL;
341 * Set a username on a GENSEC context - ensures it is talloc()ed
345 NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user)
347 gensec_security->user.name = talloc_strdup(gensec_security->mem_ctx, user);
348 if (!gensec_security->user.name) {
349 return NT_STATUS_NO_MEMORY;
355 * Set a domain on a GENSEC context - ensures it is talloc()ed
359 NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain)
361 gensec_security->user.domain = talloc_strdup(gensec_security->mem_ctx, domain);
362 if (!gensec_security->user.domain) {
363 return NT_STATUS_NO_MEMORY;
369 * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
374 NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
375 const char *password)
377 gensec_security->user.password = talloc_strdup(gensec_security->mem_ctx, password);
378 if (!gensec_security->user.password) {
379 return NT_STATUS_NO_MEMORY;
385 * Set a kerberos realm on a GENSEC context - ensures it is talloc()ed
389 NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *realm)
391 gensec_security->user.realm = talloc_strdup(gensec_security->mem_ctx, realm);
392 if (!gensec_security->user.realm) {
393 return NT_STATUS_NO_MEMORY;
399 * Set the target principal name (if already known) on a GENSEC context - ensures it is talloc()ed
403 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
405 gensec_security->target.principal = talloc_strdup(gensec_security->mem_ctx, principal);
406 if (!gensec_security->target.principal) {
407 return NT_STATUS_NO_MEMORY;
413 * Set a password callback, if the gensec module we use demands a password
416 void gensec_set_password_callback(struct gensec_security *gensec_security,
417 gensec_password_callback callback, void *callback_private_data)
419 gensec_security->password_callback = callback;
420 gensec_security->password_callback_private = callback_private_data;
424 * Get (or call back for) a password.
427 NTSTATUS gensec_get_password(struct gensec_security *gensec_security,
431 if (gensec_security->user.password) {
432 *password = talloc_strdup(mem_ctx, gensec_security->user.password);
434 return NT_STATUS_NO_MEMORY;
439 if (!gensec_security->password_callback) {
440 return NT_STATUS_INVALID_PARAMETER;
442 return gensec_security->password_callback(gensec_security, mem_ctx, password);
446 register a GENSEC backend.
448 The 'name' can be later used by other backends to find the operations
449 structure for this backend.
451 static NTSTATUS gensec_register(const void *_ops)
453 const struct gensec_security_ops *ops = _ops;
455 if (gensec_security_by_name(ops->name) != NULL) {
456 /* its already registered! */
457 DEBUG(0,("GENSEC backend '%s' already registered\n",
459 return NT_STATUS_OBJECT_NAME_COLLISION;
462 generic_security_ops = Realloc(generic_security_ops, sizeof(generic_security_ops[0]) * (num_backends+1));
463 if (!generic_security_ops) {
464 smb_panic("out of memory in gensec_register");
467 generic_security_ops[num_backends] = ops;
471 DEBUG(3,("GENSEC backend '%s' registered\n",
478 return the GENSEC interface version, and the size of some critical types
479 This can be used by backends to either detect compilation errors, or provide
480 multiple implementations for different smbd compilation options in one module
482 const struct gensec_critical_sizes *gensec_interface_version(void)
484 static const struct gensec_critical_sizes critical_sizes = {
485 GENSEC_INTERFACE_VERSION,
486 sizeof(struct gensec_security_ops),
487 sizeof(struct gensec_security),
490 return &critical_sizes;
494 initialise the GENSEC subsystem
496 BOOL gensec_init(void)
498 static BOOL initialised;
501 /* this is *completly* the wrong way to do this */
506 status = register_subsystem("gensec", gensec_register);
507 if (!NT_STATUS_IS_OK(status)) {
511 /* FIXME: Perhaps panic if a basic backend, such as NTLMSSP, fails to initialise? */
512 gensec_ntlmssp_init();
516 gensec_spnego_init();
517 gensec_dcerpc_schannel_init();
520 DEBUG(3,("GENSEC subsystem version %d initialised\n", GENSEC_INTERFACE_VERSION));