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