• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

proftpd / proftpd / 14526507026

17 Apr 2025 11:25PM UTC coverage: 93.03% (+0.4%) from 92.667%
14526507026

push

github

51358 of 55206 relevant lines covered (93.03%)

234.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.03
/src/stash.c
1
/*
2
 * ProFTPD - FTP server daemon
3
 * Copyright (c) 2010-2025 The ProFTPD Project team
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18
 *
19
 * As a special exemption, The ProFTPD Project and other respective copyright
20
 * holders give permission to link this program with OpenSSL, and distribute
21
 * the resulting executable, without including the source code for OpenSSL in
22
 * the source distribution.
23
 */
24

25
/* Symbol table hashes */
26

27
#include "conf.h"
28

29
#ifndef PR_SYM_POOL_SIZE
30
# define PR_SYM_POOL_SIZE                128
31
#endif /* PR_SYM_POOL_SIZE */
32

33
/* This local structure vastly speeds up symbol lookups. */
34
struct stash {
35
  struct stash *next, *prev;
36
  pool *sym_pool;
37
  unsigned int sym_hash;
38
  const char *sym_name;
39
  size_t sym_namelen;
40
  pr_stash_type_t sym_type;
41
  module *sym_module;
42

43
  union {
44
    conftable *sym_conf;
45
    cmdtable *sym_cmd;
46
    authtable *sym_auth;
47
    cmdtable *sym_hook;
48
    void *sym_generic;
49
  } ptr;
50
};
51

52
static pool *symbol_pool = NULL;
53

54
/* Symbol hashes for each type */
55
static xaset_t *conf_symbol_table[PR_TUNABLE_HASH_TABLE_SIZE];
56
static struct stash *conf_curr_sym = NULL;
57

58
static xaset_t *cmd_symbol_table[PR_TUNABLE_HASH_TABLE_SIZE];
59
static struct stash *cmd_curr_sym = NULL;
60

61
static xaset_t *auth_symbol_table[PR_TUNABLE_HASH_TABLE_SIZE];
62
static struct stash *auth_curr_sym = NULL;
63

64
static xaset_t *hook_symbol_table[PR_TUNABLE_HASH_TABLE_SIZE];
65
static struct stash *hook_curr_sym = NULL;
66

67
/* Symbol stash lookup code and management */
68

69
static struct stash *sym_alloc(void) {
78✔
70
  pool *sub_pool;
78✔
71
  struct stash *sym;
78✔
72

73
  /* XXX Use a smaller pool size, since there are lots of sub-pools allocated
74
   * for Stash symbols.  The default pool size (PR_TUNABLE_POOL_SIZE, 512
75
   * bytes by default) is a bit large for symbols.
76
   */
77
  sub_pool = pr_pool_create_sz(symbol_pool, PR_SYM_POOL_SIZE);
78✔
78
  pr_pool_tag(sub_pool, "symbol");
78✔
79

80
  sym = pcalloc(sub_pool, sizeof(struct stash));
78✔
81
  sym->sym_pool = sub_pool;
78✔
82

83
  return sym;
78✔
84
}
85

86
static int sym_cmp(struct stash *s1, struct stash *s2) {
11✔
87
  int res;
11✔
88
  size_t checked_len = 0, namelen;
11✔
89

90
  if (s1->sym_hash != s2->sym_hash) {
11✔
91
    return s1->sym_hash < s2->sym_hash ? -1 : 1;
×
92
  }
93

94
  if (s1->sym_namelen != s2->sym_namelen) {
11✔
95
    return s1->sym_namelen < s2->sym_namelen ? -1 : 1;
×
96
  }
97

98
  namelen = s1->sym_namelen;
11✔
99

100
  /* Try to avoid strncmp(3) if we can. */
101
  if (namelen >= 2) {
11✔
102
    char c1, c2;
11✔
103

104
    c1 = s1->sym_name[0];
11✔
105
    c2 = s2->sym_name[0];
11✔
106

107
    if (c1 != c2) {
11✔
108
      return c1 < c2 ? -1 : 1;
×
109
    }
110

111
    checked_len++;
11✔
112

113
    if (namelen >= 3) {
11✔
114
      c1 = s1->sym_name[1];
11✔
115
      c2 = s2->sym_name[1];
11✔
116

117
      if (c1 != c2) {
11✔
118
        return c1 < c2 ? -1 : 1;
×
119
      }
120

121
      checked_len++;
122
    }
123
  }
124

125
  res = strncmp(s1->sym_name + checked_len, s2->sym_name + checked_len,
11✔
126
    namelen - checked_len);
127

128
  /* Higher priority modules must go BEFORE lower priority in the
129
   * hash tables.
130
   */
131

132
  if (res == 0) {
11✔
133
    if (s1->sym_module != NULL &&
11✔
134
        s2->sym_module != NULL) {
×
135

136
      if (s1->sym_module->priority > s2->sym_module->priority) {
×
137
        return -1;
138
      }
139

140
      if (s1->sym_module->priority < s2->sym_module->priority) {
×
141
        return 1;
142
      }
143

144
      return res;
×
145
    }
146

147
    if (s1->sym_module != NULL &&
11✔
148
        s2->sym_module == NULL) {
×
149
      return -1;
150
    }
151

152
    if (s1->sym_module == NULL &&
11✔
153
        s2->sym_module != NULL) {
11✔
154
      return 1;
155
    }
156

157
    /* Both sym_module fields are null. */
158
    return 0;
11✔
159
  }
160

161
  return res;
162
}
163

