summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/client/testsmbc.c119
-rw-r--r--source3/include/libsmbclient.h25
-rw-r--r--source3/libsmb/libsmbclient.c476
3 files changed, 596 insertions, 24 deletions
diff --git a/source3/client/testsmbc.c b/source3/client/testsmbc.c
index 919b31e76b..0dbd5b3c2d 100644
--- a/source3/client/testsmbc.c
+++ b/source3/client/testsmbc.c
@@ -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 ...
*/
diff --git a/source3/include/libsmbclient.h b/source3/include/libsmbclient.h
index a56ff2d7eb..173a56270b 100644
--- a/source3/include/libsmbclient.h
+++ b/source3/include/libsmbclient.h
@@ -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
diff --git a/source3/libsmb/libsmbclient.c b/source3/libsmb/libsmbclient.c
index b299e59f7c..d0461f2257 100644
--- a/source3/libsmb/libsmbclient.c
+++ b/source3/libsmb/libsmbclient.c
@@ -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;
}