💾 Archived View for gemini.rmf-dev.com › repo › Vaati › JailWarden › files › dfb243bc6fffa2ddf4faf12… captured on 2023-05-24 at 18:14:45. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-03-20)

➡️ Next capture (2023-09-08)

-=-=-=-=-=-=-

0 /*

1 * Copyright (c) 2021 RMF <rawmonk@firemail.cc>

2 *

3 * Permission to use, copy, modify, and distribute this software for any

4 * purpose with or without fee is hereby granted, provided that the above

5 * copyright notice and this permission notice appear in all copies.

6 *

7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES

8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR

10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES

11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN

12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF

13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

14 */

15

16 #include <stdio.h>

17 #include <stdlib.h>

18 #include <unistd.h>

19 #include <sys/param.h>

20 #include <sys/jail.h>

21 #include <sys/types.h>

22 #include <sys/stat.h>

23 #include <sys/wait.h>

24 #include <jail.h>

25 #include <string.h>

26 #include <cjson/cJSON.h>

27 #include "sha256.h"

28

29 #define CONF_PATH "/usr/local/etc/jailwarden.conf"

30

31 char** global_check;

32 char** global_ignore;

33 int global_check_len;

34 int global_ignore_len;

35 char* data_dir;

36

37 typedef struct cjail {

38 int id;

39 char* name;

40 char** check;

41 char** ignore;

42 int check_len;

43 int ignore_len;

44 } cjail;

45 cjail* jails = NULL;

46 int jails_len = 0;

47 int jail_arg = -1;

48 int jail_selected = -1;

49 char* jail_selected_name = NULL;

50

51 int to_ignore(char* path, int jid) {

52 for(int i=0; i<global_ignore_len; i++)

53 if(strcmp(path,global_ignore[i])==0) return 1;

54 for(int i=0; i<jails[jid].ignore_len; i++)

55 if(strcmp(path,jails[jid].ignore[i])==0) { printf("|%s| {%s} (%d)\n",path,jails[jid].ignore[i],jid);

56 return 1; }

57 return 0;

58 }

59

60 #include <sys/syslimits.h>

61 #include <dirent.h>

62 int list_files(FILE* f, char* path, int jid) {

63 DIR * d;

64 d = opendir(path);

65

66 if(!d) {

67 printf ("[%d][Error] Cannot open directory '%s'\n", jails[jid].id, path);

68 return 0;

69 }

70 int count = 0;

71 while (1) {

72 struct dirent * entry;

73 entry = readdir (d);

74 if (!entry) {

75 break;

76 }

77 if(strcmp(entry->d_name,"..")==0||strcmp(entry->d_name,".")==0) continue;

78 char npath[PATH_MAX];

79 strcpy(npath, path);

80 strcat(npath, "/");

81 strcat(npath, entry->d_name);

82 if(to_ignore(npath, jid)) continue; //return count;

83 if(entry->d_type==4) {

84 count += list_files(f, npath, jid);

85 } else if(entry->d_type==8) {

86 unsigned char buf[32];

87 if(sha256_file(npath, buf)) continue;

88 fprintf(f, "%s ", npath);

89 for(int i=0; i<32; i++) fprintf(f, "%02X", buf[i]);

90 fprintf(f, "\n");

91 count++;

92 }

93 }

94

95 if (closedir (d)) {

96 printf("[%d][Error] Could not close '%s'\n", jails[jid].id, path);

97 }

98 return count;

99 }

100

101 int db_write(FILE* f, int jid) {

102 int count = 0;

103 for(int i=0; i<global_check_len; i++)

104 count += list_files(f, global_check[i], jid);

105 for(int i=0; i<jails[jid].check_len; i++) {

106 for(int j=0; j<global_check_len; j++) {

107 if(strlen(global_check[j])>strlen(jails[jid].check[i])) {

108 if(memcmp(jails[jid].check[i],global_check[j],strlen(jails[jid].check[i]))==0) continue;

109 } else {

110 if(memcmp(jails[jid].check[i],global_check[j],strlen(global_check[j]))==0) continue;

111 }

112 }

113 count += list_files(f, jails[jid].check[i], jid);

114 }

115 printf("[%d][Info] %d file fingerprints updated succesfully\n", jails[jid].id, count);

116 return 0;

117 }

118

119 int db_read(FILE* f, int jid) {

120 char buf[PATH_MAX*2];

121 char * line = NULL;

122 size_t len = 0;

123 ssize_t read;

124

125 int count = 0;

126 int wrong = 0;

127 while ((read = getline(&line, &len, f)) != -1) {

128 line[read-1] = 0;

129 char* hash = strrchr(line,' ');

130 hash[0] = 0;

131 hash++;

132 uint8_t h[32];

133 int ret = sha256_file(line,h);

134 if(ret==-1) {

135 printf("[%d][Warning] %s was deleted\n", jails[jid].id, line);

136 wrong++;

137 continue;

138 } else if(ret==-2) {

139 printf("[%d][Warning] %s became too big to be verified\n", jails[jid].id, line);

140 wrong++;

141 continue;

142 }

143 int same = 1;

144 for(int i=0; i<64; i+=2) {

145 char nbuf[3];

146 nbuf[0] = hash[i];

147 nbuf[1] = hash[i+1];

148 nbuf[2] = 0;

149 uint8_t i8 = strtol(nbuf, NULL, 16);

150 if(i8!=h[i/2]) {

151 same=0;

152 break;

153 }

154 }

155 if(!same) {

156 printf("[%d][Warning] Wrong hash, %s, %s != ", jails[jid].id, line, hash);

157 for(int i=0; i<32; i++) printf("%02X", (unsigned char)h[i]);

158 printf("\n");

159 wrong++;

160 }

161 count++;

162

163 }

164 if(wrong)

165 printf("[%d][Warning] %d files verified, %d %s changed\n", jails[jid].id, count, wrong, wrong==1?"file":"files");

166 else

167 printf("[%d][Info] %d files verified succesfully\n", jails[jid].id, count);

168 return wrong;

169 }

170

171 #include <sys/uio.h>

172 #include <errno.h>

173 int fetch_jails() {

174 struct iovec iov[4];

175 u_int niov;

176 int ret;

177 int flags = 0;

178 int jid = 0;

179 char empty[] = "";

180 int jail_id;

181

182 for(int i=0; 1; i++) {

183

184 *(const void **)&iov[0].iov_base = "lastjid";

185 iov[0].iov_len = strlen("lastjid")+1;

186 iov[1].iov_base = &jid;

187 iov[1].iov_len = sizeof(jid);

188

189 if( ( jail_id = jail_get(iov, 2, flags) ) == -1 ) {

190 if( errno == ENOENT ) {

191 jails_len = i;

192 return i;

193 }

194 else {

195 jails_len = i;

196 return -1;

197 }

198 }

199 if(jail_id==-1) {

200 jails_len = i;

201 return i;

202 }

203

204 if(jails==NULL) jails = malloc(sizeof(cjail));

205 else jails = realloc(jails, sizeof(cjail)*(i+1));

206 memset(&jails[i], 0, sizeof(cjail));

207 jails[i].id = jail_id;

208 jails[i].name = jail_getname(jail_id);

209

210 jid = jail_id;

211 }

212 }

213