164
static unsigned int symtab_hash(const char *name, size_t namelen) {
288✔
165
  register unsigned int i;
288✔
166
  unsigned int h = 0;
288✔
167

168
  if (name == NULL) {
288✔
169
    return 0;
170
  }
171

172
  for (i = 0; i < namelen; i++) {
2,737✔
173
    const char *cp;
2,408✔
174

175
    cp = (const char *) &(name[i]);
2,408✔
176
    h = (h * 33) + *cp;
2,408✔
177
  }
178

179
  return h;
180
}
181

182
static unsigned int sym_type_hash(pr_stash_type_t sym_type, const char *name,
373✔
183
    size_t namelen) {
184
  unsigned int hash;
373✔
185

186
  if (namelen == 0) {
373✔
187
    return 0;
188
  }
189

190
  /* XXX Ugly hack to support mixed cases of directives in config files. */
191
  if (sym_type != PR_SYM_CONF) {
329✔
192
    hash = symtab_hash(name, namelen);
288✔
193

194
  } else {
195
    register unsigned int i;
41✔
196
    char *buf;
41✔
197

198
    buf = malloc(namelen+1);
41✔
199
    if (buf == NULL) {
41✔
200
      pr_log_pri(PR_LOG_ALERT, "Out of memory!");
×
201
      exit(1);
×
202
    }
203

204
    buf[namelen] = '\0';
41✔
205
    for (i = 0; i < namelen; i++) {
382✔
206
      /* Note that the tolower(3) function is locale-sensitive.  This means
207
       * that setlocale(3) MUST be called before we hash any of the
208
       * configuration directive strings, as when modules are loading, BEFORE
209
       * we process any configuration directives during parsing.  That way,
210
       * we handle the text in a consistent manner for that locale (Bug#4466).
211
       */
212
      buf[i] = tolower((int) name[i]);
341✔
213
    }
214

215
    hash = symtab_hash(buf, namelen);
41✔
216
    free(buf);
41✔
217
  }
218

219
  return hash;
220
}
221

