2
* (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>
3
* Distributed freely under the terms of the GNU General Public License,
4
* version 2. See the file COPYING for licensing details
6
* This program is distributed in the hope that it will be useful,
7
* but WITHOUT ANY WARRANTY; without even the implied warranty of
8
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9
* GNU General Public License for more details.
11
* You should have received a copy of the GNU General Public License
12
* along with this program; if not, write to the Free Software
13
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
16
typedef unsigned char uchar;
19
#include "util.h" /* from Squid */
21
#include "smbencrypt.h"
25
#endif /* HAVE_STRING_H */
28
#endif /* HAVE_STDLIB_H */
33
/* these are part of rfcnb-priv.h and smblib-priv.h */
34
extern int SMB_Get_Error_Msg(int msg, char *msgbuf, int len);
35
extern int SMB_Get_Last_Error();
36
extern int RFCNB_Get_Last_Errno();
38
#include "smblib-priv.h" /* for SMB_Handle_Type */
40
/* a few forward-declarations. Hackish, but I don't care right now */
41
SMB_Handle_Type SMB_Connect_Server(SMB_Handle_Type Con_Handle, char *server, char *NTdomain);
43
/* this one is reallllly haackiish. We really should be using anything from smblib-priv.h
45
static char *SMB_Prots[] =
46
{"PC NETWORK PROGRAM 1.0",
47
"MICROSOFT NETWORKS 1.03",
48
"MICROSOFT NETWORKS 3.0",
62
int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle);
63
int SMB_Negotiate(void *Con_Handle, char *Prots[]);
64
int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName, char *PassWord, char *Domain, int precrypted);
68
#define debug_dump_ntlmssp_flags dump_ntlmssp_flags
70
#define debug_dump_ntlmssp_flags(X) /* empty */
74
#define ENCODED_PASS_LEN 24
75
static unsigned char challenge[NONCE_LEN];
76
static unsigned char lmencoded_empty_pass[ENCODED_PASS_LEN],
77
ntencoded_empty_pass[ENCODED_PASS_LEN];
78
SMB_Handle_Type handle = NULL;
80
/* Disconnects from the DC. A reconnection will be done upon the next request
86
SMB_Discon(handle, 0);
93
return (handle != NULL);
97
/* Tries to connect to a DC. Returns 0 on failure, 1 on OK */
99
is_dc_ok(char *domain, char *domain_controller)
101
SMB_Handle_Type h = SMB_Connect_Server(NULL, domain_controller, domain);
109
static char errstr[1001];
110
/* returns 0 on success, > 0 on failure */
112
init_challenge(char *domain, char *domain_controller)
116
if (handle != NULL) {
119
debug("Connecting to server %s domain %s\n", domain_controller, domain);
120
handle = SMB_Connect_Server(NULL, domain_controller, domain);
121
smberr = SMB_Get_Last_Error();
122
SMB_Get_Error_Msg(smberr, errstr, 1000);
125
if (handle == NULL) { /* couldn't connect */
126
debug("Couldn't connect to SMB Server. Error:%s\n", errstr);
129
if (SMB_Negotiate(handle, SMB_Prots) < 0) { /* An error */
130
debug("Error negotiating protocol with SMB Server\n");
131
SMB_Discon(handle, 0);
135
if (handle->Security == 0) { /* share-level security, unuseable */
136
debug("SMB Server uses share-level security .. we need user security.\n");
137
SMB_Discon(handle, 0);
141
memcpy(challenge, handle->Encrypt_Key, NONCE_LEN);
142
SMBencrypt((unsigned char *)"",challenge,lmencoded_empty_pass);
143
SMBNTencrypt((unsigned char *)"",challenge,ntencoded_empty_pass);
147
static char my_domain[100], my_domain_controller[100];
149
make_challenge(char *domain, char *domain_controller)
151
/* trying to circumvent some strange problem wih pointers in SMBLib */
152
/* Ugly as hell, but the lib is going to be dropped... */
153
strcpy(my_domain,domain);
154
strcpy(my_domain_controller,domain_controller);
155
if (init_challenge(my_domain, my_domain_controller) > 0) {
158
return ntlm_make_challenge(my_domain, my_domain_controller, (char *)challenge, NONCE_LEN);
161
#define min(A,B) (A<B?A:B)
164
#define MAX_USERNAME_LEN 255
165
#define MAX_DOMAIN_LEN 255
166
#define MAX_PASSWD_LEN 31
167
static char credentials[MAX_USERNAME_LEN+MAX_DOMAIN_LEN+2]; /* we can afford to waste */
170
/* Fetches the user's credentials from the challenge.
171
* Returns NULL if domain or user is not defined
172
* No identity control is performed.
173
* WARNING! The result is static storage, shared with ntlm_check_auth
176
fetch_credentials(ntlm_authenticate * auth, int auth_length)
178
char *p = credentials;
180
tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain);
184
memcpy(p, tmp.str, tmp.l);
188
tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user);
191
memcpy(p, tmp.str, tmp.l);
196
/* returns NULL on failure, or a pointer to
197
* the user's credentials (domain\\username)
198
* upon success. WARNING. It's pointing to static storage.
199
* In case of problem sets as side-effect ntlm_errno to one of the
200
* codes defined in ntlm.h
203
ntlm_check_auth(ntlm_authenticate * auth, int auth_length)
206
char pass[MAX_PASSWD_LEN+1];
207
char *domain = credentials;
211
if (handle == NULL) { /*if null we aren't connected, but it shouldn't happen */
212
debug("Weird, we've been disconnected\n");
213
ntlm_errno = NTLM_NOT_CONNECTED;
217
/* debug("fetching domain\n"); */
218
tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain);
219
if (tmp.str == NULL || tmp.l == 0) {
220
debug("No domain supplied. Returning no-auth\n");
221
ntlm_errno = NTLM_LOGON_ERROR;
224
if (tmp.l > MAX_DOMAIN_LEN) {
225
debug("Domain string exceeds %d bytes, rejecting\n", MAX_DOMAIN_LEN);
226
ntlm_errno = NTLM_LOGON_ERROR;
229
memcpy(domain, tmp.str, tmp.l);
230
user = domain + tmp.l;
233
/* debug("fetching user name\n"); */
234
tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user);
235
if (tmp.str == NULL || tmp.l == 0) {
236
debug("No username supplied. Returning no-auth\n");
237
ntlm_errno = NTLM_LOGON_ERROR;
240
if (tmp.l > MAX_USERNAME_LEN) {
241
debug("Username string exceeds %d bytes, rejecting\n", MAX_USERNAME_LEN);
242
ntlm_errno = NTLM_LOGON_ERROR;
245
memcpy(user, tmp.str, tmp.l);
246
*(user + tmp.l) = '\0';
249
/* Authenticating against the NT response doesn't seem to work... */
250
tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->lmresponse);
251
if (tmp.str == NULL || tmp.l == 0) {
252
fprintf(stderr, "No auth at all. Returning no-auth\n");
253
ntlm_errno = NTLM_LOGON_ERROR;
256
if (tmp.l > MAX_PASSWD_LEN) {
257
debug("Password string exceeds %d bytes, rejecting\n", MAX_PASSWD_LEN);
258
ntlm_errno = NTLM_LOGON_ERROR;
262
memcpy(pass, tmp.str, tmp.l);
263
pass[min(MAX_PASSWD_LEN,tmp.l)] = '\0';
266
debug ("Empty LM pass detection: user: '%s', ours:'%s', his: '%s'"
268
user,lmencoded_empty_pass,tmp.str,tmp.l);
269
if (memcmp(tmp.str,lmencoded_empty_pass,ENCODED_PASS_LEN)==0) {
270
fprintf(stderr,"Empty LM password supplied for user %s\\%s. "
271
"No-auth\n",domain,user);
272
ntlm_errno=NTLM_LOGON_ERROR;
276
tmp = ntlm_fetch_string ((char *) auth, auth_length, &auth->ntresponse);
277
if (tmp.str != NULL && tmp.l != 0) {
278
debug ("Empty NT pass detection: user: '%s', ours:'%s', his: '%s'"
280
user,ntencoded_empty_pass,tmp.str,tmp.l);
281
if (memcmp(tmp.str,lmencoded_empty_pass,ENCODED_PASS_LEN)==0) {
282
fprintf(stderr,"Empty NT password supplied for user %s\\%s. "
283
"No-auth\n",domain,user);
284
ntlm_errno=NTLM_LOGON_ERROR;
290
/* TODO: check against empty password!!!!! */
294
debug("checking domain: '%s', user: '%s', pass='%s'\n", domain, user, pass);
296
rv = SMB_Logon_Server(handle, user, pass, domain, 1);
297
debug("Login attempt had result %d\n", rv);
299
if (rv != NTV_NO_ERROR) { /* failed */
303
*(user - 1) = '\\'; /* hack. Performing, but ugly. */
305
debug("credentials: %s\n", credentials);