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