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