2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Gerald (Jerry) Carter 2004
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/>.
23 /****************************************************************************
24 Call a remote api on an arbitrary pipe. takes param, data and setup buffers.
25 ****************************************************************************/
27 bool cli_api_pipe(struct cli_state *cli, const char *pipe_name,
28 uint16 *setup, uint32 setup_count, uint32 max_setup_count,
29 char *params, uint32 param_count, uint32 max_param_count,
30 char *data, uint32 data_count, uint32 max_data_count,
31 char **rparam, uint32 *rparam_count,
32 char **rdata, uint32 *rdata_count)
34 cli_send_trans(cli, SMBtrans,
37 setup, setup_count, max_setup_count,
38 params, param_count, max_param_count,
39 data, data_count, max_data_count);
41 return (cli_receive_trans(cli, SMBtrans,
42 rparam, (unsigned int *)rparam_count,
43 rdata, (unsigned int *)rdata_count));
46 /****************************************************************************
48 ****************************************************************************/
50 bool cli_api(struct cli_state *cli,
51 char *param, int prcnt, int mprcnt,
52 char *data, int drcnt, int mdrcnt,
53 char **rparam, unsigned int *rprcnt,
54 char **rdata, unsigned int *rdrcnt)
56 cli_send_trans(cli,SMBtrans,
57 PIPE_LANMAN, /* Name */
59 NULL,0,0, /* Setup, length, max */
60 param, prcnt, mprcnt, /* Params, length, max */
61 data, drcnt, mdrcnt /* Data, length, max */
64 return (cli_receive_trans(cli,SMBtrans,
69 /****************************************************************************
70 Perform a NetWkstaUserLogon.
71 ****************************************************************************/
73 bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
78 unsigned int rdrcnt,rprcnt;
81 memset(param, 0, sizeof(param));
83 /* send a SMBtrans command with api NetWkstaUserLogon */
85 SSVAL(p,0,132); /* api number */
87 strlcpy(p,"OOWb54WrLh",sizeof(param)-PTR_DIFF(p,param));
88 p = skip_string(param,sizeof(param),p);
89 strlcpy(p,"WB21BWDWWDDDDDDDzzzD",sizeof(param)-PTR_DIFF(p,param));
90 p = skip_string(param,sizeof(param),p);
93 strlcpy(p,user,sizeof(param)-PTR_DIFF(p,param));
99 strlcpy(p, workstation,sizeof(param)-PTR_DIFF(p,param));
102 SSVAL(p, 0, CLI_BUFFER_SIZE);
104 SSVAL(p, 0, CLI_BUFFER_SIZE);
108 param, PTR_DIFF(p,param),1024, /* param, length, max */
109 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
110 &rparam, &rprcnt, /* return params, return size */
111 &rdata, &rdrcnt /* return data, return size */
113 cli->rap_error = rparam? SVAL(rparam,0) : -1;
116 if (cli->rap_error == 0) {
117 DEBUG(4,("NetWkstaUserLogon success\n"));
118 cli->privileges = SVAL(p, 24);
119 /* The cli->eff_name field used to be set here
120 but it wasn't used anywhere else. */
122 DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
128 return (cli->rap_error == 0);
131 /****************************************************************************
132 Call a NetShareEnum - try and browse available connections on a host.
133 ****************************************************************************/
135 int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
140 unsigned int rdrcnt,rprcnt;
144 /* now send a SMBtrans command with api RNetShareEnum */
146 SSVAL(p,0,0); /* api number */
148 strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
149 p = skip_string(param,sizeof(param),p);
150 strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
151 p = skip_string(param,sizeof(param),p);
154 * Win2k needs a *smaller* buffer than 0xFFFF here -
155 * it returns "out of server memory" with 0xFFFF !!! JRA.
161 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
162 NULL, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */
163 &rparam, &rprcnt, /* return params, length */
164 &rdata, &rdrcnt)) /* return data, length */
166 int res = rparam? SVAL(rparam,0) : -1;
168 if (res == 0 || res == ERRmoredata) {
169 int converter=SVAL(rparam,2);
171 char *rdata_end = rdata + rdrcnt;
173 count=SVAL(rparam,4);
176 for (i=0;i<count;i++,p+=20) {
184 TALLOC_CTX *frame = talloc_stackframe();
186 if (p + 20 > rdata_end) {
193 comment_offset = IVAL(p,16) & 0xFFFF;
194 if (comment_offset < 0 || comment_offset > (int)rdrcnt) {
198 cmnt = comment_offset?(rdata+comment_offset-converter):"";
200 /* Work out the comment length. */
201 for (p1 = cmnt, len = 0; *p1 &&
202 p1 < rdata_end; len++)
207 pull_string_talloc(frame,rdata,0,
208 &s1,sname,14,STR_ASCII);
209 pull_string_talloc(frame,rdata,0,
210 &s2,cmnt,len,STR_ASCII);
216 fn(s1, type, s2, state);
221 DEBUG(4,("NetShareEnum res=%d\n", res));
224 DEBUG(4,("NetShareEnum failed\n"));
233 /****************************************************************************
234 Call a NetServerEnum for the specified workgroup and servertype mask. This
235 function then calls the specified callback function for each name returned.
237 The callback function takes 4 arguments: the machine name, the server type,
238 the comment and a state pointer.
239 ****************************************************************************/
241 bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
242 void (*fn)(const char *, uint32, const char *, void *),
247 unsigned int rdrcnt,rprcnt;
254 errno = 0; /* reset */
256 /* send a SMBtrans command with api NetServerEnum */
258 SSVAL(p,0,0x68); /* api number */
260 strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
261 p = skip_string(param,sizeof(param),p);
263 strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
265 p = skip_string(param,sizeof(param),p);
267 SSVAL(p,2,CLI_BUFFER_SIZE);
272 len = push_ascii(p, workgroup, sizeof(param)-PTR_DIFF(p,param)-1,
273 STR_TERMINATE|STR_UPPER);
274 if (len == (size_t)-1) {
280 param, PTR_DIFF(p,param), 8, /* params, length, max */
281 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
282 &rparam, &rprcnt, /* return params, return size */
283 &rdata, &rdrcnt /* return data, return size */
285 int res = rparam? SVAL(rparam,0) : -1;
286 char *rdata_end = rdata + rdrcnt;
288 if (res == 0 || res == ERRmoredata ||
289 (res != -1 && cli_errno(cli) == 0)) {
291 int converter=SVAL(rparam,2);
293 count=SVAL(rparam,4);
296 for (i = 0;i < count;i++, p += 26) {
302 TALLOC_CTX *frame = talloc_stackframe();
304 if (p + 26 > rdata_end) {
310 comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
311 cmnt = comment_offset?(rdata+comment_offset):"";
313 if (comment_offset < 0 || comment_offset > (int)rdrcnt) {
318 /* Work out the comment length. */
319 for (p1 = cmnt, len = 0; *p1 &&
320 p1 < rdata_end; len++)
326 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
328 pull_string_talloc(frame,rdata,0,
329 &s1,sname,16,STR_ASCII);
330 pull_string_talloc(frame,rdata,0,
331 &s2,cmnt,len,STR_ASCII);
338 fn(s1, stype, s2, state);
348 errno = cli_errno(cli);
351 /* this is a very special case, when the domain master for the
352 work group isn't part of the work group itself, there is something
361 /****************************************************************************
362 Send a SamOEMChangePassword command.
363 ****************************************************************************/
365 bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
366 const char *old_password)
369 unsigned char data[532];
371 unsigned char old_pw_hash[16];
372 unsigned char new_pw_hash[16];
373 unsigned int data_len;
374 unsigned int param_len = 0;
377 unsigned int rprcnt, rdrcnt;
379 if (strlen(user) >= sizeof(fstring)-1) {
380 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
384 SSVAL(p,0,214); /* SamOEMChangePassword command. */
386 strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
387 p = skip_string(param,sizeof(param),p);
388 strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
389 p = skip_string(param,sizeof(param),p);
390 strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
391 p = skip_string(param,sizeof(param),p);
395 param_len = PTR_DIFF(p,param);
398 * Get the Lanman hash of the old password, we
399 * use this as the key to make_oem_passwd_hash().
401 E_deshash(old_password, old_pw_hash);
403 encode_pw_buffer(data, new_password, STR_ASCII);
405 #ifdef DEBUG_PASSWORD
406 DEBUG(100,("make_oem_passwd_hash\n"));
407 dump_data(100, data, 516);
409 SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
412 * Now place the old password hash in the data.
414 E_deshash(new_password, new_pw_hash);
416 E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
420 if (cli_send_trans(cli,SMBtrans,
421 PIPE_LANMAN, /* name */
422 0,0, /* fid, flags */
423 NULL,0,0, /* setup, length, max */
424 param,param_len,2, /* param, length, max */
425 (char *)data,data_len,0 /* data, length, max */
427 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
432 if (!cli_receive_trans(cli,SMBtrans,
435 DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n",
441 cli->rap_error = SVAL(rparam,0);
447 return (cli->rap_error == 0);
450 /****************************************************************************
451 Send a qpathinfo call.
452 ****************************************************************************/
454 bool cli_qpathinfo(struct cli_state *cli,
462 unsigned int data_len = 0;
463 unsigned int param_len = 0;
464 unsigned int rparam_len, rdata_len;
465 uint16 setup = TRANSACT2_QPATHINFO;
467 char *rparam=NULL, *rdata=NULL;
470 time_t (*date_fn)(struct cli_state *, const void *);
472 size_t nlen = 2*(strlen(fname)+1);
474 param = SMB_MALLOC(6+nlen+2);
480 SSVAL(p, 0, SMB_INFO_STANDARD);
482 p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
483 param_len = PTR_DIFF(p, param);
486 ret = (cli_send_trans(cli, SMBtrans2,
488 -1, 0, /* fid, flags */
489 &setup, 1, 0, /* setup, length, max */
490 param, param_len, 10, /* param, length, max */
491 NULL, data_len, cli->max_xmit /* data, length, max */
493 cli_receive_trans(cli, SMBtrans2,
494 &rparam, &rparam_len,
495 &rdata, &rdata_len));
496 if (!cli_is_dos_error(cli)) break;
498 /* we need to work around a Win95 bug - sometimes
499 it gives ERRSRV/ERRerror temprarily */
502 cli_dos_error(cli, &eclass, &ecode);
503 if (eclass != ERRSRV || ecode != ERRerror) break;
506 } while (count-- && ret==False);
509 if (!ret || !rdata || rdata_len < 22) {
514 date_fn = cli_make_unix_date;
516 date_fn = cli_make_unix_date2;
520 *change_time = date_fn(cli, rdata+0);
523 *access_time = date_fn(cli, rdata+4);
526 *write_time = date_fn(cli, rdata+8);
529 *size = IVAL(rdata, 12);
532 *mode = SVAL(rdata,l1_attrFile);
540 /****************************************************************************
541 Send a setpathinfo call.
542 ****************************************************************************/
544 bool cli_setpathinfo(struct cli_state *cli, const char *fname,
551 unsigned int data_len = 0;
552 unsigned int param_len = 0;
553 unsigned int rparam_len, rdata_len;
554 uint16 setup = TRANSACT2_SETPATHINFO;
557 char *rparam=NULL, *rdata=NULL;
561 size_t nlen = 2*(strlen(fname)+1);
563 param = SMB_MALLOC(6+nlen+2);
567 memset(param, '\0', 6);
568 memset(data, 0, sizeof(data));
572 /* Add the information level */
573 SSVAL(p, 0, SMB_FILE_BASIC_INFORMATION);
578 /* Add the file name */
579 p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
581 param_len = PTR_DIFF(p, param);
586 * Add the create, last access, modification, and status change times
588 put_long_date(p, create_time);
591 put_long_date(p, access_time);
594 put_long_date(p, write_time);
597 put_long_date(p, change_time);
608 data_len = PTR_DIFF(p, data);
611 ret = (cli_send_trans(cli, SMBtrans2,
613 -1, 0, /* fid, flags */
614 &setup, 1, 0, /* setup, length, max */
615 param, param_len, 10, /* param, length, max */
616 data, data_len, cli->max_xmit /* data, length, max */
618 cli_receive_trans(cli, SMBtrans2,
619 &rparam, &rparam_len,
620 &rdata, &rdata_len));
621 if (!cli_is_dos_error(cli)) break;
623 /* we need to work around a Win95 bug - sometimes
624 it gives ERRSRV/ERRerror temprarily */
627 cli_dos_error(cli, &eclass, &ecode);
628 if (eclass != ERRSRV || ecode != ERRerror) break;
631 } while (count-- && ret==False);
643 /****************************************************************************
644 Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
645 ****************************************************************************/
647 bool cli_qpathinfo2(struct cli_state *cli, const char *fname,
648 struct timespec *create_time,
649 struct timespec *access_time,
650 struct timespec *write_time,
651 struct timespec *change_time,
652 SMB_OFF_T *size, uint16 *mode,
655 unsigned int data_len = 0;
656 unsigned int param_len = 0;
657 uint16 setup = TRANSACT2_QPATHINFO;
659 char *rparam=NULL, *rdata=NULL;
661 size_t nlen = 2*(strlen(fname)+1);
663 param = SMB_MALLOC(6+nlen+2);
668 memset(param, '\0', 6);
669 SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
671 p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
673 param_len = PTR_DIFF(p, param);
675 if (!cli_send_trans(cli, SMBtrans2,
677 -1, 0, /* fid, flags */
678 &setup, 1, 0, /* setup, length, max */
679 param, param_len, 10, /* param, length, max */
680 NULL, data_len, cli->max_xmit /* data, length, max */
687 if (!cli_receive_trans(cli, SMBtrans2,
689 &rdata, &data_len)) {
693 if (!rdata || data_len < 22) {
698 *create_time = interpret_long_date(rdata+0);
701 *access_time = interpret_long_date(rdata+8);
704 *write_time = interpret_long_date(rdata+16);
707 *change_time = interpret_long_date(rdata+24);
710 *mode = SVAL(rdata, 32);
713 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
716 *ino = IVAL(rdata, 64);
724 /****************************************************************************
725 Send a qfileinfo QUERY_FILE_NAME_INFO call.
726 ****************************************************************************/
728 bool cli_qfilename(struct cli_state *cli, int fnum, char *name, size_t namelen)
730 unsigned int data_len = 0;
731 unsigned int param_len = 0;
732 uint16 setup = TRANSACT2_QFILEINFO;
734 char *rparam=NULL, *rdata=NULL;
737 SSVAL(param, 0, fnum);
738 SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
740 if (!cli_send_trans(cli, SMBtrans2,
742 -1, 0, /* fid, flags */
743 &setup, 1, 0, /* setup, length, max */
744 param, param_len, 2, /* param, length, max */
745 NULL, data_len, cli->max_xmit /* data, length, max */
750 if (!cli_receive_trans(cli, SMBtrans2,
752 &rdata, &data_len)) {
756 if (!rdata || data_len < 4) {
760 clistr_pull(cli, name, rdata+4, namelen, IVAL(rdata, 0), STR_UNICODE);
765 /****************************************************************************
766 Send a qfileinfo call.
767 ****************************************************************************/
769 bool cli_qfileinfo(struct cli_state *cli, int fnum,
770 uint16 *mode, SMB_OFF_T *size,
771 struct timespec *create_time,
772 struct timespec *access_time,
773 struct timespec *write_time,
774 struct timespec *change_time,
777 unsigned int data_len = 0;
778 unsigned int param_len = 0;
779 uint16 setup = TRANSACT2_QFILEINFO;
781 char *rparam=NULL, *rdata=NULL;
783 /* if its a win95 server then fail this - win95 totally screws it
785 if (cli->win95) return False;
789 SSVAL(param, 0, fnum);
790 SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
792 if (!cli_send_trans(cli, SMBtrans2,
794 -1, 0, /* fid, flags */
795 &setup, 1, 0, /* setup, length, max */
796 param, param_len, 2, /* param, length, max */
797 NULL, data_len, cli->max_xmit /* data, length, max */
802 if (!cli_receive_trans(cli, SMBtrans2,
804 &rdata, &data_len)) {
808 if (!rdata || data_len < 68) {
813 *create_time = interpret_long_date(rdata+0);
816 *access_time = interpret_long_date(rdata+8);
819 *write_time = interpret_long_date(rdata+16);
822 *change_time = interpret_long_date(rdata+24);
825 *mode = SVAL(rdata, 32);
828 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
831 *ino = IVAL(rdata, 64);
839 /****************************************************************************
840 Send a qpathinfo BASIC_INFO call.
841 ****************************************************************************/
843 bool cli_qpathinfo_basic( struct cli_state *cli, const char *name,
844 SMB_STRUCT_STAT *sbuf, uint32 *attributes )
846 unsigned int param_len = 0;
847 unsigned int data_len = 0;
848 uint16 setup = TRANSACT2_QPATHINFO;
850 char *rparam=NULL, *rdata=NULL;
855 TALLOC_CTX *frame = talloc_stackframe();
857 path = talloc_strdup(frame, name);
865 if ( path[len-1] == '\\' || path[len-1] == '/') {
868 nlen = 2*(strlen(path)+1);
870 param = TALLOC_ARRAY(frame,char,6+nlen+2);
875 memset(param, '\0', 6);
877 SSVAL(p, 0, SMB_QUERY_FILE_BASIC_INFO);
879 p += clistr_push(cli, p, path, nlen, STR_TERMINATE);
880 param_len = PTR_DIFF(p, param);
883 if (!cli_send_trans(cli, SMBtrans2,
885 -1, 0, /* fid, flags */
886 &setup, 1, 0, /* setup, length, max */
887 param, param_len, 2, /* param, length, max */
888 NULL, 0, cli->max_xmit /* data, length, max */
896 if (!cli_receive_trans(cli, SMBtrans2,
898 &rdata, &data_len)) {
908 set_atimespec(sbuf, interpret_long_date( rdata+8 )); /* Access time. */
909 set_mtimespec(sbuf, interpret_long_date( rdata+16 )); /* Write time. */
910 set_ctimespec(sbuf, interpret_long_date( rdata+24 )); /* Change time. */
912 *attributes = IVAL( rdata, 32 );
920 /****************************************************************************
921 Send a qfileinfo call.
922 ****************************************************************************/
924 bool cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen)
926 unsigned int data_len = 0;
927 unsigned int param_len = 0;
928 uint16 setup = TRANSACT2_QFILEINFO;
930 char *rparam=NULL, *rdata=NULL;
935 /* if its a win95 server then fail this - win95 totally screws it
942 SSVAL(param, 0, fnum);
943 SSVAL(param, 2, level);
945 if (!cli_send_trans(cli, SMBtrans2,
947 -1, 0, /* fid, flags */
948 &setup, 1, 0, /* setup, length, max */
949 param, param_len, 2, /* param, length, max */
950 NULL, data_len, cli->max_xmit /* data, length, max */
955 if (!cli_receive_trans(cli, SMBtrans2,
957 &rdata, &data_len)) {
961 *poutdata = (char *)memdup(rdata, data_len);
975 /****************************************************************************
976 Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
977 ****************************************************************************/
979 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
981 unsigned int data_len = 0;
982 unsigned int param_len = 0;
983 uint16 setup = TRANSACT2_QPATHINFO;
985 char *rparam=NULL, *rdata=NULL;
990 size_t nlen = 2*(strlen(fname)+1);
992 param = SMB_MALLOC(6+nlen+2);
994 return NT_STATUS_NO_MEMORY;
997 memset(param, '\0', 6);
998 SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
1000 p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
1001 param_len = PTR_DIFF(p, param);
1004 ret = (cli_send_trans(cli, SMBtrans2,
1006 -1, 0, /* fid, flags */
1007 &setup, 1, 0, /* setup, length, max */
1008 param, param_len, 10, /* param, length, max */
1009 NULL, data_len, cli->max_xmit /* data, length, max */
1011 cli_receive_trans(cli, SMBtrans2,
1012 &rparam, ¶m_len,
1013 &rdata, &data_len));
1014 if (!ret && cli_is_dos_error(cli)) {
1015 /* we need to work around a Win95 bug - sometimes
1016 it gives ERRSRV/ERRerror temprarily */
1019 cli_dos_error(cli, &eclass, &ecode);
1020 if (eclass != ERRSRV || ecode != ERRerror) break;
1023 } while (count-- && ret==False);
1027 if (!ret || !rdata || data_len < 4) {
1028 return NT_STATUS_UNSUCCESSFUL;
1031 len = IVAL(rdata, 0);
1033 if (len > data_len - 4) {
1034 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1037 clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, STR_UNICODE);
1042 return NT_STATUS_OK;