222
int pr_stash_add_symbol(pr_stash_type_t sym_type, void *data) {
80✔
223
  struct stash *sym = NULL;
80✔
224
  unsigned int hash;
80✔
225
  int idx = 0;
80✔
226
  xaset_t **symbol_table;
80✔
227
  size_t sym_namelen = 0;
80✔
228

229
  if (data == NULL) {
80✔
230
    errno = EINVAL;
1✔
231
    return -1;
1✔
232
  }
233

234
  switch (sym_type) {
79✔
235
    case PR_SYM_CONF:
15✔
236
      sym = sym_alloc();
15✔
237
      sym->sym_type = PR_SYM_CONF;
15✔
238
      sym->sym_name = ((conftable *) data)->directive;
15✔
239
      sym->sym_module = ((conftable *) data)->m;
15✔
240
      sym->ptr.sym_conf = data;
15✔
241
      symbol_table = conf_symbol_table;
15✔
242
      break;
15✔
243

244
    case PR_SYM_CMD:
16✔
245
      sym = sym_alloc();
16✔
246
      sym->sym_type = PR_SYM_CMD;
16✔
247
      sym->sym_name = ((cmdtable *) data)->command;
16✔
248
      sym->sym_module = ((cmdtable *) data)->m;
16✔
249
      sym->ptr.sym_cmd = data;
16✔
250
      symbol_table = cmd_symbol_table;
16✔
251
      break;
16✔
252

253
    case PR_SYM_AUTH:
37✔
254
      sym = sym_alloc();
37✔
255
      sym->sym_type = PR_SYM_AUTH;
37✔
256
      sym->sym_name = ((authtable *) data)->name;
37✔
257
      sym->sym_module = ((authtable *) data)->m;
37✔
258
      sym->ptr.sym_auth = data;
37✔
259
      symbol_table = auth_symbol_table;
37✔
260
      break;
37✔
261

262
    case PR_SYM_HOOK:
10✔
263
      sym = sym_alloc();
10✔
264
      sym->sym_type = PR_SYM_HOOK;
10✔
265
      sym->sym_name = ((cmdtable *) data)->command;
10✔
266
      sym->sym_module = ((cmdtable *) data)->m;
10✔
267
      sym->ptr.sym_hook = data;
10✔
268
      symbol_table = hook_symbol_table;
10✔
269
      break;
10✔
270

271
    default:
1✔
272
      errno = EINVAL;
1✔
273
      return -1;
1✔
274
  }
275

276
  /* XXX Should we check for null sym->sym_module as well? */
277
  if (sym->sym_name == NULL) {
78✔
278
    destroy_pool(sym->sym_pool);
4✔
279
    errno = EPERM;
4✔
280
    return -1;
4✔
281
  }
282

283
  sym_namelen = strlen(sym->sym_name);
74✔
284
  if (sym_namelen == 0) {
74✔
285
    destroy_pool(sym->sym_pool);
1✔
286
    errno = EPERM;
1✔
287
    return -1;
1✔
288
  }
289

290
  /* Don't forget to include one for the terminating NUL. */
291
  sym->sym_namelen = sym_namelen + 1;
73✔
292

293
  hash = sym_type_hash(sym_type, sym->sym_name, sym->sym_namelen);
73✔
294
  idx = hash % PR_TUNABLE_HASH_TABLE_SIZE;
73✔
295
  sym->sym_hash = hash;
73✔
296

297
  if (!symbol_table[idx]) {
73✔
298
    symbol_table[idx] = xaset_create(symbol_pool, (XASET_COMPARE) sym_cmp);
59✔
299
  }
300

301
  xaset_insert_sort(symbol_table[idx], (xasetmember_t *) sym, TRUE);
73✔
302
  return 0;
73✔
303
}
304

305
static struct stash *stash_lookup(pr_stash_type_t sym_type,
289✔
306
    const char *name, size_t namelen, int idx, unsigned int hash) {
307
  struct stash *sym = NULL;
289✔
308
  xaset_t **symbol_table = NULL;
289✔
309

310
  switch (sym_type) {
289✔
311
    case PR_SYM_CONF:
312
      symbol_table = conf_symbol_table;
313
      break;
314

315
    case PR_SYM_CMD:
27✔
316
      symbol_table = cmd_symbol_table;
27✔
317
      break;
27✔
318

319
    case PR_SYM_AUTH:
183✔
320
      symbol_table = auth_symbol_table;
183✔
321
      break;
183✔
322

323
    case PR_SYM_HOOK:
14✔
324
      symbol_table = hook_symbol_table;
14✔
325
      break;
14✔
326

327
    default:
×
328
      errno = EINVAL;
×
329
      return NULL;
×
330
  }
331

332
  if (symbol_table[idx]) {
289✔
333
    for (sym = (struct stash *) symbol_table[idx]->xas_list; sym;
178✔
334
        sym = sym->next) {
×
335
      int res;
140✔
336

337
      if (name == NULL) {
140✔
338
        break;
339
      }
340

341
      if (sym->sym_hash != hash) {
138✔
342
        continue;
×
343
      }
344

345
      if (sym->sym_namelen != namelen) {
138✔
346
        continue;
×
347
      }
348

349
      /* Try to avoid strncmp(3) if we can. */
350
      if (namelen >= 1) {
138✔
351
        char c1, c2;
138✔
352

353
        c1 = tolower((int) sym->sym_name[0]);
138✔
354
        c2 = tolower((int) name[0]);
138✔
355

356
        if (c1 != c2) {
138✔
357
          continue;
×
358
        }
359

360
        /* Special case (unlikely, but possible) */
361
        if (namelen == 1 &&
138✔
362
            c1 == '\0') {
138✔
363
          break;
364
        }
365
      }
366

367
      if (namelen >= 2) {
138✔
368
        char c1, c2;
138✔
369

370
        c1 = tolower((int) sym->sym_name[1]);
138✔
371
        c2 = tolower((int) name[1]);
138✔
372

373
        if (c1 != c2) {
138✔
374
          continue;
×
375
        }
376

377
        /* Special case */
378
        if (namelen == 2 &&
138✔
379
            c1 == '\0') {
138✔
380
          break;
381
        }
382
      }
383

384
      res = strncasecmp(sym->sym_name + 2, name + 2, namelen - 2);
138✔
385
      if (res == 0) {
138✔
386
        break;
387
      }
388
    }
389
  }
390

391
  return sym;
392
}
393

