Files
ncpfs/sutil/ncpmount.c
ncpfs archive import ef8405088b Import ncpfs 2.2.4
2026-04-28 20:40:00 +02:00

755 lines
18 KiB
C

/*
ncpmount.c
Copyright (C) 1995, 1997 by Volker Lendecke
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Revision history:
0.00 1995 Volker Lendecke
Initial release.
0.01 1996, January 20 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.
0.02 1998, November 28 Wolfram Pienkoss <wp@bszh.de>
NLS added. Thanks Petr Vandrovec for the idea of charset select
and many hints.
0.03 1999, September 9 Petr Vandrovec <vandrove@vc.cvut.cz>
Added ttl option.
Reverted back to exec("/sbin/nwmsg") for incomming messages.
This allows tknwmsg work again...
0.04 1999, September 9 Paul Rensing <paulr@dragonsys.com>
Added resetting behavior for SIGTERM. This fixes ncpmount from
perl scripts.
1.00 1999, November 20 Petr Vandrovec <vandrove@vc.cvut.cz>
Added license.
Replaced nds_get_tree_name with NWIsDSServer.
1.01 2000, January 16 Petr Vandrovec <vandrove@vc.cvut.cz>
Changes for 32bit uids.
1.02 2000, April 4 Petr Vandrovec <vandrove@vc.cvut.cz>
Changed /sbin/nwmsg to $(sbindir)/nwmsg (recomended by
MandrakeSoft).
1.03 2000, April 28 Petr Vandrovec <vandrove@vc.cvut.cz>
Silently ignore 'noauto' option, mount-2.10f (at least)
passes it down to mount.ncp.
1.04 2000, June 25 Petr Vandrovec <vandrove@vc.cvut.cz>
Add NCP/TCP support.
1.05 2000, October 28 Petr Vandrovec <vandrove@vc.cvut.cz>
Added nfsextras support.
Changed some constants to symbolic names (SA_*)
1.06 2001, January 7 Patrick Pollet <patrick.pollet@insa-lyon.fr>
Made all error exit codes differents to help debug Pam module
1.07 2001, February 25 Petr Vandrovec <vandrove@vc.cvut.cz>
Added UNIX socket handling for global features.
1.08 2001, September 23 Petr Vandrovec <vandrove@vc.cvut.cz>
Fix multiple mounts when using UDP or TCP.
1.09 2002, January 20 Petr Vandrovec <vandrove@vc.cvut.cz>
Verify uid/gid/owner arguments carefully. It should not be
security problem, but who knows which program derives some
security information from file uid/gid...
1.10 2002, February 27 Petr Vandrovec <vandrove@vc.cvut.cz>
Erase password quickly from command line.
Clear command line completely.
Simpler command line handling.
1.11 2002, April 19 Peter Schwindt <schwindt@ba-loerrach.de>
Add option -A to the help text.
*/
#include "ncpm_common.h"
#include "mount_login.h"
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ncp/ext/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>
#include <sys/errno.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/mount.h>
#include <mntent.h>
#include <ncp/kernel/ipx.h>
#include <ncp/nwclient.h>
#include <sys/ioctl.h>
#ifdef CONFIG_NATIVE_UNIX
#include <linux/un.h>
#endif
#include "private/libintl.h"
#define _(X) gettext(X)
#include "../lib/ncpi.h"
static void usage(void);
static void help(void);
void veprintf(const char* message, va_list ap) {
vfprintf(stderr, message, ap);
}
static void opt_set_tree(struct ncp_mount_info* info, const char* param) {
if (strlen(param) > MAX_TREE_NAME_CHARS) {
errexit(65, _("Specified tree name `%s' is too long\n"), param);
}
info->tree = param;
}
static void opt_set_bindery(struct ncp_mount_info* info, unsigned int param) {
info->force_bindery_login = param;
}
static void opt_set_volume(struct ncp_mount_info* info, const char* param) {
info->volume = param;
}
static void opt_set_allow_multiple(struct ncp_mount_info* info, unsigned int param) {
info->allow_multiple_connections = param;
}
static void opt_set_auth(struct ncp_mount_info* info, const char* param) {
info->auth_src = param;
}
static struct optinfo opts[] = {
{'T', "tree", FN_STRING, opt_set_tree, 0},
{'b', "bindery", FN_NOPARAM, opt_set_bindery, 1},
{'V', "volume", FN_STRING, opt_set_volume, 0},
{'m', "multiple", FN_NOPARAM, opt_set_allow_multiple, 1},
{'a', "auth", FN_STRING, opt_set_auth, 0},
{0, NULL, 0, NULL, 0}
};
int
main(int argc, char *argv[])
{
struct ncp_mount_info info;
struct stat st;
char mount_name[256];
#ifdef NDS_SUPPORT
NWDSContextHandle ctx;
NWCONN_HANDLE auth_conn;
#endif
int result;
long err;
struct ncp_conn_spec spec;
struct ncp_conn *conn;
int opt;
#ifdef CONFIG_NATIVE_UNIX
struct sockaddr_un server_un;
#endif
char *tmp_mount;
int mount_ncp = 0;
int opt_n = 0;
int opt_v = 0;
verify_argv(argc, argv);
setlocale(LC_ALL, "");
bindtextdomain(NCPFS_PACKAGE, LOCALEDIR);
textdomain(NCPFS_PACKAGE);
init_mount_info(&info);
while ((opt = getopt(argc, argv, "a:CS:U:c:u:g:f:d:P:nh?vV:t:r:o:"
"sN:y:p:bi:mA:T:"
#ifdef MOUNT2
"2"
#endif
#ifdef MOUNT3
"345"
#endif
)) != EOF)
{
char tmpopt[2];
switch (opt)
{
case 'C':
case 's':
case 'b':
case 'm':
optarg = NULL;
case 'a':
case 'S':
case 'T':
case 'U':
case 'c':
case 'u':
case 'g':
case 'f':
case 'd':
case 'V':
case 't':
case 'r':
case 'i':
case 'A':
case 'y':
case 'p':
tmpopt[0] = opt;
tmpopt[1] = 0;
proc_option(opts, &info, tmpopt, optarg);
break;
case 'P':
if (!mount_ncp) opt_n = 0; /* clear -n (nopasswd) */
tmpopt[0] = opt;
tmpopt[1] = 0;
proc_option(opts, &info, tmpopt, optarg);
break;
case 'n':
opt_n = 1; /* no passwd or no update /etc/fstab */
break;
case 'h':
case '?':
help();
exit(27);
case 'v':
opt_v = 1; /* version or verbose */
break;
#ifdef MOUNT2
case '2':
info.version = 2;
break;
#endif /* MOUNT2 */
#ifdef MOUNT3
case '3':
info.version = 3;
break;
case '4':
info.version = 4;
break;
case '5':
info.version = 5;
break;
#endif /* MOUNT3 */
case 'N':
{
char *inp;
char *out;
inp = optarg;
while ((out = strtok(inp, ",;:"))!=NULL) {
inp=NULL;
if (!strcasecmp(out, "OS2"))
proc_option(opts, &info, "noos2", NULL);
else if (!strcasecmp(out, "LONG"))
proc_option(opts, &info, "nolong", NULL);
else if (!strcasecmp(out, "NFS"))
proc_option(opts, &info, "nonfs", NULL);
else {
errexit(128, _("Unknown namespace \"%s\"\n"), out);
}
}
};
break;
case 'o':
{
char* arg;
arg = optarg;
mount_ncp = 1;
while (arg) {
char* end;
char* parm;
arg += strspn(arg, " \t");
if (!*arg) break;
end = strchr(arg, ',');
if (end) *end++ = 0;
parm = strchr(arg, '=');
if (parm) *parm++ = 0;
proc_option(opts, &info, arg, parm);
arg = end;
};
}
break;
default:
usage();
return -1;
}
}
if (opt_n && !mount_ncp) {
opt_n = 0;
proc_option(opts, &info, "passwd", "");
}
if (opt_v && !mount_ncp) {
fprintf(stderr, _("ncpfs version %s\n"), NCPFS_VERSION);
exit(30);
}
if (optind < argc - 1) {
char* s;
char* u;
s = strdup(argv[optind++]);
if (s) {
u = strchr(s, '/');
if (u) *u++ = 0;
} else
u = NULL;
if (!info.server && !info.tree) info.server = s;
if (!info.user) info.user = u;
}
if (info.server && info.tree) {
errexit(66, _("Both tree and server name were specified. It is not allowed.\n"));
}
if (geteuid() != 0)
{
errexit(26, _("%s must be installed suid root\n"), progname);
}
if (optind != argc - 1)
{
usage();
return -1;
}
realpath(argv[optind], mount_point);
if (stat(mount_point, &st) == -1)
{
errexit(31, _("Could not find mount point %s: %s\n"),
mount_point, strerror(errno));
}
if (mount_ok(&st) != 0)
{
errexit(32, _("Cannot to mount on %s: %s\n"),
mount_point, strerror(errno));
}
get_passwd(&info);
if (myuid != info.mdata.mounted_uid) {
if (setreuid(info.mdata.mounted_uid, -1)) {
errexit(76, _("Cannot impersonate as requested: %s\n"), strerror(errno));
}
}
#ifdef NDS_SUPPORT
if (info.tree) {
static char vol[64];
static char serv[64];
nuint32 ctxf;
if (!info.volume) {
errexit(70, _("You must specify NDS volume name if you specified tree name.\n"));
}
err = NWDSCreateContextHandle(&ctx);
if (err) {
mycom_err(err, _("in create context"));
exit(68);
}
if (!NWDSGetContext(ctx, DCK_FLAGS, &ctxf)) {
ctxf |= DCV_XLATE_STRINGS | DCV_DEREF_ALIASES | DCV_TYPELESS_NAMES | DCV_DEREF_BASE_CLASS;
NWDSSetContext(ctx, DCK_FLAGS, &ctxf);
}
err = NWCCOpenConnByName(NULL, info.tree, NWCC_NAME_FORMAT_NDS_TREE,
NWCC_OPEN_NEW_CONN,
NWCC_RESERVED, &conn);
if (err) {
NWDSFreeContext(ctx);
mycom_err(err, _("in tree search"));
exit(67);
}
err = nds_login_auth(conn, info.user, info.password);
if (err) {
NWCCCloseConn(conn);
NWDSFreeContext(ctx);
mycom_err(err, _("in nds login"));
exit(68);
}
NWDSAddConnection(ctx, conn);
err = NWCXGetNDSVolumeServerAndResourceName(ctx,
info.volume, serv, sizeof(serv),
vol, sizeof(vol));
if (err) {
NWDSFreeContext(ctx);
NWCCCloseConn(conn);
mycom_err(err, _("in volume search"));
exit(69);
}
NWDSFreeContext(ctx);
NWCCCloseConn(conn);
info.server = serv;
strcpy(info.NWpath + 2, vol);
info.NWpath[0] = 1;
info.NWpath[1] = strlen(vol);
info.pathlen = strlen(vol) + 2;
} else
#endif
{
if (info.volume) {
info.pathlen = ncp_path_to_NW_format(info.volume, info.NWpath, sizeof(info.NWpath));
info.remote_path = info.volume;
if (info.pathlen < 0) {
errexit(18, _("Volume path `%s' is invalid: `%s'\n"), info.volume, strerror(-info.pathlen));
};
if (info.pathlen == 1) {
info.mdata.mounted_vol = "";
info.remote_path = "/";
} else if (info.NWpath[0] != 1) {
info.mdata.mounted_vol = "dummy";
} else if (strlen(info.volume) > NCP_VOLNAME_LEN) {
errexit(19, _("Volume name `%s' is too long\n"), info.volume);
} else {
info.mdata.mounted_vol = info.volume;
}
}
}
err = NWDSCreateContextHandle(&ctx);
if (err) {
mycom_err(err, _("in create context"));
exit(113);
}
if (info.auth_src) {
NWDSChar user[MAX_DN_BYTES];
err = ncp_open_mount(info.auth_src, &auth_conn);
if (err) {
NWDSFreeContext(ctx);
mycom_err(err, _("opening mount %s"), info.auth_src);
exit(114);
}
NWDSAddConnection(ctx, auth_conn);
err = NWDSWhoAmI(ctx, user);
if (err) {
NWDSFreeContext(ctx);
NWCCCloseConn(auth_conn);
mycom_err(err, _("retrieving user name"));
exit(117);
}
memset(&spec, 0, sizeof(spec));
strncpy(spec.server, info.server, sizeof(spec.server));
strncpy(spec.user, user, sizeof(spec.user));
} else {
if ((err = ncp_find_conn_spec3(info.server, info.user, info.password, 1,
info.mdata.uid, 1, &spec))
!= 0)
{
NWDSFreeContext(ctx);
mycom_err(err, _("in find_conn_spec"));
exit(33);
}
if (info.upcase_password != 0)
{
str_upper(spec.password);
}
auth_conn = NULL;
}
info.mdata.server_name = spec.server;
if (info.mdata.dir_mode == 0)
{
info.mdata.dir_mode = info.mdata.file_mode;
if ((info.mdata.dir_mode & S_IRUSR) != 0)
info.mdata.dir_mode |= S_IXUSR;
if ((info.mdata.dir_mode & S_IRGRP) != 0)
info.mdata.dir_mode |= S_IXGRP;
if ((info.mdata.dir_mode & S_IROTH) != 0)
info.mdata.dir_mode |= S_IXOTH;
}
#if defined(CONFIG_NATIVE_IP) || defined(CONFIG_NATIVE_UNIX)
if (info.server_name) {
#if defined(CONFIG_NATIVE_UNIX)
if (info.server_name[0] == '/') {
server_un.sun_family = AF_UNIX;
memcpy(server_un.sun_path, "\000ncpfs", 6);
memcpy(&info.mdata.serv_addr, &server_un, 16);
} else
#endif
#if defined(CONFIG_NATIVE_IP)
{
nuint tran;
if ((!info.allow_multiple_connections)&&
((tmp_mount = ncp_find_permanent(&spec)) != NULL))
{
NWDSFreeContext(ctx);
if (auth_conn) {
NWCCCloseConn(auth_conn);
}
fprintf(stderr,
_("You already have mounted server %s\nas user "
"%s\non mount point %s\n"), spec.server, spec.user,
tmp_mount);
exit(35);
}
tran = NT_UDP;
if (info.nt.valid && info.nt.value == NT_TCP) {
tran = info.nt.value;
}
err = ncp_find_server_addr(&info.server_name, OT_FILE_SERVER, (struct sockaddr*)&info.mdata.serv_addr,
sizeof(info.mdata.serv_addr), tran);
if (err) {
NWDSFreeContext(ctx);
if (auth_conn) {
NWCCCloseConn(auth_conn);
}
eprintf(_("Get host address `%s': %s\n"), info.server_name, strnwerror(err));
exit(1);
}
}
#else
{
goto ncpipx;
}
#endif
} else
#endif /* CONFIG_NATIVE_IP */
{
ncpipx:;
if ((!info.allow_multiple_connections)&&
((tmp_mount = ncp_find_permanent(&spec)) != NULL))
{
NWDSFreeContext(ctx);
if (auth_conn) {
NWCCCloseConn(auth_conn);
}
fprintf(stderr,
_("You already have mounted server %s\nas user "
"%s\non mount point %s\n"), spec.server, spec.user,
tmp_mount);
exit(35);
}
if ((err = ncp_find_fileserver(spec.server, (struct sockaddr*)&info.mdata.serv_addr, sizeof(info.mdata.serv_addr))) != 0)
{
NWDSFreeContext(ctx);
if (auth_conn) {
NWCCCloseConn(auth_conn);
}
mycom_err(err, _("when trying to find %s"),
spec.server);
exit(36);
}
}
err = proc_buildconn(&info);
if (err) {
NWDSFreeContext(ctx);
if (auth_conn) {
NWCCCloseConn(auth_conn);
}
exit(err);
}
info.mdata.mount_point = mount_point;
strcpy(mount_name, spec.server);
strcat(mount_name, "/");
strcat(mount_name, spec.user);
result = ncp_mount(mount_name, &info);
if (result)
{
NWDSFreeContext(ctx);
if (auth_conn) {
NWCCCloseConn(auth_conn);
}
mycom_err(result, _("in mount(2)"));
exit(51);
}
err = proc_aftermount(&info, &conn);
if (err) {
umount(info.mdata.mount_point);
NWDSFreeContext(ctx);
if (auth_conn) {
NWCCCloseConn(auth_conn);
}
exit(err);
}
#ifdef NDS_SUPPORT
if (info.auth_src != NULL) {
err = NWDSAuthenticateConn(ctx, conn);
if (err) {
NWDSFreeContext(ctx);
if (auth_conn) {
NWCCCloseConn(auth_conn);
}
mycom_err(err, _("in authenticate connection"));
exit(115);
}
} else if (!info.force_bindery_login && NWIsDSServer(conn, NULL))
{
if ((err = nds_login_auth(conn, spec.user, spec.password)))
{
if (err != NWE_PASSWORD_EXPIRED) {
mycom_err(err, _("in nds login"));
fprintf(stderr, _("Login denied.\n"));
ncp_close(conn);
umount(mount_point);
NWDSFreeContext(ctx);
if (auth_conn) {
NWCCCloseConn(auth_conn);
}
exit(55);
}
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 (err != NWE_PASSWORD_EXPIRED)
{
mycom_err(err, _("in login"));
fprintf(stderr, _("Login denied\n"));
ncp_close(conn);
umount(mount_point);
NWDSFreeContext(ctx);
if (auth_conn) {
NWCCCloseConn(auth_conn);
}
exit(56);
}
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
err = NWDSFreeContext(ctx);
if (err) {
if (auth_conn) {
NWCCCloseConn(auth_conn);
}
mycom_err(err, _("in free context"));
exit(116);
}
if (auth_conn) {
NWCCCloseConn(auth_conn);
}
if ((err = ncp_mount_specific(conn, -1, info.NWpath, info.pathlen)) != 0)
{
ncp_close(conn);
umount(mount_point);
errexit(57, _("Cannot access path \"%s\": %s\n"), info.remote_path, strerror(-err));
}
ncp_close(conn);
if (!opt_n) {
add_mnt_entry(mount_name, mount_point, info.flags);
}
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"
"usage: %s [options] mount-point\n"), progname);
/* printf() is macro in glibc2.2... */
fprintf(stdout,
_("\n"
"-S server Server name to be used\n"
"-A dns_name DNS server name to be used when mounting over TCP or UDP\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"
"%s%s"
"-m Allow multiple logins to server\n"
"-N os2,nfs Do not use specified namespaces on mounted volume\n"
"-y charset character set used for input and display\n"
"-p codepage codepage used on volume, including letters `cp'\n"
"\n"),
#ifdef NDS_SUPPORT
_("-b Force bindery login to NDS servers\n")
#else
""
#endif /* NDS_SUPPORT */
,
#ifdef SIGNATURES
_("-i level Signature level, 0=never, 1=supported, 2=preferred, 3=required\n")
#else
""
#endif /* SIGNATURES */
);
}