Monday, June 28, 2010

what is SUID?

  SUID, Set User-ID, is one of the most beautiful concepts in UNIX. The common definition given for SUID is, it is an advanced file permission which allows an user to execute a script as if the owner of the script is executing it, and the famous example used for SUID is the passwd command. 

Let us do a case study right away to understand what exactly is SUID bit and how to use it.
 
A user 'blogger1' writes a simple script:
#cat test.sh
#!/usr/bin/ksh
dt=`date`
echo $USER  $dt  >> ~blogger1/log
echo "Updated the log file sucessfully."
  The above example shows a simple shell script which  writes the username and date-time to a log file and echoes a confirmation statement . On running the script, everything happens as expected for the user 'blogger1' as shown below.
#chmod 755 test.sh
#ls -l test.sh log
-rwxr-xr-x  1 blogger1 blogger1 60 Jun 24 21:44 test.sh
-rw-r--r--  1 blogger1 blogger1  0 Jun 24 21:44 log
#./test.sh
Updated the log file sucessfully.
#cat log
blogger1 Fri Jun 25 08:01:16 IST 2010
   Now, the user 'blogger2'  has been told to run this script everyday. Since the script 'test.sh' has executable permission for others, 'blogger2' can execute the script.

The user 'blogger2' logs into his account and does:
#PATH=$PATH:~blogger1
#which test.sh
/home/blogger1/test.sh
#test.sh
test.sh: line 3: /home/blogger1/log: Permission denied
#
   The 'blogger2' updated his path to where the script test.sh is present. On trying to run the script, 'blogger2' got an error stating "Permission denied" on the log file. The error occurred because the 'log' file has write permission only for the owner which is 'blogger1'. When 'blogger2' runs the script, effectively it means 'blogger2' is trying to write on the file 'log' on which he has no permission, and hence the error.

  At the outset, a solution can be thought of to give the 'write' permission to the user 'blogger2' on the file 'log'.  Let's try and see.

The user  'blogger1' gives the write permission on the log file:
#chmod o+w log
#ls -l log
-rw-r--rw-  1 blogger1 blogger1  20 Jun 24 21:44 log
Now, the user 'blogger2' tries to run the script:
#test.sh
Updated the log file sucessfully.
#cat ~blogger1/log
blogger1 Fri Jun 25 08:01:16 IST 2010
blogger2 Fri Jun 25 08:41:16 IST 2010
   The script ran successfully. However, the problem is not solved, instead it got bigger. Though the 'write' permission was given on the 'log' file to enable 'blogger2' run the script, effectively it will now enable the 'blogger2' to simply open the 'log' file and start editing as per his wish. This is because 'blogger2' has the 'write' permission and everything is his now.

  So, we want a solution wherein 'blogger2' does not get to edit the 'log' file directly, however still can run the script 'test.sh' which updates the 'log' file. This means we would like to have some kind of permission by which the effective user(blogger2) gets the permissions of the real user(blogger1) on running the test.sh script.
 
 This is where SUID comes in. When the SUID(s) bit is set on an executable, whoever runs the executable gets the same permission as the owner of the file. The SUID can be set on a file by adding the 's' bit as shown below:
#chmod o-w log
#chmod u+s test.sh
#ls -l test.sh log
-rwsr-xr-x  1 blogger1 blogger1 60 Jun 24 21:44 test.sh
-rw-r--r--  1 blogger1 blogger1 20 Jun 24 21:44 log
#
     Once the SUID is applied, it means any user who runs the executable will get the permissions of the owner of the file while running it. So, when 'blogger2' tries to run the test.sh, UNIX treats 'blogger2' with the same permission as the owner 'blogger1' has on the 'log' file, and hence 'blogger2' can update the 'log' file successfully through the script.

The 'blogger2' now tries to run the script:
#test.sh
Updated the log file sucessfully.
#cat ~blogger1/log
blogger1 Fri Jun 25 08:01:16 IST 2010
blogger2 Fri Jun 25 08:41:11 IST 2010
blogger2 Fri Jun 25 08:58:14 IST 2010
#
    This is how the SUID bit works. The same concept is being used in the passwd command as well. The passwd command can be used by any user to set/change his password. When the passwd command is run, it internally updates the system file /etc/passwd on which only the root user has the 'write' permission.  By making the passwd executable SUID enabled, any user can change his password effectively updating /etc/passwd file.


Enjoy with SUID!!!

P.S. SUID is one of the most DANGEROUS features in UNIX. I will explain why so in one of my future articles.

Monday, June 21, 2010

5 different ways to count the total lines in a file

 In one of our earlier articles, we saw the different ways to find the length of a variable. In the same lines, we will see the different ways to get the count of total lines in a file.


1. The most common method used is the piping of wc command with cat.
# cat file | wc -l
2. grep has the '-c' option to do line count of patterns matched. The '.*' tells to match anything which essentially means to match every line.


# grep -c '.*' file
3.  sed uses '=' operator for line numbering. The '$' tells to give the count only for the last line.
# sed -n '$=' file
4. awk can be used to get the file count using NR variable. NR contains the line number and   by printing NR at the end block, we get the line number of the last line, which essentially is the total lines in a file.
# awk 'END {print NR}' file
5. perl also has the same END block like awk. However, $. denotes line number in perl.
# perl -lne 'END {print $.}' file

Monday, June 14, 2010

