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