394
static struct stash *stash_lookup_next(pr_stash_type_t sym_type,
39✔
395
    const char *name, size_t namelen, int idx, unsigned int hash, void *prev) {
396
  struct stash *sym = NULL;
39✔
397
  int last_hit = 0;
39✔
398
  xaset_t **symbol_table = NULL;
39✔
399

400
  switch (sym_type) {
39✔
401
    case PR_SYM_CONF:
402
      symbol_table = conf_symbol_table;
403
      break;
404

405
    case PR_SYM_CMD:
8✔
406
      symbol_table = cmd_symbol_table;
8✔
407
      break;
8✔
408

409
    case PR_SYM_AUTH:
17✔
410
      symbol_table = auth_symbol_table;
17✔
411
      break;
17✔
412

413
    case PR_SYM_HOOK:
2✔
414
      symbol_table = hook_symbol_table;
2✔
415
      break;
2✔
416

417
    default:
×
418
      errno = EINVAL;
×
419
      return NULL;
×
420
  }
421

422
  if (symbol_table[idx]) {
39✔
423
    for (sym = (struct stash *) symbol_table[idx]->xas_list; sym;
78✔
424
        sym = sym->next) {
39✔
425
      if (last_hit) {
42✔
426
        int res;
3✔
427

428
        if (name == NULL) {
3✔
429
          break;
430
        }
431

432
        if (sym->sym_hash != hash) {
3✔
433
          continue;
×
434
        }
435

436
        if (sym->sym_namelen != namelen) {
3✔
437
          continue;
×
438
        }
439

440
        /* Try to avoid strncmp(3) if we can. */
441
        if (namelen >= 1) {
3✔
442
          char c1, c2;
3✔
443

444
          c1 = tolower((int) sym->sym_name[0]);
3✔
445
          c2 = tolower((int) name[0]);
3✔
446

447
          if (c1 != c2) {
3✔
448
            continue;
×
449
          }
450

451
          /* Special case (unlikely, but possible) */
452
          if (namelen == 1 &&
3✔
453
              c1 == '\0') {
3✔
454
            break;
455
          }
456
        }
457

458
        if (namelen >= 2) {
3✔
459
          char c1, c2;
3✔
460

461
          c1 = tolower((int) sym->sym_name[1]);
3✔
462
          c2 = tolower((int) name[1]);
3✔
463

464
          if (c1 != c2) {
3✔
465
            continue;
×
466
          }
467

468
          /* Special case */
469
          if (namelen == 2 &&
3✔
470
              c1 == '\0') {
3✔
471
            break;
472
          }
473
        }
474

475
        res = strncasecmp(sym->sym_name + 2, name + 2, namelen - 2);
3✔
476
        if (res == 0) {
3✔
477
          break;
478
        }
479
      }
480

481
      if (sym->ptr.sym_generic == prev) {
39✔
482
        last_hit++;
39✔
483
      }
484
    }
485
  }
486

487
  return sym;
488
}
489

