aaaaaa123456789 icon

Flash policy daemon

aaaaaa123456789 | PRO | 12/03/13 03:07:09 AM UTC | 0 ⭐ | 428 👁️ | Never ⏰ | []
C |

6.64 KB

|

None

|

0 👍

/

0 👎

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
 
int get_policy_data(const char *, void **);
void generate_error(int, const char *, const char *);
void process_reload_signal(int);
int create_socket(unsigned short);
void parse_requests(int, void *, int, const char *, const char *);
int create_fdset(fd_set *, int *, unsigned, int);
int * array_add(int *, unsigned, int);
int * array_remove(int *, unsigned, int);
void send_policy_info(int, void *, unsigned);
 
volatile sig_atomic_t reload_next;
 
int main (int argc, char ** argv) {
  if (argc != 2) generate_error(1, *argv, argv[1]);
  void * policydata;
  int policylength = get_policy_data(argv[1], &policydata);
  if (policylength < 0) generate_error(-policylength, *argv, argv[1]);
  reload_next = 0;
  int socketnumber = create_socket(843);
  if (socketnumber < 0) generate_error(2, *argv, argv[1]);
  if (signal(SIGHUP, &process_reload_signal) == SIG_ERR)
    fprintf(stderr, "%s: could not install SIGHUP handler\n", *argv);
  parse_requests(socketnumber, policydata, policylength, *argv, argv[1]);
  close(socketnumber);
  return 0;
}
 
int get_policy_data (const char * filename, void ** data) {
  int fd = open(filename, 0);
  if (fd < 0)
    switch (errno) {
      case EACCES: return -3;
      case ENOENT: case ENOTDIR: return -4;
      default: return -5;
    }
  struct stat statdata;
  if(fstat(fd, &statdata)) {
    close(fd);
    return -5;
  }
  int remainder = statdata.st_size;
  int size = remainder;
  *data = malloc(size + 1);
  char * readp = *data;
  int readsize;
  while (remainder > 0) {
    readsize = read(fd, readp, remainder);
    if (readsize > 0) {
      remainder -= readsize;
      readp += readsize;
      continue;
    }
    if (!readsize) {
      size = readp - ((char *) (*data));
      break;
    }
    if ((errno == EINTR) || (errno = EAGAIN)) continue;
    close(fd);
    if (errno == EISDIR) return -6;
    return -5;
  }
  close(fd);
  ((char *) (*data))[size] = 0;
  return size + 1;
}
 
void generate_error (int error, const char * programname, const char * filename) {
  switch (error) {
    case 1:
      fprintf(stderr, "usage: %s policyfile\n", programname);
      break;
    case 2:
      fprintf(stderr, "%s: could not create listening socket on port 843\n", programname);
      break;
    case 3:
      fprintf(stderr, "%s: permission denied when accessing policy file %s\n", programname, filename);
      break;
    case 4:
      fprintf(stderr, "%s: policy file %s does not exist\n", programname, filename);
      break;
    case 5:
      fprintf(stderr, "%s: unknown error accessing policy file %s\n", programname, filename);
      break;
    case 6:
      fprintf(stderr, "%s: policy file %s is actually a directory\n", programname, filename);
      break;
  }
  exit(error);
}
 
void process_reload_signal (int signalnumber) {
  reload_next = 1;
}
 
int create_socket (unsigned short port) {
  int number = socket(AF_INET, SOCK_STREAM || SOCK_NONBLOCK, 0);
  if (number < 0) return -1;
  struct sockaddr_in sa;
  sa.sin_family = AF_INET;
  sa.sin_port = htons(port);
  sa.sin_addr.s_addr = INADDR_ANY;
  if (bind(number, (struct sockaddr *) &sa, sizeof sa)) {
    close(number);
    return -1;
  }
  if (listen(number, 128)) {
    close(number);
    return -1;
  }
  return number;
}
 
void parse_requests (int socketnumber, void * policydata, int policylength, const char * programname, const char * filename) {
  struct timeval tv = {.tv_sec = 5, .tv_usec = 0};
  struct timeval tvs;
  int cont = 1;
  int result;
  fd_set fdset;
  int * clients = NULL;
  unsigned clientcount = 0;
  int * copy;
  unsigned current, limit;
  while (cont) {
    result = create_fdset(&fdset, clients, clientcount, socketnumber);
    tvs = tv;
    result = select(result, &fdset, NULL, NULL, &tvs);
    if (reload_next) {
      void * newdata;
      int status = get_policy_data(filename, &newdata);
      if (status < 0)
        fprintf(stderr, "%s: could not reload policy data from %s\n", programname, filename);
      else {
        free(policydata);
        policydata = newdata;
        policylength = status;
      }
      reload_next = 0;
    }
    if (result <= 0) continue;
    copy = malloc(clientcount * sizeof(int));
    memcpy(copy, clients, clientcount * sizeof(int));
    limit = clientcount;
    if (FD_ISSET(socketnumber, &fdset)) {
      int newsocket = accept(socketnumber, NULL, NULL);
      if (newsocket > 0) clients = array_add(clients, clientcount ++, newsocket);
    }
    for (current = 0; current < limit; current ++)
      if (FD_ISSET(copy[current], &fdset)) {
        char buffer[1024];
        int reception = recv(copy[current], buffer, 1024, MSG_DONTWAIT);
        if (!reception) {
          close(copy[current]);
          clients = array_remove(clients, clientcount --, copy[current]);
        }
        if (reception <= 0) continue;
        unsigned short pos;
        for (pos = 0; pos < reception; pos ++)
          if (!buffer[pos])
            send_policy_info(copy[current], policydata, policylength);
      }
    free(copy);
  }
}
 
int create_fdset (fd_set * fdset, int * fds, unsigned count, int listener) {
  int * max = fds + count;
  int * current;
  int maxfd = listener + 1;
  FD_ZERO(fdset);
  FD_SET(listener, fdset);
  for (current = fds; current < max; current ++) {
    if (*current >= maxfd) maxfd = *current + 1;
    FD_SET(*current, fdset);
  }
  return maxfd;
}
 
int * array_add (int * array, unsigned length, int new) {
  array = realloc(array, sizeof(int) * (length + 1));
  array[length] = new;
  return array;
}
 
int * array_remove (int * array, unsigned length, int item) {
  if (!length) {
    free(array);
    return NULL;
  }
  unsigned position;
  for (position = 0; position < length; position ++)
    if (array[position] == item) break;
  if (position >= length) return array;
  array[position] = array[-- length];
  return realloc(array, sizeof(int) * length);
}
 
void send_policy_info (int destsocket, void * data, unsigned length) {
  char * pending = data;
  unsigned size = length;
  int status, retries = 0;
  while (size) {
    status = send(destsocket, pending, size, MSG_NOSIGNAL);
    if (status >= 0) {
      retries = 0;
      size -= status;
      pending += status;
      continue;
    }
    if (errno == EPIPE) return;
    retries ++;
    if (retries >= 3) return;
  }
}

Comments