r14409: quieten warnings
[abartlet/samba.git/.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 _PUBLIC_ 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 _PUBLIC_ 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                 break;
576         case GENSEC_SERVER:
577                 if (gensec_security->ops->server_start) {
578                         status = gensec_security->ops->server_start(gensec_security);
579                         if (!NT_STATUS_IS_OK(status)) {
580                                 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
581                                           gensec_security->ops->name, nt_errstr(status))); 
582                         }
583                         return status;
584                 }
585                 break;
586         }
587         return NT_STATUS_INVALID_PARAMETER;
588 }
589
590 /** 
591  * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number 
592  * @param gensec_security GENSEC context pointer.
593  * @param auth_type DCERPC auth type
594  * @param auth_level DCERPC auth level 
595  */
596
597 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security, 
598                                        uint8_t auth_type, uint8_t auth_level) 
599 {
600         gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
601         if (!gensec_security->ops) {
602                 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
603                 return NT_STATUS_INVALID_PARAMETER;
604         }
605         gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
606         gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
607         if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
608                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
609         } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
610                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
611                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
612         } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
613                 /* Default features */
614         } else {
615                 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n", 
616                          auth_level));
617                 return NT_STATUS_INVALID_PARAMETER;
618         }
619
620         return gensec_start_mech(gensec_security);
621 }
622
623 const char *gensec_get_name_by_authtype(uint8_t authtype) 
624 {
625         const struct gensec_security_ops *ops;
626         ops = gensec_security_by_authtype(NULL, authtype);
627         if (ops) {
628                 return ops->name;
629         }
630         return NULL;
631 }
632         
633
634 const char *gensec_get_name_by_oid(const char *oid_string) 
635 {
636         const struct gensec_security_ops *ops;
637         ops = gensec_security_by_oid(NULL, oid_string);
638         if (ops) {
639                 return ops->name;
640         }
641         return oid_string;
642 }
643         
644
645 /** 
646  * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
647  *
648  */
649
650 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security, 
651                                   const struct gensec_security_ops *ops) 
652 {
653         gensec_security->ops = ops;
654         return gensec_start_mech(gensec_security);
655 }
656
657 /** 
658  * Start a GENSEC sub-mechanism by OID, used in SPNEGO
659  *
660  * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
661  *       well-known #define to hook it in.
662  */
663
664 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security, 
665                                   const char *mech_oid) 
666 {
667         gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
668         if (!gensec_security->ops) {
669                 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
670                 return NT_STATUS_INVALID_PARAMETER;
671         }
672         return gensec_start_mech(gensec_security);
673 }
674
675 /** 
676  * Start a GENSEC sub-mechanism by a well know SASL name
677  *
678  */
679
680 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security, 
681                                         const char *sasl_name) 
682 {
683         gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
684         if (!gensec_security->ops) {
685                 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
686                 return NT_STATUS_INVALID_PARAMETER;
687         }
688         return gensec_start_mech(gensec_security);
689 }
690
691 /** 
692  * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
693  *
694  */
695
696 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security, 
697                                         const char **sasl_names) 
698 {
699         NTSTATUS nt_status;
700         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
701         const struct gensec_security_ops **ops;
702         if (!mem_ctx) {
703                 return NT_STATUS_NO_MEMORY;
704         }
705         ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
706         if (!ops || !*ops) {
707                 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n", 
708                           str_list_join(mem_ctx, 
709                                         sasl_names, ' ')));
710                 talloc_free(mem_ctx);
711                 return NT_STATUS_INVALID_PARAMETER;
712         }
713         nt_status = gensec_start_mech_by_ops(gensec_security, ops[0]);
714         talloc_free(mem_ctx);
715         return nt_status;
716 }
717
718 /** 
719  * Start a GENSEC sub-mechanism by an internal name
720  *
721  */
722
723 NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security, 
724                                         const char *name) 
725 {
726         gensec_security->ops = gensec_security_by_name(gensec_security, name);
727         if (!gensec_security->ops) {
728                 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
729                 return NT_STATUS_INVALID_PARAMETER;
730         }
731         return gensec_start_mech(gensec_security);
732 }
733
734 /*
735   wrappers for the gensec function pointers
736 */
737 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security, 
738                               TALLOC_CTX *mem_ctx, 
739                               uint8_t *data, size_t length, 
740                               const uint8_t *whole_pdu, size_t pdu_length, 
741                               const DATA_BLOB *sig)
742 {
743         if (!gensec_security->ops->unseal_packet) {
744                 return NT_STATUS_NOT_IMPLEMENTED;
745         }
746         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
747                 return NT_STATUS_INVALID_PARAMETER;
748         }
749         
750         return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, 
751                                                    data, length, 
752                                                    whole_pdu, pdu_length, 
753                                                    sig);
754 }
755
756 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security, 
757                              TALLOC_CTX *mem_ctx, 
758                              const uint8_t *data, size_t length, 
759                              const uint8_t *whole_pdu, size_t pdu_length, 
760                              const DATA_BLOB *sig)
761 {
762         if (!gensec_security->ops->check_packet) {
763                 return NT_STATUS_NOT_IMPLEMENTED;
764         }
765         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
766                 return NT_STATUS_INVALID_PARAMETER;
767         }
768         
769         return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
770 }
771
772 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security, 
773                             TALLOC_CTX *mem_ctx, 
774                             uint8_t *data, size_t length, 
775                             const uint8_t *whole_pdu, size_t pdu_length, 
776                             DATA_BLOB *sig)
777 {
778         if (!gensec_security->ops->seal_packet) {
779                 return NT_STATUS_NOT_IMPLEMENTED;
780         }
781         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
782                 return NT_STATUS_INVALID_PARAMETER;
783         }
784         
785         return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
786 }
787
788 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security, 
789                             TALLOC_CTX *mem_ctx, 
790                             const uint8_t *data, size_t length, 
791                             const uint8_t *whole_pdu, size_t pdu_length, 
792                             DATA_BLOB *sig)
793 {
794         if (!gensec_security->ops->sign_packet) {
795                 return NT_STATUS_NOT_IMPLEMENTED;
796         }
797         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
798                 return NT_STATUS_INVALID_PARAMETER;
799         }
800         
801         return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
802 }
803
804 size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size) 
805 {
806         if (!gensec_security->ops->sig_size) {
807                 return 0;
808         }
809         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
810                 return 0;
811         }
812         
813         return gensec_security->ops->sig_size(gensec_security, data_size);
814 }
815
816 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security, 
817                      TALLOC_CTX *mem_ctx, 
818                      const DATA_BLOB *in, 
819                      DATA_BLOB *out) 
820 {
821         if (!gensec_security->ops->wrap) {
822                 return NT_STATUS_NOT_IMPLEMENTED;
823         }
824         return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
825 }
826
827 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security, 
828                        TALLOC_CTX *mem_ctx, 
829                        const DATA_BLOB *in, 
830                        DATA_BLOB *out) 
831 {
832         if (!gensec_security->ops->unwrap) {
833                 return NT_STATUS_NOT_IMPLEMENTED;
834         }
835         return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
836 }
837
838 NTSTATUS gensec_session_key(struct gensec_security *gensec_security, 
839                             DATA_BLOB *session_key)
840 {
841         if (!gensec_security->ops->session_key) {
842                 return NT_STATUS_NOT_IMPLEMENTED;
843         }
844         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
845                 return NT_STATUS_NO_USER_SESSION_KEY;
846         }
847         
848         return gensec_security->ops->session_key(gensec_security, session_key);
849 }
850
851 /** 
852  * Return the credentials of a logged on user, including session keys
853  * etc.
854  *
855  * Only valid after a successful authentication
856  *
857  * May only be called once per authentication.
858  *
859  */
860
861 NTSTATUS gensec_session_info(struct gensec_security *gensec_security, 
862                              struct auth_session_info **session_info)
863 {
864         if (!gensec_security->ops->session_info) {
865                 return NT_STATUS_NOT_IMPLEMENTED;
866         }
867         return gensec_security->ops->session_info(gensec_security, session_info);
868 }
869
870 /**
871  * Next state function for the GENSEC state machine
872  * 
873  * @param gensec_security GENSEC State
874  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
875  * @param in The request, as a DATA_BLOB
876  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
877  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
878  *                or NT_STATUS_OK if the user is authenticated. 
879  */
880
881 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 
882                        const DATA_BLOB in, DATA_BLOB *out) 
883 {
884         return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
885 }
886
887 /** 
888  * Set the requirement for a certain feature on the connection
889  *
890  */
891
892 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
893                          uint32_t feature) 
894 {
895         gensec_security->want_features |= feature;
896 }
897
898 /** 
899  * Check the requirement for a certain feature on the connection
900  *
901  */
902
903 _PUBLIC_ BOOL gensec_have_feature(struct gensec_security *gensec_security,
904                          uint32_t feature) 
905 {
906         if (!gensec_security->ops->have_feature) {
907                 return False;
908         }
909         
910         /* Can only 'have' a feature if you already 'want'ed it */
911         if (gensec_security->want_features & feature) {
912                 return gensec_security->ops->have_feature(gensec_security, feature);
913         }
914         return False;
915 }
916
917 /** 
918  * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context 
919  *
920  */
921
922 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials) 
923 {
924         gensec_security->credentials = talloc_reference(gensec_security, credentials);
925         return NT_STATUS_OK;
926 }
927
928 /** 
929  * Return the credentials structure associated with a GENSEC context
930  *
931  */
932
933 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security) 
934 {
935         if (!gensec_security) {
936                 return NULL;
937         }
938         return gensec_security->credentials;
939 }
940
941 /** 
942  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed 
943  *
944  */
945
946 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service) 
947 {
948         gensec_security->target.service = talloc_strdup(gensec_security, service);
949         if (!gensec_security->target.service) {
950                 return NT_STATUS_NO_MEMORY;
951         }
952         return NT_STATUS_OK;
953 }
954
955 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security) 
956 {
957         if (gensec_security->target.service) {
958                 return gensec_security->target.service;
959         }
960
961         return "host";
962 }
963
964 /** 
965  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed 
966  *
967  */
968
969 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) 
970 {
971         gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
972         if (!gensec_security->target.hostname) {
973                 return NT_STATUS_NO_MEMORY;
974         }
975         return NT_STATUS_OK;
976 }
977
978 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security) 
979 {
980         if (gensec_security->target.hostname) {
981                 return gensec_security->target.hostname;
982         }
983
984         /* We could add use the 'set sockaddr' call, and do a reverse
985          * lookup, but this would be both insecure (compromising the
986          * way kerberos works) and add DNS timeouts */
987         return NULL;
988 }
989
990 /** 
991  * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context 
992  *
993  * This is so that kerberos can include these addresses in
994  * cryptographic tokens, to avoid certain attacks.
995  */
996
997 NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr) 
998 {
999         gensec_security->my_addr = my_addr;
1000         if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1001                 return NT_STATUS_NO_MEMORY;
1002         }
1003         return NT_STATUS_OK;
1004 }
1005
1006 NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr) 
1007 {
1008         gensec_security->peer_addr = peer_addr;
1009         if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1010                 return NT_STATUS_NO_MEMORY;
1011         }
1012         return NT_STATUS_OK;
1013 }
1014
1015 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security) 
1016 {
1017         if (gensec_security->my_addr) {
1018                 return gensec_security->my_addr;
1019         }
1020
1021         /* We could add a 'set sockaddr' call, and do a lookup.  This
1022          * would avoid needing to do system calls if nothing asks. */
1023         return NULL;
1024 }
1025
1026 struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security) 
1027 {
1028         if (gensec_security->peer_addr) {
1029                 return gensec_security->peer_addr;
1030         }
1031
1032         /* We could add a 'set sockaddr' call, and do a lookup.  This
1033          * would avoid needing to do system calls if nothing asks.
1034          * However, this is not appropriate for the peer addres on
1035          * datagram sockets */
1036         return NULL;
1037 }
1038
1039
1040
1041 /** 
1042  * Set the target principal (assuming it it known, say from the SPNEGO reply)
1043  *  - ensures it is talloc()ed 
1044  *
1045  */
1046
1047 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal) 
1048 {
1049         gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1050         if (!gensec_security->target.principal) {
1051                 return NT_STATUS_NO_MEMORY;
1052         }
1053         return NT_STATUS_OK;
1054 }
1055
1056 const char *gensec_get_target_principal(struct gensec_security *gensec_security) 
1057 {
1058         if (gensec_security->target.principal) {
1059                 return gensec_security->target.principal;
1060         }
1061
1062         return NULL;
1063 }
1064
1065 /*
1066   register a GENSEC backend. 
1067
1068   The 'name' can be later used by other backends to find the operations
1069   structure for this backend.
1070 */
1071 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1072 {
1073         if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
1074                 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1075                 return NT_STATUS_OK;
1076         }
1077
1078         if (gensec_security_by_name(NULL, ops->name) != NULL) {
1079                 /* its already registered! */
1080                 DEBUG(0,("GENSEC backend '%s' already registered\n", 
1081                          ops->name));
1082                 return NT_STATUS_OBJECT_NAME_COLLISION;
1083         }
1084
1085         generic_security_ops = talloc_realloc(talloc_autofree_context(), 
1086                                               generic_security_ops, 
1087                                               struct gensec_security_ops *, 
1088                                               gensec_num_backends+2);
1089         if (!generic_security_ops) {
1090                 smb_panic("out of memory (or failed to realloc referenced memory) in gensec_register");
1091         }
1092
1093         generic_security_ops[gensec_num_backends] = discard_const(ops);
1094         gensec_num_backends++;
1095         generic_security_ops[gensec_num_backends] = NULL;
1096
1097         DEBUG(3,("GENSEC backend '%s' registered\n", 
1098                  ops->name));
1099
1100         return NT_STATUS_OK;
1101 }
1102
1103 /*
1104   return the GENSEC interface version, and the size of some critical types
1105   This can be used by backends to either detect compilation errors, or provide
1106   multiple implementations for different smbd compilation options in one module
1107 */
1108 const struct gensec_critical_sizes *gensec_interface_version(void)
1109 {
1110         static const struct gensec_critical_sizes critical_sizes = {
1111                 GENSEC_INTERFACE_VERSION,
1112                 sizeof(struct gensec_security_ops),
1113                 sizeof(struct gensec_security),
1114         };
1115
1116         return &critical_sizes;
1117 }
1118
1119 /*
1120   initialise the GENSEC subsystem
1121 */
1122 NTSTATUS gensec_init(void)
1123 {
1124         static BOOL initialized = False;
1125
1126         init_module_fn static_init[] = STATIC_gensec_MODULES;
1127         init_module_fn *shared_init = load_samba_modules(NULL, "gensec");
1128
1129         if (initialized) return NT_STATUS_OK;
1130         initialized = True;
1131
1132         run_init_functions(static_init);
1133         run_init_functions(shared_init);
1134
1135         talloc_free(shared_init);
1136         
1137         return NT_STATUS_OK;
1138 }