Пример #1
0
static void compute_digest(unsigned char *digest, const char *challenge,
                           const char *password)
{
  unsigned char secret[64];
  apr_size_t len = strlen(password), i;
  apr_md5_ctx_t ctx;

  /* Munge the password into a 64-byte secret. */
  memset(secret, 0, sizeof(secret));
  if (len <= sizeof(secret))
    memcpy(secret, password, len);
  else
    apr_md5(secret, password, len);

  /* Compute MD5(secret XOR opad, MD5(secret XOR ipad, challenge)),
   * where ipad is a string of 0x36 and opad is a string of 0x5c. */
  for (i = 0; i < sizeof(secret); i++)
    secret[i] ^= 0x36;
  apr_md5_init(&ctx);
  apr_md5_update(&ctx, secret, sizeof(secret));
  apr_md5_update(&ctx, challenge, strlen(challenge));
  apr_md5_final(digest, &ctx);
  for (i = 0; i < sizeof(secret); i++)
    secret[i] ^= (0x36 ^ 0x5c);
  apr_md5_init(&ctx);
  apr_md5_update(&ctx, secret, sizeof(secret));
  apr_md5_update(&ctx, digest, APR_MD5_DIGESTSIZE);
  apr_md5_final(digest, &ctx);
}
Пример #2
0
svn_checksum_ctx_t *
svn_checksum_ctx_create(svn_checksum_kind_t kind,
                        apr_pool_t *pool)
{
  svn_checksum_ctx_t *ctx = apr_palloc(pool, sizeof(*ctx));

  ctx->kind = kind;
  switch (kind)
    {
      case svn_checksum_md5:
        ctx->apr_ctx = apr_palloc(pool, sizeof(apr_md5_ctx_t));
        apr_md5_init(ctx->apr_ctx);
        break;

      case svn_checksum_sha1:
        ctx->apr_ctx = apr_palloc(pool, sizeof(apr_sha1_ctx_t));
        apr_sha1_init(ctx->apr_ctx);
        break;

      default:
        return NULL;
    }

  return ctx;
}
void
svn_txdelta_apply(svn_stream_t *source,
                  svn_stream_t *target,
                  unsigned char *result_digest,
                  const char *error_info,
                  apr_pool_t *pool,
                  svn_txdelta_window_handler_t *handler,
                  void **handler_baton)
{
  apr_pool_t *subpool = svn_pool_create(pool);
  struct apply_baton *ab;

  ab = apr_palloc(subpool, sizeof(*ab));
  ab->source = source;
  ab->target = target;
  ab->pool = subpool;
  ab->sbuf = NULL;
  ab->sbuf_size = 0;
  ab->sbuf_offset = 0;
  ab->sbuf_len = 0;
  ab->tbuf = NULL;
  ab->tbuf_size = 0;
  ab->result_digest = result_digest;

  if (result_digest)
    apr_md5_init(&(ab->md5_context));

  if (error_info)
    ab->error_info = apr_pstrdup(subpool, error_info);
  else
    ab->error_info = NULL;

  *handler = apply_window;
  *handler_baton = ab;
}
Пример #4
0
	void initAPR()
	{
		try
		{
			apr_status_t rc = apr_md5_init(&md5_ctx);
			if (rc != APR_SUCCESS)
				throw MakeStringException(-1, "htpasswd apr_md5_init returns error %d", rc );
			apr_initialized = true;
		}
		catch (...)
		{
			throw MakeStringException(-1, "htpasswd exception calling apr_md5_init");
		}
	}
