Make better use of the ads_init() function to get the kerberos relam etc.
[tprouty/samba.git] / source / 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);
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             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
231                 negotiate_spnego = True;
232                 capabilities |= CAP_EXTENDED_SECURITY;
233         }
234         
235         capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
236         
237         if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) {
238                 capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
239         }
240         
241         if (SMB_OFF_T_BITS == 64) {
242                 capabilities |= CAP_LARGE_FILES;
243         }
244         
245         if (lp_readraw() && lp_writeraw()) {
246                 capabilities |= CAP_RAW_MODE;
247         }
248         
249         /* allow for disabling unicode */
250         if (lp_unicode()) {
251                 capabilities |= CAP_UNICODE;
252         }
253         
254         if (lp_host_msdfs())
255                 capabilities |= CAP_DFS;
256         
257         if (lp_security() >= SEC_USER) secword |= 1;
258         if (global_encrypted_passwords_negotiated) secword |= 2;
259         
260         set_message(outbuf,17,0,True);
261         
262         CVAL(outbuf,smb_vwv1) = secword;
263         
264         Protocol = PROTOCOL_NT1;
265         
266         SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
267         SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
268         SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
269         SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
270         SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
271         SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
272         put_long_date(outbuf+smb_vwv11+1,t);
273         SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
274         
275         p = q = smb_buf(outbuf);
276         if (!negotiate_spnego) {
277                 if (global_encrypted_passwords_negotiated) { 
278                         if (!make_auth_info_subsystem(&negprot_global_auth_info)) {
279                                 smb_panic("cannot make_negprot_global_auth_info!\n");
280                         }
281                         cryptkey = auth_get_challenge(negprot_global_auth_info);
282                         memcpy(p, cryptkey.data, 8);
283                         data_blob_free(&cryptkey);
284                 }
285                 SSVALS(outbuf,smb_vwv16+1,8);
286                 p += 8;
287                 p += srvstr_push(outbuf, p, global_myworkgroup, -1, 
288                                  STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
289                 DEBUG(3,("not using SPNEGO\n"));
290         } else {
291                 int len = negprot_spnego(p);
292                 
293                 SSVALS(outbuf,smb_vwv16+1,len);
294                 p += len;
295                 DEBUG(3,("using SPNEGO\n"));
296         }
297         
298         SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
299         set_message_end(outbuf, p);
300         
301         return (smb_len(outbuf)+4);
302 }
303
304 /* these are the protocol lists used for auto architecture detection:
305
306 WinNT 3.51:
307 protocol [PC NETWORK PROGRAM 1.0]
308 protocol [XENIX CORE]
309 protocol [MICROSOFT NETWORKS 1.03]
310 protocol [LANMAN1.0]
311 protocol [Windows for Workgroups 3.1a]
312 protocol [LM1.2X002]
313 protocol [LANMAN2.1]
314 protocol [NT LM 0.12]
315
316 Win95:
317 protocol [PC NETWORK PROGRAM 1.0]
318 protocol [XENIX CORE]
319 protocol [MICROSOFT NETWORKS 1.03]
320 protocol [LANMAN1.0]
321 protocol [Windows for Workgroups 3.1a]
322 protocol [LM1.2X002]
323 protocol [LANMAN2.1]
324 protocol [NT LM 0.12]
325
326 Win2K:
327 protocol [PC NETWORK PROGRAM 1.0]
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 OS/2:
335 protocol [PC NETWORK PROGRAM 1.0]
336 protocol [XENIX CORE]
337 protocol [LANMAN1.0]
338 protocol [LM1.2X002]
339 protocol [LANMAN2.1]
340 */
341
342 /*
343   * Modified to recognize the architecture of the remote machine better.
344   *
345   * This appears to be the matrix of which protocol is used by which
346   * MS product.
347        Protocol                       WfWg    Win95   WinNT  Win2K  OS/2
348        PC NETWORK PROGRAM 1.0          1       1       1      1      1
349        XENIX CORE                                      2             2
350        MICROSOFT NETWORKS 3.0          2       2       
351        DOS LM1.2X002                   3       3       
352        MICROSOFT NETWORKS 1.03                         3
353        DOS LANMAN2.1                   4       4       
354        LANMAN1.0                                       4      2      3
355        Windows for Workgroups 3.1a     5       5       5      3
356        LM1.2X002                                       6      4      4
357        LANMAN2.1                                       7      5      5
358        NT LM 0.12                              6       8      6
359   *
360   *  tim@fsg.com 09/29/95
361   *  Win2K added by matty 17/7/99
362   */
363   
364 #define ARCH_WFWG     0x3      /* This is a fudge because WfWg is like Win95 */
365 #define ARCH_WIN95    0x2
366 #define ARCH_WINNT    0x4
367 #define ARCH_WIN2K    0xC      /* Win2K is like NT */
368 #define ARCH_OS2      0x14     /* Again OS/2 is like NT */
369 #define ARCH_SAMBA    0x20
370  
371 #define ARCH_ALL      0x3F
372  
373 /* List of supported protocols, most desired first */
374 static struct {
375   char *proto_name;
376   char *short_name;
377   int (*proto_reply_fn)(char *, char *);
378   int protocol_level;
379 } supported_protocols[] = {
380   {"NT LANMAN 1.0",           "NT1",      reply_nt1,      PROTOCOL_NT1},
381   {"NT LM 0.12",              "NT1",      reply_nt1,      PROTOCOL_NT1},
382   {"LM1.2X002",               "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
383   {"Samba",                   "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
384   {"DOS LM1.2X002",           "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
385   {"LANMAN1.0",               "LANMAN1",  reply_lanman1,  PROTOCOL_LANMAN1},
386   {"MICROSOFT NETWORKS 3.0",  "LANMAN1",  reply_lanman1,  PROTOCOL_LANMAN1},
387   {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
388   {"PC NETWORK PROGRAM 1.0",  "CORE",     reply_corep,    PROTOCOL_CORE}, 
389   {NULL,NULL,NULL,0},
390 };
391
392
393 /****************************************************************************
394   reply to a negprot
395 ****************************************************************************/
396 int reply_negprot(connection_struct *conn, 
397                   char *inbuf,char *outbuf, int dum_size, 
398                   int dum_buffsize)
399 {
400   int outsize = set_message(outbuf,1,0,True);
401   int Index=0;
402   int choice= -1;
403   int protocol;
404   char *p;
405   int bcc = SVAL(smb_buf(inbuf),-2);
406   int arch = ARCH_ALL;
407   START_PROFILE(SMBnegprot);
408
409   p = smb_buf(inbuf)+1;
410   while (p < (smb_buf(inbuf) + bcc))
411     { 
412       Index++;
413       DEBUG(3,("Requested protocol [%s]\n",p));
414       if (strcsequal(p,"Windows for Workgroups 3.1a"))
415         arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
416       else if (strcsequal(p,"DOS LM1.2X002"))
417         arch &= ( ARCH_WFWG | ARCH_WIN95 );
418       else if (strcsequal(p,"DOS LANMAN2.1"))
419         arch &= ( ARCH_WFWG | ARCH_WIN95 );
420       else if (strcsequal(p,"NT LM 0.12"))
421         arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
422       else if (strcsequal(p,"LANMAN2.1"))
423         arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
424       else if (strcsequal(p,"LM1.2X002"))
425         arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
426       else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
427         arch &= ARCH_WINNT;
428       else if (strcsequal(p,"XENIX CORE"))
429         arch &= ( ARCH_WINNT | ARCH_OS2 );
430       else if (strcsequal(p,"Samba")) {
431         arch = ARCH_SAMBA;
432         break;
433       }
434  
435       p += strlen(p) + 2;
436     }
437     
438   switch ( arch ) {
439   case ARCH_SAMBA:
440     set_remote_arch(RA_SAMBA);
441     break;
442   case ARCH_WFWG:
443     set_remote_arch(RA_WFWG);
444     break;
445   case ARCH_WIN95:
446     set_remote_arch(RA_WIN95);
447     break;
448   case ARCH_WINNT:
449    if(SVAL(inbuf,smb_flg2)==FLAGS2_WIN2K_SIGNATURE)
450      set_remote_arch(RA_WIN2K);
451    else
452      set_remote_arch(RA_WINNT);
453     break;
454   case ARCH_WIN2K:
455     set_remote_arch(RA_WIN2K);
456     break;
457   case ARCH_OS2:
458     set_remote_arch(RA_OS2);
459     break;
460   default:
461     set_remote_arch(RA_UNKNOWN);
462     break;
463   }
464  
465   /* possibly reload - change of architecture */
466   reload_services(True);      
467     
468   /* Check for protocols, most desirable first */
469   for (protocol = 0; supported_protocols[protocol].proto_name; protocol++)
470     {
471       p = smb_buf(inbuf)+1;
472       Index = 0;
473       if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) &&
474           (supported_protocols[protocol].protocol_level >= lp_minprotocol()))
475         while (p < (smb_buf(inbuf) + bcc))
476           { 
477             if (strequal(p,supported_protocols[protocol].proto_name))
478               choice = Index;
479             Index++;
480             p += strlen(p) + 2;
481           }
482       if(choice != -1)
483         break;
484     }
485   
486   SSVAL(outbuf,smb_vwv0,choice);
487   if(choice != -1) {
488     extern fstring remote_proto;
489     fstrcpy(remote_proto,supported_protocols[protocol].short_name);
490     reload_services(True);          
491     outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf);
492     DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
493   }
494   else {
495     DEBUG(0,("No protocol supported !\n"));
496   }
497   SSVAL(outbuf,smb_vwv0,choice);
498   
499   DEBUG( 5, ( "negprot index=%d\n", choice ) );
500
501   END_PROFILE(SMBnegprot);
502   return(outsize);
503 }
504