52ba5e97892e35a46079a719e84eeecf288f4360
[ira/wip.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 struct auth_context *negprot_global_auth_context = NULL;
31
32 static void get_challange(char buff[8]) 
33 {
34         NTSTATUS nt_status;
35         const uint8 *cryptkey;
36
37         /* We might be called more than once, muliple negprots are premitted */
38         if (negprot_global_auth_context) {
39                 DEBUG(3, ("get challange: is this a secondary negprot?  negprot_global_auth_context is non-NULL!\n"));
40                 negprot_global_auth_context->free(&negprot_global_auth_context);
41         }
42
43         DEBUG(10, ("get challange: creating negprot_global_auth_context\n"));
44         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&negprot_global_auth_context))) {
45                 DEBUG(0, ("make_auth_context_subsystem returned %s", get_nt_error_msg(nt_status)));
46                 smb_panic("cannot make_negprot_global_auth_context!\n");
47         }
48         DEBUG(10, ("get challange: getting challange\n"));
49         cryptkey = negprot_global_auth_context->get_ntlm_challenge(negprot_global_auth_context);
50         memcpy(buff, cryptkey, 8);
51 }
52
53 /****************************************************************************
54 reply for the core protocol
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 /****************************************************************************
67 reply for the coreplus protocol
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 /****************************************************************************
86 reply for the lanman 1.0 protocol
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) secword |= 1;
97   if (global_encrypted_passwords_negotiated) secword |= 2;
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_challange(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 /****************************************************************************
125 reply for the lanman 2.0 protocol
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) secword |= 1;
136   if (global_encrypted_passwords_negotiated) secword |= 2;
137
138   set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
139   SSVAL(outbuf,smb_vwv1,secword); 
140   SIVAL(outbuf,smb_vwv6,sys_getpid());
141
142   /* Create a token value and add it to the outgoing packet. */
143   if (global_encrypted_passwords_negotiated) {
144           get_challange(smb_buf(outbuf));
145   }
146
147   Protocol = PROTOCOL_LANMAN2;
148
149   /* Reply, SMBlockread, SMBwritelock supported. */
150   SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
151   SSVAL(outbuf,smb_vwv2,max_recv);
152   SSVAL(outbuf,smb_vwv3,lp_maxmux()); 
153   SSVAL(outbuf,smb_vwv4,1);
154   SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
155   SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
156   put_dos_date(outbuf,smb_vwv8,t);
157
158   return (smb_len(outbuf)+4);
159 }
160
161
162
163 /* 
164    generate the spnego negprot reply blob. Return the number of bytes used
165 */
166 static int negprot_spnego(char *p)
167 {
168         DATA_BLOB blob;
169         extern pstring global_myname;
170         uint8 guid[16];
171         const char *OIDs_krb5[] = {OID_NTLMSSP,
172                                    OID_KERBEROS5,
173                                    OID_KERBEROS5_OLD,
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         {
198                 ADS_STRUCT *ads;
199                 ads = ads_init(NULL, NULL, NULL, NULL);
200                 
201                 /* win2000 uses host$@REALM, which we will probably use eventually,
202                    but for now this works */
203                 asprintf(&principal, "HOST/%s@%s", guid, ads->realm);
204                 blob = spnego_gen_negTokenInit(guid, 
205                                                lp_security()==SEC_ADS ? OIDs_krb5 : OIDs_plain, 
206                                                principal);
207                 free(principal);
208                 ads_destroy(&ads);
209         }
210         memcpy(p, blob.data, blob.length);
211         len = blob.length;
212         data_blob_free(&blob);
213         return len;
214 }
215
216                 
217
218 /****************************************************************************
219 reply for the nt protocol
220 ****************************************************************************/
221 static int reply_nt1(char *inbuf, char *outbuf)
222 {
223         /* dual names + lock_and_read + nt SMBs + remote API calls */
224         int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
225                 CAP_LEVEL_II_OPLOCKS|CAP_STATUS32;
226
227         int secword=0;
228         time_t t = time(NULL);
229         char *p, *q;
230         BOOL negotiate_spnego = False;
231
232         global_encrypted_passwords_negotiated = lp_encrypted_passwords();
233
234         /* do spnego in user level security if the client
235            supports it and we can do encrypted passwords */
236         
237         if (global_encrypted_passwords_negotiated && 
238             (lp_security() != SEC_SHARE) &&
239             lp_use_spnego() &&
240             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
241                 negotiate_spnego = True;
242                 capabilities |= CAP_EXTENDED_SECURITY;
243         }
244         
245         capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
246         
247         if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) {
248                 capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
249         }
250         
251         if (SMB_OFF_T_BITS == 64) {
252                 capabilities |= CAP_LARGE_FILES;
253         }
254         
255         if (lp_readraw() && lp_writeraw()) {
256                 capabilities |= CAP_RAW_MODE;
257         }
258         
259         /* allow for disabling unicode */
260         if (lp_unicode()) {
261                 capabilities |= CAP_UNICODE;
262         }
263         
264         if (lp_host_msdfs())
265                 capabilities |= CAP_DFS;
266         
267         if (lp_security() >= SEC_USER) secword |= 1;
268         if (global_encrypted_passwords_negotiated) secword |= 2;
269         
270         set_message(outbuf,17,0,True);
271         
272         CVAL(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                         get_challange(p);
290                 }
291                 SSVALS(outbuf,smb_vwv16+1,8);
292                 p += 8;
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 /****************************************************************************
400   reply to a negprot
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   START_PROFILE(SMBnegprot);
414
415   p = smb_buf(inbuf)+1;
416   while (p < (smb_buf(inbuf) + bcc))
417     { 
418       Index++;
419       DEBUG(3,("Requested protocol [%s]\n",p));
420       if (strcsequal(p,"Windows for Workgroups 3.1a"))
421         arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
422       else if (strcsequal(p,"DOS LM1.2X002"))
423         arch &= ( ARCH_WFWG | ARCH_WIN95 );
424       else if (strcsequal(p,"DOS LANMAN2.1"))
425         arch &= ( ARCH_WFWG | ARCH_WIN95 );
426       else if (strcsequal(p,"NT LM 0.12"))
427         arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
428       else if (strcsequal(p,"LANMAN2.1"))
429         arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
430       else if (strcsequal(p,"LM1.2X002"))
431         arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
432       else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
433         arch &= ARCH_WINNT;
434       else if (strcsequal(p,"XENIX CORE"))
435         arch &= ( ARCH_WINNT | ARCH_OS2 );
436       else if (strcsequal(p,"Samba")) {
437         arch = ARCH_SAMBA;
438         break;
439       }
440  
441       p += strlen(p) + 2;
442     }
443     
444   switch ( arch ) {
445   case ARCH_SAMBA:
446     set_remote_arch(RA_SAMBA);
447     break;
448   case ARCH_WFWG:
449     set_remote_arch(RA_WFWG);
450     break;
451   case ARCH_WIN95:
452     set_remote_arch(RA_WIN95);
453     break;
454   case ARCH_WINNT:
455    if(SVAL(inbuf,smb_flg2)==FLAGS2_WIN2K_SIGNATURE)
456      set_remote_arch(RA_WIN2K);
457    else
458      set_remote_arch(RA_WINNT);
459     break;
460   case ARCH_WIN2K:
461     set_remote_arch(RA_WIN2K);
462     break;
463   case ARCH_OS2:
464     set_remote_arch(RA_OS2);
465     break;
466   default:
467     set_remote_arch(RA_UNKNOWN);
468     break;
469   }
470  
471   /* possibly reload - change of architecture */
472   reload_services(True);      
473     
474   /* Check for protocols, most desirable first */
475   for (protocol = 0; supported_protocols[protocol].proto_name; protocol++)
476     {
477       p = smb_buf(inbuf)+1;
478       Index = 0;
479       if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) &&
480           (supported_protocols[protocol].protocol_level >= lp_minprotocol()))
481         while (p < (smb_buf(inbuf) + bcc))
482           { 
483             if (strequal(p,supported_protocols[protocol].proto_name))
484               choice = Index;
485             Index++;
486             p += strlen(p) + 2;
487           }
488       if(choice != -1)
489         break;
490     }
491   
492   SSVAL(outbuf,smb_vwv0,choice);
493   if(choice != -1) {
494     extern fstring remote_proto;
495     fstrcpy(remote_proto,supported_protocols[protocol].short_name);
496     reload_services(True);          
497     outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf);
498     DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
499   }
500   else {
501     DEBUG(0,("No protocol supported !\n"));
502   }
503   SSVAL(outbuf,smb_vwv0,choice);
504   
505   DEBUG( 5, ( "negprot index=%d\n", choice ) );
506
507   END_PROFILE(SMBnegprot);
508   return(outsize);
509 }
510