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