Initial release, version 0.0.0.
[gsasl.git] / src / gsasl.c
blob83671663a9ca52a7ae33a1da7b07fe6eded01afe
1 /* gsasl.c command line interface to libgsasl
2 * Copyright (C) 2002 Simon Josefsson
4 * This file is part of libgsasl.
6 * Libgsasl is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Libgsasl is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with libgsasl; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <stdio.h>
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #ifdef HAVE_NETDB_H
30 #include <netdb.h>
31 #endif
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif
35 #ifdef HAVE_LOCALE_H
36 #include <locale.h>
37 #endif
38 #if HAVE_STRING_H
39 # if !STDC_HEADERS && HAVE_MEMORY_H
40 # include <memory.h>
41 # endif
42 # include <string.h>
43 #endif
44 #if HAVE_STRINGS_H
45 # include <strings.h>
46 #endif
47 #include <argp.h>
48 #include <gsasl.h>
50 #include "callbacks.h"
52 #include "gettext.h"
53 #ifdef ENABLE_NLS
54 extern char *_gsasl_gettext (const char *str);
55 #define _(String) _gsasl_gettext (String)
56 #define gettext_noop(String) String
57 #define N_(String) gettext_noop (String)
58 #endif
60 #define MAX_LINE_LENGTH BUFSIZ
62 enum {
63 OPTION_CLIENT_MECHANISMS = 300,
64 OPTION_SERVER_MECHANISMS,
65 OPTION_PASSCODE,
66 OPTION_SERVICE,
67 OPTION_HOSTNAME,
68 OPTION_SERVICENAME,
69 OPTION_ENABLE_CRAM_MD5_VALIDATE,
70 OPTION_DISABLE_CLEARTEXT_VALIDATE
73 const char *argp_program_version = "gsasl (" PACKAGE_STRING ")";
74 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
76 int mode;
77 int listmode;
79 int silent;
80 int verbose;
81 char *anonymous_token;
82 char *authentication_id;
83 char *authorization_id;
84 char *password;
85 char *passcode;
86 char *mechanism;
87 char *service;
88 char *hostname;
89 char *servicename;
90 char **realms;
91 size_t nrealms;
92 int enable_cram_md5_validate;
93 int disable_cleartext_validate;
94 int maxbuf;
96 static error_t
97 parse_opt (int key, char *arg, struct argp_state *state)
99 switch (key)
101 case 'q':
102 silent = 1;
103 break;
105 case 'v':
106 verbose = 1;
107 break;
109 case 'a':
110 authentication_id = strdup(arg);
111 break;
113 case 'z':
114 authorization_id = strdup(arg);
115 break;
117 case 'p':
118 password = strdup(arg);
119 break;
121 case 'n':
122 anonymous_token = strdup(arg);
123 break;
125 case 'm':
126 mechanism = strdup(arg);
127 break;
129 case 'r':
130 if (nrealms == 0)
131 realms = malloc(sizeof(*realms));
132 else
133 realms = realloc(realms, sizeof(*realms)*(nrealms+1));
134 if (realms == NULL)
135 argp_error (state, gsasl_strerror (GSASL_MALLOC_ERROR));
136 realms[nrealms++] = strdup(arg);
137 break;
139 case 'x':
140 maxbuf = strtoul(arg, NULL, 0);
141 break;
143 case OPTION_PASSCODE:
144 passcode = strdup(arg);
145 break;
147 case OPTION_SERVICE:
148 service = strdup(arg);
149 break;
151 case OPTION_HOSTNAME:
152 hostname = strdup(arg);
153 break;
155 case OPTION_SERVICENAME:
156 servicename = strdup(arg);
157 break;
159 case OPTION_ENABLE_CRAM_MD5_VALIDATE:
160 enable_cram_md5_validate = 1;
161 break;
163 case OPTION_DISABLE_CLEARTEXT_VALIDATE:
164 disable_cleartext_validate = 1;
165 break;
167 case 'c':
168 case 's':
169 mode = key;
170 break;
172 case OPTION_CLIENT_MECHANISMS:
173 case OPTION_SERVER_MECHANISMS:
174 listmode = key;
175 break;
177 case ARGP_KEY_ARG:
178 argp_error (state, "too many arguments: `%s'", arg);
179 break;
181 case ARGP_KEY_END:
182 if (mode == 0 && listmode == 0)
184 argp_state_help (state, stdout, ARGP_HELP_STD_HELP);
185 exit(0);
187 break;
189 default:
190 return ARGP_ERR_UNKNOWN;
193 return 0;
196 static struct argp_option options[] = {
198 {0, 0, 0, 0, "Commands:"},
200 {"client", 'c', 0, 0, "Act as client."},
202 {"server", 's', 0, 0, "Act as server."},
204 {"client-mechanisms", OPTION_CLIENT_MECHANISMS, 0, 0,
205 "Write name of supported client mechanisms separated by space to stdout."},
207 {"server-mechanisms", OPTION_SERVER_MECHANISMS, 0, 0,
208 "Write name of supported server mechanisms separated by space to stdout."},
210 {0, 0, 0, 0, "SASL options (prompted for if unspecified):", 500},
212 {"anonymous-token", 'n', "STRING", 0,
213 "Token for anonymous authentication (usually mail address)."},
215 {"authentication-id", 'a', "STRING", 0,
216 "Identity of credential owner."},
218 {"authorization-id", 'z', "STRING", 0,
219 "Identity to request service for."},
221 {"password", 'p', "STRING", 0,
222 "Password for authentication."},
224 {"mechanism", 'm', "STRING", 0,
225 "Mechanism to use."},
227 {"realm", 'r', "STRING", 0,
228 "Realm (may be given more than once iff server). Defaults to hostname."},
230 {"maxbuf", 'x', "NUMBER", 0,
231 "Indicate maximum buffer size (DIGEST-MD5 only)."},
233 {"passcode", OPTION_PASSCODE, "NUMBER", 0,
234 "Passcode for authentication (SECURID only)."},
236 {"service", OPTION_SERVICE, "STRING", 0,
237 "Set the requested service name (should be a registered GSSAPI host "
238 "based service name)."},
240 {"hostname", OPTION_HOSTNAME, "STRING", 0,
241 "Set the name of the server with the requested service."},
243 {"service-name", OPTION_SERVICENAME, "STRING", 0,
244 "Set the generic server name in case of a replicated server "
245 "(DIGEST-MD5 only)."},
247 {"enable-cram-md5-validate", OPTION_ENABLE_CRAM_MD5_VALIDATE, 0, 0,
248 "Validate CRAM-MD5 challenge and response interactively."},
250 {"disable-cleartext-validate", OPTION_DISABLE_CLEARTEXT_VALIDATE, 0, 0,
251 "Disable cleartext validate hook, forcing server to prompt for password."},
253 {0, 0, 0, 0, "Other options:", 1000},
255 {"verbose", 'v', 0, 0, "Produce verbose output."},
257 {"quiet", 'q', 0, 0, "Don't produce any diagnostic output."},
259 {"silent", 0, 0, OPTION_ALIAS},
264 static struct argp argp = {
265 options,
266 parse_opt,
268 "GSASL -- Command line interface to libgsasl"
272 main (int argc, char *argv[])
274 Gsasl_ctx *ctx = NULL;
275 int res;
277 setlocale (LC_ALL, "");
279 argp_parse (&argp, argc, argv, 0, 0, NULL);
281 res = gsasl_init (&ctx);
282 if (res != GSASL_OK)
284 fprintf(stderr, _("GSASL error (%d): %s\n"), res, gsasl_strerror(res));
285 return 1;
288 if (maxbuf != 0)
289 gsasl_client_callback_maxbuf_set (ctx, client_callback_maxbuf);
290 gsasl_client_callback_qop_set (ctx, client_callback_qop);
291 gsasl_client_callback_anonymous_set (ctx, client_callback_anonymous);
292 gsasl_client_callback_authentication_id_set (ctx,
293 client_callback_authentication_id);
294 gsasl_client_callback_authorization_id_set (ctx,
295 client_callback_authorization_id);
296 gsasl_client_callback_password_set (ctx, client_callback_password);
297 gsasl_client_callback_passcode_set (ctx, client_callback_passcode);
298 gsasl_client_callback_service_set (ctx, client_callback_service);
300 gsasl_server_callback_realm_set (ctx, server_callback_realm);
301 gsasl_server_callback_qop_set (ctx, server_callback_qop);
302 if (maxbuf != 0)
303 gsasl_server_callback_maxbuf_set (ctx, server_callback_maxbuf);
304 if (enable_cram_md5_validate)
305 gsasl_server_callback_cram_md5_set (ctx, server_callback_cram_md5);
306 if (!disable_cleartext_validate)
307 gsasl_server_callback_validate_set (ctx, server_callback_validate);
308 gsasl_server_callback_retrieve_set (ctx, server_callback_retrieve);
309 gsasl_server_callback_anonymous_set (ctx, server_callback_anonymous);
310 gsasl_server_callback_external_set (ctx, server_callback_external);
311 gsasl_server_callback_service_set (ctx, server_callback_service);
312 gsasl_server_callback_gssapi_set (ctx, server_callback_gssapi);
314 if (listmode == OPTION_CLIENT_MECHANISMS ||
315 listmode == OPTION_SERVER_MECHANISMS)
317 char mechs[MAX_LINE_LENGTH];
318 size_t mechslen;
320 mechslen = sizeof(mechs);
321 if (listmode == OPTION_CLIENT_MECHANISMS)
322 res = gsasl_client_listmech (ctx, mechs, &mechslen);
323 else
324 res = gsasl_server_listmech (ctx, mechs, &mechslen);
326 if (res != GSASL_OK)
328 fprintf(stderr, _("GSASL error (%d): %s\n"), res, gsasl_strerror(res));
329 return 1;
332 if (!silent)
333 fprintf(stderr, _("This %s supports the following mechanisms:\n"),
334 listmode == OPTION_CLIENT_MECHANISMS ?
335 _("client") : _("server"));
336 fprintf(stdout, "%s\n", mechs);
339 if (mode == 'c' || mode == 's')
341 char input[MAX_LINE_LENGTH];
342 char output[MAX_LINE_LENGTH];
343 size_t output_len;
344 const char *mech;
345 Gsasl_session_ctx *xctx = NULL;
346 int res;
348 if (mechanism)
350 mech = mechanism;
352 else if (mode == 'c')
354 if (!silent)
355 fprintf(stderr, _("Input SASL mechanism supported by server:\n"));
356 input[0] = '\0';
357 fgets(input, MAX_LINE_LENGTH, stdin);
359 mech = gsasl_client_suggest_mechanism (ctx, input);
360 if (mech == NULL)
362 fprintf(stderr, _("Cannot find mechanism...\n"));
363 return 1;
366 if (!silent)
367 fprintf(stderr, _("Libgsasl wants to use:\n"));
368 fprintf(stdout, "%s\n", mech);
370 else
372 if (!silent)
373 fprintf(stderr, _("Chose SASL mechanisms:\n"));
374 input[0] = '\0';
375 fgets(input, MAX_LINE_LENGTH, stdin);
376 input[strlen(input)-1] = '\0';
378 if (!silent)
379 fprintf(stderr, _("Chosed mechanism `%s'\n"), input);
380 mech = input;
383 if (mode == 'c')
384 res = gsasl_client_start (ctx, mech, &xctx);
385 else
386 res = gsasl_server_start (ctx, mech, &xctx);
387 if (res != GSASL_OK)
389 fprintf(stderr, _("Libgsasl error (%d): %s\n"),
390 res, gsasl_strerror(res));
391 return 1;
394 input[0] = '\0';
395 output[0] = '\0';
396 output_len = sizeof(output);
399 if (mode == 'c')
400 res = gsasl_client_step_base64 (xctx, input, output, output_len);
401 else
402 res = gsasl_server_step_base64 (xctx, input, output, output_len);
404 if (res != GSASL_NEEDS_MORE)
405 break;
407 if (!silent)
408 fprintf(stderr, _("Output from %s:\n"),
409 mode == 'c' ? _("client") : _("server"));
410 fprintf(stdout, "%s\n", output);
412 if (!silent)
413 fprintf(stderr,
414 _("Enter base64 data from %s (press RET if none):\n"),
415 mode == 'c' ? _("server") : _("client"));
417 input[0] = '\0';
418 fgets(input, MAX_LINE_LENGTH, stdin);
420 while (res == GSASL_NEEDS_MORE);
422 if (res != GSASL_OK)
424 fprintf(stderr, _("Libgsasl error (%d): %s\n"),
425 res, gsasl_strerror(res));
426 return 1;
429 if (!silent)
431 if (mode == 'c')
432 fprintf(stderr, _("Client finished (server trusted)...\n"));
433 else
434 fprintf(stderr, _("Server finished (client trusted)...\n"));
437 if (mode == 'c')
438 gsasl_client_finish (xctx);
439 else
440 gsasl_server_finish (xctx);
443 gsasl_done(ctx);
445 return 0;