123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include <u.h>
- #include <libc.h>
- #include <fcall.h>
- #include <thread.h>
- #include <9p.h>
- #include "cifs.h"
- static Pkt *
- t2hdr(Session *s, Share *sp, int cmd)
- {
- Pkt *p;
- p = cifshdr(s, sp, SMB_COM_TRANSACTION2);
- p->tbase = pl16(p, 0); /* 0 Total parameter bytes to be sent, filled later */
- pl16(p, 0); /* 2 Total data bytes to be sent, filled later */
- pl16(p, 64); /* 4 Max parameter to return */
- pl16(p, (MTU - T2HDRLEN)-64); /* 6 Max data to return */
- p8(p, 0); /* 8 Max setup count to return */
- p8(p, 0); /* 9 Reserved */
- pl16(p, 0); /* 10 Flags */
- pl32(p, 1000); /* 12 Timeout (ms) */
- pl16(p, 0); /* 16 Reserved */
- pl16(p, 0); /* 18 Parameter count, filled later */
- pl16(p, 0); /* 20 Parameter offset, filled later */
- pl16(p, 0); /* 22 Data count, filled later */
- pl16(p, 0); /* 24 Data offset, filled later */
- p8(p, 1); /* 26 Setup count (in words) */
- p8(p, 0); /* 27 Reserved */
- pl16(p, cmd); /* setup[0] */
- pbytes(p);
- p8(p, 0); /* padding ??!?!? */
- return p;
- }
- static void
- pt2param(Pkt *p)
- {
- uint8_t *pos = p->pos;
- assert(p->tbase != 0);
- p->pos = p->tbase + 20;
- pl16(p, (pos - p->buf) - NBHDRLEN); /* param offset */
- p->tparam = p->pos = pos;
- }
- static void
- pt2data(Pkt *p)
- {
- uint8_t *pos = p->pos;
- assert(p->tbase != 0);
- assert(p->tparam != 0);
- p->pos = p->tbase +0;
- pl16(p, pos - p->tparam); /* total param count */
- p->pos = p->tbase +18;
- pl16(p, pos - p->tparam); /* param count */
- p->pos = p->tbase +24;
- pl16(p, (pos - p->buf) - NBHDRLEN); /* data offset */
- p->tdata = p->pos = pos;
- }
- static int
- t2rpc(Pkt *p)
- {
- int got;
- uint8_t *pos;
- assert(p->tbase != 0);
- assert(p->tdata != 0);
- pos = p->pos;
- p->pos = p->tbase +2;
- pl16(p, pos - p->tdata); /* total data count */
- p->pos = p->tbase +22;
- pl16(p, pos - p->tdata); /* data count */
- p->pos = pos;
- if((got = cifsrpc(p)) == -1)
- return -1;
- gl16(p); /* Total parameter count */
- gl16(p); /* Total data count */
- gl16(p); /* Reserved */
- gl16(p); /* Parameter count in this buffer */
- p->tparam = p->buf +NBHDRLEN +gl16(p); /* Parameter offset */
- gl16(p); /* Parameter displacement */
- gl16(p); /* Data count (this buffer); */
- p->tdata = p->buf +NBHDRLEN +gl16(p); /* Data offset */
- gl16(p); /* Data displacement */
- g8(p); /* Setup count */
- g8(p); /* Reserved */
- return got;
- }
- static void
- gt2param(Pkt *p)
- {
- p->pos = p->tparam;
- }
- static void
- gt2data(Pkt *p)
- {
- p->pos = p->tdata;
- }
- int
- T2findfirst(Session *s, Share *sp, int slots, char *path, int *got,
- int32_t *resume, FInfo *fip)
- {
- int pktlen, i, n, sh;
- uint8_t *next;
- Pkt *p;
- p = t2hdr(s, sp, TRANS2_FIND_FIRST2);
- p8(p, 'D'); /* OS/2 */
- p8(p, ' '); /* OS/2 */
- pt2param(p);
- pl16(p, ATTR_HIDDEN|ATTR_SYSTEM|ATTR_DIRECTORY); /* Search attributes */
- pl16(p, slots); /* Search count */
- pl16(p, CIFS_SEARCH_RETURN_RESUME); /* Flags */
- pl16(p, SMB_FIND_FILE_FULL_DIRECTORY_INFO); /* Information level */
- pl32(p, 0); /* SearchStorage type (?) */
- ppath(p, path); /* path */
- pt2data(p);
- if((pktlen = t2rpc(p)) == -1){
- free(p);
- return -1;
- }
- s->lastfind = nsec();
- gt2param(p);
- sh = gl16(p); /* Sid (search handle) */
- *got = gl16(p); /* number of slots received */
- gl16(p); /* End of search flag */
- gl16(p); /* Offset into EA list if EA error */
- gl16(p); /* Offset into data to file name of last entry */
- gt2data(p);
- memset(fip, 0, slots * sizeof(FInfo));
- for(i = 0; i < *got; i++){
- next = p->pos;
- next += gl32(p); /* offset to next entry */
- /*
- * bug in Windows - somtimes it lies about how many
- * directory entries it has put in the packet
- */
- if(next - p->buf > pktlen){
- *got = i;
- break;
- }
- *resume = gl32(p); /* resume key for search */
- fip[i].created = gvtime(p); /* creation time */
- fip[i].accessed = gvtime(p); /* last access time */
- fip[i].written = gvtime(p); /* last written time */
- fip[i].changed = gvtime(p); /* change time */
- fip[i].size = gl64(p); /* file size */
- gl64(p); /* bytes allocated */
- fip[i].attribs = gl32(p); /* extended attributes */
- n = gl32(p); /* name length */
- gl32(p); /* EA size */
- gstr(p, fip[i].name, n); /* name */
- p->pos = next;
- }
- free(p);
- return sh;
- }
- int
- T2findnext(Session *s, Share *sp, int slots, char *path, int *got,
- int32_t *resume, FInfo *fip, int sh)
- {
- Pkt *p;
- int i, n;
- uint8_t *next;
- /*
- * So I believe from comp.protocols.smb if you send
- * TRANS2_FIND_NEXT2 requests too quickly to windows 95, it can
- * get confused and fail to reply, so we slow up a bit in these
- * circumstances.
- */
- if(!(s->caps & CAP_NT_SMBS) && nsec() - s->lastfind < 200000000LL)
- sleep(200);
- p = t2hdr(s, sp, TRANS2_FIND_NEXT2);
- p8(p, 'D'); /* OS/2 */
- p8(p, ' '); /* OS/2 */
- pt2param(p);
- pl16(p, sh); /* search handle */
- pl16(p, slots); /* Search count */
- pl16(p, SMB_FIND_FILE_FULL_DIRECTORY_INFO); /* Information level */
- pl32(p, *resume); /* resume key */
- pl16(p, CIFS_SEARCH_CONTINUE_FROM_LAST); /* Flags */
- ppath(p, path); /* file+path to resume */
- pt2data(p);
- if(t2rpc(p) == -1){
- free(p);
- return -1;
- }
- s->lastfind = nsec();
- gt2param(p);
- *got = gl16(p); /* number of slots received */
- gl16(p); /* End of search flag */
- gl16(p); /* Offset into EA list if EA error */
- gl16(p); /* Offset into data to file name of last entry */
- gt2data(p);
- memset(fip, 0, slots * sizeof(FInfo));
- for(i = 0; i < *got; i++){
- next = p->pos;
- next += gl32(p); /* offset to next entry */
- *resume = gl32(p); /* resume key for search */
- fip[i].created = gvtime(p); /* creation time */
- fip[i].accessed = gvtime(p); /* last access time */
- fip[i].written = gvtime(p); /* last written time */
- fip[i].changed = gvtime(p); /* change time */
- fip[i].size = gl64(p); /* file size */
- gl64(p); /* bytes allocated */
- fip[i].attribs = gl32(p); /* extended attributes */
- n = gl32(p); /* name length */
- gl32(p); /* EA size */
- gstr(p, fip[i].name, n); /* name */
- p->pos = next;
- }
- free(p);
- return 0;
- }
- /* supported by 2k/XP/NT4 */
- int
- T2queryall(Session *s, Share *sp, char *path, FInfo *fip)
- {
- int n;
- Pkt *p;
- p = t2hdr(s, sp, TRANS2_QUERY_PATH_INFORMATION);
- pt2param(p);
- pl16(p, SMB_QUERY_FILE_ALL_INFO); /* Information level */
- pl32(p, 0); /* reserved */
- ppath(p, path); /* path */
- pt2data(p);
- if(t2rpc(p) == -1){
- free(p);
- return -1;
- }
- gt2data(p);
- /*
- * The layout of this struct is wrong in the SINA
- * document, this layout gained by inspection.
- */
- memset(fip, 0, sizeof(FInfo));
- fip->created = gvtime(p); /* creation time */
- fip->accessed = gvtime(p); /* last access time */
- fip->written = gvtime(p); /* last written time */
- fip->changed = gvtime(p); /* change time */
- fip->attribs = gl32(p); /* attributes */
- gl32(p); /* reserved */
- gl64(p); /* bytes allocated */
- fip->size = gl64(p); /* file size */
- gl32(p); /* number of hard links */
- g8(p); /* delete pending */
- g8(p); /* is a directory */
- gl16(p); /* reserved */
- gl32(p); /* EA size */
- n = gl32(p);
- if(n >= sizeof fip->name)
- n = sizeof fip->name - 1;
- gstr(p, fip->name, n);
- free(p);
- return 0;
- }
- /* supported by 95/98/ME */
- int
- T2querystandard(Session *s, Share *sp, char *path, FInfo *fip)
- {
- Pkt *p;
- p = t2hdr(s, sp, TRANS2_QUERY_PATH_INFORMATION);
- pt2param(p);
- pl16(p, SMB_INFO_STANDARD); /* Information level */
- pl32(p, 0); /* reserved */
- ppath(p, path); /* path */
- pt2data(p);
- if(t2rpc(p) == -1){
- free(p);
- return -1;
- }
- gt2data(p);
- memset(fip, 0, sizeof(FInfo));
- fip->created = gdatetime(p); /* creation time */
- fip->accessed = gdatetime(p); /* last access time */
- fip->written = gdatetime(p); /* last written time */
- fip->changed = fip->written; /* change time */
- fip->size = gl32(p); /* file size */
- gl32(p); /* bytes allocated */
- fip->attribs = gl16(p); /* attributes */
- gl32(p); /* EA size */
- free(p);
- return 0;
- }
- int
- T2setpathinfo(Session *s, Share *sp, char *path, FInfo *fip)
- {
- int rc;
- Pkt *p;
- p = t2hdr(s, sp, TRANS2_SET_PATH_INFORMATION);
- pt2param(p);
- pl16(p, SMB_INFO_STANDARD); /* Information level */
- pl32(p, 0); /* reserved */
- ppath(p, path); /* path */
- pt2data(p);
- pdatetime(p, fip->created); /* created */
- pdatetime(p, fip->accessed); /* accessed */
- pdatetime(p, fip->written); /* written */
- pl32(p, fip->size); /* size */
- pl32(p, 0); /* allocated */
- pl16(p, fip->attribs); /* attributes */
- pl32(p, 0); /* EA size */
- pl16(p, 0); /* reserved */
- rc = t2rpc(p);
- free(p);
- return rc;
- }
- int
- T2setfilelength(Session *s, Share *sp, int fh, FInfo *fip) /* FIXME: maybe broken, needs testing */
- {
- int rc;
- Pkt *p;
- p = t2hdr(s, sp, TRANS2_SET_FILE_INFORMATION);
- pt2param(p);
- pl16(p, fh); /* file handle */
- pl16(p, SMB_SET_FILE_END_OF_FILE_INFO); /* Information level */
- pl16(p, 0); /* reserved */
- pt2data(p);
- pl64(p, fip->size);
- pl32(p, 0); /* padding ?! */
- pl16(p, 0);
- rc = t2rpc(p);
- free(p);
- return rc;
- }
- int
- T2fsvolumeinfo(Session *s, Share *sp, int32_t *created, int32_t *serialno,
- char *label, int labellen)
- {
- Pkt *p;
- int32_t ct, sn, n;
- p = t2hdr(s, sp, TRANS2_QUERY_FS_INFORMATION);
- pt2param(p);
- pl16(p, SMB_QUERY_FS_VOLUME_INFO); /* Information level */
- pt2data(p);
- if(t2rpc(p) == -1){
- free(p);
- return -1;
- }
- gt2data(p);
- ct = gvtime(p); /* creation time */
- sn = gl32(p); /* serial number */
- n = gl32(p); /* label name length */
- g8(p); /* reserved */
- g8(p); /* reserved */
- memset(label, 0, labellen);
- if(n < labellen && n > 0)
- gstr(p, label, n); /* file system label */
- if(created)
- *created = ct;
- if(serialno)
- *serialno = sn;
- free(p);
- return 0;
- }
- int
- T2fssizeinfo(Session *s, Share *sp, uint64_t *total, uint64_t *unused)
- {
- Pkt *p;
- uint64_t t, f, n, b;
- p = t2hdr(s, sp, TRANS2_QUERY_FS_INFORMATION);
- pt2param(p);
- pl16(p, SMB_QUERY_FS_SIZE_INFO); /* Information level */
- pt2data(p);
- if(t2rpc(p) == -1){
- free(p);
- return -1;
- }
- gt2data(p);
- t = gl64(p); /* total blocks */
- f = gl64(p); /* free blocks */
- n = gl32(p); /* sectors per block */
- b = gl32(p); /* bytes per sector */
- /* I just can't figure out why this is here.
- * free is always true and I don't know how
- * to deal with this. Marked f as used for
- * compiler warning.
- if(free)
- *unused = f * n * b;
- */
- USED(f);
- if(total)
- *total = t * n * b;
- free(p);
- return 0;
- }
- int
- T2getdfsreferral(Session *s, Share *sp, char *path, int *gflags,
- int *used,
- Refer *re, int nent)
- {
- int i, vers, nret, len;
- char tmp[1024];
- uint8_t *base;
- Pkt *p;
- p = t2hdr(s, sp, TRANS2_GET_DFS_REFERRAL);
- pt2param(p);
- pl16(p, 3); /* max info level we understand, must be >= 3 for domain requests */
- ppath(p, path);
- pt2data(p);
- if(t2rpc(p) == -1){
- free(p);
- return -1;
- }
- memset(re, 0, sizeof *re * nent);
- gt2data(p);
- *used = gl16(p) / 2; /* length used (/2 as Windows counts in runes) */
- nret = gl16(p); /* number of referrals returned */
- *gflags = gl32(p); /* global flags */
- for(i = 0; i < nret && i < nent && i < 16; i++){
- base = p->pos;
- vers = gl16(p); /* version of records */
- len = gl16(p); /* length of records */
- re[i].type = gl16(p); /* server type */
- re[i].flags = gl16(p); /* referal flags */
- switch(vers){
- case 1:
- re[i].prox = 0; /* nearby */
- re[i].ttl = 5*60; /* 5 mins */
- gstr(p, tmp, sizeof tmp);
- re[i].addr = estrdup9p(tmp);
- re[i].path = estrdup9p(tmp);
- break;
- case 2:
- re[i].prox = gl32(p); /* not implemented in v2 */
- re[i].ttl = gl32(p);
- goff(p, base, re[i].path, sizeof tmp);
- re[i].path = estrdup9p(tmp);
- goff(p, base, re[i].path, sizeof tmp);/* spurious 8.3 path */
- goff(p, base, tmp, sizeof tmp);
- re[i].addr = estrdup9p(tmp);
- break;
- case 3:
- if(re[i].flags & DFS_REFERAL_LIST){
- re[i].prox = 0;
- re[i].ttl = gl32(p);
- goff(p, base, tmp, sizeof tmp);
- re[i].path = estrdup9p(tmp);
- gl16(p);
- goff(p, base, tmp, sizeof tmp);
- re[i].addr = estrdup9p(tmp);
- }
- else{
- re[i].prox = 0;
- re[i].ttl = gl32(p);
- goff(p, base, tmp, sizeof tmp);
- re[i].path = estrdup9p(tmp);
- gl16(p); /* spurious 8.3 path */
- goff(p, base, tmp, sizeof tmp);
- re[i].addr = estrdup9p(tmp);
- gl16(p); /* GUID (historic) */
- }
- break;
- default:
- /*
- * this should never happen as we specify our maximum
- * understood level in the request (above)
- */
- fprint(2, "%d - unsupported DFS infolevel\n", vers);
- re[i].path = estrdup9p(tmp);
- re[i].addr = estrdup9p(tmp);
- break;
- }
- p->pos = base+len;
- }
- free(p);
- return i;
- }
|