]> Pileus Git - ~andy/fetchmail/blob - smbutil.c
Note Earl's regression fix for SSL_CTX_clear_options() on older OpenSSL.
[~andy/fetchmail] / smbutil.c
1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <ctype.h>
5 #include <assert.h>
6 #include <string.h>
7 #include "ntlm.h"
8 #include "smbencrypt.h"
9 #include "smbbyteorder.h"
10 #include "fetchmail.h"
11
12 char versionString[] ="libntlm version 0.21";
13
14 /* Utility routines that handle NTLM auth structures. */
15
16 /* The [IS]VAL macros are to take care of byte order for non-Intel
17  * Machines -- I think this file is OK, but it hasn't been tested.
18  * The other files (the ones stolen from Samba) should be OK.
19  */
20
21
22 /* I am not crazy about these macros -- they seem to have gotten
23  * a bit complex.  A new scheme for handling string/buffer fields
24  * in the structures probably needs to be designed
25  */
26
27 #define AddBytes(ptr, header, buf, count) \
28 { \
29 if (buf != NULL && count != 0) \
30   { \
31   SSVAL(&ptr->header.len,0,count); \
32   SSVAL(&ptr->header.maxlen,0,count); \
33   SIVAL(&ptr->header.offset,0,((ptr->buffer - ((uint8*)ptr)) + ptr->bufIndex)); \
34   memcpy(ptr->buffer+ptr->bufIndex, buf, count); \
35   ptr->bufIndex += count; \
36   } \
37 else \
38   { \
39   ptr->header.len = \
40   ptr->header.maxlen = 0; \
41   SIVAL(&ptr->header.offset,0,ptr->bufIndex); \
42   } \
43 }
44
45 #define AddString(ptr, header, string) \
46 { \
47 char *p_ = string; \
48 int len_ = 0; \
49 if (p_) len_ = strlen(p_); \
50 AddBytes(ptr, header, ((unsigned char*)p_), len_); \
51 }
52
53 #define AddUnicodeString(ptr, header, string) \
54 { \
55 char *p_ = string; \
56 unsigned char *b_ = NULL; \
57 int len_ = 0; \
58 if (p_) \
59   { \
60   len_ = strlen(p_); \
61   b_ = strToUnicode(p_); \
62   } \
63 AddBytes(ptr, header, b_, len_*2); \
64 }
65
66
67 #define GetUnicodeString(structPtr, header) \
68 unicodeToString(((char*)structPtr) + IVAL(&structPtr->header.offset,0) , SVAL(&structPtr->header.len,0)/2)
69 #define GetString(structPtr, header) \
70 toString((((char *)structPtr) + IVAL(&structPtr->header.offset,0)), SVAL(&structPtr->header.len,0))
71 #define DumpBuffer(fp, structPtr, header) \
72 dumpRaw(fp,((unsigned char*)structPtr)+IVAL(&structPtr->header.offset,0),SVAL(&structPtr->header.len,0))
73
74
75 static void dumpRaw(FILE *fp, unsigned char *buf, size_t len)
76   {
77   size_t i;
78   
79   for (i=0; i<len; ++i)
80     fprintf(fp,"%02x ",buf[i]);
81     
82     fprintf(fp,"\n");
83   }
84
85 /* helper macro to destructively resize buffers; assumes that bufsiz
86  * is initialized to 0 if buf is unallocated! */
87 #define allocbuf(buf, bufsiz, need, type) do { \
88   if (!buf || (need) > (bufsiz)) \
89     { \
90     (bufsiz) = ((need) < 1024) ? 1024 : (need); \
91     xfree(buf); \
92     (buf) = (type)xmalloc(bufsiz); \
93     } \
94   } while (0);
95
96 /* this is a brute-force conversion from UCS-2LE to US-ASCII, discarding
97  * the upper 9 bits */
98 static char *unicodeToString(char *p, size_t len)
99   {
100   size_t i;
101   static char *buf;
102   static size_t bufsiz;
103
104   allocbuf(buf, bufsiz, len + 1, char *);
105
106   for (i=0; i<len; ++i)
107     {
108     buf[i] = *p & 0x7f;
109     p += 2;
110     }
111
112   buf[i] = '\0';
113   return buf;
114   }
115
116 /* This is a brute-force conversion from US-ASCII to UCS-2LE */
117 static unsigned char *strToUnicode(char *p)
118   {
119   static unsigned char *buf;
120   static size_t bufsiz;
121   size_t l = strlen(p);
122   int i = 0;
123
124   allocbuf(buf, bufsiz, l * 2, unsigned char *);
125
126   while (l--)
127     {
128     buf[i++] = *p++;
129     buf[i++] = 0;
130     }
131
132   return buf;
133   }
134
135 static unsigned char *toString(char *p, size_t len)
136   {
137   static unsigned char *buf;
138   static size_t bufsiz;
139
140   allocbuf(buf, bufsiz, len + 1, unsigned char *);
141
142   memcpy(buf,p,len);
143   buf[len] = 0;
144   return buf;
145   }
146
147 void dumpSmbNtlmAuthRequest(FILE *fp, tSmbNtlmAuthRequest *request)
148   {
149   fprintf(fp,"NTLM Request:\n");
150   fprintf(fp,"      Ident = %s\n",request->ident);
151   fprintf(fp,"      mType = %ld\n",(long int)IVAL(&request->msgType,0));
152   fprintf(fp,"      Flags = %08x\n",IVAL(&request->flags,0));
153   fprintf(fp,"       User = %s\n",(char *)GetString(request,user));
154   fprintf(fp,"     Domain = %s\n",(char *)GetString(request,domain));
155   }
156
157 void dumpSmbNtlmAuthChallenge(FILE *fp, tSmbNtlmAuthChallenge *challenge)
158   {
159   fprintf(fp,"NTLM Challenge:\n");
160   fprintf(fp,"      Ident = %s\n",challenge->ident);
161   fprintf(fp,"      mType = %ld\n",(long int)IVAL(&challenge->msgType,0));
162   fprintf(fp,"     Domain = %s\n",GetUnicodeString(challenge,uDomain));
163   fprintf(fp,"      Flags = %08x\n",IVAL(&challenge->flags,0));
164   fprintf(fp,"  Challenge = "); dumpRaw(fp, challenge->challengeData,8);
165   }
166
167 void dumpSmbNtlmAuthResponse(FILE *fp, tSmbNtlmAuthResponse *response)
168   {
169   fprintf(fp,"NTLM Response:\n");
170   fprintf(fp,"      Ident = %s\n",response->ident);
171   fprintf(fp,"      mType = %ld\n",(long int)IVAL(&response->msgType,0));
172   fprintf(fp,"     LmResp = "); DumpBuffer(fp,response,lmResponse);
173   fprintf(fp,"     NTResp = "); DumpBuffer(fp,response,ntResponse);
174   fprintf(fp,"     Domain = %s\n",GetUnicodeString(response,uDomain));
175   fprintf(fp,"       User = %s\n",GetUnicodeString(response,uUser));
176   fprintf(fp,"        Wks = %s\n",GetUnicodeString(response,uWks));
177   fprintf(fp,"       sKey = "); DumpBuffer(fp, response,sessionKey);
178   fprintf(fp,"      Flags = %08x\n",IVAL(&response->flags,0));
179   }
180
181 void buildSmbNtlmAuthRequest(tSmbNtlmAuthRequest *request, char *user, char *domain)
182   {
183     char *u = xstrdup(user);
184     char *p = strchr(u,'@');
185     
186     if (p)
187       {
188         if (!domain) 
189           domain = p+1;
190         *p = '\0';
191       }
192     
193     request->bufIndex = 0;
194     memcpy(request->ident,"NTLMSSP\0\0\0",8);
195     SIVAL(&request->msgType,0,1);
196     SIVAL(&request->flags,0,0x0000b207);  /* have to figure out what these mean */
197     AddString(request,user,u);
198     AddString(request,domain,domain);
199     free(u);
200   }
201
202 void buildSmbNtlmAuthResponse(tSmbNtlmAuthChallenge *challenge, tSmbNtlmAuthResponse *response, char *user, char *password)
203   {
204     uint8 lmRespData[24];
205     uint8 ntRespData[24];
206     char *d = xstrdup(GetUnicodeString(challenge,uDomain));
207     char *domain = d;
208     char *u = xstrdup(user);
209     char *p = strchr(u,'@');
210     
211     if (p)
212       {
213         domain = p+1;
214         *p = '\0';
215       }
216     
217     SMBencrypt((uint8*)password,   challenge->challengeData, lmRespData);
218     SMBNTencrypt((uint8*)password, challenge->challengeData, ntRespData);
219     
220     response->bufIndex = 0;
221     memcpy(response->ident,"NTLMSSP\0\0\0",8);
222     SIVAL(&response->msgType,0,3);
223     
224     AddBytes(response,lmResponse,lmRespData,24);
225     AddBytes(response,ntResponse,ntRespData,24);
226     AddUnicodeString(response,uDomain,domain);
227     AddUnicodeString(response,uUser,u);
228     AddUnicodeString(response,uWks,u);
229     AddString(response,sessionKey,NULL);
230   
231     response->flags = challenge->flags;
232     
233     free(d);
234     free(u);
235   }
236