rendservice.c 155 KB
Newer Older
1
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
Nick Mathewson's avatar
Nick Mathewson committed
2
 * Copyright (c) 2007-2018, The Tor Project, Inc. */
Nick Mathewson's avatar
Nick Mathewson committed
3
4
/* See LICENSE for licensing information */

Roger Dingledine's avatar
Roger Dingledine committed
5
6
7
8
/**
 * \file rendservice.c
 * \brief The hidden-service side of rendezvous functionality.
 **/
Nick Mathewson's avatar
Nick Mathewson committed
9

10
11
#define RENDSERVICE_PRIVATE

12
#include "core/or/or.h"
13
14
15

#include "app/config/config.h"
#include "core/mainloop/mainloop.h"
16
17
18
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
19
20
21
#include "core/or/policies.h"
#include "core/or/relay.h"
#include "feature/client/circpathbias.h"
22
#include "feature/control/control.h"
23
#include "feature/dirclient/dirclient.h"
24
#include "feature/dircommon/directory.h"
25
26
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_config.h"
27
28
29
#include "feature/hs_common/replaycache.h"
#include "feature/keymgt/loadkey.h"
#include "feature/nodelist/describe.h"
30
#include "feature/nodelist/networkstatus.h"
31
32
#include "feature/nodelist/nickname.h"
#include "feature/nodelist/node_select.h"
33
#include "feature/nodelist/nodelist.h"
34
35
#include "feature/nodelist/routerparse.h"
#include "feature/nodelist/routerset.h"
36
37
38
#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
#include "feature/rend/rendservice.h"
39
#include "feature/stats/predict_ports.h"
40
41
42
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
43
#include "lib/encoding/confline.h"
44
#include "lib/net/resolve.h"
Nick Mathewson's avatar
Nick Mathewson committed
45

46
47
48
49
50
51
52
53
54
55
56
57
#include "core/or/cpath_build_state_st.h"
#include "core/or/crypt_path_st.h"
#include "core/or/crypt_path_reference_st.h"
#include "core/or/edge_connection_st.h"
#include "core/or/extend_info_st.h"
#include "feature/nodelist/networkstatus_st.h"
#include "core/or/origin_circuit_st.h"
#include "feature/rend/rend_authorized_client_st.h"
#include "feature/rend/rend_encoded_v2_service_descriptor_st.h"
#include "feature/rend/rend_intro_point_st.h"
#include "feature/rend/rend_service_descriptor_st.h"
#include "feature/nodelist/routerstatus_st.h"
58

59
60
61
62
63
64
65
66
67
68
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif

69
struct rend_service_t;
70
static origin_circuit_t *find_intro_circuit(rend_intro_point_t *intro,
71
                                            const char *pk_digest);
72
static rend_intro_point_t *find_intro_point(origin_circuit_t *circ);
73
74
static rend_intro_point_t *find_expiring_intro_point(
    struct rend_service_t *service, origin_circuit_t *circ);
75

76
77
static extend_info_t *find_rp_for_intro(
    const rend_intro_cell_t *intro,
78
    char **err_msg_out);
79

80
static int intro_point_accepted_intro_count(rend_intro_point_t *intro);
81
82
static int intro_point_should_expire_now(rend_intro_point_t *intro,
                                         time_t now);
83
static int rend_service_derive_key_digests(struct rend_service_t *s);
84
static int rend_service_load_keys(struct rend_service_t *s);
85
86
static int rend_service_load_auth_keys(struct rend_service_t *s,
                                       const char *hfname);
87
88
89
90
91
static struct rend_service_t *rend_service_get_by_pk_digest(
    const char* digest);
static struct rend_service_t *rend_service_get_by_service_id(const char *id);
static const char *rend_service_escaped_dir(
    const struct rend_service_t *s);
92

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
static ssize_t rend_service_parse_intro_for_v0_or_v1(
    rend_intro_cell_t *intro,
    const uint8_t *buf,
    size_t plaintext_len,
    char **err_msg_out);
static ssize_t rend_service_parse_intro_for_v2(
    rend_intro_cell_t *intro,
    const uint8_t *buf,
    size_t plaintext_len,
    char **err_msg_out);
static ssize_t rend_service_parse_intro_for_v3(
    rend_intro_cell_t *intro,
    const uint8_t *buf,
    size_t plaintext_len,
    char **err_msg_out);

109
110
111
static int rend_service_check_private_dir(const or_options_t *options,
                                          const rend_service_t *s,
                                          int create);
112
113
114
115
static const smartlist_t* rend_get_service_list(
                                  const smartlist_t* substitute_service_list);
static smartlist_t* rend_get_service_list_mutable(
                                  smartlist_t* substitute_service_list);
116
static int rend_max_intro_circs_per_period(unsigned int n_intro_points_wanted);
117

118
119
120
121
122
123
124
/* Hidden service directory file names:
 * new file names should be added to rend_service_add_filenames_to_list()
 * for sandboxing purposes. */
static const char *private_key_fname = "private_key";
static const char *hostname_fname = "hostname";
static const char *client_keys_fname = "client_keys";
static const char *sos_poison_fname = "onion_service_non_anonymous";
Nick Mathewson's avatar
Nick Mathewson committed
125

