xref: /plan9/sys/src/cmd/aquarela/smbrap2.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1 #include "headers.h"
2 
3 typedef struct RapTableEntry RapTableEntry;
4 
5 struct RapTableEntry {
6 	char *name;
7 	SmbProcessResult (*procedure)(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata);
8 };
9 
10 typedef int INFOSIZEFN(ushort level, void *data);
11 typedef int INFOPUTFN(SmbBuffer *b, ushort level, void *data);
12 typedef int INFOPUTSTRINGSFN(SmbBuffer *b, ushort level, int instance, void *data);
13 typedef void *INFOENUMERATEFN(void *magic, int i);
14 
15 typedef struct InfoMethod {
16 	INFOSIZEFN *size;
17 	INFOPUTFN *put;
18 	INFOPUTSTRINGSFN *putstrings;
19 	INFOENUMERATEFN *enumerate;
20 } InfoMethod;
21 
22 static int
serverinfosize(ushort level,void * data)23 serverinfosize(ushort level, void *data)
24 {
25 	SmbServerInfo *si = data;
26 	switch (level) {
27 	case 0:
28 		return 16;
29 	case 1:
30 		return 26 + smbstrlen(si->remark);
31 	default:
32 		return 0;
33 	}
34 }
35 
36 static int
serverinfoput(SmbBuffer * b,ushort level,void * data)37 serverinfoput(SmbBuffer *b, ushort level, void *data)
38 {
39 	SmbServerInfo *si = data;
40 	if (!smbbufferputstrn(b, si->name, 16, 1))
41 		return 0;
42 	if (level > 0) {
43 		if (!smbbufferputb(b, si->vmaj)
44 			|| !smbbufferputb(b, si->vmin)
45 			|| !smbbufferputl(b, si->stype)
46 			|| !smbbufferputl(b, 0))
47 			return 0;
48 	}
49 	if (level > 1)
50 		return 0;
51 	return 1;
52 }
53 
54 static int
serverinfoputstrings(SmbBuffer * b,ushort level,int instance,void * data)55 serverinfoputstrings(SmbBuffer *b, ushort level, int instance, void *data)
56 {
57 	SmbServerInfo *si = data;
58 	if (level == 1) {
59 		if (!smbbufferfixupabsolutel(b, instance * 26 + 22)
60 			|| !smbbufferputstring(b, nil, SMB_STRING_ASCII, si->remark))
61 			return 0;
62 	}
63 	return 1;
64 }
65 
66 static void *
serverinfoenumerate(void * magic,int i)67 serverinfoenumerate(void *magic, int i)
68 {
69 	if (magic) {
70 		SmbServerInfo **si = magic;
71 		return si[i];
72 	}
73 	if (i == 0)
74 		return &smbglobals.serverinfo;
75 	return nil;
76 }
77 
78 InfoMethod serverinfo = {
79 	serverinfosize,
80 	serverinfoput,
81 	serverinfoputstrings,
82 	serverinfoenumerate,
83 };
84 
85 static int
shareinfosize(ushort level,void * data)86 shareinfosize(ushort level, void *data)
87 {
88 	SmbService *serv = data;
89 	switch (level) {
90 	case 0:
91 		return 13;
92 	case 1:
93 		return 20 + smbstrlen(serv->remark);
94 	case 2:
95 		return 40 + smbstrlen(serv->remark) + smbstrlen(serv->path);
96 	default:
97 		return 0;
98 	}
99 }
100 
101 static int
shareinfoput(SmbBuffer * b,ushort level,void * data)102 shareinfoput(SmbBuffer *b, ushort level, void *data)
103 {
104 	SmbService *serv = data;
105 	if (!smbbufferputstrn(b, serv->name, 13, 0))
106 		return 0;
107 	if (level > 0) {
108 		if (!smbbufferputb(b, 0)
109 			|| !smbbufferputs(b, serv->stype)
110 			|| !smbbufferputl(b, 0))
111 			return 0;
112 	}
113 	if (level > 1) {
114 		if (!smbbufferputs(b, 7)
115 			|| !smbbufferputs(b, -1)
116 			|| !smbbufferputs(b, serv->ref)
117 			|| !smbbufferputl(b, 0)
118 			|| !smbbufferfill(b, 0, 10))
119 			return 0;
120 	}
121 	if (level > 2)
122 		return 0;
123 	return 1;
124 }
125 
126 static int
shareinfoputstrings(SmbBuffer * b,ushort level,int instance,void * data)127 shareinfoputstrings(SmbBuffer *b, ushort level, int instance, void *data)
128 {
129 	SmbService *serv = data;
130 	switch (level) {
131 	case 0:
132 		break;
133 	case 1:
134 		if (!smbbufferfixupabsolutel(b, instance * 20 + 16)
135 			|| !smbbufferputstring(b, nil, SMB_STRING_ASCII, serv->remark))
136 			return 0;
137 		break;
138 	case 2:
139 		if (!smbbufferfixupabsolutel(b, instance * 40 + 16)
140 			|| !smbbufferputstring(b, nil, SMB_STRING_ASCII, serv->remark)
141 			|| !smbbufferfixupabsolutel(b, instance * 40 + 26)
142 			|| !smbbufferputstring(b, nil, SMB_STRING_ASCII, serv->path))
143 			return 0;
144 		break;
145 	default:
146 		return 0;
147 	}
148 	return 1;
149 }
150 
151 static void *
shareinfoenumerate(void *,int i)152 shareinfoenumerate(void *, int i)
153 {
154 	SmbService *serv;
155 	for (serv = smbservices; i-- > 0 && serv; serv = serv->next)
156 		;
157 	return serv;
158 }
159 
160 static InfoMethod shareinfo = {
161 	shareinfosize,
162 	shareinfoput,
163 	shareinfoputstrings,
164 	shareinfoenumerate,
165 };
166 
167 static SmbProcessResult
thingfill(SmbBuffer * outparam,SmbBuffer * outdata,InfoMethod * m,ushort level,void * magic)168 thingfill(SmbBuffer *outparam, SmbBuffer *outdata, InfoMethod *m, ushort level, void *magic)
169 {
170 	int sentthings, totalthings;
171 	int i;
172 	int totalbytes;
173 
174 	sentthings = 0;
175 	totalbytes = 0;
176 	for (i = 0; ; i++) {
177 		int len;
178 		void *thing = (*m->enumerate)(magic, i);
179 		if (thing == nil)
180 			break;
181 		len = (*m->size)(level, thing);
182 		if (totalbytes + len <= smbbufferspace(outdata)) {
183 			assert((*m->put)(outdata, level, thing));
184 			sentthings++;
185 		}
186 		totalbytes += len;
187 	}
188 	totalthings = i;
189 	for (i = 0; i < sentthings; i++) {
190 		void *thing = (*m->enumerate)(magic, i);
191 		assert(thing);
192 		assert((*m->putstrings)(outdata, level, i, thing));
193 	}
194 	if (!smbbufferputs(outparam, sentthings < totalthings ? SMB_RAP_ERROR_MORE_DATA : SMB_RAP_NERR_SUCCESS)
195 		|| !smbbufferputs(outparam, 0)
196 		|| !smbbufferputs(outparam, totalthings)
197 		|| !smbbufferputs(outparam, sentthings))
198 		return SmbProcessResultFormat;
199 	return SmbProcessResultReply;
200 }
201 
202 static SmbProcessResult
onethingfill(SmbBuffer * outparam,SmbBuffer * outdata,InfoMethod * m,ushort level,void * thing)203 onethingfill(SmbBuffer *outparam, SmbBuffer *outdata, InfoMethod *m, ushort level, void *thing)
204 {
205 	int moredata;
206 	int totalbytes = (*m->size)(level, thing);
207 	if (totalbytes <= smbbufferspace(outdata)) {
208 		assert((*m->put)(outdata, level, thing));
209 		assert((*m->putstrings)(outdata, level, 0, thing));
210 		moredata = 0;
211 	}
212 	else
213 		moredata = 1;
214 	if (!smbbufferputs(outparam, moredata ? SMB_RAP_ERROR_MORE_DATA : SMB_RAP_NERR_SUCCESS)
215 		|| !smbbufferputs(outparam, 0)
216 		|| !smbbufferputs(outparam, totalbytes))
217 		return SmbProcessResultFormat;
218 	return SmbProcessResultReply;
219 }
220 
221 static SmbProcessResult
netshareenum(SmbBuffer * inparam,SmbBuffer * outparam,SmbBuffer * outdata)222 netshareenum(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
223 {
224 	ushort level;
225 
226 	/* WrLeh */
227 	/* ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ENTCOUNT pcEntriesRead, ushort *pcTotalAvail */
228 
229 	if (!smbbuffergets(inparam, &level))
230 		return SmbProcessResultFormat;
231 
232 	smblogprintif(smbglobals.log.rap2, "netshareenum(%lud, %lud)\n",
233 		level, smbbufferwritespace(outdata));
234 
235 	if (level != 1)
236 		return SmbProcessResultFormat;
237 
238 	return thingfill(outparam, outdata, &shareinfo, level, nil);
239 }
240 
241 static SmbProcessResult
netserverenum2(SmbBuffer * inparam,SmbBuffer * outparam,SmbBuffer * outdata)242 netserverenum2(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
243 {
244 	ushort level, rbl;
245 	char *domain;
246 	ulong servertype;
247 	SmbProcessResult pr;
248 	SmbServerInfo *si[3];
249 	SmbServerInfo domainsi;
250 	int entries;
251 
252 	/* WrLehDz
253 	 * ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ENTCOUNT pcEntriesRead, ushort *pcTotalAvail,
254 	 * ulong fServerType, char *pszDomain
255 	*/
256 
257 	if (!smbbuffergets(inparam, &level)
258 		|| !smbbuffergets(inparam, &rbl)
259 		|| !smbbuffergetl(inparam, &servertype)
260 		|| !smbbuffergetstr(inparam, 0, &domain)) {
261 	fmtfail:
262 		pr = SmbProcessResultFormat;
263 		goto done;
264 	}
265 
266 	smblogprintif(smbglobals.log.rap2, "netserverenum2(%lud, %lud, 0x%.8lux, %s)\n",
267 		level, smbbufferwritespace(outdata), servertype, domain);
268 
269 	if (level > 1)
270 		goto fmtfail;
271 
272 	if (servertype == 0xffffffff)
273 		servertype &= ~(SV_TYPE_DOMAIN_ENUM | SV_TYPE_LOCAL_LIST_ONLY);
274 
275 	if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0 && (servertype & SV_TYPE_DOMAIN_ENUM) == 0)
276 		servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
277 
278 	entries = 0;
279 
280 	if ((servertype & SV_TYPE_SERVER) != 0
281 		&& (domain[0] == 0 || cistrcmp(domain, smbglobals.primarydomain) == 0)) {
282 		si[entries++] = &smbglobals.serverinfo;
283 	}
284 
285 	if ((servertype & SV_TYPE_DOMAIN_ENUM) != 0) {
286 		/* there's only one that I know about */
287 		memset(&domainsi, 0, sizeof(domainsi));
288 		domainsi.name = smbglobals.primarydomain;
289 		domainsi.stype = SV_TYPE_DOMAIN_ENUM;
290 		si[entries++] = &domainsi;
291 	}
292 	si[entries] = 0;
293 
294 	pr = thingfill(outparam, outdata, &serverinfo, level, si);
295 
296 done:
297 	free(domain);
298 	return pr;
299 }
300 
301 static SmbProcessResult
netsharegetinfo(SmbBuffer * inparam,SmbBuffer * outparam,SmbBuffer * outdata)302 netsharegetinfo(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
303 {
304 	char *netname;
305 	ushort level;
306 	SmbProcessResult pr;
307 	SmbService *serv;
308 
309 	/*
310 	 * zWrLh
311 	 * char *pszNetName, ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ushort *pcbTotalAvail
312 	*/
313 
314 	if (!smbbuffergetstrinline(inparam, &netname)
315 		|| !smbbuffergets(inparam, &level)) {
316 	fmtfail:
317 		pr = SmbProcessResultFormat;
318 		goto done;
319 	}
320 
321 	smblogprintif(smbglobals.log.rap2, "netsharegetinfo(%s, %lud, %lud)\n",
322 		netname, level, smbbufferwritespace(outdata));
323 
324 	if (level > 2)
325 		goto fmtfail;
326 
327 	for (serv = smbservices; serv; serv = serv->next)
328 		if (cistrcmp(serv->name, netname) == 0)
329 			break;
330 
331 	if (serv == nil) {
332 		smblogprint(-1, "netsharegetinfo: service %s unimplemented\n", netname);
333 		pr = SmbProcessResultUnimp;
334 		goto done;
335 	}
336 
337 	pr = onethingfill(outparam, outdata, &shareinfo, level, serv);
338 
339 done:
340 	return pr;
341 }
342 
343 static SmbProcessResult
netservergetinfo(SmbBuffer * inparam,SmbBuffer * outparam,SmbBuffer * outdata)344 netservergetinfo(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
345 {
346 	ushort level;
347 	SmbProcessResult pr;
348 
349 	/* WrLh
350 	 * ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ushort *pcbTotalAvail
351 	*/
352 
353 	if (!smbbuffergets(inparam, &level)) {
354 	fmtfail:
355 		pr = SmbProcessResultFormat;
356 		goto done;
357 	}
358 
359 	smblogprintif(smbglobals.log.rap2, "netservergetinfo(%lud, %lud)\n",
360 		level, smbbufferwritespace(outdata));
361 
362 	if (level > 1)
363 		goto fmtfail;
364 
365 	pr = onethingfill(outparam, outdata, &shareinfo, level, &smbglobals.serverinfo);
366 
367 done:
368 	return pr;
369 }
370 
371 static SmbProcessResult
netwkstagetinfo(SmbBuffer * inparam,SmbBuffer * outparam,SmbBuffer * outdata)372 netwkstagetinfo(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
373 {
374 	ushort level;
375 	ushort usefulbytes;
376 	SmbProcessResult pr;
377 	int moredata;
378 
379 	/* WrLh
380 	 * ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ushort *pcbTotalAvail
381 	*/
382 
383 	if (!smbbuffergets(inparam, &level)) {
384 	fmtfail:
385 		pr = SmbProcessResultFormat;
386 		goto done;
387 	}
388 
389 	smblogprintif(smbglobals.log.rap2, "netwkstagetinfo(%lud, %lud)\n",
390 		level, smbbufferwritespace(outdata));
391 
392 	if (level != 10)
393 		goto fmtfail;
394 
395 	usefulbytes = 22 + smbstrlen(smbglobals.serverinfo.name) + smbstrlen(getuser())
396 		+ 3 * smbstrlen(smbglobals.primarydomain);
397 
398 	moredata = usefulbytes > smbbufferwritespace(outdata);
399 
400 	assert(smbbufferputl(outdata, 0));
401 	assert(smbbufferputl(outdata, 0));
402 	assert(smbbufferputl(outdata, 0));
403 	assert(smbbufferputb(outdata, smbglobals.serverinfo.vmaj));
404 	assert(smbbufferputb(outdata, smbglobals.serverinfo.vmin));
405 	assert(smbbufferputl(outdata, 0));
406 	assert(smbbufferputl(outdata, 0));
407 	assert(smbbufferfixupabsolutel(outdata, 0));
408 	assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, smbglobals.serverinfo.name));
409 	assert(smbbufferfixupabsolutel(outdata, 4));
410 	assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, getuser()));
411 	assert(smbbufferfixupabsolutel(outdata, 8));
412 	assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, smbglobals.primarydomain));
413 	assert(smbbufferfixupabsolutel(outdata, 14));
414 	assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, smbglobals.primarydomain));
415 	assert(smbbufferfixupabsolutel(outdata, 18));
416 	assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, smbglobals.primarydomain));
417 
418 	if (!smbbufferputs(outparam, moredata ? SMB_RAP_ERROR_MORE_DATA : SMB_RAP_NERR_SUCCESS)
419 		|| !smbbufferputs(outparam, 0)
420 		|| !smbbufferputs(outparam, usefulbytes)) {
421 		pr = SmbProcessResultFormat;
422 		goto done;
423 	}
424 
425 	pr = SmbProcessResultReply;
426 
427 done:
428 	return pr;
429 }
430 
431 static RapTableEntry raptable[] = {
432 [RapNetShareGetInfo] { "NetShareGetInfo", netsharegetinfo },
433 [RapNetShareEnum] { "NetShareEnum", netshareenum },
434 [RapNetServerGetInfo] {"NetServerGetInfo", netservergetinfo },
435 [RapNetWkstaGetInfo] { "NetWkstaGetInfo", netwkstagetinfo },
436 [RapNetServerEnum2] { "NetServerEnum2", netserverenum2 },
437 };
438 
439 SmbProcessResult
smbrap2(SmbSession * s)440 smbrap2(SmbSession *s)
441 {
442 	char *pstring;
443 	char *dstring;
444 	ushort pno;
445 	RapTableEntry *e;
446 	SmbProcessResult pr;
447 	SmbBuffer *inparam;
448 
449 	inparam = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount);
450 	if (!smbbuffergets(inparam, &pno)
451 		|| !smbbuffergetstrinline(inparam, &pstring)
452 		|| !smbbuffergetstrinline(inparam, &dstring)) {
453 		smblogprintif(smbglobals.log.rap2, "smbrap2: not enough parameters\n");
454 		pr = SmbProcessResultFormat;
455 		goto done;
456 	}
457 	if (pno > nelem(raptable) || raptable[pno].name == nil) {
458 		smblogprint(-1, "smbrap2: unsupported procedure %ud\n", pno);
459 		pr = SmbProcessResultUnimp;
460 		goto done;
461 	}
462 	e = raptable + pno;
463 	pr = (*e->procedure)(inparam, s->transaction.out.parameters, s->transaction.out.data);
464 done:
465 	smbbufferfree(&inparam);
466 	return pr;
467 }
468