summaryrefslogtreecommitdiffstats
path: root/libssh/keys.c
Commit message (Expand)AuthorAgeFilesLines
* Sanitize libssh namespace + legacy wrappersAris Adamantiadis2010-05-141-224/+224
* Fixed building libssh with DEBUG_CRYPTO.Andreas Schneider2010-05-121-0/+1
* Fix uninitialized variable usedAris Adamantiadis2010-04-281-0/+4
* Renamed private type TYPE_RSA to SSH_KEYTYPE_*Aris Adamantiadis2010-04-281-36/+36
* Fix missing string_data() in crypto debug codeAris Adamantiadis2010-04-141-8/+8
* Fixed the documentation of key functions.Andreas Schneider2010-04-041-12/+24
* more priv.h splittingAris Adamantiadis2009-09-261-0/+1
* More include file splittingAris Adamantiadis2009-09-261-0/+2
* Fixed building with Gcrypt and arith with void*Aris Adamantiadis2009-09-251-15/+15
* Get rid of CRYPTOAris Adamantiadis2009-09-231-3/+3
* Moved lots of declaration out of priv.hAris Adamantiadis2009-09-231-7/+10
* get rid of SSH_SESSIONAris Adamantiadis2009-09-231-8/+8
* Merge branch 'master' of git://git.libssh.org/projects/libssh/libsshAris Adamantiadis2009-08-231-1/+0
|\
| * Fix double free pointer crash in dsa_public_to_stringVic Lee2009-08-161-1/+0
* | experimental callback systemAris Adamantiadis2009-08-231-1/+1
|/
* Public key authentication server sidemilo2009-07-271-0/+66
* Fix conflicting declarations of ssh_session and ssh_kbdint.Andreas Schneider2009-07-251-1/+1
* Change PRIVATE_KEY * to ssh_private_keyAris Adamantiadis2009-07-241-3/+3
* Changed all PUBLIC_KEY * to ssh_public_keyAris Adamantiadis2009-07-241-14/+14
* Changed all occurences of BUFFER * to ssh_bufferAris Adamantiadis2009-07-241-11/+11
* Change all occurences of STRING * to ssh_stringAris Adamantiadis2009-07-241-45/+45
* Fixed namespace problem in public structuresAris Adamantiadis2009-07-241-4/+4
* Fix the vim modeline and place it at the end of the file.Andreas Schneider2009-05-121-2/+1
* Simplify signature_from_string() a bit.Andreas Schneider2009-04-181-30/+13
* Add error checks to ssh_do_sign_with_agent() and fix a memleak.Andreas Schneider2009-04-181-2/+17
* Replace some strcmp with switch to make it a bit faster.Andreas Schneider2009-04-181-34/+30
* Make use of ssh_type_from_name().Andreas Schneider2009-04-181-3/+3
* Some cleanup for publickey_to_string().Andreas Schneider2009-04-181-2/+2
* Fix segfault with gcrypt.Andreas Schneider2009-04-181-5/+8
* Add more error checks to ssh_sign_session_id().Andreas Schneider2009-04-181-50/+75
* Fix a segfault if we try to a signature.Andreas Schneider2009-04-181-1/+4
* Add more error checks to RSA_do_sign().Andreas Schneider2009-04-181-21/+30
* Add more error checks to signature_from_string().Andreas Schneider2009-04-181-110/+176
* Add error checks to signature_to_string().Andreas Schneider2009-04-181-69/+133
* Add check for the return value of gcry_sexp_find_token().Andreas Schneider2009-04-181-2/+47
* Add more error checks to ssh_encrypt_rsa1().Andreas Schneider2009-04-181-26/+56
* Add more error checks to ssh_do_sign().Andreas Schneider2009-04-181-60/+83
* Don't leak memory in publickey_make_* functions.Andreas Schneider2009-04-171-1/+4
* Revert commit 530.Andreas Schneider2009-04-171-4/+1
* Don't leak memory in error path.Andreas Schneider2009-04-171-1/+4
* Revert commit 527.Andreas Schneider2009-04-171-10/+3
* Don't leak memory.Andreas Schneider2009-04-171-3/+10
* Add error checking to publickey to string functions.Andreas Schneider2009-04-081-82/+173
* Add error checking to publickey_from_privatekey().Andreas Schneider2009-04-081-67/+152
* Add error checking to publickey_from_string().Andreas Schneider2009-04-081-28/+43
* Add error checking to publickey_make_rsa().Andreas Schneider2009-04-081-32/+65
* Add error checking to publickey_make_dss().Andreas Schneider2009-04-081-39/+73
* Use const where it should be used.Andreas Schneider2009-04-051-1/+1
* Fix build warnings.Andreas Schneider2009-04-051-2/+3
* Improve key free functions.Andreas Schneider2009-04-041-33/+37
a> 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
/**********************************************************************

  range.c -

  $Author$
  $Date$
  created at: Thu Aug 19 17:46:47 JST 1993

  Copyright (C) 1993-2003 Yukihiro Matsumoto

**********************************************************************/

