Fairly large change to printing code.
[Samba.git] / source / smbd / negprot.c
blob2be04fd686058f553412aa6cc13efa0d2e190b2e
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_NTLMSSP,
174 OID_KERBEROS5,
175 OID_KERBEROS5_OLD,
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 /* win2000 uses host$@REALM, which we will probably use eventually,
203 but for now this works */
204 asprintf(&principal, "HOST/%s@%s", guid, lp_realm());
205 blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal);
206 free(principal);
208 memcpy(p, blob.data, blob.length);
209 len = blob.length;
210 data_blob_free(&blob);
211 return len;
214 /****************************************************************************
215 Reply for the nt protocol.
216 ****************************************************************************/
218 static int reply_nt1(char *inbuf, char *outbuf)
220 /* dual names + lock_and_read + nt SMBs + remote API calls */
221 int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
222 CAP_LEVEL_II_OPLOCKS;
224 int secword=0;
225 time_t t = time(NULL);
226 char *p, *q;
227 BOOL negotiate_spnego = False;
229 global_encrypted_passwords_negotiated = lp_encrypted_passwords();
231 /* do spnego in user level security if the client
232 supports it and we can do encrypted passwords */
234 if (global_encrypted_passwords_negotiated &&
235 (lp_security() != SEC_SHARE) &&
236 lp_use_spnego() &&
237 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
238 negotiate_spnego = True;
239 capabilities |= CAP_EXTENDED_SECURITY;
242 capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS|CAP_UNIX;
244 if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64))
245 capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
247 if (SMB_OFF_T_BITS == 64)
248 capabilities |= CAP_LARGE_FILES;
250 if (lp_readraw() && lp_writeraw())
251 capabilities |= CAP_RAW_MODE;
253 /* allow for disabling unicode */
254 if (lp_unicode())
255 capabilities |= CAP_UNICODE;
257 if (lp_nt_status_support())
258 capabilities |= CAP_STATUS32;
260 if (lp_host_msdfs())
261 capabilities |= CAP_DFS;
263 if (lp_security() >= SEC_USER)
264 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
265 if (global_encrypted_passwords_negotiated)
266 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
268 set_message(outbuf,17,0,True);
270 SCVAL(outbuf,smb_vwv1,secword);
272 Protocol = PROTOCOL_NT1;
274 SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
275 SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
276 SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
277 SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
278 SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
279 SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
280 put_long_date(outbuf+smb_vwv11+1,t);
281 SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
283 p = q = smb_buf(outbuf);
284 if (!negotiate_spnego) {
285 /* Create a token value and add it to the outgoing packet. */
286 if (global_encrypted_passwords_negotiated) {
287 /* note that we do not send a challenge at all if
288 we are using plaintext */
289 get_challenge(p);
290 SSVALS(outbuf,smb_vwv16+1,8);
291 p += 8;
293 p += srvstr_push(outbuf, p, global_myworkgroup, -1,
294 STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
295 DEBUG(3,("not using SPNEGO\n"));
296 } else {
297 int len = negprot_spnego(p);
299 SSVALS(outbuf,smb_vwv16+1,len);
300 p += len;
301 DEBUG(3,("using SPNEGO\n"));
304 SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
305 set_message_end(outbuf, p);
307 return (smb_len(outbuf)+4);
310 /* these are the protocol lists used for auto architecture detection:
312 WinNT 3.51:
313 protocol [PC NETWORK PROGRAM 1.0]
314 protocol [XENIX CORE]
315 protocol [MICROSOFT NETWORKS 1.03]
316 protocol [LANMAN1.0]
317 protocol [Windows for Workgroups 3.1a]
318 protocol [LM1.2X002]
319 protocol [LANMAN2.1]
320 protocol [NT LM 0.12]
322 Win95:
323 protocol [PC NETWORK PROGRAM 1.0]
324 protocol [XENIX CORE]
325 protocol [MICROSOFT NETWORKS 1.03]
326 protocol [LANMAN1.0]
327 protocol [Windows for Workgroups 3.1a]
328 protocol [LM1.2X002]
329 protocol [LANMAN2.1]
330 protocol [NT LM 0.12]
332 Win2K:
333 protocol [PC NETWORK PROGRAM 1.0]
334 protocol [LANMAN1.0]
335 protocol [Windows for Workgroups 3.1a]
336 protocol [LM1.2X002]
337 protocol [LANMAN2.1]
338 protocol [NT LM 0.12]
340 OS/2:
341 protocol [PC NETWORK PROGRAM 1.0]
342 protocol [XENIX CORE]
343 protocol [LANMAN1.0]
344 protocol [LM1.2X002]
345 protocol [LANMAN2.1]
349 * Modified to recognize the architecture of the remote machine better.
351 * This appears to be the matrix of which protocol is used by which
352 * MS product.
353 Protocol WfWg Win95 WinNT Win2K OS/2
354 PC NETWORK PROGRAM 1.0 1 1 1 1 1
355 XENIX CORE 2 2
356 MICROSOFT NETWORKS 3.0 2 2
357 DOS LM1.2X002 3 3
358 MICROSOFT NETWORKS 1.03 3
359 DOS LANMAN2.1 4 4
360 LANMAN1.0 4 2 3
361 Windows for Workgroups 3.1a 5 5 5 3
362 LM1.2X002 6 4 4
363 LANMAN2.1 7 5 5
364 NT LM 0.12 6 8 6
366 * tim@fsg.com 09/29/95
367 * Win2K added by matty 17/7/99
370 #define ARCH_WFWG 0x3 /* This is a fudge because WfWg is like Win95 */
371 #define ARCH_WIN95 0x2
372 #define ARCH_WINNT 0x4
373 #define ARCH_WIN2K 0xC /* Win2K is like NT */
374 #define ARCH_OS2 0x14 /* Again OS/2 is like NT */
375 #define ARCH_SAMBA 0x20
377 #define ARCH_ALL 0x3F
379 /* List of supported protocols, most desired first */
380 static struct {
381 char *proto_name;
382 char *short_name;
383 int (*proto_reply_fn)(char *, char *);
384 int protocol_level;
385 } supported_protocols[] = {
386 {"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1},
387 {"NT LM 0.12", "NT1", reply_nt1, PROTOCOL_NT1},
388 {"LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
389 {"Samba", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
390 {"DOS LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
391 {"LANMAN1.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
392 {"MICROSOFT NETWORKS 3.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
393 {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
394 {"PC NETWORK PROGRAM 1.0", "CORE", reply_corep, PROTOCOL_CORE},
395 {NULL,NULL,NULL,0},
398 /****************************************************************************
399 Reply to a negprot.
400 ****************************************************************************/
402 int reply_negprot(connection_struct *conn,
403 char *inbuf,char *outbuf, int dum_size,
404 int dum_buffsize)
406 int outsize = set_message(outbuf,1,0,True);
407 int Index=0;
408 int choice= -1;
409 int protocol;
410 char *p;
411 int bcc = SVAL(smb_buf(inbuf),-2);
412 int arch = ARCH_ALL;
414 static BOOL done_negprot = False;
416 START_PROFILE(SMBnegprot);
418 if (done_negprot) {
419 END_PROFILE(SMBnegprot);
420 exit_server("multiple negprot's are not permitted");
422 done_negprot = True;
424 p = smb_buf(inbuf)+1;
425 while (p < (smb_buf(inbuf) + bcc)) {
426 Index++;
427 DEBUG(3,("Requested protocol [%s]\n",p));
428 if (strcsequal(p,"Windows for Workgroups 3.1a"))
429 arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
430 else if (strcsequal(p,"DOS LM1.2X002"))
431 arch &= ( ARCH_WFWG | ARCH_WIN95 );
432 else if (strcsequal(p,"DOS LANMAN2.1"))
433 arch &= ( ARCH_WFWG | ARCH_WIN95 );
434 else if (strcsequal(p,"NT LM 0.12"))
435 arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
436 else if (strcsequal(p,"LANMAN2.1"))
437 arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
438 else if (strcsequal(p,"LM1.2X002"))
439 arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
440 else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
441 arch &= ARCH_WINNT;
442 else if (strcsequal(p,"XENIX CORE"))
443 arch &= ( ARCH_WINNT | ARCH_OS2 );
444 else if (strcsequal(p,"Samba")) {
445 arch = ARCH_SAMBA;
446 break;
449 p += strlen(p) + 2;
452 switch ( arch ) {
453 case ARCH_SAMBA:
454 set_remote_arch(RA_SAMBA);
455 break;
456 case ARCH_WFWG:
457 set_remote_arch(RA_WFWG);
458 break;
459 case ARCH_WIN95:
460 set_remote_arch(RA_WIN95);
461 break;
462 case ARCH_WINNT:
463 if(SVAL(inbuf,smb_flg2)==FLAGS2_WIN2K_SIGNATURE)
464 set_remote_arch(RA_WIN2K);
465 else
466 set_remote_arch(RA_WINNT);
467 break;
468 case ARCH_WIN2K:
469 set_remote_arch(RA_WIN2K);
470 break;
471 case ARCH_OS2:
472 set_remote_arch(RA_OS2);
473 break;
474 default:
475 set_remote_arch(RA_UNKNOWN);
476 break;
479 /* possibly reload - change of architecture */
480 reload_services(True);
482 /* Check for protocols, most desirable first */
483 for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) {
484 p = smb_buf(inbuf)+1;
485 Index = 0;
486 if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) &&
487 (supported_protocols[protocol].protocol_level >= lp_minprotocol()))
488 while (p < (smb_buf(inbuf) + bcc)) {
489 if (strequal(p,supported_protocols[protocol].proto_name))
490 choice = Index;
491 Index++;
492 p += strlen(p) + 2;
494 if(choice != -1)
495 break;
498 SSVAL(outbuf,smb_vwv0,choice);
499 if(choice != -1) {
500 extern fstring remote_proto;
501 fstrcpy(remote_proto,supported_protocols[protocol].short_name);
502 reload_services(True);
503 outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf);
504 DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
505 } else {
506 DEBUG(0,("No protocol supported !\n"));
508 SSVAL(outbuf,smb_vwv0,choice);
510 DEBUG( 5, ( "negprot index=%d\n", choice ) );
512 END_PROFILE(SMBnegprot);
513 return(outsize);