io.c 29 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
/* io.c
2
 *
3
 */
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 Niels Mller
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
J.H.M. Dassen's avatar
J.H.M. Dassen committed
21
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Niels Möller's avatar
Niels Möller committed
22
23
 */

24
25
26
#if HAVE_CONFIG_H
#include "config.h"
#endif
27

Niels Möller's avatar
Niels Möller committed
28
#include <assert.h>
29
#include <errno.h>
Niels Möller's avatar
Niels Möller committed
30
31
#include <string.h>

32
#if HAVE_UNISTD_H
Niels Möller's avatar
Niels Möller committed
33
#include <unistd.h>
34
#endif
35

36
37
38
39
40
41
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
42
43
/* For the popen code */
#include <sys/wait.h>
44
45
46
47
48
49
#include <sys/ioctl.h>

/* Needed for FIONREAD on Solaris */
#if HAVE_SYS_FILIO_H
#include <sys/filio.h>
#endif
50
51
52
53
54
55

#include <arpa/inet.h>

#include "io.h"

#include "format.h"
56
#include "lsh_string.h"
57
58
59
#include "werror.h"
#include "xalloc.h"

60
#define GABA_DEFINE
61
#include "io.h.x"
62
#undef GABA_DEFINE
63
64
65

#include "io.c.x"

66
67
/* Glue to liboop */

68
69
#define WITH_LIBOOP_SIGNAL_ADAPTER 1

70
/* Because of signal handlers, there can be only one oop object. */
71
static oop_source_sys *global_oop_sys = NULL;
72
73
74
#if WITH_LIBOOP_SIGNAL_ADAPTER
static oop_adapter_signal *global_oop_signal = NULL;
#endif
75
76
77
oop_source *global_oop_source = NULL;
static unsigned global_nfiles = 0;

78

79
/* OOP Callbacks */
80
static void *
81
lsh_oop_signal_callback(oop_source *s UNUSED, int sig, void *data)
82
83
84
{
  CAST(lsh_signal_handler, self, (struct lsh_object *) data);

85
  trace("lsh_oop_signal_callback: Signal %i, handler: %t\n",
86
	sig, self->action);
87
  
88
89
  assert(sig == self->signum);
  
90
  LSH_CALLBACK(self->action);
91

92
  return OOP_CONTINUE;
93
94
95
}

static void
96
lsh_oop_register_signal(struct lsh_signal_handler *handler)
97
{
98
99
100
  trace("lsh_oop_register_signal: signal: %i, handler: %t\n",
	handler->signum, handler);
  
101
  assert(global_oop_source);
102
  if (handler->super.alive)
103
    global_oop_source->on_signal(global_oop_source, handler->signum,
Niels Möller's avatar
Niels Möller committed
104
		      lsh_oop_signal_callback, handler);
105
106
}

107
static void
108
lsh_oop_cancel_signal(struct lsh_signal_handler *handler)
109
{
110
111
  trace("lsh_oop_cancel_signal: signal: %i, handler: %t\n",
	handler->signum, handler);
112

113
  assert(global_oop_source);
114
  if (handler->super.alive)
115
    global_oop_source->cancel_signal(global_oop_source, handler->signum,
Niels Möller's avatar
Niels Möller committed
116
			  lsh_oop_signal_callback, handler);
117
}
118

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
static void *
lsh_oop_time_callback(oop_source *source UNUSED,
                      struct timeval time UNUSED, void *data)
{
  CAST(lsh_callout, callout, (struct lsh_object *) data);

  assert(callout->super.alive);

  trace("lsh_oop_time_callback: action: %t\n",
        callout->action);
  
  callout->super.alive = 0;

  LSH_CALLBACK(callout->action);

  return OOP_CONTINUE;
}

static void
lsh_oop_register_callout(struct lsh_callout *callout)
{
140
  assert(global_oop_source);
141
142
143
  trace("lsh_oop_register_callout: action: %t\n",
        callout->action);

144
  if (callout->super.alive)
145
    global_oop_source->on_time(global_oop_source, callout->when, lsh_oop_time_callback, callout);
146
147
148
149
150
}

static void
lsh_oop_cancel_callout(struct lsh_callout *callout)
{
151
  assert(global_oop_source);
152
153
  trace("lsh_oop_cancel_callout: action: %t\n",
        callout->action);
154
  if (callout->super.alive)
155
    global_oop_source->cancel_time(global_oop_source, callout->when, lsh_oop_time_callback, callout);
156
157
}

