r1440: GENSEC improvements:
[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
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
26 /* the list of currently registered GENSEC backends */
27 const static struct gensec_security_ops **generic_security_ops;
28 static int num_backends;
29
30 static const struct gensec_security_ops *gensec_security_by_authtype(uint8_t auth_type)
31 {
32         int i;
33         for (i=0; i < num_backends; i++) {
34                 if (generic_security_ops[i]->auth_type == auth_type) {
35                         return generic_security_ops[i];
36                 }
37         }
38
39         return NULL;
40 }
41
42 static const struct gensec_security_ops *gensec_security_by_oid(const char *oid)
43 {
44         int i;
45         for (i=0; i < num_backends; i++) {
46                 if (generic_security_ops[i]->oid &&
47                     (strcmp(generic_security_ops[i]->oid, oid) == 0)) {
48                         return generic_security_ops[i];
49                 }
50         }
51
52         return NULL;
53 }
54
55 static const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_name)
56 {
57         int i;
58         for (i=0; i < num_backends; i++) {
59                 if (generic_security_ops[i]->sasl_name 
60                     && (strcmp(generic_security_ops[i]->sasl_name, sasl_name) == 0)) {
61                         return generic_security_ops[i];
62                 }
63         }
64
65         return NULL;
66 }
67
68 static const struct gensec_security_ops *gensec_security_by_name(const char *name)
69 {
70         int i;
71         for (i=0; i < num_backends; i++) {
72                 if (generic_security_ops[i]->name 
73                     && (strcmp(generic_security_ops[i]->name, name) == 0)) {
74                         return generic_security_ops[i];
75                 }
76         }
77
78         return NULL;
79 }
80
81 const struct gensec_security_ops **gensec_security_all(int *num_backends_out)
82 {
83         *num_backends_out = num_backends;
84         return generic_security_ops;
85 }
86
87 static NTSTATUS gensec_start(struct gensec_security **gensec_security) 
88 {
89         TALLOC_CTX *mem_ctx;
90         /* awaiting a correct fix from metze */
91         if (!gensec_init()) {
92                 return NT_STATUS_INTERNAL_ERROR;
93         }
94
95         mem_ctx = talloc_init("gensec_security struct");
96         if (!mem_ctx) {
97                 return NT_STATUS_NO_MEMORY;
98         }
99
100         (*gensec_security) = talloc_p(mem_ctx, struct gensec_security);
101         if (!(*gensec_security)) {
102                 talloc_destroy(mem_ctx);
103                 return NT_STATUS_NO_MEMORY;
104         }
105
106         (*gensec_security)->mem_ctx = mem_ctx;
107         (*gensec_security)->ops = NULL;
108
109         (*gensec_security)->subcontext = False;
110         return NT_STATUS_OK;
111 }
112
113 /** 
114  * Start a GENSEC subcontext, with a copy of the properties of the parent
115  *
116  * @note Used by SPENGO in particular, for the actual implementation mechanism
117  */
118
119 NTSTATUS gensec_subcontext_start(struct gensec_security *parent, 
120                                  struct gensec_security **gensec_security)
121 {
122         (*gensec_security) = talloc_p(parent->mem_ctx, struct gensec_security);
123         if (!(*gensec_security)) {
124                 return NT_STATUS_NO_MEMORY;
125         }
126
127         (**gensec_security) = *parent;
128         (*gensec_security)->ops = NULL;
129         (*gensec_security)->private_data = NULL;
130
131         (*gensec_security)->subcontext = True;
132
133         return NT_STATUS_OK;
134 }
135
136 NTSTATUS gensec_client_start(struct gensec_security **gensec_security)
137 {
138         NTSTATUS status;
139         status = gensec_start(gensec_security);
140         if (!NT_STATUS_IS_OK(status)) {
141                 return status;
142         }
143         (*gensec_security)->gensec_role = GENSEC_CLIENT;
144         (*gensec_security)->password_callback = NULL;
145
146         ZERO_STRUCT((*gensec_security)->user);
147
148         return status;
149 }
150
151 NTSTATUS gensec_server_start(struct gensec_security **gensec_security)
152 {
153         NTSTATUS status;
154         status = gensec_start(gensec_security);
155         if (!NT_STATUS_IS_OK(status)) {
156                 return status;
157         }
158         (*gensec_security)->gensec_role = GENSEC_SERVER;
159
160         return status;
161 }
162
163 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security) 
164 {
165         NTSTATUS status;
166         switch (gensec_security->gensec_role) {
167         case GENSEC_CLIENT:
168                 if (gensec_security->ops->client_start) {
169                         status = gensec_security->ops->client_start(gensec_security);
170                         if (!NT_STATUS_IS_OK(status)) {
171                                 DEBUG(1, ("Faild to start GENSEC client mech %s: %s\n",
172                                           gensec_security->ops->name, nt_errstr(status))); 
173                         }
174                         return status;
175                 }
176         case GENSEC_SERVER:
177                 if (gensec_security->ops->server_start) {
178                         status = gensec_security->ops->server_start(gensec_security);
179                         if (!NT_STATUS_IS_OK(status)) {
180                                 DEBUG(1, ("Faild to start GENSEC server mech %s: %s\n",
181                                           gensec_security->ops->name, nt_errstr(status))); 
182                         }
183                         return status;
184                 }
185         }
186         return NT_STATUS_INVALID_PARAMETER;
187 }
188
189 /** 
190  * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number 
191  */
192
193 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security, 
194                                        uint8_t authtype) 
195 {
196         gensec_security->ops = gensec_security_by_authtype(authtype);
197         if (!gensec_security->ops) {
198                 DEBUG(3, ("Could not find GENSEC backend for authtype=%d\n", (int)authtype));
199                 return NT_STATUS_INVALID_PARAMETER;
200         }
201         return gensec_start_mech(gensec_security);
202 }
203
204 /** 
205  * Start a GENSEC sub-mechanism by OID, used in SPNEGO
206  *
207  * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
208  *       well-known #define to hook it in.
209  */
210
211 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security, 
212                                   const char *mech_oid) 
213 {
214         gensec_security->ops = gensec_security_by_oid(mech_oid);
215         if (!gensec_security->ops) {
216                 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
217                 return NT_STATUS_INVALID_PARAMETER;
218         }
219         return gensec_start_mech(gensec_security);
220 }
221
222 /** 
223  * Start a GENSEC sub-mechanism by a well know SASL name
224  *
225  */
226
227 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security, 
228                                         const char *sasl_name) 
229 {
230         gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
231         if (!gensec_security->ops) {
232                 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
233                 return NT_STATUS_INVALID_PARAMETER;
234         }
235         return gensec_start_mech(gensec_security);
236 }
237
238 /*
239   wrappers for the gensec function pointers
240 */
241 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security, 
242                               TALLOC_CTX *mem_ctx, 
243                               uint8_t *data, size_t length, DATA_BLOB *sig)
244 {
245         if (!gensec_security->ops->unseal_packet) {
246                 return NT_STATUS_NOT_IMPLEMENTED;
247         }
248         return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, data, length, sig);
249 }
250
251 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security, 
252                              TALLOC_CTX *mem_ctx, 
253                              const uint8_t *data, size_t length, 
254                              const DATA_BLOB *sig)
255 {
256         if (!gensec_security->ops->check_packet) {
257                 return NT_STATUS_NOT_IMPLEMENTED;
258         }
259         return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, sig);
260 }
261
262 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security, 
263                             TALLOC_CTX *mem_ctx, 
264                             uint8_t *data, size_t length, 
265                             DATA_BLOB *sig)
266 {
267         if (!gensec_security->ops->seal_packet) {
268                 return NT_STATUS_NOT_IMPLEMENTED;
269         }
270         return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, sig);
271 }
272
273 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security, 
274                             TALLOC_CTX *mem_ctx, 
275                             const uint8_t *data, size_t length, 
276                             DATA_BLOB *sig)
277 {
278         if (!gensec_security->ops->sign_packet) {
279                 return NT_STATUS_NOT_IMPLEMENTED;
280         }
281         return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, sig);
282 }
283
284 NTSTATUS gensec_session_key(struct gensec_security *gensec_security, 
285                             DATA_BLOB *session_key)
286 {
287         if (!gensec_security->ops->session_key) {
288                 return NT_STATUS_NOT_IMPLEMENTED;
289         }
290         return gensec_security->ops->session_key(gensec_security, session_key);
291 }
292
293 /** 
294  * Return the credentials of a logged on user, including session keys
295  * etc.
296  *
297  * Only valid after a successful authentication
298  *
299  * May only be called once per authentication.
300  *
301  */
302
303 NTSTATUS gensec_session_info(struct gensec_security *gensec_security, 
304                              struct auth_session_info **session_info)
305 {
306         return gensec_security->ops->session_info(gensec_security, session_info);
307 }
308
309 /**
310  * Next state function for the GENSEC state machine
311  * 
312  * @param gensec_security GENSEC State
313  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
314  * @param in The request, as a DATA_BLOB
315  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
316  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
317  *                or NT_STATUS_OK if the user is authenticated. 
318  */
319
320 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 
321                        const DATA_BLOB in, DATA_BLOB *out) 
322 {
323         return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
324 }
325
326 void gensec_end(struct gensec_security **gensec_security)
327 {
328         if ((*gensec_security)->ops) {
329                 (*gensec_security)->ops->end(*gensec_security);
330         }
331         (*gensec_security)->private_data = NULL;
332
333         if (!(*gensec_security)->subcontext) {
334                 /* don't destory this if this is a subcontext - it belongs to the parent */
335                 talloc_destroy((*gensec_security)->mem_ctx);
336         }
337         gensec_security = NULL;
338 }
339
340 /** 
341  * Set a username on a GENSEC context - ensures it is talloc()ed 
342  *
343  */
344
345 NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user) 
346 {
347         gensec_security->user.name = talloc_strdup(gensec_security->mem_ctx, user);
348         if (!gensec_security->user.name) {
349                 return NT_STATUS_NO_MEMORY;
350         }
351         return NT_STATUS_OK;
352 }
353
354 /** 
355  * Set a domain on a GENSEC context - ensures it is talloc()ed 
356  *
357  */
358
359 NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain) 
360 {
361         gensec_security->user.domain = talloc_strdup(gensec_security->mem_ctx, domain);
362         if (!gensec_security->user.domain) {
363                 return NT_STATUS_NO_MEMORY;
364         }
365         return NT_STATUS_OK;
366 }
367
368 /** 
369  * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
370  * not do a callback
371  *
372  */
373
374 NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
375                              const char *password) 
376 {
377         gensec_security->user.password = talloc_strdup(gensec_security->mem_ctx, password);
378         if (!gensec_security->user.password) {
379                 return NT_STATUS_NO_MEMORY;
380         }
381         return NT_STATUS_OK;
382 }
383
384 /** 
385  * Set a kerberos realm on a GENSEC context - ensures it is talloc()ed 
386  *
387  */
388
389 NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *realm) 
390 {
391         gensec_security->user.realm = talloc_strdup(gensec_security->mem_ctx, realm);
392         if (!gensec_security->user.realm) {
393                 return NT_STATUS_NO_MEMORY;
394         }
395         return NT_STATUS_OK;
396 }
397
398 /** 
399  * Set the target principal name (if already known) on a GENSEC context - ensures it is talloc()ed 
400  *
401  */
402
403 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal) 
404 {
405         gensec_security->target.principal = talloc_strdup(gensec_security->mem_ctx, principal);
406         if (!gensec_security->target.principal) {
407                 return NT_STATUS_NO_MEMORY;
408         }
409         return NT_STATUS_OK;
410 }
411
412 /** 
413  * Set a password callback, if the gensec module we use demands a password
414  */
415
416 void gensec_set_password_callback(struct gensec_security *gensec_security, 
417                                   gensec_password_callback callback, void *callback_private_data) 
418 {
419         gensec_security->password_callback = callback;
420         gensec_security->password_callback_private = callback_private_data;
421 }
422
423 /**
424  * Get (or call back for) a password.
425  */
426
427 NTSTATUS gensec_get_password(struct gensec_security *gensec_security,
428                              TALLOC_CTX *mem_ctx, 
429                              char **password) 
430 {
431         if (gensec_security->user.password) {
432                 *password = talloc_strdup(mem_ctx, gensec_security->user.password);
433                 if (!*password) {
434                         return NT_STATUS_NO_MEMORY;
435                 } else {
436                         return NT_STATUS_OK;
437                 }
438         }
439         if (!gensec_security->password_callback) {
440                 return NT_STATUS_INVALID_PARAMETER;
441         }
442         return gensec_security->password_callback(gensec_security, mem_ctx, password);
443 }
444
445 /*
446   register a GENSEC backend. 
447
448   The 'name' can be later used by other backends to find the operations
449   structure for this backend.
450 */
451 static NTSTATUS gensec_register(const void *_ops)
452 {
453         const struct gensec_security_ops *ops = _ops;
454         
455         if (gensec_security_by_name(ops->name) != NULL) {
456                 /* its already registered! */
457                 DEBUG(0,("GENSEC backend '%s' already registered\n", 
458                          ops->name));
459                 return NT_STATUS_OBJECT_NAME_COLLISION;
460         }
461
462         generic_security_ops = Realloc(generic_security_ops, sizeof(generic_security_ops[0]) * (num_backends+1));
463         if (!generic_security_ops) {
464                 smb_panic("out of memory in gensec_register");
465         }
466
467         generic_security_ops[num_backends] = ops;
468
469         num_backends++;
470
471         DEBUG(3,("GENSEC backend '%s' registered\n", 
472                  ops->name));
473
474         return NT_STATUS_OK;
475 }
476
477 /*
478   return the GENSEC interface version, and the size of some critical types
479   This can be used by backends to either detect compilation errors, or provide
480   multiple implementations for different smbd compilation options in one module
481 */
482 const struct gensec_critical_sizes *gensec_interface_version(void)
483 {
484         static const struct gensec_critical_sizes critical_sizes = {
485                 GENSEC_INTERFACE_VERSION,
486                 sizeof(struct gensec_security_ops),
487                 sizeof(struct gensec_security),
488         };
489
490         return &critical_sizes;
491 }
492
493 /*
494   initialise the GENSEC subsystem
495 */
496 BOOL gensec_init(void)
497 {
498         static BOOL initialised;
499         NTSTATUS status;
500
501         /* this is *completly* the wrong way to do this */
502         if (initialised) {
503                 return True;
504         }
505
506         status = register_subsystem("gensec", gensec_register); 
507         if (!NT_STATUS_IS_OK(status)) {
508                 return False;
509         }
510
511         /* FIXME: Perhaps panic if a basic backend, such as NTLMSSP, fails to initialise? */
512         gensec_ntlmssp_init();
513 #if 0
514         gensec_krb5_init();
515 #endif
516         gensec_spnego_init();
517         gensec_dcerpc_schannel_init();
518
519         initialised = True;
520         DEBUG(3,("GENSEC subsystem version %d initialised\n", GENSEC_INTERFACE_VERSION));
521         return True;
522 }