an initial fix for handling sparse files in smbd
[import/samba-cvsimport.git] / source / smbd / negprot.c
1 /* 
2    Unix SMB/CIFS implementation.
3    negprot reply code
4    Copyright (C) Andrew Tridgell 1992-1998
5    
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.
10    
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.
15    
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.
19 */
20
21 #include "includes.h"
22
23 extern int Protocol;
24 extern int max_recv;
25 extern fstring global_myworkgroup;
26 extern fstring remote_machine;
27 BOOL global_encrypted_passwords_negotiated = False;
28 BOOL global_spnego_negotiated = False;
29 struct auth_context *negprot_global_auth_context = NULL;
30
31 static void get_challenge(char buff[8]) 
32 {
33         NTSTATUS nt_status;
34         const uint8 *cryptkey;
35
36         /* We might be called more than once, muliple negprots are premitted */
37         if (negprot_global_auth_context) {
38                 DEBUG(3, ("get challenge: is this a secondary negprot?  negprot_global_auth_context is non-NULL!\n"));
39                 (negprot_global_auth_context->free)(&negprot_global_auth_context);
40         }
41
42         DEBUG(10, ("get challenge: creating negprot_global_auth_context\n"));
43         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&negprot_global_auth_context))) {
44                 DEBUG(0, ("make_auth_context_subsystem returned %s", nt_errstr(nt_status)));
45                 smb_panic("cannot make_negprot_global_auth_context!\n");
46         }
47         DEBUG(10, ("get challenge: getting challenge\n"));
48         cryptkey = negprot_global_auth_context->get_ntlm_challenge(negprot_global_auth_context);
49         memcpy(buff, cryptkey, 8);
50 }
51
52 /****************************************************************************
53  Reply for the core protocol.
54 ****************************************************************************/
55
56 static int reply_corep(char *inbuf, char *outbuf)
57 {
58         int outsize = set_message(outbuf,1,0,True);
59
60         Protocol = PROTOCOL_CORE;
61         
62         return outsize;
63 }
64
65 /****************************************************************************
66  Reply for the coreplus protocol.
67 ****************************************************************************/
68
69 static int reply_coreplus(char *inbuf, char *outbuf)
70 {
71         int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
72         int outsize = set_message(outbuf,13,0,True);
73         SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
74                         readbraw and writebraw (possibly) */
75         /* Reply, SMBlockread, SMBwritelock supported. */
76         SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
77         SSVAL(outbuf,smb_vwv1,0x1); /* user level security, don't encrypt */    
78
79         Protocol = PROTOCOL_COREPLUS;
80
81         return outsize;
82 }
83
84 /****************************************************************************
85  Reply for the lanman 1.0 protocol.
86 ****************************************************************************/
87
88 static int reply_lanman1(char *inbuf, char *outbuf)
89 {
90         int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
91         int secword=0;
92         time_t t = time(NULL);
93
94         global_encrypted_passwords_negotiated = lp_encrypted_passwords();
95
96         if (lp_security()>=SEC_USER)
97                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
98         if (global_encrypted_passwords_negotiated)
99                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
100
101         set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
102         SSVAL(outbuf,smb_vwv1,secword); 
103         /* Create a token value and add it to the outgoing packet. */
104         if (global_encrypted_passwords_negotiated) {
105                 get_challenge(smb_buf(outbuf));
106         }
107
108         Protocol = PROTOCOL_LANMAN1;
109
110         /* Reply, SMBlockread, SMBwritelock supported. */
111         SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
112         SSVAL(outbuf,smb_vwv2,max_recv);
113         SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
114         SSVAL(outbuf,smb_vwv4,1);
115         SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
116                 readbraw writebraw (possibly) */
117         SIVAL(outbuf,smb_vwv6,sys_getpid());
118         SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
119
120         put_dos_date(outbuf,smb_vwv8,t);
121
122         return (smb_len(outbuf)+4);
123 }
124
125 /****************************************************************************
126  Reply for the lanman 2.0 protocol.
127 ****************************************************************************/
128
129 static int reply_lanman2(char *inbuf, char *outbuf)
130 {
131         int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
132         int secword=0;
133         time_t t = time(NULL);
134
135         global_encrypted_passwords_negotiated = lp_encrypted_passwords();
136   
137         if (lp_security()>=SEC_USER)
138                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
139         if (global_encrypted_passwords_negotiated)
140                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
141
142         set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
143         SSVAL(outbuf,smb_vwv1,secword); 
144         SIVAL(outbuf,smb_vwv6,sys_getpid());
145
146         /* Create a token value and add it to the outgoing packet. */
147         if (global_encrypted_passwords_negotiated) {
148                 get_challenge(smb_buf(outbuf));
149         }
150
151         Protocol = PROTOCOL_LANMAN2;
152
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);
161
162         return (smb_len(outbuf)+4);
163 }
164
165 /****************************************************************************
166  Generate the spnego negprot reply blob. Return the number of bytes used.
167 ****************************************************************************/
168
169 static int negprot_spnego(char *p)
170 {
171         DATA_BLOB blob;
172         extern pstring global_myname;
173         uint8 guid[16];
174         const char *OIDs_krb5[] = {OID_NTLMSSP,
175                                    OID_KERBEROS5,
176                                    OID_KERBEROS5_OLD,
177                                    NULL};
178         const char *OIDs_plain[] = {OID_NTLMSSP, NULL};
179         char *principal;
180         int len;
181
182         global_spnego_negotiated = True;
183
184         memset(guid, 0, 16);
185         safe_strcpy((char *)guid, global_myname, 16);
186         strlower((char *)guid);
187
188 #if 0
189         /* strangely enough, NT does not sent the single OID NTLMSSP when
190            not a ADS member, it sends no OIDs at all
191
192            we can't do this until we teach our sesssion setup parser to know
193            about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)
194         */
195         if (lp_security() != SEC_ADS) {
196                 memcpy(p, guid, 16);
197                 return 16;
198         }
199 #endif
200         if (lp_security() != SEC_ADS) {
201                 blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE");
202         } else {
203                 ADS_STRUCT *ads;
204                 ads = ads_init_simple();
205                 /* win2000 uses host$@REALM, which we will probably use eventually,
206                    but for now this works */
207                 asprintf(&principal, "HOST/%s@%s", guid, ads->realm);
208                 blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal);
209                 free(principal);
210                 ads_destroy(&ads);
211         }
212         memcpy(p, blob.data, blob.length);
213         len = blob.length;
214         data_blob_free(&blob);
215         return len;
216 }
217
218 /****************************************************************************
219  Reply for the nt protocol.
220 ****************************************************************************/
221
222 static int reply_nt1(char *inbuf, char *outbuf)
223 {
224         /* dual names + lock_and_read + nt SMBs + remote API calls */
225         int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
226                 CAP_LEVEL_II_OPLOCKS;
227
228         int secword=0;
229         time_t t = time(NULL);
230         char *p, *q;
231         BOOL negotiate_spnego = False;
232
233         global_encrypted_passwords_negotiated = lp_encrypted_passwords();
234
235         /* do spnego in user level security if the client
236            supports it and we can do encrypted passwords */
237         
238         if (global_encrypted_passwords_negotiated && 
239             (lp_security() != SEC_SHARE) &&
240             lp_use_spnego() &&
241             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
242                 negotiate_spnego = True;
243                 capabilities |= CAP_EXTENDED_SECURITY;
244         }
245         
246         capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS|CAP_UNIX;
247         
248         if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64))
249                 capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
250         
251         if (SMB_OFF_T_BITS == 64)
252                 capabilities |= CAP_LARGE_FILES;
253
254         if (lp_readraw() && lp_writeraw())
255                 capabilities |= CAP_RAW_MODE;
256         
257         /* allow for disabling unicode */
258         if (lp_unicode())
259                 capabilities |= CAP_UNICODE;
260
261         if (lp_nt_status_support())
262                 capabilities |= CAP_STATUS32;
263         
264         if (lp_host_msdfs())
265                 capabilities |= CAP_DFS;
266         
267         if (lp_security() >= SEC_USER)
268                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
269         if (global_encrypted_passwords_negotiated)
270                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
271         
272         set_message(outbuf,17,0,True);
273         
274         SCVAL(outbuf,smb_vwv1,secword);
275         
276         Protocol = PROTOCOL_NT1;
277         
278         SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
279         SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
280         SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
281         SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
282         SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
283         SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
284         put_long_date(outbuf+smb_vwv11+1,t);
285         SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
286         
287         p = q = smb_buf(outbuf);
288         if (!negotiate_spnego) {
289                 /* Create a token value and add it to the outgoing packet. */
290                 if (global_encrypted_passwords_negotiated) {
291                         get_challenge(p);
292                 }
293                 SSVALS(outbuf,smb_vwv16+1,8);
294                 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);
300                 
301                 SSVALS(outbuf,smb_vwv16+1,len);
302                 p += len;
303                 DEBUG(3,("using SPNEGO\n"));
304         }
305         
306         SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
307         set_message_end(outbuf, p);
308         
309         return (smb_len(outbuf)+4);
310 }
311
312 /* these are the protocol lists used for auto architecture detection:
313
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]
323
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]
333
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]
341
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]
348 */
349
350 /*
351   * Modified to recognize the architecture of the remote machine better.
352   *
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
367   *
368   *  tim@fsg.com 09/29/95
369   *  Win2K added by matty 17/7/99
370   */
371   
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
378  
379 #define ARCH_ALL      0x3F
380  
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},
398 };
399
400 /****************************************************************************
401  Reply to a negprot.
402 ****************************************************************************/
403
404 int reply_negprot(connection_struct *conn, 
405                   char *inbuf,char *outbuf, int dum_size, 
406                   int dum_buffsize)
407 {
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;
415
416         static BOOL done_negprot = False;
417
418         START_PROFILE(SMBnegprot);
419
420         if (done_negprot) {
421                 END_PROFILE(SMBnegprot);
422                 exit_server("multiple negprot's are not permitted");
423         }
424         done_negprot = True;
425
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;
449                 }
450  
451                 p += strlen(p) + 2;
452         }
453     
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;
479         }
480  
481         /* possibly reload - change of architecture */
482         reload_services(True);      
483     
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;
495                         }
496                 if(choice != -1)
497                         break;
498         }
499   
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"));
509         }
510         SSVAL(outbuf,smb_vwv0,choice);
511   
512         DEBUG( 5, ( "negprot index=%d\n", choice ) );
513
514         END_PROFILE(SMBnegprot);
515         return(outsize);
516 }