Пример #5
0
static
void do_encrypt(apr_pool_t *p, const char *key, char *str, int len, int enc)
{
	apr_md5_ctx_t my_md5;
	unsigned char *hash = apr_pcalloc(p, APR_MD5_DIGESTSIZE);

	apr_md5_init(&my_md5);
	apr_md5_update(&my_md5, key, (unsigned int)len);
	apr_md5_final(hash, &my_md5);

	BF_KEY my_bf;
	BF_set_key(&my_bf, APR_MD5_DIGESTSIZE, hash);

	int num = 0;
	unsigned char iv[8] = {0,0,0,0,0,0,0,0};
	BF_cfb64_encrypt(str, str, len, &my_bf, iv, &num, enc);
}
Пример #6
0
int main(int argc,char **argv) {
    apr_initialize();
    apr_pool_t *pool;
    apr_pool_create(&pool,NULL);
    apr_status_t st;

    char *filename;
    if(argc > 1) {
        filename=argv[1];
    } else {
        filename="apr_md5.c";
    }

    apr_md5_ctx_t md5;
    apr_md5_init(&md5);

    apr_file_t *file;
    st=apr_file_open(&file,filename,APR_READ,APR_REG,pool);
    if(st != APR_SUCCESS) {
        apr_err("apr_file_open()",st);
        return st;
    }
    apr_size_t n=1024;
    char *buf=apr_pcalloc(pool,n);
    while(APR_EOF != apr_file_eof(file)) {
        n=1024;
        st=apr_file_read(file,buf,&n);
        apr_md5_update(&md5,buf,n);
    }
    unsigned char result[APR_MD5_DIGESTSIZE];
    apr_md5_final(result,&md5);
    for(int i=0;i<APR_MD5_DIGESTSIZE;i++) {
        printf("%02x",result[i]);
    }
    printf("\n");

    apr_file_close(file);

    apr_pool_destroy(pool);
    apr_terminate();
    return 0;
}
Пример #7
0
static void cache_hash(const char *it, char *val, int ndepth, int nlength)
{
    apr_md5_ctx_t context;
    unsigned char digest[16];
    char tmp[22];
    int i, k, d;
    unsigned int x;
    static const char enc_table[64] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@";

    apr_md5_init(&context);
    apr_md5_update(&context, (const unsigned char *) it, strlen(it));
    apr_md5_final(digest, &context);

    /* encode 128 bits as 22 characters, using a modified uuencoding
     * the encoding is 3 bytes -> 4 characters* i.e. 128 bits is
     * 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters
     */
    for (i = 0, k = 0; i < 15; i += 3) {
        x = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2];
        tmp[k++] = enc_table[x >> 18];
        tmp[k++] = enc_table[(x >> 12) & 0x3f];
        tmp[k++] = enc_table[(x >> 6) & 0x3f];
        tmp[k++] = enc_table[x & 0x3f];
    }

    /* one byte left */
    x = digest[15];
    tmp[k++] = enc_table[x >> 2];    /* use up 6 bits */
    tmp[k++] = enc_table[(x << 4) & 0x3f];

    /* now split into directory levels */
    for (i = k = d = 0; d < ndepth; ++d) {
        memcpy(&val[i], &tmp[k], nlength);
        k += nlength;
        val[i + nlength] = '/';
        i += nlength + 1;
    }
    memcpy(&val[i], &tmp[k], 22 - k);
    val[i + 22 - k] = '\0';
}
Пример #8
0
static void add_password(const char *user, const char *realm, apr_file_t *f)
{
    char *pw;
    apr_md5_ctx_t context;
    unsigned char digest[16];
    char string[MAX_STRING_LEN];
    char pwin[MAX_STRING_LEN];
    char pwv[MAX_STRING_LEN];
    unsigned int i;
    apr_size_t len = sizeof(pwin);

    if (apr_password_get("New password: "******"password too long");
        cleanup_tempfile_and_exit(5);
    }
    len = sizeof(pwin);
    apr_password_get("Re-type new password: "******"They don't match, sorry.\n");
        cleanup_tempfile_and_exit(1);
    }
    pw = pwin;
    apr_file_printf(f, "%s:%s:", user, realm);

    /* Do MD5 stuff */
    sprintf(string, "%s:%s:%s", user, realm, pw);

    apr_md5_init(&context);
#if APR_CHARSET_EBCDIC
    apr_md5_set_xlate(&context, to_ascii);
#endif
    apr_md5_update(&context, (unsigned char *) string, strlen(string));
    apr_md5_final(digest, &context);

    for (i = 0; i < 16; i++)
        apr_file_printf(f, "%02x", digest[i]);

    apr_file_printf(f, "\n");
}
Пример #9
0
/**
 * Process data the parser has stored in the input buffer.
 */
