c8f023514e6ce13678aada19a7fb773589f356d7
[kai/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         }
105
106         Protocol = PROTOCOL_LANMAN1;
107
108         /* Reply, SMBlockread, SMBwritelock supported. */
109         SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
110         SSVAL(outbuf,smb_vwv2,max_recv);
111         SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
112         SSVAL(outbuf,smb_vwv4,1);
113         SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
114                 readbraw writebraw (possibly) */
115         SIVAL(outbuf,smb_vwv6,sys_getpid());
116         SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
117
118         put_dos_date(outbuf,smb_vwv8,t);
119
120         return (smb_len(outbuf)+4);
121 }
122
123 /****************************************************************************
124  Reply for the lanman 2.0 protocol.
125 ****************************************************************************/
126
127 static int reply_lanman2(char *inbuf, char *outbuf)
128 {
129         int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
130         int secword=0;
131         time_t t = time(NULL);
132
133         global_encrypted_passwords_negotiated = lp_encrypted_passwords();
134   
135         if (lp_security()>=SEC_USER)
136                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
137         if (global_encrypted_passwords_negotiated)
138                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
139
140         set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
141         SSVAL(outbuf,smb_vwv1,secword); 
142         SIVAL(outbuf,smb_vwv6,sys_getpid());
143
144         /* Create a token value and add it to the outgoing packet. */
145         if (global_encrypted_passwords_negotiated) {
146                 get_challenge(smb_buf(outbuf));
147         }
148
149         Protocol = PROTOCOL_LANMAN2;
150
151         /* Reply, SMBlockread, SMBwritelock supported. */
152         SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
153         SSVAL(outbuf,smb_vwv2,max_recv);
154         SSVAL(outbuf,smb_vwv3,lp_maxmux()); 
155         SSVAL(outbuf,smb_vwv4,1);
156         SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
157         SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
158         put_dos_date(outbuf,smb_vwv8,t);
159
160         return (smb_len(outbuf)+4);
161 }
162
163 /****************************************************************************
164  Generate the spnego negprot reply blob. Return the number of bytes used.
165 ****************************************************************************/
166
167 static int negprot_spnego(char *p)
168 {
169         DATA_BLOB blob;
170         uint8 guid[16];
171         const char *OIDs_krb5[] = {OID_KERBEROS5,
172                                    OID_KERBEROS5_OLD,
173                                    OID_NTLMSSP,
174                                    NULL};
175         const char *OIDs_plain[] = {OID_NTLMSSP, NULL};
176         char *principal;
177         int len;
178
179         global_spnego_negotiated = True;
180
181         memset(guid, 0, 16);
182         safe_strcpy((char *)guid, global_myname(), 16);
183         strlower((char *)guid);
184
185 #if 0
186         /* strangely enough, NT does not sent the single OID NTLMSSP when
187            not a ADS member, it sends no OIDs at all
188
189            we can't do this until we teach our sesssion setup parser to know
190            about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)
191         */
192         if (lp_security() != SEC_ADS) {
193                 memcpy(p, guid, 16);
194                 return 16;
195         }
196 #endif
197         if (lp_security() != SEC_ADS) {
198                 blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE");
199         } else {
200                 asprintf(&principal, "%s$@%s", guid, lp_realm());
201                 blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal);
202                 free(principal);
203         }
204         memcpy(p, blob.data, blob.length);
205         len = blob.length;
206         data_blob_free(&blob);
207         return len;
208 }
209
210 /****************************************************************************
211  Reply for the nt protocol.
212 ****************************************************************************/
213
214 static int reply_nt1(char *inbuf, char *outbuf)
215 {
216         /* dual names + lock_and_read + nt SMBs + remote API calls */
217         int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
218                 CAP_LEVEL_II_OPLOCKS;
219
220         int secword=0;
221         time_t t = time(NULL);
222         char *p, *q;
223         BOOL negotiate_spnego = False;
224
225         global_encrypted_passwords_negotiated = lp_encrypted_passwords();
226
227         /* do spnego in user level security if the client
228            supports it and we can do encrypted passwords */
229         
230         if (global_encrypted_passwords_negotiated && 
231             (lp_security() != SEC_SHARE) &&
232             lp_use_spnego() &&
233             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
234                 negotiate_spnego = True;
235                 capabilities |= CAP_EXTENDED_SECURITY;
236         }
237         
238         capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
239
240         if (lp_unix_extensions()) {
241                 capabilities |= CAP_UNIX;
242         }
243         
244         if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64))
245                 capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
246         
247         if (SMB_OFF_T_BITS == 64)
248                 capabilities |= CAP_LARGE_FILES;
249
250         if (lp_readraw() && lp_writeraw())
251                 capabilities |= CAP_RAW_MODE;
252         
253         /* allow for disabling unicode */
254         if (lp_unicode())
255                 capabilities |= CAP_UNICODE;
256
257         if (lp_nt_status_support())
258                 capabilities |= CAP_STATUS32;
259         
260         if (lp_host_msdfs())
261                 capabilities |= CAP_DFS;
262         
263         if (lp_security() >= SEC_USER)
264                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
265         if (global_encrypted_passwords_negotiated)
266                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
267         
268         set_message(outbuf,17,0,True);
269         
270         SCVAL(outbuf,smb_vwv1,secword);
271         
272         Protocol = PROTOCOL_NT1;
273         
274         SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
275         SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
276         SIVAL(outbuf,smb_vwv3+1,max_recv); /* 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);
282         
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;
292                 }
293                 p += srvstr_push(outbuf, p, lp_workgroup(), -1, 
294                                  STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
295                 DEBUG(3,("not using SPNEGO\n"));
296         } else {
297                 int len = negprot_spnego(p);
298                 
299                 SSVALS(outbuf,smb_vwv16+1,len);
300                 p += len;
301                 DEBUG(3,("using SPNEGO\n"));
302         }
303         
304         SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
305         set_message_end(outbuf, p);
306         
307         return (smb_len(outbuf)+4);
308 }
309
310 /* these are the protocol lists used for auto architecture detection:
311
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]
321
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]
331
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]
339
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]
346 */
347
348 /*
349   * Modified to recognize the architecture of the remote machine better.
350   *
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
365   *
366   *  tim@fsg.com 09/29/95
367   *  Win2K added by matty 17/7/99
368   */
369   
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
376  
377 #define ARCH_ALL      0x3F
378  
379 /* List of supported protocols, most desired first */
380 static const struct {
381         const char *proto_name;
382         const 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},
396 };
397
398 /****************************************************************************
399  Reply to a negprot.
400 ****************************************************************************/
401
402 int reply_negprot(connection_struct *conn, 
403                   char *inbuf,char *outbuf, int dum_size, 
404                   int dum_buffsize)
405 {
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;
413
414         static BOOL done_negprot = False;
415
416         START_PROFILE(SMBnegprot);
417
418         if (done_negprot) {
419                 END_PROFILE(SMBnegprot);
420                 exit_server("multiple negprot's are not permitted");
421         }
422         done_negprot = True;
423
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;
447                 }
448  
449                 p += strlen(p) + 2;
450         }
451     
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;
477         }
478  
479         /* possibly reload - change of architecture */
480         reload_services(True);      
481     
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;
493                         }
494                 if(choice != -1)
495                         break;
496         }
497   
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"));
507         }
508         SSVAL(outbuf,smb_vwv0,choice);
509   
510         DEBUG( 5, ( "negprot index=%d\n", choice ) );
511
512         END_PROFILE(SMBnegprot);
513         return(outsize);
514 }