diff options
Diffstat (limited to 'trunk/ext/openssl/ossl_config.c')
-rw-r--r-- | trunk/ext/openssl/ossl_config.c | 464 |
1 files changed, 464 insertions, 0 deletions
diff --git a/trunk/ext/openssl/ossl_config.c b/trunk/ext/openssl/ossl_config.c new file mode 100644 index 0000000000..baa573d4bb --- /dev/null +++ b/trunk/ext/openssl/ossl_config.c @@ -0,0 +1,464 @@ +/* + * $Id$ + * 'OpenSSL for Ruby' project + * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> + * All rights reserved. + */ +/* + * This program is licenced under the same licence as Ruby. + * (See the file 'LICENCE'.) + */ +#include "ossl.h" + +#define WrapConfig(klass, obj, conf) do { \ + if (!conf) { \ + ossl_raise(rb_eRuntimeError, "Config wasn't intitialized!"); \ + } \ + obj = Data_Wrap_Struct(klass, 0, NCONF_free, conf); \ +} while (0) +#define GetConfig(obj, conf) do { \ + Data_Get_Struct(obj, CONF, conf); \ + if (!conf) { \ + ossl_raise(rb_eRuntimeError, "Config wasn't intitialized!"); \ + } \ +} while (0) +#define SafeGetConfig(obj, conf) do { \ + OSSL_Check_Kind(obj, cConfig); \ + GetConfig(obj, conf); \ +} while(0); + +/* + * Classes + */ +VALUE cConfig; +VALUE eConfigError; + +/* + * Public + */ + +static CONF *parse_config(VALUE, CONF*); + +CONF * +GetConfigPtr(VALUE obj) +{ + CONF *conf; + + SafeGetConfig(obj, conf); + + return conf; +} + +CONF * +DupConfigPtr(VALUE obj) +{ + VALUE str; + + OSSL_Check_Kind(obj, cConfig); + str = rb_funcall(obj, rb_intern("to_s"), 0); + + return parse_config(str, NULL); +} + +/* + * Private + */ +static CONF * +parse_config(VALUE str, CONF *dst) +{ + CONF *conf; + BIO *bio; + long eline = -1; + + bio = ossl_obj2bio(str); + conf = dst ? dst : NCONF_new(NULL); + if(!conf){ + BIO_free(bio); + ossl_raise(eConfigError, NULL); + } + if(!NCONF_load_bio(conf, bio, &eline)){ + BIO_free(bio); + if(!dst) NCONF_free(conf); + if (eline <= 0) ossl_raise(eConfigError, "wrong config format"); + else ossl_raise(eConfigError, "error in line %d", eline); + ossl_raise(eConfigError, NULL); + } + BIO_free(bio); + + return conf; +} + +static VALUE +ossl_config_s_parse(VALUE klass, VALUE str) +{ + CONF *conf; + VALUE obj; + + conf = parse_config(str, NULL); + WrapConfig(klass, obj, conf); + + return obj; +} + +static VALUE +ossl_config_s_alloc(VALUE klass) +{ + CONF *conf; + VALUE obj; + + if(!(conf = NCONF_new(NULL))) + ossl_raise(eConfigError, NULL); + WrapConfig(klass, obj, conf); + + return obj; +} + +static VALUE +ossl_config_copy(VALUE self, VALUE other) +{ + VALUE str; + CONF *conf; + + str = rb_funcall(self, rb_intern("to_s"), 0); + GetConfig(other, conf); + parse_config(str, conf); + + return self; +} + +static VALUE +ossl_config_initialize(int argc, VALUE *argv, VALUE self) +{ + CONF *conf; + long eline = -1; + char *filename; + VALUE path; + + rb_scan_args(argc, argv, "01", &path); + if(!NIL_P(path)){ + SafeStringValue(path); + filename = StringValuePtr(path); + GetConfig(self, conf); + if (!NCONF_load(conf, filename, &eline)){ + if (eline <= 0) + ossl_raise(eConfigError, "wrong config file %s", filename); + else + ossl_raise(eConfigError, "error in %s:%d", filename, eline); + } + } +#ifdef OSSL_NO_CONF_API + else rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)"); +#else + else { + GetConfig(self, conf); + _CONF_new_data(conf); + } +#endif + + return self; +} + +static VALUE +ossl_config_add_value(VALUE self, VALUE section, VALUE name, VALUE value) +{ +#ifdef OSSL_NO_CONF_API + rb_notimplement(); +#else + CONF *conf; + CONF_VALUE *sv, *cv; + + StringValue(section); + StringValue(name); + StringValue(value); + GetConfig(self, conf); + if(!(sv = _CONF_get_section(conf, RSTRING_PTR(section)))){ + if(!(sv = _CONF_new_section(conf, RSTRING_PTR(section)))){ + ossl_raise(eConfigError, NULL); + } + } + if(!(cv = OPENSSL_malloc(sizeof(CONF_VALUE)))){ + ossl_raise(eConfigError, NULL); + } + cv->name = BUF_strdup(RSTRING_PTR(name)); + cv->value = BUF_strdup(RSTRING_PTR(value)); + if(!cv->name || !cv->value || !_CONF_add_string(conf, sv, cv)){ + OPENSSL_free(cv->name); + OPENSSL_free(cv->value); + OPENSSL_free(cv); + ossl_raise(eConfigError, "_CONF_add_string failure"); + } + + return value; +#endif +} + +static VALUE +ossl_config_get_value(VALUE self, VALUE section, VALUE name) +{ + CONF *conf; + char *str; + + StringValue(section); + StringValue(name); + GetConfig(self, conf); + str = NCONF_get_string(conf, RSTRING_PTR(section), RSTRING_PTR(name)); + if(!str){ + ERR_clear_error(); + return Qnil; + } + + return rb_str_new2(str); +} + +static VALUE +ossl_config_get_value_old(int argc, VALUE *argv, VALUE self) +{ + VALUE section, name; + + rb_scan_args(argc, argv, "11", §ion, &name); + + /* support conf.value(nil, "HOME") -> conf.get_value("", "HOME") */ + if (NIL_P(section)) section = rb_str_new2(""); + /* support conf.value("HOME") -> conf.get_value("", "HOME") */ + if (NIL_P(name)) { + name = section; + section = rb_str_new2(""); + } + /* NOTE: Don't care about conf.get_value(nil, nil) */ + rb_warn("Config#value is deprecated; use Config#get_value"); + return ossl_config_get_value(self, section, name); +} + +static VALUE +set_conf_section_i(VALUE i, VALUE *arg) +{ + VALUE name, value; + + Check_Type(i, T_ARRAY); + name = rb_ary_entry(i, 0); + value = rb_ary_entry(i, 1); + ossl_config_add_value(arg[0], arg[1], name, value); + + return Qnil; +} + +static VALUE +ossl_config_set_section(VALUE self, VALUE section, VALUE hash) +{ + VALUE arg[2]; + + arg[0] = self; + arg[1] = section; + rb_block_call(hash, rb_intern("each"), 0, 0, set_conf_section_i, (VALUE)arg); + return hash; +} + +/* + * Get all numbers as strings - use str.to_i to convert + * long number = CONF_get_number(confp->config, sect, StringValuePtr(item)); + */ +static VALUE +ossl_config_get_section(VALUE self, VALUE section) +{ + CONF *conf; + STACK_OF(CONF_VALUE) *sk; + CONF_VALUE *entry; + int i, entries; + VALUE hash; + + hash = rb_hash_new(); + StringValue(section); + GetConfig(self, conf); + if (!(sk = NCONF_get_section(conf, StringValuePtr(section)))) { + ERR_clear_error(); + return hash; + } + if ((entries = sk_CONF_VALUE_num(sk)) < 0) { + OSSL_Debug("# of items in section is < 0?!?"); + return hash; + } + for (i=0; i<entries; i++) { + entry = sk_CONF_VALUE_value(sk, i); + rb_hash_aset(hash, rb_str_new2(entry->name), rb_str_new2(entry->value)); + } + + return hash; +} + +static VALUE +ossl_config_get_section_old(VALUE self, VALUE section) +{ + rb_warn("Config#section is deprecated; use Config#[]"); + return ossl_config_get_section(self, section); +} + +#ifdef IMPLEMENT_LHASH_DOALL_ARG_FN +static void +get_conf_section(CONF_VALUE *cv, VALUE ary) +{ + if(cv->name) return; + rb_ary_push(ary, rb_str_new2(cv->section)); +} + +static IMPLEMENT_LHASH_DOALL_ARG_FN(get_conf_section, CONF_VALUE*, VALUE); + +static VALUE +ossl_config_get_sections(VALUE self) +{ + CONF *conf; + VALUE ary; + + GetConfig(self, conf); + ary = rb_ary_new(); + lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(get_conf_section), (void*)ary); + + return ary; +} + +static void +dump_conf_value(CONF_VALUE *cv, VALUE str) +{ + STACK_OF(CONF_VALUE) *sk; + CONF_VALUE *v; + int i, num; + + if (cv->name) return; + sk = (STACK_OF(CONF_VALUE)*)cv->value; + num = sk_CONF_VALUE_num(sk); + rb_str_cat2(str, "[ "); + rb_str_cat2(str, cv->section); + rb_str_cat2(str, " ]\n"); + for(i = 0; i < num; i++){ + v = sk_CONF_VALUE_value(sk, i); + rb_str_cat2(str, v->name ? v->name : "None"); + rb_str_cat2(str, "="); + rb_str_cat2(str, v->value ? v->value : "None"); + rb_str_cat2(str, "\n"); + } + rb_str_cat2(str, "\n"); +} + +static IMPLEMENT_LHASH_DOALL_ARG_FN(dump_conf_value, CONF_VALUE*, VALUE); + +static VALUE +dump_conf(CONF *conf) +{ + VALUE str; + + str = rb_str_new(0, 0); + lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(dump_conf_value), (void*)str); + + return str; +} + +static VALUE +ossl_config_to_s(VALUE self) +{ + CONF *conf; + + GetConfig(self, conf); + + return dump_conf(conf); +} + +static void +each_conf_value(CONF_VALUE *cv, void* dummy) +{ + STACK_OF(CONF_VALUE) *sk; + CONF_VALUE *v; + VALUE section, name, value, args; + int i, num; + + if (cv->name) return; + sk = (STACK_OF(CONF_VALUE)*)cv->value; + num = sk_CONF_VALUE_num(sk); + section = rb_str_new2(cv->section); + for(i = 0; i < num; i++){ + v = sk_CONF_VALUE_value(sk, i); + name = v->name ? rb_str_new2(v->name) : Qnil; + value = v->value ? rb_str_new2(v->value) : Qnil; + args = rb_ary_new3(3, section, name, value); + rb_yield(args); + } +} + +static IMPLEMENT_LHASH_DOALL_ARG_FN(each_conf_value, CONF_VALUE*, void*); + +static VALUE +ossl_config_each(VALUE self) +{ + CONF *conf; + + RETURN_ENUMERATOR(self, 0, 0); + + GetConfig(self, conf); + lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(each_conf_value), (void*)NULL); + + return self; +} +#else +static VALUE +ossl_config_get_sections(VALUE self) +{ + rb_warn("#sections don't work with %s", OPENSSL_VERSION_TEXT); + return rb_ary_new(); +} + +static VALUE +ossl_config_to_s(VALUE self) +{ + rb_warn("#to_s don't work with %s", OPENSSL_VERSION_TEXT); + return rb_str_new(0, 0); +} + +static VALUE +ossl_config_each(VALUE self) +{ + rb_warn("#each don't work with %s", OPENSSL_VERSION_TEXT); + return self; +} +#endif + +static VALUE +ossl_config_inspect(VALUE self) +{ + VALUE str, ary = ossl_config_get_sections(self); + const char *cname = rb_class2name(rb_obj_class(self)); + + str = rb_str_new2("#<"); + rb_str_cat2(str, cname); + rb_str_cat2(str, " sections="); + rb_str_append(str, rb_inspect(ary)); + rb_str_cat2(str, ">"); + + return str; +} + +/* + * INIT + */ +void +Init_ossl_config() +{ + eConfigError = rb_define_class_under(mOSSL, "ConfigError", eOSSLError); + cConfig = rb_define_class_under(mOSSL, "Config", rb_cObject); + + rb_define_const(cConfig, "DEFAULT_CONFIG_FILE", + rb_str_new2(CONF_get1_default_config_file())); + rb_include_module(cConfig, rb_mEnumerable); + rb_define_singleton_method(cConfig, "parse", ossl_config_s_parse, 1); + rb_define_alias(CLASS_OF(cConfig), "load", "new"); + rb_define_alloc_func(cConfig, ossl_config_s_alloc); + rb_define_copy_func(cConfig, ossl_config_copy); + rb_define_method(cConfig, "initialize", ossl_config_initialize, -1); + rb_define_method(cConfig, "get_value", ossl_config_get_value, 2); + rb_define_method(cConfig, "value", ossl_config_get_value_old, -1); + rb_define_method(cConfig, "add_value", ossl_config_add_value, 3); + rb_define_method(cConfig, "[]", ossl_config_get_section, 1); + rb_define_method(cConfig, "section", ossl_config_get_section_old, 1); + rb_define_method(cConfig, "[]=", ossl_config_set_section, 2); + rb_define_method(cConfig, "sections", ossl_config_get_sections, 0); + rb_define_method(cConfig, "to_s", ossl_config_to_s, 0); + rb_define_method(cConfig, "each", ossl_config_each, 0); + rb_define_method(cConfig, "inspect", ossl_config_inspect, 0); +} |