Fixes to stop valgrind complaining about uninitialised memory when it's
[samba.git] / source3 / 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 BOOL global_encrypted_passwords_negotiated = False;
26 BOOL global_spnego_negotiated = False;
27 struct auth_context *negprot_global_auth_context = NULL;
28
29 static void get_challenge(char buff[8]) 
30 {
31         NTSTATUS nt_status;
32         const uint8 *cryptkey;
33
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);
38         }
39
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");
44         }
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);
48 }
49
50 /****************************************************************************
51  Reply for the core protocol.
52 ****************************************************************************/
53
54 static int reply_corep(char *inbuf, char *outbuf)
55 {
56         int outsize = set_message(outbuf,1,0,True);
57
58         Protocol = PROTOCOL_CORE;
59         
60         return outsize;
61 }
62
63 /****************************************************************************
64  Reply for the coreplus protocol.
65 ****************************************************************************/
66
67 static int reply_coreplus(char *inbuf, char *outbuf)
68 {
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 */    
76
77         Protocol = PROTOCOL_COREPLUS;
78
79         return outsize;
80 }
81
82 /****************************************************************************
83  Reply for the lanman 1.0 protocol.
84 ****************************************************************************/
85
86 static int reply_lanman1(char *inbuf, char *outbuf)
87 {
88         int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
89         int secword=0;
90         time_t t = time(NULL);
91
92         global_encrypted_passwords_negotiated = lp_encrypted_passwords();
93
94         if (lp_security()>=SEC_USER)
95                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
96         if (global_encrypted_passwords_negotiated)
97                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
98
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);
105         }
106
107         Protocol = PROTOCOL_LANMAN1;
108
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);
118
119         put_dos_date(outbuf,smb_vwv8,t);
120
121         return (smb_len(outbuf)+4);
122 }
123
124 /****************************************************************************
125  Reply for the lanman 2.0 protocol.
126 ****************************************************************************/
127
128 static int reply_lanman2(char *inbuf, char *outbuf)
129 {
130         int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
131         int secword=0;
132         time_t t = time(NULL);
133
134         global_encrypted_passwords_negotiated = lp_encrypted_passwords();
135   
136         if (lp_security()>=SEC_USER)
137                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
138         if (global_encrypted_passwords_negotiated)
139                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
140
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());
144
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);
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         uint8 guid[17];
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;
180
181         global_spnego_negotiated = True;
182
183         ZERO_STRUCT(guid);
184         safe_strcpy((char *)guid, global_myname(), sizeof(guid)-1);
185
186 #ifdef DEVELOPER
187         {
188                 size_t sl = strlen(guid);
189                 if (sizeof(guid)-sl)
190                         memset(&guid[sl], '\0', sizeof(guid)-sl);
191         }
192 #endif
193
194         strlower((char *)guid);
195
196 #if 0
197         /* strangely enough, NT does not sent the single OID NTLMSSP when
198            not a ADS member, it sends no OIDs at all
199
200            we can't do this until we teach our sesssion setup parser to know
201            about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)
202         */
203         if (lp_security() != SEC_ADS) {
204                 memcpy(p, guid, 16);
205                 return 16;
206         }
207 #endif
208         if (lp_security() != SEC_ADS) {
209                 blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE");
210         } else {
211                 asprintf(&principal, "%s$@%s", guid, lp_realm());
212                 blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal);
213                 free(principal);
214         }
215         memcpy(p, blob.data, blob.length);
216         len = blob.length;
217         data_blob_free(&blob);
218         return len;
219 }
220
221 /****************************************************************************
222  Reply for the nt protocol.
223 ****************************************************************************/
224
225 static int reply_nt1(char *inbuf, char *outbuf)
226 {
227         /* dual names + lock_and_read + nt SMBs + remote API calls */
228         int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
229                 CAP_LEVEL_II_OPLOCKS;
230
231         int secword=0;
232         time_t t = time(NULL);
233         char *p, *q;
234         BOOL negotiate_spnego = False;
235
236         global_encrypted_passwords_negotiated = lp_encrypted_passwords();
237
238         /* do spnego in user level security if the client
239            supports it and we can do encrypted passwords */
240         
241         if (global_encrypted_passwords_negotiated && 
242             (lp_security() != SEC_SHARE) &&
243             lp_use_spnego() &&
244             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
245                 negotiate_spnego = True;
246                 capabilities |= CAP_EXTENDED_SECURITY;
247         }
248         
249         capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
250
251         if (lp_unix_extensions()) {
252                 capabilities |= CAP_UNIX;
253         }
254         
255         if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64))
256                 capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
257         
258         if (SMB_OFF_T_BITS == 64)
259                 capabilities |= CAP_LARGE_FILES;
260
261         if (lp_readraw() && lp_writeraw())
262                 capabilities |= CAP_RAW_MODE;
263         
264         /* allow for disabling unicode */
265         if (lp_unicode())
266                 capabilities |= CAP_UNICODE;
267
268         if (lp_nt_status_support())
269                 capabilities |= CAP_STATUS32;
270         
271         if (lp_host_msdfs())
272                 capabilities |= CAP_DFS;
273         
274         if (lp_security() >= SEC_USER)
275                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
276         if (global_encrypted_passwords_negotiated)
277                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
278         
279         set_message(outbuf,17,0,True);
280         
281         SCVAL(outbuf,smb_vwv1,secword);
282         
283         Protocol = PROTOCOL_NT1;
284         
285         SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
286         SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
287         SIVAL(outbuf,smb_vwv3+1,max_recv); /* max buffer. LOTS! */
288         SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
289         SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
290         SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
291         put_long_date(outbuf+smb_vwv11+1,t);
292         SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
293         
294         p = q = smb_buf(outbuf);
295         if (!negotiate_spnego) {
296                 /* Create a token value and add it to the outgoing packet. */
297                 if (global_encrypted_passwords_negotiated) {
298                         /* note that we do not send a challenge at all if
299                            we are using plaintext */
300                         get_challenge(p);
301                         SSVALS(outbuf,smb_vwv16+1,8);
302                         p += 8;
303                 }
304                 p += srvstr_push(outbuf, p, lp_workgroup(), -1, 
305                                  STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
306                 DEBUG(3,("not using SPNEGO\n"));
307         } else {
308                 int len = negprot_spnego(p);
309                 
310                 SSVALS(outbuf,smb_vwv16+1,len);
311                 p += len;
312                 DEBUG(3,("using SPNEGO\n"));
313         }
314         
315         SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
316         set_message_end(outbuf, p);
317         
318         return (smb_len(outbuf)+4);
319 }
320
321 /* these are the protocol lists used for auto architecture detection:
322
323 WinNT 3.51:
324 protocol [PC NETWORK PROGRAM 1.0]
325 protocol [XENIX CORE]
326 protocol [MICROSOFT NETWORKS 1.03]
327 protocol [LANMAN1.0]
328 protocol [Windows for Workgroups 3.1a]
329 protocol [LM1.2X002]
330 protocol [LANMAN2.1]
331 protocol [NT LM 0.12]
332
333 Win95:
334 protocol [PC NETWORK PROGRAM 1.0]
335 protocol [XENIX CORE]
336 protocol [MICROSOFT NETWORKS 1.03]
337 protocol [LANMAN1.0]
338 protocol [Windows for Workgroups 3.1a]
339 protocol [LM1.2X002]
340 protocol [LANMAN2.1]
341 protocol [NT LM 0.12]
342
343 Win2K:
344 protocol [PC NETWORK PROGRAM 1.0]
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]
350
351 OS/2:
352 protocol [PC NETWORK PROGRAM 1.0]
353 protocol [XENIX CORE]
354 protocol [LANMAN1.0]
355 protocol [LM1.2X002]
356 protocol [LANMAN2.1]
357 */
358
359 /*
360   * Modified to recognize the architecture of the remote machine better.
361   *
362   * This appears to be the matrix of which protocol is used by which
363   * MS product.
364        Protocol                       WfWg    Win95   WinNT  Win2K  OS/2
365        PC NETWORK PROGRAM 1.0          1       1       1      1      1
366        XENIX CORE                                      2             2
367        MICROSOFT NETWORKS 3.0          2       2       
368        DOS LM1.2X002                   3       3       
369        MICROSOFT NETWORKS 1.03                         3
370        DOS LANMAN2.1                   4       4       
371        LANMAN1.0                                       4      2      3
372        Windows for Workgroups 3.1a     5       5       5      3
373        LM1.2X002                                       6      4      4
374        LANMAN2.1                                       7      5      5
375        NT LM 0.12                              6       8      6
376   *
377   *  tim@fsg.com 09/29/95
378   *  Win2K added by matty 17/7/99
379   */
380   
381 #define ARCH_WFWG     0x3      /* This is a fudge because WfWg is like Win95 */
382 #define ARCH_WIN95    0x2
383 #define ARCH_WINNT    0x4
384 #define ARCH_WIN2K    0xC      /* Win2K is like NT */
385 #define ARCH_OS2      0x14     /* Again OS/2 is like NT */
386 #define ARCH_SAMBA    0x20
387  
388 #define ARCH_ALL      0x3F
389  
390 /* List of supported protocols, most desired first */
391 static const struct {
392         const char *proto_name;
393         const char *short_name;
394         int (*proto_reply_fn)(char *, char *);
395         int protocol_level;
396 } supported_protocols[] = {
397         {"NT LANMAN 1.0",           "NT1",      reply_nt1,      PROTOCOL_NT1},
398         {"NT LM 0.12",              "NT1",      reply_nt1,      PROTOCOL_NT1},
399         {"LM1.2X002",               "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
400         {"Samba",                   "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
401         {"DOS LM1.2X002",           "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
402         {"LANMAN1.0",               "LANMAN1",  reply_lanman1,  PROTOCOL_LANMAN1},
403         {"MICROSOFT NETWORKS 3.0",  "LANMAN1",  reply_lanman1,  PROTOCOL_LANMAN1},
404         {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
405         {"PC NETWORK PROGRAM 1.0",  "CORE",     reply_corep,    PROTOCOL_CORE}, 
406         {NULL,NULL,NULL,0},
407 };
408
409 /****************************************************************************
410  Reply to a negprot.
411 ****************************************************************************/
412
413 int reply_negprot(connection_struct *conn, 
414                   char *inbuf,char *outbuf, int dum_size, 
415                   int dum_buffsize)
416 {
417         int outsize = set_message(outbuf,1,0,True);
418         int Index=0;
419         int choice= -1;
420         int protocol;
421         char *p;
422         int bcc = SVAL(smb_buf(inbuf),-2);
423         int arch = ARCH_ALL;
424
425         static BOOL done_negprot = False;
426
427         START_PROFILE(SMBnegprot);
428
429         if (done_negprot) {
430                 END_PROFILE(SMBnegprot);
431                 exit_server("multiple negprot's are not permitted");
432         }
433         done_negprot = True;
434
435         p = smb_buf(inbuf)+1;
436         while (p < (smb_buf(inbuf) + bcc)) { 
437                 Index++;
438                 DEBUG(3,("Requested protocol [%s]\n",p));
439                 if (strcsequal(p,"Windows for Workgroups 3.1a"))
440                         arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
441                 else if (strcsequal(p,"DOS LM1.2X002"))
442                         arch &= ( ARCH_WFWG | ARCH_WIN95 );
443                 else if (strcsequal(p,"DOS LANMAN2.1"))
444                         arch &= ( ARCH_WFWG | ARCH_WIN95 );
445                 else if (strcsequal(p,"NT LM 0.12"))
446                         arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
447                 else if (strcsequal(p,"LANMAN2.1"))
448                         arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
449                 else if (strcsequal(p,"LM1.2X002"))
450                         arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
451                 else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
452                         arch &= ARCH_WINNT;
453                 else if (strcsequal(p,"XENIX CORE"))
454                         arch &= ( ARCH_WINNT | ARCH_OS2 );
455                 else if (strcsequal(p,"Samba")) {
456                         arch = ARCH_SAMBA;
457                         break;
458                 }
459  
460                 p += strlen(p) + 2;
461         }
462     
463         switch ( arch ) {
464                 case ARCH_SAMBA:
465                         set_remote_arch(RA_SAMBA);
466                         break;
467                 case ARCH_WFWG:
468                         set_remote_arch(RA_WFWG);
469                         break;
470                 case ARCH_WIN95:
471                         set_remote_arch(RA_WIN95);
472                         break;
473                 case ARCH_WINNT:
474                         if(SVAL(inbuf,smb_flg2)==FLAGS2_WIN2K_SIGNATURE)
475                                 set_remote_arch(RA_WIN2K);
476                         else
477                                 set_remote_arch(RA_WINNT);
478                         break;
479                 case ARCH_WIN2K:
480                         set_remote_arch(RA_WIN2K);
481                         break;
482                 case ARCH_OS2:
483                         set_remote_arch(RA_OS2);
484                         break;
485                 default:
486                         set_remote_arch(RA_UNKNOWN);
487                 break;
488         }
489  
490         /* possibly reload - change of architecture */
491         reload_services(True);      
492     
493         /* Check for protocols, most desirable first */
494         for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) {
495                 p = smb_buf(inbuf)+1;
496                 Index = 0;
497                 if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) &&
498                                 (supported_protocols[protocol].protocol_level >= lp_minprotocol()))
499                         while (p < (smb_buf(inbuf) + bcc)) { 
500                                 if (strequal(p,supported_protocols[protocol].proto_name))
501                                         choice = Index;
502                                 Index++;
503                                 p += strlen(p) + 2;
504                         }
505                 if(choice != -1)
506                         break;
507         }
508   
509         SSVAL(outbuf,smb_vwv0,choice);
510         if(choice != -1) {
511                 extern fstring remote_proto;
512                 fstrcpy(remote_proto,supported_protocols[protocol].short_name);
513                 reload_services(True);          
514                 outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf);
515                 DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
516         } else {
517                 DEBUG(0,("No protocol supported !\n"));
518         }
519         SSVAL(outbuf,smb_vwv0,choice);
520   
521         DEBUG( 5, ( "negprot index=%d\n", choice ) );
522
523         END_PROFILE(SMBnegprot);
524         return(outsize);
525 }