~ubuntu-branches/ubuntu/oneiric/icedtea-web/oneiric-updates

« back to all changes in this revision

Viewing changes to .pc/icedtea-web-CVE-2012-3423.patch/plugin/icedteanp/IcedTeaPluginUtils.cc

  • Committer: Package Import Robot
  • Author(s): Steve Beattie
  • Date: 2012-07-28 18:58:28 UTC
  • Revision ID: package-import@ubuntu.com-20120728185828-ovspn1hzsz1ezu76
Tags: 1.2-2ubuntu0.11.10.2
* SECURITY UPDATE: uninitialized pointer use flaw
  - debian/patches/icedtea-web-CVE-2012-3422.patch: check for empty
    instance_to_id_map hash and return error if so.
  - CVE-2012-3422
* SECURITY UPDATE: incorrect handling of non NULL terminated strings
  - debian/patches/icedtea-web-CVE-2012-3423.patch: ensure NPVariant
    NPStrings are NULL terminated.
  - CVE-2012-3423

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* IcedTeaPluginUtils.cc
 
2
 
 
3
   Copyright (C) 2009, 2010  Red Hat
 
4
 
 
5
This file is part of IcedTea.
 
6
 
 
7
IcedTea is free software; you can redistribute it and/or modify
 
8
it under the terms of the GNU General Public License as published by
 
9
the Free Software Foundation; either version 2, or (at your option)
 
10
any later version.
 
11
 
 
12
IcedTea is distributed in the hope that it will be useful, but
 
13
WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
General Public License for more details.
 
16
 
 
17
You should have received a copy of the GNU General Public License
 
18
along with IcedTea; see the file COPYING.  If not, write to the
 
19
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
20
02110-1301 USA.
 
21
 
 
22
Linking this library statically or dynamically with other modules is
 
23
making a combined work based on this library.  Thus, the terms and
 
24
conditions of the GNU General Public License cover the whole
 
25
combination.
 
26
 
 
27
As a special exception, the copyright holders of this library give you
 
28
permission to link this library with independent modules to produce an
 
29
executable, regardless of the license terms of these independent
 
30
modules, and to copy and distribute the resulting executable under
 
31
terms of your choice, provided that you also meet, for each linked
 
32
independent module, the terms and conditions of the license of that
 
33
module.  An independent module is a module which is not derived from
 
34
or based on this library.  If you modify this library, you may extend
 
35
this exception to your version of the library, but you are not
 
36
obligated to do so.  If you do not wish to do so, delete this
 
37
exception statement from your version. */
 
38
 
 
39
#include "IcedTeaNPPlugin.h"
 
40
#include "IcedTeaScriptablePluginObject.h"
 
41
#include "IcedTeaPluginUtils.h"
 
42
 
 
43
/**
 
44
 * Misc. utility functions used by the plugin
 
45
 */
 
46
 
 
47
/***********************************************
 
48
 * Begin IcedTeaPluginUtilities implementation *
 
49
************************************************/
 
50
 
 
51
// Initialize static variables
 
52
int IcedTeaPluginUtilities::reference = -1;
 
53
pthread_mutex_t IcedTeaPluginUtilities::reference_mutex = PTHREAD_MUTEX_INITIALIZER;
 
54
std::map<void*, NPP>* IcedTeaPluginUtilities::instance_map = new std::map<void*, NPP>();
 
55
std::map<std::string, NPObject*>* IcedTeaPluginUtilities::object_map = new std::map<std::string, NPObject*>();
 
56
 
 
57
/* Plugin async call queue */
 
58
static std::vector< PluginThreadCall* >* pendingPluginThreadRequests = new std::vector< PluginThreadCall* >();
 
59
 
 
60
/**
 
61
 * Given a context number, constructs a message prefix to send to Java
 
62
 *
 
63
 * @param context The context of the request
 
64
 * @return The string prefix (allocated on heap)
 
65
 */
 
66
 
 
67
void
 
68
IcedTeaPluginUtilities::constructMessagePrefix(int context, std::string *result)
 
69
{
 
70
        std::string context_str = std::string();
 
71
 
 
72
        itoa(context, &context_str);
 
73
 
 
74
        result->append("context ");
 
75
        result->append(context_str);
 
76
        result->append(" reference -1");
 
77
 
 
78
}
 
79
 
 
80
/**
 
81
 * Given a context number, and reference number, constructs a message prefix to
 
82
 * send to Java
 
83
 *
 
84
 * @param context The context of the request
 
85
 * @param rerefence The reference number of the request
 
86
 * @param result The message
 
87
 */
 
88
 
 
89
void
 
90
IcedTeaPluginUtilities::constructMessagePrefix(int context, int reference, std::string* result)
 
91
{
 
92
    // Until security is implemented, use file:// source for _everything_
 
93
 
 
94
        std::string context_str = std::string();
 
95
        std::string reference_str = std::string();
 
96
 
 
97
        itoa(context, &context_str);
 
98
        itoa(reference, &reference_str);
 
99
 
 
100
        *result += "context ";
 
101
        result->append(context_str);
 
102
        *result += " reference ";
 
103
        result->append(reference_str);
 
104
}
 
105
 
 
106
/**
 
107
 * Given a context number, reference number, and source location, constructs
 
108
 * a message prefix to send to Java
 
109
 *
 
110
 * @param context The context of the request
 
111
 * @param rerefence The reference number of the request
 
112
 * @param address The address for the script that made the request
 
113
 * @param result The message
 
114
 */
 
115
 
 
116
void
 
117
IcedTeaPluginUtilities::constructMessagePrefix(int context, int reference,
 
118
                                                       std::string address,
 
119
                                                       std::string* result)
 
120
{
 
121
        std::string context_str = std::string();
 
122
        std::string reference_str = std::string();
 
123
 
 
124
        itoa(context, &context_str);
 
125
        itoa(reference, &reference_str);
 
126
 
 
127
        *result += "context ";
 
128
        result->append(context_str);
 
129
        *result += " reference ";
 
130
        result->append(reference_str);
 
131
 
 
132
        if (address.length() > 0)
 
133
        {
 
134
            *result += " src ";
 
135
        result->append(address);
 
136
        }
 
137
}
 
