Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37404696
en ru br
Репозитории ALT
S:0.3-alt1.qa1
5.1: 0.3-alt1
4.1: 0.3-alt1
4.0: 0.3-alt1
3.0: 0.2.0-alt3
www.altlinux.org/Changes

Группа :: Система/Основа
Пакет: hashalot

 Главная   Изменения   Спек   Патчи   Sources   Загрузить   Gear   Bugs and FR  Repocop 

Патч: hashalot-0.3-alt1.qa1.patch
Скачать


 ChangeLog     |   2 +-
 Makefile.am   |  14 ++-
 configure.ac  |  19 +++-
 getline.h     |  39 +++++++
 getpass.c     | 182 +++++++++++++++++++++++++++++++++
 getpass.h     |   7 ++
 hashalot.1    |  42 --------
 hashalot.8    |  42 ++++++++
 hashalot.c    | 323 +++++++++++++++++++++++++++++++---------------------------
 sha512.c      |  14 +--
 sha512.h      |  10 +-
 unlocked-io.h | 132 ++++++++++++++++++++++++
 12 files changed, 614 insertions(+), 212 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index b3fd1f7..909db3c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -23,7 +23,7 @@
 	 * forgot to erase the passphrase from memory when using a salt
 
 	 * manpage created
-	
+
 
 2004-02-08  Ben Slusky  <sluskyb@paranoiacs.org>
 
diff --git a/Makefile.am b/Makefile.am
index 4fcc6fd..973e063 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,9 +1,9 @@
 
 sbin_PROGRAMS = hashalot
 
-man_MANS = hashalot.1
+man_MANS = hashalot.8
 
-hashalot_SOURCES = hashalot.c rmd160.c rmd160.h sha512.c sha512.h
+hashalot_SOURCES = hashalot.c getpass.c rmd160.c rmd160.h sha512.c sha512.h
 
 install-exec-hook:
 	cd $(DESTDIR)$(sbindir) && \
@@ -12,9 +12,19 @@ install-exec-hook:
 	$(LN_S) -f hashalot$(EXEEXT) sha384$(EXEEXT) && \
 	$(LN_S) -f hashalot$(EXEEXT) sha512$(EXEEXT)
 
+install-data-hook:
+	cd $(DESTDIR)$(mandir)/man8 && \
+	$(LN_S) -f hashalot.8 rmd160.8 && \
+	$(LN_S) -f hashalot.8 sha256.8 && \
+	$(LN_S) -f hashalot.8 sha384.8 && \
+	$(LN_S) -f hashalot.8 sha512.8
+
 uninstall-hook:
 	cd $(DESTDIR)$(sbindir) && \
 	rm -f rmd160 sha256 sha384 sha512
+	cd $(DESTDIR)$(mandir)/man8 && \
+	rm -f rmd160.8 sha256.8 sha384.8 sha512.8
 
 TESTS = check.sh
 
+EXTRA_DIST = check.sh
diff --git a/configure.ac b/configure.ac
index d14db24..31996c2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,12 +1,25 @@
 AC_INIT(hashalot.c)
-AM_INIT_AUTOMAKE(hashalot, 0.1.0)
+AM_INIT_AUTOMAKE(hashalot, 0.3.0)
+AC_CONFIG_HEADERS([config.h])
 
+AC_GNU_SOURCE
 AC_PROG_INSTALL
 AC_PROG_CC
 AC_PROG_LN_S
 
 AC_HEADER_STDC
-AC_CHECK_HEADERS(libgen.h stdio.h stdlib.h string.h unistd.h assert.h sys/types.h sys/mman.h endian.h , , [ AC_MSG_ERROR(required header not found)])
-AC_CHECK_FUNCS(getopt snprintf , , [ AC_MSG_ERROR(required function not found)])
+AC_CHECK_HEADERS(
+   [errno.h error.h stdbool.h stddef.h stdio.h stdio_ext.h \
+    stdlib.h string.h unistd.h sys/types.h sys/mman.h endian.h], ,
+   [AC_MSG_ERROR(required header not found)])
+AC_CHECK_FUNCS(
+   [asprintf error getline getopt snprintf tcgetattr], ,
+   [AC_MSG_ERROR(required function not found)])
+
+AC_CHECK_DECLS(
+   [clearerr_unlocked, feof_unlocked, ferror_unlocked,
+    fflush_unlocked, fgets_unlocked, fputc_unlocked, fputs_unlocked,
+    fread_unlocked, fwrite_unlocked, getc_unlocked,
+    getchar_unlocked, putc_unlocked, putchar_unlocked])
 
 AC_OUTPUT(Makefile)