Niels Möller's avatar
Niels Möller committed
158
159
160
161
162
163
static void *
lsh_oop_stop_callback(oop_source *source UNUSED,
                      struct timeval time UNUSED, void *data UNUSED)
{
  trace("lsh_oop_stop_callback\n");
  
164
  if (!global_nfiles)
Niels Möller's avatar
Niels Möller committed
165
    /* An arbitrary non-NULL value stops oop_sys_run. */
166
    return OOP_HALT;
Niels Möller's avatar
Niels Möller committed
167
168
169
170
171
172
173
  else
    return OOP_CONTINUE;
}

static void
lsh_oop_stop(void)
{
174
  assert(global_oop_source);
Niels Möller's avatar
Niels Möller committed
175
  trace("lsh_oop_stop\n");
176
  global_oop_source->on_time(global_oop_source, OOP_TIME_NOW, lsh_oop_stop_callback, NULL);
Niels Möller's avatar
Niels Möller committed
177
178
179
180
181
}

static void
lsh_oop_cancel_stop(void)
{
182
  assert(global_oop_source);
Niels Möller's avatar
Niels Möller committed
183
  trace("lsh_oop_cancel_stop\n");
184
  global_oop_source->cancel_time(global_oop_source, OOP_TIME_NOW, lsh_oop_stop_callback, NULL);
Niels Möller's avatar
Niels Möller committed
185
186
}

187
/* Increments the count of active files, and sets the non-blocking and
Niels Möller's avatar
Niels Möller committed
188
   close-on-exec if appropriate. With the exception of stdio
Niels Möller's avatar
Niels Möller committed
189
   file descriptors, all file descripters handled by the backend should
Niels Möller's avatar
Niels Möller committed
190
   have the close-on-exec flag set and use non-blocking mode. */
191
192
void
io_register_fd(int fd, const char *label)
193
{
194
  trace("io_register_fd: fd = %i: %z\n", fd, label);
195

196
  if (fd > STDERR_FILENO)
197
    {
198
199
200
201
202
203
      io_set_close_on_exec(fd);
      io_set_nonblocking(fd);      
    }
  global_nfiles++;
}

204
/* Closes an fd registered as above. Stdio file descriptors are
205
206
207
208
209
210
211
212
   treated specially. */
void
io_close_fd(int fd)
{  
  if (fd < 0)
    return;

  trace("io_close_fd: fd = %i\n", fd);
213

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
  global_oop_source->cancel_fd(global_oop_source, fd, OOP_READ);
  global_oop_source->cancel_fd(global_oop_source, fd, OOP_WRITE);

  if (fd == STDERR_FILENO)
    /* Do nothing */
    ;
  else if (close(fd) < 0)
    werror("Closing fd %i failed: %e.\n", fd, errno);
  
  else if (fd <= STDOUT_FILENO)
    {
      int null = open("/dev/null", O_RDWR);
      if (null < 0)
	fatal("Failed to open /dev/null!\n");
      if (null != fd)
	fatal("Failed to map stdio fd %i to /dev/null.\n", fd);
230
    }
231
232
233
234

  assert(global_nfiles);
  if (!--global_nfiles)
    lsh_oop_stop();
235
}
Niels Möller's avatar
Niels Möller committed
236

237

Niels Möller's avatar
Niels Möller committed
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
void
io_init(void)
{
  struct sigaction pipe;
  memset(&pipe, 0, sizeof(pipe));

  pipe.sa_handler = SIG_IGN;
  sigemptyset(&pipe.sa_mask);
  pipe.sa_flags = 0;
  
  if (sigaction(SIGPIPE, &pipe, NULL) < 0)
    fatal("Failed to ignore SIGPIPE.\n");

  assert(!global_oop_sys);
  global_oop_sys = oop_sys_new();
  if (!global_oop_sys)
254
    fatal("Failed to initialize liboop oop_sys.\n");
Niels Möller's avatar
Niels Möller committed
255

256
257
258
259
#if WITH_LIBOOP_SIGNAL_ADAPTER
  global_oop_signal = oop_signal_new(oop_sys_source(global_oop_sys));
  if (!global_oop_signal)
    fatal("Failed to initialize liboop oop_signal.\n");
260
  global_oop_source = oop_signal_source(global_oop_signal);
261
#else
262
  global_oop_source = oop_sys_source(global_oop_sys);
263
#endif
Niels Möller's avatar
Niels Möller committed
264
265
266
}