138
 
 
139
/**
 
140
 * Returns a string representation of a void pointer
 
141
 *
 
142
 * @param id The pointer
 
143
 * @param result The string representation
 
144
 */
 
145
 
 
146
void
 
147
IcedTeaPluginUtilities::JSIDToString(void* id, std::string* result)
 
148
{
 
149
 
 
150
        char* id_str = (char*) malloc(sizeof(char)*20); // max = long long = 8446744073709551615 == 19 chars
 
151
 
 
152
        if (sizeof(void*) == sizeof(long long))
 
153
        {
 
154
                sprintf(id_str, "%llu", id);
 
155
        }
 
156
        else
 
157
        {
 
158
                sprintf(id_str, "%lu", id); // else use long
 
159
        }
 
160
 
 
161
        result->append(id_str);
 
162
 
 
163
        PLUGIN_DEBUG("Converting pointer %p to %s\n", id, id_str);
 
164
        free(id_str);
 
165
}
 
166
 
 
167
/**
 
168
 * Returns a void pointer from a string representation
 
169
 *
 
170
 * @param id_str The string representation
 
171
 * @return The pointer
 
172
 */
 
173
 
 
174
void*
 
175
IcedTeaPluginUtilities::stringToJSID(std::string id_str)
 
176
{
 
177
        void* ptr;
 
178
        if (sizeof(void*) == sizeof(long long))
 
179
        {
 
180
                PLUGIN_DEBUG("Casting (long long) \"%s\" -- %llu\n", id_str.c_str(), strtoull(id_str.c_str(), NULL, 0));
 
181
                ptr = reinterpret_cast <void*> ((unsigned long long) strtoull(id_str.c_str(), NULL, 0));
 
182
        } else
 
183
        {
 
184
                PLUGIN_DEBUG("Casting (long) \"%s\" -- %lu\n", id_str.c_str(), strtoul(id_str.c_str(), NULL, 0));
 
185
                ptr = reinterpret_cast <void*> ((unsigned long)  strtoul(id_str.c_str(), NULL, 0));
 
186
        }
 
187
 
 
188
        PLUGIN_DEBUG("Casted: %p\n", ptr);
 
189
 
 
190
        return ptr;
 
191
}
 
192
 
 
193
/**
 
194
 * Returns a void pointer from a string representation
 
195
 *
 
196
 * @param id_str The pointer to the string representation
 
197
 * @return The pointer
 
198
 */
 
199
 
 
200
void*
 
201
IcedTeaPluginUtilities::stringToJSID(std::string* id_str)
 
202
{
 
203
    void* ptr;
 
204
    if (sizeof(void*) == sizeof(long long))
 
205
    {
 
206
        PLUGIN_DEBUG("Casting (long long) \"%s\" -- %llu\n", id_str->c_str(), strtoull(id_str->c_str(), NULL, 0));
 
207
        ptr = reinterpret_cast <void*> ((unsigned long long) strtoull(id_str->c_str(), NULL, 0));
 
208
    } else
 
209
    {
 
210
        PLUGIN_DEBUG("Casting (long) \"%s\" -- %lu\n", id_str->c_str(), strtoul(id_str->c_str(), NULL, 0));
 
211
        ptr = reinterpret_cast <void*> ((unsigned long)  strtoul(id_str->c_str(), NULL, 0));
 
212
    }
 
213
 
 
214
    PLUGIN_DEBUG("Casted: %p\n", ptr);
 
215
 
 
216
    return ptr;
 
217
}
 
218
 
 
219
/**
 
220
 * Increments the global reference number and returns it.
 
221
 *
 
222
 * This function is thread-safe.
 
223
 */
 
224
int
 
225
IcedTeaPluginUtilities::getReference()
 
226
{
 
227
        pthread_mutex_lock(&reference_mutex);
 
228
 
 
229
        // If we are nearing the max, reset
 
230
        if (reference < -0x7FFFFFFF + 10) {
 
231
            reference = -1;
 
232
        }
 
233
 
 
234
        reference--;
 
235
        pthread_mutex_unlock(&reference_mutex);
 
236
 
 
237
        return reference;
 
238
}
 
239
 
 
240
/**
 
241
 * Decrements the global reference number.
 
242
 *
 
243
 * This function is thread-safe.
 
244
 */
 
245
void
 
246
IcedTeaPluginUtilities::releaseReference()
 
247
{
 
248
    // do nothing for now
 
249
}
 
250
 
 
251
/**
 
252
 * Converts integer to char*
 
253
 *
 
254
 * @param i The integer to convert to ascii
 
255
 * @param result The resulting string
 
256
 */
 
257
void
 
258
IcedTeaPluginUtilities::itoa(int i, std::string* result)
 
259
{
 
260
        // largest possible integer is 10 digits long
 
261
        char* int_str = (char*) malloc(sizeof(char)*11);
 
262
        sprintf(int_str, "%d", i);
 
263
        result->append(int_str);
 
264
 
 
265
        free(int_str);
 
266
}
 
267
 
 
268
/**
 
269
 * Frees memory from a string* vector
 
270
 *
 
271
 * The vector deconstructor will only delete string pointers upon being
 
272
 * called. This function frees the associated string memory as well.
 
273
 *
 
274
 * @param v The vector whose strings are to be freed
 
275
 */
 
276
void
 
277
IcedTeaPluginUtilities::freeStringPtrVector(std::vector<std::string*>* v)
 
278
{
 
279
        if (v)
 
280
        {
 
281
                for (int i=0; i < v->size(); i++) {
 
282
                        delete v->at(i);
 
283
                }
 
284
 
 
285
                delete v;
 
286
        }
 
287
 
 
288
}
 
