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