gensec: explain gensec_use_kerberos_mechs() logic
[obnox/samba/samba-obnox.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 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
284                                                                 TALLOC_CTX *mem_ctx,
285                                                                 const char **sasl_names)
286 {
287         const struct gensec_security_ops **backends_out;
288         struct gensec_security_ops **backends;
289         int i, k, sasl_idx;
290         int num_backends_out = 0;
291
292         if (!sasl_names) {
293                 return NULL;
294         }
295
296         backends = gensec_security_mechs(gensec_security, mem_ctx);
297
298         backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
299         if (!backends_out) {
300                 return NULL;
301         }
302         backends_out[0] = NULL;
303
304         /* Find backends in our preferred order, by walking our list,
305          * then looking in the supplied list */
306         for (i=0; backends && backends[i]; i++) {
307                 if (gensec_security != NULL &&
308                                 !gensec_security_ops_enabled(backends[i], gensec_security))
309                     continue;
310                 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
311                         if (!backends[i]->sasl_name ||
312                             !(strcmp(backends[i]->sasl_name,
313                                      sasl_names[sasl_idx]) == 0)) {
314                                 continue;
315                         }
316
317                         for (k=0; backends_out[k]; k++) {
318                                 if (backends_out[k] == backends[i]) {
319                                         break;
320                                 }
321                         }
322
323                         if (k < num_backends_out) {
324                                 /* already in there */
325                                 continue;
326                         }
327
328                         backends_out = talloc_realloc(mem_ctx, backends_out,
329                                                       const struct gensec_security_ops *,
330                                                       num_backends_out + 2);
331                         if (!backends_out) {
332                                 return NULL;
333                         }
334
335                         backends_out[num_backends_out] = backends[i];
336                         num_backends_out++;
337                         backends_out[num_backends_out] = NULL;
338                 }
339         }
340         return backends_out;
341 }
342
343 /**
344  * Return a unique list of security subsystems from those specified in
345  * the OID list.  That is, where two OIDs refer to the same module,
346  * return that module only once.
347  *
348  * Use the list of enabled GENSEC mechanisms from the credentials
349  * attached to the gensec_security, and return in our preferred order.
350  */
351
352 _PUBLIC_ const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(
353                                         struct gensec_security *gensec_security,
354                                         TALLOC_CTX *mem_ctx,
355                                         const char **oid_strings,
356                                         const char *skip)
357 {
358         struct gensec_security_ops_wrapper *backends_out;
359         struct gensec_security_ops **backends;
360         int i, j, k, oid_idx;
361         int num_backends_out = 0;
362
363         if (!oid_strings) {
364                 return NULL;
365         }
366
367         backends = gensec_security_mechs(gensec_security, gensec_security);
368
369         backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
370         if (!backends_out) {
371                 return NULL;
372         }
373         backends_out[0].op = NULL;
374         backends_out[0].oid = NULL;
375
376         /* Find backends in our preferred order, by walking our list,
377          * then looking in the supplied list */
378         for (i=0; backends && backends[i]; i++) {
379                 if (gensec_security != NULL &&
380                                 !gensec_security_ops_enabled(backends[i], gensec_security))
381                     continue;
382                 if (!backends[i]->oid) {
383                         continue;
384                 }
385                 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
386                         if (strcmp(oid_strings[oid_idx], skip) == 0) {
387                                 continue;
388                         }
389
390                         for (j=0; backends[i]->oid[j]; j++) {
391                                 if (!backends[i]->oid[j] ||
392                                     !(strcmp(backends[i]->oid[j],
393                                             oid_strings[oid_idx]) == 0)) {
394                                         continue;
395                                 }
396
397                                 for (k=0; backends_out[k].op; k++) {
398                                         if (backends_out[k].op == backends[i]) {
399                                                 break;
400                                         }
401                                 }
402
403                                 if (k < num_backends_out) {
404                                         /* already in there */
405                                         continue;
406                                 }
407
408                                 backends_out = talloc_realloc(mem_ctx, backends_out,
409                                                               struct gensec_security_ops_wrapper,
410                                                               num_backends_out + 2);
411                                 if (!backends_out) {
412                                         return NULL;
413                                 }
414
415                                 backends_out[num_backends_out].op = backends[i];
416                                 backends_out[num_backends_out].oid = backends[i]->oid[j];
417                                 num_backends_out++;
418                                 backends_out[num_backends_out].op = NULL;
419                                 backends_out[num_backends_out].oid = NULL;
420                         }
421                 }
422         }
423         return backends_out;
424 }
425
426 /**
427  * Return OIDS from the security subsystems listed
428  */
429
430 const char **gensec_security_oids_from_ops(struct gensec_security *gensec_security,
431                                                                                    TALLOC_CTX *mem_ctx,
432                                            struct gensec_security_ops **ops,
433                                            const char *skip)
434 {
435         int i;
436         int j = 0;
437         int k;
438         const char **oid_list;
439         if (!ops) {
440                 return NULL;
441         }
442         oid_list = talloc_array(mem_ctx, const char *, 1);
443         if (!oid_list) {
444                 return NULL;
445         }
446
447         for (i=0; ops && ops[i]; i++) {
448                 if (gensec_security != NULL &&
449                         !gensec_security_ops_enabled(ops[i], gensec_security)) {
450                         continue;
451                 }
452                 if (!ops[i]->oid) {
453                         continue;
454                 }
455
456                 for (k = 0; ops[i]->oid[k]; k++) {
457                         if (skip && strcmp(skip, ops[i]->oid[k])==0) {
458                         } else {
459                                 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
460                                 if (!oid_list) {
461                                         return NULL;
462                                 }
463                                 oid_list[j] = ops[i]->oid[k];
464                                 j++;
465                         }
466                 }
467         }
468         oid_list[j] = NULL;
469         return oid_list;
470 }
471
472
473 /**
474  * Return OIDS from the security subsystems listed
475  */
476
477 _PUBLIC_ const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
478                                 const struct gensec_security_ops_wrapper *wops)
479 {
480         int i;
481         int j = 0;
482         int k;
483         const char **oid_list;
484         if (!wops) {
485                 return NULL;
486         }
487         oid_list = talloc_array(mem_ctx, const char *, 1);
488         if (!oid_list) {
489                 return NULL;
490         }
491
492         for (i=0; wops[i].op; i++) {
493                 if (!wops[i].op->oid) {
494                         continue;
495                 }
496
497                 for (k = 0; wops[i].op->oid[k]; k++) {
498                         oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
499                         if (!oid_list) {
500                                 return NULL;
501                         }
502                         oid_list[j] = wops[i].op->oid[k];
503                         j++;
504                 }
505         }
506         oid_list[j] = NULL;
507         return oid_list;
508 }
509
510
511 /**
512  * Return all the security subsystems currently enabled on a GENSEC context.
513  *
514  * This is taken from a list attached to the cli_credentials, and
515  * skips the OID in 'skip'.  (Typically the SPNEGO OID)
516  *
517  */
518
519 _PUBLIC_ const char **gensec_security_oids(struct gensec_security *gensec_security,
520                                            TALLOC_CTX *mem_ctx,
521                                            const char *skip)
522 {
523         struct gensec_security_ops **ops
524                 = gensec_security_mechs(gensec_security, mem_ctx);
525         return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
526 }
527
528 /**
529   Start the GENSEC system, returning a context pointer.
530   @param mem_ctx The parent TALLOC memory context.
531   @param gensec_security Returned GENSEC context pointer.
532   @note  The mem_ctx is only a parent and may be NULL.
533   @note, the auth context is moved to be a referenced pointer of the
534   @ gensec_security return
535 */
536 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
537                              struct gensec_settings *settings,
538                              struct auth4_context *auth_context,
539                              struct gensec_security **gensec_security)
540 {
541         (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
542         NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
543
544         (*gensec_security)->max_update_size = 0;
545
546         SMB_ASSERT(settings->lp_ctx != NULL);
547         (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
548
549         /* We need to reference this, not steal, as the caller may be
550          * python, which won't like it if we steal it's object away
551          * from it */
552         (*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context);
553
554         return NT_STATUS_OK;
555 }
556
557 /**
558  * Start a GENSEC subcontext, with a copy of the properties of the parent
559  * @param mem_ctx The parent TALLOC memory context.
560  * @param parent The parent GENSEC context
561  * @param gensec_security Returned GENSEC context pointer.
562  * @note Used by SPNEGO in particular, for the actual implementation mechanism
563  */
564
565 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
566                                  struct gensec_security *parent,
567                                  struct gensec_security **gensec_security)
568 {
569         (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
570         NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
571
572         (**gensec_security) = *parent;
573         (*gensec_security)->ops = NULL;
574         (*gensec_security)->private_data = NULL;
575
576         (*gensec_security)->subcontext = true;
577         (*gensec_security)->want_features = parent->want_features;
578         (*gensec_security)->max_update_size = parent->max_update_size;
579         (*gensec_security)->dcerpc_auth_level = parent->dcerpc_auth_level;
580         (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
581         (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
582         (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
583
584         return NT_STATUS_OK;
585 }
586
587 /**
588   Start the GENSEC system, in client mode, returning a context pointer.
589   @param mem_ctx The parent TALLOC memory context.
590   @param gensec_security Returned GENSEC context pointer.
591   @note  The mem_ctx is only a parent and may be NULL.
592 */
593 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
594                              struct gensec_security **gensec_security,
595                              struct gensec_settings *settings)
596 {
597         NTSTATUS status;
598
599         if (settings == NULL) {
600                 DEBUG(0,("gensec_client_start: no settings given!\n"));
601                 return NT_STATUS_INTERNAL_ERROR;
602         }
603
604         status = gensec_start(mem_ctx, settings, NULL, gensec_security);
605         if (!NT_STATUS_IS_OK(status)) {
606                 return status;
607         }
608         (*gensec_security)->gensec_role = GENSEC_CLIENT;
609
610         return status;
611 }
612
613
614
615 /**
616   Start the GENSEC system, in server mode, returning a context pointer.
617   @param mem_ctx The parent TALLOC memory context.
618   @param gensec_security Returned GENSEC context pointer.
619   @note  The mem_ctx is only a parent and may be NULL.
620 */
621 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
622                                       struct gensec_settings *settings,
623                                       struct auth4_context *auth_context,
624                                       struct gensec_security **gensec_security)
625 {
626         NTSTATUS status;
627
628         if (!settings) {
629                 DEBUG(0,("gensec_server_start: no settings given!\n"));
630                 return NT_STATUS_INTERNAL_ERROR;
631         }
632
633         status = gensec_start(mem_ctx, settings, auth_context, gensec_security);
634         if (!NT_STATUS_IS_OK(status)) {
635                 return status;
636         }
637         (*gensec_security)->gensec_role = GENSEC_SERVER;
638
639         return status;
640 }
641
642 NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
643 {
644         NTSTATUS status;
645         DEBUG(5, ("Starting GENSEC %smechanism %s\n",
646                   gensec_security->subcontext ? "sub" : "",
647                   gensec_security->ops->name));
648         switch (gensec_security->gensec_role) {
649         case GENSEC_CLIENT:
650                 if (gensec_security->ops->client_start) {
651                         status = gensec_security->ops->client_start(gensec_security);
652                         if (!NT_STATUS_IS_OK(status)) {
653                                 DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n",
654                                           gensec_security->ops->name, nt_errstr(status)));
655                         }
656                         return status;
657                 }
658                 break;
659         case GENSEC_SERVER:
660                 if (gensec_security->ops->server_start) {
661                         status = gensec_security->ops->server_start(gensec_security);
662                         if (!NT_STATUS_IS_OK(status)) {
663                                 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
664                                           gensec_security->ops->name, nt_errstr(status)));
665                         }
666                         return status;
667                 }
668                 break;
669         }
670         return NT_STATUS_INVALID_PARAMETER;
671 }
672
673 /**
674  * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO
675  *
676  */
677
678 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
679                                   const struct gensec_security_ops *ops)
680 {
681         gensec_security->ops = ops;
682         return gensec_start_mech(gensec_security);
683 }
684
685
686 /**
687  * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
688  * @param gensec_security GENSEC context pointer.
689  * @param auth_type DCERPC auth type
690  * @param auth_level DCERPC auth level
691  */
692
693 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
694                                        uint8_t auth_type, uint8_t auth_level)
695 {
696         gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
697         if (!gensec_security->ops) {
698                 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
699                 return NT_STATUS_INVALID_PARAMETER;
700         }
701         gensec_security->dcerpc_auth_level = auth_level;
702         gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
703         gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
704         if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
705                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
706         } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
707                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
708                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
709         } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
710                 /* Default features */
711         } else {
712                 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
713                          auth_level));
714                 return NT_STATUS_INVALID_PARAMETER;
715         }
716
717         return gensec_start_mech(gensec_security);
718 }
719
720 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
721 {
722         const struct gensec_security_ops *ops;
723         ops = gensec_security_by_authtype(gensec_security, authtype);
724         if (ops) {
725                 return ops->name;
726         }
727         return NULL;
728 }
729
730
731 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
732                                                                                         const char *oid_string)
733 {
734         const struct gensec_security_ops *ops;
735         ops = gensec_security_by_oid(gensec_security, oid_string);
736         if (ops) {
737                 return ops->name;
738         }
739         return oid_string;
740 }
741
742 /**
743  * Start a GENSEC sub-mechanism by OID, used in SPNEGO
744  *
745  * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
746  *       well-known #define to hook it in.
747  */
748
749 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
750                                   const char *mech_oid)
751 {
752         SMB_ASSERT(gensec_security != NULL);
753
754         gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
755         if (!gensec_security->ops) {
756                 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
757                 return NT_STATUS_INVALID_PARAMETER;
758         }
759         return gensec_start_mech(gensec_security);
760 }
761
762 /**
763  * Start a GENSEC sub-mechanism by a well know SASL name
764  *
765  */
766
767 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
768                                         const char *sasl_name)
769 {
770         gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
771         if (!gensec_security->ops) {
772                 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
773                 return NT_STATUS_INVALID_PARAMETER;
774         }
775         return gensec_start_mech(gensec_security);
776 }
777
778 /**
779  * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
780  *
781  */
782
783 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
784                                                  const char **sasl_names)
785 {
786         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
787         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
788         const struct gensec_security_ops **ops;
789         int i;
790         if (!mem_ctx) {
791                 return NT_STATUS_NO_MEMORY;
792         }
793         ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
794         if (!ops || !*ops) {
795                 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
796                           str_list_join(mem_ctx,
797                                         sasl_names, ' ')));
798                 talloc_free(mem_ctx);
799                 return NT_STATUS_INVALID_PARAMETER;
800         }
801         for (i=0; ops[i]; i++) {
802                 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
803                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
804                         break;
805                 }
806         }
807         talloc_free(mem_ctx);
808         return nt_status;
809 }
810
811 /**
812  * Start a GENSEC sub-mechanism by an internal name
813  *
814  */
815
816 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
817                                         const char *name)
818 {
819         gensec_security->ops = gensec_security_by_name(gensec_security, name);
820         if (!gensec_security->ops) {
821                 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
822                 return NT_STATUS_INVALID_PARAMETER;
823         }
824         return gensec_start_mech(gensec_security);
825 }
826
827 /**
828  * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
829  *
830  */
831
832 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
833 {
834         gensec_security->credentials = talloc_reference(gensec_security, credentials);
835         NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
836         gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
837         return NT_STATUS_OK;
838 }
839
840 /*
841   register a GENSEC backend.
842
843   The 'name' can be later used by other backends to find the operations
844   structure for this backend.
845 */
846 _PUBLIC_ NTSTATUS gensec_register(const struct gensec_security_ops *ops)
847 {
848         if (gensec_security_by_name(NULL, ops->name) != NULL) {
849                 /* its already registered! */
850                 DEBUG(0,("GENSEC backend '%s' already registered\n",
851                          ops->name));
852                 return NT_STATUS_OBJECT_NAME_COLLISION;
853         }
854
855         generic_security_ops = talloc_realloc(talloc_autofree_context(),
856                                               generic_security_ops,
857                                               struct gensec_security_ops *,
858                                               gensec_num_backends+2);
859         if (!generic_security_ops) {
860                 return NT_STATUS_NO_MEMORY;
861         }
862
863         generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
864         gensec_num_backends++;
865         generic_security_ops[gensec_num_backends] = NULL;
866
867         DEBUG(3,("GENSEC backend '%s' registered\n",
868                  ops->name));
869
870         return NT_STATUS_OK;
871 }
872
873 /*
874   return the GENSEC interface version, and the size of some critical types
875   This can be used by backends to either detect compilation errors, or provide
876   multiple implementations for different smbd compilation options in one module
877 */
878 const struct gensec_critical_sizes *gensec_interface_version(void)
879 {
880         static const struct gensec_critical_sizes critical_sizes = {
881                 GENSEC_INTERFACE_VERSION,
882                 sizeof(struct gensec_security_ops),
883                 sizeof(struct gensec_security),
884         };
885
886         return &critical_sizes;
887 }
888
889 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
890         return (*gs2)->priority - (*gs1)->priority;
891 }
892
893 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
894 {
895         return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
896 }
897
898 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
899 {
900         return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
901 }
902
903 /*
904   initialise the GENSEC subsystem
905 */
906 _PUBLIC_ NTSTATUS gensec_init(void)
907 {
908         static bool initialized = false;
909 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
910 #ifdef STATIC_gensec_MODULES
911         STATIC_gensec_MODULES_PROTO;
912         init_module_fn static_init[] = { STATIC_gensec_MODULES };
913 #else
914         init_module_fn *static_init = NULL;
915 #endif
916         init_module_fn *shared_init;
917
918         if (initialized) return NT_STATUS_OK;
919         initialized = true;
920
921         shared_init = load_samba_modules(NULL, "gensec");
922
923         run_init_functions(static_init);
924         run_init_functions(shared_init);
925
926         talloc_free(shared_init);
927
928         TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
929
930         return NT_STATUS_OK;
931 }