rendservice.c 114 KB
Newer Older
1
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
2
 * Copyright (c) 2007-2013, 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

Nick Mathewson's avatar
Nick Mathewson committed
12
#include "or.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
13
#include "circuitbuild.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
14
#include "circuitlist.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
15
#include "circuituse.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
16
#include "config.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
17
#include "directory.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
18
#include "networkstatus.h"
19
#include "nodelist.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
20
#include "rendclient.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
21
#include "rendcommon.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
22
#include "rendservice.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
23
#include "router.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
24
#include "relay.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
25
#include "rephist.h"
26
#include "replaycache.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
27
#include "routerlist.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
28
#include "routerparse.h"
29
#include "routerset.h"
Nick Mathewson's avatar
Nick Mathewson committed
30

31
static origin_circuit_t *find_intro_circuit(rend_intro_point_t *intro,
32
                                            const char *pk_digest);
33
static rend_intro_point_t *find_intro_point(origin_circuit_t *circ);
34

35
36
37
38
static extend_info_t *find_rp_for_intro(
    const rend_intro_cell_t *intro,
    uint8_t *need_free_out, char **err_msg_out);

39
static int intro_point_accepted_intro_count(rend_intro_point_t *intro);
40
41
static int intro_point_should_expire_now(rend_intro_point_t *intro,
                                         time_t now);
42
43
struct rend_service_t;
static int rend_service_load_keys(struct rend_service_t *s);
44
45
static int rend_service_load_auth_keys(struct rend_service_t *s,
                                       const char *hfname);
46

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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);

Roger Dingledine's avatar
Roger Dingledine committed
63
/** Represents the mapping from a virtual port of a rendezvous service to
Nick Mathewson's avatar
Nick Mathewson committed
64
65
66
67
68
 * a real port on some IP.
 */
typedef struct rend_service_port_config_t {
  uint16_t virtual_port;
  uint16_t real_port;
69
  tor_addr_t real_addr;
Nick Mathewson's avatar
Nick Mathewson committed
70
71
} rend_service_port_config_t;

72
73
74
75
/** Try to maintain this many intro points per service by default. */
#define NUM_INTRO_POINTS_DEFAULT 3
/** Maintain no more than this many intro points per hidden service. */
#define NUM_INTRO_POINTS_MAX 10
Nick Mathewson's avatar
Nick Mathewson committed
76

77
/** If we can't build our intro circuits, don't retry for this long. */
78
#define INTRO_CIRC_RETRY_PERIOD (60*5)
79
80
/** Don't try to build more than this many circuits before giving up
 * for a while.*/
81
#define MAX_INTRO_CIRCS_PER_PERIOD 10
82
83
/** How many times will a hidden service operator attempt to connect to
 * a requested rendezvous point before giving up? */
84
85
86
87
#define MAX_REND_FAILURES 30
/** How many seconds should we spend trying to connect to a requested
 * rendezvous point before giving up? */
#define MAX_REND_TIMEOUT 30
88

89
90
91
92
/** How many seconds should we wait for new HS descriptors to reach
 * our clients before we close an expiring intro point? */
#define INTRO_POINT_EXPIRATION_GRACE_PERIOD 5*60

Roger Dingledine's avatar
Roger Dingledine committed
93
/** Represents a single hidden service running at this OP. */
Nick Mathewson's avatar
Nick Mathewson committed
94
typedef struct rend_service_t {
95
  /* Fields specified in config file */
Roger Dingledine's avatar
Roger Dingledine committed
96
97
  char *directory; /**< where in the filesystem it stores it */
  smartlist_t *ports; /**< List of rend_service_port_config_t */
98
99
100
  rend_auth_type_t auth_type; /**< Client authorization type or 0 if no client
                               * authorization is performed. */
  smartlist_t *clients; /**< List of rend_authorized_client_t's of
Nick Mathewson's avatar
Nick Mathewson committed
101
                         * clients that may access our service. Can be NULL
Nick Mathewson's avatar
Nick Mathewson committed
102
                         * if no client authorization is performed. */
Nick Mathewson's avatar
Nick Mathewson committed
103
  /* Other fields */
104
  crypto_pk_t *private_key; /**< Permanent hidden-service key. */
105
106
107
  char service_id[REND_SERVICE_ID_LEN_BASE32+1]; /**< Onion address without
                                                  * '.onion' */
  char pk_digest[DIGEST_LEN]; /**< Hash of permanent hidden-service key. */
108
  smartlist_t *intro_nodes; /**< List of rend_intro_point_t's we have,
109
                             * or are trying to establish. */
110
111
  time_t intro_period_started; /**< Start of the current period to build
                                * introduction points. */
112
  int n_intro_circuits_launched; /**< Count of intro circuits we have
113
                                  * established in this period. */
114
115
  unsigned int n_intro_points_wanted; /**< Number of intro points this
                                       * service wants to have open. */
116
117
118
119
120
121
  rend_service_descriptor_t *desc; /**< Current hidden service descriptor. */
  time_t desc_is_dirty; /**< Time at which changes to the hidden service
                         * descriptor content occurred, or 0 if it's
                         * up-to-date. */
  time_t next_upload_time; /**< Scheduled next hidden service descriptor
                            * upload time. */
122
123
124
125
126
127
  /** Replay cache for Diffie-Hellman values of INTRODUCE2 cells, to
   * detect repeats.  Clients may send INTRODUCE1 cells for the same
   * rendezvous point through two or more different introduction points;
   * when they do, this keeps us from launching multiple simultaneous attempts
   * to connect to the same rend point. */
  replaycache_t *accepted_intro_dh_parts;
Nick Mathewson's avatar
Nick Mathewson committed
128
129
} rend_service_t;

