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,
115 struct smbcli_session_options session_options)
117 struct smbcli_state *c;
118 struct nmb_name called, calling;
124 if (the_service[0] != '\\' || the_service[1] != '\\') {
129 pstrcpy(server, the_service+2);
130 share = strchr_m(server,'\\');
140 make_nmb_name(&calling, my_netbios_name, 0x0);
141 choose_called_name(&called, server, 0x20);
145 if (have_ip) ip = dest_ip;
147 /* have to open a new connection */
148 if (!(c=smbcli_initialise(NULL)) || (smbcli_set_port(c, smb_port) != smb_port) ||
149 !smbcli_connect(c, server_n, &ip)) {
150 DEBUG(0,("%d: Connection to %s failed\n", sys_getpid(), server_n));
157 /* SPNEGO doesn't work till we get NTSTATUS error support */
158 /* But it is REQUIRED for kerberos authentication */
159 if(!use_kerberos) c->use_spnego = false;
161 /* The kernel doesn't yet know how to sign it's packets */
162 c->sign_info.allow_smb_signing = false;
164 /* Use kerberos authentication if specified */
165 c->use_kerberos = use_kerberos;
167 if (!smbcli_session_request(c, &calling, &called)) {
169 DEBUG(0,("%d: session request to %s failed (%s)\n",
170 sys_getpid(), called.name, smbcli_errstr(c)));
172 if ((p=strchr_m(called.name, '.'))) {
176 if (strcmp(called.name, "*SMBSERVER")) {
177 make_nmb_name(&called , "*SMBSERVER", 0x20);
183 DEBUG(4,("%d: session request ok\n", sys_getpid()));
185 if (!smbcli_negprot(c, unicode, maxprotocol)) {
186 DEBUG(0,("%d: protocol negotiation failed\n", sys_getpid()));
192 char *pass = getpass("Password: ");
194 pstrcpy(password, pass);
198 /* This should be right for current smbfs. Future versions will support
199 large files as well as unicode and oplocks. */
200 if (status32_smbfs) {
201 c->capabilities &= ~(CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
202 CAP_NT_FIND | CAP_LEVEL_II_OPLOCKS);
205 c->capabilities &= ~(CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
206 CAP_NT_FIND | CAP_STATUS32 |
207 CAP_LEVEL_II_OPLOCKS);
208 c->force_dos_errors = true;
211 if (!smbcli_session_setup(c, username,
212 password, strlen(password),
213 password, strlen(password),
214 workgroup, session_options)) {
215 /* if a password was not supplied then try again with a
217 if (password[0] || !username[0] ||
218 !smbcli_session_setup(c, "", "", 0, "", 0, workgroup,
220 DEBUG(0,("%d: session setup failed: %s\n",
221 sys_getpid(), smbcli_errstr(c)));
225 DEBUG(0,("Anonymous login successful\n"));
228 DEBUG(4,("%d: session setup ok\n", sys_getpid()));
230 if (!smbcli_tconX(c, share, "?????", password, strlen(password)+1)) {
231 DEBUG(0,("%d: tree connect failed: %s\n",
232 sys_getpid(), smbcli_errstr(c)));
237 DEBUG(4,("%d: tconx ok\n", sys_getpid()));
245 /****************************************************************************
246 unmount smbfs (this is a bailout routine to clean up if a reconnect fails)
247 Code blatently stolen from smbumount.c
249 ****************************************************************************/
250 static void smb_umount(const char *mount_point)
258 This routine only gets called to the scene of a disaster
259 to shoot the survivors... A connection that was working
260 has now apparently failed. We have an active mount point
261 (presumably) that we need to dump. If we get errors along
262 the way - make some noise, but we are already turning out
263 the lights to exit anyways...
265 if (umount(mount_point) != 0) {
266 DEBUG(0,("%d: Could not umount %s: %s\n",
267 sys_getpid(), mount_point, strerror(errno)));
271 if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) {
272 DEBUG(0,("%d: Can't get "MOUNTED"~ lock file", sys_getpid()));
278 if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
279 DEBUG(0,("%d: Can't open " MOUNTED ": %s\n",
280 sys_getpid(), strerror(errno)));
284 #define MOUNTED_TMP MOUNTED".tmp"
286 if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
287 DEBUG(0,("%d: Can't open " MOUNTED_TMP ": %s\n",
288 sys_getpid(), strerror(errno)));
293 while ((mnt = getmntent(mtab)) != NULL) {
294 if (strcmp(mnt->mnt_dir, mount_point) != 0) {
295 addmntent(new_mtab, mnt);
301 if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
302 DEBUG(0,("%d: Error changing mode of %s: %s\n",
303 sys_getpid(), MOUNTED_TMP, strerror(errno)));
309 if (rename(MOUNTED_TMP, MOUNTED) < 0) {
310 DEBUG(0,("%d: Cannot rename %s to %s: %s\n",
311 sys_getpid(), MOUNTED, MOUNTED_TMP, strerror(errno)));
315 if (unlink(MOUNTED"~") == -1) {
316 DEBUG(0,("%d: Can't remove "MOUNTED"~", sys_getpid()));
323 * Call the smbfs ioctl to install a connection socket,
324 * then wait for a signal to reconnect. Note that we do
325 * not exit after open_sockets() or send_login() errors,
326 * as the smbfs mount would then have no way to recover.
328 static void send_fs_socket(struct loadparm_context *lp_ctx,
329 const char *the_service, const char *mount_point, struct smbcli_state *c)
331 int fd, closed = 0, res = 1;
332 pid_t parentpid = getppid();
333 struct smb_conn_opt conn_options;
334 struct smbcli_session_options session_options;
336 lp_smbcli_session_options(lp_ctx, &session_options);
338 memset(&conn_options, 0, sizeof(conn_options));
341 if ((fd = open(mount_point, O_RDONLY)) < 0) {
342 DEBUG(0,("mount.smbfs[%d]: can't open %s\n",
343 sys_getpid(), mount_point));
347 conn_options.fd = c->fd;
348 conn_options.protocol = c->protocol;
349 conn_options.case_handling = SMB_CASE_DEFAULT;
350 conn_options.max_xmit = c->max_xmit;
351 conn_options.server_uid = c->vuid;
352 conn_options.tid = c->cnum;
353 conn_options.secmode = c->sec_mode;
354 conn_options.rawmode = 0;
355 conn_options.sesskey = c->sesskey;
356 conn_options.maxraw = 0;
357 conn_options.capabilities = c->capabilities;
358 conn_options.serverzone = c->serverzone/60;
360 res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
362 DEBUG(0,("mount.smbfs[%d]: ioctl failed, res=%d\n",
369 /* Ok... We are going to kill the parent. Now
370 is the time to break the process group... */
372 /* Send a signal to the parent to terminate */
373 kill(parentpid, SIGTERM);
379 /* This looks wierd but we are only closing the userspace
380 side, the connection has already been passed to smbfs and
381 it has increased the usage count on the socket.
383 If we don't do this we will "leak" sockets and memory on
384 each reconnection we have to make. */
389 /* redirect stdout & stderr since we can't know that
390 the library functions we use are using DEBUG. */
391 if ( (fd = open("/dev/null", O_WRONLY)) < 0)
392 DEBUG(2,("mount.smbfs: can't open /dev/null\n"));
395 dup2(fd, STDOUT_FILENO);
396 dup2(fd, STDERR_FILENO);
400 /* here we are no longer interactive */
401 set_remote_machine_name("smbmount"); /* sneaky ... */
402 setup_logging("mount.smbfs", DEBUG_STDERR);
404 DEBUG(0, ("mount.smbfs: entering daemon mode for service %s, pid=%d\n", the_service, sys_getpid()));
409 /* Wait for a signal from smbfs ... but don't continue
410 until we actually get a new connection. */
412 CatchSignal(SIGUSR1, &usr1_handler);
414 DEBUG(2,("mount.smbfs[%d]: got signal, getting new socket\n", sys_getpid()));
415 c = do_connection(the_service,
417 lp_cli_maxprotocol(lp_ctx),
422 smb_umount(mount_point);
423 DEBUG(2,("mount.smbfs[%d]: exit\n", sys_getpid()));
431 static void init_mount(struct loadparm_context *lp_ctx)
433 char mount_point[MAXPATHLEN+1];
436 struct smbcli_state *c;
439 struct smbcli_session_options session_options;
441 if (realpath(mpoint, mount_point) == NULL) {
442 fprintf(stderr, "Could not resolve mount point %s\n", mpoint);
446 lp_smbcli_session_options(lp_ctx, &session_options);
448 c = do_connection(service, lp_unicode(lp_ctx), lp_cli_maxprotocol(lp_ctx),
451 fprintf(stderr,"SMB connection failed\n");
456 Set up to return as a daemon child and wait in the parent
457 until the child say it's ready...
461 pstrcpy(svc2, service);
462 string_replace(svc2, '\\','/');
463 string_replace(svc2, ' ','_');
465 memset(args, 0, sizeof(args[0])*20);
468 args[i++] = "smbmnt";
470 args[i++] = mount_point;
478 slprintf(tmp, sizeof(tmp)-1, "%d", mount_uid);
480 args[i++] = smb_xstrdup(tmp);
483 slprintf(tmp, sizeof(tmp)-1, "%d", mount_gid);
485 args[i++] = smb_xstrdup(tmp);
488 slprintf(tmp, sizeof(tmp)-1, "0%o", mount_fmask);
490 args[i++] = smb_xstrdup(tmp);
493 slprintf(tmp, sizeof(tmp)-1, "0%o", mount_dmask);
495 args[i++] = smb_xstrdup(tmp);
502 if (sys_fork() == 0) {
505 asprintf(&smbmnt_path, "%s/smbmnt", dyn_BINDIR);
507 if (file_exist(smbmnt_path)) {
508 execv(smbmnt_path, args);
510 "smbfs/init_mount: execv of %s failed. Error was %s.",
511 smbmnt_path, strerror(errno));
513 execvp("smbmnt", args);
515 "smbfs/init_mount: execv of %s failed. Error was %s.",
516 "smbmnt", strerror(errno));
522 if (waitpid(-1, &status, 0) == -1) {
523 fprintf(stderr,"waitpid failed: Error was %s", strerror(errno) );
524 /* FIXME: do some proper error handling */
528 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
529 fprintf(stderr,"smbmnt failed: %d\n", WEXITSTATUS(status));
530 /* FIXME: do some proper error handling */
532 } else if (WIFSIGNALED(status)) {
533 fprintf(stderr, "smbmnt killed by signal %d\n", WTERMSIG(status));
537 /* Ok... This is the rubicon for that mount point... At any point
538 after this, if the connections fail and can not be reconstructed
539 for any reason, we will have to unmount the mount point. There
540 is no exit from the next call...
542 send_fs_socket(lp_ctx, service, mount_point, c);
546 /****************************************************************************
547 get a password from a a file or file descriptor
548 exit on failure (from smbclient, move to libsmb or shared .c file?)
549 ****************************************************************************/
550 static void get_password_file(void)
554 bool close_it = false;
558 if ((p = getenv("PASSWD_FD")) != NULL) {
559 pstrcpy(spec, "descriptor ");
561 sscanf(p, "%d", &fd);
563 } else if ((p = getenv("PASSWD_FILE")) != NULL) {
564 fd = open(p, O_RDONLY, 0);
567 fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
568 spec, strerror(errno));
574 for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
575 p && p - pass < sizeof(pass);) {
576 switch (read(fd, p, 1)) {
578 if (*p != '\n' && *p != '\0') {
579 *++p = '\0'; /* advance p, and null-terminate pass */
584 *p = '\0'; /* null-terminate it, just in case... */
585 p = NULL; /* then force the loop condition to become false */
588 fprintf(stderr, "Error reading password from file %s: %s\n",
589 spec, "empty password\n");
594 fprintf(stderr, "Error reading password from file %s: %s\n",
595 spec, strerror(errno));
599 pstrcpy(password, pass);
604 /****************************************************************************
605 get username and password from a credentials file
606 exit on failure (from smbclient, move to libsmb or shared .c file?)
607 ****************************************************************************/
608 static void read_credentials_file(char *filename)
613 char *ptr, *val, *param;
615 if ((auth=sys_fopen(filename, "r")) == NULL)
617 /* fail if we can't open the credentials file */
618 DEBUG(0,("ERROR: Unable to open credentials file!\n"));
624 /* get a line from the file */
625 if (!fgets (buf, sizeof(buf), auth))
629 if ((len) && (buf[len-1]=='\n'))
637 /* break up the line into parameter & value.
638 will need to eat a little whitespace possibly */
640 if (!(ptr = strchr (buf, '=')))
645 /* eat leading white space */
646 while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
649 if (strwicmp("password", param) == 0)
651 pstrcpy(password, val);
654 else if (strwicmp("username", param) == 0) {
655 pstrcpy(username, val);
658 memset(buf, 0, sizeof(buf));
664 /****************************************************************************
666 ****************************************************************************/
667 static void usage(void)
669 printf("Usage: mount.smbfs service mountpoint [-o options,...]\n");
671 printf("Version %s\n\n",VERSION);
675 username=<arg> SMB username\n\
676 password=<arg> SMB password\n\
677 credentials=<filename> file with username/password\n\
678 krb use kerberos (active directory)\n\
679 netbiosname=<arg> source NetBIOS name\n\
680 uid=<arg> mount uid or username\n\
681 gid=<arg> mount gid or groupname\n\
682 port=<arg> remote SMB port number\n\
683 fmask=<arg> file umask\n\
684 dmask=<arg> directory umask\n\
685 debug=<arg> debug level\n\
686 ip=<arg> destination host or IP address\n\
687 workgroup=<arg> workgroup on destination\n\
688 sockopt=<arg> TCP socket options\n\
689 scope=<arg> NetBIOS scope\n\
690 iocharset=<arg> Linux charset (iso8859-1, utf8)\n\
691 codepage=<arg> server codepage (cp850)\n\
692 ttl=<arg> dircache time to live\n\
693 guest don't prompt for a password\n\
694 ro mount read-only\n\
695 rw mount read-write\n\
697 This command is designed to be run from within /bin/mount by giving\n\
698 the option '-t smbfs'. For example:\n\
699 mount -t smbfs -o username=tridge,password=foobar //fjall/test /data/test\n\
704 /****************************************************************************
705 Argument parsing for mount.smbfs interface
706 mount will call us like this:
707 mount.smbfs device mountpoint -o <options>
709 <options> is never empty, containing at least rw or ro
710 ****************************************************************************/
711 static void parse_mount_smb(int argc, char **argv)
720 /* FIXME: This function can silently fail if the arguments are
721 * not in the expected order.
723 > The arguments syntax of smbmount 2.2.3a (smbfs of Debian stable)
724 > requires that one gives "-o" before further options like username=...
725 > . Without -o, the username=.. setting is *silently* ignored. I've
726 > spent about an hour trying to find out why I couldn't log in now..
731 if (argc < 2 || argv[1][0] == '-') {
736 pstrcpy(service, argv[1]);
737 pstrcpy(mpoint, argv[2]);
739 /* Convert any '/' characters in the service name to
741 string_replace(service, '/','\\');
745 opt = getopt(argc, argv, "o:");
754 * option parsing from nfsmount.c (util-linux-2.9u)
756 for (opts = strtok(optarg, ","); opts; opts = strtok(NULL, ",")) {
757 DEBUG(3, ("opts: %s\n", opts));
758 if ((opteq = strchr_m(opts, '='))) {
759 val = atoi(opteq + 1);
762 if (!strcmp(opts, "username") ||
763 !strcmp(opts, "logon")) {
766 pstrcpy(username,opteq+1);
767 if ((lp=strchr_m(username,'%'))) {
769 pstrcpy(password,lp+1);
771 memset(strchr_m(opteq+1,'%')+1,'X',strlen(password));
773 if ((lp=strchr_m(username,'/'))) {
775 pstrcpy(workgroup,lp+1);
777 } else if(!strcmp(opts, "passwd") ||
778 !strcmp(opts, "password")) {
779 pstrcpy(password,opteq+1);
781 memset(opteq+1,'X',strlen(password));
782 } else if(!strcmp(opts, "credentials")) {
783 pstrcpy(credentials,opteq+1);
784 } else if(!strcmp(opts, "netbiosname")) {
785 pstrcpy(my_netbios_name,opteq+1);
786 } else if(!strcmp(opts, "uid")) {
787 mount_uid = nametouid(opteq+1);
788 } else if(!strcmp(opts, "gid")) {
789 mount_gid = nametogid(opteq+1);
790 } else if(!strcmp(opts, "port")) {
792 } else if(!strcmp(opts, "fmask")) {
793 mount_fmask = strtol(opteq+1, NULL, 8);
794 } else if(!strcmp(opts, "dmask")) {
795 mount_dmask = strtol(opteq+1, NULL, 8);
796 } else if(!strcmp(opts, "debug")) {
798 } else if(!strcmp(opts, "ip")) {
799 dest_ip = interpret_addr2(opteq+1);
800 if (is_zero_ip(dest_ip)) {
801 fprintf(stderr,"Can't resolve address %s\n", opteq+1);
805 } else if(!strcmp(opts, "workgroup")) {
806 pstrcpy(workgroup,opteq+1);
807 } else if(!strcmp(opts, "sockopt")) {
808 lp_set_cmdline("socket options", opteq+1);
809 } else if(!strcmp(opts, "scope")) {
810 lp_set_cmdline("netbios scope", opteq+1);
812 slprintf(p, sizeof(pstring) - (p - options) - 1, "%s=%s,", opts, opteq+1);
817 if(!strcmp(opts, "nocaps")) {
818 fprintf(stderr, "Unhandled option: %s\n", opteq+1);
820 } else if(!strcmp(opts, "guest")) {
823 } else if(!strcmp(opts, "krb")) {
828 fprintf(stderr, "Warning: kerberos support will only work for samba servers\n");
830 fprintf(stderr,"No kerberos support compiled in\n");
833 } else if(!strcmp(opts, "rw")) {
835 } else if(!strcmp(opts, "ro")) {
838 strncpy(p, opts, sizeof(pstring) - (p - options) - 1);
852 *(p-1) = 0; /* remove trailing , */
853 DEBUG(3,("passthrough options '%s'\n", options));
857 /****************************************************************************
859 ****************************************************************************/
860 int main(int argc,char *argv[])
865 struct loadparm_context *lp_ctx;
869 /* here we are interactive, even if run from autofs */
870 setup_logging("mount.smbfs",DEBUG_STDERR);
872 #if 0 /* JRA - Urban says not needed ? */
873 /* CLI_FORCE_ASCII=false makes smbmount negotiate unicode. The default
874 is to not announce any unicode capabilities as current smbfs does
876 p = getenv("CLI_FORCE_ASCII");
877 if (p && !strcmp(p, "false"))
878 unsetenv("CLI_FORCE_ASCII");
880 setenv("CLI_FORCE_ASCII", "true", 1);
883 if (getenv("USER")) {
884 pstrcpy(username,getenv("USER"));
886 if ((p=strchr_m(username,'%'))) {
888 pstrcpy(password,p+1);
890 memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(password));
895 if (getenv("PASSWD")) {
896 pstrcpy(password, getenv("PASSWD"));
900 if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
905 if (*username == 0 && getenv("LOGNAME")) {
906 pstrcpy(username,getenv("LOGNAME"));
909 lp_ctx = loadparm_init(talloc_autofree_context());
911 if (!lp_load(lp_ctx, dyn_CONFIGFILE)) {
912 fprintf(stderr, "Can't load %s - run testparm to debug it\n",
916 parse_mount_smb(argc, argv);
918 if (use_kerberos && !got_user) {
922 if (*credentials != 0) {
923 read_credentials_file(credentials);
926 DEBUG(3,("mount.smbfs started (version %s)\n", VERSION));
928 if (*workgroup == 0) {
929 pstrcpy(workgroup, lp_workgroup());
932 if (!*my_netbios_name) {
933 pstrcpy(my_netbios_name, myhostname());
935 strupper(my_netbios_name);