126
/** A list of rend_service_t's for services run on this OP. */
127
static smartlist_t *rend_service_list = NULL;
128
129
130
131
/** A list of rend_service_t's for services run on this OP which is used as a
 * staging area before they are put in the main list in order to prune dying
 * service on config reload. */
static smartlist_t *rend_service_staging_list = NULL;
132
133
134
135
136
137
138
139
140
141
142
143
144
145

/* Like rend_get_service_list_mutable, but returns a read-only list. */
static const smartlist_t*
rend_get_service_list(const smartlist_t* substitute_service_list)
{
  /* It is safe to cast away the const here, because
   * rend_get_service_list_mutable does not actually modify the list */
  return rend_get_service_list_mutable((smartlist_t*)substitute_service_list);
}

/* Return a mutable list of hidden services.
 * If substitute_service_list is not NULL, return it.
 * Otherwise, check if the global rend_service_list is non-NULL, and if so,
 * return it.
146
 * Otherwise, log a BUG message and return NULL.
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
 * */
static smartlist_t*
rend_get_service_list_mutable(smartlist_t* substitute_service_list)
{
  if (substitute_service_list) {
    return substitute_service_list;
  }

  /* If no special service list is provided, then just use the global one. */

  if (BUG(!rend_service_list)) {
    /* No global HS list, which is a programmer error. */
    return NULL;
  }

  return rend_service_list;
}

165
/** Tells if onion service <b>s</b> is ephemeral.
166
 */
167
168
169
170
171
172
static unsigned int
rend_service_is_ephemeral(const struct rend_service_t *s)
{
  return (s->directory == NULL);
}

173
174
175
176
177
/** Returns a escaped string representation of the service, <b>s</b>.
 */
static const char *
rend_service_escaped_dir(const struct rend_service_t *s)
{
178
  return rend_service_is_ephemeral(s) ? "[EPHEMERAL]" : escaped(s->directory);
179
180
}

181
/** Return the number of rendezvous services we have configured. */
182
int
David Goulet's avatar
David Goulet committed
183
rend_num_services(void)
184
{
185
186
187
188
189
  if (!rend_service_list)
    return 0;
  return smartlist_len(rend_service_list);
}

190
/** Helper: free storage held by a single service authorized client entry. */
191
void
192
rend_authorized_client_free_(rend_authorized_client_t *client)
193
{
194
195
  if (!client)
    return;
196
  if (client->client_key)
197
    crypto_pk_free(client->client_key);
198
199
  if (client->client_name)
    memwipe(client->client_name, 0, strlen(client->client_name));
200
  tor_free(client->client_name);
201
  memwipe(client->descriptor_cookie, 0, sizeof(client->descriptor_cookie));
202
203
204
205
206
  tor_free(client);
}

/** Helper for strmap_free. */
static void
207
rend_authorized_client_free_void(void *authorized_client)
208
{
209
  rend_authorized_client_free_(authorized_client);
210
211
}

Nick Mathewson's avatar
Nick Mathewson committed
212
/** Release the storage held by <b>service</b>.
213
 */
214
STATIC void
215
rend_service_free_(rend_service_t *service)
Nick Mathewson's avatar
Nick Mathewson committed
216
{
217
218
219
  if (!service)
    return;

220
  tor_free(service->directory);
221
222
223
224
225
  if (service->ports) {
    SMARTLIST_FOREACH(service->ports, rend_service_port_config_t*, p,
                      rend_service_port_config_free(p));
    smartlist_free(service->ports);
  }
226
  if (service->private_key)
227
    crypto_pk_free(service->private_key);
228
229
230
231
232
  if (service->intro_nodes) {
    SMARTLIST_FOREACH(service->intro_nodes, rend_intro_point_t *, intro,
      rend_intro_point_free(intro););
    smartlist_free(service->intro_nodes);
  }
233
234
235
236
237
  if (service->expiring_nodes) {
    SMARTLIST_FOREACH(service->expiring_nodes, rend_intro_point_t *, intro,
                      rend_intro_point_free(intro););
    smartlist_free(service->expiring_nodes);
  }
238
239

  rend_service_descriptor_free(service->desc);
240
241
242
243
244
  if (service->clients) {
    SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *, c,
      rend_authorized_client_free(c););
    smartlist_free(service->clients);
  }
245
246
247
  if (service->accepted_intro_dh_parts) {
    replaycache_free(service->accepted_intro_dh_parts);
  }
248
  tor_free(service);
Nick Mathewson's avatar
Nick Mathewson committed
249
250
}

251
252
253
254
255
256
257
258
259
260
261
262
263
264
/* Release all the storage held in rend_service_staging_list. */
void
rend_service_free_staging_list(void)
{
  if (rend_service_staging_list) {
    SMARTLIST_FOREACH(rend_service_staging_list, rend_service_t*, ptr,
                      rend_service_free(ptr));
    smartlist_free(rend_service_staging_list);
    rend_service_staging_list = NULL;
  }
}

/** Release all the storage held in both rend_service_list and
 * rend_service_staging_list. */
265
266
void
rend_service_free_all(void)
Nick Mathewson's avatar
Nick Mathewson committed
267
{
268
269
270
271
272
273
  if (rend_service_list) {
    SMARTLIST_FOREACH(rend_service_list, rend_service_t*, ptr,
                      rend_service_free(ptr));
    smartlist_free(rend_service_list);
    rend_service_list = NULL;
  }
274
  rend_service_free_staging_list();
Nick Mathewson's avatar
Nick Mathewson committed
275
276
}

