s4:gensec: pass down want_features to the spnego backend mech
[kai/samba.git] / source4 / auth / gensec / gensec.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 "auth/auth.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "auth/credentials/credentials.h"
28 #include "auth/gensec/gensec.h"
29 #include "auth/gensec/gensec_proto.h"
30 #include "param/param.h"
31
32 /* the list of currently registered GENSEC backends */
33 static struct gensec_security_ops **generic_security_ops;
34 static int gensec_num_backends;
35
36 /* Return all the registered mechs.  Don't modify the return pointer,
37  * but you may talloc_reference it if convient */
38 _PUBLIC_ struct gensec_security_ops **gensec_security_all(void)
39 {
40         return generic_security_ops;
41 }
42
43 /* Sometimes we want to force only kerberos, sometimes we want to
44  * force it's avoidance.  The old list could be either
45  * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
46  * an existing list we have trimmed down) */
47
48 _PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx, 
49                                                        struct gensec_security_ops **old_gensec_list, 
50                                                        struct cli_credentials *creds)
51 {
52         struct gensec_security_ops **new_gensec_list;
53         int i, j, num_mechs_in;
54         enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
55
56         if (creds) {
57                 use_kerberos = cli_credentials_get_kerberos_state(creds);
58         }
59
60         if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
61                 if (!talloc_reference(mem_ctx, old_gensec_list)) {
62                         return NULL;
63                 }
64                 return old_gensec_list;
65         }
66
67         for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
68                 /* noop */
69         }
70
71         new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
72         if (!new_gensec_list) {
73                 return NULL;
74         }
75
76         j = 0;
77         for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
78                 int oid_idx;
79                 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
80                         if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
81                                 new_gensec_list[j] = old_gensec_list[i];
82                                 j++;
83                                 break;
84                         }
85                 }
86                 switch (use_kerberos) {
87                 case CRED_DONT_USE_KERBEROS:
88                         if (old_gensec_list[i]->kerberos == false) {
89                                 new_gensec_list[j] = old_gensec_list[i];
90                                 j++;
91                         }
92                         break;
93                 case CRED_MUST_USE_KERBEROS:
94                         if (old_gensec_list[i]->kerberos == true) {
95                                 new_gensec_list[j] = old_gensec_list[i];
96                                 j++;
97                         }
98                         break;
99                 default:
100                         /* Can't happen or invalid parameter */
101                         return NULL;
102                 }
103         }
104         new_gensec_list[j] = NULL; 
105         
106         return new_gensec_list;
107 }
108
109 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
110                                                    TALLOC_CTX *mem_ctx) 
111 {
112         struct gensec_security_ops **backends;
113         backends = gensec_security_all();
114         if (!gensec_security) {
115                 if (!talloc_reference(mem_ctx, backends)) {
116                         return NULL;
117                 }
118                 return backends;
119         } else {
120                 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
121                 if (!creds) {
122                         if (!talloc_reference(mem_ctx, backends)) {
123                                 return NULL;
124                         }
125                         return backends;
126                 }
127                 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
128         }
129 }
130
131 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
132                                                                      uint8_t auth_type)
133 {
134         int i;
135         struct gensec_security_ops **backends;
136         const struct gensec_security_ops *backend;
137         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
138         if (!mem_ctx) {
139                 return NULL;
140         }
141         backends = gensec_security_mechs(gensec_security, mem_ctx);
142         for (i=0; backends && backends[i]; i++) {
143                 if (backends[i]->auth_type == auth_type) {
144                         backend = backends[i];
145                         talloc_free(mem_ctx);
146                         return backend;
147                 }
148         }
149         talloc_free(mem_ctx);
150
151         return NULL;
152 }
153
154 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
155                                                          const char *oid_string)
156 {
157         int i, j;
158         struct gensec_security_ops **backends;
159         const struct gensec_security_ops *backend;
160         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
161         if (!mem_ctx) {
162                 return NULL;
163         }
164         backends = gensec_security_mechs(gensec_security, mem_ctx);
165         for (i=0; backends && backends[i]; i++) {
166                 if (backends[i]->oid) {
167                         for (j=0; backends[i]->oid[j]; j++) { 
168                                 if (backends[i]->oid[j] &&
169                                     (strcmp(backends[i]->oid[j], oid_string) == 0)) {
170                                         backend = backends[i];
171                                         talloc_free(mem_ctx);
172                                         return backend;
173                                 }
174                         }
175                 }
176         }
177         talloc_free(mem_ctx);
178
179         return NULL;
180 }
181
182 const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
183                                                                const char *sasl_name)
184 {
185         int i;
186         struct gensec_security_ops **backends;
187         const struct gensec_security_ops *backend;
188         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
189         if (!mem_ctx) {
190                 return NULL;
191         }
192         backends = gensec_security_mechs(gensec_security, mem_ctx);
193         for (i=0; backends && backends[i]; i++) {
194                 if (backends[i]->sasl_name 
195                     && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
196                         backend = backends[i];
197                         talloc_free(mem_ctx);
198                         return backend;
199                 }
200         }
201         talloc_free(mem_ctx);
202
203         return NULL;
204 }
205
206 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
207                                                                  const char *name)
208 {
209         int i;
210         struct gensec_security_ops **backends;
211         const struct gensec_security_ops *backend;
212         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
213         if (!mem_ctx) {
214                 return NULL;
215         }
216         backends = gensec_security_mechs(gensec_security, mem_ctx);
217         for (i=0; backends && backends[i]; i++) {
218                 if (backends[i]->name 
219                     && (strcmp(backends[i]->name, name) == 0)) {
220                         backend = backends[i];
221                         talloc_free(mem_ctx);
222                         return backend;
223                 }
224         }
225         talloc_free(mem_ctx);
226         return NULL;
227 }
228
229 /**
230  * Return a unique list of security subsystems from those specified in
231  * the list of SASL names.   
232  *
233  * Use the list of enabled GENSEC mechanisms from the credentials
234  * attached to the gensec_security, and return in our preferred order.
235  */
236
237 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
238                                                                 TALLOC_CTX *mem_ctx, 
239                                                                 const char **sasl_names)
240 {
241         const struct gensec_security_ops **backends_out;
242         struct gensec_security_ops **backends;
243         int i, k, sasl_idx;
244         int num_backends_out = 0;
245
246         if (!sasl_names) {
247                 return NULL;
248         }
249
250         backends = gensec_security_mechs(gensec_security, mem_ctx);
251
252         backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
253         if (!backends_out) {
254                 return NULL;
255         }
256         backends_out[0] = NULL;
257
258         /* Find backends in our preferred order, by walking our list,
259          * then looking in the supplied list */
260         for (i=0; backends && backends[i]; i++) {
261                 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
262                         if (!backends[i]->sasl_name ||
263                             !(strcmp(backends[i]->sasl_name, 
264                                      sasl_names[sasl_idx]) == 0)) {
265                                 continue;
266                         }
267                         
268                         for (k=0; backends_out[k]; k++) {
269                                 if (backends_out[k] == backends[i]) {
270                                         break;
271                                 }
272                         }
273                         
274                         if (k < num_backends_out) {
275                                 /* already in there */
276                                 continue;
277                         }
278                         
279                         backends_out = talloc_realloc(mem_ctx, backends_out, 
280                                                       const struct gensec_security_ops *, 
281                                                       num_backends_out + 2);
282                         if (!backends_out) {
283                                 return NULL;
284                         }
285                         
286                         backends_out[num_backends_out] = backends[i];
287                         num_backends_out++;
288                         backends_out[num_backends_out] = NULL;
289                 }
290         }
291         return backends_out;
292 }
293
294 /**
295  * Return a unique list of security subsystems from those specified in
296  * the OID list.  That is, where two OIDs refer to the same module,
297  * return that module only once. 
298  *
299  * Use the list of enabled GENSEC mechanisms from the credentials
300  * attached to the gensec_security, and return in our preferred order.
301  */
302
303 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
304                                                                       TALLOC_CTX *mem_ctx, 
305                                                                       const char **oid_strings,
306                                                                       const char *skip)
307 {
308         struct gensec_security_ops_wrapper *backends_out;
309         struct gensec_security_ops **backends;
310         int i, j, k, oid_idx;
311         int num_backends_out = 0;
312
313         if (!oid_strings) {
314                 return NULL;
315         }
316
317         backends = gensec_security_mechs(gensec_security, gensec_security);
318
319         backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
320         if (!backends_out) {
321                 return NULL;
322         }
323         backends_out[0].op = NULL;
324         backends_out[0].oid = NULL;
325
326         /* Find backends in our preferred order, by walking our list,
327          * then looking in the supplied list */
328         for (i=0; backends && backends[i]; i++) {
329                 if (!backends[i]->oid) {
330                         continue;
331                 }
332                 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
333                         if (strcmp(oid_strings[oid_idx], skip) == 0) {
334                                 continue;
335                         }
336
337                         for (j=0; backends[i]->oid[j]; j++) { 
338                                 if (!backends[i]->oid[j] ||
339                                     !(strcmp(backends[i]->oid[j], 
340                                             oid_strings[oid_idx]) == 0)) {
341                                         continue;
342                                 }
343                                 
344                                 for (k=0; backends_out[k].op; k++) {
345                                         if (backends_out[k].op == backends[i]) {
346                                                 break;
347                                         }
348                                 }
349                                 
350                                 if (k < num_backends_out) {
351                                         /* already in there */
352                                         continue;
353                                 }
354
355                                 backends_out = talloc_realloc(mem_ctx, backends_out, 
356                                                               struct gensec_security_ops_wrapper, 
357                                                               num_backends_out + 2);
358                                 if (!backends_out) {
359                                         return NULL;
360                                 }
361                                 
362                                 backends_out[num_backends_out].op = backends[i];
363                                 backends_out[num_backends_out].oid = backends[i]->oid[j];
364                                 num_backends_out++;
365                                 backends_out[num_backends_out].op = NULL;
366                                 backends_out[num_backends_out].oid = NULL;
367                         }
368                 }
369         }
370         return backends_out;
371 }
372
373 /**
374  * Return OIDS from the security subsystems listed
375  */
376
377 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx, 
378                                            struct gensec_security_ops **ops,                               
379                                            const char *skip) 
380 {
381         int i;
382         int j = 0;
383         int k;
384         const char **oid_list;
385         if (!ops) {
386                 return NULL;
387         }
388         oid_list = talloc_array(mem_ctx, const char *, 1);
389         if (!oid_list) {
390                 return NULL;
391         }
392         
393         for (i=0; ops && ops[i]; i++) {
394                 if (!ops[i]->oid) {
395                         continue;
396                 }
397                 
398                 for (k = 0; ops[i]->oid[k]; k++) {
399                         if (skip && strcmp(skip, ops[i]->oid[k])==0) {
400                         } else {
401                                 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
402                                 if (!oid_list) {
403                                         return NULL;
404                                 }
405                                 oid_list[j] = ops[i]->oid[k];
406                                 j++;
407                         }
408                 }
409         }
410         oid_list[j] = NULL;
411         return oid_list;
412 }
413
414
415 /**
416  * Return OIDS from the security subsystems listed
417  */
418
419 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx, 
420                                                    const struct gensec_security_ops_wrapper *wops)
421 {
422         int i;
423         int j = 0;
424         int k;
425         const char **oid_list;
426         if (!wops) {
427                 return NULL;
428         }
429         oid_list = talloc_array(mem_ctx, const char *, 1);
430         if (!oid_list) {
431                 return NULL;
432         }
433         
434         for (i=0; wops[i].op; i++) {
435                 if (!wops[i].op->oid) {
436                         continue;
437                 }
438                 
439                 for (k = 0; wops[i].op->oid[k]; k++) {
440                         oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
441                         if (!oid_list) {
442                                 return NULL;
443                         }
444                         oid_list[j] = wops[i].op->oid[k];
445                         j++;
446                 }
447         }
448         oid_list[j] = NULL;
449         return oid_list;
450 }
451
452
453 /**
454  * Return all the security subsystems currently enabled on a GENSEC context.
455  * 
456  * This is taken from a list attached to the cli_credentials, and
457  * skips the OID in 'skip'.  (Typically the SPNEGO OID)
458  * 
459  */
460
461 const char **gensec_security_oids(struct gensec_security *gensec_security, 
462                                   TALLOC_CTX *mem_ctx, 
463                                   const char *skip) 
464 {
465         struct gensec_security_ops **ops
466                 = gensec_security_mechs(gensec_security, mem_ctx);
467         return gensec_security_oids_from_ops(mem_ctx, ops, skip);
468 }
469
470
471
472 /**
473   Start the GENSEC system, returning a context pointer.
474   @param mem_ctx The parent TALLOC memory context.
475   @param gensec_security Returned GENSEC context pointer.
476   @note  The mem_ctx is only a parent and may be NULL.
477 */
478 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, 
479                              struct event_context *ev,
480                              struct loadparm_context *lp_ctx,
481                              struct messaging_context *msg,
482                              struct gensec_security **gensec_security)
483 {
484         if (ev == NULL) {
485                 DEBUG(0, ("No event context available!\n"));
486                 return NT_STATUS_INTERNAL_ERROR;
487         }
488
489         (*gensec_security) = talloc(mem_ctx, struct gensec_security);
490         NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
491
492         (*gensec_security)->ops = NULL;
493         (*gensec_security)->private_data = NULL;
494
495         ZERO_STRUCT((*gensec_security)->target);
496         ZERO_STRUCT((*gensec_security)->peer_addr);
497         ZERO_STRUCT((*gensec_security)->my_addr);
498
499         (*gensec_security)->subcontext = false;
500         (*gensec_security)->want_features = 0;
501
502         (*gensec_security)->event_ctx = ev;
503         (*gensec_security)->msg_ctx = msg;
504         (*gensec_security)->lp_ctx = lp_ctx;
505
506         return NT_STATUS_OK;
507 }
508
509 /** 
510  * Start a GENSEC subcontext, with a copy of the properties of the parent
511  * @param mem_ctx The parent TALLOC memory context.
512  * @param parent The parent GENSEC context 
513  * @param gensec_security Returned GENSEC context pointer.
514  * @note Used by SPNEGO in particular, for the actual implementation mechanism
515  */
516
517 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx, 
518                                  struct gensec_security *parent, 
519                                  struct gensec_security **gensec_security)
520 {
521         (*gensec_security) = talloc(mem_ctx, struct gensec_security);
522         NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
523
524         (**gensec_security) = *parent;
525         (*gensec_security)->ops = NULL;
526         (*gensec_security)->private_data = NULL;
527
528         (*gensec_security)->subcontext = true;
529         (*gensec_security)->want_features = parent->want_features;
530         (*gensec_security)->event_ctx = parent->event_ctx;
531         (*gensec_security)->msg_ctx = parent->msg_ctx;
532         (*gensec_security)->lp_ctx = parent->lp_ctx;
533
534         return NT_STATUS_OK;
535 }
536
537 /**
538   Start the GENSEC system, in client mode, returning a context pointer.
539   @param mem_ctx The parent TALLOC memory context.
540   @param gensec_security Returned GENSEC context pointer.
541   @note  The mem_ctx is only a parent and may be NULL.
542 */
543 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, 
544                              struct gensec_security **gensec_security,
545                              struct event_context *ev,
546                              struct loadparm_context *lp_ctx)
547 {
548         NTSTATUS status;
549
550         status = gensec_start(mem_ctx, ev, lp_ctx, NULL, gensec_security);
551         if (!NT_STATUS_IS_OK(status)) {
552                 return status;
553         }
554         (*gensec_security)->gensec_role = GENSEC_CLIENT;
555
556         return status;
557 }
558
559 /**
560   Start the GENSEC system, in server mode, returning a context pointer.
561   @param mem_ctx The parent TALLOC memory context.
562   @param gensec_security Returned GENSEC context pointer.
563   @note  The mem_ctx is only a parent and may be NULL.
564 */
565 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, 
566                              struct event_context *ev,
567                              struct loadparm_context *lp_ctx,
568                              struct messaging_context *msg,
569                              struct gensec_security **gensec_security)
570 {
571         NTSTATUS status;
572
573         if (!ev) {
574                 DEBUG(0,("gensec_server_start: no event context given!\n"));
575                 return NT_STATUS_INTERNAL_ERROR;
576         }
577
578         if (!msg) {
579                 DEBUG(0,("gensec_server_start: no messaging context given!\n"));
580                 return NT_STATUS_INTERNAL_ERROR;
581         }
582
583         status = gensec_start(mem_ctx, ev, lp_ctx, msg, gensec_security);
584         if (!NT_STATUS_IS_OK(status)) {
585                 return status;
586         }
587         (*gensec_security)->gensec_role = GENSEC_SERVER;
588
589         return status;
590 }
591
592 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security) 
593 {
594         NTSTATUS status;
595         DEBUG(5, ("Starting GENSEC %smechanism %s\n", 
596                   gensec_security->subcontext ? "sub" : "", 
597                   gensec_security->ops->name));
598         switch (gensec_security->gensec_role) {
599         case GENSEC_CLIENT:
600                 if (gensec_security->ops->client_start) {
601                         status = gensec_security->ops->client_start(gensec_security);
602                         if (!NT_STATUS_IS_OK(status)) {
603                                 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
604                                           gensec_security->ops->name, nt_errstr(status))); 
605                         }
606                         return status;
607                 }
608                 break;
609         case GENSEC_SERVER:
610                 if (gensec_security->ops->server_start) {
611                         status = gensec_security->ops->server_start(gensec_security);
612                         if (!NT_STATUS_IS_OK(status)) {
613                                 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
614                                           gensec_security->ops->name, nt_errstr(status))); 
615                         }
616                         return status;
617                 }
618                 break;
619         }
620         return NT_STATUS_INVALID_PARAMETER;
621 }
622
623 /** 
624  * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number 
625  * @param gensec_security GENSEC context pointer.
626  * @param auth_type DCERPC auth type
627  * @param auth_level DCERPC auth level 
628  */
629
630 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security, 
631                                        uint8_t auth_type, uint8_t auth_level) 
632 {
633         gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
634         if (!gensec_security->ops) {
635                 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
636                 return NT_STATUS_INVALID_PARAMETER;
637         }
638         gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
639         gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
640         if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
641                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
642         } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
643                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
644                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
645         } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
646                 /* Default features */
647         } else {
648                 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n", 
649                          auth_level));
650                 return NT_STATUS_INVALID_PARAMETER;
651         }
652
653         return gensec_start_mech(gensec_security);
654 }
655
656 _PUBLIC_ const char *gensec_get_name_by_authtype(uint8_t authtype) 
657 {
658         const struct gensec_security_ops *ops;
659         ops = gensec_security_by_authtype(NULL, authtype);
660         if (ops) {
661                 return ops->name;
662         }
663         return NULL;
664 }
665         
666
667 _PUBLIC_ const char *gensec_get_name_by_oid(const char *oid_string) 
668 {
669         const struct gensec_security_ops *ops;
670         ops = gensec_security_by_oid(NULL, oid_string);
671         if (ops) {
672                 return ops->name;
673         }
674         return oid_string;
675 }
676         
677
678 /** 
679  * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
680  *
681  */
682
683 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security, 
684                                   const struct gensec_security_ops *ops) 
685 {
686         gensec_security->ops = ops;
687         return gensec_start_mech(gensec_security);
688 }
689
690 /** 
691  * Start a GENSEC sub-mechanism by OID, used in SPNEGO
692  *
693  * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
694  *       well-known #define to hook it in.
695  */
696
697 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security, 
698                                   const char *mech_oid) 
699 {
700         gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
701         if (!gensec_security->ops) {
702                 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
703                 return NT_STATUS_INVALID_PARAMETER;
704         }
705         return gensec_start_mech(gensec_security);
706 }
707
708 /** 
709  * Start a GENSEC sub-mechanism by a well know SASL name
710  *
711  */
712
713 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security, 
714                                         const char *sasl_name) 
715 {
716         gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
717         if (!gensec_security->ops) {
718                 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
719                 return NT_STATUS_INVALID_PARAMETER;
720         }
721         return gensec_start_mech(gensec_security);
722 }
723
724 /** 
725  * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
726  *
727  */
728
729 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security, 
730                                                  const char **sasl_names) 
731 {
732         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
733         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
734         const struct gensec_security_ops **ops;
735         int i;
736         if (!mem_ctx) {
737                 return NT_STATUS_NO_MEMORY;
738         }
739         ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
740         if (!ops || !*ops) {
741                 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n", 
742                           str_list_join(mem_ctx, 
743                                         sasl_names, ' ')));
744                 talloc_free(mem_ctx);
745                 return NT_STATUS_INVALID_PARAMETER;
746         }
747         for (i=0; ops[i]; i++) {
748                 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
749                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
750                         break;
751                 }
752         }
753         talloc_free(mem_ctx);
754         return nt_status;
755 }
756
757 /** 
758  * Start a GENSEC sub-mechanism by an internal name
759  *
760  */
761
762 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security, 
763                                         const char *name) 
764 {
765         gensec_security->ops = gensec_security_by_name(gensec_security, name);
766         if (!gensec_security->ops) {
767                 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
768                 return NT_STATUS_INVALID_PARAMETER;
769         }
770         return gensec_start_mech(gensec_security);
771 }
772
773 /*
774   wrappers for the gensec function pointers
775 */
776 _PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security, 
777                               TALLOC_CTX *mem_ctx, 
778                               uint8_t *data, size_t length, 
779                               const uint8_t *whole_pdu, size_t pdu_length, 
780                               const DATA_BLOB *sig)
781 {
782         if (!gensec_security->ops->unseal_packet) {
783                 return NT_STATUS_NOT_IMPLEMENTED;
784         }
785         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
786                 return NT_STATUS_INVALID_PARAMETER;
787         }
788         
789         return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, 
790                                                    data, length, 
791                                                    whole_pdu, pdu_length, 
792                                                    sig);
793 }
794
795 _PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security, 
796                              TALLOC_CTX *mem_ctx, 
797                              const uint8_t *data, size_t length, 
798                              const uint8_t *whole_pdu, size_t pdu_length, 
799                              const DATA_BLOB *sig)
800 {
801         if (!gensec_security->ops->check_packet) {
802                 return NT_STATUS_NOT_IMPLEMENTED;
803         }
804         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
805                 return NT_STATUS_INVALID_PARAMETER;
806         }
807         
808         return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
809 }
810
811 _PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security, 
812                             TALLOC_CTX *mem_ctx, 
813                             uint8_t *data, size_t length, 
814                             const uint8_t *whole_pdu, size_t pdu_length, 
815                             DATA_BLOB *sig)
816 {
817         if (!gensec_security->ops->seal_packet) {
818                 return NT_STATUS_NOT_IMPLEMENTED;
819         }
820         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
821                 return NT_STATUS_INVALID_PARAMETER;
822         }
823         
824         return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
825 }
826
827 _PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security, 
828                             TALLOC_CTX *mem_ctx, 
829                             const uint8_t *data, size_t length, 
830                             const uint8_t *whole_pdu, size_t pdu_length, 
831                             DATA_BLOB *sig)
832 {
833         if (!gensec_security->ops->sign_packet) {
834                 return NT_STATUS_NOT_IMPLEMENTED;
835         }
836         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
837                 return NT_STATUS_INVALID_PARAMETER;
838         }
839         
840         return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
841 }
842
843 _PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size) 
844 {
845         if (!gensec_security->ops->sig_size) {
846                 return 0;
847         }
848         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
849                 return 0;
850         }
851         
852         return gensec_security->ops->sig_size(gensec_security, data_size);
853 }
854
855 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security) 
856 {
857         if (!gensec_security->ops->max_wrapped_size) {
858                 return (1 << 17);
859         }
860         
861         return gensec_security->ops->max_wrapped_size(gensec_security);
862 }
863
864 size_t gensec_max_input_size(struct gensec_security *gensec_security) 
865 {
866         if (!gensec_security->ops->max_input_size) {
867                 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
868         }
869         
870         return gensec_security->ops->max_input_size(gensec_security);
871 }
872
873 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security, 
874                      TALLOC_CTX *mem_ctx, 
875                      const DATA_BLOB *in, 
876                      DATA_BLOB *out) 
877 {
878         if (!gensec_security->ops->wrap) {
879                 return NT_STATUS_NOT_IMPLEMENTED;
880         }
881         return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
882 }
883
884 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security, 
885                        TALLOC_CTX *mem_ctx, 
886                        const DATA_BLOB *in, 
887                        DATA_BLOB *out) 
888 {
889         if (!gensec_security->ops->unwrap) {
890                 return NT_STATUS_NOT_IMPLEMENTED;
891         }
892         return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
893 }
894
895 _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security, 
896                             DATA_BLOB *session_key)
897 {
898         if (!gensec_security->ops->session_key) {
899                 return NT_STATUS_NOT_IMPLEMENTED;
900         }
901         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
902                 return NT_STATUS_NO_USER_SESSION_KEY;
903         }
904         
905         return gensec_security->ops->session_key(gensec_security, session_key);
906 }
907
908 /** 
909  * Return the credentials of a logged on user, including session keys
910  * etc.
911  *
912  * Only valid after a successful authentication
913  *
914  * May only be called once per authentication.
915  *
916  */
917
918 _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security, 
919                              struct auth_session_info **session_info)
920 {
921         if (!gensec_security->ops->session_info) {
922                 return NT_STATUS_NOT_IMPLEMENTED;
923         }
924         return gensec_security->ops->session_info(gensec_security, session_info);
925 }
926
927 /**
928  * Next state function for the GENSEC state machine
929  * 
930  * @param gensec_security GENSEC State
931  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
932  * @param in The request, as a DATA_BLOB
933  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
934  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
935  *                or NT_STATUS_OK if the user is authenticated. 
936  */
937
938 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 
939                        const DATA_BLOB in, DATA_BLOB *out) 
940 {
941         return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
942 }
943
944 static void gensec_update_async_timed_handler(struct event_context *ev, struct timed_event *te,
945                                               struct timeval t, void *ptr)
946 {
947         struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
948         req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
949         req->callback.fn(req, req->callback.private_data);
950 }
951
952 /**
953  * Next state function for the GENSEC state machine async version
954  * 
955  * @param gensec_security GENSEC State
956  * @param in The request, as a DATA_BLOB
957  * @param callback The function that will be called when the operation is
958  *                 finished, it should return gensec_update_recv() to get output
959  * @param private_data A private pointer that will be passed to the callback function
960  */
961
962 _PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
963                                  void (*callback)(struct gensec_update_request *req, void *private_data),
964                                  void *private_data)
965 {
966         struct gensec_update_request *req = NULL;
967         struct timed_event *te = NULL;
968
969         req = talloc(gensec_security, struct gensec_update_request);
970         if (!req) goto failed;
971         req->gensec_security            = gensec_security;
972         req->in                         = in;
973         req->out                        = data_blob(NULL, 0);
974         req->callback.fn                = callback;
975         req->callback.private_data      = private_data;
976
977         te = event_add_timed(gensec_security->event_ctx, req,
978                              timeval_zero(),
979                              gensec_update_async_timed_handler, req);
980         if (!te) goto failed;
981
982         return;
983
984 failed:
985         talloc_free(req);
986         callback(NULL, private_data);
987 }
988
989 /**
990  * Next state function for the GENSEC state machine
991  * 
992  * @param req GENSEC update request state
993  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
994  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
995  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
996  *                or NT_STATUS_OK if the user is authenticated. 
997  */
998 _PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
999 {
1000         NTSTATUS status;
1001
1002         NT_STATUS_HAVE_NO_MEMORY(req);
1003
1004         *out = req->out;
1005         talloc_steal(out_mem_ctx, out->data);
1006         status = req->status;
1007
1008         talloc_free(req);
1009         return status;
1010 }
1011
1012 /** 
1013  * Set the requirement for a certain feature on the connection
1014  *
1015  */
1016
1017 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1018                          uint32_t feature) 
1019 {
1020         if (!gensec_security->ops || !gensec_security->ops->want_feature) {
1021                 gensec_security->want_features |= feature;
1022                 return;
1023         }
1024         gensec_security->ops->want_feature(gensec_security, feature);
1025 }
1026
1027 /** 
1028  * Check the requirement for a certain feature on the connection
1029  *
1030  */
1031
1032 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
1033                          uint32_t feature) 
1034 {
1035         if (!gensec_security->ops->have_feature) {
1036                 return false;
1037         }
1038         
1039         /* We might 'have' features that we don't 'want', because the
1040          * other end demanded them, or we can't neotiate them off */
1041         return gensec_security->ops->have_feature(gensec_security, feature);
1042 }
1043
1044 /** 
1045  * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context 
1046  *
1047  */
1048
1049 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials) 
1050 {
1051         gensec_security->credentials = talloc_reference(gensec_security, credentials);
1052         NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1053         gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1054         return NT_STATUS_OK;
1055 }
1056
1057 /** 
1058  * Return the credentials structure associated with a GENSEC context
1059  *
1060  */
1061
1062 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security) 
1063 {
1064         if (!gensec_security) {
1065                 return NULL;
1066         }
1067         return gensec_security->credentials;
1068 }
1069
1070 /** 
1071  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed 
1072  *
1073  */
1074
1075 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service) 
1076 {
1077         gensec_security->target.service = talloc_strdup(gensec_security, service);
1078         if (!gensec_security->target.service) {
1079                 return NT_STATUS_NO_MEMORY;
1080         }
1081         return NT_STATUS_OK;
1082 }
1083
1084 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security) 
1085 {
1086         if (gensec_security->target.service) {
1087                 return gensec_security->target.service;
1088         }
1089
1090         return "host";
1091 }
1092
1093 /** 
1094  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed 
1095  *
1096  */
1097
1098 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) 
1099 {
1100         gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1101         if (hostname && !gensec_security->target.hostname) {
1102                 return NT_STATUS_NO_MEMORY;
1103         }
1104         return NT_STATUS_OK;
1105 }
1106
1107 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security) 
1108 {
1109         /* We allow the target hostname to be overriden for testing purposes */
1110         const char *target_hostname = lp_parm_string(gensec_security->lp_ctx, NULL, "gensec", "target_hostname");
1111         if (target_hostname) {
1112                 return target_hostname;
1113         }
1114
1115         if (gensec_security->target.hostname) {
1116                 return gensec_security->target.hostname;
1117         }
1118
1119         /* We could add use the 'set sockaddr' call, and do a reverse
1120          * lookup, but this would be both insecure (compromising the
1121          * way kerberos works) and add DNS timeouts */
1122         return NULL;
1123 }
1124
1125 /** 
1126  * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context 
1127  *
1128  * This is so that kerberos can include these addresses in
1129  * cryptographic tokens, to avoid certain attacks.
1130  */
1131
1132 _PUBLIC_ NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr) 
1133 {
1134         gensec_security->my_addr = my_addr;
1135         if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1136                 return NT_STATUS_NO_MEMORY;
1137         }
1138         return NT_STATUS_OK;
1139 }
1140
1141 _PUBLIC_ NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr) 
1142 {
1143         gensec_security->peer_addr = peer_addr;
1144         if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1145                 return NT_STATUS_NO_MEMORY;
1146         }
1147         return NT_STATUS_OK;
1148 }
1149
1150 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security) 
1151 {
1152         if (gensec_security->my_addr) {
1153                 return gensec_security->my_addr;
1154         }
1155
1156         /* We could add a 'set sockaddr' call, and do a lookup.  This
1157          * would avoid needing to do system calls if nothing asks. */
1158         return NULL;
1159 }
1160
1161 _PUBLIC_ struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security) 
1162 {
1163         if (gensec_security->peer_addr) {
1164                 return gensec_security->peer_addr;
1165         }
1166
1167         /* We could add a 'set sockaddr' call, and do a lookup.  This
1168          * would avoid needing to do system calls if nothing asks.
1169          * However, this is not appropriate for the peer addres on
1170          * datagram sockets */
1171         return NULL;
1172 }
1173
1174
1175
1176 /** 
1177  * Set the target principal (assuming it it known, say from the SPNEGO reply)
1178  *  - ensures it is talloc()ed 
1179  *
1180  */
1181
1182 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal) 
1183 {
1184         gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1185         if (!gensec_security->target.principal) {
1186                 return NT_STATUS_NO_MEMORY;
1187         }
1188         return NT_STATUS_OK;
1189 }
1190
1191 const char *gensec_get_target_principal(struct gensec_security *gensec_security) 
1192 {
1193         if (gensec_security->target.principal) {
1194                 return gensec_security->target.principal;
1195         }
1196
1197         return NULL;
1198 }
1199
1200 /*
1201   register a GENSEC backend. 
1202
1203   The 'name' can be later used by other backends to find the operations
1204   structure for this backend.
1205 */
1206 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1207 {
1208         if (!lp_parm_bool(global_loadparm, NULL, "gensec", ops->name, ops->enabled)) {
1209                 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1210                 return NT_STATUS_OK;
1211         }
1212
1213         if (gensec_security_by_name(NULL, ops->name) != NULL) {
1214                 /* its already registered! */
1215                 DEBUG(0,("GENSEC backend '%s' already registered\n", 
1216                          ops->name));
1217                 return NT_STATUS_OBJECT_NAME_COLLISION;
1218         }
1219
1220         generic_security_ops = talloc_realloc(talloc_autofree_context(), 
1221                                               generic_security_ops, 
1222                                               struct gensec_security_ops *, 
1223                                               gensec_num_backends+2);
1224         if (!generic_security_ops) {
1225                 return NT_STATUS_NO_MEMORY;
1226         }
1227
1228         generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1229         gensec_num_backends++;
1230         generic_security_ops[gensec_num_backends] = NULL;
1231
1232         DEBUG(3,("GENSEC backend '%s' registered\n", 
1233                  ops->name));
1234
1235         return NT_STATUS_OK;
1236 }
1237
1238 /*
1239   return the GENSEC interface version, and the size of some critical types
1240   This can be used by backends to either detect compilation errors, or provide
1241   multiple implementations for different smbd compilation options in one module
1242 */
1243 const struct gensec_critical_sizes *gensec_interface_version(void)
1244 {
1245         static const struct gensec_critical_sizes critical_sizes = {
1246                 GENSEC_INTERFACE_VERSION,
1247                 sizeof(struct gensec_security_ops),
1248                 sizeof(struct gensec_security),
1249         };
1250
1251         return &critical_sizes;
1252 }
1253
1254 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1255         return (*gs2)->priority - (*gs1)->priority;
1256 }
1257
1258 /*
1259   initialise the GENSEC subsystem
1260 */
1261 _PUBLIC_ NTSTATUS gensec_init(struct loadparm_context *lp_ctx)
1262 {
1263         static bool initialized = false;
1264         extern NTSTATUS gensec_sasl_init(void);
1265         extern NTSTATUS gensec_krb5_init(void);
1266         extern NTSTATUS gensec_schannel_init(void);
1267         extern NTSTATUS gensec_spnego_init(void);
1268         extern NTSTATUS gensec_gssapi_init(void);
1269         extern NTSTATUS gensec_ntlmssp_init(void);
1270
1271         init_module_fn static_init[] = { STATIC_gensec_MODULES };
1272         init_module_fn *shared_init;
1273
1274         if (initialized) return NT_STATUS_OK;
1275         initialized = true;
1276         
1277         shared_init = load_samba_modules(NULL, lp_ctx, "gensec");
1278
1279         run_init_functions(static_init);
1280         run_init_functions(shared_init);
1281
1282         talloc_free(shared_init);
1283
1284         qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1285         
1286         return NT_STATUS_OK;
1287 }