A script is about the only way to do that, yes. Actually, two scripts.
A very basic example:
Notes:
chan and
hash must be the same between both scripts.
*
Change these values* or anyone can force your receiver to grant a pass. Keep both values high.
RECEIVER (Must be on the group land set to "restrict", must be deeded to group)
integer chan = 909029;
integer hash = 10241024;
default
{
state_entry()
{
llListen(chan, "", NULL_KEY, "");
}
listen(integer chan, string name, key id, string msg)
{
if (llSameGroup(id))
{
list parse = llParseString2List(msg, ["|||"], [""]);
string sig = llList2String(parse,0);
string add_id = llList2String(parse,1);
float pass_time = llList2Float(parse,2);
if ( llMD5String(add_id, hash) == sig )
{
llAddToLandPassList((key)add_id, pass_time);
}
}
}
}
TRANSMITTER - must be rezzed while you wear the proper group tag, change
time and
cost to fit your needs. Easiest if it's not behind the "NO ENTRY" lines, so cut off a little part of the parcel for it.
integer chan = 909029;
integer hash = 10241024;
integer cost = 1;
float time = 0.008333;
default
{
state_entry()
{
llSetText("Startup!.", <0,1,0>, 1.0);
llRequestPermissions(llGetOwner(), PERMISSION_DEBIT);
}
on_rez(integer n)
{
llResetScript();
}
run_time_permissions(integer p)
{
if ( p & PERMISSION_DEBIT )
{
state running;
}
else
{
state fail;
}
}
}
state fail
{
state_entry()
{
llOwnerSay("Can't give change without that permission.");
llSetText("Disabled.", <1,0,0>, 1.0);
}
on_rez(integer n)
{
llResetScript();
}
touch_start(integer n)
{
if ( llDetectedKey(0) == llGetOwner() ) llResetScript();
}
}
state running
{
state_entry()
{
llOwnerSay("Ready.");
llSetText("Pay me " + (string)cost + "L$\nfor a " + (string)time + " hour pass.", <1,1,0.5>, 1.0);
}
on_rez(integer n)
{
llResetScript();
}
money(key payee, integer amt)
{
if (amt == cost)
{
string sig = llMD5String((string)payee, hash);
string add_id = (string)payee;
llWhisper(chan, sig + "|||" + add_id + "|||" + (string)time); // change to llShout if the two objects are not to be within 5 meters of one another
}
else
{
llWhisper(0, "Passes are " + (string)cost + "L$ per " + (string)time + " hour(s).");
llGiveMoney(payee, amt);
}
}
}
This isn't 100% perfectly secure, though it's better than being just open. I suggest changeing the channel and the hash periodically.