David Goulet's avatar
David Goulet committed
277
278
279
280
281
282
/* Initialize the subsystem. */
void
rend_service_init(void)
{
  tor_assert(!rend_service_list);
  tor_assert(!rend_service_staging_list);
283

David Goulet's avatar
David Goulet committed
284
285
  rend_service_list = smartlist_new();
  rend_service_staging_list = smartlist_new();
Nick Mathewson's avatar
Nick Mathewson committed
286
287
}

288
289
290
/* Validate a <b>service</b>. Use the <b>service_list</b> to make sure there
 * is no duplicate entry for the given service object. Return 0 if valid else
 * -1 if not.*/
291
static int
292
293
rend_validate_service(const smartlist_t *service_list,
                      const rend_service_t *service)
Nick Mathewson's avatar
Nick Mathewson committed
294
{
295
  tor_assert(service_list);
296
297
  tor_assert(service);

298
299
  if (service->max_streams_per_circuit < 0) {
    log_warn(LD_CONFIG, "Hidden service (%s) configured with negative max "
300
                        "streams per circuit.",
301
             rend_service_escaped_dir(service));
302
    goto invalid;
303
304
305
306
307
  }

  if (service->max_streams_close_circuit < 0 ||
      service->max_streams_close_circuit > 1) {
    log_warn(LD_CONFIG, "Hidden service (%s) configured with invalid "
308
                        "max streams handling.",
309
             rend_service_escaped_dir(service));
310
    goto invalid;
311
312
  }

Nick Mathewson's avatar
Nick Mathewson committed
313
  if (service->auth_type != REND_NO_AUTH &&
314
315
316
      (!service->clients || smartlist_len(service->clients) == 0)) {
    log_warn(LD_CONFIG, "Hidden service (%s) with client authorization but "
                        "no clients.",
317
             rend_service_escaped_dir(service));
318
    goto invalid;
319
320
  }

teor's avatar
teor committed
321
  if (!service->ports || !smartlist_len(service->ports)) {
322
    log_warn(LD_CONFIG, "Hidden service (%s) with no ports configured.",
323
             rend_service_escaped_dir(service));
324
325
326
327
328
329
330
331
332
    goto invalid;
  }

  /* Valid. */
  return 0;
 invalid:
  return -1;
}

David Goulet's avatar
David Goulet committed
333
334
335
/** Add it to <b>service_list</b>, or to the global rend_service_list if
 * <b>service_list</b> is NULL.  Return 0 on success.  On failure, free
 * <b>service</b> and return -1. Takes ownership of <b>service</b>. */
336
static int
teor's avatar
teor committed
337
rend_add_service(smartlist_t *service_list, rend_service_t *service)
Nick Mathewson's avatar
Nick Mathewson committed
338
339
340
341
{
  int i;
  rend_service_port_config_t *p;

342
343
  tor_assert(service);

344
  smartlist_t *s_list = rend_get_service_list_mutable(service_list);
345
346
  /* We must have a service list, even if it's a temporary one, so we can
   * check for duplicate services */
347
  if (BUG(!s_list)) {
348
    rend_service_free(service);
349
    return -1;
teor's avatar
teor committed
350
351
  }

352
  service->intro_nodes = smartlist_new();
353
  service->expiring_nodes = smartlist_new();
Nick Mathewson's avatar
Nick Mathewson committed
354

David Goulet's avatar
David Goulet committed
355
356
357
358
359
360
361
362
363
364
  log_debug(LD_REND,"Configuring service with directory %s",
            rend_service_escaped_dir(service));
  for (i = 0; i < smartlist_len(service->ports); ++i) {
    p = smartlist_get(service->ports, i);
    if (!(p->is_unix_addr)) {
      log_debug(LD_REND,
                "Service maps port %d to %s",
                p->virtual_port,
                fmt_addrport(&p->real_addr, p->real_port));
    } else {
365
#ifdef HAVE_SYS_UN_H
David Goulet's avatar
David Goulet committed
366
367
368
      log_debug(LD_REND,
                "Service maps port %d to socket at \"%s\"",
                p->virtual_port, p->unix_addr);
369
#else
David Goulet's avatar
David Goulet committed
370
371
372
373
374
375
376
      log_warn(LD_BUG,
               "Service maps port %d to an AF_UNIX socket, but we "
               "have no AF_UNIX support on this platform.  This is "
               "probably a bug.",
               p->virtual_port);
      rend_service_free(service);
      return -1;
377
#endif /* defined(HAVE_SYS_UN_H) */
Nick Mathewson's avatar
Nick Mathewson committed
378
379
    }
  }
David Goulet's avatar
David Goulet committed
380
381
382
  /* The service passed all the checks */
  tor_assert(s_list);
  smartlist_add(s_list, service);
383
384
385
386
387
388
389

  /* Notify that our global service list has changed only if this new service
   * went into our global list. If not, when we move service from the staging
   * list to the new list, a notify is triggered. */
  if (s_list == rend_service_list) {
    hs_service_map_has_changed();
  }
David Goulet's avatar
David Goulet committed
390
  return 0;
Nick Mathewson's avatar
Nick Mathewson committed
391
392
}

393
394
395
396
397
398
/** Return a new rend_service_port_config_t with its path set to
 * <b>socket_path</b> or empty if <b>socket_path</b> is NULL */
