gensec: split GENSEC into mechanism-dependent and runtime functions
[samba.git] / source4 / 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 "lib/events/events.h"
26 #include "lib/socket/socket.h"
27 #include "lib/tsocket/tsocket.h"
28 #include "../lib/util/tevent_ntstatus.h"
29 #include "librpc/rpc/dcerpc.h"
30 #include "auth/credentials/credentials.h"
31 #include "auth/gensec/gensec.h"
32 #include "auth/gensec/gensec_proto.h"
33 #include "auth/auth.h"
34 #include "auth/system_session_proto.h"
35 #include "param/param.h"
36 #include "lib/util/tsort.h"
37 #include "auth/gensec/gensec_toplevel_proto.h"
38
39 /* the list of currently registered GENSEC backends */
40 static struct gensec_security_ops **generic_security_ops;
41 static int gensec_num_backends;
42
43 /* Return all the registered mechs.  Don't modify the return pointer,
44  * but you may talloc_reference it if convient */
45 _PUBLIC_ struct gensec_security_ops **gensec_security_all(void)
46 {
47         return generic_security_ops;
48 }
49
50 bool gensec_security_ops_enabled(struct gensec_security_ops *ops, struct gensec_security *security)
51 {
52         return lpcfg_parm_bool(security->settings->lp_ctx, NULL, "gensec", ops->name, ops->enabled);
53 }
54
55 /* Sometimes we want to force only kerberos, sometimes we want to
56  * force it's avoidance.  The old list could be either
57  * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
58  * an existing list we have trimmed down) */
59
60 _PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
61                                                        struct gensec_security_ops **old_gensec_list,
62                                                        struct cli_credentials *creds)
63 {
64         struct gensec_security_ops **new_gensec_list;
65         int i, j, num_mechs_in;
66         enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
67
68         if (creds) {
69                 use_kerberos = cli_credentials_get_kerberos_state(creds);
70         }
71
72         if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
73                 if (!talloc_reference(mem_ctx, old_gensec_list)) {
74                         return NULL;
75                 }
76                 return old_gensec_list;
77         }
78
79         for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
80                 /* noop */
81         }
82
83         new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
84         if (!new_gensec_list) {
85                 return NULL;
86         }
87
88         j = 0;
89         for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
90                 int oid_idx;
91
92                 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
93                         if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
94                                 new_gensec_list[j] = old_gensec_list[i];
95                                 j++;
96                                 break;
97                         }
98                 }
99                 switch (use_kerberos) {
100                 case CRED_DONT_USE_KERBEROS:
101                         if (old_gensec_list[i]->kerberos == false) {
102                                 new_gensec_list[j] = old_gensec_list[i];
103                                 j++;
104                         }
105                         break;
106                 case CRED_MUST_USE_KERBEROS:
107                         if (old_gensec_list[i]->kerberos == true) {
108                                 new_gensec_list[j] = old_gensec_list[i];
109                                 j++;
110                         }
111                         break;
112                 default:
113                         /* Can't happen or invalid parameter */
114                         return NULL;
115                 }
116         }
117         new_gensec_list[j] = NULL;
118
119         return new_gensec_list;
120 }
121
122 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
123                                                    TALLOC_CTX *mem_ctx)
124 {
125         struct gensec_security_ops **backends;
126         backends = gensec_security_all();
127         if (!gensec_security) {
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 (!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 tevent_context *ev,
515                              struct gensec_settings *settings,
516                              struct auth4_context *auth_context,
517                              struct gensec_security **gensec_security)
518 {
519         if (ev == NULL) {
520                 DEBUG(0, ("No event context available!\n"));
521                 return NT_STATUS_INTERNAL_ERROR;
522         }
523
524         (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
525         NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
526
527         (*gensec_security)->event_ctx = ev;
528         SMB_ASSERT(settings->lp_ctx != NULL);
529         (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
530
531         /* We need to reference this, not steal, as the caller may be
532          * python, which won't like it if we steal it's object away
533          * from it */
534         (*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context);
535
536         return NT_STATUS_OK;
537 }
538
539 /**
540  * Start a GENSEC subcontext, with a copy of the properties of the parent
541  * @param mem_ctx The parent TALLOC memory context.
542  * @param parent The parent GENSEC context
543  * @param gensec_security Returned GENSEC context pointer.
544  * @note Used by SPNEGO in particular, for the actual implementation mechanism
545  */
546
547 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
548                                  struct gensec_security *parent,
549                                  struct gensec_security **gensec_security)
550 {
551         (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
552         NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
553
554         (**gensec_security) = *parent;
555         (*gensec_security)->ops = NULL;
556         (*gensec_security)->private_data = NULL;
557
558         (*gensec_security)->subcontext = true;
559         (*gensec_security)->want_features = parent->want_features;
560         (*gensec_security)->event_ctx = parent->event_ctx;
561         (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
562         (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
563         (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
564
565         return NT_STATUS_OK;
566 }
567
568 /**
569   Start the GENSEC system, in client mode, returning a context pointer.
570   @param mem_ctx The parent TALLOC memory context.
571   @param gensec_security Returned GENSEC context pointer.
572   @note  The mem_ctx is only a parent and may be NULL.
573 */
574 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
575                              struct gensec_security **gensec_security,
576                              struct tevent_context *ev,
577                              struct gensec_settings *settings)
578 {
579         NTSTATUS status;
580
581         if (settings == NULL) {
582                 DEBUG(0,("gensec_client_start: no settings given!\n"));
583                 return NT_STATUS_INTERNAL_ERROR;
584         }
585
586         status = gensec_start(mem_ctx, ev, settings, NULL, gensec_security);
587         if (!NT_STATUS_IS_OK(status)) {
588                 return status;
589         }
590         (*gensec_security)->gensec_role = GENSEC_CLIENT;
591
592         return status;
593 }
594
595
596
597 /**
598   Start the GENSEC system, in server mode, returning a context pointer.
599   @param mem_ctx The parent TALLOC memory context.
600   @param gensec_security Returned GENSEC context pointer.
601   @note  The mem_ctx is only a parent and may be NULL.
602 */
603 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
604                                       struct tevent_context *ev,
605                                       struct gensec_settings *settings,
606                                       struct auth4_context *auth_context,
607                                       struct gensec_security **gensec_security)
608 {
609         NTSTATUS status;
610
611         if (!ev) {
612                 DEBUG(0,("gensec_server_start: no event context given!\n"));
613                 return NT_STATUS_INTERNAL_ERROR;
614         }
615
616         if (!settings) {
617                 DEBUG(0,("gensec_server_start: no settings given!\n"));
618                 return NT_STATUS_INTERNAL_ERROR;
619         }
620
621         status = gensec_start(mem_ctx, ev, settings, auth_context, gensec_security);
622         if (!NT_STATUS_IS_OK(status)) {
623                 return status;
624         }
625         (*gensec_security)->gensec_role = GENSEC_SERVER;
626
627         return status;
628 }
629
630 NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
631 {
632         NTSTATUS status;
633         DEBUG(5, ("Starting GENSEC %smechanism %s\n",
634                   gensec_security->subcontext ? "sub" : "",
635                   gensec_security->ops->name));
636         switch (gensec_security->gensec_role) {
637         case GENSEC_CLIENT:
638                 if (gensec_security->ops->client_start) {
639                         status = gensec_security->ops->client_start(gensec_security);
640                         if (!NT_STATUS_IS_OK(status)) {
641                                 DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n",
642                                           gensec_security->ops->name, nt_errstr(status)));
643                         }
644                         return status;
645                 }
646                 break;
647         case GENSEC_SERVER:
648                 if (gensec_security->ops->server_start) {
649                         status = gensec_security->ops->server_start(gensec_security);
650                         if (!NT_STATUS_IS_OK(status)) {
651                                 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
652                                           gensec_security->ops->name, nt_errstr(status)));
653                         }
654                         return status;
655                 }
656                 break;
657         }
658         return NT_STATUS_INVALID_PARAMETER;
659 }
660
661 /**
662  * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO
663  *
664  */
665
666 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
667                                   const struct gensec_security_ops *ops)
668 {
669         gensec_security->ops = ops;
670         return gensec_start_mech(gensec_security);
671 }
672
673
674 /**
675  * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
676  * @param gensec_security GENSEC context pointer.
677  * @param auth_type DCERPC auth type
678  * @param auth_level DCERPC auth level
679  */
680
681 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
682                                        uint8_t auth_type, uint8_t auth_level)
683 {
684         gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
685         if (!gensec_security->ops) {
686                 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
687                 return NT_STATUS_INVALID_PARAMETER;
688         }
689         gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
690         gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
691         if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
692                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
693         } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
694                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
695                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
696         } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
697                 /* Default features */
698         } else {
699                 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
700                          auth_level));
701                 return NT_STATUS_INVALID_PARAMETER;
702         }
703
704         return gensec_start_mech(gensec_security);
705 }
706
707 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
708 {
709         const struct gensec_security_ops *ops;
710         ops = gensec_security_by_authtype(gensec_security, authtype);
711         if (ops) {
712                 return ops->name;
713         }
714         return NULL;
715 }
716
717
718 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
719                                                                                         const char *oid_string)
720 {
721         const struct gensec_security_ops *ops;
722         ops = gensec_security_by_oid(gensec_security, oid_string);
723         if (ops) {
724                 return ops->name;
725         }
726         return oid_string;
727 }
728
729 /**
730  * Start a GENSEC sub-mechanism by OID, used in SPNEGO
731  *
732  * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
733  *       well-known #define to hook it in.
734  */
735
736 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
737                                   const char *mech_oid)
738 {
739         SMB_ASSERT(gensec_security != NULL);
740
741         gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
742         if (!gensec_security->ops) {
743                 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
744                 return NT_STATUS_INVALID_PARAMETER;
745         }
746         return gensec_start_mech(gensec_security);
747 }
748
749 /**
750  * Start a GENSEC sub-mechanism by a well know SASL name
751  *
752  */
753
754 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
755                                         const char *sasl_name)
756 {
757         gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
758         if (!gensec_security->ops) {
759                 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
760                 return NT_STATUS_INVALID_PARAMETER;
761         }
762         return gensec_start_mech(gensec_security);
763 }
764
765 /**
766  * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
767  *
768  */
769
770 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
771                                                  const char **sasl_names)
772 {
773         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
774         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
775         const struct gensec_security_ops **ops;
776         int i;
777         if (!mem_ctx) {
778                 return NT_STATUS_NO_MEMORY;
779         }
780         ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
781         if (!ops || !*ops) {
782                 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
783                           str_list_join(mem_ctx,
784                                         sasl_names, ' ')));
785                 talloc_free(mem_ctx);
786                 return NT_STATUS_INVALID_PARAMETER;
787         }
788         for (i=0; ops[i]; i++) {
789                 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
790                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
791                         break;
792                 }
793         }
794         talloc_free(mem_ctx);
795         return nt_status;
796 }
797
798 /**
799  * Start a GENSEC sub-mechanism by an internal name
800  *
801  */
802
803 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
804                                         const char *name)
805 {
806         gensec_security->ops = gensec_security_by_name(gensec_security, name);
807         if (!gensec_security->ops) {
808                 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
809                 return NT_STATUS_INVALID_PARAMETER;
810         }
811         return gensec_start_mech(gensec_security);
812 }
813
814 /**
815  * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
816  *
817  */
818
819 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
820 {
821         gensec_security->credentials = talloc_reference(gensec_security, credentials);
822         NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
823         gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
824         return NT_STATUS_OK;
825 }
826
827 NTSTATUS gensec_generate_session_info(TALLOC_CTX *mem_ctx,
828                                       struct gensec_security *gensec_security,
829                                       struct auth_user_info_dc *user_info_dc,
830                                       struct auth_session_info **session_info)
831 {
832         NTSTATUS nt_status;
833         uint32_t session_info_flags = 0;
834
835         if (gensec_security->want_features & GENSEC_FEATURE_UNIX_TOKEN) {
836                 session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN;
837         }
838
839         session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS;
840         if (user_info_dc->info->authenticated) {
841                 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
842         }
843
844         if (gensec_security->auth_context) {
845                 nt_status = gensec_security->auth_context->generate_session_info(mem_ctx, gensec_security->auth_context,
846                                                                                  user_info_dc,
847                                                                                  session_info_flags,
848                                                                                  session_info);
849         } else {
850                 session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
851                 nt_status = auth_generate_session_info(mem_ctx,
852                                                        NULL,
853                                                        NULL,
854                                                        user_info_dc, session_info_flags,
855                                                        session_info);
856         }
857         return nt_status;
858 }
859
860 /*
861   register a GENSEC backend.
862
863   The 'name' can be later used by other backends to find the operations
864   structure for this backend.
865 */
866 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
867 {
868         if (gensec_security_by_name(NULL, ops->name) != NULL) {
869                 /* its already registered! */
870                 DEBUG(0,("GENSEC backend '%s' already registered\n",
871                          ops->name));
872                 return NT_STATUS_OBJECT_NAME_COLLISION;
873         }
874
875         generic_security_ops = talloc_realloc(talloc_autofree_context(),
876                                               generic_security_ops,
877                                               struct gensec_security_ops *,
878                                               gensec_num_backends+2);
879         if (!generic_security_ops) {
880                 return NT_STATUS_NO_MEMORY;
881         }
882
883         generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
884         gensec_num_backends++;
885         generic_security_ops[gensec_num_backends] = NULL;
886
887         DEBUG(3,("GENSEC backend '%s' registered\n",
888                  ops->name));
889
890         return NT_STATUS_OK;
891 }
892
893 /*
894   return the GENSEC interface version, and the size of some critical types
895   This can be used by backends to either detect compilation errors, or provide
896   multiple implementations for different smbd compilation options in one module
897 */
898 const struct gensec_critical_sizes *gensec_interface_version(void)
899 {
900         static const struct gensec_critical_sizes critical_sizes = {
901                 GENSEC_INTERFACE_VERSION,
902                 sizeof(struct gensec_security_ops),
903                 sizeof(struct gensec_security),
904         };
905
906         return &critical_sizes;
907 }
908
909 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
910         return (*gs2)->priority - (*gs1)->priority;
911 }
912
913 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
914 {
915         return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
916 }
917
918 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
919 {
920         return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
921 }
922
923 /*
924   initialise the GENSEC subsystem
925 */
926 _PUBLIC_ NTSTATUS gensec_init(void)
927 {
928         static bool initialized = false;
929 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
930         STATIC_gensec_MODULES_PROTO;
931         init_module_fn static_init[] = { STATIC_gensec_MODULES };
932         init_module_fn *shared_init;
933
934         if (initialized) return NT_STATUS_OK;
935         initialized = true;
936
937         shared_init = load_samba_modules(NULL, "gensec");
938
939         run_init_functions(static_init);
940         run_init_functions(shared_init);
941
942         talloc_free(shared_init);
943
944         TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
945
946         return NT_STATUS_OK;
947 }