trans.c 17 KB

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