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