cifs.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  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("%x != %x 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. int
  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,
  444. int options,
  445. int attrs, int access, int share, int action, int *result, FInfo *fi)
  446. {
  447. Pkt *p;
  448. int fh;
  449. p = cifshdr(s, sp, SMB_COM_NT_CREATE_ANDX);
  450. p8(p, 0xFF); /* Secondary command */
  451. p8(p, 0); /* Reserved */
  452. pl16(p, 0); /* Offset to next command */
  453. p8(p, 0); /* Reserved */
  454. pl16(p, utflen(name) *2); /* file name len */
  455. pl32(p, flags); /* Flags */
  456. pl32(p, 0); /* fid of cwd, if relative path */
  457. pl32(p, access); /* access desired */
  458. pl64(p, 0); /* initial allocation size */
  459. pl32(p, attrs); /* Extended attributes */
  460. pl32(p, share); /* Share Access */
  461. pl32(p, action); /* What to do on success/failure */
  462. pl32(p, options); /* Options */
  463. pl32(p, SECURITY_IMPERSONATION); /* Impersonation level */
  464. p8(p, SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY); /* security flags */
  465. pbytes(p);
  466. p8(p, 0); /* FIXME: padding? */
  467. ppath(p, name); /* filename */
  468. if(cifsrpc(p) == -1){
  469. free(p);
  470. return -1;
  471. }
  472. memset(fi, 0, sizeof(FInfo));
  473. g8(p); /* Secondary command */
  474. g8(p); /* Reserved */
  475. gl16(p); /* Offset to next command */
  476. g8(p); /* oplock granted */
  477. fh = gl16(p); /* FID for opened object */
  478. *result = gl32(p); /* create action taken */
  479. gl64(p); /* creation time */
  480. fi->accessed = gvtime(p); /* last access time */
  481. fi->written = gvtime(p); /* last written time */
  482. fi->changed = gvtime(p); /* change time */
  483. fi->attribs = gl32(p); /* extended attributes */
  484. gl64(p); /* bytes allocated */
  485. fi->size = gl64(p); /* file size */
  486. free(p);
  487. return fh;
  488. }
  489. /* for Win95/98/ME */
  490. int
  491. CIFS_SMB_opencreate(Session *s, Share *sp, char *name, int access,
  492. int attrs, int action, int *result)
  493. {
  494. Pkt *p;
  495. int fh;
  496. p = cifshdr(s, sp, SMB_COM_OPEN_ANDX);
  497. p8(p, 0xFF); /* Secondary command */
  498. p8(p, 0); /* Reserved */
  499. pl16(p, 0); /* Offset to next command */
  500. pl16(p, 0); /* Flags (0 == no stat(2) info) */
  501. pl16(p, access); /* desired access */
  502. pl16(p, ATTR_HIDDEN|ATTR_SYSTEM);/* search attributes */
  503. pl16(p, attrs); /* file attribytes */
  504. pdatetime(p, 0); /* creation time (0 == now) */
  505. pl16(p, action); /* What to do on success/failure */
  506. pl32(p, 0); /* allocation size */
  507. pl32(p, 0); /* reserved */
  508. pl32(p, 0); /* reserved */
  509. pbytes(p);
  510. ppath(p, name); /* filename */
  511. if(cifsrpc(p) == -1){
  512. free(p);
  513. return -1;
  514. }
  515. g8(p); /* Secondary command */
  516. g8(p); /* Reserved */
  517. gl16(p); /* Offset to next command */
  518. fh = gl16(p); /* FID for opened object */
  519. gl16(p); /* extended attributes */
  520. gvtime(p); /* last written time */
  521. gl32(p); /* file size */
  522. gl16(p); /* file type (disk/fifo/printer etc) */
  523. gl16(p); /* device status (for fifos) */
  524. *result = gl16(p); /* access granted */
  525. free(p);
  526. return fh;
  527. }
  528. int64_t
  529. CIFSwrite(Session *s, Share *sp, int fh, uint64_t off, void *buf, int64_t n)
  530. {
  531. Pkt *p;
  532. int64_t got;
  533. /* FIXME: Payload should be padded to long boundary */
  534. assert((n & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES);
  535. assert((off & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES);
  536. assert(n < s->mtu - T2HDRLEN || s->caps & CAP_LARGE_WRITEX);
  537. p = cifshdr(s, sp, SMB_COM_WRITE_ANDX);
  538. p8(p, 0xFF); /* Secondary command */
  539. p8(p, 0); /* Reserved */
  540. pl16(p, 0); /* Offset to next command */
  541. pl16(p, fh); /* File handle */
  542. pl32(p, off & 0xffffffff); /* LSBs of Offset */
  543. pl32(p, 0); /* Reserved (0) */
  544. pl16(p, s->nocache); /* Write mode (0 - write through) */
  545. pl16(p, 0); /* Bytes remaining */
  546. pl16(p, n >> 16); /* MSBs of length */
  547. pl16(p, n & 0xffffffff); /* LSBs of length */
  548. pl16(p, T2HDRLEN); /* Offset to data, in bytes */
  549. pl32(p, off >> 32); /* MSBs of offset */
  550. pbytes(p);
  551. p->pos = p->buf +T2HDRLEN +NBHDRLEN;
  552. pmem(p, buf, n); /* Data */
  553. if(cifsrpc(p) == -1){
  554. free(p);
  555. return -1;
  556. }
  557. g8(p); /* Secondary command */
  558. g8(p); /* Reserved */
  559. gl16(p); /* Offset to next command */
  560. got = gl16(p); /* LSWs of bytes written */
  561. gl16(p); /* remaining (space ?) */
  562. got |= (gl16(p) << 16); /* MSWs of bytes written */
  563. free(p);
  564. return got;
  565. }
  566. int64_t
  567. CIFSread(Session *s, Share *sp, int fh, uint64_t off, void *buf, int64_t n,
  568. int64_t minlen)
  569. {
  570. int doff;
  571. int64_t got;
  572. Pkt *p;
  573. assert((n & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES);
  574. assert((off & 0xffffffff00000000LL) == 0 || s->caps & CAP_LARGE_FILES);
  575. assert(n < s->mtu - T2HDRLEN || s->caps & CAP_LARGE_READX);
  576. p = cifshdr(s, sp, SMB_COM_READ_ANDX);
  577. p8(p, 0xFF); /* Secondary command */
  578. p8(p, 0); /* Reserved */
  579. pl16(p, 0); /* Offset to next command */
  580. pl16(p, fh); /* File handle */
  581. pl32(p, off & 0xffffffff); /* Offset to beginning of write */
  582. pl16(p, n); /* Maximum number of bytes to return */
  583. pl16(p, minlen); /* Minimum number of bytes to return */
  584. pl32(p, (uint)n >> 16); /* MSBs of maxlen */
  585. pl16(p, 0); /* Bytes remaining to satisfy request */
  586. pl32(p, off >> 32); /* MS 32 bits of offset */
  587. pbytes(p);
  588. if(cifsrpc(p) == -1){
  589. free(p);
  590. return -1;
  591. }
  592. g8(p); /* Secondary command */
  593. g8(p); /* Reserved */
  594. gl16(p); /* Offset to next command */
  595. gl16(p); /* Remaining */
  596. gl16(p); /* Compression mode */
  597. gl16(p); /* Reserved */
  598. got = gl16(p); /* length */
  599. doff = gl16(p); /* Offset from header to data */
  600. got |= gl16(p) << 16;
  601. p->pos = p->buf + doff + NBHDRLEN;
  602. gmem(p, buf, got); /* data */
  603. free(p);
  604. return got;
  605. }
  606. int
  607. CIFSflush(Session *s, Share *sp, int fh)
  608. {
  609. int rc;
  610. Pkt *p;
  611. p = cifshdr(s, sp, SMB_COM_FLUSH);
  612. pl16(p, fh); /* fid */
  613. pbytes(p);
  614. rc = cifsrpc(p);
  615. free(p);
  616. return rc;
  617. }
  618. /*
  619. * Setting the time of last write to -1 gives "now" if the file
  620. * was written and leaves it the same if the file wasn't written.
  621. */
  622. int
  623. CIFSclose(Session *s, Share *sp, int fh)
  624. {
  625. int rc;
  626. Pkt *p;
  627. p = cifshdr(s, sp, SMB_COM_CLOSE);
  628. pl16(p, fh); /* fid */
  629. pl32(p, ~0L); /* Time of last write (none) */
  630. pbytes(p);
  631. rc = cifsrpc(p);
  632. free(p);
  633. return rc;
  634. }
  635. int
  636. CIFSfindclose2(Session *s, Share *sp, int sh)
  637. {
  638. int rc;
  639. Pkt *p;
  640. p = cifshdr(s, sp, SMB_COM_FIND_CLOSE2);
  641. pl16(p, sh); /* sid */
  642. pbytes(p);
  643. rc = cifsrpc(p);
  644. free(p);
  645. return rc;
  646. }
  647. int
  648. CIFSecho(Session *s)
  649. {
  650. Pkt *p;
  651. int rc;
  652. p = cifshdr(s, nil, SMB_COM_ECHO);
  653. pl16(p, 1); /* number of replies */
  654. pbytes(p);
  655. pascii(p, "abcdefghijklmnopqrstuvwxyz"); /* data */
  656. rc = cifsrpc(p);
  657. free(p);
  658. return rc;
  659. }
  660. int
  661. CIFSsetinfo(Session *s, Share *sp, char *path, FInfo *fip)
  662. {
  663. int rc;
  664. Pkt *p;
  665. p = cifshdr(s, sp, SMB_COM_SET_INFORMATION);
  666. pl16(p, fip->attribs);
  667. pl32(p, time(nil) - s->tz); /* modified time */
  668. pl64(p, 0); /* reserved */
  669. pl16(p, 0); /* reserved */
  670. pbytes(p);
  671. p8(p, STR_ASCII); /* buffer format */
  672. ppath(p, path);
  673. rc = cifsrpc(p);
  674. free(p);
  675. return rc;
  676. }