projects/libpws

changeset 2:97097b4b6bfb

Add pwsdump utility

The pwsdum utility can dump PasswordSafe database files to a plaintext format
and convert this format back into a PasswordSafe database.
author Guido Berhoerster <guido+libpws@berhoerster.name>
date Wed Apr 01 14:57:57 2015 +0200 (2015-04-01)
parents e1309515d111
children 2b9244d20ecf
files Makefile compat.h compat/err.c compat/err.h compat/getline.c compat/getline.h compat/pws-compat.h compat/readpassphrase.c compat/readpassphrase.h compat/setprogname.c compat/setprogname.h compat/unvis.c compat/vis.c compat/vis.h pwsdump.c
line diff
     1.1 --- a/Makefile	Wed Mar 25 17:10:23 2015 +0100
     1.2 +++ b/Makefile	Wed Apr 01 14:57:57 2015 +0200
     1.3 @@ -99,38 +99,73 @@
     1.4    HAVE_ARC4RANDOM ?=	0
     1.5    HAVE_ENDIAN_H ?=	1
     1.6    HAVE_SYS_ENDIAN_H ?=	0
     1.7 +  HAVE_ERR_H ?=		1
     1.8    HAVE_GETENTROPY ?=	0
     1.9 +  HAVE_GETLINE ?=	0
    1.10 +  HAVE_SETPROGNAME ?=	0
    1.11 +  HAVE_READPASSPHRASE_H ?= 0
    1.12    HAVE_SYS_TREE_H ?=	0
    1.13 +  HAVE_VIS_H ?=		0
    1.14  else ifneq ($(findstring $(OS_NAME),FreeBSD DragonFly),)
    1.15    HAVE_ARC4RANDOM ?=	1
    1.16    HAVE_ENDIAN_H ?=	0
    1.17    HAVE_SYS_ENDIAN_H ?=	1
    1.18 +  HAVE_ERR_H ?=		1
    1.19    HAVE_GETENTROPY ?=	0
    1.20 +  HAVE_GETLINE ?=	1
    1.21 +  HAVE_SETPROGNAME ?=	1
    1.22 +  HAVE_READPASSPHRASE_H ?= 1
    1.23    HAVE_SYS_TREE_H ?=	1
    1.24 +  HAVE_VIS_H ?=		1
    1.25  else ifeq ($(OS_NAME),NetBSD)
    1.26    HAVE_ARC4RANDOM ?=	1
    1.27    HAVE_ENDIAN_H ?=	0
    1.28    HAVE_SYS_ENDIAN_H ?=	1
    1.29 +  HAVE_ERR_H ?=		1
    1.30    HAVE_GETENTROPY ?=	0
    1.31 +  HAVE_GETLINE ?=	1
    1.32 +  HAVE_SETPROGNAME ?=	1
    1.33 +  HAVE_READPASSPHRASE_H ?= 0
    1.34    HAVE_SYS_TREE_H ?=	1
    1.35 +  HAVE_VIS_H ?=		1
    1.36  else ifeq ($(OS_NAME),OpenBSD)
    1.37    HAVE_ARC4RANDOM ?=	1
    1.38    HAVE_ENDIAN_H ?=	0
    1.39    HAVE_SYS_ENDIAN_H ?=	1
    1.40 +  HAVE_ERR_H ?=		1
    1.41    HAVE_GETENTROPY ?=	1
    1.42 +  HAVE_GETLINE ?=	1
    1.43 +  HAVE_SETPROGNAME ?=	1
    1.44 +  HAVE_READPASSPHRASE_H ?= 1
    1.45    HAVE_SYS_TREE_H ?=	1
    1.46 +  HAVE_VIS_H ?=		1
    1.47  else ifeq ($(OS_NAME),SunOS)
    1.48    HAVE_ARC4RANDOM ?=	0
    1.49    HAVE_ENDIAN_H ?=	0
    1.50    HAVE_SYS_ENDIAN_H ?=	0
    1.51    HAVE_GETENTROPY ?=	0
    1.52 +  ifeq ($(OS_RELEASE),5.10)
    1.53 +    HAVE_ERR_H ?=	0
    1.54 +    HAVE_GETLINE ?=	0
    1.55 +  else
    1.56 +    HAVE_ERR_H ?=	1
    1.57 +    HAVE_GETLINE ?=	1
    1.58 +  endif
    1.59 +  HAVE_SETPROGNAME ?=	0
    1.60 +  HAVE_READPASSPHRASE_H ?= 0
    1.61    HAVE_SYS_TREE_H ?=	0
    1.62 +  HAVE_VIS_H ?=		0
    1.63  else
    1.64    HAVE_ARC4RANDOM ?=	0
    1.65    HAVE_ENDIAN_H ?=	0
    1.66    HAVE_SYS_ENDIAN_H ?=	0
    1.67 +  HAVE_ERR_H ?=		0
    1.68    HAVE_GETENTROPY ?=	0
    1.69 +  HAVE_GETLINE ?=	0
    1.70 +  HAVE_SETPROGNAME ?=	0
    1.71 +  HAVE_READPASSPHRASE_H ?= 0
    1.72    HAVE_SYS_TREE_H ?=	0
    1.73 +  HAVE_VIS_H ?=		0
    1.74  endif
    1.75  
    1.76  LIBPWS_OBJS =		pws.o \
    1.77 @@ -141,7 +176,10 @@
    1.78  LIBPWS_LIB =		$(PACKAGE).a
    1.79  LIBPWS_LIB_MEMBERS =	$(LIBPWS_OBJS:%.o=$(LIBPWS_LIB)(%.o))
    1.80  
    1.81 -OBJS =			$(LIBPWS_OBJS)
    1.82 +PWSDUMP_BIN =		pwsdump
    1.83 +PWSDUMP_OBJS =		pwsdump.o
    1.84 +
    1.85 +OBJS =			$(LIBPWS_OBJS) $(PWSDUMP_OBJS)
    1.86  
    1.87  LIBPWS_MANPAGES =	libpws.3
    1.88  
    1.89 @@ -212,7 +250,7 @@
    1.90  
    1.91  .PHONY: all clean clobber dist install
    1.92  
    1.93 -all: $(LIBPWS_LIB) $(MANPAGES)
    1.94 +all: $(PWSDUMP_BIN) $(LIBPWS_LIB) $(MANPAGES)
    1.95  
    1.96  doc: $(MANPAGES) $(XHTML_DOCUMENTATION)
    1.97  
    1.98 @@ -226,15 +264,41 @@
    1.99    XCPPFLAGS +=	-DHAVE_SYS_ENDIAN_H
   1.100  else
   1.101    LIBPWS_OBJS += compat/endian.o
   1.102 +  PWSDUMP_OBJS += compat/endian.o
   1.103 +endif
   1.104 +ifeq ($(HAVE_ERR_H),1)
   1.105 +  XCPPFLAGS +=	-DHAVE_ERR_H
   1.106 +else
   1.107 +  PWSDUMP_OBJS += compat/err.o
   1.108  endif
   1.109  ifeq ($(HAVE_GETENTROPY),1)
   1.110    XCPPFLAGS +=	-DHAVE_GETENTROPY
   1.111  else
   1.112    LIBPWS_OBJS += compat/getentropy.o
   1.113  endif
   1.114 +ifeq ($(HAVE_GETLINE),1)
   1.115 +  XCPPFLAGS +=	-DHAVE_GETLINE
   1.116 +else
   1.117 +  PWSDUMP_OBJS += compat/getline.o
   1.118 +endif
   1.119 +ifeq ($(HAVE_READPASSPHRASE_H),1)
   1.120 +  XCPPFLAGS +=	-DHAVE_READPASSPHRASE_H
   1.121 +else
   1.122 +  PWSDUMP_OBJS += compat/readpassphrase.o
   1.123 +endif
   1.124 +ifeq ($(HAVE_SETPROGNAME),1)
   1.125 +  XCPPFLAGS +=	-DHAVE_SETPROGNAME
   1.126 +else
   1.127 +  PWSDUMP_OBJS += compat/setprogname.o
   1.128 +endif
   1.129  ifeq ($(HAVE_SYS_TREE_H),1)
   1.130    XCPPFLAGS +=	-DHAVE_SYS_TREE_H
   1.131  endif
   1.132 +ifeq ($(HAVE_VIS_H),1)
   1.133 +  XCPPFLAGS +=	-DHAVE_VIS_H
   1.134 +else
   1.135 +  PWSDUMP_OBJS += compat/vis.o compat/unvis.o
   1.136 +endif
   1.137  ifneq ($(findstring $(OS_NAME),FreeBSD DragonFly OpenBSD),)
   1.138    XCPPFLAGS +=	-I/usr/local/include
   1.139    XLDFLAGS +=	-L/usr/local/lib
   1.140 @@ -258,6 +322,8 @@
   1.141  
   1.142  $(eval $(call generate-manpage-rule,$(PWS3_FILE_CREATE_MANPAGES)))
   1.143  
   1.144 +$(PWSDUMP_BIN): $(PWSDUMP_OBJS) $(LIBPWS_LIB) -lnettle
   1.145 +
   1.146  %.o: %.c
   1.147  	$(MAKEDEPEND.c) $< | $(SED) -f deps.sed >$*.d
   1.148  	$(COMPILE.c) -o $@ $<
   1.149 @@ -297,7 +363,7 @@
   1.150  	done
   1.151  
   1.152  clean:
   1.153 -	rm -f $(LIBPWS_LIB) $(LIBPWS_OBJS) $(MANPAGES) \
   1.154 +	rm -f $(LIBPWS_LIB) $(PWSDUMP_BIN) $(OBJS) $(MANPAGES) \
   1.155  	    $(XHTML_DOCUMENTATION)
   1.156  
   1.157  clobber: clean
     2.1 --- a/compat.h	Wed Mar 25 17:10:23 2015 +0100
     2.2 +++ b/compat.h	Wed Apr 01 14:57:57 2015 +0200
     2.3 @@ -36,12 +36,32 @@
     2.4  #include "compat/endian.h"
     2.5  #endif /* !defined(HAVE_ENDIAN_H) && !defined(HAVE_SYS_ENDIAN_H) */
     2.6  
     2.7 +#ifndef	HAVE_ERR_H
     2.8 +#include "compat/err.h"
     2.9 +#endif /* !HAVE_ERR_H */
    2.10 +
    2.11  #ifndef	HAVE_GETENTROPY
    2.12  #include "compat/getentropy.h"
    2.13  #endif /* !HAVE_GETENTROPY */
    2.14  
    2.15 +#ifndef	HAVE_GETLINE
    2.16 +#include "compat/getline.h"
    2.17 +#endif /* !HAVE_GETLINE */
    2.18 +
    2.19 +#ifndef	HAVE_READPASSPHRASE_H
    2.20 +#include "compat/readpassphrase.h"
    2.21 +#endif /* !HAVE_READPASSPHRASE_H */
    2.22 +
    2.23 +#ifndef	HAVE_SETPROGNAME
    2.24 +#include "compat/setprogname.h"
    2.25 +#endif /* !HAVE_SETPROGNAME */
    2.26 +
    2.27  #ifndef	HAVE_SYS_TREE_H
    2.28  #include "compat/tree.h"
    2.29  #endif /* !HAVE_SYS_TREE_H */
    2.30  
    2.31 +#ifndef	HAVE_VIS_H
    2.32 +#include "compat/vis.h"
    2.33 +#endif /* !HAVE_VIS_H */
    2.34 +
    2.35  #endif /* COMPAT_H */
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/compat/err.c	Wed Apr 01 14:57:57 2015 +0200
     3.3 @@ -0,0 +1,113 @@
     3.4 +/*
     3.5 + * Copyright (C) 2011 Guido Berhoerster <guido+libpws@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 <stdlib.h>
    3.28 +#include <stdio.h>
    3.29 +#include <string.h>
    3.30 +#include <errno.h>
    3.31 +
    3.32 +#include "pws-compat.h"
    3.33 +
    3.34 +void
    3.35 +vwarn(const char *fmt, va_list args)
    3.36 +{
    3.37 +	int	old_errno = errno;
    3.38 +
    3.39 +	fprintf(stderr, "%s: ", getprogname());
    3.40 +	if (fmt != NULL) {
    3.41 +		vfprintf(stderr, fmt, args);
    3.42 +		fprintf(stderr, ": ");
    3.43 +	}
    3.44 +	fprintf(stderr, "%s\n", strerror(old_errno));
    3.45 +	errno = old_errno;
    3.46 +}
    3.47 +
    3.48 +void
    3.49 +vwarnx(const char *fmt, va_list args)
    3.50 +{
    3.51 +	fprintf(stderr, "%s: ", getprogname());
    3.52 +	if (fmt != NULL) {
    3.53 +		vfprintf(stderr, fmt, args);
    3.54 +	}
    3.55 +	fputc('\n', stderr);
    3.56 +}
    3.57 +
    3.58 +void
    3.59 +verr(int eval, const char *fmt, va_list args)
    3.60 +{
    3.61 +	vwarn(fmt, args);
    3.62 +
    3.63 +	exit(eval);
    3.64 +}
    3.65 +
    3.66 +void
    3.67 +verrx(int eval, const char *fmt, va_list args)
    3.68 +{
    3.69 +	vwarnx(fmt, args);
    3.70 +
    3.71 +	exit(eval);
    3.72 +}
    3.73 +
    3.74 +void
    3.75 +err(int eval, const char *fmt, ...)
    3.76 +{
    3.77 +	va_list	args;
    3.78 +
    3.79 +	va_start(args, fmt);
    3.80 +	vwarn(fmt, args);
    3.81 +	va_end(args);
    3.82 +
    3.83 +	exit(eval);
    3.84 +}
    3.85 +
    3.86 +void
    3.87 +errx(int eval, const char *fmt, ...)
    3.88 +{
    3.89 +	va_list	args;
    3.90 +
    3.91 +	va_start(args, fmt);
    3.92 +	vwarnx(fmt, args);
    3.93 +	va_end(args);
    3.94 +
    3.95 +	exit(eval);
    3.96 +}
    3.97 +
    3.98 +void
    3.99 +warn(const char *fmt, ...)
   3.100 +{
   3.101 +	va_list	args;
   3.102 +
   3.103 +	va_start(args, fmt);
   3.104 +	vwarn(fmt, args);
   3.105 +	va_end(args);
   3.106 +}
   3.107 +
   3.108 +void
   3.109 +warnx(const char *fmt, ...)
   3.110 +{
   3.111 +	va_list	args;
   3.112 +
   3.113 +	va_start(args, fmt);
   3.114 +	vwarnx(fmt, args);
   3.115 +	va_end(args);
   3.116 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/compat/err.h	Wed Apr 01 14:57:57 2015 +0200
     4.3 @@ -0,0 +1,38 @@
     4.4 +/*
     4.5 + * Copyright (C) 2011 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 ERR_H
    4.28 +#define ERR_H
    4.29 +
    4.30 +#include <stdarg.h>
    4.31 +
    4.32 +void	err(int, const char *, ...);
    4.33 +void	errx(int, const char *, ...);
    4.34 +void	warn(const char *, ...);
    4.35 +void	warnx(const char *, ...);
    4.36 +void	verr(int, const char *, va_list);
    4.37 +void	verrx(int, const char *, va_list);
    4.38 +void	vwarn(const char *, va_list);
    4.39 +void	vwarnx(const char *, va_list);
    4.40 +
    4.41 +#endif /* ERR_H */
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/compat/getline.c	Wed Apr 01 14:57:57 2015 +0200
     5.3 @@ -0,0 +1,93 @@
     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 +#include <stdio.h>
    5.28 +#include <stdlib.h>
    5.29 +#include <limits.h>
    5.30 +#include <sys/types.h>
    5.31 +#include <errno.h>
    5.32 +
    5.33 +#include "pws-compat.h"
    5.34 +
    5.35 +#define	MIN(x, y)	(((x) < (y)) ? (x) : (y))
    5.36 +
    5.37 +ssize_t
    5.38 +getdelim(char **linep, size_t *sizep, int delim, FILE *fp)
    5.39 +{
    5.40 +	ssize_t	len;
    5.41 +	char	*line = *linep;
    5.42 +	size_t	size = *sizep;
    5.43 +	size_t	pos = 0;
    5.44 +	char	*line_new;
    5.45 +	int	c;
    5.46 +
    5.47 +	if (*linep == NULL) {
    5.48 +		size = 0;
    5.49 +	}
    5.50 +
    5.51 +	flockfile(fp);
    5.52 +
    5.53 +	for (;;) {
    5.54 +		if (size - pos < 2) {
    5.55 +			size = MIN((size_t)SSIZE_MAX + 1,
    5.56 +			    (size < BUFSIZ) ? BUFSIZ : size * 1.5);
    5.57 +			if (size - pos < 2) {
    5.58 +				len = -1;
    5.59 +				errno = EOVERFLOW;
    5.60 +				break;
    5.61 +			}
    5.62 +			line_new = realloc(line, size);
    5.63 +			if (line_new == NULL) {
    5.64 +				len = -1;
    5.65 +				break;
    5.66 +			}
    5.67 +			*linep = line = line_new;
    5.68 +			*sizep = size;
    5.69 +		}
    5.70 +		c = fgetc(fp);
    5.71 +		if (c == EOF) {
    5.72 +			len = -1;
    5.73 +			break;
    5.74 +		}
    5.75 +		line[pos] = c;
    5.76 +		pos++;
    5.77 +		len = pos;
    5.78 +		if (c == delim) {
    5.79 +			break;
    5.80 +		}
    5.81 +	}
    5.82 +
    5.83 +	if (*linep != NULL) {
    5.84 +		(*linep)[pos] = '\0';
    5.85 +	}
    5.86 +
    5.87 +	funlockfile(fp);
    5.88 +
    5.89 +	return (len);
    5.90 +}
    5.91 +
    5.92 +ssize_t
    5.93 +getline(char **linep, size_t *sizep, FILE *fp)
    5.94 +{
    5.95 +	return (getdelim(linep, sizep, '\n', fp));
    5.96 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/compat/getline.h	Wed Apr 01 14:57:57 2015 +0200
     6.3 @@ -0,0 +1,33 @@
     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	GETLINE_H
    6.28 +#define	GETLINE_H
    6.29 +
    6.30 +#include <sys/types.h>
    6.31 +#include <stdio.h>
    6.32 +
    6.33 +ssize_t	getline(char **, size_t *, FILE *);
    6.34 +ssize_t getdelim(char **, size_t *, int, FILE *);
    6.35 +
    6.36 +#endif /* !GETLINE_H */
     7.1 --- a/compat/pws-compat.h	Wed Mar 25 17:10:23 2015 +0100
     7.2 +++ b/compat/pws-compat.h	Wed Apr 01 14:57:57 2015 +0200
     7.3 @@ -35,8 +35,44 @@
     7.4  #define	htobe32		pws_compat_htobe32
     7.5  #endif /* !defined(HAVE_ENDIAN_H) && !defined(HAVE_SYS_ENDIAN_H) */
     7.6  
     7.7 +#ifndef	HAVE_ERR_H
     7.8 +#define	err		pws_compat_err
     7.9 +#define	errx		pws_compat_errx
    7.10 +#define	warn		pws_compat_warn
    7.11 +#define	warnx		pws_compat_warnx
    7.12 +#define	verr		pws_compat_verr
    7.13 +#define	verrx		pws_compat_verrx
    7.14 +#define	vwarn		pws_compat_vwarn
    7.15 +#define	vwarnx		pws_compat_vwarnx
    7.16 +#endif /* !HAVE_ERR_H */
    7.17 +
    7.18  #ifndef	HAVE_GETENTROPY
    7.19  #define	getentropy	pws_compat_getentropy
    7.20  #endif /* !HAVE_GETENTROPY */
    7.21  
    7.22 +#ifndef	HAVE_GETLINE
    7.23 +#define	getline		pws_compat_getline
    7.24 +#define	getdelim	pws_compat_getdelim
    7.25 +#endif /* !HAVE_GETLINE */
    7.26 +
    7.27 +#ifndef	HAVE_READPASSPHRASE_H
    7.28 +#define	readpassphrase	pws_compat_readpassphrase
    7.29 +#endif /* !HAVE_READPASSPHRASE_H */
    7.30 +
    7.31 +#ifndef	HAVE_SETPROGNAME
    7.32 +#define	setprogname	pws_compat_setprogname
    7.33 +#define	getprogname	pws_compat_getprogname
    7.34 +#endif /* !HAVE_SETPROGNAME */
    7.35 +
    7.36 +#ifndef	HAVE_VIS_H
    7.37 +#define	vis		pws_compat_vis
    7.38 +#define	strvis		pws_compat_strvis
    7.39 +#define	stravis		pws_compat_stravis
    7.40 +#define	strnvis		pws_compat_strnvis
    7.41 +#define	strvisx		pws_compat_strvisx
    7.42 +#define	strunvis	pws_compat_strunvis
    7.43 +#define	unvis		pws_compat_unvis
    7.44 +#define	strnunvis	pws_compat_strnunvis
    7.45 +#endif /* !HAVE_VIS_H */
    7.46 +
    7.47  #endif /* PWS_COMPAT_H */
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/compat/readpassphrase.c	Wed Apr 01 14:57:57 2015 +0200
     8.3 @@ -0,0 +1,211 @@
     8.4 +/*	$OpenBSD: readpassphrase.c,v 1.24 2013/11/24 23:51:29 deraadt Exp $	*/
     8.5 +
     8.6 +/*
     8.7 + * Copyright (c) 2000-2002, 2007, 2010
     8.8 + *	Todd C. Miller <Todd.Miller@courtesan.com>
     8.9 + *
    8.10 + * Permission to use, copy, modify, and distribute this software for any
    8.11 + * purpose with or without fee is hereby granted, provided that the above
    8.12 + * copyright notice and this permission notice appear in all copies.
    8.13 + *
    8.14 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    8.15 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    8.16 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    8.17 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    8.18 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    8.19 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    8.20 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    8.21 + *
    8.22 + * Sponsored in part by the Defense Advanced Research Projects
    8.23 + * Agency (DARPA) and Air Force Research Laboratory, Air Force
    8.24 + * Materiel Command, USAF, under agreement number F39502-99-1-0512.
    8.25 + */
    8.26 +
    8.27 +#include <ctype.h>
    8.28 +#include <errno.h>
    8.29 +#include <fcntl.h>
    8.30 +#ifdef	HAVE_PATHS_H
    8.31 +#include <paths.h>
    8.32 +#endif /* HAVE_PATHS_H */
    8.33 +#include <pwd.h>
    8.34 +#include <signal.h>
    8.35 +#include <string.h>
    8.36 +#include <termios.h>
    8.37 +#include <unistd.h>
    8.38 +
    8.39 +#include "pws-compat.h"
    8.40 +#include "readpassphrase.h"
    8.41 +
    8.42 +#ifndef TCSASOFT
    8.43 +#define TCSASOFT 0
    8.44 +#endif /* !TCSASOFT */
    8.45 +
    8.46 +#ifndef	_NSIG
    8.47 +#ifdef NSIG
    8.48 +#define	_NSIG NSIG
    8.49 +#else /* NSIG */
    8.50 +#define	_NSIG 128
    8.51 +#endif /* NSIG */
    8.52 +#endif /* !_NSIG */
    8.53 +
    8.54 +#ifndef	_PATH_TTY
    8.55 +#define	_PATH_TTY	"/dev/tty"
    8.56 +#endif
    8.57 +
    8.58 +static volatile sig_atomic_t signo[_NSIG];
    8.59 +
    8.60 +static void handler(int);
    8.61 +
    8.62 +char *
    8.63 +readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
    8.64 +{
    8.65 +	ssize_t nr;
    8.66 +	int input, output, save_errno, i, need_restart;
    8.67 +	char ch, *p, *end;
    8.68 +	struct termios term, oterm;
    8.69 +	struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
    8.70 +	struct sigaction savetstp, savettin, savettou, savepipe;
    8.71 +
    8.72 +	/* I suppose we could alloc on demand in this case (XXX). */
    8.73 +	if (bufsiz == 0) {
    8.74 +		errno = EINVAL;
    8.75 +		return(NULL);
    8.76 +	}
    8.77 +
    8.78 +restart:
    8.79 +	for (i = 0; i < _NSIG; i++)
    8.80 +		signo[i] = 0;
    8.81 +	nr = -1;
    8.82 +	save_errno = 0;
    8.83 +	need_restart = 0;
    8.84 +	/*
    8.85 +	 * Read and write to /dev/tty if available.  If not, read from
    8.86 +	 * stdin and write to stderr unless a tty is required.
    8.87 +	 */
    8.88 +	if ((flags & RPP_STDIN) ||
    8.89 +	    (input = output = open(_PATH_TTY, O_RDWR)) == -1) {
    8.90 +		if (flags & RPP_REQUIRE_TTY) {
    8.91 +			errno = ENOTTY;
    8.92 +			return(NULL);
    8.93 +		}
    8.94 +		input = STDIN_FILENO;
    8.95 +		output = STDERR_FILENO;
    8.96 +	}
    8.97 +
    8.98 +	/*
    8.99 +	 * Turn off echo if possible.
   8.100 +	 * If we are using a tty but are not the foreground pgrp this will
   8.101 +	 * generate SIGTTOU, so do it *before* installing the signal handlers.
   8.102 +	 */
   8.103 +	if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
   8.104 +		memcpy(&term, &oterm, sizeof(term));
   8.105 +		if (!(flags & RPP_ECHO_ON))
   8.106 +			term.c_lflag &= ~(ECHO | ECHONL);
   8.107 +#ifdef VSTATUS
   8.108 +		if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
   8.109 +			term.c_cc[VSTATUS] = _POSIX_VDISABLE;
   8.110 +#endif /* VSTATUS */
   8.111 +		(void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
   8.112 +	} else {
   8.113 +		memset(&term, 0, sizeof(term));
   8.114 +		term.c_lflag |= ECHO;
   8.115 +		memset(&oterm, 0, sizeof(oterm));
   8.116 +		oterm.c_lflag |= ECHO;
   8.117 +	}
   8.118 +
   8.119 +	/*
   8.120 +	 * Catch signals that would otherwise cause the user to end
   8.121 +	 * up with echo turned off in the shell.  Don't worry about
   8.122 +	 * things like SIGXCPU and SIGVTALRM for now.
   8.123 +	 */
   8.124 +	sigemptyset(&sa.sa_mask);
   8.125 +	sa.sa_flags = 0;		/* don't restart system calls */
   8.126 +	sa.sa_handler = handler;
   8.127 +	(void)sigaction(SIGALRM, &sa, &savealrm);
   8.128 +	(void)sigaction(SIGHUP, &sa, &savehup);
   8.129 +	(void)sigaction(SIGINT, &sa, &saveint);
   8.130 +	(void)sigaction(SIGPIPE, &sa, &savepipe);
   8.131 +	(void)sigaction(SIGQUIT, &sa, &savequit);
   8.132 +	(void)sigaction(SIGTERM, &sa, &saveterm);
   8.133 +	(void)sigaction(SIGTSTP, &sa, &savetstp);
   8.134 +	(void)sigaction(SIGTTIN, &sa, &savettin);
   8.135 +	(void)sigaction(SIGTTOU, &sa, &savettou);
   8.136 +
   8.137 +	if (!(flags & RPP_STDIN))
   8.138 +		(void)write(output, prompt, strlen(prompt));
   8.139 +	end = buf + bufsiz - 1;
   8.140 +	p = buf;
   8.141 +	while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
   8.142 +		if (p < end) {
   8.143 +			if ((flags & RPP_SEVENBIT))
   8.144 +				ch &= 0x7f;
   8.145 +			if (isalpha((unsigned char)ch)) {
   8.146 +				if ((flags & RPP_FORCELOWER))
   8.147 +					ch = (char)tolower((unsigned char)ch);
   8.148 +				if ((flags & RPP_FORCEUPPER))
   8.149 +					ch = (char)toupper((unsigned char)ch);
   8.150 +			}
   8.151 +			*p++ = ch;
   8.152 +		}
   8.153 +	}
   8.154 +	*p = '\0';
   8.155 +	save_errno = errno;
   8.156 +	if (!(term.c_lflag & ECHO))
   8.157 +		(void)write(output, "\n", 1);
   8.158 +
   8.159 +	/* Restore old terminal settings and signals. */
   8.160 +	if (memcmp(&term, &oterm, sizeof(term)) != 0) {
   8.161 +		while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
   8.162 +		    errno == EINTR && !signo[SIGTTOU])
   8.163 +			continue;
   8.164 +	}
   8.165 +	(void)sigaction(SIGALRM, &savealrm, NULL);
   8.166 +	(void)sigaction(SIGHUP, &savehup, NULL);
   8.167 +	(void)sigaction(SIGINT, &saveint, NULL);
   8.168 +	(void)sigaction(SIGQUIT, &savequit, NULL);
   8.169 +	(void)sigaction(SIGPIPE, &savepipe, NULL);
   8.170 +	(void)sigaction(SIGTERM, &saveterm, NULL);
   8.171 +	(void)sigaction(SIGTSTP, &savetstp, NULL);
   8.172 +	(void)sigaction(SIGTTIN, &savettin, NULL);
   8.173 +	(void)sigaction(SIGTTOU, &savettou, NULL);
   8.174 +	if (input != STDIN_FILENO)
   8.175 +		(void)close(input);
   8.176 +
   8.177 +	/*
   8.178 +	 * If we were interrupted by a signal, resend it to ourselves
   8.179 +	 * now that we have restored the signal handlers.
   8.180 +	 */
   8.181 +	for (i = 0; i < _NSIG; i++) {
   8.182 +		if (signo[i]) {
   8.183 +			kill(getpid(), i);
   8.184 +			switch (i) {
   8.185 +			case SIGTSTP:
   8.186 +			case SIGTTIN:
   8.187 +			case SIGTTOU:
   8.188 +				need_restart = 1;
   8.189 +			}
   8.190 +		}
   8.191 +	}
   8.192 +	if (need_restart)
   8.193 +		goto restart;
   8.194 +
   8.195 +	if (save_errno)
   8.196 +		errno = save_errno;
   8.197 +	return(nr == -1 ? NULL : buf);
   8.198 +}
   8.199 +
   8.200 +#if 0
   8.201 +char *
   8.202 +getpass(const char *prompt)
   8.203 +{
   8.204 +	static char buf[_PASSWORD_LEN + 1];
   8.205 +
   8.206 +	return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF));
   8.207 +}
   8.208 +#endif
   8.209 +
   8.210 +static void handler(int s)
   8.211 +{
   8.212 +
   8.213 +	signo[s] = 1;
   8.214 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/compat/readpassphrase.h	Wed Apr 01 14:57:57 2015 +0200
     9.3 @@ -0,0 +1,38 @@
     9.4 +/*	$OpenBSD: readpassphrase.h,v 1.5 2003/06/17 21:56:23 millert Exp $	*/
     9.5 +
     9.6 +/*
     9.7 + * Copyright (c) 2000, 2002 Todd C. Miller <Todd.Miller@courtesan.com>
     9.8 + *
     9.9 + * Permission to use, copy, modify, and distribute this software for any
    9.10 + * purpose with or without fee is hereby granted, provided that the above
    9.11 + * copyright notice and this permission notice appear in all copies.
    9.12 + *
    9.13 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    9.14 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    9.15 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    9.16 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    9.17 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    9.18 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    9.19 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    9.20 + *
    9.21 + * Sponsored in part by the Defense Advanced Research Projects
    9.22 + * Agency (DARPA) and Air Force Research Laboratory, Air Force
    9.23 + * Materiel Command, USAF, under agreement number F39502-99-1-0512.
    9.24 + */
    9.25 +
    9.26 +#ifndef _READPASSPHRASE_H_
    9.27 +#define _READPASSPHRASE_H_
    9.28 +
    9.29 +#define RPP_ECHO_OFF    0x00		/* Turn off echo (default). */
    9.30 +#define RPP_ECHO_ON     0x01		/* Leave echo on. */
    9.31 +#define RPP_REQUIRE_TTY 0x02		/* Fail if there is no tty. */
    9.32 +#define RPP_FORCELOWER  0x04		/* Force input to lower case. */
    9.33 +#define RPP_FORCEUPPER  0x08		/* Force input to upper case. */
    9.34 +#define RPP_SEVENBIT    0x10		/* Strip the high bit from input. */
    9.35 +#define RPP_STDIN       0x20		/* Read from stdin, not /dev/tty */
    9.36 +
    9.37 +#include <sys/types.h>
    9.38 +
    9.39 +char * readpassphrase(const char *, char *, size_t, int);
    9.40 +
    9.41 +#endif /* !_READPASSPHRASE_H_ */
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/compat/setprogname.c	Wed Apr 01 14:57:57 2015 +0200
    10.3 @@ -0,0 +1,43 @@
    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 +#include <string.h>
   10.28 +
   10.29 +#include "pws-compat.h"
   10.30 +
   10.31 +static const char *progname = "<unknown_program>";
   10.32 +
   10.33 +void
   10.34 +setprogname(const char *name)
   10.35 +{
   10.36 +	const char	*p;
   10.37 +
   10.38 +	p = strrchr(name, '/');
   10.39 +	progname = (p != NULL) ? p + 1 : name;
   10.40 +}
   10.41 +
   10.42 +const char *
   10.43 +getprogname(void)
   10.44 +{
   10.45 +	return (progname);
   10.46 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/compat/setprogname.h	Wed Apr 01 14:57:57 2015 +0200
    11.3 @@ -0,0 +1,30 @@
    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 +#ifndef	SETPROGNAME_H
   11.28 +#define	SETPROGNAME_H
   11.29 +
   11.30 +void		setprogname(const char *);
   11.31 +const char *	getprogname(void);
   11.32 +
   11.33 +#endif /* !SETPROGNAME_H */
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/compat/unvis.c	Wed Apr 01 14:57:57 2015 +0200
    12.3 @@ -0,0 +1,290 @@
    12.4 +/*	$OpenBSD: unvis.c,v 1.17 2015/09/13 11:32:51 guenther Exp $ */
    12.5 +/*-
    12.6 + * Copyright (c) 1989, 1993
    12.7 + *	The Regents of the University of California.  All rights reserved.
    12.8 + *
    12.9 + * Redistribution and use in source and binary forms, with or without
   12.10 + * modification, are permitted provided that the following conditions
   12.11 + * are met:
   12.12 + * 1. Redistributions of source code must retain the above copyright
   12.13 + *    notice, this list of conditions and the following disclaimer.
   12.14 + * 2. Redistributions in binary form must reproduce the above copyright
   12.15 + *    notice, this list of conditions and the following disclaimer in the
   12.16 + *    documentation and/or other materials provided with the distribution.
   12.17 + * 3. Neither the name of the University nor the names of its contributors
   12.18 + *    may be used to endorse or promote products derived from this software
   12.19 + *    without specific prior written permission.
   12.20 + *
   12.21 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   12.22 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   12.23 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   12.24 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   12.25 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   12.26 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   12.27 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   12.28 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   12.29 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   12.30 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   12.31 + * SUCH DAMAGE.
   12.32 + */
   12.33 +
   12.34 +#include <sys/types.h>
   12.35 +#include <ctype.h>
   12.36 +
   12.37 +#include "pws-compat.h"
   12.38 +#include "vis.h"
   12.39 +
   12.40 +/*
   12.41 + * decode driven by state machine
   12.42 + */
   12.43 +#define	S_GROUND	0	/* haven't seen escape char */
   12.44 +#define	S_START		1	/* start decoding special sequence */
   12.45 +#define	S_META		2	/* metachar started (M) */
   12.46 +#define	S_META1		3	/* metachar more, regular char (-) */
   12.47 +#define	S_CTRL		4	/* control char started (^) */
   12.48 +#define	S_OCTAL2	5	/* octal digit 2 */
   12.49 +#define	S_OCTAL3	6	/* octal digit 3 */
   12.50 +
   12.51 +#define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
   12.52 +
   12.53 +typedef unsigned int u_int;
   12.54 +typedef unsigned char u_char;
   12.55 +
   12.56 +/*
   12.57 + * unvis - decode characters previously encoded by vis
   12.58 + */
   12.59 +int
   12.60 +unvis(char *cp, char c, int *astate, int flag)
   12.61 +{
   12.62 +
   12.63 +	if (flag & UNVIS_END) {
   12.64 +		if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
   12.65 +			*astate = S_GROUND;
   12.66 +			return (UNVIS_VALID);
   12.67 +		} 
   12.68 +		return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
   12.69 +	}
   12.70 +
   12.71 +	switch (*astate) {
   12.72 +
   12.73 +	case S_GROUND:
   12.74 +		*cp = 0;
   12.75 +		if (c == '\\') {
   12.76 +			*astate = S_START;
   12.77 +			return (0);
   12.78 +		} 
   12.79 +		*cp = c;
   12.80 +		return (UNVIS_VALID);
   12.81 +
   12.82 +	case S_START:
   12.83 +		switch(c) {
   12.84 +		case '-':
   12.85 +			*cp = 0;
   12.86 +			*astate = S_GROUND;
   12.87 +			return (0);
   12.88 +		case '\\':
   12.89 +		case '"':
   12.90 +			*cp = c;
   12.91 +			*astate = S_GROUND;
   12.92 +			return (UNVIS_VALID);
   12.93 +		case '0': case '1': case '2': case '3':
   12.94 +		case '4': case '5': case '6': case '7':
   12.95 +			*cp = (c - '0');
   12.96 +			*astate = S_OCTAL2;
   12.97 +			return (0);
   12.98 +		case 'M':
   12.99 +			*cp = (char) 0200;
  12.100 +			*astate = S_META;
  12.101 +			return (0);
  12.102 +		case '^':
  12.103 +			*astate = S_CTRL;
  12.104 +			return (0);
  12.105 +		case 'n':
  12.106 +			*cp = '\n';
  12.107 +			*astate = S_GROUND;
  12.108 +			return (UNVIS_VALID);
  12.109 +		case 'r':
  12.110 +			*cp = '\r';
  12.111 +			*astate = S_GROUND;
  12.112 +			return (UNVIS_VALID);
  12.113 +		case 'b':
  12.114 +			*cp = '\b';
  12.115 +			*astate = S_GROUND;
  12.116 +			return (UNVIS_VALID);
  12.117 +		case 'a':
  12.118 +			*cp = '\007';
  12.119 +			*astate = S_GROUND;
  12.120 +			return (UNVIS_VALID);
  12.121 +		case 'v':
  12.122 +			*cp = '\v';
  12.123 +			*astate = S_GROUND;
  12.124 +			return (UNVIS_VALID);
  12.125 +		case 't':
  12.126 +			*cp = '\t';
  12.127 +			*astate = S_GROUND;
  12.128 +			return (UNVIS_VALID);
  12.129 +		case 'f':
  12.130 +			*cp = '\f';
  12.131 +			*astate = S_GROUND;
  12.132 +			return (UNVIS_VALID);
  12.133 +		case 's':
  12.134 +			*cp = ' ';
  12.135 +			*astate = S_GROUND;
  12.136 +			return (UNVIS_VALID);
  12.137 +		case 'E':
  12.138 +			*cp = '\033';
  12.139 +			*astate = S_GROUND;
  12.140 +			return (UNVIS_VALID);
  12.141 +		case '\n':
  12.142 +			/*
  12.143 +			 * hidden newline
  12.144 +			 */
  12.145 +			*astate = S_GROUND;
  12.146 +			return (UNVIS_NOCHAR);
  12.147 +		case '$':
  12.148 +			/*
  12.149 +			 * hidden marker
  12.150 +			 */
  12.151 +			*astate = S_GROUND;
  12.152 +			return (UNVIS_NOCHAR);
  12.153 +		}
  12.154 +		*astate = S_GROUND;
  12.155 +		return (UNVIS_SYNBAD);
  12.156 +		 
  12.157 +	case S_META:
  12.158 +		if (c == '-')
  12.159 +			*astate = S_META1;
  12.160 +		else if (c == '^')
  12.161 +			*astate = S_CTRL;
  12.162 +		else {
  12.163 +			*astate = S_GROUND;
  12.164 +			return (UNVIS_SYNBAD);
  12.165 +		}
  12.166 +		return (0);
  12.167 +		 
  12.168 +	case S_META1:
  12.169 +		*astate = S_GROUND;
  12.170 +		*cp |= c;
  12.171 +		return (UNVIS_VALID);
  12.172 +		 
  12.173 +	case S_CTRL:
  12.174 +		if (c == '?')
  12.175 +			*cp |= 0177;
  12.176 +		else
  12.177 +			*cp |= c & 037;
  12.178 +		*astate = S_GROUND;
  12.179 +		return (UNVIS_VALID);
  12.180 +
  12.181 +	case S_OCTAL2:	/* second possible octal digit */
  12.182 +		if (isoctal(c)) {
  12.183 +			/* 
  12.184 +			 * yes - and maybe a third 
  12.185 +			 */
  12.186 +			*cp = (*cp << 3) + (c - '0');
  12.187 +			*astate = S_OCTAL3;	
  12.188 +			return (0);
  12.189 +		} 
  12.190 +		/* 
  12.191 +		 * no - done with current sequence, push back passed char 
  12.192 +		 */
  12.193 +		*astate = S_GROUND;
  12.194 +		return (UNVIS_VALIDPUSH);
  12.195 +
  12.196 +	case S_OCTAL3:	/* third possible octal digit */
  12.197 +		*astate = S_GROUND;
  12.198 +		if (isoctal(c)) {
  12.199 +			*cp = (*cp << 3) + (c - '0');
  12.200 +			return (UNVIS_VALID);
  12.201 +		}
  12.202 +		/*
  12.203 +		 * we were done, push back passed char
  12.204 +		 */
  12.205 +		return (UNVIS_VALIDPUSH);
  12.206 +
  12.207 +	default:	
  12.208 +		/* 
  12.209 +		 * decoder in unknown state - (probably uninitialized) 
  12.210 +		 */
  12.211 +		*astate = S_GROUND;
  12.212 +		return (UNVIS_SYNBAD);
  12.213 +	}
  12.214 +}
  12.215 +
  12.216 +/*
  12.217 + * strunvis - decode src into dst 
  12.218 + *
  12.219 + *	Number of chars decoded into dst is returned, -1 on error.
  12.220 + *	Dst is null terminated.
  12.221 + */
  12.222 +
  12.223 +int
  12.224 +strunvis(char *dst, const char *src)
  12.225 +{
  12.226 +	char c;
  12.227 +	char *start = dst;
  12.228 +	int state = 0;
  12.229 +
  12.230 +	while ((c = *src++)) {
  12.231 +	again:
  12.232 +		switch (unvis(dst, c, &state, 0)) {
  12.233 +		case UNVIS_VALID:
  12.234 +			dst++;
  12.235 +			break;
  12.236 +		case UNVIS_VALIDPUSH:
  12.237 +			dst++;
  12.238 +			goto again;
  12.239 +		case 0:
  12.240 +		case UNVIS_NOCHAR:
  12.241 +			break;
  12.242 +		default:
  12.243 +			*dst = '\0';
  12.244 +			return (-1);
  12.245 +		}
  12.246 +	}
  12.247 +	if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
  12.248 +		dst++;
  12.249 +	*dst = '\0';
  12.250 +	return (dst - start);
  12.251 +}
  12.252 +
  12.253 +ssize_t
  12.254 +strnunvis(char *dst, const char *src, size_t sz)
  12.255 +{
  12.256 +	char c, p;
  12.257 +	char *start = dst, *end = dst + sz - 1;
  12.258 +	int state = 0;
  12.259 +
  12.260 +	if (sz > 0)
  12.261 +		*end = '\0';
  12.262 +	while ((c = *src++)) {
  12.263 +	again:
  12.264 +		switch (unvis(&p, c, &state, 0)) {
  12.265 +		case UNVIS_VALID:
  12.266 +			if (dst < end)
  12.267 +				*dst = p;
  12.268 +			dst++;
  12.269 +			break;
  12.270 +		case UNVIS_VALIDPUSH:
  12.271 +			if (dst < end)
  12.272 +				*dst = p;
  12.273 +			dst++;
  12.274 +			goto again;
  12.275 +		case 0:
  12.276 +		case UNVIS_NOCHAR:
  12.277 +			break;
  12.278 +		default:
  12.279 +			if (dst <= end)
  12.280 +				*dst = '\0';
  12.281 +			return (-1);
  12.282 +		}
  12.283 +	}
  12.284 +	if (unvis(&p, c, &state, UNVIS_END) == UNVIS_VALID) {
  12.285 +		if (dst < end)
  12.286 +			*dst = p;
  12.287 +		dst++;
  12.288 +	}
  12.289 +	if (dst <= end)
  12.290 +		*dst = '\0';
  12.291 +	return (dst - start);
  12.292 +}
  12.293 +
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/compat/vis.c	Wed Apr 01 14:57:57 2015 +0200
    13.3 @@ -0,0 +1,246 @@
    13.4 +/*	$OpenBSD: vis.c,v 1.25 2015/09/13 11:32:51 guenther Exp $ */
    13.5 +/*-
    13.6 + * Copyright (c) 1989, 1993
    13.7 + *	The Regents of the University of California.  All rights reserved.
    13.8 + *
    13.9 + * Redistribution and use in source and binary forms, with or without
   13.10 + * modification, are permitted provided that the following conditions
   13.11 + * are met:
   13.12 + * 1. Redistributions of source code must retain the above copyright
   13.13 + *    notice, this list of conditions and the following disclaimer.
   13.14 + * 2. Redistributions in binary form must reproduce the above copyright
   13.15 + *    notice, this list of conditions and the following disclaimer in the
   13.16 + *    documentation and/or other materials provided with the distribution.
   13.17 + * 3. Neither the name of the University nor the names of its contributors
   13.18 + *    may be used to endorse or promote products derived from this software
   13.19 + *    without specific prior written permission.
   13.20 + *
   13.21 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   13.22 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   13.23 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   13.24 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   13.25 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   13.26 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   13.27 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   13.28 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   13.29 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   13.30 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   13.31 + * SUCH DAMAGE.
   13.32 + */
   13.33 +
   13.34 +#include <sys/types.h>
   13.35 +#include <errno.h>
   13.36 +#include <ctype.h>
   13.37 +#include <limits.h>
   13.38 +#include <string.h>
   13.39 +#include <stdlib.h>
   13.40 +
   13.41 +#include "pws-compat.h"
   13.42 +#include "vis.h"
   13.43 +
   13.44 +#define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
   13.45 +#define	isvisible(c,flag)						\
   13.46 +	(((c) == '\\' || (flag & VIS_ALL) == 0) &&			\
   13.47 +	(((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) &&		\
   13.48 +	(((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') ||	\
   13.49 +		(flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) ||	\
   13.50 +	((flag & VIS_SP) == 0 && (c) == ' ') ||				\
   13.51 +	((flag & VIS_TAB) == 0 && (c) == '\t') ||			\
   13.52 +	((flag & VIS_NL) == 0 && (c) == '\n') ||			\
   13.53 +	((flag & VIS_SAFE) && ((c) == '\b' ||				\
   13.54 +		(c) == '\007' || (c) == '\r' ||				\
   13.55 +		isgraph((u_char)(c))))))
   13.56 +
   13.57 +typedef unsigned int u_int;
   13.58 +typedef unsigned char u_char;
   13.59 +
   13.60 +/*
   13.61 + * vis - visually encode characters
   13.62 + */
   13.63 +char *
   13.64 +vis(char *dst, int c, int flag, int nextc)
   13.65 +{
   13.66 +	if (isvisible(c, flag)) {
   13.67 +		if ((c == '"' && (flag & VIS_DQ) != 0) ||
   13.68 +		    (c == '\\' && (flag & VIS_NOSLASH) == 0))
   13.69 +			*dst++ = '\\';
   13.70 +		*dst++ = c;
   13.71 +		*dst = '\0';
   13.72 +		return (dst);
   13.73 +	}
   13.74 +
   13.75 +	if (flag & VIS_CSTYLE) {
   13.76 +		switch(c) {
   13.77 +		case '\n':
   13.78 +			*dst++ = '\\';
   13.79 +			*dst++ = 'n';
   13.80 +			goto done;
   13.81 +		case '\r':
   13.82 +			*dst++ = '\\';
   13.83 +			*dst++ = 'r';
   13.84 +			goto done;
   13.85 +		case '\b':
   13.86 +			*dst++ = '\\';
   13.87 +			*dst++ = 'b';
   13.88 +			goto done;
   13.89 +		case '\a':
   13.90 +			*dst++ = '\\';
   13.91 +			*dst++ = 'a';
   13.92 +			goto done;
   13.93 +		case '\v':
   13.94 +			*dst++ = '\\';
   13.95 +			*dst++ = 'v';
   13.96 +			goto done;
   13.97 +		case '\t':
   13.98 +			*dst++ = '\\';
   13.99 +			*dst++ = 't';
  13.100 +			goto done;
  13.101 +		case '\f':
  13.102 +			*dst++ = '\\';
  13.103 +			*dst++ = 'f';
  13.104 +			goto done;
  13.105 +		case ' ':
  13.106 +			*dst++ = '\\';
  13.107 +			*dst++ = 's';
  13.108 +			goto done;
  13.109 +		case '\0':
  13.110 +			*dst++ = '\\';
  13.111 +			*dst++ = '0';
  13.112 +			if (isoctal(nextc)) {
  13.113 +				*dst++ = '0';
  13.114 +				*dst++ = '0';
  13.115 +			}
  13.116 +			goto done;
  13.117 +		}
  13.118 +	}
  13.119 +	if (((c & 0177) == ' ') || (flag & VIS_OCTAL) ||
  13.120 +	    ((flag & VIS_GLOB) && (c == '*' || c == '?' || c == '[' || c == '#'))) {
  13.121 +		*dst++ = '\\';
  13.122 +		*dst++ = ((u_char)c >> 6 & 07) + '0';
  13.123 +		*dst++ = ((u_char)c >> 3 & 07) + '0';
  13.124 +		*dst++ = ((u_char)c & 07) + '0';
  13.125 +		goto done;
  13.126 +	}
  13.127 +	if ((flag & VIS_NOSLASH) == 0)
  13.128 +		*dst++ = '\\';
  13.129 +	if (c & 0200) {
  13.130 +		c &= 0177;
  13.131 +		*dst++ = 'M';
  13.132 +	}
  13.133 +	if (iscntrl((u_char)c)) {
  13.134 +		*dst++ = '^';
  13.135 +		if (c == 0177)
  13.136 +			*dst++ = '?';
  13.137 +		else
  13.138 +			*dst++ = c + '@';
  13.139 +	} else {
  13.140 +		*dst++ = '-';
  13.141 +		*dst++ = c;
  13.142 +	}
  13.143 +done:
  13.144 +	*dst = '\0';
  13.145 +	return (dst);
  13.146 +}
  13.147 +
  13.148 +/*
  13.149 + * strvis, strnvis, strvisx - visually encode characters from src into dst
  13.150 + *	
  13.151 + *	Dst must be 4 times the size of src to account for possible
  13.152 + *	expansion.  The length of dst, not including the trailing NULL,
  13.153 + *	is returned. 
  13.154 + *
  13.155 + *	Strnvis will write no more than siz-1 bytes (and will NULL terminate).
  13.156 + *	The number of bytes needed to fully encode the string is returned.
  13.157 + *
  13.158 + *	Strvisx encodes exactly len bytes from src into dst.
  13.159 + *	This is useful for encoding a block of data.
  13.160 + */
  13.161 +int
  13.162 +strvis(char *dst, const char *src, int flag)
  13.163 +{
  13.164 +	char c;
  13.165 +	char *start;
  13.166 +
  13.167 +	for (start = dst; (c = *src);)
  13.168 +		dst = vis(dst, c, flag, *++src);
  13.169 +	*dst = '\0';
  13.170 +	return (dst - start);
  13.171 +}
  13.172 +
  13.173 +int
  13.174 +strnvis(char *dst, const char *src, size_t siz, int flag)
  13.175 +{
  13.176 +	char *start, *end;
  13.177 +	char tbuf[5];
  13.178 +	int c, i;
  13.179 +
  13.180 +	i = 0;
  13.181 +	for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) {
  13.182 +		if (isvisible(c, flag)) {
  13.183 +			if ((c == '"' && (flag & VIS_DQ) != 0) ||
  13.184 +			    (c == '\\' && (flag & VIS_NOSLASH) == 0)) {
  13.185 +				/* need space for the extra '\\' */
  13.186 +				if (dst + 1 >= end) {
  13.187 +					i = 2;
  13.188 +					break;
  13.189 +				}
  13.190 +				*dst++ = '\\';
  13.191 +			}
  13.192 +			i = 1;
  13.193 +			*dst++ = c;
  13.194 +			src++;
  13.195 +		} else {
  13.196 +			i = vis(tbuf, c, flag, *++src) - tbuf;
  13.197 +			if (dst + i <= end) {
  13.198 +				memcpy(dst, tbuf, i);
  13.199 +				dst += i;
  13.200 +			} else {
  13.201 +				src--;
  13.202 +				break;
  13.203 +			}
  13.204 +		}
  13.205 +	}
  13.206 +	if (siz > 0)
  13.207 +		*dst = '\0';
  13.208 +	if (dst + i > end) {
  13.209 +		/* adjust return value for truncation */
  13.210 +		while ((c = *src))
  13.211 +			dst += vis(tbuf, c, flag, *++src) - tbuf;
  13.212 +	}
  13.213 +	return (dst - start);
  13.214 +}
  13.215 +
  13.216 +int
  13.217 +stravis(char **outp, const char *src, int flag)
  13.218 +{
  13.219 +	char *buf;
  13.220 +	int len, serrno;
  13.221 +
  13.222 +	buf = malloc(4 * strlen(src) + 1);
  13.223 +	if (buf == NULL)
  13.224 +		return -1;
  13.225 +	len = strvis(buf, src, flag);
  13.226 +	serrno = errno;
  13.227 +	*outp = realloc(buf, len + 1);
  13.228 +	if (*outp == NULL) {
  13.229 +		*outp = buf;
  13.230 +		errno = serrno;
  13.231 +	}
  13.232 +	return (len);
  13.233 +}
  13.234 +
  13.235 +int
  13.236 +strvisx(char *dst, const char *src, size_t len, int flag)
  13.237 +{
  13.238 +	char c;
  13.239 +	char *start;
  13.240 +
  13.241 +	for (start = dst; len > 1; len--) {
  13.242 +		c = *src;
  13.243 +		dst = vis(dst, c, flag, *++src);
  13.244 +	}
  13.245 +	if (len)
  13.246 +		dst = vis(dst, *src, flag, '\0');
  13.247 +	*dst = '\0';
  13.248 +	return (dst - start);
  13.249 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/compat/vis.h	Wed Apr 01 14:57:57 2015 +0200
    14.3 @@ -0,0 +1,87 @@
    14.4 +/*	$OpenBSD: vis.h,v 1.15 2015/07/20 01:52:27 millert Exp $	*/
    14.5 +/*	$NetBSD: vis.h,v 1.4 1994/10/26 00:56:41 cgd Exp $	*/
    14.6 +
    14.7 +/*-
    14.8 + * Copyright (c) 1990 The Regents of the University of California.
    14.9 + * All rights reserved.
   14.10 + *
   14.11 + * Redistribution and use in source and binary forms, with or without
   14.12 + * modification, are permitted provided that the following conditions
   14.13 + * are met:
   14.14 + * 1. Redistributions of source code must retain the above copyright
   14.15 + *    notice, this list of conditions and the following disclaimer.
   14.16 + * 2. Redistributions in binary form must reproduce the above copyright
   14.17 + *    notice, this list of conditions and the following disclaimer in the
   14.18 + *    documentation and/or other materials provided with the distribution.
   14.19 + * 3. Neither the name of the University nor the names of its contributors
   14.20 + *    may be used to endorse or promote products derived from this software
   14.21 + *    without specific prior written permission.
   14.22 + *
   14.23 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   14.24 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   14.25 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   14.26 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   14.27 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   14.28 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   14.29 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   14.30 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   14.31 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   14.32 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   14.33 + * SUCH DAMAGE.
   14.34 + *
   14.35 + *	@(#)vis.h	5.9 (Berkeley) 4/3/91
   14.36 + */
   14.37 +
   14.38 +#ifndef _VIS_H_
   14.39 +#define	_VIS_H_
   14.40 +
   14.41 +#include <sys/types.h>
   14.42 +
   14.43 +/*
   14.44 + * to select alternate encoding format
   14.45 + */
   14.46 +#define	VIS_OCTAL	0x01	/* use octal \ddd format */
   14.47 +#define	VIS_CSTYLE	0x02	/* use \[nrft0..] where appropriate */
   14.48 +
   14.49 +/*
   14.50 + * to alter set of characters encoded (default is to encode all
   14.51 + * non-graphic except space, tab, and newline).
   14.52 + */
   14.53 +#define	VIS_SP		0x04	/* also encode space */
   14.54 +#define	VIS_TAB		0x08	/* also encode tab */
   14.55 +#define	VIS_NL		0x10	/* also encode newline */
   14.56 +#define	VIS_WHITE	(VIS_SP | VIS_TAB | VIS_NL)
   14.57 +#define	VIS_SAFE	0x20	/* only encode "unsafe" characters */
   14.58 +#define	VIS_DQ		0x200	/* backslash-escape double quotes */
   14.59 +#define	VIS_ALL		0x400	/* encode all characters */
   14.60 +
   14.61 +/*
   14.62 + * other
   14.63 + */
   14.64 +#define	VIS_NOSLASH	0x40	/* inhibit printing '\' */
   14.65 +#define	VIS_GLOB	0x100	/* encode glob(3) magics and '#' */
   14.66 +
   14.67 +/*
   14.68 + * unvis return codes
   14.69 + */
   14.70 +#define	UNVIS_VALID	 1	/* character valid */
   14.71 +#define	UNVIS_VALIDPUSH	 2	/* character valid, push back passed char */
   14.72 +#define	UNVIS_NOCHAR	 3	/* valid sequence, no character produced */
   14.73 +#define	UNVIS_SYNBAD	-1	/* unrecognized escape sequence */
   14.74 +#define	UNVIS_ERROR	-2	/* decoder in unknown state (unrecoverable) */
   14.75 +
   14.76 +/*
   14.77 + * unvis flags
   14.78 + */
   14.79 +#define	UNVIS_END	1	/* no more characters */
   14.80 +
   14.81 +char	*vis(char *, int, int, int);
   14.82 +int	strvis(char *, const char *, int);
   14.83 +int	stravis(char **, const char *, int);
   14.84 +int	strnvis(char *, const char *, size_t, int);
   14.85 +int	strvisx(char *, const char *, size_t, int);
   14.86 +int	strunvis(char *, const char *);
   14.87 +int	unvis(char *, char, int *, int);
   14.88 +ssize_t strnunvis(char *, const char *, size_t);
   14.89 +
   14.90 +#endif /* !_VIS_H_ */
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/pwsdump.c	Wed Apr 01 14:57:57 2015 +0200
    15.3 @@ -0,0 +1,1118 @@
    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 <ctype.h>
   15.30 +#include <fcntl.h>
   15.31 +#include <unistd.h>
   15.32 +#include <stdlib.h>
   15.33 +#include <string.h>
   15.34 +#include <strings.h>
   15.35 +#include <stdio.h>
   15.36 +#include <inttypes.h>
   15.37 +#include <limits.h>
   15.38 +#include <time.h>
   15.39 +#include <errno.h>
   15.40 +#include <assert.h>
   15.41 +#include <libgen.h>
   15.42 +#include <sys/stat.h>
   15.43 +#ifdef	HAVE_READPASSPHRASE_H
   15.44 +#include <readpassphrase.h>
   15.45 +#endif /* HAVE_READPASSPHRASE_H */
   15.46 +#ifdef	HAVE_VIS_H
   15.47 +#include <vis.h>
   15.48 +#endif /* HAVE_VIS_H */
   15.49 +#ifdef	HAVE_SYS_ENDIAN_H
   15.50 +#include <sys/endian.h>
   15.51 +#else
   15.52 +#ifdef	HAVE_ENDIAN_H
   15.53 +#include <endian.h>
   15.54 +#endif /* HAVE_ENDIAN_H */
   15.55 +#endif /* HAVE_SYS_ENDIAN_H */
   15.56 +#ifdef	HAVE_ERR_H
   15.57 +#include <err.h>
   15.58 +#endif /* HAVE_ERR_H */
   15.59 +#include <pws.h>
   15.60 +
   15.61 +#define	EXIT_USAGE	2
   15.62 +#define	TIME_FORMAT	"%Y-%m-%dT%TZ"
   15.63 +#define	TIME_SIZE	(4 + 1 + 2 + 1 + 2 + 1 + 8 + 1 + 1)
   15.64 +
   15.65 +enum {
   15.66 +	FORMAT_PWS3,
   15.67 +	FORMAT_DUMP
   15.68 +};
   15.69 +
   15.70 +enum {
   15.71 +	INITIAL,
   15.72 +	IN_HEADER,
   15.73 +	IN_RECORD
   15.74 +};
   15.75 +
   15.76 +static void
   15.77 +header_field_dump_write(struct pws3_field *field, FILE *fp) {
   15.78 +	size_t			i;
   15.79 +	const char		*text;
   15.80 +	char			*vis_text;
   15.81 +	const unsigned char	*bytes;
   15.82 +	time_t			time;
   15.83 +	struct tm 		*tm;
   15.84 +	char			time_buf[TIME_SIZE];
   15.85 +	size_t			len;
   15.86 +
   15.87 +	fprintf(fp, "%02x:", pws3_field_get_type(field));
   15.88 +	switch (pws3_field_get_data_type(field)) {
   15.89 +	case PWS_DATA_TYPE_UUID:
   15.90 +		bytes = pws3_field_get_uuid(field);
   15.91 +		for (i = 0; i < 16; i++) {
   15.92 +			fprintf(fp, "%02x", bytes[i]);
   15.93 +		}
   15.94 +		fprintf(fp, "\n");
   15.95 +		break;
   15.96 +	case PWS_DATA_TYPE_TEXT:
   15.97 +		text = pws3_field_get_text(field);
   15.98 +		text = (text != NULL) ? text : "";
   15.99 +		vis_text = malloc(4 * strlen(text) + 1);
  15.100 +		if (vis_text == NULL) {
  15.101 +			err(1, NULL);
  15.102 +		}
  15.103 +		strvis(vis_text, text, VIS_TAB | VIS_NL | VIS_CSTYLE);
  15.104 +		fprintf(fp, "%s\n", vis_text);
  15.105 +		free(vis_text);
  15.106 +		break;
  15.107 +	case PWS_DATA_TYPE_TIME:
  15.108 +		time = pws3_field_get_time(field);
  15.109 +		tm = gmtime(&time);
  15.110 +		strftime(time_buf, sizeof (time_buf), TIME_FORMAT, tm);
  15.111 +		fprintf(fp, "%s\n", time_buf);
  15.112 +		break;
  15.113 +	case PWS_DATA_TYPE_UINT8:
  15.114 +		fprintf(fp, "%02" PRIx8 "\n",
  15.115 +		    pws3_field_get_uint8(field));
  15.116 +		break;
  15.117 +	case PWS_DATA_TYPE_UINT16:
  15.118 +		fprintf(fp, "%04" PRIx16 "\n",
  15.119 +		    pws3_field_get_uint16(field));
  15.120 +		break;
  15.121 +	case PWS_DATA_TYPE_UINT32:
  15.122 +		fprintf(fp, "%08" PRIx32 "\n",
  15.123 +		    pws3_field_get_uint32(field));
  15.124 +		break;
  15.125 +	case PWS_DATA_TYPE_BYTES:
  15.126 +		pws3_field_get_bytes(field, &bytes, &len);
  15.127 +		for (i = 0; i < len; i++) {
  15.128 +			fprintf(fp, "%s%02x", (i > 0) ? " " : "", bytes[i]);
  15.129 +		}
  15.130 +		fprintf(fp, "\n");
  15.131 +	}
  15.132 +}
  15.133 +
  15.134 +static void
  15.135 +record_field_dump_write(struct pws3_field *field, FILE *fp) {
  15.136 +	uint8_t			field_type;
  15.137 +	size_t			i;
  15.138 +	const char		*text;
  15.139 +	char			*vis_text;
  15.140 +	const unsigned char	*bytes;
  15.141 +	time_t			time;
  15.142 +	struct tm 		*tm;
  15.143 +	char			time_buf[TIME_SIZE];
  15.144 +	size_t			len;
  15.145 +
  15.146 +	field_type = pws3_field_get_type(field);
  15.147 +	fprintf(fp, "%02x:", field_type);
  15.148 +	switch (pws3_field_get_data_type(field)) {
  15.149 +	case PWS_DATA_TYPE_UUID:
  15.150 +		bytes = pws3_field_get_uuid(field);
  15.151 +		for (i = 0; i < 16; i++) {
  15.152 +			fprintf(fp, "%02x", bytes[i]);
  15.153 +		}
  15.154 +		fprintf(fp, "\n");
  15.155 +		break;
  15.156 +	case PWS_DATA_TYPE_TEXT:
  15.157 +		text = pws3_field_get_text(field);
  15.158 +		text = (text != NULL) ? text : "";
  15.159 +
  15.160 +		if (field_type == PWS3_RECORD_FIELD_PASSWORD) {
  15.161 +			vis_text = malloc(4 * strlen(text) + 1);
  15.162 +			if (vis_text == NULL) {
  15.163 +				err(1, NULL);
  15.164 +			}
  15.165 +		} else {
  15.166 +			vis_text = malloc(4 * strlen(text) + 1);
  15.167 +			if (vis_text == NULL) {
  15.168 +				err(1, NULL);
  15.169 +			}
  15.170 +		}
  15.171 +		strvis(vis_text, text, VIS_TAB | VIS_NL | VIS_CSTYLE);
  15.172 +		fprintf(fp, "%s\n", vis_text);
  15.173 +		if (field_type == PWS3_RECORD_FIELD_PASSWORD) {
  15.174 +			free(vis_text);
  15.175 +		} else {
  15.176 +			free(vis_text);
  15.177 +		}
  15.178 +		break;
  15.179 +	case PWS_DATA_TYPE_TIME:
  15.180 +		time = pws3_field_get_time(field);
  15.181 +		tm = gmtime(&time);
  15.182 +		strftime(time_buf, sizeof (time_buf), TIME_FORMAT, tm);
  15.183 +		fprintf(fp, "%s\n", time_buf);
  15.184 +		break;
  15.185 +	case PWS_DATA_TYPE_UINT8:
  15.186 +		fprintf(fp, "%02" PRIx8 "\n",
  15.187 +		    pws3_field_get_uint8(field));
  15.188 +		break;
  15.189 +	case PWS_DATA_TYPE_UINT16:
  15.190 +		fprintf(fp, "%04" PRIx16 "\n",
  15.191 +		    pws3_field_get_uint16(field));
  15.192 +		break;
  15.193 +	case PWS_DATA_TYPE_UINT32:
  15.194 +		fprintf(fp, "%08" PRIx32 "\n",
  15.195 +		    pws3_field_get_uint32(field));
  15.196 +		break;
  15.197 +	case PWS_DATA_TYPE_BYTES:
  15.198 +		pws3_field_get_bytes(field, &bytes, &len);
  15.199 +		for (i = 0; i < len; i++) {
  15.200 +			fprintf(fp, "%s%02x", (i > 0) ? " " : "", bytes[i]);
  15.201 +		}
  15.202 +		fprintf(fp, "\n");
  15.203 +	}
  15.204 +}
  15.205 +
  15.206 +static int
  15.207 +parse_hex_byte(const char *str, uint8_t *u8p)
  15.208 +{
  15.209 +	size_t	i;
  15.210 +	uint8_t	value;
  15.211 +	uint8_t	u8 = 0;
  15.212 +
  15.213 +	if (!(isascii(str[0]) && isxdigit(str[0])) ||
  15.214 +	    !(isascii(str[1]) && isxdigit(str[1]))) {
  15.215 +		return (-1);
  15.216 +	}
  15.217 +
  15.218 +	for (i = 0; i < 2; i++) {
  15.219 +		if (str[i] >= '0' && str[i] <= '9') {
  15.220 +			value = (str[i] - '0');
  15.221 +		} else if (str[i] >= 'A' && str[i] <= 'F') {
  15.222 +			value = (10 + (str[i] - 'A'));
  15.223 +		} else {
  15.224 +			value = (10 + (str[i] - 'a'));
  15.225 +		}
  15.226 +		u8 += value << ((2 - 1 - i) * 4);
  15.227 +	}
  15.228 +
  15.229 +	*u8p = u8;
  15.230 +
  15.231 +	return (0);
  15.232 +}
  15.233 +
  15.234 +static struct pws3_field *
  15.235 +header_field_dump_parse(const char *line)
  15.236 +{
  15.237 +	const char	*p = line;
  15.238 +	uint8_t		field_type;
  15.239 +	struct pws3_field *field = NULL;
  15.240 +	size_t		len;
  15.241 +	size_t		i;
  15.242 +	unsigned char	uuid[32];
  15.243 +	char		*text = NULL;
  15.244 +	struct tm	tm;
  15.245 +	uint8_t		u8;
  15.246 +	uint16_t	u16;
  15.247 +	uint32_t	u32;
  15.248 +	unsigned char	*bytes = NULL;
  15.249 +
  15.250 +	if (strlen(line) < 3) {
  15.251 +		goto err;
  15.252 +	}
  15.253 +
  15.254 +	if (parse_hex_byte(p, &field_type) != 0) {
  15.255 +		goto err;
  15.256 +	}
  15.257 +	p += 2;
  15.258 +	field = pws3_field_create(1, field_type);
  15.259 +	if (field == NULL) {
  15.260 +		err(1, NULL);
  15.261 +	}
  15.262 +
  15.263 +	if (*p++ != ':') {
  15.264 +		goto err;
  15.265 +	}
  15.266 +
  15.267 +	len = strlen(p);
  15.268 +
  15.269 +	switch (pws3_field_get_data_type(field)) {
  15.270 +	case PWS_DATA_TYPE_UUID:
  15.271 +		for (i = 0; i < 16; i++) {
  15.272 +			if (parse_hex_byte(p, &uuid[i]) != 0) {
  15.273 +				goto err;
  15.274 +			}
  15.275 +			p += 2;
  15.276 +
  15.277 +			while (*p == ' ') { p++; }
  15.278 +		}
  15.279 +
  15.280 +		if (*p != '\0') {
  15.281 +			goto err;
  15.282 +		}
  15.283 +
  15.284 +		if (pws3_field_set_uuid(field, uuid) != 0) {
  15.285 +			goto err;
  15.286 +		}
  15.287 +		break;
  15.288 +	case PWS_DATA_TYPE_TEXT:
  15.289 +		if (len > PWS3_MAX_FIELD_SIZE) {
  15.290 +			goto err;
  15.291 +		}
  15.292 +		text = malloc(len + 1);
  15.293 +		if (text == NULL) {
  15.294 +			err(1, NULL);
  15.295 +		}
  15.296 +		if (strunvis(text, p) == -1) {
  15.297 +			goto err;
  15.298 +		}
  15.299 +		if (pws3_field_set_text(field, text) != 0) {
  15.300 +			goto err;
  15.301 +		}
  15.302 +		break;
  15.303 +	case PWS_DATA_TYPE_TIME:
  15.304 +		p = strptime(p, TIME_FORMAT, &tm);
  15.305 +		if ((p == NULL) || (*p != '\0')) {
  15.306 +			goto err;
  15.307 +		}
  15.308 +		tm.tm_isdst = -1;
  15.309 +		pws3_field_set_time(field, mktime(&tm));
  15.310 +		break;
  15.311 +	case PWS_DATA_TYPE_UINT8:
  15.312 +		if (len != 2) {
  15.313 +			goto err;
  15.314 +		}
  15.315 +		if (parse_hex_byte(p, &u8) != 0) {
  15.316 +			goto err;
  15.317 +		}
  15.318 +		pws3_field_set_uint8(field, u8);
  15.319 +		break;
  15.320 +	case PWS_DATA_TYPE_UINT16:
  15.321 +		if (len != 4) {
  15.322 +			goto err;
  15.323 +		}
  15.324 +		for (i = 0; i < 2; i++) {
  15.325 +			if (parse_hex_byte(p, &((unsigned char *)&u16)[i]) !=
  15.326 +			    0) {
  15.327 +				goto err;
  15.328 +			}
  15.329 +			p += 2;
  15.330 +		}
  15.331 +		pws3_field_set_uint16(field, be16toh(u16));
  15.332 +		break;
  15.333 +	case PWS_DATA_TYPE_UINT32:
  15.334 +		if (len != 8) {
  15.335 +			goto err;
  15.336 +		}
  15.337 +		for (i = 0; i < 4; i++) {
  15.338 +			if (parse_hex_byte(p,
  15.339 +			    &((unsigned char *)&u32)[i]) != 0) {
  15.340 +				goto err;
  15.341 +			}
  15.342 +			p += 2;
  15.343 +		}
  15.344 +		pws3_field_set_uint16(field, be32toh(u32));
  15.345 +		break;
  15.346 +	case PWS_DATA_TYPE_BYTES:
  15.347 +		bytes = malloc(len / 2);
  15.348 +		if (bytes == NULL) {
  15.349 +			err(1, NULL);
  15.350 +		}
  15.351 +		for (i = 0; (*p != '\0') && (i < PWS3_MAX_FIELD_SIZE); i++) {
  15.352 +			if (parse_hex_byte(p, &bytes[i]) != 0) {
  15.353 +				goto err;
  15.354 +			}
  15.355 +			p += 2;
  15.356 +
  15.357 +			while (*p == ' ') { p++; }
  15.358 +		}
  15.359 +
  15.360 +		if (*p != '\0') {
  15.361 +			goto err;
  15.362 +		}
  15.363 +
  15.364 +		if (pws3_field_set_bytes(field, bytes, i) != 0) {
  15.365 +			goto err;
  15.366 +		}
  15.367 +	}
  15.368 +
  15.369 +	free(bytes);
  15.370 +	free(text);
  15.371 +
  15.372 +	return (field);
  15.373 +err:
  15.374 +	free(bytes);
  15.375 +	free(text);
  15.376 +	pws3_field_destroy(field);
  15.377 +
  15.378 +	return (NULL);
  15.379 +}
  15.380 +
  15.381 +static struct pws3_field *
  15.382 +record_field_dump_parse(const char *line)
  15.383 +{
  15.384 +	const char	*p = line;
  15.385 +	uint8_t		field_type = 0xff;
  15.386 +	struct pws3_field *field = NULL;
  15.387 +	size_t		len;
  15.388 +	size_t		i;
  15.389 +	unsigned char	uuid[32];
  15.390 +	char		*text = NULL;
  15.391 +	struct tm	tm;
  15.392 +	uint8_t		u8;
  15.393 +	uint16_t	u16;
  15.394 +	uint32_t	u32;
  15.395 +	unsigned char	*bytes = NULL;
  15.396 +
  15.397 +	if (strlen(line) < 3) {
  15.398 +		goto err;
  15.399 +	}
  15.400 +
  15.401 +	if (parse_hex_byte(p, &field_type) != 0) {
  15.402 +		goto err;
  15.403 +	}
  15.404 +	p += 2;
  15.405 +	field = pws3_field_create(0, field_type);
  15.406 +	if (field == NULL) {
  15.407 +		err(1, NULL);
  15.408 +	}
  15.409 +
  15.410 +	if (*p++ != ':') {
  15.411 +		goto err;
  15.412 +	}
  15.413 +
  15.414 +	len = strlen(p);
  15.415 +
  15.416 +	switch (pws3_field_get_data_type(field)) {
  15.417 +	case PWS_DATA_TYPE_UUID:
  15.418 +		for (i = 0; i < 16; i++) {
  15.419 +			if (parse_hex_byte(p, &uuid[i]) != 0) {
  15.420 +				goto err;
  15.421 +			}
  15.422 +			p += 2;
  15.423 +
  15.424 +			while (*p == ' ') { p++; }
  15.425 +		}
  15.426 +
  15.427 +		if (*p != '\0') {
  15.428 +			goto err;
  15.429 +		}
  15.430 +
  15.431 +		if (pws3_field_set_uuid(field, uuid) != 0) {
  15.432 +			goto err;
  15.433 +		}
  15.434 +		break;
  15.435 +	case PWS_DATA_TYPE_TEXT:
  15.436 +		if (((field_type == PWS3_RECORD_FIELD_PASSWORD) &&
  15.437 +		    (len > PWS3_MAX_PASSWORD_LEN)) ||
  15.438 +		    (len > PWS3_MAX_FIELD_SIZE)) {
  15.439 +			goto err;
  15.440 +		}
  15.441 +		if (field_type == PWS3_RECORD_FIELD_PASSWORD) {
  15.442 +			text = malloc(len + 1);
  15.443 +			if (text == NULL) {
  15.444 +				err(1, NULL);
  15.445 +			}
  15.446 +		} else {
  15.447 +			text = malloc(len + 1);
  15.448 +		}
  15.449 +		if (strunvis(text, p) == -1) {
  15.450 +			goto err;
  15.451 +		}
  15.452 +		if (pws3_field_set_text(field, text) != 0) {
  15.453 +			goto err;
  15.454 +		}
  15.455 +		break;
  15.456 +	case PWS_DATA_TYPE_TIME:
  15.457 +		p = strptime(p, TIME_FORMAT, &tm);
  15.458 +		if ((p == NULL) || (*p != '\0')) {
  15.459 +			goto err;
  15.460 +		}
  15.461 +		tm.tm_isdst = -1;
  15.462 +		pws3_field_set_time(field, mktime(&tm));
  15.463 +		break;
  15.464 +	case PWS_DATA_TYPE_UINT8:
  15.465 +		if (len != 2) {
  15.466 +			goto err;
  15.467 +		}
  15.468 +		if (parse_hex_byte(p, &u8) != 0) {
  15.469 +			goto err;
  15.470 +		}
  15.471 +		pws3_field_set_uint8(field, u8);
  15.472 +		break;
  15.473 +	case PWS_DATA_TYPE_UINT16:
  15.474 +		if (len != 4) {
  15.475 +			goto err;
  15.476 +		}
  15.477 +		for (i = 0; i < 2; i++) {
  15.478 +			if (parse_hex_byte(p, &((unsigned char *)&u16)[i]) !=
  15.479 +			    0) {
  15.480 +				goto err;
  15.481 +			}
  15.482 +			p += 2;
  15.483 +		}
  15.484 +		pws3_field_set_uint16(field, be16toh(u16));
  15.485 +		break;
  15.486 +	case PWS_DATA_TYPE_UINT32:
  15.487 +		if (len != 8) {
  15.488 +			goto err;
  15.489 +		}
  15.490 +		for (i = 0; i < 4; i++) {
  15.491 +			if (parse_hex_byte(p, &((unsigned char *)&u32)[i]) !=
  15.492 +			    0) {
  15.493 +				goto err;
  15.494 +			}
  15.495 +			p += 2;
  15.496 +		}
  15.497 +		pws3_field_set_uint16(field, be32toh(u32));
  15.498 +		break;
  15.499 +	case PWS_DATA_TYPE_BYTES:
  15.500 +		bytes = malloc(len / 2);
  15.501 +		if (bytes == NULL) {
  15.502 +			err(1, NULL);
  15.503 +		}
  15.504 +		for (i = 0; (*p != '\0') && (i < PWS3_MAX_FIELD_SIZE); i++) {
  15.505 +			if (parse_hex_byte(p, &bytes[i]) != 0) {
  15.506 +				goto err;
  15.507 +			}
  15.508 +			p += 2;
  15.509 +
  15.510 +			while (*p == ' ') { p++; }
  15.511 +		}
  15.512 +
  15.513 +		if (*p != '\0') {
  15.514 +			goto err;
  15.515 +		}
  15.516 +
  15.517 +		if (pws3_field_set_bytes(field, bytes, i) != 0) {
  15.518 +			goto err;
  15.519 +		}
  15.520 +	}
  15.521 +
  15.522 +	free(bytes);
  15.523 +	if (field_type == PWS3_RECORD_FIELD_PASSWORD) {
  15.524 +		free(text);
  15.525 +	} else {
  15.526 +		free(text);
  15.527 +	}
  15.528 +
  15.529 +	return (field);
  15.530 +err:
  15.531 +	free(bytes);
  15.532 +	if (field_type == PWS3_RECORD_FIELD_PASSWORD) {
  15.533 +		free(text);
  15.534 +	} else {
  15.535 +		free(text);
  15.536 +	}
  15.537 +	pws3_field_destroy(field);
  15.538 +
  15.539 +	return (NULL);
  15.540 +}
  15.541 +
  15.542 +static int
  15.543 +dump_read(struct pws3_file *file, FILE *fp)
  15.544 +{
  15.545 +	int		retval = -1;
  15.546 +	ssize_t		line_len;
  15.547 +	char		*line = NULL;
  15.548 +	size_t		line_size = 0;
  15.549 +	size_t		line_no = 0;
  15.550 +	int		state = INITIAL;
  15.551 +	struct pws3_field *header_field = NULL;
  15.552 +	struct pws3_record *record = NULL;
  15.553 +	struct pws3_field *record_field = NULL;
  15.554 +	struct pws3_field *field_uuid;
  15.555 +
  15.556 +	errno = 0;
  15.557 +	while ((line_len = getline(&line, &line_size, fp)) != -1) {
  15.558 +		line_no++;
  15.559 +
  15.560 +		/* skip empty lines and comments */
  15.561 +		if (line_len <= 1 || (line[0] == '#')) {
  15.562 +			continue;
  15.563 +		}
  15.564 +
  15.565 +		/* remove trailing newline */
  15.566 +		if (line[line_len - 1] == '\n') {
  15.567 +			line[line_len - 1] = '\0';
  15.568 +		}
  15.569 +
  15.570 +		switch (state) {
  15.571 +		case INITIAL:
  15.572 +			if (strcasecmp(line, "HEADER") == 0) {
  15.573 +				state = IN_HEADER;
  15.574 +			} else {
  15.575 +				warnx("syntax error in line %zu", line_no);
  15.576 +				goto out;
  15.577 +			}
  15.578 +			break;
  15.579 +		case IN_HEADER:
  15.580 +			if (strncasecmp(line, "RECORD",
  15.581 +			    strlen("RECORD")) == 0) {
  15.582 +				state = IN_RECORD;
  15.583 +			} else {
  15.584 +				header_field = header_field_dump_parse(line);
  15.585 +				if (header_field == NULL) {
  15.586 +					warnx("syntax error in line %zu",
  15.587 +					    line_no);
  15.588 +					goto out;
  15.589 +				}
  15.590 +				pws3_file_set_header_field(file, header_field);
  15.591 +				header_field = NULL;
  15.592 +			}
  15.593 +			break;
  15.594 +		case IN_RECORD:
  15.595 +			if (strncasecmp(line, "RECORD",
  15.596 +			    strlen("RECORD")) == 0) {
  15.597 +				if (record == NULL) {
  15.598 +					warnx("syntax error in line %zu",
  15.599 +					    line_no);
  15.600 +					goto out;
  15.601 +				}
  15.602 +
  15.603 +				/* check for mandatory UUID field */
  15.604 +				if (((field_uuid = pws3_record_get_field(record,
  15.605 +				    PWS3_RECORD_FIELD_UUID)) == NULL) ||
  15.606 +				    (pws3_field_get_uuid(field_uuid) ==
  15.607 +				    NULL)) {
  15.608 +					warnx("record ending on line %zu is "
  15.609 +					    "missing UUID field", line_no);
  15.610 +					goto out;
  15.611 +				}
  15.612 +				pws3_file_insert_record(file, record);
  15.613 +				record = NULL;
  15.614 +			} else {
  15.615 +				if (record == NULL) {
  15.616 +					record = pws3_record_create();
  15.617 +					if (record == NULL) {
  15.618 +						err(1, NULL);
  15.619 +					}
  15.620 +				}
  15.621 +
  15.622 +				record_field = record_field_dump_parse(line);
  15.623 +				if (record_field == NULL) {
  15.624 +					warnx("syntax error in line %zu",
  15.625 +					    line_no);
  15.626 +					goto out;
  15.627 +				}
  15.628 +				pws3_record_set_field(record, record_field);
  15.629 +				record_field = NULL;
  15.630 +			}
  15.631 +		}
  15.632 +		errno = 0;
  15.633 +	}
  15.634 +	if (errno != 0) {
  15.635 +		warn("failed to read from input file");
  15.636 +		goto out;
  15.637 +	}
  15.638 +	if (record != NULL) {
  15.639 +		/* check for mandatory UUID field */
  15.640 +		if (((field_uuid = pws3_record_get_field(record,
  15.641 +		    PWS3_RECORD_FIELD_UUID)) == NULL) ||
  15.642 +		    (pws3_field_get_uuid(field_uuid) == NULL)) {
  15.643 +			warnx("record ending on line %zu is missing UUID "
  15.644 +			    "field", line_no);
  15.645 +			goto out;
  15.646 +		}
  15.647 +		pws3_file_insert_record(file, record);
  15.648 +		record = NULL;
  15.649 +	}
  15.650 +
  15.651 +	retval = 0;
  15.652 +
  15.653 +out:
  15.654 +	pws3_field_destroy(header_field);
  15.655 +	pws3_field_destroy(record_field);
  15.656 +	pws3_record_destroy(record);
  15.657 +	free(line);
  15.658 +
  15.659 +	return (retval);
  15.660 +}
  15.661 +
  15.662 +static int
  15.663 +dump_write(struct pws3_file *file, FILE *fp)
  15.664 +{
  15.665 +	size_t		i;
  15.666 +	struct pws3_field *header_field;
  15.667 +	struct pws3_record *record;
  15.668 +	size_t		n;
  15.669 +	struct pws3_field *record_field;
  15.670 +
  15.671 +	if (fprintf(fp, "# Passwordsafe v3 database dump\nHeader\n") < 0) {
  15.672 +		warn("failed to write to output file");
  15.673 +		return (-1);
  15.674 +	}
  15.675 +	for (i = 0x00; i < 0xff; i++) {
  15.676 +		header_field = pws3_file_get_header_field(file, i);
  15.677 +		if (header_field != NULL) {
  15.678 +			header_field_dump_write(header_field, fp);
  15.679 +		}
  15.680 +
  15.681 +		while ((i == PWS3_HEADER_FIELD_EMPTY_GROUPS) &&
  15.682 +		    (header_field != NULL) &&
  15.683 +		    (header_field = pws3_file_next_empty_group(file,
  15.684 +		    header_field)) != NULL) {
  15.685 +			header_field_dump_write(header_field, fp);
  15.686 +		}
  15.687 +	}
  15.688 +
  15.689 +	for (record = pws3_file_first_record(file), n = 1; record != NULL;
  15.690 +	    record = pws3_file_next_record(file, record), n++) {
  15.691 +		if (fprintf(fp, "Record %zu\n", n) < 0) {
  15.692 +			warn("failed to write to output file");
  15.693 +			return (-1);
  15.694 +		}
  15.695 +
  15.696 +		for (i = 0x00; i <= 0xff; i++) {
  15.697 +			record_field = pws3_record_get_field(record, i);
  15.698 +			if (record_field != NULL) {
  15.699 +				record_field_dump_write(record_field, fp);
  15.700 +			}
  15.701 +		}
  15.702 +	}
  15.703 +
  15.704 +	return (0);
  15.705 +}
  15.706 +
  15.707 +void
  15.708 +usage(void)
  15.709 +{
  15.710 +	fprintf(stderr, "usage: pwsdump [-f pws3 | dump] [-o filename] "
  15.711 +	    "[-p password_file] [-P password_fd] [-t pws3 | dump] "
  15.712 +	    "input_file\n"
  15.713 +	    "       pwsdump -f dump [-o filename] [-t pws3 | dump]\n");
  15.714 +}
  15.715 +
  15.716 +int
  15.717 +main(int argc, char *argv[])
  15.718 +{
  15.719 +	int		status = EXIT_FAILURE;
  15.720 +	int		c;
  15.721 +	int		errflag = 0;
  15.722 +	int		from_format = FORMAT_PWS3;
  15.723 +	int		to_format = FORMAT_DUMP;
  15.724 +	const char	*in_filename = NULL;
  15.725 +	const char	*out_filename = NULL;
  15.726 +	const char	*new_password_filename = NULL;
  15.727 +	const char	*password_filename = NULL;
  15.728 +	int		fd_value = -1;
  15.729 +	char		*p;
  15.730 +	int		fd_new_password = -1;
  15.731 +	FILE *		fp_new_password = NULL;
  15.732 +	int		fd_password = -1;
  15.733 +	FILE *		fp_password = NULL;
  15.734 +	struct pws3_file *file = NULL;
  15.735 +	FILE		*fp_in = stdin;
  15.736 +	char		*password = NULL;
  15.737 +	ssize_t		password_len;
  15.738 +	size_t		password_size = PWS3_MAX_PASSWORD_LEN + 1;
  15.739 +	char		*new_password = NULL;
  15.740 +	ssize_t		new_password_len;
  15.741 +	size_t		new_password_size = PWS3_MAX_PASSWORD_LEN + 1;
  15.742 +	char		*confirm_password = NULL;
  15.743 +	FILE		*fp_out = stdout;
  15.744 +	struct stat	statbuf_in;
  15.745 +	struct stat	statbuf_out;
  15.746 +	int		need_tmpfile = 0;
  15.747 +	int		fd_tmp = -1;
  15.748 +	char		*out_filename_tmp = NULL;
  15.749 +	char		*out_dir = NULL;
  15.750 +	char		*tmp_filename = NULL;
  15.751 +	int		len;
  15.752 +	mode_t		old_mode;
  15.753 +
  15.754 +	setprogname(argv[0]);
  15.755 +
  15.756 +	if (pws_init() != 0) {
  15.757 +		goto out;
  15.758 +	}
  15.759 +
  15.760 +	/* timestamps are processed as UTC */
  15.761 +	if (setenv("TZ", "", 1) != 0) {
  15.762 +		goto out;
  15.763 +	}
  15.764 +	tzset();
  15.765 +
  15.766 +	while (!errflag && ((c = getopt(argc, argv, "f:n:N:o:p:P:t:")) != -1)) {
  15.767 +		switch (c) {
  15.768 +		case 'f':
  15.769 +			if (strcmp(optarg, "pws3") == 0) {
  15.770 +				from_format = FORMAT_PWS3;
  15.771 +			} else if (strcmp(optarg, "dump") == 0) {
  15.772 +				from_format = FORMAT_DUMP;
  15.773 +			} else {
  15.774 +				errflag = 1;
  15.775 +			}
  15.776 +			break;
  15.777 +		case 'n':
  15.778 +			fd_new_password = -1;
  15.779 +			new_password_filename = optarg;
  15.780 +			break;
  15.781 +		case 'N':
  15.782 +			new_password_filename = NULL;
  15.783 +			errno = 0;
  15.784 +			fd_value = strtol(optarg, &p, 10);
  15.785 +			if ((errno == 0) && (p != optarg) && (*p == '\0') &&
  15.786 +			    (fd_value >= 0) && (fd_value < INT_MAX)) {
  15.787 +				fd_new_password = (int)fd_value;
  15.788 +			} else {
  15.789 +				errflag = 1;
  15.790 +			}
  15.791 +			break;
  15.792 +		case 'o':
  15.793 +			out_filename = optarg;
  15.794 +			break;
  15.795 +		case 'p':
  15.796 +			fd_password = -1;
  15.797 +			password_filename = optarg;
  15.798 +			break;
  15.799 +		case 'P':
  15.800 +			password_filename = NULL;
  15.801 +			errno = 0;
  15.802 +			fd_value = strtol(optarg, &p, 10);
  15.803 +			if ((errno == 0) && (p != optarg) && (*p == '\0') &&
  15.804 +			    (fd_value >= 0) &&
  15.805 +			    (fd_value < INT_MAX)) {
  15.806 +				fd_password = (int)fd_value;
  15.807 +			} else {
  15.808 +				errflag = 1;
  15.809 +			}
  15.810 +			break;
  15.811 +		case 't':
  15.812 +			if (strcmp(optarg, "pws3") == 0) {
  15.813 +				to_format = FORMAT_PWS3;
  15.814 +			} else if (strcmp(optarg, "dump") == 0) {
  15.815 +				to_format = FORMAT_DUMP;
  15.816 +			} else {
  15.817 +				errflag = 1;
  15.818 +			}
  15.819 +			break;
  15.820 +		default:
  15.821 +			errflag = 1;
  15.822 +		}
  15.823 +	}
  15.824 +
  15.825 +	if (errflag || ((from_format == FORMAT_PWS3) && (argc != optind + 1)) ||
  15.826 +	    (argc > optind + 1)) {
  15.827 +		usage();
  15.828 +		status = EXIT_USAGE;
  15.829 +		goto out;
  15.830 +	}
  15.831 +
  15.832 +	if (optind == argc - 1) {
  15.833 +		in_filename = argv[optind];
  15.834 +	}
  15.835 +
  15.836 +	if (fd_password != -1) {
  15.837 +		fp_password = fdopen(fd_password, "r");
  15.838 +		if (fp_password == NULL) {
  15.839 +			warn("invalid password fd %d", fd_password);
  15.840 +			goto out;
  15.841 +		}
  15.842 +		fd_password = -1;
  15.843 +	} else if (password_filename != NULL) {
  15.844 +		fp_password = fopen(password_filename, "r");
  15.845 +		if (fp_password == NULL) {
  15.846 +			warn("could not open password file");
  15.847 +			goto out;
  15.848 +		}
  15.849 +	}
  15.850 +
  15.851 +	if (fd_new_password != -1) {
  15.852 +		fp_new_password = fdopen(fd_new_password, "r");
  15.853 +		if (fp_new_password == NULL) {
  15.854 +			warn("invalid password fd %d", fd_new_password);
  15.855 +			goto out;
  15.856 +		}
  15.857 +		fd_new_password = -1;
  15.858 +	} else if (new_password_filename != NULL) {
  15.859 +		fp_new_password = fopen(new_password_filename, "r");
  15.860 +		if (fp_new_password == NULL) {
  15.861 +			warn("could not open password file");
  15.862 +			goto out;
  15.863 +		}
  15.864 +	}
  15.865 +
  15.866 +	if (in_filename != NULL) {
  15.867 +		fp_in = fopen(in_filename, "r");
  15.868 +		if (fp_in == NULL) {
  15.869 +			warn("could not open input file");
  15.870 +			goto out;
  15.871 +		}
  15.872 +	}
  15.873 +
  15.874 +	if (out_filename != NULL) {
  15.875 +		if (in_filename != NULL) {
  15.876 +			if (fstat(fileno(fp_in), &statbuf_in) == -1) {
  15.877 +				warn("could not stat input file");
  15.878 +				status = EXIT_FAILURE;
  15.879 +				goto out;
  15.880 +			}
  15.881 +			if (stat(out_filename, &statbuf_out) == -1) {
  15.882 +				if (errno != ENOENT) {
  15.883 +					warn("could not stat output file");
  15.884 +					status = 1;
  15.885 +					goto out;
  15.886 +				}
  15.887 +			} else if ((statbuf_in.st_ino == statbuf_out.st_ino) &&
  15.888 +				    (statbuf_in.st_dev == statbuf_out.st_dev)) {
  15.889 +				need_tmpfile = 1;
  15.890 +			}
  15.891 +		}
  15.892 +
  15.893 +		if (need_tmpfile) {
  15.894 +			out_filename_tmp = strdup(out_filename);
  15.895 +			if (out_filename_tmp == NULL) {
  15.896 +				err(1, NULL);
  15.897 +			}
  15.898 +			out_dir = dirname(out_filename_tmp);
  15.899 +			len = snprintf(NULL, 0, "%s/pwsdumpXXXXXX", out_dir);
  15.900 +			if (len < 0) {
  15.901 +				warn(NULL);
  15.902 +				goto out;
  15.903 +			}
  15.904 +			tmp_filename = malloc((size_t)len + 1);
  15.905 +			if (tmp_filename == NULL) {
  15.906 +				err(1, NULL);
  15.907 +			}
  15.908 +			if (snprintf(tmp_filename, (size_t)len + 1,
  15.909 +			    "%s/pwsdumpXXXXXX", out_dir) != len) {
  15.910 +				warn(NULL);
  15.911 +				goto out;
  15.912 +			}
  15.913 +			old_mode = umask(077);
  15.914 +			fd_tmp = mkstemp(tmp_filename);
  15.915 +			umask(old_mode);
  15.916 +			if (fd_tmp == -1) {
  15.917 +				warn("could not create temporary file");
  15.918 +				goto out;
  15.919 +			}
  15.920 +			fp_out = fdopen(fd_tmp, "w");
  15.921 +			if (fp_out == NULL) {
  15.922 +				warn("could not open temporary file");
  15.923 +				goto out;
  15.924 +			}
  15.925 +			fd_tmp = -1;
  15.926 +		} else {
  15.927 +			old_mode = umask(077);
  15.928 +			fp_out = fopen(out_filename, "w");
  15.929 +			umask(old_mode);
  15.930 +			if (fp_out == NULL) {
  15.931 +				warn("could not open output file");
  15.932 +				goto out;
  15.933 +			}
  15.934 +		}
  15.935 +	}
  15.936 +
  15.937 +	file = pws3_file_create();
  15.938 +	if (file == NULL) {
  15.939 +		err(1, NULL);
  15.940 +	}
  15.941 +
  15.942 +	if (from_format == FORMAT_PWS3) {
  15.943 +		password = malloc(password_size);
  15.944 +		if (password ==  NULL) {
  15.945 +			err(1, NULL);
  15.946 +		}
  15.947 +		if (fp_password != NULL) {
  15.948 +			errno = 0;
  15.949 +			if (getline(&password, &password_size,
  15.950 +			    fp_password) == -1) {
  15.951 +				if (errno != 0) {
  15.952 +					warn("failed to read password");
  15.953 +				} else {
  15.954 +					warnx("failed to read password");
  15.955 +				}
  15.956 +				goto out;
  15.957 +			}
  15.958 +			password_len = strlen(password);
  15.959 +			/* strip trailing newline */
  15.960 +			if ((password_len > 0) &&
  15.961 +			    (password[password_len - 1] == '\n')) {
  15.962 +				password[password_len - 1] = '\0';
  15.963 +				password_len--;
  15.964 +			}
  15.965 +			if (password_len == 0) {
  15.966 +				warnx("invalid password");
  15.967 +				goto out;
  15.968 +			} else if (password_len > PWS3_MAX_PASSWORD_LEN) {
  15.969 +				warnx("password too long");
  15.970 +				goto out;
  15.971 +			}
  15.972 +		} else {
  15.973 +			if (readpassphrase("Enter password: ", password,
  15.974 +			    password_size, RPP_ECHO_OFF |
  15.975 +			    RPP_REQUIRE_TTY) == NULL) {
  15.976 +				err(1, NULL);
  15.977 +			}
  15.978 +			password_len = strlen(password);
  15.979 +		}
  15.980 +		if (password_len == 0) {
  15.981 +			warnx("invalid password");
  15.982 +			goto out;
  15.983 +		}
  15.984 +
  15.985 +		if (pws3_file_read_stream(file, password, fp_in) != 0) {
  15.986 +			warnx("%s", pws3_file_get_error_message(file));
  15.987 +			goto out;
  15.988 +		}
  15.989 +	} else {
  15.990 +		if (dump_read(file, fp_in) != 0) {
  15.991 +			goto out;
  15.992 +		}
  15.993 +	}
  15.994 +
  15.995 +	if (to_format == FORMAT_PWS3) {
  15.996 +		new_password = malloc(new_password_size);
  15.997 +		if (new_password == NULL) {
  15.998 +			err(1, NULL);
  15.999 +		}
 15.1000 +		if (fp_new_password != NULL) {
 15.1001 +			errno = 0;
 15.1002 +			if (getline(&new_password, &new_password_size,
 15.1003 +			    fp_new_password) == -1) {
 15.1004 +				if (errno != 0) {
 15.1005 +					warn("failed to read password");
 15.1006 +				} else {
 15.1007 +					warnx("failed to read password");
 15.1008 +				}
 15.1009 +				goto out;
 15.1010 +			}
 15.1011 +			new_password_len = strlen(new_password);
 15.1012 +			/* strip trailing newline */
 15.1013 +			if ((new_password_len > 0) &&
 15.1014 +			    (new_password[new_password_len - 1] == '\n')) {
 15.1015 +				new_password[new_password_len - 1] = '\0';
 15.1016 +				new_password_len--;
 15.1017 +			}
 15.1018 +			if (new_password_len == 0) {
 15.1019 +				warnx("invalid password");
 15.1020 +				goto out;
 15.1021 +			} else if (new_password_len > PWS3_MAX_PASSWORD_LEN) {
 15.1022 +				warnx("password too long");
 15.1023 +				goto out;
 15.1024 +			}
 15.1025 +		} else {
 15.1026 +			if (readpassphrase("Enter new password: ", new_password,
 15.1027 +			    PWS3_MAX_PASSWORD_LEN + 1, RPP_ECHO_OFF |
 15.1028 +			    RPP_REQUIRE_TTY) == NULL) {
 15.1029 +				err(1, NULL);
 15.1030 +			}
 15.1031 +			if (strlen(new_password) == 0) {
 15.1032 +				warnx("invalid password");
 15.1033 +				goto out;
 15.1034 +			}
 15.1035 +
 15.1036 +			confirm_password = malloc(PWS3_MAX_PASSWORD_LEN + 1);
 15.1037 +			if (confirm_password ==  NULL) {
 15.1038 +				err(1, NULL);
 15.1039 +			}
 15.1040 +			if (readpassphrase("Confirm new password: ",
 15.1041 +			    confirm_password, PWS3_MAX_PASSWORD_LEN + 1,
 15.1042 +			    RPP_ECHO_OFF | RPP_REQUIRE_TTY) == NULL) {
 15.1043 +				err(1, NULL);
 15.1044 +			}
 15.1045 +			if (strcmp(new_password, confirm_password) != 0) {
 15.1046 +				warnx("password mismatch");
 15.1047 +				goto out;
 15.1048 +			}
 15.1049 +		}
 15.1050 +
 15.1051 +		if (pws3_file_write_stream(file, new_password, 10000, fp_out) !=
 15.1052 +		    0) {
 15.1053 +			goto out;
 15.1054 +		}
 15.1055 +	} else {
 15.1056 +		if (dump_write(file, fp_out) != 0) {
 15.1057 +			goto out;
 15.1058 +		}
 15.1059 +		if (fflush(fp_out) != 0) {
 15.1060 +			warn("failed to flush output file");
 15.1061 +			goto out;
 15.1062 +		}
 15.1063 +	}
 15.1064 +
 15.1065 +	status = EXIT_SUCCESS;
 15.1066 +
 15.1067 +out:
 15.1068 +	if (fd_new_password != -1) {
 15.1069 +		close(fd_new_password);
 15.1070 +	}
 15.1071 +
 15.1072 +	if (fp_new_password != NULL) {
 15.1073 +		fclose(fp_new_password);
 15.1074 +	}
 15.1075 +
 15.1076 +	if (fd_password != -1) {
 15.1077 +		close(fd_password);
 15.1078 +	}
 15.1079 +
 15.1080 +	if (fp_password != NULL) {
 15.1081 +		fclose(fp_password);
 15.1082 +	}
 15.1083 +
 15.1084 +	if ((fp_in != NULL) && (fp_in != stdin)) {
 15.1085 +		fclose(fp_in);
 15.1086 +	}
 15.1087 +
 15.1088 +	if (fd_tmp != -1) {
 15.1089 +		close(fd_tmp);
 15.1090 +	}
 15.1091 +
 15.1092 +	if ((fp_out != NULL) && (fp_out != stdout)) {
 15.1093 +		fclose(fp_out);
 15.1094 +		if (status == EXIT_SUCCESS) {
 15.1095 +			if (need_tmpfile) {
 15.1096 +				if (rename(tmp_filename, out_filename) == -1) {
 15.1097 +					warn("could not create output file");
 15.1098 +					status = EXIT_FAILURE;
 15.1099 +					unlink(tmp_filename);
 15.1100 +				}
 15.1101 +			}
 15.1102 +		} else {
 15.1103 +			if (need_tmpfile) {
 15.1104 +				unlink(tmp_filename);
 15.1105 +			} else {
 15.1106 +				unlink(out_filename);
 15.1107 +			}
 15.1108 +		}
 15.1109 +	}
 15.1110 +
 15.1111 +	pws3_file_destroy(file);
 15.1112 +	free(out_filename_tmp);
 15.1113 +	free(tmp_filename);
 15.1114 +	free(confirm_password);
 15.1115 +	free(new_password);
 15.1116 +	free(password);
 15.1117 +
 15.1118 +	pws_finalize();
 15.1119 +
 15.1120 +	exit(status);
 15.1121 +}