オープンソース・ソフトウェアの開発とダウンロード

Subversion リポジトリの参照

Contents of /branches/ccs-tools/ccstools/usr_sbin/ccs-queryd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3871 - (show annotations) (download) (as text)
Sun Aug 1 01:42:05 2010 UTC (13 years, 10 months ago) by kumaneko
File MIME type: text/x-csrc
File size: 16530 byte(s)


1 /*
2 * ccs-queryd.c
3 *
4 * TOMOYO Linux's utilities.
5 *
6 * Copyright (C) 2005-2010 NTT DATA CORPORATION
7 *
8 * Version: 1.8.0-pre 2010/08/01
9 *
10 */
11 #include "ccstools.h"
12 #include "readline.h"
13
14 #define CCS_GLOBALLY_READABLE_FILES_UPDATE_NONE 0
15 #define CCS_GLOBALLY_READABLE_FILES_UPDATE_ASK 1
16 #define CCS_GLOBALLY_READABLE_FILES_UPDATE_AUTO 2
17
18 /* Prototypes */
19
20 static void ccs_printw(const char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
21 static int ccs_send_encoded(const int fd, const char *fmt, ...) __attribute__ ((format(printf, 2, 3)));
22 static void ccs_do_check_update(const int fd);
23 static void ccs_handle_update(const int ccs_check_update, const int fd);
24 /*
25 static _Bool ccs_convert_path_info(FILE *fp, const struct ccs_path_info *pattern, const char *new);
26 */
27 static _Bool ccs_handle_query(unsigned int serial);
28
29 /* Utility functions */
30
31 static void ccs_printw(const char *fmt, ...)
32 {
33 va_list args;
34 int i;
35 int len;
36 char *buffer;
37 va_start(args, fmt);
38 len = vsnprintf((char *) &i, sizeof(i) - 1, fmt, args) + 16;
39 va_end(args);
40 buffer = malloc(len);
41 if (!buffer)
42 ccs_out_of_memory();
43 va_start(args, fmt);
44 len = vsnprintf(buffer, len, fmt, args);
45 va_end(args);
46 for (i = 0; i < len; i++) {
47 addch(buffer[i]);
48 refresh();
49 }
50 free(buffer);
51 }
52
53 static int ccs_send_encoded(const int fd, const char *fmt, ...)
54 {
55 va_list args;
56 int i;
57 int len;
58 char *buffer;
59 char *sp;
60 char *dp;
61 va_start(args, fmt);
62 len = vsnprintf((char *) &i, sizeof(i) - 1, fmt, args) + 16;
63 va_end(args);
64 buffer = malloc(len * 5);
65 if (!buffer)
66 ccs_out_of_memory();
67 va_start(args, fmt);
68 vsnprintf(buffer, len, fmt, args);
69 va_end(args);
70 sp = buffer;
71 dp = buffer + len;
72 while (true) {
73 unsigned char c = *(const unsigned char *) sp++;
74 if (!c) {
75 *dp++ = '\0';
76 break;
77 } else if (c == '\\') {
78 *dp++ = '\\';
79 *dp++ = '\\';
80 } else if (c > ' ' && c < 127) {
81 *dp++ = c;
82 } else {
83 *dp++ = '\\';
84 *dp++ = (c >> 6) + '0';
85 *dp++ = ((c >> 3) & 7) + '0';
86 *dp++ = (c & 7) + '0';
87 }
88 }
89 len = send(fd, buffer + len, strlen(buffer + len), 0);
90 free(buffer);
91 return len;
92 }
93
94 #if 0
95 static _Bool ccs_check_path_info(const char *buffer)
96 {
97 _Bool modified = false;
98 static struct ccs_path_info *update_list = NULL;
99 static int update_list_len = 0;
100 char *sp = strdup(buffer);
101 char *str = sp;
102 const char *path_list[2] = {
103 CCS_PROC_POLICY_EXCEPTION_POLICY,
104 CCS_PROC_POLICY_DOMAIN_POLICY
105 };
106 if (!str)
107 return false;
108 while (true) {
109 int i;
110 char *cp = strsep(&sp, " ");
111 if (!cp)
112 break;
113 for (i = 0; i < update_list_len; i++) {
114 int j;
115 struct ccs_path_info old;
116 /* TODO: split cp at upadte_list's depth. */
117 old.name = cp;
118 ccs_fill_path_info(&old);
119 if (!ccs_path_matches_pattern(&old, &update_list[i]))
120 continue;
121 for (j = 0; j < 2; j++) {
122 FILE *fp = fopen(path_list[j], "r+");
123 if (!fp)
124 continue;
125 if (convert_path_info(fp, &update_list[i], cp))
126 modified = true;
127 fclose(fp);
128 }
129 }
130 }
131 free(str);
132 return modified;
133 }
134 #endif
135
136 static void ccs_do_check_update(const int fd)
137 {
138 FILE *fp_in = fopen(CCS_PROC_POLICY_EXCEPTION_POLICY, "r");
139 char **pathnames = NULL;
140 int pathnames_len = 0;
141 char buffer[16384];
142 memset(buffer, 0, sizeof(buffer));
143 if (!fp_in) {
144 fprintf(stderr, "Can't open policy file.\n");
145 return;
146 }
147 while (fgets(buffer, sizeof(buffer) - 1, fp_in)) {
148 char *cp = strchr(buffer, '\n');
149 if (!cp)
150 break;
151 *cp = '\0';
152 if (!ccs_str_starts(buffer, "acl_group "))
153 continue;
154 cp = strchr(buffer, ' ');
155 if (!cp)
156 continue;
157 memmove(buffer, cp + 1, strlen(cp + 1) + 1);
158 if (!ccs_str_starts(buffer, "file read "))
159 continue;
160 if (!ccs_decode(buffer, buffer))
161 continue;
162 pathnames = realloc(pathnames, sizeof(char *) *
163 (pathnames_len + 1));
164 if (!pathnames)
165 ccs_out_of_memory();
166 pathnames[pathnames_len] = strdup(buffer);
167 if (!pathnames[pathnames_len])
168 ccs_out_of_memory();
169 pathnames_len++;
170 }
171 fclose(fp_in);
172 while (true) {
173 struct stat64 buf;
174 static time_t last_modified = 0;
175 int i;
176 sleep(1);
177 for (i = 0; i < pathnames_len; i++) {
178 int j;
179 if (!stat64(pathnames[i], &buf))
180 continue;
181 ccs_send_encoded(fd, "-%s", pathnames[i]);
182 free(pathnames[i]);
183 pathnames_len--;
184 for (j = i; j < pathnames_len; j++)
185 pathnames[j] = pathnames[j + 1];
186 i--;
187 }
188 if (stat64("/etc/ld.so.cache", &buf) ||
189 buf.st_mtime == last_modified)
190 continue;
191 fp_in = popen("/sbin/ldconfig -NXp", "r");
192 if (!fp_in)
193 continue;
194 last_modified = buf.st_mtime;
195 memset(buffer, 0, sizeof(buffer));
196 while (fgets(buffer, sizeof(buffer) - 1, fp_in)) {
197 char *cp = strchr(buffer, '\n');
198 char *real_pathname;
199 if (!cp)
200 break;
201 *cp = '\0';
202 cp = strrchr(buffer, ' ');
203 if (!cp || *++cp != '/')
204 continue;
205 if (stat64(cp, &buf))
206 continue;
207 real_pathname = realpath(cp, NULL);
208 if (!real_pathname)
209 continue;
210 for (i = 0; i < pathnames_len; i++) {
211 if (!strcmp(real_pathname, pathnames[i]))
212 break;
213 }
214 if (i == pathnames_len) {
215 char *cp;
216 pathnames = realloc(pathnames, sizeof(char *) *
217 (pathnames_len + 1));
218 if (!pathnames)
219 ccs_out_of_memory();
220 cp = strdup(real_pathname);
221 if (!cp)
222 ccs_out_of_memory();
223 pathnames[pathnames_len++] = cp;
224 ccs_send_encoded(fd, "+%s", pathnames[i]);
225 }
226 free(real_pathname);
227 }
228 pclose(fp_in);
229 }
230 }
231
232 #if 0
233 static _Bool ccs_convert_path_info(FILE *fp, const struct ccs_path_info *pattern,
234 const char *new)
235 {
236 _Bool modified = false;
237 const char *cp = pattern->name;
238 int depth = 0;
239 while (*cp)
240 if (*cp++ == '/')
241 depth++;
242 while (true) {
243 int d = depth;
244 char buffer[4096];
245 char *cp;
246 if (fscanf(fp, "%4095s", buffer) != 1)
247 break;
248 if (buffer[0] != '/')
249 goto out;
250 cp = buffer;
251 while (*cp) {
252 char c;
253 struct ccs_path_info old;
254 _Bool matched;
255 if (*cp != '/' || --d)
256 continue;
257 cp++;
258 c = *cp;
259 *cp = '\0';
260 old.name = buffer;
261 ccs_fill_path_info(&old);
262 matched = ccs_path_matches_pattern(&old, pattern);
263 *cp = c;
264 if (matched) {
265 fprintf(fp, "%s%s", new, cp);
266 modified = true;
267 buffer[0] = '\0';
268 break;
269 }
270 }
271 out:
272 fprintf(fp, "%s ", buffer);
273 }
274 return modified;
275 }
276 #endif
277
278 static void ccs_send_keepalive(void)
279 {
280 static time_t previous = 0;
281 time_t now = time(NULL);
282 if (previous != now || !previous) {
283 previous = now;
284 write(ccs_query_fd, "\n", 1);
285 }
286 }
287
288 static void ccs_handle_update(const int check_update, const int fd)
289 {
290 static FILE *fp = NULL;
291 char pathname[8192];
292 int c;
293 if (!fp)
294 fp = fopen(CCS_PROC_POLICY_EXCEPTION_POLICY, "w");
295 memset(pathname, 0, sizeof(pathname));
296 if (recv(fd, pathname, sizeof(pathname) - 1, 0) == EOF)
297 return;
298 if (check_update == CCS_GLOBALLY_READABLE_FILES_UPDATE_AUTO) {
299 if (pathname[0] == '-')
300 fprintf(fp, CCS_KEYWORD_DELETE);
301 fprintf(fp, "acl_group 0 file read %s\n", pathname + 1);
302 fflush(fp);
303 ccs_printw("The pathname %s was %s globally readable file.\n\n",
304 pathname + 1, (pathname[0] == '-') ?
305 "deleted. Deleted from" : "created. Appended to");
306 return;
307 }
308 ccs_printw("The pathname %s was %s globally readable file? ('Y'es/'N'o):",
309 pathname + 1, (pathname[0] == '-') ?
310 "deleted. Delete from" : "created. Append to");
311 while (true) {
312 c = ccs_getch2();
313 if (c == 'Y' || c == 'y' || c == 'N' || c == 'n')
314 break;
315 ccs_send_keepalive();
316 }
317 ccs_printw("%c\n", c);
318 if (c == 'Y' || c == 'y') {
319 if (pathname[0] == '-')
320 fprintf(fp, CCS_KEYWORD_DELETE);
321 fprintf(fp, "acl_group 0 file read %s\n", pathname + 1);
322 fflush(fp);
323 }
324 ccs_printw("\n");
325 }
326
327 /* Variables */
328
329 static unsigned short int ccs_retries = 0;
330
331 static int ccs_check_update = CCS_GLOBALLY_READABLE_FILES_UPDATE_AUTO;
332
333 static FILE *ccs_domain_fp = NULL;
334 static int ccs_domain_policy_fd = EOF;
335 #define CCS_MAX_READLINE_HISTORY 20
336 static const char **ccs_readline_history = NULL;
337 static int ccs_readline_history_count = 0;
338 static const int ccs_buffer_len = 32768;
339 static char *ccs_buffer = NULL;
340
341 /* Main functions */
342
343 static _Bool ccs_handle_query(unsigned int serial)
344 {
345 int c = 0;
346 int y;
347 int x;
348 char *line = NULL;
349 static unsigned int prev_pid = 0;
350 unsigned int pid;
351 time_t stamp;
352 char pidbuf[128];
353 char *cp = strstr(ccs_buffer, " (global-pid=");
354 if (!cp || sscanf(cp + 13, "%u", &pid) != 1) {
355 ccs_printw("ERROR: Unsupported query.\n");
356 return false;
357 }
358 cp = ccs_buffer + strlen(ccs_buffer);
359 if (*(cp - 1) != '\n') {
360 ccs_printw("ERROR: Unsupported query.\n");
361 return false;
362 }
363 *(cp - 1) = '\0';
364 /*
365 if (0 && !ccs_retries && check_path_info(ccs_buffer)) {
366 c = 'r';
367 goto write_answer;
368 }
369 */
370 if (pid != prev_pid) {
371 if (prev_pid)
372 ccs_printw("----------------------------------------\n");
373 prev_pid = pid;
374 }
375 if (sscanf(ccs_buffer, "#timestamp=%lu", &stamp) == 1) {
376 cp = strchr(ccs_buffer, ' ');
377 if (cp) {
378 struct tm *tm = localtime(&stamp);
379 ccs_printw("#%04d-%02d-%02d %02d:%02d:%02d#",
380 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
381 tm->tm_hour, tm->tm_min, tm->tm_sec);
382 memmove(ccs_buffer, cp, strlen(cp) + 1);
383 }
384 }
385 ccs_printw("%s\n", ccs_buffer);
386 /* Is this domain query? */
387 if (strstr(ccs_buffer, "\n#"))
388 goto not_domain_query;
389 memset(pidbuf, 0, sizeof(pidbuf));
390 snprintf(pidbuf, sizeof(pidbuf) - 1, "select global-pid=%u\n", pid);
391 ccs_printw("Allow? ('Y'es/'N'o/'R'etry/'S'how policy/'A'dd to policy "
392 "and retry):");
393 while (true) {
394 c = ccs_getch2();
395 if (c == 'Y' || c == 'y' || c == 'N' || c == 'n' || c == 'R' ||
396 c == 'r' || c == 'A' || c == 'a' || c == 'S' || c == 's')
397 break;
398 ccs_send_keepalive();
399 }
400 ccs_printw("%c\n", c);
401
402 if (c == 'S' || c == 's') {
403 if (ccs_network_mode) {
404 fprintf(ccs_domain_fp, "%s", pidbuf);
405 fputc(0, ccs_domain_fp);
406 fflush(ccs_domain_fp);
407 rewind(ccs_domain_fp);
408 while (1) {
409 char c;
410 if (fread(&c, 1, 1, ccs_domain_fp) != 1 || !c)
411 break;
412 addch(c);
413 refresh();
414 ccs_send_keepalive();
415 }
416 } else {
417 write(ccs_domain_policy_fd, pidbuf, strlen(pidbuf));
418 while (1) {
419 int i;
420 int len = read(ccs_domain_policy_fd, ccs_buffer,
421 ccs_buffer_len - 1);
422 if (len <= 0)
423 break;
424 for (i = 0; i < len; i++) {
425 addch(ccs_buffer[i]);
426 refresh();
427 }
428 ccs_send_keepalive();
429 }
430 }
431 c = 'r';
432 }
433
434 /* Append to domain policy. */
435 if (c != 'A' && c != 'a')
436 goto not_append;
437 c = 'r';
438 getyx(stdscr, y, x);
439 cp = strrchr(ccs_buffer, '\n');
440 if (!cp)
441 return false;
442 *cp++ = '\0';
443 ccs_initial_readline_data = cp;
444 ccs_readline_history_count = ccs_add_history(cp, ccs_readline_history,
445 ccs_readline_history_count,
446 CCS_MAX_READLINE_HISTORY);
447 line = ccs_readline(y, 0, "Enter new entry> ", ccs_readline_history,
448 ccs_readline_history_count, 128000, 8);
449 scrollok(stdscr, TRUE);
450 ccs_printw("\n");
451 if (!line || !*line) {
452 ccs_printw("None added.\n");
453 goto not_append;
454 }
455 ccs_readline_history_count = ccs_add_history(line, ccs_readline_history,
456 ccs_readline_history_count,
457 CCS_MAX_READLINE_HISTORY);
458 if (ccs_network_mode) {
459 fprintf(ccs_domain_fp, "%s%s\n", pidbuf, line);
460 fflush(ccs_domain_fp);
461 } else {
462 write(ccs_domain_policy_fd, pidbuf, strlen(pidbuf));
463 write(ccs_domain_policy_fd, line, strlen(line));
464 write(ccs_domain_policy_fd, "\n", 1);
465 }
466 ccs_printw("Added '%s'.\n", line);
467 not_append:
468 free(line);
469 write_answer:
470 /* Write answer. */
471 if (c == 'Y' || c == 'y' || c == 'A' || c == 'a')
472 c = 1;
473 else if (c == 'R' || c == 'r')
474 c = 3;
475 else
476 c = 2;
477 snprintf(ccs_buffer, ccs_buffer_len - 1, "A%u=%u\n", serial, c);
478 write(ccs_query_fd, ccs_buffer, strlen(ccs_buffer));
479 ccs_printw("\n");
480 return true;
481 not_domain_query:
482 ccs_printw("Allow? ('Y'es/'N'o/'R'etry):");
483 while (true) {
484 c = ccs_getch2();
485 if (c == 'Y' || c == 'y' || c == 'N' || c == 'n' ||
486 c == 'R' || c == 'r')
487 break;
488 ccs_send_keepalive();
489 }
490 ccs_printw("%c\n", c);
491 goto write_answer;
492 }
493
494 int main(int argc, char *argv[])
495 {
496 int pipe_fd[2] = { EOF, EOF };
497 if (argc == 1)
498 goto ok;
499 {
500 char *cp = strchr(argv[1], ':');
501 if (cp) {
502 *cp++ = '\0';
503 ccs_network_ip = inet_addr(argv[1]);
504 ccs_network_port = htons(atoi(cp));
505 ccs_network_mode = true;
506 if (!ccs_check_remote_host())
507 return 1;
508 ccs_check_update = CCS_GLOBALLY_READABLE_FILES_UPDATE_NONE;
509 goto ok;
510 }
511 }
512 if (!strcmp(argv[1], "--no-update")) {
513 ccs_check_update = CCS_GLOBALLY_READABLE_FILES_UPDATE_NONE;
514 goto ok;
515 }
516 if (!strcmp(argv[1], "--ask-update")) {
517 ccs_check_update = CCS_GLOBALLY_READABLE_FILES_UPDATE_ASK;
518 goto ok;
519 }
520 printf("Usage: %s [--no-update|--ask-update|remote_ip:remote_port]\n\n",
521 argv[0]);
522 printf("This program is used for granting access requests manually.\n");
523 printf("This program shows access requests that are about to rejected "
524 "by the kernel's decision.\n");
525 printf("If you answer before the kernel's decision taken effect, your "
526 "decision will take effect.\n");
527 printf("You can use this program to respond to accidental access "
528 "requests triggered by non-routine tasks (such as restarting "
529 "daemons after updating).\n");
530 printf("To terminate this program, use 'Ctrl-C'.\n");
531 return 0;
532 ok:
533 if (ccs_network_mode) {
534 ccs_query_fd = ccs_open_stream("proc:query");
535 ccs_domain_fp = ccs_open_write(CCS_PROC_POLICY_DOMAIN_POLICY);
536 } else {
537 ccs_query_fd = open(CCS_PROC_POLICY_QUERY, O_RDWR);
538 ccs_domain_policy_fd = open(CCS_PROC_POLICY_DOMAIN_POLICY, O_RDWR);
539 }
540 if (ccs_query_fd == EOF) {
541 fprintf(stderr,
542 "You can't run this utility for this kernel.\n");
543 return 1;
544 } else if (!ccs_network_mode && write(ccs_query_fd, "", 0) != 0) {
545 fprintf(stderr, "You need to register this program to %s to "
546 "run this program.\n", CCS_PROC_POLICY_MANAGER);
547 return 1;
548 }
549 if (ccs_check_update != CCS_GLOBALLY_READABLE_FILES_UPDATE_NONE) {
550 socketpair(AF_UNIX, SOCK_DGRAM, 0, pipe_fd);
551 switch (fork()) {
552 case 0:
553 if (ccs_domain_fp)
554 fclose(ccs_domain_fp);
555 else
556 close(ccs_domain_policy_fd);
557 close(ccs_query_fd);
558 close(pipe_fd[0]);
559 ccs_do_check_update(pipe_fd[1]);
560 _exit(0);
561 case -1:
562 fprintf(stderr, "Can't fork().\n");
563 return 1;
564 }
565 close(pipe_fd[1]);
566 pipe_fd[1] = EOF;
567 }
568 ccs_readline_history = malloc(CCS_MAX_READLINE_HISTORY * sizeof(const char *));
569 if (!ccs_readline_history)
570 ccs_out_of_memory();
571 ccs_send_keepalive();
572 initscr();
573 cbreak();
574 noecho();
575 nonl();
576 intrflush(stdscr, FALSE);
577 keypad(stdscr, TRUE);
578 clear();
579 refresh();
580 scrollok(stdscr, TRUE);
581 if (ccs_network_mode) {
582 const u32 ip = ntohl(ccs_network_ip);
583 ccs_printw("Monitoring /proc/ccs/query via %u.%u.%u.%u:%u.",
584 (u8) (ip >> 24), (u8) (ip >> 16), (u8) (ip >> 8),
585 (u8) ip, ntohs(ccs_network_port));
586 } else
587 ccs_printw("Monitoring /proc/ccs/query %s.",
588 ccs_check_update != CCS_GLOBALLY_READABLE_FILES_UPDATE_NONE ?
589 "and /etc/ld.so.cache " : "");
590 ccs_printw(" Press Ctrl-C to terminate.\n\n");
591 while (true) {
592 static _Bool first = true;
593 static unsigned int prev_serial = 0;
594 fd_set rfds;
595 unsigned int serial;
596 char *cp;
597 if (!ccs_buffer) {
598 ccs_buffer = malloc(ccs_buffer_len);
599 if (!ccs_buffer)
600 break;
601 }
602 /* Wait for query. */
603 if (ccs_network_mode) {
604 int i;
605 write(ccs_query_fd, "", 1);
606 memset(ccs_buffer, 0, ccs_buffer_len);
607 for (i = 0; i < ccs_buffer_len - 1; i++) {
608 if (read(ccs_query_fd, ccs_buffer + i, 1) != 1)
609 break;
610 if (!ccs_buffer[i])
611 goto read_ok;
612 }
613 break;
614 }
615 FD_ZERO(&rfds);
616 FD_SET(ccs_query_fd, &rfds);
617 if (pipe_fd[0] != EOF)
618 FD_SET(pipe_fd[0], &rfds);
619 select(ccs_query_fd > pipe_fd[0] ? ccs_query_fd + 1 : pipe_fd[0] + 1,
620 &rfds, NULL, NULL, NULL);
621 if (pipe_fd[0] != EOF && FD_ISSET(pipe_fd[0], &rfds))
622 ccs_handle_update(ccs_check_update, pipe_fd[0]);
623 if (!FD_ISSET(ccs_query_fd, &rfds))
624 continue;
625
626 /* Read query. */
627 memset(ccs_buffer, 0, ccs_buffer_len);
628 if (read(ccs_query_fd, ccs_buffer, ccs_buffer_len - 1) <= 0)
629 continue;
630 read_ok:
631 cp = strchr(ccs_buffer, '\n');
632 if (!cp)
633 continue;
634 *cp = '\0';
635
636 /* Get query number. */
637 if (sscanf(ccs_buffer, "Q%u-%hu", &serial, &ccs_retries) != 2)
638 continue;
639 memmove(ccs_buffer, cp + 1, strlen(cp + 1) + 1);
640
641 first = false;
642 prev_serial = serial;
643 /* Clear pending input. */;
644 timeout(0);
645 while (true) {
646 int c = ccs_getch2();
647 if (c == EOF || c == ERR)
648 break;
649 }
650 timeout(1000);
651 if (ccs_handle_query(serial))
652 continue;
653 break;
654 }
655 endwin();
656 return 0;
657 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26