]> Pileus Git - ~andy/fetchmail/blob - ntlmsubr.c
Credit John Beck's fixes.
[~andy/fetchmail] / ntlmsubr.c
1 #include "config.h"
2
3 #ifdef NTLM_ENABLE
4 #include "fetchmail.h"
5 #include "i18n.h"
6 #include "ntlm.h"
7 #include "socket.h"
8
9 #include <string.h>
10
11 int ntlm_helper(int sock, struct query *ctl, const char *proto)
12 {
13 /*
14  * NTLM support by Grant Edwards.
15  *
16  * Handle MS-Exchange NTLM authentication method.  This is the same
17  * as the NTLM auth used by Samba for SMB related services. We just
18  * encode the packets in base64 instead of sending them out via a
19  * network interface.
20  *
21  * Much source (ntlm.h, smb*.c smb*.h) was borrowed from Samba.
22  */
23     tSmbNtlmAuthRequest request;
24     tSmbNtlmAuthChallenge challenge;
25     tSmbNtlmAuthResponse response;
26
27     char msgbuf[2048];
28     int result;
29
30     if ((result = gen_recv(sock, msgbuf, sizeof msgbuf)))
31         return result;
32
33     if (msgbuf[0] != '+' && strspn(msgbuf+1, " \t") < strlen(msgbuf+1)) {
34         if (outlevel >= O_VERBOSE) {
35             report(stdout, GT_("Warning: received malformed challenge to \"AUTH(ENTICATE) NTLM\"!\n"));
36         }
37         result = PS_AUTHFAIL;
38         goto cancelfail;
39     }
40
41     buildSmbNtlmAuthRequest(&request,ctl->remotename,NULL);
42
43     if (outlevel >= O_DEBUG)
44         dumpSmbNtlmAuthRequest(stdout, &request);
45
46     memset(msgbuf,0,sizeof msgbuf);
47     to64frombits (msgbuf, &request, SmbLength(&request));
48
49     if (outlevel >= O_MONITOR)
50         report(stdout, "%s> %s\n", proto, msgbuf);
51
52     strcat(msgbuf,"\r\n");
53     SockWrite (sock, msgbuf, strlen (msgbuf));
54
55     if ((result = gen_recv(sock, msgbuf, sizeof msgbuf)))
56         goto cancelfail;
57
58     /*
59      * < 0: decoding error
60      * >= 0 < 32: too short to be plausible
61      */
62     if ((result = from64tobits (&challenge, msgbuf, sizeof(challenge))) < 0
63             || result < 32)
64     {
65         report (stderr, GT_("could not decode BASE64 challenge\n"));
66         /* We do not goto cancelfail; the server has already sent the
67          * tagged reply, so the protocol exchange has ended, no need
68          * for us to send the asterisk. */
69         return PS_AUTHFAIL;
70     }
71
72     /* validate challenge:
73      * - ident
74      * - message type
75      * - that offset points into buffer
76      * - that offset + length does not wrap
77      * - that offset + length is not bigger than buffer */
78     if (0 != memcmp("NTLMSSP", challenge.ident, 8)
79             || challenge.msgType != 2
80             || challenge.uDomain.offset > (unsigned)result
81             || (challenge.uDomain.offset + challenge.uDomain.len) < challenge.uDomain.offset
82             || (challenge.uDomain.offset + challenge.uDomain.len) > (unsigned)result)
83     {
84         report (stderr, GT_("NTLM challenge contains invalid data.\n"));
85         result = PS_AUTHFAIL;
86         goto cancelfail;
87     }
88
89     if (outlevel >= O_DEBUG)
90         dumpSmbNtlmAuthChallenge(stdout, &challenge);
91
92     buildSmbNtlmAuthResponse(&challenge, &response,ctl->remotename,ctl->password);
93
94     if (outlevel >= O_DEBUG)
95         dumpSmbNtlmAuthResponse(stdout, &response);
96
97     memset(msgbuf,0,sizeof msgbuf);
98     to64frombits (msgbuf, &response, SmbLength(&response));
99
100     if (outlevel >= O_MONITOR)
101         report(stdout, "%s> %s\n", proto, msgbuf);
102
103     strcat(msgbuf,"\r\n");
104     SockWrite (sock, msgbuf, strlen (msgbuf));
105
106     return PS_SUCCESS;
107
108 cancelfail: /* cancel authentication and return failure */
109     {
110         if (outlevel >= O_MONITOR)
111             report(stdout, "%s> *\n", proto);
112         SockWrite(sock, "*\r\n", 3);
113         return result;
114     }
115 }
116
117 #endif /* NTLM_ENABLE */