Skip to content

Commit

Permalink
add a simple command-line tool version of this function
Browse files Browse the repository at this point in the history
This can be useful when scripting around other tools, or with
SUDO_ASKPASS / SSH_ASKPASS etc.  See the manual page for examples.
  • Loading branch information
jschauma committed Jul 17, 2023
1 parent d383b16 commit 1ffeb31
Show file tree
Hide file tree
Showing 6 changed files with 398 additions and 31 deletions.
32 changes: 32 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
NAME= getpass
PREFIX?= /usr/local

all: ${NAME}

${NAME}: ./cmd/${NAME}.go
go build cmd/${NAME}.go

help:
@echo "The following targets are available:"
@echo "all build the executable"
@echo "clean remove build files"
@echo "doc format man page into .txt"
@echo "install install ${NAME} into ${PREFIX}"
@echo "uninstall uninstall ${NAME} from ${PREFIX}"

install:
mkdir -p ${PREFIX}/bin ${PREFIX}/share/man/man1
install -c -m 0555 ./${NAME} ${PREFIX}/bin/${NAME}
install -c -m 0444 doc/${NAME}.1 ${PREFIX}/share/man/man1/${NAME}.1

uninstall:
rm -f ${PREFIX}/bin/${NAME}
rm -f ${PREFIX}/share/man/man1/${NAME}.1

clean:
rm -f ${NAME}

doc: doc/${NAME}.1.txt

