1 /* javasasl.c--Java SASL JNI implementation
4 /***********************************************************
5 Copyright 1998 by Carnegie Mellon University
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
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 ******************************************************************/
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
40 #define VL(x) /* printf x */
42 static JNIEnv *globalenv;
43 static jobject globalobj;
45 static int setcomplete(JNIEnv *env, jobject obj);
47 static void throwexception(JNIEnv *env, int error)
51 VL (("Throwing exception!\n"));
53 newExcCls = (*env)->FindClass(env, "CyrusSasl/SaslException");
59 (*env)->ThrowNew(env, newExcCls, sasl_errstring(error,NULL,NULL));
64 JNIEXPORT jint JNICALL Java_CyrusSasl_ServerFactory_jni_1sasl_1server_1init
66 jobject obj __attribute__((unused)),
69 /* Obtain a C-copy of the Java string */
70 const char *str = (*env)->GetStringUTFChars(env, jstr, 0);
73 result=sasl_server_init(NULL,str);
75 throwexception(env,result);
77 /* Now we are done with str */
78 (*env)->ReleaseStringUTFChars(env, jstr, str);
84 log(void *context __attribute__((unused)),
89 jstring jlabel, jmessage;
119 return SASL_BADPARAM;
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");
131 /* make label into a java string */
132 jlabel= (*globalenv)->NewStringUTF(globalenv,label);
134 /* make message into a java string */
135 jmessage= (*globalenv)->NewStringUTF(globalenv,message);
138 (*globalenv)->CallVoidMethod(globalenv, globalobj, mid,
141 /* Now we are done with jlabel */
142 (*globalenv)->ReleaseStringUTFChars(globalenv, jlabel, label);
144 /* Now we are done with jmessage */
145 (*globalenv)->ReleaseStringUTFChars(globalenv, jmessage, message);
147 VL(("done with log callback"));
152 static sasl_callback_t callbacks[] = {
154 SASL_CB_LOG, &log, NULL
156 SASL_CB_PASS, NULL, NULL
158 SASL_CB_USER, NULL, NULL /* we'll handle these ourselves */
160 SASL_CB_AUTHNAME, NULL, NULL /* we'll handle these ourselves */
163 SASL_CB_ECHOPROMPT, &prompt, NULL
165 SASL_CB_NOECHOPROMPT, &prompt, NULL
167 SASL_CB_LIST_END, NULL, NULL
172 JNIEXPORT jint JNICALL Java_CyrusSasl_ClientFactory_jni_1sasl_1client_1init
174 jobject obj __attribute__((unused)),
177 /* Obtain a C-copy of the Java string */
178 const char *str = (*env)->GetStringUTFChars(env, jstr, 0);
181 VL(("client initing\n"));
183 result=sasl_client_init(callbacks);
185 throwexception(env,result);
187 /* Now we are done with str */
188 (*env)->ReleaseStringUTFChars(env, jstr, str);
195 JNIEXPORT jint JNICALL Java_CyrusSasl_ServerFactory_jni_1sasl_1server_1new
197 jobject obj __attribute__((unused)),
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;
210 VL(("local domain = %s\n",local_domain));
213 VL(("user domain = %s\n",user_domain));
216 result=sasl_server_new(service, local_domain, user_domain,
217 NULL, NULL, NULL, jsecflags, &conn);
219 throwexception(env,result);
221 /* Now we are done with str */
222 (*env)->ReleaseStringUTFChars(env, jservice, service);
223 (*env)->ReleaseStringUTFChars(env, jlocal, local_domain);
229 JNIEXPORT jint JNICALL JNICALL Java_CyrusSasl_ClientFactory_jni_1sasl_1client_1new
231 jobject obj __attribute__((unused)),
232 jstring jservice, jstring jserver, jint jsecflags, jboolean successdata)
236 const char *service = (*env)->GetStringUTFChars(env, jservice, 0);
237 const char *serverFQDN = (*env)->GetStringUTFChars(env, jserver, 0);
240 result=sasl_client_new(service, serverFQDN, NULL, NULL, NULL,
241 jsecflags | (successdata ? SASL_SUCCESS_DATA : 0),
245 throwexception(env,result);
247 /* Now we are done with str */
248 (*env)->ReleaseStringUTFChars(env, jservice, service);
249 (*env)->ReleaseStringUTFChars(env, jserver, serverFQDN);
256 JNIEXPORT jbyteArray JNICALL Java_CyrusSasl_GenericServer_jni_1sasl_1server_1start
258 jobject obj __attribute__((unused)),
259 jint ptr, jstring jstr, jbyteArray jarr, jint jlen)
262 const char *mech = (*env)->GetStringUTFChars(env, jstr, 0);
270 VL(("in server start\n"));
273 in = (*env)->GetByteArrayElements(env, jarr, 0);
275 conn=(sasl_conn_t *) ptr;
277 result=sasl_server_start(conn, mech,
278 (const char *) in, jlen,
281 if ((result!=SASL_OK) && (result!=SASL_CONTINUE))
284 throwexception(env,result);
288 /* Because SASLv2 does not allow for persistance, we'll copy
290 tmp = malloc(outlen);
292 throwexception(env, SASL_NOMEM);
296 memcpy(tmp, out, outlen);
298 arr=(*env)->NewByteArray(env,outlen);
299 (*env)->SetByteArrayRegion(env,arr, 0, outlen, (char *)tmp);
305 static int getvalue(JNIEnv *env, jobject obj, char *funcname, char **result, int *len)
312 /* set up for java callback */
313 cls = (*env)->GetObjectClass(env, obj);
314 mid = (*env)->GetMethodID(env, cls, funcname,
315 "(I)Ljava/lang/String;");
317 VL(("Can't find %s callback!!!\n",funcname));
321 VL(("do the callback\n"));
322 jstr = (jstring) (*env)->CallObjectMethod(env, obj, mid);
325 VL(("convert the result string into a char *\n"));
326 str = (*env)->GetStringUTFChars(env, jstr, 0);
328 /* copy password into the result */
329 *result=(char *) malloc( strlen(str));
330 strcpy(*result, str);
333 /* Now we are done with str */
334 (*env)->ReleaseStringUTFChars(env, jstr, str);
343 static int callall_callbacks(JNIEnv *env, jobject obj,
344 int calluid,int callaid,
345 int callpass,int callrealm)
350 /* set up for java callback */
351 cls = (*env)->GetObjectClass(env, obj);
352 mid = (*env)->GetMethodID(env, cls, "do_callbacks", "(IIII)V");
354 VL(("Can't find do_callbacks callback!!!\n"));
358 /* do the callback */
359 (*env)->CallVoidMethod(env, obj, mid,calluid,callaid,callpass,callrealm);
361 VL(("callall_callbacks worked\n"));
366 * Fills in all the prompts by doing callbacks to java
367 * returns SASL_INTERACT on sucess
370 static int fillin_interactions(JNIEnv *env, jobject obj,
371 sasl_interact_t *tlist)
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;
379 /* First go through the prompt list to see what we have */
380 while (ptr->id!=SASL_CB_LIST_END)
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; }
392 /* increment to next sasl_interact_t */
396 callall_callbacks(env,obj,is_uid,is_aid,is_pass,is_realm);
399 VL(("in is_pass\n"));
401 getvalue(env,obj,"get_password",(char **) &(pass->result),(int *) &(pass->len));
406 getvalue(env,obj,"get_authid",(char **) &(aid->result),(int *) &(aid->len));
411 getvalue(env,obj,"get_userid",(char **) &(uid->result),(int *) &(uid->len));
414 VL(("in is_realm\n"));
416 getvalue(env,obj,"get_realm",(char **) &(realm->result),(int *) &(realm->len));
419 /* everything should now be filled in (i think) */
420 VL(("everything should now be filled in (i think)\n"));
422 return SASL_INTERACT;
427 JNIEXPORT jbyteArray JNICALL Java_CyrusSasl_GenericClient_jni_1sasl_1client_1start(JNIEnv *env, jobject obj, jint ptr, jstring jstr)
429 sasl_conn_t *conn=(sasl_conn_t *) ptr;
430 const char *mechlist = (*env)->GetStringUTFChars(env, jstr, 0);
432 unsigned int outlen=0;
433 const char *mechusing;
435 sasl_interact_t *client_interact=NULL;
446 result=sasl_client_start(conn, mechlist,
452 if (result==SASL_INTERACT) {
453 int res2 = fillin_interactions(env,obj,client_interact);
456 } while (result==SASL_INTERACT);
458 /* ok release mechlist */
459 (*env)->ReleaseStringUTFChars(env, jstr, mechlist);
461 if ((result!=SASL_OK) && (result!=SASL_CONTINUE))
463 throwexception(env,result);
467 /* tell the java layer what mechanism we're using */
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");
474 throwexception(env,SASL_FAIL);
478 VL(("mechusing=%s\n",mechusing));
481 jmechusing= (*env)->NewStringUTF(env,mechusing);
483 /* do the callback */
484 (*env)->CallVoidMethod(env, obj, mid,jmechusing);
486 /* Because SASLv2 does not allow for persistance, we'll copy
488 tmp = malloc(outlen);
490 throwexception(env, SASL_NOMEM);
494 memcpy(tmp, out, outlen);
496 arr=(*env)->NewByteArray(env,outlen);
497 (*env)->SetByteArrayRegion(env,arr, 0, outlen, (char *)tmp);
504 JNIEXPORT jbyteArray JNICALL Java_CyrusSasl_GenericServer_jni_1sasl_1server_1step
507 jobject obj __attribute__((unused)),
508 jint ptr, jbyteArray jarr, jint jlen)
510 sasl_conn_t *conn=(sasl_conn_t *) ptr;
519 in = (*env)->GetByteArrayElements(env, jarr, 0);
521 result=sasl_server_step(conn, (const char *) in, jlen,
524 if ((result!=SASL_OK) && (result!=SASL_CONTINUE))
526 VL (("Throwing exception! %d\n",result));
527 /* throw exception */
528 throwexception(env,result);
532 if (result == SASL_OK) {
533 setcomplete(env,obj);
537 (*env)->ReleaseByteArrayElements(env, jarr,in ,0);
539 /* Because SASLv2 does not allow for persistance, we'll copy
541 tmp = malloc(outlen);
543 throwexception(env, SASL_NOMEM);
547 memcpy(tmp, out, outlen);
549 arr=(*env)->NewByteArray(env,outlen);
550 (*env)->SetByteArrayRegion(env,arr, 0, outlen, (char *)tmp);
557 * Tell client we're done
559 static int setcomplete(JNIEnv *env, jobject obj)
564 VL (("Complete!\n"));
566 /* set up for java callback */
567 cls = (*env)->GetObjectClass(env, obj);
568 mid = (*env)->GetMethodID(env, cls, "setcomplete",
571 VL(("Can't find do_callbacks callback!!!\n"));
575 /* do the callback */
576 (*env)->CallVoidMethod(env, obj, mid, 5);
583 JNIEXPORT jbyteArray JNICALL Java_CyrusSasl_GenericClient_jni_1sasl_1client_1step
584 (JNIEnv *env, jobject obj, jint ptr, jbyteArray jarr, jint jlen)
586 sasl_conn_t *conn=(sasl_conn_t *) ptr;
587 /* const char *in = (*env)->GetStringUTFChars(env, jstr, 0);*/
589 sasl_interact_t *client_interact=NULL;
596 VL(("in client step\n"));
599 in = (*env)->GetByteArrayElements(env, jarr, 0);
606 VL(("in client step 2\n"));
612 result=sasl_client_step(conn, (const char *) in, jlen,
616 VL(("in client step 3\n"));
618 if (result==SASL_INTERACT) {
619 result = fillin_interactions(env,obj,client_interact);
621 } while (result==SASL_INTERACT);
623 if ((result!=SASL_OK) && (result!=SASL_CONTINUE)) {
624 /* throw exception */
625 VL (("Throwing exception %d\n",result));
626 throwexception(env,result);
630 if (result == SASL_OK) {
631 VL (("Setting complete\n"));
632 setcomplete(env,obj);
636 VL(("about to releasebytearrayelements\n"));
637 (*env)->ReleaseByteArrayElements(env, jarr,in ,0);
640 /* Because SASLv2 does not allow for persistance, we'll copy
642 tmp = malloc(outlen);
644 throwexception(env, SASL_NOMEM);
648 VL(("in client step 4\n"));
650 memcpy(tmp, out, outlen);
652 arr=(*env)->NewByteArray(env,outlen);
653 (*env)->SetByteArrayRegion(env,arr, 0, outlen, (char *)tmp);
655 VL(("returning arr\n"));
660 JNIEXPORT void JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1set_1prop_1string
662 jobject obj __attribute__((unused)),
663 jint ptr, jint propnum, jstring val)
665 sasl_conn_t *conn=(sasl_conn_t *) ptr;
666 const char *value = (*env)->GetStringUTFChars(env, val, 0);
668 int result=sasl_setprop(conn, propnum, value);
671 throwexception(env,result);
675 JNIEXPORT void JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1set_1prop_1int
677 jobject obj __attribute__((unused)),
678 jint ptr, jint propnum, jint jval)
681 sasl_conn_t *conn=(sasl_conn_t *) ptr;
685 VL(("sasl conn = %d\n",conn));
686 VL (("propnum = %d\n",propnum));
688 result=sasl_setprop(conn, propnum, &value);
690 VL (("setprop returned %d\n",result));
693 throwexception(env,result);
695 JNIEXPORT void JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1set_1prop_1bytes
697 jobject obj __attribute__((unused)),
698 jint ptr, jint propnum, jbyteArray jarr)
700 char *value = (*env)->GetByteArrayElements(env, jarr, 0);
701 sasl_conn_t *conn=(sasl_conn_t *) ptr;
704 result=sasl_setprop(conn, propnum, value);
706 throwexception(env,result);
711 JNIEXPORT jbyteArray JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1encode
713 jobject obj __attribute__((unused)),
715 jbyteArray jarr, jint jlen)
717 sasl_conn_t *conn=(sasl_conn_t *) ptr;
718 char *in = (*env)->GetByteArrayElements(env, jarr, 0);
725 result=sasl_encode(conn,(const char *) in, jlen, &out, &outlen);
727 throwexception(env,result);
729 /* Because SASLv2 does not allow for persistance, we'll copy
731 tmp = malloc(outlen);
733 throwexception(env, SASL_NOMEM);
737 memcpy(tmp, out, outlen);
739 arr=(*env)->NewByteArray(env,outlen);
740 (*env)->SetByteArrayRegion(env,arr, 0, outlen, (char *)tmp);
746 JNIEXPORT jbyteArray JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1decode
748 jobject obj __attribute__((unused)),
749 jint ptr, jbyteArray jarr, jint jlen)
752 sasl_conn_t *conn=(sasl_conn_t *) ptr;
753 char *in = (*env)->GetByteArrayElements(env, jarr, 0);
755 unsigned int outlen=9;
761 result=sasl_decode(conn, (const char *) in, inlen, &out, &outlen);
763 throwexception(env,result);
766 /* Because SASLv2 does not allow for persistance, we'll copy
768 tmp = malloc(outlen);
770 throwexception(env, SASL_NOMEM);
774 memcpy(tmp, out, outlen);
776 arr=(*env)->NewByteArray(env,outlen);
777 (*env)->SetByteArrayRegion(env,arr, 0, outlen, (char *)tmp);
779 (*env)->ReleaseByteArrayElements(env, jarr, in,0);
785 /*JNIEXPORT jbyteArray JNICALL Java_sasl_saslServerConn_jni_1sasl_1server_1decode
786 (JNIEnv *env, jobject obj, jint ptr, jbyteArray in, jint inlen)
788 return Java_sasl_saslClientConn_jni_1sasl_1client_1decode(env,obj,ptr,in,inlen);
791 JNIEXPORT void JNICALL Java_CyrusSasl_CommonConn_jni_1sasl_1dispose
792 (JNIEnv *env __attribute__((unused)),
793 jobject obj __attribute__((unused)),
796 sasl_conn_t *conn=(sasl_conn_t *) ptr;
802 JNIEXPORT jstring JNICALL Java_CyrusSasl_ServerFactory_jni_1sasl_1server_1getlist
804 jobject obj __attribute__((unused)),
805 jint ptr, jstring jpre, jstring jsep, jstring jsuf)
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);
815 int result=sasl_listmech(conn, NULL, pre, sep, suf, &list, &plen, NULL);
819 throwexception(env,result);
823 ret= (*env)->NewStringUTF(env,list);
825 throwexception(env, -1);
830 JNIEXPORT void JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1set_1server
832 jobject obj __attribute__((unused)),
833 jint ptr, jbyteArray jarr, jint jport)
835 sasl_conn_t *conn=(sasl_conn_t *) ptr;
836 unsigned char *ip = (*env)->GetByteArrayElements(env, jarr, 0);
840 sprintf(out, "%d.%d.%d.%d;%d", ip[0], ip[1], ip[2], ip[3], (int)jport);
842 result=sasl_setprop(conn, SASL_IPREMOTEPORT, out);
844 VL(("Set IP_REMOTE: %s: %d\n",out, result));
846 /* if not set throw an exception */
848 throwexception(env,result);
853 JNIEXPORT void JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1set_1client
855 jobject obj __attribute__((unused)),
856 jint ptr, jbyteArray jarr, jint jport)
858 sasl_conn_t *conn=(sasl_conn_t *) ptr;
859 unsigned char *ip = (*env)->GetByteArrayElements(env, jarr, 0);
863 sprintf(out, "%d.%d.%d.%d;%d", ip[0], ip[1], ip[2], ip[3], (int)jport);
865 result=sasl_setprop(conn, SASL_IPLOCALPORT, out);
867 VL(("Set IP_LOCAL: %s: %d\n",out, result));
869 /* if not set throw and exception */
871 throwexception(env,result);
874 /* allocate a secprops structure */
876 static sasl_security_properties_t *make_secprops(int min,int max)
878 sasl_security_properties_t *ret=(sasl_security_properties_t *)
879 malloc(sizeof(sasl_security_properties_t));
881 ret->maxbufsize=1024;
885 ret->security_flags=0;
886 ret->property_names=NULL;
887 ret->property_values=NULL;
893 JNIEXPORT void JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1setSecurity
895 jobject obj __attribute__((unused)),
896 jint ptr, jint minssf, jint maxssf)
898 int result=SASL_FAIL;
899 sasl_conn_t *conn=(sasl_conn_t *) ptr;
900 sasl_security_properties_t *secprops=NULL;
903 secprops=make_secprops(minssf,maxssf);
906 result=sasl_setprop(conn, SASL_SEC_PROPS, secprops);
908 /* if not set throw and exception */
910 throwexception(env,result);
913 JNIEXPORT jint JNICALL Java_CyrusSasl_GenericCommon_jni_1sasl_1getSecurity
915 jobject obj __attribute__((unused)),
919 sasl_conn_t *conn = (sasl_conn_t *) ptr;
922 r = sasl_getprop(conn, SASL_SSF, (const void **) &ssfp);
924 throwexception(env, r);