r6028: A MAJOR update to intergrate the new credentails system fully with
[samba.git] / source4 / libcli / auth / 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         }
251         if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
252                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
253                 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
254         }
255
256         return gensec_start_mech(gensec_security);
257 }
258
259 const char *gensec_get_name_by_authtype(uint8_t authtype) 
260 {
261         const struct gensec_security_ops *ops;
262         ops = gensec_security_by_authtype(authtype);
263         if (ops) {
264                 return ops->name;
265         }
266         return NULL;
267 }
268         
269
270 const char *gensec_get_name_by_oid(const char *oid_string) 
271 {
272         const struct gensec_security_ops *ops;
273         ops = gensec_security_by_oid(oid_string);
274         if (ops) {
275                 return ops->name;
276         }
277         return NULL;
278 }
279         
280
281 /** 
282  * Start a GENSEC sub-mechanism by OID, used in SPNEGO
283  *
284  * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
285  *       well-known #define to hook it in.
286  */
287
288 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security, 
289                                   const char *mech_oid) 
290 {
291         gensec_security->ops = gensec_security_by_oid(mech_oid);
292         if (!gensec_security->ops) {
293                 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
294                 return NT_STATUS_INVALID_PARAMETER;
295         }
296         return gensec_start_mech(gensec_security);
297 }
298
299 /** 
300  * Start a GENSEC sub-mechanism by a well know SASL name
301  *
302  */
303
304 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security, 
305                                         const char *sasl_name) 
306 {
307         gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
308         if (!gensec_security->ops) {
309                 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
310                 return NT_STATUS_INVALID_PARAMETER;
311         }
312         return gensec_start_mech(gensec_security);
313 }
314
315 /*
316   wrappers for the gensec function pointers
317 */
318 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security, 
319                               TALLOC_CTX *mem_ctx, 
320                               uint8_t *data, size_t length, 
321                               const uint8_t *whole_pdu, size_t pdu_length, 
322                               DATA_BLOB *sig)
323 {
324         if (!gensec_security->ops->unseal_packet) {
325                 return NT_STATUS_NOT_IMPLEMENTED;
326         }
327         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
328                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
329                         return gensec_check_packet(gensec_security, mem_ctx, 
330                                                    data, length, 
331                                                    whole_pdu, pdu_length, 
332                                                    sig);
333                 }
334                 return NT_STATUS_INVALID_PARAMETER;
335         }
336
337         return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, 
338                                                    data, length, 
339                                                    whole_pdu, pdu_length, 
340                                                    sig);
341 }
342
343 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security, 
344                              TALLOC_CTX *mem_ctx, 
345                              const uint8_t *data, size_t length, 
346                              const uint8_t *whole_pdu, size_t pdu_length, 
347                              const DATA_BLOB *sig)
348 {
349         if (!gensec_security->ops->check_packet) {
350                 return NT_STATUS_NOT_IMPLEMENTED;
351         }
352         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
353                 return NT_STATUS_INVALID_PARAMETER;
354         }
355         
356         return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
357 }
358
359 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security, 
360                             TALLOC_CTX *mem_ctx, 
361                             uint8_t *data, size_t length, 
362                             const uint8_t *whole_pdu, size_t pdu_length, 
363                             DATA_BLOB *sig)
364 {
365         if (!gensec_security->ops->seal_packet) {
366                 return NT_STATUS_NOT_IMPLEMENTED;
367         }
368         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
369                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
370                         return gensec_sign_packet(gensec_security, mem_ctx, 
371                                                   data, length, 
372                                                   whole_pdu, pdu_length, 
373                                                   sig);
374                 }
375                 return NT_STATUS_INVALID_PARAMETER;
376         }
377
378         return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
379 }
380
381 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security, 
382                             TALLOC_CTX *mem_ctx, 
383                             const uint8_t *data, size_t length, 
384                             const uint8_t *whole_pdu, size_t pdu_length, 
385                             DATA_BLOB *sig)
386 {
387         if (!gensec_security->ops->sign_packet) {
388                 return NT_STATUS_NOT_IMPLEMENTED;
389         }
390         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
391                 return NT_STATUS_INVALID_PARAMETER;
392         }
393         
394         return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
395 }
396
397 size_t gensec_sig_size(struct gensec_security *gensec_security) 
398 {
399         if (!gensec_security->ops->sig_size) {
400                 return 0;
401         }
402         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
403                 return 0;
404         }
405         
406         return gensec_security->ops->sig_size(gensec_security);
407 }
408
409 NTSTATUS gensec_wrap(struct gensec_security *gensec_security, 
410                      TALLOC_CTX *mem_ctx, 
411                      const DATA_BLOB *in, 
412                      DATA_BLOB *out) 
413 {
414         if (!gensec_security->ops->wrap) {
415                 return NT_STATUS_NOT_IMPLEMENTED;
416         }
417         return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
418 }
419
420 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security, 
421                        TALLOC_CTX *mem_ctx, 
422                        const DATA_BLOB *in, 
423                        DATA_BLOB *out) 
424 {
425         if (!gensec_security->ops->unwrap) {
426                 return NT_STATUS_NOT_IMPLEMENTED;
427         }
428         return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
429 }
430
431 NTSTATUS gensec_session_key(struct gensec_security *gensec_security, 
432                             DATA_BLOB *session_key)
433 {
434         if (!gensec_security->ops->session_key) {
435                 return NT_STATUS_NOT_IMPLEMENTED;
436         }
437         return gensec_security->ops->session_key(gensec_security, session_key);
438 }
439
440 /** 
441  * Return the credentials of a logged on user, including session keys
442  * etc.
443  *
444  * Only valid after a successful authentication
445  *
446  * May only be called once per authentication.
447  *
448  */
449
450 NTSTATUS gensec_session_info(struct gensec_security *gensec_security, 
451                              struct auth_session_info **session_info)
452 {
453         if (!gensec_security->ops->session_info) {
454                 return NT_STATUS_NOT_IMPLEMENTED;
455         }
456         return gensec_security->ops->session_info(gensec_security, session_info);
457 }
458
459 /**
460  * Next state function for the GENSEC state machine
461  * 
462  * @param gensec_security GENSEC State
463  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
464  * @param in The request, as a DATA_BLOB
465  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
466  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
467  *                or NT_STATUS_OK if the user is authenticated. 
468  */
469
470 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 
471                        const DATA_BLOB in, DATA_BLOB *out) 
472 {
473         return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
474 }
475
476 /** 
477  * Set the requirement for a certain feature on the connection
478  *
479  */
480
481 void gensec_want_feature(struct gensec_security *gensec_security,
482                          uint32_t feature) 
483 {
484         gensec_security->want_features |= feature;
485 }
486
487 /** 
488  * Check the requirement for a certain feature on the connection
489  *
490  */
491
492 BOOL gensec_have_feature(struct gensec_security *gensec_security,
493                          uint32_t feature) 
494 {
495         if (!gensec_security->ops->have_feature) {
496                 return False;
497         }
498         return gensec_security->ops->have_feature(gensec_security, feature);
499 }
500
501 /** 
502  * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context 
503  *
504  */
505
506 NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials) 
507 {
508         gensec_security->credentials = talloc_reference(gensec_security, credentials);
509         return NT_STATUS_OK;
510 }
511
512 /** 
513  * Return the credentails structure associated with a GENSEC context
514  *
515  */
516
517 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security) 
518 {
519         return gensec_security->credentials;
520 }
521
522 /** 
523  * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed 
524  *
525  */
526
527 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service) 
528 {
529         gensec_security->target.service = talloc_strdup(gensec_security, service);
530         if (!gensec_security->target.service) {
531                 return NT_STATUS_NO_MEMORY;
532         }
533         return NT_STATUS_OK;
534 }
535
536 /** 
537  * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed 
538  *
539  */
540
541 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname) 
542 {
543         gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
544         if (!gensec_security->target.hostname) {
545                 return NT_STATUS_NO_MEMORY;
546         }
547         return NT_STATUS_OK;
548 }
549
550 const char *gensec_get_target_hostname(struct gensec_security *gensec_security) 
551 {
552         if (gensec_security->target.hostname) {
553                 return gensec_security->target.hostname;
554         }
555
556         /* TODO: Add a 'set sockaddr' call, and do a reverse lookup */
557         return NULL;
558 }
559
560 const char *gensec_get_target_service(struct gensec_security *gensec_security) 
561 {
562         if (gensec_security->target.service) {
563                 return gensec_security->target.service;
564         }
565
566         return "host";
567 }
568
569 /*
570   register a GENSEC backend. 
571
572   The 'name' can be later used by other backends to find the operations
573   structure for this backend.
574 */
575 NTSTATUS gensec_register(const void *_ops)
576 {
577         const struct gensec_security_ops *ops = _ops;
578         
579         if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
580                 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
581                 return NT_STATUS_OK;
582         }
583
584         if (gensec_security_by_name(ops->name) != NULL) {
585                 /* its already registered! */
586                 DEBUG(0,("GENSEC backend '%s' already registered\n", 
587                          ops->name));
588                 return NT_STATUS_OBJECT_NAME_COLLISION;
589         }
590
591         generic_security_ops = realloc_p(generic_security_ops, 
592                                          const struct gensec_security_ops *, 
593                                          gensec_num_backends+1);
594         if (!generic_security_ops) {
595                 smb_panic("out of memory in gensec_register");
596         }
597
598         generic_security_ops[gensec_num_backends] = ops;
599
600         gensec_num_backends++;
601
602         DEBUG(3,("GENSEC backend '%s' registered\n", 
603                  ops->name));
604
605         return NT_STATUS_OK;
606 }
607
608 /*
609   return the GENSEC interface version, and the size of some critical types
610   This can be used by backends to either detect compilation errors, or provide
611   multiple implementations for different smbd compilation options in one module
612 */
613 const struct gensec_critical_sizes *gensec_interface_version(void)
614 {
615         static const struct gensec_critical_sizes critical_sizes = {
616                 GENSEC_INTERFACE_VERSION,
617                 sizeof(struct gensec_security_ops),
618                 sizeof(struct gensec_security),
619         };
620
621         return &critical_sizes;
622 }
623
624 /*
625   initialise the GENSEC subsystem
626 */
627 NTSTATUS gensec_init(void)
628 {
629         return NT_STATUS_OK;
630 }