Hex Artifact Content

Artifact 6da8c360ca414a06595b17290690ac0b9c186160:


0000: 23 21 20 2f 75 73 72 2f 62 69 6e 2f 65 6e 76 20  #! /usr/bin/env 
0010: 74 63 6c 73 68 0a 0a 23 20 43 6f 70 79 72 69 67  tclsh..# Copyrig
0020: 68 74 20 28 63 29 20 32 30 31 36 2c 20 52 6f 79  ht (c) 2016, Roy
0030: 20 4b 65 65 6e 65 0a 23 20 41 6c 6c 20 72 69 67   Keene.# All rig
0040: 68 74 73 20 72 65 73 65 72 76 65 64 2e 0a 23 20  hts reserved..# 
0050: 0a 23 20 52 65 64 69 73 74 72 69 62 75 74 69 6f  .# Redistributio
0060: 6e 20 61 6e 64 20 75 73 65 20 69 6e 20 73 6f 75  n and use in sou
0070: 72 63 65 20 61 6e 64 20 62 69 6e 61 72 79 20 66  rce and binary f
0080: 6f 72 6d 73 2c 20 77 69 74 68 20 6f 72 20 77 69  orms, with or wi
0090: 74 68 6f 75 74 0a 23 20 6d 6f 64 69 66 69 63 61  thout.# modifica
00a0: 74 69 6f 6e 2c 20 61 72 65 20 70 65 72 6d 69 74  tion, are permit
00b0: 74 65 64 20 70 72 6f 76 69 64 65 64 20 74 68 61  ted provided tha
00c0: 74 20 74 68 65 20 66 6f 6c 6c 6f 77 69 6e 67 20  t the following 
00d0: 63 6f 6e 64 69 74 69 6f 6e 73 20 61 72 65 0a 23  conditions are.#
00e0: 20 6d 65 74 3a 0a 23 20 20 20 20 20 20 20 20 20   met:.#         
00f0: 31 2e 20 52 65 64 69 73 74 72 69 62 75 74 69 6f  1. Redistributio
0100: 6e 73 20 6f 66 20 73 6f 75 72 63 65 20 63 6f 64  ns of source cod
0110: 65 20 6d 75 73 74 20 72 65 74 61 69 6e 20 74 68  e must retain th
0120: 65 20 61 62 6f 76 65 20 63 6f 70 79 72 69 67 68  e above copyrigh
0130: 74 0a 23 20 20 20 20 20 20 20 20 20 20 20 20 6e  t.#            n
0140: 6f 74 69 63 65 2c 20 74 68 69 73 20 6c 69 73 74  otice, this list
0150: 20 6f 66 20 63 6f 6e 64 69 74 69 6f 6e 73 20 61   of conditions a
0160: 6e 64 20 74 68 65 20 66 6f 6c 6c 6f 77 69 6e 67  nd the following
0170: 20 64 69 73 63 6c 61 69 6d 65 72 2e 0a 23 20 0a   disclaimer..# .
0180: 23 20 20 20 20 20 20 20 20 20 32 2e 20 52 65 64  #         2. Red
0190: 69 73 74 72 69 62 75 74 69 6f 6e 73 20 69 6e 20  istributions in 
01a0: 62 69 6e 61 72 79 20 66 6f 72 6d 20 6d 75 73 74  binary form must
01b0: 20 72 65 70 72 6f 64 75 63 65 20 74 68 65 20 61   reproduce the a
01c0: 62 6f 76 65 0a 23 20 20 20 20 20 20 20 20 20 20  bove.#          
01d0: 20 20 63 6f 70 79 72 69 67 68 74 20 6e 6f 74 69    copyright noti
01e0: 63 65 2c 20 74 68 69 73 20 6c 69 73 74 20 6f 66  ce, this list of
01f0: 20 63 6f 6e 64 69 74 69 6f 6e 73 20 61 6e 64 20   conditions and 
0200: 74 68 65 20 66 6f 6c 6c 6f 77 69 6e 67 0a 23 20  the following.# 
0210: 20 20 20 20 20 20 20 20 20 20 20 64 69 73 63 6c             discl
0220: 61 69 6d 65 72 20 69 6e 20 74 68 65 20 64 6f 63  aimer in the doc
0230: 75 6d 65 6e 74 61 74 69 6f 6e 20 61 6e 64 2f 6f  umentation and/o
0240: 72 20 6f 74 68 65 72 20 6d 61 74 65 72 69 61 6c  r other material
0250: 73 0a 23 20 20 20 20 20 20 20 20 20 20 20 20 70  s.#            p
0260: 72 6f 76 69 64 65 64 20 77 69 74 68 20 74 68 65  rovided with the
0270: 20 64 69 73 74 72 69 62 75 74 69 6f 6e 2e 0a 23   distribution..#
0280: 0a 23 20 54 48 49 53 20 53 4f 46 54 57 41 52 45  .# THIS SOFTWARE
0290: 20 49 53 20 50 52 4f 56 49 44 45 44 20 42 59 20   IS PROVIDED BY 
02a0: 54 48 45 20 43 4f 50 59 52 49 47 48 54 20 48 4f  THE COPYRIGHT HO
02b0: 4c 44 45 52 53 20 41 4e 44 20 43 4f 4e 54 52 49  LDERS AND CONTRI
02c0: 42 55 54 4f 52 53 20 22 41 53 20 0a 23 20 49 53  BUTORS "AS .# IS
02d0: 22 20 41 4e 44 20 41 4e 59 20 45 58 50 52 45 53  " AND ANY EXPRES
02e0: 53 20 4f 52 20 49 4d 50 4c 49 45 44 20 57 41 52  S OR IMPLIED WAR
02f0: 52 41 4e 54 49 45 53 2c 20 49 4e 43 4c 55 44 49  RANTIES, INCLUDI
0300: 4e 47 2c 20 42 55 54 20 4e 4f 54 20 4c 49 4d 49  NG, BUT NOT LIMI
0310: 54 45 44 20 0a 23 20 54 4f 2c 20 54 48 45 20 49  TED .# TO, THE I
0320: 4d 50 4c 49 45 44 20 57 41 52 52 41 4e 54 49 45  MPLIED WARRANTIE
0330: 53 20 4f 46 20 4d 45 52 43 48 41 4e 54 41 42 49  S OF MERCHANTABI
0340: 4c 49 54 59 20 41 4e 44 20 46 49 54 4e 45 53 53  LITY AND FITNESS
0350: 20 46 4f 52 20 41 20 0a 23 20 50 41 52 54 49 43   FOR A .# PARTIC
0360: 55 4c 41 52 20 50 55 52 50 4f 53 45 20 41 52 45  ULAR PURPOSE ARE
0370: 20 44 49 53 43 4c 41 49 4d 45 44 2e 20 49 4e 20   DISCLAIMED. IN 
0380: 4e 4f 20 45 56 45 4e 54 20 53 48 41 4c 4c 20 54  NO EVENT SHALL T
0390: 48 45 20 43 4f 50 59 52 49 47 48 54 20 0a 23 20  HE COPYRIGHT .# 
03a0: 48 4f 4c 44 45 52 20 4f 52 20 43 4f 4e 54 52 49  HOLDER OR CONTRI
03b0: 42 55 54 4f 52 53 20 42 45 20 4c 49 41 42 4c 45  BUTORS BE LIABLE
03c0: 20 46 4f 52 20 41 4e 59 20 44 49 52 45 43 54 2c   FOR ANY DIRECT,
03d0: 20 49 4e 44 49 52 45 43 54 2c 20 49 4e 43 49 44   INDIRECT, INCID
03e0: 45 4e 54 41 4c 2c 20 0a 23 20 53 50 45 43 49 41  ENTAL, .# SPECIA
03f0: 4c 2c 20 45 58 45 4d 50 4c 41 52 59 2c 20 4f 52  L, EXEMPLARY, OR
0400: 20 43 4f 4e 53 45 51 55 45 4e 54 49 41 4c 20 44   CONSEQUENTIAL D
0410: 41 4d 41 47 45 53 20 28 49 4e 43 4c 55 44 49 4e  AMAGES (INCLUDIN
0420: 47 2c 20 42 55 54 20 4e 4f 54 20 4c 49 4d 49 54  G, BUT NOT LIMIT
0430: 45 44 20 0a 23 20 54 4f 2c 20 50 52 4f 43 55 52  ED .# TO, PROCUR
0440: 45 4d 45 4e 54 20 4f 46 20 53 55 42 53 54 49 54  EMENT OF SUBSTIT
0450: 55 54 45 20 47 4f 4f 44 53 20 4f 52 20 53 45 52  UTE GOODS OR SER
0460: 56 49 43 45 53 3b 20 4c 4f 53 53 20 4f 46 20 55  VICES; LOSS OF U
0470: 53 45 2c 20 44 41 54 41 2c 20 4f 52 20 0a 23 20  SE, DATA, OR .# 
0480: 50 52 4f 46 49 54 53 3b 20 4f 52 20 42 55 53 49  PROFITS; OR BUSI
0490: 4e 45 53 53 20 49 4e 54 45 52 52 55 50 54 49 4f  NESS INTERRUPTIO
04a0: 4e 29 20 48 4f 57 45 56 45 52 20 43 41 55 53 45  N) HOWEVER CAUSE
04b0: 44 20 41 4e 44 20 4f 4e 20 41 4e 59 20 54 48 45  D AND ON ANY THE
04c0: 4f 52 59 20 4f 46 20 0a 23 20 4c 49 41 42 49 4c  ORY OF .# LIABIL
04d0: 49 54 59 2c 20 57 48 45 54 48 45 52 20 49 4e 20  ITY, WHETHER IN 
04e0: 43 4f 4e 54 52 41 43 54 2c 20 53 54 52 49 43 54  CONTRACT, STRICT
04f0: 20 4c 49 41 42 49 4c 49 54 59 2c 20 4f 52 20 54   LIABILITY, OR T
0500: 4f 52 54 20 28 49 4e 43 4c 55 44 49 4e 47 20 0a  ORT (INCLUDING .
0510: 23 20 4e 45 47 4c 49 47 45 4e 43 45 20 4f 52 20  # NEGLIGENCE OR 
0520: 4f 54 48 45 52 57 49 53 45 29 20 41 52 49 53 49  OTHERWISE) ARISI
0530: 4e 47 20 49 4e 20 41 4e 59 20 57 41 59 20 4f 55  NG IN ANY WAY OU
0540: 54 20 4f 46 20 54 48 45 20 55 53 45 20 4f 46 20  T OF THE USE OF 
0550: 54 48 49 53 20 0a 23 20 53 4f 46 54 57 41 52 45  THIS .# SOFTWARE
0560: 2c 20 45 56 45 4e 20 49 46 20 41 44 56 49 53 45  , EVEN IF ADVISE
0570: 44 20 4f 46 20 54 48 45 20 50 4f 53 53 49 42 49  D OF THE POSSIBI
0580: 4c 49 54 59 20 4f 46 20 53 55 43 48 20 44 41 4d  LITY OF SUCH DAM
0590: 41 47 45 2e 0a 0a 73 65 74 20 70 61 73 73 77 6f  AGE...set passwo
05a0: 72 64 46 69 6c 65 20 5b 6c 69 6e 64 65 78 20 24  rdFile [lindex $
05b0: 61 72 67 76 20 30 5d 0a 73 65 74 20 61 63 74 69  argv 0].set acti
05c0: 6f 6e 20 5b 6c 69 6e 64 65 78 20 24 61 72 67 76  on [lindex $argv
05d0: 20 31 5d 0a 0a 73 65 74 20 76 61 6c 69 64 43 6f   1]..set validCo
05e0: 6d 6d 61 6e 64 73 20 5b 6c 69 73 74 20 22 6c 69  mmands [list "li
05f0: 73 74 4c 6f 63 61 6c 4b 65 79 73 22 20 22 6c 69  stLocalKeys" "li
0600: 73 74 50 61 73 73 77 6f 72 64 73 22 20 22 6c 69  stPasswords" "li
0610: 73 74 41 76 61 69 6c 61 62 6c 65 50 61 73 73 77  stAvailablePassw
0620: 6f 72 64 73 22 20 22 6c 69 73 74 55 73 65 72 73  ords" "listUsers
0630: 22 20 22 61 64 64 55 73 65 72 22 20 22 61 64 64  " "addUser" "add
0640: 50 61 73 73 77 6f 72 64 22 20 22 61 75 74 68 6f  Password" "autho
0650: 72 69 7a 65 55 73 65 72 22 20 22 61 75 74 68 6f  rizeUser" "autho
0660: 72 69 7a 65 55 73 65 72 73 22 20 22 64 65 61 75  rizeUsers" "deau
0670: 74 68 6f 72 69 7a 65 55 73 65 72 22 20 22 64 65  thorizeUser" "de
0680: 61 75 74 68 6f 72 69 7a 65 55 73 65 72 73 22 20  authorizeUsers" 
0690: 22 67 65 74 50 61 73 73 77 6f 72 64 22 20 22 75  "getPassword" "u
06a0: 70 64 61 74 65 50 61 73 73 77 6f 72 64 22 20 22  pdatePassword" "
06b0: 64 65 6c 65 74 65 50 61 73 73 77 6f 72 64 22 20  deletePassword" 
06c0: 22 68 65 6c 70 22 20 22 77 68 6f 61 6d 69 22 5d  "help" "whoami"]
06d0: 0a 0a 70 72 6f 63 20 5f 61 72 67 44 65 73 63 72  ..proc _argDescr
06e0: 69 70 74 69 6f 6e 20 7b 63 6f 6d 6d 61 6e 64 20  iption {command 
06f0: 61 72 67 4e 61 6d 65 7d 20 7b 0a 09 73 77 69 74  argName} {..swit
0700: 63 68 20 2d 2d 20 24 61 72 67 4e 61 6d 65 20 7b  ch -- $argName {
0710: 0a 09 09 22 70 61 73 73 77 6f 72 64 4e 61 6d 65  ..."passwordName
0720: 22 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 22 24  " {....return "$
0730: 61 72 67 4e 61 6d 65 20 2d 20 4e 61 6d 65 20 6f  argName - Name o
0740: 66 20 74 68 65 20 70 61 73 73 77 6f 72 64 20 65  f the password e
0750: 6e 74 72 79 22 0a 09 09 7d 0a 09 09 22 6b 65 79  ntry"...}..."key
0760: 22 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 22 24  " {....return "$
0770: 61 72 67 4e 61 6d 65 20 2d 20 50 75 62 6c 69 63  argName - Public
0780: 20 6b 65 79 20 6f 66 20 74 68 65 20 75 73 65 72   key of the user
0790: 22 0a 09 09 7d 0a 09 09 22 70 61 73 73 77 6f 72  "...}..."passwor
07a0: 64 22 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 22  d" {....return "
07b0: 24 61 72 67 4e 61 6d 65 20 2d 20 41 20 70 6c 61  $argName - A pla
07c0: 69 6e 2d 74 65 78 74 20 70 61 73 73 77 6f 72 64  in-text password
07d0: 22 0a 09 09 7d 0a 09 09 22 75 73 65 72 4e 61 6d  "...}..."userNam
07e0: 65 22 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 22  e" {....return "
07f0: 24 61 72 67 4e 61 6d 65 20 2d 20 41 20 75 73 65  $argName - A use
0800: 72 20 6e 61 6d 65 22 0a 09 09 7d 0a 09 09 22 61  r name"...}..."a
0810: 63 74 69 6f 6e 22 20 7b 0a 09 09 09 72 65 74 75  ction" {....retu
0820: 72 6e 20 22 24 61 72 67 4e 61 6d 65 20 2d 20 41  rn "$argName - A
0830: 6e 20 61 63 74 69 6f 6e 20 6e 61 6d 65 20 66 6f  n action name fo
0840: 72 20 68 65 6c 70 20 77 69 74 68 22 0a 09 09 7d  r help with"...}
0850: 0a 09 09 22 61 72 67 73 22 20 7b 0a 09 09 09 72  ..."args" {....r
0860: 65 74 75 72 6e 20 22 75 73 65 72 4c 69 73 74 20  eturn "userList 
0870: 2d 20 41 20 6c 69 73 74 20 6f 66 20 75 73 65 72  - A list of user
0880: 6e 61 6d 65 73 22 0a 09 09 7d 0a 09 7d 0a 0a 09  names"...}..}...
0890: 72 65 74 75 72 6e 20 22 3c 55 4e 4b 4e 4f 57 4e  return "<UNKNOWN
08a0: 3e 22 0a 7d 0a 0a 70 72 6f 63 20 5f 70 72 69 6e  >".}..proc _prin
08b0: 74 48 65 6c 70 20 7b 63 68 61 6e 6e 65 6c 20 63  tHelp {channel c
08c0: 6f 6d 6d 61 6e 64 7d 20 7b 0a 09 69 66 20 7b 24  ommand} {..if {$
08d0: 63 6f 6d 6d 61 6e 64 20 3d 3d 20 22 22 7d 20 7b  command == ""} {
08e0: 0a 09 09 70 75 74 73 20 24 63 68 61 6e 6e 65 6c  ...puts $channel
08f0: 20 22 55 73 61 67 65 3a 20 68 75 6e 74 65 72 32   "Usage: hunter2
0900: 20 3c 70 61 73 73 77 6f 72 64 46 69 6c 65 3e 20   <passwordFile> 
0910: 3c 61 63 74 69 6f 6e 3e 20 5c 5b 3c 61 63 74 69  <action> \[<acti
0920: 6f 6e 41 72 67 73 2e 2e 2e 3e 5c 5d 22 0a 09 09  onArgs...>\]"...
0930: 70 75 74 73 20 24 63 68 61 6e 6e 65 6c 20 22 22  puts $channel ""
0940: 0a 09 09 70 75 74 73 20 24 63 68 61 6e 6e 65 6c  ...puts $channel
0950: 20 22 41 63 74 69 6f 6e 73 3a 22 0a 09 09 70 75   "Actions:"...pu
0960: 74 73 20 24 63 68 61 6e 6e 65 6c 20 22 20 20 20  ts $channel "   
0970: 20 5b 6a 6f 69 6e 20 24 3a 3a 76 61 6c 69 64 43   [join $::validC
0980: 6f 6d 6d 61 6e 64 73 20 7b 2c 20 7d 5d 22 0a 09  ommands {, }]"..
0990: 09 70 75 74 73 20 24 63 68 61 6e 6e 65 6c 20 22  .puts $channel "
09a0: 22 0a 09 09 70 75 74 73 20 24 63 68 61 6e 6e 65  "...puts $channe
09b0: 6c 20 22 20 20 20 20 68 75 6e 74 65 72 32 20 3c  l "    hunter2 <
09c0: 66 69 6c 65 3e 20 68 65 6c 70 20 3c 61 63 74 69  file> help <acti
09d0: 6f 6e 3e 20 20 20 20 66 6f 72 20 68 65 6c 70 20  on>    for help 
09e0: 77 69 74 68 20 61 6e 20 61 63 74 69 6f 6e 22 0a  with an action".
09f0: 09 7d 20 65 6c 73 65 20 7b 0a 09 09 73 65 74 20  .} else {...set 
0a00: 61 72 67 73 20 5b 69 6e 66 6f 20 61 72 67 73 20  args [info args 
0a10: 24 63 6f 6d 6d 61 6e 64 5d 0a 09 09 73 65 74 20  $command]...set 
0a20: 70 72 69 6e 74 41 72 67 73 20 5b 6c 69 73 74 5d  printArgs [list]
0a30: 0a 09 09 66 6f 72 65 61 63 68 20 61 72 67 20 24  ...foreach arg $
0a40: 61 72 67 73 20 7b 0a 09 09 09 69 66 20 7b 24 61  args {....if {$a
0a50: 72 67 20 3d 3d 20 22 61 72 67 73 22 7d 20 7b 0a  rg == "args"} {.
0a60: 09 09 09 09 73 65 74 20 61 72 67 20 22 75 73 65  ....set arg "use
0a70: 72 4c 69 73 74 22 0a 09 09 09 7d 0a 09 09 09 6c  rList"....}....l
0a80: 61 70 70 65 6e 64 20 70 72 69 6e 74 41 72 67 73  append printArgs
0a90: 20 22 3c 24 61 72 67 3e 22 0a 09 09 7d 0a 0a 09   "<$arg>"...}...
0aa0: 09 70 75 74 73 20 24 63 68 61 6e 6e 65 6c 20 22  .puts $channel "
0ab0: 55 73 61 67 65 3a 20 68 75 6e 74 65 72 32 20 3c  Usage: hunter2 <
0ac0: 70 61 73 73 77 6f 72 64 46 69 6c 65 3e 20 24 63  passwordFile> $c
0ad0: 6f 6d 6d 61 6e 64 20 5b 6a 6f 69 6e 20 24 70 72  ommand [join $pr
0ae0: 69 6e 74 41 72 67 73 5d 22 0a 0a 09 09 69 66 20  intArgs]"....if 
0af0: 7b 5b 6c 6c 65 6e 67 74 68 20 24 61 72 67 73 5d  {[llength $args]
0b00: 20 3e 20 30 7d 20 7b 0a 09 09 09 70 75 74 73 20   > 0} {....puts 
0b10: 24 63 68 61 6e 6e 65 6c 20 22 22 0a 09 09 09 70  $channel ""....p
0b20: 75 74 73 20 24 63 68 61 6e 6e 65 6c 20 22 41 72  uts $channel "Ar
0b30: 67 75 6d 65 6e 74 73 3a 22 0a 09 09 09 66 6f 72  guments:"....for
0b40: 65 61 63 68 20 61 72 67 20 24 61 72 67 73 20 7b  each arg $args {
0b50: 0a 09 09 09 09 70 75 74 73 20 24 63 68 61 6e 6e  .....puts $chann
0b60: 65 6c 20 22 20 20 20 20 5b 5f 61 72 67 44 65 73  el "    [_argDes
0b70: 63 72 69 70 74 69 6f 6e 20 24 63 6f 6d 6d 61 6e  cription $comman
0b80: 64 20 24 61 72 67 5d 22 0a 09 09 09 7d 0a 09 09  d $arg]"....}...
0b90: 7d 0a 09 7d 0a 7d 0a 0a 69 66 20 7b 5b 6c 6c 65  }..}.}..if {[lle
0ba0: 6e 67 74 68 20 24 61 72 67 76 5d 20 3c 20 32 7d  ngth $argv] < 2}
0bb0: 20 7b 0a 09 5f 70 72 69 6e 74 48 65 6c 70 20 73   {.._printHelp s
0bc0: 74 64 65 72 72 20 22 22 0a 0a 09 65 78 69 74 20  tderr ""...exit 
0bd0: 31 0a 7d 0a 0a 73 65 74 20 61 72 67 76 20 5b 6c  1.}..set argv [l
0be0: 72 61 6e 67 65 20 24 61 72 67 76 20 32 20 65 6e  range $argv 2 en
0bf0: 64 5d 0a 0a 23 20 57 65 20 6e 65 65 64 20 54 63  d]..# We need Tc
0c00: 6c 20 38 2e 36 20 66 6f 72 20 5b 62 69 6e 61 72  l 8.6 for [binar
0c10: 79 20 65 6e 63 6f 64 65 20 62 61 73 65 36 34 5d  y encode base64]
0c20: 0a 70 61 63 6b 61 67 65 20 72 65 71 75 69 72 65  .package require
0c30: 20 54 63 6c 20 38 2e 36 0a 70 61 63 6b 61 67 65   Tcl 8.6.package
0c40: 20 72 65 71 75 69 72 65 20 73 71 6c 69 74 65 33   require sqlite3
0c50: 0a 70 61 63 6b 61 67 65 20 72 65 71 75 69 72 65  .package require
0c60: 20 70 6c 61 74 66 6f 72 6d 0a 0a 6c 61 70 70 65   platform..lappe
0c70: 6e 64 20 3a 3a 61 75 74 6f 5f 70 61 74 68 20 5b  nd ::auto_path [
0c80: 66 69 6c 65 20 6a 6f 69 6e 20 5b 66 69 6c 65 20  file join [file 
0c90: 64 69 72 6e 61 6d 65 20 5b 69 6e 66 6f 20 73 63  dirname [info sc
0ca0: 72 69 70 74 5d 5d 20 6c 69 62 20 5b 70 6c 61 74  ript]] lib [plat
0cb0: 66 6f 72 6d 3a 3a 69 64 65 6e 74 69 66 79 5d 5d  form::identify]]
0cc0: 0a 6c 61 70 70 65 6e 64 20 3a 3a 61 75 74 6f 5f  .lappend ::auto_
0cd0: 70 61 74 68 20 5b 66 69 6c 65 20 6a 6f 69 6e 20  path [file join 
0ce0: 5b 66 69 6c 65 20 64 69 72 6e 61 6d 65 20 5b 69  [file dirname [i
0cf0: 6e 66 6f 20 73 63 72 69 70 74 5d 5d 20 6c 69 62  nfo script]] lib
0d00: 20 5b 70 6c 61 74 66 6f 72 6d 3a 3a 67 65 6e 65   [platform::gene
0d10: 72 69 63 5d 5d 0a 6c 61 70 70 65 6e 64 20 3a 3a  ric]].lappend ::
0d20: 61 75 74 6f 5f 70 61 74 68 20 5b 66 69 6c 65 20  auto_path [file 
0d30: 6a 6f 69 6e 20 5b 66 69 6c 65 20 64 69 72 6e 61  join [file dirna
0d40: 6d 65 20 5b 69 6e 66 6f 20 73 63 72 69 70 74 5d  me [info script]
0d50: 5d 20 6c 69 62 5d 0a 0a 70 61 63 6b 61 67 65 20  ] lib]..package 
0d60: 72 65 71 75 69 72 65 20 70 6b 69 0a 70 61 63 6b  require pki.pack
0d70: 61 67 65 20 72 65 71 75 69 72 65 20 70 6b 69 3a  age require pki:
0d80: 3a 70 6b 63 73 31 31 0a 70 61 63 6b 61 67 65 20  :pkcs11.package 
0d90: 72 65 71 75 69 72 65 20 61 65 73 0a 70 61 63 6b  require aes.pack
0da0: 61 67 65 20 72 65 71 75 69 72 65 20 73 68 61 32  age require sha2
0db0: 35 36 0a 0a 23 20 42 61 63 6b 70 6f 72 74 73 20  56..# Backports 
0dc0: 66 6f 72 20 6f 6c 64 65 72 20 76 65 72 73 69 6f  for older versio
0dd0: 6e 73 20 6f 66 20 22 70 6b 69 22 0a 70 72 6f 63  ns of "pki".proc
0de0: 20 3a 3a 70 6b 69 3a 3a 70 6b 63 73 3a 3a 70 61   ::pki::pkcs::pa
0df0: 72 73 65 5f 70 75 62 6c 69 63 5f 6b 65 79 20 7b  rse_public_key {
0e00: 6b 65 79 20 7b 70 61 73 73 77 6f 72 64 20 22 22  key {password ""
0e10: 7d 7d 20 7b 0a 20 20 20 20 20 20 20 20 61 72 72  }} {.        arr
0e20: 61 79 20 73 65 74 20 70 61 72 73 65 64 5f 6b 65  ay set parsed_ke
0e30: 79 20 5b 3a 3a 70 6b 69 3a 3a 5f 70 61 72 73 65  y [::pki::_parse
0e40: 5f 70 65 6d 20 24 6b 65 79 20 22 2d 2d 2d 2d 2d  _pem $key "-----
0e50: 42 45 47 49 4e 20 50 55 42 4c 49 43 20 4b 45 59  BEGIN PUBLIC KEY
0e60: 2d 2d 2d 2d 2d 22 20 22 2d 2d 2d 2d 2d 45 4e 44  -----" "-----END
0e70: 20 50 55 42 4c 49 43 20 4b 45 59 2d 2d 2d 2d 2d   PUBLIC KEY-----
0e80: 22 20 24 70 61 73 73 77 6f 72 64 5d 0a 0a 20 20  " $password]..  
0e90: 20 20 20 20 20 20 73 65 74 20 6b 65 79 5f 73 65        set key_se
0ea0: 71 20 24 70 61 72 73 65 64 5f 6b 65 79 28 64 61  q $parsed_key(da
0eb0: 74 61 29 0a 0a 20 20 20 20 20 20 20 20 3a 3a 61  ta)..        ::a
0ec0: 73 6e 3a 3a 61 73 6e 47 65 74 53 65 71 75 65 6e  sn::asnGetSequen
0ed0: 63 65 20 6b 65 79 5f 73 65 71 20 70 75 62 6b 65  ce key_seq pubke
0ee0: 79 69 6e 66 6f 0a 20 20 20 20 20 20 20 20 20 20  yinfo.          
0ef0: 20 20 20 20 20 20 3a 3a 61 73 6e 3a 3a 61 73 6e        ::asn::asn
0f00: 47 65 74 53 65 71 75 65 6e 63 65 20 70 75 62 6b  GetSequence pubk
0f10: 65 79 69 6e 66 6f 20 70 75 62 6b 65 79 5f 61 6c  eyinfo pubkey_al
0f20: 67 6f 69 64 0a 20 20 20 20 20 20 20 20 20 20 20  goid.           
0f30: 20 20 20 20 20 20 20 20 20 20 20 20 20 3a 3a 61               ::a
0f40: 73 6e 3a 3a 61 73 6e 47 65 74 4f 62 6a 65 63 74  sn::asnGetObject
0f50: 49 64 65 6e 74 69 66 69 65 72 20 70 75 62 6b 65  Identifier pubke
0f60: 79 5f 61 6c 67 6f 69 64 20 6f 69 64 0a 20 20 20  y_algoid oid.   
0f70: 20 20 20 20 20 20 20 20 20 20 20 20 20 3a 3a 61               ::a
0f80: 73 6e 3a 3a 61 73 6e 47 65 74 42 69 74 53 74 72  sn::asnGetBitStr
0f90: 69 6e 67 20 70 75 62 6b 65 79 69 6e 66 6f 20 70  ing pubkeyinfo p
0fa0: 75 62 6b 65 79 0a 20 20 20 20 20 20 20 20 73 65  ubkey.        se
0fb0: 74 20 72 65 74 28 70 75 62 6b 65 79 5f 61 6c 67  t ret(pubkey_alg
0fc0: 6f 29 20 5b 3a 3a 70 6b 69 3a 3a 5f 6f 69 64 5f  o) [::pki::_oid_
0fd0: 6e 75 6d 62 65 72 5f 74 6f 5f 6e 61 6d 65 20 24  number_to_name $
0fe0: 6f 69 64 5d 0a 0a 20 20 20 20 20 20 20 20 73 77  oid]..        sw
0ff0: 69 74 63 68 20 2d 2d 20 24 72 65 74 28 70 75 62  itch -- $ret(pub
1000: 6b 65 79 5f 61 6c 67 6f 29 20 7b 0a 20 20 20 20  key_algo) {.    
1010: 20 20 20 20 20 20 20 20 20 20 20 20 22 72 73 61              "rsa
1020: 45 6e 63 72 79 70 74 69 6f 6e 22 20 7b 0a 20 20  Encryption" {.  
1030: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1040: 20 20 20 20 20 20 73 65 74 20 70 75 62 6b 65 79        set pubkey
1050: 20 5b 62 69 6e 61 72 79 20 66 6f 72 6d 61 74 20   [binary format 
1060: 42 2a 20 24 70 75 62 6b 65 79 5d 0a 0a 20 20 20  B* $pubkey]..   
1070: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1080: 20 20 20 20 20 3a 3a 61 73 6e 3a 3a 61 73 6e 47       ::asn::asnG
1090: 65 74 53 65 71 75 65 6e 63 65 20 70 75 62 6b 65  etSequence pubke
10a0: 79 20 70 75 62 6b 65 79 5f 70 61 72 74 73 0a 20  y pubkey_parts. 
10b0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
10c0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 3a                 :
10d0: 3a 61 73 6e 3a 3a 61 73 6e 47 65 74 42 69 67 49  :asn::asnGetBigI
10e0: 6e 74 65 67 65 72 20 70 75 62 6b 65 79 5f 70 61  nteger pubkey_pa
10f0: 72 74 73 20 72 65 74 28 6e 29 0a 20 20 20 20 20  rts ret(n).     
1100: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1110: 20 20 20 20 20 20 20 20 20 20 20 3a 3a 61 73 6e             ::asn
1120: 3a 3a 61 73 6e 47 65 74 42 69 67 49 6e 74 65 67  ::asnGetBigInteg
1130: 65 72 20 70 75 62 6b 65 79 5f 70 61 72 74 73 20  er pubkey_parts 
1140: 72 65 74 28 65 29 0a 0a 20 20 20 20 20 20 20 20  ret(e)..        
1150: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1160: 73 65 74 20 72 65 74 28 6e 29 20 5b 3a 3a 6d 61  set ret(n) [::ma
1170: 74 68 3a 3a 62 69 67 6e 75 6d 3a 3a 74 6f 73 74  th::bignum::tost
1180: 72 20 24 72 65 74 28 6e 29 5d 0a 20 20 20 20 20  r $ret(n)].     
1190: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
11a0: 20 20 20 73 65 74 20 72 65 74 28 65 29 20 5b 3a     set ret(e) [:
11b0: 3a 6d 61 74 68 3a 3a 62 69 67 6e 75 6d 3a 3a 74  :math::bignum::t
11c0: 6f 73 74 72 20 24 72 65 74 28 65 29 5d 0a 20 20  ostr $ret(e)].  
11d0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
11e0: 20 20 20 20 20 20 73 65 74 20 72 65 74 28 6c 29        set ret(l)
11f0: 20 5b 65 78 70 72 20 7b 69 6e 74 28 5b 3a 3a 70   [expr {int([::p
1200: 6b 69 3a 3a 5f 62 69 74 73 20 24 72 65 74 28 6e  ki::_bits $ret(n
1210: 29 5d 20 2f 20 38 2e 30 30 30 30 20 2b 20 30 2e  )] / 8.0000 + 0.
1220: 35 29 20 2a 20 38 7d 5d 0a 20 20 20 20 20 20 20  5) * 8}].       
1230: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1240: 20 73 65 74 20 72 65 74 28 74 79 70 65 29 20 72   set ret(type) r
1250: 73 61 0a 20 20 20 20 20 20 20 20 20 20 20 20 20  sa.             
1260: 20 20 20 7d 0a 20 20 20 20 20 20 20 20 20 20 20     }.           
1270: 20 20 20 20 20 64 65 66 61 75 6c 74 20 7b 0a 20       default {. 
1280: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1290: 20 20 20 20 20 20 20 65 72 72 6f 72 20 22 55 6e         error "Un
12a0: 6b 6e 6f 77 6e 20 61 6c 67 6f 72 69 74 68 6d 22  known algorithm"
12b0: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
12c0: 20 7d 0a 20 20 20 20 20 20 20 20 7d 0a 0a 20 20   }.        }..  
12d0: 20 20 20 20 20 20 72 65 74 75 72 6e 20 5b 61 72        return [ar
12e0: 72 61 79 20 67 65 74 20 72 65 74 5d 0a 7d 0a 0a  ray get ret].}..
12f0: 70 72 6f 63 20 3a 3a 70 6b 69 3a 3a 72 73 61 3a  proc ::pki::rsa:
1300: 3a 73 65 72 69 61 6c 69 7a 65 5f 70 75 62 6c 69  :serialize_publi
1310: 63 5f 6b 65 79 20 7b 6b 65 79 6c 69 73 74 7d 20  c_key {keylist} 
1320: 7b 0a 20 20 20 20 20 20 20 20 61 72 72 61 79 20  {.        array 
1330: 73 65 74 20 6b 65 79 20 24 6b 65 79 6c 69 73 74  set key $keylist
1340: 0a 0a 20 20 20 20 20 20 20 20 66 6f 72 65 61 63  ..        foreac
1350: 68 20 65 6e 74 72 79 20 5b 6c 69 73 74 20 6e 20  h entry [list n 
1360: 65 5d 20 7b 0a 20 20 20 20 20 20 20 20 20 20 20  e] {.           
1370: 20 20 20 20 20 69 66 20 7b 21 5b 69 6e 66 6f 20       if {![info 
1380: 65 78 69 73 74 73 20 6b 65 79 28 24 65 6e 74 72  exists key($entr
1390: 79 29 5d 7d 20 7b 0a 20 20 20 20 20 20 20 20 20  y)]} {.         
13a0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 72                 r
13b0: 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f  eturn -code erro
13c0: 72 20 22 4b 65 79 20 64 6f 65 73 20 6e 6f 74 20  r "Key does not 
13d0: 63 6f 6e 74 61 69 6e 20 61 6e 20 65 6c 65 6d 65  contain an eleme
13e0: 6e 74 20 24 65 6e 74 72 79 22 0a 20 20 20 20 20  nt $entry".     
13f0: 20 20 20 20 20 20 20 20 20 20 20 7d 0a 20 20 20             }.   
1400: 20 20 20 20 20 7d 0a 0a 20 20 20 20 20 20 20 20       }..        
1410: 73 65 74 20 70 75 62 6b 65 79 20 5b 3a 3a 61 73  set pubkey [::as
1420: 6e 3a 3a 61 73 6e 53 65 71 75 65 6e 63 65 20 5c  n::asnSequence \
1430: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
1440: 20 5b 3a 3a 61 73 6e 3a 3a 61 73 6e 42 69 67 49   [::asn::asnBigI
1450: 6e 74 65 67 65 72 20 5b 3a 3a 6d 61 74 68 3a 3a  nteger [::math::
1460: 62 69 67 6e 75 6d 3a 3a 66 72 6f 6d 73 74 72 20  bignum::fromstr 
1470: 24 6b 65 79 28 6e 29 5d 5d 20 5c 0a 20 20 20 20  $key(n)]] \.    
1480: 20 20 20 20 20 20 20 20 20 20 20 20 5b 3a 3a 61              [::a
1490: 73 6e 3a 3a 61 73 6e 42 69 67 49 6e 74 65 67 65  sn::asnBigIntege
14a0: 72 20 5b 3a 3a 6d 61 74 68 3a 3a 62 69 67 6e 75  r [::math::bignu
14b0: 6d 3a 3a 66 72 6f 6d 73 74 72 20 24 6b 65 79 28  m::fromstr $key(
14c0: 65 29 5d 5d 20 5c 0a 20 20 20 20 20 20 20 20 20  e)]] \.         
14d0: 20 20 20 20 20 20 20 5d 20 20 0a 20 20 20 20 20         ]  .     
14e0: 20 20 20 73 65 74 20 70 75 62 6b 65 79 5f 61 6c     set pubkey_al
14f0: 67 6f 5f 70 61 72 61 6d 73 20 5b 3a 3a 61 73 6e  go_params [::asn
1500: 3a 3a 61 73 6e 4e 75 6c 6c 5d 0a 0a 20 20 20 20  ::asnNull]..    
1510: 20 20 20 20 62 69 6e 61 72 79 20 73 63 61 6e 20      binary scan 
1520: 24 70 75 62 6b 65 79 20 42 2a 20 70 75 62 6b 65  $pubkey B* pubke
1530: 79 5f 62 69 74 73 74 72 69 6e 67 0a 0a 20 20 20  y_bitstring..   
1540: 20 20 20 20 20 73 65 74 20 72 65 74 20 5b 3a 3a       set ret [::
1550: 61 73 6e 3a 3a 61 73 6e 53 65 71 75 65 6e 63 65  asn::asnSequence
1560: 20 5c 0a 20 20 20 20 20 20 20 20 20 20 20 20 20   \.             
1570: 20 20 20 5b 3a 3a 61 73 6e 3a 3a 61 73 6e 53 65     [::asn::asnSe
1580: 71 75 65 6e 63 65 20 5c 0a 20 20 20 20 20 20 20  quence \.       
1590: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
15a0: 20 20 20 20 20 20 20 20 20 5b 3a 3a 61 73 6e 3a           [::asn:
15b0: 3a 61 73 6e 4f 62 6a 65 63 74 49 64 65 6e 74 69  :asnObjectIdenti
15c0: 66 69 65 72 20 5b 3a 3a 70 6b 69 3a 3a 5f 6f 69  fier [::pki::_oi
15d0: 64 5f 6e 61 6d 65 5f 74 6f 5f 6e 75 6d 62 65 72  d_name_to_number
15e0: 20 72 73 61 45 6e 63 72 79 70 74 69 6f 6e 5d 5d   rsaEncryption]]
15f0: 20 5c 0a 20 20 20 20 20 20 20 20 20 20 20 20 20   \.             
1600: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1610: 20 20 20 24 70 75 62 6b 65 79 5f 61 6c 67 6f 5f     $pubkey_algo_
1620: 70 61 72 61 6d 73 20 5c 0a 20 20 20 20 20 20 20  params \.       
1630: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1640: 20 5d 20 5c 0a 20 20 20 20 20 20 20 20 20 20 20   ] \.           
1650: 20 20 20 20 20 20 20 20 20 20 20 20 20 5b 3a 3a               [::
1660: 61 73 6e 3a 3a 61 73 6e 42 69 74 53 74 72 69 6e  asn::asnBitStrin
1670: 67 20 24 70 75 62 6b 65 79 5f 62 69 74 73 74 72  g $pubkey_bitstr
1680: 69 6e 67 5d 20 5c 0a 20 20 20 20 20 20 20 20 20  ing] \.         
1690: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 5d                 ]
16a0: 0a 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e  ..        return
16b0: 20 5b 6c 69 73 74 20 64 61 74 61 20 24 72 65 74   [list data $ret
16c0: 20 62 65 67 69 6e 20 22 2d 2d 2d 2d 2d 42 45 47   begin "-----BEG
16d0: 49 4e 20 50 55 42 4c 49 43 20 4b 45 59 2d 2d 2d  IN PUBLIC KEY---
16e0: 2d 2d 22 20 65 6e 64 20 22 2d 2d 2d 2d 2d 45 4e  --" end "-----EN
16f0: 44 20 50 55 42 4c 49 43 20 4b 45 59 2d 2d 2d 2d  D PUBLIC KEY----
1700: 2d 22 5d 0a 7d 0a 23 20 45 6e 64 20 62 61 63 6b  -"].}.# End back
1710: 70 6f 72 74 73 0a 0a 23 20 53 74 61 72 74 20 69  ports..# Start i
1720: 6e 74 65 72 6e 61 6c 20 66 75 6e 63 74 69 6f 6e  nternal function
1730: 73 0a 70 72 6f 63 20 5f 6c 6f 61 64 44 42 20 7b  s.proc _loadDB {
1740: 64 62 43 6d 64 20 66 69 6c 65 4e 61 6d 65 7d 20  dbCmd fileName} 
1750: 7b 0a 09 73 65 74 20 3a 3a 73 61 76 65 52 65 71  {..set ::saveReq
1760: 75 69 72 65 64 20 31 0a 0a 09 69 66 20 7b 5b 66  uired 1...if {[f
1770: 69 6c 65 20 65 78 69 73 74 73 20 24 66 69 6c 65  ile exists $file
1780: 4e 61 6d 65 5d 7d 20 7b 0a 09 09 73 65 74 20 66  Name]} {...set f
1790: 64 20 5b 6f 70 65 6e 20 24 66 69 6c 65 4e 61 6d  d [open $fileNam
17a0: 65 5d 0a 0a 09 09 23 20 56 65 72 69 66 79 20 74  e]....# Verify t
17b0: 68 61 74 20 77 65 20 68 61 76 65 20 61 20 76 61  hat we have a va
17c0: 6c 69 64 20 66 69 6c 65 0a 09 09 67 65 74 73 20  lid file...gets 
17d0: 24 66 64 20 68 65 61 64 65 72 0a 0a 09 09 23 20  $fd header....# 
17e0: 49 67 6e 6f 72 65 20 74 68 65 20 66 69 72 73 74  Ignore the first
17f0: 20 6c 69 6e 65 20 69 66 20 69 74 20 69 73 20 61   line if it is a
1800: 20 68 61 73 68 2d 62 61 6e 67 20 61 73 20 77 65   hash-bang as we
1810: 6c 6c 0a 09 09 69 66 20 7b 5b 73 74 72 69 6e 67  ll...if {[string
1820: 20 72 61 6e 67 65 20 24 68 65 61 64 65 72 20 30   range $header 0
1830: 20 31 5d 20 3d 3d 20 22 23 21 22 7d 20 7b 0a 09   1] == "#!"} {..
1840: 09 09 73 65 74 20 3a 3a 67 6c 6f 62 61 6c 48 65  ..set ::globalHe
1850: 61 64 65 72 28 24 64 62 43 6d 64 29 20 24 68 65  ader($dbCmd) $he
1860: 61 64 65 72 0a 0a 09 09 09 67 65 74 73 20 24 66  ader.....gets $f
1870: 64 20 68 65 61 64 65 72 0a 09 09 7d 0a 0a 09 09  d header...}....
1880: 69 66 20 7b 24 68 65 61 64 65 72 20 6e 65 20 22  if {$header ne "
1890: 23 20 3c 41 7a 75 72 65 44 69 61 6d 6f 6e 64 3e  # <AzureDiamond>
18a0: 20 6f 68 2c 20 6f 6b 2e 22 7d 20 7b 0a 09 09 09   oh, ok."} {....
18b0: 23 20 54 68 69 73 20 6d 61 79 20 62 65 20 61 6e  # This may be an
18c0: 20 6f 6c 64 20 53 51 4c 69 74 65 33 20 44 42 2c   old SQLite3 DB,
18d0: 20 63 6f 6e 76 65 72 74 20 69 74 0a 09 09 09 63   convert it....c
18e0: 6c 6f 73 65 20 24 66 64 0a 0a 09 09 09 73 71 6c  lose $fd.....sql
18f0: 69 74 65 33 20 24 64 62 43 6d 64 20 24 66 69 6c  ite3 $dbCmd $fil
1900: 65 4e 61 6d 65 0a 0a 09 09 09 5f 73 61 76 65 44  eName....._saveD
1910: 42 20 24 64 62 43 6d 64 20 24 66 69 6c 65 4e 61  B $dbCmd $fileNa
1920: 6d 65 0a 0a 09 09 09 24 64 62 43 6d 64 20 63 6c  me.....$dbCmd cl
1930: 6f 73 65 0a 0a 09 09 09 72 65 74 75 72 6e 20 5b  ose.....return [
1940: 5f 6c 6f 61 64 44 42 20 24 64 62 43 6d 64 20 24  _loadDB $dbCmd $
1950: 66 69 6c 65 4e 61 6d 65 5d 0a 09 09 7d 0a 0a 09  fileName]...}...
1960: 09 73 65 74 20 64 61 74 61 20 5b 72 65 61 64 20  .set data [read 
1970: 24 66 64 5d 0a 0a 09 09 63 6c 6f 73 65 20 24 66  $fd]....close $f
1980: 64 0a 09 7d 20 65 6c 73 65 20 7b 0a 09 09 73 65  d..} else {...se
1990: 74 20 64 61 74 61 20 22 22 0a 09 7d 0a 0a 09 73  t data ""..}...s
19a0: 71 6c 69 74 65 33 20 24 64 62 43 6d 64 20 22 3a  qlite3 $dbCmd ":
19b0: 6d 65 6d 6f 72 79 3a 22 0a 0a 09 24 64 62 43 6d  memory:"...$dbCm
19c0: 64 20 65 76 61 6c 20 7b 0a 09 09 43 52 45 41 54  d eval {...CREAT
19d0: 45 20 54 41 42 4c 45 20 49 46 20 4e 4f 54 20 45  E TABLE IF NOT E
19e0: 58 49 53 54 53 20 75 73 65 72 73 28 6e 61 6d 65  XISTS users(name
19f0: 2c 20 70 75 62 6c 69 63 4b 65 79 20 42 4c 4f 42  , publicKey BLOB
1a00: 29 3b 0a 09 09 43 52 45 41 54 45 20 54 41 42 4c  );...CREATE TABL
1a10: 45 20 49 46 20 4e 4f 54 20 45 58 49 53 54 53 20  E IF NOT EXISTS 
1a20: 70 61 73 73 77 6f 72 64 73 28 6e 61 6d 65 2c 20  passwords(name, 
1a30: 65 6e 63 72 79 70 74 65 64 50 61 73 73 20 42 4c  encryptedPass BL
1a40: 4f 42 2c 20 65 6e 63 72 79 70 74 65 64 4b 65 79  OB, encryptedKey
1a50: 20 42 4c 4f 42 2c 20 70 75 62 6c 69 63 4b 65 79   BLOB, publicKey
1a60: 20 42 4c 4f 42 2c 20 76 65 72 69 66 69 63 61 74   BLOB, verificat
1a70: 69 6f 6e 20 42 4c 4f 42 29 3b 0a 09 7d 0a 0a 09  ion BLOB);..}...
1a80: 24 64 62 43 6d 64 20 74 72 61 6e 73 61 63 74 69  $dbCmd transacti
1a90: 6f 6e 20 7b 0a 09 09 66 6f 72 65 61 63 68 20 6c  on {...foreach l
1aa0: 69 6e 65 20 5b 73 70 6c 69 74 20 24 64 61 74 61  ine [split $data
1ab0: 20 22 5c 6e 22 5d 20 7b 0a 09 09 09 69 66 20 7b   "\n"] {....if {
1ac0: 5b 73 74 72 69 6e 67 20 74 72 69 6d 20 24 6c 69  [string trim $li
1ad0: 6e 65 5d 20 65 71 20 22 22 7d 20 7b 0a 09 09 09  ne] eq ""} {....
1ae0: 09 63 6f 6e 74 69 6e 75 65 0a 09 09 09 7d 0a 0a  .continue....}..
1af0: 09 09 09 73 65 74 20 74 61 62 6c 65 20 5b 6c 69  ...set table [li
1b00: 6e 64 65 78 20 24 6c 69 6e 65 20 30 5d 0a 09 09  ndex $line 0]...
1b10: 09 73 65 74 20 6c 69 6e 65 20 5b 6c 72 61 6e 67  .set line [lrang
1b20: 65 20 24 6c 69 6e 65 20 31 20 65 6e 64 5d 0a 0a  e $line 1 end]..
1b30: 09 09 09 73 65 74 20 6b 65 79 73 20 5b 6c 69 73  ...set keys [lis
1b40: 74 5d 0a 09 09 09 73 65 74 20 76 61 6c 75 65 73  t]....set values
1b50: 20 5b 6c 69 73 74 5d 0a 09 09 09 75 6e 73 65 74   [list]....unset
1b60: 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e 20 76 61 6c   -nocomplain val
1b70: 75 65 41 72 72 61 79 0a 0a 09 09 09 66 6f 72 65  ueArray.....fore
1b80: 61 63 68 20 7b 6b 65 79 20 76 61 6c 75 65 7d 20  ach {key value} 
1b90: 24 6c 69 6e 65 20 7b 0a 09 09 09 09 69 66 20 7b  $line {.....if {
1ba0: 5b 73 74 72 69 6e 67 20 69 6e 64 65 78 20 24 6b  [string index $k
1bb0: 65 79 20 30 5d 20 3d 3d 20 22 3a 22 7d 20 7b 0a  ey 0] == ":"} {.
1bc0: 09 09 09 09 09 73 65 74 20 6b 65 79 20 5b 73 74  .....set key [st
1bd0: 72 69 6e 67 20 72 61 6e 67 65 20 24 6b 65 79 20  ring range $key 
1be0: 31 20 65 6e 64 5d 0a 09 09 09 09 09 73 65 74 20  1 end]......set 
1bf0: 76 61 6c 75 65 42 61 73 65 36 34 45 6e 63 6f 64  valueBase64Encod
1c00: 65 64 20 31 0a 09 09 09 09 7d 20 65 6c 73 65 20  ed 1.....} else 
1c10: 7b 0a 09 09 09 09 09 73 65 74 20 76 61 6c 75 65  {......set value
1c20: 42 61 73 65 36 34 45 6e 63 6f 64 65 64 20 30 0a  Base64Encoded 0.
1c30: 09 09 09 09 7d 0a 0a 09 09 09 09 69 66 20 7b 24  ....}......if {$
1c40: 76 61 6c 75 65 42 61 73 65 36 34 45 6e 63 6f 64  valueBase64Encod
1c50: 65 64 7d 20 7b 0a 09 09 09 09 09 73 65 74 20 76  ed} {......set v
1c60: 61 6c 75 65 20 5b 62 69 6e 61 72 79 20 64 65 63  alue [binary dec
1c70: 6f 64 65 20 62 61 73 65 36 34 20 24 76 61 6c 75  ode base64 $valu
1c80: 65 5d 0a 09 09 09 09 7d 0a 0a 09 09 09 09 69 66  e].....}......if
1c90: 20 7b 21 5b 72 65 67 65 78 70 20 7b 5e 5b 61 2d   {![regexp {^[a-
1ca0: 7a 41 2d 5a 5d 2b 24 7d 20 24 6b 65 79 5d 7d 20  zA-Z]+$} $key]} 
1cb0: 7b 0a 09 09 09 09 09 72 65 74 75 72 6e 20 2d 63  {......return -c
1cc0: 6f 64 65 20 65 72 72 6f 72 20 22 49 6e 76 61 6c  ode error "Inval
1cd0: 69 64 20 6b 65 79 20 6e 61 6d 65 3a 20 24 6b 65  id key name: $ke
1ce0: 79 22 0a 09 09 09 09 7d 0a 0a 09 09 09 09 73 77  y".....}......sw
1cf0: 69 74 63 68 20 2d 2d 20 24 6b 65 79 20 7b 0a 09  itch -- $key {..
1d00: 09 09 09 09 22 6e 61 6d 65 22 20 7b 0a 09 09 09  ...."name" {....
1d10: 09 09 09 73 65 74 20 74 79 70 65 20 22 22 0a 09  ...set type ""..
1d20: 09 09 09 09 09 73 65 74 20 74 79 70 65 49 6e 73  .....set typeIns
1d30: 65 72 74 43 68 61 72 20 7b 24 7d 0a 0a 09 09 09  ertChar {$}.....
1d40: 09 09 09 23 20 43 6f 6e 76 65 72 74 20 74 68 69  ...# Convert thi
1d50: 73 20 74 6f 20 61 20 73 74 72 69 6e 67 2d 69 66  s to a string-if
1d60: 69 65 64 20 76 61 6c 75 65 0a 09 09 09 09 09 09  ied value.......
1d70: 73 65 74 20 76 61 6c 75 65 20 5b 73 74 72 69 6e  set value [strin
1d80: 67 20 72 61 6e 67 65 20 22 78 24 76 61 6c 75 65  g range "x$value
1d90: 22 20 31 20 65 6e 64 5d 0a 09 09 09 09 09 7d 0a  " 1 end]......}.
1da0: 09 09 09 09 09 64 65 66 61 75 6c 74 20 7b 0a 09  .....default {..
1db0: 09 09 09 09 09 73 65 74 20 74 79 70 65 20 22 42  .....set type "B
1dc0: 4c 4f 42 22 0a 09 09 09 09 09 09 73 65 74 20 74  LOB".......set t
1dd0: 79 70 65 49 6e 73 65 72 74 43 68 61 72 20 22 40  ypeInsertChar "@
1de0: 22 0a 09 09 09 09 09 7d 0a 09 09 09 09 7d 0a 0a  "......}.....}..
1df0: 09 09 09 09 6c 61 70 70 65 6e 64 20 6b 65 79 73  ....lappend keys
1e00: 20 24 6b 65 79 0a 0a 09 09 09 09 73 65 74 20 76   $key......set v
1e10: 61 6c 75 65 41 72 72 61 79 28 24 6b 65 79 29 20  alueArray($key) 
1e20: 24 76 61 6c 75 65 0a 0a 09 09 09 09 6c 61 70 70  $value......lapp
1e30: 65 6e 64 20 76 61 6c 75 65 73 20 24 7b 74 79 70  end values ${typ
1e40: 65 49 6e 73 65 72 74 43 68 61 72 7d 76 61 6c 75  eInsertChar}valu
1e50: 65 41 72 72 61 79 28 24 6b 65 79 29 0a 09 09 09  eArray($key)....
1e60: 7d 0a 0a 09 09 09 24 64 62 43 6d 64 20 65 76 61  }.....$dbCmd eva
1e70: 6c 20 22 49 4e 53 45 52 54 20 49 4e 54 4f 20 24  l "INSERT INTO $
1e80: 74 61 62 6c 65 20 28 5b 6a 6f 69 6e 20 24 6b 65  table ([join $ke
1e90: 79 73 20 7b 2c 20 7d 5d 29 20 56 41 4c 55 45 53  ys {, }]) VALUES
1ea0: 20 28 5b 6a 6f 69 6e 20 24 76 61 6c 75 65 73 20   ([join $values 
1eb0: 7b 2c 20 7d 5d 29 3b 22 0a 09 09 7d 0a 09 7d 0a  {, }]);"...}..}.
1ec0: 7d 0a 0a 70 72 6f 63 20 5f 73 61 76 65 44 42 20  }..proc _saveDB 
1ed0: 7b 64 62 43 6d 64 20 66 69 6c 65 4e 61 6d 65 7d  {dbCmd fileName}
1ee0: 20 7b 0a 09 69 66 20 7b 5b 69 6e 66 6f 20 65 78   {..if {[info ex
1ef0: 69 73 74 73 20 3a 3a 67 6c 6f 62 61 6c 48 65 61  ists ::globalHea
1f00: 64 65 72 28 24 64 62 43 6d 64 29 5d 7d 20 7b 0a  der($dbCmd)]} {.
1f10: 09 09 6c 61 70 70 65 6e 64 20 6f 75 74 70 75 74  ..lappend output
1f20: 20 24 3a 3a 67 6c 6f 62 61 6c 48 65 61 64 65 72   $::globalHeader
1f30: 28 24 64 62 43 6d 64 29 0a 0a 09 09 75 6e 73 65  ($dbCmd)....unse
1f40: 74 20 3a 3a 67 6c 6f 62 61 6c 48 65 61 64 65 72  t ::globalHeader
1f50: 28 24 64 62 43 6d 64 29 0a 09 7d 0a 0a 09 6c 61  ($dbCmd)..}...la
1f60: 70 70 65 6e 64 20 6f 75 74 70 75 74 20 22 23 20  ppend output "# 
1f70: 3c 41 7a 75 72 65 44 69 61 6d 6f 6e 64 3e 20 6f  <AzureDiamond> o
1f80: 68 2c 20 6f 6b 2e 22 0a 0a 09 66 6f 72 65 61 63  h, ok."...foreac
1f90: 68 20 74 61 62 6c 65 20 5b 6c 69 73 74 20 75 73  h table [list us
1fa0: 65 72 73 20 70 61 73 73 77 6f 72 64 73 5d 20 7b  ers passwords] {
1fb0: 0a 09 09 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70  ...unset -nocomp
1fc0: 6c 61 69 6e 20 72 6f 77 0a 09 09 24 64 62 43 6d  lain row...$dbCm
1fd0: 64 20 65 76 61 6c 20 22 53 45 4c 45 43 54 20 2a  d eval "SELECT *
1fe0: 20 46 52 4f 4d 20 24 74 61 62 6c 65 20 4f 52 44   FROM $table ORD
1ff0: 45 52 20 42 59 20 6e 61 6d 65 3b 22 20 72 6f 77  ER BY name;" row
2000: 20 7b 0a 09 09 09 73 65 74 20 6f 75 74 70 75 74   {....set output
2010: 4c 69 6e 65 20 5b 6c 69 73 74 20 24 74 61 62 6c  Line [list $tabl
2020: 65 5d 0a 0a 09 09 09 75 6e 73 65 74 20 2d 6e 6f  e].....unset -no
2030: 63 6f 6d 70 6c 61 69 6e 20 72 6f 77 28 2a 29 0a  complain row(*).
2040: 0a 09 09 09 66 6f 72 65 61 63 68 20 7b 6b 65 79  ....foreach {key
2050: 20 76 61 6c 75 65 7d 20 5b 61 72 72 61 79 20 67   value} [array g
2060: 65 74 20 72 6f 77 5d 20 7b 0a 09 09 09 09 69 66  et row] {.....if
2070: 20 7b 21 5b 72 65 67 65 78 70 20 7b 5e 5b 61 2d   {![regexp {^[a-
2080: 7a 41 2d 5a 5d 2b 24 7d 20 24 76 61 6c 75 65 5d  zA-Z]+$} $value]
2090: 7d 20 7b 0a 09 09 09 09 09 73 65 74 20 6b 65 79  } {......set key
20a0: 20 22 3a 24 6b 65 79 22 0a 09 09 09 09 09 73 65   ":$key"......se
20b0: 74 20 76 61 6c 75 65 20 5b 62 69 6e 61 72 79 20  t value [binary 
20c0: 65 6e 63 6f 64 65 20 62 61 73 65 36 34 20 24 76  encode base64 $v
20d0: 61 6c 75 65 5d 0a 09 09 09 09 7d 0a 0a 09 09 09  alue].....}.....
20e0: 09 6c 61 70 70 65 6e 64 20 6f 75 74 70 75 74 4c  .lappend outputL
20f0: 69 6e 65 20 24 6b 65 79 20 24 76 61 6c 75 65 0a  ine $key $value.
2100: 09 09 09 7d 0a 0a 09 09 09 6c 61 70 70 65 6e 64  ...}.....lappend
2110: 20 6f 75 74 70 75 74 20 24 6f 75 74 70 75 74 4c   output $outputL
2120: 69 6e 65 0a 09 09 7d 0a 09 7d 0a 0a 09 73 65 74  ine...}..}...set
2130: 20 66 64 20 5b 6f 70 65 6e 20 24 66 69 6c 65 4e   fd [open $fileN
2140: 61 6d 65 20 77 20 30 36 30 30 5d 0a 09 70 75 74  ame w 0600]..put
2150: 73 20 24 66 64 20 5b 6a 6f 69 6e 20 24 6f 75 74  s $fd [join $out
2160: 70 75 74 20 22 5c 6e 22 5d 0a 09 63 6c 6f 73 65  put "\n"]..close
2170: 20 24 66 64 0a 7d 0a 0a 70 72 6f 63 20 5f 6c 69   $fd.}..proc _li
2180: 73 74 43 65 72 74 69 66 69 63 61 74 65 73 20 7b  stCertificates {
2190: 7d 20 7b 0a 09 69 66 20 7b 21 5b 69 6e 66 6f 20  } {..if {![info 
21a0: 65 78 69 73 74 73 20 3a 3a 65 6e 76 28 50 4b 43  exists ::env(PKC
21b0: 53 31 31 4d 4f 44 55 4c 45 29 5d 7d 20 7b 0a 09  S11MODULE)]} {..
21c0: 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72  .return -code er
21d0: 72 6f 72 20 22 45 52 52 4f 52 3a 20 50 4b 43 53  ror "ERROR: PKCS
21e0: 31 31 4d 4f 44 55 4c 45 20 65 6e 76 69 72 6f 6e  11MODULE environ
21f0: 6d 65 6e 74 20 76 61 72 69 61 62 6c 65 20 69 73  ment variable is
2200: 20 6e 6f 74 20 73 65 74 20 74 6f 20 79 6f 75 72   not set to your
2210: 20 50 4b 43 53 31 31 20 6d 6f 64 75 6c 65 22 0a   PKCS11 module".
2220: 09 7d 0a 0a 09 23 20 48 61 72 64 63 6f 64 65 20  .}...# Hardcode 
2230: 73 6f 6d 65 20 50 4b 43 53 31 31 20 6d 6f 64 75  some PKCS11 modu
2240: 6c 65 20 77 6f 72 6b 61 72 6f 75 6e 64 73 0a 09  le workarounds..
2250: 73 65 74 20 3a 3a 65 6e 76 28 43 41 43 4b 45 59  set ::env(CACKEY
2260: 5f 4e 4f 5f 45 58 54 52 41 5f 43 45 52 54 53 29  _NO_EXTRA_CERTS)
2270: 20 31 0a 0a 09 73 65 74 20 68 61 6e 64 6c 65 20   1...set handle 
2280: 5b 3a 3a 70 6b 69 3a 3a 70 6b 63 73 31 31 3a 3a  [::pki::pkcs11::
2290: 6c 6f 61 64 6d 6f 64 75 6c 65 20 24 3a 3a 65 6e  loadmodule $::en
22a0: 76 28 50 4b 43 53 31 31 4d 4f 44 55 4c 45 29 5d  v(PKCS11MODULE)]
22b0: 0a 0a 09 73 65 74 20 73 6c 6f 74 49 6e 66 6f 20  ...set slotInfo 
22c0: 5b 6c 69 73 74 5d 0a 09 66 6f 72 65 61 63 68 20  [list]..foreach 
22d0: 73 6c 6f 74 20 5b 3a 3a 70 6b 69 3a 3a 70 6b 63  slot [::pki::pkc
22e0: 73 31 31 3a 3a 6c 69 73 74 73 6c 6f 74 73 20 24  s11::listslots $
22f0: 68 61 6e 64 6c 65 5d 20 7b 0a 09 09 73 65 74 20  handle] {...set 
2300: 73 6c 6f 74 49 44 20 5b 6c 69 6e 64 65 78 20 24  slotID [lindex $
2310: 73 6c 6f 74 20 30 5d 0a 09 09 73 65 74 20 73 6c  slot 0]...set sl
2320: 6f 74 4c 61 62 65 6c 20 5b 6c 69 6e 64 65 78 20  otLabel [lindex 
2330: 24 73 6c 6f 74 20 31 5d 0a 09 09 73 65 74 20 73  $slot 1]...set s
2340: 6c 6f 74 46 6c 61 67 73 20 5b 6c 69 6e 64 65 78  lotFlags [lindex
2350: 20 24 73 6c 6f 74 20 32 5d 0a 0a 09 09 69 66 20   $slot 2]....if 
2360: 7b 22 54 4f 4b 45 4e 5f 50 52 45 53 45 4e 54 22  {"TOKEN_PRESENT"
2370: 20 6e 69 20 24 73 6c 6f 74 46 6c 61 67 73 7d 20   ni $slotFlags} 
2380: 7b 0a 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09  {....continue...
2390: 7d 0a 0a 09 09 69 66 20 7b 22 54 4f 4b 45 4e 5f  }....if {"TOKEN_
23a0: 49 4e 49 54 49 41 4c 49 5a 45 44 22 20 6e 69 20  INITIALIZED" ni 
23b0: 24 73 6c 6f 74 46 6c 61 67 73 7d 20 7b 0a 09 09  $slotFlags} {...
23c0: 09 63 6f 6e 74 69 6e 75 65 0a 09 09 7d 0a 0a 09  .continue...}...
23d0: 09 73 65 74 20 73 6c 6f 74 50 72 6f 6d 70 74 46  .set slotPromptF
23e0: 6f 72 50 49 4e 20 66 61 6c 73 65 0a 09 09 69 66  orPIN false...if
23f0: 20 7b 22 50 52 4f 54 45 43 54 45 44 5f 41 55 54   {"PROTECTED_AUT
2400: 48 45 4e 54 49 43 41 54 49 4f 4e 5f 50 41 54 48  HENTICATION_PATH
2410: 22 20 6e 69 20 24 73 6c 6f 74 46 6c 61 67 73 7d  " ni $slotFlags}
2420: 20 7b 0a 09 09 09 69 66 20 7b 22 4c 4f 47 49 4e   {....if {"LOGIN
2430: 5f 52 45 51 55 49 52 45 44 22 20 69 6e 20 24 73  _REQUIRED" in $s
2440: 6c 6f 74 46 6c 61 67 73 7d 20 7b 0a 09 09 09 09  lotFlags} {.....
2450: 73 65 74 20 73 6c 6f 74 50 72 6f 6d 70 74 46 6f  set slotPromptFo
2460: 72 50 49 4e 20 74 72 75 65 0a 09 09 09 7d 0a 09  rPIN true....}..
2470: 09 7d 0a 0a 09 09 66 6f 72 65 61 63 68 20 63 65  .}....foreach ce
2480: 72 74 20 5b 3a 3a 70 6b 69 3a 3a 70 6b 63 73 31  rt [::pki::pkcs1
2490: 31 3a 3a 6c 69 73 74 63 65 72 74 73 20 24 68 61  1::listcerts $ha
24a0: 6e 64 6c 65 20 24 73 6c 6f 74 49 44 5d 20 7b 0a  ndle $slotID] {.
24b0: 09 09 09 73 65 74 20 70 75 62 6b 65 79 20 5b 62  ...set pubkey [b
24c0: 69 6e 61 72 79 20 65 6e 63 6f 64 65 20 62 61 73  inary encode bas
24d0: 65 36 34 20 5b 64 69 63 74 20 67 65 74 20 5b 3a  e64 [dict get [:
24e0: 3a 70 6b 69 3a 3a 72 73 61 3a 3a 73 65 72 69 61  :pki::rsa::seria
24f0: 6c 69 7a 65 5f 70 75 62 6c 69 63 5f 6b 65 79 20  lize_public_key 
2500: 24 63 65 72 74 5d 20 64 61 74 61 5d 5d 0a 0a 09  $cert] data]]...
2510: 09 09 6c 61 70 70 65 6e 64 20 73 6c 6f 74 49 6e  ..lappend slotIn
2520: 66 6f 20 5b 6c 69 73 74 20 68 61 6e 64 6c 65 20  fo [list handle 
2530: 24 68 61 6e 64 6c 65 20 69 64 20 24 73 6c 6f 74  $handle id $slot
2540: 49 44 20 70 72 6f 6d 70 74 20 24 73 6c 6f 74 50  ID prompt $slotP
2550: 72 6f 6d 70 74 46 6f 72 50 49 4e 20 63 65 72 74  romptForPIN cert
2560: 20 24 63 65 72 74 20 70 75 62 6b 65 79 20 24 70   $cert pubkey $p
2570: 75 62 6b 65 79 5d 0a 09 09 7d 0a 09 7d 0a 0a 09  ubkey]...}..}...
2580: 72 65 74 75 72 6e 20 24 73 6c 6f 74 49 6e 66 6f  return $slotInfo
2590: 0a 7d 0a 0a 70 72 6f 63 20 5f 76 65 72 69 66 79  .}..proc _verify
25a0: 50 61 73 73 77 6f 72 64 20 7b 6e 61 6d 65 20 70  Password {name p
25b0: 61 73 73 77 6f 72 64 7d 20 7b 0a 09 73 65 74 20  assword} {..set 
25c0: 70 75 62 6c 69 63 4b 65 79 73 20 5b 6c 69 73 74  publicKeys [list
25d0: 5d 0a 0a 09 64 62 20 65 76 61 6c 20 7b 53 45 4c  ]...db eval {SEL
25e0: 45 43 54 20 70 75 62 6c 69 63 4b 65 79 2c 20 76  ECT publicKey, v
25f0: 65 72 69 66 69 63 61 74 69 6f 6e 20 46 52 4f 4d  erification FROM
2600: 20 70 61 73 73 77 6f 72 64 73 20 57 48 45 52 45   passwords WHERE
2610: 20 6e 61 6d 65 20 3d 20 24 6e 61 6d 65 7d 20 72   name = $name} r
2620: 6f 77 20 7b 0a 09 09 73 65 74 20 73 61 6c 74 20  ow {...set salt 
2630: 5b 64 69 63 74 20 67 65 74 20 24 72 6f 77 28 76  [dict get $row(v
2640: 65 72 69 66 69 63 61 74 69 6f 6e 29 20 73 61 6c  erification) sal
2650: 74 5d 0a 09 09 73 65 74 20 68 61 73 68 41 6c 67  t]...set hashAlg
2660: 6f 72 69 74 68 6d 20 5b 64 69 63 74 20 67 65 74  orithm [dict get
2670: 20 24 72 6f 77 28 76 65 72 69 66 69 63 61 74 69   $row(verificati
2680: 6f 6e 29 20 68 61 73 68 41 6c 67 6f 72 69 74 68  on) hashAlgorith
2690: 6d 5d 0a 09 09 73 65 74 20 70 75 62 6c 69 63 4b  m]...set publicK
26a0: 65 79 20 24 72 6f 77 28 70 75 62 6c 69 63 4b 65  ey $row(publicKe
26b0: 79 29 0a 0a 09 09 73 65 74 20 70 6c 61 69 6e 74  y)....set plaint
26c0: 65 78 74 20 22 24 7b 73 61 6c 74 7d 7c 24 7b 70  ext "${salt}|${p
26d0: 75 62 6c 69 63 4b 65 79 7d 7c 24 7b 70 61 73 73  ublicKey}|${pass
26e0: 77 6f 72 64 7d 22 0a 0a 09 09 73 77 69 74 63 68  word}"....switch
26f0: 20 2d 2d 20 24 68 61 73 68 41 6c 67 6f 72 69 74   -- $hashAlgorit
2700: 68 6d 20 7b 0a 09 09 09 22 73 68 61 32 35 36 22  hm {...."sha256"
2710: 20 7b 0a 09 09 09 09 73 65 74 20 76 65 72 69 66   {.....set verif
2720: 69 63 61 74 69 6f 6e 48 61 73 68 20 5b 73 68 61  icationHash [sha
2730: 32 3a 3a 73 68 61 32 35 36 20 2d 68 65 78 20 2d  2::sha256 -hex -
2740: 2d 20 24 70 6c 61 69 6e 74 65 78 74 5d 0a 09 09  - $plaintext]...
2750: 09 7d 0a 09 09 09 64 65 66 61 75 6c 74 20 7b 0a  .}....default {.
2760: 09 09 09 09 72 65 74 75 72 6e 20 2d 63 6f 64 65  ....return -code
2770: 20 65 72 72 6f 72 20 22 55 6e 6b 6e 6f 77 6e 20   error "Unknown 
2780: 68 61 73 68 69 6e 67 20 61 6c 67 6f 72 69 74 68  hashing algorith
2790: 6d 3a 20 24 68 61 73 68 41 6c 67 6f 72 69 74 68  m: $hashAlgorith
27a0: 6d 22 0a 09 09 09 7d 0a 09 09 7d 0a 0a 09 09 73  m"....}...}....s
27b0: 65 74 20 72 6f 77 28 76 65 72 69 66 69 63 61 74  et row(verificat
27c0: 69 6f 6e 48 61 73 68 29 20 5b 64 69 63 74 20 67  ionHash) [dict g
27d0: 65 74 20 24 72 6f 77 28 76 65 72 69 66 69 63 61  et $row(verifica
27e0: 74 69 6f 6e 29 20 68 61 73 68 5d 0a 0a 09 09 69  tion) hash]....i
27f0: 66 20 7b 24 76 65 72 69 66 69 63 61 74 69 6f 6e  f {$verification
2800: 48 61 73 68 20 6e 65 20 24 72 6f 77 28 76 65 72  Hash ne $row(ver
2810: 69 66 69 63 61 74 69 6f 6e 48 61 73 68 29 7d 20  ificationHash)} 
2820: 7b 0a 09 09 09 72 65 74 75 72 6e 20 2d 63 6f 64  {....return -cod
2830: 65 20 65 72 72 6f 72 20 22 46 41 49 4c 45 44 3a  e error "FAILED:
2840: 20 76 65 72 69 66 69 63 61 74 69 6f 6e 20 66 61   verification fa
2850: 69 6c 65 64 20 66 6f 72 20 24 6e 61 6d 65 20 77  iled for $name w
2860: 69 74 68 20 70 75 62 6c 69 63 20 6b 65 79 20 24  ith public key $
2870: 70 75 62 6c 69 63 4b 65 79 20 2d 2d 20 69 74 20  publicKey -- it 
2880: 77 69 6c 6c 20 6e 6f 74 20 67 65 74 20 74 68 65  will not get the
2890: 20 6e 65 77 20 70 61 73 73 77 6f 72 64 2e 22 0a   new password.".
28a0: 0a 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09 7d  ....continue...}
28b0: 0a 0a 09 09 6c 61 70 70 65 6e 64 20 70 75 62 6c  ....lappend publ
28c0: 69 63 4b 65 79 73 20 24 70 75 62 6c 69 63 4b 65  icKeys $publicKe
28d0: 79 0a 09 7d 0a 0a 09 72 65 74 75 72 6e 20 24 70  y..}...return $p
28e0: 75 62 6c 69 63 4b 65 79 73 0a 7d 0a 0a 70 72 6f  ublicKeys.}..pro
28f0: 63 20 5f 61 64 64 50 61 73 73 77 6f 72 64 20 7b  c _addPassword {
2900: 6e 61 6d 65 20 70 61 73 73 77 6f 72 64 20 70 75  name password pu
2910: 62 6c 69 63 4b 65 79 73 7d 20 7b 0a 09 73 65 74  blicKeys} {..set
2920: 20 66 64 20 5b 6f 70 65 6e 20 22 2f 64 65 76 2f   fd [open "/dev/
2930: 75 72 61 6e 64 6f 6d 22 20 72 5d 0a 09 66 63 6f  urandom" r]..fco
2940: 6e 66 69 67 75 72 65 20 24 66 64 20 2d 74 72 61  nfigure $fd -tra
2950: 6e 73 6c 61 74 69 6f 6e 20 62 69 6e 61 72 79 0a  nslation binary.
2960: 0a 09 73 65 74 20 6b 65 79 53 69 7a 65 20 31 36  ..set keySize 16
2970: 0a 0a 09 23 20 50 61 64 20 74 68 65 20 70 61 73  ...# Pad the pas
2980: 73 77 6f 72 64 20 77 69 74 68 20 30 20 62 79 74  sword with 0 byt
2990: 65 73 20 75 6e 74 69 6c 20 69 74 20 69 73 20 61  es until it is a
29a0: 20 6d 75 6c 74 69 70 6c 65 20 6f 66 20 74 68 65   multiple of the
29b0: 20 6b 65 79 20 73 69 7a 65 0a 09 73 65 74 20 62   key size..set b
29c0: 6c 6f 63 6b 50 61 73 73 77 6f 72 64 20 24 70 61  lockPassword $pa
29d0: 73 73 77 6f 72 64 0a 09 61 70 70 65 6e 64 20 62  ssword..append b
29e0: 6c 6f 63 6b 50 61 73 73 77 6f 72 64 20 5b 73 74  lockPassword [st
29f0: 72 69 6e 67 20 72 65 70 65 61 74 20 22 5c 78 30  ring repeat "\x0
2a00: 30 22 20 5b 65 78 70 72 20 7b 2d 5b 73 74 72 69  0" [expr {-[stri
2a10: 6e 67 20 6c 65 6e 67 74 68 20 24 70 61 73 73 77  ng length $passw
2a20: 6f 72 64 5d 20 25 20 24 6b 65 79 53 69 7a 65 7d  ord] % $keySize}
2a30: 5d 5d 0a 0a 09 64 62 20 74 72 61 6e 73 61 63 74  ]]...db transact
2a40: 69 6f 6e 20 7b 0a 09 09 64 62 20 65 76 61 6c 20  ion {...db eval 
2a50: 7b 44 45 4c 45 54 45 20 46 52 4f 4d 20 70 61 73  {DELETE FROM pas
2a60: 73 77 6f 72 64 73 20 57 48 45 52 45 20 6e 61 6d  swords WHERE nam
2a70: 65 20 3d 20 24 6e 61 6d 65 3b 7d 0a 0a 09 09 66  e = $name;}....f
2a80: 6f 72 65 61 63 68 20 70 75 62 6c 69 63 4b 65 79  oreach publicKey
2a90: 20 24 70 75 62 6c 69 63 4b 65 79 73 20 7b 0a 09   $publicKeys {..
2aa0: 09 09 73 65 74 20 6b 65 79 20 5b 72 65 61 64 20  ..set key [read 
2ab0: 24 66 64 20 24 6b 65 79 53 69 7a 65 5d 0a 09 09  $fd $keySize]...
2ac0: 09 69 66 20 7b 5b 73 74 72 69 6e 67 20 6c 65 6e  .if {[string len
2ad0: 67 74 68 20 24 6b 65 79 5d 20 21 3d 20 24 6b 65  gth $key] != $ke
2ae0: 79 53 69 7a 65 7d 20 7b 0a 09 09 09 09 63 6c 6f  ySize} {.....clo
2af0: 73 65 20 24 66 64 0a 0a 09 09 09 09 72 65 74 75  se $fd......retu
2b00: 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22  rn -code error "
2b10: 45 52 52 4f 52 3a 20 53 68 6f 72 74 20 72 65 61  ERROR: Short rea
2b20: 64 20 66 72 6f 6d 20 72 61 6e 64 6f 6d 20 64 65  d from random de
2b30: 76 69 63 65 22 0a 09 09 09 7d 0a 0a 09 09 09 73  vice"....}.....s
2b40: 65 74 20 73 61 6c 74 20 5b 72 65 61 64 20 24 66  et salt [read $f
2b50: 64 20 24 6b 65 79 53 69 7a 65 5d 0a 09 09 09 73  d $keySize]....s
2b60: 65 74 20 73 61 6c 74 20 5b 62 69 6e 61 72 79 20  et salt [binary 
2b70: 65 6e 63 6f 64 65 20 62 61 73 65 36 34 20 24 73  encode base64 $s
2b80: 61 6c 74 5d 0a 0a 09 09 09 73 65 74 20 70 75 62  alt].....set pub
2b90: 6c 69 63 4b 65 79 49 74 65 6d 20 5b 3a 3a 70 6b  licKeyItem [::pk
2ba0: 69 3a 3a 70 6b 63 73 3a 3a 70 61 72 73 65 5f 70  i::pkcs::parse_p
2bb0: 75 62 6c 69 63 5f 6b 65 79 20 5b 62 69 6e 61 72  ublic_key [binar
2bc0: 79 20 64 65 63 6f 64 65 20 62 61 73 65 36 34 20  y decode base64 
2bd0: 24 70 75 62 6c 69 63 4b 65 79 5d 5d 0a 0a 09 09  $publicKey]]....
2be0: 09 73 65 74 20 65 6e 63 72 79 70 74 65 64 4b 65  .set encryptedKe
2bf0: 79 20 5b 62 69 6e 61 72 79 20 65 6e 63 6f 64 65  y [binary encode
2c00: 20 62 61 73 65 36 34 20 5b 3a 3a 70 6b 69 3a 3a   base64 [::pki::
2c10: 65 6e 63 72 79 70 74 20 2d 70 75 62 20 2d 62 69  encrypt -pub -bi
2c20: 6e 61 72 79 20 2d 2d 20 24 6b 65 79 20 24 70 75  nary -- $key $pu
2c30: 62 6c 69 63 4b 65 79 49 74 65 6d 5d 5d 0a 0a 09  blicKeyItem]]...
2c40: 09 09 73 65 74 20 65 6e 63 72 79 70 74 65 64 50  ..set encryptedP
2c50: 61 73 73 20 5b 62 69 6e 61 72 79 20 65 6e 63 6f  ass [binary enco
2c60: 64 65 20 62 61 73 65 36 34 20 5b 3a 3a 61 65 73  de base64 [::aes
2c70: 3a 3a 61 65 73 20 2d 64 69 72 20 65 6e 63 72 79  ::aes -dir encry
2c80: 70 74 20 2d 6b 65 79 20 24 6b 65 79 20 2d 2d 20  pt -key $key -- 
2c90: 24 62 6c 6f 63 6b 50 61 73 73 77 6f 72 64 5d 5d  $blockPassword]]
2ca0: 0a 0a 09 09 09 73 65 74 20 76 65 72 69 66 69 63  .....set verific
2cb0: 61 74 69 6f 6e 48 61 73 68 20 5b 73 68 61 32 3a  ationHash [sha2:
2cc0: 3a 73 68 61 32 35 36 20 2d 68 65 78 20 2d 2d 20  :sha256 -hex -- 
2cd0: 22 24 7b 73 61 6c 74 7d 7c 24 7b 70 75 62 6c 69  "${salt}|${publi
2ce0: 63 4b 65 79 7d 7c 24 7b 70 61 73 73 77 6f 72 64  cKey}|${password
2cf0: 7d 22 5d 0a 09 09 09 73 65 74 20 76 65 72 69 66  }"]....set verif
2d00: 69 63 61 74 69 6f 6e 20 5b 6c 69 73 74 20 73 61  ication [list sa
2d10: 6c 74 20 24 73 61 6c 74 20 68 61 73 68 41 6c 67  lt $salt hashAlg
2d20: 6f 72 69 74 68 6d 20 73 68 61 32 35 36 20 68 61  orithm sha256 ha
2d30: 73 68 20 24 76 65 72 69 66 69 63 61 74 69 6f 6e  sh $verification
2d40: 48 61 73 68 5d 0a 0a 09 09 09 64 62 20 65 76 61  Hash].....db eva
2d50: 6c 20 7b 49 4e 53 45 52 54 20 49 4e 54 4f 20 70  l {INSERT INTO p
2d60: 61 73 73 77 6f 72 64 73 20 28 6e 61 6d 65 2c 20  asswords (name, 
2d70: 65 6e 63 72 79 70 74 65 64 50 61 73 73 2c 20 65  encryptedPass, e
2d80: 6e 63 72 79 70 74 65 64 4b 65 79 2c 20 70 75 62  ncryptedKey, pub
2d90: 6c 69 63 4b 65 79 2c 20 76 65 72 69 66 69 63 61  licKey, verifica
2da0: 74 69 6f 6e 29 20 56 41 4c 55 45 53 20 28 24 6e  tion) VALUES ($n
2db0: 61 6d 65 2c 20 40 65 6e 63 72 79 70 74 65 64 50  ame, @encryptedP
2dc0: 61 73 73 2c 20 40 65 6e 63 72 79 70 74 65 64 4b  ass, @encryptedK
2dd0: 65 79 2c 20 40 70 75 62 6c 69 63 4b 65 79 2c 20  ey, @publicKey, 
2de0: 40 76 65 72 69 66 69 63 61 74 69 6f 6e 29 3b 7d  @verification);}
2df0: 0a 09 09 7d 0a 09 7d 0a 0a 09 63 6c 6f 73 65 20  ...}..}...close 
2e00: 24 66 64 0a 7d 0a 0a 70 72 6f 63 20 5f 70 72 6f  $fd.}..proc _pro
2e10: 6d 70 74 20 7b 70 72 6f 6d 70 74 7d 20 7b 0a 09  mpt {prompt} {..
2e20: 70 75 74 73 20 2d 6e 6f 6e 65 77 6c 69 6e 65 20  puts -nonewline 
2e30: 24 70 72 6f 6d 70 74 0a 09 66 6c 75 73 68 20 73  $prompt..flush s
2e40: 74 64 6f 75 74 0a 0a 09 70 75 74 73 20 2d 6e 6f  tdout...puts -no
2e50: 6e 65 77 6c 69 6e 65 20 5b 65 78 65 63 20 73 74  newline [exec st
2e60: 74 79 20 2d 65 63 68 6f 5d 0a 09 66 6c 75 73 68  ty -echo]..flush
2e70: 20 73 74 64 6f 75 74 0a 0a 09 73 65 74 20 70 61   stdout...set pa
2e80: 73 73 77 6f 72 64 20 5b 67 65 74 73 20 73 74 64  ssword [gets std
2e90: 69 6e 5d 0a 0a 09 70 75 74 73 20 2d 6e 6f 6e 65  in]...puts -none
2ea0: 77 6c 69 6e 65 20 5b 65 78 65 63 20 73 74 74 79  wline [exec stty
2eb0: 20 65 63 68 6f 5d 0a 09 70 75 74 73 20 22 22 0a   echo]..puts "".
2ec0: 09 66 6c 75 73 68 20 73 74 64 6f 75 74 0a 0a 09  .flush stdout...
2ed0: 72 65 74 75 72 6e 20 24 70 61 73 73 77 6f 72 64  return $password
2ee0: 0a 7d 0a 0a 70 72 6f 63 20 5f 67 65 74 50 61 73  .}..proc _getPas
2ef0: 73 77 6f 72 64 20 7b 6e 61 6d 65 7d 20 7b 0a 09  sword {name} {..
2f00: 73 65 74 20 65 78 69 73 74 73 20 5b 64 62 20 65  set exists [db e
2f10: 76 61 6c 20 7b 53 45 4c 45 43 54 20 31 20 46 52  val {SELECT 1 FR
2f20: 4f 4d 20 70 61 73 73 77 6f 72 64 73 20 57 48 45  OM passwords WHE
2f30: 52 45 20 6e 61 6d 65 20 3d 20 24 6e 61 6d 65 20  RE name = $name 
2f40: 4c 49 4d 49 54 20 31 3b 7d 5d 0a 09 69 66 20 7b  LIMIT 1;}]..if {
2f50: 24 65 78 69 73 74 73 20 21 3d 20 22 31 22 7d 20  $exists != "1"} 
2f60: 7b 0a 09 09 72 65 74 75 72 6e 20 2d 63 6f 64 65  {...return -code
2f70: 20 65 72 72 6f 72 20 22 50 61 73 73 77 6f 72 64   error "Password
2f80: 20 5c 22 24 6e 61 6d 65 5c 22 20 64 6f 65 73 20   \"$name\" does 
2f90: 6e 6f 74 20 65 78 69 73 74 73 2e 22 0a 09 7d 0a  not exists."..}.
2fa0: 0a 09 66 6f 72 65 61 63 68 20 73 6c 6f 74 49 6e  ..foreach slotIn
2fb0: 66 6f 44 69 63 74 20 5b 5f 6c 69 73 74 43 65 72  foDict [_listCer
2fc0: 74 69 66 69 63 61 74 65 73 5d 20 7b 0a 09 09 75  tificates] {...u
2fd0: 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e  nset -nocomplain
2fe0: 20 73 6c 6f 74 49 6e 66 6f 0a 09 09 61 72 72 61   slotInfo...arra
2ff0: 79 20 73 65 74 20 73 6c 6f 74 49 6e 66 6f 20 24  y set slotInfo $
3000: 73 6c 6f 74 49 6e 66 6f 44 69 63 74 0a 0a 09 09  slotInfoDict....
3010: 73 65 74 20 70 75 62 6b 65 79 20 24 73 6c 6f 74  set pubkey $slot
3020: 49 6e 66 6f 28 70 75 62 6b 65 79 29 0a 09 09 73  Info(pubkey)...s
3030: 65 74 20 70 72 6f 6d 70 74 20 24 73 6c 6f 74 49  et prompt $slotI
3040: 6e 66 6f 28 70 72 6f 6d 70 74 29 0a 0a 09 09 69  nfo(prompt)....i
3050: 66 20 7b 5b 69 6e 66 6f 20 65 78 69 73 74 73 20  f {[info exists 
3060: 70 72 6f 6d 70 74 65 64 28 24 73 6c 6f 74 49 6e  prompted($slotIn
3070: 66 6f 28 69 64 29 29 5d 7d 20 7b 0a 09 09 09 73  fo(id))]} {....s
3080: 65 74 20 70 72 6f 6d 70 74 20 66 61 6c 73 65 0a  et prompt false.
3090: 09 09 7d 0a 0a 09 09 69 66 20 7b 24 70 72 6f 6d  ..}....if {$prom
30a0: 70 74 7d 20 7b 0a 09 09 09 73 65 74 20 50 49 4e  pt} {....set PIN
30b0: 20 5b 5f 70 72 6f 6d 70 74 20 22 50 6c 65 61 73   [_prompt "Pleas
30c0: 65 20 65 6e 74 65 72 20 74 68 65 20 50 49 4e 20  e enter the PIN 
30d0: 66 6f 72 20 5b 64 69 63 74 20 67 65 74 20 24 73  for [dict get $s
30e0: 6c 6f 74 49 6e 66 6f 28 63 65 72 74 29 20 73 75  lotInfo(cert) su
30f0: 62 6a 65 63 74 5d 3a 20 22 5d 0a 0a 09 09 09 69  bject]: "].....i
3100: 66 20 7b 21 5b 3a 3a 70 6b 69 3a 3a 70 6b 63 73  f {![::pki::pkcs
3110: 31 31 3a 3a 6c 6f 67 69 6e 20 24 73 6c 6f 74 49  11::login $slotI
3120: 6e 66 6f 28 68 61 6e 64 6c 65 29 20 24 73 6c 6f  nfo(handle) $slo
3130: 74 49 6e 66 6f 28 69 64 29 20 24 50 49 4e 5d 7d  tInfo(id) $PIN]}
3140: 20 7b 0a 09 09 09 09 72 65 74 75 72 6e 20 2d 63   {.....return -c
3150: 6f 64 65 20 65 72 72 6f 72 20 22 55 6e 61 62 6c  ode error "Unabl
3160: 65 20 74 6f 20 61 75 74 68 65 6e 74 69 63 61 74  e to authenticat
3170: 65 22 0a 09 09 09 7d 0a 0a 09 09 09 73 65 74 20  e"....}.....set 
3180: 70 72 6f 6d 70 74 65 64 28 24 73 6c 6f 74 49 6e  prompted($slotIn
3190: 66 6f 28 69 64 29 29 20 31 0a 09 09 7d 0a 0a 09  fo(id)) 1...}...
31a0: 09 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54  .db eval {SELECT
31b0: 20 65 6e 63 72 79 70 74 65 64 50 61 73 73 2c 20   encryptedPass, 
31c0: 65 6e 63 72 79 70 74 65 64 4b 65 79 20 46 52 4f  encryptedKey FRO
31d0: 4d 20 70 61 73 73 77 6f 72 64 73 20 57 48 45 52  M passwords WHER
31e0: 45 20 6e 61 6d 65 20 3d 20 24 6e 61 6d 65 20 41  E name = $name A
31f0: 4e 44 20 70 75 62 6c 69 63 4b 65 79 20 3d 20 24  ND publicKey = $
3200: 70 75 62 6b 65 79 3b 7d 20 72 6f 77 20 7b 0a 09  pubkey;} row {..
3210: 09 09 73 65 74 20 6b 65 79 20 5b 3a 3a 70 6b 69  ..set key [::pki
3220: 3a 3a 64 65 63 72 79 70 74 20 2d 62 69 6e 61 72  ::decrypt -binar
3230: 79 20 2d 70 72 69 76 20 2d 2d 20 5b 62 69 6e 61  y -priv -- [bina
3240: 72 79 20 64 65 63 6f 64 65 20 62 61 73 65 36 34  ry decode base64
3250: 20 24 72 6f 77 28 65 6e 63 72 79 70 74 65 64 4b   $row(encryptedK
3260: 65 79 29 5d 20 24 73 6c 6f 74 49 6e 66 6f 28 63  ey)] $slotInfo(c
3270: 65 72 74 29 5d 0a 09 09 09 73 65 74 20 70 61 73  ert)]....set pas
3280: 73 77 6f 72 64 20 5b 3a 3a 61 65 73 3a 3a 61 65  sword [::aes::ae
3290: 73 20 2d 64 69 72 20 64 65 63 72 79 70 74 20 2d  s -dir decrypt -
32a0: 6b 65 79 20 24 6b 65 79 20 2d 2d 20 5b 62 69 6e  key $key -- [bin
32b0: 61 72 79 20 64 65 63 6f 64 65 20 62 61 73 65 36  ary decode base6
32c0: 34 20 24 72 6f 77 28 65 6e 63 72 79 70 74 65 64  4 $row(encrypted
32d0: 50 61 73 73 29 5d 5d 0a 0a 09 09 09 72 65 74 75  Pass)]].....retu
32e0: 72 6e 20 5b 73 74 72 69 6e 67 20 74 72 69 6d 72  rn [string trimr
32f0: 69 67 68 74 20 24 70 61 73 73 77 6f 72 64 20 22  ight $password "
3300: 5c 78 30 30 22 5d 0a 09 09 7d 0a 09 7d 0a 0a 09  \x00"]...}..}...
3310: 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72  return -code err
3320: 6f 72 20 22 4e 6f 20 76 61 6c 69 64 20 6b 65 79  or "No valid key
3330: 73 22 0a 7d 0a 0a 70 72 6f 63 20 5f 6d 6f 64 69  s".}..proc _modi
3340: 66 79 50 75 62 6c 69 63 4b 65 79 73 20 7b 70 61  fyPublicKeys {pa
3350: 73 73 77 6f 72 64 4e 61 6d 65 20 75 73 65 72 4e  sswordName userN
3360: 61 6d 65 73 20 73 71 6c 7d 20 7b 0a 09 73 65 74  ames sql} {..set
3370: 20 65 78 69 73 74 73 20 5b 64 62 20 65 76 61 6c   exists [db eval
3380: 20 7b 53 45 4c 45 43 54 20 31 20 46 52 4f 4d 20   {SELECT 1 FROM 
3390: 70 61 73 73 77 6f 72 64 73 20 57 48 45 52 45 20  passwords WHERE 
33a0: 6e 61 6d 65 20 3d 20 24 70 61 73 73 77 6f 72 64  name = $password
33b0: 4e 61 6d 65 20 4c 49 4d 49 54 20 31 3b 7d 5d 0a  Name LIMIT 1;}].
33c0: 09 69 66 20 7b 24 65 78 69 73 74 73 20 21 3d 20  .if {$exists != 
33d0: 22 31 22 7d 20 7b 0a 09 09 72 65 74 75 72 6e 20  "1"} {...return 
33e0: 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 50 61 73  -code error "Pas
33f0: 73 77 6f 72 64 20 5c 22 24 70 61 73 73 77 6f 72  sword \"$passwor
3400: 64 4e 61 6d 65 5c 22 20 64 6f 65 73 20 6e 6f 74  dName\" does not
3410: 20 65 78 69 73 74 73 2e 22 0a 09 7d 0a 0a 09 73   exists."..}...s
3420: 65 74 20 70 75 62 6c 69 63 4b 65 79 73 20 5b 6c  et publicKeys [l
3430: 69 73 74 5d 0a 0a 09 64 62 20 65 76 61 6c 20 7b  ist]...db eval {
3440: 53 45 4c 45 43 54 20 70 75 62 6c 69 63 4b 65 79  SELECT publicKey
3450: 20 46 52 4f 4d 20 70 61 73 73 77 6f 72 64 73 20   FROM passwords 
3460: 57 48 45 52 45 20 6e 61 6d 65 20 3d 20 24 70 61  WHERE name = $pa
3470: 73 73 77 6f 72 64 4e 61 6d 65 3b 7d 20 72 6f 77  sswordName;} row
3480: 20 7b 0a 09 09 6c 61 70 70 65 6e 64 20 70 75 62   {...lappend pub
3490: 6c 69 63 4b 65 79 73 20 24 72 6f 77 28 70 75 62  licKeys $row(pub
34a0: 6c 69 63 4b 65 79 29 0a 09 7d 0a 0a 09 73 65 74  licKey)..}...set
34b0: 20 63 68 61 6e 67 65 52 65 71 75 69 72 65 64 20   changeRequired 
34c0: 30 0a 09 66 6f 72 65 61 63 68 20 75 73 65 72 20  0..foreach user 
34d0: 24 75 73 65 72 4e 61 6d 65 73 20 7b 0a 09 09 75  $userNames {...u
34e0: 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e  nset -nocomplain
34f0: 20 72 6f 77 0a 09 09 64 62 20 65 76 61 6c 20 7b   row...db eval {
3500: 53 45 4c 45 43 54 20 70 75 62 6c 69 63 4b 65 79  SELECT publicKey
3510: 20 46 52 4f 4d 20 75 73 65 72 73 20 57 48 45 52   FROM users WHER
3520: 45 20 6e 61 6d 65 20 3d 20 24 75 73 65 72 3b 7d  E name = $user;}
3530: 20 72 6f 77 20 24 73 71 6c 0a 09 7d 0a 0a 09 69   row $sql..}...i
3540: 66 20 7b 21 24 63 68 61 6e 67 65 52 65 71 75 69  f {!$changeRequi
3550: 72 65 64 7d 20 7b 0a 09 09 72 65 74 75 72 6e 0a  red} {...return.
3560: 09 7d 0a 0a 09 73 65 74 20 70 61 73 73 77 6f 72  .}...set passwor
3570: 64 20 5b 5f 67 65 74 50 61 73 73 77 6f 72 64 20  d [_getPassword 
3580: 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 5d 0a 0a  $passwordName]..
3590: 09 5f 61 64 64 50 61 73 73 77 6f 72 64 20 24 70  ._addPassword $p
35a0: 61 73 73 77 6f 72 64 4e 61 6d 65 20 24 70 61 73  asswordName $pas
35b0: 73 77 6f 72 64 20 24 70 75 62 6c 69 63 4b 65 79  sword $publicKey
35c0: 73 0a 7d 0a 0a 70 72 6f 63 20 5f 67 65 74 55 73  s.}..proc _getUs
35d0: 65 72 73 46 6f 72 50 61 73 73 77 6f 72 64 20 7b  ersForPassword {
35e0: 70 61 73 73 77 6f 72 64 4e 61 6d 65 73 7d 20 7b  passwordNames} {
35f0: 0a 09 73 65 74 20 75 73 65 72 4e 61 6d 65 73 20  ..set userNames 
3600: 5b 6c 69 73 74 5d 0a 0a 09 66 6f 72 65 61 63 68  [list]...foreach
3610: 20 70 61 73 73 77 6f 72 64 4e 61 6d 65 20 24 70   passwordName $p
3620: 61 73 73 77 6f 72 64 4e 61 6d 65 73 20 7b 0a 09  asswordNames {..
3630: 09 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54  .db eval {SELECT
3640: 20 70 75 62 6c 69 63 4b 65 79 20 46 52 4f 4d 20   publicKey FROM 
3650: 70 61 73 73 77 6f 72 64 73 20 57 48 45 52 45 20  passwords WHERE 
3660: 6e 61 6d 65 20 3d 20 24 70 61 73 73 77 6f 72 64  name = $password
3670: 4e 61 6d 65 3b 7d 20 70 61 73 73 77 6f 72 64 52  Name;} passwordR
3680: 6f 77 20 7b 0a 09 09 09 64 62 20 65 76 61 6c 20  ow {....db eval 
3690: 7b 53 45 4c 45 43 54 20 6e 61 6d 65 20 46 52 4f  {SELECT name FRO
36a0: 4d 20 75 73 65 72 73 20 57 48 45 52 45 20 70 75  M users WHERE pu
36b0: 62 6c 69 63 4b 65 79 20 3d 20 24 70 61 73 73 77  blicKey = $passw
36c0: 6f 72 64 52 6f 77 28 70 75 62 6c 69 63 4b 65 79  ordRow(publicKey
36d0: 29 7d 20 75 73 65 72 52 6f 77 20 7b 0a 09 09 09  )} userRow {....
36e0: 09 69 66 20 7b 24 75 73 65 72 52 6f 77 28 6e 61  .if {$userRow(na
36f0: 6d 65 29 20 69 6e 20 24 75 73 65 72 4e 61 6d 65  me) in $userName
3700: 73 7d 20 7b 0a 09 09 09 09 09 63 6f 6e 74 69 6e  s} {......contin
3710: 75 65 0a 09 09 09 09 7d 0a 0a 09 09 09 09 6c 61  ue.....}......la
3720: 70 70 65 6e 64 20 75 73 65 72 4e 61 6d 65 73 20  ppend userNames 
3730: 24 75 73 65 72 52 6f 77 28 6e 61 6d 65 29 0a 09  $userRow(name)..
3740: 09 09 7d 0a 09 09 7d 0a 09 7d 0a 0a 09 72 65 74  ..}...}..}...ret
3750: 75 72 6e 20 24 75 73 65 72 4e 61 6d 65 73 0a 7d  urn $userNames.}
3760: 0a 0a 70 72 6f 63 20 5f 67 65 74 50 61 73 73 77  ..proc _getPassw
3770: 6f 72 64 73 46 6f 72 55 73 65 72 20 7b 75 73 65  ordsForUser {use
3780: 72 4e 61 6d 65 73 7d 20 7b 0a 09 73 65 74 20 70  rNames} {..set p
3790: 61 73 73 77 6f 72 64 4e 61 6d 65 73 20 5b 6c 69  asswordNames [li
37a0: 73 74 5d 0a 0a 09 66 6f 72 65 61 63 68 20 75 73  st]...foreach us
37b0: 65 72 4e 61 6d 65 20 24 75 73 65 72 4e 61 6d 65  erName $userName
37c0: 73 20 7b 0a 09 09 64 62 20 65 76 61 6c 20 7b 53  s {...db eval {S
37d0: 45 4c 45 43 54 20 70 75 62 6c 69 63 4b 65 79 20  ELECT publicKey 
37e0: 46 52 4f 4d 20 75 73 65 72 73 20 57 48 45 52 45  FROM users WHERE
37f0: 20 6e 61 6d 65 20 3d 20 24 75 73 65 72 4e 61 6d   name = $userNam
3800: 65 3b 7d 20 75 73 65 72 52 6f 77 20 7b 0a 09 09  e;} userRow {...
3810: 09 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54  .db eval {SELECT
3820: 20 6e 61 6d 65 20 46 52 4f 4d 20 70 61 73 73 77   name FROM passw
3830: 6f 72 64 73 20 57 48 45 52 45 20 70 75 62 6c 69  ords WHERE publi
3840: 63 4b 65 79 20 3d 20 24 75 73 65 72 52 6f 77 28  cKey = $userRow(
3850: 70 75 62 6c 69 63 4b 65 79 29 7d 20 70 61 73 73  publicKey)} pass
3860: 77 6f 72 64 52 6f 77 20 7b 0a 09 09 09 09 69 66  wordRow {.....if
3870: 20 7b 24 70 61 73 73 77 6f 72 64 52 6f 77 28 6e   {$passwordRow(n
3880: 61 6d 65 29 20 69 6e 20 24 70 61 73 73 77 6f 72  ame) in $passwor
3890: 64 4e 61 6d 65 73 7d 20 7b 0a 09 09 09 09 09 63  dNames} {......c
38a0: 6f 6e 74 69 6e 75 65 0a 09 09 09 09 7d 0a 0a 09  ontinue.....}...
38b0: 09 09 09 6c 61 70 70 65 6e 64 20 70 61 73 73 77  ...lappend passw
38c0: 6f 72 64 4e 61 6d 65 73 20 24 70 61 73 73 77 6f  ordNames $passwo
38d0: 72 64 52 6f 77 28 6e 61 6d 65 29 0a 09 09 09 7d  rdRow(name)....}
38e0: 0a 09 09 7d 0a 09 7d 0a 0a 09 72 65 74 75 72 6e  ...}..}...return
38f0: 20 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 73 0a   $passwordNames.
3900: 7d 0a 23 20 45 6e 64 20 69 6e 74 65 72 6e 61 6c  }.# End internal
3910: 20 66 75 6e 63 74 69 6f 6e 73 0a 0a 23 20 53 74   functions..# St
3920: 61 72 74 20 75 73 65 72 20 43 4c 49 20 66 75 6e  art user CLI fun
3930: 63 74 69 6f 6e 73 0a 70 72 6f 63 20 6c 69 73 74  ctions.proc list
3940: 4c 6f 63 61 6c 4b 65 79 73 20 7b 7d 20 7b 0a 09  LocalKeys {} {..
3950: 66 6f 72 65 61 63 68 20 73 6c 6f 74 49 6e 66 6f  foreach slotInfo
3960: 44 69 63 74 20 5b 5f 6c 69 73 74 43 65 72 74 69  Dict [_listCerti
3970: 66 69 63 61 74 65 73 5d 20 7b 0a 09 09 75 6e 73  ficates] {...uns
3980: 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e 20 73  et -nocomplain s
3990: 6c 6f 74 49 6e 66 6f 0a 09 09 61 72 72 61 79 20  lotInfo...array 
39a0: 73 65 74 20 73 6c 6f 74 49 6e 66 6f 20 24 73 6c  set slotInfo $sl
39b0: 6f 74 49 6e 66 6f 44 69 63 74 0a 0a 09 09 73 65  otInfoDict....se
39c0: 74 20 73 75 62 6a 65 63 74 20 5b 64 69 63 74 20  t subject [dict 
39d0: 67 65 74 20 24 73 6c 6f 74 49 6e 66 6f 28 63 65  get $slotInfo(ce
39e0: 72 74 29 20 73 75 62 6a 65 63 74 5d 0a 09 09 73  rt) subject]...s
39f0: 65 74 20 70 75 62 6b 65 79 20 20 24 73 6c 6f 74  et pubkey  $slot
3a00: 49 6e 66 6f 28 70 75 62 6b 65 79 29 0a 0a 09 09  Info(pubkey)....
3a10: 6c 61 70 70 65 6e 64 20 70 75 62 6c 69 63 4b 65  lappend publicKe
3a20: 79 73 28 24 73 75 62 6a 65 63 74 29 20 24 70 75  ys($subject) $pu
3a30: 62 6b 65 79 0a 09 7d 0a 0a 09 66 6f 72 65 61 63  bkey..}...foreac
3a40: 68 20 7b 73 75 62 6a 65 63 74 20 70 75 62 6b 65  h {subject pubke
3a50: 79 73 7d 20 5b 61 72 72 61 79 20 67 65 74 20 70  ys} [array get p
3a60: 75 62 6c 69 63 4b 65 79 73 5d 20 7b 0a 09 09 70  ublicKeys] {...p
3a70: 75 74 73 20 22 24 73 75 62 6a 65 63 74 22 0a 0a  uts "$subject"..
3a80: 09 09 66 6f 72 65 61 63 68 20 70 75 62 6b 65 79  ..foreach pubkey
3a90: 20 24 70 75 62 6b 65 79 73 20 7b 0a 09 09 09 70   $pubkeys {....p
3aa0: 75 74 73 20 22 20 20 7c 2d 3e 20 24 70 75 62 6b  uts "  |-> $pubk
3ab0: 65 79 22 0a 09 09 7d 0a 09 7d 0a 0a 09 73 65 74  ey"...}..}...set
3ac0: 20 3a 3a 73 61 76 65 52 65 71 75 69 72 65 64 20   ::saveRequired 
3ad0: 30 0a 7d 0a 0a 70 72 6f 63 20 6c 69 73 74 41 76  0.}..proc listAv
3ae0: 61 69 6c 61 62 6c 65 50 61 73 73 77 6f 72 64 73  ailablePasswords
3af0: 20 7b 7d 20 7b 0a 09 73 65 74 20 70 61 73 73 77   {} {..set passw
3b00: 6f 72 64 4e 61 6d 65 73 20 5b 6c 69 73 74 5d 0a  ordNames [list].
3b10: 09 66 6f 72 65 61 63 68 20 73 6c 6f 74 49 6e 66  .foreach slotInf
3b20: 6f 44 69 63 74 20 5b 5f 6c 69 73 74 43 65 72 74  oDict [_listCert
3b30: 69 66 69 63 61 74 65 73 5d 20 7b 0a 09 09 75 6e  ificates] {...un
3b40: 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e 20  set -nocomplain 
3b50: 73 6c 6f 74 49 6e 66 6f 0a 09 09 61 72 72 61 79  slotInfo...array
3b60: 20 73 65 74 20 73 6c 6f 74 49 6e 66 6f 20 24 73   set slotInfo $s
3b70: 6c 6f 74 49 6e 66 6f 44 69 63 74 0a 0a 09 09 73  lotInfoDict....s
3b80: 65 74 20 70 75 62 6b 65 79 20 24 73 6c 6f 74 49  et pubkey $slotI
3b90: 6e 66 6f 28 70 75 62 6b 65 79 29 0a 0a 09 09 75  nfo(pubkey)....u
3ba0: 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e  nset -nocomplain
3bb0: 20 72 6f 77 0a 09 09 64 62 20 65 76 61 6c 20 7b   row...db eval {
3bc0: 53 45 4c 45 43 54 20 6e 61 6d 65 20 46 52 4f 4d  SELECT name FROM
3bd0: 20 70 61 73 73 77 6f 72 64 73 20 57 48 45 52 45   passwords WHERE
3be0: 20 70 75 62 6c 69 63 4b 65 79 20 3d 20 24 70 75   publicKey = $pu
3bf0: 62 6b 65 79 3b 7d 20 72 6f 77 20 7b 0a 09 09 09  bkey;} row {....
3c00: 69 66 20 7b 24 72 6f 77 28 6e 61 6d 65 29 20 69  if {$row(name) i
3c10: 6e 20 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 73  n $passwordNames
3c20: 7d 20 7b 0a 09 09 09 09 63 6f 6e 74 69 6e 75 65  } {.....continue
3c30: 0a 09 09 09 7d 0a 0a 09 09 09 6c 61 70 70 65 6e  ....}.....lappen
3c40: 64 20 70 61 73 73 77 6f 72 64 4e 61 6d 65 73 20  d passwordNames 
3c50: 24 72 6f 77 28 6e 61 6d 65 29 0a 09 09 7d 0a 09  $row(name)...}..
3c60: 7d 0a 0a 0a 09 66 6f 72 65 61 63 68 20 70 61 73  }....foreach pas
3c70: 73 77 6f 72 64 4e 61 6d 65 20 24 70 61 73 73 77  swordName $passw
3c80: 6f 72 64 4e 61 6d 65 73 20 7b 0a 09 09 70 75 74  ordNames {...put
3c90: 73 20 22 24 70 61 73 73 77 6f 72 64 4e 61 6d 65  s "$passwordName
3ca0: 20 2d 20 5b 6a 6f 69 6e 20 5b 5f 67 65 74 55 73   - [join [_getUs
3cb0: 65 72 73 46 6f 72 50 61 73 73 77 6f 72 64 20 5b  ersForPassword [
3cc0: 6c 69 73 74 20 24 70 61 73 73 77 6f 72 64 4e 61  list $passwordNa
3cd0: 6d 65 5d 5d 20 7b 2c 20 7d 5d 22 0a 09 7d 0a 0a  me]] {, }]"..}..
3ce0: 09 73 65 74 20 3a 3a 73 61 76 65 52 65 71 75 69  .set ::saveRequi
3cf0: 72 65 64 20 30 0a 7d 0a 0a 70 72 6f 63 20 6c 69  red 0.}..proc li
3d00: 73 74 50 61 73 73 77 6f 72 64 73 20 7b 7d 20 7b  stPasswords {} {
3d10: 0a 09 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43  ..db eval {SELEC
3d20: 54 20 44 49 53 54 49 4e 43 54 20 6e 61 6d 65 20  T DISTINCT name 
3d30: 46 52 4f 4d 20 70 61 73 73 77 6f 72 64 73 3b 7d  FROM passwords;}
3d40: 20 72 6f 77 20 7b 0a 09 09 70 75 74 73 20 22 24   row {...puts "$
3d50: 72 6f 77 28 6e 61 6d 65 29 20 2d 20 5b 6a 6f 69  row(name) - [joi
3d60: 6e 20 5b 5f 67 65 74 55 73 65 72 73 46 6f 72 50  n [_getUsersForP
3d70: 61 73 73 77 6f 72 64 20 5b 6c 69 73 74 20 24 72  assword [list $r
3d80: 6f 77 28 6e 61 6d 65 29 5d 5d 20 7b 2c 20 7d 5d  ow(name)]] {, }]
3d90: 22 0a 09 7d 0a 0a 09 73 65 74 20 3a 3a 73 61 76  "..}...set ::sav
3da0: 65 52 65 71 75 69 72 65 64 20 30 0a 7d 0a 0a 70  eRequired 0.}..p
3db0: 72 6f 63 20 6c 69 73 74 55 73 65 72 73 20 7b 7d  roc listUsers {}
3dc0: 20 7b 0a 09 64 62 20 65 76 61 6c 20 7b 53 45 4c   {..db eval {SEL
3dd0: 45 43 54 20 44 49 53 54 49 4e 43 54 20 6e 61 6d  ECT DISTINCT nam
3de0: 65 20 46 52 4f 4d 20 75 73 65 72 73 3b 7d 20 72  e FROM users;} r
3df0: 6f 77 20 7b 0a 09 09 70 75 74 73 20 22 24 72 6f  ow {...puts "$ro
3e00: 77 28 6e 61 6d 65 29 20 2d 20 5b 6a 6f 69 6e 20  w(name) - [join 
3e10: 5b 5f 67 65 74 50 61 73 73 77 6f 72 64 73 46 6f  [_getPasswordsFo
3e20: 72 55 73 65 72 20 5b 6c 69 73 74 20 24 72 6f 77  rUser [list $row
3e30: 28 6e 61 6d 65 29 5d 5d 20 7b 2c 20 7d 5d 22 0a  (name)]] {, }]".
3e40: 09 7d 0a 0a 09 73 65 74 20 3a 3a 73 61 76 65 52  .}...set ::saveR
3e50: 65 71 75 69 72 65 64 20 30 0a 7d 0a 0a 70 72 6f  equired 0.}..pro
3e60: 63 20 61 64 64 55 73 65 72 20 7b 75 73 65 72 4e  c addUser {userN
3e70: 61 6d 65 20 6b 65 79 7d 20 7b 0a 09 73 65 74 20  ame key} {..set 
3e80: 6b 65 79 52 61 77 20 5b 62 69 6e 61 72 79 20 64  keyRaw [binary d
3e90: 65 63 6f 64 65 20 62 61 73 65 36 34 20 24 6b 65  ecode base64 $ke
3ea0: 79 5d 0a 09 73 65 74 20 6b 65 79 56 65 72 69 66  y]..set keyVerif
3eb0: 79 20 5b 3a 3a 70 6b 69 3a 3a 70 6b 63 73 3a 3a  y [::pki::pkcs::
3ec0: 70 61 72 73 65 5f 70 75 62 6c 69 63 5f 6b 65 79  parse_public_key
3ed0: 20 24 6b 65 79 52 61 77 5d 0a 0a 09 64 62 20 65   $keyRaw]...db e
3ee0: 76 61 6c 20 7b 49 4e 53 45 52 54 20 49 4e 54 4f  val {INSERT INTO
3ef0: 20 75 73 65 72 73 20 28 6e 61 6d 65 2c 20 70 75   users (name, pu
3f00: 62 6c 69 63 4b 65 79 29 20 56 41 4c 55 45 53 20  blicKey) VALUES 
3f10: 28 24 75 73 65 72 4e 61 6d 65 2c 20 40 6b 65 79  ($userName, @key
3f20: 29 3b 7d 0a 0a 09 23 20 58 58 58 3a 54 4f 44 4f  );}...# XXX:TODO
3f30: 3a 47 6f 20 74 68 72 6f 75 67 68 20 61 6e 64 20  :Go through and 
3f40: 72 65 2d 61 75 74 68 6f 72 69 7a 65 20 69 66 20  re-authorize if 
3f50: 70 6f 73 73 69 62 6c 65 0a 7d 0a 0a 70 72 6f 63  possible.}..proc
3f60: 20 64 65 6c 65 74 65 55 73 65 72 20 7b 75 73 65   deleteUser {use
3f70: 72 4e 61 6d 65 7d 20 7b 0a 09 23 20 58 58 58 3a  rName} {..# XXX:
3f80: 54 4f 44 4f 3a 20 47 6f 20 74 68 72 6f 75 67 68  TODO: Go through
3f90: 20 61 6e 64 20 64 65 2d 61 75 74 68 6f 72 69 7a   and de-authoriz
3fa0: 65 0a 7d 0a 0a 70 72 6f 63 20 61 64 64 50 61 73  e.}..proc addPas
3fb0: 73 77 6f 72 64 20 7b 70 61 73 73 77 6f 72 64 4e  sword {passwordN
3fc0: 61 6d 65 20 70 61 73 73 77 6f 72 64 20 61 72 67  ame password arg
3fd0: 73 7d 20 7b 0a 09 73 65 74 20 69 6e 69 74 69 61  s} {..set initia
3fe0: 6c 55 73 65 72 73 20 24 61 72 67 73 0a 0a 09 69  lUsers $args...i
3ff0: 66 20 7b 24 70 61 73 73 77 6f 72 64 20 65 71 20  f {$password eq 
4000: 22 22 7d 20 7b 0a 09 09 73 65 74 20 70 61 73 73  ""} {...set pass
4010: 77 6f 72 64 20 5b 5f 70 72 6f 6d 70 74 20 22 50  word [_prompt "P
4020: 6c 65 61 73 65 20 65 6e 74 65 72 20 74 68 65 20  lease enter the 
4030: 6e 65 77 20 70 61 73 73 77 6f 72 64 3a 20 22 5d  new password: "]
4040: 0a 09 7d 0a 0a 09 23 20 56 65 72 69 66 79 20 74  ..}...# Verify t
4050: 68 61 74 20 74 68 69 73 20 70 61 73 73 77 6f 72  hat this passwor
4060: 64 20 64 6f 65 73 20 6e 6f 74 20 61 6c 72 65 61  d does not alrea
4070: 64 79 20 65 78 69 73 74 0a 09 73 65 74 20 65 78  dy exist..set ex
4080: 69 73 74 73 20 5b 64 62 20 65 76 61 6c 20 7b 53  ists [db eval {S
4090: 45 4c 45 43 54 20 31 20 46 52 4f 4d 20 70 61 73  ELECT 1 FROM pas
40a0: 73 77 6f 72 64 73 20 57 48 45 52 45 20 6e 61 6d  swords WHERE nam
40b0: 65 20 3d 20 24 70 61 73 73 77 6f 72 64 4e 61 6d  e = $passwordNam
40c0: 65 20 4c 49 4d 49 54 20 31 3b 7d 5d 0a 09 69 66  e LIMIT 1;}]..if
40d0: 20 7b 24 65 78 69 73 74 73 20 3d 3d 20 22 31 22   {$exists == "1"
40e0: 7d 20 7b 0a 09 09 72 65 74 75 72 6e 20 2d 63 6f  } {...return -co
40f0: 64 65 20 65 72 72 6f 72 20 22 50 61 73 73 77 6f  de error "Passwo
4100: 72 64 20 5c 22 24 70 61 73 73 77 6f 72 64 4e 61  rd \"$passwordNa
4110: 6d 65 5c 22 20 61 6c 72 65 61 64 79 20 65 78 69  me\" already exi
4120: 73 74 73 2c 20 63 61 6e 6e 6f 74 20 61 64 64 2e  sts, cannot add.
4130: 22 0a 09 7d 0a 0a 09 23 20 47 65 74 20 6b 65 79  "..}...# Get key
4140: 73 20 66 6f 72 20 69 6e 69 74 69 61 6c 20 75 73  s for initial us
4150: 65 72 73 0a 09 73 65 74 20 70 75 62 6c 69 63 4b  ers..set publicK
4160: 65 79 73 20 5b 6c 69 73 74 5d 0a 09 66 6f 72 65  eys [list]..fore
4170: 61 63 68 20 75 73 65 72 20 24 69 6e 69 74 69 61  ach user $initia
4180: 6c 55 73 65 72 73 20 7b 0a 09 09 75 6e 73 65 74  lUsers {...unset
4190: 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e 20 72 6f 77   -nocomplain row
41a0: 0a 09 09 64 62 20 65 76 61 6c 20 7b 53 45 4c 45  ...db eval {SELE
41b0: 43 54 20 70 75 62 6c 69 63 4b 65 79 20 46 52 4f  CT publicKey FRO
41c0: 4d 20 75 73 65 72 73 20 57 48 45 52 45 20 6e 61  M users WHERE na
41d0: 6d 65 20 3d 20 24 75 73 65 72 3b 7d 20 72 6f 77  me = $user;} row
41e0: 20 7b 0a 09 09 09 6c 61 70 70 65 6e 64 20 70 75   {....lappend pu
41f0: 62 6c 69 63 4b 65 79 73 20 24 72 6f 77 28 70 75  blicKeys $row(pu
4200: 62 6c 69 63 4b 65 79 29 0a 09 09 7d 0a 09 7d 0a  blicKey)...}..}.
4210: 0a 09 5f 61 64 64 50 61 73 73 77 6f 72 64 20 24  .._addPassword $
4220: 70 61 73 73 77 6f 72 64 4e 61 6d 65 20 24 70 61  passwordName $pa
4230: 73 73 77 6f 72 64 20 24 70 75 62 6c 69 63 4b 65  ssword $publicKe
4240: 79 73 0a 7d 0a 0a 70 72 6f 63 20 67 65 74 50 61  ys.}..proc getPa
4250: 73 73 77 6f 72 64 20 7b 70 61 73 73 77 6f 72 64  ssword {password
4260: 4e 61 6d 65 7d 20 7b 0a 09 70 75 74 73 20 5b 5f  Name} {..puts [_
4270: 67 65 74 50 61 73 73 77 6f 72 64 20 24 70 61 73  getPassword $pas
4280: 73 77 6f 72 64 4e 61 6d 65 5d 0a 0a 09 73 65 74  swordName]...set
4290: 20 3a 3a 73 61 76 65 52 65 71 75 69 72 65 64 20   ::saveRequired 
42a0: 30 0a 7d 0a 0a 70 72 6f 63 20 75 70 64 61 74 65  0.}..proc update
42b0: 50 61 73 73 77 6f 72 64 20 7b 70 61 73 73 77 6f  Password {passwo
42c0: 72 64 4e 61 6d 65 20 70 61 73 73 77 6f 72 64 7d  rdName password}
42d0: 20 7b 0a 09 69 66 20 7b 24 70 61 73 73 77 6f 72   {..if {$passwor
42e0: 64 20 65 71 20 22 22 7d 20 7b 0a 09 09 73 65 74  d eq ""} {...set
42f0: 20 70 61 73 73 77 6f 72 64 20 5b 5f 70 72 6f 6d   password [_prom
4300: 70 74 20 22 50 6c 65 61 73 65 20 65 6e 74 65 72  pt "Please enter
4310: 20 74 68 65 20 6e 65 77 20 70 61 73 73 77 6f 72   the new passwor
4320: 64 3a 20 22 5d 0a 09 7d 0a 0a 09 73 65 74 20 6f  d: "]..}...set o
4330: 6c 64 50 61 73 73 77 6f 72 64 20 5b 5f 67 65 74  ldPassword [_get
4340: 50 61 73 73 77 6f 72 64 20 24 70 61 73 73 77 6f  Password $passwo
4350: 72 64 4e 61 6d 65 5d 0a 0a 09 73 65 74 20 70 75  rdName]...set pu
4360: 62 6c 69 63 4b 65 79 73 20 5b 5f 76 65 72 69 66  blicKeys [_verif
4370: 79 50 61 73 73 77 6f 72 64 20 24 70 61 73 73 77  yPassword $passw
4380: 6f 72 64 4e 61 6d 65 20 24 6f 6c 64 50 61 73 73  ordName $oldPass
4390: 77 6f 72 64 5d 0a 0a 09 69 66 20 7b 5b 6c 6c 65  word]...if {[lle
43a0: 6e 67 74 68 20 24 70 75 62 6c 69 63 4b 65 79 73  ngth $publicKeys
43b0: 5d 20 3d 3d 20 30 7d 20 7b 0a 09 09 70 75 74 73  ] == 0} {...puts
43c0: 20 73 74 64 65 72 72 20 22 57 61 72 6e 69 6e 67   stderr "Warning
43d0: 3a 20 54 68 69 73 20 77 69 6c 6c 20 64 65 6c 65  : This will dele
43e0: 74 65 20 74 68 65 20 70 61 73 73 77 6f 72 64 20  te the password 
43f0: 73 69 6e 63 65 20 74 68 65 72 65 20 61 72 65 20  since there are 
4400: 6e 6f 20 76 61 6c 69 64 20 70 75 62 6c 69 63 20  no valid public 
4410: 6b 65 79 73 2e 22 0a 09 7d 0a 0a 09 5f 61 64 64  keys."..}..._add
4420: 50 61 73 73 77 6f 72 64 20 24 70 61 73 73 77 6f  Password $passwo
4430: 72 64 4e 61 6d 65 20 24 70 61 73 73 77 6f 72 64  rdName $password
4440: 20 24 70 75 62 6c 69 63 4b 65 79 73 0a 7d 0a 0a   $publicKeys.}..
4450: 70 72 6f 63 20 64 65 6c 65 74 65 50 61 73 73 77  proc deletePassw
4460: 6f 72 64 20 7b 70 61 73 73 77 6f 72 64 4e 61 6d  ord {passwordNam
4470: 65 7d 20 7b 0a 09 64 62 20 65 76 61 6c 20 7b 44  e} {..db eval {D
4480: 45 4c 45 54 45 20 46 52 4f 4d 20 70 61 73 73 77  ELETE FROM passw
4490: 6f 72 64 73 20 57 48 45 52 45 20 6e 61 6d 65 20  ords WHERE name 
44a0: 3d 20 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 3b  = $passwordName;
44b0: 7d 0a 7d 0a 0a 70 72 6f 63 20 61 75 74 68 6f 72  }.}..proc author
44c0: 69 7a 65 55 73 65 72 73 20 7b 70 61 73 73 77 6f  izeUsers {passwo
44d0: 72 64 4e 61 6d 65 20 61 72 67 73 7d 20 7b 0a 09  rdName args} {..
44e0: 73 65 74 20 75 73 65 72 73 20 24 61 72 67 73 0a  set users $args.
44f0: 0a 09 5f 6d 6f 64 69 66 79 50 75 62 6c 69 63 4b  .._modifyPublicK
4500: 65 79 73 20 24 70 61 73 73 77 6f 72 64 4e 61 6d  eys $passwordNam
4510: 65 20 24 75 73 65 72 73 20 7b 0a 09 09 69 66 20  e $users {...if 
4520: 7b 24 72 6f 77 28 70 75 62 6c 69 63 4b 65 79 29  {$row(publicKey)
4530: 20 69 6e 20 24 70 75 62 6c 69 63 4b 65 79 73 7d   in $publicKeys}
4540: 20 7b 0a 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09   {....continue..
4550: 09 7d 0a 0a 09 09 6c 61 70 70 65 6e 64 20 70 75  .}....lappend pu
4560: 62 6c 69 63 4b 65 79 73 20 24 72 6f 77 28 70 75  blicKeys $row(pu
4570: 62 6c 69 63 4b 65 79 29 0a 0a 09 09 73 65 74 20  blicKey)....set 
4580: 63 68 61 6e 67 65 52 65 71 75 69 72 65 64 20 31  changeRequired 1
4590: 0a 09 7d 0a 7d 0a 0a 70 72 6f 63 20 61 75 74 68  ..}.}..proc auth
45a0: 6f 72 69 7a 65 55 73 65 72 20 7b 70 61 73 73 77  orizeUser {passw
45b0: 6f 72 64 4e 61 6d 65 20 75 73 65 72 4e 61 6d 65  ordName userName
45c0: 7d 20 7b 0a 09 72 65 74 75 72 6e 20 5b 61 75 74  } {..return [aut
45d0: 68 6f 72 69 7a 65 55 73 65 72 73 20 24 70 61 73  horizeUsers $pas
45e0: 73 77 6f 72 64 4e 61 6d 65 20 24 75 73 65 72 4e  swordName $userN
45f0: 61 6d 65 5d 0a 7d 0a 0a 70 72 6f 63 20 64 65 61  ame].}..proc dea
4600: 75 74 68 6f 72 69 7a 65 55 73 65 72 73 20 7b 70  uthorizeUsers {p
4610: 61 73 73 77 6f 72 64 4e 61 6d 65 20 61 72 67 73  asswordName args
4620: 7d 20 7b 0a 09 73 65 74 20 75 73 65 72 73 20 24  } {..set users $
4630: 61 72 67 73 0a 0a 09 5f 6d 6f 64 69 66 79 50 75  args..._modifyPu
4640: 62 6c 69 63 4b 65 79 73 20 24 70 61 73 73 77 6f  blicKeys $passwo
4650: 72 64 4e 61 6d 65 20 24 75 73 65 72 73 20 7b 0a  rdName $users {.
4660: 09 09 73 65 74 20 69 64 78 20 5b 6c 73 65 61 72  ..set idx [lsear
4670: 63 68 20 2d 65 78 61 63 74 20 24 70 75 62 6c 69  ch -exact $publi
4680: 63 4b 65 79 73 20 24 72 6f 77 28 70 75 62 6c 69  cKeys $row(publi
4690: 63 4b 65 79 29 5d 0a 09 09 69 66 20 7b 24 69 64  cKey)]...if {$id
46a0: 78 20 3d 3d 20 2d 31 7d 20 7b 0a 09 09 09 63 6f  x == -1} {....co
46b0: 6e 74 69 6e 75 65 0a 09 09 7d 0a 0a 09 09 73 65  ntinue...}....se
46c0: 74 20 70 75 62 6c 69 63 4b 65 79 73 20 5b 6c 72  t publicKeys [lr
46d0: 65 70 6c 61 63 65 20 24 70 75 62 6c 69 63 4b 65  eplace $publicKe
46e0: 79 73 20 24 69 64 78 20 24 69 64 78 5d 0a 0a 09  ys $idx $idx]...
46f0: 09 73 65 74 20 63 68 61 6e 67 65 52 65 71 75 69  .set changeRequi
4700: 72 65 64 20 31 0a 09 7d 0a 7d 0a 0a 70 72 6f 63  red 1..}.}..proc
4710: 20 64 65 61 75 74 68 6f 72 69 7a 65 55 73 65 72   deauthorizeUser
4720: 20 7b 70 61 73 73 77 6f 72 64 4e 61 6d 65 20 75   {passwordName u
4730: 73 65 72 4e 61 6d 65 7d 20 7b 0a 09 72 65 74 75  serName} {..retu
4740: 72 6e 20 5b 64 65 61 75 74 68 6f 72 69 7a 65 55  rn [deauthorizeU
4750: 73 65 72 73 20 24 70 61 73 73 77 6f 72 64 4e 61  sers $passwordNa
4760: 6d 65 20 24 75 73 65 72 4e 61 6d 65 5d 0a 7d 0a  me $userName].}.
4770: 0a 70 72 6f 63 20 77 68 6f 61 6d 69 20 7b 7d 20  .proc whoami {} 
4780: 7b 0a 09 66 6f 72 65 61 63 68 20 73 6c 6f 74 49  {..foreach slotI
4790: 6e 66 6f 44 69 63 74 20 5b 5f 6c 69 73 74 43 65  nfoDict [_listCe
47a0: 72 74 69 66 69 63 61 74 65 73 5d 20 7b 0a 09 09  rtificates] {...
47b0: 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69  unset -nocomplai
47c0: 6e 20 73 6c 6f 74 49 6e 66 6f 0a 09 09 61 72 72  n slotInfo...arr
47d0: 61 79 20 73 65 74 20 73 6c 6f 74 49 6e 66 6f 20  ay set slotInfo 
47e0: 24 73 6c 6f 74 49 6e 66 6f 44 69 63 74 0a 0a 09  $slotInfoDict...
47f0: 09 73 65 74 20 70 75 62 6b 65 79 20 24 73 6c 6f  .set pubkey $slo
4800: 74 49 6e 66 6f 28 70 75 62 6b 65 79 29 0a 0a 09  tInfo(pubkey)...
4810: 09 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61  .unset -nocompla
4820: 69 6e 20 72 6f 77 0a 09 09 64 62 20 65 76 61 6c  in row...db eval
4830: 20 7b 53 45 4c 45 43 54 20 6e 61 6d 65 20 46 52   {SELECT name FR
4840: 4f 4d 20 75 73 65 72 73 20 57 48 45 52 45 20 70  OM users WHERE p
4850: 75 62 6c 69 63 4b 65 79 20 3d 20 24 70 75 62 6b  ublicKey = $pubk
4860: 65 79 3b 7d 20 72 6f 77 20 7b 0a 09 09 09 73 65  ey;} row {....se
4870: 74 20 75 73 65 72 73 28 24 72 6f 77 28 6e 61 6d  t users($row(nam
4880: 65 29 29 20 31 0a 09 09 7d 0a 09 7d 0a 0a 09 70  e)) 1...}..}...p
4890: 75 74 73 20 5b 6a 6f 69 6e 20 5b 61 72 72 61 79  uts [join [array
48a0: 20 6e 61 6d 65 73 20 75 73 65 72 73 5d 20 7b 2c   names users] {,
48b0: 20 7d 5d 0a 0a 09 73 65 74 20 3a 3a 73 61 76 65   }]...set ::save
48c0: 52 65 71 75 69 72 65 64 20 30 0a 7d 0a 0a 70 72  Required 0.}..pr
48d0: 6f 63 20 68 65 6c 70 20 7b 7b 61 63 74 69 6f 6e  oc help {{action
48e0: 20 22 22 7d 7d 20 7b 0a 09 5f 70 72 69 6e 74 48   ""}} {.._printH
48f0: 65 6c 70 20 73 74 64 6f 75 74 20 24 61 63 74 69  elp stdout $acti
4900: 6f 6e 0a 0a 09 73 65 74 20 3a 3a 73 61 76 65 52  on...set ::saveR
4910: 65 71 75 69 72 65 64 20 30 0a 7d 0a 23 20 45 6e  equired 0.}.# En
4920: 64 20 75 73 65 72 20 43 4c 49 20 66 75 6e 63 74  d user CLI funct
4930: 69 6f 6e 73 0a 0a 23 23 23 20 4d 41 49 4e 0a 0a  ions..### MAIN..
4940: 5f 6c 6f 61 64 44 42 20 64 62 20 24 70 61 73 73  _loadDB db $pass
4950: 77 6f 72 64 46 69 6c 65 0a 0a 69 66 20 7b 24 61  wordFile..if {$a
4960: 63 74 69 6f 6e 20 69 6e 20 24 76 61 6c 69 64 43  ction in $validC
4970: 6f 6d 6d 61 6e 64 73 7d 20 7b 0a 09 69 66 20 7b  ommands} {..if {
4980: 5b 63 61 74 63 68 20 7b 0a 09 09 24 61 63 74 69  [catch {...$acti
4990: 6f 6e 20 7b 2a 7d 24 61 72 67 76 0a 09 7d 20 65  on {*}$argv..} e
49a0: 72 72 6f 72 5d 7d 20 7b 0a 09 09 70 75 74 73 20  rror]} {...puts 
49b0: 73 74 64 65 72 72 20 22 45 72 72 6f 72 3a 20 24  stderr "Error: $
49c0: 65 72 72 6f 72 22 0a 0a 09 09 65 78 69 74 20 31  error"....exit 1
49d0: 0a 09 7d 0a 7d 20 65 6c 73 65 20 7b 0a 09 70 75  ..}.} else {..pu
49e0: 74 73 20 73 74 64 65 72 72 20 22 49 6e 76 61 6c  ts stderr "Inval
49f0: 69 64 20 61 63 74 69 6f 6e 22 0a 0a 09 65 78 69  id action"...exi
4a00: 74 20 31 0a 7d 0a 0a 69 66 20 7b 24 3a 3a 73 61  t 1.}..if {$::sa
4a10: 76 65 52 65 71 75 69 72 65 64 7d 20 7b 0a 09 5f  veRequired} {.._
4a20: 73 61 76 65 44 42 20 64 62 20 24 70 61 73 73 77  saveDB db $passw
4a30: 6f 72 64 46 69 6c 65 0a 7d 0a 0a 64 62 20 63 6c  ordFile.}..db cl
4a40: 6f 73 65 0a 0a 65 78 69 74 20 30 0a              ose..exit 0.