cifs.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <fcall.h>
  12. #include <thread.h>
  13. #include <9p.h>
  14. #include "cifs.h"
  15. static char magic[] = { 0xff, 'S', 'M', 'B' };
  16. Session *
  17. cifsdial(char *host, char *called, char *sysname)
  18. {
  19. int nbt, fd;
  20. char *addr;
  21. Session *s;
  22. if(Debug)
  23. fprint(2, "cifsdial: host=%s called=%s sysname=%s\n", host, called, sysname);
  24. if((addr = netmkaddr(host, "tcp", "cifs")) == nil)
  25. return nil;
  26. nbt = 0;
  27. if((fd = dial(addr, nil, nil, nil)) == -1){
  28. nbt = 1;
  29. if((fd = nbtdial(host, called, sysname)) == -1)
  30. return nil;
  31. }
  32. s = emalloc9p(sizeof(Session));
  33. memset(s, 0, sizeof(Session));
  34. s->fd = fd;
  35. s->nbt = nbt;
  36. s->mtu = MTU;
  37. s->pid = getpid();
  38. s->mid = time(nil) ^ getpid();
  39. s->uid = NO_UID;
  40. s->seq = 0;
  41. s->seqrun = 0;
  42. s->secmode = SECMODE_SIGN_ENABLED; /* hope for the best */
  43. s->flags2 = FL2_KNOWS_LONG_NAMES | FL2_HAS_LONG_NAMES | FL2_PAGEING_IO;
  44. s->macidx = -1;
  45. return s;
  46. }
  47. void
  48. cifsclose(Session *s)
  49. {
  50. if(s->fd)
  51. close(s->fd);
  52. free(s);
  53. }
  54. Pkt *
  55. cifshdr(Session *s, Share *sp, int cmd)
  56. {
  57. Pkt *p;
  58. int sign, tid, dfs;
  59. dfs = 0;
  60. tid = NO_TID;
  61. Active = IDLE_TIME;
  62. werrstr("");
  63. sign = s->secmode & SECMODE_SIGN_ENABLED? FL2_PACKET_SIGNATURES: 0;
  64. if(sp){
  65. tid = sp->tid;
  66. // FIXME! if(sp->options & SMB_SHARE_IS_IN_DFS)
  67. // FIXME! dfs = FL2_DFS;
  68. }
  69. p = emalloc9p(sizeof(Pkt) + MTU);
  70. memset(p, 0, sizeof(Pkt) +MTU);
  71. p->buf = (uint8_t *)p + sizeof(Pkt);
  72. p->s = s;
  73. qlock(&s->seqlock);
  74. if(s->seqrun){
  75. p->seq = s->seq;
  76. s->seq = (s->seq + 2) % 0x10000;
  77. }
  78. qunlock(&s->seqlock);
  79. nbthdr(p);
  80. pmem(p, magic, nelem(magic));
  81. p8(p, cmd);
  82. pl32(p, 0); /* status (error) */
  83. p8(p, FL_CASELESS_NAMES | FL_CANNONICAL_NAMES); /* flags */
  84. pl16(p, s->flags2 | dfs | sign); /* flags2 */
  85. pl16(p, (s->pid >> 16) & 0xffff); /* PID MS bits */
  86. pl32(p, p->seq); /* MAC / sequence number */
  87. pl32(p, 0); /* MAC */
  88. pl16(p, 0); /* padding */
  89. pl16(p, tid);
  90. pl16(p, s->pid & 0xffff);
  91. pl16(p, s->uid);
  92. pl16(p, s->mid);
  93. p->wordbase = p8(p, 0); /* filled in by pbytes() */
  94. return p;
  95. }
  96. void
  97. pbytes(Pkt *p)
  98. {
  99. int n;
  100. assert(p->wordbase != nil); /* cifshdr not called */
  101. assert(p->bytebase == nil); /* called twice */
  102. n = p->pos - p->wordbase;
  103. assert(n % 2 != 0); /* even addr */
  104. *p->wordbase = n / 2;
  105. p->bytebase = pl16(p, 0); /* filled in by cifsrpc() */
  106. }
  107. int
  108. cifsrpc(Pkt *p)
  109. {
  110. int flags2, got, err;
  111. uint tid, uid, seq;
  112. uint8_t *pos;
  113. char m[nelem(magic)];
  114. pos = p->pos;
  115. if(p->bytebase){
  116. p->pos = p->bytebase;
  117. pl16(p, pos - (p->bytebase + 2)); /* 2 = sizeof bytecount */
  118. }
  119. p->pos = pos;
  120. if(p->s->secmode & SECMODE_SIGN_ENABLED)
  121. macsign(p, p->seq);
  122. qlock(&p->s->rpclock);
  123. got = nbtrpc(p);
  124. qunlock(&p->s->rpclock);
  125. if(got == -1)
  126. return -1;
  127. gmem(p, m, nelem(magic));
  128. if(memcmp(m, magic, nelem(magic)) != 0){
  129. werrstr("cifsrpc: bad magic number in packet %20ux%02ux%02ux%02ux",
  130. m[0], m[1], m[2], m[3]);
  131. return -1;
  132. }
  133. g8(p); /* cmd */
  134. err = gl32(p); /* errcode */
  135. g8(p); /* flags */
  136. flags2 = gl16(p); /* flags2 */
  137. gl16(p); /* PID MS bits */
  138. seq = gl32(p); /* reserved */
  139. gl32(p); /* MAC (if in use) */
  140. gl16(p); /* Padding */
  141. tid = gl16(p); /* TID */
  142. gl16(p); /* PID lsbs */
  143. uid = gl16(p); /* UID */
  144. gl16(p); /* mid */
  145. g8(p); /* word count */
  146. if(p->s->secmode & SECMODE_SIGN_ENABLED){
  147. if(macsign(p, p->seq+1) != 0 && p->s->seqrun){
  148. werrstr("cifsrpc: invalid packet signature");
  149. print("MAC signature bad\n");
  150. // FIXME: for debug only return -1;
  151. }
  152. }else{
  153. /*
  154. * We allow the sequence number of zero as some old samba
  155. * servers seem to fall back to this unexpectedly
  156. * after reporting sequence numbers correctly for a while.
  157. *
  158. * Some other samba servers seem to always report a sequence
  159. * number of zero if MAC signing is disabled, so we have to
  160. * catch that too.
  161. */
  162. if(p->s->seqrun && seq != p->seq && seq != 0){
  163. print("%ux != %ux bad sequence number\n", seq, p->seq);
  164. return -1;
  165. }
  166. }
  167. p->tid = tid;
  168. if(p->s->uid == NO_UID)
  169. p->s->uid = uid;
  170. if(flags2 & FL2_NT_ERRCODES){
  171. /* is it a real error rather than info/warning/chatter? */
  172. if((err & 0xF0000000) == 0xC0000000){
  173. werrstr("%s", nterrstr(err));
  174. return -1;
  175. }
  176. }else{
  177. if(err){
  178. werrstr("%s", doserrstr(err));
  179. return -1;
  180. }
  181. }
  182. return got;
  183. }
  184. /*
  185. * Some older servers (old samba) prefer to talk older
  186. * dialects but if given no choice they will talk the
  187. * more modern ones, so we don't give them the choice.
  188. */
  189. int
  190. CIFSnegotiate(Session *s, int32_t *svrtime, char *domain, int domlen,
  191. char *cname,
  192. int cnamlen)
  193. {
  194. int d, i;
  195. char *ispeak = "NT LM 0.12";
  196. static char *dialects[] = {
  197. // { "PC NETWORK PROGRAM 1.0"},
  198. // { "MICROSOFT NETWORKS 1.03"},
  199. // { "MICROSOFT NETWORKS 3.0"},
  200. // { "LANMAN1.0"},
  201. // { "LM1.2X002"},
  202. // { "NT LANMAN 1.0"},
  203. { "NT LM 0.12" },
  204. };
  205. Pkt *p;
  206. p = cifshdr(s, nil, SMB_COM_NEGOTIATE);
  207. pbytes(p);
  208. for(i = 0; i < nelem(dialects); i++){
  209. p8(p, STR_DIALECT);
  210. pstr(p, dialects[i]);
  211. }
  212. if(cifsrpc(p) == -1){
  213. free(p);
  214. return -1;
  215. }
  216. d = gl16(p);
  217. if(d < 0 || d > nelem(dialects)){
  218. werrstr("no CIFS dialect in common");
  219. free(p);
  220. return -1;
  221. }
  222. if(strcmp(dialects[d], ispeak) != 0){
  223. werrstr("%s dialect unsupported", dialects[d]);
  224. free(p);
  225. return -1;
  226. }
  227. s->secmode = g8(p); /* Security mode */
  228. gl16(p); /* Max outstanding requests */
  229. gl16(p); /* Max VCs */
  230. s->mtu = gl32(p); /* Max buffer size */
  231. gl32(p); /* Max raw buffer size (depricated) */
  232. gl32(p); /* Session key */
  233. s->caps = gl32(p); /* Server capabilities */
  234. *svrtime = gvtime(p); /* fileserver time */
  235. s->tz = (int16_t)gl16(p) * 60; /* TZ in mins, is signed (SNIA doc is wrong) */
  236. s->challen = g8(p); /* Encryption key length */
  237. gl16(p);
  238. gmem(p, s->chal, s->challen); /* Get the challenge */
  239. gstr(p, domain, domlen); /* source domain */
  240. { /* NetApp Filer seem not to report its called name */
  241. char *cn = emalloc9p(cnamlen);
  242. gstr(p, cn, cnamlen); /* their name */
  243. if(strlen(cn) > 0)
  244. memcpy(cname, cn, cnamlen);
  245. free(cn);
  246. }
  247. if(s->caps & CAP_UNICODE)
  248. s->flags2 |= FL2_UNICODE;
  249. free(p);
  250. return 0;
  251. }
  252. int
  253. CIFSsession(Session *s)
  254. {
  255. char os[64], *q;
  256. Rune r;
  257. Pkt *p;
  258. enum {
  259. mycaps = CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
  260. CAP_NT_FIND | CAP_STATUS32,
  261. };
  262. s->seqrun = 1; /* activate the sequence number generation/checking */
  263. p = cifshdr(s, nil, SMB_COM_SESSION_SETUP_ANDX);
  264. p8(p, 0xFF); /* No secondary command */
  265. p8(p, 0); /* Reserved (must be zero) */
  266. pl16(p, 0); /* Offset to next command */
  267. pl16(p, MTU); /* my max buffer size */
  268. pl16(p, 1); /* my max multiplexed pending requests */
  269. pl16(p, 0); /* Virtual connection # */
  270. pl32(p, 0); /* Session key (if vc != 0) */
  271. if((s->secmode & SECMODE_PW_ENCRYPT) == 0) {
  272. pl16(p, utflen(Sess->auth->resp[0])*2 + 2); /* passwd size */
  273. pl16(p, utflen(Sess->auth->resp[0])*2 + 2); /* passwd size (UPPER CASE) */
  274. pl32(p, 0); /* Reserved */
  275. pl32(p, mycaps);
  276. pbytes(p);
  277. for(q = Sess->auth->resp[0]; *q; ){
  278. q += chartorune(&r, q);
  279. pl16(p, toupperrune(r));
  280. }
  281. pl16(p, 0);
  282. for(q = Sess->auth->resp[0]; *q; ){
  283. q += chartorune(&r, q);
  284. pl16(p, r);
  285. }
  286. pl16(p, 0);
  287. }else{
  288. pl16(p, Sess->auth->len[0]); /* LM passwd size */
  289. pl16(p, Sess->auth->len[1]); /* NTLM passwd size */
  290. pl32(p, 0); /* Reserved */
  291. pl32(p, mycaps);
  292. pbytes(p);
  293. pmem(p, Sess->auth->resp[0], Sess->auth->len[0]);
  294. pmem(p, Sess->auth->resp[1], Sess->auth->len[1]);
  295. }
  296. pstr(p, Sess->auth->user); /* Account name */
  297. pstr(p, Sess->auth->windom); /* Primary domain */
  298. pstr(p, "plan9"); /* Client OS */
  299. pstr(p, argv0); /* Client LAN Manager type */
  300. if(cifsrpc(p) == -1){
  301. free(p);
  302. return -1;
  303. }
  304. g8(p); /* Reserved (0) */
  305. gl16(p); /* Offset to next command wordcount */
  306. Sess->isguest = gl16(p) & 1; /* logged in as guest */
  307. gl16(p);
  308. gl16(p);
  309. /* no security blob here - we don't understand extended security anyway */
  310. gstr(p, os, sizeof(os));
  311. s->remos = estrdup9p(os);
  312. free(p);
  313. return 0;
  314. }
  315. CIFStreeconnect(Session *s, char *cname, char *tree, Share *sp)
  316. {
  317. int len;
  318. char *resp, *path;
  319. char zeros[24];
  320. Pkt *p;
  321. resp = Sess->auth->resp[0];
  322. len = Sess->auth->len[0];
  323. if((s->secmode & SECMODE_USER) != SECMODE_USER){
  324. memset(zeros, 0, sizeof(zeros));
  325. resp = zeros;
  326. len = sizeof(zeros);
  327. }
  328. p = cifshdr(s, nil, SMB_COM_TREE_CONNECT_ANDX);
  329. p8(p, 0xFF); /* Secondary command */
  330. p8(p, 0); /* Reserved */
  331. pl16(p, 0); /* Offset to next Word Count */
  332. pl16(p, 0); /* Flags */
  333. if((s->secmode & SECMODE_PW_ENCRYPT) == 0){
  334. pl16(p, len+1); /* password len, including null */
  335. pbytes(p);
  336. pascii(p, resp);
  337. }else{
  338. pl16(p, len);
  339. pbytes(p);
  340. pmem(p, resp, len);
  341. }
  342. path = smprint("//%s/%s", cname, tree);
  343. strupr(path);
  344. ppath(p, path); /* path */
  345. free(path);
  346. pascii(p, "?????"); /* service type any (so we can do RAP calls) */
  347. if(cifsrpc(p) == -1){
  348. free(p);
  349. return -1;
  350. }
  351. g8(p); /* Secondary command */
  352. g8(p); /* Reserved */
  353. gl16(p); /* Offset to next command */
  354. sp->options = g8(p); /* options supported */
  355. sp->tid = p->tid; /* get received TID from packet header */
  356. free(p);
  357. return 0;
  358. }
  359. int
  360. CIFSlogoff(Session *s)
  361. {
  362. int rc;
  363. Pkt *p;
  364. p = cifshdr(s, nil, SMB_COM_LOGOFF_ANDX);
  365. p8(p, 0xFF); /* No ANDX command */
  366. p8(p, 0); /* Reserved (must be zero) */
  367. pl16(p, 0); /* offset ot ANDX */
  368. pbytes(p);
  369. rc = cifsrpc(p);
  370. free(p);
  371. return rc;
  372. }
  373. int
  374. CIFStreedisconnect(Session *s, Share *sp)
  375. {
  376. int rc;
  377. Pkt *p;
  378. p = cifshdr(s, sp, SMB_COM_TREE_DISCONNECT);
  379. pbytes(p);
  380. rc = cifsrpc(p);
  381. free(p);
  382. return rc;
  383. }
  384. int
  385. CIFSdeletefile(Session *s, Share *sp, char *name)
  386. {
  387. int rc;
  388. Pkt *p;
  389. p = cifshdr(s, sp, SMB_COM_DELETE);
  390. pl16(p, ATTR_HIDDEN|ATTR_SYSTEM); /* search attributes */
  391. pbytes(p);
  392. p8(p, STR_ASCII); /* buffer format */
  393. ppath(p, name);
  394. rc = cifsrpc(p);
  395. free(p);
  396. return rc;
  397. }
  398. int
  399. CIFSdeletedirectory(Session *s, Share *sp, char *name)
  400. {
  401. int rc;
  402. Pkt *p;
  403. p = cifshdr(s, sp, SMB_COM_DELETE_DIRECTORY);
  404. pbytes(p);
  405. p8(p, STR_ASCII); /* buffer format */
  406. ppath(p, name);
  407. rc = cifsrpc(p);
  408. free(p);
  409. return rc;
  410. }
  411. int
  412. CIFScreatedirectory(Session *s, Share *sp, char *name)
  413. {
  414. int rc;
  415. Pkt *p;
  416. p = cifshdr(s, sp, SMB_COM_CREATE_DIRECTORY);
  417. pbytes(p);
  418. p8(p, STR_ASCII);
  419. ppath(p, name);
  420. rc = cifsrpc(p);
  421. free(p);
  422. return rc;
  423. }
  424. int
  425. CIFSrename(Session *s, Share *sp, char *old, char *new)
  426. {
  427. int rc;
  428. Pkt *p;
  429. p = cifshdr(s, sp, SMB_COM_RENAME);
  430. pl16(p, ATTR_HIDDEN|ATTR_SYSTEM|ATTR_DIRECTORY); /* search attributes */
  431. pbytes(p);
  432. p8(p, STR_ASCII);
  433. ppath(p, old);
  434. p8(p, STR_ASCII);
  435. ppath(p, new);
  436. rc = cifsrpc(p);
  437. free(p);
  438. return rc;
  439. }
  440. /* for NT4/Win2k/XP */
  441. int
  442. CIFS_NT_opencreate(Session *s, Share *sp, char *name, int flags,
  443. 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. int64_t
  527. CIFSwrite(Session *s, Share *sp, int fh, uint64_t off, void *buf, int64_t n)
  528. {
  529. Pkt *p;
  530. int64_t 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. int64_t
  565. CIFSread(Session *s, Share *sp, int fh, uint64_t off, void *buf, int64_t n,
  566. int64_t minlen)
  567. {
  568. int doff;
  569. int64_t 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. }