Let's take a look at the login program now. What are the goals? Well, the first goal of the login program is to only allow authorized users onto the system. That's what the password and login prompts are supposed to do. They check that the password belongs to the user whose name is given. The second thing is, you start off as an end user root. You don't want to stay that user, as soon as you know who the real user is, you drop privileges because that prevents the user who's logging in from doing things as the administrator. The third thing is, if something goes wrong we want to know about it, so we log enough information to reconstruct any unauthorized login. The only thing we don't record is the password. Why? Because if someone's going through the log files and sees the password, they can easily impersonate the original user and we want to avoid that. Okay, given these goals, what are the environment and what are the assumptions? Well, the first thing is since we are going to authenticate the user, we absolutely need to know where the authentication data is, and determine the password, how do we validate it? On Linux and Unix the usual way is through a password file of some kind, /etc/passwd in the old days, /etc/shadow in the newer days. Some systems though use Kerberos, others use distributed authentication tools like AgRom or OAuth2 interfaces or things like that. We're going to assume that all this data is up-to-date. One of the most common errors a company makes is when someone leaves they don't change their password, so the person can still get back in. The third question we have here is, does it use environment variables? These are variables describing aspects of the system or of the environment that affect how the program runs. The login program also needs to set the correct environment, and this is not so much when you log in initially, it's when you log in when someone else is using the terminal or the connection. The first case you get a pristine environment, but in the second case where someone has a session going and you type login and your name to log in as yourself. The environment may be inherited from that session, so you want to make sure it's not. You want to make sure login always cleans out the environment. Now here come a couple of riddles and examples. If you look at the code here, first of all it gets the host name from the environment and does something. It then looks to see if there's an error rather and it does something else. Once it gets that name it comparison to host one and if so it uses a protocol called SKEY key to authenticate. If its host to it uses Kerberos and if it's host three it uses a shadow file. What is the problem with this code? Well, the big problem is get env host. Host is an environment variable which means it's under the control of the person running the program. So, that person if they for example don't have access to SKEY, but are on the Kerberos list, they can force Kerberos to be used simply by setting host to host two, whereas it really should be host one. So, this effectively lets the host decide how they want to authenticate. If you are going to do this, don't pull the host name from the environment, use something like get host name or get host by name whichever your system supports to get the host name because that's done by the kernel not by the user. Now, here's another one that actually existed and it recurred which is the reason I bring it up. This system here was in login part, this part was in the login program. First it said always authenticate, but then it looked at the options to login. If you gave it a dash and flag, it would turn off authentication so it would immediately log you in as it claimed you to be. Now, the reason this was done was in the early days of Windows systems, what used to happen was they would have you log into each Window. That was painful so they call login dash n, as a Windows started so you'll automatically be logged in. The problem here is of course a bad assumption. The dash n would never be invoked by the user. When you sit down to log in as a regular user, you presented it with the login prompt, there's no way to give the dash n option. But once I login normally, what it can do is type login dash n route. The dash n says don't authenticate, so I immediately get access to the system administration account. That's why you don't want to do this. This occurred if I remember correctly in the late eighties. Then sometime in the late nineties, people were looking through the code of a particular system and noticed it happened to use the same code as was in the earlier library. So, they tried this and it turned out it was a different flag, I forget which one, but exactly the same thing happened. So these errors do recur. Now, here's another problem where you're going to mail message to staff saying, "Send help soon." The way you're going to do this in this program is you're going to open pipe to a shell, and the shell will execute the command male staff as though it were typed at the terminal window. The w means opened for writing, so then you're going to write send help soon, close it and then when you close that p open ends the shell which will cause the mail to be sent. There at least three problems in this code. The first one is, how do you know which mail program it's getting. On this system you control that by a path variable, it's an environment variable but it's under the users control. So, the user could set it to a directory containing his or her own mail program. The second one is, how do you know the shell command works as expected? It may be that when the shell starts up, the default shell runs a small startup script that gives me whatever program I want. If this is coming from root, privileges and privileges aren't dropped, that means I can do whatever I want as root. The third thing is, even if I fix this to say, "I'm user bin mail" or whatever the mail program is located at. How do you know that I can't somehow change the interpretation of slashes from Directory to blank? So, slash bin slash mail would be read by the shell that you invoke in this be open as bin with the argument mail. I can easily write a script called bin to do all sorts of interesting things when run from this. The way to get around that is a shell variable called Internal Field Separator. Many shells now no longer lets you set that, specifically because of the type of the attack I'm talking about. But the Internal Field Separator or IFS, if it has a slash, well that means slashes is interpreted as a blank or actually a word separator to be technical. One last puzzle. Here's the code. What I'm doing is I'm resetting path to a known safe value. So, I am going through an environment list called environ which I got from the call. I'm looking for the first five characters of any variable being path. If I've got it, then I'm simply going to replace it with my own path, presumably to make things safe. Then I'm going to run a program which invokes the shell and sends, "Hi there" to me. This looks good until you start asking, "Why am I assuming there's only one path there?" Because if you have the path environment variable, I break at the first one. What happens if there's a second? It's actually fairly easy to do that. All you do is you pull in the current environment list, create a new array and copy it over, tack on a new value of path and then spawn the shell. It's very enlightening because some shells go from zero back and stop at the first one. Others go from zero back and stop at the last one. Which is which? It depends, so that's another thing you have to be somewhat careful of. So this brings us to a checklist and again these checklists are not meant as if you do this you'll be safe. What checklists are meant to do is simply help you focus attention. You'll find things there are times when the checklist should be ignored. That's fine you should just be able to justify it. But the big checklist item here is, what will the users or will I be getting from the environment or from the users or what? How do I check for validity, how do I know if it's bogus and what assumptions am I making? Ask yourself those and those will help you uncover potential problems with your program. The second checklist item is, what am I assuming about library functions? The big issue here is not so much what the functions do when they return, but what did they do as side effects? What assumptions do the library functions make? What information does it obtained from remote servers in the environment because, many libraries use environment variables as well and some will go out to remote servers and ask for questions. What information does it get? The third one is, does the library function do what the manual claims? Read the manual very carefully, because at times the wording is very imprecise and other times it's very precise and if you don't read it precisely, you'll get messed up.