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