r1936: Fix bug noticed by Steve - ensure extended security bit is on only
[Samba/bb.git] / source / smbd / negprot.c
blob5ee8abbe6baaa31867d70f00190547e7fa5ced56
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 BOOL global_encrypted_passwords_negotiated = False;
26 BOOL global_spnego_negotiated = False;
27 struct auth_context *negprot_global_auth_context = NULL;
29 static void get_challenge(char buff[8])
31 NTSTATUS nt_status;
32 const uint8 *cryptkey;
34 /* We might be called more than once, muliple negprots are premitted */
35 if (negprot_global_auth_context) {
36 DEBUG(3, ("get challenge: is this a secondary negprot? negprot_global_auth_context is non-NULL!\n"));
37 (negprot_global_auth_context->free)(&negprot_global_auth_context);
40 DEBUG(10, ("get challenge: creating negprot_global_auth_context\n"));
41 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&negprot_global_auth_context))) {
42 DEBUG(0, ("make_auth_context_subsystem returned %s", nt_errstr(nt_status)));
43 smb_panic("cannot make_negprot_global_auth_context!\n");
45 DEBUG(10, ("get challenge: getting challenge\n"));
46 cryptkey = negprot_global_auth_context->get_ntlm_challenge(negprot_global_auth_context);
47 memcpy(buff, cryptkey, 8);
50 /****************************************************************************
51 Reply for the core protocol.
52 ****************************************************************************/
54 static int reply_corep(char *inbuf, char *outbuf)
56 int outsize = set_message(outbuf,1,0,True);
58 Protocol = PROTOCOL_CORE;
60 return outsize;
63 /****************************************************************************
64 Reply for the coreplus protocol.
65 ****************************************************************************/
67 static int reply_coreplus(char *inbuf, char *outbuf)
69 int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
70 int outsize = set_message(outbuf,13,0,True);
71 SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
72 readbraw and writebraw (possibly) */
73 /* Reply, SMBlockread, SMBwritelock supported. */
74 SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
75 SSVAL(outbuf,smb_vwv1,0x1); /* user level security, don't encrypt */
77 Protocol = PROTOCOL_COREPLUS;
79 return outsize;
82 /****************************************************************************
83 Reply for the lanman 1.0 protocol.
84 ****************************************************************************/
86 static int reply_lanman1(char *inbuf, char *outbuf)
88 int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
89 int secword=0;
90 time_t t = time(NULL);
92 global_encrypted_passwords_negotiated = lp_encrypted_passwords();
94 if (lp_security()>=SEC_USER)
95 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
96 if (global_encrypted_passwords_negotiated)
97 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
99 set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
100 SSVAL(outbuf,smb_vwv1,secword);
101 /* Create a token value and add it to the outgoing packet. */
102 if (global_encrypted_passwords_negotiated) {
103 get_challenge(smb_buf(outbuf));
104 SSVAL(outbuf,smb_vwv11, 8);
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));
148 SSVAL(outbuf,smb_vwv11, 8);
151 Protocol = PROTOCOL_LANMAN2;
153 /* Reply, SMBlockread, SMBwritelock supported. */
154 SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
155 SSVAL(outbuf,smb_vwv2,max_recv);
156 SSVAL(outbuf,smb_vwv3,lp_maxmux());
157 SSVAL(outbuf,smb_vwv4,1);
158 SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
159 SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
160 put_dos_date(outbuf,smb_vwv8,t);
162 return (smb_len(outbuf)+4);
165 /****************************************************************************
166 Generate the spnego negprot reply blob. Return the number of bytes used.
167 ****************************************************************************/
169 static int negprot_spnego(char *p)
171 DATA_BLOB blob;
172 nstring dos_name;
173 fstring unix_name;
174 uint8 guid[17];
175 const char *OIDs_krb5[] = {OID_KERBEROS5,
176 OID_KERBEROS5_OLD,
177 OID_NTLMSSP,
178 NULL};
179 const char *OIDs_plain[] = {OID_NTLMSSP, NULL};
180 char *principal;
181 int len;
183 global_spnego_negotiated = True;
185 ZERO_STRUCT(guid);
187 safe_strcpy(unix_name, global_myname(), sizeof(unix_name)-1);
188 strlower_m(unix_name);
189 push_ascii_nstring(dos_name, unix_name);
190 safe_strcpy((char *)guid, dos_name, sizeof(guid)-1);
192 #ifdef DEVELOPER
193 /* valgrind fixer... */
195 size_t sl = strlen(guid);
196 if (sizeof(guid)-sl)
197 memset(&guid[sl], '\0', sizeof(guid)-sl);
199 #endif
201 #if 0
202 /* strangely enough, NT does not sent the single OID NTLMSSP when
203 not a ADS member, it sends no OIDs at all
205 we can't do this until we teach our sesssion setup parser to know
206 about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)
208 if (lp_security() != SEC_ADS) {
209 memcpy(p, guid, 16);
210 return 16;
212 #endif
213 if (lp_security() != SEC_ADS) {
214 blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE");
215 } else {
216 asprintf(&principal, "%s$@%s", guid, lp_realm());
217 blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal);
218 free(principal);
220 memcpy(p, blob.data, blob.length);
221 len = blob.length;
222 data_blob_free(&blob);
223 return len;
226 /****************************************************************************
227 Reply for the nt protocol.
228 ****************************************************************************/
230 static int reply_nt1(char *inbuf, char *outbuf)
232 /* dual names + lock_and_read + nt SMBs + remote API calls */
233 int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
234 CAP_LEVEL_II_OPLOCKS;
236 int secword=0;
237 time_t t = time(NULL);
238 char *p, *q;
239 BOOL negotiate_spnego = False;
241 global_encrypted_passwords_negotiated = lp_encrypted_passwords();
243 /* do spnego in user level security if the client
244 supports it and we can do encrypted passwords */
246 if (global_encrypted_passwords_negotiated &&
247 (lp_security() != SEC_SHARE) &&
248 lp_use_spnego() &&
249 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
250 negotiate_spnego = True;
251 capabilities |= CAP_EXTENDED_SECURITY;
252 add_to_common_flags2(FLAGS2_EXTENDED_SECURITY);
255 capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS|CAP_UNICODE;
257 if (lp_unix_extensions()) {
258 capabilities |= CAP_UNIX;
261 if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64))
262 capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
264 if (SMB_OFF_T_BITS == 64)
265 capabilities |= CAP_LARGE_FILES;
267 if (lp_readraw() && lp_writeraw())
268 capabilities |= CAP_RAW_MODE;
270 if (lp_nt_status_support())
271 capabilities |= CAP_STATUS32;
273 if (lp_host_msdfs())
274 capabilities |= CAP_DFS;
276 if (lp_security() >= SEC_USER)
277 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
278 if (global_encrypted_passwords_negotiated)
279 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
281 if (lp_server_signing()) {
282 if (lp_security() >= SEC_USER) {
283 secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
284 /* No raw mode with smb signing. */
285 capabilities &= ~CAP_RAW_MODE;
286 if (lp_server_signing() == Required)
287 secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
288 srv_set_signing_negotiated();
289 } else {
290 DEBUG(0,("reply_nt1: smb signing is incompatible with share level security !\n"));
291 if (lp_server_signing() == Required) {
292 exit_server("reply_nt1: smb signing required and share level security selected.");
297 set_message(outbuf,17,0,True);
299 SCVAL(outbuf,smb_vwv1,secword);
301 Protocol = PROTOCOL_NT1;
303 SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
304 SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
305 SIVAL(outbuf,smb_vwv3+1,max_recv); /* max buffer. LOTS! */
306 SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
307 SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
308 SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
309 put_long_date(outbuf+smb_vwv11+1,t);
310 SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
312 p = q = smb_buf(outbuf);
313 if (!negotiate_spnego) {
314 /* Create a token value and add it to the outgoing packet. */
315 if (global_encrypted_passwords_negotiated) {
316 /* note that we do not send a challenge at all if
317 we are using plaintext */
318 get_challenge(p);
319 SSVALS(outbuf,smb_vwv16+1,8);
320 p += 8;
322 p += srvstr_push(outbuf, p, lp_workgroup(), -1,
323 STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
324 DEBUG(3,("not using SPNEGO\n"));
325 } else {
326 int len = negprot_spnego(p);
328 SSVALS(outbuf,smb_vwv16+1,len);
329 p += len;
330 DEBUG(3,("using SPNEGO\n"));
333 SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
334 set_message_end(outbuf, p);
336 return (smb_len(outbuf)+4);
339 /* these are the protocol lists used for auto architecture detection:
341 WinNT 3.51:
342 protocol [PC NETWORK PROGRAM 1.0]
343 protocol [XENIX CORE]
344 protocol [MICROSOFT NETWORKS 1.03]
345 protocol [LANMAN1.0]
346 protocol [Windows for Workgroups 3.1a]
347 protocol [LM1.2X002]
348 protocol [LANMAN2.1]
349 protocol [NT LM 0.12]
351 Win95:
352 protocol [PC NETWORK PROGRAM 1.0]
353 protocol [XENIX CORE]
354 protocol [MICROSOFT NETWORKS 1.03]
355 protocol [LANMAN1.0]
356 protocol [Windows for Workgroups 3.1a]
357 protocol [LM1.2X002]
358 protocol [LANMAN2.1]
359 protocol [NT LM 0.12]
361 Win2K:
362 protocol [PC NETWORK PROGRAM 1.0]
363 protocol [LANMAN1.0]
364 protocol [Windows for Workgroups 3.1a]
365 protocol [LM1.2X002]
366 protocol [LANMAN2.1]
367 protocol [NT LM 0.12]
369 OS/2:
370 protocol [PC NETWORK PROGRAM 1.0]
371 protocol [XENIX CORE]
372 protocol [LANMAN1.0]
373 protocol [LM1.2X002]
374 protocol [LANMAN2.1]
378 * Modified to recognize the architecture of the remote machine better.
380 * This appears to be the matrix of which protocol is used by which
381 * MS product.
382 Protocol WfWg Win95 WinNT Win2K OS/2
383 PC NETWORK PROGRAM 1.0 1 1 1 1 1
384 XENIX CORE 2 2
385 MICROSOFT NETWORKS 3.0 2 2
386 DOS LM1.2X002 3 3
387 MICROSOFT NETWORKS 1.03 3
388 DOS LANMAN2.1 4 4
389 LANMAN1.0 4 2 3
390 Windows for Workgroups 3.1a 5 5 5 3
391 LM1.2X002 6 4 4
392 LANMAN2.1 7 5 5
393 NT LM 0.12 6 8 6
395 * tim@fsg.com 09/29/95
396 * Win2K added by matty 17/7/99
399 #define ARCH_WFWG 0x3 /* This is a fudge because WfWg is like Win95 */
400 #define ARCH_WIN95 0x2
401 #define ARCH_WINNT 0x4
402 #define ARCH_WIN2K 0xC /* Win2K is like NT */
403 #define ARCH_OS2 0x14 /* Again OS/2 is like NT */
404 #define ARCH_SAMBA 0x20
405 #define ARCH_CIFSFS 0x40
407 #define ARCH_ALL 0x7F
409 /* List of supported protocols, most desired first */
410 static const struct {
411 const char *proto_name;
412 const char *short_name;
413 int (*proto_reply_fn)(char *, char *);
414 int protocol_level;
415 } supported_protocols[] = {
416 {"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1},
417 {"NT LM 0.12", "NT1", reply_nt1, PROTOCOL_NT1},
418 {"POSIX 2", "NT1", reply_nt1, PROTOCOL_NT1},
419 {"LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
420 {"Samba", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
421 {"DOS LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
422 {"LANMAN1.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
423 {"MICROSOFT NETWORKS 3.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
424 {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
425 {"PC NETWORK PROGRAM 1.0", "CORE", reply_corep, PROTOCOL_CORE},
426 {NULL,NULL,NULL,0},
429 /****************************************************************************
430 Reply to a negprot.
431 ****************************************************************************/
433 int reply_negprot(connection_struct *conn,
434 char *inbuf,char *outbuf, int dum_size,
435 int dum_buffsize)
437 int outsize = set_message(outbuf,1,0,True);
438 int Index=0;
439 int choice= -1;
440 int protocol;
441 char *p;
442 int bcc = SVAL(smb_buf(inbuf),-2);
443 int arch = ARCH_ALL;
445 static BOOL done_negprot = False;
447 START_PROFILE(SMBnegprot);
449 if (done_negprot) {
450 END_PROFILE(SMBnegprot);
451 exit_server("multiple negprot's are not permitted");
453 done_negprot = True;
455 p = smb_buf(inbuf)+1;
456 while (p < (smb_buf(inbuf) + bcc)) {
457 Index++;
458 DEBUG(3,("Requested protocol [%s]\n",p));
459 if (strcsequal(p,"Windows for Workgroups 3.1a"))
460 arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
461 else if (strcsequal(p,"DOS LM1.2X002"))
462 arch &= ( ARCH_WFWG | ARCH_WIN95 );
463 else if (strcsequal(p,"DOS LANMAN2.1"))
464 arch &= ( ARCH_WFWG | ARCH_WIN95 );
465 else if (strcsequal(p,"NT LM 0.12"))
466 arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K | ARCH_CIFSFS);
467 else if (strcsequal(p,"LANMAN2.1"))
468 arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
469 else if (strcsequal(p,"LM1.2X002"))
470 arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
471 else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
472 arch &= ARCH_WINNT;
473 else if (strcsequal(p,"XENIX CORE"))
474 arch &= ( ARCH_WINNT | ARCH_OS2 );
475 else if (strcsequal(p,"Samba")) {
476 arch = ARCH_SAMBA;
477 break;
478 } else if (strcsequal(p,"POSIX 2")) {
479 arch = ARCH_CIFSFS;
480 break;
483 p += strlen(p) + 2;
486 /* CIFSFS can send one arch only, NT LM 0.12. */
487 if (Index == 1 && (arch & ARCH_CIFSFS)) {
488 arch = ARCH_CIFSFS;
491 switch ( arch ) {
492 case ARCH_CIFSFS:
493 set_remote_arch(RA_CIFSFS);
494 break;
495 case ARCH_SAMBA:
496 set_remote_arch(RA_SAMBA);
497 break;
498 case ARCH_WFWG:
499 set_remote_arch(RA_WFWG);
500 break;
501 case ARCH_WIN95:
502 set_remote_arch(RA_WIN95);
503 break;
504 case ARCH_WINNT:
505 if(SVAL(inbuf,smb_flg2)==FLAGS2_WIN2K_SIGNATURE)
506 set_remote_arch(RA_WIN2K);
507 else
508 set_remote_arch(RA_WINNT);
509 break;
510 case ARCH_WIN2K:
511 set_remote_arch(RA_WIN2K);
512 break;
513 case ARCH_OS2:
514 set_remote_arch(RA_OS2);
515 break;
516 default:
517 set_remote_arch(RA_UNKNOWN);
518 break;
521 /* possibly reload - change of architecture */
522 reload_services(True);
524 /* Check for protocols, most desirable first */
525 for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) {
526 p = smb_buf(inbuf)+1;
527 Index = 0;
528 if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) &&
529 (supported_protocols[protocol].protocol_level >= lp_minprotocol()))
530 while (p < (smb_buf(inbuf) + bcc)) {
531 if (strequal(p,supported_protocols[protocol].proto_name))
532 choice = Index;
533 Index++;
534 p += strlen(p) + 2;
536 if(choice != -1)
537 break;
540 SSVAL(outbuf,smb_vwv0,choice);
541 if(choice != -1) {
542 extern fstring remote_proto;
543 fstrcpy(remote_proto,supported_protocols[protocol].short_name);
544 reload_services(True);
545 outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf);
546 DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
547 } else {
548 DEBUG(0,("No protocol supported !\n"));
550 SSVAL(outbuf,smb_vwv0,choice);
552 DEBUG( 5, ( "negprot index=%d\n", choice ) );
554 if ((lp_server_signing() == Required) && (Protocol < PROTOCOL_NT1)) {
555 exit_server("SMB signing is required and client negotiated a downlevel protocol");
558 END_PROFILE(SMBnegprot);
559 return(outsize);