Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/aux/ncpfs/main.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include "ncp.h"

#define min(a,b)	(((a)<(b))?(a):(b))

char Host[OBJNAMLEN];		// host connect to
int Numvol;			// number of volumes
int Debug;			// Packet hex-dump
int Maxio;			// Maximum IO chunk size
int Slip;			// time slip in secs between server and us
int Fsver;			// server software version * 1000
int Bigfiles;			// flag: 64 bit files possible on this server
Qid Root;			// root of remote system
Session *Sess;			// netware session
ulong Myuid;			// my UID

enum {

	RIMstat = RIMname|RIMattr|RIMsize|RIMarch|RIMmodif|
		RIMcreate|RIMns|RIMdir|RIMrights,
	DARnewdir = DARreadexisting|DARwriteexisting|DARoldopenexisting|
		DARcreatenewentry|DARdeleteexisting|DARchangeacl|DARsearch|
		DARmodify|DARsuporvisor,
	DARnewfile = DARreadonly|DARwriteonly,
	RIMqid = RIMattr|RIMmodif|RIMdir,
	RIMnone = 0,
};

typedef struct NWdir NWdir;
	
typedef struct Aux Aux;
struct Aux {
	char *path;		// full path fo file
	long expire;		// expiration time of cache
	long off;		// file pos of start of cache
	long end;		// file pos of end of cache
	char *cache;
	union {
		Srch srch;	// NCP dir search state
		Fh fh;		// file handle
	};
};

static void
responderrstr(Req *r)
{
	char e[ERRMAX];
	rerrstr(e, sizeof e);
	respond(r, e);
}

/*
 * used only for root dir and volumes
 * to which we have no rights
 */
static void
V2D(Dir *d, ulong vol, char *name)
{
	memset(d, 0, sizeof(Dir));
	d->type = 'N';
	d->dev = vol;
	d->name = strlwr(estrdup9p(name));
	d->uid = estrdup9p("supervisor");
	d->muid = estrdup9p("supervisor");
	d->gid = estrdup9p("none");
	d->mode = DMDIR;	// zero mode, no rights
	d->qid.vers = Vvol;
	d->qid.path = vol;
	d->qid.type = QTDIR;
}

static Qid 
I2Qid( FInfo *i)
{
	Qid q;
	q.path = i->dirent;
	q.vers = i->modified;
	q.type = (i->attr & FAdirectory)? QTDIR: QTFILE;
	return q;
}

static void
I2D(Dir *d, FInfo *i)
{
	char *u, *g;

	memset(d, 0, sizeof(Dir));
	d->type = 'N';
	d->dev = i->vol;
	d->name = estrdup9p(i->name);
	if (i->creatns == NSdos)
		strlwr(d->name);
	uid2names(Sess, i->creator, &u, &g); 
	d->uid = estrdup9p(u);
	d->gid = estrdup9p(g);
	uid2names(Sess, i->modifier, &u, &g); 
	d->muid = estrdup9p(u);
	d->atime = i->accessed;
	d->mtime = i->modified;
	d->qid = I2Qid(i);
	if (i->attr & FAdirectory){
		d->length = 0;
		d->mode = (i->rights & ERall)? (DMDIR|0777): (DMDIR|0555);
	}
	else{	d->length = i->size;
		d->mode = (i->attr & FAreadonly)? 0444: 0666;
	}
}

static char *
newpath(char *path, char *name)
{
	char *p, *q;

	assert((p = strrchr(path, '/')) != nil);

	if (strcmp(name, "..") == 0){
		if (p == path)
			return estrdup9p("/");
		q = emalloc9p((p-path)+1);
		strecpy(q, q+(p-path)+1, path);
		return q;
	}
	if (strcmp(path, "/") == 0)
		return smprint("/%s", name);
	return smprint("%s/%s", path, name);
}

