UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2013 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 30 #ifdef __gnu_linux__ 31 #define _GNU_SOURCE 32 #endif 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <dlfcn.h> 37 #include <grp.h> 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 41 #include <openssl/bio.h> 42 #include <openssl/ssl.h> 43 #include <openssl/err.h> 44 45 #include "../public/nsapi.h" 46 #include "../public/auth.h" 47 #include "../util/systhr.h" 48 #include "../util/pblock.h" 49 #include "../util/util.h" 50 51 #include <cx/utils.h> 52 #include <cx/printf.h> 53 #include <cx/compare.h> 54 55 #include "../safs/common.h" 56 57 #include "func.h" 58 #include "config.h" 59 #include "configmanager.h" 60 #include "httplistener.h" 61 #include "webserver.h" 62 #include "auth.h" 63 #include "srvctrl.h" 64 #include "resourcepool.h" 65 #include "ldap_resource.h" 66 67 extern struct FuncStruct webserver_funcs[]; 68 69 static RestartCallback *atrestart; 70 71 int webserver_init() { 72 // init NSPR 73 systhread_init("webserver"); 74 75 log_ereport(LOG_VERBOSE, "webserver_init"); 76 77 // init ssl 78 if(ws_init_ssl()) { 79 log_ereport(LOG_FAILURE, "ssl init failed"); 80 return -1; 81 } 82 83 // init listener socket map 84 if(http_listener_global_init()) { 85 log_ereport(LOG_FAILURE, "listener global init failed"); 86 return -1; 87 } 88 89 // init NSAPI functions 90 pblock_init_default_keys(); 91 atexit(pblock_free_default_keys); 92 func_init(); 93 add_functions(webserver_funcs); 94 95 // init resource pools 96 if(init_resource_pools()) { 97 log_ereport(LOG_FAILURE, "resource pool init failed"); 98 return -1; 99 } 100 if(resourcepool_register_type("ldap", ldap_get_resource_type())) { 101 log_ereport(LOG_FAILURE, "webserver-init: Cannot register ldap resourcepool type"); 102 return -1; 103 } 104 105 // load init.conf 106 InitConfig *init_config = load_init_conf("config/init.conf"); 107 if(!init_config) { 108 return -1; 109 } 110 111 // load server.conf 112 // Only the runtime infos are stored in the ServerConfiguration at 113 // this stage. The remaining configuration is loaded after the uid 114 // is changed (if needed). 115 init_configuration_manager(); 116 CfgManager mgr; 117 if(cfgmgr_load_config(&mgr) != 0) { 118 return 1; 119 } 120 log_ereport(LOG_VERBOSE, "cfgmgr_load_config stage 1 successful"); 121 ServerConfiguration *cfg = mgr.cfg; 122 123 // set global vars 124 conf_global_vars_s *vars = conf_getglobals(); 125 126 WSBool changeuid = FALSE; 127 uid_t ws_uid = geteuid(); 128 setpwent(); 129 char *pwbuf = malloc(DEF_PWBUF); 130 vars->Vuserpw = malloc(sizeof(struct passwd)); 131 if(cfg->user.ptr) { 132 if(!util_getpwnam(cfg->user.ptr, vars->Vuserpw, pwbuf, DEF_PWBUF)) { 133 log_ereport( 134 LOG_MISCONFIG, 135 "user %s does not exist!", 136 cfg->user.ptr); 137 free(vars->Vuserpw); 138 vars->Vuserpw = NULL; 139 } else { 140 changeuid = TRUE; 141 } 142 } else { 143 if(!util_getpwuid(ws_uid, vars->Vuserpw, pwbuf, DEF_PWBUF)) { 144 log_ereport(LOG_FAILURE, "webserver_init: cannot get passwd data"); 145 free(vars->Vuserpw); 146 vars->Vuserpw = NULL; 147 } 148 } 149 if(!vars->Vuserpw) { 150 log_ereport(LOG_VERBOSE, "globalvars->Vuserpw is null"); 151 } 152 153 // change uid 154 if(changeuid && ws_uid == 0) { 155 // a webserver user is set and we are root 156 log_ereport(LOG_VERBOSE, "setgid(%d)", vars->Vuserpw->pw_gid); 157 if(setgid(vars->Vuserpw->pw_gid) != 0) { 158 log_ereport( 159 LOG_FAILURE, 160 "setgid(%d) failed", 161 vars->Vuserpw->pw_gid); 162 return -1; 163 } else { 164 // setgid was successful 165 // we need to call initgroups to have all group permissions 166 if(initgroups(vars->Vuserpw->pw_name, vars->Vuserpw->pw_gid)!=0) { 167 log_ereport(LOG_FAILURE, "initgroups failed"); 168 return -1; 169 } 170 } 171 172 // change the uid 173 log_ereport(LOG_VERBOSE, "setuid(%d)", vars->Vuserpw->pw_uid); 174 if(setuid(vars->Vuserpw->pw_uid)) { 175 log_ereport( 176 LOG_FAILURE, 177 "setuid(%d) failed", 178 vars->Vuserpw->pw_uid); 179 return -1; 180 } 181 } else if(vars->Vuserpw) { 182 log_ereport( 183 LOG_WARN, 184 "server must be started as root to change uid"); 185 } 186 187 // run Init directives 188 // this must be done after setuid 189 int err = apply_init_conf(init_config); 190 free_init_conf(init_config); 191 if(err) { 192 log_ereport(LOG_FAILURE, "server init failed"); 193 return 1; 194 } 195 196 // init caches 197 auth_cache_init(); 198 199 // init SAFs 200 common_saf_init(); 201 202 203 // now that the process is running as the correct user, we can load 204 // the remaining config 205 if(cfgmgr_apply_config(&mgr)) { 206 log_ereport(LOG_FAILURE, "load config stage 2 failed"); 207 return -1; 208 } 209 210 211 // create tmp dir and pid file 212 char *mkdir_cmd = NULL; 213 asprintf(&mkdir_cmd, "mkdir -p %s", cfg->tmp.ptr); 214 system(mkdir_cmd); 215 free(mkdir_cmd); 216 217 char *pid_file_path = NULL; 218 asprintf(&pid_file_path, "%s/pid", cfg->tmp.ptr); 219 FILE *pidfile = fopen(pid_file_path, "w"); 220 if(!pidfile) { 221 log_ereport(LOG_FAILURE, "cannot open pid file %s: %s", pid_file_path, strerror(errno)); 222 return -1; 223 } 224 pid_t pid = getpid(); 225 fprintf(pidfile, "%d", pid); 226 fclose(pidfile); 227 free(pid_file_path); 228 229 // create unix domain socket for server control 230 cxmutstr tmp_priv = cx_asprintf("%s/private", cfg->tmp.ptr); 231 // TODO: remove existing private dir 232 if(mkdir(tmp_priv.ptr, S_IRWXU)) { 233 if(errno == EEXIST) { 234 if(chmod(tmp_priv.ptr, S_IRWXU)) { 235 log_ereport( 236 LOG_CATASTROPHE, 237 "cannot change permissions of tmp dir %s:", 238 tmp_priv.ptr, 239 strerror(errno)); 240 return -1; 241 } 242 } else { 243 log_ereport( 244 LOG_CATASTROPHE, 245 "cannot create tmp dir %s:", 246 tmp_priv.ptr, 247 strerror(errno)); 248 return -1; 249 } 250 } 251 free(tmp_priv.ptr); 252 253 254 // create srvctrl unix domain socket 255 // this socket is used for stop, reconfigure and other operations 256 if(srvctrl_init(cfg)) { 257 return -1; 258 } 259 260 //endpwent(); // TODO: close or not? 261 //free(pwbuf); // TODO: ? 262 263 return 0; 264 } 265 266 int webserver_run() { 267 log_ereport(LOG_VERBOSE, "webserver_run"); 268 269 // start all http listener 270 if(start_all_listener() != 0) { 271 fprintf(stderr, "Error: Cannot start http listener\n"); 272 } 273 274 log_ereport(LOG_INFORM, "webserver started"); 275 276 return 0; 277 } 278 279 void webserver_shutdown() { 280 log_ereport(LOG_INFORM, "webserver shutdown"); 281 282 srvctrl_shutdown(); 283 } 284 285 void webserver_end() { 286 // execute restart callbacks 287 RestartCallback *re = atrestart; 288 while(re) { 289 re->func(re->data); 290 re = re->next; 291 } 292 293 shutdown_threadpools(); 294 295 shutdown_eventhandlers_wait(); 296 297 webserver_destroy(); 298 } 299 300 int webserver_reconfig() { 301 CfgManager mgr; 302 if(cfgmgr_load_config(&mgr) != 0) { 303 log_ereport(LOG_FAILURE, "cannot reload server.conf"); 304 return 1; 305 } else { 306 if(cfgmgr_apply_config(&mgr)) { 307 log_ereport(LOG_FAILURE, "cannot reload config"); 308 return 1; 309 } 310 } 311 312 // start newly created listeners 313 start_all_listener(); 314 315 return 0; 316 } 317 318 void webserver_atrestart(void (*fn)(void *), void *data) { 319 RestartCallback *cb = malloc(sizeof(RestartCallback)); 320 cb->func = fn; 321 cb->data = data; 322 cb->next = NULL; 323 324 if(atrestart) { 325 RestartCallback *elm = atrestart; 326 while(elm) { 327 if(!elm->next) { 328 elm->next = cb; 329 break; 330 } 331 elm = elm->next; 332 } 333 } else { 334 atrestart = cb; 335 } 336 } 337 338 void webserver_destroy() { 339 // free some stuff 340 // this is not necessary, because the whole process will exit 341 // however it will result in a nicer valgrind output with less 342 // memory leaks 343 pool_destroy(cfg_get_init_pool()); 344 } 345 346 int nsapi_runtime_version() { 347 return 303; 348 } 349 350 351 int ws_init_ssl() { 352 // TODO: handle errors 353 SSL_load_error_strings(); 354 SSL_library_init(); 355 OpenSSL_add_all_algorithms(); 356 return 0; 357 } 358