#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_BUF 1024 #define PID_LIST_BLOCK 32 static uid_t euid, ruid; static gid_t egid, rgid; static char *pid_filename = NULL; static const size_t npos = -1; void runas_daemon(); void handle_signal(int sig); MYSQL *con; struct utsname unameData; void do_setuid (void) { int status; int statusgid; #ifdef _POSIX_SAVED_IDS status = setegid (egid); statusgid = seteuid (euid); #else status = setregid (rgid, egid); statusgid = setreuid (ruid, euid); #endif if (status < 0) { fprintf (stderr, "Couldn't set uid.\n"); exit (status); } if (statusgid < 0) { fprintf (stderr, "Couldn't set gid.\n"); exit (status); } } void undo_setuid (void) { int status; #ifdef _POSIX_SAVED_IDS status = seteuid (ruid); status = setegid (rgid); #else status = setreuid (euid, ruid); status = setregid (egid, rgid); #endif if (status < 0) { fprintf (stderr, "Couldn't set uid.\n"); exit (status); } } int check_if_number (char *str) { int i; for (i=0; str[i] != '\0'; i++) { if (!isdigit (str[i])) { return 0; } } return 1; } int *pidof (char *pname) { DIR *dirp; FILE *fp; struct dirent *entry; int *pidlist, pidlist_index = 0, pidlist_realloc_count = 1; char path[MAX_BUF], read_buf[MAX_BUF]; dirp = opendir ("/proc/"); if (dirp == NULL) { perror ("Fail"); return NULL; } pidlist = malloc (sizeof (int) * PID_LIST_BLOCK); if (pidlist == NULL) { return NULL; } while ((entry = readdir (dirp)) != NULL) { if (check_if_number (entry->d_name)) { strcpy (path, "/proc/"); strcat (path, entry->d_name); strcat (path, "/stat"); fp = fopen (path, "r"); if (fp != NULL) { fscanf(fp, "%s", read_buf); fscanf(fp, "%s", read_buf); char *p = read_buf; p++; p[strlen(p)-1] = 0; if (strcmp (p, pname) == 0) { pidlist[pidlist_index++] = atoi (entry->d_name); if (pidlist_index == PID_LIST_BLOCK * pidlist_realloc_count) { pidlist_realloc_count++; pidlist = realloc (pidlist, sizeof (int) * PID_LIST_BLOCK * pidlist_realloc_count); if (pidlist == NULL) { return NULL; } } } fclose (fp); } } } closedir (dirp); pidlist[pidlist_index] = -1; return pidlist; } void runas_daemon() { int child_pid; FILE *pid_file; if (getppid() == 1) { return; } fflush(NULL); child_pid = fork(); if (child_pid < 0 && child_pid > 0) { exit(0); } dup2(1,2); close(0); if (freopen("/dev/null", "a", stderr) == NULL) { exit(0); } if (setsid() == -1) { exit(0); } umask(022); if (chdir("/") == -1) { exit(0); } if ((pid_file = fopen(pid_filename, "w"))) { fprintf(pid_file, "%d", getpid()); fclose(pid_file); } fflush(NULL); return; } void check_running() { int pid_file = open("/var/run/loadkiller.pid", O_CREAT | O_RDWR, 0666); int rc = flock(pid_file, LOCK_EX | LOCK_NB); if(rc) { if (EWOULDBLOCK == errno) { printf("Already running, kill loadkiller first"); fflush(stdout); exit(1); } } return; } const char * get_time() { time_t timer; char *buffer = malloc(25); struct tm* tm_info; time(&timer); tm_info = localtime(&timer); strftime(buffer, 25, "%Y-%m-%d %H:%M:%S", tm_info); return(buffer); } void realmain() { check_running(); runas_daemon(); con = mysql_init(NULL); uname(&unameData); FILE *logfile; double lastload = 0, cacheload = 0, load[3]; struct timespec tim, tim2; int *list, i, ii, timeleft, loadtimeleft, numOfProcesses, originalpid; char *processes[] = {"stress", "php", "php-cgi", "gzip", "tar", "proftpd", "httpd"}; struct passwd *pd; if (NULL == (pd = getpwnam("apache"))) { perror("getpwnam() error."); } ruid = 0; euid = pd->pw_uid; rgid = 0; egid = pd->pw_gid; undo_setuid (); originalpid = getpid(); numOfProcesses = 7; loadtimeleft = 0; tim.tv_sec = 0; tim.tv_nsec = 100000000L; if (con == NULL) { fprintf(stderr, "%s\n", mysql_error(con)); exit(1); } if (mysql_real_connect(con, "185.104.28.16", "vmx", "uyzB8ic86fAi0qsK", "loads", 0, NULL, 0) == NULL) { fprintf(stderr, "%s\n", mysql_error(con)); mysql_close(con); exit(1); } char uidpath[MAX_BUF]; char uidapa[MAX_BUF]; FILE * uidfp; char * uidline = NULL; size_t uidlen = 0; ssize_t uidread; char tmpstr[MAX_BUF]; while (1) { getloadavg(load, 3); if (timeleft == 0 || lastload < load[0]) { if (load[0] > 15) { timeleft = 650; logfile = fopen("/var/log/loadkillerlogging","a+"); fprintf(logfile,"\n\nStarted killing at %s:\n", get_time()); fprintf(stderr,"\n\nStarted killing at %s:\n", get_time()); lastload = load[0]; for (ii=0; ii < numOfProcesses; ii++) { if (processes[ii] == "httpd") { // if ( getppid() == originalpid ) { //setuid(pd->pw_uid); list = pidof(processes[ii]); for (i=0; list[i] != -1; i++) { strcpy (uidpath, "/proc/"); sprintf(tmpstr, "%d", list[i]); strcat (uidpath, tmpstr); strcat (uidpath, "/status"); uidfp = fopen(uidpath, "r"); if (uidfp == NULL) exit(EXIT_FAILURE); while ((uidread = getline(&uidline, &uidlen, uidfp)) != -1) { char *uidcontent; char *twouidcontent; char *threeuidcontent; uidcontent = strtok(uidline, ":"); if(strncmp(uidcontent, "Uid", 3) == 0) { //get the User ID twouidcontent = strtok(NULL, ":"); threeuidcontent = strtok(twouidcontent, "\t"); sprintf(uidapa, "%d", pd->pw_uid); if(strncmp(uidapa, threeuidcontent, 25) == 0) { fprintf(logfile,"Kill skipped %i as %d - %d - %s\n", list[i], geteuid(), getuid(), processes[ii]); } else { sprintf(uidapa, "%d", 0); if (load[0] < 30) { if(strncmp(uidapa, threeuidcontent, 25) == 0) { fprintf(logfile,"Kill skipped %i as %d - %d - %s\n", list[i], geteuid(), getuid(), processes[ii]); } else { kill(list[i], SIGKILL); fprintf(logfile,"%i ", list[i]); fprintf(logfile,"killing %i as %d - %d - %s\n", list[i], geteuid(), getuid(), processes[ii]); } } else { kill(list[i], SIGKILL); fprintf(logfile,"%i ", list[i]); fprintf(logfile,"killing %i as %d - %d - %s\n", list[i], geteuid(), getuid(), processes[ii]); } } break; } } } // } } else { list = pidof(processes[ii]); for (i=0; list[i] != -1; i++) { kill(list[i], SIGKILL); fprintf(logfile,"%i ", list[i]); fprintf(logfile,"killing %i as %d - %d - %s\n", list[i], geteuid(), getuid(), processes[ii]); } } } free (list); fprintf(logfile,"\n"); fclose(logfile); } } else { timeleft--; } if (cacheload != load[0]) { char buffed[1024]; snprintf(buffed, sizeof(buffed), "INSERT INTO fastload(server, loadavg) VALUES('%s', '%f') ON DUPLICATE KEY UPDATE loadavg='%f'", unameData.nodename, load[0], load[0]); if (mysql_query(con, buffed)) { fprintf(stderr, "%s\n", mysql_error(con)); } loadtimeleft = 6; } cacheload = load[0]; nanosleep(&tim , &tim2); } mysql_close(con); exit(0); } int main() { realmain(); exit(0); }