d2d62d6652e6071c15ed5bf5b8616ac492546722
[samba.git] / auth / gensec / gensec_start.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 "tevent.h"
26 #include "../lib/util/tevent_ntstatus.h"
27 #include "librpc/gen_ndr/dcerpc.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/gensec/gensec.h"
30 #include "auth/gensec/gensec_internal.h"
31 #include "lib/param/param.h"
32 #include "lib/util/tsort.h"
33 #include "lib/util/samba_modules.h"
34 #include "lib/util/base64.h"
35 #include "lib/crypto/gnutls_helpers.h"
36
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_AUTH
39
40 /* the list of currently registered GENSEC backends */
41 static const struct gensec_security_ops **generic_security_ops;
42 static int gensec_num_backends;
43
44 /* Return all the registered mechs.  Don't modify the return pointer,
45  * but you may talloc_referen it if convient */
46 _PUBLIC_ const struct gensec_security_ops * const *gensec_security_all(void)
47 {
48         return generic_security_ops;
49 }
50
51 bool gensec_security_ops_enabled(const struct gensec_security_ops *ops, struct gensec_security *security)
52 {
53         bool ok = lpcfg_parm_bool(security->settings->lp_ctx,
54                                   NULL,
55                                   "gensec",
56                                   ops->name,
57                                   ops->enabled);
58
59         if (!samba_gnutls_weak_crypto_allowed() && ops->weak_crypto) {
60                 ok = false;
61         }
62
63         return ok;
64 }
65
66 /* Sometimes we want to force only kerberos, sometimes we want to
67  * force it's avoidance.  The old list could be either
68  * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
69  * an existing list we have trimmed down)
70  *
71  * The intended logic is:
72  *
73  * if we are in the default AUTO have kerberos:
74  * - take a reference to the master list
75  * otherwise
76  * - always add spnego then:
77  * - if we 'MUST' have kerberos:
78  *   only add kerberos mechs
79  * - if we 'DONT' want kerberos':
80  *   only add non-kerberos mechs
81  *
82  * Once we get things like NegoEx or moonshot, this will of course get
83  * more compplex.
84  */
85
86 _PUBLIC_ const struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
87                         const struct gensec_security_ops * const *old_gensec_list,
88                         struct cli_credentials *creds)
89 {
90         const struct gensec_security_ops **new_gensec_list;
91         int i, j, num_mechs_in;
92         enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
93         bool keep_schannel = false;
94
95         if (creds) {
96                 use_kerberos = cli_credentials_get_kerberos_state(creds);
97                 if (cli_credentials_get_netlogon_creds(creds) != NULL) {
98                         keep_schannel = true;
99                 }
100         }
101
102         for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
103                 /* noop */
104         }
105
106         new_gensec_list = talloc_array(mem_ctx,
107                                        const struct gensec_security_ops *,
108                                        num_mechs_in + 1);
109         if (!new_gensec_list) {
110                 return NULL;
111         }
112
113         j = 0;
114         for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
115                 bool keep = false;
116
117                 /*
118                  * We want to keep SPNGEO and other backends
119                  */
120                 keep = old_gensec_list[i]->glue;
121
122                 if (old_gensec_list[i]->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
123                         keep = keep_schannel;
124                 }
125
126                 switch (use_kerberos) {
127                 case CRED_AUTO_USE_KERBEROS:
128                         keep = true;
129                         break;
130
131                 case CRED_DONT_USE_KERBEROS:
132                         if (old_gensec_list[i]->kerberos == false) {
133                                 keep = true;
134                         }
135
136                         break;
137
138                 case CRED_MUST_USE_KERBEROS:
139                         if (old_gensec_list[i]->kerberos == true) {
140                                 keep = true;
141                         }
142
143                         break;
144                 default:
145                         /* Can't happen or invalid parameter */
146                         return NULL;
147                 }
148
149                 if (!keep) {
150                         continue;
151                 }
152
153                 new_gensec_list[j] = old_gensec_list[i];
154                 j++;
155         }
156         new_gensec_list[j] = NULL;
157
158         return new_gensec_list;
159 }
160
161 _PUBLIC_ const struct gensec_security_ops **gensec_security_mechs(
162                                 struct gensec_security *gensec_security,
163                                 TALLOC_CTX *mem_ctx)
164 {
165         struct cli_credentials *creds = NULL;
166         const struct gensec_security_ops * const *backends = gensec_security_all();
167
168         if (gensec_security != NULL) {
169                 creds = gensec_get_credentials(gensec_security);
170
171                 if (gensec_security->settings->backends) {
172                         backends = gensec_security->settings->backends;
173                 }
174         }
175
176         return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
177
178 }
179
180 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_oid(
181                                 struct gensec_security *gensec_security,
182                                 const char *oid_string)
183 {
184         int i, j;
185         const struct gensec_security_ops **backends;
186         const struct gensec_security_ops *backend;
187         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
188         if (!mem_ctx) {
189                 return NULL;
190         }
191         backends = gensec_security_mechs(gensec_security, mem_ctx);
192         for (i=0; backends && backends[i]; i++) {
193                 if (gensec_security != NULL &&
194                                 !gensec_security_ops_enabled(backends[i],
195                                                                                          gensec_security))
196                     continue;
197                 if (backends[i]->oid) {
198                         for (j=0; backends[i]->oid[j]; j++) {
199                                 if (backends[i]->oid[j] &&
200                                     (strcmp(backends[i]->oid[j], oid_string) == 0)) {
201                                         backend = backends[i];
202                                         talloc_free(mem_ctx);
203                                         return backend;
204                                 }
205                         }
206                 }
207         }
208         talloc_free(mem_ctx);
209
210         return NULL;
211 }
212
213 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_sasl_name(
214                                 struct gensec_security *gensec_security,
215                                 const char *sasl_name)
216 {
217         int i;
218         const struct gensec_security_ops **backends;
219         const struct gensec_security_ops *backend;
220         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
221         if (!mem_ctx) {
222                 return NULL;
223         }
224         backends = gensec_security_mechs(gensec_security, mem_ctx);
225         for (i=0; backends && backends[i]; i++) {
226                 if (gensec_security != NULL &&
227                     !gensec_security_ops_enabled(backends[i], gensec_security)) {
228                         continue;
229                 }
230                 if (backends[i]->sasl_name
231                     && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
232                         backend = backends[i];
233                         talloc_free(mem_ctx);
234                         return backend;
235                 }
236         }
237         talloc_free(mem_ctx);
238
239         return NULL;
240 }
241
242 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_auth_type(
243                                 struct gensec_security *gensec_security,
244                                 uint32_t auth_type)
245 {
246         int i;
247         const struct gensec_security_ops **backends;
248         const struct gensec_security_ops *backend;
249         TALLOC_CTX *mem_ctx;
250
251         if (auth_type == DCERPC_AUTH_TYPE_NONE) {
252                 return NULL;
253         }
254
255         mem_ctx = talloc_new(gensec_security);
256         if (!mem_ctx) {
257                 return NULL;
258         }
259         backends = gensec_security_mechs(gensec_security, mem_ctx);
260         for (i=0; backends && backends[i]; i++) {
261                 if (gensec_security != NULL &&
262                     !gensec_security_ops_enabled(backends[i], gensec_security)) {
263                         continue;
264                 }
265                 if (backends[i]->auth_type == auth_type) {
266                         backend = backends[i];
267                         talloc_free(mem_ctx);
268                         return backend;
269                 }
270         }
271         talloc_free(mem_ctx);
272
273         return NULL;
274 }
275
276 const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
277                                                           const char *name)
278 {
279         int i;
280         const struct gensec_security_ops **backends;
281         const struct gensec_security_ops *backend;
282         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
283         if (!mem_ctx) {
284                 return NULL;
285         }
286         backends = gensec_security_mechs(gensec_security, mem_ctx);
287         for (i=0; backends && backends[i]; i++) {
288                 if (gensec_security != NULL &&
289                                 !gensec_security_ops_enabled(backends[i], gensec_security))
290                     continue;
291                 if (backends[i]->name
292                     && (strcmp(backends[i]->name, name) == 0)) {
293                         backend = backends[i];
294                         talloc_free(mem_ctx);
295                         return backend;
296                 }
297         }
298         talloc_free(mem_ctx);
299         return NULL;
300 }
301
302 /**
303  * Return a unique list of security subsystems from those specified in
304  * the list of SASL names.
305  *
306  * Use the list of enabled GENSEC mechanisms from the credentials
307  * attached to the gensec_security, and return in our preferred order.
308  */
309
310 static const struct gensec_security_ops **gensec_security_by_sasl_list(
311         struct gensec_security *gensec_security,
312         TALLOC_CTX *mem_ctx,
313         const char **sasl_names)
314 {
315         const struct gensec_security_ops **backends_out;
316         const struct gensec_security_ops **backends;
317         int i, k, sasl_idx;
318         int num_backends_out = 0;
319
320         if (!sasl_names) {
321                 return NULL;
322         }
323
324         backends = gensec_security_mechs(gensec_security, mem_ctx);
325
326         backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
327         if (!backends_out) {
328                 return NULL;
329         }
330         backends_out[0] = NULL;
331
332         /* Find backends in our preferred order, by walking our list,
333          * then looking in the supplied list */
334         for (i=0; backends && backends[i]; i++) {
335                 if (gensec_security != NULL &&
336                                 !gensec_security_ops_enabled(backends[i], gensec_security))
337                     continue;
338                 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
339                         if (!backends[i]->sasl_name ||
340                             !(strcmp(backends[i]->sasl_name,
341                                      sasl_names[sasl_idx]) == 0)) {
342                                 continue;
343                         }
344
345                         for (k=0; backends_out[k]; k++) {
346                                 if (backends_out[k] == backends[i]) {
347                                         break;
348                                 }
349                         }
350
351                         if (k < num_backends_out) {
352                                 /* already in there */
353                                 continue;
354                         }
355
356                         backends_out = talloc_realloc(mem_ctx, backends_out,
357                                                       const struct gensec_security_ops *,
358                                                       num_backends_out + 2);
359                         if (!backends_out) {
360                                 return NULL;
361                         }
362
363                         backends_out[num_backends_out] = backends[i];
364                         num_backends_out++;
365                         backends_out[num_backends_out] = NULL;
366                 }
367         }
368         return backends_out;
369 }
370
371 /**
372  * Return a unique list of security subsystems from those specified in
373  * the OID list.  That is, where two OIDs refer to the same module,
374  * return that module only once.
375  *
376  * Use the list of enabled GENSEC mechanisms from the credentials
377  * attached to the gensec_security, and return in our preferred order.
378  */
379
380 _PUBLIC_ const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(
381                                         struct gensec_security *gensec_security,
382                                         TALLOC_CTX *mem_ctx,
383                                         const char * const *oid_strings,
384                                         const char *skip)
385 {
386         struct gensec_security_ops_wrapper *backends_out;
387         const struct gensec_security_ops **backends;
388         int i, j, k, oid_idx;
389         int num_backends_out = 0;
390
391         if (!oid_strings) {
392                 return NULL;
393         }
394
395         backends = gensec_security_mechs(gensec_security, gensec_security);
396
397         backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
398         if (!backends_out) {
399                 return NULL;
400         }
401         backends_out[0].op = NULL;
402         backends_out[0].oid = NULL;
403
404         /* Find backends in our preferred order, by walking our list,
405          * then looking in the supplied list */
406         for (i=0; backends && backends[i]; i++) {
407                 if (gensec_security != NULL &&
408                                 !gensec_security_ops_enabled(backends[i], gensec_security))
409                     continue;
410                 if (!backends[i]->oid) {
411                         continue;
412                 }
413                 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
414                         if (strcmp(oid_strings[oid_idx], skip) == 0) {
415                                 continue;
416                         }
417
418                         for (j=0; backends[i]->oid[j]; j++) {
419                                 if (!backends[i]->oid[j] ||
420                                     !(strcmp(backends[i]->oid[j],
421                                             oid_strings[oid_idx]) == 0)) {
422                                         continue;
423                                 }
424
425                                 for (k=0; backends_out[k].op; k++) {
426                                         if (backends_out[k].op == backends[i]) {
427                                                 break;
428                                         }
429                                 }
430
431                                 if (k < num_backends_out) {
432                                         /* already in there */
433                                         continue;
434                                 }
435
436                                 backends_out = talloc_realloc(mem_ctx, backends_out,
437                                                               struct gensec_security_ops_wrapper,
438                                                               num_backends_out + 2);
439                                 if (!backends_out) {
440                                         return NULL;
441                                 }
442
443                                 backends_out[num_backends_out].op = backends[i];
444                                 backends_out[num_backends_out].oid = backends[i]->oid[j];
445                                 num_backends_out++;
446                                 backends_out[num_backends_out].op = NULL;
447                                 backends_out[num_backends_out].oid = NULL;
448                         }
449                 }
450         }
451         return backends_out;
452 }
453
454 /**
455  * Return OIDS from the security subsystems listed
456  */
457
458 static const char **gensec_security_oids_from_ops(
459         struct gensec_security *gensec_security,
460         TALLOC_CTX *mem_ctx,
461         const struct gensec_security_ops * const *ops,
462         const char *skip)
463 {
464         int i;
465         int j = 0;
466         int k;
467         const char **oid_list;
468         if (!ops) {
469                 return NULL;
470         }
471         oid_list = talloc_array(mem_ctx, const char *, 1);
472         if (!oid_list) {
473                 return NULL;
474         }
475
476         for (i=0; ops && ops[i]; i++) {
477                 if (gensec_security != NULL &&
478                         !gensec_security_ops_enabled(ops[i], gensec_security)) {
479                         continue;
480                 }
481                 if (!ops[i]->oid) {
482                         continue;
483                 }
484
485                 for (k = 0; ops[i]->oid[k]; k++) {
486                         if (skip && strcmp(skip, ops[i]->oid[k])==0) {
487                         } else {
488                                 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
489                                 if (!oid_list) {
490                                         return NULL;
491                                 }
492                                 oid_list[j] = ops[i]->oid[k];
493                                 j++;
494                         }
495                 }
496         }
497         oid_list[j] = NULL;
498         return oid_list;
499 }
500
501
502 /**
503  * Return OIDS from the security subsystems listed
504  */
505
506 _PUBLIC_ const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
507                                 const struct gensec_security_ops_wrapper *wops)
508 {
509         int i;
510         int j = 0;
511         int k;
512         const char **oid_list;
513         if (!wops) {
514                 return NULL;
515         }
516         oid_list = talloc_array(mem_ctx, const char *, 1);
517         if (!oid_list) {
518                 return NULL;
519         }
520
521         for (i=0; wops[i].op; i++) {
522                 if (!wops[i].op->oid) {
523                         continue;
524                 }
525
526                 for (k = 0; wops[i].op->oid[k]; k++) {
527                         oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
528                         if (!oid_list) {
529                                 return NULL;
530                         }
531                         oid_list[j] = wops[i].op->oid[k];
532                         j++;
533                 }
534         }
535         oid_list[j] = NULL;
536         return oid_list;
537 }
538
539
540 /**
541  * Return all the security subsystems currently enabled on a GENSEC context.
542  *
543  * This is taken from a list attached to the cli_credentials, and
544  * skips the OID in 'skip'.  (Typically the SPNEGO OID)
545  *
546  */
547
548 _PUBLIC_ const char **gensec_security_oids(struct gensec_security *gensec_security,
549                                            TALLOC_CTX *mem_ctx,
550                                            const char *skip)
551 {
552         const struct gensec_security_ops **ops;
553
554         ops = gensec_security_mechs(gensec_security, mem_ctx);
555
556         return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
557 }
558
559 static int gensec_security_destructor(struct gensec_security *gctx)
560 {
561         if (gctx->parent_security != NULL) {
562                 if (gctx->parent_security->child_security == gctx) {
563                         gctx->parent_security->child_security = NULL;
564                 }
565                 gctx->parent_security = NULL;
566         }
567
568         if (gctx->child_security != NULL) {
569                 if (gctx->child_security->parent_security == gctx) {
570                         gctx->child_security->parent_security = NULL;
571                 }
572                 gctx->child_security = NULL;
573         }
574
575         return 0;
576 }
577
578 /**
579   Start the GENSEC system, returning a context pointer.
580   @param mem_ctx The parent TALLOC memory context.
581   @param gensec_security Returned GENSEC context pointer.
582   @note  The mem_ctx is only a parent and may be NULL.
583   @note, the auth context is moved to be a referenced pointer of the
584   @ gensec_security return
585 */
586 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
587                              struct gensec_settings *settings,
588                              struct auth4_context *auth_context,
589                              struct gensec_security **gensec_security)
590 {
591         (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
592         NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
593
594         (*gensec_security)->max_update_size = 0;
595
596         SMB_ASSERT(settings->lp_ctx != NULL);
597         (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
598
599         /* We need to reference this, not steal, as the caller may be
600          * python, which won't like it if we steal it's object away
601          * from it */
602         (*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context);
603
604         talloc_set_destructor((*gensec_security), gensec_security_destructor);
605         return NT_STATUS_OK;
606 }
607
608 /**
609  * Start a GENSEC subcontext, with a copy of the properties of the parent
610  * @param mem_ctx The parent TALLOC memory context.
611  * @param parent The parent GENSEC context
612  * @param gensec_security Returned GENSEC context pointer.
613  * @note Used by SPNEGO in particular, for the actual implementation mechanism
614  */
615
616 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
617                                  struct gensec_security *parent,
618                                  struct gensec_security **gensec_security)
619 {
620         if (parent->child_security != NULL) {
621                 return NT_STATUS_INTERNAL_ERROR;
622         }
623
624         (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
625         NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
626
627         (**gensec_security) = *parent;
628         (*gensec_security)->ops = NULL;
629         (*gensec_security)->private_data = NULL;
630         (*gensec_security)->update_busy_ptr = NULL;
631
632         (*gensec_security)->subcontext = true;
633         (*gensec_security)->want_features = parent->want_features;
634         (*gensec_security)->max_update_size = parent->max_update_size;
635         (*gensec_security)->dcerpc_auth_level = parent->dcerpc_auth_level;
636         (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
637         (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
638         (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
639
640         talloc_set_destructor((*gensec_security), gensec_security_destructor);
641         return NT_STATUS_OK;
642 }
643
644 _PUBLIC_ NTSTATUS gensec_child_ready(struct gensec_security *parent,
645                                      struct gensec_security *child)
646 {
647         if (parent->child_security != NULL) {
648                 return NT_STATUS_INTERNAL_ERROR;
649         }
650
651         if (child->parent_security != NULL) {
652                 return NT_STATUS_INTERNAL_ERROR;
653         }
654
655         parent->child_security = child;
656         child->parent_security = parent;
657         return NT_STATUS_OK;
658 }
659
660 /**
661   Start the GENSEC system, in client mode, returning a context pointer.
662   @param mem_ctx The parent TALLOC memory context.
663   @param gensec_security Returned GENSEC context pointer.
664   @note  The mem_ctx is only a parent and may be NULL.
665 */
666 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
667                              struct gensec_security **gensec_security,
668                              struct gensec_settings *settings)
669 {
670         NTSTATUS status;
671
672         if (settings == NULL) {
673                 DEBUG(0,("gensec_client_start: no settings given!\n"));
674                 return NT_STATUS_INTERNAL_ERROR;
675         }
676
677         status = gensec_start(mem_ctx, settings, NULL, gensec_security);
678         if (!NT_STATUS_IS_OK(status)) {
679                 return status;
680         }
681         (*gensec_security)->gensec_role = GENSEC_CLIENT;
682
683         return status;
684 }
685
686
687
688 /**
689   Start the GENSEC system, in server mode, returning a context pointer.
690   @param mem_ctx The parent TALLOC memory context.
691   @param gensec_security Returned GENSEC context pointer.
692   @note  The mem_ctx is only a parent and may be NULL.
693 */
694 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
695                                       struct gensec_settings *settings,
696                                       struct auth4_context *auth_context,
697                                       struct gensec_security **gensec_security)
698 {
699         NTSTATUS status;
700
701         if (!settings) {
702                 DEBUG(0,("gensec_server_start: no settings given!\n"));
703                 return NT_STATUS_INTERNAL_ERROR;
704         }
705
706         status = gensec_start(mem_ctx, settings, auth_context, gensec_security);
707         if (!NT_STATUS_IS_OK(status)) {
708                 return status;
709         }
710         (*gensec_security)->gensec_role = GENSEC_SERVER;
711
712         return status;
713 }
714
715 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
716 {
717         NTSTATUS status;
718
719         /*
720          * Callers sometimes just reuse a context, we should
721          * clear the internal state before starting it again.
722          */
723         talloc_unlink(gensec_security, gensec_security->private_data);
724         gensec_security->private_data = NULL;
725
726         if (gensec_security->child_security != NULL) {
727                 /*
728                  * The talloc_unlink(.., gensec_security->private_data)
729                  * should have cleared this via
730                  * gensec_security_destructor().
731                  */
732                 return NT_STATUS_INTERNAL_ERROR;
733         }
734
735         if (gensec_security->credentials) {
736                 const char *forced_mech = cli_credentials_get_forced_sasl_mech(gensec_security->credentials);
737                 if (forced_mech &&
738                     (gensec_security->ops->sasl_name == NULL ||
739                      strcasecmp(forced_mech, gensec_security->ops->sasl_name) != 0)) {
740                         DEBUG(5, ("GENSEC mechanism %s (%s) skipped, as it "
741                                   "did not match forced mechanism %s\n",
742                                   gensec_security->ops->name,
743                                   gensec_security->ops->sasl_name,
744                                   forced_mech));
745                         return NT_STATUS_INVALID_PARAMETER;
746                 }
747         }
748         DEBUG(5, ("Starting GENSEC %smechanism %s\n",
749                   gensec_security->subcontext ? "sub" : "",
750                   gensec_security->ops->name));
751         switch (gensec_security->gensec_role) {
752         case GENSEC_CLIENT:
753                 if (gensec_security->ops->client_start) {
754                         status = gensec_security->ops->client_start(gensec_security);
755                         if (!NT_STATUS_IS_OK(status)) {
756                                 DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n",
757                                           gensec_security->ops->name, nt_errstr(status)));
758                         }
759                         return status;
760                 }
761                 break;
762         case GENSEC_SERVER:
763                 if (gensec_security->ops->server_start) {
764                         status = gensec_security->ops->server_start(gensec_security);
765                         if (!NT_STATUS_IS_OK(status)) {
766                                 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
767                                           gensec_security->ops->name, nt_errstr(status)));
768                         }
769                         return status;
770                 }
771                 break;
772         }
773         return NT_STATUS_INVALID_PARAMETER;
774 }
775
776 /**
777  * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO
778  *
779  */
780
781 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
782                                   const struct gensec_security_ops *ops)
783 {
784         gensec_security->ops = ops;
785         return gensec_start_mech(gensec_security);
786 }
787
788
789 /**
790  * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
791  * @param gensec_security GENSEC context pointer.
792  * @param auth_type DCERPC auth type
793  * @param auth_level DCERPC auth level
794  */
795
796 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
797                                        uint8_t auth_type, uint8_t auth_level)
798 {
799         gensec_security->ops = gensec_security_by_auth_type(gensec_security, auth_type);
800         if (!gensec_security->ops) {
801                 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
802                 return NT_STATUS_INVALID_PARAMETER;
803         }
804         gensec_security->dcerpc_auth_level = auth_level;
805         /*
806          * We need to reset sign/seal in order to reset it.
807          * We may got some default features inherited by the credentials
808          */
809         gensec_security->want_features &= ~GENSEC_FEATURE_SIGN;
810         gensec_security->want_features &= ~GENSEC_FEATURE_SEAL;
811         gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
812         gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
813         if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
814                 if (gensec_security->gensec_role == GENSEC_CLIENT) {
815                         gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
816                 }
817         } else if (auth_level == DCERPC_AUTH_LEVEL_PACKET) {
818                 /*
819                  * For connection oriented DCERPC DCERPC_AUTH_LEVEL_PACKET (4)
820                  * has the same behavior as DCERPC_AUTH_LEVEL_INTEGRITY (5).
821                  */
822                 if (gensec_security->gensec_role == GENSEC_CLIENT) {
823                         gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
824                 }
825         } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
826                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
827                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
828         } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
829                 /* Default features */
830         } else {
831                 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
832                          auth_level));
833                 return NT_STATUS_INVALID_PARAMETER;
834         }
835
836         return gensec_start_mech(gensec_security);
837 }
838
839 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
840 {
841         const struct gensec_security_ops *ops;
842         ops = gensec_security_by_auth_type(gensec_security, authtype);
843         if (ops) {
844                 return ops->name;
845         }
846         return NULL;
847 }
848
849
850 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
851                                                                                         const char *oid_string)
852 {
853         const struct gensec_security_ops *ops;
854         ops = gensec_security_by_oid(gensec_security, oid_string);
855         if (ops) {
856                 return ops->name;
857         }
858         return oid_string;
859 }
860
861 /**
862  * Start a GENSEC sub-mechanism by OID, used in SPNEGO
863  *
864  * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
865  *       well-known #define to hook it in.
866  */
867
868 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
869                                   const char *mech_oid)
870 {
871         SMB_ASSERT(gensec_security != NULL);
872
873         gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
874         if (!gensec_security->ops) {
875                 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
876                 return NT_STATUS_INVALID_PARAMETER;
877         }
878         return gensec_start_mech(gensec_security);
879 }
880
881 /**
882  * Start a GENSEC sub-mechanism by a well know SASL name
883  *
884  */
885
886 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
887                                         const char *sasl_name)
888 {
889         gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
890         if (!gensec_security->ops) {
891                 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
892                 return NT_STATUS_INVALID_PARAMETER;
893         }
894         return gensec_start_mech(gensec_security);
895 }
896
897 /**
898  * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
899  *
900  */
901
902 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
903                                                  const char **sasl_names)
904 {
905         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
906         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
907         const struct gensec_security_ops **ops;
908         int i;
909         if (!mem_ctx) {
910                 return NT_STATUS_NO_MEMORY;
911         }
912         ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
913         if (!ops || !*ops) {
914                 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
915                           str_list_join(mem_ctx,
916                                         sasl_names, ' ')));
917                 talloc_free(mem_ctx);
918                 return NT_STATUS_INVALID_PARAMETER;
919         }
920         for (i=0; ops[i]; i++) {
921                 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
922                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
923                         break;
924                 }
925         }
926         talloc_free(mem_ctx);
927         return nt_status;
928 }
929
930 /**
931  * Start a GENSEC sub-mechanism by an internal name
932  *
933  */
934
935 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
936                                         const char *name)
937 {
938         gensec_security->ops = gensec_security_by_name(gensec_security, name);
939         if (!gensec_security->ops) {
940                 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
941                 return NT_STATUS_INVALID_PARAMETER;
942         }
943         return gensec_start_mech(gensec_security);
944 }
945
946 /**
947  * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
948  *
949  */
950
951 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
952 {
953         gensec_security->credentials = talloc_reference(gensec_security, credentials);
954         NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
955         gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
956         return NT_STATUS_OK;
957 }
958
959 /*
960   register a GENSEC backend.
961
962   The 'name' can be later used by other backends to find the operations
963   structure for this backend.
964 */
965 _PUBLIC_ NTSTATUS gensec_register(TALLOC_CTX *ctx,
966                         const struct gensec_security_ops *ops)
967 {
968         if (gensec_security_by_name(NULL, ops->name) != NULL) {
969                 /* its already registered! */
970                 DEBUG(0,("GENSEC backend '%s' already registered\n",
971                          ops->name));
972                 return NT_STATUS_OBJECT_NAME_COLLISION;
973         }
974
975         generic_security_ops = talloc_realloc(ctx,
976                                               generic_security_ops,
977                                               const struct gensec_security_ops *,
978                                               gensec_num_backends+2);
979         if (!generic_security_ops) {
980                 return NT_STATUS_NO_MEMORY;
981         }
982
983         generic_security_ops[gensec_num_backends] = ops;
984         gensec_num_backends++;
985         generic_security_ops[gensec_num_backends] = NULL;
986
987         DEBUG(3,("GENSEC backend '%s' registered\n",
988                  ops->name));
989
990         return NT_STATUS_OK;
991 }
992
993 /*
994   return the GENSEC interface version, and the size of some critical types
995   This can be used by backends to either detect compilation errors, or provide
996   multiple implementations for different smbd compilation options in one module
997 */
998 _PUBLIC_ const struct gensec_critical_sizes *gensec_interface_version(void)
999 {
1000         static const struct gensec_critical_sizes critical_sizes = {
1001                 GENSEC_INTERFACE_VERSION,
1002                 sizeof(struct gensec_security_ops),
1003                 sizeof(struct gensec_security),
1004         };
1005
1006         return &critical_sizes;
1007 }
1008
1009 static int sort_gensec(const struct gensec_security_ops **gs1, const struct gensec_security_ops **gs2) {
1010         return (*gs2)->priority - (*gs1)->priority;
1011 }
1012
1013 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
1014 {
1015         return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
1016 }
1017
1018 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
1019 {
1020         return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
1021 }
1022
1023 /*
1024   initialise the GENSEC subsystem
1025 */
1026 _PUBLIC_ NTSTATUS gensec_init(void)
1027 {
1028         static bool initialized = false;
1029 #define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *);
1030 #ifdef STATIC_gensec_MODULES
1031         STATIC_gensec_MODULES_PROTO;
1032         init_module_fn static_init[] = { STATIC_gensec_MODULES };
1033 #else
1034         init_module_fn *static_init = NULL;
1035 #endif
1036         init_module_fn *shared_init;
1037
1038         if (initialized) return NT_STATUS_OK;
1039         initialized = true;
1040
1041         shared_init = load_samba_modules(NULL, "gensec");
1042
1043         run_init_functions(NULL, static_init);
1044         run_init_functions(NULL, shared_init);
1045
1046         talloc_free(shared_init);
1047
1048         TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
1049
1050         return NT_STATUS_OK;
1051 }