the real source code for the smbfs utilities. Forgot to do
authorVolker Lendecke <vlendec@samba.org>
Mon, 5 Jan 1998 22:56:29 +0000 (22:56 +0000)
committerVolker Lendecke <vlendec@samba.org>
Mon, 5 Jan 1998 22:56:29 +0000 (22:56 +0000)
cvs add first.
Volker

source/client/smbmnt.c [new file with mode: 0644]
source/client/smbmount.c [new file with mode: 0644]
source/client/smbumount.c [new file with mode: 0644]

diff --git a/source/client/smbmnt.c b/source/client/smbmnt.c
new file mode 100644 (file)
index 0000000..9bb7f56
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ *  smbmount.c
+ *
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+/* #include <sys/wait.h> */  /* generates a warning here */
+extern pid_t waitpid(pid_t, int *, int);
+#include <sys/errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <mntent.h>
+
+#include <linux/fs.h>
+#include <linux/smb.h>
+#include <linux/smb_mount.h>
+
+#include <asm/unistd.h>
+
+static char *progname;
+
+
+static void
+usage(void)
+{
+        printf("usage: %s mount-point [options]\n", progname);
+        printf("Try `%s -h' for more information\n", progname);
+}
+
+static void
+help(void)
+{
+        printf("\n");
+        printf("usage: %s mount-point [options]\n", progname);
+        printf("-u uid         uid the mounted files get\n"
+               "-g gid         gid the mounted files get\n"
+               "-f mode        permission the files get (octal notation)\n"
+               "-d mode        permission the dirs get (octal notation)\n"
+              "-P pid         connection handler's pid\n\n"
+               "-h             print this help text\n");
+}
+
+static int
+parse_args(int argc, char *argv[], struct smb_mount_data *data)
+{
+        int opt;
+        struct passwd *pwd;
+        struct group  *grp;
+
+        while ((opt = getopt (argc, argv, "u:g:f:d:"))
+              != EOF)
+       {
+                switch (opt)
+               {
+                case 'u':
+                        if (isdigit(optarg[0]))
+                       {
+                                data->uid = atoi(optarg);
+                        }
+                       else
+                       {
+                                pwd = getpwnam(optarg);
+                                if (pwd == NULL)
+                               {
+                                        fprintf(stderr, "Unknown user: %s\n",
+                                                optarg);
+                                        return 1;
+                                }
+                                data->uid = pwd->pw_uid;
+                        }
+                        break;
+                case 'g':
+                        if (isdigit(optarg[0]))
+                       {
+                                data->gid = atoi(optarg);
+                        }
+                       else
+                       {
+                                grp = getgrnam(optarg);
+                                if (grp == NULL)
+                               {
+                                        fprintf(stderr, "Unknown group: %s\n",
+                                                optarg);
+                                        return 1;
+                                }
+                                data->gid = grp->gr_gid;
+                        }
+                        break;
+                case 'f':
+                        data->file_mode = strtol(optarg, NULL, 8);
+                        break;
+                case 'd':
+                        data->dir_mode = strtol(optarg, NULL, 8);
+                        break;
+                default:
+                        return -1;
+                }
+        }
+        return 0;
+        
+}
+
+static char *
+fullpath(const char *p)
+{
+        char path[MAXPATHLEN];
+
+       if (strlen(p) > MAXPATHLEN-1)
+       {
+               return NULL;
+       }
+
+        if (realpath(p, path) == NULL)
+       {
+                return strdup(p);
+       }
+       return strdup(path);
+}
+
+/* Check whether user is allowed to mount on the specified mount point */
+static int
+mount_ok(struct stat *st)
+{
+        if (!S_ISDIR(st->st_mode))
+        {
+                errno = ENOTDIR;
+                return -1;
+        }
+       
+        if (   (getuid() != 0)
+            && (   (getuid() != st->st_uid)
+                || ((st->st_mode & S_IRWXU) != S_IRWXU)))
+        {
+                errno = EPERM;
+                return -1;
+        }
+
+        return 0;
+}
+
+int 
+main(int argc, char *argv[])
+{
+        struct smb_mount_data data;
+        struct stat st;
+
+        int fd;
+        int um;
+       unsigned int flags;
+
+        char *mount_point;
+
+        struct mntent ment;
+        FILE *mtab;
+
+        progname = argv[0];
+
+       memset(&data, 0, sizeof(struct smb_mount_data));
+
+       if (   (argc == 2)
+              && (argv[1][0] == '-')
+              && (argv[1][1] == 'h')
+              && (argv[1][2] == '\0'))
+       {
+               help();
+               return 0;
+       }
+
+        if (geteuid() != 0) {
+                fprintf(stderr, "%s must be installed suid root\n", progname);
+                exit(1);
+        }
+
+       if (argc < 2)
+       {
+               usage();
+               return 1;
+       }
+
+        mount_point = argv[1];
+
+        argv += 1;
+        argc -= 1;
+
+        if (stat(mount_point, &st) == -1) {
+                fprintf(stderr, "could not find mount point %s: %s\n",
+                        mount_point, strerror(errno));
+                exit(1);
+        }
+
+        if (mount_ok(&st) != 0) {
+                fprintf(stderr, "cannot mount on %s: %s\n",
+                        mount_point, strerror(errno));
+                exit(1);
+        }
+
+       data.version = SMB_MOUNT_VERSION;
+
+        /* getuid() gives us the real uid, who may umount the fs */
+        data.mounted_uid = getuid();
+
+        data.uid = getuid();
+        data.gid = getgid();
+        um = umask(0);
+        umask(um);
+        data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & ~um;
+        data.dir_mode  = 0;
+
+        if (parse_args(argc, argv, &data) != 0) {
+                usage();
+                return -1;
+        }
+
+        if (data.dir_mode == 0) {
+                data.dir_mode = data.file_mode;
+                if ((data.dir_mode & S_IRUSR) != 0)
+                        data.dir_mode |= S_IXUSR;
+                if ((data.dir_mode & S_IRGRP) != 0)
+                        data.dir_mode |= S_IXGRP;
+                if ((data.dir_mode & S_IROTH) != 0)
+                        data.dir_mode |= S_IXOTH;
+        }
+
+       flags = MS_MGC_VAL;
+
+       if (mount(NULL, mount_point, "smbfs",
+                  flags, (char *)&data) < 0) {
+               perror("mount error");
+               printf("Please look at smbmount's manual page for "
+                      "possible reasons\n");
+               return -1;
+       }
+
+        ment.mnt_fsname = "none";
+        ment.mnt_dir = fullpath(mount_point);
+        ment.mnt_type = "smbfs";
+        ment.mnt_opts = "";
+        ment.mnt_freq = 0;
+        ment.mnt_passno= 0;
+
+        mount_point = ment.mnt_dir;
+
+       if (mount_point == NULL)
+       {
+               fprintf(stderr, "Mount point too long\n");
+               return -1;
+       }
+       
+        if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)
+        {
+                fprintf(stderr, "Can't get "MOUNTED"~ lock file");
+                return 1;
+        }
+        close(fd);
+       
+        if ((mtab = setmntent(MOUNTED, "a+")) == NULL)
+        {
+                fprintf(stderr, "Can't open " MOUNTED);
+                return 1;
+        }
+
+        if (addmntent(mtab, &ment) == 1)
+        {
+                fprintf(stderr, "Can't write mount entry");
+                return 1;
+        }
+        if (fchmod(fileno(mtab), 0644) == -1)
+        {
+                fprintf(stderr, "Can't set perms on "MOUNTED);
+                return 1;
+        }
+        endmntent(mtab);
+
+        if (unlink(MOUNTED"~") == -1)
+        {
+                fprintf(stderr, "Can't remove "MOUNTED"~");
+                return 1;
+        }
+
+       return 0;
+}      
diff --git a/source/client/smbmount.c b/source/client/smbmount.c
new file mode 100644 (file)
index 0000000..2ef426a
--- /dev/null
@@ -0,0 +1,941 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   SMB client
+   Copyright (C) Andrew Tridgell 1994-1997
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+#include <linux/smb_fs.h>
+static struct smb_conn_opt conn_options;
+
+#ifndef REGISTER
+#define REGISTER 0
+#endif
+
+pstring cur_dir = "\\";
+pstring cd_path = "";
+extern pstring service;
+extern pstring desthost;
+extern pstring myname;
+extern pstring myhostname;
+extern pstring password;
+extern pstring username;
+extern pstring workgroup;
+char *cmdstr="";
+extern BOOL got_pass;
+extern BOOL connect_as_printer;
+extern BOOL connect_as_ipc;
+extern struct in_addr ipzero;
+
+extern BOOL doencrypt;
+
+extern pstring user_socket_options;
+
+/* 30 second timeout on most commands */
+#define CLIENT_TIMEOUT (30*1000)
+#define SHORT_TIMEOUT (5*1000)
+
+/* value for unused fid field in trans2 secondary request */
+#define FID_UNUSED (0xFFFF)
+
+extern int name_type;
+
+extern int max_protocol;
+
+
+time_t newer_than = 0;
+int archive_level = 0;
+
+extern pstring debugf;
+extern int DEBUGLEVEL;
+
+BOOL translation = False;
+
+extern int cnum;
+extern int mid;
+extern int pid;
+extern int tid;
+extern int gid;
+extern int uid;
+
+extern BOOL have_ip;
+extern int max_xmit;
+
+/* clitar bits insert */
+extern int blocksize;
+extern BOOL tar_inc;
+extern BOOL tar_reset;
+/* clitar bits end */
+
+int myumask = 0755;
+
+extern pstring scope;
+
+BOOL prompt = True;
+
+int printmode = 1;
+
+BOOL recurse = False;
+BOOL lowercase = False;
+
+struct in_addr dest_ip;
+
+#define SEPARATORS " \t\n\r"
+
+BOOL abort_mget = True;
+
+extern int Protocol;
+
+extern BOOL readbraw_supported ;
+extern BOOL writebraw_supported;
+
+pstring fileselection = "";
+
+extern file_info def_finfo;
+
+/* timing globals */
+int get_total_size = 0;
+int get_total_time_ms = 0;
+int put_total_size = 0;
+int put_total_time_ms = 0;
+
+/* totals globals */
+int dir_total = 0;
+
+extern int Client;
+
+#define USENMB
+
+static BOOL setup_term_code(char *code)
+{
+       interpret_coding_system(code);
+       return True;
+}
+#define CNV_LANG(s) dos2unix_format(s,False)
+#define CNV_INPUT(s) unix2dos_format(s,True)
+
+/****************************************************************************
+check for existance of a dir
+****************************************************************************/
+static BOOL chkpath(char *path,BOOL report)
+{
+  fstring path2;
+  pstring inbuf,outbuf;
+  char *p;
+
+  strcpy(path2,path);
+  trim_string(path2,NULL,"\\");
+  if (!*path2) *path2 = '\\';
+
+  bzero(outbuf,smb_size);
+  set_message(outbuf,0,4 + strlen(path2),True);
+  SCVAL(outbuf,smb_com,SMBchkpth);
+  SSVAL(outbuf,smb_tid,cnum);
+  cli_setup_pkt(outbuf);
+
+  p = smb_buf(outbuf);
+  *p++ = 4;
+  strcpy(p,path2);
+
+#if 0
+  {
+         /* this little bit of code can be used to extract NT error codes.
+            Just feed a bunch of "cd foo" commands to smbclient then watch
+            in netmon (tridge) */
+         static int code=0;
+         SIVAL(outbuf, smb_rcls, code | 0xC0000000);
+         SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | (1<<14));
+         code++;
+  }
+#endif
+
+  send_smb(Client,outbuf);
+  client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+
+  if (report && CVAL(inbuf,smb_rcls) != 0)
+    DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf)));
+
+  return(CVAL(inbuf,smb_rcls) == 0);
+}
+
+
+/* #define SMBFS_DEBUG 1 */
+
+static void
+daemonize(void)
+{
+       int i;
+       if ((i = fork()) < 0)
+       {
+               DEBUG(0, ("could not fork\n"));
+       }
+       if (i > 0)
+       {
+               /* parent simply exits */
+               exit(0);
+       }
+       setsid();
+       chdir("/");
+}
+
+static void
+close_our_files(void)
+{
+       int i;
+       for (i = 0; i < NR_OPEN; i++) {
+               if (i == Client) {
+                       continue;
+               }
+               close(i);
+       }
+}
+
+static void
+usr1_handler(int x)
+{
+       return;
+}
+
+/*
+ * Send a login and store the connection options. This is a separate
+ * function to keep clientutil.c independent of linux kernel changes.
+ */
+static BOOL mount_send_login(char *inbuf, char *outbuf)
+{
+  struct connection_options opt;
+  int res = cli_send_login(inbuf, outbuf, True, True, &opt);
+
+  if (!res)
+    return res;
+
+  conn_options.protocol = opt.protocol;
+  conn_options.case_handling = CASE_LOWER;
+  conn_options.max_xmit = opt.max_xmit;
+  conn_options.server_uid = opt.server_uid;
+  conn_options.tid = opt.tid;
+  conn_options.secmode = opt.sec_mode;
+  conn_options.maxmux = opt.max_mux;
+  conn_options.maxvcs = opt.max_vcs;
+  conn_options.rawmode = opt.rawmode;
+  conn_options.sesskey = opt.sesskey;
+  conn_options.maxraw = opt.maxraw;
+  conn_options.capabilities = opt.capabilities;
+  conn_options.serverzone = opt.serverzone;
+
+  return True;
+}
+
+/*
+ * Call the smbfs ioctl to install a connection socket,
+ * then wait for a signal to reconnect. Note that we do
+ * 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 *mount_point, char *inbuf, char *outbuf)
+{
+       int fd, closed = 0, res = 1;
+
+       while (1)
+       {
+               if ((fd = open(mount_point, O_RDONLY)) < 0)
+               {
+#ifdef SMBFS_DEBUG
+                       printf("smbclient: can't open %s\n", mount_point);
+#endif
+                       break;
+               }               
+
+               /*
+                * Call the ioctl even if we couldn't get a socket ...
+                * there's no point in making smbfs wait for a timeout.
+                */
+               conn_options.fd = -1;
+               if (res)
+                       conn_options.fd = Client;
+               res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
+               if (res != 0)
+               {
+#ifdef SMBFS_DEBUG
+                       printf("smbclient: ioctl failed, res=%d\n",res);
+#endif
+               }
+
+               close_sockets();
+               close(fd);
+               /*
+                * Close all open files if we haven't done so yet.
+                */
+#ifndef SMBFS_DEBUG
+               if (!closed)
+               {
+                       closed = 1;
+                       close_our_files();
+               }
+#endif
+
+               /*
+                * Wait for a signal from smbfs ...
+                */
+               signal(SIGUSR1, &usr1_handler);
+               pause();
+#ifdef SMBFS_DEBUG
+               printf("smbclient: got signal, getting new socket\n");
+#endif
+
+               res = mount_send_login(inbuf,outbuf);
+               if (!res)
+               {
+#ifdef SMBFS_DEBUG
+                       printf("smbclient: login failed\n");
+#endif
+               }
+       }
+#ifdef SMBFS_DEBUG
+       printf("smbclient: exit\n");
+#endif
+       exit(1);
+}
+
+/****************************************************************************
+mount smbfs
+****************************************************************************/
+static void cmd_mount(char *inbuf,char *outbuf)
+{
+       pstring mpoint;
+       char mount_point[MAXPATHLEN+1];
+       pstring mount_command;
+       fstring buf;
+       int retval;
+
+       if (!next_token(NULL, mpoint, NULL))
+       {
+               DEBUG(0,("You must supply a mount point\n"));
+               return;
+       }
+
+       memset(mount_point, 0, sizeof(mount_point));
+
+       if (realpath(mpoint, mount_point) == NULL)
+       {
+               DEBUG(0, ("Could not resolve mount point\n"));
+               return;
+       }
+
+       sprintf(mount_command, "smbmnt %s", mount_point);
+
+       while(next_token(NULL, buf, NULL))
+       {
+               strcat(mount_command, " ");
+               strcat(mount_command, buf);
+       }
+
+       DEBUG(3,("mount command: %s\n", mount_command));
+
+       /*
+        * Create the background process before trying the mount.
+        * (We delay closing files to allow diagnostic messages.)
+        */
+       daemonize();
+
+       /* The parent has exited here, the child handles the connection: */
+       if ((retval = system(mount_command)) != 0)
+       {
+               DEBUG(0,("mount failed\n"));
+               exit(1);
+       }
+       send_fs_socket(mount_point, inbuf, outbuf);
+}      
+
+
+
+
+
+/* This defines the commands supported by this client */
+struct
+{
+  char *name;
+  void (*fn)();
+  char *description;
+} commands[] = 
+{
+  {"mount", cmd_mount, "<mount-point options> mount an smbfs file system"},
+  {"",NULL,NULL}
+};
+
+
+/*******************************************************************
+  lookup a command string in the list of commands, including 
+  abbreviations
+  ******************************************************************/
+static int process_tok(fstring tok)
+{
+  int i = 0, matches = 0;
+  int cmd=0;
+  int tok_len = strlen(tok);
+  
+  while (commands[i].fn != NULL)
+    {
+      if (strequal(commands[i].name,tok))
+       {
+         matches = 1;
+         cmd = i;
+         break;
+       }
+      else if (strnequal(commands[i].name, tok, tok_len))
+       {
+         matches++;
+         cmd = i;
+       }
+      i++;
+    }
+  
+  if (matches == 0)
+    return(-1);
+  else if (matches == 1)
+    return(cmd);
+  else
+    return(-2);
+}
+
+/****************************************************************************
+help
+****************************************************************************/
+void cmd_help(void)
+{
+  int i=0,j;
+  fstring buf;
+
+  if (next_token(NULL,buf,NULL))
+    {
+      if ((i = process_tok(buf)) >= 0)
+       DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));                   
+    }
+  else
+    while (commands[i].description)
+      {
+       for (j=0; commands[i].description && (j<5); j++) {
+         DEBUG(0,("%-15s",commands[i].name));
+         i++;
+       }
+       DEBUG(0,("\n"));
+      }
+}
+
+/****************************************************************************
+wait for keyboard activity, swallowing network packets
+****************************************************************************/
+#ifdef CLIX
+static char wait_keyboard(char *buffer)
+#else
+static void wait_keyboard(char *buffer)
+#endif
+{
+  fd_set fds;
+  int selrtn;
+  struct timeval timeout;
+  
+#ifdef CLIX
+  int delay = 0;
+#endif
+  
+  while (1) 
+    {
+      extern int Client;
+      FD_ZERO(&fds);
+      FD_SET(Client,&fds);
+#ifndef CLIX
+      FD_SET(fileno(stdin),&fds);
+#endif
+
+      timeout.tv_sec = 20;
+      timeout.tv_usec = 0;
+#ifdef CLIX
+      timeout.tv_sec = 0;
+#endif
+      selrtn = sys_select(&fds,&timeout);
+      
+#ifndef CLIX
+      if (FD_ISSET(fileno(stdin),&fds))
+       return;
+#else
+      {
+       char ch;
+       int readret;
+
+    set_blocking(fileno(stdin), False);        
+       readret = read_data( fileno(stdin), &ch, 1);
+       set_blocking(fileno(stdin), True);
+       if (readret == -1)
+         {
+           if (errno != EAGAIN)
+             {
+               /* should crash here */
+               DEBUG(1,("readchar stdin failed\n"));
+             }
+         }
+       else if (readret != 0)
+         {
+           return ch;
+         }
+      }
+#endif
+
+      /* We deliberately use receive_smb instead of
+         client_receive_smb as we want to receive
+         session keepalives and then drop them here.
+       */
+      if (FD_ISSET(Client,&fds))
+       receive_smb(Client,buffer,0);
+      
+#ifdef CLIX
+      delay++;
+      if (delay > 100000)
+       {
+         delay = 0;
+         chkpath("\\",False);
+       }
+#else
+      chkpath("\\",False);
+#endif
+    }  
+}
+
+
+/****************************************************************************
+  process commands from the client
+****************************************************************************/
+static BOOL process(char *base_directory)
+{
+  extern FILE *dbf;
+  pstring line;
+  char *cmd;
+
+  char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+  char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+
+  if ((InBuffer == NULL) || (OutBuffer == NULL)) 
+    return(False);
+  
+  bzero(OutBuffer,smb_size);
+
+  if (!mount_send_login(InBuffer,OutBuffer))
+    return(False);
+
+  cmd = cmdstr;
+  if (cmd[0] != '\0') while (cmd[0] != '\0')
+    {
+      char *p;
+      fstring tok;
+      int i;
+
+      if ((p = strchr(cmd, ';')) == 0)
+       {
+         strncpy(line, cmd, 999);
+         line[1000] = '\0';
+         cmd += strlen(cmd);
+       }
+      else
+       {
+         if (p - cmd > 999) p = cmd + 999;
+         strncpy(line, cmd, p - cmd);
+         line[p - cmd] = '\0';
+         cmd = p + 1;
+       }
+
+      /* input language code to internal one */
+      CNV_INPUT (line);
+      
+      /* and get the first part of the command */
+      {
+       char *ptr = line;
+       if (!next_token(&ptr,tok,NULL)) continue;
+      }
+
+      if ((i = process_tok(tok)) >= 0)
+       commands[i].fn(InBuffer,OutBuffer);
+      else if (i == -2)
+       DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
+      else
+       DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
+    }
+  else while (!feof(stdin))
+    {
+      fstring tok;
+      int i;
+
+      bzero(OutBuffer,smb_size);
+
+      /* display a prompt */
+      DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
+      fflush(dbf);
+
+#ifdef CLIX
+      line[0] = wait_keyboard(InBuffer);
+      /* this might not be such a good idea... */
+      if ( line[0] == EOF)
+       break;
+#else
+      wait_keyboard(InBuffer);
+#endif
+  
+      /* and get a response */
+#ifdef CLIX
+      fgets( &line[1],999, stdin);
+#else
+      if (!fgets(line,1000,stdin))
+       break;
+#endif
+
+      /* input language code to internal one */
+      CNV_INPUT (line);
+
+      /* special case - first char is ! */
+      if (*line == '!')
+       {
+         system(line + 1);
+         continue;
+       }
+      
+      /* and get the first part of the command */
+      {
+       char *ptr = line;
+       if (!next_token(&ptr,tok,NULL)) continue;
+      }
+
+      if ((i = process_tok(tok)) >= 0)
+       commands[i].fn(InBuffer,OutBuffer);
+      else if (i == -2)
+       DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
+      else
+       DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
+    }
+  
+  cli_send_logout();
+  return(True);
+}
+
+/****************************************************************************
+usage on the program
+****************************************************************************/
+static void usage(char *pname)
+{
+  DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
+          pname));
+
+  DEBUG(0,("\nVersion %s\n",VERSION));
+  DEBUG(0,("\t-p port               connect to the specified port\n"));
+  DEBUG(0,("\t-d debuglevel         set the debuglevel\n"));
+  DEBUG(0,("\t-l log basename.      Basename for log/debug files\n"));
+  DEBUG(0,("\t-n netbios name.      Use this name as my netbios name\n"));
+  DEBUG(0,("\t-N                    don't ask for a password\n"));
+  DEBUG(0,("\t-P                    connect to service as a printer\n"));
+  DEBUG(0,("\t-M host               send a winpopup message to the host\n"));
+  DEBUG(0,("\t-m max protocol       set the max protocol level\n"));
+  DEBUG(0,("\t-L host               get a list of shares available on a host\n"));
+  DEBUG(0,("\t-I dest IP            use this IP to connect to\n"));
+  DEBUG(0,("\t-E                    write messages to stderr instead of stdout\n"));
+  DEBUG(0,("\t-U username           set the network username\n"));
+  DEBUG(0,("\t-W workgroup          set the workgroup name\n"));
+  DEBUG(0,("\t-c command string     execute semicolon separated commands\n"));
+  DEBUG(0,("\t-t terminal code      terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
+  DEBUG(0,("\t-T<c|x>IXgbNa          command line tar\n"));
+  DEBUG(0,("\t-D directory          start from directory\n"));
+  DEBUG(0,("\n"));
+}
+
+/****************************************************************************
+  main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+  fstring base_directory;
+  char *pname = argv[0];
+  int port = SMB_PORT;
+  int opt;
+  extern FILE *dbf;
+  extern char *optarg;
+  extern int optind;
+  pstring query_host;
+  BOOL nt_domain_logon = False;
+  static pstring servicesf = CONFIGFILE;
+  pstring term_code;
+  char *p;
+
+#ifdef KANJI
+  strcpy(term_code, KANJI);
+#else /* KANJI */
+  *term_code = 0;
+#endif /* KANJI */
+
+  *query_host = 0;
+  *base_directory = 0;
+
+  DEBUGLEVEL = 2;
+
+  setup_logging(pname,True);
+
+  TimeInit();
+  charset_initialise();
+
+  pid = getpid();
+  uid = getuid();
+  gid = getgid();
+  mid = pid + 100;
+  myumask = umask(0);
+  umask(myumask);
+
+  if (getenv("USER"))
+  {
+    strcpy(username,getenv("USER"));
+
+    /* modification to support userid%passwd syntax in the USER var
+       25.Aug.97, jdblair@uab.edu */
+
+    if ((p=strchr(username,'%')))
+    {
+      *p = 0;
+      strcpy(password,p+1);
+      got_pass = True;
+      memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
+    }
+    strupper(username);
+  }
+
+ /* modification to support PASSWD environmental var
+  25.Aug.97, jdblair@uab.edu */
+
+  if (getenv("PASSWD"))
+    strcpy(password,getenv("PASSWD"));
+
+  if (*username == 0 && getenv("LOGNAME"))
+    {
+      strcpy(username,getenv("LOGNAME"));
+      strupper(username);
+    }
+
+  if (argc < 2)
+    {
+      usage(pname);
+      exit(1);
+    }
+  
+  if (*argv[1] != '-')
+    {
+
+      strcpy(service,argv[1]);  
+      /* Convert any '/' characters in the service name to '\' characters */
+      string_replace( service, '/','\\');
+      argc--;
+      argv++;
+
+      if (count_chars(service,'\\') < 3)
+       {
+         usage(pname);
+         printf("\n%s: Not enough '\\' characters in service\n",service);
+         exit(1);
+       }
+
+/*
+      if (count_chars(service,'\\') > 3)
+       {
+         usage(pname);
+         printf("\n%s: Too many '\\' characters in service\n",service);
+         exit(1);
+       }
+       */
+
+      if (argc > 1 && (*argv[1] != '-'))
+       {
+         got_pass = True;
+         strcpy(password,argv[1]);  
+         memset(argv[1],'X',strlen(argv[1]));
+         argc--;
+         argv++;
+       }
+    }
+
+  while ((opt = 
+         getopt(argc, argv,"s:B:O:M:S:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
+    switch (opt)
+      {
+      case 'm':
+       max_protocol = interpret_protocol(optarg,max_protocol);
+       break;
+      case 'O':
+       strcpy(user_socket_options,optarg);
+       break;  
+      case 'S':
+       strcpy(desthost,optarg);
+       strupper(desthost);
+       nt_domain_logon = True;
+       break;
+      case 'B':
+       iface_set_default(NULL,optarg,NULL);
+       break;
+      case 'D':
+       strcpy(base_directory,optarg);
+       break;
+      case 'i':
+       strcpy(scope,optarg);
+       break;
+      case 'U':
+       {
+         char *lp;
+       strcpy(username,optarg);
+       if ((lp=strchr(username,'%')))
+         {
+           *lp = 0;
+           strcpy(password,lp+1);
+           got_pass = True;
+           memset(strchr(optarg,'%')+1,'X',strlen(password));
+         }
+       }
+           
+       break;
+      case 'W':
+       strcpy(workgroup,optarg);
+       break;
+      case 'E':
+       dbf = stderr;
+       break;
+      case 'I':
+       {
+         dest_ip = *interpret_addr2(optarg);
+         if (zero_ip(dest_ip)) exit(1);
+         have_ip = True;
+       }
+       break;
+      case 'n':
+       strcpy(myname,optarg);
+       break;
+      case 'N':
+       got_pass = True;
+       break;
+      case 'd':
+       if (*optarg == 'A')
+         DEBUGLEVEL = 10000;
+       else
+         DEBUGLEVEL = atoi(optarg);
+       break;
+      case 'l':
+       sprintf(debugf,"%s.client",optarg);
+       break;
+      case 'p':
+       port = atoi(optarg);
+       break;
+      case 'c':
+       cmdstr = optarg;
+       got_pass = True;
+       break;
+      case 'h':
+       usage(pname);
+       exit(0);
+       break;
+      case 's':
+       strcpy(servicesf, optarg);
+       break;
+      case 't':
+        strcpy(term_code, optarg);
+       break;
+      default:
+       usage(pname);
+       exit(1);
+      }
+
+  if (!*query_host && !*service)
+    {
+      usage(pname);
+      exit(1);
+    }
+
+
+  DEBUG(3,("%s client started (version %s)\n",timestring(),VERSION));
+
+  if(!get_myname(myhostname,NULL))
+  {
+    DEBUG(0,("Failed to get my hostname.\n"));
+  }
+
+  if (!lp_load(servicesf,True)) {
+    fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
+  }
+
+  codepage_initialise(lp_client_code_page());
+
+  if(lp_client_code_page() == KANJI_CODEPAGE)
+  {
+        if (!setup_term_code (term_code))
+    {
+            DEBUG(0, ("%s: unknown terminal code name\n", optarg));
+            usage (pname);
+            exit (1);
+        }
+  }
+
+  if (*workgroup == 0)
+    strcpy(workgroup,lp_workgroup());
+
+  load_interfaces();
+  get_myname((*myname)?NULL:myname,NULL);  
+  strupper(myname);
+
+#ifdef NTDOMAIN
+
+       if (nt_domain_logon)
+       {
+               int ret = 0;
+               sprintf(service,"\\\\%s\\IPC$",query_host);
+               strupper(service);
+               connect_as_ipc = True;
+
+               DEBUG(5,("NT Domain Logon.  Service: %s\n", service));
+
+               if (cli_open_sockets(port))
+               {
+                       if (!cli_send_login(NULL,NULL,True,True,NULL)) return(1);
+
+                       do_nt_login(desthost, myhostname, Client, cnum);
+
+                       cli_send_logout();
+                       close_sockets();
+               }
+
+               return(ret);
+       }
+#endif 
+
+  if (cli_open_sockets(port))
+    {
+      if (!process(base_directory))
+       {
+         close_sockets();
+         return(1);
+       }
+      close_sockets();
+    }
+  else
+    return(1);
+
+  return(0);
+}
diff --git a/source/client/smbumount.c b/source/client/smbumount.c
new file mode 100644 (file)
index 0000000..304da24
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ *  smbumount.c
+ *
+ *  Copyright (C) 1995 by Volker Lendecke
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+/* #include <sys/wait.h> */  /* generates a warning here */
+extern pid_t waitpid(pid_t, int *, int);
+#include <sys/errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <mntent.h>
+
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <linux/smb.h>
+#include <linux/smb_mount.h>
+#include <linux/smb_fs.h>
+
+static char *progname;
+
+static void
+usage(void)
+{
+        printf("usage: %s mount-point\n", progname);
+}
+
+static int
+umount_ok(const char *mount_point)
+{
+        int fid = open(mount_point, O_RDONLY, 0);
+        uid_t mount_uid;
+
+        if (fid == -1) {
+                fprintf(stderr, "Could not open %s: %s\n",
+                        mount_point, strerror(errno));
+                return -1;
+        }
+        
+        if (ioctl(fid, SMB_IOC_GETMOUNTUID, &mount_uid) != 0) {
+                fprintf(stderr, "%s probably not smb-filesystem\n",
+                        mount_point);
+                return -1;
+        }
+
+        if (   (getuid() != 0)
+            && (mount_uid != getuid())) {
+                fprintf(stderr, "You are not allowed to umount %s\n",
+                        mount_point);
+                return -1;
+        }
+
+        close(fid);
+        return 0;
+}
+
+/* Make a canonical pathname from PATH.  Returns a freshly malloced string.
+   It is up the *caller* to ensure that the PATH is sensible.  i.e.
+   canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.''
+   is not a legal pathname for ``/dev/fd0.''  Anything we cannot parse
+   we return unmodified.   */
+char *
+canonicalize (const char *path)
+{
+       char *canonical = malloc (PATH_MAX + 1);
+
+       if (strlen(path) > PATH_MAX)
+       {
+               fprintf(stderr, "Mount point string too long\n");
+               return NULL;
+       }
+
+       if (path == NULL)
+               return NULL;
+  
+       if (realpath (path, canonical))
+               return canonical;
+
+       strcpy (canonical, path);
+       return canonical;
+}
+
+
+int 
+main(int argc, char *argv[])
+{
+        int fd;
+
+        char* mount_point;
+
+        struct mntent *mnt;
+        FILE* mtab;
+        FILE* new_mtab;
+
+        progname = argv[0];
+
+        if (argc != 2) {
+                usage();
+                exit(1);
+        }
+
+        if (geteuid() != 0) {
+                fprintf(stderr, "%s must be installed suid root\n", progname);
+                exit(1);
+        }
+
+        mount_point = canonicalize(argv[1]);
+
+       if (mount_point == NULL)
+       {
+               exit(1);
+       }
+
+        if (umount_ok(mount_point) != 0) {
+                exit(1);
+        }
+
+        if (umount(mount_point) != 0) {
+                fprintf(stderr, "Could not umount %s: %s\n",
+                        mount_point, strerror(errno));
+                exit(1);
+        }
+
+        if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)
+        {
+                fprintf(stderr, "Can't get "MOUNTED"~ lock file");
+                return 1;
+        }
+        close(fd);
+       
+        if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
+                fprintf(stderr, "Can't open " MOUNTED ": %s\n",
+                        strerror(errno));
+                return 1;
+        }
+
+#define MOUNTED_TMP MOUNTED".tmp"
+
+        if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
+                fprintf(stderr, "Can't open " MOUNTED_TMP ": %s\n",
+                        strerror(errno));
+                endmntent(mtab);
+                return 1;
+        }
+
+        while ((mnt = getmntent(mtab)) != NULL) {
+                if (strcmp(mnt->mnt_dir, mount_point) != 0) {
+                        addmntent(new_mtab, mnt);
+                }
+        }
+
+        endmntent(mtab);
+
+        if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
+                fprintf(stderr, "Error changing mode of %s: %s\n",
+                        MOUNTED_TMP, strerror(errno));
+                exit(1);
+        }
+
+        endmntent(new_mtab);
+
+        if (rename(MOUNTED_TMP, MOUNTED) < 0) {
+                fprintf(stderr, "Cannot rename %s to %s: %s\n",
+                        MOUNTED, MOUNTED_TMP, strerror(errno));
+                exit(1);
+        }
+
+        if (unlink(MOUNTED"~") == -1)
+        {
+                fprintf(stderr, "Can't remove "MOUNTED"~");
+                return 1;
+        }
+
+       return 0;
+}