diff options
Diffstat (limited to 'source/client')
-rw-r--r-- | source/client/client.c | 691 | ||||
-rw-r--r-- | source/client/clitar.c | 92 | ||||
-rw-r--r-- | source/client/smbmnt.c | 201 | ||||
-rw-r--r-- | source/client/smbmount.c | 1196 | ||||
-rw-r--r-- | source/client/smbumount.c | 27 |
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, <arbuf[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); } |