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