trying to get HEAD building again. If you want the code
[gd/samba-autobuild/.git] / source3 / client / smbmount.c
index d0c18e6134bbcc7377fdb6a5d035c521751a2541..343d4f267576b7b7cf2821f8d9016817763f38ea 100644 (file)
@@ -1,6 +1,5 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 2.0.
+   Unix SMB/CIFS implementation.
    SMBFS mount program
    Copyright (C) Andrew Tridgell 1999
    
 #include <asm/types.h>
 #include <linux/smb_fs.h>
 
-extern struct in_addr ipzero;
-extern int DEBUGLEVEL;
-
 extern BOOL in_client;
 extern pstring user_socket_options;
-extern BOOL append_log;
-extern fstring remote_machine;
 
 static pstring credentials;
 static pstring my_netbios_name;
@@ -46,13 +40,19 @@ static pstring options;
 
 static struct in_addr dest_ip;
 static BOOL have_ip;
-static int smb_port = 139;
+static int smb_port = 0;
+static BOOL got_user;
 static BOOL got_pass;
 static uid_t mount_uid;
 static gid_t mount_gid;
 static int mount_ro;
 static unsigned mount_fmask;
 static unsigned mount_dmask;
+static BOOL use_kerberos;
+/* TODO: Add code to detect smbfs version in kernel */
+static BOOL status32_smbfs = False;
+static BOOL smbfs_has_unicode = False;
+static BOOL smbfs_has_lfs = False;
 
 static void usage(void);
 
@@ -84,8 +84,12 @@ static void daemonize(void)
                        }
                        break;
                }
+
                /* If we get here - the child exited with some error status */
-               exit(status);
+               if (WIFSIGNALED(status))
+                       exit(128 + WTERMSIG(status));
+               else
+                       exit(WEXITSTATUS(status));
        }
 
        signal( SIGTERM, SIG_DFL );
@@ -114,22 +118,21 @@ static void usr1_handler(int x)
 /***************************************************** 
 return a connection to a server
 *******************************************************/
