/* ** oidentd_options.c - oidentd command-line handler. ** Copyright (C) 2001-2006 Ryan McCabe ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License, version 2, ** as published by the Free Software Foundation. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MASQ_SUPPORT # define OPTSTRING "a:c:C:def::g:hiIl:mo::p:P:qr:St:u:Uv" extern in_port_t fwdport; #else # define OPTSTRING "a:c:C:deg:hiIl:o::p:P:qr:St:u:Uv" #endif extern struct sockaddr_storage proxy; extern char *failuser; extern char *ret_os; extern char *config_file; extern u_int32_t timeout; extern u_int32_t connection_limit; extern in_port_t listen_port; extern struct sockaddr_storage *addr; extern uid_t uid; extern gid_t gid; static void print_usage(void); static void print_version(void); static inline void enable_opt(u_int32_t option); static const struct option longopts[] = { {"address", required_argument, 0, 'a'}, {"charset", required_argument, 0, 'c'}, {"config", required_argument, 0, 'C'}, {"debug", no_argument, 0, 'd'}, {"error", no_argument, 0, 'e'}, {"group", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"foreground", no_argument, 0, 'i'}, {"stdio", no_argument, 0, 'I'}, {"limit", required_argument, 0, 'l'}, {"other", optional_argument, 0, 'o'}, {"port", required_argument, 0, 'p'}, {"quiet", no_argument, 0, 'q'}, {"reply", required_argument, 0, 'r'}, {"nosyslog", no_argument, 0, 'S'}, {"timeout", required_argument, 0, 't'}, {"user", required_argument, 0, 'u'}, #ifdef HAVE_LIBUDB {"udb", no_argument, 0, 'U'}, #endif {"version", no_argument, 0, 'v'}, #ifdef MASQ_SUPPORT {"forward", optional_argument, 0, 'f'}, {"masquerade", no_argument, 0, 'm'}, #endif {"proxy", required_argument, 0, 'P'}, {NULL, 0, NULL, 0} }; static u_int32_t flags; /* ** Returns true if "option" is enabled, false if it isn't. */ inline bool opt_enabled(u_int32_t option) { return ((flags & option) != 0); } /* ** Enables "option." */ static inline void enable_opt(u_int32_t option) { flags |= option; } /* ** Disables "option." */ inline void disable_opt(u_int32_t option) { flags &= ~option; } /* ** Parse any arguments passed to the program. ** Returns 0 on success, -1 on failure. */ int get_options(int argc, char *const argv[]) { int opt; char *temp_os; char *charset = NULL; #ifdef MASQ_SUPPORT if (get_port(DEFAULT_FPORT, &fwdport) == -1) { o_log(NORMAL, "Fatal: Bad port: \"%s\"", DEFAULT_FPORT); return (-1); } fwdport = htons(fwdport); #endif connection_limit = 0xffffffff; config_file = xstrdup(CONFFILE); temp_os = xstrdup("UNIX"); if (get_port(DEFAULT_PORT, &listen_port) == -1) { o_log(NORMAL, "Fatal: Bad port: \"%s\"", DEFAULT_PORT); return (-1); } while ((opt = getopt_long(argc, argv, OPTSTRING, longopts, NULL)) != EOF) { switch (opt) { case 'a': { struct sockaddr_storage *temp_ss = xmalloc(sizeof(struct sockaddr_storage)); if (get_addr(optarg, temp_ss) == -1) { o_log(NORMAL, "Fatal: Unknown host: \"%s\"", optarg); free(temp_ss); return (-1); } addr = temp_ss; break; } case 'c': if (charset != NULL) free(charset); charset = xstrdup(optarg); break; case 'C': if (config_file != NULL) free(config_file); config_file = xstrdup(optarg); break; case 'd': enable_opt(DEBUG_MSGS); break; case 'e': enable_opt(HIDE_ERRORS); break; #ifdef MASQ_SUPPORT case 'f': { const char *p; if (optarg == NULL) p = DEFAULT_FPORT; else p = optarg; if (get_port(p, &fwdport) == -1) { o_log(NORMAL, "Fatal: Bad port: \"%s\"", p); return (-1); } fwdport = htons(fwdport); enable_opt(FORWARD); break; } case 'm': enable_opt(MASQ); break; #endif case 'P': { if (get_addr(optarg, &proxy) == -1) { o_log(NORMAL, "Fatal: Unknown host: \"%s\"", optarg); return (-1); } enable_opt(PROXY); break; } case 'g': enable_opt(CHANGE_GID); if (find_group(optarg, &gid) == -1) { o_log(NORMAL, "Fatal: Unknown group: \"%s\"", optarg); return (-1); } break; /* pre-connected, as when run from inetd */ case 'I': enable_opt(STDIO | FOREGROUND); break; /* do not become a daemon */ case 'i': enable_opt(FOREGROUND); break; case 'l': { u_int32_t temp_limit; char *end; temp_limit = strtoul(optarg, &end, 10); if (*end != '\0') { o_log(NORMAL, "Fatal: Not a valid number: \"%s\"", optarg); return (-1); } connection_limit = temp_limit; } case 'o': if (temp_os != NULL) free(temp_os); if (optarg != NULL) { char *p; temp_os = xstrdup(optarg); p = strchr(temp_os, '\n'); if (p != NULL) *p = '\0'; p = strchr(temp_os, '\r'); if (p != NULL) *p = '\0'; } else temp_os = xstrdup("OTHER"); break; case 'p': if (get_port(optarg, &listen_port) == -1) { o_log(NORMAL, "Fatal: Bad port: \"%s\"", optarg); return (-1); } break; case 'q': enable_opt(QUIET); break; case 'r': if (failuser != NULL) free(failuser); failuser = xstrdup(optarg); break; case 'S': enable_opt(NOSYSLOG); break; case 't': { char *end; timeout = strtoul(optarg, &end, 10); if (*end != '\0') { o_log(NORMAL, "Fatal: Bad timeout value: \"%s\"", optarg); return (-1); } break; } case 'u': enable_opt(CHANGE_UID); if (find_user(optarg, &uid) == -1) { o_log(NORMAL, "Fatal: Unknown user: \"%s\"", optarg); return (-1); } break; #ifdef HAVE_LIBUDB case 'U': enable_opt(USEUDB); break; #endif case 'v': print_version(); return (-1); case 'h': default: print_usage(); return (-1); } } if (charset != NULL) { size_t len = strlen(temp_os) + strlen(charset) + 4; ret_os = xmalloc(len); snprintf(ret_os, len, "%s , %s", temp_os, charset); free(temp_os); free(charset); } else ret_os = temp_os; if (opt_enabled(DEBUG_MSGS) && opt_enabled(QUIET)) { o_log(NORMAL, "Fatal: The debug and quiet flags are incompatible"); return (-1); } /* ** If no user was specified, use a reasonable default. */ if (!opt_enabled(CHANGE_UID)) { if (find_user("nobody", &uid) == -1) { o_log(NORMAL, "user \"nobody\" does not exist. Using %u as default UID", DEFAULT_UID); uid = DEFAULT_UID; } } /* ** If no group is specified, use a reasonable default. */ if (!opt_enabled(CHANGE_GID)) { if (find_group("nobody", &gid) == -1) { if (find_group("nogroup", &gid) == -1) { o_log(NORMAL, "Groups \"nobody\" and \"nogroup\" do not exist. Using %u as default GID", DEFAULT_GID); gid = DEFAULT_GID; } } } return (0); } static void print_usage(void) { const char usage[] = "\nUsage: oidentd [options]\n" "-a or --address
Bind to
\n" "-c or --charset Specify an alternate charset\n" "-C or --config Use the specifed file instead of /etc/oidentd.conf\n" "-d or --debug Enable debugging\n" "-e or --error Return \"UNKNOWN-ERROR\" for all errors\n" #ifdef MASQ_SUPPORT "-f or --forward [] Forward requests for masqueraded hosts to the host on port \n" "-m or --masquerade Enable support for IP masquerading\n" #endif "-P or --proxy acts as a proxy, forwarding connections to us\n" "-g or --group Run with specified group or GID\n" "-i or --foreground Don't run as a daemon\n" "-I or --stdio Service a single client connected to stdin/stdout then exit (use when oidentd is running from inetd/xinetd/etc).\n" "-l or --limit Limit the number of open connections to the specified number\n" "-o or --other [] Return instead of the operating system. Uses \"OTHER\" if no argument is given.\n" "-p or --port Listen for connections on specified port\n" "-q or --quiet Suppress normal logging\n" "-S or --nosyslog Write messages to stderr not syslog\n" "-t or --timeout Wait for before closing connection\n" "-u or --user Run as specified user or UID\n" #ifdef HAVE_LIBUDB "-U or --udb Perform lookups in UDB shared memory tables\n" #endif "-v or --version Display version information and exit\n" "-r or --reply If a query fails, pretend it succeeded, returning \n" "-h or --help This help message\n"; print_version(); printf("%s", usage); } static void print_version(void) { printf("%s\n", PACKAGE_STRING); printf("Written by %s <%s>\n", PACKAGE_AUTHOR, PACKAGE_BUGREPORT); printf("%s\n", PACKAGE_WEBSITE); }