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