aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OhSillyThreatDetector.lsl
blob: 2c808d2723cfbae20f8e86b24b94ec5a62f602e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

// 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);
    }
}