r4358: At metze's request, the Christmas elves have removed gensec_end in
[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         (*gensec_security) = talloc_p(mem_ctx, struct gensec_security);
124         if (!(*gensec_security)) {
125                 return NT_STATUS_NO_MEMORY;
126         }
127
128         (*gensec_security)->ops = NULL;
129
130         ZERO_STRUCT((*gensec_security)->user);
131         ZERO_STRUCT((*gensec_security)->target);
132         ZERO_STRUCT((*gensec_security)->default_user);
133
134         (*gensec_security)->default_user.name = "";
135         (*gensec_security)->default_user.domain = talloc_strdup(*gensec_security, lp_workgroup());
136         (*gensec_security)->default_user.realm = talloc_strdup(*gensec_security, lp_realm());
137
138         (*gensec_security)->subcontext = False;
139         (*gensec_security)->want_features = 0;
140         (*gensec_security)->have_features = 0;
141         return NT_STATUS_OK;
142 }
143
144 /** 
145  * Start a GENSEC subcontext, with a copy of the properties of the parent
146  *
147  * @note Used by SPENGO in particular, for the actual implementation mechanism
148  */
149
150 NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx, 
151                                  struct gensec_security *parent, 
152                                  struct gensec_security **gensec_security)
153 {
154         (*gensec_security) = talloc_p(mem_ctx, struct gensec_security);
155         if (!(*gensec_security)) {
156                 return NT_STATUS_NO_MEMORY;
157         }
158
159         (**gensec_security) = *parent;
160         (*gensec_security)->ops = NULL;
161         (*gensec_security)->private_data = NULL;
162
163         (*gensec_security)->subcontext = True;
164
165         return NT_STATUS_OK;
166 }
167
168 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
169 {
170         NTSTATUS status;
171         status = gensec_start(mem_ctx, gensec_security);
172         if (!NT_STATUS_IS_OK(status)) {
173                 return status;
174         }
175         (*gensec_security)->gensec_role = GENSEC_CLIENT;
176         (*gensec_security)->password_callback = NULL;
177
178         ZERO_STRUCT((*gensec_security)->user);
179
180         return status;
181 }
182
183 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
184 {
185         NTSTATUS status;
186         status = gensec_start(mem_ctx, gensec_security);
187         if (!NT_STATUS_IS_OK(status)) {
188                 return status;
189         }
190         (*gensec_security)->gensec_role = GENSEC_SERVER;
191
192         return status;
193 }
194
195 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security) 
196 {
197         NTSTATUS status;
198         DEBUG(5, ("Starting GENSEC %smechanism %s\n", 
199                   gensec_security->subcontext ? "sub" : "", 
200                   gensec_security->ops->name));
201         switch (gensec_security->gensec_role) {
202         case GENSEC_CLIENT:
203                 if (gensec_security->ops->client_start) {
204                         status = gensec_security->ops->client_start(gensec_security);
205                         if (!NT_STATUS_IS_OK(status)) {
206                                 DEBUG(1, ("Failed to start GENSEC client mech %s: %s\n",
207                                           gensec_security->ops->name, nt_errstr(status))); 
208                         }
209                         return status;
210                 }
211         case GENSEC_SERVER:
212                 if (gensec_security->ops->server_start) {
213                         status = gensec_security->ops->server_start(gensec_security);
214                         if (!NT_STATUS_IS_OK(status)) {
215                                 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
216                                           gensec_security->ops->name, nt_errstr(status))); 
217                         }
218                         return status;
219                 }
220         }
221         return NT_STATUS_INVALID_PARAMETER;
222 }
223
224 /** 
225  * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number 
226  */
227
228 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security, 
229                                        uint8_t auth_type, uint8_t auth_level) 
230 {
231         gensec_security->ops = gensec_security_by_authtype(auth_type);
232         if (!gensec_security->ops) {
233                 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
234                 return NT_STATUS_INVALID_PARAMETER;
235         }
236         gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
237         if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
238                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
239         }
240         if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
241                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
242                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
243         }
244
245         return gensec_start_mech(gensec_security);
246 }
247
248 const char *gensec_get_name_by_authtype(uint8_t authtype) 
249 {
250         const struct gensec_security_ops *ops;
251         ops = gensec_security_by_authtype(authtype);
252         if (ops) {
253                 return ops->name;
254         }
255         return NULL;
256 }
257         
258
259 const char *gensec_get_name_by_oid(const char *oid_string) 
260 {
261         const struct gensec_security_ops *ops;
262         ops = gensec_security_by_oid(oid_string);
263         if (ops) {
264                 return ops->name;
265         }
266         return NULL;
267 }
268         
269
270 /** 
271  * Start a GENSEC sub-mechanism by OID, used in SPNEGO
272  *
273  * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
274  *       well-known #define to hook it in.
275  */
276
277 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security, 
278                                   const char *mech_oid) 
279 {
280         gensec_security->ops = gensec_security_by_oid(mech_oid);
281         if (!gensec_security->ops) {
282                 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
283                 return NT_STATUS_INVALID_PARAMETER;
284         }
285         return gensec_start_mech(gensec_security);
286 }
287
288 /** 
289  * Start a GENSEC sub-mechanism by a well know SASL name
290  *
291  */
292
293 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security, 
294                                         const char *sasl_name) 
295 {
296         gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
297         if (!gensec_security->ops) {
298                 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
299                 return NT_STATUS_INVALID_PARAMETER;
300         }
301         return gensec_start_mech(gensec_security);
302 }
303
304 /*
305   wrappers for the gensec function pointers
306 */
307 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security, 
308                               TALLOC_CTX *mem_ctx, 
309                               uint8_t *data, size_t length, 
310                               const uint8_t *whole_pdu, size_t pdu_length, 
311                               DATA_BLOB *sig)
312 {
313         if (!gensec_security->ops->unseal_packet) {
314                 return NT_STATUS_NOT_IMPLEMENTED;
315         }
316         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
317                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
318                         return gensec_check_packet(gensec_security, mem_ctx, 
319                                                    data, length, 
320                                                    whole_pdu, pdu_length, 
321                                                    sig);
322                 }
323                 return NT_STATUS_INVALID_PARAMETER;
324         }
325
326         return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, 
327                                                    data, length, 
328                                                    whole_pdu, pdu_length, 
329                                                    sig);
330 }
331
332 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security, 
333                              TALLOC_CTX *mem_ctx, 
334                              const uint8_t *data, size_t length, 
335                              const uint8_t *whole_pdu, size_t pdu_length, 
336                              const DATA_BLOB *sig)
337 {
338         if (!gensec_security->ops->check_packet) {
339                 return NT_STATUS_NOT_IMPLEMENTED;
340         }
341         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
342                 return NT_STATUS_INVALID_PARAMETER;
343         }
344         
345         return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
346 }
347
348 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security, 
349                             TALLOC_CTX *mem_ctx, 
350                             uint8_t *data, size_t length, 
351                             const uint8_t *whole_pdu, size_t pdu_length, 
352                             DATA_BLOB *sig)
353 {
354         if (!gensec_security->ops->seal_packet) {
355                 return NT_STATUS_NOT_IMPLEMENTED;
356         }
357         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
358                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
359                         return gensec_sign_packet(gensec_security, mem_ctx, 
360                                                   data, length, 
361                                                   whole_pdu, pdu_length, 
362                                                   sig);
363                 }
364                 return NT_STATUS_INVALID_PARAMETER;
365         }
366
367         return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
368 }
369
370 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security, 
371                             TALLOC_CTX *mem_ctx, 
372                             const uint8_t *data, size_t length, 
373                             const uint8_t *whole_pdu, size_t pdu_length, 
374                             DATA_BLOB *sig)
375 {
376         if (!gensec_security->ops->sign_packet) {
377                 return NT_STATUS_NOT_IMPLEMENTED;
378         }
379         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
380                 return NT_STATUS_INVALID_PARAMETER;
381         }
382         
383         return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
384 }
385
386 size_t gensec_sig_size(struct gensec_security *gensec_security) 
387 {
388         if (!gensec_security->ops->sig_size) {
389                 return 0;
390         }
391         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
392                 return 0;
393         }
394         
395         return gensec_security->ops->sig_size(gensec_security);
396 }
397
398 NTSTATUS gensec_session_key(struct gensec_security *gensec_security, 
399                             DATA_BLOB *session_key)
400 {
401         if (!gensec_security->ops->session_key) {
402                 return NT_STATUS_NOT_IMPLEMENTED;
403         }
404         return gensec_security->ops->session_key(gensec_security, session_key);
405 }
406
407 /** 
408  * Return the credentials of a logged on user, including session keys
409  * etc.
410  *
411  * Only valid after a successful authentication
412  *
413  * May only be called once per authentication.
414  *
415  */
416
417 NTSTATUS gensec_session_info(struct gensec_security *gensec_security, 
418                              struct auth_session_info **session_info)
419 {
420         if (!gensec_security->ops->session_info) {
421                 return NT_STATUS_NOT_IMPLEMENTED;
422         }
423         return gensec_security->ops->session_info(gensec_security, session_info);
424 }
425
426 /**
427  * Next state function for the GENSEC state machine
428  * 
429  * @param gensec_security GENSEC State
430  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
431  * @param in The request, as a DATA_BLOB
432  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
433  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
434  *                or NT_STATUS_OK if the user is authenticated. 
435  */
436
437 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 
438                        const DATA_BLOB in, DATA_BLOB *out) 
439 {
440         return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
441 }
442
443 /** 
444  * Set the requirement for a certain feature on the connection
445  *
446  */
447
448 void gensec_want_feature(struct gensec_security *gensec_security,
449                          uint32 feature) 
450 {
451         gensec_security->want_features |= feature;
452 }
453
454 /** 
455  * Check the requirement for a certain feature on the connection
456  *
457  */
458
459 BOOL gensec_have_feature(struct gensec_security *gensec_security,
460                          uint32 feature) 
461 {
462         if (gensec_security->have_features & feature) {
463                 return True;
464         }
465
466         return False;
467 }
468
469 /** 
470  * Set a username on a GENSEC context - ensures it is talloc()ed 
471  *
472  */
473
474 NTSTATUS gensec_set_unparsed_username(struct gensec_security *gensec_security, const char *user) 
475 {
476         char *p;
477         char *u = talloc_strdup(gensec_security, user);
478         if (!u) {
479                 return NT_STATUS_NO_MEMORY;
480         }
481
482         p = strchr_m(user, '@');
483         
484         if (p) {
485                 *p = '\0';
486                 gensec_security->user.name = talloc_strdup(gensec_security, u);
487                 if (!gensec_security->user.name) {
488                         return NT_STATUS_NO_MEMORY;
489                 }
490                 
491                 gensec_security->user.realm = talloc_strdup(gensec_security, p+1);
492                 if (!gensec_security->user.realm) {
493                         return NT_STATUS_NO_MEMORY;
494                 }
495                 return NT_STATUS_OK;
496         } 
497
498         p = strchr_m(user, '\\');
499         if (!p) {
500                 p = strchr_m(user, '/');
501         }
502         
503         if (p) {
504                 *p = '\0';
505                 gensec_security->user.domain = talloc_strdup(gensec_security, u);
506                 if (!gensec_security->user.domain) {
507                         return NT_STATUS_NO_MEMORY;
508                 }
509                 gensec_security->user.name = talloc_strdup(gensec_security, p+1);
510                 if (!gensec_security->user.name) {
511                         return NT_STATUS_NO_MEMORY;
512                 }
513                 
514                 return NT_STATUS_OK;
515         } 
516         
517         gensec_security->user.name = u;
518         if (!gensec_security->user.name) {
519                 return NT_STATUS_NO_MEMORY;
520         }
521         return NT_STATUS_OK;
522 }
523
524 /** 
525  * Set a username on a GENSEC context - ensures it is talloc()ed 
526  *
527  */
528
529 NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user) 
530 {
531         gensec_security->user.name = talloc_strdup(gensec_security, user);
532         if (!gensec_security->user.name) {
533                 return NT_STATUS_NO_MEMORY;
534         }
535         return NT_STATUS_OK;
536 }
537
538 /** 
539  * Set a username on a GENSEC context - ensures it is talloc()ed 
540  *
541  */
542
543 const char *gensec_get_username(struct gensec_security *gensec_security) 
544 {
545         if (gensec_security->user.name) {
546                 return gensec_security->user.name;
547         }
548         return gensec_security->default_user.name;
549 }
550
551 /** 
552  * Set a domain on a GENSEC context - ensures it is talloc()ed 
553  *
554  */
555
556 NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain) 
557 {
558         gensec_security->user.domain = talloc_strdup(gensec_security, domain);
559         if (!gensec_security->user.domain) {
560                 return NT_STATUS_NO_MEMORY;
561         }
562         return NT_STATUS_OK;
563 }
564
565 /** 
566  * Return the NT domain for this GENSEC context
567  *
568  */
569
570 const char *gensec_get_domain(struct gensec_security *gensec_security) 
571 {
572         if (gensec_security->user.domain) {
573                 return gensec_security->user.domain;
574         } else if (gensec_security->user.realm) {
575                 return gensec_security->user.realm;
576         }
577         return gensec_security->default_user.domain;
578 }
579
580 /** 
581  * Set a kerberos realm on a GENSEC context - ensures it is talloc()ed 
582  *
583  */
584
585 NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *realm) 
586 {
587         gensec_security->user.realm = talloc_strdup(gensec_security, realm);
588         if (!gensec_security->user.realm) {
589                 return NT_STATUS_NO_MEMORY;
590         }
591         return NT_STATUS_OK;
592 }
593
594 /** 
595  * Return the Krb5 realm for this context
596  *
597  */
598
599 const char *gensec_get_realm(struct gensec_security *gensec_security) 
600 {
601         if (gensec_security->user.realm) {
602                 return gensec_security->user.realm;
603         } else if (gensec_security->user.domain) {
604                 return gensec_security->user.domain;
605         }
606         return gensec_security->default_user.realm;
607 }
608
609 /** 
610  * Return a kerberos principal for this context, if one has been set 
611  *
612  */
613
614 char *gensec_get_client_principal(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx) 
615 {
616         const char *realm = gensec_get_realm(gensec_security);
617         if (realm) {
618                 return talloc_asprintf(mem_ctx, "%s@%s", 
619                                        gensec_get_username(gensec_security), 
620                                        gensec_get_realm(gensec_security));
621         } else {
622                 return talloc_strdup(mem_ctx, gensec_get_username(gensec_security));
623         }
624 }
625
626 /** 
627  * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
628  * not do a callback
629  *
630  */
631
632 NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
633                              const char *password) 
634 {
635         gensec_security->user.password = talloc_strdup(gensec_security, password);
636         if (password && !gensec_security->user.password) {
637                 return NT_STATUS_NO_MEMORY;
638         }
639         return NT_STATUS_OK;
640 }
641
642 /** 
643  * Set the target principal name (if already known) on a GENSEC context - ensures it is talloc()ed 
644  *
645  */
646
647 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal) 
648 {
649         gensec_security->target.principal = talloc_strdup(gensec_security, principal);
650         if (!gensec_security->target.principal) {
651                 return NT_STATUS_NO_MEMORY;
652         }
653         return NT_STATUS_OK;
654 }
655
656 /** 
657  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed 
658  *
659  */
660
661 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service) 
662 {
663         gensec_security->target.service = talloc_strdup(gensec_security, service);
664         if (!gensec_security->target.service) {
665                 return NT_STATUS_NO_MEMORY;
666         }
667         return NT_STATUS_OK;
668 }
669
670 /** 
671  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed 
672  *
673  */
674
675 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) 
676 {
677         gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
678         if (!gensec_security->target.hostname) {
679                 return NT_STATUS_NO_MEMORY;
680         }
681         return NT_STATUS_OK;
682 }
683
684 const char *gensec_get_target_hostname(struct gensec_security *gensec_security) 
685 {
686         if (gensec_security->target.hostname) {
687                 return gensec_security->target.hostname;
688         }
689
690         /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
691         return NULL;
692 }
693
694 const char *gensec_get_target_service(struct gensec_security *gensec_security) 
695 {
696         if (gensec_security->target.service) {
697                 return gensec_security->target.service;
698         }
699
700         return "host";
701 }
702
703 const char *gensec_get_target_principal(struct gensec_security *gensec_security) 
704 {
705         const char *mechListMIC;
706         
707         if (gensec_security->target.principal) {
708                 return gensec_security->target.principal;
709         }
710
711         mechListMIC = talloc_asprintf(gensec_security,"%s$@%s",
712                                       lp_netbios_name(),
713                                       lp_realm());
714         return mechListMIC;
715 }
716
717 /** 
718  * Set a password callback, if the gensec module we use demands a password
719  */
720
721 void gensec_set_password_callback(struct gensec_security *gensec_security, 
722                                   gensec_password_callback callback, void *callback_private_data) 
723 {
724         gensec_security->password_callback = callback;
725         gensec_security->password_callback_private = callback_private_data;
726 }
727
728 /**
729  * Get (or call back for) a password.
730  */
731
732 NTSTATUS gensec_get_password(struct gensec_security *gensec_security,
733                              TALLOC_CTX *mem_ctx, 
734                              char **password) 
735 {
736         if (gensec_security->user.password) {
737                 *password = talloc_strdup(mem_ctx, gensec_security->user.password);
738                 if (!*password) {
739                         return NT_STATUS_NO_MEMORY;
740                 } else {
741                         return NT_STATUS_OK;
742                 }
743         }
744         if (!gensec_security->password_callback) {
745                 *password = NULL;
746                 return NT_STATUS_OK;
747         }
748         return gensec_security->password_callback(gensec_security, mem_ctx, password);
749 }
750
751 /*
752   register a GENSEC backend. 
753
754   The 'name' can be later used by other backends to find the operations
755   structure for this backend.
756 */
757 NTSTATUS gensec_register(const void *_ops)
758 {
759         const struct gensec_security_ops *ops = _ops;
760         
761         if (!lp_parm_bool(-1, "gensec", ops->name, True)) {
762                 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
763                 return NT_STATUS_OK;
764         }
765
766         if (gensec_security_by_name(ops->name) != NULL) {
767                 /* its already registered! */
768                 DEBUG(0,("GENSEC backend '%s' already registered\n", 
769                          ops->name));
770                 return NT_STATUS_OBJECT_NAME_COLLISION;
771         }
772
773         generic_security_ops = realloc_p(generic_security_ops, 
774                                          const struct gensec_security_ops *, 
775                                          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 NTSTATUS gensec_init(void)
810 {
811         gensec_dcerpc_schannel_init();
812         return NT_STATUS_OK;
813 }