diff options
| author | christos <christos@NetBSD.org> | 2012-04-12 19:36:19 +0000 |
|---|---|---|
| committer | christos <christos@NetBSD.org> | 2012-04-12 19:36:19 +0000 |
| commit | 652c40994fb4f2f4df0bbba95e9e9e45bbf9ee5c (patch) | |
| tree | 05ae8f645f26701a76bee8652258f243ab6e631a | |
| parent | 0d661d96a27ae4502145a12838c5a6fae0b004ca (diff) | |
Add a new getpass implementation that does not mess with signals, and
include getpass_r
| -rw-r--r-- | lib/libc/gen/Makefile.inc | 3 | ||||
| -rw-r--r-- | lib/libc/gen/getpass.3 | 39 | ||||
| -rw-r--r-- | lib/libc/gen/getpass.c | 263 | ||||
| -rw-r--r-- | lib/libc/include/namespace.h | 3 |
4 files changed, 233 insertions, 75 deletions
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index ef7c0ee6cb2..fc1cff47368 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -1,4 +1,4 @@ -# $NetBSD: Makefile.inc,v 1.182 2012/02/11 23:31:24 martin Exp $ +# $NetBSD: Makefile.inc,v 1.183 2012/04/12 19:36:19 christos Exp $ # from: @(#)Makefile.inc 8.6 (Berkeley) 5/4/95 # gen sources @@ -117,6 +117,7 @@ MLINKS+=cgetcap.3 cgetclose.3 cgetcap.3 cgetent.3 \ cgetcap.3 cgetnum.3 cgetcap.3 cgetset.3 cgetcap.3 cgetstr.3 \ cgetcap.3 cgetustr.3 MLINKS+=getcwd.3 getwd.3 +MLINKS+=getpass.3 getpass_r.3 MLINKS+=getdiskbyname.3 setdisktab.3 MLINKS+=getdomainname.3 setdomainname.3 MLINKS+=getfsent.3 endfsent.3 getfsent.3 getfsfile.3 getfsent.3 getfsspec.3 \ diff --git a/lib/libc/gen/getpass.3 b/lib/libc/gen/getpass.3 index 64220f0a95c..2b337a55275 100644 --- a/lib/libc/gen/getpass.3 +++ b/lib/libc/gen/getpass.3 @@ -1,4 +1,4 @@ -.\" $NetBSD: getpass.3,v 1.13 2010/05/06 11:09:39 jruoho Exp $ +.\" $NetBSD: getpass.3,v 1.14 2012/04/12 19:36:19 christos Exp $ .\" .\" Copyright (c) 1989, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" @(#)getpass.3 8.1 (Berkeley) 6/4/93 .\" -.Dd May 6, 2010 +.Dd April 12, 2012 .Dt GETPASS 3 .Os .Sh NAME @@ -38,10 +38,11 @@ .Sh LIBRARY .Lb libc .Sh SYNOPSIS -.In pwd.h .In unistd.h .Ft char * .Fn getpass "const char *prompt" +.Ft char * +.Fn getpass_r "const char *prompt" "char *buf" "size_t buflen" .Sh DESCRIPTION The .Fn getpass @@ -52,16 +53,34 @@ If this file is not accessible, displays the prompt on the standard error output and reads from the standard input. .Pp -The password may be up to _PASSWORD_LEN (currently 128) +The password may be up to +.Xr sysconf 3 +.Dv _SC_PASS_MAX characters in length. Any additional characters and the terminating newline character are discarded. .Pp .Fn getpass turns off character echoing while reading the password. +.Pp +.Fn getpass_r +is similar to +.Fn getpass +only it puts its result in +.Fa buf +for up to +.Fa buflen +characters. .Sh RETURN VALUES +The .Fn getpass -returns a pointer to the null terminated password. +function returns a pointer to the NUL terminated password, or an empty +string on error. +The +.Fn getpass_r +function returns a pointer to the NUL terminated password, or +.Dv NULL +on error. .Sh FILES .Bl -tag -width /dev/tty -compact .It Pa /dev/tty @@ -82,6 +101,10 @@ A .Fn getpass function appeared in .At v7 . +The +.Fn getpass_r +function appeared in +.Nx 7.0 . .Sh BUGS The .Fn getpass @@ -94,3 +117,9 @@ will modify the same object. The calling process should zero the password as soon as possible to avoid leaving the cleartext password visible in the process's address space. +.Pp +Historically +.Nm +accepted and returned a password if it could not modify the terminal +settings to turn echo off (or if the input was not a terminal). +In this implementation, only terminal input is accepted. diff --git a/lib/libc/gen/getpass.c b/lib/libc/gen/getpass.c index ee4a8961b78..2cd6a918b38 100644 --- a/lib/libc/gen/getpass.c +++ b/lib/libc/gen/getpass.c @@ -1,8 +1,11 @@ -/* $NetBSD: getpass.c,v 1.16 2008/01/01 21:22:55 christos Exp $ */ +/* $NetBSD: getpass.c,v 1.17 2012/04/12 19:36:19 christos Exp $ */ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. +/*- + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,96 +15,220 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ - #include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -#if 0 -static char sccsid[] = "@(#)getpass.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: getpass.c,v 1.16 2008/01/01 21:22:55 christos Exp $"); -#endif +__RCSID("$NetBSD: getpass.c,v 1.17 2012/04/12 19:36:19 christos Exp $"); #endif /* LIBC_SCCS and not lint */ #include "namespace.h" #include <assert.h> -#include <paths.h> -#include <pwd.h> -#include <signal.h> +#ifdef TEST #include <stdio.h> +#endif +#include <errno.h> +#include <string.h> +#include <paths.h> +#include <stdbool.h> +#include <stdlib.h> #include <termios.h> #include <unistd.h> +#include <fcntl.h> #ifdef __weak_alias +__weak_alias(getpass_r,_getpass_r) __weak_alias(getpass,_getpass) #endif +/* + * Notes: + * - There is no getpass_r in POSIX + * - Historically EOF is documented to be treated as EOL, we provide a + * tunable for that DONT_TREAT_EOF_AS_EOL to disable this. + * - Historically getpass ate extra characters silently, we provide + * a tunable for that DONT_DISCARD_SILENTLY to disable this. + * - Historically getpass "worked" by echoing characters when turning + * off echo failed, we provide a tunable DONT_WORK_AND_ECHO to + * disable this. + * - Some implementations say that on interrupt the program shall + * receive an interrupt signal before the function returns. This + * does not sound useful, but it could be easy to implement using + * raise(3). + */ char * -getpass(prompt) - const char *prompt; +getpass_r(const char *prompt, char *ret, size_t len) { - struct termios term; - int ch; - char *p; - FILE *fp, *outfp; - int echo; - static char buf[_PASSWORD_LEN + 1]; - sigset_t oset, nset; + struct termios gt; + char c; + int infd, outfd; + bool lnext, havetty; _DIAGASSERT(prompt != NULL); /* - * note - blocking signals isn't necessarily the - * right thing, but we leave it for now. + * Try to use /dev/tty if possible; otherwise read from stdin and + * write to stderr. */ - sigemptyset(&nset); - sigaddset(&nset, SIGINT); - sigaddset(&nset, SIGTSTP); - (void)sigprocmask(SIG_BLOCK, &nset, &oset); + if ((outfd = infd = open(_PATH_TTY, O_RDWR)) == -1) { + infd = STDIN_FILENO; + outfd = STDERR_FILENO; + havetty = false; + } else + havetty = true; - /* - * read and write to /dev/tty if possible; else read from - * stdin and write to stderr. - */ - if ((outfp = fp = fopen(_PATH_TTY, "w+")) == NULL) { - outfp = stderr; - fp = stdin; + if (tcgetattr(infd, >) == -1) { + havetty = false; +#ifdef DONT_WORK_AND_ECHO + goto out; +#else + memset(>, -1, sizeof(gt)); +#endif + } else + havetty = true; + + + if (havetty) { + struct termios st = gt; + + st.c_lflag &= ~(ECHO|ECHOK|ECHOE|ECHOKE|ECHOCTL|ISIG|ICANON); + st.c_cc[VMIN] = 1; + st.c_cc[VTIME] = 0; + if (tcsetattr(infd, TCSAFLUSH|TCSASOFT, &st) == -1) + goto out; } - (void)tcgetattr(fileno(fp), &term); - if ((echo = (term.c_lflag & ECHO)) != 0) { - term.c_lflag &= ~ECHO; - (void)tcsetattr(fileno(fp), TCSAFLUSH|TCSASOFT, &term); + + if (prompt != NULL) { + size_t plen = strlen(prompt); + (void)write(outfd, prompt, plen); } - if (prompt != NULL) - (void)fputs(prompt, outfp); - rewind(outfp); /* implied flush */ - for (p = buf; (ch = getc(fp)) != EOF && ch != '\n';) - if (p < buf + _PASSWORD_LEN) - *p++ = ch; - *p = '\0'; - (void)write(fileno(outfp), "\n", 1); - if (echo) { - term.c_lflag |= ECHO; - (void)tcsetattr(fileno(fp), TCSAFLUSH|TCSASOFT, &term); + + c = '\1'; + lnext = false; + for (size_t l = 0; c != '\0'; ) { + if (read(infd, &c, 1) != 1) + goto restore; + +#define beep() write(outfd, "\a", 1) +#define C(a, b) (gt.c_cc[(a)] == _POSIX_VDISABLE ? (b) : gt.c_cc[(a)]) + + if (lnext) { + lnext = false; + goto add; + } + + /* Ignored */ + if (c == C(VREPRINT, CTRL('r')) || c == C(VSTART, CTRL('q')) || + c == C(VSTOP, CTRL('s')) || c == C(VSTATUS, CTRL('t')) || + c == C(VDISCARD, CTRL('o'))) + continue; + + /* Literal next */ + if (c == C(VLNEXT, CTRL('v'))) { + lnext = true; + continue; + } + + /* Line or word kill, treat as reset */ + if (c == C(VKILL, CTRL('u')) || c == C(VWERASE, CTRL('w'))) { + l = 0; + continue; + } + + /* Character erase */ + if (c == C(VERASE, CTRL('h'))) { + if (l == 0) + beep(); + else + l--; + continue; + } + + /* EOF or tty signal characters */ + if ( +#ifdef DONT_TREAT_EOF_AS_EOL + c == C(VEOF, CTRL('d')) || +#endif + c == C(VINTR, CTRL('c')) || + c == C(VQUIT, CTRL('\\')) || c == C(VSUSP, CTRL('z')) || + c == C(VDSUSP, CTRL('y'))) { + errno = EINTR; + goto out; + } + + /* End of line */ + if ( +#ifndef DONT_TREAT_EOF_AS_EOL + c == C(VEOF, CTRL('d')) || +#endif + c == C(VEOL, CTRL('j')) || c == C(VEOL2, CTRL('l'))) + c = '\0'; +add: + if (l >= len) { +#ifdef DONT_DISCARD_SILENTLY + beep(); + continue; +#else + if (c == '\0' && l > 0) + l--; + else + continue; +#endif + } + ret[l++] = c; } - if (fp != stdin) - (void)fclose(fp); - (void)sigprocmask(SIG_SETMASK, &oset, NULL); - return(buf); + + if (havetty) + (void)tcsetattr(infd, TCSAFLUSH|TCSASOFT, >); + return ret; +restore: + c = errno; + if (havetty) + (void)tcsetattr(infd, TCSAFLUSH|TCSASOFT, >); + errno = c; +out: + return NULL; } + +char * +getpass(const char *prompt) +{ + static char e[] = ""; + static char *buf; + static long bufsiz; + char *rv; + + if (buf == NULL) { + if ((bufsiz = sysconf(_SC_PASS_MAX)) == -1) + return e; + if ((buf = malloc((size_t)bufsiz)) == NULL) + return e; + } + + if ((rv = getpass_r(prompt, buf, (size_t)bufsiz)) == NULL) + return e; + + return rv; +} + +#ifdef TEST +int +main(int argc, char *argv[]) +{ + char buf[28]; + printf("[%s]\n", getpass_r("foo>", buf, sizeof(buf))); + return 0; +} +#endif diff --git a/lib/libc/include/namespace.h b/lib/libc/include/namespace.h index e6d5ff96c81..a0a16338610 100644 --- a/lib/libc/include/namespace.h +++ b/lib/libc/include/namespace.h @@ -1,4 +1,4 @@ -/* $NetBSD: namespace.h,v 1.151 2012/03/02 17:27:49 christos Exp $ */ +/* $NetBSD: namespace.h,v 1.152 2012/04/12 19:36:19 christos Exp $ */ /*- * Copyright (c) 1997-2004 The NetBSD Foundation, Inc. @@ -326,6 +326,7 @@ #define getopt_long _getopt_long #define getpagesize _getpagesize #define getpass _getpass +#define getpass_r _getpass_r #define getprogname _getprogname #define getprotobyname _getprotobyname #define getprotobyname_r _getprotobyname_r |
