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