Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/openssl/ossl_x509store.c

Go to the documentation of this file.

    00001 /*
    00002  * $Id: ossl_x509store.c 27437 2010-04-22 08:04:13Z nobu $
    00003  * 'OpenSSL for Ruby' project
    00004  * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
    00005  * All rights reserved.
    00006  */
    00007 /*
    00008  * This program is licenced under the same licence as Ruby.
    00009  * (See the file 'LICENCE'.)
    00010  */
    00011 #include "ossl.h"
    00012
    00013 #define WrapX509Store(klass, obj, st) do { \
    00014     if (!st) { \
    00015         ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
    00016     } \
    00017     obj = Data_Wrap_Struct(klass, 0, X509_STORE_free, st); \
    00018 } while (0)
    00019 #define GetX509Store(obj, st) do { \
    00020     Data_Get_Struct(obj, X509_STORE, st); \
    00021     if (!st) { \
    00022         ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
    00023     } \
    00024 } while (0)
    00025 #define SafeGetX509Store(obj, st) do { \
    00026     OSSL_Check_Kind(obj, cX509Store); \
    00027     GetX509Store(obj, st); \
    00028 } while (0)
    00029
    00030 #define WrapX509StCtx(klass, obj, ctx) do { \
    00031     if (!ctx) { \
    00032         ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \
    00033     } \
    00034     obj = Data_Wrap_Struct(klass, 0, ossl_x509stctx_free, ctx); \
    00035 } while (0)
    00036 #define GetX509StCtx(obj, ctx) do { \
    00037     Data_Get_Struct(obj, X509_STORE_CTX, ctx); \
    00038     if (!ctx) { \
    00039         ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \
    00040     } \
    00041 } while (0)
    00042 #define SafeGetX509StCtx(obj, storep) do { \
    00043     OSSL_Check_Kind(obj, cX509StoreContext); \
    00044     GetX509Store(obj, ctx); \
    00045 } while (0)
    00046
    00047 /*
    00048  * Classes
    00049  */
    00050 VALUE cX509Store;
    00051 VALUE cX509StoreContext;
    00052 VALUE eX509StoreError;
    00053
    00054 /*
    00055  * Public functions
    00056  */
    00057 VALUE
    00058 ossl_x509store_new(X509_STORE *store)
    00059 {
    00060     VALUE obj;
    00061
    00062     WrapX509Store(cX509Store, obj, store);
    00063
    00064     return obj;
    00065 }
    00066
    00067 X509_STORE *
    00068 GetX509StorePtr(VALUE obj)
    00069 {
    00070     X509_STORE *store;
    00071
    00072     SafeGetX509Store(obj, store);
    00073
    00074     return store;
    00075 }
    00076
    00077 X509_STORE *
    00078 DupX509StorePtr(VALUE obj)
    00079 {
    00080     X509_STORE *store;
    00081
    00082     SafeGetX509Store(obj, store);
    00083     CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE);
    00084
    00085     return store;
    00086 }
    00087
    00088 /*
    00089  * Private functions
    00090  */
    00091 static VALUE
    00092 ossl_x509store_alloc(VALUE klass)
    00093 {
    00094     X509_STORE *store;
    00095     VALUE obj;
    00096
    00097     if((store = X509_STORE_new()) == NULL){
    00098         ossl_raise(eX509StoreError, NULL);
    00099     }
    00100     WrapX509Store(klass, obj, store);
    00101
    00102     return obj;
    00103 }
    00104
    00105 /*
    00106  * General callback for OpenSSL verify
    00107  */
    00108 static VALUE
    00109 ossl_x509store_set_vfy_cb(VALUE self, VALUE cb)
    00110 {
    00111     X509_STORE *store;
    00112
    00113     GetX509Store(self, store);
    00114     X509_STORE_set_ex_data(store, ossl_verify_cb_idx, (void*)cb);
    00115     rb_iv_set(self, "@verify_callback", cb);
    00116
    00117     return cb;
    00118 }
    00119
    00120
    00121 /*
    00122  * call-seq:
    00123  *    X509::Store.new => store
    00124  *
    00125  */
    00126 static VALUE
    00127 ossl_x509store_initialize(int argc, VALUE *argv, VALUE self)
    00128 {
    00129     X509_STORE *store;
    00130
    00131 /* BUG: This method takes any number of arguments but appears to ignore them. */
    00132     GetX509Store(self, store);
    00133     store->ex_data.sk = NULL;
    00134     X509_STORE_set_verify_cb_func(store, ossl_verify_cb);
    00135     ossl_x509store_set_vfy_cb(self, Qnil);
    00136
    00137 #if (OPENSSL_VERSION_NUMBER < 0x00907000L)
    00138     rb_iv_set(self, "@flags", INT2NUM(0));
    00139     rb_iv_set(self, "@purpose", INT2NUM(0));
    00140     rb_iv_set(self, "@trust", INT2NUM(0));
    00141 #endif
    00142
    00143     /* last verification status */
    00144     rb_iv_set(self, "@error", Qnil);
    00145     rb_iv_set(self, "@error_string", Qnil);
    00146     rb_iv_set(self, "@chain", Qnil);
    00147     rb_iv_set(self, "@time", Qnil);
    00148
    00149     return self;
    00150 }
    00151
    00152 static VALUE
    00153 ossl_x509store_set_flags(VALUE self, VALUE flags)
    00154 {
    00155 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
    00156     X509_STORE *store;
    00157     long f = NUM2LONG(flags);
    00158
    00159     GetX509Store(self, store);
    00160     X509_STORE_set_flags(store, f);
    00161 #else
    00162     rb_iv_set(self, "@flags", flags);
    00163 #endif
    00164
    00165     return flags;
    00166 }
    00167
    00168 static VALUE
    00169 ossl_x509store_set_purpose(VALUE self, VALUE purpose)
    00170 {
    00171 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
    00172     X509_STORE *store;
    00173     long p = NUM2LONG(purpose);
    00174
    00175     GetX509Store(self, store);
    00176     X509_STORE_set_purpose(store, p);
    00177 #else
    00178     rb_iv_set(self, "@purpose", purpose);
    00179 #endif
    00180
    00181     return purpose;
    00182 }
    00183
    00184 static VALUE
    00185 ossl_x509store_set_trust(VALUE self, VALUE trust)
    00186 {
    00187 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
    00188     X509_STORE *store;
    00189     long t = NUM2LONG(trust);
    00190
    00191     GetX509Store(self, store);
    00192     X509_STORE_set_trust(store, t);
    00193 #else
    00194     rb_iv_set(self, "@trust", trust);
    00195 #endif
    00196
    00197     return trust;
    00198 }
    00199
    00200 static VALUE
    00201 ossl_x509store_set_time(VALUE self, VALUE time)
    00202 {
    00203     rb_iv_set(self, "@time", time);
    00204     return time;
    00205 }
    00206
    00207 static VALUE
    00208 ossl_x509store_add_file(VALUE self, VALUE file)
    00209 {
    00210     X509_STORE *store;
    00211     X509_LOOKUP *lookup;
    00212     char *path = NULL;
    00213
    00214     if(file != Qnil){
    00215         SafeStringValue(file);
    00216         path = RSTRING_PTR(file);
    00217     }
    00218     GetX509Store(self, store);
    00219     lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
    00220     if(lookup == NULL) ossl_raise(eX509StoreError, NULL);
    00221     if(X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM) != 1){
    00222         ossl_raise(eX509StoreError, NULL);
    00223     }
    00224
    00225     return self;
    00226 }
    00227
    00228 static VALUE
    00229 ossl_x509store_add_path(VALUE self, VALUE dir)
    00230 {
    00231     X509_STORE *store;
    00232     X509_LOOKUP *lookup;
    00233     char *path = NULL;
    00234
    00235     if(dir != Qnil){
    00236         SafeStringValue(dir);
    00237         path = RSTRING_PTR(dir);
    00238     }
    00239     GetX509Store(self, store);
    00240     lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
    00241     if(lookup == NULL) ossl_raise(eX509StoreError, NULL);
    00242     if(X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM) != 1){
    00243         ossl_raise(eX509StoreError, NULL);
    00244     }
    00245
    00246     return self;
    00247 }
    00248
    00249 static VALUE
    00250 ossl_x509store_set_default_paths(VALUE self)
    00251 {
    00252     X509_STORE *store;
    00253
    00254     GetX509Store(self, store);
    00255     if (X509_STORE_set_default_paths(store) != 1){
    00256         ossl_raise(eX509StoreError, NULL);
    00257     }
    00258
    00259     return Qnil;
    00260 }
    00261
    00262 static VALUE
    00263 ossl_x509store_add_cert(VALUE self, VALUE arg)
    00264 {
    00265     X509_STORE *store;
    00266     X509 *cert;
    00267
    00268     cert = GetX509CertPtr(arg); /* NO NEED TO DUP */
    00269     GetX509Store(self, store);
    00270     if (X509_STORE_add_cert(store, cert) != 1){
    00271         ossl_raise(eX509StoreError, NULL);
    00272     }
    00273
    00274     return self;
    00275 }
    00276
    00277 static VALUE
    00278 ossl_x509store_add_crl(VALUE self, VALUE arg)
    00279 {
    00280     X509_STORE *store;
    00281     X509_CRL *crl;
    00282
    00283     crl = GetX509CRLPtr(arg); /* NO NEED TO DUP */
    00284     GetX509Store(self, store);
    00285     if (X509_STORE_add_crl(store, crl) != 1){
    00286         ossl_raise(eX509StoreError, NULL);
    00287     }
    00288
    00289     return self;
    00290 }
    00291
    00292 static VALUE ossl_x509stctx_get_err(VALUE);
    00293 static VALUE ossl_x509stctx_get_err_string(VALUE);
    00294 static VALUE ossl_x509stctx_get_chain(VALUE);
    00295
    00296 static VALUE
    00297 ossl_x509store_verify(int argc, VALUE *argv, VALUE self)
    00298 {
    00299     VALUE cert, chain;
    00300     VALUE ctx, proc, result;
    00301
    00302     rb_scan_args(argc, argv, "11", &cert, &chain);
    00303     ctx = rb_funcall(cX509StoreContext, rb_intern("new"), 3, self, cert, chain);
    00304     proc = rb_block_given_p() ?  rb_block_proc() :
    00305            rb_iv_get(self, "@verify_callback");
    00306     rb_iv_set(ctx, "@verify_callback", proc);
    00307     result = rb_funcall(ctx, rb_intern("verify"), 0);
    00308
    00309     rb_iv_set(self, "@error", ossl_x509stctx_get_err(ctx));
    00310     rb_iv_set(self, "@error_string", ossl_x509stctx_get_err_string(ctx));
    00311     rb_iv_set(self, "@chain", ossl_x509stctx_get_chain(ctx));
    00312
    00313     return result;
    00314 }
    00315
    00316 /*
    00317  * Public Functions
    00318  */
    00319 static void ossl_x509stctx_free(X509_STORE_CTX*);
    00320
    00321 VALUE
    00322 ossl_x509stctx_new(X509_STORE_CTX *ctx)
    00323 {
    00324     VALUE obj;
    00325
    00326     WrapX509StCtx(cX509StoreContext, obj, ctx);
    00327
    00328     return obj;
    00329 }
    00330
    00331 VALUE
    00332 ossl_x509stctx_clear_ptr(VALUE obj)
    00333 {
    00334     OSSL_Check_Kind(obj, cX509StoreContext);
    00335     RDATA(obj)->data = NULL;
    00336
    00337     return obj;
    00338 }
    00339
    00340 /*
    00341  * Private functions
    00342  */
    00343 static void
    00344 ossl_x509stctx_free(X509_STORE_CTX *ctx)
    00345 {
    00346     if(ctx->untrusted)
    00347         sk_X509_pop_free(ctx->untrusted, X509_free);
    00348     if(ctx->cert)
    00349         X509_free(ctx->cert);
    00350     X509_STORE_CTX_free(ctx);
    00351 }
    00352
    00353 static VALUE
    00354 ossl_x509stctx_alloc(VALUE klass)
    00355 {
    00356     X509_STORE_CTX *ctx;
    00357     VALUE obj;
    00358
    00359     if((ctx = X509_STORE_CTX_new()) == NULL){
    00360         ossl_raise(eX509StoreError, NULL);
    00361     }
    00362     WrapX509StCtx(klass, obj, ctx);
    00363
    00364     return obj;
    00365 }
    00366
    00367 static VALUE ossl_x509stctx_set_flags(VALUE, VALUE);
    00368 static VALUE ossl_x509stctx_set_purpose(VALUE, VALUE);
    00369 static VALUE ossl_x509stctx_set_trust(VALUE, VALUE);
    00370 static VALUE ossl_x509stctx_set_time(VALUE, VALUE);
    00371
    00372 static VALUE
    00373 ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self)
    00374 {
    00375     VALUE store, cert, chain, t;
    00376     X509_STORE_CTX *ctx;
    00377     X509_STORE *x509st;
    00378     X509 *x509 = NULL;
    00379     STACK_OF(X509) *x509s = NULL;
    00380
    00381     rb_scan_args(argc, argv, "12", &store, &cert, &chain);
    00382     GetX509StCtx(self, ctx);
    00383     SafeGetX509Store(store, x509st);
    00384     if(!NIL_P(cert)) x509 = DupX509CertPtr(cert); /* NEED TO DUP */
    00385     if(!NIL_P(chain)) x509s = ossl_x509_ary2sk(chain);
    00386 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
    00387     if(X509_STORE_CTX_init(ctx, x509st, x509, x509s) != 1){
    00388         sk_X509_pop_free(x509s, X509_free);
    00389         ossl_raise(eX509StoreError, NULL);
    00390     }
    00391 #else
    00392     X509_STORE_CTX_init(ctx, x509st, x509, x509s);
    00393     ossl_x509stctx_set_flags(self, rb_iv_get(store, "@flags"));
    00394     ossl_x509stctx_set_purpose(self, rb_iv_get(store, "@purpose"));
    00395     ossl_x509stctx_set_trust(self, rb_iv_get(store, "@trust"));
    00396 #endif
    00397     if (!NIL_P(t = rb_iv_get(store, "@time")))
    00398         ossl_x509stctx_set_time(self, t);
    00399     rb_iv_set(self, "@verify_callback", rb_iv_get(store, "@verify_callback"));
    00400     rb_iv_set(self, "@cert", cert);
    00401
    00402     return self;
    00403 }
    00404
    00405 static VALUE
    00406 ossl_x509stctx_verify(VALUE self)
    00407 {
    00408     X509_STORE_CTX *ctx;
    00409     int result;
    00410
    00411     GetX509StCtx(self, ctx);
    00412     X509_STORE_CTX_set_ex_data(ctx, ossl_verify_cb_idx,
    00413                                (void*)rb_iv_get(self, "@verify_callback"));
    00414     result = X509_verify_cert(ctx);
    00415
    00416     return result ? Qtrue : Qfalse;
    00417 }
    00418
    00419 static VALUE
    00420 ossl_x509stctx_get_chain(VALUE self)
    00421 {
    00422     X509_STORE_CTX *ctx;
    00423     STACK_OF(X509) *chain;
    00424     X509 *x509;
    00425     int i, num;
    00426     VALUE ary;
    00427
    00428     GetX509StCtx(self, ctx);
    00429     if((chain = X509_STORE_CTX_get_chain(ctx)) == NULL){
    00430         return Qnil;
    00431     }
    00432     if((num = sk_X509_num(chain)) < 0){
    00433         OSSL_Debug("certs in chain < 0???");
    00434         return rb_ary_new();
    00435     }
    00436     ary = rb_ary_new2(num);
    00437     for(i = 0; i < num; i++) {
    00438         x509 = sk_X509_value(chain, i);
    00439         rb_ary_push(ary, ossl_x509_new(x509));
    00440     }
    00441
    00442     return ary;
    00443 }
    00444
    00445 static VALUE
    00446 ossl_x509stctx_get_err(VALUE self)
    00447 {
    00448     X509_STORE_CTX *ctx;
    00449
    00450     GetX509StCtx(self, ctx);
    00451
    00452     return INT2FIX(X509_STORE_CTX_get_error(ctx));
    00453 }
    00454
    00455 static VALUE
    00456 ossl_x509stctx_set_error(VALUE self, VALUE err)
    00457 {
    00458     X509_STORE_CTX *ctx;
    00459
    00460     GetX509StCtx(self, ctx);
    00461     X509_STORE_CTX_set_error(ctx, NUM2INT(err));
    00462
    00463     return err;
    00464 }
    00465
    00466 static VALUE
    00467 ossl_x509stctx_get_err_string(VALUE self)
    00468 {
    00469     X509_STORE_CTX *ctx;
    00470     long err;
    00471
    00472     GetX509StCtx(self, ctx);
    00473     err = X509_STORE_CTX_get_error(ctx);
    00474
    00475     return rb_str_new2(X509_verify_cert_error_string(err));
    00476 }
    00477
    00478 static VALUE
    00479 ossl_x509stctx_get_err_depth(VALUE self)
    00480 {
    00481     X509_STORE_CTX *ctx;
    00482
    00483     GetX509StCtx(self, ctx);
    00484
    00485     return INT2FIX(X509_STORE_CTX_get_error_depth(ctx));
    00486 }
    00487
    00488 static VALUE
    00489 ossl_x509stctx_get_curr_cert(VALUE self)
    00490 {
    00491     X509_STORE_CTX *ctx;
    00492
    00493     GetX509StCtx(self, ctx);
    00494
    00495     return ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx));
    00496 }
    00497
    00498 static VALUE
    00499 ossl_x509stctx_get_curr_crl(VALUE self)
    00500 {
    00501 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
    00502     X509_STORE_CTX *ctx;
    00503
    00504     GetX509StCtx(self, ctx);
    00505     if(!ctx->current_crl) return Qnil;
    00506
    00507     return ossl_x509crl_new(ctx->current_crl);
    00508 #else
    00509     return Qnil;
    00510 #endif
    00511 }
    00512
    00513 static VALUE
    00514 ossl_x509stctx_cleanup(VALUE self)
    00515 {
    00516     X509_STORE_CTX *ctx;
    00517
    00518     GetX509StCtx(self, ctx);
    00519     X509_STORE_CTX_cleanup(ctx);
    00520
    00521     return self;
    00522 }
    00523
    00524 static VALUE
    00525 ossl_x509stctx_set_flags(VALUE self, VALUE flags)
    00526 {
    00527     X509_STORE_CTX *store;
    00528     long f = NUM2LONG(flags);
    00529
    00530     GetX509StCtx(self, store);
    00531     X509_STORE_CTX_set_flags(store, f);
    00532
    00533     return flags;
    00534 }
    00535
    00536 static VALUE
    00537 ossl_x509stctx_set_purpose(VALUE self, VALUE purpose)
    00538 {
    00539     X509_STORE_CTX *store;
    00540     long p = NUM2LONG(purpose);
    00541
    00542     GetX509StCtx(self, store);
    00543     X509_STORE_CTX_set_purpose(store, p);
    00544
    00545     return purpose;
    00546 }
    00547
    00548 static VALUE
    00549 ossl_x509stctx_set_trust(VALUE self, VALUE trust)
    00550 {
    00551     X509_STORE_CTX *store;
    00552     long t = NUM2LONG(trust);
    00553
    00554     GetX509StCtx(self, store);
    00555     X509_STORE_CTX_set_trust(store, t);
    00556
    00557     return trust;
    00558 }
    00559
    00560 /*
    00561  * call-seq:
    00562  *    storectx.time = time => time
    00563  */
    00564 static VALUE
    00565 ossl_x509stctx_set_time(VALUE self, VALUE time)
    00566 {
    00567     X509_STORE_CTX *store;
    00568     long t;
    00569
    00570     t = NUM2LONG(rb_Integer(time));
    00571     GetX509StCtx(self, store);
    00572     X509_STORE_CTX_set_time(store, 0, t);
    00573
    00574     return time;
    00575 }
    00576
    00577 /*
    00578  * INIT
    00579  */
    00580 void
    00581 Init_ossl_x509store()
    00582 {
    00583     VALUE x509stctx;
    00584
    00585     eX509StoreError = rb_define_class_under(mX509, "StoreError", eOSSLError);
    00586
    00587     cX509Store = rb_define_class_under(mX509, "Store", rb_cObject);
    00588     rb_attr(cX509Store, rb_intern("verify_callback"), 1, 0, Qfalse);
    00589     rb_attr(cX509Store, rb_intern("error"), 1, 0, Qfalse);
    00590     rb_attr(cX509Store, rb_intern("error_string"), 1, 0, Qfalse);
    00591     rb_attr(cX509Store, rb_intern("chain"), 1, 0, Qfalse);
    00592     rb_define_alloc_func(cX509Store, ossl_x509store_alloc);
    00593     rb_define_method(cX509Store, "initialize",   ossl_x509store_initialize, -1);
    00594     rb_define_method(cX509Store, "verify_callback=", ossl_x509store_set_vfy_cb, 1);
    00595     rb_define_method(cX509Store, "flags=",       ossl_x509store_set_flags, 1);
    00596     rb_define_method(cX509Store, "purpose=",     ossl_x509store_set_purpose, 1);
    00597     rb_define_method(cX509Store, "trust=",       ossl_x509store_set_trust, 1);
    00598     rb_define_method(cX509Store, "time=",        ossl_x509store_set_time, 1);
    00599     rb_define_method(cX509Store, "add_path",     ossl_x509store_add_path, 1);
    00600     rb_define_method(cX509Store, "add_file",     ossl_x509store_add_file, 1);
    00601     rb_define_method(cX509Store, "set_default_paths", ossl_x509store_set_default_paths, 0);
    00602     rb_define_method(cX509Store, "add_cert",     ossl_x509store_add_cert, 1);
    00603     rb_define_method(cX509Store, "add_crl",      ossl_x509store_add_crl, 1);
    00604     rb_define_method(cX509Store, "verify",       ossl_x509store_verify, -1);
    00605
    00606     cX509StoreContext = rb_define_class_under(mX509,"StoreContext",rb_cObject);
    00607     x509stctx = cX509StoreContext;
    00608     rb_define_alloc_func(cX509StoreContext, ossl_x509stctx_alloc);
    00609     rb_define_method(x509stctx,"initialize",  ossl_x509stctx_initialize, -1);
    00610     rb_define_method(x509stctx,"verify",      ossl_x509stctx_verify, 0);
    00611     rb_define_method(x509stctx,"chain",       ossl_x509stctx_get_chain,0);
    00612     rb_define_method(x509stctx,"error",       ossl_x509stctx_get_err, 0);
    00613     rb_define_method(x509stctx,"error=",      ossl_x509stctx_set_error, 1);
    00614     rb_define_method(x509stctx,"error_string",ossl_x509stctx_get_err_string,0);
    00615     rb_define_method(x509stctx,"error_depth", ossl_x509stctx_get_err_depth, 0);
    00616     rb_define_method(x509stctx,"current_cert",ossl_x509stctx_get_curr_cert, 0);
    00617     rb_define_method(x509stctx,"current_crl", ossl_x509stctx_get_curr_crl, 0);
    00618     rb_define_method(x509stctx,"cleanup",     ossl_x509stctx_cleanup, 0);
    00619     rb_define_method(x509stctx,"flags=",      ossl_x509stctx_set_flags, 1);
    00620     rb_define_method(x509stctx,"purpose=",    ossl_x509stctx_set_purpose, 1);
    00621     rb_define_method(x509stctx,"trust=",      ossl_x509stctx_set_trust, 1);
    00622     rb_define_method(x509stctx,"time=",       ossl_x509stctx_set_time, 1);
    00623
    00624 }
    00625