Check-in [8732d95e73]
Overview
SHA1:8732d95e73d67b2ce7d388c5c885731bfc78220d
Date: 2016-03-15 19:34:31
User: rkeene
Comment:Updated to use a plain-text format for password storage
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | folders | manifest
Tags And Properties
Context
2016-03-15
19:41
[bf46eec3a7] Updated README to be more accurate and deal with the new storage mechanism (user: rkeene, tags: trunk)
19:34
[8732d95e73] Updated to use a plain-text format for password storage (user: rkeene, tags: trunk)
18:35
[21bc3c9fe8] Updated to make verification failure more fatal (user: rkeene, tags: trunk)
Changes

Modified hunter2 from [05208b6e4e] to [a60ac58fb4].

    90     90   	_printHelp stderr ""
    91     91   
    92     92   	exit 1
    93     93   }
    94     94   
    95     95   set argv [lrange $argv 2 end]
    96     96   
           97  +# We need Tcl 8.6 for [binary encode base64]
           98  +package require Tcl 8.6
    97     99   package require sqlite3
    98    100   package require platform
    99    101   
   100    102   lappend ::auto_path [file join [file dirname [info script]] lib [platform::identify]]
   101    103   lappend ::auto_path [file join [file dirname [info script]] lib [platform::generic]]
   102    104   lappend ::auto_path [file join [file dirname [info script]] lib]
   103    105   
