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
;
75 time_t newer_than
= 0;
76 int archive_level
= 0;
78 extern pstring debugf
;
79 extern int DEBUGLEVEL
;
81 BOOL translation
= False
;
91 /* clitar bits insert */
94 extern BOOL tar_reset
;
98 mode_t myumask
= 0755;
100 extern pstring scope
;
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
;
117 extern BOOL readbraw_supported
;
118 extern BOOL writebraw_supported
;
120 pstring fileselection
= "";
122 extern file_info def_finfo
;
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;
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
)
146 pstring inbuf
,outbuf
;
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
);
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) */
169 SIVAL(outbuf
, smb_rcls
, code
| 0xC0000000);
170 SSVAL(outbuf
, smb_flg2
, SVAL(outbuf
, smb_flg2
) | (1<<14));
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);
188 if ((i
= fork()) < 0)
190 DEBUG(0, ("could not fork\n"));
194 /* parent simply exits */
202 close_our_files(void)
205 for (i
= 0; i
< NR_OPEN
; i
++) {
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
);
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
;
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.
255 send_fs_socket(char *mount_point
, char *inbuf
, char *outbuf
)
257 int fd
, closed
= 0, res
= 1;
261 if ((fd
= open(mount_point
, O_RDONLY
)) < 0)
263 DEBUG(0, ("smbmount: can't open %s\n", mount_point
));
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;
273 conn_options
.fd
= Client
;
274 res
= ioctl(fd
, SMB_IOC_NEWCONN
, &conn_options
);
277 DEBUG(0, ("smbmount: ioctl failed, res=%d\n", res
));
283 * Close all open files if we haven't done so yet.
294 * Wait for a signal from smbfs ...
296 CatchSignal(SIGUSR1
, &usr1_handler
);
298 DEBUG(0, ("smbmount: got signal, getting new socket\n"));
300 res
= cli_open_sockets(port
);
303 DEBUG(0, ("smbmount: can't open sockets\n"));
307 res
= mount_send_login(inbuf
, outbuf
);
310 DEBUG(0, ("smbmount: login failed\n"));
313 DEBUG(0, ("smbmount: exit\n"));
317 /****************************************************************************
319 ****************************************************************************/
320 static void cmd_mount(char *inbuf
,char *outbuf
)
324 pstring mount_command
;
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"));
335 memset(mount_point
, 0, sizeof(mount_point
));
337 if (realpath(mpoint
, mount_point
) == NULL
)
339 DEBUG(0, ("Could not resolve mount point\n"));
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"));
368 * Create the background process after trying the mount.
369 * to avoid race conditions with automount and other processes.
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 */
388 {"mount", cmd_mount
, "<mount-point options> mount an smbfs file system"},
393 /*******************************************************************
394 lookup a command string in the list of commands, including
396 ******************************************************************/
397 static int process_tok(fstring tok
)
399 int i
= 0, matches
= 0;
401 int tok_len
= strlen(tok
);
403 while (commands
[i
].fn
!= NULL
)
405 if (strequal(commands
[i
].name
,tok
))
411 else if (strnequal(commands
[i
].name
, tok
, tok_len
))
421 else if (matches
== 1)
427 /****************************************************************************
429 ****************************************************************************/
430 void cmd_help(char *dum_in
, char *dum_out
)
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
));
441 while (commands
[i
].description
)
443 for (j
=0; commands
[i
].description
&& (j
<5); j
++) {
444 DEBUG(0,("%-15s",commands
[i
].name
));
451 /****************************************************************************
452 wait for keyboard activity, swallowing network packets
453 ****************************************************************************/
454 static void wait_keyboard(char *buffer
)
458 struct timeval timeout
;
465 FD_SET(fileno(stdin
),&fds
);
469 selrtn
= sys_select(MAX(Client
,fileno(stdin
))+1,&fds
,&timeout
);
471 if (FD_ISSET(fileno(stdin
),&fds
))
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);
486 /****************************************************************************
487 process commands from the client
488 ****************************************************************************/
489 static BOOL
process(char *base_directory
)
495 char *InBuffer
= (char *)malloc(BUFFER_SIZE
+ SAFETY_MARGIN
);
496 char *OutBuffer
= (char *)malloc(BUFFER_SIZE
+ SAFETY_MARGIN
);
498 if ((InBuffer
== NULL
) || (OutBuffer
== NULL
))
501 bzero(OutBuffer
,smb_size
);
503 if (!mount_send_login(InBuffer
,OutBuffer
))
507 if (cmd
[0] != '\0') while (cmd
[0] != '\0')
513 if ((p
= strchr(cmd
, ';')) == 0)
515 strncpy(line
, cmd
, 999);
521 if (p
- cmd
> 999) p
= cmd
+ 999;
522 strncpy(line
, cmd
, p
- cmd
);
523 line
[p
- cmd
] = '\0';
527 /* input language code to internal one */
530 /* and get the first part of the command */
533 if (!next_token(&ptr
,tok
,NULL
,sizeof(tok
))) continue;
536 if ((i
= process_tok(tok
)) >= 0)
537 commands
[i
].fn(InBuffer
,OutBuffer
);
539 DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok
)));
541 DEBUG(0,("%s: command not found\n",CNV_LANG(tok
)));
543 else while (!feof(stdin
))
548 bzero(OutBuffer
,smb_size
);
550 /* display a prompt */
551 DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir
)));
554 wait_keyboard(InBuffer
);
556 /* and get a response */
557 if (!fgets(line
,1000,stdin
))
560 /* input language code to internal one */
563 /* special case - first char is ! */
570 /* and get the first part of the command */
573 if (!next_token(&ptr
,tok
,NULL
,sizeof(tok
))) continue;
576 if ((i
= process_tok(tok
)) >= 0)
577 commands
[i
].fn(InBuffer
,OutBuffer
);
579 DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok
)));
581 DEBUG(0,("%s: command not found\n",CNV_LANG(tok
)));
584 cli_send_logout(InBuffer
,OutBuffer
);
588 /****************************************************************************
590 ****************************************************************************/
591 static void usage(char *pname
)
593 DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
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"));
613 /****************************************************************************
615 ****************************************************************************/
616 int main(int argc
,char *argv
[])
618 fstring base_directory
;
619 char *pname
= argv
[0];
625 BOOL nt_domain_logon
= False
;
626 static pstring servicesf
= CONFIGFILE
;
631 pstrcpy(term_code
, KANJI
);
641 setup_logging(pname
,True
);
644 charset_initialise();
646 pid
= (uint16
)getpid();
647 vuid
= (uint16
)getuid();
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
,'%')))
662 pstrcpy(password
,p
+1);
664 memset(strchr(getenv("USER"),'%')+1,'X',strlen(password
));
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"));
690 pstrcpy(service
, argv
[1]);
691 /* Convert any '/' characters in the service name to '\' characters */
692 string_replace( service
, '/','\\');
696 if (count_chars(service
,'\\') < 3)
699 printf("\n%s: Not enough '\\' characters in service\n",service
);
703 if (argc
> 1 && (*argv
[1] != '-'))
706 pstrcpy(password
,argv
[1]);
707 memset(argv
[1],'X',strlen(argv
[1]));
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
)
718 max_protocol
= interpret_protocol(optarg
,max_protocol
);
721 pstrcpy(user_socket_options
,optarg
);
724 pstrcpy(desthost
,optarg
);
726 nt_domain_logon
= True
;
729 iface_set_default(NULL
,optarg
,NULL
);
732 pstrcpy(base_directory
,optarg
);
735 pstrcpy(scope
,optarg
);
740 pstrcpy(username
,optarg
);
741 if ((lp
=strchr(username
,'%')))
744 pstrcpy(password
,lp
+1);
746 memset(strchr(optarg
,'%')+1,'X',strlen(password
));
752 pstrcpy(workgroup
,optarg
);
759 dest_ip
= *interpret_addr2(optarg
);
760 if (zero_ip(dest_ip
)) exit(1);
765 pstrcpy(global_myname
,optarg
);
774 DEBUGLEVEL
= atoi(optarg
);
777 slprintf(debugf
,sizeof(debugf
)-1,"%s.client",optarg
);
791 pstrcpy(servicesf
, optarg
);
794 pstrcpy(term_code
, optarg
);
801 if (!*query_host
&& !*service
)
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
);
824 pstrcpy(workgroup
,lp_workgroup());
827 get_myname((*global_myname
)?NULL
:global_myname
,NULL
);
828 strupper(global_myname
);
830 if (cli_open_sockets(port
))
832 if (!process(base_directory
))