Roger Dingledine's avatar
Roger Dingledine committed
130
/** A list of rend_service_t's for services run on this OP.
Nick Mathewson's avatar
Nick Mathewson committed
131
132
133
 */
static smartlist_t *rend_service_list = NULL;

134
/** Return the number of rendezvous services we have configured. */
135
136
137
int
num_rend_services(void)
{
138
139
140
141
142
  if (!rend_service_list)
    return 0;
  return smartlist_len(rend_service_list);
}

143
144
145
146
147
148
149
150
151
152
153
/** Return a string identifying <b>service</b>, suitable for use in a
 * log message.  The result does not need to be freed, but may be
 * overwritten by the next call to this function. */
static const char *
rend_service_describe_for_log(rend_service_t *service)
{
  /* XXX024 Use this function throughout rendservice.c. */
  /* XXX024 Return a more useful description? */
  return safe_str_client(service->service_id);
}

154
155
156
157
/** Helper: free storage held by a single service authorized client entry. */
static void
rend_authorized_client_free(rend_authorized_client_t *client)
{
158
159
  if (!client)
    return;
160
  if (client->client_key)
161
    crypto_pk_free(client->client_key);
162
  tor_strclear(client->client_name);
163
  tor_free(client->client_name);
164
  memwipe(client->descriptor_cookie, 0, sizeof(client->descriptor_cookie));
165
166
167
168
169
170
171
172
173
174
  tor_free(client);
}

/** Helper for strmap_free. */
static void
rend_authorized_client_strmap_item_free(void *authorized_client)
{
  rend_authorized_client_free(authorized_client);
}

Nick Mathewson's avatar
Nick Mathewson committed
175
/** Release the storage held by <b>service</b>.
176
 */
177
178
static void
rend_service_free(rend_service_t *service)
Nick Mathewson's avatar
Nick Mathewson committed
179
{
180
181
182
  if (!service)
    return;

183
184
185
186
  tor_free(service->directory);
  SMARTLIST_FOREACH(service->ports, void*, p, tor_free(p));
  smartlist_free(service->ports);
  if (service->private_key)
187
    crypto_pk_free(service->private_key);
188
189
190
191
192
  if (service->intro_nodes) {
    SMARTLIST_FOREACH(service->intro_nodes, rend_intro_point_t *, intro,
      rend_intro_point_free(intro););
    smartlist_free(service->intro_nodes);
  }
193
194

  rend_service_descriptor_free(service->desc);
195
196
197
198
199
  if (service->clients) {
    SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *, c,
      rend_authorized_client_free(c););
    smartlist_free(service->clients);
  }
200
201
202
  if (service->accepted_intro_dh_parts) {
    replaycache_free(service->accepted_intro_dh_parts);
  }
203
  tor_free(service);
Nick Mathewson's avatar
Nick Mathewson committed
204
205
}

Roger Dingledine's avatar
Roger Dingledine committed
206
/** Release all the storage held in rend_service_list.
207
 */
208
209
void
rend_service_free_all(void)
Nick Mathewson's avatar
Nick Mathewson committed
210
{
211
  if (!rend_service_list)
Nick Mathewson's avatar
Nick Mathewson committed
212
    return;
213

Nick Mathewson's avatar
Nick Mathewson committed
214
215
  SMARTLIST_FOREACH(rend_service_list, rend_service_t*, ptr,
                    rend_service_free(ptr));
Nick Mathewson's avatar
Nick Mathewson committed
216
  smartlist_free(rend_service_list);
217
  rend_service_list = NULL;
Nick Mathewson's avatar
Nick Mathewson committed
218
219
}

Nick Mathewson's avatar
Nick Mathewson committed
220
/** Validate <b>service</b> and add it to rend_service_list if possible.
221
 */
222
static void
Roger Dingledine's avatar
Roger Dingledine committed
223
rend_add_service(rend_service_t *service)
Nick Mathewson's avatar
Nick Mathewson committed
224
225
226
227
{
  int i;
  rend_service_port_config_t *p;

228
  service->intro_nodes = smartlist_new();
Nick Mathewson's avatar
Nick Mathewson committed
229

Nick Mathewson's avatar
Nick Mathewson committed
230
231
  if (service->auth_type != REND_NO_AUTH &&
      smartlist_len(service->clients) == 0) {
232
233
    log_warn(LD_CONFIG, "Hidden service (%s) with client authorization but no "
                        "clients; ignoring.",
234
             escaped(service->directory));
235
236
237
238
    rend_service_free(service);
    return;
  }

Nick Mathewson's avatar
Nick Mathewson committed
239
  if (!smartlist_len(service->ports)) {
240
241
    log_warn(LD_CONFIG, "Hidden service (%s) with no ports configured; "
             "ignoring.",
242
             escaped(service->directory));
Nick Mathewson's avatar
Nick Mathewson committed
243
244
    rend_service_free(service);
  } else {
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
    int dupe = 0;
    /* XXX This duplicate check has two problems:
     *
     * a) It's O(n^2), but the same comment from the bottom of
     *    rend_config_services() should apply.
     *
     * b) We only compare directory paths as strings, so we can't
     *    detect two distinct paths that specify the same directory
     *    (which can arise from symlinks, case-insensitivity, bind
     *    mounts, etc.).
     *
     * It also can't detect that two separate Tor instances are trying
     * to use the same HiddenServiceDir; for that, we would need a
     * lock file.  But this is enough to detect a simple mistake that
     * at least one person has actually made.
     */
    SMARTLIST_FOREACH(rend_service_list, rend_service_t*, ptr,
                      dupe = dupe ||
                             !strcmp(ptr->directory, service->directory));
    if (dupe) {
      log_warn(LD_REND, "Another hidden service is already configured for "
               "directory %s, ignoring.", service->directory);
      rend_service_free(service);
      return;
    }
Nick Mathewson's avatar
Nick Mathewson committed
270
    smartlist_add(rend_service_list, service);
271
272
    log_debug(LD_REND,"Configuring service with directory \"%s\"",
              service->directory);
Nick Mathewson's avatar
Nick Mathewson committed
273
274
    for (i = 0; i < smartlist_len(service->ports); ++i) {
      p = smartlist_get(service->ports, i);
275
276
      log_debug(LD_REND,"Service maps port %d to %s",
                p->virtual_port, fmt_addrport(&p->real_addr, p->real_port));
Nick Mathewson's avatar
Nick Mathewson committed
277
278
279
280
    }
  }
}

Roger Dingledine's avatar
Roger Dingledine committed
281
/** Parses a real-port to virtual-port mapping and returns a new
282
283
284
 * rend_service_port_config_t.
 *
 * The format is: VirtualPort (IP|RealPort|IP:RealPort)?
Nick Mathewson's avatar
Nick Mathewson committed
285
286
 *
 * IP defaults to 127.0.0.1; RealPort defaults to VirtualPort.
Nick Mathewson's avatar
Nick Mathewson committed
287
 */
288
289
static rend_service_port_config_t *
parse_port_config(const char *string)
Nick Mathewson's avatar
Nick Mathewson committed
290
{
291
  smartlist_t *sl;
292
  int virtport;
293
294
  int realport;
  uint16_t p;
295
  tor_addr_t addr;
296
297
298
  const char *addrport;
  rend_service_port_config_t *result = NULL;

299
  sl = smartlist_new();
300
301
  smartlist_split_string(sl, string, " ",
                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
302
  if (smartlist_len(sl) < 1 || smartlist_len(sl) > 2) {
303
    log_warn(LD_CONFIG, "Bad syntax in hidden service port configuration.");
304
    goto err;
Nick Mathewson's avatar
Nick Mathewson committed
305
  }
306

307
308
309
310
  virtport = (int)tor_parse_long(smartlist_get(sl,0), 10, 1, 65535, NULL,NULL);
  if (!virtport) {
    log_warn(LD_CONFIG, "Missing or invalid port %s in hidden service port "
             "configuration", escaped(smartlist_get(sl,0)));
311
    goto err;
Nick Mathewson's avatar
Nick Mathewson committed
312
  }
313
314

  if (smartlist_len(sl) == 1) {
Nick Mathewson's avatar
Nick Mathewson committed
315
316
    /* No addr:port part; use default. */
    realport = virtport;
317
    tor_addr_from_ipv4h(&addr, 0x7F000001u); /* 127.0.0.1 */
318
  } else {
319
320
    addrport = smartlist_get(sl,1);
    if (strchr(addrport, ':') || strchr(addrport, '.')) {
321
      if (tor_addr_port_lookup(addrport, &addr, &p)<0) {
322
323
        log_warn(LD_CONFIG,"Unparseable address in hidden service port "
                 "configuration.");
324
325
326
327
328
        goto err;
      }
      realport = p?p:virtport;
    } else {
      /* No addr:port, no addr -- must be port. */
329
330
331
332
      realport = (int)tor_parse_long(addrport, 10, 1, 65535, NULL, NULL);
      if (!realport) {
        log_warn(LD_CONFIG,"Unparseable or out-of-range port %s in hidden "
                 "service port configuration.", escaped(addrport));
333
        goto err;
334
      }
335
      tor_addr_from_ipv4h(&addr, 0x7F000001u); /* Default to 127.0.0.1 */
336
    }
Nick Mathewson's avatar
Nick Mathewson committed
337
338
339
340
341
  }

  result = tor_malloc(sizeof(rend_service_port_config_t));
  result->virtual_port = virtport;
  result->real_port = realport;
342
  tor_addr_copy(&result->real_addr, &addr);
343
344
345
 err:
  SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
  smartlist_free(sl);
Nick Mathewson's avatar
Nick Mathewson committed
346
347
348
  return result;
}

Roger Dingledine's avatar
Roger Dingledine committed
349
/** Set up rend_service_list, based on the values of HiddenServiceDir and
Nick Mathewson's avatar
Nick Mathewson committed
350
 * HiddenServicePort in <b>options</b>.  Return 0 on success and -1 on
351
352
 * failure.  (If <b>validate_only</b> is set, parse, warn and return as
 * normal, but don't actually change the configured services.)
Nick Mathewson's avatar
Nick Mathewson committed
353
 */
354
int
355
rend_config_services(const or_options_t *options, int validate_only)
Nick Mathewson's avatar
Nick Mathewson committed
356
{
357
  config_line_t *line;
Nick Mathewson's avatar
Nick Mathewson committed
358
359
  rend_service_t *service = NULL;
  rend_service_port_config_t *portcfg;
360
  smartlist_t *old_service_list = NULL;
361

362
  if (!validate_only) {
363
    old_service_list = rend_service_list;
364
    rend_service_list = smartlist_new();
365
  }
Nick Mathewson's avatar
Nick Mathewson committed
366
367
368

  for (line = options->RendConfigLines; line; line = line->next) {
    if (!strcasecmp(line->key, "HiddenServiceDir")) {
369
      if (service) { /* register the one we just finished parsing */
370
371
372
        if (validate_only)
          rend_service_free(service);
        else
Roger Dingledine's avatar
Roger Dingledine committed
373
          rend_add_service(service);
374
      }
Nick Mathewson's avatar
Nick Mathewson committed
375
376
      service = tor_malloc_zero(sizeof(rend_service_t));
      service->directory = tor_strdup(line->value);
377
      service->ports = smartlist_new();
378
      service->intro_period_started = time(NULL);
379
      service->n_intro_points_wanted = NUM_INTRO_POINTS_DEFAULT;
380
381
382
      continue;
    }
    if (!service) {
383
384
      log_warn(LD_CONFIG, "%s with no preceding HiddenServiceDir directive",
               line->key);
385
386
387
388
      rend_service_free(service);
      return -1;
    }
    if (!strcasecmp(line->key, "HiddenServicePort")) {
Nick Mathewson's avatar
Nick Mathewson committed
389
390
      portcfg = parse_port_config(line->value);
      if (!portcfg) {
Roger Dingledine's avatar
tabs    
Roger Dingledine committed
391
392
        rend_service_free(service);
        return -1;
Nick Mathewson's avatar
Nick Mathewson committed
393
394
      }
      smartlist_add(service->ports, portcfg);
395
396
397
398
399
400
    } else if (!strcasecmp(line->key, "HiddenServiceAuthorizeClient")) {
      /* 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;
Nick Mathewson's avatar
Nick Mathewson committed
401
402
      int num_clients;
      if (service->auth_type != REND_NO_AUTH) {
403
404
405
406
407
        log_warn(LD_CONFIG, "Got multiple HiddenServiceAuthorizeClient "
                 "lines for a single service.");
        rend_service_free(service);
        return -1;
      }
408
      type_names_split = smartlist_new();
Nick Mathewson's avatar
Nick Mathewson committed
409
      smartlist_split_string(type_names_split, line->value, " ", 0, 2);
410
411
412
413
414
415
416
417
418
      if (smartlist_len(type_names_split) < 1) {
        log_warn(LD_BUG, "HiddenServiceAuthorizeClient has no value. This "
                         "should have been prevented when parsing the "
                         "configuration.");
        smartlist_free(type_names_split);
        rend_service_free(service);
        return -1;
      }
      authname = smartlist_get(type_names_split, 0);
Nick Mathewson's avatar
Nick Mathewson committed
419
      if (!strcasecmp(authname, "basic")) {
420
        service->auth_type = REND_BASIC_AUTH;
Nick Mathewson's avatar
Nick Mathewson committed
421
      } else if (!strcasecmp(authname, "stealth")) {
422
423
424
        service->auth_type = REND_STEALTH_AUTH;
      } else {
        log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains "
Nick Mathewson's avatar
Nick Mathewson committed
425
426
                 "unrecognized auth-type '%s'. Only 'basic' or 'stealth' "
                 "are recognized.",
427
428
429
430
431
432
                 (char *) smartlist_get(type_names_split, 0));
        SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
        smartlist_free(type_names_split);
        rend_service_free(service);
        return -1;
      }
433
      service->clients = smartlist_new();
434
435
      if (smartlist_len(type_names_split) < 2) {
        log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains "
Nick Mathewson's avatar
Nick Mathewson committed
436
                            "auth-type '%s', but no client names.",
437
                 service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth");
438
439
440
441
        SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
        smartlist_free(type_names_split);
        continue;
      }
442
      clients = smartlist_new();
443
      smartlist_split_string(clients, smartlist_get(type_names_split, 1),
Nick Mathewson's avatar
Nick Mathewson committed
444
                             ",", SPLIT_SKIP_SPACE, 0);
445
446
      SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
      smartlist_free(type_names_split);
Nick Mathewson's avatar
Nick Mathewson committed
447
448
449
450
451
452
453
454
455
456
      /* Remove duplicate client names. */
      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));
        num_clients = smartlist_len(clients);
      }
457
458
459
460
      SMARTLIST_FOREACH_BEGIN(clients, const char *, client_name)
      {
        rend_authorized_client_t *client;
        size_t len = strlen(client_name);
Nick Mathewson's avatar
Nick Mathewson committed
461
        if (len < 1 || len > REND_CLIENTNAME_MAX_LEN) {
462
463
          log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains an "
                              "illegal client name: '%s'. Length must be "
Nick Mathewson's avatar
Nick Mathewson committed
464
465
                              "between 1 and %d characters.",
                   client_name, REND_CLIENTNAME_MAX_LEN);
466
467
468
469
470
471
472
473
          SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp));
          smartlist_free(clients);
          rend_service_free(service);
          return -1;
        }
        if (strspn(client_name, REND_LEGAL_CLIENTNAME_CHARACTERS) != len) {
          log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains an "
                              "illegal client name: '%s'. Valid "
Robert Ransom's avatar
Robert Ransom committed
474
                              "characters are [A-Za-z0-9+_-].",
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
                   client_name);
          SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp));
          smartlist_free(clients);
          rend_service_free(service);
          return -1;
        }
        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
