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