int main(int argc, char **argv) { FILE *fp; char cfgfile[128]; char line[1024]; int linenr = 0; int grant = 0; char **env = NULL; size_t env_a = 0; size_t env_i = 0; char *command = NULL; char *user; struct passwd *pw; int log_opts = LOG_PID | LOG_PERROR; int c; clean_fds(); cmnd = argv[0]; while ((c = getopt(argc, argv, "q")) != EOF) { switch(c) { case 'q': log_opts &= !LOG_PERROR; break; case '?': usage(); default: assert(0); } } if (argc - optind < 2) usage(); user = argv[optind++]; openlog("xssd", log_opts, LOG_AUTH); /* a / in either the username or the command name could be used to * break out of /etc/xssd. Of course the user would actually have to * exist to do harm, but better safe than sorry. */ if (strchr(user, '/')) { syslog(LOG_ERR, "invalid username %s. [Ruid: %d]", user, getuid()); exit(1); } if (strchr(argv[optind], '/')) { syslog(LOG_ERR, "invalid command name %s. [Ruid: %d]", argv[optind], getuid()); exit(1); } snprintf(cfgfile, sizeof(cfgfile), "/etc/xssd/%s/%s", user, argv[optind]); /* check for return value unnecessary, because fopen below will fail if no config file exists */ if ((fp = fopen(cfgfile, "r")) == NULL) { syslog(LOG_ERR, "%s: fopen failed: %s. [Ruid: %d]", cfgfile, strerror(errno), getuid()); exit(1); } while (fgets(line, sizeof(line), fp)) { int lp; linenr++; /* remove trailing white space */ lp = strlen(line)-1; if (line[lp] != '\n') { syslog(LOG_ERR, "config file %s[%d]: Line unterminated or too long. [Ruid: %d]", cfgfile, linenr, getuid()); exit(1); } while (lp >= 0 && isspace((unsigned char)line[lp])) { line[lp--] = '\0'; } /* Check for keywords. */ if (*line == '#') { continue; } if (strncmp(line, "Command:", strlen("Command:") ) == 0) { int lp; skip_ws(line, lp, strlen("Command:")); command = strdup(line + lp); continue; } if (strncmp(line, "User:"******"User:"******"User:"******"Group:", strlen("Group:") ) == 0) { int lp; struct group *gr; skip_ws(line, lp, strlen("Group:")); gr = getgrnam(line + lp); if (gr) { if (gr->gr_gid == getgid()) { grant = 1; } else { gid_t groups[NGROUPS_MAX] = {0}; int ngroups = getgroups(NGROUPS_MAX, groups); int i; for (i = 0; i < ngroups; i++) { if (gr->gr_gid == groups[i]) { grant = 1; } } } } continue; } if (strncmp(line, "Env:", strlen("Env:") ) == 0) { char *s; int lp; skip_ws(line, lp, strlen("Env:")); fprintf(stderr, "Env: %s\n", line + lp); s = getenv(line + lp); if (s) { if (env_i >= env_a) { env_a = env_a * 3 / 2 + 10; if ((env = realloc(env, env_a * sizeof(*env))) == NULL) { syslog(LOG_ERR, "config file %s[%d]: cannot realloc env to %ld strings: %s. [Ruid: %d]", cfgfile, linenr, (long)env_a, strerror(errno), getuid()); exit(1); } } if ((env[env_i] = malloc(strlen(line + lp) + 1 + strlen(s) + 1)) == NULL) { syslog(LOG_ERR, "config file %s[%d]: cannot strdup env variable %s: %s. [Ruid: %d]", cfgfile, linenr, line + lp, strerror(errno), getuid()); } sprintf(env[env_i], "%s=%s", line + lp, s); env_i++; } continue; } /* if we get here, we have an unknown keyword or mistyped or ... */ fprintf(stderr, "Do not know what to do with \"%s\"\n", line); exit(1); } fclose(fp); if (env_i >= env_a) { env_a = env_a * 3 / 2 + 10; if ((env = realloc(env, env_a * sizeof(*env))) == NULL) { syslog(LOG_ERR, "config file %s[%d]: cannot realloc env to %ld strings: %s. [Ruid: %d]", cfgfile, linenr, (long)env_a, strerror(errno), getuid()); exit(1); } } env[env_i] = NULL; if (grant) { syslog(LOG_INFO, "%s: access granted. [Ruid: %d]", cfgfile, getuid()); } else { syslog(LOG_NOTICE, "%s: access denied. [Ruid: %d]", cfgfile, getuid()); exit(1); } pw = getpwnam (user); if (pw == NULL) { syslog(LOG_ERR, "%s: unknown target user %s. [Ruid: %d]", cfgfile, user, getuid()); exit(1); } if (initgroups(user, pw->pw_gid) == -1) { syslog(LOG_ERR, "%s: initgroups(%s, %d) failed: %s. [Ruid: %d]", cfgfile, user, pw->pw_gid, strerror(errno), getuid()); exit(1); } if (setgid(pw->pw_gid) == -1) { syslog(LOG_ERR, "%s: setgid(%d) failed: %s. [Ruid: %d]", cfgfile, (int)pw->pw_gid, strerror(errno), getuid()); exit(1); } if (setuid(pw->pw_uid) == -1) { syslog(LOG_ERR, "%s: setuid(%d) failed: %s. [Ruid: %d]", cfgfile, (int)pw->pw_uid, strerror(errno), getuid()); exit(1); } syslog(LOG_INFO, "%s: execing %s. [Ruid: %d]", cfgfile, command, getuid()); execve(command, argv + optind, env); syslog(LOG_ERR, "%s: execve(%s) failed: %s. [Ruid: %d]", cfgfile, command, strerror(errno), getuid()); return 1; }
int main(int argc, char *argv[]) { if (argc == 1) print_usage(); int in_guard_mode = 0; int dump_core = 0; int children_instance = 0; char *run_as_user = NULL; // parse args int c = -1; extern char *optarg; extern int optopt; const char *opt = ":gvu:Cs:ep:h"; while((c = getopt(argc, argv, opt)) != -1) { switch (c) { case 'v': // version fprintf(stderr, "\033[0;32m%s %s\033[0m\n", SVC_EDITION, BIN_V); return 0; case 'g': in_guard_mode = 1; break; case 'u': run_as_user = optarg; break; case 'C': dump_core = 1; break; case 'e': children_instance = 1; break; case 'p': break; case ':': fprintf(stderr, "\n\033[0;35mOption -%c requires an operand\033[0m\n", optopt); case 'h': default: print_usage(); } } const int max_clients = 1024*4; set_max_fds(max_clients); g_max_fds = get_max_fds(); if (run_as_user && runas(run_as_user) != 0) { fprintf(stderr, "\033[0;35mSudo to %s error!\033[0m\n", run_as_user); return -1; } if (dump_core && dump_corefile() != 0) { fprintf(stderr, "\033[0;35mSet dump corefile error!\033[0m\n"); return -1; } if (in_guard_mode) { if (children_instance == 0) guard_process(g_svc_name, argc, argv); clean_fds(); }else output_pid(g_svc_name); //= child process child_sig_handle(); sys::r = new reactor(); if (sys::r->open(max_clients, max_clients + 16) != 0) { fprintf(stderr, "Error: reactor - open failed!\n"); return -1; } if (sys::init_svc() != 0) { fprintf(stderr, "Error: init_svc - init failed!\n"); return -1; } s_log->rinfo("launch ok! max fds:%d", g_max_fds); e_log->rinfo("launch ok! max fds:%d", g_max_fds); // reactor event loop sys::r->run_reactor_event_loop(); return 1; }