void
Niels Möller's avatar
Niels Möller committed
267
io_run(void)
Niels Möller's avatar
Niels Möller committed
268
{
Niels Möller's avatar
Niels Möller committed
269
270
271
272
273
274
275
276
277
  void *res = oop_sys_run(global_oop_sys);

  /* We need liboop-0.8, OOP_ERROR is not defined in liboop-0.7. */

  if (res == OOP_ERROR)
    werror("oop_sys_run %e\n", errno);

  trace("io_run: Cleaning up\n");

Niels Möller's avatar
Niels Möller committed
278
279
280
281
282
  gc_final();

  /* The final gc may have closed some files, and called lsh_oop_stop.
   * So we must unregister that before deleting the oop source. */
  lsh_oop_cancel_stop();
283

Niels Möller's avatar
Niels Möller committed
284
  /* There mustn't be any outstanding callbacks left. */
285
  assert(global_nfiles == 0);
286
  
287
288
289
290
#if WITH_LIBOOP_SIGNAL_ADAPTER
  oop_signal_delete(global_oop_signal);
  global_oop_signal = NULL;
#endif
Niels Möller's avatar
Niels Möller committed
291
292
  oop_sys_delete(global_oop_sys);
  global_oop_sys = NULL;
293
  global_oop_source = NULL;
Niels Möller's avatar
Niels Möller committed
294
295
}

296

297
298
299
300
301
302
/* Calls trigged by a signal handler. */
/* GABA:
   (class
     (name lsh_signal_handler)
     (super resource)
     (vars
303
       (signum . int)
304
305
306
307
308
309
310
311
       (action object lsh_callback)))
*/

/* GABA:
   (class
     (name lsh_callout)
     (super resource)
     (vars
312
       (when . "struct timeval")
313
314
315
       (action object lsh_callback)))
*/

316

317
318
319
320
321
322
323
static void
do_kill_signal_handler(struct resource *s)
{
  CAST(lsh_signal_handler, self, s);

  if (self->super.alive)
    {
324
      lsh_oop_cancel_signal(self);
325
326
327
328
      self->super.alive = 0;
    }
}

329
struct resource *
330
io_signal_handler(int signum,
331
332
333
		  struct lsh_callback *action)
{
  NEW(lsh_signal_handler, handler);
334
335

  init_resource(&handler->super, do_kill_signal_handler);
336

337
  handler->signum = signum;
338
339
  handler->action = action;

340
  lsh_oop_register_signal(handler);
341
  gc_global(&handler->super);
342
343
344
345
  
  return &handler->super;
}

346
347
348
349
350
351
352
353
354
355
356
357
static void
do_kill_callout(struct resource *s)
{
  CAST(lsh_callout, self, s);

  if (self->super.alive)
    {
      lsh_oop_cancel_callout(self);
      self->super.alive = 0;
    }
}

358
struct resource *
359
io_callout(struct lsh_callback *action, unsigned seconds)
360
{
361
  NEW(lsh_callout, self);
362
  init_resource(&self->super, do_kill_callout);
363

364
365
366
367
368
369
370
371
372
373
374
  if (seconds)
    {
      /* NOTE: Using absolute times, like oop does, is a little
       * dangerous if the system time is changed abruptly. */
      if (gettimeofday(&self->when, NULL) < 0)
	fatal("io_callout: gettimeofday failed!\n");
      self->when.tv_sec += seconds;
    }
  else
    self->when = OOP_TIME_NOW;
  
375
  self->action = action;
376
      
377
378
  lsh_oop_register_callout(self);
  
379
380
  gc_global(&self->super);
  return &self->super;
381
}
Niels Möller's avatar
Niels Möller committed
382

Niels Möller's avatar
Niels Möller committed
383
static void
384
kill_io_fd_resource(struct resource *s)
Niels Möller's avatar
Niels Möller committed
385
{
386
  CAST_SUBTYPE(io_fd_resource, self, s);
387
  if (self->super.alive)
388
    {
389
      self->super.alive = 0;
390
391
392

      io_close_fd(self->fd);
      self->fd = -1;
393
    }
Niels Möller's avatar
Niels Möller committed
394
}
395

396
397
398
399
void
init_io_connect_state(struct io_connect_state *self,
		      void (*done)(struct io_connect_state *self, int fd),
		      void (*error)(struct io_connect_state *self, int err))
400
{
401
402
  init_resource(&self->super.super, kill_io_fd_resource);
  self->super.fd = -1;
403
404
  self->done = done;
  self->error = error;
405
}
Niels Möller's avatar
Niels Möller committed
406

407
408
409
410
411
412
413
static void *
oop_io_connect(oop_source *source UNUSED,
	       int fd, oop_event event, void *state)
{
  CAST_SUBTYPE(io_connect_state, self, (struct lsh_object *) state);
  int socket_error = 0;
  socklen_t len = sizeof(socket_error);
414

415
  assert(self->super.fd == fd);
416
  assert(event == OOP_WRITE);
Niels Möller's avatar
Niels Möller committed
417

418
  global_oop_source->cancel_fd(global_oop_source, fd, OOP_WRITE);
419

420
  /* Check if the connection was successful */
421
  if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *) &socket_error, &len) < 0
