| [5700] | 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 | } | 
|---|