Mercurial > projects > libpws
diff pws-field.c @ 0:d541e748cfd8
Initial revision
author | Guido Berhoerster <guido+libpws@berhoerster.name> |
---|---|
date | Tue, 10 Feb 2015 11:29:54 +0100 |
parents | |
children | 1c0e7f79e737 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pws-field.c Tue Feb 10 11:29:54 2015 +0100 @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name> + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "compat.h" + +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#include "pws-internal.h" + +static const enum pws_data_type header_data_types[256] = { + [PWS3_HEADER_FIELD_VERSION] = PWS_DATA_TYPE_UINT16, + [PWS3_HEADER_FIELD_UUID] = PWS_DATA_TYPE_UUID, + [PWS3_HEADER_FIELD_NON_DEFAULT_PREFERENCES] = PWS_DATA_TYPE_TEXT, + [PWS3_HEADER_FIELD_TREE_DISPLAY_STATUS] = PWS_DATA_TYPE_TEXT, + [PWS3_HEADER_FIELD_SAVE_TIMESTAMP] = PWS_DATA_TYPE_TIME, + [PWS3_HEADER_FIELD_SAVE_USER_HOST] = PWS_DATA_TYPE_TEXT, + [PWS3_HEADER_FIELD_SAVE_APPLICATION] = PWS_DATA_TYPE_TEXT, + [PWS3_HEADER_FIELD_SAVE_USER] = PWS_DATA_TYPE_TEXT, + [PWS3_HEADER_FIELD_SAVE_HOST] = PWS_DATA_TYPE_TEXT, + [PWS3_HEADER_FIELD_DATABASE_NAME] = PWS_DATA_TYPE_TEXT, + [PWS3_HEADER_FIELD_DATABASE_DESCRIPTION] = PWS_DATA_TYPE_TEXT, + [PWS3_HEADER_FIELD_DATABASE_FILTERS] = PWS_DATA_TYPE_TEXT, + [PWS3_HEADER_FIELD_RESERVED_1] = PWS_DATA_TYPE_BYTES, + [PWS3_HEADER_FIELD_RESERVED_2] = PWS_DATA_TYPE_BYTES, + [PWS3_HEADER_FIELD_RESERVED_3] = PWS_DATA_TYPE_BYTES, + [PWS3_HEADER_FIELD_RECENTLY_USED_ENTRIES] = PWS_DATA_TYPE_TEXT, + [PWS3_HEADER_FIELD_NAMED_PASSWORD_POLICIES] = PWS_DATA_TYPE_TEXT, + [PWS3_HEADER_FIELD_EMPTY_GROUPS] = PWS_DATA_TYPE_TEXT, + [PWS3_HEADER_FIELD_YUBICO] = PWS_DATA_TYPE_TEXT +}; + +static const enum pws_data_type record_data_types[256] = { + [PWS3_RECORD_FIELD_UUID] = PWS_DATA_TYPE_UUID, + [PWS3_RECORD_FIELD_GROUP] = PWS_DATA_TYPE_TEXT, + [PWS3_RECORD_FIELD_TITLE] = PWS_DATA_TYPE_TEXT, + [PWS3_RECORD_FIELD_USERNAME] = PWS_DATA_TYPE_TEXT, + [PWS3_RECORD_FIELD_NOTES] = PWS_DATA_TYPE_TEXT, + [PWS3_RECORD_FIELD_PASSWORD] = PWS_DATA_TYPE_TEXT, + [PWS3_RECORD_FIELD_CREATION_TIME] = PWS_DATA_TYPE_TIME, + [PWS3_RECORD_FIELD_PASSWORD_MODIFICATION_TIME] = PWS_DATA_TYPE_TIME, + [PWS3_RECORD_FIELD_ACCESS_TIME] = PWS_DATA_TYPE_TIME, + [PWS3_RECORD_FIELD_PASSWORD_EXPIRY_TIME] = PWS_DATA_TYPE_TIME, + [PWS3_RECORD_FIELD_RESERVED_1] = PWS_DATA_TYPE_BYTES, + [PWS3_RECORD_FIELD_MODIFICATION_TIME] = PWS_DATA_TYPE_TIME, + [PWS3_RECORD_FIELD_URL] = PWS_DATA_TYPE_TEXT, + [PWS3_RECORD_FIELD_AUTOTYPE] = PWS_DATA_TYPE_TEXT, + [PWS3_RECORD_FIELD_PASSWORD_HISTORY] = PWS_DATA_TYPE_TEXT, + [PWS3_RECORD_FIELD_PASSWORD_POLICY] = PWS_DATA_TYPE_TEXT, + [PWS3_RECORD_FIELD_PASSWORD_EXPIRY_INTERVAL] = PWS_DATA_TYPE_UINT32, + [PWS3_RECORD_FIELD_RUN_COMMAND] = PWS_DATA_TYPE_TEXT, + [PWS3_RECORD_FIELD_DOUBLE_CLICK_ACTION] = PWS_DATA_TYPE_BYTES, + [PWS3_RECORD_FIELD_EMAIL_ADDRESS] = PWS_DATA_TYPE_TEXT, + [PWS3_RECORD_FIELD_PROTECTED] = PWS_DATA_TYPE_UINT8, + [PWS3_RECORD_FIELD_ALLOWED_PASSWORD_SYMBOLS] = PWS_DATA_TYPE_TEXT, + [PWS3_RECORD_FIELD_SHIFT_DOUBLE_CLICK_ACTION] = PWS_DATA_TYPE_BYTES, + [PWS3_RECORD_FIELD_PASSWORD_POLICY_NAME] = PWS_DATA_TYPE_TEXT, + [PWS3_RECORD_FIELD_KEYBOARD_SHORTCUT] = PWS_DATA_TYPE_BYTES +}; + +struct pws3_field * +pws3_field_create(int is_header, uint8_t field_type) +{ + struct pws3_field *field; + + field = pws_alloc(sizeof (struct pws3_field)); + if (field == NULL) { + return (NULL); + } + + field->is_header = is_header; + field->field_type = field_type; + field->size = 0; + switch (pws3_field_get_data_type(field)) { + case PWS_DATA_TYPE_BYTES: + field->value.bytes = NULL; + break; + case PWS_DATA_TYPE_UUID: + memset(field->value.uuid, 0, PWS3_UUID_SIZE); + break; + case PWS_DATA_TYPE_TEXT: + field->value.text = NULL; + break; + case PWS_DATA_TYPE_UINT8: + field->value.uint8 = 0; + break; + case PWS_DATA_TYPE_UINT16: + field->value.uint16 = 0; + break; + case PWS_DATA_TYPE_TIME: /* FALLTHROUGH */ + case PWS_DATA_TYPE_UINT32: + field->value.uint32 = 0; + } + + return (field); +} + +void +pws3_field_destroy(struct pws3_field *field) +{ + if (field == NULL) { + return; + } + + switch (pws3_field_get_data_type(field)) { + case PWS_DATA_TYPE_BYTES: + pws_free(field->value.bytes, field->size); + break; + case PWS_DATA_TYPE_TEXT: + if (!field->is_header && + (field->field_type == PWS3_RECORD_FIELD_PASSWORD)) { + pws_secure_free(field->value.text, field->size + 1); + } else { + pws_free(field->value.text, field->size + 1); + } + break; + default: + break; + } + + pws_free(field, sizeof (struct pws3_field)); +} + +int +pws3_field_is_header(struct pws3_field *field) +{ + return (field->is_header); +} + +uint8_t +pws3_field_get_type(struct pws3_field *field) +{ + return (field->field_type); +} + +enum pws_data_type +pws3_field_get_data_type(struct pws3_field *field) +{ + return (field->is_header ? header_data_types[field->field_type] : + record_data_types[field->field_type]); +} + +int +pws3_field_set_uuid(struct pws3_field *field, + const unsigned char s[static PWS3_UUID_SIZE]) +{ + PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UUID); + + field->size = PWS3_UUID_SIZE; + memcpy(field->value.uuid, s, PWS3_UUID_SIZE); + + return (0); +} + +int +pws3_field_set_text(struct pws3_field *field, const char s[static 1]) +{ + size_t len; + char *t; + + PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_TEXT); + + len = strlen(s); + if (len > PWS3_MAX_FIELD_SIZE) { + return (-1); + } + + if (!field->is_header && + (field->field_type == PWS3_RECORD_FIELD_PASSWORD)) { + if (len > PWS3_MAX_PASSWORD_LEN) { + return (-1); + } + t = pws_secure_realloc(field->value.text, len + 1); + } else { + t = pws_realloc(field->value.text, len + 1); + } + if (t == NULL) { + return (-1); + } + field->value.text = t; + field->size = len + 1; + memcpy(field->value.text, s, field->size); + + return (0); +} + +int +pws3_field_set_time(struct pws3_field *field, time_t time) +{ + PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_TIME); + + field->size = 4; + field->value.uint32 = CLAMP(time, 0, UINT32_MAX); + + return (0); +} + +int +pws3_field_set_uint8(struct pws3_field *field, uint8_t u8) +{ + PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UINT8); + + field->size = 1; + field->value.uint8 = u8; + + return (0); +} + +int +pws3_field_set_uint16(struct pws3_field *field, uint16_t u16) +{ + PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UINT16); + + field->size = 2; + field->value.uint16 = u16; + + return (0); +} + +int +pws3_field_set_uint32(struct pws3_field *field, uint32_t u32) +{ + PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UINT32); + + field->size = 4; + field->value.uint32 = u32; + + return (0); +} + +int +pws3_field_set_bytes(struct pws3_field *field, const unsigned char s[static 1], + size_t n) +{ + unsigned char *t; + + PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_BYTES); + + if (n > PWS3_MAX_FIELD_SIZE) { + return (-1); + } + + t = pws_realloc(field->value.bytes, n); + if (t == NULL) { + return (-1); + } + field->size = n; + field->value.bytes = t; + memcpy(t, s, n); + + return (0); +} + +const unsigned char * +pws3_field_get_uuid(struct pws3_field *field) +{ + PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UUID); + + return (field->value.uuid); +} + +const char * +pws3_field_get_text(struct pws3_field *field) +{ + PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_TEXT); + + return (field->value.text); +} + +time_t +pws3_field_get_time(struct pws3_field *field) +{ + PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_TIME); + + /* assume time_t can hold at least a INT32_MAX */ + return ((time_t)CLAMP(field->value.uint32, 0, INT32_MAX)); +} + +uint8_t +pws3_field_get_uint8(struct pws3_field *field) +{ + PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UINT8); + + return (field->value.uint8); +} + +uint16_t +pws3_field_get_uint16(struct pws3_field *field) +{ + PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UINT16); + + return (field->value.uint16); +} + +uint32_t +pws3_field_get_uint32(struct pws3_field *field) +{ + PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UINT32); + + return (field->value.uint32); +} + +void +pws3_field_get_bytes(struct pws3_field *field, const unsigned char **sp, + size_t *np) +{ + PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_BYTES); + + *sp = field->value.bytes; + *np = field->size; +}