422
      || socket_error)
423
    {
424
      self->error(self, socket_error);
425
426
    }
  else
Niels Möller's avatar
Niels Möller committed
427
    {
428
      self->super.fd = -1;
429
      self->done(self, fd);
430
    }
431

432
  KILL_RESOURCE(&self->super.super);
433
  return OOP_CONTINUE;
434
435
}

436
437
438
439
int
io_connect(struct io_connect_state *self,
	   socklen_t addr_length,
	   struct sockaddr *addr)
440
{
441
442
  assert(self->super.fd < 0);
  self->super.fd = socket(addr->sa_family, SOCK_STREAM, 0);
443

444
  if (self->super.fd < 0)
445
    return 0;
446

447
  io_register_fd(self->super.fd, "connect fd");
448
  
449
  if (connect(self->super.fd, addr, addr_length) < 0 && errno != EINPROGRESS)
450
    {
451
      int saved_errno = errno;
452

453
      KILL_RESOURCE(&self->super.super);
454
455
456
      errno = saved_errno;

      return 0;
457
458
    }

459
460
  global_oop_source->on_fd(global_oop_source, self->super.fd, OOP_WRITE, oop_io_connect, self);
  gc_global(&self->super.super);
461
462
  return 1;
}
463

464
465
466
467
468
469
470
471
472

/* Listening */
void
init_io_listen_port(struct io_listen_port *self, int fd,
		    void (*accept)(struct io_listen_port *self,
				   int fd,
				   socklen_t addr_len,
				   const struct sockaddr *addr))
{
473
  init_resource(&self->super.super, kill_io_fd_resource);
474
475
476

  io_register_fd(fd, "listen port");

477
  self->super.fd = fd;
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
  self->accept = accept;  
}

static void *
oop_io_accept(oop_source *source UNUSED,
	      int fd, oop_event event, void *state)
{
  CAST_SUBTYPE(io_listen_port, self, (struct lsh_object *) state);

#if WITH_IPV6
  struct sockaddr_storage peer;
#else
  struct sockaddr_in peer;
#endif

  socklen_t peer_length = sizeof(peer);
  int s;
  
  assert(event == OOP_READ);
497
  assert(self->super.fd == fd);
498

499
  s = accept(fd, (struct sockaddr *) &peer, &peer_length);
500
  if (s < 0)
501
    werror("accept failed, fd = %i: %e\n", fd, errno);
502
503
504
505
506
507
508

  else
    self->accept(self, s, peer_length, (struct sockaddr *) &peer);

  return OOP_CONTINUE;
}

Niels Möller's avatar
Niels Möller committed
509
/* FIXME: Can this be merged with init_io_listen_port? Or are the calls ever separated? */
510
511
512
int
io_listen(struct io_listen_port *self)
{
513
  if (listen(self->super.fd, 256) < 0)
514
515
    return 0;

516
  global_oop_source->on_fd(global_oop_source, self->super.fd, OOP_READ,
517
518
519
520
521
522
			   oop_io_accept, self);

  return 1;
}


523
/* These functions are used by werror and friends */
Niels Möller's avatar
Niels Möller committed
524

525
526
/* For fd:s in blocking mode. On error, see errno. */
int
527
write_raw(int fd, uint32_t length, const uint8_t *data)
Niels Möller's avatar
Niels Möller committed
528
{
529
  while (length)
Niels Möller's avatar
Niels Möller committed
530
531
532
    {
      int written = write(fd, data, length);
      if (written < 0)
533
534
	{
	  if (errno == EINTR)
Niels Möller's avatar
Niels Möller committed
535
	    continue;
536
537
538
	  else
	    return 0;
	}
Niels Möller's avatar
Niels Möller committed
539
540
541
      length -= written;
      data += written;
    }
542
  return 1;
Niels Möller's avatar
Niels Möller committed
543
544
}

