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