490
void *pr_stash_get_symbol2(pr_stash_type_t sym_type, const char *name,
333✔
491
    void *prev, int *idx_cache, unsigned int *hash_cache) {
492
  int idx;
333✔
493
  unsigned int hash = 0;
333✔
494
  struct stash *sym = NULL;
333✔
495
  size_t namelen = 0;
333✔
496

497
  if (sym_type != PR_SYM_CONF &&
333✔
498
      sym_type != PR_SYM_CMD &&
499
      sym_type != PR_SYM_AUTH &&
333✔
500
      sym_type != PR_SYM_HOOK) {
501
    errno = EINVAL;
4✔
502
    return NULL;
4✔
503
  }
504

505
  if (name != NULL) {
329✔
506
    /* Don't forget to include one for the terminating NUL. */
507
    namelen = strlen(name) + 1;
285✔
508
  }
509

510
  if (idx_cache != NULL &&
329✔
511
      *idx_cache != -1) {
305✔
512
    idx = *idx_cache;
121✔
513

514
    if (hash_cache != NULL) {
121✔
515
      hash = *hash_cache;
121✔
516
      if (hash == 0) {
121✔
517
        hash = sym_type_hash(sym_type, name, namelen);
42✔
518
        *hash_cache = hash;
42✔
519
      }
520

521
    } else {
522
      hash = sym_type_hash(sym_type, name, namelen);
×
523
    }
524

525
  } else {
526
    hash = sym_type_hash(sym_type, name, namelen);
208✔
527
    idx = hash % PR_TUNABLE_HASH_TABLE_SIZE;
208✔
528

529
    if (idx_cache != NULL) {
208✔
530
      *idx_cache = idx;
184✔
531
    }
532

533
    if (hash_cache != NULL) {
208✔
534
      *hash_cache = hash;
184✔
535
    }
536
  }
537

538
  if (idx >= PR_TUNABLE_HASH_TABLE_SIZE) {
329✔
539
    if (idx_cache != NULL) {
1✔
540
      *idx_cache = -1;
1✔
541
    }
542

543
    if (hash_cache != NULL) {
1✔
544
      *hash_cache = 0;
1✔
545
    }
546

547
    errno = EINVAL;
1✔
548
    return NULL;
1✔
549
  }
550

551
  if (prev != NULL) {
328✔
552
    sym = stash_lookup_next(sym_type, name, namelen, idx, hash, prev);
39✔
553

554
  } else {
555
    sym = stash_lookup(sym_type, name, namelen, idx, hash);
289✔
556
  }
557

558
  switch (sym_type) {
328✔
559
    case PR_SYM_CONF:
77✔
560
      conf_curr_sym = sym;
77✔
561
      if (sym != NULL) {
77✔
562
        return sym->ptr.sym_conf;
17✔
563
      }
564

565
      errno = ENOENT;
60✔
566
      return NULL;
60✔
567

568
    case PR_SYM_CMD:
35✔
569
      cmd_curr_sym = sym;
35✔
570
      if (sym != NULL) {
35✔
571
        return sym->ptr.sym_cmd;
19✔
572
      }
573

574
      errno = ENOENT;
16✔
575
      return NULL;
16✔
576

577
    case PR_SYM_AUTH:
200✔
578
      auth_curr_sym = sym;
200✔
579
      if (sym != NULL) {
200✔
580
        return sym->ptr.sym_auth;
100✔
581
      }
582

583
      errno = ENOENT;
100✔
584
      return NULL;
100✔
585

586
    case PR_SYM_HOOK:
16✔
587
      hook_curr_sym = sym;
16✔
588
      if (sym != NULL) {
16✔
589
        return sym->ptr.sym_hook;
7✔
590
      }
591

592
      errno = ENOENT;
9✔
593
      return NULL;
9✔
594

595
    default:
596
      /* The expected types are checked at the start of this function. */
597
      break;
598
  }
599

600
  errno = EINVAL;
14✔
601
  return NULL;
602
}
14✔
603

604
void *pr_stash_get_symbol(pr_stash_type_t sym_type, const char *name,
605
    void *prev, int *idx_cache) {
7✔
606
  return pr_stash_get_symbol2(sym_type, name, prev, idx_cache, NULL);
7✔
607
}
7✔
608

