trans.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  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. #include "remsmb.h"
  8. #include "apinums.h"
  9. static Pkt *
  10. thdr(Session *s, Share *sp)
  11. {
  12. Pkt *p;
  13. p = cifshdr(s, sp, SMB_COM_TRANSACTION);
  14. p->tbase = pl16(p, 0); /* 0 Total parameter bytes to be sent, filled later */
  15. pl16(p, 0); /* 2 Total data bytes to be sent, filled later */
  16. pl16(p, 64); /* 4 Max parameter to return */
  17. pl16(p, MTU - T2HDRLEN - 128); /* 6 Max data to return */
  18. pl16(p, 1); /* 8 Max setup count to return */
  19. pl16(p, 0); /* 10 Flags */
  20. pl32(p, 1000); /* 12 Timeout (ms) */
  21. pl16(p, 0); /* 16 Reserved */
  22. pl16(p, 0); /* 18 Parameter count, filled later */
  23. pl16(p, 0); /* 20 Parameter offset, filled later */
  24. pl16(p, 0); /* 22 Data count, filled later */
  25. pl16(p, 0); /* 24 Data offset, filled later */
  26. pl16(p, 0); /* 26 Setup count (in words) */
  27. pbytes(p); /* end of cifs words section */
  28. return p;
  29. }
  30. static void
  31. ptparam(Pkt *p)
  32. {
  33. uchar *pos;
  34. if(((p->pos - p->tbase) % 2) != 0)
  35. p8(p, 0); /* pad to word boundry */
  36. pos = p->pos;
  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. ptdata(Pkt *p)
  43. {
  44. uchar *pos = p->pos;
  45. assert(p->tparam != 0);
  46. if(((p->pos - p->tbase) % 2) != 0)
  47. p8(p, 0); /* pad to word boundry */
  48. p->pos = p->tbase + 0;
  49. pl16(p, pos - p->tparam); /* total param count */
  50. p->pos = p->tbase + 18;
  51. pl16(p, pos - p->tparam); /* param count */
  52. p->pos = p->tbase + 24;
  53. pl16(p, pos - p->buf - NBHDRLEN); /* data offset */
  54. p->tdata = p->pos = pos;
  55. }
  56. static int
  57. trpc(Pkt *p)
  58. {
  59. int got;
  60. uchar *pos = p->pos;
  61. assert(p->tbase != 0);
  62. assert(p->tdata != 0);
  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. gtparam(Pkt *p)
  85. {
  86. p->pos = p->tparam;
  87. }
  88. static void
  89. gtdata(Pkt *p)
  90. {
  91. p->pos = p->tdata;
  92. }
  93. int
  94. RAPshareenum(Session *s, Share *sp, Share **ent)
  95. {
  96. int ngot = 0, err, navail, nret;
  97. char tmp[1024];
  98. Pkt *p;
  99. Share *q;
  100. p = thdr(s, sp);
  101. pstr(p, "\\PIPE\\LANMAN");
  102. ptparam(p);
  103. pl16(p, API_WShareEnum);
  104. pascii(p, REMSmb_NetShareEnum_P); /* request descriptor */
  105. pascii(p, REMSmb_share_info_0); /* reply descriptor */
  106. pl16(p, 0); /* detail level */
  107. pl16(p, MTU - 200); /* receive buffer length */
  108. ptdata(p);
  109. if(trpc(p) == -1){
  110. free(p);
  111. return -1;
  112. }
  113. gtparam(p);
  114. err = gl16(p); /* error code */
  115. gl16(p); /* rx buffer offset */
  116. nret = gl16(p); /* number of entries returned */
  117. navail = gl16(p); /* number of entries available */
  118. if(err && err != RAP_ERR_MOREINFO){
  119. werrstr("%s", raperrstr(err));
  120. free(p);
  121. return -1;
  122. }
  123. if(ngot == 0){
  124. *ent = emalloc9p(sizeof(Share) * navail);
  125. memset(*ent, 0, sizeof(Share) * navail);
  126. }
  127. q = *ent + ngot;
  128. for (; ngot < navail && nret--; ngot++){
  129. gmem(p, tmp, 13); /* name */
  130. tmp[13] = 0;
  131. q->name = estrdup9p(tmp);
  132. q++;
  133. }
  134. if(ngot < navail)
  135. fprint(2, "%s: %d/%d - share list incomplete\n", argv0, ngot, navail);
  136. free(p);
  137. return ngot;
  138. }
  139. int
  140. RAPshareinfo(Session *s, Share *sp, char *share, Shareinfo2 *si2p)
  141. {
  142. int conv, err;
  143. char tmp[1024];
  144. Pkt *p;
  145. p = thdr(s, sp);
  146. pstr(p, "\\PIPE\\LANMAN");
  147. ptparam(p);
  148. pl16(p, API_WShareGetInfo);
  149. pascii(p, REMSmb_NetShareGetInfo_P); /* request descriptor */
  150. pascii(p, REMSmb_share_info_2); /* reply descriptor */
  151. pascii(p, share);
  152. pl16(p, 1); /* detail level */
  153. pl16(p, MTU - 200); /* receive buffer length */
  154. ptdata(p);
  155. if(trpc(p) == -1){
  156. free(p);
  157. return -1;
  158. }
  159. gtparam(p);
  160. err = gl16(p); /* error code */
  161. conv = gl16(p); /* rx buffer offset */
  162. gl16(p); /* number of entries returned */
  163. gl16(p); /* number of entries available */
  164. if(err){
  165. werrstr("%s", raperrstr(err));
  166. free(p);
  167. return -1;
  168. }
  169. memset(si2p, 0, sizeof(Shareinfo2));
  170. gmem(p, tmp, 13);
  171. tmp[13] = 0;
  172. g8(p); /* padding */
  173. si2p->name = estrdup9p(tmp);
  174. si2p->type = gl16(p);
  175. gconv(p, conv, tmp, sizeof tmp);
  176. si2p->comment = estrdup9p(tmp);
  177. gl16(p); /* comment offset high (unused) */
  178. si2p->perms = gl16(p);
  179. si2p->maxusrs = gl16(p);
  180. si2p->activeusrs = gl16(p);
  181. gconv(p, conv, tmp, sizeof tmp);
  182. si2p->path = estrdup9p(tmp);
  183. gl16(p); /* path offset high (unused) */
  184. gmem(p, tmp, 9);
  185. tmp[9] = 0;
  186. si2p->passwd = estrdup9p(tmp);
  187. free(p);
  188. return 0;
  189. }
  190. /*
  191. * Tried to split sessionenum into two passes, one getting the names
  192. * of the connected workstations and the other collecting the detailed info,
  193. * however API_WSessionGetInfo doesn't seem to work agains win2k3 for infolevel
  194. * ten and infolevel one and two are priviledged calls. This means this code
  195. * will work for small numbers of sessions agains win2k3 and fail for samba 3.0
  196. * as it supports info levels zero and two only.
  197. */
  198. int
  199. RAPsessionenum(Session *s, Share *sp, Sessinfo **sip)
  200. {
  201. int ngot = 0, conv, err, navail, nret;
  202. char tmp[1024];
  203. Pkt *p;
  204. Sessinfo *q;
  205. p = thdr(s, sp);
  206. pstr(p, "\\PIPE\\LANMAN");
  207. ptparam(p);
  208. pl16(p, API_WSessionEnum);
  209. pascii(p, REMSmb_NetSessionEnum_P); /* request descriptor */
  210. pascii(p, REMSmb_session_info_10); /* reply descriptor */
  211. pl16(p, 10); /* detail level */
  212. pl16(p, MTU - 200); /* receive buffer length */
  213. ptdata(p);
  214. if(trpc(p) == -1){
  215. free(p);
  216. return -1;
  217. }
  218. gtparam(p);
  219. err = gl16(p); /* error code */
  220. conv = gl16(p); /* rx buffer offset */
  221. nret = gl16(p); /* number of entries returned */
  222. navail = gl16(p); /* number of entries available */
  223. if(err && err != RAP_ERR_MOREINFO){
  224. werrstr("%s", raperrstr(err));
  225. free(p);
  226. return -1;
  227. }
  228. if(ngot == 0){
  229. *sip = emalloc9p(sizeof(Sessinfo) * navail);
  230. memset(*sip, 0, sizeof(Sessinfo) * navail);
  231. }
  232. q = *sip + ngot;
  233. while(nret-- != 0){
  234. gconv(p, conv, tmp, sizeof tmp);
  235. q->wrkstn = estrdup9p(tmp);
  236. gconv(p, conv, tmp, sizeof tmp);
  237. q->user = estrdup9p(tmp);
  238. q->sesstime = gl32(p);
  239. q->idletime = gl32(p);
  240. ngot++;
  241. q++;
  242. }
  243. if(ngot < navail)
  244. fprint(2, "warning: %d/%d - session list incomplete\n", ngot, navail);
  245. free(p);
  246. return ngot;
  247. }
  248. int
  249. RAPgroupenum(Session *s, Share *sp, Namelist **nlp)
  250. {
  251. int ngot, err, navail, nret;
  252. char tmp[1024];
  253. Pkt *p;
  254. Namelist *q;
  255. ngot = 0;
  256. p = thdr(s, sp);
  257. pstr(p, "\\PIPE\\LANMAN");
  258. ptparam(p);
  259. pl16(p, API_WGroupEnum);
  260. pascii(p, REMSmb_NetGroupEnum_P); /* request descriptor */
  261. pascii(p, REMSmb_group_info_0); /* reply descriptor */
  262. pl16(p, 0); /* detail level */
  263. pl16(p, MTU - 200); /* receive buffer length */
  264. ptdata(p);
  265. if(trpc(p) == -1){
  266. free(p);
  267. return -1;
  268. }
  269. gtparam(p);
  270. err = gl16(p); /* error code */
  271. gl16(p); /* rx buffer offset */
  272. nret = gl16(p); /* number of entries returned */
  273. navail = gl16(p); /* number of entries available */
  274. if(err && err != RAP_ERR_MOREINFO){
  275. werrstr("%s", raperrstr(err));
  276. free(p);
  277. return -1;
  278. }
  279. *nlp = emalloc9p(sizeof(Namelist) * navail);
  280. memset(*nlp, 0, sizeof(Namelist) * navail);
  281. q = *nlp + ngot;
  282. while(ngot < navail && nret--){
  283. gmem(p, tmp, 21);
  284. tmp[21] = 0;
  285. q->name = estrdup9p(tmp);
  286. ngot++;
  287. q++;
  288. if(p->pos >= p->eop) /* Windows seems to lie somtimes */
  289. break;
  290. }
  291. free(p);
  292. return ngot;
  293. }
  294. int
  295. RAPgroupusers(Session *s, Share *sp, char *group, Namelist **nlp)
  296. {
  297. int ngot, err, navail, nret;
  298. char tmp[1024];
  299. Pkt *p;
  300. Namelist *q;
  301. ngot = 0;
  302. p = thdr(s, sp);
  303. pstr(p, "\\PIPE\\LANMAN");
  304. ptparam(p);
  305. pl16(p, API_WGroupGetUsers);
  306. pascii(p, REMSmb_NetGroupGetUsers_P); /* request descriptor */
  307. pascii(p, REMSmb_user_info_0); /* reply descriptor */
  308. pascii(p, group); /* group name for list */
  309. pl16(p, 0); /* detail level */
  310. pl16(p, MTU - 200); /* receive buffer length */
  311. ptdata(p);
  312. if(trpc(p) == -1){
  313. free(p);
  314. return -1;
  315. }
  316. gtparam(p);
  317. err = gl16(p); /* error code */
  318. gl16(p); /* rx buffer offset */
  319. nret = gl16(p); /* number of entries returned */
  320. navail = gl16(p); /* number of entries available */
  321. if(err && err != RAP_ERR_MOREINFO){
  322. werrstr("%s", raperrstr(err));
  323. free(p);
  324. return -1;
  325. }
  326. *nlp = emalloc9p(sizeof(Namelist) * navail);
  327. memset(*nlp, 0, sizeof(Namelist) * navail);
  328. q = *nlp + ngot;
  329. while(ngot < navail && nret--){
  330. gmem(p, tmp, 21);
  331. tmp[21] = 0;
  332. q->name = estrdup9p(tmp);
  333. ngot++;
  334. q++;
  335. if(p->pos >= p->eop) /* Windows seems to lie somtimes */
  336. break;
  337. }
  338. free(p);
  339. return ngot;
  340. }
  341. int
  342. RAPuserenum(Session *s, Share *sp, Namelist **nlp)
  343. {
  344. int ngot, err, navail, nret;
  345. char tmp[1024];
  346. Pkt *p;
  347. Namelist *q;
  348. ngot = 0;
  349. p = thdr(s, sp);
  350. pstr(p, "\\PIPE\\LANMAN");
  351. ptparam(p);
  352. pl16(p, API_WUserEnum);
  353. pascii(p, REMSmb_NetUserEnum_P); /* request descriptor */
  354. pascii(p, REMSmb_user_info_0); /* reply descriptor */
  355. pl16(p, 0); /* detail level */
  356. pl16(p, MTU - 200); /* receive buffer length */
  357. ptdata(p);
  358. if(trpc(p) == -1){
  359. free(p);
  360. return -1;
  361. }
  362. gtparam(p);
  363. err = gl16(p); /* error code */
  364. gl16(p); /* rx buffer offset */
  365. nret = gl16(p); /* number of entries returned */
  366. navail = gl16(p); /* number of entries available */
  367. if(err && err != RAP_ERR_MOREINFO){
  368. werrstr("%s", raperrstr(err));
  369. free(p);
  370. return -1;
  371. }
  372. *nlp = emalloc9p(sizeof(Namelist) * navail);
  373. memset(*nlp, 0, sizeof(Namelist) * navail);
  374. q = *nlp + ngot;
  375. while(ngot < navail && nret--){
  376. gmem(p, tmp, 21);
  377. tmp[21] = 0;
  378. q->name = estrdup9p(tmp);
  379. ngot++;
  380. q++;
  381. if(p->pos >= p->eop) /* Windows seems to lie somtimes */
  382. break;
  383. }
  384. free(p);
  385. return ngot;
  386. }
  387. int
  388. RAPuserenum2(Session *s, Share *sp, Namelist **nlp)
  389. {
  390. int ngot, resume, err, navail, nret;
  391. char tmp[1024];
  392. Pkt *p;
  393. Namelist *q;
  394. ngot = 0;
  395. resume = 0;
  396. more:
  397. p = thdr(s, sp);
  398. pstr(p, "\\PIPE\\LANMAN");
  399. ptparam(p);
  400. pl16(p, API_WUserEnum2);
  401. pascii(p, REMSmb_NetUserEnum2_P); /* request descriptor */
  402. pascii(p, REMSmb_user_info_0); /* reply descriptor */
  403. pl16(p, 0); /* detail level */
  404. pl16(p, MTU - 200); /* receive buffer length */
  405. pl32(p, resume); /* resume key to allow multiple fetches */
  406. ptdata(p);
  407. if(trpc(p) == -1){
  408. free(p);
  409. return -1;
  410. }
  411. gtparam(p);
  412. err = gl16(p); /* error code */
  413. gl16(p); /* rx buffer offset */
  414. resume = gl32(p); /* resume key returned */
  415. nret = gl16(p); /* number of entries returned */
  416. navail = gl16(p); /* number of entries available */
  417. if(err && err != RAP_ERR_MOREINFO){
  418. werrstr("%s", raperrstr(err));
  419. free(p);
  420. return -1;
  421. }
  422. if(ngot == 0){
  423. *nlp = emalloc9p(sizeof(Namelist) * navail);
  424. memset(*nlp, 0, sizeof(Namelist) * navail);
  425. }
  426. q = *nlp + ngot;
  427. while(ngot < navail && nret--){
  428. gmem(p, tmp, 21);
  429. tmp[21] = 0;
  430. q->name = estrdup9p(tmp);
  431. ngot++;
  432. q++;
  433. if(p->pos >= p->eop) /* Windows seems to lie somtimes */
  434. break;
  435. }
  436. free(p);
  437. if(ngot < navail)
  438. goto more;
  439. return ngot;
  440. }
  441. int
  442. RAPuserinfo(Session *s, Share *sp, char *user, Userinfo *uip)
  443. {
  444. int conv, err;
  445. char tmp[1024];
  446. Pkt *p;
  447. p = thdr(s, sp);
  448. pstr(p, "\\PIPE\\LANMAN");
  449. ptparam(p);
  450. pl16(p, API_WUserGetInfo);
  451. pascii(p, REMSmb_NetUserGetInfo_P); /* request descriptor */
  452. pascii(p, REMSmb_user_info_10); /* reply descriptor */
  453. pascii(p, user); /* username */
  454. pl16(p, 10); /* detail level */
  455. pl16(p, MTU - 200); /* receive buffer length */
  456. ptdata(p);
  457. if(trpc(p) == -1){
  458. free(p);
  459. return -1;
  460. }
  461. gtparam(p);
  462. err = gl16(p); /* error code */
  463. conv = gl16(p); /* rx buffer offset */
  464. gl16(p); /* number of entries returned */
  465. gl16(p); /* number of entries available */
  466. if(err && err != RAP_ERR_MOREINFO){
  467. werrstr("%s", raperrstr(err));
  468. free(p);
  469. return -1;
  470. }
  471. gmem(p, tmp, 21);
  472. tmp[21] = 0;
  473. uip->user = estrdup9p(tmp);
  474. g8(p); /* padding */
  475. gconv(p, conv, tmp, sizeof tmp);
  476. uip->comment = estrdup9p(tmp);
  477. gconv(p, conv, tmp, sizeof tmp);
  478. uip->user_comment = estrdup9p(tmp);
  479. gconv(p, conv, tmp, sizeof tmp);
  480. uip->fullname = estrdup9p(tmp);
  481. free(p);
  482. return 0;
  483. }
  484. /*
  485. * This works agains win2k3 but fails
  486. * against XP with the undocumented error 71/0x47
  487. */
  488. int
  489. RAPServerenum2(Session *s, Share *sp, char *workgroup, int type, int *more,
  490. Serverinfo **si)
  491. {
  492. int ngot = 0, conv, err, nret, navail;
  493. char tmp[1024];
  494. Pkt *p;
  495. Serverinfo *q;
  496. p = thdr(s, sp);
  497. pstr(p, "\\PIPE\\LANMAN");
  498. ptparam(p);
  499. pl16(p, API_NetServerEnum2);
  500. pascii(p, REMSmb_NetServerEnum2_P); /* request descriptor */
  501. pascii(p, REMSmb_server_info_1); /* reply descriptor */
  502. pl16(p, 1); /* detail level */
  503. pl16(p, MTU - 200); /* receive buffer length */
  504. pl32(p, type);
  505. pascii(p, workgroup);
  506. ptdata(p);
  507. if(trpc(p) == -1){
  508. free(p);
  509. return -1;
  510. }
  511. gtparam(p);
  512. err = gl16(p); /* error code */
  513. conv = gl16(p); /* rx buffer offset */
  514. nret = gl16(p); /* number of entries returned */
  515. navail = gl16(p); /* number of entries available */
  516. if(err && err != RAP_ERR_MOREINFO){
  517. werrstr("%s", raperrstr(err));
  518. free(p);
  519. return -1;
  520. }
  521. *si = emalloc9p(sizeof(Serverinfo) * navail);
  522. memset(*si, 0, sizeof(Serverinfo) * navail);
  523. q = *si;
  524. for (; nret-- != 0 && ngot < navail; ngot++){
  525. gmem(p, tmp, 16);
  526. tmp[16] = 0;
  527. q->name = estrdup9p(tmp);
  528. q->major = g8(p);
  529. q->minor = g8(p);
  530. q->type = gl32(p);
  531. gconv(p, conv, tmp, sizeof tmp);
  532. q->comment = estrdup9p(tmp);
  533. q++;
  534. }
  535. free(p);
  536. *more = err == RAP_ERR_MOREINFO;
  537. return ngot;
  538. }
  539. int
  540. RAPServerenum3(Session *s, Share *sp, char *workgroup, int type, int last,
  541. Serverinfo *si)
  542. {
  543. int conv, err, ngot, nret, navail;
  544. char *first, tmp[1024];
  545. Pkt *p;
  546. Serverinfo *q;
  547. ngot = last +1;
  548. first = si[last].name;
  549. more:
  550. p = thdr(s, sp);
  551. pstr(p, "\\PIPE\\LANMAN");
  552. ptparam(p);
  553. pl16(p, API_NetServerEnum3);
  554. pascii(p, REMSmb_NetServerEnum3_P); /* request descriptor */
  555. pascii(p, REMSmb_server_info_1); /* reply descriptor */
  556. pl16(p, 1); /* detail level */
  557. pl16(p, MTU - 200); /* receive buffer length */
  558. pl32(p, type);
  559. pascii(p, workgroup);
  560. pascii(p, first);
  561. ptdata(p);
  562. if(trpc(p) == -1){
  563. free(p);
  564. return -1;
  565. }
  566. gtparam(p);
  567. err = gl16(p); /* error code */
  568. conv = gl16(p); /* rx buffer offset */
  569. nret = gl16(p); /* number of entries returned */
  570. navail = gl16(p); /* number of entries available */
  571. if(err && err != RAP_ERR_MOREINFO){
  572. werrstr("%s", raperrstr(err));
  573. free(p);
  574. return -1;
  575. }
  576. if(nret < 2){ /* paranoia */
  577. free(p);
  578. return ngot;
  579. }
  580. q = si+ngot;
  581. while(nret-- != 0 && ngot < navail){
  582. gmem(p, tmp, 16);
  583. tmp[16] = 0;
  584. q->name = estrdup9p(tmp);
  585. q->major = g8(p);
  586. q->minor = g8(p);
  587. q->type = gl32(p);
  588. gconv(p, conv, tmp, sizeof tmp);
  589. tmp[sizeof tmp - 1] = 0;
  590. q->comment = estrdup9p(tmp);
  591. if(strcmp(first, tmp) == 0){ /* 1st one thru _may_ be a repeat */
  592. free(q->name);
  593. free(q->comment);
  594. continue;
  595. }
  596. ngot++;
  597. q++;
  598. }
  599. free(p);
  600. if(ngot < navail)
  601. goto more;
  602. return ngot;
  603. }
  604. /* Only the Administrator has permission to do this */
  605. int
  606. RAPFileenum2(Session *s, Share *sp, char *user, char *path, Fileinfo **fip)
  607. {
  608. int conv, err, ngot, resume, nret, navail;
  609. char tmp[1024];
  610. Pkt *p;
  611. Fileinfo *q;
  612. ngot = 0;
  613. resume = 0;
  614. more:
  615. p = thdr(s, sp);
  616. pstr(p, "\\PIPE\\LANMAN");
  617. ptparam(p);
  618. pl16(p, API_WFileEnum2);
  619. pascii(p, REMSmb_NetFileEnum2_P); /* request descriptor */
  620. pascii(p, REMSmb_file_info_1); /* reply descriptor */
  621. pascii(p, path);
  622. pascii(p, user);
  623. pl16(p, 1); /* detail level */
  624. pl16(p, MTU - 200); /* receive buffer length */
  625. pl32(p, resume); /* resume key */
  626. /* FIXME: maybe the padding and resume key are the wrong way around? */
  627. pl32(p, 0); /* padding ? */
  628. ptdata(p);
  629. if(trpc(p) == -1){
  630. free(p);
  631. return -1;
  632. }
  633. gtparam(p);
  634. err = gl16(p); /* error code */
  635. conv = gl16(p); /* rx buffer offset */
  636. resume = gl32(p); /* resume key returned */
  637. nret = gl16(p); /* number of entries returned */
  638. navail = gl16(p); /* number of entries available */
  639. if(err && err != RAP_ERR_MOREINFO){
  640. werrstr("%s", raperrstr(err));
  641. free(p);
  642. return -1;
  643. }
  644. if(nret < 2){ /* paranoia */
  645. free(p);
  646. return ngot;
  647. }
  648. if(ngot == 0){
  649. *fip = emalloc9p(sizeof(Fileinfo) * navail);
  650. memset(*fip, 0, sizeof(Fileinfo) * navail);
  651. }
  652. q = *fip + ngot;
  653. for(; nret-- && ngot < navail; ngot++){
  654. q->ident = gl16(p);
  655. q->perms = gl16(p);
  656. q->locks = gl16(p);
  657. gconv(p, conv, tmp, sizeof tmp);
  658. tmp[sizeof tmp - 1] = 0;
  659. q->path = estrdup9p(tmp);
  660. gconv(p, conv, tmp, sizeof tmp);
  661. tmp[sizeof tmp - 1] = 0;
  662. q->user = estrdup9p(tmp);
  663. q++;
  664. }
  665. free(p);
  666. if(ngot < navail)
  667. goto more;
  668. return ngot;
  669. }