]> git.ipfire.org Git - thirdparty/squid.git/blame - helpers/ntlm_auth/mswin_sspi/libntlmssp.c
SourceFormat: enforcement
[thirdparty/squid.git] / helpers / ntlm_auth / mswin_sspi / libntlmssp.c
CommitLineData
6e785d85 1/*
9af66127 2 * (C) 2002,2005 Guido Serassio <guido.serassio@acmeconsulting.it>
6e785d85 3 * Based on previous work of Francesco Chemolli and Robert Collins
4 * Distributed freely under the terms of the GNU General Public License,
5 * version 2. See the file COPYING for licensing details
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
26ac0430 11
6e785d85 12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
15 */
16
17typedef unsigned char uchar;
18
19#include "util.h"
20#include "ntlm.h"
21#if HAVE_CTYPE_H
22#include <ctype.h>
23#endif
24#include <lm.h>
25#include <ntsecapi.h>
26
27/* returns 1 on success, 0 on failure */
28int
29Valid_Group(char *UserName, char *Group)
30{
31 int result = FALSE;
32 WCHAR wszUserName[UNLEN+1]; // Unicode user name
33 WCHAR wszGroup[GNLEN+1]; // Unicode Group
34
35 LPLOCALGROUP_USERS_INFO_0 pBuf = NULL;
36 LPLOCALGROUP_USERS_INFO_0 pTmpBuf;
37 DWORD dwLevel = 0;
38 DWORD dwFlags = LG_INCLUDE_INDIRECT;
39 DWORD dwPrefMaxLen = -1;
40 DWORD dwEntriesRead = 0;
41 DWORD dwTotalEntries = 0;
42 NET_API_STATUS nStatus;
43 DWORD i;
44 DWORD dwTotalCount = 0;
45
26ac0430 46 /* Convert ANSI User Name and Group to Unicode */
6e785d85 47
48 MultiByteToWideChar(CP_ACP, 0, UserName,
26ac0430
AJ
49 strlen(UserName) + 1, wszUserName,
50 sizeof(wszUserName) / sizeof(wszUserName[0]));
6e785d85 51 MultiByteToWideChar(CP_ACP, 0, Group,
26ac0430 52 strlen(Group) + 1, wszGroup, sizeof(wszGroup) / sizeof(wszGroup[0]));
6e785d85 53
54 /*
26ac0430
AJ
55 * Call the NetUserGetLocalGroups function
56 * specifying information level 0.
57 *
58 * The LG_INCLUDE_INDIRECT flag specifies that the
59 * function should also return the names of the local
60 * groups in which the user is indirectly a member.
61 */
62 nStatus = NetUserGetLocalGroups(NULL,
63 wszUserName,
64 dwLevel,
65 dwFlags,
66 (LPBYTE *) & pBuf, dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries);
67 /*
68 * If the call succeeds,
69 */
6e785d85 70 if (nStatus == NERR_Success) {
26ac0430
AJ
71 if ((pTmpBuf = pBuf) != NULL) {
72 for (i = 0; i < dwEntriesRead; i++) {
73 if (pTmpBuf == NULL) {
74 result = FALSE;
75 break;
76 }
77 if (wcscmp(pTmpBuf->lgrui0_name, wszGroup) == 0) {
78 result = TRUE;
79 break;
80 }
81 pTmpBuf++;
82 dwTotalCount++;
83 }
84 }
6e785d85 85 } else
26ac0430
AJ
86 result = FALSE;
87 /*
88 * Free the allocated memory.
89 */
6e785d85 90 if (pBuf != NULL)
26ac0430 91 NetApiBufferFree(pBuf);
6e785d85 92 return result;
93}
94
95
96char * AllocStrFromLSAStr(LSA_UNICODE_STRING LsaStr)
97{
98 size_t len;
99 static char * target;
100
101 len = LsaStr.Length/sizeof(WCHAR) + 1;
102
103 /* allocate buffer for str + null termination */
104 safe_free(target);
105 target = (char *)xmalloc(len);
106 if (target == NULL)
26ac0430 107 return NULL;
6e785d85 108
109 /* copy unicode buffer */
110 WideCharToMultiByte(CP_ACP, 0, LsaStr.Buffer, LsaStr.Length, target, len, NULL, NULL );
111
112 /* add null termination */
113 target[len-1] = '\0';
114 return target;
115}
116
117
118char * GetDomainName(void)
119
120{
121 LSA_HANDLE PolicyHandle;
122 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
123 NTSTATUS status;
124 PPOLICY_PRIMARY_DOMAIN_INFO ppdiDomainInfo;
125 PWKSTA_INFO_100 pwkiWorkstationInfo;
126 DWORD netret;
127 char * DomainName = NULL;
128
26ac0430 129 /*
6e785d85 130 * Always initialize the object attributes to all zeroes.
26ac0430 131 */
6e785d85 132 memset(&ObjectAttributes, '\0', sizeof(ObjectAttributes));
133
26ac0430 134 /*
6e785d85 135 * You need the local workstation name. Use NetWkstaGetInfo at level
136 * 100 to retrieve a WKSTA_INFO_100 structure.
26ac0430 137 *
6e785d85 138 * The wki100_computername field contains a pointer to a UNICODE
139 * string containing the local computer name.
26ac0430 140 */
6e785d85 141 netret = NetWkstaGetInfo(NULL, 100, (LPBYTE *)&pwkiWorkstationInfo);
142 if (netret == NERR_Success) {
26ac0430
AJ
143 /*
144 * We have the workstation name in:
145 * pwkiWorkstationInfo->wki100_computername
146 *
147 * Next, open the policy object for the local system using
148 * the LsaOpenPolicy function.
149 */
150 status = LsaOpenPolicy(
151 NULL,
152 &ObjectAttributes,
153 GENERIC_READ | POLICY_VIEW_LOCAL_INFORMATION,
154 &PolicyHandle
155 );
156
157 /*
158 * Error checking.
159 */
160 if (status) {
161 debug("OpenPolicy Error: %ld\n", status);
162 } else {
163
164 /*
165 * You have a handle to the policy object. Now, get the
166 * domain information using LsaQueryInformationPolicy.
167 */
168 status = LsaQueryInformationPolicy(PolicyHandle,
169 PolicyPrimaryDomainInformation,
170 (void **)&ppdiDomainInfo);
171 if (status) {
172 debug("LsaQueryInformationPolicy Error: %ld\n", status);
173 } else {
174
175 /* Get name in useable format */
176 DomainName = AllocStrFromLSAStr(ppdiDomainInfo->Name);
177
178 /*
179 * Check the Sid pointer, if it is null, the
180 * workstation is either a stand-alone computer
181 * or a member of a workgroup.
182 */
183 if (ppdiDomainInfo->Sid) {
184
185 /*
186 * Member of a domain. Display it in debug mode.
187 */
188 debug("Member of Domain %s\n",DomainName);
189 } else {
190 DomainName = NULL;
6e785d85 191 }
26ac0430
AJ
192 }
193 }
194
195 /*
196 * Clean up all the memory buffers created by the LSA and
197 * Net* APIs.
198 */
199 NetApiBufferFree(pwkiWorkstationInfo);
200 LsaFreeMemory((LPVOID)ppdiDomainInfo);
201 } else
202 debug("NetWkstaGetInfo Error: %ld\n", netret);
6e785d85 203 return DomainName;
204}
205
206
207int ntlm_errno;
208
209
210/* returns NULL on failure, or a pointer to
211 * the user's credentials (domain\\username)
212 * upon success. WARNING. It's pointing to static storage.
213 * In case of problem sets as side-effect ntlm_errno to one of the
214 * codes defined in ntlm.h
215 */
216char *
217ntlm_check_auth(ntlm_authenticate * auth, int auth_length)
218{
219 int rv;
220 char domain[DNLEN+1];
221 char user[UNLEN+1];
222 static char credentials[DNLEN+UNLEN+2]; /* we can afford to waste */
223
224 lstring tmp;
225
226 if (!NTLM_LocalCall) {
227
228 tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain);
229
230 if (tmp.str == NULL || tmp.l == 0) {
26ac0430
AJ
231 debug("No domain supplied. Returning no-auth\n");
232 ntlm_errno = NTLM_BAD_REQUEST;
233 return NULL;
6e785d85 234 }
235 if (Use_Unicode) {
236 /* copy unicode buffer */
237 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) tmp.str, tmp.l, domain, DNLEN, NULL, NULL );
238 /* add null termination */
239 domain[tmp.l / sizeof(WCHAR)] = '\0';
240 } else {
241 if (tmp.l > DNLEN) {
26ac0430
AJ
242 debug("Domain string exceeds %d bytes, rejecting\n", DNLEN);
243 ntlm_errno = NTLM_BAD_REQUEST;
244 return NULL;
6e785d85 245 }
246 memcpy(domain, tmp.str, tmp.l);
247 domain[tmp.l] = '\0';
248 }
249 tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user);
250 if (tmp.str == NULL || tmp.l == 0) {
26ac0430
AJ
251 debug("No username supplied. Returning no-auth\n");
252 ntlm_errno = NTLM_BAD_REQUEST;
253 return NULL;
6e785d85 254 }
255 if (Use_Unicode) {
256 /* copy unicode buffer */
257 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) tmp.str, tmp.l, user, UNLEN, NULL, NULL );
258 /* add null termination */
259 user[tmp.l / sizeof(WCHAR)] = '\0';
260 } else {
261 if (tmp.l > UNLEN) {
26ac0430
AJ
262 debug("Username string exceeds %d bytes, rejecting\n", UNLEN);
263 ntlm_errno = NTLM_BAD_REQUEST;
264 return NULL;
6e785d85 265 }
266 memcpy(user, tmp.str, tmp.l);
267 user[tmp.l] = '\0';
268 }
269 debug("checking domain: '%s', user: '%s'\n", domain, user);
270
271 } else
272 debug("checking local user\n");
273
274 rv = SSP_ValidateNTLMCredentials(auth, auth_length, credentials);
275
276 debug("Login attempt had result %d\n", rv);
277
278 if (!rv) { /* failed */
26ac0430
AJ
279 ntlm_errno = NTLM_SSPI_ERROR;
280 return NULL;
6e785d85 281 }
26ac0430 282
6e785d85 283 if (UseAllowedGroup) {
26ac0430
AJ
284 if (!Valid_Group(credentials, NTAllowedGroup)) {
285 ntlm_errno = NTLM_BAD_NTGROUP;
286 debug("User %s not in allowed Group %s\n", credentials, NTAllowedGroup);
287 return NULL;
288 }
6e785d85 289 }
290 if (UseDisallowedGroup) {
26ac0430
AJ
291 if (Valid_Group(credentials, NTDisAllowedGroup)) {
292 ntlm_errno = NTLM_BAD_NTGROUP;
293 debug("User %s is in denied Group %s\n", credentials, NTDisAllowedGroup);
294 return NULL;
295 }
6e785d85 296 }
297
298 debug("credentials: %s\n", credentials);
299 return credentials;
300}
301
302
303const char *
304ntlm_make_negotiate(void)
305{
306 ntlm_negotiate ne;
307 const char *encoded;
308 memset(&ne, 0, sizeof(ntlm_negotiate)); /* reset */
309 memcpy(ne.signature, "NTLMSSP", 8); /* set the signature */
310 ne.type = le32toh(NTLM_NEGOTIATE); /* this is a challenge */
311 ne.flags = le32toh(
26ac0430
AJ
312 NEGOTIATE_ALWAYS_SIGN |
313 NEGOTIATE_USE_NTLM |
314 NEGOTIATE_USE_LM |
315 NEGOTIATE_ASCII |
316 0
317 );
6e785d85 318 encoded = base64_encode_bin((char *) &ne, NEGOTIATE_LENGTH);
319 debug("Negotiate packet not supplied - self generated\n");
320 return encoded;
321}
322
323
324void hex_dump(void *data, int size)
325{
326 /* dumps size bytes of *data to stdout. Looks like:
327 * [0000] 75 6E 6B 6E 6F 77 6E 20
328 * 30 FF 00 00 00 00 39 00 unknown 0.....9.
329 * (in a single line of course)
330 */
331
332 if (!data)
333 return;
334
335 if (debug_enabled) {
336 unsigned char *p = data;
337 unsigned char c;
338 int n;
339 char bytestr[4] = {0};
340 char addrstr[10] = {0};
341 char hexstr[ 16*3 + 5] = {0};
342 char charstr[16*1 + 5] = {0};
e1381638 343 for (n=1; n<=size; n++) {
6e785d85 344 if (n%16 == 1) {
345 /* store address for this line */
346 snprintf(addrstr, sizeof(addrstr), "%.4x",
26ac0430 347 ((unsigned int)p-(unsigned int)data) );
6e785d85 348 }
26ac0430 349
6e785d85 350 c = *p;
e4755e29 351 if (xisalnum(c) == 0) {
6e785d85 352 c = '.';
353 }
354
355 /* store hex str (for left side) */
356 snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
357 strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);
358
359 /* store char str (for right side) */
360 snprintf(bytestr, sizeof(bytestr), "%c", c);
361 strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);
362
26ac0430 363 if (n%16 == 0) {
6e785d85 364 /* line completed */
365 fprintf(stderr, "[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
366 hexstr[0] = 0;
367 charstr[0] = 0;
26ac0430 368 } else if (n%8 == 0) {
6e785d85 369 /* half line: add whitespaces */
370 strncat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1);
371 strncat(charstr, " ", sizeof(charstr)-strlen(charstr)-1);
372 }
373 p++; /* next byte */
374 }
375
376 if (strlen(hexstr) > 0) {
377 /* print rest of buffer if not empty */
378 fprintf(stderr, "[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
379 }
380 }
381}
382