ntlmauth.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 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  * Inspired by previous work by Andrew Doran <ad@interlude.eu.org>.
11  */
12 #include "squid.h"
13 
14 #include <cstring>
15 #include <random>
16 #if HAVE_STRINGS_H
17 #include <strings.h>
18 #endif
19 
20 #include "ntlmauth/ntlmauth.h"
21 #include "util.h" /* for base64-related stuff */
22 
23 /* ************************************************************************* */
24 /* DEBUG functions */
25 /* ************************************************************************* */
26 
28 void
29 ntlm_dump_ntlmssp_flags(uint32_t flags)
30 {
31  fprintf(stderr, "flags: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
32  (flags & NTLM_NEGOTIATE_UNICODE ? "Unicode " : ""),
33  (flags & NTLM_NEGOTIATE_ASCII ? "ASCII " : ""),
34  (flags & NTLM_NEGOTIATE_REQUEST_TARGET ? "ReqTgt " : ""),
35  (flags & NTLM_NEGOTIATE_REQUEST_SIGN ? "ReqSign " : ""),
36  (flags & NTLM_NEGOTIATE_REQUEST_SEAL ? "ReqSeal " : ""),
37  (flags & NTLM_NEGOTIATE_DATAGRAM_STYLE ? "Dgram " : ""),
38  (flags & NTLM_NEGOTIATE_USE_LM ? "UseLM " : ""),
39  (flags & NTLM_NEGOTIATE_USE_NETWARE ? "UseNW " : ""),
40  (flags & NTLM_NEGOTIATE_USE_NTLM ? "UseNTLM " : ""),
41  (flags & NTLM_NEGOTIATE_DOMAIN_SUPPLIED ? "HaveDomain " : ""),
42  (flags & NTLM_NEGOTIATE_WORKSTATION_SUPPLIED ? "HaveWKS " : ""),
43  (flags & NTLM_NEGOTIATE_THIS_IS_LOCAL_CALL ? "LocalCall " : ""),
44  (flags & NTLM_NEGOTIATE_ALWAYS_SIGN ? "AlwaysSign " : ""),
45  (flags & NTLM_CHALLENGE_TARGET_IS_DOMAIN ? "Tgt_is_domain" : ""),
46  (flags & NTLM_CHALLENGE_TARGET_IS_SERVER ? "Tgt_is_server " : ""),
47  (flags & NTLM_CHALLENGE_TARGET_IS_SHARE ? "Tgt_is_share " : ""),
48  (flags & NTLM_REQUEST_INIT_RESPONSE ? "Req_init_response " : ""),
49  (flags & NTLM_REQUEST_ACCEPT_RESPONSE ? "Req_accept_response " : ""),
50  (flags & NTLM_REQUEST_NON_NT_SESSION_KEY ? "Req_nonnt_sesskey " : "")
51  );
52 }
53 
54 /* ************************************************************************* */
55 /* Packet and Payload handling functions */
56 /* ************************************************************************* */
57 
65 int
66 ntlm_validate_packet(const ntlmhdr * hdr, const int32_t type)
67 {
68  /*
69  * Must be the correct security package and request type.
70  * The 8 bytes compared includes the ASCII 'NUL'.
71  */
72  if (memcmp(hdr->signature, "NTLMSSP", 8) != 0) {
73  fprintf(stderr, "ntlmCheckHeader: bad header signature\n");
74  return NTLM_ERR_BLOB;
75  }
76  if (type == NTLM_ANY)
77  return NTLM_ERR_NONE;
78 
79  if ((int32_t)le32toh(hdr->type) != type) {
80  /* don't report this error - it's ok as we do a if() around this function */
81  debug("ntlm_validate_packet: type is %d, wanted %d\n", le32toh(hdr->type), type);
82  return NTLM_ERR_PROTOCOL;
83  }
84  return NTLM_ERR_NONE;
85 }
86 
96 lstring
97 ntlm_fetch_string(const ntlmhdr *packet, const int32_t packet_size, const strhdr * str, const uint32_t flags)
98 {
99  static char buf[NTLM_MAX_FIELD_LENGTH];
100  lstring rv;
101  char *d;
102 
103  rv.str = NULL;
104  rv.l = -1;
105 
106  int16_t l = le16toh(str->len);
107  int32_t o = le32toh(str->offset);
108  // debug("ntlm_fetch_string(plength=%d,l=%d,o=%d)\n",packet_size,l,o);
109 
110  if (l < 0 || l > NTLM_MAX_FIELD_LENGTH || o + l > packet_size || o == 0) {
111  debug("ntlm_fetch_string: insane data (pkt-sz: %d, fetch len: %d, offset: %d)\n", packet_size,l,o);
112  return rv;
113  }
114  rv.str = (char *)packet + o;
115  rv.l = 0;
116  if ((flags & NTLM_NEGOTIATE_ASCII) == 0) {
117  /* UNICODE string */
118  unsigned short *s = (unsigned short *)rv.str;
119  rv.str = d = buf;
120 
121  for (uint32_t len = (l>>1); len; ++s, --len) {
122  uint16_t c = le16toh(*s);
123  if (c > 254 || c == '\0') {
124  fprintf(stderr, "ntlmssp: bad unicode: %04x\n", c);
125  return rv;
126  }
127  *d = static_cast<char>(c&0xFF);
128  ++d;
129  ++rv.l;
130  }
131  } else {
132  /* ASCII/OEM string */
133  char *sc = rv.str;
134 
135  for (; l>=0; ++sc, --l) {
136  if (*sc == '\0' || !xisprint(*sc)) {
137  fprintf(stderr, "ntlmssp: bad ascii: %04x\n", *sc);
138  return rv;
139  }
140  ++rv.l;
141  }
142  }
143 
144  return rv;
145 }
146 
153 void
154 ntlm_add_to_payload(const ntlmhdr *packet_hdr,
155  char *payload,
156  int *payload_length,
157  strhdr * hdr,
158  const char *toadd,
159  const uint16_t toadd_length)
160 {
161  int l = (*payload_length);
162  memcpy(payload + l, toadd, toadd_length);
163 
164  hdr->len = htole16(toadd_length);
165  hdr->maxlen = htole16(toadd_length);
166  const off_t o = l + reinterpret_cast<const ntlmhdr *>(payload) - packet_hdr;
167  hdr->offset = htole32(o & 0xFFFFFFFF);
168  (*payload_length) += toadd_length;
169 }
170 
171 /* ************************************************************************* */
172 /* Negotiate Packet functions */
173 /* ************************************************************************* */
174 
175 // ?
176 
177 /* ************************************************************************* */
178 /* Challenge Packet functions */
179 /* ************************************************************************* */
180 
181 /*
182  * Generates a challenge request nonce.
183  */
184 void
185 ntlm_make_nonce(char *nonce)
186 {
187  static std::mt19937 mt(time(0));
188  static xuniform_int_distribution<uint8_t> dist;
189 
190  for (int i = 0; i < NTLM_NONCE_LEN; ++i)
191  nonce[i] = static_cast<char>(dist(mt) & 0xFF);
192 }
193 
198 void
200  const char *domain, const char *,
201  const char *challenge_nonce, const int challenge_nonce_len,
202  const uint32_t flags)
203 {
204  int pl = 0;
205  memset(ch, 0, sizeof(ntlm_challenge)); /* reset */
206  memcpy(ch->hdr.signature, "NTLMSSP", 8); /* set the signature */
207  ch->hdr.type = htole32(NTLM_CHALLENGE); /* this is a challenge */
208  if (domain != NULL) {
209  // silently truncate the domain if it exceeds 2^16-1 bytes.
210  // NTLM packets normally expect 2^8 bytes of domain.
211  const uint16_t dlen = strlen(domain) & 0xFFFF;
212  ntlm_add_to_payload(&ch->hdr, ch->payload, &pl, &ch->target, domain, dlen);
213  }
214  ch->flags = htole32(flags);
215  ch->context_low = 0; /* check this out */
216  ch->context_high = 0;
217  memcpy(ch->challenge, challenge_nonce, challenge_nonce_len);
218 }
219 
220 /* ************************************************************************* */
221 /* Authenticate Packet functions */
222 /* ************************************************************************* */
223 
235 int
236 ntlm_unpack_auth(const ntlm_authenticate *auth, char *user, char *domain, const int32_t size)
237 {
238  lstring rv;
239 
241  fprintf(stderr, "ntlm_unpack_auth: header check fails\n");
242  return NTLM_ERR_PROTOCOL;
243  }
244  debug("ntlm_unpack_auth: size of %d\n", size);
245  debug("ntlm_unpack_auth: flg %08x\n", auth->flags);
246  debug("ntlm_unpack_auth: lmr o(%d) l(%d)\n", le32toh(auth->lmresponse.offset), auth->lmresponse.len);
247  debug("ntlm_unpack_auth: ntr o(%d) l(%d)\n", le32toh(auth->ntresponse.offset), auth->ntresponse.len);
248  debug("ntlm_unpack_auth: dom o(%d) l(%d)\n", le32toh(auth->domain.offset), auth->domain.len);
249  debug("ntlm_unpack_auth: usr o(%d) l(%d)\n", le32toh(auth->user.offset), auth->user.len);
250  debug("ntlm_unpack_auth: wst o(%d) l(%d)\n", le32toh(auth->workstation.offset), auth->workstation.len);
251  debug("ntlm_unpack_auth: key o(%d) l(%d)\n", le32toh(auth->sessionkey.offset), auth->sessionkey.len);
252 
253  rv = ntlm_fetch_string(&auth->hdr, size, &auth->domain, auth->flags);
254  if (rv.l > 0) {
255  memcpy(domain, rv.str, rv.l);
256  domain[rv.l] = '\0';
257  debug("ntlm_unpack_auth: Domain '%s' (len=%d).\n", domain, rv.l);
258  }
259  if (rv.l >= size) {
260  debug("ntlm_unpack_auth: Domain length %d too big for %d byte packet.\n", rv.l, size);
261  return NTLM_ERR_BLOB;
262  }
263 
264  rv = ntlm_fetch_string(&auth->hdr, size, &auth->user, auth->flags);
265  if (rv.l > 0) {
266  memcpy(user, rv.str, rv.l);
267  user[rv.l] = '\0';
268  debug("ntlm_unpack_auth: Username '%s' (len=%d).\n", user, rv.l);
269  } else
270  return NTLM_ERR_LOGON;
271 
272  return NTLM_ERR_NONE;
273 }
274 
#define NTLM_CHALLENGE_TARGET_IS_DOMAIN
Definition: ntlmauth.h:137
void ntlm_add_to_payload(const ntlmhdr *packet_hdr, char *payload, int *payload_length, strhdr *hdr, const char *toadd, const uint16_t toadd_length)
Definition: ntlmauth.cc:154
#define NTLM_NEGOTIATE_USE_NETWARE
Definition: ntlmauth.h:114
static int sc[16]
Definition: smbdes.c:121
int ntlm_validate_packet(const ntlmhdr *hdr, const int32_t type)
Definition: ntlmauth.cc:66
#define NTLM_NEGOTIATE_ALWAYS_SIGN
Definition: ntlmauth.h:119
char payload[256]
Definition: ntlmauth.h:149
int type
Definition: errorpage.cc:79
strhdr workstation
Definition: ntlmauth.h:179
void ntlm_make_nonce(char *nonce)
Definition: ntlmauth.cc:185
#define NTLM_REQUEST_INIT_RESPONSE
Definition: ntlmauth.h:30
int i
Definition: membanger.c:49
#define le16toh(x)
#define NTLM_ERR_LOGON
Definition: ntlmauth.h:42
int32_t offset
Definition: ntlmauth.h:55
void ntlm_dump_ntlmssp_flags(uint32_t flags)
Definition: ntlmauth.cc:29
int16_t len
Definition: ntlmauth.h:53
#define NTLM_NEGOTIATE_DOMAIN_SUPPLIED
Definition: ntlmauth.h:116
char signature[8]
Definition: ntlmauth.h:81
#define le32toh(x)
#define NTLM_NEGOTIATE_ASCII
Definition: ntlmauth.h:108
#define NTLM_NEGOTIATE_WORKSTATION_SUPPLIED
Definition: ntlmauth.h:117
uint32_t flags
Definition: ntlmauth.h:145
uint32_t context_high
Definition: ntlmauth.h:148
void ntlm_make_challenge(ntlm_challenge *ch, const char *domain, const char *, const char *challenge_nonce, const int challenge_nonce_len, const uint32_t flags)
Definition: ntlmauth.cc:199
uint32_t context_low
Definition: ntlmauth.h:147
#define NTLM_CHALLENGE_TARGET_IS_SHARE
Definition: ntlmauth.h:139
#define NTLM_ERR_BLOB
Definition: ntlmauth.h:36
#define NTLM_AUTHENTICATE
Definition: ntlmauth.h:75
#define NTLM_NEGOTIATE_THIS_IS_LOCAL_CALL
Definition: ntlmauth.h:118
int32_t type
Definition: ntlmauth.h:82
#define NTLM_NEGOTIATE_UNICODE
Definition: ntlmauth.h:107
#define NTLM_NEGOTIATE_REQUEST_TARGET
Definition: ntlmauth.h:109
#define NTLM_NEGOTIATE_USE_NTLM
Definition: ntlmauth.h:115
#define NTLM_ERR_NONE
Definition: ntlmauth.h:38
#define htole32(x)
#define NTLM_CHALLENGE
Definition: ntlmauth.h:74
u_char challenge[NTLM_NONCE_LEN]
Definition: ntlmauth.h:146
#define NTLM_NEGOTIATE_USE_LM
Definition: ntlmauth.h:113
static int debug
Definition: tcp-banger3.c:105
#define NTLM_ERR_PROTOCOL
Definition: ntlmauth.h:41
lstring ntlm_fetch_string(const ntlmhdr *packet, const int32_t packet_size, const strhdr *str, const uint32_t flags)
Definition: ntlmauth.cc:97
#define NTLM_NEGOTIATE_DATAGRAM_STYLE
Definition: ntlmauth.h:112
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
void const char * buf
Definition: stub_helper.cc:16
int ntlm_unpack_auth(const ntlm_authenticate *auth, char *user, char *domain, const int32_t size)
Definition: ntlmauth.cc:236
#define NTLM_REQUEST_ACCEPT_RESPONSE
Definition: ntlmauth.h:31
int32_t l
Definition: ntlmauth.h:60
ntlmhdr hdr
Definition: ntlmauth.h:143
#define NTLM_CHALLENGE_TARGET_IS_SERVER
Definition: ntlmauth.h:138
strhdr target
Definition: ntlmauth.h:144
#define NTLM_MAX_FIELD_LENGTH
Definition: ntlmauth.h:22
int16_t maxlen
Definition: ntlmauth.h:54
#define NTLM_NEGOTIATE_REQUEST_SEAL
Definition: ntlmauth.h:111
#define htole16(x)
#define NTLM_ANY
Definition: ntlmauth.h:72
char * str
Definition: ntlmauth.h:61
#define NTLM_NONCE_LEN
Definition: ntlmauth.h:134
#define NTLM_REQUEST_NON_NT_SESSION_KEY
Definition: ntlmauth.h:32
#define xisprint(x)
Definition: xis.h:24
#define NULL
Definition: types.h:166
uint32_t flags
Definition: ntlmauth.h:181
#define NTLM_NEGOTIATE_REQUEST_SIGN
Definition: ntlmauth.h:110
int size
Definition: ModDevPoll.cc:77

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors