3
* AUTHOR: Robert Collins <rbtcollins@hotmail.com>
5
* Example ntlm authentication program for Squid, based on the
6
* original proxy_auth code from client_side.c, written by
7
* Jon Thackray <jrmt@uk.gdscorp.com>. and the inital ntlm code
10
* This code gets the username and returns it. No validation is done.
11
* and by the way: it is a complete patch-up. Use the "real thing" NTLMSSP
45
#define NTLM_STATIC_CHALLENGE "deadbeef"
47
static char *authenticate_ntlm_domain = "LIFELESSWKS";
49
/* NTLM authentication by ad@netbsd.org - 07/1999 */
50
/* XXX this is not done cleanly... */
52
/* makes a null-terminated string lower-case. Changes CONTENTS! */
65
* Generates a challenge request. The randomness of the 8 byte
66
* challenge strings can be guarenteed to be poor at best.
69
ntlmMakeChallenge(struct ntlm_challenge *chal)
71
#ifndef NTLM_STATIC_CHALLENGE
78
memset(chal, 0, sizeof(*chal));
79
memcpy(chal->hdr.signature, "NTLMSSP", 8);
80
chal->flags = WSWAP(0x00018206);
81
chal->hdr.type = WSWAP(NTLM_CHALLENGE);
82
chal->unknown[6] = SSWAP(0x003a);
84
d = (char *) chal + 48;
87
if (authenticate_ntlm_domain != NULL)
88
while (authenticate_ntlm_domain[i++]);
91
chal->target.offset = WSWAP(48);
92
chal->target.maxlen = SSWAP(i);
93
chal->target.len = chal->target.maxlen;
95
#ifdef NTLM_STATIC_CHALLENGE
96
memcpy(chal->challenge, NTLM_STATIC_CHALLENGE, 8);
101
for (i = 0; i < 8; i++) {
102
chal->challenge[i] = r;
111
* Check the vailidity of a request header. Return -1 on error.
114
ntlmCheckHeader(struct ntlmhdr *hdr, int type)
117
* Must be the correct security package and request type. The
118
* 8 bytes compared includes the ASCII 'NUL'.
120
if (memcmp(hdr->signature, "NTLMSSP", 8) != 0) {
121
fprintf(stderr, "ntlmCheckHeader: bad header signature\n");
124
if (type == NTLM_ANY)
127
if (WSWAP(hdr->type) != type) {
128
/* don't report this error - it's ok as we do a if() around this function */
129
// fprintf(stderr, "ntlmCheckHeader: type is %d, wanted %d\n",
130
// WSWAP(hdr->type), type);
137
* Extract a string from an NTLM request and return as ASCII.
140
ntlmGetString(ntlmhdr * hdr, strhdr * str, int flags)
142
static char buf[512];
148
o = WSWAP(str->offset);
150
/* Sanity checks. XXX values arbitrarialy chosen */
151
if (l <= 0 || l >= 32 || o >= 256) {
152
fprintf(stderr, "ntlmGetString: insane: l:%d o:%d\n", l, o);
155
if ((flags & 2) == 0) {
157
s = (u_short *) ((char *) hdr + o);
160
for (l >>= 1; l; s++, l--) {
162
if (c > 254 || c == '\0' || !isprint(c)) {
163
fprintf(stderr, "ntlmGetString: bad uni: %04x\n", c);
167
fprintf(stderr, "ntlmGetString: conv: '%c'\n", c);
173
sc = (char *) hdr + o;
177
if (*sc == '\0' || !isprint(*sc)) {
178
fprintf(stderr, "ntlmGetString: bad ascii: %04x\n", *sc);
191
* Decode the strings in an NTLM authentication request
194
ntlmDecodeAuth(struct ntlm_authenticate *auth, char *buf, size_t size)
203
if (ntlmCheckHeader(&auth->hdr, NTLM_AUTHENTICATE)) {
205
fprintf(stderr, "ntlmDecodeAuth: header check fails\n");
208
/* only on when you need to debug
209
* fprintf(stderr,"ntlmDecodeAuth: size of %d\n", size);
210
* fprintf(stderr,"ntlmDecodeAuth: flg %08x\n", auth->flags);
211
* fprintf(stderr,"ntlmDecodeAuth: usr o(%d) l(%d)\n", auth->user.offset, auth->user.len);
213
if ((p = ntlmGetString(&auth->hdr, &auth->domain, 2)) == NULL)
214
p = authenticate_ntlm_domain;
215
// fprintf(stderr,"ntlmDecodeAuth: Domain '%s'.\n",p);
216
if ((s = strlen(p) + 1) >= size)
219
// fprintf(stdout,"ntlmDecodeAuth: Domain '%s'.\n",buf);
223
*buf++ = '\\'; /* Using \ is more consistent with MS-proxy */
225
p = ntlmGetString(&auth->hdr, &auth->user, 2);
226
if ((s = strlen(p) + 1) >= size)
229
*buf++ = (*p++); //tolower
233
// fprintf(stderr, "ntlmDecodeAuth: user: %s%s\n",origbuf, p);
244
char user[256], *p, *cleartext;
245
struct ntlm_challenge chal;
249
setbuf(stdout, NULL);
250
while (fgets(buf, 256, stdin) != NULL) {
251
user[0] = '\0'; /*no usercode */
253
if ((p = strchr(buf, '\n')) != NULL)
254
*p = '\0'; /* strip \n */
255
#if defined(NTLMHELPPROTOCOLV3) || !defined(NTLMHELPPROTOCOLV2)
256
if (strncasecmp(buf, "YR", 2) == 0) {
257
ntlmMakeChallenge(&chal);
259
sizeof(chal) - sizeof(chal.pad) +
260
SSWAP(chal.target.maxlen);
261
data = (char *) base64_encode_bin((char *) &chal, len);
262
printf("TT %s\n", data);
263
} else if (strncasecmp(buf, "KK ", 3) == 0) {
264
cleartext = (char *) uudecode(buf + 3);
265
if (!ntlmCheckHeader((struct ntlmhdr *) cleartext, NTLM_AUTHENTICATE)) {
266
if (!ntlmDecodeAuth((struct ntlm_authenticate *) cleartext, user, 256)) {
268
printf("AF %s\n", user);
271
printf("NA invalid credentials%s\n", user);
275
printf("BH wrong packet type!%s\n", user);
279
#ifdef NTLMHELPPROTOCOLV2
280
/* V2 of the protocol */
281
if (strncasecmp(buf, "RESET", 5) == 0) {
282
printf("RESET OK\n");
284
cleartext = (char *) uudecode(buf);
285
if (!ntlmCheckHeader((struct ntlmhdr *) cleartext, NTLM_NEGOTIATE)) {
286
ntlmMakeChallenge(&chal);
288
sizeof(chal) - sizeof(chal.pad) +
289
SSWAP(chal.target.maxlen);
290
data = (char *) base64_encode_bin((char *) &chal, len);
291
printf("CH %s\n", data);
292
} else if (!ntlmCheckHeader
293
((struct ntlmhdr *) cleartext, NTLM_AUTHENTICATE)) {
295
((struct ntlm_authenticate *) cleartext, user, 256)) {
297
printf("OK %s\n", user);
300
printf("ERR %s\n", user);
304
printf("ERR %s\n", user);