289
 
 
290
/**
 
291
 * Given a string, splits it on the given delimiters.
 
292
 *
 
293
 * @param str The string to split
 
294
 * @param The delimiters to split on
 
295
 * @return A string vector containing the aplit components
 
296
 */
 
297
 
 
298
std::vector<std::string*>*
 
299
IcedTeaPluginUtilities::strSplit(const char* str, const char* delim)
 
300
{
 
301
        std::vector<std::string*>* v = new std::vector<std::string*>();
 
302
        v->reserve(strlen(str)/2);
 
303
        char* copy;
 
304
 
 
305
        // Tokening is done on a copy
 
306
        copy = (char*) malloc (sizeof(char)*strlen(str) + 1);
 
307
        strcpy(copy, str);
 
308
 
 
309
        char* tok_ptr;
 
310
        tok_ptr = strtok (copy, delim);
 
311
 
 
312
        while (tok_ptr != NULL)
 
313
        {
 
314
            // Allocation on heap since caller has no way to knowing how much will
 
315
            // be needed. Make sure caller cleans up!
 
316
                std::string* s = new std::string();
 
317
                s->append(tok_ptr);
 
318
                v->push_back(s);
 
319
                tok_ptr = strtok (NULL, " ");
 
320
        }
 
321
 
 
322
        return v;
 
323
}
 
324
 
 
325
/**
 
326
 * Given a unicode byte array, converts it to a UTF8 string
 
327
 *
 
328
 * The actual contents in the array may be surrounded by other data.
 
329
 *
 
330
 * e.g. with length 5, begin = 3,
 
331
 * unicode_byte_array = "37 28 5 48 45 4c 4c 4f 9e 47":
 
332
 *
 
333
 * We'd start at 3 i.e. "48" and go on for 5 i.e. upto and including "4f".
 
334
 * So we convert "48 45 4c 4c 4f" which is "hello"
 
335
 *
 
336
 * @param length The length of the string
 
337
 * @param begin Where in the array to begin conversion
 
338
 * @param result_unicode_str The return variable in which the
 
339
 *        converted string is placed
 
340
 */
 
341
 
 
342
void
 
343
IcedTeaPluginUtilities::getUTF8String(int length, int begin, std::vector<std::string*>* unicode_byte_array, std::string* result_unicode_str)
 
344
{
 
345
        result_unicode_str->clear();
 
346
        result_unicode_str->reserve(unicode_byte_array->size()/2);
 
347
        for (int i = begin; i < begin+length; i++)
 
348
            result_unicode_str->push_back((char) strtol(unicode_byte_array->at(i)->c_str(), NULL, 16));
 
349
 
 
350
        PLUGIN_DEBUG("Converted UTF-8 string: %s. Length=%d\n", result_unicode_str->c_str(), result_unicode_str->length());
 
351
}
 
352
 
 
353
/**
 
354
 * Given a UTF8 string, converts it to a space delimited string of hex characters
 
355
 *
 
356
 * The first element in the return array is the length of the string
 
357
 *
 
358
 * e.g. "hello" would convert to: "5 48 45 4c 4c 4f"
 
359
 *
 
360
 * @param str The string to convert
 
361
 * @param urt_str The result
 
362
 */
 
363
 
 
364
void
 
365
IcedTeaPluginUtilities::convertStringToUTF8(std::string* str, std::string* utf_str)
 
366
{
 
367
        std::ostringstream ostream;
 
368
 
 
369
        std::string length = std::string();
 
370
        itoa(str->length(), &length);
 
371
 
 
372
        ostream << length;
 
373
 
 
374
        // UTF-8 characters are 4-bytes max + space + '\0'
 
375
        char* hex_value = (char*) malloc(sizeof(char)*10);
 
376
 
 
377
        for (int i = 0; i < str->length(); i++)
 
378
        {
 
379
                sprintf(hex_value, " %hx", str->at(i));
 
380
                ostream << hex_value;
 
381
        }
 
382
 
 
383
        utf_str->clear();
 
384
        *utf_str = ostream.str();
 
385
 
 
386
        free(hex_value);
 
387
        PLUGIN_DEBUG("Converted %s to UTF-8 string %s\n", str->c_str(), utf_str->c_str());
 
388
}
 
389
 
 
390
/**
 
391
 * Given a unicode byte array, converts it to a UTF16LE/UCS-2 string
 
392
 *
 
393
 * This works in a manner similar to getUTF8String, except that it reads 2
 
394
 * slots for each byte.
 
395
 *
 
396
 * @param length The length of the string
 
397
 * @param begin Where in the array to begin conversion
 
398
 * @param result_unicode_str The return variable in which the
 
399
 *        converted string is placed
 
400
 */
 
401
void
 
402
IcedTeaPluginUtilities::getUTF16LEString(int length, int begin, std::vector<std::string*>* unicode_byte_array, std::wstring* result_unicode_str)
 
403
{
 
404
 
 
405
        wchar_t c;
 
406
 
 
407
        if (plugin_debug) printf("Converted UTF-16LE string: ");
 
408
 
 
409
        result_unicode_str->clear();
 
410
        for (int i = begin; i < begin+length; i+=2)
 
411
        {
 
412
                int low = strtol(unicode_byte_array->at(i)->c_str(), NULL, 16);
 
413
                int high = strtol(unicode_byte_array->at(i+1)->c_str(), NULL, 16);
 
414
 
 
415
        c = ((high << 8) | low);
 
416
 
 
417
        if ((c >= 'a' && c <= 'z') ||
 
418
                (c >= 'A' && c <= 'Z') ||
 
419
                (c >= '0' && c <= '9'))
 
420
        {
 
421
                if (plugin_debug) printf("%c", c);
 
422
        }
 
423
 
 
424
        result_unicode_str->push_back(c);
 
425
        }
 
426
 
 
427
        // not routing via debug print macros due to wide-string issues
 
428
        if (plugin_debug) printf(". Length=%d\n", result_unicode_str->length());
 
429
}
 