static apr_status_t alp2_pp_process_internal(alp2_pp_t *alp_pp) {
    /* Do not proceed if we've previously 
     * encountered a fatal error.
     */
    if (alp_pp->errored != 0) {
        return ALP2_ERROR_FATAL;
    }

    if (alp_pp->done) {
        return ALP2_DONE;
    }

    /* Go back straight away if we don't have anything to work with. */
    if (alp_pp->input_len == 0) {
        return ALP2_NEED_DATA;
    }

    while (alp_pp->input_pos < alp_pp->input_len) {
        int c;

        if (alp_pp->done) {
            return ALP2_DONE;
        }

        if (alp_pp->line_pos >= alp_pp->line_size) {
            /* Our line buffer is full with the
             * line incomplete.
             */
            alp2_pp_process_part_data(alp_pp);

            /* Reset line buffer . */
            alp_pp->line_pos = 0;
            alp_pp->line_has_start = 0;
            alp_pp->line_offset = alp_pp->current_offset;
        }

        /* Consume one byte. */
        c = alp_pp->input_buf[alp_pp->input_pos];
        alp_pp->input_pos++;
        alp_pp->current_offset++;
        
        /* Copy the byte to the line buffer. */
        alp_pp->line_buf[alp_pp->line_pos] = c;
        alp_pp->line_pos++;
       
        /* Are we at the end of a line? */       
        if (c == '\n') {
            if (alp_pp->line_has_start) {
                /* We have one complete line. */
                
                int id = alp2_pp_is_boundary_line(alp_pp);

                if (id != 0) {
                    /* The line is a boundary. */
                    
                    /* Finish with the previous part, if any. */
                    if (alp_pp->current_part != NULL) {
                        /* Update the MD5 context. */
                        apr_md5_update(alp_pp->current_entry->md5_context,
                            &alp_pp->line_buf[0], alp_pp->line_pos - 1);
                        
                        /* Event PART_END. */
                        if (alp_pp->callback != NULL) {
                            if (alp_pp->callback(alp_pp, ALP2_EVENT_PART_END) == 0) {
                                alp_pp->done = 1;
                            }
                        }
                        
                        /* Add part to the current entry. */
                        *(alp2_pp_part_t **)apr_array_push(alp_pp->current_entry->parts)
                            = alp_pp->current_part;

                        /* Delete part. */
                        alp_pp->current_part = NULL;
                        
                        /* If the new part is part Z, then finish
                         * with the current entry. */
                        if (id == 'Z') {
                            alp_pp->current_entry->size = alp_pp->current_offset - alp_pp->current_entry->offset;

                            /* Create the MD5 digest. */
                            apr_md5_final(alp_pp->current_entry->md5_digest,
                                alp_pp->current_entry->md5_context);

                            /* Event ENTRY_END. */
                            if (alp_pp->callback != NULL) {
                                if (alp_pp->callback(alp_pp, ALP2_EVENT_ENTRY_END) == 0) {
                                    alp_pp->done = 1;
                                }
                            }

                            /* We are about to destroy our only reference to the per-entry
                             * memory pool, but that is all right since we've passed all
                             * responsibility for the entry to the higher-level handler.
                             */
                            alp_pp->current_entry = NULL;
                        }
                    }
                    
                    if (id != 'Z') {
                        /* Create new entry if necessary. */
                        if (alp_pp->current_entry == NULL) {
                            apr_pool_t *new_pool = NULL;

                            /* Create a per-entry pool directly from the main memory pool. */
                            apr_pool_create(&new_pool, apr_pool_parent_get(alp_pp->mp));

                            alp_pp->current_entry = apr_pcalloc(new_pool, sizeof(alp2_pp_entry_t));
                            alp_pp->current_entry->mp = new_pool;
                            alp_pp->current_entry->offset = alp_pp->line_offset;
                            alp_pp->current_entry->boundary = apr_pstrdup(new_pool, alp_pp->boundary);
                            alp_pp->boundary = NULL;

                            alp_pp->current_entry->parts = apr_array_make(alp_pp->current_entry->mp,
                                16, sizeof(alp2_pp_part_t *));

                            /* Initialise the MD5 context. */
                            alp_pp->current_entry->md5_context = apr_pcalloc(alp_pp->current_entry->mp,
                                sizeof(apr_md5_ctx_t));
                            apr_md5_init(alp_pp->current_entry->md5_context);

                            /* Start calculating the has with the first line. */
                            apr_md5_update(alp_pp->current_entry->md5_context, &alp_pp->line_buf[0], alp_pp->line_pos - 1);

                            /* Event ENTRY_START. */
                            if (alp_pp->callback != NULL) {
                                if (alp_pp->callback(alp_pp, ALP2_EVENT_ENTRY_START) == 0) {
                                    alp_pp->done = 1;
                                }
                            }
                        }
                    
                        /* Create new part, but only if we are not
                         * dealing with an entry terminator.
                         */
                        alp_pp->current_part = apr_pcalloc(alp_pp->current_entry->mp, sizeof(alp2_pp_part_t));
                        alp_pp->current_part->id = id;
                        alp_pp->current_part->offset = alp_pp->current_offset;

                        /* Event PART_START. */
                        if (alp_pp->callback != NULL) {
                            if (alp_pp->callback(alp_pp, ALP2_EVENT_PART_START) == 0) {
                                alp_pp->done = 1;
                            }
                        }
                    }
                }
                else {
                    /* The line does not contain a boundary,
                     * so process it as part data.
                     */
                    alp2_pp_process_part_data(alp_pp);
                }
            }
            else {
                /* We have a chunk of data that is not a line, which
                 * probably means that our buffer was not big enough, either
                 * because the line (is a line and it) was too big, or because
                 * we are processing binary data. Ideally the latter.
                 */
                alp2_pp_process_part_data(alp_pp);
            }
            
            /* Reset the line buffer. */
            alp_pp->line_pos = 0;
            alp_pp->line_has_start = 1;
            alp_pp->line_offset = alp_pp->current_offset;
        }
    }

    if (alp_pp->done) {
        return ALP2_DONE;
    }
    else {
        return ALP2_NEED_DATA;
    }
}
Пример #10
0
/*--------------------------------------------------------------------------*/
static int post_config_hook(apr_pool_t *pconf, apr_pool_t *plog,
                            apr_pool_t *ptemp, server_rec *s)
{
    apr_status_t rv;
    const char *pk = "advertise_init_module_tag";
    apr_pool_t *pproc = s->process->pool;
    apr_thread_t *tp;
    mod_advertise_config *mconf = ap_get_module_config(s->module_config, &advertise_module);
    int advertisefound = 0;
    server_rec *server = s;

    /* Advertise directive in more than one VirtualHost: not supported */
    while (server) {
        mod_advertise_config *conf = ap_get_module_config(server->module_config, &advertise_module);
        if (conf->ma_advertise_server == server) {
            if (advertisefound) {
                ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                         "mod_advertise: directive in more than one VirtualHost: not supported");
                return !OK;
            } else
                advertisefound = -1;
        }
        server = server->next;
    }

    /* Our server */
    server = s;
    while (server) {
        mconf = ap_get_module_config(server->module_config, &advertise_module);
        if (mconf->ma_advertise_server == server)
            break;
        server = server->next;
    }

    apr_pool_userdata_get((void *)&magd, pk, pproc);
    if (!magd) {
        if (!(magd = apr_pcalloc(pproc, sizeof(ma_global_data_t))))
            return apr_get_os_error();
        apr_pool_create(&magd->ppool, pproc);
        apr_pool_userdata_set(magd, pk, apr_pool_cleanup_null, pproc);
        /* First time config phase -- skip. */
        return OK;
    }
