* Fix 12124 [DOGFOOD] Reading user's preferences

* Implement site-specific security policies (bug 858)
r=mstoltz
* Use Recycle rather than delete[] to clean up Purify logs
r=law


git-svn-id: svn://10.0.0.236/trunk@53631 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
norris%netscape.com
1999-11-16 05:07:31 +00:00
parent 4c9d876f3f
commit 331cf153db
20 changed files with 279 additions and 200 deletions

View File

@@ -367,23 +367,59 @@ nsScriptSecurityManager::CheckScriptAccess(nsIScriptContext *aContext,
}
NS_IMETHODIMP
nsScriptSecurityManager::CheckURI(nsIScriptContext *aContext,
nsIURI *aURI,
PRBool *aResult)
nsScriptSecurityManager::CheckLoadURIFromScript(nsIScriptContext *aContext,
nsIURI *aURI)
{
// Temporary: only enforce if security.checkuri pref is enabled
nsresult rv;
NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &rv);
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
PRBool enabled;
if (NS_FAILED(prefs->GetBoolPref("security.checkuri", &enabled)) ||
!enabled)
{
*aResult = PR_TRUE;
return NS_OK;
// Get principal of currently executing script.
JSContext *cx = (JSContext*) aContext->GetNativeContext();
nsCOMPtr<nsIPrincipal> principal;
if (NS_FAILED(GetSubjectPrincipal(cx, getter_AddRefs(principal)))) {
return NS_ERROR_FAILURE;
}
// The system principal can load all URIs.
PRBool equals;
if (NS_FAILED(principal->Equals(mSystemPrincipal, &equals)))
return NS_ERROR_FAILURE;
if (equals)
return NS_OK;
// Otherwise, principal should have a codebase that we can use to
// do the remaining tests.
nsCOMPtr<nsICodebasePrincipal> codebase = do_QueryInterface(principal);
if (!principal)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIURI> uri;
if (NS_FAILED(codebase->GetURI(getter_AddRefs(uri))))
return NS_ERROR_FAILURE;
if (NS_SUCCEEDED(CheckLoadURI(uri, aURI)))
return NS_OK;
// See if we're attempting to load a file: URI. If so, let a
// UniversalFileRead capability trump the above check.
nsXPIDLCString scheme;
if (NS_FAILED(aURI->GetScheme(getter_Copies(scheme))))
return NS_ERROR_FAILURE;
if (nsCRT::strcmp(scheme, "file") == 0) {
PRBool enabled;
if (NS_FAILED(IsCapabilityEnabled("UniversalFileRead", &enabled)))
return NS_ERROR_FAILURE;
if (enabled)
return NS_OK;
}
// Report error.
nsXPIDLCString spec;
if (NS_FAILED(aURI->GetSpec(getter_Copies(spec))))
return NS_ERROR_FAILURE;
JS_ReportError(cx, "illegal URL method '%s'", (const char *)spec);
return NS_ERROR_DOM_BAD_URI;
}
NS_IMETHODIMP
nsScriptSecurityManager::CheckLoadURI(nsIURI *aFromURI,
nsIURI *aURI)
{
nsXPIDLCString scheme;
if (NS_FAILED(aURI->GetScheme(getter_Copies(scheme))))
return NS_ERROR_FAILURE;
@@ -394,7 +430,6 @@ nsScriptSecurityManager::CheckURI(nsIScriptContext *aContext,
nsCRT::strcmp(scheme, "mailto") == 0 ||
nsCRT::strcmp(scheme, "news") == 0)
{
*aResult = PR_TRUE;
return NS_OK;
}
if (nsCRT::strcmp(scheme, "about") == 0) {
@@ -402,53 +437,31 @@ nsScriptSecurityManager::CheckURI(nsIScriptContext *aContext,
if (NS_FAILED(aURI->GetSpec(getter_Copies(spec))))
return NS_ERROR_FAILURE;
if (nsCRT::strcmp(spec, "about:blank") == 0) {
*aResult = PR_TRUE;
return NS_OK;
}
}
JSContext *cx = (JSContext*) aContext->GetNativeContext();
nsCOMPtr<nsIPrincipal> principal;
if (NS_FAILED(GetSubjectPrincipal(cx, getter_AddRefs(principal)))) {
return NS_ERROR_FAILURE;
}
if (nsCRT::strcmp(scheme, "file") == 0) {
nsCOMPtr<nsICodebasePrincipal> codebase;
if (NS_SUCCEEDED(principal->QueryInterface(
NS_GET_IID(nsICodebasePrincipal),
(void **) getter_AddRefs(codebase))))
nsXPIDLCString scheme2;
if (NS_SUCCEEDED(aFromURI->GetScheme(getter_Copies(scheme2))) &&
nsCRT::strcmp(scheme2, "file") == 0)
{
nsCOMPtr<nsIURI> uri;
if (NS_SUCCEEDED(codebase->GetURI(getter_AddRefs(uri)))) {
nsXPIDLCString scheme2;
if (NS_SUCCEEDED(uri->GetScheme(getter_Copies(scheme2))) &&
nsCRT::strcmp(scheme2, "file") == 0)
{
*aResult = PR_TRUE;
return NS_OK;
}
}
}
if (NS_FAILED(IsCapabilityEnabled("UniversalFileRead", aResult)))
return NS_ERROR_FAILURE;
if (*aResult)
return NS_OK;
}
}
// Only allowed for the system principal to create other URIs.
if (NS_FAILED(principal->Equals(mSystemPrincipal, aResult)))
return NS_ERROR_FAILURE;
if (!*aResult) {
// Report error.
nsXPIDLCString spec;
if (NS_FAILED(aURI->GetSpec(getter_Copies(spec))))
return NS_ERROR_FAILURE;
JS_ReportError(cx, "illegal URL method '%s'", (const char *)spec);
return NS_ERROR_DOM_BAD_URI;
// Temporary: allow a preference to disable this check
nsresult rv;
NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &rv);
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
PRBool enabled;
if (NS_SUCCEEDED(prefs->GetBoolPref("security.checkuri", &enabled)) &&
!enabled)
{
return NS_OK;
}
return NS_OK;
return NS_ERROR_DOM_BAD_URI;
}
NS_IMETHODIMP
@@ -482,12 +495,12 @@ nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result)
}
NS_IMETHODIMP
nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI *aURI,
nsIPrincipal **result)
nsScriptSecurityManager::GetCodebasePrincipal(nsIURI *aURI,
nsIPrincipal **result)
{
nsresult rv;
nsCodebasePrincipal *codebase = new nsCodebasePrincipal();
NS_ADDREF(codebase); // XXX should constructor addref?
NS_ADDREF(codebase);
if (!codebase)
return NS_ERROR_OUT_OF_MEMORY;
if (NS_FAILED(codebase->Init(aURI))) {
@@ -593,7 +606,9 @@ nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
&canEnable);
if (NS_FAILED(rv))
return rv;
if (canEnable == nsIPrincipal::ENABLE_DENIED) {
if (canEnable != nsIPrincipal::ENABLE_GRANTED &&
canEnable != nsIPrincipal::ENABLE_WITH_USER_PERMISSION)
{
*result = PR_FALSE;
return NS_OK;
}
@@ -792,7 +807,8 @@ nsScriptSecurityManager::CanSetProperty(JSContext *aJSContext,
///////////////////
nsScriptSecurityManager::nsScriptSecurityManager(void)
: mSystemPrincipal(nsnull), mPrincipals(nsnull)
: mOriginToPolicyMap(nsnull), mSystemPrincipal(nsnull),
mPrincipals(nsnull)
{
NS_INIT_REFCNT();
memset(domPropertyPolicyTypes, 0, sizeof(domPropertyPolicyTypes));
@@ -801,6 +817,7 @@ nsScriptSecurityManager::nsScriptSecurityManager(void)
nsScriptSecurityManager::~nsScriptSecurityManager(void)
{
delete mOriginToPolicyMap;
NS_IF_RELEASE(mSystemPrincipal);
delete mPrincipals;
}
@@ -931,14 +948,14 @@ nsScriptSecurityManager::CheckPermissions(JSContext *aCx, JSObject *aObj,
PRInt32
nsScriptSecurityManager::GetSecurityLevel(JSContext *cx, char *prop_name,
nsScriptSecurityManager::GetSecurityLevel(JSContext *cx, char *propName,
PolicyType type, PRBool isWrite,
char **capability)
{
if (prop_name == nsnull)
if (propName == nsnull)
return SCRIPT_SECURITY_NO_ACCESS;
char *tmp_prop_name = AddSecPolicyPrefix(cx, prop_name, type);
if (tmp_prop_name == nsnull)
nsXPIDLCString prefName;
if (NS_FAILED(GetPrefName(cx, propName, type, getter_Copies(prefName))))
return SCRIPT_SECURITY_NO_ACCESS;
PRInt32 secLevel;
char *secLevelString;
@@ -946,18 +963,17 @@ nsScriptSecurityManager::GetSecurityLevel(JSContext *cx, char *prop_name,
NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &rv);
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
rv = prefs->CopyCharPref(tmp_prop_name, &secLevelString);
rv = prefs->CopyCharPref(prefName, &secLevelString);
if (NS_FAILED(rv)) {
nsAutoString s = tmp_prop_name;
nsAutoString s = (const char *) prefName;
s += (isWrite ? ".write" : ".read");
char *cp = s.ToNewCString();
if (!cp)
if (!cp)
return SCRIPT_SECURITY_NO_ACCESS;
rv = prefs->CopyCharPref(cp, &secLevelString);
Recycle(cp);
}
if (NS_SUCCEEDED(rv) && secLevelString) {
PR_FREEIF(tmp_prop_name);
if (PL_strcmp(secLevelString, "sameOrigin") == 0)
secLevel = SCRIPT_SECURITY_SAME_DOMAIN_ACCESS;
else if (PL_strcmp(secLevelString, "allAccess") == 0)
@@ -979,40 +995,51 @@ nsScriptSecurityManager::GetSecurityLevel(JSContext *cx, char *prop_name,
// This violates the rule of a safe default, but means we don't have
// to specify the large majority of unchecked properties, only the
// minority of checked ones.
PR_FREEIF(tmp_prop_name);
return SCRIPT_SECURITY_ALL_ACCESS;
}
char *
nsScriptSecurityManager::AddSecPolicyPrefix(JSContext *cx, char *pref_str,
PolicyType type)
NS_IMETHODIMP
nsScriptSecurityManager::GetPrefName(JSContext *cx, char *propName,
PolicyType type, char **result)
{
const char *subjectOrigin = "";//GetSubjectOriginURL(cx);
char *policy_str, *retval = 0;
if ((policy_str = GetSitePolicy(subjectOrigin)) == 0) {
/* No site-specific policy. Get global policy name. */
nsresult rv;
NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &rv);
if (NS_FAILED(rv) ||
NS_FAILED(prefs->CopyCharPref("javascript.security_policy", &policy_str)))
{
policy_str = PL_strdup("default");
}
nsresult rv;
static const char *defaultStr = "default";
nsAutoString s = "security.policy.";
if (type == POLICY_TYPE_DEFAULT) {
s += defaultStr;
} else if (type == POLICY_TYPE_PERDOMAIN) {
nsCOMPtr<nsIPrincipal> principal;
if (NS_FAILED(GetSubjectPrincipal(cx, getter_AddRefs(principal)))) {
return NS_ERROR_FAILURE;
}
PRBool equals;
if (NS_FAILED(principal->Equals(mSystemPrincipal, &equals)))
return NS_ERROR_FAILURE;
if (equals) {
s += defaultStr;
} else {
nsCOMPtr<nsICodebasePrincipal> codebase = do_QueryInterface(principal, &rv);
if (NS_FAILED(rv))
return rv;
nsXPIDLCString origin;
if (NS_FAILED(rv = codebase->GetOrigin(getter_Copies(origin))))
return rv;
nsCString *policy = nsnull;
if (mOriginToPolicyMap) {
nsStringKey key(origin);
policy = (nsCString *) mOriginToPolicyMap->Get(&key);
}
if (policy)
s += *policy;
else
s += defaultStr;
}
}
if (policy_str) { //why can't this be default? && PL_strcasecmp(policy_str, "default") != 0) {
retval = PR_sprintf_append(NULL, "security.policy.%s.%s", policy_str, pref_str);
PR_Free(policy_str);
}
return retval;
}
char *
nsScriptSecurityManager::GetSitePolicy(const char *org)
{
return nsnull;
s += '.';
s += propName;
*result = s.ToNewCString();
return *result ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
@@ -1959,12 +1986,25 @@ findDomProp(const char *propName, int n)
return -1;
}
// security.policy.<policyname>.<object>.<property>[.read|.write]
PR_STATIC_CALLBACK(PRBool)
DeleteEntry(nsHashKey *aKey, void *aData, void* closure)
{
nsCString* entry = (nsCString*) aData;
delete entry;
return PR_TRUE;
}
struct PolicyEnumeratorInfo {
nsScriptSecurityManager::PolicyType *policies;
nsIPref *prefs;
nsScriptSecurityManager *secMan;
};
PR_STATIC_CALLBACK(void)
enumeratePolicy(const char *prefName, void *policies) {
enumeratePolicy(const char *prefName, void *data) {
if (!prefName || !*prefName)
return;
PolicyEnumeratorInfo *info = (PolicyEnumeratorInfo *) data;
unsigned count = 0;
const char *dots[5];
const char *p;
@@ -1977,23 +2017,59 @@ enumeratePolicy(const char *prefName, void *policies) {
}
if (count < sizeof(dots)/sizeof(dots[0]))
dots[count] = p;
if (count >= 4) {
const char *policyName = dots[1] + 1;
int policyLength = dots[2] - policyName;
PRBool isDefault = PL_strncmp("default", policyName, policyLength) == 0;
if (count < 3)
return;
const char *policyName = dots[1] + 1;
int policyLength = dots[2] - policyName;
PRBool isDefault = PL_strncmp("default", policyName, policyLength) == 0;
if (!isDefault && count == 3) {
// security.policy.<policyname>.sites
const char *sitesName = dots[2] + 1;
int sitesLength = dots[3] - sitesName;
if (PL_strncmp("sites", sitesName, sitesLength) == 0) {
if (!info->secMan->mOriginToPolicyMap) {
info->secMan->mOriginToPolicyMap =
new nsObjectHashtable(nsnull, nsnull, DeleteEntry, nsnull);
if (!info->secMan->mOriginToPolicyMap)
return;
}
char *s;
if (NS_FAILED(info->prefs->CopyCharPref(prefName, &s)))
return;
char *q=s;
char *r=s;
PRBool working = PR_TRUE;
while (working) {
if (*r == ' ' || *r == '\0') {
working = (*r != '\0');
*r = '\0';
nsStringKey key(q);
nsCString *value = new nsCString(policyName, policyLength);
if (!value)
break;
info->secMan->mOriginToPolicyMap->Put(&key, value);
q = r + 1;
}
r++;
}
PR_Free(s);
return;
}
} else if (count >= 4) {
// security.policy.<policyname>.<object>.<property>[.read|.write]
const char *domPropName = dots[2] + 1;
int domPropLength = dots[4] - domPropName;
PRInt16 domProp = findDomProp(domPropName, domPropLength);
if (domProp >= 0) {
nsScriptSecurityManager::PolicyType *policyType =
((nsScriptSecurityManager::PolicyType *) policies) + domProp;
info->policies + domProp;
if (!isDefault)
*policyType = nsScriptSecurityManager::POLICY_TYPE_PERDOMAIN;
else if (*policyType == nsScriptSecurityManager::POLICY_TYPE_NONE)
*policyType = nsScriptSecurityManager::POLICY_TYPE_DEFAULT;
return;
}
}
}
NS_ASSERTION(PR_FALSE, "DOM property name invalid or not found");
}
@@ -2004,7 +2080,11 @@ nsScriptSecurityManager::InitFromPrefs()
NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &rv);
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
PolicyEnumeratorInfo info;
info.policies = domPropertyPolicyTypes;
info.prefs = prefs;
info.secMan = this;
prefs->EnumerateChildren("security.policy", enumeratePolicy,
(void *) domPropertyPolicyTypes);
(void *) &info);
return NS_OK;
}