497
                            "authorization type '%s'.",
498
499
                 smartlist_len(service->clients),
                 service->auth_type == REND_BASIC_AUTH ? 512 : 16,
500
                 service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth");
501
502
503
        rend_service_free(service);
        return -1;
      }
504
505
    } else {
      tor_assert(!strcasecmp(line->key, "HiddenServiceVersion"));
506
507
508
509
510
      if (strcmp(line->value, "2")) {
        log_warn(LD_CONFIG,
                 "The only supported HiddenServiceVersion is 2.");
        rend_service_free(service);
        return -1;
511
      }
Nick Mathewson's avatar
Nick Mathewson committed
512
513
    }
  }
514
515
516
517
  if (service) {
    if (validate_only)
      rend_service_free(service);
    else
Roger Dingledine's avatar
Roger Dingledine committed
518
      rend_add_service(service);
519
  }
Nick Mathewson's avatar
Nick Mathewson committed
520

521
522
523
524
  /* If this is a reload and there were hidden services configured before,
   * keep the introduction points that are still needed and close the
   * other ones. */
  if (old_service_list && !validate_only) {
525
    smartlist_t *surviving_services = smartlist_new();
526
527
528
529
530
    circuit_t *circ;

    /* Copy introduction points to new services. */
    /* XXXX This is O(n^2), but it's only called on reconfigure, so it's
     * probably ok? */
531
532
    SMARTLIST_FOREACH_BEGIN(rend_service_list, rend_service_t *, new) {
      SMARTLIST_FOREACH_BEGIN(old_service_list, rend_service_t *, old) {
533
        if (!strcmp(old->directory, new->directory)) {
534
535
536
537
538
          smartlist_add_all(new->intro_nodes, old->intro_nodes);
          smartlist_clear(old->intro_nodes);
          smartlist_add(surviving_services, old);
          break;
        }
539
540
      } SMARTLIST_FOREACH_END(old);
    } SMARTLIST_FOREACH_END(new);
541
542
543
544
545

    /* Close introduction circuits of services we don't serve anymore. */
    /* XXXX it would be nicer if we had a nicer abstraction to use here,
     * so we could just iterate over the list of services to close, but
     * once again, this isn't critical-path code. */
546
    for (circ = circuit_get_global_list_(); circ; circ = circ->next) {
547
548
549
550
551
552
553
554
      if (!circ->marked_for_close &&
          circ->state == CIRCUIT_STATE_OPEN &&
          (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
           circ->purpose == CIRCUIT_PURPOSE_S_INTRO)) {
        origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
        int keep_it = 0;
        tor_assert(oc->rend_data);
        SMARTLIST_FOREACH(surviving_services, rend_service_t *, ptr, {
555
          if (tor_memeq(ptr->pk_digest, oc->rend_data->rend_pk_digest,
556
                      DIGEST_LEN)) {
557
558
559
560
561
562
            keep_it = 1;
            break;
          }
        });
        if (keep_it)
          continue;
563
        log_info(LD_REND, "Closing intro point %s for service %s.",
564
565
                 safe_str_client(extend_info_describe(
                                            oc->build_state->chosen_exit)),
566
                 oc->rend_data->onion_address);
567
568
569
570
571
572
573
574
575
576
        circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
        /* XXXX Is there another reason we should use here? */
      }
    }
    smartlist_free(surviving_services);
    SMARTLIST_FOREACH(old_service_list, rend_service_t *, ptr,
                      rend_service_free(ptr));
    smartlist_free(old_service_list);
  }