430
 
 
431
/*
 
432
 * Prints the given string vector (if debug is true)
 
433
 *
 
434
 * @param prefix The prefix to print before printing the vector contents
 
435
 * @param cv The string vector whose contents are to be printed
 
436
 */
 
437
void
 
438
IcedTeaPluginUtilities::printStringVector(const char* prefix, std::vector<std::string>* str_vector)
 
439
{
 
440
 
 
441
        // This is a CPU intensive function. Run only if debugging
 
442
        if (!plugin_debug)
 
443
            return;
 
444
 
 
445
        std::string* str = new std::string();
 
446
        *str += "{ ";
 
447
        for (int i=0; i < str_vector->size(); i++)
 
448
        {
 
449
                *str += str_vector->at(i);
 
450
 
 
451
                if (i != str_vector->size() - 1)
 
452
                        *str += ", ";
 
453
        }
 
454
 
 
455
        *str += " }";
 
456
 
 
457
        PLUGIN_DEBUG("%s %s\n", prefix, str->c_str());
 
458
 
 
459
        delete str;
 
460
}
 
461
 
 
462
const gchar*
 
463
IcedTeaPluginUtilities::getSourceFromInstance(NPP instance)
 
464
{
 
465
    // At the moment, src cannot be securely fetched via NPAPI
 
466
    // See:
 
467
    // http://www.mail-archive.com/chromium-dev@googlegroups.com/msg04872.html
 
468
 
 
469
    // Since we use the insecure window.location.href attribute to compute
 
470
    // source, we cannot use it to make security decisions. Therefore,
 
471
    // instance associated source will always return empty
 
472
 
 
473
    //ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
 
474
    //return (data->source) ? data->source : "";
 
475
 
 
476
    return "http://null.null";
 
477
}
 
478
 
 
479
/**
 
480
 * Stores a window pointer <-> instance mapping
 
481
 *
 
482
 * @param member_ptr The pointer key
 
483
 * @param instance The instance to associate with this pointer
 
484
 */
 
485
 
 
486
void
 
487
IcedTeaPluginUtilities::storeInstanceID(void* member_ptr, NPP instance)
 
488
{
 
489
    PLUGIN_DEBUG("Storing instance %p with key %p\n", instance, member_ptr);
 
490
    instance_map->insert(std::make_pair(member_ptr, instance));
 
491
}
 
492
 
 
493
/**
 
494
 * Removes a window pointer <-> instance mapping
 
495
 *
 
496
 * @param member_ptr The key to remove
 
497
 */
 
498
 
 
499
void
 
500
IcedTeaPluginUtilities::removeInstanceID(void* member_ptr)
 
501
{
 
502
    PLUGIN_DEBUG("Removing key %p from instance map\n", member_ptr);
 
503
    instance_map->erase(member_ptr);
 
504
}
 
505
 
 
506
/**
 
507
 * Removes all mappings to a given instance, and all associated objects
 
508
 */
 
509
void
 
510
IcedTeaPluginUtilities::invalidateInstance(NPP instance)
 
511
{
 
512
    PLUGIN_DEBUG("Invalidating instance %p\n", instance);
 
513
 
 
514
    std::map<void*,NPP>::iterator iterator;
 
515
 
 
516
    for (iterator = instance_map->begin(); iterator != instance_map->end(); )
 
517
    {
 
518
        if ((*iterator).second == instance)
 
519
        {
 
520
            instance_map->erase(iterator++);
 
521
        }
 
522
        else
 
523
        {
 
524
            ++iterator;
 
525
        }
 
526
    }
 
527
}
 
528
 
 
529
/**
 
530
 * Given the window pointer, returns the instance associated with it
 
531
 *
 
532
 * @param member_ptr The pointer key
 
533
 * @return The associated instance
 
534
 */
 
535
 
 
536
NPP
 
537
IcedTeaPluginUtilities::getInstanceFromMemberPtr(void* member_ptr)
 
538
{
 
539
 
 
540
    NPP instance = NULL;
 
541
    PLUGIN_DEBUG("getInstanceFromMemberPtr looking for %p\n", member_ptr);
 
542
 
 
543
    std::map<void*, NPP>::iterator iterator = instance_map->find(member_ptr);
 
544
 
 
545
    if (iterator != instance_map->end())
 
546
    {
 
547
        instance = instance_map->find(member_ptr)->second;
 
548
        PLUGIN_DEBUG("getInstanceFromMemberPtr found %p. Instance = %p\n", member_ptr, instance);
 
549
    }
 
550
 
 
551
    return instance;
 
552
}
 
553
 
 
554
/**
 
555
 * Given a java id key ('classid:instanceid'), returns the associated valid NPObject, if any
 
556
 *
 
557
 * @param key the key
 
558
 * @return The associated active NPObject, NULL otherwise
 
559
 */
 
560
 
 
561
NPObject*
 
562
IcedTeaPluginUtilities::getNPObjectFromJavaKey(std::string key)
 
563
{
 
564
 
 
565
    NPObject* object = NULL;
 
566
    PLUGIN_DEBUG("getNPObjectFromJavaKey looking for %s\n", key.c_str());
 
567
 
 
568
    std::map<std::string, NPObject*>::iterator iterator = object_map->find(key);
 
569
 
 
570
    if (iterator != object_map->end())
 
571
    {
 
572
        NPObject* mapped_object = object_map->find(key)->second;
 
573
 
 
574
        if (getInstanceFromMemberPtr(mapped_object) != NULL)
 
575
        {
 
576
            object = mapped_object;
 
577
            PLUGIN_DEBUG("getNPObjectFromJavaKey found %s. NPObject = %p\n", key.c_str(), object);
 
578
        }
 
579
    }
 
580
 
 
581
    return object;
 
582
}
 
583
 
 
584
/**
 
585
 * Stores a java id key <-> NPObject mapping
 
586
 *
 
587
 * @param key The Java ID Key
 
588
 * @param object The object to map to
 
589
 */
 
