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