2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1999
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.
27 #include <asm/types.h>
28 #include <linux/smb_fs.h>
30 /* Uncomment this to allow debug the mount.smb daemon */
31 /* WARNING! This option is incompatible with autofs/automount because
32 it does not close the stdout pipe back to the automount
33 process, which automount depends on. This will cause automount
34 to hang! Use with caution! */
35 /* #define SMBFS_DEBUG 1 */
37 extern struct in_addr ipzero;
38 extern int DEBUGLEVEL;
40 extern BOOL in_client;
41 extern pstring user_socket_options;
43 static pstring my_netbios_name;
44 static pstring password;
45 static pstring username;
46 static pstring workgroup;
47 static pstring mpoint;
48 static pstring service;
50 static struct in_addr dest_ip;
52 static int smb_port = 139;
54 static uid_t mount_uid;
55 static gid_t mount_gid;
57 static unsigned mount_fmask;
58 static unsigned mount_dmask;
60 static void usage(void);
62 static void exit_parent(int sig)
64 /* parent simply exits when child says go... */
68 static void daemonize(void)
73 signal( SIGTERM, exit_parent );
75 if ((child_pid = sys_fork()) < 0) {
76 fprintf(stderr,"could not fork\n");
81 j = waitpid( child_pid, &status, 0 );
83 if( EINTR == errno ) {
90 /* If we get here - the child exited with some error status */
94 signal( SIGTERM, SIG_DFL );
98 static void close_our_files(int client_fd)
101 for (i = 0; i < 256; i++) {
102 if (i == client_fd) continue;
107 static void usr1_handler(int x)
113 /*****************************************************
114 return a connection to a server
115 *******************************************************/
116 static struct cli_state *do_connection(char *service)
119 struct nmb_name called, calling;
122 extern struct in_addr ipzero;
126 if (service[0] != '\\' || service[1] != '\\') {
131 pstrcpy(server, service+2);
132 share = strchr(server,'\\');
144 make_nmb_name(&calling, my_netbios_name, 0x0);
145 make_nmb_name(&called , server, 0x20);
149 if (have_ip) ip = dest_ip;
151 /* have to open a new connection */
152 if (!(c=cli_initialise(NULL)) || (cli_set_port(c, smb_port) == 0) ||
153 !cli_connect(c, server_n, &ip)) {
154 fprintf(stderr,"Connection to %s failed\n", server_n);
158 if (!cli_session_request(c, &calling, &called)) {
159 fprintf(stderr, "session request to %s failed\n", called.name);
161 if (strcmp(called.name, "*SMBSERVER")) {
162 make_nmb_name(&called , "*SMBSERVER", 0x20);
168 DEBUG(4,(" session request ok\n"));
170 if (!cli_negprot(c)) {
171 fprintf(stderr, "protocol negotiation failed\n");
177 char *pass = getpass("Password: ");
179 pstrcpy(password, pass);
183 if (!cli_session_setup(c, username,
184 password, strlen(password),
185 password, strlen(password),
187 fprintf(stderr, "session setup failed: %s\n", cli_errstr(c));
191 DEBUG(4,(" session setup ok\n"));
193 if (!cli_send_tconX(c, share, "?????",
194 password, strlen(password)+1)) {
195 fprintf(stderr,"tree connect failed: %s\n", cli_errstr(c));
200 DEBUG(4,(" tconx ok\n"));
208 /****************************************************************************
209 unmount smbfs (this is a bailout routine to clean up if a reconnect fails)
210 Code blatently stolen from smbumount.c
212 ****************************************************************************/
213 static void smb_umount(char *mount_point)
221 This routine only gets called to the scene of a disaster
222 to shoot the survivors... A connection that was working
223 has now apparently failed. We have an active mount point
224 (presumably) that we need to dump. If we get errors along
225 the way - make some noise, but we are already turning out
226 the lights to exit anyways...
228 if (umount(mount_point) != 0) {
229 fprintf(stderr, "Could not umount %s: %s\n",
230 mount_point, strerror(errno));
234 if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) {
235 fprintf(stderr, "Can't get "MOUNTED"~ lock file");
241 if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
242 fprintf(stderr, "Can't open " MOUNTED ": %s\n",
247 #define MOUNTED_TMP MOUNTED".tmp"
249 if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
250 fprintf(stderr, "Can't open " MOUNTED_TMP ": %s\n",
256 while ((mnt = getmntent(mtab)) != NULL) {
257 if (strcmp(mnt->mnt_dir, mount_point) != 0) {
258 addmntent(new_mtab, mnt);
264 if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
265 fprintf(stderr, "Error changing mode of %s: %s\n",
266 MOUNTED_TMP, strerror(errno));
272 if (rename(MOUNTED_TMP, MOUNTED) < 0) {
273 fprintf(stderr, "Cannot rename %s to %s: %s\n",
274 MOUNTED, MOUNTED_TMP, strerror(errno));
278 if (unlink(MOUNTED"~") == -1) {
279 fprintf(stderr, "Can't remove "MOUNTED"~");
286 * Call the smbfs ioctl to install a connection socket,
287 * then wait for a signal to reconnect. Note that we do
288 * not exit after open_sockets() or send_login() errors,
289 * as the smbfs mount would then have no way to recover.
291 static void send_fs_socket(char *service, char *mount_point, struct cli_state *c)
293 int fd, closed = 0, res = 1;
294 pid_t parentpid = getppid();
295 struct smb_conn_opt conn_options;
297 memset(&conn_options, 0, sizeof(conn_options));
300 if ((fd = open(mount_point, O_RDONLY)) < 0) {
301 fprintf(stderr, "mount.smbfs: can't open %s\n", mount_point);
305 conn_options.fd = c->fd;
306 conn_options.protocol = c->protocol;
307 conn_options.case_handling = SMB_CASE_DEFAULT;
308 conn_options.max_xmit = c->max_xmit;
309 conn_options.server_uid = c->vuid;
310 conn_options.tid = c->cnum;
311 conn_options.secmode = c->sec_mode;
312 conn_options.rawmode = 0;
313 conn_options.sesskey = c->sesskey;
314 conn_options.maxraw = 0;
315 conn_options.capabilities = c->capabilities;
316 conn_options.serverzone = c->serverzone/60;
318 res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
320 fprintf(stderr, "mount.smbfs: ioctl failed, res=%d\n", res);
325 /* Ok... We are going to kill the parent. Now
326 is the time to break the process group... */
328 /* Send a signal to the parent to terminate */
329 kill(parentpid, SIGTERM);
336 /* Close all open files if we haven't done so yet. */
341 close_our_files(c?c->fd:-1);
345 /* Wait for a signal from smbfs ... */
346 CatchSignal(SIGUSR1, &usr1_handler);
349 DEBUG(2,("mount.smbfs: got signal, getting new socket\n"));
351 c = do_connection(service);
354 smb_umount(mount_point);
355 DEBUG(2,("mount.smbfs: exit\n"));
359 /*********************************************************
361 **********************************************************/
362 static char *xstrdup(char *s)
366 fprintf(stderr,"out of memory\n");
373 /****************************************************************************
375 ****************************************************************************/
376 static void init_mount(void)
378 char mount_point[MAXPATHLEN+1];
385 if (realpath(mpoint, mount_point) == NULL) {
386 fprintf(stderr, "Could not resolve mount point %s\n", mpoint);
391 c = do_connection(service);
393 fprintf(stderr,"SMB connection failed\n");
398 Set up to return as a daemon child and wait in the parent
399 until the child say it's ready...
403 pstrcpy(svc2, service);
404 string_replace(svc2, '\\','/');
405 string_replace(svc2, ' ','_');
407 memset(args, 0, sizeof(args[0])*20);
410 args[i++] = "smbmnt";
412 args[i++] = mount_point;
420 slprintf(tmp, sizeof(tmp), "%d", mount_uid);
422 args[i++] = xstrdup(tmp);
425 slprintf(tmp, sizeof(tmp), "%d", mount_gid);
427 args[i++] = xstrdup(tmp);
430 slprintf(tmp, sizeof(tmp), "0%o", mount_fmask);
432 args[i++] = xstrdup(tmp);
435 slprintf(tmp, sizeof(tmp), "0%o", mount_dmask);
437 args[i++] = xstrdup(tmp);
440 if (sys_fork() == 0) {
441 if (file_exist(BINDIR "/smbmnt", NULL)) {
442 execv(BINDIR "/smbmnt", args);
443 fprintf(stderr,"execv of %s failed. Error was %s.", BINDIR "/smbmnt", strerror(errno));
445 execvp("smbmnt", args);
446 fprintf(stderr,"execvp of smbmnt failed. Error was %s.", strerror(errno) );
451 if (waitpid(-1, &status, 0) == -1) {
452 fprintf(stderr,"waitpid failed: Error was %s", strerror(errno) );
453 /* FIXME: do some proper error handling */
457 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
458 fprintf(stderr,"smbmnt failed: %d\n", WEXITSTATUS(status));
461 /* Ok... This is the rubicon for that mount point... At any point
462 after this, if the connections fail and can not be reconstructed
463 for any reason, we will have to unmount the mount point. There
464 is no exit from the next call...
466 send_fs_socket(service, mount_point, c);
470 /****************************************************************************
472 ****************************************************************************/
473 static void usage(void)
475 printf("Usage: mount.smbfs service mountpoint [-o options,...]\n");
477 printf("Version %s\n\n",VERSION);
481 username=<arg> SMB username
482 password=<arg> SMB password
483 netbiosname=<arg> source NetBIOS name
484 uid=<arg> mount uid or username
485 gid=<arg> mount gid or groupname
486 port=<arg> remote SMB port number
487 fmask=<arg> file umask
488 dmask=<arg> directory umask
489 debug=<arg> debug level
490 ip=<arg> destination host or IP address
491 workgroup=<arg> workgroup on destination
492 sockopt=<arg> TCP socket options
493 scope=<arg> NetBIOS scope
494 guest don't prompt for a password
498 This command is designed to be run from within /bin/mount by giving
499 the option '-t smbfs'. For example:
500 mount -t smbfs -o username=tridge,password=foobar //fjall/test /data/test
505 /****************************************************************************
506 Argument parsing for mount.smbfs interface
507 mount will call us like this:
508 mount.smbfs device mountpoint -o <options>
510 <options> is never empty, containing at least rw or ro
511 ****************************************************************************/
512 static void parse_mount_smb(int argc, char **argv)
519 extern pstring global_scope;
521 if (argc < 2 || argv[1][0] == '-') {
526 pstrcpy(service, argv[1]);
527 pstrcpy(mpoint, argv[2]);
529 /* Convert any '/' characters in the service name to
531 string_replace(service, '/','\\');
535 opt = getopt(argc, argv, "o:");
541 * option parsing from nfsmount.c (util-linux-2.9u)
543 for (opts = strtok(optarg, ","); opts; opts = strtok(NULL, ",")) {
544 DEBUG(3, ("opts: %s\n", opts));
545 if ((opteq = strchr(opts, '='))) {
546 val = atoi(opteq + 1);
549 if (!strcmp(opts, "username") ||
550 !strcmp(opts, "logon")) {
552 pstrcpy(username,opteq+1);
553 if ((lp=strchr(username,'%'))) {
555 pstrcpy(password,lp+1);
557 memset(strchr(opteq+1,'%')+1,'X',strlen(password));
559 if ((lp=strchr(username,'/'))) {
561 pstrcpy(workgroup,lp+1);
563 } else if(!strcmp(opts, "passwd") ||
564 !strcmp(opts, "password")) {
565 pstrcpy(password,opteq+1);
567 memset(opteq+1,'X',strlen(password));
568 } else if(!strcmp(opts, "netbiosname")) {
569 pstrcpy(my_netbios_name,opteq+1);
570 } else if(!strcmp(opts, "uid")) {
571 mount_uid = nametouid(opteq+1);
572 } else if(!strcmp(opts, "gid")) {
573 mount_gid = nametogid(opteq+1);
574 } else if(!strcmp(opts, "port")) {
576 } else if(!strcmp(opts, "fmask")) {
577 mount_fmask = strtol(opteq+1, NULL, 8);
578 } else if(!strcmp(opts, "dmask")) {
579 mount_dmask = strtol(opteq+1, NULL, 8);
580 } else if(!strcmp(opts, "debug")) {
582 } else if(!strcmp(opts, "ip")) {
583 dest_ip = *interpret_addr2(opteq+1);
584 if (zero_ip(dest_ip)) {
585 fprintf(stderr,"Can't resolve address %s\n", opteq+1);
589 } else if(!strcmp(opts, "workgroup")) {
590 pstrcpy(workgroup,opteq+1);
591 } else if(!strcmp(opts, "sockopt")) {
592 pstrcpy(user_socket_options,opteq+1);
593 } else if(!strcmp(opts, "scope")) {
594 pstrcpy(global_scope,opteq+1);
601 if(!strcmp(opts, "nocaps")) {
602 fprintf(stderr, "Unhandled option: %s\n", opteq+1);
604 } else if(!strcmp(opts, "guest")) {
606 } else if(!strcmp(opts, "rw")) {
608 } else if(!strcmp(opts, "ro")) {
620 /****************************************************************************
622 ****************************************************************************/
623 int main(int argc,char *argv[])
627 static pstring servicesf = CONFIGFILE;
632 setup_logging("mount.smbfs",True);
635 charset_initialise();
637 in_client = True; /* Make sure that we tell lp_load we are */
639 if (getenv("USER")) {
640 pstrcpy(username,getenv("USER"));
642 if ((p=strchr(username,'%'))) {
644 pstrcpy(password,p+1);
649 if (getenv("PASSWD")) {
650 pstrcpy(password,getenv("PASSWD"));
653 if (*username == 0 && getenv("LOGNAME")) {
654 pstrcpy(username,getenv("LOGNAME"));
657 parse_mount_smb(argc, argv);
659 DEBUG(3,("mount.smbfs started (version %s)\n", VERSION));
661 if (!lp_load(servicesf,True,False,False)) {
662 fprintf(stderr, "Can't load %s - run testparm to debug it\n",
666 codepage_initialise(lp_client_code_page());
668 if (*workgroup == 0) {
669 pstrcpy(workgroup,lp_workgroup());
673 if (!*my_netbios_name) {
674 pstrcpy(my_netbios_name, myhostname());
676 strupper(my_netbios_name);