]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libc/9sys/convM2S.c
allow # netpath in dial string
[plan9front.git] / sys / src / libc / 9sys / convM2S.c
1 #include        <u.h>
2 #include        <libc.h>
3 #include        <fcall.h>
4
5 static
6 uchar*
7 gstring(uchar *p, uchar *ep, char **s)
8 {
9         uint n;
10
11         if(p+BIT16SZ > ep)
12                 return nil;
13         n = GBIT16(p);
14         p += BIT16SZ - 1;
15         if(p+n+1 > ep)
16                 return nil;
17         /* move it down, on top of count, to make room for '\0' */
18         memmove(p, p + 1, n);
19         p[n] = '\0';
20         *s = (char*)p;
21         p += n+1;
22         return p;
23 }
24
25 static
26 uchar*
27 gqid(uchar *p, uchar *ep, Qid *q)
28 {
29         if(p+QIDSZ > ep)
30                 return nil;
31         q->type = GBIT8(p);
32         p += BIT8SZ;
33         q->vers = GBIT32(p);
34         p += BIT32SZ;
35         q->path = GBIT64(p);
36         p += BIT64SZ;
37         return p;
38 }
39
40 /*
41  * no syntactic checks.
42  * three causes for error:
43  *  1. message size field is incorrect
44  *  2. input buffer too short for its own data (counts too long, etc.)
45  *  3. too many names or qids
46  * gqid() and gstring() return nil if they would reach beyond buffer.
47  * main switch statement checks range and also can fall through
48  * to test at end of routine.
49  */
50 uint
51 convM2S(uchar *ap, uint nap, Fcall *f)
52 {
53         uchar *p, *ep;
54         uint i, size;
55
56         p = ap;
57         ep = p + nap;
58
59         if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)
60                 return 0;
61         size = GBIT32(p);
62         p += BIT32SZ;
63
64         if(size < BIT32SZ+BIT8SZ+BIT16SZ)
65                 return 0;
66
67         f->type = GBIT8(p);
68         p += BIT8SZ;
69         f->tag = GBIT16(p);
70         p += BIT16SZ;
71
72         switch(f->type)
73         {
74         default:
75                 return 0;
76
77         case Tversion:
78                 if(p+BIT32SZ > ep)
79                         return 0;
80                 f->msize = GBIT32(p);
81                 p += BIT32SZ;
82                 p = gstring(p, ep, &f->version);
83                 break;
84
85         case Tflush:
86                 if(p+BIT16SZ > ep)
87                         return 0;
88                 f->oldtag = GBIT16(p);
89                 p += BIT16SZ;
90                 break;
91
92         case Tauth:
93                 if(p+BIT32SZ > ep)
94                         return 0;
95                 f->afid = GBIT32(p);
96                 p += BIT32SZ;
97                 p = gstring(p, ep, &f->uname);
98                 if(p == nil)
99                         break;
100                 p = gstring(p, ep, &f->aname);
101                 if(p == nil)
102                         break;
103                 break;
104
105         case Tattach:
106                 if(p+BIT32SZ > ep)
107                         return 0;
108                 f->fid = GBIT32(p);
109                 p += BIT32SZ;
110                 if(p+BIT32SZ > ep)
111                         return 0;
112                 f->afid = GBIT32(p);
113                 p += BIT32SZ;
114                 p = gstring(p, ep, &f->uname);
115                 if(p == nil)
116                         break;
117                 p = gstring(p, ep, &f->aname);
118                 if(p == nil)
119                         break;
120                 break;
121
122         case Twalk:
123                 if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
124                         return 0;
125                 f->fid = GBIT32(p);
126                 p += BIT32SZ;
127                 f->newfid = GBIT32(p);
128                 p += BIT32SZ;
129                 f->nwname = GBIT16(p);
130                 p += BIT16SZ;
131                 if(f->nwname > MAXWELEM)
132                         return 0;
133                 for(i=0; i<f->nwname; i++){
134                         p = gstring(p, ep, &f->wname[i]);
135                         if(p == nil)
136                                 break;
137                 }
138                 break;
139
140         case Topen:
141                 if(p+BIT32SZ+BIT8SZ > ep)
142                         return 0;
143                 f->fid = GBIT32(p);
144                 p += BIT32SZ;
145                 f->mode = GBIT8(p);
146                 p += BIT8SZ;
147                 break;
148
149         case Tcreate:
150                 if(p+BIT32SZ > ep)
151                         return 0;
152                 f->fid = GBIT32(p);
153                 p += BIT32SZ;
154                 p = gstring(p, ep, &f->name);
155                 if(p == nil)
156                         break;
157                 if(p+BIT32SZ+BIT8SZ > ep)
158                         return 0;
159                 f->perm = GBIT32(p);
160                 p += BIT32SZ;
161                 f->mode = GBIT8(p);
162                 p += BIT8SZ;
163                 break;
164
165         case Tread:
166                 if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
167                         return 0;
168                 f->fid = GBIT32(p);
169                 p += BIT32SZ;
170                 f->offset = GBIT64(p);
171                 p += BIT64SZ;
172                 f->count = GBIT32(p);
173                 p += BIT32SZ;
174                 break;
175
176         case Twrite:
177                 if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
178                         return 0;
179                 f->fid = GBIT32(p);
180                 p += BIT32SZ;
181                 f->offset = GBIT64(p);
182                 p += BIT64SZ;
183                 f->count = GBIT32(p);
184                 p += BIT32SZ;
185                 if(p+f->count > ep)
186                         return 0;
187                 f->data = (char*)p;
188                 p += f->count;
189                 break;
190
191         case Tclunk:
192         case Tremove:
193                 if(p+BIT32SZ > ep)
194                         return 0;
195                 f->fid = GBIT32(p);
196                 p += BIT32SZ;
197                 break;
198
199         case Tstat:
200                 if(p+BIT32SZ > ep)
201                         return 0;
202                 f->fid = GBIT32(p);
203                 p += BIT32SZ;
204                 break;
205
206         case Twstat:
207                 if(p+BIT32SZ+BIT16SZ > ep)
208                         return 0;
209                 f->fid = GBIT32(p);
210                 p += BIT32SZ;
211                 f->nstat = GBIT16(p);
212                 p += BIT16SZ;
213                 if(p+f->nstat > ep)
214                         return 0;
215                 f->stat = p;
216                 p += f->nstat;
217                 break;
218
219 /*
220  */
221         case Rversion:
222                 if(p+BIT32SZ > ep)
223                         return 0;
224                 f->msize = GBIT32(p);
225                 p += BIT32SZ;
226                 p = gstring(p, ep, &f->version);
227                 break;
228
229         case Rerror:
230                 p = gstring(p, ep, &f->ename);
231                 break;
232
233         case Rflush:
234                 break;
235
236         case Rauth:
237                 p = gqid(p, ep, &f->aqid);
238                 if(p == nil)
239                         break;
240                 break;
241
242         case Rattach:
243                 p = gqid(p, ep, &f->qid);
244                 if(p == nil)
245                         break;
246                 break;
247
248         case Rwalk:
249                 if(p+BIT16SZ > ep)
250                         return 0;
251                 f->nwqid = GBIT16(p);
252                 p += BIT16SZ;
253                 if(f->nwqid > MAXWELEM)
254                         return 0;
255                 for(i=0; i<f->nwqid; i++){
256                         p = gqid(p, ep, &f->wqid[i]);
257                         if(p == nil)
258                                 break;
259                 }
260                 break;
261
262         case Ropen:
263         case Rcreate:
264                 p = gqid(p, ep, &f->qid);
265                 if(p == nil)
266                         break;
267                 if(p+BIT32SZ > ep)
268                         return 0;
269                 f->iounit = GBIT32(p);
270                 p += BIT32SZ;
271                 break;
272
273         case Rread:
274                 if(p+BIT32SZ > ep)
275                         return 0;
276                 f->count = GBIT32(p);
277                 p += BIT32SZ;
278                 if(p+f->count > ep)
279                         return 0;
280                 f->data = (char*)p;
281                 p += f->count;
282                 break;
283
284         case Rwrite:
285                 if(p+BIT32SZ > ep)
286                         return 0;
287                 f->count = GBIT32(p);
288                 p += BIT32SZ;
289                 break;
290
291         case Rclunk:
292         case Rremove:
293                 break;
294
295         case Rstat:
296                 if(p+BIT16SZ > ep)
297                         return 0;
298                 f->nstat = GBIT16(p);
299                 p += BIT16SZ;
300                 if(p+f->nstat > ep)
301                         return 0;
302                 f->stat = p;
303                 p += f->nstat;
304                 break;
305
306         case Rwstat:
307                 break;
308         }
309
310         if(p==nil || p>ep)
311                 return 0;
312         if(ap+size == p)
313                 return size;
314         return 0;
315 }