................................................................................
   165    167                           ]
   166    168   
   167    169           return [list data $ret begin "-----BEGIN PUBLIC KEY-----" end "-----END PUBLIC KEY-----"]
   168    170   }
   169    171   # End backports
   170    172   
   171    173   # Start internal functions
          174  +proc _loadDB {dbCmd fileName} {
          175  +	set ::saveRequired 1
          176  +
          177  +	if {[file exists $fileName]} {
          178  +		set fd [open $fileName]
          179  +
          180  +		# Verify that we have a valid file
          181  +		gets $fd header
          182  +
          183  +		# Ignore the first line if it is a hash-bang as well
          184  +		if {[string range $header 0 1] == "#!"} {
          185  +			set ::globalHeader($dbCmd) $header
          186  +
          187  +			gets $fd header
          188  +		}
          189  +
          190  +		if {$header ne "# <AzureDiamond> oh, ok."} {
          191  +			# This may be an old SQLite3 DB, convert it
          192  +			close $fd
          193  +
          194  +			sqlite3 $dbCmd $fileName
          195  +
          196  +			_saveDB $dbCmd $fileName
          197  +
          198  +			$dbCmd close
          199  +
          200  +			return [_loadDB $dbCmd $fileName]
          201  +		}
          202  +
          203  +		set data [read $fd]
          204  +
          205  +		close $fd
          206  +	} else {
          207  +		set data ""
          208  +	}
          209  +
          210  +	sqlite3 $dbCmd ":memory:"
          211  +
          212  +	$dbCmd eval {
          213  +		CREATE TABLE IF NOT EXISTS users(name, publicKey BLOB);
          214  +		CREATE TABLE IF NOT EXISTS passwords(name, encryptedPass BLOB, encryptedKey BLOB, publicKey BLOB, verification BLOB);
          215  +	}
          216  +
          217  +	$dbCmd transaction {
          218  +		foreach line [split $data "\n"] {
          219  +			if {[string trim $line] eq ""} {
          220  +				continue
          221  +			}
          222  +
          223  +			set table [lindex $line 0]
          224  +			set line [lrange $line 1 end]
          225  +
          226  +			set keys [list]
          227  +			set values [list]
          228  +			unset -nocomplain valueArray
          229  +
          230  +			foreach {key value} $line {
          231  +				if {[string index $key 0] == ":"} {
          232  +					set key [string range $key 1 end]
          233  +					set valueBase64Encoded 1
          234  +				} else {
          235  +					set valueBase64Encoded 0
          236  +				}
          237  +
          238  +				if {$valueBase64Encoded} {
          239  +					set value [binary decode base64 $value]
          240  +				}
          241  +
          242  +				if {![regexp {^[a-zA-Z]+$} $key]} {
          243  +					return -code error "Invalid key name: $key"
          244  +				}
          245  +
          246  +				switch -- $key {
          247  +					"name" {
          248  +						set type ""
          249  +						set typeInsertChar {$}
          250  +
          251  +						# Convert this to a string-ified value
          252  +						set value [string range "x$value" 1 end]
          253  +					}
          254  +					default {
          255  +						set type "BLOB"
          256  +						set typeInsertChar "@"
          257  +					}
          258  +				}
          259  +
          260  +				lappend keys $key
          261  +
          262  +				set valueArray($key) $value
          263  +
          264  +				lappend values ${typeInsertChar}valueArray($key)
          265  +			}
          266  +
          267  +			$dbCmd eval "INSERT INTO $table ([join $keys {, }]) VALUES ([join $values {, }]);"
          268  +		}
          269  +	}
          270  +}
          271  +
          272  +proc _saveDB {dbCmd fileName} {
          273  +	set tmpFileName "${fileName}.[expr rand()]"
          274  +
          275  +	file delete -force -- $tmpFileName
          276  +
          277  +	set fd [open $tmpFileName w]
          278  +
          279  +	if {[info exists ::globalHeader($dbCmd)]} {
          280  +		puts $fd $::globalHeader($dbCmd)
          281  +
          282  +		unset ::globalHeader($dbCmd)
          283  +	}
          284  +
          285  +	puts $fd "# <AzureDiamond> oh, ok."
          286  +
          287  +	foreach table [list users passwords] {
          288  +		unset -nocomplain row
          289  +		$dbCmd eval "SELECT * FROM $table ORDER BY name;" row {
          290  +			set outputLine [list $table]
          291  +
          292  +			unset -nocomplain row(*)
          293  +
          294  +			foreach {key value} [array get row] {
          295  +				if {![regexp {^[a-zA-Z]+$} $value]} {
          296  +					set key ":$key"
          297  +					set value [binary encode base64 $value]
          298  +				}
          299  +
          300  +				lappend outputLine $key $value
          301  +			}
          302  +
          303  +			puts $fd $outputLine
          304  +		}
          305  +	}
          306  +
          307  +	close $fd
          308  +
          309  +	catch {
          310  +		file attributes $tmpFileName {*}[file attributes $fileName]
          311  +	}
          312  +
          313  +	file rename -force -- $tmpFileName $fileName
          314  +}
          315  +
   172    316   proc _listCertificates {} {
   173    317   	if {![info exists ::env(PKCS11MODULE)]} {
   174    318   		return [list]
   175    319   	}
   176    320   
   177    321   	set ::env(CACKEY_NO_EXTRA_CERTS) 1
   178    322   
................................................................................
   415    559   	foreach {subject pubkeys} [array get publicKeys] {
   416    560   		puts "$subject"
   417    561   
   418    562   		foreach pubkey $pubkeys {
   419    563   			puts "  |-> $pubkey"
   420    564   		}
   421    565   	}
          566  +
          567  +	set ::saveRequired 0
   422    568   }
   423    569   
   424    570   proc listAvailablePasswords {} {
   425    571   	set passwordNames [list]
   426    572   	foreach slotInfoDict [_listCertificates] {
   427    573   		unset -nocomplain slotInfo
   428    574   		array set slotInfo $slotInfoDict
................................................................................
   439    585   		}
   440    586   	}
   441    587   
   442    588   
   443    589   	foreach passwordName $passwordNames {
   444    590   		puts "$passwordName - [join [_getUsersForPassword [list $passwordName]] {, }]"
   445    591   	}
          592  +
          593  +	set ::saveRequired 0
   446    594   }
   447    595   
   448    596   proc listPasswords {} {
   449    597   	db eval {SELECT DISTINCT name FROM passwords;} row {
   450    598   		puts "$row(name) - [join [_getUsersForPassword [list $row(name)]] {, }]"
   451    599   	}
          600  +
          601  +	set ::saveRequired 0
   452    602   }
   453    603   
   454    604   proc listUsers {} {
   455    605   	db eval {SELECT DISTINCT name FROM users;} row {
   456    606   		puts "$row(name) - [join [_getPasswordsForUser [list $row(name)]] {, }]"
   457    607   	}
          608  +
          609  +	set ::saveRequired 0
   458    610   }
   459    611   
   460    612   proc addUser {userName key} {
   461    613   	set keyRaw [binary decode base64 $key]
   462    614   	set keyVerify [::pki::pkcs::parse_public_key $keyRaw]
   463    615   
   464    616   	db eval {INSERT INTO users (name, publicKey) VALUES ($userName, @key);}
................................................................................
   493    645   	}
   494    646   
   495    647   	_addPassword $passwordName $password $publicKeys
   496    648   }
   497    649   
   498    650   proc getPassword {passwordName} {
   499    651   	puts [_getPassword $passwordName]
          652  +
          653  +	set ::saveRequired 0
   500    654   }
   501    655   
   502    656   proc updatePassword {passwordName password} {
   503    657   	if {$password eq ""} {
   504    658   		set password [_prompt "Please enter the new password: "]
   505    659   	}
   506    660   
................................................................................
   566    720   		unset -nocomplain row
   567    721   		db eval {SELECT name FROM users WHERE publicKey = $pubkey;} row {
   568    722   			set users($row(name)) 1
   569    723   		}
   570    724   	}
   571    725   
   572    726   	puts [join [array names users] {, }]
          727  +
          728  +	set ::saveRequired 0
   573    729   }
   574    730   
   575    731   proc help {{action ""}} {
   576    732   	_printHelp stdout $action
          733  +
          734  +	set ::saveRequired 0
   577    735   }
   578    736   # End user CLI functions
   579    737   
   580    738   ### MAIN
   581    739   
   582         -sqlite3 db $passwordFile
   583         -
   584         -db eval {
   585         -	CREATE TABLE IF NOT EXISTS users(name, publicKey BLOB);
   586         -	CREATE TABLE IF NOT EXISTS passwords(name, encryptedPass BLOB, encryptedKey BLOB, publicKey BLOB, verification BLOB);
   587         -}
          740  +_loadDB db $passwordFile
   588    741   
   589    742   if {$action in $validCommands} {
   590    743   	if {[catch {
   591    744   		$action {*}$argv
   592    745   	} error]} {
   593    746   		puts stderr "Error: $error"
   594    747   
................................................................................
   596    749   	}
   597    750   } else {
   598    751   	puts stderr "Invalid action"
   599    752   
   600    753   	exit 1
   601    754   }
   602    755   
   603         -exit 0
          756  +if {$::saveRequired} {
          757  +	_saveDB db $passwordFile
          758  +}
          759  +
          760  +db close
   604    761   
          762  +exit 0