diff --git a/getline.h b/getline.h
new file mode 100644
index 0000000..ee9fc05
--- /dev/null
+++ b/getline.h
@@ -0,0 +1,39 @@
+/* Replacement for GNU C library function getline
+
+   Copyright (C) 1995, 1997, 1999, 2000, 2001, 2002, 2003 Free
+   Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef GETLINE_H_
+# define GETLINE_H_ 1
+
+# include <stddef.h>
+# include <stdio.h>
+
+/* Get ssize_t.  */
+# include <sys/types.h>
+
+/* glibc2 has these functions declared in <stdio.h>.  Avoid redeclarations.  */
+# if __GLIBC__ < 2
+
+extern ssize_t getline (char **_lineptr, size_t *_linesize, FILE *_stream);
+
+extern ssize_t getdelim (char **_lineptr, size_t *_linesize, int _delimiter,
+			  FILE *_stream);
+
+# endif
+
+#endif /* not GETLINE_H_ */
diff --git a/getpass.c b/getpass.c
new file mode 100644
index 0000000..c46966f
--- /dev/null
+++ b/getpass.c
@@ -0,0 +1,182 @@
+/* Copyright (C) 1992-2001, 2003 Free Software Foundation, Inc.
+   This file was part of the GNU C Library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if _LIBC
+# define HAVE_STDIO_EXT_H 1
+#endif
+
+#include <stdbool.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#if HAVE_STDIO_EXT_H
+# include <stdio_ext.h>
+#else
+# define __fsetlocking(stream, type) /* empty */
+#endif
+#if !_LIBC
+# include "getline.h"
+#endif
+
+#include <termios.h>
+#include <unistd.h>
+
+#if _LIBC
+# include <wchar.h>
+#endif
+
+#if _LIBC
+# define NOTCANCEL_MODE "c"
+#else
+# define NOTCANCEL_MODE
+#endif
+
+#if _LIBC
+# define flockfile(s) _IO_flockfile (s)
+# define funlockfile(s) _IO_funlockfile (s)
+#else
+# include "unlocked-io.h"
+#endif
+
+#if _LIBC
+# include <bits/libc-lock.h>
+#else
+# define __libc_cleanup_push(function, arg) /* empty */
+# define __libc_cleanup_pop(execute) /* empty */
+#endif
+
+#if !_LIBC
+# define __getline getline
+# define __tcgetattr tcgetattr
+#endif
+
+/* It is desirable to use this bit on systems that have it.
+   The only bit of terminal state we want to twiddle is echoing, which is
+   done in software; there is no need to change the state of the terminal
+   hardware.  */
+
+#ifndef TCSASOFT
+# define TCSASOFT 0
+#endif
+
+static void
+call_fclose (void *arg)
+{
+  if (arg != NULL)
+    fclose (arg);
+}
+
+char *
+xgetpass (const char *prompt)
+{
+  FILE *tty;
+  FILE *in, *out;
+  struct termios s, t;
+  bool tty_changed;
+  char *buf = NULL;
+  size_t bufsize = 0;
+  ssize_t nread;
+
+  /* Try to write to and read from the terminal if we can.
+     If we can't open the terminal, use stderr and stdin.  */
+
+  tty = fopen ("/dev/tty", "w+" NOTCANCEL_MODE);
+  if (tty == NULL)
+    {
+      in = stdin;
+      out = stderr;
+    }
+  else
+    {
+      /* We do the locking ourselves.  */
+      __fsetlocking (tty, FSETLOCKING_BYCALLER);
+
+      out = in = tty;
+    }
+
+  /* Make sure the stream we opened is closed even if the thread is
+     canceled.  */
+  __libc_cleanup_push (call_fclose, tty);
+
+  flockfile (out);
+
+  /* Turn echoing off if it is on now.  */
+
+  if (__tcgetattr (fileno (in), &t) == 0)
+    {
+      /* Save the old one. */
+      s = t;
+      /* Tricky, tricky. */
+      t.c_lflag &= ~(ECHO|ISIG);
+      tty_changed = (tcsetattr (fileno (in), TCSAFLUSH|TCSASOFT, &t) == 0);
+    }
+  else
+    tty_changed = false;
+
+  /* Write the prompt.  */
+#ifdef USE_IN_LIBIO
+  if (_IO_fwide (out, 0) > 0)
+    __fwprintf (out, L"%s", prompt);
+  else
+#endif
+    fputs_unlocked (prompt, out);
+  fflush_unlocked (out);
+
+  /* Read the password.  */
+  errno = 0;
+  nread = __getline (&buf, &bufsize, in);
+
+  if (buf != NULL)
+    {
+      if (nread < 0)
+        {
+	  free (buf);
+	  buf = NULL;
+	}
+      else if ((nread > 0) && (buf[nread - 1] == '\n'))
+	{
+	  /* Remove the newline.  */
+	  buf[nread - 1] = '\0';
+	}
+    }
+
+  if (tty_changed)
+    {
+      /* Write the newline that was not echoed.  */
+#ifdef USE_IN_LIBIO
+      if (_IO_fwide (out, 0) > 0)
+	putwc_unlocked (L'\n', out);
+      else
+#endif
+	putc_unlocked ('\n', out);
+      /* Restore the original setting.  */
+      (void) tcsetattr (fileno (in), TCSAFLUSH|TCSASOFT, &s);
+    }
+
+  funlockfile (out);
+
+  __libc_cleanup_pop (0);
+
+  call_fclose (tty);
+
+  return buf;
+}
diff --git a/getpass.h b/getpass.h
new file mode 100644
index 0000000..131947c
--- /dev/null
+++ b/getpass.h
@@ -0,0 +1,7 @@
+#ifndef GETPASS_H_
+#define GETPASS_H_
+
+char *
+xgetpass (const char *prompt);
+
+#endif /* GETPASS_H_ */
diff --git a/hashalot.1 b/hashalot.1
deleted file mode 100644
index 20ace86..0000000
--- a/hashalot.1
+++ /dev/null
@@ -1,42 +0,0 @@
-.TH HASHALOT 1 "09 Feb 2004"
-.SH NAME
-hashalot \- read a passphrase and print a hash
-.SH SYNOPSIS
-.B  hashalot [ \-s SALT ] [ \-x ] [ \-n #BYTES ] HASHTYPE
-.br
-.B  HASHTYPE [ \-s SALT ] [ \-x ] [ \-n #BYTES ]
-.SH DESCRIPTION
-.PP
-\fIhashalot\fP is a small tool that reads a passphrase from standard
-input, hashes it using the given hash type, and prints the result to
-standard output.
-.PP
-Supported values for \fIHASHTYPE\fP:
-.br
-.RS 8
-ripemd160 rmd160 rmd160compat sha256 sha384 sha512
-.RE
-.PP
-.SH OPTIONS
-.l
-The option
-.B \-s \fISALT\fP
-specifies an initialization vector to the hashing algorithm. You need
-this if you want to prevent identical passwords to map to identical
-hashes, which is a security risk.
-.PP
-If the
-.B \-x
-option is given then the hash will be printed as a string of hexadecimal
-digits.
-.PP
-The
-.B \-n
-option can be used to limit (or increase) the number of bytes output. The
-default is as appropriate for the specified hash algorithm: 20 bytes for
-RIPEMD160, 32 bytes for SHA256, etc. The default for the "rmd160compat"
-hash is 16 bytes, for compatibility with the old kerneli.org utilities.
-.SH AUTHOR
-Ben Slusky <sluskyb@paranoiacs.org>
-.PP
-This manual page was written by Matthias Urlichs <smurf@debian.org>.
diff --git a/hashalot.8 b/hashalot.8
new file mode 100644
index 0000000..20ace86
--- /dev/null
+++ b/hashalot.8
@@ -0,0 +1,42 @@
+.TH HASHALOT 1 "09 Feb 2004"
+.SH NAME
+hashalot \- read a passphrase and print a hash
+.SH SYNOPSIS
+.B  hashalot [ \-s SALT ] [ \-x ] [ \-n #BYTES ] HASHTYPE
+.br
+.B  HASHTYPE [ \-s SALT ] [ \-x ] [ \-n #BYTES ]
+.SH DESCRIPTION
+.PP
+\fIhashalot\fP is a small tool that reads a passphrase from standard
+input, hashes it using the given hash type, and prints the result to
+standard output.
+.PP
+Supported values for \fIHASHTYPE\fP:
+.br
+.RS 8
+ripemd160 rmd160 rmd160compat sha256 sha384 sha512
+.RE
+.PP
+.SH OPTIONS
+.l
+The option
+.B \-s \fISALT\fP
+specifies an initialization vector to the hashing algorithm. You need
+this if you want to prevent identical passwords to map to identical
+hashes, which is a security risk.
+.PP
+If the
+.B \-x
+option is given then the hash will be printed as a string of hexadecimal
+digits.
+.PP
+The
+.B \-n
+option can be used to limit (or increase) the number of bytes output. The
+default is as appropriate for the specified hash algorithm: 20 bytes for
+RIPEMD160, 32 bytes for SHA256, etc. The default for the "rmd160compat"
+hash is 16 bytes, for compatibility with the old kerneli.org utilities.
+.SH AUTHOR
+Ben Slusky <sluskyb@paranoiacs.org>
+.PP
+This manual page was written by Matthias Urlichs <smurf@debian.org>.
diff --git a/hashalot.c b/hashalot.c
index 8823dea..c31ec4a 100644
--- a/hashalot.c
+++ b/hashalot.c
@@ -6,77 +6,89 @@
 ** an encryption key.
 **
 ** USAGE:
-**		hashalot [ -x ] [ -s _salt_ ] [ -n _#bytes_ ] _hashtype_
+**		hashalot [ -q ] [ -x ] [ -s _salt_ ] [ -n _#bytes_ ] _hashtype_
 **	OR
-**		_hashtype_ [ -x ] [ -s _salt_ ] [ -n _#bytes_ ]
+**		_hashtype_ [ -q ] [ -x ] [ -s _salt_ ] [ -n _#bytes_ ]
 **
 ** Most of the code was cribbed from the kerneli.org patch to util-linux,
 ** by Marc Mutz <Marc@Mutz.com>. Most of what wasn't, was cribbed from GnuPG,
 ** v.1.0.3 (http://www.gnupg.org/).
 */
 
-#include <libgen.h>
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <assert.h>
+#include <errno.h>
+#include <error.h>
 
 #include <sys/types.h>
 #include <sys/mman.h>
 
 #include "rmd160.h"
 #include "sha512.h"
+#include "getpass.h"
 
 #define PASSWDBUFFLEN 130
 
-typedef int (*phash_func_t)(char dest[], size_t dest_len, const char src[], size_t src_len);
+const char *progname;
+
+typedef int (*phash_func_t) (char *dest, size_t dest_len,
+			     const char *src, size_t src_len);
 
 static int
-phash_rmd160(char dest[], size_t dest_len, const char src[], size_t src_len)
+phash_rmd160(char *dest, size_t dest_len, const char *src, size_t src_len)
 {
-	char tmp[PASSWDBUFFLEN] = { 'A', 0, };
-	char key[RMD160_HASH_SIZE * 2] = { 0, };
+	char    tmp[PASSWDBUFFLEN] = { 'A', 0, };
+	char    key[RMD160_HASH_SIZE * 2] = { 0, };
+
+	strncat(tmp, src, sizeof(tmp) - 1);
 
-	strncpy(tmp + 1, src, PASSWDBUFFLEN - 1);
-	tmp[PASSWDBUFFLEN - 1] = '\0';
-  
 	rmd160_hash_buffer(key, src, src_len);
-	rmd160_hash_buffer(key + RMD160_HASH_SIZE, tmp, src_len + 1 /* dangerous! */);
+	rmd160_hash_buffer(key + RMD160_HASH_SIZE, tmp,
+			   src_len + 1 /* dangerous! */ );
 
 	memcpy(dest, key, dest_len);
 
-	memset (tmp, 0, PASSWDBUFFLEN);        /* paranoia */
-	memset (key, 0, RMD160_HASH_SIZE * 2); /* paranoia */
+	memset(tmp, 0, sizeof tmp);	/* paranoia */
+	memset(key, 0, sizeof key);	/* paranoia */
 
 	return dest_len;
 }
 
 static int
-phash_sha256(char dest[], size_t dest_len, const char src[], size_t src_len)
+phash_sha256(char *dest, size_t dest_len, const char *src, size_t src_len)
 {
 	memset(dest, 0, dest_len);
-	sha256_hash_buffer((char *) src, src_len, dest, dest_len);
+	sha256_hash_buffer((const unsigned char *) src, src_len,
+			   (unsigned char *) dest, dest_len);
 	return dest_len;
 }
 
 static int
-phash_sha384(char dest[], size_t dest_len, const char src[], size_t src_len)
+phash_sha384(char *dest, size_t dest_len, const char *src, size_t src_len)
 {
 	memset(dest, 0, dest_len);
-	sha384_hash_buffer((char *) src, src_len, dest, dest_len);
+	sha384_hash_buffer((const unsigned char *) src, src_len,
+			   (unsigned char *) dest, dest_len);
 	return dest_len;
 }
 
 static int
-phash_sha512(char dest[], size_t dest_len, const char src[], size_t src_len)
+phash_sha512(char *dest, size_t dest_len, const char *src, size_t src_len)
 {
 	memset(dest, 0, dest_len);
-	sha512_hash_buffer((char *) src, src_len, dest, dest_len);
+	sha512_hash_buffer((const unsigned char *) src, src_len,
+			   (unsigned char *) dest, dest_len);
 	return dest_len;
 }
 
-struct func_table_t {
+struct func_table_t
+{
 	const char *name;
 	phash_func_t func;
 	size_t def_length;
@@ -90,197 +102,204 @@ struct func_table_t {
 	{ 0, 0, 0 }
 };
 
-static int
-show_usage(const char argv0[])
+static int __attribute__ ((__noreturn__))
+show_usage(void)
 {
 	struct func_table_t *p = func_table;
 
-	fprintf (stderr,
-		 "usage:\n"
-		 "    hashalot [ -x ] [ -s SALT ] [ -n _#bytes_ ] HASHTYPE\n"
-		 "  or\n"
-		 "    HASHTYPE [ -x ] [ -s SALT ] [ -n _#bytes_ ]\n"
-		 "\n"
-		 "supported values for HASHTYPE: ");
+	fprintf(stderr,
+		"usage:\n"
+		"    hashalot [ -q ] [ -x ] [ -s SALT ] [ -n _#bytes_ ] HASHTYPE\n"
+		"  or\n"
+		"    HASHTYPE [ -q ] [ -x ] [ -s SALT ] [ -n _#bytes_ ]\n"
+		"\n" "supported values for HASHTYPE:");
 
 	for (; p->name; ++p)
-		fprintf (stderr, "%s ", p->name);
+		fprintf(stderr, " %s", p->name);
+
+	fprintf(stderr, "\n");
 
-	fprintf (stderr, "\n");
-	
-	return 1;
+	exit(EXIT_FAILURE);
 }
 
-static phash_func_t 
-phash_lookup(const char phash_name[], size_t *length)
+static  phash_func_t
+phash_lookup(const char *phash_name, size_t *length)
 {
 	struct func_table_t *p = func_table;
 
 	if (!phash_name)
 		return 0;
 
-	for (; p->name && strcmp(phash_name, p->name); ++p);
-  
-	if (length) *length = p->def_length;
+	for (; p->name && strcmp(phash_name, p->name); ++p)
+		;
+	if (length)
+		*length = p->def_length;
 	return p->func;
 }
 
-/* A function to read the passphrase either from the terminal or from
- * an open file descriptor */
 static char *
-xgetpass(const char *prompt)
+zeroize(char *str)
 {
-	if (isatty(STDIN_FILENO))	/* terminal */
-		return getpass(prompt); /* FIXME getpass(3) obsolete */
-	else {				/* file descriptor */
-		char *pass = NULL;
-		int buflen, i;
-
-		buflen=0;
-		for (i=0; ; i++) {
-			if (i >= buflen - 1) {
-				/* we're running out of space in the buffer. 
-				 * Make it bigger: */
-				char *tmppass = pass;
-				buflen += 128;
-				pass = (char *) realloc(tmppass, buflen);
-				if (pass == NULL) {
-					/* realloc failed. Stop reading _now_. */
-					fprintf(stderr, "not enough memory while reading passphrase\n");
-					pass = tmppass; /* the old buffer hasn't changed */
-					break;
-				}
-			}
-			if (read(STDIN_FILENO, pass+i, 1) != 1 || pass[i] == '\n')
-				break;
-		}
-		if (pass == NULL)
-			return "";
-		else {
-			pass[i] = 0;
-			return pass;
-		}
-	}
-}
-
-static void *
-xmalloc (size_t size) {
-        void *p;
-
-        if (size == 0)
-                return NULL;
+	char *p = str;
 
-        p = malloc(size);
-        if (p == NULL) {
-		perror("malloc");
-                exit(1);
-        }
-
-        return p;
+	while (*p)
+		*p++ = '\0';
+	return str;
 }
 
 /* function to append a "salt" to the passphrase, to better resist
  * dictionary attacks */
 static char *
-salt_passphrase(char *pass, char *salt) {
-	char *buf = xmalloc(strlen(pass) + strlen(salt) + 1);
-	sprintf(buf, "%s%s", pass, salt);
+salt_passphrase(char *pass, const char *salt)
+{
+	char   *buf;
+	int     rc;
 
-	memset (pass, 0, strlen (pass)); /* paranoia */
-	free(pass);
+	rc = asprintf(&buf, "%s%s", pass, salt);
+	zeroize(pass);
+	if (rc < 0)
+		error(EXIT_FAILURE, errno, "asprintf");
 
+	free(pass);
 	return buf;
 }
 
+static void *
+xmalloc(size_t size)
+{
+	void   *r = malloc(size);
+
+	if (!r)
+		error(EXIT_FAILURE, errno, "malloc");
+	return r;
+}
+
 static void
-hexify(char *hash, size_t hashlen) {
-	int i;
-	char *h = xmalloc(hashlen);
-	memcpy(h, hash, hashlen);
+hexify(char *hash, size_t hashlen)
+{
+	int     i;
+	char   *h = xmalloc(hashlen);
 
-	for (i=0; i < hashlen; i++)
-		snprintf((hash + 2*i), 3, "%.2x", (unsigned char) h[i]);
+	memcpy(h, hash, hashlen);
+	for (i = 0; i < hashlen; i++)
+		snprintf((hash + 2 * i), 3, "%.2x", (unsigned char) h[i]);
 	strcat(hash, "\n");
 
-	memset(h, 0, hashlen); /* paranoia */
+	memset(h, 0, hashlen);	/* paranoia */
 	free(h);
 }
 
+static int
+write_loop(int fd, const char *buffer, size_t count)
+{
+	ssize_t offset = 0;
+
+	while (count > 0)
+	{
+		ssize_t block = write(fd, &buffer[offset], count);
+
+		if (block < 0)
+		{
+			if (errno == EINTR)
+				continue;
+			return block;
+		}
+		if (!block)
+			break;
+		offset += block;
+		count -= block;
+	}
+	return offset;
+}
+
 int
-main(int argc, char *argv[]) 
+main(int argc, char *argv[])
 {
-	char *pass, *passhash, *salt = NULL, *p;
-	size_t hashlen = 0;
+	char   *pass, *passhash, *salt = NULL, *p;
+	size_t  hashlen = 0;
 	phash_func_t func;
-	int hex_output = 0, c;
-
-	while ((c = getopt(argc, argv, "n:s:x")) != -1) {
-		switch (c) {
-		case 'n':
-			hashlen = strtoul(optarg, &p, 0);
-			if (*p != '\0' || *optarg == '\0') {
-				fprintf (stderr,
-					 "%s: argument to -n option must be numeric\n",
-					 argv[0]);
-				show_usage(argv[0]);
-				exit(EXIT_FAILURE);
-			}
-			break;
-                case 's':
-                        salt = optarg;
-                        break;
-		case 'x':
-			hex_output++;
-			break;
-                default:
-                        show_usage(argv[0]);
-			exit(EXIT_FAILURE);
-                }
+	int     quiet = 0, hex_output = 0, c;
+	int     rc = EXIT_SUCCESS;
+
+	progname = (argc > 0) ? basename(argv[0]) : "hashalot";
+
+	while ((c = getopt(argc, argv, "n:qs:x")) != -1)
+	{
+		switch (c)
+		{
+			case 'n':
+				hashlen = strtoul(optarg, &p, 0);
+				if (*p != '\0' || *optarg == '\0')
+				{
+					fprintf(stderr,
+						"%s: argument to -n option must be numeric\n",
+						progname);
+					show_usage();
+					exit(EXIT_FAILURE);
+				}
+				break;
+			case 'q':
+				quiet = 1;
+				break;
+			case 's':
+				salt = optarg;
+				break;
+			case 'x':
+				hex_output = 1;
+				break;
+			default:
+				return EXIT_FAILURE;
+		}
 	}
 
-	if (!(func = phash_lookup(basename(argv[0]), (hashlen ? NULL : &hashlen))))
+	if (!(func = phash_lookup(progname, (hashlen ? NULL : &hashlen))))
+	{
 		/* lookup failed, so try next argv */
-		if (!(func = phash_lookup(argv[optind], (hashlen ? NULL : &hashlen)))) {
-		/* lookup failed again */
-			fprintf (stderr,
-				 "%s: missing or unknown hash type requested\n",
-				 argv[0]);
-			show_usage(argv[0]);
-			exit(EXIT_FAILURE);
-		} 
-
-	assert (func != 0);
+		if (optind + 1 != argc)
+			show_usage();
+		func = phash_lookup(argv[optind],
+				    (hashlen ? NULL : &hashlen));
+		if (!func)
+		{
+			/* lookup failed again */
+			fprintf(stderr,
+				"%s: missing or unknown hash type requested\n",
+				progname);
+			show_usage();
+		}
+	}
 
 	/* allocate memory for the password hash:
 	 * enough for 2 hex digits per byte of the requested hash length,
 	 * plus a newline, plus a null */
-	passhash = xmalloc(2*hashlen + 2);
+	passhash = xmalloc(2 * hashlen + 2);
 
 	/* try to lock memory so it doesn't get swapped out for sure */
-	if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
-		perror("mlockall");
-		fputs("Warning: couldn't lock memory, are you root?\n", stderr);
-	}
+	if (mlockall(MCL_CURRENT | MCL_FUTURE) && !quiet)
+		error(EXIT_SUCCESS, errno, "failed to lock memory");
 
 	/* here we acquire the precious passphrase... */
-	pass = xgetpass("Enter passphrase: ");
+	if (!(pass = xgetpass("Enter passphrase: ")))
+		error(EXIT_FAILURE, errno, "getpass failed");
 	if (salt)
 		pass = salt_passphrase(pass, salt);
 	hashlen = func(passhash, hashlen, pass, strlen(pass));
-	memset (pass, 0, strlen (pass)); /* paranoia */
-	free(pass);
+	free(zeroize(pass));
 
-	if (hex_output) {
+	if (hex_output)
+	{
 		hexify(passhash, hashlen);
 		hashlen = hashlen * 2 + 1;
 	}
 
-	if (write(STDOUT_FILENO, passhash, hashlen) != hashlen)
-		perror("write");
+	if (write_loop(STDOUT_FILENO, passhash, hashlen) != hashlen)
+	{
+		error(EXIT_SUCCESS, errno, "write");
+		rc = EXIT_FAILURE;
+	}
 
-	memset (passhash, 0, hashlen); /* paranoia again */
+	memset(passhash, 0, hashlen);	/* paranoia again */
 	free(passhash);
 
-	exit(EXIT_SUCCESS);
+	return rc;
 }
-
diff --git a/sha512.c b/sha512.c
index a795228..e8f72bd 100644
--- a/sha512.c
+++ b/sha512.c
@@ -104,7 +104,7 @@ void sha256_init(sha256_context *ctx)
 #define lSig0(x)    ((S(7,(x))) ^ (S(18,(x))) ^ (R(3,(x))))
 #define lSig1(x)    ((S(17,(x))) ^ (S(19,(x))) ^ (R(10,(x))))
 
-static void sha256_transform(sha256_context *ctx, unsigned char *datap)
+static void sha256_transform(sha256_context *ctx, const unsigned char *datap)
 {
     register int    j;
     u_int32_t       a, b, c, d, e, f, g, h;
@@ -157,7 +157,7 @@ static void sha256_transform(sha256_context *ctx, unsigned char *datap)
     ctx->sha_blocks++;
 }
 
-void sha256_write(sha256_context *ctx, unsigned char *datap, int length)
+void sha256_write(sha256_context *ctx, const unsigned char *datap, int length)
 {
     while(length > 0) {
         if(!ctx->sha_bufCnt) {
@@ -221,7 +221,7 @@ void sha256_final(sha256_context *ctx)
     memset(&ctx->sha_out[32], 0, sizeof(sha256_context) - 32);
 }
 
-void sha256_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole)
+void sha256_hash_buffer(const unsigned char *ib, int ile, unsigned char *ob, int ole)
 {
     sha256_context ctx;
 
@@ -259,7 +259,7 @@ void sha512_init(sha512_context *ctx)
 #define lSig0(x)    ((S(1,(x))) ^ (S(8,(x))) ^ (R(7,(x))))
 #define lSig1(x)    ((S(19,(x))) ^ (S(61,(x))) ^ (R(6,(x))))
 
-static void sha512_transform(sha512_context *ctx, unsigned char *datap)
+static void sha512_transform(sha512_context *ctx, const unsigned char *datap)
 {
     register int    j;
     u_int64_t       a, b, c, d, e, f, g, h;
@@ -315,7 +315,7 @@ static void sha512_transform(sha512_context *ctx, unsigned char *datap)
     if(!ctx->sha_blocks) ctx->sha_blocksMSB++;
 }
 
-void sha512_write(sha512_context *ctx, unsigned char *datap, int length)
+void sha512_write(sha512_context *ctx, const unsigned char *datap, int length)
 {
     while(length > 0) {
         if(!ctx->sha_bufCnt) {
@@ -392,7 +392,7 @@ void sha512_final(sha512_context *ctx)
     memset(&ctx->sha_out[64], 0, sizeof(sha512_context) - 64);
 }
 
-void sha512_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole)
+void sha512_hash_buffer(const unsigned char *ib, int ile, unsigned char *ob, int ole)
 {
     sha512_context ctx;
 
@@ -416,7 +416,7 @@ void sha384_init(sha512_context *ctx)
     ctx->sha_bufCnt = 0;
 }
 
-void sha384_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole)
+void sha384_hash_buffer(const unsigned char *ib, int ile, unsigned char *ob, int ole)
 {
     sha512_context ctx;
 
diff --git a/sha512.h b/sha512.h
index 817dc26..5f5e4fc 100644
--- a/sha512.h
+++ b/sha512.h
@@ -28,18 +28,18 @@ typedef struct {
 
 /* 256 bit hash, provides 128 bits of security against collision attacks */
 extern void sha256_init(sha256_context *);
-extern void sha256_write(sha256_context *, unsigned char *, int);
+extern void sha256_write(sha256_context *, const unsigned char *, int);
 extern void sha256_final(sha256_context *);
-extern void sha256_hash_buffer(unsigned char *, int, unsigned char *, int);
+extern void sha256_hash_buffer(const unsigned char *, int, unsigned char *, int);
 
 /* 512 bit hash, provides 256 bits of security against collision attacks */
 extern void sha512_init(sha512_context *);
-extern void sha512_write(sha512_context *, unsigned char *, int);
+extern void sha512_write(sha512_context *, const unsigned char *, int);
 extern void sha512_final(sha512_context *);
-extern void sha512_hash_buffer(unsigned char *, int, unsigned char *, int);
+extern void sha512_hash_buffer(const unsigned char *, int, unsigned char *, int);
 
 /* 384 bit hash, provides 192 bits of security against collision attacks */
 extern void sha384_init(sha512_context *);
 /* no sha384_write(), use sha512_write() */
 /* no sha384_final(), use sha512_final(), result in ctx->sha_out[0...47]  */
-extern void sha384_hash_buffer(unsigned char *, int, unsigned char *, int);
+extern void sha384_hash_buffer(const unsigned char *, int, unsigned char *, int);
diff --git a/unlocked-io.h b/unlocked-io.h
new file mode 100644
index 0000000..36a7a48
--- /dev/null
+++ b/unlocked-io.h
@@ -0,0 +1,132 @@
+/* Prefer faster, non-thread-safe stdio functions if available.
+
+   Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Written by Jim Meyering.  */
+
+#ifndef UNLOCKED_IO_H
+# define UNLOCKED_IO_H 1
+
+# ifndef USE_UNLOCKED_IO
+#  define USE_UNLOCKED_IO 1
+# endif
+
+# if USE_UNLOCKED_IO
+
+/* These are wrappers for functions/macros from the GNU C library, and
+   from other C libraries supporting POSIX's optional thread-safe functions.
+
+   The standard I/O functions are thread-safe.  These *_unlocked ones are
+   more efficient but not thread-safe.  That they're not thread-safe is
+   fine since all of the applications in this package are single threaded.
+
+   Also, some code that is shared with the GNU C library may invoke
+   the *_unlocked functions directly.  On hosts that lack those
+   functions, invoke the non-thread-safe versions instead.  */
+
+#  include <stdio.h>
+
+#  if HAVE_DECL_CLEARERR_UNLOCKED
+#   undef clearerr
+#   define clearerr(x) clearerr_unlocked (x)
+#  else
+#   define clearerr_unlocked(x) clearerr (x)
+#  endif
+#  if HAVE_DECL_FEOF_UNLOCKED
+#   undef feof
+#   define feof(x) feof_unlocked (x)
+#  else
+#   define feof_unlocked(x) feof (x)
+#  endif
+#  if HAVE_DECL_FERROR_UNLOCKED
+#   undef ferror
+#   define ferror(x) ferror_unlocked (x)
+#  else
+#   define ferror_unlocked(x) ferror (x)
+#  endif
+#  if HAVE_DECL_FFLUSH_UNLOCKED
+#   undef fflush
+#   define fflush(x) fflush_unlocked (x)
+#  else
+#   define fflush_unlocked(x) fflush (x)
+#  endif
+#  if HAVE_DECL_FGETS_UNLOCKED
+#   undef fgets
+#   define fgets(x,y,z) fgets_unlocked (x,y,z)
+#  else
+#   define fgets_unlocked(x,y,z) fgets (x,y,z)
+#  endif
+#  if HAVE_DECL_FPUTC_UNLOCKED
+#   undef fputc
+#   define fputc(x,y) fputc_unlocked (x,y)
+#  else
+#   define fputc_unlocked(x,y) fputc (x,y)
+#  endif
+#  if HAVE_DECL_FPUTS_UNLOCKED
+#   undef fputs
+#   define fputs(x,y) fputs_unlocked (x,y)
+#  else
+#   define fputs_unlocked(x,y) fputs (x,y)
+#  endif
+#  if HAVE_DECL_FREAD_UNLOCKED
+#   undef fread
+#   define fread(w,x,y,z) fread_unlocked (w,x,y,z)
+#  else
+#   define fread_unlocked(w,x,y,z) fread (w,x,y,z)
+#  endif
+#  if HAVE_DECL_FWRITE_UNLOCKED
+#   undef fwrite
+#   define fwrite(w,x,y,z) fwrite_unlocked (w,x,y,z)
+#  else
+#   define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z)
+#  endif
+#  if HAVE_DECL_GETC_UNLOCKED
+#   undef getc
+#   define getc(x) getc_unlocked (x)
+#  else
+#   define getc_unlocked(x) getc (x)
+#  endif
+#  if HAVE_DECL_GETCHAR_UNLOCKED
+#   undef getchar
+#   define getchar() getchar_unlocked ()
+#  else
+#   define getchar_unlocked() getchar ()
+#  endif
+#  if HAVE_DECL_PUTC_UNLOCKED
+#   undef putc
+#   define putc(x,y) putc_unlocked (x,y)
+#  else
+#   define putc_unlocked(x,y) putc (x,y)
+#  endif
+#  if HAVE_DECL_PUTCHAR_UNLOCKED
+#   undef putchar
+#   define putchar(x) putchar_unlocked (x)
+#  else
+#   define putchar_unlocked(x) putchar (x)
+#  endif
+
+#  undef flockfile
+#  define flockfile(x) ((void) 0)
+
+#  undef ftrylockfile
+#  define ftrylockfile(x) 0
+
+#  undef funlockfile
+#  define funlockfile(x) ((void) 0)
+
+# endif /* USE_UNLOCKED_IO */
+#endif /* UNLOCKED_IO_H */
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin