automatically uppercase server and share names (win95 won't handle
[Samba/gbeck.git] / source / libsmb / clientgen.c
blob550f7cc391dc4d3379f748c16f7fe201459a8ea8
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 SMB client generic functions
5 Copyright (C) Andrew Tridgell 1994-1998
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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #define NO_SYSLOG
24 #include "includes.h"
25 #include "trans2.h"
28 extern int DEBUGLEVEL;
31 /****************************************************************************
32 recv an smb
33 ****************************************************************************/
34 static BOOL cli_receive_smb(struct cli_state *cli)
36 return client_receive_smb(cli->fd,cli->inbuf,cli->timeout);
39 /****************************************************************************
40 send an smb to a fd and re-establish if necessary
41 ****************************************************************************/
42 static BOOL cli_send_smb(struct cli_state *cli)
44 size_t len;
45 size_t nwritten=0;
46 ssize_t ret;
47 BOOL reestablished=False;
49 len = smb_len(cli->outbuf) + 4;
51 while (nwritten < len) {
52 ret = write_socket(cli->fd,cli->outbuf+nwritten,len - nwritten);
53 if (ret <= 0 && errno == EPIPE && !reestablished) {
54 if (cli_reestablish_connection(cli)) {
55 reestablished = True;
56 nwritten=0;
57 continue;
60 if (ret <= 0) {
61 DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",
62 len,ret));
63 close_sockets();
64 exit(1);
66 nwritten += ret;
69 return True;
72 /*****************************************************
73 RAP error codes - a small start but will be extended.
74 *******************************************************/
76 struct
78 int err;
79 char *message;
80 } rap_errmap[] =
82 {5, "User has insufficient privilege" },
83 {86, "The specified password is invalid" },
84 {2226, "Operation only permitted on a Primary Domain Controller" },
85 {2242, "The password of this user has expired." },
86 {2243, "The password of this user cannot change." },
87 {2244, "This password cannot be used now (password history conflict)." },
88 {2245, "The password is shorter than required." },
89 {2246, "The password of this user is too recent to change."},
90 {0, NULL}
91 };
93 /****************************************************************************
94 return a description of an SMB error
95 ****************************************************************************/
96 static char *cli_smb_errstr(struct cli_state *cli)
98 return smb_errstr(cli->inbuf);
101 /******************************************************
102 Return an error message - either an SMB error or a RAP
103 error.
104 *******************************************************/
106 char *cli_errstr(struct cli_state *cli)
108 static fstring error_message;
109 uint8 errclass;
110 uint32 errnum;
111 int i;
114 * Errors are of three kinds - smb errors,
115 * dealt with by cli_smb_errstr, NT errors,
116 * whose code is in cli.nt_error, and rap
117 * errors, whose error code is in cli.rap_error.
120 cli_error(cli, &errclass, &errnum);
122 if (errclass != 0)
124 return cli_smb_errstr(cli);
128 * Was it an NT error ?
131 if (cli->nt_error)
133 char *nt_msg = get_nt_error_msg(cli->nt_error);
135 if (nt_msg == NULL)
137 slprintf(error_message, sizeof(fstring) - 1, "NT code %d", cli->nt_error);
139 else
141 fstrcpy(error_message, nt_msg);
144 return error_message;
148 * Must have been a rap error.
151 slprintf(error_message, sizeof(error_message) - 1, "code %d", cli->rap_error);
153 for (i = 0; rap_errmap[i].message != NULL; i++)
155 if (rap_errmap[i].err == cli->rap_error)
157 fstrcpy( error_message, rap_errmap[i].message);
158 break;
162 return error_message;
165 /****************************************************************************
166 setup basics in a outgoing packet
167 ****************************************************************************/
168 static void cli_setup_packet(struct cli_state *cli)
170 cli->rap_error = 0;
171 cli->nt_error = 0;
172 SSVAL(cli->outbuf,smb_pid,cli->pid);
173 SSVAL(cli->outbuf,smb_uid,cli->vuid);
174 SSVAL(cli->outbuf,smb_mid,cli->mid);
175 if (cli->protocol > PROTOCOL_CORE) {
176 SCVAL(cli->outbuf,smb_flg,0x8);
177 SSVAL(cli->outbuf,smb_flg2,0x1);
182 /*****************************************************************************
183 Convert a character pointer in a cli_call_api() response to a form we can use.
184 This function contains code to prevent core dumps if the server returns
185 invalid data.
186 *****************************************************************************/
187 static char *fix_char_ptr(unsigned int datap, unsigned int converter,
188 char *rdata, int rdrcnt)
190 if (datap == 0) { /* turn NULL pointers into zero length strings */
191 return "";
192 } else {
193 unsigned int offset = datap - converter;
195 if (offset >= rdrcnt) {
196 DEBUG(1,("bad char ptr: datap=%u, converter=%u rdrcnt=%d>",
197 datap, converter, rdrcnt));
198 return "<ERROR>";
199 } else {
200 return &rdata[offset];
205 /****************************************************************************
206 send a SMB trans or trans2 request
207 ****************************************************************************/
208 static BOOL cli_send_trans(struct cli_state *cli, int trans,
209 char *name, int pipe_name_len,
210 int fid, int flags,
211 uint16 *setup, int lsetup, int msetup,
212 char *param, int lparam, int mparam,
213 char *data, int ldata, int mdata)
215 int i;
216 int this_ldata,this_lparam;
217 int tot_data=0,tot_param=0;
218 char *outdata,*outparam;
219 char *p;
221 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
222 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
224 bzero(cli->outbuf,smb_size);
225 set_message(cli->outbuf,14+lsetup,0,True);
226 CVAL(cli->outbuf,smb_com) = trans;
227 SSVAL(cli->outbuf,smb_tid, cli->cnum);
228 cli_setup_packet(cli);
230 outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len+1 : 3);
231 outdata = outparam+this_lparam;
233 /* primary request */
234 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
235 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
236 SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */
237 SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */
238 SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */
239 SSVAL(cli->outbuf,smb_flags,flags); /* flags */
240 SIVAL(cli->outbuf,smb_timeout,0); /* timeout */
241 SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */
242 SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
243 SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */
244 SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
245 SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */
246 for (i=0;i<lsetup;i++) /* setup[] */
247 SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
248 p = smb_buf(cli->outbuf);
249 if (trans==SMBtrans) {
250 memcpy(p,name, pipe_name_len + 1); /* name[] */
251 } else {
252 *p++ = 0; /* put in a null smb_name */
253 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
255 if (this_lparam) /* param[] */
256 memcpy(outparam,param,this_lparam);
257 if (this_ldata) /* data[] */
258 memcpy(outdata,data,this_ldata);
259 set_message(cli->outbuf,14+lsetup, /* wcnt, bcc */
260 PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
262 show_msg(cli->outbuf);
263 cli_send_smb(cli);
265 if (this_ldata < ldata || this_lparam < lparam) {
266 /* receive interim response */
267 if (!cli_receive_smb(cli) ||
268 CVAL(cli->inbuf,smb_rcls) != 0) {
269 return(False);
272 tot_data = this_ldata;
273 tot_param = this_lparam;
275 while (tot_data < ldata || tot_param < lparam) {
276 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
277 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
279 set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
280 CVAL(cli->outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
282 outparam = smb_buf(cli->outbuf);
283 outdata = outparam+this_lparam;
285 /* secondary request */
286 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
287 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
288 SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */
289 SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
290 SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */
291 SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */
292 SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
293 SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */
294 if (trans==SMBtrans2)
295 SSVALS(cli->outbuf,smb_sfid,fid); /* fid */
296 if (this_lparam) /* param[] */
297 memcpy(outparam,param,this_lparam);
298 if (this_ldata) /* data[] */
299 memcpy(outdata,data,this_ldata);
300 set_message(cli->outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
301 PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
303 show_msg(cli->outbuf);
304 cli_send_smb(cli);
306 tot_data += this_ldata;
307 tot_param += this_lparam;
311 return(True);
315 /****************************************************************************
316 receive a SMB trans or trans2 response allocating the necessary memory
317 ****************************************************************************/
318 static BOOL cli_receive_trans(struct cli_state *cli,int trans,
319 char **param, int *param_len,
320 char **data, int *data_len)
322 int total_data=0;
323 int total_param=0;
324 int this_data,this_param;
326 *data_len = *param_len = 0;
328 if (!cli_receive_smb(cli))
329 return False;
331 show_msg(cli->inbuf);
333 /* sanity check */
334 if (CVAL(cli->inbuf,smb_com) != trans) {
335 DEBUG(0,("Expected %s response, got command 0x%02x\n",
336 trans==SMBtrans?"SMBtrans":"SMBtrans2",
337 CVAL(cli->inbuf,smb_com)));
338 return(False);
341 if (cli_error(cli, NULL, NULL))
343 return(False);
346 /* parse out the lengths */
347 total_data = SVAL(cli->inbuf,smb_tdrcnt);
348 total_param = SVAL(cli->inbuf,smb_tprcnt);
350 /* allocate it */
351 *data = Realloc(*data,total_data);
352 *param = Realloc(*param,total_param);
354 while (1) {
355 this_data = SVAL(cli->inbuf,smb_drcnt);
356 this_param = SVAL(cli->inbuf,smb_prcnt);
358 if (this_data + *data_len > total_data ||
359 this_param + *param_len > total_param) {
360 DEBUG(1,("Data overflow in cli_receive_trans\n"));
361 return False;
364 if (this_data)
365 memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
366 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
367 this_data);
368 if (this_param)
369 memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
370 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff),
371 this_param);
372 *data_len += this_data;
373 *param_len += this_param;
375 /* parse out the total lengths again - they can shrink! */
376 total_data = SVAL(cli->inbuf,smb_tdrcnt);
377 total_param = SVAL(cli->inbuf,smb_tprcnt);
379 if (total_data <= *data_len && total_param <= *param_len)
380 break;
382 if (!cli_receive_smb(cli))
383 return False;
385 show_msg(cli->inbuf);
387 /* sanity check */
388 if (CVAL(cli->inbuf,smb_com) != trans) {
389 DEBUG(0,("Expected %s response, got command 0x%02x\n",
390 trans==SMBtrans?"SMBtrans":"SMBtrans2",
391 CVAL(cli->inbuf,smb_com)));
392 return(False);
394 if (cli_error(cli, NULL, NULL))
396 return(False);
400 return(True);
403 /****************************************************************************
404 Call a remote api on an arbitrary pipe. takes param, data and setup buffers.
405 ****************************************************************************/
406 BOOL cli_api_pipe(struct cli_state *cli, char *pipe_name, int pipe_name_len,
407 uint16 *setup, uint32 setup_count, uint32 max_setup_count,
408 char *params, uint32 param_count, uint32 max_param_count,
409 char *data, uint32 data_count, uint32 max_data_count,
410 char **rparam, uint32 *rparam_count,
411 char **rdata, uint32 *rdata_count)
413 if (pipe_name_len == 0)
414 pipe_name_len = strlen(pipe_name);
416 cli_send_trans(cli, SMBtrans,
417 pipe_name, pipe_name_len,
418 0,0, /* fid, flags */
419 setup, setup_count, max_setup_count,
420 params, param_count, max_param_count,
421 data, data_count, max_data_count);
423 return (cli_receive_trans(cli, SMBtrans,
424 rparam, (int *)rparam_count,
425 rdata, (int *)rdata_count));
428 /****************************************************************************
429 call a remote api
430 ****************************************************************************/
431 BOOL cli_api(struct cli_state *cli,
432 char *param, int prcnt, int mprcnt,
433 char *data, int drcnt, int mdrcnt,
434 char **rparam, int *rprcnt,
435 char **rdata, int *rdrcnt)
437 cli_send_trans(cli,SMBtrans,
438 PIPE_LANMAN,strlen(PIPE_LANMAN), /* Name, length */
439 0,0, /* fid, flags */
440 NULL,0,0, /* Setup, length, max */
441 param, prcnt, mprcnt, /* Params, length, max */
442 data, drcnt, mdrcnt /* Data, length, max */
445 return (cli_receive_trans(cli,SMBtrans,
446 rparam, rprcnt,
447 rdata, rdrcnt));
451 /****************************************************************************
452 perform a NetWkstaUserLogon
453 ****************************************************************************/
454 BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
456 char *rparam = NULL;
457 char *rdata = NULL;
458 char *p;
459 int rdrcnt,rprcnt;
460 pstring param;
462 memset(param, 0, sizeof(param));
464 /* send a SMBtrans command with api NetWkstaUserLogon */
465 p = param;
466 SSVAL(p,0,132); /* api number */
467 p += 2;
468 pstrcpy(p,"OOWb54WrLh");
469 p = skip_string(p,1);
470 pstrcpy(p,"WB21BWDWWDDDDDDDzzzD");
471 p = skip_string(p,1);
472 SSVAL(p,0,1);
473 p += 2;
474 pstrcpy(p,user);
475 strupper(p);
476 p += 21;
477 p++;
478 p += 15;
479 p++;
480 pstrcpy(p, workstation);
481 strupper(p);
482 p += 16;
483 SSVAL(p, 0, CLI_BUFFER_SIZE);
484 p += 2;
485 SSVAL(p, 0, CLI_BUFFER_SIZE);
486 p += 2;
488 if (cli_api(cli,
489 param, PTR_DIFF(p,param),1024, /* param, length, max */
490 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
491 &rparam, &rprcnt, /* return params, return size */
492 &rdata, &rdrcnt /* return data, return size */
493 )) {
494 cli->rap_error = SVAL(rparam,0);
495 p = rdata;
497 if (cli->rap_error == 0) {
498 DEBUG(4,("NetWkstaUserLogon success\n"));
499 cli->privilages = SVAL(p, 24);
500 fstrcpy(cli->eff_name,p+2);
501 } else {
502 DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
506 if (rparam)
507 free(rparam);
508 if (rdata)
509 free(rdata);
510 return (cli->rap_error == 0);
513 /****************************************************************************
514 call a NetShareEnum - try and browse available connections on a host
515 ****************************************************************************/
516 BOOL cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *))
518 char *rparam = NULL;
519 char *rdata = NULL;
520 char *p;
521 int rdrcnt,rprcnt;
522 pstring param;
523 int count = -1;
525 /* now send a SMBtrans command with api RNetShareEnum */
526 p = param;
527 SSVAL(p,0,0); /* api number */
528 p += 2;
529 pstrcpy(p,"WrLeh");
530 p = skip_string(p,1);
531 pstrcpy(p,"B13BWz");
532 p = skip_string(p,1);
533 SSVAL(p,0,1);
534 SSVAL(p,2,0xFFFF);
535 p += 4;
537 if (cli_api(cli,
538 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
539 NULL, 0, 0xFFFF, /* data, length, maxlen */
540 &rparam, &rprcnt, /* return params, length */
541 &rdata, &rdrcnt)) /* return data, length */
543 int res = SVAL(rparam,0);
544 int converter=SVAL(rparam,2);
545 int i;
547 if (res == 0 || res == ERRmoredata) {
548 count=SVAL(rparam,4);
549 p = rdata;
551 for (i=0;i<count;i++,p+=20) {
552 char *sname = p;
553 int type = SVAL(p,14);
554 int comment_offset = IVAL(p,16) & 0xFFFF;
555 char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
556 fn(sname, type, cmnt);
558 } else {
559 DEBUG(4,("NetShareEnum res=%d\n", res));
561 } else {
562 DEBUG(4,("NetShareEnum failed\n"));
565 if (rparam)
566 free(rparam);
567 if (rdata)
568 free(rdata);
570 return count;
574 /****************************************************************************
575 call a NetServerEnum for the specified workgroup and servertype mask.
576 This function then calls the specified callback function for each name returned.
578 The callback function takes 3 arguments: the machine name, the server type and
579 the comment.
580 ****************************************************************************/
581 BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
582 void (*fn)(const char *, uint32, const char *))
584 char *rparam = NULL;
585 char *rdata = NULL;
586 int rdrcnt,rprcnt;
587 char *p;
588 pstring param;
589 int uLevel = 1;
590 int count = -1;
592 /* send a SMBtrans command with api NetServerEnum */
593 p = param;
594 SSVAL(p,0,0x68); /* api number */
595 p += 2;
596 pstrcpy(p,"WrLehDz");
597 p = skip_string(p,1);
599 pstrcpy(p,"B16BBDz");
601 p = skip_string(p,1);
602 SSVAL(p,0,uLevel);
603 SSVAL(p,2,CLI_BUFFER_SIZE);
604 p += 4;
605 SIVAL(p,0,stype);
606 p += 4;
608 pstrcpy(p, workgroup);
609 p = skip_string(p,1);
611 if (cli_api(cli,
612 param, PTR_DIFF(p,param), 8, /* params, length, max */
613 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
614 &rparam, &rprcnt, /* return params, return size */
615 &rdata, &rdrcnt /* return data, return size */
616 )) {
617 int res = SVAL(rparam,0);
618 int converter=SVAL(rparam,2);
619 int i;
621 if (res == 0 || res == ERRmoredata) {
622 count=SVAL(rparam,4);
623 p = rdata;
625 for (i = 0;i < count;i++, p += 26) {
626 char *sname = p;
627 int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
628 char *cmnt = comment_offset?(rdata+comment_offset):"";
629 if (comment_offset < 0 || comment_offset > rdrcnt) continue;
631 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
633 fn(sname, stype, cmnt);
638 if (rparam)
639 free(rparam);
640 if (rdata)
641 free(rdata);
643 return(count > 0);
649 static struct {
650 int prot;
651 char *name;
653 prots[] =
655 {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
656 {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
657 {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
658 {PROTOCOL_LANMAN1,"LANMAN1.0"},
659 {PROTOCOL_LANMAN2,"LM1.2X002"},
660 {PROTOCOL_LANMAN2,"Samba"},
661 {PROTOCOL_NT1,"NT LANMAN 1.0"},
662 {PROTOCOL_NT1,"NT LM 0.12"},
663 {-1,NULL}
667 /****************************************************************************
668 send a session setup
669 ****************************************************************************/
670 BOOL cli_session_setup(struct cli_state *cli,
671 char *user,
672 char *pass, int passlen,
673 char *ntpass, int ntpasslen,
674 char *workgroup)
676 char *p;
677 fstring pword, ntpword;
679 if (cli->protocol < PROTOCOL_LANMAN1)
680 return True;
682 if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
683 return False;
686 if (((passlen == 0) || (passlen == 1)) && (pass[0] == '\0')) {
687 /* Null session connect. */
688 pword[0] = '\0';
689 ntpword[0] = '\0';
690 } else {
691 if ((cli->sec_mode & 2) && passlen != 24) {
692 passlen = 24;
693 ntpasslen = 24;
694 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
695 SMBNTencrypt((uchar *)ntpass,(uchar *)cli->cryptkey,(uchar *)ntpword);
696 } else {
697 fstrcpy(pword, pass);
698 fstrcpy(ntpword, "");
699 ntpasslen = 0;
703 /* if in share level security then don't send a password now */
704 if (!(cli->sec_mode & 1)) {
705 fstrcpy(pword, "");
706 passlen=1;
707 fstrcpy(ntpword, "");
708 ntpasslen=1;
711 /* send a session setup command */
712 bzero(cli->outbuf,smb_size);
714 if (cli->protocol < PROTOCOL_NT1)
716 set_message(cli->outbuf,10,1 + strlen(user) + passlen,True);
717 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
718 cli_setup_packet(cli);
720 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
721 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
722 SSVAL(cli->outbuf,smb_vwv3,2);
723 SSVAL(cli->outbuf,smb_vwv4,1);
724 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
725 SSVAL(cli->outbuf,smb_vwv7,passlen);
726 p = smb_buf(cli->outbuf);
727 memcpy(p,pword,passlen);
728 p += passlen;
729 pstrcpy(p,user);
730 strupper(p);
732 else
734 set_message(cli->outbuf,13,0,True);
735 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
736 cli_setup_packet(cli);
738 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
739 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
740 SSVAL(cli->outbuf,smb_vwv3,2);
741 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
742 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
743 SSVAL(cli->outbuf,smb_vwv7,passlen);
744 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
745 SSVAL(cli->outbuf,smb_vwv11,0);
746 p = smb_buf(cli->outbuf);
747 memcpy(p,pword,passlen);
748 p += SVAL(cli->outbuf,smb_vwv7);
749 memcpy(p,ntpword,ntpasslen);
750 p += SVAL(cli->outbuf,smb_vwv8);
751 pstrcpy(p,user);
752 strupper(p);
753 p = skip_string(p,1);
754 pstrcpy(p,workgroup);
755 strupper(p);
756 p = skip_string(p,1);
757 pstrcpy(p,"Unix");p = skip_string(p,1);
758 pstrcpy(p,"Samba");p = skip_string(p,1);
759 set_message(cli->outbuf,13,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
762 cli_send_smb(cli);
763 if (!cli_receive_smb(cli))
764 return False;
766 show_msg(cli->inbuf);
768 if (CVAL(cli->inbuf,smb_rcls) != 0) {
769 return False;
772 /* use the returned vuid from now on */
773 cli->vuid = SVAL(cli->inbuf,smb_uid);
775 if (cli->protocol >= PROTOCOL_NT1) {
777 * Save off some of the connected server
778 * info.
780 char *server_domain,*server_os,*server_type;
781 server_os = smb_buf(cli->inbuf);
782 server_type = skip_string(server_os,1);
783 server_domain = skip_string(server_type,1);
784 fstrcpy(cli->server_os, server_os);
785 fstrcpy(cli->server_type, server_type);
786 fstrcpy(cli->server_domain, server_domain);
789 fstrcpy(cli->user_name, user);
791 return True;
794 /****************************************************************************
795 Send a uloggoff.
796 *****************************************************************************/
798 BOOL cli_ulogoff(struct cli_state *cli)
800 bzero(cli->outbuf,smb_size);
801 set_message(cli->outbuf,2,0,True);
802 CVAL(cli->outbuf,smb_com) = SMBulogoffX;
803 cli_setup_packet(cli);
804 SSVAL(cli->outbuf,smb_vwv0,0xFF);
805 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
807 cli_send_smb(cli);
808 if (!cli_receive_smb(cli))
809 return False;
811 return CVAL(cli->inbuf,smb_rcls) == 0;
814 /****************************************************************************
815 send a tconX
816 ****************************************************************************/
817 BOOL cli_send_tconX(struct cli_state *cli,
818 char *share, char *dev, char *pass, int passlen)
820 fstring fullshare, pword;
821 char *p;
822 bzero(cli->outbuf,smb_size);
823 bzero(cli->inbuf,smb_size);
825 fstrcpy(cli->share, share);
827 /* in user level security don't send a password now */
828 if (cli->sec_mode & 1) {
829 passlen = 1;
830 pass = "";
833 if ((cli->sec_mode & 2) && *pass && passlen != 24) {
834 passlen = 24;
835 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
836 } else {
837 memcpy(pword, pass, passlen);
840 slprintf(fullshare, sizeof(fullshare)-1,
841 "\\\\%s\\%s", cli->desthost, share);
842 strupper(fullshare);
844 set_message(cli->outbuf,4,
845 2 + strlen(fullshare) + passlen + strlen(dev),True);
846 CVAL(cli->outbuf,smb_com) = SMBtconX;
847 cli_setup_packet(cli);
849 SSVAL(cli->outbuf,smb_vwv0,0xFF);
850 SSVAL(cli->outbuf,smb_vwv3,passlen);
852 p = smb_buf(cli->outbuf);
853 memcpy(p,pword,passlen);
854 p += passlen;
855 fstrcpy(p,fullshare);
856 p = skip_string(p,1);
857 pstrcpy(p,dev);
859 SCVAL(cli->inbuf,smb_rcls, 1);
861 cli_send_smb(cli);
862 if (!cli_receive_smb(cli))
863 return False;
865 if (CVAL(cli->inbuf,smb_rcls) != 0) {
866 return False;
869 fstrcpy(cli->dev, "A:");
871 if (cli->protocol >= PROTOCOL_NT1) {
872 fstrcpy(cli->dev, smb_buf(cli->inbuf));
875 if (strcasecmp(share,"IPC$")==0) {
876 fstrcpy(cli->dev, "IPC");
879 /* only grab the device if we have a recent protocol level */
880 if (cli->protocol >= PROTOCOL_NT1 &&
881 smb_buflen(cli->inbuf) == 3) {
882 /* almost certainly win95 - enable bug fixes */
883 cli->win95 = True;
886 cli->cnum = SVAL(cli->inbuf,smb_tid);
887 return True;
891 /****************************************************************************
892 send a tree disconnect
893 ****************************************************************************/
894 BOOL cli_tdis(struct cli_state *cli)
896 bzero(cli->outbuf,smb_size);
897 set_message(cli->outbuf,0,0,True);
898 CVAL(cli->outbuf,smb_com) = SMBtdis;
899 SSVAL(cli->outbuf,smb_tid,cli->cnum);
900 cli_setup_packet(cli);
902 cli_send_smb(cli);
903 if (!cli_receive_smb(cli))
904 return False;
906 return CVAL(cli->inbuf,smb_rcls) == 0;
909 /****************************************************************************
910 rename a file
911 ****************************************************************************/
912 BOOL cli_rename(struct cli_state *cli, char *fname_src, char *fname_dst)
914 char *p;
916 bzero(cli->outbuf,smb_size);
917 bzero(cli->inbuf,smb_size);
919 set_message(cli->outbuf,1, 4 + strlen(fname_src) + strlen(fname_dst), True);
921 CVAL(cli->outbuf,smb_com) = SMBmv;
922 SSVAL(cli->outbuf,smb_tid,cli->cnum);
923 cli_setup_packet(cli);
925 SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
927 p = smb_buf(cli->outbuf);
928 *p++ = 4;
929 pstrcpy(p,fname_src);
930 p = skip_string(p,1);
931 *p++ = 4;
932 pstrcpy(p,fname_dst);
934 cli_send_smb(cli);
935 if (!cli_receive_smb(cli)) {
936 return False;
939 if (CVAL(cli->inbuf,smb_rcls) != 0) {
940 return False;
943 return True;
946 /****************************************************************************
947 delete a file
948 ****************************************************************************/
949 BOOL cli_unlink(struct cli_state *cli, char *fname)
951 char *p;
953 bzero(cli->outbuf,smb_size);
954 bzero(cli->inbuf,smb_size);
956 set_message(cli->outbuf,1, 2 + strlen(fname),True);
958 CVAL(cli->outbuf,smb_com) = SMBunlink;
959 SSVAL(cli->outbuf,smb_tid,cli->cnum);
960 cli_setup_packet(cli);
962 SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
964 p = smb_buf(cli->outbuf);
965 *p++ = 4;
966 pstrcpy(p,fname);
968 cli_send_smb(cli);
969 if (!cli_receive_smb(cli)) {
970 return False;
973 if (CVAL(cli->inbuf,smb_rcls) != 0) {
974 return False;
977 return True;
980 /****************************************************************************
981 create a directory
982 ****************************************************************************/
983 BOOL cli_mkdir(struct cli_state *cli, char *dname)
985 char *p;
987 bzero(cli->outbuf,smb_size);
988 bzero(cli->inbuf,smb_size);
990 set_message(cli->outbuf,0, 2 + strlen(dname),True);
992 CVAL(cli->outbuf,smb_com) = SMBmkdir;
993 SSVAL(cli->outbuf,smb_tid,cli->cnum);
994 cli_setup_packet(cli);
996 p = smb_buf(cli->outbuf);
997 *p++ = 4;
998 pstrcpy(p,dname);
1000 cli_send_smb(cli);
1001 if (!cli_receive_smb(cli)) {
1002 return False;
1005 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1006 return False;
1009 return True;
1012 /****************************************************************************
1013 remove a directory
1014 ****************************************************************************/
1015 BOOL cli_rmdir(struct cli_state *cli, char *dname)
1017 char *p;
1019 bzero(cli->outbuf,smb_size);
1020 bzero(cli->inbuf,smb_size);
1022 set_message(cli->outbuf,0, 2 + strlen(dname),True);
1024 CVAL(cli->outbuf,smb_com) = SMBrmdir;
1025 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1026 cli_setup_packet(cli);
1028 p = smb_buf(cli->outbuf);
1029 *p++ = 4;
1030 pstrcpy(p,dname);
1032 cli_send_smb(cli);
1033 if (!cli_receive_smb(cli)) {
1034 return False;
1037 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1038 return False;
1041 return True;
1046 /****************************************************************************
1047 open a file
1048 ****************************************************************************/
1049 int cli_nt_create(struct cli_state *cli, char *fname)
1051 char *p;
1053 bzero(cli->outbuf,smb_size);
1054 bzero(cli->inbuf,smb_size);
1056 set_message(cli->outbuf,24,1 + strlen(fname),True);
1058 CVAL(cli->outbuf,smb_com) = SMBntcreateX;
1059 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1060 cli_setup_packet(cli);
1062 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1063 SIVAL(cli->outbuf,smb_ntcreate_Flags, 0x06);
1064 SIVAL(cli->outbuf,smb_ntcreate_RootDirectoryFid, 0x0);
1065 SIVAL(cli->outbuf,smb_ntcreate_DesiredAccess, 0x2019f);
1066 SIVAL(cli->outbuf,smb_ntcreate_FileAttributes, 0x0);
1067 SIVAL(cli->outbuf,smb_ntcreate_ShareAccess, 0x03);
1068 SIVAL(cli->outbuf,smb_ntcreate_CreateDisposition, 0x01);
1069 SIVAL(cli->outbuf,smb_ntcreate_CreateOptions, 0x0);
1070 SIVAL(cli->outbuf,smb_ntcreate_ImpersonationLevel, 0x02);
1071 SSVAL(cli->outbuf,smb_ntcreate_NameLength, strlen(fname));
1073 p = smb_buf(cli->outbuf);
1074 pstrcpy(p,fname);
1075 p = skip_string(p,1);
1077 cli_send_smb(cli);
1078 if (!cli_receive_smb(cli)) {
1079 return -1;
1082 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1083 return -1;
1086 return SVAL(cli->inbuf,smb_vwv2 + 1);
1090 /****************************************************************************
1091 open a file
1092 ****************************************************************************/
1093 int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode)
1095 char *p;
1096 unsigned openfn=0;
1097 unsigned accessmode=0;
1099 /* you must open for RW not just write - otherwise getattrE doesn't
1100 work! */
1101 if ((flags & O_ACCMODE) == O_WRONLY && strncmp(cli->dev, "LPT", 3)) {
1102 flags = (flags & ~O_ACCMODE) | O_RDWR;
1105 if (flags & O_CREAT)
1106 openfn |= (1<<4);
1107 if (!(flags & O_EXCL)) {
1108 if (flags & O_TRUNC)
1109 openfn |= (1<<1);
1110 else
1111 openfn |= (1<<0);
1114 accessmode = (share_mode<<4);
1116 if ((flags & O_ACCMODE) == O_RDWR) {
1117 accessmode |= 2;
1118 } else if ((flags & O_ACCMODE) == O_WRONLY) {
1119 accessmode |= 1;
1122 #if defined(O_SYNC)
1123 if ((flags & O_SYNC) == O_SYNC) {
1124 accessmode |= (1<<14);
1126 #endif /* O_SYNC */
1128 bzero(cli->outbuf,smb_size);
1129 bzero(cli->inbuf,smb_size);
1131 set_message(cli->outbuf,15,1 + strlen(fname),True);
1133 CVAL(cli->outbuf,smb_com) = SMBopenX;
1134 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1135 cli_setup_packet(cli);
1137 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1138 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
1139 SSVAL(cli->outbuf,smb_vwv3,accessmode);
1140 SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
1141 SSVAL(cli->outbuf,smb_vwv5,0);
1142 SSVAL(cli->outbuf,smb_vwv8,openfn);
1144 p = smb_buf(cli->outbuf);
1145 pstrcpy(p,fname);
1146 p = skip_string(p,1);
1148 cli_send_smb(cli);
1149 if (!cli_receive_smb(cli)) {
1150 return -1;
1153 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1154 return -1;
1157 return SVAL(cli->inbuf,smb_vwv2);
1163 /****************************************************************************
1164 close a file
1165 ****************************************************************************/
1166 BOOL cli_close(struct cli_state *cli, int fnum)
1168 bzero(cli->outbuf,smb_size);
1169 bzero(cli->inbuf,smb_size);
1171 set_message(cli->outbuf,3,0,True);
1173 CVAL(cli->outbuf,smb_com) = SMBclose;
1174 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1175 cli_setup_packet(cli);
1177 SSVAL(cli->outbuf,smb_vwv0,fnum);
1178 SIVALS(cli->outbuf,smb_vwv1,-1);
1180 cli_send_smb(cli);
1181 if (!cli_receive_smb(cli)) {
1182 return False;
1185 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1186 return False;
1189 return True;
1193 /****************************************************************************
1194 lock a file
1195 ****************************************************************************/
1196 BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
1198 char *p;
1199 int saved_timeout = cli->timeout;
1201 bzero(cli->outbuf,smb_size);
1202 bzero(cli->inbuf,smb_size);
1204 set_message(cli->outbuf,8,10,True);
1206 CVAL(cli->outbuf,smb_com) = SMBlockingX;
1207 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1208 cli_setup_packet(cli);
1210 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1211 SSVAL(cli->outbuf,smb_vwv2,fnum);
1212 CVAL(cli->outbuf,smb_vwv3) = 0;
1213 SIVALS(cli->outbuf, smb_vwv4, timeout);
1214 SSVAL(cli->outbuf,smb_vwv6,0);
1215 SSVAL(cli->outbuf,smb_vwv7,1);
1217 p = smb_buf(cli->outbuf);
1218 SSVAL(p, 0, cli->pid);
1219 SIVAL(p, 2, offset);
1220 SIVAL(p, 6, len);
1221 cli_send_smb(cli);
1223 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : timeout;
1225 if (!cli_receive_smb(cli)) {
1226 cli->timeout = saved_timeout;
1227 return False;
1230 cli->timeout = saved_timeout;
1232 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1233 return False;
1236 return True;
1239 /****************************************************************************
1240 unlock a file
1241 ****************************************************************************/
1242 BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
1244 char *p;
1246 bzero(cli->outbuf,smb_size);
1247 bzero(cli->inbuf,smb_size);
1249 set_message(cli->outbuf,8,10,True);
1251 CVAL(cli->outbuf,smb_com) = SMBlockingX;
1252 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1253 cli_setup_packet(cli);
1255 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1256 SSVAL(cli->outbuf,smb_vwv2,fnum);
1257 CVAL(cli->outbuf,smb_vwv3) = 0;
1258 SIVALS(cli->outbuf, smb_vwv4, timeout);
1259 SSVAL(cli->outbuf,smb_vwv6,1);
1260 SSVAL(cli->outbuf,smb_vwv7,0);
1262 p = smb_buf(cli->outbuf);
1263 SSVAL(p, 0, cli->pid);
1264 SIVAL(p, 2, offset);
1265 SIVAL(p, 6, len);
1267 cli_send_smb(cli);
1268 if (!cli_receive_smb(cli)) {
1269 return False;
1272 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1273 return False;
1276 return True;
1281 /****************************************************************************
1282 issue a single SMBread and don't wait for a reply
1283 ****************************************************************************/
1284 static void cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
1285 size_t size, int i)
1287 bzero(cli->outbuf,smb_size);
1288 bzero(cli->inbuf,smb_size);
1290 set_message(cli->outbuf,10,0,True);
1292 CVAL(cli->outbuf,smb_com) = SMBreadX;
1293 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1294 cli_setup_packet(cli);
1296 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1297 SSVAL(cli->outbuf,smb_vwv2,fnum);
1298 SIVAL(cli->outbuf,smb_vwv3,offset);
1299 SSVAL(cli->outbuf,smb_vwv5,size);
1300 SSVAL(cli->outbuf,smb_vwv6,size);
1301 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1303 cli_send_smb(cli);
1306 /****************************************************************************
1307 read from a file
1308 ****************************************************************************/
1309 size_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
1311 char *p;
1312 int total = -1;
1313 int issued=0;
1314 int received=0;
1315 int mpx = MAX(cli->max_mux-1, 1);
1316 int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1317 int mid;
1318 int blocks = (size + (block-1)) / block;
1320 if (size == 0) return 0;
1322 while (received < blocks) {
1323 int size2;
1325 while (issued - received < mpx && issued < blocks) {
1326 int size1 = MIN(block, size-issued*block);
1327 cli_issue_read(cli, fnum, offset+issued*block, size1, issued);
1328 issued++;
1331 if (!cli_receive_smb(cli)) {
1332 return total;
1335 received++;
1336 mid = SVAL(cli->inbuf, smb_mid) - cli->mid;
1337 size2 = SVAL(cli->inbuf, smb_vwv5);
1339 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1340 blocks = MIN(blocks, mid-1);
1341 continue;
1344 if (size2 <= 0) {
1345 blocks = MIN(blocks, mid-1);
1346 /* this distinguishes EOF from an error */
1347 total = MAX(total, 0);
1348 continue;
1351 if (size2 > block) {
1352 DEBUG(0,("server returned more than we wanted!\n"));
1353 exit(1);
1355 if (mid >= issued) {
1356 DEBUG(0,("invalid mid from server!\n"));
1357 exit(1);
1359 p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
1361 memcpy(buf+mid*block, p, size2);
1363 total = MAX(total, mid*block + size2);
1366 while (received < issued) {
1367 cli_receive_smb(cli);
1368 received++;
1371 return total;
1375 /****************************************************************************
1376 issue a single SMBwrite and don't wait for a reply
1377 ****************************************************************************/
1378 static void cli_issue_write(struct cli_state *cli, int fnum, off_t offset, uint16 mode, char *buf,
1379 size_t size, int i)
1381 char *p;
1383 bzero(cli->outbuf,smb_size);
1384 bzero(cli->inbuf,smb_size);
1386 set_message(cli->outbuf,12,size,True);
1388 CVAL(cli->outbuf,smb_com) = SMBwriteX;
1389 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1390 cli_setup_packet(cli);
1392 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1393 SSVAL(cli->outbuf,smb_vwv2,fnum);
1395 SIVAL(cli->outbuf,smb_vwv3,offset);
1396 SIVAL(cli->outbuf,smb_vwv5,IS_BITS_SET_ALL(mode, 0x0008) ? 0xFFFFFFFF : 0);
1397 SSVAL(cli->outbuf,smb_vwv7,mode);
1399 SSVAL(cli->outbuf,smb_vwv8,IS_BITS_SET_ALL(mode, 0x0008) ? size : 0);
1400 SSVAL(cli->outbuf,smb_vwv10,size);
1401 SSVAL(cli->outbuf,smb_vwv11,
1402 smb_buf(cli->outbuf) - smb_base(cli->outbuf));
1404 p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
1405 memcpy(p, buf, size);
1407 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1409 show_msg(cli->outbuf);
1410 cli_send_smb(cli);
1413 /****************************************************************************
1414 write to a file
1415 write_mode: 0x0001 disallow write cacheing
1416 0x0002 return bytes remaining
1417 0x0004 use raw named pipe protocol
1418 0x0008 start of message mode named pipe protocol
1419 ****************************************************************************/
1420 ssize_t cli_write(struct cli_state *cli,
1421 int fnum, uint16 write_mode,
1422 char *buf, off_t offset, size_t size)
1424 int total = -1;
1425 int issued=0;
1426 int received=0;
1427 int mpx = MAX(cli->max_mux-1, 1);
1428 int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1429 int mid;
1430 int blocks = (size + (block-1)) / block;
1432 if (size == 0) return 0;
1434 while (received < blocks) {
1435 int size2;
1437 while (issued - received < mpx && issued < blocks) {
1438 int size1 = MIN(block, size-issued*block);
1439 cli_issue_write(cli, fnum, offset+issued*block,
1440 write_mode,
1441 buf + issued*block,
1442 size1, issued);
1443 issued++;
1446 if (!cli_receive_smb(cli)) {
1447 return total;
1450 received++;
1451 mid = SVAL(cli->inbuf, smb_mid) - cli->mid;
1452 size2 = SVAL(cli->inbuf, smb_vwv2);
1454 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1455 blocks = MIN(blocks, mid-1);
1456 continue;
1459 if (size2 <= 0) {
1460 blocks = MIN(blocks, mid-1);
1461 /* this distinguishes EOF from an error */
1462 total = MAX(total, 0);
1463 continue;
1466 total += size2;
1468 total = MAX(total, mid*block + size2);
1471 while (received < issued) {
1472 cli_receive_smb(cli);
1473 received++;
1476 return total;
1480 /****************************************************************************
1481 do a SMBgetattrE call
1482 ****************************************************************************/
1483 BOOL cli_getattrE(struct cli_state *cli, int fd,
1484 uint16 *attr, size_t *size,
1485 time_t *c_time, time_t *a_time, time_t *m_time)
1487 bzero(cli->outbuf,smb_size);
1488 bzero(cli->inbuf,smb_size);
1490 set_message(cli->outbuf,2,0,True);
1492 CVAL(cli->outbuf,smb_com) = SMBgetattrE;
1493 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1494 cli_setup_packet(cli);
1496 SSVAL(cli->outbuf,smb_vwv0,fd);
1498 cli_send_smb(cli);
1499 if (!cli_receive_smb(cli)) {
1500 return False;
1503 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1504 return False;
1507 if (size) {
1508 *size = IVAL(cli->inbuf, smb_vwv6);
1511 if (attr) {
1512 *attr = SVAL(cli->inbuf,smb_vwv10);
1515 if (c_time) {
1516 *c_time = make_unix_date3(cli->inbuf+smb_vwv0);
1519 if (a_time) {
1520 *a_time = make_unix_date3(cli->inbuf+smb_vwv2);
1523 if (m_time) {
1524 *m_time = make_unix_date3(cli->inbuf+smb_vwv4);
1527 return True;
1531 /****************************************************************************
1532 do a SMBgetatr call
1533 ****************************************************************************/
1534 BOOL cli_getatr(struct cli_state *cli, char *fname,
1535 uint16 *attr, size_t *size, time_t *t)
1537 char *p;
1539 bzero(cli->outbuf,smb_size);
1540 bzero(cli->inbuf,smb_size);
1542 set_message(cli->outbuf,0,strlen(fname)+2,True);
1544 CVAL(cli->outbuf,smb_com) = SMBgetatr;
1545 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1546 cli_setup_packet(cli);
1548 p = smb_buf(cli->outbuf);
1549 *p = 4;
1550 pstrcpy(p+1, fname);
1552 cli_send_smb(cli);
1553 if (!cli_receive_smb(cli)) {
1554 return False;
1557 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1558 return False;
1561 if (size) {
1562 *size = IVAL(cli->inbuf, smb_vwv3);
1565 if (t) {
1566 *t = make_unix_date3(cli->inbuf+smb_vwv1);
1569 if (attr) {
1570 *attr = SVAL(cli->inbuf,smb_vwv0);
1574 return True;
1578 /****************************************************************************
1579 do a SMBsetatr call
1580 ****************************************************************************/
1581 BOOL cli_setatr(struct cli_state *cli, char *fname, uint16 attr, time_t t)
1583 char *p;
1585 bzero(cli->outbuf,smb_size);
1586 bzero(cli->inbuf,smb_size);
1588 set_message(cli->outbuf,8,strlen(fname)+4,True);
1590 CVAL(cli->outbuf,smb_com) = SMBsetatr;
1591 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1592 cli_setup_packet(cli);
1594 SSVAL(cli->outbuf,smb_vwv0, attr);
1595 put_dos_date3(cli->outbuf,smb_vwv1, t);
1597 p = smb_buf(cli->outbuf);
1598 *p = 4;
1599 pstrcpy(p+1, fname);
1600 p = skip_string(p,1);
1601 *p = 4;
1603 cli_send_smb(cli);
1604 if (!cli_receive_smb(cli)) {
1605 return False;
1608 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1609 return False;
1612 return True;
1615 /****************************************************************************
1616 send a qpathinfo call
1617 ****************************************************************************/
1618 BOOL cli_qpathinfo(struct cli_state *cli, const char *fname,
1619 time_t *c_time, time_t *a_time, time_t *m_time,
1620 size_t *size, uint16 *mode)
1622 int data_len = 0;
1623 int param_len = 0;
1624 uint16 setup = TRANSACT2_QPATHINFO;
1625 pstring param;
1626 char *rparam=NULL, *rdata=NULL;
1627 int count=8;
1628 BOOL ret;
1629 time_t (*date_fn)(void *);
1631 param_len = strlen(fname) + 7;
1633 memset(param, 0, param_len);
1634 SSVAL(param, 0, SMB_INFO_STANDARD);
1635 pstrcpy(&param[6], fname);
1637 do {
1638 ret = (cli_send_trans(cli, SMBtrans2,
1639 NULL, 0, /* Name, length */
1640 -1, 0, /* fid, flags */
1641 &setup, 1, 0, /* setup, length, max */
1642 param, param_len, 10, /* param, length, max */
1643 NULL, data_len, cli->max_xmit /* data, length, max */
1644 ) &&
1645 cli_receive_trans(cli, SMBtrans2,
1646 &rparam, &param_len,
1647 &rdata, &data_len));
1648 if (!ret) {
1649 /* we need to work around a Win95 bug - sometimes
1650 it gives ERRSRV/ERRerror temprarily */
1651 uint8 eclass;
1652 uint32 ecode;
1653 cli_error(cli, &eclass, &ecode);
1654 if (eclass != ERRSRV || ecode != ERRerror) break;
1655 msleep(100);
1657 } while (count-- && ret==False);
1659 if (!ret || !rdata || data_len < 22) {
1660 return False;
1663 if (cli->win95) {
1664 date_fn = make_unix_date;
1665 } else {
1666 date_fn = make_unix_date2;
1669 if (c_time) {
1670 *c_time = date_fn(rdata+0);
1672 if (a_time) {
1673 *a_time = date_fn(rdata+4);
1675 if (m_time) {
1676 *m_time = date_fn(rdata+8);
1678 if (size) {
1679 *size = IVAL(rdata, 12);
1681 if (mode) {
1682 *mode = SVAL(rdata,l1_attrFile);
1685 if (rdata) free(rdata);
1686 if (rparam) free(rparam);
1687 return True;
1690 /****************************************************************************
1691 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
1692 ****************************************************************************/
1693 BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname,
1694 time_t *c_time, time_t *a_time, time_t *m_time,
1695 time_t *w_time, size_t *size, uint16 *mode,
1696 SMB_INO_T *ino)
1698 int data_len = 0;
1699 int param_len = 0;
1700 uint16 setup = TRANSACT2_QPATHINFO;
1701 pstring param;
1702 char *rparam=NULL, *rdata=NULL;
1704 param_len = strlen(fname) + 7;
1706 memset(param, 0, param_len);
1707 SSVAL(param, 0, SMB_QUERY_FILE_ALL_INFO);
1708 pstrcpy(&param[6], fname);
1710 if (!cli_send_trans(cli, SMBtrans2,
1711 NULL, 0, /* name, length */
1712 -1, 0, /* fid, flags */
1713 &setup, 1, 0, /* setup, length, max */
1714 param, param_len, 10, /* param, length, max */
1715 NULL, data_len, cli->max_xmit /* data, length, max */
1716 )) {
1717 return False;
1720 if (!cli_receive_trans(cli, SMBtrans2,
1721 &rparam, &param_len,
1722 &rdata, &data_len)) {
1723 return False;
1726 if (!rdata || data_len < 22) {
1727 return False;
1730 if (c_time) {
1731 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
1733 if (a_time) {
1734 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
1736 if (m_time) {
1737 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
1739 if (w_time) {
1740 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
1742 if (mode) {
1743 *mode = SVAL(rdata, 32);
1745 if (size) {
1746 *size = IVAL(rdata, 40);
1748 if (ino) {
1749 *ino = IVAL(rdata, 64);
1752 if (rdata) free(rdata);
1753 if (rparam) free(rparam);
1754 return True;
1758 /****************************************************************************
1759 send a qfileinfo call
1760 ****************************************************************************/
1761 BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
1762 uint16 *mode, size_t *size,
1763 time_t *c_time, time_t *a_time, time_t *m_time,
1764 time_t *w_time, SMB_INO_T *ino)
1766 int data_len = 0;
1767 int param_len = 0;
1768 uint16 setup = TRANSACT2_QFILEINFO;
1769 pstring param;
1770 char *rparam=NULL, *rdata=NULL;
1772 /* if its a win95 server then fail this - win95 totally screws it
1773 up */
1774 if (cli->win95) return False;
1776 param_len = 4;
1778 memset(param, 0, param_len);
1779 SSVAL(param, 0, fnum);
1780 SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
1782 if (!cli_send_trans(cli, SMBtrans2,
1783 NULL, 0, /* name, length */
1784 -1, 0, /* fid, flags */
1785 &setup, 1, 0, /* setup, length, max */
1786 param, param_len, 2, /* param, length, max */
1787 NULL, data_len, cli->max_xmit /* data, length, max */
1788 )) {
1789 return False;
1792 if (!cli_receive_trans(cli, SMBtrans2,
1793 &rparam, &param_len,
1794 &rdata, &data_len)) {
1795 return False;
1798 if (!rdata || data_len < 68) {
1799 return False;
1802 if (c_time) {
1803 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
1805 if (a_time) {
1806 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
1808 if (m_time) {
1809 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
1811 if (w_time) {
1812 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
1814 if (mode) {
1815 *mode = SVAL(rdata, 32);
1817 if (size) {
1818 *size = IVAL(rdata, 40);
1820 if (ino) {
1821 *ino = IVAL(rdata, 64);
1824 if (rdata) free(rdata);
1825 if (rparam) free(rparam);
1826 return True;
1830 /****************************************************************************
1831 interpret a long filename structure - this is mostly guesses at the moment
1832 The length of the structure is returned
1833 The structure of a long filename depends on the info level. 260 is used
1834 by NT and 2 is used by OS/2
1835 ****************************************************************************/
1836 static int interpret_long_filename(int level,char *p,file_info *finfo)
1838 extern file_info def_finfo;
1840 if (finfo)
1841 memcpy(finfo,&def_finfo,sizeof(*finfo));
1843 switch (level)
1845 case 1: /* OS/2 understands this */
1846 if (finfo) {
1847 /* these dates are converted to GMT by make_unix_date */
1848 finfo->ctime = make_unix_date2(p+4);
1849 finfo->atime = make_unix_date2(p+8);
1850 finfo->mtime = make_unix_date2(p+12);
1851 finfo->size = IVAL(p,16);
1852 finfo->mode = CVAL(p,24);
1853 pstrcpy(finfo->name,p+27);
1855 return(28 + CVAL(p,26));
1857 case 2: /* this is what OS/2 uses mostly */
1858 if (finfo) {
1859 /* these dates are converted to GMT by make_unix_date */
1860 finfo->ctime = make_unix_date2(p+4);
1861 finfo->atime = make_unix_date2(p+8);
1862 finfo->mtime = make_unix_date2(p+12);
1863 finfo->size = IVAL(p,16);
1864 finfo->mode = CVAL(p,24);
1865 pstrcpy(finfo->name,p+31);
1867 return(32 + CVAL(p,30));
1869 /* levels 3 and 4 are untested */
1870 case 3:
1871 if (finfo) {
1872 /* these dates are probably like the other ones */
1873 finfo->ctime = make_unix_date2(p+8);
1874 finfo->atime = make_unix_date2(p+12);
1875 finfo->mtime = make_unix_date2(p+16);
1876 finfo->size = IVAL(p,20);
1877 finfo->mode = CVAL(p,28);
1878 pstrcpy(finfo->name,p+33);
1880 return(SVAL(p,4)+4);
1882 case 4:
1883 if (finfo) {
1884 /* these dates are probably like the other ones */
1885 finfo->ctime = make_unix_date2(p+8);
1886 finfo->atime = make_unix_date2(p+12);
1887 finfo->mtime = make_unix_date2(p+16);
1888 finfo->size = IVAL(p,20);
1889 finfo->mode = CVAL(p,28);
1890 pstrcpy(finfo->name,p+37);
1892 return(SVAL(p,4)+4);
1894 case 260: /* NT uses this, but also accepts 2 */
1895 if (finfo) {
1896 int ret = SVAL(p,0);
1897 int namelen;
1898 p += 4; /* next entry offset */
1899 p += 4; /* fileindex */
1901 /* these dates appear to arrive in a
1902 weird way. It seems to be localtime
1903 plus the serverzone given in the
1904 initial connect. This is GMT when
1905 DST is not in effect and one hour
1906 from GMT otherwise. Can this really
1907 be right??
1909 I suppose this could be called
1910 kludge-GMT. Is is the GMT you get
1911 by using the current DST setting on
1912 a different localtime. It will be
1913 cheap to calculate, I suppose, as
1914 no DST tables will be needed */
1916 finfo->ctime = interpret_long_date(p); p += 8;
1917 finfo->atime = interpret_long_date(p); p += 8;
1918 finfo->mtime = interpret_long_date(p); p += 8; p += 8;
1919 finfo->size = IVAL(p,0); p += 8;
1920 p += 8; /* alloc size */
1921 finfo->mode = CVAL(p,0); p += 4;
1922 namelen = IVAL(p,0); p += 4;
1923 p += 4; /* EA size */
1924 p += 2; /* short name len? */
1925 p += 24; /* short name? */
1926 StrnCpy(finfo->name,p,namelen);
1927 return(ret);
1929 return(SVAL(p,0));
1932 DEBUG(1,("Unknown long filename format %d\n",level));
1933 return(SVAL(p,0));
1937 /****************************************************************************
1938 do a directory listing, calling fn on each file found
1939 ****************************************************************************/
1940 int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
1941 void (*fn)(file_info *, const char *))
1943 int max_matches = 512;
1944 /* NT uses 260, OS/2 uses 2. Both accept 1. */
1945 int info_level = cli->protocol<PROTOCOL_NT1?1:260;
1946 char *p, *p2;
1947 pstring mask;
1948 file_info finfo;
1949 int i;
1950 char *dirlist = NULL;
1951 int dirlist_len = 0;
1952 int total_received = -1;
1953 BOOL First = True;
1954 int ff_resume_key = 0;
1955 int ff_searchcount=0;
1956 int ff_eos=0;
1957 int ff_lastname=0;
1958 int ff_dir_handle=0;
1959 int loop_count = 0;
1960 char *rparam=NULL, *rdata=NULL;
1961 int param_len, data_len;
1963 uint16 setup;
1964 pstring param;
1966 pstrcpy(mask,Mask);
1968 while (ff_eos == 0) {
1969 loop_count++;
1970 if (loop_count > 200) {
1971 DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
1972 break;
1975 param_len = 12+strlen(mask)+1;
1977 if (First) {
1978 setup = TRANSACT2_FINDFIRST;
1979 SSVAL(param,0,attribute); /* attribute */
1980 SSVAL(param,2,max_matches); /* max count */
1981 SSVAL(param,4,8+4+2); /* resume required + close on end + continue */
1982 SSVAL(param,6,info_level);
1983 SIVAL(param,8,0);
1984 pstrcpy(param+12,mask);
1985 } else {
1986 setup = TRANSACT2_FINDNEXT;
1987 SSVAL(param,0,ff_dir_handle);
1988 SSVAL(param,2,max_matches); /* max count */
1989 SSVAL(param,4,info_level);
1990 SIVAL(param,6,ff_resume_key); /* ff_resume_key */
1991 SSVAL(param,10,8+4+2); /* resume required + close on end + continue */
1992 pstrcpy(param+12,mask);
1994 DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
1995 ff_dir_handle,ff_resume_key,ff_lastname,mask));
1998 if (!cli_send_trans(cli, SMBtrans2,
1999 NULL, 0, /* Name, length */
2000 -1, 0, /* fid, flags */
2001 &setup, 1, 0, /* setup, length, max */
2002 param, param_len, 10, /* param, length, max */
2003 NULL, 0,
2004 cli->max_xmit /* data, length, max */
2005 )) {
2006 break;
2009 if (!cli_receive_trans(cli, SMBtrans2,
2010 &rparam, &param_len,
2011 &rdata, &data_len)) {
2012 /* we need to work around a Win95 bug - sometimes
2013 it gives ERRSRV/ERRerror temprarily */
2014 uint8 eclass;
2015 uint32 ecode;
2016 cli_error(cli, &eclass, &ecode);
2017 if (eclass != ERRSRV || ecode != ERRerror) break;
2018 msleep(100);
2019 continue;
2022 if (total_received == -1) total_received = 0;
2024 /* parse out some important return info */
2025 p = rparam;
2026 if (First) {
2027 ff_dir_handle = SVAL(p,0);
2028 ff_searchcount = SVAL(p,2);
2029 ff_eos = SVAL(p,4);
2030 ff_lastname = SVAL(p,8);
2031 } else {
2032 ff_searchcount = SVAL(p,0);
2033 ff_eos = SVAL(p,2);
2034 ff_lastname = SVAL(p,6);
2037 if (ff_searchcount == 0)
2038 break;
2040 /* point to the data bytes */
2041 p = rdata;
2043 /* we might need the lastname for continuations */
2044 if (ff_lastname > 0) {
2045 switch(info_level)
2047 case 260:
2048 ff_resume_key =0;
2049 StrnCpy(mask,p+ff_lastname,
2050 data_len-ff_lastname);
2051 break;
2052 case 1:
2053 pstrcpy(mask,p + ff_lastname + 1);
2054 ff_resume_key = 0;
2055 break;
2057 } else {
2058 pstrcpy(mask,"");
2061 /* and add them to the dirlist pool */
2062 dirlist = Realloc(dirlist,dirlist_len + data_len);
2064 if (!dirlist) {
2065 DEBUG(0,("Failed to expand dirlist\n"));
2066 break;
2069 /* put in a length for the last entry, to ensure we can chain entries
2070 into the next packet */
2071 for (p2=p,i=0;i<(ff_searchcount-1);i++)
2072 p2 += interpret_long_filename(info_level,p2,NULL);
2073 SSVAL(p2,0,data_len - PTR_DIFF(p2,p));
2075 /* grab the data for later use */
2076 memcpy(dirlist+dirlist_len,p,data_len);
2077 dirlist_len += data_len;
2079 total_received += ff_searchcount;
2081 if (rdata) free(rdata); rdata = NULL;
2082 if (rparam) free(rparam); rparam = NULL;
2084 DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
2085 ff_searchcount,ff_eos,ff_resume_key));
2087 First = False;
2090 for (p=dirlist,i=0;i<total_received;i++) {
2091 p += interpret_long_filename(info_level,p,&finfo);
2092 fn(&finfo, Mask);
2095 /* free up the dirlist buffer */
2096 if (dirlist) free(dirlist);
2097 return(total_received);
2101 /****************************************************************************
2102 Send a SamOEMChangePassword command
2103 ****************************************************************************/
2105 BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
2106 const char *old_password)
2108 char param[16+sizeof(fstring)];
2109 char data[532];
2110 char *p = param;
2111 fstring upper_case_old_pw;
2112 fstring upper_case_new_pw;
2113 unsigned char old_pw_hash[16];
2114 unsigned char new_pw_hash[16];
2115 int data_len;
2116 int param_len = 0;
2117 char *rparam = NULL;
2118 char *rdata = NULL;
2119 int rprcnt, rdrcnt;
2121 if (strlen(user) >= sizeof(fstring)-1) {
2122 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
2123 return False;
2126 SSVAL(p,0,214); /* SamOEMChangePassword command. */
2127 p += 2;
2128 pstrcpy(p, "zsT");
2129 p = skip_string(p,1);
2130 pstrcpy(p, "B516B16");
2131 p = skip_string(p,1);
2132 pstrcpy(p,user);
2133 p = skip_string(p,1);
2134 SSVAL(p,0,532);
2135 p += 2;
2137 param_len = PTR_DIFF(p,param);
2140 * Get the Lanman hash of the old password, we
2141 * use this as the key to make_oem_passwd_hash().
2143 memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw));
2144 fstrcpy(upper_case_old_pw, old_password);
2145 strupper(upper_case_old_pw);
2146 E_P16((uchar *)upper_case_old_pw, old_pw_hash);
2148 if (!make_oem_passwd_hash( data, new_password, old_pw_hash, False))
2150 return False;
2154 * Now place the old password hash in the data.
2156 memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw));
2157 fstrcpy(upper_case_new_pw, new_password);
2158 strupper(upper_case_new_pw);
2160 E_P16((uchar *)upper_case_new_pw, new_pw_hash);
2162 E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
2164 data_len = 532;
2166 if (cli_send_trans(cli,SMBtrans,
2167 PIPE_LANMAN,strlen(PIPE_LANMAN), /* name, length */
2168 0,0, /* fid, flags */
2169 NULL,0,0, /* setup, length, max */
2170 param,param_len,2, /* param, length, max */
2171 data,data_len,0 /* data, length, max */
2172 ) == False) {
2173 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
2174 user ));
2175 return False;
2178 if (cli_receive_trans(cli,SMBtrans,
2179 &rparam, &rprcnt,
2180 &rdata, &rdrcnt)) {
2181 if (rparam)
2182 cli->rap_error = SVAL(rparam,0);
2185 if (rparam)
2186 free(rparam);
2187 if (rdata)
2188 free(rdata);
2190 return (cli->rap_error == 0);
2193 /****************************************************************************
2194 send a negprot command
2195 ****************************************************************************/
2196 BOOL cli_negprot(struct cli_state *cli)
2198 char *p;
2199 int numprots;
2200 int plength;
2202 bzero(cli->outbuf,smb_size);
2204 /* setup the protocol strings */
2205 for (plength=0,numprots=0;
2206 prots[numprots].name && prots[numprots].prot<=cli->protocol;
2207 numprots++)
2208 plength += strlen(prots[numprots].name)+2;
2210 set_message(cli->outbuf,0,plength,True);
2212 p = smb_buf(cli->outbuf);
2213 for (numprots=0;
2214 prots[numprots].name && prots[numprots].prot<=cli->protocol;
2215 numprots++) {
2216 *p++ = 2;
2217 pstrcpy(p,prots[numprots].name);
2218 p += strlen(p) + 1;
2221 CVAL(cli->outbuf,smb_com) = SMBnegprot;
2222 cli_setup_packet(cli);
2224 CVAL(smb_buf(cli->outbuf),0) = 2;
2226 cli_send_smb(cli);
2227 if (!cli_receive_smb(cli))
2228 return False;
2230 show_msg(cli->inbuf);
2232 if (CVAL(cli->inbuf,smb_rcls) != 0 ||
2233 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
2234 return(False);
2237 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
2240 if (cli->protocol >= PROTOCOL_NT1) {
2241 /* NT protocol */
2242 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
2243 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
2244 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
2245 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
2246 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1)*60;
2247 /* this time arrives in real GMT */
2248 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
2249 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2250 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
2251 if (cli->capabilities & 1) {
2252 cli->readbraw_supported = True;
2253 cli->writebraw_supported = True;
2255 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
2256 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
2257 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
2258 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
2259 cli->serverzone = SVALS(cli->inbuf,smb_vwv10)*60;
2260 /* this time is converted to GMT by make_unix_date */
2261 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
2262 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
2263 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
2264 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2265 } else {
2266 /* the old core protocol */
2267 cli->sec_mode = 0;
2268 cli->serverzone = TimeDiff(time(NULL));
2271 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
2273 return True;
2277 /****************************************************************************
2278 send a session request. see rfc1002.txt 4.3 and 4.3.2
2279 ****************************************************************************/
2280 BOOL cli_session_request(struct cli_state *cli,
2281 struct nmb_name *calling, struct nmb_name *called)
2283 char *p;
2284 int len = 4;
2285 /* send a session request (RFC 1002) */
2287 memcpy(&(cli->calling), calling, sizeof(*calling));
2288 memcpy(&(cli->called ), called , sizeof(*called ));
2290 /* put in the destination name */
2291 p = cli->outbuf+len;
2292 name_mangle(cli->called .name, p, cli->called .name_type);
2293 len += name_len(p);
2295 /* and my name */
2296 p = cli->outbuf+len;
2297 name_mangle(cli->calling.name, p, cli->calling.name_type);
2298 len += name_len(p);
2300 /* setup the packet length */
2301 _smb_setlen(cli->outbuf,len);
2302 CVAL(cli->outbuf,0) = 0x81;
2304 #ifdef WITH_SSL
2305 retry:
2306 #endif /* WITH_SSL */
2308 cli_send_smb(cli);
2309 DEBUG(5,("Sent session request\n"));
2311 if (!cli_receive_smb(cli))
2312 return False;
2314 #ifdef WITH_SSL
2315 if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
2316 if (!sslutil_fd_is_ssl(cli->fd)){
2317 if (sslutil_connect(cli->fd) == 0)
2318 goto retry;
2321 #endif /* WITH_SSL */
2323 if (CVAL(cli->inbuf,0) != 0x82) {
2324 /* This is the wrong place to put the error... JRA. */
2325 cli->rap_error = CVAL(cli->inbuf,0);
2326 return False;
2328 return(True);
2332 /****************************************************************************
2333 open the client sockets
2334 ****************************************************************************/
2335 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
2337 extern struct in_addr ipzero;
2339 fstrcpy(cli->desthost, host);
2341 if (!ip || ip_equal(*ip, ipzero)) {
2342 if (!resolve_name( cli->desthost, &cli->dest_ip, 0x20)) {
2343 return False;
2345 if (ip) *ip = cli->dest_ip;
2346 } else {
2347 cli->dest_ip = *ip;
2351 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
2352 139, cli->timeout);
2353 if (cli->fd == -1)
2354 return False;
2356 return True;
2360 /****************************************************************************
2361 initialise a client structure
2362 ****************************************************************************/
2363 struct cli_state *cli_initialise(struct cli_state *cli)
2365 if (!cli) {
2366 cli = (struct cli_state *)malloc(sizeof(*cli));
2367 if (!cli)
2368 return NULL;
2369 ZERO_STRUCTP(cli);
2372 if (cli->initialised) {
2373 cli_shutdown(cli);
2376 ZERO_STRUCTP(cli);
2378 cli->fd = -1;
2379 cli->cnum = -1;
2380 cli->pid = (uint16)getpid();
2381 cli->mid = 1;
2382 cli->vuid = UID_FIELD_INVALID;
2383 cli->protocol = PROTOCOL_NT1;
2384 cli->timeout = 20000;
2385 cli->bufsize = CLI_BUFFER_SIZE+4;
2386 cli->max_xmit = cli->bufsize;
2387 cli->outbuf = (char *)malloc(cli->bufsize);
2388 cli->inbuf = (char *)malloc(cli->bufsize);
2389 if (!cli->outbuf || !cli->inbuf)
2391 return False;
2394 cli->initialised = 1;
2396 return cli;
2399 /****************************************************************************
2400 shutdown a client structure
2401 ****************************************************************************/
2402 void cli_shutdown(struct cli_state *cli)
2404 if (cli->outbuf)
2406 free(cli->outbuf);
2408 if (cli->inbuf)
2410 free(cli->inbuf);
2412 #ifdef WITH_SSL
2413 if (cli->fd != -1)
2414 sslutil_disconnect(cli->fd);
2415 #endif /* WITH_SSL */
2416 if (cli->fd != -1)
2417 close(cli->fd);
2418 memset(cli, 0, sizeof(*cli));
2422 /****************************************************************************
2423 return error codes for the last packet
2424 returns 0 if there was no error and the best approx of a unix errno
2425 otherwise
2427 for 32 bit "warnings", a return code of 0 is expected.
2429 ****************************************************************************/
2430 int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num)
2432 int flgs2 = SVAL(cli->inbuf,smb_flg2);
2433 char rcls;
2434 int code;
2436 if (eclass) *eclass = 0;
2437 if (num ) *num = 0;
2439 if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
2440 /* 32 bit error codes detected */
2441 uint32 nt_err = IVAL(cli->inbuf,smb_rcls);
2442 if (num) *num = nt_err;
2443 DEBUG(10,("cli_error: 32 bit codes: code=%08x\n", nt_err));
2444 if (!IS_BITS_SET_ALL(nt_err, 0xc0000000)) return 0;
2446 switch (nt_err & 0xFFFFFF) {
2447 case NT_STATUS_ACCESS_VIOLATION: return EACCES;
2448 case NT_STATUS_NO_SUCH_FILE: return ENOENT;
2449 case NT_STATUS_NO_SUCH_DEVICE: return ENODEV;
2450 case NT_STATUS_INVALID_HANDLE: return EBADF;
2451 case NT_STATUS_NO_MEMORY: return ENOMEM;
2452 case NT_STATUS_ACCESS_DENIED: return EACCES;
2453 case NT_STATUS_OBJECT_NAME_NOT_FOUND: return ENOENT;
2454 case NT_STATUS_SHARING_VIOLATION: return EBUSY;
2455 case NT_STATUS_OBJECT_PATH_INVALID: return ENOTDIR;
2456 case NT_STATUS_OBJECT_NAME_COLLISION: return EEXIST;
2459 /* for all other cases - a default code */
2460 return EINVAL;
2463 rcls = CVAL(cli->inbuf,smb_rcls);
2464 code = SVAL(cli->inbuf,smb_err);
2465 if (rcls == 0) return 0;
2467 if (eclass) *eclass = rcls;
2468 if (num ) *num = code;
2470 if (rcls == ERRDOS) {
2471 switch (code) {
2472 case ERRbadfile: return ENOENT;
2473 case ERRbadpath: return ENOTDIR;
2474 case ERRnoaccess: return EACCES;
2475 case ERRfilexists: return EEXIST;
2476 case ERRrename: return EEXIST;
2477 case ERRbadshare: return EBUSY;
2478 case ERRlock: return EBUSY;
2481 if (rcls == ERRSRV) {
2482 switch (code) {
2483 case ERRbadpw: return EPERM;
2484 case ERRaccess: return EACCES;
2485 case ERRnoresource: return ENOMEM;
2486 case ERRinvdevice: return ENODEV;
2487 case ERRinvnetname: return ENODEV;
2490 /* for other cases */
2491 return EINVAL;
2494 /****************************************************************************
2495 set socket options on a open connection
2496 ****************************************************************************/
2497 void cli_sockopt(struct cli_state *cli, char *options)
2499 set_socket_options(cli->fd, options);
2502 /****************************************************************************
2503 set the PID to use for smb messages. Return the old pid.
2504 ****************************************************************************/
2505 uint16 cli_setpid(struct cli_state *cli, uint16 pid)
2507 uint16 ret = cli->pid;
2508 cli->pid = pid;
2509 return ret;
2512 /****************************************************************************
2513 re-establishes a connection
2514 ****************************************************************************/
2515 BOOL cli_reestablish_connection(struct cli_state *cli)
2517 struct nmb_name calling;
2518 struct nmb_name called;
2519 fstring dest_host;
2520 fstring share;
2521 fstring dev;
2522 BOOL do_tcon = False;
2523 int oldfd = cli->fd;
2525 if (!cli->initialised || cli->fd == -1)
2527 DEBUG(3,("cli_reestablish_connection: not connected\n"));
2528 return False;
2531 /* copy the parameters necessary to re-establish the connection */
2533 if (cli->cnum != 0)
2535 fstrcpy(share, cli->share);
2536 fstrcpy(dev , cli->dev);
2537 do_tcon = True;
2540 memcpy(&called , &(cli->called ), sizeof(called ));
2541 memcpy(&calling, &(cli->calling), sizeof(calling));
2542 fstrcpy(dest_host, cli->full_dest_host_name);
2544 DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
2545 nmb_namestr(&calling), nmb_namestr(&called),
2546 inet_ntoa(cli->dest_ip),
2547 cli->user_name, cli->domain));
2549 cli->fd = -1;
2551 if (cli_establish_connection(cli,
2552 dest_host, &cli->dest_ip,
2553 &calling, &called,
2554 share, dev, False, do_tcon)) {
2555 if (cli->fd != oldfd) {
2556 if (dup2(cli->fd, oldfd) == oldfd) {
2557 close(cli->fd);
2560 return True;
2562 return False;
2565 /****************************************************************************
2566 establishes a connection right up to doing tconX, reading in a password.
2567 ****************************************************************************/
2568 BOOL cli_establish_connection(struct cli_state *cli,
2569 char *dest_host, struct in_addr *dest_ip,
2570 struct nmb_name *calling, struct nmb_name *called,
2571 char *service, char *service_type,
2572 BOOL do_shutdown, BOOL do_tcon)
2574 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
2575 nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
2576 cli->user_name, cli->domain));
2578 /* establish connection */
2580 if ((!cli->initialised))
2582 return False;
2585 if (cli->fd == -1)
2587 if (!cli_connect(cli, dest_host, dest_ip))
2589 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
2590 nmb_namestr(calling), inet_ntoa(*dest_ip)));
2591 return False;
2595 if (!cli_session_request(cli, calling, called))
2597 DEBUG(1,("failed session request\n"));
2598 if (do_shutdown)
2599 cli_shutdown(cli);
2600 return False;
2603 if (!cli_negprot(cli))
2605 DEBUG(1,("failed negprot\n"));
2606 if (do_shutdown)
2607 cli_shutdown(cli);
2608 return False;
2611 if (cli->pwd.cleartext || cli->pwd.null_pwd)
2613 fstring passwd;
2614 int pass_len;
2616 if (cli->pwd.null_pwd)
2618 /* attempt null session */
2619 passwd[0] = 0;
2620 pass_len = 1;
2622 else
2624 /* attempt clear-text session */
2625 pwd_get_cleartext(&(cli->pwd), passwd);
2626 pass_len = strlen(passwd);
2629 /* attempt clear-text session */
2630 if (!cli_session_setup(cli, cli->user_name,
2631 passwd, pass_len,
2632 NULL, 0,
2633 cli->domain))
2635 DEBUG(1,("failed session setup\n"));
2636 if (do_shutdown)
2638 cli_shutdown(cli);
2640 return False;
2642 if (do_tcon)
2644 if (!cli_send_tconX(cli, service, service_type,
2645 (char*)passwd, strlen(passwd)))
2647 DEBUG(1,("failed tcon_X\n"));
2648 if (do_shutdown)
2650 cli_shutdown(cli);
2652 return False;
2656 else
2658 /* attempt encrypted session */
2659 unsigned char nt_sess_pwd[24];
2660 unsigned char lm_sess_pwd[24];
2662 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
2663 pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey);
2664 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
2666 /* attempt encrypted session */
2667 if (!cli_session_setup(cli, cli->user_name,
2668 (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
2669 (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
2670 cli->domain))
2672 DEBUG(1,("failed session setup\n"));
2673 if (do_shutdown)
2674 cli_shutdown(cli);
2675 return False;
2678 if (do_tcon)
2680 if (!cli_send_tconX(cli, service, service_type,
2681 (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
2683 DEBUG(1,("failed tcon_X\n"));
2684 if (do_shutdown)
2685 cli_shutdown(cli);
2686 return False;
2691 if (do_shutdown)
2692 cli_shutdown(cli);
2694 return True;
2698 /****************************************************************************
2699 cancel a print job
2700 ****************************************************************************/
2701 int cli_printjob_del(struct cli_state *cli, int job)
2703 char *rparam = NULL;
2704 char *rdata = NULL;
2705 char *p;
2706 int rdrcnt,rprcnt, ret = -1;
2707 pstring param;
2709 bzero(param,sizeof(param));
2711 p = param;
2712 SSVAL(p,0,81); /* DosPrintJobDel() */
2713 p += 2;
2714 pstrcpy(p,"W");
2715 p = skip_string(p,1);
2716 pstrcpy(p,"");
2717 p = skip_string(p,1);
2718 SSVAL(p,0,job);
2719 p += 2;
2721 if (cli_api(cli,
2722 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
2723 NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
2724 &rparam, &rprcnt, /* return params, length */
2725 &rdata, &rdrcnt)) { /* return data, length */
2726 ret = SVAL(rparam,0);
2729 if (rparam) free(rparam);
2730 if (rdata) free(rdata);
2732 return ret;
2736 /****************************************************************************
2737 call fn() on each entry in a print queue
2738 ****************************************************************************/
2739 int cli_print_queue(struct cli_state *cli,
2740 void (*fn)(struct print_job_info *))
2742 char *rparam = NULL;
2743 char *rdata = NULL;
2744 char *p;
2745 int rdrcnt, rprcnt;
2746 pstring param;
2747 int result_code=0;
2748 int i = -1;
2750 bzero(param,sizeof(param));
2752 p = param;
2753 SSVAL(p,0,76); /* API function number 76 (DosPrintJobEnum) */
2754 p += 2;
2755 pstrcpy(p,"zWrLeh"); /* parameter description? */
2756 p = skip_string(p,1);
2757 pstrcpy(p,"WWzWWDDzz"); /* returned data format */
2758 p = skip_string(p,1);
2759 pstrcpy(p,cli->share); /* name of queue */
2760 p = skip_string(p,1);
2761 SSVAL(p,0,2); /* API function level 2, PRJINFO_2 data structure */
2762 SSVAL(p,2,1000); /* size of bytes of returned data buffer */
2763 p += 4;
2764 pstrcpy(p,""); /* subformat */
2765 p = skip_string(p,1);
2767 DEBUG(4,("doing cli_print_queue for %s\n", cli->share));
2769 if (cli_api(cli,
2770 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
2771 NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
2772 &rparam, &rprcnt, /* return params, length */
2773 &rdata, &rdrcnt)) { /* return data, length */
2774 int converter;
2775 result_code = SVAL(rparam,0);
2776 converter = SVAL(rparam,2); /* conversion factor */
2778 if (result_code == 0) {
2779 struct print_job_info job;
2781 p = rdata;
2783 for (i = 0; i < SVAL(rparam,4); ++i) {
2784 job.id = SVAL(p,0);
2785 job.priority = SVAL(p,2);
2786 fstrcpy(job.user,
2787 fix_char_ptr(SVAL(p,4), converter,
2788 rdata, rdrcnt));
2789 job.t = make_unix_date3(p + 12);
2790 job.size = IVAL(p,16);
2791 fstrcpy(job.name,fix_char_ptr(SVAL(p,24),
2792 converter,
2793 rdata, rdrcnt));
2794 fn(&job);
2795 p += 28;
2800 /* If any parameters or data were returned, free the storage. */
2801 if(rparam) free(rparam);
2802 if(rdata) free(rdata);
2804 return i;
2807 /****************************************************************************
2808 check for existance of a dir
2809 ****************************************************************************/
2810 BOOL cli_chkpath(struct cli_state *cli, char *path)
2812 fstring path2;
2813 char *p;
2815 fstrcpy(path2,path);
2816 trim_string(path2,NULL,"\\");
2817 if (!*path2) *path2 = '\\';
2819 bzero(cli->outbuf,smb_size);
2820 set_message(cli->outbuf,0,4 + strlen(path2),True);
2821 SCVAL(cli->outbuf,smb_com,SMBchkpth);
2822 SSVAL(cli->outbuf,smb_tid,cli->cnum);
2823 cli_setup_packet(cli);
2825 p = smb_buf(cli->outbuf);
2826 *p++ = 4;
2827 fstrcpy(p,path2);
2829 cli_send_smb(cli);
2830 if (!cli_receive_smb(cli)) {
2831 return False;
2834 if (cli_error(cli, NULL, NULL)) return False;
2836 return True;
2840 /****************************************************************************
2841 start a message sequence
2842 ****************************************************************************/
2843 BOOL cli_message_start(struct cli_state *cli, char *host, char *username,
2844 int *grp)
2846 char *p;
2848 /* send a SMBsendstrt command */
2849 bzero(cli->outbuf,smb_size);
2850 set_message(cli->outbuf,0,0,True);
2851 CVAL(cli->outbuf,smb_com) = SMBsendstrt;
2852 SSVAL(cli->outbuf,smb_tid,cli->cnum);
2853 cli_setup_packet(cli);
2855 p = smb_buf(cli->outbuf);
2856 *p++ = 4;
2857 pstrcpy(p,username);
2858 p = skip_string(p,1);
2859 *p++ = 4;
2860 pstrcpy(p,host);
2861 p = skip_string(p,1);
2863 set_message(cli->outbuf,0,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
2865 cli_send_smb(cli);
2867 if (!cli_receive_smb(cli)) {
2868 return False;
2871 if (cli_error(cli, NULL, NULL)) return False;
2873 *grp = SVAL(cli->inbuf,smb_vwv0);
2875 return True;
2879 /****************************************************************************
2880 send a message
2881 ****************************************************************************/
2882 BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp)
2884 char *p;
2886 bzero(cli->outbuf,smb_size);
2887 set_message(cli->outbuf,1,len+3,True);
2888 CVAL(cli->outbuf,smb_com) = SMBsendtxt;
2889 SSVAL(cli->outbuf,smb_tid,cli->cnum);
2890 cli_setup_packet(cli);
2892 SSVAL(cli->outbuf,smb_vwv0,grp);
2894 p = smb_buf(cli->outbuf);
2895 *p = 1;
2896 SSVAL(p,1,len);
2897 memcpy(p+3,msg,len);
2898 cli_send_smb(cli);
2900 if (!cli_receive_smb(cli)) {
2901 return False;
2904 if (cli_error(cli, NULL, NULL)) return False;
2906 return True;
2909 /****************************************************************************
2910 end a message
2911 ****************************************************************************/
2912 BOOL cli_message_end(struct cli_state *cli, int grp)
2914 bzero(cli->outbuf,smb_size);
2915 set_message(cli->outbuf,1,0,True);
2916 CVAL(cli->outbuf,smb_com) = SMBsendend;
2917 SSVAL(cli->outbuf,smb_tid,cli->cnum);
2919 SSVAL(cli->outbuf,smb_vwv0,grp);
2921 cli_setup_packet(cli);
2923 cli_send_smb(cli);
2925 if (!cli_receive_smb(cli)) {
2926 return False;
2929 if (cli_error(cli, NULL, NULL)) return False;
2931 return True;
2935 /****************************************************************************
2936 query disk space
2937 ****************************************************************************/
2938 BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
2940 bzero(cli->outbuf,smb_size);
2941 set_message(cli->outbuf,0,0,True);
2942 CVAL(cli->outbuf,smb_com) = SMBdskattr;
2943 SSVAL(cli->outbuf,smb_tid,cli->cnum);
2944 cli_setup_packet(cli);
2946 cli_send_smb(cli);
2947 if (!cli_receive_smb(cli)) {
2948 return False;
2951 *bsize = SVAL(cli->inbuf,smb_vwv1)*SVAL(cli->inbuf,smb_vwv2);
2952 *total = SVAL(cli->inbuf,smb_vwv0);
2953 *avail = SVAL(cli->inbuf,smb_vwv3);
2955 return True;