This commit was manufactured by cvs2svn to create tag
[Samba/gbeck.git] / source / client / smbmount.c
blob364c28cdcdaa6951788240752a783e282117ad55
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 SMB client
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.
22 #define NO_SYSLOG
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
28 #endif
30 #include "includes.h"
32 #include <asm/types.h>
33 #include <linux/smb_fs.h>
34 static struct smb_conn_opt conn_options;
36 #ifndef REGISTER
37 #define REGISTER 0
38 #endif
40 /* Uncomment this to allow debug the smbmount daemon */
41 #define SMBFS_DEBUG 1
43 pstring cur_dir = "\\";
44 pstring cd_path = "";
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;
52 char *cmdstr="";
53 extern BOOL got_pass;
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)
69 extern int name_type;
71 extern int max_protocol;
72 int port = SMB_PORT;
75 time_t newer_than = 0;
76 int archive_level = 0;
78 extern pstring debugf;
79 extern int DEBUGLEVEL;
81 BOOL translation = False;
83 extern uint16 cnum;
84 extern uint16 mid;
85 extern uint16 pid;
86 extern uint16 vuid;
88 extern BOOL have_ip;
89 extern int max_xmit;
91 /* clitar bits insert */
92 extern int blocksize;
93 extern BOOL tar_inc;
94 extern BOOL tar_reset;
95 /* clitar bits end */
98 mode_t myumask = 0755;
100 extern pstring scope;
102 BOOL prompt = True;
104 int printmode = 1;
106 BOOL recurse = False;
107 BOOL lowercase = False;
109 struct in_addr dest_ip;
111 #define SEPARATORS " \t\n\r"
113 BOOL abort_mget = True;
115 extern int Protocol;
117 extern BOOL readbraw_supported ;
118 extern BOOL writebraw_supported;
120 pstring fileselection = "";
122 extern file_info def_finfo;
124 /* timing globals */
125 int get_total_size = 0;
126 int get_total_time_ms = 0;
127 int put_total_size = 0;
128 int put_total_time_ms = 0;
130 /* totals globals */
131 int dir_total = 0;
133 extern int Client;
135 #define USENMB
137 #define CNV_LANG(s) dos_to_unix(s,False)
138 #define CNV_INPUT(s) unix_to_dos(s,True)
140 /****************************************************************************
141 check for existance of a dir
142 ****************************************************************************/
143 static BOOL chkpath(char *path,BOOL report)
145 fstring path2;
146 pstring inbuf,outbuf;
147 char *p;
149 fstrcpy(path2,path);
150 trim_string(path2,NULL,"\\");
151 if (!*path2) *path2 = '\\';
153 bzero(outbuf,smb_size);
154 set_message(outbuf,0,4 + strlen(path2),True);
155 SCVAL(outbuf,smb_com,SMBchkpth);
156 SSVAL(outbuf,smb_tid,cnum);
157 cli_setup_pkt(outbuf);
159 p = smb_buf(outbuf);
160 *p++ = 4;
161 fstrcpy(p,path2);
163 #if 0
165 /* this little bit of code can be used to extract NT error codes.
166 Just feed a bunch of "cd foo" commands to smbclient then watch
167 in netmon (tridge) */
168 static int code=0;
169 SIVAL(outbuf, smb_rcls, code | 0xC0000000);
170 SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | (1<<14));
171 code++;
173 #endif
175 send_smb(Client,outbuf);
176 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
178 if (report && CVAL(inbuf,smb_rcls) != 0)
179 DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf)));
181 return(CVAL(inbuf,smb_rcls) == 0);
184 static void
185 daemonize(void)
187 int i;
188 if ((i = fork()) < 0)
190 DEBUG(0, ("could not fork\n"));
192 if (i > 0)
194 /* parent simply exits */
195 exit(0);
197 setsid();
198 chdir("/");
201 static void
202 close_our_files(void)
204 int i;
205 for (i = 0; i < NR_OPEN; i++) {
206 if (i == Client) {
207 continue;
209 close(i);
213 static void
214 usr1_handler(int x)
216 return;
220 * Send a login and store the connection options. This is a separate
221 * function to keep clientutil.c independent of linux kernel changes.
223 static BOOL mount_send_login(char *inbuf, char *outbuf)
225 struct connection_options opt;
226 int res = cli_send_login(inbuf, outbuf, True, True, &opt);
228 if (!res)
229 return res;
231 conn_options.protocol = opt.protocol;
232 conn_options.case_handling = CASE_LOWER;
233 conn_options.max_xmit = opt.max_xmit;
234 conn_options.server_uid = opt.server_vuid;
235 conn_options.tid = opt.tid;
236 conn_options.secmode = opt.sec_mode;
237 conn_options.maxmux = opt.max_mux;
238 conn_options.maxvcs = opt.max_vcs;
239 conn_options.rawmode = opt.rawmode;
240 conn_options.sesskey = opt.sesskey;
241 conn_options.maxraw = opt.maxraw;
242 conn_options.capabilities = opt.capabilities;
243 conn_options.serverzone = opt.serverzone;
245 return True;
249 * Call the smbfs ioctl to install a connection socket,
250 * then wait for a signal to reconnect. Note that we do
251 * not exit after open_sockets() or send_login() errors,
252 * as the smbfs mount would then have no way to recover.
254 static void
255 send_fs_socket(char *mount_point, char *inbuf, char *outbuf)
257 int fd, closed = 0, res = 1;
259 while (1)
261 if ((fd = open(mount_point, O_RDONLY)) < 0)
263 DEBUG(0, ("smbmount: can't open %s\n", mount_point));
264 break;
268 * Call the ioctl even if we couldn't get a socket ...
269 * there's no point in making smbfs wait for a timeout.
271 conn_options.fd = -1;
272 if (res)
273 conn_options.fd = Client;
274 res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
275 if (res != 0)
277 DEBUG(0, ("smbmount: ioctl failed, res=%d\n", res));
280 close_sockets();
281 close(fd);
283 * Close all open files if we haven't done so yet.
285 #ifndef SMBFS_DEBUG
286 if (!closed)
288 closed = 1;
289 close_our_files();
291 #endif
294 * Wait for a signal from smbfs ...
296 CatchSignal(SIGUSR1, &usr1_handler);
297 pause();
298 DEBUG(0, ("smbmount: got signal, getting new socket\n"));
300 res = cli_open_sockets(port);
301 if (!res)
303 DEBUG(0, ("smbmount: can't open sockets\n"));
304 continue;
307 res = mount_send_login(inbuf, outbuf);
308 if (!res)
310 DEBUG(0, ("smbmount: login failed\n"));
313 DEBUG(0, ("smbmount: exit\n"));
314 exit(1);
317 /****************************************************************************
318 mount smbfs
319 ****************************************************************************/
320 static void cmd_mount(char *inbuf,char *outbuf)
322 pstring mpoint;
323 pstring share_name;
324 pstring mount_command;
325 fstring buf;
326 int retval;
327 char mount_point[MAXPATHLEN+1];
329 if (!next_token(NULL, mpoint, NULL, sizeof(mpoint)))
331 DEBUG(0,("You must supply a mount point\n"));
332 return;
335 memset(mount_point, 0, sizeof(mount_point));
337 if (realpath(mpoint, mount_point) == NULL)
339 DEBUG(0, ("Could not resolve mount point\n"));
340 return;
344 * Build the service name to report on the Unix side,
345 * converting '\' to '/' and ' ' to '_'.
347 pstrcpy(share_name, service);
348 string_replace(share_name, '\\', '/');
349 string_replace(share_name, ' ', '_');
351 slprintf(mount_command, sizeof(mount_command)-1,"smbmnt %s -s %s", mount_point, share_name);
353 while(next_token(NULL, buf, NULL, sizeof(buf)))
355 pstrcat(mount_command, " ");
356 pstrcat(mount_command, buf);
359 DEBUG(3, ("mount command: %s\n", mount_command));
361 if ((retval = system(mount_command)) != 0)
363 DEBUG(0,("mount failed\n"));
364 exit(1);
368 * Create the background process after trying the mount.
369 * to avoid race conditions with automount and other processes.
371 daemonize();
373 /* The parent has exited here, leave the daemon to deal with
374 * disconnects and reconnects
376 send_fs_socket(mount_point, inbuf, outbuf);
380 /* This defines the commands supported by this client */
381 struct
383 char *name;
384 void (*fn)();
385 char *description;
386 } commands[] =
388 {"mount", cmd_mount, "<mount-point options> mount an smbfs file system"},
389 {"",NULL,NULL}
393 /*******************************************************************
394 lookup a command string in the list of commands, including
395 abbreviations
396 ******************************************************************/
397 static int process_tok(fstring tok)
399 int i = 0, matches = 0;
400 int cmd=0;
401 int tok_len = strlen(tok);
403 while (commands[i].fn != NULL)
405 if (strequal(commands[i].name,tok))
407 matches = 1;
408 cmd = i;
409 break;
411 else if (strnequal(commands[i].name, tok, tok_len))
413 matches++;
414 cmd = i;
416 i++;
419 if (matches == 0)
420 return(-1);
421 else if (matches == 1)
422 return(cmd);
423 else
424 return(-2);
427 /****************************************************************************
428 help
429 ****************************************************************************/
430 void cmd_help(char *dum_in, char *dum_out)
432 int i=0,j;
433 fstring buf;
435 if (next_token(NULL,buf,NULL,sizeof(buf)))
437 if ((i = process_tok(buf)) >= 0)
438 DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));
440 else
441 while (commands[i].description)
443 for (j=0; commands[i].description && (j<5); j++) {
444 DEBUG(0,("%-15s",commands[i].name));
445 i++;
447 DEBUG(0,("\n"));
451 /****************************************************************************
452 wait for keyboard activity, swallowing network packets
453 ****************************************************************************/
454 static void wait_keyboard(char *buffer)
456 fd_set fds;
457 int selrtn;
458 struct timeval timeout;
460 while (1)
462 extern int Client;
463 FD_ZERO(&fds);
464 FD_SET(Client,&fds);
465 FD_SET(fileno(stdin),&fds);
467 timeout.tv_sec = 20;
468 timeout.tv_usec = 0;
469 selrtn = sys_select(MAX(Client,fileno(stdin))+1,&fds,&timeout);
471 if (FD_ISSET(fileno(stdin),&fds))
472 return;
474 /* We deliberately use receive_smb instead of
475 client_receive_smb as we want to receive
476 session keepalives and then drop them here.
478 if (FD_ISSET(Client,&fds))
479 receive_smb(Client,buffer,0);
481 chkpath("\\",False);
486 /****************************************************************************
487 process commands from the client
488 ****************************************************************************/
489 static BOOL process(char *base_directory)
491 extern FILE *dbf;
492 pstring line;
493 char *cmd;
495 char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
496 char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
498 if ((InBuffer == NULL) || (OutBuffer == NULL))
499 return(False);
501 bzero(OutBuffer,smb_size);
503 if (!mount_send_login(InBuffer,OutBuffer))
504 return(False);
506 cmd = cmdstr;
507 if (cmd[0] != '\0') while (cmd[0] != '\0')
509 char *p;
510 fstring tok;
511 int i;
513 if ((p = strchr(cmd, ';')) == 0)
515 strncpy(line, cmd, 999);
516 line[1000] = '\0';
517 cmd += strlen(cmd);
519 else
521 if (p - cmd > 999) p = cmd + 999;
522 strncpy(line, cmd, p - cmd);
523 line[p - cmd] = '\0';
524 cmd = p + 1;
527 /* input language code to internal one */
528 CNV_INPUT (line);
530 /* and get the first part of the command */
532 char *ptr = line;
533 if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
536 if ((i = process_tok(tok)) >= 0)
537 commands[i].fn(InBuffer,OutBuffer);
538 else if (i == -2)
539 DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
540 else
541 DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
543 else while (!feof(stdin))
545 fstring tok;
546 int i;
548 bzero(OutBuffer,smb_size);
550 /* display a prompt */
551 DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
552 dbgflush();
554 wait_keyboard(InBuffer);
556 /* and get a response */
557 if (!fgets(line,1000,stdin))
558 break;
560 /* input language code to internal one */
561 CNV_INPUT (line);
563 /* special case - first char is ! */
564 if (*line == '!')
566 system(line + 1);
567 continue;
570 /* and get the first part of the command */
572 char *ptr = line;
573 if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
576 if ((i = process_tok(tok)) >= 0)
577 commands[i].fn(InBuffer,OutBuffer);
578 else if (i == -2)
579 DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
580 else
581 DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
584 cli_send_logout(InBuffer,OutBuffer);
585 return(True);
588 /****************************************************************************
589 usage on the program
590 ****************************************************************************/
591 static void usage(char *pname)
593 DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
594 pname));
596 DEBUG(0,("\nVersion %s\n",VERSION));
597 DEBUG(0,("\t-p port connect to the specified port\n"));
598 DEBUG(0,("\t-d debuglevel set the debuglevel\n"));
599 DEBUG(0,("\t-l log basename. Basename for log/debug files\n"));
600 DEBUG(0,("\t-n netbios name. Use this name as my netbios name\n"));
601 DEBUG(0,("\t-N don't ask for a password\n"));
602 DEBUG(0,("\t-m max protocol set the max protocol level\n"));
603 DEBUG(0,("\t-I dest IP use this IP to connect to\n"));
604 DEBUG(0,("\t-E write messages to stderr instead of stdout\n"));
605 DEBUG(0,("\t-U username set the network username\n"));
606 DEBUG(0,("\t-W workgroup set the workgroup name\n"));
607 DEBUG(0,("\t-c command string execute semicolon separated commands\n"));
608 DEBUG(0,("\t-t terminal code terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
609 DEBUG(0,("\t-D directory start from directory\n"));
610 DEBUG(0,("\n"));
613 /****************************************************************************
614 main program
615 ****************************************************************************/
616 int main(int argc,char *argv[])
618 fstring base_directory;
619 char *pname = argv[0];
620 int opt;
621 extern FILE *dbf;
622 extern char *optarg;
623 extern int optind;
624 pstring query_host;
625 BOOL nt_domain_logon = False;
626 static pstring servicesf = CONFIGFILE;
627 pstring term_code;
628 char *p;
630 #ifdef KANJI
631 pstrcpy(term_code, KANJI);
632 #else /* KANJI */
633 *term_code = 0;
634 #endif /* KANJI */
636 *query_host = 0;
637 *base_directory = 0;
639 DEBUGLEVEL = 2;
641 setup_logging(pname,True);
643 TimeInit();
644 charset_initialise();
646 pid = (uint16)getpid();
647 vuid = (uint16)getuid();
648 mid = pid + 100;
649 myumask = umask(0);
650 umask(myumask);
652 if (getenv("USER"))
654 pstrcpy(username,getenv("USER"));
656 /* modification to support userid%passwd syntax in the USER var
657 25.Aug.97, jdblair@uab.edu */
659 if ((p=strchr(username,'%')))
661 *p = 0;
662 pstrcpy(password,p+1);
663 got_pass = True;
664 memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
666 strupper(username);
669 /* modification to support PASSWD environmental var
670 25.Aug.97, jdblair@uab.edu */
672 if (getenv("PASSWD"))
673 pstrcpy(password,getenv("PASSWD"));
675 if (*username == 0 && getenv("LOGNAME"))
677 pstrcpy(username,getenv("LOGNAME"));
678 strupper(username);
681 if (argc < 2)
683 usage(pname);
684 exit(1);
687 if (*argv[1] != '-')
690 pstrcpy(service, argv[1]);
691 /* Convert any '/' characters in the service name to '\' characters */
692 string_replace( service, '/','\\');
693 argc--;
694 argv++;
696 if (count_chars(service,'\\') < 3)
698 usage(pname);
699 printf("\n%s: Not enough '\\' characters in service\n",service);
700 exit(1);
703 if (argc > 1 && (*argv[1] != '-'))
705 got_pass = True;
706 pstrcpy(password,argv[1]);
707 memset(argv[1],'X',strlen(argv[1]));
708 argc--;
709 argv++;
713 while ((opt =
714 getopt(argc, argv,"s:B:O:M:S:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
715 switch (opt)
717 case 'm':
718 max_protocol = interpret_protocol(optarg,max_protocol);
719 break;
720 case 'O':
721 pstrcpy(user_socket_options,optarg);
722 break;
723 case 'S':
724 pstrcpy(desthost,optarg);
725 strupper(desthost);
726 nt_domain_logon = True;
727 break;
728 case 'B':
729 iface_set_default(NULL,optarg,NULL);
730 break;
731 case 'D':
732 pstrcpy(base_directory,optarg);
733 break;
734 case 'i':
735 pstrcpy(scope,optarg);
736 break;
737 case 'U':
739 char *lp;
740 pstrcpy(username,optarg);
741 if ((lp=strchr(username,'%')))
743 *lp = 0;
744 pstrcpy(password,lp+1);
745 got_pass = True;
746 memset(strchr(optarg,'%')+1,'X',strlen(password));
750 break;
751 case 'W':
752 pstrcpy(workgroup,optarg);
753 break;
754 case 'E':
755 dbf = stderr;
756 break;
757 case 'I':
759 dest_ip = *interpret_addr2(optarg);
760 if (zero_ip(dest_ip)) exit(1);
761 have_ip = True;
763 break;
764 case 'n':
765 pstrcpy(global_myname,optarg);
766 break;
767 case 'N':
768 got_pass = True;
769 break;
770 case 'd':
771 if (*optarg == 'A')
772 DEBUGLEVEL = 10000;
773 else
774 DEBUGLEVEL = atoi(optarg);
775 break;
776 case 'l':
777 slprintf(debugf,sizeof(debugf)-1,"%s.client",optarg);
778 break;
779 case 'p':
780 port = atoi(optarg);
781 break;
782 case 'c':
783 cmdstr = optarg;
784 got_pass = True;
785 break;
786 case 'h':
787 usage(pname);
788 exit(0);
789 break;
790 case 's':
791 pstrcpy(servicesf, optarg);
792 break;
793 case 't':
794 pstrcpy(term_code, optarg);
795 break;
796 default:
797 usage(pname);
798 exit(1);
801 if (!*query_host && !*service)
803 usage(pname);
804 exit(1);
808 DEBUG( 3, ( "Client started (version %s)\n", VERSION ) );
810 if(!get_myname(myhostname,NULL))
812 DEBUG(0,("Failed to get my hostname.\n"));
815 if (!lp_load(servicesf,True,False,False)) {
816 fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
819 codepage_initialise(lp_client_code_page());
821 interpret_coding_system(term_code);
823 if (*workgroup == 0)
824 pstrcpy(workgroup,lp_workgroup());
826 load_interfaces();
827 get_myname((*global_myname)?NULL:global_myname,NULL);
828 strupper(global_myname);
830 if (cli_open_sockets(port))
832 if (!process(base_directory))
834 close_sockets();
835 return(1);
837 close_sockets();
839 else
840 return(1);
842 return(0);