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