r6610: Fix a const warning in the gensec spnego implementation. (A make proto
[samba.git] / source / auth / gensec / gensec.c
1 /* 
2    Unix SMB/CIFS implementation.
3  
4    Generic Authentication Interface
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "auth/auth.h"
26
27 /* the list of currently registered GENSEC backends */
28 const static struct gensec_security_ops **generic_security_ops;
29 static int gensec_num_backends;
30
31 static const struct gensec_security_ops *gensec_security_by_authtype(uint8_t auth_type)
32 {
33         int i;
34         for (i=0; i < gensec_num_backends; i++) {
35                 if (generic_security_ops[i]->auth_type == auth_type) {
36                         return generic_security_ops[i];
37                 }
38         }
39
40         return NULL;
41 }
42
43 static const struct gensec_security_ops *gensec_security_by_oid(const char *oid_string)
44 {
45         int i;
46         for (i=0; i < gensec_num_backends; i++) {
47                 if (generic_security_ops[i]->oid &&
48                     (strcmp(generic_security_ops[i]->oid, oid_string) == 0)) {
49                         return generic_security_ops[i];
50                 }
51         }
52
53         return NULL;
54 }
55
56 static const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_name)
57 {
58         int i;
59         for (i=0; i < gensec_num_backends; i++) {
60                 if (generic_security_ops[i]->sasl_name 
61                     && (strcmp(generic_security_ops[i]->sasl_name, sasl_name) == 0)) {
62                         return generic_security_ops[i];
63                 }
64         }
65
66         return NULL;
67 }
68
69 static const struct gensec_security_ops *gensec_security_by_name(const char *name)
70 {
71         int i;
72         for (i=0; i < gensec_num_backends; i++) {
73                 if (generic_security_ops[i]->name 
74                     && (strcmp(generic_security_ops[i]->name, name) == 0)) {
75                         return generic_security_ops[i];
76                 }
77         }
78
79         return NULL;
80 }
81
82 const struct gensec_security_ops **gensec_security_all(int *num_backends_out)
83 {
84         *num_backends_out = gensec_num_backends;
85         return generic_security_ops;
86 }
87
88 const char **gensec_security_oids(TALLOC_CTX *mem_ctx, const char *skip) 
89 {
90         int i, j = 0;
91         const char **oid_list;
92         int num_backends;
93         const struct gensec_security_ops **ops = gensec_security_all(&num_backends);
94         if (!ops) {
95                 return NULL;
96         }
97         oid_list = talloc_array(mem_ctx, const char *, num_backends + 1);
98         if (!oid_list) {
99                 return NULL;
100         }
101         
102         for (i=0; i<num_backends; i++) {
103                 if (!ops[i]->oid) {
104                         continue;
105                 }
106                 
107                 if (skip && strcmp(skip, ops[i]->oid)==0) {
108                         continue;
109                 }
110
111                 oid_list[j] = ops[i]->oid;
112                 j++;
113         }
114         oid_list[j] = NULL;
115         return oid_list;
116 }
117
118 /**
119   Start the GENSEC system, returning a context pointer.
120   @param mem_ctx The parent TALLOC memory context.
121   @param gensec_security Returned GENSEC context pointer.
122   @note  The mem_ctx is only a parent and may be NULL.
123 */
124 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security) 
125 {
126         (*gensec_security) = talloc(mem_ctx, struct gensec_security);
127         if (!(*gensec_security)) {
128                 return NT_STATUS_NO_MEMORY;
129         }
130
131         (*gensec_security)->ops = NULL;
132
133         ZERO_STRUCT((*gensec_security)->target);
134
135         (*gensec_security)->subcontext = False;
136         (*gensec_security)->want_features = 0;
137         return NT_STATUS_OK;
138 }
139
140 /** 
141  * Start a GENSEC subcontext, with a copy of the properties of the parent
142  * @param mem_ctx The parent TALLOC memory context.
143  * @param parent The parent GENSEC context 
144  * @param gensec_security Returned GENSEC context pointer.
145  * @note Used by SPNEGO in particular, for the actual implementation mechanism
146  */
147
148 NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx, 
149                                  struct gensec_security *parent, 
150                                  struct gensec_security **gensec_security)
151 {
152         (*gensec_security) = talloc(mem_ctx, struct gensec_security);
153         if (!(*gensec_security)) {
154                 return NT_STATUS_NO_MEMORY;
155         }
156
157         (**gensec_security) = *parent;
158         (*gensec_security)->ops = NULL;
159         (*gensec_security)->private_data = NULL;
160
161         (*gensec_security)->subcontext = True;
162
163         return NT_STATUS_OK;
164 }
165
166 /**
167   Start the GENSEC system, in client mode, returning a context pointer.
168   @param mem_ctx The parent TALLOC memory context.
169   @param gensec_security Returned GENSEC context pointer.
170   @note  The mem_ctx is only a parent and may be NULL.
171 */
172 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
173 {
174         NTSTATUS status;
175         status = gensec_start(mem_ctx, gensec_security);
176         if (!NT_STATUS_IS_OK(status)) {
177                 return status;
178         }
179         (*gensec_security)->gensec_role = GENSEC_CLIENT;
180         (*gensec_security)->password_callback = NULL;
181
182         return status;
183 }
184
185 /**
186   Start the GENSEC system, in server mode, returning a context pointer.
187   @param mem_ctx The parent TALLOC memory context.
188   @param gensec_security Returned GENSEC context pointer.
189   @note  The mem_ctx is only a parent and may be NULL.
190 */
191 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
192 {
193         NTSTATUS status;
194         status = gensec_start(mem_ctx, gensec_security);
195         if (!NT_STATUS_IS_OK(status)) {
196                 return status;
197         }
198         (*gensec_security)->gensec_role = GENSEC_SERVER;
199
200         return status;
201 }
202
203 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security) 
204 {
205         NTSTATUS status;
206         DEBUG(5, ("Starting GENSEC %smechanism %s\n", 
207                   gensec_security->subcontext ? "sub" : "", 
208                   gensec_security->ops->name));
209         switch (gensec_security->gensec_role) {
210         case GENSEC_CLIENT:
211                 if (gensec_security->ops->client_start) {
212                         status = gensec_security->ops->client_start(gensec_security);
213                         if (!NT_STATUS_IS_OK(status)) {
214                                 DEBUG(1, ("Failed to start GENSEC client mech %s: %s\n",
215                                           gensec_security->ops->name, nt_errstr(status))); 
216                         }
217                         return status;
218                 }
219         case GENSEC_SERVER:
220                 if (gensec_security->ops->server_start) {
221                         status = gensec_security->ops->server_start(gensec_security);
222                         if (!NT_STATUS_IS_OK(status)) {
223                                 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
224                                           gensec_security->ops->name, nt_errstr(status))); 
225                         }
226                         return status;
227                 }
228         }
229         return NT_STATUS_INVALID_PARAMETER;
230 }
231
232 /** 
233  * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number 
234  * @param gensec_security GENSEC context pointer.
235  * @param auth_type DCERPC auth type
236  * @param auth_level DCERPC auth level 
237  */
238
239 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security, 
240                                        uint8_t auth_type, uint8_t auth_level) 
241 {
242         gensec_security->ops = gensec_security_by_authtype(auth_type);
243         if (!gensec_security->ops) {
244                 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
245                 return NT_STATUS_INVALID_PARAMETER;
246         }
247         gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
248         if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
249                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
250         } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
251                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
252                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
253         } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
254                 /* Default features */
255         } else {
256                 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n", 
257                          auth_level));
258                 return NT_STATUS_INVALID_PARAMETER;
259         }
260
261         return gensec_start_mech(gensec_security);
262 }
263
264 const char *gensec_get_name_by_authtype(uint8_t authtype) 
265 {
266         const struct gensec_security_ops *ops;
267         ops = gensec_security_by_authtype(authtype);
268         if (ops) {
269                 return ops->name;
270         }
271         return NULL;
272 }
273         
274
275 const char *gensec_get_name_by_oid(const char *oid_string) 
276 {
277         const struct gensec_security_ops *ops;
278         ops = gensec_security_by_oid(oid_string);
279         if (ops) {
280                 return ops->name;
281         }
282         return NULL;
283 }
284         
285
286 /** 
287  * Start a GENSEC sub-mechanism by OID, used in SPNEGO
288  *
289  * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
290  *       well-known #define to hook it in.
291  */
292
293 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security, 
294                                   const char *mech_oid) 
295 {
296         gensec_security->ops = gensec_security_by_oid(mech_oid);
297         if (!gensec_security->ops) {
298                 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
299                 return NT_STATUS_INVALID_PARAMETER;
300         }
301         return gensec_start_mech(gensec_security);
302 }
303
304 /** 
305  * Start a GENSEC sub-mechanism by a well know SASL name
306  *
307  */
308
309 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security, 
310                                         const char *sasl_name) 
311 {
312         gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
313         if (!gensec_security->ops) {
314                 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
315                 return NT_STATUS_INVALID_PARAMETER;
316         }
317         return gensec_start_mech(gensec_security);
318 }
319
320 /*
321   wrappers for the gensec function pointers
322 */
323 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security, 
324                               TALLOC_CTX *mem_ctx, 
325                               uint8_t *data, size_t length, 
326                               const uint8_t *whole_pdu, size_t pdu_length, 
327                               const DATA_BLOB *sig)
328 {
329         if (!gensec_security->ops->unseal_packet) {
330                 return NT_STATUS_NOT_IMPLEMENTED;
331         }
332         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
333                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
334                         return gensec_check_packet(gensec_security, mem_ctx, 
335                                                    data, length, 
336                                                    whole_pdu, pdu_length, 
337                                                    sig);
338                 }
339                 return NT_STATUS_INVALID_PARAMETER;
340         }
341
342         return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, 
343                                                    data, length, 
344                                                    whole_pdu, pdu_length, 
345                                                    sig);
346 }
347
348 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security, 
349                              TALLOC_CTX *mem_ctx, 
350                              const uint8_t *data, size_t length, 
351                              const uint8_t *whole_pdu, size_t pdu_length, 
352                              const DATA_BLOB *sig)
353 {
354         if (!gensec_security->ops->check_packet) {
355                 return NT_STATUS_NOT_IMPLEMENTED;
356         }
357         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
358                 return NT_STATUS_INVALID_PARAMETER;
359         }
360         
361         return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
362 }
363
364 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security, 
365                             TALLOC_CTX *mem_ctx, 
366                             uint8_t *data, size_t length, 
367                             const uint8_t *whole_pdu, size_t pdu_length, 
368                             DATA_BLOB *sig)
369 {
370         if (!gensec_security->ops->seal_packet) {
371                 return NT_STATUS_NOT_IMPLEMENTED;
372         }
373         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
374                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
375                         return gensec_sign_packet(gensec_security, mem_ctx, 
376                                                   data, length, 
377                                                   whole_pdu, pdu_length, 
378                                                   sig);
379                 }
380                 return NT_STATUS_INVALID_PARAMETER;
381         }
382
383         return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
384 }
385
386 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security, 
387                             TALLOC_CTX *mem_ctx, 
388                             const uint8_t *data, size_t length, 
389                             const uint8_t *whole_pdu, size_t pdu_length, 
390                             DATA_BLOB *sig)
391 {
392         if (!gensec_security->ops->sign_packet) {
393                 return NT_STATUS_NOT_IMPLEMENTED;
394         }
395         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
396                 return NT_STATUS_INVALID_PARAMETER;
397         }
398         
399         return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
400 }
401
402 size_t gensec_sig_size(struct gensec_security *gensec_security) 
403 {
404         if (!gensec_security->ops->sig_size) {
405                 return 0;
406         }
407         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
408                 return 0;
409         }
410         
411         return gensec_security->ops->sig_size(gensec_security);
412 }
413
414 NTSTATUS gensec_wrap(struct gensec_security *gensec_security, 
415                      TALLOC_CTX *mem_ctx, 
416                      const DATA_BLOB *in, 
417                      DATA_BLOB *out) 
418 {
419         if (!gensec_security->ops->wrap) {
420                 return NT_STATUS_NOT_IMPLEMENTED;
421         }
422         return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
423 }
424
425 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security, 
426                        TALLOC_CTX *mem_ctx, 
427                        const DATA_BLOB *in, 
428                        DATA_BLOB *out) 
429 {
430         if (!gensec_security->ops->unwrap) {
431                 return NT_STATUS_NOT_IMPLEMENTED;
432         }
433         return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
434 }
435
436 NTSTATUS gensec_session_key(struct gensec_security *gensec_security, 
437                             DATA_BLOB *session_key)
438 {
439         if (!gensec_security->ops->session_key) {
440                 return NT_STATUS_NOT_IMPLEMENTED;
441         }
442         return gensec_security->ops->session_key(gensec_security, session_key);
443 }
444
445 /** 
446  * Return the credentials of a logged on user, including session keys
447  * etc.
448  *
449  * Only valid after a successful authentication
450  *
451  * May only be called once per authentication.
452  *
453  */
454
455 NTSTATUS gensec_session_info(struct gensec_security *gensec_security, 
456                              struct auth_session_info **session_info)
457 {
458         if (!gensec_security->ops->session_info) {
459                 return NT_STATUS_NOT_IMPLEMENTED;
460         }
461         return gensec_security->ops->session_info(gensec_security, session_info);
462 }
463
464 /**
465  * Next state function for the GENSEC state machine
466  * 
467  * @param gensec_security GENSEC State
468  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
469  * @param in The request, as a DATA_BLOB
470  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
471  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
472  *                or NT_STATUS_OK if the user is authenticated. 
473  */
474
475 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 
476                        const DATA_BLOB in, DATA_BLOB *out) 
477 {
478         return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
479 }
480
481 /** 
482  * Set the requirement for a certain feature on the connection
483  *
484  */
485
486 void gensec_want_feature(struct gensec_security *gensec_security,
487                          uint32_t feature) 
488 {
489         gensec_security->want_features |= feature;
490 }
491
492 /** 
493  * Check the requirement for a certain feature on the connection
494  *
495  */
496
497 BOOL gensec_have_feature(struct gensec_security *gensec_security,
498                          uint32_t feature) 
499 {
500         if (!gensec_security->ops->have_feature) {
501                 return False;
502         }
503         return gensec_security->ops->have_feature(gensec_security, feature);
504 }
505
506 /** 
507  * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context 
508  *
509  */
510
511 NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials) 
512 {
513         gensec_security->credentials = talloc_reference(gensec_security, credentials);
514         return NT_STATUS_OK;
515 }
516
517 /** 
518  * Return the credentails structure associated with a GENSEC context
519  *
520  */
521
522 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security) 
523 {
524         return gensec_security->credentials;
525 }
526
527 /** 
528  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed 
529  *
530  */
531
532 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service) 
533 {
534         gensec_security->target.service = talloc_strdup(gensec_security, service);
535         if (!gensec_security->target.service) {
536                 return NT_STATUS_NO_MEMORY;
537         }
538         return NT_STATUS_OK;
539 }
540
541 /** 
542  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed 
543  *
544  */
545
546 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) 
547 {
548         gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
549         if (!gensec_security->target.hostname) {
550                 return NT_STATUS_NO_MEMORY;
551         }
552         return NT_STATUS_OK;
553 }
554
555 const char *gensec_get_target_hostname(struct gensec_security *gensec_security) 
556 {
557         if (gensec_security->target.hostname) {
558                 return gensec_security->target.hostname;
559         }
560
561         /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
562         return NULL;
563 }
564
565 const char *gensec_get_target_service(struct gensec_security *gensec_security) 
566 {
567         if (gensec_security->target.service) {
568                 return gensec_security->target.service;
569         }
570
571         return "host";
572 }
573
574 /*
575   register a GENSEC backend. 
576
577   The 'name' can be later used by other backends to find the operations
578   structure for this backend.
579 */
580 NTSTATUS gensec_register(const void *_ops)
581 {
582         const struct gensec_security_ops *ops = _ops;
583         
584         if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
585                 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
586                 return NT_STATUS_OK;
587         }
588
589         if (gensec_security_by_name(ops->name) != NULL) {
590                 /* its already registered! */
591                 DEBUG(0,("GENSEC backend '%s' already registered\n", 
592                          ops->name));
593                 return NT_STATUS_OBJECT_NAME_COLLISION;
594         }
595
596         generic_security_ops = realloc_p(generic_security_ops, 
597                                          const struct gensec_security_ops *, 
598                                          gensec_num_backends+1);
599         if (!generic_security_ops) {
600                 smb_panic("out of memory in gensec_register");
601         }
602
603         generic_security_ops[gensec_num_backends] = ops;
604
605         gensec_num_backends++;
606
607         DEBUG(3,("GENSEC backend '%s' registered\n", 
608                  ops->name));
609
610         return NT_STATUS_OK;
611 }
612
613 /*
614   return the GENSEC interface version, and the size of some critical types
615   This can be used by backends to either detect compilation errors, or provide
616   multiple implementations for different smbd compilation options in one module
617 */
618 const struct gensec_critical_sizes *gensec_interface_version(void)
619 {
620         static const struct gensec_critical_sizes critical_sizes = {
621                 GENSEC_INTERFACE_VERSION,
622                 sizeof(struct gensec_security_ops),
623                 sizeof(struct gensec_security),
624         };
625
626         return &critical_sizes;
627 }
628
629 /*
630   initialise the GENSEC subsystem
631 */
632 NTSTATUS gensec_init(void)
633 {
634         return NT_STATUS_OK;
635 }