590
 
 
591
void
 
592
IcedTeaPluginUtilities::storeObjectMapping(std::string key, NPObject* object)
 
593
{
 
594
    PLUGIN_DEBUG("Storing object %p with key %s\n", object, key.c_str());
 
595
    object_map->insert(std::make_pair(key, object));
 
596
}
 
597
 
 
598
/**
 
599
 * Removes a java id key <-> NPObject mapping
 
600
 *
 
601
 * @param key The key to remove
 
602
 */
 
603
 
 
604
void
 
605
IcedTeaPluginUtilities::removeObjectMapping(std::string key)
 
606
{
 
607
    PLUGIN_DEBUG("Removing key %s from object map\n", key.c_str());
 
608
    object_map->erase(key);
 
609
}
 
610
 
 
611
/*
 
612
 * Similar to printStringVector, but takes a vector of string pointers instead
 
613
 *
 
614
 * @param prefix The prefix to print before printing the vector contents
 
615
 * @param cv The string* vector whose contents are to be printed
 
616
 */
 
617
 
 
618
void
 
619
IcedTeaPluginUtilities::printStringPtrVector(const char* prefix, std::vector<std::string*>* str_ptr_vector)
 
620
{
 
621
        // This is a CPU intensive function. Run only if debugging
 
622
        if (!plugin_debug)
 
623
            return;
 
624
 
 
625
        std::string* str = new std::string();
 
626
        *str += "{ ";
 
627
        for (int i=0; i < str_ptr_vector->size(); i++)
 
628
        {
 
629
                *str += *(str_ptr_vector->at(i));
 
630
 
 
631
                if (i != str_ptr_vector->size() - 1)
 
632
                        *str += ", ";
 
633
        }
 
634
 
 
635
        *str += " }";
 
636
 
 
637
        PLUGIN_DEBUG("%s %s\n", prefix, str->c_str());
 
638
 
 
639
        delete str;
 
640
}
 
641
 
 
642
void
 
643
IcedTeaPluginUtilities::printNPVariant(NPVariant variant)
 
644
{
 
645
    // This is a CPU intensive function. Run only if debugging
 
646
    if (!plugin_debug)
 
647
        return;
 
648
 
 
649
    if (NPVARIANT_IS_VOID(variant))
 
650
    {
 
651
        PLUGIN_DEBUG("VOID %d\n", variant);
 
652
    }
 
653
    else if (NPVARIANT_IS_NULL(variant))
 
654
    {
 
655
        PLUGIN_DEBUG("NULL\n", variant);
 
656
    }
 
657
    else if (NPVARIANT_IS_BOOLEAN(variant))
 
658
    {
 
659
        PLUGIN_DEBUG("BOOL: %d\n", NPVARIANT_TO_BOOLEAN(variant));
 
660
    }
 
661
    else if (NPVARIANT_IS_INT32(variant))
 
662
    {
 
663
        PLUGIN_DEBUG("INT32: %d\n", NPVARIANT_TO_INT32(variant));
 
664
    }
 
665
    else if (NPVARIANT_IS_DOUBLE(variant))
 
666
    {
 
667
        PLUGIN_DEBUG("DOUBLE: %f\n", NPVARIANT_TO_DOUBLE(variant));
 
668
    }
 
669
    else if (NPVARIANT_IS_STRING(variant))
 
670
    {
 
671
#if MOZILLA_VERSION_COLLAPSED < 1090200
 
672
        PLUGIN_DEBUG("STRING: %s\n", NPVARIANT_TO_STRING(variant).utf8characters);
 
673
#else
 
674
        PLUGIN_DEBUG("STRING: %s\n", NPVARIANT_TO_STRING(variant).UTF8Characters);
 
675
#endif
 
676
    }
 
677
    else
 
678
    {
 
679
        PLUGIN_DEBUG("OBJ: %p\n", NPVARIANT_TO_OBJECT(variant));
 
680
    }
 
681
}
 
682
 
 
683
void
 
684
IcedTeaPluginUtilities::NPVariantToString(NPVariant variant, std::string* result)
 
685
{
 
686
        char* str = (char*) malloc(sizeof(char)*32); // enough for everything except string
 
687
 
 
688
    if (NPVARIANT_IS_VOID(variant))
 
689
    {
 
690
        sprintf(str, "%p", variant);
 
691
    }
 
692
    else if (NPVARIANT_IS_NULL(variant))
 
693
    {
 
694
        sprintf(str, "NULL");
 
695
    }
 
696
    else if (NPVARIANT_IS_BOOLEAN(variant))
 
697
    {
 
698
        if (NPVARIANT_TO_BOOLEAN(variant))
 
699
                sprintf(str, "true");
 
700
        else
 
701
                sprintf(str, "false");
 
702
    }
 
703
    else if (NPVARIANT_IS_INT32(variant))
 
704
    {
 
705
        sprintf(str, "%d", NPVARIANT_TO_INT32(variant));
 
706
    }
 
707
    else if (NPVARIANT_IS_DOUBLE(variant))
 
708
    {
 
709
        sprintf(str, "%f", NPVARIANT_TO_DOUBLE(variant));;
 
710
    }
 
711
    else if (NPVARIANT_IS_STRING(variant))
 
712
    {
 
713
        free(str);
 
714
#if MOZILLA_VERSION_COLLAPSED < 1090200
 
715
        str = (char*) malloc(sizeof(char)*NPVARIANT_TO_STRING(variant).utf8length);
 
716
        sprintf(str, "%s", NPVARIANT_TO_STRING(variant).utf8characters);
 
717
#else
 
718
        str = (char*) malloc(sizeof(char)*NPVARIANT_TO_STRING(variant).UTF8Length);
 
719
        sprintf(str, "%s", NPVARIANT_TO_STRING(variant).UTF8Characters);
 
720
#endif
 
721
    }
 
722
    else
 
723
    {
 
724
        sprintf(str, "[Object %p]", variant);
 
725
    }
 
726
 
 
727
    result->append(str);
 
728
    free(str);
 
729
}
 
