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

**URL:** <https://www.ruby-forum.com/t/c-code-works-with-rubyinline-doesnt-with-c-extension/68932>\
**Category:** Ruby\
**Created:** [September 16, 2006, 11:39pm UTC](https://www.ruby-forum.com/t/c-code-works-with-rubyinline-doesnt-with-c-extension/68932 "2006-09-16T23:39:06Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![snacktime](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/7feea3/32.png) [@snacktime](https://www.ruby-forum.com/u/snacktime)\
**Post date:** [September 16, 2006, 11:39pm UTC](https://www.ruby-forum.com/t/c-code-works-with-rubyinline-doesnt-with-c-extension/68932/1 "2006-09-16T23:39:06Z")

</div>

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)

---

<div class="post-metadata">

**Author:** ![snacktime](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/7feea3/32.png) [@snacktime](https://www.ruby-forum.com/u/snacktime)\
**Post date:** [September 16, 2006, 11:59pm UTC](https://www.ruby-forum.com/t/c-code-works-with-rubyinline-doesnt-with-c-extension/68932/2 "2006-09-16T23:59:07Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![snacktime](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/7feea3/32.png) [@snacktime](https://www.ruby-forum.com/u/snacktime)\
**Post date:** [September 18, 2006, 7:14pm UTC](https://www.ruby-forum.com/t/c-code-works-with-rubyinline-doesnt-with-c-extension/68932/3 "2006-09-18T19:14:37Z")

</div>

On 9/18/06, Squeamizh [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> 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.

---

<div class="post-metadata">

**Author:** ![snacktime](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/7feea3/32.png) [@snacktime](https://www.ruby-forum.com/u/snacktime)\
**Post date:** [September 18, 2006, 6:20pm UTC](https://www.ruby-forum.com/t/c-code-works-with-rubyinline-doesnt-with-c-extension/68932/4 "2006-09-18T18:20:30Z")

</div>

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);
