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