What is .exrc file for?

   vi is one of the most commonly used editors in UNIX. When we open a file using vi, we do some settings depending on our needs say, to set line number, to set indentation, to set the tab space etc in the file. However, these settings or customizations last only till the file is open. Some of these settings any user would always like to retain on opening any file.  These settings can be grouped in a file called .exrc file, and hence the settings become permanent.

  Whenever a file is opened using vi, vi looks for the .exrc file in the home directory of the user. If present, it reads the file and applies the settings in the file being opened. And hence any customization we would like to have in the file should be put in this. In fact, all the commands which we execute in the escape mode or the last line execution mode can be put in the .exrc file.

Settings commonly maintained in the .exrc file are:

1.  Set commands :- Set commands used in vi like set list, set number, etc.
2. Abbreviations:-  Frequently used words can be abbreviated. For example,say, a user uses the word 'include' lot many times.  The user can create an abbreviation 'inc' for the word include.
3. Mapping keys:- Some key combinations can be mapped or made into a hot-key combination. We saw in in one of our earlier articles, how to map function keys.

A typical $HOME/.exrc file will look like as shown below:
set number
set autoindent
set nowrapscan
ab inc include
map Q :q!
1. The first three entries are part of the set commands, which includes setting line number, auto-indentation and search wrapping. With these settings, whenever a file is opened, automatically the line numbers will be set, and so is the indentation and search wrap.


2. The abbreviation 'ab inc include':- whenever you type 'inc' followed by a space in a file, it automatically gets converted to 'include'. This is a very helpful feature at times.

3. map Q :q! - This command maps the Q key with the quit operation. So, whenever the user wants to quit the file, instead of typing ':q!', the user can simply type 'Q' from the escape mode.

   The .exrc file should be present in the home directory itself and there is no limitation on the number of customizations being done in it.

Thursday, June 10, 2010

Different ways to split the PATH variable

  Hardly a day passes for a UNIX programmer or an administrator without executing the command 'echo $PATH' . A typical output of this command will be as shown below:
#echo $PATH
/usr/xpg4/bin:/usr/bin:/bin:/usr/local/include
  In the above example, for simplicity, we have shown only 4 components in the PATH variable. However, in a real-time environment, the number of components in a PATH variable could be really lot. And hence it becomes really cumbersome to interpret OR to know whether a particular component in the PATH variable what we are looking for is present or not. In fact, even doing grep on the 'echo $PATH' wont help us since either it will return the whole thing back or nothing.

  It would have been more readable had the PATH variable been split or broken and displayed as shown below:
/usr/xpg4/bin
/usr/bin
/bin
/usr/local/include
Let us see the different ways how we can split the PATH variable:

1. The simplest and my favorite is echo piped with tr. (tr is one of the most powerful commands ). This simply substitutes ':' with a new line.
#echo $PATH | tr ':' '\n'
2. There are many ways in awk to achieve the same. This one is using the record separator RS.
#echo $PATH | awk  '1' RS=":"
     The default RS is a new line. In this case, we tell awk to consider ':' as the record separator, and hence it prints every component on encountering the ':'.

3. awk provides a gsub function using which the we can split the variable. The gsub substitutes all ':' to newline:
#echo $PATH | awk 'gsub ( ":","\n" )'
4. Using the ':' as delimiter, we can read the different components as different columns:
#echo $PATH | awk -F: '{ for(j=1;j<=NF;j++) print $j;}'
5. The last one using the 'sed'. However, this is the least, I would prefer among the rest. sed replaces('s') all(g) occurrences of  ':' with a form-feed character. The newline cannot be used as a replacement in sed as with 'tr' command and hence this workaround:
#echo $PATH | sed "s/:/`echo  '\f'`/g"
   Friends, in every article, we try to solve a problem with as many different options as possible. The reason is simple: Next time we encounter an issue, we start thinking in many different ways.

Happy Unix Programming!!!

Tuesday, June 1, 2010

Different ways to print non-empty lines in a file

 There are times when we want to display only the actual lines in a file, leaving the blank lines. There are various methods in which we can print only the non-empty lines of a file.

1. The simplest of all is using the famous 'grep' command:
grep -v '^$' file
     This is one of the most common methods used to get the non-empty lines of a file. The '^' is used to denote "lines beginning with", and '$' is used to denote "lines ending with".  In this case, '^$' means a line beginning with and ending, which is nothing but a blank line. By using the -v options, we get the lines other than the blank lines.

2. Different ways of achieving the same thing in sed:
sed '/^$/D' file
      The above method removes('D') all the patterns(blank lines) matching and displays the rest.
sed -n '/^$/!p' file
     This form suppresses the default output(-n) and prints the non-empty(!p) lines.

3. Three different ways of getting non-empty lines using awk;
awk NF file
     This is my favourite of all. NF indicates the total number of fields, and hence this prints only non-blank lines, since in blank lines NF is 0 and evaluates to false.

awk 'length' file
      This one is almost same as the above, but uses the length function and prints only those lines whose length is > 0.
awk '$0 !~ /^$/' file
      An other option using awk as the previous methods.  !~ indicates lines not containing.

4. Getting the non-empty lines using perl:
perl -lne 'print if length($_) ' file
      This is perl version of using the same in awk as before.
perl -lne 'print if $_ ne ""' file
     $_ indicates the current line. Prints only those lines which is not(ne) blank.
perl -ne 'print unless /^$/' file
     'print unless' indicates print lines which does not contain.