Пример #1
0
/* Look up a port using getaddrinfo, and bind one or more sockets. */
static unsigned
open_port (struct lshd_context *ctx, struct resource_list *resources,
	   const struct lsh_string *interface, const struct lsh_string *port)
{
#if HAVE_GETADDRINFO
  struct addrinfo hints;
  struct addrinfo *list;
  struct addrinfo *p;
  int err;

  const char *node;
  unsigned done = 0;

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = PF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;

  node = interface ? lsh_get_cstring(interface) : NULL;

  if (node && !node[0])
    node = NULL;

  debug("open_port: node = %z, port = %S\n",
	node ? node : "ANY", port);

  /* FIXME: Also use AI_ADDRCONFIG? */
  hints.ai_flags = AI_PASSIVE;

  err = getaddrinfo(node, lsh_get_cstring(port), &hints, &list);
  if (err)
    werror ("getaddrinfo failed for interface %z, port %S: %z\n",
	    node ? node : "ANY", port, gai_strerror(err));
  else
    {
      for (p = list; p; p = p->ai_next)
	{
	  if (p->ai_family == AF_INET || p->ai_family == AF_INET6)
	    {
	      struct resource *port = 
		make_lshd_port (ctx, p->ai_addrlen, p->ai_addr);
	      if (port)
		{
		  remember_resource(resources, port);
		  done++;
		}
	    }
	}
      freeaddrinfo(list);
    }
  return done;
#else /* !HAVE_GETADDRINFO */
#error getaddrinfo currently required */
#endif /* !HAVE_GETADDRINFO */
}
Пример #2
0
/* Consumes file name */
struct resource *
make_pid_file_resource(struct lsh_string *file)
{
  const char *cname = lsh_get_cstring(file);
  int fd;

  assert (cname);

  /* Try to open the file atomically. This provides sufficient locking
   * on normal (non-NFS) file systems. */

  fd = open(cname, O_WRONLY | O_CREAT | O_EXCL, 0644);

  if (fd < 0)
    {
      if (errno != EEXIST)
	werror("Failed to open pid file '%S': %e.\n",
		 file, errno);
      else
	/* FIXME: We could try to detect and ignore stale pid files. */
	werror("Pid file '%S' already exists.\n", file);
      
      lsh_string_length(file);
      return NULL;
    }
  else
    {
      struct lsh_string *pid = ssh_format("%di", getpid());

      if (!write_raw(fd, STRING_LD(pid)))
	{
	  werror("Writing pidfile `%S' failed: %e\n",
		 file, errno);

	  /* Attempt unlinking file */
	  if (unlink(cname) < 0)
	    werror("Unlinking pid file '%S' failed: %e.\n",
		   file, errno);

	  close(fd);
	  
	  lsh_string_free(pid);
	  lsh_string_free(file);

	  return NULL;
	}
      else
	{      
	  NEW(pid_file_resource, self);
	  init_resource(&self->super, do_kill_pid_file);

	  self->file = file;

	  lsh_string_free(pid);
	  close(fd);
	  
	  return &self->super;
	}
    }
}
Пример #3
0
static void
do_kill_pid_file(struct resource *s)
{
  CAST(pid_file_resource, self, s);
  if (self->super.alive)
    {
      self->super.alive = 0;
      if (unlink(lsh_get_cstring(self->file)) < 0)
	werror("Unlinking pidfile `%S' failed: %e.\n", self->file, errno);
    }
}
Пример #4
0
/* Bind all appropriate ports for a given interface. */
static unsigned
open_interface(struct lshd_context *ctx, struct resource_list *resources,
	       struct lshd_interface *interface, struct string_queue *ports)
{
  debug("open_interface: name = %z, port = %z\n",
	interface && interface->name ? lsh_get_cstring(interface->name) : "ANY",
	interface && interface->port ? lsh_get_cstring(interface->port) : "DEFAULT");