static int
dodelete(char *s)
{
	FInfo i;
	Mfi mfi;
	char e[ERRMAX];

	/*
	 * Netware won't delete readonly files
	 */
	memset(&i, 0, sizeof i);
	if (ObtainFileOrDirInfo(Sess, NSlong, NSlong, RIMattr, s, &i) == -1){
		return -1;
	}
	memset(&mfi, 0, sizeof mfi);
	mfi.attr = FAnormal | (i.attr & FAdirectory);
	ModifyFileOrDirInfo(Sess, NSlong, SAall, MFIattr, &mfi, s);

	if (DeteleFileOrDir(Sess, NSlong, SAall, s) == -1){
		errstr(e, sizeof e);
		mfi.attr = i.attr;
		ModifyFileOrDirInfo(Sess, NSlong, SAall, MFIattr, &mfi, s);
		errstr(e, sizeof e);
		return -1;
	}
	return 0;
}

static int
dorename(char *src, char *dst)
{
	int sa;
	FInfo i;
	Mfi mfi;
	char e[ERRMAX];

	/*
	 * Netware won't rename of readonly files
 	 */
	memset(&i, 0, sizeof i);
	if (ObtainFileOrDirInfo(Sess, NSlong, NSlong, RIMattr, src, &i) == -1)
		return -1;

	memset(&mfi, 0, sizeof mfi);
	mfi.attr = FAnormal | (i.attr & FAdirectory);
	if (ModifyFileOrDirInfo(Sess, NSlong, SAall, MFIattr, &mfi, src) == -1)
		return -1;

	/*
	 * I don't understand why this is nescessary, but rename fails
	 * on subdirs if we simply pass SAall as the search attribute.
	 */
	sa = (i.attr & FAdirectory)? SAsubdironly: SAsubdirfiles;

	if (RenameOrMoveFileOrDir(Sess, NSlong, 1, sa, src, dst) == -1){
		errstr(e, sizeof e);

		memset(&mfi, 0, sizeof mfi);
		mfi.attr = i.attr;
		ModifyFileOrDirInfo(Sess, NSlong, SAall, MFIattr, &mfi, src);

		errstr(e, sizeof e);
		return -1;
	}

	memset(&mfi, 0, sizeof mfi);
	mfi.attr = i.attr;
	ModifyFileOrDirInfo(Sess, NSlong, SAall, MFIattr, &mfi, dst);

	return 0;
}

int
doreopen(Fid *f)	/* as we must close open files during rename */
{
	FInfo i;
	int oca;
	Aux *a = f->aux;
	int dar = DARcompatibility;

	switch (f->omode & OMASK){
	case OREAD:
		dar |= DARreadonly;
		break;
	case OWRITE:
		dar |= DARwriteonly;
		break;
	case ORDWR:
		dar |= DARreadonly|DARwriteonly;
		break;
	case OEXEC:
		dar |= DARreadonly;
		break;
	}
	if (OpenCreateFileOrSubdir(Sess, NSlong, OCMopen, SAall, RIMnone, dar,
	    FAnormal, a->path, &oca, a->fh, &i) == -1)
		return -1;
	return 0;
}

int
dotruncate(char *path, ulong len)
{
	Fh fh;
	FInfo i;
	int err, oca;
	char buf[1];

	if (OpenCreateFileOrSubdir(Sess, NSlong, OCMopen, SAall, RIMnone,
	    DARreadonly|DARwriteonly, FAnormal, path, &oca, fh, &i) == -1){
		return -1;
	}
	err = WriteToAFile(Sess, fh, buf, 0, len);
	err += CloseFile(Sess, fh);
	return (err == 0)? 0: -1;
}

