TOC 
M. Rose
 Dover Beach Consulting, Inc.
 June 15, 2002

Tcl SASL v1.0.1

Abstract

Tcl SASL provides a Tcl interface to the Cyrus SASLv2 library.



 TOC 

Table of Contents




 TOC 

1. SYNOPSIS

    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.

1.1 Requirements

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 

2. CONVENTIONS

2.1 Return Codes

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.

2.2 Data Types

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.

2.3 Interactions

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.

2.4 Callbacks

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.

2.4.1 Client/Server callbacks

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.

2.4.2 Client-only callbacks

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)

2.4.3 Server-only callbacks

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 

3. PROCEDURES

3.1 Server-only calls

The calling sequence is:

  1. Invoke sasl::server_init to load plugins.
  2. On each incoming connection, invoke sasl::server_new to get a server token.
  3. Invoke $token -operation setprop to set the security properties for the connection.
  4. Invoke $token -operation list to get the list of mechanisms to send to the client.
  5. When client selects a mechanism, invoke $token -operation start, and go to Step 7.
  6. Invoke $token -operation step.
  7. Look at the result:
    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.

  8. Invoke $token -operation getprop to get the new security properties for the connection.

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.

3.2 Client-only calls

The calling sequence is:

  1. Invoke sasl::client_init to load plugins.
  2. On each outgoing connection, invoke sasl::client_new to get a client token.
  3. Invoke $token -operation setprop to set the security properties for the connection.
  4. When the server indicates which mechanisms are available invoke $token -operation start, and go to Step 6.
  5. Invoke $token -operation step.
  6. Look at the result:
    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.)

  7. Wait for the server's confirmation.
  8. Invoke $token -operation getprop to get the new security properties for the connection.

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.

3.3 Client/Server calls

$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.

3.4 Miscellaneous calls

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 

4. EXAMPLES

4.1 Server

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
    }
}

4.2 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 

References

[1] Myers, J., "Simple Authentication and Security Layer (SASL)", RFC 2222, October 1997.


 TOC 

Author's Address

  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 

Appendix A. Changes

From v1.0.0:



 TOC 

Appendix B. TODO List



 TOC 

Appendix C. Copyrights

(c) 2002 Marshall T. Rose

Hold harmless the author, and any lawful use is allowed.



 TOC 

Index

C 
 callbacks
   authname
   canonuser
   checkpass
   cnonce
   echoprompt
   getopt
   getpath
   getrealm
   language
   log
   noechoprompt
   pass
   proxy
   setpass
   user
   verifyfile
P 
 procedures
   client -operation start
   client -operation step
   sasl::client_init
   sasl::client_new
   sasl::decode64
   sasl::done
   sasl::encode64
   sasl::errstring
   sasl::info
   sasl::mechanisms
   sasl::server_init
   sasl::server_new
   server -operation auxprop_getctx
   server -operation auxprop_request
   server -operation checkpass
   server -operation list
   server -operation setpass
   server -operation start
   server -operation step
   server -operation userexists
   token -operation decode
   token -operation encode
   token -operation errdetail
   token -operation getprop
   token -operation info
   token -operation setprop