/*
- 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;
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);
}
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 );
/*****************************************************
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();
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;
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;
}
}
}
+ /* 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;
*/
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;
}
if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
DEBUG(0,("%d: Can't open " MOUNTED ": %s\n",
- getpid(), strerror(errno)));
+ sys_getpid(), strerror(errno)));
return;
}
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;
}
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;
}
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;
}
}
* 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();
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;
}
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;
}
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) {
}
/* 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;
}
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];
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";
}
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);
}
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
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));
}
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\
");
}
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);
if (!strcmp(opts, "username") ||
!strcmp(opts, "logon")) {
char *lp;
+ got_user = True;
pstrcpy(username,opteq+1);
if ((lp=strchr_m(username,'%'))) {
*lp = 0;
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);
}
} 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);
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);
{
extern char *optarg;
extern int optind;
- static pstring servicesf = CONFIGFILE;
char *p;
DEBUGLEVEL = 1;
/* 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")) {
got_pass = True;
memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(password));
}
- strupper(username);
+ strupper_m(username);
}
if (getenv("PASSWD")) {
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);
}
if (!*my_netbios_name) {
pstrcpy(my_netbios_name, myhostname());
}
- strupper(my_netbios_name);
+ strupper_m(my_netbios_name);
init_mount();
return 0;