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