summaryrefslogtreecommitdiffstats
path: root/source/client
diff options
context:
space:
mode:
Diffstat (limited to 'source/client')
-rw-r--r--source/client/client.c691
-rw-r--r--source/client/clitar.c92
-rw-r--r--source/client/smbmnt.c201
-rw-r--r--source/client/smbmount.c1196
-rw-r--r--source/client/smbumount.c27
5 files changed, 1004 insertions, 1203 deletions
diff --git a/source/client/client.c b/source/client/client.c
index 180aa493bac..292da56497b 100644
--- a/source/client/client.c
+++ b/source/client/client.c
@@ -35,12 +35,12 @@ pstring cd_path = "";
static pstring service;
static pstring desthost;
extern pstring global_myname;
-extern pstring myhostname;
static pstring password;
static pstring username;
static pstring workgroup;
static char *cmdstr;
static BOOL got_pass;
+static int io_bufsize = 65520;
extern struct in_addr ipzero;
extern pstring scope;
@@ -149,18 +149,16 @@ static int readfile(char *b, int size, int n, FILE *f)
return(fread(b,size,n,f));
i = 0;
- while (i < n) {
+ while (i < (n - 1) && (i < BUFFER_SIZE)) {
if ((c = getc(f)) == EOF) {
break;
}
if (c == '\n') { /* change all LFs to CR/LF */
b[i++] = '\r';
- n++;
}
- if(i < n)
- b[i++] = c;
+ b[i++] = c;
}
return(i);
@@ -327,7 +325,7 @@ static void display_finfo(file_info *finfo)
{
if (do_this_one(finfo)) {
time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
- DEBUG(0,(" %-30s%7.7s%8.0f %s",
+ DEBUG(0,(" %-30s%7.7s %8.0f %s",
CNV_LANG(finfo->name),
attrib_string(finfo->mode),
(double)finfo->size,
@@ -349,10 +347,128 @@ static void do_du(file_info *finfo)
static BOOL do_list_recurse;
static BOOL do_list_dirs;
-static int do_list_attr;
+static char *do_list_queue = 0;
+static long do_list_queue_size = 0;
+static long do_list_queue_start = 0;
+static long do_list_queue_end = 0;
static void (*do_list_fn)(file_info *);
/****************************************************************************
+functions for do_list_queue
+ ****************************************************************************/
+
+/*
+ * The do_list_queue is a NUL-separated list of strings stored in a
+ * char*. Since this is a FIFO, we keep track of the beginning and
+ * ending locations of the data in the queue. When we overflow, we
+ * double the size of the char*. When the start of the data passes
+ * the midpoint, we move everything back. This is logically more
+ * complex than a linked list, but easier from a memory management
+ * angle. In any memory error condition, do_list_queue is reset.
+ * Functions check to ensure that do_list_queue is non-NULL before
+ * accessing it.
+ */
+static void reset_do_list_queue(void)
+{
+ if (do_list_queue)
+ {
+ free(do_list_queue);
+ }
+ do_list_queue = 0;
+ do_list_queue_size = 0;
+ do_list_queue_start = 0;
+ do_list_queue_end = 0;
+}
+
+static void init_do_list_queue(void)
+{
+ reset_do_list_queue();
+ do_list_queue_size = 1024;
+ do_list_queue = malloc(do_list_queue_size);
+ if (do_list_queue == 0) {
+ DEBUG(0,("malloc fail for size %d\n",
+ (int)do_list_queue_size));
+ reset_do_list_queue();
+ } else {
+ memset(do_list_queue, 0, do_list_queue_size);
+ }
+}
+
+static void adjust_do_list_queue(void)
+{
+ /*
+ * If the starting point of the queue is more than half way through,
+ * move everything toward the beginning.
+ */
+ if (do_list_queue && (do_list_queue_start == do_list_queue_end))
+ {
+ DEBUG(4,("do_list_queue is empty\n"));
+ do_list_queue_start = do_list_queue_end = 0;
+ *do_list_queue = '\0';
+ }
+ else if (do_list_queue_start > (do_list_queue_size / 2))
+ {
+ DEBUG(4,("sliding do_list_queue backward\n"));
+ memmove(do_list_queue,
+ do_list_queue + do_list_queue_start,
+ do_list_queue_end - do_list_queue_start);
+ do_list_queue_end -= do_list_queue_start;
+ do_list_queue_start = 0;
+ }
+
+}
+
+static void add_to_do_list_queue(const char* entry)
+{
+ long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
+ while (new_end > do_list_queue_size)
+ {
+ do_list_queue_size *= 2;
+ DEBUG(4,("enlarging do_list_queue to %d\n",
+ (int)do_list_queue_size));
+ do_list_queue = Realloc(do_list_queue, do_list_queue_size);
+ if (! do_list_queue) {
+ DEBUG(0,("failure enlarging do_list_queue to %d bytes\n",
+ (int)do_list_queue_size));
+ reset_do_list_queue();
+ }
+ else
+ {
+ memset(do_list_queue + do_list_queue_size / 2,
+ 0, do_list_queue_size / 2);
+ }
+ }
+ if (do_list_queue)
+ {
+ pstrcpy(do_list_queue + do_list_queue_end, entry);
+ do_list_queue_end = new_end;
+ DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
+ entry, (int)do_list_queue_start, (int)do_list_queue_end));
+ }
+}
+
+static char *do_list_queue_head(void)
+{
+ return do_list_queue + do_list_queue_start;
+}
+
+static void remove_do_list_queue_head(void)
+{
+ if (do_list_queue_end > do_list_queue_start)
+ {
+ do_list_queue_start += strlen(do_list_queue_head()) + 1;
+ adjust_do_list_queue();
+ DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
+ (int)do_list_queue_start, (int)do_list_queue_end));
+ }
+}
+
+static int do_list_queue_empty(void)
+{
+ return (! (do_list_queue && *do_list_queue));
+}
+
+/****************************************************************************
a helper for do_list
****************************************************************************/
static void do_list_helper(file_info *f, const char *mask)
@@ -372,11 +488,8 @@ static void do_list_helper(file_info *f, const char *mask)
if (!p) return;
p[1] = 0;
pstrcat(mask2, f->name);
- if (do_list_fn == display_finfo) {
- DEBUG(0,("\n%s\n",CNV_LANG(mask2)));
- }
pstrcat(mask2,"\\*");
- do_list(mask2, do_list_attr, do_list_fn, True, True);
+ add_to_do_list_queue(mask2);
}
return;
}
@@ -392,12 +505,68 @@ a wrapper around cli_list that adds recursion
****************************************************************************/
void do_list(const char *mask,uint16 attribute,void (*fn)(file_info *),BOOL rec, BOOL dirs)
{
+ static int in_do_list = 0;
+
+ if (in_do_list && rec)
+ {
+ fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
+ exit(1);
+ }
+
+ in_do_list = 1;
+
do_list_recurse = rec;
do_list_dirs = dirs;
do_list_fn = fn;
- do_list_attr = attribute;
- cli_list(cli, mask, attribute, do_list_helper);
+ if (rec)
+ {
+ init_do_list_queue();
+ add_to_do_list_queue(mask);
+
+ while (! do_list_queue_empty())
+ {
+ /*
+ * Need to copy head so that it doesn't become
+ * invalid inside the call to cli_list. This
+ * would happen if the list were expanded
+ * during the call.
+ * Fix from E. Jay Berkenbilt (ejb@ql.org)
+ */
+ pstring head;
+ pstrcpy(head, do_list_queue_head());
+ cli_list(cli, head, attribute, do_list_helper);
+ remove_do_list_queue_head();
+ if ((! do_list_queue_empty()) && (fn == display_finfo))
+ {
+ char* next_file = do_list_queue_head();
+ char* save_ch = 0;
+ if ((strlen(next_file) >= 2) &&
+ (next_file[strlen(next_file) - 1] == '*') &&
+ (next_file[strlen(next_file) - 2] == '\\'))
+ {
+ save_ch = next_file +
+ strlen(next_file) - 2;
+ *save_ch = '\0';
+ }
+ DEBUG(0,("\n%s\n",CNV_LANG(next_file)));
+ if (save_ch)
+ {
+ *save_ch = '\\';
+ }
+ }
+ }
+ }
+ else
+ {
+ if (cli_list(cli, mask, attribute, do_list_helper) == -1)
+ {
+ DEBUG(0, ("%s listing %s\n", cli_errstr(cli), mask));
+ }
+ }
+
+ in_do_list = 0;
+ reset_do_list_queue();
}
/****************************************************************************
@@ -476,7 +645,7 @@ static void do_get(char *rname,char *lname)
BOOL newhandle = False;
char *data;
struct timeval tp_start;
- int read_size = 65520;
+ int read_size = io_bufsize;
uint16 attr;
size_t size;
off_t nread = 0;
@@ -517,7 +686,11 @@ static void do_get(char *rname,char *lname)
DEBUG(2,("getting file %s of size %.0f as %s ",
lname, (double)size, lname));
- data = (char *)malloc(read_size);
+ if(!(data = (char *)malloc(read_size))) {
+ DEBUG(0,("malloc fail for size %d\n", read_size));
+ cli_close(cli, fnum);
+ return;
+ }
while (1) {
int n = cli_read(cli, fnum, data, nread, read_size);
@@ -531,6 +704,13 @@ static void do_get(char *rname,char *lname)
nread += n;
}
+
+ if (nread < size) {
+ DEBUG (0, ("Short read when getting file %s. Only got %ld bytes.\n",
+ CNV_LANG(rname), (long)nread));
+ }
+
+ free(data);
if (!cli_close(cli, fnum)) {
DEBUG(0,("Error %s closing remote file\n",cli_errstr(cli)));
@@ -743,7 +923,7 @@ static BOOL do_mkdir(char *name)
/****************************************************************************
-make a directory of name "name"
+ Exit client.
****************************************************************************/
static void cmd_quit(void)
{
@@ -801,7 +981,7 @@ static void do_put(char *rname,char *lname)
FILE *f;
int nread=0;
char *buf=NULL;
- int maxwrite=65520;
+ int maxwrite=io_bufsize;
struct timeval tp_start;
GetTimeOfDay(&tp_start);
@@ -1151,6 +1331,24 @@ static void cmd_del(void)
do_list(mask, attribute,do_del,False,False);
}
+/****************************************************************************
+****************************************************************************/
+static void cmd_open(void)
+{
+ pstring mask;
+ fstring buf;
+
+ pstrcpy(mask,cur_dir);
+
+ if (!next_token(NULL,buf,NULL,sizeof(buf))) {
+ DEBUG(0,("del <filename>\n"));
+ return;
+ }
+ pstrcat(mask,buf);
+
+ cli_open(cli, mask, O_RDWR, DENY_ALL);
+}
+
/****************************************************************************
remove a directory
@@ -1332,6 +1530,7 @@ list a share name
static void browse_fn(const char *name, uint32 m, const char *comment)
{
fstring typestr;
+
*typestr=0;
switch (m)
@@ -1375,18 +1574,40 @@ try and browse available connections on a host
****************************************************************************/
static BOOL list_servers(char *wk_grp)
{
+ if (!cli->server_domain) return False;
+
printf("\n\tServer Comment\n");
printf("\t--------- -------\n");
- cli_NetServerEnum(cli, workgroup, SV_TYPE_ALL, server_fn);
+ cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn);
printf("\n\tWorkgroup Master\n");
printf("\t--------- -------\n");
- cli_NetServerEnum(cli, workgroup, SV_TYPE_DOMAIN_ENUM, server_fn);
+ cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM, server_fn);
return True;
}
+#if defined(HAVE_LIBREADLINE)
+# if defined(HAVE_READLINE_HISTORY_H) || defined(HAVE_HISTORY_H)
+/****************************************************************************
+history
+****************************************************************************/
+static void cmd_history(void)
+{
+ HIST_ENTRY **hlist;
+ register int i;
+
+ hlist = history_list (); /* Get pointer to history list */
+
+ if (hlist) /* If list not empty */
+ {
+ for (i = 0; hlist[i]; i++) /* then display it */
+ DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
+ }
+}
+# endif
+#endif
/* Some constants for completing filename arguments */
@@ -1417,6 +1638,7 @@ struct
{"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},
{"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
{"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
+ {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
{"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
{"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
{"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
@@ -1442,6 +1664,9 @@ struct
{"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
{"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
{"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
+#ifdef HAVE_LIBREADLINE
+ {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
+#endif
{"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
{"",NULL,NULL,{COMPL_NONE,COMPL_NONE}}
};
@@ -1499,6 +1724,7 @@ static void cmd_help(void)
}
}
+#ifndef HAVE_LIBREADLINE
/****************************************************************************
wait for keyboard activity, swallowing network packets
****************************************************************************/
@@ -1514,7 +1740,7 @@ static void wait_keyboard(void)
timeout.tv_sec = 20;
timeout.tv_usec = 0;
- sys_select(MAX(cli->fd,fileno(stdin))+1,&fds,NULL, &timeout);
+ sys_select(MAX(cli->fd,fileno(stdin))+1,&fds,&timeout);
if (FD_ISSET(fileno(stdin),&fds))
return;
@@ -1529,6 +1755,7 @@ static void wait_keyboard(void)
cli_chkpath(cli, "\\");
}
}
+#endif
/****************************************************************************
process a -c command string
@@ -1571,223 +1798,58 @@ static void process_command_string(char *cmd)
}
}
-#ifdef HAVE_LIBREADLINE
-
-/****************************************************************************
-GNU readline completion functions
-****************************************************************************/
-
-/* Argh. This is where it gets ugly. We really need to be able to
- pass back from the do_list() iterator function. */
-
-static int compl_state;
-static char *compl_text;
-static pstring result;
-
-/* Iterator function for do_list() */
-
-static void complete_process_file(file_info *f)
-{
- /* Do we have a partial match? */
-
- if ((compl_state >= 0) && (strncmp(compl_text, f->name,
- strlen(compl_text)) == 0)) {
-
- /* Return filename if we have made enough matches */
-
- if (compl_state == 0) {
- pstrcpy(result, f->name);
- compl_state = -1;
-
- return;
- }
- compl_state--;
- }
-}
-
-/* Complete a remote file */
-
-static char *complete_remote_file(char *text, int state)
-{
- int attribute = aDIR | aSYSTEM | aHIDDEN;
- pstring mask;
-
- /* Create dir mask */
-
- pstrcpy(mask, cur_dir);
- pstrcat(mask, "*");
-
- /* Initialise static vars for filename match */
-
- compl_text = text;
- compl_state = state;
- result[0] = '\0';
-
- /* Iterate over all files in directory */
-
- do_list(mask, attribute, complete_process_file, False, True);
-
- /* Return matched filename */
-
- if (result[0] != '\0') {
- return strdup(result); /* Readline will dispose of strings */
- } else {
- return NULL;
- }
-}
-
-/* Complete a smbclient command */
-
-static char *complete_cmd(char *text, int state)
-{
- static int cmd_index;
- char *name;
-
- /* Initialise */
-
- if (state == 0) {
- cmd_index = 0;
- }
-
- /* Return the next name which partially matches the list of commands */
-
- while (strlen(name = commands[cmd_index++].name) > 0) {
- if (strncmp(name, text, strlen(text)) == 0) {
- return strdup(name);
- }
- }
-
- return NULL;
-}
-
-/* Main completion function for smbclient. Work out which word we are
- trying to complete and call the appropriate helper function -
- complete_cmd() if we are completing smbclient commands,
- comlete_remote_file() if we are completing a file on the remote end,
- filename_completion_function() builtin to GNU readline for local
- files. */
-
-static char **completion_fn(char *text, int start, int end)
-{
- int i, num_words, cmd_index;
- char lastch = ' ';
-
- /* If we are at the start of a word, we are completing a smbclient
- command. */
-
- if (start == 0) {
- return completion_matches(text, complete_cmd);
- }
-
- /* Count # of words in command */
-
- num_words = 0;
- for (i = 0; i <= end; i++) {
- if ((rl_line_buffer[i] != ' ') && (lastch == ' '))
- num_words++;
- lastch = rl_line_buffer[i];
- }
-
- if (rl_line_buffer[end] == ' ')
- num_words++;
-
- /* Work out which command we are completing for */
-
- for (cmd_index = 0; strcmp(commands[cmd_index].name, "") != 0;
- cmd_index++) {
-
- /* Check each command in array */
-
- if (strncmp(rl_line_buffer, commands[cmd_index].name,
- strlen(commands[cmd_index].name)) == 0) {
-
- /* Call appropriate completion function */
-
- if ((num_words == 2) || (num_words == 3)) {
- switch (commands[cmd_index].compl_args[num_words - 2]) {
-
- case COMPL_REMOTE:
- return completion_matches(text, complete_remote_file);
- break;
-
- case COMPL_LOCAL:
- return completion_matches(text, filename_completion_function);
- break;
-
- default:
- /* An invalid completion type */
- break;
- }
- }
-
- /* We're either completing an argument > 3 or found an invalid
- completion type. Either way do nothing about it. */
-
- break;
- }
- }
-
- return NULL;
-}
-
-/* To avoid filename completion being activated when no valid
- completions are found, we assign this stub completion function
- to the rl_completion_entry_function variable. */
-
-static char *complete_cmd_null(char *text, int state)
-{
- return NULL;
-}
-
-#endif /* HAVE_LIBREADLINE */
-
/****************************************************************************
process commands on stdin
****************************************************************************/
static void process_stdin(void)
{
pstring line;
-#ifdef HAVE_LIBREADLINE
- pstring promptline;
-#endif
char *ptr;
+#ifdef HAVE_LIBREADLINE
+/* Minimal readline support, 29Jun1999, s.xenitellis@rhbnc.ac.uk */
+#ifdef PROMPTSIZE
+#undef PROMPTSIZE
+#endif
+#define PROMPTSIZE 2048
+ char prompt_str[PROMPTSIZE]; /* This holds the buffer "smb: \dir1\> " */
+
+ char *temp; /* Gets the buffer from readline() */
+ temp = (char *)NULL;
+#endif
while (!feof(stdin)) {
fstring tok;
int i;
+#ifdef HAVE_LIBREADLINE
+ if ( temp != (char *)NULL )
+ {
+ free( temp ); /* Free memory allocated every time by readline() */
+ temp = (char *)NULL;
+ }
-#ifndef HAVE_LIBREADLINE
+ snprintf( prompt_str, PROMPTSIZE - 1, "smb: %s> ", CNV_LANG(cur_dir) );
+
+ temp = readline( prompt_str ); /* We read the line here */
+ if ( !temp )
+ break; /* EOF occured */
+
+ if ( *temp ) /* If non-empty line, save to history */
+ add_history (temp);
+
+ strncpy( line, temp, 1023 ); /* Maximum size of (pstring)line. Null is guarranteed. */
+#else
/* display a prompt */
DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
dbgflush( );
-
+
wait_keyboard();
/* and get a response */
if (!fgets(line,1000,stdin))
break;
-
-#else /* !HAVE_LIBREADLINE */
-
- /* Read input using GNU Readline */
-
- slprintf(promptline, sizeof(promptline) - 1, "smb: %s> ",
- CNV_LANG(cur_dir));
-
- if (!readline(promptline))
- break;
-
- /* Copy read line to samba buffer */
-
- pstrcpy(line, rl_line_buffer);
- pstrcat(line, "\n");
-
- /* Add line to history */
-
- if (strlen(line) > 0)
- add_history(line);
#endif
+
/* input language code to internal one */
CNV_INPUT (line);
@@ -1815,22 +1877,15 @@ static void process_stdin(void)
/*****************************************************
return a connection to a server
*******************************************************/
-struct cli_state *do_connect(char *server, char *share, int smb_port)
+struct cli_state *do_connect(char *server, char *share)
{
- struct cli_state *smb_cli;
- struct nmb_name called, calling, stupid_smbserver_called;
+ struct cli_state *c;
+ struct nmb_name called, calling;
char *server_n;
struct in_addr ip;
extern struct in_addr ipzero;
- if ((smb_cli=cli_initialise(NULL)) == NULL)
- {
- DEBUG(1,("cli_initialise failed\n"));
- return NULL;
- }
-
- if (*share == '\\')
- {
+ if (*share == '\\') {
server = share+2;
share = strchr(server,'\\');
if (!share) return NULL;
@@ -1844,52 +1899,86 @@ struct cli_state *do_connect(char *server, char *share, int smb_port)
make_nmb_name(&calling, global_myname, 0x0, "");
make_nmb_name(&called , server, name_type, "");
- make_nmb_name(&stupid_smbserver_called , "*SMBSERVER", 0x20, scope);
-
- fstrcpy(smb_cli->usr.user_name, username);
- fstrcpy(smb_cli->usr.domain, workgroup);
+ again:
ip = ipzero;
if (have_ip) ip = dest_ip;
- if (cli_set_port(smb_cli, smb_port) == 0)
- {
+ /* have to open a new connection */
+ if (!(c=cli_initialise(NULL)) || (cli_set_port(c, port) == 0) ||
+ !cli_connect(c, server_n, &ip)) {
+ DEBUG(0,("Connection to %s failed\n", server_n));
return NULL;
}
- /* set the password cache info */
- if (got_pass)
- {
- if (password[0] == 0)
- {
- pwd_set_nullpwd(&(smb_cli->usr.pwd));
+ if (!cli_session_request(c, &calling, &called)) {
+ char *p;
+ DEBUG(0,("session request to %s failed (%s)\n",
+ called.name, cli_errstr(c)));
+ cli_shutdown(c);
+ if ((p=strchr(called.name, '.'))) {
+ *p = 0;
+ goto again;
}
- else
- {
- /* generate 16 byte hashes */
- pwd_make_lm_nt_16(&(smb_cli->usr.pwd), password);
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20, "");
+ goto again;
}
+ return NULL;
}
- else
- {
- pwd_read(&(smb_cli->usr.pwd), "Password:", True);
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(c)) {
+ DEBUG(0,("protocol negotiation failed\n"));
+ cli_shutdown(c);
+ return NULL;
}
- /* paranoia: destroy the local copy of the password */
- bzero(password, sizeof(password));
+ if (!got_pass) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ pstrcpy(password, pass);
+ }
+ }
- smb_cli->use_ntlmv2 = lp_client_ntlmv2();
+ if (!cli_session_setup(c, username,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup)) {
+ /* if a password was not supplied then try again with a null username */
+ if (password[0] || !username[0] ||
+ !cli_session_setup(c, "", "", 0, "", 0, workgroup)) {
+ DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
+ return NULL;
+ }
+ DEBUG(0,("Anonymous login successful\n"));
+ }
- if (!cli_establish_connection(smb_cli, server, &ip, &calling, &called,
- share, "?????", False, True) &&
- !cli_establish_connection(smb_cli, server, &ip,
- &calling, &stupid_smbserver_called,
- share, "?????", False, True))
- {
+ /*
+ * These next two lines are needed to emulate
+ * old client behaviour for people who have
+ * scripts based on client output.
+ * QUESTION ? Do we want to have a 'client compatibility
+ * mode to turn these on/off ? JRA.
+ */
+
+ if (*c->server_domain || *c->server_os || *c->server_type)
+ DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
+ c->server_domain,c->server_os,c->server_type));
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(c, share, "?????",
+ password, strlen(password)+1)) {
+ DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
+ cli_shutdown(c);
return NULL;
}
-
- return smb_cli;
+
+ DEBUG(4,(" tconx ok\n"));
+
+ return c;
}
@@ -1898,7 +1987,7 @@ struct cli_state *do_connect(char *server, char *share, int smb_port)
****************************************************************************/
static BOOL process(char *base_directory)
{
- cli = do_connect(desthost, service, port);
+ cli = do_connect(desthost, service);
if (!cli) {
return(False);
}
@@ -1920,11 +2009,10 @@ usage on the program
****************************************************************************/
static void usage(char *pname)
{
- DEBUG(0,("Usage: %s service <password> ", pname));
+ DEBUG(0,("Usage: %s service <password> [options]", pname));
DEBUG(0,("\nVersion %s\n",VERSION));
DEBUG(0,("\t-s smb.conf pathname to smb.conf file\n"));
- DEBUG(0,("\t-B IP addr broadcast IP address to use\n"));
DEBUG(0,("\t-O socket_options socket options to use\n"));
DEBUG(0,("\t-R name resolve order use these name resolution services only\n"));
DEBUG(0,("\t-M host send a winpopup message to the host\n"));
@@ -1946,6 +2034,7 @@ static void usage(char *pname)
DEBUG(0,("\t-T<c|x>IXFqgbNan command line tar\n"));
DEBUG(0,("\t-D directory start from directory\n"));
DEBUG(0,("\t-c command string execute semicolon separated commands\n"));
+ DEBUG(0,("\t-b xmit/send buffer changes the transmit/send buffer (default: 65520)\n"));
DEBUG(0,("\n"));
}
@@ -2013,9 +2102,9 @@ static void get_password_file(void)
/****************************************************************************
handle a -L query
****************************************************************************/
-static int do_host_query(char *query_host, int smb_port)
+static int do_host_query(char *query_host)
{
- cli = do_connect(query_host, "IPC$", smb_port);
+ cli = do_connect(query_host, "IPC$");
if (!cli)
return 1;
@@ -2031,10 +2120,10 @@ static int do_host_query(char *query_host, int smb_port)
/****************************************************************************
handle a tar operation
****************************************************************************/
-static int do_tar_op(int smb_port, char *base_directory)
+static int do_tar_op(char *base_directory)
{
int ret;
- cli = do_connect(desthost, service, smb_port);
+ cli = do_connect(desthost, service);
if (!cli)
return 1;
@@ -2096,7 +2185,6 @@ static int do_message_op(void)
extern int optind;
pstring query_host;
BOOL message = False;
- BOOL explicit_user = False;
extern char tar_type;
static pstring servicesf = CONFIGFILE;
pstring term_code;
@@ -2116,15 +2204,39 @@ static int do_message_op(void)
DEBUGLEVEL = 2;
+#ifdef HAVE_LIBREADLINE
+ /* Allow conditional parsing of the ~/.inputrc file. */
+ rl_readline_name = "smbclient";
+#endif
setup_logging(pname,True);
- TimeInit();
- charset_initialise();
+ /*
+ * If the -E option is given, be careful not to clobber stdout
+ * before processing the options. 28.Feb.99, richard@hacom.nl.
+ * Also pre-parse the -s option to get the service file name.
+ */
- if(!get_myname(myhostname,NULL)) {
- DEBUG(0,("Failed to get my hostname.\n"));
+ for (opt = 1; opt < argc; opt++) {
+ if (strcmp(argv[opt], "-E") == 0)
+ dbf = stderr;
+ else if(strncmp(argv[opt], "-s", 2) == 0) {
+ if(argv[opt][2] != '\0')
+ pstrcpy(servicesf, &argv[opt][2]);
+ else if(argv[opt+1] != NULL) {
+ /*
+ * At least one more arg left.
+ */
+ pstrcpy(servicesf, argv[opt+1]);
+ } else {
+ usage(pname);
+ exit(1);
+ }
+ }
}
+ TimeInit();
+ charset_initialise();
+
in_client = True; /* Make sure that we tell lp_load we are */
if (!lp_load(servicesf,True,False,False)) {
@@ -2133,8 +2245,6 @@ static int do_message_op(void)
codepage_initialise(lp_client_code_page());
- interpret_coding_system(term_code);
-
#ifdef WITH_SSL
sslutil_init(0);
#endif
@@ -2209,14 +2319,11 @@ static int do_message_op(void)
}
while ((opt =
- getopt(argc, argv,"s:B:O:R:M:i:Nn:d:Pp:l:hI:EU:L:t:m:W:T:D:c:")) != EOF) {
+ getopt(argc, argv,"s:O:R:M:i:Nn:d:Pp:l:hI:EU:L:t:m:W:T:D:c:b:")) != EOF) {
switch (opt) {
case 's':
pstrcpy(servicesf, optarg);
break;
- case 'B':
- iface_set_default(NULL,optarg,NULL);
- break;
case 'O':
pstrcpy(user_socket_options,optarg);
break;
@@ -2270,7 +2377,6 @@ static int do_message_op(void)
case 'U':
{
char *lp;
- explicit_user = True;
pstrcpy(username,optarg);
if ((lp=strchr(username,'%'))) {
*lp = 0;
@@ -2281,9 +2387,10 @@ static int do_message_op(void)
}
break;
case 'L':
- pstrcpy(query_host,optarg);
- if(!explicit_user)
- *username = '\0';
+ p = optarg;
+ while(*p == '\\' || *p == '/')
+ p++;
+ pstrcpy(query_host,p);
break;
case 't':
pstrcpy(term_code, optarg);
@@ -2307,40 +2414,32 @@ static int do_message_op(void)
cmdstr = optarg;
got_pass = True;
break;
+ case 'b':
+ io_bufsize = MAX(1, atoi(optarg));
+ break;
default:
usage(pname);
exit(1);
}
}
- get_myname((*global_myname)?NULL:global_myname,NULL);
+ get_myname((*global_myname)?NULL:global_myname);
if(*new_name_resolve_order)
lp_set_name_resolve_order(new_name_resolve_order);
+ if (*term_code)
+ interpret_coding_system(term_code);
+
if (!tar_type && !*query_host && !*service && !message) {
usage(pname);
exit(1);
}
-#ifdef HAVE_LIBREADLINE
-
- /* Initialise GNU Readline */
-
- rl_readline_name = "smbclient";
- rl_attempted_completion_function = completion_fn;
- rl_completion_entry_function = (Function *)complete_cmd_null;
-
- /* Initialise history list */
-
- using_history();
-
-#endif /* HAVE_LIBREADLINE */
-
DEBUG( 3, ( "Client started (version %s).\n", VERSION ) );
if (tar_type) {
- return do_tar_op(port, base_directory);
+ return do_tar_op(base_directory);
}
if ((p=strchr(query_host,'#'))) {
@@ -2350,7 +2449,7 @@ static int do_message_op(void)
}
if (*query_host) {
- return do_host_query(query_host, port);
+ return do_host_query(query_host);
}
if (message) {
@@ -2358,10 +2457,8 @@ static int do_message_op(void)
}
if (!process(base_directory)) {
- close_sockets();
return(1);
}
- close_sockets();
return(0);
}
diff --git a/source/client/clitar.c b/source/client/clitar.c
index 0b7cf6f54d5..76b6ff94d58 100644
--- a/source/client/clitar.c
+++ b/source/client/clitar.c
@@ -193,7 +193,7 @@ static void writetarheader(int f, char *aname, int size, time_t mtime,
memset(b, 0, l+TBLOCK+100);
fixtarname(b, aname, l);
i = strlen(b)+1;
- DEBUG(5, ("File name in tar file: %s, size=%i, \n", b, strlen(b)));
+ DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
free(b);
}
@@ -659,7 +659,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
{
DEBUG(3,("skipping file %s of size %d bytes\n",
finfo.name,
- finfo.size));
+ (int)finfo.size));
shallitime=0;
ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
ntarf++;
@@ -712,7 +712,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
{
DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
finfo.name,
- finfo.size,
+ (int)finfo.size,
lname));
/* write a tar header, don't bother with mode - just set to 100644 */
@@ -747,7 +747,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
/* pad tar file with zero's if we couldn't get entire file */
if (nread < finfo.size) {
- DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo.size, nread));
+ DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", (int)finfo.size, (int)nread));
if (padit(data, sizeof(data), finfo.size - nread))
DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
}
@@ -781,7 +781,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
if (tar_noisy)
{
DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
- finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
+ (int)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
finfo.name));
}
@@ -806,7 +806,7 @@ static void do_tar(file_info *finfo)
if (!tar_excl && clipn) {
pstring exclaim;
- DEBUG(5, ("Excl: strlen(cur_dir) = %i\n", strlen(cur_dir)));
+ DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
safe_strcpy(exclaim, cur_dir, sizeof(pstring));
*(exclaim+strlen(exclaim)-1)='\0';
@@ -834,7 +834,7 @@ static void do_tar(file_info *finfo)
safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
- DEBUG(5, ("Sizeof(cur_dir)=%i, strlen(cur_dir)=%i, strlen(finfo->name)=%i\nname=%s,cur_dir=%s\n", sizeof(cur_dir), strlen(cur_dir), strlen(finfo->name), finfo->name, cur_dir));
+ DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n", (int)sizeof(cur_dir), (int)strlen(cur_dir), (int)strlen(finfo->name), finfo->name, cur_dir));
safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
safe_strcat(cur_dir,"\\", sizeof(cur_dir));
@@ -923,14 +923,27 @@ static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
DEBUG(5, ("Reading more data into ltarbuf ...\n"));
- total = 0;
+ /*
+ * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
+ * Fixes bug where read can return short if coming from
+ * a pipe.
+ */
- for (bufread = read(tarhandle, ltarbuf, bufsiz); total < bufsiz; total += bufread) {
+ bufread = read(tarhandle, ltarbuf, bufsiz);
+ total = bufread;
- if (bufread <= 0) { /* An error, return false */
- return (total > 0 ? -2 : bufread);
+ while (total < bufsiz) {
+ if (bufread < 0) { /* An error, return false */
+ return (total > 0 ? -2 : bufread);
}
-
+ if (bufread == 0) {
+ if (total <= 0) {
+ return -2;
+ }
+ break;
+ }
+ bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
+ total += bufread;
}
DEBUG(5, ("Total bytes read ... %i\n", total));
@@ -968,24 +981,27 @@ static int skip_file(int skipsize)
return(True);
}
-/* We get a file from the tar file and store it */
+/*************************************************************
+ Get a file from the tar file and store it.
+ When this is called, tarbuf already contains the first
+ file block. This is a bit broken & needs fixing.
+**************************************************************/
+
static int get_file(file_info2 finfo)
{
- int fsize = finfo.size;
int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
- DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, fsize));
+ DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
if (ensurepath(finfo.name) &&
- (fnum=cli_open(cli, finfo.name, O_WRONLY|O_CREAT|O_TRUNC, DENY_NONE)) == -1)
- {
+ (fnum=cli_open(cli, finfo.name, O_WRONLY|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
DEBUG(0, ("abandoning restore\n"));
return(False);
- }
+ }
/* read the blocks from the tar file and write to the remote file */
- rsize = fsize; /* This is how much to write */
+ rsize = finfo.size; /* This is how much to write */
while (rsize > 0) {
@@ -1023,17 +1039,23 @@ static int get_file(file_info2 finfo)
}
- while (dsize >= TBLOCK) {
+ /*
+ * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
+ * If the file being extracted is an exact multiple of
+ * TBLOCK bytes then we don't want to extract the next
+ * block from the tarfile here, as it will be done in
+ * the caller of get_file().
+ */
- if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
+ while (((rsize != 0) && (dsize >= TBLOCK)) ||
+ ((rsize == 0) && (dsize > TBLOCK))) {
+ if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
return False;
-
}
dsize -= TBLOCK;
-
}
bpos = dsize;
@@ -1060,7 +1082,7 @@ static int get_file(file_info2 finfo)
ntarf++;
- DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, finfo.size));
+ DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
return(True);
}
@@ -1071,7 +1093,7 @@ static int get_file(file_info2 finfo)
static int get_dir(file_info2 finfo)
{
- DEBUG(5, ("Creating directory: %s\n", finfo.name));
+ DEBUG(0, ("restore directory %s\n", finfo.name));
if (!ensurepath(finfo.name)) {
@@ -1079,6 +1101,8 @@ static int get_dir(file_info2 finfo)
return(False);
}
+
+ ntarf++;
return(True);
}
@@ -1094,12 +1118,12 @@ static char * get_longfilename(file_info2 finfo)
BOOL first = True;
DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
- DEBUG(5, ("Len = %i\n", finfo.size));
+ DEBUG(5, ("Len = %d\n", (int)finfo.size));
if (longname == NULL) {
DEBUG(0, ("could not allocate buffer of size %d for longname\n",
- finfo.size + strlen(cur_dir) + 2));
+ (int)(finfo.size + strlen(cur_dir) + 2)));
return(NULL);
}
@@ -1181,7 +1205,7 @@ static void do_tarput(void)
return;
case 0: /* chksum is zero - looks like an EOF */
- DEBUG(0, ("total of %d tar files restored to share\n", ntarf));
+ DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
return; /* Hmmm, bad here ... */
default:
@@ -1229,10 +1253,14 @@ static void do_tarput(void)
case '0': /* Should use symbolic names--FIXME */
- /* Skip to the next block first, so we can get the file, FIXME, should
- be in get_file ... */
+ /*
+ * Skip to the next block first, so we can get the file, FIXME, should
+ * be in get_file ...
+ * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
+ * Fixes bug where file size in tarfile is zero.
+ */
- if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
+ if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
DEBUG(0, ("Short file, bailing out...\n"));
return;
}
@@ -1486,7 +1514,7 @@ int process_tar(void)
close(tarhandle);
free(tarbuf);
- DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
+ DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
break;
}
diff --git a/source/client/smbmnt.c b/source/client/smbmnt.c
index fa3cacb8640..b7e30c3967f 100644
--- a/source/client/smbmnt.c
+++ b/source/client/smbmnt.c
@@ -1,7 +1,8 @@
/*
- * smbmount.c
+ * smbmnt.c
*
* Copyright (C) 1995-1998 by Paal-Kr. Engstad and Volker Lendecke
+ * extensively modified by Tridge
*
*/
@@ -23,27 +24,24 @@
#include <linux/fs.h>
#endif
-static char *progname;
-
-
-static void
-usage(void)
-{
- printf("usage: %s mount-point [options]\n", progname);
- printf("Try `%s -h' for more information\n", progname);
-}
+static uid_t mount_uid;
+static gid_t mount_gid;
+static int mount_ro;
+static unsigned mount_fmask;
+static unsigned mount_dmask;
+static int user_mount;
static void
help(void)
{
printf("\n");
- printf("usage: %s mount-point [options]\n", progname);
- printf("-u uid uid the mounted files get\n"
- "-g gid gid the mounted files get\n"
- "-f mode permission the files get (octal notation)\n"
- "-d mode permission the dirs get (octal notation)\n"
- "-P pid connection handler's pid\n\n"
- "-s share share name on server\n\n"
+ printf("usage: smbmnt mount-point [options]\n");
+ printf("-s share share name on server\n"
+ "-r mount read-only\n"
+ "-u uid mount as uid\n"
+ "-g gid mount as gid\n"
+ "-f mask permission mask for files\n"
+ "-d mask permission mask for directories\n"
"-h print this help text\n");
}
@@ -51,55 +49,32 @@ static int
parse_args(int argc, char *argv[], struct smb_mount_data *data, char **share)
{
int opt;
- struct passwd *pwd;
- struct group *grp;
- while ((opt = getopt (argc, argv, "u:g:f:d:s:")) != EOF)
+ while ((opt = getopt (argc, argv, "s:u:g:rf:d:")) != EOF)
{
switch (opt)
{
+ case 's':
+ *share = optarg;
+ break;
case 'u':
- if (isdigit(optarg[0]))
- {
- data->uid = atoi(optarg);
- }
- else
- {
- pwd = getpwnam(optarg);
- if (pwd == NULL)
- {
- fprintf(stderr, "Unknown user: %s\n",
- optarg);
- return 1;
- }
- data->uid = pwd->pw_uid;
- }
+ if (!user_mount) {
+ mount_uid = strtol(optarg, NULL, 0);
+ }
break;
case 'g':
- if (isdigit(optarg[0]))
- {
- data->gid = atoi(optarg);
- }
- else
- {
- grp = getgrnam(optarg);
- if (grp == NULL)
- {
- fprintf(stderr, "Unknown group: %s\n",
- optarg);
- return 1;
- }
- data->gid = grp->gr_gid;
- }
+ if (!user_mount) {
+ mount_gid = strtol(optarg, NULL, 0);
+ }
+ break;
+ case 'r':
+ mount_ro = 1;
break;
case 'f':
- data->file_mode = strtol(optarg, NULL, 8);
+ mount_fmask = strtol(optarg, NULL, 8);
break;
case 'd':
- data->dir_mode = strtol(optarg, NULL, 8);
- break;
- case 's':
- *share = optarg;
+ mount_dmask = strtol(optarg, NULL, 8);
break;
default:
return -1;
@@ -114,32 +89,39 @@ fullpath(const char *p)
{
char path[MAXPATHLEN];
- if (strlen(p) > MAXPATHLEN-1)
- {
+ if (strlen(p) > MAXPATHLEN-1) {
return NULL;
}
- if (realpath(p, path) == NULL)
- {
- return strdup(p);
+ if (realpath(p, path) == NULL) {
+ fprintf(stderr,"Failed to find real path for mount point\n");
+ exit(1);
}
return strdup(path);
}
-/* Check whether user is allowed to mount on the specified mount point */
-static int
-mount_ok(SMB_STRUCT_STAT *st)
+/* Check whether user is allowed to mount on the specified mount point. If it's
+ OK then we change into that directory - this prevents race conditions */
+static int mount_ok(char *mount_point)
{
- if (!S_ISDIR(st->st_mode))
- {
+ SMB_STRUCT_STAT st;
+
+ if (chdir(mount_point) != 0) {
+ return -1;
+ }
+
+ if (sys_stat(".", &st) != 0) {
+ return -1;
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
errno = ENOTDIR;
return -1;
}
-
- if ( (getuid() != 0)
- && ( (getuid() != st->st_uid)
- || ((st->st_mode & S_IRWXU) != S_IRWXU)))
- {
+
+ if ((getuid() != 0) &&
+ ((getuid() != st.st_uid) ||
+ ((st.st_mode & S_IRWXU) != S_IRWXU))) {
errno = EPERM;
return -1;
}
@@ -147,53 +129,48 @@ mount_ok(SMB_STRUCT_STAT *st)
return 0;
}
-int
-main(int argc, char *argv[])
+ int main(int argc, char *argv[])
{
char *mount_point, *share_name = NULL;
FILE *mtab;
- int fd, um;
+ int fd;
unsigned int flags;
struct smb_mount_data data;
- SMB_STRUCT_STAT st;
struct mntent ment;
- progname = argv[0];
-
memset(&data, 0, sizeof(struct smb_mount_data));
- if ( (argc == 2)
- && (argv[1][0] == '-')
- && (argv[1][1] == 'h')
- && (argv[1][2] == '\0'))
- {
+ if (argc < 2) {
+ help();
+ exit(1);
+ }
+
+ if (argv[1][0] == '-') {
help();
- return 0;
+ exit(1);
+ }
+
+ if (getuid() != 0) {
+ user_mount = 1;
}
if (geteuid() != 0) {
- fprintf(stderr, "%s must be installed suid root\n", progname);
+ fprintf(stderr, "smbmnt must be installed suid root for direct user mounts (%d,%d)\n", getuid(), geteuid());
exit(1);
}
- if (argc < 2)
- {
- usage();
- return 1;
- }
+ mount_uid = getuid();
+ mount_gid = getgid();
+ mount_fmask = umask(0);
+ umask(mount_fmask);
+ mount_fmask = ~mount_fmask;
- mount_point = argv[1];
+ mount_point = fullpath(argv[1]);
argv += 1;
argc -= 1;
- if (sys_stat(mount_point, &st) == -1) {
- fprintf(stderr, "could not find mount point %s: %s\n",
- mount_point, strerror(errno));
- exit(1);
- }
-
- if (mount_ok(&st) != 0) {
+ if (mount_ok(mount_point) != 0) {
fprintf(stderr, "cannot mount on %s: %s\n",
mount_point, strerror(errno));
exit(1);
@@ -204,19 +181,17 @@ main(int argc, char *argv[])
/* getuid() gives us the real uid, who may umount the fs */
data.mounted_uid = getuid();
- data.uid = getuid();
- data.gid = getgid();
- um = umask(0);
- umask(um);
- data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & ~um;
- data.dir_mode = 0;
-
if (parse_args(argc, argv, &data, &share_name) != 0) {
- usage();
+ help();
return -1;
}
- if (data.dir_mode == 0) {
+ data.uid = mount_uid;
+ data.gid = mount_gid;
+ data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & mount_fmask;
+ data.dir_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & mount_dmask;
+
+ if (mount_dmask == 0) {
data.dir_mode = data.file_mode;
if ((data.dir_mode & S_IRUSR) != 0)
data.dir_mode |= S_IXUSR;
@@ -228,15 +203,23 @@ main(int argc, char *argv[])
flags = MS_MGC_VAL;
- if (mount(share_name, mount_point, "smbfs", flags, (char *)&data) < 0)
+ if (mount_ro) flags |= MS_RDONLY;
+
+ if (mount(share_name, ".", "smbfs", flags, (char *)&data) < 0)
{
- perror("mount error");
- printf("Please refer to the smbmnt(8) manual page\n");
+ switch (errno) {
+ case ENODEV:
+ fprintf(stderr, "ERROR: smbfs filesystem not supported by the kernel\n");
+ break;
+ default:
+ perror("mount error");
+ }
+ fprintf(stderr, "Please refer to the smbmnt(8) manual page\n");
return -1;
}
ment.mnt_fsname = share_name ? share_name : "none";
- ment.mnt_dir = fullpath(mount_point);
+ ment.mnt_dir = mount_point;
ment.mnt_type = "smbfs";
ment.mnt_opts = "";
ment.mnt_freq = 0;
diff --git a/source/client/smbmount.c b/source/client/smbmount.c
index 3fad6674fb8..e25efcaf566 100644
--- a/source/client/smbmount.c
+++ b/source/client/smbmount.c
@@ -1,8 +1,8 @@
/*
Unix SMB/Netbios implementation.
- Version 1.9.
- SMB client
- Copyright (C) Andrew Tridgell 1994-1998
+ Version 2.0.
+ SMBFS mount program
+ Copyright (C) Andrew Tridgell 1999
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
@@ -21,193 +21,63 @@
#define NO_SYSLOG
-#include <linux/version.h>
-#define LVERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
-#if LINUX_VERSION_CODE < LVERSION(2,1,70)
-#error this code will only compile on versions of linux after 2.1.70
-#endif
-
#include "includes.h"
#include <mntent.h>
-
#include <asm/types.h>
#include <linux/smb_fs.h>
-static struct smb_conn_opt conn_options;
-#ifndef REGISTER
-#define REGISTER 0
-#endif
-
-/* Uncomment this to allow debug the smbmount daemon */
+/* Uncomment this to allow debug the mount.smb daemon */
/* WARNING! This option is incompatible with autofs/automount because
it does not close the stdout pipe back to the automount
process, which automount depends on. This will cause automount
to hang! Use with caution! */
-/* #define SMBFS_DEBUG 1 */
-
-pstring cur_dir = "\\";
-pstring cd_path = "";
-extern pstring service;
-extern pstring desthost;
-extern pstring global_myname;
-extern pstring myhostname;
-extern pstring password;
-extern pstring smb_login_passwd;
-extern pstring username;
-extern pstring workgroup;
-char *cmdstr="";
-extern BOOL got_pass;
-extern BOOL connect_as_printer;
-extern BOOL connect_as_ipc;
-extern struct in_addr ipzero;
-
-extern BOOL doencrypt;
-
-extern pstring user_socket_options;
-
-/* 30 second timeout on most commands */
-#define CLIENT_TIMEOUT (30*1000)
-#define SHORT_TIMEOUT (5*1000)
-
-/* value for unused fid field in trans2 secondary request */
-#define FID_UNUSED (0xFFFF)
-
-extern int name_type;
+/* #define SMBFS_DEBUG 1 */
-extern int max_protocol;
-int port = SMB_PORT;
-
-time_t newer_than = 0;
-int archive_level = 0;
-
-extern pstring debugf;
+extern struct in_addr ipzero;
extern int DEBUGLEVEL;
-BOOL translation = False;
-
-extern uint16 cnum;
-extern uint16 mid;
-extern uint16 pid;
-extern uint16 vuid;
-
-extern BOOL have_ip;
-extern int max_xmit;
-
-/* clitar bits insert */
-extern int blocksize;
-extern BOOL tar_inc;
-extern BOOL tar_reset;
-/* clitar bits end */
-
-
-mode_t myumask = 0755;
-
extern pstring scope;
+extern BOOL in_client;
+extern pstring user_socket_options;
-BOOL prompt = True;
-
-int printmode = 1;
-
-BOOL recurse = False;
-BOOL lowercase = False;
-
-struct in_addr dest_ip;
-
-#define SEPARATORS " \t\n\r"
-
-BOOL abort_mget = True;
-
-extern int Protocol;
-
-extern BOOL readbraw_supported ;
-extern BOOL writebraw_supported;
-
-pstring fileselection = "";
-
-extern file_info def_finfo;
-
-/* timing globals */
-int get_total_size = 0;
-int get_total_time_ms = 0;
-int put_total_size = 0;
-int put_total_time_ms = 0;
-
-/* totals globals */
-int dir_total = 0;
-
-extern int Client;
-
-#define USENMB
-
-#define CNV_LANG(s) dos_to_unix(s,False)
-#define CNV_INPUT(s) unix_to_dos(s,True)
-
-/****************************************************************************
-check for existance of a dir
-****************************************************************************/
-static BOOL chkpath(char *path,BOOL report)
-{
- fstring path2;
- pstring inbuf,outbuf;
- char *p;
-
- fstrcpy(path2,path);
- trim_string(path2,NULL,"\\");
- if (!*path2) *path2 = '\\';
-
- memset(outbuf,'\0',smb_size);
- set_message(outbuf,0,4 + strlen(path2),True);
- SCVAL(outbuf,smb_com,SMBchkpth);
- SSVAL(outbuf,smb_tid,cnum);
- cli_setup_pkt(outbuf);
-
- p = smb_buf(outbuf);
- *p++ = 4;
- fstrcpy(p,path2);
-
-#if 0
- {
- /* this little bit of code can be used to extract NT error codes.
- Just feed a bunch of "cd foo" commands to smbclient then watch
- in netmon (tridge) */
- static int code=0;
- SIVAL(outbuf, smb_rcls, code | 0xC0000000);
- SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | (1<<14));
- code++;
- }
-#endif
-
- send_smb(Client,outbuf);
- client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (report && CVAL(inbuf,smb_rcls) != 0)
- DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf)));
-
- return(CVAL(inbuf,smb_rcls) == 0);
-}
-
-static void
-exit_parent( int sig )
+static pstring my_netbios_name;
+static pstring password;
+static pstring username;
+static pstring workgroup;
+static pstring mpoint;
+static pstring service;
+
+static struct in_addr dest_ip;
+static BOOL have_ip;
+static int smb_port = 139;
+static BOOL got_pass;
+static uid_t mount_uid;
+static gid_t mount_gid;
+static int mount_ro;
+static unsigned mount_fmask;
+static unsigned mount_dmask;
+
+static void usage(void);
+
+static void exit_parent(int sig)
{
/* parent simply exits when child says go... */
exit(0);
}
-static void
-daemonize(void)
+static void daemonize(void)
{
int j, status;
pid_t child_pid;
signal( SIGTERM, exit_parent );
- if ((child_pid = fork()) < 0)
- {
- DEBUG(0, ("could not fork\n"));
+ if ((child_pid = fork()) < 0) {
+ fprintf(stderr,"could not fork\n");
}
- if (child_pid > 0)
- {
+
+ if (child_pid > 0) {
while( 1 ) {
j = waitpid( child_pid, &status, 0 );
if( j < 0 ) {
@@ -221,84 +91,127 @@ daemonize(void)
/* If we get here - the child exited with some error status */
exit(status);
}
- /* Programmers Note:
- Danger Will Robinson! Danger!
- There use to be a call to setsid() here. This does no
- harm to normal mount operations, but it broke automounting.
- The setsid call has been moved to just before the child
- sends the SIGTERM to the parent. All of our deadly embrace
- conditions with autofs will have been cleared by then...
- -mhw-
- */
signal( SIGTERM, SIG_DFL );
chdir("/");
}
-static void
-close_our_files(void)
+static void close_our_files(int client_fd)
{
int i;
- for (i = 0; i < NR_OPEN; i++) {
- if (i == Client) {
- continue;
- }
+ for (i = 0; i < 256; i++) {
+ if (i == client_fd) continue;
close(i);
}
}
-static void
-usr1_handler(int x)
+static void usr1_handler(int x)
{
return;
}
-/*
- * Send a login and store the connection options. This is a separate
- * function to keep clientutil.c independent of linux kernel changes.
- */
-static BOOL mount_send_login(char *inbuf, char *outbuf)
+
+/*****************************************************
+return a connection to a server
+*******************************************************/
+static struct cli_state *do_connection(char *service)
{
- struct connection_options opt;
- int res = cli_send_login(inbuf, outbuf, True, True, &opt);
-
- if (!res)
- return res;
-
- if( !got_pass ) {
- /* Ok... If we got this thing connected and got_pass is false,
- that means that the client util prompted for a password and
- got a good one... We need to cache this in password and set
- got_pass for future retries. We don't want to prompt for the
- $#@$#$ password everytime the network blinks!
- */
+ struct cli_state *c;
+ struct nmb_name called, calling;
+ char *server_n;
+ struct in_addr ip;
+ extern struct in_addr ipzero;
+ pstring server;
+ char *share;
+
+ if (service[0] != '\\' || service[1] != '\\') {
+ usage();
+ exit(1);
+ }
+
+ pstrcpy(server, service+2);
+ share = strchr(server,'\\');
+ if (!share) {
+ usage();
+ exit(1);
+ }
+ *share = 0;
+ share++;
+
+ server_n = server;
+
+ ip = ipzero;
+
+ make_nmb_name(&calling, my_netbios_name, 0x0, "");
+ make_nmb_name(&called , server, 0x20, "");
+
+ again:
+ ip = ipzero;
+ if (have_ip) ip = dest_ip;
+
+ /* have to open a new connection */
+ if (!(c=cli_initialise(NULL)) || (cli_set_port(c, smb_port) == 0) ||
+ !cli_connect(c, server_n, &ip)) {
+ fprintf(stderr,"Connection to %s failed\n", server_n);
+ return NULL;
+ }
+
+ if (!cli_session_request(c, &calling, &called)) {
+ fprintf(stderr, "session request to %s failed\n", called.name);
+ cli_shutdown(c);
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20, "");
+ goto again;
+ }
+ return NULL;
+ }
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(c)) {
+ fprintf(stderr, "protocol negotiation failed\n");
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ if (!got_pass) {
+ char *pass = getpass("Password: ");
+ if (pass) {
+ pstrcpy(password, pass);
+ }
+ }
+
+ if (!cli_session_setup(c, username,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup)) {
+ fprintf(stderr, "session setup failed: %s\n", cli_errstr(c));
+ return NULL;
+ }
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(c, share, "?????",
+ password, strlen(password)+1)) {
+ fprintf(stderr,"tree connect failed: %s\n", cli_errstr(c));
+ cli_shutdown(c);
+ return NULL;
+ }
+
+ DEBUG(4,(" tconx ok\n"));
+
+ got_pass = True;
- pstrcpy(password,smb_login_passwd);
- got_pass = True;
- }
- conn_options.protocol = opt.protocol;
- conn_options.case_handling = CASE_LOWER;
- conn_options.max_xmit = opt.max_xmit;
- conn_options.server_uid = opt.server_vuid;
- conn_options.tid = opt.tid;
- conn_options.secmode = opt.sec_mode;
- conn_options.maxmux = opt.max_mux;
- conn_options.maxvcs = opt.max_vcs;
- conn_options.rawmode = opt.rawmode;
- conn_options.sesskey = opt.sesskey;
- conn_options.maxraw = opt.maxraw;
- conn_options.capabilities = opt.capabilities;
- conn_options.serverzone = opt.serverzone;
-
- return True;
+ return c;
}
+
/****************************************************************************
unmount smbfs (this is a bailout routine to clean up if a reconnect fails)
Code blatently stolen from smbumount.c
-mhw-
****************************************************************************/
-static void smb_umount( char *mount_point )
+static void smb_umount(char *mount_point)
{
int fd;
struct mntent *mnt;
@@ -314,29 +227,29 @@ static void smb_umount( char *mount_point )
the lights to exit anyways...
*/
if (umount(mount_point) != 0) {
- DEBUG(0, ("Could not umount %s: %s\n",
- mount_point, strerror(errno)));
+ fprintf(stderr, "Could not umount %s: %s\n",
+ mount_point, strerror(errno));
return;
}
- if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)
- {
- DEBUG(0, ("Can't get "MOUNTED"~ lock file"));
+ if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) {
+ fprintf(stderr, "Can't get "MOUNTED"~ lock file");
return;
}
+
close(fd);
if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
- DEBUG(0, ("Can't open " MOUNTED ": %s\n",
- strerror(errno)));
+ fprintf(stderr, "Can't open " MOUNTED ": %s\n",
+ strerror(errno));
return;
}
#define MOUNTED_TMP MOUNTED".tmp"
if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
- DEBUG(0, ("Can't open " MOUNTED_TMP ": %s\n",
- strerror(errno)));
+ fprintf(stderr, "Can't open " MOUNTED_TMP ": %s\n",
+ strerror(errno));
endmntent(mtab);
return;
}
@@ -350,26 +263,23 @@ static void smb_umount( char *mount_point )
endmntent(mtab);
if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
- DEBUG(0, ("Error changing mode of %s: %s\n",
- MOUNTED_TMP, strerror(errno)));
+ fprintf(stderr, "Error changing mode of %s: %s\n",
+ MOUNTED_TMP, strerror(errno));
return;
}
endmntent(new_mtab);
if (rename(MOUNTED_TMP, MOUNTED) < 0) {
- DEBUG(0, ("Cannot rename %s to %s: %s\n",
- MOUNTED, MOUNTED_TMP, strerror(errno)));
+ fprintf(stderr, "Cannot rename %s to %s: %s\n",
+ MOUNTED, MOUNTED_TMP, strerror(errno));
return;
}
- if (unlink(MOUNTED"~") == -1)
- {
- DEBUG(0, ("Can't remove "MOUNTED"~"));
+ if (unlink(MOUNTED"~") == -1) {
+ fprintf(stderr, "Can't remove "MOUNTED"~");
return;
}
-
- return;
}
@@ -379,136 +289,174 @@ static void smb_umount( char *mount_point )
* not exit after open_sockets() or send_login() errors,
* as the smbfs mount would then have no way to recover.
*/
-static void
-send_fs_socket(char *mount_point, char *inbuf, char *outbuf)
+static void send_fs_socket(char *service, char *mount_point, struct cli_state *c)
{
int fd, closed = 0, res = 1;
-
pid_t parentpid = getppid();
+ struct smb_conn_opt conn_options;
+
+ memset(&conn_options, 0, sizeof(conn_options));
- while (1)
- {
- if ((fd = open(mount_point, O_RDONLY)) < 0)
- {
- DEBUG(0, ("smbmount: can't open %s\n", mount_point));
+ while (1) {
+ if ((fd = open(mount_point, O_RDONLY)) < 0) {
+ fprintf(stderr, "mount.smbfs: can't open %s\n", mount_point);
break;
}
- /*
- * Call the ioctl even if we couldn't get a socket ...
- * there's no point in making smbfs wait for a timeout.
- */
- conn_options.fd = -1;
- if (res)
- conn_options.fd = Client;
+ conn_options.fd = c->fd;
+ conn_options.protocol = c->protocol;
+ conn_options.case_handling = SMB_CASE_DEFAULT;
+ conn_options.max_xmit = c->max_xmit;
+ conn_options.server_uid = c->vuid;
+ conn_options.tid = c->cnum;
+ conn_options.secmode = c->sec_mode;
+ conn_options.rawmode = 0;
+ conn_options.sesskey = c->sesskey;
+ conn_options.maxraw = 0;
+ conn_options.capabilities = c->capabilities;
+ conn_options.serverzone = c->serverzone/60;
+
res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
- if (res != 0)
- {
- DEBUG(0, ("smbmount: ioctl failed, res=%d\n", res));
+ if (res != 0) {
+ fprintf(stderr, "mount.smbfs: ioctl failed, res=%d\n", res);
+ break;
}
- if( parentpid ) {
+ if (parentpid) {
/* Ok... We are going to kill the parent. Now
is the time to break the process group... */
setsid();
/* Send a signal to the parent to terminate */
- kill( parentpid, SIGTERM );
+ kill(parentpid, SIGTERM);
parentpid = 0;
}
- close_sockets();
close(fd);
- /*
- * Close all open files if we haven't done so yet.
- */
+
#ifndef SMBFS_DEBUG
- if (!closed)
- {
+ /* Close all open files if we haven't done so yet. */
+ if (!closed) {
+ extern FILE *dbf;
closed = 1;
- close_our_files();
+ dbf = NULL;
+ close_our_files(c?c->fd:-1);
}
#endif
- /*
- * Wait for a signal from smbfs ...
- */
+ /* Wait for a signal from smbfs ... */
CatchSignal(SIGUSR1, &usr1_handler);
pause();
- DEBUG(0, ("smbmount: got signal, getting new socket\n"));
+#ifdef SMBFS_DEBUG
+ DEBUG(2,("mount.smbfs: got signal, getting new socket\n"));
+#endif
+ c = do_connection(service);
+ }
- res = cli_open_sockets(port);
- if (!res)
- {
- DEBUG(0, ("smbmount: can't open sockets\n"));
- continue;
- }
+ smb_umount(mount_point);
+ DEBUG(2,("mount.smbfs: exit\n"));
+ exit(1);
+}
- res = mount_send_login(inbuf, outbuf);
- if (!res)
- {
- DEBUG(0, ("smbmount: login failed\n"));
- break;
- }
+/*********************************************************
+a strdup with exit
+**********************************************************/
+static char *xstrdup(char *s)
+{
+ s = strdup(s);
+ if (!s) {
+ fprintf(stderr,"out of memory\n");
+ exit(1);
}
- smb_umount( mount_point );
- DEBUG(0, ("smbmount: exit\n"));
- exit(1);
+ return s;
}
+
/****************************************************************************
mount smbfs
****************************************************************************/
-static void cmd_mount(char *inbuf,char *outbuf)
+static void init_mount(void)
{
- pstring mpoint;
- pstring share_name;
- pstring mount_command;
- fstring buf;
- int retval;
char mount_point[MAXPATHLEN+1];
-
- if (!next_token(NULL, mpoint, NULL, sizeof(mpoint)))
- {
- DEBUG(0,("You must supply a mount point\n"));
+ pstring tmp;
+ pstring svc2;
+ struct cli_state *c;
+ char *args[20];
+ int i, status;
+
+ if (realpath(mpoint, mount_point) == NULL) {
+ fprintf(stderr, "Could not resolve mount point %s\n", mpoint);
return;
}
- memset(mount_point, 0, sizeof(mount_point));
- if (realpath(mpoint, mount_point) == NULL)
- {
- DEBUG(0, ("Could not resolve mount point\n"));
- return;
- }
-
- /*
- * Build the service name to report on the Unix side,
- * converting '\' to '/' and ' ' to '_'.
- */
- pstrcpy(share_name, service);
- string_replace(share_name, '\\', '/');
- string_replace(share_name, ' ', '_');
-
- slprintf(mount_command, sizeof(mount_command)-1,"smbmnt %s -s %s", mount_point, share_name);
-
- while(next_token(NULL, buf, NULL, sizeof(buf)))
- {
- pstrcat(mount_command, " ");
- pstrcat(mount_command, buf);
+ c = do_connection(service);
+ if (!c) {
+ fprintf(stderr,"SMB connection failed\n");
+ exit(1);
}
- DEBUG(3, ("mount command: %s\n", mount_command));
-
/*
Set up to return as a daemon child and wait in the parent
until the child say it's ready...
*/
daemonize();
- if ((retval = system(mount_command)) != 0)
- {
- DEBUG(0,("mount failed\n"));
+ pstrcpy(svc2, service);
+ string_replace(svc2, '\\','/');
+ string_replace(svc2, ' ','_');
+
+ memset(args, 0, sizeof(args[0])*20);
+
+ i=0;
+ args[i++] = "smbmnt";
+
+ args[i++] = mount_point;
+ args[i++] = "-s";
+ args[i++] = svc2;
+
+ if (mount_ro) {
+ args[i++] = "-r";
+ }
+ if (mount_uid) {
+ slprintf(tmp, sizeof(tmp), "%d", mount_uid);
+ args[i++] = "-u";
+ args[i++] = xstrdup(tmp);
+ }
+ if (mount_gid) {
+ slprintf(tmp, sizeof(tmp), "%d", mount_gid);
+ args[i++] = "-g";
+ args[i++] = xstrdup(tmp);
+ }
+ if (mount_fmask) {
+ slprintf(tmp, sizeof(tmp), "0%o", mount_fmask);
+ args[i++] = "-f";
+ args[i++] = xstrdup(tmp);
+ }
+ if (mount_dmask) {
+ slprintf(tmp, sizeof(tmp), "0%o", mount_dmask);
+ args[i++] = "-d";
+ args[i++] = xstrdup(tmp);
+ }
+
+ if (fork() == 0) {
+ if (file_exist(BINDIR "/smbmnt", NULL)) {
+ execv(BINDIR "/smbmnt", args);
+ fprintf(stderr,"execv of %s failed. Error was %s.", BINDIR "/smbmnt", strerror(errno));
+ } else {
+ execvp("smbmnt", args);
+ fprintf(stderr,"execvp of smbmnt failed. Error was %s.", strerror(errno) );
+ }
+ exit(1);
+ }
+
+ if (waitpid(-1, &status, 0) == -1) {
+ fprintf(stderr,"waitpid failed: Error was %s", strerror(errno) );
+ /* FIXME: do some proper error handling */
exit(1);
+ }
+
+ if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
+ fprintf(stderr,"smbmnt failed: %d\n", WEXITSTATUS(status));
}
/* Ok... This is the rubicon for that mount point... At any point
@@ -516,241 +464,157 @@ static void cmd_mount(char *inbuf,char *outbuf)
for any reason, we will have to unmount the mount point. There
is no exit from the next call...
*/
- send_fs_socket(mount_point, inbuf, outbuf);
+ send_fs_socket(service, mount_point, c);
}
-/* This defines the commands supported by this client */
-struct
-{
- char *name;
- void (*fn)();
- char *description;
-} commands[] =
-{
- {"mount", cmd_mount, "<mount-point options> mount an smbfs file system"},
- {"",NULL,NULL}
-};
-
-
-/*******************************************************************
- lookup a command string in the list of commands, including
- abbreviations
- ******************************************************************/
-static int process_tok(fstring tok)
-{
- int i = 0, matches = 0;
- int cmd=0;
- int tok_len = strlen(tok);
-
- while (commands[i].fn != NULL)
- {
- if (strequal(commands[i].name,tok))
- {
- matches = 1;
- cmd = i;
- break;
- }
- else if (strnequal(commands[i].name, tok, tok_len))
- {
- matches++;
- cmd = i;
- }
- i++;
- }
-
- if (matches == 0)
- return(-1);
- else if (matches == 1)
- return(cmd);
- else
- return(-2);
-}
-
-/****************************************************************************
-help
-****************************************************************************/
-void cmd_help(char *dum_in, char *dum_out)
-{
- int i=0,j;
- fstring buf;
-
- if (next_token(NULL,buf,NULL,sizeof(buf)))
- {
- if ((i = process_tok(buf)) >= 0)
- DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));
- }
- else
- while (commands[i].description)
- {
- for (j=0; commands[i].description && (j<5); j++) {
- DEBUG(0,("%-15s",commands[i].name));
- i++;
- }
- DEBUG(0,("\n"));
- }
-}
-
/****************************************************************************
-wait for keyboard activity, swallowing network packets
+usage on the program
****************************************************************************/
-static void wait_keyboard(char *buffer)
+static void usage(void)
{
- fd_set fds;
- int selrtn;
- struct timeval timeout;
-
- while (1)
- {
- extern int Client;
- FD_ZERO(&fds);
- FD_SET(Client,&fds);
- FD_SET(fileno(stdin),&fds);
-
- timeout.tv_sec = 20;
- timeout.tv_usec = 0;
- selrtn = sys_select(MAX(Client,fileno(stdin))+1,&fds,NULL, &timeout);
-
- if (FD_ISSET(fileno(stdin),&fds))
- return;
-
- /* We deliberately use receive_smb instead of
- client_receive_smb as we want to receive
- session keepalives and then drop them here.
- */
- if (FD_ISSET(Client,&fds))
- receive_smb(Client,buffer,0);
-
- chkpath("\\",False);
- }
+ printf("Usage: mount.smbfs service mountpoint [-o options,...]\n");
+
+ printf("Version %s\n\n",VERSION);
+
+ printf(
+"Options:
+ username=<arg> SMB username
+ password=<arg> SMB password
+ netbiosname=<arg> source NetBIOS name
+ uid=<arg> mount uid or username
+ gid=<arg> mount gid or groupname
+ port=<arg> remote SMB port number
+ fmask=<arg> file umask
+ dmask=<arg> directory umask
+ debug=<arg> debug level
+ ip=<arg> destination host or IP address
+ workgroup=<arg> workgroup on destination
+ sockopt=<arg> TCP socket options
+ scope=<arg> NetBIOS scope
+ guest don't prompt for a password
+ ro mount read-only
+ rw mount read-write
+
+This command is designed to be run from within /bin/mount by giving
+the option '-t smbfs'. For example:
+ mount -t smbfs -o username=tridge,password=foobar //fjall/test /data/test
+");
}
/****************************************************************************
- process commands from the client
-****************************************************************************/
-static BOOL process(char *base_directory)
+ Argument parsing for mount.smbfs interface
+ mount will call us like this:
+ mount.smbfs device mountpoint -o <options>
+
+ <options> is never empty, containing at least rw or ro
+ ****************************************************************************/
+static void parse_mount_smb(int argc, char **argv)
{
- extern FILE *dbf;
- pstring line;
- char *cmd;
+ int opt;
+ char *opts;
+ char *opteq;
+ extern char *optarg;
+ int val;
+
+ if (argc < 2 || argv[1][0] == '-') {
+ usage();
+ exit(1);
+ }
+
+ pstrcpy(service, argv[1]);
+ pstrcpy(mpoint, argv[2]);
- char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ /* Convert any '/' characters in the service name to
+ '\' characters */
+ string_replace(service, '/','\\');
+ argc -= 2;
+ argv += 2;
- if ((InBuffer == NULL) || (OutBuffer == NULL))
- return(False);
-
- memset(OutBuffer,'\0',smb_size);
-
- if (!mount_send_login(InBuffer,OutBuffer))
- return(False);
-
- cmd = cmdstr;
- if (cmd[0] != '\0') while (cmd[0] != '\0')
- {
- char *p;
- fstring tok;
- int i;
-
- if ((p = strchr(cmd, ';')) == 0)
- {
- strncpy(line, cmd, 999);
- line[1000] = '\0';
- cmd += strlen(cmd);
- }
- else
- {
- if (p - cmd > 999) p = cmd + 999;
- strncpy(line, cmd, p - cmd);
- line[p - cmd] = '\0';
- cmd = p + 1;
- }
-
- /* input language code to internal one */
- CNV_INPUT (line);
-
- /* and get the first part of the command */
- {
- char *ptr = line;
- if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
- }
-
- if ((i = process_tok(tok)) >= 0)
- commands[i].fn(InBuffer,OutBuffer);
- else if (i == -2)
- DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
- else
- DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
- }
- else while (!feof(stdin))
- {
- fstring tok;
- int i;
-
- memset(OutBuffer,'\0',smb_size);
-
- /* display a prompt */
- DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
- dbgflush();
-
- wait_keyboard(InBuffer);
-
- /* and get a response */
- if (!fgets(line,1000,stdin))
- break;
-
- /* input language code to internal one */
- CNV_INPUT (line);
-
- /* special case - first char is ! */
- if (*line == '!')
- {
- system(line + 1);
- continue;
- }
-
- /* and get the first part of the command */
- {
- char *ptr = line;
- if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
- }
-
- if ((i = process_tok(tok)) >= 0)
- commands[i].fn(InBuffer,OutBuffer);
- else if (i == -2)
- DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
- else
- DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
- }
-
- cli_send_logout(InBuffer,OutBuffer);
- return(True);
-}
+ opt = getopt(argc, argv, "o:");
+ if(opt != 'o') {
+ return;
+ }
-/****************************************************************************
-usage on the program
-****************************************************************************/
-static void usage(char *pname)
-{
- DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
- pname));
-
- DEBUG(0,("\nVersion %s\n",VERSION));
- DEBUG(0,("\t-p port connect to the specified port\n"));
- DEBUG(0,("\t-d debuglevel set the debuglevel\n"));
- DEBUG(0,("\t-l log basename. Basename for log/debug files\n"));
- DEBUG(0,("\t-n netbios name. Use this name as my netbios name\n"));
- DEBUG(0,("\t-N don't ask for a password\n"));
- DEBUG(0,("\t-m max protocol set the max protocol level\n"));
- DEBUG(0,("\t-I dest IP use this IP to connect to\n"));
- DEBUG(0,("\t-E write messages to stderr instead of stdout\n"));
- DEBUG(0,("\t-U username set the network username\n"));
- DEBUG(0,("\t-W workgroup set the workgroup name\n"));
- DEBUG(0,("\t-c command string execute semicolon separated commands\n"));
- DEBUG(0,("\t-t terminal code terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
- DEBUG(0,("\t-D directory start from directory\n"));
- DEBUG(0,("\n"));
+ /*
+ * option parsing from nfsmount.c (util-linux-2.9u)
+ */
+ for (opts = strtok(optarg, ","); opts; opts = strtok(NULL, ",")) {
+ DEBUG(3, ("opts: %s\n", opts));
+ if ((opteq = strchr(opts, '='))) {
+ val = atoi(opteq + 1);
+ *opteq = '\0';
+
+ if (!strcmp(opts, "username") ||
+ !strcmp(opts, "logon")) {
+ char *lp;
+ pstrcpy(username,opteq+1);
+ if ((lp=strchr(username,'%'))) {
+ *lp = 0;
+ pstrcpy(password,lp+1);
+ got_pass = True;
+ memset(strchr(opteq+1,'%')+1,'X',strlen(password));
+ }
+ if ((lp=strchr(username,'/'))) {
+ *lp = 0;
+ pstrcpy(workgroup,lp+1);
+ }
+ } else if(!strcmp(opts, "passwd") ||
+ !strcmp(opts, "password")) {
+ pstrcpy(password,opteq+1);
+ got_pass = True;
+ memset(opteq+1,'X',strlen(password));
+ } else if(!strcmp(opts, "netbiosname")) {
+ pstrcpy(my_netbios_name,opteq+1);
+ } else if(!strcmp(opts, "uid")) {
+ mount_uid = nametouid(opteq+1);
+ } else if(!strcmp(opts, "gid")) {
+ mount_gid = nametogid(opteq+1);
+ } else if(!strcmp(opts, "port")) {
+ smb_port = val;
+ } else if(!strcmp(opts, "fmask")) {
+ mount_fmask = strtol(opteq+1, NULL, 8);
+ } else if(!strcmp(opts, "dmask")) {
+ mount_dmask = strtol(opteq+1, NULL, 8);
+ } else if(!strcmp(opts, "debug")) {
+ DEBUGLEVEL = val;
+ } else if(!strcmp(opts, "ip")) {
+ dest_ip = *interpret_addr2(opteq+1);
+ if (zero_ip(dest_ip)) {
+ fprintf(stderr,"Can't resolve address %s\n", opteq+1);
+ exit(1);
+ }
+ have_ip = True;
+ } else if(!strcmp(opts, "workgroup")) {
+ pstrcpy(workgroup,opteq+1);
+ } else if(!strcmp(opts, "sockopt")) {
+ pstrcpy(user_socket_options,opteq+1);
+ } else if(!strcmp(opts, "scope")) {
+ pstrcpy(scope,opteq+1);
+ } else {
+ usage();
+ exit(1);
+ }
+ } else {
+ val = 1;
+ if(!strcmp(opts, "nocaps")) {
+ fprintf(stderr, "Unhandled option: %s\n", opteq+1);
+ exit(1);
+ } else if(!strcmp(opts, "guest")) {
+ got_pass = True;
+ } else if(!strcmp(opts, "rw")) {
+ mount_ro = 0;
+ } else if(!strcmp(opts, "ro")) {
+ mount_ro = 1;
+ }
+ }
+ }
+
+ if (!*service) {
+ usage();
+ exit(1);
+ }
}
/****************************************************************************
@@ -758,229 +622,59 @@ static void usage(char *pname)
****************************************************************************/
int main(int argc,char *argv[])
{
- fstring base_directory;
- char *pname = argv[0];
- int opt;
- extern FILE *dbf;
- extern char *optarg;
- extern int optind;
- pstring query_host;
- BOOL nt_domain_logon = False;
- static pstring servicesf = CONFIGFILE;
- pstring term_code;
- char *p;
-
-#ifdef KANJI
- pstrcpy(term_code, KANJI);
-#else /* KANJI */
- *term_code = 0;
-#endif /* KANJI */
-
- *query_host = 0;
- *base_directory = 0;
-
- DEBUGLEVEL = 2;
-
- setup_logging(pname,True);
-
- TimeInit();
- charset_initialise();
-
- pid = (uint16)getpid();
- vuid = (uint16)getuid();
- mid = pid + 100;
- myumask = umask(0);
- umask(myumask);
-
- if (getenv("USER"))
- {
- pstrcpy(username,getenv("USER"));
-
- /* modification to support userid%passwd syntax in the USER var
- 25.Aug.97, jdblair@uab.edu */
-
- if ((p=strchr(username,'%')))
- {
- *p = 0;
- pstrcpy(password,p+1);
- got_pass = True;
- memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
- }
- strupper(username);
- }
-
- /* modification to support PASSWD environmental var
- 25.Aug.97, jdblair@uab.edu */
-
- if (getenv("PASSWD"))
- pstrcpy(password,getenv("PASSWD"));
-
- if (*username == 0 && getenv("LOGNAME"))
- {
- pstrcpy(username,getenv("LOGNAME"));
- strupper(username);
- }
-
- if (argc < 2)
- {
- usage(pname);
- exit(1);
- }
-
- if (*argv[1] != '-')
- {
-
- pstrcpy(service, argv[1]);
- /* Convert any '/' characters in the service name to '\' characters */
- string_replace( service, '/','\\');
- argc--;
- argv++;
-
- if (count_chars(service,'\\') < 3)
- {
- usage(pname);
- printf("\n%s: Not enough '\\' characters in service\n",service);
- exit(1);
- }
-
- if (argc > 1 && (*argv[1] != '-'))
- {
- got_pass = True;
- pstrcpy(password,argv[1]);
- memset(argv[1],'X',strlen(argv[1]));
- argc--;
- argv++;
- }
- }
-
- while ((opt =
- getopt(argc, argv,"s:B:O:M:S:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
- switch (opt)
- {
- case 'm':
- max_protocol = interpret_protocol(optarg,max_protocol);
- break;
- case 'O':
- pstrcpy(user_socket_options,optarg);
- break;
- case 'S':
- pstrcpy(desthost,optarg);
- strupper(desthost);
- nt_domain_logon = True;
- break;
- case 'B':
- iface_set_default(NULL,optarg,NULL);
- break;
- case 'D':
- pstrcpy(base_directory,optarg);
- break;
- case 'i':
- pstrcpy(scope,optarg);
- break;
- case 'U':
- {
- char *lp;
- pstrcpy(username,optarg);
- if ((lp=strchr(username,'%')))
- {
- *lp = 0;
- pstrcpy(password,lp+1);
- got_pass = True;
- memset(strchr(optarg,'%')+1,'X',strlen(password));
- }
- }
-
- break;
- case 'W':
- pstrcpy(workgroup,optarg);
- break;
- case 'E':
- dbf = stderr;
- break;
- case 'I':
- {
- dest_ip = *interpret_addr2(optarg);
- if (zero_ip(dest_ip)) exit(1);
- have_ip = True;
- }
- break;
- case 'n':
- pstrcpy(global_myname,optarg);
- break;
- case 'N':
- got_pass = True;
- break;
- case 'd':
- if (*optarg == 'A')
- DEBUGLEVEL = 10000;
- else
- DEBUGLEVEL = atoi(optarg);
- break;
- case 'l':
- slprintf(debugf,sizeof(debugf)-1,"%s.client",optarg);
- break;
- case 'p':
- port = atoi(optarg);
- break;
- case 'c':
- cmdstr = optarg;
- got_pass = True;
- break;
- case 'h':
- usage(pname);
- exit(0);
- break;
- case 's':
- pstrcpy(servicesf, optarg);
- break;
- case 't':
- pstrcpy(term_code, optarg);
- break;
- default:
- usage(pname);
- exit(1);
- }
+ extern char *optarg;
+ extern int optind;
+ static pstring servicesf = CONFIGFILE;
+ char *p;
- if (!*query_host && !*service)
- {
- usage(pname);
- exit(1);
- }
+ DEBUGLEVEL = 1;
+
+ setup_logging("mount.smbfs",True);
+ TimeInit();
+ charset_initialise();
+
+ in_client = True; /* Make sure that we tell lp_load we are */
- DEBUG( 3, ( "Client started (version %s)\n", VERSION ) );
+ if (getenv("USER")) {
+ pstrcpy(username,getenv("USER"));
- if(!get_myname(myhostname,NULL))
- {
- DEBUG(0,("Failed to get my hostname.\n"));
- }
+ if ((p=strchr(username,'%'))) {
+ *p = 0;
+ pstrcpy(password,p+1);
+ got_pass = True;
+ }
+ }
- if (!lp_load(servicesf,True,False,False)) {
- fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
- }
+ if (getenv("PASSWD")) {
+ pstrcpy(password,getenv("PASSWD"));
+ }
- codepage_initialise(lp_client_code_page());
+ if (*username == 0 && getenv("LOGNAME")) {
+ pstrcpy(username,getenv("LOGNAME"));
+ }
+
+ parse_mount_smb(argc, argv);
- interpret_coding_system(term_code);
+ DEBUG(3,("mount.smbfs started (version %s)\n", VERSION));
- if (*workgroup == 0)
- pstrcpy(workgroup,lp_workgroup());
+ if (!lp_load(servicesf,True,False,False)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n",
+ servicesf);
+ }
- load_interfaces();
- get_myname((*global_myname)?NULL:global_myname,NULL);
- strupper(global_myname);
+ codepage_initialise(lp_client_code_page());
+
+ if (*workgroup == 0) {
+ pstrcpy(workgroup,lp_workgroup());
+ }
- if (cli_open_sockets(port))
- {
- if (!process(base_directory))
- {
- close_sockets();
- return(1);
+ load_interfaces();
+ if (!*my_netbios_name) {
+ pstrcpy(my_netbios_name, myhostname());
}
- close_sockets();
- }
- else
- return(1);
+ strupper(my_netbios_name);
- return(0);
+ init_mount();
+ return 0;
}
diff --git a/source/client/smbumount.c b/source/client/smbumount.c
index bc8999d765e..dacf4ab67d0 100644
--- a/source/client/smbumount.c
+++ b/source/client/smbumount.c
@@ -23,20 +23,24 @@
#undef SMB_IOC_GETMOUNTUID
#define SMB_IOC_GETMOUNTUID _IOR('u', 1, __kernel_uid_t)
-static char *progname;
+#ifndef O_NOFOLLOW
+#define O_NOFOLLOW 0400000
+#endif
static void
usage(void)
{
- printf("usage: %s mount-point\n", progname);
+ printf("usage: smbumount mountpoint\n");
}
static int
umount_ok(const char *mount_point)
{
- int fid = open(mount_point, O_RDONLY, 0);
+ /* we set O_NOFOLLOW to prevent users playing games with symlinks to
+ umount filesystems they don't own */
+ int fid = open(mount_point, O_RDONLY|O_NOFOLLOW, 0);
__kernel_uid_t mount_uid;
-
+
if (fid == -1) {
fprintf(stderr, "Could not open %s: %s\n",
mount_point, strerror(errno));
@@ -49,7 +53,7 @@ umount_ok(const char *mount_point)
return -1;
}
- if ( (getuid() != 0)
+ if ((getuid() != 0)
&& (mount_uid != getuid())) {
fprintf(stderr, "You are not allowed to umount %s\n",
mount_point);
@@ -63,15 +67,14 @@ umount_ok(const char *mount_point)
/* Make a canonical pathname from PATH. Returns a freshly malloced string.
It is up the *caller* to ensure that the PATH is sensible. i.e.
canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.''
- is not a legal pathname for ``/dev/fd0.'' Anything we cannot parse
+ is not a legal pathname for ``/dev/fd0'' Anything we cannot parse
we return unmodified. */
-char *
+static char *
canonicalize (char *path)
{
char *canonical = malloc (PATH_MAX + 1);
- if (strlen(path) > PATH_MAX)
- {
+ if (strlen(path) > PATH_MAX) {
fprintf(stderr, "Mount point string too long\n");
return NULL;
}
@@ -91,22 +94,18 @@ int
main(int argc, char *argv[])
{
int fd;
-
char* mount_point;
-
struct mntent *mnt;
FILE* mtab;
FILE* new_mtab;
- progname = argv[0];
-
if (argc != 2) {
usage();
exit(1);
}
if (geteuid() != 0) {
- fprintf(stderr, "%s must be installed suid root\n", progname);
+ fprintf(stderr, "smbumount must be installed suid root\n");
exit(1);
}