static int
dirgen(int slot, Dir *d, void *aux)
{
	FInfo i;
	Aux *a = aux;
	int nent, more;
	char *npath, volnam[VOLNAMLEN];
	long off;
	int numinf = numinfo();

	if (strcmp(a->path, "/") == 0){
		if (slot < numinf){
			dirgeninfo(slot, d);
			return 0;
		}
		else
			slot -= numinf;

		*volnam = 0;
		if (slot >= Numvol)
			return -1;
		if (GetVolumeName(Sess, slot, volnam) == -1)
			return -1;
		if (*volnam == 0)
			return -1;
		npath = newpath(a->path, volnam);
		memset(&i, 0, sizeof i);
		if (ObtainFileOrDirInfo(Sess, NSlong, NSlong, RIMstat, npath, &i) == 0){
			/*
			 * ObtainFileOrDirInfo() on volumes returns mostly correct
			 * metadata (NW 5.0) but the filename is missing, so we add
			 * that by hand, and also tweek the permissions. It may fails
			 * on earlier server versions, but we just fall back to V2D().
			 */
			I2D(d, &i);
			free(d->name);
			d->name = estrdup9p(strlwr(volnam));
			d->mode = 0555|DMDIR;
		}
		else
			V2D(d, slot, volnam);
		free(npath);
		return 0;
	}

	off = slot * sizeof(FInfo);
	if (off >= a->off && off < a->end && time(nil) < a->expire){
		I2D(d, (FInfo *)(a->cache + (off - a->off)));
		return 0;
	}

	if (off == 0){
		if (InitializeSearch(Sess, NSlong, a->path, a->srch) == -1)
			return -1;
		a->off = 0;
		a->end = 0;
	}

	/*
	 * we try to read dirs in 64 entry chunks - the
	 * server will round this down to an integer number of
	 * entrys to fit in the negiotated packet size;
	 *
	 * Disappointingly we only seem to get 4 to 6
	 * directory entries per read.
	 */
	more = 1;
	do {
		nent = 64;
		a->off = a->end;
		if (SearchFileOrSubdirectorySet(Sess, a->srch, NSlong, DSdos, SAall,
	    	    "\377*", RIMstat, (FInfo *)a->cache, &nent, &more) == -1)
			return -1;
		a->end = a->off + nent * sizeof(FInfo);
	}while (a->off < off && more);

	a->expire = time(nil) + CACHETIME;

	if (off >= a->end)
		return -1;

	I2D(d, (FInfo *)(a->cache + (off - a->off)));
	return 0;
}

static void
fsattach(Req *r)
{
	Aux *a;
	char *spec = r->ifcall.aname;

	if(spec && spec[0]){
		respond(r, "invalid attach specifier");
		return;
	}

	r->ofcall.qid = (Qid){Proot, Vvol, QTDIR};
	r->fid->qid = r->ofcall.qid;

	a = r->fid->aux = emalloc9p(sizeof(Aux));
	memset(a, 0, sizeof(Aux));
	a->path = estrdup9p("/");

	respond(r, nil);
}


static char*
fsclone(Fid *ofid, Fid *fid)
{
	Aux *a = emalloc9p(sizeof(Aux));

	*a = *(Aux*)ofid->aux;
	if (a->path)
		a->path = estrdup9p(a->path);

	fid->aux = a;
	return nil;
}

static char*
fswalk1(Fid *fid, char *name, Qid *qid)
{
	FInfo i;
	int n, vol;
	char *npath;
	static char e[ERRMAX];
	Aux *a = fid->aux;

	npath = newpath(a->path, name);

	if (strcmp(npath, "/") == 0)
		*qid = (Qid){Proot, Vvol, QTDIR};
	else
	if (strrchr(npath, '/') == npath){
		if ((n = walkinfo(name)) != -1){
			*qid = (Qid){n, Vinfo, 0};
		}
		else {
			if (GetVolumeNumber(Sess, npath +1, &vol) == -1){
				free(npath);
				rerrstr(e, sizeof(e));
				return e;
			}
			*qid = (Qid){vol, Vvol, QTDIR};
		}
	}
	else{
		memset(&i, 0, sizeof i);
		if (ObtainFileOrDirInfo(Sess, NSlong, NSlong, RIMqid, npath, &i) == -1){
			free(npath);
			rerrstr(e, sizeof(e));
			if (strcmp(e, "failed") == 0)
				return "file does not exist";
			return e;
		}
		*qid = I2Qid(&i);
	}

	free(a->path);
	a->path = npath;
	fid->qid = *qid;
	return nil;

}

