0edb34d7403fc7d048314ac3d005bf2128bb202f
[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
494         ZERO_STRUCT((*gensec_security)->target);
495         ZERO_STRUCT((*gensec_security)->peer_addr);
496         ZERO_STRUCT((*gensec_security)->my_addr);
497
498         (*gensec_security)->subcontext = false;
499         (*gensec_security)->want_features = 0;
500
501         (*gensec_security)->event_ctx = ev;
502         (*gensec_security)->msg_ctx = msg;
503         (*gensec_security)->lp_ctx = lp_ctx;
504
505         return NT_STATUS_OK;
506 }
507
508 /** 
509  * Start a GENSEC subcontext, with a copy of the properties of the parent
510  * @param mem_ctx The parent TALLOC memory context.
511  * @param parent The parent GENSEC context 
512  * @param gensec_security Returned GENSEC context pointer.
513  * @note Used by SPNEGO in particular, for the actual implementation mechanism
514  */
515
516 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx, 
517                                  struct gensec_security *parent, 
518                                  struct gensec_security **gensec_security)
519 {
520         (*gensec_security) = talloc(mem_ctx, struct gensec_security);
521         NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
522
523         (**gensec_security) = *parent;
524         (*gensec_security)->ops = NULL;
525         (*gensec_security)->private_data = NULL;
526
527         (*gensec_security)->subcontext = true;
528         (*gensec_security)->event_ctx = parent->event_ctx;
529         (*gensec_security)->msg_ctx = parent->msg_ctx;
530         (*gensec_security)->lp_ctx = parent->lp_ctx;
531
532         return NT_STATUS_OK;
533 }
534
535 /**
536   Start the GENSEC system, in client mode, returning a context pointer.
537   @param mem_ctx The parent TALLOC memory context.
538   @param gensec_security Returned GENSEC context pointer.
539   @note  The mem_ctx is only a parent and may be NULL.
540 */
541 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, 
542                              struct gensec_security **gensec_security,
543                              struct event_context *ev,
544                              struct loadparm_context *lp_ctx)
545 {
546         NTSTATUS status;
547
548         status = gensec_start(mem_ctx, ev, lp_ctx, NULL, gensec_security);
549         if (!NT_STATUS_IS_OK(status)) {
550                 return status;
551         }
552         (*gensec_security)->gensec_role = GENSEC_CLIENT;
553
554         return status;
555 }
556
557 /**
558   Start the GENSEC system, in server mode, returning a context pointer.
559   @param mem_ctx The parent TALLOC memory context.
560   @param gensec_security Returned GENSEC context pointer.
561   @note  The mem_ctx is only a parent and may be NULL.
562 */
563 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, 
564                              struct event_context *ev,
565                              struct loadparm_context *lp_ctx,
566                              struct messaging_context *msg,
567                              struct gensec_security **gensec_security)
568 {
569         NTSTATUS status;
570
571         if (!ev) {
572                 DEBUG(0,("gensec_server_start: no event context given!\n"));
573                 return NT_STATUS_INTERNAL_ERROR;
574         }
575
576         if (!msg) {
577                 DEBUG(0,("gensec_server_start: no messaging context given!\n"));
578                 return NT_STATUS_INTERNAL_ERROR;
579         }
580
581         status = gensec_start(mem_ctx, ev, lp_ctx, msg, gensec_security);
582         if (!NT_STATUS_IS_OK(status)) {
583                 return status;
584         }
585         (*gensec_security)->gensec_role = GENSEC_SERVER;
586
587         return status;
588 }
589
590 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security) 
591 {
592         NTSTATUS status;
593         DEBUG(5, ("Starting GENSEC %smechanism %s\n", 
594                   gensec_security->subcontext ? "sub" : "", 
595                   gensec_security->ops->name));
596         switch (gensec_security->gensec_role) {
597         case GENSEC_CLIENT:
598                 if (gensec_security->ops->client_start) {
599                         status = gensec_security->ops->client_start(gensec_security);
600                         if (!NT_STATUS_IS_OK(status)) {
601                                 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
602                                           gensec_security->ops->name, nt_errstr(status))); 
603                         }
604                         return status;
605                 }
606                 break;
607         case GENSEC_SERVER:
608                 if (gensec_security->ops->server_start) {
609                         status = gensec_security->ops->server_start(gensec_security);
610                         if (!NT_STATUS_IS_OK(status)) {
611                                 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
612                                           gensec_security->ops->name, nt_errstr(status))); 
613                         }
614                         return status;
615                 }
616                 break;
617         }
618         return NT_STATUS_INVALID_PARAMETER;
619 }
620
621 /** 
622  * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number 
623  * @param gensec_security GENSEC context pointer.
624  * @param auth_type DCERPC auth type
625  * @param auth_level DCERPC auth level 
626  */
627
628 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security, 
629                                        uint8_t auth_type, uint8_t auth_level) 
630 {
631         gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
632         if (!gensec_security->ops) {
633                 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
634                 return NT_STATUS_INVALID_PARAMETER;
635         }
636         gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
637         gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
638         if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
639                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
640         } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
641                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
642                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
643         } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
644                 /* Default features */
645         } else {
646                 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n", 
647                          auth_level));
648                 return NT_STATUS_INVALID_PARAMETER;
649         }
650
651         return gensec_start_mech(gensec_security);
652 }
653
654 _PUBLIC_ const char *gensec_get_name_by_authtype(uint8_t authtype) 
655 {
656         const struct gensec_security_ops *ops;
657         ops = gensec_security_by_authtype(NULL, authtype);
658         if (ops) {
659                 return ops->name;
660         }
661         return NULL;
662 }
663         
664
665 _PUBLIC_ const char *gensec_get_name_by_oid(const char *oid_string) 
666 {
667         const struct gensec_security_ops *ops;
668         ops = gensec_security_by_oid(NULL, oid_string);
669         if (ops) {
670                 return ops->name;
671         }
672         return oid_string;
673 }
674         
675
676 /** 
677  * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
678  *
679  */
680
681 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security, 
682                                   const struct gensec_security_ops *ops) 
683 {
684         gensec_security->ops = ops;
685         return gensec_start_mech(gensec_security);
686 }
687
688 /** 
689  * Start a GENSEC sub-mechanism by OID, used in SPNEGO
690  *
691  * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
692  *       well-known #define to hook it in.
693  */
694
695 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security, 
696                                   const char *mech_oid) 
697 {
698         gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
699         if (!gensec_security->ops) {
700                 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
701                 return NT_STATUS_INVALID_PARAMETER;
702         }
703         return gensec_start_mech(gensec_security);
704 }
705
706 /** 
707  * Start a GENSEC sub-mechanism by a well know SASL name
708  *
709  */
710
711 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security, 
712                                         const char *sasl_name) 
713 {
714         gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
715         if (!gensec_security->ops) {
716                 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
717                 return NT_STATUS_INVALID_PARAMETER;
718         }
719         return gensec_start_mech(gensec_security);
720 }
721
722 /** 
723  * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
724  *
725  */
726
727 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security, 
728                                                  const char **sasl_names) 
729 {
730         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
731         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
732         const struct gensec_security_ops **ops;
733         int i;
734         if (!mem_ctx) {
735                 return NT_STATUS_NO_MEMORY;
736         }
737         ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
738         if (!ops || !*ops) {
739                 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n", 
740                           str_list_join(mem_ctx, 
741                                         sasl_names, ' ')));
742                 talloc_free(mem_ctx);
743                 return NT_STATUS_INVALID_PARAMETER;
744         }
745         for (i=0; ops[i]; i++) {
746                 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
747                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
748                         break;
749                 }
750         }
751         talloc_free(mem_ctx);
752         return nt_status;
753 }
754
755 /** 
756  * Start a GENSEC sub-mechanism by an internal name
757  *
758  */
759
760 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security, 
761                                         const char *name) 
762 {
763         gensec_security->ops = gensec_security_by_name(gensec_security, name);
764         if (!gensec_security->ops) {
765                 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
766                 return NT_STATUS_INVALID_PARAMETER;
767         }
768         return gensec_start_mech(gensec_security);
769 }
770
771 /*
772   wrappers for the gensec function pointers
773 */
774 _PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security, 
775                               TALLOC_CTX *mem_ctx, 
776                               uint8_t *data, size_t length, 
777                               const uint8_t *whole_pdu, size_t pdu_length, 
778                               const DATA_BLOB *sig)
779 {
780         if (!gensec_security->ops->unseal_packet) {
781                 return NT_STATUS_NOT_IMPLEMENTED;
782         }
783         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
784                 return NT_STATUS_INVALID_PARAMETER;
785         }
786         
787         return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, 
788                                                    data, length, 
789                                                    whole_pdu, pdu_length, 
790                                                    sig);
791 }
792
793 _PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security, 
794                              TALLOC_CTX *mem_ctx, 
795                              const uint8_t *data, size_t length, 
796                              const uint8_t *whole_pdu, size_t pdu_length, 
797                              const DATA_BLOB *sig)
798 {
799         if (!gensec_security->ops->check_packet) {
800                 return NT_STATUS_NOT_IMPLEMENTED;
801         }
802         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
803                 return NT_STATUS_INVALID_PARAMETER;
804         }
805         
806         return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
807 }
808
809 _PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security, 
810                             TALLOC_CTX *mem_ctx, 
811                             uint8_t *data, size_t length, 
812                             const uint8_t *whole_pdu, size_t pdu_length, 
813                             DATA_BLOB *sig)
814 {
815         if (!gensec_security->ops->seal_packet) {
816                 return NT_STATUS_NOT_IMPLEMENTED;
817         }
818         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
819                 return NT_STATUS_INVALID_PARAMETER;
820         }
821         
822         return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
823 }
824
825 _PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security, 
826                             TALLOC_CTX *mem_ctx, 
827                             const uint8_t *data, size_t length, 
828                             const uint8_t *whole_pdu, size_t pdu_length, 
829                             DATA_BLOB *sig)
830 {
831         if (!gensec_security->ops->sign_packet) {
832                 return NT_STATUS_NOT_IMPLEMENTED;
833         }
834         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
835                 return NT_STATUS_INVALID_PARAMETER;
836         }
837         
838         return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
839 }
840
841 _PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size) 
842 {
843         if (!gensec_security->ops->sig_size) {
844                 return 0;
845         }
846         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
847                 return 0;
848         }
849         
850         return gensec_security->ops->sig_size(gensec_security, data_size);
851 }
852
853 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security) 
854 {
855         if (!gensec_security->ops->max_wrapped_size) {
856                 return (1 << 17);
857         }
858         
859         return gensec_security->ops->max_wrapped_size(gensec_security);
860 }
861
862 size_t gensec_max_input_size(struct gensec_security *gensec_security) 
863 {
864         if (!gensec_security->ops->max_input_size) {
865                 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
866         }
867         
868         return gensec_security->ops->max_input_size(gensec_security);
869 }
870
871 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security, 
872                      TALLOC_CTX *mem_ctx, 
873                      const DATA_BLOB *in, 
874                      DATA_BLOB *out) 
875 {
876         if (!gensec_security->ops->wrap) {
877                 return NT_STATUS_NOT_IMPLEMENTED;
878         }
879         return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
880 }
881
882 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security, 
883                        TALLOC_CTX *mem_ctx, 
884                        const DATA_BLOB *in, 
885                        DATA_BLOB *out) 
886 {
887         if (!gensec_security->ops->unwrap) {
888                 return NT_STATUS_NOT_IMPLEMENTED;
889         }
890         return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
891 }
892
893 _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security, 
894                             DATA_BLOB *session_key)
895 {
896         if (!gensec_security->ops->session_key) {
897                 return NT_STATUS_NOT_IMPLEMENTED;
898         }
899         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
900                 return NT_STATUS_NO_USER_SESSION_KEY;
901         }
902         
903         return gensec_security->ops->session_key(gensec_security, session_key);
904 }
905
906 /** 
907  * Return the credentials of a logged on user, including session keys
908  * etc.
909  *
910  * Only valid after a successful authentication
911  *
912  * May only be called once per authentication.
913  *
914  */
915
916 _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security, 
917                              struct auth_session_info **session_info)
918 {
919         if (!gensec_security->ops->session_info) {
920                 return NT_STATUS_NOT_IMPLEMENTED;
921         }
922         return gensec_security->ops->session_info(gensec_security, session_info);
923 }
924
925 /**
926  * Next state function for the GENSEC state machine
927  * 
928  * @param gensec_security GENSEC State
929  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
930  * @param in The request, as a DATA_BLOB
931  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
932  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
933  *                or NT_STATUS_OK if the user is authenticated. 
934  */
935
936 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 
937                        const DATA_BLOB in, DATA_BLOB *out) 
938 {
939         return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
940 }
941
942 static void gensec_update_async_timed_handler(struct event_context *ev, struct timed_event *te,
943                                               struct timeval t, void *ptr)
944 {
945         struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
946         req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
947         req->callback.fn(req, req->callback.private_data);
948 }
949
950 /**
951  * Next state function for the GENSEC state machine async version
952  * 
953  * @param gensec_security GENSEC State
954  * @param in The request, as a DATA_BLOB
955  * @param callback The function that will be called when the operation is
956  *                 finished, it should return gensec_update_recv() to get output
957  * @param private_data A private pointer that will be passed to the callback function
958  */
959
960 _PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
961                                  void (*callback)(struct gensec_update_request *req, void *private_data),
962                                  void *private_data)
963 {
964         struct gensec_update_request *req = NULL;
965         struct timed_event *te = NULL;
966
967         req = talloc(gensec_security, struct gensec_update_request);
968         if (!req) goto failed;
969         req->gensec_security            = gensec_security;
970         req->in                         = in;
971         req->out                        = data_blob(NULL, 0);
972         req->callback.fn                = callback;
973         req->callback.private_data      = private_data;
974
975         te = event_add_timed(gensec_security->event_ctx, req,
976                              timeval_zero(),
977                              gensec_update_async_timed_handler, req);
978         if (!te) goto failed;
979
980         return;
981
982 failed:
983         talloc_free(req);
984         callback(NULL, private_data);
985 }
986
987 /**
988  * Next state function for the GENSEC state machine
989  * 
990  * @param req GENSEC update request state
991  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
992  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
993  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
994  *                or NT_STATUS_OK if the user is authenticated. 
995  */
996 _PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
997 {
998         NTSTATUS status;
999
1000         NT_STATUS_HAVE_NO_MEMORY(req);
1001
1002         *out = req->out;
1003         talloc_steal(out_mem_ctx, out->data);
1004         status = req->status;
1005
1006         talloc_free(req);
1007         return status;
1008 }
1009
1010 /** 
1011  * Set the requirement for a certain feature on the connection
1012  *
1013  */
1014
1015 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1016                          uint32_t feature) 
1017 {
1018         gensec_security->want_features |= feature;
1019 }
1020
1021 /** 
1022  * Check the requirement for a certain feature on the connection
1023  *
1024  */
1025
1026 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
1027                          uint32_t feature) 
1028 {
1029         if (!gensec_security->ops->have_feature) {
1030                 return false;
1031         }
1032         
1033         /* We might 'have' features that we don't 'want', because the
1034          * other end demanded them, or we can't neotiate them off */
1035         return gensec_security->ops->have_feature(gensec_security, feature);
1036 }
1037
1038 /** 
1039  * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context 
1040  *
1041  */
1042
1043 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials) 
1044 {
1045         gensec_security->credentials = talloc_reference(gensec_security, credentials);
1046         NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1047         gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1048         return NT_STATUS_OK;
1049 }
1050
1051 /** 
1052  * Return the credentials structure associated with a GENSEC context
1053  *
1054  */
1055
1056 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security) 
1057 {
1058         if (!gensec_security) {
1059                 return NULL;
1060         }
1061         return gensec_security->credentials;
1062 }
1063
1064 /** 
1065  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed 
1066  *
1067  */
1068
1069 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service) 
1070 {
1071         gensec_security->target.service = talloc_strdup(gensec_security, service);
1072         if (!gensec_security->target.service) {
1073                 return NT_STATUS_NO_MEMORY;
1074         }
1075         return NT_STATUS_OK;
1076 }
1077
1078 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security) 
1079 {
1080         if (gensec_security->target.service) {
1081                 return gensec_security->target.service;
1082         }
1083
1084         return "host";
1085 }
1086
1087 /** 
1088  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed 
1089  *
1090  */
1091
1092 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) 
1093 {
1094         gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1095         if (hostname && !gensec_security->target.hostname) {
1096                 return NT_STATUS_NO_MEMORY;
1097         }
1098         return NT_STATUS_OK;
1099 }
1100
1101 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security) 
1102 {
1103         /* We allow the target hostname to be overriden for testing purposes */
1104         const char *target_hostname = lp_parm_string(gensec_security->lp_ctx, NULL, "gensec", "target_hostname");
1105         if (target_hostname) {
1106                 return target_hostname;
1107         }
1108
1109         if (gensec_security->target.hostname) {
1110                 return gensec_security->target.hostname;
1111         }
1112
1113         /* We could add use the 'set sockaddr' call, and do a reverse
1114          * lookup, but this would be both insecure (compromising the
1115          * way kerberos works) and add DNS timeouts */
1116         return NULL;
1117 }
1118
1119 /** 
1120  * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context 
1121  *
1122  * This is so that kerberos can include these addresses in
1123  * cryptographic tokens, to avoid certain attacks.
1124  */
1125
1126 _PUBLIC_ NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr) 
1127 {
1128         gensec_security->my_addr = my_addr;
1129         if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1130                 return NT_STATUS_NO_MEMORY;
1131         }
1132         return NT_STATUS_OK;
1133 }
1134
1135 _PUBLIC_ NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr) 
1136 {
1137         gensec_security->peer_addr = peer_addr;
1138         if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1139                 return NT_STATUS_NO_MEMORY;
1140         }
1141         return NT_STATUS_OK;
1142 }
1143
1144 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security) 
1145 {
1146         if (gensec_security->my_addr) {
1147                 return gensec_security->my_addr;
1148         }
1149
1150         /* We could add a 'set sockaddr' call, and do a lookup.  This
1151          * would avoid needing to do system calls if nothing asks. */
1152         return NULL;
1153 }
1154
1155 _PUBLIC_ struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security) 
1156 {
1157         if (gensec_security->peer_addr) {
1158                 return gensec_security->peer_addr;
1159         }
1160
1161         /* We could add a 'set sockaddr' call, and do a lookup.  This
1162          * would avoid needing to do system calls if nothing asks.
1163          * However, this is not appropriate for the peer addres on
1164          * datagram sockets */
1165         return NULL;
1166 }
1167
1168
1169
1170 /** 
1171  * Set the target principal (assuming it it known, say from the SPNEGO reply)
1172  *  - ensures it is talloc()ed 
1173  *
1174  */
1175
1176 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal) 
1177 {
1178         gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1179         if (!gensec_security->target.principal) {
1180                 return NT_STATUS_NO_MEMORY;
1181         }
1182         return NT_STATUS_OK;
1183 }
1184
1185 const char *gensec_get_target_principal(struct gensec_security *gensec_security) 
1186 {
1187         if (gensec_security->target.principal) {
1188                 return gensec_security->target.principal;
1189         }
1190
1191         return NULL;
1192 }
1193
1194 /*
1195   register a GENSEC backend. 
1196
1197   The 'name' can be later used by other backends to find the operations
1198   structure for this backend.
1199 */
1200 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1201 {
1202         if (!lp_parm_bool(global_loadparm, NULL, "gensec", ops->name, ops->enabled)) {
1203                 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1204                 return NT_STATUS_OK;
1205         }
1206
1207         if (gensec_security_by_name(NULL, ops->name) != NULL) {
1208                 /* its already registered! */
1209                 DEBUG(0,("GENSEC backend '%s' already registered\n", 
1210                          ops->name));
1211                 return NT_STATUS_OBJECT_NAME_COLLISION;
1212         }
1213
1214         generic_security_ops = talloc_realloc(talloc_autofree_context(), 
1215                                               generic_security_ops, 
1216                                               struct gensec_security_ops *, 
1217                                               gensec_num_backends+2);
1218         if (!generic_security_ops) {
1219                 return NT_STATUS_NO_MEMORY;
1220         }
1221
1222         generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1223         gensec_num_backends++;
1224         generic_security_ops[gensec_num_backends] = NULL;
1225
1226         DEBUG(3,("GENSEC backend '%s' registered\n", 
1227                  ops->name));
1228
1229         return NT_STATUS_OK;
1230 }
1231
1232 /*
1233   return the GENSEC interface version, and the size of some critical types
1234   This can be used by backends to either detect compilation errors, or provide
1235   multiple implementations for different smbd compilation options in one module
1236 */
1237 const struct gensec_critical_sizes *gensec_interface_version(void)
1238 {
1239         static const struct gensec_critical_sizes critical_sizes = {
1240                 GENSEC_INTERFACE_VERSION,
1241                 sizeof(struct gensec_security_ops),
1242                 sizeof(struct gensec_security),
1243         };
1244
1245         return &critical_sizes;
1246 }
1247
1248 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1249         return (*gs2)->priority - (*gs1)->priority;
1250 }
1251
1252 /*
1253   initialise the GENSEC subsystem
1254 */
1255 _PUBLIC_ NTSTATUS gensec_init(struct loadparm_context *lp_ctx)
1256 {
1257         static bool initialized = false;
1258         extern NTSTATUS gensec_sasl_init(void);
1259         extern NTSTATUS gensec_krb5_init(void);
1260         extern NTSTATUS gensec_schannel_init(void);
1261         extern NTSTATUS gensec_spnego_init(void);
1262         extern NTSTATUS gensec_gssapi_init(void);
1263         extern NTSTATUS gensec_ntlmssp_init(void);
1264
1265         init_module_fn static_init[] = { STATIC_gensec_MODULES };
1266         init_module_fn *shared_init;
1267
1268         if (initialized) return NT_STATUS_OK;
1269         initialized = true;
1270         
1271         shared_init = load_samba_modules(NULL, lp_ctx, "gensec");
1272
1273         run_init_functions(static_init);
1274         run_init_functions(shared_init);
1275
1276         talloc_free(shared_init);
1277
1278         qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1279         
1280         return NT_STATUS_OK;
1281 }