// Detect when OpenSim reports a function was used that triggered a threat level warning. // Coz their official method doesn't always work, and often their threat levels are set way too high. // This script will send a link message with number DEBUG_CHANNEL, message being the name of the naughty function, // and key of the prim containing the naughty script. It's up to the naughty script to catch this link message // and do something less naughty. // Since it sniffs on DEBUG_CHANNEL messages, and a script can't hear any message sent by scripts in the same prim, // you'll need to put this script in a prim without the naughty scripts you want to check. // Naturally it looks as if OpenSim has decided that scripts sniffing DEBUG_CHANNEL is a bad idea now. // Bits of this where taken from the script at the bottom of http://opensimulator.org/wiki/Threat_level // OSSL Function Availability Tester // // Demonstrates a method by which a script may determine whether or not it is permitted to call // various OSSL functions. integer WhichProbeFunction; // to tell us which function we're probing // OpenSim lies. list FunctionNames = [ "osAvatarPlayAnimation", // very high "osAvatarStopAnimation", // very high "osForceOtherSit", // very high "osGetAvatarList", // none "osMakeNotecard", // high (describes what they where when making this decision) "osGetNotecard", // very high (describes what they where when making this decision) "osGetNotecardLine", // very high (describes what they where when making this decision) "osGetNumberOfNotecardLines", // very high (describes what they where when making this decision) "osGetInventoryDesc", // - "osGetRegionSize", // - "osGetRezzingObject", // none "osIsNpc", // - "osKey2Name", // low "osMessageObject", // low "osNpcSit", // high "osSetSpeed", // moderate // "osSetOwnerSpeed", // moderate (not in 0.9.0.2) "osTeleportAgent", // severe "osTeleportOwner" // none ]; list FunctionPermitted = []; // 0 = not permitted, 1 = permitted startProbe() { string root = llKey2Name(llList2Key(llGetObjectDetails(llGetKey(), [OBJECT_ROOT]), 0)); llRegionSay(DEBUG_CHANNEL, "The '" + llGetObjectName() + "' prim in the object called '" + root + "' belonging to '" + llKey2Name(llGetOwner()) + "' might be about to spew OhSilly Threat Level system errors on the debug channel. " + "Blame OpenSim developers for making this script jump through these hoops. Apologies. \n\n" + "Probing OhSilly threat system to see what OpenSim script functions we are allowed use..."); WhichProbeFunction = -1; integer i = llGetListLength(FunctionNames); FunctionPermitted = []; while (i--) FunctionPermitted += [-1]; llRemoveInventory("OhSillyThreatCard"); llSetTimerEvent(0.25); // check only four functions a second, just to be nice. } // The default state uses the timer to call all the OSSL functions we're interested in using, in turn. // If the function call fails, the timer event handler will abend, but the script doesn't crash. We can // use this fact to check all of our desired functions in turn, and then pass control to the Running // state once we've checked them all. default { state_entry() { llListen(DEBUG_CHANNEL, "", NULL_KEY, ""); //llSay(DEBUG_CHANNEL, "G'day, I'm " + llGetKey() + " part of " + llGetLinkKey(LINK_ROOT) // + "\nOpenSim sucks with their OhSilly threat system!"); } listen(integer channel, string name, key id, string message) { // key root = llList2Key(llGetObjectDetails(id, [OBJECT_ROOT]), 0); // name is the name of the prim, id is the UUID of the prim. // Reports the name and UUID of the prim itself, not the object it's part of. // Naturally can't detect debugs from our own prim, even if it's a different script. // Works from another prim in the same object. /* Threat level errors look like this (at least in OpenSim 0.8.2) - OSSL Runtime Error: osSetStateEvents permission denied. Script creator is not in the list of users allowed to execute this function and prim owner also has no permission. There is also (OpenSim 0.9.1 at least) - Max Zephyr script OSSL Runtime Error: permission denied. All OS functions are disabled.(script: oc_settings event: changed primID:487baa88-d6e5-420c-b18c-f47f5bbd7de4 at <127.9408, 128.0009, 25.75689>) My script OSSL Runtime Error: osSetSpeed permission denied. All OS functions are disabled.(script: 1AOor2 event: changed primID:c7db8d3c-ae33-44ce-a685-cf63a37f0cf5 at <123.933, 203.0375, 24.29473>) From the source (NOTE: first version has no function name) - ("{0} permission denied. All OS functions are disabled.") ("{0} permission denied. All OS functions are disabled.", function) ("{0} permission denied. Allowed threat level is {1} but function threat level is {2}.", function, ("{0} permission denied. Script creator is not in the list of users allowed to execute this function and prim owner also has no permission.", function ("{0} permission denied. Script permissions error.", function OpenSim 0.9.1 sends to DEBUG_CHANNEL, but scripts can't read that. osForceOtherSit permission denied. Script creator is not in the list of users allowed to execute this function and prim owner also has no permission.(script: OhSillyThreatDetector event: timer at <754.7451, 311.6997, 23.24454>) */ //llOwnerSay(message); // if (llGetLinkKey(LINK_ROOT) == root) { integer f = llSubStringIndex(message, "permission denied. "); if (-1 != f) { list e = llParseStringKeepNulls(llGetSubString(message, 0, -f), [" "], []); string function = llList2String(e, 0); if (("OSSL" == llList2String(e, 0)) && ("Runtime" == llList2String(e, 1)) && ("Error:" == llList2String(e, 2))) function = llList2String(e, 3); llMessageLinked(LINK_SET, DEBUG_CHANNEL, function, "0"); llOwnerSay("Found naughty function " + function); llRegionSay(DEBUG_CHANNEL, "OPENSIM SUCKS!"); } } } link_message(integer sender, integer num, string message, key id) { if ((DEBUG_CHANNEL == num) && ("OHSILLYPROBE" == message)) startProbe(); else { integer f = llListFindList(FunctionNames, [message]); if (-1 != f) { FunctionPermitted = llListReplaceList(FunctionPermitted, [(integer) id], f, f); // llSay(0, "BROKEN " + message + " " + id); } } } // As noted above, this script wont hear itself when the below tests dump an error. timer() { string name = llList2String(FunctionNames, ++WhichProbeFunction); string BogusKey = "12345678-1234-1234-1234-123456789abc"; // it doesn't need to be valid if ("" == name) { llSetTimerEvent(0.0); // stop the timer llRemoveInventory("OhSillyThreatCard"); string s = "The OpenSim script functions we are allowed to use - "; string t = "The Opensim script functions we are NOT ALLOWED to use - "; integer i = llGetListLength(FunctionNames); while (i--) { integer p = llList2Integer(FunctionPermitted, i); if (-1 == p) p = 0; llMessageLinked(LINK_SET, DEBUG_CHANNEL, llList2String(FunctionNames, i), (string) p); if (p) s += llList2String(FunctionNames, i) + "() "; else t += llList2String(FunctionNames, i) + "() "; } // llSay(0, s); llOwnerSay(t); return; } // llOwnerSay("Checking OpenSim function " + name + "()"); // say status if ("osAvatarPlayAnimation" == name) osAvatarPlayAnimation(BogusKey, BogusKey); else if ("osAvatarStopAnimation" == name) osAvatarStopAnimation(BogusKey, BogusKey); else if ("osForceOtherSit" == name) osForceOtherSit(BogusKey, llGetKey()); else if ("osGetAvatarList" == name) osGetAvatarList(); else if ("osMakeNotecard" == name) // Out of order, so the others have something to read. osMakeNotecard("OhSillyThreatCard", [""]); else if ("osGetNotecard" == name) osGetNotecard("OhSillyThreatCard"); else if ("osGetNotecardLine" == name) osGetNotecardLine("OhSillyThreatCard", 0); else if ("osGetNumberOfNotecardLines" == name) osGetNumberOfNotecardLines("OhSillyThreatCard"); else if ("osGetInventoryDesc" == name) osGetInventoryDesc("inventory"); else if ("osGetRegionSize" == name) osGetRegionSize(); else if ("osGetRezzingObject" == name) osGetRezzingObject(); else if ("osIsNpc" == name) osIsNpc(BogusKey); else if ("osKey2Name" == name) osKey2Name(llGetOwner()); else if ("osMessageObject" == name) osMessageObject(llGetKey(), "G'day."); else if ("osNpcSit" == name) osNpcSit(BogusKey, llGetKey(), 0); else if ("osSetSpeed" == name) osSetSpeed(BogusKey, 1.0); // else if ("osSetOwnerSpeed" == name) // osSetOwnerSpeed(1.0); else if ("osTeleportAgent" == name) osTeleportAgent(BogusKey, ZERO_VECTOR, ZERO_VECTOR); else if ("osTeleportAgent" == name) osTeleportOwner(ZERO_VECTOR, ZERO_VECTOR); // If we got here, then the timer() handler didn't crash, which means the function it checked for // was actually permitted. So we update the list to indicate that we can use that particular function. // llOwnerSay("Working " + name + "()"); if (-1 == llList2Integer(FunctionPermitted, WhichProbeFunction)) FunctionPermitted = llListReplaceList(FunctionPermitted, [1], WhichProbeFunction, WhichProbeFunction); } }