END_TEST /* Generate a null-terminated string of random bytes between one and * length_limit characters */ char *rand_str(apr_pool_t *p, unsigned int length_limit) { /* Generate a random length from one to length_limit, inclusive. * This method for choosing a length is biased, but it should be * fine for testing purposes. */ unsigned int len; if (length_limit < 1) { len = 1; } else { apr_generate_random_bytes((unsigned char*)(&len), sizeof(unsigned int)); len = abs(len) % length_limit; } /* Make room for the null terminator */ len++; /* Generate a random, null-terminated sequence of bytes. The * terminator may appear earlier than the end, but we guarantee * that the string is terminated at or before length_limit * bytes. */ char *ans = apr_palloc(p, len); apr_generate_random_bytes((unsigned char *) ans, len - 1); ans[len - 1] = '\0'; return ans; }
/* extremely naively generates a number between 0 and 1 */ MVMnum64 MVM_proc_rand_n(MVMThreadContext *tc) { MVMuint64 first, second; apr_generate_random_bytes((unsigned char *)&first, sizeof(MVMuint64)); do { apr_generate_random_bytes((unsigned char *)&second, sizeof(MVMuint64)); /* prevent division by zero in the 2**-128 chance both are 0 */ } while (first == second); return first < second ? (MVMnum64)first / second : (MVMnum64)second / first; }
/* * Generate a new session ID. * * Note that apr_generate_random_bytes() blocks on Linux due to reading from * /dev/random. FreeBSD /dev/random never blocks. Solaris /dev/random does * not seem to block either. To keep mod_but usable on Linux, we try to not * waste any randomness: only read as much as needed and use all bits. * On Linux, APR should be compiled to read from /dev/urandom by default. */ char * generate_session_id(request_rec *r) { apr_status_t rc; unsigned char rnd[MOD_BUT_SIDBYTES]; char *sid = apr_pcalloc(r->pool, apr_base64_encode_len(MOD_BUT_SIDBYTES) + 1); if (!sid) { ERRLOG_CRIT("FATAL: Out of memory"); return NULL; } if (APR_SUCCESS != (rc = apr_generate_random_bytes(rnd, MOD_BUT_SIDBYTES))) { ERRLOG_CRIT("FATAL: apr_generate_random_bytes returned %d", rc); return NULL; } if (0 >= apr_base64_encode_binary(sid, rnd, MOD_BUT_SIDBYTES)) { ERRLOG_CRIT("FATAL: apr_base64_encode failed"); return NULL; } ERRLOG_INFO("Session ID generated [%s]", sid); return sid; }
static int generate_salt(char *s, size_t size, const char **errstr, apr_pool_t *pool) { unsigned char rnd[32]; static const char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; apr_size_t n; unsigned int val = 0, bits = 0; apr_status_t rv; n = (size * 6 + 7)/8; if (n > sizeof(rnd)) { apr_file_printf(errfile, "generate_salt(): BUG: Buffer too small"); abort(); } rv = apr_generate_random_bytes(rnd, n); if (rv) { *errstr = apr_psprintf(pool, "Unable to generate random bytes: %pm", &rv); return ERR_RANDOM; } n = 0; while (size > 0) { if (bits < 6) { val |= (rnd[n++] << bits); bits += 8; } *s++ = itoa64[val & 0x3f]; size--; val >>= 6; bits -= 6; } *s = '\0'; return 0; }
/* If we can, make the nonce with random bytes. If we can't... well, * it just has to be different each time. The current time isn't * absolutely guaranteed to be different for each connection, but it * should prevent replay attacks in practice. */ static apr_status_t make_nonce(apr_uint64_t *nonce) { #if APR_HAS_RANDOM return apr_generate_random_bytes((unsigned char *) nonce, sizeof(*nonce)); #else *nonce = apr_time_now(); return APR_SUCCESS; #endif }
/* true_random -- generate a crypto-quality random number. Taken from apr-util's getuuid.c file */ int true_random() { #if APR_HAS_RANDOM unsigned char buf[2]; if (apr_generate_random_bytes(buf, 2) == APR_SUCCESS) return (buf[0] << 8) | buf[1]; #endif apr_uint64_t time_now = apr_time_now(); srand((unsigned int)(((time_now >> 32) ^ time_now) & 0xffffffff)); return rand() & 0x0FFFF; };
static apr_status_t seed_rand(void) { int seed = 0; apr_status_t rv; rv = apr_generate_random_bytes((unsigned char*) &seed, sizeof(seed)); if (rv) { apr_file_printf(errfile, "Unable to generate random bytes: %pm" NL, &rv); return rv; } srand(seed); return rv; }
void url_InitRandom(RandState state) { unsigned int seed; apr_generate_random_bytes((unsigned char*)&seed, sizeof(int)); #if HAVE_LRAND48_R srand48_r(seed, state); #else srand(seed); #endif }
static void rand_exists(abts_case *tc, void *data) { #if !APR_HAS_RANDOM ABTS_NOT_IMPL(tc, "apr_generate_random_bytes"); #else unsigned char c[42]; /* There must be a better way to test random-ness, but I don't know * what it is right now. */ APR_ASSERT_SUCCESS(tc, "apr_generate_random_bytes failed", apr_generate_random_bytes(c, sizeof c)); #endif }
/* * generate a random value (nonce) to correlate request/response through browser state */ apr_byte_t oidc_proto_generate_nonce(request_rec *r, char **nonce) { unsigned char *nonce_bytes = apr_pcalloc(r->pool, OIDC_PROTO_NONCE_LENGTH); if (apr_generate_random_bytes(nonce_bytes, OIDC_PROTO_NONCE_LENGTH) != APR_SUCCESS) { oidc_error(r, "apr_generate_random_bytes returned an error"); return FALSE; } if (oidc_base64url_encode(r, nonce, (const char *) nonce_bytes, OIDC_PROTO_NONCE_LENGTH, TRUE) <= 0) { oidc_error(r, "oidc_base64url_encode returned an error"); return FALSE; } return TRUE; }
/* Set RAND_BYTES to a block of bytes containing random data RAND_LEN long and allocated from RESULT_POOL. */ static svn_error_t * get_random_bytes(const unsigned char **rand_bytes, svn_crypto__ctx_t *ctx, apr_size_t rand_len, apr_pool_t *result_pool) { apr_status_t apr_err; unsigned char *bytes; bytes = apr_palloc(result_pool, rand_len); apr_err = apr_generate_random_bytes(bytes, rand_len); if (apr_err != APR_SUCCESS) return svn_error_wrap_apr(apr_err, _("Error obtaining random data")); *rand_bytes = bytes; return SVN_NO_ERROR; }
static void *persona_create_svr_config(apr_pool_t *p, server_rec *s) { persona_config_t *conf = apr_palloc(p, sizeof(*conf)); apr_random_t *prng = apr_random_standard_new(p); while (apr_random_secure_ready(prng) == APR_ENOTENOUGHENTROPY) { unsigned char randbuf[RAND_BYTES_AT_A_TIME]; apr_generate_random_bytes(randbuf, RAND_BYTES_AT_A_TIME); apr_random_add_entropy(prng, randbuf, RAND_BYTES_AT_A_TIME); } char *secret = apr_palloc(p, PERSONA_SECRET_SIZE); apr_random_secure_bytes(prng, secret, PERSONA_SECRET_SIZE); conf->secret = apr_palloc(p, sizeof(buffer_t)); conf->secret->len = PERSONA_SECRET_SIZE; conf->secret->data = secret; conf->logout_path = apr_palloc(p, sizeof(buffer_t)); conf->logout_path->len = 0; conf->logout_path->data = NULL; return conf; }
TCN_IMPLEMENT_CALL(jint, OS, random)(TCN_STDARGS, jbyteArray buf, jint len) { #if APR_HAS_RANDOM apr_status_t rv; jbyte *b = (*e)->GetPrimitiveArrayCritical(e, buf, NULL); UNREFERENCED(o); if ((rv = apr_generate_random_bytes((unsigned char *)b, (apr_size_t)len)) == APR_SUCCESS) (*e)->ReleasePrimitiveArrayCritical(e, buf, b, 0); else (*e)->ReleasePrimitiveArrayCritical(e, buf, b, JNI_ABORT); if ((*e)->ExceptionCheck(e)) { (*e)->ExceptionClear(e); rv = APR_EGENERAL; } return (jint)rv; #else return APR_ENOTIMPL; #endif }
static void * APR_THREAD_FUNC resource_consuming_thread(apr_thread_t *thd, void *data) { int i; apr_uint32_t chance; void *vp; apr_status_t rv; my_resource_t *res; my_thread_info_t *thread_info = data; apr_reslist_t *rl = thread_info->reslist; #if APR_HAS_RANDOM apr_generate_random_bytes((void*)&chance, sizeof(chance)); #else chance = (apr_uint32_t)(apr_time_now() % APR_TIME_C(4294967291)); #endif for (i = 0; i < CONSUMER_ITERATIONS; i++) { rv = apr_reslist_acquire(rl, &vp); ABTS_INT_EQUAL(thread_info->tc, APR_SUCCESS, rv); res = vp; apr_sleep(thread_info->work_delay_sleep); /* simulate a 5% chance of the resource being bad */ chance = lgc(chance); if ( chance < PERCENT95th ) { rv = apr_reslist_release(rl, res); ABTS_INT_EQUAL(thread_info->tc, APR_SUCCESS, rv); } else { rv = apr_reslist_invalidate(rl, res); ABTS_INT_EQUAL(thread_info->tc, APR_SUCCESS, rv); } } return APR_SUCCESS; }
/* XXX the internet says this may block... */ MVMint64 MVM_proc_rand_i(MVMThreadContext *tc) { MVMint64 result; apr_generate_random_bytes((unsigned char *)&result, sizeof(MVMint64)); return result; }
APR_DECLARE(apr_status_t) apr_file_pipe_create_pools(apr_file_t **in, apr_file_t **out, apr_int32_t blocking, apr_pool_t *pool_in, apr_pool_t *pool_out) { #ifdef _WIN32_WCE return APR_ENOTIMPL; #else SECURITY_ATTRIBUTES sa; static unsigned long id = 0; DWORD dwPipeMode; DWORD dwOpenMode; sa.nLength = sizeof(sa); #if APR_HAS_UNICODE_FS IF_WIN_OS_IS_UNICODE sa.bInheritHandle = FALSE; #endif #if APR_HAS_ANSI_FS ELSE_WIN_OS_IS_ANSI sa.bInheritHandle = TRUE; #endif sa.lpSecurityDescriptor = NULL; (*in) = (apr_file_t *)apr_pcalloc(pool_in, sizeof(apr_file_t)); (*in)->pool = pool_in; (*in)->fname = NULL; (*in)->pipe = 1; (*in)->timeout = -1; (*in)->ungetchar = -1; (*in)->eof_hit = 0; (*in)->filePtr = 0; (*in)->bufpos = 0; (*in)->dataRead = 0; (*in)->direction = 0; (*in)->pOverlapped = NULL; #if APR_FILES_AS_SOCKETS (void) apr_pollset_create(&(*in)->pollset, 1, p, 0); #endif (*out) = (apr_file_t *)apr_pcalloc(pool_out, sizeof(apr_file_t)); (*out)->pool = pool_out; (*out)->fname = NULL; (*out)->pipe = 1; (*out)->timeout = -1; (*out)->ungetchar = -1; (*out)->eof_hit = 0; (*out)->filePtr = 0; (*out)->bufpos = 0; (*out)->dataRead = 0; (*out)->direction = 0; (*out)->pOverlapped = NULL; #if APR_FILES_AS_SOCKETS (void) apr_pollset_create(&(*out)->pollset, 1, p, 0); #endif if (apr_os_level >= APR_WIN_NT) { char rand[8]; int pid = getpid(); #define FMT_PIPE_NAME "\\\\.\\pipe\\apr-pipe-%x.%lx." /* ^ ^ ^ * pid | | * | | * id | * | * hex-escaped rand[8] (16 bytes) */ char name[sizeof FMT_PIPE_NAME + 2 * sizeof(pid) + 2 * sizeof(id) + 2 * sizeof(rand)]; apr_size_t pos; /* Create the read end of the pipe */ dwOpenMode = PIPE_ACCESS_INBOUND; #ifdef FILE_FLAG_FIRST_PIPE_INSTANCE dwOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; #endif if (blocking == APR_WRITE_BLOCK /* READ_NONBLOCK */ || blocking == APR_FULL_NONBLOCK) { dwOpenMode |= FILE_FLAG_OVERLAPPED; (*in)->pOverlapped = (OVERLAPPED*) apr_pcalloc((*in)->pool, sizeof(OVERLAPPED)); (*in)->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); (*in)->timeout = 0; } dwPipeMode = 0; apr_generate_random_bytes(rand, sizeof rand); pos = apr_snprintf(name, sizeof name, FMT_PIPE_NAME, pid, id++); apr_escape_hex(name + pos, rand, sizeof rand, 0, NULL); (*in)->filehand = CreateNamedPipe(name, dwOpenMode, dwPipeMode, 1, /* nMaxInstances, */ 0, /* nOutBufferSize, */ 65536, /* nInBufferSize, */ 1, /* nDefaultTimeOut, */ &sa); if ((*in)->filehand == INVALID_HANDLE_VALUE) { apr_status_t rv = apr_get_os_error(); file_cleanup(*in); return rv; } /* Create the write end of the pipe */ dwOpenMode = FILE_ATTRIBUTE_NORMAL; if (blocking == APR_READ_BLOCK /* WRITE_NONBLOCK */ || blocking == APR_FULL_NONBLOCK) { dwOpenMode |= FILE_FLAG_OVERLAPPED; (*out)->pOverlapped = (OVERLAPPED*) apr_pcalloc((*out)->pool, sizeof(OVERLAPPED)); (*out)->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); (*out)->timeout = 0; } (*out)->filehand = CreateFile(name, GENERIC_WRITE, /* access mode */ 0, /* share mode */ &sa, /* Security attributes */ OPEN_EXISTING, /* dwCreationDisposition */ dwOpenMode, /* Pipe attributes */ NULL); /* handle to template file */ if ((*out)->filehand == INVALID_HANDLE_VALUE) { apr_status_t rv = apr_get_os_error(); file_cleanup(*out); file_cleanup(*in); return rv; } } else { /* Pipes on Win9* are blocking. Live with it. */ if (!CreatePipe(&(*in)->filehand, &(*out)->filehand, &sa, 65536)) { return apr_get_os_error(); } } apr_pool_cleanup_register((*in)->pool, (void *)(*in), file_cleanup, apr_pool_cleanup_null); apr_pool_cleanup_register((*out)->pool, (void *)(*out), file_cleanup, apr_pool_cleanup_null); return APR_SUCCESS; #endif /* _WIN32_WCE */ }
static bool mag_auth_basic(request_rec *req, struct mag_config *cfg, gss_buffer_desc ba_user, gss_buffer_desc ba_pwd, gss_name_t *client, gss_OID *mech_type, gss_cred_id_t *delegated_cred, uint32_t *vtime) { #ifdef HAVE_GSS_KRB5_CCACHE_NAME const char *user_ccache = NULL; const char *orig_ccache = NULL; long long unsigned int rndname; apr_status_t rs; #endif gss_name_t user = GSS_C_NO_NAME; gss_cred_id_t user_cred = GSS_C_NO_CREDENTIAL; gss_ctx_id_t user_ctx = GSS_C_NO_CONTEXT; gss_name_t server = GSS_C_NO_NAME; gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL; gss_ctx_id_t server_ctx = GSS_C_NO_CONTEXT; gss_buffer_desc input = GSS_C_EMPTY_BUFFER; gss_buffer_desc output = GSS_C_EMPTY_BUFFER; gss_OID_set allowed_mechs; gss_OID_set filtered_mechs; gss_OID_set actual_mechs = GSS_C_NO_OID_SET; uint32_t init_flags = 0; uint32_t maj, min; int present = 0; bool ret = false; maj = gss_import_name(&min, &ba_user, GSS_C_NT_USER_NAME, &user); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "In Basic Auth, %s", mag_error(req, "gss_import_name() failed", maj, min)); goto done; } if (cfg->basic_mechs) { allowed_mechs = cfg->basic_mechs; } else if (cfg->allowed_mechs) { allowed_mechs = cfg->allowed_mechs; } else { struct mag_server_config *scfg; /* Try to fetch the default set if not explicitly configured, * We need to do this because gss_acquire_cred_with_password() * is currently limited to acquire creds for a single "default" * mechanism if no desired mechanisms are passed in. This causes * authentication to fail for secondary mechanisms as no user * credentials are generated for those. */ scfg = ap_get_module_config(req->server->module_config, &auth_gssapi_module); /* In the worst case scenario default_mechs equals to GSS_C_NO_OID_SET. * This generally causes only the krb5 mechanism to be tried due * to implementation constraints, but may change in future. */ allowed_mechs = scfg->default_mechs; } /* Remove Spnego if present, or we'd repeat failed authentiations * multiple times, one within Spnego and then again with an explicit * mechanism. We would normally just force Spnego and use * gss_set_neg_mechs, but due to the way we source the server name * and the fact MIT up to 1.14 at least does no handle union names, * we can't provide spnego with a server name that can be used by * multiple mechanisms, causing any but the first mechanism to fail. * Also remove unwanted krb mechs, or AS requests will be repeated * multiple times uselessly. */ filtered_mechs = mag_filter_unwanted_mechs(allowed_mechs); if (filtered_mechs == allowed_mechs) { /* in case filtered_mechs was not allocated here don't free it */ filtered_mechs = GSS_C_NO_OID_SET; } else if (filtered_mechs == GSS_C_NO_OID_SET) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, req, "Fatal " "failure while filtering mechs, aborting"); goto done; } else { /* use the filtered list */ allowed_mechs = filtered_mechs; } #ifdef HAVE_GSS_KRB5_CCACHE_NAME /* If we are using the krb5 mechanism make sure to set a per thread * memory ccache so that there can't be interferences between threads. * Also make sure we have new cache so no cached results end up being * used. Some implementations of gss_acquire_cred_with_password() do * not reacquire creds if cached ones are around, failing to check * again for the password. */ maj = gss_test_oid_set_member(&min, discard_const(gss_mech_krb5), allowed_mechs, &present); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "In Basic Auth, %s", mag_error(req, "gss_test_oid_set_member() failed", maj, min)); goto done; } if (present) { rs = apr_generate_random_bytes((unsigned char *)(&rndname), sizeof(long long unsigned int)); if (rs != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "Failed to generate random ccache name"); goto done; } user_ccache = apr_psprintf(req->pool, "MEMORY:user_%qu", rndname); maj = gss_krb5_ccache_name(&min, user_ccache, &orig_ccache); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "In Basic Auth, %s", mag_error(req, "gss_krb5_ccache_name() " "failed", maj, min)); goto done; } } #endif maj = gss_acquire_cred_with_password(&min, user, &ba_pwd, GSS_C_INDEFINITE, allowed_mechs, GSS_C_INITIATE, &user_cred, &actual_mechs, NULL); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "In Basic Auth, %s", mag_error(req, "gss_acquire_cred_with_password() " "failed", maj, min)); goto done; } /* must acquire creds based on the actual mechs we want to try */ if (!mag_acquire_creds(req, cfg, actual_mechs, GSS_C_ACCEPT, &server_cred, NULL)) { goto done; } #ifdef HAVE_CRED_STORE if (cfg->deleg_ccache_dir) { /* delegate ourselves credentials so we store them as requested */ init_flags |= GSS_C_DELEG_FLAG; } #endif for (int i = 0; i < actual_mechs->count; i++) { /* free these if looping */ gss_release_buffer(&min, &output); gss_release_buffer(&min, &input); gss_release_name(&min, &server); maj = gss_inquire_cred_by_mech(&min, server_cred, &actual_mechs->elements[i], &server, NULL, NULL, NULL); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", mag_error(req, "gss_inquired_cred_by_mech() " "failed", maj, min)); continue; } do { /* output and input are inverted here, this is intentional */ maj = gss_init_sec_context(&min, user_cred, &user_ctx, server, &actual_mechs->elements[i], init_flags, 300, GSS_C_NO_CHANNEL_BINDINGS, &output, NULL, &input, NULL, NULL); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", mag_error(req, "gss_init_sec_context() " "failed", maj, min)); break; } gss_release_buffer(&min, &output); maj = gss_accept_sec_context(&min, &server_ctx, server_cred, &input, GSS_C_NO_CHANNEL_BINDINGS, client, mech_type, &output, NULL, vtime, delegated_cred); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", mag_error(req, "gss_accept_sec_context()" " failed", maj, min)); break; } gss_release_buffer(&min, &input); } while (maj == GSS_S_CONTINUE_NEEDED); if (maj == GSS_S_COMPLETE) { ret = true; break; } } done: gss_release_buffer(&min, &output); gss_release_buffer(&min, &input); gss_release_name(&min, &server); gss_delete_sec_context(&min, &server_ctx, GSS_C_NO_BUFFER); gss_release_cred(&min, &server_cred); gss_release_name(&min, &user); gss_release_cred(&min, &user_cred); gss_delete_sec_context(&min, &user_ctx, GSS_C_NO_BUFFER); gss_release_oid_set(&min, &actual_mechs); gss_release_oid_set(&min, &filtered_mechs); #ifdef HAVE_GSS_KRB5_CCACHE_NAME if (user_ccache != NULL) { maj = gss_krb5_ccache_name(&min, orig_ccache, NULL); if (maj != GSS_S_COMPLETE) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "Failed to restore per-thread ccache, %s", mag_error(req, "gss_krb5_ccache_name() " "failed", maj, min)); } } #endif return ret; }
/* * Make a password record from the given information. A zero return * indicates success; on failure, ctx->errstr points to the error message. */ int mkhash(struct passwd_ctx *ctx) { char *pw; char pwin[MAX_STRING_LEN]; char salt[16]; apr_status_t rv; int ret = 0; #if CRYPT_ALGO_SUPPORTED char *cbuf; #endif if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT) { apr_file_printf(errfile, "Warning: Ignoring -C argument for this algorithm." NL); } if (ctx->passwd != NULL) { pw = ctx->passwd; } else { if ((ret = get_password(ctx)) != 0) return ret; pw = pwin; } switch (ctx->alg) { case ALG_APSHA: /* XXX out >= 28 + strlen(sha1) chars - fixed len SHA */ apr_sha1_base64(pw, strlen(pw), ctx->out); break; case ALG_APMD5: ret = generate_salt(salt, 8, &ctx->errstr, ctx->pool); if (ret != 0) break; rv = apr_md5_encode(pw, salt, ctx->out, ctx->out_len); if (rv != APR_SUCCESS) { ctx->errstr = apr_psprintf(ctx->pool, "could not encode password: %pm", &rv); ret = ERR_GENERAL; } break; case ALG_PLAIN: /* XXX this len limitation is not in sync with any HTTPd len. */ apr_cpystrn(ctx->out, pw, ctx->out_len); break; #if CRYPT_ALGO_SUPPORTED case ALG_CRYPT: ret = generate_salt(salt, 8, &ctx->errstr, ctx->pool); if (ret != 0) break; cbuf = crypt(pw, salt); if (cbuf == NULL) { rv = APR_FROM_OS_ERROR(errno); ctx->errstr = apr_psprintf(ctx->pool, "crypt() failed: %pm", &rv); ret = ERR_PWMISMATCH; break; } apr_cpystrn(ctx->out, cbuf, ctx->out_len - 1); if (strlen(pw) > 8) { char *truncpw = strdup(pw); truncpw[8] = '\0'; if (!strcmp(ctx->out, crypt(truncpw, salt))) { apr_file_printf(errfile, "Warning: Password truncated to 8 " "characters by CRYPT algorithm." NL); } memset(truncpw, '\0', strlen(pw)); free(truncpw); } break; #endif /* CRYPT_ALGO_SUPPORTED */ #if BCRYPT_ALGO_SUPPORTED case ALG_BCRYPT: rv = apr_generate_random_bytes((unsigned char*)salt, 16); if (rv != APR_SUCCESS) { ctx->errstr = apr_psprintf(ctx->pool, "Unable to generate random " "bytes: %pm", &rv); ret = ERR_RANDOM; break; } if (ctx->cost == 0) ctx->cost = BCRYPT_DEFAULT_COST; rv = apr_bcrypt_encode(pw, ctx->cost, (unsigned char*)salt, 16, ctx->out, ctx->out_len); if (rv != APR_SUCCESS) { ctx->errstr = apr_psprintf(ctx->pool, "Unable to encode with " "bcrypt: %pm", &rv); ret = ERR_PWMISMATCH; break; } break; #endif /* BCRYPT_ALGO_SUPPORTED */ default: apr_file_printf(errfile, "mkhash(): BUG: invalid algorithm %d", ctx->alg); abort(); } memset(pw, '\0', strlen(pw)); return ret; }
static ngx_http_modsecurity_ctx_t * ngx_http_modsecurity_create_ctx(ngx_http_request_t *r) { ngx_http_modsecurity_loc_conf_t *cf; ngx_pool_cleanup_t *cln; ngx_http_modsecurity_ctx_t *ctx; apr_sockaddr_t *asa; struct sockaddr_in *sin; char *txid; unsigned char salt[TXID_SIZE]; int i; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_modsecurity_ctx_t)); if (ctx == NULL) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "modSecurity: ctx memory allocation error"); return NULL; } cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_modsecurity_ctx_t)); if (cln == NULL) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "modSecurity: ctx memory allocation error"); return NULL; } cln->handler = ngx_http_modsecurity_cleanup; cln->data = ctx; ctx->r = r; if (r->connection->requests == 0 || ctx->connection == NULL) { /* TODO: set server_rec, why igonre return value? */ ctx->connection = modsecNewConnection(); /* fill apr_sockaddr_t */ asa = ngx_palloc(r->pool, sizeof(apr_sockaddr_t)); asa->pool = ctx->connection->pool; asa->hostname = (char *)ngx_pstrdup0(r->pool, &r->connection->addr_text); asa->servname = asa->hostname; asa->next = NULL; asa->salen = r->connection->socklen; ngx_memcpy(&asa->sa, r->connection->sockaddr, asa->salen); asa->family = ((struct sockaddr *)&asa->sa)->sa_family; switch ( asa->family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *)&asa->sa; asa->ipaddr_ptr = &sin6->sin6_addr; asa->ipaddr_len = sizeof(sin6->sin6_addr); asa->port = ntohs(sin6->sin6_port); asa->addr_str_len = NGX_INET6_ADDRSTRLEN + 1; break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) &asa->sa; asa->ipaddr_ptr = &sin->sin_addr; asa->ipaddr_len = sizeof(sin->sin_addr); asa->port = ntohs(sin->sin_port); asa->addr_str_len = NGX_INET_ADDRSTRLEN + 1; break; } #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3 ctx->connection->remote_addr = asa; ctx->connection->remote_ip = asa->hostname; #else ctx->connection->client_addr = asa; ctx->connection->client_ip = asa->hostname; #endif ctx->connection->remote_host = NULL; modsecProcessConnection(ctx->connection); } cf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity); ctx->req = modsecNewRequest(ctx->connection, cf->config); apr_table_setn(ctx->req->notes, NOTE_NGINX_REQUEST_CTX, (const char *) ctx); apr_generate_random_bytes(salt, TXID_SIZE); txid = apr_pcalloc (ctx->req->pool, TXID_SIZE); apr_base64_encode (txid, (const char*)salt, TXID_SIZE); for(i=0;i<TXID_SIZE;i++) { if((salt[i] >= 0x30) && (salt[i] <= 0x39)) {} else if((salt[i] >= 0x40) && (salt[i] <= 0x5A)) {} else if((salt[i] >= 0x61) && (salt[i] <= 0x7A)) {} else { if((i%2)==0) salt[i] = 0x41; else salt[i] = 0x63; } } salt[TXID_SIZE-1] = '\0'; apr_table_setn(ctx->req->subprocess_env, "UNIQUE_ID", apr_psprintf(ctx->req->pool, "%s", salt)); ctx->brigade = apr_brigade_create(ctx->req->pool, ctx->req->connection->bucket_alloc); if (ctx->brigade == NULL) { return NULL; } return ctx; }