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