add cifsd

This commit is contained in:
cinap_lenrek 2011-05-09 10:42:20 +00:00
parent 7dfb8b6ec5
commit 4b550911d9
16 changed files with 4439 additions and 0 deletions

105
sys/man/8/cifsd Normal file
View file

@ -0,0 +1,105 @@
.TH cifsd 8
.SH NAME
cifsd \- CIFS/SMB network daemon
.SH SYNOPSIS
.B ip/cifsd
[
.B -t
] [
.B -d
] [
.B -f
.I debuglog
] [
.B -w
.I name
] [
.B -o
.I option
] ... [
.I conndir
]
.SH DESCRIPTION
.I Cifsd
exports filesystems to
.SM CIFS or
.SM SMB
clients like Microsoft \(tm Windows.
.PP
It is normally started by the network listen process via the
.B /rc/bin/service/tcp445
service script (see
.IR listen (8)),
wich passes
.I conndir
and filedescriptors 0 and 1 to the incoming connection.
.PP
Users are authenticated by ther Inferno/pop secret held by the auth server.
When successfull,
.I cifsd
changes its user id and namespace to the authenticated user.
Informative log messages are appended to
.B /sys/log/cifsd
if it exists.
.PP
By default the share
.B local
is offered, which represents the root of the namespace
described by
.B /lib/namespace.
If a different name is explicitly requested by the client then
.B /bin/9fs
(see
.IR srv (4))
is invoked to attach that filesystem, which is then exported instead.
.PP
The flags are:
.TP
.B t
Run the server in trusted mode, so it will not require
authentication from the client and keep running in the callers
namespace.
.TP
.B d
Enable or increases debug verbosity for the
.I debuglog
file. Debug messages are never written to the system logfile.
.TP
.B f
Specify the filename for the
.I debuglog
file. If not specified no debug messages are generated.
.TP
.B w
Set the workgroup (or primary domain) to
.I name. The default is
.SM WORKGROUP
.TP
.B o
Enables the following
.I option
string.
This flag can appear multiple times when more than one option has to
be enabled. Valid options are:
.RS
.TP
.B trspaces
transforms whitespaces in filenames to non breaking whitespaces. This is usefull
when exporting filesystems other than fossil.
.TP
.B casesensitive
By default, filename lookups are done case insensitive to match
windows filesystem sematics. This option disables case insensitive
lookups wich can result in a performance improvement, but might break
some applications.
.SH FILES
.B /rc/bin/service/tcp445
.br
.B /sys/log/cifsd
.br
.B /lib/namespace
.SH SOURCE
.B /sys/src/cmd/ip/cifsd
.SH "SEE ALSO"
.IR listen (8),
.IR srv (4)

View file

@ -0,0 +1,20 @@
look at the cifsd.man manpage for instrctions.
check for new releases on the web:
http://9hal.ath.cx/usr/cinap_lenrek/cifsd.tgz
http://9hal.ath.cx/usr/cinap_lenrek/
or on sources:
/n/sources/contrib/cinap_lenrek/cifsd.tgz
/n/sources/contrib/cinap_lenrek
you can email me for requests/bugreports/contrib at:
cinap_lenrek AT gmx DOT de
special thanks goes to:
capso (http://nanosouffle.net/)
for testing and bug reporting
steve simon (http://quintile.net/)
factotum/authsrv support for NTLM auth and cifsd testing and bug reporting

232
sys/src/cmd/ip/cifsd/dat.h Normal file
View file

@ -0,0 +1,232 @@
typedef struct Rop Rop;
typedef struct Req Req;
typedef struct Trans Trans;
typedef struct Share Share;
typedef struct File File;
typedef struct Find Find;
typedef struct Tree Tree;
struct Rop
{
int (*strpack)(uchar *, uchar *, uchar *, void *);
int (*strunpack)(uchar *, uchar *, uchar *, void *);
int (*namepack)(uchar *, uchar *, uchar *, void *);
int (*nameunpack)(uchar *, uchar *, uchar *, void *);
int (*untermstrpack)(uchar *, uchar *, uchar *, void *);
int (*untermnamepack)(uchar *, uchar *, uchar *, void *);
};
struct Req
{
int cmd;
int tid;
int pid;
int uid;
int mid;
int flags;
int flags2;
uchar sig[8];
uchar *lh, *rh, *rp, *re;
Rop *o;
char *name;
void (*respond)(Req *r, int err);
int (*namecmp)(char *, char *);
};
struct Trans
{
int cmd;
int flags;
struct {
struct {
uchar *b, *p, *e;
} param, data, setup;
} in, out;
Req *r;
Rop *o;
char *name;
void (*respond)(Trans *t, int err);
int (*namecmp)(char *, char *);
};
struct File
{
int ref;
int fd;
int rtype;
int dacc;
char *path;
void *aux;
};
struct Find
{
int ref;
int attr;
char *base;
char *pattern;
int casesensitive;
int index;
Dir *dotdot;
Dir *dot;
Dir *dir;
int ndir;
};
struct Share
{
Share *next;
char *service;
int stype;
char *name;
char *root;
char *remark;
char *fsname;
int namelen;
vlong allocsize;
vlong freesize;
int sectorsize;
int blocksize;
};
struct Tree
{
int tid;
void **file;
int nfile;
void **find;
int nfind;
Share *share;
};
int debug;
int trspaces;
int needauth;
char *domain;
char *progname;
char *osname;
char *remotesys;
char *remoteuser;
int remotebuffersize;
long starttime;
int tzoff;
enum
{
BUFFERSIZE = 0x8000,
STATUS_INVALID_SMB = 0x00010002,
STATUS_SMB_BAD_TID = 0x00050002,
STATUS_SMB_BAD_FID = 0x00060001,
STATUS_OS2_INVALID_ACCESS = 0x000C0001,
STATUS_SMB_BAD_UID = 0x005B0002,
STATUS_OS2_INVALID_LEVEL = 0x007C0001,
STATUS_NO_MORE_FILES = 0x80000006,
STATUS_INVALID_HANDLE = 0xC0000008,
STATUS_NO_SUCH_FILE = 0xC000000F,
STATUS_ACCESS_DENIED = 0xC0000022,
STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034,
STATUS_OBJECT_NAME_COLLISION = 0xC0000035,
STATUS_OBJECT_PATH_INVALID = 0xC0000039,
STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A,
STATUS_OBJECT_PATH_SYNTAX_BAD = 0xC000003B,
STATUS_SHARING_VIOLATION = 0xC0000043,
STATUS_LOGON_FAILURE = 0xC000006D,
STATUS_FILE_IS_A_DIRECTORY = 0xC00000BA,
STATUS_NOT_SUPPORTED = 0xC00000BB,
STATUS_BAD_DEVICE_TYPE = 0xC00000CB,
STATUS_BAD_NETWORK_NAME = 0xC00000CC,
STATUS_NOT_SAME_DEVICE = 0xC00000D4,
STATUS_DIRECTORY_NOT_EMPTY = 0xC0000101,
/* resource type */
FileTypeDisk = 0,
/* stype */
STYPE_DISKTREE = 0,
STYPE_PRINTQ = 1,
STYPE_DEVICE = 2,
STYPE_IPC = 3,
/* capabilities */
CAP_UNICODE = 0x4,
CAP_LARGEFILES = 0x8,
CAP_NT_SMBS = 0x10,
CAP_NT_STATUS = 0x40,
CAP_NT_FIND = 0x200,
/* extended file attributes */
ATTR_READONLY = 0x1,
ATTR_HIDDEN = 0x2,
ATTR_SYSTEM = 0x4,
ATTR_DIRECTORY = 0x10,
ATTR_ARCHIVE = 0x20,
ATTR_NORMAL = 0x80,
DOSMASK = 0x37,
/* access */
FILE_READ_DATA = 0x1,
FILE_WRITE_DATA = 0x2,
FILE_APPEND_DATA = 0x4,
FILE_EXECUTE = 0x20,
FILE_DELETE = 0x10000,
GENERIC_ALL = 0x10000000,
GENERIC_EXECUTE = 0x20000000,
GENERIC_WRITE = 0x40000000,
GENERIC_READ = 0x80000000,
READMASK =
FILE_READ_DATA |
FILE_EXECUTE |
GENERIC_ALL |
GENERIC_EXECUTE |
GENERIC_READ,
WRITEMASK =
FILE_WRITE_DATA |
FILE_APPEND_DATA |
GENERIC_ALL |
GENERIC_WRITE,
/* share access */
FILE_SHARE_NONE = 0,
FILE_SHARE_READ = 1,
FILE_SHARE_WRITE = 2,
FILE_SHARE_DELETE = 4,
FILE_SHARE_COMPAT = -1,
/* createdisposition */
FILE_SUPERSEDE = 0,
FILE_OPEN,
FILE_CREATE,
FILE_OPEN_IF,
FILE_OVERWRITE,
FILE_OVERWRITE_IF,
/* createaction */
FILE_SUPERSEDED = 0,
FILE_OPEND,
FILE_CREATED,
FILE_OVERWRITTEN,
/* createoptions */
FILE_DIRECTORY_FILE = 0x1,
FILE_NON_DIRECTORY_FILE = 0x40,
FILE_DELETE_ON_CLOSE = 0x1000,
FILE_OPEN_BY_FILE_ID = 0x2000,
};

218
sys/src/cmd/ip/cifsd/dir.c Normal file
View file

@ -0,0 +1,218 @@
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"
static char*
append(char **p, char *s)
{
int n;
char *o;
if(s == nil)
return nil;
n = strlen(s)+1;
memmove(o = *p, s, n);
*p += n;
return o;
}
static Dir*
xdirdup(Dir *d, int n)
{
char *p;
Dir *o;
int i;
p = nil;
for(i=0; i<n; i++){
p += strlen(d[i].name)+1;
if(d[i].uid) p += strlen(d[i].uid)+1;
if(d[i].gid) p += strlen(d[i].gid)+1;
if(d[i].muid) p += strlen(d[i].muid)+1;
}
o = malloc(n*sizeof(*d) + (int)p);
memmove(o, d, n*sizeof(*d));
p = (char*)&o[n];
for(i=0; i<n; i++){
o[i].name = append(&p, d[i].name);
o[i].uid = append(&p, d[i].uid);
o[i].gid = append(&p, d[i].gid);
o[i].muid = append(&p, d[i].muid);
}
return o;
}
static int xdirread0(char **path, int (*namecmp)(char *, char *), Dir **d);
int
xdirread(char **path, int (*namecmp)(char *, char *), Dir **d)
{
Dir *t;
int n;
if((n = xdirread0(path, namecmp, &t)) > 0)
*d = xdirdup(t, n);
else
*d = nil;
return n;
}
static Dir*
xdirstat0(char **path, int (*namecmp)(char *, char *), char *err)
{
char *base, *name;
Dir *d, *t;
int n, i;
if(d = dirstat(*path))
return d;
if(!splitpath(*path, &base, &name))
return nil;
if((n = xdirread0(&base, namecmp, &t)) < 0)
goto out;
for(i=0; i<n; i++){
if(namecmp(t[i].name, name))
continue;
free(*path); *path = conspath(base, t[i].name);
d = xdirdup(&t[i], 1);
goto out;
}
werrstr("%s", err);
out:
free(base);
free(name);
return d;
}
Dir*
xdirstat(char **path, int (*namecmp)(char *, char *))
{
return xdirstat0(path, namecmp, "name not found");
}
typedef struct XDir XDir;
struct XDir
{
Qid qid;
char *path;
int ndir;
Dir *dir;
XDir *next;
};
static void
freexdir(XDir *x)
{
free(x->path);
free(x->dir);
free(x);
}
static int
qidcmp(Qid *q1, Qid *q2)
{
return (q1->type != q2->type) || (q1->path != q2->path) || (q1->vers != q2->vers);
}
static XDir *xdirlist;
static int xdircount;
static int
xdirread0(char **path, int (*namecmp)(char *, char *), Dir **d)
{
XDir *x, *p;
int fd, n;
Dir *t;
t = nil;
for(p = nil, x = xdirlist; x; p=x, x=x->next){
if(namecmp(x->path, *path))
continue;
if(x == xdirlist)
xdirlist = x->next;
else
p->next = x->next;
while(t = dirstat(x->path)){
if(qidcmp(&t->qid, &x->qid))
break;
free(t);
x->next = xdirlist;
xdirlist = x;
if(strcmp(x->path, *path)){
free(*path);
*path = strdup(x->path);
}
if(d) *d = x->dir;
return x->ndir;
}
xdircount--;
freexdir(x);
break;
}
if((fd = open(*path, OREAD)) < 0){
free(t);
if(t = xdirstat0(path, namecmp, "directory entry not found"))
fd = open(*path, OREAD);
} else if(t == nil)
t = dirfstat(fd);
n = -1;
if(fd < 0 || t == nil)
goto out;
if(t->qid.type != QTDIR){
werrstr("not a directory");
goto out;
}
if((n = dirreadall(fd, d)) < 0)
goto out;
if(xdircount >= 8){
xdircount--;
for(p = xdirlist, x = xdirlist->next; x->next; p = x, x = x->next)
;
p->next = nil;
freexdir(x);
}
x = mallocz(sizeof(*x), 1);
x->qid = t->qid;
x->path = strdup(*path);
x->ndir = n;
x->dir = *d;
x->next = xdirlist;
xdirlist = x;
xdircount++;
out:
if(fd >= 0)
close(fd);
free(t);
return n;
}
void
xdirflush(char *path, int (*namecmp)(char *, char *))
{
XDir **pp, **xx, *x;
char *d, *s;
int n;
n = strlen(path);
if(s = strrchr(path, '/'))
n = s - path;
d = smprint("%.*s", n, path);
s = malloc(++n);
for(pp = &xdirlist; x = *pp; pp = xx){
xx = &x->next;
snprint(s, n, "%s", x->path);
if(namecmp(d, s) == 0){
*pp = *xx; xx = pp;
xdircount--;
freexdir(x);
}
}
free(s);
free(d);
}

View file

@ -0,0 +1,129 @@
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"
enum {
/* error class */
ERRDOS = 1,
ERRSRV = 2,
ERRHRD = 3,
ERRCMD = 0xFF,
/* error codes */
ERRbadfunc = 0x1,
ERRbadfile = 0x2,
ERRbadpath = 0x3,
ERRnofids = 0x4,
ERRnoaccess = 0x5,
ERRbadfid = 0x6,
ERRbadmcp = 0x7,
ERRnomem = 0x8,
ERRbadmem = 0x9,
ERRbadenv = 0xA,
ERRbadformat = 0xB,
ERRbadaccess = 0xC,
ERRbaddata = 0xD,
ERRbaddrive = 0xF,
ERRremcd = 0x10,
ERRdiffdevice = 0x11,
ERRnofiles = 0x12,
ERRgeneral = 0x1F,
ERRbadshare = 0x20,
ERRlock = 0x21,
ERReof = 0x26,
ERRunsup = 0x32,
ERRfilexists = 0x50,
ERRinvalidparam = 0x57,
ERRunknownlevel = 0x7C,
ERRbadpipe = 0xE6,
ERRinvnetname = 0x06,
ERRreqnotaccep = 0x47,
ERRnosuchshare = 0x43,
ERRerror = 0x1,
ERRbadpw = 0x2,
ERRaccess = 0x4,
ERRinvtid = 0x5,
ERRinvdevice = 0x7,
ERRbaduid = 0x5b,
};
int
doserror(int err)
{
#define SE(c,e) e<<16 | c
static struct Ent {
int error;
int status;
} tab[] = {
SE(ERRSRV, ERRerror), STATUS_INVALID_SMB,
SE(ERRSRV, ERRinvtid), STATUS_SMB_BAD_TID,
SE(ERRDOS, ERRbadfid), STATUS_SMB_BAD_FID,
SE(ERRDOS, ERRbadaccess), STATUS_OS2_INVALID_ACCESS,
SE(ERRSRV, ERRbaduid), STATUS_SMB_BAD_UID,
SE(ERRDOS, ERRunknownlevel), STATUS_OS2_INVALID_LEVEL,
SE(ERRDOS, ERRnofiles), STATUS_NO_MORE_FILES,
SE(ERRDOS, ERRbadfid), STATUS_INVALID_HANDLE,
SE(ERRDOS, ERRnoaccess), STATUS_ACCESS_DENIED,
SE(ERRDOS, ERRbadfile), STATUS_OBJECT_NAME_NOT_FOUND,
SE(ERRDOS, ERRfilexists), STATUS_OBJECT_NAME_COLLISION,
SE(ERRDOS, ERRbadpath), STATUS_OBJECT_PATH_INVALID,
SE(ERRDOS, ERRbadpath), STATUS_OBJECT_PATH_NOT_FOUND,
SE(ERRDOS, ERRbadpath), STATUS_OBJECT_PATH_SYNTAX_BAD,
SE(ERRDOS, ERRbadshare), STATUS_SHARING_VIOLATION,
SE(ERRSRV, ERRbadpw), STATUS_LOGON_FAILURE,
SE(ERRDOS, ERRnoaccess), STATUS_FILE_IS_A_DIRECTORY,
SE(ERRDOS, ERRunsup), STATUS_NOT_SUPPORTED,
SE(ERRSRV, ERRinvdevice), STATUS_BAD_DEVICE_TYPE,
SE(ERRSRV, ERRinvnetname), STATUS_BAD_NETWORK_NAME,
SE(ERRDOS, ERRdiffdevice), STATUS_NOT_SAME_DEVICE,
SE(ERRDOS, ERRremcd), STATUS_DIRECTORY_NOT_EMPTY,
SE(ERRSRV, ERRerror), 0,
};
struct Ent *p;
for(p=tab; p->status; p++)
if(p->status == err)
break;
return p->error;
}
int
smbmkerror(void)
{
static struct Ent {
int status;
char *str;
} tab[] = {
STATUS_ACCESS_DENIED, "permission denied",
STATUS_ACCESS_DENIED, "access permission denied",
STATUS_ACCESS_DENIED, "create prohibited",
STATUS_ACCESS_DENIED, "mounted directory forbids creation",
STATUS_DIRECTORY_NOT_EMPTY, "directory not empty",
STATUS_NO_SUCH_FILE, "no such file",
STATUS_OBJECT_NAME_NOT_FOUND, "name not found",
STATUS_OBJECT_PATH_NOT_FOUND, "directory entry not found",
STATUS_OBJECT_PATH_NOT_FOUND, "not a directory",
STATUS_OBJECT_PATH_NOT_FOUND, "does not exist",
STATUS_OBJECT_PATH_SYNTAX_BAD, "bad character",
STATUS_OBJECT_PATH_SYNTAX_BAD, "file name syntax",
STATUS_OBJECT_NAME_COLLISION, "file already exists",
STATUS_FILE_IS_A_DIRECTORY, "is a directory",
/* kenfs */
STATUS_OBJECT_NAME_COLLISION, "create/wstat -- file exists",
STATUS_ACCESS_DENIED, "wstat -- not owner",
STATUS_ACCESS_DENIED, "wstat -- not in group",
/* unknown error */
STATUS_INVALID_SMB, nil,
};
char buf[ERRMAX];
struct Ent *p;
rerrstr(buf, sizeof(buf));
for(p = tab; p->str; p++)
if(strstr(buf, p->str))
break;
if(debug)
fprint(2, "smbmkerror: %s -> %lux\n", buf, (ulong)p->status);
return p->status;
}

319
sys/src/cmd/ip/cifsd/file.c Normal file
View file

@ -0,0 +1,319 @@
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"
typedef struct Opl Opl;
struct Opl
{
int ref;
ulong hash;
char *path;
Opl *next;
File *locked;
int dacc;
int sacc;
int delete;
};
static Opl *locktab[64];
static Opl*
getopl(char **path, int (*namecmp)(char *, char *), int dacc, int sacc)
{
Opl *opl, **pp;
ulong h;
h = namehash(*path);
for(pp = &locktab[h % nelem(locktab)]; *pp; pp=&((*pp)->next)){
opl = *pp;
if(namecmp(opl->path, *path))
continue;
if(sacc == FILE_SHARE_COMPAT){
if(sacc != opl->sacc)
return nil;
if((opl->dacc | dacc) & WRITEMASK)
return nil;
} else {
if(opl->sacc == FILE_SHARE_COMPAT)
return nil;
if((dacc & READMASK) && (opl->sacc & FILE_SHARE_READ)==0)
return nil;
if((dacc & WRITEMASK) && (opl->sacc & FILE_SHARE_WRITE)==0)
return nil;
if((dacc & FILE_DELETE) && (opl->sacc & FILE_SHARE_DELETE)==0)
return nil;
}
opl->ref++;
if(strcmp(opl->path, *path)){
free(*path);
*path = strdup(opl->path);
}
return opl;
}
opl = mallocz(sizeof(*opl), 1);
opl->ref = 1;
opl->hash = h;
opl->dacc = dacc;
opl->sacc = sacc;
*pp = opl;
return opl;
}
static void
putopl(Opl *opl)
{
Opl **pp;
if(opl==nil || --opl->ref)
return;
for(pp = &locktab[opl->hash % nelem(locktab)]; *pp; pp=&((*pp)->next)){
if(*pp == opl){
*pp = opl->next;
opl->next = nil;
break;
}
}
if(opl->path && opl->delete){
if(debug)
fprint(2, "remove on close: %s\n", opl->path);
if(remove(opl->path) < 0)
logit("remove %s: %r", opl->path);
}
free(opl->path);
free(opl);
}
File*
createfile(char *path, int (*namecmp)(char *, char *),
int dacc, int sacc, int cdisp, int copt, vlong csize, int fattr, int *pact, Dir **pdir, int *perr)
{
int err, act, fd, mode, perm, isdir, delete;
Opl *o;
File *f;
Dir *d;
o = nil;
f = nil;
d = nil;
fd = -1;
path = strdup(path);
if(copt & FILE_OPEN_BY_FILE_ID){
unsup:
err = STATUS_NOT_SUPPORTED;
goto out;
}
if((o = getopl(&path, namecmp, dacc, sacc)) == nil){
err = STATUS_SHARING_VIOLATION;
goto out;
}
mode = -1;
if(dacc & READMASK)
mode += 1;
if(dacc & WRITEMASK)
mode += 2;
delete = isdir = 0;
if(d = xdirstat(&path, namecmp)){
if(mode >= 0 && d->type != '/' && d->type != 'M'){
noaccess:
err = STATUS_ACCESS_DENIED;
goto out;
}
isdir = d->qid.type == QTDIR;
switch(cdisp){
case FILE_SUPERSEDE:
act = FILE_SUPERSEDED;
if(remove(path) < 0){
logit("remove: %r");
oserror:
err = smbmkerror();
goto out;
}
goto docreate;
case FILE_OVERWRITE:
case FILE_OVERWRITE_IF:
act = FILE_OVERWRITTEN;
if(isdir || (mode != OWRITE && mode != ORDWR))
goto noaccess;
d->length = 0;
mode |= OTRUNC;
break;
case FILE_OPEN:
case FILE_OPEN_IF:
act = FILE_OPEND;
break;
case FILE_CREATE:
err = STATUS_OBJECT_NAME_COLLISION;
goto out;
default:
goto unsup;
}
if((copt & FILE_DIRECTORY_FILE) && !isdir)
goto noaccess;
if((copt & FILE_NON_DIRECTORY_FILE) && isdir){
err = STATUS_FILE_IS_A_DIRECTORY;
goto out;
}
if(copt & FILE_DELETE_ON_CLOSE){
if(isdir || (dacc & FILE_DELETE)==0)
goto noaccess;
delete = 1;
}
if(mode >= 0 && !isdir)
if((fd = open(path, mode)) < 0)
goto oserror;
} else {
switch(cdisp){
case FILE_SUPERSEDE:
case FILE_CREATE:
case FILE_OPEN_IF:
case FILE_OVERWRITE_IF:
act = FILE_CREATED;
break;
case FILE_OVERWRITE:
case FILE_OPEN:
err = smbmkerror();
goto out;
default:
goto unsup;
}
docreate:
perm = 0666;
if(fattr & ATTR_READONLY)
perm &= ~0222;
if(copt & FILE_DIRECTORY_FILE){
perm |= DMDIR | 0111;
mode = OREAD;
isdir = 1;
}
if(mode < 0)
mode = OREAD;
if(copt & FILE_DELETE_ON_CLOSE){
if(isdir || (dacc & FILE_DELETE)==0)
goto noaccess;
delete = 1;
}
if((fd = create(path, mode, perm)) < 0){
char *name, *base;
Dir *t;
err = smbmkerror();
if(!splitpath(path, &base, &name))
goto out;
if((t = xdirstat(&base, namecmp)) == nil){
free(base); free(name);
goto out;
}
free(t);
free(path); path = conspath(base, name);
free(base); free(name);
if((fd = create(path, mode, perm)) < 0)
goto oserror;
}
if(csize > 0 && !isdir){
Dir nd;
nulldir(&nd);
nd.length = csize;
if(dirfwstat(fd, &nd) < 0)
goto oserror;
}
if(pdir)
if((d = dirfstat(fd)) == nil)
goto oserror;
if(isdir){
close(fd);
fd = -1;
}
}
f = mallocz(sizeof(*f), 1);
f->ref = 1;
f->fd = fd; fd = -1;
f->rtype = FileTypeDisk;
f->dacc = dacc;
o->delete |= delete;
if(o->path == nil){
o->path = path;
path = nil;
}
f->path = o->path;
f->aux = o; o = nil;
if(pact)
*pact = act;
if(pdir){
*pdir = d;
d = nil;
}
err = 0;
out:
if(perr)
*perr = err;
if(fd >= 0)
close(fd);
free(path);
putopl(o);
free(d);
return f;
}
Dir*
statfile(File *f)
{
if(f == nil)
return nil;
if(f->fd >= 0)
return dirfstat(f->fd);
else
return dirstat(f->path);
}
int
lockfile(File *f)
{
Opl *opl = f->aux;
if(opl->locked && opl->locked != f)
return 0;
opl->locked = f;
return 1;
}
void
deletefile(File *f, int delete)
{
Opl *opl = f->aux;
if(opl->delete == delete)
return;
opl->delete = delete;
}
int
deletedfile(File *f)
{
Opl *opl = f->aux;
return opl->delete;
}
void
putfile(File *f)
{
Opl *opl;
if(f == nil || --f->ref)
return;
if(f->fd >= 0)
close(f->fd);
opl = f->aux;
if(opl->locked == f)
opl->locked = nil;
putopl(opl);
free(f);
}

191
sys/src/cmd/ip/cifsd/find.c Normal file
View file

@ -0,0 +1,191 @@
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"
static int
iswild(char *pattern)
{
return strchrs(pattern, "*?<>\"") != nil;
}
static int
matchpattern(char *name, char *pattern, int casesensitive)
{
Rune p, r;
int n;
while(*pattern){
pattern += chartorune(&p, pattern);
n = chartorune(&r, name);
switch(p){
case '?':
if(r == 0)
return 0;
name += n;
break;
case '>':
switch(r){
case '.':
if(!name[1] && matchpattern(name+1, pattern, casesensitive))
return 1;
case 0:
return matchpattern(name, pattern, casesensitive);
}
name += n;
break;
case '*':
case '<':
while(r){
if(matchpattern(name, pattern, casesensitive))
return 1;
if(p == '<' && r == '.' && !strchrs(name+1, ".")){
name++;
break;
}
n = chartorune(&r, name += n);
}
break;
case '"':
if(r == 0 && matchpattern(name, pattern, casesensitive))
return 1;
if(r != '.')
return 0;
name += n;
break;
default:
if(p != r && casesensitive || toupperrune(p) != toupperrune(r))
return 0;
name += n;
}
}
return *name == 0;
}
int
matchattr(Dir *d, int s)
{
int a, m;
m = ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY;
a = dosfileattr(d);
if((a & ~s) & m)
return 0;
m = (s >> 8) & m;
if(m && ((m & a) != m))
return 0;
return 1;
}
Find*
openfind(char *path, int (*namecmp)(char *, char *), int attr, int withdot, int *perr)
{
char *base, *pattern, *parent;
Dir *dir;
int ndir, err;
Find *f;
f = nil;
path = strdup(path);
base = pattern = parent = nil;
if(!splitpath(path, &base, &pattern)){
err = STATUS_OBJECT_PATH_SYNTAX_BAD;
goto out;
}
if(debug)
fprint(2, "base %s\npattern %s\nattr %x\nwithdot %d\n", base, pattern, attr, withdot);
if(iswild(pattern)){
if((ndir = xdirread(&base, namecmp, &dir)) < 0){
err = smbmkerror();
goto out;
}
} else {
ndir = 0;
withdot = 0;
if(dir = xdirstat(&path, namecmp)){
free(base);
free(pattern);
splitpath(path, &base, &pattern);
ndir++;
}
}
f = mallocz(sizeof(*f), 1);
f->ref = 1;
f->base = base;
f->pattern = pattern;
f->attr = attr;
f->dir = dir;
f->ndir = ndir;
f->index = 0;
f->casesensitive = (namecmp == strcmp);
if(withdot){
if(f->dot = dirstat(base))
f->dot->name = ".";
if(splitpath(base, &parent, nil))
if(f->dotdot = dirstat(parent))
f->dotdot->name = "..";
}
base = nil;
pattern = nil;
err = 0;
out:
if(perr)
*perr = err;
free(base);
free(pattern);
free(parent);
free(path);
return f;
}
int
readfind(Find *f, int i, Dir **dp)
{
Dir *d;
int x;
x = i;
if(f->dot && f->dotdot)
x -= 2;
for(;;){
if(x == -2){
d = f->dot;
} else if(x == -1){
d = f->dotdot;
} else if(x < f->ndir){
d = f->dir + x;
} else {
d = nil;
i = -1;
break;
}
if(matchattr(d, f->attr) && matchpattern(d->name, f->pattern, f->casesensitive))
break;
i++; x++;
}
if(debug && d)
fprint(2, "readfile [%d] attr=%x name=%s\n", i, extfileattr(d), d->name);
*dp = d;
return i;
}
void
putfind(Find *f)
{
if(f == nil || --f->ref)
return;
free(f->pattern);
free(f->base);
free(f->dot);
free(f->dotdot);
free(f->dir);
free(f);
}

View file

@ -0,0 +1,85 @@
/* pack */
int unpack(uchar *b, uchar *p, uchar *e, char *f, ...);
int vunpack(uchar *b, uchar *p, uchar *e, char *f, va_list a);
int pack(uchar *b, uchar *p, uchar *e, char *f, ...);
int vpack(uchar *b, uchar *p, uchar *e, char *f, va_list a);
/* error */
int smbmkerror(void);
int doserror(int err);
/* util */
void logit(char *fmt, ...);
#pragma varargck argpos logit 1
char *getremote(char *dir);
char *conspath(char *base, char *name);
int splitpath(char *path, char **base, char **name);
void dumphex(char *s, uchar *h, uchar *e);
void todatetime(long time, int *pdate, int *ptime);
long fromdatetime(int date, int time);
vlong tofiletime(long time);
long fromfiletime(vlong filetime);
int filesize32(vlong);
vlong allocsize(vlong size, int blocksize);
int extfileattr(Dir *d);
int dosfileattr(Dir *d);
ulong namehash(char *s);
char *strtr(char *s, Rune (*tr)(Rune));
char *strchrs(char *s, char *c);
int smbstrpack8(uchar *, uchar *p, uchar *e, void *arg);
int smbstrpack16(uchar *b, uchar *p, uchar *e, void *arg);
int smbstrunpack8(uchar *, uchar *p, uchar *e, void *arg);
int smbstrunpack16(uchar *b, uchar *p, uchar *e, void *arg);
int smbnamepack8(uchar *b, uchar *p, uchar *e, void *arg);
int smbnamepack16(uchar *b, uchar *p, uchar *e, void *arg);
int smbnameunpack8(uchar *b, uchar *p, uchar *e, void *arg);
int smbnameunpack16(uchar *b, uchar *p, uchar *e, void *arg);
int smbuntermstrpack8(uchar *b, uchar *p, uchar *e, void *arg);
int smbuntermstrpack16(uchar *b, uchar *p, uchar *e, void *arg);
int smbuntermnamepack8(uchar *b, uchar *p, uchar *e, void *arg);
int smbuntermnamepack16(uchar *b, uchar *p, uchar *e, void *arg);
/* smb */
void smbcmd(Req *r, int cmd, uchar *h, uchar *p, uchar *e);
/* share */
Share *mapshare(char *path);
/* rap */
void transrap(Trans *t);
/* tree */
Tree *connecttree(char *service, char *path, int *perr);
int disconnecttree(int tid);
void logoff(void);
Tree *gettree(int tid);
int newfid(Tree *t, File *f);
void delfid(Tree *t, int fid);
File *getfile(int tid, int fid, Tree **ptree, int *perr);
char *getpath(int tid, char *name, Tree **ptree, int *perr);
int newsid(Tree *t, Find *f);
void delsid(Tree *t, int sid);
Find *getfind(int tid, int sid, Tree **ptree, int *perr);
/* file */
File* createfile(char *path, int (*namecmp)(char *, char *),
int dacc, int sacc, int cdisp, int copt, vlong csize, int fattr, int *pact, Dir **pdir, int *perr);
Dir* statfile(File *f);
void putfile(File *f);
int lockfile(File *f);
void deletefile(File *f, int delete);
int deletedfile(File *f);
/* find */
Find *openfind(char *path, int (*namecmp)(char *, char *),
int attr, int withdot, int *perr);
int matchattr(Dir *d, int s);
int readfind(Find *f, int i, Dir **dp);
void putfind(Find *f);
/* dir */
int xdirread(char **path, int (*namecmp)(char *, char *), Dir **d);
Dir *xdirstat(char **path, int (*namecmp)(char *, char *));
void xdirflush(char *path, int (*namecmp)(char *, char *));

214
sys/src/cmd/ip/cifsd/main.c Normal file
View file

@ -0,0 +1,214 @@
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"
enum {
LENHDR = 4,
MAGIC = 0xFF | ('S'<<8) | ('M'<<16) | ('B'<<24),
SMB_FLAGS_CASE_INSENSITIVE = 0x08,
SMB_FLAGS_CANONICALIZED_PATHS = 0x10,
SMB_FLAGS_REPLY = 0x80,
NOCASEMASK = SMB_FLAGS_CASE_INSENSITIVE | SMB_FLAGS_CANONICALIZED_PATHS,
SMB_FLAGS2_LONG_NAMES = 0x0001,
SMB_FLAGS2_EAS = 0x0002,
SMB_FLAGS2_IS_LONG_NAME = 0x0040,
SMB_FLAGS2_NT_STATUS = 0x4000,
SMB_FLAGS2_UNICODE = 0x8000,
};
static int casesensitive = 0;
static void
respond(Req *r, int err)
{
int n, flags, flags2;
if(err && !(r->flags2 & SMB_FLAGS2_NT_STATUS))
err = doserror(err);
flags = (r->flags & (r->namecmp != strcmp ? NOCASEMASK : 0)) |
SMB_FLAGS_REPLY;
flags2 = (r->flags2 & (SMB_FLAGS2_NT_STATUS |
SMB_FLAGS2_LONG_NAMES | SMB_FLAGS2_UNICODE)) |
SMB_FLAGS2_IS_LONG_NAME;
if(r->cmd != 0x73) /* SMB_COM_SESSION_SETUP_ANDX */
memset(r->sig, 0, sizeof(r->sig));
n = pack(r->rh, r->rh, r->rh+32, "lblbww[]__wwww",
MAGIC, r->cmd, err, flags, flags2, r->pid>>16, r->sig, r->sig+sizeof(r->sig),
r->tid, r->pid & 0xFFFF, r->uid, r->mid);
if(err){
r->rp = r->rh+n;
r->rp += pack(r->rh, r->rp, r->re, "#0b{*2}#1w{}");
}
if(debug > 1)
dumphex("respond", r->rh, r->rp);
if(debug)
fprint(2, "respond: err=%x\n\n", err);
n = r->rp - r->rh;
r->lh[0] = 0;
r->lh[1] = 0;
r->lh[2] = n>>8 & 0xFF;
r->lh[3] = n & 0xFF;
write(1, r->lh, LENHDR+n);
}
static void
receive(uchar *h, uchar *e)
{
static uchar buffer[LENHDR + BUFFERSIZE];
static Rop rop8 = {
.strpack = smbstrpack8,
.strunpack = smbstrunpack8,
.namepack = smbnamepack8,
.nameunpack = smbnameunpack8,
.untermstrpack = smbuntermstrpack8,
.untermnamepack = smbuntermnamepack8,
}, rop16 = {
.strpack = smbstrpack16,
.strunpack = smbstrunpack16,
.namepack = smbnamepack16,
.nameunpack = smbnameunpack16,
.untermstrpack = smbuntermstrpack16,
.untermnamepack = smbuntermnamepack16,
};
uchar *sig;
int n, hpid, magic;
Req r;
if(debug > 1)
dumphex("receive", h, e);
if((n = unpack(h, h, e, "lb____bww{.________}__wwww", &magic,
&r.cmd, &r.flags, &r.flags2, &hpid, &sig, &r.tid, &r.pid, &r.uid, &r.mid)) == 0){
logit("bad smb header");
return;
}
if(magic != MAGIC){
logit("bad smb magic");
return;
}
r.pid |= hpid<<16;
r.lh = buffer;
r.rh = r.lh + LENHDR;
r.rp = r.rh + n;
r.re = r.rh + remotebuffersize;
r.o = (r.flags2 & SMB_FLAGS2_UNICODE) ? &rop16 : &rop8;
memmove(r.sig, sig, sizeof(r.sig));
r.name = nil;
r.respond = respond;
r.namecmp = ((r.flags & NOCASEMASK) && !casesensitive) ? cistrcmp : strcmp;
smbcmd(&r, r.cmd, h, h+n, e);
}
static void
serve(void)
{
static uchar buffer[LENHDR + BUFFERSIZE];
uchar *m, *me;
uchar *p, *pe;
uchar *hl;
int n;
p = hl = buffer;
pe = p + LENHDR+BUFFERSIZE;
for(;;){
n = read(0, p, pe - p);
if(n <= 0)
break;
p += n;
Next:
if(p - hl < LENHDR)
continue;
n = hl[2]<<8 | hl[3];
m = hl + LENHDR;
me = m + n;
if(me > pe){
logit("message too big");
break;
}
if(me > p)
continue;
receive(m, me);
n = p - me;
p = hl + n;
if(n > 0){
memmove(hl, me, n);
goto Next;
}
}
}
void
main(int argc, char *argv[])
{
static struct {
char *s;
int *v;
} opts[] = {
{ "trspaces", &trspaces },
{ "casesensitive", &casesensitive },
{ nil, nil }
}, *o;
char *log, *opt;
Tm *tm;
int pid;
debug = 0;
trspaces = 0;
needauth = 1;
domain = "WORKGROUP";
progname = "cifsd";
osname = "Plan 9";
log = nil;
ARGBEGIN {
case 't':
needauth = 0;
break;
case 'd':
debug++;
break;
case 'f':
log = EARGF(exits("bad arg"));
break;
case 'w':
domain = EARGF(exits("bad arg"));
break;
case 'o':
opt = EARGF(exits("bad arg"));
for(o=opts; o->s; o++)
if(strcmp(opt, o->s) == 0){
*o->v = 1;
break;
}
if(o->s == nil)
exits("bad arg");
break;
} ARGEND
close(2);
if(!log || open(log, OWRITE) < 0){
open("/dev/null", OWRITE);
debug = 0;
}
remotesys = argc ? getremote(argv[argc-1]) : nil;
remoteuser = nil;
remotebuffersize = BUFFERSIZE;
starttime = time(nil);
pid = getpid();
srand(starttime ^ pid);
tm = localtime(starttime);
tzoff = tm->tzoff;
logit("started [%d]", pid);
serve();
logoff();
logit("exited [%d]", pid);
}

View file

@ -0,0 +1,21 @@
</$objtype/mkfile
BIN=/$objtype/bin/ip
TARG=cifsd
HFILES=dat.h fns.h
OFILES=\
pack.$O \
util.$O \
error.$O \
smb.$O \
rap.$O \
share.$O \
tree.$O \
dir.$O \
file.$O \
find.$O \
main.$O \
</sys/src/cmd/mkone

305
sys/src/cmd/ip/cifsd/pack.c Normal file
View file

@ -0,0 +1,305 @@
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"
int
unpack(uchar *b, uchar *p, uchar *e, char *f, ...)
{
va_list a;
int r;
va_start(a, f);
r = vunpack(b, p, e, f, a);
va_end(a);
return r;
}
int
pack(uchar *b, uchar *p, uchar *e, char *f, ...)
{
va_list a;
int r;
va_start(a, f);
r = vpack(b, p, e, f, a);
va_end(a);
return r;
}
int
vunpack(uchar *b, uchar *p, uchar *e, char *f, va_list a)
{
struct {
void *prev;
int o, c, i;
uchar *e;
uchar **ap, **ae;
} sub[8], *sp, *sa;
int (*funpack)(uchar *, uchar *, uchar *, void *);
char c, ff[2];
int i, x, n;
uchar *t;
memset(sub, 0, sizeof(sub));
for(sp = sub; sp < sub+nelem(sub); sp++){
sp->o = -1;
sp->c = -1;
sp->i = 1;
}
t = p;
sp = nil;
sa = sub;
while(c = *f++){
switch(c){
case '_':
case 'b':
if(p >= e)
return 0;
if(c == 'b')
*va_arg(a, int*) = *p;
p++;
break;
case 'w':
if(p+1 >= e)
return 0;
*va_arg(a, int*) = (int)p[1]<<8 | (int)p[0];
p+=2;
break;
case 'l':
if(p+3 >= e)
return 0;
*va_arg(a, int*) = (int)p[3]<<24 | (int)p[2]<<16 | (int)p[1]<<8 | (int)p[0];
p+=4;
break;
case 'v':
if(p+7 >= e)
return 0;
*va_arg(a, vlong*) =
(vlong)p[7]<<56 |
(vlong)p[6]<<48 |
(vlong)p[5]<<40 |
(vlong)p[4]<<32 |
(vlong)p[3]<<24 |
(vlong)p[2]<<16 |
(vlong)p[1]<<8 |
(vlong)p[0];
p += 8;
break;
case '%':
x = *f++ - '0';
while((p - b) % x)
p++;
break;
case 'f':
funpack = va_arg(a, void*);
if((n = funpack(b, p, e, va_arg(a, void*))) == 0)
return 0;
p += n;
break;
case '#':
case '@':
x = *f++ - '0';
ff[0] = *f++;
ff[1] = 0;
if((n = unpack(b, p, e, ff, &i)) == 0)
return 0;
p += n;
if(c == '#'){
sub[x].c = i;
} else {
sub[x].o = i;
}
break;
case '{':
case '[':
sa->prev = sp;
sp = sa++;
if(*f == '*'){
sp->i = f[1]-'0';
f += 2;
}
if(sp->o >= 0 && b + sp->o > p)
if(b + sp->o <= e || *f != '?')
p = b + sp->o;
if(*f == '?')
f++;
sp->o = p - b;
sp->e = e;
if(sp->c >= 0){
e = p + sp->c * sp->i;
if(e > sp->e)
return 0;
}
if(c == '['){
sp->ap = va_arg(a, uchar**);
sp->ae = va_arg(a, uchar**);
}
break;
case '}':
case ']':
e = sp->e;
if(sp->c < 0)
sp->c = ((p - (b + sp->o))+sp->i-1)/sp->i;
p = b + sp->o + sp->c * sp->i;
if(p > e)
return 0;
if(sp->ap)
*sp->ap = b + sp->o;
if(sp->ae)
*sp->ae = p;
sp = sp->prev;
break;
case '.':
*va_arg(a, uchar**) = p;
break;
}
if(p > e)
return 0;
}
return p - t;
}
vpack(uchar *b, uchar *p, uchar *e, char *f, va_list a)
{
struct {
void *prev;
int o, i;
uchar *wc, *wo, wcf, wof;
} sub[8], *sp, *sa;
int (*fpack)(uchar *, uchar *, uchar *, void *);
char c, ff[2];
int i, x, n;
vlong v;
uchar *t;
memset(sub, 0, sizeof(sub));
for(sp = sub; sp < sub+nelem(sub); sp++){
sp->o = -1;
sp->i = 1;
}
t = p;
sp = nil;
sa = sub;
while(c = *f++){
switch(c){
case '_':
case 'b':
if(p >= e)
return 0;
if(c == 'b')
*p++ = va_arg(a, int);
else
*p++ = 0;
break;
case 'w':
if(p+1 >= e)
return 0;
i = va_arg(a, int);
*p++ = i & 0xFF;
*p++ = i>>8 & 0xFF;
break;
case 'l':
if(p+3 >= e)
return 0;
i = va_arg(a, int);
*p++ = i & 0xFF;
*p++ = i>>8 & 0xFF;
*p++ = i>>16 & 0xFF;
*p++ = i>>24 & 0xFF;
break;
case 'v':
if(p+7 >= e)
return 0;
v = va_arg(a, vlong);
*p++ = v & 0xFF;
*p++ = v>>8 & 0xFF;
*p++ = v>>16 & 0xFF;
*p++ = v>>24 & 0xFF;
*p++ = v>>32 & 0xFF;
*p++ = v>>40 & 0xFF;
*p++ = v>>48 & 0xFF;
*p++ = v>>56 & 0xFF;
break;
case '%':
x = *f++ - '0';
while((p - b) % x){
if(p >= e)
return 0;
*p++ = 0;
}
break;
case 'f':
fpack = va_arg(a, void*);
if((n = fpack(b, p, e, va_arg(a, void*))) == 0)
return 0;
p += n;
break;
case '#':
case '@':
x = *f++ - '0';
ff[0] = *f++;
ff[1] = 0;
if((n = pack(b, p, e, ff, 0)) == 0)
return 0;
if(c == '#'){
sub[x].wc = p;
sub[x].wcf = ff[0];
} else {
sub[x].wo = p;
sub[x].wof = ff[0];
}
p += n;
break;
case '{':
case '[':
sa->prev = sp;
sp = sa++;
if(*f == '*'){
sp->i = f[1]-'0';
f += 2;
}
if(*f == '?')
f++;
sp->o = p - b;
if(c == '['){
uchar *s, *se;
s = va_arg(a, uchar*);
se = va_arg(a, uchar*);
n = se - s;
if(n < 0 || p + n > e)
return 0;
if(p != s)
memmove(p, s, n);
p += n;
}
break;
case '}':
case ']':
n = ((p - (b + sp->o))+sp->i-1)/sp->i;
p = b + sp->o + n * sp->i;
if(sp->wc){
ff[0] = sp->wcf;
ff[1] = 0;
pack(b, sp->wc, e, ff, n);
}
if(sp->wo){
ff[0] = sp->wof;
ff[1] = 0;
pack(b, sp->wo, e, ff, sp->o);
}
sp = sp->prev;
break;
case '.':
*va_arg(a, uchar**) = p;
break;
}
if(p > e)
return 0;
}
return p - t;
}

143
sys/src/cmd/ip/cifsd/rap.c Normal file
View file

@ -0,0 +1,143 @@
#include <u.h>
#include <libc.h>
#include <auth.h>
#include "dat.h"
#include "fns.h"
static void
padname(uchar *buf, int len, char *name)
{
int n;
n = strlen(name);
if(n >= len)
n = len-1;
memset(buf, 0, len);
memmove(buf, name, n);
}
static int
packshareinfo(Trans *t, int level, char *name, int *pstatus)
{
Share *share;
uchar buf[13];
if((share = mapshare(name)) == nil){
if(pstatus)
*pstatus = 0x906; /* NERR_NetNameNotFound */
return 0;
}
padname(buf, sizeof(buf), share->name);
switch(level){
case 0:
return pack(t->out.data.b, t->out.data.p, t->out.data.e, "[]",
buf, buf+sizeof(buf));
case 1:
return pack(t->out.data.b, t->out.data.p, t->out.data.e, "[]_w@1l{f}",
buf, buf+sizeof(buf), share->stype, smbstrpack8, share->remark);
case 2:
return pack(t->out.data.b, t->out.data.p, t->out.data.e, "[]_w@1l__ww@2l__________{f}{f}",
buf, buf+sizeof(buf), share->stype, 100, 1, smbstrpack8, share->remark,
smbnamepack8, share->root);
default:
return -1;
}
}
void
transrap(Trans *t)
{
char *pd, *dd, *name;
int n, code, status, level, rbs;
uchar *ip, *ipe, *op, *opb, *ope;
uchar buf[16];
code = 0;
name = nil;
pd = dd = nil;
ip = ipe = t->in.param.e;
if(!unpack(t->in.param.b, t->in.param.p, t->in.param.e, "wff[]", &code,
smbstrunpack8, &pd, smbstrunpack8, &dd, &ip, nil)){
t->respond(t, STATUS_NOT_SUPPORTED);
goto out;
}
ope = t->out.param.e;
opb = op = t->out.param.b+2+2;
n = status = level = 0;
switch(code){
case 0x0000: /* NetShareEnum */
op += pack(opb, op, ope, "ww", 0, 0);
if(!unpack(ip, ip, ipe, "ww", &level, &rbs))
break;
if((n = packshareinfo(t, level, "local", nil)) > 0){
t->out.data.p += n;
pack(opb, opb, ope, "ww", 1, 1);
}
break;
case 0x0001: /* NetShareGetInfo */
op += pack(opb, op, ope, "w", 0);
if(!unpack(ip, ip, ipe, "fww", smbstrunpack8, &name, &level, &rbs))
break;
if((n = packshareinfo(t, level, name, &status)) > 0){
outlen:
t->out.data.p += n;
pack(opb, opb, ope, "w", n);
}
break;
case 0x000d: /* NetServerGetInfo */
op += pack(opb, op, ope, "w", 0);
if(!unpack(ip, ip, ipe, "ww", &level, &rbs))
break;
padname(buf, sizeof(buf), "");
switch(level){
case 0:
if((n = pack(t->out.data.b, t->out.data.p, t->out.data.e, "[]",
buf, buf+sizeof(buf))) > 0)
goto outlen;
break;
case 1:
if((n = pack(t->out.data.b, t->out.data.p, t->out.data.e, "[]bbl@1l{f}",
buf, buf+sizeof(buf), 0x05, 0x00, 2, smbstrpack8, osname)) > 0)
goto outlen;
default:
n = -1;
}
break;
case 0x003f: /* NetWrkstaGetInfo */
op += pack(opb, op, ope, "w", 0);
if(!unpack(ip, ip, ipe, "ww", &level, &rbs))
break;
if(level != 10){
n = -1;
break;
}
if((n = pack(t->out.data.b, t->out.data.p, t->out.data.e,
"@0l____@1lbb________{f}{f}", 0x05, 0x00,
smbstrpack8, sysname(), smbstrpack8, domain)) > 0)
goto outlen;
break;
default:
logit("[%.4x] unknown rap command pd=%s dd=%s", code, pd, dd);
}
if(n < 0){
logit("[%.4x] unknown rap level [%.4x]", code, level);
status = 0x7C;
}
if((n = pack(t->out.param.b, t->out.param.p, t->out.param.e, "w__[]", status, opb, op)) == 0){
t->respond(t, STATUS_INVALID_SMB);
goto out;
}
t->out.param.p += n;
t->respond(t, 0);
out:
free(name);
free(pd);
free(dd);
return;
}

View file

@ -0,0 +1,124 @@
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"
static int
run9fs(char *arg)
{
char buf[1024], *argv[3], *s;
Waitmsg *w;
int fd, pid;
switch(pid = rfork(RFCFDG|RFREND|RFPROC)){
case -1:
return -1;
case 0:
open("/dev/null", ORDWR);
snprint(buf, sizeof(buf), "/sys/log/%s", progname);
if((fd = open(buf, OWRITE)) >= 0)
seek(fd, 0, 2);
else
fd = 0;
dup(fd, 1);
dup(fd, 2);
argv[0] = "/bin/9fs";
argv[1] = arg;
argv[2] = 0;
exec(argv[0], argv);
exits("failed to exec 9fs");
}
for (;;) {
if((w = wait()) == nil)
return -1;
if (w->pid == pid)
break;
free(w);
}
if(w->msg[0]){
if(s = strchr(w->msg, ':'))
s = s+1;
else
s = w->msg;
werrstr("%s", s);
free(w);
return -1;
} else {
free(w);
return 0;
}
}
static Share *shares;
Share*
mapshare(char *path)
{
char *tmp, *tmp2, *name, *root, *service, *fsname, *remark;
int stype;
Share *s;
if(name = strrchr(path, '/'))
name++;
else if(name = strrchr(path, '\\'))
name++;
else
name = path;
if(name==nil || *name==0 || *name=='.' || strchrs(name, "\\* ") || strstr(name, ".."))
return nil;
root = tmp = smprint("/n/%s", name);
name = strtr(strrchr(root, '/')+1, tolowerrune);
service = "A:";
stype = STYPE_DISKTREE;
fsname = "9fs";
remark = tmp2 = smprint("9fs %s; cd %s", name, root);
if(!strcmp(name, "local")){
root = "/";
fsname = "local";
remark = "The standard namespace";
}
if(!strcmp(name, "ipc$")){
root = "/dev/null";
name = "IPC$";
fsname = "";
service = "IPC";
stype = STYPE_IPC;
remark = "The IPC service";
}
for(s = shares; s; s=s->next)
if(!strcmp(s->name, name))
goto out;
logit("mapshare %s -> %s %s %s", path, service, name, root);
if(!strcmp(service, "A:") && (stype == STYPE_DISKTREE)){
if(!strcmp(fsname, "9fs") && (run9fs(name) < 0)){
logit("9fs %s: %r", name);
goto out;
}
}
s = malloc(sizeof(*s));
s->service = strdup(service);
s->stype = stype;
s->name = strdup(name);
s->root = strdup(root);
s->remark = strdup(remark);
s->fsname = strdup(fsname);
s->namelen = 255;
s->sectorsize = 0x200;
s->blocksize = 0x2000;
s->allocsize = 0;
s->freesize = s->blocksize;
s->next = shares;
shares = s;
out:
free(tmp);
free(tmp2);
return s;
}

1691
sys/src/cmd/ip/cifsd/smb.c Normal file

File diff suppressed because it is too large Load diff

233
sys/src/cmd/ip/cifsd/tree.c Normal file
View file

@ -0,0 +1,233 @@
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"
static void*
getid(void **a, int n, int i)
{
void *p;
if(i <= 0 || i > n || (p = a[i-1]) == nil)
return nil;
return p;
}
static void
setid(void **a, int n, int i, void *p)
{
assert(i > 0 || i <= n);
a[i-1] = p;
}
static int
newid(void ***pa, int *pn, void *p)
{
int i;
for(i=0; i < *pn; i++)
if((*pa)[i] == nil)
break;
if(i == *pn){
(*pn)++;
if((i % 8) == 0)
*pa = realloc(*pa, (i + 8) * sizeof(p));
}
(*pa)[i] = p;
return i+1;
}
static void **tree;
static int ntree;
static void
freetree(Tree *t)
{
int i;
if(t == nil)
return;
for(i = 0; i < t->nfile; i++)
putfile(t->file[i]);
for(i = 0; i < t->nfind; i++)
putfile(t->find[i]);
free(t->file);
free(t->find);
free(t);
}
Tree*
connecttree(char *service, char *path, int *perr)
{
Share *s;
Tree *t;
int err;
t = nil;
if((s = mapshare(path)) == nil){
err = STATUS_BAD_NETWORK_NAME;
goto out;
}
if(strcmp(service, "?????") && cistrcmp(service, s->service)){
err = STATUS_BAD_DEVICE_TYPE;
goto out;
}
t = mallocz(sizeof(*t), 1);
t->share = s;
t->tid = newid(&tree, &ntree, t);
err = 0;
out:
if(perr)
*perr = err;
return t;
}
int
disconnecttree(int tid)
{
Tree *t;
if((t = gettree(tid)) == nil)
return STATUS_SMB_BAD_TID;
setid(tree, ntree, tid, nil);
freetree(t);
return 0;
}
void
logoff(void)
{
int i;
for(i=0; i<ntree; i++)
freetree(tree[i]);
free(tree);
tree = nil;
ntree = 0;
}
Tree*
gettree(int tid)
{
Tree *t;
if(t = getid(tree, ntree, tid))
if(debug)
fprint(2, "tree [%.4x] %s\n", tid, t->share->root);
return t;
}
int
newfid(Tree *t, File *f)
{
f->ref++;
return newid(&t->file, &t->nfile, f);
}
void
delfid(Tree *t, int fid)
{
File *f;
if(f = getid(t->file, t->nfile, fid)){
setid(t->file, t->nfile, fid, nil);
putfile(f);
}
}
File*
getfile(int tid, int fid, Tree **ptree, int *perr)
{
Tree *t;
File *f;
int err;
f = nil;
if((t = gettree(tid)) == nil){
err = STATUS_SMB_BAD_TID;
goto out;
}
if((f = getid(t->file, t->nfile, fid)) == nil){
err = STATUS_SMB_BAD_FID;
goto out;
}
f->ref++;
err = 0;
if(debug)
fprint(2, "file [%x] %s\n", fid, f->path);
out:
if(perr)
*perr = err;
if(ptree)
*ptree = t;
return f;
}
char*
getpath(int tid, char *name, Tree **ptree, int *perr)
{
Tree *t;
char *p;
int err;
if(t = gettree(tid)){
err = 0;
p = conspath(t->share->root, name);
if(debug)
fprint(2, "path %s\n", p);
} else {
err = STATUS_SMB_BAD_TID;
p = nil;
}
if(perr)
*perr = err;
if(ptree)
*ptree = t;
return p;
}
int
newsid(Tree *t, Find *f)
{
f->ref++;
return newid(&t->find, &t->nfind, f);
}
void
delsid(Tree *t, int sid)
{
Find *f;
if(f = getid(t->find, t->nfind, sid)){
setid(t->find, t->nfind, sid, nil);
putfind(f);
}
}
Find*
getfind(int tid, int sid, Tree **ptree, int *perr)
{
Tree *t;
Find *f;
int err;
f = nil;
if((t = gettree(tid)) == nil){
err = STATUS_SMB_BAD_TID;
goto out;
}
if((f = getid(t->find, t->nfind, sid)) == nil){
err = STATUS_SMB_BAD_FID;
goto out;
}
f->ref++;
err = 0;
if(debug)
fprint(2, "find [%x] %s %s\n", sid, f->base, f->pattern);
out:
if(perr)
*perr = err;
if(ptree)
*ptree = t;
return f;
}

409
sys/src/cmd/ip/cifsd/util.c Normal file
View file

@ -0,0 +1,409 @@
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"
void
logit(char *fmt, ...)
{
char buf[8192];
va_list arg;
va_start(arg, fmt);
vseprint(buf, buf + sizeof(buf), fmt, arg);
va_end(arg);
if(debug)
fprint(2, "%s\n", buf);
syslog(0, progname, "(%s\\%s) %s", remotesys, remoteuser, buf);
}
char*
getremote(char *dir)
{
int fd, n;
char remfile[256];
static char buf[256];
sprint(remfile, "%s/remote", dir);
fd = open(remfile, OREAD);
if(fd < 0)
return nil;
if((n = read(fd, buf, sizeof(buf)-1))>0)
buf[n-1] = 0;
else
strcpy(buf, remfile);
close(fd);
return buf;
}
char*
conspath(char *base, char *name)
{
return cleanname(smprint("%s/%s", base, name ? name : ""));
}
int
splitpath(char *path, char **base, char **name)
{
char *p, *b;
b = strdup(path);
if((p = strrchr(b, '/')) == nil){
free(b);
if(name)
*name = nil;
if(base)
*base = nil;
return 0;
}
if(p == b){
if(name) *name = strdup(p+1);
p[1] = 0;
} else {
*p++ = 0;
if(name) *name = strdup(p);
}
if(base)
*base = b;
else
free(b);
return 1;
}
void
dumphex(char *s, uchar *h, uchar *e)
{
int i, n;
n = e - h;
for(i=0; i<n; i++){
if((i % 16) == 0)
fprint(2, "%s%s: [%.4x] ", i ? "\n" : "", s, i);
fprint(2, "%.2x ", (int)h[i]);
}
fprint(2, "\n");
}
void
todatetime(long time, int *pdate, int *ptime)
{
Tm *tm;
tm = gmtime(time);
if(pdate)
*pdate = (tm->mday) | ((tm->mon + 1) << 5) | ((tm->year - 80) << 9);
if(ptime)
*ptime = (tm->sec >> 1) | (tm->min << 5) | (tm->hour << 11);
}
long
fromdatetime(int date, int time)
{
Tm tm;
strcpy(tm.zone, "GMT");
tm.mday = date & 0x1f;
tm.mon = ((date >> 5) & 0xf) - 1;
tm.year = (date >> 9) + 80;
tm.yday = 0;
tm.sec = (time & 0x1f) << 1;
tm.min = (time >> 5) & 0x3f;
tm.hour = time >> 11;
return tm2sec(&tm);
}
vlong
tofiletime(long time)
{
return ((vlong)time + 11644473600LL) * 10000000;
}
long
fromfiletime(vlong filetime)
{
return filetime / 10000000 - 11644473600LL;
}
int
filesize32(vlong size)
{
if(size > 0xFFFFFFFFUL)
return 0xFFFFFFFF;
return size;
}
vlong
allocsize(vlong size, int blocksize)
{
return ((size + blocksize-1)/blocksize)*blocksize;
}
int
extfileattr(Dir *d)
{
int a;
a = (d->qid.type == QTDIR) ? ATTR_DIRECTORY : ATTR_NORMAL;
if((d->mode & 0222) == 0)
a |= ATTR_READONLY;
if(d->name[0] == '.' && d->name[1] && d->name[1] != '.')
a |= ATTR_HIDDEN;
return a;
}
int
dosfileattr(Dir *d)
{
return extfileattr(d) & DOSMASK;
}
ulong
namehash(char *s)
{
ulong h, t;
Rune r;
h = 0;
while(*s){
s += chartorune(&r, s);
r = toupperrune(r);
t = h & 0xf8000000;
h <<= 5;
h ^= t>>27;
h ^= (ulong)r;
}
return h;
}
char*
strtr(char *s, Rune (*tr)(Rune))
{
char buf[UTFmax], *p, *w;
Rune r;
int n;
p = s;
w = s;
while(*p){
p += chartorune(&r, p);
r = (*tr)(r);
n = runetochar(buf, &r);
if(w + n <= p){
memmove(w, buf, n);
w += n;
}
}
*w = 0;
return s;
}
char*
strchrs(char *s, char *c)
{
Rune r;
int n;
while(*s){
n = chartorune(&r, s);
if(strchr(c, r))
return s;
s += n;
}
return nil;
}
static int
strpack8(uchar *, uchar *p, uchar *e, char *s, int term, Rune (*tr)(Rune))
{
uchar *t;
Rune r;
t = p;
while((p < e) && *s){
s += chartorune(&r, s);
r = tr(r);
*p++ = r & 0x7F;
}
if(p >= e)
return 0;
if(term)
*p++ = 0;
return p - t;
}
static int
strpack16(uchar *b, uchar *p, uchar *e, char *s, int term, Rune (*tr)(Rune))
{
unsigned int rr;
uchar *t;
Rune r;
t = p;
if((p - b) % 2){
if(p >= e)
return 0;
*p++ = 0;
}
while((p+1 < e) && *s){
s += chartorune(&r, s);
rr = tr(r);
if(rr > 0xFFFF){
if(p+3 >= e)
break;
rr -= 0x10000;
*p++ = (rr>>10) & 0xFF;
*p++ = ((rr>>18)&3) + 0xD8;
*p++ = rr & 0xFF;
*p++ = ((rr>>8)&3) + 0xDC;
} else {
*p++ = rr & 0xFF;
*p++ = rr>>8;
}
}
if(p+1 >= e)
return 0;
if(term){
*p++ = 0;
*p++ = 0;
}
return p - t;
}
static int
strunpack8(uchar *, uchar *p, uchar *e, char **dp, int term, Rune (*tr)(Rune))
{
uchar *t;
char *d;
Rune r;
int n;
t = p;
n = 0;
while((p < e) && (!term || *p)){
p++;
n++;
}
if(term && ((p >= e) || *p))
return 0;
p -= n;
*dp = d = malloc(n*UTFmax+1);
while(n--){
r = *p & 0x7F;
r = tr(r);
d += runetochar(d, &r);
p++;
}
*d = 0;
if(term)
p++;
return p - t;
}
static int
strunpack16(uchar *b, uchar *p, uchar *e, char **dp, int term, Rune (*tr)(Rune))
{
unsigned int rr;
uchar *t;
char *d;
Rune r;
int n;
t = p;
if((p - b) % 2)
p++;
n = 0;
while((p+1 < e) && (!term || (p[0] || p[1]))){
p += 2;
n++;
}
if(term && ((p+1 >= e) || p[0] || p[1]))
return 0;
p -= 2*n;
*dp = d = malloc(n*UTFmax+1);
while(n--){
if(p[1] >= 0xD8 && p[1] <= 0xDB){
if(!n--)
break;
rr = ((p[0]<<10) | ((p[1]-0xD8)<<18) | p[2] | ((p[3]-0xDC)<<8))+0x10000;
p += 2;
} else
rr = p[0] | (p[1]<<8);
r = tr(rr);
d += runetochar(d, &r);
p += 2;
}
*d = 0;
if(term)
p += 2;
return p - t;
}
static Rune
notr(Rune r)
{
return r;
}
static Rune
fromnametr(Rune r)
{
switch(r){
case '\\':
return '/';
case ' ':
if(trspaces)
return 0xa0;
}
return r;
}
static Rune
tonametr(Rune r)
{
switch(r){
case '/':
return '\\';
case 0xa0:
if(trspaces)
return ' ';
}
return r;
}
int smbstrpack8(uchar *b, uchar *p, uchar *e, void *arg){
return strpack8(b, p, e, (char*)arg, 1, notr);
}
int smbstrpack16(uchar *b, uchar *p, uchar *e, void *arg){
return strpack16(b, p, e, (char*)arg, 1, notr);
}
int smbstrunpack8(uchar *b, uchar *p, uchar *e, void *arg){
return strunpack8(b, p, e, (char**)arg, 1, notr);
}
int smbstrunpack16(uchar *b, uchar *p, uchar *e, void *arg){
return strunpack16(b, p, e, (char**)arg, 1, notr);
}
int smbnamepack8(uchar *b, uchar *p, uchar *e, void *arg){
return strpack8(b, p, e, (char*)arg, 1, tonametr);
}
int smbnamepack16(uchar *b, uchar *p, uchar *e, void *arg){
return strpack16(b, p, e, (char*)arg, 1, tonametr);
}
int smbnameunpack8(uchar *b, uchar *p, uchar *e, void *arg){
return strunpack8(b, p, e, (char**)arg, 1, fromnametr);
}
int smbnameunpack16(uchar *b, uchar *p, uchar *e, void *arg){
return strunpack16(b, p, e, (char**)arg, 1, fromnametr);
}
int smbuntermstrpack8(uchar *b, uchar *p, uchar *e, void *arg){
return strpack8(b, p, e, (char*)arg, 0, notr);
}
int smbuntermstrpack16(uchar *b, uchar *p, uchar *e, void *arg){
return strpack16(b, p, e, (char*)arg, 0, notr);
}
int smbuntermnamepack8(uchar *b, uchar *p, uchar *e, void *arg){
return strpack8(b, p, e, (char*)arg, 0, tonametr);
}
int smbuntermnamepack16(uchar *b, uchar *p, uchar *e, void *arg){
return strpack16(b, p, e, (char*)arg, 0, tonametr);
}