r13245: Don't segfault if we don't have a credentials structure on this gensec
[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 "smb_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(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 by an internal name
691  *
692  */
693
694 NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security, 
695                                         const char *name) 
696 {
697         gensec_security->ops = gensec_security_by_name(gensec_security, name);
698         if (!gensec_security->ops) {
699                 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
700                 return NT_STATUS_INVALID_PARAMETER;
701         }
702         return gensec_start_mech(gensec_security);
703 }
704
705 /*
706   wrappers for the gensec function pointers
707 */
708 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security, 
709                               TALLOC_CTX *mem_ctx, 
710                               uint8_t *data, size_t length, 
711                               const uint8_t *whole_pdu, size_t pdu_length, 
712                               const DATA_BLOB *sig)
713 {
714         if (!gensec_security->ops->unseal_packet) {
715                 return NT_STATUS_NOT_IMPLEMENTED;
716         }
717         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
718                 return NT_STATUS_INVALID_PARAMETER;
719         }
720         
721         return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, 
722                                                    data, length, 
723                                                    whole_pdu, pdu_length, 
724                                                    sig);
725 }
726
727 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security, 
728                              TALLOC_CTX *mem_ctx, 
729                              const uint8_t *data, size_t length, 
730                              const uint8_t *whole_pdu, size_t pdu_length, 
731                              const DATA_BLOB *sig)
732 {
733         if (!gensec_security->ops->check_packet) {
734                 return NT_STATUS_NOT_IMPLEMENTED;
735         }
736         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
737                 return NT_STATUS_INVALID_PARAMETER;
738         }
739         
740         return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
741 }
742
743 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security, 
744                             TALLOC_CTX *mem_ctx, 
745                             uint8_t *data, size_t length, 
746                             const uint8_t *whole_pdu, size_t pdu_length, 
747                             DATA_BLOB *sig)
748 {
749         if (!gensec_security->ops->seal_packet) {
750                 return NT_STATUS_NOT_IMPLEMENTED;
751         }
752         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
753                 return NT_STATUS_INVALID_PARAMETER;
754         }
755         
756         return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
757 }
758
759 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security, 
760                             TALLOC_CTX *mem_ctx, 
761                             const uint8_t *data, size_t length, 
762                             const uint8_t *whole_pdu, size_t pdu_length, 
763                             DATA_BLOB *sig)
764 {
765         if (!gensec_security->ops->sign_packet) {
766                 return NT_STATUS_NOT_IMPLEMENTED;
767         }
768         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
769                 return NT_STATUS_INVALID_PARAMETER;
770         }
771         
772         return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
773 }
774
775 size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size) 
776 {
777         if (!gensec_security->ops->sig_size) {
778                 return 0;
779         }
780         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
781                 return 0;
782         }
783         
784         return gensec_security->ops->sig_size(gensec_security, data_size);
785 }
786
787 NTSTATUS gensec_wrap(struct gensec_security *gensec_security, 
788                      TALLOC_CTX *mem_ctx, 
789                      const DATA_BLOB *in, 
790                      DATA_BLOB *out) 
791 {
792         if (!gensec_security->ops->wrap) {
793                 return NT_STATUS_NOT_IMPLEMENTED;
794         }
795         return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
796 }
797
798 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security, 
799                        TALLOC_CTX *mem_ctx, 
800                        const DATA_BLOB *in, 
801                        DATA_BLOB *out) 
802 {
803         if (!gensec_security->ops->unwrap) {
804                 return NT_STATUS_NOT_IMPLEMENTED;
805         }
806         return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
807 }
808
809 NTSTATUS gensec_session_key(struct gensec_security *gensec_security, 
810                             DATA_BLOB *session_key)
811 {
812         if (!gensec_security->ops->session_key) {
813                 return NT_STATUS_NOT_IMPLEMENTED;
814         }
815         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
816                 return NT_STATUS_NO_USER_SESSION_KEY;
817         }
818         
819         return gensec_security->ops->session_key(gensec_security, session_key);
820 }
821
822 /** 
823  * Return the credentials of a logged on user, including session keys
824  * etc.
825  *
826  * Only valid after a successful authentication
827  *
828  * May only be called once per authentication.
829  *
830  */
831
832 NTSTATUS gensec_session_info(struct gensec_security *gensec_security, 
833                              struct auth_session_info **session_info)
834 {
835         if (!gensec_security->ops->session_info) {
836                 return NT_STATUS_NOT_IMPLEMENTED;
837         }
838         return gensec_security->ops->session_info(gensec_security, session_info);
839 }
840
841 /**
842  * Next state function for the GENSEC state machine
843  * 
844  * @param gensec_security GENSEC State
845  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
846  * @param in The request, as a DATA_BLOB
847  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
848  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
849  *                or NT_STATUS_OK if the user is authenticated. 
850  */
851
852 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 
853                        const DATA_BLOB in, DATA_BLOB *out) 
854 {
855         return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
856 }
857
858 /** 
859  * Set the requirement for a certain feature on the connection
860  *
861  */
862
863 void gensec_want_feature(struct gensec_security *gensec_security,
864                          uint32_t feature) 
865 {
866         gensec_security->want_features |= feature;
867 }
868
869 /** 
870  * Check the requirement for a certain feature on the connection
871  *
872  */
873
874 BOOL gensec_have_feature(struct gensec_security *gensec_security,
875                          uint32_t feature) 
876 {
877         if (!gensec_security->ops->have_feature) {
878                 return False;
879         }
880         
881         /* Can only 'have' a feature if you already 'want'ed it */
882         if (gensec_security->want_features & feature) {
883                 return gensec_security->ops->have_feature(gensec_security, feature);
884         }
885         return False;
886 }
887
888 /** 
889  * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context 
890  *
891  */
892
893 NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials) 
894 {
895         gensec_security->credentials = talloc_reference(gensec_security, credentials);
896         return NT_STATUS_OK;
897 }
898
899 /** 
900  * Return the credentials structure associated with a GENSEC context
901  *
902  */
903
904 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security) 
905 {
906         if (!gensec_security) {
907                 return NULL;
908         }
909         return gensec_security->credentials;
910 }
911
912 /** 
913  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed 
914  *
915  */
916
917 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service) 
918 {
919         gensec_security->target.service = talloc_strdup(gensec_security, service);
920         if (!gensec_security->target.service) {
921                 return NT_STATUS_NO_MEMORY;
922         }
923         return NT_STATUS_OK;
924 }
925
926 const char *gensec_get_target_service(struct gensec_security *gensec_security) 
927 {
928         if (gensec_security->target.service) {
929                 return gensec_security->target.service;
930         }
931
932         return "host";
933 }
934
935 /** 
936  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed 
937  *
938  */
939
940 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) 
941 {
942         gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
943         if (!gensec_security->target.hostname) {
944                 return NT_STATUS_NO_MEMORY;
945         }
946         return NT_STATUS_OK;
947 }
948
949 const char *gensec_get_target_hostname(struct gensec_security *gensec_security) 
950 {
951         if (gensec_security->target.hostname) {
952                 return gensec_security->target.hostname;
953         }
954
955         /* We could add use the 'set sockaddr' call, and do a reverse
956          * lookup, but this would be both insecure (compromising the
957          * way kerberos works) and add DNS timeouts */
958         return NULL;
959 }
960
961 /** 
962  * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context 
963  *
964  * This is so that kerberos can include these addresses in
965  * cryptographic tokens, to avoid certain attacks.
966  */
967
968 NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr) 
969 {
970         gensec_security->my_addr = my_addr;
971         if (my_addr && !talloc_reference(gensec_security, my_addr)) {
972                 return NT_STATUS_NO_MEMORY;
973         }
974         return NT_STATUS_OK;
975 }
976
977 NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr) 
978 {
979         gensec_security->peer_addr = peer_addr;
980         if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
981                 return NT_STATUS_NO_MEMORY;
982         }
983         return NT_STATUS_OK;
984 }
985
986 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security) 
987 {
988         if (gensec_security->my_addr) {
989                 return gensec_security->my_addr;
990         }
991
992         /* We could add a 'set sockaddr' call, and do a lookup.  This
993          * would avoid needing to do system calls if nothing asks. */
994         return NULL;
995 }
996
997 struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security) 
998 {
999         if (gensec_security->peer_addr) {
1000                 return gensec_security->peer_addr;
1001         }
1002
1003         /* We could add a 'set sockaddr' call, and do a lookup.  This
1004          * would avoid needing to do system calls if nothing asks.
1005          * However, this is not appropriate for the peer addres on
1006          * datagram sockets */
1007         return NULL;
1008 }
1009
1010
1011
1012 /** 
1013  * Set the target principal (assuming it it known, say from the SPNEGO reply)
1014  *  - ensures it is talloc()ed 
1015  *
1016  */
1017
1018 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal) 
1019 {
1020         gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1021         if (!gensec_security->target.principal) {
1022                 return NT_STATUS_NO_MEMORY;
1023         }
1024         return NT_STATUS_OK;
1025 }
1026
1027 const char *gensec_get_target_principal(struct gensec_security *gensec_security) 
1028 {
1029         if (gensec_security->target.principal) {
1030                 return gensec_security->target.principal;
1031         }
1032
1033         return NULL;
1034 }
1035
1036 /*
1037   register a GENSEC backend. 
1038
1039   The 'name' can be later used by other backends to find the operations
1040   structure for this backend.
1041 */
1042 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1043 {
1044         if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
1045                 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1046                 return NT_STATUS_OK;
1047         }
1048
1049         if (gensec_security_by_name(NULL, ops->name) != NULL) {
1050                 /* its already registered! */
1051                 DEBUG(0,("GENSEC backend '%s' already registered\n", 
1052                          ops->name));
1053                 return NT_STATUS_OBJECT_NAME_COLLISION;
1054         }
1055
1056         generic_security_ops = talloc_realloc(talloc_autofree_context(), 
1057                                               generic_security_ops, 
1058                                               struct gensec_security_ops *, 
1059                                               gensec_num_backends+2);
1060         if (!generic_security_ops) {
1061                 smb_panic("out of memory (or failed to realloc referenced memory) in gensec_register");
1062         }
1063
1064         generic_security_ops[gensec_num_backends] = ops;
1065         gensec_num_backends++;
1066         generic_security_ops[gensec_num_backends] = NULL;
1067
1068         DEBUG(3,("GENSEC backend '%s' registered\n", 
1069                  ops->name));
1070
1071         return NT_STATUS_OK;
1072 }
1073
1074 /*
1075   return the GENSEC interface version, and the size of some critical types
1076   This can be used by backends to either detect compilation errors, or provide
1077   multiple implementations for different smbd compilation options in one module
1078 */
1079 const struct gensec_critical_sizes *gensec_interface_version(void)
1080 {
1081         static const struct gensec_critical_sizes critical_sizes = {
1082                 GENSEC_INTERFACE_VERSION,
1083                 sizeof(struct gensec_security_ops),
1084                 sizeof(struct gensec_security),
1085         };
1086
1087         return &critical_sizes;
1088 }
1089
1090 /*
1091   initialise the GENSEC subsystem
1092 */
1093 NTSTATUS gensec_init(void)
1094 {
1095         static BOOL initialized = False;
1096
1097         init_module_fn static_init[] = STATIC_GENSEC_MODULES;
1098         init_module_fn *shared_init = load_samba_modules(NULL, "gensec");
1099
1100         if (initialized) return NT_STATUS_OK;
1101         initialized = True;
1102
1103         run_init_functions(static_init);
1104         run_init_functions(shared_init);
1105
1106         talloc_free(shared_init);
1107         
1108         return NT_STATUS_OK;
1109 }