Hex Artifact Content

Artifact 7d93abb92c1bf9eea35458e3ad7ad77ac8f01a7f:


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 3a 3a 64 65 66 61  AGE...set ::defa
05a0: 75 6c 74 57 72 61 70 4c 65 6e 67 74 68 20 36 30  ultWrapLength 60
05b0: 0a 0a 73 65 74 20 70 61 73 73 77 6f 72 64 46 69  ..set passwordFi
05c0: 6c 65 20 5b 6c 69 6e 64 65 78 20 24 61 72 67 76  le [lindex $argv
05d0: 20 30 5d 0a 73 65 74 20 61 63 74 69 6f 6e 20 5b   0].set action [
05e0: 6c 69 6e 64 65 78 20 24 61 72 67 76 20 31 5d 0a  lindex $argv 1].
05f0: 0a 73 65 74 20 76 61 6c 69 64 43 6f 6d 6d 61 6e  .set validComman
0600: 64 73 20 5b 6c 69 73 74 20 22 6c 69 73 74 4c 6f  ds [list "listLo
0610: 63 61 6c 4b 65 79 73 22 20 22 6c 69 73 74 50 61  calKeys" "listPa
0620: 73 73 77 6f 72 64 73 22 20 22 6c 69 73 74 41 76  sswords" "listAv
0630: 61 69 6c 61 62 6c 65 50 61 73 73 77 6f 72 64 73  ailablePasswords
0640: 22 20 22 6c 69 73 74 55 73 65 72 73 22 20 22 61  " "listUsers" "a
0650: 64 64 55 73 65 72 22 20 22 61 64 64 50 61 73 73  ddUser" "addPass
0660: 77 6f 72 64 22 20 22 61 75 74 68 6f 72 69 7a 65  word" "authorize
0670: 55 73 65 72 22 20 22 61 75 74 68 6f 72 69 7a 65  User" "authorize
0680: 55 73 65 72 73 22 20 22 64 65 61 75 74 68 6f 72  Users" "deauthor
0690: 69 7a 65 55 73 65 72 22 20 22 64 65 61 75 74 68  izeUser" "deauth
06a0: 6f 72 69 7a 65 55 73 65 72 73 22 20 22 67 65 74  orizeUsers" "get
06b0: 50 61 73 73 77 6f 72 64 22 20 22 75 70 64 61 74  Password" "updat
06c0: 65 50 61 73 73 77 6f 72 64 22 20 22 64 65 6c 65  ePassword" "dele
06d0: 74 65 50 61 73 73 77 6f 72 64 22 20 22 68 65 6c  tePassword" "hel
06e0: 70 22 20 22 77 68 6f 61 6d 69 22 5d 0a 0a 70 72  p" "whoami"]..pr
06f0: 6f 63 20 5f 61 72 67 44 65 73 63 72 69 70 74 69  oc _argDescripti
0700: 6f 6e 20 7b 63 6f 6d 6d 61 6e 64 20 61 72 67 4e  on {command argN
0710: 61 6d 65 7d 20 7b 0a 09 73 77 69 74 63 68 20 2d  ame} {..switch -
0720: 2d 20 24 61 72 67 4e 61 6d 65 20 7b 0a 09 09 22  - $argName {..."
0730: 70 61 73 73 77 6f 72 64 4e 61 6d 65 22 20 7b 0a  passwordName" {.
0740: 09 09 09 72 65 74 75 72 6e 20 22 24 61 72 67 4e  ...return "$argN
0750: 61 6d 65 20 2d 20 4e 61 6d 65 20 6f 66 20 74 68  ame - Name of th
0760: 65 20 70 61 73 73 77 6f 72 64 20 65 6e 74 72 79  e password entry
0770: 22 0a 09 09 7d 0a 09 09 22 6b 65 79 22 20 7b 0a  "...}..."key" {.
0780: 09 09 09 72 65 74 75 72 6e 20 22 24 61 72 67 4e  ...return "$argN
0790: 61 6d 65 20 2d 20 50 75 62 6c 69 63 20 6b 65 79  ame - Public key
07a0: 20 6f 66 20 74 68 65 20 75 73 65 72 22 0a 09 09   of the user"...
07b0: 7d 0a 09 09 22 70 61 73 73 77 6f 72 64 22 20 7b  }..."password" {
07c0: 0a 09 09 09 72 65 74 75 72 6e 20 22 24 61 72 67  ....return "$arg
07d0: 4e 61 6d 65 20 2d 20 41 20 70 6c 61 69 6e 2d 74  Name - A plain-t
07e0: 65 78 74 20 70 61 73 73 77 6f 72 64 22 0a 09 09  ext password"...
07f0: 7d 0a 09 09 22 75 73 65 72 4e 61 6d 65 22 20 7b  }..."userName" {
0800: 0a 09 09 09 72 65 74 75 72 6e 20 22 24 61 72 67  ....return "$arg
0810: 4e 61 6d 65 20 2d 20 41 20 75 73 65 72 20 6e 61  Name - A user na
0820: 6d 65 22 0a 09 09 7d 0a 09 09 22 61 63 74 69 6f  me"...}..."actio
0830: 6e 22 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 22  n" {....return "
0840: 24 61 72 67 4e 61 6d 65 20 2d 20 41 6e 20 61 63  $argName - An ac
0850: 74 69 6f 6e 20 6e 61 6d 65 20 66 6f 72 20 68 65  tion name for he
0860: 6c 70 20 77 69 74 68 22 0a 09 09 7d 0a 09 09 22  lp with"...}..."
0870: 61 72 67 73 22 20 7b 0a 09 09 09 72 65 74 75 72  args" {....retur
0880: 6e 20 22 75 73 65 72 4c 69 73 74 20 2d 20 41 20  n "userList - A 
0890: 6c 69 73 74 20 6f 66 20 75 73 65 72 6e 61 6d 65  list of username
08a0: 73 22 0a 09 09 7d 0a 09 7d 0a 0a 09 72 65 74 75  s"...}..}...retu
08b0: 72 6e 20 22 3c 55 4e 4b 4e 4f 57 4e 3e 22 0a 7d  rn "<UNKNOWN>".}
08c0: 0a 0a 70 72 6f 63 20 5f 77 72 61 70 53 74 72 69  ..proc _wrapStri
08d0: 6e 67 20 7b 73 74 72 69 6e 67 20 77 69 64 74 68  ng {string width
08e0: 20 7b 70 72 65 66 69 78 20 22 22 7d 7d 20 7b 0a   {prefix ""}} {.
08f0: 09 73 65 74 20 6e 65 77 53 74 72 69 6e 67 20 22  .set newString "
0900: 22 0a 0a 09 73 65 74 20 70 72 65 66 69 78 57 69  "...set prefixWi
0910: 64 74 68 20 5b 73 74 72 69 6e 67 20 6c 65 6e 67  dth [string leng
0920: 74 68 20 24 70 72 65 66 69 78 5d 0a 09 73 65 74  th $prefix]..set
0930: 20 77 69 64 74 68 20 5b 65 78 70 72 20 7b 24 77   width [expr {$w
0940: 69 64 74 68 20 2d 20 24 70 72 65 66 69 78 57 69  idth - $prefixWi
0950: 64 74 68 7d 5d 0a 09 77 68 69 6c 65 20 7b 5b 73  dth}]..while {[s
0960: 74 72 69 6e 67 20 6c 65 6e 67 74 68 20 24 73 74  tring length $st
0970: 72 69 6e 67 5d 20 3e 20 30 7d 20 7b 0a 09 09 69  ring] > 0} {...i
0980: 66 20 7b 5b 73 74 72 69 6e 67 20 6c 65 6e 67 74  f {[string lengt
0990: 68 20 24 73 74 72 69 6e 67 5d 20 3e 20 24 77 69  h $string] > $wi
09a0: 64 74 68 7d 20 7b 0a 09 09 09 73 65 74 20 73 75  dth} {....set su
09b0: 62 53 74 72 69 6e 67 49 6e 64 65 78 20 5b 73 74  bStringIndex [st
09c0: 72 69 6e 67 20 6c 61 73 74 20 22 20 22 20 24 73  ring last " " $s
09d0: 74 72 69 6e 67 20 24 77 69 64 74 68 5d 0a 0a 09  tring $width]...
09e0: 09 09 69 66 20 7b 24 73 75 62 53 74 72 69 6e 67  ..if {$subString
09f0: 49 6e 64 65 78 20 3d 3d 20 2d 31 7d 20 7b 0a 09  Index == -1} {..
0a00: 09 09 09 73 65 74 20 73 75 62 53 74 72 69 6e 67  ...set subString
0a10: 49 6e 64 65 78 20 5b 73 74 72 69 6e 67 20 66 69  Index [string fi
0a20: 72 73 74 20 22 20 22 20 24 73 74 72 69 6e 67 5d  rst " " $string]
0a30: 0a 09 09 09 7d 0a 09 09 7d 20 65 6c 73 65 20 7b  ....}...} else {
0a40: 0a 09 09 09 73 65 74 20 73 75 62 53 74 72 69 6e  ....set subStrin
0a50: 67 49 6e 64 65 78 20 2d 31 0a 09 09 7d 0a 0a 09  gIndex -1...}...
0a60: 09 69 66 20 7b 24 73 75 62 53 74 72 69 6e 67 49  .if {$subStringI
0a70: 6e 64 65 78 20 3d 3d 20 2d 31 7d 20 7b 0a 09 09  ndex == -1} {...
0a80: 09 73 65 74 20 73 75 62 53 74 72 69 6e 67 49 6e  .set subStringIn
0a90: 64 65 78 20 65 6e 64 0a 09 09 7d 0a 09 09 73 65  dex end...}...se
0aa0: 74 20 73 75 62 53 74 72 69 6e 67 20 5b 73 74 72  t subString [str
0ab0: 69 6e 67 20 74 72 69 6d 20 5b 73 74 72 69 6e 67  ing trim [string
0ac0: 20 72 61 6e 67 65 20 24 73 74 72 69 6e 67 20 30   range $string 0
0ad0: 20 24 73 75 62 53 74 72 69 6e 67 49 6e 64 65 78   $subStringIndex
0ae0: 5d 5d 0a 09 09 73 65 74 20 73 74 72 69 6e 67 20  ]]...set string 
0af0: 5b 73 74 72 69 6e 67 20 74 72 69 6d 20 5b 73 74  [string trim [st
0b00: 72 69 6e 67 20 72 61 6e 67 65 20 24 73 74 72 69  ring range $stri
0b10: 6e 67 20 24 73 75 62 53 74 72 69 6e 67 49 6e 64  ng $subStringInd
0b20: 65 78 2b 31 20 65 6e 64 5d 5d 0a 0a 09 09 61 70  ex+1 end]]....ap
0b30: 70 65 6e 64 20 6e 65 77 53 74 72 69 6e 67 20 24  pend newString $
0b40: 70 72 65 66 69 78 0a 09 09 61 70 70 65 6e 64 20  prefix...append 
0b50: 6e 65 77 53 74 72 69 6e 67 20 24 73 75 62 53 74  newString $subSt
0b60: 72 69 6e 67 0a 09 09 69 66 20 7b 24 73 74 72 69  ring...if {$stri
0b70: 6e 67 20 6e 65 20 22 22 7d 20 7b 0a 09 09 09 61  ng ne ""} {....a
0b80: 70 70 65 6e 64 20 6e 65 77 53 74 72 69 6e 67 20  ppend newString 
0b90: 22 5c 6e 22 0a 09 09 7d 0a 09 7d 0a 0a 09 72 65  "\n"...}..}...re
0ba0: 74 75 72 6e 20 24 6e 65 77 53 74 72 69 6e 67 0a  turn $newString.
0bb0: 7d 0a 0a 70 72 6f 63 20 5f 70 72 69 6e 74 48 65  }..proc _printHe
0bc0: 6c 70 20 7b 63 68 61 6e 6e 65 6c 20 63 6f 6d 6d  lp {channel comm
0bd0: 61 6e 64 7d 20 7b 0a 09 69 66 20 7b 24 63 6f 6d  and} {..if {$com
0be0: 6d 61 6e 64 20 3d 3d 20 22 22 7d 20 7b 0a 09 09  mand == ""} {...
0bf0: 70 75 74 73 20 24 63 68 61 6e 6e 65 6c 20 22 55  puts $channel "U
0c00: 73 61 67 65 3a 20 68 75 6e 74 65 72 32 20 3c 70  sage: hunter2 <p
0c10: 61 73 73 77 6f 72 64 46 69 6c 65 3e 20 3c 61 63  asswordFile> <ac
0c20: 74 69 6f 6e 3e 20 5c 5b 3c 61 63 74 69 6f 6e 41  tion> \[<actionA
0c30: 72 67 73 2e 2e 2e 3e 5c 5d 22 0a 09 09 70 75 74  rgs...>\]"...put
0c40: 73 20 24 63 68 61 6e 6e 65 6c 20 22 22 0a 09 09  s $channel ""...
0c50: 70 75 74 73 20 24 63 68 61 6e 6e 65 6c 20 22 41  puts $channel "A
0c60: 63 74 69 6f 6e 73 3a 22 0a 09 09 70 75 74 73 20  ctions:"...puts 
0c70: 24 63 68 61 6e 6e 65 6c 20 22 5b 5f 77 72 61 70  $channel "[_wrap
0c80: 53 74 72 69 6e 67 20 5b 6a 6f 69 6e 20 24 3a 3a  String [join $::
0c90: 76 61 6c 69 64 43 6f 6d 6d 61 6e 64 73 20 7b 2c  validCommands {,
0ca0: 20 7d 5d 20 24 3a 3a 64 65 66 61 75 6c 74 57 72   }] $::defaultWr
0cb0: 61 70 4c 65 6e 67 74 68 20 7b 20 20 20 20 7d 5d  apLength {    }]
0cc0: 22 0a 09 09 70 75 74 73 20 24 63 68 61 6e 6e 65  "...puts $channe
0cd0: 6c 20 22 22 0a 09 09 70 75 74 73 20 24 63 68 61  l ""...puts $cha
0ce0: 6e 6e 65 6c 20 22 20 20 20 20 68 75 6e 74 65 72  nnel "    hunter
0cf0: 32 20 3c 66 69 6c 65 3e 20 68 65 6c 70 20 3c 61  2 <file> help <a
0d00: 63 74 69 6f 6e 3e 20 20 20 20 66 6f 72 20 68 65  ction>    for he
0d10: 6c 70 20 77 69 74 68 20 61 6e 20 61 63 74 69 6f  lp with an actio
0d20: 6e 22 0a 09 7d 20 65 6c 73 65 20 7b 0a 09 09 73  n"..} else {...s
0d30: 65 74 20 61 72 67 73 20 5b 69 6e 66 6f 20 61 72  et args [info ar
0d40: 67 73 20 24 63 6f 6d 6d 61 6e 64 5d 0a 09 09 73  gs $command]...s
0d50: 65 74 20 70 72 69 6e 74 41 72 67 73 20 5b 6c 69  et printArgs [li
0d60: 73 74 5d 0a 09 09 66 6f 72 65 61 63 68 20 61 72  st]...foreach ar
0d70: 67 20 24 61 72 67 73 20 7b 0a 09 09 09 69 66 20  g $args {....if 
0d80: 7b 24 61 72 67 20 3d 3d 20 22 61 72 67 73 22 7d  {$arg == "args"}
0d90: 20 7b 0a 09 09 09 09 73 65 74 20 61 72 67 20 22   {.....set arg "
0da0: 75 73 65 72 4c 69 73 74 22 0a 09 09 09 7d 0a 09  userList"....}..
0db0: 09 09 6c 61 70 70 65 6e 64 20 70 72 69 6e 74 41  ..lappend printA
0dc0: 72 67 73 20 22 3c 24 61 72 67 3e 22 0a 09 09 7d  rgs "<$arg>"...}
0dd0: 0a 0a 09 09 70 75 74 73 20 24 63 68 61 6e 6e 65  ....puts $channe
0de0: 6c 20 22 55 73 61 67 65 3a 20 68 75 6e 74 65 72  l "Usage: hunter
0df0: 32 20 3c 70 61 73 73 77 6f 72 64 46 69 6c 65 3e  2 <passwordFile>
0e00: 20 24 63 6f 6d 6d 61 6e 64 20 5b 6a 6f 69 6e 20   $command [join 
0e10: 24 70 72 69 6e 74 41 72 67 73 5d 22 0a 0a 09 09  $printArgs]"....
0e20: 69 66 20 7b 5b 6c 6c 65 6e 67 74 68 20 24 61 72  if {[llength $ar
0e30: 67 73 5d 20 3e 20 30 7d 20 7b 0a 09 09 09 70 75  gs] > 0} {....pu
0e40: 74 73 20 24 63 68 61 6e 6e 65 6c 20 22 22 0a 09  ts $channel ""..
0e50: 09 09 70 75 74 73 20 24 63 68 61 6e 6e 65 6c 20  ..puts $channel 
0e60: 22 41 72 67 75 6d 65 6e 74 73 3a 22 0a 09 09 09  "Arguments:"....
0e70: 66 6f 72 65 61 63 68 20 61 72 67 20 24 61 72 67  foreach arg $arg
0e80: 73 20 7b 0a 09 09 09 09 70 75 74 73 20 24 63 68  s {.....puts $ch
0e90: 61 6e 6e 65 6c 20 22 20 20 20 20 5b 5f 61 72 67  annel "    [_arg
0ea0: 44 65 73 63 72 69 70 74 69 6f 6e 20 24 63 6f 6d  Description $com
0eb0: 6d 61 6e 64 20 24 61 72 67 5d 22 0a 09 09 09 7d  mand $arg]"....}
0ec0: 0a 09 09 7d 0a 09 7d 0a 7d 0a 0a 69 66 20 7b 5b  ...}..}.}..if {[
0ed0: 6c 6c 65 6e 67 74 68 20 24 61 72 67 76 5d 20 3c  llength $argv] <
0ee0: 20 32 7d 20 7b 0a 09 5f 70 72 69 6e 74 48 65 6c   2} {.._printHel
0ef0: 70 20 73 74 64 65 72 72 20 22 22 0a 0a 09 65 78  p stderr ""...ex
0f00: 69 74 20 31 0a 7d 0a 0a 73 65 74 20 61 72 67 76  it 1.}..set argv
0f10: 20 5b 6c 72 61 6e 67 65 20 24 61 72 67 76 20 32   [lrange $argv 2
0f20: 20 65 6e 64 5d 0a 0a 23 20 57 65 20 6e 65 65 64   end]..# We need
0f30: 20 54 63 6c 20 38 2e 36 20 66 6f 72 20 5b 62 69   Tcl 8.6 for [bi
0f40: 6e 61 72 79 20 65 6e 63 6f 64 65 20 62 61 73 65  nary encode base
0f50: 36 34 5d 0a 70 61 63 6b 61 67 65 20 72 65 71 75  64].package requ
0f60: 69 72 65 20 54 63 6c 20 38 2e 36 0a 70 61 63 6b  ire Tcl 8.6.pack
0f70: 61 67 65 20 72 65 71 75 69 72 65 20 73 71 6c 69  age require sqli
0f80: 74 65 33 0a 70 61 63 6b 61 67 65 20 72 65 71 75  te3.package requ
0f90: 69 72 65 20 70 6c 61 74 66 6f 72 6d 0a 0a 6c 61  ire platform..la
0fa0: 70 70 65 6e 64 20 3a 3a 61 75 74 6f 5f 70 61 74  ppend ::auto_pat
0fb0: 68 20 5b 66 69 6c 65 20 6a 6f 69 6e 20 5b 66 69  h [file join [fi
0fc0: 6c 65 20 64 69 72 6e 61 6d 65 20 5b 69 6e 66 6f  le dirname [info
0fd0: 20 73 63 72 69 70 74 5d 5d 20 6c 69 62 20 5b 70   script]] lib [p
0fe0: 6c 61 74 66 6f 72 6d 3a 3a 69 64 65 6e 74 69 66  latform::identif
0ff0: 79 5d 5d 0a 6c 61 70 70 65 6e 64 20 3a 3a 61 75  y]].lappend ::au
1000: 74 6f 5f 70 61 74 68 20 5b 66 69 6c 65 20 6a 6f  to_path [file jo
1010: 69 6e 20 5b 66 69 6c 65 20 64 69 72 6e 61 6d 65  in [file dirname
1020: 20 5b 69 6e 66 6f 20 73 63 72 69 70 74 5d 5d 20   [info script]] 
1030: 6c 69 62 20 5b 70 6c 61 74 66 6f 72 6d 3a 3a 67  lib [platform::g
1040: 65 6e 65 72 69 63 5d 5d 0a 6c 61 70 70 65 6e 64  eneric]].lappend
1050: 20 3a 3a 61 75 74 6f 5f 70 61 74 68 20 5b 66 69   ::auto_path [fi
1060: 6c 65 20 6a 6f 69 6e 20 5b 66 69 6c 65 20 64 69  le join [file di
1070: 72 6e 61 6d 65 20 5b 69 6e 66 6f 20 73 63 72 69  rname [info scri
1080: 70 74 5d 5d 20 6c 69 62 5d 0a 0a 70 61 63 6b 61  pt]] lib]..packa
1090: 67 65 20 72 65 71 75 69 72 65 20 70 6b 69 0a 70  ge require pki.p
10a0: 61 63 6b 61 67 65 20 72 65 71 75 69 72 65 20 70  ackage require p
10b0: 6b 69 3a 3a 70 6b 63 73 31 31 0a 70 61 63 6b 61  ki::pkcs11.packa
10c0: 67 65 20 72 65 71 75 69 72 65 20 61 65 73 0a 70  ge require aes.p
10d0: 61 63 6b 61 67 65 20 72 65 71 75 69 72 65 20 73  ackage require s
10e0: 68 61 32 35 36 0a 0a 23 20 42 61 63 6b 70 6f 72  ha256..# Backpor
10f0: 74 73 20 66 6f 72 20 6f 6c 64 65 72 20 76 65 72  ts for older ver
1100: 73 69 6f 6e 73 20 6f 66 20 22 70 6b 69 22 0a 70  sions of "pki".p
1110: 72 6f 63 20 3a 3a 70 6b 69 3a 3a 70 6b 63 73 3a  roc ::pki::pkcs:
1120: 3a 70 61 72 73 65 5f 70 75 62 6c 69 63 5f 6b 65  :parse_public_ke
1130: 79 20 7b 6b 65 79 20 7b 70 61 73 73 77 6f 72 64  y {key {password
1140: 20 22 22 7d 7d 20 7b 0a 20 20 20 20 20 20 20 20   ""}} {.        
1150: 61 72 72 61 79 20 73 65 74 20 70 61 72 73 65 64  array set parsed
1160: 5f 6b 65 79 20 5b 3a 3a 70 6b 69 3a 3a 5f 70 61  _key [::pki::_pa
1170: 72 73 65 5f 70 65 6d 20 24 6b 65 79 20 22 2d 2d  rse_pem $key "--
1180: 2d 2d 2d 42 45 47 49 4e 20 50 55 42 4c 49 43 20  ---BEGIN PUBLIC 
1190: 4b 45 59 2d 2d 2d 2d 2d 22 20 22 2d 2d 2d 2d 2d  KEY-----" "-----
11a0: 45 4e 44 20 50 55 42 4c 49 43 20 4b 45 59 2d 2d  END PUBLIC KEY--
11b0: 2d 2d 2d 22 20 24 70 61 73 73 77 6f 72 64 5d 0a  ---" $password].
11c0: 0a 20 20 20 20 20 20 20 20 73 65 74 20 6b 65 79  .        set key
11d0: 5f 73 65 71 20 24 70 61 72 73 65 64 5f 6b 65 79  _seq $parsed_key
11e0: 28 64 61 74 61 29 0a 0a 20 20 20 20 20 20 20 20  (data)..        
11f0: 3a 3a 61 73 6e 3a 3a 61 73 6e 47 65 74 53 65 71  ::asn::asnGetSeq
1200: 75 65 6e 63 65 20 6b 65 79 5f 73 65 71 20 70 75  uence key_seq pu
1210: 62 6b 65 79 69 6e 66 6f 0a 20 20 20 20 20 20 20  bkeyinfo.       
1220: 20 20 20 20 20 20 20 20 20 3a 3a 61 73 6e 3a 3a           ::asn::
1230: 61 73 6e 47 65 74 53 65 71 75 65 6e 63 65 20 70  asnGetSequence p
1240: 75 62 6b 65 79 69 6e 66 6f 20 70 75 62 6b 65 79  ubkeyinfo pubkey
1250: 5f 61 6c 67 6f 69 64 0a 20 20 20 20 20 20 20 20  _algoid.        
1260: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1270: 3a 3a 61 73 6e 3a 3a 61 73 6e 47 65 74 4f 62 6a  ::asn::asnGetObj
1280: 65 63 74 49 64 65 6e 74 69 66 69 65 72 20 70 75  ectIdentifier pu
1290: 62 6b 65 79 5f 61 6c 67 6f 69 64 20 6f 69 64 0a  bkey_algoid oid.
12a0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
12b0: 3a 3a 61 73 6e 3a 3a 61 73 6e 47 65 74 42 69 74  ::asn::asnGetBit
12c0: 53 74 72 69 6e 67 20 70 75 62 6b 65 79 69 6e 66  String pubkeyinf
12d0: 6f 20 70 75 62 6b 65 79 0a 20 20 20 20 20 20 20  o pubkey.       
12e0: 20 73 65 74 20 72 65 74 28 70 75 62 6b 65 79 5f   set ret(pubkey_
12f0: 61 6c 67 6f 29 20 5b 3a 3a 70 6b 69 3a 3a 5f 6f  algo) [::pki::_o
1300: 69 64 5f 6e 75 6d 62 65 72 5f 74 6f 5f 6e 61 6d  id_number_to_nam
1310: 65 20 24 6f 69 64 5d 0a 0a 20 20 20 20 20 20 20  e $oid]..       
1320: 20 73 77 69 74 63 68 20 2d 2d 20 24 72 65 74 28   switch -- $ret(
1330: 70 75 62 6b 65 79 5f 61 6c 67 6f 29 20 7b 0a 20  pubkey_algo) {. 
1340: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 22                 "
1350: 72 73 61 45 6e 63 72 79 70 74 69 6f 6e 22 20 7b  rsaEncryption" {
1360: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
1370: 20 20 20 20 20 20 20 20 20 73 65 74 20 70 75 62           set pub
1380: 6b 65 79 20 5b 62 69 6e 61 72 79 20 66 6f 72 6d  key [binary form
1390: 61 74 20 42 2a 20 24 70 75 62 6b 65 79 5d 0a 0a  at B* $pubkey]..
13a0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
13b0: 20 20 20 20 20 20 20 20 3a 3a 61 73 6e 3a 3a 61          ::asn::a
13c0: 73 6e 47 65 74 53 65 71 75 65 6e 63 65 20 70 75  snGetSequence pu
13d0: 62 6b 65 79 20 70 75 62 6b 65 79 5f 70 61 72 74  bkey pubkey_part
13e0: 73 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  s.              
13f0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1400: 20 20 3a 3a 61 73 6e 3a 3a 61 73 6e 47 65 74 42    ::asn::asnGetB
1410: 69 67 49 6e 74 65 67 65 72 20 70 75 62 6b 65 79  igInteger pubkey
1420: 5f 70 61 72 74 73 20 72 65 74 28 6e 29 0a 20 20  _parts ret(n).  
1430: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1440: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 3a 3a                ::
1450: 61 73 6e 3a 3a 61 73 6e 47 65 74 42 69 67 49 6e  asn::asnGetBigIn
1460: 74 65 67 65 72 20 70 75 62 6b 65 79 5f 70 61 72  teger pubkey_par
1470: 74 73 20 72 65 74 28 65 29 0a 0a 20 20 20 20 20  ts ret(e)..     
1480: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1490: 20 20 20 73 65 74 20 72 65 74 28 6e 29 20 5b 3a     set ret(n) [:
14a0: 3a 6d 61 74 68 3a 3a 62 69 67 6e 75 6d 3a 3a 74  :math::bignum::t
14b0: 6f 73 74 72 20 24 72 65 74 28 6e 29 5d 0a 20 20  ostr $ret(n)].  
14c0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
14d0: 20 20 20 20 20 20 73 65 74 20 72 65 74 28 65 29        set ret(e)
14e0: 20 5b 3a 3a 6d 61 74 68 3a 3a 62 69 67 6e 75 6d   [::math::bignum
14f0: 3a 3a 74 6f 73 74 72 20 24 72 65 74 28 65 29 5d  ::tostr $ret(e)]
1500: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
1510: 20 20 20 20 20 20 20 20 20 73 65 74 20 72 65 74           set ret
1520: 28 6c 29 20 5b 65 78 70 72 20 7b 69 6e 74 28 5b  (l) [expr {int([
1530: 3a 3a 70 6b 69 3a 3a 5f 62 69 74 73 20 24 72 65  ::pki::_bits $re
1540: 74 28 6e 29 5d 20 2f 20 38 2e 30 30 30 30 20 2b  t(n)] / 8.0000 +
1550: 20 30 2e 35 29 20 2a 20 38 7d 5d 0a 20 20 20 20   0.5) * 8}].    
1560: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1570: 20 20 20 20 73 65 74 20 72 65 74 28 74 79 70 65      set ret(type
1580: 29 20 72 73 61 0a 20 20 20 20 20 20 20 20 20 20  ) rsa.          
1590: 20 20 20 20 20 20 7d 0a 20 20 20 20 20 20 20 20        }.        
15a0: 20 20 20 20 20 20 20 20 64 65 66 61 75 6c 74 20          default 
15b0: 7b 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  {.              
15c0: 20 20 20 20 20 20 20 20 20 20 65 72 72 6f 72 20            error 
15d0: 22 55 6e 6b 6e 6f 77 6e 20 61 6c 67 6f 72 69 74  "Unknown algorit
15e0: 68 6d 22 0a 20 20 20 20 20 20 20 20 20 20 20 20  hm".            
15f0: 20 20 20 20 7d 0a 20 20 20 20 20 20 20 20 7d 0a      }.        }.
1600: 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20  .        return 
1610: 5b 61 72 72 61 79 20 67 65 74 20 72 65 74 5d 0a  [array get ret].
1620: 7d 0a 0a 70 72 6f 63 20 3a 3a 70 6b 69 3a 3a 72  }..proc ::pki::r
1630: 73 61 3a 3a 73 65 72 69 61 6c 69 7a 65 5f 70 75  sa::serialize_pu
1640: 62 6c 69 63 5f 6b 65 79 20 7b 6b 65 79 6c 69 73  blic_key {keylis
1650: 74 7d 20 7b 0a 20 20 20 20 20 20 20 20 61 72 72  t} {.        arr
1660: 61 79 20 73 65 74 20 6b 65 79 20 24 6b 65 79 6c  ay set key $keyl
1670: 69 73 74 0a 0a 20 20 20 20 20 20 20 20 66 6f 72  ist..        for
1680: 65 61 63 68 20 65 6e 74 72 79 20 5b 6c 69 73 74  each entry [list
1690: 20 6e 20 65 5d 20 7b 0a 20 20 20 20 20 20 20 20   n e] {.        
16a0: 20 20 20 20 20 20 20 20 69 66 20 7b 21 5b 69 6e          if {![in
16b0: 66 6f 20 65 78 69 73 74 73 20 6b 65 79 28 24 65  fo exists key($e
16c0: 6e 74 72 79 29 5d 7d 20 7b 0a 20 20 20 20 20 20  ntry)]} {.      
16d0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
16e0: 20 20 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65    return -code e
16f0: 72 72 6f 72 20 22 4b 65 79 20 64 6f 65 73 20 6e  rror "Key does n
1700: 6f 74 20 63 6f 6e 74 61 69 6e 20 61 6e 20 65 6c  ot contain an el
1710: 65 6d 65 6e 74 20 24 65 6e 74 72 79 22 0a 20 20  ement $entry".  
1720: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7d 0a                }.
1730: 20 20 20 20 20 20 20 20 7d 0a 0a 20 20 20 20 20          }..     
1740: 20 20 20 73 65 74 20 70 75 62 6b 65 79 20 5b 3a     set pubkey [:
1750: 3a 61 73 6e 3a 3a 61 73 6e 53 65 71 75 65 6e 63  :asn::asnSequenc
1760: 65 20 5c 0a 20 20 20 20 20 20 20 20 20 20 20 20  e \.            
1770: 20 20 20 20 5b 3a 3a 61 73 6e 3a 3a 61 73 6e 42      [::asn::asnB
1780: 69 67 49 6e 74 65 67 65 72 20 5b 3a 3a 6d 61 74  igInteger [::mat
1790: 68 3a 3a 62 69 67 6e 75 6d 3a 3a 66 72 6f 6d 73  h::bignum::froms
17a0: 74 72 20 24 6b 65 79 28 6e 29 5d 5d 20 5c 0a 20  tr $key(n)]] \. 
17b0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 5b                 [
17c0: 3a 3a 61 73 6e 3a 3a 61 73 6e 42 69 67 49 6e 74  ::asn::asnBigInt
17d0: 65 67 65 72 20 5b 3a 3a 6d 61 74 68 3a 3a 62 69  eger [::math::bi
17e0: 67 6e 75 6d 3a 3a 66 72 6f 6d 73 74 72 20 24 6b  gnum::fromstr $k
17f0: 65 79 28 65 29 5d 5d 20 5c 0a 20 20 20 20 20 20  ey(e)]] \.      
1800: 20 20 20 20 20 20 20 20 20 20 5d 20 20 0a 20 20            ]  .  
1810: 20 20 20 20 20 20 73 65 74 20 70 75 62 6b 65 79        set pubkey
1820: 5f 61 6c 67 6f 5f 70 61 72 61 6d 73 20 5b 3a 3a  _algo_params [::
1830: 61 73 6e 3a 3a 61 73 6e 4e 75 6c 6c 5d 0a 0a 20  asn::asnNull].. 
1840: 20 20 20 20 20 20 20 62 69 6e 61 72 79 20 73 63         binary sc
1850: 61 6e 20 24 70 75 62 6b 65 79 20 42 2a 20 70 75  an $pubkey B* pu
1860: 62 6b 65 79 5f 62 69 74 73 74 72 69 6e 67 0a 0a  bkey_bitstring..
1870: 20 20 20 20 20 20 20 20 73 65 74 20 72 65 74 20          set ret 
1880: 5b 3a 3a 61 73 6e 3a 3a 61 73 6e 53 65 71 75 65  [::asn::asnSeque
1890: 6e 63 65 20 5c 0a 20 20 20 20 20 20 20 20 20 20  nce \.          
18a0: 20 20 20 20 20 20 5b 3a 3a 61 73 6e 3a 3a 61 73        [::asn::as
18b0: 6e 53 65 71 75 65 6e 63 65 20 5c 0a 20 20 20 20  nSequence \.    
18c0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
18d0: 20 20 20 20 20 20 20 20 20 20 20 20 5b 3a 3a 61              [::a
18e0: 73 6e 3a 3a 61 73 6e 4f 62 6a 65 63 74 49 64 65  sn::asnObjectIde
18f0: 6e 74 69 66 69 65 72 20 5b 3a 3a 70 6b 69 3a 3a  ntifier [::pki::
1900: 5f 6f 69 64 5f 6e 61 6d 65 5f 74 6f 5f 6e 75 6d  _oid_name_to_num
1910: 62 65 72 20 72 73 61 45 6e 63 72 79 70 74 69 6f  ber rsaEncryptio
1920: 6e 5d 5d 20 5c 0a 20 20 20 20 20 20 20 20 20 20  n]] \.          
1930: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1940: 20 20 20 20 20 20 24 70 75 62 6b 65 79 5f 61 6c        $pubkey_al
1950: 67 6f 5f 70 61 72 61 6d 73 20 5c 0a 20 20 20 20  go_params \.    
1960: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1970: 20 20 20 20 5d 20 5c 0a 20 20 20 20 20 20 20 20      ] \.        
1980: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1990: 5b 3a 3a 61 73 6e 3a 3a 61 73 6e 42 69 74 53 74  [::asn::asnBitSt
19a0: 72 69 6e 67 20 24 70 75 62 6b 65 79 5f 62 69 74  ring $pubkey_bit
19b0: 73 74 72 69 6e 67 5d 20 5c 0a 20 20 20 20 20 20  string] \.      
19c0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
19d0: 20 20 5d 0a 0a 20 20 20 20 20 20 20 20 72 65 74    ]..        ret
19e0: 75 72 6e 20 5b 6c 69 73 74 20 64 61 74 61 20 24  urn [list data $
19f0: 72 65 74 20 62 65 67 69 6e 20 22 2d 2d 2d 2d 2d  ret begin "-----
1a00: 42 45 47 49 4e 20 50 55 42 4c 49 43 20 4b 45 59  BEGIN PUBLIC KEY
1a10: 2d 2d 2d 2d 2d 22 20 65 6e 64 20 22 2d 2d 2d 2d  -----" end "----
1a20: 2d 45 4e 44 20 50 55 42 4c 49 43 20 4b 45 59 2d  -END PUBLIC KEY-
1a30: 2d 2d 2d 2d 22 5d 0a 7d 0a 23 20 45 6e 64 20 62  ----"].}.# End b
1a40: 61 63 6b 70 6f 72 74 73 0a 0a 23 20 53 74 61 72  ackports..# Star
1a50: 74 20 69 6e 74 65 72 6e 61 6c 20 66 75 6e 63 74  t internal funct
1a60: 69 6f 6e 73 0a 70 72 6f 63 20 5f 6c 6f 61 64 44  ions.proc _loadD
1a70: 42 20 7b 64 62 43 6d 64 20 66 69 6c 65 4e 61 6d  B {dbCmd fileNam
1a80: 65 7d 20 7b 0a 09 73 65 74 20 3a 3a 73 61 76 65  e} {..set ::save
1a90: 52 65 71 75 69 72 65 64 20 31 0a 0a 09 69 66 20  Required 1...if 
1aa0: 7b 5b 66 69 6c 65 20 65 78 69 73 74 73 20 24 66  {[file exists $f
1ab0: 69 6c 65 4e 61 6d 65 5d 7d 20 7b 0a 09 09 73 65  ileName]} {...se
1ac0: 74 20 66 64 20 5b 6f 70 65 6e 20 24 66 69 6c 65  t fd [open $file
1ad0: 4e 61 6d 65 5d 0a 0a 09 09 23 20 56 65 72 69 66  Name]....# Verif
1ae0: 79 20 74 68 61 74 20 77 65 20 68 61 76 65 20 61  y that we have a
1af0: 20 76 61 6c 69 64 20 66 69 6c 65 0a 09 09 67 65   valid file...ge
1b00: 74 73 20 24 66 64 20 68 65 61 64 65 72 0a 0a 09  ts $fd header...
1b10: 09 23 20 49 67 6e 6f 72 65 20 74 68 65 20 66 69  .# Ignore the fi
1b20: 72 73 74 20 6c 69 6e 65 20 69 66 20 69 74 20 69  rst line if it i
1b30: 73 20 61 20 68 61 73 68 2d 62 61 6e 67 20 61 73  s a hash-bang as
1b40: 20 77 65 6c 6c 0a 09 09 69 66 20 7b 5b 73 74 72   well...if {[str
1b50: 69 6e 67 20 72 61 6e 67 65 20 24 68 65 61 64 65  ing range $heade
1b60: 72 20 30 20 31 5d 20 3d 3d 20 22 23 21 22 7d 20  r 0 1] == "#!"} 
1b70: 7b 0a 09 09 09 73 65 74 20 3a 3a 67 6c 6f 62 61  {....set ::globa
1b80: 6c 48 65 61 64 65 72 28 24 64 62 43 6d 64 29 20  lHeader($dbCmd) 
1b90: 24 68 65 61 64 65 72 0a 0a 09 09 09 67 65 74 73  $header.....gets
1ba0: 20 24 66 64 20 68 65 61 64 65 72 0a 09 09 7d 0a   $fd header...}.
1bb0: 0a 09 09 69 66 20 7b 24 68 65 61 64 65 72 20 6e  ...if {$header n
1bc0: 65 20 22 23 20 3c 41 7a 75 72 65 44 69 61 6d 6f  e "# <AzureDiamo
1bd0: 6e 64 3e 20 6f 68 2c 20 6f 6b 2e 22 7d 20 7b 0a  nd> oh, ok."} {.
1be0: 09 09 09 23 20 54 68 69 73 20 6d 61 79 20 62 65  ...# This may be
1bf0: 20 61 6e 20 6f 6c 64 20 53 51 4c 69 74 65 33 20   an old SQLite3 
1c00: 44 42 2c 20 63 6f 6e 76 65 72 74 20 69 74 0a 09  DB, convert it..
1c10: 09 09 63 6c 6f 73 65 20 24 66 64 0a 0a 09 09 09  ..close $fd.....
1c20: 73 71 6c 69 74 65 33 20 24 64 62 43 6d 64 20 24  sqlite3 $dbCmd $
1c30: 66 69 6c 65 4e 61 6d 65 0a 0a 09 09 09 5f 73 61  fileName....._sa
1c40: 76 65 44 42 20 24 64 62 43 6d 64 20 24 66 69 6c  veDB $dbCmd $fil
1c50: 65 4e 61 6d 65 0a 0a 09 09 09 24 64 62 43 6d 64  eName.....$dbCmd
1c60: 20 63 6c 6f 73 65 0a 0a 09 09 09 72 65 74 75 72   close.....retur
1c70: 6e 20 5b 5f 6c 6f 61 64 44 42 20 24 64 62 43 6d  n [_loadDB $dbCm
1c80: 64 20 24 66 69 6c 65 4e 61 6d 65 5d 0a 09 09 7d  d $fileName]...}
1c90: 0a 0a 09 09 73 65 74 20 64 61 74 61 20 5b 72 65  ....set data [re
1ca0: 61 64 20 24 66 64 5d 0a 0a 09 09 63 6c 6f 73 65  ad $fd]....close
1cb0: 20 24 66 64 0a 09 7d 20 65 6c 73 65 20 7b 0a 09   $fd..} else {..
1cc0: 09 73 65 74 20 64 61 74 61 20 22 22 0a 09 7d 0a  .set data ""..}.
1cd0: 0a 09 73 71 6c 69 74 65 33 20 24 64 62 43 6d 64  ..sqlite3 $dbCmd
1ce0: 20 22 3a 6d 65 6d 6f 72 79 3a 22 0a 0a 09 24 64   ":memory:"...$d
1cf0: 62 43 6d 64 20 65 76 61 6c 20 7b 0a 09 09 43 52  bCmd eval {...CR
1d00: 45 41 54 45 20 54 41 42 4c 45 20 49 46 20 4e 4f  EATE TABLE IF NO
1d10: 54 20 45 58 49 53 54 53 20 75 73 65 72 73 28 6e  T EXISTS users(n
1d20: 61 6d 65 2c 20 70 75 62 6c 69 63 4b 65 79 20 42  ame, publicKey B
1d30: 4c 4f 42 29 3b 0a 09 09 43 52 45 41 54 45 20 54  LOB);...CREATE T
1d40: 41 42 4c 45 20 49 46 20 4e 4f 54 20 45 58 49 53  ABLE IF NOT EXIS
1d50: 54 53 20 70 61 73 73 77 6f 72 64 73 28 6e 61 6d  TS passwords(nam
1d60: 65 2c 20 65 6e 63 72 79 70 74 65 64 50 61 73 73  e, encryptedPass
1d70: 20 42 4c 4f 42 2c 20 65 6e 63 72 79 70 74 65 64   BLOB, encrypted
1d80: 4b 65 79 20 42 4c 4f 42 2c 20 70 75 62 6c 69 63  Key BLOB, public
1d90: 4b 65 79 20 42 4c 4f 42 2c 20 76 65 72 69 66 69  Key BLOB, verifi
1da0: 63 61 74 69 6f 6e 20 42 4c 4f 42 29 3b 0a 09 7d  cation BLOB);..}
1db0: 0a 0a 09 24 64 62 43 6d 64 20 74 72 61 6e 73 61  ...$dbCmd transa
1dc0: 63 74 69 6f 6e 20 7b 0a 09 09 66 6f 72 65 61 63  ction {...foreac
1dd0: 68 20 6c 69 6e 65 20 5b 73 70 6c 69 74 20 24 64  h line [split $d
1de0: 61 74 61 20 22 5c 6e 22 5d 20 7b 0a 09 09 09 69  ata "\n"] {....i
1df0: 66 20 7b 5b 73 74 72 69 6e 67 20 74 72 69 6d 20  f {[string trim 
1e00: 24 6c 69 6e 65 5d 20 65 71 20 22 22 7d 20 7b 0a  $line] eq ""} {.
1e10: 09 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09 09  ....continue....
1e20: 7d 0a 0a 09 09 09 73 65 74 20 74 61 62 6c 65 20  }.....set table 
1e30: 5b 6c 69 6e 64 65 78 20 24 6c 69 6e 65 20 30 5d  [lindex $line 0]
1e40: 0a 09 09 09 73 65 74 20 6c 69 6e 65 20 5b 6c 72  ....set line [lr
1e50: 61 6e 67 65 20 24 6c 69 6e 65 20 31 20 65 6e 64  ange $line 1 end
1e60: 5d 0a 0a 09 09 09 73 65 74 20 6b 65 79 73 20 5b  ].....set keys [
1e70: 6c 69 73 74 5d 0a 09 09 09 73 65 74 20 76 61 6c  list]....set val
1e80: 75 65 73 20 5b 6c 69 73 74 5d 0a 09 09 09 75 6e  ues [list]....un
1e90: 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e 20  set -nocomplain 
1ea0: 76 61 6c 75 65 41 72 72 61 79 0a 0a 09 09 09 66  valueArray.....f
1eb0: 6f 72 65 61 63 68 20 7b 6b 65 79 20 76 61 6c 75  oreach {key valu
1ec0: 65 7d 20 24 6c 69 6e 65 20 7b 0a 09 09 09 09 69  e} $line {.....i
1ed0: 66 20 7b 5b 73 74 72 69 6e 67 20 69 6e 64 65 78  f {[string index
1ee0: 20 24 6b 65 79 20 30 5d 20 3d 3d 20 22 3a 22 7d   $key 0] == ":"}
1ef0: 20 7b 0a 09 09 09 09 09 73 65 74 20 6b 65 79 20   {......set key 
1f00: 5b 73 74 72 69 6e 67 20 72 61 6e 67 65 20 24 6b  [string range $k
1f10: 65 79 20 31 20 65 6e 64 5d 0a 09 09 09 09 09 73  ey 1 end]......s
1f20: 65 74 20 76 61 6c 75 65 42 61 73 65 36 34 45 6e  et valueBase64En
1f30: 63 6f 64 65 64 20 31 0a 09 09 09 09 7d 20 65 6c  coded 1.....} el
1f40: 73 65 20 7b 0a 09 09 09 09 09 73 65 74 20 76 61  se {......set va
1f50: 6c 75 65 42 61 73 65 36 34 45 6e 63 6f 64 65 64  lueBase64Encoded
1f60: 20 30 0a 09 09 09 09 7d 0a 0a 09 09 09 09 69 66   0.....}......if
1f70: 20 7b 24 76 61 6c 75 65 42 61 73 65 36 34 45 6e   {$valueBase64En
1f80: 63 6f 64 65 64 7d 20 7b 0a 09 09 09 09 09 73 65  coded} {......se
1f90: 74 20 76 61 6c 75 65 20 5b 62 69 6e 61 72 79 20  t value [binary 
1fa0: 64 65 63 6f 64 65 20 62 61 73 65 36 34 20 24 76  decode base64 $v
1fb0: 61 6c 75 65 5d 0a 09 09 09 09 7d 0a 0a 09 09 09  alue].....}.....
1fc0: 09 69 66 20 7b 21 5b 72 65 67 65 78 70 20 7b 5e  .if {![regexp {^
1fd0: 5b 61 2d 7a 41 2d 5a 5d 2b 24 7d 20 24 6b 65 79  [a-zA-Z]+$} $key
1fe0: 5d 7d 20 7b 0a 09 09 09 09 09 72 65 74 75 72 6e  ]} {......return
1ff0: 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 49 6e   -code error "In
2000: 76 61 6c 69 64 20 6b 65 79 20 6e 61 6d 65 3a 20  valid key name: 
2010: 24 6b 65 79 22 0a 09 09 09 09 7d 0a 0a 09 09 09  $key".....}.....
2020: 09 73 77 69 74 63 68 20 2d 2d 20 24 6b 65 79 20  .switch -- $key 
2030: 7b 0a 09 09 09 09 09 22 6e 61 6d 65 22 20 7b 0a  {......"name" {.
2040: 09 09 09 09 09 09 73 65 74 20 74 79 70 65 20 22  ......set type "
2050: 22 0a 09 09 09 09 09 09 73 65 74 20 74 79 70 65  ".......set type
2060: 49 6e 73 65 72 74 43 68 61 72 20 7b 24 7d 0a 0a  InsertChar {$}..
2070: 09 09 09 09 09 09 23 20 43 6f 6e 76 65 72 74 20  ......# Convert 
2080: 74 68 69 73 20 74 6f 20 61 20 73 74 72 69 6e 67  this to a string
2090: 2d 69 66 69 65 64 20 76 61 6c 75 65 0a 09 09 09  -ified value....
20a0: 09 09 09 73 65 74 20 76 61 6c 75 65 20 5b 73 74  ...set value [st
20b0: 72 69 6e 67 20 72 61 6e 67 65 20 22 78 24 76 61  ring range "x$va
20c0: 6c 75 65 22 20 31 20 65 6e 64 5d 0a 09 09 09 09  lue" 1 end].....
20d0: 09 7d 0a 09 09 09 09 09 64 65 66 61 75 6c 74 20  .}......default 
20e0: 7b 0a 09 09 09 09 09 09 73 65 74 20 74 79 70 65  {.......set type
20f0: 20 22 42 4c 4f 42 22 0a 09 09 09 09 09 09 73 65   "BLOB".......se
2100: 74 20 74 79 70 65 49 6e 73 65 72 74 43 68 61 72  t typeInsertChar
2110: 20 22 40 22 0a 09 09 09 09 09 7d 0a 09 09 09 09   "@"......}.....
2120: 7d 0a 0a 09 09 09 09 6c 61 70 70 65 6e 64 20 6b  }......lappend k
2130: 65 79 73 20 24 6b 65 79 0a 0a 09 09 09 09 73 65  eys $key......se
2140: 74 20 76 61 6c 75 65 41 72 72 61 79 28 24 6b 65  t valueArray($ke
2150: 79 29 20 24 76 61 6c 75 65 0a 0a 09 09 09 09 6c  y) $value......l
2160: 61 70 70 65 6e 64 20 76 61 6c 75 65 73 20 24 7b  append values ${
2170: 74 79 70 65 49 6e 73 65 72 74 43 68 61 72 7d 76  typeInsertChar}v
2180: 61 6c 75 65 41 72 72 61 79 28 24 6b 65 79 29 0a  alueArray($key).
2190: 09 09 09 7d 0a 0a 09 09 09 24 64 62 43 6d 64 20  ...}.....$dbCmd 
21a0: 65 76 61 6c 20 22 49 4e 53 45 52 54 20 49 4e 54  eval "INSERT INT
21b0: 4f 20 24 74 61 62 6c 65 20 28 5b 6a 6f 69 6e 20  O $table ([join 
21c0: 24 6b 65 79 73 20 7b 2c 20 7d 5d 29 20 56 41 4c  $keys {, }]) VAL
21d0: 55 45 53 20 28 5b 6a 6f 69 6e 20 24 76 61 6c 75  UES ([join $valu
21e0: 65 73 20 7b 2c 20 7d 5d 29 3b 22 0a 09 09 7d 0a  es {, }]);"...}.
21f0: 09 7d 0a 7d 0a 0a 70 72 6f 63 20 5f 73 61 76 65  .}.}..proc _save
2200: 44 42 20 7b 64 62 43 6d 64 20 66 69 6c 65 4e 61  DB {dbCmd fileNa
2210: 6d 65 7d 20 7b 0a 09 69 66 20 7b 5b 69 6e 66 6f  me} {..if {[info
2220: 20 65 78 69 73 74 73 20 3a 3a 67 6c 6f 62 61 6c   exists ::global
2230: 48 65 61 64 65 72 28 24 64 62 43 6d 64 29 5d 7d  Header($dbCmd)]}
2240: 20 7b 0a 09 09 6c 61 70 70 65 6e 64 20 6f 75 74   {...lappend out
2250: 70 75 74 20 24 3a 3a 67 6c 6f 62 61 6c 48 65 61  put $::globalHea
2260: 64 65 72 28 24 64 62 43 6d 64 29 0a 0a 09 09 75  der($dbCmd)....u
2270: 6e 73 65 74 20 3a 3a 67 6c 6f 62 61 6c 48 65 61  nset ::globalHea
2280: 64 65 72 28 24 64 62 43 6d 64 29 0a 09 7d 0a 0a  der($dbCmd)..}..
2290: 09 6c 61 70 70 65 6e 64 20 6f 75 74 70 75 74 20  .lappend output 
22a0: 22 23 20 3c 41 7a 75 72 65 44 69 61 6d 6f 6e 64  "# <AzureDiamond
22b0: 3e 20 6f 68 2c 20 6f 6b 2e 22 0a 0a 09 66 6f 72  > oh, ok."...for
22c0: 65 61 63 68 20 74 61 62 6c 65 20 5b 6c 69 73 74  each table [list
22d0: 20 75 73 65 72 73 20 70 61 73 73 77 6f 72 64 73   users passwords
22e0: 5d 20 7b 0a 09 09 75 6e 73 65 74 20 2d 6e 6f 63  ] {...unset -noc
22f0: 6f 6d 70 6c 61 69 6e 20 72 6f 77 0a 09 09 24 64  omplain row...$d
2300: 62 43 6d 64 20 65 76 61 6c 20 22 53 45 4c 45 43  bCmd eval "SELEC
2310: 54 20 2a 20 46 52 4f 4d 20 24 74 61 62 6c 65 20  T * FROM $table 
2320: 4f 52 44 45 52 20 42 59 20 6e 61 6d 65 3b 22 20  ORDER BY name;" 
2330: 72 6f 77 20 7b 0a 09 09 09 73 65 74 20 6f 75 74  row {....set out
2340: 70 75 74 4c 69 6e 65 20 5b 6c 69 73 74 20 24 74  putLine [list $t
2350: 61 62 6c 65 5d 0a 0a 09 09 09 75 6e 73 65 74 20  able].....unset 
2360: 2d 6e 6f 63 6f 6d 70 6c 61 69 6e 20 72 6f 77 28  -nocomplain row(
2370: 2a 29 0a 0a 09 09 09 66 6f 72 65 61 63 68 20 7b  *).....foreach {
2380: 6b 65 79 20 76 61 6c 75 65 7d 20 5b 61 72 72 61  key value} [arra
2390: 79 20 67 65 74 20 72 6f 77 5d 20 7b 0a 09 09 09  y get row] {....
23a0: 09 69 66 20 7b 21 5b 72 65 67 65 78 70 20 7b 5e  .if {![regexp {^
23b0: 5b 61 2d 7a 41 2d 5a 5d 2b 24 7d 20 24 76 61 6c  [a-zA-Z]+$} $val
23c0: 75 65 5d 7d 20 7b 0a 09 09 09 09 09 73 65 74 20  ue]} {......set 
23d0: 6b 65 79 20 22 3a 24 6b 65 79 22 0a 09 09 09 09  key ":$key".....
23e0: 09 73 65 74 20 76 61 6c 75 65 20 5b 62 69 6e 61  .set value [bina
23f0: 72 79 20 65 6e 63 6f 64 65 20 62 61 73 65 36 34  ry encode base64
2400: 20 24 76 61 6c 75 65 5d 0a 09 09 09 09 7d 0a 0a   $value].....}..
2410: 09 09 09 09 6c 61 70 70 65 6e 64 20 6f 75 74 70  ....lappend outp
2420: 75 74 4c 69 6e 65 20 24 6b 65 79 20 24 76 61 6c  utLine $key $val
2430: 75 65 0a 09 09 09 7d 0a 0a 09 09 09 6c 61 70 70  ue....}.....lapp
2440: 65 6e 64 20 6f 75 74 70 75 74 20 24 6f 75 74 70  end output $outp
2450: 75 74 4c 69 6e 65 0a 09 09 7d 0a 09 7d 0a 0a 09  utLine...}..}...
2460: 73 65 74 20 66 64 20 5b 6f 70 65 6e 20 24 66 69  set fd [open $fi
2470: 6c 65 4e 61 6d 65 20 77 20 30 36 30 30 5d 0a 09  leName w 0600]..
2480: 70 75 74 73 20 24 66 64 20 5b 6a 6f 69 6e 20 24  puts $fd [join $
2490: 6f 75 74 70 75 74 20 22 5c 6e 22 5d 0a 09 63 6c  output "\n"]..cl
24a0: 6f 73 65 20 24 66 64 0a 7d 0a 0a 70 72 6f 63 20  ose $fd.}..proc 
24b0: 5f 6c 69 73 74 43 65 72 74 69 66 69 63 61 74 65  _listCertificate
24c0: 73 20 7b 7d 20 7b 0a 09 69 66 20 7b 21 5b 69 6e  s {} {..if {![in
24d0: 66 6f 20 65 78 69 73 74 73 20 3a 3a 65 6e 76 28  fo exists ::env(
24e0: 50 4b 43 53 31 31 4d 4f 44 55 4c 45 29 5d 7d 20  PKCS11MODULE)]} 
24f0: 7b 0a 09 09 72 65 74 75 72 6e 20 2d 63 6f 64 65  {...return -code
2500: 20 65 72 72 6f 72 20 22 45 52 52 4f 52 3a 20 50   error "ERROR: P
2510: 4b 43 53 31 31 4d 4f 44 55 4c 45 20 65 6e 76 69  KCS11MODULE envi
2520: 72 6f 6e 6d 65 6e 74 20 76 61 72 69 61 62 6c 65  ronment variable
2530: 20 69 73 20 6e 6f 74 20 73 65 74 20 74 6f 20 79   is not set to y
2540: 6f 75 72 20 50 4b 43 53 31 31 20 6d 6f 64 75 6c  our PKCS11 modul
2550: 65 22 0a 09 7d 0a 0a 09 23 20 48 61 72 64 63 6f  e"..}...# Hardco
2560: 64 65 20 73 6f 6d 65 20 50 4b 43 53 31 31 20 6d  de some PKCS11 m
2570: 6f 64 75 6c 65 20 77 6f 72 6b 61 72 6f 75 6e 64  odule workaround
2580: 73 0a 09 73 65 74 20 3a 3a 65 6e 76 28 43 41 43  s..set ::env(CAC
2590: 4b 45 59 5f 4e 4f 5f 45 58 54 52 41 5f 43 45 52  KEY_NO_EXTRA_CER
25a0: 54 53 29 20 31 0a 0a 09 73 65 74 20 68 61 6e 64  TS) 1...set hand
25b0: 6c 65 20 5b 3a 3a 70 6b 69 3a 3a 70 6b 63 73 31  le [::pki::pkcs1
25c0: 31 3a 3a 6c 6f 61 64 6d 6f 64 75 6c 65 20 24 3a  1::loadmodule $:
25d0: 3a 65 6e 76 28 50 4b 43 53 31 31 4d 4f 44 55 4c  :env(PKCS11MODUL
25e0: 45 29 5d 0a 0a 09 73 65 74 20 73 6c 6f 74 49 6e  E)]...set slotIn
25f0: 66 6f 20 5b 6c 69 73 74 5d 0a 09 66 6f 72 65 61  fo [list]..forea
2600: 63 68 20 73 6c 6f 74 20 5b 3a 3a 70 6b 69 3a 3a  ch slot [::pki::
2610: 70 6b 63 73 31 31 3a 3a 6c 69 73 74 73 6c 6f 74  pkcs11::listslot
2620: 73 20 24 68 61 6e 64 6c 65 5d 20 7b 0a 09 09 73  s $handle] {...s
2630: 65 74 20 73 6c 6f 74 49 44 20 5b 6c 69 6e 64 65  et slotID [linde
2640: 78 20 24 73 6c 6f 74 20 30 5d 0a 09 09 73 65 74  x $slot 0]...set
2650: 20 73 6c 6f 74 4c 61 62 65 6c 20 5b 6c 69 6e 64   slotLabel [lind
2660: 65 78 20 24 73 6c 6f 74 20 31 5d 0a 09 09 73 65  ex $slot 1]...se
2670: 74 20 73 6c 6f 74 46 6c 61 67 73 20 5b 6c 69 6e  t slotFlags [lin
2680: 64 65 78 20 24 73 6c 6f 74 20 32 5d 0a 0a 09 09  dex $slot 2]....
2690: 69 66 20 7b 22 54 4f 4b 45 4e 5f 50 52 45 53 45  if {"TOKEN_PRESE
26a0: 4e 54 22 20 6e 69 20 24 73 6c 6f 74 46 6c 61 67  NT" ni $slotFlag
26b0: 73 7d 20 7b 0a 09 09 09 63 6f 6e 74 69 6e 75 65  s} {....continue
26c0: 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 22 54 4f 4b  ...}....if {"TOK
26d0: 45 4e 5f 49 4e 49 54 49 41 4c 49 5a 45 44 22 20  EN_INITIALIZED" 
26e0: 6e 69 20 24 73 6c 6f 74 46 6c 61 67 73 7d 20 7b  ni $slotFlags} {
26f0: 0a 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09 7d  ....continue...}
2700: 0a 0a 09 09 73 65 74 20 73 6c 6f 74 50 72 6f 6d  ....set slotProm
2710: 70 74 46 6f 72 50 49 4e 20 66 61 6c 73 65 0a 09  ptForPIN false..
2720: 09 69 66 20 7b 22 50 52 4f 54 45 43 54 45 44 5f  .if {"PROTECTED_
2730: 41 55 54 48 45 4e 54 49 43 41 54 49 4f 4e 5f 50  AUTHENTICATION_P
2740: 41 54 48 22 20 6e 69 20 24 73 6c 6f 74 46 6c 61  ATH" ni $slotFla
2750: 67 73 7d 20 7b 0a 09 09 09 69 66 20 7b 22 4c 4f  gs} {....if {"LO
2760: 47 49 4e 5f 52 45 51 55 49 52 45 44 22 20 69 6e  GIN_REQUIRED" in
2770: 20 24 73 6c 6f 74 46 6c 61 67 73 7d 20 7b 0a 09   $slotFlags} {..
2780: 09 09 09 73 65 74 20 73 6c 6f 74 50 72 6f 6d 70  ...set slotPromp
2790: 74 46 6f 72 50 49 4e 20 74 72 75 65 0a 09 09 09  tForPIN true....
27a0: 7d 0a 09 09 7d 0a 0a 09 09 66 6f 72 65 61 63 68  }...}....foreach
27b0: 20 63 65 72 74 20 5b 3a 3a 70 6b 69 3a 3a 70 6b   cert [::pki::pk
27c0: 63 73 31 31 3a 3a 6c 69 73 74 63 65 72 74 73 20  cs11::listcerts 
27d0: 24 68 61 6e 64 6c 65 20 24 73 6c 6f 74 49 44 5d  $handle $slotID]
27e0: 20 7b 0a 09 09 09 73 65 74 20 70 75 62 6b 65 79   {....set pubkey
27f0: 20 5b 62 69 6e 61 72 79 20 65 6e 63 6f 64 65 20   [binary encode 
2800: 62 61 73 65 36 34 20 5b 64 69 63 74 20 67 65 74  base64 [dict get
2810: 20 5b 3a 3a 70 6b 69 3a 3a 72 73 61 3a 3a 73 65   [::pki::rsa::se
2820: 72 69 61 6c 69 7a 65 5f 70 75 62 6c 69 63 5f 6b  rialize_public_k
2830: 65 79 20 24 63 65 72 74 5d 20 64 61 74 61 5d 5d  ey $cert] data]]
2840: 0a 0a 09 09 09 6c 61 70 70 65 6e 64 20 73 6c 6f  .....lappend slo
2850: 74 49 6e 66 6f 20 5b 6c 69 73 74 20 68 61 6e 64  tInfo [list hand
2860: 6c 65 20 24 68 61 6e 64 6c 65 20 69 64 20 24 73  le $handle id $s
2870: 6c 6f 74 49 44 20 70 72 6f 6d 70 74 20 24 73 6c  lotID prompt $sl
2880: 6f 74 50 72 6f 6d 70 74 46 6f 72 50 49 4e 20 63  otPromptForPIN c
2890: 65 72 74 20 24 63 65 72 74 20 70 75 62 6b 65 79  ert $cert pubkey
28a0: 20 24 70 75 62 6b 65 79 5d 0a 09 09 7d 0a 09 7d   $pubkey]...}..}
28b0: 0a 0a 09 72 65 74 75 72 6e 20 24 73 6c 6f 74 49  ...return $slotI
28c0: 6e 66 6f 0a 7d 0a 0a 70 72 6f 63 20 5f 76 65 72  nfo.}..proc _ver
28d0: 69 66 79 50 61 73 73 77 6f 72 64 20 7b 6e 61 6d  ifyPassword {nam
28e0: 65 20 70 61 73 73 77 6f 72 64 7d 20 7b 0a 09 73  e password} {..s
28f0: 65 74 20 70 75 62 6c 69 63 4b 65 79 73 20 5b 6c  et publicKeys [l
2900: 69 73 74 5d 0a 0a 09 64 62 20 65 76 61 6c 20 7b  ist]...db eval {
2910: 53 45 4c 45 43 54 20 70 75 62 6c 69 63 4b 65 79  SELECT publicKey
2920: 2c 20 76 65 72 69 66 69 63 61 74 69 6f 6e 20 46  , verification F
2930: 52 4f 4d 20 70 61 73 73 77 6f 72 64 73 20 57 48  ROM passwords WH
2940: 45 52 45 20 6e 61 6d 65 20 3d 20 24 6e 61 6d 65  ERE name = $name
2950: 7d 20 72 6f 77 20 7b 0a 09 09 73 65 74 20 73 61  } row {...set sa
2960: 6c 74 20 5b 64 69 63 74 20 67 65 74 20 24 72 6f  lt [dict get $ro
2970: 77 28 76 65 72 69 66 69 63 61 74 69 6f 6e 29 20  w(verification) 
2980: 73 61 6c 74 5d 0a 09 09 73 65 74 20 68 61 73 68  salt]...set hash
2990: 41 6c 67 6f 72 69 74 68 6d 20 5b 64 69 63 74 20  Algorithm [dict 
29a0: 67 65 74 20 24 72 6f 77 28 76 65 72 69 66 69 63  get $row(verific
29b0: 61 74 69 6f 6e 29 20 68 61 73 68 41 6c 67 6f 72  ation) hashAlgor
29c0: 69 74 68 6d 5d 0a 09 09 73 65 74 20 70 75 62 6c  ithm]...set publ
29d0: 69 63 4b 65 79 20 24 72 6f 77 28 70 75 62 6c 69  icKey $row(publi
29e0: 63 4b 65 79 29 0a 0a 09 09 73 65 74 20 70 6c 61  cKey)....set pla
29f0: 69 6e 74 65 78 74 20 22 24 7b 73 61 6c 74 7d 7c  intext "${salt}|
2a00: 24 7b 70 75 62 6c 69 63 4b 65 79 7d 7c 24 7b 70  ${publicKey}|${p
2a10: 61 73 73 77 6f 72 64 7d 22 0a 0a 09 09 73 77 69  assword}"....swi
2a20: 74 63 68 20 2d 2d 20 24 68 61 73 68 41 6c 67 6f  tch -- $hashAlgo
2a30: 72 69 74 68 6d 20 7b 0a 09 09 09 22 73 68 61 32  rithm {...."sha2
2a40: 35 36 22 20 7b 0a 09 09 09 09 73 65 74 20 76 65  56" {.....set ve
2a50: 72 69 66 69 63 61 74 69 6f 6e 48 61 73 68 20 5b  rificationHash [
2a60: 73 68 61 32 3a 3a 73 68 61 32 35 36 20 2d 68 65  sha2::sha256 -he
2a70: 78 20 2d 2d 20 24 70 6c 61 69 6e 74 65 78 74 5d  x -- $plaintext]
2a80: 0a 09 09 09 7d 0a 09 09 09 64 65 66 61 75 6c 74  ....}....default
2a90: 20 7b 0a 09 09 09 09 72 65 74 75 72 6e 20 2d 63   {.....return -c
2aa0: 6f 64 65 20 65 72 72 6f 72 20 22 55 6e 6b 6e 6f  ode error "Unkno
2ab0: 77 6e 20 68 61 73 68 69 6e 67 20 61 6c 67 6f 72  wn hashing algor
2ac0: 69 74 68 6d 3a 20 24 68 61 73 68 41 6c 67 6f 72  ithm: $hashAlgor
2ad0: 69 74 68 6d 22 0a 09 09 09 7d 0a 09 09 7d 0a 0a  ithm"....}...}..
2ae0: 09 09 73 65 74 20 72 6f 77 28 76 65 72 69 66 69  ..set row(verifi
2af0: 63 61 74 69 6f 6e 48 61 73 68 29 20 5b 64 69 63  cationHash) [dic
2b00: 74 20 67 65 74 20 24 72 6f 77 28 76 65 72 69 66  t get $row(verif
2b10: 69 63 61 74 69 6f 6e 29 20 68 61 73 68 5d 0a 0a  ication) hash]..
2b20: 09 09 69 66 20 7b 24 76 65 72 69 66 69 63 61 74  ..if {$verificat
2b30: 69 6f 6e 48 61 73 68 20 6e 65 20 24 72 6f 77 28  ionHash ne $row(
2b40: 76 65 72 69 66 69 63 61 74 69 6f 6e 48 61 73 68  verificationHash
2b50: 29 7d 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 2d  )} {....return -
2b60: 63 6f 64 65 20 65 72 72 6f 72 20 22 46 41 49 4c  code error "FAIL
2b70: 45 44 3a 20 76 65 72 69 66 69 63 61 74 69 6f 6e  ED: verification
2b80: 20 66 61 69 6c 65 64 20 66 6f 72 20 24 6e 61 6d   failed for $nam
2b90: 65 20 77 69 74 68 20 70 75 62 6c 69 63 20 6b 65  e with public ke
2ba0: 79 20 24 70 75 62 6c 69 63 4b 65 79 20 2d 2d 20  y $publicKey -- 
2bb0: 69 74 20 77 69 6c 6c 20 6e 6f 74 20 67 65 74 20  it will not get 
2bc0: 74 68 65 20 6e 65 77 20 70 61 73 73 77 6f 72 64  the new password
2bd0: 2e 22 0a 0a 09 09 09 63 6f 6e 74 69 6e 75 65 0a  .".....continue.
2be0: 09 09 7d 0a 0a 09 09 6c 61 70 70 65 6e 64 20 70  ..}....lappend p
2bf0: 75 62 6c 69 63 4b 65 79 73 20 24 70 75 62 6c 69  ublicKeys $publi
2c00: 63 4b 65 79 0a 09 7d 0a 0a 09 72 65 74 75 72 6e  cKey..}...return
2c10: 20 24 70 75 62 6c 69 63 4b 65 79 73 0a 7d 0a 0a   $publicKeys.}..
2c20: 70 72 6f 63 20 5f 61 64 64 50 61 73 73 77 6f 72  proc _addPasswor
2c30: 64 20 7b 6e 61 6d 65 20 70 61 73 73 77 6f 72 64  d {name password
2c40: 20 70 75 62 6c 69 63 4b 65 79 73 7d 20 7b 0a 09   publicKeys} {..
2c50: 73 65 74 20 66 64 20 5b 6f 70 65 6e 20 22 2f 64  set fd [open "/d
2c60: 65 76 2f 75 72 61 6e 64 6f 6d 22 20 72 5d 0a 09  ev/urandom" r]..
2c70: 66 63 6f 6e 66 69 67 75 72 65 20 24 66 64 20 2d  fconfigure $fd -
2c80: 74 72 61 6e 73 6c 61 74 69 6f 6e 20 62 69 6e 61  translation bina
2c90: 72 79 0a 0a 09 73 65 74 20 6b 65 79 53 69 7a 65  ry...set keySize
2ca0: 20 31 36 0a 0a 09 23 20 50 61 64 20 74 68 65 20   16...# Pad the 
2cb0: 70 61 73 73 77 6f 72 64 20 77 69 74 68 20 30 20  password with 0 
2cc0: 62 79 74 65 73 20 75 6e 74 69 6c 20 69 74 20 69  bytes until it i
2cd0: 73 20 61 20 6d 75 6c 74 69 70 6c 65 20 6f 66 20  s a multiple of 
2ce0: 74 68 65 20 6b 65 79 20 73 69 7a 65 0a 09 73 65  the key size..se
2cf0: 74 20 62 6c 6f 63 6b 50 61 73 73 77 6f 72 64 20  t blockPassword 
2d00: 24 70 61 73 73 77 6f 72 64 0a 09 61 70 70 65 6e  $password..appen
2d10: 64 20 62 6c 6f 63 6b 50 61 73 73 77 6f 72 64 20  d blockPassword 
2d20: 5b 73 74 72 69 6e 67 20 72 65 70 65 61 74 20 22  [string repeat "
2d30: 5c 78 30 30 22 20 5b 65 78 70 72 20 7b 2d 5b 73  \x00" [expr {-[s
2d40: 74 72 69 6e 67 20 6c 65 6e 67 74 68 20 24 70 61  tring length $pa
2d50: 73 73 77 6f 72 64 5d 20 25 20 24 6b 65 79 53 69  ssword] % $keySi
2d60: 7a 65 7d 5d 5d 0a 0a 09 64 62 20 74 72 61 6e 73  ze}]]...db trans
2d70: 61 63 74 69 6f 6e 20 7b 0a 09 09 64 62 20 65 76  action {...db ev
2d80: 61 6c 20 7b 44 45 4c 45 54 45 20 46 52 4f 4d 20  al {DELETE FROM 
2d90: 70 61 73 73 77 6f 72 64 73 20 57 48 45 52 45 20  passwords WHERE 
2da0: 6e 61 6d 65 20 3d 20 24 6e 61 6d 65 3b 7d 0a 0a  name = $name;}..
2db0: 09 09 66 6f 72 65 61 63 68 20 70 75 62 6c 69 63  ..foreach public
2dc0: 4b 65 79 20 24 70 75 62 6c 69 63 4b 65 79 73 20  Key $publicKeys 
2dd0: 7b 0a 09 09 09 73 65 74 20 6b 65 79 20 5b 72 65  {....set key [re
2de0: 61 64 20 24 66 64 20 24 6b 65 79 53 69 7a 65 5d  ad $fd $keySize]
2df0: 0a 09 09 09 69 66 20 7b 5b 73 74 72 69 6e 67 20  ....if {[string 
2e00: 6c 65 6e 67 74 68 20 24 6b 65 79 5d 20 21 3d 20  length $key] != 
2e10: 24 6b 65 79 53 69 7a 65 7d 20 7b 0a 09 09 09 09  $keySize} {.....
2e20: 63 6c 6f 73 65 20 24 66 64 0a 0a 09 09 09 09 72  close $fd......r
2e30: 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f  eturn -code erro
2e40: 72 20 22 45 52 52 4f 52 3a 20 53 68 6f 72 74 20  r "ERROR: Short 
2e50: 72 65 61 64 20 66 72 6f 6d 20 72 61 6e 64 6f 6d  read from random
2e60: 20 64 65 76 69 63 65 22 0a 09 09 09 7d 0a 0a 09   device"....}...
2e70: 09 09 73 65 74 20 73 61 6c 74 20 5b 72 65 61 64  ..set salt [read
2e80: 20 24 66 64 20 24 6b 65 79 53 69 7a 65 5d 0a 09   $fd $keySize]..
2e90: 09 09 73 65 74 20 73 61 6c 74 20 5b 62 69 6e 61  ..set salt [bina
2ea0: 72 79 20 65 6e 63 6f 64 65 20 62 61 73 65 36 34  ry encode base64
2eb0: 20 24 73 61 6c 74 5d 0a 0a 09 09 09 73 65 74 20   $salt].....set 
2ec0: 70 75 62 6c 69 63 4b 65 79 49 74 65 6d 20 5b 3a  publicKeyItem [:
2ed0: 3a 70 6b 69 3a 3a 70 6b 63 73 3a 3a 70 61 72 73  :pki::pkcs::pars
2ee0: 65 5f 70 75 62 6c 69 63 5f 6b 65 79 20 5b 62 69  e_public_key [bi
2ef0: 6e 61 72 79 20 64 65 63 6f 64 65 20 62 61 73 65  nary decode base
2f00: 36 34 20 24 70 75 62 6c 69 63 4b 65 79 5d 5d 0a  64 $publicKey]].
2f10: 0a 09 09 09 73 65 74 20 65 6e 63 72 79 70 74 65  ....set encrypte
2f20: 64 4b 65 79 20 5b 62 69 6e 61 72 79 20 65 6e 63  dKey [binary enc
2f30: 6f 64 65 20 62 61 73 65 36 34 20 5b 3a 3a 70 6b  ode base64 [::pk
2f40: 69 3a 3a 65 6e 63 72 79 70 74 20 2d 70 75 62 20  i::encrypt -pub 
2f50: 2d 62 69 6e 61 72 79 20 2d 2d 20 24 6b 65 79 20  -binary -- $key 
2f60: 24 70 75 62 6c 69 63 4b 65 79 49 74 65 6d 5d 5d  $publicKeyItem]]
2f70: 0a 0a 09 09 09 73 65 74 20 65 6e 63 72 79 70 74  .....set encrypt
2f80: 65 64 50 61 73 73 20 5b 62 69 6e 61 72 79 20 65  edPass [binary e
2f90: 6e 63 6f 64 65 20 62 61 73 65 36 34 20 5b 3a 3a  ncode base64 [::
2fa0: 61 65 73 3a 3a 61 65 73 20 2d 64 69 72 20 65 6e  aes::aes -dir en
2fb0: 63 72 79 70 74 20 2d 6b 65 79 20 24 6b 65 79 20  crypt -key $key 
2fc0: 2d 2d 20 24 62 6c 6f 63 6b 50 61 73 73 77 6f 72  -- $blockPasswor
2fd0: 64 5d 5d 0a 0a 09 09 09 73 65 74 20 76 65 72 69  d]].....set veri
2fe0: 66 69 63 61 74 69 6f 6e 48 61 73 68 20 5b 73 68  ficationHash [sh
2ff0: 61 32 3a 3a 73 68 61 32 35 36 20 2d 68 65 78 20  a2::sha256 -hex 
3000: 2d 2d 20 22 24 7b 73 61 6c 74 7d 7c 24 7b 70 75  -- "${salt}|${pu
3010: 62 6c 69 63 4b 65 79 7d 7c 24 7b 70 61 73 73 77  blicKey}|${passw
3020: 6f 72 64 7d 22 5d 0a 09 09 09 73 65 74 20 76 65  ord}"]....set ve
3030: 72 69 66 69 63 61 74 69 6f 6e 20 5b 6c 69 73 74  rification [list
3040: 20 73 61 6c 74 20 24 73 61 6c 74 20 68 61 73 68   salt $salt hash
3050: 41 6c 67 6f 72 69 74 68 6d 20 73 68 61 32 35 36  Algorithm sha256
3060: 20 68 61 73 68 20 24 76 65 72 69 66 69 63 61 74   hash $verificat
3070: 69 6f 6e 48 61 73 68 5d 0a 0a 09 09 09 64 62 20  ionHash].....db 
3080: 65 76 61 6c 20 7b 49 4e 53 45 52 54 20 49 4e 54  eval {INSERT INT
3090: 4f 20 70 61 73 73 77 6f 72 64 73 20 28 6e 61 6d  O passwords (nam
30a0: 65 2c 20 65 6e 63 72 79 70 74 65 64 50 61 73 73  e, encryptedPass
30b0: 2c 20 65 6e 63 72 79 70 74 65 64 4b 65 79 2c 20  , encryptedKey, 
30c0: 70 75 62 6c 69 63 4b 65 79 2c 20 76 65 72 69 66  publicKey, verif
30d0: 69 63 61 74 69 6f 6e 29 20 56 41 4c 55 45 53 20  ication) VALUES 
30e0: 28 24 6e 61 6d 65 2c 20 40 65 6e 63 72 79 70 74  ($name, @encrypt
30f0: 65 64 50 61 73 73 2c 20 40 65 6e 63 72 79 70 74  edPass, @encrypt
3100: 65 64 4b 65 79 2c 20 40 70 75 62 6c 69 63 4b 65  edKey, @publicKe
3110: 79 2c 20 40 76 65 72 69 66 69 63 61 74 69 6f 6e  y, @verification
3120: 29 3b 7d 0a 09 09 7d 0a 09 7d 0a 0a 09 63 6c 6f  );}...}..}...clo
3130: 73 65 20 24 66 64 0a 7d 0a 0a 70 72 6f 63 20 5f  se $fd.}..proc _
3140: 70 72 6f 6d 70 74 20 7b 70 72 6f 6d 70 74 7d 20  prompt {prompt} 
3150: 7b 0a 09 70 75 74 73 20 2d 6e 6f 6e 65 77 6c 69  {..puts -nonewli
3160: 6e 65 20 24 70 72 6f 6d 70 74 0a 09 66 6c 75 73  ne $prompt..flus
3170: 68 20 73 74 64 6f 75 74 0a 0a 09 70 75 74 73 20  h stdout...puts 
3180: 2d 6e 6f 6e 65 77 6c 69 6e 65 20 5b 65 78 65 63  -nonewline [exec
3190: 20 73 74 74 79 20 2d 65 63 68 6f 5d 0a 09 66 6c   stty -echo]..fl
31a0: 75 73 68 20 73 74 64 6f 75 74 0a 0a 09 73 65 74  ush stdout...set
31b0: 20 70 61 73 73 77 6f 72 64 20 5b 67 65 74 73 20   password [gets 
31c0: 73 74 64 69 6e 5d 0a 0a 09 70 75 74 73 20 2d 6e  stdin]...puts -n
31d0: 6f 6e 65 77 6c 69 6e 65 20 5b 65 78 65 63 20 73  onewline [exec s
31e0: 74 74 79 20 65 63 68 6f 5d 0a 09 70 75 74 73 20  tty echo]..puts 
31f0: 22 22 0a 09 66 6c 75 73 68 20 73 74 64 6f 75 74  ""..flush stdout
3200: 0a 0a 09 72 65 74 75 72 6e 20 24 70 61 73 73 77  ...return $passw
3210: 6f 72 64 0a 7d 0a 0a 70 72 6f 63 20 5f 67 65 74  ord.}..proc _get
3220: 50 61 73 73 77 6f 72 64 20 7b 6e 61 6d 65 7d 20  Password {name} 
3230: 7b 0a 09 73 65 74 20 65 78 69 73 74 73 20 5b 64  {..set exists [d
3240: 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54 20 31  b eval {SELECT 1
3250: 20 46 52 4f 4d 20 70 61 73 73 77 6f 72 64 73 20   FROM passwords 
3260: 57 48 45 52 45 20 6e 61 6d 65 20 3d 20 24 6e 61  WHERE name = $na
3270: 6d 65 20 4c 49 4d 49 54 20 31 3b 7d 5d 0a 09 69  me LIMIT 1;}]..i
3280: 66 20 7b 24 65 78 69 73 74 73 20 21 3d 20 22 31  f {$exists != "1
3290: 22 7d 20 7b 0a 09 09 72 65 74 75 72 6e 20 2d 63  "} {...return -c
32a0: 6f 64 65 20 65 72 72 6f 72 20 22 50 61 73 73 77  ode error "Passw
32b0: 6f 72 64 20 5c 22 24 6e 61 6d 65 5c 22 20 64 6f  ord \"$name\" do
32c0: 65 73 20 6e 6f 74 20 65 78 69 73 74 73 2e 22 0a  es not exists.".
32d0: 09 7d 0a 0a 09 66 6f 72 65 61 63 68 20 73 6c 6f  .}...foreach slo
32e0: 74 49 6e 66 6f 44 69 63 74 20 5b 5f 6c 69 73 74  tInfoDict [_list
32f0: 43 65 72 74 69 66 69 63 61 74 65 73 5d 20 7b 0a  Certificates] {.
3300: 09 09 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c  ..unset -nocompl
3310: 61 69 6e 20 73 6c 6f 74 49 6e 66 6f 0a 09 09 61  ain slotInfo...a
3320: 72 72 61 79 20 73 65 74 20 73 6c 6f 74 49 6e 66  rray set slotInf
3330: 6f 20 24 73 6c 6f 74 49 6e 66 6f 44 69 63 74 0a  o $slotInfoDict.
3340: 0a 09 09 73 65 74 20 70 75 62 6b 65 79 20 24 73  ...set pubkey $s
3350: 6c 6f 74 49 6e 66 6f 28 70 75 62 6b 65 79 29 0a  lotInfo(pubkey).
3360: 09 09 73 65 74 20 70 72 6f 6d 70 74 20 24 73 6c  ..set prompt $sl
3370: 6f 74 49 6e 66 6f 28 70 72 6f 6d 70 74 29 0a 0a  otInfo(prompt)..
3380: 09 09 69 66 20 7b 5b 69 6e 66 6f 20 65 78 69 73  ..if {[info exis
3390: 74 73 20 70 72 6f 6d 70 74 65 64 28 24 73 6c 6f  ts prompted($slo
33a0: 74 49 6e 66 6f 28 69 64 29 29 5d 7d 20 7b 0a 09  tInfo(id))]} {..
33b0: 09 09 73 65 74 20 70 72 6f 6d 70 74 20 66 61 6c  ..set prompt fal
33c0: 73 65 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 24 70  se...}....if {$p
33d0: 72 6f 6d 70 74 7d 20 7b 0a 09 09 09 73 65 74 20  rompt} {....set 
33e0: 50 49 4e 20 5b 5f 70 72 6f 6d 70 74 20 22 50 6c  PIN [_prompt "Pl
33f0: 65 61 73 65 20 65 6e 74 65 72 20 74 68 65 20 50  ease enter the P
3400: 49 4e 20 66 6f 72 20 5b 64 69 63 74 20 67 65 74  IN for [dict get
3410: 20 24 73 6c 6f 74 49 6e 66 6f 28 63 65 72 74 29   $slotInfo(cert)
3420: 20 73 75 62 6a 65 63 74 5d 3a 20 22 5d 0a 0a 09   subject]: "]...
3430: 09 09 69 66 20 7b 21 5b 3a 3a 70 6b 69 3a 3a 70  ..if {![::pki::p
3440: 6b 63 73 31 31 3a 3a 6c 6f 67 69 6e 20 24 73 6c  kcs11::login $sl
3450: 6f 74 49 6e 66 6f 28 68 61 6e 64 6c 65 29 20 24  otInfo(handle) $
3460: 73 6c 6f 74 49 6e 66 6f 28 69 64 29 20 24 50 49  slotInfo(id) $PI
3470: 4e 5d 7d 20 7b 0a 09 09 09 09 72 65 74 75 72 6e  N]} {.....return
3480: 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 55 6e   -code error "Un
3490: 61 62 6c 65 20 74 6f 20 61 75 74 68 65 6e 74 69  able to authenti
34a0: 63 61 74 65 22 0a 09 09 09 7d 0a 0a 09 09 09 73  cate"....}.....s
34b0: 65 74 20 70 72 6f 6d 70 74 65 64 28 24 73 6c 6f  et prompted($slo
34c0: 74 49 6e 66 6f 28 69 64 29 29 20 31 0a 09 09 7d  tInfo(id)) 1...}
34d0: 0a 0a 09 09 64 62 20 65 76 61 6c 20 7b 53 45 4c  ....db eval {SEL
34e0: 45 43 54 20 65 6e 63 72 79 70 74 65 64 50 61 73  ECT encryptedPas
34f0: 73 2c 20 65 6e 63 72 79 70 74 65 64 4b 65 79 20  s, encryptedKey 
3500: 46 52 4f 4d 20 70 61 73 73 77 6f 72 64 73 20 57  FROM passwords W
3510: 48 45 52 45 20 6e 61 6d 65 20 3d 20 24 6e 61 6d  HERE name = $nam
3520: 65 20 41 4e 44 20 70 75 62 6c 69 63 4b 65 79 20  e AND publicKey 
3530: 3d 20 24 70 75 62 6b 65 79 3b 7d 20 72 6f 77 20  = $pubkey;} row 
3540: 7b 0a 09 09 09 73 65 74 20 6b 65 79 20 5b 3a 3a  {....set key [::
3550: 70 6b 69 3a 3a 64 65 63 72 79 70 74 20 2d 62 69  pki::decrypt -bi
3560: 6e 61 72 79 20 2d 70 72 69 76 20 2d 2d 20 5b 62  nary -priv -- [b
3570: 69 6e 61 72 79 20 64 65 63 6f 64 65 20 62 61 73  inary decode bas
3580: 65 36 34 20 24 72 6f 77 28 65 6e 63 72 79 70 74  e64 $row(encrypt
3590: 65 64 4b 65 79 29 5d 20 24 73 6c 6f 74 49 6e 66  edKey)] $slotInf
35a0: 6f 28 63 65 72 74 29 5d 0a 09 09 09 73 65 74 20  o(cert)]....set 
35b0: 70 61 73 73 77 6f 72 64 20 5b 3a 3a 61 65 73 3a  password [::aes:
35c0: 3a 61 65 73 20 2d 64 69 72 20 64 65 63 72 79 70  :aes -dir decryp
35d0: 74 20 2d 6b 65 79 20 24 6b 65 79 20 2d 2d 20 5b  t -key $key -- [
35e0: 62 69 6e 61 72 79 20 64 65 63 6f 64 65 20 62 61  binary decode ba
35f0: 73 65 36 34 20 24 72 6f 77 28 65 6e 63 72 79 70  se64 $row(encryp
3600: 74 65 64 50 61 73 73 29 5d 5d 0a 0a 09 09 09 72  tedPass)]].....r
3610: 65 74 75 72 6e 20 5b 73 74 72 69 6e 67 20 74 72  eturn [string tr
3620: 69 6d 72 69 67 68 74 20 24 70 61 73 73 77 6f 72  imright $passwor
3630: 64 20 22 5c 78 30 30 22 5d 0a 09 09 7d 0a 09 7d  d "\x00"]...}..}
3640: 0a 0a 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20  ...return -code 
3650: 65 72 72 6f 72 20 22 4e 6f 20 76 61 6c 69 64 20  error "No valid 
3660: 6b 65 79 73 22 0a 7d 0a 0a 70 72 6f 63 20 5f 6d  keys".}..proc _m
3670: 6f 64 69 66 79 50 75 62 6c 69 63 4b 65 79 73 20  odifyPublicKeys 
3680: 7b 70 61 73 73 77 6f 72 64 4e 61 6d 65 20 75 73  {passwordName us
3690: 65 72 4e 61 6d 65 73 20 73 71 6c 7d 20 7b 0a 09  erNames sql} {..
36a0: 73 65 74 20 65 78 69 73 74 73 20 5b 64 62 20 65  set exists [db e
36b0: 76 61 6c 20 7b 53 45 4c 45 43 54 20 31 20 46 52  val {SELECT 1 FR
36c0: 4f 4d 20 70 61 73 73 77 6f 72 64 73 20 57 48 45  OM passwords WHE
36d0: 52 45 20 6e 61 6d 65 20 3d 20 24 70 61 73 73 77  RE name = $passw
36e0: 6f 72 64 4e 61 6d 65 20 4c 49 4d 49 54 20 31 3b  ordName LIMIT 1;
36f0: 7d 5d 0a 09 69 66 20 7b 24 65 78 69 73 74 73 20  }]..if {$exists 
3700: 21 3d 20 22 31 22 7d 20 7b 0a 09 09 72 65 74 75  != "1"} {...retu
3710: 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22  rn -code error "
3720: 50 61 73 73 77 6f 72 64 20 5c 22 24 70 61 73 73  Password \"$pass
3730: 77 6f 72 64 4e 61 6d 65 5c 22 20 64 6f 65 73 20  wordName\" does 
3740: 6e 6f 74 20 65 78 69 73 74 73 2e 22 0a 09 7d 0a  not exists."..}.
3750: 0a 09 73 65 74 20 70 75 62 6c 69 63 4b 65 79 73  ..set publicKeys
3760: 20 5b 6c 69 73 74 5d 0a 0a 09 64 62 20 65 76 61   [list]...db eva
3770: 6c 20 7b 53 45 4c 45 43 54 20 70 75 62 6c 69 63  l {SELECT public
3780: 4b 65 79 20 46 52 4f 4d 20 70 61 73 73 77 6f 72  Key FROM passwor
3790: 64 73 20 57 48 45 52 45 20 6e 61 6d 65 20 3d 20  ds WHERE name = 
37a0: 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 3b 7d 20  $passwordName;} 
37b0: 72 6f 77 20 7b 0a 09 09 6c 61 70 70 65 6e 64 20  row {...lappend 
37c0: 70 75 62 6c 69 63 4b 65 79 73 20 24 72 6f 77 28  publicKeys $row(
37d0: 70 75 62 6c 69 63 4b 65 79 29 0a 09 7d 0a 0a 09  publicKey)..}...
37e0: 73 65 74 20 63 68 61 6e 67 65 52 65 71 75 69 72  set changeRequir
37f0: 65 64 20 30 0a 09 66 6f 72 65 61 63 68 20 75 73  ed 0..foreach us
3800: 65 72 20 24 75 73 65 72 4e 61 6d 65 73 20 7b 0a  er $userNames {.
3810: 09 09 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c  ..unset -nocompl
3820: 61 69 6e 20 72 6f 77 0a 09 09 64 62 20 65 76 61  ain row...db eva
3830: 6c 20 7b 53 45 4c 45 43 54 20 70 75 62 6c 69 63  l {SELECT public
3840: 4b 65 79 20 46 52 4f 4d 20 75 73 65 72 73 20 57  Key FROM users W
3850: 48 45 52 45 20 6e 61 6d 65 20 3d 20 24 75 73 65  HERE name = $use
3860: 72 3b 7d 20 72 6f 77 20 24 73 71 6c 0a 09 7d 0a  r;} row $sql..}.
3870: 0a 09 69 66 20 7b 21 24 63 68 61 6e 67 65 52 65  ..if {!$changeRe
3880: 71 75 69 72 65 64 7d 20 7b 0a 09 09 72 65 74 75  quired} {...retu
3890: 72 6e 0a 09 7d 0a 0a 09 73 65 74 20 70 61 73 73  rn..}...set pass
38a0: 77 6f 72 64 20 5b 5f 67 65 74 50 61 73 73 77 6f  word [_getPasswo
38b0: 72 64 20 24 70 61 73 73 77 6f 72 64 4e 61 6d 65  rd $passwordName
38c0: 5d 0a 0a 09 5f 61 64 64 50 61 73 73 77 6f 72 64  ]..._addPassword
38d0: 20 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 20 24   $passwordName $
38e0: 70 61 73 73 77 6f 72 64 20 24 70 75 62 6c 69 63  password $public
38f0: 4b 65 79 73 0a 7d 0a 0a 70 72 6f 63 20 5f 67 65  Keys.}..proc _ge
3900: 74 55 73 65 72 73 46 6f 72 50 61 73 73 77 6f 72  tUsersForPasswor
3910: 64 20 7b 70 61 73 73 77 6f 72 64 4e 61 6d 65 73  d {passwordNames
3920: 7d 20 7b 0a 09 73 65 74 20 75 73 65 72 4e 61 6d  } {..set userNam
3930: 65 73 20 5b 6c 69 73 74 5d 0a 0a 09 66 6f 72 65  es [list]...fore
3940: 61 63 68 20 70 61 73 73 77 6f 72 64 4e 61 6d 65  ach passwordName
3950: 20 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 73 20   $passwordNames 
3960: 7b 0a 09 09 64 62 20 65 76 61 6c 20 7b 53 45 4c  {...db eval {SEL
3970: 45 43 54 20 70 75 62 6c 69 63 4b 65 79 20 46 52  ECT publicKey FR
3980: 4f 4d 20 70 61 73 73 77 6f 72 64 73 20 57 48 45  OM passwords WHE
3990: 52 45 20 6e 61 6d 65 20 3d 20 24 70 61 73 73 77  RE name = $passw
39a0: 6f 72 64 4e 61 6d 65 3b 7d 20 70 61 73 73 77 6f  ordName;} passwo
39b0: 72 64 52 6f 77 20 7b 0a 09 09 09 64 62 20 65 76  rdRow {....db ev
39c0: 61 6c 20 7b 53 45 4c 45 43 54 20 6e 61 6d 65 20  al {SELECT name 
39d0: 46 52 4f 4d 20 75 73 65 72 73 20 57 48 45 52 45  FROM users WHERE
39e0: 20 70 75 62 6c 69 63 4b 65 79 20 3d 20 24 70 61   publicKey = $pa
39f0: 73 73 77 6f 72 64 52 6f 77 28 70 75 62 6c 69 63  sswordRow(public
3a00: 4b 65 79 29 7d 20 75 73 65 72 52 6f 77 20 7b 0a  Key)} userRow {.
3a10: 09 09 09 09 69 66 20 7b 24 75 73 65 72 52 6f 77  ....if {$userRow
3a20: 28 6e 61 6d 65 29 20 69 6e 20 24 75 73 65 72 4e  (name) in $userN
3a30: 61 6d 65 73 7d 20 7b 0a 09 09 09 09 09 63 6f 6e  ames} {......con
3a40: 74 69 6e 75 65 0a 09 09 09 09 7d 0a 0a 09 09 09  tinue.....}.....
3a50: 09 6c 61 70 70 65 6e 64 20 75 73 65 72 4e 61 6d  .lappend userNam
3a60: 65 73 20 24 75 73 65 72 52 6f 77 28 6e 61 6d 65  es $userRow(name
3a70: 29 0a 09 09 09 7d 0a 09 09 7d 0a 09 7d 0a 0a 09  )....}...}..}...
3a80: 72 65 74 75 72 6e 20 24 75 73 65 72 4e 61 6d 65  return $userName
3a90: 73 0a 7d 0a 0a 70 72 6f 63 20 5f 67 65 74 50 61  s.}..proc _getPa
3aa0: 73 73 77 6f 72 64 73 46 6f 72 55 73 65 72 20 7b  sswordsForUser {
3ab0: 75 73 65 72 4e 61 6d 65 73 7d 20 7b 0a 09 73 65  userNames} {..se
3ac0: 74 20 70 61 73 73 77 6f 72 64 4e 61 6d 65 73 20  t passwordNames 
3ad0: 5b 6c 69 73 74 5d 0a 0a 09 66 6f 72 65 61 63 68  [list]...foreach
3ae0: 20 75 73 65 72 4e 61 6d 65 20 24 75 73 65 72 4e   userName $userN
3af0: 61 6d 65 73 20 7b 0a 09 09 64 62 20 65 76 61 6c  ames {...db eval
3b00: 20 7b 53 45 4c 45 43 54 20 70 75 62 6c 69 63 4b   {SELECT publicK
3b10: 65 79 20 46 52 4f 4d 20 75 73 65 72 73 20 57 48  ey FROM users WH
3b20: 45 52 45 20 6e 61 6d 65 20 3d 20 24 75 73 65 72  ERE name = $user
3b30: 4e 61 6d 65 3b 7d 20 75 73 65 72 52 6f 77 20 7b  Name;} userRow {
3b40: 0a 09 09 09 64 62 20 65 76 61 6c 20 7b 53 45 4c  ....db eval {SEL
3b50: 45 43 54 20 6e 61 6d 65 20 46 52 4f 4d 20 70 61  ECT name FROM pa
3b60: 73 73 77 6f 72 64 73 20 57 48 45 52 45 20 70 75  sswords WHERE pu
3b70: 62 6c 69 63 4b 65 79 20 3d 20 24 75 73 65 72 52  blicKey = $userR
3b80: 6f 77 28 70 75 62 6c 69 63 4b 65 79 29 7d 20 70  ow(publicKey)} p
3b90: 61 73 73 77 6f 72 64 52 6f 77 20 7b 0a 09 09 09  asswordRow {....
3ba0: 09 69 66 20 7b 24 70 61 73 73 77 6f 72 64 52 6f  .if {$passwordRo
3bb0: 77 28 6e 61 6d 65 29 20 69 6e 20 24 70 61 73 73  w(name) in $pass
3bc0: 77 6f 72 64 4e 61 6d 65 73 7d 20 7b 0a 09 09 09  wordNames} {....
3bd0: 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09 09 09 7d  ..continue.....}
3be0: 0a 0a 09 09 09 09 6c 61 70 70 65 6e 64 20 70 61  ......lappend pa
3bf0: 73 73 77 6f 72 64 4e 61 6d 65 73 20 24 70 61 73  sswordNames $pas
3c00: 73 77 6f 72 64 52 6f 77 28 6e 61 6d 65 29 0a 09  swordRow(name)..
3c10: 09 09 7d 0a 09 09 7d 0a 09 7d 0a 0a 09 72 65 74  ..}...}..}...ret
3c20: 75 72 6e 20 24 70 61 73 73 77 6f 72 64 4e 61 6d  urn $passwordNam
3c30: 65 73 0a 7d 0a 23 20 45 6e 64 20 69 6e 74 65 72  es.}.# End inter
3c40: 6e 61 6c 20 66 75 6e 63 74 69 6f 6e 73 0a 0a 23  nal functions..#
3c50: 20 53 74 61 72 74 20 75 73 65 72 20 43 4c 49 20   Start user CLI 
3c60: 66 75 6e 63 74 69 6f 6e 73 0a 70 72 6f 63 20 6c  functions.proc l
3c70: 69 73 74 4c 6f 63 61 6c 4b 65 79 73 20 7b 7d 20  istLocalKeys {} 
3c80: 7b 0a 09 66 6f 72 65 61 63 68 20 73 6c 6f 74 49  {..foreach slotI
3c90: 6e 66 6f 44 69 63 74 20 5b 5f 6c 69 73 74 43 65  nfoDict [_listCe
3ca0: 72 74 69 66 69 63 61 74 65 73 5d 20 7b 0a 09 09  rtificates] {...
3cb0: 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69  unset -nocomplai
3cc0: 6e 20 73 6c 6f 74 49 6e 66 6f 0a 09 09 61 72 72  n slotInfo...arr
3cd0: 61 79 20 73 65 74 20 73 6c 6f 74 49 6e 66 6f 20  ay set slotInfo 
3ce0: 24 73 6c 6f 74 49 6e 66 6f 44 69 63 74 0a 0a 09  $slotInfoDict...
3cf0: 09 73 65 74 20 73 75 62 6a 65 63 74 20 5b 64 69  .set subject [di
3d00: 63 74 20 67 65 74 20 24 73 6c 6f 74 49 6e 66 6f  ct get $slotInfo
3d10: 28 63 65 72 74 29 20 73 75 62 6a 65 63 74 5d 0a  (cert) subject].
3d20: 09 09 73 65 74 20 70 75 62 6b 65 79 20 20 24 73  ..set pubkey  $s
3d30: 6c 6f 74 49 6e 66 6f 28 70 75 62 6b 65 79 29 0a  lotInfo(pubkey).
3d40: 0a 09 09 6c 61 70 70 65 6e 64 20 70 75 62 6c 69  ...lappend publi
3d50: 63 4b 65 79 73 28 24 73 75 62 6a 65 63 74 29 20  cKeys($subject) 
3d60: 24 70 75 62 6b 65 79 0a 09 7d 0a 0a 09 66 6f 72  $pubkey..}...for
3d70: 65 61 63 68 20 7b 73 75 62 6a 65 63 74 20 70 75  each {subject pu
3d80: 62 6b 65 79 73 7d 20 5b 61 72 72 61 79 20 67 65  bkeys} [array ge
3d90: 74 20 70 75 62 6c 69 63 4b 65 79 73 5d 20 7b 0a  t publicKeys] {.
3da0: 09 09 70 75 74 73 20 22 24 73 75 62 6a 65 63 74  ..puts "$subject
3db0: 22 0a 0a 09 09 66 6f 72 65 61 63 68 20 70 75 62  "....foreach pub
3dc0: 6b 65 79 20 24 70 75 62 6b 65 79 73 20 7b 0a 09  key $pubkeys {..
3dd0: 09 09 70 75 74 73 20 22 20 20 7c 2d 3e 20 24 70  ..puts "  |-> $p
3de0: 75 62 6b 65 79 22 0a 09 09 7d 0a 09 7d 0a 0a 09  ubkey"...}..}...
3df0: 73 65 74 20 3a 3a 73 61 76 65 52 65 71 75 69 72  set ::saveRequir
3e00: 65 64 20 30 0a 7d 0a 0a 70 72 6f 63 20 6c 69 73  ed 0.}..proc lis
3e10: 74 41 76 61 69 6c 61 62 6c 65 50 61 73 73 77 6f  tAvailablePasswo
3e20: 72 64 73 20 7b 7d 20 7b 0a 09 73 65 74 20 70 61  rds {} {..set pa
3e30: 73 73 77 6f 72 64 4e 61 6d 65 73 20 5b 6c 69 73  sswordNames [lis
3e40: 74 5d 0a 09 66 6f 72 65 61 63 68 20 73 6c 6f 74  t]..foreach slot
3e50: 49 6e 66 6f 44 69 63 74 20 5b 5f 6c 69 73 74 43  InfoDict [_listC
3e60: 65 72 74 69 66 69 63 61 74 65 73 5d 20 7b 0a 09  ertificates] {..
3e70: 09 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61  .unset -nocompla
3e80: 69 6e 20 73 6c 6f 74 49 6e 66 6f 0a 09 09 61 72  in slotInfo...ar
3e90: 72 61 79 20 73 65 74 20 73 6c 6f 74 49 6e 66 6f  ray set slotInfo
3ea0: 20 24 73 6c 6f 74 49 6e 66 6f 44 69 63 74 0a 0a   $slotInfoDict..
3eb0: 09 09 73 65 74 20 70 75 62 6b 65 79 20 24 73 6c  ..set pubkey $sl
3ec0: 6f 74 49 6e 66 6f 28 70 75 62 6b 65 79 29 0a 0a  otInfo(pubkey)..
3ed0: 09 09 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c  ..unset -nocompl
3ee0: 61 69 6e 20 72 6f 77 0a 09 09 64 62 20 65 76 61  ain row...db eva
3ef0: 6c 20 7b 53 45 4c 45 43 54 20 6e 61 6d 65 20 46  l {SELECT name F
3f00: 52 4f 4d 20 70 61 73 73 77 6f 72 64 73 20 57 48  ROM passwords WH
3f10: 45 52 45 20 70 75 62 6c 69 63 4b 65 79 20 3d 20  ERE publicKey = 
3f20: 24 70 75 62 6b 65 79 3b 7d 20 72 6f 77 20 7b 0a  $pubkey;} row {.
3f30: 09 09 09 69 66 20 7b 24 72 6f 77 28 6e 61 6d 65  ...if {$row(name
3f40: 29 20 69 6e 20 24 70 61 73 73 77 6f 72 64 4e 61  ) in $passwordNa
3f50: 6d 65 73 7d 20 7b 0a 09 09 09 09 63 6f 6e 74 69  mes} {.....conti
3f60: 6e 75 65 0a 09 09 09 7d 0a 0a 09 09 09 6c 61 70  nue....}.....lap
3f70: 70 65 6e 64 20 70 61 73 73 77 6f 72 64 4e 61 6d  pend passwordNam
3f80: 65 73 20 24 72 6f 77 28 6e 61 6d 65 29 0a 09 09  es $row(name)...
3f90: 7d 0a 09 7d 0a 0a 0a 09 66 6f 72 65 61 63 68 20  }..}....foreach 
3fa0: 70 61 73 73 77 6f 72 64 4e 61 6d 65 20 24 70 61  passwordName $pa
3fb0: 73 73 77 6f 72 64 4e 61 6d 65 73 20 7b 0a 09 09  sswordNames {...
3fc0: 70 75 74 73 20 22 5b 5f 77 72 61 70 53 74 72 69  puts "[_wrapStri
3fd0: 6e 67 20 5b 6a 6f 69 6e 20 5b 5f 67 65 74 55 73  ng [join [_getUs
3fe0: 65 72 73 46 6f 72 50 61 73 73 77 6f 72 64 20 5b  ersForPassword [
3ff0: 6c 69 73 74 20 24 70 61 73 73 77 6f 72 64 4e 61  list $passwordNa
4000: 6d 65 5d 5d 20 7b 2c 20 7d 5d 20 24 3a 3a 64 65  me]] {, }] $::de
4010: 66 61 75 6c 74 57 72 61 70 4c 65 6e 67 74 68 20  faultWrapLength 
4020: 22 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 20 2d  "$passwordName -
4030: 20 22 5d 22 0a 09 7d 0a 0a 09 73 65 74 20 3a 3a   "]"..}...set ::
4040: 73 61 76 65 52 65 71 75 69 72 65 64 20 30 0a 7d  saveRequired 0.}
4050: 0a 0a 70 72 6f 63 20 6c 69 73 74 50 61 73 73 77  ..proc listPassw
4060: 6f 72 64 73 20 7b 7d 20 7b 0a 09 64 62 20 65 76  ords {} {..db ev
4070: 61 6c 20 7b 53 45 4c 45 43 54 20 44 49 53 54 49  al {SELECT DISTI
4080: 4e 43 54 20 6e 61 6d 65 20 46 52 4f 4d 20 70 61  NCT name FROM pa
4090: 73 73 77 6f 72 64 73 3b 7d 20 72 6f 77 20 7b 0a  sswords;} row {.
40a0: 09 09 70 75 74 73 20 22 5b 5f 77 72 61 70 53 74  ..puts "[_wrapSt
40b0: 72 69 6e 67 20 5b 6a 6f 69 6e 20 5b 5f 67 65 74  ring [join [_get
40c0: 55 73 65 72 73 46 6f 72 50 61 73 73 77 6f 72 64  UsersForPassword
40d0: 20 5b 6c 69 73 74 20 24 72 6f 77 28 6e 61 6d 65   [list $row(name
40e0: 29 5d 5d 20 7b 2c 20 7d 5d 20 24 3a 3a 64 65 66  )]] {, }] $::def
40f0: 61 75 6c 74 57 72 61 70 4c 65 6e 67 74 68 20 22  aultWrapLength "
4100: 24 72 6f 77 28 6e 61 6d 65 29 20 2d 20 22 5d 22  $row(name) - "]"
4110: 0a 09 7d 0a 0a 09 73 65 74 20 3a 3a 73 61 76 65  ..}...set ::save
4120: 52 65 71 75 69 72 65 64 20 30 0a 7d 0a 0a 70 72  Required 0.}..pr
4130: 6f 63 20 6c 69 73 74 55 73 65 72 73 20 7b 7d 20  oc listUsers {} 
4140: 7b 0a 09 64 62 20 65 76 61 6c 20 7b 53 45 4c 45  {..db eval {SELE
4150: 43 54 20 44 49 53 54 49 4e 43 54 20 6e 61 6d 65  CT DISTINCT name
4160: 20 46 52 4f 4d 20 75 73 65 72 73 3b 7d 20 72 6f   FROM users;} ro
4170: 77 20 7b 0a 09 09 70 75 74 73 20 22 5b 5f 77 72  w {...puts "[_wr
4180: 61 70 53 74 72 69 6e 67 20 5b 6a 6f 69 6e 20 5b  apString [join [
4190: 5f 67 65 74 50 61 73 73 77 6f 72 64 73 46 6f 72  _getPasswordsFor
41a0: 55 73 65 72 20 5b 6c 69 73 74 20 24 72 6f 77 28  User [list $row(
41b0: 6e 61 6d 65 29 5d 5d 20 7b 2c 20 7d 5d 20 24 3a  name)]] {, }] $:
41c0: 3a 64 65 66 61 75 6c 74 57 72 61 70 4c 65 6e 67  :defaultWrapLeng
41d0: 74 68 20 22 24 72 6f 77 28 6e 61 6d 65 29 20 2d  th "$row(name) -
41e0: 20 22 5d 22 0a 09 7d 0a 0a 09 73 65 74 20 3a 3a   "]"..}...set ::
41f0: 73 61 76 65 52 65 71 75 69 72 65 64 20 30 0a 7d  saveRequired 0.}
4200: 0a 0a 70 72 6f 63 20 61 64 64 55 73 65 72 20 7b  ..proc addUser {
4210: 75 73 65 72 4e 61 6d 65 20 6b 65 79 7d 20 7b 0a  userName key} {.
4220: 09 73 65 74 20 6b 65 79 52 61 77 20 5b 62 69 6e  .set keyRaw [bin
4230: 61 72 79 20 64 65 63 6f 64 65 20 62 61 73 65 36  ary decode base6
4240: 34 20 24 6b 65 79 5d 0a 09 73 65 74 20 6b 65 79  4 $key]..set key
4250: 56 65 72 69 66 79 20 5b 3a 3a 70 6b 69 3a 3a 70  Verify [::pki::p
4260: 6b 63 73 3a 3a 70 61 72 73 65 5f 70 75 62 6c 69  kcs::parse_publi
4270: 63 5f 6b 65 79 20 24 6b 65 79 52 61 77 5d 0a 0a  c_key $keyRaw]..
4280: 09 64 62 20 65 76 61 6c 20 7b 49 4e 53 45 52 54  .db eval {INSERT
4290: 20 49 4e 54 4f 20 75 73 65 72 73 20 28 6e 61 6d   INTO users (nam
42a0: 65 2c 20 70 75 62 6c 69 63 4b 65 79 29 20 56 41  e, publicKey) VA
42b0: 4c 55 45 53 20 28 24 75 73 65 72 4e 61 6d 65 2c  LUES ($userName,
42c0: 20 40 6b 65 79 29 3b 7d 0a 0a 09 23 20 58 58 58   @key);}...# XXX
42d0: 3a 54 4f 44 4f 3a 47 6f 20 74 68 72 6f 75 67 68  :TODO:Go through
42e0: 20 61 6e 64 20 72 65 2d 61 75 74 68 6f 72 69 7a   and re-authoriz
42f0: 65 20 69 66 20 70 6f 73 73 69 62 6c 65 0a 7d 0a  e if possible.}.
4300: 0a 70 72 6f 63 20 64 65 6c 65 74 65 55 73 65 72  .proc deleteUser
4310: 20 7b 75 73 65 72 4e 61 6d 65 7d 20 7b 0a 09 23   {userName} {..#
4320: 20 58 58 58 3a 54 4f 44 4f 3a 20 47 6f 20 74 68   XXX:TODO: Go th
4330: 72 6f 75 67 68 20 61 6e 64 20 64 65 2d 61 75 74  rough and de-aut
4340: 68 6f 72 69 7a 65 0a 7d 0a 0a 70 72 6f 63 20 61  horize.}..proc a
4350: 64 64 50 61 73 73 77 6f 72 64 20 7b 70 61 73 73  ddPassword {pass
4360: 77 6f 72 64 4e 61 6d 65 20 70 61 73 73 77 6f 72  wordName passwor
4370: 64 20 61 72 67 73 7d 20 7b 0a 09 73 65 74 20 69  d args} {..set i
4380: 6e 69 74 69 61 6c 55 73 65 72 73 20 24 61 72 67  nitialUsers $arg
4390: 73 0a 0a 09 69 66 20 7b 24 70 61 73 73 77 6f 72  s...if {$passwor
43a0: 64 20 65 71 20 22 22 7d 20 7b 0a 09 09 73 65 74  d eq ""} {...set
43b0: 20 70 61 73 73 77 6f 72 64 20 5b 5f 70 72 6f 6d   password [_prom
43c0: 70 74 20 22 50 6c 65 61 73 65 20 65 6e 74 65 72  pt "Please enter
43d0: 20 74 68 65 20 6e 65 77 20 70 61 73 73 77 6f 72   the new passwor
43e0: 64 3a 20 22 5d 0a 09 7d 0a 0a 09 23 20 56 65 72  d: "]..}...# Ver
43f0: 69 66 79 20 74 68 61 74 20 74 68 69 73 20 70 61  ify that this pa
4400: 73 73 77 6f 72 64 20 64 6f 65 73 20 6e 6f 74 20  ssword does not 
4410: 61 6c 72 65 61 64 79 20 65 78 69 73 74 0a 09 73  already exist..s
4420: 65 74 20 65 78 69 73 74 73 20 5b 64 62 20 65 76  et exists [db ev
4430: 61 6c 20 7b 53 45 4c 45 43 54 20 31 20 46 52 4f  al {SELECT 1 FRO
4440: 4d 20 70 61 73 73 77 6f 72 64 73 20 57 48 45 52  M passwords WHER
4450: 45 20 6e 61 6d 65 20 3d 20 24 70 61 73 73 77 6f  E name = $passwo
4460: 72 64 4e 61 6d 65 20 4c 49 4d 49 54 20 31 3b 7d  rdName LIMIT 1;}
4470: 5d 0a 09 69 66 20 7b 24 65 78 69 73 74 73 20 3d  ]..if {$exists =
4480: 3d 20 22 31 22 7d 20 7b 0a 09 09 72 65 74 75 72  = "1"} {...retur
4490: 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 50  n -code error "P
44a0: 61 73 73 77 6f 72 64 20 5c 22 24 70 61 73 73 77  assword \"$passw
44b0: 6f 72 64 4e 61 6d 65 5c 22 20 61 6c 72 65 61 64  ordName\" alread
44c0: 79 20 65 78 69 73 74 73 2c 20 63 61 6e 6e 6f 74  y exists, cannot
44d0: 20 61 64 64 2e 22 0a 09 7d 0a 0a 09 23 20 47 65   add."..}...# Ge
44e0: 74 20 6b 65 79 73 20 66 6f 72 20 69 6e 69 74 69  t keys for initi
44f0: 61 6c 20 75 73 65 72 73 0a 09 73 65 74 20 70 75  al users..set pu
4500: 62 6c 69 63 4b 65 79 73 20 5b 6c 69 73 74 5d 0a  blicKeys [list].
4510: 09 66 6f 72 65 61 63 68 20 75 73 65 72 20 24 69  .foreach user $i
4520: 6e 69 74 69 61 6c 55 73 65 72 73 20 7b 0a 09 09  nitialUsers {...
4530: 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69  unset -nocomplai
4540: 6e 20 72 6f 77 0a 09 09 64 62 20 65 76 61 6c 20  n row...db eval 
4550: 7b 53 45 4c 45 43 54 20 70 75 62 6c 69 63 4b 65  {SELECT publicKe
4560: 79 20 46 52 4f 4d 20 75 73 65 72 73 20 57 48 45  y FROM users WHE
4570: 52 45 20 6e 61 6d 65 20 3d 20 24 75 73 65 72 3b  RE name = $user;
4580: 7d 20 72 6f 77 20 7b 0a 09 09 09 6c 61 70 70 65  } row {....lappe
4590: 6e 64 20 70 75 62 6c 69 63 4b 65 79 73 20 24 72  nd publicKeys $r
45a0: 6f 77 28 70 75 62 6c 69 63 4b 65 79 29 0a 09 09  ow(publicKey)...
45b0: 7d 0a 09 7d 0a 0a 09 5f 61 64 64 50 61 73 73 77  }..}..._addPassw
45c0: 6f 72 64 20 24 70 61 73 73 77 6f 72 64 4e 61 6d  ord $passwordNam
45d0: 65 20 24 70 61 73 73 77 6f 72 64 20 24 70 75 62  e $password $pub
45e0: 6c 69 63 4b 65 79 73 0a 7d 0a 0a 70 72 6f 63 20  licKeys.}..proc 
45f0: 67 65 74 50 61 73 73 77 6f 72 64 20 7b 70 61 73  getPassword {pas
4600: 73 77 6f 72 64 4e 61 6d 65 7d 20 7b 0a 09 70 75  swordName} {..pu
4610: 74 73 20 5b 5f 67 65 74 50 61 73 73 77 6f 72 64  ts [_getPassword
4620: 20 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 5d 0a   $passwordName].
4630: 0a 09 73 65 74 20 3a 3a 73 61 76 65 52 65 71 75  ..set ::saveRequ
4640: 69 72 65 64 20 30 0a 7d 0a 0a 70 72 6f 63 20 75  ired 0.}..proc u
4650: 70 64 61 74 65 50 61 73 73 77 6f 72 64 20 7b 70  pdatePassword {p
4660: 61 73 73 77 6f 72 64 4e 61 6d 65 20 70 61 73 73  asswordName pass
4670: 77 6f 72 64 7d 20 7b 0a 09 69 66 20 7b 24 70 61  word} {..if {$pa
4680: 73 73 77 6f 72 64 20 65 71 20 22 22 7d 20 7b 0a  ssword eq ""} {.
4690: 09 09 73 65 74 20 70 61 73 73 77 6f 72 64 20 5b  ..set password [
46a0: 5f 70 72 6f 6d 70 74 20 22 50 6c 65 61 73 65 20  _prompt "Please 
46b0: 65 6e 74 65 72 20 74 68 65 20 6e 65 77 20 70 61  enter the new pa
46c0: 73 73 77 6f 72 64 3a 20 22 5d 0a 09 7d 0a 0a 09  ssword: "]..}...
46d0: 73 65 74 20 6f 6c 64 50 61 73 73 77 6f 72 64 20  set oldPassword 
46e0: 5b 5f 67 65 74 50 61 73 73 77 6f 72 64 20 24 70  [_getPassword $p
46f0: 61 73 73 77 6f 72 64 4e 61 6d 65 5d 0a 0a 09 73  asswordName]...s
4700: 65 74 20 70 75 62 6c 69 63 4b 65 79 73 20 5b 5f  et publicKeys [_
4710: 76 65 72 69 66 79 50 61 73 73 77 6f 72 64 20 24  verifyPassword $
4720: 70 61 73 73 77 6f 72 64 4e 61 6d 65 20 24 6f 6c  passwordName $ol
4730: 64 50 61 73 73 77 6f 72 64 5d 0a 0a 09 69 66 20  dPassword]...if 
4740: 7b 5b 6c 6c 65 6e 67 74 68 20 24 70 75 62 6c 69  {[llength $publi
4750: 63 4b 65 79 73 5d 20 3d 3d 20 30 7d 20 7b 0a 09  cKeys] == 0} {..
4760: 09 70 75 74 73 20 73 74 64 65 72 72 20 22 57 61  .puts stderr "Wa
4770: 72 6e 69 6e 67 3a 20 54 68 69 73 20 77 69 6c 6c  rning: This will
4780: 20 64 65 6c 65 74 65 20 74 68 65 20 70 61 73 73   delete the pass
4790: 77 6f 72 64 20 73 69 6e 63 65 20 74 68 65 72 65  word since there
47a0: 20 61 72 65 20 6e 6f 20 76 61 6c 69 64 20 70 75   are no valid pu
47b0: 62 6c 69 63 20 6b 65 79 73 2e 22 0a 09 7d 0a 0a  blic keys."..}..
47c0: 09 5f 61 64 64 50 61 73 73 77 6f 72 64 20 24 70  ._addPassword $p
47d0: 61 73 73 77 6f 72 64 4e 61 6d 65 20 24 70 61 73  asswordName $pas
47e0: 73 77 6f 72 64 20 24 70 75 62 6c 69 63 4b 65 79  sword $publicKey
47f0: 73 0a 7d 0a 0a 70 72 6f 63 20 64 65 6c 65 74 65  s.}..proc delete
4800: 50 61 73 73 77 6f 72 64 20 7b 70 61 73 73 77 6f  Password {passwo
4810: 72 64 4e 61 6d 65 7d 20 7b 0a 09 64 62 20 65 76  rdName} {..db ev
4820: 61 6c 20 7b 44 45 4c 45 54 45 20 46 52 4f 4d 20  al {DELETE FROM 
4830: 70 61 73 73 77 6f 72 64 73 20 57 48 45 52 45 20  passwords WHERE 
4840: 6e 61 6d 65 20 3d 20 24 70 61 73 73 77 6f 72 64  name = $password
4850: 4e 61 6d 65 3b 7d 0a 7d 0a 0a 70 72 6f 63 20 61  Name;}.}..proc a
4860: 75 74 68 6f 72 69 7a 65 55 73 65 72 73 20 7b 70  uthorizeUsers {p
4870: 61 73 73 77 6f 72 64 4e 61 6d 65 20 61 72 67 73  asswordName args
4880: 7d 20 7b 0a 09 73 65 74 20 75 73 65 72 73 20 24  } {..set users $
4890: 61 72 67 73 0a 0a 09 5f 6d 6f 64 69 66 79 50 75  args..._modifyPu
48a0: 62 6c 69 63 4b 65 79 73 20 24 70 61 73 73 77 6f  blicKeys $passwo
48b0: 72 64 4e 61 6d 65 20 24 75 73 65 72 73 20 7b 0a  rdName $users {.
48c0: 09 09 69 66 20 7b 24 72 6f 77 28 70 75 62 6c 69  ..if {$row(publi
48d0: 63 4b 65 79 29 20 69 6e 20 24 70 75 62 6c 69 63  cKey) in $public
48e0: 4b 65 79 73 7d 20 7b 0a 09 09 09 63 6f 6e 74 69  Keys} {....conti
48f0: 6e 75 65 0a 09 09 7d 0a 0a 09 09 6c 61 70 70 65  nue...}....lappe
4900: 6e 64 20 70 75 62 6c 69 63 4b 65 79 73 20 24 72  nd publicKeys $r
4910: 6f 77 28 70 75 62 6c 69 63 4b 65 79 29 0a 0a 09  ow(publicKey)...
4920: 09 73 65 74 20 63 68 61 6e 67 65 52 65 71 75 69  .set changeRequi
4930: 72 65 64 20 31 0a 09 7d 0a 7d 0a 0a 70 72 6f 63  red 1..}.}..proc
4940: 20 61 75 74 68 6f 72 69 7a 65 55 73 65 72 20 7b   authorizeUser {
4950: 70 61 73 73 77 6f 72 64 4e 61 6d 65 20 75 73 65  passwordName use
4960: 72 4e 61 6d 65 7d 20 7b 0a 09 72 65 74 75 72 6e  rName} {..return
4970: 20 5b 61 75 74 68 6f 72 69 7a 65 55 73 65 72 73   [authorizeUsers
4980: 20 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 20 24   $passwordName $
4990: 75 73 65 72 4e 61 6d 65 5d 0a 7d 0a 0a 70 72 6f  userName].}..pro
49a0: 63 20 64 65 61 75 74 68 6f 72 69 7a 65 55 73 65  c deauthorizeUse
49b0: 72 73 20 7b 70 61 73 73 77 6f 72 64 4e 61 6d 65  rs {passwordName
49c0: 20 61 72 67 73 7d 20 7b 0a 09 73 65 74 20 75 73   args} {..set us
49d0: 65 72 73 20 24 61 72 67 73 0a 0a 09 5f 6d 6f 64  ers $args..._mod
49e0: 69 66 79 50 75 62 6c 69 63 4b 65 79 73 20 24 70  ifyPublicKeys $p
49f0: 61 73 73 77 6f 72 64 4e 61 6d 65 20 24 75 73 65  asswordName $use
4a00: 72 73 20 7b 0a 09 09 73 65 74 20 69 64 78 20 5b  rs {...set idx [
4a10: 6c 73 65 61 72 63 68 20 2d 65 78 61 63 74 20 24  lsearch -exact $
4a20: 70 75 62 6c 69 63 4b 65 79 73 20 24 72 6f 77 28  publicKeys $row(
4a30: 70 75 62 6c 69 63 4b 65 79 29 5d 0a 09 09 69 66  publicKey)]...if
4a40: 20 7b 24 69 64 78 20 3d 3d 20 2d 31 7d 20 7b 0a   {$idx == -1} {.
4a50: 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09 7d 0a  ...continue...}.
4a60: 0a 09 09 73 65 74 20 70 75 62 6c 69 63 4b 65 79  ...set publicKey
4a70: 73 20 5b 6c 72 65 70 6c 61 63 65 20 24 70 75 62  s [lreplace $pub
4a80: 6c 69 63 4b 65 79 73 20 24 69 64 78 20 24 69 64  licKeys $idx $id
4a90: 78 5d 0a 0a 09 09 73 65 74 20 63 68 61 6e 67 65  x]....set change
4aa0: 52 65 71 75 69 72 65 64 20 31 0a 09 7d 0a 7d 0a  Required 1..}.}.
4ab0: 0a 70 72 6f 63 20 64 65 61 75 74 68 6f 72 69 7a  .proc deauthoriz
4ac0: 65 55 73 65 72 20 7b 70 61 73 73 77 6f 72 64 4e  eUser {passwordN
4ad0: 61 6d 65 20 75 73 65 72 4e 61 6d 65 7d 20 7b 0a  ame userName} {.
4ae0: 09 72 65 74 75 72 6e 20 5b 64 65 61 75 74 68 6f  .return [deautho
4af0: 72 69 7a 65 55 73 65 72 73 20 24 70 61 73 73 77  rizeUsers $passw
4b00: 6f 72 64 4e 61 6d 65 20 24 75 73 65 72 4e 61 6d  ordName $userNam
4b10: 65 5d 0a 7d 0a 0a 70 72 6f 63 20 77 68 6f 61 6d  e].}..proc whoam
4b20: 69 20 7b 7d 20 7b 0a 09 66 6f 72 65 61 63 68 20  i {} {..foreach 
4b30: 73 6c 6f 74 49 6e 66 6f 44 69 63 74 20 5b 5f 6c  slotInfoDict [_l
4b40: 69 73 74 43 65 72 74 69 66 69 63 61 74 65 73 5d  istCertificates]
4b50: 20 7b 0a 09 09 75 6e 73 65 74 20 2d 6e 6f 63 6f   {...unset -noco
4b60: 6d 70 6c 61 69 6e 20 73 6c 6f 74 49 6e 66 6f 0a  mplain slotInfo.
4b70: 09 09 61 72 72 61 79 20 73 65 74 20 73 6c 6f 74  ..array set slot
4b80: 49 6e 66 6f 20 24 73 6c 6f 74 49 6e 66 6f 44 69  Info $slotInfoDi
4b90: 63 74 0a 0a 09 09 73 65 74 20 70 75 62 6b 65 79  ct....set pubkey
4ba0: 20 24 73 6c 6f 74 49 6e 66 6f 28 70 75 62 6b 65   $slotInfo(pubke
4bb0: 79 29 0a 0a 09 09 75 6e 73 65 74 20 2d 6e 6f 63  y)....unset -noc
4bc0: 6f 6d 70 6c 61 69 6e 20 72 6f 77 0a 09 09 64 62  omplain row...db
4bd0: 20 65 76 61 6c 20 7b 53 45 4c 45 43 54 20 6e 61   eval {SELECT na
4be0: 6d 65 20 46 52 4f 4d 20 75 73 65 72 73 20 57 48  me FROM users WH
4bf0: 45 52 45 20 70 75 62 6c 69 63 4b 65 79 20 3d 20  ERE publicKey = 
4c00: 24 70 75 62 6b 65 79 3b 7d 20 72 6f 77 20 7b 0a  $pubkey;} row {.
4c10: 09 09 09 73 65 74 20 75 73 65 72 73 28 24 72 6f  ...set users($ro
4c20: 77 28 6e 61 6d 65 29 29 20 31 0a 09 09 7d 0a 09  w(name)) 1...}..
4c30: 7d 0a 0a 09 70 75 74 73 20 5b 6a 6f 69 6e 20 5b  }...puts [join [
4c40: 61 72 72 61 79 20 6e 61 6d 65 73 20 75 73 65 72  array names user
4c50: 73 5d 20 7b 2c 20 7d 5d 0a 0a 09 73 65 74 20 3a  s] {, }]...set :
4c60: 3a 73 61 76 65 52 65 71 75 69 72 65 64 20 30 0a  :saveRequired 0.
4c70: 7d 0a 0a 70 72 6f 63 20 68 65 6c 70 20 7b 7b 61  }..proc help {{a
4c80: 63 74 69 6f 6e 20 22 22 7d 7d 20 7b 0a 09 5f 70  ction ""}} {.._p
4c90: 72 69 6e 74 48 65 6c 70 20 73 74 64 6f 75 74 20  rintHelp stdout 
4ca0: 24 61 63 74 69 6f 6e 0a 0a 09 73 65 74 20 3a 3a  $action...set ::
4cb0: 73 61 76 65 52 65 71 75 69 72 65 64 20 30 0a 7d  saveRequired 0.}
4cc0: 0a 23 20 45 6e 64 20 75 73 65 72 20 43 4c 49 20  .# End user CLI 
4cd0: 66 75 6e 63 74 69 6f 6e 73 0a 0a 23 23 23 20 4d  functions..### M
4ce0: 41 49 4e 0a 0a 5f 6c 6f 61 64 44 42 20 64 62 20  AIN.._loadDB db 
4cf0: 24 70 61 73 73 77 6f 72 64 46 69 6c 65 0a 0a 69  $passwordFile..i
4d00: 66 20 7b 24 61 63 74 69 6f 6e 20 69 6e 20 24 76  f {$action in $v
4d10: 61 6c 69 64 43 6f 6d 6d 61 6e 64 73 7d 20 7b 0a  alidCommands} {.
4d20: 09 69 66 20 7b 5b 63 61 74 63 68 20 7b 0a 09 09  .if {[catch {...
4d30: 24 61 63 74 69 6f 6e 20 7b 2a 7d 24 61 72 67 76  $action {*}$argv
4d40: 0a 09 7d 20 65 72 72 6f 72 5d 7d 20 7b 0a 09 09  ..} error]} {...
4d50: 70 75 74 73 20 73 74 64 65 72 72 20 22 45 72 72  puts stderr "Err
4d60: 6f 72 3a 20 24 65 72 72 6f 72 22 0a 0a 09 09 65  or: $error"....e
4d70: 78 69 74 20 31 0a 09 7d 0a 7d 20 65 6c 73 65 20  xit 1..}.} else 
4d80: 7b 0a 09 70 75 74 73 20 73 74 64 65 72 72 20 22  {..puts stderr "
4d90: 49 6e 76 61 6c 69 64 20 61 63 74 69 6f 6e 22 0a  Invalid action".
4da0: 0a 09 65 78 69 74 20 31 0a 7d 0a 0a 69 66 20 7b  ..exit 1.}..if {
4db0: 24 3a 3a 73 61 76 65 52 65 71 75 69 72 65 64 7d  $::saveRequired}
4dc0: 20 7b 0a 09 5f 73 61 76 65 44 42 20 64 62 20 24   {.._saveDB db $
4dd0: 70 61 73 73 77 6f 72 64 46 69 6c 65 0a 7d 0a 0a  passwordFile.}..
4de0: 64 62 20 63 6c 6f 73 65 0a 0a 65 78 69 74 20 30  db close..exit 0
4df0: 0a                                               .