730
 
 
731
bool
 
732
IcedTeaPluginUtilities::javaResultToNPVariant(NPP instance,
 
733
                                              std::string* java_value,
 
734
                                              NPVariant* variant)
 
735
{
 
736
    JavaRequestProcessor java_request = JavaRequestProcessor();
 
737
    JavaResultData* java_result;
 
738
 
 
739
    if (java_value->find("literalreturn") == 0)
 
740
    {
 
741
        // 'literalreturn ' == 14 to skip
 
742
        std::string value = java_value->substr(14);
 
743
 
 
744
        // VOID/BOOLEAN/NUMBER
 
745
 
 
746
        if (value == "void")
 
747
        {
 
748
            PLUGIN_DEBUG("Method call returned void\n");
 
749
            VOID_TO_NPVARIANT(*variant);
 
750
        } else if (value == "null")
 
751
        {
 
752
            PLUGIN_DEBUG("Method call returned null\n");
 
753
            NULL_TO_NPVARIANT(*variant);
 
754
        }else if (value == "true")
 
755
        {
 
756
            PLUGIN_DEBUG("Method call returned a boolean (true)\n");
 
757
            BOOLEAN_TO_NPVARIANT(true, *variant);
 
758
        } else if (value == "false")
 
759
        {
 
760
            PLUGIN_DEBUG("Method call returned a boolean (false)\n");
 
761
            BOOLEAN_TO_NPVARIANT(false, *variant);
 
762
        } else
 
763
        {
 
764
            double d = strtod(value.c_str(), NULL);
 
765
 
 
766
            // See if it is convertible to int
 
767
            if (value.find(".") != std::string::npos ||
 
768
                d < -(0x7fffffffL - 1L) ||
 
769
                d > 0x7fffffffL)
 
770
            {
 
771
                PLUGIN_DEBUG("Method call returned a double %f\n", d);
 
772
                DOUBLE_TO_NPVARIANT(d, *variant);
 
773
            } else
 
774
            {
 
775
                int32_t i = (int32_t) d;
 
776
                PLUGIN_DEBUG("Method call returned an int %d\n", i);
 
777
                INT32_TO_NPVARIANT(i, *variant);
 
778
            }
 
779
        }
 
780
    } else {
 
781
        // Else this is a complex java object
 
782
 
 
783
        // To keep code a little bit cleaner, we create variables with proper descriptive names
 
784
        std::string return_obj_instance_id = std::string();
 
785
        std::string return_obj_class_id = std::string();
 
786
        std::string return_obj_class_name = std::string();
 
787
        return_obj_instance_id.append(*java_value);
 
788
 
 
789
        // Find out the class name first, because string is a special case
 
790
        java_result = java_request.getClassName(return_obj_instance_id);
 
791
 
 
792
        if (java_result->error_occurred)
 
793
        {
 
794
            return false;
 
795
        }
 
796
 
 
797
        return_obj_class_name.append(*(java_result->return_string));
 
798
 
 
799
        if (return_obj_class_name == "java.lang.String")
 
800
        {
 
801
            // String is a special case as NPVariant can handle it directly
 
802
            java_result = java_request.getString(return_obj_instance_id);
 
803
 
 
804
            if (java_result->error_occurred)
 
805
            {
 
806
                return false;
 
807
            }
 
808
 
 
809
            // needs to be on the heap
 
810
            NPUTF8* return_str = (NPUTF8*) malloc(sizeof(NPUTF8)*java_result->return_string->size() + 1);
 
811
            strcpy(return_str, java_result->return_string->c_str());
 
812
 
 
813
            PLUGIN_DEBUG("Method call returned a string: \"%s\"\n", return_str);
 
814
            STRINGZ_TO_NPVARIANT(return_str, *variant);
 
815
 
 
816
        } else {
 
817
 
 
818
            // Else this is a regular class. Reference the class object so
 
819
            // we can construct an NPObject with it and the instance
 
820
            java_result = java_request.getClassID(return_obj_instance_id);
 
821
 
 
822
            if (java_result->error_occurred)
 
823
            {
 
824
                return false;
 
825
            }
 
826
 
 
827
            return_obj_class_id.append(*(java_result->return_string));
 
828
 
 
829
            NPObject* obj;
 
830
 
 
831
            if (return_obj_class_name.find('[') == 0) // array
 
832
                obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(
 
833
                                instance,
 
834
                                return_obj_class_id, return_obj_instance_id, true);
 
835
            else
 
836
                obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(
 
837
                                                instance,
 
838
                                                return_obj_class_id, return_obj_instance_id, false);
 
839
 
 
840
            OBJECT_TO_NPVARIANT(obj, *variant);
 
841
        }
 
842
    }
 
843
 
 
844
    return true;
 
845
}
 
846
 
 
847
bool
 
848
IcedTeaPluginUtilities::isObjectJSArray(NPP instance, NPObject* object)
 
849
{
 
850
 
 
851
    NPVariant constructor_v = NPVariant();
 
852
    NPIdentifier constructor_id = browser_functions.getstringidentifier("constructor");
 
853
    browser_functions.getproperty(instance, object, constructor_id, &constructor_v);
 
854
    IcedTeaPluginUtilities::printNPVariant(constructor_v);
 
855
 
 
856
    // void constructor => not an array
 
857
    if (NPVARIANT_IS_VOID(constructor_v))
 
858
        return false;
 
859
 
 
860
    NPObject* constructor = NPVARIANT_TO_OBJECT(constructor_v);
 
861
 
 
862
    NPVariant constructor_str;
 
863
    NPIdentifier toString = browser_functions.getstringidentifier("toString");
 
864
    browser_functions.invoke(instance, constructor, toString, NULL, 0, &constructor_str);
 
865
    IcedTeaPluginUtilities::printNPVariant(constructor_str);
 
866
 
 
867
    std::string constructor_name = std::string();
 
868
 
 
869
#if MOZILLA_VERSION_COLLAPSED < 1090200
 
870
    constructor_name.append(NPVARIANT_TO_STRING(constructor_str).utf8characters);
 
871
#else
 
872
    constructor_name.append(NPVARIANT_TO_STRING(constructor_str).UTF8Characters);
 
873
#endif
 
874
 
 
875
    PLUGIN_DEBUG("Constructor for NPObject is %s\n", constructor_name.c_str());
 
876
 
 
877
    return constructor_name.find("function Array") == 0;
 
878
}
 
