change ADS negprot to match more closely the options used by w2k. This
[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_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         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                 asprintf(&principal, "%s$@%s", guid, lp_realm());
203                 blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal);
204                 free(principal);
205         }
206         memcpy(p, blob.data, blob.length);
207         len = blob.length;
208         data_blob_free(&blob);
209         return len;
210 }
211
212 /****************************************************************************
213  Reply for the nt protocol.
214 ****************************************************************************/
215
216 static int reply_nt1(char *inbuf, char *outbuf)
217 {
218         /* dual names + lock_and_read + nt SMBs + remote API calls */
219         int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
220                 CAP_LEVEL_II_OPLOCKS;
221
222         int secword=0;
223         time_t t = time(NULL);
224         char *p, *q;
225         BOOL negotiate_spnego = False;
226
227         global_encrypted_passwords_negotiated = lp_encrypted_passwords();
228
229         /* do spnego in user level security if the client
230            supports it and we can do encrypted passwords */
231         
232         if (global_encrypted_passwords_negotiated && 
233             (lp_security() != SEC_SHARE) &&
234             lp_use_spnego() &&
235             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
236                 negotiate_spnego = True;
237                 capabilities |= CAP_EXTENDED_SECURITY;
238         }
239         
240         capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
241
242         if (lp_unix_extensions()) {
243                 capabilities |= CAP_UNIX;
244         }
245         
246         if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64))
247                 capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
248         
249         if (SMB_OFF_T_BITS == 64)
250                 capabilities |= CAP_LARGE_FILES;
251
252         if (lp_readraw() && lp_writeraw())
253                 capabilities |= CAP_RAW_MODE;
254         
255         /* allow for disabling unicode */
256         if (lp_unicode())
257                 capabilities |= CAP_UNICODE;
258
259         if (lp_nt_status_support())
260                 capabilities |= CAP_STATUS32;
261         
262         if (lp_host_msdfs())
263                 capabilities |= CAP_DFS;
264         
265         if (lp_security() >= SEC_USER)
266                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
267         if (global_encrypted_passwords_negotiated)
268                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
269         
270         set_message(outbuf,17,0,True);
271         
272         SCVAL(outbuf,smb_vwv1,secword);
273         
274         Protocol = PROTOCOL_NT1;
275         
276         SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
277         SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
278         SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
279         SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
280         SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
281         SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
282         put_long_date(outbuf+smb_vwv11+1,t);
283         SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
284         
285         p = q = smb_buf(outbuf);
286         if (!negotiate_spnego) {
287                 /* Create a token value and add it to the outgoing packet. */
288                 if (global_encrypted_passwords_negotiated) {
289                         /* note that we do not send a challenge at all if
290                            we are using plaintext */
291                         get_challenge(p);
292                         SSVALS(outbuf,smb_vwv16+1,8);
293                         p += 8;
294                 }
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 }