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