9front - general discussion about 9front
 help / color / mirror / Atom feed
* [9front] ipso: read keys from stdin
@ 2021-09-01  1:37 ori
  2021-09-01 21:42 ` Steve Simon
  0 siblings, 1 reply; 2+ messages in thread
From: ori @ 2021-09-01  1:37 UTC (permalink / raw)
  To: 9front

It's useful to generate keys programatically and put
them into factotum.  Things like SSH keys or
certificate signing requests could stand to go directly
to secstore.

For example, the ssh example in rsa(8) could be
rewritten from:


	auth/rsagen -t 'service=ssh' >key
	auth/rsa2ssh key | ssh unix 'cat >>.ssh/authorized_keys'
	cat key >/mnt/factotum/ctl

to:

	auth/rsagen -t 'service=ssh' | \
		tee >{auth/rsa2ssh | ssh unix 'cat >>.ssh/authorized_keys}' | \
		>/mnt/factotum/ctl

or the csr for acmed could be generated as:

	auth/rsagen -t 'service=acme role=sign hash=sha256 acct=me@example.org' \
		| tee >{auth/rsa2jwk \
			>/sys/lib/tls/acmed/me@example.org.pub}
		| ipso -r -l factotum


As a result, I started hacking in support for reading
keys directly from stdin to ipso, which quickly turned
into a partial rewrite.

2 major changes, and a bit of code shuffling:

- we look for changes to files by qid instead
  of by timestamp
- we keep the files in a directory and their
  metadata elsewhere

I also took the opportunity to improve the manpage a
bit, though I didn't document the '-f', '-l', and '-e'
flags: I'm not sure where they're useful.

diff 49b5319f761e2de848d35361a507a5af8b6eb1ed uncommitted
--- a//rc/bin/ipso
+++ b//rc/bin/ipso
@@ -1,8 +1,9 @@
 #!/bin/rc
+
 # ipso - edit secstore files, reload factotum keys
 if(! ~ $service terminal &&
     ! ~ $user `{ ls -ld /mnt/factotum/ctl | awk '{print $4}' }){
-	echo >[1=2] ipso should be run only on the terminal
+	msg ipso should be run only on the terminal
 	exit terminal
 }
 
@@ -9,112 +10,93 @@
 rfork e
 path=(/bin)
 home=(/tmp)
-editor = (acme -c1)
-name = secstore
-get = secstoreget
-put = secstoreput
-edit = no
-load = no
-flush = no
+pass=/tmp/_password
+editor=(acme -c1)
+edexp=`{grep '^editor=' /mnt/plumb/rules >[2]/dev/null}
+if(~ $#edexp 1)
+	eval $edexp
+nl='
+'
 
-fn secstoreget{
-	auth/secstore -i -g $1 <_password
-}
+args='[file...]'
+flagsfile='s:usesam, a:useaescbc, f:flush, e:edit, l:load, r:readin'
+if(! eval `''{aux/getflags $*})
+	exec aux/usage
 