7✔
609
int pr_stash_remove_conf(const char *directive_name, module *m) {
7✔
610
  int count = 0, prev_idx, symtab_idx = 0;
611
  size_t directive_namelen = 0;
7✔
612
  unsigned int hash;
1✔
613
  conftable *tab = NULL;
1✔
614

615
  if (directive_name == NULL) {
616
    errno = EINVAL;
617
    return -1;
6✔
618
  }
619

6✔
620
  /* Don't forget to include one for the terminating NUL. */
6✔
621
  directive_namelen = strlen(directive_name) + 1;
6✔
622

623
  hash = sym_type_hash(PR_SYM_CONF, directive_name, directive_namelen);
6✔
624
  symtab_idx = hash % PR_TUNABLE_HASH_TABLE_SIZE;
625
  prev_idx = -1;
11✔
626

5✔
627
  tab = pr_stash_get_symbol2(PR_SYM_CONF, directive_name, NULL, &prev_idx,
628
    &hash);
629
  while (tab) {
630
    pr_signals_handle();
631

632
    /* Note: this works because of a hack: the symbol lookup functions set a
633
     * static pointer, conf_curr_sym, to point to the struct stash just looked
634
     * up.  conf_curr_sym will not be NULL if pr_stash_get_symbol2() returns
5✔
635
     * non-NULL.
×
636
     */
5✔
637

638
    if (m == NULL ||
5✔
639
        conf_curr_sym->sym_module == m) {
5✔
640
      xaset_remove(conf_symbol_table[symtab_idx],
5✔
641
        (xasetmember_t *) conf_curr_sym);
5✔
642
      destroy_pool(conf_curr_sym->sym_pool);
643
      conf_curr_sym = NULL;
644
      tab = NULL;
5✔
645
      count++;
646
    }
647

648
    tab = pr_stash_get_symbol2(PR_SYM_CONF, directive_name, tab, &prev_idx,
649
      &hash);
650
  }
651

652
  return count;
653
}
654

655
/* Sentinel values:
656
 *
657
 *  cmd_type = 0
12✔
658
 *  cmd_group = NULL
659
 *  cmd_class = -1
12✔
660
 */
12✔
661
int pr_stash_remove_cmd(const char *cmd_name, module *m,
12✔
662
    unsigned char cmd_type, const char *cmd_group, int cmd_class) {
12✔
663
  int count = 0, prev_idx, symtab_idx = 0;
664
  size_t cmd_namelen = 0;
12✔
665
  unsigned int hash;
1✔
666
  cmdtable *tab = NULL;
1✔
667

668
  if (cmd_name == NULL) {
669
    errno = EINVAL;
670
    return -1;
11✔
671
  }
672

11✔
673
  /* Don't forget to include one for the terminating NUL. */
11✔
674
  cmd_namelen = strlen(cmd_name) + 1;
11✔
675

676
  hash = sym_type_hash(PR_SYM_CMD, cmd_name, cmd_namelen);
11✔
677
  symtab_idx = hash % PR_TUNABLE_HASH_TABLE_SIZE;
28✔
678
  prev_idx = -1;
17✔
679

680
  tab = pr_stash_get_symbol2(PR_SYM_CMD, cmd_name, NULL, &prev_idx, &hash);
17✔
681
  while (tab) {
682
    cmdtable *cmd_sym;
683

684
    pr_signals_handle();
685

686
    /* Note: this works because of a hack: the symbol lookup functions set a
687
     * static pointer, cmd_curr_sym, to point to the struct stash just looked
688
     * up.  cmd_curr_sym will not be NULL if pr_stash_get_symbol2() returns
17✔
689
     * non-NULL.
17✔
690
     */
17✔
691

4✔
692
    cmd_sym = cmd_curr_sym->ptr.sym_cmd;
693
    if ((m == NULL || cmd_curr_sym->sym_module == m) &&
3✔
694
        (cmd_type == 0 || cmd_sym->cmd_type == cmd_type) &&
13✔
695
        (cmd_group == NULL ||
3✔
696
         (cmd_group != NULL &&
11✔
697
          cmd_sym->group != NULL &&
698
          strcmp(cmd_sym->group, cmd_group) == 0)) &&
11✔
699
        (cmd_class == -1 || cmd_sym->cmd_class == cmd_class)) {
11✔
700
      xaset_remove(cmd_symbol_table[symtab_idx],
11✔
701
        (xasetmember_t *) cmd_curr_sym);
11✔
702
      destroy_pool(cmd_curr_sym->sym_pool);
703
      cmd_curr_sym = NULL;
704
      tab = NULL;
17✔
705
      count++;
706
    }
707

708
    tab = pr_stash_get_symbol2(PR_SYM_CMD, cmd_name, tab, &prev_idx, &hash);
709
  }
710

29✔
711
  return count;
29✔
712
}
29✔
713

