GSS_S_PROMPTING_NEEDED is a bit
[cyrus-sasl.git] / sample / sample-client.c
1 /* sample-client.c -- sample SASL client
2  * Rob Earhart
3  * $Id: sample-client.c,v 1.31 2004/10/26 11:14:33 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 <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 <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 ? (unsigned) strlen(value) : 0;
227     break;
228   case SASL_CB_AUTHNAME:
229     *result = value;
230     if (len)
231       *len = value ? (unsigned) 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   unsigned 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 = (unsigned) 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 = (unsigned) 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, (unsigned) 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 #ifdef WIN32
439   /* initialize winsock */
440     WSADATA wsaData;
441
442     result = WSAStartup( MAKEWORD(2, 0), &wsaData );
443     if ( result != 0) {
444         saslfail(SASL_FAIL, "Initializing WinSockets", NULL);
445     }
446 #endif
447
448   progname = strrchr(argv[0], HIER_DELIMITER);
449   if (progname)
450     progname++;
451   else
452     progname = argv[0];
453
454   /* Init defaults... */
455   memset(&secprops, 0L, sizeof(secprops));
456   secprops.maxbufsize = SAMPLE_SEC_BUF_SIZE;
457   secprops.max_ssf = UINT_MAX;
458
459   verbose = 0;
460   while ((c = getopt(argc, argv, "vhldb:e:m:f:i:p:r:s:n:u:a:?")) != EOF)
461     switch (c) {
462     case 'v':
463         verbose = 1;
464         break;
465     case 'b':
466       options = optarg;
467       while (*options != '\0')
468         switch(getsubopt(&options, (const char * const *)bit_subopts, &value)) {
469         case OPT_MIN:
470           if (! value)
471             errflag = 1;
472           else
473             secprops.min_ssf = atoi(value);
474           break;
475         case OPT_MAX:
476           if (! value)
477             errflag = 1;
478           else
479             secprops.max_ssf = atoi(value);
480           break;
481         default:
482           errflag = 1;
483           break;          
484           }
485       break;
486
487     case 'l':
488         serverlast = SASL_SUCCESS_DATA;
489         break;
490         
491     case 'd':
492         clientfirst = 0;
493         break;
494
495     case 'e':
496       options = optarg;
497       while (*options != '\0')
498         switch(getsubopt(&options, (const char * const *)ext_subopts, &value)) {
499         case OPT_EXT_SSF:
500           if (! value)
501             errflag = 1;
502           else
503             extssf = atoi(value);
504           break;
505         case OPT_MAX:
506           if (! value)
507             errflag = 1;
508           else
509             ext_authid = value;
510           break;
511         default:
512           errflag = 1;
513           break;
514           }
515       break;
516
517     case 'm':
518       mech = optarg;
519       break;
520
521     case 'f':
522       options = optarg;
523       while (*options != '\0') {
524         switch(getsubopt(&options, (const char * const *)flag_subopts, &value)) {
525         case OPT_NOPLAIN:
526           secprops.security_flags |= SASL_SEC_NOPLAINTEXT;
527           break;
528         case OPT_NOACTIVE:
529           secprops.security_flags |= SASL_SEC_NOACTIVE;
530           break;
531         case OPT_NODICT:
532           secprops.security_flags |= SASL_SEC_NODICTIONARY;
533           break;
534         case OPT_FORWARDSEC:
535           secprops.security_flags |= SASL_SEC_FORWARD_SECRECY;
536           break;
537         case OPT_NOANONYMOUS:
538           secprops.security_flags |= SASL_SEC_NOANONYMOUS;
539           break;
540         case OPT_PASSCRED:
541           secprops.security_flags |= SASL_SEC_PASS_CREDENTIALS;
542           break;
543         default:
544           errflag = 1;
545           break;
546           }
547         if (value) errflag = 1;
548         }
549       break;
550
551     case 'i':
552       options = optarg;
553       while (*options != '\0')
554         switch(getsubopt(&options, (const char * const *)ip_subopts, &value)) {
555         case OPT_IP_LOCAL:
556           if (! value)
557             errflag = 1;
558           else
559             iplocal = value;
560           break;
561         case OPT_IP_REMOTE:
562           if (! value)
563             errflag = 1;
564           else
565             ipremote = value;
566           break;
567         default:
568           errflag = 1;
569           break;
570           }
571       break;
572
573     case 'p':
574       searchpath = optarg;
575       break;
576
577     case 'r':
578       realm = optarg;
579       break;
580
581     case 's':
582       service=malloc(1000);
583       strcpy(service,optarg);
584       /*      service = optarg;*/
585       printf("service=%s\n",service);
586       break;
587
588     case 'n':
589       fqdn = optarg;
590       break;
591
592     case 'u':
593       userid = optarg;
594       break;
595
596     case 'a':
597       authid = optarg;
598       break;
599
600     default:                    /* unknown flag */
601       errflag = 1;
602       break;
603     }
604
605   if (optind != argc) {
606     /* We don't *have* extra arguments */
607     errflag = 1;
608   }
609
610   if (errflag) {
611     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"
612             "\t-b ...\t#bits to use for encryption\n"
613             "\t\tmin=N\tminumum #bits to use (1 => integrity)\n"
614             "\t\tmax=N\tmaximum #bits to use\n"
615             "\t-e ...\tassume external encryption\n"
616             "\t\tssf=N\texternal mech provides N bits of encryption\n"
617             "\t\tid=ID\texternal mech provides authentication id ID\n"
618             "\t-m MECH\tforce use of MECH for security\n"
619             "\t-f ...\tset security flags\n"
620             "\t\tnoplain\t\trequire security vs. passive attacks\n"
621             "\t\tnoactive\trequire security vs. active attacks\n"
622             "\t\tnodict\t\trequire security vs. passive dictionary attacks\n"
623             "\t\tforwardsec\trequire forward secrecy\n"
624             "\t\tmaximum\t\trequire all security flags\n"
625             "\t\tpasscred\tattempt to pass client credentials\n"
626             "\t-i ...\tset IP addresses (required by some mechs)\n"
627             "\t\tlocal=IP;PORT\tset local address to IP, port PORT\n"
628             "\t\tremote=IP;PORT\tset remote address to IP, port PORT\n"
629             "\t-p PATH\tcolon-seperated search path for mechanisms\n"
630             "\t-r REALM\trealm to use"
631             "\t-s NAME\tservice name pass to mechanisms\n"
632             "\t-n FQDN\tserver fully-qualified domain name\n"
633             "\t-u ID\tuser (authorization) id to request\n"
634             "\t-a ID\tid to authenticate as\n"
635             "\t-d\tDisable client-send-first\n"
636             "\t-l\tEnable server-send-last\n",
637             progname, progname);
638     exit(EXIT_FAILURE);
639   }
640
641   /* Fill in the callbacks that we're providing... */
642   callback = callbacks;
643
644   /* log */
645   callback->id = SASL_CB_LOG;
646   callback->proc = &sasl_my_log;
647   callback->context = NULL;
648   ++callback;
649   
650   /* getpath */
651   if (searchpath) {
652     callback->id = SASL_CB_GETPATH;
653     callback->proc = &getpath;
654     callback->context = searchpath;
655     ++callback;
656   }
657
658   /* user */
659   if (userid) {
660     callback->id = SASL_CB_USER;
661     callback->proc = &simple;
662     callback->context = userid;
663     ++callback;
664   }
665
666   /* authname */
667   if (authid) {
668     callback->id = SASL_CB_AUTHNAME;
669     callback->proc = &simple;
670     callback->context = authid;
671     ++callback;
672   }
673
674   if (realm!=NULL)
675   {
676     callback->id = SASL_CB_GETREALM;
677     callback->proc = &getrealm;
678     callback->context = realm;
679     callback++;
680   }
681
682   /* password */
683   callback->id = SASL_CB_PASS;
684   callback->proc = &getsecret;
685   callback->context = NULL;
686   ++callback;
687
688   /* echoprompt */
689   callback->id = SASL_CB_ECHOPROMPT;
690   callback->proc = &prompt;
691   callback->context = NULL;
692   ++callback;
693
694   /* noechoprompt */
695   callback->id = SASL_CB_NOECHOPROMPT;
696   callback->proc = &prompt;
697   callback->context = NULL;
698   ++callback;
699
700   /* termination */
701   callback->id = SASL_CB_LIST_END;
702   callback->proc = NULL;
703   callback->context = NULL;
704   ++callback;
705
706   if (N_CALLBACKS < callback - callbacks)
707     fail("Out of callback space; recompile with larger N_CALLBACKS");
708
709   result = sasl_client_init(callbacks);
710   if (result != SASL_OK)
711     saslfail(result, "Initializing libsasl", NULL);
712
713   result = sasl_client_new(service,
714                            fqdn,
715                            iplocal,ipremote,
716                            NULL,serverlast,
717                            &conn);
718   if (result != SASL_OK)
719     saslfail(result, "Allocating sasl connection state", NULL);
720
721   if(extssf) {
722       result = sasl_setprop(conn,
723                             SASL_SSF_EXTERNAL,
724                             &extssf);
725
726       if (result != SASL_OK)
727           saslfail(result, "Setting external SSF", NULL);
728   }
729   
730   if(ext_authid) {
731       result = sasl_setprop(conn,
732                             SASL_AUTH_EXTERNAL,
733                             &ext_authid);
734
735       if (result != SASL_OK)
736           saslfail(result, "Setting external authid", NULL);
737   }
738   
739   result = sasl_setprop(conn,
740                         SASL_SEC_PROPS,
741                         &secprops);
742
743   if (result != SASL_OK)
744     saslfail(result, "Setting security properties", NULL);
745
746   puts("Waiting for mechanism list from server...");
747   len = samp_recv();
748
749   if (mech) {
750     printf("Forcing use of mechanism %s\n", mech);
751     strncpy(buf, mech, SAMPLE_SEC_BUF_SIZE);
752     buf[SAMPLE_SEC_BUF_SIZE - 1] = '\0';
753   }
754
755   printf("Choosing best mechanism from: %s\n", buf);
756
757   if(clientfirst) {
758       result = sasl_client_start(conn,
759                                  buf,
760                                  NULL,
761                                  &data,
762                                  &len,
763                                  &chosenmech);
764   } else {
765       data = "";
766       len = 0;
767       result = sasl_client_start(conn,
768                                  buf,
769                                  NULL,
770                                  NULL,
771                                  0,
772                                  &chosenmech);
773   }
774   
775   
776   if (result != SASL_OK && result != SASL_CONTINUE) {
777       printf("error was %s\n", sasl_errdetail(conn));
778       saslfail(result, "Starting SASL negotiation", NULL);
779   }
780
781   printf("Using mechanism %s\n", chosenmech);
782   strcpy(buf, chosenmech);
783   if (data) {
784     if (SAMPLE_SEC_BUF_SIZE - strlen(buf) - 1 < len)
785       fail("Not enough buffer space");
786     puts("Preparing initial.");
787     memcpy(buf + strlen(buf) + 1, data, len);
788     len += (unsigned) strlen(buf) + 1;
789     data = NULL;
790   } else {
791     len = (unsigned) strlen(buf);
792   }
793   
794   puts("Sending initial response...");
795   samp_send(buf, len);
796
797   while (result == SASL_CONTINUE) {
798     puts("Waiting for server reply...");
799     len = samp_recv();
800     result = sasl_client_step(conn, buf, len, NULL,
801                               &data, &len);
802     if (result != SASL_OK && result != SASL_CONTINUE)
803         saslfail(result, "Performing SASL negotiation", NULL);
804     if (data && len) {
805         puts("Sending response...");
806         samp_send(data, len);
807     } else if (result != SASL_OK || !serverlast) {
808         samp_send("",0);
809     }
810     
811   }
812   puts("Negotiation complete");
813
814   result = sasl_getprop(conn, SASL_USERNAME, (const void **)&data);
815   if (result != SASL_OK)
816     sasldebug(result, "username", NULL);
817   else
818     printf("Username: %s\n", data);
819
820 #define CLIENT_MSG1 "client message 1"
821 #define SERVER_MSG1 "srv message 1"
822
823   result = sasl_getprop(conn, SASL_SSF, (const void **)&ssf);
824   if (result != SASL_OK)
825     sasldebug(result, "ssf", NULL);
826   else
827     printf("SSF: %d\n", *ssf);
828  
829  printf("Waiting for encoded message...\n");
830  len=samp_recv();
831  {
832         unsigned int recv_len;
833         const char *recv_data;
834         result=sasl_decode(conn,buf,len,&recv_data,&recv_len);
835         if (result != SASL_OK)
836             saslfail(result, "sasl_decode", NULL);
837         printf("recieved decoded message '%s'\n",recv_data);
838         if(strcmp(recv_data,SERVER_MSG1)!=0)
839             saslfail(1,"recive decoded server message",NULL);
840  }
841   result=sasl_encode(conn,CLIENT_MSG1,sizeof(CLIENT_MSG1),
842         &data,&len);
843   if (result != SASL_OK)
844       saslfail(result, "sasl_encode", NULL);
845   printf("sending encrypted message '%s'\n",CLIENT_MSG1);
846   samp_send(data,len);
847
848   free_conn();
849   sasl_done();
850
851 #ifdef WIN32
852   WSACleanup();
853 #endif
854   return (EXIT_SUCCESS);
855 }