static void
fsstat(Req *r)
{
	FInfo i;
	Aux *a = r->fid->aux;

	if (r->fid->qid.path == Proot)
		V2D(&r->d, Proot, "");
	else
	if (r->fid->qid.vers == Vinfo)
		dirgeninfo(r->fid->qid.path, &r->d);
	else
	if (r->fid->qid.vers == Vvol){
		memset(&i, 0, sizeof i);
		if (ObtainFileOrDirInfo(Sess, NSlong, NSlong, RIMstat, a->path, &i) == 0)
			I2D(&r->d, &i);
		else
			V2D(&r->d, r->fid->qid.path, a->path +1);			
	}
	else{
		memset(&i, 0, sizeof i);
		if (ObtainFileOrDirInfo(Sess, NSlong, NSlong, RIMstat, a->path, &i) == -1){
			responderrstr(r);
			return;
		}
		I2D(&r->d, &i);
	}
	respond(r, nil);
}

/*
 * All files are created in compatibility mode because of one marginal case:
 * If you use mk to build an ANSI C library (using pcc) then the object files
 * are opened for reading whilst 8c is still writing them. This is illegal in
 * NCP unless the compatability mode is set.
 */
static void
fscreate(Req *r)
{
	FInfo i;
	char *npath;
	int oca, ocm, dar, attr;
	Aux *a = r->fid->aux;

	a->cache = emalloc9p(Sess->mtu);
	npath = smprint("%s/%s", a->path, r->ifcall.name);
	if (r->ifcall.perm & DMDIR){
		attr = FAdirectory;
		ocm = OCMcreate;
		dar = DARnewdir;
	}
	else {
		attr = FAnormal;
		dar = DARnewfile|DARcompatibility;
		ocm = OCMcreate|OCMopen|OCMtruncate;
	}

 	memset(&i, 0, sizeof i);
	if (OpenCreateFileOrSubdir(Sess, NSlong, ocm, SAall, RIMqid, dar,
		attr, npath, &oca, a->fh, &i) == -1 || oca != OCAcreated){
			char e[ERRMAX];
			rerrstr(e, sizeof(e));
			if (oca != OCAcreated && strcmp(e, "lock fail") != 0){
				free(npath);
				responderrstr(r);
				return;
			}
	}

	free(a->path);
	a->path = npath;

	r->ofcall.qid = I2Qid(&i);
	r->fid->qid = r->ofcall.qid;
	respond(r, nil);
}

static void
fsopen(Req *r)
{
	FInfo i;
	Aux *a = r->fid->aux;
	int oca, ocm = OCMopen;
	int dar = DARcompatibility;

	if (r->fid->qid.vers == Vinfo){
		if (makeinfo(r->fid->qid.path) != -1)
			respond(r, nil);
		else
			respond(r, "cannot renerate info");
		return;
	}

	a->cache = emalloc9p(Sess->mtu);
	if (r->ofcall.qid.type & QTDIR){
		respond(r, nil);
		return;
	}

	if (r->ifcall.mode & OTRUNC)
		ocm |= OCMtruncate;

	switch (r->ifcall.mode & OMASK){
	case OREAD:
		dar |= DARreadonly;
		break;
	case OWRITE:
		dar |= DARwriteonly;
		break;
	case ORDWR:
		dar |= DARreadonly|DARwriteonly;
		break;
	case OEXEC:
		dar |= DARreadonly;
		break;
	}

	if (OpenCreateFileOrSubdir(Sess, NSlong, ocm, SAall, RIMnone, dar,
	    FAnormal, a->path, &oca, a->fh, &i) == -1){
		responderrstr(r);
		return;
	}
	respond(r, 0);
}

static void
fswrite(Req *r)
{
	long n, m;
	int err;
	long got = 0;
	Aux *a = r->fid->aux;
	char *buf = r->ifcall.data;
	long len = r->ifcall.count;
	long off = r->ifcall.offset;

	if (r->fid->qid.vers == Vinfo){
		respond(r, "illegal operation");
		return;
	}

	if (r->ifcall.offset > ~0U ||
	    r->ifcall.count + r->ifcall.offset > ~0U){
		respond(r, "64 bit file offsets not supported");
		return;
	}
		
	/* Writes must not cross a 4096 byte boundry */
	do {
		m = n = min(Maxio-(off % IOCHUNK), len-got);
		err = WriteToAFile(Sess, a->fh, buf, n, off);
		off += n;
		got += n;
		buf += n;
	} while (got < len && n == m && !err);
	r->ofcall.count = got;
	if (err == -1)
		responderrstr(r);
	else
		respond(r, nil);
}

static void
fsread(Req *r)
{
	long n, m;
	int err;
	long got = 0;
	Aux *a = r->fid->aux;
	char *buf = r->ofcall.data;
	long len = r->ifcall.count;
	long off = r->ifcall.offset;

	if (r->fid->qid.vers == Vinfo){
		r->ofcall.count = readinfo(r->fid->qid.path, buf, len, off);
		respond(r, nil);
		return;
	}
	
	if (r->ifcall.offset > ~0U ||
	    r->ifcall.count + r->ifcall.offset > ~0U){
		respond(r, "64 bit file offsets not supported");
		return;
	}
		
	if (r->fid->qid.type & QTDIR){
		dirread9p(r, dirgen, a);
		respond(r, nil);
		return;
	}

	if (off >= a->off && (off + len) < a->end && time(nil) < a->expire){
		memcpy(buf, a->cache + (off - a->off), len);
		r->ofcall.count = len;
		respond(r, nil);
		return;
	}

	a->off = off - (off % IOCHUNK);
	do {
		m = n = Maxio;
		err = ReadFromAFile(Sess, a->fh, a->cache + got, &n, a->off + got);
		got += n;
	} while (got < Maxio && n == m && !err);
	a->end = a->off + got;
	a->expire = time(nil) + CACHETIME;

	if ((a->end - a->off) > (off - a->off))
		r->ofcall.count = min(len, (a->end - a->off) - (off - a->off));
	else
		r->ofcall.count = 0;

	if (err == -1){
		responderrstr(r);
		return;
	}
	memcpy(buf, a->cache + (off - a->off), r->ofcall.count);
	respond(r, nil);
}

static void
fsdestroyfid(Fid *f)
{
	Aux *a = f->aux;
	
	if (f->qid.vers == Vinfo)
		freeinfo(f->qid.path);

	if (f->omode != -1 && (f->qid.type & DMDIR) == 0)
		CloseFile(Sess, a->fh);

	if ((f->omode != -1) && (f->omode & ORCLOSE) == ORCLOSE)
		dodelete(a->path);

	if (a && a->cache)
		free(a->cache);
	if (a && a->path)
		free(a->path);
	if (a)
		free(a);

	f->omode = -1;
}

static void
fsremove(Req *r)
{
	Aux *a = r->fid->aux;

	if (r->fid->qid.vers == Vinfo){
		respond(r, "illegal operation");
		return;
	}

	if (r->fid->omode != -1 && (r->fid->qid.type & DMDIR) == 0)
		CloseFile(Sess, a->fh);
	r->fid->omode = -1;
	if (dodelete(a->path) == -1){
		responderrstr(r);
		return;
	}
	respond(r, nil);
}

