/*************************************************************************** main.cpp - main file for posadis ------------------- begin : zo dec 22 18:24:18 CET 2002 copyright : (C) 2002 by Meilof email : meilof@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #include #include #include #else #include #include #include #include #endif #include "hashvector.h" #include "zones.h" #include "primary.h" #include "masterfile.h" #include "query.h" #include "lib.h" #include "resolver.h" #include "configuration.h" #include "updates.h" #include "posadisrc.h" #ifdef _WIN32 extern char *PLUGINDIR; #endif void cleanup(int sig) { pos_setquitflag(); } void querylog(int sig) { do_query_logging = !do_query_logging; } #ifndef _WIN32 void sighup(int sig) { pthread_t tr; posthread_create(&tr, zones_reload, NULL); } #endif void print_help() { printf("Posadis - A DNS server.\n\n" "Usage:\n" " -c, --conf-file Use the specified configuration file\n" " -h, --help Print this help message\n" " -v, --version Print version info\n" " -p, --pidfile Filename to write the Posadis PID to\n" " -l, --log Specify log file name (or - if none)\n" #ifndef _WIN32 " -u, --user Switch to user after reading configuration\n" " -g, --group Switch to group after reading configuration\n" " -f, --fork Run in the background\n" " -r, --chroot Specify directory to chroot to\n" #endif "\n" "Posadis comes with no warranty. Use at your own risk, and be sure to report\n" "all issues to the Posadis team!\n"); } void print_version() { printf("Posadis\n\n" " A noble spirit embiggens the smallest man\n" " -- Jebediah Springfield\n\n" " Version: " POS6_VERSION "\n" " Built on: " __DATE__ "\n" " Plugin dir: %s\n", plugin_dir); } FILE *pidf = NULL; #ifdef POS_W32_SERVICE int pos6_main(int argc, char *argv[]) { #else int main(int argc, char *argv[]) { #endif int ret = EXIT_SUCCESS; int x; char fname[PATH_MAX]; char pidfile[PATH_MAX] = ""; #ifdef _WIN32 HKEY hkey; DWORD valuetype = 16; DWORD buffsize = sizeof(fname); if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Posadis", 0, KEY_READ, &hkey) == ERROR_SUCCESS) { if (RegQueryValueEx(hkey, "Posadisrc " POS6_VERSION, NULL, &valuetype, (BYTE*)fname, &buffsize) != ERROR_SUCCESS || valuetype != REG_SZ) strcpy(fname, "c:\\posadisrc.txt"); buffsize = PATH_MAX; if (RegQueryValueEx(hkey, "Posadis-libs " POS6_VERSION, NULL, &valuetype, (BYTE*)plugin_dir, &buffsize) != ERROR_SUCCESS || valuetype != REG_SZ) strcpy(plugin_dir, "c:\\posadis " POS6_VERSION); RegCloseKey(hkey); } #else strcpy(fname, "/etc/posadisrc"); char chrootdir[PATH_MAX] = ""; #endif #ifndef _WIN32 bool do_fork = false; #endif for (x = 1; x < argc; x++) { if (strcmpi(argv[x], "-c") == 0 || strcmpi(argv[x], "--conf-file") == 0) { if (x == argc - 1) { printf("Expected argument to --conf-file option!\n\n"); print_help(); return 1; } x++; if (strlen(argv[x]) + 1 >= PATH_MAX) { printf("Configuration file name too long!\n"); return 1; } strcpy(fname, argv[x]); } else if (strcmpi(argv[x], "-h") == 0 || strcmpi(argv[x], "--help") == 0) { print_help(); return 0; } else if (strcmpi(argv[x], "-v") == 0 || strcmpi(argv[x], "--version") == 0) { print_version(); return 0; } else if (strcmpi(argv[x], "--embiggen") == 0) { printf("Hitch that team up, Jebediah Springfield\n" "Whip them horses, let them wagons roll\n" "That a people might embiggen America\n" "That a man might embiggen his soul\n" "His soul\n" "His soul...\n"); return 0; #ifndef _WIN32 } else if (strcmpi(argv[x], "-f") == 0 || strcmpi(argv[x], "--fork") == 0) { do_fork = true; } else if (strcmpi(argv[x], "-u") == 0 || strcmpi(argv[x], "--user") == 0) { if (x == argc - 1) { printf("Expected argument to --user option!\n\n"); print_help(); return 1; } x++; if (strlen(argv[x]) + 1 >= sizeof(username)) { printf("User name %s too long!\n", argv[x]); return 1; } strcpy(username, argv[x]); cmd_username = true; } else if (strcmpi(argv[x], "-g") == 0 || strcmpi(argv[x], "--group") == 0) { if (x == argc - 1) { printf("Expected argument to --group option!\n\n"); print_help(); return 1; } x++; if (strlen(argv[x]) + 1 >= sizeof(group)) { printf("Group name %s too long!\n", argv[x]); return 1; } strcpy(groupname, argv[x]); cmd_groupname = true; } else if (strcmpi(argv[x], "-r") == 0 || strcmpi(argv[x], "--chroot") == 0) { if (x == argc - 1) { printf("Expected argument to --chroot option!\n\n"); print_help(); return 1; } x++; if (strlen(argv[x]) + 1 >= sizeof(chrootdir)) { printf("Chroot dir name %s too long!\n", argv[x]); return 1; } strcpy(chrootdir, argv[x]); #endif } else if (strcmpi(argv[x], "-l") == 0 || strcmpi(argv[x], "--log") == 0) { if (x == argc - 1) { printf("Expected argument to --log option!\n\n"); print_help(); return 1; } x++; if (strlen(argv[x]) + 1 >= sizeof(logfile)) { printf("Log file name %s too long!\n", argv[x]); return 1; } strcpy(logfile, argv[x]); cmd_logfile = true; } else if (strcmpi(argv[x], "-p") == 0 || strcmpi(argv[x], "--pidfile") == 0) { if (x == argc - 1) { printf("Expected argument to --pidfile option!\n\n"); print_help(); return 1; } x++; if (strlen(argv[x]) + 1 >= sizeof(pidfile)) { printf("Pid file name %s too long!\n", argv[x]); return 1; } strcpy(pidfile, argv[x]); } else { printf("Unknown configuration flag %s!\n\n", argv[x]); print_help(); return 1; } } config_init(); lib_init(); zones_init(); try { read_posadisrc(fname); } catch (PException p) { ret = 1; printf("*** Fatal: %s\n", p.message); goto _quitmain; } try { if (logfile[0] && !(logfile[0] == '-' && logfile[1] == '\0')) { open_new_logfile(); } if (pidfile[0]) { pidf = try_fopen(pidfile, "w"); if (!pidf) { throw PException(true, "Could not open pidfile %s for writing!", pidfile); } } #ifndef _WIN32 if (chrootdir[0]) { if (chroot(chrootdir) != 0) throw PException("Cannot chroot to %s!", chrootdir); chdir("/"); } if (groupname[0]) { struct group *grinfo; gid_t grid; grinfo = getgrnam(groupname); if (!grinfo) throw PException(true, "Cannot switch to unknown group %s", groupname); grid = grinfo->gr_gid; if (setgid(grid) != 0) throw PException(true, "Cannot setgid() to %s", groupname); } if (username[0]) { struct passwd *pwinfo; uid_t uid; pwinfo = getpwnam(username); if (!pwinfo) throw PException(true, "Cannot switch to unknown user %s", username); uid = pwinfo->pw_uid; if (setuid(uid) != 0) throw PException(true, "Cannot setuid() to %s", username); } if (do_fork) { int t = fork(); if (t == -1) throw PException("Forking failed!"); else if (t > 0) _exit(0); /* now, stop logging */ do_stderr_log = false; } #endif /* write pid */ if (pidfile[0]) { fprintf(pidf, "%d", getpid()); fclose(pidf); pidf = NULL; } /* now that we've forked, we can safely call end_setting and start creating new threads */ posadisrc_finalize(); handle_query = query_entry_point; user_cleanup_function = my_cleanup; allow_tcp_connection = our_allow_tcp_connection; signal(SIGINT, cleanup); signal(SIGTERM, cleanup); #ifndef _WIN32 signal(SIGUSR1, querylog); signal(SIGHUP, sighup); #endif pos_log(context_server, log_info, "Posadis server starting up..."); if (servers.begin() == servers.end()) pos_log(context_server, log_warning, "Not listening to any network interfaces"); #ifdef POS_W32_SERVICE return 0; #else posserver_run(); #endif } catch (PException p) { if (pidf) { fclose(pidf); pidf = NULL; } printf("Fatal error: %s\n", p.message); ret = 1; } _quitmain: #ifdef POS_W32_SERVICE return ret; } int pos_destruction() { int ret = 0; #endif /* every destruction process that uses shared libraries should be placed here to prevent it from being called before dlexit */ if (pidf) { fclose(pidf); pidf = NULL; } pthread_mutex_lock(&m_auth_zones); if (auth_root_zone) auth_root_zone->deletefn(auth_root_zone); auth_root_zone = NULL; pthread_mutex_unlock(&m_auth_zones); #ifdef _WIN32 if (logfile_fd != INVALID_HANDLE_VALUE) CloseHandle(logfile_fd); #endif return ret; }