diff --git a/include/Makefile b/include/Makefile index 98fef4877189..8a4451765601 100644 --- a/include/Makefile +++ b/include/Makefile @@ -16,7 +16,7 @@ FILES= a.out.h ar.h assert.h bitstring.h complex.h ctype.h db.h \ libgen.h limits.h link.h locale.h malloc.h memory.h monetary.h mpool.h \ ndbm.h netconfig.h netdb.h nl_types.h nlist.h nsswitch.h objformat.h \ paths.h pthread.h pthread_np.h pwd.h \ - ranlib.h regex.h regexp.h resolv.h rune.h runetype.h \ + ranlib.h readpassphrase.h regex.h regexp.h resolv.h rune.h runetype.h \ search.h setjmp.h sgtty.h \ signal.h stab.h stdbool.h stddef.h stdio.h stdlib.h strhash.h \ string.h stringlist.h strings.h sysexits.h tar.h time.h timers.h \ diff --git a/include/readpassphrase.h b/include/readpassphrase.h new file mode 100644 index 000000000000..ba656e39e2be --- /dev/null +++ b/include/readpassphrase.h @@ -0,0 +1,47 @@ +/* $OpenBSD: readpassphrase.h,v 1.1 2000/11/21 00:48:38 millert Exp $ */ +/* $FreeBSD$ */ + +/* + * Copyright (c) 2000 Todd C. Miller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + */ + +#ifndef _READPASSPHRASE_H_ +#define _READPASSPHRASE_H_ + +#define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */ +#define RPP_ECHO_ON 0x01 /* Leave echo on. */ +#define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */ +#define RPP_FORCELOWER 0x04 /* Force input to lower case. */ +#define RPP_FORCEUPPER 0x08 /* Force input to upper case. */ +#define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */ + +#include + +__BEGIN_DECLS +char * readpassphrase __P((const char *, char *, size_t, int)); +__END_DECLS + +#endif /* !_READPASSPHRASE_H_ */ diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 2f6ab7d59007..3cc848dbbabc 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -13,7 +13,7 @@ SRCS+= __xuname.c _pthread_stubs.c _rand48.c _spinlock_stub.c _thread_init.c \ getcap.c getcwd.c getdomainname.c getgrent.c getgrouplist.c \ gethostname.c getloadavg.c getlogin.c getmntinfo.c getnetgrent.c \ getobjformat.c getosreldate.c getpagesize.c \ - getpass.c getpeereid.c getprogname.c getpwent.c getttyent.c \ + getpeereid.c getprogname.c getpwent.c getttyent.c \ getusershell.c getvfsbyname.c getvfsent.c glob.c \ initgroups.c isatty.c jrand48.c lcong48.c \ lockf.c lrand48.c mrand48.c msgctl.c \ @@ -21,6 +21,7 @@ SRCS+= __xuname.c _pthread_stubs.c _rand48.c _spinlock_stub.c _thread_init.c \ nlist.c nrand48.c ntp_gettime.c opendir.c \ pause.c popen.c psignal.c pw_scan.c pwcache.c raise.c readdir.c rewinddir.c \ posixshm.c \ + readpassphrase.c \ scandir.c seed48.c seekdir.c semconfig.c semctl.c semget.c semop.c \ setdomainname.c sethostname.c setjmperr.c setmode.c setprogname.c \ setproctitle.c \ @@ -51,7 +52,7 @@ MAN+= alarm.3 arc4random.3 clock.3 \ glob.3 initgroups.3 isinf.3 \ ldexp.3 lockf.3 modf.3 msgctl.3 msgget.3 msgrcv.3 msgsnd.3 \ nice.3 nlist.3 pause.3 popen.3 psignal.3 pwcache.3 \ - raise.3 rand48.3 rfork_thread.3 \ + raise.3 rand48.3 readpassphrase.3 rfork_thread.3 \ scandir.3 setjmp.3 setmode.3 setproctitle.3 shm_open.3 \ siginterrupt.3 signal.3 sigsetops.3 sleep.3 stringlist.3 \ strtofflags.3 sysconf.3 sysctl.3 syslog.3 tcgetpgrp.3 \ diff --git a/lib/libc/gen/getpass.3 b/lib/libc/gen/getpass.3 index aa921d76b471..ea80814db3bb 100644 --- a/lib/libc/gen/getpass.3 +++ b/lib/libc/gen/getpass.3 @@ -73,6 +73,7 @@ function returns a pointer to the null terminated password. .El .Sh SEE ALSO .Xr crypt 3 +.Xr readpassphrase 3 .Sh HISTORY A .Fn getpass diff --git a/lib/libc/gen/getpass.c b/lib/libc/gen/getpass.c deleted file mode 100644 index f44cf17d2345..000000000000 --- a/lib/libc/gen/getpass.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. 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. - * - * $FreeBSD$ - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)getpass.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ - -#include "namespace.h" -#include -#include - -#include -#include -#include -#include -#include "un-namespace.h" - -static struct termios oterm, term; -static FILE *fp; - -char * -getpass(prompt) - const char *prompt; -{ - register int ch; - register char *p; - FILE *outfp; - static char buf[_PASSWORD_LEN + 1]; - sigset_t oset, nset; - - /* - * 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; - } - - /* - * note - blocking signals isn't necessarily the - * right thing, but we leave it for now. - */ - sigemptyset(&nset); - sigaddset(&nset, SIGINT); - sigaddset(&nset, SIGTSTP); - (void)_sigprocmask(SIG_BLOCK, &nset, &oset); - - (void)tcgetattr(fileno(fp), &oterm); - term = oterm; - term.c_lflag &= ~ECHO; - (void)tcsetattr(fileno(fp), TCSAFLUSH|TCSASOFT, &term); - (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); - (void)tcsetattr(fileno(fp), TCSAFLUSH|TCSASOFT, &oterm); - - (void)_sigprocmask(SIG_SETMASK, &oset, NULL); - - if (fp != stdin) - (void)fclose(fp); - return(buf); -} diff --git a/lib/libc/gen/readpassphrase.3 b/lib/libc/gen/readpassphrase.3 new file mode 100644 index 000000000000..2fe97bf1b8d7 --- /dev/null +++ b/lib/libc/gen/readpassphrase.3 @@ -0,0 +1,118 @@ +.\" $OpenBSD: readpassphrase.3,v 1.3 2001/08/06 10:42:25 mpech Exp $ +.\" $FreeBSD$ +.\" +.\" Copyright (c) 2000 Todd C. Miller +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 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. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. +.\" +.Dd November 20, 2000 +.Dt READPASSPHRASE 3 +.Os +.Sh NAME +.Nm readpassphrase +.Nd get a passphrase from the user +.Sh SYNOPSIS +.Fd #include +.Ft char * +.Fn readpassphrase "const char *prompt" "char *buf" "size_t bufsiz" "int flags" +.Sh DESCRIPTION +The +.Fn readpassphrase +function displays a prompt to, and reads in a passphrase from, +.Pa /dev/tty . +If this file is inaccessible +and the +.Dv RPP_REQUIRE_TTY +flag is not set, +.Fn readpassphrase +displays the prompt on the standard error output and reads from the standard +input. +In this case it is generally not possible to turn off echo. +.Pp +Up to +.Fa bufsiz +- 1 characters (one is for the NUL) are read into the provided buffer +.Fa buf . +Any additional +characters and the terminating newline (or return) character are discarded. +.Pp +.Fn readpassphrase +takes the following optional +.Fa flags : +.Pp +.Bd -literal -offset indent -compact +RPP_ECHO_OFF turn off echo (default behavior) +RPP_ECHO_ON leave echo on +RPP_REQUIRE_TTY fail if there is no tty +RPP_FORCELOWER force input to lower case +RPP_FORCEUPPER force input to upper case +RPP_SEVENBIT strip the high bit from input +.Ed +.Pp +The calling process should zero the passphrase as soon as possible to +avoid leaving the cleartext passphrase visible in the process's address +space. +.Sh RETURN VALUES +On success, +.Fn readpassphrase +returns a pointer to the null-terminated passphrase. +If the +.Dv RPP_REQUIRE_TTY +flag is set and +.Pa /dev/tty +is inaccessible, +.Fn readpassphrase +returns a null pointer. +.Sh EXAMPLES +The following code fragment will read a passphrase from +.Pa /dev/tty +into the buffer +.Fa passbuf. +.Bd -literal -offset indent +char passbuf[1024]; + +\&... + +if (readpassphrase("Response: ", passbuf, sizeof(passbuf), + RPP_REQUIRE_TTY) == NULL) + errx(1, "unable to read passphrase"); + +if (compare(transform(passbuf), epass) != 0) + errx(1, "bad passphrase"); + +\&... + +memset(passbuf, 0, sizeof(passbuf)); +.Ed +.Sh FILES +.Bl -tag -width /dev/tty -compact +.It Pa /dev/tty +.El +.Sh SEE ALSO +.Xr getpass 3 +.Sh HISTORY +The +.Fn readpassphrase +function first appeared in +.Ox 2.9 . diff --git a/lib/libc/gen/readpassphrase.c b/lib/libc/gen/readpassphrase.c new file mode 100644 index 000000000000..cd68eef22d2d --- /dev/null +++ b/lib/libc/gen/readpassphrase.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2000 Todd C. Miller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$OpenBSD: readpassphrase.c,v 1.7 2001/08/07 19:34:11 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char * +readpassphrase(prompt, buf, bufsiz, flags) + const char *prompt; + char *buf; + size_t bufsiz; + int flags; +{ + struct termios term, oterm; + char ch, *p, *end; + int input, output; + sigset_t oset, nset; + + /* I suppose we could alloc on demand in this case (XXX). */ + if (bufsiz == 0) { + errno = EINVAL; + return(NULL); + } + + /* + * Read and write to /dev/tty if available. If not, read from + * stdin and write to stderr unless a tty is required. + */ + if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) { + if (flags & RPP_REQUIRE_TTY) { + errno = ENOTTY; + return(NULL); + } + input = STDIN_FILENO; + output = STDERR_FILENO; + } + + /* + * We block SIGINT and SIGTSTP so the terminal is not left + * in an inconsistent state (ie: no echo). It would probably + * be better to simply catch these though. + */ + sigemptyset(&nset); + sigaddset(&nset, SIGINT); + sigaddset(&nset, SIGTSTP); + (void)sigprocmask(SIG_BLOCK, &nset, &oset); + + /* Turn off echo if possible. */ + if (tcgetattr(input, &oterm) == 0) { + memcpy(&term, &oterm, sizeof(term)); + if (!(flags & RPP_ECHO_ON) && (term.c_lflag & ECHO)) + term.c_lflag &= ~ECHO; + if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) + term.c_cc[VSTATUS] = _POSIX_VDISABLE; + (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term); + } else { + memset(&term, 0, sizeof(term)); + memset(&oterm, 0, sizeof(oterm)); + } + + (void)write(output, prompt, strlen(prompt)); + end = buf + bufsiz - 1; + for (p = buf; read(input, &ch, 1) == 1 && ch != '\n' && ch != '\r';) { + if (p < end) { + if ((flags & RPP_SEVENBIT)) + ch &= 0x7f; + if (isalpha(ch)) { + if ((flags & RPP_FORCELOWER)) + ch = tolower(ch); + if ((flags & RPP_FORCEUPPER)) + ch = toupper(ch); + } + *p++ = ch; + } + } + *p = '\0'; + if (!(term.c_lflag & ECHO)) + (void)write(output, "\n", 1); + + /* Restore old terminal settings and signal mask. */ + if (memcmp(&term, &oterm, sizeof(term)) != 0) + (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm); + (void)sigprocmask(SIG_SETMASK, &oset, NULL); + if (input != STDIN_FILENO) + (void)close(input); + return(buf); +} + +char * +getpass(prompt) + const char *prompt; +{ + static char buf[_PASSWORD_LEN + 1]; + + return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF)); +}