Pages

A look into /etc/passwd,/etc/shadow and /etc/group

As all operating systems, linux also allows us to create users and protect the login by the use of passwords.

Every user is linux is allocated a user id which the kernel user internally while doing user specific operations.

Other than users, linux also allows us to create groups, which can consist of more than one user. The advantage of the groups is that if we want to address a number of users at the same time, for e.g. give read/write permissions of a file to a specific set of users, then we can create a group with that set and then assign the permissions to the group thus enabling us to address all the users we are interested in. Similar to user id every group also has a group id and every user has a group of his/her name by default.

Every user that is created in linux has folder by the user name in the /home folder (Other than root for whom home folder is /root). For example if we create a user by the name "user1" then there will be a folder by the name "/home/user1" and if the user is not an admin he/she will have rights to modify files only under his/her home folder.

To maintain information about the users,groups and their passwords linux makes use of three files .

1./etc/passwd

This file has the information regarding all the users in the system,their user id,group id, etc.

Every line in the file is an entry for one user, the following figure gives a break up of what each field in a line means.





If the password field does not have an "x" it means that the user does not have a password set, else the presence of "x" indicates there is a password and the same is stored in encrypted format in the /etc/shadow file.

The user info field can hold extra information about the user like contact address,phone number etc which can be read using the commands like finger .

The users who have a shell in their last field are the only ones who can log in.

2. /etc/groups

This file has information regarding the various groups in the system, each line gives information about one group. The figure below gives the details of the various fields in a line mean





3. /etc/shadow. This file stores the password of all the users in an encrypted format, and other information related to the password as shown in the image below.





The password could be encrypted using different methods, which is recognized by the "id" present after first character which is the "$" symbol. The table below gives the value of the id and the corresponding encryption technique it indicates.



What ever follows after the id is the encrypted passowrd. For eg if the encrypted password field has

$6$VmCqoObV$W5qPmTUyb4TwG6HUwpgZH5/bpPr8KpcyJJTVHzZe0Y..(etc)

Then from the "id" value of "6" we can deduce that the encryption is done using sha512.

All the values of number of days in the /etc/shadow file are counted with reference to Jan 1 1970.

Thus using the file /etc/shadow and /etc/passwd the system manages the authentication and information for all the users in the system.

Viewing the contents of a directory in tree format

There are number of differnt ways to view the contents of a directory on the command line using the command "ls". But in case you want to view the contents in a tree format, that is starting from the parent directory every file and folder getting listed under its repective directory in the form a tree then the command tree comes to the rescue.

The command might not be available by default in many distros in which case you will have to install the relevan packge. For eg in case of debian based systems, search for the packge "tree" in the package manager and install the same.

Once installed, you can view the contents of any directory in the "tree" format using the command " tree ".

Example :

Let us create a directory "temp1" and in that we will create a file "file1" .



Now in the directory temp1 create two directories temp2 and temp3



In temp2 and temp3 create files file2 and file3 respectively



Now use the command "tree" on temp1



The output should look like this


The directories and files are displayed in their respective colors, and at the end of the output the total number of files and directories present is also displayed.

Inter process communication using shared memory

Processes can communicate between each other in various ways, one of the techniques is by using shared memory, i.e. the processes share a memory region between each other which both can read from. Processes can read and write from this memory what ever that has to be shared.

To create or get access to an already created shared memory we use the function shmget (shared memory get).



Arguments: key : The key used by the process to identify the shared memory, it is assigned by the process and the other processes which want to communicate with this shared memory need to know this key.

size: The size of the shared memory that is allocated.

flag: If the shared memory is being created then we can use the flag IPC_CREAT as the flag. If we are trying the get access to a shared memory already created then we can pass the mode flag specifying the rights for owner,group and the world in the same format as followed by "chmod".

Return : An identifier to the shared memory which is used along with the "key" to identify the memory segment for communication.

Once the share memory is allocated to start the communication we need forts attach this shard memory with the memory of the process to this we use the function shmat (shared memory attach)



Arguments:

shmid: The identifier returned by shmget

shmaddr: The address where the segment should get attached, if left NULL the system automatically chooses a suitable location for the attach.

shmflg: Used in the specific case when mapping of the segment should replace any existing mapping in the range starting at shmaddr , can be left NULL otherwise.

Return: The address of the shared memory that was attached to the process.

Once the memory segment is attached data can be read from and written to the shared memory using the address returned by shmat and the the functions sscanf and sprintf respectively.

Example:

The following program creates a shared memory in the default mode and then writes a message in the shard memory.

Note the used of IPC_CREAT flag with the shmget call.

write_shm.c



The following code tries access the shared memory created by the above code and read the data written in it. Note that the value of key used by both the codes are same, failing which the shmget will be unable to identify the shared memory.

read_shm.c



Compile the above programs



execute them



You should see the message written by the first process displayed by the second process thus achieving the required communication between the processes.

Introduction to gdb

gdb stands for gnu debugger,a tool to debug programs of language C,C++ etc. It does not have gui and is a command line based debugger.

In this post we will learn how to start using the debugger to debuga simple C program.