879
 
 
880
void
 
881
IcedTeaPluginUtilities::decodeURL(const gchar* url, gchar** decoded_url)
 
882
{
 
883
 
 
884
    PLUGIN_DEBUG("GOT URL: %s -- %s\n", url, *decoded_url);
 
885
    int length = strlen(url);
 
886
    for (int i=0; i < length; i++)
 
887
    {
 
888
        if (url[i] == '%' && i < length - 2)
 
889
        {
 
890
            unsigned char code1 = (unsigned char) url[i+1];
 
891
            unsigned char code2 = (unsigned char) url[i+2];
 
892
 
 
893
            if (!IS_VALID_HEX(&code1) || !IS_VALID_HEX(&code2))
 
894
                continue;
 
895
 
 
896
            // Convert hex value to integer
 
897
            int converted1 = HEX_TO_INT(&code1);
 
898
            int converted2 = HEX_TO_INT(&code2);
 
899
 
 
900
            // bitshift 4 to simulate *16
 
901
            int value = (converted1 << 4) + converted2;
 
902
            char decoded = value;
 
903
 
 
904
            strncat(*decoded_url, &decoded, 1);
 
905
 
 
906
            i += 2;
 
907
        } else
 
908
        {
 
909
            strncat(*decoded_url, &url[i], 1);
 
910
        }
 
911
    }
 
912
 
 
913
    PLUGIN_DEBUG("SENDING URL: %s\n", *decoded_url);
 
914
}
 
915
 
 
916
 
 
917
/**
 
918
 * Posts a function for execution on the plug-in thread and wait for result.
 
919
 *
 
920
 * @param instance The NPP instance
 
921
 * @param func The function to post
 
922
 * @param data Arguments to *func
 
923
 */
 
924
void
 
925
IcedTeaPluginUtilities::callAndWaitForResult(NPP instance, void (*func) (void *), AsyncCallThreadData* data)
 
926
{
 
927
 
 
928
    struct timespec t;
 
929
    struct timespec curr_t;
 
930
    clock_gettime(CLOCK_REALTIME, &t);
 
931
    t.tv_sec += REQUESTTIMEOUT; // timeout
 
932
 
 
933
    // post request
 
934
    postPluginThreadAsyncCall(instance, func, data);
 
935
 
 
936
    do
 
937
    {
 
938
        clock_gettime(CLOCK_REALTIME, &curr_t);
 
939
        if (data != NULL && !data->result_ready && (curr_t.tv_sec < t.tv_sec))
 
940
        {
 
941
            usleep(2000);
 
942
        } else
 
943
        {
 
944
            break;
 
945
        }
 
946
    } while (1);
 
947
}
 
948
 
 
949
 
 
950
/**
 
951
 * Posts a request that needs to be handled in a plugin thread.
 
952
 *
 
953
 * @param instance The plugin instance
 
954
 * @param func The function to execute
 
955
 * @param userData The userData for the function to consume/write to
 
956
 * @return if the call was posted successfully
 
957
 */
 
958
 
 
959
bool
 
960
IcedTeaPluginUtilities::postPluginThreadAsyncCall(NPP instance, void (*func) (void *), void* data)
 
961
{
 
962
    if (instance)
 
963
    {
 
964
        PluginThreadCall* call = new PluginThreadCall();
 
965
        call->instance = instance;
 
966
        call->func = func;
 
967
        call->userData = data;
 
968
 
 
969
        pthread_mutex_lock(&pluginAsyncCallMutex);
 
970
        pendingPluginThreadRequests->push_back(call);
 
971
        pthread_mutex_unlock(&pluginAsyncCallMutex);
 
972
 
 
973
        browser_functions.pluginthreadasynccall(instance, &processAsyncCallQueue, NULL); // Always returns immediately
 
974
 
 
975
        PLUGIN_DEBUG("Pushed back call evt %p\n", call);
 
976
 
 
977
        return true;
 
978
    }
 
979
 
 
980
    // Else
 
981
    PLUGIN_DEBUG("Instance is not active. Call rejected.\n");
 
982
    return false;
 
983
}
 
984
 
 
985
/**
 
986
 * Runs through the async call wait queue and executes all calls
 
987
 *
 
988
 * @param param Ignored -- required to conform to NPN_PluginThreadAsynCall API
 
989
 */
 
990
void
 
991
processAsyncCallQueue(void* param /* ignored */)
 
992
{
 
993
    do {
 
994
        PluginThreadCall* call = NULL;
 
995
 
 
996
        pthread_mutex_lock(&pluginAsyncCallMutex);
 
997
        if (pendingPluginThreadRequests->size() > 0)
 
998
        {
 
999
            call = pendingPluginThreadRequests->front();
 
1000
            pendingPluginThreadRequests->erase(pendingPluginThreadRequests->begin());
 
1001
        }
 
1002
        pthread_mutex_unlock(&pluginAsyncCallMutex);
 
1003
 
 
1004
        if (call)
 
1005
        {
 
1006
            PLUGIN_DEBUG("Processing call evt %p\n", call);
 
1007
            call->func(call->userData);
 
1008
            PLUGIN_DEBUG("Call evt %p processed\n", call);
 
1009
 
 
1010
            delete call;
 
1011
        } else
 
1012
        {
 
1013
            break;
 
1014
        }
 
1015
    } while(1);
 
1016
}
 
