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