| [3374] | 1 | # irkauth.tcl: | 
|---|
 | 2 | # | 
|---|
 | 3 | # Various procedures that deal with user authentication: | 
|---|
 | 4 |  | 
|---|
 | 5 | namespace eval ::irk { | 
|---|
 | 6 |  | 
|---|
 | 7 |     # The AUTH module keeps information about each user and facility ($fac) | 
|---|
 | 8 |     # in the state array: | 
|---|
 | 9 |     # | 
|---|
 | 10 |     # auth(auth,$fac,$user)             If set, then $user has authenticated | 
|---|
 | 11 |     #                                   successfully for the facility $fac. | 
|---|
 | 12 |     # auth(user,$fac,$user,pass)        The password for this $user and $fac. | 
|---|
 | 13 |     # auth(user,$fac,$user,ident)       The ident token for this $user & $fac. | 
|---|
 | 14 |     # | 
|---|
 | 15 |     # auth(ident,$fac,$ident,pass)      The password for this $ident and $fac. | 
|---|
 | 16 |     # auth(ident,$fac,$ident,user)      The user for this $ident and $fac. | 
|---|
 | 17 |     # | 
|---|
 | 18 |     # auth(identcounter,$fac)           The ident token counter for $fac. This | 
|---|
 | 19 |     #                                   is incremented each time a new user | 
|---|
 | 20 |     #                                   establishes themselves with $fac. | 
|---|
 | 21 |  | 
|---|
 | 22 |     # This procedure can be called by programs using the IRK library | 
|---|
 | 23 |     # when a user sends a password. | 
|---|
 | 24 |  | 
|---|
 | 25 |     proc pass {token fac nick user rest} { | 
|---|
 | 26 |         variable auth | 
|---|
 | 27 |  | 
|---|
 | 28 |         if {[llength $rest] != 1} { | 
|---|
 | 29 |             # Incorrect syntax: | 
|---|
 | 30 |  | 
|---|
 | 31 |             set reply "$nick, syntax is !pass <yourpass> (one word, no spaces)" | 
|---|
 | 32 |         } elseif {[info exists auth(user,$fac,$user,pass)]} { | 
|---|
 | 33 |  | 
|---|
 | 34 |             # If this user has already established a password, | 
|---|
 | 35 |             # check that they're giving the right password. | 
|---|
 | 36 |  | 
|---|
 | 37 |             if {[string compare $auth(user,$fac,$user,pass) \ | 
|---|
 | 38 |                                 [lindex $rest 0]]} { | 
|---|
 | 39 |                 set reply "$nick, sorry, wrong password!" | 
|---|
 | 40 |             } else { | 
|---|
 | 41 |                 set reply "$nick, thanks for entering your password!" | 
|---|
 | 42 |                 set auth(auth,$fac,$user) 1 | 
|---|
 | 43 |             } | 
|---|
 | 44 |         } else { | 
|---|
 | 45 |  | 
|---|
 | 46 |             # This is the first time we're seeing this user. Accept | 
|---|
 | 47 |             # their password and send them an ident token. They can | 
|---|
 | 48 |             # use the ident token to reestablish themselves when their | 
|---|
 | 49 |             # user mask changes significantly. | 
|---|
 | 50 |  | 
|---|
 | 51 |             if {![info exists auth(identcounter,$fac)]} { | 
|---|
 | 52 |                 set auth(identcounter,$fac) 0 | 
|---|
 | 53 |             } | 
|---|
 | 54 |             set ident $auth(identcounter,$fac) | 
|---|
 | 55 |             incr auth(identcounter,$fac) | 
|---|
 | 56 |  | 
|---|
 | 57 |             set auth(ident,$fac,$ident,user) $user | 
|---|
 | 58 |             set auth(ident,$fac,$ident,pass) [lindex $rest 0] | 
|---|
 | 59 |  | 
|---|
 | 60 |             set auth(user,$fac,$user,ident) $ident | 
|---|
 | 61 |             set auth(user,$fac,$user,pass) [lindex $rest 0] | 
|---|
 | 62 |  | 
|---|
 | 63 |             # Save the changes | 
|---|
 | 64 |  | 
|---|
 | 65 |             saveauth | 
|---|
 | 66 |  | 
|---|
 | 67 |             # Save them a step and also authorize them: | 
|---|
 | 68 |  | 
|---|
 | 69 |             set auth(ident,$fac,$user) 1 | 
|---|
 | 70 |  | 
|---|
 | 71 |             set reply [list \ | 
|---|
 | 72 |                 $nick, your password is [lindex $rest 0]. Your ident is \ | 
|---|
 | 73 |                 $ident, write it down, you will need it later to \ | 
|---|
 | 74 |                 reidentify yourself if your user mask changes. \ | 
|---|
 | 75 |                 You user mask is currently $user. You are now authorised \ | 
|---|
 | 76 |                 to use $fac.] | 
|---|
 | 77 |         } | 
|---|
 | 78 |  | 
|---|
 | 79 |         # Tell them what happened: | 
|---|
 | 80 |  | 
|---|
 | 81 |         ::irk::say $token $nick $reply | 
|---|
 | 82 |  | 
|---|
 | 83 |         return "" | 
|---|
 | 84 |     } | 
|---|
 | 85 |  | 
|---|
 | 86 |     # This procedure can be called by programs when the user attempts to | 
|---|
 | 87 |     # reestablish themselves with the existing ident and password. | 
|---|
 | 88 |  | 
|---|
 | 89 |     proc id {token fac nick user rest} { | 
|---|
 | 90 |         variable auth | 
|---|
 | 91 |  | 
|---|
 | 92 |         set len [llength $rest] | 
|---|
 | 93 |         set reply "Wrong syntax. Call !ident or !ident <ident> <pass>" | 
|---|
 | 94 |  | 
|---|
 | 95 |         if {$len == 0} { | 
|---|
 | 96 |  | 
|---|
 | 97 |             # Calling ident with zero arguments. The user is trying to | 
|---|
 | 98 |             # retrieve their ident. Give it to them only if they did | 
|---|
 | 99 |             # identify successfully with the correct password. | 
|---|
 | 100 |  | 
|---|
 | 101 |             if {![info exists auth(user,$fac,$user,pass)]} { | 
|---|
 | 102 |                 set reply "$nick, first set a password" | 
|---|
 | 103 |             } elseif {[info exists auth(auth,$fac,$user)]} { | 
|---|
 | 104 |                 set reply \ | 
|---|
 | 105 |                     "$nick, your ident is $auth(user,$fac,$user,ident)" | 
|---|
 | 106 |             } else { | 
|---|
 | 107 |                 set reply \ | 
|---|
 | 108 |                    "$nick, identify with password before getting your ident!" | 
|---|
 | 109 |             } | 
|---|
 | 110 |         } elseif {$len == 2} { | 
|---|
 | 111 |  | 
|---|
 | 112 |             # Calling ident with two arguments. The user is trying to | 
|---|
 | 113 |             # establish a new value for $user to associate with this | 
|---|
 | 114 |             # ident and password. If $auth($ident,pass) is the password | 
|---|
 | 115 |             # she gave, then they're the rightfull owner of the ident and | 
|---|
 | 116 |             # so we now recognize the new $user mask. | 
|---|
 | 117 |  | 
|---|
 | 118 |             set ident [lindex $rest 0] | 
|---|
 | 119 |             set pass [lindex $rest 1] | 
|---|
 | 120 |  | 
|---|
 | 121 |             if {[info exists auth(ident,$fac,$ident,pass)]} { | 
|---|
 | 122 |                 if {![string compare $auth(ident,$fac,$ident,pass) $pass]} { | 
|---|
 | 123 |  | 
|---|
 | 124 |                     # Identify the old user mask they were using: | 
|---|
 | 125 |  | 
|---|
 | 126 |                     set olduser $auth(ident,$fac,$ident,user) | 
|---|
 | 127 |  | 
|---|
 | 128 |                     # Clean up the state associated with the old mask: | 
|---|
 | 129 |  | 
|---|
 | 130 |                     array unset auth user,$fac,$olduser,* | 
|---|
 | 131 |                     catch {unset auth(ident,$face,$olduser)} | 
|---|
 | 132 |  | 
|---|
 | 133 |                     # Link up the new state: | 
|---|
 | 134 |  | 
|---|
 | 135 |                     set auth(ident,$fac,$ident,user) $user | 
|---|
 | 136 |  | 
|---|
 | 137 |                     set auth(user,$fac,$user,ident) $ident | 
|---|
 | 138 |                     set auth(user,$fac,$user,pass) $pass | 
|---|
 | 139 |  | 
|---|
 | 140 |                     # Save the changes | 
|---|
 | 141 |  | 
|---|
 | 142 |                     saveauth | 
|---|
 | 143 |  | 
|---|
 | 144 |                     # Save them a step and also treat them as authenticated: | 
|---|
 | 145 |  | 
|---|
 | 146 |                     set auth(ident,$fac,$user) 1 | 
|---|
 | 147 |  | 
|---|
 | 148 |                     set reply \ | 
|---|
 | 149 |                             "OK, $nick, I'm now recognising you as $user.\ | 
|---|
 | 150 |                              You are now authorised to use $fac." | 
|---|
 | 151 |                 } else { | 
|---|
 | 152 |                     set reply "$nick, sorry, wrong ident or password" | 
|---|
 | 153 |                 } | 
|---|
 | 154 |             } else { | 
|---|
 | 155 |                 set reply "$nick, sorry, wrong ident or password" | 
|---|
 | 156 |             } | 
|---|
 | 157 |         } | 
|---|
 | 158 |  | 
|---|
 | 159 |         # Tell them what happened: | 
|---|
 | 160 |  | 
|---|
 | 161 |         ::irk::say $token $nick $reply | 
|---|
 | 162 |  | 
|---|
 | 163 |         return "" | 
|---|
 | 164 |     } | 
|---|
 | 165 |  | 
|---|
 | 166 |     # This procedure can be invoked by a program when a user tries to | 
|---|
 | 167 |     # change her password. | 
|---|
 | 168 |  | 
|---|
 | 169 |     proc np {token fac nick user rest} { | 
|---|
 | 170 |         variable auth | 
|---|
 | 171 |  | 
|---|
 | 172 |         set reply "Wrong syntax. Call !newpass <oldpass> <newpass>" | 
|---|
 | 173 |  | 
|---|
 | 174 |         if {[llength $rest] == 2} { | 
|---|
 | 175 |             set opw [lindex $rest 0] | 
|---|
 | 176 |             set npw [lindex $rest 1] | 
|---|
 | 177 |  | 
|---|
 | 178 |             if {![info exists auth(user,$fac,$user,pass)]} { | 
|---|
 | 179 |                 # Unknown $user, probably their user mask changed. Help | 
|---|
 | 180 |                 # them reestablish the connection. | 
|---|
 | 181 |  | 
|---|
 | 182 |                 set reply \ | 
|---|
 | 183 |                    [list $nick, I don't have you in my database. Perhaps \ | 
|---|
 | 184 |                          your user mask changed drastically. If so, please \ | 
|---|
 | 185 |                          reestablish your user mask by using !ident <ident> \ | 
|---|
 | 186 |                          <oldpass>.] | 
|---|
 | 187 |             } elseif {[string compare $auth(user,$fac,$user,pass) $opw]} { | 
|---|
 | 188 |                 # Wrong old password! | 
|---|
 | 189 |  | 
|---|
 | 190 |                 set reply "$nick, sorry, wrong old password!" | 
|---|
 | 191 |             } else { | 
|---|
 | 192 |                 # Their user mask matches and they gave the correct old | 
|---|
 | 193 |                 # password, so we accept their new password: | 
|---|
 | 194 |  | 
|---|
 | 195 |                 set ident $auth(user,$fac,$user,ident) | 
|---|
 | 196 |  | 
|---|
 | 197 |                 set auth(ident,$fac,$ident,pass) $npw | 
|---|
 | 198 |                 set auth(user,$fac,$user,pass) $npw | 
|---|
 | 199 |  | 
|---|
 | 200 |                 # Save the changes: | 
|---|
 | 201 |  | 
|---|
 | 202 |                 saveauth | 
|---|
 | 203 |  | 
|---|
 | 204 |                 # Save them a step by also recording that they | 
|---|
 | 205 |                 # authenticated: | 
|---|
 | 206 |  | 
|---|
 | 207 |                 set auth(auth,$fac,$user) 1 | 
|---|
 | 208 |  | 
|---|
 | 209 |                 set reply "OK, $nick, your new password is now $npw" | 
|---|
 | 210 |             } | 
|---|
 | 211 |         } | 
|---|
 | 212 |  | 
|---|
 | 213 |         # Tell them what happened: | 
|---|
 | 214 |  | 
|---|
 | 215 |         ::irk::say $token $nick $reply | 
|---|
 | 216 |  | 
|---|
 | 217 |         return "" | 
|---|
 | 218 |     } | 
|---|
 | 219 |  | 
|---|
 | 220 |     # This procedure can be called by programs when the user wants to | 
|---|
 | 221 |     # "log out" or lose her authentication with a given facility: | 
|---|
 | 222 |  | 
|---|
 | 223 |     proc logout {token fac nick user rest} { | 
|---|
 | 224 |         variable auth | 
|---|
 | 225 |  | 
|---|
 | 226 |         set reply "You were not logged into $fac. Now you certainly aren't." | 
|---|
 | 227 |  | 
|---|
 | 228 |         if {[info exists auth(auth,$fac,$user)]} { | 
|---|
 | 229 |             unset auth(auth,$fac,$user) | 
|---|
 | 230 |  | 
|---|
 | 231 |             set reply \ | 
|---|
 | 232 |                 [list $nick, you logged out successfully from $fac. Thank you \ | 
|---|
 | 233 |                       for using $fac.] | 
|---|
 | 234 |         } | 
|---|
 | 235 |  | 
|---|
 | 236 |         # Tell them what happened: | 
|---|
 | 237 |  | 
|---|
 | 238 |         ::irk::say $token $nick $reply | 
|---|
 | 239 |  | 
|---|
 | 240 |         return "" | 
|---|
 | 241 |     } | 
|---|
 | 242 |  | 
|---|
 | 243 |     # Is the user authenticated with the given facility? | 
|---|
 | 244 |  | 
|---|
 | 245 |     proc userauthenticated {fac user} { | 
|---|
 | 246 |         variable auth | 
|---|
 | 247 |  | 
|---|
 | 248 |         # If auth(auth,$fac,$user) exists, then she is authenticated. | 
|---|
 | 249 |  | 
|---|
 | 250 |         if {[info exists auth(auth,$fac,$user)]} { | 
|---|
 | 251 |             return 1 | 
|---|
 | 252 |         } | 
|---|
 | 253 |         return 0 | 
|---|
 | 254 |     } | 
|---|
 | 255 |  | 
|---|
 | 256 |     # This procedure automatically saves the authorization database: | 
|---|
 | 257 |  | 
|---|
 | 258 |     proc saveauth {} { | 
|---|
 | 259 |         variable state | 
|---|
 | 260 |         variable auth | 
|---|
 | 261 |  | 
|---|
 | 262 |         puts "Saving!" | 
|---|
 | 263 |  | 
|---|
 | 264 |         # Define the patterns to save: | 
|---|
 | 265 |  | 
|---|
 | 266 |         set p1 "identcounter,*" | 
|---|
 | 267 |         set p2 "user,*" | 
|---|
 | 268 |         set p3 "ident,*" | 
|---|
 | 269 |  | 
|---|
 | 270 |         # Try to open the save file: | 
|---|
 | 271 |  | 
|---|
 | 272 |         if {[info exists state(auth,save,file)]} { | 
|---|
 | 273 |             if {![catch {set fd [open $state(auth,save,file) w]}]} { | 
|---|
 | 274 |                 puts $fd "array set ::irk::auth [list [array get auth $p1]]" | 
|---|
 | 275 |                 puts $fd "array set ::irk::auth [list [array get auth $p2]]" | 
|---|
 | 276 |                 puts $fd "array set ::irk::auth [list [array get auth $p3]]" | 
|---|
 | 277 |  | 
|---|
 | 278 |                 catch {close $fd} | 
|---|
 | 279 |             } | 
|---|
 | 280 |         } | 
|---|
 | 281 |     } | 
|---|
 | 282 |  | 
|---|
 | 283 |     # This procedure restores the authorization database: | 
|---|
 | 284 |  | 
|---|
 | 285 |     proc restoreauth {} { | 
|---|
 | 286 |         variable state | 
|---|
 | 287 |  | 
|---|
 | 288 |         if {[info exists state(auth,save,file)]} { | 
|---|
 | 289 |             catch {uplevel #0 source $state(auth,save,file)} | 
|---|
 | 290 |         } | 
|---|
 | 291 |         set state(auth,restored) 1 | 
|---|
 | 292 |     } | 
|---|
 | 293 |  | 
|---|
 | 294 |     # If this is the first time we're loading the IRK package, then | 
|---|
 | 295 |     # restore the authorization database. Otherwise we'd be overwriting | 
|---|
 | 296 |     # a potentially unsaved state. | 
|---|
 | 297 |  | 
|---|
 | 298 |     variable state | 
|---|
 | 299 |  | 
|---|
 | 300 |     if {![info exists state(auth,restored)]} { | 
|---|
 | 301 |         restoreauth | 
|---|
 | 302 |     } | 
|---|
 | 303 | } | 
|---|