static void
fswstat(Req *r)
{
	Mfi mfi;
	char *p, *npath;
	int mask = 0;
	Aux *a = r->fid->aux;

	if (r->fid->qid.vers == Vinfo){
		respond(r, "illegal operation");
		return;
	}

	memset(&mfi, 0, sizeof mfi);
	if((r->d.uid && r->d.uid[0]) || (r->d.gid && r->d.gid[0])){
		respond(r, nil);
// this change makes replica happier
//		respond(r, "cannot change ownership");
		return;
	}
	if(~r->d.mode){
		if(((r->d.mode & ~(0777 | DMDIR)) != 0)){
			respond(r, "mode not supported");
			return;
		}
		mfi.attr = (r->d.mode & 0222)? 0: FAreadonly;
		mfi.attr |= (r->d.mode & DMDIR)? FAdirectory: FAnormal;
		mask |= MFIattr;
	}
	if(~r->d.length){
		if (r->d.length > ~0U){
			respond(r, "64 bit file offsets not supported");
			return;
		}
		if (dotruncate(a->path, (ulong)r->d.length) == -1)
			responderrstr(r);
			return;
		}
	if(~r->d.mtime){
		mfi.modified = r->d.mtime;
		mfi.modifier = Myuid;
		mask |= MFImodified;
	}
	if(~r->d.atime){
		mfi.accessed = r->d.atime;
		mask |= MFIaccessed;
	}

	if(r->d.name && r->d.name[0]){

		if ((p = strrchr(a->path, '/')) == nil){
			respond(r, "illegal path");
			return;
		}
		npath = emalloc9p((p-a->path)+strlen(r->d.name)+2);
		strecpy(npath, npath+(p- a->path)+2, a->path);
		strcat(npath, r->d.name);

		if (r->fid->omode != -1 && (r->fid->qid.type & DMDIR) == 0)
			CloseFile(Sess, a->fh);
		if (dorename(a->path, npath) == -1){
			free(npath);
			responderrstr(r);
			return;
		}
		if (r->fid->omode != -1 && (r->fid->qid.type & DMDIR) == 0)
			if (doreopen(r->fid) == -1){
				respond(r, "reopen after rename - failed");
				return;
			}

		free(a->path);
		a->path = npath;
	}

	if(mask && ModifyFileOrDirInfo(Sess, NSlong, SAall, mask, &mfi, a->path)){
		responderrstr(r);
		return;
	}

	/*
	 * This only works for open files under Netware,
	 * but it might be usefull...
	 */
	if (!mask && (!r->d.name || !r->d.name[0]) && r->fid->omode != -1){
		if (CommitFile(Sess, a->fh) == -1){
			responderrstr(r);
			return;
		}
	}

	respond(r, nil);
}

static void
fsend(Srv *srv)
{
	USED(srv);

	Logout(Sess);
	Detach(Sess);
}

Srv fs =
{
	.destroyfid =	fsdestroyfid,
	.attach=	fsattach,
	.open=		fsopen,
	.create=	fscreate,
	.read=		fsread,
	.write=		fswrite,
	.remove=	fsremove,
	.stat=		fsstat,
	.wstat=		fswstat,
	.clone= 	fsclone,
	.walk1= 	fswalk1,
	.end=		fsend,
};



void
usage(void)
{
	fprint(2, "usage: %s [-dD] [-s service] [-m mtpt] [-k keyparam] host\n", argv0);
	exits("usage");
}


