r5902: A rather large change...
[kai/samba-autobuild/.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_unparsed_username(struct gensec_security *gensec_security, const char *user) 
515 {
516         char *p;
517         char *u = talloc_strdup(gensec_security, user);
518         if (!u) {
519                 return NT_STATUS_NO_MEMORY;
520         }
521
522         p = strchr_m(user, '@');
523         
524         if (p) {
525                 *p = '\0';
526                 gensec_security->user.name = talloc_strdup(gensec_security, u);
527                 if (!gensec_security->user.name) {
528                         return NT_STATUS_NO_MEMORY;
529                 }
530                 
531                 gensec_security->user.realm = talloc_strdup(gensec_security, p+1);
532                 if (!gensec_security->user.realm) {
533                         return NT_STATUS_NO_MEMORY;
534                 }
535                 return NT_STATUS_OK;
536         } 
537
538         p = strchr_m(user, '\\');
539         if (!p) {
540                 p = strchr_m(user, '/');
541         }
542         
543         if (p) {
544                 *p = '\0';
545                 gensec_security->user.domain = talloc_strdup(gensec_security, u);
546                 if (!gensec_security->user.domain) {
547                         return NT_STATUS_NO_MEMORY;
548                 }
549                 gensec_security->user.name = talloc_strdup(gensec_security, p+1);
550                 if (!gensec_security->user.name) {
551                         return NT_STATUS_NO_MEMORY;
552                 }
553                 
554                 return NT_STATUS_OK;
555         } 
556         
557         gensec_security->user.name = u;
558         if (!gensec_security->user.name) {
559                 return NT_STATUS_NO_MEMORY;
560         }
561         return NT_STATUS_OK;
562 }
563
564 /** 
565  * Set a username on a GENSEC context - ensures it is talloc()ed 
566  *
567  */
568
569 NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user) 
570 {
571         gensec_security->user.name = talloc_strdup(gensec_security, user);
572         if (!gensec_security->user.name) {
573                 return NT_STATUS_NO_MEMORY;
574         }
575         return NT_STATUS_OK;
576 }
577
578 /** 
579  * Set a username on a GENSEC context - ensures it is talloc()ed 
580  *
581  */
582
583 const char *gensec_get_username(struct gensec_security *gensec_security) 
584 {
585         if (gensec_security->user.name) {
586                 return gensec_security->user.name;
587         }
588         return gensec_security->default_user.name;
589 }
590
591 /** 
592  * Set a domain on a GENSEC context - ensures it is talloc()ed 
593  *
594  */
595
596 NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain) 
597 {
598         gensec_security->user.domain = talloc_strdup(gensec_security, domain);
599         if (!gensec_security->user.domain) {
600                 return NT_STATUS_NO_MEMORY;
601         }
602         return NT_STATUS_OK;
603 }
604
605 /** 
606  * Return the NT domain for this GENSEC context
607  *
608  */
609
610 const char *gensec_get_domain(struct gensec_security *gensec_security) 
611 {
612         if (gensec_security->user.domain) {
613                 return gensec_security->user.domain;
614         } else if (gensec_security->user.realm) {
615                 return gensec_security->user.realm;
616         }
617         return gensec_security->default_user.domain;
618 }
619
620 /** 
621  * Set the client workstation on a GENSEC context - ensures it is talloc()ed 
622  *
623  */
624
625 NTSTATUS gensec_set_workstation(struct gensec_security *gensec_security, const char *workstation) 
626 {
627         gensec_security->user.workstation = talloc_strdup(gensec_security, workstation);
628         if (!gensec_security->user.workstation) {
629                 return NT_STATUS_NO_MEMORY;
630         }
631         return NT_STATUS_OK;
632 }
633
634 /** 
635  * Return the client workstation on a GENSEC context - ensures it is talloc()ed 
636  *
637  */
638
639 const char *gensec_get_workstation(struct gensec_security *gensec_security) 
640 {
641         if (gensec_security->user.workstation) {
642                 return gensec_security->user.workstation;
643         } else {
644                 return lp_netbios_name();
645         }
646 }
647
648 /** 
649  * Set a kerberos realm on a GENSEC context - ensures it is talloc()ed 
650  *
651  */
652
653 NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *realm) 
654 {
655         gensec_security->user.realm = talloc_strdup(gensec_security, realm);
656         if (!gensec_security->user.realm) {
657                 return NT_STATUS_NO_MEMORY;
658         }
659         return NT_STATUS_OK;
660 }
661
662 /** 
663  * Return the Krb5 realm for this context
664  *
665  */
666
667 const char *gensec_get_realm(struct gensec_security *gensec_security) 
668 {
669         if (gensec_security->user.realm) {
670                 return gensec_security->user.realm;
671         } else if (gensec_security->user.domain) {
672                 return gensec_security->user.domain;
673         }
674         return gensec_security->default_user.realm;
675 }
676
677 /** 
678  * Return a kerberos principal for this context, if one has been set 
679  *
680  */
681
682 char *gensec_get_client_principal(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx) 
683 {
684         const char *realm = gensec_get_realm(gensec_security);
685         if (realm) {
686                 return talloc_asprintf(mem_ctx, "%s@%s", 
687                                        gensec_get_username(gensec_security), 
688                                        gensec_get_realm(gensec_security));
689         } else {
690                 return talloc_strdup(mem_ctx, gensec_get_username(gensec_security));
691         }
692 }
693
694 /** 
695  * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
696  * not do a callback
697  *
698  */
699
700 NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
701                              const char *password) 
702 {
703         gensec_security->user.password = talloc_strdup(gensec_security, password);
704         if (password && !gensec_security->user.password) {
705                 return NT_STATUS_NO_MEMORY;
706         }
707         return NT_STATUS_OK;
708 }
709
710 /** 
711  * Set the target principal name (if already known) on a GENSEC context - ensures it is talloc()ed 
712  *
713  */
714
715 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal) 
716 {
717         gensec_security->target.principal = talloc_strdup(gensec_security, principal);
718         if (!gensec_security->target.principal) {
719                 return NT_STATUS_NO_MEMORY;
720         }
721         return NT_STATUS_OK;
722 }
723
724 /** 
725  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed 
726  *
727  */
728
729 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service) 
730 {
731         gensec_security->target.service = talloc_strdup(gensec_security, service);
732         if (!gensec_security->target.service) {
733                 return NT_STATUS_NO_MEMORY;
734         }
735         return NT_STATUS_OK;
736 }
737
738 /** 
739  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed 
740  *
741  */
742
743 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) 
744 {
745         gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
746         if (!gensec_security->target.hostname) {
747                 return NT_STATUS_NO_MEMORY;
748         }
749         return NT_STATUS_OK;
750 }
751
752 const char *gensec_get_target_hostname(struct gensec_security *gensec_security) 
753 {
754         if (gensec_security->target.hostname) {
755                 return gensec_security->target.hostname;
756         }
757
758         /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
759         return NULL;
760 }
761
762 const char *gensec_get_target_service(struct gensec_security *gensec_security) 
763 {
764         if (gensec_security->target.service) {
765                 return gensec_security->target.service;
766         }
767
768         return "host";
769 }
770
771 const char *gensec_get_target_principal(struct gensec_security *gensec_security) 
772 {
773         const char *mechListMIC;
774         
775         if (gensec_security->target.principal) {
776                 return gensec_security->target.principal;
777         }
778
779         mechListMIC = talloc_asprintf(gensec_security,"%s$@%s",
780                                       lp_netbios_name(),
781                                       lp_realm());
782         return mechListMIC;
783 }
784
785 /** 
786  * Set a password callback, if the gensec module we use demands a password
787  */
788
789 void gensec_set_password_callback(struct gensec_security *gensec_security, 
790                                   gensec_password_callback callback, void *callback_private_data) 
791 {
792         gensec_security->password_callback = callback;
793         gensec_security->password_callback_private = callback_private_data;
794 }
795
796 /**
797  * Get (or call back for) a password.
798  */
799
800 NTSTATUS gensec_get_password(struct gensec_security *gensec_security,
801                              TALLOC_CTX *mem_ctx, 
802                              char **password) 
803 {
804         if (gensec_security->user.password) {
805                 *password = talloc_strdup(mem_ctx, gensec_security->user.password);
806                 if (!*password) {
807                         return NT_STATUS_NO_MEMORY;
808                 } else {
809                         return NT_STATUS_OK;
810                 }
811         }
812         if (!gensec_security->password_callback) {
813                 *password = NULL;
814                 return NT_STATUS_OK;
815         }
816         return gensec_security->password_callback(gensec_security, mem_ctx, password);
817 }
818
819 /*
820   register a GENSEC backend. 
821
822   The 'name' can be later used by other backends to find the operations
823   structure for this backend.
824 */
825 NTSTATUS gensec_register(const void *_ops)
826 {
827         const struct gensec_security_ops *ops = _ops;
828         
829         if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
830                 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
831                 return NT_STATUS_OK;
832         }
833
834         if (gensec_security_by_name(ops->name) != NULL) {
835                 /* its already registered! */
836                 DEBUG(0,("GENSEC backend '%s' already registered\n", 
837                          ops->name));
838                 return NT_STATUS_OBJECT_NAME_COLLISION;
839         }
840
841         generic_security_ops = realloc_p(generic_security_ops, 
842                                          const struct gensec_security_ops *, 
843                                          gensec_num_backends+1);
844         if (!generic_security_ops) {
845                 smb_panic("out of memory in gensec_register");
846         }
847
848         generic_security_ops[gensec_num_backends] = ops;
849
850         gensec_num_backends++;
851
852         DEBUG(3,("GENSEC backend '%s' registered\n", 
853                  ops->name));
854
855         return NT_STATUS_OK;
856 }
857
858 /*
859   return the GENSEC interface version, and the size of some critical types
860   This can be used by backends to either detect compilation errors, or provide
861   multiple implementations for different smbd compilation options in one module
862 */
863 const struct gensec_critical_sizes *gensec_interface_version(void)
864 {
865         static const struct gensec_critical_sizes critical_sizes = {
866                 GENSEC_INTERFACE_VERSION,
867                 sizeof(struct gensec_security_ops),
868                 sizeof(struct gensec_security),
869         };
870
871         return &critical_sizes;
872 }
873
874 /*
875   initialise the GENSEC subsystem
876 */
877 NTSTATUS gensec_init(void)
878 {
879         gensec_dcerpc_schannel_init();
880         return NT_STATUS_OK;
881 }