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