Nick Mathewson's avatar
Nick Mathewson committed
577
578
579
  return 0;
}

Nick Mathewson's avatar
Nick Mathewson committed
580
/** Replace the old value of <b>service</b>-\>desc with one that reflects
Nick Mathewson's avatar
Nick Mathewson committed
581
 * the other fields in service.
Nick Mathewson's avatar
Nick Mathewson committed
582
 */
583
584
static void
rend_service_update_descriptor(rend_service_t *service)
Nick Mathewson's avatar
Nick Mathewson committed
585
586
{
  rend_service_descriptor_t *d;
587
  origin_circuit_t *circ;
588
  int i;
589
590
591
592

  rend_service_descriptor_free(service->desc);
  service->desc = NULL;

593
  d = service->desc = tor_malloc_zero(sizeof(rend_service_descriptor_t));
Nick Mathewson's avatar
Nick Mathewson committed
594
595
  d->pk = crypto_pk_dup_key(service->private_key);
  d->timestamp = time(NULL);
596
  d->intro_nodes = smartlist_new();
597
598
  /* Support intro protocols 2 and 3. */
  d->protocols = (1 << 2) + (1 << 3);
599

600
601
602
  for (i = 0; i < smartlist_len(service->intro_nodes); ++i) {
    rend_intro_point_t *intro_svc = smartlist_get(service->intro_nodes, i);
    rend_intro_point_t *intro_desc;
603
604
605
606

    /* This intro point won't be listed in the descriptor... */
    intro_svc->listed_in_last_desc = 0;

607
608
609
610
611
    if (intro_svc->time_expiring != -1) {
      /* This intro point is expiring.  Don't list it. */
      continue;
    }

612
    circ = find_intro_circuit(intro_svc, service->pk_digest);
613
    if (!circ || circ->base_.purpose != CIRCUIT_PURPOSE_S_INTRO) {
614
      /* This intro point's circuit isn't finished yet.  Don't list it. */
615
      continue;
616
    }
617

618
619
    /* ...unless this intro point is listed in the descriptor. */
    intro_svc->listed_in_last_desc = 1;
620

Robert Ransom's avatar
Robert Ransom committed
621
622
    /* We have an entirely established intro circuit.  Publish it in
     * our descriptor. */
623
624
625
626
627
    intro_desc = tor_malloc_zero(sizeof(rend_intro_point_t));
    intro_desc->extend_info = extend_info_dup(intro_svc->extend_info);
    if (intro_svc->intro_key)
      intro_desc->intro_key = crypto_pk_dup_key(intro_svc->intro_key);
    smartlist_add(d->intro_nodes, intro_desc);
628
629
630
631
632
633
634

    if (intro_svc->time_published == -1) {
      /* We are publishing this intro point in a descriptor for the
       * first time -- note the current time in the service's copy of
       * the intro point. */
      intro_svc->time_published = time(NULL);
    }
Nick Mathewson's avatar
Nick Mathewson committed
635
636
637
  }
}