static rend_service_port_config_t *
rend_service_port_config_new(const char *socket_path)
{
  if (!socket_path)
399
    return tor_malloc_zero(sizeof(rend_service_port_config_t) + 1);
400
401
402
403
404
405
406
407
408

  const size_t pathlen = strlen(socket_path) + 1;
  rend_service_port_config_t *conf =
    tor_malloc_zero(sizeof(rend_service_port_config_t) + pathlen);
  memcpy(conf->unix_addr, socket_path, pathlen);
  conf->is_unix_addr = 1;
  return conf;
}

409
410
411
/** Parses a virtual-port to real-port/socket mapping separated by
 * the provided separator and returns a new rend_service_port_config_t,
 * or NULL and an optional error string on failure.
412
 *
413
 * The format is: VirtualPort SEP (IP|RealPort|IP:RealPort|'socket':path)?
Nick Mathewson's avatar
Nick Mathewson committed
414
415
 *
 * IP defaults to 127.0.0.1; RealPort defaults to VirtualPort.
Nick Mathewson's avatar
Nick Mathewson committed
416
 */
417
418
419
rend_service_port_config_t *
rend_service_parse_port_config(const char *string, const char *sep,
                               char **err_msg_out)
Nick Mathewson's avatar
Nick Mathewson committed
420
{
421
  smartlist_t *sl;
422
  int virtport;
423
  int realport = 0;
424
  uint16_t p;
425
  tor_addr_t addr;
426
  rend_service_port_config_t *result = NULL;
427
  unsigned int is_unix_addr = 0;
428
  const char *socket_path = NULL;
429
  char *err_msg = NULL;
430
  char *addrport = NULL;
431

432
  sl = smartlist_new();
433
  smartlist_split_string(sl, string, sep,
434
435
                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
  if (smartlist_len(sl) < 1 || BUG(smartlist_len(sl) > 2)) {
436
    err_msg = tor_strdup("Bad syntax in hidden service port configuration.");
437
    goto err;
Nick Mathewson's avatar
Nick Mathewson committed
438
  }
439
440
  virtport = (int)tor_parse_long(smartlist_get(sl,0), 10, 1, 65535, NULL,NULL);
  if (!virtport) {
441
    tor_asprintf(&err_msg, "Missing or invalid port %s in hidden service "
442
443
                   "port configuration", escaped(smartlist_get(sl,0)));

444
    goto err;
Nick Mathewson's avatar
Nick Mathewson committed
445
  }
446
  if (smartlist_len(sl) == 1) {
Nick Mathewson's avatar
Nick Mathewson committed
447
448
    /* No addr:port part; use default. */
    realport = virtport;
449
    tor_addr_from_ipv4h(&addr, 0x7F000001u); /* 127.0.0.1 */
450
  } else {
451
452
    int ret;

453
454
455
456
457
    const char *addrport_element = smartlist_get(sl,1);
    const char *rest = NULL;
    int is_unix;
    ret = port_cfg_line_extract_addrport(addrport_element, &addrport,
                                         &is_unix, &rest);
rl1987's avatar
rl1987 committed
458

459
    if (ret < 0) {
Nick Mathewson's avatar
Nick Mathewson committed
460
461
      tor_asprintf(&err_msg, "Couldn't process address <%s> from hidden "
                   "service configuration", addrport_element);
462
463
      goto err;
    }
rl1987's avatar
rl1987 committed
464
465
466
467
468
469
470

    if (rest && strlen(rest)) {
      err_msg = tor_strdup("HiddenServicePort parse error: invalid port "
                           "mapping");
      goto err;
    }

471
472
    if (is_unix) {
      socket_path = addrport;
473
      is_unix_addr = 1;
474
475
    } else if (strchr(addrport, ':') || strchr(addrport, '.')) {
      /* else try it as an IP:port pair if it has a : or . in it */
476
      if (tor_addr_port_lookup(addrport, &addr, &p)<0) {
477
478
        err_msg = tor_strdup("Unparseable address in hidden service port "
                             "configuration.");
479
480
481
482
483
        goto err;
      }
      realport = p?p:virtport;
    } else {
      /* No addr:port, no addr -- must be port. */
484
485
      realport = (int)tor_parse_long(addrport, 10, 1, 65535, NULL, NULL);
      if (!realport) {
486
487
488
        tor_asprintf(&err_msg, "Unparseable or out-of-range port %s in "
                     "hidden service port configuration.",
                     escaped(addrport));
489
        goto err;
490
      }
491
      tor_addr_from_ipv4h(&addr, 0x7F000001u); /* Default to 127.0.0.1 */
492
    }
Nick Mathewson's avatar
Nick Mathewson committed
493
494
  }

495
496
  /* Allow room for unix_addr */
  result = rend_service_port_config_new(socket_path);
Nick Mathewson's avatar
Nick Mathewson committed
497
  result->virtual_port = virtport;
498
499
500
501
502
503
504
  result->is_unix_addr = is_unix_addr;
  if (!is_unix_addr) {
    result->real_port = realport;
    tor_addr_copy(&result->real_addr, &addr);
    result->unix_addr[0] = '\0';
  }

505
 err:
506
  tor_free(addrport);
507
508
509
510
511
  if (err_msg_out != NULL) {
    *err_msg_out = err_msg;
  } else {
    tor_free(err_msg);
  }
512
513
  SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
  smartlist_free(sl);
514

Nick Mathewson's avatar
Nick Mathewson committed
515
516
517
  return result;
}

518
519
/** Release all storage held in a rend_service_port_config_t. */
void
520
rend_service_port_config_free_(rend_service_port_config_t *p)
521
522
523
524
{
  tor_free(p);
}

525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
/* Copy relevant data from service src to dst while pruning the service lists.
 * This should only be called during the pruning process which takes existing
 * services and copy their data to the newly configured services. The src
 * service replaycache will be set to NULL after this call. */
static void
copy_service_on_prunning(rend_service_t *dst, rend_service_t *src)
{
  tor_assert(dst);
  tor_assert(src);

  /* Keep the timestamps for when the content changed and the next upload
   * time so we can properly upload the descriptor if needed for the new
   * service object. */
  dst->desc_is_dirty = src->desc_is_dirty;
  dst->next_upload_time = src->next_upload_time;
  /* Move the replaycache to the new object. */
  dst->accepted_intro_dh_parts = src->accepted_intro_dh_parts;
  src->accepted_intro_dh_parts = NULL;
  /* Copy intro point information to destination service. */
  dst->intro_period_started = src->intro_period_started;
  dst->n_intro_circuits_launched = src->n_intro_circuits_launched;
  dst->n_intro_points_wanted = src->n_intro_points_wanted;
}

549
550
551
552
/* Helper: Actual implementation of the pruning on reload which we've
 * decoupled in order to make the unit test workeable without ugly hacks.
 * Furthermore, this function does NOT free any memory but will nullify the
 * temporary list pointer whatever happens. */
553
STATIC void
554
rend_service_prune_list_impl_(void)
555
556
{
  origin_circuit_t *ocirc = NULL;
557
558
559
560
561
  smartlist_t *surviving_services, *old_service_list, *new_service_list;

  /* When pruning our current service list, we must have a staging list that
   * contains what we want to check else it's a code flow error. */
  tor_assert(rend_service_staging_list);
562

563
564
565
566
567
568
569
570
571
572
573
574
575
576
  /* We are about to prune the current list of its dead service so set the
   * semantic for that list to be the "old" one. */
  old_service_list = rend_service_list;
  /* The staging list is now the "new" list so set this semantic. */
  new_service_list = rend_service_staging_list;
  /* After this, whatever happens, we'll use our new list. */
  rend_service_list = new_service_list;
  /* Finally, nullify the staging list pointer as we don't need it anymore
   * and it needs to be NULL before the next reload. */
  rend_service_staging_list = NULL;
  /* Nothing to prune if we have no service list so stop right away. */
  if (!old_service_list) {
    return;
  }
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621

  /* This contains all _existing_ services that survives the relaod that is
   * that haven't been removed from the configuration. The difference between
   * this list and the new service list is that the new list can possibly
   * contain newly configured service that have no introduction points opened
   * yet nor key material loaded or generated. */
  surviving_services = smartlist_new();

  /* Preserve the existing ephemeral services.
   *
   * This is the ephemeral service equivalent of the "Copy introduction
   * points to new services" block, except there's no copy required since
   * the service structure isn't regenerated.
   *
   * After this is done, all ephemeral services will be:
   *  * Removed from old_service_list, so the equivalent non-ephemeral code
   *    will not attempt to preserve them.
   *  * Added to the new_service_list (that previously only had the
   *    services listed in the configuration).
   *  * Added to surviving_services, which is the list of services that
   *    will NOT have their intro point closed.
   */
  SMARTLIST_FOREACH_BEGIN(old_service_list, rend_service_t *, old) {
    if (rend_service_is_ephemeral(old)) {
      SMARTLIST_DEL_CURRENT(old_service_list, old);
      smartlist_add(surviving_services, old);
      smartlist_add(new_service_list, old);
    }
  } SMARTLIST_FOREACH_END(old);

  /* Copy introduction points to new services. This is O(n^2), but it's only
   * called on reconfigure, so it's ok performance wise. */
  SMARTLIST_FOREACH_BEGIN(new_service_list, rend_service_t *, new) {
    SMARTLIST_FOREACH_BEGIN(old_service_list, rend_service_t *, old) {
      /* Skip ephemeral services as we only want to copy introduction points
       * from current services to newly configured one that already exists.
       * The same directory means it's the same service. */
      if (rend_service_is_ephemeral(new) || rend_service_is_ephemeral(old) ||
          strcmp(old->directory, new->directory)) {
        continue;
      }
      smartlist_add_all(new->intro_nodes, old->intro_nodes);
      smartlist_clear(old->intro_nodes);
      smartlist_add_all(new->expiring_nodes, old->expiring_nodes);
      smartlist_clear(old->expiring_nodes);
622
623
624
625

      /* Copy needed information from old to new. */
      copy_service_on_prunning(new, old);

626
627
628
629
630
631
632
633
634
635
      /* This regular service will survive the closing IPs step after. */
      smartlist_add(surviving_services, old);
      break;
    } SMARTLIST_FOREACH_END(old);
  } SMARTLIST_FOREACH_END(new);

  /* For every service introduction circuit we can find, see if we have a
   * matching surviving configured service. If not, close the circuit. */
  while ((ocirc = circuit_get_next_service_intro_circ(ocirc))) {
    int keep_it = 0;
636
637
638
639
    if (ocirc->rend_data == NULL) {
      /* This is a v3 circuit, ignore it. */
      continue;
    }
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
    SMARTLIST_FOREACH_BEGIN(surviving_services, const rend_service_t *, s) {
      if (rend_circuit_pk_digest_eq(ocirc, (uint8_t *) s->pk_digest)) {
        /* Keep this circuit as we have a matching configured service. */
        keep_it = 1;
        break;
      }
    } SMARTLIST_FOREACH_END(s);
    if (keep_it) {
      continue;
    }
    log_info(LD_REND, "Closing intro point %s for service %s.",
             safe_str_client(extend_info_describe(
                                        ocirc->build_state->chosen_exit)),
             safe_str_client(rend_data_get_address(ocirc->rend_data)));
    /* Reason is FINISHED because service has been removed and thus the
     * circuit is considered old/uneeded. */
    circuit_mark_for_close(TO_CIRCUIT(ocirc), END_CIRC_REASON_FINISHED);
  }
  smartlist_free(surviving_services);
659
660
  /* Notify that our global service list has changed. */
  hs_service_map_has_changed();
661
662
}

663
664
665
666
667
668
669
/* Try to prune our main service list using the temporary one that we just
 * loaded and parsed successfully. The pruning process decides which onion
 * services to keep and which to discard after a reload. */
void
rend_service_prune_list(void)
{
  smartlist_t *old_service_list = rend_service_list;
670

671
  if (!rend_service_staging_list) {
672
    rend_service_staging_list = smartlist_new();
673
  }
674

675
676
677
678
679
680
681
682
683
684
  rend_service_prune_list_impl_();
  if (old_service_list) {
    /* Every remaining service in the old list have been removed from the
     * configuration so clean them up safely. */
    SMARTLIST_FOREACH(old_service_list, rend_service_t *, s,
                      rend_service_free(s));
    smartlist_free(old_service_list);
  }
}

685
686
687
688
689
690
/* Copy all the relevant data that the hs_service object contains over to the
 * rend_service_t object. The reason to do so is because when configuring a
 * service, we go through a generic handler that creates an hs_service_t
 * object which so we have to copy the parsed values to a rend service object
 * which is version 2 specific. */
static void
691
692
service_config_shadow_copy(rend_service_t *service,
                           hs_service_config_t *config)
693
694
{
  tor_assert(service);
695
  tor_assert(config);
696
697
698
699

  service->directory = tor_strdup(config->directory_path);
  service->dir_group_readable = config->dir_group_readable;
  service->allow_unknown_ports = config->allow_unknown_ports;
David Goulet's avatar
David Goulet committed
700
701
702
703
704
705
706
707
  /* This value can't go above HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT (65535)
   * if the code flow is right so this cast is safe. But just in case, we'll
   * check it. */
  service->max_streams_per_circuit = (int) config->max_streams_per_rdv_circuit;
  if (BUG(config->max_streams_per_rdv_circuit >
          HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT)) {
    service->max_streams_per_circuit = HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT;
  }
708
709
710
711
  service->max_streams_close_circuit = config->max_streams_close_circuit;
  service->n_intro_points_wanted = config->num_intro_points;
  /* Switching ownership of the ports to the rend service object. */
  smartlist_add_all(service->ports, config->ports);
712
713
  smartlist_free(config->ports);
  config->ports = NULL;
714
715
716
}

/* Parse the hidden service configuration starting at <b>line_</b> using the
717
718
719
720
 * already configured generic service configuration in <b>config</b>. This
 * function will translate the config object to a rend_service_t and add it to
 * the temporary list if valid. If <b>validate_only</b> is set, parse, warn
 * and return as normal but don't actually add the service to the list. */
721
int
722
723
rend_config_service(const config_line_t *line_,
                    const or_options_t *options,
724
                    hs_service_config_t *config)
Nick Mathewson's avatar
Nick Mathewson committed
725
{
726
  const config_line_t *line;
Nick Mathewson's avatar
Nick Mathewson committed
727
  rend_service_t *service = NULL;
728
729
730
731

  /* line_ can be NULL which would mean that the service configuration only
   * have one line that is the directory directive. */
  tor_assert(options);
732
  tor_assert(config);
733

734
735
736
737
738
  /* Use the staging service list so that we can check then do the pruning
   * process using the main list at the end. */
  if (rend_service_staging_list == NULL) {
    rend_service_staging_list = smartlist_new();
  }
Nick Mathewson's avatar
Nick Mathewson committed
739

740
741
742
743
744
745
  /* Initialize service. */
  service = tor_malloc_zero(sizeof(rend_service_t));
  service->intro_period_started = time(NULL);
  service->ports = smartlist_new();
  /* From the hs_service object which has been used to load the generic
   * options, we'll copy over the useful data to the rend_service_t object. */
746
  service_config_shadow_copy(service, config);
747
748

  for (line = line_; line; line = line->next) {
Nick Mathewson's avatar
Nick Mathewson committed
749
    if (!strcasecmp(line->key, "HiddenServiceDir")) {
750
751
      /* We just hit the next hidden service, stop right now. */
      break;
752
    }
753
754
755
756
    /* Number of introduction points. */
    if (!strcasecmp(line->key, "HiddenServiceNumIntroductionPoints")) {
      int ok = 0;
      /* Those are specific defaults for version 2. */
757
758
      service->n_intro_points_wanted =
        (unsigned int) tor_parse_long(line->value, 10,
759
                                      0, NUM_INTRO_POINTS_MAX, &ok, NULL);
760
761
762
763
      if (!ok) {
        log_warn(LD_CONFIG,
                 "HiddenServiceNumIntroductionPoints "
                 "should be between %d and %d, not %s",
764
                 0, NUM_INTRO_POINTS_MAX, line->value);
765
        goto err;
766
767
      }
      log_info(LD_CONFIG, "HiddenServiceNumIntroductionPoints=%d for %s",
768
769
770
771
               service->n_intro_points_wanted, escaped(service->directory));
      continue;
    }
    if (!strcasecmp(line->key, "HiddenServiceAuthorizeClient")) {
772
773
774
775
776
777
778
779
      /* Parse auth type and comma-separated list of client names and add a
       * rend_authorized_client_t for each client to the service's list
       * of authorized clients. */
      smartlist_t *type_names_split, *clients;
      const char *authname;
      if (service->auth_type != REND_NO_AUTH) {
        log_warn(LD_CONFIG, "Got multiple HiddenServiceAuthorizeClient "
                 "lines for a single service.");
780
        goto err;
781
782
783
784
785
786
787
      }
      type_names_split = smartlist_new();
      smartlist_split_string(type_names_split, line->value, " ", 0, 2);
      if (smartlist_len(type_names_split) < 1) {
        log_warn(LD_BUG, "HiddenServiceAuthorizeClient has no value. This "
                         "should have been prevented when parsing the "
                         "configuration.");
788
789
        smartlist_free(type_names_split);
        goto err;
790
791
792
793
794
795
796
797
798
799
800
801
802
      }
      authname = smartlist_get(type_names_split, 0);
      if (!strcasecmp(authname, "basic")) {
        service->auth_type = REND_BASIC_AUTH;
      } else if (!strcasecmp(authname, "stealth")) {
        service->auth_type = REND_STEALTH_AUTH;
      } else {
        log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains "
                 "unrecognized auth-type '%s'. Only 'basic' or 'stealth' "
                 "are recognized.",
                 (char *) smartlist_get(type_names_split, 0));
        SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
        smartlist_free(type_names_split);
803
        goto err;
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
      }
      service->clients = smartlist_new();
      if (smartlist_len(type_names_split) < 2) {
        log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains "
                            "auth-type '%s', but no client names.",
                 service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth");
        SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
        smartlist_free(type_names_split);
        continue;
      }
      clients = smartlist_new();
      smartlist_split_string(clients, smartlist_get(type_names_split, 1),
                             ",", SPLIT_SKIP_SPACE, 0);
      SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
      smartlist_free(type_names_split);
      /* Remove duplicate client names. */
820
821
822
823
824
825
826
827
828
      {
        int num_clients = smartlist_len(clients);
        smartlist_sort_strings(clients);
        smartlist_uniq_strings(clients);
        if (smartlist_len(clients) < num_clients) {
          log_info(LD_CONFIG, "HiddenServiceAuthorizeClient contains %d "
                   "duplicate client name(s); removing.",
                   num_clients - smartlist_len(clients));
        }
Nick Mathewson's avatar
Nick Mathewson committed
829
      }
830
831
832
      SMARTLIST_FOREACH_BEGIN(clients, const char *, client_name)
      {
        rend_authorized_client_t *client;
833
        if (!rend_valid_client_name(client_name)) {
834
          log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains an "
835
836
837
                              "illegal client name: '%s'. Names must be "
                              "between 1 and %d characters and contain "
                              "only [A-Za-z0-9+_-].",
Nick Mathewson's avatar
Nick Mathewson committed
838
                   client_name, REND_CLIENTNAME_MAX_LEN);
839
840
          SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp));
          smartlist_free(clients);
841
          goto err;
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
        }
        client = tor_malloc_zero(sizeof(rend_authorized_client_t));
        client->client_name = tor_strdup(client_name);
        smartlist_add(service->clients, client);
        log_debug(LD_REND, "Adding client name '%s'", client_name);
      }
      SMARTLIST_FOREACH_END(client_name);
      SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp));
      smartlist_free(clients);
      /* Ensure maximum number of clients. */
      if ((service->auth_type == REND_BASIC_AUTH &&
            smartlist_len(service->clients) > 512) ||
          (service->auth_type == REND_STEALTH_AUTH &&
            smartlist_len(service->clients) > 16)) {
        log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains %d "
                            "client authorization entries, but only a "
                            "maximum of %d entries is allowed for "
Nick Mathewson's avatar
Nick Mathewson committed
859
                            "authorization type '%s'.",
860
861
                 smartlist_len(service->clients),
                 service->auth_type == REND_BASIC_AUTH ? 512 : 16,
862
                 service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth");
863
        goto err;
864
      }
