-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathphunt.c
More file actions
394 lines (311 loc) · 11.8 KB
/
phunt.c
File metadata and controls
394 lines (311 loc) · 11.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <pwd.h>
#include <dirent.h>
#include <sys/resource.h>
#define ERR -1
#define logSize 200
#define tempStringSize 6
#define startupStringSize 26
#define SUCCESS 1
#define FAILURE 0
#define LOWERPRIORITY -20
//struct used to get the linux version
struct utsname linVersion;
int keepRunning = 1;
//call this if Ctrl-c is pressed, it will cause the while loop to exit and program to end gracefully
void youDontControlMe(int signal) {
printf(" Program ended\n");
keepRunning = 0;
}
//parse the arguments
void parse_inputs (int argc, char *argv[], char **logFile, char **configFile) {
for (int i = 0; i < argc; i++) {
//if we are not at the last argument
if (i != argc - 1) {
//if -l or -c, the file is the next argument
if (!strcmp(argv[i], "-l")) {
*logFile = argv[i+1];
}
else if (!strcmp(argv[i], "-c")) {
*configFile = argv[i+1];
}
}
}
}
//open the log and config files if they can be opened, otherwise throw an error
void openFiles (FILE **logFile, FILE **configFile, char *log, char *config) {
*logFile = fopen(log, "a");
if (*logFile == NULL) {
printf("Error opening log file\n");
exit(0);
}
if( access( config, R_OK ) != -1 ) {
// file exists and we are able to read it
*configFile = fopen(config, "r");
if (*configFile == NULL) {
printf("Error opening config file\n");
fclose(*logFile);
exit(0);
}
} else {
// file doesn't exist
printf("Config file %s does not exist or is not accessible\n", config);
fclose(*logFile);
exit(0);
}
}
//return the current time as a string and remove the newline at the end.
char * timeStamp() {
time_t currentTime;
currentTime = time(NULL);
char *stringTime = asctime(localtime(¤tTime));
stringTime[strlen(stringTime) - 1] = '\0';
return stringTime;
}
//put together a string of all important information and use it on a log
char * createEntry (char *news) {
char *entry = malloc(logSize);
entry[0] = '\0';
//add timeStamp
strcat(entry, timeStamp());
strcat(entry, " ");
strcat(entry, linVersion.nodename);
strcat(entry, " ");
strcat(entry, "phunt: ");
strcat(entry, news);
return entry;
}
//create the string that is logged on startup, contains the PID of this phunt
char * startup() {
int pid = (int)getpid();
char temp[tempStringSize];
sprintf(temp, "%d", pid);
char * startupString = malloc(startupStringSize);
startupString[0] = '\0';
strcat(startupString, "phunt startup (PID=");
strcat(startupString, temp);
strcat(startupString, ")");
return startupString;
}
//prints the given string to the logfile
void enterLog(FILE **logFile, char *logEntry) {
fprintf(*logFile, "%s\n", logEntry);
}
//appends two to the end of one, returns the result
char * concatenate(char *one, char *two) {
char * result = malloc(50);
strcpy(result, one);
strcat(result, two);
return result;
}
int isSuspended(char * processID) {
char * procpath = concatenate(concatenate("/proc/", processID), "/status");
FILE * statusFile = fopen(procpath, "r");
if(statusFile == NULL) {
printf("No status file for this document\n");
fclose(statusFile);
return 0;
}
char status[4][256];
fscanf(statusFile, "%s %s %s %s", status[0],status[1],status[2],status[3]);
fclose(statusFile);
//if the status is T (stopped) send a 1
if (strcmp(status[3], "T") == 0)
return 1;
else
return 0;
}
//This program handles the command. It kills, suspends, or nices appropriate files
int killit(char * action, char * type, char * param, FILE **logFile) {
char *name;
int processID;
//placeholder, literally used for nothing else
long nothing;
long actualMemoryUsed;
//statm file found in /proc/xx/ directory
FILE *statmFile;
//stat struct that holds the uid needed for username
struct stat st;
//open /proc directory holding the process files
//DIR used to "navigate" directories
DIR *d;
struct dirent *dir;
d = opendir("/proc");
if (d) {
//read through all files and find the owner, if it is blacklist owner, kill it
while ((dir = readdir(d)) != NULL) {
stat(concatenate("/proc/",dir->d_name), &st);
struct passwd *pass;
pass = getpwuid(st.st_uid);
processID = atoi(dir->d_name);
//if we need to mess with the user
if (strcmp(type, "user") == 0) {
//if the process is owned by the blacklisted user
if (strcmp(pass->pw_name, param) == 0) {
//kill the process and report it
if (strcmp("kill", action) == 0) {
enterLog(logFile, createEntry(concatenate("Killing process number ", dir->d_name)));
if (kill(processID, SIGKILL) == 0)
enterLog(logFile, createEntry(concatenate("Successfully killed process number ", dir->d_name)));
else
enterLog(logFile, createEntry(concatenate("Did NOT successfully kill process number ", dir->d_name)));
//suspend the process and report it
} else if ((strcmp("suspend", action) == 0) && isSuspended(dir->d_name) == 0) {
enterLog(logFile, createEntry(concatenate("Suspending process number ", dir->d_name)));
if (kill(processID, SIGTSTP) == 0)
enterLog(logFile, createEntry(concatenate("Successfully suspended process number ", dir->d_name)));
else
enterLog(logFile, createEntry(concatenate("Did NOT successfully suspend process number ", dir->d_name)));
//nice the process and report it
} else if (strcmp("nice", action) == 0) {
if (getpriority(PRIO_PROCESS, processID) > -20) {
enterLog(logFile, createEntry(concatenate("Nicing process number ", dir->d_name)));
if (setpriority(PRIO_PROCESS, processID, LOWERPRIORITY) == 0)
enterLog(logFile, createEntry(concatenate("Successfully niced process number ", dir->d_name)));
else
enterLog(logFile, createEntry(concatenate("Did NOT successfully nice process number ", dir->d_name)));
}
}
}
//if we are affecting based on path
} else if (strcmp(type, "path") == 0) {
//pathname is the path found by readlink based on the pid
char * callingDir = malloc(70);
char * procpath = concatenate(concatenate("/proc/", dir->d_name), "/exe");
char root[256];
//read all of the exe files within the /proc/*/ directory
readlink(procpath, callingDir, 70);
//get first n characters of the string
strncpy(root, callingDir, strlen(param));
//null terminate destination
root[strlen(param)] = 0;
//if the directory matches the listed one
if (strcmp(root, param) == 0) {
//kill the process, report it
if (strcmp("kill", action) == 0) {
enterLog(logFile, createEntry(concatenate("Killing process number ", dir->d_name)));
if (kill(processID, SIGKILL) == 0)
enterLog(logFile, createEntry(concatenate("Successfully killed process number ", dir->d_name)));
else
enterLog(logFile, createEntry(concatenate("Did NOT successfully kill process number ", dir->d_name)));
//suspend the process, report it
} else if ((strcmp("suspend", action) == 0) && isSuspended(dir->d_name) == 0) {
enterLog(logFile, createEntry(concatenate("Suspending process number ", dir->d_name)));
if (kill(processID, SIGTSTP) == 0)
enterLog(logFile, createEntry(concatenate("Successfully suspended process number ", dir->d_name)));
else
enterLog(logFile, createEntry(concatenate("Did NOT successfully suspend process number ", dir->d_name)));
//nice the process
} else if (strcmp("nice", action) == 0) {
if (getpriority(PRIO_PROCESS, processID) > -20) {
enterLog(logFile, createEntry(concatenate("Nicing process number ", dir->d_name)));
if (setpriority(PRIO_PROCESS, processID, LOWERPRIORITY) == 0)
enterLog(logFile, createEntry(concatenate("Successfully niced process number ", dir->d_name)));
else
enterLog(logFile, createEntry(concatenate("Did NOT successfully nice process number ", dir->d_name)));
}
}
}
//if we are affecting based on memory
} else if (strcmp(type, "memory") == 0) {
//open the statm file of each process to read the mem usage
statmFile = fopen(concatenate(concatenate("/proc/", dir->d_name), "/statm"),"r");
if(statmFile == NULL){
continue;
} else {
//place the rss into a variable we can use. multiply by 4K to get the bytes used
fscanf(statmFile,"%ld %ld", ¬hing ,&actualMemoryUsed);
actualMemoryUsed *= 4096;
char * stringBytes = concatenate(param, "000000");
int numberBytesAllowed = atoi(stringBytes);
//if the process is using more than is allowed, handle it
if (actualMemoryUsed > numberBytesAllowed) {
if (strcmp("kill", action) == 0) {
enterLog(logFile, createEntry(concatenate("Killing process number ", dir->d_name)));
if (kill(processID, SIGKILL) == 0)
enterLog(logFile, createEntry(concatenate("Successfully killed process number ", dir->d_name)));
else
enterLog(logFile, createEntry(concatenate("Did NOT successfully kill process number ", dir->d_name)));
} else if ((strcmp("suspend", action) == 0) && isSuspended(dir->d_name) == 0) {
enterLog(logFile, createEntry(concatenate("Suspending process number ", dir->d_name)));
if (kill(processID, SIGTSTP) == 0)
enterLog(logFile, createEntry(concatenate("Successfully suspended process number ", dir->d_name)));
else
enterLog(logFile, createEntry(concatenate("Did NOT successfully suspend process number ", dir->d_name)));
} else if (strcmp("nice", action) == 0) {
//if the nice value is not already the lowest value, change it
if (getpriority(PRIO_PROCESS, processID) > -20) {
enterLog(logFile, createEntry(concatenate("Nicing process number ", dir->d_name)));
if (setpriority(PRIO_PROCESS, processID, LOWERPRIORITY) == 0)
enterLog(logFile, createEntry(concatenate("Successfully niced process number ", dir->d_name)));
else
enterLog(logFile, createEntry(concatenate("Did NOT successfully nice process number ", dir->d_name)));
}
}
}
}
fclose(statmFile);
}
}
closedir(d);
}
return SUCCESS;
}
void main (int argc, char *argv[]) {
//get the linux distribution for logging
uname(&linVersion);
//record when the program started
char *pHuntStartString = createEntry(startup());
char *tempString = malloc(50);
//default log and config files
char *log = "/var/log/phunt.log";
char *config = "/etc/phunt.conf";
char * line = NULL;
size_t length = 0;
ssize_t read;
char * command = " ";
char * action = " ";
char * type = " ";
char * param = " ";
signal(SIGINT, youDontControlMe);
parse_inputs(argc, argv, &log, &config);
FILE *logFile;
FILE *configFile;
openFiles(&logFile, &configFile, log, config);
//start logging important events
enterLog(&logFile, pHuntStartString);
//log the opening of the log file
enterLog(&logFile, createEntry(concatenate("opened logfile ", log)));
//log the start of parsing
enterLog(&logFile, createEntry(concatenate("parsing configuration file ", config)));
while(keepRunning) {
//start actually parsing
while ((read = getline(&line, &length, configFile)) != -1) {
//if this line is an actual command
if (line[0] != '#' && read > 1) {
command = strtok(line, " ");
action = command;
command = strtok (NULL, " ");
type = command;
command = strtok (NULL, " \n");
param = command;
killit(action, type, param, &logFile);
}
}
//wait one second and rewind to the top of the config file
sleep(1);
fseek(configFile, 0, SEEK_SET);
}
//enter the end of the program
enterLog(&logFile, createEntry("phunt ended, closing files."));
//close files when done
fclose(logFile);
fclose(configFile);
}