#include "ruby.h"

VALUE rb_cRange;
static ID id_cmp, id_succ, id_beg, id_end, id_excl;

#define EXCL(r) RTEST(rb_ivar_get((r), id_excl))
#define SET_EXCL(r,v) rb_ivar_set((r), id_excl, (v) ? Qtrue : Qfalse)

static VALUE
range_failed()
{
    rb_raise(rb_eArgError, "bad value for range");
    return Qnil;		/* dummy */
}

static VALUE
range_check(args)
    VALUE *args;
{
    VALUE v;

    v = rb_funcall(args[0], id_cmp, 1, args[1]);
    if (NIL_P(v)) range_failed();
    return Qnil;
}

static void
range_init(range, beg, end, exclude_end)
    VALUE range, beg, end;
    int exclude_end;
{
    VALUE args[2];

    args[0] = beg;
    args[1] = end;
    
    if (!FIXNUM_P(beg) || !FIXNUM_P(end)) {
	rb_rescue(range_check, (VALUE)args, range_failed, 0);
    }

    SET_EXCL(range, exclude_end);
    rb_ivar_set(range, id_beg, beg);
    rb_ivar_set(range, id_end, end);
}

VALUE
rb_range_new(beg, end, exclude_end)
    VALUE beg, end;
    int exclude_end;
{
    VALUE range = rb_obj_alloc(rb_cRange);

    range_init(range, beg, end, exclude_end);
    return range;
}

/*
 *  call-seq:
 *     Range.new(start, end, exclusive=false)    => range
 *  
 *  Constructs a range using the given <i>start</i> and <i>end</i>. If the third
 *  parameter is omitted or is <code>false</code>, the <i>range</i> will include
 *  the end object; otherwise, it will be excluded.
 */

static VALUE
range_initialize(argc, argv, range)
    int argc;
    VALUE *argv;
    VALUE range;
{
    VALUE beg, end, flags;
    
    rb_scan_args(argc, argv, "21", &beg, &end, &flags);
    /* Ranges are immutable, so that they should be initialized only once. */
    if (rb_ivar_defined(range, id_beg)) {
	rb_name_error(rb_intern("initialize"), "`initialize' called twice");
    }
    range_init(range, beg, end, RTEST(flags));
    return Qnil;
}


/*
 *  call-seq:
 *     rng.exclude_end?    => true or false
 *  
 *  Returns <code>true</code> if <i>rng</i> excludes its end value.
 */

static VALUE
range_exclude_end_p(range)
    VALUE range;
{
    return EXCL(range) ? Qtrue : Qfalse;
}


/*
 *  call-seq:
 *     rng == obj    => true or false
 *  
 *  Returns <code>true</code> only if <i>obj</i> is a Range, has equivalent
 *  beginning and end items (by comparing them with <code>==</code>), and has
 *  the same #exclude_end? setting as <i>rng</t>.
 *     
 *    (0..2) == (0..2)            #=> true
 *    (0..2) == Range.new(0,2)    #=> true
 *    (0..2) == (0...2)           #=> false
 *     
 */

static VALUE
range_eq(range, obj)
    VALUE range, obj;
{
    if (range == obj) return Qtrue;
    if (!rb_obj_is_instance_of(obj, rb_obj_class(range)))
	return Qfalse;

    if (!rb_equal(rb_ivar_get(range, id_beg), rb_ivar_get(obj, id_beg)))
	return Qfalse;
    if (!rb_equal(rb_ivar_get(range, id_end), rb_ivar_get(obj, id_end)))
	return Qfalse;

    if (EXCL(range) != EXCL(obj)) return Qfalse;

    return Qtrue;
}

