TOC |
|
Tcl SASL provides a Tcl interface to the Cyrus SASLv2 library.
TOC |
TOC |
package provide sasl 1.0
Tcl SASL provides a Tcl interface to the Cyrus SASLv2 library.
This document won't tell you what SASL[1] is. What it will tell you, the Tcl programmer, is how you can access the Cyrus SASLv2 library from your Tcl script.
First, you'll need to have Cyrus SASL v2.1.0 (or later) already installed. Look at the download area, look for a file named "cyrus-sasl-2.*.tar.gz". (Be sure to avoid any Cyrus SASL v1 releases.)
If, for some reason, you have this file, but not the source distribution, you can find it here.
TOC |
If an exception occurs in a Cyrus SASL library function, an error is thrown and the errorCode global is set to a list containing four elements:
In addition to the usual "normal" return, four routines (sasl::server_start, sasl::server_step, sasl::client_start, and sasl::client_step) may also use the "continue" return. This occurs when the corresponding Cyrus SASL library function returns SASL_CONTINUE.
A serialized array is a list that contains an series of keywords and values.
A serialized array can be traversed using foreach, e.g.,
foreach {k v} $aList { puts stdout "$k has value $v" }
Alternatively, an array can be initialized and accessed, e.g.,
array set data $aList if {[info exists data(plugin)]} { puts stdout "plugin entry is present" }
Several routines accept serialized arrays as arguments. In particular, the Cyrus SASL security properties is expressed as a serialized array with these elements:
With the exception of flags, each of these takes an integer value. The flags entry takes a list value. To find out what flags are known, try sasl::info sec_flags.
Two routines (sasl::client_start and sasl::client_step) have an optional -interact switch that takes a script argument.
When evaluated, the script is given one argument, a serialized array. At a minimum, the id element is present in the serialized array. Optionally, three other elements (challenge, prompt, and default) may also be present.
If the script makes a normal return, the return value is supplied to the Cyrus SASL library.
Four routines (sasl::server_init, sasl::server_new, sasl::client_init, and sasl::client_new) have a -callbacks switch that takes a list argument. Each element of the list is either:
The former case is used by clients to tell the Cyrus SASL library what information may be determined using an interaction. Otherwise, the supplied script is evaluated to get the indicated information.
In this latter case, the script is given one argument, a serialized array containing callback-specific elements.
- getopt:
- Returns a string.
Elements:
- ?plugin?
- option
- log:
- Elements:
- level
- message
- getpath:
- Returns a string.
Elements: none.
- verifyfile:
- Returns an integer (a SASL result code), either 0 (SASL_OK), 1 (SASL_CONTINUE), or -1 (SASL_FAIL).
Elements:
- file
- type
To find out what types are known, try sasl::info verify_types.
- user:
- Returns a string.
Elements: id
- authname:
- Returns a string.
Elements: id
- language:
- Returns a string.
Elements: id
- cnonce:
- Returns a string.
Elements: id
- pass:
- Returns a string.
Elements:
- token (a client token)
- id
- ?no?echoprompt:
- Returns a string.
Elements:
- id
- challenge
- prompt
- default
- getrealm:
- Returns a string.
Elements:
- id
- ?available? (a list of possible choices)
- proxy:
- Returns an integer (a SASL result code), usually either 0 (SASL_OK), or -14 (SASL_NOAUTHZ).
Elements:
- token (a server token)
- target
- user
- ?realm?
- ?propctx? (a propctx token)
- checkpass:
- Returns an integer (a SASL result code).
Elements:
- token (a server token)
- user
- pass
- ?propctx? (a propctx token)
- setpass:
- Returns an integer (a SASL result code).
Elements:
- token (a server token)
- user
- pass
- flags
- ?propctx? (a propctx token)
To find out what flags are known, try sasl::info setpass_flags.
- canonuser:
- Returns a string.
Elements:
- token (a server token)
- in
- ?realm?
- outmax
- flags
To find out what flags are known, try sasl::info canon_flags.
TOC |
The calling sequence is:
- normal return:
- Tell the client it's successful and goto Step 8.
- continue return:
- Send the result to the client, wait for more input, and goto Step 6.
- error return:
- Tell the client it loses and abort.
Now, let's look at the actual procedures.
sasl::server_init \ -callbacks list \ ?-appname string?
Initialize server-side code, supplying default -callbacks and an -appname for logging.
sasl::server_new \ -service string \ ?-serverFQDN string? \ ?-realm string? \ ?-iplocalport string? \ ?-ipremoteport string? \ ?-callbacks script? \ ?-flags list?
Return a "server token" for a single SASL connection, supplying the registered name of the -service. To find out what flags are known, try sasl::info servernew_flags.
$token -operation list \ ?-user string?
Return a list of mechanisms available to the server.
$token -operation start \ -mechanism string \ ?-input string?
Start a -mechanism (optionally, with an -input string from the client), returning an output string for the client.
$token -operation step \ -input string
Perform another exchange, taking an input string from the client, returning an output string for the client.
$token -operation checkpass \ -user string \ -pass string
Determine if a plaintext password is valid; if not, throw an error.
$token -operation userexists \ -server string \ ?-realm string? \ -user string
Determine if a user exists; it not, throw an error.
$token -operation setpass \ -user string \ ?-realm string? \ ?-newpass string? \ ?-oldpass string? \ ?-flags list?
Set the password for a user; on failure, throw an error. If the -realm switch is given, then in addition to setting mechanism-specific passwords, the password in the generic sasldb is set as well. To find out what flags are known, try sasl::info setpass_flags.
$token -operation auxprop_request \ ?-properties list?
Request a set of auxiliary -properties (or reset the list if this switch is absent); on failure, throw an error.
$token -operation auxprop_getctx
Return a "propctx token" containing the current auxiliary properties.
The calling sequence is:
- normal return:
- If the result is empty, goto Step 8; otherwise, send the result to the server and goto Step 7
- continue return:
- Send the result to the server, wait for more input, and goto Step 5.
- error return:
- You lose, abort.
(If you're familiar with the Cyrus SASL library API, you'll notice there is no "interaction" return Tcl SASL handles this through a callback for you.)
Now, let's look at the actual procedures.
sasl::client_init \ -callbacks list
Initialize client-side code, supplying default -callbacks.
sasl::client_new \ -service string \ -serverFQDN string \ ?-iplocalport string? \ ?-ipremoteport string? \ ?-callbacks script? \ ?-flags list?
Return a "client token" for a single SASL connection, supplying the registered name of the -service, and the -serverFQDN of the server. To find out what flags are known, try sasl::info clientnew_flags.
$token -operation start \ -mechanisms list \ ?-interact script?
Select one of the given -mechanisms, and return a serialized array containing two elements: the mechanism to use, and, an output string for the server.
$token -operation step \ -input string \ ?-interact script?
Perform another exchange, taking an input string from the server, returning an output string for the server.
$token -operation info
Return a list of known operations for the token.
$token -operation getprop \ -property string
Return a string corresponding to the value of the given -property. To find out what properties are known, try sasl::info getprops.
$token -operation setprop \ -property string \ -value string
Set the -value of the given -property. To find out what properties are known, try sasl::info setprops.
$token -operation errdetail
Return the detail for the last error encountered for the token.
$token -operation decode \ -input string
Take an -input string and decipher/verify it (using the previously-negotiated security layer), and return a plaintext string.
$token -operation encode \ -input string
Take an -output string and encipher/sign it (using the previously-negotiated security layer), and return a string to be sent over the network.
sasl::decode64 string
Return a string decoded from base64.
sasl::done
Release all resources associated with this package.
sasl::encode64 string
Return a string encoded to base64.
sasl::errstring -code number \ ?-languages string?
Take a SASL result -code and a list of -languages (e.g., "en-US"), and return a serialized array containing two elements: the corresponding diagnostic string, and, optionally, the language used to localize the diagnostic.
sasl::info ?option?
Return a list of known options, or a list of known choices for a given option.
sasl::mechanisms
Return a list of all known mechanisms.
TOC |
proc sasl_log {data} { array set params $data # look at data(level) and data(message) } proc server_callback {id data} { array set params $data # look at data(level) and data(message) global server array set params $data switch -- $id { getopt { if {![info exists params(plugin)]} { set params(plugin) "" } switch -- $params(plugin)/$params(option) { /auto_transition - /canon_user_plugin - /mech_list - /sasldb_path - OTP/opiekeys - default { # if value isn't set, an error is thrown below # that's okay, the Cyrus SASL library will use a default value } } } verifyfile { # set value... } proxy { # set value... } checkpass { # set value... } } return $value } sasl::server_init -callbacks [list [list log sasl_log]] set callbacks {} foreach id [list getopt verifyfile proxy checkpass] { lappend callbacks [list $id "server_callback $id"] } set token [sasl::server_new -service $service \ -callbacks $callbacks \ -flags [list success_data]] if {$ssf > 0} { $token -operation setprop ssf_external $ssf } if {[string length $clientID] > 0} { $token -operation setprop auth_external $clientID } $token -operation setprop sec_props \ [list min_ssf $min \ max_ssf $max \ max_bufsize $bufsiz \ flags $flags] set mechlist [$token -operation list] # send $mechlist to client # recv mechanism and input from client set code 4 for {set operation start} {$code == 4} {set operation step} { set cmd [list $token -operation $operation \ -input $input] if {![string compare $operation start]} { lappend cmd -mechanism $mechanism } switch -- [set code [catch { eval $cmd } output]] { 0 { # send success to client set ssf [$token -operation getprop ssf] } 4 { # send continue to client with output # recv input from client } default { # send error to client } }
proc client_callback {data} { global client array set params $data switch -- $params(id) { pass - echoprompt - noechoprompt { # ask the user... } getrealm { if {[info exists params(available)]} { # ask the user to pick one from the list... } else { # ask the user to supply one... } } } return $value } proc client_interact {data} { global client array set params $data set id $params(id) catch { set value $params(default) } # ask the user to enter the $id using $params(prompt)... return $value } sasl::client_init -callbacks [list [list log sasl_log]] # interact script will supply these set callbacks [list authname cnonce language user] # callback script will supply these foreach id [list pass echoprompt noechoprompt] { lappend callbacks [list $id client_callback] } set token [sasl::client_new -service $service \ -serverFQDN $fqdn \ -callbacks $callbacks \ -flags [list success_data]] if {$ssf > 0} { $token -operation setprop ssf_external $ssf } if {[string length $serverID] > 0} { $token -operation setprop auth_external $serverID } $token -operation setprop sec_props \ [list min_ssf $min \ max_ssf $max \ max_bufsize $bufsiz \ flags $flags] # recv mechlist from server switch -- [set code [catch { $token -operation start \ -mechanisms $mechlist \ -interact client_interact } result]] { 0 - 4 { array set data $result # send data(mechanism) and optionally data(output) to server # recv input from server set code 4 } default { # error! } } while {$code == 4} { switch -- [set code [catch { $token -operation step \ -input $input \ -interact client_interact } output]] { 0 { if {![string compare $output ""]} { break } } 4 { } default { # error! } # make sure that server response says to continue... # send output to server # recv input from server } # make sure that server's last response says complete... }
TOC |
[1] | Myers, J., "Simple Authentication and Security Layer (SASL)", RFC 2222, October 1997. |
TOC |
Marshall T. Rose | |
Dover Beach Consulting, Inc. | |
POB 255268 | |
Sacramento, CA 95865-5268 | |
US | |
Phone: | +1 916 483 8878 |
Fax: | +1 916 483 8848 |
EMail: | mrose@dbc.mtview.ca.us |
TOC |
From v1.0.0:
TOC |
TOC |
(c) 2002 Marshall T. Rose
Hold harmless the author, and any lawful use is allowed.
TOC |