/* * rotn_error -- * Display an error from this module in a standard way. */ static int rotn_error(ROTN_ENCRYPTOR *encryptor, WT_SESSION *session, int err, const char *msg) { WT_EXTENSION_API *wtext; wtext = encryptor->wtext; (void)wtext->err_printf(wtext, session, "rotn encryption: %s: %s", msg, wtext->strerror(wtext, NULL, err)); return (err); }
/* * csv_extract -- * WiredTiger CSV extraction. */ static int csv_extract(WT_EXTRACTOR *extractor, WT_SESSION *session, const WT_ITEM *key, const WT_ITEM *value, WT_CURSOR *result_cursor) { char *copy, *p, *pend, *valstr; const CSV_EXTRACTOR *csv_extractor; int i, ret, val; size_t len; WT_EXTENSION_API *wtapi; (void)key; /* Unused parameters */ csv_extractor = (const CSV_EXTRACTOR *)extractor; wtapi = csv_extractor->wt_api; /* Unpack the value. */ if ((ret = wtapi->struct_unpack(wtapi, session, value->data, value->size, "S", &valstr)) != 0) return (ret); p = valstr; pend = strchr(p, ','); for (i = 0; i < csv_extractor->field && pend != NULL; i++) { p = pend + 1; pend = strchr(p, ','); } if (i == csv_extractor->field) { if (pend == NULL) pend = p + strlen(p); /* * The key we must return is a null terminated string, but p * is not necessarily NULL-terminated. So make a copy, just * for the duration of the insert. */ len = (size_t)(pend - p); if ((copy = malloc(len + 1)) == NULL) return (errno); strncpy(copy, p, len); copy[len] = '\0'; if (csv_extractor->format_isnum) { if ((val = atoi(copy)) < 0) { free(copy); return (EINVAL); } result_cursor->set_key(result_cursor, val); } else result_cursor->set_key(result_cursor, copy); ret = result_cursor->insert(result_cursor); free(copy); if (ret != 0) return (ret); } return (0); }
/* * rotn_configure -- * WiredTiger no-op encryption configuration. */ static int rotn_configure(ROTN_ENCRYPTOR *rotn_encryptor, WT_CONFIG_ARG *config) { WT_CONFIG_ITEM k, v; WT_CONFIG_PARSER *config_parser; WT_EXTENSION_API *wtext; /* Extension API */ int ret, t_ret; wtext = rotn_encryptor->wtext; /* Get the configuration string. */ if ((ret = wtext->config_get(wtext, NULL, config, "config", &v)) != 0) return (rotn_error(rotn_encryptor, NULL, ret, "WT_EXTENSION_API.config_get")); /* Step through the list of configuration options. */ if ((ret = wtext->config_parser_open( wtext, NULL, v.str, v.len, &config_parser)) != 0) return (rotn_error(rotn_encryptor, NULL, ret, "WT_EXTENSION_API.config_parser_open")); while ((ret = config_parser->next(config_parser, &k, &v)) == 0) { if (strncmp("rotn_force_error", k.str, k.len) == 0 && strlen("rotn_force_error") == k.len) { rotn_encryptor->force_error = v.val == 0 ? 0 : 1; continue; } else { if ((ret = config_parser->close(config_parser)) != 0) return (rotn_error(rotn_encryptor, NULL, ret, "WT_CONFIG_PARSER.close")); return (rotn_error(rotn_encryptor, NULL, EINVAL, "unknown config key")); } } if ((t_ret = config_parser->close(config_parser)) != 0) return (rotn_error(rotn_encryptor, NULL, t_ret, "WT_CONFIG_PARSER.close")); if (ret != WT_NOTFOUND) return (rotn_error(rotn_encryptor, NULL, ret, "WT_CONFIG_PARSER.next")); return (0); }
/* * csv_customize -- * The customize function creates a customized extractor, * needed to save the field number and format. */ static int csv_customize(WT_EXTRACTOR *extractor, WT_SESSION *session, const char *uri, WT_CONFIG_ITEM *appcfg, WT_EXTRACTOR **customp) { const CSV_EXTRACTOR *orig; CSV_EXTRACTOR *csv_extractor; WT_CONFIG_ITEM field, format; WT_CONFIG_PARSER *parser; WT_EXTENSION_API *wtapi; int ret; long field_num; (void)session; /* Unused parameters */ (void)uri; /* Unused parameters */ orig = (const CSV_EXTRACTOR *)extractor; wtapi = orig->wt_api; if ((ret = wtapi->config_parser_open(wtapi, session, appcfg->str, appcfg->len, &parser)) != 0) return (ret); if ((ret = parser->get(parser, "field", &field)) != 0 || (ret = parser->get(parser, "format", &format)) != 0) { if (ret == WT_NOTFOUND) return (EINVAL); return (ret); } field_num = strtol(field.str, NULL, 10); if (field_num < 0 || field_num > INT_MAX) return (EINVAL); if (format.len != 1 || (format.str[0] != 'S' && format.str[0] != 'i')) return (EINVAL); if ((csv_extractor = calloc(1, sizeof(CSV_EXTRACTOR))) == NULL) return (errno); *csv_extractor = *orig; csv_extractor->field = field_num; csv_extractor->format_isnum = (format.str[0] == 'i'); *customp = (WT_EXTRACTOR *)csv_extractor; return (0); }
/* * rotn_customize -- * The customize function creates a customized encryptor */ static int rotn_customize(WT_ENCRYPTOR *encryptor, WT_SESSION *session, WT_CONFIG_ARG *encrypt_config, WT_ENCRYPTOR **customp) { const ROTN_ENCRYPTOR *orig; ROTN_ENCRYPTOR *rotn_encryptor; WT_CONFIG_ITEM keyid, secret; WT_EXTENSION_API *wtext; size_t i, len; int ret, keyid_val; u_char base; ret = 0; keyid_val = 0; orig = (const ROTN_ENCRYPTOR *)encryptor; wtext = orig->wtext; if ((rotn_encryptor = calloc(1, sizeof(ROTN_ENCRYPTOR))) == NULL) return (errno); *rotn_encryptor = *orig; rotn_encryptor->keyid = rotn_encryptor->secretkey = NULL; /* * Stash the keyid from the configuration string. */ if ((ret = wtext->config_get(wtext, session, encrypt_config, "keyid", &keyid)) == 0 && keyid.len != 0) { /* * In this demonstration, we expect keyid to be a number. */ if ((keyid_val = atoi(keyid.str)) < 0) { ret = EINVAL; goto err; } if ((rotn_encryptor->keyid = malloc(keyid.len + 1)) == NULL) { ret = errno; goto err; } strncpy(rotn_encryptor->keyid, keyid.str, keyid.len + 1); rotn_encryptor->keyid[keyid.len] = '\0'; } /* * In this demonstration, the secret key must be alphabetic characters. * We stash the secret key from the configuration string * and build some shift bytes to make encryption/decryption easy. */ if ((ret = wtext->config_get(wtext, session, encrypt_config, "secretkey", &secret)) == 0 && secret.len != 0) { len = secret.len; if ((rotn_encryptor->secretkey = malloc(len + 1)) == NULL || (rotn_encryptor->shift_forw = malloc(len)) == NULL || (rotn_encryptor->shift_back = malloc(len)) == NULL) { ret = errno; goto err; } for (i = 0; i < len; i++) { if ('a' <= secret.str[i] && secret.str[i] <= 'z') base = 'a'; else if ('A' <= secret.str[i] && secret.str[i] <= 'Z') base = 'A'; else { ret = EINVAL; goto err; } base -= (u_char)keyid_val; rotn_encryptor->shift_forw[i] = (u_char)secret.str[i] - base; rotn_encryptor->shift_back[i] = base - (u_char)secret.str[i]; } rotn_encryptor->shift_len = len; strncpy(rotn_encryptor->secretkey, secret.str, secret.len + 1); rotn_encryptor->secretkey[secret.len] = '\0'; } /* * In a real encryptor, we could use some sophisticated key management * here to map the keyid onto a secret key. */ rotn_encryptor->rot_N = keyid_val; *customp = (WT_ENCRYPTOR *)rotn_encryptor; return (0); err: free(rotn_encryptor->keyid); free(rotn_encryptor->secretkey); free(rotn_encryptor->shift_forw); free(rotn_encryptor->shift_back); free(rotn_encryptor); return (ret); }
/* * dump_config -- * Dump the config for the uri. */ static int dump_config(WT_SESSION *session, const char *uri, int hex) { WT_CURSOR *cursor; WT_DECL_RET; WT_EXTENSION_API *wtext; int tret; const char *value; /* Dump the config. */ if (WT_PREFIX_MATCH(uri, "table:")) { /* Open a metadata cursor. */ if ((ret = session->open_cursor( session, "metadata:", NULL, NULL, &cursor)) != 0) { fprintf(stderr, "%s: %s: session.open_cursor: %s\n", progname, "metadata:", wiredtiger_strerror(ret)); return (1); } /* * Search for the object itself, just to make sure it exists, * we don't want to output a header if the user entered the * wrong name. This where we find out a table object doesn't * exist, use a simple error message. */ cursor->set_key(cursor, uri); if ((ret = cursor->search(cursor)) == 0) { if (dump_prefix(hex) != 0 || dump_table_config(session, cursor, uri) != 0 || dump_suffix() != 0) ret = 1; } else if (ret == WT_NOTFOUND) ret = util_err(0, "%s: No such object exists", uri); else ret = util_err(ret, "%s", uri); if ((tret = cursor->close(cursor)) != 0) { tret = util_cerr(uri, "close", tret); if (ret == 0) ret = tret; } } else { /* * We want to be able to dump the metadata file itself, but the * configuration for that file lives in the turtle file. Reach * down into the library and ask for the file's configuration, * that will work in all cases. * * This where we find out a file object doesn't exist, use a * simple error message. */ wtext = session-> connection->get_extension_api(session->connection); if ((ret = wtext->metadata_search(wtext, session, uri, &value)) == 0) { if (dump_prefix(hex) != 0 || print_config(session, uri, value, NULL) != 0 || dump_suffix() != 0) ret = 1; } else if (ret == WT_NOTFOUND) ret = util_err(0, "%s: No such object exists", uri); else ret = util_err(ret, "%s", uri); } return (ret); }
/* * rotate_customize -- * The customize function creates a customized encryptor */ static int rotate_customize(WT_ENCRYPTOR *encryptor, WT_SESSION *session, WT_CONFIG_ARG *encrypt_config, WT_ENCRYPTOR **customp) { MY_CRYPTO *my_crypto; WT_CONFIG_ITEM keyid, secret; WT_EXTENSION_API *extapi; int ret; const MY_CRYPTO *orig_crypto; extapi = session->connection->get_extension_api(session->connection); orig_crypto = (const MY_CRYPTO *)encryptor; if ((my_crypto = calloc(1, sizeof(MY_CRYPTO))) == NULL) { ret = errno; goto err; } *my_crypto = *orig_crypto; my_crypto->keyid = my_crypto->password = NULL; /* * Stash the keyid and the (optional) secret key from the configuration * string. */ error_check(extapi->config_get( extapi, session, encrypt_config, "keyid", &keyid)); if (keyid.len != 0) { if ((my_crypto->keyid = malloc(keyid.len + 1)) == NULL) { ret = errno; goto err; } strncpy(my_crypto->keyid, keyid.str, keyid.len + 1); my_crypto->keyid[keyid.len] = '\0'; } ret = extapi->config_get( extapi, session, encrypt_config, "secretkey", &secret); if (ret == 0 && secret.len != 0) { if ((my_crypto->password = malloc(secret.len + 1)) == NULL) { ret = errno; goto err; } strncpy(my_crypto->password, secret.str, secret.len + 1); my_crypto->password[secret.len] = '\0'; } /* * Presumably we'd have some sophisticated key management * here that maps the id onto a secret key. */ if (ITEM_MATCHES(keyid, "system")) { if (my_crypto->password == NULL || strcmp(my_crypto->password, SYS_PW) != 0) { ret = EPERM; goto err; } my_crypto->rot_N = 13; } else if (ITEM_MATCHES(keyid, USER1_KEYID)) my_crypto->rot_N = 4; else if (ITEM_MATCHES(keyid, USER2_KEYID)) my_crypto->rot_N = 19; else { ret = EINVAL; goto err; } ++my_crypto->num_calls; /* Call count */ *customp = (WT_ENCRYPTOR *)my_crypto; return (0); err: free(my_crypto->keyid); free(my_crypto->password); free(my_crypto); return (ret); }