638
639
/** Load and/or generate private keys for all hidden services, possibly
 * including keys for client authorization.  Return 0 on success, -1 on
640
 * failure. */
641
int
642
rend_service_load_all_keys(void)
Nick Mathewson's avatar
Nick Mathewson committed
643
{
644
  SMARTLIST_FOREACH_BEGIN(rend_service_list, rend_service_t *, s) {
Nick Mathewson's avatar
Nick Mathewson committed
645
646
    if (s->private_key)
      continue;
647
648
    log_info(LD_REND, "Loading hidden-service keys from \"%s\"",
             s->directory);
Nick Mathewson's avatar
Nick Mathewson committed
649

650
    if (rend_service_load_keys(s) < 0)
Nick Mathewson's avatar
Nick Mathewson committed
651
      return -1;
652
  } SMARTLIST_FOREACH_END(s);
Nick Mathewson's avatar
Nick Mathewson committed
653

654
655
656
657
658
659
660
661
  return 0;
}

/** Load and/or generate private keys for the hidden service <b>s</b>,
 * possibly including keys for client authorization.  Return 0 on success, -1
 * on failure. */
static int
rend_service_load_keys(rend_service_t *s)
Nick Mathewson's avatar
Nick Mathewson committed
662
663
{
  char fname[512];
664
  char buf[128];
Nick Mathewson's avatar
Nick Mathewson committed
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
690
691
692
693
694
695
696
697
  /* Check/create directory */
  if (check_private_dir(s->directory, CPD_CREATE, get_options()->User) < 0)
    return -1;

  /* Load key */
  if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
      strlcat(fname,PATH_SEPARATOR"private_key",sizeof(fname))
         >= sizeof(fname)) {
    log_warn(LD_CONFIG, "Directory name too long to store key file: \"%s\".",
             s->directory);
    return -1;
  }
  s->private_key = init_key_from_file(fname, 1, LOG_ERR);
  if (!s->private_key)
    return -1;

  /* Create service file */
  if (rend_get_service_id(s->private_key, s->service_id)<0) {
    log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
    return -1;
  }
  if (crypto_pk_get_digest(s->private_key, s->pk_digest)<0) {
    log_warn(LD_BUG, "Couldn't compute hash of public key.");
    return -1;
  }
  if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
      strlcat(fname,PATH_SEPARATOR"hostname",sizeof(fname))
      >= sizeof(fname)) {
    log_warn(LD_CONFIG, "Directory name too long to store hostname file:"
             " \"%s\".", s->directory);
    return -1;
  }
698

699
700
701
  tor_snprintf(buf, sizeof(buf),"%s.onion\n", s->service_id);
  if (write_str_to_file(fname,buf,0)<0) {
    log_warn(LD_CONFIG, "Could not write onion address to hostname file.");
702
    memwipe(buf, 0, sizeof(buf));
703
704
    return -1;
  }
705
  memwipe(buf, 0, sizeof(buf));
Nick Mathewson's avatar
Nick Mathewson committed
706

707
708
  /* If client authorization is configured, load or generate keys. */
  if (s->auth_type != REND_NO_AUTH) {
709
    if (rend_service_load_auth_keys(s, fname) < 0)
Nick Mathewson's avatar
Nick Mathewson committed
710
      return -1;
711
712
713
714
715
716
  }

  return 0;
}

/** Load and/or generate client authorization keys for the hidden service
717
718
 * <b>s</b>, which stores its hostname in <b>hfname</b>.  Return 0 on success,
 * -1 on failure. */