545
struct lsh_string *
546
io_read_file_raw(int fd, uint32_t guess)
547
{
Niels Möller's avatar
Niels Möller committed
548
549
550
  struct lsh_string *buffer = lsh_string_alloc(guess);
  uint32_t pos = 0;
  
551
  for (;;)
552
    {
Niels Möller's avatar
Niels Möller committed
553
      uint32_t left = lsh_string_length(buffer) - pos;
554
      int res;
555

Niels Möller's avatar
Niels Möller committed
556
      if (!left)
557
	{
Niels Möller's avatar
Niels Möller committed
558
559
560
561
	  /* Roughly double the size of the buffer */
	  
	  buffer = lsh_string_realloc(buffer, 2*pos + 100);
	  left = lsh_string_length(buffer) - pos;
562
	}
563

Niels Möller's avatar
Niels Möller committed
564
      res = lsh_string_read(buffer, pos, fd, left);
565
566
567
568
569
      
      if (res < 0)
        {
          if (errno == EINTR)
            continue;
Niels Möller's avatar
Niels Möller committed
570
571

	  lsh_string_free(buffer);
572
573
574
575
576
          return NULL;
        }
      else if (!res)
        {
          /* EOF */
Niels Möller's avatar
Niels Möller committed
577
578
	  lsh_string_trunc(buffer, pos);
	  return buffer;
579
        }
Niels Möller's avatar
Niels Möller committed
580
      assert( (unsigned) res <= left);
581
      
Niels Möller's avatar
Niels Möller committed
582
      pos += res;
583
584
585
    }
}

586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
int
io_readable_p(int fd)
{
#if HAVE_IOCTL_FIONREAD
  int nbytes = 0;
  if (ioctl(fd, FIONREAD, &nbytes) < 0)
    {
      debug("ioctl FIONREAD failed: %e\n", errno);
      return 0;
    }
  return nbytes != 0;
#else /* ! HAVE_IOCTL_FIONREAD */
  return 0;
#endif /* !HAVE_IOCTL_FIONREAD */
}

Niels Möller's avatar
Niels Möller committed
602
603
/* Network utility functions */

604
/* Converts a string port number or service name to a port number.
605
606
 * Returns the port number in _host_ byte order, or 0 if lookup
 * fails. */
607

608
609
unsigned
get_portno(const char *service, const char *protocol)
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
{
  if (service == NULL)
    return 0;
  else
    {
      char *end;
      long portno;

      portno = strtol(service, &end, 10);
      if (portno > 0
	  &&  portno <= 65535
	  &&  end != service
	  &&  *end == '\0')
	  return portno;
      else
	{
	  struct servent * serv;

	  serv = getservbyname(service, protocol);
629
630
	  if (!serv)
	    return 0;
631
632
633
634
635
	  return ntohs(serv->s_port);
	}
    }
}

636
struct address_info *
637
make_address_info(struct lsh_string *host, uint32_t port)
638
639
640
{
  NEW(address_info, info);

641
  info->port = port;
642
643
644
645
  info->ip = host;
  return info;
}

646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
/* FIXME: Review need for this function. And maybe also the need for
   the address_info type? */
struct address_info *
sockaddr2info(size_t addr_length,
              const struct sockaddr *addr)
{
  NEW(address_info, info);
  
  switch(addr->sa_family)
    {
    case AF_INET:
      assert(addr_length == sizeof(struct sockaddr_in));
      {
        const struct sockaddr_in *in = (const struct sockaddr_in *) addr;
        uint32_t ip = ntohl(in->sin_addr.s_addr);
        
        info->port = ntohs(in->sin_port);
        info->ip = ssh_format("%di.%di.%di.%di",
                              (ip >> 24) & 0xff,
                              (ip >> 16) & 0xff,
                              (ip >> 8) & 0xff,
                              ip & 0xff);
      }
      return info;
      
#if WITH_IPV6
    case AF_INET6:
      assert(addr_length == sizeof(struct sockaddr_in6));
      {
        const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) addr;

        info->port = ntohs(in->sin6_port);
        info->ip = lsh_string_ntop(addr->sa_family, INET6_ADDRSTRLEN,
                                   &in->sin6_addr);

      }
      return info;
#endif /* WITH_IPV6 */

    default:
      fatal("io.c: sockaddr2info: Unsupported address family.\n");
    }
}

690
691
692
693
/* Creates a sockaddr. Only handles ip-addresses, no dns names. This
   is a simplified version of address_info2sockaddr. */
