cleanup
[cyrus-sasl.git] / java / CyrusSasl / javasasl.c
1 /* javasasl.c--Java SASL JNI implementation
2  * Tim Martin
3  */
4 /***********************************************************
5         Copyright 1998 by Carnegie Mellon University
6
7                       All Rights Reserved
8
9 Permission to use, copy, modify, and distribute this software and its
10 documentation for any purpose and without fee is hereby granted,
11 provided that the above copyright notice appear in all copies and that
12 both that copyright notice and this permission notice appear in
13 supporting documentation, and that the name of Carnegie Mellon
14 University not be used in advertising or publicity pertaining to
15 distribution of the software without specific, written prior
16 permission.
17
18 CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
19 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
21 ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
23 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
24 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 ******************************************************************/
26
27 #include <config.h>
28 #include <stdio.h>
29 #include <sasl.h>
30 #include <saslutil.h>
31 #include <saslplug.h>
32 #include <netdb.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <assert.h>
37
38 #include "javasasl.h"
39
40 #define VL(x) /* printf x */
41
42 static JNIEnv *globalenv;
43 static jobject globalobj;
44
45 static int setcomplete(JNIEnv *env, jobject obj);
46
47 static void throwexception(JNIEnv *env, int error)
48 {
49   jclass newExcCls;
50
51   VL (("Throwing exception!\n"));
52
53   newExcCls = (*env)->FindClass(env, "CyrusSasl/SaslException");
54
55   if (newExcCls == 0) { 
56     return;
57   }
58
59   (*env)->ThrowNew(env, newExcCls, sasl_errstring(error,NULL,NULL));
60 }
61
62 /* server init */
63
64 JNIEXPORT jint JNICALL Java_CyrusSasl_ServerFactory_jni_1sasl_1server_1init
65   (JNIEnv *env,
66    jobject obj __attribute__((unused)),
67    jstring jstr)
68 {
69   /* Obtain a C-copy of the Java string */
70   const char *str = (*env)->GetStringUTFChars(env, jstr, 0);
71   int result;
72
73   result=sasl_server_init(NULL,str);
74   if (result!=SASL_OK)
75     throwexception(env,result);
76
77   /* Now we are done with str */
78   (*env)->ReleaseStringUTFChars(env, jstr, str);
79
80   return result;
81 }
82
83 static int
84 log(void *context __attribute__((unused)),
85     int priority,
86     const char *message) 
87 {
88   const char *label;
89   jstring jlabel, jmessage;
90   jclass cls;
91   jmethodID mid;
92
93   if (! message)
94     return SASL_BADPARAM;
95
96   switch (priority) {
97   case SASL_LOG_ERR:
98     label = "Error";
99     break;
100   case SASL_LOG_WARN:
101     label = "Warning";
102     break;
103   case SASL_LOG_NOTE:
104     label = "Note";
105     break;
106   case SASL_LOG_FAIL:
107     label = "Fail";
108     break;
109   case SASL_LOG_PASS:
110     label = "Pass";
111     break;
112   case SASL_LOG_TRACE:
113     label = "Trace";
114     break;
115   case SASL_LOG_DEBUG:
116     label = "Debug";
117     break;
118   default:
119     return SASL_BADPARAM;
120   }
121
122   VL(("I have message %s\n",message));
123   VL(("Trying to call log callback\n"));
124   cls = (*globalenv)->GetObjectClass(globalenv, globalobj);
125   mid = (*globalenv)->GetMethodID(globalenv, cls, "callback_log",
126                                   "(Ljava/lang/String;Ljava/lang/String;)V");
127   if (mid == 0) {
128     return SASL_FAIL;
129   }
130
131   /* make label into a java string */
132   jlabel= (*globalenv)->NewStringUTF(globalenv,label);
133
134   /* make message into a java string */
135   jmessage= (*globalenv)->NewStringUTF(globalenv,message);
136
137   /* call java */
138   (*globalenv)->CallVoidMethod(globalenv, globalobj, mid, 
139                                jlabel, jmessage);
140
141   /* Now we are done with jlabel */
142   (*globalenv)->ReleaseStringUTFChars(globalenv, jlabel, label);
143
144   /* Now we are done with jmessage */
145   (*globalenv)->ReleaseStringUTFChars(globalenv, jmessage, message);
146
147   VL(("done with log callback"));
148
149   return SASL_OK;
150 }
151
152 static sasl_callback_t callbacks[] = {
153   {
154     SASL_CB_LOG,      &log, NULL
155   }, {
156     SASL_CB_PASS,     NULL, NULL
157   }, {
158     SASL_CB_USER,     NULL, NULL /* we'll handle these ourselves */
159   }, {
160     SASL_CB_AUTHNAME, NULL, NULL /* we'll handle these ourselves */
161   }, {
162       /* TODO
163          SASL_CB_ECHOPROMPT, &prompt, NULL
164   }, {
165     SASL_CB_NOECHOPROMPT, &prompt, NULL
166     }, { */
167     SASL_CB_LIST_END, NULL, NULL
168   }
169 };
170
171 /* client init */
172 JNIEXPORT jint JNICALL Java_CyrusSasl_ClientFactory_jni_1sasl_1client_1init
173   (JNIEnv *env,
174    jobject obj __attribute__((unused)),
175    jstring jstr)
176 {
177   /* Obtain a C-copy of the Java string */
178   const char *str = (*env)->GetStringUTFChars(env, jstr, 0);
179   int result;
180
181   VL(("client initing\n"));
182
183   result=sasl_client_init(callbacks);
184   if (result!=SASL_OK)
185     throwexception(env,result);
186
187   /* Now we are done with str */
188   (*env)->ReleaseStringUTFChars(env, jstr, str);
189
190   return result;
191 }
192
193 /* server new */
194
195 JNIEXPORT jint JNICALL Java_CyrusSasl_ServerFactory_jni_1sasl_1server_1new
196   (JNIEnv *env,
197    jobject obj __attribute__((unused)),
198    jstring jservice, 
199    jstring jlocal, 
200    jint jsecflags)
201 {
202   sasl_conn_t *conn;
203
204   const char *service = (*env)->GetStringUTFChars(env, jservice, 0);
205   const char *local_domain = (*env)->GetStringUTFChars(env, jlocal, 0);
206   const char *user_domain = NULL;  
207   int result;
208
209   if (local_domain) {
210       VL(("local domain = %s\n",local_domain));
211   }
212   if (user_domain) {
213       VL(("user domain = %s\n",user_domain));
214   }
215
216   result=sasl_server_new(service, local_domain, user_domain, 
217                          NULL, NULL, NULL, jsecflags, &conn);
218   if (result!=SASL_OK)
219     throwexception(env,result);
220
221   /* Now we are done with str */
222   (*env)->ReleaseStringUTFChars(env, jservice, service);  
223   (*env)->ReleaseStringUTFChars(env, jlocal, local_domain);  
224
225   return (jint) conn;
226 }
227
228
229 JNIEXPORT jint JNICALL JNICALL Java_CyrusSasl_ClientFactory_jni_1sasl_1client_1new
230   (JNIEnv *env,
231    jobject obj __attribute__((unused)),
232    jstring jservice, jstring jserver, jint jsecflags, jboolean successdata)
233 {
234   sasl_conn_t *conn;
235
236   const char *service = (*env)->GetStringUTFChars(env, jservice, 0);
237   const char *serverFQDN = (*env)->GetStringUTFChars(env, jserver, 0);
238   int result;
239
240   result=sasl_client_new(service, serverFQDN, NULL, NULL, NULL,
241                          jsecflags | (successdata ? SASL_SUCCESS_DATA : 0), 
242                          &conn);
243
244   if (result!=SASL_OK)
245     throwexception(env,result);
246
247   /* Now we are done with str */
248   (*env)->ReleaseStringUTFChars(env, jservice, service);  
249   (*env)->ReleaseStringUTFChars(env, jserver, serverFQDN);  
250
251   return (jint) conn;
252 }
253
254 /* server start */
255
256 JNIEXPORT jbyteArray JNICALL Java_CyrusSasl_GenericServer_jni_1sasl_1server_1start
257   (JNIEnv *env,
258    jobject obj __attribute__((unused)),
259    jint ptr, jstring jstr, jbyteArray jarr, jint jlen)
260 {
261   sasl_conn_t *conn;
262   const char *mech = (*env)->GetStringUTFChars(env, jstr, 0);
263   const char *out;
264   unsigned int outlen;
265    int result;
266   jbyteArray arr;
267   char *tmp;
268   char *in=NULL;
269
270   VL(("in server start\n"));
271
272   if (jarr!=NULL)
273     in = (*env)->GetByteArrayElements(env, jarr, 0);
274
275   conn=(sasl_conn_t *) ptr;
276
277   result=sasl_server_start(conn, mech,
278                            (const char *) in, jlen,
279                            &out, &outlen);
280
281   if ((result!=SASL_OK) && (result!=SASL_CONTINUE))
282   {
283
284     throwexception(env,result);
285     return NULL;
286   }
287
288   /* Because SASLv2 does not allow for persistance, we'll copy
289    * it here */
290   tmp = malloc(outlen);
291   if(!tmp) {
292       throwexception(env, SASL_NOMEM);
293       return NULL;
294   }
295
296   memcpy(tmp, out, outlen);
297   
298   arr=(*env)->NewByteArray(env,outlen);
299   (*env)->SetByteArrayRegion(env,arr, 0, outlen, (char *)tmp);
300
301   return arr;
302 }
303
304
305 static int getvalue(JNIEnv *env, jobject obj, char *funcname, char **result, int *len)
306 {
307     jclass cls;
308     jmethodID mid;
309     const char *str;
310     jstring jstr;
311     
312     /* set up for java callback */
313     cls = (*env)->GetObjectClass(env, obj);
314     mid = (*env)->GetMethodID(env, cls, funcname,
315                                   "(I)Ljava/lang/String;");
316     if (mid == 0) {
317         VL(("Can't find %s callback!!!\n",funcname));
318         return SASL_FAIL;
319     }
320
321     VL(("do the callback\n"));
322     jstr = (jstring) (*env)->CallObjectMethod(env, obj, mid);
323
324     if (jstr) {
325         VL(("convert the result string into a char *\n"));
326         str = (*env)->GetStringUTFChars(env, jstr, 0);
327
328         /* copy password into the result */    
329         *result=(char *) malloc( strlen(str));
330         strcpy(*result, str);
331         *len=strlen(str);
332
333         /* Now we are done with str */
334         (*env)->ReleaseStringUTFChars(env, jstr, str);
335     } else {
336         *result = NULL;
337         *len = 0;
338     }
339
340     return SASL_OK;
341 }
342
343 static int callall_callbacks(JNIEnv *env, jobject obj, 
344                              int calluid,int callaid,
345                              int callpass,int callrealm)
346 {
347     jclass cls;
348     jmethodID mid;
349     
350     /* set up for java callback */
351     cls = (*env)->GetObjectClass(env, obj);
352     mid = (*env)->GetMethodID(env, cls, "do_callbacks", "(IIII)V");
353     if (mid == 0) {
354         VL(("Can't find do_callbacks callback!!!\n"));
355         return SASL_FAIL;
356     }
357
358     /* do the callback */
359     (*env)->CallVoidMethod(env, obj, mid,calluid,callaid,callpass,callrealm);
360
361     VL(("callall_callbacks worked\n"));
362     return SASL_OK;
363 }
364
365 /*
366  * Fills in all the prompts by doing callbacks to java
367  * returns SASL_INTERACT on sucess
368  */
369
370 static int fillin_interactions(JNIEnv *env, jobject obj, 
371                                 sasl_interact_t *tlist)
372 {
373   sasl_interact_t *ptr=tlist;
374   sasl_interact_t *uid=NULL; int is_uid = 0;
375   sasl_interact_t *aid=NULL; int is_aid = 0;
376   sasl_interact_t *pass=NULL;int is_pass = 0;
377   sasl_interact_t *realm=NULL; int is_realm = 0;
378
379   /* First go through the prompt list to see what we have */
380   while (ptr->id!=SASL_CB_LIST_END)
381   {
382     if (ptr->id==SASL_CB_PASS)
383         {  pass=ptr; is_pass = 1; }
384     if (ptr->id==SASL_CB_AUTHNAME)
385         { aid=ptr; is_aid = 1; }
386     if (ptr->id==SASL_CB_USER)
387         { uid=ptr; is_uid = 1; }
388     if (ptr->id==SASL_CB_GETREALM)
389         { realm = ptr; is_realm = 1; }
390     ptr->result=NULL;
391     
392     /* increment to next sasl_interact_t */
393     ptr++;
394   }
395
396   callall_callbacks(env,obj,is_uid,is_aid,is_pass,is_realm);
397
398   if (is_pass) {
399       VL(("in is_pass\n"));
400
401       getvalue(env,obj,"get_password",(char **) &(pass->result),(int *) &(pass->len));
402   }
403   if (is_aid) {
404       VL(("in is_aid\n"));
405
406       getvalue(env,obj,"get_authid",(char **) &(aid->result),(int *) &(aid->len));
407   }
408   if (is_uid) {
409       VL(("in is_uid\n"));
410
411       getvalue(env,obj,"get_userid",(char **) &(uid->result),(int *) &(uid->len)); 
412   }
413   if (is_realm) {
414       VL(("in is_realm\n"));
415
416       getvalue(env,obj,"get_realm",(char **) &(realm->result),(int *) &(realm->len));
417   }
418
419   /* everything should now be filled in (i think) */
420   VL(("everything should now be filled in (i think)\n"));
421
422   return SASL_INTERACT;
423 }
424
425 /* client start */
426
427 JNIEXPORT jbyteArray JNICALL Java_CyrusSasl_GenericClient_jni_1sasl_1client_1start(JNIEnv *env, jobject obj, jint ptr, jstring jstr)
428 {    
429   sasl_conn_t *conn=(sasl_conn_t *) ptr;
430   const char *mechlist = (*env)->GetStringUTFChars(env, jstr, 0);
431   const char *out;
432   unsigned int outlen=0;
433   const char *mechusing;
434   int result;
435   sasl_interact_t *client_interact=NULL;
436   char *tmp;
437   jbyteArray arr;
438   jstring jmechusing;
439   jclass cls;
440   jmethodID mid;
441
442   VL(("sasl_start"));
443  
444   do {
445
446       result=sasl_client_start(conn, mechlist,
447                                &client_interact,
448                                &out, 
449                                &outlen,
450                                &mechusing);
451
452       if (result==SASL_INTERACT) {
453           int res2 = fillin_interactions(env,obj,client_interact);
454       }
455
456   } while (result==SASL_INTERACT);
457
458   /* ok release mechlist */
459   (*env)->ReleaseStringUTFChars(env, jstr, mechlist);  
460
461   if ((result!=SASL_OK) && (result!=SASL_CONTINUE))
462   {
463     throwexception(env,result);
464     return NULL;
465   }
466
467   /* tell the java layer what mechanism we're using */
468
469   /* set up for java callback */
470   cls = (*env)->GetObjectClass(env, obj);
471   mid = (*env)->GetMethodID(env, cls, "callback_setmechanism",
472                             "(Ljava/lang/String;I)V");
473   if (mid == 0) {
474       throwexception(env,SASL_FAIL);
475     return NULL;
476   }
477
478   VL(("mechusing=%s\n",mechusing));
479
480   /* make into mech */
481   jmechusing= (*env)->NewStringUTF(env,mechusing);
482
483   /* do the callback */
484   (*env)->CallVoidMethod(env, obj, mid,jmechusing);
485
486   /* Because SASLv2 does not allow for persistance, we'll copy
487    * it here */
488   tmp = malloc(outlen);
489   if(!tmp) {
490       throwexception(env, SASL_NOMEM);
491       return NULL;
492   }
493   
494   memcpy(tmp, out, outlen);
495   
496   arr=(*env)->NewByteArray(env,outlen);
497   (*env)->SetByteArrayRegion(env,arr, 0, outlen, (char *)tmp);
498
499   return arr;
500 }
501
502 /* server step */
503
504 JNIEXPORT jbyteArray JNICALL Java_CyrusSasl_GenericServer_jni_1sasl_1server_1step
505
506   (JNIEnv *env,
507    jobject obj __attribute__((unused)),
508    jint ptr, jbyteArray jarr, jint jlen)
509 {
510   sasl_conn_t *conn=(sasl_conn_t *) ptr;
511   int result;
512   const char *out;
513   unsigned int outlen;
514   jbyteArray arr;
515   char *in = NULL;
516   char *tmp;
517   
518   if (jlen > 0)
519       in = (*env)->GetByteArrayElements(env, jarr, 0);
520
521   result=sasl_server_step(conn, (const char *) in, jlen,
522                           &out, &outlen);
523
524   if ((result!=SASL_OK) && (result!=SASL_CONTINUE))
525   {
526       VL (("Throwing exception! %d\n",result));
527       /* throw exception */
528       throwexception(env,result);
529       return NULL;
530   }
531
532   if (result == SASL_OK) {
533       setcomplete(env,obj);
534   }
535
536   if (jlen > 0)
537       (*env)->ReleaseByteArrayElements(env, jarr,in ,0);
538
539   /* Because SASLv2 does not allow for persistance, we'll copy
540    * it here */
541   tmp = malloc(outlen);
542   if(!tmp) {
543       throwexception(env, SASL_NOMEM);
544       return NULL;
545   }
546
547   memcpy(tmp, out, outlen);
548   
549   arr=(*env)->NewByteArray(env,outlen);
550   (*env)->SetByteArrayRegion(env,arr, 0, outlen, (char *)tmp);
551
552   return arr;
553 }
554
555
556 /* 
557  * Tell client we're done
558  */
559 static int setcomplete(JNIEnv *env, jobject obj)
560 {
561     jclass cls;
562     jmethodID mid;
563
564     VL (("Complete!\n"));
565     
566     /* set up for java callback */
567     cls = (*env)->GetObjectClass(env, obj);
568     mid = (*env)->GetMethodID(env, cls, "setcomplete",
569                                   "(I)V");
570     if (mid == 0) {
571         VL(("Can't find do_callbacks callback!!!\n"));
572         return SASL_FAIL;
573     }
574
575     /* do the callback */
576     (*env)->CallVoidMethod(env, obj, mid, 5);
577
578     return SASL_OK;
579 }
580
581 /* client step */
582
583 JNIEXPORT jbyteArray JNICALL Java_CyrusSasl_GenericClient_jni_1sasl_1client_1step
584     (JNIEnv *env, jobject obj, jint ptr, jbyteArray jarr, jint jlen)
585 {    
586   sasl_conn_t *conn=(sasl_conn_t *) ptr;
587   /*  const char *in = (*env)->GetStringUTFChars(env, jstr, 0);*/
588   int result;
589   sasl_interact_t *client_interact=NULL;
590   const char *out;
591   unsigned int outlen;
592   jbyteArray arr;
593   char *in;
594   char *tmp;
595   
596   VL(("in client step\n"));
597
598   if (jarr) {
599       in = (*env)->GetByteArrayElements(env, jarr, 0);
600       in[jlen]=0;
601   } else {
602       assert(jlen == 0);
603        in = NULL;
604   }
605
606   VL(("in client step 2\n"));
607
608   globalenv=env;
609   globalobj=obj;
610
611   do {
612       result=sasl_client_step(conn, (const char *) in, jlen,
613                               &client_interact,
614                               &out, &outlen);
615
616       VL(("in client step 3\n"));
617
618       if (result==SASL_INTERACT) {
619           result = fillin_interactions(env,obj,client_interact);
620       }
621   } while (result==SASL_INTERACT);
622
623   if ((result!=SASL_OK) && (result!=SASL_CONTINUE)) {
624       /* throw exception */
625       VL (("Throwing exception %d\n",result));
626       throwexception(env,result);
627       return NULL;
628   }
629
630   if (result == SASL_OK) {
631       VL (("Setting complete\n"));
632       setcomplete(env,obj);
633   }
634
635   if (jarr) {
636       VL(("about to releasebytearrayelements\n"));
637       (*env)->ReleaseByteArrayElements(env, jarr,in ,0);
638   }
639       
640   /* Because SASLv2 does not allow for persistance, we'll copy
641    * it here */
642   tmp = malloc(outlen);
643   if(!tmp) {
644       throwexception(env, SASL_NOMEM);
645       return NULL;
646   }
647
648   VL(("in client step 4\n"));
649
650   memcpy(tmp, out, outlen);
651   
652   arr=(*env)->NewByteArray(env,outlen);
653   (*env)->SetByteArrayRegion(env,arr, 0, outlen, (char *)tmp);
654
655   VL(("returning arr\n"));
656   return arr;
657 }
658
659
660 JNIEXPORT void JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1set_1prop_1string
661   (JNIEnv *env,
662    jobject obj __attribute__((unused)),
663    jint ptr, jint propnum, jstring val)
664 {
665   sasl_conn_t *conn=(sasl_conn_t *) ptr;
666   const char *value = (*env)->GetStringUTFChars(env, val, 0);
667
668   int result=sasl_setprop(conn, propnum, value);
669
670   if (result!=SASL_OK)
671     throwexception(env,result);
672 }
673
674
675 JNIEXPORT void JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1set_1prop_1int
676   (JNIEnv *env,
677    jobject obj __attribute__((unused)),
678    jint ptr, jint propnum, jint jval)
679 {
680
681   sasl_conn_t *conn=(sasl_conn_t *) ptr;
682   int value=jval;
683   int result;
684
685   VL(("sasl conn = %d\n",conn));
686   VL (("propnum = %d\n",propnum));
687
688   result=sasl_setprop(conn, propnum, &value);  
689
690   VL (("setprop returned %d\n",result));
691
692   if (result!=SASL_OK)
693     throwexception(env,result);
694 }
695 JNIEXPORT void JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1set_1prop_1bytes
696   (JNIEnv *env,
697    jobject obj __attribute__((unused)),
698    jint ptr, jint propnum, jbyteArray jarr)
699 {
700   char *value = (*env)->GetByteArrayElements(env, jarr, 0);
701   sasl_conn_t *conn=(sasl_conn_t *) ptr;
702   int result;
703
704   result=sasl_setprop(conn, propnum, value);
705   if (result!=SASL_OK)
706     throwexception(env,result);
707
708 }
709
710 /* encode */
711 JNIEXPORT jbyteArray JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1encode
712   (JNIEnv *env,
713    jobject obj __attribute__((unused)),
714    jint ptr, 
715    jbyteArray jarr, jint jlen)
716 {
717   sasl_conn_t *conn=(sasl_conn_t *) ptr;
718   char *in = (*env)->GetByteArrayElements(env, jarr, 0);
719   const char *out;
720   unsigned int outlen;
721   char *tmp;
722   int result;
723   jbyteArray arr;
724
725   result=sasl_encode(conn,(const char *) in, jlen, &out, &outlen);
726   if (result!=SASL_OK)
727     throwexception(env,result);
728
729   /* Because SASLv2 does not allow for persistance, we'll copy
730    * it here */
731   tmp = malloc(outlen);
732   if(!tmp) {
733       throwexception(env, SASL_NOMEM);
734       return NULL;
735   }
736
737   memcpy(tmp, out, outlen);
738   
739   arr=(*env)->NewByteArray(env,outlen);
740   (*env)->SetByteArrayRegion(env,arr, 0, outlen, (char *)tmp);
741
742   return arr;
743 }
744
745 /* decode */
746 JNIEXPORT jbyteArray JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1decode
747   (JNIEnv *env,
748    jobject obj __attribute__((unused)), 
749    jint ptr, jbyteArray jarr, jint jlen)
750 {
751
752   sasl_conn_t *conn=(sasl_conn_t *) ptr;
753   char *in = (*env)->GetByteArrayElements(env, jarr, 0);
754   const char *out;
755   unsigned int outlen=9;
756   char *tmp;
757   int inlen=jlen;
758   int result;
759   jbyteArray arr;
760
761   result=sasl_decode(conn, (const char *) in, inlen, &out, &outlen);
762   if (result!=SASL_OK)
763     throwexception(env,result);
764
765
766   /* Because SASLv2 does not allow for persistance, we'll copy
767    * it here */
768   tmp = malloc(outlen);
769   if(!tmp) {
770       throwexception(env, SASL_NOMEM);
771       return NULL;
772   }
773
774   memcpy(tmp, out, outlen);
775   
776   arr=(*env)->NewByteArray(env,outlen);
777   (*env)->SetByteArrayRegion(env,arr, 0, outlen, (char *)tmp);
778
779   (*env)->ReleaseByteArrayElements(env, jarr, in,0);
780
781   return arr;
782
783 }
784
785 /*JNIEXPORT jbyteArray JNICALL Java_sasl_saslServerConn_jni_1sasl_1server_1decode
786   (JNIEnv *env, jobject obj, jint ptr, jbyteArray in, jint inlen)
787 {
788   return Java_sasl_saslClientConn_jni_1sasl_1client_1decode(env,obj,ptr,in,inlen);
789   }*/
790
791 JNIEXPORT void JNICALL Java_CyrusSasl_CommonConn_jni_1sasl_1dispose
792   (JNIEnv *env __attribute__((unused)),
793    jobject obj __attribute__((unused)),
794    jint ptr)
795 {
796   sasl_conn_t *conn=(sasl_conn_t *) ptr;
797
798   sasl_dispose(&conn);
799
800 }
801
802 JNIEXPORT jstring JNICALL Java_CyrusSasl_ServerFactory_jni_1sasl_1server_1getlist
803   (JNIEnv *env,
804    jobject obj __attribute__((unused)),
805    jint ptr, jstring jpre, jstring jsep, jstring jsuf)
806 {
807   sasl_conn_t *conn=(sasl_conn_t *) ptr;
808   const char *pre = (*env)->GetStringUTFChars(env, jpre, 0);
809   const char *sep = (*env)->GetStringUTFChars(env, jsep, 0);
810   const char *suf = (*env)->GetStringUTFChars(env, jsuf, 0);
811   const char *list;
812   unsigned int plen;
813   jstring ret;
814
815   int result=sasl_listmech(conn, NULL, pre, sep, suf, &list, &plen, NULL);
816
817   if (result!=SASL_OK)
818   {
819     throwexception(env,result);  
820     return NULL;
821   }
822
823   ret= (*env)->NewStringUTF(env,list);
824   if (ret==NULL)
825     throwexception(env, -1);
826
827   return ret;
828 }
829
830 JNIEXPORT void JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1set_1server
831   (JNIEnv *env,
832    jobject obj __attribute__((unused)),
833    jint ptr, jbyteArray jarr, jint jport)
834 {
835   sasl_conn_t *conn=(sasl_conn_t *) ptr;
836   unsigned char *ip = (*env)->GetByteArrayElements(env, jarr, 0);
837   char out[52];
838   int result;
839
840   sprintf(out, "%d.%d.%d.%d;%d", ip[0], ip[1], ip[2], ip[3], (int)jport);
841
842   result=sasl_setprop(conn, SASL_IPREMOTEPORT, out);  
843
844   VL(("Set IP_REMOTE: %s: %d\n",out, result));
845
846   /* if not set throw an exception */
847   if (result!=SASL_OK)
848     throwexception(env,result); 
849 }
850
851
852
853 JNIEXPORT void JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1set_1client
854   (JNIEnv *env,
855    jobject obj __attribute__((unused)),
856    jint ptr, jbyteArray jarr, jint jport)
857 {
858   sasl_conn_t *conn=(sasl_conn_t *) ptr;
859   unsigned char *ip = (*env)->GetByteArrayElements(env, jarr, 0);
860   char out[52];
861   int result;
862
863   sprintf(out, "%d.%d.%d.%d;%d", ip[0], ip[1], ip[2], ip[3], (int)jport);
864
865   result=sasl_setprop(conn, SASL_IPLOCALPORT, out);
866
867   VL(("Set IP_LOCAL: %s: %d\n",out, result));
868
869   /* if not set throw and exception */
870   if (result!=SASL_OK)
871     throwexception(env,result);  
872 }
873
874 /* allocate a secprops structure */
875
876 static sasl_security_properties_t *make_secprops(int min,int max)
877 {
878   sasl_security_properties_t *ret=(sasl_security_properties_t *)
879     malloc(sizeof(sasl_security_properties_t));
880
881   ret->maxbufsize=1024;
882   ret->min_ssf=min;
883   ret->max_ssf=max;
884
885   ret->security_flags=0;
886   ret->property_names=NULL;
887   ret->property_values=NULL;
888
889   return ret;
890 }
891
892
893 JNIEXPORT void JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1setSecurity
894   (JNIEnv *env,
895    jobject obj __attribute__((unused)),
896    jint ptr, jint minssf, jint maxssf)
897 {
898   int result=SASL_FAIL;
899   sasl_conn_t *conn=(sasl_conn_t *) ptr;
900   sasl_security_properties_t *secprops=NULL;
901   
902   /* set sec props */
903   secprops=make_secprops(minssf,maxssf);
904
905   if (secprops!=NULL)
906     result=sasl_setprop(conn, SASL_SEC_PROPS, secprops);  
907
908   /* if not set throw and exception */
909   if (result!=SASL_OK)
910     throwexception(env,result);
911 }
912
913 JNIEXPORT jint JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1getSecurity
914   (JNIEnv *env,
915    jobject obj __attribute__((unused)),
916    jint ptr)
917 {
918     int r = SASL_FAIL;
919     sasl_conn_t *conn = (sasl_conn_t *) ptr;
920     int *ssfp;
921
922     r = sasl_getprop(conn, SASL_SSF, (const void **) &ssfp);
923     if (r != SASL_OK) {
924         throwexception(env, r);
925     }
926
927     return *ssfp;
928 }
929
930