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