First step is to install the debugger, you can do that from your pacakge manager by searching for the package by the name gdb.

Once you have installed gdb open the terminal and run the command

gdb --version

To make sure the installation has happened successfully. You should see an output similar to this.



Now to start debugging let us take an example program

ex_gdb.c



To be able to debug a C program we need to use the option "-g", so that the debugging realted information is incorporated into the executable.

Thus compile the above code as follows



Now to debug this code pass the executable to gdb as below



output:



At this gdb prompt, we can run various commands that will help us debug the code To come out of the prompt use the command quit.

The program is not executing as of now, to start the execution type "run" at the gdb prompt and hit enter. The program starts running and if no break points are set in the program, will run till the end.

To set a breakpoint before starting the execution use the command break for e.g. to set a breakpoint at the function main run the command



As you can see, the execution has halted as soon as the main function is encountered. Now we can single step through the code, executing the program line by line. To execute the next line of the code use the command "next"



You can see above the print statement was executed and its output shown on the screen, before starting the execution of the next statement. At exch step the statement that is going to be executed next is shown.

In case we want to view the value of variables we can use the command "print" and pass the variable name whose value we want to view. For eg. if we want to view the value of "var1" inside for loop in the above program we can do it as follows



As we can see the value of var2 is sbeing printed rightly as "0" after the execution of the statement "var2 = var2 *i" where i was 0.

To stop single stepping and execute the rest of code use the command "continue". The program will run till next break point or till the end of the code if there are no more break points.

Finding out the glibc version

There are four ways to find the glibc version that is installed in the system.

1. Open a terminal and run



Which should give an output like



Indicating the glibc version is 2.11.3.

2. The second method is by writing a program for it.

glibc_version.c



Compile it



and execute it



output :



Note: You might get a different output based on your version.

3. Open a terminal and run the command



output :



4. The fourth rather crude way which would work if are running debian based systems is to open the synaptic package manager and go to the package libc-bin and see the installed version number in front of it.

IPC: Messgae queues with message priority

In the previous post we saw how we can create a message queue and use the same to communicate between processes.

The message queues also have the ability to assign priorities to messages that are sent, so that while recieving the messages with higher priority are recieved first even if they are sent after a low priority message.

Let us look at this operation of the message queues using an example.

We will use the example similar to the one used in the previous post, only difference being the queue is being created by the sender where as in the previous example it was created by the reciever.

To set the priority of a message we pass the priority as an integer number to the call mq_send. For eg :



The last argument "1" is the priority of the message, higher the integer number higher the priority.

Let us send 4 messages each with a different priority and send the least prioirty message first. i.e.



And in the recieve program we will recieve using mq_recieve 4 times, and while recieveing we will read the priority of the message and display the same.



The complete codes for the two programs will be as below.

prio_send.c



recieve.c



Compile the two programs



First execute the send program, so that we send messages of four different priorities in the queue



Now to read the message execute the receive program



The output should be :



Thus we can see that the message queue does not perform as a fifo and the message with higher priority is read before message with lower priority .Messages of the same prioirty are read in the fifo manner.

Inter process communication using Message Queues (mq) -2

In the previous post we saw the various functions available for creation of message queues.

Now let us look at an example for creating and communication using message queues.

The first step is to create a message queue using mq_open



Note that the name of the message queue begins with a "/" which is mandatory.

The flag O_CREAT signifies that the queues is being created new, and we are not opening a previously existing queue.

0666 gives read and write permissions to every one

We are creating the queue with default attributes hence leaving the last argument as NULL.

If a process wants to recieve data from the queue, it will need a buffer into which the data will have to be placed, hence we create a buffer for 10 characters as follows.



To recieve data from the queue we need to make use of the function mq_receive, which requires the attribute, "message size", of the queue to be passed to it.

To get the message size of the queue we created we need to make use of the function mq_getattr as follows.



We allocate memory for the structure and then pass the queue descriptor and the structure pointer to mq_getattr, which fills the strucutre with the relevant data.

Now we can get the message size from the structure by accessing the mq_msgsize field, i.e. attr1->mq_msgsize.

Now we can call mq_recevie to get data from the queue .



The full code would look as follows.

recieve.c

Now we need a process to send the messages into the queue.

To send messages we again need to open the queue, but no create it. Hence the call to mq_open would be



Note that the name of the queue, test_q, is same as the one we used while creation making sure that we are sending and receiving on the same queue.

Let us create a buffer having data that has to be sent.



To send data we make use of the function mq_send.



The full code will look as follows

send.c

To see the queue in operation, open a terminal and compile the above two programs.

Note that for compiling these we need to pass the option "-lrt" to the compiler.



Open two terminals and go the directory where the above executable were created.

In the first terminal execute the recieve program



The terminal should go into a wait state, waiting for a message. (It is a blocking receive)

Open the second terminal and execute the send program



As soon as the send program is executed, the terminal waiting in the receive program will recieve the message, and print the same before exiting.

Thus the two processes could communicate with each other using the message queues.

In the future posts we will see how can the message priority be used.