]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/ntlm_auth/smb_lm/libntlmssp.c
Merge from trunk
[thirdparty/squid.git] / helpers / ntlm_auth / smb_lm / libntlmssp.c
1 /*
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
5 *
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.
10
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.
14 */
15
16 typedef unsigned char uchar;
17
18 #include "ntlm_smb_lm_auth.h"
19 #include "util.h" /* from Squid */
20 #include "valid.h"
21 #include "smbencrypt.h"
22
23 #if HAVE_STRING_H
24 #include <string.h>
25 #endif /* HAVE_STRING_H */
26 #if HAVE_STDLIB_H
27 #include <stdlib.h>
28 #endif /* HAVE_STDLIB_H */
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32
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();
37
38 #include "smblib-priv.h" /* for SMB_Handle_Type */
39
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);
42
43 /* this one is reallllly haackiish. We really should be using anything from smblib-priv.h
44 */
45 static char const *SMB_Prots[] = {"PC NETWORK PROGRAM 1.0",
46 "MICROSOFT NETWORKS 1.03",
47 "MICROSOFT NETWORKS 3.0",
48 "DOS LANMAN1.0",
49 "LANMAN1.0",
50 "DOS LM1.2X002",
51 "LM1.2X002",
52 "DOS LANMAN2.1",
53 "LANMAN2.1",
54 "Samba",
55 "NT LM 0.12",
56 "NT LANMAN 1.0",
57 NULL
58 };
59
60 #if 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);
64 #endif
65
66 #ifdef DEBUG
67 #define debug_dump_ntlmssp_flags dump_ntlmssp_flags
68 #else /* DEBUG */
69 #define debug_dump_ntlmssp_flags(X) /* empty */
70 #endif /* DEBUG */
71
72
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;
78
79 /* Disconnects from the DC. A reconnection will be done upon the next request
80 */
81 void
82 dc_disconnect()
83 {
84 if (handle != NULL)
85 SMB_Discon(handle, 0);
86 handle = NULL;
87 }
88
89 int
90 connectedp()
91 {
92 return (handle != NULL);
93 }
94
95
96 /* Tries to connect to a DC. Returns 0 on failure, 1 on OK */
97 int
98 is_dc_ok(char *domain, char *domain_controller)
99 {
100 SMB_Handle_Type h = SMB_Connect_Server(NULL, domain_controller, domain);
101 if (h == NULL)
102 return 0;
103 SMB_Discon(h, 0);
104 return 1;
105 }
106
107
108 static char errstr[1001];
109 /* returns 0 on success, > 0 on failure */
110 static int
111 init_challenge(char *domain, char *domain_controller)
112 {
113 int smberr;
114
115 if (handle != NULL) {
116 return 0;
117 }
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);
122
123
124 if (handle == NULL) { /* couldn't connect */
125 debug("Couldn't connect to SMB Server. Error:%s\n", errstr);
126 return 1;
127 }
128 if (SMB_Negotiate(handle, SMB_Prots) < 0) { /* An error */
129 debug("Error negotiating protocol with SMB Server\n");
130 SMB_Discon(handle, 0);
131 handle = NULL;
132 return 2;
133 }
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);
137 handle = NULL;
138 return 3;
139 }
140 memcpy(challenge, handle->Encrypt_Key, NONCE_LEN);
141 SMBencrypt((unsigned char *)"",challenge,lmencoded_empty_pass);
142 SMBNTencrypt((unsigned char *)"",challenge,ntencoded_empty_pass);
143 return 0;
144 }
145
146 static char my_domain[100], my_domain_controller[100];
147 const char *
148 make_challenge(char *domain, char *domain_controller)
149 {
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) {
155 return NULL;
156 }
157 return ntlm_make_challenge(my_domain, my_domain_controller, (char *)challenge, NONCE_LEN);
158 }
159
160 int ntlm_errno;
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 */
165
166
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
171 */
172 char *
173 fetch_credentials(ntlm_authenticate * auth, int auth_length)
174 {
175 char *p = credentials;
176 lstring tmp;
177 tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain);
178 *p = '\0';
179 if (tmp.str == NULL)
180 return NULL;
181 memcpy(p, tmp.str, tmp.l);
182 p += tmp.l;
183 *p++ = '\\';
184 *p = '\0';
185 tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user);
186 if (tmp.str == NULL)
187 return NULL;
188 memcpy(p, tmp.str, tmp.l);
189 *(p + tmp.l) = '\0';
190 return credentials;
191 }
192
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
198 */
199 char *
200 ntlm_check_auth(ntlm_authenticate * auth, int auth_length)
201 {
202 int rv;
203 char pass[MAX_PASSWD_LEN+1];
204 char *domain = credentials;
205 char *user;
206 lstring tmp;
207
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;
211 return NULL;
212 }
213
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;
219 return NULL;
220 }
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;
224 return NULL;
225 }
226 memcpy(domain, tmp.str, tmp.l);
227 user = domain + tmp.l;
228 *user++ = '\0';
229
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;
235 return NULL;
236 }
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;
240 return NULL;
241 }
242 memcpy(user, tmp.str, tmp.l);
243 *(user + tmp.l) = '\0';
244
245
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;
251 return NULL;
252 }
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;
256 return NULL;
257 }
258
259 memcpy(pass, tmp.str, tmp.l);
260 pass[min(MAX_PASSWD_LEN,tmp.l)] = '\0';
261
262 #if 1
263 debug ("Empty LM pass detection: user: '%s', ours:'%s', his: '%s'"
264 "(length: %d)\n",
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;
270 return NULL;
271 }
272
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'"
276 "(length: %d)\n",
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;
282 return NULL;
283 }
284 }
285 #endif
286
287 /* TODO: check against empty password!!!!! */
288
289
290
291 debug("checking domain: '%s', user: '%s', pass='%s'\n", domain, user, pass);
292
293 rv = SMB_Logon_Server(handle, user, pass, domain, 1);
294 debug("Login attempt had result %d\n", rv);
295
296 if (rv != NTV_NO_ERROR) { /* failed */
297 ntlm_errno = rv;
298 return NULL;
299 }
300 *(user - 1) = '\\'; /* hack. Performing, but ugly. */
301
302 debug("credentials: %s\n", credentials);
303 return credentials;
304 }