xref: /dragonfly/contrib/smbfs/lib/smb/rap.c (revision 402014d6a31eefa5b6ea0e29b86df7fc0b63c690)
1 /*
2  * Copyright (c) 2000, Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *    This product includes software developed by Boris Popov.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: rap.c,v 1.8 2001/02/24 15:56:05 bp Exp $
33  *
34  * This is very simple implementation of RAP protocol.
35  */
36 #include <sys/param.h>
37 #include <sys/errno.h>
38 #include <sys/stat.h>
39 #include <ctype.h>
40 #include <err.h>
41 #include <stdio.h>
42 #include <unistd.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <sysexits.h>
46 
47 #include <sys/endian.h>
48 
49 #include <netsmb/smb_lib.h>
50 #include <netsmb/smb_conn.h>
51 #include <netsmb/smb_rap.h>
52 
53 /*#include <sys/ioctl.h>*/
54 
55 static int
smb_rap_parserqparam(const char * s,char ** next,int * rlen)56 smb_rap_parserqparam(const char *s, char **next, int *rlen)
57 {
58           char *np;
59           int len, m;
60 
61           m = 1;
62           switch (*s++) {
63               case 'L':
64               case 'T':
65               case 'W':
66                     len = 2;
67                     break;
68               case 'D':
69               case 'O':
70                     len = 4;
71                     break;
72               case 'b':
73               case 'F':
74                     len = 1;
75                     break;
76               case 'r':
77               case 's':
78                     len = 0;
79                     break;
80               default:
81                     return EINVAL;
82           }
83           if (isdigit(*s)) {
84                     len *= strtoul(s, &np, 10);
85                     s = np;
86           }
87           *rlen = len;
88           *(const char**)next = s;
89           return 0;
90 }
91 
92 static int
smb_rap_parserpparam(const char * s,char ** next,int * rlen)93 smb_rap_parserpparam(const char *s, char **next, int *rlen)
94 {
95           char *np;
96           int len, m;
97 
98           m = 1;
99           switch (*s++) {
100               case 'e':
101               case 'h':
102                     len = 2;
103                     break;
104               case 'i':
105                     len = 4;
106                     break;
107               case 'g':
108                     len = 1;
109                     break;
110               default:
111                     return EINVAL;
112           }
113           if (isdigit(*s)) {
114                     len *= strtoul(s, &np, 10);
115                     s = np;
116           }
117           *rlen = len;
118           *(const char**)next = s;
119           return 0;
120 }
121 
122 static int
smb_rap_parserpdata(const char * s,char ** next,int * rlen)123 smb_rap_parserpdata(const char *s, char **next, int *rlen)
124 {
125           char *np;
126           int len, m;
127 
128           m = 1;
129           switch (*s++) {
130               case 'B':
131                     len = 1;
132                     break;
133               case 'W':
134                     len = 2;
135                     break;
136               case 'D':
137               case 'O':
138               case 'z':
139                     len = 4;
140                     break;
141               default:
142                     return EINVAL;
143           }
144           if (isdigit(*s)) {
145                     len *= strtoul(s, &np, 10);
146                     s = np;
147           }
148           *rlen = len;
149           *(const char**)next = s;
150           return 0;
151 }
152 
153 static int
smb_rap_rqparam_z(struct smb_rap * rap,const char * value)154 smb_rap_rqparam_z(struct smb_rap *rap, const char *value)
155 {
156           int len = strlen(value) + 1;
157 
158           bcopy(value, rap->r_npbuf, len);
159           rap->r_npbuf += len;
160           rap->r_plen += len;
161           return 0;
162 }
163 
164 static int
smb_rap_rqparam(struct smb_rap * rap,char ptype,char plen,long value)165 smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, long value)
166 {
167           char *p = rap->r_npbuf;
168           int len;
169 
170           switch (ptype) {
171               case 'L':
172               case 'W':
173                     setwle(p, 0, value);
174                     len = 2;
175                     break;
176               case 'D':
177                     setdle(p, 0, value);
178                     len = 4;
179                     break;
180               case 'b':
181                     memset(p, value, plen);
182                     len = plen;
183               default:
184                     return EINVAL;
185           }
186           rap->r_npbuf += len;
187           rap->r_plen += len;
188           return 0;
189 }
190 
191 int
smb_rap_create(int fn,const char * param,const char * data,struct smb_rap ** rapp)192 smb_rap_create(int fn, const char *param, const char *data,
193           struct smb_rap **rapp)
194 {
195           struct smb_rap *rap;
196           char *p;
197           int plen, len;
198 
199           rap = malloc(sizeof(*rap));
200           if (rap == NULL)
201                     return ENOMEM;
202           bzero(rap, sizeof(*rap));
203           p = rap->r_sparam = rap->r_nparam = strdup(param);
204           rap->r_sdata = rap->r_ndata = strdup(data);
205           /*
206            * Calculate length of request parameter block
207            */
208           len = 2 + strlen(param) + 1 + strlen(data) + 1;
209 
210           while (*p) {
211                     if (smb_rap_parserqparam(p, &p, &plen) != 0)
212                               break;
213                     len += plen;
214           }
215           rap->r_pbuf = rap->r_npbuf = malloc(len);
216           smb_rap_rqparam(rap, 'W', 1, fn);
217           smb_rap_rqparam_z(rap, rap->r_sparam);
218           smb_rap_rqparam_z(rap, rap->r_sdata);
219           *rapp = rap;
220           return 0;
221 }
222 
223 void
smb_rap_done(struct smb_rap * rap)224 smb_rap_done(struct smb_rap *rap)
225 {
226           if (rap->r_sparam)
227                     free(rap->r_sparam);
228           if (rap->r_sdata)
229                     free(rap->r_sdata);
230           free(rap);
231 }
232 
233 int
smb_rap_setNparam(struct smb_rap * rap,long value)234 smb_rap_setNparam(struct smb_rap *rap, long value)
235 {
236           char *p = rap->r_nparam;
237           char ptype = *p;
238           int error, plen;
239 
240           error = smb_rap_parserqparam(p, &p, &plen);
241           if (error)
242                     return error;
243           switch (ptype) {
244               case 'L':
245                     rap->r_rcvbuflen = value;
246                     /* FALLTHROUGH */
247               case 'W':
248               case 'D':
249               case 'b':
250                     error = smb_rap_rqparam(rap, ptype, plen, value);
251                     break;
252               default:
253                     return EINVAL;
254           }
255           rap->r_nparam = p;
256           return 0;
257 }
258 
259 int
smb_rap_setPparam(struct smb_rap * rap,void * value)260 smb_rap_setPparam(struct smb_rap *rap, void *value)
261 {
262           char *p = rap->r_nparam;
263           char ptype = *p;
264           int error, plen;
265 
266           error = smb_rap_parserqparam(p, &p, &plen);
267           if (error)
268                     return error;
269           switch (ptype) {
270               case 'r':
271                     rap->r_rcvbuf = value;
272                     break;
273               default:
274                     return EINVAL;
275           }
276           rap->r_nparam = p;
277           return 0;
278 }
279 
280 static int
smb_rap_getNparam(struct smb_rap * rap,long * value)281 smb_rap_getNparam(struct smb_rap *rap, long *value)
282 {
283           char *p = rap->r_nparam;
284           char ptype = *p;
285           int error, plen;
286 
287           error = smb_rap_parserpparam(p, &p, &plen);
288           if (error)
289                     return error;
290           switch (ptype) {
291               case 'h':
292                     *value = le16toh(*(u_int16_t*)rap->r_npbuf);
293                     break;
294               default:
295                     return EINVAL;
296           }
297           rap->r_npbuf += plen;
298           rap->r_nparam = p;
299           return 0;
300 }
301 
302 int
smb_rap_request(struct smb_rap * rap,struct smb_ctx * ctx)303 smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
304 {
305           u_int16_t *rp, conv;
306           u_int32_t *p32;
307           char *dp, *p = rap->r_nparam;
308           char ptype;
309           int error, rdatacnt, rparamcnt, entries, done, dlen;
310 
311           rdatacnt = rap->r_rcvbuflen;
312           rparamcnt = rap->r_plen;
313           error = smb_t2_request(ctx, 0, 0, "\\PIPE\\LANMAN",
314               rap->r_plen, rap->r_pbuf,           /* int tparamcnt, void *tparam */
315               0, NULL,                                      /* int tdatacnt, void *tdata */
316               &rparamcnt, rap->r_pbuf,            /* rparamcnt, void *rparam */
317               &rdatacnt, rap->r_rcvbuf            /* int *rdatacnt, void *rdata */
318           );
319           if (error)
320                     return error;
321           rp = (u_int16_t*)rap->r_pbuf;
322           rap->r_result = le16toh(*rp++);
323           conv = le16toh(*rp++);
324           rap->r_npbuf = (char*)rp;
325           rap->r_entries = entries = 0;
326           done = 0;
327           while (!done && *p) {
328                     ptype = *p;
329                     switch (ptype) {
330                         case 'e':
331                               rap->r_entries = entries = le16toh(*(u_int16_t*)rap->r_npbuf);
332                               rap->r_npbuf += 2;
333                               p++;
334                               break;
335                         default:
336                               done = 1;
337                     }
338 /*                  error = smb_rap_parserpparam(p, &p, &plen);
339                     if (error) {
340                               smb_error("reply parameter mismath %s", 0, p);
341                               return EBADRPC;
342                     }*/
343           }
344           rap->r_nparam = p;
345           /*
346            * In general, unpacking entries we may need to relocate
347            * entries for proper alingning. For now use them as is.
348            */
349           dp = rap->r_rcvbuf;
350           while (entries--) {
351                     p = rap->r_sdata;
352                     while (*p) {
353                               ptype = *p;
354                               error = smb_rap_parserpdata(p, &p, &dlen);
355                               if (error) {
356                                         smb_error("reply data mismath %s", 0, p);
357                                         return EBADRPC;
358                               }
359                               switch (ptype) {
360                                   case 'z':
361                                         p32 = (u_int32_t*)dp;
362                                         *p32 = (*p32 & 0xffff) - conv;
363                                         break;
364                               }
365                               dp += dlen;
366                     }
367           }
368           return error;
369 }
370 
371 int
smb_rap_error(struct smb_rap * rap,int error)372 smb_rap_error(struct smb_rap *rap, int error)
373 {
374           if (error)
375                     return error;
376           if (rap->r_result == 0)
377                     return 0;
378           return rap->r_result | SMB_RAP_ERROR;
379 }
380 
381 int
smb_rap_NetShareEnum(struct smb_ctx * ctx,int sLevel,void * pbBuffer,int cbBuffer,int * pcEntriesRead,int * pcTotalAvail)382 smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer,
383           int cbBuffer, int *pcEntriesRead, int *pcTotalAvail)
384 {
385           struct smb_rap *rap;
386           long lval;
387           int error;
388 
389           error = smb_rap_create(0, "WrLeh", "B13BWz", &rap);
390           if (error)
391                     return error;
392           smb_rap_setNparam(rap, sLevel);                   /* W - sLevel */
393           smb_rap_setPparam(rap, pbBuffer);       /* r - pbBuffer */
394           smb_rap_setNparam(rap, cbBuffer);       /* L - cbBuffer */
395           error = smb_rap_request(rap, ctx);
396           if (error == 0) {
397                     *pcEntriesRead = rap->r_entries;
398                     error = smb_rap_getNparam(rap, &lval);
399                     *pcTotalAvail = lval;
400           }
401           error = smb_rap_error(rap, error);
402           smb_rap_done(rap);
403           return error;
404 }
405