865
      continue;
Nick Mathewson's avatar
Nick Mathewson committed
866
867
    }
  }
868
869
870
871
  /* Validate the service just parsed. */
  if (rend_validate_service(rend_service_staging_list, service) < 0) {
    /* Service is in the staging list so don't try to free it. */
    goto err;
872
  }
Nick Mathewson's avatar
Nick Mathewson committed
873

874
875
876
877
878
879
  /* Add it to the temporary list which we will use to prune our current
   * list if any after configuring all services. */
  if (rend_add_service(rend_service_staging_list, service) < 0) {
    /* The object has been freed on error already. */
    service = NULL;
    goto err;
880
881
  }

Nick Mathewson's avatar
Nick Mathewson committed
882
  return 0;
883
 err:
884
  rend_service_free(service);
885
  return -1;
Nick Mathewson's avatar
Nick Mathewson committed
886
887
}

888
889
890
/** Add the ephemeral service <b>pk</b>/<b>ports</b> if possible, using
 * client authorization <b>auth_type</b> and an optional list of
 * rend_authorized_client_t in <b>auth_clients</b>, with
891
892
893
 * <b>max_streams_per_circuit</b> streams allowed per rendezvous circuit,
 * and circuit closure on max streams being exceeded set by
 * <b>max_streams_close_circuit</b>.
894
 *
895
896
897
898
 * Ownership of pk, ports, and auth_clients is passed to this routine.
 * Regardless of success/failure, callers should not touch these values
 * after calling this routine, and may assume that correct cleanup has
 * been done on failure.
899
 *
900
 * Return an appropriate hs_service_add_ephemeral_status_t.
901
 */
