#include "includes.h" #include "smbwrp.h" #ifndef DEBUG_PRINTF #define debug_printf( ...) #endif static int net_share_enum_rpc(struct cli_state *cli, void (*fn)(const char *name, uint32 type, const char *comment, void *state), void *state) { int i; WERROR result; ENUM_HND enum_hnd; uint32 info_level = 1; uint32 preferred_len = 0xffffffff; uint32 type; SRV_SHARE_INFO_CTR ctr; fstring name = ""; fstring comment = ""; void *mem_ctx; struct rpc_pipe_client *pipe_hnd; NTSTATUS nt_status; /* Open the server service pipe */ pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &nt_status); if (!pipe_hnd) { DEBUG(1, ("net_share_enum_rpc pipe open fail!\n")); return -1; } /* Allocate a context for parsing and for the entries in "ctr" */ mem_ctx = talloc_init("libsmbclient: net_share_enum_rpc"); if (mem_ctx == NULL) { DEBUG(0, ("out of memory for net_share_enum_rpc!\n")); cli_rpc_pipe_close(pipe_hnd); return -1; } /* Issue the NetShareEnum RPC call and retrieve the response */ init_enum_hnd(&enum_hnd, 0); result = rpccli_srvsvc_net_share_enum(pipe_hnd, mem_ctx, info_level, &ctr, preferred_len, &enum_hnd); /* Was it successful? */ if (!W_ERROR_IS_OK(result) || ctr.num_entries == 0) { /* Nope. Go clean up. */ goto done; } /* For each returned entry... */ for (i = 0; i < ctr.num_entries; i++) { /* pull out the share name */ rpcstr_pull_unistr2_fstring( name, &ctr.share.info1[i].info_1_str.uni_netname); /* pull out the share's comment */ rpcstr_pull_unistr2_fstring( comment, &ctr.share.info1[i].info_1_str.uni_remark); /* Get the type value */ type = ctr.share.info1[i].info_1.type; /* Add this share to the list */ (*fn)(name, type, comment, state); } done: /* Close the server service pipe */ cli_rpc_pipe_close(pipe_hnd); /* Free all memory which was allocated for this request */ TALLOC_FREE(mem_ctx); /* Tell 'em if it worked */ return W_ERROR_IS_OK(result) ? 0 : -1; } /* * Wrapper for cli_errno to return not connected error on negative fd */ int os2cli_errno(cli_state * cli) { if (cli->fd == -1) { return ENOTCONN; } return cli_errno(cli); } int _System smbwrp_getclisize(void) { return sizeof(struct cli_state); } /***************************************************** initialise structures *******************************************************/ int _System smbwrp_init(void) { static int initialised = 0; char *p; pstring line; if (initialised) { return 0; } initialised = 1; load_case_tables(); init_globals( True); load_interfaces(); if (!init_names()) { return 1; } /* if ((p=smbw_getshared("RESOLVE_ORDER"))) { lp_set_name_resolve_order(p); } */ return 0; } #if 0 /***************************************************** remove redundent stuff from a filename *******************************************************/ void clean_fname(char *name) { char *p, *p2; int l; int modified = 1; if (!name) return; while (modified) { modified = 0; if ((p=strstr(name,"/./"))) { modified = 1; while (*p) { p[0] = p[2]; p++; } } if ((p=strstr(name,"//"))) { modified = 1; while (*p) { p[0] = p[1]; p++; } } if (strcmp(name,"/../")==0) { modified = 1; name[1] = 0; } if ((p=strstr(name,"/../"))) { modified = 1; for (p2=(p>name?p-1:p);p2>name;p2--) { if (p2[0] == '/') break; } while (*p2) { p2[0] = p2[3]; p2++; } } if (strcmp(name,"/..")==0) { modified = 1; name[1] = 0; } l = strlen(name); p = l>=3?(name+l-3):name; if (strcmp(p,"/..")==0) { modified = 1; for (p2=p-1;p2>name;p2--) { if (p2[0] == '/') break; } if (p2==name) { p[0] = '/'; p[1] = 0; } else { p2[0] = 0; } } l = strlen(name); p = l>=2?(name+l-2):name; if (strcmp(p,"/.")==0) { if (p == name) { p[1] = 0; } else { p[0] = 0; } } if (strncmp(p=name,"./",2) == 0) { modified = 1; do { p[0] = p[2]; } while (*p++); } l = strlen(p=name); if (l > 1 && p[l-1] == '/') { modified = 1; p[l-1] = 0; } } } #endif /**************************************************************************** send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level ****************************************************************************/ BOOL cli_qpathinfo3(struct cli_state *cli, const char *fname, time_t *c_time, time_t *a_time, time_t *m_time, time_t *w_time, off_t *size, uint16 *mode, SMB_INO_T *ino) { unsigned int data_len = 0; unsigned int param_len = 0; uint16 setup = TRANSACT2_QPATHINFO; pstring param; char *rparam=NULL, *rdata=NULL; char *p; p = param; memset(p, 0, 6); SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO); p += 6; p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE); param_len = PTR_DIFF(p, param); if (!cli_send_trans(cli, SMBtrans2, NULL, /* name */ -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; } if (!cli_receive_trans(cli, SMBtrans2, &rparam, ¶m_len, &rdata, &data_len)) { return False; } if (!rdata || data_len < 22) { return False; } if (c_time) { *c_time = convert_timespec_to_time_t(interpret_long_date(rdata+0)); } if (a_time) { *a_time = convert_timespec_to_time_t(interpret_long_date(rdata+8)); } if (m_time) { *m_time = convert_timespec_to_time_t(interpret_long_date(rdata+16)); } if (w_time) { *w_time = convert_timespec_to_time_t(interpret_long_date(rdata+24)); } if (mode) { *mode = SVAL(rdata, 32); } if (size) { *size = IVAL2_TO_SMB_BIG_UINT(rdata, 48); } if (ino) { *ino = IVAL(rdata, 64); } SAFE_FREE(rdata); SAFE_FREE(rparam); return True; } /**************************************************************************** send a qfileinfo call ****************************************************************************/ BOOL cli_qfileinfo3(struct cli_state *cli, int fnum, uint16 *mode, off_t *size, time_t *c_time, time_t *a_time, time_t *m_time, time_t *w_time, SMB_INO_T *ino) { unsigned int data_len = 0; unsigned int param_len = 0; uint16 setup = TRANSACT2_QFILEINFO; pstring param; char *rparam=NULL, *rdata=NULL; /* if its a win95 server then fail this - win95 totally screws it up */ if (cli->win95) return False; param_len = 4; memset(param, 0, param_len); SSVAL(param, 0, fnum); SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO); if (!cli_send_trans(cli, SMBtrans2, NULL, /* name */ -1, 0, /* fid, flags */ &setup, 1, 0, /* setup, length, max */ param, param_len, 2, /* param, length, max */ NULL, data_len, cli->max_xmit /* data, length, max */ )) { return False; } if (!cli_receive_trans(cli, SMBtrans2, &rparam, ¶m_len, &rdata, &data_len)) { return False; } if (!rdata || data_len < 68) { return False; } if (c_time) { *c_time = convert_timespec_to_time_t(interpret_long_date(rdata+0)); } if (a_time) { *a_time = convert_timespec_to_time_t(interpret_long_date(rdata+8)); } if (m_time) { *m_time = convert_timespec_to_time_t(interpret_long_date(rdata+16)); } if (w_time) { *w_time = convert_timespec_to_time_t(interpret_long_date(rdata+24)); } if (mode) { *mode = SVAL(rdata, 32); } if (size) { *size = IVAL2_TO_SMB_BIG_UINT(rdata, 48); } if (ino) { *ino = IVAL(rdata, 64); } SAFE_FREE(rdata); SAFE_FREE(rparam); return True; } /***************************************************** return a connection to a server *******************************************************/ int _System smbwrp_connect(smbwrp_server * srv, struct cli_state ** cli, int krb5support) { char * server = srv->server_name; char * share = *(srv->share_name) ? srv->share_name : "IPC$"; char * workgroup = srv->workgroup; struct nmb_name called, calling; char *p, *server_n = server; fstring group; struct in_addr ip; NTSTATUS rc; struct cli_state * c; char* dev_type; zero_ip(&ip); debuglocal(1,"Connecting to \\\\%s:*********@%s:%s\\%s. Master %s:%d\n", srv->username, workgroup, server, share, srv->master, srv->ifmastergroup); if (!*server) { struct in_addr sip; if (*workgroup) { if (!find_master_ip(workgroup, &sip)) { return 1; } fstrcpy(group, inet_ntoa(sip)); server_n = group; } else if (*srv->master) { if (srv->ifmastergroup) { if (!find_master_ip(srv->master, &sip)) { return 11; } strncpy(srv->master, inet_ntoa(sip), sizeof(srv->master) - 1); srv->ifmastergroup = 0; } server_n = srv->master; } else { return 10; } } make_nmb_name(&calling, global_myname(), 0x0); // make_nmb_name(&calling, "WORK", 0x0); // this machine name make_nmb_name(&called , server_n, 0x20); again: zero_ip(&ip); /* have to open a new connection */ if (!(c=cli_initialise())) { return 2; } if (!NT_STATUS_IS_OK(cli_connect(c, server_n, &ip))) { return 3; } if (krb5support == 1){ debuglocal(1,"Kerberos support enabled\n"); c->use_kerberos = True;} if (!cli_session_request(c, &calling, &called)) { cli_shutdown(c); if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } return 4; } debuglocal(4," session request ok\n"); if (!cli_negprot(c)) { cli_shutdown(c); return 5; } debuglocal(4," session setuping for <%s>/<********> in <%s> %08x %08x %08x\n", srv->username, workgroup, c->protocol, c->sec_mode, c->capabilities); if (!NT_STATUS_IS_OK(cli_session_setup(c, srv->username, srv->password, strlen(srv->password), srv->password, strlen(srv->password), workgroup))) { debuglocal(4,"%s/******** login failed\n", srv->username); /* try an anonymous login if it failed */ if (!NT_STATUS_IS_OK(cli_session_setup(c, "", "", 1,"", 0, workgroup))) { debuglocal(4,"Anonymous login failed"); cli_shutdown(c); return 6; } } debuglocal(4," session setup ok. Sending tconx <%s> <********>\n", share); // YD ticket:58 we need to check resource type to avoid connecting to printers. // dev type is set to IPC for IPC$, A: for everything else (printers use LPT1:) if (!strcmp( share, "IPC$")) dev_type = "IPC"; else dev_type = "A:"; if (!cli_send_tconX(c, share, dev_type, srv->password, strlen(srv->password)+1)) { cli_shutdown(c); return 7; } debuglocal(4," tconx ok. cli caps %08x\n", c->capabilities); // copy back cli_state *cli = c; // srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); return 0; } /***************************************************** close a connection to a server *******************************************************/ void _System smbwrp_disconnect(struct cli_state ** cli) { if (cli) { // this call will free all buffers, close handles and free cli mem cli_shutdown(*cli); // set to zero because no longer valid *cli = 0; } } /***************************************************** a wrapper for open() *******************************************************/ int _System smbwrp_open(cli_state * cli, smbwrp_file * file) { int fd = -1; if (!cli || !file || !*file->fname) { return EINVAL; } if (file->denymode < DENY_ALL || file->denymode > DENY_NONE) { file->denymode = DENY_NONE; } debuglocal(4,"cli_open(%s) attr %08x mode %02x denymode %02x\n", file->fname, file->openattr, file->openmode, file->denymode); file->fd = cli_open(cli, file->fname, file->openmode, file->denymode); if (file->fd == -1) { return os2cli_errno(cli); } if (file->openmode & (O_WRONLY | O_RDWR | O_TRUNC | O_CREAT)) { time_t t; file->mtime = time(NULL); t = get_time_zone(file->mtime); debuglocal(4,"cli_open mtime %lu %lu\n", file->mtime, t); file->mtime -= t; } file->offset = 0; return 0; } /***************************************************** a wrapper for read() *******************************************************/ int _System smbwrp_read(cli_state * cli, smbwrp_file * file, void *buf, unsigned long count, unsigned long * result) { int ret; if (!cli || !file || !buf || !result) { return EINVAL; } *result = 0; ret = cli_read(cli, file->fd, buf, file->offset, count); if (ret == -1) { return os2cli_errno(cli); } file->offset += ret; *result = ret; return 0; } /***************************************************** a wrapper for write() *******************************************************/ int _System smbwrp_write(cli_state * cli, smbwrp_file * file, void *buf, unsigned long count, unsigned long * result) { int ret; if (!cli || !file || !buf || !result) { return EINVAL; } *result = 0; //debuglocal(1,("Write %x %d %lld %d", cli, file->fd, file->offset, count)); ret = cli_write(cli, file->fd, 0, buf, file->offset, count); if (ret == -1) { return os2cli_errno(cli); } file->offset += ret; *result = ret; return 0; } /***************************************************** a wrapper for close() *******************************************************/ int _System smbwrp_close(cli_state * cli, smbwrp_file * file) { int rc = 0; if (!cli || !file) { return EINVAL; } if (!cli_close(cli, file->fd)) { return os2cli_errno(cli); } file->fd = -1; file->offset = 0; if (file->openattr || file->mtime) { debuglocal(4,"Set attr on close %s %08x %d %d\n", file->fname, file->openattr, file->mtime, file->mtime); if (!cli_setatr(cli, file->fname, file->openattr, file->mtime)) { debuglocal(4,"Set attr on close failed %d\n", os2cli_errno(cli)); //rc = os2cli_errno(cli); } file->openattr = 0; file->mtime = 0; } *file->fname = 0; return rc; } /***************************************************** a wrapper for setfilesize() *******************************************************/ int cli_setfilenewsize(struct cli_state *cli, int fnum, off_t newsize) { unsigned int data_len = 8; unsigned int param_len = 6; uint16 setup = TRANSACT2_SETFILEINFO; pstring param; char *rparam=NULL, *rdata=NULL; memset(param, 0, param_len); SSVAL(param,0,fnum); SSVAL(param,2,SMB_SET_FILE_END_OF_FILE_INFO); if (!cli_send_trans(cli, SMBtrans2, NULL, /* name */ -1, 0, /* fid, flags */ &setup, 1, 0, /* setup, length, max */ param, param_len, 2, /* param, length, max */ (char *)&newsize, sizeof(newsize), cli->max_xmit /* data, length, max */ )) { return False; } if (!cli_receive_trans(cli, SMBtrans2, &rparam, ¶m_len, &rdata, &data_len)) { return False; } SAFE_FREE(rdata); SAFE_FREE(rparam); return True; } int _System smbwrp_setfilesize(cli_state * cli, smbwrp_file * file, long long newsize) { int rc = 0; if (!cli || !file) { return EINVAL; } debuglocal(4,"cli_setnewfileszie(%s) %lld\n", file->fname, newsize); if (!cli_setfilenewsize(cli, file->fd, newsize)) { if (newsize) { rc = os2cli_errno(cli); } if (!cli_close(cli, file->fd)) { return os2cli_errno(cli); } file->fd = -1; file->offset = 0; file->openmode &= ~(O_CREAT | O_EXCL); file->openmode |= O_TRUNC; debuglocal(4,"cli_setnewfileszie : cli_open(%s) attr %08x mode %02x denymode %02x\n", file->fname, file->openattr, file->openmode, file->denymode); file->fd = cli_open(cli, file->fname, file->openmode, file->denymode); if (file->fd == -1) { return os2cli_errno(cli); } } return 0; } /***************************************************** a wrapper for rename() *******************************************************/ int _System smbwrp_rename(cli_state * cli, char *oldname, char *newname) { if (!cli || !oldname || !newname) { return EINVAL; } debuglocal(1,"Rename <%s> -> <%s>\n", oldname, newname); //cli_unlink(cli, newname); // if (!cli_rename(cli, oldname, newname) && !cli_ntrename(cli, oldname, newname)) if (!cli_rename(cli, oldname, newname)) { return os2cli_errno(cli); } return 0; } /***************************************************** a wrapper for chmod() *******************************************************/ int _System smbwrp_setattr(cli_state * cli, smbwrp_fileinfo *finfo) { if (!cli || !finfo || !*finfo->fname) { return EINVAL; } debuglocal(4,"Setting on <%s> attr %04x, time %lu/%lu\n", finfo->fname, finfo->attr, finfo->mtime, finfo->mtime + get_time_zone(finfo->mtime)); if (!cli_setatr(cli, finfo->fname, finfo->attr, finfo->mtime + (finfo->mtime == 0 ? 0 : get_time_zone(finfo->mtime))) && !cli_setatr(cli, finfo->fname, finfo->attr, 0)) { return os2cli_errno(cli); } return 0; } /***************************************************** a wrapper for unlink() *******************************************************/ int _System smbwrp_unlink(cli_state * cli, const char *fname) { if (!cli || !fname) { return EINVAL; } #if 0 if (strncmp(cli->dev, "LPT", 3) == 0) { int job = smbw_stat_printjob(cli, fname, NULL, NULL); if (job == -1) { goto failed; } if (cli_printjob_del(cli, job) != 0) { goto failed; } } else #endif if (!cli_unlink(cli, fname)) { return os2cli_errno(cli); } return 0; } /***************************************************** a wrapper for lseek() *******************************************************/ int _System smbwrp_lseek(cli_state * cli, smbwrp_file * file, int whence, long long offset) { off_t size; if (!cli || !file) { return EINVAL; } debuglocal(4,"lseek %d %lld %lld\n", whence, offset, file->offset); switch (whence) { case SEEK_SET: if (offset < 0) { return EINVAL; } file->offset = offset; break; case SEEK_CUR: file->offset += offset; break; case SEEK_END: if (offset > 0) { return EINVAL; } if (!cli_qfileinfo3(cli, file->fd, NULL, &size, NULL, NULL, NULL, NULL, NULL) && !cli_getattrE(cli, file->fd, NULL, (SMB_BIG_UINT *)&size, NULL, NULL, NULL)) { return os2cli_errno(cli); } file->offset = size + offset; break; default: return EINVAL; } return 0; } /***************************************************** try to do a QPATHINFO and if that fails then do a getatr this is needed because win95 sometimes refuses the qpathinfo *******************************************************/ int _System smbwrp_getattr(smbwrp_server *srv, cli_state * cli, smbwrp_fileinfo *finfo) { SMB_INO_T ino = 0; if (!cli || !finfo || !*finfo->fname) { return EINVAL; } debug_printf( "smbwrp_getattr\n"); debuglocal(4,"getattr %d %d <%s>\n", cli->capabilities & CAP_NOPATHINFO2, cli->capabilities & CAP_NT_SMBS, finfo->fname); if (!(cli->capabilities & CAP_NOPATHINFO2) && cli_qpathinfo3(cli, finfo->fname, (time_t *)&finfo->ctime, (time_t *)&finfo->atime, (time_t *)&finfo->mtime, NULL, (off_t *)&finfo->size, (unsigned short *)&finfo->attr, &ino)) { finfo->attr &= 0x7F; //debuglocal(2,("gotattr %08x <%s>\n", finfo->attr, finfo->fname)); // finfo->ctime -= get_time_zone(finfo->ctime); // finfo->atime -= get_time_zone(finfo->atime); // finfo->mtime -= get_time_zone(finfo->mtime); return 0; } //debuglocal(2,("getattr rc1 %d\n", os2cli_errno(cli))); /* If the path is not on a share (it is a workgroup or a server), * then cli_qpathinfo3 obviously fails. Return some fake information * about the directory. */ if ( *srv->server_name == 0 || (strcmp(cli->dev,"IPC") == 0) || *srv->share_name == 0 || (stricmp(srv->share_name,"IPC$") == 0) || (strncmp(cli->dev,"LPT",3) == 0) ) { debuglocal(4,"getattr not a share.\n"); *(time_t *)&finfo->ctime = time (NULL); *(time_t *)&finfo->atime = time (NULL); *(time_t *)&finfo->mtime = time (NULL); finfo->size = 0; finfo->easize = 0; finfo->attr = aDIR; return 0; } /* if this is NT then don't bother with the getatr */ if (cli->capabilities & CAP_NT_SMBS && !(cli->capabilities & CAP_NOPATHINFO2)) { int rc = os2cli_errno(cli); // cli_qpathinfo* reports EINVAL when path of given file not exists // thus there is no real situation when EINVAL should be returned to // client at this point, we just replace it to ENOTDIR if (rc == EINVAL) { rc = ENOTDIR; } return rc; } if (cli_getatr(cli, finfo->fname, (unsigned short *)&finfo->attr, &finfo->size, (time_t *)&finfo->mtime)) { //debuglocal(2,("gotattr1 %08x <%s>\n", finfo->attr, finfo->fname)); finfo->mtime -= get_time_zone(finfo->mtime); finfo->atime = finfo->atime; //was mtime finfo->ctime = finfo->ctime; //was mtime cli->capabilities &= CAP_NOPATHINFO2; return 0; } return os2cli_errno(cli); } /***************************************************** try to do a QPATHINFO and if that fails then do a getatr this is needed because win95 sometimes refuses the qpathinfo *******************************************************/ int _System smbwrp_fgetattr(cli_state * cli, smbwrp_file *file, smbwrp_fileinfo *finfo) { SMB_INO_T ino = 0; if (!cli || !file || !finfo) { return EINVAL; } strncpy(finfo->fname, file->fname, sizeof(finfo->fname) - 1); if (!cli_qfileinfo3(cli, file->fd, (unsigned short *)&finfo->attr, (off_t *)&finfo->size, (time_t *)&finfo->ctime, (time_t *)&finfo->atime, (time_t *)&finfo->mtime, NULL, &ino)) { if (!cli_getattrE(cli, file->fd, (unsigned short *)&finfo->attr, (SMB_BIG_UINT *)(&finfo->size), (time_t *)&finfo->ctime, (time_t *)&finfo->atime, (time_t *)&finfo->mtime)) { return os2cli_errno(cli); } else { finfo->ctime -= get_time_zone(finfo->ctime); finfo->atime -= get_time_zone(finfo->atime); finfo->mtime -= get_time_zone(finfo->mtime); } } else { // finfo->ctime -= get_time_zone(finfo->ctime); // finfo->atime -= get_time_zone(finfo->atime); // finfo->mtime -= get_time_zone(finfo->mtime); } return 0; } // =============================DIRECTORY ROUTINES============================ /***************************************************** add a entry to a directory listing *******************************************************/ static void smbwrp_dir_add(const char* mnt, smbwrp_fileinfo *finfo, const char *mask, void *state) { if (state && finfo) { filelist_state * st = (filelist_state *)state; if (st->add_dir_entry) { debuglocal(8,"adding <%s> %d %d\n", finfo->fname, sizeof(st->finfo), st->datalen); memcpy(&st->finfo, finfo, sizeof(st->finfo)); st->add_dir_entry(state); } } } #if 0 static void smbwrp_dir_add_old(struct file_info *finfo, const char *mask, void *state) { if (state && finfo) { filelist_state * st = (filelist_state *)state; if (st->add_dir_entry) { strncpy(st->finfo.fname, finfo->name, sizeof(st->finfo.fname) - 1); st->finfo.size = finfo->size; st->finfo.easize = -1; st->finfo.attr = finfo->mode; st->finfo.ctime = finfo->ctime_ts.tv_sec - get_time_zone(finfo->ctime_ts.tv_sec); st->finfo.mtime = finfo->mtime_ts.tv_sec - get_time_zone(finfo->mtime_ts.tv_sec); st->finfo.atime = finfo->atime_ts.tv_sec - get_time_zone(finfo->atime_ts.tv_sec); st->add_dir_entry(state); } } } #endif static void smbwrp_special_add(const char * name, void * state) { smbwrp_fileinfo finfo = {0}; if (!name) { return; } ZERO_STRUCT(finfo); strncpy(finfo.fname, name, sizeof(finfo.fname) - 1); finfo.attr = aRONLY | aDIR; smbwrp_dir_add("", &finfo, NULL, state); } static void smbwrp_printjob_add(struct print_job_info *job, void * state) { smbwrp_fileinfo finfo = {0}; ZERO_STRUCT(finfo); //printf("Printjob <%s>\n", job->name); strncpy(finfo.fname, job->name, sizeof(finfo.fname) - 1); finfo.mtime = job->t - get_time_zone(job->t); finfo.atime = finfo.atime; //was mtime finfo.ctime = finfo.ctime; //was mtime finfo.attr = aRONLY; finfo.size = job->size; smbwrp_dir_add("", &finfo, NULL, state); } static void smbwrp_share_add(const char *share, uint32 type, const char *comment, void *state) { smbwrp_fileinfo finfo = {0}; // strip administrative names and printers from list if (type == STYPE_PRINTQ || strcmp(share,"IPC$") == 0) return; ZERO_STRUCT(finfo); strncpy(finfo.fname, share, sizeof(finfo.fname) - 1); finfo.attr = aRONLY | aDIR; smbwrp_dir_add("", &finfo, NULL, state); } /**************************************************************************** Interpret a long filename structure - this is mostly guesses at the moment. The length of the structure is returned The structure of a long filename depends on the info level. 260 is used by NT and 2 is used by OS/2 ****************************************************************************/ // YD from libsmb\clilist.c static size_t _os2_interpret_long_filename(struct cli_state *cli, int level,char *p, smbwrp_fileinfo *finfo, uint32 *p_resume_key, DATA_BLOB *p_last_name_raw, uint32 *p_last_name_raw_len) { extern file_info def_finfo; int len; char *base = p; smbwrp_fileinfo finfo1; if (!finfo) finfo = &finfo1; if (p_resume_key) { *p_resume_key = 0; } finfo->attr = def_finfo.mode; finfo->mtime = def_finfo.mtime_ts.tv_sec; finfo->atime = def_finfo.atime_ts.tv_sec; finfo->ctime = def_finfo.ctime_ts.tv_sec; strncpy(finfo->fname, def_finfo.name, sizeof(finfo->fname) - 1); debug_printf( "fname %s (serverzone %d, level %d)\n",finfo->fname, cli->serverzone, level); switch (level) { case 1: /* OS/2 understands this */ /* these dates are converted to GMT by make_unix_date */ finfo->ctime = cli_make_unix_date2(cli, p+4) - cli->serverzone; finfo->atime = cli_make_unix_date2(cli, p+8) - cli->serverzone; finfo->mtime = cli_make_unix_date2(cli, p+12) - cli->serverzone; finfo->size = IVAL(p,16); finfo->attr = CVAL(p,24); len = CVAL(p, 26); p += 27; p += clistr_align_in(cli, p, 0); /* the len+2 below looks strange but it is important to cope with the differences between win2000 and win9x for this call (tridge) */ p += clistr_pull(cli, finfo->fname, p, sizeof(finfo->fname), len+2, STR_TERMINATE); finfo->easize = -1; return PTR_DIFF(p, base); case 2: /* this is what OS/2 uses mostly */ /* these dates are converted to GMT by make_unix_date */ finfo->ctime = cli_make_unix_date2(cli, p+4) - cli->serverzone; finfo->atime = cli_make_unix_date2(cli, p+8) - cli->serverzone; finfo->mtime = cli_make_unix_date2(cli, p+12) - cli->serverzone; finfo->size = IVAL(p,16); finfo->attr = CVAL(p,24); finfo->easize = IVAL(p,26); len = CVAL(p, 30); p += 31; /* check for unisys! */ p += clistr_pull(cli, finfo->fname, p, sizeof(finfo->fname), len, STR_NOALIGN); return PTR_DIFF(p, base) + 1; case 260: /* NT uses this, but also accepts 2 */ { size_t namelen, slen; p += 4; /* next entry offset */ if (p_resume_key) { *p_resume_key = IVAL(p,0); } p += 4; /* fileindex */ /* Offset zero is "create time", not "change time". */ p += 8; finfo->atime = interpret_long_date(p).tv_sec; p += 8; finfo->mtime = interpret_long_date(p).tv_sec; p += 8; finfo->ctime = interpret_long_date(p).tv_sec; p += 8; finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0); p += 8; p += 8; /* alloc size */ finfo->attr = CVAL(p,0); p += 4; namelen = IVAL(p,0); p += 4; finfo->easize = IVAL(p,0); p += 4; /* EA size */ slen = SVAL(p, 0); p += 2; #if 0 { /* stupid NT bugs. grr */ int flags = 0; if (p[1] == 0 && namelen > 1) flags |= STR_UNICODE; clistr_pull(cli, finfo->short_name, p, sizeof(finfo->short_name), slen, flags); } #endif p += 24; /* short name? */ clistr_pull(cli, finfo->fname, p, sizeof(finfo->fname), namelen, 0); /* To be robust in the face of unicode conversion failures we need to copy the raw bytes of the last name seen here. Namelen doesn't include the terminating unicode null, so copy it here. */ #if 0 if (p_last_name_raw && p_last_name_raw_len) { if (namelen + 2 > p_last_name_raw->length) { memset(p_last_name_raw->data, '\0', sizeof(p_last_name_raw->length)); *p_last_name_raw_len = 0; } else { memcpy(p_last_name_raw->data, p, namelen); SSVAL(p_last_name_raw->data, namelen, 0); *p_last_name_raw_len = namelen + 2; } } #endif return (size_t)IVAL(base, 0); } } debuglocal(1,"Unknown long filename format %d\n",level); return (size_t)IVAL(base,0); } /**************************************************************************** Do a directory listing, calling fn on each file found. Modified from cli_list_new ****************************************************************************/ static int list_files(struct cli_state *cli, const char *Mask, uint16 attribute, void (*fn)(const char*, smbwrp_fileinfo *, const char *, void *), void *state) { #if 1 int max_matches = 1366; /* Match W2k - was 512. */ #else int max_matches = 512; #endif int info_level; char *p, *p2; pstring mask; smbwrp_fileinfo finfo; int i; char *dirlist = NULL; int dirlist_len = 0; int total_received = -1; BOOL First = True; int ff_searchcount=0; int ff_eos=0; int ff_dir_handle=0; int loop_count = 0; char *rparam=NULL, *rdata=NULL; unsigned int param_len, data_len; uint16 setup; pstring param; const char *mnt; uint32 resume_key = 0; uint32 last_name_raw_len = 0; DATA_BLOB last_name_raw = data_blob(NULL, 2*sizeof(pstring)); /* NT uses 260, OS/2 uses 2. Both accept 1. */ info_level = (cli->capabilities&CAP_NT_SMBS)?260:2; debuglocal(4,"list_files level %d. mask <%s>\n", info_level, mask); /* when getting a directory listing from a 2k dfs root share, we have to include the full path (\server\share\mask) here */ if ( cli->dfsroot ) pstr_sprintf( mask, "\\%s\\%s\\%s", cli->desthost, cli->share, Mask ); else pstrcpy(mask,Mask); while (ff_eos == 0) { loop_count++; if (loop_count > 200) { debuglocal(0,"Error: Looping in FIND_NEXT??\n"); break; } if (First) { setup = TRANSACT2_FINDFIRST; SSVAL(param,0,attribute); /* attribute */ SSVAL(param,2,max_matches); /* max count */ SSVAL(param,4,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END)); /* resume required + close on end */ SSVAL(param,6,info_level); SIVAL(param,8,0); p = param+12; p += clistr_push(cli, param+12, mask, sizeof(param)-12, STR_TERMINATE); } else { setup = TRANSACT2_FINDNEXT; SSVAL(param,0,ff_dir_handle); SSVAL(param,2,max_matches); /* max count */ SSVAL(param,4,info_level); /* For W2K servers serving out FAT filesystems we *must* set the resume key. If it's not FAT then it's returned as zero. */ SIVAL(param,6,resume_key); /* ff_resume_key */ /* NB. *DON'T* use continue here. If you do it seems that W2K and bretheren can miss filenames. Use last filename continue instead. JRA */ SSVAL(param,10,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END)); /* resume required + close on end */ p = param+12; if (last_name_raw_len && (last_name_raw_len < (sizeof(param)-12))) { memcpy(p, last_name_raw.data, last_name_raw_len); p += last_name_raw_len; } else { p += clistr_push(cli, param+12, mask, sizeof(param)-12, STR_TERMINATE); } } param_len = PTR_DIFF(p, param); if (!cli_send_trans(cli, SMBtrans2, NULL, /* Name */ -1, 0, /* fid, flags */ &setup, 1, 0, /* setup, length, max */ param, param_len, 10, /* param, length, max */ NULL, 0, #if 0 /* w2k value. */ MIN(16384,cli->max_xmit) /* data, length, max. */ #else cli->max_xmit /* data, length, max. */ #endif )) { break; } if (!cli_receive_trans(cli, SMBtrans2, &rparam, ¶m_len, &rdata, &data_len) && cli_is_dos_error(cli)) { /* we need to work around a Win95 bug - sometimes it gives ERRSRV/ERRerror temprarily */ uint8 eclass; uint32 ecode; SAFE_FREE(rdata); SAFE_FREE(rparam); cli_dos_error(cli, &eclass, &ecode); /* * OS/2 might return "no more files", * which just tells us, that searchcount is zero * in this search. * Guenter Kukkukk */ if (eclass == ERRDOS && ecode == ERRnofiles) { ff_searchcount = 0; cli_reset_error(cli); break; } if (eclass != ERRSRV || ecode != ERRerror) break; smb_msleep(100); continue; } if (cli_is_error(cli) || !rdata || !rparam) { if (First && info_level == 2) { // we have tried query ea size, but now will try without ea size info_level = 1; debuglocal(4,"list_files fallback to level %d\n", info_level); continue; } SAFE_FREE(rdata); SAFE_FREE(rparam); break; } if (total_received == -1) total_received = 0; /* parse out some important return info */ p = rparam; if (First) { ff_dir_handle = SVAL(p,0); ff_searchcount = SVAL(p,2); ff_eos = SVAL(p,4); } else { ff_searchcount = SVAL(p,0); ff_eos = SVAL(p,2); } debuglocal(4,"list_files %d %d %d %d\n", ff_searchcount, ff_eos, "(ff_lastname)", First); if (ff_searchcount == 0) { SAFE_FREE(rdata); SAFE_FREE(rparam); break; } /* point to the data bytes */ p = rdata; memset(&finfo, 0, sizeof(finfo)); finfo.easize = -1; /* we might need the lastname for continuations */ for (p2=p,i=0;i 0) { pstrcpy(mask, finfo.fname); } else { pstrcpy(mask,""); } /* grab the data for later use */ /* and add them to the dirlist pool */ dirlist = (char *)SMB_REALLOC(dirlist,dirlist_len + data_len); if (!dirlist) { debuglocal(0,"cli_list_new: Failed to expand dirlist\n"); SAFE_FREE(rdata); SAFE_FREE(rparam); break; } memcpy(dirlist+dirlist_len,p,data_len); dirlist_len += data_len; total_received += ff_searchcount; SAFE_FREE(rdata); SAFE_FREE(rparam); debuglocal(3,"received %d entries (eos=%d)\n", ff_searchcount,ff_eos); if (ff_searchcount > 0) loop_count = 0; First = False; } mnt = cli_cm_get_mntpoint( cli ); /* see if the server disconnected or the connection otherwise failed */ if (cli_is_error(cli)) { total_received = -1; } else { /* no connection problem. let user function add each entry */ for (p=dirlist,i=0;imask) { return EINVAL; } debuglocal(1,"Filelist <%s> on master <%s> wgrp <%s> server <%s> share <%s> clidev <%s>\n", state->mask, srv->master, srv->workgroup, srv->server_name, srv->share_name, cli->dev); debug_printf( "Filelist <%s> on master <%s> wgrp <%s> server <%s> share <%s> clidev <%s>\n", state->mask, srv->master, srv->workgroup, srv->server_name, srv->share_name, cli->dev); if (*srv->workgroup == 0 && *srv->server_name == 0) { smbwrp_special_add(".", state); smbwrp_special_add("..", state); cli_NetServerEnum(cli, srv->master, SV_TYPE_DOMAIN_ENUM, smbwrp_share_add, state); } else if (*srv->server_name == 0) { smbwrp_special_add(".", state); smbwrp_special_add("..", state); cli_NetServerEnum(cli, srv->workgroup, SV_TYPE_ALL, smbwrp_share_add, state); } else if ((strcmp(cli->dev,"IPC") == 0) || *srv->share_name == 0 || (stricmp(srv->share_name,"IPC$") == 0)) { smbwrp_special_add(".", state); smbwrp_special_add("..", state); if (net_share_enum_rpc(cli, smbwrp_share_add, state) < 0 && cli_RNetShareEnum(cli,smbwrp_share_add, state) < 0) { return os2cli_errno(cli); } } else if (strncmp(cli->dev,"LPT",3) == 0) { smbwrp_special_add(".", state); smbwrp_special_add("..", state); if (cli_print_queue_state(cli, smbwrp_printjob_add, state) < 0) { return os2cli_errno(cli); } } else { #if 0 if (strcmp(path,"\\") == 0) { smbwrp_special_add(".", state); smbwrp_special_add("..", state); } #endif #if 0 if (cli_list(cli, state->mask, aHIDDEN|aSYSTEM|aDIR, smbwrp_dir_add_old, state) < 0) #else if (list_files(cli, state->mask, aHIDDEN|aSYSTEM|aDIR, smbwrp_dir_add, state) < 0) #endif { return os2cli_errno(cli); } } return 0; } /***************************************************** a wrapper for chdir() *******************************************************/ int _System smbwrp_chdir(smbwrp_server *srv, cli_state * cli, char *fname) { unsigned short mode = aDIR; smbwrp_fileinfo finfo = {0}; if (!cli || !fname) { return EINVAL; } strncpy(finfo.fname, fname, sizeof(finfo.fname) - 1); if (smbwrp_getattr(srv, cli, &finfo)) { return os2cli_errno(cli); } if (!(finfo.attr & aDIR)) { return ENOTDIR; } return 0; } /***************************************************** a wrapper for mkdir() *******************************************************/ int _System smbwrp_mkdir(cli_state * cli, char *fname) { if (!cli || !fname) { return EINVAL; } if (!cli_mkdir(cli, fname)) { return os2cli_errno(cli); } return 0; } /***************************************************** a wrapper for rmdir() *******************************************************/ int _System smbwrp_rmdir(cli_state * cli, char *fname) { if (!cli || !fname) { return EINVAL; } if (!cli_rmdir(cli, fname)) { return os2cli_errno(cli); } return 0; } /***************************************************** set EA for a path *******************************************************/ int _System smbwrp_setea(cli_state * cli, char *fname, char * name, unsigned char * value, int size) { if (!cli || !fname || !name) { return EINVAL; } if (!cli_set_ea_path(cli, fname, name, value, size)) { return os2cli_errno(cli); } return 0; } /***************************************************** set EA for a file *******************************************************/ int _System smbwrp_fsetea(cli_state * cli, smbwrp_file *file, char * name, unsigned char * value, int size) { if (!cli || !file || !name) { return EINVAL; } if (!cli_set_ea_fnum(cli, file->fd, name, value, size)) { return os2cli_errno(cli); } return 0; } #pragma pack(1) typedef struct _FEA /* fea */ { unsigned char fEA; /* flags */ unsigned char cbName; /* name length not including NULL */ unsigned short cbValue; /* value length */ } FEA; typedef struct _FEALIST /* feal */ { unsigned long cbList; /* total bytes of structure including full list */ FEA list[1]; /* variable length FEA structures */ } FEALIST; #pragma pack() static int unilistea(cli_state * cli, char *fname, smbwrp_file *file, void * buffer, unsigned long size) { int fnum, i; int gotsize = sizeof(unsigned long); size_t num_eas; struct ea_struct *ea_list = NULL; TALLOC_CTX *mem_ctx; FEA * p; FEALIST * pfealist; char * q; mem_ctx = talloc_init("%d: ealist", _gettid()); pfealist = (FEALIST *)buffer; pfealist->cbList = 0; if (file) { if (!cli_get_ea_list_fnum(cli, file->fd, mem_ctx, &num_eas, &ea_list)) { debuglocal(4,"ea_get_fnum list failed - %s\n", cli_errstr(cli)); talloc_destroy(mem_ctx); return os2cli_errno(cli); } } else { if (!cli_get_ea_list_path(cli, fname, mem_ctx, &num_eas, &ea_list)) { debuglocal(4,"ea_get_file list failed - %s\n", cli_errstr(cli)); talloc_destroy(mem_ctx); return os2cli_errno(cli); } } debuglocal(4,"num_eas = %d\n", num_eas); // we will count that os/2 max EA size for file is 64kb p = pfealist->list; for (i = 0; i < num_eas; i++) { int namelen = strlen(ea_list[i].name); debuglocal(4, "%d Got EA <%s> with namelen %d, size %d. Gross %d. Buf %d\n", i, ea_list[i].name, namelen, ea_list[i].value.length, gotsize, size); if (namelen > 0xFF || ea_list[i].value.length > 0xFFFF) { debuglocal(4, "Skip EA <%s> with namelen %d, size %d\n", ea_list[i].name, namelen, ea_list[i].value.length); continue; } gotsize += sizeof(FEA) + namelen + ea_list[i].value.length + 1; if (size >= gotsize) { p->fEA = 0; p->cbName = namelen; p->cbValue = ea_list[i].value.length; q = (char *)(p + 1); strncpy(q, ea_list[i].name, namelen + 1); q += namelen + 1; memcpy(q, ea_list[i].value.data, ea_list[i].value.length); p = (FEA *)(q + ea_list[i].value.length); } } pfealist->cbList = gotsize; debuglocal(4,"ret size = %d\n", gotsize); talloc_destroy(mem_ctx); return 0; } /***************************************************** lists EA of a path *******************************************************/ int _System smbwrp_listea(cli_state * cli, char *fname, void * buffer, unsigned long size) { if (!cli || !fname || !buffer) { return EINVAL; } debuglocal(4,"EALIst for <%s>\n", fname); return unilistea(cli, fname, NULL, buffer, size); } /***************************************************** lists EA of a file *******************************************************/ int _System smbwrp_flistea(cli_state * cli, smbwrp_file *file, void * buffer, unsigned long size) { if (!cli || !file || !buffer) { return EINVAL; } debuglocal(4,"FEALIst for <%s>/%d\n", file->fname, file->fd); return unilistea(cli, NULL, file, buffer, size); } /**************************************************************************** Check the space on a device. ****************************************************************************/ int _System smbwrp_dskattr(cli_state * cli, FSALLOCATE *pfsa) { int total, bsize, avail; if (!cli || !pfsa) { return EINVAL; } if (!cli_dskattr(cli, &bsize, &total, &avail)) { debuglocal(4,"Error in dskattr: %s\n",cli_errstr(cli)); return os2cli_errno(cli); } debuglocal(4,"\n\t\t%d blocks of size %d. %d blocks available\n", total, bsize, avail); // YD currently Samba return it in MB! pfsa->cSectorUnit = 1; if (bsize > 65536) { pfsa->cUnit = total*1024; pfsa->cUnitAvail = avail*1024; pfsa->cbSector = bsize/1024; } else { pfsa->cUnit = total; pfsa->cUnitAvail = avail; pfsa->cbSector = bsize; } return 0; }