struct sockaddr *
io_make_sockaddr(socklen_t *lenp, const char *ip, unsigned port)
694
{
695
696
697
698
699
700
701
702
  struct sockaddr *sa;
  int res;

  if (!ip)
    {
      werror("io_make_sockaddr: NULL ip address!\n");
      return NULL;
    }
703
  if (port >= 0x10000)
704
705
706
707
708
    {
      werror("io_make_sockaddr: Invalid port %i.\n", port);
      return NULL;
    }

709
#if WITH_IPV6
710
711
712
713
714
715
716
717
718
719
720
  if (strchr(ip, ':'))
    {
      /* IPv6 */
      struct sockaddr_in6 *sin6;
      NEW_SPACE(sin6);
      
      sin6->sin6_family = AF_INET6;
      sin6->sin6_port = htons(port);
      res = inet_pton(AF_INET6, ip, &sin6->sin6_addr);

      *lenp = sizeof(*sin6);
721
      sa = (struct sockaddr *) sin6;
722
723
    }
  else
724
#endif
725
726
727
728
729
730
731
732
    {
      /* IPv4 */
      struct sockaddr_in *sin;
      NEW_SPACE(sin);
      
      sin->sin_family = AF_INET;
      sin->sin_port = htons(port);
      res = inet_pton(AF_INET, ip, &sin->sin_addr);
733

734
      *lenp = sizeof(*sin);
735
      sa = (struct sockaddr *) sin;
736
737
738
739
740
    }
  if (res < 0)
    {
      werror("inet_pton failed for address type %i: %e.\n",
	     sa->sa_family, errno);
741

742
      lsh_space_free(sa);
743
744
      return NULL;
    }
745
746
747
748
749
750
751
752
753
754
755
  else if (!res)
    {
      werror("Invalid address for address type %i.\n",
	     sa->sa_family);
      lsh_space_free(sa);
      return NULL;
    }

  return sa;
}

756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
/* Translating a dns name to an IP address. We don't currently support
   DNS names in tcpip forwarding requests, so all names have to be
   translated by the client. */

struct address_info *
io_lookup_address(const char *ip, const char *service)
{
  struct address_info *addr;
  const char *last_dot;
  
  assert(ip);

  if (strchr(ip, ':'))
    {
      /* Raw IPv6 address */
      unsigned port;

    raw_address:

      port = get_portno(service, "tcp");
      if (port > 0)
	return make_address_info(make_string(ip), port);
      else return 0;
    }

  /* Difference between a dns name and an ip address is that the ip
     address is dotted, and the final component starts with a
     digit. */
  last_dot = strrchr(ip, '.');
  if (last_dot && last_dot[1] >= '0' && last_dot[1] <= '9')
    /* Raw IPv4 address */
    goto raw_address;

  /* So, it looks like a domain name. Look it up. */
#if HAVE_GETADDRINFO
  {
    struct addrinfo hints;
    struct addrinfo *list;
    struct addrinfo *p;
    int err;
    
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    err = getaddrinfo(ip, service, &hints, &list);
    if (err)
      {
804
805
      	werror("io_address_lookup: getaddrinfo failed: %z\n",
	      gai_strerror(err));
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
	return 0;
      }

    addr = NULL;
    
    /* We pick only one address, and prefer IPv4 */
    for (p = list; p; p = p->ai_next)
      {
	if (p->ai_family == AF_INET)
	  {
	    struct sockaddr_in *sin = (struct sockaddr_in *) p->ai_addr;
	    assert(p->ai_addrlen == sizeof(*sin));
	    
	    addr = make_address_info(lsh_string_ntop(AF_INET, INET_ADDRSTRLEN,
						     &sin->sin_addr),
				     ntohs(sin->sin_port));
822

823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
	    break;
	  }
      }
#if WITH_IPV6
    if (!addr)
      for (p = list; p; p = p->ai_next)
      {
	if (p->ai_family == AF_INET6)
	  {
	    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) p->ai_addr;
	    assert(p->ai_addrlen == sizeof(*sin6));
	    
	    addr = make_address_info(lsh_string_ntop(AF_INET6, INET6_ADDRSTRLEN,
						     &sin6->sin6_addr),
				     ntohs(sin6->sin6_port));

	    break;
	  }
      }
#endif
    freeaddrinfo(list);
    
    if (!addr)
      {
	werror("No internet address found.\n");
	return NULL;
      }

    return addr;
  }
#else
#error At the moment, getaddrinfo is required
#endif
856
857
}

858
859
860
861
862
863
static void
handle_nonblock_error(const char *msg)
{
  /* On BSD, trying to set /dev/null in nonblocking mode fails with
   * errno 19, ENODEV. We have to ignore that.
   *
864
865
   * And on FreeBSD 5, the error code is changed to ENOTTY, for the
   * same problem.
866
867
   *
   * For now, still display a warning message, to keep track of when
868
869
   * and where it occurs.
   */
870
  if (errno == ENODEV || errno == ENOTTY)
871
872
873
    werror("%z %e\n", msg, errno);
  else
    fatal("%z %e\n", msg, errno);
874
875
}

876
877
void
io_set_nonblocking(int fd)
878
{
879
  int old = fcntl(fd, F_GETFL);
Niels Möller's avatar
Niels Möller committed
880

881
  if (old < 0)
882
    fatal("io_set_nonblocking: fcntl(F_GETFL) failed: %e\n", errno);
883
884
  
  if (fcntl(fd, F_SETFL, old | O_NONBLOCK) < 0)
885
    handle_nonblock_error("io_set_nonblocking: fcntl(F_SETFL) failed");
Niels Möller's avatar
Niels Möller committed
886
887
}

