ntlm_sspi_auth.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/*
10 * ntlm_sspi_auth: helper for NTLM Authentication for Squid Cache
11 *
12 * (C)2002,2005 Guido Serassio - Acme Consulting S.r.l.
13 *
14 * Authors:
15 * Guido Serassio <guido.serassio@acmeconsulting.it>
16 * Acme Consulting S.r.l., Italy <http://www.acmeconsulting.it>
17 *
18 * With contributions from others mentioned in the change history section
19 * below.
20 *
21 * Based on previous work of Francesco Chemolli and Robert Collins.
22 *
23 * Dependencies: Windows NT4 SP4 and later.
24 *
25 * This program is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation; either version 2 of the License, or
28 * (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program; if not, write to the Free Software
37 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
38 *
39 * History:
40 *
41 * Version 1.22
42 * 29-10-2005 Guido Serassio
43 * Updated for Negotiate auth support.
44 * Version 1.21
45 * 21-02-2004 Guido Serassio
46 * Removed control of use of NTLM NEGOTIATE packet from
47 * command line, now the support is automatic.
48 * Version 1.20
49 * 30-11-2003 Guido Serassio
50 * Added support for NTLM local calls.
51 * Added control of use of NTLM NEGOTIATE packet from
52 * command line.
53 * Updated documentation.
54 * Version 1.10
55 * 07-09-2003 Guido Serassio
56 * Now is true NTLM authenticator.
57 * More debug info.
58 * Updated documentation.
59 * Version 1.0
60 * 29-06-2002 Guido Serassio
61 * First release.
62 *
63 *
64 */
65
66/************* CONFIGURATION ***************/
67
68#define FAIL_DEBUG 0
69
70/************* END CONFIGURATION ***************/
71
72//typedef unsigned char uchar;
73
74#include "squid.h"
75#include "base64.h"
77#include "ntlmauth/ntlmauth.h"
79#include "sspi/sspwin32.h"
80#include "util.h"
81
82#include <cctype>
83#include <lm.h>
84#if HAVE_GETOPT_H
85#include <getopt.h>
86#endif
87
89static int have_challenge;
94
95#if FAIL_DEBUG
96int fail_debug_enabled = 0;
97#endif
98
99/* returns 1 on success, 0 on failure */
100int
101Valid_Group(char *UserName, char *Group)
102{
103 int result = FALSE;
104 WCHAR wszUserName[UNLEN+1]; // Unicode user name
105 WCHAR wszGroup[GNLEN+1]; // Unicode Group
106
107 LPLOCALGROUP_USERS_INFO_0 pBuf = nullptr;
108 LPLOCALGROUP_USERS_INFO_0 pTmpBuf;
109 DWORD dwLevel = 0;
110 DWORD dwFlags = LG_INCLUDE_INDIRECT;
111 DWORD dwPrefMaxLen = -1;
112 DWORD dwEntriesRead = 0;
113 DWORD dwTotalEntries = 0;
114 NET_API_STATUS nStatus;
115 DWORD i;
116 DWORD dwTotalCount = 0;
117
118 /* Convert ANSI User Name and Group to Unicode */
119
120 MultiByteToWideChar(CP_ACP, 0, UserName,
121 strlen(UserName) + 1, wszUserName,
122 sizeof(wszUserName) / sizeof(wszUserName[0]));
123 MultiByteToWideChar(CP_ACP, 0, Group,
124 strlen(Group) + 1, wszGroup, sizeof(wszGroup) / sizeof(wszGroup[0]));
125
126 /*
127 * Call the NetUserGetLocalGroups function
128 * specifying information level 0.
129 *
130 * The LG_INCLUDE_INDIRECT flag specifies that the
131 * function should also return the names of the local
132 * groups in which the user is indirectly a member.
133 */
134 nStatus = NetUserGetLocalGroups(nullptr,
135 wszUserName,
136 dwLevel,
137 dwFlags,
138 (LPBYTE *) & pBuf, dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries);
139 /*
140 * If the call succeeds,
141 */
142 if (nStatus == NERR_Success) {
143 if ((pTmpBuf = pBuf) != NULL) {
144 for (i = 0; i < dwEntriesRead; ++i) {
145 if (pTmpBuf == NULL) {
146 result = FALSE;
147 break;
148 }
149 if (wcscmp(pTmpBuf->lgrui0_name, wszGroup) == 0) {
150 result = TRUE;
151 break;
152 }
153 ++pTmpBuf;
154 ++dwTotalCount;
155 }
156 }
157 } else
158 result = FALSE;
159 /*
160 * Free the allocated memory.
161 */
162 if (pBuf != NULL)
163 NetApiBufferFree(pBuf);
164 return result;
165}
166
167char * AllocStrFromLSAStr(LSA_UNICODE_STRING LsaStr)
168{
169 size_t len;
170 static char * target;
171
172 len = LsaStr.Length/sizeof(WCHAR) + 1;
173
174 /* allocate buffer for str + null termination */
175 safe_free(target);
176 target = (char *)xmalloc(len);
177 if (target == NULL)
178 return nullptr;
179
180 /* copy unicode buffer */
181 WideCharToMultiByte(CP_ACP, 0, LsaStr.Buffer, LsaStr.Length, target, len, nullptr, nullptr);
182
183 /* add null termination */
184 target[len-1] = '\0';
185 return target;
186}
187
188char * GetDomainName(void)
189
190{
191 LSA_HANDLE PolicyHandle;
192 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
193 NTSTATUS status;
194 PPOLICY_PRIMARY_DOMAIN_INFO ppdiDomainInfo;
195 PWKSTA_INFO_100 pwkiWorkstationInfo;
196 DWORD netret;
197 char * DomainName = nullptr;
198
199 /*
200 * Always initialize the object attributes to all zeroes.
201 */
202 memset(&ObjectAttributes, '\0', sizeof(ObjectAttributes));
203
204 /*
205 * You need the local workstation name. Use NetWkstaGetInfo at level
206 * 100 to retrieve a WKSTA_INFO_100 structure.
207 *
208 * The wki100_computername field contains a pointer to a UNICODE
209 * string containing the local computer name.
210 */
211 netret = NetWkstaGetInfo(nullptr, 100, (LPBYTE *)&pwkiWorkstationInfo);
212 if (netret == NERR_Success) {
213 /*
214 * We have the workstation name in:
215 * pwkiWorkstationInfo->wki100_computername
216 *
217 * Next, open the policy object for the local system using
218 * the LsaOpenPolicy function.
219 */
220 status = LsaOpenPolicy(
221 nullptr,
222 &ObjectAttributes,
223 GENERIC_READ | POLICY_VIEW_LOCAL_INFORMATION,
224 &PolicyHandle
225 );
226
227 /*
228 * Error checking.
229 */
230 if (status) {
231 debug("OpenPolicy Error: %ld\n", status);
232 } else {
233
234 /*
235 * You have a handle to the policy object. Now, get the
236 * domain information using LsaQueryInformationPolicy.
237 */
238 status = LsaQueryInformationPolicy(PolicyHandle,
239 PolicyPrimaryDomainInformation,
240 (void **)&ppdiDomainInfo);
241 if (status) {
242 debug("LsaQueryInformationPolicy Error: %ld\n", status);
243 } else {
244
245 /* Get name in usable format */
246 DomainName = AllocStrFromLSAStr(ppdiDomainInfo->Name);
247
248 /*
249 * Check the Sid pointer, if it is null, the
250 * workstation is either a stand-alone computer
251 * or a member of a workgroup.
252 */
253 if (ppdiDomainInfo->Sid) {
254
255 /*
256 * Member of a domain. Display it in debug mode.
257 */
258 debug("Member of Domain %s\n",DomainName);
259 } else {
260 DomainName = nullptr;
261 }
262 }
263 }
264
265 /*
266 * Clean up all the memory buffers created by the LSA and
267 * Net* APIs.
268 */
269 NetApiBufferFree(pwkiWorkstationInfo);
270 LsaFreeMemory((LPVOID)ppdiDomainInfo);
271 } else
272 debug("NetWkstaGetInfo Error: %ld\n", netret);
273 return DomainName;
274}
275
276/*
277 * Fills auth with the user's credentials.
278 *
279 * In case of problem returns one of the
280 * codes defined in libntlmauth/ntlmauth.h
281 */
282int
283ntlm_check_auth(ntlm_authenticate * auth, char *user, char *domain, int auth_length)
284{
285 int x;
286 int rv;
287 char credentials[DNLEN+UNLEN+2]; /* we can afford to waste */
288
289 if (!NTLM_LocalCall) {
290
291 user[0] = '\0';
292 domain[0] = '\0';
293 x = ntlm_unpack_auth(auth, user, domain, auth_length);
294
295 if (x != NTLM_ERR_NONE)
296 return x;
297
298 if (domain[0] == '\0') {
299 debug("No domain supplied. Returning no-auth\n");
300 return NTLM_BAD_REQUEST;
301 }
302 if (user[0] == '\0') {
303 debug("No username supplied. Returning no-auth\n");
304 return NTLM_BAD_REQUEST;
305 }
306 debug("checking domain: '%s', user: '%s'\n", domain, user);
307
308 } else
309 debug("checking local user\n");
310
311 snprintf(credentials, DNLEN+UNLEN+2, "%s\\%s", domain, user);
312
313 rv = SSP_ValidateNTLMCredentials(auth, auth_length, credentials);
314
315 debug("Login attempt had result %d\n", rv);
316
317 if (!rv) { /* failed */
318 return NTLM_SSPI_ERROR;
319 }
320
321 if (UseAllowedGroup) {
323 debug("User %s not in allowed Group %s\n", credentials, NTAllowedGroup);
324 return NTLM_BAD_NTGROUP;
325 }
326 }
327 if (UseDisallowedGroup) {
329 debug("User %s is in denied Group %s\n", credentials, NTDisAllowedGroup);
330 return NTLM_BAD_NTGROUP;
331 }
332 }
333
334 debug("credentials: %s\n", credentials);
335 return NTLM_ERR_NONE;
336}
337
338void
339helperfail(const char *reason)
340{
341#if FAIL_DEBUG
342 fail_debug_enabled =1;
343#endif
344 SEND_BH(reason);
345}
346
347/*
348 options:
349 -d enable debugging.
350 -v enable verbose NTLM packet debugging.
351 -A can specify a Windows Local Group name allowed to authenticate.
352 -D can specify a Windows Local Group name not allowed to authenticate.
353 */
354char *my_program_name = nullptr;
355
356void
358{
359 fprintf(stderr,
360 "Usage: %s [-d] [-v] [-A|D LocalUserGroup] [-h]\n"
361 " -d enable debugging.\n"
362 " -v enable verbose NTLM packet debugging.\n"
363 " -A specify a Windows Local Group name allowed to authenticate\n"
364 " -D specify a Windows Local Group name not allowed to authenticate\n"
365 " -h this message\n\n",
367}
368
369void
370process_options(int argc, char *argv[])
371{
372 int opt, had_error = 0;
373
374 opterr =0;
375 while (-1 != (opt = getopt(argc, argv, "hdvA:D:"))) {
376 switch (opt) {
377 case 'A':
380 UseAllowedGroup = 1;
381 break;
382 case 'D':
386 break;
387 case 'd':
388 debug_enabled = 1;
389 break;
390 case 'v':
391 debug_enabled = 1;
393 break;
394 case 'h':
395 usage();
396 exit(EXIT_SUCCESS);
397 case '?':
398 opt = optopt;
399 [[fallthrough]];
400 default:
401 fprintf(stderr, "unknown option: -%c. Exiting\n", opt);
402 usage();
403 had_error = 1;
404 }
405 }
406 if (had_error)
407 exit(EXIT_FAILURE);
408}
409
410static bool
411token_decode(size_t *decodedLen, uint8_t decoded[], const char *buf)
412{
413 struct base64_decode_ctx ctx;
414 base64_decode_init(&ctx);
415 if (!base64_decode_update(&ctx, decodedLen, decoded, strlen(buf), buf) ||
416 !base64_decode_final(&ctx)) {
417 SEND_BH("message=\"base64 decode failed\"");
418 fprintf(stderr, "ERROR: base64 decoding failed for: '%s'\n", buf);
419 return false;
420 }
421 return true;
422}
423
424int
426{
427 ntlmhdr *fast_header;
428 char buf[HELPER_INPUT_BUFFER];
429 uint8_t decoded[HELPER_INPUT_BUFFER];
430 size_t decodedLen = 0;
431 char helper_command[3];
432 int oversized = 0;
433 char * ErrorMessage;
434 static ntlm_negotiate local_nego;
435 char domain[DNLEN+1];
436 char user[UNLEN+1];
437
438 /* NP: for some reason this helper sometimes needs to accept
439 * from clients that send no negotiate packet. */
440 if (memcpy(local_nego.hdr.signature, "NTLMSSP", 8) != 0) {
441 memset(&local_nego, 0, sizeof(ntlm_negotiate)); /* reset */
442 memcpy(local_nego.hdr.signature, "NTLMSSP", 8); /* set the signature */
443 local_nego.hdr.type = le32toh(NTLM_NEGOTIATE); /* this is a challenge */
448 }
449
450 do {
451 if (fgets(buf, sizeof(buf), stdin) == NULL)
452 return 0;
453
454 char *c = static_cast<char*>(memchr(buf, '\n', sizeof(buf)));
455 if (c) {
456 if (oversized) {
457 helperfail("message=\"illegal request received\"");
458 fprintf(stderr, "Illegal request received: '%s'\n", buf);
459 return 1;
460 }
461 *c = '\0';
462 } else {
463 fprintf(stderr, "No newline in '%s'\n", buf);
464 oversized = 1;
465 continue;
466 }
467 } while (false);
468
469 if ((strlen(buf) > 3) && NTLM_packet_debug_enabled) {
470 if (!token_decode(&decodedLen, decoded, buf+3))
471 return 1;
472 strncpy(helper_command, buf, 2);
473 debug("Got '%s' from Squid with data:\n", helper_command);
474 hex_dump(reinterpret_cast<unsigned char*>(decoded), decodedLen);
475 } else
476 debug("Got '%s' from Squid\n", buf);
477 if (memcmp(buf, "YR", 2) == 0) { /* refresh-request */
478 /* figure out what we got */
479 if (strlen(buf) > 3) {
480 if (!decodedLen /* already decoded*/ && !token_decode(&decodedLen, decoded, buf+3))
481 return 1;
482 } else {
483 debug("Negotiate packet not supplied - self generated\n");
484 memcpy(decoded, &local_nego, sizeof(local_nego));
485 decodedLen = sizeof(local_nego);
486 }
487 if ((size_t)decodedLen < sizeof(ntlmhdr)) { /* decoding failure, return error */
488 SEND_ERR("message=\"Packet format error\"");
489 return 1;
490 }
491 /* fast-track-decode request type. */
492 fast_header = (struct _ntlmhdr *) decoded;
493
494 /* sanity-check: it IS a NTLMSSP packet, isn't it? */
495 if (ntlm_validate_packet(fast_header, NTLM_ANY) != NTLM_ERR_NONE) {
496 SEND_ERR("message=\"Broken authentication packet\"");
497 return 1;
498 }
499 switch (fast_header->type) {
500 case NTLM_NEGOTIATE: {
501 /* Obtain challenge against SSPI */
502 debug("attempting SSPI challenge retrieval\n");
503 char *c = (char *) SSP_MakeChallenge((ntlm_negotiate *) decoded, decodedLen);
504 if (c) {
505 SEND_TT(c);
507 if (!token_decode(&decodedLen, decoded, c))
508 return 1;
509 debug("send 'TT' to squid with data:\n");
510 hex_dump(reinterpret_cast<unsigned char*>(decoded), decodedLen);
511 if (NTLM_LocalCall) {
512 debug("NTLM Local Call detected\n");
513 }
514 }
515 have_challenge = 1;
516 } else
517 helperfail("message=\"can't obtain challenge\"");
518
519 return 1;
520 }
521 /* notreached */
522 case NTLM_CHALLENGE:
523 SEND_ERR("message=\"Got a challenge. We refuse to have our authority disputed\"");
524 return 1;
525 /* notreached */
527 SEND_ERR("message=\"Got authentication request instead of negotiate request\"");
528 return 1;
529 /* notreached */
530 default:
531 helperfail("message=\"unknown refresh-request packet type\"");
532 return 1;
533 }
534 return 1;
535 }
536 if (memcmp(buf, "KK ", 3) == 0) { /* authenticate-request */
537 if (!have_challenge) {
538 helperfail("message=\"invalid challenge\"");
539 return 1;
540 }
541 /* figure out what we got */
542 if (!decodedLen /* already decoded*/ && !token_decode(&decodedLen, decoded, buf+3))
543 return 1;
544
545 if ((size_t)decodedLen < sizeof(ntlmhdr)) { /* decoding failure, return error */
546 SEND_ERR("message=\"Packet format error\"");
547 return 1;
548 }
549 /* fast-track-decode request type. */
550 fast_header = (struct _ntlmhdr *) decoded;
551
552 /* sanity-check: it IS a NTLMSSP packet, isn't it? */
553 if (ntlm_validate_packet(fast_header, NTLM_ANY) != NTLM_ERR_NONE) {
554 SEND_ERR("message=\"Broken authentication packet\"");
555 return 1;
556 }
557 switch (fast_header->type) {
558 case NTLM_NEGOTIATE:
559 SEND_ERR("message=\"Invalid negotiation request received\"");
560 return 1;
561 /* notreached */
562 case NTLM_CHALLENGE:
563 SEND_ERR("message=\"Got a challenge. We refuse to have our authority disputed\"");
564 return 1;
565 /* notreached */
566 case NTLM_AUTHENTICATE: {
567 /* check against SSPI */
568 int err = ntlm_check_auth((ntlm_authenticate *) decoded, user, domain, decodedLen);
569 have_challenge = 0;
570 if (err != NTLM_ERR_NONE) {
571#if FAIL_DEBUG
572 fail_debug_enabled =1;
573#endif
574 switch (err) {
575 case NTLM_ERR_NONE:
576 break;
577 case NTLM_BAD_NTGROUP:
578 SEND_ERR("message=\"Incorrect Group Membership\"");
579 return 1;
580 case NTLM_BAD_REQUEST:
581 SEND_ERR("message=\"Incorrect Request Format\"");
582 return 1;
583 case NTLM_SSPI_ERROR:
584 FormatMessage(
585 FORMAT_MESSAGE_ALLOCATE_BUFFER |
586 FORMAT_MESSAGE_FROM_SYSTEM |
587 FORMAT_MESSAGE_IGNORE_INSERTS,
588 nullptr,
589 GetLastError(),
590 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
591 (LPTSTR) &ErrorMessage,
592 0,
593 nullptr);
594 if (ErrorMessage[strlen(ErrorMessage) - 1] == '\n')
595 ErrorMessage[strlen(ErrorMessage) - 1] = '\0';
596 if (ErrorMessage[strlen(ErrorMessage) - 1] == '\r')
597 ErrorMessage[strlen(ErrorMessage) - 1] = '\0';
598 SEND_ERR(ErrorMessage); // TODO update to new syntax
599 LocalFree(ErrorMessage);
600 return 1;
601 default:
602 SEND_ERR("message=\"Unknown Error\"");
603 return 1;
604 }
605 }
606 /* let's lowercase them for our convenience */
607 lc(domain);
608 lc(user);
609 fprintf(stdout, "OK user=\"%s\\%s\"", domain, user);
610 return 1;
611 }
612 default:
613 helperfail("message=\"unknown authentication packet type\"");
614 return 1;
615 }
616 return 1;
617 } else { /* not an auth-request */
618 helperfail("message=\"illegal request received\"");
619 fprintf(stderr, "Illegal request received: '%s'\n", buf);
620 return 1;
621 }
622 helperfail("message=\"detected protocol error\"");
623 return 1;
624 /********* END ********/
625}
626
627int
628main(int argc, char *argv[])
629{
630 my_program_name = argv[0];
631
632 process_options(argc, argv);
633
634 debug("%s " VERSION " " SQUID_BUILD_INFO " starting up...\n", my_program_name);
635
637 fprintf(stderr, "FATAL, can't initialize SSPI, exiting.\n");
638 exit(EXIT_FAILURE);
639 }
640 debug("SSPI initialized OK\n");
641
642 atexit(UnloadSecurityDll);
643
644 /* initialize FDescs */
645 setbuf(stdout, nullptr);
646 setbuf(stderr, nullptr);
647
648 while (manage_request()) {
649 /* everything is done within manage_request */
650 }
651 return EXIT_SUCCESS;
652}
653
void base64_decode_init(struct base64_decode_ctx *ctx)
Definition: base64.c:54
int base64_decode_update(struct base64_decode_ctx *ctx, size_t *dst_length, uint8_t *dst, size_t src_length, const char *src)
Definition: base64.c:129
int base64_decode_final(struct base64_decode_ctx *ctx)
Definition: base64.c:159
#define HELPER_INPUT_BUFFER
Definition: UserRequest.cc:24
int debug_enabled
Definition: debug.cc:13
void debug(const char *format,...)
Definition: debug.cc:19
int optopt
Definition: getopt.c:49
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: getopt.c:62
char * optarg
Definition: getopt.c:51
int opterr
Definition: getopt.c:47
#define VERSION
#define xstrdup
#define xmalloc
static char credentials[MAX_USERNAME_LEN+MAX_DOMAIN_LEN+2]
int NTLM_packet_debug_enabled
static bool token_decode(size_t *decodedLen, uint8_t decoded[], const char *buf)
int main(int argc, char *argv[])
int ntlm_check_auth(ntlm_authenticate *auth, char *user, char *domain, int auth_length)
void usage()
static int have_challenge
char * AllocStrFromLSAStr(LSA_UNICODE_STRING LsaStr)
char * NTAllowedGroup
void helperfail(const char *reason)
char * my_program_name
void process_options(int argc, char *argv[])
int UseAllowedGroup
char * GetDomainName(void)
int Valid_Group(char *UserName, char *Group)
char * NTDisAllowedGroup
int manage_request()
int UseDisallowedGroup
int ntlm_validate_packet(const ntlmhdr *hdr, const int32_t type)
Definition: ntlmauth.cc:67
int ntlm_unpack_auth(const ntlm_authenticate *auth, char *user, char *domain, const int32_t size)
Definition: ntlmauth.cc:246
#define NTLM_AUTHENTICATE
Definition: ntlmauth.h:75
#define NTLM_BAD_NTGROUP
Definition: ntlmauth.h:47
#define NTLM_ERR_NONE
Definition: ntlmauth.h:38
#define NTLM_NEGOTIATE_USE_NTLM
Definition: ntlmauth.h:115
#define NTLM_SSPI_ERROR
Definition: ntlmauth.h:46
#define NTLM_NEGOTIATE_USE_LM
Definition: ntlmauth.h:113
#define NTLM_NEGOTIATE
Definition: ntlmauth.h:73
#define NTLM_CHALLENGE
Definition: ntlmauth.h:74
#define NTLM_BAD_REQUEST
Definition: ntlmauth.h:48
#define NTLM_ANY
Definition: ntlmauth.h:72
#define NTLM_NEGOTIATE_ASCII
Definition: ntlmauth.h:108
struct _ntlmhdr ntlmhdr
#define NTLM_NEGOTIATE_ALWAYS_SIGN
Definition: ntlmauth.h:119
#define SEND_TT(x)
#define SEND_ERR(x)
#define SEND_BH(x)
void UnloadSecurityDll(void)
Definition: sspwin32.cc:77
HMODULE LoadSecurityDll(int mode, const char *SSP_Package)
Definition: sspwin32.cc:104
#define NTLM_PACKAGE_NAME
Definition: sspwin32.h:18
#define SSP_NTLM
Definition: sspwin32.h:43
#define TRUE
Definition: std-includes.h:55
#define FALSE
Definition: std-includes.h:56
ntlmhdr hdr
Definition: ntlmauth.h:123
uint32_t flags
Definition: ntlmauth.h:124
int32_t type
Definition: ntlmauth.h:82
char signature[8]
Definition: ntlmauth.h:81
void lc(char *string)
void hex_dump(unsigned char *data, int size)
#define le32toh(x)
#define NULL
Definition: types.h:145
#define safe_free(x)
Definition: xalloc.h:73

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors