The remaining lessons are theoretical discussions covering the changes to scripts and leave the reader to consider modification and experimentation as exercises.
These lessons are not designed to be interactive. However, if you work through the sample policies, making changes, and trying out the policy files in the same way you did for Lesson 1 through 7, you will extend your understanding of the process, approach, and style required to create policies.
The advanced lessons are:
This policy file introduces a number of environmental controls that give you greater flexibility and control over the command and user execution environment.
if (cwd != "/usr" && !glob("/usr/*", cwd))
runcwd = "/tmp";
The first uses the runcwd variable which gives you the ability to examine and override the working directory in which the requested command runs. In this example, you allow commands to be run from /usr and its subdirectories, but you run all other commands from /tmp.
if (argc > 2)
runargv = range(argv, 0, 2);
You can also control the number of arguments specified on the requested command line. You can examine the number of arguments together with the value of each argument, as well as remove, modify, or supplement them with additional arguments not previously present on the original command line.
runuser = "root";
rungroup = "bin";
if (command != "hostname")
runhost = submithost;
You can also examine the rungroup and the host on which the command is destined to run and override them.
keepenv("TERM", "DISPLAY", "HOME", "TZ", "PWD", "WINDOWID", "COLUMNS", "LINES");
setenv("PATH",
"/usr/ucb:/bin:/usr/bin:/usr/local/bin:/usr/bin/X11:" +
"/usr/X11/bin:/usr/etc:/etc:/usr/local/etc:/usr/sbin");
Control of the run environment is vitally important as you can use environment variables to exploit security vulnerabilities in some UNIX programs, so one aspect of the policy can be to cleanse the execution environment to make sure there is nothing which could be considered unsafe. A common requirement within policy files is to ensure that the PATH is cleansed, removing any user appended paths which may be higher up the search path, where a user-created script may be lurking.
runumask = 022;
runnice = -4;
You can control many other aspects of the execution environment including the nice value and umask.
Refer to Lesson 8 Sample: Controlling the execution environment to see the sample policy used in this lesson.
This lesson introduces you to another execution control construct using switch(), case, and break statements which allow you control which parts of the script are to run.
adminprogs = {"ls", "hostname", "kill", "csh", "ksh", "echo"};
if (command in adminprogs) {
switch (dayname) {
case "Mon":
case "Wed":
case "Fri":
adminusers = {"dan", "robyn"};
break;
case "Tue":
case "Thu":
adminusers = {"robyn", "cory"};
break;
default:
adminusers = {};
}
if (user in adminusers) {
runuser = "root";
accept;
}
}
In this example, you use the switch and case statements to control which users are considered to be admin users on any given day of the week. Execution commences when the first case statement matches the condition. It proceeds until it encounters the end of the switch statement or reaches a break statement.
Refer to Lesson 9 Sample: Flow control to see the sample policy used in this lesson.
This final lesson demonstrates the use of a rudimentary menu system which you can present to the user when he enters the adminmenu command.
if(command=="adminmenu") {
print("========= Admin Menu =========");
print("1) Add users");
print("2) Start a backup");
print("3) Change ownership of a file");
print("4) Fix line printer queues");
choice = input("Please choose one: ");
switch(choice) {
case "1":
if(!getstringpasswd("m9xxg7B4.v8Ck", "Type in the adduser
password: ", 2))
reject;
runcommand = "/usr/local/bin/adduser";
runuser = "root";
break;
case "2":
runcommand = "/usr/local/bin/dobackup";
runuser = "backup";
break;
case "3":
runcommand = "/usr/bin/chown";
runuser = "root";
break;
case "4":
runcommand = "/usr/lib/lpadmin";
runuser = "root";
break;
default:
printf("\"%s\" was not a valid choice. Sorry.\n", choice);
reject;
}
if (choice == "3") {
file_name=input("Please enter the new owner's name then file name: ");
arguments = split(file_name);
runargv = insert(arguments, 0, "Spacer");
}
print("** Command to be run :", runcommand);
print("** User to run command as :", runuser);
accept;
}
This example shows how to gather input from the user, check the value of a literal hard-coded password, and manipulate command line arguments. It is purely illustrative of the scope and scale of what you can achieve from within a policy file, although there is much more that has not been covered in this lesson.
Refer to Lesson 10 Sample: Basic menus to see the sample policy used in this lesson.