719
static int
720
rend_service_load_auth_keys(rend_service_t *s, const char *hfname)
721
722
{
  int r = 0;
723
  char cfname[512];
724
725
726
727
728
729
730
731
  char *client_keys_str = NULL;
  strmap_t *parsed_clients = strmap_new();
  FILE *cfile, *hfile;
  open_file_t *open_cfile = NULL, *open_hfile = NULL;
  char extended_desc_cookie[REND_DESC_COOKIE_LEN+1];
  char desc_cook_out[3*REND_DESC_COOKIE_LEN_BASE64+1];
  char service_id[16+1];
  char buf[1500];
732

733
734
735
736
737
738
739
740
741
742
743
744
  /* Load client keys and descriptor cookies, if available. */
  if (tor_snprintf(cfname, sizeof(cfname), "%s"PATH_SEPARATOR"client_keys",
                   s->directory)<0) {
    log_warn(LD_CONFIG, "Directory name too long to store client keys "
             "file: \"%s\".", s->directory);
    goto err;
  }
  client_keys_str = read_file_to_str(cfname, RFTS_IGNORE_MISSING, NULL);
  if (client_keys_str) {
    if (rend_parse_client_keys(parsed_clients, client_keys_str) < 0) {
      log_warn(LD_CONFIG, "Previously stored client_keys file could not "
               "be parsed.");
745
      goto err;
746
747
748
    } else {
      log_info(LD_CONFIG, "Parsed %d previously stored client entries.",
               strmap_size(parsed_clients));
Nick Mathewson's avatar
Nick Mathewson committed
749
    }
750
  }
Nick Mathewson's avatar
Nick Mathewson committed
751

752
753
754
755
756
757
758
759
  /* Prepare client_keys and hostname files. */
  if (!(cfile = start_writing_to_stdio_file(cfname,
                                            OPEN_FLAGS_REPLACE | O_TEXT,
                                            0600, &open_cfile))) {
    log_warn(LD_CONFIG, "Could not open client_keys file %s",
             escaped(cfname));
    goto err;
  }
760
761

  if (!(hfile = start_writing_to_stdio_file(hfname,
762
763
                                            OPEN_FLAGS_REPLACE | O_TEXT,
                                            0600, &open_hfile))) {
764
    log_warn(LD_CONFIG, "Could not open hostname file %s", escaped(hfname));
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
    goto err;
  }

  /* Either use loaded keys for configured clients or generate new
   * ones if a client is new. */
  SMARTLIST_FOREACH_BEGIN(s->clients, rend_authorized_client_t *, client) {
    rend_authorized_client_t *parsed =
      strmap_get(parsed_clients, client->client_name);
    int written;
    size_t len;
    /* Copy descriptor cookie from parsed entry or create new one. */
    if (parsed) {
      memcpy(client->descriptor_cookie, parsed->descriptor_cookie,
             REND_DESC_COOKIE_LEN);
    } else {
      crypto_rand(client->descriptor_cookie, REND_DESC_COOKIE_LEN);
Nick Mathewson's avatar
Nick Mathewson committed
781
    }
782
783
784
785
    if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
                      client->descriptor_cookie,
                      REND_DESC_COOKIE_LEN) < 0) {
      log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
786
      goto err;
787
    }
788
789
790
791
792
793
794
795
796
    /* Copy client key from parsed entry or create new one if required. */
    if (parsed && parsed->client_key) {
      client->client_key = crypto_pk_dup_key(parsed->client_key);
    } else if (s->auth_type == REND_STEALTH_AUTH) {
      /* Create private key for client. */
      crypto_pk_t *prkey = NULL;
      if (!(prkey = crypto_pk_new())) {
        log_warn(LD_BUG,"Error constructing client key");
        goto err;
797
      }
798
799
800
801
      if (crypto_pk_generate_key(prkey)) {
        log_warn(LD_BUG,"Error generating client key");
        crypto_pk_free(prkey);
        goto err;
802
      }
803
804
805
806
      if (crypto_pk_check_key(prkey) <= 0) {
        log_warn(LD_BUG,"Generated client key seems invalid");
        crypto_pk_free(prkey);
        goto err;
807
      }
808
      client->client_key = prkey;
Nick Mathewson's avatar
Nick Mathewson committed
809
    }
810
811
812
813
814
815
816
817
    /* Add entry to client_keys file. */
    desc_cook_out[strlen(desc_cook_out)-1] = '\0'; /* Remove newline. */
    written = tor_snprintf(buf, sizeof(buf),
                           "client-name %s\ndescriptor-cookie %s\n",
                           client->client_name, desc_cook_out);
    if (written < 0) {
      log_warn(LD_BUG, "Could not write client entry.");
      goto err;
818
    }
819
820
821
822
823
824
    if (client->client_key) {
      char *client_key_out = NULL;
      if (crypto_pk_write_private_key_to_string(client->client_key,
                                                &client_key_out, &len) != 0) {
        log_warn(LD_BUG, "Internal error: "
                 "crypto_pk_write_private_key_to_string() failed.");
825
826
        goto err;
      }
827
828
829
830
831
832
      if (rend_get_service_id(client->client_key, service_id)<0) {
        log_warn(LD_BUG, "Internal error: couldn't encode service ID.");
        /*
         * len is string length, not buffer length, but last byte is NUL
         * anyway.
         */
833
        memwipe(client_key_out, 0, len);
834
        tor_free(client_key_out);
835
836
        goto err;
      }
837
838
      written = tor_snprintf(buf + written, sizeof(buf) - written,
                             "client-key\n%s", client_key_out);
839
      memwipe(client_key_out, 0, len);
840
841
842
      tor_free(client_key_out);
      if (written < 0) {
        log_warn(LD_BUG, "Could not write client entry.");
843
844
        goto err;
      }
845
    }
846

847
848
849
850
851
    if (fputs(buf, cfile) < 0) {
      log_warn(LD_FS, "Could not append client entry to file: %s",
               strerror(errno));
      goto err;
    }
852

