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