[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

C code works with rubyinline, doesn't with C extension

snacktime

9/16/2006 9:40:00 PM

So I've blatantly stolen some code from a perl module to do simple
kerberos authentication and not being the most adept C programmer I
have something I can't figure out.

The following code using rubyinline works fine. The code below that
which is just a ruby c extension segfaults on the call to
krb5_free_cred_contents(ctx, &creds). If I comment it out then it
works. This is on Freebsd 6.1 using MIT kerberos, ruby 1.8.5 with the
latest RubyInline.


-------------------------------------------
require 'rubygems'
require 'inline'

class Krb
inline(:C) do |builder|
builder.include '<krb5.h>'
builder.include '<stdio.h>'
builder.include '<strings.h>'
builder.add_compile_flags "-I/usr/local/include -L/usr/local/lib
-lkrb5 -lk5crypto -lcom_err"
builder.c "
int _krb5_auth(char* user, char* pass)
{
int krbret;
krb5_context ctx;
krb5_creds creds;
krb5_principal princ;

int ret = 0;

/* Initialize krb5 context...
*/
if ((krbret = krb5_init_context(&ctx))) {
return krbret;
}

memset(&creds, 0, sizeof(krb5_creds));

/* Get principal name...
*/
if ((krbret = krb5_parse_name(ctx, user, &princ))) {
ret = krbret;
krb5_free_context(ctx);
}

/* Check the user's pasword...
*/
if ((krbret = krb5_get_init_creds_password(
ctx, &creds, princ, pass, 0, NULL, 0, NULL, NULL))) {
ret = krbret;
krb5_free_cred_contents(ctx, &creds);
krb5_free_principal(ctx, princ);
}

return ret;
}"
end
end

k = Krb.new
res = k._krb5_auth('test','test')
p res

-------------------------------------------------------
#include "ruby.h"
#include <krb5.h>
#include <stdio.h>
#include <strings.h>

static VALUE _krb5_auth(VALUE self, VALUE _user, VALUE _pass) {
char * user = STR2CSTR(_user);
char * pass = STR2CSTR(_pass);

int krbret;
krb5_context ctx;
krb5_creds creds;
krb5_principal princ;

int ret = 0;
if ((krbret = krb5_init_context(&ctx))) {
return INT2FIX(krbret);
}

memset(&creds, 0, sizeof(krb5_creds));
if ((krbret = krb5_parse_name(ctx, user, &princ))) {
ret = krbret;
krb5_free_context(ctx);
}
if ((krbret = krb5_get_init_creds_password(
ctx, &creds, princ, pass, 0, NULL, 0, NULL, NULL))) {
ret = krbret;
/* krb5_free_cred_contents(ctx, &creds); Uncomment this to
get a segfault*/
krb5_free_principal(ctx, princ);
}


return INT2FIX(ret);
}


void Init_krb() {
VALUE Krb = rb_define_class("Krb", rb_cObject);
rb_define_method(Krb, "krb5_auth", _krb5_auth,2);
}

-----------------------------------------------
require 'mkmf'
extension_name = 'krb'
dir_config("/usr/local/lib","/usr/local/include")
have_library("krb5","krb5_init_context")
have_library("k5crypto","krb5_encrypt")
have_library("com_err","com_err")
create_makefile(extension_name)

3 Answers

snacktime

9/16/2006 9:59:00 PM

0

I forgot to mention. The c extension only fails when I pass bad
credentials and the call to krb5_get_init_creds_password fails. Also,
the extension code is the same as the C code generated by RubyInline
except for the Init_ definition.

Chris

Squeamizh

9/18/2006 4:15:00 PM

0

snacktime wrote:
> I forgot to mention. The c extension only fails when I pass bad
> credentials and the call to krb5_get_init_creds_password fails. Also,
> the extension code is the same as the C code generated by RubyInline
> except for the Init_ definition.

Unfortunately, it is difficult to say without knowing mroe about krb5's
interface. Also, note that just because commenting a particular line
seems to fix the problem does not necessarilly mean that the problem is
caused by that line. By the same token, your inline version could have
the same bug, but for whatever reason, it is not manifesting itself.

That being said, I did see one thing that looks a little suspiscious.
When name parsing fails, it looks like everything gets cleaned up, but
then the function continues on to password parsing. If both name
parsing and password parsing fail, then everything gets cleaned up
twice.

If this is indeed the problem, then one solution is to return before
the name parsing if-block closes. You could add the following line at
the end of the name parsing if-block:

return INT2FIX(ret);

snacktime

9/18/2006 5:15:00 PM

0

On 9/18/06, Squeamizh <squeamz@hotmail.com> wrote:
> snacktime wrote:
> > I forgot to mention. The c extension only fails when I pass bad
> > credentials and the call to krb5_get_init_creds_password fails. Also,
> > the extension code is the same as the C code generated by RubyInline
> > except for the Init_ definition.
>
> Unfortunately, it is difficult to say without knowing mroe about krb5's
> interface. Also, note that just because commenting a particular line
> seems to fix the problem does not necessarilly mean that the problem is
> caused by that line. By the same token, your inline version could have
> the same bug, but for whatever reason, it is not manifesting itself.

That's actually what was happening. The code should have done
something bad because I was calling krb5_free_cred_contents when no
credentials existed. Now why it didn't segfault with RubyInline I
have no idea.