2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1999
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "system/passwd.h"
24 #include <asm/types.h>
25 #include <linux/smb_fs.h>
27 static pstring credentials;
28 static pstring my_netbios_name;
29 static pstring password;
30 static pstring username;
31 static pstring workgroup;
32 static pstring mpoint;
33 static pstring service;
34 static pstring options;
36 static struct in_addr dest_ip;
38 static int smb_port = 0;
41 static uid_t mount_uid;
42 static gid_t mount_gid;
44 static uint_t mount_fmask;
45 static uint_t mount_dmask;
46 static bool use_kerberos;
47 /* TODO: Add code to detect smbfs version in kernel */
48 static bool status32_smbfs = false;
50 static void usage(void);
52 static void exit_parent(int sig)
54 /* parent simply exits when child says go... */
58 static void daemonize(void)
63 signal( SIGTERM, exit_parent );
65 if ((child_pid = sys_fork()) < 0) {
66 DEBUG(0,("could not fork\n"));
71 j = waitpid( child_pid, &status, 0 );
73 if( EINTR == errno ) {
81 /* If we get here - the child exited with some error status */
82 if (WIFSIGNALED(status))
83 exit(128 + WTERMSIG(status));
85 exit(WEXITSTATUS(status));
88 signal( SIGTERM, SIG_DFL );
92 static void close_our_files(int client_fd)
97 getrlimit(RLIMIT_NOFILE,&limits);
98 for (i = 0; i< limits.rlim_max; i++) {
105 static void usr1_handler(int x)
111 /*****************************************************
112 return a connection to a server
113 *******************************************************/
114 static struct smbcli_state *do_connection(const char *the_service, bool unicode, int maxprotocol)
116 struct smbcli_state *c;
117 struct nmb_name called, calling;
123 if (the_service[0] != '\\' || the_service[1] != '\\') {
128 pstrcpy(server, the_service+2);
129 share = strchr_m(server,'\\');
139 make_nmb_name(&calling, my_netbios_name, 0x0);
140 choose_called_name(&called, server, 0x20);
144 if (have_ip) ip = dest_ip;
146 /* have to open a new connection */
147 if (!(c=smbcli_initialise(NULL)) || (smbcli_set_port(c, smb_port) != smb_port) ||
148 !smbcli_connect(c, server_n, &ip)) {
149 DEBUG(0,("%d: Connection to %s failed\n", sys_getpid(), server_n));
156 /* SPNEGO doesn't work till we get NTSTATUS error support */
157 /* But it is REQUIRED for kerberos authentication */
158 if(!use_kerberos) c->use_spnego = false;
160 /* The kernel doesn't yet know how to sign it's packets */
161 c->sign_info.allow_smb_signing = false;
163 /* Use kerberos authentication if specified */
164 c->use_kerberos = use_kerberos;
166 if (!smbcli_session_request(c, &calling, &called)) {
168 DEBUG(0,("%d: session request to %s failed (%s)\n",
169 sys_getpid(), called.name, smbcli_errstr(c)));
171 if ((p=strchr_m(called.name, '.'))) {
175 if (strcmp(called.name, "*SMBSERVER")) {
176 make_nmb_name(&called , "*SMBSERVER", 0x20);
182 DEBUG(4,("%d: session request ok\n", sys_getpid()));
184 if (!smbcli_negprot(c, unicode, maxprotocol)) {
185 DEBUG(0,("%d: protocol negotiation failed\n", sys_getpid()));
191 char *pass = getpass("Password: ");
193 pstrcpy(password, pass);
197 /* This should be right for current smbfs. Future versions will support
198 large files as well as unicode and oplocks. */
199 if (status32_smbfs) {
200 c->capabilities &= ~(CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
201 CAP_NT_FIND | CAP_LEVEL_II_OPLOCKS);
204 c->capabilities &= ~(CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
205 CAP_NT_FIND | CAP_STATUS32 |
206 CAP_LEVEL_II_OPLOCKS);
207 c->force_dos_errors = true;
210 if (!smbcli_session_setup(c, username,
211 password, strlen(password),
212 password, strlen(password),
214 /* if a password was not supplied then try again with a
216 if (password[0] || !username[0] ||
217 !smbcli_session_setup(c, "", "", 0, "", 0, workgroup)) {
218 DEBUG(0,("%d: session setup failed: %s\n",
219 sys_getpid(), smbcli_errstr(c)));
223 DEBUG(0,("Anonymous login successful\n"));
226 DEBUG(4,("%d: session setup ok\n", sys_getpid()));
228 if (!smbcli_tconX(c, share, "?????", password, strlen(password)+1)) {
229 DEBUG(0,("%d: tree connect failed: %s\n",
230 sys_getpid(), smbcli_errstr(c)));
235 DEBUG(4,("%d: tconx ok\n", sys_getpid()));
243 /****************************************************************************
244 unmount smbfs (this is a bailout routine to clean up if a reconnect fails)
245 Code blatently stolen from smbumount.c
247 ****************************************************************************/
248 static void smb_umount(char *mount_point)
256 This routine only gets called to the scene of a disaster
257 to shoot the survivors... A connection that was working
258 has now apparently failed. We have an active mount point
259 (presumably) that we need to dump. If we get errors along
260 the way - make some noise, but we are already turning out
261 the lights to exit anyways...
263 if (umount(mount_point) != 0) {
264 DEBUG(0,("%d: Could not umount %s: %s\n",
265 sys_getpid(), mount_point, strerror(errno)));
269 if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) {
270 DEBUG(0,("%d: Can't get "MOUNTED"~ lock file", sys_getpid()));
276 if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
277 DEBUG(0,("%d: Can't open " MOUNTED ": %s\n",
278 sys_getpid(), strerror(errno)));
282 #define MOUNTED_TMP MOUNTED".tmp"
284 if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
285 DEBUG(0,("%d: Can't open " MOUNTED_TMP ": %s\n",
286 sys_getpid(), strerror(errno)));
291 while ((mnt = getmntent(mtab)) != NULL) {
292 if (strcmp(mnt->mnt_dir, mount_point) != 0) {
293 addmntent(new_mtab, mnt);
299 if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
300 DEBUG(0,("%d: Error changing mode of %s: %s\n",
301 sys_getpid(), MOUNTED_TMP, strerror(errno)));
307 if (rename(MOUNTED_TMP, MOUNTED) < 0) {
308 DEBUG(0,("%d: Cannot rename %s to %s: %s\n",
309 sys_getpid(), MOUNTED, MOUNTED_TMP, strerror(errno)));
313 if (unlink(MOUNTED"~") == -1) {
314 DEBUG(0,("%d: Can't remove "MOUNTED"~", sys_getpid()));
321 * Call the smbfs ioctl to install a connection socket,
322 * then wait for a signal to reconnect. Note that we do
323 * not exit after open_sockets() or send_login() errors,
324 * as the smbfs mount would then have no way to recover.
326 static void send_fs_socket(const char *the_service, char *mount_point, struct smbcli_state *c)
328 int fd, closed = 0, res = 1;
329 pid_t parentpid = getppid();
330 struct smb_conn_opt conn_options;
332 memset(&conn_options, 0, sizeof(conn_options));
335 if ((fd = open(mount_point, O_RDONLY)) < 0) {
336 DEBUG(0,("mount.smbfs[%d]: can't open %s\n",
337 sys_getpid(), mount_point));
341 conn_options.fd = c->fd;
342 conn_options.protocol = c->protocol;
343 conn_options.case_handling = SMB_CASE_DEFAULT;
344 conn_options.max_xmit = c->max_xmit;
345 conn_options.server_uid = c->vuid;
346 conn_options.tid = c->cnum;
347 conn_options.secmode = c->sec_mode;
348 conn_options.rawmode = 0;
349 conn_options.sesskey = c->sesskey;
350 conn_options.maxraw = 0;
351 conn_options.capabilities = c->capabilities;
352 conn_options.serverzone = c->serverzone/60;
354 res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
356 DEBUG(0,("mount.smbfs[%d]: ioctl failed, res=%d\n",
363 /* Ok... We are going to kill the parent. Now
364 is the time to break the process group... */
366 /* Send a signal to the parent to terminate */
367 kill(parentpid, SIGTERM);
373 /* This looks wierd but we are only closing the userspace
374 side, the connection has already been passed to smbfs and
375 it has increased the usage count on the socket.
377 If we don't do this we will "leak" sockets and memory on
378 each reconnection we have to make. */
383 /* redirect stdout & stderr since we can't know that
384 the library functions we use are using DEBUG. */
385 if ( (fd = open("/dev/null", O_WRONLY)) < 0)
386 DEBUG(2,("mount.smbfs: can't open /dev/null\n"));
389 dup2(fd, STDOUT_FILENO);
390 dup2(fd, STDERR_FILENO);
394 /* here we are no longer interactive */
395 set_remote_machine_name("smbmount"); /* sneaky ... */
396 setup_logging("mount.smbfs", DEBUG_STDERR);
398 DEBUG(0, ("mount.smbfs: entering daemon mode for service %s, pid=%d\n", the_service, sys_getpid()));
403 /* Wait for a signal from smbfs ... but don't continue
404 until we actually get a new connection. */
406 CatchSignal(SIGUSR1, &usr1_handler);
408 DEBUG(2,("mount.smbfs[%d]: got signal, getting new socket\n", sys_getpid()));
409 c = do_connection(the_service, lp_unicode(global_loadparm), lp_cli_maxprotocol(global_loadparm));
413 smb_umount(mount_point);
414 DEBUG(2,("mount.smbfs[%d]: exit\n", sys_getpid()));
422 static void init_mount(void)
424 char mount_point[MAXPATHLEN+1];
427 struct smbcli_state *c;
431 if (realpath(mpoint, mount_point) == NULL) {
432 fprintf(stderr, "Could not resolve mount point %s\n", mpoint);
437 c = do_connection(service, lp_unicode(global_loadparm), lp_cli_maxprotocol(global_loadparm));
439 fprintf(stderr,"SMB connection failed\n");
444 Set up to return as a daemon child and wait in the parent
445 until the child say it's ready...
449 pstrcpy(svc2, service);
450 string_replace(svc2, '\\','/');
451 string_replace(svc2, ' ','_');
453 memset(args, 0, sizeof(args[0])*20);
456 args[i++] = "smbmnt";
458 args[i++] = mount_point;
466 slprintf(tmp, sizeof(tmp)-1, "%d", mount_uid);
468 args[i++] = smb_xstrdup(tmp);
471 slprintf(tmp, sizeof(tmp)-1, "%d", mount_gid);
473 args[i++] = smb_xstrdup(tmp);
476 slprintf(tmp, sizeof(tmp)-1, "0%o", mount_fmask);
478 args[i++] = smb_xstrdup(tmp);
481 slprintf(tmp, sizeof(tmp)-1, "0%o", mount_dmask);
483 args[i++] = smb_xstrdup(tmp);
490 if (sys_fork() == 0) {
493 asprintf(&smbmnt_path, "%s/smbmnt", dyn_BINDIR);
495 if (file_exist(smbmnt_path)) {
496 execv(smbmnt_path, args);
498 "smbfs/init_mount: execv of %s failed. Error was %s.",
499 smbmnt_path, strerror(errno));
501 execvp("smbmnt", args);
503 "smbfs/init_mount: execv of %s failed. Error was %s.",
504 "smbmnt", strerror(errno));
510 if (waitpid(-1, &status, 0) == -1) {
511 fprintf(stderr,"waitpid failed: Error was %s", strerror(errno) );
512 /* FIXME: do some proper error handling */
516 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
517 fprintf(stderr,"smbmnt failed: %d\n", WEXITSTATUS(status));
518 /* FIXME: do some proper error handling */
520 } else if (WIFSIGNALED(status)) {
521 fprintf(stderr, "smbmnt killed by signal %d\n", WTERMSIG(status));
525 /* Ok... This is the rubicon for that mount point... At any point
526 after this, if the connections fail and can not be reconstructed
527 for any reason, we will have to unmount the mount point. There
528 is no exit from the next call...
530 send_fs_socket(service, mount_point, c);
534 /****************************************************************************
535 get a password from a a file or file descriptor
536 exit on failure (from smbclient, move to libsmb or shared .c file?)
537 ****************************************************************************/
538 static void get_password_file(void)
542 bool close_it = false;
546 if ((p = getenv("PASSWD_FD")) != NULL) {
547 pstrcpy(spec, "descriptor ");
549 sscanf(p, "%d", &fd);
551 } else if ((p = getenv("PASSWD_FILE")) != NULL) {
552 fd = open(p, O_RDONLY, 0);
555 fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
556 spec, strerror(errno));
562 for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
563 p && p - pass < sizeof(pass);) {
564 switch (read(fd, p, 1)) {
566 if (*p != '\n' && *p != '\0') {
567 *++p = '\0'; /* advance p, and null-terminate pass */
572 *p = '\0'; /* null-terminate it, just in case... */
573 p = NULL; /* then force the loop condition to become false */
576 fprintf(stderr, "Error reading password from file %s: %s\n",
577 spec, "empty password\n");
582 fprintf(stderr, "Error reading password from file %s: %s\n",
583 spec, strerror(errno));
587 pstrcpy(password, pass);
592 /****************************************************************************
593 get username and password from a credentials file
594 exit on failure (from smbclient, move to libsmb or shared .c file?)
595 ****************************************************************************/
596 static void read_credentials_file(char *filename)
601 char *ptr, *val, *param;
603 if ((auth=sys_fopen(filename, "r")) == NULL)
605 /* fail if we can't open the credentials file */
606 DEBUG(0,("ERROR: Unable to open credentials file!\n"));
612 /* get a line from the file */
613 if (!fgets (buf, sizeof(buf), auth))
617 if ((len) && (buf[len-1]=='\n'))
625 /* break up the line into parameter & value.
626 will need to eat a little whitespace possibly */
628 if (!(ptr = strchr (buf, '=')))
633 /* eat leading white space */
634 while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
637 if (strwicmp("password", param) == 0)
639 pstrcpy(password, val);
642 else if (strwicmp("username", param) == 0) {
643 pstrcpy(username, val);
646 memset(buf, 0, sizeof(buf));
652 /****************************************************************************
654 ****************************************************************************/
655 static void usage(void)
657 printf("Usage: mount.smbfs service mountpoint [-o options,...]\n");
659 printf("Version %s\n\n",VERSION);
663 username=<arg> SMB username\n\
664 password=<arg> SMB password\n\
665 credentials=<filename> file with username/password\n\
666 krb use kerberos (active directory)\n\
667 netbiosname=<arg> source NetBIOS name\n\
668 uid=<arg> mount uid or username\n\
669 gid=<arg> mount gid or groupname\n\
670 port=<arg> remote SMB port number\n\
671 fmask=<arg> file umask\n\
672 dmask=<arg> directory umask\n\
673 debug=<arg> debug level\n\
674 ip=<arg> destination host or IP address\n\
675 workgroup=<arg> workgroup on destination\n\
676 sockopt=<arg> TCP socket options\n\
677 scope=<arg> NetBIOS scope\n\
678 iocharset=<arg> Linux charset (iso8859-1, utf8)\n\
679 codepage=<arg> server codepage (cp850)\n\
680 ttl=<arg> dircache time to live\n\
681 guest don't prompt for a password\n\
682 ro mount read-only\n\
683 rw mount read-write\n\
685 This command is designed to be run from within /bin/mount by giving\n\
686 the option '-t smbfs'. For example:\n\
687 mount -t smbfs -o username=tridge,password=foobar //fjall/test /data/test\n\
692 /****************************************************************************
693 Argument parsing for mount.smbfs interface
694 mount will call us like this:
695 mount.smbfs device mountpoint -o <options>
697 <options> is never empty, containing at least rw or ro
698 ****************************************************************************/
699 static void parse_mount_smb(int argc, char **argv)
708 /* FIXME: This function can silently fail if the arguments are
709 * not in the expected order.
711 > The arguments syntax of smbmount 2.2.3a (smbfs of Debian stable)
712 > requires that one gives "-o" before further options like username=...
713 > . Without -o, the username=.. setting is *silently* ignored. I've
714 > spent about an hour trying to find out why I couldn't log in now..
719 if (argc < 2 || argv[1][0] == '-') {
724 pstrcpy(service, argv[1]);
725 pstrcpy(mpoint, argv[2]);
727 /* Convert any '/' characters in the service name to
729 string_replace(service, '/','\\');
733 opt = getopt(argc, argv, "o:");
742 * option parsing from nfsmount.c (util-linux-2.9u)
744 for (opts = strtok(optarg, ","); opts; opts = strtok(NULL, ",")) {
745 DEBUG(3, ("opts: %s\n", opts));
746 if ((opteq = strchr_m(opts, '='))) {
747 val = atoi(opteq + 1);
750 if (!strcmp(opts, "username") ||
751 !strcmp(opts, "logon")) {
754 pstrcpy(username,opteq+1);
755 if ((lp=strchr_m(username,'%'))) {
757 pstrcpy(password,lp+1);
759 memset(strchr_m(opteq+1,'%')+1,'X',strlen(password));
761 if ((lp=strchr_m(username,'/'))) {
763 pstrcpy(workgroup,lp+1);
765 } else if(!strcmp(opts, "passwd") ||
766 !strcmp(opts, "password")) {
767 pstrcpy(password,opteq+1);
769 memset(opteq+1,'X',strlen(password));
770 } else if(!strcmp(opts, "credentials")) {
771 pstrcpy(credentials,opteq+1);
772 } else if(!strcmp(opts, "netbiosname")) {
773 pstrcpy(my_netbios_name,opteq+1);
774 } else if(!strcmp(opts, "uid")) {
775 mount_uid = nametouid(opteq+1);
776 } else if(!strcmp(opts, "gid")) {
777 mount_gid = nametogid(opteq+1);
778 } else if(!strcmp(opts, "port")) {
780 } else if(!strcmp(opts, "fmask")) {
781 mount_fmask = strtol(opteq+1, NULL, 8);
782 } else if(!strcmp(opts, "dmask")) {
783 mount_dmask = strtol(opteq+1, NULL, 8);
784 } else if(!strcmp(opts, "debug")) {
786 } else if(!strcmp(opts, "ip")) {
787 dest_ip = interpret_addr2(opteq+1);
788 if (is_zero_ip(dest_ip)) {
789 fprintf(stderr,"Can't resolve address %s\n", opteq+1);
793 } else if(!strcmp(opts, "workgroup")) {
794 pstrcpy(workgroup,opteq+1);
795 } else if(!strcmp(opts, "sockopt")) {
796 lp_set_cmdline("socket options", opteq+1);
797 } else if(!strcmp(opts, "scope")) {
798 lp_set_cmdline("netbios scope", opteq+1);
800 slprintf(p, sizeof(pstring) - (p - options) - 1, "%s=%s,", opts, opteq+1);
805 if(!strcmp(opts, "nocaps")) {
806 fprintf(stderr, "Unhandled option: %s\n", opteq+1);
808 } else if(!strcmp(opts, "guest")) {
811 } else if(!strcmp(opts, "krb")) {
816 fprintf(stderr, "Warning: kerberos support will only work for samba servers\n");
818 fprintf(stderr,"No kerberos support compiled in\n");
821 } else if(!strcmp(opts, "rw")) {
823 } else if(!strcmp(opts, "ro")) {
826 strncpy(p, opts, sizeof(pstring) - (p - options) - 1);
840 *(p-1) = 0; /* remove trailing , */
841 DEBUG(3,("passthrough options '%s'\n", options));
845 /****************************************************************************
847 ****************************************************************************/
848 int main(int argc,char *argv[])
856 /* here we are interactive, even if run from autofs */
857 setup_logging("mount.smbfs",DEBUG_STDERR);
859 #if 0 /* JRA - Urban says not needed ? */
860 /* CLI_FORCE_ASCII=false makes smbmount negotiate unicode. The default
861 is to not announce any unicode capabilities as current smbfs does
863 p = getenv("CLI_FORCE_ASCII");
864 if (p && !strcmp(p, "false"))
865 unsetenv("CLI_FORCE_ASCII");
867 setenv("CLI_FORCE_ASCII", "true", 1);
870 if (getenv("USER")) {
871 pstrcpy(username,getenv("USER"));
873 if ((p=strchr_m(username,'%'))) {
875 pstrcpy(password,p+1);
877 memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(password));
882 if (getenv("PASSWD")) {
883 pstrcpy(password,getenv("PASSWD"));
887 if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
892 if (*username == 0 && getenv("LOGNAME")) {
893 pstrcpy(username,getenv("LOGNAME"));
896 if (!lp_load(dyn_CONFIGFILE)) {
897 fprintf(stderr, "Can't load %s - run testparm to debug it\n",
901 parse_mount_smb(argc, argv);
903 if (use_kerberos && !got_user) {
907 if (*credentials != 0) {
908 read_credentials_file(credentials);
911 DEBUG(3,("mount.smbfs started (version %s)\n", VERSION));
913 if (*workgroup == 0) {
914 pstrcpy(workgroup, lp_workgroup());
917 if (!*my_netbios_name) {
918 pstrcpy(my_netbios_name, myhostname());
920 strupper(my_netbios_name);