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