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