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