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