214 int main(int argc, char* argv[]) {

215

216 if(geteuid() != 0) {

217 printf("%s: Program must be run as root\n", argv[0]);

218 return -1;

219 }

220

221 if(argc<2) {

222 printf("%s: Not enough arguments\n", argv[0]);

223 arg_err:

224 printf("Usage: %s <check|update> [jail id]\n", argv[0]);

225 return -1;

226 }

227

228 int read;

229 if(strcmp(argv[1],"check")==0) read = 1;

230 else if(strcmp(argv[1],"update")==0) read = 0;

231 else {

232 printf("%s: Wrong arguments\n", argv[0]);

233 goto arg_err;

234 }

235

236 if(argc>2) {

237 jail_arg = atoi(argv[2]);

238 if(jail_arg<1) {

239 printf("%s: Invalid jail id\n", argv[0]);

240 goto arg_err;

241 }

242 jail_selected_name = jail_getname(jail_arg);

243 if(jail_selected_name==NULL) {

244 printf("%s: No jail with the id %d found\n", argv[0], jail_arg);

245 goto arg_err;

246 }

247 printf("[INFO] %s jail selected\n", jail_selected_name);

248 }

249

250 FILE* conf = fopen(CONF_PATH, "rb");

251 if(!conf) {

252 printf("[ERROR] No configuration file found at %s\n", CONF_PATH);

253 return -1;

254 }

255 fseek(conf, 0, SEEK_END);

256 int len = ftell(conf);

257 fseek(conf, 0, SEEK_SET);

258 char* data = malloc(len);

259 fread(data, 1, len, conf);

260 fclose(conf);

261 cJSON *json = cJSON_ParseWithLength(data, len);

262 free(data);

263 if(!json) {

264 conf_err:

265 printf("[ERROR] Invalid configuration file %s\n",cJSON_GetErrorPtr());

266 return -1;

267 }

268

269 cJSON *json_dir = cJSON_GetObjectItem(json, "data_dir");

270 if(!json_dir) goto conf_err;

271 if(!cJSON_IsString(json_dir)) goto conf_err;

272 data_dir = cJSON_GetStringValue(json_dir);

273 struct stat st = {0};

274 if (stat(data_dir, &st) == -1) {

275 if(mkdir(data_dir, 0700)==-1) {

276 printf("[ERROR] Failed to create data directory\n");

277 return -1;

278 }

279 }

280

281 int fetched = 0;

282 if(jail_selected_name == NULL) {

283 cJSON *json_fetch = cJSON_GetObjectItem(json, "all_jails");

284 if(json_fetch) {

285 if(!cJSON_IsBool(json_fetch)) goto conf_err;

286 if(cJSON_IsTrue(json_fetch)) {

287 if(fetch_jails()==-1) {

288 printf("[ERROR] Failed to list jails\n");

289 return -1;

290 }

291 if(jails_len==0) {

292 printf("[ERROR] No jail is currently running\n");

293 return -1;

294 }

295 fetched = 1;

296 }

297 }

298 }

299

300 cJSON *json_jails = cJSON_GetObjectItem(json, "jails");

301 if(!json_jails) goto conf_err;

302 len = cJSON_GetArraySize(json_jails);

303 if(jails==NULL)

304 jails = malloc(sizeof(cjail)*(jail_selected==-1?len:1));

305 int i=0;

306 for(; i<len; i++) {

307 cjail jail;

308 memset(&jail, 0, sizeof(cjail));

309 cJSON* item = cJSON_GetArrayItem(json_jails, i);

310 if(!item) break;

311 if(!item->string) break;

312 int global = 0;

313 if(strcmp(item->string,"*")==0) global = 1;

314 else jail.id = jail_getid(item->string);

315 if(!global) {

316 if(jail_selected_name!=NULL&&strcmp(item->string,jail_selected_name))

317 continue;

318 if(jail.id==-1) {

319 printf("[ERROR] No jail named %s\n", item->string);

320 return -1;

321 }

322 jail.name = malloc(strlen(item->string));

323 strcpy(jail.name,item->string);

324 }

325 cJSON* check = cJSON_GetObjectItem(item,"check");

326 if(check) {

327 int l = cJSON_GetArraySize(check);

328 if(global) global_check_len = l;

329 else jail.check_len = l;

330 char*** ptr = global?&global_check:&jail.check;

331 *ptr = malloc(sizeof(void*)*l);

332 for(int j=0; j<l; j++) {

333 cJSON* sitem = cJSON_GetArrayItem(check, j);

334 if(!cJSON_IsString(sitem)) {

335 break;

336 }

337 char* str = malloc(strlen(sitem->valuestring));

338 strcpy(str,sitem->valuestring);

339 (*ptr)[j] = str;

340 }

341 }

342 cJSON* ignore = cJSON_GetObjectItem(item,"ignore");

343 if(ignore) {

344 int l = cJSON_GetArraySize(ignore);

345 if(global) global_ignore_len = l;

346 else jail.ignore_len = l;

347 char*** ptr = global?&global_ignore:&jail.ignore;

348 *ptr = malloc(sizeof(void*)*l);

349 for(int j=0; j<l; j++) {

350 cJSON* sitem = cJSON_GetArrayItem(ignore, j);

351 if(!cJSON_IsString(sitem)) {

352 break;

353 }

354 char* str = malloc(strlen(sitem->valuestring));

355 strcpy(str,sitem->valuestring);

356 (*ptr)[j] = str;

357 }

358 }

359 if(global) continue;

360 if(fetched) {

361 for(int j=0; j<jails_len; j++) if(jails[j].id==jail.id) {

362 free(jails[j].name);

363 jails[j]=jail;

364 }

365 } else {

366 jails[jails_len] = jail;

367 jails_len++;

368 if(jail.id == jail_arg)

369 jail_selected = jails_len-1;

370 }

371 }

372 if(i!=len) goto conf_err;

373 cJSON_Delete(json);

374

375 if(jails_len==0) {

376 memset(jails, 0, sizeof(cjail));

377 jails[0].id=jail_arg;

378 jails[0].name=jail_selected_name;

379 jails_len++;

380 }

381

382 int parent = 0;

383 for(int i=0; i<jails_len; i++) {

384 if (fork() == 0) {

385 printf("[%d][Info] %s database for jail %s\n", jails[i].id, read?"Verifying":"Writting", jails[i].name);

386 char* path = malloc(strlen(data_dir)+strlen(jails[i].name)+5);

387 strcpy(path, data_dir);

388 strcat(path, "/");

389 strcat(path, jails[i].name);

390 strcat(path, ".dat");

391 FILE* db = fopen(path, read?"rb":"wb");

392 if(!db) {

393 printf("[%d][Error] There's no database for jail %s yet, aborting verification\n", jails[i].id, jails[i].name);

394 return -1;

395 }

396 free(path);

397

398 int ret = jail_attach(jails[i].id);

399 if(ret==-1) {

400 printf("[%d][Error] Cannot attach process to jail %s\n", jails[i].id, jails[i].name);

401 return -1;

402 }

403

404 if(read) db_read(db, i);

405 else db_write(db, i);

406

407 fclose(db);

408 printf("[%d][Info] Database for jail %s %s succesfully\n", jails[i].id, jails[i].name, read?"verified":"updated");

409 return 0;

410 } else parent = 1;

411 }

412 for(int i=0; i<jails_len&&parent; i++)

413 wait(NULL);

414 return 0;

415 }

416