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