Some cleanups:
[Samba.git] / source / smbd / sesssetup.c
blobe408cc88e9a1f919aca34b1021f546f5230dd54b
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 2002
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "includes.h"
25 uint32 global_client_caps = 0;
27 static struct auth_ntlmssp_state *global_ntlmssp_state;
30 on a logon error possibly map the error to success if "map to guest"
31 is set approriately
33 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
34 const char *user, const char *domain)
36 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
37 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
38 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
39 DEBUG(3,("No such user %s [%s] - using guest account\n",
40 user, domain));
41 make_server_info_guest(server_info);
42 status = NT_STATUS_OK;
46 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
47 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
48 DEBUG(3,("Registered username %s for guest access\n",user));
49 make_server_info_guest(server_info);
50 status = NT_STATUS_OK;
54 return status;
58 /****************************************************************************
59 Add the standard 'Samba' signature to the end of the session setup.
60 ****************************************************************************/
61 static void add_signature(char *outbuf)
63 char *p;
64 p = smb_buf(outbuf);
65 p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
66 p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
67 p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
68 set_message_end(outbuf,p);
71 /****************************************************************************
72 send a security blob via a session setup reply
73 ****************************************************************************/
74 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
75 DATA_BLOB blob, NTSTATUS nt_status)
77 char *p;
79 set_message(outbuf,4,0,True);
81 /* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
82 that we aren't finished yet */
84 nt_status = nt_status_squash(nt_status);
85 SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
86 SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
87 SSVAL(outbuf, smb_vwv3, blob.length);
88 p = smb_buf(outbuf);
90 /* should we cap this? */
91 memcpy(p, blob.data, blob.length);
92 p += blob.length;
94 p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
95 p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
96 p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
97 set_message_end(outbuf,p);
99 return send_smb(smbd_server_fd(),outbuf);
102 /****************************************************************************
103 Do a 'guest' logon, getting back the
104 ****************************************************************************/
105 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
107 struct auth_context *auth_context;
108 auth_usersupplied_info *user_info = NULL;
110 NTSTATUS nt_status;
111 unsigned char chal[8];
113 ZERO_STRUCT(chal);
115 DEBUG(3,("Got anonymous request\n"));
117 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
118 return nt_status;
121 if (!make_user_info_guest(&user_info)) {
122 (auth_context->free)(&auth_context);
123 return NT_STATUS_NO_MEMORY;
126 nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
127 (auth_context->free)(&auth_context);
128 free_user_info(&user_info);
129 return nt_status;
133 #ifdef HAVE_KRB5
134 /****************************************************************************
135 reply to a session setup spnego negotiate packet for kerberos
136 ****************************************************************************/
137 static int reply_spnego_kerberos(connection_struct *conn,
138 char *inbuf, char *outbuf,
139 int length, int bufsize,
140 DATA_BLOB *secblob)
142 DATA_BLOB ticket;
143 char *client, *p;
144 const struct passwd *pw;
145 char *user;
146 int sess_vuid;
147 NTSTATUS ret;
148 DATA_BLOB auth_data;
149 auth_serversupplied_info *server_info = NULL;
150 ADS_STRUCT *ads;
152 if (!spnego_parse_krb5_wrap(*secblob, &ticket)) {
153 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
156 ads = ads_init_simple();
158 if (!ads) {
159 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
162 ads->auth.realm = strdup(lp_realm());
164 ret = ads_verify_ticket(ads, &ticket, &client, &auth_data);
165 if (!NT_STATUS_IS_OK(ret)) {
166 DEBUG(1,("Failed to verify incoming ticket!\n"));
167 ads_destroy(&ads);
168 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
171 data_blob_free(&auth_data);
173 DEBUG(3,("Ticket name is [%s]\n", client));
175 p = strchr_m(client, '@');
176 if (!p) {
177 DEBUG(3,("Doesn't look like a valid principal\n"));
178 ads_destroy(&ads);
179 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
182 *p = 0;
183 if (strcasecmp(p+1, ads->auth.realm) != 0) {
184 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
185 if (!lp_allow_trusted_domains()) {
186 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
188 /* this gives a fully qualified user name (ie. with full realm).
189 that leads to very long usernames, but what else can we do? */
190 asprintf(&user, "%s%s%s", p+1, lp_winbind_separator(), client);
191 } else {
192 user = strdup(client);
194 ads_destroy(&ads);
196 /* setup the string used by %U */
197 sub_set_smb_name(user);
199 reload_services(True);
201 /* the password is good - let them in */
202 pw = Get_Pwnam(user);
203 if (!pw && !strstr(user, lp_winbind_separator())) {
204 char *user2;
205 /* try it with a winbind domain prefix */
206 asprintf(&user2, "%s%s%s", lp_workgroup(), lp_winbind_separator(), user);
207 pw = Get_Pwnam(user2);
208 if (pw) {
209 free(user);
210 user = user2;
214 if (!pw) {
215 DEBUG(1,("Username %s is invalid on this system\n",user));
216 return ERROR_NT(NT_STATUS_NO_SUCH_USER);
219 if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info,pw))) {
220 DEBUG(1,("make_server_info_from_pw failed!\n"));
221 return ERROR_NT(ret);
224 /* register_vuid keeps the server info */
225 sess_vuid = register_vuid(server_info, user);
227 free(user);
229 if (sess_vuid == -1) {
230 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
233 set_message(outbuf,4,0,True);
234 SSVAL(outbuf, smb_vwv3, 0);
235 add_signature(outbuf);
237 SSVAL(outbuf,smb_uid,sess_vuid);
238 SSVAL(inbuf,smb_uid,sess_vuid);
240 return chain_reply(inbuf,outbuf,length,bufsize);
242 #endif
245 /****************************************************************************
246 send a session setup reply, wrapped in SPNEGO.
247 get vuid and check first.
248 end the NTLMSSP exchange context if we are OK/complete fail
249 ***************************************************************************/
250 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *outbuf,
251 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
252 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status)
254 BOOL ret;
255 DATA_BLOB response;
256 struct auth_serversupplied_info *server_info;
257 server_info = (*auth_ntlmssp_state)->server_info;
259 if (!NT_STATUS_IS_OK(nt_status)) {
260 nt_status = do_map_to_guest(nt_status,
261 &server_info,
262 (*auth_ntlmssp_state)->ntlmssp_state->user,
263 (*auth_ntlmssp_state)->ntlmssp_state->domain);
266 if (NT_STATUS_IS_OK(nt_status)) {
267 int sess_vuid;
268 /* register_vuid keeps the server info */
269 sess_vuid = register_vuid(server_info, (*auth_ntlmssp_state)->ntlmssp_state->user);
270 (*auth_ntlmssp_state)->server_info = NULL;
272 if (sess_vuid == -1) {
273 nt_status = NT_STATUS_LOGON_FAILURE;
274 } else {
276 set_message(outbuf,4,0,True);
277 SSVAL(outbuf, smb_vwv3, 0);
279 if (server_info->guest) {
280 SSVAL(outbuf,smb_vwv2,1);
283 SSVAL(outbuf,smb_uid,sess_vuid);
287 response = spnego_gen_auth_response(ntlmssp_blob, nt_status);
288 ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
289 data_blob_free(&response);
291 if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
292 auth_ntlmssp_end(auth_ntlmssp_state);
295 return ret;
298 /****************************************************************************
299 reply to a session setup spnego negotiate packet
300 ****************************************************************************/
301 static int reply_spnego_negotiate(connection_struct *conn,
302 char *inbuf,
303 char *outbuf,
304 int length, int bufsize,
305 DATA_BLOB blob1)
307 char *OIDs[ASN1_MAX_OIDS];
308 DATA_BLOB secblob;
309 int i;
310 DATA_BLOB chal;
311 BOOL got_kerberos = False;
312 NTSTATUS nt_status;
314 /* parse out the OIDs and the first sec blob */
315 if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
316 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
319 for (i=0;OIDs[i];i++) {
320 DEBUG(3,("Got OID %s\n", OIDs[i]));
321 if (strcmp(OID_KERBEROS5, OIDs[i]) == 0 ||
322 strcmp(OID_KERBEROS5_OLD, OIDs[i]) == 0) {
323 got_kerberos = True;
325 free(OIDs[i]);
327 DEBUG(3,("Got secblob of size %d\n", secblob.length));
329 #ifdef HAVE_KRB5
330 if (got_kerberos && (SEC_ADS == lp_security())) {
331 int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
332 length, bufsize, &secblob);
333 data_blob_free(&secblob);
334 return ret;
336 #endif
338 if (global_ntlmssp_state) {
339 auth_ntlmssp_end(&global_ntlmssp_state);
342 nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
343 if (!NT_STATUS_IS_OK(nt_status)) {
344 return ERROR_NT(nt_status);
347 nt_status = auth_ntlmssp_update(global_ntlmssp_state,
348 secblob, &chal);
350 data_blob_free(&secblob);
352 reply_spnego_ntlmssp(conn, outbuf, &global_ntlmssp_state,
353 &chal, nt_status);
355 data_blob_free(&chal);
357 /* already replied */
358 return -1;
362 /****************************************************************************
363 reply to a session setup spnego auth packet
364 ****************************************************************************/
365 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
366 int length, int bufsize,
367 DATA_BLOB blob1)
369 DATA_BLOB auth, auth_reply;
370 NTSTATUS nt_status;
372 if (!spnego_parse_auth(blob1, &auth)) {
373 #if 0
374 file_save("auth.dat", blob1.data, blob1.length);
375 #endif
376 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
379 nt_status = auth_ntlmssp_update(global_ntlmssp_state,
380 auth, &auth_reply);
382 data_blob_free(&auth);
384 reply_spnego_ntlmssp(conn, outbuf, &global_ntlmssp_state,
385 &auth_reply, nt_status);
387 data_blob_free(&auth_reply);
389 /* and tell smbd that we have already replied to this packet */
390 return -1;
394 /****************************************************************************
395 reply to a session setup command
396 ****************************************************************************/
397 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
398 char *outbuf,
399 int length,int bufsize)
401 uint8 *p;
402 DATA_BLOB blob1;
403 int ret;
404 size_t bufrem;
406 DEBUG(3,("Doing spnego session setup\n"));
408 if (global_client_caps == 0) {
409 global_client_caps = IVAL(inbuf,smb_vwv10);
412 p = (uint8 *)smb_buf(inbuf);
414 if (SVAL(inbuf, smb_vwv7) == 0) {
415 /* an invalid request */
416 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
419 bufrem = smb_bufrem(inbuf, p);
420 /* pull the spnego blob */
421 blob1 = data_blob(p, MIN(bufrem, SVAL(inbuf, smb_vwv7)));
423 #if 0
424 file_save("negotiate.dat", blob1.data, blob1.length);
425 #endif
427 if (blob1.data[0] == ASN1_APPLICATION(0)) {
428 /* its a negTokenTarg packet */
429 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
430 data_blob_free(&blob1);
431 return ret;
434 if (blob1.data[0] == ASN1_CONTEXT(1)) {
435 /* its a auth packet */
436 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
437 data_blob_free(&blob1);
438 return ret;
441 /* what sort of packet is this? */
442 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
444 data_blob_free(&blob1);
446 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
450 /****************************************************************************
451 reply to a session setup command
452 ****************************************************************************/
453 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
454 int length,int bufsize)
456 int sess_vuid;
457 int smb_bufsize;
458 DATA_BLOB lm_resp;
459 DATA_BLOB nt_resp;
460 DATA_BLOB plaintext_password;
461 fstring user;
462 fstring sub_user; /* Sainitised username for substituion */
463 fstring domain;
464 fstring native_os;
465 fstring native_lanman;
466 static BOOL done_sesssetup = False;
467 extern BOOL global_encrypted_passwords_negotiated;
468 extern BOOL global_spnego_negotiated;
469 extern int Protocol;
470 extern userdom_struct current_user_info;
471 extern int max_send;
473 auth_usersupplied_info *user_info = NULL;
474 extern struct auth_context *negprot_global_auth_context;
475 auth_serversupplied_info *server_info = NULL;
477 NTSTATUS nt_status;
479 BOOL doencrypt = global_encrypted_passwords_negotiated;
481 START_PROFILE(SMBsesssetupX);
483 ZERO_STRUCT(lm_resp);
484 ZERO_STRUCT(nt_resp);
485 ZERO_STRUCT(plaintext_password);
487 DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
489 /* a SPNEGO session setup has 12 command words, whereas a normal
490 NT1 session setup has 13. See the cifs spec. */
491 if (CVAL(inbuf, smb_wct) == 12 &&
492 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
493 if (!global_spnego_negotiated) {
494 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
495 return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
498 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
501 smb_bufsize = SVAL(inbuf,smb_vwv2);
503 if (Protocol < PROTOCOL_NT1) {
504 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
505 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
506 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
509 if (doencrypt) {
510 lm_resp = data_blob(smb_buf(inbuf), passlen1);
511 } else {
512 plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
513 /* Ensure null termination */
514 plaintext_password.data[passlen1] = 0;
517 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
518 *domain = 0;
520 } else {
521 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
522 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
523 enum remote_arch_types ra_type = get_remote_arch();
524 char *p = smb_buf(inbuf);
526 if(global_client_caps == 0)
527 global_client_caps = IVAL(inbuf,smb_vwv11);
529 /* client_caps is used as final determination if client is NT or Win95.
530 This is needed to return the correct error codes in some
531 circumstances.
534 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
535 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
536 set_remote_arch( RA_WIN95);
540 if (!doencrypt) {
541 /* both Win95 and WinNT stuff up the password lengths for
542 non-encrypting systems. Uggh.
544 if passlen1==24 its a win95 system, and its setting the
545 password length incorrectly. Luckily it still works with the
546 default code because Win95 will null terminate the password
547 anyway
549 if passlen1>0 and passlen2>0 then maybe its a NT box and its
550 setting passlen2 to some random value which really stuffs
551 things up. we need to fix that one. */
553 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
554 passlen2 = 0;
557 /* check for nasty tricks */
558 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
559 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
562 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
563 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
566 /* Save the lanman2 password and the NT md4 password. */
568 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
569 doencrypt = False;
572 if (doencrypt) {
573 lm_resp = data_blob(p, passlen1);
574 nt_resp = data_blob(p+passlen1, passlen2);
575 } else {
576 pstring pass;
577 srvstr_pull(inbuf, pass, smb_buf(inbuf),
578 sizeof(pass), passlen1, STR_TERMINATE);
579 plaintext_password = data_blob(pass, strlen(pass)+1);
582 p += passlen1 + passlen2;
583 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
584 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
585 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
586 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
587 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n",
588 domain,native_os,native_lanman));
591 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
593 if (*user) {
594 if (global_spnego_negotiated) {
596 /* This has to be here, becouse this is a perfectly valid behaviour for guest logons :-( */
598 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
599 return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
601 fstrcpy(sub_user, user);
603 /* setup the string used by %U */
604 sub_set_smb_name(user);
605 } else {
606 fstrcpy(sub_user, lp_guestaccount());
609 sub_set_smb_name(sub_user);
611 reload_services(True);
613 if (lp_security() == SEC_SHARE) {
614 /* in share level we should ignore any passwords */
616 data_blob_free(&lm_resp);
617 data_blob_free(&nt_resp);
618 data_blob_clear_free(&plaintext_password);
620 map_username(sub_user);
621 add_session_user(sub_user);
622 /* Then force it to null for the benfit of the code below */
623 *user = 0;
626 if (!*user) {
628 nt_status = check_guest_password(&server_info);
630 } else if (doencrypt) {
631 if (!negprot_global_auth_context) {
632 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
633 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
635 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
636 lm_resp, nt_resp);
637 if (NT_STATUS_IS_OK(nt_status)) {
638 nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context,
639 user_info,
640 &server_info);
642 } else {
643 struct auth_context *plaintext_auth_context = NULL;
644 const uint8 *chal;
645 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
646 chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
648 if (!make_user_info_for_reply(&user_info,
649 user, domain, chal,
650 plaintext_password)) {
651 nt_status = NT_STATUS_NO_MEMORY;
654 if (NT_STATUS_IS_OK(nt_status)) {
655 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context,
656 user_info,
657 &server_info);
659 (plaintext_auth_context->free)(&plaintext_auth_context);
664 free_user_info(&user_info);
666 data_blob_free(&lm_resp);
667 data_blob_free(&nt_resp);
668 data_blob_clear_free(&plaintext_password);
670 if (!NT_STATUS_IS_OK(nt_status)) {
671 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
674 if (!NT_STATUS_IS_OK(nt_status)) {
675 return ERROR_NT(nt_status_squash(nt_status));
678 /* it's ok - setup a reply */
679 set_message(outbuf,3,0,True);
680 if (Protocol >= PROTOCOL_NT1) {
681 add_signature(outbuf);
682 /* perhaps grab OS version here?? */
685 if (server_info->guest) {
686 SSVAL(outbuf,smb_vwv2,1);
689 /* register the name and uid as being validated, so further connections
690 to a uid can get through without a password, on the same VC */
692 /* register_vuid keeps the server info */
693 sess_vuid = register_vuid(server_info, sub_user);
695 if (sess_vuid == -1) {
696 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
699 SSVAL(outbuf,smb_uid,sess_vuid);
700 SSVAL(inbuf,smb_uid,sess_vuid);
702 if (!done_sesssetup)
703 max_send = MIN(max_send,smb_bufsize);
705 done_sesssetup = True;
707 END_PROFILE(SMBsesssetupX);
708 return chain_reply(inbuf,outbuf,length,bufsize);