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