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