Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/workshop_adaptation_for_conver…
Browse files Browse the repository at this point in the history
…sion' into tohexstring

Conflicts:
	tests/ruby/builtins_test.rb
  • Loading branch information
Ladislav Slezak committed May 7, 2013
2 parents 20ce36c + 3b99b04 commit 573837b
Show file tree
Hide file tree
Showing 11 changed files with 397 additions and 50 deletions.
270 changes: 270 additions & 0 deletions src/binary/Builtin.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#ifndef _OW_SOURCE
#define _OW_SOURCE
#endif

#include <string>
#include <sstream>
#include <iconv.h>
#include <errno.h>
extern "C" {
#include <crypt.h>
}
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#include "ycp/y2log.h"
#include "ycp/ExecutionEnvironment.h"
Expand All @@ -17,6 +34,9 @@
static VALUE rb_mSCR;
static VALUE rb_mWFM;
static VALUE rb_mYCP;
static VALUE rb_mBuiltins;
static VALUE rb_mFloat;


static SCR scr;
static WFM wfm;
Expand Down Expand Up @@ -75,6 +95,248 @@ extern "C" {
return call_builtin(qualified_name,argc,argv);
}

static bool recode(std::wstring &in, std::string &out)
{
iconv_t cd = iconv_open ("UTF-8", "WCHAR_T");

if (cd == (iconv_t)(-1))
{
y2error ("iconv_open: %m");
return false;
}

char* in_ptr = (char*)(in.data ());
size_t in_len = in.length () * sizeof (wchar_t);

const size_t buffer_size = 1024;
char buffer[buffer_size];

out.clear ();

bool errors = false;

while (in_len != (size_t)(0))
{
char *tmp_ptr = buffer;
size_t tmp_size = buffer_size;
size_t r = iconv (cd, &in_ptr, &in_len, &tmp_ptr, &tmp_size);
size_t n = tmp_ptr - buffer;

out.append (buffer, n);

if (r == (size_t)(-1))
{
if (errno == EINVAL || errno == EILSEQ)
{
// more or less harmless
out.append (1, '?');
in_ptr += sizeof (wchar_t);
in_len -= sizeof (wchar_t);
errors = true;
}
else if (errno == E2BIG && n == 0)
{
// fatal: the buffer is too small to hold a
// single multi-byte sequence
iconv_close(cd);
return false;
}
}
}

if (errors)
y2warning("recode errors");

iconv_close(cd);

return true;
}

static VALUE
float_to_lstring(VALUE self, VALUE rfloat, VALUE rprecision)
{
if (NIL_P(rfloat) || NIL_P(rprecision))
return Qnil;

std::wostringstream ss; // bnc#683881#c12: need wide chars
ss.imbue (std::locale (""));
ss.precision (NUM2LONG(rprecision));
ss << fixed<< NUM2DBL(rfloat);
std::wstring res = ss.str();
std::string utf_res;
if (!recode(res,utf_res))
return Qnil;
return rb_str_new2(utf_res.c_str());
}

// crypt part taken from y2crypt from yast core
// TODO refactor to use sharedddd functionality
// TODO move to own module, it is stupid to have it as builtin
enum crypt_ybuiltin_t { CRYPT, MD5, BLOWFISH, SHA256, SHA512 };

static int
read_loop (int fd, char* buffer, int count)
{
int offset, block;

offset = 0;
while (count > 0)
{
block = read (fd, &buffer[offset], count);

if (block < 0)
{
if (errno == EINTR)
continue;
return block;
}

if (!block)
return offset;

offset += block;
count -= block;
}

return offset;
}


static char*
make_crypt_salt (const char* crypt_prefix, int crypt_rounds)
{
#define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1)

#ifndef RANDOM_DEVICE
#define RANDOM_DEVICE "/dev/urandom"
#endif

int fd = open (RANDOM_DEVICE, O_RDONLY);
if (fd < 0)
{
y2error ("Can't open %s for reading: %s\n", RANDOM_DEVICE,
strerror (errno));
return 0;
}

char entropy[16];
if (read_loop (fd, entropy, sizeof(entropy)) != sizeof(entropy))
{
close (fd);
y2error ("Unable to obtain entropy from %s\n", RANDOM_DEVICE);
return 0;
}

close (fd);

char output[CRYPT_GENSALT_OUTPUT_SIZE];
char* retval = crypt_gensalt_rn (crypt_prefix, crypt_rounds, entropy,
sizeof(entropy), output, sizeof(output));

memset (entropy, 0, sizeof (entropy));

if (!retval)
{
y2error ("Unable to generate a salt, check your crypt settings.\n");
return 0;
}

return strdup (retval);
}