853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
    /* Add line to hostname file. */
    if (s->auth_type == REND_BASIC_AUTH) {
      /* Remove == signs (newline has been removed above). */
      desc_cook_out[strlen(desc_cook_out)-2] = '\0';
      tor_snprintf(buf, sizeof(buf),"%s.onion %s # client: %s\n",
                   s->service_id, desc_cook_out, client->client_name);
    } else {
      memcpy(extended_desc_cookie, client->descriptor_cookie,
             REND_DESC_COOKIE_LEN);
      extended_desc_cookie[REND_DESC_COOKIE_LEN] =
        ((int)s->auth_type - 1) << 4;
      if (base64_encode(desc_cook_out, 3*REND_DESC_COOKIE_LEN_BASE64+1,
                        extended_desc_cookie,
                        REND_DESC_COOKIE_LEN+1) < 0) {
        log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
868
        goto err;
869
      }
870
871
872
873
      desc_cook_out[strlen(desc_cook_out)-3] = '\0'; /* Remove A= and
                                                        newline. */
      tor_snprintf(buf, sizeof(buf),"%s.onion %s # client: %s\n",
                   service_id, desc_cook_out, client->client_name);
874
875
    }

876
877
878
879
    if (fputs(buf, hfile)<0) {
      log_warn(LD_FS, "Could not append host entry to file: %s",
               strerror(errno));
      goto err;
880
    }
881
882
883
884
  } SMARTLIST_FOREACH_END(client);

  finish_writing_to_file(open_cfile);
  finish_writing_to_file(open_hfile);
885
886
887
888

  goto done;
 err:
  r = -1;
889
890
891
892
  if (open_cfile)
    abort_writing_to_file(open_cfile);
  if (open_hfile)
    abort_writing_to_file(open_hfile);
893
 done:
894
895
896
897
  if (client_keys_str) {
    tor_strclear(client_keys_str);
    tor_free(client_keys_str);
  }
898
  strmap_free(parsed_clients, rend_authorized_client_strmap_item_free);
899

900
  memwipe(cfname, 0, sizeof(cfname));
901
902

  /* Clear stack buffers that held key-derived material. */
903
904
905
906
  memwipe(buf, 0, sizeof(buf));
  memwipe(desc_cook_out, 0, sizeof(desc_cook_out));
  memwipe(service_id, 0, sizeof(service_id));
  memwipe(extended_desc_cookie, 0, sizeof(extended_desc_cookie));
907

908
  return r;
Nick Mathewson's avatar
Nick Mathewson committed
909
}
910

911
912
/** Return the service whose public key has a digest of <b>digest</b>, or
 * NULL if no such service exists.
913
 */
914
static rend_service_t *
915
rend_service_get_by_pk_digest(const char* digest)
916
{
Nick Mathewson's avatar
Nick Mathewson committed
917
  SMARTLIST_FOREACH(rend_service_list, rend_service_t*, s,
918
                    if (tor_memeq(s->pk_digest,digest,DIGEST_LEN))
919
                        return s);
920
921
922
  return NULL;
}

923
924
925
926
/** Return 1 if any virtual port in <b>service</b> wants a circuit
 * to have good uptime. Else return 0.
 */
static int
927
928
rend_service_requires_uptime(rend_service_t *service)
{
929
930
931
932
933
  int i;
  rend_service_port_config_t *p;

  for (i=0; i < smartlist_len(service->ports); ++i) {
    p = smartlist_get(service->ports, i);
Nick Mathewson's avatar
Nick Mathewson committed
934
    if (smartlist_contains_int_as_string(get_options()->LongLivedPorts,
935
                                  p->virtual_port))
936
937
938
939
940
      return 1;
  }
  return 0;
}

941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
/** Check client authorization of a given <b>descriptor_cookie</b> for
 * <b>service</b>. Return 1 for success and 0 for failure. */
static int
rend_check_authorization(rend_service_t *service,
                         const char *descriptor_cookie)
{
  rend_authorized_client_t *auth_client = NULL;
  tor_assert(service);
  tor_assert(descriptor_cookie);
  if (!service->clients) {
    log_warn(LD_BUG, "Can't check authorization for a service that has no "
                     "authorized clients configured.");
    return 0;
  }

  /* Look up client authorization by descriptor cookie. */
  SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *, client, {
958
    if (tor_memeq(client->descriptor_cookie, descriptor_cookie,
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
                REND_DESC_COOKIE_LEN)) {
      auth_client = client;
      break;
    }
  });
  if (!auth_client) {
    char descriptor_cookie_base64[3*REND_DESC_COOKIE_LEN_BASE64];
    base64_encode(descriptor_cookie_base64, sizeof(descriptor_cookie_base64),
                  descriptor_cookie, REND_DESC_COOKIE_LEN);
    log_info(LD_REND, "No authorization found for descriptor cookie '%s'! "
                      "Dropping cell!",
             descriptor_cookie_base64);
    return 0;
  }

  /* Allow the request. */
  log_debug(LD_REND, "Client %s authorized for service %s.",
            auth_client->client_name, service->service_id);
  return 1;
}

980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/** Called when <b>intro</b> will soon be removed from
 * <b>service</b>'s list of intro points. */
static void
rend_service_note_removing_intro_point(rend_service_t *service,
                                       rend_intro_point_t *intro)
{
  time_t now = time(NULL);

  /* Don't process an intro point twice here. */
  if (intro->rend_service_note_removing_intro_point_called) {
    return;
  } else {
    intro->rend_service_note_removing_intro_point_called = 1;
  }

  /* Update service->n_intro_points_wanted based on how long intro
   * lasted and how many introductions it handled. */
  if (intro->time_published == -1) {
    /* This intro point was never used.  Don't change
     * n_intro_points_wanted. */
  } else {
For faster browsing, not all history is shown. View entire blame