1017
 
 
1018
/******************************************
 
1019
 * Begin JavaMessageSender implementation *
 
1020
 ******************************************
 
1021
 *
 
1022
 * This implementation is very simple and is therefore folded into this file
 
1023
 * rather than a new one.
 
1024
 */
 
1025
 
 
1026
/**
 
1027
 * Sends to the Java side
 
1028
 *
 
1029
 * @param message The message to send.
 
1030
 * @param returns whether the message was consumable (always true)
 
1031
 */
 
1032
 
 
1033
bool
 
1034
JavaMessageSender::newMessageOnBus(const char* message)
 
1035
{
 
1036
        char* msg = (char*) malloc(sizeof(char)*strlen(message) + 1);
 
1037
        strcpy(msg, message);
 
1038
        plugin_send_message_to_appletviewer(msg);
 
1039
 
 
1040
        free(msg);
 
1041
        msg = NULL;
 
1042
 
 
1043
        // Always successful
 
1044
        return true;
 
1045
}
 
1046
 
 
1047
/***********************************
 
1048
 * Begin MessageBus implementation *
 
1049
 ***********************************/
 
1050
 
 
1051
/**
 
1052
 * Constructor.
 
1053
 *
 
1054
 * Initializes the mutexes needed by the other functions.
 
1055
 */
 
1056
MessageBus::MessageBus()
 
1057
{
 
1058
        int ret;
 
1059
 
 
1060
        ret = pthread_mutex_init(&subscriber_mutex, NULL);
 
1061
 
 
1062
        if(ret)
 
1063
                PLUGIN_DEBUG("Error: Unable to initialize subscriber mutex: %d\n", ret);
 
1064
 
 
1065
        ret = pthread_mutex_init(&msg_queue_mutex, NULL);
 
1066
        if(ret)
 
1067
                PLUGIN_DEBUG("Error: Unable to initialize message queue mutex: %d\n", ret);
 
1068
 
 
1069
        PLUGIN_DEBUG("Mutexs %p and %p initialized\n", &subscriber_mutex, &msg_queue_mutex);
 
1070
}
 
1071
 
 
1072
/**
 
1073
 * Destructor.
 
1074
 *
 
1075
 * Destroy the mutexes initialized by the constructor.
 
1076
 */
 
1077
 
 
1078
MessageBus::~MessageBus()
 
1079
{
 
1080
    PLUGIN_DEBUG("MessageBus::~MessageBus\n");
 
1081
 
 
1082
        int ret;
 
1083
 
 
1084
        ret = pthread_mutex_destroy(&subscriber_mutex);
 
1085
        if(ret)
 
1086
                PLUGIN_DEBUG("Error: Unable to destroy subscriber mutex: %d\n", ret);
 
1087
 
 
1088
        ret = pthread_mutex_destroy(&msg_queue_mutex);
 
1089
        if(ret)
 
1090
                        PLUGIN_DEBUG("Error: Unable to destroy message queue mutex: %d\n", ret);
 
1091
}
 
1092
 
 
1093
/**
 
1094
 * Adds the given BusSubscriber as a subscriber to self
 
1095
 *
 
1096
 * @param b The BusSubscriber to subscribe
 
1097
 */
 
1098
void
 
1099
MessageBus::subscribe(BusSubscriber* b)
 
1100
{
 
1101
    // Applets may initialize in parallel. So lock before pushing.
 
1102
 
 
1103
        PLUGIN_DEBUG("Subscribing %p to bus %p\n", b, this);
 
1104
    pthread_mutex_lock(&subscriber_mutex);
 
1105
    subscribers.push_back(b);
 
1106
    pthread_mutex_unlock(&subscriber_mutex);
 
1107
}
 
1108
 
 
1109
/**
 
1110
 * Removes the given BusSubscriber from the subscriber list
 
1111
 *
 
1112
 * @param b The BusSubscriber to ubsubscribe
 
1113
 */
 
1114
void
 
1115
MessageBus::unSubscribe(BusSubscriber* b)
 
1116
{
 
1117
    // Applets may initialize in parallel. So lock before pushing.
 
1118
 
 
1119
        PLUGIN_DEBUG("Un-subscribing %p from bus %p\n", b, this);
 
1120
    pthread_mutex_lock(&subscriber_mutex);
 
1121
    subscribers.remove(b);
 
1122
    pthread_mutex_unlock(&subscriber_mutex);
 
1123
}
 
1124
 
 
1125
/**
 
1126
 * Notifies all subscribers with the given message
 
1127
 *
 
1128
 * @param message The message to send to the subscribers
 
1129
 */
 
1130
void
 
1131
MessageBus::post(const char* message)
 
1132
{
 
1133
        char* msg = (char*) malloc(sizeof(char)*strlen(message) + 1);
 
1134
        bool message_consumed = false;
 
1135
 
 
1136
        // consumer frees this memory
 
1137
        strcpy(msg, message);
 
1138
 
 
1139
        PLUGIN_DEBUG("Trying to lock %p...\n", &msg_queue_mutex);
 
1140
        pthread_mutex_lock(&subscriber_mutex);
 
1141
 
 
1142
    PLUGIN_DEBUG("Message %s received on bus. Notifying subscribers.\n", msg);
 
1143
 
 
1144
    std::list<BusSubscriber*>::const_iterator i;
 
1145
    for( i = subscribers.begin(); i != subscribers.end() && !message_consumed; ++i ) {
 
1146
        PLUGIN_DEBUG("Notifying subscriber %p of %s\n", *i, msg);
 
1147
        message_consumed = ((BusSubscriber*) *i)->newMessageOnBus(msg);
 
1148
    }
 
1149
 
 
1150
    pthread_mutex_unlock(&subscriber_mutex);
 
1151
 
 
1152
    if (!message_consumed)
 
1153
        PLUGIN_DEBUG("Warning: No consumer found for message %s\n", msg);
 
1154
 
 
1155
    PLUGIN_DEBUG("%p unlocked...\n", &msg_queue_mutex);
 
1156
}