-static struct cli_state *do_connection(char *service)
+static struct cli_state *do_connection(char *the_service)
 {
        struct cli_state *c;
        struct nmb_name called, calling;
        char *server_n;
        struct in_addr ip;
-       extern struct in_addr ipzero;
        pstring server;
        char *share;
 
-       if (service[0] != '\\' || service[1] != '\\') {
+       if (the_service[0] != '\\' || the_service[1] != '\\') {
                usage();
                exit(1);
        }
 
-       pstrcpy(server, service+2);
+       pstrcpy(server, the_service+2);
        share = strchr_m(server,'\\');
        if (!share) {
                usage();
@@ -144,26 +147,34 @@ static struct cli_state *do_connection(char *service)
        make_nmb_name(&called , server, 0x20);
 
  again:
-       ip = ipzero;
+        zero_ip(&ip);
        if (have_ip) ip = dest_ip;
 
        /* have to open a new connection */
-       if (!(c=cli_initialise(NULL)) || (cli_set_port(c, smb_port) == 0) ||
+       if (!(c=cli_initialise(NULL)) || (cli_set_port(c, smb_port) != smb_port) ||
            !cli_connect(c, server_n, &ip)) {
-               DEBUG(0,("%d: Connection to %s failed\n", getpid(), server_n));
+               DEBUG(0,("%d: Connection to %s failed\n", sys_getpid(), server_n));
                if (c) {
                        cli_shutdown(c);
-                       free(c);
                }
                return NULL;
        }
 
+       /* SPNEGO doesn't work till we get NTSTATUS error support */
+       /* But it is REQUIRED for kerberos authentication */
+       if(!use_kerberos) c->use_spnego = False;
+
+       /* The kernel doesn't yet know how to sign it's packets */
+       c->sign_info.allow_smb_signing = False;
+
+       /* Use kerberos authentication if specified */
+       c->use_kerberos = use_kerberos;
+
        if (!cli_session_request(c, &calling, &called)) {
                char *p;
                DEBUG(0,("%d: session request to %s failed (%s)\n", 
-                        getpid(), called.name, cli_errstr(c)));
+                        sys_getpid(), called.name, cli_errstr(c)));
                cli_shutdown(c);
-               free(c);
                if ((p=strchr_m(called.name, '.'))) {
                        *p = 0;
                        goto again;
@@ -175,12 +186,11 @@ static struct cli_state *do_connection(char *service)
                return NULL;
        }
 
-       DEBUG(4,("%d: session request ok\n", getpid()));
+       DEBUG(4,("%d: session request ok\n", sys_getpid()));
 
        if (!cli_negprot(c)) {
-               DEBUG(0,("%d: protocol negotiation failed\n", getpid()));
+               DEBUG(0,("%d: protocol negotiation failed\n", sys_getpid()));
                cli_shutdown(c);
-               free(c);
                return NULL;
        }
 
@@ -191,29 +201,45 @@ static struct cli_state *do_connection(char *service)
                }
        }
 
+       /* This should be right for current smbfs. Future versions will support
+         large files as well as unicode and oplocks. */
+       c->capabilities &= ~(CAP_NT_SMBS | CAP_NT_FIND | CAP_LEVEL_II_OPLOCKS);
+       if (!smbfs_has_lfs)
+               c->capabilities &= ~CAP_LARGE_FILES;
+       if (!smbfs_has_unicode)
+               c->capabilities &= ~CAP_UNICODE;
+       if (!status32_smbfs) {
+               c->capabilities &= ~CAP_STATUS32;
+               c->force_dos_errors = True;
+       }
+
        if (!cli_session_setup(c, username, 
                               password, strlen(password),
                               password, strlen(password),
                               workgroup)) {
-               DEBUG(0,("%d: session setup failed: %s\n",
-                        getpid(), cli_errstr(c)));
-               cli_shutdown(c);
-               free(c);
-               return NULL;
+               /* if a password was not supplied then try again with a
+                       null username */
+               if (password[0] || !username[0] ||
+                               !cli_session_setup(c, "", "", 0, "", 0, workgroup)) {
+                       DEBUG(0,("%d: session setup failed: %s\n",
+                               sys_getpid(), cli_errstr(c)));
+                       cli_shutdown(c);
+                       return NULL;
+               }
+               DEBUG(0,("Anonymous login successful\n"));
        }
 
-       DEBUG(4,("%d: session setup ok\n", getpid()));
+       DEBUG(4,("%d: session setup ok\n", sys_getpid()));
 
        if (!cli_send_tconX(c, share, "?????",
                            password, strlen(password)+1)) {
                DEBUG(0,("%d: tree connect failed: %s\n",
-                        getpid(), cli_errstr(c)));
+                        sys_getpid(), cli_errstr(c)));
                cli_shutdown(c);
-               free(c);
                return NULL;
        }
 
-       DEBUG(4,("%d: tconx ok\n", getpid()));
+       DEBUG(4,("%d: tconx ok\n", sys_getpid()));
 
        got_pass = True;
 
@@ -243,12 +269,12 @@ static void smb_umount(char *mount_point)
        */
         if (umount(mount_point) != 0) {
                 DEBUG(0,("%d: Could not umount %s: %s\n",
-                        getpid(), mount_point, strerror(errno)));
+                        sys_getpid(), mount_point, strerror(errno)));
                 return;
         }
 
         if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) {
-                DEBUG(0,("%d: Can't get "MOUNTED"~ lock file", getpid()));
+                DEBUG(0,("%d: Can't get "MOUNTED"~ lock file", sys_getpid()));
                 return;
         }
 
@@ -256,7 +282,7 @@ static void smb_umount(char *mount_point)
        
         if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
                 DEBUG(0,("%d: Can't open " MOUNTED ": %s\n",
-                        getpid(), strerror(errno)));
+                        sys_getpid(), strerror(errno)));
                 return;
         }
 
