1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-13 13:18:06 +03:00

The latest changes to libsmbclient ...

It can now do a directory listing for workgroups, servers, and shares, and,
with a bit more effort, it will be able to list directories and files.

I also does not request a username and password for the IPC$ share, but it
should if the first attempt to connect fails.
(This used to be commit 38ff91c505)
This commit is contained in:
Richard Sharpe 2001-01-05 13:43:19 +00:00
parent dca808cbc4
commit b6e811b90b
3 changed files with 596 additions and 24 deletions

View File

@ -55,11 +55,13 @@ void auth_fn(char *server, char *share,
int main(int argc, char *argv[])
{
int err, fd;
int err, fd, dh1, dh2, dh3, dsize, dirc;
const char *file = "smb://samba/public/testfile.txt";
const char *file2 = "smb://samba/public/testfile2.txt";
const char *workgroup = "sambanet";
char buff[256];
char dirbuf[512];
struct smbc_dirent *dirp;
struct stat st1, st2;
err = smbc_init(auth_fn, workgroup, 10); /* Initialize things */
@ -70,6 +72,121 @@ int main(int argc, char *argv[])
}
if (argc > 1) {
if ((dh1 = smbc_opendir("smb://"))<1) {
fprintf(stderr, "Could not open directory: smb://: %s\n",
strerror(errno));
exit(1);
}
if ((dh2 = smbc_opendir("smb://sambanet")) < 0) {
fprintf(stderr, "Could not open directory: smb://sambanet: %s\n",
strerror(errno));
exit(1);
}
if ((dh3 = smbc_opendir("smb://samba")) < 0) {
fprintf(stderr, "Could not open directory: smb://samba: %s\n",
strerror(errno));
exit(1);
}
fprintf(stdout, "Directory handles: %u, %u, %u\n", dh1, dh2, dh3);
/* Now, list those directories, but in funny ways ... */
dirp = (struct smbc_dirent *)dirbuf;
if ((dirc = smbc_getdents(dh1, dirp, sizeof(dirbuf))) < 0) {
fprintf(stderr, "Problems getting directory entries: %s\n",
strerror(errno));
exit(1);
}
/* Now, process the list of names ... */
fprintf(stdout, "Directory listing, size = %u\n", dirc);
while (dirc > 0) {
dsize = sizeof(struct smbc_dirent) + dirp->namelen + dirp->commentlen + 1;
fprintf(stdout, "Dir Ent, Type: %u, Name: %s, Comment: %s\n",
dirp->smbc_type, dirp->name, dirp->comment);
(char *)dirp += dsize;
(char *)dirc -= dsize;
}
dirp = (struct smbc_dirent *)dirbuf;
if ((dirc = smbc_getdents(dh2, dirp, sizeof(dirbuf))) < 0) {
fprintf(stderr, "Problems getting directory entries: %s\n",
strerror(errno));
exit(1);
}
/* Now, process the list of names ... */
fprintf(stdout, "\nDirectory listing, size = %u\n", dirc);
while (dirc > 0) {
dsize = sizeof(struct smbc_dirent) + dirp->namelen + dirp->commentlen + 1;
fprintf(stdout, "Dir Ent, Type: %u, Name: %s, Comment: %s\n",
dirp->smbc_type, dirp->name, dirp->comment);
(char *)dirp += dsize;
(char *)dirc -= dsize;
}
dirp = (struct smbc_dirent *)dirbuf;
if ((dirc = smbc_getdents(dh3, dirp, sizeof(dirbuf))) < 0) {
fprintf(stderr, "Problems getting directory entries: %s\n",
strerror(errno));
exit(1);
}
/* Now, process the list of names ... */
fprintf(stdout, "Directory listing, size = %u\n", dirc);
while (dirc > 0) {
dsize = sizeof(struct smbc_dirent) + dirp->namelen + dirp->commentlen + 1;
fprintf(stdout, "\nDir Ent, Type: %u, Name: %s, Comment: %s\n",
dirp->smbc_type, dirp->name, dirp->comment);
(char *)dirp += dsize;
(char *)dirc -= dsize;
}
exit(1);
}
/* For now, open a file on a server that is hard coded ... later will
* read from the command line ...
*/

View File

@ -29,7 +29,28 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#define SMBC_MAX_NAME 1023
struct smbc_dirent {
uint smbc_type; /* Type of entity, see below */
uint namelen;
uint commentlen;
char *comment; /* Points to the comment futher down */
char name[1];
};
#define SMBC_WORKGROUP 1
#define SMBC_SERVER 2
#define SMBC_FILE_SHARE 3
#define SMBC_PRINTER_SHARE 4
#define SMBC_COMMS_SHARE 5
#define SMBC_IPC_SHARE 6
#define SMBC_DIR 7
#define SMBC_FILE 8
#define SMBC_LINK 9
#define SMBC_FILE_MODE (S_IFREG | 0444)
#define SMBC_DIR_MODE (S_IFDIR | 0555)
@ -133,7 +154,7 @@ int smbc_closedir(int fd);
* Get a directory entry
*/
int smbc_getdents(unsigned int fd, struct dirent *dirp, int count);
int smbc_getdents(unsigned int fd, struct smbc_dirent *dirp, int count);
/*
* Create a directory on a server, share, dir in fname URL

View File

@ -39,6 +39,12 @@ struct smbc_server {
BOOL no_pathinfo2;
};
/* Keep directory entries in a list */
struct smbc_dir_list {
struct smbc_dir_list *next;
struct smbc_dirent *dirent;
};
struct smbc_file {
int cli_fd;
int smbc_fd;
@ -46,21 +52,26 @@ struct smbc_file {
off_t offset;
struct smbc_server *srv;
BOOL file;
struct smbc_dir_list *dir_list, *dir_end, *dir_next;
int dir_type, dir_error;
};
extern BOOL in_client;
static int smbc_initialized = 0;
static smbc_get_auth_data_fn smbc_auth_fn = NULL;
static int smbc_debug;
static int smbc_start_fd;
static int smbc_max_fd = 10000;
static struct smbc_file **smbc_file_table;
static struct smbc_server *smbc_srvs;
static pstring my_netbios_name;
/*
* Clean up a filename by removing redundent stuff
*/
static void
clean_fname(char *name)
smbc_clean_fname(char *name)
{
char *p, *p2;
int l;
@ -153,8 +164,11 @@ clean_fname(char *name)
/*
* Function to parse a path and turn it into components
*
* We accept smb://server/share/path...
* We also accept //server/share/path ...
* We accept smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]]
*
* smb:// means show all the workgroups
* smb://name/ means, if name<1D> exists, list servers in workgroup,
* else, if name<20> exists, list all shares for server ...
*/
static const char *smbc_prefix = "smb:";
@ -167,6 +181,7 @@ smbc_parse_path(const char *fname, char *server, char *share, char *path)
int len;
fstring workgroup;
server[0] = share[0] = path[0] = (char)0;
pstrcpy(s, fname);
/* clean_fname(s); causing problems ... */
@ -186,7 +201,10 @@ smbc_parse_path(const char *fname, char *server, char *share, char *path)
}
p += 2; /* Skip the // or \\ */
p += 2; /* Skip the // or \\ */
if (*p == (char)0)
return 0;
/* ok, its for us. Now parse out the server, share etc. */
@ -195,13 +213,15 @@ smbc_parse_path(const char *fname, char *server, char *share, char *path)
return -1;
}
if (*p == (char)0) return 0; /* That's it ... */
if (!next_token(&p, share, "/", sizeof(fstring))) {
return -1;
}
pstrcpy(path, p);
all_string_sub(path, "/", "\\", 0);
@ -232,9 +252,6 @@ int smbc_errno(struct cli_state *c)
* Connect to a server, possibly on an existing connection
*/
static struct smbc_server *smbc_srvs;
static pstring my_netbios_name;
struct smbc_server *smbc_server(char *server, char *share)
{
struct smbc_server *srv=NULL;
@ -252,7 +269,15 @@ struct smbc_server *smbc_server(char *server, char *share)
ip = ipzero;
ZERO_STRUCT(c);
smbc_auth_fn(server, share, &workgroup, &username, &password);
if (strncmp(share, "IPC$", 4)) /* IPC$ should not need a pwd ... */
smbc_auth_fn(server, share, &workgroup, &username, &password);
else {
workgroup = lp_workgroup(); /* Is this relevant here? */
username = "";
password = "";
}
/* try to use an existing connection */
for (srv=smbc_srvs;srv;srv=srv->next) {
@ -394,8 +419,9 @@ struct smbc_server *smbc_server(char *server, char *share)
int smbc_init(smbc_get_auth_data_fn fn, const char *wgroup, int debug)
{
static pstring workgroup;
pstring conf;
int p, pid;
char *user = NULL, *host = NULL;
char *user = NULL, *host = NULL, *home = NULL;
smbc_initialized = 1;
smbc_auth_fn = fn;
@ -421,7 +447,28 @@ int smbc_init(smbc_get_auth_data_fn fn, const char *wgroup, int debug)
/* Here we would open the smb.conf file if needed ... */
/* To do soon ... try $HOME/.smb/smb.conf first ... */
home = getenv("HOME");
slprintf(conf, sizeof(conf), "%s/.smb/smb.conf", home);
load_interfaces(); /* Load the list of interfaces ... */
in_client = True; /* FIXME, make a param */
if (!lp_load(conf, True, False, False)) {
/*
* Hmmm, what the hell do we do here ... we could not parse the
* config file ... We must return an error ... and keep info around
* about why we failed
*/
/*
errno = ENOENT; /* Hmmm, what error resp does lp_load return ? */
return -1;
}
/*
* Now initialize the file descriptor array and figure out what the
@ -463,8 +510,6 @@ int smbc_init(smbc_get_auth_data_fn fn, const char *wgroup, int debug)
if (!smbc_file_table)
return ENOMEM;
smbc_start_fd = 100000; /* FIXME: Figure it out */
return 0; /* Success */
}
@ -519,12 +564,21 @@ int smbc_open(const char *fname, int flags, mode_t mode)
while (smbc_file_table[slot])
slot++;
if (slot > smbc_max_fd) return ENOMEM; /* FIXME, is this best? */
if (slot > smbc_max_fd) {
errno = ENOMEM; /* FIXME, is this best? */
return -1;
}
smbc_file_table[slot] = malloc(sizeof(struct smbc_file));
if (!smbc_file_table[slot])
return ENOMEM;
if (!smbc_file_table[slot]) {
errno = ENOMEM;
return -1;
}
fd = cli_open(&srv->cli, path, flags, DENY_NONE);
@ -547,7 +601,7 @@ int smbc_open(const char *fname, int flags, mode_t mode)
int eno = 0;
eno = smbc_errno(&srv->cli);
fd = smbc_dir_open(fname);
fd = smbc_opendir(fname);
if (fd < 0) errno = eno;
return fd;
@ -648,7 +702,7 @@ ssize_t smbc_write(int fd, void *buf, size_t count)
return ret; /* Success, 0 bytes of data ... */
}
/*
* Routine to close() a file ...
*/
@ -1077,15 +1131,324 @@ int smbc_fstat(int fd, struct stat *st)
/*
* Routine to open a directory
*
* We want to allow:
*
* smb: which should list all the workgroups available
* smb:workgroup
* smb:workgroup//server
* smb://server
* smb://server/share
*/
int smbc_dir_open(const char *fname)
static void smbc_remove_dir(struct smbc_file *dir)
{
for (dir->dir_next = dir->dir_list;
dir->dir_next != NULL;
dir->dir_next = dir->dir_next->next) {
if (dir->dir_next->dirent) free(dir->dir_next->dirent);
free(dir->dir_next);
}
dir->dir_list = dir->dir_end = dir->dir_next = NULL;
}
static int add_dirent(struct smbc_file *dir, const char *name, const char *comment, uint32 type)
{
struct smbc_dirent *dirent;
/*
* Allocate space for the dirent, which must be increased by the
* size of the name and the comment and 1 for the null on the comment.
* The null on the name is already accounted for.
*/
dirent = malloc(sizeof(struct smbc_dirent) + (name?strlen(name):0) +
(comment?strlen(comment):0) + 1);
if (!dirent) {
dir->dir_error = ENOMEM;
return -1;
}
if (dir->dir_list == NULL) {
dir->dir_list = malloc(sizeof(struct smbc_dir_list));
if (!dir->dir_list) {
free(dirent);
dir->dir_error = ENOMEM;
return -1;
}
dir->dir_end = dir->dir_next = dir->dir_list;
}
else {
dir->dir_end->next = malloc(sizeof(struct smbc_dir_list));
if (!dir->dir_end) {
free(dirent);
dir->dir_error = ENOMEM;
return -1;
}
dir->dir_end = dir->dir_end->next;
dir->dir_end->next = NULL;
}
dir->dir_end->dirent = dirent;
dirent->smbc_type = dir->dir_type;
dirent->namelen = (name?strlen(name):0);
dirent->commentlen = (comment?strlen(comment):0);
strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
return 0;
}
static void
list_fn(const char *name, uint32 type, const char *comment, void *state)
{
if (add_dirent((struct smbc_file *)state, name, comment, type) < 0) {
/* An error occurred, what do we do? */
}
}
int smbc_opendir(const char *fname)
{
struct in_addr addr;
fstring server, share;
pstring path;
struct smbc_server *srv = NULL;
struct in_addr rem_ip;
int slot = 0;
if (!smbc_initialized) {
errno = EUCLEAN;
return -1;
}
if (!fname) {
errno = EINVAL;
return -1;
}
if (smbc_parse_path(fname, server, share, path)) {
errno = EINVAL;
return -1;
}
/* Get a file entry ... */
slot = 0;
while (smbc_file_table[slot])
slot++;
if (slot > smbc_max_fd) {
errno = ENOMEM;
return -1; /* FIXME, ... move into a func */
}
smbc_file_table[slot] = malloc(sizeof(struct smbc_file));
if (!smbc_file_table[slot]) {
errno = ENOMEM;
return -1;
}
smbc_file_table[slot]->cli_fd = 0;
smbc_file_table[slot]->smbc_fd = slot + smbc_start_fd;
smbc_file_table[slot]->fname = strdup(fname);
smbc_file_table[slot]->srv = NULL;
smbc_file_table[slot]->offset = 0;
smbc_file_table[slot]->file = False;
smbc_file_table[slot]->dir_list = NULL;
if (server[0] == (char)0) {
if (share[0] != (char)0 || path[0] != (char)0) {
errno = EINVAL;
if (smbc_file_table[slot]) free(smbc_file_table[slot]);
smbc_file_table[slot] = NULL;
return -1;
}
/* We have server and share and path empty ... so list the workgroups */
/* fprintf(stderr, "Workgroup is: %s\n", lp_workgroup()); */
cli_get_backup_server(my_netbios_name, lp_workgroup(), server, sizeof(server));
smbc_file_table[slot]->dir_type = SMBC_WORKGROUP;
/*
* Get a connection to IPC$ on the server if we do not already have one
*/
srv = smbc_server(server, "IPC$");
if (!srv) {
if (smbc_file_table[slot]) free(smbc_file_table[slot]);
smbc_file_table[slot] = NULL;
return -1;
}
smbc_file_table[slot]->srv = srv;
/* Now, list the stuff ... */
if (!cli_NetServerEnum(&srv->cli, lp_workgroup(), 0x80000000, list_fn,
(void *)smbc_file_table[slot])) {
if (smbc_file_table[slot]) free(smbc_file_table[slot]);
smbc_file_table[slot] = NULL;
return -1;
}
}
else { /* Server not an empty string ... Check the rest and see what gives */
if (share[0] == (char)0) {
if (path[0] != (char)0) { /* Should not have empty share with path */
errno = EINVAL;
if (smbc_file_table[slot]) free(smbc_file_table[slot]);
smbc_file_table[slot] = NULL;
return -1;
}
/* Check to see if <server><1D> translates, or <server><20> translates */
if (resolve_name(server, &rem_ip, 0x1d)) { /* Found LMB */
smbc_file_table[slot]->dir_type = SMBC_SERVER;
/*
* Get the backup list ...
*/
cli_get_backup_server(my_netbios_name, server, server, sizeof(server));
/*
* Get a connection to IPC$ on the server if we do not already have one
*/
srv = smbc_server(server, "IPC$");
if (!srv) {
if (smbc_file_table[slot]) free(smbc_file_table[slot]);
smbc_file_table[slot] = NULL; /* FIXME: Memory leaks ... */
return -1;
}
smbc_file_table[slot]->srv = srv;
/* Now, list the servers ... */
if (!cli_NetServerEnum(&srv->cli, lp_workgroup(), 0x0000FFFE, list_fn,
(void *)smbc_file_table[slot])) {
if (smbc_file_table[slot]) free(smbc_file_table[slot]);
smbc_file_table[slot] = NULL;
return -1;
}
}
else {
if (resolve_name(server, &rem_ip, 0x20)) {
/* Now, list the shares ... */
smbc_file_table[slot]->dir_type = SMBC_FILE_SHARE;
srv = smbc_server(server, "IPC$");
if (!srv) {
if (smbc_file_table[slot]) free(smbc_file_table[slot]);
smbc_file_table[slot] = NULL;
return -1;
}
smbc_file_table[slot]->srv = srv;
/* Now, list the servers ... */
if (!cli_RNetShareEnum(&srv->cli, list_fn,
(void *)smbc_file_table[slot])) {
if (smbc_file_table[slot]) free(smbc_file_table[slot]);
smbc_file_table[slot] = NULL;
return -1;
}
}
else {
errno = EINVAL;
if (smbc_file_table[slot]) free(smbc_file_table[slot]);
smbc_file_table[slot] = NULL;
return -1;
}
}
}
else { /* The server and share are specified ... work from there ... */
}
}
return smbc_file_table[slot]->smbc_fd;
}
/*
* Routine to close a directory
*/
@ -1101,10 +1464,81 @@ int smbc_closedir(int fd)
* Routine to get a directory entry
*/
int smbc_getdents(unsigned int fd, struct dirent *dirp, int count)
int smbc_getdents(unsigned int fd, struct smbc_dirent *dirp, int count)
{
struct smbc_file *fe;
struct smbc_dir_list *dir;
int rem = count, reqd;
return 0;
/* Check that all is ok first ... */
if (fd < smbc_start_fd || fd >= (smbc_start_fd + smbc_max_fd)) {
errno = EBADF;
return -1;
}
fe = smbc_file_table[fd - smbc_start_fd];
if (fe->file != False) { /* FIXME, should be dir, perhaps */
errno = ENOTDIR;
return -1;
}
/*
* Now, retrieve the number of entries that will fit in what was passed
* We have to figure out if the info is in the list, or we need to
* send a request to the server to get the info.
*/
while ((dir = fe->dir_next)) {
struct smbc_dirent *dirent;
if (!dir->dirent) {
errno = ENOENT; /* Bad error */
return -1;
}
if (rem < (reqd = (sizeof(struct smbc_dirent) + dir->dirent->namelen +
dir->dirent->commentlen + 1))) {
if (rem < count) { /* We managed to copy something */
errno = 0;
return count - rem;
}
else { /* Nothing copied ... */
errno = EINVAL; /* Not enough space ... */
return -1;
}
}
dirent = dir->dirent;
bcopy(dirent, dirp, reqd); /* Copy the data in ... */
dirp->comment = (char *)(&dirp->name + dirent->namelen + 1);
(char *)dirp += reqd;
rem -= reqd;
fe->dir_next = dir = dir -> next;
}
if (rem == count)
return 0;
else
return count - rem;
}