示例#1
0
/** set_timeout
    check for a regex match on the -t flag
    (could be on argv[i] or argv[i+1])
    get the timeout number
    convert to seconds if needed
    ex: to shut the server down in 4 hours:
    -t4h OR -t4 OR -t 4 OR -t 4h
*/
void set_timeout (char **argv, int *i, void *var) {
  int val = 0;
  int m = 4; /* number of parenthasized expressions being match +1 */
  regex_t preg;
  regmatch_t pmatch[m];
  if (0 != regcomp(&preg, "^(-t)?([0-9]+)([d,h,m,s])?$", REG_EXTENDED)) {
    dprintf (STDERR_FILENO,
	     "Error in matcher, using default value %d for timeout\n", DEFAULT_T);
    *((int*)var) = DEFAULT_T;
    return;
  }
  
  if (0 == regexec(&preg, argv[(*i)], (size_t)m, pmatch, 0)) {
    /* flags were -tTIMEc */
    val = _set_timeout (argv, *i, pmatch[2], pmatch[3]);
  } else if (argv[(*i)+1] && 0 == regexec(&preg, argv[(*i)+1], (size_t)m, pmatch, 0)) {
    /* flags were -t TIMEc */
    val = _set_timeout (argv, (*i)+1, pmatch[2], pmatch[3]);
  } else  { /* regex did not match */
    val = DEFAULT_T;
  }
  
  regfree(&preg);
  _set_var_to_int(var, val, MIN_T, MAX_T, DEFAULT_T);
}
示例#2
0
int main(int argc, char *argv[]) {
	/* a request */
	request_t request = {{0}};

	/* resolving hints */
	struct addrinfo hints = {0};

	/* the address of a client */
	struct sockaddr client_address = {0};

	/* the daemon data */
	daemon_t daemon_data = {{{0}}};

	/* the request size */
	ssize_t size = 0;

	/* the client address size */
	socklen_t address_size = 0;

	/* the exit code */
	int exit_code = EXIT_FAILURE;

	/* a received signal */
	int received_signal = 0;

	/* child process ID */
	pid_t pid = 0;

	/* the local address */
	struct addrinfo *address = NULL;

	/* the file path */
	const char *path = NULL;

	/* the transfer mode */
	const char *mode = NULL;

	/* make sure the number of command-line arguments is valid */
	if (1 != argc) {
		PRINT(USAGE);
		goto end;
	}

	/* resolve the local address */
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_V4MAPPED;
	if (0 != getaddrinfo(NULL, LISTENING_PORT, &hints, &address)) {
		goto end;
	}

	/* create a socket */
	daemon_data.fd = socket(address->ai_family,
	                        address->ai_socktype,
	                        address->ai_protocol);
	if (-1 == daemon_data.fd) {
		goto free_address;
	}

	/* set the socket timeout */
	if (false == _set_timeout(daemon_data.fd)) {
		goto end;
	}

	/* bind the socket */
	if (-1 == bind(daemon_data.fd, address->ai_addr, address->ai_addrlen)) {
		goto close_socket;
	}

	/* open the system log*/
	openlog("tftpd", LOG_NDELAY, LOG_DAEMON);

	/* initialize the daemon */
	if (false == daemon_init(&daemon_data, SERVER_ROOT, DAEMON_USER)) {
		goto close_log;
	}

	do {
		/* wait for a request */
		if (false == daemon_wait(&daemon_data, &received_signal)) {
			break;
		}

		/* if the received signal is a termination one, report success */
		if (SIGTERM == received_signal) {
			break;
		}

		/* receive the request */
		address_size = sizeof(client_address);
		size = recvfrom(daemon_data.fd,
		                (void *) request.data,
		                sizeof(request.data),
		                0,
		                &client_address,
		                &address_size);
		switch (size) {
			case 0:
				/* if it was nothing but a scan, ignore it */
				continue;

			case (-1):
				goto close_log;
		}

		/* make sure the request isn't too small */
		if (MIN_REQUEST_SIZE > size) {
			continue;
		}

		/* make sure the request is valid */
		request.header.opcode = ntohs(request.header.opcode);
		switch (request.header.opcode) {
			case PACKET_TYPE_RRQ:
			case PACKET_TYPE_WRQ:
				break;

			default:
				continue;
		}

		/* locate the path */
		path = (const char *) &request.data[sizeof(uint16_t)];

		/* make sure the path is null-terminated */
		mode = memchr((const void *) path, '\0', 1 + NAME_MAX);
		if (NULL == mode) {
			continue;
		}

		/* skip the null byte */
		++mode;

		/* spawn a child process */
		pid = fork();
		switch (pid) {
			case (-1):
				goto close_log;

			case 0:
				/* handle the request */
				if (false == _handle_request(path,
				                             mode,
				                             request.header.opcode,
				                             address,
				                             &client_address,
				                             address_size)) {
					goto close_log;
				}
				goto success;
		}
	} while (1);

success:
	/* report success */
	exit_code = EXIT_SUCCESS;

close_log:
	/* close the system log */
	closelog();

close_socket:
	/* close the socket */
	(void) close(daemon_data.fd);

free_address:
	/* free the local address */
	freeaddrinfo(address);

end:
	return exit_code;
}
示例#3
0
static bool _handle_request(const char *path,
                            const char *mode,
                            const uint16_t opcode,
                            const struct addrinfo *local_address,
                            const struct sockaddr *client_address,
                            const socklen_t address_size) {
	/* the socket */
	int s = (-1);

	/* the source address */
	struct sockaddr source = {0};

	/* the return value */
	bool result = false;

	/* the transaction ID */
	short tid = 0;

	assert(NULL != path);
	assert((PACKET_TYPE_RRQ == opcode) || (PACKET_TYPE_WRQ == opcode));
	assert(0 < address_size);
	assert(NULL != local_address);
	assert(NULL != client_address);
	assert(0 < address_size);

	/* get the transaction ID */
	switch (client_address->sa_family) {
		case AF_INET:
			tid = ((struct sockaddr_in *) client_address)->sin_port;
			break;

		case AF_INET6:
			tid = ((struct sockaddr_in6 *) client_address)->sin6_port;
			break;

		default:
			goto end;
	}

	/* create a socket */
	s = socket(local_address->ai_family,
	           local_address->ai_socktype,
	           local_address->ai_protocol);
	if (-1 == s) {
		goto end;
	}

	/* set the socket timeout */
	if (false == _set_timeout(s)) {
		goto end;
	}

	/* pick a unique source port and bind the socket on it */
	(void) memcpy(&source, local_address->ai_addr, local_address->ai_addrlen);
	if (false == _pick_tid(s, &source, local_address->ai_addrlen)) {
		goto close_socket;
	}

	/* make sure the transfer mode is "octet" */
	if (0 != strcmp("octet", mode)) {
		_send_error(s, ERROR_ILLEGAL_OPERATION, client_address, address_size);
		goto close_socket;
	}

	/* make sure the file doesn't contain a sub-director */
	if (NULL != strchr(path, '/')) {
		_send_error(s, ERROR_ACCESS_VIOLATION, client_address, address_size);
		goto close_socket;
	}

	/* handle the request */
	switch (opcode) {
		case PACKET_TYPE_RRQ:
			_log_request("GET", path, client_address, address_size);
			result = _handle_rrq(s, path, client_address, address_size, tid);
			break;

		case PACKET_TYPE_WRQ:
			_log_request("PUT", path, client_address, address_size);
			result = _handle_wrq(s, path, client_address, address_size, tid);
			break;

		default:
			_send_error(s,
			            ERROR_ILLEGAL_OPERATION,
			            client_address,
			            address_size);
			goto close_socket;
	}

close_socket:
	/* close the socket */
	(void) close(s);

end:
	return result;
}