2 Unix SMB/CIFS implementation.
3 client connect/disconnect routines
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Andrew Bartlett 2001-2003
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 {PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
28 {PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"},
29 {PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"},
30 {PROTOCOL_LANMAN1, "LANMAN1.0"},
31 {PROTOCOL_LANMAN2, "LM1.2X002"},
32 {PROTOCOL_LANMAN2, "DOS LANMAN2.1"},
33 {PROTOCOL_LANMAN2, "LANMAN2.1"},
34 {PROTOCOL_LANMAN2, "Samba"},
35 {PROTOCOL_NT1, "NT LANMAN 1.0"},
36 {PROTOCOL_NT1, "NT LM 0.12"},
39 #define STAR_SMBSERVER "*SMBSERVER"
42 * Set the user session key for a connection
43 * @param cli The cli structure to add it too
44 * @param session_key The session key used. (A copy of this is taken for the cli struct)
48 static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key)
50 cli->user_session_key = data_blob(session_key.data, session_key.length);
53 /****************************************************************************
54 Do an old lanman2 style session setup.
55 ****************************************************************************/
57 static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli,
59 const char *pass, size_t passlen,
60 const char *workgroup)
62 DATA_BLOB session_key = data_blob_null;
63 DATA_BLOB lm_response = data_blob_null;
68 if (passlen > sizeof(pword)-1) {
69 return NT_STATUS_INVALID_PARAMETER;
72 /* LANMAN servers predate NT status codes and Unicode and ignore those
73 smb flags so we must disable the corresponding default capabilities
74 that would otherwise cause the Unicode and NT Status flags to be
75 set (and even returned by the server) */
77 cli->capabilities &= ~(CAP_UNICODE | CAP_STATUS32);
79 /* if in share level security then don't send a password now */
80 if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL))
83 if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
84 /* Encrypted mode needed, and non encrypted password supplied. */
85 lm_response = data_blob(NULL, 24);
86 if (!SMBencrypt(pass, cli->secblob.data,(uchar *)lm_response.data)) {
87 DEBUG(1, ("Password is > 14 chars in length, and is therefore incompatible with Lanman authentication\n"));
88 return NT_STATUS_ACCESS_DENIED;
90 } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
91 /* Encrypted mode needed, and encrypted password supplied. */
92 lm_response = data_blob(pass, passlen);
93 } else if (passlen > 0) {
94 /* Plaintext mode needed, assume plaintext supplied. */
95 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
96 lm_response = data_blob(pass, passlen);
99 /* send a session setup command */
100 memset(cli->outbuf,'\0',smb_size);
101 cli_set_message(cli->outbuf,10, 0, True);
102 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
103 cli_setup_packet(cli);
105 SCVAL(cli->outbuf,smb_vwv0,0xFF);
106 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
107 SSVAL(cli->outbuf,smb_vwv3,2);
108 SSVAL(cli->outbuf,smb_vwv4,1);
109 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
110 SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
112 p = smb_buf(cli->outbuf);
113 memcpy(p,lm_response.data,lm_response.length);
114 p += lm_response.length;
115 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
116 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
117 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
118 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
119 cli_setup_bcc(cli, p);
121 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
122 return cli_nt_error(cli);
125 show_msg(cli->inbuf);
127 if (cli_is_error(cli)) {
128 return cli_nt_error(cli);
131 /* use the returned vuid from now on */
132 cli->vuid = SVAL(cli->inbuf,smb_uid);
133 status = cli_set_username(cli, user);
134 if (!NT_STATUS_IS_OK(status)) {
138 if (session_key.data) {
139 /* Have plaintext orginal */
140 cli_set_session_key(cli, session_key);
146 /****************************************************************************
147 Work out suitable capabilities to offer the server.
148 ****************************************************************************/
150 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
152 uint32 capabilities = CAP_NT_SMBS;
154 if (!cli->force_dos_errors)
155 capabilities |= CAP_STATUS32;
157 if (cli->use_level_II_oplocks)
158 capabilities |= CAP_LEVEL_II_OPLOCKS;
160 capabilities |= (cli->capabilities & (CAP_UNICODE|CAP_LARGE_FILES|CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_DFS));
164 /****************************************************************************
165 Do a NT1 guest session setup.
166 ****************************************************************************/
168 struct cli_session_setup_guest_state {
169 struct cli_state *cli;
173 static void cli_session_setup_guest_done(struct tevent_req *subreq);
175 struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx,
176 struct event_context *ev,
177 struct cli_state *cli)
179 struct tevent_req *req, *subreq;
180 struct cli_session_setup_guest_state *state;
184 req = tevent_req_create(mem_ctx, &state,
185 struct cli_session_setup_guest_state);
192 SCVAL(vwv+0, 0, 0xFF);
195 SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
197 SSVAL(vwv+4, 0, cli->pid);
198 SIVAL(vwv+5, 0, cli->sesskey);
203 SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli));
205 bytes = talloc_array(state, uint8_t, 0);
207 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* username */
209 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* workgroup */
211 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Unix", 5, NULL);
212 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Samba", 6, NULL);
214 if (tevent_req_nomem(bytes, req)) {
215 return tevent_req_post(req, ev);
218 subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
219 talloc_get_size(bytes), bytes);
220 if (tevent_req_nomem(subreq, req)) {
221 return tevent_req_post(req, ev);
223 tevent_req_set_callback(subreq, cli_session_setup_guest_done, req);
227 static void cli_session_setup_guest_done(struct tevent_req *subreq)
229 struct tevent_req *req = tevent_req_callback_data(
230 subreq, struct tevent_req);
231 struct cli_session_setup_guest_state *state = tevent_req_data(
232 req, struct cli_session_setup_guest_state);
233 struct cli_state *cli = state->cli;
240 status = cli_smb_recv(subreq, 0, NULL, NULL, &num_bytes, &bytes);
241 if (!NT_STATUS_IS_OK(status)) {
243 tevent_req_nterror(req, status);
247 inbuf = (char *)cli_smb_inbuf(subreq);
250 cli->vuid = SVAL(inbuf, smb_uid);
252 p += clistr_pull(inbuf, cli->server_os, (char *)p, sizeof(fstring),
253 bytes+num_bytes-p, STR_TERMINATE);
254 p += clistr_pull(inbuf, cli->server_type, (char *)p, sizeof(fstring),
255 bytes+num_bytes-p, STR_TERMINATE);
256 p += clistr_pull(inbuf, cli->server_domain, (char *)p, sizeof(fstring),
257 bytes+num_bytes-p, STR_TERMINATE);
259 if (strstr(cli->server_type, "Samba")) {
260 cli->is_samba = True;
265 status = cli_set_username(cli, "");
266 if (!NT_STATUS_IS_OK(status)) {
267 tevent_req_nterror(req, status);
270 tevent_req_done(req);
273 NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req)
275 return tevent_req_simple_recv_ntstatus(req);
278 static NTSTATUS cli_session_setup_guest(struct cli_state *cli)
280 TALLOC_CTX *frame = talloc_stackframe();
281 struct event_context *ev;
282 struct tevent_req *req;
283 NTSTATUS status = NT_STATUS_OK;
285 if (cli_has_async_calls(cli)) {
287 * Can't use sync call while an async call is in flight
289 status = NT_STATUS_INVALID_PARAMETER;
293 ev = event_context_init(frame);
295 status = NT_STATUS_NO_MEMORY;
299 req = cli_session_setup_guest_send(frame, ev, cli);
301 status = NT_STATUS_NO_MEMORY;
305 if (!tevent_req_poll(req, ev)) {
306 status = map_nt_error_from_unix(errno);
310 status = cli_session_setup_guest_recv(req);
313 if (!NT_STATUS_IS_OK(status)) {
314 cli_set_error(cli, status);
319 /****************************************************************************
320 Do a NT1 plaintext session setup.
321 ****************************************************************************/
323 static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
324 const char *user, const char *pass,
325 const char *workgroup)
327 uint32 capabilities = cli_session_setup_capabilities(cli);
332 fstr_sprintf( lanman, "Samba %s", samba_version_string());
334 memset(cli->outbuf, '\0', smb_size);
335 cli_set_message(cli->outbuf,13,0,True);
336 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
337 cli_setup_packet(cli);
339 SCVAL(cli->outbuf,smb_vwv0,0xFF);
340 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
341 SSVAL(cli->outbuf,smb_vwv3,2);
342 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
343 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
344 SSVAL(cli->outbuf,smb_vwv8,0);
345 SIVAL(cli->outbuf,smb_vwv11,capabilities);
346 p = smb_buf(cli->outbuf);
348 /* check wether to send the ASCII or UNICODE version of the password */
350 if ( (capabilities & CAP_UNICODE) == 0 ) {
351 p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
352 SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
355 /* For ucs2 passwords clistr_push calls ucs2_align, which causes
356 * the space taken by the unicode password to be one byte too
357 * long (as we're on an odd byte boundary here). Reduce the
358 * count by 1 to cope with this. Fixes smbclient against NetApp
359 * servers which can't cope. Fix from
360 * bryan.kolodziej@allenlund.com in bug #3840.
362 p += clistr_push(cli, p, pass, -1, STR_UNICODE|STR_TERMINATE); /* unicode password */
363 SSVAL(cli->outbuf,smb_vwv8,PTR_DIFF(p, smb_buf(cli->outbuf))-1);
366 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
367 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
368 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
369 p += clistr_push(cli, p, lanman, -1, STR_TERMINATE);
370 cli_setup_bcc(cli, p);
372 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
373 return cli_nt_error(cli);
376 show_msg(cli->inbuf);
378 if (cli_is_error(cli)) {
379 return cli_nt_error(cli);
382 cli->vuid = SVAL(cli->inbuf,smb_uid);
383 p = smb_buf(cli->inbuf);
384 p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
386 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
388 p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
390 status = cli_set_username(cli, user);
391 if (!NT_STATUS_IS_OK(status)) {
394 if (strstr(cli->server_type, "Samba")) {
395 cli->is_samba = True;
401 /****************************************************************************
402 do a NT1 NTLM/LM encrypted session setup - for when extended security
404 @param cli client state to create do session setup on
406 @param pass *either* cleartext password (passlen !=24) or LM response.
407 @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
408 @param workgroup The user's domain.
409 ****************************************************************************/
411 static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
412 const char *pass, size_t passlen,
413 const char *ntpass, size_t ntpasslen,
414 const char *workgroup)
416 uint32 capabilities = cli_session_setup_capabilities(cli);
417 DATA_BLOB lm_response = data_blob_null;
418 DATA_BLOB nt_response = data_blob_null;
419 DATA_BLOB session_key = data_blob_null;
425 /* do nothing - guest login */
426 } else if (passlen != 24) {
427 if (lp_client_ntlmv2_auth()) {
428 DATA_BLOB server_chal;
429 DATA_BLOB names_blob;
430 server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8));
432 /* note that the 'workgroup' here is a best guess - we don't know
433 the server's domain at this point. The 'server name' is also
436 names_blob = NTLMv2_generate_names_blob(cli->called.name, workgroup);
438 if (!SMBNTLMv2encrypt(user, workgroup, pass, &server_chal,
440 &lm_response, &nt_response, &session_key)) {
441 data_blob_free(&names_blob);
442 data_blob_free(&server_chal);
443 return NT_STATUS_ACCESS_DENIED;
445 data_blob_free(&names_blob);
446 data_blob_free(&server_chal);
450 E_md4hash(pass, nt_hash);
453 nt_response = data_blob_null;
455 nt_response = data_blob(NULL, 24);
456 SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
458 /* non encrypted password supplied. Ignore ntpass. */
459 if (lp_client_lanman_auth()) {
460 lm_response = data_blob(NULL, 24);
461 if (!SMBencrypt(pass,cli->secblob.data, lm_response.data)) {
462 /* Oops, the LM response is invalid, just put
463 the NT response there instead */
464 data_blob_free(&lm_response);
465 lm_response = data_blob(nt_response.data, nt_response.length);
468 /* LM disabled, place NT# in LM field instead */
469 lm_response = data_blob(nt_response.data, nt_response.length);
472 session_key = data_blob(NULL, 16);
474 E_deshash(pass, session_key.data);
475 memset(&session_key.data[8], '\0', 8);
477 SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
480 cli_temp_set_signing(cli);
482 /* pre-encrypted password supplied. Only used for
483 security=server, can't do
484 signing because we don't have original key */
486 lm_response = data_blob(pass, passlen);
487 nt_response = data_blob(ntpass, ntpasslen);
490 /* send a session setup command */
491 memset(cli->outbuf,'\0',smb_size);
493 cli_set_message(cli->outbuf,13,0,True);
494 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
495 cli_setup_packet(cli);
497 SCVAL(cli->outbuf,smb_vwv0,0xFF);
498 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
499 SSVAL(cli->outbuf,smb_vwv3,2);
500 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
501 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
502 SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
503 SSVAL(cli->outbuf,smb_vwv8,nt_response.length);
504 SIVAL(cli->outbuf,smb_vwv11,capabilities);
505 p = smb_buf(cli->outbuf);
506 if (lm_response.length) {
507 memcpy(p,lm_response.data, lm_response.length); p += lm_response.length;
509 if (nt_response.length) {
510 memcpy(p,nt_response.data, nt_response.length); p += nt_response.length;
512 p += clistr_push(cli, p, user, -1, STR_TERMINATE);
514 /* Upper case here might help some NTLMv2 implementations */
515 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
516 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
517 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
518 cli_setup_bcc(cli, p);
520 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
521 result = cli_nt_error(cli);
525 /* show_msg(cli->inbuf); */
527 if (cli_is_error(cli)) {
528 result = cli_nt_error(cli);
533 ok = cli_simple_set_signing(cli, session_key, lm_response);
535 ok = cli_simple_set_signing(cli, session_key, nt_response);
538 if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
539 result = NT_STATUS_ACCESS_DENIED;
544 /* use the returned vuid from now on */
545 cli->vuid = SVAL(cli->inbuf,smb_uid);
547 p = smb_buf(cli->inbuf);
548 p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
550 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
552 p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
555 if (strstr(cli->server_type, "Samba")) {
556 cli->is_samba = True;
559 result = cli_set_username(cli, user);
560 if (!NT_STATUS_IS_OK(result)) {
564 if (session_key.data) {
565 /* Have plaintext orginal */
566 cli_set_session_key(cli, session_key);
569 result = NT_STATUS_OK;
571 data_blob_free(&lm_response);
572 data_blob_free(&nt_response);
573 data_blob_free(&session_key);
577 /****************************************************************************
578 Send a extended security session setup blob
579 ****************************************************************************/
581 static bool cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob)
583 uint32 capabilities = cli_session_setup_capabilities(cli);
586 capabilities |= CAP_EXTENDED_SECURITY;
588 /* send a session setup command */
589 memset(cli->outbuf,'\0',smb_size);
591 cli_set_message(cli->outbuf,12,0,True);
592 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
594 cli_setup_packet(cli);
596 SCVAL(cli->outbuf,smb_vwv0,0xFF);
597 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
598 SSVAL(cli->outbuf,smb_vwv3,2);
599 SSVAL(cli->outbuf,smb_vwv4,1);
600 SIVAL(cli->outbuf,smb_vwv5,0);
601 SSVAL(cli->outbuf,smb_vwv7,blob.length);
602 SIVAL(cli->outbuf,smb_vwv10,capabilities);
603 p = smb_buf(cli->outbuf);
604 memcpy(p, blob.data, blob.length);
606 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
607 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
608 cli_setup_bcc(cli, p);
609 return cli_send_smb(cli);
612 /****************************************************************************
613 Send a extended security session setup blob, returning a reply blob.
614 ****************************************************************************/
616 static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli)
618 DATA_BLOB blob2 = data_blob_null;
622 if (!cli_receive_smb(cli))
625 show_msg(cli->inbuf);
627 if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
628 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
632 /* use the returned vuid from now on */
633 cli->vuid = SVAL(cli->inbuf,smb_uid);
635 p = smb_buf(cli->inbuf);
637 blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
640 p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
643 /* w2k with kerberos doesn't properly null terminate this field */
644 len = smb_bufrem(cli->inbuf, p);
645 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
652 /****************************************************************************
653 Send a extended security session setup blob, returning a reply blob.
654 ****************************************************************************/
656 /* The following is calculated from :
658 * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
659 * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at
663 #define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
665 static bool cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
667 int32 remaining = blob.length;
669 DATA_BLOB send_blob = data_blob_null;
670 int32 max_blob_size = 0;
671 DATA_BLOB receive_blob = data_blob_null;
673 if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) {
674 DEBUG(0,("cli_session_setup_blob: cli->max_xmit too small "
675 "(was %u, need minimum %u)\n",
676 (unsigned int)cli->max_xmit,
677 BASE_SESSSETUP_BLOB_PACKET_SIZE));
678 cli_set_nt_error(cli, NT_STATUS_INVALID_PARAMETER);
682 max_blob_size = cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE;
684 while ( remaining > 0) {
685 if (remaining >= max_blob_size) {
686 send_blob.length = max_blob_size;
687 remaining -= max_blob_size;
689 send_blob.length = remaining;
693 send_blob.data = &blob.data[cur];
694 cur += send_blob.length;
696 DEBUG(10, ("cli_session_setup_blob: Remaining (%u) sending (%u) current (%u)\n",
697 (unsigned int)remaining,
698 (unsigned int)send_blob.length,
699 (unsigned int)cur ));
701 if (!cli_session_setup_blob_send(cli, send_blob)) {
702 DEBUG(0, ("cli_session_setup_blob: send failed\n"));
706 receive_blob = cli_session_setup_blob_receive(cli);
707 data_blob_free(&receive_blob);
709 if (cli_is_error(cli) &&
710 !NT_STATUS_EQUAL( cli_get_nt_error(cli),
711 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
712 DEBUG(0, ("cli_session_setup_blob: receive failed "
713 "(%s)\n", nt_errstr(cli_get_nt_error(cli))));
722 /****************************************************************************
723 Use in-memory credentials cache
724 ****************************************************************************/
726 static void use_in_memory_ccache(void) {
727 setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
730 /****************************************************************************
731 Do a spnego/kerberos encrypted session setup.
732 ****************************************************************************/
734 static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
736 DATA_BLOB negTokenTarg;
737 DATA_BLOB session_key_krb5;
741 cli_temp_set_signing(cli);
743 DEBUG(2,("Doing kerberos session setup\n"));
745 /* generate the encapsulated kerberos5 ticket */
746 rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5, 0, NULL);
749 DEBUG(1, ("cli_session_setup_kerberos: spnego_gen_negTokenTarg failed: %s\n",
751 return ADS_ERROR_KRB5(rc);
755 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
758 if (!cli_session_setup_blob(cli, negTokenTarg)) {
759 nt_status = cli_nt_error(cli);
763 if (cli_is_error(cli)) {
764 nt_status = cli_nt_error(cli);
765 if (NT_STATUS_IS_OK(nt_status)) {
766 nt_status = NT_STATUS_UNSUCCESSFUL;
771 cli_set_session_key(cli, session_key_krb5);
773 if (cli_simple_set_signing(
774 cli, session_key_krb5, data_blob_null)) {
776 if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
777 nt_status = NT_STATUS_ACCESS_DENIED;
782 data_blob_free(&negTokenTarg);
783 data_blob_free(&session_key_krb5);
785 return ADS_ERROR_NT(NT_STATUS_OK);
788 data_blob_free(&negTokenTarg);
789 data_blob_free(&session_key_krb5);
791 return ADS_ERROR_NT(nt_status);
793 #endif /* HAVE_KRB5 */
796 /****************************************************************************
797 Do a spnego/NTLMSSP encrypted session setup.
798 ****************************************************************************/
800 static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
801 const char *pass, const char *domain)
803 struct ntlmssp_state *ntlmssp_state;
807 DATA_BLOB blob = data_blob_null;
808 DATA_BLOB blob_in = data_blob_null;
809 DATA_BLOB blob_out = data_blob_null;
811 cli_temp_set_signing(cli);
813 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
816 ntlmssp_want_feature(ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
818 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
821 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) {
824 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) {
829 nt_status = ntlmssp_update(ntlmssp_state,
831 data_blob_free(&blob_in);
832 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(nt_status)) {
834 /* and wrap it in a SPNEGO wrapper */
835 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
837 /* wrap it in SPNEGO */
838 msg1 = spnego_gen_auth(blob_out);
841 /* now send that blob on its way */
842 if (!cli_session_setup_blob_send(cli, msg1)) {
843 DEBUG(3, ("Failed to send NTLMSSP/SPNEGO blob to server!\n"));
844 nt_status = NT_STATUS_UNSUCCESSFUL;
846 blob = cli_session_setup_blob_receive(cli);
848 nt_status = cli_nt_error(cli);
849 if (cli_is_error(cli) && NT_STATUS_IS_OK(nt_status)) {
850 if (cli->smb_rw_error == SMB_READ_BAD_SIG) {
851 nt_status = NT_STATUS_ACCESS_DENIED;
853 nt_status = NT_STATUS_UNSUCCESSFUL;
857 data_blob_free(&msg1);
861 if (NT_STATUS_IS_OK(nt_status)) {
862 nt_status = NT_STATUS_UNSUCCESSFUL;
864 } else if ((turn == 1) &&
865 NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
866 DATA_BLOB tmp_blob = data_blob_null;
867 /* the server might give us back two challenges */
868 if (!spnego_parse_challenge(blob, &blob_in,
870 DEBUG(3,("Failed to parse challenges\n"));
871 nt_status = NT_STATUS_INVALID_PARAMETER;
873 data_blob_free(&tmp_blob);
875 if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP,
877 DEBUG(3,("Failed to parse auth response\n"));
878 if (NT_STATUS_IS_OK(nt_status)
879 || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED))
880 nt_status = NT_STATUS_INVALID_PARAMETER;
883 data_blob_free(&blob);
884 data_blob_free(&blob_out);
886 } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED));
888 data_blob_free(&blob_in);
890 if (NT_STATUS_IS_OK(nt_status)) {
892 fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
893 cli_set_session_key(cli, ntlmssp_state->session_key);
895 if (cli_simple_set_signing(
896 cli, ntlmssp_state->session_key, data_blob_null)) {
898 if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
899 nt_status = NT_STATUS_ACCESS_DENIED;
904 /* we have a reference conter on ntlmssp_state, if we are signing
905 then the state will be kept by the signing engine */
907 ntlmssp_end(&ntlmssp_state);
909 if (!NT_STATUS_IS_OK(nt_status)) {
915 /****************************************************************************
916 Do a spnego encrypted session setup.
918 user_domain: The shortname of the domain the user/machine is a member of.
919 dest_realm: The realm we're connecting to, if NULL we use our default realm.
920 ****************************************************************************/
922 ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
923 const char *pass, const char *user_domain,
924 const char * dest_realm)
926 char *principal = NULL;
927 char *OIDs[ASN1_MAX_OIDS];
930 const char *p = NULL;
931 char *account = NULL;
934 DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
936 /* the server might not even do spnego */
937 if (cli->secblob.length <= 16) {
938 DEBUG(3,("server didn't supply a full spnego negprot\n"));
943 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
946 /* there is 16 bytes of GUID before the real spnego packet starts */
947 blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
949 /* The server sent us the first part of the SPNEGO exchange in the
950 * negprot reply. It is WRONG to depend on the principal sent in the
951 * negprot reply, but right now we do it. If we don't receive one,
952 * we try to best guess, then fall back to NTLM. */
953 if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
954 data_blob_free(&blob);
955 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
957 data_blob_free(&blob);
959 /* make sure the server understands kerberos */
960 for (i=0;OIDs[i];i++) {
961 DEBUG(3,("got OID=%s\n", OIDs[i]));
962 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
963 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
964 cli->got_kerberos_mechanism = True;
966 talloc_free(OIDs[i]);
969 DEBUG(3,("got principal=%s\n", principal ? principal : "<null>"));
971 status = cli_set_username(cli, user);
972 if (!NT_STATUS_IS_OK(status)) {
973 return ADS_ERROR_NT(status);
977 /* If password is set we reauthenticate to kerberos server
978 * and do not store results */
980 if (cli->got_kerberos_mechanism && cli->use_kerberos) {
986 use_in_memory_ccache();
987 ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
990 TALLOC_FREE(principal);
991 DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
992 if (cli->fallback_after_kerberos)
994 return ADS_ERROR_KRB5(ret);
998 /* If we get a bad principal, try to guess it if
999 we have a valid host NetBIOS name.
1001 if (strequal(principal, ADS_IGNORE_PRINCIPAL)) {
1002 TALLOC_FREE(principal);
1005 if (principal == NULL &&
1006 !is_ipaddress(cli->desthost) &&
1007 !strequal(STAR_SMBSERVER,
1010 char *machine = NULL;
1012 DEBUG(3,("cli_session_setup_spnego: got a "
1013 "bad server principal, trying to guess ...\n"));
1015 host = strchr_m(cli->desthost, '.');
1017 machine = SMB_STRNDUP(cli->desthost,
1018 host - cli->desthost);
1020 machine = SMB_STRDUP(cli->desthost);
1022 if (machine == NULL) {
1023 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1027 realm = SMB_STRDUP(dest_realm);
1030 realm = kerberos_get_default_realm_from_ccache();
1032 if (realm && *realm) {
1033 principal = talloc_asprintf(NULL, "%s$@%s",
1038 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1040 DEBUG(3,("cli_session_setup_spnego: guessed "
1041 "server principal=%s\n",
1042 principal ? principal : "<null>"));
1049 rc = cli_session_setup_kerberos(cli, principal,
1051 if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
1052 TALLOC_FREE(principal);
1059 TALLOC_FREE(principal);
1063 account = talloc_strdup(talloc_tos(), user);
1065 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1068 /* when falling back to ntlmssp while authenticating with a machine
1069 * account strip off the realm - gd */
1071 if ((p = strchr_m(user, '@')) != NULL) {
1072 account[PTR_DIFF(p,user)] = '\0';
1075 return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, account, pass, user_domain));
1078 /****************************************************************************
1079 Send a session setup. The username and workgroup is in UNIX character
1080 format and must be converted to DOS codepage format before sending. If the
1081 password is in plaintext, the same should be done.
1082 ****************************************************************************/
1084 NTSTATUS cli_session_setup(struct cli_state *cli,
1086 const char *pass, int passlen,
1087 const char *ntpass, int ntpasslen,
1088 const char *workgroup)
1094 fstrcpy(user2, user);
1103 /* allow for workgroups as part of the username */
1104 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
1105 (p=strchr_m(user2,*lp_winbind_separator()))) {
1111 if (cli->protocol < PROTOCOL_LANMAN1) {
1112 return NT_STATUS_OK;
1115 /* now work out what sort of session setup we are going to
1116 do. I have split this into separate functions to make the
1117 flow a bit easier to understand (tridge) */
1119 /* if its an older server then we have to use the older request format */
1121 if (cli->protocol < PROTOCOL_NT1) {
1122 if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
1123 DEBUG(1, ("Server requested LM password but 'client lanman auth'"
1125 return NT_STATUS_ACCESS_DENIED;
1128 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
1129 !lp_client_plaintext_auth() && (*pass)) {
1130 DEBUG(1, ("Server requested plaintext password but "
1131 "'client plaintext auth' is disabled\n"));
1132 return NT_STATUS_ACCESS_DENIED;
1135 return cli_session_setup_lanman2(cli, user, pass, passlen,
1139 /* if no user is supplied then we have to do an anonymous connection.
1140 passwords are ignored */
1142 if (!user || !*user)
1143 return cli_session_setup_guest(cli);
1145 /* if the server is share level then send a plaintext null
1146 password at this point. The password is sent in the tree
1149 if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
1150 return cli_session_setup_plaintext(cli, user, "", workgroup);
1152 /* if the server doesn't support encryption then we have to use
1153 plaintext. The second password is ignored */
1155 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
1156 if (!lp_client_plaintext_auth() && (*pass)) {
1157 DEBUG(1, ("Server requested plaintext password but "
1158 "'client plaintext auth' is disabled\n"));
1159 return NT_STATUS_ACCESS_DENIED;
1161 return cli_session_setup_plaintext(cli, user, pass, workgroup);
1164 /* if the server supports extended security then use SPNEGO */
1166 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
1167 ADS_STATUS status = cli_session_setup_spnego(cli, user, pass,
1169 if (!ADS_ERR_OK(status)) {
1170 DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
1171 return ads_ntstatus(status);
1176 /* otherwise do a NT1 style session setup */
1177 status = cli_session_setup_nt1(cli, user, pass, passlen,
1178 ntpass, ntpasslen, workgroup);
1179 if (!NT_STATUS_IS_OK(status)) {
1180 DEBUG(3,("cli_session_setup: NT1 session setup "
1181 "failed: %s\n", nt_errstr(status)));
1186 if (strstr(cli->server_type, "Samba")) {
1187 cli->is_samba = True;
1190 return NT_STATUS_OK;
1193 /****************************************************************************
1195 *****************************************************************************/
1197 bool cli_ulogoff(struct cli_state *cli)
1199 memset(cli->outbuf,'\0',smb_size);
1200 cli_set_message(cli->outbuf,2,0,True);
1201 SCVAL(cli->outbuf,smb_com,SMBulogoffX);
1202 cli_setup_packet(cli);
1203 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1204 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
1207 if (!cli_receive_smb(cli))
1210 if (cli_is_error(cli)) {
1218 /****************************************************************************
1220 ****************************************************************************/
1222 struct async_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx,
1223 struct event_context *ev,
1224 struct cli_state *cli,
1225 const char *share, const char *dev,
1226 const char *pass, int passlen)
1230 struct async_req *result;
1234 fstrcpy(cli->share, share);
1236 /* in user level security don't send a password now */
1237 if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
1240 } else if (pass == NULL) {
1241 DEBUG(1, ("Server not using user level security and no "
1242 "password supplied.\n"));
1246 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) &&
1247 *pass && passlen != 24) {
1248 if (!lp_client_lanman_auth()) {
1249 DEBUG(1, ("Server requested LANMAN password "
1250 "(share-level security) but "
1251 "'client lanman auth' is disabled\n"));
1256 * Non-encrypted passwords - convert to DOS codepage before
1260 SMBencrypt(pass, cli->secblob.data, (uchar *)pword);
1262 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL
1263 |NEGOTIATE_SECURITY_CHALLENGE_RESPONSE))
1265 if (!lp_client_plaintext_auth() && (*pass)) {
1266 DEBUG(1, ("Server requested plaintext "
1267 "password but 'client plaintext "
1268 "auth' is disabled\n"));
1273 * Non-encrypted passwords - convert to DOS codepage
1276 passlen = clistr_push(cli, pword, pass, sizeof(pword),
1278 if (passlen == -1) {
1279 DEBUG(1, ("clistr_push(pword) failed\n"));
1284 memcpy(pword, pass, passlen);
1289 SCVAL(vwv+0, 0, 0xFF);
1292 SSVAL(vwv+2, 0, TCONX_FLAG_EXTENDED_RESPONSE);
1293 SSVAL(vwv+3, 0, passlen);
1296 bytes = (uint8_t *)talloc_memdup(talloc_tos(), pword, passlen);
1298 bytes = talloc_array(talloc_tos(), uint8_t, 0);
1304 tmp = talloc_asprintf_strupper_m(talloc_tos(), "\\\\%s\\%s",
1305 cli->desthost, share);
1310 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
1315 * Add the devicetype
1317 tmp = talloc_strdup_upper(talloc_tos(), dev);
1322 bytes = smb_bytes_push_str(bytes, false, tmp, strlen(tmp)+1, NULL);
1325 if (bytes == NULL) {
1329 result = cli_request_send(mem_ctx, ev, cli, SMBtconX, 0,
1330 4, vwv, 0, talloc_get_size(bytes), bytes);
1336 struct cli_request *state;
1337 if (!async_req_setup(mem_ctx, &result, &state,
1338 struct cli_request)) {
1341 if (async_post_ntstatus(result, ev, NT_STATUS_ACCESS_DENIED)) {
1346 TALLOC_FREE(result);
1350 NTSTATUS cli_tcon_andx_recv(struct async_req *req)
1352 struct cli_request *cli_req = talloc_get_type_abort(
1353 req->private_data, struct cli_request);
1354 struct cli_state *cli = cli_req->cli;
1361 if (async_req_is_nterror(req, &status)) {
1365 status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
1366 if (!NT_STATUS_IS_OK(status)) {
1370 clistr_pull(cli_req->inbuf, cli->dev, bytes, sizeof(fstring),
1371 num_bytes, STR_TERMINATE|STR_ASCII);
1373 if ((cli->protocol >= PROTOCOL_NT1) && (num_bytes == 3)) {
1374 /* almost certainly win95 - enable bug fixes */
1379 * Make sure that we have the optional support 16-bit field. WCT > 2.
1380 * Avoids issues when connecting to Win9x boxes sharing files
1383 cli->dfsroot = false;
1385 if ((wct > 2) && (cli->protocol >= PROTOCOL_LANMAN2)) {
1386 cli->dfsroot = ((SVAL(vwv+2, 0) & SMB_SHARE_IN_DFS) != 0);
1389 cli->cnum = SVAL(cli_req->inbuf,smb_tid);
1390 return NT_STATUS_OK;
1393 NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share,
1394 const char *dev, const char *pass, int passlen)
1396 TALLOC_CTX *frame = talloc_stackframe();
1397 struct event_context *ev;
1398 struct async_req *req;
1401 if (cli->fd_event != NULL) {
1403 * Can't use sync call while an async call is in flight
1405 status = NT_STATUS_INVALID_PARAMETER;
1409 ev = event_context_init(frame);
1411 status = NT_STATUS_NO_MEMORY;
1415 req = cli_tcon_andx_send(frame, ev, cli, share, dev, pass, passlen);
1417 status = NT_STATUS_NO_MEMORY;
1421 while (req->state < ASYNC_REQ_DONE) {
1422 event_loop_once(ev);
1425 status = cli_tcon_andx_recv(req);
1431 /****************************************************************************
1432 Send a tree disconnect.
1433 ****************************************************************************/
1435 bool cli_tdis(struct cli_state *cli)
1437 memset(cli->outbuf,'\0',smb_size);
1438 cli_set_message(cli->outbuf,0,0,True);
1439 SCVAL(cli->outbuf,smb_com,SMBtdis);
1440 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1441 cli_setup_packet(cli);
1444 if (!cli_receive_smb(cli))
1447 if (cli_is_error(cli)) {
1455 /****************************************************************************
1456 Send a negprot command.
1457 ****************************************************************************/
1459 void cli_negprot_sendsync(struct cli_state *cli)
1464 if (cli->protocol < PROTOCOL_NT1)
1465 cli->use_spnego = False;
1467 memset(cli->outbuf,'\0',smb_size);
1469 /* setup the protocol strings */
1470 cli_set_message(cli->outbuf,0,0,True);
1472 p = smb_buf(cli->outbuf);
1473 for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
1474 if (prots[numprots].prot > cli->protocol) {
1478 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
1481 SCVAL(cli->outbuf,smb_com,SMBnegprot);
1482 cli_setup_bcc(cli, p);
1483 cli_setup_packet(cli);
1485 SCVAL(smb_buf(cli->outbuf),0,2);
1490 /****************************************************************************
1491 Send a negprot command.
1492 ****************************************************************************/
1494 struct cli_negprot_state {
1495 struct cli_state *cli;
1498 static void cli_negprot_done(struct tevent_req *subreq);
1500 struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx,
1501 struct event_context *ev,
1502 struct cli_state *cli)
1504 struct tevent_req *req, *subreq;
1505 struct cli_negprot_state *state;
1506 uint8_t *bytes = NULL;
1509 req = tevent_req_create(mem_ctx, &state, struct cli_negprot_state);
1515 if (cli->protocol < PROTOCOL_NT1)
1516 cli->use_spnego = False;
1518 /* setup the protocol strings */
1519 for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
1521 if (prots[numprots].prot > cli->protocol) {
1524 bytes = (uint8_t *)talloc_append_blob(
1525 state, bytes, data_blob_const(&c, sizeof(c)));
1526 if (tevent_req_nomem(bytes, req)) {
1527 return tevent_req_post(req, ev);
1529 bytes = smb_bytes_push_str(bytes, false,
1530 prots[numprots].name,
1531 strlen(prots[numprots].name)+1,
1533 if (tevent_req_nomem(bytes, req)) {
1534 return tevent_req_post(req, ev);
1538 subreq = cli_smb_send(state, ev, cli, SMBnegprot, 0, 0, NULL,
1539 talloc_get_size(bytes), bytes);
1540 if (tevent_req_nomem(subreq, req)) {
1541 return tevent_req_post(req, ev);
1543 tevent_req_set_callback(subreq, cli_negprot_done, req);
1547 static void cli_negprot_done(struct tevent_req *subreq)
1549 struct tevent_req *req = tevent_req_callback_data(
1550 subreq, struct tevent_req);
1551 struct cli_negprot_state *state = tevent_req_data(
1552 req, struct cli_negprot_state);
1553 struct cli_state *cli = state->cli;
1561 status = cli_smb_recv(subreq, 1, &wct, &vwv, &num_bytes, &bytes);
1562 if (!NT_STATUS_IS_OK(status)) {
1563 TALLOC_FREE(subreq);
1567 protnum = SVAL(vwv, 0);
1569 if ((protnum >= ARRAY_SIZE(prots))
1570 || (prots[protnum].prot > cli->protocol)) {
1571 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1575 cli->protocol = prots[protnum].prot;
1577 if ((cli->protocol < PROTOCOL_NT1) &&
1578 client_is_signing_mandatory(cli)) {
1579 DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
1580 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1584 if (cli->protocol >= PROTOCOL_NT1) {
1586 bool negotiated_smb_signing = false;
1589 cli->sec_mode = CVAL(vwv + 1, 0);
1590 cli->max_mux = SVAL(vwv + 1, 1);
1591 cli->max_xmit = IVAL(vwv + 3, 1);
1592 cli->sesskey = IVAL(vwv + 7, 1);
1593 cli->serverzone = SVALS(vwv + 15, 1);
1594 cli->serverzone *= 60;
1595 /* this time arrives in real GMT */
1596 ts = interpret_long_date(((char *)(vwv+11))+1);
1597 cli->servertime = ts.tv_sec;
1598 cli->secblob = data_blob(bytes, num_bytes);
1599 cli->capabilities = IVAL(vwv + 9, 1);
1600 if (cli->capabilities & CAP_RAW_MODE) {
1601 cli->readbraw_supported = True;
1602 cli->writebraw_supported = True;
1604 /* work out if they sent us a workgroup */
1605 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
1606 smb_buflen(cli->inbuf) > 8) {
1607 clistr_pull(cli->inbuf, cli->server_domain,
1608 bytes+8, sizeof(cli->server_domain),
1610 STR_UNICODE|STR_NOALIGN);
1614 * As signing is slow we only turn it on if either the client or
1615 * the server require it. JRA.
1618 if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
1619 /* Fail if server says signing is mandatory and we don't want to support it. */
1620 if (!client_is_signing_allowed(cli)) {
1621 DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
1622 tevent_req_nterror(req,
1623 NT_STATUS_ACCESS_DENIED);
1626 negotiated_smb_signing = true;
1627 } else if (client_is_signing_mandatory(cli) && client_is_signing_allowed(cli)) {
1628 /* Fail if client says signing is mandatory and the server doesn't support it. */
1629 if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
1630 DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
1631 tevent_req_nterror(req,
1632 NT_STATUS_ACCESS_DENIED);
1635 negotiated_smb_signing = true;
1636 } else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
1637 negotiated_smb_signing = true;
1640 if (negotiated_smb_signing) {
1641 cli_set_signing_negotiated(cli);
1644 if (cli->capabilities & (CAP_LARGE_READX|CAP_LARGE_WRITEX)) {
1645 SAFE_FREE(cli->outbuf);
1646 SAFE_FREE(cli->inbuf);
1647 cli->outbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
1648 cli->inbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
1649 cli->bufsize = CLI_SAMBA_MAX_LARGE_READX_SIZE + LARGE_WRITEX_HDR_SIZE;
1652 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
1653 cli->use_spnego = False;
1654 cli->sec_mode = SVAL(vwv + 1, 0);
1655 cli->max_xmit = SVAL(vwv + 2, 0);
1656 cli->max_mux = SVAL(vwv + 3, 0);
1657 cli->sesskey = IVAL(vwv + 6, 0);
1658 cli->serverzone = SVALS(vwv + 10, 0);
1659 cli->serverzone *= 60;
1660 /* this time is converted to GMT by make_unix_date */
1661 cli->servertime = cli_make_unix_date(
1662 cli, (char *)(vwv + 8));
1663 cli->readbraw_supported = ((SVAL(vwv + 5, 0) & 0x1) != 0);
1664 cli->writebraw_supported = ((SVAL(vwv + 5, 0) & 0x2) != 0);
1665 cli->secblob = data_blob(bytes, num_bytes);
1667 /* the old core protocol */
1668 cli->use_spnego = False;
1670 cli->serverzone = get_time_zone(time(NULL));
1673 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
1675 /* a way to force ascii SMB */
1676 if (getenv("CLI_FORCE_ASCII"))
1677 cli->capabilities &= ~CAP_UNICODE;
1679 tevent_req_done(req);
1682 NTSTATUS cli_negprot_recv(struct tevent_req *req)
1684 return tevent_req_simple_recv_ntstatus(req);
1687 NTSTATUS cli_negprot(struct cli_state *cli)
1689 TALLOC_CTX *frame = talloc_stackframe();
1690 struct event_context *ev;
1691 struct tevent_req *req;
1692 NTSTATUS status = NT_STATUS_OK;
1694 if (cli_has_async_calls(cli)) {
1696 * Can't use sync call while an async call is in flight
1698 status = NT_STATUS_INVALID_PARAMETER;
1702 ev = event_context_init(frame);
1704 status = NT_STATUS_NO_MEMORY;
1708 req = cli_negprot_send(frame, ev, cli);
1710 status = NT_STATUS_NO_MEMORY;
1714 if (!tevent_req_poll(req, ev)) {
1715 status = map_nt_error_from_unix(errno);
1719 status = cli_negprot_recv(req);
1722 if (!NT_STATUS_IS_OK(status)) {
1723 cli_set_error(cli, status);
1728 /****************************************************************************
1729 Send a session request. See rfc1002.txt 4.3 and 4.3.2.
1730 ****************************************************************************/
1732 bool cli_session_request(struct cli_state *cli,
1733 struct nmb_name *calling, struct nmb_name *called)
1739 /* 445 doesn't have session request */
1740 if (cli->port == 445)
1743 memcpy(&(cli->calling), calling, sizeof(*calling));
1744 memcpy(&(cli->called ), called , sizeof(*called ));
1746 /* put in the destination name */
1748 tmp = name_mangle(talloc_tos(), cli->called.name,
1749 cli->called.name_type);
1754 p = cli->outbuf+len;
1755 memcpy(p, tmp, name_len(tmp));
1756 len += name_len(tmp);
1761 tmp = name_mangle(talloc_tos(), cli->calling.name,
1762 cli->calling.name_type);
1767 p = cli->outbuf+len;
1768 memcpy(p, tmp, name_len(tmp));
1769 len += name_len(tmp);
1772 /* send a session request (RFC 1002) */
1773 /* setup the packet length
1774 * Remove four bytes from the length count, since the length
1775 * field in the NBT Session Service header counts the number
1776 * of bytes which follow. The cli_send_smb() function knows
1777 * about this and accounts for those four bytes.
1781 _smb_setlen(cli->outbuf,len);
1782 SCVAL(cli->outbuf,0,0x81);
1785 DEBUG(5,("Sent session request\n"));
1787 if (!cli_receive_smb(cli))
1790 if (CVAL(cli->inbuf,0) == 0x84) {
1791 /* C. Hoch 9/14/95 Start */
1792 /* For information, here is the response structure.
1793 * We do the byte-twiddling to for portability.
1794 struct RetargetResponse{
1796 unsigned char flags;
1802 uint16_t port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
1803 struct in_addr dest_ip;
1806 /* SESSION RETARGET */
1807 putip((char *)&dest_ip,cli->inbuf+4);
1808 in_addr_to_sockaddr_storage(&cli->dest_ss, dest_ip);
1810 status = open_socket_out(&cli->dest_ss, port,
1811 LONG_CONNECT_TIMEOUT, &cli->fd);
1812 if (!NT_STATUS_IS_OK(status)) {
1816 DEBUG(3,("Retargeted\n"));
1818 set_socket_options(cli->fd, lp_socket_options());
1825 DEBUG(0,("Retarget recursion - failing\n"));
1829 ret = cli_session_request(cli, calling, called);
1833 } /* C. Hoch 9/14/95 End */
1835 if (CVAL(cli->inbuf,0) != 0x82) {
1836 /* This is the wrong place to put the error... JRA. */
1837 cli->rap_error = CVAL(cli->inbuf,4);
1847 static void smb_sock_connected(struct tevent_req *req)
1849 struct fd_struct *pfd = tevent_req_callback_data(
1850 req, struct fd_struct);
1854 status = open_socket_out_defer_recv(req, &fd);
1855 if (NT_STATUS_IS_OK(status)) {
1860 static NTSTATUS open_smb_socket(const struct sockaddr_storage *pss,
1861 uint16_t *port, int timeout, int *pfd)
1863 struct event_context *ev;
1864 struct tevent_req *r139, *r445;
1865 struct fd_struct *fd139, *fd445;
1866 NTSTATUS status = NT_STATUS_NO_MEMORY;
1869 return open_socket_out(pss, *port, timeout, pfd);
1872 ev = event_context_init(talloc_tos());
1874 return NT_STATUS_NO_MEMORY;
1877 fd139 = talloc(ev, struct fd_struct);
1878 if (fd139 == NULL) {
1883 fd445 = talloc(ev, struct fd_struct);
1884 if (fd445 == NULL) {
1889 r445 = open_socket_out_defer_send(ev, ev, timeval_set(0, 0),
1891 r139 = open_socket_out_defer_send(ev, ev, timeval_set(0, 3000),
1893 if ((r445 == NULL) || (r139 == NULL)) {
1896 tevent_req_set_callback(r445, smb_sock_connected, fd445);
1897 tevent_req_set_callback(r139, smb_sock_connected, fd139);
1899 while ((fd445->fd == -1) && (fd139->fd == -1)
1900 && (tevent_req_is_in_progress(r139)
1901 || tevent_req_is_in_progress(r445))) {
1902 event_loop_once(ev);
1905 if ((fd139->fd != -1) && (fd445->fd != -1)) {
1910 if (fd445->fd != -1) {
1913 status = NT_STATUS_OK;
1916 if (fd139->fd != -1) {
1919 status = NT_STATUS_OK;
1923 status = open_socket_out_defer_recv(r445, &fd445->fd);
1929 /****************************************************************************
1930 Open the client sockets.
1931 ****************************************************************************/
1933 NTSTATUS cli_connect(struct cli_state *cli,
1935 struct sockaddr_storage *dest_ss)
1938 int name_type = 0x20;
1939 TALLOC_CTX *frame = talloc_stackframe();
1940 unsigned int num_addrs = 0;
1942 struct sockaddr_storage *ss_arr = NULL;
1945 /* reasonable default hostname */
1947 host = STAR_SMBSERVER;
1950 fstrcpy(cli->desthost, host);
1952 /* allow hostnames of the form NAME#xx and do a netbios lookup */
1953 if ((p = strchr(cli->desthost, '#'))) {
1954 name_type = strtol(p+1, NULL, 16);
1958 if (!dest_ss || is_zero_addr((struct sockaddr *)dest_ss)) {
1959 NTSTATUS status =resolve_name_list(frame,
1964 if (!NT_STATUS_IS_OK(status)) {
1966 return NT_STATUS_BAD_NETWORK_NAME;
1970 ss_arr = TALLOC_P(frame, struct sockaddr_storage);
1973 return NT_STATUS_NO_MEMORY;
1978 for (i = 0; i < num_addrs; i++) {
1979 cli->dest_ss = ss_arr[i];
1980 if (getenv("LIBSMB_PROG")) {
1981 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1983 uint16_t port = cli->port;
1985 status = open_smb_socket(&cli->dest_ss, &port,
1986 cli->timeout, &cli->fd);
1987 if (NT_STATUS_IS_OK(status)) {
1991 if (cli->fd == -1) {
1992 char addr[INET6_ADDRSTRLEN];
1993 print_sockaddr(addr, sizeof(addr), &ss_arr[i]);
1994 DEBUG(2,("Error connecting to %s (%s)\n",
1995 dest_ss?addr:host,strerror(errno)));
1997 /* Exit from loop on first connection. */
2002 if (cli->fd == -1) {
2004 return map_nt_error_from_unix(errno);
2008 *dest_ss = cli->dest_ss;
2011 set_socket_options(cli->fd, lp_socket_options());
2014 return NT_STATUS_OK;
2018 establishes a connection to after the negprot.
2019 @param output_cli A fully initialised cli structure, non-null only on success
2020 @param dest_host The netbios name of the remote host
2021 @param dest_ss (optional) The the destination IP, NULL for name based lookup
2022 @param port (optional) The destination port (0 for default)
2023 @param retry bool. Did this connection fail with a retryable error ?
2026 NTSTATUS cli_start_connection(struct cli_state **output_cli,
2027 const char *my_name,
2028 const char *dest_host,
2029 struct sockaddr_storage *dest_ss, int port,
2030 int signing_state, int flags,
2034 struct nmb_name calling;
2035 struct nmb_name called;
2036 struct cli_state *cli;
2037 struct sockaddr_storage ss;
2043 my_name = global_myname();
2045 if (!(cli = cli_initialise_ex(signing_state))) {
2046 return NT_STATUS_NO_MEMORY;
2049 make_nmb_name(&calling, my_name, 0x0);
2050 make_nmb_name(&called , dest_host, 0x20);
2052 cli_set_port(cli, port);
2053 cli_set_timeout(cli, 10000); /* 10 seconds. */
2063 DEBUG(3,("Connecting to host=%s\n", dest_host));
2065 nt_status = cli_connect(cli, dest_host, &ss);
2066 if (!NT_STATUS_IS_OK(nt_status)) {
2067 char addr[INET6_ADDRSTRLEN];
2068 print_sockaddr(addr, sizeof(addr), &ss);
2069 DEBUG(1,("cli_start_connection: failed to connect to %s (%s). Error %s\n",
2070 nmb_namestr(&called), addr, nt_errstr(nt_status) ));
2078 if (!cli_session_request(cli, &calling, &called)) {
2080 DEBUG(1,("session request to %s failed (%s)\n",
2081 called.name, cli_errstr(cli)));
2082 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
2086 if (strcmp(called.name, STAR_SMBSERVER)) {
2087 make_nmb_name(&called , STAR_SMBSERVER, 0x20);
2090 return NT_STATUS_BAD_NETWORK_NAME;
2093 if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
2094 cli->use_spnego = False;
2095 else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
2096 cli->use_kerberos = True;
2098 if ((flags & CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS) &&
2099 cli->use_kerberos) {
2100 cli->fallback_after_kerberos = true;
2103 nt_status = cli_negprot(cli);
2104 if (!NT_STATUS_IS_OK(nt_status)) {
2105 DEBUG(1, ("failed negprot: %s\n", nt_errstr(nt_status)));
2111 return NT_STATUS_OK;
2116 establishes a connection right up to doing tconX, password specified.
2117 @param output_cli A fully initialised cli structure, non-null only on success
2118 @param dest_host The netbios name of the remote host
2119 @param dest_ip (optional) The the destination IP, NULL for name based lookup
2120 @param port (optional) The destination port (0 for default)
2121 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
2122 @param service_type The 'type' of serivice.
2123 @param user Username, unix string
2124 @param domain User's domain
2125 @param password User's password, unencrypted unix string.
2126 @param retry bool. Did this connection fail with a retryable error ?
2129 NTSTATUS cli_full_connection(struct cli_state **output_cli,
2130 const char *my_name,
2131 const char *dest_host,
2132 struct sockaddr_storage *dest_ss, int port,
2133 const char *service, const char *service_type,
2134 const char *user, const char *domain,
2135 const char *password, int flags,
2140 struct cli_state *cli = NULL;
2141 int pw_len = password ? strlen(password)+1 : 0;
2145 if (password == NULL) {
2149 nt_status = cli_start_connection(&cli, my_name, dest_host,
2150 dest_ss, port, signing_state,
2153 if (!NT_STATUS_IS_OK(nt_status)) {
2157 nt_status = cli_session_setup(cli, user, password, pw_len, password,
2159 if (!NT_STATUS_IS_OK(nt_status)) {
2161 if (!(flags & CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK)) {
2162 DEBUG(1,("failed session setup with %s\n",
2163 nt_errstr(nt_status)));
2168 nt_status = cli_session_setup(cli, "", "", 0, "", 0, domain);
2169 if (!NT_STATUS_IS_OK(nt_status)) {
2170 DEBUG(1,("anonymous failed session setup with %s\n",
2171 nt_errstr(nt_status)));
2178 nt_status = cli_tcon_andx(cli, service, service_type, password,
2180 if (!NT_STATUS_IS_OK(nt_status)) {
2181 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
2183 if (NT_STATUS_IS_OK(nt_status)) {
2184 nt_status = NT_STATUS_UNSUCCESSFUL;
2190 nt_status = cli_init_creds(cli, user, domain, password);
2191 if (!NT_STATUS_IS_OK(nt_status)) {
2197 return NT_STATUS_OK;
2200 /****************************************************************************
2201 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
2202 ****************************************************************************/
2204 bool attempt_netbios_session_request(struct cli_state **ppcli, const char *srchost, const char *desthost,
2205 struct sockaddr_storage *pdest_ss)
2207 struct nmb_name calling, called;
2209 make_nmb_name(&calling, srchost, 0x0);
2212 * If the called name is an IP address
2213 * then use *SMBSERVER immediately.
2216 if(is_ipaddress(desthost)) {
2217 make_nmb_name(&called, STAR_SMBSERVER, 0x20);
2219 make_nmb_name(&called, desthost, 0x20);
2222 if (!cli_session_request(*ppcli, &calling, &called)) {
2224 struct nmb_name smbservername;
2226 make_nmb_name(&smbservername, STAR_SMBSERVER, 0x20);
2229 * If the name wasn't *SMBSERVER then
2230 * try with *SMBSERVER if the first name fails.
2233 if (nmb_name_equal(&called, &smbservername)) {
2236 * The name used was *SMBSERVER, don't bother with another name.
2239 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
2240 with error %s.\n", desthost, cli_errstr(*ppcli) ));
2245 cli_shutdown(*ppcli);
2247 *ppcli = cli_initialise();
2249 /* Out of memory... */
2253 status = cli_connect(*ppcli, desthost, pdest_ss);
2254 if (!NT_STATUS_IS_OK(status) ||
2255 !cli_session_request(*ppcli, &calling, &smbservername)) {
2256 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
2257 name *SMBSERVER with error %s\n", desthost, cli_errstr(*ppcli) ));
2265 /****************************************************************************
2266 Send an old style tcon.
2267 ****************************************************************************/
2268 NTSTATUS cli_raw_tcon(struct cli_state *cli,
2269 const char *service, const char *pass, const char *dev,
2270 uint16 *max_xmit, uint16 *tid)
2274 if (!lp_client_plaintext_auth() && (*pass)) {
2275 DEBUG(1, ("Server requested plaintext password but 'client "
2276 "plaintext auth' is disabled\n"));
2277 return NT_STATUS_ACCESS_DENIED;
2280 memset(cli->outbuf,'\0',smb_size);
2281 memset(cli->inbuf,'\0',smb_size);
2283 cli_set_message(cli->outbuf, 0, 0, True);
2284 SCVAL(cli->outbuf,smb_com,SMBtcon);
2285 cli_setup_packet(cli);
2287 p = smb_buf(cli->outbuf);
2288 *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
2289 *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
2290 *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
2292 cli_setup_bcc(cli, p);
2295 if (!cli_receive_smb(cli)) {
2296 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2299 if (cli_is_error(cli)) {
2300 return cli_nt_error(cli);
2303 *max_xmit = SVAL(cli->inbuf, smb_vwv0);
2304 *tid = SVAL(cli->inbuf, smb_vwv1);
2306 return NT_STATUS_OK;
2309 /* Return a cli_state pointing at the IPC$ share for the given server */
2311 struct cli_state *get_ipc_connect(char *server,
2312 struct sockaddr_storage *server_ss,
2313 const struct user_auth_info *user_info)
2315 struct cli_state *cli;
2317 uint32_t flags = CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
2319 if (user_info->use_kerberos) {
2320 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
2323 nt_status = cli_full_connection(&cli, NULL, server, server_ss, 0, "IPC$", "IPC",
2324 user_info->username ? user_info->username : "",
2326 user_info->password ? user_info->password : "",
2330 if (NT_STATUS_IS_OK(nt_status)) {
2332 } else if (is_ipaddress(server)) {
2333 /* windows 9* needs a correct NMB name for connections */
2334 fstring remote_name;
2336 if (name_status_find("*", 0, 0, server_ss, remote_name)) {
2337 cli = get_ipc_connect(remote_name, server_ss, user_info);
2346 * Given the IP address of a master browser on the network, return its
2347 * workgroup and connect to it.
2349 * This function is provided to allow additional processing beyond what
2350 * get_ipc_connect_master_ip_bcast() does, e.g. to retrieve the list of master
2351 * browsers and obtain each master browsers' list of domains (in case the
2352 * first master browser is recently on the network and has not yet
2353 * synchronized with other master browsers and therefore does not yet have the
2354 * entire network browse list)
2357 struct cli_state *get_ipc_connect_master_ip(TALLOC_CTX *ctx,
2358 struct ip_service *mb_ip,
2359 const struct user_auth_info *user_info,
2360 char **pp_workgroup_out)
2362 char addr[INET6_ADDRSTRLEN];
2364 struct cli_state *cli;
2365 struct sockaddr_storage server_ss;
2367 *pp_workgroup_out = NULL;
2369 print_sockaddr(addr, sizeof(addr), &mb_ip->ss);
2370 DEBUG(99, ("Looking up name of master browser %s\n",
2374 * Do a name status query to find out the name of the master browser.
2375 * We use <01><02>__MSBROWSE__<02>#01 if *#00 fails because a domain
2376 * master browser will not respond to a wildcard query (or, at least,
2377 * an NT4 server acting as the domain master browser will not).
2379 * We might be able to use ONLY the query on MSBROWSE, but that's not
2380 * yet been tested with all Windows versions, so until it is, leave
2381 * the original wildcard query as the first choice and fall back to
2382 * MSBROWSE if the wildcard query fails.
2384 if (!name_status_find("*", 0, 0x1d, &mb_ip->ss, name) &&
2385 !name_status_find(MSBROWSE, 1, 0x1d, &mb_ip->ss, name)) {
2387 DEBUG(99, ("Could not retrieve name status for %s\n",
2392 if (!find_master_ip(name, &server_ss)) {
2393 DEBUG(99, ("Could not find master ip for %s\n", name));
2397 *pp_workgroup_out = talloc_strdup(ctx, name);
2399 DEBUG(4, ("found master browser %s, %s\n", name, addr));
2401 print_sockaddr(addr, sizeof(addr), &server_ss);
2402 cli = get_ipc_connect(addr, &server_ss, user_info);
2408 * Return the IP address and workgroup of a master browser on the network, and
2412 struct cli_state *get_ipc_connect_master_ip_bcast(TALLOC_CTX *ctx,
2413 const struct user_auth_info *user_info,
2414 char **pp_workgroup_out)
2416 struct ip_service *ip_list;
2417 struct cli_state *cli;
2420 *pp_workgroup_out = NULL;
2422 DEBUG(99, ("Do broadcast lookup for workgroups on local network\n"));
2424 /* Go looking for workgroups by broadcasting on the local network */
2426 if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
2428 DEBUG(99, ("No master browsers responded\n"));
2432 for (i = 0; i < count; i++) {
2433 char addr[INET6_ADDRSTRLEN];
2434 print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
2435 DEBUG(99, ("Found master browser %s\n", addr));
2437 cli = get_ipc_connect_master_ip(ctx, &ip_list[i],
2438 user_info, pp_workgroup_out);