Coverage Report

Created: 2025-08-29 06:26

/src/opensc/src/pkcs11/misc.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * misc.c: Miscellaneous PKCS#11 library helper functions
3
 *
4
 * Copyright (C) 2002  Timo Teräs <timo.teras@iki.fi>
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
21
#include "config.h"
22
23
#include <stdlib.h>
24
#include <string.h>
25
26
#include "common/constant-time.h"
27
#include "sc-pkcs11.h"
28
29
#define DUMP_TEMPLATE_MAX 32
30
31
struct sc_to_cryptoki_error_conversion  {
32
  const char *context;
33
  int sc_error;
34
  CK_RV ck_error;
35
};
36
37
static struct sc_to_cryptoki_error_conversion sc_to_cryptoki_error_map[]  = {
38
  { "C_GenerateKeyPair",  SC_ERROR_INVALID_PIN_LENGTH,  CKR_GENERAL_ERROR },
39
  { "C_Sign",   SC_ERROR_NOT_ALLOWED,   CKR_FUNCTION_FAILED},
40
  { "C_Decrypt",    SC_ERROR_NOT_ALLOWED,   CKR_FUNCTION_FAILED},
41
  {NULL, 0, 0}
42
};
43
44
45
void strcpy_bp(u8 * dst, const char *src, size_t dstsize)
46
106k
{
47
106k
  if (!dst || !dstsize)
48
0
    return;
49
50
106k
  memset((char *)dst, ' ', dstsize);
51
52
106k
  if (src) {
53
59.1k
    size_t src_len = strlen(src);
54
55
59.1k
    if (src_len > dstsize) {
56
      /* string will be truncated */
57
7
      memcpy((char *)dst, src, dstsize);
58
7
      if (dstsize > 3) {
59
        /* show truncation with '...' */
60
        /* FIXME avoid breaking an UTF-8 character on multiple bytes */
61
7
        memset((char *)dst + dstsize - 3, '.', 3);
62
7
      }
63
59.1k
    } else {
64
59.1k
      memcpy((char *)dst, src, src_len);
65
59.1k
    }
66
59.1k
  }
67
106k
}
68
69
70
static CK_RV sc_to_cryptoki_error_common(int rc)
71
32.0k
{
72
32.0k
  sc_log(context, "libopensc return value: %d (%s)\n", rc, sc_strerror(rc));
73
32.0k
  switch (rc) {
74
13.9k
  case SC_SUCCESS:
75
13.9k
    return CKR_OK;
76
1.36k
  case SC_ERROR_NOT_SUPPORTED:
77
1.36k
    return CKR_FUNCTION_NOT_SUPPORTED;
78
0
  case SC_ERROR_OUT_OF_MEMORY:
79
0
    return CKR_HOST_MEMORY;
80
20
  case SC_ERROR_PIN_CODE_INCORRECT:
81
20
    return CKR_PIN_INCORRECT;
82
3
  case SC_ERROR_AUTH_METHOD_BLOCKED:
83
3
    return CKR_PIN_LOCKED;
84
1
  case SC_ERROR_BUFFER_TOO_SMALL:
85
1
    return CKR_BUFFER_TOO_SMALL;
86
0
  case SC_ERROR_CARD_NOT_PRESENT:
87
0
    return CKR_TOKEN_NOT_PRESENT;
88
4.57k
  case SC_ERROR_INVALID_CARD:
89
11.5k
  case SC_ERROR_WRONG_CARD:
90
11.5k
  case SC_ERROR_NO_CARD_SUPPORT:
91
11.5k
    return CKR_TOKEN_NOT_RECOGNIZED;
92
46
  case SC_ERROR_WRONG_LENGTH:
93
46
    return CKR_DATA_LEN_RANGE;
94
159
  case SC_ERROR_INVALID_PIN_LENGTH:
95
159
    return CKR_PIN_LEN_RANGE;
96
0
  case SC_ERROR_KEYPAD_CANCELLED:
97
0
  case SC_ERROR_KEYPAD_TIMEOUT:
98
0
    return CKR_FUNCTION_CANCELED;
99
0
  case SC_ERROR_CARD_REMOVED:
100
0
    return CKR_DEVICE_REMOVED;
101
9
  case SC_ERROR_SECURITY_STATUS_NOT_SATISFIED:
102
9
    return CKR_USER_NOT_LOGGED_IN;
103
0
  case SC_ERROR_KEYPAD_PIN_MISMATCH:
104
0
    return CKR_PIN_INVALID;
105
109
  case SC_ERROR_INVALID_ARGUMENTS:
106
109
    return CKR_ARGUMENTS_BAD;
107
153
  case SC_ERROR_INVALID_DATA:
108
169
  case SC_ERROR_INCORRECT_PARAMETERS:
109
169
    return CKR_DATA_INVALID;
110
0
  case SC_ERROR_CARD_UNRESPONSIVE:
111
0
  case SC_ERROR_READER_LOCKED:
112
0
    return CKR_DEVICE_ERROR;
113
0
  case SC_ERROR_READER_DETACHED:
114
0
    return CKR_TOKEN_NOT_PRESENT; /* Maybe CKR_DEVICE_REMOVED ? */
115
27
  case SC_ERROR_NOT_ENOUGH_MEMORY:
116
27
    return CKR_DEVICE_MEMORY;
117
1
  case SC_ERROR_MEMORY_FAILURE: /* EEPROM has failed */
118
1
    return CKR_DEVICE_ERROR;
119
82
  case SC_ERROR_WRONG_PADDING:
120
82
    return CKR_ENCRYPTED_DATA_INVALID;
121
32.0k
  }
122
4.54k
  return CKR_GENERAL_ERROR;
123
32.0k
}
124
125
126
CK_RV sc_to_cryptoki_error(int rc, const char *ctx)
127
32.0k
{
128
32.0k
  if (ctx)   {
129
9.53k
    int ii;
130
131
38.1k
    for (ii = 0; sc_to_cryptoki_error_map[ii].context; ii++) {
132
28.5k
      if (sc_to_cryptoki_error_map[ii].sc_error != rc)
133
28.4k
        continue;
134
183
      if (strcmp(sc_to_cryptoki_error_map[ii].context, ctx))
135
179
        continue;
136
4
      return sc_to_cryptoki_error_map[ii].ck_error;
137
183
    }
138
9.53k
  }
139
32.0k
  return sc_to_cryptoki_error_common(rc);
140
32.0k
}
141
142
143
struct sc_pkcs11_login {
144
  CK_USER_TYPE userType;
145
  CK_CHAR_PTR pPin;
146
  CK_ULONG ulPinLen;
147
};
148
149
CK_RV restore_login_state(struct sc_pkcs11_slot *slot)
150
3.52k
{
151
3.52k
  CK_RV r = CKR_OK;
152
153
3.52k
  if (sc_pkcs11_conf.atomic && slot) {
154
0
    if (list_iterator_start(&slot->logins)) {
155
0
      struct sc_pkcs11_login *login = list_iterator_next(&slot->logins);
156
0
      while (login && slot->p11card && slot->p11card->framework) {
157
0
        r = slot->p11card->framework->login(slot, login->userType,
158
0
            login->pPin, login->ulPinLen);
159
0
        if (r != CKR_OK)
160
0
          break;
161
0
        login = list_iterator_next(&slot->logins);
162
0
      }
163
0
      list_iterator_stop(&slot->logins);
164
0
    }
165
0
  }
166
167
3.52k
  return r;
168
3.52k
}
169
170
CK_RV reset_login_state(struct sc_pkcs11_slot *slot, CK_RV rv)
171
3.52k
{
172
3.52k
  if (slot) {
173
3.52k
    if (sc_pkcs11_conf.atomic
174
3.52k
        && slot->p11card && slot->p11card->framework) {
175
0
      slot->p11card->framework->logout(slot);
176
0
    }
177
178
3.52k
    if (constant_time_eq_s(rv, CKR_USER_NOT_LOGGED_IN)) {
179
7
      slot->login_user = -1;
180
7
      pop_all_login_states(slot);
181
7
    }
182
3.52k
  }
183
184
3.52k
  return rv;
185
3.52k
}
186
187
CK_RV push_login_state(struct sc_pkcs11_slot *slot,
188
    CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
189
747
{
190
747
  CK_RV r = CKR_HOST_MEMORY;
191
747
  struct sc_pkcs11_login *login = NULL;
192
193
747
  if (!sc_pkcs11_conf.atomic || !slot) {
194
747
    return CKR_OK;
195
747
  }
196
197
0
  login = (struct sc_pkcs11_login *) calloc(1, sizeof *login);
198
0
  if (login == NULL) {
199
0
    goto err;
200
0
  }
201
202
0
  if (pPin && ulPinLen) {
203
0
    login->pPin = sc_mem_secure_alloc((sizeof *pPin)*ulPinLen);
204
0
    if (login->pPin == NULL) {
205
0
      goto err;
206
0
    }
207
0
    memcpy(login->pPin, pPin, (sizeof *pPin)*ulPinLen);
208
0
    login->ulPinLen = ulPinLen;
209
0
  }
210
0
  login->userType = userType;
211
212
0
  if (0 > list_append(&slot->logins, login)) {
213
0
    goto err;
214
0
  }
215
216
0
  login = NULL;
217
0
  r = CKR_OK;
218
219
0
err:
220
0
  if (login) {
221
0
    if (login->pPin) {
222
0
      sc_mem_secure_clear_free(login->pPin, login->ulPinLen);
223
0
    }
224
0
    free(login);
225
0
  }
226
227
0
  return r;
228
0
}
229
230
void pop_login_state(struct sc_pkcs11_slot *slot)
231
0
{
232
0
  if (slot) {
233
0
    unsigned int size = list_size(&slot->logins);
234
0
    if (size > 0) {
235
0
      struct sc_pkcs11_login *login = list_get_at(&slot->logins, size-1);
236
0
      if (login) {
237
0
        sc_mem_secure_clear_free(login->pPin, login->ulPinLen);
238
0
        free(login);
239
0
      }
240
0
      if (0 > list_delete_at(&slot->logins, size-1))
241
0
        sc_log(context, "Error deleting login state");
242
0
    }
243
0
  }
244
0
}
245
246
void pop_all_login_states(struct sc_pkcs11_slot *slot)
247
15.4k
{
248
15.4k
  if (sc_pkcs11_conf.atomic && slot) {
249
0
    struct sc_pkcs11_login *login = list_fetch(&slot->logins);
250
0
    while (login) {
251
0
      sc_mem_secure_clear_free(login->pPin, login->ulPinLen);
252
0
      free(login);
253
0
      login = list_fetch(&slot->logins);
254
0
    }
255
0
  }
256
15.4k
}
257
258
259
/* Session manipulation */
260
CK_RV session_start_operation(struct sc_pkcs11_session * session,
261
            int type, sc_pkcs11_mechanism_type_t * mech, struct sc_pkcs11_operation ** operation)
262
1.44k
{
263
1.44k
  sc_pkcs11_operation_t *op;
264
265
1.44k
  if (context == NULL)
266
0
    return CKR_CRYPTOKI_NOT_INITIALIZED;
267
268
1.44k
  LOG_FUNC_CALLED(context);
269
1.44k
  sc_log(context, "Session 0x%lx, type %d", session->handle, type);
270
1.44k
  if (type < 0 || type >= SC_PKCS11_OPERATION_MAX)
271
0
    return CKR_ARGUMENTS_BAD;
272
273
1.44k
  if (session->operation[type] != NULL)
274
0
    return CKR_OPERATION_ACTIVE;
275
276
1.44k
  if (!(op = sc_pkcs11_new_operation(session, mech)))
277
0
    return CKR_HOST_MEMORY;
278
279
1.44k
  session->operation[type] = op;
280
1.44k
  if (operation)
281
1.44k
    *operation = op;
282
283
1.44k
  return CKR_OK;
284
1.44k
}
285
286
CK_RV session_get_operation(struct sc_pkcs11_session * session, int type, sc_pkcs11_operation_t ** operation)
287
3.10k
{
288
3.10k
  sc_pkcs11_operation_t *op;
289
290
3.10k
  LOG_FUNC_CALLED(context);
291
292
3.10k
  if (type < 0 || type >= SC_PKCS11_OPERATION_MAX)
293
0
    return CKR_ARGUMENTS_BAD;
294
295
3.10k
  if (!(op = session->operation[type]))
296
0
    return CKR_OPERATION_NOT_INITIALIZED;
297
298
3.10k
  if (operation)
299
2.16k
    *operation = op;
300
301
3.10k
  return CKR_OK;
302
3.10k
}
303
304
CK_RV session_stop_operation(struct sc_pkcs11_session * session, int type)
305
1.44k
{
306
1.44k
  if (type < 0 || type >= SC_PKCS11_OPERATION_MAX)
307
0
    return CKR_ARGUMENTS_BAD;
308
309
1.44k
  if (session->operation[type] == NULL)
310
0
    return CKR_OPERATION_NOT_INITIALIZED;
311
312
1.44k
  sc_pkcs11_release_operation(&session->operation[type]);
313
1.44k
  return CKR_OK;
314
1.44k
}
315
316
CK_RV attr_extract(CK_ATTRIBUTE_PTR pAttr, void *ptr, size_t * sizep)
317
724
{
318
724
  size_t size;
319
320
724
  if (sizep) {
321
0
    size = *sizep;
322
0
    if (size < pAttr->ulValueLen)
323
0
      return CKR_ATTRIBUTE_VALUE_INVALID;
324
0
    *sizep = pAttr->ulValueLen;
325
724
  } else {
326
724
    switch (pAttr->type) {
327
180
    case CKA_CLASS:
328
180
      size = sizeof(CK_OBJECT_CLASS);
329
180
      break;
330
0
    case CKA_KEY_TYPE:
331
0
      size = sizeof(CK_KEY_TYPE);
332
0
      break;
333
56
    case CKA_PRIVATE:
334
537
    case CKA_TOKEN:
335
537
      size = sizeof(CK_BBOOL);
336
537
      break;
337
7
    case CKA_CERTIFICATE_TYPE:
338
7
      size = sizeof(CK_CERTIFICATE_TYPE);
339
7
      break;
340
0
    case CKA_VALUE_LEN:
341
0
    case CKA_MODULUS_BITS:
342
0
      size = sizeof(CK_ULONG);
343
0
      break;
344
0
    case CKA_OBJECT_ID:
345
0
      size = sizeof(struct sc_object_id);
346
0
      break;
347
0
    default:
348
0
      return CKR_FUNCTION_FAILED;
349
724
    }
350
724
    if (size != pAttr->ulValueLen)
351
0
      return CKR_ATTRIBUTE_VALUE_INVALID;
352
724
  }
353
724
  memcpy(ptr, pAttr->pValue, pAttr->ulValueLen);
354
724
  return CKR_OK;
355
724
}
356
357
CK_RV attr_find(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_ULONG type, void *ptr, size_t * sizep)
358
668
{
359
668
  unsigned int n;
360
361
1.66k
  for (n = 0; n < ulCount; n++, pTemplate++) {
362
1.66k
    if (pTemplate->type == type)
363
668
      break;
364
1.66k
  }
365
366
668
  if (n >= ulCount)
367
0
    return CKR_TEMPLATE_INCOMPLETE;
368
668
  return attr_extract(pTemplate, ptr, sizep);
369
668
}
370
371
CK_RV attr_find2(CK_ATTRIBUTE_PTR pTemp1, CK_ULONG ulCount1,
372
     CK_ATTRIBUTE_PTR pTemp2, CK_ULONG ulCount2, CK_ULONG type, void *ptr, size_t * sizep)
373
0
{
374
0
  CK_RV rv;
375
376
0
  rv = attr_find(pTemp1, ulCount1, type, ptr, sizep);
377
0
  if (rv != CKR_OK)
378
0
    rv = attr_find(pTemp2, ulCount2, type, ptr, sizep);
379
380
0
  return rv;
381
0
}
382
383
CK_RV attr_find_and_allocate_ptr(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_ULONG type, void **out, size_t *out_len)
384
0
{
385
0
  void *ptr;
386
0
  size_t len;
387
0
  CK_RV rv;
388
389
0
  if (!out || !out_len)
390
0
    return CKR_ARGUMENTS_BAD;
391
0
  len = *out_len;
392
393
0
  rv = attr_find_ptr(pTemplate, ulCount, type, &ptr, &len);
394
0
  if (rv != CKR_OK)
395
0
    return rv;
396
397
0
  *out = calloc(1, len);
398
0
  if (*out == NULL)
399
0
    return CKR_HOST_MEMORY;
400
401
0
  memcpy(*out, ptr, len);
402
0
  *out_len = len;
403
404
0
  return CKR_OK;
405
0
}
406
407
CK_RV attr_find_ptr(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_ULONG type, void **ptr, size_t * sizep)
408
0
{
409
0
  unsigned int n;
410
411
0
  for (n = 0; n < ulCount; n++, pTemplate++) {
412
0
    if (pTemplate->type == type)
413
0
      break;
414
0
  }
415
416
0
  if (n >= ulCount)
417
0
    return CKR_TEMPLATE_INCOMPLETE;
418
419
0
  if (sizep)
420
0
    *sizep = pTemplate->ulValueLen;
421
0
  *ptr = pTemplate->pValue;
422
0
  return CKR_OK;
423
0
}
424
425
CK_RV attr_find_ptr2(CK_ATTRIBUTE_PTR pTemp1, CK_ULONG ulCount1,
426
     CK_ATTRIBUTE_PTR pTemp2, CK_ULONG ulCount2, CK_ULONG type, void **ptr, size_t * sizep)
427
0
{
428
0
  CK_RV rv;
429
430
0
  rv = attr_find_ptr(pTemp1, ulCount1, type, ptr, sizep);
431
0
  if (rv != CKR_OK)
432
0
    rv = attr_find_ptr(pTemp2, ulCount2, type, ptr, sizep);
433
434
0
  return rv;
435
0
}
436
437
CK_RV attr_find_var(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_ULONG type, void *ptr, size_t * sizep)
438
0
{
439
0
  unsigned int n;
440
441
0
  for (n = 0; n < ulCount; n++, pTemplate++) {
442
0
    if (pTemplate->type == type)
443
0
      break;
444
0
  }
445
446
0
  if (n >= ulCount)
447
0
    return CKR_TEMPLATE_INCOMPLETE;
448
449
0
  return attr_extract(pTemplate, ptr, sizep);
450
0
}
451
452
static int is_nss_browser(sc_context_t * ctx)
453
15.4k
{
454
15.4k
  const char *basename;
455
#ifdef _WIN32
456
  const char sep = '\\';
457
#else
458
15.4k
  const char sep = '/';
459
15.4k
#endif
460
15.4k
  if (!ctx || !ctx->exe_path)
461
0
    return 0;
462
463
15.4k
  basename = strrchr(ctx->exe_path, sep);
464
15.4k
  if (!basename)
465
0
    basename = ctx->exe_path;
466
15.4k
  else
467
    /* discard the separator */
468
15.4k
    basename += sizeof(char);
469
470
15.4k
  if (strstr(basename, "chromium") || strstr(basename, "chrome")
471
15.4k
      || strstr(basename, "firefox") || strstr(basename, "msedge"))
472
0
    return 1;
473
474
15.4k
  return 0;
475
15.4k
}
476
477
void load_pkcs11_parameters(struct sc_pkcs11_config *conf, sc_context_t * ctx)
478
15.4k
{
479
15.4k
  scconf_block *conf_block = NULL;
480
15.4k
  char *unblock_style = NULL;
481
15.4k
  char *create_slots_for_pins = NULL, *op, *tmp;
482
483
  /* Set defaults */
484
15.4k
  conf->max_virtual_slots = 16;
485
15.4k
  if (is_nss_browser(ctx)) {
486
    /* NSS verifies *every* PIN even though only a single one would be
487
     * needed to use one specific key. In known NSS browsers, we set
488
     * slots_per_card to `1` to only look at the authentication PIN, i.e.
489
     * ignoring a potential signature PIN. */
490
0
    conf->slots_per_card = 1;
491
15.4k
  } else {
492
15.4k
    conf->slots_per_card = 4;
493
15.4k
  }
494
15.4k
  conf->atomic = 0;
495
15.4k
  conf->lock_login = 0;
496
15.4k
  conf->init_sloppy = 1;
497
15.4k
  conf->pin_unblock_style = SC_PKCS11_PIN_UNBLOCK_NOT_ALLOWED;
498
15.4k
  conf->create_puk_slot = 0;
499
15.4k
  conf->create_slots_flags = SC_PKCS11_SLOT_CREATE_ALL;
500
501
15.4k
  conf_block = sc_get_conf_block(ctx, "pkcs11", NULL, 1);
502
15.4k
  if (!conf_block)
503
15.4k
    goto out;
504
505
  /* contains the defaults, if there is a "pkcs11" config block */
506
0
  conf->max_virtual_slots = scconf_get_int(conf_block, "max_virtual_slots", conf->max_virtual_slots);
507
0
  conf->slots_per_card = scconf_get_int(conf_block, "slots_per_card", conf->slots_per_card);
508
0
  conf->atomic = scconf_get_bool(conf_block, "atomic", conf->atomic);
509
0
  if (conf->atomic)
510
0
    conf->lock_login = 1;
511
0
  conf->lock_login = scconf_get_bool(conf_block, "lock_login", conf->lock_login);
512
0
  conf->init_sloppy = scconf_get_bool(conf_block, "init_sloppy", conf->init_sloppy);
513
514
0
  unblock_style = (char *)scconf_get_str(conf_block, "user_pin_unblock_style", NULL);
515
0
  if (unblock_style && !strcmp(unblock_style, "set_pin_in_unlogged_session"))
516
0
    conf->pin_unblock_style = SC_PKCS11_PIN_UNBLOCK_UNLOGGED_SETPIN;
517
0
  else if (unblock_style && !strcmp(unblock_style, "set_pin_in_specific_context"))
518
0
    conf->pin_unblock_style = SC_PKCS11_PIN_UNBLOCK_SCONTEXT_SETPIN;
519
0
  else if (unblock_style && !strcmp(unblock_style, "init_pin_in_so_session"))
520
0
    conf->pin_unblock_style = SC_PKCS11_PIN_UNBLOCK_SO_LOGGED_INITPIN;
521
522
0
  conf->create_puk_slot = scconf_get_bool(conf_block, "create_puk_slot", conf->create_puk_slot);
523
524
0
  create_slots_for_pins = (char *)scconf_get_str(conf_block, "create_slots_for_pins", "all");
525
0
  conf->create_slots_flags = 0;
526
0
  tmp = strdup(create_slots_for_pins);
527
0
  op = strtok(tmp, " ,");
528
0
  while (op) {
529
0
    if (!strcmp(op, "user"))
530
0
      conf->create_slots_flags |= SC_PKCS11_SLOT_FOR_PIN_USER;
531
0
    else if (!strcmp(op, "sign"))
532
0
      conf->create_slots_flags |= SC_PKCS11_SLOT_FOR_PIN_SIGN;
533
0
    else if (!strcmp(op, "all"))
534
0
      conf->create_slots_flags |= SC_PKCS11_SLOT_CREATE_ALL;
535
0
    op = strtok(NULL, " ,");
536
0
  }
537
0
  free(tmp);
538
539
15.4k
out:
540
15.4k
  sc_log(ctx, "PKCS#11 options: max_virtual_slots=%d slots_per_card=%d "
541
15.4k
     "lock_login=%d atomic=%d pin_unblock_style=%d "
542
15.4k
     "create_slots_flags=0x%X",
543
15.4k
     conf->max_virtual_slots, conf->slots_per_card,
544
15.4k
     conf->lock_login, conf->atomic, conf->pin_unblock_style,
545
15.4k
     conf->create_slots_flags);
546
15.4k
}