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