1 #include "headers.h"
2 #include <pool.h>
3
4 void
smbsearchfree(SmbSearch ** searchp)5 smbsearchfree(SmbSearch **searchp)
6 {
7 SmbSearch *search = *searchp;
8 if (search) {
9 smbdircachefree(&search->dc);
10 free(search->rep);
11 free(search);
12 *searchp = nil;
13 }
14 }
15
16 void
smbsearchclose(SmbSession * s,SmbSearch * search)17 smbsearchclose(SmbSession *s, SmbSearch *search)
18 {
19 if (search) {
20 smblogprintif(smbglobals.log.sids, "smbsearchclose: tid 0x%.4ux sid 0x%.4ux\n", search->t->id, search->id);
21 smbidmapremove(s->sidmap, search);
22 smbsearchfree(&search);
23 }
24 }
25
26 void
smbsearchclosebyid(SmbSession * s,ushort sid)27 smbsearchclosebyid(SmbSession *s, ushort sid)
28 {
29 smbsearchclose(s, smbidmapfind(s->sidmap, sid));
30 }
31
32 SmbSearch *
smbsearchnew(SmbSession * s,SmbDirCache * dc,Reprog * r,SmbTree * t)33 smbsearchnew(SmbSession *s, SmbDirCache *dc, Reprog *r, SmbTree *t)
34 {
35 SmbSearch *search;
36 if (s->sidmap == nil)
37 s->sidmap = smbidmapnew();
38 search = smbemalloc(sizeof(SmbSearch));
39 smbidmapadd(s->sidmap, search);
40 search->dc = dc;
41 search->rep = r;
42 search->t = t;
43 smblogprintif(smbglobals.log.sids, "smbsearchnew: 0x%.4ux\n", search->id);
44 return search;
45 }
46
47 static int
standardflatten(SmbSession * s,SmbBuffer * b,Dir * d,ulong * nameoffsetp)48 standardflatten(SmbSession *s, SmbBuffer *b, Dir *d, ulong *nameoffsetp)
49 {
50 ushort mdate, mtime;
51 ushort adate, atime;
52 ushort fnlfixupoffset;
53
54 smbplan9time2datetime(d->mtime, s->tzoff, &mdate, &mtime);
55 smbplan9time2datetime(d->atime, s->tzoff, &adate, &atime);
56 if (!smbbufferputs(b, mdate)
57 || !smbbufferputs(b, mtime)
58 || !smbbufferputs(b, adate)
59 || !smbbufferputs(b, atime)
60 || !smbbufferputs(b, mdate)
61 || !smbbufferputs(b, mtime)
62 || !smbbufferputl(b, d->length)
63 || !smbbufferputl(b, 512) // ha
64 || !smbbufferputs(b, (d->qid.type & QTDIR) ? 0x10 : 0))
65 return 0;
66 fnlfixupoffset = smbbufferwriteoffset(b);
67 if (!smbbufferputs(b, 0))
68 return 0;
69 *nameoffsetp = smbbufferwriteoffset(b);
70 if (!smbbufferputstring(b, &s->peerinfo, 0, d->name))
71 return 0;
72 return smbbufferfixuprelatives(b, fnlfixupoffset);
73 }
74
75 static int
findbothflatten(SmbBuffer * b,SmbPeerInfo * p,Dir * d,ulong resumekey,ulong * nameoffsetp)76 findbothflatten(SmbBuffer *b, SmbPeerInfo *p, Dir *d, ulong resumekey, ulong *nameoffsetp)
77 {
78 vlong mtime, atime;
79 ulong fixup;
80
81 fixup = smbbufferwriteoffset(b);
82 mtime = smbplan9time2time(d->mtime);
83 atime = smbplan9time2time(d->atime);
84 poolcheck(mainmem);
85 if (!smbbufferputl(b, 0)
86 || !smbbufferputl(b, resumekey)
87 || !smbbufferputv(b, mtime)
88 || !smbbufferputv(b, atime)
89 || !smbbufferputv(b, mtime)
90 || !smbbufferputv(b, mtime)
91 || !smbbufferputv(b, d->length)
92 || !smbbufferputv(b, smbl2roundupvlong(d->length, smbglobals.l2allocationsize)) // ha
93 || !smbbufferputl(b, (d->qid.type & QTDIR) ? 0x10 : 0x80)
94 || !smbbufferputl(b, smbstringlen(p, d->name))
95 || !smbbufferputl(b, 0)
96 || !smbbufferputb(b, 0)
97 || !smbbufferputb(b, 0)
98 || !smbbufferfill(b, 0, 24))
99 return 0;
100 poolcheck(mainmem);
101 *nameoffsetp = smbbufferwriteoffset(b);
102 if (!smbbufferputstring(b, p, 0, d->name) || !smbbufferalignl2(b, 2))
103 return 0;
104 poolcheck(mainmem);
105 return smbbufferfixuprelativeinclusivel(b, fixup);
106 }
107
108 static void
populate(SmbSession * s,SmbDirCache * dc,Reprog * r,ushort informationlevel,ushort flags,ushort scount,ushort * ep,ulong * nameoffsetp)109 populate(SmbSession *s, SmbDirCache *dc, Reprog *r, ushort informationlevel, ushort flags, ushort scount,
110 ushort *ep, ulong *nameoffsetp)
111 {
112 ushort e;
113 ulong nameoffset;
114 e = 0;
115 nameoffset = 0;
116 while (dc->i < dc->n && e < scount) {
117 ulong backup;
118 int rv;
119
120 if (!smbmatch(dc->buf[dc->i].name, r)) {
121 dc->i++;
122 continue;
123 }
124 rv = 0;
125 backup = smbbufferwriteoffset(s->transaction.out.data);
126 switch (informationlevel) {
127 case SMB_INFO_STANDARD:
128 if (flags & SMB_FIND_RETURN_RESUME_KEYS) {
129 if (!smbbufferputl(s->transaction.out.data, dc->i)) {
130 rv = 0;
131 break;
132 }
133 }
134 rv = standardflatten(s, s->transaction.out.data, dc->buf + dc->i, &nameoffset);
135 break;
136 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
137 rv = findbothflatten(s->transaction.out.data, &s->peerinfo, dc->buf + dc->i, dc->i, &nameoffset);
138 break;
139 }
140 if (rv == 0) {
141 smbbufferwritebackup(s->transaction.out.data, backup);
142 break;
143 }
144 dc->i++;
145 e++;
146 }
147 *ep = e;
148 *nameoffsetp = nameoffset;
149 }
150
151 SmbProcessResult
smbtrans2findfirst2(SmbSession * s,SmbHeader * h)152 smbtrans2findfirst2(SmbSession *s, SmbHeader *h)
153 {
154 SmbBuffer *b;
155 char *pattern = nil;
156 char *dir = nil;
157 char *name = nil;
158 ushort searchattributes, searchcount, flags, informationlevel;
159 ulong searchstoragetype;
160 SmbDirCache *dc = nil;
161 ushort e;
162 ulong nameoffset;
163 ushort eos;
164 SmbSearch *search;
165 SmbProcessResult pr;
166 Reprog *r = nil;
167 SmbTree *t;
168 int debug;
169
170 debug = smboptable[h->command].debug
171 || smbtrans2optable[SMB_TRANS2_FIND_FIRST2].debug
172 || smbglobals.log.find;
173 poolcheck(mainmem);
174 b = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount);
175 if (!smbbuffergets(b, &searchattributes)
176 || !smbbuffergets(b, &searchcount)
177 || !smbbuffergets(b, &flags)
178 || !smbbuffergets(b, &informationlevel)
179 || !smbbuffergetl(b, &searchstoragetype)
180 || !smbbuffergetstring(b, h, SMB_STRING_PATH, &pattern)) {
181 pr = SmbProcessResultFormat;
182 goto done;
183 }
184 smbloglock();
185 smblogprintif(debug, "searchattributes: 0x%.4ux\n", searchattributes);
186 smblogprintif(debug, "searchcount: 0x%.4ux\n", searchcount);
187 smblogprintif(debug, "flags: 0x%.4ux\n", flags);
188 smblogprintif(debug, "informationlevel: 0x%.4ux\n", informationlevel);
189 smblogprintif(debug, "searchstoragetype: 0x%.8lux\n", searchstoragetype);
190 smblogprintif(debug, "pattern: %s\n", pattern);
191 smblogunlock();
192 smbpathsplit(pattern, &dir, &name);
193 if (informationlevel != SMB_INFO_STANDARD && informationlevel != SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
194 smblogprint(-1, "smbtrans2findfirst2: infolevel 0x%.4ux not implemented\n", informationlevel);
195 smbseterror(s, ERRDOS, ERRunknownlevel);
196 pr = SmbProcessResultError;
197 goto done;
198 }
199
200 t = smbidmapfind(s->tidmap, h->tid);
201 if (t == nil) {
202 smbseterror(s, ERRSRV, ERRinvtid);
203 pr = SmbProcessResultError;
204 goto done;
205 }
206
207 dc = smbmkdircache(t, dir);
208 if (dc == nil) {
209 smbseterror(s, ERRDOS, ERRnoaccess);
210 pr = SmbProcessResultError;
211 goto done;
212 }
213 poolcheck(mainmem);
214 r = smbmkrep(name);
215 populate(s, dc, r, informationlevel, flags, searchcount, &e, &nameoffset);
216 poolcheck(mainmem);
217 eos = dc->i >= dc->n;
218 if ((flags & SMB_FIND_CLOSE) != 0 || ((flags & SMB_FIND_CLOSE_EOS) != 0 && eos))
219 smbdircachefree(&dc);
220 poolcheck(mainmem);
221 if (dc) {
222 /* create a search handle */
223 search = smbsearchnew(s, dc, r, t);
224 r = nil;
225 dc = nil;
226 }
227 else
228 search = nil;
229 smbbufferputs(s->transaction.out.parameters, search ? search->id : 0);
230 smbbufferputs(s->transaction.out.parameters, e);
231 smbbufferputs(s->transaction.out.parameters, eos);
232 smbbufferputs(s->transaction.out.parameters, 0);
233 smbbufferputs(s->transaction.out.parameters, nameoffset);
234 pr = SmbProcessResultReply;
235 done:
236 smbbufferfree(&b);
237 free(pattern);
238 free(dir);
239 free(name);
240 smbdircachefree(&dc);
241 free(r);
242 return pr;
243 }
244
245 SmbProcessResult
smbtrans2findnext2(SmbSession * s,SmbHeader * h)246 smbtrans2findnext2(SmbSession *s, SmbHeader *h)
247 {
248 SmbBuffer *b;
249 int debug;
250 ushort sid, scount, infolevel;
251 ulong resumekey;
252 ushort flags;
253 char *filename = nil;
254 SmbProcessResult pr;
255 ushort e;
256 ulong nameoffset;
257 ushort eos;
258 SmbTree *t;
259 SmbSearch *search;
260
261 debug = smboptable[h->command].debug
262 || smbtrans2optable[SMB_TRANS2_FIND_NEXT2].debug
263 || smbglobals.log.find;
264 b = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount);
265 if (!smbbuffergets(b, &sid)
266 || !smbbuffergets(b, &scount)
267 || !smbbuffergets(b, &infolevel)
268 || !smbbuffergetl(b, &resumekey)
269 || !smbbuffergets(b, &flags)
270 || !smbbuffergetstring(b, h, 0, &filename)) {
271 pr = SmbProcessResultFormat;
272 goto done;
273 }
274 smblogprintif(debug,
275 "smbtrans2findnext2: sid %d scount %d infolevel 0x%.4ux resumekey %lud flags 0x%.4ux filename %s\n",
276 sid, scount, infolevel, resumekey, flags, filename);
277
278 if (infolevel != SMB_INFO_STANDARD && infolevel != SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
279 smblogprint(-1, "smbtrans2findnext2: infolevel 0x%.4ux not implemented\n", infolevel);
280 smbseterror(s, ERRDOS, ERRunknownlevel);
281 pr = SmbProcessResultError;
282 goto done;
283 }
284
285 t = smbidmapfind(s->tidmap, h->tid);
286 if (t == nil) {
287 smbseterror(s, ERRSRV, ERRinvtid);
288 pr = SmbProcessResultError;
289 goto done;
290 }
291
292 search = smbidmapfind(s->sidmap, sid);
293 if (search == nil) {
294 smbseterror(s, ERRDOS, ERRnofiles);
295 pr = SmbProcessResultError;
296 goto done;
297 }
298
299 if (search->t != t) {
300 smbseterror(s, ERRSRV, ERRinvtid);
301 pr = SmbProcessResultError;
302 goto done;
303 }
304
305 if ((flags & (1 << 3)) == 0) {
306 long i;
307 if (filename == nil) {
308 smbseterror(s, ERRDOS, ERRnofiles);
309 pr = SmbProcessResultError;
310 goto done;
311 }
312 for (i = 0; i < search->dc->n; i++)
313 if (strcmp(search->dc->buf[i].name, filename) == 0) {
314 search->dc->i = i + 1;
315 break;
316 }
317 }
318
319 populate(s, search->dc, search->rep, infolevel, flags, scount, &e, &nameoffset);
320
321 eos = search->dc->i >= search->dc->n;
322 if ((flags & SMB_FIND_CLOSE) != 0 || ((flags & SMB_FIND_CLOSE_EOS) != 0 && eos))
323 smbsearchclose(s, search);
324 smbbufferputs(s->transaction.out.parameters, e);
325 smbbufferputs(s->transaction.out.parameters, eos);
326 smbbufferputs(s->transaction.out.parameters, 0);
327 smbbufferputs(s->transaction.out.parameters, nameoffset);
328 pr = SmbProcessResultReply;
329 done:
330 smbbufferfree(&b);
331 free(filename);
332 return pr;
333 }
334