7430eef957246c301e154b7177b122e553851867
[gd/samba-autobuild/.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-2006
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 3 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, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "system/network.h"
25 #include "lib/events/events.h"
26 #include "lib/socket/socket.h"
27 #include "lib/tsocket/tsocket.h"
28 #include "../lib/util/tevent_ntstatus.h"
29 #include "librpc/rpc/dcerpc.h"
30 #include "auth/credentials/credentials.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
33 #include "lib/util/tsort.h"
34
35 /* the list of currently registered GENSEC backends */
36 static struct gensec_security_ops **generic_security_ops;
37 static int gensec_num_backends;
38
39 /* Return all the registered mechs.  Don't modify the return pointer,
40  * but you may talloc_reference it if convient */
41 _PUBLIC_ struct gensec_security_ops **gensec_security_all(void)
42 {
43         return generic_security_ops;
44 }
45
46 bool gensec_security_ops_enabled(struct gensec_security_ops *ops, struct gensec_security *security)
47 {
48         return lp_parm_bool(security->settings->lp_ctx, NULL, "gensec", ops->name, ops->enabled);
49 }
50
51 /* Sometimes we want to force only kerberos, sometimes we want to
52  * force it's avoidance.  The old list could be either
53  * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
54  * an existing list we have trimmed down) */
55
56 _PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx, 
57                                                        struct gensec_security_ops **old_gensec_list, 
58                                                        struct cli_credentials *creds)
59 {
60         struct gensec_security_ops **new_gensec_list;
61         int i, j, num_mechs_in;
62         enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
63
64         if (creds) {
65                 use_kerberos = cli_credentials_get_kerberos_state(creds);
66         }
67
68         if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
69                 if (!talloc_reference(mem_ctx, old_gensec_list)) {
70                         return NULL;
71                 }
72                 return old_gensec_list;
73         }
74
75         for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
76                 /* noop */
77         }
78
79         new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
80         if (!new_gensec_list) {
81                 return NULL;
82         }
83
84         j = 0;
85         for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
86                 int oid_idx;
87
88                 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
89                         if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
90                                 new_gensec_list[j] = old_gensec_list[i];
91                                 j++;
92                                 break;
93                         }
94                 }
95                 switch (use_kerberos) {
96                 case CRED_DONT_USE_KERBEROS:
97                         if (old_gensec_list[i]->kerberos == false) {
98                                 new_gensec_list[j] = old_gensec_list[i];
99                                 j++;
100                         }
101                         break;
102                 case CRED_MUST_USE_KERBEROS:
103                         if (old_gensec_list[i]->kerberos == true) {
104                                 new_gensec_list[j] = old_gensec_list[i];
105                                 j++;
106                         }
107                         break;
108                 default:
109                         /* Can't happen or invalid parameter */
110                         return NULL;
111                 }
112         }
113         new_gensec_list[j] = NULL; 
114         
115         return new_gensec_list;
116 }
117
118 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
119                                                    TALLOC_CTX *mem_ctx) 
120 {
121         struct gensec_security_ops **backends;
122         backends = gensec_security_all();
123         if (!gensec_security) {
124                 if (!talloc_reference(mem_ctx, backends)) {
125                         return NULL;
126                 }
127                 return backends;
128         } else {
129                 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
130                 if (!creds) {
131                         if (!talloc_reference(mem_ctx, backends)) {
132                                 return NULL;
133                         }
134                         return backends;
135                 }
136                 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
137         }
138 }
139
140 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
141                                                                      uint8_t auth_type)
142 {
143         int i;
144         struct gensec_security_ops **backends;
145         const struct gensec_security_ops *backend;
146         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
147         if (!mem_ctx) {
148                 return NULL;
149         }
150         backends = gensec_security_mechs(gensec_security, mem_ctx);
151         for (i=0; backends && backends[i]; i++) {
152                 if (!gensec_security_ops_enabled(backends[i], gensec_security))
153                                 continue;
154                 if (backends[i]->auth_type == auth_type) {
155                         backend = backends[i];
156                         talloc_free(mem_ctx);
157                         return backend;
158                 }
159         }
160         talloc_free(mem_ctx);
161
162         return NULL;
163 }
164
165 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
166                                                          const char *oid_string)
167 {
168         int i, j;
169         struct gensec_security_ops **backends;
170         const struct gensec_security_ops *backend;
171         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
172         if (!mem_ctx) {
173                 return NULL;
174         }
175         backends = gensec_security_mechs(gensec_security, mem_ctx);
176         for (i=0; backends && backends[i]; i++) {
177                 if (gensec_security != NULL && 
178                                 !gensec_security_ops_enabled(backends[i], 
179                                                                                          gensec_security))
180                     continue;
181                 if (backends[i]->oid) {
182                         for (j=0; backends[i]->oid[j]; j++) { 
183                                 if (backends[i]->oid[j] &&
184                                     (strcmp(backends[i]->oid[j], oid_string) == 0)) {
185                                         backend = backends[i];
186                                         talloc_free(mem_ctx);
187                                         return backend;
188                                 }
189                         }
190                 }
191         }
192         talloc_free(mem_ctx);
193
194         return NULL;
195 }
196
197 const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
198                                                                const char *sasl_name)
199 {
200         int i;
201         struct gensec_security_ops **backends;
202         const struct gensec_security_ops *backend;
203         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
204         if (!mem_ctx) {
205                 return NULL;
206         }
207         backends = gensec_security_mechs(gensec_security, mem_ctx);
208         for (i=0; backends && backends[i]; i++) {
209                 if (!gensec_security_ops_enabled(backends[i], gensec_security))
210                     continue;
211                 if (backends[i]->sasl_name 
212                     && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
213                         backend = backends[i];
214                         talloc_free(mem_ctx);
215                         return backend;
216                 }
217         }
218         talloc_free(mem_ctx);
219
220         return NULL;
221 }
222
223 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
224                                                                  const char *name)
225 {
226         int i;
227         struct gensec_security_ops **backends;
228         const struct gensec_security_ops *backend;
229         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
230         if (!mem_ctx) {
231                 return NULL;
232         }
233         backends = gensec_security_mechs(gensec_security, mem_ctx);
234         for (i=0; backends && backends[i]; i++) {
235                 if (gensec_security != NULL && 
236                                 !gensec_security_ops_enabled(backends[i], gensec_security))
237                     continue;
238                 if (backends[i]->name 
239                     && (strcmp(backends[i]->name, name) == 0)) {
240                         backend = backends[i];
241                         talloc_free(mem_ctx);
242                         return backend;
243                 }
244         }
245         talloc_free(mem_ctx);
246         return NULL;
247 }
248
249 /**
250  * Return a unique list of security subsystems from those specified in
251  * the list of SASL names.   
252  *
253  * Use the list of enabled GENSEC mechanisms from the credentials
254  * attached to the gensec_security, and return in our preferred order.
255  */
256
257 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
258                                                                 TALLOC_CTX *mem_ctx, 
259                                                                 const char **sasl_names)
260 {
261         const struct gensec_security_ops **backends_out;
262         struct gensec_security_ops **backends;
263         int i, k, sasl_idx;
264         int num_backends_out = 0;
265
266         if (!sasl_names) {
267                 return NULL;
268         }
269
270         backends = gensec_security_mechs(gensec_security, mem_ctx);
271
272         backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
273         if (!backends_out) {
274                 return NULL;
275         }
276         backends_out[0] = NULL;
277
278         /* Find backends in our preferred order, by walking our list,
279          * then looking in the supplied list */
280         for (i=0; backends && backends[i]; i++) {
281                 if (gensec_security != NULL &&
282                                 !gensec_security_ops_enabled(backends[i], gensec_security))
283                     continue;
284                 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
285                         if (!backends[i]->sasl_name ||
286                             !(strcmp(backends[i]->sasl_name, 
287                                      sasl_names[sasl_idx]) == 0)) {
288                                 continue;
289                         }
290                         
291                         for (k=0; backends_out[k]; k++) {
292                                 if (backends_out[k] == backends[i]) {
293                                         break;
294                                 }
295                         }
296                         
297                         if (k < num_backends_out) {
298                                 /* already in there */
299                                 continue;
300                         }
301                         
302                         backends_out = talloc_realloc(mem_ctx, backends_out, 
303                                                       const struct gensec_security_ops *, 
304                                                       num_backends_out + 2);
305                         if (!backends_out) {
306                                 return NULL;
307                         }
308                         
309                         backends_out[num_backends_out] = backends[i];
310                         num_backends_out++;
311                         backends_out[num_backends_out] = NULL;
312                 }
313         }
314         return backends_out;
315 }
316
317 /**
318  * Return a unique list of security subsystems from those specified in
319  * the OID list.  That is, where two OIDs refer to the same module,
320  * return that module only once. 
321  *
322  * Use the list of enabled GENSEC mechanisms from the credentials
323  * attached to the gensec_security, and return in our preferred order.
324  */
325
326 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
327                                                                       TALLOC_CTX *mem_ctx, 
328                                                                       const char **oid_strings,
329                                                                       const char *skip)
330 {
331         struct gensec_security_ops_wrapper *backends_out;
332         struct gensec_security_ops **backends;
333         int i, j, k, oid_idx;
334         int num_backends_out = 0;
335
336         if (!oid_strings) {
337                 return NULL;
338         }
339
340         backends = gensec_security_mechs(gensec_security, gensec_security);
341
342         backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
343         if (!backends_out) {
344                 return NULL;
345         }
346         backends_out[0].op = NULL;
347         backends_out[0].oid = NULL;
348
349         /* Find backends in our preferred order, by walking our list,
350          * then looking in the supplied list */
351         for (i=0; backends && backends[i]; i++) {
352                 if (gensec_security != NULL && 
353                                 !gensec_security_ops_enabled(backends[i], gensec_security))
354                     continue;
355                 if (!backends[i]->oid) {
356                         continue;
357                 }
358                 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
359                         if (strcmp(oid_strings[oid_idx], skip) == 0) {
360                                 continue;
361                         }
362
363                         for (j=0; backends[i]->oid[j]; j++) { 
364                                 if (!backends[i]->oid[j] ||
365                                     !(strcmp(backends[i]->oid[j], 
366                                             oid_strings[oid_idx]) == 0)) {
367                                         continue;
368                                 }
369                                 
370                                 for (k=0; backends_out[k].op; k++) {
371                                         if (backends_out[k].op == backends[i]) {
372                                                 break;
373                                         }
374                                 }
375                                 
376                                 if (k < num_backends_out) {
377                                         /* already in there */
378                                         continue;
379                                 }
380
381                                 backends_out = talloc_realloc(mem_ctx, backends_out, 
382                                                               struct gensec_security_ops_wrapper, 
383                                                               num_backends_out + 2);
384                                 if (!backends_out) {
385                                         return NULL;
386                                 }
387                                 
388                                 backends_out[num_backends_out].op = backends[i];
389                                 backends_out[num_backends_out].oid = backends[i]->oid[j];
390                                 num_backends_out++;
391                                 backends_out[num_backends_out].op = NULL;
392                                 backends_out[num_backends_out].oid = NULL;
393                         }
394                 }
395         }
396         return backends_out;
397 }
398
399 /**
400  * Return OIDS from the security subsystems listed
401  */
402
403 const char **gensec_security_oids_from_ops(struct gensec_security *gensec_security,
404                                                                                    TALLOC_CTX *mem_ctx, 
405                                            struct gensec_security_ops **ops,                               
406                                            const char *skip) 
407 {
408         int i;
409         int j = 0;
410         int k;
411         const char **oid_list;
412         if (!ops) {
413                 return NULL;
414         }
415         oid_list = talloc_array(mem_ctx, const char *, 1);
416         if (!oid_list) {
417                 return NULL;
418         }
419         
420         for (i=0; ops && ops[i]; i++) {
421                 if (gensec_security != NULL && 
422                         !gensec_security_ops_enabled(ops[i], gensec_security)) {
423                         continue;
424                 }
425                 if (!ops[i]->oid) {
426                         continue;
427                 }
428                 
429                 for (k = 0; ops[i]->oid[k]; k++) {
430                         if (skip && strcmp(skip, ops[i]->oid[k])==0) {
431                         } else {
432                                 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
433                                 if (!oid_list) {
434                                         return NULL;
435                                 }
436                                 oid_list[j] = ops[i]->oid[k];
437                                 j++;
438                         }
439                 }
440         }
441         oid_list[j] = NULL;
442         return oid_list;
443 }
444
445
446 /**
447  * Return OIDS from the security subsystems listed
448  */
449
450 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx, 
451                                                    const struct gensec_security_ops_wrapper *wops)
452 {
453         int i;
454         int j = 0;
455         int k;
456         const char **oid_list;
457         if (!wops) {
458                 return NULL;
459         }
460         oid_list = talloc_array(mem_ctx, const char *, 1);
461         if (!oid_list) {
462                 return NULL;
463         }
464         
465         for (i=0; wops[i].op; i++) {
466                 if (!wops[i].op->oid) {
467                         continue;
468                 }
469                 
470                 for (k = 0; wops[i].op->oid[k]; k++) {
471                         oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
472                         if (!oid_list) {
473                                 return NULL;
474                         }
475                         oid_list[j] = wops[i].op->oid[k];
476                         j++;
477                 }
478         }
479         oid_list[j] = NULL;
480         return oid_list;
481 }
482
483
484 /**
485  * Return all the security subsystems currently enabled on a GENSEC context.
486  * 
487  * This is taken from a list attached to the cli_credentials, and
488  * skips the OID in 'skip'.  (Typically the SPNEGO OID)
489  * 
490  */
491
492 const char **gensec_security_oids(struct gensec_security *gensec_security, 
493                                   TALLOC_CTX *mem_ctx, 
494                                   const char *skip) 
495 {
496         struct gensec_security_ops **ops
497                 = gensec_security_mechs(gensec_security, mem_ctx);
498         return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
499 }
500
501
502
503 /**
504   Start the GENSEC system, returning a context pointer.
505   @param mem_ctx The parent TALLOC memory context.
506   @param gensec_security Returned GENSEC context pointer.
507   @note  The mem_ctx is only a parent and may be NULL.
508   @note, the auth context is moved to be a child of the
509   @ gensec_security return 
510 */
511 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, 
512                              struct tevent_context *ev,
513                              struct gensec_settings *settings,
514                              struct auth_context *auth_context,
515                              struct gensec_security **gensec_security)
516 {
517         if (ev == NULL) {
518                 DEBUG(0, ("No event context available!\n"));
519                 return NT_STATUS_INTERNAL_ERROR;
520         }
521
522         (*gensec_security) = talloc(mem_ctx, struct gensec_security);
523         NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
524
525         (*gensec_security)->ops = NULL;
526         (*gensec_security)->local_addr = NULL;
527         (*gensec_security)->remote_addr = NULL;
528         (*gensec_security)->private_data = NULL;
529
530         ZERO_STRUCT((*gensec_security)->target);
531
532         (*gensec_security)->subcontext = false;
533         (*gensec_security)->want_features = 0;
534
535         (*gensec_security)->event_ctx = ev;
536         SMB_ASSERT(settings->lp_ctx != NULL);
537         (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
538         (*gensec_security)->auth_context = talloc_steal(*gensec_security, auth_context);
539
540         return NT_STATUS_OK;
541 }
542
543 /** 
544  * Start a GENSEC subcontext, with a copy of the properties of the parent
545  * @param mem_ctx The parent TALLOC memory context.
546  * @param parent The parent GENSEC context 
547  * @param gensec_security Returned GENSEC context pointer.
548  * @note Used by SPNEGO in particular, for the actual implementation mechanism
549  */
550
551 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx, 
552                                  struct gensec_security *parent, 
553                                  struct gensec_security **gensec_security)
554 {
555         (*gensec_security) = talloc(mem_ctx, struct gensec_security);
556         NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
557
558         (**gensec_security) = *parent;
559         (*gensec_security)->ops = NULL;
560         (*gensec_security)->private_data = NULL;
561
562         (*gensec_security)->subcontext = true;
563         (*gensec_security)->want_features = parent->want_features;
564         (*gensec_security)->event_ctx = parent->event_ctx;
565         (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
566         (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
567         (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
568
569         return NT_STATUS_OK;
570 }
571
572 /**
573   Start the GENSEC system, in client mode, returning a context pointer.
574   @param mem_ctx The parent TALLOC memory context.
575   @param gensec_security Returned GENSEC context pointer.
576   @note  The mem_ctx is only a parent and may be NULL.
577 */
578 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, 
579                              struct gensec_security **gensec_security,
580                              struct tevent_context *ev,
581                              struct gensec_settings *settings)
582 {
583         NTSTATUS status;
584
585         if (settings == NULL) {
586                 DEBUG(0,("gensec_client_start: no settings given!\n"));
587                 return NT_STATUS_INTERNAL_ERROR;
588         }
589
590         status = gensec_start(mem_ctx, ev, settings, NULL, gensec_security);
591         if (!NT_STATUS_IS_OK(status)) {
592                 return status;
593         }
594         (*gensec_security)->gensec_role = GENSEC_CLIENT;
595
596         return status;
597 }
598
599 /**
600   Start the GENSEC system, in server mode, returning a context pointer.
601   @param mem_ctx The parent TALLOC memory context.
602   @param gensec_security Returned GENSEC context pointer.
603   @note  The mem_ctx is only a parent and may be NULL.
604 */
605 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, 
606                                       struct tevent_context *ev,
607                                       struct gensec_settings *settings,
608                                       struct auth_context *auth_context,
609                                       struct gensec_security **gensec_security)
610 {
611         NTSTATUS status;
612
613         if (!ev) {
614                 DEBUG(0,("gensec_server_start: no event context given!\n"));
615                 return NT_STATUS_INTERNAL_ERROR;
616         }
617
618         if (!settings) {
619                 DEBUG(0,("gensec_server_start: no settings given!\n"));
620                 return NT_STATUS_INTERNAL_ERROR;
621         }
622
623         status = gensec_start(mem_ctx, ev, settings, auth_context, gensec_security);
624         if (!NT_STATUS_IS_OK(status)) {
625                 return status;
626         }
627         (*gensec_security)->gensec_role = GENSEC_SERVER;
628
629         return status;
630 }
631
632 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security) 
633 {
634         NTSTATUS status;
635         DEBUG(5, ("Starting GENSEC %smechanism %s\n", 
636                   gensec_security->subcontext ? "sub" : "", 
637                   gensec_security->ops->name));
638         switch (gensec_security->gensec_role) {
639         case GENSEC_CLIENT:
640                 if (gensec_security->ops->client_start) {
641                         status = gensec_security->ops->client_start(gensec_security);
642                         if (!NT_STATUS_IS_OK(status)) {
643                                 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
644                                           gensec_security->ops->name, nt_errstr(status))); 
645                         }
646                         return status;
647                 }
648                 break;
649         case GENSEC_SERVER:
650                 if (gensec_security->ops->server_start) {
651                         status = gensec_security->ops->server_start(gensec_security);
652                         if (!NT_STATUS_IS_OK(status)) {
653                                 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
654                                           gensec_security->ops->name, nt_errstr(status))); 
655                         }
656                         return status;
657                 }
658                 break;
659         }
660         return NT_STATUS_INVALID_PARAMETER;
661 }
662
663 /** 
664  * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number 
665  * @param gensec_security GENSEC context pointer.
666  * @param auth_type DCERPC auth type
667  * @param auth_level DCERPC auth level 
668  */
669
670 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security, 
671                                        uint8_t auth_type, uint8_t auth_level) 
672 {
673         gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
674         if (!gensec_security->ops) {
675                 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
676                 return NT_STATUS_INVALID_PARAMETER;
677         }
678         gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
679         gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
680         if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
681                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
682         } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
683                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
684                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
685         } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
686                 /* Default features */
687         } else {
688                 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n", 
689                          auth_level));
690                 return NT_STATUS_INVALID_PARAMETER;
691         }
692
693         return gensec_start_mech(gensec_security);
694 }
695
696 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype) 
697 {
698         const struct gensec_security_ops *ops;
699         ops = gensec_security_by_authtype(gensec_security, authtype);
700         if (ops) {
701                 return ops->name;
702         }
703         return NULL;
704 }
705         
706
707 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
708                                                                                         const char *oid_string) 
709 {
710         const struct gensec_security_ops *ops;
711         ops = gensec_security_by_oid(gensec_security, oid_string);
712         if (ops) {
713                 return ops->name;
714         }
715         return oid_string;
716 }
717         
718
719 /** 
720  * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
721  *
722  */
723
724 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security, 
725                                   const struct gensec_security_ops *ops) 
726 {
727         gensec_security->ops = ops;
728         return gensec_start_mech(gensec_security);
729 }
730
731 /** 
732  * Start a GENSEC sub-mechanism by OID, used in SPNEGO
733  *
734  * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
735  *       well-known #define to hook it in.
736  */
737
738 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security, 
739                                   const char *mech_oid) 
740 {
741         SMB_ASSERT(gensec_security != NULL);
742
743         gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
744         if (!gensec_security->ops) {
745                 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
746                 return NT_STATUS_INVALID_PARAMETER;
747         }
748         return gensec_start_mech(gensec_security);
749 }
750
751 /** 
752  * Start a GENSEC sub-mechanism by a well know SASL name
753  *
754  */
755
756 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security, 
757                                         const char *sasl_name) 
758 {
759         gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
760         if (!gensec_security->ops) {
761                 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
762                 return NT_STATUS_INVALID_PARAMETER;
763         }
764         return gensec_start_mech(gensec_security);
765 }
766
767 /** 
768  * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
769  *
770  */
771
772 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security, 
773                                                  const char **sasl_names) 
774 {
775         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
776         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
777         const struct gensec_security_ops **ops;
778         int i;
779         if (!mem_ctx) {
780                 return NT_STATUS_NO_MEMORY;
781         }
782         ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
783         if (!ops || !*ops) {
784                 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n", 
785                           str_list_join(mem_ctx, 
786                                         sasl_names, ' ')));
787                 talloc_free(mem_ctx);
788                 return NT_STATUS_INVALID_PARAMETER;
789         }
790         for (i=0; ops[i]; i++) {
791                 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
792                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
793                         break;
794                 }
795         }
796         talloc_free(mem_ctx);
797         return nt_status;
798 }
799
800 /** 
801  * Start a GENSEC sub-mechanism by an internal name
802  *
803  */
804
805 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security, 
806                                         const char *name) 
807 {
808         gensec_security->ops = gensec_security_by_name(gensec_security, name);
809         if (!gensec_security->ops) {
810                 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
811                 return NT_STATUS_INVALID_PARAMETER;
812         }
813         return gensec_start_mech(gensec_security);
814 }
815
816 /*
817   wrappers for the gensec function pointers
818 */
819 _PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security, 
820                               TALLOC_CTX *mem_ctx, 
821                               uint8_t *data, size_t length, 
822                               const uint8_t *whole_pdu, size_t pdu_length, 
823                               const DATA_BLOB *sig)
824 {
825         if (!gensec_security->ops->unseal_packet) {
826                 return NT_STATUS_NOT_IMPLEMENTED;
827         }
828         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
829                 return NT_STATUS_INVALID_PARAMETER;
830         }
831         
832         return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, 
833                                                    data, length, 
834                                                    whole_pdu, pdu_length, 
835                                                    sig);
836 }
837
838 _PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security, 
839                              TALLOC_CTX *mem_ctx, 
840                              const uint8_t *data, size_t length, 
841                              const uint8_t *whole_pdu, size_t pdu_length, 
842                              const DATA_BLOB *sig)
843 {
844         if (!gensec_security->ops->check_packet) {
845                 return NT_STATUS_NOT_IMPLEMENTED;
846         }
847         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
848                 return NT_STATUS_INVALID_PARAMETER;
849         }
850         
851         return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
852 }
853
854 _PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security, 
855                             TALLOC_CTX *mem_ctx, 
856                             uint8_t *data, size_t length, 
857                             const uint8_t *whole_pdu, size_t pdu_length, 
858                             DATA_BLOB *sig)
859 {
860         if (!gensec_security->ops->seal_packet) {
861                 return NT_STATUS_NOT_IMPLEMENTED;
862         }
863         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
864                 return NT_STATUS_INVALID_PARAMETER;
865         }
866         
867         return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
868 }
869
870 _PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security, 
871                             TALLOC_CTX *mem_ctx, 
872                             const uint8_t *data, size_t length, 
873                             const uint8_t *whole_pdu, size_t pdu_length, 
874                             DATA_BLOB *sig)
875 {
876         if (!gensec_security->ops->sign_packet) {
877                 return NT_STATUS_NOT_IMPLEMENTED;
878         }
879         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
880                 return NT_STATUS_INVALID_PARAMETER;
881         }
882         
883         return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
884 }
885
886 _PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size) 
887 {
888         if (!gensec_security->ops->sig_size) {
889                 return 0;
890         }
891         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
892                 return 0;
893         }
894         
895         return gensec_security->ops->sig_size(gensec_security, data_size);
896 }
897
898 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security) 
899 {
900         if (!gensec_security->ops->max_wrapped_size) {
901                 return (1 << 17);
902         }
903         
904         return gensec_security->ops->max_wrapped_size(gensec_security);
905 }
906
907 size_t gensec_max_input_size(struct gensec_security *gensec_security) 
908 {
909         if (!gensec_security->ops->max_input_size) {
910                 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
911         }
912         
913         return gensec_security->ops->max_input_size(gensec_security);
914 }
915
916 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security, 
917                      TALLOC_CTX *mem_ctx, 
918                      const DATA_BLOB *in, 
919                      DATA_BLOB *out) 
920 {
921         if (!gensec_security->ops->wrap) {
922                 return NT_STATUS_NOT_IMPLEMENTED;
923         }
924         return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
925 }
926
927 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security, 
928                        TALLOC_CTX *mem_ctx, 
929                        const DATA_BLOB *in, 
930                        DATA_BLOB *out) 
931 {
932         if (!gensec_security->ops->unwrap) {
933                 return NT_STATUS_NOT_IMPLEMENTED;
934         }
935         return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
936 }
937
938 _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security, 
939                             DATA_BLOB *session_key)
940 {
941         if (!gensec_security->ops->session_key) {
942                 return NT_STATUS_NOT_IMPLEMENTED;
943         }
944         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
945                 return NT_STATUS_NO_USER_SESSION_KEY;
946         }
947         
948         return gensec_security->ops->session_key(gensec_security, session_key);
949 }
950
951 /** 
952  * Return the credentials of a logged on user, including session keys
953  * etc.
954  *
955  * Only valid after a successful authentication
956  *
957  * May only be called once per authentication.
958  *
959  */
960
961 _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security, 
962                              struct auth_session_info **session_info)
963 {
964         if (!gensec_security->ops->session_info) {
965                 return NT_STATUS_NOT_IMPLEMENTED;
966         }
967         return gensec_security->ops->session_info(gensec_security, session_info);
968 }
969
970 /**
971  * Next state function for the GENSEC state machine
972  * 
973  * @param gensec_security GENSEC State
974  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
975  * @param in The request, as a DATA_BLOB
976  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
977  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
978  *                or NT_STATUS_OK if the user is authenticated. 
979  */
980
981 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 
982                        const DATA_BLOB in, DATA_BLOB *out) 
983 {
984         return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
985 }
986
987 struct gensec_update_state {
988         struct tevent_immediate *im;
989         struct gensec_security *gensec_security;
990         DATA_BLOB in;
991         DATA_BLOB out;
992 };
993
994 static void gensec_update_async_trigger(struct tevent_context *ctx,
995                                         struct tevent_immediate *im,
996                                         void *private_data);
997 /**
998  * Next state function for the GENSEC state machine async version
999  *
1000  * @param mem_ctx The memory context for the request
1001  * @param ev The event context for the request
1002  * @param gensec_security GENSEC State
1003  * @param in The request, as a DATA_BLOB
1004  *
1005  * @return The request handle or NULL on no memory failure
1006  */
1007
1008 _PUBLIC_ struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx,
1009                                                struct tevent_context *ev,
1010                                                struct gensec_security *gensec_security,
1011                                                const DATA_BLOB in)
1012 {
1013         struct tevent_req *req;
1014         struct gensec_update_state *state = NULL;
1015
1016         req = tevent_req_create(mem_ctx, &state,
1017                                 struct gensec_update_state);
1018         if (req == NULL) {
1019                 return NULL;
1020         }
1021
1022         state->gensec_security          = gensec_security;
1023         state->in                       = in;
1024         state->out                      = data_blob(NULL, 0);
1025         state->im                       = tevent_create_immediate(state);
1026         if (tevent_req_nomem(state->im, req)) {
1027                 return tevent_req_post(req, ev);
1028         }
1029
1030         tevent_schedule_immediate(state->im, ev,
1031                                   gensec_update_async_trigger,
1032                                   req);
1033
1034         return req;
1035 }
1036
1037 static void gensec_update_async_trigger(struct tevent_context *ctx,
1038                                         struct tevent_immediate *im,
1039                                         void *private_data)
1040 {
1041         struct tevent_req *req =
1042                 talloc_get_type_abort(private_data, struct tevent_req);
1043         struct gensec_update_state *state =
1044                 tevent_req_data(req, struct gensec_update_state);
1045         NTSTATUS status;
1046
1047         status = gensec_update(state->gensec_security, state,
1048                                state->in, &state->out);
1049         if (tevent_req_nterror(req, status)) {
1050                 return;
1051         }
1052
1053         tevent_req_done(req);
1054 }
1055
1056 /**
1057  * Next state function for the GENSEC state machine
1058  * 
1059  * @param req request state
1060  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
1061  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
1062  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
1063  *                or NT_STATUS_OK if the user is authenticated. 
1064  */
1065 _PUBLIC_ NTSTATUS gensec_update_recv(struct tevent_req *req,
1066                                      TALLOC_CTX *out_mem_ctx,
1067                                      DATA_BLOB *out)
1068 {
1069         struct gensec_update_state *state =
1070                 tevent_req_data(req, struct gensec_update_state);
1071         NTSTATUS status;
1072
1073         if (tevent_req_is_nterror(req, &status)) {
1074                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1075                         tevent_req_received(req);
1076                         return status;
1077                 }
1078         } else {
1079                 status = NT_STATUS_OK;
1080         }
1081
1082         *out = state->out;
1083         talloc_steal(out_mem_ctx, out->data);
1084
1085         tevent_req_received(req);
1086         return status;
1087 }
1088
1089 /** 
1090  * Set the requirement for a certain feature on the connection
1091  *
1092  */
1093
1094 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1095                          uint32_t feature) 
1096 {
1097         if (!gensec_security->ops || !gensec_security->ops->want_feature) {
1098                 gensec_security->want_features |= feature;
1099                 return;
1100         }
1101         gensec_security->ops->want_feature(gensec_security, feature);
1102 }
1103
1104 /** 
1105  * Check the requirement for a certain feature on the connection
1106  *
1107  */
1108
1109 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
1110                          uint32_t feature) 
1111 {
1112         if (!gensec_security->ops->have_feature) {
1113                 return false;
1114         }
1115         
1116         /* We might 'have' features that we don't 'want', because the
1117          * other end demanded them, or we can't neotiate them off */
1118         return gensec_security->ops->have_feature(gensec_security, feature);
1119 }
1120
1121 /** 
1122  * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context 
1123  *
1124  */
1125
1126 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials) 
1127 {
1128         gensec_security->credentials = talloc_reference(gensec_security, credentials);
1129         NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1130         gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1131         return NT_STATUS_OK;
1132 }
1133
1134 /** 
1135  * Return the credentials structure associated with a GENSEC context
1136  *
1137  */
1138
1139 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security) 
1140 {
1141         if (!gensec_security) {
1142                 return NULL;
1143         }
1144         return gensec_security->credentials;
1145 }
1146
1147 /** 
1148  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed 
1149  *
1150  */
1151
1152 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service) 
1153 {
1154         gensec_security->target.service = talloc_strdup(gensec_security, service);
1155         if (!gensec_security->target.service) {
1156                 return NT_STATUS_NO_MEMORY;
1157         }
1158         return NT_STATUS_OK;
1159 }
1160
1161 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security) 
1162 {
1163         if (gensec_security->target.service) {
1164                 return gensec_security->target.service;
1165         }
1166
1167         return "host";
1168 }
1169
1170 /** 
1171  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed 
1172  *
1173  */
1174
1175 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) 
1176 {
1177         gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1178         if (hostname && !gensec_security->target.hostname) {
1179                 return NT_STATUS_NO_MEMORY;
1180         }
1181         return NT_STATUS_OK;
1182 }
1183
1184 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security) 
1185 {
1186         /* We allow the target hostname to be overriden for testing purposes */
1187         if (gensec_security->settings->target_hostname) {
1188                 return gensec_security->settings->target_hostname;
1189         }
1190
1191         if (gensec_security->target.hostname) {
1192                 return gensec_security->target.hostname;
1193         }
1194
1195         /* We could add use the 'set sockaddr' call, and do a reverse
1196          * lookup, but this would be both insecure (compromising the
1197          * way kerberos works) and add DNS timeouts */
1198         return NULL;
1199 }
1200
1201 /**
1202  * Set (and talloc_reference) local and peer socket addresses onto a socket
1203  * context on the GENSEC context.
1204  *
1205  * This is so that kerberos can include these addresses in
1206  * cryptographic tokens, to avoid certain attacks.
1207  */
1208
1209 /**
1210  * @brief Set the local gensec address.
1211  *
1212  * @param  gensec_security   The gensec security context to use.
1213  *
1214  * @param  remote       The local address to set.
1215  *
1216  * @return              On success NT_STATUS_OK is returned or an NT_STATUS
1217  *                      error.
1218  */
1219 _PUBLIC_ NTSTATUS gensec_set_local_address(struct gensec_security *gensec_security,
1220                 const struct tsocket_address *local)
1221 {
1222         TALLOC_FREE(gensec_security->local_addr);
1223
1224         if (local == NULL) {
1225                 return NT_STATUS_OK;
1226         }
1227
1228         gensec_security->local_addr = tsocket_address_copy(local, gensec_security);
1229         if (gensec_security->local_addr == NULL) {
1230                 return NT_STATUS_NO_MEMORY;
1231         }
1232
1233         return NT_STATUS_OK;
1234 }
1235
1236 /**
1237  * @brief Set the remote gensec address.
1238  *
1239  * @param  gensec_security   The gensec security context to use.
1240  *
1241  * @param  remote       The remote address to set.
1242  *
1243  * @return              On success NT_STATUS_OK is returned or an NT_STATUS
1244  *                      error.
1245  */
1246 _PUBLIC_ NTSTATUS gensec_set_remote_address(struct gensec_security *gensec_security,
1247                 const struct tsocket_address *remote)
1248 {
1249         TALLOC_FREE(gensec_security->remote_addr);
1250
1251         if (remote == NULL) {
1252                 return NT_STATUS_OK;
1253         }
1254
1255         gensec_security->remote_addr = tsocket_address_copy(remote, gensec_security);
1256         if (gensec_security->remote_addr == NULL) {
1257                 return NT_STATUS_NO_MEMORY;
1258         }
1259
1260         return NT_STATUS_OK;
1261 }
1262
1263 /**
1264  * @brief Get the local address from a gensec security context.
1265  *
1266  * @param  gensec_security   The security context to get the address from.
1267  *
1268  * @return              The address as tsocket_address which could be NULL if
1269  *                      no address is set.
1270  */
1271 _PUBLIC_ const struct tsocket_address *gensec_get_local_address(struct gensec_security *gensec_security)
1272 {
1273         if (gensec_security == NULL) {
1274                 return NULL;
1275         }
1276         return gensec_security->local_addr;
1277 }
1278
1279 /**
1280  * @brief Get the remote address from a gensec security context.
1281  *
1282  * @param  gensec_security   The security context to get the address from.
1283  *
1284  * @return              The address as tsocket_address which could be NULL if
1285  *                      no address is set.
1286  */
1287 _PUBLIC_ const struct tsocket_address *gensec_get_remote_address(struct gensec_security *gensec_security)
1288 {
1289         if (gensec_security == NULL) {
1290                 return NULL;
1291         }
1292         return gensec_security->remote_addr;
1293 }
1294
1295
1296 /** 
1297  * Set the target principal (assuming it it known, say from the SPNEGO reply)
1298  *  - ensures it is talloc()ed 
1299  *
1300  */
1301
1302 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal) 
1303 {
1304         gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1305         if (!gensec_security->target.principal) {
1306                 return NT_STATUS_NO_MEMORY;
1307         }
1308         return NT_STATUS_OK;
1309 }
1310
1311 const char *gensec_get_target_principal(struct gensec_security *gensec_security) 
1312 {
1313         if (gensec_security->target.principal) {
1314                 return gensec_security->target.principal;
1315         }
1316
1317         return NULL;
1318 }
1319
1320 /*
1321   register a GENSEC backend. 
1322
1323   The 'name' can be later used by other backends to find the operations
1324   structure for this backend.
1325 */
1326 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1327 {
1328         if (gensec_security_by_name(NULL, ops->name) != NULL) {
1329                 /* its already registered! */
1330                 DEBUG(0,("GENSEC backend '%s' already registered\n", 
1331                          ops->name));
1332                 return NT_STATUS_OBJECT_NAME_COLLISION;
1333         }
1334
1335         generic_security_ops = talloc_realloc(talloc_autofree_context(), 
1336                                               generic_security_ops, 
1337                                               struct gensec_security_ops *, 
1338                                               gensec_num_backends+2);
1339         if (!generic_security_ops) {
1340                 return NT_STATUS_NO_MEMORY;
1341         }
1342
1343         generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1344         gensec_num_backends++;
1345         generic_security_ops[gensec_num_backends] = NULL;
1346
1347         DEBUG(3,("GENSEC backend '%s' registered\n", 
1348                  ops->name));
1349
1350         return NT_STATUS_OK;
1351 }
1352
1353 /*
1354   return the GENSEC interface version, and the size of some critical types
1355   This can be used by backends to either detect compilation errors, or provide
1356   multiple implementations for different smbd compilation options in one module
1357 */
1358 const struct gensec_critical_sizes *gensec_interface_version(void)
1359 {
1360         static const struct gensec_critical_sizes critical_sizes = {
1361                 GENSEC_INTERFACE_VERSION,
1362                 sizeof(struct gensec_security_ops),
1363                 sizeof(struct gensec_security),
1364         };
1365
1366         return &critical_sizes;
1367 }
1368
1369 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1370         return (*gs2)->priority - (*gs1)->priority;
1371 }
1372
1373 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
1374 {
1375         return lp_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
1376 }
1377
1378 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
1379 {
1380         return lp_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
1381 }
1382
1383 /*
1384   initialise the GENSEC subsystem
1385 */
1386 _PUBLIC_ NTSTATUS gensec_init(struct loadparm_context *lp_ctx)
1387 {
1388         static bool initialized = false;
1389         extern NTSTATUS gensec_sasl_init(void);
1390         extern NTSTATUS gensec_krb5_init(void);
1391         extern NTSTATUS gensec_schannel_init(void);
1392         extern NTSTATUS gensec_spnego_init(void);
1393         extern NTSTATUS gensec_gssapi_init(void);
1394         extern NTSTATUS gensec_ntlmssp_init(void);
1395
1396         init_module_fn static_init[] = { STATIC_gensec_MODULES };
1397         init_module_fn *shared_init;
1398
1399         if (initialized) return NT_STATUS_OK;
1400         initialized = true;
1401         
1402         shared_init = load_samba_modules(NULL, lp_ctx, "gensec");
1403
1404         run_init_functions(static_init);
1405         run_init_functions(shared_init);
1406
1407         talloc_free(shared_init);
1408
1409         TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
1410         
1411         return NT_STATUS_OK;
1412 }