902
hs_service_add_ephemeral_status_t
903
904
rend_service_add_ephemeral(crypto_pk_t *pk,
                           smartlist_t *ports,
905
906
                           int max_streams_per_circuit,
                           int max_streams_close_circuit,
907
908
                           rend_auth_type_t auth_type,
                           smartlist_t *auth_clients,
909
910
911
912
913
914
915
916
917
                           char **service_id_out)
{
  *service_id_out = NULL;
  /* Allocate the service structure, and initialize the key, and key derived
   * parameters.
   */
  rend_service_t *s = tor_malloc_zero(sizeof(rend_service_t));
  s->directory = NULL; /* This indicates the service is ephemeral. */
  s->private_key = pk;
918
919
  s->auth_type = auth_type;
  s->clients = auth_clients;
920
921
922
  s->ports = ports;
  s->intro_period_started = time(NULL);
  s->n_intro_points_wanted = NUM_INTRO_POINTS_DEFAULT;
923
924
  s->max_streams_per_circuit = max_streams_per_circuit;
  s->max_streams_close_circuit = max_streams_close_circuit;
925
926
927
928
929
930
931
932
933
934
  if (rend_service_derive_key_digests(s) < 0) {
    rend_service_free(s);
    return RSAE_BADPRIVKEY;
  }

  if (!s->ports || smartlist_len(s->ports) == 0) {
    log_warn(LD_CONFIG, "At least one VIRTPORT/TARGET must be specified.");
    rend_service_free(s);
    return RSAE_BADVIRTPORT;
  }
935
936
937
938
939
940
  if (s->auth_type != REND_NO_AUTH &&
      (!s->clients || smartlist_len(s->clients) == 0)) {
    log_warn(LD_CONFIG, "At least one authorized client must be specified.");
    rend_service_free(s);
    return RSAE_BADAUTH;
  }
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957

  /* Enforcing pk/id uniqueness should be done by rend_service_load_keys(), but
   * it's not, see #14828.
   */
  if (rend_service_get_by_pk_digest(s->pk_digest)) {
    log_warn(LD_CONFIG, "Onion Service private key collides with an "
             "existing service.");
    rend_service_free(s);
    return RSAE_ADDREXISTS;
  }
  if (rend_service_get_by_service_id(s->service_id)) {
    log_warn(LD_CONFIG, "Onion Service id collides with an existing service.");
    rend_service_free(s);
    return RSAE_ADDREXISTS;
  }

  /* Initialize the service. */
teor's avatar
teor committed
958
  if (rend_add_service(NULL, s)) {
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
    return RSAE_INTERNAL;
  }
  *service_id_out = tor_strdup(s->service_id);

  log_debug(LD_CONFIG, "Added ephemeral Onion Service: %s", s->service_id);
  return RSAE_OKAY;
}

