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