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