~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201207201942

« back to all changes in this revision

Viewing changes to modules/solaris/vmhgfs/rpcout.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2009-03-20 10:19:00 UTC
  • mfrom: (1.1.4 upstream) (2.4.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090320101900-1o604camiubq2de8
Tags: 2009.03.18-154848-2
Correcting patch system depends (Closes: #520493).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*********************************************************
 
2
 * Copyright (C) 2004 VMware, Inc. All rights reserved.
 
3
 *
 
4
 * The contents of this file are subject to the terms of the Common
 
5
 * Development and Distribution License (the "License") version 1.0
 
6
 * and no later version.  You may not use this file except in
 
7
 * compliance with the License.
 
8
 *
 
9
 * You can obtain a copy of the License at
 
10
 *         http://www.opensource.org/licenses/cddl1.php
 
11
 *
 
12
 * See the License for the specific language governing permissions
 
13
 * and limitations under the License.
 
14
 *
 
15
 *********************************************************/
 
16
 
 
17
/*
 
18
 * rpcout.c --
 
19
 *
 
20
 *    Remote Procedure Call between VMware and guest applications
 
21
 *    C implementation.
 
22
 *
 
23
 *    This module contains implements the out (guest=>host) direction only.
 
24
 *    The in and out modules are separate since some applications (e.g.
 
25
 *    drivers that want to do RPC-based logging) only want/need/can have the
 
26
 *    out direction.
 
27
 */
 
28
 
 
29
 
 
30
#if defined(__KERNEL__) || defined(_KERNEL) || defined(KERNEL)
 
31
#   include "kernelStubs.h"
 
32
#else
 
33
#   include <stdio.h>
 
34
#   include <string.h>
 
35
#   include <stdlib.h>
 
36
#   include <stdarg.h>
 
37
#   include "str.h"
 
38
#   include "debug.h"
 
39
#endif
 
40
 
 
41
#include "vmware.h"
 
42
#include "rpcout.h"
 
43
#include "message.h"
 
44
 
 
45
 
 
46
/*
 
47
 * The RpcOut object
 
48
 */
 
49
 
 
50
struct RpcOut {
 
51
   Message_Channel *channel;
 
52
};
 
53
 
 
54
 
 
55
/*
 
56
 *-----------------------------------------------------------------------------
 
57
 *
 
58
 * RpcOut_Construct --
 
59
 *
 
60
 *      Constructor for the RpcOut object
 
61
 *
 
62
 * Results:
 
63
 *      New RpcOut object.
 
64
 *
 
65
 * Side effects:
 
66
 *      Allocates memory.
 
67
 *
 
68
 *-----------------------------------------------------------------------------
 
69
 */
 
70
 
 
71
RpcOut *
 
72
RpcOut_Construct(void)
 
73
{
 
74
   return (RpcOut *)calloc(1, sizeof(RpcOut));
 
75
}
 
76
 
 
77
 
 
78
/*
 
79
 *-----------------------------------------------------------------------------
 
80
 *
 
81
 * RpcOut_Destruct --
 
82
 *
 
83
 *      Destructor for the RpcOut object.
 
84
 *
 
85
 * Results:
 
86
 *      None.
 
87
 *
 
88
 * Side effects:
 
89
 *      Frees RpcOut object memory.
 
90
 *
 
91
 *-----------------------------------------------------------------------------
 
92
 */
 
93
 
 
94
void
 
95
RpcOut_Destruct(RpcOut *out) // IN
 
96
{
 
97
   ASSERT(out);
 
98
   ASSERT(out->channel == NULL);
 
99
 
 
100
   free(out);
 
101
}
 
102
 
 
103
 
 
104
/*
 
105
 *-----------------------------------------------------------------------------
 
106
 *
 
107
 * RpcOut_start --
 
108
 *
 
109
 *      Open the channel
 
110
 *
 
111
 * Result:
 
112
 *      TRUE on success
 
113
 *      FALSE on failure
 
114
 *
 
115
 * Side-effects:
 
116
 *      None
 
117
 *
 
118
 *-----------------------------------------------------------------------------
 
119
 */
 
120
 
 
121
Bool
 
122
RpcOut_start(RpcOut *out) // IN
 
123
{
 
124
   ASSERT(out);
 
125
   ASSERT(out->channel == NULL);
 
126
   out->channel = Message_Open(RPCI_PROTOCOL_NUM);
 
127
   if (out->channel == NULL) {
 
128
      Debug("RpcOut: couldn't open channel with RPCI protocol\n");
 
129
      return FALSE;
 
130
   }
 
131
 
 
132
   return TRUE;
 
133
}
 
134
 
 
135
 
 
136
/*
 
137
 *-----------------------------------------------------------------------------
 
138
 *
 
139
 * RpcOut_send --
 
140
 *
 
141
 *    Make VMware synchroneously execute a TCLO command
 
142
 *
 
143
 *    Unlike the other send varieties, RpcOut_send requires that the
 
144
 *    caller pass non-NULL reply and repLen arguments.
 
145
 *
 
146
 * Result
 
147
 *    TRUE on success. 'reply' contains the result of the rpc
 
148
 *    FALSE on error. 'reply' will contain a description of the error
 
149
 *
 
150
 *    In both cases, the caller should not free the reply.
 
151
 *
 
152
 * Side-effects
 
153
 *    None
 
154
 *
 
155
 *-----------------------------------------------------------------------------
 
156
 */
 
157
 
 
158
Bool
 
159
RpcOut_send(RpcOut *out,         // IN
 
160
            char const *request, // IN
 
161
            size_t reqLen,       // IN
 
162
            char const **reply,  // OUT
 
163
            size_t *repLen)      // OUT
 
164
{
 
165
   unsigned char *myReply;
 
166
   size_t myRepLen;
 
167
   Bool success;
 
168
 
 
169
   ASSERT(out);
 
170
 
 
171
   ASSERT(out->channel);
 
172
   if (Message_Send(out->channel, (const unsigned char *)request, reqLen) == FALSE) {
 
173
      *reply = "RpcOut: Unable to send the RPCI command";
 
174
      *repLen = strlen(*reply);
 
175
 
 
176
      return FALSE;
 
177
   }
 
178
 
 
179
   if (Message_Receive(out->channel, &myReply, &myRepLen) == FALSE) {
 
180
      *reply = "RpcOut: Unable to receive the result of the RPCI command";
 
181
      *repLen = strlen(*reply);
 
182
 
 
183
      return FALSE;
 
184
   }
 
185
 
 
186
   if (myRepLen < 2
 
187
       || (   (success = strncmp((const char *)myReply, "1 ", 2) == 0) == FALSE
 
188
              && strncmp((const char *)myReply, "0 ", 2))) {
 
189
      *reply = "RpcOut: Invalid format for the result of the RPCI command";
 
190
      *repLen = strlen(*reply);
 
191
 
 
192
      return FALSE;
 
193
   }
 
194
 
 
195
   *reply = ((const char *)myReply) + 2;
 
196
   *repLen = myRepLen - 2;
 
197
 
 
198
   return success;
 
199
}
 
200
 
 
201
 
 
202
/*
 
203
 *-----------------------------------------------------------------------------
 
204
 *
 
205
 * RpcOut_stop --
 
206
 *
 
207
 *    Close the channel
 
208
 *
 
209
 * Result
 
210
 *    TRUE on success
 
211
 *    FALSE on failure
 
212
 *
 
213
 * Side-effects
 
214
 *    Frees the result of the last command.
 
215
 *
 
216
 *-----------------------------------------------------------------------------
 
217
 */
 
218
 
 
219
Bool
 
220
RpcOut_stop(RpcOut *out) // IN
 
221
{
 
222
   Bool status;
 
223
 
 
224
   ASSERT(out);
 
225
 
 
226
   status = TRUE;
 
227
 
 
228
   if (out->channel) {
 
229
      /* Try to close the channel */
 
230
      if (Message_Close(out->channel) == FALSE) {
 
231
         Debug("RpcOut: couldn't close channel\n");
 
232
         status = FALSE;
 
233
      }
 
234
 
 
235
      out->channel = NULL;
 
236
   }
 
237
 
 
238
   return status;
 
239
}
 
240
 
 
241
 
 
242
/*
 
243
 *-----------------------------------------------------------------------------
 
244
 *
 
245
 * RpcOut_sendOne --
 
246
 *
 
247
 *    Make VMware execute a RPCI command
 
248
 *
 
249
 *    VMware closes a channel when it detects that there has been no activity
 
250
 *    on it for a while. Because we do not know how often this program will
 
251
 *    make VMware execute a RPCI, we open/close one channel per RPCI command
 
252
 *
 
253
 * Return value:
 
254
 *    TRUE on success. '*reply' contains an allocated result of the rpc
 
255
 *    FALSE on error. '*reply' contains an allocated description of the error 
 
256
 *                    or NULL.
 
257
 *
 
258
 * Side effects:
 
259
 *    None
 
260
 *
 
261
 *-----------------------------------------------------------------------------
 
262
 */
 
263
 
 
264
Bool
 
265
RpcOut_sendOne(char **reply,        // OUT: Result
 
266
               size_t *repLen,      // OUT: Length of the result
 
267
               char const *reqFmt,  // IN: RPCI command
 
268
               ...)                 // Unspecified
 
269
{
 
270
   va_list args;
 
271
   Bool status;
 
272
   char *request;
 
273
   size_t reqLen = 0;
 
274
 
 
275
   status = FALSE;
 
276
 
 
277
   /* Format the request string */
 
278
   va_start(args, reqFmt);
 
279
   request = Str_Vasprintf(&reqLen, reqFmt, args);
 
280
   va_end(args);
 
281
 
 
282
   /* 
 
283
    * If Str_Vasprintf failed, write NULL into the reply if the caller wanted
 
284
    * a reply back.
 
285
    */
 
286
   if (request == NULL) {
 
287
      if (reply) {
 
288
         *reply = NULL;
 
289
      }
 
290
      return FALSE;
 
291
   }
 
292
 
 
293
   /*
 
294
    * If the command doesn't contain a space, add one to the end to maintain
 
295
    * compatibility with old VMXs.
 
296
    *
 
297
    * For a long time, the GuestRpc logic in the VMX was wired to expect a
 
298
    * trailing space in every command, even commands without arguments. That is
 
299
    * no longer true, but we must continue to add a trailing space because we
 
300
    * don't know whether we're talking to an old or new VMX.
 
301
    */
 
302
   if (strchr(request, ' ') == NULL) {
 
303
      char *tmp;
 
304
 
 
305
      tmp = Str_Asprintf(NULL, "%s ", request);
 
306
      free(request);
 
307
      request = tmp;
 
308
 
 
309
      /* 
 
310
       * If Str_Asprintf failed, write NULL into reply if the caller wanted 
 
311
       * a reply back. 
 
312
       */
 
313
      if (request == NULL) {
 
314
         if (reply != NULL) {
 
315
            *reply = NULL;
 
316
         }
 
317
         return FALSE;
 
318
      }
 
319
   }
 
320
 
 
321
   status = RpcOut_SendOneRaw(request, reqLen, reply, repLen);
 
322
 
 
323
   free(request);
 
324
 
 
325
   return status;
 
326
}
 
327
 
 
328
 
 
329
/*
 
330
 *-----------------------------------------------------------------------------
 
331
 *
 
332
 * RpcOut_SendOneRaw --
 
333
 *
 
334
 *    Make VMware execute a RPCI command
 
335
 *
 
336
 *    VMware closes a channel when it detects that there has been no activity
 
337
 *    on it for a while. Because we do not know how often this program will
 
338
 *    make VMware execute a RPCI, we open/close one channel per RPCI command.
 
339
 *
 
340
 *    This function sends a message over the backdoor without using
 
341
 *    any of the Str_ functions on the request buffer; Str_Asprintf() in
 
342
 *    particular uses FormatMessage on Win32, which corrupts some UTF-8
 
343
 *    strings. Using this function directly instead of using RpcOut_SendOne()
 
344
 *    avoids these problems.
 
345
 *
 
346
 *    If this is not an issue, you can use RpcOut_sendOne(), which has
 
347
 *    varargs.
 
348
 *
 
349
 *    Note: It is the caller's responsibility to ensure that the RPCI command
 
350
 *          followed by a space appear at the start of the request buffer. See
 
351
 *          the command in RpcOut_sendOne for details.
 
352
 *
 
353
 * Return value:
 
354
 *    TRUE on success. '*reply' contains an allocated result of the rpc
 
355
 *    FALSE on error. '*reply' contains an allocated description of the 
 
356
 *                    error or NULL.
 
357
 *                    
 
358
 *
 
359
 * Side effects:
 
360
 *    None
 
361
 *
 
362
 *-----------------------------------------------------------------------------
 
363
 */
 
364
 
 
365
Bool
 
366
RpcOut_SendOneRaw(void *request,       // IN: RPCI command
 
367
                  size_t reqLen,       // IN: Size of request buffer
 
368
                  char **reply,        // OUT: Result
 
369
                  size_t *repLen)      // OUT: Length of the result
 
370
{
 
371
   Bool status;
 
372
   RpcOut *out = NULL;
 
373
   char const *myReply;
 
374
   size_t myRepLen;
 
375
 
 
376
   status = FALSE;
 
377
 
 
378
   Debug("Rpci: Sending request='%s'\n", (char *)request);
 
379
   out = RpcOut_Construct();
 
380
   if (out == NULL) {
 
381
      myReply = "RpcOut: Unable to create the RpcOut object";
 
382
      myRepLen = strlen(myReply);
 
383
 
 
384
      goto sent;
 
385
   } else if (RpcOut_start(out) == FALSE) {
 
386
      myReply = "RpcOut: Unable to open the communication channel";
 
387
      myRepLen = strlen(myReply);
 
388
 
 
389
      goto sent;
 
390
   } else if (RpcOut_send(out, request, reqLen, &myReply, &myRepLen)
 
391
              == FALSE) {
 
392
      /* We already have the description of the error */
 
393
      goto sent;
 
394
   }
 
395
 
 
396
   status = TRUE;
 
397
 
 
398
sent:
 
399
   Debug("Rpci: Sent request='%s', reply='%s', len=%"FMTSZ"u, status=%d\n",
 
400
         (char *)request, myReply, myRepLen, status);
 
401
 
 
402
   if (reply != NULL) {
 
403
      /* 
 
404
       * If we got a non-NULL reply, make a copy of it, because the reply
 
405
       * we got back is inside the channel buffer, which will get destroyed
 
406
       * at the end of this function.
 
407
       */
 
408
      if (myReply != NULL) {
 
409
         /*
 
410
          * We previously used strdup to duplicate myReply, but that
 
411
          * breaks if you are sending binary (not string) data over the
 
412
          * backdoor. Don't assume the data is a string.
 
413
          *
 
414
          * myRepLen is strlen(myReply), so we need an extra byte to
 
415
          * cover the NUL terminator.
 
416
          */
 
417
         *reply = malloc(myRepLen + 1);
 
418
         if (*reply != NULL) {
 
419
            memcpy(*reply, myReply, myRepLen);
 
420
            /*
 
421
             * The message layer already writes a trailing NUL but we might
 
422
             * change that someday, so do it again here.
 
423
             */
 
424
            (*reply)[myRepLen] = 0;
 
425
         }
 
426
      } else {
 
427
         /* 
 
428
          * Our reply was NULL, so just pass the NULL back up to the caller.
 
429
          */ 
 
430
         *reply = NULL;
 
431
      }
 
432
      
 
433
      /* 
 
434
       * Only set the length if the caller wanted it and if we got a good 
 
435
       * reply. 
 
436
       */
 
437
      if (repLen != NULL && *reply != NULL) {
 
438
         *repLen = myRepLen;
 
439
      }
 
440
   }
 
441
 
 
442
   if (out) {
 
443
      if (RpcOut_stop(out) == FALSE) {
 
444
         /* 
 
445
          * We couldn't stop the channel. Free anything we allocated, give our
 
446
          * client a reply of NULL, and return FALSE.
 
447
          */
 
448
 
 
449
         if (reply != NULL) {
 
450
            free(*reply);
 
451
            *reply = NULL;
 
452
         }
 
453
         Debug("Rpci: unable to close the communication channel\n");
 
454
         status = FALSE;
 
455
      }
 
456
 
 
457
      RpcOut_Destruct(out);
 
458
      out = NULL;
 
459
   }
 
460
 
 
461
   return status;
 
462
}
 
463
 
 
464