void
main(int argc, char **argv)
{
	FSInfo fsi;
	long fstime;
	UserPasswd *up;
	ulong nds_uid;
	int fd, maxpkt;
	uchar uid[sizeof(nds_uid)], *p;
	char *addr, *keyp, defmnt[64], *mtpt, *svs, errbuf[64];
	uchar chal[NWKEYLEN], tmp[NWKEYLEN *2], key[NWKEYLEN];

	svs = nil;
	keyp = "";
	mtpt = defmnt;
	ARGBEGIN{
	case 'd':
		Debug = 1;
		break;
	case 'D':
		chatty9p++;
		break;
	case 'k':
		keyp = EARGF(usage());
		break;
	case 's':
		svs = EARGF(usage());
		break;
	case 'm':
		mtpt = EARGF(usage());
		break;
	default:
		usage();
	}ARGEND

	if(argc != 1)
		usage();

	strncpy(Host, *argv, sizeof(Host));

	fmtinstall('N', ncpfmt);

	addr = netmkaddr(Host, "tcp", "ncp");
	if ((fd = dial(addr, 0, 0, 0)) == -1)
		sysfatal("cannot dial %s", addr);

	if ((up = auth_getuserpasswd(auth_getkey, "proto=pass service=ncp %s", keyp)) == nil) {
		fprint(2, "cannot authenticate\n");
		exits("auth");
	}

	if ((Sess = Attach(fd)) == nil){
		memset(up->passwd, 0, strlen(up->passwd));
		fprint(2, "%s - attach failed, %r\n", Host);
		exits("attach");
	}

	strupr(up->passwd);

	if (GetLoginKey(Sess, 1, chal) != 0){
		/*
		 * As we cannot get the random challange from the server
		 * then we must use the depricated plain-text login
		 */
		if (LoginObject(Sess, up->user, OTuser, up->passwd) == -1){
			memset(up->passwd, 0, strlen(up->passwd));
			rerrstr(errbuf, sizeof(errbuf));
			if (strcmp(errbuf, "no q job rights") == 0)
				fprint(2, "%s:%s - encrypted login only\n", Host, up->user);
			else
				fprint(2, "%s:%s login failed - %r\n", Host, up->user);
			exits("user");
		}
		memset(up->passwd, 0, strlen(up->passwd));

	}
	else{
		/*
		 * NB: We ask for the ObjectID _after_ requesting a
		 * our LoginKey and before doing a KeyedObjectLogin.
		 * This hints to the server to give us the NDS ObjectID
		 * (If it is running NDS), nescessary for authentication.
		 * The server specific ObjectID for the user is returned by
		 * GetBinderyObjectId() called at "any other time".
		 */

		if (GetBinderyObjectId(Sess, up->user, OTuser, &nds_uid) != 0){
			memset(up->passwd, 0, strlen(up->passwd));
			rerrstr(errbuf, sizeof(errbuf));
			if (strcmp(errbuf, "no such object") == 0)
				fprint(2, "%s:%s - unknown username\n", Host, up->user);
			else
				fprint(2, "%s:%s get userid failed - %r\n", Host, up->user);
			exits("user");
		}

		p = uid;
		*(p++) = (nds_uid >> 24) & 0xff;
		*(p++) = (nds_uid >> 16) & 0xff;
		*(p++) = (nds_uid >> 8) & 0xff;
		*(p++) = nds_uid & 0xff;
		USED(p);

		shuffle(uid, (uchar *)up->passwd, strlen(up->passwd), tmp);
		memset(up->passwd, 0, strlen(up->passwd));
		nw_encrypt(chal, tmp, key);

		/*
		 * the "old password" error looks apropriate, and is taken
		 * from the Linux ncpfs code, however my NW 5.0 server returns
		 * "unable to bind" on password expiration (grace logins still apply)
		 */
		if (KeyedObjectLogin(Sess, OTuser, (char *)up->user, key) != 0){
			rerrstr(errbuf, sizeof(errbuf));
			if (strcmp(errbuf, "old password") == 0 ||
			    strcmp(errbuf, "unable to bind") == 0){
				fprint(2, "%s: warning %s:%s - password expiration imminent\n",
					argv0, up->user, Host);
			}
			else{
				fprint(2, "%s: %s:%s - login failed, %r\n", argv0, Host, up->user);
				exits("login");
			}
		}
	}


	maxpkt = MTU;
	if (NegotiateBufferSize(Sess, &maxpkt) == -1)
		sysfatal("negotiate MTU - %r");
	free(Sess->buf);
	Sess->mtu = maxpkt;
	Sess->buf = emalloc9p(Sess->mtu);
	Maxio = maxpkt - 32;			// leave space for packet headers

	if (GetFileServerDateAndTime(Sess, &fstime) == -1)
		sysfatal("get FS time - %r");
	Slip = fstime - time(nil);

	if (GetFileServerInfo(Sess, &fsi) == -1)
		sysfatal("get FS info - %r");
	Fsver = fsi.fsvermaj * 1000 + fsi.fsvermin;
	Bigfiles = fsi.bigfiles;
	Numvol = fsi.numvol;

	/*
	 * by doing this now we get the users
	 * bindery user ID rather than their NDS user ID
	 */
	if (GetBinderyObjectId(Sess, up->user, OTuser, &Myuid) != 0){
		fprint(2, "%s:%s get userid failed - %r\n", Host, up->user);
		exits("user");
	}

	strcpy(defmnt, "/n/");
	strcat(defmnt, *argv);

	postmountsrv(&fs, svs, mtpt, MREPL);
	exits(nil);
}


Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.