xref: /plan9/sys/src/cmd/aquarela/smbcommon.c (revision 1936bb650459bace06c38a45b60888b47e5cd459)
1 #include "headers.h"
2 
3 int
smbsendunicode(SmbPeerInfo * i)4 smbsendunicode(SmbPeerInfo *i)
5 {
6 	return smbglobals.unicode && (i == nil || (i->capabilities & CAP_UNICODE) != 0);
7 }
8 
9 int
smbcheckwordcount(char * name,SmbHeader * h,ushort wordcount)10 smbcheckwordcount(char *name, SmbHeader *h, ushort wordcount)
11 {
12 	if (h->wordcount != wordcount) {
13 		smblogprint(-1, "smb%s: word count not %ud\n", name, wordcount);
14 		return 0;
15 	}
16 	return 1;
17 }
18 
19 int
smbcheckwordandbytecount(char * name,SmbHeader * h,ushort wordcount,uchar ** bdatap,uchar ** edatap)20 smbcheckwordandbytecount(char *name, SmbHeader *h, ushort wordcount, uchar **bdatap, uchar **edatap)
21 {
22 	ushort bytecount;
23 	uchar *bdata;
24 	if (h->wordcount != wordcount) {
25 		smblogprint(-1, "smb%s: word count not %ud\n", name, wordcount);
26 		return 0;
27 	}
28 	bdata = *bdatap;
29 	if (bdata + 2 > *edatap) {
30 		smblogprint(-1, "smb%s: not enough data for byte count\n", name);
31 		return 0;
32 	}
33 	bytecount = smbnhgets(bdata); bdata += 2;
34 	if (bdata + bytecount > *edatap) {
35 		smblogprint(-1, "smb%s: not enough data for bytes\n", name);
36 		return 0;
37 	}
38 	*edatap = bdata + bytecount;
39 	*bdatap = bdata;
40 	return 1;
41 }
42 
43 SmbProcessResult
smbchaincommand(SmbSession * s,SmbHeader * h,ulong andxoffsetfixup,uchar cmd,ushort offset,SmbBuffer * b)44 smbchaincommand(SmbSession *s, SmbHeader *h, ulong andxoffsetfixup, uchar cmd, ushort offset, SmbBuffer *b)
45 {
46 	SmbOpTableEntry *ote;
47 	uchar *pdata;
48 	ushort bytecount;
49 
50 	h->command = cmd;
51 	ote = smboptable + cmd;
52 	if (ote->process == nil) {
53 		smblogprint(-1, "smbchaincommand: %s (0x%.2ux) not implemented\n", ote->name, cmd);
54 		return SmbProcessResultUnimp;
55 	}
56 	if (!smbresponsealignl2(s, 2)
57 		|| !smbresponseoffsetputs(s, andxoffsetfixup, smbresponseoffset(s))
58 		|| !smbbufferpopreadlimit(b))
59 		return SmbProcessResultMisc;
60 	if (!smbbufferreadskipto(b, offset)) {
61 		smblogprint(-1, "smbchaincommand: illegal offset\n");
62 		return SmbProcessResultFormat;
63 	}
64 	if (!smbbuffergetb(b, &h->wordcount)) {
65 		smblogprint(-1, "smbchaincommand: not enough space for wordcount\n");
66 		return SmbProcessResultFormat;
67 	}
68 	pdata = smbbufferreadpointer(b);
69 	if (!smbbuffergetbytes(b, nil, h->wordcount * 2)) {
70 		smblogprint(-1, "smbchaincommand: not enough space for parameters\n");
71 		return SmbProcessResultFormat;
72 	}
73 	if (!smbbuffergets(b, &bytecount)) {
74 		smblogprint(-1, "smbchaincommand: not enough space for bytecount\n");
75 		return SmbProcessResultFormat;
76 	}
77 	if (!smbbufferpushreadlimit(b, smbbufferreadoffset(b) + bytecount)) {
78 		smblogprint(-1, "smbchaincommand: not enough space for bytes\n");
79 		return SmbProcessResultFormat;
80 	}
81 smblogprint(cmd, "chaining to %s\n", ote->name);
82 	return (*ote->process)(s, h, pdata, b);
83 }
84 
85 int
smbbuffergetheader(SmbBuffer * b,SmbHeader * h,uchar ** parametersp,ushort * bytecountp)86 smbbuffergetheader(SmbBuffer *b, SmbHeader *h, uchar **parametersp, ushort *bytecountp)
87 {
88 	SmbOpTableEntry *ote;
89 	SmbRawHeader *rh;
90 	rh = (SmbRawHeader *)smbbufferreadpointer(b);
91 	if (!smbbuffergetbytes(b, nil, (long)offsetof(SmbRawHeader, parameterwords[0]))) {
92 		smblogprint(-1, "smbgetheader: short packet\n");
93 		return 0;
94 	}
95 	if (rh->protocol[0] != 0xff || memcmp(rh->protocol + 1, "SMB", 3) != 0) {
96 		smblogprint(-1, "smbgetheader: invalid protocol\n");
97 		return 0;
98 	}
99 	h->command = rh->command;
100 	ote = smboptable + h->command;
101 	if (ote->name == nil) {
102 		smblogprint(-1, "smbgetheader: illegal opcode 0x%.2ux\n", h->command);
103 		return 0;
104 	}
105 	h->errclass = rh->status[0];
106 	h->error = smbnhgets(rh->status + 2);
107 	h->flags = rh->flags;
108 	h->flags2 = smbnhgets(rh->flags2);
109 	if (h->flags & ~(SmbHeaderFlagCaseless | SMB_FLAGS_SERVER_TO_REDIR | SmbHeaderFlagReserved | SmbHeaderFlagServerIgnore))
110 		smblogprint(-1, "smbgetheader: warning: unexpected flags 0x%.2ux\n", h->flags);
111 	h->wordcount = rh->wordcount;
112 	if (parametersp)
113 		*parametersp = smbbufferreadpointer(b);
114 	if (!smbbuffergetbytes(b, nil, h->wordcount * 2)) {
115 		smblogprint(-1, "smbgetheader: not enough data for parameter words\n");
116 		return 0;
117 	}
118 	h->tid = smbnhgets(rh->tid);
119 	h->pid = smbnhgets(rh->pid);
120 	h->uid = smbnhgets(rh->uid);
121 	h->mid = smbnhgets(rh->mid);
122 	if (!smbbuffergets(b, bytecountp))
123 		*bytecountp = 0;
124 	if (!smbbufferpushreadlimit(b, smbbufferreadoffset(b) + *bytecountp))
125 		return 0;
126 
127 smblogprint(h->command, "%s %s: tid 0x%.4ux pid 0x%.4ux uid 0x%.4ux mid 0x%.4ux\n", ote->name,
128 	(h->flags & SMB_FLAGS_SERVER_TO_REDIR) ? "response" : "request", h->tid, h->pid, h->uid, h->mid);
129 	return 1;
130 }
131 
132 int
smbcheckheaderdirection(SmbHeader * h,int response,char ** errmsgp)133 smbcheckheaderdirection(SmbHeader *h, int response, char **errmsgp)
134 {
135 	if (((h->flags & SMB_FLAGS_SERVER_TO_REDIR) == 0) == response) {
136 		smbstringprint(errmsgp, "unexpected %s", response ? "request" : "response");
137 		return 0;
138 	}
139 	return 1;
140 }
141 
142 int
smbcheckheader(SmbHeader * h,uchar command,int response,char ** errmsgp)143 smbcheckheader(SmbHeader *h, uchar command, int response, char **errmsgp)
144 {
145 	if (response && h->command != command) {
146 		smbstringprint(errmsgp, "sent %.2uc request, got %.2ux response", command, h->command);
147 		return 0;
148 	}
149 	if (!smbcheckheaderdirection(h, response, errmsgp))
150 		return 0;
151 	return 1;
152 }
153 
154 int
smbbuffergetandcheckheader(SmbBuffer * b,SmbHeader * h,uchar command,int response,uchar ** pdatap,ushort * bytecountp,char ** errmsgp)155 smbbuffergetandcheckheader(SmbBuffer *b, SmbHeader *h, uchar command, int response, uchar **pdatap, ushort *bytecountp, char **errmsgp)
156 {
157 	if (!smbbuffergetheader(b, h, pdatap, bytecountp)) {
158 		smbstringprint(errmsgp, "smbbuffergetandcheckheader: not enough data for header");
159 		return 0;
160 	}
161 	return smbcheckheader(h, command, response, errmsgp);
162 }
163 
164 int
smbsuccess(SmbHeader * h,char ** errmsgp)165 smbsuccess(SmbHeader *h, char **errmsgp)
166 {
167 	if (h->errclass != SUCCESS) {
168 		smbstringprint(errmsgp, "%s returned error %d/%d", smboptable[h->command].name, h->errclass, h->error);
169 		return 0;
170 	}
171 	return 1;
172 }
173 
174 #define BASE_FLAGS (0)
175 
176 int
smbbufferputheader(SmbBuffer * b,SmbHeader * h,SmbPeerInfo * p)177 smbbufferputheader(SmbBuffer *b, SmbHeader *h, SmbPeerInfo *p)
178 {
179 	SmbRawHeader *rh;
180 	if (offsetof(SmbRawHeader, parameterwords[0]) > smbbufferwritespace(b))
181 		return 0;
182 	if (smbbufferwriteoffset(b) == 0) {
183 		rh = (SmbRawHeader *)smbbufferwritepointer(b);
184 		rh->protocol[0] = 0xff;
185 		memcpy(rh->protocol + 1, "SMB", 3);
186 		rh->flags = SMB_FLAGS_SERVER_TO_REDIR | SmbHeaderFlagCaseless;
187 		rh->command = h->command;
188 		smbhnputs(rh->flags2, BASE_FLAGS | (smbsendunicode(p) ? SMB_FLAGS2_UNICODE : 0));
189 		memset(rh->extra, 0, sizeof(rh->extra));
190 		if (!smbbufferputbytes(b, nil, offsetof(SmbRawHeader, parameterwords[0])))
191 			return 0;
192 		rh->wordcount = h->wordcount;
193 	}
194 	else {
195 		rh = (SmbRawHeader *)smbbufferreadpointer(b);
196 		smbbufferputb(b, h->wordcount);
197 	}
198 	rh->status[0] = h->errclass;
199 	rh->status[1] = 0;
200 	smbhnputs(rh->status + 2, h->error);
201 	smbhnputs(rh->tid, h->tid);
202 	smbhnputs(rh->pid, h->pid);
203 	smbhnputs(rh->uid, h->uid);
204 	smbhnputs(rh->mid, h->mid);
205 	return 1;
206 }
207 
208 int
smbbufferputerror(SmbBuffer * s,SmbHeader * h,SmbPeerInfo * p,uchar errclass,ushort error)209 smbbufferputerror(SmbBuffer *s, SmbHeader *h, SmbPeerInfo *p, uchar errclass, ushort error)
210 {
211 	h->errclass = errclass;
212 	h->error = error;
213 	return smbbufferputheader(s, h, p);
214 }
215 
216 int
smbbufferputandxheader(SmbBuffer * b,SmbHeader * h,SmbPeerInfo * p,uchar andxcommand,ulong * andxoffsetfixupp)217 smbbufferputandxheader(SmbBuffer *b, SmbHeader *h, SmbPeerInfo *p, uchar andxcommand, ulong *andxoffsetfixupp)
218 {
219 	if (!smbbufferputheader(b, h, p)
220 		|| !smbbufferputb(b, andxcommand)
221 		|| !smbbufferputb(b, 0))
222 		return 0;
223 	*andxoffsetfixupp = smbbufferwriteoffset(b);
224 	return smbbufferputbytes(b, nil, 2);
225 }
226 
227 void
smbseterror(SmbSession * s,uchar errclass,ushort error)228 smbseterror(SmbSession *s, uchar errclass, ushort error)
229 {
230 	s->errclass = errclass;
231 	s->error = error;
232 }
233 
234 SmbProcessResult
smbbufferputack(SmbBuffer * b,SmbHeader * h,SmbPeerInfo * p)235 smbbufferputack(SmbBuffer *b, SmbHeader *h, SmbPeerInfo *p)
236 {
237 	h->wordcount = 0;
238 	return smbbufferputheader(b, h, p) && smbbufferputs(b, 0) ? SmbProcessResultReply : SmbProcessResultMisc;
239 }
240 
241 ushort
smbplan9mode2dosattr(ulong mode)242 smbplan9mode2dosattr(ulong mode)
243 {
244 	if (mode & DMDIR)
245 		return SMB_ATTR_DIRECTORY;
246 	return SMB_ATTR_NORMAL;
247 }
248 
249 ulong
smbdosattr2plan9mode(ushort attr)250 smbdosattr2plan9mode(ushort attr)
251 {
252 	ulong mode = 0444;
253 	if ((attr & SMB_ATTR_READ_ONLY) == 0)
254 		mode |= 0222;
255 	if (attr & SMB_ATTR_DIRECTORY) {
256 		mode |= DMDIR | 0711;
257 		mode &= DMDIR | 0755;
258 	}
259 	else
260 		mode &= 0744;
261 	return mode;
262 }
263 
264 ulong
smbdosattr2plan9wstatmode(ulong oldmode,ushort attr)265 smbdosattr2plan9wstatmode(ulong oldmode, ushort attr)
266 {
267 	ulong mode;
268 	if (oldmode & DMDIR)
269 		attr |= SMB_ATTR_DIRECTORY;
270 	else
271 		attr &= ~SMB_ATTR_DIRECTORY;
272 	mode = smbdosattr2plan9mode(attr);
273 	if (oldmode & 0444)
274 		mode = (mode & ~0444) | (mode & 0444);
275 	if ((attr & SMB_ATTR_READ_ONLY) == 0)
276 		mode |= oldmode & 0222;
277 	if (mode == oldmode)
278 		mode = 0xffffffff;
279 	return mode;
280 }
281 
282 ulong
smbplan9length2size32(vlong length)283 smbplan9length2size32(vlong length)
284 {
285 	if (length > 0xffffffff)
286 		return 0xffffffff;
287 	return length;
288 }
289 
290 vlong
smbl2roundupvlong(vlong v,int l2)291 smbl2roundupvlong(vlong v, int l2)
292 {
293 	uvlong mask;
294 	mask = (1 << l2) - 1;
295 	return (v + mask) & ~mask;
296 }
297 
298 SmbSlut smbsharemodeslut[] = {
299 	{ "compatibility", SMB_OPEN_MODE_SHARE_COMPATIBILITY },
300 	{ "exclusive", SMB_OPEN_MODE_SHARE_EXCLUSIVE },
301 	{ "denywrite", SMB_OPEN_MODE_SHARE_DENY_WRITE },
302 	{ "denyread", SMB_OPEN_MODE_SHARE_DENY_READOREXEC },
303 	{ "denynone", SMB_OPEN_MODE_SHARE_DENY_NONE },
304 	{ 0 }
305 };
306 
307 SmbSlut smbopenmodeslut[] = {
308 	{ "oread", OREAD },
309 	{ "owrite", OWRITE },
310 	{ "ordwr", ORDWR },
311 	{ "oexec", OEXEC },
312 	{ 0 }
313 };
314 
315 int
smbslut(SmbSlut * s,char * pat)316 smbslut(SmbSlut *s, char *pat)
317 {
318 	while (s->name) {
319 		if (cistrcmp(s->name, pat) == 0)
320 			return s->val;
321 		s++;
322 	}
323 	return -1;
324 }
325 
326 char *
smbrevslut(SmbSlut * s,int val)327 smbrevslut(SmbSlut *s, int val)
328 {
329 	while (s->name) {
330 		if (s->val == val)
331 			return s->name;
332 		s++;
333 	}
334 	return nil;
335 }
336