bud_error_t bud_config_drop_privileges(bud_config_t* config) { #ifndef _WIN32 if (config->user != NULL) { struct passwd* p; p = getpwnam(config->user); if (p == NULL) return bud_error_dstr(kBudErrInvalidUser, config->user); if (setgid(p->pw_gid) != 0) return bud_error_num(kBudErrSetgid, errno); if (setuid(p->pw_uid) != 0) return bud_error_num(kBudErrSetuid, errno); } else if (config->group != NULL) { struct group* g; g = getgrnam(config->group); if (g == NULL) return bud_error_dstr(kBudErrInvalidGroup, config->group); if (setgid(g->gr_gid) != 0) return bud_error_num(kBudErrSetgid, errno); } #endif /* !_WIN32 */ return bud_ok(); }
bud_error_t bud_config_load_backend(bud_config_t* config, JSON_Object* obj, bud_config_backend_t* backend, bud_hashmap_t* map, unsigned int* ext_count) { bud_error_t err; JSON_Value* val; const char* external; int r; bud_config_load_addr(obj, (bud_config_addr_t*) backend); backend->config = config; backend->xforward = -1; val = json_object_get_value(obj, "proxyline"); if (json_value_get_type(val) == JSONString) { const char* pline; pline = json_value_get_string(val); if (strcmp(pline, "haproxy") == 0) backend->proxyline = kBudProxylineHAProxy; else if (strcmp(pline, "json") == 0) backend->proxyline = kBudProxylineJSON; else return bud_error_dstr(kBudErrProxyline, pline); } else { backend->proxyline = val != NULL && json_value_get_boolean(val) ? kBudProxylineHAProxy : kBudProxylineNone; } val = json_object_get_value(obj, "x-forward"); if (val != NULL) backend->xforward = json_value_get_boolean(val); /* Set defaults here to use them in sni.c */ bud_config_set_backend_defaults(backend); r = bud_config_str_to_addr(backend->host, backend->port, &backend->addr); if (r != 0) return bud_error_num(kBudErrPton, r); external = json_object_get_string(obj, "external"); if (external == NULL) return bud_ok(); /* Insert backend into a hashmap */ err = bud_hashmap_insert(map, external, strlen(external), backend); if (!bud_is_ok(err)) return err; (*ext_count)++; return bud_ok(); }
bud_error_t bud_config_load_ca_file(X509_STORE** store, const char* filename) { BIO* b; X509* x509; bud_error_t err; b = BIO_new_file(filename, "r"); if (b == NULL) return bud_error_dstr(kBudErrLoadCert, filename); x509 = NULL; *store = X509_STORE_new(); if (*store == NULL) { err = bud_error_dstr(kBudErrNoMem, "CA store"); goto fatal; } while ((x509 = PEM_read_bio_X509(b, NULL, NULL, NULL)) != NULL) { if (x509 == NULL) { err = bud_error_dstr(kBudErrParseCert, filename); goto fatal; } if (X509_STORE_add_cert(*store, x509) != 1) { err = bud_error(kBudErrAddCert); goto fatal; } X509_free(x509); x509 = NULL; } err = bud_ok(); fatal: if (x509 != NULL) X509_free(x509); BIO_free_all(b); return bud_ok(); }
bud_error_t bud_config_verify_all_strings(const JSON_Array* arr, const char* name) { int i; int count; if (arr == NULL) return bud_ok(); count = json_array_get_count(arr); for (i = 0; i < count; i++) { if (json_value_get_type(json_array_get_value(arr, i)) == JSONString) continue; return bud_error_dstr(kBudErrNonString, name); } return bud_ok(); }
bud_error_t bud_config_load_ca_arr(X509_STORE** store, const JSON_Array* ca) { int i; int count; bud_error_t err; err = bud_config_verify_all_strings(ca, "ca"); if (!bud_is_ok(err)) return err; *store = X509_STORE_new(); if (*store == NULL) return bud_error_str(kBudErrNoMem, "CA store"); count = json_array_get_count(ca); for (i = 0; i < count; i++) { const char* cert; BIO* b; X509* x509; cert = json_array_get_string(ca, i); b = BIO_new_mem_buf((void*) cert, -1); if (b == NULL) return bud_error_str(kBudErrNoMem, "BIO_new_mem_buf:CA store bio"); while ((x509 = PEM_read_bio_X509(b, NULL, NULL, NULL)) != NULL) { if (x509 == NULL) { err = bud_error_dstr(kBudErrParseCert, cert); break; } if (X509_STORE_add_cert(*store, x509) != 1) { err = bud_error(kBudErrAddCert); break; } X509_free(x509); x509 = NULL; } BIO_free_all(b); if (x509 != NULL) X509_free(x509); } return err; }
bud_error_t bud_config_load(bud_config_t* config) { int i; bud_error_t err; JSON_Value* json; JSON_Value* val; JSON_Object* frontend; JSON_Object* obj; JSON_Object* log; JSON_Object* avail; JSON_Array* contexts; if (config->piped) { char* content; ASSERT(config->loop != NULL, "Loop should be present"); err = bud_read_file_by_fd(config->loop, 0, &content); if (!bud_is_ok(err)) goto end; err = bud_hashmap_insert(&config->files.hashmap, kPipedConfigPath, strlen(kPipedConfigPath), content); if (!bud_is_ok(err)) { free(content); goto end; } json = json_parse_string(content); } else if (config->inlined) { json = json_parse_string(config->path); } else { const char* contents; err = bud_config_load_file(config, config->path, &contents); if (!bud_is_ok(err)) goto end; json = json_parse_string(contents); } if (json == NULL) { err = bud_error_dstr(kBudErrJSONParse, config->path); goto end; } obj = json_value_get_object(json); if (obj == NULL) { err = bud_error(kBudErrJSONNonObjectRoot); goto failed_alloc_path; } err = bud_config_load_tracing(&config->trace, json_object_get_object(obj, "tracing")); if (!bud_is_ok(err)) goto failed_alloc_path; /* Allocate contexts and backends */ contexts = json_object_get_array(obj, "contexts"); config->context_count = contexts == NULL ? 0 : json_array_get_count(contexts); config->contexts = calloc(config->context_count + 1, sizeof(*config->contexts)); if (config->contexts == NULL) { err = bud_error_str(kBudErrNoMem, "bud_context_t"); goto failed_alloc_contexts; } config->json = json; /* Workers configuration */ config->worker_count = -1; config->restart_timeout = -1; config->master_ipc = -1; val = json_object_get_value(obj, "workers"); if (val != NULL) config->worker_count = json_value_get_number(val); val = json_object_get_value(obj, "restart_timeout"); if (val != NULL) config->restart_timeout = json_value_get_number(val); val = json_object_get_value(obj, "master_ipc"); if (val != NULL) config->master_ipc = json_value_get_boolean(val); /* Logger configuration */ log = json_object_get_object(obj, "log"); config->log.stdio = -1; config->log.syslog = -1; if (log != NULL) { config->log.level = json_object_get_string(log, "level"); config->log.facility = json_object_get_string(log, "facility"); val = json_object_get_value(log, "stdio"); if (val != NULL) config->log.stdio = json_value_get_boolean(val); val = json_object_get_value(log, "syslog"); if (val != NULL) config->log.syslog = json_value_get_boolean(val); } /* Availability configuration */ avail = json_object_get_object(obj, "availability"); config->availability.death_timeout = -1; config->availability.revive_interval = -1; config->availability.retry_interval = -1; config->availability.max_retries = -1; if (avail != NULL) { val = json_object_get_value(avail, "death_timeout"); if (val != NULL) config->availability.death_timeout = json_value_get_number(val); val = json_object_get_value(avail, "revive_interval"); if (val != NULL) config->availability.revive_interval = json_value_get_number(val); val = json_object_get_value(avail, "retry_interval"); if (val != NULL) config->availability.retry_interval = json_value_get_number(val); val = json_object_get_value(avail, "max_retries"); if (val != NULL) config->availability.max_retries = json_value_get_number(val); } /* Frontend configuration */ frontend = json_object_get_object(obj, "frontend"); err = bud_config_load_frontend(frontend, &config->frontend); if (!bud_is_ok(err)) goto failed_alloc_contexts; /* Load frontend's context */ err = bud_context_load(frontend, &config->contexts[0]); if (!bud_is_ok(err)) goto failed_alloc_contexts; /* Backend configuration */ config->balance = json_object_get_string(obj, "balance"); err = bud_config_load_backend_list(config, obj, &config->contexts[0].backend); if (!bud_is_ok(err)) goto failed_alloc_contexts; /* User and group configuration */ config->user = json_object_get_string(obj, "user"); config->group = json_object_get_string(obj, "group"); /* SNI configuration */ bud_config_read_pool_conf(obj, "sni", &config->sni); /* OCSP Stapling configuration */ bud_config_read_pool_conf(obj, "stapling", &config->stapling); /* SSL Contexts */ /* TODO(indutny): sort them and do binary search */ for (i = 0; i < config->context_count; i++) { bud_context_t* ctx; /* NOTE: contexts[0] - is a default context */ ctx = &config->contexts[i + 1]; obj = json_array_get_object(contexts, i); if (obj == NULL) { err = bud_error(kBudErrJSONNonObjectCtx); goto failed_load_context; } err = bud_context_load(obj, ctx); if (!bud_is_ok(err)) goto failed_load_context; err = bud_config_load_backend_list(config, obj, &ctx->backend); if (!bud_is_ok(err)) goto failed_load_context; } bud_config_set_defaults(config); return bud_config_init(config); failed_load_context: /* Deinitalize contexts */ for (i++; i >= 0; i--) { bud_context_t* ctx; ctx = &config->contexts[i]; free(ctx->backend.list); ctx->backend.list = NULL; } failed_alloc_contexts: free(config->contexts); config->contexts = NULL; free(config->trace.dso); config->trace.dso = NULL; failed_alloc_path: json_value_free(json); config->json = NULL; end: return err; }