char *
crypt_pass (const char* unencrypted, crypt_ybuiltin_t use_crypt)
{
char* salt;

switch (use_crypt)
{
case CRYPT:
salt = make_crypt_salt ("", 0);
break;

case MD5:
salt = make_crypt_salt ("$1$", 0);
break;

case BLOWFISH:
salt = make_crypt_salt ("$2y$", 0);
break;

case SHA256:
salt = make_crypt_salt ("$5$", 0);
break;

case SHA512:
salt = make_crypt_salt ("$6$", 0);
break;

default:
y2error ("Don't know crypt type %d", use_crypt);
return 0;
}
if (!salt)
{
y2error ("Cannot create salt for sha512 crypt");
return 0;
}

struct crypt_data output;
memset (&output, 0, sizeof (output));

char *newencrypted = crypt_r (unencrypted, salt, &output);
free (salt);

if (!newencrypted
/* catch retval magic by ow-crypt/libxcrypt */
|| !strcmp(newencrypted, "*0") || !strcmp(newencrypted, "*1"))
{
y2error ("crypt_r () returns 0 pointer");
return 0;
}
y2milestone ("encrypted %s", newencrypted);

//data lives on stack so dup it
return strdup(newencrypted);
}

VALUE crypt_internal(crypt_ybuiltin_t type, VALUE unencrypted)
{
const char* source = StringValuePtr(unencrypted);
char * res = crypt_pass(source, type);
if (!res)
return Qnil;
VALUE ret = rb_str_new2(res);
delete res;
return ret;
}

VALUE crypt_crypt(VALUE mod, VALUE input)
{
return crypt_internal(CRYPT, input);
}

VALUE crypt_md5(VALUE mod, VALUE input)
{
return crypt_internal(MD5, input);
}

VALUE crypt_blowfish(VALUE mod, VALUE input)
{
return crypt_internal(BLOWFISH, input);
}

VALUE crypt_sha256(VALUE mod, VALUE input)
{
return crypt_internal(SHA256, input);
}

VALUE crypt_sha512(VALUE mod, VALUE input)
{
return crypt_internal(SHA512, input);
}

}

extern "C"
Expand All @@ -96,5 +358,13 @@ extern "C"
rb_define_singleton_method( rb_mSCR, "call_builtin", RUBY_METHOD_FUNC(scr_call_builtin), -1);
rb_mWFM = rb_define_module_under(rb_mYCP, "WFM");
rb_define_singleton_method( rb_mWFM, "call_builtin", RUBY_METHOD_FUNC(wfm_call_builtin), -1);
rb_mBuiltins = rb_define_module_under(rb_mYCP, "Builtins");
rb_mFloat = rb_define_module_under(rb_mBuiltins, "Float");
rb_define_singleton_method( rb_mFloat, "tolstring", RUBY_METHOD_FUNC(float_to_lstring), 2);
rb_define_singleton_method( rb_mBuiltins, "crypt", RUBY_METHOD_FUNC(crypt_crypt), 1);
rb_define_singleton_method( rb_mBuiltins, "cryptmd5", RUBY_METHOD_FUNC(crypt_md5), 1);
rb_define_singleton_method( rb_mBuiltins, "cryptblowfish", RUBY_METHOD_FUNC(crypt_blowfish), 1);
rb_define_singleton_method( rb_mBuiltins, "cryptsha256", RUBY_METHOD_FUNC(crypt_sha256), 1);
rb_define_singleton_method( rb_mBuiltins, "cryptsha512", RUBY_METHOD_FUNC(crypt_sha512), 1);
}
}
1 change: 1 addition & 0 deletions src/binary/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ target_link_libraries( builtinx ${YAST_LIBRARY} )
target_link_libraries( builtinx ${YAST_YCP_LIBRARY} )
target_link_libraries( builtinx ${YAST_PLUGIN_SCR_LIBRARY} )
target_link_libraries( builtinx ${YAST_PLUGIN_WFM_LIBRARY} )
target_link_libraries( builtinx crypt )