doc/${NAME}.1.txt: doc/${NAME}.1
mandoc -c -O width=80 $? | col -b >$@
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@
Reference](https://pkg.go.dev/badge/github.com/jschauma/getpass.svg)](https://pkg.go.dev/github.com/jschauma/getpass)

The `getpass` module provides a simple way to retrieve a password from
the user by specifying a number of different password sources:
the user by specifying a number of different password sources.

A simple command-line tool using this function to
provide a generic helper command is also provided in
this directory. Please see the [manual
page](https://github.com/jschauma/getpass/blob/main/doc/getpass.1.txt) for
details.

---

```
func Getpass(passfrom string) (pass string, err error)
Expand Down
65 changes: 65 additions & 0 deletions cmd/getpass.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Originally written by Jan Schaumann
// <[email protected]> in July 2023.

package main

import (
"flag"
"fmt"
"os"

"github.com/jschauma/getpass"
)

const PROGNAME = "getpass"
const VERSION = "0.2.2"

func usage() {
help := `Usage: getpass [-Vh] [passin]
-V print version numbe and exit
-h print this help and exit
passin may be one of:
cmd:command, env:var, fd:num, file:pathname, keychain:name,
lpass:name, op:name, pass:password, stdin, tty[:prompt]
`
fmt.Printf(help)
}

func main() {

printVersion := false
flag.BoolVar(&printVersion, "V", false, "print help")

printHelp := false
flag.BoolVar(&printHelp, "h", false, "print help")

flag.Parse()
if printHelp {
usage()
os.Exit(0)
}

if printVersion {
fmt.Printf("%s version %s\n", PROGNAME, VERSION)
os.Exit(0)
}

if len(os.Args) > 2 {
fmt.Fprintf(os.Stderr, "Usage: %s [-Vh] [passin]\n", PROGNAME)
os.Exit(1)
}

pass := "tty"
if len(os.Args) == 2 {
pass = os.Args[1]
}

p, err := getpass.Getpass(pass)
if err != nil {
fmt.Fprintf(os.Stderr, "%s: Unable to getpass using '%s: %s\n",
PROGNAME, pass, err)
os.Exit(1)
}
fmt.Printf("%s\n", p)
}
155 changes: 155 additions & 0 deletions doc/getpass.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
.\" Copyright (c) 2023, Jan Schaumann
.\" Author: Jan Schaumann <[email protected]>
.\" https://github.com/jschauma/getpass
.\"
.Dd July 17, 2023
.Dt GETPASS 1
.Os
.Sh NAME
.Nm getpass
.Nd get a password from the user
.Sh SYNOPSIS
.Nm
.Op Fl Vh
.Op Ar passin
.Sh DESCRIPTION
The
.Nm
tool provides a simple way to retrieve a password from
the user by specifying a number of different password
sources.
The password is then printed to stdout.
.Sh OPTIONS
The following options are supported by
.Nm :
.Bl -tag -width _p_passin_
.It Fl V
Print version number and exit.
.It Fl h
Print a short help message and exit.
.Sh DETAILS
Writing shell scripts that interact with different
commands that require a password is often
cumbersome:
Many tools require a password to run, but may only
implement limited or inconsistent ways to provide the
password.
.Pp
The
.Nm
tool can be used to retrieve a password from the user
in several ways, carrying different methods carry
different risks, and you should carefully evaluate
what may be the best option for you.
.Pp
The supported options for the
.Ar passin
argument are:
.Bl -tag -width pass_password_
.It \fBenv:var\fR
Obtain the password from the environment variable \fBvar\fR.
Since the environment of other processes may be visible via e.g.
.Xr ps 1 ,
this option should be used with caution.
.It \fBfile:pathname\fR
The first line of \fBpathname\fR is the password.
\fBpathname\fR need not refer to a regular file: it could for example
refer to a device or named pipe.
Note that standard Unix file access controls should be used to protect
this file.
.It \fBfd:num\fR
Read the password from the given file descriptor.
The file descriptor must have been opened before
invoking
.Nm
and the shell must allow subprocesses to inherit open
file descriptors ('set -o posix' for e.g., bourne
shells).
.Pp
Note that on many platforms this is functionally
equivalent to 'file:/proc/$$/fd/num'.
.It \fBkeychain:name\fR
.Nm
will use the
.Xr security 1
utility to retrieve the password from the macOS keychain.
.It \fBlpass:name\fR
.Nm
will use the LastPass command-line client
.Xr lpass 1
to retrieve the named password.
You should previously have run 'lpass login' for this
to work.
.It \fBop:name\fR
.Nm
will use the 1Password command-line client
.Xr op 1
to retrieve the named password.
.It \fBpass:password\fR
The actual password is \fBpassword\fR.
Since the password is visible to utilities such as
.Xr ps 1
this form should only be used where security is not important.
.It \fBstdin\fR
Read the password from stdin. This is actually a
convenience alias for 'fd:0'; on many platforms the same
effect can be achieved via 'file:/dev/stdin'.
.It \fBtty[:prompt]\fR
This is the default: Getpass will prompt the user on
the controlling tty using the provided prompt.
If no prompt is provided, then Getpass will use
"Password: ".
.El
.Sh EXAMPLES
The primary use case for
.Nm
is to pass a password to another process.
For example, assume that the command
.Ar cmd
only accepts a password on the command-line, but you
want to retrieve it from the macOS keychain entry
"mypass":
.Bd -literal -offset indent
$ cmd -p $(getpass keychain:mypass)
.Ed
.Pp
Note: since the subshell is evaluated prior to the
execution of
.Ar cmd
the password is now present in the process table.
.Pp
To allow your
.Xr sudo 8
password to be fetched from your 1Password vault,
create a
.Ev SSH_ASKPASS
wrapper using
.Nm :
.Bd -literal -offset indent
$ cat >${HOME}/bin/askpass <<EOF
#! /bin/sh
getpass op:sudo
EOF
$ chmod a+rx ${HOME}/bin/askpass
$ export SSH_ASKPASS=${HOME}/bin/askpass
$ sudo -A command
.Ed
.Pp
To non-interactively provide a password from your
LastPass vault to a tool that only accepts a password
on stdin:
.Bd -literal -offset indent
$ getpass lpass:extra-secret | cmd --password-stdin
.Ed
.Sh SEE ALSO
.Xr lpass 1 ,
.Xr security 1 ,
.Xr sudo 8
.Pp
https://www.netmeister.org/blog/passing-passwords.html
.Sh HISTORY
.Nm
was originally written by
.An Jan Schaumann
.Aq [email protected]
in July 2023.
107 changes: 107 additions & 0 deletions doc/getpass.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
GETPASS(1) General Commands Manual GETPASS(1)

NAME
getpass get a password from the user

SYNOPSIS
getpass [-Vh] [passin]

DESCRIPTION
The getpass tool provides a simple way to retrieve a password from the user
by specifying a number of different password sources. The password is then
printed to stdout.

OPTIONS
The following options are supported by getpass:

-V Print version number and exit.

-h Print a short help message and exit.

DETAILS
Writing shell scripts that interact with different commands that require a
password is often cumbersome: Many tools require a password to run, but may
only implement limited or inconsistent ways to provide the password.

The getpass tool can be used to retrieve a password from the user in
several ways, carrying different methods carry different risks, and you
should carefully evaluate what may be the best option for you.

The supported options for the passin argument are:

env:var Obtain the password from the environment variable var.
Since the environment of other processes may be visible via
e.g. ps(1), this option should be used with caution.

file:pathname The first line of pathname is the password. pathname need
not refer to a regular file: it could for example refer to
a device or named pipe. Note that standard Unix file
access controls should be used to protect this file.

fd:num Read the password from the given file descriptor. The file
descriptor must have been opened before invoking getpass
and the shell must allow subprocesses to inherit open file
descriptors ('set -o posix' for e.g., bourne shells).

Note that on many platforms this is functionally equivalent
to 'file:/proc/$$/fd/num'.

keychain:name getpass will use the security(1) utility to retrieve the
password from the macOS keychain.

lpass:name getpass will use the LastPass command-line client lpass(1)
to retrieve the named password. You should previously have
run 'lpass login' for this to work.

op:name getpass will use the 1Password command-line client op(1) to
retrieve the named password.

pass:password The actual password is password. Since the password is
visible to utilities such as ps(1) this form should only be
used where security is not important.

stdin Read the password from stdin. This is actually a
convenience alias for 'fd:0'; on many platforms the same
effect can be achieved via 'file:/dev/stdin'.

tty[:prompt] This is the default: Getpass will prompt the user on the
controlling tty using the provided prompt. If no prompt is
provided, then Getpass will use "Password: ".

EXAMPLES
The primary use case for getpass is to pass a password to another process.
For example, assume that the command cmd only accepts a password on the
command-line, but you want to retrieve it from the macOS keychain entry
"mypass":

$ cmd -p $(getpass keychain:mypass)

Note: since the subshell is evaluated prior to the execution of cmd the
password is now present in the process table.

To allow your sudo(8) password to be fetched from your 1Password vault,
create a SSH_ASKPASS wrapper using getpass:

$ cat >${HOME}/bin/askpass <<EOF
#! /bin/sh
getpass op:sudo
EOF
$ chmod a+rx ${HOME}/bin/askpass
$ export SSH_ASKPASS=${HOME}/bin/askpass
$ sudo -A command

To non-interactively provide a password from your LastPass vault to a tool
that only accepts a password on stdin:

$ getpass lpass:extra-secret | cmd --password-stdin

SEE ALSO
lpass(1), security(1), sudo(8)

https://www.netmeister.org/blog/passing-passwords.html

HISTORY
getpass was originally written by Jan Schaumann [email protected]
in July 2023.

NetBSD 9.3 July 17, 2023 NetBSD 9.3
Loading

0 comments on commit 1ffeb31

Please sign in to comment.