29✔
714
int pr_stash_remove_auth(const char *api_name, module *m) {
29✔
715
  int count = 0, prev_idx, symtab_idx = 0;
716
  size_t api_namelen = 0;
29✔
717
  unsigned int hash;
1✔
718
  authtable *tab = NULL;
1✔
719

720
  if (api_name == NULL) {
721
    errno = EINVAL;
722
    return -1;
28✔
723
  }
724

28✔
725
  /* Don't forget to include one for the terminating NUL. */
28✔
726
  api_namelen = strlen(api_name) + 1;
28✔
727

728
  hash = sym_type_hash(PR_SYM_AUTH, api_name, api_namelen);
28✔
729
  symtab_idx = hash % PR_TUNABLE_HASH_TABLE_SIZE;
56✔
730
  prev_idx = -1;
28✔
731

732
  tab = pr_stash_get_symbol2(PR_SYM_AUTH, api_name, NULL, &prev_idx, &hash);
733
  while (tab) {
734
    pr_signals_handle();
735

736
    /* Note: this works because of a hack: the symbol lookup functions set a
737
     * static pointer, auth_curr_sym, to point to the struct stash just looked
738
     * up.  auth_curr_sym will not be NULL if pr_stash_get_symbol2() returns
28✔
739
     * non-NULL.
23✔
740
     */
28✔
741

742
    if (m == NULL ||
28✔
743
        auth_curr_sym->sym_module == m) {
28✔
744
      xaset_remove(auth_symbol_table[symtab_idx],
28✔
745
        (xasetmember_t *) auth_curr_sym);
28✔
746
      destroy_pool(auth_curr_sym->sym_pool);
747
      auth_curr_sym = NULL;
748
      tab = NULL;
28✔
749
      count++;
750
    }
751

752
    tab = pr_stash_get_symbol2(PR_SYM_AUTH, api_name, tab, &prev_idx, &hash);
753
  }
754

6✔
755
  return count;
6✔
756
}
6✔
757

6✔
758
int pr_stash_remove_hook(const char *hook_name, module *m) {
6✔
759
  int count = 0, prev_idx, symtab_idx = 0;
760
  size_t hook_namelen = 0;
6✔
761
  unsigned int hash;
1✔
762
  cmdtable *tab = NULL;
1✔
763

764
  if (hook_name == NULL) {
765
    errno = EINVAL;
766
    return -1;
5✔
767
  }
768

5✔
769
  /* Don't forget to include one for the terminating NUL. */
5✔
770
  hook_namelen = strlen(hook_name) + 1;
5✔
771

772
  hash = sym_type_hash(PR_SYM_HOOK, hook_name, hook_namelen);
5✔
773
  symtab_idx = hash % PR_TUNABLE_HASH_TABLE_SIZE;
10✔
774
  prev_idx = -1;
5✔
775

776
  tab = pr_stash_get_symbol2(PR_SYM_HOOK, hook_name, NULL, &prev_idx, &hash);
777
  while (tab) {
778
    pr_signals_handle();
779

780
    /* Note: this works because of a hack: the symbol lookup functions set a
781
     * static pointer, hook_curr_sym, to point to the struct stash just looked
782
     * up.  hook_curr_sym will not be NULL if pr_stash_get_symbol2() returns
5✔
783
     * non-NULL.
×
784
     */
5✔
785

786
    if (m == NULL ||
5✔
787
        hook_curr_sym->sym_module == m) {
5✔
788
      xaset_remove(hook_symbol_table[symtab_idx],
5✔
789
        (xasetmember_t *) hook_curr_sym);
5✔
790
      destroy_pool(hook_curr_sym->sym_pool);
791
      hook_curr_sym = NULL;
792
      tab = NULL;
5✔
793
      count++;
794
    }
795

796
    tab = pr_stash_get_symbol2(PR_SYM_HOOK, hook_name, tab, &prev_idx, &hash);
797
  }
798

41✔
799
  return count;
800
}
41✔
801

802
int pr_stash_remove_symbol(pr_stash_type_t sym_type, const char *sym_name,
41✔
803
    module *sym_module) {
4✔
804
  int count = 0;
4✔
805

4✔
806
  switch (sym_type) {
807
    case PR_SYM_CONF:
6✔
808
      count = pr_stash_remove_conf(sym_name, sym_module);
6✔
809
      break;
6✔
810

811
    case PR_SYM_CMD:
26✔
812
      count = pr_stash_remove_cmd(sym_name, sym_module, 0, NULL, -1);
26✔
813
      break;
26✔
814

815
    case PR_SYM_AUTH:
3✔
816
      count = pr_stash_remove_auth(sym_name, sym_module);
3✔
817
      break;
3✔
818

819
    case PR_SYM_HOOK:
2✔
820
      count = pr_stash_remove_hook(sym_name, sym_module);
2✔
821
      break;
2✔
822

823
    default:
824
      errno = EINVAL;
825
      return -1;
826
  }
827

828
  return count;
×
829
}
×
830

×
831
#ifdef PR_USE_DEVEL
832
static void stash_dumpf(const char *fmt, ...) {
×
833
  char buf[PR_TUNABLE_BUFFER_SIZE] = {'\0'};
×
834
  va_list msg;
×
835

836
  va_start(msg, fmt);
×
837
  pr_vsnprintf(buf, sizeof(buf), fmt, msg);
838
  va_end(msg);
×
839

×
840
  buf[sizeof(buf)-1] = '\0';
841

842
  pr_log_debug(DEBUG5, "%s", buf);
843
}
12✔
844
#endif
845

12✔
846
#ifdef PR_USE_DEVEL
12✔
847
static unsigned int stash_dump_syms(xaset_t **symbol_table, const char *type,
848
    void (*dumpf)(const char *, ...)) {
492✔
849
  register unsigned int i;
480✔
850
  unsigned int count = 0;
480✔
851

480✔
852
  for (i = 0; i < PR_TUNABLE_HASH_TABLE_SIZE; i++) {
853
    unsigned int nrow_syms = 0;
480✔
854
    struct stash *sym;
855
    xaset_t *syms;
480✔
856

480✔
857
    pr_signals_handle();
472✔
858

859
    syms = symbol_table[i];
860
    if (syms == NULL) {
12✔
861
      continue;
4✔
862
    }
863

864
    for (sym = (struct stash *) syms->xas_list; sym; sym = sym->next) {
8✔
865
      nrow_syms++;
866
    }
12✔
867

4✔
868
    dumpf("%s stab index %u: %u symbols", type, i, nrow_syms);
869

4✔
870
    for (sym = (struct stash *) syms->xas_list; sym; sym = sym->next) {
1✔
871
      count++;
872

873
      if (sym->sym_module != NULL) {
874
        dumpf(" + %s symbol: %s (mod_%s.c)", type, sym->sym_name,
3✔
875
          sym->sym_module->name);
876

877
      } else {
878
        dumpf(" + %s symbol: %s (core)", type, sym->sym_name);
879
      }
12✔
880
    }
881
  }
882

883
  return count;
3✔
884
}
885
#endif /* PR_USE_DEVEL */
3✔
886

3✔
887
void pr_stash_dump(void (*dumpf)(const char *, ...)) {
888
#ifdef PR_USE_DEVEL
3✔
889
  unsigned int nsyms = 0, nconf_syms = 0, ncmd_syms = 0, nauth_syms = 0,
×
890
    nhook_syms = 0;
891

892
  if (dumpf == NULL) {
3✔
893
    dumpf = stash_dumpf;
3✔
894
  }
3✔
895

3✔
896
  nconf_syms = stash_dump_syms(conf_symbol_table, "CONF", dumpf);
3✔
897
  ncmd_syms = stash_dump_syms(cmd_symbol_table, "CMD", dumpf);
898
  nauth_syms = stash_dump_syms(auth_symbol_table, "AUTH", dumpf);
3✔
899
  nhook_syms = stash_dump_syms(hook_symbol_table, "HOOK", dumpf);
900
  nsyms = nconf_syms + ncmd_syms + nauth_syms + nhook_syms;
901

3✔
902
  dumpf("stab: %u total symbols: %u CONF, %u CMD, %u AUTH, %u HOOK", nsyms,
903
    nconf_syms, ncmd_syms, nauth_syms, nhook_syms);
73✔
904
#endif /* PR_USE_DEVEL */
73✔
905
}
×
906

907
int init_stash(void) {
908
  if (symbol_pool != NULL) {
73✔
909
    destroy_pool(symbol_pool);
73✔
910
  }
911

73✔
912
  symbol_pool = make_sub_pool(permanent_pool);
73✔
913
  pr_pool_tag(symbol_pool, "Stash Pool");
73✔
914

73✔
915
  memset(conf_symbol_table, '\0', sizeof(conf_symbol_table));
916
  memset(cmd_symbol_table, '\0', sizeof(cmd_symbol_table));
73✔
917
  memset(auth_symbol_table, '\0', sizeof(auth_symbol_table));
918
  memset(hook_symbol_table, '\0', sizeof(hook_symbol_table));
919

920
  return 0;
921
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc