Lesson 7: Policy optimizations
In this final interactive lesson, you will look at methods you can use to optimize your policy using all of the constructions we have covered so far:
-
list variables
-
constraint tests
-
I/O logging
-
message display
Additionally, you are introduced to the concept of requesting a password as confirmation before a certain command can be run.
One Identity recommends that you examine the policy and make any necessary modifications to establish the password validation test performs as expected.
# LESSON=7; export LESSON
# date mmdd2200
# su dan
$ pmrun hostname
Sorry, you can't use that command outside office hours.
Request Rejected by pmmasterd on UPMhost
$ exit
# su robyn
$ pmrun hostname
$ Password: <type in Robyn's password>
UPMhost
Remember to reset the correct time on your system by running the date command as the root user.
This lesson expands on the example in lesson 6. First, you forbid dan from running admin commands outside normal office hours. Then, because you saved the boolean value "officehours" earlier, you can check it again, this time to request for Robyn's password if they attempt to run a command outside office hours.
officehours = timebetween(800, 1700) && dayname !in {"Sat", "Sun"};
adminusers = {"dan", "robyn"};
adminprogs = {"ls", "hostname", "kill", "csh", "ksh"};
if (user in adminusers && command in adminprogs) {
runuser = "root";
if (user == "dan" && !officehours) {
print("Sorry, you can't use that command outside office hours.");
reject;
}
if (user == "robyn" && !officehours) {
if (!getuserpasswd(user)) reject;
}
accept;
}
To see the sample policy used in this lesson, see Lesson 7 Sample: Policy optimizations.
Advanced lessons
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:
Lesson 8: Controlling the execution environment
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.
To see the sample policy used in this lesson, see Lesson 8 Sample: Controlling the execution environment.
Lesson 9: Flow control
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.
To see the sample policy used in this lesson, see Lesson 9 Sample: Flow control.