projects/libpws

changeset 0:d541e748cfd8

Initial revision
author Guido Berhoerster <guido+libpws@berhoerster.name>
date Tue Feb 10 11:29:54 2015 +0100 (2015-02-10)
parents
children e1309515d111
files Makefile compat.h compat/endian.c compat/endian.h compat/getentropy.c compat/getentropy.h compat/pws-compat.h compat/tree.h deps.sed include/pws.h pws-field.c pws-file.c pws-internal.h pws-random.c pws-record.c pws.c
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Makefile	Tue Feb 10 11:29:54 2015 +0100
     1.3 @@ -0,0 +1,176 @@
     1.4 +#
     1.5 +# Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name>
     1.6 +#
     1.7 +# Permission is hereby granted, free of charge, to any person obtaining
     1.8 +# a copy of this software and associated documentation files (the
     1.9 +# "Software"), to deal in the Software without restriction, including
    1.10 +# without limitation the rights to use, copy, modify, merge, publish,
    1.11 +# distribute, sublicense, and/or sell copies of the Software, and to
    1.12 +# permit persons to whom the Software is furnished to do so, subject to
    1.13 +# the following conditions:
    1.14 +#
    1.15 +# The above copyright notice and this permission notice shall be included
    1.16 +# in all copies or substantial portions of the Software.
    1.17 +#
    1.18 +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    1.19 +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    1.20 +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    1.21 +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    1.22 +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    1.23 +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    1.24 +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    1.25 +#
    1.26 +
    1.27 +PACKAGE =	libpws
    1.28 +VERSION =	1.0.0
    1.29 +DISTNAME :=	$(PACKAGE)-$(VERSION)
    1.30 +
    1.31 +# gcc, clang, icc, Sun/Solaris Studio
    1.32 +CC :=		$(CC) -std=c99
    1.33 +COMPILE.c =	$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(XCPPFLAGS) $(TARGET_ARCH) -c
    1.34 +# gcc, clang, icc
    1.35 +MAKEDEPEND.c =	$(CC) -MM $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(XCPPFLAGS)
    1.36 +# Sun/Solaris Studio
    1.37 +#MAKEDEPEND.c =	$(CC) -xM1 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(XCPPFLAGS)
    1.38 +# X makedepend
    1.39 +#MAKEDEPEND.c =	makedepend -f- -Y -- $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(XCPPFLAGS) --
    1.40 +LINK.c =	$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(XCPPFLAGS) $(LDFLAGS) $(XLDFLAGS) $(TARGET_ARCH)
    1.41 +LINK.o =	$(CC) $(LDFLAGS) $(XLDFLAGS) $(TARGET_ARCH)
    1.42 +AR :=		ar
    1.43 +RANLIB :=	ranlib
    1.44 +INSTALL :=	install
    1.45 +INSTALL.exec :=	$(INSTALL) -D -m 0755
    1.46 +INSTALL.lib :=	$(INSTALL) -D -m 0644
    1.47 +INSTALL.data :=	$(INSTALL) -D -m 0644
    1.48 +PAX :=		pax
    1.49 +GZIP :=		gzip
    1.50 +SED :=		sed
    1.51 +
    1.52 +DESTDIR ?=
    1.53 +prefix ?=	/usr/local
    1.54 +bindir ?=	$(prefix)/bin
    1.55 +libdir ?=	$(prefix)/lib
    1.56 +includedir ?=	$(prefix)/include
    1.57 +datadir ?=	$(prefix)/share
    1.58 +
    1.59 +OS_NAME :=	$(shell uname -s)
    1.60 +OS_RELEASE :=	$(shell uname -r)
    1.61 +
    1.62 +ifeq ($(OS_NAME),Linux)
    1.63 +  HAVE_ARC4RANDOM ?=	0
    1.64 +  HAVE_ENDIAN_H ?=	1
    1.65 +  HAVE_SYS_ENDIAN_H ?=	0
    1.66 +  HAVE_GETENTROPY ?=	0
    1.67 +  HAVE_SYS_TREE_H ?=	0
    1.68 +else ifneq ($(findstring $(OS_NAME),FreeBSD DragonFly),)
    1.69 +  HAVE_ARC4RANDOM ?=	1
    1.70 +  HAVE_ENDIAN_H ?=	0
    1.71 +  HAVE_SYS_ENDIAN_H ?=	1
    1.72 +  HAVE_GETENTROPY ?=	0
    1.73 +  HAVE_SYS_TREE_H ?=	1
    1.74 +else ifeq ($(OS_NAME),NetBSD)
    1.75 +  HAVE_ARC4RANDOM ?=	1
    1.76 +  HAVE_ENDIAN_H ?=	0
    1.77 +  HAVE_SYS_ENDIAN_H ?=	1
    1.78 +  HAVE_GETENTROPY ?=	0
    1.79 +  HAVE_SYS_TREE_H ?=	1
    1.80 +else ifeq ($(OS_NAME),OpenBSD)
    1.81 +  HAVE_ARC4RANDOM ?=	1
    1.82 +  HAVE_ENDIAN_H ?=	0
    1.83 +  HAVE_SYS_ENDIAN_H ?=	1
    1.84 +  HAVE_GETENTROPY ?=	1
    1.85 +  HAVE_SYS_TREE_H ?=	1
    1.86 +else ifeq ($(OS_NAME),SunOS)
    1.87 +  HAVE_ARC4RANDOM ?=	0
    1.88 +  HAVE_ENDIAN_H ?=	0
    1.89 +  HAVE_SYS_ENDIAN_H ?=	0
    1.90 +  HAVE_GETENTROPY ?=	0
    1.91 +  HAVE_SYS_TREE_H ?=	0
    1.92 +else
    1.93 +  HAVE_ARC4RANDOM ?=	0
    1.94 +  HAVE_ENDIAN_H ?=	0
    1.95 +  HAVE_SYS_ENDIAN_H ?=	0
    1.96 +  HAVE_GETENTROPY ?=	0
    1.97 +  HAVE_SYS_TREE_H ?=	0
    1.98 +endif
    1.99 +
   1.100 +LIBPWS_OBJS =		pws.o \
   1.101 +			pws-file.o \
   1.102 +			pws-record.o \
   1.103 +			pws-field.o \
   1.104 +			pws-random.o
   1.105 +LIBPWS_LIB =		$(PACKAGE).a
   1.106 +LIBPWS_LIB_MEMBERS =	$(LIBPWS_OBJS:%.o=$(LIBPWS_LIB)(%.o))
   1.107 +
   1.108 +OBJS =			$(LIBPWS_OBJS)
   1.109 +
   1.110 +.DEFAULT_TARGET = all
   1.111 +
   1.112 +.PHONY: all clean clobber dist install
   1.113 +
   1.114 +all: $(LIBPWS_LIB)
   1.115 +
   1.116 +XCPPFLAGS = -Iinclude
   1.117 +ifeq ($(HAVE_ARC4RANDOM),1)
   1.118 +  XCPPFLAGS +=	-DHAVE_ARC4RANDOM
   1.119 +endif
   1.120 +ifeq ($(HAVE_ENDIAN_H),1)
   1.121 +  XCPPFLAGS +=	-DHAVE_ENDIAN_H
   1.122 +else ifeq ($(HAVE_SYS_ENDIAN_H),1)
   1.123 +  XCPPFLAGS +=	-DHAVE_SYS_ENDIAN_H
   1.124 +else
   1.125 +  LIBPWS_OBJS += compat/endian.o
   1.126 +endif
   1.127 +ifeq ($(HAVE_GETENTROPY),1)
   1.128 +  XCPPFLAGS +=	-DHAVE_GETENTROPY
   1.129 +else
   1.130 +  LIBPWS_OBJS += compat/getentropy.o
   1.131 +endif
   1.132 +ifeq ($(HAVE_SYS_TREE_H),1)
   1.133 +  XCPPFLAGS +=	-DHAVE_SYS_TREE_H
   1.134 +endif
   1.135 +ifneq ($(findstring $(OS_NAME),FreeBSD DragonFly OpenBSD),)
   1.136 +  XCPPFLAGS +=	-I/usr/local/include
   1.137 +  XLDFLAGS +=	-L/usr/local/lib
   1.138 +else ifeq ($(OS_NAME),NetBSD)
   1.139 +  XCPPFLAGS +=	-I/usr/pkg/include
   1.140 +  XLDFLAGS +=	-L/usr/pkg/lib
   1.141 +endif
   1.142 +ifeq ($(OS_NAME),SunOS)
   1.143 +  XCPPFLAGS +=	-I/usr/xpg4/include -D__EXTENSIONS__
   1.144 +  XLDFLAGS +=	-L/usr/xpg4/lib -R/usr/xpg4/lib
   1.145 +endif
   1.146 +ifeq ($(findstring $(OS_NAME),FreeBSD DragonFly NetBSD OpenBSD),)
   1.147 +  XCPPFLAGS +=	-D_XOPEN_SOURCE=600
   1.148 +endif
   1.149 +
   1.150 +$(LIBPWS_LIB): $(LIBPWS_LIB_MEMBERS)
   1.151 +
   1.152 +%.o: %.c
   1.153 +	$(MAKEDEPEND.c) $< | $(SED) -f deps.sed >$*.d
   1.154 +	$(COMPILE.c) -o $@ $<
   1.155 +
   1.156 +(%): %
   1.157 +	$(AR) $(ARFLAGS) $@ $<
   1.158 +	$(RANLIB) $@
   1.159 +
   1.160 +install:
   1.161 +	for header in include/*.h; do \
   1.162 +	    $(INSTALL.data) $${header} \
   1.163 +	        "$(DESTDIR)$(includedir)/$(PACKAGE)/$${header##*/}"; \
   1.164 +	done
   1.165 +	$(INSTALL.lib) $(LIBPWS_LIB) \
   1.166 +	    "$(DESTDIR)$(libdir)/$(notdir $(LIBPWS_LIB))"
   1.167 +
   1.168 +clean:
   1.169 +	rm -f $(LIBPWS_LIB) $(LIBPWS_OBJS)
   1.170 +
   1.171 +clobber: clean
   1.172 +	rm -f $(patsubst %.o,%.d,$(OBJS))
   1.173 +
   1.174 +dist: clobber
   1.175 +	$(PAX) -w -x ustar -s ',.*/\..*,,' -s ',./[^/]*\.tar\.gz,,' \
   1.176 +	    -s ',^\.$$,,' -s ',\./,$(DISTNAME)/,' . | \
   1.177 +	    $(GZIP) > $(DISTNAME).tar.gz
   1.178 +
   1.179 +-include $(patsubst %.o,%.d,$(OBJS))
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/compat.h	Tue Feb 10 11:29:54 2015 +0100
     2.3 @@ -0,0 +1,47 @@
     2.4 +/*
     2.5 + * Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name>
     2.6 + *
     2.7 + * Permission is hereby granted, free of charge, to any person obtaining
     2.8 + * a copy of this software and associated documentation files (the
     2.9 + * "Software"), to deal in the Software without restriction, including
    2.10 + * without limitation the rights to use, copy, modify, merge, publish,
    2.11 + * distribute, sublicense, and/or sell copies of the Software, and to
    2.12 + * permit persons to whom the Software is furnished to do so, subject to
    2.13 + * the following conditions:
    2.14 + *
    2.15 + * The above copyright notice and this permission notice shall be included
    2.16 + * in all copies or substantial portions of the Software.
    2.17 + *
    2.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    2.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    2.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    2.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    2.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    2.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    2.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    2.25 + */
    2.26 +
    2.27 +#ifndef	COMPAT_H
    2.28 +#define	COMPAT_H
    2.29 +
    2.30 +#include "compat/pws-compat.h"
    2.31 +
    2.32 +/* for FreeBSD getline() */
    2.33 +#define	_WITH_GETLINE
    2.34 +
    2.35 +/* for glibc endian.h */
    2.36 +#define	_BSD_SOURCE
    2.37 +
    2.38 +#if	!defined(HAVE_ENDIAN_H) && !defined(HAVE_SYS_ENDIAN_H)
    2.39 +#include "compat/endian.h"
    2.40 +#endif /* !defined(HAVE_ENDIAN_H) && !defined(HAVE_SYS_ENDIAN_H) */
    2.41 +
    2.42 +#ifndef	HAVE_GETENTROPY
    2.43 +#include "compat/getentropy.h"
    2.44 +#endif /* !HAVE_GETENTROPY */
    2.45 +
    2.46 +#ifndef	HAVE_SYS_TREE_H
    2.47 +#include "compat/tree.h"
    2.48 +#endif /* !HAVE_SYS_TREE_H */
    2.49 +
    2.50 +#endif /* COMPAT_H */
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/compat/endian.c	Tue Feb 10 11:29:54 2015 +0100
     3.3 @@ -0,0 +1,93 @@
     3.4 +/*
     3.5 + * Copyright (C) 2015 Guido Berhoerster <guido+pws@berhoerster.name>
     3.6 + *
     3.7 + * Permission is hereby granted, free of charge, to any person obtaining
     3.8 + * a copy of this software and associated documentation files (the
     3.9 + * "Software"), to deal in the Software without restriction, including
    3.10 + * without limitation the rights to use, copy, modify, merge, publish,
    3.11 + * distribute, sublicense, and/or sell copies of the Software, and to
    3.12 + * permit persons to whom the Software is furnished to do so, subject to
    3.13 + * the following conditions:
    3.14 + *
    3.15 + * The above copyright notice and this permission notice shall be included
    3.16 + * in all copies or substantial portions of the Software.
    3.17 + *
    3.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    3.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    3.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    3.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    3.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    3.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    3.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    3.25 + */
    3.26 +
    3.27 +#include <arpa/inet.h>
    3.28 +
    3.29 +#include "pws-compat.h"
    3.30 +#include "endian.h"
    3.31 +
    3.32 +uint16_t
    3.33 +le16toh(uint16_t little16)
    3.34 +{
    3.35 +	unsigned char	*b = (unsigned char *)&little16;
    3.36 +
    3.37 +	return ((b[0] << 0) | (b[1] << 8));
    3.38 +}
    3.39 +
    3.40 +uint16_t
    3.41 +htole16(uint16_t host16)
    3.42 +{
    3.43 +	uint16_t	little16;
    3.44 +	unsigned char	*b = (unsigned char *)&little16;
    3.45 +
    3.46 +	b[0] = (unsigned char)(host16 >> 0);
    3.47 +	b[1] = (unsigned char)(host16 >> 8);
    3.48 +
    3.49 +	return (little16);
    3.50 +}
    3.51 +
    3.52 +uint32_t
    3.53 +le32toh(uint32_t little32)
    3.54 +{
    3.55 +	unsigned char	*b = (unsigned char *)&little32;
    3.56 +
    3.57 +	return ((b[0] << 0) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24));
    3.58 +}
    3.59 +
    3.60 +uint32_t
    3.61 +htole32(uint32_t host32)
    3.62 +{
    3.63 +	uint32_t	little32;
    3.64 +	unsigned char	*b = (unsigned char *)&little32;
    3.65 +
    3.66 +	b[0] = (unsigned char)(host32 >> 0);
    3.67 +	b[1] = (unsigned char)(host32 >> 8);
    3.68 +	b[2] = (unsigned char)(host32 >> 16);
    3.69 +	b[3] = (unsigned char)(host32 >> 24);
    3.70 +
    3.71 +	return (little32);
    3.72 +}
    3.73 +
    3.74 +uint16_t
    3.75 +be16toh(uint16_t big16)
    3.76 +{
    3.77 +	return (ntohs(big16));
    3.78 +}
    3.79 +
    3.80 +uint16_t
    3.81 +htobe16(uint16_t host16)
    3.82 +{
    3.83 +	return (htons(host16));
    3.84 +}
    3.85 +
    3.86 +uint32_t
    3.87 +be32toh(uint32_t big32)
    3.88 +{
    3.89 +	return (ntohl(big32));
    3.90 +}
    3.91 +
    3.92 +uint32_t
    3.93 +htobe32(uint32_t host32)
    3.94 +{
    3.95 +	return (htonl(host32));
    3.96 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/compat/endian.h	Tue Feb 10 11:29:54 2015 +0100
     4.3 @@ -0,0 +1,38 @@
     4.4 +/*
     4.5 + * Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name>
     4.6 + *
     4.7 + * Permission is hereby granted, free of charge, to any person obtaining
     4.8 + * a copy of this software and associated documentation files (the
     4.9 + * "Software"), to deal in the Software without restriction, including
    4.10 + * without limitation the rights to use, copy, modify, merge, publish,
    4.11 + * distribute, sublicense, and/or sell copies of the Software, and to
    4.12 + * permit persons to whom the Software is furnished to do so, subject to
    4.13 + * the following conditions:
    4.14 + *
    4.15 + * The above copyright notice and this permission notice shall be included
    4.16 + * in all copies or substantial portions of the Software.
    4.17 + *
    4.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    4.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    4.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    4.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    4.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    4.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    4.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    4.25 + */
    4.26 +
    4.27 +#ifndef	ENDIAN_H
    4.28 +#define	ENDIAN_H
    4.29 +
    4.30 +#include <stdint.h>
    4.31 +
    4.32 +uint16_t	le16toh(uint16_t);
    4.33 +uint16_t	htole16(uint16_t);
    4.34 +uint32_t	le32toh(uint32_t);
    4.35 +uint32_t	htole32(uint32_t);
    4.36 +uint16_t	be16toh(uint16_t);
    4.37 +uint16_t	htobe16(uint16_t);
    4.38 +uint32_t	be32toh(uint32_t);
    4.39 +uint32_t	htobe32(uint32_t);
    4.40 +
    4.41 +#endif /* !ENDIAN_H */
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/compat/getentropy.c	Tue Feb 10 11:29:54 2015 +0100
     5.3 @@ -0,0 +1,112 @@
     5.4 +/*
     5.5 + * Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name>
     5.6 + *
     5.7 + * Permission is hereby granted, free of charge, to any person obtaining
     5.8 + * a copy of this software and associated documentation files (the
     5.9 + * "Software"), to deal in the Software without restriction, including
    5.10 + * without limitation the rights to use, copy, modify, merge, publish,
    5.11 + * distribute, sublicense, and/or sell copies of the Software, and to
    5.12 + * permit persons to whom the Software is furnished to do so, subject to
    5.13 + * the following conditions:
    5.14 + *
    5.15 + * The above copyright notice and this permission notice shall be included
    5.16 + * in all copies or substantial portions of the Software.
    5.17 + *
    5.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    5.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    5.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    5.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    5.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    5.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    5.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    5.25 + */
    5.26 +
    5.27 +/* needed for syscall(2) on Linux */
    5.28 +#define	_GNU_SOURCE
    5.29 +
    5.30 +/* Linux >= 3.17 has getrandom(2) system call */
    5.31 +#ifdef	__linux__
    5.32 +#include <unistd.h>
    5.33 +#include <sys/syscall.h>
    5.34 +#include <linux/random.h>
    5.35 +#ifdef	SYS_getrandom
    5.36 +#define	HAVE_GETRANDOM
    5.37 +#endif /* SYS_getrandom */
    5.38 +#endif /* __linux__ */
    5.39 +/*
    5.40 + * on unknown Unix systems without getentropy(2) or Linux without getrandom(2)
    5.41 + * fall back to * reading from /dev/(u)random
    5.42 + */
    5.43 +#ifndef	HAVE_GETRANDOM
    5.44 +#include <stdio.h>
    5.45 +#ifndef	RANDOM_DEVICE
    5.46 +#ifdef	__linux__
    5.47 +/* on Linux /dev/urandom should be good enough */
    5.48 +#define	RANDOM_DEVICE	"/dev/urandom"
    5.49 +#else /* __linux__ */
    5.50 +/* on unknown Unix systems use the possibly blocking /dev/random */
    5.51 +#define	RANDOM_DEVICE	"/dev/random"
    5.52 +#endif /* __linux__ */
    5.53 +#endif /* !RANDOM_DEVICE */
    5.54 +#endif /* !HAVE_GETRANDOM */
    5.55 +#include <errno.h>
    5.56 +
    5.57 +#include "pws-compat.h"
    5.58 +
    5.59 +#ifdef	HAVE_GETRANDOM
    5.60 +static int
    5.61 +getentropy_linux_getrandom(void *buf, size_t buf_len)
    5.62 +{
    5.63 +	int retval;
    5.64 +
    5.65 +	retval = syscall(SYS_getrandom, buf, buf_len, 0);
    5.66 +	if (retval < 0) {
    5.67 +		return (-1);
    5.68 +	} else if ((size_t)retval != buf_len) {
    5.69 +		errno = EIO;
    5.70 +		return (-1);
    5.71 +	}
    5.72 +
    5.73 +	return (0);
    5.74 +}
    5.75 +#else
    5.76 +static int
    5.77 +getentropy_dev_random(void *buf, size_t buf_len)
    5.78 +{
    5.79 +	FILE	*fp;
    5.80 +	int	saved_errno;
    5.81 +
    5.82 +	fp = fopen(RANDOM_DEVICE, "r");
    5.83 +	if (fp == NULL) {
    5.84 +		return (-1);
    5.85 +	}
    5.86 +	if (fread(buf, 1, buf_len, fp) != buf_len) {
    5.87 +		saved_errno = errno;
    5.88 +		fclose(fp);
    5.89 +		errno = saved_errno;
    5.90 +		return (-1);
    5.91 +	}
    5.92 +	if (fclose(fp) != 0) {
    5.93 +		return (-1);
    5.94 +	}
    5.95 +
    5.96 +	return (0);
    5.97 +}
    5.98 +#endif /* HAVE_GETRANDOM */
    5.99 +
   5.100 +int
   5.101 +getentropy(void *buf, size_t buf_len)
   5.102 +{
   5.103 +	if (buf_len > 256) {
   5.104 +		errno = EIO;
   5.105 +		return (-1);
   5.106 +	}
   5.107 +
   5.108 +	return (
   5.109 +#ifdef	HAVE_GETRANDOM
   5.110 +	    getentropy_linux_getrandom(
   5.111 +#else /* HAVE_GETRANDOM */
   5.112 +	    getentropy_dev_random(
   5.113 +#endif /* HAVE_GETRANDOM */
   5.114 +	    buf, buf_len));
   5.115 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/compat/getentropy.h	Tue Feb 10 11:29:54 2015 +0100
     6.3 @@ -0,0 +1,31 @@
     6.4 +/*
     6.5 + * Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name>
     6.6 + *
     6.7 + * Permission is hereby granted, free of charge, to any person obtaining
     6.8 + * a copy of this software and associated documentation files (the
     6.9 + * "Software"), to deal in the Software without restriction, including
    6.10 + * without limitation the rights to use, copy, modify, merge, publish,
    6.11 + * distribute, sublicense, and/or sell copies of the Software, and to
    6.12 + * permit persons to whom the Software is furnished to do so, subject to
    6.13 + * the following conditions:
    6.14 + *
    6.15 + * The above copyright notice and this permission notice shall be included
    6.16 + * in all copies or substantial portions of the Software.
    6.17 + *
    6.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    6.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    6.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    6.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    6.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    6.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    6.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    6.25 + */
    6.26 +
    6.27 +#ifndef	GETENTROPY_H
    6.28 +#define	GETENTROPY_H
    6.29 +
    6.30 +#include <stddef.h>
    6.31 +
    6.32 +int	getentropy(void *, size_t);
    6.33 +
    6.34 +#endif /* !GETENTROPY_H */
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/compat/pws-compat.h	Tue Feb 10 11:29:54 2015 +0100
     7.3 @@ -0,0 +1,42 @@
     7.4 +/*
     7.5 + * Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name>
     7.6 + *
     7.7 + * Permission is hereby granted, free of charge, to any person obtaining
     7.8 + * a copy of this software and associated documentation files (the
     7.9 + * "Software"), to deal in the Software without restriction, including
    7.10 + * without limitation the rights to use, copy, modify, merge, publish,
    7.11 + * distribute, sublicense, and/or sell copies of the Software, and to
    7.12 + * permit persons to whom the Software is furnished to do so, subject to
    7.13 + * the following conditions:
    7.14 + *
    7.15 + * The above copyright notice and this permission notice shall be included
    7.16 + * in all copies or substantial portions of the Software.
    7.17 + *
    7.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    7.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    7.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    7.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    7.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    7.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    7.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    7.25 + */
    7.26 +
    7.27 +#ifndef	PWS_COMPAT_H
    7.28 +#define	PWS_COMPAT_H
    7.29 +
    7.30 +#if	!defined(HAVE_ENDIAN_H) && !defined(HAVE_SYS_ENDIAN_H)
    7.31 +#define	le16toh		pws_compat_le16toh
    7.32 +#define	htole16		pws_compat_htole16
    7.33 +#define	le32toh		pws_compat_le32toh
    7.34 +#define	htole32		pws_compat_htole32
    7.35 +#define	be16toh		pws_compat_be16toh
    7.36 +#define	htobe16		pws_compat_htobe16
    7.37 +#define	be32toh		pws_compat_be32toh
    7.38 +#define	htobe32		pws_compat_htobe32
    7.39 +#endif /* !defined(HAVE_ENDIAN_H) && !defined(HAVE_SYS_ENDIAN_H) */
    7.40 +
    7.41 +#ifndef	HAVE_GETENTROPY
    7.42 +#define	getentropy	pws_compat_getentropy
    7.43 +#endif /* !HAVE_GETENTROPY */
    7.44 +
    7.45 +#endif /* PWS_COMPAT_H */
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/compat/tree.h	Tue Feb 10 11:29:54 2015 +0100
     8.3 @@ -0,0 +1,748 @@
     8.4 +/*	$OpenBSD: tree.h,v 1.13 2011/07/09 00:19:45 pirofti Exp $	*/
     8.5 +/*
     8.6 + * Copyright 2002 Niels Provos <provos@citi.umich.edu>
     8.7 + * All rights reserved.
     8.8 + *
     8.9 + * Redistribution and use in source and binary forms, with or without
    8.10 + * modification, are permitted provided that the following conditions
    8.11 + * are met:
    8.12 + * 1. Redistributions of source code must retain the above copyright
    8.13 + *    notice, this list of conditions and the following disclaimer.
    8.14 + * 2. Redistributions in binary form must reproduce the above copyright
    8.15 + *    notice, this list of conditions and the following disclaimer in the
    8.16 + *    documentation and/or other materials provided with the distribution.
    8.17 + *
    8.18 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    8.19 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    8.20 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    8.21 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    8.22 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    8.23 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    8.24 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    8.25 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    8.26 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    8.27 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    8.28 + */
    8.29 +
    8.30 +#ifndef	_SYS_TREE_H_
    8.31 +#define	_SYS_TREE_H_
    8.32 +
    8.33 +/*
    8.34 + * This file defines data structures for different types of trees:
    8.35 + * splay trees and red-black trees.
    8.36 + *
    8.37 + * A splay tree is a self-organizing data structure.  Every operation
    8.38 + * on the tree causes a splay to happen.  The splay moves the requested
    8.39 + * node to the root of the tree and partly rebalances it.
    8.40 + *
    8.41 + * This has the benefit that request locality causes faster lookups as
    8.42 + * the requested nodes move to the top of the tree.  On the other hand,
    8.43 + * every lookup causes memory writes.
    8.44 + *
    8.45 + * The Balance Theorem bounds the total access time for m operations
    8.46 + * and n inserts on an initially empty tree as O((m + n)lg n).  The
    8.47 + * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
    8.48 + *
    8.49 + * A red-black tree is a binary search tree with the node color as an
    8.50 + * extra attribute.  It fulfills a set of conditions:
    8.51 + *	- every search path from the root to a leaf consists of the
    8.52 + *	  same number of black nodes,
    8.53 + *	- each red node (except for the root) has a black parent,
    8.54 + *	- each leaf node is black.
    8.55 + *
    8.56 + * Every operation on a red-black tree is bounded as O(lg n).
    8.57 + * The maximum height of a red-black tree is 2lg (n+1).
    8.58 + */
    8.59 +
    8.60 +#define SPLAY_HEAD(name, type)						\
    8.61 +struct name {								\
    8.62 +	struct type *sph_root; /* root of the tree */			\
    8.63 +}
    8.64 +
    8.65 +#define SPLAY_INITIALIZER(root)						\
    8.66 +	{ NULL }
    8.67 +
    8.68 +#define SPLAY_INIT(root) do {						\
    8.69 +	(root)->sph_root = NULL;					\
    8.70 +} while (0)
    8.71 +
    8.72 +#define SPLAY_ENTRY(type)						\
    8.73 +struct {								\
    8.74 +	struct type *spe_left; /* left element */			\
    8.75 +	struct type *spe_right; /* right element */			\
    8.76 +}
    8.77 +
    8.78 +#define SPLAY_LEFT(elm, field)		(elm)->field.spe_left
    8.79 +#define SPLAY_RIGHT(elm, field)		(elm)->field.spe_right
    8.80 +#define SPLAY_ROOT(head)		(head)->sph_root
    8.81 +#define SPLAY_EMPTY(head)		(SPLAY_ROOT(head) == NULL)
    8.82 +
    8.83 +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
    8.84 +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do {			\
    8.85 +	SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field);	\
    8.86 +	SPLAY_RIGHT(tmp, field) = (head)->sph_root;			\
    8.87 +	(head)->sph_root = tmp;						\
    8.88 +} while (0)
    8.89 +	
    8.90 +#define SPLAY_ROTATE_LEFT(head, tmp, field) do {			\
    8.91 +	SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field);	\
    8.92 +	SPLAY_LEFT(tmp, field) = (head)->sph_root;			\
    8.93 +	(head)->sph_root = tmp;						\
    8.94 +} while (0)
    8.95 +
    8.96 +#define SPLAY_LINKLEFT(head, tmp, field) do {				\
    8.97 +	SPLAY_LEFT(tmp, field) = (head)->sph_root;			\
    8.98 +	tmp = (head)->sph_root;						\
    8.99 +	(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);		\
   8.100 +} while (0)
   8.101 +
   8.102 +#define SPLAY_LINKRIGHT(head, tmp, field) do {				\
   8.103 +	SPLAY_RIGHT(tmp, field) = (head)->sph_root;			\
   8.104 +	tmp = (head)->sph_root;						\
   8.105 +	(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);	\
   8.106 +} while (0)
   8.107 +
   8.108 +#define SPLAY_ASSEMBLE(head, node, left, right, field) do {		\
   8.109 +	SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field);	\
   8.110 +	SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
   8.111 +	SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field);	\
   8.112 +	SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field);	\
   8.113 +} while (0)
   8.114 +
   8.115 +/* Generates prototypes and inline functions */
   8.116 +
   8.117 +#define SPLAY_PROTOTYPE(name, type, field, cmp)				\
   8.118 +void name##_SPLAY(struct name *, struct type *);			\
   8.119 +void name##_SPLAY_MINMAX(struct name *, int);				\
   8.120 +struct type *name##_SPLAY_INSERT(struct name *, struct type *);		\
   8.121 +struct type *name##_SPLAY_REMOVE(struct name *, struct type *);		\
   8.122 +									\
   8.123 +/* Finds the node with the same key as elm */				\
   8.124 +static __inline struct type *						\
   8.125 +name##_SPLAY_FIND(struct name *head, struct type *elm)			\
   8.126 +{									\
   8.127 +	if (SPLAY_EMPTY(head))						\
   8.128 +		return(NULL);						\
   8.129 +	name##_SPLAY(head, elm);					\
   8.130 +	if ((cmp)(elm, (head)->sph_root) == 0)				\
   8.131 +		return (head->sph_root);				\
   8.132 +	return (NULL);							\
   8.133 +}									\
   8.134 +									\
   8.135 +static __inline struct type *						\
   8.136 +name##_SPLAY_NEXT(struct name *head, struct type *elm)			\
   8.137 +{									\
   8.138 +	name##_SPLAY(head, elm);					\
   8.139 +	if (SPLAY_RIGHT(elm, field) != NULL) {				\
   8.140 +		elm = SPLAY_RIGHT(elm, field);				\
   8.141 +		while (SPLAY_LEFT(elm, field) != NULL) {		\
   8.142 +			elm = SPLAY_LEFT(elm, field);			\
   8.143 +		}							\
   8.144 +	} else								\
   8.145 +		elm = NULL;						\
   8.146 +	return (elm);							\
   8.147 +}									\
   8.148 +									\
   8.149 +static __inline struct type *						\
   8.150 +name##_SPLAY_MIN_MAX(struct name *head, int val)			\
   8.151 +{									\
   8.152 +	name##_SPLAY_MINMAX(head, val);					\
   8.153 +        return (SPLAY_ROOT(head));					\
   8.154 +}
   8.155 +
   8.156 +/* Main splay operation.
   8.157 + * Moves node close to the key of elm to top
   8.158 + */
   8.159 +#define SPLAY_GENERATE(name, type, field, cmp)				\
   8.160 +struct type *								\
   8.161 +name##_SPLAY_INSERT(struct name *head, struct type *elm)		\
   8.162 +{									\
   8.163 +    if (SPLAY_EMPTY(head)) {						\
   8.164 +	    SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL;	\
   8.165 +    } else {								\
   8.166 +	    int __comp;							\
   8.167 +	    name##_SPLAY(head, elm);					\
   8.168 +	    __comp = (cmp)(elm, (head)->sph_root);			\
   8.169 +	    if(__comp < 0) {						\
   8.170 +		    SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
   8.171 +		    SPLAY_RIGHT(elm, field) = (head)->sph_root;		\
   8.172 +		    SPLAY_LEFT((head)->sph_root, field) = NULL;		\
   8.173 +	    } else if (__comp > 0) {					\
   8.174 +		    SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
   8.175 +		    SPLAY_LEFT(elm, field) = (head)->sph_root;		\
   8.176 +		    SPLAY_RIGHT((head)->sph_root, field) = NULL;	\
   8.177 +	    } else							\
   8.178 +		    return ((head)->sph_root);				\
   8.179 +    }									\
   8.180 +    (head)->sph_root = (elm);						\
   8.181 +    return (NULL);							\
   8.182 +}									\
   8.183 +									\
   8.184 +struct type *								\
   8.185 +name##_SPLAY_REMOVE(struct name *head, struct type *elm)		\
   8.186 +{									\
   8.187 +	struct type *__tmp;						\
   8.188 +	if (SPLAY_EMPTY(head))						\
   8.189 +		return (NULL);						\
   8.190 +	name##_SPLAY(head, elm);					\
   8.191 +	if ((cmp)(elm, (head)->sph_root) == 0) {			\
   8.192 +		if (SPLAY_LEFT((head)->sph_root, field) == NULL) {	\
   8.193 +			(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
   8.194 +		} else {						\
   8.195 +			__tmp = SPLAY_RIGHT((head)->sph_root, field);	\
   8.196 +			(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
   8.197 +			name##_SPLAY(head, elm);			\
   8.198 +			SPLAY_RIGHT((head)->sph_root, field) = __tmp;	\
   8.199 +		}							\
   8.200 +		return (elm);						\
   8.201 +	}								\
   8.202 +	return (NULL);							\
   8.203 +}									\
   8.204 +									\
   8.205 +void									\
   8.206 +name##_SPLAY(struct name *head, struct type *elm)			\
   8.207 +{									\
   8.208 +	struct type __node, *__left, *__right, *__tmp;			\
   8.209 +	int __comp;							\
   8.210 +\
   8.211 +	SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
   8.212 +	__left = __right = &__node;					\
   8.213 +\
   8.214 +	while ((__comp = (cmp)(elm, (head)->sph_root))) {		\
   8.215 +		if (__comp < 0) {					\
   8.216 +			__tmp = SPLAY_LEFT((head)->sph_root, field);	\
   8.217 +			if (__tmp == NULL)				\
   8.218 +				break;					\
   8.219 +			if ((cmp)(elm, __tmp) < 0){			\
   8.220 +				SPLAY_ROTATE_RIGHT(head, __tmp, field);	\
   8.221 +				if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
   8.222 +					break;				\
   8.223 +			}						\
   8.224 +			SPLAY_LINKLEFT(head, __right, field);		\
   8.225 +		} else if (__comp > 0) {				\
   8.226 +			__tmp = SPLAY_RIGHT((head)->sph_root, field);	\
   8.227 +			if (__tmp == NULL)				\
   8.228 +				break;					\
   8.229 +			if ((cmp)(elm, __tmp) > 0){			\
   8.230 +				SPLAY_ROTATE_LEFT(head, __tmp, field);	\
   8.231 +				if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
   8.232 +					break;				\
   8.233 +			}						\
   8.234 +			SPLAY_LINKRIGHT(head, __left, field);		\
   8.235 +		}							\
   8.236 +	}								\
   8.237 +	SPLAY_ASSEMBLE(head, &__node, __left, __right, field);		\
   8.238 +}									\
   8.239 +									\
   8.240 +/* Splay with either the minimum or the maximum element			\
   8.241 + * Used to find minimum or maximum element in tree.			\
   8.242 + */									\
   8.243 +void name##_SPLAY_MINMAX(struct name *head, int __comp) \
   8.244 +{									\
   8.245 +	struct type __node, *__left, *__right, *__tmp;			\
   8.246 +\
   8.247 +	SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
   8.248 +	__left = __right = &__node;					\
   8.249 +\
   8.250 +	while (1) {							\
   8.251 +		if (__comp < 0) {					\
   8.252 +			__tmp = SPLAY_LEFT((head)->sph_root, field);	\
   8.253 +			if (__tmp == NULL)				\
   8.254 +				break;					\
   8.255 +			if (__comp < 0){				\
   8.256 +				SPLAY_ROTATE_RIGHT(head, __tmp, field);	\
   8.257 +				if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
   8.258 +					break;				\
   8.259 +			}						\
   8.260 +			SPLAY_LINKLEFT(head, __right, field);		\
   8.261 +		} else if (__comp > 0) {				\
   8.262 +			__tmp = SPLAY_RIGHT((head)->sph_root, field);	\
   8.263 +			if (__tmp == NULL)				\
   8.264 +				break;					\
   8.265 +			if (__comp > 0) {				\
   8.266 +				SPLAY_ROTATE_LEFT(head, __tmp, field);	\
   8.267 +				if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
   8.268 +					break;				\
   8.269 +			}						\
   8.270 +			SPLAY_LINKRIGHT(head, __left, field);		\
   8.271 +		}							\
   8.272 +	}								\
   8.273 +	SPLAY_ASSEMBLE(head, &__node, __left, __right, field);		\
   8.274 +}
   8.275 +
   8.276 +#define SPLAY_NEGINF	-1
   8.277 +#define SPLAY_INF	1
   8.278 +
   8.279 +#define SPLAY_INSERT(name, x, y)	name##_SPLAY_INSERT(x, y)
   8.280 +#define SPLAY_REMOVE(name, x, y)	name##_SPLAY_REMOVE(x, y)
   8.281 +#define SPLAY_FIND(name, x, y)		name##_SPLAY_FIND(x, y)
   8.282 +#define SPLAY_NEXT(name, x, y)		name##_SPLAY_NEXT(x, y)
   8.283 +#define SPLAY_MIN(name, x)		(SPLAY_EMPTY(x) ? NULL	\
   8.284 +					: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
   8.285 +#define SPLAY_MAX(name, x)		(SPLAY_EMPTY(x) ? NULL	\
   8.286 +					: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
   8.287 +
   8.288 +#define SPLAY_FOREACH(x, name, head)					\
   8.289 +	for ((x) = SPLAY_MIN(name, head);				\
   8.290 +	     (x) != NULL;						\
   8.291 +	     (x) = SPLAY_NEXT(name, head, x))
   8.292 +
   8.293 +/* Macros that define a red-black tree */
   8.294 +#define RB_HEAD(name, type)						\
   8.295 +struct name {								\
   8.296 +	struct type *rbh_root; /* root of the tree */			\
   8.297 +}
   8.298 +
   8.299 +#define RB_INITIALIZER(root)						\
   8.300 +	{ NULL }
   8.301 +
   8.302 +#define RB_INIT(root) do {						\
   8.303 +	(root)->rbh_root = NULL;					\
   8.304 +} while (0)
   8.305 +
   8.306 +#define RB_BLACK	0
   8.307 +#define RB_RED		1
   8.308 +#define RB_ENTRY(type)							\
   8.309 +struct {								\
   8.310 +	struct type *rbe_left;		/* left element */		\
   8.311 +	struct type *rbe_right;		/* right element */		\
   8.312 +	struct type *rbe_parent;	/* parent element */		\
   8.313 +	int rbe_color;			/* node color */		\
   8.314 +}
   8.315 +
   8.316 +#define RB_LEFT(elm, field)		(elm)->field.rbe_left
   8.317 +#define RB_RIGHT(elm, field)		(elm)->field.rbe_right
   8.318 +#define RB_PARENT(elm, field)		(elm)->field.rbe_parent
   8.319 +#define RB_COLOR(elm, field)		(elm)->field.rbe_color
   8.320 +#define RB_ROOT(head)			(head)->rbh_root
   8.321 +#define RB_EMPTY(head)			(RB_ROOT(head) == NULL)
   8.322 +
   8.323 +#define RB_SET(elm, parent, field) do {					\
   8.324 +	RB_PARENT(elm, field) = parent;					\
   8.325 +	RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL;		\
   8.326 +	RB_COLOR(elm, field) = RB_RED;					\
   8.327 +} while (0)
   8.328 +
   8.329 +#define RB_SET_BLACKRED(black, red, field) do {				\
   8.330 +	RB_COLOR(black, field) = RB_BLACK;				\
   8.331 +	RB_COLOR(red, field) = RB_RED;					\
   8.332 +} while (0)
   8.333 +
   8.334 +#ifndef RB_AUGMENT
   8.335 +#define RB_AUGMENT(x)	do {} while (0)
   8.336 +#endif
   8.337 +
   8.338 +#define RB_ROTATE_LEFT(head, elm, tmp, field) do {			\
   8.339 +	(tmp) = RB_RIGHT(elm, field);					\
   8.340 +	if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) {		\
   8.341 +		RB_PARENT(RB_LEFT(tmp, field), field) = (elm);		\
   8.342 +	}								\
   8.343 +	RB_AUGMENT(elm);						\
   8.344 +	if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) {		\
   8.345 +		if ((elm) == RB_LEFT(RB_PARENT(elm, field), field))	\
   8.346 +			RB_LEFT(RB_PARENT(elm, field), field) = (tmp);	\
   8.347 +		else							\
   8.348 +			RB_RIGHT(RB_PARENT(elm, field), field) = (tmp);	\
   8.349 +	} else								\
   8.350 +		(head)->rbh_root = (tmp);				\
   8.351 +	RB_LEFT(tmp, field) = (elm);					\
   8.352 +	RB_PARENT(elm, field) = (tmp);					\
   8.353 +	RB_AUGMENT(tmp);						\
   8.354 +	if ((RB_PARENT(tmp, field)))					\
   8.355 +		RB_AUGMENT(RB_PARENT(tmp, field));			\
   8.356 +} while (0)
   8.357 +
   8.358 +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do {			\
   8.359 +	(tmp) = RB_LEFT(elm, field);					\
   8.360 +	if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) {		\
   8.361 +		RB_PARENT(RB_RIGHT(tmp, field), field) = (elm);		\
   8.362 +	}								\
   8.363 +	RB_AUGMENT(elm);						\
   8.364 +	if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) {		\
   8.365 +		if ((elm) == RB_LEFT(RB_PARENT(elm, field), field))	\
   8.366 +			RB_LEFT(RB_PARENT(elm, field), field) = (tmp);	\
   8.367 +		else							\
   8.368 +			RB_RIGHT(RB_PARENT(elm, field), field) = (tmp);	\
   8.369 +	} else								\
   8.370 +		(head)->rbh_root = (tmp);				\
   8.371 +	RB_RIGHT(tmp, field) = (elm);					\
   8.372 +	RB_PARENT(elm, field) = (tmp);					\
   8.373 +	RB_AUGMENT(tmp);						\
   8.374 +	if ((RB_PARENT(tmp, field)))					\
   8.375 +		RB_AUGMENT(RB_PARENT(tmp, field));			\
   8.376 +} while (0)
   8.377 +
   8.378 +/* Generates prototypes and inline functions */
   8.379 +#define	RB_PROTOTYPE(name, type, field, cmp)				\
   8.380 +	RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
   8.381 +#define	RB_PROTOTYPE_STATIC(name, type, field, cmp)			\
   8.382 +	RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static)
   8.383 +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr)		\
   8.384 +attr void name##_RB_INSERT_COLOR(struct name *, struct type *);		\
   8.385 +attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
   8.386 +attr struct type *name##_RB_REMOVE(struct name *, struct type *);	\
   8.387 +attr struct type *name##_RB_INSERT(struct name *, struct type *);	\
   8.388 +attr struct type *name##_RB_FIND(struct name *, struct type *);		\
   8.389 +attr struct type *name##_RB_NFIND(struct name *, struct type *);	\
   8.390 +attr struct type *name##_RB_NEXT(struct type *);			\
   8.391 +attr struct type *name##_RB_PREV(struct type *);			\
   8.392 +attr struct type *name##_RB_MINMAX(struct name *, int);			\
   8.393 +									\
   8.394 +
   8.395 +/* Main rb operation.
   8.396 + * Moves node close to the key of elm to top
   8.397 + */
   8.398 +#define	RB_GENERATE(name, type, field, cmp)				\
   8.399 +	RB_GENERATE_INTERNAL(name, type, field, cmp,)
   8.400 +#define	RB_GENERATE_STATIC(name, type, field, cmp)			\
   8.401 +	RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static)
   8.402 +#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr)		\
   8.403 +attr void								\
   8.404 +name##_RB_INSERT_COLOR(struct name *head, struct type *elm)		\
   8.405 +{									\
   8.406 +	struct type *parent, *gparent, *tmp;				\
   8.407 +	while ((parent = RB_PARENT(elm, field)) &&			\
   8.408 +	    RB_COLOR(parent, field) == RB_RED) {			\
   8.409 +		gparent = RB_PARENT(parent, field);			\
   8.410 +		if (parent == RB_LEFT(gparent, field)) {		\
   8.411 +			tmp = RB_RIGHT(gparent, field);			\
   8.412 +			if (tmp && RB_COLOR(tmp, field) == RB_RED) {	\
   8.413 +				RB_COLOR(tmp, field) = RB_BLACK;	\
   8.414 +				RB_SET_BLACKRED(parent, gparent, field);\
   8.415 +				elm = gparent;				\
   8.416 +				continue;				\
   8.417 +			}						\
   8.418 +			if (RB_RIGHT(parent, field) == elm) {		\
   8.419 +				RB_ROTATE_LEFT(head, parent, tmp, field);\
   8.420 +				tmp = parent;				\
   8.421 +				parent = elm;				\
   8.422 +				elm = tmp;				\
   8.423 +			}						\
   8.424 +			RB_SET_BLACKRED(parent, gparent, field);	\
   8.425 +			RB_ROTATE_RIGHT(head, gparent, tmp, field);	\
   8.426 +		} else {						\
   8.427 +			tmp = RB_LEFT(gparent, field);			\
   8.428 +			if (tmp && RB_COLOR(tmp, field) == RB_RED) {	\
   8.429 +				RB_COLOR(tmp, field) = RB_BLACK;	\
   8.430 +				RB_SET_BLACKRED(parent, gparent, field);\
   8.431 +				elm = gparent;				\
   8.432 +				continue;				\
   8.433 +			}						\
   8.434 +			if (RB_LEFT(parent, field) == elm) {		\
   8.435 +				RB_ROTATE_RIGHT(head, parent, tmp, field);\
   8.436 +				tmp = parent;				\
   8.437 +				parent = elm;				\
   8.438 +				elm = tmp;				\
   8.439 +			}						\
   8.440 +			RB_SET_BLACKRED(parent, gparent, field);	\
   8.441 +			RB_ROTATE_LEFT(head, gparent, tmp, field);	\
   8.442 +		}							\
   8.443 +	}								\
   8.444 +	RB_COLOR(head->rbh_root, field) = RB_BLACK;			\
   8.445 +}									\
   8.446 +									\
   8.447 +attr void								\
   8.448 +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
   8.449 +{									\
   8.450 +	struct type *tmp;						\
   8.451 +	while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) &&	\
   8.452 +	    elm != RB_ROOT(head)) {					\
   8.453 +		if (RB_LEFT(parent, field) == elm) {			\
   8.454 +			tmp = RB_RIGHT(parent, field);			\
   8.455 +			if (RB_COLOR(tmp, field) == RB_RED) {		\
   8.456 +				RB_SET_BLACKRED(tmp, parent, field);	\
   8.457 +				RB_ROTATE_LEFT(head, parent, tmp, field);\
   8.458 +				tmp = RB_RIGHT(parent, field);		\
   8.459 +			}						\
   8.460 +			if ((RB_LEFT(tmp, field) == NULL ||		\
   8.461 +			    RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
   8.462 +			    (RB_RIGHT(tmp, field) == NULL ||		\
   8.463 +			    RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
   8.464 +				RB_COLOR(tmp, field) = RB_RED;		\
   8.465 +				elm = parent;				\
   8.466 +				parent = RB_PARENT(elm, field);		\
   8.467 +			} else {					\
   8.468 +				if (RB_RIGHT(tmp, field) == NULL ||	\
   8.469 +				    RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
   8.470 +					struct type *oleft;		\
   8.471 +					if ((oleft = RB_LEFT(tmp, field)))\
   8.472 +						RB_COLOR(oleft, field) = RB_BLACK;\
   8.473 +					RB_COLOR(tmp, field) = RB_RED;	\
   8.474 +					RB_ROTATE_RIGHT(head, tmp, oleft, field);\
   8.475 +					tmp = RB_RIGHT(parent, field);	\
   8.476 +				}					\
   8.477 +				RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
   8.478 +				RB_COLOR(parent, field) = RB_BLACK;	\
   8.479 +				if (RB_RIGHT(tmp, field))		\
   8.480 +					RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
   8.481 +				RB_ROTATE_LEFT(head, parent, tmp, field);\
   8.482 +				elm = RB_ROOT(head);			\
   8.483 +				break;					\
   8.484 +			}						\
   8.485 +		} else {						\
   8.486 +			tmp = RB_LEFT(parent, field);			\
   8.487 +			if (RB_COLOR(tmp, field) == RB_RED) {		\
   8.488 +				RB_SET_BLACKRED(tmp, parent, field);	\
   8.489 +				RB_ROTATE_RIGHT(head, parent, tmp, field);\
   8.490 +				tmp = RB_LEFT(parent, field);		\
   8.491 +			}						\
   8.492 +			if ((RB_LEFT(tmp, field) == NULL ||		\
   8.493 +			    RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
   8.494 +			    (RB_RIGHT(tmp, field) == NULL ||		\
   8.495 +			    RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
   8.496 +				RB_COLOR(tmp, field) = RB_RED;		\
   8.497 +				elm = parent;				\
   8.498 +				parent = RB_PARENT(elm, field);		\
   8.499 +			} else {					\
   8.500 +				if (RB_LEFT(tmp, field) == NULL ||	\
   8.501 +				    RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
   8.502 +					struct type *oright;		\
   8.503 +					if ((oright = RB_RIGHT(tmp, field)))\
   8.504 +						RB_COLOR(oright, field) = RB_BLACK;\
   8.505 +					RB_COLOR(tmp, field) = RB_RED;	\
   8.506 +					RB_ROTATE_LEFT(head, tmp, oright, field);\
   8.507 +					tmp = RB_LEFT(parent, field);	\
   8.508 +				}					\
   8.509 +				RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
   8.510 +				RB_COLOR(parent, field) = RB_BLACK;	\
   8.511 +				if (RB_LEFT(tmp, field))		\
   8.512 +					RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
   8.513 +				RB_ROTATE_RIGHT(head, parent, tmp, field);\
   8.514 +				elm = RB_ROOT(head);			\
   8.515 +				break;					\
   8.516 +			}						\
   8.517 +		}							\
   8.518 +	}								\
   8.519 +	if (elm)							\
   8.520 +		RB_COLOR(elm, field) = RB_BLACK;			\
   8.521 +}									\
   8.522 +									\
   8.523 +attr struct type *							\
   8.524 +name##_RB_REMOVE(struct name *head, struct type *elm)			\
   8.525 +{									\
   8.526 +	struct type *child, *parent, *old = elm;			\
   8.527 +	int color;							\
   8.528 +	if (RB_LEFT(elm, field) == NULL)				\
   8.529 +		child = RB_RIGHT(elm, field);				\
   8.530 +	else if (RB_RIGHT(elm, field) == NULL)				\
   8.531 +		child = RB_LEFT(elm, field);				\
   8.532 +	else {								\
   8.533 +		struct type *left;					\
   8.534 +		elm = RB_RIGHT(elm, field);				\
   8.535 +		while ((left = RB_LEFT(elm, field)))			\
   8.536 +			elm = left;					\
   8.537 +		child = RB_RIGHT(elm, field);				\
   8.538 +		parent = RB_PARENT(elm, field);				\
   8.539 +		color = RB_COLOR(elm, field);				\
   8.540 +		if (child)						\
   8.541 +			RB_PARENT(child, field) = parent;		\
   8.542 +		if (parent) {						\
   8.543 +			if (RB_LEFT(parent, field) == elm)		\
   8.544 +				RB_LEFT(parent, field) = child;		\
   8.545 +			else						\
   8.546 +				RB_RIGHT(parent, field) = child;	\
   8.547 +			RB_AUGMENT(parent);				\
   8.548 +		} else							\
   8.549 +			RB_ROOT(head) = child;				\
   8.550 +		if (RB_PARENT(elm, field) == old)			\
   8.551 +			parent = elm;					\
   8.552 +		(elm)->field = (old)->field;				\
   8.553 +		if (RB_PARENT(old, field)) {				\
   8.554 +			if (RB_LEFT(RB_PARENT(old, field), field) == old)\
   8.555 +				RB_LEFT(RB_PARENT(old, field), field) = elm;\
   8.556 +			else						\
   8.557 +				RB_RIGHT(RB_PARENT(old, field), field) = elm;\
   8.558 +			RB_AUGMENT(RB_PARENT(old, field));		\
   8.559 +		} else							\
   8.560 +			RB_ROOT(head) = elm;				\
   8.561 +		RB_PARENT(RB_LEFT(old, field), field) = elm;		\
   8.562 +		if (RB_RIGHT(old, field))				\
   8.563 +			RB_PARENT(RB_RIGHT(old, field), field) = elm;	\
   8.564 +		if (parent) {						\
   8.565 +			left = parent;					\
   8.566 +			do {						\
   8.567 +				RB_AUGMENT(left);			\
   8.568 +			} while ((left = RB_PARENT(left, field)));	\
   8.569 +		}							\
   8.570 +		goto color;						\
   8.571 +	}								\
   8.572 +	parent = RB_PARENT(elm, field);					\
   8.573 +	color = RB_COLOR(elm, field);					\
   8.574 +	if (child)							\
   8.575 +		RB_PARENT(child, field) = parent;			\
   8.576 +	if (parent) {							\
   8.577 +		if (RB_LEFT(parent, field) == elm)			\
   8.578 +			RB_LEFT(parent, field) = child;			\
   8.579 +		else							\
   8.580 +			RB_RIGHT(parent, field) = child;		\
   8.581 +		RB_AUGMENT(parent);					\
   8.582 +	} else								\
   8.583 +		RB_ROOT(head) = child;					\
   8.584 +color:									\
   8.585 +	if (color == RB_BLACK)						\
   8.586 +		name##_RB_REMOVE_COLOR(head, parent, child);		\
   8.587 +	return (old);							\
   8.588 +}									\
   8.589 +									\
   8.590 +/* Inserts a node into the RB tree */					\
   8.591 +attr struct type *							\
   8.592 +name##_RB_INSERT(struct name *head, struct type *elm)			\
   8.593 +{									\
   8.594 +	struct type *tmp;						\
   8.595 +	struct type *parent = NULL;					\
   8.596 +	int comp = 0;							\
   8.597 +	tmp = RB_ROOT(head);						\
   8.598 +	while (tmp) {							\
   8.599 +		parent = tmp;						\
   8.600 +		comp = (cmp)(elm, parent);				\
   8.601 +		if (comp < 0)						\
   8.602 +			tmp = RB_LEFT(tmp, field);			\
   8.603 +		else if (comp > 0)					\
   8.604 +			tmp = RB_RIGHT(tmp, field);			\
   8.605 +		else							\
   8.606 +			return (tmp);					\
   8.607 +	}								\
   8.608 +	RB_SET(elm, parent, field);					\
   8.609 +	if (parent != NULL) {						\
   8.610 +		if (comp < 0)						\
   8.611 +			RB_LEFT(parent, field) = elm;			\
   8.612 +		else							\
   8.613 +			RB_RIGHT(parent, field) = elm;			\
   8.614 +		RB_AUGMENT(parent);					\
   8.615 +	} else								\
   8.616 +		RB_ROOT(head) = elm;					\
   8.617 +	name##_RB_INSERT_COLOR(head, elm);				\
   8.618 +	return (NULL);							\
   8.619 +}									\
   8.620 +									\
   8.621 +/* Finds the node with the same key as elm */				\
   8.622 +attr struct type *							\
   8.623 +name##_RB_FIND(struct name *head, struct type *elm)			\
   8.624 +{									\
   8.625 +	struct type *tmp = RB_ROOT(head);				\
   8.626 +	int comp;							\
   8.627 +	while (tmp) {							\
   8.628 +		comp = cmp(elm, tmp);					\
   8.629 +		if (comp < 0)						\
   8.630 +			tmp = RB_LEFT(tmp, field);			\
   8.631 +		else if (comp > 0)					\
   8.632 +			tmp = RB_RIGHT(tmp, field);			\
   8.633 +		else							\
   8.634 +			return (tmp);					\
   8.635 +	}								\
   8.636 +	return (NULL);							\
   8.637 +}									\
   8.638 +									\
   8.639 +/* Finds the first node greater than or equal to the search key */	\
   8.640 +attr struct type *							\
   8.641 +name##_RB_NFIND(struct name *head, struct type *elm)			\
   8.642 +{									\
   8.643 +	struct type *tmp = RB_ROOT(head);				\
   8.644 +	struct type *res = NULL;					\
   8.645 +	int comp;							\
   8.646 +	while (tmp) {							\
   8.647 +		comp = cmp(elm, tmp);					\
   8.648 +		if (comp < 0) {						\
   8.649 +			res = tmp;					\
   8.650 +			tmp = RB_LEFT(tmp, field);			\
   8.651 +		}							\
   8.652 +		else if (comp > 0)					\
   8.653 +			tmp = RB_RIGHT(tmp, field);			\
   8.654 +		else							\
   8.655 +			return (tmp);					\
   8.656 +	}								\
   8.657 +	return (res);							\
   8.658 +}									\
   8.659 +									\
   8.660 +/* ARGSUSED */								\
   8.661 +attr struct type *							\
   8.662 +name##_RB_NEXT(struct type *elm)					\
   8.663 +{									\
   8.664 +	if (RB_RIGHT(elm, field)) {					\
   8.665 +		elm = RB_RIGHT(elm, field);				\
   8.666 +		while (RB_LEFT(elm, field))				\
   8.667 +			elm = RB_LEFT(elm, field);			\
   8.668 +	} else {							\
   8.669 +		if (RB_PARENT(elm, field) &&				\
   8.670 +		    (elm == RB_LEFT(RB_PARENT(elm, field), field)))	\
   8.671 +			elm = RB_PARENT(elm, field);			\
   8.672 +		else {							\
   8.673 +			while (RB_PARENT(elm, field) &&			\
   8.674 +			    (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
   8.675 +				elm = RB_PARENT(elm, field);		\
   8.676 +			elm = RB_PARENT(elm, field);			\
   8.677 +		}							\
   8.678 +	}								\
   8.679 +	return (elm);							\
   8.680 +}									\
   8.681 +									\
   8.682 +/* ARGSUSED */								\
   8.683 +attr struct type *							\
   8.684 +name##_RB_PREV(struct type *elm)					\
   8.685 +{									\
   8.686 +	if (RB_LEFT(elm, field)) {					\
   8.687 +		elm = RB_LEFT(elm, field);				\
   8.688 +		while (RB_RIGHT(elm, field))				\
   8.689 +			elm = RB_RIGHT(elm, field);			\
   8.690 +	} else {							\
   8.691 +		if (RB_PARENT(elm, field) &&				\
   8.692 +		    (elm == RB_RIGHT(RB_PARENT(elm, field), field)))	\
   8.693 +			elm = RB_PARENT(elm, field);			\
   8.694 +		else {							\
   8.695 +			while (RB_PARENT(elm, field) &&			\
   8.696 +			    (elm == RB_LEFT(RB_PARENT(elm, field), field)))\
   8.697 +				elm = RB_PARENT(elm, field);		\
   8.698 +			elm = RB_PARENT(elm, field);			\
   8.699 +		}							\
   8.700 +	}								\
   8.701 +	return (elm);							\
   8.702 +}									\
   8.703 +									\
   8.704 +attr struct type *							\
   8.705 +name##_RB_MINMAX(struct name *head, int val)				\
   8.706 +{									\
   8.707 +	struct type *tmp = RB_ROOT(head);				\
   8.708 +	struct type *parent = NULL;					\
   8.709 +	while (tmp) {							\
   8.710 +		parent = tmp;						\
   8.711 +		if (val < 0)						\
   8.712 +			tmp = RB_LEFT(tmp, field);			\
   8.713 +		else							\
   8.714 +			tmp = RB_RIGHT(tmp, field);			\
   8.715 +	}								\
   8.716 +	return (parent);						\
   8.717 +}
   8.718 +
   8.719 +#define RB_NEGINF	-1
   8.720 +#define RB_INF	1
   8.721 +
   8.722 +#define RB_INSERT(name, x, y)	name##_RB_INSERT(x, y)
   8.723 +#define RB_REMOVE(name, x, y)	name##_RB_REMOVE(x, y)
   8.724 +#define RB_FIND(name, x, y)	name##_RB_FIND(x, y)
   8.725 +#define RB_NFIND(name, x, y)	name##_RB_NFIND(x, y)
   8.726 +#define RB_NEXT(name, x, y)	name##_RB_NEXT(y)
   8.727 +#define RB_PREV(name, x, y)	name##_RB_PREV(y)
   8.728 +#define RB_MIN(name, x)		name##_RB_MINMAX(x, RB_NEGINF)
   8.729 +#define RB_MAX(name, x)		name##_RB_MINMAX(x, RB_INF)
   8.730 +
   8.731 +#define RB_FOREACH(x, name, head)					\
   8.732 +	for ((x) = RB_MIN(name, head);					\
   8.733 +	     (x) != NULL;						\
   8.734 +	     (x) = name##_RB_NEXT(x))
   8.735 +
   8.736 +#define RB_FOREACH_SAFE(x, name, head, y)				\
   8.737 +	for ((x) = RB_MIN(name, head);					\
   8.738 +	    ((x) != NULL) && ((y) = name##_RB_NEXT(x), 1);		\
   8.739 +	     (x) = (y))
   8.740 +
   8.741 +#define RB_FOREACH_REVERSE(x, name, head)				\
   8.742 +	for ((x) = RB_MAX(name, head);					\
   8.743 +	     (x) != NULL;						\
   8.744 +	     (x) = name##_RB_PREV(x))
   8.745 +
   8.746 +#define RB_FOREACH_REVERSE_SAFE(x, name, head, y)			\
   8.747 +	for ((x) = RB_MAX(name, head);					\
   8.748 +	    ((x) != NULL) && ((y) = name##_RB_PREV(x), 1);		\
   8.749 +	     (x) = (y))
   8.750 +
   8.751 +#endif	/* _SYS_TREE_H_ */
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/deps.sed	Tue Feb 10 11:29:54 2015 +0100
     9.3 @@ -0,0 +1,26 @@
     9.4 +/^[^:]\{1,\}:.*\\$/{
     9.5 +    h
     9.6 +    s/\([^:]\{1,\}:\).*/\1/
     9.7 +    x
     9.8 +    s/[^:]\{1,\}://
     9.9 +}
    9.10 +/\\$/,/^$/bgen
    9.11 +/\\$/,/[^\\]$/{
    9.12 +:gen
    9.13 +    s/[[:blank:]]*\\$//
    9.14 +    s/^[[:blank:]]*//
    9.15 +    G
    9.16 +    s/\(.*\)\n\(.*\)/\2 \1/
    9.17 +}
    9.18 +/^[^:]\{1,\}:[[:blank:]]*$/d
    9.19 +/^[^:]\{1,\}\.o:/{
    9.20 +    s/[[:blank:]]*[^[:blank:]]\{1,\}\.[cC][[:blank:]]*/ /g
    9.21 +    s/[[:blank:]]*[^[:blank:]]\{1,\}\.[cC]$//g
    9.22 +    s/[[:blank:]]*[^[:blank:]]\{1,\}\.cc[[:blank:]]*/ /g
    9.23 +    s/[[:blank:]]*[^[:blank:]]\{1,\}\.cc$//g
    9.24 +    s/[[:blank:]]*[^[:blank:]]\{1,\}\.cpp[[:blank:]]*/ /g
    9.25 +    s/[[:blank:]]*[^[:blank:]]\{1,\}\.cpp$//g
    9.26 +    /^[^:]\{1,\}:[[:blank:]]*$/d
    9.27 +    s/^\([^:]\{1,\}\)\.o[[:blank:]]*:[[:blank:]]*\(.*\)/\1.d: $(wildcard \2)\
    9.28 +&/
    9.29 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/include/pws.h	Tue Feb 10 11:29:54 2015 +0100
    10.3 @@ -0,0 +1,205 @@
    10.4 +/*
    10.5 + * Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name>
    10.6 + *
    10.7 + * Permission is hereby granted, free of charge, to any person obtaining
    10.8 + * a copy of this software and associated documentation files (the
    10.9 + * "Software"), to deal in the Software without restriction, including
   10.10 + * without limitation the rights to use, copy, modify, merge, publish,
   10.11 + * distribute, sublicense, and/or sell copies of the Software, and to
   10.12 + * permit persons to whom the Software is furnished to do so, subject to
   10.13 + * the following conditions:
   10.14 + *
   10.15 + * The above copyright notice and this permission notice shall be included
   10.16 + * in all copies or substantial portions of the Software.
   10.17 + *
   10.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   10.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   10.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   10.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   10.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   10.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   10.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   10.25 + */
   10.26 +
   10.27 +#ifndef	PWS_H
   10.28 +#define	PWS_H
   10.29 +
   10.30 +#ifdef __cplusplus
   10.31 +extern "C" {
   10.32 +#endif /* __cplusplus */
   10.33 +
   10.34 +#include <stdint.h>
   10.35 +#include <sys/types.h>
   10.36 +#include <stdio.h>
   10.37 +
   10.38 +#define	LIBPWS_VERSION_MAJOR	1
   10.39 +#define	LIBPWS_VERSION_MINOR	0
   10.40 +#define	LIBPWS_VERSION_MICRO	0
   10.41 +
   10.42 +#define	PWS3_VERSION		0x030D
   10.43 +
   10.44 +#define	PWS3_MAX_FIELD_SIZE	(16 * 1024)
   10.45 +#define	PWS3_MAX_PASSWORD_LEN	1023
   10.46 +#define	PWS3_UUID_SIZE		16
   10.47 +
   10.48 +struct pws3_field;
   10.49 +struct pws3_record;
   10.50 +struct pws3_file;
   10.51 +
   10.52 +enum pws_error_code {
   10.53 +	PWS_ERR_GENERIC_ERROR,
   10.54 +	PWS_ERR_NO_MEMORY,
   10.55 +	PWS_ERR_IO_ERROR,
   10.56 +	PWS_ERR_TRUNCATED_FILE,
   10.57 +	PWS_ERR_INVALID_CHECKSUM,
   10.58 +	PWS_ERR_INVALID_RECORD,
   10.59 +	PWS_ERR_INVALID_HEADER,
   10.60 +	PWS_ERR_UNSUPPORTED_VERSION
   10.61 +};
   10.62 +
   10.63 +enum pws_data_type {
   10.64 +	PWS_DATA_TYPE_BYTES,
   10.65 +	PWS_DATA_TYPE_UUID,
   10.66 +	PWS_DATA_TYPE_TEXT,
   10.67 +	PWS_DATA_TYPE_TIME,
   10.68 +	PWS_DATA_TYPE_UINT8,
   10.69 +	PWS_DATA_TYPE_UINT16,
   10.70 +	PWS_DATA_TYPE_UINT32
   10.71 +};
   10.72 +
   10.73 +enum pws3_header_field_type {
   10.74 +	PWS3_HEADER_FIELD_VERSION,			/* 0x00 */
   10.75 +	PWS3_HEADER_FIELD_UUID,				/* 0x01 */
   10.76 +	PWS3_HEADER_FIELD_NON_DEFAULT_PREFERENCES,	/* 0x02 */
   10.77 +	PWS3_HEADER_FIELD_TREE_DISPLAY_STATUS,		/* 0x03 */
   10.78 +	PWS3_HEADER_FIELD_SAVE_TIMESTAMP,		/* 0x04 */
   10.79 +	PWS3_HEADER_FIELD_SAVE_USER_HOST,		/* 0x05 */
   10.80 +	PWS3_HEADER_FIELD_SAVE_APPLICATION,		/* 0x06 */
   10.81 +	PWS3_HEADER_FIELD_SAVE_USER,			/* 0x07 */
   10.82 +	PWS3_HEADER_FIELD_SAVE_HOST,			/* 0x08 */
   10.83 +	PWS3_HEADER_FIELD_DATABASE_NAME,		/* 0x09 */
   10.84 +	PWS3_HEADER_FIELD_DATABASE_DESCRIPTION,		/* 0x0a */
   10.85 +	PWS3_HEADER_FIELD_DATABASE_FILTERS,		/* 0x0b */
   10.86 +	PWS3_HEADER_FIELD_RESERVED_1,			/* 0x0c */
   10.87 +	PWS3_HEADER_FIELD_RESERVED_2,			/* 0x0d */
   10.88 +	PWS3_HEADER_FIELD_RESERVED_3,			/* 0x0e */
   10.89 +	PWS3_HEADER_FIELD_RECENTLY_USED_ENTRIES,	/* 0x0f */
   10.90 +	PWS3_HEADER_FIELD_NAMED_PASSWORD_POLICIES,	/* 0x10 */
   10.91 +	PWS3_HEADER_FIELD_EMPTY_GROUPS,			/* 0x11 */
   10.92 +	PWS3_HEADER_FIELD_YUBICO,			/* 0x12 */
   10.93 +	PWS3_HEADER_FIELD_END = 0xff
   10.94 +};
   10.95 +
   10.96 +enum pws3_record_field_type {
   10.97 +	PWS3_RECORD_FIELD_UUID = 0x01,
   10.98 +	PWS3_RECORD_FIELD_GROUP,			/* 0x02 */
   10.99 +	PWS3_RECORD_FIELD_TITLE,			/* 0x03 */
  10.100 +	PWS3_RECORD_FIELD_USERNAME,			/* 0x04 */
  10.101 +	PWS3_RECORD_FIELD_NOTES,			/* 0x05 */
  10.102 +	PWS3_RECORD_FIELD_PASSWORD,			/* 0x06 */
  10.103 +	PWS3_RECORD_FIELD_CREATION_TIME,		/* 0x07 */
  10.104 +	PWS3_RECORD_FIELD_PASSWORD_MODIFICATION_TIME,	/* 0x08 */
  10.105 +	PWS3_RECORD_FIELD_ACCESS_TIME,			/* 0x09 */
  10.106 +	PWS3_RECORD_FIELD_PASSWORD_EXPIRY_TIME,		/* 0x0a */
  10.107 +	PWS3_RECORD_FIELD_RESERVED_1,			/* 0x0b */
  10.108 +	PWS3_RECORD_FIELD_MODIFICATION_TIME,		/* 0x0c */
  10.109 +	PWS3_RECORD_FIELD_URL,				/* 0x0d */
  10.110 +	PWS3_RECORD_FIELD_AUTOTYPE,			/* 0x0e */
  10.111 +	PWS3_RECORD_FIELD_PASSWORD_HISTORY,		/* 0x0f */
  10.112 +	PWS3_RECORD_FIELD_PASSWORD_POLICY,		/* 0x10 */
  10.113 +	PWS3_RECORD_FIELD_PASSWORD_EXPIRY_INTERVAL,	/* 0x11 */
  10.114 +	PWS3_RECORD_FIELD_RUN_COMMAND,			/* 0x12 */
  10.115 +	PWS3_RECORD_FIELD_DOUBLE_CLICK_ACTION,		/* 0x13 */
  10.116 +	PWS3_RECORD_FIELD_EMAIL_ADDRESS,		/* 0x14 */
  10.117 +	PWS3_RECORD_FIELD_PROTECTED,			/* 0x15 */
  10.118 +	PWS3_RECORD_FIELD_ALLOWED_PASSWORD_SYMBOLS,	/* 0x16 */
  10.119 +	PWS3_RECORD_FIELD_SHIFT_DOUBLE_CLICK_ACTION,	/* 0x17 */
  10.120 +	PWS3_RECORD_FIELD_PASSWORD_POLICY_NAME,		/* 0x18 */
  10.121 +	PWS3_RECORD_FIELD_KEYBOARD_SHORTCUT,		/* 0x19 */
  10.122 +	PWS3_RECORD_FIELD_END = 0xff
  10.123 +};
  10.124 +
  10.125 +int		pws_init(void);
  10.126 +void		pws_finalize(void);
  10.127 +void		pws_set_alloc_functions(void *(*)(size_t),
  10.128 +    void *(*)(void *, size_t), void (*)(void *, size_t), void *(*)(size_t),
  10.129 +    void *(*)(void *, size_t), void (*)(void *, size_t));
  10.130 +int		pws_generate_uuid(unsigned char [static PWS3_UUID_SIZE]);
  10.131 +
  10.132 +struct pws3_field * pws3_field_create(int, uint8_t);
  10.133 +void		pws3_field_destroy(struct pws3_field *);
  10.134 +int		pws3_field_is_header(struct pws3_field *);
  10.135 +uint8_t		pws3_field_get_type(struct pws3_field *);
  10.136 +enum pws_data_type pws3_field_get_data_type(struct pws3_field *);
  10.137 +int		pws3_field_set_uuid(struct pws3_field *,
  10.138 +    const unsigned char [static PWS3_UUID_SIZE]);
  10.139 +int		pws3_field_set_text(struct pws3_field *, const char [static 1]);
  10.140 +int		pws3_field_set_time(struct pws3_field *, time_t);
  10.141 +int		pws3_field_set_uint8(struct pws3_field *, uint8_t);
  10.142 +int		pws3_field_set_uint16(struct pws3_field *, uint16_t);
  10.143 +int		pws3_field_set_uint32(struct pws3_field *, uint32_t);
  10.144 +int		pws3_field_set_bytes(struct pws3_field *,
  10.145 +    const unsigned char [static 1], size_t);
  10.146 +const unsigned char * pws3_field_get_uuid(struct pws3_field *);
  10.147 +const char *	pws3_field_get_text(struct pws3_field *);
  10.148 +time_t		pws3_field_get_time(struct pws3_field *);
  10.149 +uint8_t		pws3_field_get_uint8(struct pws3_field *);
  10.150 +uint16_t	pws3_field_get_uint16(struct pws3_field *);
  10.151 +uint32_t	pws3_field_get_uint32(struct pws3_field *);
  10.152 +void		pws3_field_get_bytes(struct pws3_field *,
  10.153 +    const unsigned char **, size_t *);
  10.154 +
  10.155 +void		pws3_record_destroy(struct pws3_record *);
  10.156 +struct pws3_record * pws3_record_create(void);
  10.157 +void		pws3_record_set_field(struct pws3_record *,
  10.158 +    struct pws3_field *);
  10.159 +struct pws3_field * pws3_record_get_field(struct pws3_record *, uint8_t);
  10.160 +struct pws3_field * pws3_record_remove_field(struct pws3_record *, uint8_t);
  10.161 +
  10.162 +void		pws3_file_destroy(struct pws3_file *);
  10.163 +struct pws3_file * pws3_file_create(void);
  10.164 +enum pws_error_code pws3_file_get_error_code(struct pws3_file *);
  10.165 +const char *	pws3_file_get_error_message(struct pws3_file *);
  10.166 +int		pws3_file_read_mem(struct pws3_file *, const char *,
  10.167 +    unsigned char *, size_t);
  10.168 +int		pws3_file_read_stream(struct pws3_file *, const char *, FILE *);
  10.169 +int		pws3_file_write_mem(struct pws3_file *, const char *, uint32_t,
  10.170 +    unsigned char **, size_t *);
  10.171 +int		pws3_file_write_stream(struct pws3_file *, const char *,
  10.172 +    uint32_t, FILE *);
  10.173 +
  10.174 +void		pws3_file_set_header_field(struct pws3_file *,
  10.175 +    struct pws3_field *);
  10.176 +struct pws3_field * pws3_file_get_header_field(struct pws3_file *, uint8_t);
  10.177 +struct pws3_field * pws3_file_remove_header_field(struct pws3_file *, uint8_t);
  10.178 +
  10.179 +void		pws3_file_insert_empty_group(struct pws3_file *,
  10.180 +    struct pws3_field *);
  10.181 +struct pws3_field * pws3_file_get_empty_group(struct pws3_file *, const char *);
  10.182 +struct pws3_field * pws3_file_remove_empty_group(struct pws3_file *,
  10.183 +    const char *);
  10.184 +struct pws3_field * pws3_file_first_empty_group(struct pws3_file *);
  10.185 +struct pws3_field * pws3_file_last_empty_group(struct pws3_file *);
  10.186 +struct pws3_field * pws3_file_next_empty_group(struct pws3_file *,
  10.187 +    struct pws3_field *);
  10.188 +struct pws3_field * pws3_file_prev_empty_group(struct pws3_file *,
  10.189 +    struct pws3_field *);
  10.190 +
  10.191 +void		pws3_file_insert_record(struct pws3_file *,
  10.192 +    struct pws3_record *);
  10.193 +struct pws3_record * pws3_file_get_record(struct pws3_file *,
  10.194 +    const unsigned char [static PWS3_UUID_SIZE]);
  10.195 +struct pws3_record * pws3_file_remove_record(struct pws3_file *,
  10.196 +    const unsigned char [static PWS3_UUID_SIZE]);
  10.197 +struct pws3_record * pws3_file_first_record(struct pws3_file *);
  10.198 +struct pws3_record * pws3_file_last_record(struct pws3_file *);
  10.199 +struct pws3_record * pws3_file_next_record(struct pws3_file *,
  10.200 +    struct pws3_record *);
  10.201 +struct pws3_record * pws3_file_prev_record(struct pws3_file *,
  10.202 +    struct pws3_record *);
  10.203 +
  10.204 +#ifdef __cplusplus
  10.205 +}
  10.206 +#endif /* __cplusplus */
  10.207 +
  10.208 +#endif /* !PWS_H */
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/pws-field.c	Tue Feb 10 11:29:54 2015 +0100
    11.3 @@ -0,0 +1,332 @@
    11.4 +/*
    11.5 + * Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name>
    11.6 + *
    11.7 + * Permission is hereby granted, free of charge, to any person obtaining
    11.8 + * a copy of this software and associated documentation files (the
    11.9 + * "Software"), to deal in the Software without restriction, including
   11.10 + * without limitation the rights to use, copy, modify, merge, publish,
   11.11 + * distribute, sublicense, and/or sell copies of the Software, and to
   11.12 + * permit persons to whom the Software is furnished to do so, subject to
   11.13 + * the following conditions:
   11.14 + *
   11.15 + * The above copyright notice and this permission notice shall be included
   11.16 + * in all copies or substantial portions of the Software.
   11.17 + *
   11.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   11.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   11.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   11.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   11.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   11.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   11.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   11.25 + */
   11.26 +
   11.27 +#include "compat.h"
   11.28 +
   11.29 +#include <stdlib.h>
   11.30 +#include <string.h>
   11.31 +#include <limits.h>
   11.32 +
   11.33 +#include "pws-internal.h"
   11.34 +
   11.35 +static const enum pws_data_type	header_data_types[256] = {
   11.36 +	[PWS3_HEADER_FIELD_VERSION] = PWS_DATA_TYPE_UINT16,
   11.37 +	[PWS3_HEADER_FIELD_UUID] = PWS_DATA_TYPE_UUID,
   11.38 +	[PWS3_HEADER_FIELD_NON_DEFAULT_PREFERENCES] = PWS_DATA_TYPE_TEXT,
   11.39 +	[PWS3_HEADER_FIELD_TREE_DISPLAY_STATUS] = PWS_DATA_TYPE_TEXT,
   11.40 +	[PWS3_HEADER_FIELD_SAVE_TIMESTAMP] = PWS_DATA_TYPE_TIME,
   11.41 +	[PWS3_HEADER_FIELD_SAVE_USER_HOST] = PWS_DATA_TYPE_TEXT,
   11.42 +	[PWS3_HEADER_FIELD_SAVE_APPLICATION] = PWS_DATA_TYPE_TEXT,
   11.43 +	[PWS3_HEADER_FIELD_SAVE_USER] = PWS_DATA_TYPE_TEXT,
   11.44 +	[PWS3_HEADER_FIELD_SAVE_HOST] = PWS_DATA_TYPE_TEXT,
   11.45 +	[PWS3_HEADER_FIELD_DATABASE_NAME] = PWS_DATA_TYPE_TEXT,
   11.46 +	[PWS3_HEADER_FIELD_DATABASE_DESCRIPTION] = PWS_DATA_TYPE_TEXT,
   11.47 +	[PWS3_HEADER_FIELD_DATABASE_FILTERS] = PWS_DATA_TYPE_TEXT,
   11.48 +	[PWS3_HEADER_FIELD_RESERVED_1] = PWS_DATA_TYPE_BYTES,
   11.49 +	[PWS3_HEADER_FIELD_RESERVED_2] = PWS_DATA_TYPE_BYTES,
   11.50 +	[PWS3_HEADER_FIELD_RESERVED_3] = PWS_DATA_TYPE_BYTES,
   11.51 +	[PWS3_HEADER_FIELD_RECENTLY_USED_ENTRIES] = PWS_DATA_TYPE_TEXT,
   11.52 +	[PWS3_HEADER_FIELD_NAMED_PASSWORD_POLICIES] = PWS_DATA_TYPE_TEXT,
   11.53 +	[PWS3_HEADER_FIELD_EMPTY_GROUPS] = PWS_DATA_TYPE_TEXT,
   11.54 +	[PWS3_HEADER_FIELD_YUBICO] = PWS_DATA_TYPE_TEXT
   11.55 +};
   11.56 +
   11.57 +static const enum pws_data_type	record_data_types[256] = {
   11.58 +	[PWS3_RECORD_FIELD_UUID] = PWS_DATA_TYPE_UUID,
   11.59 +	[PWS3_RECORD_FIELD_GROUP] = PWS_DATA_TYPE_TEXT,
   11.60 +	[PWS3_RECORD_FIELD_TITLE] = PWS_DATA_TYPE_TEXT,
   11.61 +	[PWS3_RECORD_FIELD_USERNAME] = PWS_DATA_TYPE_TEXT,
   11.62 +	[PWS3_RECORD_FIELD_NOTES] = PWS_DATA_TYPE_TEXT,
   11.63 +	[PWS3_RECORD_FIELD_PASSWORD] = PWS_DATA_TYPE_TEXT,
   11.64 +	[PWS3_RECORD_FIELD_CREATION_TIME] = PWS_DATA_TYPE_TIME,
   11.65 +	[PWS3_RECORD_FIELD_PASSWORD_MODIFICATION_TIME] = PWS_DATA_TYPE_TIME,
   11.66 +	[PWS3_RECORD_FIELD_ACCESS_TIME] = PWS_DATA_TYPE_TIME,
   11.67 +	[PWS3_RECORD_FIELD_PASSWORD_EXPIRY_TIME] = PWS_DATA_TYPE_TIME,
   11.68 +	[PWS3_RECORD_FIELD_RESERVED_1] = PWS_DATA_TYPE_BYTES,
   11.69 +	[PWS3_RECORD_FIELD_MODIFICATION_TIME] = PWS_DATA_TYPE_TIME,
   11.70 +	[PWS3_RECORD_FIELD_URL] = PWS_DATA_TYPE_TEXT,
   11.71 +	[PWS3_RECORD_FIELD_AUTOTYPE] = PWS_DATA_TYPE_TEXT,
   11.72 +	[PWS3_RECORD_FIELD_PASSWORD_HISTORY] = PWS_DATA_TYPE_TEXT,
   11.73 +	[PWS3_RECORD_FIELD_PASSWORD_POLICY] = PWS_DATA_TYPE_TEXT,
   11.74 +	[PWS3_RECORD_FIELD_PASSWORD_EXPIRY_INTERVAL] = PWS_DATA_TYPE_UINT32,
   11.75 +	[PWS3_RECORD_FIELD_RUN_COMMAND] = PWS_DATA_TYPE_TEXT,
   11.76 +	[PWS3_RECORD_FIELD_DOUBLE_CLICK_ACTION] = PWS_DATA_TYPE_BYTES,
   11.77 +	[PWS3_RECORD_FIELD_EMAIL_ADDRESS] = PWS_DATA_TYPE_TEXT,
   11.78 +	[PWS3_RECORD_FIELD_PROTECTED] = PWS_DATA_TYPE_UINT8,
   11.79 +	[PWS3_RECORD_FIELD_ALLOWED_PASSWORD_SYMBOLS] = PWS_DATA_TYPE_TEXT,
   11.80 +	[PWS3_RECORD_FIELD_SHIFT_DOUBLE_CLICK_ACTION] = PWS_DATA_TYPE_BYTES,
   11.81 +	[PWS3_RECORD_FIELD_PASSWORD_POLICY_NAME] = PWS_DATA_TYPE_TEXT,
   11.82 +	[PWS3_RECORD_FIELD_KEYBOARD_SHORTCUT] = PWS_DATA_TYPE_BYTES
   11.83 +};
   11.84 +
   11.85 +struct pws3_field *
   11.86 +pws3_field_create(int is_header, uint8_t field_type)
   11.87 +{
   11.88 +	struct pws3_field	*field;
   11.89 +
   11.90 +	field = pws_alloc(sizeof (struct pws3_field));
   11.91 +	if (field == NULL) {
   11.92 +		return (NULL);
   11.93 +	}
   11.94 +
   11.95 +	field->is_header = is_header;
   11.96 +	field->field_type = field_type;
   11.97 +	field->size = 0;
   11.98 +	switch (pws3_field_get_data_type(field)) {
   11.99 +	case PWS_DATA_TYPE_BYTES:
  11.100 +		field->value.bytes = NULL;
  11.101 +		break;
  11.102 +	case PWS_DATA_TYPE_UUID:
  11.103 +		memset(field->value.uuid, 0, PWS3_UUID_SIZE);
  11.104 +		break;
  11.105 +	case PWS_DATA_TYPE_TEXT:
  11.106 +		field->value.text = NULL;
  11.107 +		break;
  11.108 +	case PWS_DATA_TYPE_UINT8:
  11.109 +		field->value.uint8 = 0;
  11.110 +		break;
  11.111 +	case PWS_DATA_TYPE_UINT16:
  11.112 +		field->value.uint16 = 0;
  11.113 +		break;
  11.114 +	case PWS_DATA_TYPE_TIME:   /* FALLTHROUGH */
  11.115 +	case PWS_DATA_TYPE_UINT32:
  11.116 +		field->value.uint32 = 0;
  11.117 +	}
  11.118 +
  11.119 +	return (field);
  11.120 +}
  11.121 +
  11.122 +void
  11.123 +pws3_field_destroy(struct pws3_field *field)
  11.124 +{
  11.125 +	if (field == NULL) {
  11.126 +		return;
  11.127 +	}
  11.128 +
  11.129 +	switch (pws3_field_get_data_type(field)) {
  11.130 +	case PWS_DATA_TYPE_BYTES:
  11.131 +		pws_free(field->value.bytes, field->size);
  11.132 +		break;
  11.133 +	case PWS_DATA_TYPE_TEXT:
  11.134 +		if (!field->is_header &&
  11.135 +		    (field->field_type == PWS3_RECORD_FIELD_PASSWORD)) {
  11.136 +			pws_secure_free(field->value.text, field->size + 1);
  11.137 +		} else {
  11.138 +			pws_free(field->value.text, field->size + 1);
  11.139 +		}
  11.140 +		break;
  11.141 +	default:
  11.142 +		break;
  11.143 +	}
  11.144 +
  11.145 +	pws_free(field, sizeof (struct pws3_field));
  11.146 +}
  11.147 +
  11.148 +int
  11.149 +pws3_field_is_header(struct pws3_field *field)
  11.150 +{
  11.151 +	return (field->is_header);
  11.152 +}
  11.153 +
  11.154 +uint8_t
  11.155 +pws3_field_get_type(struct pws3_field *field)
  11.156 +{
  11.157 +	return (field->field_type);
  11.158 +}
  11.159 +
  11.160 +enum pws_data_type
  11.161 +pws3_field_get_data_type(struct pws3_field *field)
  11.162 +{
  11.163 +	return (field->is_header ? header_data_types[field->field_type] :
  11.164 +	    record_data_types[field->field_type]);
  11.165 +}
  11.166 +
  11.167 +int
  11.168 +pws3_field_set_uuid(struct pws3_field *field,
  11.169 +    const unsigned char s[static PWS3_UUID_SIZE])
  11.170 +{
  11.171 +	PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UUID);
  11.172 +
  11.173 +	field->size = PWS3_UUID_SIZE;
  11.174 +	memcpy(field->value.uuid, s, PWS3_UUID_SIZE);
  11.175 +
  11.176 +	return (0);
  11.177 +}
  11.178 +
  11.179 +int
  11.180 +pws3_field_set_text(struct pws3_field *field, const char s[static 1])
  11.181 +{
  11.182 +	size_t	len;
  11.183 +	char	*t;
  11.184 +
  11.185 +	PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_TEXT);
  11.186 +
  11.187 +	len = strlen(s);
  11.188 +	if (len > PWS3_MAX_FIELD_SIZE) {
  11.189 +		return (-1);
  11.190 +	}
  11.191 +
  11.192 +	if (!field->is_header &&
  11.193 +	    (field->field_type == PWS3_RECORD_FIELD_PASSWORD)) {
  11.194 +		if (len > PWS3_MAX_PASSWORD_LEN) {
  11.195 +			return (-1);
  11.196 +		}
  11.197 +		t = pws_secure_realloc(field->value.text, len + 1);
  11.198 +	} else {
  11.199 +		t = pws_realloc(field->value.text, len + 1);
  11.200 +	}
  11.201 +	if (t == NULL) {
  11.202 +		return (-1);
  11.203 +	}
  11.204 +	field->value.text = t;
  11.205 +	field->size = len + 1;
  11.206 +	memcpy(field->value.text, s, field->size);
  11.207 +
  11.208 +	return (0);
  11.209 +}
  11.210 +
  11.211 +int
  11.212 +pws3_field_set_time(struct pws3_field *field, time_t time)
  11.213 +{
  11.214 +	PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_TIME);
  11.215 +
  11.216 +	field->size = 4;
  11.217 +	field->value.uint32 = CLAMP(time, 0, UINT32_MAX);
  11.218 +
  11.219 +	return (0);
  11.220 +}
  11.221 +
  11.222 +int
  11.223 +pws3_field_set_uint8(struct pws3_field *field, uint8_t u8)
  11.224 +{
  11.225 +	PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UINT8);
  11.226 +
  11.227 +	field->size = 1;
  11.228 +	field->value.uint8 = u8;
  11.229 +
  11.230 +	return (0);
  11.231 +}
  11.232 +
  11.233 +int
  11.234 +pws3_field_set_uint16(struct pws3_field *field, uint16_t u16)
  11.235 +{
  11.236 +	PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UINT16);
  11.237 +
  11.238 +	field->size = 2;
  11.239 +	field->value.uint16 = u16;
  11.240 +
  11.241 +	return (0);
  11.242 +}
  11.243 +
  11.244 +int
  11.245 +pws3_field_set_uint32(struct pws3_field *field, uint32_t u32)
  11.246 +{
  11.247 +	PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UINT32);
  11.248 +
  11.249 +	field->size = 4;
  11.250 +	field->value.uint32 = u32;
  11.251 +
  11.252 +	return (0);
  11.253 +}
  11.254 +
  11.255 +int
  11.256 +pws3_field_set_bytes(struct pws3_field *field, const unsigned char s[static 1],
  11.257 +    size_t n)
  11.258 +{
  11.259 +	unsigned char	*t;
  11.260 +
  11.261 +	PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_BYTES);
  11.262 +
  11.263 +	if (n > PWS3_MAX_FIELD_SIZE) {
  11.264 +		return (-1);
  11.265 +	}
  11.266 +
  11.267 +	t = pws_realloc(field->value.bytes, n);
  11.268 +	if (t == NULL) {
  11.269 +		return (-1);
  11.270 +	}
  11.271 +	field->size = n;
  11.272 +	field->value.bytes = t;
  11.273 +	memcpy(t, s, n);
  11.274 +
  11.275 +	return (0);
  11.276 +}
  11.277 +
  11.278 +const unsigned char *
  11.279 +pws3_field_get_uuid(struct pws3_field *field)
  11.280 +{
  11.281 +	PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UUID);
  11.282 +
  11.283 +	return (field->value.uuid);
  11.284 +}
  11.285 +
  11.286 +const char *
  11.287 +pws3_field_get_text(struct pws3_field *field)
  11.288 +{
  11.289 +	PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_TEXT);
  11.290 +
  11.291 +	return (field->value.text);
  11.292 +}
  11.293 +
  11.294 +time_t
  11.295 +pws3_field_get_time(struct pws3_field *field)
  11.296 +{
  11.297 +	PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_TIME);
  11.298 +
  11.299 +	/* assume time_t can hold at least a INT32_MAX */
  11.300 +	return ((time_t)CLAMP(field->value.uint32, 0, INT32_MAX));
  11.301 +}
  11.302 +
  11.303 +uint8_t
  11.304 +pws3_field_get_uint8(struct pws3_field *field)
  11.305 +{
  11.306 +	PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UINT8);
  11.307 +
  11.308 +	return (field->value.uint8);
  11.309 +}
  11.310 +
  11.311 +uint16_t
  11.312 +pws3_field_get_uint16(struct pws3_field *field)
  11.313 +{
  11.314 +	PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UINT16);
  11.315 +
  11.316 +	return (field->value.uint16);
  11.317 +}
  11.318 +
  11.319 +uint32_t
  11.320 +pws3_field_get_uint32(struct pws3_field *field)
  11.321 +{
  11.322 +	PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_UINT32);
  11.323 +
  11.324 +	return (field->value.uint32);
  11.325 +}
  11.326 +
  11.327 +void
  11.328 +pws3_field_get_bytes(struct pws3_field *field, const unsigned char **sp,
  11.329 +    size_t *np)
  11.330 +{
  11.331 +	PWS_ASSERT(pws3_field_get_data_type(field) == PWS_DATA_TYPE_BYTES);
  11.332 +
  11.333 +	*sp = field->value.bytes;
  11.334 +	*np = field->size;
  11.335 +}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/pws-file.c	Tue Feb 10 11:29:54 2015 +0100
    12.3 @@ -0,0 +1,1502 @@
    12.4 +/*
    12.5 + * Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name>
    12.6 + *
    12.7 + * Permission is hereby granted, free of charge, to any person obtaining
    12.8 + * a copy of this software and associated documentation files (the
    12.9 + * "Software"), to deal in the Software without restriction, including
   12.10 + * without limitation the rights to use, copy, modify, merge, publish,
   12.11 + * distribute, sublicense, and/or sell copies of the Software, and to
   12.12 + * permit persons to whom the Software is furnished to do so, subject to
   12.13 + * the following conditions:
   12.14 + *
   12.15 + * The above copyright notice and this permission notice shall be included
   12.16 + * in all copies or substantial portions of the Software.
   12.17 + *
   12.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   12.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   12.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   12.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   12.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   12.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   12.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   12.25 + */
   12.26 +
   12.27 +#include "compat.h"
   12.28 +
   12.29 +#include <stdlib.h>
   12.30 +#include <unistd.h>
   12.31 +#include <string.h>
   12.32 +#include <stdarg.h>
   12.33 +#include <errno.h>
   12.34 +#ifdef	HAVE_ENDIAN_H
   12.35 +#include <endian.h>
   12.36 +#endif /* HAVE_ENDIAN_H */
   12.37 +#ifdef	HAVE_SYS_ENDIAN_H
   12.38 +#include <sys/endian.h>
   12.39 +#endif /* HAVE_ENDIAN_H */
   12.40 +#include <nettle/twofish.h>
   12.41 +#include <nettle/cbc.h>
   12.42 +#include <nettle/hmac.h>
   12.43 +#include <nettle/sha.h>
   12.44 +
   12.45 +#include "pws-internal.h"
   12.46 +
   12.47 +#define	MAX_ITER		(1 << 22)
   12.48 +#define	DEFAULT_ITER		10000
   12.49 +#define	KEY_SIZE		32UL
   12.50 +#define	SALT_SIZE		32UL
   12.51 +#define	METADATA_SIZE		(sizeof (psafe3_tag) + SALT_SIZE + 4 +\
   12.52 +    SHA256_DIGEST_SIZE + KEY_SIZE + KEY_SIZE + TWOFISH_BLOCK_SIZE)
   12.53 +
   12.54 +static const unsigned char psafe3_tag[] = { 'P', 'W', 'S', '3' };
   12.55 +static const unsigned char eof_marker[] = { 'P', 'W', 'S', '3', '-', 'E', 'O',
   12.56 +    'F', 'P', 'W', 'S', '3', '-', 'E', 'O', 'F' };
   12.57 +
   12.58 +RB_HEAD(empty_groups_tree, pws3_field);
   12.59 +
   12.60 +RB_HEAD(records_tree, pws3_record);
   12.61 +
   12.62 +struct pws3_file {
   12.63 +	struct pws3_field	*fields[256];
   12.64 +	struct empty_groups_tree *empty_groups_tree;
   12.65 +	struct records_tree	*records_tree;
   12.66 +	struct pws_file_error {
   12.67 +		enum pws_error_code code;
   12.68 +		int		errnum;
   12.69 +		char		*msg;
   12.70 +	} error;
   12.71 +};
   12.72 +
   12.73 +struct twofish_cbc_ctx CBC_CTX(struct twofish_ctx, TWOFISH_BLOCK_SIZE);
   12.74 +
   12.75 +struct pws_file_ctx {
   12.76 +	FILE		*fp;
   12.77 +	unsigned char	*mem;
   12.78 +	size_t		mem_size;
   12.79 +	size_t		mem_pos;
   12.80 +	struct twofish_cbc_ctx cipher_ctx;
   12.81 +	struct hmac_sha256_ctx hmac_ctx;
   12.82 +	struct pws3_file *pws_file;
   12.83 +	uint32_t	n_iter;
   12.84 +};
   12.85 +
   12.86 +static int	empty_groups_cmp(struct pws3_field *, struct pws3_field *);
   12.87 +static int	record_cmp(struct pws3_record *, struct pws3_record *);
   12.88 +RB_PROTOTYPE_STATIC(empty_groups_tree, pws3_field, tree_entry, empty_groups_cmp)
   12.89 +RB_PROTOTYPE_STATIC(records_tree, pws3_record, tree_entry, record_cmp)
   12.90 +
   12.91 +RB_GENERATE_STATIC(empty_groups_tree, pws3_field, tree_entry, empty_groups_cmp)
   12.92 +
   12.93 +RB_GENERATE_STATIC(records_tree, pws3_record, tree_entry, record_cmp)
   12.94 +
   12.95 +static int
   12.96 +empty_groups_cmp(struct pws3_field *field1, struct pws3_field *field2)
   12.97 +{
   12.98 +	PWS_ASSERT(pws3_field_is_header(field1) &&
   12.99 +	    pws3_field_is_header(field2));
  12.100 +	PWS_ASSERT((pws3_field_get_type(field1) ==
  12.101 +	    PWS3_HEADER_FIELD_EMPTY_GROUPS) &&
  12.102 +	    (pws3_field_get_type(field2) == PWS3_HEADER_FIELD_EMPTY_GROUPS));
  12.103 +
  12.104 +	return (strcmp(pws3_field_get_text(field1),
  12.105 +	    pws3_field_get_text(field2)));
  12.106 +}
  12.107 +
  12.108 +static int
  12.109 +record_cmp(struct pws3_record *record1, struct pws3_record *record2)
  12.110 +{
  12.111 +	struct pws3_field	*uuid_field1;
  12.112 +	struct pws3_field	*uuid_field2;
  12.113 +
  12.114 +	uuid_field1 = pws3_record_get_field(record1, PWS3_RECORD_FIELD_UUID);
  12.115 +	uuid_field2 = pws3_record_get_field(record2, PWS3_RECORD_FIELD_UUID);
  12.116 +	PWS_ASSERT((uuid_field1 != NULL) && (uuid_field2 != NULL));
  12.117 +
  12.118 +	return (memcmp(pws3_field_get_uuid(uuid_field1),
  12.119 +	    pws3_field_get_uuid(uuid_field2), PWS3_UUID_SIZE));
  12.120 +}
  12.121 +
  12.122 +static void
  12.123 +pws_set_system_error(struct pws3_file *pws_file, enum pws_error_code code,
  12.124 +    int errnum, const char *fmt, ...)
  12.125 +{
  12.126 +	char	system_error_buf[4096] = "";
  12.127 +	size_t	system_error_len;
  12.128 +	int	error_len;
  12.129 +	va_list	args;
  12.130 +	va_list	args2;
  12.131 +
  12.132 +	pws_file->error.code = code;
  12.133 +	pws_file->error.errnum = errnum;
  12.134 +
  12.135 +	strerror_r(errnum, system_error_buf, sizeof (system_error_buf) - 1);
  12.136 +	system_error_len = strlen(system_error_buf);
  12.137 +
  12.138 +	pws_free(pws_file->error.msg, (pws_file->error.msg != NULL) ?
  12.139 +	    strlen(pws_file->error.msg) + 1 : 0);
  12.140 +	if (fmt != NULL) {
  12.141 +		va_start(args, fmt);
  12.142 +		va_copy(args2, args);
  12.143 +		error_len = vsnprintf(NULL, 0, fmt, args);
  12.144 +		pws_file->error.msg = pws_alloc(error_len + 2 +
  12.145 +		    system_error_len + 1);
  12.146 +		if (pws_file->error.msg == NULL) {
  12.147 +			va_end(args2);
  12.148 +			va_end(args);
  12.149 +			return;
  12.150 +		}
  12.151 +		vsnprintf(pws_file->error.msg, error_len + 1, fmt, args2);
  12.152 +		va_end(args2);
  12.153 +		va_end(args);
  12.154 +		strcpy(pws_file->error.msg + error_len, ": ");
  12.155 +		strcpy(pws_file->error.msg + error_len + 2, system_error_buf);
  12.156 +	} else {
  12.157 +		pws_file->error.msg = pws_alloc(system_error_len + 1);
  12.158 +		snprintf(pws_file->error.msg, system_error_len + 1, "%s",
  12.159 +		    system_error_buf);
  12.160 +	}
  12.161 +}
  12.162 +
  12.163 +static void
  12.164 +pws_set_error(struct pws3_file *pws_file, enum pws_error_code code,
  12.165 +    const char *fmt, ...)
  12.166 +{
  12.167 +	va_list	args;
  12.168 +	va_list	args2;
  12.169 +	int	error_len;
  12.170 +
  12.171 +	pws_file->error.code = code;
  12.172 +	pws_file->error.errnum = 0;
  12.173 +
  12.174 +	pws_free(pws_file->error.msg, (pws_file->error.msg != NULL) ?
  12.175 +	    strlen(pws_file->error.msg) + 1 : 0);
  12.176 +	va_start(args, fmt);
  12.177 +	va_copy(args2, args);
  12.178 +	error_len = vsnprintf(NULL, 0, fmt, args);
  12.179 +	pws_file->error.msg = pws_alloc(error_len + 1);
  12.180 +	if (pws_file->error.msg == NULL) {
  12.181 +		va_end(args2);
  12.182 +		va_end(args);
  12.183 +		return;
  12.184 +	}
  12.185 +	vsnprintf(pws_file->error.msg, error_len + 1, fmt, args2);
  12.186 +	va_end(args2);
  12.187 +	va_end(args);
  12.188 +}
  12.189 +
  12.190 +static int
  12.191 +read_buf(struct pws_file_ctx *ctx, unsigned char *buf, size_t buf_size)
  12.192 +{
  12.193 +	if (ctx->fp != NULL) {
  12.194 +		if (fread(buf, 1, buf_size, ctx->fp) != buf_size) {
  12.195 +			if (ferror(ctx->fp) != 0) {
  12.196 +				return (-1);
  12.197 +			} else if (feof(ctx->fp) != 0) {
  12.198 +				return (1);
  12.199 +			}
  12.200 +		}
  12.201 +	} else {
  12.202 +		PWS_ASSERT(ctx->mem != NULL);
  12.203 +		if (ctx->mem_size - ctx->mem_pos < buf_size) {
  12.204 +			return (1);
  12.205 +		}
  12.206 +		memcpy(buf, &ctx->mem[ctx->mem_pos], buf_size);
  12.207 +		ctx->mem_pos += buf_size;
  12.208 +	}
  12.209 +
  12.210 +	return (0);
  12.211 +}
  12.212 +
  12.213 +static int
  12.214 +write_buf(struct pws_file_ctx *ctx, const unsigned char *buf, size_t buf_size)
  12.215 +{
  12.216 +	size_t		remaining;
  12.217 +	unsigned char	*tmp;
  12.218 +
  12.219 +	if (ctx->fp != NULL) {
  12.220 +		if (fwrite(buf, 1, buf_size, ctx->fp) != buf_size) {
  12.221 +			return (-1);
  12.222 +		}
  12.223 +		if (fflush(ctx->fp) != 0) {
  12.224 +			return (-1);
  12.225 +		}
  12.226 +	} else {
  12.227 +		remaining = ctx->mem_size - ctx->mem_pos;
  12.228 +		if (remaining < buf_size) {
  12.229 +			tmp = pws_realloc(ctx->mem, ctx->mem_size +
  12.230 +			    (buf_size - remaining));
  12.231 +			if (tmp == NULL) {
  12.232 +				return (-1);
  12.233 +			}
  12.234 +			ctx->mem = tmp;
  12.235 +			ctx->mem_size += (buf_size - remaining);
  12.236 +		}
  12.237 +		memcpy(&ctx->mem[ctx->mem_pos], buf, buf_size);
  12.238 +		ctx->mem_pos += buf_size;
  12.239 +	}
  12.240 +
  12.241 +	return (0);
  12.242 +}
  12.243 +
  12.244 +static void
  12.245 +pws_file_clear(struct pws3_file *pws_file)
  12.246 +{
  12.247 +	size_t			i;
  12.248 +	struct pws3_field	*empty_group_field;
  12.249 +	struct pws3_field	*empty_group_field_tmp;
  12.250 +	struct pws3_record	*record;
  12.251 +	struct pws3_record	*record_tmp;
  12.252 +
  12.253 +	for (i = 0x00; i <= 0xff; i++) {
  12.254 +		pws3_field_destroy(pws_file->fields[i]);
  12.255 +		pws_file->fields[i] = NULL;
  12.256 +	}
  12.257 +
  12.258 +	RB_FOREACH_SAFE(empty_group_field, empty_groups_tree,
  12.259 +	    pws_file->empty_groups_tree, empty_group_field_tmp) {
  12.260 +		pws3_field_destroy(RB_REMOVE(empty_groups_tree,
  12.261 +		    pws_file->empty_groups_tree, empty_group_field));
  12.262 +	}
  12.263 +
  12.264 +	RB_FOREACH_SAFE(record, records_tree, pws_file->records_tree,
  12.265 +	    record_tmp) {
  12.266 +		pws3_record_destroy(RB_REMOVE(records_tree,
  12.267 +		    pws_file->records_tree, record));
  12.268 +	}
  12.269 +}
  12.270 +
  12.271 +void
  12.272 +pws3_file_destroy(struct pws3_file *pws_file)
  12.273 +{
  12.274 +	if (pws_file == NULL) {
  12.275 +		return;
  12.276 +	}
  12.277 +
  12.278 +	pws_free(pws_file->error.msg, (pws_file->error.msg != NULL) ?
  12.279 +	    strlen(pws_file->error.msg) + 1 : 0);
  12.280 +	pws_file_clear(pws_file);
  12.281 +	pws_free(pws_file->empty_groups_tree,
  12.282 +	    sizeof (struct empty_groups_tree));
  12.283 +	pws_free(pws_file->records_tree, sizeof (struct records_tree));
  12.284 +	pws_free(pws_file, sizeof (struct pws3_file));
  12.285 +}
  12.286 +
  12.287 +struct pws3_file *
  12.288 +pws3_file_create(void)
  12.289 +{
  12.290 +	struct pws3_field	*version_field = NULL;
  12.291 +	struct pws3_file	*pws_file = NULL;
  12.292 +	size_t			i;
  12.293 +
  12.294 +	/* version field is mandatory */
  12.295 +	version_field = pws3_field_create(1, PWS3_HEADER_FIELD_VERSION);
  12.296 +	if (version_field == NULL) {
  12.297 +		goto err;
  12.298 +	}
  12.299 +	pws3_field_set_uint16(version_field, PWS3_VERSION);
  12.300 +
  12.301 +	pws_file = pws_alloc(sizeof (struct pws3_file));
  12.302 +	if (pws_file == NULL) {
  12.303 +		goto err;
  12.304 +	}
  12.305 +	for (i = 0x00; i <= 0xff; i++) {
  12.306 +		pws_file->fields[i] = NULL;
  12.307 +	}
  12.308 +	pws_file->empty_groups_tree = NULL;
  12.309 +	pws_file->records_tree = NULL;
  12.310 +	pws_file->error.errnum = 0;
  12.311 +	pws_file->error.code = 0;
  12.312 +	pws_file->error.msg = NULL;
  12.313 +
  12.314 +	pws_file->empty_groups_tree =
  12.315 +	    pws_alloc(sizeof (struct empty_groups_tree));
  12.316 +	if (pws_file->empty_groups_tree == NULL) {
  12.317 +		goto err;
  12.318 +	}
  12.319 +	RB_INIT(pws_file->empty_groups_tree);
  12.320 +
  12.321 +	pws_file->records_tree = pws_alloc(sizeof (struct records_tree));
  12.322 +	if (pws_file->records_tree == NULL) {
  12.323 +		goto err;
  12.324 +	}
  12.325 +	RB_INIT(pws_file->records_tree);
  12.326 +
  12.327 +	pws3_file_set_header_field(pws_file, version_field);
  12.328 +
  12.329 +	return (pws_file);
  12.330 +err:
  12.331 +	pws3_field_destroy(version_field);
  12.332 +	if (pws_file != NULL) {
  12.333 +		pws_free(pws_file->records_tree, sizeof (struct records_tree));
  12.334 +		pws_free(pws_file->empty_groups_tree,
  12.335 +		    sizeof (struct empty_groups_tree));
  12.336 +	}
  12.337 +	pws_free(pws_file, sizeof (struct pws3_file));
  12.338 +
  12.339 +	return (NULL);
  12.340 +}
  12.341 +
  12.342 +enum pws_error_code
  12.343 +pws3_file_get_error_code(struct pws3_file *pws_file)
  12.344 +{
  12.345 +	return (pws_file->error.code);
  12.346 +}
  12.347 +
  12.348 +const char *
  12.349 +pws3_file_get_error_message(struct pws3_file *pws_file)
  12.350 +{
  12.351 +	return ((pws_file->error.msg != NULL) ? pws_file->error.msg : "");
  12.352 +}
  12.353 +
  12.354 +static void
  12.355 +stretch_key(unsigned char *stretched_key, uint32_t n_iter, const char *key,
  12.356 +    size_t key_size, const unsigned char *salt, size_t salt_size)
  12.357 +{
  12.358 +	uint32_t	i;
  12.359 +	struct sha256_ctx md_ctx;
  12.360 +
  12.361 +	sha256_init(&md_ctx);
  12.362 +	sha256_update(&md_ctx, key_size, (uint8_t *)key);
  12.363 +	sha256_update(&md_ctx, salt_size, salt);
  12.364 +	sha256_digest(&md_ctx, SHA256_DIGEST_SIZE, stretched_key);
  12.365 +
  12.366 +	for (i = 0; i < n_iter; i++) {
  12.367 +		sha256_update(&md_ctx, SHA256_DIGEST_SIZE, stretched_key);
  12.368 +		sha256_digest(&md_ctx, SHA256_DIGEST_SIZE, stretched_key);
  12.369 +	}
  12.370 +}
  12.371 +
  12.372 +static int
  12.373 +read_metadata(struct pws_file_ctx *ctx, const char *password)
  12.374 +{
  12.375 +	int		retval = -1;
  12.376 +	unsigned char	buf[METADATA_SIZE];
  12.377 +	unsigned char	*p = buf;
  12.378 +	unsigned char	*stretched_key = NULL;
  12.379 +	unsigned char	*key_k = NULL;
  12.380 +	unsigned char	*key_l = NULL;
  12.381 +	int		read_retval;
  12.382 +	unsigned char	salt[SALT_SIZE];
  12.383 +	unsigned char	key_digest[SHA256_DIGEST_SIZE];
  12.384 +	struct sha256_ctx md_ctx;
  12.385 +	struct twofish_ctx cipher_ctx;
  12.386 +
  12.387 +	stretched_key = pws_secure_alloc(SHA256_DIGEST_SIZE);
  12.388 +	if (stretched_key == NULL) {
  12.389 +		pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
  12.390 +		    "out of memory");
  12.391 +		goto out;
  12.392 +	}
  12.393 +
  12.394 +	key_k = pws_secure_alloc(KEY_SIZE);
  12.395 +	if (key_k == NULL) {
  12.396 +		pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
  12.397 +		    "out of memory");
  12.398 +		goto out;
  12.399 +	}
  12.400 +
  12.401 +	key_l = pws_secure_alloc(KEY_SIZE);
  12.402 +	if (key_l == NULL) {
  12.403 +		pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
  12.404 +		    "out of memory");
  12.405 +		goto out;
  12.406 +	}
  12.407 +
  12.408 +	read_retval = read_buf(ctx, buf, sizeof (buf));
  12.409 +	if (read_retval == 1) {
  12.410 +		pws_set_error(ctx->pws_file, PWS_ERR_TRUNCATED_FILE,
  12.411 +		    "unexpected end of file");
  12.412 +		goto out;
  12.413 +	} else if (read_retval != 0) {
  12.414 +		pws_set_system_error(ctx->pws_file, PWS_ERR_IO_ERROR, errno,
  12.415 +		    NULL);
  12.416 +		goto out;
  12.417 +	}
  12.418 +
  12.419 +	/* check tag */
  12.420 +	if (memcmp(p, psafe3_tag, sizeof (psafe3_tag)) != 0) {
  12.421 +		pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
  12.422 +		    "unknown filetype");
  12.423 +		goto out;
  12.424 +	}
  12.425 +	p += sizeof (psafe3_tag);
  12.426 +
  12.427 +	/* salt */
  12.428 +	memcpy(salt, p, SALT_SIZE);
  12.429 +	p += SALT_SIZE;
  12.430 +
  12.431 +	/* iterations */
  12.432 +	memcpy(&ctx->n_iter, p, 4);
  12.433 +	ctx->n_iter = le32toh(ctx->n_iter);
  12.434 +	if ((ctx->n_iter < 1) || (ctx->n_iter > MAX_ITER)) {
  12.435 +		pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
  12.436 +		    "invalid number of iterations: %d", ctx->n_iter);
  12.437 +		goto out;
  12.438 +	}
  12.439 +	p += 4;
  12.440 +
  12.441 +	/* verify password */
  12.442 +	stretch_key(stretched_key, ctx->n_iter, password, strlen(password),
  12.443 +	    salt, SALT_SIZE);
  12.444 +	sha256_init(&md_ctx);
  12.445 +	sha256_update(&md_ctx, SHA256_DIGEST_SIZE, stretched_key);
  12.446 +	sha256_digest(&md_ctx, SHA256_DIGEST_SIZE, key_digest);
  12.447 +	if (memcmp(key_digest, p, SHA256_DIGEST_SIZE) != 0) {
  12.448 +		pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
  12.449 +		    "wrong password");
  12.450 +		goto out;
  12.451 +	}
  12.452 +	p += SHA256_DIGEST_SIZE;
  12.453 +
  12.454 +	/* decrypt keys */
  12.455 +	twofish_set_key(&cipher_ctx, KEY_SIZE, stretched_key);
  12.456 +	twofish_decrypt(&cipher_ctx, KEY_SIZE, key_k, p);
  12.457 +	p += KEY_SIZE;
  12.458 +	twofish_decrypt(&cipher_ctx, KEY_SIZE, key_l, p);
  12.459 +	p += KEY_SIZE;
  12.460 +
  12.461 +	/* set key for decryption */
  12.462 +	twofish_set_key(&ctx->cipher_ctx.ctx, KEY_SIZE, key_k);
  12.463 +
  12.464 +	/* set IV */
  12.465 +	CBC_SET_IV(&ctx->cipher_ctx, p);
  12.466 +
  12.467 +	/* set key for HMAC */
  12.468 +	HMAC_SET_KEY(&ctx->hmac_ctx, &nettle_sha256, KEY_SIZE, key_l);
  12.469 +
  12.470 +	retval = 0;
  12.471 +
  12.472 +out:
  12.473 +	pws_secure_free(stretched_key, (stretched_key != NULL) ?
  12.474 +	    SHA256_DIGEST_SIZE : 0);
  12.475 +	pws_secure_free(key_l, (key_l != NULL) ? KEY_SIZE : 0);
  12.476 +	pws_secure_free(key_k, (key_k != NULL) ? KEY_SIZE : 0);
  12.477 +
  12.478 +	return (retval);
  12.479 +}
  12.480 +
  12.481 +static int
  12.482 +read_block(struct pws_file_ctx *ctx, unsigned char *block)
  12.483 +{
  12.484 +	unsigned char	buf[TWOFISH_BLOCK_SIZE];
  12.485 +	int		read_retval;
  12.486 +
  12.487 +	read_retval = read_buf(ctx, buf, sizeof (buf));
  12.488 +	if (read_retval == 1) {
  12.489 +		pws_set_error(ctx->pws_file, PWS_ERR_TRUNCATED_FILE,
  12.490 +		    "unexpected end of file");
  12.491 +		return (-1);
  12.492 +	} else if (read_retval != 0) {
  12.493 +		pws_set_system_error(ctx->pws_file, PWS_ERR_IO_ERROR, errno,
  12.494 +		    NULL);
  12.495 +		return (-1);
  12.496 +	}
  12.497 +
  12.498 +	/* reached the EOF block marking the end of encrypted records */
  12.499 +	if (memcmp(buf, eof_marker, TWOFISH_BLOCK_SIZE) == 0) {
  12.500 +		return (1);
  12.501 +	}
  12.502 +
  12.503 +	CBC_DECRYPT(&ctx->cipher_ctx, twofish_decrypt, TWOFISH_BLOCK_SIZE,
  12.504 +	    block, buf);
  12.505 +
  12.506 +	return (0);
  12.507 +}
  12.508 +
  12.509 +static int
  12.510 +read_field(struct pws_file_ctx *ctx, struct pws3_field **fieldp, int is_header)
  12.511 +{
  12.512 +	int		retval = -1;
  12.513 +	enum pws_data_type data_type;
  12.514 +	struct pws3_field *field = NULL;
  12.515 +	unsigned char	*block_buf = NULL;
  12.516 +	unsigned char	*p;
  12.517 +	int		read_retval;
  12.518 +	unsigned char	*field_buf = NULL;
  12.519 +	uint32_t	field_size;
  12.520 +	size_t		remaining;
  12.521 +	size_t		field_buf_size = 0;
  12.522 +	uint8_t field_type = 0xff;
  12.523 +	time_t		data_time;
  12.524 +	uint32_t	data_uint32;
  12.525 +	uint16_t	data_uint16;
  12.526 +	uint8_t		data_uint8;
  12.527 +
  12.528 +	block_buf = pws_secure_alloc(TWOFISH_BLOCK_SIZE);
  12.529 +	if (block_buf == NULL) {
  12.530 +		pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
  12.531 +		    "out of memory");
  12.532 +		goto out;
  12.533 +	}
  12.534 +
  12.535 +next_field:
  12.536 +	p = block_buf;
  12.537 +
  12.538 +	/* read first block */
  12.539 +	read_retval = read_block(ctx, block_buf);
  12.540 +	if (read_retval != 0) {
  12.541 +		retval = read_retval;
  12.542 +		goto out;
  12.543 +	}
  12.544 +
  12.545 +	/* determine field length */
  12.546 +	memcpy(&field_size, p, 4);
  12.547 +	remaining = field_buf_size = field_size = le32toh(field_size);
  12.548 +	p += 4;
  12.549 +	/* determine field type */
  12.550 +	memcpy(&field_type, p, 1);
  12.551 +	p++;
  12.552 +
  12.553 +	/* check for end of header fields or end of record */
  12.554 +	if ((is_header && (field_type == PWS3_HEADER_FIELD_END)) ||
  12.555 +	    (!is_header && (field_type == PWS3_RECORD_FIELD_END))) {
  12.556 +		retval = 1;
  12.557 +		goto out;
  12.558 +	}
  12.559 +
  12.560 +	/* skip empty fields */
  12.561 +	if (field_size == 0) {
  12.562 +		goto next_field;
  12.563 +	}
  12.564 +
  12.565 +	/* determine data type */
  12.566 +	data_type = pws3_field_get_data_type(&(struct pws3_field){ .is_header =
  12.567 +	    is_header, .field_type = field_type });
  12.568 +
  12.569 +	/* make room for a terminating \0 in text fields */
  12.570 +	if (data_type == PWS_DATA_TYPE_TEXT) {
  12.571 +		field_buf_size++;
  12.572 +	}
  12.573 +
  12.574 +	/* validate field length */
  12.575 +	switch (data_type) {
  12.576 +	case PWS_DATA_TYPE_UUID:
  12.577 +		if ((field_size != 0) && (field_size != PWS3_UUID_SIZE)) {
  12.578 +			pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
  12.579 +			    "invalid field length");
  12.580 +			goto out;
  12.581 +		}
  12.582 +		break;
  12.583 +	case PWS_DATA_TYPE_TIME:  /* FALLTHROUGH */
  12.584 +	case PWS_DATA_TYPE_UINT32:
  12.585 +		if ((field_size != 0) && (field_size != 4)) {
  12.586 +			pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
  12.587 +			    "invalid field length");
  12.588 +			goto out;
  12.589 +		}
  12.590 +		break;
  12.591 +	case PWS_DATA_TYPE_UINT8:
  12.592 +		if ((field_size != 0) && (field_size != 1)) {
  12.593 +			pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
  12.594 +			    "invalid field length");
  12.595 +			goto out;
  12.596 +		}
  12.597 +		break;
  12.598 +	case PWS_DATA_TYPE_UINT16:
  12.599 +		if ((field_size != 0) && (field_size != 2)) {
  12.600 +			pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
  12.601 +			    "invalid field length");
  12.602 +			goto out;
  12.603 +		}
  12.604 +		break;
  12.605 +	default:
  12.606 +		/* text or bytes */
  12.607 +		if ((!is_header &&
  12.608 +		    (field_type == PWS3_RECORD_FIELD_PASSWORD) &&
  12.609 +		    (field_buf_size > PWS3_MAX_PASSWORD_LEN)) ||
  12.610 +		    (field_buf_size > PWS3_MAX_FIELD_SIZE)) {
  12.611 +			pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
  12.612 +			    "invalid field length");
  12.613 +			goto out;
  12.614 +		}
  12.615 +	}
  12.616 +
  12.617 +	field = pws3_field_create(is_header, field_type);
  12.618 +	if (field == NULL) {
  12.619 +		pws_set_system_error(ctx->pws_file, PWS_ERR_NO_MEMORY, errno,
  12.620 +		    NULL);
  12.621 +		goto out;
  12.622 +	}
  12.623 +
  12.624 +	/* create field */
  12.625 +	if (field_buf_size > 0) {
  12.626 +		if (!is_header && (field_type == PWS3_RECORD_FIELD_PASSWORD)) {
  12.627 +			field_buf = pws_secure_alloc(field_buf_size);
  12.628 +		} else {
  12.629 +			field_buf = pws_alloc(field_buf_size);
  12.630 +		}
  12.631 +		if (field_buf == NULL) {
  12.632 +			pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
  12.633 +			    "out of memory");
  12.634 +			goto out;
  12.635 +		}
  12.636 +		memset(field_buf, 0, field_buf_size);
  12.637 +
  12.638 +		memcpy(field_buf, p, MIN(remaining,
  12.639 +		    (size_t)TWOFISH_BLOCK_SIZE - (p - block_buf)));
  12.640 +		remaining -= MIN(remaining,
  12.641 +		    (size_t)TWOFISH_BLOCK_SIZE - (p - block_buf));
  12.642 +
  12.643 +		while (remaining > 0) {
  12.644 +			read_retval = read_block(ctx, block_buf);
  12.645 +			if (read_retval != 0) {
  12.646 +				goto out;
  12.647 +			}
  12.648 +			memcpy(field_buf + (field_size - remaining),
  12.649 +			    block_buf, MIN(remaining, TWOFISH_BLOCK_SIZE));
  12.650 +			remaining -= MIN(remaining, TWOFISH_BLOCK_SIZE);
  12.651 +		}
  12.652 +
  12.653 +		hmac_sha256_update(&ctx->hmac_ctx, field_size, field_buf);
  12.654 +
  12.655 +		switch (data_type) {
  12.656 +		case PWS_DATA_TYPE_UUID:
  12.657 +			retval = pws3_field_set_uuid(field, field_buf);
  12.658 +			break;
  12.659 +		case PWS_DATA_TYPE_TEXT:
  12.660 +			retval = pws3_field_set_text(field, (char *)field_buf);
  12.661 +			break;
  12.662 +		case PWS_DATA_TYPE_TIME:
  12.663 +			memcpy(&data_uint32, field_buf, 4);
  12.664 +			data_time = le32toh(data_uint32);
  12.665 +			retval = pws3_field_set_time(field, data_time);
  12.666 +			break;
  12.667 +		case PWS_DATA_TYPE_UINT8:
  12.668 +			memcpy(&data_uint8, field_buf, 1);
  12.669 +			retval = pws3_field_set_uint8(field, data_uint8);
  12.670 +			break;
  12.671 +		case PWS_DATA_TYPE_UINT16:
  12.672 +			memcpy(&data_uint16, field_buf, 2);
  12.673 +			data_uint16 = le16toh(data_uint16);
  12.674 +			retval = pws3_field_set_uint16(field, data_uint16);
  12.675 +			break;
  12.676 +		case PWS_DATA_TYPE_UINT32:
  12.677 +			memcpy(&data_uint32, field_buf, 4);
  12.678 +			data_uint32 = le32toh(data_uint32);
  12.679 +			retval = pws3_field_set_uint32(field, data_uint32);
  12.680 +			break;
  12.681 +		case PWS_DATA_TYPE_BYTES:
  12.682 +			retval = pws3_field_set_bytes(field, field_buf,
  12.683 +			    field_buf_size);
  12.684 +		}
  12.685 +		if (retval != 0) {
  12.686 +			goto out;
  12.687 +		}
  12.688 +	}
  12.689 +
  12.690 +	retval = 0;
  12.691 +
  12.692 +out:
  12.693 +	if (!is_header && (field_type == PWS3_RECORD_FIELD_PASSWORD)) {
  12.694 +		pws_secure_free(field_buf, field_buf_size);
  12.695 +	} else {
  12.696 +		pws_free(field_buf, field_buf_size);
  12.697 +	}
  12.698 +	pws_secure_free(block_buf, (block_buf != NULL) ?
  12.699 +	    (size_t)TWOFISH_BLOCK_SIZE : 0);
  12.700 +
  12.701 +	if (retval == 0) {
  12.702 +		*fieldp = field;
  12.703 +	} else {
  12.704 +		pws3_field_destroy(field);
  12.705 +	}
  12.706 +
  12.707 +	return (retval);
  12.708 +}
  12.709 +
  12.710 +static int
  12.711 +read_header(struct pws_file_ctx *ctx)
  12.712 +{
  12.713 +	int		retval;
  12.714 +	struct pws3_field *field = NULL;
  12.715 +
  12.716 +	/* the header must start with a version field */
  12.717 +	retval = read_field(ctx, &field, 1);
  12.718 +	if (retval != 0) {
  12.719 +		/* error or end of headers */
  12.720 +		pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
  12.721 +		    "header does not start with a version field");
  12.722 +		return (-1);
  12.723 +	} else if (field->field_type != PWS3_HEADER_FIELD_VERSION) {
  12.724 +		/* header does not start with a version field */
  12.725 +		pws3_field_destroy(field);
  12.726 +		pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
  12.727 +		    "header does not start with a version field");
  12.728 +		return (-1);
  12.729 +	} else if (field->value.uint16 > PWS3_VERSION) {
  12.730 +		/* unsupported database version */
  12.731 +		pws3_field_destroy(field);
  12.732 +		pws_set_error(ctx->pws_file, PWS_ERR_UNSUPPORTED_VERSION,
  12.733 +		    "unsupported database version");
  12.734 +		return (-1);
  12.735 +	}
  12.736 +	pws3_file_set_header_field(ctx->pws_file, field);
  12.737 +
  12.738 +	for (;;) {
  12.739 +		retval = read_field(ctx, &field, 1);
  12.740 +		if (retval == 1) {
  12.741 +			/* end of headers */
  12.742 +			pws_set_error(ctx->pws_file, PWS_ERR_INVALID_HEADER,
  12.743 +			    "unexpected end of headers");
  12.744 +			break;
  12.745 +		} else if (retval != 0) {
  12.746 +			return (-1);
  12.747 +		}
  12.748 +		pws3_file_set_header_field(ctx->pws_file, field);
  12.749 +	}
  12.750 +
  12.751 +	return (0);
  12.752 +}
  12.753 +
  12.754 +static int
  12.755 +read_records(struct pws_file_ctx *ctx)
  12.756 +{
  12.757 +	int		retval;
  12.758 +	struct pws3_record *record = NULL;
  12.759 +	struct pws3_field *field = NULL;
  12.760 +
  12.761 +	for (;;) {
  12.762 +		/*
  12.763 +		 * a record must consist of at least three fields, instead of
  12.764 +		 * the first field there could also be an EOF marker
  12.765 +		 */
  12.766 +		retval = read_field(ctx, &field, 0);
  12.767 +		if (retval == 1) {
  12.768 +			/* EOF marker */
  12.769 +			retval = 0;
  12.770 +			goto out;
  12.771 +		} else if (retval != 0) {
  12.772 +			/* read error */
  12.773 +			goto out;
  12.774 +		} else if (field->field_type == PWS3_RECORD_FIELD_END) {
  12.775 +			/* empty record */
  12.776 +			retval = -1;
  12.777 +			goto out;
  12.778 +		}
  12.779 +
  12.780 +		record = pws3_record_create();
  12.781 +		if (record == NULL) {
  12.782 +			pws_set_system_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
  12.783 +			    errno, NULL);
  12.784 +			goto out;
  12.785 +		}
  12.786 +
  12.787 +		pws3_record_set_field(record, field);
  12.788 +		field = NULL;
  12.789 +
  12.790 +		/* read the remaining fileds */
  12.791 +		for (;;) {
  12.792 +			retval = read_field(ctx, &field, 0);
  12.793 +			if (retval == 1) {
  12.794 +				/* end of record */
  12.795 +				break;
  12.796 +			} else if (retval != 0) {
  12.797 +				/* read error */
  12.798 +				retval = -1;
  12.799 +				goto out;
  12.800 +			}
  12.801 +			pws3_record_set_field(record, field);
  12.802 +			field = NULL;
  12.803 +		}
  12.804 +
  12.805 +		/* check whether UUID is not empty */
  12.806 +		if (pws3_record_get_field(record, PWS3_RECORD_FIELD_UUID) ==
  12.807 +		    NULL) {
  12.808 +			/* record is missing mandatory fields */
  12.809 +			pws_set_error(ctx->pws_file, PWS_ERR_INVALID_RECORD,
  12.810 +			    "record is missing mandatory fields");
  12.811 +			pws3_record_destroy(record);
  12.812 +			retval = -1;
  12.813 +			goto out;
  12.814 +		}
  12.815 +
  12.816 +		pws3_file_insert_record(ctx->pws_file, record);
  12.817 +		record = NULL;
  12.818 +	}
  12.819 +
  12.820 +out:
  12.821 +	if (retval != 0) {
  12.822 +		pws3_field_destroy(field);
  12.823 +		pws3_record_destroy(record);
  12.824 +	}
  12.825 +
  12.826 +	return (retval);
  12.827 +}
  12.828 +
  12.829 +static int
  12.830 +verify_checksum(struct pws_file_ctx *ctx)
  12.831 +{
  12.832 +	int		retval;
  12.833 +	unsigned char	hmac_file[SHA256_DIGEST_SIZE];
  12.834 +	unsigned char	hmac[SHA256_DIGEST_SIZE];
  12.835 +
  12.836 +	retval = read_buf(ctx, hmac_file, sizeof (hmac_file));
  12.837 +	if (retval == 1) {
  12.838 +		pws_set_error(ctx->pws_file, PWS_ERR_TRUNCATED_FILE,
  12.839 +		    "unexpected end of file");
  12.840 +		return (-1);
  12.841 +	} else if (retval != 0) {
  12.842 +		pws_set_system_error(ctx->pws_file, PWS_ERR_IO_ERROR, errno,
  12.843 +		    NULL);
  12.844 +		return (-1);
  12.845 +	}
  12.846 +
  12.847 +	hmac_sha256_digest(&ctx->hmac_ctx, sizeof (hmac), hmac);
  12.848 +	if (memcmp(hmac_file, hmac, sizeof (hmac_file)) != 0) {
  12.849 +		/* inconsistent database */
  12.850 +		pws_set_error(ctx->pws_file, PWS_ERR_INVALID_CHECKSUM,
  12.851 +		    "checksum failed");
  12.852 +		return (-1);
  12.853 +	}
  12.854 +
  12.855 +	return (0);
  12.856 +}
  12.857 +
  12.858 +static int
  12.859 +pws3_file_read(struct pws3_file *pws_file, const char *password,
  12.860 +    unsigned char *s, size_t n, FILE *fp)
  12.861 +{
  12.862 +	int		retval = -1;
  12.863 +	struct pws_file_ctx	ctx = {
  12.864 +		.fp = fp,
  12.865 +		.mem = s,
  12.866 +		.mem_size = n,
  12.867 +		.mem_pos = 0,
  12.868 +		.pws_file = pws_file,
  12.869 +	};
  12.870 +
  12.871 +	pws_file_clear(pws_file);
  12.872 +
  12.873 +	retval = read_metadata(&ctx, password);
  12.874 +	if (retval != 0) {
  12.875 +		goto out;
  12.876 +	}
  12.877 +
  12.878 +	retval = read_header(&ctx);
  12.879 +	if (retval != 0) {
  12.880 +		goto out;
  12.881 +	}
  12.882 +
  12.883 +	retval = read_records(&ctx);
  12.884 +	if (retval != 0) {
  12.885 +		goto out;
  12.886 +	}
  12.887 +
  12.888 +	retval = verify_checksum(&ctx);
  12.889 +	if (retval != 0) {
  12.890 +		goto out;
  12.891 +	}
  12.892 +
  12.893 +out:
  12.894 +	if (retval != 0) {
  12.895 +		pws_file_clear(ctx.pws_file);
  12.896 +	}
  12.897 +
  12.898 +	return (retval);
  12.899 +}
  12.900 +
  12.901 +int
  12.902 +pws3_file_read_mem(struct pws3_file *pws_file, const char *password,
  12.903 +    unsigned char *s, size_t n)
  12.904 +{
  12.905 +	return (pws3_file_read(pws_file, password, s, n, NULL));
  12.906 +}
  12.907 +
  12.908 +int
  12.909 +pws3_file_read_stream(struct pws3_file *pws_file, const char *password,
  12.910 +    FILE *fp)
  12.911 +{
  12.912 +	return (pws3_file_read(pws_file, password, NULL, 0, fp));
  12.913 +}
  12.914 +
  12.915 +static int
  12.916 +write_metadata(struct pws_file_ctx *ctx, const char *password)
  12.917 +{
  12.918 +	int		retval = -1;
  12.919 +	unsigned char	*stretched_key = NULL;
  12.920 +	unsigned char	*key_k = NULL;
  12.921 +	unsigned char	*key_l = NULL;
  12.922 +	unsigned char	metadata[METADATA_SIZE];
  12.923 +	unsigned char	*p = metadata;
  12.924 +	unsigned char	*salt;
  12.925 +	uint32_t	n_iter_le;
  12.926 +	struct sha256_ctx md_ctx;
  12.927 +	unsigned char	*b1;
  12.928 +	unsigned char	*b3;
  12.929 +	unsigned char	*iv;
  12.930 +	struct twofish_ctx cipher_ctx;
  12.931 +
  12.932 +	stretched_key = pws_secure_alloc(SHA256_DIGEST_SIZE);
  12.933 +	if (stretched_key == NULL) {
  12.934 +		pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
  12.935 +		    "out of memory");
  12.936 +		goto out;
  12.937 +	}
  12.938 +
  12.939 +	key_k = pws_secure_alloc(KEY_SIZE);
  12.940 +	if (key_k == NULL) {
  12.941 +		pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
  12.942 +		    "out of memory");
  12.943 +		goto out;
  12.944 +	}
  12.945 +
  12.946 +	key_l = pws_secure_alloc(KEY_SIZE);
  12.947 +	if (key_l == NULL) {
  12.948 +		pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
  12.949 +		    "out of memory");
  12.950 +		goto out;
  12.951 +	}
  12.952 +
  12.953 +	/* generate new keys */
  12.954 +	if (pws_random_bytes(key_k, KEY_SIZE) != 0) {
  12.955 +		pws_set_error(ctx->pws_file, PWS_ERR_GENERIC_ERROR,
  12.956 +		    "failed to generate key");
  12.957 +		goto out;
  12.958 +	}
  12.959 +
  12.960 +	if (pws_random_bytes(key_l, KEY_SIZE) != 0) {
  12.961 +		pws_set_error(ctx->pws_file, PWS_ERR_GENERIC_ERROR,
  12.962 +		    "failed to generate key");
  12.963 +		goto out;
  12.964 +	}
  12.965 +
  12.966 +	/* tag */
  12.967 +	memcpy(p, psafe3_tag, sizeof (psafe3_tag));
  12.968 +	p += sizeof (psafe3_tag);
  12.969 +
  12.970 +	/* generate new salt */
  12.971 +	salt = p;
  12.972 +	if (pws_random_bytes(salt, SALT_SIZE) != 0) {
  12.973 +		pws_set_error(ctx->pws_file, PWS_ERR_GENERIC_ERROR,
  12.974 +		    "failed to generate salt");
  12.975 +		goto out;
  12.976 +	}
  12.977 +	p += SALT_SIZE;
  12.978 +
  12.979 +	/* number of iterations */
  12.980 +	n_iter_le = htole32(ctx->n_iter);
  12.981 +	memcpy(p, &n_iter_le, 4);
  12.982 +	p += 4;
  12.983 +
  12.984 +	/* stretch, hash password */
  12.985 +	stretch_key(stretched_key, ctx->n_iter, password, strlen(password),
  12.986 +	    salt, SALT_SIZE);
  12.987 +	sha256_init(&md_ctx);
  12.988 +	sha256_update(&md_ctx, SHA256_DIGEST_SIZE, stretched_key);
  12.989 +	sha256_digest(&md_ctx, SHA256_DIGEST_SIZE, p);
  12.990 +	p += SHA256_DIGEST_SIZE;
  12.991 +
  12.992 +	b1 = p;
  12.993 +	p += KEY_SIZE;
  12.994 +
  12.995 +	b3 = p;
  12.996 +	p += KEY_SIZE;
  12.997 +
  12.998 +	/* generate IV */
  12.999 +	iv = p;
 12.1000 +	if (pws_random_bytes(iv, TWOFISH_BLOCK_SIZE) != 0) {
 12.1001 +		pws_set_error(ctx->pws_file, PWS_ERR_GENERIC_ERROR,
 12.1002 +		    "failed to generate IV");
 12.1003 +		goto out;
 12.1004 +	}
 12.1005 +
 12.1006 +	/* encrypt keys */
 12.1007 +	twofish_set_key(&cipher_ctx, KEY_SIZE, stretched_key);
 12.1008 +	twofish_encrypt(&cipher_ctx, KEY_SIZE, b1, key_k);
 12.1009 +	twofish_encrypt(&cipher_ctx, KEY_SIZE, b3, key_l);
 12.1010 +
 12.1011 +	/* set key for decryption */
 12.1012 +	twofish_set_key(&ctx->cipher_ctx.ctx, KEY_SIZE, key_k);
 12.1013 +
 12.1014 +	/* set IV */
 12.1015 +	CBC_SET_IV(&ctx->cipher_ctx, p);
 12.1016 +
 12.1017 +	/* set key for HMAC */
 12.1018 +	hmac_sha256_set_key(&ctx->hmac_ctx, KEY_SIZE, key_l);
 12.1019 +
 12.1020 +	/* write metadata */
 12.1021 +	if (write_buf(ctx, metadata, sizeof (metadata)) != 0) {
 12.1022 +		pws_set_system_error(ctx->pws_file, PWS_ERR_IO_ERROR, errno,
 12.1023 +		    NULL);
 12.1024 +		retval = -1;
 12.1025 +		goto out;
 12.1026 +	}
 12.1027 +
 12.1028 +	retval = 0;
 12.1029 +
 12.1030 +out:
 12.1031 +	pws_secure_free(key_k, (key_k != NULL) ? KEY_SIZE : 0);
 12.1032 +	pws_secure_free(key_l, (key_l != NULL) ? KEY_SIZE : 0);
 12.1033 +	pws_secure_free(stretched_key, (stretched_key != NULL) ?
 12.1034 +	    SHA256_DIGEST_SIZE : 0);
 12.1035 +
 12.1036 +	return (retval);
 12.1037 +}
 12.1038 +
 12.1039 +static int
 12.1040 +write_block(struct pws_file_ctx *ctx, unsigned char *block)
 12.1041 +{
 12.1042 +	unsigned char	buf[TWOFISH_BLOCK_SIZE];
 12.1043 +
 12.1044 +	CBC_ENCRYPT(&ctx->cipher_ctx, twofish_encrypt, sizeof (buf), buf,
 12.1045 +	    block);
 12.1046 +
 12.1047 +	if (write_buf(ctx, buf, sizeof (buf)) != 0) {
 12.1048 +		pws_set_system_error(ctx->pws_file, PWS_ERR_IO_ERROR, errno,
 12.1049 +		    NULL);
 12.1050 +		return (-1);
 12.1051 +	}
 12.1052 +
 12.1053 +	return (0);
 12.1054 +}
 12.1055 +
 12.1056 +static int
 12.1057 +write_field(struct pws_file_ctx *ctx, struct pws3_field *field)
 12.1058 +{
 12.1059 +	int		retval = -1;
 12.1060 +	unsigned char	*buf = NULL;
 12.1061 +	unsigned char	*p;
 12.1062 +	unsigned char	*field_data;
 12.1063 +	enum pws_data_type data_type;
 12.1064 +	size_t		blocks = (field->size + 4 + 1) / TWOFISH_BLOCK_SIZE +
 12.1065 +	    ((field->size + 4 + 1) % TWOFISH_BLOCK_SIZE != 0);
 12.1066 +	size_t		i;
 12.1067 +	size_t		j;
 12.1068 +	uint32_t	len_le;
 12.1069 +
 12.1070 +	buf = pws_secure_alloc(TWOFISH_BLOCK_SIZE);
 12.1071 +	if (buf == NULL) {
 12.1072 +		pws_set_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
 12.1073 +		    "out of memory");
 12.1074 +		goto out;
 12.1075 +	}
 12.1076 +
 12.1077 +	data_type = pws3_field_get_data_type(field);
 12.1078 +
 12.1079 +	for (i = 0, j = 0; i < blocks; i++) {
 12.1080 +		p = field_data = buf;
 12.1081 +		if (pws_random_bytes(buf, TWOFISH_BLOCK_SIZE) != 0) {
 12.1082 +			pws_set_error(ctx->pws_file, PWS_ERR_GENERIC_ERROR,
 12.1083 +			    "could not get random numbers");
 12.1084 +			goto out;
 12.1085 +		}
 12.1086 +
 12.1087 +		/* the first block of the field contains the length and type */
 12.1088 +		if (i == 0) {
 12.1089 +			len_le = htole32(field->size);
 12.1090 +			memcpy(p, &len_le, 4);
 12.1091 +			p += 4;
 12.1092 +
 12.1093 +			*p = field->field_type;
 12.1094 +			p++;
 12.1095 +			field_data = p;
 12.1096 +		}
 12.1097 +
 12.1098 +		while ((j < field->size) &&
 12.1099 +		    (p - buf < (ptrdiff_t)TWOFISH_BLOCK_SIZE)) {
 12.1100 +			switch (data_type) {
 12.1101 +			case PWS_DATA_TYPE_UINT8:
 12.1102 +				*p = field->value.uint8;
 12.1103 +				break;
 12.1104 +			case PWS_DATA_TYPE_UINT16:
 12.1105 +				/* little endian */
 12.1106 +				*p = (field->value.uint16 >> (8 * j)) & 0xff;
 12.1107 +				break;
 12.1108 +			case PWS_DATA_TYPE_TIME: /* FALLTHROUGH */
 12.1109 +			case PWS_DATA_TYPE_UINT32:
 12.1110 +				/* little endian */
 12.1111 +				*p = (field->value.uint32 >> (8 * j)) & 0xff;
 12.1112 +				break;
 12.1113 +			case PWS_DATA_TYPE_TEXT:
 12.1114 +				*p = field->value.text[j];
 12.1115 +				break;
 12.1116 +			case PWS_DATA_TYPE_UUID:
 12.1117 +				*p = field->value.uuid[j];
 12.1118 +				break;
 12.1119 +			default:
 12.1120 +				*p = field->value.bytes[j];
 12.1121 +			}
 12.1122 +
 12.1123 +			p++;
 12.1124 +			j++;
 12.1125 +		}
 12.1126 +
 12.1127 +		hmac_sha256_update(&ctx->hmac_ctx, p - field_data, field_data);
 12.1128 +
 12.1129 +		retval = write_block(ctx, buf);
 12.1130 +		if (retval != 0) {
 12.1131 +			goto out;
 12.1132 +		}
 12.1133 +	}
 12.1134 +
 12.1135 +	retval = 0;
 12.1136 +
 12.1137 +out:
 12.1138 +	pws_secure_free(buf, (buf != NULL) ? TWOFISH_BLOCK_SIZE : 0);
 12.1139 +
 12.1140 +	return (retval);
 12.1141 +}
 12.1142 +
 12.1143 +static int
 12.1144 +write_header(struct pws_file_ctx *ctx)
 12.1145 +{
 12.1146 +	int		retval = -1;
 12.1147 +	size_t		i;
 12.1148 +	struct pws3_field *version_field;
 12.1149 +	struct pws3_field *field = NULL;
 12.1150 +	struct pws3_field *end_field = NULL;
 12.1151 +
 12.1152 +	version_field = pws3_file_get_header_field(ctx->pws_file,
 12.1153 +	    PWS3_HEADER_FIELD_VERSION);
 12.1154 +	if (version_field == NULL) {
 12.1155 +		/* add mandatory version header version_field if necessary */
 12.1156 +		version_field = pws3_field_create(1, PWS3_HEADER_FIELD_VERSION);
 12.1157 +		if (version_field == NULL) {
 12.1158 +			pws_set_system_error(ctx->pws_file, PWS_ERR_NO_MEMORY,
 12.1159 +			    errno, NULL);
 12.1160 +			goto out;
 12.1161 +		}
 12.1162 +		pws3_field_set_uint16(version_field, PWS3_VERSION);
 12.1163 +		pws3_file_set_header_field(ctx->pws_file, version_field);
 12.1164 +	}
 12.1165 +	retval = write_field(ctx, version_field);
 12.1166 +	if (retval != 0) {
 12.1167 +		goto out;
 12.1168 +	}
 12.1169 +
 12.1170 +	for (i = 0x01; i < 0xff; i++) {
 12.1171 +		if (ctx->pws_file->fields[i] != NULL) {
 12.1172 +			retval = write_field(ctx, ctx->pws_file->fields[i]);
 12.1173 +			if (retval != 0) {
 12.1174 +				goto out;
 12.1175 +			}
 12.1176 +		}
 12.1177 +	}
 12.1178 +
 12.1179 +	RB_FOREACH(field, empty_groups_tree, ctx->pws_file->empty_groups_tree) {
 12.1180 +		retval = write_field(ctx, field);
 12.1181 +		if (retval != 0) {
 12.1182 +			goto out;
 12.1183 +		}
 12.1184 +	}
 12.1185 +
 12.1186 +	end_field = pws3_field_create(1, PWS3_HEADER_FIELD_END);
 12.1187 +	retval = write_field(ctx, end_field);
 12.1188 +	if (retval != 0) {
 12.1189 +		goto out;
 12.1190 +	}
 12.1191 +
 12.1192 +out:
 12.1193 +	pws3_field_destroy(end_field);
 12.1194 +
 12.1195 +	return (retval);
 12.1196 +}
 12.1197 +
 12.1198 +static int
 12.1199 +write_records(struct pws_file_ctx *ctx)
 12.1200 +{
 12.1201 +	int		retval = -1;
 12.1202 +	struct pws3_field *end_field = NULL;
 12.1203 +	size_t		i;
 12.1204 +	struct pws3_record *record;
 12.1205 +
 12.1206 +	end_field = pws3_field_create(0, PWS3_RECORD_FIELD_END);
 12.1207 +	if (end_field == NULL) {
 12.1208 +		pws_set_system_error(ctx->pws_file, PWS_ERR_NO_MEMORY, errno,
 12.1209 +		    NULL);
 12.1210 +		goto out;
 12.1211 +	}
 12.1212 +
 12.1213 +	RB_FOREACH(record, records_tree, ctx->pws_file->records_tree) {
 12.1214 +		/* record fields */
 12.1215 +		for (i = 0x01; i < 0xff; i++) {
 12.1216 +			if (record->fields[i] != NULL) {
 12.1217 +				retval = write_field(ctx, record->fields[i]);
 12.1218 +				if (retval != 0) {
 12.1219 +					goto out;
 12.1220 +				}
 12.1221 +			}
 12.1222 +		}
 12.1223 +
 12.1224 +		/* end of entry marker */
 12.1225 +		retval = write_field(ctx, end_field);
 12.1226 +		if (retval != 0) {
 12.1227 +			goto out;
 12.1228 +		}
 12.1229 +	}
 12.1230 +
 12.1231 +	/* end of file marker */
 12.1232 +	if (write_buf(ctx, eof_marker, sizeof (eof_marker)) != 0) {
 12.1233 +		pws_set_system_error(ctx->pws_file, PWS_ERR_IO_ERROR, errno,
 12.1234 +		    NULL);
 12.1235 +		retval = -1;
 12.1236 +		goto out;
 12.1237 +	}
 12.1238 +
 12.1239 +	retval = 0;
 12.1240 +
 12.1241 +out:
 12.1242 +	pws3_field_destroy(end_field);
 12.1243 +
 12.1244 +	return (retval);
 12.1245 +}
 12.1246 +
 12.1247 +static int
 12.1248 +write_checksum(struct pws_file_ctx *ctx)
 12.1249 +{
 12.1250 +	unsigned char	hmac[SHA256_DIGEST_SIZE];
 12.1251 +
 12.1252 +	hmac_sha256_digest(&ctx->hmac_ctx, sizeof (hmac), hmac);
 12.1253 +
 12.1254 +	if (write_buf(ctx, hmac, sizeof (hmac)) != 0) {
 12.1255 +		pws_set_system_error(ctx->pws_file, PWS_ERR_IO_ERROR, errno,
 12.1256 +		    NULL);
 12.1257 +		return (-1);
 12.1258 +	}
 12.1259 +
 12.1260 +	return (0);
 12.1261 +}
 12.1262 +
 12.1263 +static int
 12.1264 +pws3_file_write(struct pws3_file *pws_file, const char *password,
 12.1265 +    uint32_t n_iter, unsigned char **memp, size_t *mem_sizep, FILE *fp)
 12.1266 +{
 12.1267 +	int		retval = -1;
 12.1268 +	struct pws_file_ctx	ctx = {
 12.1269 +		.fp = fp,
 12.1270 +		.pws_file = pws_file,
 12.1271 +		.n_iter = n_iter
 12.1272 +	};
 12.1273 +
 12.1274 +	retval = write_metadata(&ctx, password);
 12.1275 +	if (retval != 0) {
 12.1276 +		goto out;
 12.1277 +	}
 12.1278 +
 12.1279 +	retval = write_header(&ctx);
 12.1280 +	if (retval != 0) {
 12.1281 +		goto out;
 12.1282 +	}
 12.1283 +
 12.1284 +	retval = write_records(&ctx);
 12.1285 +	if (retval != 0) {
 12.1286 +		goto out;
 12.1287 +	}
 12.1288 +
 12.1289 +	retval = write_checksum(&ctx);
 12.1290 +	if (retval != 0) {
 12.1291 +		goto out;
 12.1292 +	}
 12.1293 +
 12.1294 +	if (memp != NULL) {
 12.1295 +		*memp = ctx.mem;
 12.1296 +		*mem_sizep = ctx.mem_size;
 12.1297 +	}
 12.1298 +
 12.1299 +out:
 12.1300 +	if (retval != 0) {
 12.1301 +		pws_free(ctx.mem, ctx.mem_size);
 12.1302 +	}
 12.1303 +
 12.1304 +	return (retval);
 12.1305 +}
 12.1306 +
 12.1307 +int
 12.1308 +pws3_file_write_mem(struct pws3_file *pws_file, const char *password,
 12.1309 +    uint32_t n_iter, unsigned char **memp, size_t *mem_sizep)
 12.1310 +{
 12.1311 +	PWS_ASSERT(memp != NULL);
 12.1312 +	PWS_ASSERT(mem_sizep != NULL);
 12.1313 +
 12.1314 +	return (pws3_file_write(pws_file, password, n_iter, memp, mem_sizep,
 12.1315 +	    NULL));
 12.1316 +}
 12.1317 +
 12.1318 +int
 12.1319 +pws3_file_write_stream(struct pws3_file *pws_file, const char *password,
 12.1320 +    uint32_t n_iter, FILE *fp)
 12.1321 +{
 12.1322 +	PWS_ASSERT(fp != NULL);
 12.1323 +
 12.1324 +	return (pws3_file_write(pws_file, password, n_iter, NULL, NULL, fp));
 12.1325 +}
 12.1326 +
 12.1327 +void
 12.1328 +pws3_file_set_header_field(struct pws3_file *pws_file, struct pws3_field *field)
 12.1329 +{
 12.1330 +	PWS_ASSERT(pws3_field_is_header(field));
 12.1331 +	PWS_ASSERT((pws3_field_get_data_type(field) != PWS_DATA_TYPE_TEXT) ||
 12.1332 +	    (field->value.text != NULL));
 12.1333 +	PWS_ASSERT((pws3_field_get_data_type(field) != PWS_DATA_TYPE_BYTES) ||
 12.1334 +	    (field->value.bytes != NULL));
 12.1335 +
 12.1336 +	if (field->field_type == PWS3_HEADER_FIELD_EMPTY_GROUPS) {
 12.1337 +		pws3_file_insert_empty_group(pws_file, field);
 12.1338 +		return;
 12.1339 +	}
 12.1340 +
 12.1341 +	pws3_field_destroy(pws3_file_remove_header_field(pws_file,
 12.1342 +	    field->field_type));
 12.1343 +	pws_file->fields[field->field_type] = field;
 12.1344 +}
 12.1345 +
 12.1346 +struct pws3_field *
 12.1347 +pws3_file_get_header_field(struct pws3_file *pws_file, uint8_t field_type)
 12.1348 +{
 12.1349 +	if (field_type == PWS3_HEADER_FIELD_EMPTY_GROUPS) {
 12.1350 +		return (pws3_file_first_empty_group(pws_file));
 12.1351 +	}
 12.1352 +
 12.1353 +	return (pws_file->fields[field_type]);
 12.1354 +}
 12.1355 +
 12.1356 +struct pws3_field *
 12.1357 +pws3_file_remove_header_field(struct pws3_file *pws_file, uint8_t field_type)
 12.1358 +{
 12.1359 +	struct pws3_field	*field;
 12.1360 +
 12.1361 +	if (field_type == PWS3_HEADER_FIELD_EMPTY_GROUPS) {
 12.1362 +		return (NULL);
 12.1363 +	}
 12.1364 +
 12.1365 +	field = pws3_file_get_header_field(pws_file, field_type);
 12.1366 +	pws_file->fields[field_type] = NULL;
 12.1367 +
 12.1368 +	return (field);
 12.1369 +}
 12.1370 +
 12.1371 +void
 12.1372 +pws3_file_insert_empty_group(struct pws3_file *pws_file,
 12.1373 +    struct pws3_field *field)
 12.1374 +{
 12.1375 +	const char	*group_name;
 12.1376 +
 12.1377 +	PWS_ASSERT(pws3_field_is_header(field));
 12.1378 +	PWS_ASSERT(pws3_field_get_type(field) ==
 12.1379 +	    PWS3_HEADER_FIELD_EMPTY_GROUPS);
 12.1380 +
 12.1381 +	group_name = pws3_field_get_text(field);
 12.1382 +	pws3_field_destroy(pws3_file_remove_empty_group(pws_file, group_name));
 12.1383 +	RB_INSERT(empty_groups_tree, pws_file->empty_groups_tree, field);
 12.1384 +}
 12.1385 +
 12.1386 +struct pws3_field *
 12.1387 +pws3_file_get_empty_group(struct pws3_file *pws_file, const char *group_name)
 12.1388 +{
 12.1389 +	return (RB_FIND(empty_groups_tree, pws_file->empty_groups_tree,
 12.1390 +	    (&(struct pws3_field){ .is_header = 1,
 12.1391 +	    .field_type = PWS3_HEADER_FIELD_EMPTY_GROUPS,
 12.1392 +	    .value.text = (char *)group_name })));
 12.1393 +}
 12.1394 +
 12.1395 +struct pws3_field *
 12.1396 +pws3_file_remove_empty_group(struct pws3_file *pws_file, const char *group_name)
 12.1397 +{
 12.1398 +	struct pws3_field *field;
 12.1399 +
 12.1400 +	field = RB_FIND(empty_groups_tree, pws_file->empty_groups_tree,
 12.1401 +	    (&(struct pws3_field){ .is_header = 1,
 12.1402 +	    .field_type = PWS3_HEADER_FIELD_EMPTY_GROUPS,
 12.1403 +	    .value.text = (char *)group_name }));
 12.1404 +	if (field != NULL) {
 12.1405 +		RB_REMOVE(empty_groups_tree, pws_file->empty_groups_tree,
 12.1406 +		    field);
 12.1407 +	}
 12.1408 +
 12.1409 +	return (field);
 12.1410 +}
 12.1411 +
 12.1412 +struct pws3_field *
 12.1413 +pws3_file_first_empty_group(struct pws3_file *pws_file)
 12.1414 +{
 12.1415 +	return (RB_MIN(empty_groups_tree, pws_file->empty_groups_tree));
 12.1416 +}
 12.1417 +
 12.1418 +struct pws3_field *
 12.1419 +pws3_file_last_empty_group(struct pws3_file *pws_file)
 12.1420 +{
 12.1421 +	return (RB_MAX(empty_groups_tree, pws_file->empty_groups_tree));
 12.1422 +}
 12.1423 +
 12.1424 +struct pws3_field *
 12.1425 +pws3_file_next_empty_group(struct pws3_file *pws_file, struct pws3_field *field)
 12.1426 +{
 12.1427 +	return (RB_NEXT(empty_groups_tree, pws_file->empty_groups_tree, field));
 12.1428 +}
 12.1429 +
 12.1430 +struct pws3_field *
 12.1431 +pws3_file_prev_empty_group(struct pws3_file *pws_file, struct pws3_field *field)
 12.1432 +{
 12.1433 +	return (RB_PREV(empty_groups_tree, pws_file->empty_groups_tree, field));
 12.1434 +}
 12.1435 +
 12.1436 +void
 12.1437 +pws3_file_insert_record(struct pws3_file *pws_file, struct pws3_record *record)
 12.1438 +{
 12.1439 +	struct pws3_field	*uuid_field;
 12.1440 +	const unsigned char	*uuid;
 12.1441 +
 12.1442 +	uuid_field = pws3_record_get_field(record, PWS3_RECORD_FIELD_UUID);
 12.1443 +	PWS_ASSERT(uuid_field != NULL);
 12.1444 +	uuid = pws3_field_get_uuid(uuid_field);
 12.1445 +
 12.1446 +	/* replace existing record */
 12.1447 +	pws3_record_destroy(pws3_file_remove_record(pws_file, uuid));
 12.1448 +
 12.1449 +	RB_INSERT(records_tree, pws_file->records_tree, record);
 12.1450 +}
 12.1451 +
 12.1452 +struct pws3_record *
 12.1453 +pws3_file_get_record(struct pws3_file *pws_file,
 12.1454 +    const unsigned char uuid[static PWS3_UUID_SIZE])
 12.1455 +{
 12.1456 +	struct pws3_field uuid_field = {
 12.1457 +		.is_header = 0,
 12.1458 +		.field_type = PWS3_RECORD_FIELD_UUID
 12.1459 +	};
 12.1460 +	struct pws3_record search_record = {
 12.1461 +		.fields[PWS3_RECORD_FIELD_UUID] = &uuid_field
 12.1462 +	};
 12.1463 +
 12.1464 +	memcpy(uuid_field.value.uuid, uuid, PWS3_UUID_SIZE);
 12.1465 +
 12.1466 +	return (RB_FIND(records_tree, pws_file->records_tree, &search_record));
 12.1467 +}
 12.1468 +
 12.1469 +struct pws3_record *
 12.1470 +pws3_file_remove_record(struct pws3_file *pws_file,
 12.1471 +    const unsigned char uuid[static PWS3_UUID_SIZE])
 12.1472 +{
 12.1473 +	struct pws3_record *record;
 12.1474 +
 12.1475 +	record = pws3_file_get_record(pws_file, uuid);
 12.1476 +	if (record != NULL) {
 12.1477 +		RB_REMOVE(records_tree, pws_file->records_tree, record);
 12.1478 +	}
 12.1479 +
 12.1480 +	return (record);
 12.1481 +}
 12.1482 +
 12.1483 +struct pws3_record *
 12.1484 +pws3_file_first_record(struct pws3_file *pws_file)
 12.1485 +{
 12.1486 +	return (RB_MIN(records_tree, pws_file->records_tree));
 12.1487 +}
 12.1488 +
 12.1489 +struct pws3_record *
 12.1490 +pws3_file_last_record(struct pws3_file *pws_file)
 12.1491 +{
 12.1492 +	return (RB_MAX(records_tree, pws_file->records_tree));
 12.1493 +}
 12.1494 +
 12.1495 +struct pws3_record *
 12.1496 +pws3_file_next_record(struct pws3_file *pws_file, struct pws3_record *record)
 12.1497 +{
 12.1498 +	return (RB_NEXT(records_tree, pws_file->records_tree, record));
 12.1499 +}
 12.1500 +
 12.1501 +struct pws3_record *
 12.1502 +pws3_file_prev_record(struct pws3_file *pws_file, struct pws3_record *record)
 12.1503 +{
 12.1504 +	return (RB_PREV(records_tree, pws_file->records_tree, record));
 12.1505 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/pws-internal.h	Tue Feb 10 11:29:54 2015 +0100
    13.3 @@ -0,0 +1,83 @@
    13.4 +/*
    13.5 + * Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name>
    13.6 + *
    13.7 + * Permission is hereby granted, free of charge, to any person obtaining
    13.8 + * a copy of this software and associated documentation files (the
    13.9 + * "Software"), to deal in the Software without restriction, including
   13.10 + * without limitation the rights to use, copy, modify, merge, publish,
   13.11 + * distribute, sublicense, and/or sell copies of the Software, and to
   13.12 + * permit persons to whom the Software is furnished to do so, subject to
   13.13 + * the following conditions:
   13.14 + *
   13.15 + * The above copyright notice and this permission notice shall be included
   13.16 + * in all copies or substantial portions of the Software.
   13.17 + *
   13.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   13.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   13.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   13.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   13.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   13.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   13.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   13.25 + */
   13.26 +
   13.27 +#ifndef	PWS_INTERNAL_H
   13.28 +#define	PWS_INTERNAL_H
   13.29 +
   13.30 +#include <signal.h>
   13.31 +#ifdef	HAVE_SYS_TREE_H
   13.32 +#include <sys/tree.h>
   13.33 +#endif /* HAVE_SYS_TREE_H */
   13.34 +#include <sys/types.h>
   13.35 +#include <unistd.h>
   13.36 +
   13.37 +#include "include/pws.h"
   13.38 +
   13.39 +#define	MAX(x, y)		(((x) > (y)) ? (x) : (y))
   13.40 +#define	MIN(x, y)		(((x) < (y)) ? (x) : (y))
   13.41 +#define	CLAMP(x, min, max)	(((x) > (max)) ? (max) : (((x) < (min)) ?\
   13.42 +    (min) : (x)))
   13.43 +
   13.44 +#ifdef	NDEBUG
   13.45 +#include <signal.h>
   13.46 +#include <unistd.h>
   13.47 +#define	PWS_ASSERT(cond)	while (cond) {\
   13.48 +    write(STDERR_FIELNO, "assertion failed: " #cond "\n", \
   13.49 +    sizeof ("assertion failed: " #cond "\n"));\
   13.50 +    raise(SIGKILL);\
   13.51 +    }
   13.52 +#else
   13.53 +#include <assert.h>
   13.54 +#define	PWS_ASSERT(cond)	assert(cond)
   13.55 +#endif /* NDEBUG */
   13.56 +
   13.57 +struct pws3_field {
   13.58 +	int		is_header;
   13.59 +	uint8_t		field_type;
   13.60 +	size_t		size;
   13.61 +	union {
   13.62 +		unsigned char	*bytes;
   13.63 +		unsigned char	uuid[PWS3_UUID_SIZE];
   13.64 +		char		*text;
   13.65 +		uint8_t		uint8;
   13.66 +		uint16_t	uint16;
   13.67 +		uint32_t	uint32;
   13.68 +	} value;
   13.69 +	RB_ENTRY(pws3_field) tree_entry;
   13.70 +};
   13.71 +
   13.72 +struct pws3_record {
   13.73 +	struct pws3_field *fields[256];
   13.74 +	RB_ENTRY(pws3_record) tree_entry;
   13.75 +};
   13.76 +
   13.77 +extern void *	(*pws_alloc)(size_t);
   13.78 +extern void *	(*pws_realloc)(void *, size_t);
   13.79 +extern void	(*pws_free)(void *, size_t);
   13.80 +extern void *	(*pws_secure_alloc)(size_t);
   13.81 +extern void *	(*pws_secure_realloc)(void *, size_t);
   13.82 +extern void	(*pws_secure_free)(void *, size_t);
   13.83 +
   13.84 +int	pws_random_bytes(void *, size_t);
   13.85 +
   13.86 +#endif /* PWS_INTERNAL_H */
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/pws-random.c	Tue Feb 10 11:29:54 2015 +0100
    14.3 @@ -0,0 +1,61 @@
    14.4 +/*
    14.5 + * Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name>
    14.6 + *
    14.7 + * Permission is hereby granted, free of charge, to any person obtaining
    14.8 + * a copy of this software and associated documentation files (the
    14.9 + * "Software"), to deal in the Software without restriction, including
   14.10 + * without limitation the rights to use, copy, modify, merge, publish,
   14.11 + * distribute, sublicense, and/or sell copies of the Software, and to
   14.12 + * permit persons to whom the Software is furnished to do so, subject to
   14.13 + * the following conditions:
   14.14 + *
   14.15 + * The above copyright notice and this permission notice shall be included
   14.16 + * in all copies or substantial portions of the Software.
   14.17 + *
   14.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   14.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   14.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   14.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   14.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   14.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   14.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   14.25 + */
   14.26 +
   14.27 +#include "compat.h"
   14.28 +#include "pws-internal.h"
   14.29 +
   14.30 +#ifdef	HAVE_ARC4RANDOM
   14.31 +/* prefer system arc4random(3) implementation */
   14.32 +#include <stdlib.h>
   14.33 +#else /* HAVE_ARC4RANDOM */
   14.34 +#ifdef	HAVE_GETENTROPY
   14.35 +/*
   14.36 + * otherwise use system getentropy(2) implementation or fallback to seed
   14.37 + * Yarrow-256 PRNG from libnettle
   14.38 + */
   14.39 +#include <unistd.h>
   14.40 +#endif /* HAVE_GETENTROPY */
   14.41 +#include <nettle/yarrow.h>
   14.42 +#endif /* HAVE_ARC4RANDOM */
   14.43 +
   14.44 +#include "pws-internal.h"
   14.45 +
   14.46 +int
   14.47 +pws_random_bytes(void *buf, size_t buf_size)
   14.48 +{
   14.49 +#ifdef	HAVE_ARC4RANDOM
   14.50 +	arc4random_buf(buf, buf_size);
   14.51 +#else /* HAVE_ARC4RANDOM */
   14.52 +	struct yarrow256_ctx	ctx;
   14.53 +	unsigned char		seed_buf[YARROW256_SEED_FILE_SIZE];
   14.54 +
   14.55 +	if (getentropy(&seed_buf, sizeof (seed_buf)) != 0) {
   14.56 +		return (-1);
   14.57 +	}
   14.58 +	yarrow256_init(&ctx, 0, NULL);
   14.59 +	yarrow256_seed(&ctx, sizeof (seed_buf), seed_buf);
   14.60 +	yarrow256_random(&ctx, buf_size, buf);
   14.61 +#endif /* HAVE_ARC4RANDOM */
   14.62 +
   14.63 +	return (0);
   14.64 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/pws-record.c	Tue Feb 10 11:29:54 2015 +0100
    15.3 @@ -0,0 +1,116 @@
    15.4 +/*
    15.5 + * Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name>
    15.6 + *
    15.7 + * Permission is hereby granted, free of charge, to any person obtaining
    15.8 + * a copy of this software and associated documentation files (the
    15.9 + * "Software"), to deal in the Software without restriction, including
   15.10 + * without limitation the rights to use, copy, modify, merge, publish,
   15.11 + * distribute, sublicense, and/or sell copies of the Software, and to
   15.12 + * permit persons to whom the Software is furnished to do so, subject to
   15.13 + * the following conditions:
   15.14 + *
   15.15 + * The above copyright notice and this permission notice shall be included
   15.16 + * in all copies or substantial portions of the Software.
   15.17 + *
   15.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   15.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   15.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   15.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   15.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   15.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   15.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   15.25 + */
   15.26 +
   15.27 +#include "compat.h"
   15.28 +
   15.29 +#include <stdlib.h>
   15.30 +
   15.31 +#include "pws-internal.h"
   15.32 +
   15.33 +void
   15.34 +pws3_record_destroy(struct pws3_record *record)
   15.35 +{
   15.36 +	size_t		i;
   15.37 +
   15.38 +	if (record == NULL) {
   15.39 +		return;
   15.40 +	}
   15.41 +
   15.42 +	for (i = 0x01; i <= 0xff; i++) {
   15.43 +		pws3_field_destroy(record->fields[i]);
   15.44 +	}
   15.45 +	pws_free(record, sizeof (record));
   15.46 +}
   15.47 +
   15.48 +struct pws3_record *
   15.49 +pws3_record_create(void)
   15.50 +{
   15.51 +	struct pws3_field *uuid_field = NULL;
   15.52 +	unsigned char	uuid[PWS3_UUID_SIZE];
   15.53 +	struct pws3_record *record = NULL;
   15.54 +	size_t		i;
   15.55 +
   15.56 +	/*
   15.57 +	 * always add an UUID field which is mandatory and needed for inserting
   15.58 +	 * a record into a database
   15.59 +	 */
   15.60 +	if (pws_generate_uuid(uuid) != 0) {
   15.61 +		goto err;
   15.62 +	}
   15.63 +	uuid_field = pws3_field_create(0, PWS3_RECORD_FIELD_UUID);
   15.64 +	if (uuid_field == NULL) {
   15.65 +		goto err;
   15.66 +	}
   15.67 +	pws3_field_set_uuid(uuid_field, uuid);
   15.68 +
   15.69 +	record = pws_alloc(sizeof (struct pws3_record));
   15.70 +	if (record == NULL) {
   15.71 +		goto err;
   15.72 +	}
   15.73 +
   15.74 +	for (i = 0x00; i <= 0xff; i++) {
   15.75 +		record->fields[i] = NULL;
   15.76 +	}
   15.77 +
   15.78 +	pws3_record_set_field(record, uuid_field);
   15.79 +
   15.80 +	return (record);
   15.81 +err:
   15.82 +	pws3_field_destroy(uuid_field);
   15.83 +	pws_free(record, (record != NULL) ? sizeof (struct pws3_record) : 0);
   15.84 +
   15.85 +	return (NULL);
   15.86 +}
   15.87 +
   15.88 +void
   15.89 +pws3_record_set_field(struct pws3_record *record, struct pws3_field *field)
   15.90 +{
   15.91 +	uint8_t	field_type;
   15.92 +
   15.93 +	PWS_ASSERT(!pws3_field_is_header(field));
   15.94 +	PWS_ASSERT((pws3_field_get_data_type(field) != PWS_DATA_TYPE_TEXT) ||
   15.95 +	    (field->value.text != NULL));
   15.96 +	PWS_ASSERT((pws3_field_get_data_type(field) != PWS_DATA_TYPE_BYTES) ||
   15.97 +	    (field->value.bytes != NULL));
   15.98 +
   15.99 +	field_type = pws3_field_get_type(field);
  15.100 +	pws3_field_destroy(pws3_record_remove_field(record, field_type));
  15.101 +	record->fields[field_type] = field;
  15.102 +}
  15.103 +
  15.104 +struct pws3_field *
  15.105 +pws3_record_get_field(struct pws3_record *record, uint8_t field_type)
  15.106 +{
  15.107 +	return (record->fields[field_type]);
  15.108 +}
  15.109 +
  15.110 +struct pws3_field *
  15.111 +pws3_record_remove_field(struct pws3_record *record, uint8_t field_type)
  15.112 +{
  15.113 +	struct pws3_field *field;
  15.114 +
  15.115 +	field = pws3_record_get_field(record, field_type);
  15.116 +	record->fields[field_type] = NULL;
  15.117 +
  15.118 +	return (field);
  15.119 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/pws.c	Tue Feb 10 11:29:54 2015 +0100
    16.3 @@ -0,0 +1,91 @@
    16.4 +/*
    16.5 + * Copyright (C) 2015 Guido Berhoerster <guido+libpws@berhoerster.name>
    16.6 + *
    16.7 + * Permission is hereby granted, free of charge, to any person obtaining
    16.8 + * a copy of this software and associated documentation files (the
    16.9 + * "Software"), to deal in the Software without restriction, including
   16.10 + * without limitation the rights to use, copy, modify, merge, publish,
   16.11 + * distribute, sublicense, and/or sell copies of the Software, and to
   16.12 + * permit persons to whom the Software is furnished to do so, subject to
   16.13 + * the following conditions:
   16.14 + *
   16.15 + * The above copyright notice and this permission notice shall be included
   16.16 + * in all copies or substantial portions of the Software.
   16.17 + *
   16.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   16.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   16.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   16.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   16.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   16.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   16.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   16.25 + */
   16.26 +
   16.27 +#include "compat.h"
   16.28 +
   16.29 +#include <stdlib.h>
   16.30 +#include <string.h>
   16.31 +
   16.32 +#include "pws-internal.h"
   16.33 +
   16.34 +static void	default_free(void *, size_t);
   16.35 +
   16.36 +void *	(*pws_alloc)(size_t) = malloc;
   16.37 +void *	(*pws_realloc)(void *, size_t) = realloc;
   16.38 +void	(*pws_free)(void *, size_t) = default_free;
   16.39 +void *	(*pws_secure_alloc)(size_t) = malloc;
   16.40 +void *	(*pws_secure_realloc)(void *, size_t) = realloc;
   16.41 +void	(*pws_secure_free)(void *, size_t) = default_free;
   16.42 +
   16.43 +int
   16.44 +pws_init(void)
   16.45 +{
   16.46 +	return (0);
   16.47 +}
   16.48 +
   16.49 +void
   16.50 +pws_finalize(void)
   16.51 +{
   16.52 +}
   16.53 +
   16.54 +static void
   16.55 +default_free(void *ptr, size_t n)
   16.56 +{
   16.57 +	free(ptr);
   16.58 +}
   16.59 +
   16.60 +void
   16.61 +pws_set_alloc_functions(void *(*alloc_function)(size_t),
   16.62 +    void *(*realloc_function)(void *, size_t),
   16.63 +    void (*free_function)(void *, size_t),
   16.64 +    void *(*secure_alloc_function)(size_t),
   16.65 +    void *(*secure_realloc_function)(void *, size_t),
   16.66 +    void (*secure_free_function)(void *, size_t))
   16.67 +{
   16.68 +	pws_alloc = (alloc_function != NULL) ? alloc_function : malloc;
   16.69 +	pws_realloc = (realloc_function != NULL) ? realloc_function : realloc;
   16.70 +	pws_free = (free_function != NULL) ? free_function : default_free;
   16.71 +	pws_secure_alloc = (secure_alloc_function != NULL) ?
   16.72 +	    secure_alloc_function : malloc;
   16.73 +	pws_secure_realloc = (secure_realloc_function != NULL) ?
   16.74 +	    secure_realloc_function : realloc;
   16.75 +	pws_secure_free = (secure_free_function != NULL) ?
   16.76 +	    secure_free_function : default_free;
   16.77 +}
   16.78 +
   16.79 +int
   16.80 +pws_generate_uuid(unsigned char uuid[static PWS3_UUID_SIZE])
   16.81 +{
   16.82 +	unsigned char	buf[PWS3_UUID_SIZE];
   16.83 +
   16.84 +	if (pws_random_bytes(buf, sizeof (buf)) != 0) {
   16.85 +		return (-1);
   16.86 +	}
   16.87 +
   16.88 +	/* UUID v4 from RFC 4122, section 4.4 */
   16.89 +	buf[6] = (buf[6] & 0x0f) | 0x40;
   16.90 +	buf[8] = (buf[8] & 0x3f) | 0x80;
   16.91 +	memcpy(uuid, buf, sizeof (buf));
   16.92 +
   16.93 +	return (0);
   16.94 +}