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