/* Netdrive Samba client plugin samba library wrappers Copyright (C) netlabs.org 2003-2012 Copyright (C) bww bitwise works GmbH 2012-2016 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" #include "rpc_client/cli_pipe.h" #include "librpc/gen_ndr/ndr_srvsvc_c.h" #include "libsmb/libsmb.h" #include "libsmb/clirap.h" #include "trans2.h" #include "dircache.h" #include "smbwrp.h" /* * Wrapper for cli_errno to return not connected error on negative fd * Now returns an OS/2 return code instead of lerrno. */ int os2cli_errno(cli_state * cli) { if (cli->fd == -1) return maperror(ENOTCONN); return maperror(cli_errno(cli)); } void smbwrp_Logging(Resource *pRes) { if (pRes && pRes->loglevel > 0) { // init samba for debug messages setup_logging("ndpsmb", DEBUG_FILE); char smblevel[3]; itoa(pRes->loglevel, smblevel, 10); lp_set_logfile(pRes->smb_logfile); lp_set_cmdline("log level", smblevel); reopen_logs(); } return; } const char * smbwrp_getVersion() { return samba_version_string(); } int _System smbwrp_getclisize(void) { return sizeof(struct cli_state); } /* * initialise structures */ int _System smbwrp_init(Resource *pRes) { char *p; if (pRes->smb_initialised) return 0; pRes->smb_initialised = 1; lp_set_in_client(true); // Make sure that we tell lp_load we are client load_case_tables(); if (!lp_load(get_dyn_CONFIGFILE(),true,false,false,true)) debuglocal(pRes, 0,("The initial smb.conf is missing, defaults are used!\n")); load_interfaces(); if (!init_names()) return 1; smbwrp_Logging(pRes); debuglocal(pRes, 5,("smbwrp_init done\n")); /* if ((p=smbw_getshared("RESOLVE_ORDER"))) lp_set_name_resolve_order(p); */ return 0; } void smbwrp_initthread(void) { /* * Block SIGPIPE (from lib/util_sock.c: write()) * It is not needed and should not stop execution */ BlockSignals(True, SIGPIPE); return; } #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 /* * return a connection to a server */ int _System smbwrp_connect(Resource* pRes, cli_state ** cli) { smbwrp_server * srv = &pRes->srv; 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 sockaddr_storage ss; struct cli_state * c; char* dev_type; int loginerror = 0; NTSTATUS status; zero_sockaddr(&ss); debuglocal(pRes, 1,"Connecting to \\\\%s:*********@%s:%s\\%s. Master %s:%d\n", srv->username, workgroup, server, share, srv->master, srv->ifmastergroup); if (!*server) { struct sockaddr_storage sip; if (*workgroup) { if (!find_master_ip(workgroup, &sip)) return 1; fstrcpy(group, inet_ntoa(sip.sin_addr)); 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.sin_addr), 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_sockaddr(&ss); // have to open a new connection if (!(c=cli_initialise())) return 2; cli_set_timeout(c, 10000); // 10 seconds if (pRes->krb5support == 1) { debuglocal(pRes, 1,"Kerberos support enabled\n"); c->use_kerberos = True; } if (!NT_STATUS_IS_OK(cli_connect(c, server_n, &ss))) return 3; 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(pRes, 4,"session request ok\n"); if (!NT_STATUS_IS_OK(cli_negprot(c))) { cli_shutdown(c); return 5; } debuglocal(pRes, 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(pRes, 4,"%s/******** login failed\n", srv->username); loginerror = 1; // save the login error // try an anonymous login if it failed if (!NT_STATUS_IS_OK(cli_session_setup(c, "", "", 0,"", 0, workgroup))) { debuglocal(pRes, 4,"Anonymous login failed\n"); cli_shutdown(c); return 6; } debuglocal(pRes, 4,"Anonymous login successful\n"); status = cli_init_creds(c, "", lp_workgroup(), ""); } else { status = cli_init_creds(c, srv->username, workgroup, srv->password); } if (!NT_STATUS_IS_OK(status)) { debuglocal(pRes, 4,"cli_init_creds() failed\n"); cli_shutdown(c); // if loginerror is != 0 means normal login failed, but anonymous login worked if (loginerror !=0) return 6; else return 7; } debuglocal(pRes, 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 (!NT_STATUS_IS_OK(cli_tcon_andx(c, share, dev_type, srv->password, strlen(srv->password)+1))) { cli_shutdown(c); // if loginerror is != 0 means normal login failed, but anonymous login worked if (loginerror !=0) return 6; else return 7; } debuglocal(pRes, 4,"tconx ok. cli caps %08x\n", c->capabilities); // save cli_state pointer *cli = c; return 0; } /* * close a connection to a server */ void _System smbwrp_disconnect(Resource* pRes, cli_state * cli) { // this call will free all buffers, close handles and free cli mem if (pRes && cli) cli_shutdown( cli); } /* * a wrapper for open() */ int _System smbwrp_open(Resource *pRes, cli_state * cli, smbwrp_file * file) { uint16_t fd = 0; if (!cli || !file || !*file->fname) return maperror(EINVAL); if (file->denymode < DENY_ALL || file->denymode > DENY_NONE) file->denymode = DENY_NONE; debuglocal(pRes, 4,"cli_open(%s) attr %08x mode %02x denymode %02x\n", file->fname, file->openattr, file->openmode, file->denymode); if (!NT_STATUS_IS_OK(cli_open(cli, file->fname, file->openmode, file->denymode, &fd))) return os2cli_errno(cli); file->fd = fd; file->updatetime = 0; file->offset = 0; return 0; } /* * a wrapper for read() */ int _System smbwrp_read(Resource *pRes, cli_state * cli, smbwrp_file * file, void *buf, unsigned long count, unsigned long * result) { int ret; if (!cli || !file || !buf || !result) return maperror(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(Resource *pRes, cli_state * cli, smbwrp_file * file, void *buf, unsigned long count, unsigned long * result) { NTSTATUS status; size_t ret; if (!cli || !file || !buf || !result) return maperror(EINVAL); *result = 0; debuglocal(pRes, 10, "Write %x %d %lld %d\n", cli, file->fd, file->offset, count); status = cli_writeall(cli, file->fd, 0, buf, file->offset, count, &ret); if (!NT_STATUS_IS_OK(status)) return os2cli_errno(cli); file->updatetime = 1; file->offset += ret; *result = ret; return 0; } /* * a wrapper for close() */ int _System smbwrp_close(Resource *pRes, cli_state * cli, smbwrp_file * file) { int rc = 0; if (!cli || !file) return maperror(EINVAL); debuglocal(pRes, 4,"smpwrp_close updatetime: %d\n", file->updatetime); if (file->updatetime == 1) { file->mtime = time(NULL); debuglocal(pRes, 4,"cli_close new mtime %lu\n", file->mtime); } if (!NT_STATUS_IS_OK(cli_close(cli, file->fd))) rc = os2cli_errno(cli); if (!rc && (file->openattr || file->mtime || file->ctime)) { debuglocal(pRes, 4,"Set pathinfo on close %s %08x %d %d\n", file->fname, file->openattr, file->mtime, file->ctime); if (!NT_STATUS_IS_OK(cli_setpathinfo_basic(cli, file->fname, file->ctime, 0, file->mtime, 0, file->openattr))) { debuglocal(pRes, 4,"Set pathinfo on close failed %d\n", os2cli_errno(cli)); } } file->openattr = 0; file->mtime = 0; file->ctime = 0; file->updatetime = 0; file->fd = -1; file->offset = 0; *file->fname = 0; return rc; } int _System smbwrp_setfilesize(Resource *pRes, cli_state * cli, smbwrp_file * file, long long newsize) { int rc = 0; if (!cli || !file) return maperror(EINVAL); debuglocal(pRes, 4,"cli_setnewfilesize(%s) %lld\n", file->fname, newsize); if (!NT_STATUS_IS_OK(cli_ftruncate(cli, file->fd, newsize))) { if (newsize) rc = os2cli_errno(cli); if (!NT_STATUS_IS_OK(cli_close(cli, file->fd))) return os2cli_errno(cli); uint16_t fd = 0; file->fd = -1; file->offset = 0; file->openmode &= ~(O_CREAT | O_EXCL); file->openmode |= O_TRUNC; debuglocal(pRes, 4,"cli_setnewfileszie : cli_open(%s) attr %08x mode %02x denymode %02x\n", file->fname, file->openattr, file->openmode, file->denymode); if (!NT_STATUS_IS_OK(cli_open(cli, file->fname, file->openmode, file->denymode, &fd))) return os2cli_errno(cli); file->fd = fd; } return 0; } /* * a wrapper for rename() */ int _System smbwrp_rename(Resource *pRes, cli_state * cli, char *oldname, char *newname) { if (!cli || !oldname || !newname) return maperror(EINVAL); debuglocal(pRes, 4,"Rename <%s> -> <%s>\n", oldname, newname); if (!NT_STATUS_IS_OK(cli_rename(cli, oldname, newname))) return os2cli_errno(cli); return 0; } /* * a wrapper for chmod() */ int _System smbwrp_setattr(Resource *pRes, cli_state * cli, smbwrp_fileinfo *finfo) { if (!cli || !finfo || !*finfo->fname) return maperror(EINVAL); debuglocal(pRes, 4,"Setting on <%s> attr %04x, time %lu (timezone /%lu\n", finfo->fname, finfo->attr, finfo->mtime, finfo->mtime + get_time_zone(finfo->mtime)); // we already have gmt time, so no need to add timezone // if (!cli_setatr(cli, finfo->fname, finfo->attr, finfo->mtime + (finfo->mtime == 0 ? 0 : get_time_zone(finfo->mtime))) if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo->fname, finfo->attr, finfo->mtime)) && !NT_STATUS_IS_OK(cli_setatr(cli, finfo->fname, finfo->attr, 0))) return os2cli_errno(cli); return 0; } /* * a wrapper for unlink() */ int _System smbwrp_unlink(Resource *pRes, cli_state * cli, const char *fname) { if (!cli || !fname) return maperror(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 (!NT_STATUS_IS_OK(cli_unlink(cli, fname, aSYSTEM | aHIDDEN))) return os2cli_errno(cli); return 0; } /* * a wrapper for lseek() */ int _System smbwrp_lseek(Resource *pRes, cli_state * cli, smbwrp_file * file, int whence, long long offset) { off_t size; if (!cli || !file) return maperror(EINVAL); debuglocal(pRes, 4,"lseek %d %lld %lld\n", whence, offset, file->offset); switch (whence) { case SEEK_SET: if (offset < 0) return maperror(EINVAL); file->offset = offset; break; case SEEK_CUR: file->offset += offset; break; case SEEK_END: if (offset > 0) return maperror(EINVAL); if (!NT_STATUS_IS_OK(cli_qfileinfo_basic(cli, file->fd, NULL, &size, NULL, NULL, NULL,NULL, NULL)) && !NT_STATUS_IS_OK(cli_getattrE(cli, file->fd, NULL, &size, NULL, NULL, NULL))) return os2cli_errno(cli); file->offset = size + offset; break; default: return maperror(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(Resource *pRes, smbwrp_server *srv, cli_state * cli, smbwrp_fileinfo *finfo) { SMB_INO_T ino = 0; struct timespec ctime; struct timespec mtime; struct timespec atime; if (!cli || !finfo || !*finfo->fname) return maperror(EINVAL); debuglocal(pRes, 4,"getattr %d %d <%s>\n", cli->capabilities & CAP_NOPATHINFO2, cli->capabilities & CAP_NT_SMBS, finfo->fname); if (!(cli->capabilities & CAP_NOPATHINFO2) && NT_STATUS_IS_OK(cli_qpathinfo2(cli, finfo->fname, &ctime, &atime, &mtime, NULL, (off_t *)&finfo->size, (unsigned short *)&finfo->attr, &ino))) { finfo->attr &= 0x7F; finfo->ctime = convert_timespec_to_time_t(ctime); finfo->atime = convert_timespec_to_time_t(atime); finfo->mtime = convert_timespec_to_time_t(mtime); return 0; } // fd == -1 means the connection is broken */ if (cli->fd == -1) return maperror(ENOTCONN); /* If the path is not on a share (it is a workgroup or a server), * then cli_qpathinfo2 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(pRes, 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 ret = cli_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 (ret == EINVAL) ret = ENOTDIR; return maperror(ret); } if (NT_STATUS_IS_OK(cli_getatr(cli, finfo->fname, (unsigned short *)&finfo->attr, &finfo->size, (time_t *)&finfo->mtime))) { debuglocal(pRes, 10,("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(Resource *pRes, cli_state * cli, smbwrp_file *file, smbwrp_fileinfo *finfo) { struct timespec ctime; struct timespec mtime; struct timespec atime; SMB_INO_T ino = 0; if (!cli || !file || !finfo) return maperror(EINVAL); strncpy(finfo->fname, file->fname, sizeof(finfo->fname) - 1); if (!NT_STATUS_IS_OK(cli_qfileinfo_basic(cli, file->fd, (unsigned short *)&finfo->attr, (off_t *)&finfo->size, &ctime, &atime, &mtime, NULL, &ino))) { if (!NT_STATUS_IS_OK(cli_getattrE(cli, file->fd, (unsigned short *)&finfo->attr, (&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 = convert_timespec_to_time_t(ctime); finfo->atime = convert_timespec_to_time_t(atime); finfo->mtime = convert_timespec_to_time_t(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; char fullname[ _MAX_PATH] = {0}; debuglocal(st->pConn->pRes, 8,"adding <%s> %d %d %d\n", finfo->fname, sizeof(st->finfo), st->datalen, sizeof(st->finfo.fname)); memcpy(&st->finfo, finfo, sizeof(st->finfo)); strncpy(fullname, st->dir, strlen(st->dir)); strncat(fullname, finfo->fname, sizeof(fullname) - strlen(fullname) -1); strncpy(st->finfo.fname, fullname, sizeof(st->finfo.fname)); addFindInfoL(st->pConn->pRes, st->plist, &st->finfo, st->ulAttribute, st->dir_mask); } return; } 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); return; } 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); return; } 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); return; } /* * Do a directory listing, calling fn on each file found. * Modified from cli_list */ static int list_files(struct cli_state *cli, const char *mask, uint16 attribute, void (*fn)(const char *, smbwrp_fileinfo *, const char *, void *), filelist_state *state) { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_NO_MEMORY; struct file_info *finfo; size_t i, num_finfo; uint16_t info_level; void *dircachectx = NULL; Resource *pRes = state->pConn->pRes; // Try to get the listing from cache. debuglocal(pRes, 9, "list_files: check cache %s\n", state->fullpath); if (dircache_list_files(pRes->pdc, addFindInfoCachedL, state->plist, state->dir_mask, (char*) state->fullpath, &num_finfo)) { debuglocal(pRes, 9, "list_files: %s, got %d from cache\n", state->fullpath, num_finfo); return(num_finfo); // Got from cache } if (cli_has_async_calls(cli)) { /* * Can't use sync call while an async call is in flight */ status = NT_STATUS_INVALID_PARAMETER; goto fail; } ev = event_context_init(frame); if (ev == NULL) goto fail; info_level = (cli->capabilities & CAP_NT_SMBS) ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_EA_SIZE; debuglocal(pRes, 4,"list_files level %d. mask <%s>\n", info_level, mask); req = cli_list_send(frame, ev, cli, mask, attribute, info_level); if (req == NULL) goto fail; if (!tevent_req_poll(req, ev)) { status = map_nt_error_from_unix(errno); goto fail; } status = cli_list_recv(req, frame, &finfo, &num_finfo); if (!NT_STATUS_IS_OK(status)) goto fail; dircachectx = dircache_write_begin(pRes->pdc, state->dir_mask, (char*) state->fullpath, num_finfo); debuglocal(pRes, 4,"list_files: got %d files\n", num_finfo); for (i=0; isize = finfo[i].size; wrpfinfo->attr = finfo[i].mode; wrpfinfo->ctime = convert_timespec_to_time_t(finfo[i].ctime_ts); wrpfinfo->mtime = convert_timespec_to_time_t(finfo[i].mtime_ts); wrpfinfo->atime = convert_timespec_to_time_t(finfo[i].atime_ts); wrpfinfo->easize = finfo[i].easize; strncpy(wrpfinfo->fname, finfo[i].name, sizeof(wrpfinfo->fname) -1); // add to netdrive plist debuglocal(pRes, 9,"list_files: dircachectx %x, %s->%p\n", dircachectx, wrpfinfo->fname, wrpfinfo); addFindInfoCachedL(state->plist, wrpfinfo); // Also add the entry to the cache, this pointer will be released // when cache will be deleted dircache_write_entry(pRes->pdc, dircachectx, wrpfinfo->fname, wrpfinfo); } dircache_write_end(pRes->pdc, dircachectx); fail: TALLOC_FREE(frame); return num_finfo; } /* * open a directory on the server */ int _System smbwrp_filelist(Resource *pRes, smbwrp_server *srv, cli_state * cli, filelist_state * state) { if (!srv || !cli || !state || !*state->mask) return maperror(EINVAL); debuglocal(pRes, 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); 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 (list_files(cli, state->mask, aHIDDEN|aSYSTEM|aDIR, smbwrp_dir_add, state) < 0) return os2cli_errno(cli); } return 0; } /* * a wrapper for chdir() */ int _System smbwrp_chdir(Resource *pRes, smbwrp_server *srv, cli_state * cli, char *fname) { unsigned short mode = aDIR; smbwrp_fileinfo finfo = {0}; if (!cli || !fname) return maperror(EINVAL); strncpy(finfo.fname, fname, sizeof(finfo.fname) - 1); if (smbwrp_getattr(pRes, srv, cli, &finfo)) return os2cli_errno(cli); if (!(finfo.attr & aDIR)) return maperror(ENOTDIR); return 0; } /* * a wrapper for mkdir() */ int _System smbwrp_mkdir(Resource *pRes, cli_state * cli, char *fname) { if (!cli || !fname) return maperror(EINVAL); if (!NT_STATUS_IS_OK(cli_mkdir(cli, fname))) return os2cli_errno(cli); return 0; } /* * a wrapper for rmdir() */ int _System smbwrp_rmdir(Resource *pRes, cli_state * cli, char *fname) { if (!cli || !fname) return maperror(EINVAL); if (!NT_STATUS_IS_OK(cli_rmdir(cli, fname))) return os2cli_errno(cli); return 0; } /* * set EA for a path */ int _System smbwrp_setea(Resource *pRes, cli_state * cli, char *fname, char * name, unsigned char * value, int size) { if (!cli || !fname || !name) return maperror(EINVAL); if (!NT_STATUS_IS_OK(cli_set_ea_path(cli, fname, name, value, size))) return os2cli_errno(cli); return 0; } /* * set EA for a file */ int _System smbwrp_fsetea(Resource *pRes, cli_state * cli, smbwrp_file *file, char * name, unsigned char * value, int size) { if (!cli || !file || !name) return maperror(EINVAL); if (!NT_STATUS_IS_OK(cli_set_ea_fnum(cli, file->fd, name, value, size))) return os2cli_errno(cli); return 0; } static int unilistea(Resource *pRes, cli_state * cli, char *fname, 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 (!NT_STATUS_IS_OK(cli_get_ea_list_path(cli, fname, mem_ctx, &num_eas, &ea_list))) { debuglocal(pRes, 4,"ea_get_file list failed - %s\n", cli_errstr(cli)); talloc_destroy(mem_ctx); return os2cli_errno(cli); } debuglocal(pRes, 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(pRes, 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(pRes, 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(pRes, 4,"ret size = %d\n", gotsize); talloc_destroy(mem_ctx); return 0; } /* * lists EA of a path */ int _System smbwrp_listea(Resource *pRes, cli_state * cli, char *fname, void * buffer, unsigned long size) { if (!cli || !fname || !buffer) return maperror(EINVAL); debuglocal(pRes, 4,"EALIst for <%s>\n", fname); return unilistea(pRes, cli, fname, buffer, size); } /* * lists EA of a file */ int _System smbwrp_flistea(Resource *pRes, cli_state * cli, smbwrp_file *file, void * buffer, unsigned long size) { if (!cli || !file || !buffer) return maperror(EINVAL); debuglocal(pRes, 4,"FEALIst for <%s>\n", file->fname); return unilistea(pRes, cli, file->fname, buffer, size); } /* * Check the space on a device. */ int _System smbwrp_dskattr(Resource *pRes, cli_state * cli, FSALLOCATE *pfsa) { int total, bsize, avail; if (!cli || !pfsa) return maperror(EINVAL); if (!NT_STATUS_IS_OK(cli_dskattr(cli, &bsize, &total, &avail))) { debuglocal(pRes, 4,"Error in dskattr: %s\n",cli_errstr(cli)); return os2cli_errno(cli); } debuglocal(pRes, 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; }