reading in smb server domain name from SMBnegprot response
[samba.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 DEBUGLEVEL;
25 extern int Protocol;
26 extern int max_recv;
27 extern fstring global_myworkgroup;
28 extern fstring remote_machine;
29 extern pstring myhostname;
30 extern dfs_internal dfs_struct;
31
32 /****************************************************************************
33 reply for the core protocol
34 ****************************************************************************/
35 static int reply_corep(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 *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 *outbuf)
68 {
69   int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
70   int secword=0;
71   BOOL doencrypt = SMBENCRYPT();
72   time_t t = time(NULL);
73
74   if (lp_security()>=SEC_USER) secword |= 1;
75   if (doencrypt) secword |= 2;
76
77   set_message(outbuf,13,doencrypt?8:0,True);
78   SSVAL(outbuf,smb_vwv1,secword); 
79   /* Create a token value and add it to the outgoing packet. */
80   if (doencrypt) 
81     generate_next_challenge(smb_buf(outbuf));
82
83   Protocol = PROTOCOL_LANMAN1;
84
85   /* Reply, SMBlockread, SMBwritelock supported. */
86   SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
87   SSVAL(outbuf,smb_vwv2,max_recv);
88   SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
89   SSVAL(outbuf,smb_vwv4,1);
90   SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
91                                  readbraw writebraw (possibly) */
92   SIVAL(outbuf,smb_vwv6,getpid());
93   SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
94
95   put_dos_date(outbuf,smb_vwv8,t);
96
97   return (smb_len(outbuf)+4);
98 }
99
100
101 /****************************************************************************
102 reply for the lanman 2.0 protocol
103 ****************************************************************************/
104 static int reply_lanman2(char *outbuf)
105 {
106   int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
107   int secword=0;
108   BOOL doencrypt = SMBENCRYPT();
109   time_t t = time(NULL);
110   struct cli_state *cli = NULL;
111   char cryptkey[8];
112   char crypt_len = 0;
113
114   if (lp_security() == SEC_SERVER) {
115           cli = server_cryptkey();
116   }
117
118   if (cli) {
119           DEBUG(3,("using password server validation\n"));
120           doencrypt = ((cli->sec_mode & 2) != 0);
121   }
122
123   if (lp_security()>=SEC_USER) secword |= 1;
124   if (doencrypt) secword |= 2;
125
126   if (doencrypt) {
127           crypt_len = 8;
128           if (!cli) {
129                   generate_next_challenge(cryptkey);
130           } else {
131                   memcpy(cryptkey, cli->cryptkey, 8);
132                   set_challenge(cli->cryptkey);
133           }
134   }
135
136   set_message(outbuf,13,crypt_len,True);
137   SSVAL(outbuf,smb_vwv1,secword); 
138   SIVAL(outbuf,smb_vwv6,getpid());
139   if (doencrypt) 
140           memcpy(smb_buf(outbuf), cryptkey, 8);
141
142   Protocol = PROTOCOL_LANMAN2;
143
144   /* Reply, SMBlockread, SMBwritelock supported. */
145   SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
146   SSVAL(outbuf,smb_vwv2,max_recv);
147   SSVAL(outbuf,smb_vwv3,lp_maxmux()); 
148   SSVAL(outbuf,smb_vwv4,1);
149   SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
150   SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
151   put_dos_date(outbuf,smb_vwv8,t);
152
153   return (smb_len(outbuf)+4);
154 }
155
156
157 /****************************************************************************
158 reply for the nt protocol
159 ****************************************************************************/
160 static int reply_nt1(char *outbuf)
161 {
162   /* dual names + lock_and_read + nt SMBs + remote API calls */
163   int secword=0;
164   BOOL doencrypt = SMBENCRYPT();
165   time_t t = time(NULL);
166   int data_len;
167   struct cli_state *cli = NULL;
168   char cryptkey[8];
169   char crypt_len = 0;
170
171   int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ;
172
173         if (lp_nt_smb_support())
174         {
175                 capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS;
176         }
177
178         if (SMB_OFF_T_BITS == 64)
179         {
180                 capabilities |= CAP_LARGE_FILES;
181         }
182
183         if (dfs_struct.ready==True)
184         {
185                 capabilities |= CAP_DFS;
186         }
187
188 /*
189   other valid capabilities which we may support at some time...
190                      CAP_LARGE_READX|CAP_STATUS32|CAP_LEVEL_II_OPLOCKS;
191  */
192
193         if (lp_security() == SEC_SERVER)
194         {
195                 cli = server_cryptkey();
196         }
197
198   if (cli) {
199           DEBUG(3,("using password server validation\n"));
200           doencrypt = ((cli->sec_mode & 2) != 0);
201   }
202
203   if (doencrypt) {
204           crypt_len = 8;
205           if (!cli) {
206                   generate_next_challenge(cryptkey);
207           } else {
208                   memcpy(cryptkey, cli->cryptkey, 8);
209                   set_challenge(cli->cryptkey);
210           }
211   }
212
213   if (lp_readraw() && lp_writeraw()) {
214           capabilities |= CAP_RAW_MODE;
215   }
216
217   if (lp_security() >= SEC_USER) secword |= 1;
218   if (doencrypt) secword |= 2;
219
220   /* decide where (if) to put the encryption challenge, and
221      follow it with the OEM'd domain name in Unicode.
222    */
223   data_len = crypt_len + (strlen(global_myworkgroup)+1)*2;
224
225   set_message(outbuf,17,data_len,True);
226   ascii_to_unibuf(smb_buf(outbuf)+crypt_len, global_myworkgroup,
227                   (strlen(global_myworkgroup)+1)*2);
228
229   CVAL(outbuf,smb_vwv1) = secword;
230   SSVALS(outbuf,smb_vwv16+1,crypt_len);
231   if (doencrypt) 
232           memcpy(smb_buf(outbuf), cryptkey, 8);
233
234   Protocol = PROTOCOL_NT1;
235
236   SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
237   SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
238   SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
239   SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
240   SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */
241   SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
242   put_long_date(outbuf+smb_vwv11+1,t);
243   SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
244   SSVAL(outbuf,smb_vwv17,data_len); /* length of challenge+domain strings */
245
246   return (smb_len(outbuf)+4);
247 }
248
249 /* these are the protocol lists used for auto architecture detection:
250
251 WinNT 3.51:
252 protocol [PC NETWORK PROGRAM 1.0]
253 protocol [XENIX CORE]
254 protocol [MICROSOFT NETWORKS 1.03]
255 protocol [LANMAN1.0]
256 protocol [Windows for Workgroups 3.1a]
257 protocol [LM1.2X002]
258 protocol [LANMAN2.1]
259 protocol [NT LM 0.12]
260
261 Win95:
262 protocol [PC NETWORK PROGRAM 1.0]
263 protocol [XENIX CORE]
264 protocol [MICROSOFT NETWORKS 1.03]
265 protocol [LANMAN1.0]
266 protocol [Windows for Workgroups 3.1a]
267 protocol [LM1.2X002]
268 protocol [LANMAN2.1]
269 protocol [NT LM 0.12]
270
271 OS/2:
272 protocol [PC NETWORK PROGRAM 1.0]
273 protocol [XENIX CORE]
274 protocol [LANMAN1.0]
275 protocol [LM1.2X002]
276 protocol [LANMAN2.1]
277 */
278
279 /*
280   * Modified to recognize the architecture of the remote machine better.
281   *
282   * This appears to be the matrix of which protocol is used by which
283   * MS product.
284        Protocol                       WfWg    Win95   WinNT  OS/2
285        PC NETWORK PROGRAM 1.0          1       1       1      1
286        XENIX CORE                                      2      2
287        MICROSOFT NETWORKS 3.0          2       2       
288        DOS LM1.2X002                   3       3       
289        MICROSOFT NETWORKS 1.03                         3
290        DOS LANMAN2.1                   4       4       
291        LANMAN1.0                                       4      3
292        Windows for Workgroups 3.1a     5       5       5
293        LM1.2X002                                       6      4
294        LANMAN2.1                                       7      5
295        NT LM 0.12                              6       8
296   *
297   *  tim@fsg.com 09/29/95
298   */
299   
300 #define ARCH_WFWG     0x3      /* This is a fudge because WfWg is like Win95 */
301 #define ARCH_WIN95    0x2
302 #define ARCH_OS2      0xC      /* Again OS/2 is like NT */
303 #define ARCH_WINNT    0x8
304 #define ARCH_SAMBA    0x10
305  
306 #define ARCH_ALL      0x1F
307  
308 /* List of supported protocols, most desired first */
309 static struct {
310   char *proto_name;
311   char *short_name;
312   int (*proto_reply_fn)(char *);
313   int protocol_level;
314 } supported_protocols[] = {
315   {"NT LANMAN 1.0",           "NT1",      reply_nt1,      PROTOCOL_NT1},
316   {"NT LM 0.12",              "NT1",      reply_nt1,      PROTOCOL_NT1},
317   {"LM1.2X002",               "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
318   {"Samba",                   "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
319   {"DOS LM1.2X002",           "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
320   {"LANMAN1.0",               "LANMAN1",  reply_lanman1,  PROTOCOL_LANMAN1},
321   {"MICROSOFT NETWORKS 3.0",  "LANMAN1",  reply_lanman1,  PROTOCOL_LANMAN1},
322   {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
323   {"PC NETWORK PROGRAM 1.0",  "CORE",     reply_corep,    PROTOCOL_CORE}, 
324   {NULL,NULL},
325 };
326
327
328 /****************************************************************************
329   reply to a negprot
330 ****************************************************************************/
331 int reply_negprot(connection_struct *conn, 
332                   char *inbuf,char *outbuf, int dum_size, 
333                   int dum_buffsize)
334 {
335   int outsize = set_message(outbuf,1,0,True);
336   int Index=0;
337   int choice= -1;
338   int protocol;
339   char *p;
340   int bcc = SVAL(smb_buf(inbuf),-2);
341   int arch = ARCH_ALL;
342
343   p = smb_buf(inbuf)+1;
344   while (p < (smb_buf(inbuf) + bcc))
345     { 
346       Index++;
347       DEBUG(3,("Requested protocol [%s]\n",p));
348       if (strcsequal(p,"Windows for Workgroups 3.1a"))
349         arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT );
350       else if (strcsequal(p,"DOS LM1.2X002"))
351         arch &= ( ARCH_WFWG | ARCH_WIN95 );
352       else if (strcsequal(p,"DOS LANMAN2.1"))
353         arch &= ( ARCH_WFWG | ARCH_WIN95 );
354       else if (strcsequal(p,"NT LM 0.12"))
355         arch &= ( ARCH_WIN95 | ARCH_WINNT );
356       else if (strcsequal(p,"LANMAN2.1"))
357         arch &= ( ARCH_WINNT | ARCH_OS2 );
358       else if (strcsequal(p,"LM1.2X002"))
359         arch &= ( ARCH_WINNT | ARCH_OS2 );
360       else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
361         arch &= ARCH_WINNT;
362       else if (strcsequal(p,"XENIX CORE"))
363         arch &= ( ARCH_WINNT | ARCH_OS2 );
364       else if (strcsequal(p,"Samba")) {
365         arch = ARCH_SAMBA;
366         break;
367       }
368  
369       p += strlen(p) + 2;
370     }
371     
372   switch ( arch ) {
373   case ARCH_SAMBA:
374     set_remote_arch(RA_SAMBA);
375     break;
376   case ARCH_WFWG:
377     set_remote_arch(RA_WFWG);
378     break;
379   case ARCH_WIN95:
380     set_remote_arch(RA_WIN95);
381     break;
382   case ARCH_WINNT:
383     set_remote_arch(RA_WINNT);
384     break;
385   case ARCH_OS2:
386     set_remote_arch(RA_OS2);
387     break;
388   default:
389     set_remote_arch(RA_UNKNOWN);
390     break;
391   }
392  
393   /* possibly reload - change of architecture */
394   reload_services(True);      
395     
396   /* a special case to stop password server loops */
397   if (Index == 1 && strequal(remote_machine,myhostname) && 
398       (lp_security()==SEC_SERVER || lp_security()==SEC_DOMAIN))
399     exit_server("Password server loop!");
400   
401   /* Check for protocols, most desirable first */
402   for (protocol = 0; supported_protocols[protocol].proto_name; protocol++)
403     {
404       p = smb_buf(inbuf)+1;
405       Index = 0;
406       if (lp_maxprotocol() >= supported_protocols[protocol].protocol_level)
407         while (p < (smb_buf(inbuf) + bcc))
408           { 
409             if (strequal(p,supported_protocols[protocol].proto_name))
410               choice = Index;
411             Index++;
412             p += strlen(p) + 2;
413           }
414       if(choice != -1)
415         break;
416     }
417   
418   SSVAL(outbuf,smb_vwv0,choice);
419   if(choice != -1) {
420     extern fstring remote_proto;
421     fstrcpy(remote_proto,supported_protocols[protocol].short_name);
422     reload_services(True);          
423     outsize = supported_protocols[protocol].proto_reply_fn(outbuf);
424     DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
425   }
426   else {
427     DEBUG(0,("No protocol supported !\n"));
428   }
429   SSVAL(outbuf,smb_vwv0,choice);
430   
431   DEBUG( 5, ( "negprot index=%d\n", choice ) );
432
433   return(outsize);
434 }