/** Remove the ephemeral service <b>service_id</b> if possible.  Returns 0 on
 * success, and -1 on failure.
 */
int
rend_service_del_ephemeral(const char *service_id)
{
  rend_service_t *s;
974
  if (!rend_valid_v2_service_id(service_id)) {
975
976
977
978
979
980
981
982
    log_warn(LD_CONFIG, "Requested malformed Onion Service id for removal.");
    return -1;
  }
  if ((s = rend_service_get_by_service_id(service_id)) == NULL) {
    log_warn(LD_CONFIG, "Requested non-existent Onion Service id for "
             "removal.");
    return -1;
  }
983
  if (!rend_service_is_ephemeral(s)) {
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
    log_warn(LD_CONFIG, "Requested non-ephemeral Onion Service for removal.");
    return -1;
  }

  /* Kill the intro point circuit for the Onion Service, and remove it from
   * the list.  Closing existing connections is the application's problem.
   *
   * XXX: As with the comment in rend_config_services(), a nice abstraction
   * would be ideal here, but for now just duplicate the code.
   */
  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
    if (!circ->marked_for_close &&
        (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
         circ->purpose == CIRCUIT_PURPOSE_S_INTRO)) {
      origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
999
1000
      if (oc->rend_data == NULL ||
          !rend_circuit_pk_digest_eq(oc, (uint8_t *) s->pk_digest)) {
For faster browsing, not all history is shown. View entire blame