added a "use spnego" option
[bbaumbach/samba-autobuild/.git] / source3 / smbd / negprot.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    negprot reply code
5    Copyright (C) Andrew Tridgell 1992-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 extern int Protocol;
25 extern int max_recv;
26 extern fstring global_myworkgroup;
27 extern fstring remote_machine;
28 BOOL global_encrypted_passwords_negotiated = False;
29 BOOL global_spnego_negotiated = False;
30 auth_authsupplied_info *negprot_global_auth_info = NULL;
31
32 /****************************************************************************
33 reply for the core protocol
34 ****************************************************************************/
35 static int reply_corep(char *inbuf, char *outbuf)
36 {
37         int outsize = set_message(outbuf,1,0,True);
38
39         Protocol = PROTOCOL_CORE;
40         
41         return outsize;
42 }
43
44
45 /****************************************************************************
46 reply for the coreplus protocol
47 ****************************************************************************/
48 static int reply_coreplus(char *inbuf, char *outbuf)
49 {
50   int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
51   int outsize = set_message(outbuf,13,0,True);
52   SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
53                                  readbraw and writebraw (possibly) */
54   /* Reply, SMBlockread, SMBwritelock supported. */
55   SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
56   SSVAL(outbuf,smb_vwv1,0x1); /* user level security, don't encrypt */  
57
58   Protocol = PROTOCOL_COREPLUS;
59
60   return outsize;
61 }
62
63
64 /****************************************************************************
65 reply for the lanman 1.0 protocol
66 ****************************************************************************/
67 static int reply_lanman1(char *inbuf, char *outbuf)
68 {
69   int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
70   int secword=0;
71   time_t t = time(NULL);
72   DATA_BLOB cryptkey;
73
74   global_encrypted_passwords_negotiated = lp_encrypted_passwords();
75
76   if (lp_security()>=SEC_USER) secword |= 1;
77   if (global_encrypted_passwords_negotiated) secword |= 2;
78
79   set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
80   SSVAL(outbuf,smb_vwv1,secword); 
81   /* Create a token value and add it to the outgoing packet. */
82   if (global_encrypted_passwords_negotiated) {
83           if (!make_auth_info_subsystem(&negprot_global_auth_info)) {
84                   smb_panic("cannot make_negprot_global_auth_info!\n");
85           }
86           cryptkey = auth_get_challenge(negprot_global_auth_info);
87           memcpy(smb_buf(outbuf), cryptkey.data, 8);
88           data_blob_free(&cryptkey);
89   }
90
91   Protocol = PROTOCOL_LANMAN1;
92
93   /* Reply, SMBlockread, SMBwritelock supported. */
94   SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
95   SSVAL(outbuf,smb_vwv2,max_recv);
96   SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
97   SSVAL(outbuf,smb_vwv4,1);
98   SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
99                                  readbraw writebraw (possibly) */
100   SIVAL(outbuf,smb_vwv6,sys_getpid());
101   SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
102
103   put_dos_date(outbuf,smb_vwv8,t);
104
105   return (smb_len(outbuf)+4);
106 }
107
108
109 /****************************************************************************
110 reply for the lanman 2.0 protocol
111 ****************************************************************************/
112 static int reply_lanman2(char *inbuf, char *outbuf)
113 {
114   int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
115   int secword=0;
116   time_t t = time(NULL);
117   DATA_BLOB cryptkey;
118
119   global_encrypted_passwords_negotiated = lp_encrypted_passwords();
120   
121   if (lp_security()>=SEC_USER) secword |= 1;
122   if (global_encrypted_passwords_negotiated) secword |= 2;
123
124   set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
125   SSVAL(outbuf,smb_vwv1,secword); 
126   SIVAL(outbuf,smb_vwv6,sys_getpid());
127
128   if (global_encrypted_passwords_negotiated) {
129           if (!make_auth_info_subsystem(&negprot_global_auth_info)) {
130                   smb_panic("cannot make_negprot_global_auth_info!\n");
131           }
132           cryptkey = auth_get_challenge(negprot_global_auth_info);
133           memcpy(smb_buf(outbuf), cryptkey.data, 8);
134           data_blob_free(&cryptkey);
135   }
136
137   Protocol = PROTOCOL_LANMAN2;
138
139   /* Reply, SMBlockread, SMBwritelock supported. */
140   SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
141   SSVAL(outbuf,smb_vwv2,max_recv);
142   SSVAL(outbuf,smb_vwv3,lp_maxmux()); 
143   SSVAL(outbuf,smb_vwv4,1);
144   SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
145   SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
146   put_dos_date(outbuf,smb_vwv8,t);
147
148   return (smb_len(outbuf)+4);
149 }
150
151
152
153 /* 
154    generate the spnego negprot reply blob. Return the number of bytes used
155 */
156 static int negprot_spnego(char *p)
157 {
158         DATA_BLOB blob;
159         extern pstring global_myname;
160         uint8 guid[16];
161         const char *OIDs_krb5[] = {OID_NTLMSSP,
162                                    OID_KERBEROS5,
163                                    OID_KERBEROS5_OLD,
164                                    NULL};
165         const char *OIDs_plain[] = {OID_NTLMSSP, NULL};
166         char *principal;
167         int len;
168
169         global_spnego_negotiated = True;
170
171         memset(guid, 0, 16);
172         safe_strcpy((char *)guid, global_myname, 16);
173         strlower((char *)guid);
174
175 #if 0
176         /* strangely enough, NT does not sent the single OID NTLMSSP when
177            not a ADS member, it sends no OIDs at all
178
179            we can't do this until we teach our sesssion setup parser to know
180            about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)
181         */
182         if (lp_security() != SEC_ADS) {
183                 memcpy(p, guid, 16);
184                 return 16;
185         }
186 #endif
187         {
188                 ADS_STRUCT *ads;
189                 ads = ads_init(NULL, NULL, NULL, NULL);
190                 
191                 /* win2000 uses host$@REALM, which we will probably use eventually,
192                    but for now this works */
193                 asprintf(&principal, "HOST/%s@%s", guid, ads->realm);
194                 blob = spnego_gen_negTokenInit(guid, 
195                                                lp_security()==SEC_ADS ? OIDs_krb5 : OIDs_plain, 
196                                                principal);
197                 free(principal);
198                 ads_destroy(&ads);
199         }
200         memcpy(p, blob.data, blob.length);
201         len = blob.length;
202         data_blob_free(&blob);
203         return len;
204 }
205
206                 
207
208 /****************************************************************************
209 reply for the nt protocol
210 ****************************************************************************/
211 static int reply_nt1(char *inbuf, char *outbuf)
212 {
213         /* dual names + lock_and_read + nt SMBs + remote API calls */
214         int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
215                 CAP_LEVEL_II_OPLOCKS|CAP_STATUS32;
216
217         int secword=0;
218         time_t t = time(NULL);
219         DATA_BLOB cryptkey;
220         char *p, *q;
221         BOOL negotiate_spnego = False;
222
223         global_encrypted_passwords_negotiated = lp_encrypted_passwords();
224
225         /* do spnego in user level security if the client
226            supports it and we can do encrypted passwords */
227         
228         if (global_encrypted_passwords_negotiated && 
229             (lp_security() != SEC_SHARE) &&
230             lp_use_spnego() &&
231             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
232                 negotiate_spnego = True;
233                 capabilities |= CAP_EXTENDED_SECURITY;
234         }
235         
236         capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
237         
238         if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) {
239                 capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
240         }
241         
242         if (SMB_OFF_T_BITS == 64) {
243                 capabilities |= CAP_LARGE_FILES;
244         }
245         
246         if (lp_readraw() && lp_writeraw()) {
247                 capabilities |= CAP_RAW_MODE;
248         }
249         
250         /* allow for disabling unicode */
251         if (lp_unicode()) {
252                 capabilities |= CAP_UNICODE;
253         }
254         
255         if (lp_host_msdfs())
256                 capabilities |= CAP_DFS;
257         
258         if (lp_security() >= SEC_USER) secword |= 1;
259         if (global_encrypted_passwords_negotiated) secword |= 2;
260         
261         set_message(outbuf,17,0,True);
262         
263         CVAL(outbuf,smb_vwv1) = secword;
264         
265         Protocol = PROTOCOL_NT1;
266         
267         SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
268         SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
269         SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
270         SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
271         SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
272         SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
273         put_long_date(outbuf+smb_vwv11+1,t);
274         SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
275         
276         p = q = smb_buf(outbuf);
277         if (!negotiate_spnego) {
278                 if (global_encrypted_passwords_negotiated) { 
279                         if (!make_auth_info_subsystem(&negprot_global_auth_info)) {
280                                 smb_panic("cannot make_negprot_global_auth_info!\n");
281                         }
282                         cryptkey = auth_get_challenge(negprot_global_auth_info);
283                         memcpy(p, cryptkey.data, 8);
284                         data_blob_free(&cryptkey);
285                 }
286                 SSVALS(outbuf,smb_vwv16+1,8);
287                 p += 8;
288                 p += srvstr_push(outbuf, p, global_myworkgroup, -1, 
289                                  STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
290                 DEBUG(3,("not using SPNEGO\n"));
291         } else {
292                 int len = negprot_spnego(p);
293                 
294                 SSVALS(outbuf,smb_vwv16+1,len);
295                 p += len;
296                 DEBUG(3,("using SPNEGO\n"));
297         }
298         
299         SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
300         set_message_end(outbuf, p);
301         
302         return (smb_len(outbuf)+4);
303 }
304
305 /* these are the protocol lists used for auto architecture detection:
306
307 WinNT 3.51:
308 protocol [PC NETWORK PROGRAM 1.0]
309 protocol [XENIX CORE]
310 protocol [MICROSOFT NETWORKS 1.03]
311 protocol [LANMAN1.0]
312 protocol [Windows for Workgroups 3.1a]
313 protocol [LM1.2X002]
314 protocol [LANMAN2.1]
315 protocol [NT LM 0.12]
316
317 Win95:
318 protocol [PC NETWORK PROGRAM 1.0]
319 protocol [XENIX CORE]
320 protocol [MICROSOFT NETWORKS 1.03]
321 protocol [LANMAN1.0]
322 protocol [Windows for Workgroups 3.1a]
323 protocol [LM1.2X002]
324 protocol [LANMAN2.1]
325 protocol [NT LM 0.12]
326
327 Win2K:
328 protocol [PC NETWORK PROGRAM 1.0]
329 protocol [LANMAN1.0]
330 protocol [Windows for Workgroups 3.1a]
331 protocol [LM1.2X002]
332 protocol [LANMAN2.1]
333 protocol [NT LM 0.12]
334
335 OS/2:
336 protocol [PC NETWORK PROGRAM 1.0]
337 protocol [XENIX CORE]
338 protocol [LANMAN1.0]
339 protocol [LM1.2X002]
340 protocol [LANMAN2.1]
341 */
342
343 /*
344   * Modified to recognize the architecture of the remote machine better.
345   *
346   * This appears to be the matrix of which protocol is used by which
347   * MS product.
348        Protocol                       WfWg    Win95   WinNT  Win2K  OS/2
349        PC NETWORK PROGRAM 1.0          1       1       1      1      1
350        XENIX CORE                                      2             2
351        MICROSOFT NETWORKS 3.0          2       2       
352        DOS LM1.2X002                   3       3       
353        MICROSOFT NETWORKS 1.03                         3
354        DOS LANMAN2.1                   4       4       
355        LANMAN1.0                                       4      2      3
356        Windows for Workgroups 3.1a     5       5       5      3
357        LM1.2X002                                       6      4      4
358        LANMAN2.1                                       7      5      5
359        NT LM 0.12                              6       8      6
360   *
361   *  tim@fsg.com 09/29/95
362   *  Win2K added by matty 17/7/99
363   */
364   
365 #define ARCH_WFWG     0x3      /* This is a fudge because WfWg is like Win95 */
366 #define ARCH_WIN95    0x2
367 #define ARCH_WINNT    0x4
368 #define ARCH_WIN2K    0xC      /* Win2K is like NT */
369 #define ARCH_OS2      0x14     /* Again OS/2 is like NT */
370 #define ARCH_SAMBA    0x20
371  
372 #define ARCH_ALL      0x3F
373  
374 /* List of supported protocols, most desired first */
375 static struct {
376   char *proto_name;
377   char *short_name;
378   int (*proto_reply_fn)(char *, char *);
379   int protocol_level;
380 } supported_protocols[] = {
381   {"NT LANMAN 1.0",           "NT1",      reply_nt1,      PROTOCOL_NT1},
382   {"NT LM 0.12",              "NT1",      reply_nt1,      PROTOCOL_NT1},
383   {"LM1.2X002",               "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
384   {"Samba",                   "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
385   {"DOS LM1.2X002",           "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
386   {"LANMAN1.0",               "LANMAN1",  reply_lanman1,  PROTOCOL_LANMAN1},
387   {"MICROSOFT NETWORKS 3.0",  "LANMAN1",  reply_lanman1,  PROTOCOL_LANMAN1},
388   {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
389   {"PC NETWORK PROGRAM 1.0",  "CORE",     reply_corep,    PROTOCOL_CORE}, 
390   {NULL,NULL,NULL,0},
391 };
392
393
394 /****************************************************************************
395   reply to a negprot
396 ****************************************************************************/
397 int reply_negprot(connection_struct *conn, 
398                   char *inbuf,char *outbuf, int dum_size, 
399                   int dum_buffsize)
400 {
401   int outsize = set_message(outbuf,1,0,True);
402   int Index=0;
403   int choice= -1;
404   int protocol;
405   char *p;
406   int bcc = SVAL(smb_buf(inbuf),-2);
407   int arch = ARCH_ALL;
408   START_PROFILE(SMBnegprot);
409
410   p = smb_buf(inbuf)+1;
411   while (p < (smb_buf(inbuf) + bcc))
412     { 
413       Index++;
414       DEBUG(3,("Requested protocol [%s]\n",p));
415       if (strcsequal(p,"Windows for Workgroups 3.1a"))
416         arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
417       else if (strcsequal(p,"DOS LM1.2X002"))
418         arch &= ( ARCH_WFWG | ARCH_WIN95 );
419       else if (strcsequal(p,"DOS LANMAN2.1"))
420         arch &= ( ARCH_WFWG | ARCH_WIN95 );
421       else if (strcsequal(p,"NT LM 0.12"))
422         arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
423       else if (strcsequal(p,"LANMAN2.1"))
424         arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
425       else if (strcsequal(p,"LM1.2X002"))
426         arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
427       else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
428         arch &= ARCH_WINNT;
429       else if (strcsequal(p,"XENIX CORE"))
430         arch &= ( ARCH_WINNT | ARCH_OS2 );
431       else if (strcsequal(p,"Samba")) {
432         arch = ARCH_SAMBA;
433         break;
434       }
435  
436       p += strlen(p) + 2;
437     }
438     
439   switch ( arch ) {
440   case ARCH_SAMBA:
441     set_remote_arch(RA_SAMBA);
442     break;
443   case ARCH_WFWG:
444     set_remote_arch(RA_WFWG);
445     break;
446   case ARCH_WIN95:
447     set_remote_arch(RA_WIN95);
448     break;
449   case ARCH_WINNT:
450    if(SVAL(inbuf,smb_flg2)==FLAGS2_WIN2K_SIGNATURE)
451      set_remote_arch(RA_WIN2K);
452    else
453      set_remote_arch(RA_WINNT);
454     break;
455   case ARCH_WIN2K:
456     set_remote_arch(RA_WIN2K);
457     break;
458   case ARCH_OS2:
459     set_remote_arch(RA_OS2);
460     break;
461   default:
462     set_remote_arch(RA_UNKNOWN);
463     break;
464   }
465  
466   /* possibly reload - change of architecture */
467   reload_services(True);      
468     
469   /* Check for protocols, most desirable first */
470   for (protocol = 0; supported_protocols[protocol].proto_name; protocol++)
471     {
472       p = smb_buf(inbuf)+1;
473       Index = 0;
474       if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) &&
475           (supported_protocols[protocol].protocol_level >= lp_minprotocol()))
476         while (p < (smb_buf(inbuf) + bcc))
477           { 
478             if (strequal(p,supported_protocols[protocol].proto_name))
479               choice = Index;
480             Index++;
481             p += strlen(p) + 2;
482           }
483       if(choice != -1)
484         break;
485     }
486   
487   SSVAL(outbuf,smb_vwv0,choice);
488   if(choice != -1) {
489     extern fstring remote_proto;
490     fstrcpy(remote_proto,supported_protocols[protocol].short_name);
491     reload_services(True);          
492     outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf);
493     DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
494   }
495   else {
496     DEBUG(0,("No protocol supported !\n"));
497   }
498   SSVAL(outbuf,smb_vwv0,choice);
499   
500   DEBUG( 5, ( "negprot index=%d\n", choice ) );
501
502   END_PROFILE(SMBnegprot);
503   return(outsize);
504 }
505