#if defined(WIN32)
    {
        const char *ppid = getenv("AP_PARENT_PID");
        if (ppid) {
            ma_parent_pid = atol(ppid);
            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                "[%" APR_PID_T_FMT " - %" APR_PID_T_FMT
                "] in child post config hook",
                getpid(), ma_parent_pid);
            return OK;
        }
    }
#endif
    ma_server_rec = server; 
    if (mconf->ma_advertise_skey) {
        apr_md5_ctx_t mc;
        apr_md5_init(&mc);
        apr_md5_update(&mc, mconf->ma_advertise_skey, strlen(mconf->ma_advertise_skey));
        apr_md5_final(magd->ssalt, &mc);
    } else {
        /* If security key is not configured, the digest is calculated from zero bytes */
        memset(magd->ssalt, '\0', APR_MD5_DIGESTSIZE);
    }
    apr_uuid_get(&magd->suuid);
    magd->srvid[0] = '/';
    apr_uuid_format(&magd->srvid[1], &magd->suuid);
    if (!mconf->ma_advertise_srvh)
        mconf->ma_advertise_srvh = magd->srvid;
    /* Check if we have advertise set */
    if (mconf->ma_advertise_mode != ma_advertise_off &&
        mconf->ma_advertise_adrs) {
        rv = ma_group_join(mconf->ma_advertise_adrs, mconf->ma_advertise_port, mconf->ma_bind_adrs, mconf->ma_bind_port, pconf, s);
        if (rv != APR_SUCCESS) {
            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
                         "mod_advertise: multicast join failed for %s:%d.",
                         mconf->ma_advertise_adrs, mconf->ma_advertise_port);
            ma_advertise_run = 0;
        }
        else {
            ma_advertise_run  = 1;
            ma_advertise_stat = 200;
        }
    }

    /* Fill default values */
    if (!mconf->ma_advertise_srvm)  {
        if (ma_server_rec && ma_server_rec->server_scheme) {
            /* ServerName scheme://fully-qualified-domain-name[:port] */
            mconf->ma_advertise_srvm = apr_pstrdup(pconf, ma_server_rec->server_scheme);
        } else {
            mconf->ma_advertise_srvm = apr_pstrdup(pconf, "http");
        }
    }

    if (mconf->ma_advertise_srvs == NULL && ma_server_rec) {
        /*
         * That is not easy just use ServerAdvertise with the server parameter
         * if the code below doesn't work
         */
        char *ptr = NULL;
        int port = DEFAULT_HTTP_PORT;
        if (ma_server_rec->addrs && ma_server_rec->addrs->host_addr &&
            ma_server_rec->addrs->host_addr->next == NULL) {
            ptr = apr_psprintf(pproc, "%pI", ma_server_rec->addrs->host_addr);
        }
        /* Use don't use any as local address too */
        if (ptr == NULL || strncmp(ptr,"0.0.0.0", 7) == 0 || strncmp(ptr,"::",2) == 0) {
            if  ( ma_server_rec->port == 0 || ma_server_rec->port == 1) {
                if (ma_server_rec->addrs->host_addr->port != 0)
                    port = ma_server_rec->addrs->host_addr->port;
            } else {
                port = ma_server_rec->port;
             }
            ptr = apr_psprintf(pproc, "%s:%lu", ma_server_rec->server_hostname, port);
        }
        rv = apr_parse_addr_port(&mconf->ma_advertise_srvs,
                                 &mconf->ma_advertise_srvi,
                                 &mconf->ma_advertise_srvp,
                                 ptr, pproc);
        if (rv != APR_SUCCESS || !mconf->ma_advertise_srvs ||
                                 !mconf->ma_advertise_srvp) {
            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
                         "mod_advertise: Invalid ServerAdvertise Address %s",
                         ptr);
            return rv;
        }
    }

    /* prevent X-Manager-Address: (null):0  */
    if (!mconf->ma_advertise_srvs || !mconf->ma_advertise_srvp) {
            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
                         "mod_advertise: ServerAdvertise Address or Port not defined, Advertise disabled!!!");
            return OK;
    }

    /* Create parent management thread */
    is_mp_running = 1;
    rv = apr_thread_create(&tp, NULL, parent_thread, server, pconf);
    if (rv != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
                     "mod_advertise: parent apr_thread_create");
        return rv;
    }
    apr_thread_detach(tp);

    /* Create cleanup pool that will be destroyed first
     * in future use new apr_pool_pre_cleanup_register from APR 1.3
     */
    apr_pool_create(&magd->cpool, pconf);
    apr_pool_cleanup_register(magd->cpool, magd, pconfig_cleanup,
                              apr_pool_cleanup_null);

    ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
                 "Advertise initialized for process %" APR_PID_T_FMT,
                 getpid());

    apr_pool_cleanup_register(magd->ppool, magd, process_cleanup,
                              apr_pool_cleanup_null);



    return OK;
}
Пример #11
0
apr_status_t ma_advertise_server(server_rec *server, int type)
{
    char buf[MA_BSIZE];
    char dat[APR_RFC822_DATE_LEN];
    char add[40];
    unsigned char msig[APR_MD5_DIGESTSIZE];
    unsigned char ssig[APR_MD5_DIGESTSIZE * 2 + 1];
    const char *asl;
    char *p = buf;
    int  i, c = 0;
    apr_size_t l = MA_BSIZE - 8;
    apr_size_t n = 0;
    apr_md5_ctx_t md;
    mod_advertise_config *mconf = ap_get_module_config(server->module_config, &advertise_module);

    ma_sequence++;
    if (ma_sequence < 1)
        ma_sequence = 1;
    sprintf(buf, "%" APR_INT64_T_FMT, ma_sequence);
    ap_recent_rfc822_date(dat, apr_time_now());
    asl = ap_get_status_line(ma_advertise_stat);

    /* Create MD5 digest
     * salt + date + sequence + srvid
     */
    apr_md5_init(&md);
    apr_md5_update(&md, magd->ssalt, APR_MD5_DIGESTSIZE);
    apr_md5_update(&md, dat, strlen(dat));
    apr_md5_update(&md, buf, strlen(buf));
    apr_md5_update(&md, magd->srvid + 1, strlen(magd->srvid) - 1);
    apr_md5_final(msig, &md);
    /* Convert MD5 digest to hex string */
    for (i = 0; i < APR_MD5_DIGESTSIZE; i++) {
        ssig[c++] = hex[msig[i] >> 4];
        ssig[c++] = hex[msig[i] & 0x0F];
    }
    ssig[c] = '\0';
    n = apr_snprintf(p, l, MA_ADVERTISE_SERVER_FMT,
                     asl, dat, ma_sequence, ssig, magd->srvid + 1);
    if (type == MA_ADVERTISE_SERVER) {
        char *ma_advertise_srvs = mconf->ma_advertise_srvs;
        if (strchr(ma_advertise_srvs, ':') != NULL) {
            apr_snprintf(add, 40, "[%s]", mconf->ma_advertise_srvs);
            ma_advertise_srvs = add;
        }
        l -= n;
        n += apr_snprintf(p + n, l,
                          "X-Manager-Address: %s:%u" CRLF
                          "X-Manager-Url: %s" CRLF
                          "X-Manager-Protocol: %s" CRLF
                          "X-Manager-Host: %s" CRLF,
                          ma_advertise_srvs,
                          mconf->ma_advertise_srvp,
                          mconf->ma_advertise_srvh,
                          mconf->ma_advertise_srvm,
                          server->server_hostname);

    }
    strcat(p, CRLF);
    n += 2;
    return apr_socket_sendto(ma_mgroup_socket,
                             ma_mgroup_sa, 0, buf, &n);
}
Пример #12
0
static int authenticate_token(request_rec *r)
{
	const char *usertoken, *timestamp, *path, *remoteip;
	unsigned char digest[APR_MD5_DIGESTSIZE];
	char token[APR_MD5_DIGESTSIZE * 2];
	auth_token_config_rec *conf;
	apr_md5_ctx_t context;

	conf = ap_get_module_config(r->per_dir_config, &auth_token_module);
	
	/* Get the remote IP , forcing to get an IP instead DNS record*/
	if (conf->checkip) {
		remoteip = ap_get_remote_host(r->connection, NULL, REMOTE_NAME, NULL);
    	if(NULL == remoteip)
		{	
			ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "mod_auth_token: request from ip FAILED." );
			return DECLINED;
		}		
		ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "mod_auth_token: request from ip %s", remoteip );
	}


	/* check if the request uri is to be protected */
	if (conf->prefix == NULL || strncmp(r->uri, conf->prefix, conf->prefix_len)) {
		return DECLINED;
	}

	/* <prefix> <32-byte-token> "/" <8-byte-timestamp> "/" */
	if (strlen(r->uri) < conf->prefix_len + 32 + 1 + 8 + 1) {
		ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "mod_auth_token: malformed or nonexistent token");
		return HTTP_UNAUTHORIZED;
	}

	/* mark token, timestamp and relative path components */
	usertoken = r->uri + conf->prefix_len;
	timestamp = r->uri + conf->prefix_len + 32 + 1;
	path = r->uri + conf->prefix_len + 32 + 1 + 8;

	/* check if token has expired */
	if ((unsigned int)apr_time_sec(apr_time_now()) > auth_token_hex2sec(timestamp) + conf->timeout) {
		ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "mod_auth_token: token expired at %u, now is %u",
			auth_token_hex2sec(timestamp) + conf->timeout, (unsigned int)apr_time_sec(apr_time_now()));
		return HTTP_GONE;
	}

	/* create md5 token of secret + path + timestamp */
	apr_md5_init(&context);

	apr_md5_update(&context, (unsigned char *) conf->secret, strlen(conf->secret));
	apr_md5_update(&context, (unsigned char *) path, strlen(path));
	apr_md5_update(&context, (unsigned char *) timestamp, 8);
	if (conf->checkip)
		apr_md5_update(&context, (unsigned char *) remoteip, strlen(remoteip));
	apr_md5_final(digest, &context);

	/* compare hex encoded token and user provided token */
	auth_token_bin2hex(token, (const char *)digest, APR_MD5_DIGESTSIZE);

	if (strncasecmp(token, usertoken, APR_MD5_DIGESTSIZE * 2) == 0) {
		/* remove token and timestamp from uri */
		memmove(r->uri + conf->prefix_len - 1, path, strlen(path) + 1);
		r->filename = apr_pstrdup(r->pool, r->uri);

		/* allow other modules to run their hooks */
		return DECLINED;
	}

	ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "mod_auth_token: failed token auth (got '%s', expected '%s', uri '%s')",
		apr_pstrndup(r->pool, usertoken, 32), apr_pstrndup(r->pool, token, 32), r->uri);
	return HTTP_FORBIDDEN;
}