static int
r_lt(a, b)
    VALUE a, b;
{
    VALUE r = rb_funcall(a, id_cmp, 1, b);

    if (NIL_P(r)) return Qfalse;
    if (rb_cmpint(r, a, b) < 0) return Qtrue;
    return Qfalse;
}

static int
r_le(a, b)
    VALUE a, b;
{
    int c;
    VALUE r = rb_funcall(a, id_cmp, 1, b);

    if (NIL_P(r)) return Qfalse;
    c = rb_cmpint(r, a, b);
    if (c == 0) return INT2FIX(0);
    if (c < 0) return Qtrue;
    return Qfalse;
}


/*
 *  call-seq:
 *     rng.eql?(obj)    => true or false
 *  
 *  Returns <code>true</code> only if <i>obj</i> is a Range, has equivalent
 *  beginning and end items (by comparing them with #eql?), and has the same
 *  #exclude_end? setting as <i>rng</i>.
 *     
 *    (0..2) == (0..2)            #=> true
 *    (0..2) == Range.new(0,2)    #=> true
 *    (0..2) == (0...2)           #=> false
 *     
 */

static VALUE
range_eql(range, obj)
    VALUE range, obj;
{
    if (range == obj) return Qtrue;
    if (!rb_obj_is_instance_of(obj, rb_obj_class(range)))
	return Qfalse;

    if (!rb_eql(rb_ivar_get(range, id_beg), rb_ivar_get(obj, id_beg)))
	return Qfalse;
    if (!rb_eql(rb_ivar_get(range, id_end), rb_ivar_get(obj, id_end)))
	return Qfalse;

    if (EXCL(range) != EXCL(obj)) return Qfalse;

    return Qtrue;
}

/*
 * call-seq:
 *   rng.hash    => fixnum
 *
 * Generate a hash value such that two ranges with the same start and
 * end points, and the same value for the "exclude end" flag, generate
 * the same hash value.
 */

static VALUE
range_hash(range)
    VALUE range;
{
    long hash = EXCL(range);
    VALUE v;

    v = rb_hash(rb_ivar_get(range, id_beg));
    hash ^= v << 1;
    v = rb_hash(rb_ivar_get(range, id_end));
    hash ^= v << 9;
    hash ^= EXCL(range) << 24;

    return LONG2FIX(hash);
}

static VALUE
str_step(args)
    VALUE *args;
{
    return rb_str_upto(args[0], args[1], EXCL(args[2]));
}

static VALUE
step_i(i, iter)
    VALUE i;
    long *iter;
{
    iter[0]--;
    if (iter[0] == 0) {
	rb_yield(i);
	iter[0] = iter[1];
    }
    return Qnil;
}

static void
range_each_func(range, func, v, e, arg)
    VALUE range;
    VALUE (*func) _((VALUE, void*));
    VALUE v, e;
    void *arg;
{
    int c;

    if (EXCL(range)) {
	while (r_lt(v, e)) {
	    (*func)(v, arg);
	    v = rb_funcall(v, id_succ, 0, 0);
	}
    }
    else {
	while (RTEST(c = r_le(v, e))) {
	    (*func)(v, arg);
	    if (c == INT2FIX(0)) break;
	    v = rb_funcall(v, id_succ, 0, 0);
	}
    }
}

/*
 *  call-seq:
 *     rng.step(n=1) {| obj | block }    => rng
 *  
 *  Iterates over <i>rng</i>, passing each <i>n</i>th element to the block. If
 *  the range contains numbers or strings, natural ordering is used.  Otherwise
 *  <code>step</code> invokes <code>succ</code> to iterate through range
 *  elements. The following code uses class <code>Xs</code>, which is defined
 *  in the class-level documentation.
 *     
 *     range = Xs.new(1)..Xs.new(10)
 *     range.step(2) {|x| puts x}
 *     range.step(3) {|x| puts x}
 *     
 *  <em>produces:</em>
 *     
 *      1 x
 *      3 xxx
 *      5 xxxxx
 *      7 xxxxxxx
 *      9 xxxxxxxxx
 *      1 x
 *      4 xxxx
 *      7 xxxxxxx
 *     10 xxxxxxxxxx
 */


