2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1994-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <linux/version.h>
25 #define LVERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
26 #if LINUX_VERSION_CODE < LVERSION(2,1,70)
27 #error this code will only compile on versions of linux after 2.1.70
32 #include <asm/types.h>
33 #include <linux/smb_fs.h>
34 static struct smb_conn_opt conn_options;
40 /* Uncomment this to allow debug the smbmount daemon */
43 pstring cur_dir = "\\";
45 extern pstring service;
46 extern pstring desthost;
47 extern pstring global_myname;
48 extern pstring myhostname;
49 extern pstring password;
50 extern pstring username;
51 extern pstring workgroup;
54 extern BOOL connect_as_printer;
55 extern BOOL connect_as_ipc;
56 extern struct in_addr ipzero;
58 extern BOOL doencrypt;
60 extern pstring user_socket_options;
62 /* 30 second timeout on most commands */
63 #define CLIENT_TIMEOUT (30*1000)
64 #define SHORT_TIMEOUT (5*1000)
66 /* value for unused fid field in trans2 secondary request */
67 #define FID_UNUSED (0xFFFF)
71 extern int max_protocol;
74 time_t newer_than = 0;
75 int archive_level = 0;
77 extern pstring debugf;
78 extern int DEBUGLEVEL;
80 BOOL translation = False;
90 /* clitar bits insert */
93 extern BOOL tar_reset;
97 mode_t myumask = 0755;
105 BOOL recurse = False;
106 BOOL lowercase = False;
108 struct in_addr dest_ip;
110 #define SEPARATORS " \t\n\r"
112 BOOL abort_mget = True;
116 extern BOOL readbraw_supported ;
117 extern BOOL writebraw_supported;
119 pstring fileselection = "";
121 extern file_info def_finfo;
124 int get_total_size = 0;
125 int get_total_time_ms = 0;
126 int put_total_size = 0;
127 int put_total_time_ms = 0;
136 #define CNV_LANG(s) dos_to_unix(s,False)
137 #define CNV_INPUT(s) unix_to_dos(s,True)
139 /****************************************************************************
140 check for existance of a dir
141 ****************************************************************************/
142 static BOOL chkpath(char *path,BOOL report)
145 pstring inbuf,outbuf;
149 trim_string(path2,NULL,"\\");
150 if (!*path2) *path2 = '\\';
152 memset(outbuf,'\0',smb_size);
153 set_message(outbuf,0,4 + strlen(path2),True);
154 SCVAL(outbuf,smb_com,SMBchkpth);
155 SSVAL(outbuf,smb_tid,cnum);
156 cli_setup_pkt(outbuf);
164 /* this little bit of code can be used to extract NT error codes.
165 Just feed a bunch of "cd foo" commands to smbclient then watch
166 in netmon (tridge) */
168 SIVAL(outbuf, smb_rcls, code | 0xC0000000);
169 SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | (1<<14));
174 send_smb(Client,outbuf);
175 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
177 if (report && CVAL(inbuf,smb_rcls) != 0)
178 DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf)));
180 return(CVAL(inbuf,smb_rcls) == 0);
184 exit_parent( int sig )
186 /* parent simply exits when child says go... */
196 signal( SIGTERM, exit_parent );
198 if ((child_pid = fork()) < 0)
200 DEBUG(0, ("could not fork\n"));
205 j = waitpid( child_pid, &status, 0 );
207 if( EINTR == errno ) {
214 /* If we get here - the child exited with some error status */
218 Danger Will Robinson! Danger!
220 There use to be a call to setsid() here. This does no
221 harm to normal mount operations, but it broke automounting.
222 The setsid call has been moved to just before the child
223 sends the SIGTERM to the parent. All of our deadly embrace
224 conditions with autofs will have been cleared by then...
227 signal( SIGTERM, SIG_DFL );
232 close_our_files(void)
235 for (i = 0; i < NR_OPEN; i++) {
250 * Send a login and store the connection options. This is a separate
251 * function to keep clientutil.c independent of linux kernel changes.
253 static BOOL mount_send_login(char *inbuf, char *outbuf)
255 struct connection_options opt;
256 int res = cli_send_login(inbuf, outbuf, True, True, &opt);
261 conn_options.protocol = opt.protocol;
262 conn_options.case_handling = CASE_LOWER;
263 conn_options.max_xmit = opt.max_xmit;
264 conn_options.server_uid = opt.server_vuid;
265 conn_options.tid = opt.tid;
266 conn_options.secmode = opt.sec_mode;
267 conn_options.maxmux = opt.max_mux;
268 conn_options.maxvcs = opt.max_vcs;
269 conn_options.rawmode = opt.rawmode;
270 conn_options.sesskey = opt.sesskey;
271 conn_options.maxraw = opt.maxraw;
272 conn_options.capabilities = opt.capabilities;
273 conn_options.serverzone = opt.serverzone;
279 * Call the smbfs ioctl to install a connection socket,
280 * then wait for a signal to reconnect. Note that we do
281 * not exit after open_sockets() or send_login() errors,
282 * as the smbfs mount would then have no way to recover.
285 send_fs_socket(char *mount_point, char *inbuf, char *outbuf)
287 int fd, closed = 0, res = 1;
289 pid_t parentpid = getppid();
293 if ((fd = open(mount_point, O_RDONLY)) < 0)
295 DEBUG(0, ("smbmount: can't open %s\n", mount_point));
300 * Call the ioctl even if we couldn't get a socket ...
301 * there's no point in making smbfs wait for a timeout.
303 conn_options.fd = -1;
305 conn_options.fd = Client;
306 res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
309 DEBUG(0, ("smbmount: ioctl failed, res=%d\n", res));
313 /* Ok... We are going to kill the parent. Now
314 is the time to break the process group... */
316 /* Send a signal to the parent to terminate */
317 kill( parentpid, SIGTERM );
324 * Close all open files if we haven't done so yet.
335 * Wait for a signal from smbfs ...
337 CatchSignal(SIGUSR1, &usr1_handler);
339 DEBUG(0, ("smbmount: got signal, getting new socket\n"));
341 res = cli_open_sockets(port);
344 DEBUG(0, ("smbmount: can't open sockets\n"));
348 res = mount_send_login(inbuf, outbuf);
351 DEBUG(0, ("smbmount: login failed\n"));
354 DEBUG(0, ("smbmount: exit\n"));
358 /****************************************************************************
360 ****************************************************************************/
361 static void cmd_mount(char *inbuf,char *outbuf)
365 pstring mount_command;
368 char mount_point[MAXPATHLEN+1];
370 if (!next_token(NULL, mpoint, NULL, sizeof(mpoint)))
372 DEBUG(0,("You must supply a mount point\n"));
376 memset(mount_point, 0, sizeof(mount_point));
378 if (realpath(mpoint, mount_point) == NULL)
380 DEBUG(0, ("Could not resolve mount point\n"));
385 * Build the service name to report on the Unix side,
386 * converting '\' to '/' and ' ' to '_'.
388 pstrcpy(share_name, service);
389 string_replace(share_name, '\\', '/');
390 string_replace(share_name, ' ', '_');
392 slprintf(mount_command, sizeof(mount_command)-1,"smbmnt %s -s %s", mount_point, share_name);
394 while(next_token(NULL, buf, NULL, sizeof(buf)))
396 pstrcat(mount_command, " ");
397 pstrcat(mount_command, buf);
400 DEBUG(3, ("mount command: %s\n", mount_command));
403 Set up to return as a daemon child and wait in the parent
404 until the child say it's ready...
408 if ((retval = system(mount_command)) != 0)
410 DEBUG(0,("mount failed\n"));
414 send_fs_socket(mount_point, inbuf, outbuf);
418 /* This defines the commands supported by this client */
426 {"mount", cmd_mount, "<mount-point options> mount an smbfs file system"},
431 /*******************************************************************
432 lookup a command string in the list of commands, including
434 ******************************************************************/
435 static int process_tok(fstring tok)
437 int i = 0, matches = 0;
439 int tok_len = strlen(tok);
441 while (commands[i].fn != NULL)
443 if (strequal(commands[i].name,tok))
449 else if (strnequal(commands[i].name, tok, tok_len))
459 else if (matches == 1)
465 /****************************************************************************
467 ****************************************************************************/
468 void cmd_help(char *dum_in, char *dum_out)
473 if (next_token(NULL,buf,NULL,sizeof(buf)))
475 if ((i = process_tok(buf)) >= 0)
476 DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));
479 while (commands[i].description)
481 for (j=0; commands[i].description && (j<5); j++) {
482 DEBUG(0,("%-15s",commands[i].name));
489 /****************************************************************************
490 wait for keyboard activity, swallowing network packets
491 ****************************************************************************/
492 static void wait_keyboard(char *buffer)
496 struct timeval timeout;
503 FD_SET(fileno(stdin),&fds);
507 selrtn = sys_select(MAX(Client,fileno(stdin))+1,&fds,&timeout);
509 if (FD_ISSET(fileno(stdin),&fds))
512 /* We deliberately use receive_smb instead of
513 client_receive_smb as we want to receive
514 session keepalives and then drop them here.
516 if (FD_ISSET(Client,&fds))
517 receive_smb(Client,buffer,0);
524 /****************************************************************************
525 process commands from the client
526 ****************************************************************************/
527 static BOOL process(char *base_directory)
533 char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
534 char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
536 if ((InBuffer == NULL) || (OutBuffer == NULL))
539 memset(OutBuffer,'\0',smb_size);
541 if (!mount_send_login(InBuffer,OutBuffer))
545 if (cmd[0] != '\0') while (cmd[0] != '\0')
551 if ((p = strchr(cmd, ';')) == 0)
553 strncpy(line, cmd, 999);
559 if (p - cmd > 999) p = cmd + 999;
560 strncpy(line, cmd, p - cmd);
561 line[p - cmd] = '\0';
565 /* input language code to internal one */
568 /* and get the first part of the command */
571 if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
574 if ((i = process_tok(tok)) >= 0)
575 commands[i].fn(InBuffer,OutBuffer);
577 DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
579 DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
581 else while (!feof(stdin))
586 memset(OutBuffer,'\0',smb_size);
588 /* display a prompt */
589 DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
592 wait_keyboard(InBuffer);
594 /* and get a response */
595 if (!fgets(line,1000,stdin))
598 /* input language code to internal one */
601 /* special case - first char is ! */
608 /* and get the first part of the command */
611 if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
614 if ((i = process_tok(tok)) >= 0)
615 commands[i].fn(InBuffer,OutBuffer);
617 DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
619 DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
622 cli_send_logout(InBuffer,OutBuffer);
626 /****************************************************************************
628 ****************************************************************************/
629 static void usage(char *pname)
631 DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
634 DEBUG(0,("\nVersion %s\n",VERSION));
635 DEBUG(0,("\t-p port connect to the specified port\n"));
636 DEBUG(0,("\t-d debuglevel set the debuglevel\n"));
637 DEBUG(0,("\t-l log basename. Basename for log/debug files\n"));
638 DEBUG(0,("\t-n netbios name. Use this name as my netbios name\n"));
639 DEBUG(0,("\t-N don't ask for a password\n"));
640 DEBUG(0,("\t-m max protocol set the max protocol level\n"));
641 DEBUG(0,("\t-I dest IP use this IP to connect to\n"));
642 DEBUG(0,("\t-E write messages to stderr instead of stdout\n"));
643 DEBUG(0,("\t-U username set the network username\n"));
644 DEBUG(0,("\t-W workgroup set the workgroup name\n"));
645 DEBUG(0,("\t-c command string execute semicolon separated commands\n"));
646 DEBUG(0,("\t-t terminal code terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
647 DEBUG(0,("\t-D directory start from directory\n"));
651 /****************************************************************************
653 ****************************************************************************/
654 int main(int argc,char *argv[])
656 fstring base_directory;
657 char *pname = argv[0];
663 BOOL nt_domain_logon = False;
664 static pstring servicesf = CONFIGFILE;
669 pstrcpy(term_code, KANJI);
679 setup_logging(pname,True);
682 charset_initialise();
684 pid = (uint16)getpid();
685 vuid = (uint16)getuid();
692 pstrcpy(username,getenv("USER"));
694 /* modification to support userid%passwd syntax in the USER var
695 25.Aug.97, jdblair@uab.edu */
697 if ((p=strchr(username,'%')))
700 pstrcpy(password,p+1);
702 memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
707 /* modification to support PASSWD environmental var
708 25.Aug.97, jdblair@uab.edu */
710 if (getenv("PASSWD"))
711 pstrcpy(password,getenv("PASSWD"));
713 if (*username == 0 && getenv("LOGNAME"))
715 pstrcpy(username,getenv("LOGNAME"));
728 pstrcpy(service, argv[1]);
729 /* Convert any '/' characters in the service name to '\' characters */
730 string_replace( service, '/','\\');
734 if (count_chars(service,'\\') < 3)
737 printf("\n%s: Not enough '\\' characters in service\n",service);
741 if (argc > 1 && (*argv[1] != '-'))
744 pstrcpy(password,argv[1]);
745 memset(argv[1],'X',strlen(argv[1]));
752 getopt(argc, argv,"s:B:O:M:S:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
756 max_protocol = interpret_protocol(optarg,max_protocol);
759 pstrcpy(user_socket_options,optarg);
762 pstrcpy(desthost,optarg);
764 nt_domain_logon = True;
767 iface_set_default(NULL,optarg,NULL);
770 pstrcpy(base_directory,optarg);
773 pstrcpy(scope,optarg);
778 pstrcpy(username,optarg);
779 if ((lp=strchr(username,'%')))
782 pstrcpy(password,lp+1);
784 memset(strchr(optarg,'%')+1,'X',strlen(password));
790 pstrcpy(workgroup,optarg);
797 dest_ip = *interpret_addr2(optarg);
798 if (zero_ip(dest_ip)) exit(1);
803 pstrcpy(global_myname,optarg);
812 DEBUGLEVEL = atoi(optarg);
815 slprintf(debugf,sizeof(debugf)-1,"%s.client",optarg);
829 pstrcpy(servicesf, optarg);
832 pstrcpy(term_code, optarg);
839 if (!*query_host && !*service)
846 DEBUG( 3, ( "Client started (version %s)\n", VERSION ) );
848 if(!get_myname(myhostname,NULL))
850 DEBUG(0,("Failed to get my hostname.\n"));
853 if (!lp_load(servicesf,True,False,False)) {
854 fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
857 codepage_initialise(lp_client_code_page());
859 interpret_coding_system(term_code);
862 pstrcpy(workgroup,lp_workgroup());
865 get_myname((*global_myname)?NULL:global_myname,NULL);
866 strupper(global_myname);
868 if (cli_open_sockets(port))
870 if (!process(base_directory))