-fn secstoreput{
-	auth/secstore -i -p $1 <_password
+fn msg{
+	echo $* >[1=2]
 }
 
-fn aesget{
-	if(! ~ $1 /*){
-		echo >[1=2] ipso: aescbc requires fully qualified pathname
-		exit usage
+if(~ $#useaescbc 0){
+	name=secstore
+	fn get{
+		auth/secstore -i -g $1 <$pass
 	}
-	auth/aescbc -i -d < $1 > `{basename $1} <[3] _password
-}
+	fn put{
+		auth/secstore -i -p $1 <$pass
+	}
 
-fn aesput{
-	auth/aescbc -i -e > $1 < `{basename $1} <[3] _password
 }
-
-fn editedfiles{
-	if(~ $get aesget){
-		for(i in $files)
-			if(ls -tr | sed '1,/^_timestamp$/d' | grep -s '^'^`{basename $i}^'$')
-				echo $i
+if not {
+	name=aescbc
+	if(~ $#* 0){
+		msg ipso: must specify a fully qualified file name for aescbc '(-a)'
+		exit usage
 	}
-	if not
-		ls -tr | sed '1,/^_timestamp$/d'
-}
+	fn get{
+		if(! ~ $1 /*){
+			msg aescbc requires fully qualified pathname
+			exit usage
+		}
+		auth/aescbc -i -d < $1 > `{basename $1} <[3] $pass
+	}
 
-edexp=`{grep '^editor=' /mnt/plumb/rules >[2]/dev/null}
-if(~ $#edexp 1)
-	eval $edexp
-
-while(~ $1 -*){
-	switch($1){
-	case -s
-		editor = sam
-	case -a
-		name = aescbc
-		get = aesget
-		put = aesput
-	case -f
-		flush = yes
-	case -e
-		edit = yes
-	case -l
-		load = yes
-	case *
-		echo >[2=1] 'usage: ipso [-a -f -e -l] [-s] [file ...]'
-		exit usage
+	fn put{
+		auth/aescbc -i -e > $1 < `{basename $1} <[3] $pass
 	}
-	shift
 }
 
-if(~ $flush no && ~ $edit no && ~ $load no){
-	load = yes
-	edit = yes
-	flush = yes
+fn edited {
+	for(f in $files)
+		if(! ~ `{walk -eq $f} `{cat ../qids/$f})
+			echo $f
 }
 
-if(~ $flush yes && ~ $edit no && ~ $load no){
-	echo flushing old keys
-	echo delkey > /mnt/factotum/ctl
-	exit 0
-}
-
-if(~ $get aesget && ~ $#* 0){
-	echo >[2=1] ipso: must specify a fully qualified file name for aescbc '(-a)'
-	exit usage
-}
-
 rfork ne
 ramfs -p >[2] /dev/null # silence 'i/o on hungup channel' message at exit
 unmount /mnt/plumb
 bind -c /tmp /srv
-builtin cd /tmp
+mkdir /tmp/qids
+mkdir /tmp/data
+builtin cd /tmp/data
 
-if ( ~ $edit yes ) echo '
+if(~ $#flush 0 && ~ $#edit 0 && ~ $#load 0 && ~ $#readin 0){
+	load = 1
+	edit = 1
+	flush = 1
+	readin = ()
+}
+
+if ( ~ $edit 1 )
+	msg '
 	Warning: The editor will display the secret contents of
 	your '$name' files in the clear.
 '
+
 # get password and remember it
 {
 	echo rawon
 	echo -n $name password: >/dev/cons
-	read > _password
+	read > $pass
 	echo > /dev/cons
 }</dev/cons > /dev/consctl
 
 # get list of files
 if(~ $#* 0){
-	if(! auth/secstore -G . -i < _password > _listing){
-		echo 'secstore read failed - bad password?'
-		sleep 2
+	if(! files=`{auth/secstore -G . -i < $pass | sed 's/[ 	]+.*//'}){
+		msg 'secstore read failed - bad password?'
 		exit password
 	}
-	files=`{sed 's/[ 	]+.*//' _listing}
 }
 if not
 	files = $*
@@ -121,43 +103,49 @@
 
 # copy the files to local ramfs
 for(i in $files){
-	if(! $get $i){
-		echo $name ' read failed - bad password?'
-		sleep 2
+	if(! get $i){
+		msg $name ' read failed - bad password?'
 		exit password
 	}
+	walk -eq $i > ../qids/$i
 }
-sleep 2; date > _timestamp	# so we can find which files have been edited.
 
 # edit the files
-if(~ $edit yes) $editor `{for(i in $files) basename $i}
-if(~ $flush yes ){
-	echo flushing old keys
+if(~ $readin 1) {
+	if(! ~ $#files 1){
+		msg $name ': ambiguous file to append'
+		exit toomany
+	}
+	cat >>$files
+}
+if not if(~ $edit 1)
+	$editor `{for(i in $files) basename $i}
+if(~ $flush 1 ){
+	msg flushing old keys
 	echo delkey > /mnt/factotum/ctl
 }
-if(~ $load yes){
-	echo loading factotum keys
-	if (~ factotum $files) read -m < factotum > /mnt/factotum/ctl
+if(~ $load 1){
+	msg loading factotum keys
+	if (~ factotum $files)
+		read -m < factotum > /mnt/factotum/ctl
 }
 
 # copy the files back
-for(i in `{editedfiles}){
-	echo -n copy ''''`{basename $i}^'''' back?' [y/n/x]'
-	switch(`{read}){
+for(i in `{edited}){
+	msg -n copy ''''`{basename $i}^'''' back?' [y/n/x] '
+	switch(`{read /dev/cons}){
 	case [yY]*
-		if(! $put $i){
-			echo $name ' read failed - bad password?'
+		if(! put $i){
+			msg $name ' read failed - bad password?'
 			sleep 2
 			exit password
 		}
-		echo ''''$i'''' copied to $name
+		msg ''''$i'''' copied to $name
 		if(~ $i factotum)
 			read -m < $i > /mnt/factotum/ctl
 	case [xXqQ]*
 		exit
 	case [nN]* *
-		echo ''''$i'''' skipped
+		msg ''''$i'''' skipped
 	}
 }
-
-exit ''
--- a//sys/man/1/secstore
+++ b//sys/man/1/secstore
@@ -36,7 +36,7 @@
 .PP
 .B ipso
 [
-.B -a -e -l -f -s
+.B -[asr]
 ] [
 .I file
 \&...
@@ -53,8 +53,9 @@
 .B -c
 prompts for a password change.
 .PP
-Option
-.B -g
+It accepts the following options:
+.TP
+.B -g, -G
 retrieves a file to the local directory;
 option
 .B -G
@@ -65,14 +66,12 @@
 .L \&.
 will send to standard output
 a list of remote files with dates, lengths and SHA1 hashes.
-.PP
-Option
+.TP
 .B -i
 says that the password should be read from standard input
 instead of from
 .BR /dev/cons .
-.PP
-Option
+.TP
 .B -n
 says that the password should be read from NVRAM
 (see
@@ -79,16 +78,13 @@
 .IR authsrv (2))
 instead of from
 .BR /dev/cons .
-.PP
-Option
+.TP
 .B -p
 stores a file on the secstore.
-.PP
-Option
+.TP
 .B -r
 removes a file from the secstore.
-.PP
-Option
+.TP
 .B -s
 sets the dial string of the
 .IR secstore (8)
@@ -102,21 +98,19 @@
 .IR secstore (1)
 will attempt to dial
 .BR tcp!$auth!secstore  .
-.PP
-Option
+.TP
 .B -u
 access the secure-store files belonging to
 .IR user .
-.PP
-Option
+.TP
 .B -v
 produces more verbose output, in particular providing a few
 bits of feedback to help the user detect mistyping.
-.PP
+.IP
 For example, to add a secret to the file read by
 .IR factotum (4)
 at startup, open a new window, type
-.LP
+.IP
 .EX
   % ramfs -p; cd /tmp
   % auth/secstore -g factotum
@@ -126,7 +120,7 @@
   secstore password:
   % read -m factotum > /mnt/factotum/ctl
 .EE
-.LP
+.IP
 and delete the window.
 The first line creates an ephemeral memory-resident workspace,
 invisible to others and automatically removed when the window is deleted.
@@ -176,18 +170,10 @@
 .I ipso
 will just perform only the requested operations, i.e.,
 edit, flush, and/or load.
-.PP
-The
-.B -s
-option of
-.I ipso
-invokes
-.IR sam (1)
-as the editor insted of
-.BR acme ;
-the
+Ipso accepts the following options:
+.TP
 .B -a
-option provides a similar service for files encrypted by
+causes acme to act on files encrypted by
 .I aescbc
 .RI ( q.v. ).
 With the
@@ -200,6 +186,28 @@
 Also with
 .BR -a ,
 newly created files are ignored.
+.TP
+.B -r
+reads a key specification from stdin, adding it to
+the file managed by factotum.
+When
+.B -r
+is passed, only one file must be edited at once.
+.TP
+.B -s
+invokes
+.IR sam (1)
+as the editor.
+If
+.B -s
+is not specified, then the editor is inferred from
+the contents of
+.IR /mnt/plumb/rules ,
+falling back to
+.IR acme (1)
+if there is no
+.I editor=
+line present.
 .PP
 .I Aescbc
 encrypts (under


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-09-01 22:27 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-01  1:37 [9front] ipso: read keys from stdin ori
2021-09-01 21:42 ` Steve Simon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).