diff options
Diffstat (limited to 'source3/libsmb/clientgen.c')
-rw-r--r-- | source3/libsmb/clientgen.c | 308 |
1 files changed, 221 insertions, 87 deletions
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 4c1690f6f2..7be2717bed 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -445,7 +445,6 @@ BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation) return (cli->rap_error == 0); } -#if UNUSED_CODE /**************************************************************************** call a NetShareEnum - try and browse available connections on a host ****************************************************************************/ @@ -501,9 +500,9 @@ BOOL cli_RNetShareEnum(struct cli_state *cli, void (*fn)(char *, uint32, char *) if (rdata) free(rdata); - return(count>0); + return count; } -#endif + /**************************************************************************** call a NetServerEnum for the specified workgroup and servertype mask. @@ -608,29 +607,38 @@ BOOL cli_session_setup(struct cli_state *cli, char *workgroup) { char *p; - fstring pword; + fstring pword, ntpword; if (cli->protocol < PROTOCOL_LANMAN1) return True; - if (passlen > sizeof(pword)-1) { + if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) { return False; } if (((passlen == 0) || (passlen == 1)) && (pass[0] == '\0')) { /* Null session connect. */ pword[0] = '\0'; + ntpword[0] = '\0'; } else { if ((cli->sec_mode & 2) && passlen != 24) { passlen = 24; + ntpasslen = 24; SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword); + SMBNTencrypt((uchar *)ntpass,(uchar *)cli->cryptkey,(uchar *)ntpword); } else { memcpy(pword, pass, passlen); + memcpy(ntpword, ntpass, ntpasslen); } } /* if in share level security then don't send a password now */ - if (!(cli->sec_mode & 1)) {fstrcpy(pword, "");passlen=1;} + if (!(cli->sec_mode & 1)) { + fstrcpy(pword, ""); + passlen=1; + fstrcpy(ntpword, ""); + ntpasslen=1; + } /* send a session setup command */ bzero(cli->outbuf,smb_size); @@ -670,11 +678,8 @@ BOOL cli_session_setup(struct cli_state *cli, p = smb_buf(cli->outbuf); memcpy(p,pword,passlen); p += SVAL(cli->outbuf,smb_vwv7); - if (ntpasslen != 0) - { - memcpy(p,ntpass,ntpasslen); - p += SVAL(cli->outbuf,smb_vwv8); - } + memcpy(p,ntpword,ntpasslen); + p += SVAL(cli->outbuf,smb_vwv8); pstrcpy(p,user); strupper(p); p = skip_string(p,1); @@ -773,6 +778,12 @@ BOOL cli_send_tconX(struct cli_state *cli, return False; } + if (cli->protocol >= PROTOCOL_NT1 && + smb_buflen(cli->inbuf) == 3) { + /* almost certainly win95 - enable bug fixes */ + cli->win95 = True; + } + cli->cnum = SVAL(cli->inbuf,smb_tid); return True; } @@ -1119,37 +1130,51 @@ BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int int cli_read(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size) { char *p; + int total=0; - bzero(cli->outbuf,smb_size); - bzero(cli->inbuf,smb_size); + while (total < size) { + int size1 = MIN(size-total, cli->max_xmit - (smb_size+32)); + int size2; - set_message(cli->outbuf,10,0,True); + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); - CVAL(cli->outbuf,smb_com) = SMBreadX; - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); + set_message(cli->outbuf,10,0,True); + + CVAL(cli->outbuf,smb_com) = SMBreadX; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); - CVAL(cli->outbuf,smb_vwv0) = 0xFF; - SSVAL(cli->outbuf,smb_vwv2,fnum); - SIVAL(cli->outbuf,smb_vwv3,offset); - SSVAL(cli->outbuf,smb_vwv5,size); - SSVAL(cli->outbuf,smb_vwv6,size); + CVAL(cli->outbuf,smb_vwv0) = 0xFF; + SSVAL(cli->outbuf,smb_vwv2,fnum); + SIVAL(cli->outbuf,smb_vwv3,offset+total); + SSVAL(cli->outbuf,smb_vwv5,size1); + SSVAL(cli->outbuf,smb_vwv6,size1); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return total?total:-1; + } - send_smb(cli->fd,cli->outbuf); - if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { - return -1; - } + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return total?total:-1; + } - if (CVAL(cli->inbuf,smb_rcls) != 0) { - return -1; - } + size2 = SVAL(cli->inbuf, smb_vwv5); + if (size2 > size1) { + DEBUG(0,("server returned more than we wanted!\n")); + exit(1); + } + p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6); + + if (size2 <= 0) break; - size = SVAL(cli->inbuf, smb_vwv5); - p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6); + memcpy(buf+total, p, size2); - memcpy(buf, p, size); + total += size2; + } - return size; + return total; } @@ -1159,36 +1184,100 @@ int cli_read(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 s int cli_write(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size) { char *p; + int total=0; + while (total < size) { + int size1 = MIN(size-total, cli->max_xmit - (smb_size+32)); + int size2; + + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,12,size1,True); + + CVAL(cli->outbuf,smb_com) = SMBwriteX; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + CVAL(cli->outbuf,smb_vwv0) = 0xFF; + SSVAL(cli->outbuf,smb_vwv2,fnum); + SIVAL(cli->outbuf,smb_vwv3,offset+total); + + SSVAL(cli->outbuf,smb_vwv10,size1); + SSVAL(cli->outbuf,smb_vwv11, + smb_buf(cli->outbuf) - smb_base(cli->outbuf)); + + p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11); + memcpy(p, buf+total, size1); + + send_smb(cli->fd,cli->outbuf); + if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return -1; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return -1; + } + + size2 = SVAL(cli->inbuf, smb_vwv2); + + if (size2 <= 0) break; + + total += size2; + } + + return total; +} + + +/**************************************************************************** +do a SMBgetattrE call +****************************************************************************/ +BOOL cli_getattrE(struct cli_state *cli, int fd, + int *attr, uint32 *size, + time_t *c_time, time_t *a_time, time_t *m_time) +{ bzero(cli->outbuf,smb_size); bzero(cli->inbuf,smb_size); - set_message(cli->outbuf,12,size,True); + set_message(cli->outbuf,2,0,True); - CVAL(cli->outbuf,smb_com) = SMBwriteX; + CVAL(cli->outbuf,smb_com) = SMBgetattrE; SSVAL(cli->outbuf,smb_tid,cli->cnum); cli_setup_packet(cli); - CVAL(cli->outbuf,smb_vwv0) = 0xFF; - SSVAL(cli->outbuf,smb_vwv2,fnum); - SIVAL(cli->outbuf,smb_vwv3,offset); - - SSVAL(cli->outbuf,smb_vwv10,size); - SSVAL(cli->outbuf,smb_vwv11,smb_buf(cli->outbuf) - smb_base(cli->outbuf)); - - p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11); - memcpy(p, buf, size); + SSVAL(cli->outbuf,smb_vwv0,fd); send_smb(cli->fd,cli->outbuf); if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) { - return -1; + return False; } - + if (CVAL(cli->inbuf,smb_rcls) != 0) { - return -1; + return False; + } + + if (size) { + *size = IVAL(cli->inbuf, smb_vwv6); + } + + if (attr) { + *attr = SVAL(cli->inbuf,smb_vwv10); + } + + if (c_time) { + *c_time = make_unix_date3(cli->inbuf+smb_vwv0); } - return SVAL(cli->inbuf, smb_vwv2); + if (a_time) { + *a_time = make_unix_date3(cli->inbuf+smb_vwv2); + } + + if (m_time) { + *m_time = make_unix_date3(cli->inbuf+smb_vwv4); + } + + return True; } @@ -1196,7 +1285,7 @@ int cli_write(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 do a SMBgetatr call ****************************************************************************/ BOOL cli_getatr(struct cli_state *cli, char *fname, - int *attr, uint32 *size, time_t *t) + uint32 *attr, size_t *size, time_t *t) { char *p; @@ -1281,13 +1370,16 @@ send a qpathinfo call ****************************************************************************/ BOOL cli_qpathinfo(struct cli_state *cli, char *fname, time_t *c_time, time_t *a_time, time_t *m_time, - uint32 *size, int *mode) + size_t *size, uint32 *mode) { int data_len = 0; int param_len = 0; uint16 setup = TRANSACT2_QPATHINFO; pstring param; char *rparam=NULL, *rdata=NULL; + int count=8; + BOOL ret; + time_t (*date_fn)(void *); param_len = strlen(fname) + 7; @@ -1295,34 +1387,46 @@ BOOL cli_qpathinfo(struct cli_state *cli, char *fname, SSVAL(param, 0, SMB_INFO_STANDARD); pstrcpy(¶m[6], fname); - if (!cli_send_trans(cli, SMBtrans2, - NULL, 0, /* Name, length */ - -1, 0, /* fid, flags */ - &setup, 1, 0, /* setup, length, max */ - param, param_len, 10, /* param, length, max */ - NULL, data_len, cli->max_xmit /* data, length, max */ - )) { - return False; - } + do { + ret = (cli_send_trans(cli, SMBtrans2, + NULL, 0, /* Name, length */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 10, /* param, length, max */ + NULL, data_len, cli->max_xmit /* data, length, max */ + ) && + cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)); + if (!ret) { + /* we need to work around a Win95 bug - sometimes + it gives ERRSRV/ERRerror temprarily */ + uint8 eclass; + uint32 ecode; + cli_error(cli, &eclass, &ecode); + if (eclass != ERRSRV || ecode != ERRerror) break; + msleep(100); + } + } while (count-- && ret==False); - if (!cli_receive_trans(cli, SMBtrans2, - &rparam, ¶m_len, - &rdata, &data_len)) { + if (!ret || !rdata || data_len < 22) { return False; } - if (!rdata || data_len < 22) { - return False; + if (cli->win95) { + date_fn = make_unix_date; + } else { + date_fn = make_unix_date2; } if (c_time) { - *c_time = make_unix_date2(rdata+0); + *c_time = date_fn(rdata+0); } if (a_time) { - *a_time = make_unix_date2(rdata+4); + *a_time = date_fn(rdata+4); } if (m_time) { - *m_time = make_unix_date2(rdata+8); + *m_time = date_fn(rdata+8); } if (size) { *size = IVAL(rdata, 12); @@ -1579,7 +1683,7 @@ int cli_list(struct cli_state *cli,char *Mask,int attribute,void (*fn)(file_info int i; char *dirlist = NULL; int dirlist_len = 0; - int total_received = 0; + int total_received = -1; BOOL First = True; int ff_resume_key = 0; int ff_searchcount=0; @@ -1633,15 +1737,24 @@ int cli_list(struct cli_state *cli,char *Mask,int attribute,void (*fn)(file_info NULL, 0, cli->max_xmit /* data, length, max */ )) { - return -1; + break; } if (!cli_receive_trans(cli, SMBtrans2, &rparam, ¶m_len, &rdata, &data_len)) { - return -1; + /* we need to work around a Win95 bug - sometimes + it gives ERRSRV/ERRerror temprarily */ + uint8 eclass; + uint32 ecode; + cli_error(cli, &eclass, &ecode); + if (eclass != ERRSRV || ecode != ERRerror) break; + msleep(100); + continue; } + if (total_received == -1) total_received = 0; + /* parse out some important return info */ p = rparam; if (First) { @@ -1880,9 +1993,11 @@ BOOL cli_negprot(struct cli_state *cli) /* this time arrives in real GMT */ cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1); memcpy(cli->cryptkey,smb_buf(cli->inbuf),8); - if (IVAL(cli->inbuf,smb_vwv9+1) & 1) - cli->readbraw_supported = - cli->writebraw_supported = True; + cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1); + if (cli->capabilities & 1) { + cli->readbraw_supported = True; + cli->writebraw_supported = True; + } } else if (cli->protocol >= PROTOCOL_LANMAN1) { cli->sec_mode = SVAL(cli->inbuf,smb_vwv1); cli->max_xmit = SVAL(cli->inbuf,smb_vwv2); @@ -2032,34 +2147,53 @@ void cli_shutdown(struct cli_state *cli) /**************************************************************************** return error codes for the last packet + returns 0 if there was no error and the bext approx of a unix errno + otherwise ****************************************************************************/ -BOOL cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num) +int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num) { int flgs2 = SVAL(cli->inbuf,smb_flg2); + char rcls; + int code; if (eclass) *eclass = 0; if (num ) *num = 0; - if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) - { + if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) { /* 32 bit error codes detected */ uint32 nt_err = IVAL(cli->inbuf,smb_rcls); if (num) *num = nt_err; DEBUG(10,("cli_error: 32 bit codes: code=%08x\n", nt_err)); - return (IS_BITS_SET_ALL(nt_err, 0xc0000000)); + if (!IS_BITS_SET_ALL(nt_err, 0xc0000000)) return 0; + + switch (nt_err & 0xFFFFFF) { + case NT_STATUS_ACCESS_VIOLATION: return EPERM; + } + + /* for all other cases - a default code */ + return EINVAL; } - else - { - /* dos 16 bit error codes detected */ - char rcls = CVAL(cli->inbuf,smb_rcls); - if (rcls != 0) - { - if (eclass) *eclass = rcls; - if (num ) *num = SVAL(cli->inbuf,smb_err); - return True; + + rcls = CVAL(cli->inbuf,smb_rcls); + code = SVAL(cli->inbuf,smb_err); + if (rcls == 0) return 0; + + if (eclass) *eclass = rcls; + if (num ) *num = code; + + if (rcls == ERRDOS) { + switch (code) { + case ERRbadfile: return ENOENT; + case ERRnoaccess: return EPERM; + } + } + if (rcls == ERRSRV) { + switch (code) { + case ERRbadpw: return EPERM; } } - return False; + /* for other cases */ + return EINVAL; } /**************************************************************************** |