Email Authentication with MIME

Email Authentication with MIME , by Jeff Gosnell, provides a couple of procedures that use Tcllib's Tcllib MIME package to authenticate a user on a email server that requires authentication.

email_authentication.tcl

[L1 ]

# created by Jeff Gosnell for the tcl community
# Tuesday, May 29, 2001
#
# a couple of simple procedures to authenticate a user
# on a mailserver that requires authentication.
#
# Take care when using these procedures.  They use the 
# global variable array user
#
# run the LogOn procedure to get a nice display.
# LogOn will then run VrfyUser 
# Make sure the pathname is correct for your installation
# of tcllib0.9's MIME package
#
# There is no visible result that the login was successful
# except that the .logOn window will disappear.
# When sending an email (in another procedure), 
# use $user(nameMIME) and $user(pwMIME) to authenticate.
#

proc LogOn {} {
    set w [toplevel .logOn]
    wm geometry $w 175x140+100+100
    wm title $w "Log On Information"
    
    set sw [frame $w.name]
    label $sw.lbl -text "Username: "
    entry $sw.ent -width 15 -textvariable user(name)
    pack $sw.lbl $sw.ent -side left -padx 2 -expand true
    
    set sw [frame $w.pw]
    label $sw.lbl -text "Password: "
    entry $sw.ent -width 15 -textvariable user(pw) -show *
    pack $sw.lbl $sw.ent -side left -padx 2 -expand true
 
    set sw [frame $w.server]
    label $sw.lbl -text "Mail Server:"
    entry $sw.ent -width 15 -textvariable user(mailserver)
    pack $sw.lbl $sw.ent -side left -padx 2 -expand true
 
    set sw [frame $w.buttons]
    button $sw.ok -text Ok -command {VrfyUser .logOn} -width 8
    button $sw.cancel -text Cancel -command {
        destroy .logOn; array unset user; return Cancelled} -width 8
    pack $sw.ok $sw.cancel -side left -padx 5 -expand true
 
    pack $w.name $w.pw $w.server $w.buttons -side top -pady 2 -expand true \
        -fill both
 
    bind $w <Return> {.logOn.buttons.ok invoke}
} ;# end proc LogOn


##########################################
#            proc VrfyUser               #
#                                        #
# This procedure is designed to verify   #
# the username and password for          #
# authenticating the user for emailing.  #
# It will notify the user if it fails.   #
#                                        #
#                                        #
##########################################
proc VrfyUser w {
    global user

    source {/program files/tcl/tcllib0.8/mime/mime.tcl}
    source {/program files/tcl/tcllib0.8/mime/smtp.tcl}
    package provide mime 1.2
    package provide smtp 1.2

    # display a toplevel showing the system logging in.
    toplevel $w.working -width 200 -height 100 -bg #ff3d3d
    wm overrideredirect $w.working 1
    wm geometry $w.working +150+150
    pack [
        frame $w.working.frame -bd 2 -relief raised -width 200 -height 100
    ] -ipadx 1 -ipady 1
    pack [label $w.working.frame.lbl -bg #ff3d3d -relief sunken \
        -text "Logging $user(name) on the system."] -fill both
    update

    # convert the username to mime format
    set t_name [mime::initialize -canonical text/octet-stream \
        -encoding base64 -string $user(name)]
    set user(nameMIME) [lindex [mime::buildmessage $t_name] end]
    mime::finalize $t_name -subordinates all

    # convert the password to mime format
    set t_pw [mime::initialize -canonical text/octet-stream \
        -encoding base64 -string $user(pw)]
    set user(pwMIME) [lindex [mime::buildmessage $t_pw] end]
    mime::finalize $t_pw -subordinates all

    # log on to the server
    set sid [socket $user(mailserver) 25]
    # if the server doesn't return 220 it failed
    if {[lindex [gets $sid] 0] != 220} {
        catch {destroy $w.msg}
        pack [label $w.msg -text \
            "Error logging in:  \nFailed to connect to server" \
            -font {-family Arial -size 10} -justify left
        ] -side bottom -pady 2
        catch {destroy $w.working}
        focus $w
        return
    }

    # log on user
    #Note the 'HELO' parameter is not actually a username.
    #It is generally supposed to be the client machines Hostname or IP address.
    # Some SMTP servers are fussier than others as to what they will accept here.
    # If the server is a 'Mail Submission Agent' for end-users it will probably accept almost anything.
    puts $sid "HELO $user(name)"
    flush $sid
    if {[lindex [gets $sid] 0] != 250} {
        catch {destroy $w.msg}
        pack [label $w.msg -text \
            "Error during HELO greeting:  \nHelo not accepted by server" \
            -font {-family Arial -size 10} -justify left
            ] -side bottom -pady 2
        catch {destroy $w.working}
        focus $w
        return
    }

    # attempt authentication
    puts $sid {AUTH LOGIN}
    flush $sid
    if {[lindex [gets $sid] 0] != 334} {
        catch {destroy $w.msg}
        pack [label $w.msg -text \
            "Error logging in:  \nFailed to initiate authorization" \
            -font {-family Arial -size 10} -justify left
            ] -side bottom -pady 2
        catch {destroy $w.working}
        focus $w
        return
    }

    # Username:
    puts $sid $user(nameMIME)
    flush $sid
    if {[lindex [gets $sid] 0] != 334} {
        catch {destroy $w.msg}
        pack [label $w.msg -text \
            "Error logging in:  \nInvalid username or password" \
            -font {-family Arial -size 10} -justify left
            ] -side bottom -pady 2
        catch {destroy $w.working}
        focus $w
        return
    }

    # Password:
    puts $sid $user(pwMIME)
    flush $sid
    if {[lindex [gets $sid] 0] != 235} {
        catch {destroy $w.msg}
        pack [label $w.msg -text \
            "Error logging in:  \nInvalid username or password" \
            -font {-family Arial -size 10} -justify left
            ] -side bottom -pady 2
        catch {destroy $w.working}
        focus $w
        return
    }

    close $sid
    destroy $w
    return {Log on successful}

} ;# end proc VrfyUser