@@ -264,7 +290,7 @@ static void smb_umount(char *mount_point)
 
         if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
                 DEBUG(0,("%d: Can't open " MOUNTED_TMP ": %s\n",
-                        getpid(), strerror(errno)));
+                        sys_getpid(), strerror(errno)));
                 endmntent(mtab);
                 return;
         }
@@ -279,7 +305,7 @@ static void smb_umount(char *mount_point)
 
         if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
                 DEBUG(0,("%d: Error changing mode of %s: %s\n",
-                        getpid(), MOUNTED_TMP, strerror(errno)));
+                        sys_getpid(), MOUNTED_TMP, strerror(errno)));
                 return;
         }
 
@@ -287,12 +313,12 @@ static void smb_umount(char *mount_point)
 
         if (rename(MOUNTED_TMP, MOUNTED) < 0) {
                 DEBUG(0,("%d: Cannot rename %s to %s: %s\n",
-                        getpid(), MOUNTED, MOUNTED_TMP, strerror(errno)));
+                        sys_getpid(), MOUNTED, MOUNTED_TMP, strerror(errno)));
                 return;
         }
 
         if (unlink(MOUNTED"~") == -1) {
-                DEBUG(0,("%d: Can't remove "MOUNTED"~", getpid()));
+                DEBUG(0,("%d: Can't remove "MOUNTED"~", sys_getpid()));
                 return;
         }
 }
@@ -304,7 +330,7 @@ static void smb_umount(char *mount_point)
  * not exit after open_sockets() or send_login() errors,
  * as the smbfs mount would then have no way to recover.
  */
-static void send_fs_socket(char *service, char *mount_point, struct cli_state *c)
+static void send_fs_socket(char *the_service, char *mount_point, struct cli_state *c)
 {
        int fd, closed = 0, res = 1;
        pid_t parentpid = getppid();
@@ -315,7 +341,7 @@ static void send_fs_socket(char *service, char *mount_point, struct cli_state *c
        while (1) {
                if ((fd = open(mount_point, O_RDONLY)) < 0) {
                        DEBUG(0,("mount.smbfs[%d]: can't open %s\n",
-                                getpid(), mount_point));
+                                sys_getpid(), mount_point));
                        break;
                }
 
@@ -335,7 +361,7 @@ static void send_fs_socket(char *service, char *mount_point, struct cli_state *c
                res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
                if (res != 0) {
                        DEBUG(0,("mount.smbfs[%d]: ioctl failed, res=%d\n",
-                                getpid(), res));
+                                sys_getpid(), res));
                        close(fd);
                        break;
                }
@@ -358,7 +384,6 @@ static void send_fs_socket(char *service, char *mount_point, struct cli_state *c
                   If we don't do this we will "leak" sockets and memory on
                   each reconnection we have to make. */
                cli_shutdown(c);
-               free(c);
                c = NULL;
 
                if (!closed) {
@@ -374,11 +399,10 @@ static void send_fs_socket(char *service, char *mount_point, struct cli_state *c
                        }
 
                        /* here we are no longer interactive */
-                       pstrcpy(remote_machine, "smbmount");    /* sneaky ... */
+                       set_remote_machine_name("smbmount", False);     /* sneaky ... */
                        setup_logging("mount.smbfs", False);
-                       append_log = True;
                        reopen_logs();
-                       DEBUG(0, ("mount.smbfs: entering daemon mode for service %s, pid=%d\n", service, getpid()));
+                       DEBUG(0, ("mount.smbfs: entering daemon mode for service %s, pid=%d\n", the_service, sys_getpid()));
 
                        closed = 1;
                }
@@ -388,33 +412,20 @@ static void send_fs_socket(char *service, char *mount_point, struct cli_state *c
                while (!c) {
                        CatchSignal(SIGUSR1, &usr1_handler);
                        pause();
-                       DEBUG(2,("mount.smbfs[%d]: got signal, getting new socket\n", getpid()));
-                       c = do_connection(service);
+                       DEBUG(2,("mount.smbfs[%d]: got signal, getting new socket\n", sys_getpid()));
+                       c = do_connection(the_service);
                }
        }
 
        smb_umount(mount_point);
-       DEBUG(2,("mount.smbfs[%d]: exit\n", getpid()));
+       DEBUG(2,("mount.smbfs[%d]: exit\n", sys_getpid()));
        exit(1);
 }
 
