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