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