cifs.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <fcall.h>
  4. #include <thread.h>
  5. #include <9p.h>
  6. #include "cifs.h"
  7. static char magic[] = { 0xff, 'S', 'M', 'B' };
  8. Session *
  9. cifsdial(char *host, char *called, char *sysname)
  10. {
  11. int nbt, fd;
  12. char *addr;
  13. Session *s;
  14. if(Debug)
  15. fprint(2, "cifsdial: host=%s called=%s sysname=%s\n", host, called, sysname);
  16. if((addr = netmkaddr(host, "tcp", "cifs")) == nil)
  17. return nil;
  18. nbt = 0;
  19. if((fd = dial(addr, nil, nil, nil)) == -1){
  20. nbt = 1;
  21. if((fd = nbtdial(host, called, sysname)) == -1)
  22. return nil;
  23. }
  24. s = emalloc9p(sizeof(Session));
  25. memset(s, 0, sizeof(Session));
  26. s->fd = fd;
  27. s->nbt = nbt;
  28. s->mtu = MTU;
  29. s->pid = getpid();
  30. s->mid = time(nil) ^ getpid();
  31. s->uid = NO_UID;
  32. s->seq = 0;
  33. s->seqrun = 0;
  34. s->secmode = SECMODE_SIGN_ENABLED; /* hope for the best */
  35. s->flags2 = FL2_KNOWS_LONG_NAMES | FL2_HAS_LONG_NAMES | FL2_PAGEING_IO;
  36. s->macidx = -1;
  37. return s;
  38. }
  39. void
  40. cifsclose(Session *s)
  41. {
  42. if(s->fd)
  43. close(s->fd);
  44. free(s);
  45. }
  46. Pkt *
  47. cifshdr(Session *s, Share *sp, int cmd)
  48. {
  49. Pkt *p;
  50. int sign, tid, dfs;
  51. dfs = 0;
  52. tid = NO_TID;
  53. Active = IDLE_TIME;
  54. sign = s->secmode & SECMODE_SIGN_ENABLED? FL2_PACKET_SIGNATURES: 0;
  55. if(sp){
  56. tid = sp->tid;
  57. // FIXME! if(sp->options & SMB_SHARE_IS_IN_DFS)
  58. // FIXME! dfs = FL2_DFS;
  59. }
  60. p = emalloc9p(sizeof(Pkt) + MTU);
  61. memset(p, 0, sizeof(Pkt) +MTU);
  62. p->buf = (uchar *)p + sizeof(Pkt);
  63. p->s = s;
  64. qlock(&s->seqlock);
  65. if(s->seqrun){
  66. p->seq = s->seq;
  67. s->seq = (s->seq + 2) % 0x10000;
  68. }
  69. qunlock(&s->seqlock);
  70. nbthdr(p);
  71. pmem(p, magic, nelem(magic));
  72. p8(p, cmd);
  73. pl32(p, 0); /* status (error) */
  74. p8(p, FL_CASELESS_NAMES | FL_CANNONICAL_NAMES); /* flags */
  75. pl16(p, s->flags2 | dfs | sign); /* flags2 */
  76. pl16(p, (s->pid >> 16) & 0xffff); /* PID MS bits */
  77. pl32(p, p->seq); /* MAC / sequence number */
  78. pl32(p, 0); /* MAC */
  79. pl16(p, 0); /* padding */
  80. pl16(p, tid);
  81. pl16(p, s->pid & 0xffff);
  82. pl16(p, s->uid);
  83. pl16(p, s->mid);
  84. p->wordbase = p8(p, 0); /* filled in by pbytes() */
  85. return p;
  86. }
  87. void
  88. pbytes(Pkt *p)
  89. {
  90. int n;
  91. assert(p->wordbase != nil); /* cifshdr not called */
  92. assert(p->bytebase == nil); /* called twice */
  93. n = p->pos - p->wordbase;
  94. assert(n % 2 != 0); /* even addr */
  95. *p->wordbase = n / 2;
  96. p->bytebase = pl16(p, 0); /* filled in by cifsrpc() */
  97. }
  98. static void
  99. dmp(int seq, uchar *buf)
  100. {
  101. int i;
  102. if(seq == 99)
  103. print("\n ");
  104. else
  105. print("%+2d ", seq);
  106. for(i = 0; i < 8; i++)
  107. print("%02x ", buf[i] & 0xff);
  108. print("\n");
  109. }
  110. int
  111. cifsrpc(Pkt *p)
  112. {
  113. int flags2, got, err;
  114. uint tid, uid, seq;
  115. uchar *pos;
  116. char m[nelem(magic)];
  117. pos = p->pos;
  118. if(p->bytebase){
  119. p->pos = p->bytebase;
  120. pl16(p, pos - (p->bytebase + 2)); /* 2 = sizeof bytecount */
  121. }
  122. p->pos = pos;
  123. if(p->s->secmode & SECMODE_SIGN_ENABLED)
  124. macsign(p, p->seq);
  125. qlock(&p->s->rpclock);
  126. got = nbtrpc(p);
  127. qunlock(&p->s->rpclock);
  128. if(got == -1)
  129. return -1;
  130. gmem(p, m, nelem(magic));
  131. if(memcmp(m, magic, nelem(magic)) != 0){
  132. werrstr("cifsrpc: bad magic number in packet %20ux%02ux%02ux%02ux",
  133. m[0], m[1], m[2], m[3]);
  134. return -1;
  135. }
  136. g8(p); /* cmd */
  137. err = gl32(p); /* errcode */
  138. g8(p); /* flags */
  139. flags2 = gl16(p); /* flags2 */
  140. gl16(p); /* PID MS bits */
  141. seq = gl32(p); /* reserved */
  142. gl32(p); /* MAC (if in use) */
  143. gl16(p); /* Padding */
  144. tid = gl16(p); /* TID */
  145. gl16(p); /* PID lsbs */
  146. uid = gl16(p); /* UID */
  147. gl16(p); /* mid */
  148. g8(p); /* word count */
  149. if(p->s->secmode & SECMODE_SIGN_ENABLED){
  150. if(macsign(p, p->seq+1) != 0 && p->s->seqrun){
  151. werrstr("cifsrpc: invalid packet signature");
  152. print("MAC signature bad\n");
  153. // FIXME: for debug only return -1;
  154. }
  155. }else{
  156. /*
  157. * We allow the sequence number of zero as some old samba
  158. * servers seem to fall back to this unexpectedly
  159. * after reporting sequence numbers correctly for a while.
  160. *
  161. * Some other samba servers seem to always report a sequence
  162. * number of zero if MAC signing is disabled, so we have to
  163. * catch that too.
  164. */
  165. if(p->s->seqrun && seq != p->seq && seq != 0){
  166. werrstr("%ux != %ux bad sequence number", seq, p->seq);
  167. return -1;
  168. }
  169. }
  170. p->tid = tid;
  171. if(p->s->uid == NO_UID)
  172. p->s->uid = uid;
  173. if(flags2 & FL2_NT_ERRCODES){
  174. /* is it a real error rather than info/warning/chatter */
  175. if((err & 0xF0000000) == 0xC0000000){
  176. werrstr("%s", nterrstr(err));
  177. return -1;
  178. }
  179. }else{
  180. if(err){
  181. werrstr("%s", doserrstr(err));
  182. return -1;
  183. }
  184. }
  185. return got;
  186. }
  187. /*
  188. * Some older servers (old samba) prefer to talk older
  189. * dialects but if given no choice they will talk the
  190. * more modern ones, so we don't give them the choice.
  191. */
  192. int
  193. CIFSnegotiate(Session *s, long *svrtime, char *domain, int domlen, char *cname, int cnamlen)
  194. {
  195. int d, i;
  196. char *ispeak = "NT LM 0.12";
  197. char *dialects[] = {
  198. // { "PC NETWORK PROGRAM 1.0"},
  199. // { "MICROSOFT NETWORKS 1.03"},
  200. // { "MICROSOFT NETWORKS 3.0"},
  201. // { "LANMAN1.0"},
  202. // { "LM1.2X002"},
  203. // { "NT LANMAN 1.0"},
  204. { "NT LM 0.12" },
  205. };
  206. Pkt *p;
  207. p = cifshdr(s, nil, SMB_COM_NEGOTIATE);
  208. pbytes(p);
  209. for(i = 0; i < nelem(dialects); i++){
  210. p8(p, STR_DIALECT);
  211. pstr(p, dialects[i]);
  212. }
  213. if(cifsrpc(p) == -1){
  214. free(p);
  215. return -1;
  216. }
  217. d = gl16(p);
  218. if(d < 0 || d > nelem(dialects)){
  219. werrstr("no CIFS dialect in common");
  220. free(p);
  221. return -1;
  222. }
  223. if(strcmp(dialects[d], ispeak) != 0){
  224. werrstr("%s dialect unsupported", dialects[d]);
  225. free(p);
  226. return -1;
  227. }
  228. s->secmode = g8(p); /* Security mode */
  229. gl16(p); /* Max outstanding requests */
  230. gl16(p); /* Max VCs */
  231. s->mtu = gl32(p); /* Max buffer size */
  232. gl32(p); /* Max raw buffer size (depricated) */
  233. gl32(p); /* Session key */
  234. s->caps = gl32(p); /* Server capabilities */
  235. *svrtime = gvtime(p); /* fileserver time */
  236. s->tz = (short)gl16(p) * 60; /* TZ in mins, is signed (SNIA doc is wrong) */
  237. s->challen = g8(p); /* Encryption key length */
  238. gl16(p);
  239. gmem(p, s->chal, s->challen); /* Get the challenge */
  240. gstr(p, domain, domlen); /* source domain */
  241. { /* NetApp Filer seem not to report its called name */
  242. char *cn = emalloc9p(cnamlen);
  243. gstr(p, cn, cnamlen); /* their name */
  244. if(strlen(cn) > 0)
  245. memcpy(cname, cn, cnamlen);
  246. free(cn);
  247. }
  248. if(s->caps & CAP_UNICODE)
  249. s->flags2 |= FL2_UNICODE;
  250. free(p);
  251. return 0;
  252. }
  253. int
  254. CIFSsession(Session *s)
  255. {
  256. char os[64], *q;
  257. Rune r;
  258. Pkt *p;
  259. enum {
  260. mycaps = CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
  261. CAP_NT_FIND | CAP_STATUS32,
  262. };
  263. s->seqrun = 1; /* activate the sequence number generation/checking */
  264. p = cifshdr(s, nil, SMB_COM_SESSION_SETUP_ANDX);
  265. p8(p, 0xFF); /* No secondary command */
  266. p8(p, 0); /* Reserved (must be zero) */
  267. pl16(p, 0); /* Offset to next command */
  268. pl16(p, MTU); /* my max buffer size */
  269. pl16(p, 1); /* my max multiplexed pending requests */
  270. pl16(p, 0); /* Virtual connection # */
  271. pl32(p, 0); /* Session key (if vc != 0) */
  272. if((s->secmode & SECMODE_PW_ENCRYPT) == 0) {
  273. pl16(p, utflen(Sess->auth->resp[0])*2 + 2); /* passwd size */
  274. pl16(p, utflen(Sess->auth->resp[0])*2 + 2); /* passwd size (UPPER CASE) */
  275. pl32(p, 0); /* Reserved */
  276. pl32(p, mycaps);
  277. pbytes(p);
  278. for(q = Sess->auth->resp[0]; *q; ){
  279. q += chartorune(&r, q);
  280. pl16(p, toupperrune(r));
  281. }
  282. pl16(p, 0);
  283. for(q = Sess->auth->resp[0]; *q; ){
  284. q += chartorune(&r, q);
  285. pl16(p, r);
  286. }
  287. pl16(p, 0);
  288. }else{
  289. pl16(p, Sess->auth->len[0]); /* LM passwd size */
  290. pl16(p, Sess->auth->len[1]); /* NTLM passwd size */
  291. pl32(p, 0); /* Reserved */
  292. pl32(p, mycaps);
  293. pbytes(p);
  294. pmem(p, Sess->auth->resp[0], Sess->auth->len[0]);
  295. pmem(p, Sess->auth->resp[1], Sess->auth->len[1]);
  296. }
  297. pstr(p, Sess->auth->user); /* Account name */
  298. pstr(p, Sess->auth->windom); /* Primary domain */
  299. pstr(p, "plan9"); /* Client OS */
  300. pstr(p, argv0); /* Client LAN Manager type */
  301. if(cifsrpc(p) == -1){
  302. free(p);
  303. return -1;
  304. }
  305. g8(p); /* Reserved (0) */
  306. gl16(p); /* Offset to next command wordcount */
  307. Sess->isguest = gl16(p) & 1; /* logged in as guest */
  308. gl16(p);
  309. gl16(p);
  310. /* no security blob here - we don't understand extended security anyway */
  311. gstr(p, os, sizeof(os));
  312. s->remos = estrdup9p(os);
  313. free(p);
  314. return 0;
  315. }
  316. CIFStreeconnect(Session *s, char *cname, char *tree, Share *sp)
  317. {
  318. int len;
  319. char *resp, *path;
  320. char zeros[24];
  321. Pkt *p;
  322. resp = Sess->auth->resp[0];
  323. len = Sess->auth->len[0];
  324. if((s->secmode & SECMODE_USER) != SECMODE_USER){
  325. memset(zeros, 0, sizeof(zeros));
  326. resp = zeros;
  327. len = sizeof(zeros);
  328. }
  329. p = cifshdr(s, nil, SMB_COM_TREE_CONNECT_ANDX);
  330. p8(p, 0xFF); /* Secondary command */
  331. p8(p, 0); /* Reserved */
  332. pl16(p, 0); /* Offset to next Word Count */
  333. pl16(p, 0); /* Flags */
  334. if((s->secmode & SECMODE_PW_ENCRYPT) == 0){
  335. pl16(p, len+1); /* password len, including null */
  336. pbytes(p);
  337. pascii(p, resp);
  338. }else{
  339. pl16(p, len);
  340. pbytes(p);
  341. pmem(p, resp, len);
  342. }
  343. path = smprint("//%s/%s", cname, tree);
  344. strupr(path);
  345. ppath(p, path); /* path */
  346. free(path);
  347. pascii(p, "?????"); /* service type any (so we can do RAP calls) */
  348. if(cifsrpc(p) == -1){
  349. free(p);
  350. return -1;
  351. }
  352. g8(p); /* Secondary command */
  353. g8(p); /* Reserved */
  354. gl16(p); /* Offset to next command */
  355. sp->options = g8(p); /* options supported */
  356. sp->tid = p->tid; /* get received TID from packet header */
  357. free(p);
  358. return 0;
  359. }
  360. int
  361. CIFSlogoff(Session *s)
  362. {
  363. int rc;
  364. Pkt *p;
  365. p = cifshdr(s, nil, SMB_COM_LOGOFF_ANDX);
  366. p8(p, 0xFF); /* No ANDX command */
  367. p8(p, 0); /* Reserved (must be zero) */
  368. pl16(p, 0); /* offset ot ANDX */
  369. pbytes(p);
  370. rc = cifsrpc(p);
  371. free(p);
  372. return rc;
  373. }
  374. int
  375. CIFStreedisconnect(Session *s, Share *sp)
  376. {
  377. int rc;
  378. Pkt *p;
  379. p = cifshdr(s, sp, SMB_COM_TREE_DISCONNECT);
  380. pbytes(p);
  381. rc = cifsrpc(p);
  382. free(p);
  383. return rc;
  384. }
  385. int
  386. CIFSdeletefile(Session *s, Share *sp, char *name)
  387. {
  388. int rc;
  389. Pkt *p;
  390. p = cifshdr(s, sp, SMB_COM_DELETE);
  391. pl16(p, ATTR_HIDDEN|ATTR_SYSTEM); /* search attributes */
  392. pbytes(p);
  393. p8(p, STR_ASCII); /* buffer format */
  394. ppath(p, name);
  395. rc = cifsrpc(p);
  396. free(p);
  397. return rc;
  398. }
  399. int
  400. CIFSdeletedirectory(Session *s, Share *sp, char *name)
  401. {
  402. int rc;
  403. Pkt *p;
  404. p = cifshdr(s, sp, SMB_COM_DELETE_DIRECTORY);
  405. pbytes(p);
  406. p8(p, STR_ASCII); /* buffer format */
  407. ppath(p, name);
  408. rc = cifsrpc(p);
  409. free(p);
  410. return rc;
  411. }
  412. int
  413. CIFScreatedirectory(Session *s, Share *sp, char *name)
  414. {
  415. int rc;
  416. Pkt *p;
  417. p = cifshdr(s, sp, SMB_COM_CREATE_DIRECTORY);
  418. pbytes(p);
  419. p8(p, STR_ASCII);
  420. ppath(p, name);
  421. rc = cifsrpc(p);
  422. free(p);
  423. return rc;
  424. }
  425. int
  426. CIFSrename(Session *s, Share *sp, char *old, char *new)
  427. {
  428. int rc;
  429. Pkt *p;
  430. p = cifshdr(s, sp, SMB_COM_RENAME);
  431. pl16(p, ATTR_HIDDEN|ATTR_SYSTEM|ATTR_DIRECTORY); /* search attributes */
  432. pbytes(p);
  433. p8(p, STR_ASCII);
  434. ppath(p, old);
  435. p8(p, STR_ASCII);
  436. ppath(p, new);
  437. rc = cifsrpc(p);
  438. free(p);
  439. return rc;
  440. }
  441. /* for NT4/Win2k/XP */
  442. int
  443. CIFS_NT_opencreate(Session *s, Share *sp, char *name, int flags, int options,
  444. int attrs, int access, int share, int action, int *result, FInfo *fi)
  445. {
  446. Pkt *p;
  447. int fh;
  448. p = cifshdr(s, sp, SMB_COM_NT_CREATE_ANDX);
  449. p8(p, 0xFF); /* Secondary command */
  450. p8(p, 0); /* Reserved */
  451. pl16(p, 0); /* Offset to next command */
  452. p8(p, 0); /* Reserved */
  453. pl16(p, utflen(name) *2); /* file name len */
  454. pl32(p, flags); /* Flags */
  455. pl32(p, 0); /* fid of cwd, if relative path */
  456. pl32(p, access); /* access desired */
  457. pl64(p, 0); /* initial allocation size */
  458. pl32(p, attrs); /* Extended attributes */
  459. pl32(p, share); /* Share Access */
  460. pl32(p, action); /* What to do on success/failure */
  461. pl32(p, options); /* Options */
  462. pl32(p, SECURITY_IMPERSONATION); /* Impersonation level */
  463. p8(p, SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY); /* security flags */
  464. pbytes(p);
  465. p8(p, 0); /* FIXME: padding? */
  466. ppath(p, name); /* filename */
  467. if(cifsrpc(p) == -1){
  468. free(p);
  469. return -1;
  470. }
  471. memset(fi, 0, sizeof(FInfo));
  472. g8(p); /* Secondary command */
  473. g8(p); /* Reserved */
  474. gl16(p); /* Offset to next command */
  475. g8(p); /* oplock granted */
  476. fh = gl16(p); /* FID for opened object */
  477. *result = gl32(p); /* create action taken */
  478. gl64(p); /* creation time */
  479. fi->accessed = gvtime(p); /* last access time */
  480. fi->written = gvtime(p); /* last written time */
  481. fi->changed = gvtime(p); /* change time */
  482. fi->attribs = gl32(p); /* extended attributes */
  483. gl64(p); /* bytes allocated */
  484. fi->size = gl64(p); /* file size */
  485. free(p);
  486. return fh;
  487. }
  488. /* for Win95/98/ME */
  489. CIFS_SMB_opencreate(Session *s, Share *sp, char *name, int access,
  490. int attrs, int action, int *result)
  491. {
  492. Pkt *p;
  493. int fh;
  494. p = cifshdr(s, sp, SMB_COM_OPEN_ANDX);
  495. p8(p, 0xFF); /* Secondary command */
  496. p8(p, 0); /* Reserved */
  497. pl16(p, 0); /* Offset to next command */
  498. pl16(p, 0); /* Flags (0 == no stat(2) info) */
  499. pl16(p, access); /* desired access */
  500. pl16(p, ATTR_HIDDEN|ATTR_SYSTEM);/* search attributes */
  501. pl16(p, attrs); /* file attribytes */
  502. pdatetime(p, 0); /* creation time (0 == now) */
  503. pl16(p, action); /* What to do on success/failure */
  504. pl32(p, 0); /* allocation size */
  505. pl32(p, 0); /* reserved */
  506. pl32(p, 0); /* reserved */
  507. pbytes(p);
  508. ppath(p, name); /* filename */
  509. if(cifsrpc(p) == -1){
  510. free(p);
  511. return -1;
  512. }
  513. g8(p); /* Secondary command */
  514. g8(p); /* Reserved */
  515. gl16(p); /* Offset to next command */
  516. fh = gl16(p); /* FID for opened object */
  517. gl16(p); /* extended attributes */
  518. gvtime(p); /* last written time */
  519. gl32(p); /* file size */
  520. gl16(p); /* file type (disk/fifo/printer etc) */
  521. gl16(p); /* device status (for fifos) */
  522. *result = gl16(p); /* access granted */
  523. free(p);
  524. return fh;
  525. }
  526. vlong
  527. CIFSwrite(Session *s, Share *sp, int fh, uvlong off, void *buf, vlong n)
  528. {
  529. Pkt *p;
  530. vlong got;
  531. /* FIXME: Payload should be padded to long boundary */
  532. assert((n & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES);
  533. assert((off & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES);
  534. assert(n < s->mtu - T2HDRLEN || s->caps & CAP_LARGE_WRITEX);
  535. p = cifshdr(s, sp, SMB_COM_WRITE_ANDX);
  536. p8(p, 0xFF); /* Secondary command */
  537. p8(p, 0); /* Reserved */
  538. pl16(p, 0); /* Offset to next command */
  539. pl16(p, fh); /* File handle */
  540. pl32(p, off & 0xffffffff); /* LSBs of Offset */
  541. pl32(p, 0); /* Reserved (0) */
  542. pl16(p, s->nocache); /* Write mode (0 - write through) */
  543. pl16(p, 0); /* Bytes remaining */
  544. pl16(p, n >> 16); /* MSBs of length */
  545. pl16(p, n & 0xffffffff); /* LSBs of length */
  546. pl16(p, T2HDRLEN); /* Offset to data, in bytes */
  547. pl32(p, off >> 32); /* MSBs of offset */
  548. pbytes(p);
  549. p->pos = p->buf +T2HDRLEN +NBHDRLEN;
  550. pmem(p, buf, n); /* Data */
  551. if(cifsrpc(p) == -1){
  552. free(p);
  553. return -1;
  554. }
  555. g8(p); /* Secondary command */
  556. g8(p); /* Reserved */
  557. gl16(p); /* Offset to next command */
  558. got = gl16(p); /* LSWs of bytes written */
  559. gl16(p); /* remaining (space ?) */
  560. got |= (gl16(p) << 16); /* MSWs of bytes written */
  561. free(p);
  562. return got;
  563. }
  564. vlong
  565. CIFSread(Session *s, Share *sp, int fh, uvlong off, void *buf, vlong n,
  566. vlong minlen)
  567. {
  568. int doff;
  569. vlong got;
  570. Pkt *p;
  571. assert((n & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES);
  572. assert((off & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES);
  573. assert(n < s->mtu - T2HDRLEN || s->caps & CAP_LARGE_READX);
  574. p = cifshdr(s, sp, SMB_COM_READ_ANDX);
  575. p8(p, 0xFF); /* Secondary command */
  576. p8(p, 0); /* Reserved */
  577. pl16(p, 0); /* Offset to next command */
  578. pl16(p, fh); /* File handle */
  579. pl32(p, off & 0xffffffff); /* Offset to beginning of write */
  580. pl16(p, n); /* Maximum number of bytes to return */
  581. pl16(p, minlen); /* Minimum number of bytes to return */
  582. pl32(p, (uint)n >> 16); /* MSBs of maxlen */
  583. pl16(p, 0); /* Bytes remaining to satisfy request */
  584. pl32(p, off >> 32); /* MS 32 bits of offset */
  585. pbytes(p);
  586. if(cifsrpc(p) == -1){
  587. free(p);
  588. return -1;
  589. }
  590. g8(p); /* Secondary command */
  591. g8(p); /* Reserved */
  592. gl16(p); /* Offset to next command */
  593. gl16(p); /* Remaining */
  594. gl16(p); /* Compression mode */
  595. gl16(p); /* Reserved */
  596. got = gl16(p); /* length */
  597. doff = gl16(p); /* Offset from header to data */
  598. got |= gl16(p) << 16;
  599. p->pos = p->buf + doff + NBHDRLEN;
  600. gmem(p, buf, got); /* data */
  601. free(p);
  602. return got;
  603. }
  604. int
  605. CIFSflush(Session *s, Share *sp, int fh)
  606. {
  607. int rc;
  608. Pkt *p;
  609. p = cifshdr(s, sp, SMB_COM_FLUSH);
  610. pl16(p, fh); /* fid */
  611. pbytes(p);
  612. rc = cifsrpc(p);
  613. free(p);
  614. return rc;
  615. }
  616. /*
  617. * Setting the time of last write to -1 gives "now" if the file
  618. * was written and leaves it the same if the file wasn't written.
  619. */
  620. int
  621. CIFSclose(Session *s, Share *sp, int fh)
  622. {
  623. int rc;
  624. Pkt *p;
  625. p = cifshdr(s, sp, SMB_COM_CLOSE);
  626. pl16(p, fh); /* fid */
  627. pl32(p, ~0L); /* Time of last write (none) */
  628. pbytes(p);
  629. rc = cifsrpc(p);
  630. free(p);
  631. return rc;
  632. }
  633. int
  634. CIFSfindclose2(Session *s, Share *sp, int sh)
  635. {
  636. int rc;
  637. Pkt *p;
  638. p = cifshdr(s, sp, SMB_COM_FIND_CLOSE2);
  639. pl16(p, sh); /* sid */
  640. pbytes(p);
  641. rc = cifsrpc(p);
  642. free(p);
  643. return rc;
  644. }
  645. int
  646. CIFSecho(Session *s)
  647. {
  648. Pkt *p;
  649. int rc;
  650. p = cifshdr(s, nil, SMB_COM_ECHO);
  651. pl16(p, 1); /* number of replies */
  652. pbytes(p);
  653. pascii(p, "abcdefghijklmnopqrstuvwxyz"); /* data */
  654. rc = cifsrpc(p);
  655. free(p);
  656. return rc;
  657. }
  658. int
  659. CIFSsetinfo(Session *s, Share *sp, char *path, FInfo *fip)
  660. {
  661. int rc;
  662. Pkt *p;
  663. p = cifshdr(s, sp, SMB_COM_SET_INFORMATION);
  664. pl16(p, fip->attribs);
  665. pl32(p, time(nil) - s->tz); /* modified time */
  666. pl64(p, 0); /* reserved */
  667. pl16(p, 0); /* reserved */
  668. pbytes(p);
  669. p8(p, STR_ASCII); /* buffer format */
  670. ppath(p, path);
  671. rc = cifsrpc(p);
  672. free(p);
  673. return rc;
  674. }