static VALUE
range_step(argc, argv, range)
    int argc;
    VALUE *argv;
    VALUE range;
{
    VALUE b, e, step;
    long unit;

    b = rb_ivar_get(range, id_beg);
    e = rb_ivar_get(range, id_end);
    if (rb_scan_args(argc, argv, "01", &step) == 0) {
	step = INT2FIX(1);
    }

    unit = NUM2LONG(step);
    if (unit < 0) {
	rb_raise(rb_eArgError, "step can't be negative");
    } 
    if (FIXNUM_P(b) && FIXNUM_P(e)) { /* fixnums are special */
	long end = FIX2LONG(e);
	long i;

	if (unit == 0) rb_raise(rb_eArgError, "step can't be 0");
	if (!EXCL(range)) end += 1;
	for (i=FIX2LONG(b); i<end; i+=unit) {
	    rb_yield(LONG2NUM(i));
	}
    }
    else {
	VALUE tmp = rb_check_string_type(b);

	if (!NIL_P(tmp)) {
	    VALUE args[5];
	    long iter[2];

	    b = tmp;
	    if (unit == 0) rb_raise(rb_eArgError, "step can't be 0");
	    args[0] = b; args[1] = e; args[2] = range;
	    iter[0] = 1; iter[1] = unit;
	    rb_iterate((VALUE(*)_((VALUE)))str_step, (VALUE)args, step_i, (VALUE)iter);
	}
	else if (rb_obj_is_kind_of(b, rb_cNumeric)) {
	    ID c = rb_intern(EXCL(range) ? "<" : "<=");

	    if (rb_equal(step, INT2FIX(0))) rb_raise(rb_eArgError, "step can't be 0");
	    while (RTEST(rb_funcall(b, c, 1, e))) {
		rb_yield(b);
		b = rb_funcall(b, '+', 1, step);
	    }
	}
	else {
	    long args[2];

	    if (unit == 0) rb_raise(rb_eArgError, "step can't be 0");
	    if (!rb_respond_to(b, id_succ)) {
		rb_raise(rb_eTypeError, "cannot iterate from %s",
			 rb_obj_classname(b));
	    }
	
	    args[0] = 1;
	    args[1] = unit;
	    range_each_func(range, step_i, b, e, args);
	}
    }
    return range;
}

static VALUE
each_i(v, arg)
    VALUE v;
    void *arg;
{
    return rb_yield(v);
}

/*
 *  call-seq:
 *     rng.each {| i | block } => rng
 *  
 *  Iterates over the elements <i>rng</i>, passing each in turn to the
 *  block. You can only iterate if the start object of the range
 *  supports the +succ+ method (which means that you can't iterate over
 *  ranges of +Float+ objects).
 *     
 *     (10..15).each do |n|
 *        print n, ' '
 *     end
 *     
 *  <em>produces:</em>
 *     
 *     10 11 12 13 14 15
 */

static VALUE
range_each(range)
    VALUE range;
{
    VALUE beg, end;

    beg = rb_ivar_get(range, id_beg);
    end = rb_ivar_get(range, id_end);

    if (!rb_respond_to(beg, id_succ)) {
	rb_raise(rb_eTypeError, "cannot iterate from %s",
		 rb_obj_classname(beg));
    }
    if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */
	long lim = FIX2LONG(end);
	long i;

	if (!EXCL(range)) lim += 1;
	for (i=FIX2LONG(beg); i<lim; i++) {
	    rb_yield(LONG2NUM(i));
	}
    }
    else if (TYPE(beg) == T_STRING) {
	VALUE args[5];
	long iter[2];

	args[0] = beg; args[1] = end; args[2] = range;
	iter[0] = 1; iter[1] = 1;
	rb_iterate((VALUE(*)_((VALUE)))str_step, (VALUE)args, step_i, (VALUE)iter);
    }
    else {
	range_each_func(range, each_i, beg, end, NULL);
    }
    return range;
}

