int drop_privileges(wkr_t *w, scgi_t *scgi) { char *str; str = (char*) scgi_header_value_get(scgi, "USER"); if(str && strlen(str) > 0) { struct passwd *user_info=NULL; user_info = getpwnam(str); // Check for user existence if(user_info) { w->tmp->uid = user_info->pw_uid; w->tmp->gid = user_info->pw_gid; } else { scgi_body_add(w->ctl->scgi, "Application run_as_user is invalid. Application not started.", strlen("Application run_as_user is invalid. Application not started.")); LOG_ERROR(SEVERE,"Application run_as_user is invalid. Application not started."); return FALSE; } } else { scgi_body_add(w->ctl->scgi, "Application run_as_user is missing. Application not started.", strlen("Application run_as_user is missing. Application not started.")); LOG_ERROR(SEVERE,"Application run_as_user is missing. Application not started."); return FALSE; } change_log_file_owner(w->tmp->uid, w->tmp->gid); //setting read, effective, saved group and user id if(setgid(w->tmp->gid)!=0) { scgi_body_add(w->ctl->scgi, "setegid() failed", strlen("setegid() failed")); LOG_ERROR(SEVERE,"setegid() failed"); return FALSE; } if(setuid(w->tmp->uid)!=0) { scgi_body_add(w->ctl->scgi, "seteuid() failed", strlen("seteuid() failed")); LOG_ERROR(SEVERE,"seteuid() failed"); return FALSE; } LOG_DEBUG(DEBUG,"Passed userid=%d and groupid=%d", w->tmp->uid, w->tmp->gid); LOG_DEBUG(DEBUG,"effective userid=%d and groupid=%d",geteuid(),getegid()); #ifdef __linux__ int rv = prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); LOG_DEBUG(DEBUG,"prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) = %d", rv); if (rv < 0) { LOG_ERROR(SEVERE,"error setting prctl(PR_SET_DUMPABLE, 1, 0, 0, 0), errno = %d, desc = %s", errno, strerror(errno)); } #endif return TRUE; }
void manipulate_environment_variable(wkr_t* w, scgi_t *scgi) { LOG_FUNCTION char *var, *str; int rv = 0; str = (char*) scgi_header_value_get(scgi, "ENV_VAR"); w->env_var = wr_string_list_new(); if(str){ var = strtok(str,"#"); while(var){ LOG_DEBUG(DEBUG,"Environment variable string = %s", var); wr_string_list_add(w->env_var, var, strlen(var)); // TODO: see the security concerns rv = putenv(w->env_var->rear->str.str); if (rv != 0) { LOG_ERROR(WARN, "putenv() failed, errno = %d, description = %s", errno, strerror(errno)); } var = strtok(NULL,"#"); } } }
/** Reads the response from worker, deserialize it, render it to the Request. */ static void wr_resp_len_read_cb(struct ev_loop *loop, struct ev_io *w, int revents) { LOG_FUNCTION wr_req_t* req = (wr_req_t*) w->data; wr_wkr_t *worker = req->wkr; ssize_t read; LOG_DEBUG(DEBUG,"Request %d",req->id); if(!(revents & EV_READ)) return; read = recv(w->fd, req->resp_buf + req->bytes_received, WR_RESP_BUF_SIZE - req->bytes_received, 0); if(read <= 0) { ev_io_stop(loop,w); LOG_ERROR(WARN,"Error reading response:%s",strerror(errno)); worker->state += (WR_WKR_ERROR + WR_WKR_HANG); wr_ctl_free(worker->ctl); return; } req->bytes_received =+ read; //worker responding LOG_DEBUG(DEBUG,"Idle watcher reset for worker %d", worker->id); LOG_DEBUG(DEBUG,"bytes read = %d", req->bytes_received); scgi_t* scgi = scgi_parse(req->resp_buf, req->bytes_received); if(scgi) { ev_io_stop(loop,w); const char *value = scgi_header_value_get(scgi, SCGI_CONTENT_LENGTH); // Set response length if(value) req->resp_buf_len = atoi(value); else req->resp_buf_len = 0; // Set rsponse code value = scgi_header_value_get(scgi, RESP_CODE); if(value) req->resp_code = atoi(value); else req->resp_code = 0; // Set content length value = scgi_header_value_get(scgi, RESP_CONTENT_LENGTH); if(value) req->resp_body_len = atoi(value); else req->resp_body_len = 0; LOG_DEBUG(DEBUG,"resp_code = %d, content len = %d, resp len = %d", req->resp_code, req->resp_body_len, req->resp_buf_len); // Response length should be greater than 0 if(req->resp_buf_len == 0) { //TODO: Render 500 Internal Error, close Request, allocate worker to next Request LOG_ERROR(WARN,"Got response len 0"); ev_io_stop(loop,w); worker->state += (WR_WKR_ERROR + WR_WKR_HANG); wr_ctl_free(worker->ctl); return; } if(!req->conn_err && req->app && req->app->svr->conf->server->flag & WR_SVR_ACCESS_LOG) { wr_access_log(req); } scgi_free(req->scgi); req->scgi = NULL; req->bytes_received = scgi->body_length; LOG_DEBUG(DEBUG,"wr_resp_len_read_cb() bytes read = %d", req->bytes_received); if(req->bytes_received > 0 && !req->conn_err) { wr_conn_resp_body_add(req->conn, scgi->body, scgi->body_length); } scgi_free(scgi); // Check for response length if(req->resp_buf_len == req->bytes_received) { LOG_DEBUG(DEBUG,"Idle watcher stopped for worker %d", worker->id); // worker is done with current Request worker->req = NULL; req->using_wkr = FALSE; worker->state &= (~224); ev_timer_stop(worker->loop,&worker->t_wait); // Close Request once complete response read wr_wkr_release(req); } else { LOG_DEBUG(DEBUG,"wr_resp_len_read_cb() Request %d, read %d/%d", req->id, req->bytes_received, req->resp_buf_len); ev_io_init(w,wr_resp_read_cb, w->fd,EV_READ); ev_io_start(loop,w); wr_wait_watcher_start(worker); } } }
void application_config_read_cb(wkr_t* w, scgi_t *scgi){ LOG_FUNCTION char *str; /*w->ctl->scgi = scgi_new(); if(w->ctl->scgi == NULL) { LOG_ERROR(SEVERE,"Cannot create SCGI Request"); sigproc(); return; } */ if(w->tmp->is_static){ #ifdef W_ZLIB str = (char*) scgi_header_value_get(scgi, "LOWER_LIMIT"); if(str){ w->tmp->lower_limit = atol(str); } str = (char*) scgi_header_value_get(scgi, "UPPER_LIMIT"); if(str){ w->tmp->upper_limit = atol(str); } #ifdef W_REGEX str = (char*) scgi_header_value_get(scgi, "CONTENT_TYPE"); if(str){ wr_string_new(w->tmp->r_content_type, str, strlen(str)); }else { wr_string_new(w->tmp->r_content_type, DEFAULT_CONTENT_TYPE, strlen(DEFAULT_CONTENT_TYPE)); } str = (char*) scgi_header_value_get(scgi, "USER_AGENT"); if(str){ wr_string_new(w->tmp->r_user_agent, str, strlen(str)); } #endif #endif }else{ if(drop_privileges(w, scgi) == FALSE) { wkr_tmp_free(&w->tmp); sigproc(); return; } manipulate_environment_variable(w, scgi); str = (char*) scgi_header_value_get(scgi, "PATH"); if(str){ wr_string_new(w->tmp->path, str, strlen(str)); } str = (char*) scgi_header_value_get(scgi, "ENV"); if(str){ wr_string_new(w->tmp->env, str, strlen(str)); } str = (char*) scgi_header_value_get(scgi, "TYPE"); if(str){ wr_string_new(w->tmp->type, str, strlen(str)); } str = (char*) scgi_header_value_get(scgi, "BASE_URI"); if(str){ wr_string_new(w->tmp->resolver, str, strlen(str)); } str = (char*) scgi_header_value_get(scgi, "ANALYTICS"); if(str && strcmp(str,"enabled")==0){ w->tmp->profiler = 'y'; }else{ w->tmp->profiler = 'n'; } } load_application(w); }
wr_ctl_msg_t* wr_ctl_msg_validate(scgi_t* request, wr_ctl_t* ctl) { LOG_FUNCTION wr_ctl_msg_t* ctl_msg = wr_malloc(wr_ctl_msg_t); char *val; char error[STR_SIZE64]; ctl->type = WR_CTL_MSG_NONE; ctl->scgi = scgi_new(); val = (char*) scgi_header_value_get(request,"COMPONENT"); if(val == NULL) { memcpy(error,"COMPONENT missing.", strlen("COMPONENT missing.")+1); goto ctl_msg_err; } scgi_header_add(ctl->scgi, "COMPONENT", strlen("COMPONENT"), val, strlen(val)); if(strcmp(val,"APPLICATION")==0) { val = (char*) scgi_header_value_get(request,"METHOD"); if(val == NULL) { memcpy(error,"METHOD missing.", strlen("METHOD missing.")+1); goto ctl_msg_err; } scgi_header_add(ctl->scgi, "METHOD", strlen("METHOD"), val, strlen(val)); ctl_msg->msg.app.app_name.str = (char*) scgi_header_value_get(request,"APP_NAME"); if(ctl_msg->msg.app.app_name.str) ctl_msg->msg.app.app_name.len = strlen(ctl_msg->msg.app.app_name.str); if(ctl_msg->msg.app.app_name.str == NULL) { memcpy(error,"Application name is missing.", strlen("Application name is missing.")+1); goto ctl_msg_err; } // Application Add if(strcmp(val,"ADD")==0) { ctl->type = WR_CTL_MSG_APPLICATION_ADD; } else if(strcmp(val,"REMOVE")==0) { ctl->type = WR_CTL_MSG_APPLICATION_REMOVE; } else if(strcmp(val,"RELOAD")==0) { ctl->type = WR_CTL_MSG_APPLICATION_RELOAD; }else { memcpy(error, "Invalid METHOD.", strlen("Invalid METHOD.")+1); goto ctl_msg_err; } } else if(strcmp(val,"WORKER")==0) { val = (char*) scgi_header_value_get(request,"METHOD"); if(val == NULL) { memcpy(error, "METHOD missing.", strlen("METHOD missing.")+1); goto ctl_msg_err; } if(strcmp(val,"ERROR")==0) { scgi_header_add(ctl->scgi, "METHOD", strlen("METHOD"), "ACK", strlen("ACK")); }else{ scgi_header_add(ctl->scgi, "METHOD", strlen("METHOD"), val, strlen(val)); } // Worker Add if(strcmp(val,"ADD")==0) { ctl->type = WR_CTL_MSG_WORKER_ADD; ctl_msg->msg.wkr.app_name.str = (char*) scgi_header_value_get(request,"APPLICATION"); if(ctl_msg->msg.wkr.app_name.str) ctl_msg->msg.wkr.app_name.len = strlen(ctl_msg->msg.wkr.app_name.str); ctl_msg->msg.wkr.pid.str = (char*) scgi_header_value_get(request,"PID"); if(ctl_msg->msg.wkr.pid.str) ctl_msg->msg.wkr.pid.len = strlen(ctl_msg->msg.wkr.pid.str); ctl_msg->msg.wkr.port.str = (char*) scgi_header_value_get(request,"PORT"); if(ctl_msg->msg.wkr.port.str) ctl_msg->msg.wkr.port.len = strlen(ctl_msg->msg.wkr.port.str); ctl_msg->msg.wkr.sock_path.str = (char*) scgi_header_value_get(request,"SOCK_PATH"); if(ctl_msg->msg.wkr.sock_path.str) ctl_msg->msg.wkr.sock_path.len = strlen(ctl_msg->msg.wkr.sock_path.str); ctl_msg->msg.wkr.uds.str = (char*) scgi_header_value_get(request,"UDS"); if(ctl_msg->msg.wkr.uds.str) ctl_msg->msg.wkr.uds.len = strlen(ctl_msg->msg.wkr.uds.str); if(ctl_msg->msg.wkr.app_name.str == NULL || ctl_msg->msg.wkr.pid.str == NULL || ctl_msg->msg.wkr.uds.str == NULL) { memcpy(error, "Missing some headers.", strlen("Missing some headers.")+1); goto ctl_msg_err; } } else if(strcmp(val,"REMOVE")==0) { ctl->type = WR_CTL_MSG_WORKER_REMOVE; } else if(strcmp(val,"PING") == 0) { ctl->type = WR_CTL_MSG_WORKER_PING; } else if(strcmp(val,"CONF_REQ") == 0){ ctl->type = WR_CTL_MSG_WORKER_CONF_REQ; ctl_msg->msg.wkr.app_name.str = (char*) scgi_header_value_get(request,"APPLICATION"); if(ctl_msg->msg.wkr.app_name.str) ctl_msg->msg.wkr.app_name.len = strlen(ctl_msg->msg.wkr.app_name.str); } else if(strcmp(val,"ERROR") == 0) { ctl->type = WR_CTL_MSG_WORKER_ADD_ERROR; ctl_msg->msg.wkr.app_name.str = (char*) scgi_header_value_get(request,"APPLICATION"); if(ctl_msg->msg.wkr.app_name.str) ctl_msg->msg.wkr.app_name.len = strlen(ctl_msg->msg.wkr.app_name.str); ctl_msg->msg.wkr.pid.str = (char*) scgi_header_value_get(request,"PID"); if(ctl_msg->msg.wkr.pid.str) ctl_msg->msg.wkr.pid.len = strlen(ctl_msg->msg.wkr.pid.str); ctl_msg->msg.wkr.port.str = (char*) scgi_header_value_get(request,"PORT"); if(ctl_msg->msg.wkr.port.str) ctl_msg->msg.wkr.port.len = strlen(ctl_msg->msg.wkr.port.str); ctl_msg->msg.wkr.sock_path.str = (char*) scgi_header_value_get(request,"SOCK_PATH"); if(ctl_msg->msg.wkr.sock_path.str) ctl_msg->msg.wkr.sock_path.len = strlen(ctl_msg->msg.wkr.sock_path.str); ctl_msg->msg.wkr.uds.str = (char*) scgi_header_value_get(request,"UDS"); if(ctl_msg->msg.wkr.uds.str) ctl_msg->msg.wkr.uds.len = strlen(ctl_msg->msg.wkr.uds.str); if(ctl_msg->msg.wkr.app_name.str == NULL || ctl_msg->msg.wkr.pid.str == NULL || ctl_msg->msg.wkr.uds.str == NULL) { memcpy(error, "Missing some headers.", strlen("Missing some headers.")+1); goto ctl_msg_err; } }else { memcpy(error,"Invalid METHOD.", strlen("Invalid METHOD.")+1); goto ctl_msg_err; } } else { memcpy(error,"Invalid COMPONENT.", strlen("Invalid COMPONENT.")+1); goto ctl_msg_err; } return ctl_msg; ctl_msg_err: LOG_ERROR(WARN,"Error found in controller message"); ctl->type = WR_CTL_MSG_TYPE_ERROR; scgi_body_add(ctl->scgi, error, strlen(error)); scgi_header_add(ctl->scgi, "STATUS", strlen("STATUS"), "ERROR", strlen("ERROR")); return ctl_msg; }