auth/gensec: add gensec_*max_update_size()
[nivanova/samba-autobuild/.git] / auth / gensec / gensec_start.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Generic Authentication Interface
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2006
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "system/network.h"
25 #include "tevent.h"
26 #include "../lib/util/tevent_ntstatus.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/gensec/gensec.h"
30 #include "lib/param/param.h"
31 #include "lib/util/tsort.h"
32 #include "lib/util/samba_modules.h"
33
34 /* the list of currently registered GENSEC backends */
35 static struct gensec_security_ops **generic_security_ops;
36 static int gensec_num_backends;
37
38 /* Return all the registered mechs.  Don't modify the return pointer,
39  * but you may talloc_reference it if convient */
40 _PUBLIC_ struct gensec_security_ops **gensec_security_all(void)
41 {
42         return generic_security_ops;
43 }
44
45 bool gensec_security_ops_enabled(struct gensec_security_ops *ops, struct gensec_security *security)
46 {
47         return lpcfg_parm_bool(security->settings->lp_ctx, NULL, "gensec", ops->name, ops->enabled);
48 }
49
50 /* Sometimes we want to force only kerberos, sometimes we want to
51  * force it's avoidance.  The old list could be either
52  * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
53  * an existing list we have trimmed down) */
54
55 _PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
56                                                        struct gensec_security_ops **old_gensec_list,
57                                                        struct cli_credentials *creds)
58 {
59         struct gensec_security_ops **new_gensec_list;
60         int i, j, num_mechs_in;
61         enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
62
63         if (creds) {
64                 use_kerberos = cli_credentials_get_kerberos_state(creds);
65         }
66
67         if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
68                 if (!talloc_reference(mem_ctx, old_gensec_list)) {
69                         return NULL;
70                 }
71                 return old_gensec_list;
72         }
73
74         for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
75                 /* noop */
76         }
77
78         new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, 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         (*gensec_security)->max_update_size = UINT32_MAX;
522
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)->max_update_size = parent->max_update_size;
556         (*gensec_security)->dcerpc_auth_level = parent->dcerpc_auth_level;
557         (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
558         (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
559         (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
560
561         return NT_STATUS_OK;
562 }
563
564 /**
565   Start the GENSEC system, in client mode, returning a context pointer.
566   @param mem_ctx The parent TALLOC memory context.
567   @param gensec_security Returned GENSEC context pointer.
568   @note  The mem_ctx is only a parent and may be NULL.
569 */
570 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
571                              struct gensec_security **gensec_security,
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, 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 gensec_settings *settings,
600                                       struct auth4_context *auth_context,
601                                       struct gensec_security **gensec_security)
602 {
603         NTSTATUS status;
604
605         if (!settings) {
606                 DEBUG(0,("gensec_server_start: no settings given!\n"));
607                 return NT_STATUS_INTERNAL_ERROR;
608         }
609
610         status = gensec_start(mem_ctx, settings, auth_context, gensec_security);
611         if (!NT_STATUS_IS_OK(status)) {
612                 return status;
613         }
614         (*gensec_security)->gensec_role = GENSEC_SERVER;
615
616         return status;
617 }
618
619 NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
620 {
621         NTSTATUS status;
622         DEBUG(5, ("Starting GENSEC %smechanism %s\n",
623                   gensec_security->subcontext ? "sub" : "",
624                   gensec_security->ops->name));
625         switch (gensec_security->gensec_role) {
626         case GENSEC_CLIENT:
627                 if (gensec_security->ops->client_start) {
628                         status = gensec_security->ops->client_start(gensec_security);
629                         if (!NT_STATUS_IS_OK(status)) {
630                                 DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n",
631                                           gensec_security->ops->name, nt_errstr(status)));
632                         }
633                         return status;
634                 }
635                 break;
636         case GENSEC_SERVER:
637                 if (gensec_security->ops->server_start) {
638                         status = gensec_security->ops->server_start(gensec_security);
639                         if (!NT_STATUS_IS_OK(status)) {
640                                 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
641                                           gensec_security->ops->name, nt_errstr(status)));
642                         }
643                         return status;
644                 }
645                 break;
646         }
647         return NT_STATUS_INVALID_PARAMETER;
648 }
649
650 /**
651  * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO
652  *
653  */
654
655 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
656                                   const struct gensec_security_ops *ops)
657 {
658         gensec_security->ops = ops;
659         return gensec_start_mech(gensec_security);
660 }
661
662
663 /**
664  * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
665  * @param gensec_security GENSEC context pointer.
666  * @param auth_type DCERPC auth type
667  * @param auth_level DCERPC auth level
668  */
669
670 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
671                                        uint8_t auth_type, uint8_t auth_level)
672 {
673         gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
674         if (!gensec_security->ops) {
675                 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
676                 return NT_STATUS_INVALID_PARAMETER;
677         }
678         gensec_security->dcerpc_auth_level = auth_level;
679         gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
680         gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
681         if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
682                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
683         } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
684                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
685                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
686         } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
687                 /* Default features */
688         } else {
689                 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
690                          auth_level));
691                 return NT_STATUS_INVALID_PARAMETER;
692         }
693
694         return gensec_start_mech(gensec_security);
695 }
696
697 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
698 {
699         const struct gensec_security_ops *ops;
700         ops = gensec_security_by_authtype(gensec_security, authtype);
701         if (ops) {
702                 return ops->name;
703         }
704         return NULL;
705 }
706
707
708 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
709                                                                                         const char *oid_string)
710 {
711         const struct gensec_security_ops *ops;
712         ops = gensec_security_by_oid(gensec_security, oid_string);
713         if (ops) {
714                 return ops->name;
715         }
716         return oid_string;
717 }
718
719 /**
720  * Start a GENSEC sub-mechanism by OID, used in SPNEGO
721  *
722  * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
723  *       well-known #define to hook it in.
724  */
725
726 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
727                                   const char *mech_oid)
728 {
729         SMB_ASSERT(gensec_security != NULL);
730
731         gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
732         if (!gensec_security->ops) {
733                 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
734                 return NT_STATUS_INVALID_PARAMETER;
735         }
736         return gensec_start_mech(gensec_security);
737 }
738
739 /**
740  * Start a GENSEC sub-mechanism by a well know SASL name
741  *
742  */
743
744 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
745                                         const char *sasl_name)
746 {
747         gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
748         if (!gensec_security->ops) {
749                 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
750                 return NT_STATUS_INVALID_PARAMETER;
751         }
752         return gensec_start_mech(gensec_security);
753 }
754
755 /**
756  * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
757  *
758  */
759
760 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
761                                                  const char **sasl_names)
762 {
763         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
764         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
765         const struct gensec_security_ops **ops;
766         int i;
767         if (!mem_ctx) {
768                 return NT_STATUS_NO_MEMORY;
769         }
770         ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
771         if (!ops || !*ops) {
772                 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
773                           str_list_join(mem_ctx,
774                                         sasl_names, ' ')));
775                 talloc_free(mem_ctx);
776                 return NT_STATUS_INVALID_PARAMETER;
777         }
778         for (i=0; ops[i]; i++) {
779                 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
780                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
781                         break;
782                 }
783         }
784         talloc_free(mem_ctx);
785         return nt_status;
786 }
787
788 /**
789  * Start a GENSEC sub-mechanism by an internal name
790  *
791  */
792
793 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
794                                         const char *name)
795 {
796         gensec_security->ops = gensec_security_by_name(gensec_security, name);
797         if (!gensec_security->ops) {
798                 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
799                 return NT_STATUS_INVALID_PARAMETER;
800         }
801         return gensec_start_mech(gensec_security);
802 }
803
804 /**
805  * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
806  *
807  */
808
809 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
810 {
811         gensec_security->credentials = talloc_reference(gensec_security, credentials);
812         NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
813         gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
814         return NT_STATUS_OK;
815 }
816
817 /*
818   register a GENSEC backend.
819
820   The 'name' can be later used by other backends to find the operations
821   structure for this backend.
822 */
823 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
824 {
825         if (gensec_security_by_name(NULL, ops->name) != NULL) {
826                 /* its already registered! */
827                 DEBUG(0,("GENSEC backend '%s' already registered\n",
828                          ops->name));
829                 return NT_STATUS_OBJECT_NAME_COLLISION;
830         }
831
832         generic_security_ops = talloc_realloc(talloc_autofree_context(),
833                                               generic_security_ops,
834                                               struct gensec_security_ops *,
835                                               gensec_num_backends+2);
836         if (!generic_security_ops) {
837                 return NT_STATUS_NO_MEMORY;
838         }
839
840         generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
841         gensec_num_backends++;
842         generic_security_ops[gensec_num_backends] = NULL;
843
844         DEBUG(3,("GENSEC backend '%s' registered\n",
845                  ops->name));
846
847         return NT_STATUS_OK;
848 }
849
850 /*
851   return the GENSEC interface version, and the size of some critical types
852   This can be used by backends to either detect compilation errors, or provide
853   multiple implementations for different smbd compilation options in one module
854 */
855 const struct gensec_critical_sizes *gensec_interface_version(void)
856 {
857         static const struct gensec_critical_sizes critical_sizes = {
858                 GENSEC_INTERFACE_VERSION,
859                 sizeof(struct gensec_security_ops),
860                 sizeof(struct gensec_security),
861         };
862
863         return &critical_sizes;
864 }
865
866 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
867         return (*gs2)->priority - (*gs1)->priority;
868 }
869
870 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
871 {
872         return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
873 }
874
875 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
876 {
877         return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
878 }
879
880 /*
881   initialise the GENSEC subsystem
882 */
883 _PUBLIC_ NTSTATUS gensec_init(void)
884 {
885         static bool initialized = false;
886 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
887 #ifdef STATIC_gensec_MODULES
888         STATIC_gensec_MODULES_PROTO;
889         init_module_fn static_init[] = { STATIC_gensec_MODULES };
890 #else
891         init_module_fn *static_init = NULL;
892 #endif
893         init_module_fn *shared_init;
894
895         if (initialized) return NT_STATUS_OK;
896         initialized = true;
897
898         shared_init = load_samba_modules(NULL, "gensec");
899
900         run_init_functions(static_init);
901         run_init_functions(shared_init);
902
903         talloc_free(shared_init);
904
905         TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
906
907         return NT_STATUS_OK;
908 }