  if (interface && interface->port)
    return open_port(ctx, resources, interface->name, interface->port);
  else
    {
      const struct lsh_string *name = interface ? interface->name : NULL;
      unsigned done = 0;

      FOR_STRING_QUEUE(ports, port)
	done += open_port(ctx, resources, name, port);

      return done;
    }
}
Пример #5
0
static int
write_syslog(int fd UNUSED, uint32_t length, const uint8_t *data)
{
  struct lsh_string *s;

  /* Data must not contain any NUL:s */
  assert(!memchr(data, '\0', length));
  
  /* NUL-terminate the string. */
  s = ssh_format("%ls", length, data);

  /* FIXME: Should we use different log levels for werror, verbose and
   * debug? */
  
  syslog(LOG_NOTICE, "%s", lsh_get_cstring(s));
  lsh_string_free(s);
  
  return 1;
}
Пример #6
0
/* Resolve a dns name or a literal IPv4 or IPv6 address */
static void
do_resolve(struct command *s,
	   struct lsh_object *x,
	   struct command_continuation *c,
	   struct exception_handler *e)
{
  CAST(resolver_command, self, s);
  CAST(address_info, a, x);
  adns_query q;
  const char *name = lsh_get_cstring(a->host);;
  
  assert(!a->socket);

  /* FIXME: Check literal address first. And fail more gracefully for
   * names including NUL.*/
  assert(name);
  adns_submit(self->resolver->adns,
	      name,
	      adns_r_addr,
	      0, /* adns_queryflags, could use IPv6-related flags */
	      make_resolver_context(a, c, e),
	      &q);
}
Пример #7
0
int main(int argc, char **argv)
{
  struct lsh_decode_key_options *options = make_lsh_decode_key_options();
  struct lsh_string *input;
  struct lsh_string *output;
  
  int out = STDOUT_FILENO;
  
  argp_parse(&main_argp, argc, argv, 0, NULL, options);

  if (options->file)
    {
      out = open(lsh_get_cstring(options->file),
                 O_WRONLY | O_CREAT, 0666);
      if (out < 0)
        {
          werror("Failed to open file `%S' for writing: %e.\n",
                 options->file, errno);
          return EXIT_FAILURE;
        }
    }

  input = io_read_file_raw(STDIN_FILENO, 3000);
  if (!input)
    {
      werror("Failed to read stdin: %e.\n", errno);
      return EXIT_FAILURE;
    }

  if (options->base64)
    {
      if (!lsh_string_base64_decode(input))
	{
          werror("Invalid base64 encoding.\n");

	  lsh_string_free(input);

          return EXIT_FAILURE;
        }
    }
  
  output = lsh_decode_key(input);
  lsh_string_free(input);

  if (!output)
    {
      werror("Invalid ssh2 key.\n");
      return EXIT_FAILURE;
    }
    
  if (!write_raw(out, STRING_LD(output)))
    {
      werror("Write failed: %e.\n", errno);
      return EXIT_FAILURE;
    }
  lsh_string_free(output);
  
  gc_final();
  
  return EXIT_SUCCESS;
}
Пример #8
0
static void
lshd_service_request_handler(struct transport_forward *self,
			     uint32_t length, const uint8_t *packet)
{
  struct simple_buffer buffer;
  unsigned msg_number;

  const uint8_t *name;
  uint32_t name_length;

  simple_buffer_init(&buffer, length, packet);

  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_SERVICE_REQUEST)
      && parse_string(&buffer, &name_length, &name)
      && parse_eod(&buffer))
    {
      CAST(lshd_context, ctx, self->super.ctx);
      const struct service_entry *service
	= service_config_lookup(ctx->service_config,
				name_length, name);
      
      if (service)
	{
	  int pipe[2];
	  pid_t child;

	  if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe) < 0)
	    {
	      werror("lshd_service_request_handler: socketpair failed: %e.\n",
		     errno);
	      transport_disconnect(&self->super,
				   SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
				   "Service could not be started");
	      return;
	    }

	  child = fork();
	  if (child < 0)
	    {
	      werror("lshd_service_request_handler: fork failed: %e.\n",
		     errno);
	      close(pipe[0]);
	      close(pipe[1]);
	      transport_disconnect(&self->super,
				   SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
				   "Service could not be started");
	      return;
	    }
	  if (child)
	    {
	      /* Parent process */
	      close(pipe[1]);

	      transport_send_packet(&self->super, TRANSPORT_WRITE_FLAG_PUSH,
				    format_service_accept(name_length, name));

	      /* Setup forwarding. Replaces event_handler and packet_handler. */
	      transport_forward_setup(self, pipe[0], pipe[0]);
	    }
	  else
	    {
	      /* Child process */
	      struct arglist args;
	      const char *program;
	      unsigned i;

	      close(pipe[0]);
	      dup2(pipe[1], STDIN_FILENO);
	      dup2(pipe[1], STDOUT_FILENO);
	      close(pipe[1]);

	      /* FIXME: Pass sufficient information so that
		 $SSH_CLIENT can be set properly. */
	      arglist_init (&args);

	      program = service->args.argv[0];
	      arglist_push (&args, program);

	      /* If not absolute, interpret it relative to
		 libexecdir. */
	      if (program[0] != '/')
		program = lsh_get_cstring(ssh_format("%lz/%lz",
						     ctx->service_config->libexec_dir,
						     program));
	      
	      for (i = 1; i < service->args.argc; i++)
		{
		  const char *arg = service->args.argv[i];
		  if (arg[0] == '$')
		    {
		      if (!strcmp(arg+1, "(session_id)"))
			arg = lsh_get_cstring(ssh_format("%lxS",
							 self->super.session_id));
		    }
		  arglist_push (&args, arg);
		}
	      debug("exec of service %s, program %z. Argument list:\n",
		    name_length, name, program);
	      for (i = 0; i < args.argc; i++)
		debug("  %z\n", args.argv[i]);

	      execv(program, (char **) args.argv);

	      werror("lshd_service_request_handler: exec of %z failed: %e.\n",
		     args.argv[0], errno);
	      _exit(EXIT_FAILURE);
	    }
	}
      else
	transport_disconnect(&self->super,
			     SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
			      "Service not available");
    }
  else
    transport_protocol_error(&self->super, "Invalid SERVICE_REQUEST");
}
Пример #9
0
int
test_main(void)
{
  struct lsh_string *s;
  const char *p;
  
  s = S("foo");
  p = lsh_get_cstring(s);

  ASSERT(p && !strcmp(p, "foo")) ;

  s = H("66006f");
  ASSERT(!lsh_get_cstring(s));

  s = H("6600");
  ASSERT(!lsh_get_cstring(s));

  s = H("");
  p = lsh_get_cstring(s);
  ASSERT(p && !*p);

  s = S("colonize this");
  s = lsh_string_colonize(s, 2, 1);
  p = lsh_get_cstring(s);
  
  ASSERT(p && !strcmp(p, "co:lo:ni:ze: t:hi:s")) ;

  s = S("fo");
  s = lsh_string_colonize(s, 2, 1);
  p = lsh_get_cstring(s);
  
  ASSERT(p && !strcmp(p, "fo")) ;
 
  s = S("");
  s = lsh_string_colonize(s, 1, 1);
  p = lsh_get_cstring(s);
  
  ASSERT(p && !*p) ;
  
  s = S("colonize this");
  s = lsh_string_colonize( s, 1, 1);
  p = lsh_get_cstring(s);

  ASSERT(p && !strcmp(p, "c:o:l:o:n:i:z:e: :t:h:i:s")) ;
  
  s = S("");
  s = lsh_string_bubblebabble(s, 1);
  p = lsh_get_cstring(s);
  
  ASSERT(p && !strcmp(p, "xexax")) ;

  s = S("1234567890");
  s = lsh_string_bubblebabble(s, 1);
  p = lsh_get_cstring(s);
  
  ASSERT(p && !strcmp(p, "xesef-disof-gytuf-katof-movif-baxux")) ;
  
  s = S("Pineapple");
  s = lsh_string_bubblebabble(s, 1);
  p = lsh_get_cstring(s);

  ASSERT(p && !strcmp(p, "xigak-nyryk-humil-bosek-sonax")) ;

  /* This should at least strigger one typo I made in the bubble babble routine */ 

  s = S("\xb8\x4e\xce\x86\x7b\x92\x8e\xf2\xda\x8e\xee\x15\xc2\x5d\xac\xd6\xe8\x6c\xb3\x43");
  s = lsh_string_bubblebabble(s, 1);
  p = lsh_get_cstring(s);	
           
  ASSERT(p && !strcmp(p, "xovag-vafim-kivun-dafez-dykim-veryc-habeh-turyt-kopyk-sasug-fixax")) ;

  SUCCESS();
}
Пример #10
0
static error_t
main_argp_parser(int key, char *arg, struct argp_state *state)
{
  CAST(lsh_writekey_options, self, state->input);

  switch(key)
    {
    default:
      return ARGP_ERR_UNKNOWN;

    case ARGP_KEY_INIT:
      state->child_inputs[0] = &self->style;
      state->child_inputs[1] = NULL;
      break;

    case ARGP_KEY_END:
      if (!self->file)
	{
	  char *home = getenv("HOME");
	  struct lsh_string *s;
	  
	  if (!home)
	    {
	      argp_failure(state, EXIT_FAILURE, 0, "$HOME not set.");
	      return EINVAL;
	    }
	  else
	    {
#ifndef MACOS
	      s = ssh_format("%lz/.lsh", home);
	      if (mkdir(lsh_get_cstring(s), 0755) < 0)
		{
		  if (errno != EEXIST)
		    argp_failure(state, EXIT_FAILURE, errno, "Creating directory %s failed.", s->data);
		}
	      lsh_string_free(s);
	      self->file = ssh_format("%lz/.lsh/identity", home);
#else
	      self->file = ssh_format("%lzidentity", home);
#endif
	    }
	}
      if (self->crypto)
	{
	  if (!self->label)
	    {
	      const char *name = getenv("LOGNAME");
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 300
#endif
	      char host[MAXHOSTNAMELEN];
	  
	      if (!name)
		{
		  argp_failure(state, EXIT_FAILURE, 0,
			       "LOGNAME not set. Please use the -l option.");
		  return EINVAL;
		}

	      if ( (gethostname(host, sizeof(host)) < 0)
		   && (errno != ENAMETOOLONG) )
		argp_failure(state, EXIT_FAILURE, errno,
			     "Can't get the host name. Please use the -l option.");
	      
	      self->label = ssh_format("%lz@%lz", name, host);
	    }
	  while (!self->passphrase)
	    {
	      struct lsh_string *pw;
	      struct lsh_string *again;

	      pw = INTERACT_READ_PASSWORD(self->tty, 500,
					  ssh_format("Enter new passphrase: "), 1);
	      if (!pw)
		argp_failure(state, EXIT_FAILURE, 0, "Aborted.");

	      again = INTERACT_READ_PASSWORD(self->tty, 500,
					     ssh_format("Again: "), 1);
	      if (!again)
		argp_failure(state, EXIT_FAILURE, 0, "Aborted.");

	      if (lsh_string_eq(pw, again))
		self->passphrase = pw;
	      else
		lsh_string_free(pw);

	      lsh_string_free(again);
	    }
	}
      break;
      
    case 'o':
      self->file = make_string(arg);
      break;

    case 'i':
      {
	long i;
	char *end;
	i = strtol(arg, &end, 0);

	if ((end == arg) || *end || (i < 1))
	  {
	    argp_failure(state, EXIT_FAILURE, 0, "Invalid iteration count.");
	    return EINVAL;
	  }
	else if (i > PKCS5_MAX_ITERATIONS)
	  {
	    argp_error(state, "Iteration count ridiculously large (> %d).",
		       PKCS5_MAX_ITERATIONS);
	    return EINVAL;
	  }
	else
	  self->iterations = i;

	break;
      }

    case 'c':
      {
	int name = lookup_crypto(self->crypto_algorithms, arg, &self->crypto);

	if (name)
	  self->crypto_name = name;
	else
	  {
	    list_crypto_algorithms(state, self->crypto_algorithms);
	    argp_error(state, "Unknown crypto algorithm '%s'.", arg);
	  }
	break;
      }
      
    case 'l':
      self->label = ssh_format("%lz", arg);
      break;
      
    case 'p':
      self->passphrase = ssh_format("%lz", arg);
      break;
    }
  return 0;
}