Files
ncpfs/sutil/ncplogin.c
2026-04-28 20:56:05 +02:00

1034 lines
29 KiB
C

/*
ncplogin.c ncpmap.c and possibly 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:
1.00 2001 February 26 Patrick Pollet <patrick.pollet@insa-lyon.fr>
Initial release
This program is based on ncpmount.c release 1.07 2001, February 25 by Petr Vandrovec <vandrove@vc.cvut.cz>
Basically it substitute the -S server parameter with -T tree -X context options
Source code of ncplogin AND ncpmap (AND eventually ncpmount) should stays the same.
See the Makefile.in for compile flags.
CFLAGS_ncplogin.o = -DNWMSG=\"$(sbindir)/nwmsg\"
CFLAGS_ncpmap.o = -DNWMSG=\"$(sbindir)/nwmsg\" -DNCPMAP=1
CFLAGS_ncpmount.o = -DNWMSG=\"$(sbindir)/nwmsg\" -DNCPMOUNT=1
1.01 2001 March 10 Patrick Pollet <patrick.pollet@insa-lyon.fr>
Added failed in all error messages for easier TCL/tk parsing
Added -'E' option to echo mount_point in case of success (for TCL/Tk)
Shuffled some blocks of code to mimize #ifdef #ifndef
Corrected:#1135 (make_unique_dir= forgot to autocreate ~/ncp!
Corrected:#1397 wrong list of possible arguments to getopt()
Corrected:#1754 else was missing.
Corrected:#2147 ncplogin cannot use NWDSWhoami since we are not yet authenticated
Corrected:forgot to free context at various errors points
Corrected:incomplete help ncplogin,ncpmap (-X missing)
1.02 2001 March 12 Patrick Pollet <patrick.pollet@insa-lyon.fr>
Corrected #1668 info.resourcename was not set to SYS with -S option.
Note that with ncplogin/ncpmap: if volume is already mounted
the message already mounted:name of mount point will be printed and exitcode=0 (#2201)
1.03 2001 March 16 Patrick Pollet <patrick.pollet@insa-lyon.fr>
Added Default user logic if missing from command line (ncplogin only in TREE mode)
1.04 2001 August 11 Petr Vandrovec
Modified ncpmount part to match ncpmount v 1.08
1.05 2001 October 25 Patrick Pollet <patrick.pollet@insa-lyon.fr>
Added a signal(SIGPIPE, SIG_IGN) in process_connexion to match ncpmount v 1.08
In progress: ncpmap does not complains in case of multiple connexions and mount it twice
(2 entries in /etc/mtab)???
not a problem with ncplogin since it check that user is not currently authenticated ...
1.06 2001 December 8 Patrick Pollet <patrick.pollet@insa-lyon.fr>
ncplogin with -S option did not searched for missing -U user argument in environnment/nwclient
file if not supplied on the command line. Code moved from the -T case to all cases.
1.07 2002 January 20 Petr Vandrovec <vandrove@vc.cvut.cz>
Apply checks on uid/gid/owner value, so normal user can no longer mount filesystem
with someone else's uid.
Convert fprintf(stderr, "failed:yyy"...) to eprintf("yyy"...). Now ncpmount and ncplogin
use same .po entries.
Convert eprintf() + exit() => errexit()
1.08 2002, February 27 Petr Vandrovec <vandrove@vc.cvut.cz>
Fix core dump when no username is specified to ncplogin.
1.09 2002, February 27 Petr Vandrovec <vandrove@vc.cvut.cz>
Erase password quickly from command line.
Clear command line completely.
Simpler command line handling.
1.10 2002, April 19 Peter Schwindt <schwindt@ba-loerrach.de>
Add option -A to the help text.
1.11 2002, May 12 Patrick Pollet <patrick.pollet@insa-lyon.fr>
On NFS mounted homes, local root user has normally no rights to peek in user's home, not speaking
about autocreating there a mount point directory (unless NFS directories are exported with the no_root_squash
option, which is quite unsafe !). So we autocreate mount point in a local /mnt/ncp/$USER directory.
As usual this directory is autocreated and chmoded to 0700 ... To activate this, we added a -l command line option
(for local mount).
*/
#define NCP_OBSOLETE
#include "ncpm_common.h"
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pwd.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 <ncp/kernel/ipx.h>
#include <sys/ioctl.h>
#ifdef CONFIG_NATIVE_UNIX
#include <linux/un.h>
#endif
#ifndef NDS_SUPPORT
# error "NDS_SUPPORT must be enabled for ncplogin/ncpmap"
#endif
#include <ncp/nwclient.h>
#include "private/libintl.h"
#define _(X) gettext(X)
#include "../lib/ncpi.h"
#include "mount_login.h"
static void usage(void);
static void help(void);
void veprintf(const char* message, va_list ap) {
fprintf(stderr, "failed:");
vfprintf(stderr, message, ap);
}
/*begin of "alternating code between ncplogin/ncpmap/ncpmount */
/*basically ncpmap has no user nor passord required
thus all options regarding "user identity" (uid,gid, mount id ...) are marked off */
/*options of ncpmount irrelevant to both are marked off with #ifdef NCPMOUNT #endif */
/*ncplogin/ncpmap */
/*actually ncplogin does not care about this (it use -V SYS and -a internally) */
#ifdef NCPMAP
/* we will parse volume name later since in can be in NDS format */
static void opt_set_volume(struct ncp_mount_info* info, const char* param) {
info->remote_path = param;
}
static void opt_set_auto_create(struct ncp_mount_info* info, unsigned int param) {
info->autocreate = param;
}
struct optinfo extopts[] = {
{'a', "autocreate", FN_NOPARAM, opt_set_auto_create, 1},/*not in ncplogin*/
{'V', "volume", FN_STRING, opt_set_volume, 0},/*not in ncplogin*/
{0, NULL, 0, NULL, 0}
};
#endif
static int opt_set_volume_after_parsing_all_options(struct ncp_mount_info* info) {
char *path;
int e;
if (info->root_path) {
e = asprintf(&path, "%s/%s", info->remote_path, info->root_path);
} else {
e = asprintf(&path, "%s", info->remote_path);
}
if (e == -1) {
errexit(84, _("Cannot allocate memory for path\n"));
}
/* I keep forgeting typing it in uppercase so let's do it here */
str_upper(path);
info->pathlen = e = ncp_path_to_NW_format(path, info->NWpath, sizeof(info->NWpath));
if (e < 0) {
errexit(18, _("Volume path `%s' is invalid: `%s'\n"), path, strerror(-e));
};
if (info->pathlen == 1) {
info->mdata.mounted_vol = "";
info->remote_path = "/";
free(path);
} else if (info->NWpath[0] != 1) {
info->mdata.mounted_vol = "dummy";
free(path);
} else if (strlen(path) > NCP_VOLNAME_LEN) {
errexit(19, _("Volume name `%s' is too long\n"), path);
} else {
info->mdata.mounted_vol = path;
}
return 0;
}
/* new options ncplogin/ncpmap */
static void opt_set_tree(struct ncp_mount_info* info, const char* param) {
info->tree = param;
}
static void opt_set_root_path(struct ncp_mount_info* info, const char* param) {
info->root_path = param;
}
static void opt_set_name_context(struct ncp_mount_info* info, const char* param) {
if (strlen(param) < sizeof(info->context))
strcpy(info->context, param);
else{
errexit(19, _("Context name `%s' is too long\n"), param);
}
}
static void opt_set_bcast_mode(struct ncp_mount_info* info, unsigned int param) {
info->bcastmode = param & 3;
}
static void opt_set_echo(struct ncp_mount_info* info, unsigned int param) {
info->echo_mnt_pnt = param;
}
static void opt_set_use_local_mnt_dir(struct ncp_mount_info* info, const char* param) {
info->use_local_mnt_dir = param ? param : "/mnt/ncp";
info->autocreate = 1; /* if -l present, force -a */
}
static struct optinfo opts[] = {
{'X', "namecontext", FN_STRING, opt_set_name_context, 1},/*unfortunate that C,c and N reserved*/
{'T', "tree", FN_STRING, opt_set_tree, 0},
{'R', "root", FN_STRING, opt_set_root_path, 0},
{'B', "broadcast", FN_INT, opt_set_bcast_mode, 1},
{'E', "echo", FN_NOPARAM, opt_set_echo, 1},
{'l', "localmount", FN_NOPARAM | FN_STRING,
opt_set_use_local_mnt_dir, 0},
{0, NULL, 0, NULL, 0}
};
static int make_unique_dir(struct ncp_mount_info* info, char * mpnt, size_t maxl,
const char* p1, const char* p2) {
struct stat st;
size_t ln;
char* curr;
const struct passwd* pwd;
if (!info->server || !info->NWpath || !info->NWpath[0]) return -1;
pwd = getpwuid(info->mdata.uid);
if (!pwd) return -1;
if (!p2) {
p2 = pwd->pw_name;
}
if (!p1) {
p1 = pwd->pw_dir;
} else {
if (stat(p1, &st)) {
if (mkdir(p1, 0711)) {
return -1;
}
}
}
curr = mpnt;
ln = snprintf(curr, maxl, "%s/%s", p1, p2);
if (ln >= maxl) {
return E2BIG;
}
if (stat(mpnt, &st)) {
if (mkdir(mpnt, 0700) || chown(mpnt, pwd->pw_uid, pwd->pw_gid)) {
return -1;
}
}
curr[ln] = '/';
curr += ln + 1;
maxl -= ln + 1;
ln = strlen(info->server);
if (ln >= maxl) {
return E2BIG;
}
memcpy(curr, info->server, ln);
curr[ln] = 0;
str_upper(curr);
curr += ln;
maxl -= ln;
if (stat(mpnt, &st)){
if (mkdir(mpnt,0700) || chown(mpnt, pwd->pw_uid, pwd->pw_gid)) {
return -1;
}
}
ln = info->NWpath[1]; /*length of NW fragments*/
if (ln + 1 >= maxl) {
return E2BIG;
}
*curr++ = '/';
memcpy(curr, info->NWpath + 2, ln);
curr[ln] = 0;
str_upper(curr);
if (stat(mpnt, &st)) {
if (mkdir(mpnt, 0700) || chown(mpnt, pwd->pw_uid, pwd->pw_gid)) {
return -1;
}
}
return 0;
}
int
main(int argc, char *argv[])
{
struct ncp_mount_info info;
struct stat st;
char *mount_name;
int result;
long err;
char ntree[MAX_TREE_NAME_CHARS + 1];
#ifndef NCPMAP
struct ncp_conn_spec spec;
#endif
NWDSContextHandle ctx=NULL;
struct ncp_conn *conn;
int opt;
#ifdef CONFIG_NATIVE_UNIX
struct sockaddr_un server_un;
#endif
int mount_ncp = 0;
#ifndef NCPMAP
int opt_n = 0;
#endif
int opt_v = 0;
verify_argv(argc, argv);
setlocale(LC_ALL, "");
bindtextdomain(NCPFS_PACKAGE, LOCALEDIR);
textdomain(NCPFS_PACKAGE);
init_mount_info(&info);
if (myeuid != 0)
{
errexit(26, _("%s must be installed suid root\n"), progname);
}
/*ncplogin,ncpmap */
#ifdef NCPMAP
/*same as ncpmount :minus all users,passwd , uids, guids
:plus -R -a -T -X*/
while ((opt = getopt(argc, argv, "S:f:d:h?vV:t:r:o:"
"sN:y:p:i:A:B:T:X:R:aEl"
#else
/*same as ncpmount :plus -T, -X
:minus -b -m
ncplogin does not want -R -a */
while ((opt = getopt(argc, argv, "CS:U:c:u:g:f:d:P:nh?vV:t:r:o:"
"sN:y:p:i:A:B:T:X:El"
#endif
#ifdef MOUNT2
"2"
#endif
#ifdef MOUNT3
"345"
#endif
)) != EOF)
{
char tmpopt[2];
switch (opt)
{
#ifndef NCPMAP
case 'C':
#else
case 'a':
#endif
case 's':
case 'E':
case 'l':
optarg = NULL;
#ifndef NCPMAP
case 'U':
case 'c':
case 'u':
case 'g':
#else
case 'V':
case 'R':
#endif
case 'S':
case 'T':
case 'X':
case 'f':
case 'd':
case 't':
case 'r':
case 'i':
case 'A':
case 'y':
case 'p':
case 'B':
tmpopt[0] = opt;
tmpopt[1] = 0;
proc_option(opts, &info, tmpopt, optarg);
break;
#ifndef NCPMAP
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;
#endif
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:
eprintf(_("invalid option: %c\n"),opt);
usage();
return -1;
}
}
#ifndef NCPMAP
if (opt_n && !mount_ncp) {
opt_n = 0;
proc_option(opts, &info, "passwd", "");
}
#endif
if (opt_v && !mount_ncp) {
fprintf(stderr, _("ncpfs version %s\n"), NCPFS_VERSION);
exit(30);
}
/*ncplogin -a not allowed.
ncpmap only :added autocreate feature as LinuxNeighborood GUI utility for samba client*/
#ifdef NCPMAP
if (optind != argc - 1){
if (!info.autocreate) {
usage();
return -1;
}
/* we will autocreate later since NCPMAP may have to resolve NDS volume name!*/
} else {
realpath(argv[optind], mount_point);
info.autocreate = 0; /*turn it off user has provided a mount point*/
}
#else
if (optind != argc) {
usage();
return -1;
}
info.autocreate = 1; /*forced in ncplogin */
#endif
if (myuid != info.mdata.mounted_uid) {
if (setreuid(info.mdata.mounted_uid, -1)) {
errexit(76, _("Cannot impersonate as requested: %s\n"), strerror(errno));
}
}
/* processing new arguments */
/* FIX ME: so far I do not consider info.server_name (IP name) nor bindery only */
#ifdef NCPMAP
if (!info.remote_path) {
errexit(100, _("You must specify a volume to mount using -V option.\n"));
}
#endif
if (info.server && info.tree) {
errexit(101, _("Cannot have both -T tree and -S server options\n"));
}
/* if a server has been specified, get its NDS status and tree */
if (info.server) {
err = NWCCOpenConnByName (NULL,info.server,NWCC_NAME_FORMAT_BIND,0,NWCC_RESERVED,&conn);
if (err) {
errexit(102, _("Unable to open connection to %s.\n"),info.server);
}
if (!NWCXIsDSServer(conn, ntree)) { /* we have removed trailing ---*/
NWCCCloseConn(conn);
#ifdef NCPMAP
errexit(103, _("%s is not a NDS server, so background authentication will fail.\n"), info.server);
#else
errexit(103, _("%s is not a NDS server, so NDS authentication will fail.\n"), info.server);
#endif
}
NWCCCloseConn(conn);
err = NWDSCreateContextHandleMnt(&ctx, ntree);
if (err) {
errexit(104, _("Cannot create NDS context handle: %s\n"), strerror(err));
}
#ifdef NCPMAP
if (!NWCXIsDSAuthenticated(ctx)) {
NWDSFreeContext(ctx);
errexit(105, _("Server %s belong to tree %s and you are not authenticated to it.\n"), info.server, ntree);
}
#else
if (NWCXIsDSAuthenticated(ctx)) {
NWDSFreeContext(ctx);
errexit(105, _("Server %s belong to tree %s and you are already authenticated to it.\n"),info.server, ntree);
}
/* with ncplogin use SYS as volume name */
strcpy(info.resourceName, "SYS");
info.remote_path=info.resourceName;
#endif
info.tree = ntree;
/*in that case the volume name must be in bindery format */
} else {
/* try to get a default tree from env variable */
/* we are using the same env names as the Caldera client (hope they won't mind)
#define PREFER_TREE_ENV "NWCLIENT_PREFERRED_TREE"
#define PREFER_CTX_ENV "NWCLIENT_DEFAULT_NAME_CONTEXT"
*/
int flags = 0;
if (!info.tree) {
err=NWCXGetPreferredDSTree(ntree, sizeof(ntree));
if (err){
errexit(104, _("Cannot get preffered DS tree: %s\n"),strnwerror(err));
}
info.tree = ntree;
}
err = NWDSCreateContextHandleMnt (&ctx,info.tree);
if (err) {
errexit(104, _("Cannot create NDS context handle: %s\n"),strnwerror(err));
}
#ifdef NCPMAP
if (!NWCXIsDSAuthenticated(ctx)) {
NWDSFreeContext(ctx);
errexit(105, _("You are not authenticated to tree %s.\n"),info.tree);
}
#else
if (NWCXIsDSAuthenticated(ctx)) {
NWDSFreeContext(ctx);
errexit(105, _("You are already authenticated to tree %s.\n"),info.tree);
}
#endif
err = NWDSGetContext(ctx, DCK_FLAGS, &flags);
if (!err) {
flags |= DCV_XLATE_STRINGS | DCV_TYPELESS_NAMES | DCV_DEREF_ALIASES;
err = NWDSSetContext(ctx, DCK_FLAGS, &flags);
}
if (err) {
NWDSFreeContext(ctx);
errexit(110, _("NWDSGetContext/NWDSSetContext (DCK_FLAGS) failed: %s.\n"), strnwerror(err));
}
/* no -X argument */
if (!info.context[0])
NWCXGetDefaultNameContext(info.tree,info.context,sizeof(info.context));
/* got one */
if (info.context[0]) {
err = NWDSSetContext(ctx, DCK_NAME_CONTEXT, info.context);
if (err) {
errexit(106, _("NWDSSetContext(DCK_NAME_CTX) failed: %s\n"), strnwerror(err));
}
}
#ifdef NCPMAP
/*resolve NDS volume name */
if ((err=NWCXGetNDSVolumeServerAndResourceName(ctx,info.remote_path,
info.serverName,sizeof(info.serverName),
info.resourceName,sizeof(info.resourceName)))) {
NWDSFreeContext(ctx);
errexit(105, _("Cannot resolve volume name %s on tree %s (using context %s). Err:%s\n"),
info.remote_path,info.tree,info.context[0]?info.context:"[Root]",strnwerror(err));
} else {
err = NWCXSplitNameAndContext(ctx,info.serverName,info.serverName,NULL);
info.server=info.serverName;
info.remote_path=info.resourceName;
}
#else
/* get a server name from that tree
NWCXAttchToTreeByName do search for a default server in env
*/
if ((err=NWCXAttachToTreeByName (&conn,info.tree))) {
NWDSFreeContext(ctx);
errexit(108, _("Cannot attach to tree %s. Err:%s\n"),
info.tree,strnwerror(err));
}
if ((err=NWCCGetConnInfo(conn,NWCC_INFO_SERVER_NAME,sizeof(info.serverName),info.serverName))){
NWCCCloseConn(conn);
NWDSFreeContext(ctx);
errexit(109, _("Cannot get server name from connection to tree %s. Err:%s\n"),
info.tree,strnwerror(err));
}
/* use SYS volume that should always exist */
strcpy(info.resourceName, "SYS");
info.server = info.serverName;
info.remote_path = info.resourceName;
NWCCCloseConn(conn);
#endif
}
/* v 1.06 make search of DefaultUserName (ncplogin/ncpmount only) moved here so it is called with both -T or -S options*/
#ifndef NCPMAP
if (!info.user) {
if (!NWCXGetDefaultUserName(info.tree,info.defaultUser,sizeof(info.defaultUser))) {
info.user = info.defaultUser;
} else {
NWDSFreeContext(ctx);
errexit(110, _("No user name found in cmd line nor in env\n"));
}
}
#endif
/* just now do what ncpmount.c used to do where parsing -V option */
err=opt_set_volume_after_parsing_all_options(&info);
if (err) {
NWDSFreeContext(ctx);
exit(err);
}
/*printf ("Ok we will mount %s:%s:%s in %s\n",info.server,info.remote_path,info.root_path,mount_point);*/
/* try autocreation of mount_point must be done AFTER NCPMAP specific part cause it is
only now that server and volume are correct*/
if (info.autocreate) {
/* printf ("try autocreate %s\n","");*/
if (info.use_local_mnt_dir) {
err = make_unique_dir(&info, mount_point, sizeof(mount_point), info.use_local_mnt_dir, NULL);
} else {
err = make_unique_dir(&info, mount_point, sizeof(mount_point), NULL, "ncp");
}
if (err) {
NWDSFreeContext(ctx);
errexit(-1, _("Could not autocreate mount point %s: %s\n"),mount_point, strerror(err));
}
}
/* final checking it's time to do it for all ! */
if (stat(mount_point, &st) == -1)
{
err = errno;
NWDSFreeContext(ctx);
errexit(31, _("Could not find mount point %s: %s\n"),
mount_point, strerror(err));
}
if (mount_ok(&st) != 0)
{
err = errno;
NWDSFreeContext(ctx);
errexit(32, _("Cannot mount on %s: %s\n"), mount_point, strerror(err));
}
/* ncplogin: now that we have the server NAME in bindery format we can do it */
#ifndef NCPMAP
/* no user/pwd in ncpmap */
get_passwd(&info);
if ((err = ncp_find_conn_spec3(info.server, info.user, info.password, 1, info.mdata.uid, info.allow_multiple_connections, &spec))
!= 0)
{
mycom_err(err, _("in find_conn_spec"));
exit(33);
}
/* I am afraid it's too late. ncp_find_conn_spec3 did it */
if (info.upcase_password != 0)
{
str_upper(spec.password);
}
#endif
#ifndef NCPMAP
info.mdata.server_name = spec.server;
#endif
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;
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) {
eprintf(_("Get host address `%s': %s\n"), info.server_name, strnwerror(err));
NWDSFreeContext(ctx);
exit(1);
}
}
#else
{
goto ncpipx;
}
#endif
} else
#endif /* CONFIG_NATIVE_IP */
{
#if defined(CONFIG_NATIVE_UNIX) && !defined(CONFIG_NATIVE_IP)
ncpipx:;
#endif
#ifndef NCPMAP /*ncpmount & ncplogin */
if ((err = ncp_find_fileserver(spec.server, (struct sockaddr*)&info.mdata.serv_addr, sizeof(info.mdata.serv_addr))) != 0)
{
mycom_err(err, _("when trying to find %s"), spec.server);
NWDSFreeContext(ctx);
exit(36);
}
#else
if ((err = ncp_find_fileserver(info.server, (struct sockaddr*)&info.mdata.serv_addr, sizeof(info.mdata.serv_addr))) != 0)
{
mycom_err(err, _("when trying to find %s"), info.server);
NWDSFreeContext(ctx);
exit(36);
}
#endif
}
err = proc_buildconn(&info);
if (err) {
NWDSFreeContext(ctx);
exit(err);
}
info.mdata.mount_point = mount_point;
#ifndef NCPMAP
if (asprintf(&mount_name, "%s/%s", spec.server, spec.user) < 0) {
NWDSFreeContext(ctx);
errexit(85, _("Cannot allocate memory for mtab entry: %s\n"), strerror(ENOMEM));
}
#else
{
NWDSChar user[MAX_DN_BYTES];
err = NWDSWhoAmI(ctx, user);
if (err) {
NWDSFreeContext(ctx);
errexit(51, _("Cannot retrieve user identity: %s\n"), strnwerror(err));
}
err = NWCXSplitNameAndContext(ctx, user, user, NULL);
if (err) {
NWDSFreeContext(ctx);
errexit(86, _("Cannot parse user name: %s\n"), strnwerror(err));
}
/* FIXME: str_upper is unwanted! NWCXSplitNameAndContext too, BTW... Just retrieve name from server and do 'NWDSAbbreviateName' on it */
str_upper(user);
if (asprintf(&mount_name, "%s/%s", info.server, user) < 0) {
NWDSFreeContext(ctx);
errexit(85, _("Cannot allocate memory for mtab entry: %s\n"), strerror(ENOMEM));
}
}
#endif
result = ncp_mount(mount_name, &info);
if (result)
{
if (result == EBUSY) {
/* for TCL/tk to catch it*/
fprintf(stderr, _("already mounted:%s\n"), mount_point);
} else {
mycom_err(result, _("failed in mount(2)"));
}
free(mount_name);
NWDSFreeContext(ctx);
/*exit code stays 0 for TCL/tk to be fixed...*/
exit(0);
}
err = proc_aftermount(&info, &conn);
if (err) {
free(mount_name);
NWDSFreeContext(ctx);
proc_ncpm_umount(mount_point);
exit(err);
}
#ifndef NCPMAP
#ifdef NDS_SUPPORT
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, _("failed in nds login"));
fprintf(stderr, _("Login denied.\n"));
ncp_close(conn);
proc_ncpm_umount(mount_point);
free(mount_name);
NWDSFreeContext(ctx);
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);
proc_ncpm_umount(mount_point);
free(mount_name);
NWDSFreeContext(ctx);
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);
}
}
}
#else /*ncpmap only*/
err = NWDSAddConnection(ctx, conn);
if (err) {
ncp_close(conn);
proc_ncpm_umount(mount_point);
free(mount_name);
NWDSFreeContext(ctx);
errexit(110, _("Cannot attach connection to context: %s\n"), strnwerror(err));
}
err = NWDSAuthenticateConn(ctx, conn);
if (err) {
ncp_close(conn);
proc_ncpm_umount(mount_point);
free(mount_name);
NWDSFreeContext(ctx);
errexit(112, _("Cannot authenticate connection: %s\n"), strnwerror(err));
}
#endif
err = NWSetBroadcastMode(conn,info.bcastmode); /*ignore error for now */
if ((err = ncp_mount_specific(conn, -1, info.NWpath, info.pathlen)) != 0)
{
ncp_close(conn);
proc_ncpm_umount(mount_point);
NWDSFreeContext(ctx);
errexit(57, _("Cannot access path \"%s\": %s\n"), info.remote_path, strerror(-err));
}
NWCCCloseConn(conn);
NWDSFreeContext(ctx);
free(mount_name);
if (info.echo_mnt_pnt) {
printf(_("mounted on:%s\n"),mount_point);
}
return 0;
}
static void usage(void)
{
#ifdef NCPMAP
printf(_("usage: %s [options] mount-point\n"), progname);
#else
printf(_("usage: %s [options]\n"), progname);
#endif
printf(_("Try `%s -h' for more information\n"), progname);
}
static void
help(void)
{
const char* str;
const char* str2;
#ifdef NCPMAP
printf(_("\n"
"usage: %s [options] mount-point\n"), progname);
#else
printf(_("\n"
"usage: %s [options]\n"), progname);
#endif
#ifdef NCPMAP
str = _(" mount_point is optional if -a option specified\n");
#else
str = "";
#endif
printf(_("\n"
"%s"
"-T tree Tree name to be used\n"
"-S server Server name to be used\n"
" these two options are exclusive\n"
"-X name_ctx Default name context to be used\n"
"-E Echo value of final mount_point\n")
, str);
#ifndef NCPMAP
printf(_("\n"
"-U username Username sent to server\n"
"-u uid uid the mounted files get\n"
"-g gid gid the mounted files get\n"
"-c uid uid to identify the connection to mount on\n"
" Only makes sense for root\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")
);
#else
printf(_("\n"
"-V volume Volume to mount\n"
" must be in bindery format if -S server\n"
" or in NDS format if -T tree\n"
"-R path Path in volume to 'map root'\n")
);
#endif
#ifdef SIGNATURES
str = _("-i level Signature level, 0=never, 1=supported, 2=preferred, 3=required\n");
#else
str = "";
#endif
#ifdef NCPMAP
str2 = _("-a Autocreate mounting point if needed in ~/ncp/SERVER/VOLUME\n");
#else
str2 = "";
#endif
printf(_("\n"
"-f mode permission the files get (octal notation)\n"
"-d mode permission the dirs get (octal notation)\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"
"-s Enable renaming/deletion of read-only files\n"
"-h print this help text\n"
"-v print ncpfs version number\n"
"%s"
"-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"
"-B bcast Broadcast mode =0 all 1= console 2= none (default=all)\n"
"%s"
"-l Autocreate mounting point if needed in /mnt/ncp/SERVER/VOLUME\n"
"\n"),
str, str2);
}