trans2.c 12 KB

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