-/*********************************************************
-a strdup with exit
-**********************************************************/
-static char *xstrdup(char *s)
-{
-       s = strdup(s);
-       if (!s) {
-               fprintf(stderr,"out of memory\n");
-               exit(1);
-       }
-       return s;
-}
-
 
-/****************************************************************************
-mount smbfs
-****************************************************************************/
+/**
+ * Mount a smbfs
+ **/
 static void init_mount(void)
 {
        char mount_point[MAXPATHLEN+1];
@@ -461,22 +472,22 @@ static void init_mount(void)
        if (mount_uid) {
                slprintf(tmp, sizeof(tmp)-1, "%d", mount_uid);
                args[i++] = "-u";
-               args[i++] = xstrdup(tmp);
+               args[i++] = smb_xstrdup(tmp);
        }
        if (mount_gid) {
                slprintf(tmp, sizeof(tmp)-1, "%d", mount_gid);
                args[i++] = "-g";
-               args[i++] = xstrdup(tmp);
+               args[i++] = smb_xstrdup(tmp);
        }
        if (mount_fmask) {
                slprintf(tmp, sizeof(tmp)-1, "0%o", mount_fmask);
                args[i++] = "-f";
-               args[i++] = xstrdup(tmp);
+               args[i++] = smb_xstrdup(tmp);
        }
        if (mount_dmask) {
                slprintf(tmp, sizeof(tmp)-1, "0%o", mount_dmask);
                args[i++] = "-d";
-               args[i++] = xstrdup(tmp);
+               args[i++] = smb_xstrdup(tmp);
        }
        if (options) {
                args[i++] = "-o";
@@ -484,13 +495,22 @@ static void init_mount(void)
        }
 
        if (sys_fork() == 0) {
-               if (file_exist(BINDIR "/smbmnt", NULL)) {
-                       execv(BINDIR "/smbmnt", args);
-                       fprintf(stderr,"execv of %s failed. Error was %s.", BINDIR "/smbmnt", strerror(errno));
+               char *smbmnt_path;
+
+               asprintf(&smbmnt_path, "%s/smbmnt", dyn_BINDIR);
+               
+               if (file_exist(smbmnt_path, NULL)) {
+                       execv(smbmnt_path, args);
+                       fprintf(stderr,
+                               "smbfs/init_mount: execv of %s failed. Error was %s.",
+                               smbmnt_path, strerror(errno));
                } else {
                        execvp("smbmnt", args);
-                       fprintf(stderr,"execvp of smbmnt failed. Error was %s.", strerror(errno) );
+                       fprintf(stderr,
+                               "smbfs/init_mount: execv of %s failed. Error was %s.",
+                               "smbmnt", strerror(errno));
                }
+               free(smbmnt_path);
                exit(1);
        }
 
@@ -504,6 +524,9 @@ static void init_mount(void)
                fprintf(stderr,"smbmnt failed: %d\n", WEXITSTATUS(status));
                /* FIXME: do some proper error handling */
                exit(1);
+       } else if (WIFSIGNALED(status)) {
+               fprintf(stderr, "smbmnt killed by signal %d\n", WTERMSIG(status));
+               exit(1);
        }
 
        /* Ok...  This is the rubicon for that mount point...  At any point
@@ -623,8 +646,9 @@ static void read_credentials_file(char *filename)
                        pstrcpy(password, val);
                        got_pass = True;
                }
-               else if (strwicmp("username", param) == 0)
+               else if (strwicmp("username", param) == 0) {
                        pstrcpy(username, val);
+               }
 
                memset(buf, 0, sizeof(buf));
        }
@@ -642,31 +666,34 @@ static void usage(void)
        printf("Version %s\n\n",VERSION);
 
        printf(
-"Options:
-      username=<arg>                  SMB username
-      password=<arg>                  SMB password
-      credentials=<filename>          file with username/password
-      netbiosname=<arg>               source NetBIOS name
-      uid=<arg>                       mount uid or username
-      gid=<arg>                       mount gid or groupname
-      port=<arg>                      remote SMB port number
-      fmask=<arg>                     file umask
-      dmask=<arg>                     directory umask
-      debug=<arg>                     debug level
-      ip=<arg>                        destination host or IP address
-      workgroup=<arg>                 workgroup on destination
-      sockopt=<arg>                   TCP socket options
-      scope=<arg>                     NetBIOS scope
-      iocharset=<arg>                 Linux charset (iso8859-1, utf8)
-      codepage=<arg>                  server codepage (cp850)
-      ttl=<arg>                       dircache time to live
-      guest                           don't prompt for a password
-      ro                              mount read-only
-      rw                              mount read-write
-
-This command is designed to be run from within /bin/mount by giving
-the option '-t smbfs'. For example:
-  mount -t smbfs -o username=tridge,password=foobar //fjall/test /data/test
+"Options:\n\
+      username=<arg>                  SMB username\n\
+      password=<arg>                  SMB password\n\
+      credentials=<filename>          file with username/password\n\
+      krb                             use kerberos (active directory)\n\
+      netbiosname=<arg>               source NetBIOS name\n\
+      uid=<arg>                       mount uid or username\n\
+      gid=<arg>                       mount gid or groupname\n\
+      port=<arg>                      remote SMB port number\n\
+      fmask=<arg>                     file umask\n\
+      dmask=<arg>                     directory umask\n\
+      debug=<arg>                     debug level\n\
+      ip=<arg>                        destination host or IP address\n\
+      workgroup=<arg>                 workgroup on destination\n\
+      sockopt=<arg>                   TCP socket options\n\
+      scope=<arg>                     NetBIOS scope\n\
+      iocharset=<arg>                 Linux charset (iso8859-1, utf8)\n\
+      codepage=<arg>                  server codepage (cp850)\n\
+      unicode                         use unicode when communicating with server\n\
+      lfs                             large file system support\n\
+      ttl=<arg>                       dircache time to live\n\
+      guest                           don't prompt for a password\n\
+      ro                              mount read-only\n\
+      rw                              mount read-write\n\
+\n\
+This command is designed to be run from within /bin/mount by giving\n\
+the option '-t smbfs'. For example:\n\
+  mount -t smbfs -o username=tridge,password=foobar //fjall/test /data/test\n\
 ");
 }
 
@@ -685,9 +712,19 @@ static void parse_mount_smb(int argc, char **argv)
        char *opteq;
        extern char *optarg;
        int val;
-       extern pstring global_scope;
        char *p;
 
+       /* FIXME: This function can silently fail if the arguments are
+        * not in the expected order.
+
+       > The arguments syntax of smbmount 2.2.3a (smbfs of Debian stable)
+       > requires that one gives "-o" before further options like username=...
+       > . Without -o, the username=.. setting is *silently* ignored. I've
+       > spent about an hour trying to find out why I couldn't log in now..
+
+       */
+
+
        if (argc < 2 || argv[1][0] == '-') {
                usage();
                exit(1);
@@ -722,6 +759,7 @@ static void parse_mount_smb(int argc, char **argv)
                         if (!strcmp(opts, "username") || 
                            !strcmp(opts, "logon")) {
                                char *lp;
+                               got_user = True;
                                pstrcpy(username,opteq+1);
                                if ((lp=strchr_m(username,'%'))) {
                                        *lp = 0;
@@ -756,7 +794,7 @@ static void parse_mount_smb(int argc, char **argv)
                                DEBUGLEVEL = val;
                        } else if(!strcmp(opts, "ip")) {
                                dest_ip = *interpret_addr2(opteq+1);
-                               if (zero_ip(dest_ip)) {
+                               if (is_zero_ip(dest_ip)) {
                                        fprintf(stderr,"Can't resolve address %s\n", opteq+1);
                                        exit(1);
                                }
@@ -766,7 +804,7 @@ static void parse_mount_smb(int argc, char **argv)
                        } else if(!strcmp(opts, "sockopt")) {
                                pstrcpy(user_socket_options,opteq+1);
                        } else if(!strcmp(opts, "scope")) {
-                               pstrcpy(global_scope,opteq+1);
+                               set_global_scope(opteq+1);
                        } else {
                                slprintf(p, sizeof(pstring) - (p - options) - 1, "%s=%s,", opts, opteq+1);
                                p += strlen(p);
@@ -777,11 +815,26 @@ static void parse_mount_smb(int argc, char **argv)
                                fprintf(stderr, "Unhandled option: %s\n", opteq+1);
                                exit(1);
                        } else if(!strcmp(opts, "guest")) {
+                               *password = '\0';
                                got_pass = True;
+                       } else if(!strcmp(opts, "krb")) {
+#ifdef HAVE_KRB5
+
+                               use_kerberos = True;
+                               if(!status32_smbfs)
+                                       fprintf(stderr, "Warning: kerberos support will only work for samba servers\n");
+#else
+                               fprintf(stderr,"No kerberos support compiled in\n");
+                               exit(1);
+#endif
                        } else if(!strcmp(opts, "rw")) {
                                mount_ro = 0;
                        } else if(!strcmp(opts, "ro")) {
                                mount_ro = 1;
+                       } else if(!strcmp(opts, "unicode")) {
+                               smbfs_has_unicode = True;
+                       } else if(!strcmp(opts, "lfs")) {
+                               smbfs_has_lfs = True;
                        } else {
                                strncpy(p, opts, sizeof(pstring) - (p - options) - 1);
                                p += strlen(opts);
@@ -809,7 +862,6 @@ static void parse_mount_smb(int argc, char **argv)
 {
        extern char *optarg;
        extern int optind;
-       static pstring servicesf = CONFIGFILE;
        char *p;
 
        DEBUGLEVEL = 1;
@@ -817,8 +869,17 @@ static void parse_mount_smb(int argc, char **argv)
        /* here we are interactive, even if run from autofs */
        setup_logging("mount.smbfs",True);
 
-       TimeInit();
-       
+#if 0 /* JRA - Urban says not needed ? */
+       /* CLI_FORCE_ASCII=false makes smbmount negotiate unicode. The default
+          is to not announce any unicode capabilities as current smbfs does
+          not support it. */
+       p = getenv("CLI_FORCE_ASCII");
+       if (p && !strcmp(p, "false"))
+               unsetenv("CLI_FORCE_ASCII");
+       else
+               setenv("CLI_FORCE_ASCII", "true", 1);
+#endif
+
        in_client = True;   /* Make sure that we tell lp_load we are */
 
        if (getenv("USER")) {
@@ -830,7 +891,7 @@ static void parse_mount_smb(int argc, char **argv)
                        got_pass = True;
                        memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(password));
                }
-               strupper(username);
+               strupper_m(username);
        }
 
        if (getenv("PASSWD")) {
@@ -847,13 +908,17 @@ static void parse_mount_smb(int argc, char **argv)
                pstrcpy(username,getenv("LOGNAME"));
        }
 
-       if (!lp_load(servicesf,True,False,False)) {
+       if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
                fprintf(stderr, "Can't load %s - run testparm to debug it\n", 
-                       servicesf);
+                       dyn_CONFIGFILE);
        }
 
        parse_mount_smb(argc, argv);
 
+       if (use_kerberos && !got_user) {
+               got_pass = True;
+       }
+
        if (*credentials != 0) {
                read_credentials_file(credentials);
        }
@@ -868,7 +933,7 @@ static void parse_mount_smb(int argc, char **argv)
        if (!*my_netbios_name) {
                pstrcpy(my_netbios_name, myhostname());
        }
-       strupper(my_netbios_name);
+       strupper_m(my_netbios_name);
 
        init_mount();
        return 0;