/*
 *  call-seq:
 *     rng.first    => obj
 *     rng.begin    => obj
 *  
 *  Returns the first object in <i>rng</i>.
 */

static VALUE
range_first(range)
    VALUE range;
{
    return rb_ivar_get(range, id_beg);
}


/*
 *  call-seq:
 *     rng.end    => obj
 *     rng.last   => obj
 *  
 *  Returns the object that defines the end of <i>rng</i>.
 *     
 *     (1..10).end    #=> 10
 *     (1...10).end   #=> 10
 */


static VALUE
range_last(range)
    VALUE range;
{
    return rb_ivar_get(range, id_end);
}

VALUE
rb_range_beg_len(range, begp, lenp, len, err)
    VALUE range;
    long *begp, *lenp;
    long len;
    int err;
{
    long beg, end, b, e;

    if (!rb_obj_is_kind_of(range, rb_cRange)) return Qfalse;

    beg = b = NUM2LONG(rb_ivar_get(range, id_beg));
    end = e = NUM2LONG(rb_ivar_get(range, id_end));

    if (beg < 0) {
	beg += len;
	if (beg < 0) goto out_of_range;
    }
    if (err == 0 || err == 2) {
	if (beg > len) goto out_of_range;
	if (end > len)
	    end = len;
    }
    if (end < 0) end += len;
    if (!EXCL(range)) end++;	/* include end point */
    if (end < 0) goto out_of_range;
    len = end - beg;
    if (len < 0) goto out_of_range;

    *begp = beg;
    *lenp = len;
    return Qtrue;

  out_of_range:
    if (err) {
	rb_raise(rb_eRangeError, "%ld..%s%ld out of range",
		 b, EXCL(range)? "." : "", e);
    }
    return Qnil;
}

/*
 * call-seq:
 *   rng.to_s   => string
 *
 * Convert this range object to a printable form.
 */

static VALUE
range_to_s(range)
    VALUE range;
{
    VALUE str, str2;

    str = rb_obj_as_string(rb_ivar_get(range, id_beg));
    str2 = rb_obj_as_string(rb_ivar_get(range, id_end));
    str = rb_str_dup(str);
    rb_str_cat(str, "...", EXCL(range)?3:2);
    rb_str_append(str, str2);
    OBJ_INFECT(str, str2);

    return str;
}

/*
 * call-seq:
 *   rng.inspect  => string
 *
 * Convert this range object to a printable form (using 
 * <code>inspect</code> to convert the start and end
 * objects).
 */


static VALUE
range_inspect(range)
    VALUE range;
{
    VALUE str, str2;

    str = rb_inspect(rb_ivar_get(range, id_beg));
    str2 = rb_inspect(rb_ivar_get(range, id_end));
    str = rb_str_dup(str);
    rb_str_cat(str, "...", EXCL(range)?3:2);
    rb_str_append(str, str2);
    OBJ_INFECT(str, str2);

    return str;
}

static void
member_i(v, args)
    VALUE v;
    VALUE *args;
{
    if (rb_equal(v, args[0])) {
	args[1] = Qtrue;
    }
}

/*
 * call-seq:
 *   rng.member?(val)   =>  true or false
 *
 * Return +true+ if _val_ is one of the values in _rng_ (that is if
 * <code>Range#each</code> would return _val_ at some point).
 */

static VALUE
range_member(range, val)
    VALUE range, val;
{
    VALUE beg, end;
    VALUE args[2];

    beg = rb_ivar_get(range, id_beg);
    end = rb_ivar_get(range, id_end);

    if (!rb_respond_to(beg, id_succ)) {
	rb_raise(rb_eTypeError, "cannot iterate from %s",
		 rb_obj_classname(beg));
    }
    args[0] = val;
    args[1] = Qfalse;
    range_each_func(range, member_i, beg, end, args);
    return args[1];
}

/*
 *  call-seq:
 *     rng === obj    => true or false
 *  
 *  Returns <code>true</code> if <i>obj</i> is an element of
 *  <i>rng</i>, <code>false</code> otherwise. Conveniently,
 *  <code>===</code> is the comparison operator used by
 *  <code>case</code> statements.
 *     
 *     case 79
 *     when 1..50   then   print "low\n"
 *     when 51..75  then   print "medium\n"
 *     when 76..100 then   print "high\n"
 *     end
 *     
 *  <em>produces:</em>
 *     
 *     high
 */

