1175 lines
26 KiB
C
1175 lines
26 KiB
C
/*
|
|
* ncpmount.c
|
|
*
|
|
* Copyright (C) 1995, 1997 by Volker Lendecke
|
|
*
|
|
* 1/20/96 - Steven N. Hirsch (hirsch@emba.uvm.edu)
|
|
*
|
|
* If the ncpfs support is not loaded and we are using kerneld to
|
|
* autoload modules, then we don't want to do it here. I added
|
|
* a conditional which leaves out the test and load code.
|
|
*
|
|
* Even if we _do_ want ncpmount to load the module, passing a
|
|
* fully-qualified pathname to modprobe causes it to bypass a
|
|
* path search. This may lead to ncpfs.o not being found on
|
|
* some systems.
|
|
*/
|
|
|
|
#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>
|
|
extern pid_t waitpid(pid_t, int *, int);
|
|
#include <sys/errno.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <sys/mount.h>
|
|
#include <mntent.h>
|
|
#include "kernel/ipx.h"
|
|
#include <sys/ioctl.h>
|
|
#ifdef MOUNT3
|
|
#include <utmp.h>
|
|
#include <syslog.h>
|
|
#endif
|
|
|
|
#include "kernel/ncp.h"
|
|
#include "kernel/ncp_fs.h"
|
|
#include "ncpmount.h"
|
|
#include "ncplib.h"
|
|
#include "com_err.h"
|
|
#include "ncplib_err.h"
|
|
#ifdef NDS_SUPPORT
|
|
#include "ndslib.h"
|
|
#endif
|
|
|
|
#if defined(MOUNT2) && defined(MOUNT3)
|
|
#define MULTIVERSION_MOUNT 1
|
|
#else
|
|
#define MULTIVERSION_MOUNT 0
|
|
#endif
|
|
|
|
#if MULTIVERSION_MOUNT
|
|
#include <sys/utsname.h>
|
|
#endif
|
|
|
|
static char *progname;
|
|
static char mount_point[MAXPATHLEN + 1];
|
|
static void usage(void);
|
|
static void help(void);
|
|
|
|
/* Returns 0 if the filesystem is in the kernel after this routine
|
|
completes */
|
|
static int
|
|
load_ncpfs(void)
|
|
{
|
|
FILE *ffs;
|
|
char s[1024];
|
|
char *p, *p1;
|
|
pid_t pid;
|
|
int status;
|
|
|
|
/* Check if ncpfs is in the kernel */
|
|
ffs = fopen("/proc/filesystems", "r");
|
|
|
|
if (ffs == NULL)
|
|
{
|
|
perror("Error: \"/proc/filesystems\" could not be read:");
|
|
return -1;
|
|
}
|
|
p = NULL;
|
|
while (!feof(ffs))
|
|
{
|
|
p1 = fgets(s, sizeof(s), ffs);
|
|
if (p1)
|
|
{
|
|
p = strstr(s, "ncpfs");
|
|
if (p)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
fclose(ffs);
|
|
|
|
if (p)
|
|
{
|
|
return 0;
|
|
}
|
|
/* system() function without signal handling, from Stevens */
|
|
|
|
if ((pid = fork()) < 0)
|
|
{
|
|
return 1;
|
|
} else if (pid == 0)
|
|
{
|
|
/* child */
|
|
execl("/sbin/modprobe", "modprobe", "ncpfs", NULL);
|
|
_exit(127); /* execl error */
|
|
} else
|
|
{
|
|
/* parent */
|
|
while (waitpid(pid, &status, 0) < 0)
|
|
{
|
|
if (errno != EINTR)
|
|
{
|
|
status = -1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
#ifdef MOUNT3
|
|
static int process_connection(int wdog_fd, int msg_fd);
|
|
#endif
|
|
|
|
#if MULTIVERSION_MOUNT
|
|
int getmountver(void) {
|
|
struct utsname name;
|
|
int maj, mid;
|
|
int ver;
|
|
|
|
if (uname(&name)) {
|
|
fprintf(stderr, "Cannot get kernel release\n");
|
|
exit(1);
|
|
}
|
|
if (sscanf(name.release, "%d.%d", &maj, &mid) != 2) {
|
|
fprintf(stderr, "Cannot convert kernel release \"%s\" to number\n", name.release);
|
|
exit(1);
|
|
}
|
|
ver = maj*0x10000 + mid*0x100;
|
|
if (ver < 0x20100) {
|
|
#ifdef MOUNT2
|
|
return 2;
|
|
#else
|
|
fprintf(stderr, "This kernel requires mount version 2 which is not available\n");
|
|
exit(1);
|
|
#endif
|
|
}
|
|
#ifdef MOUNT3
|
|
return 3;
|
|
#else
|
|
fprintf(stderr, "This kernel requires mount version 3 which is not available\n");
|
|
exit(1);
|
|
#endif
|
|
}
|
|
#else
|
|
#ifdef MOUNT3
|
|
#define getmountver() 3
|
|
#else
|
|
#ifdef MOUNT2
|
|
#define getmountver() 2
|
|
#else
|
|
#error "You must define at least one of MOUNT2, MOUNT3"
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
/* 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;
|
|
}
|
|
|
|
#ifdef MOUNT3
|
|
/*
|
|
* This function changes the processes name as shown by the system.
|
|
* Stolen from Marcin Dalecki's modald :-)
|
|
*/
|
|
static void inststr(char *dst[], int argc, char *src)
|
|
{
|
|
/* stolen from the source to perl 4.036 (assigning to $0) */
|
|
char *ptr, *ptr2;
|
|
int count;
|
|
ptr = dst[0] + strlen(dst[0]);
|
|
for (count = 1; count < argc; count++) {
|
|
if (dst[count] == ptr + 1)
|
|
ptr += strlen(++ptr);
|
|
}
|
|
if (environ[0] == ptr + 1) {
|
|
for (count = 0; environ[count]; count++)
|
|
if (environ[count] == ptr + 1)
|
|
ptr += strlen(++ptr);
|
|
}
|
|
count = 0;
|
|
for (ptr2 = dst[0]; ptr2 <= ptr; ptr2++) {
|
|
*ptr2 = '\0';
|
|
count++;
|
|
}
|
|
strncpy(dst[0], src, count);
|
|
for (count = 1; count < argc; count++) {
|
|
dst[count] = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
struct ncp_mount_data_independent {
|
|
unsigned int ncp_fd;
|
|
unsigned int wdog_fd;
|
|
unsigned int message_fd;
|
|
uid_t mounted_uid;
|
|
struct sockaddr_ipx serv_addr;
|
|
unsigned char *server_name;
|
|
unsigned char *mount_point;
|
|
unsigned char *mounted_vol;
|
|
unsigned int time_out;
|
|
unsigned int retry_count;
|
|
struct {
|
|
unsigned int mount_soft:1;
|
|
unsigned int mount_intr:1;
|
|
unsigned int mount_strong:1;
|
|
unsigned int mount_no_os2:1;
|
|
unsigned int mount_no_nfs:1;
|
|
} flags;
|
|
uid_t uid;
|
|
gid_t gid;
|
|
mode_t file_mode;
|
|
mode_t dir_mode;
|
|
};
|
|
|
|
#ifdef MOUNT2
|
|
int ncp_mount_v2(const char* mount_name, unsigned long flags, const struct ncp_mount_data_independent* data) {
|
|
struct ncp_mount_data_v2 datav2;
|
|
|
|
datav2.version = NCP_MOUNT_VERSION_V2;
|
|
datav2.ncp_fd = data->ncp_fd;
|
|
datav2.wdog_fd = data->wdog_fd;
|
|
datav2.message_fd = data->message_fd;
|
|
datav2.mounted_uid = data->mounted_uid;
|
|
memcpy(&datav2.serv_addr, &data->serv_addr, sizeof(datav2.serv_addr));
|
|
strncpy(datav2.server_name, data->server_name, sizeof(datav2.server_name));
|
|
strncpy(datav2.mount_point, data->mount_point, sizeof(datav2.mount_point));
|
|
strncpy(datav2.mounted_vol, data->mounted_vol, sizeof(datav2.mounted_vol));
|
|
datav2.time_out = data->time_out;
|
|
datav2.retry_count = data->retry_count;
|
|
datav2.flags = 0;
|
|
datav2.flags |= data->flags.mount_soft?NCP_MOUNT2_SOFT:0;
|
|
datav2.flags |= data->flags.mount_intr?NCP_MOUNT2_INTR:0;
|
|
datav2.flags |= data->flags.mount_strong?NCP_MOUNT2_STRONG:0;
|
|
datav2.flags |= data->flags.mount_no_os2?NCP_MOUNT2_NO_OS2:0;
|
|
datav2.flags |= data->flags.mount_no_nfs?NCP_MOUNT2_NO_NFS:0;
|
|
datav2.uid = data->uid;
|
|
datav2.gid = data->gid;
|
|
datav2.file_mode = data->file_mode;
|
|
datav2.dir_mode = data->dir_mode;
|
|
return mount(mount_name, data->mount_point, "ncpfs", flags, (void*) &datav2);
|
|
}
|
|
#endif
|
|
|
|
#ifdef MOUNT3
|
|
int ncp_mount_v3(const char* mount_name, unsigned long flags, const struct ncp_mount_data_independent* data, int argc, char* argv[]) {
|
|
struct ncp_mount_data_v3 datav3;
|
|
int err;
|
|
|
|
datav3.version = NCP_MOUNT_VERSION_V3;
|
|
datav3.ncp_fd = data->ncp_fd;
|
|
datav3.mounted_uid = data->mounted_uid;
|
|
strncpy(datav3.mounted_vol, data->mounted_vol, sizeof(datav3.mounted_vol));
|
|
datav3.time_out = data->time_out;
|
|
datav3.retry_count = data->retry_count;
|
|
datav3.flags = 0;
|
|
datav3.flags |= data->flags.mount_soft?NCP_MOUNT3_SOFT:0;
|
|
datav3.flags |= data->flags.mount_intr?NCP_MOUNT3_INTR:0;
|
|
datav3.flags |= data->flags.mount_strong?NCP_MOUNT3_STRONG:0;
|
|
datav3.flags |= data->flags.mount_no_os2?NCP_MOUNT3_NO_OS2:0;
|
|
datav3.flags |= data->flags.mount_no_nfs?NCP_MOUNT3_NO_NFS:0;
|
|
datav3.uid = data->uid;
|
|
datav3.gid = data->gid;
|
|
datav3.file_mode = data->file_mode;
|
|
datav3.dir_mode = data->dir_mode;
|
|
connect(datav3.ncp_fd, (struct sockaddr *)&data->serv_addr, sizeof(data->serv_addr));
|
|
datav3.wdog_pid = fork();
|
|
if (datav3.wdog_pid < 0) {
|
|
fprintf(stderr, "could not fork: %s\n", strerror(errno));
|
|
exit(1);
|
|
}
|
|
if (datav3.wdog_pid == 0) {
|
|
/* Child */
|
|
inststr(argv, argc, "ncpd");
|
|
process_connection(data->wdog_fd, data->message_fd);
|
|
exit(0); /* Should not return from process_connection */
|
|
}
|
|
err=mount(mount_name, data->mount_point, "ncpfs", flags, (void*) &datav3);
|
|
if (err) {
|
|
/* Mount unsuccesful so we have to kill daemon */
|
|
/* If mount success, kernel kills daemon (at least in 2.1.79) */
|
|
kill(datav3.wdog_pid, SIGTERM);
|
|
}
|
|
return err;
|
|
}
|
|
#endif
|
|
|
|
int
|
|
ncp_mount_specific(struct ncp_conn* conn, int pathNS, const unsigned char* NWpath, int pathlen) {
|
|
int result;
|
|
|
|
#ifdef NCP_IOC_SETROOT
|
|
{
|
|
struct ncp_setroot_ioctl sr;
|
|
|
|
if (pathlen == 1) {
|
|
sr.volNumber = -1;
|
|
sr.namespace = -1;
|
|
sr.dirEntNum = 0;
|
|
} else {
|
|
struct nw_info_struct dirinfo;
|
|
|
|
result = ncp_obtain_file_or_subdir_info2(conn, pathNS, NW_NS_DOS,
|
|
0x8006, RIM_ALL, 0xFF, 0, 0, NWpath, pathlen, &dirinfo);
|
|
if (result) {
|
|
return -ENOENT;
|
|
}
|
|
if (!(dirinfo.attributes & htonl(0x10000000))) {
|
|
return -ENOTDIR;
|
|
}
|
|
sr.volNumber = dirinfo.volNumber;
|
|
sr.namespace = NW_NS_DOS;
|
|
sr.dirEntNum = dirinfo.dirEntNum;
|
|
}
|
|
result = ioctl(conn->mount_fid, NCP_IOC_SETROOT, &sr);
|
|
if (!result) {
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
if ((pathlen != 1) && (*NWpath != 1)) {
|
|
fprintf(stderr, "Remote directory is specified but "
|
|
#ifdef NCP_IOC_SETROOT
|
|
"kernel"
|
|
#else
|
|
"ncpmount"
|
|
#endif
|
|
" does not support subdir mounts\n");
|
|
return -ENOPKG;
|
|
}
|
|
if (ioctl(conn->mount_fid, NCP_IOC_CONN_LOGGED_IN, NULL) != 0) {
|
|
return -errno;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
struct ncp_mount_data_independent mdata;
|
|
struct stat st;
|
|
char mount_name[256];
|
|
|
|
int fd, result;
|
|
struct sockaddr_ipx addr;
|
|
struct sockaddr_ipx *server_addr;
|
|
int addrlen;
|
|
|
|
int upcase_password;
|
|
long err;
|
|
|
|
int um;
|
|
unsigned int flags;
|
|
|
|
struct mntent ment;
|
|
FILE *mtab;
|
|
|
|
char *server = NULL;
|
|
char *user = NULL;
|
|
char *password = NULL;
|
|
|
|
struct ncp_conn_spec *spec;
|
|
|
|
struct ncp_conn *conn;
|
|
|
|
int opt;
|
|
|
|
#ifdef NDS_SUPPORT
|
|
int force_bindery_login = 0;
|
|
#endif
|
|
|
|
char *tmp_mount;
|
|
int allow_multiple_connections = 0;
|
|
|
|
int mount_protocol_version = -1;
|
|
|
|
const char* remotepath = "/";
|
|
unsigned char NWpath[512];
|
|
int pathlen = 1;
|
|
NWpath[0] = 0;
|
|
|
|
progname = argv[0];
|
|
|
|
memzero(mdata);
|
|
memzero(spec);
|
|
|
|
mdata.mounted_uid = getuid();
|
|
|
|
if (geteuid() != 0)
|
|
{
|
|
fprintf(stderr, "%s must be installed suid root\n", progname);
|
|
exit(1);
|
|
}
|
|
mdata.uid = getuid();
|
|
mdata.gid = getgid();
|
|
um = umask(0);
|
|
umask(um);
|
|
mdata.file_mode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~um;
|
|
mdata.dir_mode = 0;
|
|
mdata.flags.mount_soft = 1;
|
|
mdata.flags.mount_intr = 0;
|
|
mdata.flags.mount_strong = 0;
|
|
mdata.flags.mount_no_os2 = 0;
|
|
mdata.flags.mount_no_nfs = 0;
|
|
mdata.time_out = 60;
|
|
mdata.retry_count = 5;
|
|
mdata.mounted_vol = "";
|
|
|
|
upcase_password = 1;
|
|
|
|
while ((opt = getopt(argc, argv, "CS:U:c:u:g:f:d:P:nh?vV:t:r:"
|
|
"sN:"
|
|
#ifdef NDS_SUPPORT
|
|
"b"
|
|
#endif
|
|
"m"
|
|
#ifdef MOUNT2
|
|
"2"
|
|
#endif
|
|
#ifdef MOUNT3
|
|
"3"
|
|
#endif
|
|
)) != EOF)
|
|
{
|
|
switch (opt)
|
|
{
|
|
case 'C':
|
|
upcase_password = 0;
|
|
break;
|
|
case 'S':
|
|
if (strlen(optarg) >= sizeof(spec->server))
|
|
{
|
|
fprintf(stderr, "Servername too long:%s\n",
|
|
optarg);
|
|
return 1;
|
|
}
|
|
server = optarg;
|
|
break;
|
|
case 'U':
|
|
user = optarg;
|
|
break;
|
|
case 'c':
|
|
if (isdigit(optarg[0]))
|
|
{
|
|
mdata.mounted_uid = atoi(optarg);
|
|
} else
|
|
{
|
|
struct passwd *pwd = getpwnam(optarg);
|
|
if (pwd == NULL)
|
|
{
|
|
fprintf(stderr, "Unknown user: %s\n",
|
|
optarg);
|
|
return 1;
|
|
}
|
|
mdata.mounted_uid = pwd->pw_uid;
|
|
}
|
|
break;
|
|
case 'u':
|
|
if (isdigit(optarg[0]))
|
|
{
|
|
mdata.uid = atoi(optarg);
|
|
} else
|
|
{
|
|
struct passwd *pwd = getpwnam(optarg);
|
|
if (pwd == NULL)
|
|
{
|
|
fprintf(stderr, "Unknown user: %s\n",
|
|
optarg);
|
|
return 1;
|
|
}
|
|
mdata.uid = pwd->pw_uid;
|
|
}
|
|
break;
|
|
case 'g':
|
|
if (isdigit(optarg[0]))
|
|
{
|
|
mdata.gid = atoi(optarg);
|
|
} else
|
|
{
|
|
struct group *grp = getgrnam(optarg);
|
|
if (grp == NULL)
|
|
{
|
|
fprintf(stderr, "Unknown group: %s\n",
|
|
optarg);
|
|
return 1;
|
|
}
|
|
mdata.gid = grp->gr_gid;
|
|
}
|
|
break;
|
|
case 'f':
|
|
mdata.file_mode = strtol(optarg, NULL, 8);
|
|
break;
|
|
case 'd':
|
|
mdata.dir_mode = strtol(optarg, NULL, 8);
|
|
break;
|
|
case 'P':
|
|
if (strlen(optarg) >= sizeof(spec->password))
|
|
{
|
|
printf("password too long\n");
|
|
exit(1);
|
|
}
|
|
password = optarg;
|
|
break;
|
|
case 'V':
|
|
pathlen = ncp_path_to_NW_format(optarg, NWpath, sizeof(NWpath));
|
|
remotepath = optarg;
|
|
if (pathlen < 0) {
|
|
fprintf(stderr, "Volume path invalid: %s\n", strerror(-pathlen));
|
|
exit(1);
|
|
};
|
|
if (pathlen == 1) {
|
|
mdata.mounted_vol = "";
|
|
remotepath = "/";
|
|
} else if (*NWpath != 1) {
|
|
mdata.mounted_vol = "dummy";
|
|
} else if (strlen(optarg) > NCP_VOLNAME_LEN) {
|
|
printf("Volume too long: %s\n", optarg);
|
|
exit(1);
|
|
} else {
|
|
mdata.mounted_vol=optarg;
|
|
}
|
|
break;
|
|
case 'n':
|
|
password = "";
|
|
break;
|
|
case 't':
|
|
mdata.time_out = atoi(optarg);
|
|
break;
|
|
case 'r':
|
|
mdata.retry_count = atoi(optarg);
|
|
break;
|
|
case 'h':
|
|
case '?':
|
|
help();
|
|
exit(1);
|
|
case 'v':
|
|
fprintf(stderr, "ncpfs version %s\n", NCPFS_VERSION);
|
|
exit(1);
|
|
case 's':
|
|
mdata.flags.mount_strong = 1;
|
|
break;
|
|
#ifdef NDS_SUPPORT
|
|
case 'b':
|
|
force_bindery_login = 1;
|
|
break;
|
|
#endif
|
|
case 'm':
|
|
allow_multiple_connections = 1;
|
|
break;
|
|
#ifdef MOUNT2
|
|
case '2':
|
|
mount_protocol_version = 2;
|
|
break;
|
|
#endif
|
|
#ifdef MOUNT3
|
|
case '3':
|
|
mount_protocol_version = 3;
|
|
break;
|
|
#endif
|
|
case 'N':
|
|
{
|
|
char *inp = optarg;
|
|
char *out;
|
|
|
|
while ((out = strtok(inp, ",;:"))!=NULL) {
|
|
inp=NULL;
|
|
if (!strcasecmp(out, "OS2"))
|
|
mdata.flags.mount_no_os2=1;
|
|
else if (!strcasecmp(out, "LONG"))
|
|
mdata.flags.mount_no_os2=1;
|
|
else if (!strcasecmp(out, "NFS"))
|
|
mdata.flags.mount_no_nfs=1;
|
|
else {
|
|
fprintf(stderr, "Unknown namespace \"%s\"\n", out);
|
|
return 128;
|
|
}
|
|
}
|
|
};
|
|
break;
|
|
|
|
default:
|
|
usage();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (mount_protocol_version < 0) {
|
|
mount_protocol_version = getmountver();
|
|
}
|
|
if ((spec = ncp_find_conn_spec2(server, user, password, 1, mdata.uid, allow_multiple_connections, &err))
|
|
== NULL)
|
|
{
|
|
com_err(progname, err, "in find_conn_spec");
|
|
exit(1);
|
|
}
|
|
if (upcase_password != 0)
|
|
{
|
|
str_upper(spec->password);
|
|
}
|
|
if (optind != argc - 1)
|
|
{
|
|
usage();
|
|
return -1;
|
|
}
|
|
realpath(argv[optind], mount_point);
|
|
|
|
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 to mount on %s: %s\n",
|
|
mount_point, strerror(errno));
|
|
exit(1);
|
|
}
|
|
/* Check if the ncpfs filesystem is in the kernel. If not, attempt
|
|
* to load the ncpfs module */
|
|
if (load_ncpfs() != 0)
|
|
{
|
|
fprintf(stderr, "Error: Unable to load ncpfs, exiting...\n");
|
|
exit(1);
|
|
}
|
|
|
|
mdata.server_name = spec->server;
|
|
|
|
if (mdata.dir_mode == 0)
|
|
{
|
|
mdata.dir_mode = mdata.file_mode;
|
|
if ((mdata.dir_mode & S_IRUSR) != 0)
|
|
mdata.dir_mode |= S_IXUSR;
|
|
if ((mdata.dir_mode & S_IRGRP) != 0)
|
|
mdata.dir_mode |= S_IXGRP;
|
|
if ((mdata.dir_mode & S_IROTH) != 0)
|
|
mdata.dir_mode |= S_IXOTH;
|
|
}
|
|
if ((!allow_multiple_connections)&&
|
|
((tmp_mount = ncp_find_permanent(spec)) != NULL))
|
|
{
|
|
fprintf(stderr,
|
|
"You already have mounted server %s\nas user "
|
|
"%s\non mount point %s\n", spec->server, spec->user,
|
|
tmp_mount);
|
|
exit(1);
|
|
}
|
|
if ((server_addr = ncp_find_fileserver(spec->server, &err)) == NULL)
|
|
{
|
|
com_err("ncpmount", err, "when trying to find %s",
|
|
spec->server);
|
|
exit(1);
|
|
}
|
|
mdata.serv_addr = *server_addr;
|
|
|
|
mdata.ncp_fd = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
|
|
if (mdata.ncp_fd == -1)
|
|
{
|
|
com_err("ncpmount", err, "opening ncp_socket");
|
|
exit(1);
|
|
}
|
|
mdata.wdog_fd = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
|
|
if (mdata.wdog_fd == -1)
|
|
{
|
|
fprintf(stderr, "could not open wdog socket: %s\n",
|
|
strerror(errno));
|
|
exit(1);
|
|
}
|
|
memzero(addr);
|
|
addr.sipx_family = AF_IPX;
|
|
addr.sipx_type = NCP_PTYPE;
|
|
|
|
if (bind(mdata.ncp_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
|
|
{
|
|
fprintf(stderr, "\nbind: %s\n",
|
|
strerror(errno));
|
|
fprintf(stderr,
|
|
"\nMaybe you want to use \n"
|
|
"ipx_configure --auto_interface=on --auto_primary=on\n"
|
|
"and try again after waiting a minute.\n\n");
|
|
exit(1);
|
|
}
|
|
addrlen = sizeof(addr);
|
|
|
|
if (getsockname(mdata.ncp_fd, (struct sockaddr *) &addr, &addrlen) == -1)
|
|
{
|
|
perror("getsockname ncp socket");
|
|
close(mdata.ncp_fd);
|
|
close(mdata.wdog_fd);
|
|
exit(1);
|
|
}
|
|
addr.sipx_port = htons(ntohs(addr.sipx_port) + 1);
|
|
|
|
if (bind(mdata.wdog_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
|
|
{
|
|
fprintf(stderr, "bind(wdog_sock, ): %s\n",
|
|
strerror(errno));
|
|
exit(1);
|
|
}
|
|
#if 1
|
|
|
|
mdata.message_fd = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
|
|
if (mdata.message_fd == -1)
|
|
{
|
|
fprintf(stderr, "could not open message socket: %s\n",
|
|
strerror(errno));
|
|
exit(1);
|
|
}
|
|
addr.sipx_port = htons(ntohs(addr.sipx_port) + 1);
|
|
|
|
if (bind(mdata.message_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
|
|
{
|
|
fprintf(stderr, "bind(message_sock, ): %s\n",
|
|
strerror(errno));
|
|
exit(1);
|
|
}
|
|
mdata.mount_point = mount_point;
|
|
#endif
|
|
|
|
flags = MS_MGC_VAL;
|
|
|
|
strcpy(mount_name, spec->server);
|
|
strcat(mount_name, "/");
|
|
strcat(mount_name, spec->user);
|
|
|
|
switch (mount_protocol_version) {
|
|
#ifdef MOUNT2
|
|
case 2:
|
|
result = ncp_mount_v2(mount_name, flags, &mdata);
|
|
break;
|
|
#endif
|
|
#ifdef MOUNT3
|
|
case 3:
|
|
result = ncp_mount_v3(mount_name, flags, &mdata, argc, argv);
|
|
break;
|
|
#endif
|
|
default:
|
|
fprintf(stderr, "Unsupported mount protocol version %d\n", mount_protocol_version);
|
|
exit(2);
|
|
}
|
|
if (result < 0)
|
|
{
|
|
com_err("ncpmount", errno, "in mount(2)");
|
|
exit(1);
|
|
}
|
|
if ((conn = ncp_open_mount(mount_point, &err)) == NULL)
|
|
{
|
|
com_err("ncpmount", err, "attempt to open mount point");
|
|
umount(mount_point);
|
|
exit(1);
|
|
}
|
|
#ifdef NDS_SUPPORT
|
|
if ((!force_bindery_login) && (!nds_get_tree_name(conn, NULL, 0)))
|
|
{
|
|
if ((err = nds_login_auth(conn, spec->user, spec->password)))
|
|
{
|
|
if ((err != NCPL_ET_REQUEST_ERROR) ||
|
|
(conn->completion != NDS_GRACE_PERIOD)) {
|
|
com_err("ncpmount", err, "in nds login");
|
|
if (err == NCPL_ET_REQUEST_ERROR)
|
|
fprintf(stderr, "NDS error code %d.\n",
|
|
conn->completion);
|
|
fprintf(stderr, "Login denied.\n");
|
|
ncp_close(conn);
|
|
umount(mount_point);
|
|
exit(1);
|
|
}
|
|
fprintf(stderr, "Your password has expired\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
if ((err = ncp_login_user(conn, spec->user, spec->password)) != 0)
|
|
{
|
|
struct nw_property p;
|
|
struct ncp_prop_login_control *l
|
|
= (struct ncp_prop_login_control *) &p;
|
|
|
|
if (conn->completion != NCP_GRACE_PERIOD)
|
|
{
|
|
com_err("ncpmount", err, "in login");
|
|
fprintf(stderr, "Login denied\n");
|
|
ncp_close(conn);
|
|
umount(mount_point);
|
|
exit(1);
|
|
}
|
|
fprintf(stderr, "Your password has expired\n");
|
|
|
|
if ((err = ncp_read_property_value(conn, NCP_BINDERY_USER,
|
|
spec->user, 1,
|
|
"LOGIN_CONTROL", &p)) == 0)
|
|
{
|
|
fprintf(stderr, "You have %d login attempts left\n",
|
|
l->GraceLogins);
|
|
}
|
|
}
|
|
#ifdef NDS_SUPPORT
|
|
}
|
|
#endif
|
|
if ((err = ncp_mount_specific(conn, NW_NS_DOS, NWpath, pathlen)) != 0)
|
|
{
|
|
fprintf(stderr, "Cannot access path \"%s\": %s\n", remotepath, strerror(-err));
|
|
ncp_close(conn);
|
|
umount(mount_point);
|
|
exit(1);
|
|
}
|
|
ncp_close(conn);
|
|
|
|
ment.mnt_fsname = mount_name;
|
|
ment.mnt_dir = mount_point;
|
|
ment.mnt_type = "ncpfs";
|
|
ment.mnt_opts = "rw";
|
|
ment.mnt_freq = 0;
|
|
ment.mnt_passno = 0;
|
|
|
|
if ((fd = open(MOUNTED "~", O_RDWR | O_CREAT | O_EXCL, 0600)) == -1)
|
|
{
|
|
fprintf(stderr, "Can't get " MOUNTED "~ lock file");
|
|
exit(1);
|
|
}
|
|
close(fd);
|
|
|
|
if ((mtab = setmntent(MOUNTED, "a+")) == NULL)
|
|
{
|
|
fprintf(stderr, "Can't open " MOUNTED);
|
|
exit(1);
|
|
}
|
|
if (addmntent(mtab, &ment) == 1)
|
|
{
|
|
fprintf(stderr, "Can't write mount entry");
|
|
exit(1);
|
|
}
|
|
if (fchmod(fileno(mtab), 0644) == -1)
|
|
{
|
|
fprintf(stderr, "Can't set perms on " MOUNTED);
|
|
exit(1);
|
|
}
|
|
endmntent(mtab);
|
|
|
|
if (unlink(MOUNTED "~") == -1)
|
|
{
|
|
fprintf(stderr, "Can't remove " MOUNTED "~");
|
|
exit(1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void usage(void)
|
|
{
|
|
printf("usage: %s [options] mount-point\n", progname);
|
|
printf("Try `%s -h' for more information\n", progname);
|
|
}
|
|
|
|
static void
|
|
help(void)
|
|
{
|
|
printf("\n");
|
|
printf("usage: %s [options] mount-point\n", progname);
|
|
printf("\n"
|
|
"-S server Server name to be used\n"
|
|
"-U username Username sent to server\n"
|
|
"-V volume Volume to mount, for NFS re-export\n"
|
|
"-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"
|
|
"-c uid uid to identify the connection to mount on\n"
|
|
" Only makes sense for root\n"
|
|
"-t time_out Waiting time (in 1/100s) to wait for\n"
|
|
" an answer from the server. Default: 60\n"
|
|
"-r retry_count Number of retry attempts. Default: 5\n"
|
|
"-C Don't convert password to uppercase\n"
|
|
"-P password Use this password\n"
|
|
"-n Do not use any password\n"
|
|
" If neither -P nor -n are given, you are\n"
|
|
" asked for a password.\n"
|
|
"-s Enable renaming/deletion of read-only files\n"
|
|
"-h print this help text\n"
|
|
"-v print ncpfs version number\n"
|
|
#ifdef NDS_SUPPORT
|
|
"-b Force bindery login to NDS servers\n"
|
|
#endif
|
|
"-m Allow multiple logins to server\n"
|
|
"-N os2,nfs Do not use specified namespaces on mounted volume\n"
|
|
"\n");
|
|
}
|
|
|
|
#ifdef MOUNT3
|
|
|
|
/* The following routines have been taken from util-linux-2.5's write.c */
|
|
|
|
/*
|
|
* term_chk - check that a terminal exists, and get the message bit
|
|
* and the access time
|
|
*/
|
|
static int
|
|
term_chk (char *tty, int *msgsokP, time_t * atimeP, int *showerror)
|
|
{
|
|
struct stat s;
|
|
char path[MAXPATHLEN];
|
|
|
|
(void) sprintf(path, "/dev/%s", tty);
|
|
if (stat(path, &s) < 0) {
|
|
if (showerror)
|
|
(void) fprintf(stderr,
|
|
"write: %s: %s\n", path, strerror(errno));
|
|
return (1);
|
|
}
|
|
*msgsokP = (s.st_mode & (S_IWRITE >> 3)) != 0; /* group write bit */
|
|
*atimeP = s.st_atime;
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* search_utmp - search utmp for the "best" terminal to write to
|
|
*
|
|
* Ignores terminals with messages disabled, and of the rest, returns
|
|
* the one with the most recent access time. Returns as value the number
|
|
* of the user's terminals with messages enabled, or -1 if the user is
|
|
* not logged in at all.
|
|
*
|
|
* Special case for writing to yourself - ignore the terminal you're
|
|
* writing from, unless that's the only terminal with messages enabled.
|
|
*/
|
|
static int
|
|
search_utmp (char *user, char *tty)
|
|
{
|
|
struct utmp u;
|
|
time_t bestatime, atime;
|
|
int ufd, nloggedttys, nttys, msgsok, user_is_me;
|
|
|
|
char atty[sizeof (u.ut_line) + 1];
|
|
|
|
if ((ufd = open (_PATH_UTMP, O_RDONLY)) < 0)
|
|
{
|
|
perror ("utmp");
|
|
return -1;
|
|
}
|
|
nloggedttys = nttys = 0;
|
|
bestatime = 0;
|
|
user_is_me = 0;
|
|
while (read (ufd, (char *) &u, sizeof (u)) == sizeof (u))
|
|
if (strncmp (user, u.ut_name, sizeof (u.ut_name)) == 0)
|
|
{
|
|
++nloggedttys;
|
|
|
|
(void) strncpy (atty, u.ut_line, sizeof (u.ut_line));
|
|
atty[sizeof (u.ut_line)] = '\0';
|
|
|
|
if (term_chk (atty, &msgsok, &atime, 0))
|
|
continue; /* bad term? skip */
|
|
if (!msgsok)
|
|
continue; /* skip ttys with msgs off */
|
|
|
|
if (u.ut_type != USER_PROCESS)
|
|
continue; /* it's not a valid entry */
|
|
|
|
++nttys;
|
|
if (atime > bestatime)
|
|
{
|
|
bestatime = atime;
|
|
(void) strcpy (tty, atty);
|
|
}
|
|
}
|
|
(void) close (ufd);
|
|
if (nloggedttys == 0)
|
|
{
|
|
(void) fprintf (stderr, "write: %s is not logged in\n", user);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
msg_received (void)
|
|
{
|
|
struct ncp_conn *conn;
|
|
char message[256];
|
|
struct ncp_fs_info info;
|
|
struct passwd *pwd;
|
|
char tty[256];
|
|
char tty_path[256];
|
|
FILE *tty_file;
|
|
FILE *mtab;
|
|
struct mntent *mnt;
|
|
long err;
|
|
|
|
openlog ("nwmsg", LOG_PID, LOG_LPR);
|
|
|
|
if ((conn = ncp_open_mount(mount_point, &err)) == NULL) {
|
|
return;
|
|
}
|
|
if (ncp_get_broadcast_message(conn, message) != 0) {
|
|
ncp_close(conn);
|
|
return;
|
|
}
|
|
if (strlen(message) == 0) {
|
|
syslog(LOG_DEBUG, "no message");
|
|
ncp_close(conn);
|
|
return;
|
|
}
|
|
syslog(LOG_DEBUG, "message: %s", message);
|
|
|
|
info.version = NCP_GET_FS_INFO_VERSION;
|
|
if (ioctl(conn->mount_fid, NCP_IOC_GET_FS_INFO, &info) < 0) {
|
|
ncp_close(conn);
|
|
return;
|
|
}
|
|
ncp_close(conn);
|
|
|
|
if ((pwd = getpwuid(info.mounted_uid)) == NULL) {
|
|
fprintf(stderr, "%s: user %d not known\n",
|
|
progname, info.mounted_uid);
|
|
return;
|
|
}
|
|
if ((mtab = fopen(MOUNTED, "r")) == NULL) {
|
|
fprintf(stderr, "%s: can't open %s\n",
|
|
progname, MOUNTED);
|
|
return;
|
|
}
|
|
while ((mnt = getmntent(mtab)) != NULL) {
|
|
if (strcmp(mnt->mnt_dir, mount_point) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (mnt == NULL) {
|
|
syslog(LOG_DEBUG, "cannot find mtab entry\n");
|
|
}
|
|
if (search_utmp(pwd->pw_name, tty) != 0) {
|
|
return;
|
|
}
|
|
sprintf(tty_path, "/dev/%s", tty);
|
|
if ((tty_file = fopen(tty_path, "w")) == NULL) {
|
|
fprintf(stderr, "%s: cannot open %s: %s\n",
|
|
progname, tty_path, strerror(errno));
|
|
return;
|
|
}
|
|
fprintf(tty_file, "\r\n\007\007\007Message from NetWare Server: %s\r\n",
|
|
mnt->mnt_fsname);
|
|
fprintf(tty_file, "%s\r\n", message);
|
|
fclose(tty_file);
|
|
fclose(mtab);
|
|
return;
|
|
}
|
|
|
|
/* MSG_DONTWAIT defined and module can run only on 2.1.x kernel */
|
|
#if defined(MSG_DONTWAIT) && !defined(MOUNT2)
|
|
#define recvfrom_notm(fd,buf,ln,sender,addrlen) recvfrom(fd,buf,ln,MSG_DONTWAIT,sender,addrlen)
|
|
#else
|
|
int recvfrom_notm(int fd, void* buf, size_t len, struct sockaddr* sender, size_t* addrlen) {
|
|
int ret;
|
|
int flg;
|
|
|
|
flg = fcntl(fd, F_GETFL);
|
|
if (flg == -1) return -1;
|
|
fcntl(fd, F_SETFL, flg | O_NONBLOCK);
|
|
ret = recvfrom(fd, buf, len, 0, sender, addrlen);
|
|
fcntl(fd, F_SETFL, flg);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
process_msg_packet (int msg_fd)
|
|
{
|
|
struct sockaddr_ipx sender;
|
|
int addrlen = sizeof(sender);
|
|
char buf[1024];
|
|
|
|
if (recvfrom_notm(msg_fd, buf, sizeof(buf),
|
|
(struct sockaddr *) &sender, &addrlen) <= 0) {
|
|
return;
|
|
}
|
|
msg_received();
|
|
}
|
|
|
|
static void
|
|
process_wdog_packet (int wdog_fd)
|
|
{
|
|
struct sockaddr_ipx sender;
|
|
int addrlen = sizeof(sender);
|
|
char buf[2];
|
|
|
|
if (recvfrom_notm(wdog_fd, buf, sizeof(buf),
|
|
(struct sockaddr *) &sender, &addrlen) < sizeof(buf)) {
|
|
return;
|
|
}
|
|
if (buf[1] != '?') {
|
|
return;
|
|
}
|
|
buf[1] = 'Y';
|
|
sendto(wdog_fd, buf, 2, 0, (struct sockaddr *) &sender, addrlen);
|
|
}
|
|
|
|
static int
|
|
process_connection (int wdog_fd, int msg_fd)
|
|
{
|
|
int i;
|
|
int result;
|
|
int max;
|
|
|
|
chdir("/");
|
|
setsid();
|
|
for (i = 0; i < NR_OPEN; i++) {
|
|
if ((i == wdog_fd) || (i == msg_fd)) {
|
|
continue;
|
|
}
|
|
close(i);
|
|
}
|
|
|
|
max = (wdog_fd > msg_fd ? wdog_fd : msg_fd) + 1;
|
|
|
|
while (1) {
|
|
fd_set rd;
|
|
|
|
FD_ZERO(&rd);
|
|
FD_SET(wdog_fd, &rd);
|
|
FD_SET(msg_fd, &rd);
|
|
|
|
if ((result = select(max, &rd, NULL, NULL, NULL)) == -1) {
|
|
exit(0);
|
|
}
|
|
if (FD_ISSET(wdog_fd, &rd)) {
|
|
process_wdog_packet(wdog_fd);
|
|
}
|
|
if (FD_ISSET(msg_fd, &rd)) {
|
|
process_msg_packet(msg_fd);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif
|