--- /dev/null
+There is ability to integrity protect the exported configuration.
+Exported txtar contains trailing ".csum" pseudo file with one or
+multiple hashes of the digested data.
+
+DSC_HASHES environment variables specified what hashes must be included
+and invoked. For example "blake2b-512:b2sum,skein-512:skein512" value
+means, that BLAKE2b-512 is calculated by calling "b2sum" utility, and
+Skein-512 by "skein512".
+
+"dsc csum" command can be used to calculate hashes over the arbitrary
+data. "dsc import-check" can be used to verify piped in configuration
+integrity. "dsc import-pipe" does not do any checks, so import-check
+should be called before. "dsc import FILE" just calls import-check
+followed by import-pipe.
dsc revert opt -- revert opt's configuration
dsc commit -- commit (save) configuration
dsc export [prefix] >file.txtar -- export (whole by default) configuration
- dsc import <file.txtar -- import it
+ dsc import-check <file.txtar -- verify configuration's checksum
+ dsc import-pipe <file.txtar -- import configuration
+ dsc import file.txtar -- verify and import configuration
dsc path opt -- get full path to option's value (if set)
dsc apply prefix -- apply configuration on given prefix
+ dsc csum <data -- compute data's checksum
Environmental variables:
$DSC_SCHEMA -- path to the schema definition
$DSC_STASH -- path to stashed/unsaved state
$DSC_SAVED -- path to committed/saved state
+ $DSC_HASHES -- sha2-512:sha512 by default
+ Comma-separated list of hash-name:cmd pairs
There are two kinds of options:
* array/list ones, which are identified with /*/ in "list"'s
exit 1
}
-if {[catch {set Schema $env(DSC_SCHEMA)}]} {set Schema schema}
-if {[catch {set Stash $env(DSC_STASH)}]} {set Stash stash}
-if {[catch {set Saved $env(DSC_SAVED)}]} {set Saved saved}
+set CopyBufLen [expr {128 * 1024}]
+if {[info exists env(DSC_SCHEMA)]} {set Schema $env(DSC_SCHEMA)} {set Schema schema}
+if {[info exists env(DSC_STASH)]} {set Stash $env(DSC_STASH)} {set Stash stash}
+if {[info exists env(DSC_SAVED)]} {set Saved $env(DSC_SAVED)} {set Saved saved}
+if {[info exists env(DSC_HASHES)]} {
+ set Hashes [dict create]
+ foreach pair [split $env(DSC_HASHES) ,] {
+ set cols [split $pair :]
+ if {[llength $cols] != 2} {
+ error "bad DSC_HASHES"
+ }
+ dict set Hashes [lindex $cols 0] [lindex $cols 1]
+ }
+} {
+ set Hashes [dict create sha2-512 sha512]
+}
proc readents {root typ} {
set ents [glob -directory $root -tails -nocomplain -- *]
file rename $tmp $Saved
file delete -force $Saved.bak
}
- export {
+ csum {
+ set hsh [dict create]
+ dict for {name cmd} $Hashes {
+ lassign [pipe] r w
+ set fh [open [list |$cmd >@$w] w]
+ fconfigure $fh -translation binary
+ dict set hsh $name [list $fh $r $w]
+ }
+ fconfigure stdin -translation binary
+ while {![eof stdin]} {
+ set buf [read stdin $CopyBufLen]
+ dict for {_ fhs} $hsh {
+ lassign $fhs fh
+ puts -nonewline $fh $buf
+ }
+ }
+ foreach name [lsort [dict keys $hsh]] {
+ lassign [dict get $hsh $name] fh r w
+ close $fh
+ close $w
+ gets $r v
+ set v [split $v " "]
+ puts "$name [lindex $v 0]"
+ }
+ }
+ export-raw {
set dirs [walk $Saved/$opt directory]
if {$opt != ""} {
set dirs [list $Saved/$opt {*}$dirs]
}
}
}
- import {
+ export {
+ set exporter [open [list |$argv0 export-raw $opt]]
+ fconfigure $exporter -translation binary
+ lassign [pipe] r w
+ set hasher [open [list |$argv0 csum >@$w] w]
+ fconfigure $hasher -translation binary
+ fconfigure stdout -translation binary
+ while {![eof $exporter]} {
+ set buf [read $exporter $CopyBufLen]
+ puts -nonewline stdout $buf
+ puts -nonewline $hasher $buf
+ }
+ close $hasher
+ close $w
+ puts "-- .csum --"
+ puts -nonewline [read $r]
+ }
+ import-pipe {
fconfigure stdin -translation binary
while {[gets stdin line] >= 0} {
set fn [txtar-fn $line]
puts $fh $line
} elseif {[string range $fn 0 2] == "-- "} {
puts $fh $fn
+ } elseif {$fn == ".csum"} {
+ break
} else {
close $fh
set fh [openfh $fn]
close $fh
exec sync
}
+ import-check {
+ lassign [pipe] r w
+ set hasher [open [list |$argv0 csum >@$w] w]
+ fconfigure $hasher -translation binary
+ fconfigure stdin -translation binary
+ while {[gets stdin line] >= 0} {
+ if {$line == "-- .csum --"} {
+ break
+ }
+ puts $hasher $line
+ }
+ close $hasher
+ close $w
+ set got [read $r]
+ set exp [read stdin]
+ if {$got == $exp} {
+ exit 0
+ }
+ puts stderr "integrity failure"
+ puts -nonewline stderr $got
+ puts stderr "\t!="
+ puts -nonewline stderr $exp
+ exit 1
+ }
+ import {
+ exec $argv0 import-check <$opt
+ exec $argv0 import-pipe <$opt
+ }
path {
if {[file exists $Stash/$opt]} {
puts [file normalize $Stash/$opt]
test_expect_success "export" "dsc export >out"
test_expect_success "has base64" "grep -q :base64 out"
test_expect_success "del *" 'dsc del ""'
-test_expect_success "import" "dsc import <out"
+test_expect_success "import" "dsc import-pipe <out"
test_expect_success "get" "dsc get ssh/prv >out"
test_expect_success "cmp" "test_cmp out prv"
--- /dev/null
+#!/bin/sh
+
+test_description="$(basename $0)"
+. $SHARNESS_TEST_SRCDIR/sharness.sh
+. $SHARNESS_TEST_DIRECTORY/setup.rc
+
+test_expect_success "hostname" "dsc set sys/hostname mein"
+test_expect_success "commit" "dsc commit"
+test_expect_success "export-raw" "dsc export-raw >out"
+test_expect_success "csum" "dsc csum <out >detached"
+cp out expected
+printf "%s\n" "-- .csum --" >>expected
+cat detached >>expected
+test_expect_success "export" "dsc export >out"
+test_expect_success "cmp" "test_cmp out expected"
+test_expect_success "import-check" "dsc import-check <out"
+test_expect_success "import" "dsc import out"
+
+dsc export-raw >out
+test_expect_success "without csum -check" "! dsc import-check <out"
+test_expect_success "without csum import" "! dsc import out"
+printf "%s\n" "-- .csum --" >>expected
+echo "whatever hash" >>expected
+test_expect_success "wrong csum" "! dsc import-check <out"
+
+DSC_HASHES="sha2-512:sha512"
+test_expect_success "export sha512" "dsc export >out"
+cat >expected <<EOF
+-- .dirs --
+sys
+-- sys/hostname --
+mein
+EOF
+sha512 <expected >hsh
+printf "%s\n" "-- .csum --" >>expected
+echo -n "sha2-512 " >>expected
+cat hsh >>expected
+test_expect_success "cmp" "test_cmp out expected"
+
+test_done
test_expect_success "commit" "dsc commit"
test_expect_success "diff" "dsc diff >out"
test_expect_success "diff is empty" "! [ -s out ]"
-test_expect_success "export" "dsc export >out"
+test_expect_success "export" "dsc export-raw >out"
cat >expected <<EOF
-- .dirs --
net
test_expect_success "cmp" "test_cmp out expected"
rm -r $DSC_STASH
-test_expect_success "import" "dsc import <out"
+test_expect_success "import" "dsc import-pipe <out"
test_expect_success "diff" "dsc diff >out"
-cat out
test_expect_success "diff is empty" "! [ -s out ]"
test_done
-- /abs/path --
gotcha
EOF
-test_expect_success "import abs" "! dsc import <in >out 2>&1"
+test_expect_success "import abs" "! dsc import-pipe <in >out 2>&1"
test_expect_success "import abs msg" \
'[ "$(cat out)" = "absolute paths are forbidden" ]'
-- path/../rel --
gotcha
EOF
-test_expect_success "import rel" "! dsc import <in >out 2>&1"
+test_expect_success "import rel" "! dsc import-pipe <in >out 2>&1"
test_expect_success "import rel msg" \
'[ "$(cat out)" = "relative paths are forbidden" ]'
/abs/path
gotcha
EOF
-test_expect_success "import abs" "! dsc import <in >out 2>&1"
+test_expect_success "import abs" "! dsc import-pipe <in >out 2>&1"
test_expect_success "import abs msg" \
'[ "$(cat out)" = "absolute paths are forbidden" ]'
-- .dirs --
path/../rel
EOF
-test_expect_success "import rel" "! dsc import <in >out 2>&1"
+test_expect_success "import rel" "! dsc import-pipe <in >out 2>&1"
test_expect_success "import rel msg" \
'[ "$(cat out)" = "relative paths are forbidden" ]'
export JIMLIB="$SHARNESS_TEST_DIRECTORY/../jimlib:$JIMLIB"
PATH="$SHARNESS_TEST_DIRECTORY/..:$PATH"
mkdir saved
+export DSC_HASHES="sha2-512:sha512"
+if command -v skein512 2>/dev/null >/dev/null ; then
+ DSC_HASHES="skein-512:skein512,$DSC_HASHES"
+fi
+if command -v b2sum 2>/dev/null >/dev/null ; then
+ DSC_HASHES="blake2b-512:b2sum,$DSC_HASHES"
+fi