This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[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 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;
29
30 static void get_challenge(char buff[8]) 
31 {
32         NTSTATUS nt_status;
33         const uint8 *cryptkey;
34
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);
39         }
40
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");
45         }
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);
49 }
50
51 /****************************************************************************
52  Reply for the core protocol.
53 ****************************************************************************/
54
55 static int reply_corep(char *inbuf, char *outbuf)
56 {
57         int outsize = set_message(outbuf,1,0,True);
58
59         Protocol = PROTOCOL_CORE;
60         
61         return outsize;
62 }
63
64 /****************************************************************************
65  Reply for the coreplus protocol.
66 ****************************************************************************/
67
68 static int reply_coreplus(char *inbuf, char *outbuf)
69 {
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 */    
77
78         Protocol = PROTOCOL_COREPLUS;
79
80         return outsize;
81 }
82
83 /****************************************************************************
84  Reply for the lanman 1.0 protocol.
85 ****************************************************************************/
86
87 static int reply_lanman1(char *inbuf, char *outbuf)
88 {
89         int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
90         int secword=0;
91         time_t t = time(NULL);
92
93         global_encrypted_passwords_negotiated = lp_encrypted_passwords();
94
95         if (lp_security()>=SEC_USER)
96                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
97         if (global_encrypted_passwords_negotiated)
98                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
99
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));
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         }
149
150         Protocol = PROTOCOL_LANMAN2;
151
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);
160
161         return (smb_len(outbuf)+4);
162 }
163
164 /****************************************************************************
165  Generate the spnego negprot reply blob. Return the number of bytes used.
166 ****************************************************************************/
167
168 static int negprot_spnego(char *p)
169 {
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;
180
181         global_spnego_negotiated = True;
182
183         memset(guid, 0, 16);
184         safe_strcpy((char *)guid, global_myname, 16);
185         strlower((char *)guid);
186
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
190
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)
193         */
194         if (lp_security() != SEC_ADS) {
195                 memcpy(p, guid, 16);
196                 return 16;
197         }
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);
207         }
208         memcpy(p, blob.data, blob.length);
209         len = blob.length;
210         data_blob_free(&blob);
211         return len;
212 }
213
214 /****************************************************************************
215  Reply for the nt protocol.
216 ****************************************************************************/
217
218 static int reply_nt1(char *inbuf, char *outbuf)
219 {
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;
223
224         int secword=0;
225         time_t t = time(NULL);
226         char *p, *q;
227         BOOL negotiate_spnego = False;
228
229         global_encrypted_passwords_negotiated = lp_encrypted_passwords();
230
231         /* do spnego in user level security if the client
232            supports it and we can do encrypted passwords */
233         
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;
240         }
241         
242         capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS|CAP_UNIX;
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,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);
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, 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);
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 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},
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 }