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