home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libmocha / lm_taint.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  61.1 KB  |  2,034 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /*
  19.  * JS/Mozilla data tainting support.
  20.  * XXX replace with lm_sec.c and lm_CheckAccess or similar
  21.  *
  22.  */
  23. #include "lm.h"
  24. #include "xp.h"
  25. #include "mkparse.h"
  26. #include "mkutils.h"
  27. #include "prclist.h"
  28. #include "plhash.h"
  29. #include "prmem.h"
  30. #include "shist.h"
  31. #include "jsapi.h"
  32. #include "jsdbgapi.h"
  33. #include "jscntxt.h"  /* XXX - needed for charSetName */
  34. #include "zip.h"
  35. #include "zig.h"
  36. #include "jri.h"
  37. #include "jsjava.h"
  38. #include "java.h"
  39. #include "jsobj.h"
  40. #include "jsatom.h"
  41. #include "jsscope.h"
  42.  
  43. /* Needed to access private method; making method public would be
  44.    security hole */
  45. #define IMPLEMENT_netscape_security_PrivilegeManager
  46.  
  47. #include "netscape_security_Principal.h"
  48. #include "netscape_security_Zig.h"
  49. #ifdef XP_MAC
  50.     #include "n_security_PrivilegeManager.h"
  51.     #include "n_security_PrivilegeTable.h"
  52. #else
  53.     #include "netscape_security_PrivilegeManager.h"
  54.     #include "netscape_security_PrivilegeTable.h"
  55. #endif /* XP_MAC */
  56. #include "netscape_security_Privilege.h"
  57. #include "netscape_security_Target.h"
  58.  
  59. extern JRIEnv * LJ_JSJ_CurrentEnv(JSContext * cx);
  60. extern char *LJ_GetAppletScriptOrigin(JRIEnv *env);
  61. extern struct java_lang_String *makeJavaString(const char *, int);
  62.  
  63. char lm_unknown_origin_str[] = "[unknown origin]";
  64.  
  65. static char file_url_prefix[]    = "file:";
  66. static char access_error_message[] =
  67.     "access disallowed from scripts at %s to documents at another domain";
  68. static char container_error_message[] =
  69.     "script at '%s' is not signed by sufficient principals to access "
  70.     "signed container";
  71.  
  72. #define FILE_URL_PREFIX_LEN     (sizeof file_url_prefix - 1)
  73. #define WYSIWYG_TYPE_LEN        10      /* wysiwyg:// */
  74.  
  75. const char *
  76. LM_StripWysiwygURLPrefix(const char *url_string)
  77. {
  78.     switch (NET_URL_Type(url_string)) {
  79.       case WYSIWYG_TYPE_URL:
  80.         return LM_SkipWysiwygURLPrefix(url_string);
  81.       default:
  82.         return url_string;
  83.     }
  84. }
  85.  
  86. const char *
  87. LM_SkipWysiwygURLPrefix(const char *url_string)
  88. {
  89.     if (XP_STRLEN(url_string) < WYSIWYG_TYPE_LEN)
  90.         return NULL;
  91.     url_string += WYSIWYG_TYPE_LEN;
  92.     url_string = XP_STRCHR(url_string, '/');
  93.     if (!url_string)
  94.         return NULL;
  95.     return url_string + 1;
  96. }
  97.  
  98.  
  99. JSPrincipals *
  100. lm_GetCompilationPrincipals(MochaDecoder *decoder,
  101.                             JSPrincipals *layoutPrincipals)
  102. {
  103.     JSContext *cx;
  104.     JSPrincipals *principals;
  105.  
  106.     cx = decoder->js_context;
  107.  
  108.     if (decoder->writing_input && lm_writing_context != NULL) {
  109.         /*
  110.          * Compiling a script added due to a document.write.
  111.          * Get principals from stack frame. We can't just use these
  112.          * principals since the document.write code will fail signature
  113.          * verification. So just grab the codebase and form a new set
  114.          * of principals.
  115.          */
  116.         principals = lm_GetPrincipalsFromStackFrame(lm_writing_context);
  117.         principals = LM_NewJSPrincipals(NULL, NULL, principals
  118.                             ? principals->codebase
  119.                             : NULL);
  120.         if (principals == NULL) {
  121.             JS_ReportOutOfMemory(cx);
  122.             return NULL;
  123.         }
  124.         lm_InvalidateCertPrincipals(decoder, principals);
  125.         return principals;
  126.     }
  127.  
  128.     if (layoutPrincipals) {
  129.         return layoutPrincipals;
  130.     }
  131.  
  132.     /*
  133.      * Just get principals corresponding to the window or layer we're
  134.      * currently parsing.
  135.      */
  136.     return lm_GetInnermostPrincipals(cx,
  137.                                      lm_GetActiveContainer(decoder),
  138.                                      NULL);
  139. }
  140.  
  141. static const char *
  142. find_creator_url(MWContext *context)
  143. {
  144.     History_entry *he;
  145.     const char *address;
  146.     JSContext *cx;
  147.     MochaDecoder *decoder;
  148.  
  149.     he = SHIST_GetCurrent(&context->hist);
  150.     if (he) {
  151.     address = he->wysiwyg_url;
  152.     if (!address)
  153.         address = he->address;
  154.     switch (NET_URL_Type(address)) {
  155.       case ABOUT_TYPE_URL:
  156.       case MOCHA_TYPE_URL:
  157.         /* These types cannot name the true origin (server) of JS code. */
  158.         break;
  159.       case WYSIWYG_TYPE_URL:
  160.         return LM_SkipWysiwygURLPrefix(address);
  161.       case VIEW_SOURCE_TYPE_URL:
  162.         XP_ASSERT(0);
  163.       default:
  164.         return address;
  165.     }
  166.     }
  167.  
  168.     if (context->grid_parent) {
  169.         address = find_creator_url(context->grid_parent);
  170.         if (address)
  171.             return address;
  172.     }
  173.  
  174.     cx = context->mocha_context;
  175.     if (cx) {
  176.         decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  177.         if (decoder && decoder->opener) {
  178.             /* self.opener property is valid, check its MWContext. */
  179.             MochaDecoder *opener = JS_GetPrivate(cx, decoder->opener);
  180.             if (!opener->visited) {
  181.                 opener->visited = JS_TRUE;
  182.                 address = opener->window_context
  183.             ? find_creator_url(opener->window_context)
  184.             : NULL;
  185.                 opener->visited = JS_FALSE;
  186.                 if (address) 
  187.                     return address;
  188.             }
  189.         }
  190.     }
  191.  
  192.     return NULL;
  193. }
  194.  
  195. static const char *
  196. find_origin_url(JSContext *cx, MochaDecoder *decoder)
  197. {
  198.     const char *url_string;
  199.     MWContext *context;
  200.     MochaDecoder *running;
  201.  
  202.     context = decoder->window_context;
  203.     url_string = context ? find_creator_url(context) : NULL;
  204.     if (url_string == NULL) {
  205.         /* Must be a new, empty window?  Use running origin. */
  206.         running = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  207.  
  208.         /* Compare running and decoder to avoid infinite recursion. */
  209.         if (running == decoder) {
  210.             url_string = lm_unknown_origin_str;
  211.         } else {
  212.             url_string = lm_GetSubjectOriginURL(cx);
  213.         if (!url_string)
  214.         return NULL;
  215.         }
  216.     }
  217.     return url_string;
  218. }
  219.  
  220. static char *
  221. strip_file_double_slash(const char *url_string)
  222. {
  223.     char *new_url_string;
  224.  
  225.     if (!XP_STRNCASECMP(url_string, file_url_prefix, FILE_URL_PREFIX_LEN) &&
  226.         url_string[FILE_URL_PREFIX_LEN + 0] == '/' &&
  227.         url_string[FILE_URL_PREFIX_LEN + 1] == '/') {
  228.         new_url_string = PR_smprintf("%s%s",
  229.                                      file_url_prefix,
  230.                                      url_string + FILE_URL_PREFIX_LEN + 2);
  231.     } else {
  232.         new_url_string = XP_STRDUP(url_string);
  233.     }
  234.     return new_url_string;
  235. }
  236.  
  237. static char *
  238. getCanonicalizedOrigin(JSContext *cx, const char *url_string)
  239. {
  240.     const char *origin;
  241.  
  242.     if (NET_URL_Type(url_string) == WYSIWYG_TYPE_URL)
  243.         url_string = LM_SkipWysiwygURLPrefix(url_string);
  244.     origin = NET_ParseURL(url_string, GET_PROTOCOL_PART | GET_HOST_PART);
  245.     if (!origin) {
  246.         JS_ReportOutOfMemory(cx);
  247.         return NULL;
  248.     }
  249.     return (char *) origin;
  250. }
  251.  
  252. const char *
  253. lm_GetObjectOriginURL(JSContext *cx, JSObject *obj)
  254. {
  255.     JSPrincipals *principals;
  256.  
  257.     principals = lm_GetInnermostPrincipals(cx, obj, NULL);
  258.     return principals ? principals->codebase : NULL;
  259. }
  260.  
  261. static JSBool
  262. sameOrigins(JSContext *cx, const char *origin1, const char *origin2)
  263. {
  264.     char *cmp1, *cmp2;
  265.     JSBool ok;
  266.  
  267.     if (origin1 == NULL || origin2 == NULL)
  268.         return JS_FALSE;
  269. #if 0  /* XXX Need to enable this and test throroughly */
  270.     /* Shouldn't return true if both origin1 and origin2 are
  271.      * lm_unknown_origin_str. */
  272.     if (XP_STRCMP(origin1, lm_unknown_origin_str) == 0)
  273.         return JS_FALSE;
  274. #endif
  275.     if (XP_STRCMP(origin1, origin2) == 0)
  276.         return JS_TRUE;
  277.     cmp1 = getCanonicalizedOrigin(cx, origin1);
  278.     cmp2 = getCanonicalizedOrigin(cx, origin2);
  279.     if (cmp1 && cmp2 &&
  280.         XP_STRNCASECMP(cmp1, file_url_prefix, FILE_URL_PREFIX_LEN) == 0 &&
  281.     XP_STRNCASECMP(cmp2, file_url_prefix, FILE_URL_PREFIX_LEN) == 0)
  282.     return JS_TRUE;
  283.     ok = (JSBool)(cmp1 && cmp2 && XP_STRCMP(cmp1, cmp2) == 0);
  284.     PR_FREEIF(cmp1);
  285.     PR_FREEIF(cmp2);
  286.     return ok;
  287. }
  288.  
  289. JSBool
  290. lm_CheckPermissions(JSContext *cx, JSObject *obj, JSTarget target)
  291. {
  292.     const char *subjectOrigin, *objectOrigin;
  293.     MochaDecoder *running;
  294.     JSPrincipals *principals;
  295.     JSBool result;
  296.  
  297.     /* May be in a layer loaded from a different origin.*/
  298.     subjectOrigin = lm_GetSubjectOriginURL(cx);
  299.  
  300.     /*
  301.      * Hold onto reference to the running decoder's principals
  302.      * in case a call to lm_GetInnermostPrincipals ends up 
  303.      * dropping a reference due to an origin changing 
  304.      * underneath us.
  305.      */
  306.     running = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  307.     principals = running ? running->principals : NULL;
  308.     if (principals)
  309.     JSPRINCIPALS_HOLD(cx, principals);
  310.  
  311.     objectOrigin = lm_GetObjectOriginURL(cx, obj);
  312.  
  313.     if (subjectOrigin == NULL || objectOrigin == NULL) {
  314.     result = JS_FALSE;
  315.     goto out;
  316.     }
  317.  
  318.     /* Now see whether the origin methods and servers match. */
  319.     if (sameOrigins(cx, subjectOrigin, objectOrigin)) {
  320.     result = JS_TRUE;
  321.     goto out;
  322.     }
  323.  
  324.     /*
  325.      * If we failed the origin tests it still might be the case that we
  326.      *   are a signed script and have permissions to do this operation.
  327.      * Check for that here
  328.      */
  329.     if (target != JSTARGET_MAX && lm_CanAccessTarget(cx, target)) {
  330.     result = JS_TRUE;
  331.     goto out;
  332.     }
  333.  
  334.     JS_ReportError(cx, access_error_message, subjectOrigin);
  335.     result = JS_FALSE;
  336.  
  337. out:
  338.     if (principals)
  339.     JSPRINCIPALS_DROP(cx, principals);
  340.     return result;
  341. }
  342.  
  343. static JSBool
  344. isExternalCaptureEnabled(JSContext *cx, JSPrincipals *principals);
  345.  
  346. JSBool
  347. lm_CanCaptureEvent(JSContext *cx, JSFunction *fun, JSEvent *event)
  348. {
  349.     JSScript *script;
  350.     JSPrincipals *principals;
  351.     const char *origin;
  352.  
  353.     script = JS_GetFunctionScript(cx, fun);
  354.     if (script == NULL)
  355.         return JS_FALSE;
  356.     principals = JS_GetScriptPrincipals(cx, script);
  357.     if (principals == NULL)
  358.         return JS_FALSE;
  359.     origin = lm_GetObjectOriginURL(cx, event->object);
  360.     if (origin == NULL)
  361.         return JS_FALSE;
  362.     return (JSBool)(sameOrigins(cx, origin, principals->codebase) ||
  363.            isExternalCaptureEnabled(cx, principals));
  364. }
  365.  
  366.  
  367. JSPrincipals *
  368. lm_GetPrincipalsFromStackFrame(JSContext *cx)
  369. {
  370.     /*
  371.      * Get principals from script of innermost interpreted frame.
  372.      */
  373.     JSStackFrame *fp;
  374.     JSScript *script;
  375.  
  376.     fp = NULL;
  377.     while ((fp = JS_FrameIterator(cx, &fp)) != NULL) {
  378.         script = JS_GetFrameScript(cx, fp);
  379.         if (script) {
  380.             return JS_GetScriptPrincipals(cx, script);
  381.         }
  382.     }
  383. #ifdef JAVA
  384.     if (JSJ_IsCalledFromJava(cx)) {
  385.         return LM_GetJSPrincipalsFromJavaCaller(cx, 0);
  386.     }
  387. #endif
  388.  
  389.     return NULL;
  390. }
  391.  
  392. const char *
  393. lm_GetSubjectOriginURL(JSContext *cx)
  394. {
  395.     /*
  396.      * Get origin from script of innermost interpreted frame.
  397.      */
  398.     JSPrincipals *principals;
  399.     JSStackFrame *fp;
  400.     JSScript *script;
  401.     JRIEnv *env;
  402.     char *str;
  403.     MochaDecoder *running;
  404.  
  405.     fp = NULL;
  406.     while ((fp = JS_FrameIterator(cx, &fp)) != NULL) {
  407.         script = JS_GetFrameScript(cx, fp);
  408.         if (script) {
  409.             principals = JS_GetScriptPrincipals(cx, script);
  410.             return principals
  411.                 ? principals->codebase
  412.                 : JS_GetScriptFilename(cx, script);
  413.         }
  414.     }
  415.  
  416. #ifdef JAVA
  417.     /* fell off the js stack, look to see if there's a java
  418.      * classloader above us that has MAYSCRIPT set on it */
  419.     if (JSJ_IsCalledFromJava(cx)) {
  420.         env = LJ_JSJ_CurrentEnv(cx);
  421.         if (!env) {
  422.             return NULL;
  423.         }
  424.  
  425.         str = LJ_GetAppletScriptOrigin(env);
  426.         if (!str)
  427.         return NULL;
  428.         return str;
  429.     }
  430. #endif
  431.  
  432.     /*
  433.      * Not called from either JS or Java. We must be called
  434.      * from the interpreter. Get the origin from the decoder.
  435.      */
  436.     running = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  437.     return lm_GetObjectOriginURL(cx, running->window_object);
  438. }
  439.  
  440. /*
  441.  * Reference count ZIGs to increase sharing since creating
  442.  * them is so expensive.
  443.  */
  444. typedef struct SharedZig {
  445.     ZIG *zig;
  446.     int32 refCount;
  447.     JRIGlobalRef zigObjectRef;
  448. } SharedZig;
  449.  
  450. static SharedZig *
  451. newSharedZig(JRIEnv *env, zip_t *zip)
  452. {
  453. #ifdef JAVA
  454.     ZIG *zig;
  455.     SharedZig *result;
  456.     struct netscape_security_Zig *zigObject = NULL;
  457.     JRIGlobalRef zigObjectRef;
  458.  
  459.     zig = LJ_InitializeZig(zip);
  460.     if (zig == NULL)
  461.         return NULL;
  462.  
  463.     zigObject = ns_createZigObject(env, zig);
  464.     if (zigObject == NULL) {
  465.         SOB_destroy(zig);
  466.         return NULL;
  467.     }
  468.  
  469.     /* 
  470.      * From this point on, Java will call SOB_destroy, when java ref 
  471.      * count goes to zero.
  472.      */
  473.     zigObjectRef = JRI_NewGlobalRef(env, zigObject);
  474.     if (zigObjectRef == NULL) {
  475.         return NULL;
  476.     }
  477.  
  478.     result = (SharedZig *) XP_ALLOC(sizeof(SharedZig));
  479.     if (result == NULL) {
  480.         JRI_DisposeGlobalRef(env, zigObjectRef);
  481.         return NULL;
  482.     }
  483.     result->zig = zig;
  484.     result->refCount = 0;
  485.     result->zigObjectRef = zigObjectRef;
  486.     return result;
  487. #else
  488.     return NULL;
  489. #endif
  490. }
  491.  
  492. static void
  493. destroySharedZig(JRIEnv *env, SharedZig *sharedZig)
  494. {
  495. #ifdef JAVA
  496.     /* ZigObject will call SOB_destroy when java reference count goes to zero */
  497.     JRI_DisposeGlobalRef(env, sharedZig->zigObjectRef);
  498.     XP_FREE(sharedZig);
  499. #endif
  500. }
  501.  
  502. static SharedZig *
  503. holdZig(JRIEnv *env, SharedZig *sharedZig)
  504. {
  505. #ifdef JAVA
  506.     if (sharedZig) {
  507.         XP_ASSERT(sharedZig->refCount >= 0);
  508.         /* XXX: Why are you checking this again */
  509.         if (sharedZig)
  510.             sharedZig->refCount++;
  511.     }
  512.     return sharedZig;
  513. #else
  514.     return NULL;
  515. #endif
  516. }
  517.  
  518. static void
  519. dropZig(JRIEnv *env, SharedZig *sharedZig)
  520. {
  521. #ifdef JAVA
  522.     if (sharedZig) {
  523.         XP_ASSERT(sharedZig->refCount > 0);
  524.         if (--sharedZig->refCount == 0) {
  525.             destroySharedZig(env, sharedZig);
  526.         }
  527.     }
  528. #endif
  529. }
  530.  
  531. struct JSPrincipalsList {
  532.     JSPrincipals *principals;
  533.     struct JSPrincipalsList *next;
  534. };
  535.  
  536. void
  537. lm_DestroyPrincipalsList(JSContext *cx, JSPrincipalsList *p)
  538. {
  539.     while (p) {
  540.     JSPrincipalsList *next = p->next;
  541.     if (p->principals)
  542.         JSPRINCIPALS_DROP(cx, p->principals);
  543.     XP_FREE(p);
  544.     p = next;
  545.     }
  546. }
  547.  
  548. enum Signedness {
  549.     HAS_NO_SCRIPTS,
  550.     HAS_UNSIGNED_SCRIPTS,
  551.     HAS_SIGNED_SCRIPTS
  552. };
  553.  
  554. #ifdef DEBUG_norris
  555. static int serial;
  556. #endif
  557.  
  558. typedef struct JSPrincipalsData {
  559.     JSPrincipals principals;
  560.     SharedZig *sharedZig;
  561.     JRIGlobalRef principalsArrayRef;
  562.     URL_Struct *url_struct;
  563.     char *name;
  564.     zip_t *zip;
  565.     uint32 externalCapturePrincipalsCount;
  566.     char *untransformed;
  567.     char *transformed;
  568.     JSBool needUnlock;
  569.     char *codebaseBeforeSettingDomain;
  570. #ifdef DEBUG_norris
  571.     int serial;
  572. #endif
  573.     enum Signedness signedness;
  574. } JSPrincipalsData;
  575.  
  576. PR_STATIC_CALLBACK(void)
  577. destroyJSPrincipals(JSContext *cx, JSPrincipals *principals);
  578.  
  579. static JSBool
  580. principalsCanAccessTarget(JSContext *cx, JSTarget target);
  581.  
  582. PR_STATIC_CALLBACK(void *)
  583. getPrincipalArray(JSContext *cx, struct JSPrincipals *principals);
  584.  
  585. PR_STATIC_CALLBACK(JSBool)
  586. globalPrivilegesEnabled(JSContext *cx, JSPrincipals *principals);
  587.  
  588. static struct netscape_security_PrivilegeManager *
  589. getPrivilegeManager(JRIEnv *env);
  590.  
  591. static JSPrincipalsData unknownPrincipals = {
  592.     {
  593.         lm_unknown_origin_str,
  594.         getPrincipalArray,
  595.         globalPrivilegesEnabled,
  596.         0,
  597.         destroyJSPrincipals
  598.     },
  599.     NULL
  600. };
  601.  
  602. static char *
  603. getOriginFromSourceURL(const char *sourceURL)
  604. {
  605.     char *s;
  606.     char *result;
  607.     int urlType;
  608.  
  609.     if (*sourceURL == '\0' || XP_STRCMP(sourceURL, lm_unknown_origin_str) == 0) {
  610.         return XP_STRDUP(lm_unknown_origin_str);
  611.     }
  612.     urlType = NET_URL_Type(sourceURL);
  613.     if (urlType == WYSIWYG_TYPE_URL) {
  614.         sourceURL = LM_SkipWysiwygURLPrefix(sourceURL);
  615.     } else if (urlType == MOCHA_TYPE_URL) {
  616.         XP_ASSERT(JS_FALSE);    /* this shouldn't occur */
  617.         return XP_STRDUP(lm_unknown_origin_str);
  618.     }
  619.     s = strip_file_double_slash(sourceURL);
  620.     if (s == NULL)
  621.         return NULL;
  622.     result = NET_ParseURL(s, GET_PROTOCOL_PART|GET_HOST_PART|GET_PATH_PART);
  623.     PR_FREEIF(s);
  624.     return result;
  625. }
  626.  
  627. static char *
  628. getJavaCodebaseFromOrigin(const char *origin)
  629. {
  630.     /* Remove filename part. */
  631.     char *result = XP_STRDUP(origin);
  632.     if (result) {
  633.         char *slash = XP_STRRCHR(result, '/');
  634.         if (slash && slash > result && slash[-1] != '/')
  635.             slash[1] = '\0';
  636.     }
  637.     return result;
  638. }
  639.  
  640.  
  641. extern JSPrincipals *
  642. LM_NewJSPrincipals(URL_Struct *archive, char *id, const char *codebase)
  643. {
  644.     JSPrincipalsData *result;
  645.     JSBool needUnlock = JS_FALSE;
  646.     zip_t *zip = NULL;
  647.  
  648.     if (archive) {
  649.         char *fn = NULL;
  650.  
  651.         if (NET_IsLocalFileURL(archive->address)) {
  652.             char* pathPart = NET_ParseURL(archive->address, GET_PATH_PART);
  653.             NET_UnEscape(pathPart); /* Handle "file:D%7C/dir/file.zip" */
  654.             fn = WH_FileName(pathPart, xpURL);
  655.             XP_FREE(pathPart);
  656.         } else if (archive->cache_file && NET_ChangeCacheFileLock(archive, TRUE)) {
  657.             fn = WH_FileName(archive->cache_file, xpCache);
  658.             needUnlock = JS_TRUE;
  659.         }
  660.  
  661.         if (fn) {
  662. #ifdef XP_MAC
  663.             /*
  664.              * Unfortunately, zip_open wants a Unix-style name. Convert Mac path
  665.              * to a Unix-style path. This code is copied from appletStubs.c.
  666.              */
  667.             OSErr ConvertMacPathToUnixPath(const char *macPath, char **unixPath);
  668.             char *unixPath = NULL;
  669.  
  670.             if (ConvertMacPathToUnixPath(fn, &unixPath) == 0) {
  671.                 zip = zip_open(unixPath);
  672.             }
  673.             XP_FREEIF(unixPath);
  674. #else
  675.             zip = zip_open(fn);
  676. #endif
  677.             XP_FREE(fn);
  678.         }
  679.     }
  680.  
  681.     result = XP_NEW_ZAP(JSPrincipalsData);
  682.     if (result == NULL)
  683.         return NULL;
  684.     result->principals.codebase = codebase
  685.         ? getOriginFromSourceURL(codebase)
  686.         : NULL;
  687.     if (result->principals.codebase == NULL) {
  688.         result->principals.codebase = XP_STRDUP(lm_unknown_origin_str);
  689.         if (result->principals.codebase == NULL) {
  690.             XP_FREE(result);
  691.             return NULL;
  692.         }
  693.     }
  694.     if (id) {
  695.         result->name = XP_STRDUP(id);
  696.         if (result->name == NULL) {
  697.             XP_FREE(result);
  698.             return NULL;
  699.         }
  700.     }
  701.     result->principals.destroy = destroyJSPrincipals;
  702.     result->principals.getPrincipalArray = getPrincipalArray;
  703.     result->principals.globalPrivilegesEnabled = globalPrivilegesEnabled;
  704.     result->url_struct = NET_HoldURLStruct(archive);
  705.     result->zip = zip;
  706.     result->needUnlock = needUnlock;
  707. #ifdef DEBUG_norris
  708.     result->serial = ++serial;
  709.     XP_TRACE(("JSPrincipals #%.4d allocated\n", serial));
  710. #endif
  711.  
  712.     return (JSPrincipals *) result;
  713. }
  714.  
  715.  
  716. PR_STATIC_CALLBACK(void)
  717. destroyJSPrincipals(JSContext *cx, JSPrincipals *principals)
  718. {
  719.     if (principals != NULL &&
  720.         principals != (JSPrincipals *) &unknownPrincipals)
  721.     {
  722.         JSPrincipalsData *data = (JSPrincipalsData *) principals;
  723. #ifdef JAVA
  724.         JRIEnv *env = NULL;
  725.         if (data->sharedZig || data->principalsArrayRef) {
  726.             /* Avoid starting Java if "env" not needed */
  727.             env = LJ_JSJ_CurrentEnv(cx);
  728.         }
  729. #endif /* JAVA */
  730.  
  731. #ifdef DEBUG_norris
  732.         XP_TRACE(("JSPrincipals #%.4d released\n", data->serial));
  733. #endif
  734.         XP_FREEIF(principals->codebase);
  735. #ifdef JAVA
  736.         if (env && data->sharedZig) {
  737.             dropZig(env, data->sharedZig);
  738.         }
  739.         if (env && (data->principalsArrayRef != NULL)) {
  740.             JRI_DisposeGlobalRef(env, data->principalsArrayRef);
  741.         }
  742. #endif /* JAVA */
  743.         XP_FREEIF(data->name);
  744.         XP_FREEIF(data->untransformed);
  745.         XP_FREEIF(data->transformed);
  746.         if (data->zip)
  747.             zip_close(data->zip);
  748.         if (data->needUnlock)
  749.             NET_ChangeCacheFileLock(data->url_struct, FALSE);
  750.         if (data->url_struct)
  751.             NET_DropURLStruct(data->url_struct);
  752.         XP_FREEIF(data->codebaseBeforeSettingDomain);
  753.         XP_FREE(data);
  754.     }
  755. }
  756.  
  757. PR_STATIC_CALLBACK(JSBool)
  758. globalPrivilegesEnabled(JSContext *cx, JSPrincipals *principals)
  759. {
  760.     JSPrincipalsData *data = (JSPrincipalsData *) principals;
  761.  
  762.     return (JSBool)(data->principalsArrayRef != NULL ||
  763.            XP_STRCMP(principals->codebase, lm_unknown_origin_str) != 0);
  764. }
  765.  
  766. static void
  767. printPrincipalsToConsole(JSContext *cx, JSPrincipals *principals)
  768. {
  769. #ifdef JAVA
  770.     JRIEnv *env;
  771.     jobjectArray principalsArray;
  772.     struct netscape_security_Principal *principal;
  773.     struct java_lang_String *javaString;
  774.     uint32 i, count;
  775.     static char emptyStr[] = "<empty>\n";
  776.  
  777.     env = LJ_JSJ_CurrentEnv(cx);
  778.     if (env == NULL) {
  779.         return;
  780.     }
  781.  
  782.     principalsArray = principals->getPrincipalArray(cx, principals);
  783.  
  784.     if (principalsArray == NULL) {
  785.         PrintToConsole(emptyStr);
  786.         return;
  787.     }
  788.  
  789.     PrintToConsole("[\n");
  790.     count = JRI_GetObjectArrayLength(env, principalsArray);
  791.     for (i = 0; i < count; i++) {
  792.         principal = JRI_GetObjectArrayElement(env, principalsArray, i);
  793.         javaString = netscape_security_Principal_getVendor(env, principal);
  794.         if (javaString) {
  795.             const char *s = JRI_GetStringPlatformChars(env, javaString,
  796.                                      (const jbyte *)cx->charSetName,
  797.                                      (jint)cx->charSetNameLength);
  798.             if (s == NULL) {
  799.                 JS_ReportOutOfMemory(cx);
  800.                 return;
  801.             }
  802.             PrintToConsole(s);
  803.         }
  804.         PrintToConsole(",\n");
  805.     }
  806.     PrintToConsole("]\n");
  807. #endif /* JAVA */
  808. }
  809.  
  810. extern void
  811. lm_InvalidateCertPrincipals(MochaDecoder *decoder, JSPrincipals *principals)
  812. {
  813.     JSPrincipalsData *data = (JSPrincipalsData *) principals;
  814. #ifdef JAVA
  815.     JRIEnv *env;
  816.  
  817.     if (data->principalsArrayRef) {
  818.         PrintToConsole("Invalidating certificate principals in ");
  819.         printPrincipalsToConsole(decoder->js_context, principals);
  820.         env = LJ_JSJ_CurrentEnv(decoder->js_context);
  821.         if (env != NULL) {
  822.             JRI_DisposeGlobalRef(env, data->principalsArrayRef);
  823.         }
  824.         data->principalsArrayRef = NULL;
  825.     }
  826. #endif /* JAVA */
  827.     data->signedness = HAS_UNSIGNED_SCRIPTS;
  828. }
  829.  
  830. extern JSBool
  831. lm_SetDocumentDomain(JSContext *cx, JSPrincipals *principals,
  832.                      const char *codebase)
  833. {
  834.     JSPrincipalsData *data;
  835.  
  836.     if (principals->codebase == codebase)
  837.        return JS_TRUE;
  838.     data = (JSPrincipalsData *) principals;
  839.     if (data->codebaseBeforeSettingDomain == NULL)
  840.         data->codebaseBeforeSettingDomain = principals->codebase;
  841.     else
  842.         XP_FREEIF(principals->codebase);
  843.     principals->codebase = getOriginFromSourceURL(codebase);
  844.     if (principals->codebase == NULL) {
  845.         JS_ReportOutOfMemory(cx);
  846.         return JS_FALSE;
  847.     }
  848. #ifdef JAVA
  849.     if (data->principalsArrayRef != NULL) {
  850.         JRIEnv *env = LJ_JSJ_CurrentEnv(cx);
  851.         if (env == NULL) {
  852.             return JS_FALSE;
  853.         }
  854.         JRI_DisposeGlobalRef(env, data->principalsArrayRef);
  855.         data->principalsArrayRef = NULL;
  856.     }
  857. #endif /* JAVA */
  858.     return JS_TRUE;
  859. }
  860.  
  861. JSPrincipals *
  862. lm_GetInnermostPrincipals(JSContext *cx, JSObject *container,
  863.                           JSObject **foundIn)
  864. {
  865.     /* Get innermost non-null principals */
  866.     while (container) {
  867.         if (foundIn)
  868.             *foundIn = container;
  869.         if (JS_InstanceOf(cx, container, &lm_layer_class, 0)) {
  870.             JSPrincipals *principals = lm_GetContainerPrincipals(cx, container);
  871.             if (principals)
  872.                 return principals;
  873.         } else if (JS_InstanceOf(cx, container, &lm_window_class, 0)) {
  874.             MochaDecoder *decoder = JS_GetInstancePrivate(cx, container,
  875.                                                           &lm_window_class,
  876.                                                           NULL);
  877.             const char *origin_url;
  878.  
  879.         /* 
  880.              * We need to check that the origin hasn't changed underneath 
  881.              * us as a result of user navigation. 
  882.              */
  883.             origin_url = find_origin_url(cx, decoder);
  884.             if (!origin_url)
  885.                 return NULL;
  886.             if (decoder->principals) {
  887.                 JSPrincipalsData *data;
  888.  
  889.                 if (sameOrigins(cx, origin_url, decoder->principals->codebase))
  890.                     return decoder->principals;
  891.                 data = (JSPrincipalsData *) decoder->principals;
  892.                 if (data->codebaseBeforeSettingDomain &&
  893.                     sameOrigins(cx, origin_url, 
  894.                                 data->codebaseBeforeSettingDomain))
  895.                 {
  896.                     /* document.domain was set, so principals are okay */
  897.                     return decoder->principals;
  898.                 }
  899.                 /* Principals have changed underneath us. Remove them. */
  900.                 JSPRINCIPALS_DROP(cx, decoder->principals);
  901.                 decoder->principals = NULL;
  902.             }
  903.             /* Create new principals and return them. */
  904.             decoder->principals = LM_NewJSPrincipals(NULL, NULL, origin_url);
  905.             if (decoder->principals == NULL) {
  906.                 JS_ReportOutOfMemory(cx);
  907.                 return NULL;
  908.             }
  909.             JSPRINCIPALS_HOLD(cx, decoder->principals);
  910.             return decoder->principals;
  911.         }
  912.         container = JS_GetParent(cx, container);
  913.     }
  914.     if (foundIn)
  915.         *foundIn = NULL;
  916.     return (JSPrincipals *) &unknownPrincipals;
  917. }
  918.  
  919. static JSPropertyOp oldParentSlotSetter = NULL;
  920.  
  921. PR_STATIC_CALLBACK(JSBool)
  922. setParentSlot(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  923. {
  924.     JSObject *newParent;
  925.  
  926.     if (!JSVAL_IS_OBJECT(*vp))
  927.     return JS_TRUE;
  928.     newParent = JSVAL_TO_OBJECT(*vp);
  929.     if (newParent) {
  930.         const char *oldOrigin = lm_GetObjectOriginURL(cx, obj);
  931.         const char *newOrigin = lm_GetObjectOriginURL(cx, newParent);
  932.         if (!sameOrigins(cx, oldOrigin, newOrigin))
  933.             return JS_TRUE;
  934.     } else {
  935.         if (!JS_InstanceOf(cx, obj, &lm_layer_class, 0) && 
  936.             !JS_InstanceOf(cx, obj, &lm_window_class, 0))
  937.         {
  938.             return JS_TRUE;
  939.         }
  940.         if (lm_GetContainerPrincipals(cx, obj) == NULL) {
  941.             JSPrincipals *principals;
  942.             principals = lm_GetInnermostPrincipals(cx, obj, NULL);
  943.             if (principals == NULL)
  944.                 return JS_FALSE;
  945.             lm_SetContainerPrincipals(cx, obj, principals);
  946.         }
  947.     }
  948.     return (*oldParentSlotSetter)(cx, obj, id, vp);
  949. }
  950.  
  951. JSBool
  952. lm_AddSetParentSecurityCheck(JSContext *cx, JSObject *obj) 
  953. {
  954.     JSAtom *atom;
  955.     JSObject *proto;
  956.     static char parentName[] = "__parent__";
  957.     JSProperty *prop;
  958.     JSBool ok;
  959.  
  960.     /*
  961.      * Set up to intercept attempts to set __parent__. We need to check
  962.      * that an evil script is not changing the parent links so that it
  963.      * gains access to restricted information.
  964.      */
  965.     proto = obj;
  966.     for(;;) {
  967.         JSObject *next = JS_GetPrototype(cx, proto);
  968.         if (next == NULL)
  969.             break;
  970.         proto = next;
  971.     }
  972.     atom = js_Atomize(cx, parentName, sizeof(parentName)-1, 0); 
  973.     if (atom == NULL) 
  974.         return JS_FALSE;
  975.     ok = js_LookupProperty(cx, proto, (jsval)atom, NULL, &prop);
  976.     js_DropAtom(cx, atom);
  977.     if (!ok || prop == NULL)
  978.         return JS_FALSE;
  979.     if (oldParentSlotSetter == NULL)
  980.         oldParentSlotSetter = prop->setter;
  981.     prop->setter = setParentSlot;
  982.     return JS_TRUE;
  983. }
  984.  
  985.  
  986. static JSBool
  987. canExtendTrust(JSContext *cx, void *from, void *to)
  988. {
  989. #ifdef JAVA
  990.     JRIEnv *env = LJ_JSJ_CurrentEnv(cx);
  991.     if (env == NULL) {
  992.         return JS_FALSE;
  993.     }
  994.     if (from == NULL || to == NULL) {
  995.         return JS_FALSE;
  996.     }
  997.     return (JSBool)netscape_security_PrivilegeManager_canExtendTrust(
  998.                     env,
  999.                     getPrivilegeManager(env),
  1000.                     from,
  1001.                     to);
  1002. #else
  1003.     /* should never be called without signed scripts */
  1004.     XP_ASSERT(0);
  1005.     return JS_FALSE;
  1006. #endif /* JAVA */
  1007. }
  1008.  
  1009. static JSPrincipals *
  1010. newJSPrincipalsFromArray(JSContext *cx, jobjectArray principalsArray);
  1011.  
  1012. extern JSBool
  1013. lm_CheckContainerAccess(JSContext *cx, JSObject *obj, MochaDecoder *decoder,
  1014.                         JSTarget target)
  1015. {
  1016.     JSPrincipals *principals;
  1017.     JSPrincipalsData *data;
  1018.     JRIEnv *env;
  1019.     JSStackFrame *fp;
  1020.     JSScript *script;
  1021.     JSPrincipals *subjPrincipals;
  1022.     JSPrincipalsList *list;
  1023.     const char *fn;
  1024.  
  1025.     principals = decoder->principals
  1026.                  ? lm_GetInnermostPrincipals(decoder->js_context, obj, NULL)
  1027.                  : NULL;
  1028.     if (principals == NULL) {
  1029.         /*
  1030.          * Attempt to access container before container has any scripts.
  1031.          * Most of these accesses come from natives when initializing a
  1032.          * window. Check for that by seeing if we have an executing script.
  1033.          * If we do, remember the principals of the script that performed
  1034.          * the access so we can report an error later if need be.
  1035.          */
  1036.         fp = NULL;
  1037.         subjPrincipals = lm_GetPrincipalsFromStackFrame(cx);
  1038.         if (subjPrincipals == NULL) {
  1039.             return JS_TRUE;
  1040.         }
  1041.  
  1042.         /* See if subjPrincipals are already on list */
  1043.         list = (JSPrincipalsList *) decoder->early_access_list;
  1044.         while (list && list->principals != subjPrincipals) {
  1045.             list = list->next;
  1046.         }
  1047.         if (list == NULL) {
  1048.         list = XP_ALLOC(sizeof(*list));
  1049.             if (list == NULL) {
  1050.                 JS_ReportOutOfMemory(cx);
  1051.         return JS_FALSE;
  1052.             }
  1053.         list->principals = subjPrincipals;
  1054.         JSPRINCIPALS_HOLD(cx, list->principals);
  1055.         list->next = (JSPrincipalsList *) decoder->early_access_list;
  1056.         decoder->early_access_list = list;
  1057.         }
  1058.     /*
  1059.      * XXX - Still possible to modify contents of another page
  1060.      * even if cross-origin access is disabled by setting to
  1061.      * about:blank, modifying, and then loading the attackee.
  1062.          * Similarly with window.open("").
  1063.      */
  1064.         return JS_TRUE;
  1065.     }
  1066.  
  1067.     /* 
  1068.      * If object doesn't have signed scripts and cross-origin access 
  1069.      * is enabled, return true. 
  1070.      */
  1071.     data = (JSPrincipalsData *) principals;
  1072.     if (data->signedness != HAS_SIGNED_SCRIPTS && lm_GetCrossOriginEnabled())
  1073.         return JS_TRUE;
  1074.  
  1075.     /* Check if user requested lower privileges */
  1076.  
  1077.     if (data->signedness == HAS_SIGNED_SCRIPTS &&
  1078.         !lm_GetPrincipalsCompromise(cx, obj))
  1079.     {
  1080.         /*
  1081.          * We have signed scripts. Must check that the object principals are
  1082.          * a subset of the the subject principals.
  1083.          */
  1084.         env = LJ_JSJ_CurrentEnv(cx);
  1085.         if (env == NULL) {
  1086.             return JS_FALSE;
  1087.         }
  1088.         fp = NULL;
  1089.         fp = JS_FrameIterator(cx, &fp);
  1090.         if (fp == NULL || (script = JS_GetFrameScript(cx, fp)) == NULL) {
  1091.             /* haven't begun execution yet; allow the parser to create functions */
  1092.             return JS_TRUE;
  1093.         }
  1094.         subjPrincipals = JS_GetScriptPrincipals(cx, script);
  1095.         if (subjPrincipals &&
  1096.             canExtendTrust(cx,
  1097.                 principals->getPrincipalArray(cx, principals),
  1098.                 subjPrincipals->getPrincipalArray(cx, subjPrincipals)))
  1099.         {
  1100.             return JS_TRUE;
  1101.         }
  1102.         fn = lm_GetSubjectOriginURL(cx);
  1103.     if (!fn)
  1104.         return JS_FALSE;
  1105.         if (subjPrincipals && principals) {
  1106.             PrintToConsole("Principals of script: ");
  1107.             printPrincipalsToConsole(cx, subjPrincipals);
  1108.             PrintToConsole("Principals of signed container: ");
  1109.             printPrincipalsToConsole(cx, principals);
  1110.         }
  1111.         JS_ReportError(cx, container_error_message, fn);
  1112.         return JS_FALSE;
  1113.     }
  1114.  
  1115.     /* The signed script has called compromisePrincipals(), so
  1116.      * we do the weaker origin check.
  1117.      */
  1118.     return lm_CheckPermissions(cx, obj, target);
  1119. }
  1120.  
  1121. static JSBool
  1122. checkEarlyAccess(MochaDecoder *decoder, JSPrincipals *principals)
  1123. {
  1124.     JSContext *cx;
  1125.     JSPrincipalsData *data;
  1126.     JSPrincipalsList *p;
  1127.     JSBool ok;
  1128.  
  1129.     cx = decoder->js_context;
  1130.     data = (JSPrincipalsData *) principals;
  1131.     ok = JS_TRUE;
  1132.  
  1133.     for (p = (JSPrincipalsList *) decoder->early_access_list; p; p = p->next) {
  1134.         if (data->signedness == HAS_SIGNED_SCRIPTS) {
  1135.             if (!canExtendTrust(cx,
  1136.                         principals->getPrincipalArray(cx, principals),
  1137.                     p->principals->getPrincipalArray(cx,
  1138.                                                                  p->principals)))
  1139.             {
  1140.                 JS_ReportError(cx, container_error_message,
  1141.                                p->principals->codebase);
  1142.                 ok = JS_FALSE;
  1143.                 break;
  1144.             }
  1145.         } else {
  1146.             if (!sameOrigins(cx, p->principals->codebase,
  1147.                      principals->codebase))
  1148.             {
  1149.                 /*
  1150.                  * Check to see if early access violated the cross-origin
  1151.                  * container check.
  1152.                  */
  1153.                 JS_ReportError(cx, access_error_message,
  1154.                        p->principals->codebase);
  1155.                 ok = JS_FALSE;
  1156.                 break;
  1157.             }
  1158.         }
  1159.     }
  1160.     lm_DestroyPrincipalsList(cx, decoder->early_access_list);
  1161.     decoder->early_access_list = NULL;
  1162.     return ok;
  1163. }
  1164.  
  1165. /*
  1166.  * Compute the intersection of "principals" and "other", saving in
  1167.  * "principals". Return true iff the intersection is nonnull.
  1168.  */
  1169. static JSBool
  1170. intersectPrincipals(MochaDecoder *decoder, JSPrincipals *principals,
  1171.                     JSPrincipals *newPrincipals)
  1172. {
  1173.     JSPrincipalsData *data = (JSPrincipalsData *) principals;
  1174.     JSPrincipalsData *newData = (JSPrincipalsData *) newPrincipals;
  1175.     JSContext *cx;
  1176. #ifdef JAVA
  1177.     JRIEnv *env;
  1178.     struct netscape_security_PrivilegeManager *privilegeManager;
  1179.     jobjectArray principalArray, newPrincipalArray;
  1180.     JRIGlobalRef principalsArrayRef;
  1181. #endif /* JAVA */
  1182.  
  1183.     XP_ASSERT(data->signedness != HAS_NO_SCRIPTS);
  1184.     XP_ASSERT(newData->signedness != HAS_NO_SCRIPTS);
  1185.  
  1186.     cx = decoder->js_context;
  1187.     if (!sameOrigins(cx, principals->codebase, newPrincipals->codebase)) {
  1188.         XP_FREEIF(principals->codebase);
  1189.         principals->codebase = JS_strdup(cx, lm_unknown_origin_str);
  1190.         if (principals->codebase == NULL) {
  1191.             return JS_FALSE;
  1192.         }
  1193.     }
  1194.  
  1195.     if (data->signedness == HAS_UNSIGNED_SCRIPTS ||
  1196.         newData->signedness == HAS_UNSIGNED_SCRIPTS)
  1197.     {
  1198.         /*
  1199.          * No cert principals. Nonempty only if there is a codebase
  1200.          * principal.
  1201.          */
  1202.         lm_InvalidateCertPrincipals(decoder, principals);
  1203.         return JS_TRUE;
  1204.     }
  1205. #ifdef JAVA 
  1206.     /* Compute the intersection. */
  1207.     env = LJ_JSJ_CurrentEnv(cx);
  1208.     if (env == NULL) {
  1209.         lm_InvalidateCertPrincipals(decoder, principals);
  1210.         return globalPrivilegesEnabled(cx, principals);
  1211.     }
  1212.     privilegeManager = getPrivilegeManager(env);
  1213.     principalArray = getPrincipalArray(cx, principals);
  1214.     newPrincipalArray = getPrincipalArray(cx, newPrincipals);
  1215.     if (privilegeManager == NULL || principalArray == NULL
  1216.         || newPrincipalArray == NULL)
  1217.     {
  1218.         lm_InvalidateCertPrincipals(decoder, principals);
  1219.         return JS_TRUE;
  1220.     }
  1221.  
  1222.     principalArray = netscape_security_PrivilegeManager_intersectPrincipalArray(
  1223.         env, privilegeManager, principalArray, newPrincipalArray);
  1224.     principalsArrayRef = JRI_NewGlobalRef(env, principalArray);
  1225.  
  1226.     if (principalArray == NULL) {
  1227.         lm_InvalidateCertPrincipals(decoder, principals);
  1228.         return JS_TRUE;
  1229.     }
  1230.  
  1231.     JRI_DisposeGlobalRef(env, data->principalsArrayRef);
  1232.     data->principalsArrayRef = principalsArrayRef;
  1233.     return JS_TRUE;
  1234. #else
  1235.     XP_ASSERT(0); /* should never get here without signed scripts */
  1236.     return JS_FALSE;
  1237. #endif /* JAVA */
  1238. }
  1239.  
  1240. static uint32
  1241. getPrincipalsCount(JSContext *cx, JSPrincipals *principals)
  1242. {
  1243. #ifdef JAVA
  1244.     JRIEnv *env;
  1245.     jref principalArray;
  1246.  
  1247.     env = LJ_JSJ_CurrentEnv(cx);
  1248.     if (env == NULL) {
  1249.         return 0;
  1250.     }
  1251.  
  1252.     /* Get array of principals */
  1253.     principalArray = getPrincipalArray(cx, principals);
  1254.  
  1255.     return principalArray ? JRI_GetObjectArrayLength(env, principalArray) : 0;
  1256. #else
  1257.     return 0;
  1258. #endif /* JAVA */
  1259. }
  1260.  
  1261. static JSBool
  1262. principalsEqual(JSContext *cx, JSPrincipals *a, JSPrincipals *b)
  1263. {
  1264. #ifdef JAVA
  1265.     JSPrincipalsData *dataA, *dataB;
  1266.     jobjectArray arrayA, arrayB;
  1267.     JRIEnv *env;
  1268.  
  1269.     if (a == b)
  1270.         return JS_TRUE;
  1271.  
  1272.     dataA = (JSPrincipalsData *) a;
  1273.     dataB = (JSPrincipalsData *) b;
  1274.  
  1275.     if (dataA->signedness != dataB->signedness)
  1276.         return JS_FALSE;
  1277.  
  1278.     arrayA = getPrincipalArray(cx, a);
  1279.     arrayB = getPrincipalArray(cx, b);
  1280.  
  1281.     env = LJ_JSJ_CurrentEnv(cx);
  1282.     if (env == NULL) {
  1283.         return JS_FALSE;
  1284.     }
  1285.  
  1286.     return (JSBool)(netscape_security_PrivilegeManager_comparePrincipalArray(env,
  1287.                     getPrivilegeManager(env),
  1288.                     arrayA,
  1289.                     arrayB)
  1290.                 == netscape_security_PrivilegeManager_EQUAL);
  1291. #else
  1292.     /* Shouldn't get here without signed scripts */
  1293.     XP_ASSERT(0);
  1294.     return JS_FALSE;
  1295. #endif /* JAVA */
  1296. }
  1297.  
  1298. /*
  1299.  * createPrincipalsArray takes ZIG file information and returns a
  1300.  * reference to a Java array of Java Principal objects.
  1301.  * It also registers the principals with the PrivilegeManager.
  1302.  */
  1303. static jref
  1304. createPrincipalsArray(JRIEnv *env,
  1305.                       struct netscape_security_PrivilegeManager *privilegeManager,
  1306.                       JSPrincipals *principals)
  1307. {
  1308. #ifdef JAVA 
  1309.     JSPrincipalsData *data = (JSPrincipalsData *) principals;
  1310.     JSBool hasCodebase;
  1311.     SOBITEM *item;
  1312.     int i;
  1313.     ZIG *zig;
  1314.     struct java_lang_Class *principalClass;
  1315.     unsigned count;
  1316.     jref result;
  1317.     jref byteArray;
  1318.     struct netscape_security_Principal *principal;
  1319.     ZIG_Context * zig_cx = NULL;
  1320.     void *zigObj;
  1321.  
  1322.     if (principals == (JSPrincipals *) &unknownPrincipals)
  1323.         return NULL;
  1324.  
  1325.     hasCodebase = (JSBool)(principals->codebase && 
  1326.                   XP_STRCMP(principals->codebase, lm_unknown_origin_str) != 0);
  1327.  
  1328.     /* First count the number of principals */
  1329.     count = hasCodebase ? 1 : 0;
  1330.  
  1331.     zig = data->signedness == HAS_UNSIGNED_SCRIPTS
  1332.         ? NULL
  1333.         : (data->sharedZig ? data->sharedZig->zig : NULL);
  1334.  
  1335.     if (zig && data->name) {
  1336.         /* Make sure file is signed */
  1337.         if ((zig_cx = SOB_find(zig, data->name, ZIG_SIGN)) != NULL) {
  1338.             int zig_count=0;
  1339.             /* count the number of signers */
  1340.             while (SOB_find_next(zig_cx, &item) >= 0) {
  1341.                 zig_count++;
  1342.             }
  1343.             SOB_find_end(zig_cx);
  1344.             count += zig_count;
  1345.         } else {
  1346.           zig = NULL;
  1347.         }
  1348.     }
  1349.  
  1350.     if (count == 0) {
  1351.         return NULL;
  1352.     }
  1353.  
  1354.     /* Now allocate the array */
  1355.     principalClass = class_netscape_security_Principal(env);
  1356.     result = JRI_NewObjectArray(env, count, principalClass, NULL);
  1357.     if (result == NULL) {
  1358.         return NULL;
  1359.     }
  1360.  
  1361.     if (zig && ((zig_cx = SOB_find(zig, data->name, ZIG_SIGN)) == NULL)) {
  1362.         return NULL;
  1363.     }
  1364.  
  1365.     i = 0;
  1366.     if (zig) {
  1367.         zigObj = JRI_GetGlobalRef(env, data->sharedZig->zigObjectRef);
  1368.     }
  1369.     while (zig && SOB_find_next(zig_cx, &item) >= 0) {
  1370.         FINGERZIG *fingPrint;
  1371.  
  1372.         fingPrint = (FINGERZIG *) item->data;
  1373.  
  1374.         /* call java: new Principal(CERT_KEY, fingPrint->key) */
  1375.         byteArray = JRI_NewByteArray(env, fingPrint->length,
  1376.                                      fingPrint->key);
  1377.  
  1378.         principal = netscape_security_Principal_new_5(env,
  1379.             principalClass,
  1380.             netscape_security_Principal_CERT_KEY,
  1381.             byteArray,
  1382.             (struct netscape_security_Zig *)zigObj);
  1383.  
  1384.         netscape_security_PrivilegeManager_registerPrincipal(env,
  1385.             privilegeManager, principal);
  1386.  
  1387.         JRI_SetObjectArrayElement(env, result, i++, principal);
  1388.     }
  1389.     if (zig) {
  1390.          SOB_find_end(zig_cx);
  1391.     }
  1392.  
  1393.     if (hasCodebase) {
  1394.         /* Add a codebase principal. */
  1395.         char *javaCodebase;
  1396.         javaCodebase = getJavaCodebaseFromOrigin(principals->codebase);
  1397.         if (javaCodebase == NULL)
  1398.             return NULL;
  1399.         byteArray = JRI_NewByteArray(env,
  1400.                                      XP_STRLEN(javaCodebase),
  1401.                                      javaCodebase);
  1402.         principal = netscape_security_Principal_new_3(env,
  1403.             principalClass,
  1404.             netscape_security_Principal_CODEBASE_EXACT,
  1405.             byteArray);
  1406.         netscape_security_PrivilegeManager_registerPrincipal(env,
  1407.             privilegeManager, principal);
  1408.         JRI_SetObjectArrayElement(env, result, i++, principal);
  1409.         XP_FREE(javaCodebase);
  1410.     }
  1411.  
  1412.     data->principalsArrayRef = JRI_NewGlobalRef(env, result);
  1413.  
  1414.     return result;
  1415. #else
  1416.     /* This should never be called without signed scripts. */
  1417.     XP_ASSERT(0);
  1418.     return NULL;
  1419. #endif /* JAVA */
  1420. }
  1421.  
  1422. static JSBool
  1423. isExternalCaptureEnabled(JSContext *cx, JSPrincipals *principals)
  1424. {
  1425.     JSPrincipalsData *data = (JSPrincipalsData *) principals;
  1426.  
  1427.     if (data->externalCapturePrincipalsCount == 0) {
  1428.         return JS_FALSE;
  1429.     } else {
  1430.         uint32 count = getPrincipalsCount(cx, principals);
  1431.         return (JSBool)(data->externalCapturePrincipalsCount == count);
  1432.     }
  1433. }
  1434.  
  1435. void
  1436. lm_SetExternalCapture(JSContext *cx, JSPrincipals *principals,
  1437.                       JSBool b)
  1438. {
  1439.     JSPrincipalsData *data = (JSPrincipalsData *) principals;
  1440.  
  1441.     if (b) {
  1442.         uint32 count = getPrincipalsCount(cx, principals);
  1443.         data->externalCapturePrincipalsCount = count;
  1444.     } else {
  1445.         data->externalCapturePrincipalsCount = 0;
  1446.     }
  1447. }
  1448.  
  1449.  
  1450. JSBool
  1451. lm_CanAccessTarget(JSContext *cx, JSTarget target)
  1452. {
  1453.     JSPrincipals *principals;
  1454.  
  1455.     principals = lm_GetPrincipalsFromStackFrame(cx);
  1456.     if (principals && !globalPrivilegesEnabled(cx, principals)) {
  1457.         return JS_FALSE;
  1458.     }
  1459.     if (!principalsCanAccessTarget(cx, target)) {
  1460.         return JS_FALSE;
  1461.     }
  1462.     return JS_TRUE;
  1463. }
  1464.  
  1465. /* This array must be kept in sync with the JSTarget enum in jsapi.h */
  1466. static char *targetStrings[] = {
  1467.     "UniversalBrowserRead",
  1468.     "UniversalBrowserWrite",
  1469.     "UniversalSendMail",
  1470.     "UniversalFileRead",
  1471.     "UniversalFileWrite",
  1472.     "UniversalPreferencesRead",
  1473.     "UniversalPreferencesWrite",
  1474.     /* See Target.java for more targets */
  1475. };
  1476.  
  1477. /* get PrivilegeManager object: call static PrivilegeManager.getPrivilegeManager() */
  1478. static struct netscape_security_PrivilegeManager *
  1479. getPrivilegeManager(JRIEnv *env)
  1480. {
  1481. #ifdef JAVA
  1482.     return netscape_security_PrivilegeManager_getPrivilegeManager(env,
  1483.         JRI_FindClass(env,
  1484.             classname_netscape_security_PrivilegeManager));
  1485. #else
  1486.     return NULL;
  1487. #endif
  1488. }
  1489.  
  1490. /*
  1491. ** If given principals can access the given target, return true. Otherwise return false.
  1492. ** The script must already have explicitly requested access to the given target.
  1493. */
  1494. static JSBool
  1495. principalsCanAccessTarget(JSContext *cx, JSTarget target)
  1496. {
  1497. #ifdef JAVA
  1498.     JRIEnv *env;
  1499.     struct netscape_security_PrivilegeManager *privilegeManager;
  1500.     struct netscape_security_PrivilegeTable *annotation;
  1501.     struct netscape_security_Privilege *privilege;
  1502.     struct netscape_security_Target *javaTarget;
  1503.     struct java_lang_String *javaString;
  1504.     struct java_lang_Class *targetClass;
  1505.     jint perm;
  1506.     JSStackFrame *fp;
  1507.     jglobal annotationRef;
  1508.     void *principalArray = NULL;
  1509.  
  1510.     env = LJ_JSJ_CurrentEnv(cx);
  1511.     if (env == NULL) {
  1512.         return JS_FALSE;
  1513.     }
  1514.  
  1515.     privilegeManager = getPrivilegeManager(env);
  1516.  
  1517.     /* Map JSTarget to netscape_security_Target */
  1518.     XP_ASSERT(target >= 0);
  1519.     XP_ASSERT(target < sizeof(targetStrings)/sizeof(targetStrings[0]));
  1520.     targetClass = JRI_FindClass(env, classname_netscape_security_Target);
  1521.     javaString = makeJavaString(targetStrings[target], strlen(targetStrings[target]));
  1522.     javaTarget = netscape_security_Target_findTarget(env, targetClass, javaString);
  1523.  
  1524.     /* Find annotation */
  1525.     annotationRef = NULL;
  1526.     principalArray = NULL;
  1527.     fp = NULL;
  1528.     while ((fp = JS_FrameIterator(cx, &fp)) != NULL) {
  1529.         void *current;
  1530.         if (JS_GetFrameScript(cx, fp) == NULL)
  1531.             continue;
  1532.         current = JS_GetFramePrincipalArray(cx, fp);
  1533.         if (current == NULL) {
  1534.             return JS_FALSE;
  1535.         }
  1536.         annotationRef = (jglobal) JS_GetFrameAnnotation(cx, fp);
  1537.         if (annotationRef) {
  1538.             if (principalArray &&
  1539.                 !netscape_security_PrivilegeManager_canExtendTrust(
  1540.                     env, privilegeManager, current, principalArray))
  1541.             {
  1542.                 return JS_FALSE;
  1543.             }
  1544.             break;
  1545.         }
  1546.         principalArray = principalArray
  1547.             ? netscape_security_PrivilegeManager_intersectPrincipalArray(
  1548.                 env, privilegeManager, principalArray, current)
  1549.             : current;
  1550.     }
  1551.  
  1552.     if (annotationRef) {
  1553.         annotation = (struct netscape_security_PrivilegeTable *)
  1554.             JRI_GetGlobalRef(env, annotationRef);
  1555.     } else if (JSJ_IsCalledFromJava(cx)) {
  1556.         /*
  1557.          * Call from Java into JS. Just call the Java routine for checking
  1558.          * privileges.
  1559.          */
  1560.         if (principalArray) {
  1561.             /*
  1562.              * Must check that the principals that signed the Java applet are
  1563.              * a subset of the principals that signed this script.
  1564.              */
  1565.             jobjectArray javaPrincipals;
  1566.  
  1567.             javaPrincipals =
  1568.                 netscape_security_PrivilegeManager_getClassPrincipalsFromStack(
  1569.                     env,
  1570.                     privilegeManager,
  1571.                     0);
  1572.             if (!canExtendTrust(cx, javaPrincipals, principalArray)) {
  1573.                 return JS_FALSE;
  1574.             }
  1575.         }
  1576.         return (JSBool)netscape_security_PrivilegeManager_isPrivilegeEnabled(
  1577.             env, privilegeManager, javaTarget, 0);
  1578.     } else {
  1579.         /* No annotation in stack */
  1580.         return JS_FALSE;
  1581.     }
  1582.  
  1583.    /* Now find permission for (annotation, target) pair. */
  1584.     privilege = netscape_security_PrivilegeTable_get_1(env,
  1585.                                      annotation,
  1586.                                      javaTarget);
  1587.     if (JRI_ExceptionOccurred(env)) {
  1588.         return JS_FALSE;
  1589.     }
  1590.     XP_ASSERT(privilege);
  1591.     perm = netscape_security_Privilege_getPermission(env,
  1592.                                                privilege);
  1593.     XP_ASSERT(!JRI_ExceptionOccurred(env));
  1594.  
  1595.     return (JSBool)(perm == netscape_security_Privilege_ALLOWED);
  1596. #else
  1597.     return JS_FALSE;
  1598. #endif /* JAVA */
  1599. }
  1600.  
  1601.  
  1602. PR_STATIC_CALLBACK(void *)
  1603. getPrincipalArray(JSContext *cx, struct JSPrincipals *principals)
  1604. {
  1605. #ifdef JAVA
  1606.     JSPrincipalsData *data = (JSPrincipalsData *) principals;
  1607.     struct netscape_security_PrivilegeManager *privilegeManager;
  1608.     JRIEnv *env;
  1609.  
  1610.     env = LJ_JSJ_CurrentEnv(cx);
  1611.     if (env == NULL) {
  1612.         return NULL;
  1613.     }
  1614.  
  1615.     /* Get array of principals */
  1616.  
  1617.     if (data->principalsArrayRef == NULL) {
  1618.         privilegeManager = getPrivilegeManager(env);
  1619.         if (createPrincipalsArray(env, privilegeManager, principals) == NULL)
  1620.             return NULL;
  1621.     }
  1622.  
  1623.     return JRI_GetGlobalRef(env, data->principalsArrayRef);
  1624. #else
  1625.     return NULL;
  1626. #endif
  1627. }
  1628.  
  1629.  
  1630. extern char *
  1631. LM_ExtractFromPrincipalsArchive(JSPrincipals *principals, char *name,
  1632.                                 uint *length)
  1633. {
  1634.     JSPrincipalsData *data = (JSPrincipalsData *) principals;
  1635.     char *result;
  1636.  
  1637.     result = LJ_LoadFromZipFile(data->zip, name);
  1638.     *length = result ? XP_STRLEN(result) : 0;
  1639.  
  1640.     return result;
  1641. }
  1642.  
  1643. extern JSBool
  1644. LM_SetUntransformedSource(JSPrincipals *principals, char *original,
  1645.                           char *transformed)
  1646. {
  1647.     JSPrincipalsData *data = (JSPrincipalsData *) principals;
  1648.  
  1649.     XP_ASSERT(data->untransformed == NULL);
  1650.     data->untransformed = XP_STRDUP(original);
  1651.     if (data->untransformed == NULL)
  1652.         return JS_FALSE;
  1653.     data->transformed = XP_STRDUP(transformed);
  1654.     if (data->transformed == NULL)
  1655.         return JS_FALSE;
  1656.     return JS_TRUE;
  1657. }
  1658.  
  1659. JSPrincipals * PR_CALLBACK
  1660. LM_GetJSPrincipalsFromJavaCaller(JSContext *cx, int callerDepth)
  1661. {
  1662. #ifdef JAVA
  1663.     JRIEnv *env;
  1664.     jobjectArray principalsArray;
  1665.  
  1666.     env = LJ_JSJ_CurrentEnv(cx);
  1667.     if (env == NULL) {
  1668.         return NULL;
  1669.     }
  1670.  
  1671.     principalsArray = native_netscape_security_PrivilegeManager_getClassPrincipalsFromStackUnsafe(
  1672.         env,
  1673.         getPrivilegeManager(env),
  1674.         callerDepth);
  1675.  
  1676.     if (principalsArray == NULL)
  1677.         return NULL;
  1678.  
  1679.     return newJSPrincipalsFromArray(cx, principalsArray);
  1680. #else
  1681.     return NULL;
  1682. #endif
  1683. }
  1684.  
  1685. static JSPrincipals *
  1686. newJSPrincipalsFromArray(JSContext *cx, jobjectArray principalsArray)
  1687. {
  1688. #ifdef JAVA
  1689.     JRIEnv *env;
  1690.     JSPrincipals *result;
  1691.     struct netscape_security_Principal *principal;
  1692.     struct java_lang_String *javaString;
  1693.     const char *codebase;
  1694.     JSPrincipalsData *data;
  1695.     uint32 i, count;
  1696.  
  1697.     env = LJ_JSJ_CurrentEnv(cx);
  1698.     if (env == NULL) {
  1699.         return NULL;
  1700.     }
  1701.  
  1702.     count = JRI_GetObjectArrayLength(env, principalsArray);
  1703.     if (count == 0) {
  1704.         JS_ReportError(cx, "No principals found for Java caller");
  1705.         return NULL;
  1706.     }
  1707.  
  1708.     javaString = NULL;
  1709.     for (i = count; i > 0; i--) {
  1710.         principal = JRI_GetObjectArrayElement(env, principalsArray, i-1);
  1711.         if (netscape_security_Principal_isCodebaseExact(env, principal)) {
  1712.             javaString = netscape_security_Principal_toString(env, principal);
  1713.             break;
  1714.         }
  1715.     }
  1716.  
  1717.     codebase = javaString
  1718.         ? JRI_GetStringPlatformChars(env, javaString,
  1719.                                      (const jbyte *)cx->charSetName,
  1720.                                      (jint)cx->charSetNameLength)
  1721.         : NULL;
  1722.     result = LM_NewJSPrincipals(NULL, NULL, (char *) codebase);
  1723.     if (result == NULL) {
  1724.         JS_ReportOutOfMemory(cx);
  1725.         return NULL;
  1726.     }
  1727.  
  1728.     data = (JSPrincipalsData *) result;
  1729.     data->principalsArrayRef = JRI_NewGlobalRef(env, principalsArray);
  1730.     data->signedness = count == 1 && codebase
  1731.                        ? HAS_UNSIGNED_SCRIPTS
  1732.                        : HAS_SIGNED_SCRIPTS;
  1733.  
  1734.     return result;
  1735. #else
  1736.     /* Should not get here without signed scripts */
  1737.     XP_ASSERT(0);
  1738.     return NULL;
  1739. #endif /* JAVA */
  1740. }
  1741.  
  1742. static JSBool
  1743. verifyPrincipals(MochaDecoder *decoder, JSPrincipals *containerPrincipals,
  1744.                  JSPrincipals *principals, char *name, char *src,
  1745.                  uint srcSize, JSBool implicitName)
  1746. {
  1747. #ifdef JAVA
  1748.     JSPrincipalsData *data = (JSPrincipalsData *) principals;
  1749.     ZIG *zig;
  1750.     DIGESTS *dig = NULL;
  1751.     JSBool sameName = JS_FALSE;
  1752.     int ret;
  1753.     JSPrincipalsData *containerData;
  1754.     zip_t *containerZip;
  1755.     JSBool verified;
  1756.     SOBITEM *item;
  1757.     ZIG_Context * zig_cx;
  1758.     JRIEnv *env;
  1759.  
  1760.     if (data->signedness == HAS_UNSIGNED_SCRIPTS)
  1761.         return JS_FALSE;
  1762.  
  1763.     containerData = (JSPrincipalsData *) containerPrincipals;
  1764.  
  1765.     containerZip = containerData && containerData->signedness != HAS_UNSIGNED_SCRIPTS
  1766.                    ? containerData->zip
  1767.                    : NULL;
  1768.  
  1769.     if (data->zip == NULL && containerZip == NULL)
  1770.         return JS_FALSE;
  1771.  
  1772.     if (data->name && data->signedness == HAS_NO_SCRIPTS) {
  1773.         if (XP_STRCMP(name, data->name) == 0) {
  1774.             sameName = JS_TRUE;
  1775.         } else {
  1776.             return JS_FALSE;
  1777.         }
  1778.     }
  1779.  
  1780.     /*
  1781.      * Set to the value we want if verification fails, and then
  1782.      * reset below.
  1783.      */
  1784.     verified = JS_FALSE;
  1785.  
  1786.     /* Start Java since errors may need to be printed to the console. */
  1787.     env = LJ_JSJ_CurrentEnv(decoder->js_context);
  1788.     if (env == NULL) {
  1789.         return JS_FALSE;
  1790.     }
  1791.  
  1792.     if (containerData == NULL) {
  1793.         /* First script seen; initialize zig. */
  1794.         data->sharedZig = holdZig(env, newSharedZig(env, data->zip));
  1795.     } else if (data == containerData) {
  1796.         /* Already have a zig if there is one; nothing more to do. */
  1797.     } else if (data->zip == NULL) {
  1798.         /* "Inherit" data->sharedZig from container data. */
  1799.         data->sharedZig = holdZig(env, containerData->sharedZig);
  1800.     } else if (containerData->url_struct &&
  1801.                XP_STRCMP(data->url_struct->address,
  1802.                          containerData->url_struct->address) == 0)
  1803.     {
  1804.         /* Two identical zips. Share the zigs. */
  1805.         data->sharedZig = holdZig(env, containerData->sharedZig);
  1806.     } else {
  1807.         /* Different zips. Must create a new zig. */
  1808.         data->sharedZig = holdZig(env, newSharedZig(env, data->zip));
  1809.     }
  1810.  
  1811.     if (data->sharedZig == NULL)
  1812.         return JS_FALSE;
  1813.  
  1814.     zig = data->sharedZig->zig;
  1815.     dig = SOB_calculate_digest(src, srcSize);
  1816.     if (dig == NULL)
  1817.         return JS_FALSE;
  1818.  
  1819.     zig_cx = NULL;
  1820.     ret = SOB_verify_digest(zig, name, dig);
  1821.     XP_FREE(dig);
  1822.     if ((ret >= 0) &&
  1823.         ((zig_cx = SOB_find(zig, name, ZIG_SIGN)) != NULL) &&
  1824.         (SOB_find_next(zig_cx, &item) >= 0))
  1825.     {
  1826.         verified = JS_TRUE;
  1827.         if (!sameName) {
  1828.             data->name = JS_strdup(decoder->js_context, name);
  1829.             if (data->name == NULL)
  1830.                 return JS_FALSE;
  1831.         }
  1832.     } else if (!implicitName || ret != ZIG_ERR_PNF) {
  1833.         LJ_PrintZigError(ret, zig, "", name, SOB_get_error(ret));
  1834.     }
  1835.     if (zig_cx) {
  1836.         SOB_find_end(zig_cx);
  1837.     }
  1838.     return verified;
  1839. #else
  1840.     return JS_FALSE;
  1841. #endif /* JAVA */
  1842. }
  1843.  
  1844.  
  1845.  
  1846. extern JSPrincipals *
  1847. LM_RegisterPrincipals(MochaDecoder *decoder, JSPrincipals *principals,
  1848.                       char *name, char *src)
  1849. {
  1850.     JSContext *cx = decoder->js_context;
  1851.     JSBool verified;
  1852.     JSPrincipalsData *data;
  1853.     JSObject *inner, *container;
  1854.     JSPrincipals *containerPrincipals;
  1855.     JSPrincipalsData *containerData;
  1856.     char *untransformed, *implicitName;
  1857.  
  1858.     data = (JSPrincipalsData *) principals;
  1859.     inner = lm_GetActiveContainer(decoder);
  1860.     if (inner == NULL)
  1861.         return NULL;
  1862.     containerPrincipals = lm_GetInnermostPrincipals(decoder->js_context,
  1863.                                                     inner, &container);
  1864.     if (containerPrincipals == NULL) {
  1865.         /* Out of memory */
  1866.         return NULL;
  1867.     }
  1868.     containerData = (JSPrincipalsData *) containerPrincipals;
  1869.  
  1870.     if (name == NULL && principals != containerPrincipals && principals) {
  1871.         /*
  1872.          * "name" argument omitted since it was specified when "principals"
  1873.          * was created. Get it from "principals".
  1874.          */
  1875.         name = data->name;
  1876.     }
  1877.     implicitName = NULL;
  1878.     if (name == NULL && data && data->signedness == HAS_SIGNED_SCRIPTS) {
  1879.         /*
  1880.          * Name is unspecified. Use the implicit name formed from the
  1881.          * origin URL and the ordinal within the page. For example, the
  1882.          * third implicit name on http://www.co.com/dir/mypage.html
  1883.          * would be "_mypage2".
  1884.          */
  1885.         const char *url;
  1886.         char *path;
  1887.  
  1888.         url = LM_GetSourceURL(decoder);
  1889.         if (url == NULL) {
  1890.             return NULL;
  1891.         }
  1892.         path = *url? NET_ParseURL(url, GET_PATH_PART) : NULL;
  1893.         if (path && *path) {
  1894.             char *s;
  1895.             s = XP_STRRCHR(path, '.');
  1896.             if (s)
  1897.                 *s = '\0';
  1898.             s = XP_STRRCHR(path, '/');
  1899.             implicitName = PR_sprintf_append(NULL, "_%s%d", s ? s+1 : path,
  1900.                                              decoder->signature_ordinal++);
  1901.             name = implicitName;
  1902.         }
  1903.         XP_FREEIF(path);
  1904.     }
  1905.  
  1906.     untransformed = NULL;
  1907.     if (data && data->untransformed && !XP_STRCMP(data->transformed, src)) {
  1908.         /* Perform verification on original source. */
  1909.         src = untransformed = data->untransformed;
  1910.         data->untransformed = NULL;
  1911.         XP_FREE(data->transformed);
  1912.         data->transformed = NULL;
  1913.     }
  1914.  
  1915.     /* Verify cert principals */
  1916.     verified = (JSBool)(principals && name && src &&
  1917.                verifyPrincipals(decoder, containerPrincipals, principals, name,
  1918.                                 src, XP_STRLEN(src), (JSBool)(implicitName != NULL)));
  1919.  
  1920.     XP_FREEIF(untransformed);
  1921.     src = NULL;
  1922.     XP_FREEIF(implicitName);
  1923.     name = NULL;
  1924.  
  1925.     /*
  1926.      * Now that we've attempted verification, we need to set the appropriate
  1927.      * level of signedness based on whether verification succeeded.
  1928.      * We avoid setting signedness if principals is the same as container
  1929.      * principals (i.e., we "inherited" the principals from a script earlier
  1930.      * in the page) and we are not in a subcontainer of the container where
  1931.      * the principals were found. In that case we will create a new set of
  1932.      * principals for the inner container.
  1933.      */
  1934.     if (data && !(principals == containerPrincipals && container != inner)) {
  1935.         data->signedness = verified ? HAS_SIGNED_SCRIPTS : HAS_UNSIGNED_SCRIPTS;
  1936.     }
  1937.  
  1938.     if (verified && decoder->early_access_list &&
  1939.         !checkEarlyAccess(decoder, principals))
  1940.     {
  1941.         return NULL;
  1942.     }
  1943.  
  1944.     if (!verified) {
  1945.         /* No cert principals; try codebase principal */
  1946.         if (principals == NULL || principals == containerPrincipals) {
  1947.             if (container == inner ||
  1948.                 containerData->signedness == HAS_UNSIGNED_SCRIPTS)
  1949.             {
  1950.                 principals = containerPrincipals;
  1951.                 data = (JSPrincipalsData *) principals;
  1952.             } else {
  1953.                 /* Just put restricted principals in inner */
  1954.                 principals = LM_NewJSPrincipals(NULL, NULL,
  1955.                                                 containerPrincipals->codebase);
  1956.                 if (principals == NULL) {
  1957.                     JS_ReportOutOfMemory(cx);
  1958.                     return NULL;
  1959.                 }
  1960.                 data = (JSPrincipalsData *) principals;
  1961.             }
  1962.         }
  1963.         lm_InvalidateCertPrincipals(decoder, principals);
  1964.  
  1965.         if (decoder->early_access_list && !lm_GetCrossOriginEnabled() &&
  1966.             !checkEarlyAccess(decoder, principals))
  1967.         {
  1968.             return NULL;
  1969.         }
  1970.  
  1971.         if (container == inner) {
  1972.             lm_InvalidateCertPrincipals(decoder, containerPrincipals);
  1973.  
  1974.             /* compare codebase principals */
  1975.             if (!sameOrigins(cx, containerPrincipals->codebase,
  1976.                              principals->codebase))
  1977.             {
  1978.                 /* Codebases don't match; evaluate under different
  1979.                    principals than container */
  1980.                 return principals;
  1981.             }
  1982.             /* Codebases match */
  1983.             return containerPrincipals;
  1984.         }
  1985.  
  1986.         /* Just put restricted principals in inner */
  1987.         lm_SetContainerPrincipals(cx, inner, principals);
  1988.         return principals;
  1989.     }
  1990.  
  1991.     if (!principalsEqual(cx, principals, containerPrincipals)) {
  1992.         /* We have two unequal sets of principals. */
  1993.         if (containerData->signedness == HAS_NO_SCRIPTS &&
  1994.             sameOrigins(cx, principals->codebase,
  1995.                         containerPrincipals->codebase))
  1996.         {
  1997.             /*
  1998.              * Principals are unequal because we have container principals
  1999.              * carrying only a codebase, and the principals of this script
  2000.              * that carry cert principals as well.
  2001.              */
  2002.             lm_SetContainerPrincipals(cx, container, principals);
  2003.             return principals;
  2004.         }
  2005.         if (inner == container) {
  2006.             /*
  2007.              * Intersect principals and container principals,
  2008.              * modifying the container principals.
  2009.              */
  2010.             PrintToConsole("Intersecting principals ");
  2011.             printPrincipalsToConsole(cx, containerPrincipals);
  2012.             PrintToConsole("with ");
  2013.             printPrincipalsToConsole(cx, principals);
  2014.             if (!intersectPrincipals(decoder, containerPrincipals,
  2015.                                      principals))
  2016.             {
  2017.                 return NULL;
  2018.             }
  2019.             PrintToConsole("yielding ");
  2020.             printPrincipalsToConsole(cx, containerPrincipals);
  2021.         } else {
  2022.             /*
  2023.              * Store the disjoint set of principals in the
  2024.              * innermost container
  2025.              */
  2026.             lm_SetContainerPrincipals(cx, inner, principals);
  2027.             return principals;
  2028.         }
  2029.  
  2030.     }
  2031.     return containerPrincipals;
  2032. }
  2033.  
  2034.