trans2.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  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 Pkt *
  16. t2hdr(Session *s, Share *sp, int cmd)
  17. {
  18. Pkt *p;
  19. p = cifshdr(s, sp, SMB_COM_TRANSACTION2);
  20. p->tbase = pl16(p, 0); /* 0 Total parameter bytes to be sent, filled later */
  21. pl16(p, 0); /* 2 Total data bytes to be sent, filled later */
  22. pl16(p, 64); /* 4 Max parameter to return */
  23. pl16(p, (MTU - T2HDRLEN)-64); /* 6 Max data to return */
  24. p8(p, 0); /* 8 Max setup count to return */
  25. p8(p, 0); /* 9 Reserved */
  26. pl16(p, 0); /* 10 Flags */
  27. pl32(p, 1000); /* 12 Timeout (ms) */
  28. pl16(p, 0); /* 16 Reserved */
  29. pl16(p, 0); /* 18 Parameter count, filled later */
  30. pl16(p, 0); /* 20 Parameter offset, filled later */
  31. pl16(p, 0); /* 22 Data count, filled later */
  32. pl16(p, 0); /* 24 Data offset, filled later */
  33. p8(p, 1); /* 26 Setup count (in words) */
  34. p8(p, 0); /* 27 Reserved */
  35. pl16(p, cmd); /* setup[0] */
  36. pbytes(p);
  37. p8(p, 0); /* padding ??!?!? */
  38. return p;
  39. }
  40. static void
  41. pt2param(Pkt *p)
  42. {
  43. uint8_t *pos = p->pos;
  44. assert(p->tbase != 0);
  45. p->pos = p->tbase + 20;
  46. pl16(p, (pos - p->buf) - NBHDRLEN); /* param offset */
  47. p->tparam = p->pos = pos;
  48. }
  49. static void
  50. pt2data(Pkt *p)
  51. {
  52. uint8_t *pos = p->pos;
  53. assert(p->tbase != 0);
  54. assert(p->tparam != 0);
  55. p->pos = p->tbase +0;
  56. pl16(p, pos - p->tparam); /* total param count */
  57. p->pos = p->tbase +18;
  58. pl16(p, pos - p->tparam); /* param count */
  59. p->pos = p->tbase +24;
  60. pl16(p, (pos - p->buf) - NBHDRLEN); /* data offset */
  61. p->tdata = p->pos = pos;
  62. }
  63. static int
  64. t2rpc(Pkt *p)
  65. {
  66. int got;
  67. uint8_t *pos;
  68. assert(p->tbase != 0);
  69. assert(p->tdata != 0);
  70. pos = p->pos;
  71. p->pos = p->tbase +2;
  72. pl16(p, pos - p->tdata); /* total data count */
  73. p->pos = p->tbase +22;
  74. pl16(p, pos - p->tdata); /* data count */
  75. p->pos = pos;
  76. if((got = cifsrpc(p)) == -1)
  77. return -1;
  78. gl16(p); /* Total parameter count */
  79. gl16(p); /* Total data count */
  80. gl16(p); /* Reserved */
  81. gl16(p); /* Parameter count in this buffer */
  82. p->tparam = p->buf +NBHDRLEN +gl16(p); /* Parameter offset */
  83. gl16(p); /* Parameter displacement */
  84. gl16(p); /* Data count (this buffer); */
  85. p->tdata = p->buf +NBHDRLEN +gl16(p); /* Data offset */
  86. gl16(p); /* Data displacement */
  87. g8(p); /* Setup count */
  88. g8(p); /* Reserved */
  89. return got;
  90. }
  91. static void
  92. gt2param(Pkt *p)
  93. {
  94. p->pos = p->tparam;
  95. }
  96. static void
  97. gt2data(Pkt *p)
  98. {
  99. p->pos = p->tdata;
  100. }
  101. int
  102. T2findfirst(Session *s, Share *sp, int slots, char *path, int *got,
  103. int32_t *resume, FInfo *fip)
  104. {
  105. int pktlen, i, n, sh;
  106. uint8_t *next;
  107. Pkt *p;
  108. p = t2hdr(s, sp, TRANS2_FIND_FIRST2);
  109. p8(p, 'D'); /* OS/2 */
  110. p8(p, ' '); /* OS/2 */
  111. pt2param(p);
  112. pl16(p, ATTR_HIDDEN|ATTR_SYSTEM|ATTR_DIRECTORY); /* Search attributes */
  113. pl16(p, slots); /* Search count */
  114. pl16(p, CIFS_SEARCH_RETURN_RESUME); /* Flags */
  115. pl16(p, SMB_FIND_FILE_FULL_DIRECTORY_INFO); /* Information level */
  116. pl32(p, 0); /* SearchStorage type (?) */
  117. ppath(p, path); /* path */
  118. pt2data(p);
  119. if((pktlen = t2rpc(p)) == -1){
  120. free(p);
  121. return -1;
  122. }
  123. s->lastfind = nsec();
  124. gt2param(p);
  125. sh = gl16(p); /* Sid (search handle) */
  126. *got = gl16(p); /* number of slots received */
  127. gl16(p); /* End of search flag */
  128. gl16(p); /* Offset into EA list if EA error */
  129. gl16(p); /* Offset into data to file name of last entry */
  130. gt2data(p);
  131. memset(fip, 0, slots * sizeof(FInfo));
  132. for(i = 0; i < *got; i++){
  133. next = p->pos;
  134. next += gl32(p); /* offset to next entry */
  135. /*
  136. * bug in Windows - somtimes it lies about how many
  137. * directory entries it has put in the packet
  138. */
  139. if(next - p->buf > pktlen){
  140. *got = i;
  141. break;
  142. }
  143. *resume = gl32(p); /* resume key for search */
  144. fip[i].created = gvtime(p); /* creation time */
  145. fip[i].accessed = gvtime(p); /* last access time */
  146. fip[i].written = gvtime(p); /* last written time */
  147. fip[i].changed = gvtime(p); /* change time */
  148. fip[i].size = gl64(p); /* file size */
  149. gl64(p); /* bytes allocated */
  150. fip[i].attribs = gl32(p); /* extended attributes */
  151. n = gl32(p); /* name length */
  152. gl32(p); /* EA size */
  153. gstr(p, fip[i].name, n); /* name */
  154. p->pos = next;
  155. }
  156. free(p);
  157. return sh;
  158. }
  159. int
  160. T2findnext(Session *s, Share *sp, int slots, char *path, int *got,
  161. int32_t *resume, FInfo *fip, int sh)
  162. {
  163. Pkt *p;
  164. int i, n;
  165. uint8_t *next;
  166. /*
  167. * So I believe from comp.protocols.smb if you send
  168. * TRANS2_FIND_NEXT2 requests too quickly to windows 95, it can
  169. * get confused and fail to reply, so we slow up a bit in these
  170. * circumstances.
  171. */
  172. if(!(s->caps & CAP_NT_SMBS) && nsec() - s->lastfind < 200000000LL)
  173. sleep(200);
  174. p = t2hdr(s, sp, TRANS2_FIND_NEXT2);
  175. p8(p, 'D'); /* OS/2 */
  176. p8(p, ' '); /* OS/2 */
  177. pt2param(p);
  178. pl16(p, sh); /* search handle */
  179. pl16(p, slots); /* Search count */
  180. pl16(p, SMB_FIND_FILE_FULL_DIRECTORY_INFO); /* Information level */
  181. pl32(p, *resume); /* resume key */
  182. pl16(p, CIFS_SEARCH_CONTINUE_FROM_LAST); /* Flags */
  183. ppath(p, path); /* file+path to resume */
  184. pt2data(p);
  185. if(t2rpc(p) == -1){
  186. free(p);
  187. return -1;
  188. }
  189. s->lastfind = nsec();
  190. gt2param(p);
  191. *got = gl16(p); /* number of slots received */
  192. gl16(p); /* End of search flag */
  193. gl16(p); /* Offset into EA list if EA error */
  194. gl16(p); /* Offset into data to file name of last entry */
  195. gt2data(p);
  196. memset(fip, 0, slots * sizeof(FInfo));
  197. for(i = 0; i < *got; i++){
  198. next = p->pos;
  199. next += gl32(p); /* offset to next entry */
  200. *resume = gl32(p); /* resume key for search */
  201. fip[i].created = gvtime(p); /* creation time */
  202. fip[i].accessed = gvtime(p); /* last access time */
  203. fip[i].written = gvtime(p); /* last written time */
  204. fip[i].changed = gvtime(p); /* change time */
  205. fip[i].size = gl64(p); /* file size */
  206. gl64(p); /* bytes allocated */
  207. fip[i].attribs = gl32(p); /* extended attributes */
  208. n = gl32(p); /* name length */
  209. gl32(p); /* EA size */
  210. gstr(p, fip[i].name, n); /* name */
  211. p->pos = next;
  212. }
  213. free(p);
  214. return 0;
  215. }
  216. /* supported by 2k/XP/NT4 */
  217. int
  218. T2queryall(Session *s, Share *sp, char *path, FInfo *fip)
  219. {
  220. int n;
  221. Pkt *p;
  222. p = t2hdr(s, sp, TRANS2_QUERY_PATH_INFORMATION);
  223. pt2param(p);
  224. pl16(p, SMB_QUERY_FILE_ALL_INFO); /* Information level */
  225. pl32(p, 0); /* reserved */
  226. ppath(p, path); /* path */
  227. pt2data(p);
  228. if(t2rpc(p) == -1){
  229. free(p);
  230. return -1;
  231. }
  232. gt2data(p);
  233. /*
  234. * The layout of this struct is wrong in the SINA
  235. * document, this layout gained by inspection.
  236. */
  237. memset(fip, 0, sizeof(FInfo));
  238. fip->created = gvtime(p); /* creation time */
  239. fip->accessed = gvtime(p); /* last access time */
  240. fip->written = gvtime(p); /* last written time */
  241. fip->changed = gvtime(p); /* change time */
  242. fip->attribs = gl32(p); /* attributes */
  243. gl32(p); /* reserved */
  244. gl64(p); /* bytes allocated */
  245. fip->size = gl64(p); /* file size */
  246. gl32(p); /* number of hard links */
  247. g8(p); /* delete pending */
  248. g8(p); /* is a directory */
  249. gl16(p); /* reserved */
  250. gl32(p); /* EA size */
  251. n = gl32(p);
  252. if(n >= sizeof fip->name)
  253. n = sizeof fip->name - 1;
  254. gstr(p, fip->name, n);
  255. free(p);
  256. return 0;
  257. }
  258. /* supported by 95/98/ME */
  259. int
  260. T2querystandard(Session *s, Share *sp, char *path, FInfo *fip)
  261. {
  262. Pkt *p;
  263. p = t2hdr(s, sp, TRANS2_QUERY_PATH_INFORMATION);
  264. pt2param(p);
  265. pl16(p, SMB_INFO_STANDARD); /* Information level */
  266. pl32(p, 0); /* reserved */
  267. ppath(p, path); /* path */
  268. pt2data(p);
  269. if(t2rpc(p) == -1){
  270. free(p);
  271. return -1;
  272. }
  273. gt2data(p);
  274. memset(fip, 0, sizeof(FInfo));
  275. fip->created = gdatetime(p); /* creation time */
  276. fip->accessed = gdatetime(p); /* last access time */
  277. fip->written = gdatetime(p); /* last written time */
  278. fip->changed = fip->written; /* change time */
  279. fip->size = gl32(p); /* file size */
  280. gl32(p); /* bytes allocated */
  281. fip->attribs = gl16(p); /* attributes */
  282. gl32(p); /* EA size */
  283. free(p);
  284. return 0;
  285. }
  286. int
  287. T2setpathinfo(Session *s, Share *sp, char *path, FInfo *fip)
  288. {
  289. int rc;
  290. Pkt *p;
  291. p = t2hdr(s, sp, TRANS2_SET_PATH_INFORMATION);
  292. pt2param(p);
  293. pl16(p, SMB_INFO_STANDARD); /* Information level */
  294. pl32(p, 0); /* reserved */
  295. ppath(p, path); /* path */
  296. pt2data(p);
  297. pdatetime(p, fip->created); /* created */
  298. pdatetime(p, fip->accessed); /* accessed */
  299. pdatetime(p, fip->written); /* written */
  300. pl32(p, fip->size); /* size */
  301. pl32(p, 0); /* allocated */
  302. pl16(p, fip->attribs); /* attributes */
  303. pl32(p, 0); /* EA size */
  304. pl16(p, 0); /* reserved */
  305. rc = t2rpc(p);
  306. free(p);
  307. return rc;
  308. }
  309. int
  310. T2setfilelength(Session *s, Share *sp, int fh, FInfo *fip) /* FIXME: maybe broken, needs testing */
  311. {
  312. int rc;
  313. Pkt *p;
  314. p = t2hdr(s, sp, TRANS2_SET_FILE_INFORMATION);
  315. pt2param(p);
  316. pl16(p, fh); /* file handle */
  317. pl16(p, SMB_SET_FILE_END_OF_FILE_INFO); /* Information level */
  318. pl16(p, 0); /* reserved */
  319. pt2data(p);
  320. pl64(p, fip->size);
  321. pl32(p, 0); /* padding ?! */
  322. pl16(p, 0);
  323. rc = t2rpc(p);
  324. free(p);
  325. return rc;
  326. }
  327. int
  328. T2fsvolumeinfo(Session *s, Share *sp, int32_t *created, int32_t *serialno,
  329. char *label, int labellen)
  330. {
  331. Pkt *p;
  332. int32_t ct, sn, n;
  333. p = t2hdr(s, sp, TRANS2_QUERY_FS_INFORMATION);
  334. pt2param(p);
  335. pl16(p, SMB_QUERY_FS_VOLUME_INFO); /* Information level */
  336. pt2data(p);
  337. if(t2rpc(p) == -1){
  338. free(p);
  339. return -1;
  340. }
  341. gt2data(p);
  342. ct = gvtime(p); /* creation time */
  343. sn = gl32(p); /* serial number */
  344. n = gl32(p); /* label name length */
  345. g8(p); /* reserved */
  346. g8(p); /* reserved */
  347. memset(label, 0, labellen);
  348. if(n < labellen && n > 0)
  349. gstr(p, label, n); /* file system label */
  350. if(created)
  351. *created = ct;
  352. if(serialno)
  353. *serialno = sn;
  354. free(p);
  355. return 0;
  356. }
  357. int
  358. T2fssizeinfo(Session *s, Share *sp, uint64_t *total, uint64_t *unused)
  359. {
  360. Pkt *p;
  361. uint64_t t, f, n, b;
  362. p = t2hdr(s, sp, TRANS2_QUERY_FS_INFORMATION);
  363. pt2param(p);
  364. pl16(p, SMB_QUERY_FS_SIZE_INFO); /* Information level */
  365. pt2data(p);
  366. if(t2rpc(p) == -1){
  367. free(p);
  368. return -1;
  369. }
  370. gt2data(p);
  371. t = gl64(p); /* total blocks */
  372. f = gl64(p); /* free blocks */
  373. n = gl32(p); /* sectors per block */
  374. b = gl32(p); /* bytes per sector */
  375. /* I just can't figure out why this is here.
  376. * free is always true and I don't know how
  377. * to deal with this. Marked f as used for
  378. * compiler warning.
  379. if(free)
  380. *unused = f * n * b;
  381. */
  382. USED(f);
  383. if(total)
  384. *total = t * n * b;
  385. free(p);
  386. return 0;
  387. }
  388. int
  389. T2getdfsreferral(Session *s, Share *sp, char *path, int *gflags,
  390. int *used,
  391. Refer *re, int nent)
  392. {
  393. int i, vers, nret, len;
  394. char tmp[1024];
  395. uint8_t *base;
  396. Pkt *p;
  397. p = t2hdr(s, sp, TRANS2_GET_DFS_REFERRAL);
  398. pt2param(p);
  399. pl16(p, 3); /* max info level we understand, must be >= 3 for domain requests */
  400. ppath(p, path);
  401. pt2data(p);
  402. if(t2rpc(p) == -1){
  403. free(p);
  404. return -1;
  405. }
  406. memset(re, 0, sizeof *re * nent);
  407. gt2data(p);
  408. *used = gl16(p) / 2; /* length used (/2 as Windows counts in runes) */
  409. nret = gl16(p); /* number of referrals returned */
  410. *gflags = gl32(p); /* global flags */
  411. for(i = 0; i < nret && i < nent && i < 16; i++){
  412. base = p->pos;
  413. vers = gl16(p); /* version of records */
  414. len = gl16(p); /* length of records */
  415. re[i].type = gl16(p); /* server type */
  416. re[i].flags = gl16(p); /* referal flags */
  417. switch(vers){
  418. case 1:
  419. re[i].prox = 0; /* nearby */
  420. re[i].ttl = 5*60; /* 5 mins */
  421. gstr(p, tmp, sizeof tmp);
  422. re[i].addr = estrdup9p(tmp);
  423. re[i].path = estrdup9p(tmp);
  424. break;
  425. case 2:
  426. re[i].prox = gl32(p); /* not implemented in v2 */
  427. re[i].ttl = gl32(p);
  428. goff(p, base, re[i].path, sizeof tmp);
  429. re[i].path = estrdup9p(tmp);
  430. goff(p, base, re[i].path, sizeof tmp);/* spurious 8.3 path */
  431. goff(p, base, tmp, sizeof tmp);
  432. re[i].addr = estrdup9p(tmp);
  433. break;
  434. case 3:
  435. if(re[i].flags & DFS_REFERAL_LIST){
  436. re[i].prox = 0;
  437. re[i].ttl = gl32(p);
  438. goff(p, base, tmp, sizeof tmp);
  439. re[i].path = estrdup9p(tmp);
  440. gl16(p);
  441. goff(p, base, tmp, sizeof tmp);
  442. re[i].addr = estrdup9p(tmp);
  443. }
  444. else{
  445. re[i].prox = 0;
  446. re[i].ttl = gl32(p);
  447. goff(p, base, tmp, sizeof tmp);
  448. re[i].path = estrdup9p(tmp);
  449. gl16(p); /* spurious 8.3 path */
  450. goff(p, base, tmp, sizeof tmp);
  451. re[i].addr = estrdup9p(tmp);
  452. gl16(p); /* GUID (historic) */
  453. }
  454. break;
  455. default:
  456. /*
  457. * this should never happen as we specify our maximum
  458. * understood level in the request (above)
  459. */
  460. fprint(2, "%d - unsupported DFS infolevel\n", vers);
  461. re[i].path = estrdup9p(tmp);
  462. re[i].addr = estrdup9p(tmp);
  463. break;
  464. }
  465. p->pos = base+len;
  466. }
  467. free(p);
  468. return i;
  469. }