1 | /* sample-client.c -- sample SASL client |
---|
2 | * Rob Earhart |
---|
3 | * $Id: sample-client.c,v 1.1.1.1 2002-10-13 18:00:17 ghudson Exp $ |
---|
4 | */ |
---|
5 | /* |
---|
6 | * Copyright (c) 2001 Carnegie Mellon University. All rights reserved. |
---|
7 | * |
---|
8 | * Redistribution and use in source and binary forms, with or without |
---|
9 | * modification, are permitted provided that the following conditions |
---|
10 | * are met: |
---|
11 | * |
---|
12 | * 1. Redistributions of source code must retain the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer. |
---|
14 | * |
---|
15 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
16 | * notice, this list of conditions and the following disclaimer in |
---|
17 | * the documentation and/or other materials provided with the |
---|
18 | * distribution. |
---|
19 | * |
---|
20 | * 3. The name "Carnegie Mellon University" must not be used to |
---|
21 | * endorse or promote products derived from this software without |
---|
22 | * prior written permission. For permission or any other legal |
---|
23 | * details, please contact |
---|
24 | * Office of Technology Transfer |
---|
25 | * Carnegie Mellon University |
---|
26 | * 5000 Forbes Avenue |
---|
27 | * Pittsburgh, PA 15213-3890 |
---|
28 | * (412) 268-4387, fax: (412) 268-7395 |
---|
29 | * tech-transfer@andrew.cmu.edu |
---|
30 | * |
---|
31 | * 4. Redistributions of any form whatsoever must retain the following |
---|
32 | * acknowledgment: |
---|
33 | * "This product includes software developed by Computing Services |
---|
34 | * at Carnegie Mellon University (http://www.cmu.edu/computing/)." |
---|
35 | * |
---|
36 | * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO |
---|
37 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
---|
38 | * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE |
---|
39 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
---|
40 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN |
---|
41 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
---|
42 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
---|
43 | */ |
---|
44 | #include <config.h> |
---|
45 | #include <limits.h> |
---|
46 | #include <stdio.h> |
---|
47 | #include <string.h> |
---|
48 | #include <stdlib.h> |
---|
49 | #ifdef WIN32 |
---|
50 | # include <winsock.h> |
---|
51 | __declspec(dllimport) char *optarg; |
---|
52 | __declspec(dllimport) int optind; |
---|
53 | __declspec(dllimport) int getsubopt(char **optionp, const char * const *tokens, char **valuep); |
---|
54 | #else /* WIN32 */ |
---|
55 | # include <netinet/in.h> |
---|
56 | #endif /* WIN32 */ |
---|
57 | #include <sasl.h> |
---|
58 | #include <saslutil.h> |
---|
59 | |
---|
60 | #ifdef macintosh |
---|
61 | #include <sioux.h> |
---|
62 | #include <parse_cmd_line.h> |
---|
63 | #define MAX_ARGC (100) |
---|
64 | int xxx_main(int argc, char *argv[]); |
---|
65 | int main(void) |
---|
66 | { |
---|
67 | char *argv[MAX_ARGC]; |
---|
68 | int argc; |
---|
69 | char line[400]; |
---|
70 | SIOUXSettings.asktosaveonclose = 0; |
---|
71 | SIOUXSettings.showstatusline = 1; |
---|
72 | argc=parse_cmd_line(MAX_ARGC,argv,sizeof(line),line); |
---|
73 | return xxx_main(argc,argv); |
---|
74 | } |
---|
75 | #define main xxx_main |
---|
76 | #endif |
---|
77 | |
---|
78 | #ifdef HAVE_GETOPT_H |
---|
79 | #include <getopt.h> |
---|
80 | #endif |
---|
81 | #ifdef HAVE_UNISTD_H |
---|
82 | #include <unistd.h> |
---|
83 | #endif |
---|
84 | |
---|
85 | #ifndef HAVE_GETSUBOPT |
---|
86 | int getsubopt(char **optionp, const char * const *tokens, char **valuep); |
---|
87 | #endif |
---|
88 | |
---|
89 | static const char |
---|
90 | build_ident[] = "$Build: sample-client " PACKAGE "-" VERSION " $"; |
---|
91 | |
---|
92 | static const char *progname = NULL; |
---|
93 | static int verbose; |
---|
94 | |
---|
95 | #define SAMPLE_SEC_BUF_SIZE (2048) |
---|
96 | |
---|
97 | #define N_CALLBACKS (16) |
---|
98 | |
---|
99 | static const char |
---|
100 | message[] = "Come here Watson, I want you."; |
---|
101 | |
---|
102 | char buf[SAMPLE_SEC_BUF_SIZE]; |
---|
103 | |
---|
104 | static const char *bit_subopts[] = { |
---|
105 | #define OPT_MIN (0) |
---|
106 | "min", |
---|
107 | #define OPT_MAX (1) |
---|
108 | "max", |
---|
109 | NULL |
---|
110 | }; |
---|
111 | |
---|
112 | static const char *ext_subopts[] = { |
---|
113 | #define OPT_EXT_SSF (0) |
---|
114 | "ssf", |
---|
115 | #define OPT_EXT_ID (1) |
---|
116 | "id", |
---|
117 | NULL |
---|
118 | }; |
---|
119 | |
---|
120 | static const char *flag_subopts[] = { |
---|
121 | #define OPT_NOPLAIN (0) |
---|
122 | "noplain", |
---|
123 | #define OPT_NOACTIVE (1) |
---|
124 | "noactive", |
---|
125 | #define OPT_NODICT (2) |
---|
126 | "nodict", |
---|
127 | #define OPT_FORWARDSEC (3) |
---|
128 | "forwardsec", |
---|
129 | #define OPT_NOANONYMOUS (4) |
---|
130 | "noanonymous", |
---|
131 | #define OPT_PASSCRED (5) |
---|
132 | "passcred", |
---|
133 | NULL |
---|
134 | }; |
---|
135 | |
---|
136 | static const char *ip_subopts[] = { |
---|
137 | #define OPT_IP_LOCAL (0) |
---|
138 | "local", |
---|
139 | #define OPT_IP_REMOTE (1) |
---|
140 | "remote", |
---|
141 | NULL |
---|
142 | }; |
---|
143 | |
---|
144 | static sasl_conn_t *conn = NULL; |
---|
145 | |
---|
146 | static void |
---|
147 | free_conn(void) |
---|
148 | { |
---|
149 | if (conn) |
---|
150 | sasl_dispose(&conn); |
---|
151 | } |
---|
152 | |
---|
153 | static int |
---|
154 | sasl_my_log(void *context __attribute__((unused)), |
---|
155 | int priority, |
---|
156 | const char *message) |
---|
157 | { |
---|
158 | const char *label; |
---|
159 | |
---|
160 | if (! message) |
---|
161 | return SASL_BADPARAM; |
---|
162 | |
---|
163 | switch (priority) { |
---|
164 | case SASL_LOG_ERR: |
---|
165 | label = "Error"; |
---|
166 | break; |
---|
167 | case SASL_LOG_NOTE: |
---|
168 | label = "Info"; |
---|
169 | break; |
---|
170 | default: |
---|
171 | label = "Other"; |
---|
172 | break; |
---|
173 | } |
---|
174 | |
---|
175 | fprintf(stderr, "%s: SASL %s: %s\n", |
---|
176 | progname, label, message); |
---|
177 | |
---|
178 | return SASL_OK; |
---|
179 | } |
---|
180 | |
---|
181 | static int getrealm(void *context, |
---|
182 | int id, |
---|
183 | const char **availrealms __attribute__((unused)), |
---|
184 | const char **result) |
---|
185 | { |
---|
186 | if (id!=SASL_CB_GETREALM) return SASL_FAIL; |
---|
187 | |
---|
188 | *result=(char *) context; |
---|
189 | |
---|
190 | return SASL_OK; |
---|
191 | } |
---|
192 | |
---|
193 | static int |
---|
194 | getpath(void *context, |
---|
195 | const char ** path) |
---|
196 | { |
---|
197 | const char *searchpath = (const char *) context; |
---|
198 | |
---|
199 | if (! path) |
---|
200 | return SASL_BADPARAM; |
---|
201 | |
---|
202 | if (searchpath) { |
---|
203 | *path = searchpath; |
---|
204 | } else { |
---|
205 | *path = PLUGINDIR; |
---|
206 | } |
---|
207 | |
---|
208 | return SASL_OK; |
---|
209 | } |
---|
210 | |
---|
211 | static int |
---|
212 | simple(void *context, |
---|
213 | int id, |
---|
214 | const char **result, |
---|
215 | unsigned *len) |
---|
216 | { |
---|
217 | const char *value = (const char *)context; |
---|
218 | |
---|
219 | if (! result) |
---|
220 | return SASL_BADPARAM; |
---|
221 | |
---|
222 | switch (id) { |
---|
223 | case SASL_CB_USER: |
---|
224 | *result = value; |
---|
225 | if (len) |
---|
226 | *len = value ? strlen(value) : 0; |
---|
227 | break; |
---|
228 | case SASL_CB_AUTHNAME: |
---|
229 | *result = value; |
---|
230 | if (len) |
---|
231 | *len = value ? strlen(value) : 0; |
---|
232 | break; |
---|
233 | case SASL_CB_LANGUAGE: |
---|
234 | *result = NULL; |
---|
235 | if (len) |
---|
236 | *len = 0; |
---|
237 | break; |
---|
238 | default: |
---|
239 | return SASL_BADPARAM; |
---|
240 | } |
---|
241 | |
---|
242 | printf("returning OK: %s\n", *result); |
---|
243 | |
---|
244 | return SASL_OK; |
---|
245 | } |
---|
246 | |
---|
247 | #ifndef HAVE_GETPASSPHRASE |
---|
248 | static char * |
---|
249 | getpassphrase(const char *prompt) |
---|
250 | { |
---|
251 | return getpass(prompt); |
---|
252 | } |
---|
253 | #endif /* ! HAVE_GETPASSPHRASE */ |
---|
254 | |
---|
255 | static int |
---|
256 | getsecret(sasl_conn_t *conn, |
---|
257 | void *context __attribute__((unused)), |
---|
258 | int id, |
---|
259 | sasl_secret_t **psecret) |
---|
260 | { |
---|
261 | char *password; |
---|
262 | size_t len; |
---|
263 | |
---|
264 | if (! conn || ! psecret || id != SASL_CB_PASS) |
---|
265 | return SASL_BADPARAM; |
---|
266 | |
---|
267 | password = getpassphrase("Password: "); |
---|
268 | if (! password) |
---|
269 | return SASL_FAIL; |
---|
270 | |
---|
271 | len = strlen(password); |
---|
272 | |
---|
273 | *psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len); |
---|
274 | |
---|
275 | if (! *psecret) { |
---|
276 | memset(password, 0, len); |
---|
277 | return SASL_NOMEM; |
---|
278 | } |
---|
279 | |
---|
280 | (*psecret)->len = len; |
---|
281 | strcpy((char *)(*psecret)->data, password); |
---|
282 | memset(password, 0, len); |
---|
283 | |
---|
284 | return SASL_OK; |
---|
285 | } |
---|
286 | |
---|
287 | static int |
---|
288 | prompt(void *context __attribute__((unused)), |
---|
289 | int id, |
---|
290 | const char *challenge, |
---|
291 | const char *prompt, |
---|
292 | const char *defresult, |
---|
293 | const char **result, |
---|
294 | unsigned *len) |
---|
295 | { |
---|
296 | if ((id != SASL_CB_ECHOPROMPT && id != SASL_CB_NOECHOPROMPT) |
---|
297 | || !prompt || !result || !len) |
---|
298 | return SASL_BADPARAM; |
---|
299 | |
---|
300 | if (! defresult) |
---|
301 | defresult = ""; |
---|
302 | |
---|
303 | fputs(prompt, stdout); |
---|
304 | if (challenge) |
---|
305 | printf(" [challenge: %s]", challenge); |
---|
306 | printf(" [%s]: ", defresult); |
---|
307 | fflush(stdout); |
---|
308 | |
---|
309 | if (id == SASL_CB_ECHOPROMPT) { |
---|
310 | char *original = getpassphrase(""); |
---|
311 | if (! original) |
---|
312 | return SASL_FAIL; |
---|
313 | if (*original) |
---|
314 | *result = strdup(original); |
---|
315 | else |
---|
316 | *result = strdup(defresult); |
---|
317 | memset(original, 0L, strlen(original)); |
---|
318 | } else { |
---|
319 | char buf[1024]; |
---|
320 | fgets(buf, 1024, stdin); |
---|
321 | if (buf[0]) { |
---|
322 | *result = strdup(buf); |
---|
323 | } else { |
---|
324 | *result = strdup(defresult); |
---|
325 | } |
---|
326 | memset(buf, 0L, sizeof(buf)); |
---|
327 | } |
---|
328 | if (! *result) |
---|
329 | return SASL_NOMEM; |
---|
330 | |
---|
331 | *len = strlen(*result); |
---|
332 | |
---|
333 | return SASL_OK; |
---|
334 | } |
---|
335 | |
---|
336 | static void |
---|
337 | sasldebug(int why, const char *what, const char *errstr) |
---|
338 | { |
---|
339 | fprintf(stderr, "%s: %s: %s", |
---|
340 | progname, |
---|
341 | what, |
---|
342 | sasl_errstring(why, NULL, NULL)); |
---|
343 | if (errstr) |
---|
344 | fprintf(stderr, " (%s)\n", errstr); |
---|
345 | else |
---|
346 | putc('\n', stderr); |
---|
347 | } |
---|
348 | |
---|
349 | static void |
---|
350 | saslfail(int why, const char *what, const char *errstr) |
---|
351 | { |
---|
352 | sasldebug(why, what, errstr); |
---|
353 | free_conn(); |
---|
354 | sasl_done(); |
---|
355 | exit(EXIT_FAILURE); |
---|
356 | } |
---|
357 | |
---|
358 | static void |
---|
359 | fail(const char *what) |
---|
360 | { |
---|
361 | fprintf(stderr, "%s: %s\n", |
---|
362 | progname, what); |
---|
363 | exit(EXIT_FAILURE); |
---|
364 | } |
---|
365 | |
---|
366 | static void |
---|
367 | osfail() |
---|
368 | { |
---|
369 | perror(progname); |
---|
370 | exit(EXIT_FAILURE); |
---|
371 | } |
---|
372 | |
---|
373 | static void |
---|
374 | samp_send(const char *buffer, |
---|
375 | unsigned length) |
---|
376 | { |
---|
377 | char *buf; |
---|
378 | unsigned len, alloclen; |
---|
379 | int result; |
---|
380 | |
---|
381 | alloclen = ((length / 3) + 1) * 4 + 1; |
---|
382 | buf = malloc(alloclen); |
---|
383 | if (! buf) |
---|
384 | osfail(); |
---|
385 | result = sasl_encode64(buffer, length, buf, alloclen, &len); |
---|
386 | if (result != SASL_OK) |
---|
387 | saslfail(result, "Encoding data in base64", NULL); |
---|
388 | printf("C: %s\n", buf); |
---|
389 | free(buf); |
---|
390 | } |
---|
391 | |
---|
392 | static unsigned |
---|
393 | samp_recv() |
---|
394 | { |
---|
395 | unsigned len; |
---|
396 | int result; |
---|
397 | |
---|
398 | if (! fgets(buf, SAMPLE_SEC_BUF_SIZE, stdin) |
---|
399 | || strncmp(buf, "S: ", 3)) |
---|
400 | fail("Unable to parse input"); |
---|
401 | result = sasl_decode64(buf + 3, strlen(buf + 3), buf, |
---|
402 | SAMPLE_SEC_BUF_SIZE, &len); |
---|
403 | if (result != SASL_OK) |
---|
404 | saslfail(result, "Decoding data from base64", NULL); |
---|
405 | buf[len] = '\0'; |
---|
406 | printf("recieved %d byte message\n",len); |
---|
407 | if (verbose) { printf("got '%s'\n", buf); } |
---|
408 | return len; |
---|
409 | } |
---|
410 | |
---|
411 | int |
---|
412 | main(int argc, char *argv[]) |
---|
413 | { |
---|
414 | int c = 0; |
---|
415 | int errflag = 0; |
---|
416 | int result; |
---|
417 | sasl_security_properties_t secprops; |
---|
418 | sasl_ssf_t extssf = 0; |
---|
419 | const char *ext_authid = NULL; |
---|
420 | char *options, *value; |
---|
421 | const char *data; |
---|
422 | const char *chosenmech; |
---|
423 | int serverlast = 0; |
---|
424 | unsigned len; |
---|
425 | int clientfirst = 1; |
---|
426 | sasl_callback_t callbacks[N_CALLBACKS], *callback; |
---|
427 | char *realm = NULL; |
---|
428 | char *mech = NULL, |
---|
429 | *iplocal = NULL, |
---|
430 | *ipremote = NULL, |
---|
431 | *searchpath = NULL, |
---|
432 | *service = "rcmd", |
---|
433 | *fqdn = "", |
---|
434 | *userid = NULL, |
---|
435 | *authid = NULL; |
---|
436 | sasl_ssf_t *ssf; |
---|
437 | |
---|
438 | progname = strrchr(argv[0], '/'); |
---|
439 | if (progname) |
---|
440 | progname++; |
---|
441 | else |
---|
442 | progname = argv[0]; |
---|
443 | |
---|
444 | /* Init defaults... */ |
---|
445 | memset(&secprops, 0L, sizeof(secprops)); |
---|
446 | secprops.maxbufsize = SAMPLE_SEC_BUF_SIZE; |
---|
447 | secprops.max_ssf = UINT_MAX; |
---|
448 | |
---|
449 | verbose = 0; |
---|
450 | while ((c = getopt(argc, argv, "vhldb:e:m:f:i:p:r:s:n:u:a:?")) != EOF) |
---|
451 | switch (c) { |
---|
452 | case 'v': |
---|
453 | verbose = 1; |
---|
454 | break; |
---|
455 | case 'b': |
---|
456 | options = optarg; |
---|
457 | while (*options != '\0') |
---|
458 | switch(getsubopt(&options, (const char * const *)bit_subopts, &value)) { |
---|
459 | case OPT_MIN: |
---|
460 | if (! value) |
---|
461 | errflag = 1; |
---|
462 | else |
---|
463 | secprops.min_ssf = atoi(value); |
---|
464 | break; |
---|
465 | case OPT_MAX: |
---|
466 | if (! value) |
---|
467 | errflag = 1; |
---|
468 | else |
---|
469 | secprops.max_ssf = atoi(value); |
---|
470 | break; |
---|
471 | default: |
---|
472 | errflag = 1; |
---|
473 | break; |
---|
474 | } |
---|
475 | break; |
---|
476 | |
---|
477 | case 'l': |
---|
478 | serverlast = SASL_SUCCESS_DATA; |
---|
479 | break; |
---|
480 | |
---|
481 | case 'd': |
---|
482 | clientfirst = 0; |
---|
483 | break; |
---|
484 | |
---|
485 | case 'e': |
---|
486 | options = optarg; |
---|
487 | while (*options != '\0') |
---|
488 | switch(getsubopt(&options, (const char * const *)ext_subopts, &value)) { |
---|
489 | case OPT_EXT_SSF: |
---|
490 | if (! value) |
---|
491 | errflag = 1; |
---|
492 | else |
---|
493 | extssf = atoi(value); |
---|
494 | break; |
---|
495 | case OPT_MAX: |
---|
496 | if (! value) |
---|
497 | errflag = 1; |
---|
498 | else |
---|
499 | ext_authid = value; |
---|
500 | break; |
---|
501 | default: |
---|
502 | errflag = 1; |
---|
503 | break; |
---|
504 | } |
---|
505 | break; |
---|
506 | |
---|
507 | case 'm': |
---|
508 | mech = optarg; |
---|
509 | break; |
---|
510 | |
---|
511 | case 'f': |
---|
512 | options = optarg; |
---|
513 | while (*options != '\0') { |
---|
514 | switch(getsubopt(&options, (const char * const *)flag_subopts, &value)) { |
---|
515 | case OPT_NOPLAIN: |
---|
516 | secprops.security_flags |= SASL_SEC_NOPLAINTEXT; |
---|
517 | break; |
---|
518 | case OPT_NOACTIVE: |
---|
519 | secprops.security_flags |= SASL_SEC_NOACTIVE; |
---|
520 | break; |
---|
521 | case OPT_NODICT: |
---|
522 | secprops.security_flags |= SASL_SEC_NODICTIONARY; |
---|
523 | break; |
---|
524 | case OPT_FORWARDSEC: |
---|
525 | secprops.security_flags |= SASL_SEC_FORWARD_SECRECY; |
---|
526 | break; |
---|
527 | case OPT_NOANONYMOUS: |
---|
528 | secprops.security_flags |= SASL_SEC_NOANONYMOUS; |
---|
529 | break; |
---|
530 | case OPT_PASSCRED: |
---|
531 | secprops.security_flags |= SASL_SEC_PASS_CREDENTIALS; |
---|
532 | break; |
---|
533 | default: |
---|
534 | errflag = 1; |
---|
535 | break; |
---|
536 | } |
---|
537 | if (value) errflag = 1; |
---|
538 | } |
---|
539 | break; |
---|
540 | |
---|
541 | case 'i': |
---|
542 | options = optarg; |
---|
543 | while (*options != '\0') |
---|
544 | switch(getsubopt(&options, (const char * const *)ip_subopts, &value)) { |
---|
545 | case OPT_IP_LOCAL: |
---|
546 | if (! value) |
---|
547 | errflag = 1; |
---|
548 | else |
---|
549 | iplocal = value; |
---|
550 | break; |
---|
551 | case OPT_IP_REMOTE: |
---|
552 | if (! value) |
---|
553 | errflag = 1; |
---|
554 | else |
---|
555 | ipremote = value; |
---|
556 | break; |
---|
557 | default: |
---|
558 | errflag = 1; |
---|
559 | break; |
---|
560 | } |
---|
561 | break; |
---|
562 | |
---|
563 | case 'p': |
---|
564 | searchpath = optarg; |
---|
565 | break; |
---|
566 | |
---|
567 | case 'r': |
---|
568 | realm = optarg; |
---|
569 | break; |
---|
570 | |
---|
571 | case 's': |
---|
572 | service=malloc(1000); |
---|
573 | strcpy(service,optarg); |
---|
574 | /* service = optarg;*/ |
---|
575 | printf("service=%s\n",service); |
---|
576 | break; |
---|
577 | |
---|
578 | case 'n': |
---|
579 | fqdn = optarg; |
---|
580 | break; |
---|
581 | |
---|
582 | case 'u': |
---|
583 | userid = optarg; |
---|
584 | break; |
---|
585 | |
---|
586 | case 'a': |
---|
587 | authid = optarg; |
---|
588 | break; |
---|
589 | |
---|
590 | default: /* unknown flag */ |
---|
591 | errflag = 1; |
---|
592 | break; |
---|
593 | } |
---|
594 | |
---|
595 | if (optind != argc) { |
---|
596 | /* We don't *have* extra arguments */ |
---|
597 | errflag = 1; |
---|
598 | } |
---|
599 | |
---|
600 | if (errflag) { |
---|
601 | fprintf(stderr, "%s: Usage: %s [-b min=N,max=N] [-e ssf=N,id=ID] [-m MECH] [-f FLAGS] [-i local=IP,remote=IP] [-p PATH] [-s NAME] [-n FQDN] [-u ID] [-a ID]\n" |
---|
602 | "\t-b ...\t#bits to use for encryption\n" |
---|
603 | "\t\tmin=N\tminumum #bits to use (1 => integrity)\n" |
---|
604 | "\t\tmax=N\tmaximum #bits to use\n" |
---|
605 | "\t-e ...\tassume external encryption\n" |
---|
606 | "\t\tssf=N\texternal mech provides N bits of encryption\n" |
---|
607 | "\t\tid=ID\texternal mech provides authentication id ID\n" |
---|
608 | "\t-m MECH\tforce use of MECH for security\n" |
---|
609 | "\t-f ...\tset security flags\n" |
---|
610 | "\t\tnoplain\t\trequire security vs. passive attacks\n" |
---|
611 | "\t\tnoactive\trequire security vs. active attacks\n" |
---|
612 | "\t\tnodict\t\trequire security vs. passive dictionary attacks\n" |
---|
613 | "\t\tforwardsec\trequire forward secrecy\n" |
---|
614 | "\t\tmaximum\t\trequire all security flags\n" |
---|
615 | "\t\tpasscred\tattempt to pass client credentials\n" |
---|
616 | "\t-i ...\tset IP addresses (required by some mechs)\n" |
---|
617 | "\t\tlocal=IP;PORT\tset local address to IP, port PORT\n" |
---|
618 | "\t\tremote=IP;PORT\tset remote address to IP, port PORT\n" |
---|
619 | "\t-p PATH\tcolon-seperated search path for mechanisms\n" |
---|
620 | "\t-r REALM\trealm to use" |
---|
621 | "\t-s NAME\tservice name pass to mechanisms\n" |
---|
622 | "\t-n FQDN\tserver fully-qualified domain name\n" |
---|
623 | "\t-u ID\tuser (authorization) id to request\n" |
---|
624 | "\t-a ID\tid to authenticate as\n" |
---|
625 | "\t-d\tDisable client-send-first\n" |
---|
626 | "\t-l\tEnable server-send-last\n", |
---|
627 | progname, progname); |
---|
628 | exit(EXIT_FAILURE); |
---|
629 | } |
---|
630 | |
---|
631 | /* Fill in the callbacks that we're providing... */ |
---|
632 | callback = callbacks; |
---|
633 | |
---|
634 | /* log */ |
---|
635 | callback->id = SASL_CB_LOG; |
---|
636 | callback->proc = &sasl_my_log; |
---|
637 | callback->context = NULL; |
---|
638 | ++callback; |
---|
639 | |
---|
640 | /* getpath */ |
---|
641 | if (searchpath) { |
---|
642 | callback->id = SASL_CB_GETPATH; |
---|
643 | callback->proc = &getpath; |
---|
644 | callback->context = searchpath; |
---|
645 | ++callback; |
---|
646 | } |
---|
647 | |
---|
648 | /* user */ |
---|
649 | if (userid) { |
---|
650 | callback->id = SASL_CB_USER; |
---|
651 | callback->proc = &simple; |
---|
652 | callback->context = userid; |
---|
653 | ++callback; |
---|
654 | } |
---|
655 | |
---|
656 | /* authname */ |
---|
657 | if (authid) { |
---|
658 | callback->id = SASL_CB_AUTHNAME; |
---|
659 | callback->proc = &simple; |
---|
660 | callback->context = authid; |
---|
661 | ++callback; |
---|
662 | } |
---|
663 | |
---|
664 | if (realm!=NULL) |
---|
665 | { |
---|
666 | callback->id = SASL_CB_GETREALM; |
---|
667 | callback->proc = &getrealm; |
---|
668 | callback->context = realm; |
---|
669 | callback++; |
---|
670 | } |
---|
671 | |
---|
672 | /* password */ |
---|
673 | callback->id = SASL_CB_PASS; |
---|
674 | callback->proc = &getsecret; |
---|
675 | callback->context = NULL; |
---|
676 | ++callback; |
---|
677 | |
---|
678 | /* echoprompt */ |
---|
679 | callback->id = SASL_CB_ECHOPROMPT; |
---|
680 | callback->proc = &prompt; |
---|
681 | callback->context = NULL; |
---|
682 | ++callback; |
---|
683 | |
---|
684 | /* noechoprompt */ |
---|
685 | callback->id = SASL_CB_NOECHOPROMPT; |
---|
686 | callback->proc = &prompt; |
---|
687 | callback->context = NULL; |
---|
688 | ++callback; |
---|
689 | |
---|
690 | /* termination */ |
---|
691 | callback->id = SASL_CB_LIST_END; |
---|
692 | callback->proc = NULL; |
---|
693 | callback->context = NULL; |
---|
694 | ++callback; |
---|
695 | |
---|
696 | if (N_CALLBACKS < callback - callbacks) |
---|
697 | fail("Out of callback space; recompile with larger N_CALLBACKS"); |
---|
698 | |
---|
699 | result = sasl_client_init(callbacks); |
---|
700 | if (result != SASL_OK) |
---|
701 | saslfail(result, "Initializing libsasl", NULL); |
---|
702 | |
---|
703 | result = sasl_client_new(service, |
---|
704 | fqdn, |
---|
705 | iplocal,ipremote, |
---|
706 | NULL,serverlast, |
---|
707 | &conn); |
---|
708 | if (result != SASL_OK) |
---|
709 | saslfail(result, "Allocating sasl connection state", NULL); |
---|
710 | |
---|
711 | if(extssf) { |
---|
712 | result = sasl_setprop(conn, |
---|
713 | SASL_SSF_EXTERNAL, |
---|
714 | &extssf); |
---|
715 | |
---|
716 | if (result != SASL_OK) |
---|
717 | saslfail(result, "Setting external SSF", NULL); |
---|
718 | } |
---|
719 | |
---|
720 | if(ext_authid) { |
---|
721 | result = sasl_setprop(conn, |
---|
722 | SASL_AUTH_EXTERNAL, |
---|
723 | &ext_authid); |
---|
724 | |
---|
725 | if (result != SASL_OK) |
---|
726 | saslfail(result, "Setting external authid", NULL); |
---|
727 | } |
---|
728 | |
---|
729 | result = sasl_setprop(conn, |
---|
730 | SASL_SEC_PROPS, |
---|
731 | &secprops); |
---|
732 | |
---|
733 | if (result != SASL_OK) |
---|
734 | saslfail(result, "Setting security properties", NULL); |
---|
735 | |
---|
736 | puts("Waiting for mechanism list from server..."); |
---|
737 | len = samp_recv(); |
---|
738 | |
---|
739 | if (mech) { |
---|
740 | printf("Forcing use of mechanism %s\n", mech); |
---|
741 | strncpy(buf, mech, SAMPLE_SEC_BUF_SIZE); |
---|
742 | buf[SAMPLE_SEC_BUF_SIZE - 1] = '\0'; |
---|
743 | } |
---|
744 | |
---|
745 | printf("Choosing best mechanism from: %s\n", buf); |
---|
746 | |
---|
747 | if(clientfirst) { |
---|
748 | result = sasl_client_start(conn, |
---|
749 | buf, |
---|
750 | NULL, |
---|
751 | &data, |
---|
752 | &len, |
---|
753 | &chosenmech); |
---|
754 | } else { |
---|
755 | data = ""; |
---|
756 | len = 0; |
---|
757 | result = sasl_client_start(conn, |
---|
758 | buf, |
---|
759 | NULL, |
---|
760 | NULL, |
---|
761 | 0, |
---|
762 | &chosenmech); |
---|
763 | } |
---|
764 | |
---|
765 | |
---|
766 | if (result != SASL_OK && result != SASL_CONTINUE) { |
---|
767 | printf("error was %s\n", sasl_errdetail(conn)); |
---|
768 | saslfail(result, "Starting SASL negotiation", NULL); |
---|
769 | } |
---|
770 | |
---|
771 | printf("Using mechanism %s\n", chosenmech); |
---|
772 | strcpy(buf, chosenmech); |
---|
773 | if (data) { |
---|
774 | if (SAMPLE_SEC_BUF_SIZE - strlen(buf) - 1 < len) |
---|
775 | fail("Not enough buffer space"); |
---|
776 | puts("Preparing initial."); |
---|
777 | memcpy(buf + strlen(buf) + 1, data, len); |
---|
778 | len += strlen(buf) + 1; |
---|
779 | data = NULL; |
---|
780 | } else { |
---|
781 | len = strlen(buf); |
---|
782 | } |
---|
783 | |
---|
784 | puts("Sending initial response..."); |
---|
785 | samp_send(buf, len); |
---|
786 | |
---|
787 | while (result == SASL_CONTINUE) { |
---|
788 | puts("Waiting for server reply..."); |
---|
789 | len = samp_recv(); |
---|
790 | result = sasl_client_step(conn, buf, len, NULL, |
---|
791 | &data, &len); |
---|
792 | if (result != SASL_OK && result != SASL_CONTINUE) |
---|
793 | saslfail(result, "Performing SASL negotiation", NULL); |
---|
794 | if (data && len) { |
---|
795 | puts("Sending response..."); |
---|
796 | samp_send(data, len); |
---|
797 | } else if (result != SASL_OK || !serverlast) { |
---|
798 | samp_send("",0); |
---|
799 | } |
---|
800 | |
---|
801 | } |
---|
802 | puts("Negotiation complete"); |
---|
803 | |
---|
804 | result = sasl_getprop(conn, SASL_USERNAME, (const void **)&data); |
---|
805 | if (result != SASL_OK) |
---|
806 | sasldebug(result, "username", NULL); |
---|
807 | else |
---|
808 | printf("Username: %s\n", data); |
---|
809 | |
---|
810 | #define CLIENT_MSG1 "client message 1" |
---|
811 | #define SERVER_MSG1 "srv message 1" |
---|
812 | |
---|
813 | result = sasl_getprop(conn, SASL_SSF, (const void **)&ssf); |
---|
814 | if (result != SASL_OK) |
---|
815 | sasldebug(result, "ssf", NULL); |
---|
816 | else |
---|
817 | printf("SSF: %d\n", *ssf); |
---|
818 | |
---|
819 | printf("Waiting for encoded message...\n"); |
---|
820 | len=samp_recv(); |
---|
821 | { |
---|
822 | unsigned int recv_len; |
---|
823 | const char *recv_data; |
---|
824 | result=sasl_decode(conn,buf,len,&recv_data,&recv_len); |
---|
825 | if (result != SASL_OK) |
---|
826 | saslfail(result, "sasl_decode", NULL); |
---|
827 | printf("recieved decoded message '%s'\n",recv_data); |
---|
828 | if(strcmp(recv_data,SERVER_MSG1)!=0) |
---|
829 | saslfail(1,"recive decoded server message",NULL); |
---|
830 | } |
---|
831 | result=sasl_encode(conn,CLIENT_MSG1,sizeof(CLIENT_MSG1), |
---|
832 | &data,&len); |
---|
833 | if (result != SASL_OK) |
---|
834 | saslfail(result, "sasl_encode", NULL); |
---|
835 | printf("sending encrypted message '%s'\n",CLIENT_MSG1); |
---|
836 | samp_send(data,len); |
---|
837 | |
---|
838 | free_conn(); |
---|
839 | sasl_done(); |
---|
840 | |
---|
841 | return (EXIT_SUCCESS); |
---|
842 | } |
---|