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
;
18 #include "ntlm_smb_lm_auth.h"
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 const *SMB_Prots
[] = {"PC NETWORK PROGRAM 1.0",
46 "MICROSOFT NETWORKS 1.03",
47 "MICROSOFT NETWORKS 3.0",
61 int SMB_Discon(SMB_Handle_Type Con_Handle
, BOOL KeepHandle
);
62 int SMB_Negotiate(void *Con_Handle
, char *Prots
[]);
63 int SMB_Logon_Server(SMB_Handle_Type Con_Handle
, char *UserName
, char *PassWord
, char *Domain
, int precrypted
);
67 #define debug_dump_ntlmssp_flags dump_ntlmssp_flags
69 #define debug_dump_ntlmssp_flags(X) /* empty */
73 #define ENCODED_PASS_LEN 24
74 static unsigned char challenge
[NONCE_LEN
];
75 static unsigned char lmencoded_empty_pass
[ENCODED_PASS_LEN
],
76 ntencoded_empty_pass
[ENCODED_PASS_LEN
];
77 SMB_Handle_Type handle
= NULL
;
79 /* Disconnects from the DC. A reconnection will be done upon the next request
85 SMB_Discon(handle
, 0);
92 return (handle
!= NULL
);
96 /* Tries to connect to a DC. Returns 0 on failure, 1 on OK */
98 is_dc_ok(char *domain
, char *domain_controller
)
100 SMB_Handle_Type h
= SMB_Connect_Server(NULL
, domain_controller
, domain
);
108 static char errstr
[1001];
109 /* returns 0 on success, > 0 on failure */
111 init_challenge(char *domain
, char *domain_controller
)
115 if (handle
!= NULL
) {
118 debug("Connecting to server %s domain %s\n", domain_controller
, domain
);
119 handle
= SMB_Connect_Server(NULL
, domain_controller
, domain
);
120 smberr
= SMB_Get_Last_Error();
121 SMB_Get_Error_Msg(smberr
, errstr
, 1000);
124 if (handle
== NULL
) { /* couldn't connect */
125 debug("Couldn't connect to SMB Server. Error:%s\n", errstr
);
128 if (SMB_Negotiate(handle
, SMB_Prots
) < 0) { /* An error */
129 debug("Error negotiating protocol with SMB Server\n");
130 SMB_Discon(handle
, 0);
134 if (handle
->Security
== 0) { /* share-level security, unuseable */
135 debug("SMB Server uses share-level security .. we need user security.\n");
136 SMB_Discon(handle
, 0);
140 memcpy(challenge
, handle
->Encrypt_Key
, NONCE_LEN
);
141 SMBencrypt((unsigned char *)"",challenge
,lmencoded_empty_pass
);
142 SMBNTencrypt((unsigned char *)"",challenge
,ntencoded_empty_pass
);
146 static char my_domain
[100], my_domain_controller
[100];
148 make_challenge(char *domain
, char *domain_controller
)
150 /* trying to circumvent some strange problem wih pointers in SMBLib */
151 /* Ugly as hell, but the lib is going to be dropped... */
152 strcpy(my_domain
,domain
);
153 strcpy(my_domain_controller
,domain_controller
);
154 if (init_challenge(my_domain
, my_domain_controller
) > 0) {
157 return ntlm_make_challenge(my_domain
, my_domain_controller
, (char *)challenge
, NONCE_LEN
);
161 #define MAX_USERNAME_LEN 255
162 #define MAX_DOMAIN_LEN 255
163 #define MAX_PASSWD_LEN 31
164 static char credentials
[MAX_USERNAME_LEN
+MAX_DOMAIN_LEN
+2]; /* we can afford to waste */
167 /* Fetches the user's credentials from the challenge.
168 * Returns NULL if domain or user is not defined
169 * No identity control is performed.
170 * WARNING! The result is static storage, shared with ntlm_check_auth
173 fetch_credentials(ntlm_authenticate
* auth
, int auth_length
)
175 char *p
= credentials
;
177 tmp
= ntlm_fetch_string((char *) auth
, auth_length
, &auth
->domain
);
181 memcpy(p
, tmp
.str
, tmp
.l
);
185 tmp
= ntlm_fetch_string((char *) auth
, auth_length
, &auth
->user
);
188 memcpy(p
, tmp
.str
, tmp
.l
);
193 /* returns NULL on failure, or a pointer to
194 * the user's credentials (domain\\username)
195 * upon success. WARNING. It's pointing to static storage.
196 * In case of problem sets as side-effect ntlm_errno to one of the
197 * codes defined in ntlm.h
200 ntlm_check_auth(ntlm_authenticate
* auth
, int auth_length
)
203 char pass
[MAX_PASSWD_LEN
+1];
204 char *domain
= credentials
;
208 if (handle
== NULL
) { /*if null we aren't connected, but it shouldn't happen */
209 debug("Weird, we've been disconnected\n");
210 ntlm_errno
= NTLM_NOT_CONNECTED
;
214 /* debug("fetching domain\n"); */
215 tmp
= ntlm_fetch_string((char *) auth
, auth_length
, &auth
->domain
);
216 if (tmp
.str
== NULL
|| tmp
.l
== 0) {
217 debug("No domain supplied. Returning no-auth\n");
218 ntlm_errno
= NTLM_LOGON_ERROR
;
221 if (tmp
.l
> MAX_DOMAIN_LEN
) {
222 debug("Domain string exceeds %d bytes, rejecting\n", MAX_DOMAIN_LEN
);
223 ntlm_errno
= NTLM_LOGON_ERROR
;
226 memcpy(domain
, tmp
.str
, tmp
.l
);
227 user
= domain
+ tmp
.l
;
230 /* debug("fetching user name\n"); */
231 tmp
= ntlm_fetch_string((char *) auth
, auth_length
, &auth
->user
);
232 if (tmp
.str
== NULL
|| tmp
.l
== 0) {
233 debug("No username supplied. Returning no-auth\n");
234 ntlm_errno
= NTLM_LOGON_ERROR
;
237 if (tmp
.l
> MAX_USERNAME_LEN
) {
238 debug("Username string exceeds %d bytes, rejecting\n", MAX_USERNAME_LEN
);
239 ntlm_errno
= NTLM_LOGON_ERROR
;
242 memcpy(user
, tmp
.str
, tmp
.l
);
243 *(user
+ tmp
.l
) = '\0';
246 /* Authenticating against the NT response doesn't seem to work... */
247 tmp
= ntlm_fetch_string((char *) auth
, auth_length
, &auth
->lmresponse
);
248 if (tmp
.str
== NULL
|| tmp
.l
== 0) {
249 fprintf(stderr
, "No auth at all. Returning no-auth\n");
250 ntlm_errno
= NTLM_LOGON_ERROR
;
253 if (tmp
.l
> MAX_PASSWD_LEN
) {
254 debug("Password string exceeds %d bytes, rejecting\n", MAX_PASSWD_LEN
);
255 ntlm_errno
= NTLM_LOGON_ERROR
;
259 memcpy(pass
, tmp
.str
, tmp
.l
);
260 pass
[min(MAX_PASSWD_LEN
,tmp
.l
)] = '\0';
263 debug ("Empty LM pass detection: user: '%s', ours:'%s', his: '%s'"
265 user
,lmencoded_empty_pass
,tmp
.str
,tmp
.l
);
266 if (memcmp(tmp
.str
,lmencoded_empty_pass
,ENCODED_PASS_LEN
)==0) {
267 fprintf(stderr
,"Empty LM password supplied for user %s\\%s. "
268 "No-auth\n",domain
,user
);
269 ntlm_errno
=NTLM_LOGON_ERROR
;
273 tmp
= ntlm_fetch_string ((char *) auth
, auth_length
, &auth
->ntresponse
);
274 if (tmp
.str
!= NULL
&& tmp
.l
!= 0) {
275 debug ("Empty NT pass detection: user: '%s', ours:'%s', his: '%s'"
277 user
,ntencoded_empty_pass
,tmp
.str
,tmp
.l
);
278 if (memcmp(tmp
.str
,lmencoded_empty_pass
,ENCODED_PASS_LEN
)==0) {
279 fprintf(stderr
,"Empty NT password supplied for user %s\\%s. "
280 "No-auth\n",domain
,user
);
281 ntlm_errno
=NTLM_LOGON_ERROR
;
287 /* TODO: check against empty password!!!!! */
291 debug("checking domain: '%s', user: '%s', pass='%s'\n", domain
, user
, pass
);
293 rv
= SMB_Logon_Server(handle
, user
, pass
, domain
, 1);
294 debug("Login attempt had result %d\n", rv
);
296 if (rv
!= NTV_NO_ERROR
) { /* failed */
300 *(user
- 1) = '\\'; /* hack. Performing, but ugly. */
302 debug("credentials: %s\n", credentials
);