253dc1d7a4465475d12d092c0700403687e974ce
[ira/wip.git] / source / smb_server / 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 /* initialise the auth_context for this server and return the cryptkey */
24 static void get_challenge(struct server_context *smb, char buff[8]) 
25 {
26         NTSTATUS nt_status;
27         const uint8 *cryptkey;
28
29         /* muliple negprots are not premitted */
30         if (smb->negotiate.auth_context) {
31                 DEBUG(3,("get challenge: is this a secondary negprot?  auth_context is non-NULL!\n"));
32                 smb_panic("secondary negprot");
33         }
34
35         DEBUG(10, ("get challenge: creating negprot_global_auth_context\n"));
36
37         nt_status = make_auth_context_subsystem(&smb->negotiate.auth_context);
38
39         if (!NT_STATUS_IS_OK(nt_status)) {
40                 DEBUG(0, ("make_auth_context_subsystem returned %s", nt_errstr(nt_status)));
41                 smb_panic("cannot make_negprot_global_auth_context!\n");
42         }
43
44         DEBUG(10, ("get challenge: getting challenge\n"));
45         cryptkey = smb->negotiate.auth_context->get_ntlm_challenge(smb->negotiate.auth_context);
46         memcpy(buff, cryptkey, 8);
47 }
48
49 /****************************************************************************
50  Reply for the core protocol.
51 ****************************************************************************/
52 static void reply_corep(struct request_context *req, uint16 choice)
53 {
54         req_setup_reply(req, 1, 0);
55
56         SSVAL(req->out.vwv, VWV(0), choice);
57
58         req->smb->negotiate.protocol = PROTOCOL_CORE;
59
60         req_send_reply(req);
61 }
62
63 /****************************************************************************
64  Reply for the coreplus protocol.
65 this is quite incomplete - we only fill in a small part of the reply, but as nobody uses
66 this any more it probably doesn't matter
67 ****************************************************************************/
68 static void reply_coreplus(struct request_context *req, uint16 choice)
69 {
70         uint16 raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
71
72         req_setup_reply(req, 13, 0);
73
74         /* Reply, SMBlockread, SMBwritelock supported. */
75         SCVAL(req->out.hdr,HDR_FLG,
76               CVAL(req->out.hdr, HDR_FLG) | FLAG_SUPPORT_LOCKREAD);
77
78         SSVAL(req->out.vwv, VWV(0), choice);
79         SSVAL(req->out.vwv, VWV(1), 0x1); /* user level security, don't encrypt */      
80
81         /* tell redirector we support
82            readbraw and writebraw (possibly) */
83         SSVAL(req->out.vwv, VWV(5), raw); 
84
85         req->smb->negotiate.protocol = PROTOCOL_COREPLUS;
86
87         req_send_reply(req);
88 }
89
90 /****************************************************************************
91  Reply for the lanman 1.0 protocol.
92 ****************************************************************************/
93 static void reply_lanman1(struct request_context *req, uint16 choice)
94 {
95         int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
96         int secword=0;
97         time_t t = req->request_time.tv_sec;
98
99         req->smb->negotiate.encrypted_passwords = lp_encrypted_passwords();
100
101         if (lp_security() != SEC_SHARE)
102                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
103
104         if (req->smb->negotiate.encrypted_passwords)
105                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
106
107         req->smb->negotiate.protocol = PROTOCOL_LANMAN1;
108
109         req_setup_reply(req, 13, req->smb->negotiate.encrypted_passwords ? 8 : 0);
110
111         /* SMBlockread, SMBwritelock supported. */
112         SCVAL(req->out.hdr,HDR_FLG,
113               CVAL(req->out.hdr, HDR_FLG) | FLAG_SUPPORT_LOCKREAD);
114
115         SSVAL(req->out.vwv, VWV(0), choice);
116         SSVAL(req->out.vwv, VWV(1), secword); 
117         SSVAL(req->out.vwv, VWV(2), req->smb->negotiate.max_recv);
118         SSVAL(req->out.vwv, VWV(3), lp_maxmux());
119         SSVAL(req->out.vwv, VWV(4), 1);
120         SSVAL(req->out.vwv, VWV(5), raw); 
121         SIVAL(req->out.vwv, VWV(6), req->smb->pid);
122         srv_push_dos_date(req->smb, req->out.vwv, VWV(8), t);
123         SSVAL(req->out.vwv, VWV(10), req->smb->negotiate.zone_offset/60);
124
125         /* Create a token value and add it to the outgoing packet. */
126         if (req->smb->negotiate.encrypted_passwords) {
127                 SSVAL(req->out.vwv, VWV(11), 8);
128                 get_challenge(req->smb, req->out.data);
129         }
130
131         req_send_reply(req);    
132 }
133
134 /****************************************************************************
135  Reply for the lanman 2.0 protocol.
136 ****************************************************************************/
137 static void reply_lanman2(struct request_context *req, uint16 choice)
138 {
139         int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
140         int secword=0;
141         time_t t = req->request_time.tv_sec;
142
143         req->smb->negotiate.encrypted_passwords = lp_encrypted_passwords();
144   
145         if (lp_security() != SEC_SHARE)
146                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
147
148         if (req->smb->negotiate.encrypted_passwords)
149                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
150
151         req->smb->negotiate.protocol = PROTOCOL_LANMAN2;
152
153         req_setup_reply(req, 13, 0);
154
155         SSVAL(req->out.vwv, VWV(0), choice);
156         SSVAL(req->out.vwv, VWV(1), secword); 
157         SSVAL(req->out.vwv, VWV(2), req->smb->negotiate.max_recv);
158         SSVAL(req->out.vwv, VWV(3), lp_maxmux());
159         SSVAL(req->out.vwv, VWV(4), 1);
160         SSVAL(req->out.vwv, VWV(5), raw); 
161         SIVAL(req->out.vwv, VWV(6), req->smb->pid);
162         srv_push_dos_date(req->smb, req->out.vwv, VWV(8), t);
163         SSVAL(req->out.vwv, VWV(10), req->smb->negotiate.zone_offset/60);
164
165         /* Create a token value and add it to the outgoing packet. */
166         if (req->smb->negotiate.encrypted_passwords) {
167                 SSVAL(req->out.vwv, VWV(11), 8);
168                 req_grow_data(req, 8);
169                 get_challenge(req->smb, req->out.data);
170         }
171
172         req_push_str(req, NULL, lp_workgroup(), -1, STR_TERMINATE);
173
174         req_send_reply(req);
175 }
176
177
178 #if 0
179 /****************************************************************************
180  Generate the spnego negprot reply blob. Return the number of bytes used.
181 ****************************************************************************/
182 static DATA_BLOB negprot_spnego(struct server_context *smb)
183 {
184         DATA_BLOB blob;
185         uint8 guid[16];
186         const char *OIDs_krb5[] = {OID_KERBEROS5,
187                                    OID_KERBEROS5_OLD,
188                                    OID_NTLMSSP,
189                                    NULL};
190         const char *OIDs_plain[] = {OID_NTLMSSP, NULL};
191         char *principal;
192
193         smb->negotiate.spnego_negotiated = True;
194
195         memset(guid, 0, 16);
196         safe_strcpy((char *)guid, lp_netbios_name(), 16);
197         strlower((char *)guid);
198
199 #if 0
200         /* strangely enough, NT does not send the single OID NTLMSSP when
201            not a ADS member, it sends no OIDs at all
202
203            we can't do this until we teach our sesssion setup parser to know
204            about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)
205         */
206         if (lp_security() != SEC_ADS) {
207                 memcpy(p, guid, 16);
208                 return 16;
209         }
210 #endif
211         if (lp_security() != SEC_ADS) {
212                 blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE");
213         } else {
214                 asprintf(&principal, "%s$@%s", guid, lp_realm());
215                 blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal);
216                 free(principal);
217         }
218
219         return blob;
220 }
221 #endif
222
223 /****************************************************************************
224  Reply for the nt protocol.
225 ****************************************************************************/
226 static void reply_nt1(struct request_context *req, uint16 choice)
227 {
228         /* dual names + lock_and_read + nt SMBs + remote API calls */
229         int capabilities;
230         int secword=0;
231         time_t t = req->request_time.tv_sec;
232         NTTIME nttime;
233         BOOL negotiate_spnego = False;
234
235         unix_to_nt_time(&nttime, t);
236
237         capabilities = 
238                 CAP_NT_FIND | CAP_LOCK_AND_READ | 
239                 CAP_LEVEL_II_OPLOCKS | CAP_NT_SMBS | CAP_RPC_REMOTE_APIS;
240
241         req->smb->negotiate.encrypted_passwords = lp_encrypted_passwords();
242
243         /* do spnego in user level security if the client
244            supports it and we can do encrypted passwords */
245         
246         if (req->smb->negotiate.encrypted_passwords && 
247             (lp_security() != SEC_SHARE) &&
248             lp_use_spnego() &&
249             (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
250 /* REWRITE              negotiate_spnego = True; 
251                 capabilities |= CAP_EXTENDED_SECURITY;
252 */
253         }
254         
255         if (lp_unix_extensions()) {
256                 capabilities |= CAP_UNIX;
257         }
258         
259         if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) {
260                 capabilities |= CAP_LARGE_READX | CAP_LARGE_WRITEX | CAP_W2K_SMBS;
261         }
262         
263         if (SMB_OFF_T_BITS >= 64) {
264                 capabilities |= CAP_LARGE_FILES;
265         }
266
267         if (lp_readraw() && lp_writeraw()) {
268                 capabilities |= CAP_RAW_MODE;
269         }
270         
271         /* allow for disabling unicode */
272         if (lp_unicode()) {
273                 capabilities |= CAP_UNICODE;
274         }
275
276         if (lp_nt_status_support()) {
277                 capabilities |= CAP_STATUS32;
278         }
279         
280         if (lp_host_msdfs()) {
281                 capabilities |= CAP_DFS;
282         }
283         
284         if (lp_security() != SEC_SHARE) {
285                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
286         }
287
288         if (req->smb->negotiate.encrypted_passwords) {
289                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
290         }
291
292         req->smb->signing.signing_state = lp_server_signing();
293
294         switch (req->smb->signing.signing_state) {
295         case SMB_SIGNING_OFF:
296                 break;
297         case SMB_SIGNING_SUPPORTED:
298                 secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
299                 break;
300         case SMB_SIGNING_REQUIRED:
301                 secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED |
302                         NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
303                 break;
304         }
305         
306         req->smb->negotiate.protocol = PROTOCOL_NT1;
307
308         req_setup_reply(req, 17, 0);
309         
310         SSVAL(req->out.vwv, VWV(0), choice);
311         SCVAL(req->out.vwv, VWV(1), secword);
312
313         /* notice the strange +1 on vwv here? That's because
314            this is the one and only SMB packet that is malformed in
315            the specification - all the command words after the secword
316            are offset by 1 byte */
317         SSVAL(req->out.vwv+1, VWV(1), lp_maxmux());
318         SSVAL(req->out.vwv+1, VWV(2), 1); /* num vcs */
319         SIVAL(req->out.vwv+1, VWV(3), req->smb->negotiate.max_recv);
320         SIVAL(req->out.vwv+1, VWV(5), 0x10000); /* raw size. full 64k */
321         SIVAL(req->out.vwv+1, VWV(7), req->smb->pid); /* session key */
322         SIVAL(req->out.vwv+1, VWV(9), capabilities);
323         push_nttime(req->out.vwv+1, VWV(11), &nttime);
324         SSVALS(req->out.vwv+1,VWV(15), req->smb->negotiate.zone_offset/60);
325         
326         if (!negotiate_spnego) {
327                 /* Create a token value and add it to the outgoing packet. */
328                 if (req->smb->negotiate.encrypted_passwords) {
329                         req_grow_data(req, 8);
330                         /* note that we do not send a challenge at all if
331                            we are using plaintext */
332                         get_challenge(req->smb, req->out.ptr);
333                         req->out.ptr += 8;
334                         SCVAL(req->out.vwv+1, VWV(16), 8);
335                 }
336                 req_push_str(req, NULL, lp_workgroup(), -1, STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
337                 req_push_str(req, NULL, lp_netbios_name(), -1, STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
338                 DEBUG(3,("not using SPNEGO\n"));
339         } else {
340 #if 0
341                 DATA_BLOB blob = negprot_spnego(req->smb);
342
343                 req_grow_data(req, blob.length);
344                 memcpy(req->out.ptr, blob.data, blob.length);
345                 DEBUG(3,("using SPNEGO\n"));
346 #else
347                 exit_server(req->smb, "no SPNEGO please");
348 #endif
349         }
350         
351         req_send_reply_nosign(req);     
352 }
353
354 /* these are the protocol lists used for auto architecture detection:
355
356 WinNT 3.51:
357 protocol [PC NETWORK PROGRAM 1.0]
358 protocol [XENIX CORE]
359 protocol [MICROSOFT NETWORKS 1.03]
360 protocol [LANMAN1.0]
361 protocol [Windows for Workgroups 3.1a]
362 protocol [LM1.2X002]
363 protocol [LANMAN2.1]
364 protocol [NT LM 0.12]
365
366 Win95:
367 protocol [PC NETWORK PROGRAM 1.0]
368 protocol [XENIX CORE]
369 protocol [MICROSOFT NETWORKS 1.03]
370 protocol [LANMAN1.0]
371 protocol [Windows for Workgroups 3.1a]
372 protocol [LM1.2X002]
373 protocol [LANMAN2.1]
374 protocol [NT LM 0.12]
375
376 Win2K:
377 protocol [PC NETWORK PROGRAM 1.0]
378 protocol [LANMAN1.0]
379 protocol [Windows for Workgroups 3.1a]
380 protocol [LM1.2X002]
381 protocol [LANMAN2.1]
382 protocol [NT LM 0.12]
383
384 OS/2:
385 protocol [PC NETWORK PROGRAM 1.0]
386 protocol [XENIX CORE]
387 protocol [LANMAN1.0]
388 protocol [LM1.2X002]
389 protocol [LANMAN2.1]
390 */
391
392 /*
393   * Modified to recognize the architecture of the remote machine better.
394   *
395   * This appears to be the matrix of which protocol is used by which
396   * MS product.
397        Protocol                       WfWg    Win95   WinNT  Win2K  OS/2
398        PC NETWORK PROGRAM 1.0          1       1       1      1      1
399        XENIX CORE                                      2             2
400        MICROSOFT NETWORKS 3.0          2       2       
401        DOS LM1.2X002                   3       3       
402        MICROSOFT NETWORKS 1.03                         3
403        DOS LANMAN2.1                   4       4       
404        LANMAN1.0                                       4      2      3
405        Windows for Workgroups 3.1a     5       5       5      3
406        LM1.2X002                                       6      4      4
407        LANMAN2.1                                       7      5      5
408        NT LM 0.12                              6       8      6
409   *
410   *  tim@fsg.com 09/29/95
411   *  Win2K added by matty 17/7/99
412   */
413   
414 #define ARCH_WFWG     0x3      /* This is a fudge because WfWg is like Win95 */
415 #define ARCH_WIN95    0x2
416 #define ARCH_WINNT    0x4
417 #define ARCH_WIN2K    0xC      /* Win2K is like NT */
418 #define ARCH_OS2      0x14     /* Again OS/2 is like NT */
419 #define ARCH_SAMBA    0x20
420  
421 #define ARCH_ALL      0x3F
422  
423 /* List of supported protocols, most desired first */
424 static const struct {
425         const char *proto_name;
426         const char *short_name;
427         void (*proto_reply_fn)(struct request_context *req, uint16 choice);
428         int protocol_level;
429 } supported_protocols[] = {
430         {"NT LANMAN 1.0",           "NT1",      reply_nt1,      PROTOCOL_NT1},
431         {"NT LM 0.12",              "NT1",      reply_nt1,      PROTOCOL_NT1},
432         {"LM1.2X002",               "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
433         {"Samba",                   "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
434         {"DOS LM1.2X002",           "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
435         {"LANMAN1.0",               "LANMAN1",  reply_lanman1,  PROTOCOL_LANMAN1},
436         {"MICROSOFT NETWORKS 3.0",  "LANMAN1",  reply_lanman1,  PROTOCOL_LANMAN1},
437         {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
438         {"PC NETWORK PROGRAM 1.0",  "CORE",     reply_corep,    PROTOCOL_CORE}, 
439         {NULL,NULL,NULL,0},
440 };
441
442 /****************************************************************************
443  Reply to a negprot.
444 ****************************************************************************/
445
446 void reply_negprot(struct request_context *req)
447 {
448         int Index=0;
449         int choice = -1;
450         int protocol;
451         char *p;
452         int arch = ARCH_ALL;
453
454         if (req->smb->negotiate.done_negprot) {
455                 exit_server(req->smb, "multiple negprot's are not permitted");
456         }
457         req->smb->negotiate.done_negprot = True;
458
459         p = req->in.data + 1;
460
461         while (p < req->in.data + req->in.data_size) { 
462                 Index++;
463                 DEBUG(3,("Requested protocol [%s]\n",p));
464                 if (strcmp(p,"Windows for Workgroups 3.1a") == 0)
465                         arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
466                 else if (strcmp(p,"DOS LM1.2X002") == 0)
467                         arch &= ( ARCH_WFWG | ARCH_WIN95 );
468                 else if (strcmp(p,"DOS LANMAN2.1") == 0)
469                         arch &= ( ARCH_WFWG | ARCH_WIN95 );
470                 else if (strcmp(p,"NT LM 0.12") == 0)
471                         arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
472                 else if (strcmp(p,"LANMAN2.1") == 0)
473                         arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
474                 else if (strcmp(p,"LM1.2X002") == 0)
475                         arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
476                 else if (strcmp(p,"MICROSOFT NETWORKS 1.03") == 0)
477                         arch &= ARCH_WINNT;
478                 else if (strcmp(p,"XENIX CORE") == 0)
479                         arch &= ( ARCH_WINNT | ARCH_OS2 );
480                 else if (strcmp(p,"Samba") == 0) {
481                         arch = ARCH_SAMBA;
482                         break;
483                 }
484  
485                 p += strlen(p) + 2;
486         }
487     
488         switch (arch) {
489                 case ARCH_SAMBA:
490                         set_remote_arch(req->smb, RA_SAMBA);
491                         break;
492                 case ARCH_WFWG:
493                         set_remote_arch(req->smb, RA_WFWG);
494                         break;
495                 case ARCH_WIN95:
496                         set_remote_arch(req->smb, RA_WIN95);
497                         break;
498                 case ARCH_WINNT:
499                         if (req->flags2==FLAGS2_WIN2K_SIGNATURE)
500                                 set_remote_arch(req->smb, RA_WIN2K);
501                         else
502                                 set_remote_arch(req->smb, RA_WINNT);
503                         break;
504                 case ARCH_WIN2K:
505                         set_remote_arch(req->smb, RA_WIN2K);
506                         break;
507                 case ARCH_OS2:
508                         set_remote_arch(req->smb, RA_OS2);
509                         break;
510                 default:
511                         set_remote_arch(req->smb, RA_UNKNOWN);
512                 break;
513         }
514  
515         /* possibly reload - change of architecture */
516         reload_services(req->smb, True);      
517     
518         /* Check for protocols, most desirable first */
519         for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) {
520                 p = req->in.data+1;
521                 Index = 0;
522                 if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) &&
523                                 (supported_protocols[protocol].protocol_level >= lp_minprotocol()))
524                         while (p < (req->in.data + req->in.data_size)) { 
525                                 if (strequal(p,supported_protocols[protocol].proto_name))
526                                         choice = Index;
527                                 Index++;
528                                 p += strlen(p) + 2;
529                         }
530                 if(choice != -1)
531                         break;
532         }
533   
534         if(choice != -1) {
535                 sub_set_remote_proto(supported_protocols[protocol].short_name);
536                 reload_services(req->smb, True);
537                 supported_protocols[protocol].proto_reply_fn(req, choice);
538                 DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
539         } else {
540                 DEBUG(0,("No protocol supported !\n"));
541         }
542   
543         DEBUG(5,("negprot index=%d\n", choice));
544 }