888
void
889
io_set_close_on_exec(int fd)
890
{
891
892
  /* NOTE: There's only one documented flag bit, so reading the old
   * value should be redundant. */
893
  
894
  int old = fcntl(fd, F_GETFD);
895

896
  if (old < 0)
897
    fatal("io_set_close_on_exec: fcntl(F_GETFD) failed %e\n", errno);
898
899
  
  if (fcntl(fd, F_SETFD, old | 1) < 0)
900
    fatal("Can't set close-on-exec flag for fd %i %e\n", fd, errno);
901
902
}

903
904
905

/* AF_LOCAL sockets */

906
struct local_info *
907
908
make_local_info(const struct lsh_string *directory,
		const struct lsh_string *name)
909
{
910
911
  if (!directory || !name
      || memchr(lsh_string_data(name), '/', lsh_string_length(name)))
912
913
    return NULL;

914
915
  assert(lsh_get_cstring(directory));
  assert(lsh_get_cstring(name));
916
917
918
919
920
921
922
923
924
  
  {
    NEW(local_info, self);
    self->directory = directory;
    self->name = name;
    return self;
  }
}

Niels Möller's avatar
Niels Möller committed
925
926
void
lsh_popd(int old_cd, const char *directory)
927
{
928
929
  while (fchdir(old_cd) < 0)
    if (errno != EINTR)
930
931
      fatal("io.c: Failed to cd back from %z %e\n",
	    directory, errno);
932
933
934
935
      
  close(old_cd);
}

Niels Möller's avatar
Niels Möller committed
936
937
int
lsh_pushd_fd(int dir)
938
939
940
941
942
943
944
945
{
  int old_cd;

  /* cd to it, but first save old cwd */

  old_cd = open(".", O_RDONLY);
  if (old_cd < 0)
    {
Niels Möller's avatar
Niels Möller committed
946
      werror("io.c: open(`.') failed.\n");
947
948
949
      return -1;
    }

950
951
  io_set_close_on_exec(old_cd);

952
953
954
955
  /* Test if we are allowed to cd to our current working directory. */
  while (fchdir(old_cd) < 0)
    if (errno != EINTR)
      {
956
	werror("io.c: fchdir(`.') failed %e\n", errno);
957
958
959
960
961
962
963
	close(old_cd);
	return -1;
      }

  /* As far as I have been able to determine, all checks for
   * fchdir:ability is performed at the time the directory was opened.
   * Even if the directory is chmod:et to zero, or unlinked, we can
964
   * probably fchdir back to old_cd later. */
965

Niels Möller's avatar
Niels Möller committed
966
  while (fchdir(dir) < 0)
967
968
969
970
971
972
    if (errno != EINTR)
      {
	close(old_cd);
	return -1;
      }

Niels Möller's avatar
Niels Möller committed
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
  return old_cd;
}

/* Changes the cwd, making sure that it it has reasonable permissions,
 * and that we can change back later. */
