1 /* pluginviewer.c -- Plugin Viewer for CMU SASL
2 * Alexey Melnikov, Isode Ltd.
4 * $Id: pluginviewer.c,v 1.4 2006/04/26 15:34:34 mel Exp $
7 * Copyright (c) 2004 Carnegie Mellon University. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
21 * 3. The name "Carnegie Mellon University" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission. For permission or any other legal
24 * details, please contact
25 * Office of Technology Transfer
26 * Carnegie Mellon University
28 * Pittsburgh, PA 15213-3890
29 * (412) 268-4387, fax: (412) 268-7395
30 * tech-transfer@andrew.cmu.edu
32 * 4. Redistributions of any form whatsoever must retain the following
34 * "This product includes software developed by Computing Services
35 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
37 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
38 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
39 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
40 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
42 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
43 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
52 __declspec(dllimport) char *optarg;
53 __declspec(dllimport) int optind;
54 __declspec(dllimport) int getsubopt(char **optionp, const char * const *tokens, char **valuep);
56 # include <netinet/in.h>
64 #include <parse_cmd_line.h>
65 #define MAX_ARGC (100)
66 int xxx_main(int argc, char *argv[]);
72 SIOUXSettings.asktosaveonclose = 0;
73 SIOUXSettings.showstatusline = 1;
74 argc=parse_cmd_line(MAX_ARGC,argv,sizeof(line),line);
75 return xxx_main(argc,argv);
87 #ifndef HAVE_GETSUBOPT
88 int getsubopt(char **optionp, const char * const *tokens, char **valuep);
92 build_ident[] = "$Build: pluginviewer " PACKAGE "-" VERSION " $";
94 static const char *progname = NULL;
95 /* SASL authentication methods (client or server side). NULL means all. */
96 static char *mech = NULL;
97 /* auxprop methods. NULL means all. */
98 static char *auxprop_mech = NULL;
100 #define N_CALLBACKS (16)
102 #define NOT_NULL (void *) -1
104 #define SAMPLE_SEC_BUF_SIZE (2048)
106 static const char *bit_subopts[] = {
114 static const char *ext_subopts[] = {
115 #define OPT_EXT_SSF (0)
117 #define OPT_EXT_ID (1)
122 static const char *flag_subopts[] = {
123 #define OPT_NOPLAIN (0)
125 #define OPT_NOACTIVE (1)
127 #define OPT_NODICT (2)
129 #define OPT_FORWARDSEC (3)
131 #define OPT_NOANONYMOUS (4)
133 #define OPT_PASSCRED (5)
138 static const char *ip_subopts[] = {
139 #define OPT_IP_LOCAL (0)
141 #define OPT_IP_REMOTE (1)
146 /* Whitespace separated list of mechanisms to allow (e.g. 'plain otp').
147 Used to restrict the mechanisms to a subset of the installed plugins.
148 Default: NULL (i.e. all available) */
149 #define SASL_OPT_MECH_LIST "mech_list"
150 /* Name of canon_user plugin to use, default is "INTERNAL" */
151 #define SASL_OPT_CANON_USER_PLUGIN "canon_user_plugin"
152 /* Name of auxiliary plugin to use, you may specify a space-separated list
153 of plugin names, and the plugins will be queried in order. Default is NULL (i.e. query all) */
154 #define SASL_OPT_AUXPROP_PLUGIN "auxprop_plugin"
156 static sasl_conn_t *server_conn = NULL;
157 static sasl_conn_t *client_conn = NULL;
163 sasl_dispose(&server_conn);
166 sasl_dispose(&client_conn);
171 sasl_my_log(void *context __attribute__((unused)),
178 return SASL_BADPARAM;
193 fprintf(stderr, "%s: SASL %s: %s\n",
194 progname, label, message);
200 getpath(void *context,
203 const char *searchpath = (const char *) context;
206 return SASL_BADPARAM;
221 const char *plugin_name,
227 if (strcasecmp (option, SASL_OPT_MECH_LIST) == 0) {
228 /* Whitespace separated list of mechanisms to allow (e.g. 'plain otp').
229 Used to restrict the mechanisms to a subset of the installed plugins.
230 Default: NULL (i.e. all available) */
231 if (result != NULL) {
236 /* This might be NULL, which means "all mechanisms" */
237 *len = mech ? strlen(mech) : 0;
248 sasldebug(int why, const char *what, const char *errstr)
250 fprintf(stderr, "%s: %s: %s",
253 sasl_errstring(why, NULL, NULL));
255 fprintf(stderr, " (%s)\n", errstr);
262 saslfail(int why, const char *what, const char *errstr)
264 sasldebug(why, what, errstr);
266 /* Call sasl_done twice - one for the client side SASL and
267 one for the server side. */
274 fail(const char *what)
276 fprintf(stderr, "%s: %s\n",
288 /* Produce a space separated list of installed mechanisms */
290 list_installed_server_mechanisms (
291 server_sasl_mechanism_t *m,
292 sasl_info_callback_stage_t stage,
296 char ** list_of_mechs = (char **) rock;
299 if (stage == SASL_INFO_LIST_START || stage == SASL_INFO_LIST_END) {
303 if (m->plug != NULL) {
304 if (*list_of_mechs == NULL) {
305 *list_of_mechs = strdup(m->plug->mech_name);
307 /* This is suboptimal, but works */
308 new_list = malloc (strlen(*list_of_mechs) + strlen(m->plug->mech_name) + 2);
309 sprintf (new_list, "%s %s", *list_of_mechs, m->plug->mech_name);
310 free (*list_of_mechs);
311 *list_of_mechs = new_list;
316 /* Produce a space separated list of installed mechanisms */
318 list_installed_client_mechanisms (
319 client_sasl_mechanism_t *m,
320 sasl_info_callback_stage_t stage,
324 char ** list_of_mechs = (char **) rock;
327 if (stage == SASL_INFO_LIST_START || stage == SASL_INFO_LIST_END) {
331 if (m->plug != NULL) {
332 if (*list_of_mechs == NULL) {
333 *list_of_mechs = strdup(m->plug->mech_name);
335 /* This is suboptimal, but works */
336 new_list = malloc (strlen(*list_of_mechs) + strlen(m->plug->mech_name) + 2);
337 sprintf (new_list, "%s %s", *list_of_mechs, m->plug->mech_name);
338 free (*list_of_mechs);
339 *list_of_mechs = new_list;
344 /* Produce a space separated list of installed mechanisms */
346 list_installed_auxprop_mechanisms (
347 sasl_auxprop_plug_t *m,
348 sasl_info_callback_stage_t stage,
352 char ** list_of_mechs = (char **) rock;
355 if (stage == SASL_INFO_LIST_START || stage == SASL_INFO_LIST_END) {
359 if (*list_of_mechs == NULL) {
360 *list_of_mechs = strdup(m->name);
362 /* This is suboptimal, but works */
363 new_list = malloc (strlen(*list_of_mechs) + strlen(m->name) + 2);
364 sprintf (new_list, "%s %s", *list_of_mechs, m->name);
365 free (*list_of_mechs);
366 *list_of_mechs = new_list;
371 main(int argc, char *argv[])
376 sasl_security_properties_t secprops;
377 sasl_ssf_t extssf = 0;
378 const char *ext_authid = NULL;
379 char *options, *value;
380 const char *available_mechs = NULL;
383 sasl_callback_t callbacks[N_CALLBACKS], *callback;
384 char *searchpath = NULL;
385 char *service = "test";
386 char * list_of_server_mechs = NULL;
387 char * list_of_client_mechs = NULL;
388 char * list_of_auxprop_mechs = NULL;
389 int list_all_plugins = 1; /* By default we list all plugins */
390 int list_client_auth_plugins = 0;
391 int list_server_auth_plugins = 0;
392 int list_auxprop_plugins = 0;
395 /* initialize winsock */
398 result = WSAStartup( MAKEWORD(2, 0), &wsaData );
400 saslfail(SASL_FAIL, "Initializing WinSockets", NULL);
404 progname = strrchr(argv[0], HIER_DELIMITER);
411 /* Init defaults... */
412 memset(&secprops, 0L, sizeof(secprops));
413 secprops.maxbufsize = SAMPLE_SEC_BUF_SIZE;
414 secprops.max_ssf = UINT_MAX;
416 while ((c = getopt(argc, argv, "acshb:e:m:f:p:x:?")) != EOF)
419 list_auxprop_plugins = 1;
420 list_all_plugins = 0;
424 auxprop_mech = optarg;
428 list_client_auth_plugins = 1;
429 list_all_plugins = 0;
433 list_server_auth_plugins = 1;
434 list_all_plugins = 0;
439 while (*options != '\0') {
440 switch(getsubopt(&options, (const char * const *)bit_subopts, &value)) {
445 secprops.min_ssf = atoi(value);
452 secprops.max_ssf = atoi(value);
464 while (*options != '\0') {
465 switch(getsubopt(&options, (const char * const *)ext_subopts, &value)) {
470 extssf = atoi(value);
493 while (*options != '\0') {
494 switch(getsubopt(&options, (const char * const *)flag_subopts, &value)) {
496 secprops.security_flags |= SASL_SEC_NOPLAINTEXT;
499 secprops.security_flags |= SASL_SEC_NOACTIVE;
502 secprops.security_flags |= SASL_SEC_NODICTIONARY;
505 secprops.security_flags |= SASL_SEC_FORWARD_SECRECY;
507 case OPT_NOANONYMOUS:
508 secprops.security_flags |= SASL_SEC_NOANONYMOUS;
511 secprops.security_flags |= SASL_SEC_PASS_CREDENTIALS;
517 if (value) errflag = 1;
525 default: /* unknown flag */
530 if (optind != argc) {
531 /* We don't *have* extra arguments */
536 fprintf(stderr, "%s: Usage: %s [-a] [-s] [-c] [-b min=N,max=N] [-e ssf=N,id=ID] [-m MECHS] [-x AUXPROP_MECH] [-f FLAGS] [-i local=IP,remote=IP] [-p PATH]\n"
537 "\t-a\tlist auxprop plugins\n"
538 "\t-s\tlist server authentication (SASL) plugins\n"
539 "\t-s\tlist client authentication (SASL) plugins\n"
540 "\t-b ...\t#bits to use for encryption\n"
541 "\t\tmin=N\tminumum #bits to use (1 => integrity)\n"
542 "\t\tmax=N\tmaximum #bits to use\n"
543 "\t-e ...\tassume external encryption\n"
544 "\t\tssf=N\texternal mech provides N bits of encryption\n"
545 "\t\tid=ID\texternal mech provides authentication id ID\n"
546 "\t-m MECHS\tforce to use one of MECHS SASL mechanism\n"
547 "\t-x AUXPROP_MECHS\tforce to use one of AUXPROP_MECHS auxprop plugins\n"
548 "\t-f ...\tset security flags\n"
549 "\t\tnoplain\t\tno plaintext password send during authentication\n"
550 "\t\tnoactive\trequire security vs. active attacks\n"
551 "\t\tnodict\t\trequire security vs. passive dictionary attacks\n"
552 "\t\tforwardsec\trequire forward secrecy\n"
553 "\t\tmaximum\t\trequire all security flags\n"
554 "\t\tpasscred\tattempt to pass client credentials\n"
556 "\t-p PATH\tsemicolon-separated search path for mechanisms\n",
558 "\t-p PATH\tcolon-seperated search path for mechanisms\n",
564 /* Fill in the callbacks that we're providing... */
565 callback = callbacks;
568 callback->id = SASL_CB_LOG;
569 callback->proc = &sasl_my_log;
570 callback->context = NULL;
575 callback->id = SASL_CB_GETPATH;
576 callback->proc = &getpath;
577 callback->context = searchpath;
582 callback->id = SASL_CB_GETOPT;
583 callback->proc = &sasl_getopt;
584 callback->context = NULL;
587 /* The following callbacks are for a client connection only.
588 We reuse the same callbacks variable and the server side doesn't like
589 proc == NULL. So we just put something there, != NULL! */
590 callback->id = SASL_CB_AUTHNAME;
591 callback->proc = NOT_NULL;
592 callback->context = NULL;
596 callback->id = SASL_CB_PASS;
597 callback->proc = NOT_NULL;
598 callback->context = NULL;
602 callback->id = SASL_CB_LIST_END;
603 callback->proc = NULL;
604 callback->context = NULL;
607 /* FIXME: In general case this is not going to work of course,
608 as some plugins will need more callbacks then others. */
609 if (N_CALLBACKS < callback - callbacks) {
610 fail("Out of callback space; recompile with larger N_CALLBACKS");
613 result = sasl_client_init(callbacks);
614 if (result != SASL_OK) {
615 saslfail(result, "Initializing client side of libsasl", NULL);
618 result = sasl_server_init(callbacks, "pluginviewer");
619 if (result != SASL_OK) {
620 saslfail(result, "Initializing server side of libsasl", NULL);
623 if (list_all_plugins || list_server_auth_plugins) {
625 /* SASL server plugins */
626 result = sasl_server_new(service,
627 /* Has to be any non NULL value */
628 "test.example.com", /* localdomain */
629 NULL, /* userdomain */
635 if (result != SASL_OK) {
636 saslfail(result, "Allocating sasl connection state (server side)", NULL);
639 /* The following two options are required for SSF */
641 result = sasl_setprop(server_conn,
645 if (result != SASL_OK) {
646 saslfail(result, "Setting external SSF", NULL);
651 result = sasl_setprop(server_conn,
655 if (result != SASL_OK) {
656 saslfail(result, "Setting external authid", NULL);
660 result = sasl_setprop(server_conn,
664 if (result != SASL_OK) {
665 saslfail(result, "Setting security properties", NULL);
668 /* This will use getopt callback, which is using the "mech" global variable */
669 result = sasl_listmech(server_conn,
677 if (result != SASL_OK) {
678 saslfail(result, "Setting security properties", NULL);
682 list_of_server_mechs = NULL;
684 sasl_server_plugin_info (NULL, /* list all SASL mechanisms */
685 &list_installed_server_mechanisms,
686 (void *) &list_of_server_mechs);
688 printf ("Installed SASL (server side) mechanisms are:\n%s\n", list_of_server_mechs);
690 free (list_of_server_mechs);
692 /* Dump information about the requested SASL mechanism */
693 /* NOTE - available_mechs must not be freed */
694 sasl_server_plugin_info (available_mechs, NULL, NULL);
696 printf ("No server side SASL mechanisms installed\n");
700 if (list_all_plugins || list_auxprop_plugins) {
701 list_of_auxprop_mechs = NULL;
703 auxprop_plugin_info (NULL, /* list all auxprop mechanisms */
704 &list_installed_auxprop_mechanisms,
705 (void *) &list_of_auxprop_mechs);
707 printf ("Installed auxprop mechanisms are:\n%s\n", list_of_auxprop_mechs);
709 free (list_of_auxprop_mechs);
712 auxprop_plugin_info (auxprop_mech, NULL, NULL);
715 /* TODO: add listing of canonicalization plugins, if needed. */
717 if (list_all_plugins || list_client_auth_plugins) {
718 /* SASL client plugins */
719 result = sasl_client_new(service,
720 /* Has to be any non NULL value */
721 "test.example.com", /* fqdn */
728 if (result != SASL_OK) {
729 saslfail(result, "Allocating sasl connection state (client side)", NULL);
732 /* The following two options are required for SSF */
734 result = sasl_setprop(client_conn,
738 if (result != SASL_OK) {
739 saslfail(result, "Setting external SSF", NULL);
744 result = sasl_setprop(client_conn,
748 if (result != SASL_OK) {
749 saslfail(result, "Setting external authid", NULL);
753 result = sasl_setprop(client_conn,
757 if (result != SASL_OK) {
758 saslfail(result, "Setting security properties", NULL);
761 /* This will use getopt callback, which is using the "mech" global variable */
762 result = sasl_listmech(client_conn,
770 if (result != SASL_OK) {
771 saslfail(result, "Setting security properties", NULL);
775 list_of_client_mechs = NULL;
777 sasl_client_plugin_info (NULL, /* list all SASL mechanisms */
778 &list_installed_client_mechanisms,
779 (void *) &list_of_client_mechs);
781 printf ("Installed SASL (client side) mechanisms are:\n%s\n", list_of_client_mechs);
783 free (list_of_client_mechs);
786 /* Dump information about the requested SASL mechanism */
787 /* NOTE - available_mechs must not be freed */
788 sasl_client_plugin_info (available_mechs, NULL, NULL);
790 printf ("No client side SASL mechanisms installed\n");
795 /* Call sasl_done twice - one for the client side SASL and
796 one for the server side. */
804 return (EXIT_SUCCESS);