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