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