install(TARGETS ycpx LIBRARY DESTINATION ${RUBY_VENDORARCH_DIR} )
install(TARGETS builtinx LIBRARY DESTINATION ${RUBY_VENDORARCH_DIR}/ycp )
Expand Down
16 changes: 13 additions & 3 deletions src/binary/Y2CCRubyClient.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,20 @@ Y2Component *Y2CCRubyClient::provideNamespace (const char *name)

Y2Component *Y2CCRubyClient::create ( const char * name) const
{
string client_path = YCPPathSearch::find (YCPPathSearch::Client, string (name) + ".rb");
//client is not in ruby
y2debug("look for client with name %s", name);
string sname(name);
string client_path = YCPPathSearch::find (YCPPathSearch::Client, sname + ".rb");
//client not found in form clients/<name>.rb
if (client_path.empty())
return NULL;
{
// for paths it needs at least one slash BNC#330965#c10
if(!strchr (name, '/'))
return NULL;

client_path = Y2PathSearch::completeFilename (sname);
if (client_path.empty())
return NULL;
}

Y2RubyClientComponent* rc = Y2RubyClientComponent::instance();
rc->setClient(client_path);
Expand Down
15 changes: 14 additions & 1 deletion src/binary/Y2RubyTypeConv.cc
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,15 @@ static YCPValue rbreference_2_ycpreference( VALUE value )
return YCPReference(s_entry);
}

static YCPValue rbargreference_2_ycpreference( VALUE value )
{
VALUE val = rb_funcall(value,rb_intern("value"),0);
YCPValue v = rbvalue_2_ycpvalue(val);
SymbolEntryPtr se = new SymbolEntry(0, 0, "ref", SymbolEntry::c_variable, Type::vt2type(v->valuetype()));
se->setValue(v);
return YCPReference(se);
}

static YCPValue rbyreference_2_ycpreference( VALUE value )
{
SymbolEntry *se;
Expand Down Expand Up @@ -259,7 +268,11 @@ rbvalue_2_ycpvalue( VALUE value )
{
return rbterm_2_ycpterm(value);
}
else if ( !strcmp(class_name, "YCP::Reference"))
else if ( !strcmp(class_name, "YCP::ArgRef"))
{
return rbargreference_2_ycpreference(value);
}
else if ( !strcmp(class_name, "YCP::FunRef"))
{
return rbreference_2_ycpreference(value);
}
Expand Down
25 changes: 14 additions & 11 deletions src/binary/YCP.cc
Original file line number Diff line number Diff line change
Expand Up @@ -306,29 +306,32 @@ ycp_module_call_ycp_function(int argc, VALUE *argv, VALUE self)
}

y2debug("Call %s", function_name);
std::map<int,SymbolEntryPtr> refs;
// add the parameters
for (int i=2; i < argc; i++)
{
YCPValue v = rbvalue_2_ycpvalue(argv[i]);
y2debug("Append parameter %s", v->toString().c_str());
if (call->wantedParameterType()->isReference() && !v->isReference())
{
//FIXME DO not work for integers or booleans e.g.
// FIXME just fake entry to make it at least partially work
y2error("Use ycp reference as parameter for non reference type");
SymbolEntryPtr se = new SymbolEntry(0, 0, "ref", SymbolEntry::c_variable, Type::vt2type(v->valuetype()));
se->setValue(v);
call->appendParameter(YCPReference(se));
}
else

const char *class_name = rb_obj_classname(argv[i]);
//handle args passed by references
if (!strcmp(class_name, "YCP::ArgRef"))
{
call->appendParameter (v);
refs[i] = v->asReference()->entry();
}
call->appendParameter (v);
}
call->finishParameters ();

YCPValue res = call->evaluateCall ();
delete call;
for (std::map<int,SymbolEntryPtr>::iterator i = refs.begin(); i != refs.end(); ++i)
{
//set back reference
rb_funcall(argv[i->first], rb_intern("value="), 1, ycpvalue_2_rbvalue(i->second->value()));
//clean up created symbol entry
delete (SymbolEntry*)&(*(i->second));
}
return ycpvalue_2_rbvalue(res);
}
}
Expand Down

0 comments on commit 573837b

Please sign in to comment.