sync'ing up for 3.0alpha20 release
[Samba.git] / source / smbd / negprot.c
blob16427b00d705ee101a89babde07090764c2df415
1 /*
2 Unix SMB/CIFS implementation.
3 negprot reply code
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "includes.h"
23 extern int Protocol;
24 extern int max_recv;
25 extern fstring global_myworkgroup;
26 BOOL global_encrypted_passwords_negotiated = False;
27 BOOL global_spnego_negotiated = False;
28 struct auth_context *negprot_global_auth_context = NULL;
30 static void get_challenge(char buff[8])
32 NTSTATUS nt_status;
33 const uint8 *cryptkey;
35 /* We might be called more than once, muliple negprots are premitted */
36 if (negprot_global_auth_context) {
37 DEBUG(3, ("get challenge: is this a secondary negprot? negprot_global_auth_context is non-NULL!\n"));
38 (negprot_global_auth_context->free)(&negprot_global_auth_context);
41 DEBUG(10, ("get challenge: creating negprot_global_auth_context\n"));
42 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&negprot_global_auth_context))) {
43 DEBUG(0, ("make_auth_context_subsystem returned %s", nt_errstr(nt_status)));
44 smb_panic("cannot make_negprot_global_auth_context!\n");
46 DEBUG(10, ("get challenge: getting challenge\n"));
47 cryptkey = negprot_global_auth_context->get_ntlm_challenge(negprot_global_auth_context);
48 memcpy(buff, cryptkey, 8);
51 /****************************************************************************
52 Reply for the core protocol.
53 ****************************************************************************/
55 static int reply_corep(char *inbuf, char *outbuf)
57 int outsize = set_message(outbuf,1,0,True);
59 Protocol = PROTOCOL_CORE;
61 return outsize;
64 /****************************************************************************
65 Reply for the coreplus protocol.
66 ****************************************************************************/
68 static int reply_coreplus(char *inbuf, char *outbuf)
70 int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
71 int outsize = set_message(outbuf,13,0,True);
72 SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
73 readbraw and writebraw (possibly) */
74 /* Reply, SMBlockread, SMBwritelock supported. */
75 SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
76 SSVAL(outbuf,smb_vwv1,0x1); /* user level security, don't encrypt */
78 Protocol = PROTOCOL_COREPLUS;
80 return outsize;
83 /****************************************************************************
84 Reply for the lanman 1.0 protocol.
85 ****************************************************************************/
87 static int reply_lanman1(char *inbuf, char *outbuf)
89 int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
90 int secword=0;
91 time_t t = time(NULL);
93 global_encrypted_passwords_negotiated = lp_encrypted_passwords();
95 if (lp_security()>=SEC_USER)
96 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
97 if (global_encrypted_passwords_negotiated)
98 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
100 set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
101 SSVAL(outbuf,smb_vwv1,secword);
102 /* Create a token value and add it to the outgoing packet. */
103 if (global_encrypted_passwords_negotiated) {
104 get_challenge(smb_buf(outbuf));
107 Protocol = PROTOCOL_LANMAN1;
109 /* Reply, SMBlockread, SMBwritelock supported. */
110 SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
111 SSVAL(outbuf,smb_vwv2,max_recv);
112 SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
113 SSVAL(outbuf,smb_vwv4,1);
114 SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
115 readbraw writebraw (possibly) */
116 SIVAL(outbuf,smb_vwv6,sys_getpid());
117 SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
119 put_dos_date(outbuf,smb_vwv8,t);
121 return (smb_len(outbuf)+4);
124 /****************************************************************************
125 Reply for the lanman 2.0 protocol.
126 ****************************************************************************/
128 static int reply_lanman2(char *inbuf, char *outbuf)
130 int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
131 int secword=0;
132 time_t t = time(NULL);
134 global_encrypted_passwords_negotiated = lp_encrypted_passwords();
136 if (lp_security()>=SEC_USER)
137 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
138 if (global_encrypted_passwords_negotiated)
139 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
141 set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
142 SSVAL(outbuf,smb_vwv1,secword);
143 SIVAL(outbuf,smb_vwv6,sys_getpid());
145 /* Create a token value and add it to the outgoing packet. */
146 if (global_encrypted_passwords_negotiated) {
147 get_challenge(smb_buf(outbuf));
150 Protocol = PROTOCOL_LANMAN2;
152 /* Reply, SMBlockread, SMBwritelock supported. */
153 SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
154 SSVAL(outbuf,smb_vwv2,max_recv);
155 SSVAL(outbuf,smb_vwv3,lp_maxmux());
156 SSVAL(outbuf,smb_vwv4,1);
157 SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
158 SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
159 put_dos_date(outbuf,smb_vwv8,t);
161 return (smb_len(outbuf)+4);
164 /****************************************************************************
165 Generate the spnego negprot reply blob. Return the number of bytes used.
166 ****************************************************************************/
168 static int negprot_spnego(char *p)
170 DATA_BLOB blob;
171 extern pstring global_myname;
172 uint8 guid[16];
173 const char *OIDs_krb5[] = {OID_KERBEROS5,
174 OID_KERBEROS5_OLD,
175 OID_NTLMSSP,
176 NULL};
177 const char *OIDs_plain[] = {OID_NTLMSSP, NULL};
178 char *principal;
179 int len;
181 global_spnego_negotiated = True;
183 memset(guid, 0, 16);
184 safe_strcpy((char *)guid, global_myname, 16);
185 strlower((char *)guid);
187 #if 0
188 /* strangely enough, NT does not sent the single OID NTLMSSP when
189 not a ADS member, it sends no OIDs at all
191 we can't do this until we teach our sesssion setup parser to know
192 about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)
194 if (lp_security() != SEC_ADS) {
195 memcpy(p, guid, 16);
196 return 16;
198 #endif
199 if (lp_security() != SEC_ADS) {
200 blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE");
201 } else {
202 asprintf(&principal, "%s$@%s", guid, lp_realm());
203 blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal);
204 free(principal);
206 memcpy(p, blob.data, blob.length);
207 len = blob.length;
208 data_blob_free(&blob);
209 return len;
212 /****************************************************************************
213 Reply for the nt protocol.
214 ****************************************************************************/
216 static int reply_nt1(char *inbuf, char *outbuf)
218 /* dual names + lock_and_read + nt SMBs + remote API calls */
219 int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
220 CAP_LEVEL_II_OPLOCKS;
222 int secword=0;
223 time_t t = time(NULL);
224 char *p, *q;
225 BOOL negotiate_spnego = False;
227 global_encrypted_passwords_negotiated = lp_encrypted_passwords();
229 /* do spnego in user level security if the client
230 supports it and we can do encrypted passwords */
232 if (global_encrypted_passwords_negotiated &&
233 (lp_security() != SEC_SHARE) &&
234 lp_use_spnego() &&
235 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
236 negotiate_spnego = True;
237 capabilities |= CAP_EXTENDED_SECURITY;
240 capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
242 if (lp_unix_extensions()) {
243 capabilities |= CAP_UNIX;
246 if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64))
247 capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
249 if (SMB_OFF_T_BITS == 64)
250 capabilities |= CAP_LARGE_FILES;
252 if (lp_readraw() && lp_writeraw())
253 capabilities |= CAP_RAW_MODE;
255 /* allow for disabling unicode */
256 if (lp_unicode())
257 capabilities |= CAP_UNICODE;
259 if (lp_nt_status_support())
260 capabilities |= CAP_STATUS32;
262 if (lp_host_msdfs())
263 capabilities |= CAP_DFS;
265 if (lp_security() >= SEC_USER)
266 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
267 if (global_encrypted_passwords_negotiated)
268 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
270 set_message(outbuf,17,0,True);
272 SCVAL(outbuf,smb_vwv1,secword);
274 Protocol = PROTOCOL_NT1;
276 SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
277 SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
278 SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
279 SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
280 SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
281 SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
282 put_long_date(outbuf+smb_vwv11+1,t);
283 SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
285 p = q = smb_buf(outbuf);
286 if (!negotiate_spnego) {
287 /* Create a token value and add it to the outgoing packet. */
288 if (global_encrypted_passwords_negotiated) {
289 /* note that we do not send a challenge at all if
290 we are using plaintext */
291 get_challenge(p);
292 SSVALS(outbuf,smb_vwv16+1,8);
293 p += 8;
295 p += srvstr_push(outbuf, p, global_myworkgroup, -1,
296 STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
297 DEBUG(3,("not using SPNEGO\n"));
298 } else {
299 int len = negprot_spnego(p);
301 SSVALS(outbuf,smb_vwv16+1,len);
302 p += len;
303 DEBUG(3,("using SPNEGO\n"));
306 SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
307 set_message_end(outbuf, p);
309 return (smb_len(outbuf)+4);
312 /* these are the protocol lists used for auto architecture detection:
314 WinNT 3.51:
315 protocol [PC NETWORK PROGRAM 1.0]
316 protocol [XENIX CORE]
317 protocol [MICROSOFT NETWORKS 1.03]
318 protocol [LANMAN1.0]
319 protocol [Windows for Workgroups 3.1a]
320 protocol [LM1.2X002]
321 protocol [LANMAN2.1]
322 protocol [NT LM 0.12]
324 Win95:
325 protocol [PC NETWORK PROGRAM 1.0]
326 protocol [XENIX CORE]
327 protocol [MICROSOFT NETWORKS 1.03]
328 protocol [LANMAN1.0]
329 protocol [Windows for Workgroups 3.1a]
330 protocol [LM1.2X002]
331 protocol [LANMAN2.1]
332 protocol [NT LM 0.12]
334 Win2K:
335 protocol [PC NETWORK PROGRAM 1.0]
336 protocol [LANMAN1.0]
337 protocol [Windows for Workgroups 3.1a]
338 protocol [LM1.2X002]
339 protocol [LANMAN2.1]
340 protocol [NT LM 0.12]
342 OS/2:
343 protocol [PC NETWORK PROGRAM 1.0]
344 protocol [XENIX CORE]
345 protocol [LANMAN1.0]
346 protocol [LM1.2X002]
347 protocol [LANMAN2.1]
351 * Modified to recognize the architecture of the remote machine better.
353 * This appears to be the matrix of which protocol is used by which
354 * MS product.
355 Protocol WfWg Win95 WinNT Win2K OS/2
356 PC NETWORK PROGRAM 1.0 1 1 1 1 1
357 XENIX CORE 2 2
358 MICROSOFT NETWORKS 3.0 2 2
359 DOS LM1.2X002 3 3
360 MICROSOFT NETWORKS 1.03 3
361 DOS LANMAN2.1 4 4
362 LANMAN1.0 4 2 3
363 Windows for Workgroups 3.1a 5 5 5 3
364 LM1.2X002 6 4 4
365 LANMAN2.1 7 5 5
366 NT LM 0.12 6 8 6
368 * tim@fsg.com 09/29/95
369 * Win2K added by matty 17/7/99
372 #define ARCH_WFWG 0x3 /* This is a fudge because WfWg is like Win95 */
373 #define ARCH_WIN95 0x2
374 #define ARCH_WINNT 0x4
375 #define ARCH_WIN2K 0xC /* Win2K is like NT */
376 #define ARCH_OS2 0x14 /* Again OS/2 is like NT */
377 #define ARCH_SAMBA 0x20
379 #define ARCH_ALL 0x3F
381 /* List of supported protocols, most desired first */
382 static struct {
383 char *proto_name;
384 char *short_name;
385 int (*proto_reply_fn)(char *, char *);
386 int protocol_level;
387 } supported_protocols[] = {
388 {"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1},
389 {"NT LM 0.12", "NT1", reply_nt1, PROTOCOL_NT1},
390 {"LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
391 {"Samba", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
392 {"DOS LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
393 {"LANMAN1.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
394 {"MICROSOFT NETWORKS 3.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
395 {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
396 {"PC NETWORK PROGRAM 1.0", "CORE", reply_corep, PROTOCOL_CORE},
397 {NULL,NULL,NULL,0},
400 /****************************************************************************
401 Reply to a negprot.
402 ****************************************************************************/
404 int reply_negprot(connection_struct *conn,
405 char *inbuf,char *outbuf, int dum_size,
406 int dum_buffsize)
408 int outsize = set_message(outbuf,1,0,True);
409 int Index=0;
410 int choice= -1;
411 int protocol;
412 char *p;
413 int bcc = SVAL(smb_buf(inbuf),-2);
414 int arch = ARCH_ALL;
416 static BOOL done_negprot = False;
418 START_PROFILE(SMBnegprot);
420 if (done_negprot) {
421 END_PROFILE(SMBnegprot);
422 exit_server("multiple negprot's are not permitted");
424 done_negprot = True;
426 p = smb_buf(inbuf)+1;
427 while (p < (smb_buf(inbuf) + bcc)) {
428 Index++;
429 DEBUG(3,("Requested protocol [%s]\n",p));
430 if (strcsequal(p,"Windows for Workgroups 3.1a"))
431 arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
432 else if (strcsequal(p,"DOS LM1.2X002"))
433 arch &= ( ARCH_WFWG | ARCH_WIN95 );
434 else if (strcsequal(p,"DOS LANMAN2.1"))
435 arch &= ( ARCH_WFWG | ARCH_WIN95 );
436 else if (strcsequal(p,"NT LM 0.12"))
437 arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
438 else if (strcsequal(p,"LANMAN2.1"))
439 arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
440 else if (strcsequal(p,"LM1.2X002"))
441 arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
442 else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
443 arch &= ARCH_WINNT;
444 else if (strcsequal(p,"XENIX CORE"))
445 arch &= ( ARCH_WINNT | ARCH_OS2 );
446 else if (strcsequal(p,"Samba")) {
447 arch = ARCH_SAMBA;
448 break;
451 p += strlen(p) + 2;
454 switch ( arch ) {
455 case ARCH_SAMBA:
456 set_remote_arch(RA_SAMBA);
457 break;
458 case ARCH_WFWG:
459 set_remote_arch(RA_WFWG);
460 break;
461 case ARCH_WIN95:
462 set_remote_arch(RA_WIN95);
463 break;
464 case ARCH_WINNT:
465 if(SVAL(inbuf,smb_flg2)==FLAGS2_WIN2K_SIGNATURE)
466 set_remote_arch(RA_WIN2K);
467 else
468 set_remote_arch(RA_WINNT);
469 break;
470 case ARCH_WIN2K:
471 set_remote_arch(RA_WIN2K);
472 break;
473 case ARCH_OS2:
474 set_remote_arch(RA_OS2);
475 break;
476 default:
477 set_remote_arch(RA_UNKNOWN);
478 break;
481 /* possibly reload - change of architecture */
482 reload_services(True);
484 /* Check for protocols, most desirable first */
485 for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) {
486 p = smb_buf(inbuf)+1;
487 Index = 0;
488 if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) &&
489 (supported_protocols[protocol].protocol_level >= lp_minprotocol()))
490 while (p < (smb_buf(inbuf) + bcc)) {
491 if (strequal(p,supported_protocols[protocol].proto_name))
492 choice = Index;
493 Index++;
494 p += strlen(p) + 2;
496 if(choice != -1)
497 break;
500 SSVAL(outbuf,smb_vwv0,choice);
501 if(choice != -1) {
502 extern fstring remote_proto;
503 fstrcpy(remote_proto,supported_protocols[protocol].short_name);
504 reload_services(True);
505 outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf);
506 DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
507 } else {
508 DEBUG(0,("No protocol supported !\n"));
510 SSVAL(outbuf,smb_vwv0,choice);
512 DEBUG( 5, ( "negprot index=%d\n", choice ) );
514 END_PROFILE(SMBnegprot);
515 return(outsize);