r3453: - split out the auth and popt includes
[samba.git] / source4 / libcli / auth / gensec.c
1 /* 
2    Unix SMB/CIFS implementation.
3  
4    Generic Authentication Interface
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
8    
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.
13    
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.
18    
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.
22 */
23
24 #include "includes.h"
25 #include "auth/auth.h"
26
27 /* the list of currently registered GENSEC backends */
28 const static struct gensec_security_ops **generic_security_ops;
29 static int gensec_num_backends;
30
31 static const struct gensec_security_ops *gensec_security_by_authtype(uint8_t auth_type)
32 {
33         int i;
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];
37                 }
38         }
39
40         return NULL;
41 }
42
43 static const struct gensec_security_ops *gensec_security_by_oid(const char *oid_string)
44 {
45         int i;
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];
50                 }
51         }
52
53         return NULL;
54 }
55
56 static const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_name)
57 {
58         int i;
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];
63                 }
64         }
65
66         return NULL;
67 }
68
69 static const struct gensec_security_ops *gensec_security_by_name(const char *name)
70 {
71         int i;
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];
76                 }
77         }
78
79         return NULL;
80 }
81
82 const struct gensec_security_ops **gensec_security_all(int *num_backends_out)
83 {
84         *num_backends_out = gensec_num_backends;
85         return generic_security_ops;
86 }
87
88 const char **gensec_security_oids(TALLOC_CTX *mem_ctx, const char *skip) 
89 {
90         int i, j = 0;
91         const char **oid_list;
92         int num_backends;
93         const struct gensec_security_ops **ops = gensec_security_all(&num_backends);
94         if (!ops) {
95                 return NULL;
96         }
97         oid_list = talloc_array_p(mem_ctx, const char *, num_backends + 1);
98         if (!oid_list) {
99                 return NULL;
100         }
101         
102         for (i=0; i<num_backends; i++) {
103                 if (!ops[i]->oid) {
104                         continue;
105                 }
106                 
107                 if (skip && strcmp(skip, ops[i]->oid)==0) {
108                         continue;
109                 }
110
111                 oid_list[j] = ops[i]->oid;
112                 j++;
113         }
114         oid_list[j] = NULL;
115         return oid_list;
116 }
117
118 /*
119   note that memory context is the parent context to hang this gensec context off. It may be NULL.
120 */
121 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security) 
122 {
123         /* awaiting a correct fix from metze */
124         if (!gensec_init()) {
125                 return NT_STATUS_INTERNAL_ERROR;
126         }
127
128         (*gensec_security) = talloc_p(mem_ctx, struct gensec_security);
129         if (!(*gensec_security)) {
130                 return NT_STATUS_NO_MEMORY;
131         }
132
133         (*gensec_security)->ops = NULL;
134
135         ZERO_STRUCT((*gensec_security)->user);
136         ZERO_STRUCT((*gensec_security)->target);
137         ZERO_STRUCT((*gensec_security)->default_user);
138
139         (*gensec_security)->default_user.name = "";
140         (*gensec_security)->default_user.domain = talloc_strdup(*gensec_security, lp_workgroup());
141         (*gensec_security)->default_user.realm = talloc_strdup(*gensec_security, lp_realm());
142
143         (*gensec_security)->subcontext = False;
144         (*gensec_security)->want_features = 0;
145         return NT_STATUS_OK;
146 }
147
148 /** 
149  * Start a GENSEC subcontext, with a copy of the properties of the parent
150  *
151  * @note Used by SPENGO in particular, for the actual implementation mechanism
152  */
153
154 NTSTATUS gensec_subcontext_start(struct gensec_security *parent, 
155                                  struct gensec_security **gensec_security)
156 {
157         (*gensec_security) = talloc_p(parent, struct gensec_security);
158         if (!(*gensec_security)) {
159                 return NT_STATUS_NO_MEMORY;
160         }
161
162         (**gensec_security) = *parent;
163         (*gensec_security)->ops = NULL;
164         (*gensec_security)->private_data = NULL;
165
166         (*gensec_security)->subcontext = True;
167
168         return NT_STATUS_OK;
169 }
170
171 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
172 {
173         NTSTATUS status;
174         status = gensec_start(mem_ctx, gensec_security);
175         if (!NT_STATUS_IS_OK(status)) {
176                 return status;
177         }
178         (*gensec_security)->gensec_role = GENSEC_CLIENT;
179         (*gensec_security)->password_callback = NULL;
180
181         ZERO_STRUCT((*gensec_security)->user);
182
183         return status;
184 }
185
186 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
187 {
188         NTSTATUS status;
189         status = gensec_start(mem_ctx, gensec_security);
190         if (!NT_STATUS_IS_OK(status)) {
191                 return status;
192         }
193         (*gensec_security)->gensec_role = GENSEC_SERVER;
194
195         return status;
196 }
197
198 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security) 
199 {
200         NTSTATUS status;
201         DEBUG(5, ("Starting GENSEC %smechanism %s\n", 
202                   gensec_security->subcontext ? "sub" : "", 
203                   gensec_security->ops->name));
204         switch (gensec_security->gensec_role) {
205         case GENSEC_CLIENT:
206                 if (gensec_security->ops->client_start) {
207                         status = gensec_security->ops->client_start(gensec_security);
208                         if (!NT_STATUS_IS_OK(status)) {
209                                 DEBUG(1, ("Faild to start GENSEC client mech %s: %s\n",
210                                           gensec_security->ops->name, nt_errstr(status))); 
211                         }
212                         return status;
213                 }
214         case GENSEC_SERVER:
215                 if (gensec_security->ops->server_start) {
216                         status = gensec_security->ops->server_start(gensec_security);
217                         if (!NT_STATUS_IS_OK(status)) {
218                                 DEBUG(1, ("Faild to start GENSEC server mech %s: %s\n",
219                                           gensec_security->ops->name, nt_errstr(status))); 
220                         }
221                         return status;
222                 }
223         }
224         return NT_STATUS_INVALID_PARAMETER;
225 }
226
227 /** 
228  * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number 
229  */
230
231 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security, 
232                                        uint8_t auth_type, uint8_t auth_level) 
233 {
234         gensec_security->ops = gensec_security_by_authtype(auth_type);
235         if (!gensec_security->ops) {
236                 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
237                 return NT_STATUS_INVALID_PARAMETER;
238         }
239         if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
240                 gensec_want_feature(gensec_security, GENSEC_WANT_SIGN);
241         }
242         if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
243                 gensec_want_feature(gensec_security, GENSEC_WANT_SIGN);
244                 gensec_want_feature(gensec_security, GENSEC_WANT_SEAL);
245         }
246
247         return gensec_start_mech(gensec_security);
248 }
249
250 const char *gensec_get_name_by_authtype(uint8_t authtype) 
251 {
252         const struct gensec_security_ops *ops;
253         ops = gensec_security_by_authtype(authtype);
254         if (ops) {
255                 return ops->name;
256         }
257         return NULL;
258 }
259         
260
261 const char *gensec_get_name_by_oid(const char *oid_string) 
262 {
263         const struct gensec_security_ops *ops;
264         ops = gensec_security_by_oid(oid_string);
265         if (ops) {
266                 return ops->name;
267         }
268         return NULL;
269 }
270         
271
272 /** 
273  * Start a GENSEC sub-mechanism by OID, used in SPNEGO
274  *
275  * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
276  *       well-known #define to hook it in.
277  */
278
279 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security, 
280                                   const char *mech_oid) 
281 {
282         gensec_security->ops = gensec_security_by_oid(mech_oid);
283         if (!gensec_security->ops) {
284                 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
285                 return NT_STATUS_INVALID_PARAMETER;
286         }
287         return gensec_start_mech(gensec_security);
288 }
289
290 /** 
291  * Start a GENSEC sub-mechanism by a well know SASL name
292  *
293  */
294
295 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security, 
296                                         const char *sasl_name) 
297 {
298         gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
299         if (!gensec_security->ops) {
300                 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
301                 return NT_STATUS_INVALID_PARAMETER;
302         }
303         return gensec_start_mech(gensec_security);
304 }
305
306 /*
307   wrappers for the gensec function pointers
308 */
309 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security, 
310                               TALLOC_CTX *mem_ctx, 
311                               uint8_t *data, size_t length, 
312                               const uint8_t *whole_pdu, size_t pdu_length, 
313                               DATA_BLOB *sig)
314 {
315         if (!gensec_security->ops->unseal_packet) {
316                 return NT_STATUS_NOT_IMPLEMENTED;
317         }
318         if (!(gensec_security->want_features & GENSEC_WANT_SEAL)) {
319                 if (gensec_security->want_features & GENSEC_WANT_SIGN) {
320                         return gensec_check_packet(gensec_security, mem_ctx, 
321                                                    data, length, 
322                                                    whole_pdu, pdu_length, 
323                                                    sig);
324                 }
325                 return NT_STATUS_INVALID_PARAMETER;
326         }
327
328         return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, 
329                                                    data, length, 
330                                                    whole_pdu, pdu_length, 
331                                                    sig);
332 }
333
334 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security, 
335                              TALLOC_CTX *mem_ctx, 
336                              const uint8_t *data, size_t length, 
337                              const uint8_t *whole_pdu, size_t pdu_length, 
338                              const DATA_BLOB *sig)
339 {
340         if (!gensec_security->ops->check_packet) {
341                 return NT_STATUS_NOT_IMPLEMENTED;
342         }
343         if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
344                 return NT_STATUS_INVALID_PARAMETER;
345         }
346         
347         return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
348 }
349
350 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security, 
351                             TALLOC_CTX *mem_ctx, 
352                             uint8_t *data, size_t length, 
353                             const uint8_t *whole_pdu, size_t pdu_length, 
354                             DATA_BLOB *sig)
355 {
356         if (!gensec_security->ops->seal_packet) {
357                 return NT_STATUS_NOT_IMPLEMENTED;
358         }
359         if (!(gensec_security->want_features & GENSEC_WANT_SEAL)) {
360                 if (gensec_security->want_features & GENSEC_WANT_SIGN) {
361                         return gensec_sign_packet(gensec_security, mem_ctx, 
362                                                   data, length, 
363                                                   whole_pdu, pdu_length, 
364                                                   sig);
365                 }
366                 return NT_STATUS_INVALID_PARAMETER;
367         }
368
369         return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
370 }
371
372 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security, 
373                             TALLOC_CTX *mem_ctx, 
374                             const uint8_t *data, size_t length, 
375                             const uint8_t *whole_pdu, size_t pdu_length, 
376                             DATA_BLOB *sig)
377 {
378         if (!gensec_security->ops->sign_packet) {
379                 return NT_STATUS_NOT_IMPLEMENTED;
380         }
381         if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
382                 return NT_STATUS_INVALID_PARAMETER;
383         }
384         
385         return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
386 }
387
388 size_t gensec_sig_size(struct gensec_security *gensec_security) 
389 {
390         if (!gensec_security->ops->sig_size) {
391                 return 0;
392         }
393         if (!(gensec_security->want_features & GENSEC_WANT_SIGN)) {
394                 return 0;
395         }
396         
397         return gensec_security->ops->sig_size(gensec_security);
398 }
399
400 NTSTATUS gensec_session_key(struct gensec_security *gensec_security, 
401                             DATA_BLOB *session_key)
402 {
403         if (!gensec_security->ops->session_key) {
404                 return NT_STATUS_NOT_IMPLEMENTED;
405         }
406         if (!(gensec_security->want_features & GENSEC_WANT_SESSION_KEY)) {
407                 return NT_STATUS_INVALID_PARAMETER;
408         }
409         
410         return gensec_security->ops->session_key(gensec_security, session_key);
411 }
412
413 /** 
414  * Return the credentials of a logged on user, including session keys
415  * etc.
416  *
417  * Only valid after a successful authentication
418  *
419  * May only be called once per authentication.
420  *
421  */
422
423 NTSTATUS gensec_session_info(struct gensec_security *gensec_security, 
424                              struct auth_session_info **session_info)
425 {
426         if (!gensec_security->ops->session_info) {
427                 return NT_STATUS_NOT_IMPLEMENTED;
428         }
429         return gensec_security->ops->session_info(gensec_security, session_info);
430 }
431
432 /**
433  * Next state function for the GENSEC state machine
434  * 
435  * @param gensec_security GENSEC State
436  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
437  * @param in The request, as a DATA_BLOB
438  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
439  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
440  *                or NT_STATUS_OK if the user is authenticated. 
441  */
442
443 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 
444                        const DATA_BLOB in, DATA_BLOB *out) 
445 {
446         return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
447 }
448
449 void gensec_end(struct gensec_security **gensec_security)
450 {
451         if ((*gensec_security)->ops) {
452                 (*gensec_security)->ops->end(*gensec_security);
453         }
454         (*gensec_security)->private_data = NULL;
455
456         talloc_free(*gensec_security);
457         *gensec_security = NULL;
458 }
459
460 /** 
461  * Set the requirement for a certain feature on the connection
462  *
463  */
464
465 void gensec_want_feature(struct gensec_security *gensec_security,
466                          uint32 feature) 
467 {
468         gensec_security->want_features |= feature;
469 }
470
471 /** 
472  * Check the requirement for a certain feature on the connection
473  *
474  */
475
476 BOOL gensec_have_feature(struct gensec_security *gensec_security,
477                          uint32 feature) 
478 {
479         if (gensec_security->want_features & feature) {
480                 return True;
481         }
482
483         return False;
484 }
485
486 /** 
487  * Set a username on a GENSEC context - ensures it is talloc()ed 
488  *
489  */
490
491 NTSTATUS gensec_set_unparsed_username(struct gensec_security *gensec_security, const char *user) 
492 {
493         char *p;
494         char *u = talloc_strdup(gensec_security, user);
495         if (!u) {
496                 return NT_STATUS_NO_MEMORY;
497         }
498
499         p = strchr_m(user, '@');
500         
501         if (p) {
502                 *p = '\0';
503                 gensec_security->user.name = talloc_strdup(gensec_security, u);
504                 if (!gensec_security->user.name) {
505                         return NT_STATUS_NO_MEMORY;
506                 }
507                 
508                 gensec_security->user.realm = talloc_strdup(gensec_security, p+1);
509                 if (!gensec_security->user.realm) {
510                         return NT_STATUS_NO_MEMORY;
511                 }
512                 return NT_STATUS_OK;
513         } 
514
515         p = strchr_m(user, '\\');
516         if (!p) {
517                 p = strchr_m(user, '/');
518         }
519         
520         if (p) {
521                 *p = '\0';
522                 gensec_security->user.domain = talloc_strdup(gensec_security, u);
523                 if (!gensec_security->user.domain) {
524                         return NT_STATUS_NO_MEMORY;
525                 }
526                 gensec_security->user.name = talloc_strdup(gensec_security, p+1);
527                 if (!gensec_security->user.name) {
528                         return NT_STATUS_NO_MEMORY;
529                 }
530                 
531                 return NT_STATUS_OK;
532         } 
533         
534         gensec_security->user.name = u;
535         if (!gensec_security->user.name) {
536                 return NT_STATUS_NO_MEMORY;
537         }
538         return NT_STATUS_OK;
539 }
540
541 /** 
542  * Set a username on a GENSEC context - ensures it is talloc()ed 
543  *
544  */
545
546 NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user) 
547 {
548         gensec_security->user.name = talloc_strdup(gensec_security, user);
549         if (!gensec_security->user.name) {
550                 return NT_STATUS_NO_MEMORY;
551         }
552         return NT_STATUS_OK;
553 }
554
555 /** 
556  * Set a username on a GENSEC context - ensures it is talloc()ed 
557  *
558  */
559
560 const char *gensec_get_username(struct gensec_security *gensec_security) 
561 {
562         if (gensec_security->user.name) {
563                 return gensec_security->user.name;
564         }
565         return gensec_security->default_user.name;
566 }
567
568 /** 
569  * Set a domain on a GENSEC context - ensures it is talloc()ed 
570  *
571  */
572
573 NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain) 
574 {
575         gensec_security->user.domain = talloc_strdup(gensec_security, domain);
576         if (!gensec_security->user.domain) {
577                 return NT_STATUS_NO_MEMORY;
578         }
579         return NT_STATUS_OK;
580 }
581
582 /** 
583  * Return the NT domain for this GENSEC context
584  *
585  */
586
587 const char *gensec_get_domain(struct gensec_security *gensec_security) 
588 {
589         if (gensec_security->user.domain) {
590                 return gensec_security->user.domain;
591         } else if (gensec_security->user.realm) {
592                 return gensec_security->user.realm;
593         }
594         return gensec_security->default_user.domain;
595 }
596
597 /** 
598  * Set a kerberos realm on a GENSEC context - ensures it is talloc()ed 
599  *
600  */
601
602 NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *realm) 
603 {
604         gensec_security->user.realm = talloc_strdup(gensec_security, realm);
605         if (!gensec_security->user.realm) {
606                 return NT_STATUS_NO_MEMORY;
607         }
608         return NT_STATUS_OK;
609 }
610
611 /** 
612  * Return the Krb5 realm for this context
613  *
614  */
615
616 const char *gensec_get_realm(struct gensec_security *gensec_security) 
617 {
618         if (gensec_security->user.realm) {
619                 return gensec_security->user.realm;
620         } else if (gensec_security->user.domain) {
621                 return gensec_security->user.domain;
622         }
623         return gensec_security->default_user.realm;
624 }
625
626 /** 
627  * Return a kerberos principal for this context, if one has been set 
628  *
629  */
630
631 char *gensec_get_client_principal(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx) 
632 {
633         const char *realm = gensec_get_realm(gensec_security);
634         if (realm) {
635                 return talloc_asprintf(mem_ctx, "%s@%s", 
636                                        gensec_get_username(gensec_security), 
637                                        gensec_get_realm(gensec_security));
638         } else {
639                 return talloc_strdup(mem_ctx, gensec_get_username(gensec_security));
640         }
641 }
642
643 /** 
644  * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
645  * not do a callback
646  *
647  */
648
649 NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
650                              const char *password) 
651 {
652         gensec_security->user.password = talloc_strdup(gensec_security, password);
653         if (!gensec_security->user.password) {
654                 return NT_STATUS_NO_MEMORY;
655         }
656         return NT_STATUS_OK;
657 }
658
659 /** 
660  * Set the target principal name (if already known) on a GENSEC context - ensures it is talloc()ed 
661  *
662  */
663
664 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal) 
665 {
666         gensec_security->target.principal = talloc_strdup(gensec_security, principal);
667         if (!gensec_security->target.principal) {
668                 return NT_STATUS_NO_MEMORY;
669         }
670         return NT_STATUS_OK;
671 }
672
673 /** 
674  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed 
675  *
676  */
677
678 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service) 
679 {
680         gensec_security->target.service = talloc_strdup(gensec_security, service);
681         if (!gensec_security->target.service) {
682                 return NT_STATUS_NO_MEMORY;
683         }
684         return NT_STATUS_OK;
685 }
686
687 /** 
688  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed 
689  *
690  */
691
692 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) 
693 {
694         gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
695         if (!gensec_security->target.hostname) {
696                 return NT_STATUS_NO_MEMORY;
697         }
698         return NT_STATUS_OK;
699 }
700
701 const char *gensec_get_target_hostname(struct gensec_security *gensec_security) 
702 {
703         if (gensec_security->target.hostname) {
704                 return gensec_security->target.hostname;
705         }
706
707         /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
708         return NULL;
709 }
710
711 const char *gensec_get_target_service(struct gensec_security *gensec_security) 
712 {
713         if (gensec_security->target.service) {
714                 return gensec_security->target.service;
715         }
716
717         return "host";
718 }
719
720 /** 
721  * Set a password callback, if the gensec module we use demands a password
722  */
723
724 void gensec_set_password_callback(struct gensec_security *gensec_security, 
725                                   gensec_password_callback callback, void *callback_private_data) 
726 {
727         gensec_security->password_callback = callback;
728         gensec_security->password_callback_private = callback_private_data;
729 }
730
731 /**
732  * Get (or call back for) a password.
733  */
734
735 NTSTATUS gensec_get_password(struct gensec_security *gensec_security,
736                              TALLOC_CTX *mem_ctx, 
737                              char **password) 
738 {
739         if (gensec_security->user.password) {
740                 *password = talloc_strdup(mem_ctx, gensec_security->user.password);
741                 if (!*password) {
742                         return NT_STATUS_NO_MEMORY;
743                 } else {
744                         return NT_STATUS_OK;
745                 }
746         }
747         if (!gensec_security->password_callback) {
748                 return NT_STATUS_INVALID_PARAMETER;
749         }
750         return gensec_security->password_callback(gensec_security, mem_ctx, password);
751 }
752
753 /*
754   register a GENSEC backend. 
755
756   The 'name' can be later used by other backends to find the operations
757   structure for this backend.
758 */
759 static NTSTATUS gensec_register(const void *_ops)
760 {
761         const struct gensec_security_ops *ops = _ops;
762         
763         if (!lp_parm_bool(-1, "gensec", ops->name, True)) {
764                 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
765                 return NT_STATUS_OK;
766         }
767
768         if (gensec_security_by_name(ops->name) != NULL) {
769                 /* its already registered! */
770                 DEBUG(0,("GENSEC backend '%s' already registered\n", 
771                          ops->name));
772                 return NT_STATUS_OBJECT_NAME_COLLISION;
773         }
774
775         generic_security_ops = Realloc(generic_security_ops, sizeof(generic_security_ops[0]) * (gensec_num_backends+1));
776         if (!generic_security_ops) {
777                 smb_panic("out of memory in gensec_register");
778         }
779
780         generic_security_ops[gensec_num_backends] = ops;
781
782         gensec_num_backends++;
783
784         DEBUG(3,("GENSEC backend '%s' registered\n", 
785                  ops->name));
786
787         return NT_STATUS_OK;
788 }
789
790 /*
791   return the GENSEC interface version, and the size of some critical types
792   This can be used by backends to either detect compilation errors, or provide
793   multiple implementations for different smbd compilation options in one module
794 */
795 const struct gensec_critical_sizes *gensec_interface_version(void)
796 {
797         static const struct gensec_critical_sizes critical_sizes = {
798                 GENSEC_INTERFACE_VERSION,
799                 sizeof(struct gensec_security_ops),
800                 sizeof(struct gensec_security),
801         };
802
803         return &critical_sizes;
804 }
805
806 /*
807   initialise the GENSEC subsystem
808 */
809 BOOL gensec_init(void)
810 {
811         static BOOL initialised;
812         NTSTATUS status;
813
814         /* this is *completely* the wrong way to do this */
815         if (initialised) {
816                 return True;
817         }
818
819         status = register_subsystem("gensec", gensec_register); 
820         if (!NT_STATUS_IS_OK(status)) {
821                 return False;
822         }
823
824         static_init_gensec;
825         gensec_dcerpc_schannel_init();
826
827         initialised = True;
828         DEBUG(3,("GENSEC subsystem version %d initialised\n", GENSEC_INTERFACE_VERSION));
829         return True;
830 }