Subject: RE: smtp cram-md5

From: "Gard, Torbjorn" <[email-masked]>
Date: Wed, 29 Oct 2003 15:36:59 +0100

Hello Mark!

Thanks a lot for this info! Seems I have a lot to do :-)

regards
Torbjörn

-----Original Message-----
From: Mark Crispin [mailto:[email-masked]] 
Sent: den 29 oktober 2003 15:21
To: Gard, Torbjorn
Cc: [email-masked]'
Subject: Re: smtp cram-md5

On Wed, 29 Oct 2003, Gard, Torbjorn wrote:
> How is the user set? I tried mail_parameters(NIL,SET_USERNAME,"xxxx");
This
> did not work.

Nor is it likely to.  That function sets c-client's idea of the local user
name on UNIX systems only, overriding what was previously there.  I've
long ago forgotten why it was needed, and I suspect that in fact it no
longer is needed.

> The way I got it to work somewhat is to use this:
>  stream = smtp_open_full
>
(NIL,hostlist,"service=smtp/user=xxxx",SMTPTCPPORT,SOP_DSN|OP_DEBUG|SOP_DSN_
> NOTIFY_FAILURE);

That "service=smtp/user=xxxx" is wrong.  The third argument to
smtp_open_full() is a service name, not a series of switches.  It turns
out that the code currently does not enforce that, nor does it break if
you kludge by doing this, but there is no guarantee that it will work in
the future.

The proper place to put /user=xxxx is in the individual entries of the
hostlist.

Also, there is no need for most applications to pass a NETDRIVER dispatch,
service name, or port number; all of this is only needed if you are using
a non-TCP connection to the SMTP server.  If you want to use a
non-standard port number for a particular server you can/should pass that
in the individual entry in the hostlist as ":port".

In other words, individual entries on the hostlist would look like:
	smtp.example.com/user=fred
	smtp.example.com:4025/user=joe
etc. and you should simply use the smtp_open() interface as such:
 stream = smtp_open (hostlist,SOP_DSN|OP_DEBUG|SOP_DSN_NOTIFY_FAILURE);

> But it still wants the user in the mm_login callback!

Yes, of course.  mm_login() is the means by which the password is
obtained.  You'll notice that the /user=xxxx username is passed in the
first argument, so all mm_login functions should look something like:

void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
{
  if (*mb->user) strcpy (user,mb->user);
  else {
   ...prompt for user name...
  }
  ...prompt for password...
}

Look at the sample code in mtest and mailutil and you will see this type
of construct.

It is alright to use strcpy() since the NETMBX username is constrained in
size to be smaller than the user buffer that is passed to mm_login().

> So I fill in the same
> user in this function and call auth_md5_pwd() with the user like this:
>
> void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
> {
>  strcpy(user,"xxxx");
>  strcpy(pwd,auth_md5_pwd(user));
> }

Ugh.  Here you are trying to use the cram-md5.pwd file, which is a
*server* password database for UNIX systems, as a cache for *client*
passwords on Windows.

Such usage was never intended to work.  What's more, the cram-md5.pwd file
only works on servers running on DOS-based Windows (Windows 95, Windows
98, Windows Millenium) because on NT-based Windows (Windows NT, Windows
2000, Windows XP) logon requires the real password which is stored in the
NT accounts data.

The password has to be provided by your application -- that is why
mm_login() is called! -- and if there is any sort of cache of passwords it
is something that your application should provide.

> Then it seems to work ... but I have not been able to get the
authorization
> to work. (500 5.7.0 authentication failed). I have verified that there is
an
> exchange of:
> "334 PDM4NTk2MDE1MDcuMTAzODM1NDFAc3RyZWFtc2VydmUuY29tPg=="
> "dGdhMDEgMTkxMDBiODRiYjFiODBjYTYxNzI0MzliNjE0NjM5OGY="

There are any number of places in which it could have gone wrong.  I
suggest that you start by undoing all of your hacks to c-client (revert to
an unmodified c-client), then go about calling and using it properly as I
indicated above.  Maybe the problem will magically go away.

If it does not go away...  Did you try communicating with that SMTP server
using Pine or some other c-client based application which is known to work
right?  If it works in Pine, then review what I told you to do in the
previous paragraph.

If it fails in Pine, are you sure that you have the correct password for
that SMTP server?  Are you certain that the SMTP server is properly set up
for CRAM-MD5 authentication?  Note that a UNIX based server can't use the
/etc/passwd or /etc/shadow passwords for CRAM-MD5 authentication; it must
have access to plaintext or plaintext equivalent of the passwords.

> I
> am using makefile.nt without modification. I removed two leading
backslashes
> from the content of MD5ENABLE to read "cram-md5.pwd" instead.
> In order to set the service argument to  smtp_open_full with
> ,"service=smtp/user=xxxx" I had to modify a sprintf() like this in
> smtp.c:smtp_open_full:
>     sprintf (tmp,"{%.800s/%.200s}",*hostlist,service ? service : "smtp");
> The previous behaviour was to use only 20 characters in service.

The fact that you felt that you had to do these types of changes should
have alerted you to the fact that you were going about the problem all
wrong.  There is a reason why there were two leading backslashes in
MD5ENABLE.  There is a reason why smtp_open_full() used only 20 characters
for the service.

A good rule of thumb is that it's better to ask questions first before
making changes to a widely-used library.  In some cases, if you are
configuring an IMAP or POP3 server, it may be necessary to make changes in
c-client's env_unix.c module.  There is no reason, that I can think of,
that client applications would ever need to have to modify c-client.

> I have configured sendmail-8.11.6-25.72 to support cram-md5 (250-AUTH
> DIGEST-MD5 CRAM-MD5).

Please note what I mentioned above about proper configuration of your
server and in particular of the password requirements for CRAM-MD5.

-- Mark --

http://staff.washington.edu/mrc
Science does not emerge from voting, party politics, or public debate.
Si vis pacem, para bellum.