int
lsh_pushd(const char *directory,
	  /* The fd to the directory is stored in *FD, unless fd is
	   * NULL */
	  int *result,
	  int create, int secret)
{
  int old_cd;
  int fd;
  struct stat sbuf;

  if (create)
    {  
      /* First create the directory, in case it doesn't yet exist. */
      if ( (mkdir(directory, 0700) < 0)
	   && (errno != EEXIST) )
	{
	  werror("io.c: Creating directory %z failed "
996
		 "%e\n", directory, errno);
Niels Möller's avatar
Niels Möller committed
997
998
999
1000
1001
1002
1003
	}
    }

  fd = open(directory, O_RDONLY);
  if (fd < 0)
    return -1;

1004
1005
  io_set_close_on_exec(fd);
  
Niels Möller's avatar
Niels Möller committed
1006
  if (fstat(fd, &sbuf) < 0)
1007
    {
Niels Möller's avatar
Niels Möller committed
1008
      werror("io.c: Failed to stat `%z'.\n"
1009
	     "  %e\n", directory, errno);
1010
      close(fd);
1011
1012
      return -1;
    }
Niels Möller's avatar
Niels Möller committed
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
  
  if (!S_ISDIR(sbuf.st_mode))
    {
      close(fd);
      return -1;
    }

  if (secret)
    {
      /* Check that it has reasonable permissions */
      if (sbuf.st_uid != getuid())
	{
	  werror("io.c: Socket directory %z not owned by user.\n", directory);

	  close(fd);
	  return -1;
	}
    
      if (sbuf.st_mode & (S_IRWXG | S_IRWXO))
	{
	  werror("io.c: Permission bits on %z are too loose.\n", directory);

	  close(fd);
	  return -1;
	}
    }
  
  /* cd to it, but first save old cwd */
1041

Niels Möller's avatar
Niels Möller committed
1042
1043
  old_cd = open(".", O_RDONLY);
  if (old_cd < 0)
1044
    {
Niels Möller's avatar
Niels Möller committed
1045
      werror("io.c: open('.') failed.\n");
1046

Niels Möller's avatar
Niels Möller committed
1047
      close(fd);
1048
      return -1;
1049
    }
Niels Möller's avatar
Niels Möller committed
1050

1051
1052
  io_set_close_on_exec(old_cd);

Niels Möller's avatar
Niels Möller committed
1053
1054
  /* Test if we are allowed to cd to our current working directory. */
  while (fchdir(old_cd) < 0)
1055
1056
1057
1058
1059
1060
    if (errno != EINTR)
      {
	werror("io.c: fchdir(\".\") failed %e\n", errno);
	close(fd);
	close(old_cd);
	return -1;
Niels Möller's avatar
Niels Möller committed
1061
1062
1063
1064
1065
1066
      }

  /* As far as I have been able to determine, all checks for
   * fchdir:ability is performed at the time the directory was opened.
   * Even if the directory is chmod:et to zero, or unlinked, we can
   * probably fchdir back to old_cd later. */
1067

Niels Möller's avatar
Niels Möller committed
1068
  while (fchdir(fd) < 0)
1069
1070
1071
1072
1073
1074
    if (errno != EINTR)
      {
	close(fd);
	close(old_cd);
	return -1;
      }
1075

Niels Möller's avatar
Niels Möller committed
1076
1077
1078
1079
1080
  if (result)
    *result = fd;
  else
    close(fd);
  
1081
  return old_cd;
1082
}
1083

1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
int
io_bind_sockaddr(struct sockaddr *addr, socklen_t addr_length)
{
  int yes = 1;
  int fd;

  fd = socket(addr->sa_family, SOCK_STREAM, 0);
  if (fd < 0)
    return -1;

  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes)) < 0)
    werror("setsockopt failed: %e\n", errno);
1096

1097
1098
1099
1100
1101
1102
1103
1104
  if (bind(fd, addr, addr_length) < 0)
    {
      close(fd);
      return -1;
    }

  return fd;
}
1105

1106
int
1107
io_bind_local(const struct local_info *info)
1108
{
1109
  int old_cd;
1110

1111
1112
1113
1114
  mode_t old_umask;
  struct sockaddr_un *local;
  socklen_t local_length;

1115
  int fd;
1116
1117
1118

  const char *cdir = lsh_get_cstring(info->directory);
  const char *cname = lsh_get_cstring(info->name);
1119
  uint32_t length = lsh_string_length(info->name);
1120
  
1121
1122
  assert(cdir);
  assert(cname);
1123
1124
1125

  /* NAME should not be a plain filename, with no directory separators.
   * In particular, it should not be an absolute filename. */
1126
  assert(!memchr(cname, '/', length));
1127

1128
  local_length = offsetof(struct sockaddr_un, sun_path) + length;
1129
  local = alloca(local_length + 1);
1130

Niels Möller's avatar
Niels Möller committed
1131
  local->sun_family = AF_UNIX;
1132
  memcpy(local->sun_path, cname, length);
1133
1134
  local->sun_path[length] = 0;
  
1135
  /* cd to it, but first save old cwd */
1136

Niels Möller's avatar
Niels Möller committed
1137
  old_cd = lsh_pushd(cdir, NULL, 1, 1);
1138
  if (old_cd < 0)
1139
    return -1;
1140

1141
  /* Ok, now the current directory should be a decent place for
1142
1143
1144
   * creating a socket. */

  /* Try unlinking any existing file. */
1145
  if ( (unlink(cname) < 0)
1146
1147
       && (errno != ENOENT))
    {
1148
1149
      werror("io.c: unlink '%S'/'%S' failed %e\n",
	     info->directory, info->name, errno);
Niels Möller's avatar
Niels Möller committed
1150
      lsh_popd(old_cd, cdir);
1151
      return -1;
1152
1153
1154
    }

  /* We have to change the umask, as that's the only way to control
1155
   * the permissions that bind uses. */
1156

1157
  old_umask = umask(0077);
1158

1159
  fd = io_bind_sockaddr((struct sockaddr *) local, local_length);
1160
1161
1162
1163
  
  /* Ok, now we restore umask and cwd */
  umask(old_umask);

1164
  lsh_popd(old_cd, cdir);
1165
1166
1167
1168

  return fd;
}

1169
1170
/* Uses a blocking connect */
int
1171
io_connect_local(const struct local_info *info)