r14170: Paranioa fix for sesssetup.
[vlendec/samba-autobuild/.git] / source3 / smbd / sesssetup.c
1 /* 
2    Unix SMB/CIFS implementation.
3    handle SMBsessionsetup
4    Copyright (C) Andrew Tridgell 1998-2001
5    Copyright (C) Andrew Bartlett      2001
6    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7    Copyright (C) Luke Howard          2003
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 uint32 global_client_caps = 0;
27
28 /*
29   on a logon error possibly map the error to success if "map to guest"
30   is set approriately
31 */
32 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
33                                 const char *user, const char *domain)
34 {
35         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
36                 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
37                     (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
38                         DEBUG(3,("No such user %s [%s] - using guest account\n",
39                                  user, domain));
40                         status = make_server_info_guest(server_info);
41                 }
42         }
43
44         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
45                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
46                         DEBUG(3,("Registered username %s for guest access\n",user));
47                         status = make_server_info_guest(server_info);
48                 }
49         }
50
51         return status;
52 }
53
54 /****************************************************************************
55  Add the standard 'Samba' signature to the end of the session setup.
56 ****************************************************************************/
57
58 static int add_signature(char *outbuf, char *p)
59 {
60         char *start = p;
61         fstring lanman;
62
63         fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
64
65         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
66         p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
67         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
68
69         return PTR_DIFF(p, start);
70 }
71
72 /****************************************************************************
73  Start the signing engine if needed. Don't fail signing here.
74 ****************************************************************************/
75
76 static void sessionsetup_start_signing_engine(const auth_serversupplied_info *server_info, char *inbuf)
77 {
78         if (!server_info->guest && !srv_signing_started()) {
79                 /* We need to start the signing engine
80                  * here but a W2K client sends the old
81                  * "BSRSPYL " signature instead of the
82                  * correct one. Subsequent packets will
83                  * be correct.
84                  */
85                 srv_check_sign_mac(inbuf, False);
86         }
87 }
88
89 /****************************************************************************
90  Send a security blob via a session setup reply.
91 ****************************************************************************/
92
93 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
94                                  DATA_BLOB blob, NTSTATUS nt_status)
95 {
96         char *p;
97
98         set_message(outbuf,4,0,True);
99
100         nt_status = nt_status_squash(nt_status);
101         SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
102         SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
103         SSVAL(outbuf, smb_vwv3, blob.length);
104         p = smb_buf(outbuf);
105
106         /* should we cap this? */
107         memcpy(p, blob.data, blob.length);
108         p += blob.length;
109
110         p += add_signature( outbuf, p );
111
112         set_message_end(outbuf,p);
113
114         show_msg(outbuf);
115         return send_smb(smbd_server_fd(),outbuf);
116 }
117
118 /****************************************************************************
119  Do a 'guest' logon, getting back the 
120 ****************************************************************************/
121
122 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
123 {
124         struct auth_context *auth_context;
125         auth_usersupplied_info *user_info = NULL;
126         
127         NTSTATUS nt_status;
128         unsigned char chal[8];
129
130         ZERO_STRUCT(chal);
131
132         DEBUG(3,("Got anonymous request\n"));
133
134         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
135                 return nt_status;
136         }
137
138         if (!make_user_info_guest(&user_info)) {
139                 (auth_context->free)(&auth_context);
140                 return NT_STATUS_NO_MEMORY;
141         }
142         
143         nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
144         (auth_context->free)(&auth_context);
145         free_user_info(&user_info);
146         return nt_status;
147 }
148
149
150 #ifdef HAVE_KRB5
151 /****************************************************************************
152 reply to a session setup spnego negotiate packet for kerberos
153 ****************************************************************************/
154 static int reply_spnego_kerberos(connection_struct *conn, 
155                                  char *inbuf, char *outbuf,
156                                  int length, int bufsize,
157                                  DATA_BLOB *secblob)
158 {
159         TALLOC_CTX *mem_ctx;
160         DATA_BLOB ticket;
161         char *client, *p, *domain;
162         fstring netbios_domain_name;
163         struct passwd *pw;
164         fstring user;
165         int sess_vuid;
166         NTSTATUS ret;
167         PAC_DATA *pac_data;
168         DATA_BLOB ap_rep, ap_rep_wrapped, response;
169         auth_serversupplied_info *server_info = NULL;
170         DATA_BLOB session_key = data_blob(NULL, 0);
171         uint8 tok_id[2];
172         DATA_BLOB nullblob = data_blob(NULL, 0);
173         fstring real_username;
174         BOOL map_domainuser_to_guest = False;
175         PAC_LOGON_INFO *logon_info = NULL;
176
177         ZERO_STRUCT(ticket);
178         ZERO_STRUCT(pac_data);
179         ZERO_STRUCT(ap_rep);
180         ZERO_STRUCT(ap_rep_wrapped);
181         ZERO_STRUCT(response);
182
183         mem_ctx = talloc_init("reply_spnego_kerberos");
184         if (mem_ctx == NULL)
185                 return ERROR_NT(NT_STATUS_NO_MEMORY);
186
187         if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
188                 talloc_destroy(mem_ctx);
189                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
190         }
191
192         ret = ads_verify_ticket(mem_ctx, lp_realm(), &ticket, &client, &pac_data, &ap_rep, &session_key);
193
194         data_blob_free(&ticket);
195
196         if (!NT_STATUS_IS_OK(ret)) {
197                 DEBUG(1,("Failed to verify incoming ticket!\n"));       
198                 talloc_destroy(mem_ctx);
199                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
200         }
201
202         DEBUG(3,("Ticket name is [%s]\n", client));
203
204         p = strchr_m(client, '@');
205         if (!p) {
206                 DEBUG(3,("Doesn't look like a valid principal\n"));
207                 data_blob_free(&ap_rep);
208                 data_blob_free(&session_key);
209                 SAFE_FREE(client);
210                 talloc_destroy(mem_ctx);
211                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
212         }
213
214         *p = 0;
215
216         /* save the PAC data if we have it */
217
218         if (pac_data) {
219                 logon_info = get_logon_info_from_pac(pac_data);
220                 netsamlogon_cache_store( client, &logon_info->info3 );
221         }
222
223         if (!strequal(p+1, lp_realm())) {
224                 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
225                 if (!lp_allow_trusted_domains()) {
226                         data_blob_free(&ap_rep);
227                         data_blob_free(&session_key);
228                         SAFE_FREE(client);
229                         talloc_destroy(mem_ctx);
230                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
231                 }
232         }
233
234         /* this gives a fully qualified user name (ie. with full realm).
235            that leads to very long usernames, but what else can we do? */
236
237         domain = p+1;
238
239         if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
240
241                 unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
242                 domain = netbios_domain_name;
243                 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
244
245         } else {
246
247                 /* If we have winbind running, we can (and must) shorten the
248                    username by using the short netbios name. Otherwise we will
249                    have inconsistent user names. With Kerberos, we get the
250                    fully qualified realm, with ntlmssp we get the short
251                    name. And even w2k3 does use ntlmssp if you for example
252                    connect to an ip address. */
253
254                 struct winbindd_request wb_request;
255                 struct winbindd_response wb_response;
256                 NSS_STATUS wb_result;
257
258                 ZERO_STRUCT(wb_request);
259                 ZERO_STRUCT(wb_response);
260
261                 DEBUG(10, ("Mapping [%s] to short name\n", domain));
262
263                 fstrcpy(wb_request.domain_name, domain);
264
265                 wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
266                                              &wb_request, &wb_response);
267
268                 if (wb_result == NSS_STATUS_SUCCESS) {
269
270                         fstrcpy(netbios_domain_name,
271                                 wb_response.data.domain_info.name);
272                         domain = netbios_domain_name;
273
274                         DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
275                 } else {
276                         DEBUG(3, ("Could not find short name -- winbind "
277                                   "not running?\n"));
278                 }
279         }
280
281         fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
282         
283         /* lookup the passwd struct, create a new user if necessary */
284
285         map_username( user );
286
287         pw = smb_getpwnam( mem_ctx, user, real_username, True );
288         if (!pw) {
289
290                 /* this was originally the behavior of Samba 2.2, if a user
291                    did not have a local uid but has been authenticated, then 
292                    map them to a guest account */
293
294                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){ 
295                         map_domainuser_to_guest = True;
296                         fstrcpy(user,lp_guestaccount());
297                         pw = smb_getpwnam( mem_ctx, user, real_username, True );
298                 } 
299
300                 /* extra sanity check that the guest account is valid */
301
302                 if ( !pw ) {
303                         DEBUG(1,("Username %s is invalid on this system\n", user));
304                         SAFE_FREE(client);
305                         data_blob_free(&ap_rep);
306                         data_blob_free(&session_key);
307                         talloc_destroy(mem_ctx);
308                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
309                 }
310         }
311
312         /* setup the string used by %U */
313         
314         sub_set_smb_name( real_username );
315         reload_services(True);
316         if ( map_domainuser_to_guest ) {
317                 make_server_info_guest(&server_info);
318         } else if (logon_info) {
319                 ret = make_server_info_info3(mem_ctx, real_username, real_username, domain, 
320                                              &server_info, &logon_info->info3);
321                 if ( !NT_STATUS_IS_OK(ret) ) {
322                         DEBUG(1,("make_server_info_info3 failed: %s!\n",
323                                  nt_errstr(ret)));
324                         SAFE_FREE(client);
325                         data_blob_free(&ap_rep);
326                         data_blob_free(&session_key);
327                         talloc_destroy(mem_ctx);
328                         return ERROR_NT(ret);
329                 }
330
331         } else {
332                 ret = make_server_info_pw(&server_info, real_username, pw);
333
334                 if ( !NT_STATUS_IS_OK(ret) ) {
335                         DEBUG(1,("make_server_info_pw failed: %s!\n",
336                                  nt_errstr(ret)));
337                         SAFE_FREE(client);
338                         data_blob_free(&ap_rep);
339                         data_blob_free(&session_key);
340                         talloc_destroy(mem_ctx);
341                         return ERROR_NT(ret);
342                 }
343
344                 /* make_server_info_pw does not set the domain. Without this
345                  * we end up with the local netbios name in substitutions for
346                  * %D. */
347
348                 if (server_info->sam_account != NULL) {
349                         pdb_set_domain(server_info->sam_account, domain, PDB_SET);
350                 }
351         }
352         
353         /* we need to build the token for the user. make_server_info_guest()
354            already does this */
355         
356         if ( !server_info->ptok ) {
357                 ret = create_local_token( server_info );
358                 if ( !NT_STATUS_IS_OK(ret) ) {
359                         SAFE_FREE(client);
360                         data_blob_free(&ap_rep);
361                         data_blob_free(&session_key);
362                         TALLOC_FREE( mem_ctx );
363                         TALLOC_FREE( server_info );
364                         return ERROR_NT(ret);
365                 }
366         }
367
368         /* register_vuid keeps the server info */
369         /* register_vuid takes ownership of session_key, no need to free after this.
370            A better interface would copy it.... */
371         sess_vuid = register_vuid(server_info, session_key, nullblob, client);
372
373         SAFE_FREE(client);
374
375         if (sess_vuid == UID_FIELD_INVALID ) {
376                 ret = NT_STATUS_LOGON_FAILURE;
377         } else {
378                 /* current_user_info is changed on new vuid */
379                 reload_services( True );
380
381                 set_message(outbuf,4,0,True);
382                 SSVAL(outbuf, smb_vwv3, 0);
383                         
384                 if (server_info->guest) {
385                         SSVAL(outbuf,smb_vwv2,1);
386                 }
387                 
388                 SSVAL(outbuf, smb_uid, sess_vuid);
389
390                 sessionsetup_start_signing_engine(server_info, inbuf);
391         }
392
393         /* wrap that up in a nice GSS-API wrapping */
394         if (NT_STATUS_IS_OK(ret)) {
395                 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
396         } else {
397                 ap_rep_wrapped = data_blob(NULL, 0);
398         }
399         response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
400         reply_sesssetup_blob(conn, outbuf, response, ret);
401
402         data_blob_free(&ap_rep);
403         data_blob_free(&ap_rep_wrapped);
404         data_blob_free(&response);
405         talloc_destroy(mem_ctx);
406
407         return -1; /* already replied */
408 }
409 #endif
410
411 /****************************************************************************
412  Send a session setup reply, wrapped in SPNEGO.
413  Get vuid and check first.
414  End the NTLMSSP exchange context if we are OK/complete fail
415  This should be split into two functions, one to handle each
416  leg of the NTLM auth steps.
417 ***************************************************************************/
418
419 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
420                                  uint16 vuid,
421                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
422                                  DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status, 
423                                  BOOL wrap) 
424 {
425         BOOL ret;
426         DATA_BLOB response;
427         struct auth_serversupplied_info *server_info = NULL;
428
429         if (NT_STATUS_IS_OK(nt_status)) {
430                 server_info = (*auth_ntlmssp_state)->server_info;
431         } else {
432                 nt_status = do_map_to_guest(nt_status, 
433                                             &server_info, 
434                                             (*auth_ntlmssp_state)->ntlmssp_state->user, 
435                                             (*auth_ntlmssp_state)->ntlmssp_state->domain);
436         }
437
438         if (NT_STATUS_IS_OK(nt_status)) {
439                 int sess_vuid;
440                 DATA_BLOB nullblob = data_blob(NULL, 0);
441                 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
442
443                 /* register_vuid keeps the server info */
444                 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
445                 (*auth_ntlmssp_state)->server_info = NULL;
446
447                 if (sess_vuid == UID_FIELD_INVALID ) {
448                         nt_status = NT_STATUS_LOGON_FAILURE;
449                 } else {
450                         
451                         /* current_user_info is changed on new vuid */
452                         reload_services( True );
453
454                         set_message(outbuf,4,0,True);
455                         SSVAL(outbuf, smb_vwv3, 0);
456                         
457                         if (server_info->guest) {
458                                 SSVAL(outbuf,smb_vwv2,1);
459                         }
460                         
461                         SSVAL(outbuf,smb_uid,sess_vuid);
462
463                         sessionsetup_start_signing_engine(server_info, inbuf);
464                 }
465         }
466
467         if (wrap) {
468                 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
469         } else {
470                 response = *ntlmssp_blob;
471         }
472
473         ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
474         if (wrap) {
475                 data_blob_free(&response);
476         }
477
478         /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
479            and the other end, that we are not finished yet. */
480
481         if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
482                 /* NB. This is *NOT* an error case. JRA */
483                 auth_ntlmssp_end(auth_ntlmssp_state);
484                 /* Kill the intermediate vuid */
485                 invalidate_vuid(vuid);
486         }
487
488         return ret;
489 }
490
491 /****************************************************************************
492  Reply to a session setup spnego negotiate packet.
493 ****************************************************************************/
494
495 static int reply_spnego_negotiate(connection_struct *conn, 
496                                   char *inbuf,
497                                   char *outbuf,
498                                   uint16 vuid,
499                                   int length, int bufsize,
500                                   DATA_BLOB blob1,
501                                   AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
502 {
503         char *OIDs[ASN1_MAX_OIDS];
504         DATA_BLOB secblob;
505         int i;
506         DATA_BLOB chal;
507 #ifdef HAVE_KRB5
508         BOOL got_kerberos_mechanism = False;
509 #endif
510         NTSTATUS nt_status;
511
512         /* parse out the OIDs and the first sec blob */
513         if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
514                 /* Kill the intermediate vuid */
515                 invalidate_vuid(vuid);
516
517                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
518         }
519
520         /* only look at the first OID for determining the mechToken --
521            accoirding to RFC2478, we should choose the one we want 
522            and renegotiate, but i smell a client bug here..  
523            
524            Problem observed when connecting to a member (samba box) 
525            of an AD domain as a user in a Samba domain.  Samba member 
526            server sent back krb5/mskrb5/ntlmssp as mechtypes, but the 
527            client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an 
528            NTLMSSP mechtoken.                 --jerry              */
529
530 #ifdef HAVE_KRB5        
531         if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
532             strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
533                 got_kerberos_mechanism = True;
534         }
535 #endif
536                 
537         for (i=0;OIDs[i];i++) {
538                 DEBUG(3,("Got OID %s\n", OIDs[i]));
539                 free(OIDs[i]);
540         }
541         DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
542
543 #ifdef HAVE_KRB5
544         if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
545                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
546                                                 length, bufsize, &secblob);
547                 data_blob_free(&secblob);
548                 /* Kill the intermediate vuid */
549                 invalidate_vuid(vuid);
550
551                 return ret;
552         }
553 #endif
554
555         if (*auth_ntlmssp_state) {
556                 auth_ntlmssp_end(auth_ntlmssp_state);
557         }
558
559         nt_status = auth_ntlmssp_start(auth_ntlmssp_state);
560         if (!NT_STATUS_IS_OK(nt_status)) {
561                 /* Kill the intermediate vuid */
562                 invalidate_vuid(vuid);
563
564                 return ERROR_NT(nt_status);
565         }
566
567         nt_status = auth_ntlmssp_update(*auth_ntlmssp_state, 
568                                         secblob, &chal);
569
570         data_blob_free(&secblob);
571
572         reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
573                              &chal, nt_status, True);
574
575         data_blob_free(&chal);
576
577         /* already replied */
578         return -1;
579 }
580         
581 /****************************************************************************
582  Reply to a session setup spnego auth packet.
583 ****************************************************************************/
584
585 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
586                              uint16 vuid,
587                              int length, int bufsize,
588                              DATA_BLOB blob1,
589                              AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
590 {
591         DATA_BLOB auth, auth_reply;
592         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
593
594         if (!spnego_parse_auth(blob1, &auth)) {
595 #if 0
596                 file_save("auth.dat", blob1.data, blob1.length);
597 #endif
598                 /* Kill the intermediate vuid */
599                 invalidate_vuid(vuid);
600
601                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
602         }
603         
604         if (!*auth_ntlmssp_state) {
605                 /* Kill the intermediate vuid */
606                 invalidate_vuid(vuid);
607
608                 /* auth before negotiatiate? */
609                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
610         }
611         
612         nt_status = auth_ntlmssp_update(*auth_ntlmssp_state, 
613                                         auth, &auth_reply);
614
615         data_blob_free(&auth);
616
617         reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
618                              auth_ntlmssp_state,
619                              &auth_reply, nt_status, True);
620                 
621         data_blob_free(&auth_reply);
622
623         /* and tell smbd that we have already replied to this packet */
624         return -1;
625 }
626
627 /****************************************************************************
628  Reply to a session setup command.
629 ****************************************************************************/
630
631 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
632                                         char *outbuf,
633                                         int length,int bufsize)
634 {
635         uint8 *p;
636         DATA_BLOB blob1;
637         int ret;
638         size_t bufrem;
639         fstring native_os, native_lanman, primary_domain;
640         char *p2;
641         uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
642         enum remote_arch_types ra_type = get_remote_arch();
643         int vuid = SVAL(inbuf,smb_uid);
644         user_struct *vuser = NULL;
645
646         DEBUG(3,("Doing spnego session setup\n"));
647
648         if (global_client_caps == 0) {
649                 global_client_caps = IVAL(inbuf,smb_vwv10);
650
651                 if (!(global_client_caps & CAP_STATUS32)) {
652                         remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
653                 }
654
655         }
656                 
657         p = (uint8 *)smb_buf(inbuf);
658
659         if (data_blob_len == 0) {
660                 /* an invalid request */
661                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
662         }
663
664         bufrem = smb_bufrem(inbuf, p);
665         /* pull the spnego blob */
666         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
667
668 #if 0
669         file_save("negotiate.dat", blob1.data, blob1.length);
670 #endif
671
672         p2 = inbuf + smb_vwv13 + data_blob_len;
673         p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
674         p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
675         p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
676         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
677                 native_os, native_lanman, primary_domain));
678
679         if ( ra_type == RA_WIN2K ) {
680                 /* Windows 2003 doesn't set the native lanman string, 
681                    but does set primary domain which is a bug I think */
682                            
683                 if ( !strlen(native_lanman) )
684                         ra_lanman_string( primary_domain );
685                 else
686                         ra_lanman_string( native_lanman );
687         }
688                 
689         vuser = get_partial_auth_user_struct(vuid);
690         if (!vuser) {
691                 vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
692                 if (vuid == UID_FIELD_INVALID ) {
693                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
694                 }
695         
696                 vuser = get_partial_auth_user_struct(vuid);
697         }
698
699         if (!vuser) {
700                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
701         }
702         
703         SSVAL(outbuf,smb_uid,vuid);
704         
705         if (blob1.data[0] == ASN1_APPLICATION(0)) {
706                 /* its a negTokenTarg packet */
707                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
708                                              &vuser->auth_ntlmssp_state);
709                 data_blob_free(&blob1);
710                 return ret;
711         }
712
713         if (blob1.data[0] == ASN1_CONTEXT(1)) {
714                 /* its a auth packet */
715                 ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
716                                         &vuser->auth_ntlmssp_state);
717                 data_blob_free(&blob1);
718                 return ret;
719         }
720
721         if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
722                 DATA_BLOB chal;
723                 NTSTATUS nt_status;
724                 if (!vuser->auth_ntlmssp_state) {
725                         nt_status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
726                         if (!NT_STATUS_IS_OK(nt_status)) {
727                                 /* Kill the intermediate vuid */
728                                 invalidate_vuid(vuid);
729                                 
730                                 return ERROR_NT(nt_status);
731                         }
732                 }
733
734                 nt_status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
735                                                 blob1, &chal);
736                 
737                 data_blob_free(&blob1);
738                 
739                 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
740                                            &vuser->auth_ntlmssp_state,
741                                            &chal, nt_status, False);
742                 data_blob_free(&chal);
743                 return -1;
744         }
745
746         /* what sort of packet is this? */
747         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
748
749         data_blob_free(&blob1);
750
751         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
752 }
753
754 /****************************************************************************
755  On new VC == 0, shutdown *all* old connections and users.
756  It seems that only NT4.x does this. At W2K and above (XP etc.).
757  a new session setup with VC==0 is ignored.
758 ****************************************************************************/
759
760 static int shutdown_other_smbds(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
761                                 void *p)
762 {
763         struct sessionid *sessionid = (struct sessionid *)dbuf.dptr;
764         const char *ip = (const char *)p;
765
766         if (!process_exists(pid_to_procid(sessionid->pid))) {
767                 return 0;
768         }
769
770         if (sessionid->pid == sys_getpid()) {
771                 return 0;
772         }
773
774         if (strcmp(ip, sessionid->ip_addr) != 0) {
775                 return 0;
776         }
777
778         message_send_pid(pid_to_procid(sessionid->pid), MSG_SHUTDOWN,
779                          NULL, 0, True);
780         return 0;
781 }
782
783 static void setup_new_vc_session(void)
784 {
785         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
786 #if 0
787         conn_close_all();
788         invalidate_all_vuids();
789 #endif
790         if (lp_reset_on_zero_vc()) {
791                 session_traverse(shutdown_other_smbds, client_addr());
792         }
793 }
794
795 /****************************************************************************
796  Reply to a session setup command.
797 ****************************************************************************/
798
799 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
800                           int length,int bufsize)
801 {
802         int sess_vuid;
803         int   smb_bufsize;    
804         DATA_BLOB lm_resp;
805         DATA_BLOB nt_resp;
806         DATA_BLOB plaintext_password;
807         fstring user;
808         fstring sub_user; /* Sainitised username for substituion */
809         fstring domain;
810         fstring native_os;
811         fstring native_lanman;
812         fstring primary_domain;
813         static BOOL done_sesssetup = False;
814         extern BOOL global_encrypted_passwords_negotiated;
815         extern BOOL global_spnego_negotiated;
816         extern enum protocol_types Protocol;
817         extern int max_send;
818
819         auth_usersupplied_info *user_info = NULL;
820         extern struct auth_context *negprot_global_auth_context;
821         auth_serversupplied_info *server_info = NULL;
822
823         NTSTATUS nt_status;
824
825         BOOL doencrypt = global_encrypted_passwords_negotiated;
826
827         DATA_BLOB session_key;
828         
829         START_PROFILE(SMBsesssetupX);
830
831         ZERO_STRUCT(lm_resp);
832         ZERO_STRUCT(nt_resp);
833         ZERO_STRUCT(plaintext_password);
834
835         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
836
837         /* a SPNEGO session setup has 12 command words, whereas a normal
838            NT1 session setup has 13. See the cifs spec. */
839         if (CVAL(inbuf, smb_wct) == 12 &&
840             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
841                 if (!global_spnego_negotiated) {
842                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
843                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
844                 }
845
846                 if (SVAL(inbuf,smb_vwv4) == 0) {
847                         setup_new_vc_session();
848                 }
849                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
850         }
851
852         smb_bufsize = SVAL(inbuf,smb_vwv2);
853
854         if (Protocol < PROTOCOL_NT1) {
855                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
856
857                 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
858                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
859
860                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
861                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
862                 }
863
864                 if (doencrypt) {
865                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
866                 } else {
867                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
868                         /* Ensure null termination */
869                         plaintext_password.data[passlen1] = 0;
870                 }
871
872                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
873                 *domain = 0;
874
875         } else {
876                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
877                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
878                 enum remote_arch_types ra_type = get_remote_arch();
879                 char *p = smb_buf(inbuf);    
880                 char *save_p = smb_buf(inbuf);
881                 uint16 byte_count;
882                         
883
884                 if(global_client_caps == 0) {
885                         global_client_caps = IVAL(inbuf,smb_vwv11);
886                 
887                         if (!(global_client_caps & CAP_STATUS32)) {
888                                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
889                         }
890
891                         /* client_caps is used as final determination if client is NT or Win95. 
892                            This is needed to return the correct error codes in some
893                            circumstances.
894                         */
895                 
896                         if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
897                                 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
898                                         set_remote_arch( RA_WIN95);
899                                 }
900                         }
901                 }
902
903                 if (!doencrypt) {
904                         /* both Win95 and WinNT stuff up the password lengths for
905                            non-encrypting systems. Uggh. 
906                            
907                            if passlen1==24 its a win95 system, and its setting the
908                            password length incorrectly. Luckily it still works with the
909                            default code because Win95 will null terminate the password
910                            anyway 
911                            
912                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
913                            setting passlen2 to some random value which really stuffs
914                            things up. we need to fix that one.  */
915                         
916                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
917                                 passlen2 = 0;
918                 }
919                 
920                 /* check for nasty tricks */
921                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
922                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
923                 }
924
925                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
926                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
927                 }
928
929                 /* Save the lanman2 password and the NT md4 password. */
930                 
931                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
932                         doencrypt = False;
933                 }
934
935                 if (doencrypt) {
936                         lm_resp = data_blob(p, passlen1);
937                         nt_resp = data_blob(p+passlen1, passlen2);
938                 } else {
939                         pstring pass;
940                         BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
941
942 #if 0
943                         /* This was the previous fix. Not sure if it's still valid. JRA. */
944                         if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
945                                 /* NT4.0 stuffs up plaintext unicode password lengths... */
946                                 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
947                                         sizeof(pass), passlen1, STR_TERMINATE);
948 #endif
949
950                         if (unic && (passlen2 == 0) && passlen1) {
951                                 /* Only a ascii plaintext password was sent. */
952                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
953                                         passlen1, STR_TERMINATE|STR_ASCII);
954                         } else {
955                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), 
956                                         sizeof(pass),  unic ? passlen2 : passlen1, 
957                                         STR_TERMINATE);
958                         }
959                         plaintext_password = data_blob(pass, strlen(pass)+1);
960                 }
961                 
962                 p += passlen1 + passlen2;
963                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
964                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
965                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
966                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
967
968                 /* not documented or decoded by Ethereal but there is one more string 
969                    in the extra bytes which is the same as the PrimaryDomain when using 
970                    extended security.  Windows NT 4 and 2003 use this string to store 
971                    the native lanman string. Windows 9x does not include a string here 
972                    at all so we have to check if we have any extra bytes left */
973                 
974                 byte_count = SVAL(inbuf, smb_vwv13);
975                 if ( PTR_DIFF(p, save_p) < byte_count)
976                         p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
977                 else 
978                         fstrcpy( primary_domain, "null" );
979
980                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
981                          domain, native_os, native_lanman, primary_domain));
982
983                 if ( ra_type == RA_WIN2K ) {
984                         if ( strlen(native_lanman) == 0 )
985                                 ra_lanman_string( primary_domain );
986                         else
987                                 ra_lanman_string( native_lanman );
988                 }
989
990         }
991
992         if (SVAL(inbuf,smb_vwv4) == 0) {
993                 setup_new_vc_session();
994         }
995
996         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
997
998         if (*user) {
999                 if (global_spnego_negotiated) {
1000                         
1001                         /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
1002                         
1003                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
1004                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
1005                 }
1006                 fstrcpy(sub_user, user);
1007         } else {
1008                 fstrcpy(sub_user, lp_guestaccount());
1009         }
1010
1011         sub_set_smb_name(sub_user);
1012
1013         reload_services(True);
1014         
1015         if (lp_security() == SEC_SHARE) {
1016                 /* in share level we should ignore any passwords */
1017
1018                 data_blob_free(&lm_resp);
1019                 data_blob_free(&nt_resp);
1020                 data_blob_clear_free(&plaintext_password);
1021
1022                 map_username(sub_user);
1023                 add_session_user(sub_user);
1024                 /* Then force it to null for the benfit of the code below */
1025                 *user = 0;
1026         }
1027         
1028         if (!*user) {
1029
1030                 nt_status = check_guest_password(&server_info);
1031
1032         } else if (doencrypt) {
1033                 if (!negprot_global_auth_context) {
1034                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
1035                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
1036                 }
1037                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
1038                                                          lm_resp, nt_resp);
1039                 if (NT_STATUS_IS_OK(nt_status)) {
1040                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
1041                                                                                      user_info, 
1042                                                                                      &server_info);
1043                 }
1044         } else {
1045                 struct auth_context *plaintext_auth_context = NULL;
1046                 const uint8 *chal;
1047
1048                 nt_status = make_auth_context_subsystem(&plaintext_auth_context);
1049
1050                 if (NT_STATUS_IS_OK(nt_status)) {
1051                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
1052                         
1053                         if (!make_user_info_for_reply(&user_info, 
1054                                                       user, domain, chal,
1055                                                       plaintext_password)) {
1056                                 nt_status = NT_STATUS_NO_MEMORY;
1057                         }
1058                 
1059                         if (NT_STATUS_IS_OK(nt_status)) {
1060                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
1061                                                                                         user_info, 
1062                                                                                         &server_info); 
1063                                 
1064                                 (plaintext_auth_context->free)(&plaintext_auth_context);
1065                         }
1066                 }
1067         }
1068
1069         free_user_info(&user_info);
1070         
1071         if (!NT_STATUS_IS_OK(nt_status)) {
1072                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
1073         }
1074         
1075         if (!NT_STATUS_IS_OK(nt_status)) {
1076                 data_blob_free(&nt_resp);
1077                 data_blob_free(&lm_resp);
1078                 data_blob_clear_free(&plaintext_password);
1079                 return ERROR_NT(nt_status_squash(nt_status));
1080         }
1081
1082         /* Ensure we can't possible take a code path leading to a null defref. */
1083         if (!server_info) {
1084                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
1085         }
1086
1087         nt_status = create_local_token(server_info);
1088         if (!NT_STATUS_IS_OK(nt_status)) {
1089                 DEBUG(10, ("create_local_token failed: %s\n",
1090                            nt_errstr(nt_status)));
1091                 data_blob_free(&nt_resp);
1092                 data_blob_free(&lm_resp);
1093                 data_blob_clear_free(&plaintext_password);
1094                 return ERROR_NT(nt_status_squash(nt_status));
1095         }
1096
1097         if (server_info->user_session_key.data) {
1098                 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
1099         } else {
1100                 session_key = data_blob(NULL, 0);
1101         }
1102
1103         data_blob_clear_free(&plaintext_password);
1104         
1105         /* it's ok - setup a reply */
1106         set_message(outbuf,3,0,True);
1107         if (Protocol >= PROTOCOL_NT1) {
1108                 char *p = smb_buf( outbuf );
1109                 p += add_signature( outbuf, p );
1110                 set_message_end( outbuf, p );
1111                 /* perhaps grab OS version here?? */
1112         }
1113         
1114         if (server_info->guest) {
1115                 SSVAL(outbuf,smb_vwv2,1);
1116         }
1117
1118         /* register the name and uid as being validated, so further connections
1119            to a uid can get through without a password, on the same VC */
1120
1121         /* register_vuid keeps the server info */
1122         sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user);
1123         data_blob_free(&nt_resp);
1124         data_blob_free(&lm_resp);
1125
1126         if (sess_vuid == UID_FIELD_INVALID) {
1127                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
1128         }
1129
1130         /* current_user_info is changed on new vuid */
1131         reload_services( True );
1132
1133         sessionsetup_start_signing_engine(server_info, inbuf);
1134
1135         SSVAL(outbuf,smb_uid,sess_vuid);
1136         SSVAL(inbuf,smb_uid,sess_vuid);
1137         
1138         if (!done_sesssetup)
1139                 max_send = MIN(max_send,smb_bufsize);
1140         
1141         done_sesssetup = True;
1142         
1143         END_PROFILE(SMBsesssetupX);
1144         return chain_reply(inbuf,outbuf,length,bufsize);
1145 }