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