r9416: Cleanups inspired by jra's work to migrate Samba4's NTLMSSP code back
[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 NULL;
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   wrappers for the gensec function pointers
494 */
495 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security, 
496                               TALLOC_CTX *mem_ctx, 
497                               uint8_t *data, size_t length, 
498                               const uint8_t *whole_pdu, size_t pdu_length, 
499                               const DATA_BLOB *sig)
500 {
501         if (!gensec_security->ops->unseal_packet) {
502                 return NT_STATUS_NOT_IMPLEMENTED;
503         }
504         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
505                 return NT_STATUS_INVALID_PARAMETER;
506         }
507         
508         return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, 
509                                                    data, length, 
510                                                    whole_pdu, pdu_length, 
511                                                    sig);
512 }
513
514 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security, 
515                              TALLOC_CTX *mem_ctx, 
516                              const uint8_t *data, size_t length, 
517                              const uint8_t *whole_pdu, size_t pdu_length, 
518                              const DATA_BLOB *sig)
519 {
520         if (!gensec_security->ops->check_packet) {
521                 return NT_STATUS_NOT_IMPLEMENTED;
522         }
523         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
524                 return NT_STATUS_INVALID_PARAMETER;
525         }
526         
527         return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
528 }
529
530 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security, 
531                             TALLOC_CTX *mem_ctx, 
532                             uint8_t *data, size_t length, 
533                             const uint8_t *whole_pdu, size_t pdu_length, 
534                             DATA_BLOB *sig)
535 {
536         if (!gensec_security->ops->seal_packet) {
537                 return NT_STATUS_NOT_IMPLEMENTED;
538         }
539         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
540                 return NT_STATUS_INVALID_PARAMETER;
541         }
542         
543         return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
544 }
545
546 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security, 
547                             TALLOC_CTX *mem_ctx, 
548                             const 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->sign_packet) {
553                 return NT_STATUS_NOT_IMPLEMENTED;
554         }
555         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
556                 return NT_STATUS_INVALID_PARAMETER;
557         }
558         
559         return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
560 }
561
562 size_t gensec_sig_size(struct gensec_security *gensec_security) 
563 {
564         if (!gensec_security->ops->sig_size) {
565                 return 0;
566         }
567         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
568                 return 0;
569         }
570         
571         return gensec_security->ops->sig_size(gensec_security);
572 }
573
574 NTSTATUS gensec_wrap(struct gensec_security *gensec_security, 
575                      TALLOC_CTX *mem_ctx, 
576                      const DATA_BLOB *in, 
577                      DATA_BLOB *out) 
578 {
579         if (!gensec_security->ops->wrap) {
580                 return NT_STATUS_NOT_IMPLEMENTED;
581         }
582         return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
583 }
584
585 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security, 
586                        TALLOC_CTX *mem_ctx, 
587                        const DATA_BLOB *in, 
588                        DATA_BLOB *out) 
589 {
590         if (!gensec_security->ops->unwrap) {
591                 return NT_STATUS_NOT_IMPLEMENTED;
592         }
593         return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
594 }
595
596 NTSTATUS gensec_session_key(struct gensec_security *gensec_security, 
597                             DATA_BLOB *session_key)
598 {
599         if (!gensec_security->ops->session_key) {
600                 return NT_STATUS_NOT_IMPLEMENTED;
601         }
602         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
603                 return NT_STATUS_NO_USER_SESSION_KEY;
604         }
605         
606         return gensec_security->ops->session_key(gensec_security, session_key);
607 }
608
609 /** 
610  * Return the credentials of a logged on user, including session keys
611  * etc.
612  *
613  * Only valid after a successful authentication
614  *
615  * May only be called once per authentication.
616  *
617  */
618
619 NTSTATUS gensec_session_info(struct gensec_security *gensec_security, 
620                              struct auth_session_info **session_info)
621 {
622         if (!gensec_security->ops->session_info) {
623                 return NT_STATUS_NOT_IMPLEMENTED;
624         }
625         return gensec_security->ops->session_info(gensec_security, session_info);
626 }
627
628 /**
629  * Next state function for the GENSEC state machine
630  * 
631  * @param gensec_security GENSEC State
632  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
633  * @param in The request, as a DATA_BLOB
634  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
635  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
636  *                or NT_STATUS_OK if the user is authenticated. 
637  */
638
639 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 
640                        const DATA_BLOB in, DATA_BLOB *out) 
641 {
642         return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
643 }
644
645 /** 
646  * Set the requirement for a certain feature on the connection
647  *
648  */
649
650 void gensec_want_feature(struct gensec_security *gensec_security,
651                          uint32_t feature) 
652 {
653         gensec_security->want_features |= feature;
654 }
655
656 /** 
657  * Check the requirement for a certain feature on the connection
658  *
659  */
660
661 BOOL gensec_have_feature(struct gensec_security *gensec_security,
662                          uint32_t feature) 
663 {
664         if (!gensec_security->ops->have_feature) {
665                 return False;
666         }
667         
668         /* Can only 'have' a feature if you already 'want'ed it */
669         if (gensec_security->want_features & feature) {
670                 return gensec_security->ops->have_feature(gensec_security, feature);
671         }
672         return False;
673 }
674
675 /** 
676  * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context 
677  *
678  */
679
680 NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials) 
681 {
682         gensec_security->credentials = talloc_reference(gensec_security, credentials);
683         return NT_STATUS_OK;
684 }
685
686 /** 
687  * Return the credentails structure associated with a GENSEC context
688  *
689  */
690
691 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security) 
692 {
693         return gensec_security->credentials;
694 }
695
696 /** 
697  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed 
698  *
699  */
700
701 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service) 
702 {
703         gensec_security->target.service = talloc_strdup(gensec_security, service);
704         if (!gensec_security->target.service) {
705                 return NT_STATUS_NO_MEMORY;
706         }
707         return NT_STATUS_OK;
708 }
709
710 /** 
711  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed 
712  *
713  */
714
715 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) 
716 {
717         gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
718         if (!gensec_security->target.hostname) {
719                 return NT_STATUS_NO_MEMORY;
720         }
721         return NT_STATUS_OK;
722 }
723
724 const char *gensec_get_target_hostname(struct gensec_security *gensec_security) 
725 {
726         if (gensec_security->target.hostname) {
727                 return gensec_security->target.hostname;
728         }
729
730         /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
731         return NULL;
732 }
733
734 const char *gensec_get_target_service(struct gensec_security *gensec_security) 
735 {
736         if (gensec_security->target.service) {
737                 return gensec_security->target.service;
738         }
739
740         return "host";
741 }
742
743 /*
744   register a GENSEC backend. 
745
746   The 'name' can be later used by other backends to find the operations
747   structure for this backend.
748 */
749 NTSTATUS gensec_register(const void *_ops)
750 {
751         const struct gensec_security_ops *ops = _ops;
752         
753         if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
754                 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
755                 return NT_STATUS_OK;
756         }
757
758         if (gensec_security_by_name(ops->name) != NULL) {
759                 /* its already registered! */
760                 DEBUG(0,("GENSEC backend '%s' already registered\n", 
761                          ops->name));
762                 return NT_STATUS_OBJECT_NAME_COLLISION;
763         }
764
765         generic_security_ops = realloc_p(generic_security_ops, 
766                                          const struct gensec_security_ops *, 
767                                          gensec_num_backends+1);
768         if (!generic_security_ops) {
769                 smb_panic("out of memory in gensec_register");
770         }
771
772         generic_security_ops[gensec_num_backends] = ops;
773
774         gensec_num_backends++;
775
776         DEBUG(3,("GENSEC backend '%s' registered\n", 
777                  ops->name));
778
779         return NT_STATUS_OK;
780 }
781
782 /*
783   return the GENSEC interface version, and the size of some critical types
784   This can be used by backends to either detect compilation errors, or provide
785   multiple implementations for different smbd compilation options in one module
786 */
787 const struct gensec_critical_sizes *gensec_interface_version(void)
788 {
789         static const struct gensec_critical_sizes critical_sizes = {
790                 GENSEC_INTERFACE_VERSION,
791                 sizeof(struct gensec_security_ops),
792                 sizeof(struct gensec_security),
793         };
794
795         return &critical_sizes;
796 }
797
798 /*
799   initialise the GENSEC subsystem
800 */
801 NTSTATUS gensec_init(void)
802 {
803         return NT_STATUS_OK;
804 }