static VALUE
range_include(range, val)
    VALUE range, val;
{
    VALUE beg, end;

    beg = rb_ivar_get(range, id_beg);
    end = rb_ivar_get(range, id_end);
    if (r_le(beg, val)) {
	if (EXCL(range)) {
	    if (r_lt(val, end)) return Qtrue;
	}
	else {
	    if (r_le(val, end)) return Qtrue;
	}
    }
    return Qfalse;
}


/*  A <code>Range</code> represents an interval---a set of values with a
 *  start and an end. Ranges may be constructed using the
 *  <em>s</em><code>..</code><em>e</em> and
 *  <em>s</em><code>...</code><em>e</em> literals, or with
 *  <code>Range::new</code>. Ranges constructed using <code>..</code>
 *  run from the start to the end inclusively. Those created using
 *  <code>...</code> exclude the end value. When used as an iterator,
 *  ranges return each value in the sequence.
 *     
 *     (-1..-5).to_a      #=> []
 *     (-5..-1).to_a      #=> [-5, -4, -3, -2, -1]
 *     ('a'..'e').to_a    #=> ["a", "b", "c", "d", "e"]
 *     ('a'...'e').to_a   #=> ["a", "b", "c", "d"]
 *     
 *  Ranges can be constructed using objects of any type, as long as the
 *  objects can be compared using their <code><=></code> operator and
 *  they support the <code>succ</code> method to return the next object
 *  in sequence.
 *     
 *     class Xs                # represent a string of 'x's
 *       include Comparable
 *       attr :length
 *       def initialize(n)
 *         @length = n
 *       end
 *       def succ
 *         Xs.new(@length + 1)
 *       end
 *       def <=>(other)
 *         @length <=> other.length
 *       end
 *       def to_s
 *         sprintf "%2d #{inspect}", @length
 *       end
 *       def inspect
 *         'x' * @length
 *       end
 *     end
 *     
 *     r = Xs.new(3)..Xs.new(6)   #=> xxx..xxxxxx
 *     r.to_a                     #=> [xxx, xxxx, xxxxx, xxxxxx]
 *     r.member?(Xs.new(5))       #=> true
 *     
 *  In the previous code example, class <code>Xs</code> includes the
 *  <code>Comparable</code> module. This is because
 *  <code>Enumerable#member?</code> checks for equality using
 *  <code>==</code>. Including <code>Comparable</code> ensures that the
 *  <code>==</code> method is defined in terms of the <code><=></code>
 *  method implemented in <code>Xs</code>.
 *     
 */

void
Init_Range()
{
    rb_cRange = rb_define_class("Range", rb_cObject);
    rb_include_module(rb_cRange, rb_mEnumerable);
    rb_define_method(rb_cRange, "initialize", range_initialize, -1);
    rb_define_method(rb_cRange, "==", range_eq, 1);
    rb_define_method(rb_cRange, "===", range_include, 1);
    rb_define_method(rb_cRange, "eql?", range_eql, 1);
    rb_define_method(rb_cRange, "hash", range_hash, 0);
    rb_define_method(rb_cRange, "each", range_each, 0);
    rb_define_method(rb_cRange, "step", range_step, -1);
    rb_define_method(rb_cRange, "first", range_first, 0);
    rb_define_method(rb_cRange, "last", range_last, 0);
    rb_define_method(rb_cRange, "begin", range_first, 0);
    rb_define_method(rb_cRange, "end", range_last, 0);
    rb_define_method(rb_cRange, "to_s", range_to_s, 0);
    rb_define_method(rb_cRange, "inspect", range_inspect, 0);

    rb_define_method(rb_cRange, "exclude_end?", range_exclude_end_p, 0);

    rb_define_method(rb_cRange, "member?", range_member, 1);
    rb_define_method(rb_cRange, "include?", range_include, 1);

    id_cmp = rb_intern("<=>");
    id_succ = rb_intern("succ");
    id_beg = rb_intern("begin");
    id_end = rb_intern("end");
    id_excl = rb_intern("excl");
}