Showing posts with label linux. Show all posts
Showing posts with label linux. Show all posts

Saturday, February 4, 2012

How to calculate MD5 hash value using OpenSSL library

OpenSSL is an open source library which provides the basic cryptographic functions (see http://www.openssl.org/ for details).

This post describes how to use cryptographic hash functions (MD5 as an example) provided by this library.

Actually, type "man EVP_get_digestbyname" and you will see description of the needed functions and a sample.

Here is the example with my comments:
#include <stdio.h>
#include <openssl/evp.h>

main(int argc, char *argv[])
{
  EVP_MD_CTX mdctx;
  const EVP_MD *md;
  char input[] = "md5";
  unsigned char output[EVP_MAX_MD_SIZE];
  int output_len, i;

  /* Initialize digests table */
  OpenSSL_add_all_digests();

  /* You can pass the name of another algorithm supported by your version of OpenSSL here */
  /* For instance, MD2, MD4, SHA1, RIPEMD160 etc. Check the OpenSSL documentation for details */
  md = EVP_get_digestbyname("MD5");

  if(!md) {
         printf("Unable to init MD5 digest\n");
         exit(1);
  }

  EVP_MD_CTX_init(&mdctx);
  EVP_DigestInit_ex(&mdctx, md, NULL);
  EVP_DigestUpdate(&mdctx, input, strlen(input));
  /* to add more data to hash, place additional calls to EVP_DigestUpdate here */
  EVP_DigestFinal_ex(&mdctx, output, &output_len);
  EVP_MD_CTX_cleanup(&mdctx);

  /* Now output contains the hash value, output_len contains length of output, which is 128 bit or 16 byte in case of MD5 */

  printf("Digest is: ");
  for(i = 0; i < output_len; i++) printf("%02x", output[i]);
  printf("\n");
}

Link with crypto library (-lcrypto).

Sunday, January 8, 2012

Useful Linux commands

Useful information about Linux commands.


1. The very famous "Argument list too long" issue.
When I try to copy too many files with command like
cp /blablabla/somedir/* ./
I got error like "-bash: /bin/cp: Argument list too long". The same problem appears in any command where asterisk applies to a large count of files.

An easy way to deal with it is to use find command. For instance,
find /blablabla/somedir/ -name "*" -exec cp -p {} ./ \;


2. Rather useful GUI to build find command:
http://find.unixpin.com/

3. Get information about executable files and/or shared libraries.

ldd prints the shared libraries required by each program or shared library specified on the command line.
For instance,
ldd a.out - prints out the list of *.so files on which a.out depends.

nm - list symbols from object files (for instance, can be used to get list of functions in *.so file).

file - determine file type.
For instance,
file a.out prints out the file format and target architecture (i.e. 32 or 64).

objdump - display information from object files.

For instance, 
objdump -f a.out
may be used to get file format as well;

objdump -x a.out
prints out a lot of useful information.

4. How to find out Linux distribution name and version.

cat /etc/*-release - for distribution name.
uname -mrs - prints the machine hardware name, the kernel release and the kernel name. This can be used to get CPU type: CPU is 64bit if you see x86_64.
lsb_release -a - prints Linux Standard Base and distribution-specific information.

More information is available here and here.

5. lsof - list open files.
lsof -i :8000 - who is listening on the port 8000.

Monday, January 2, 2012

How to list all users of the given group (Linux)

Let's say I have a group name and I want function that lists all users of this group.

From the first point of view, the solutions is obvious. There is a function getgrnam which returns a pointer to struct group which has array of strings gr_mem (type "man getgrnam" for details). So we need to call the function and iterate through gr_mem until we meet NULL.

However, this is not accurate.  The problem is that this function parses the group databases. Some users may be not present in the group database but may have group id set as a field in /etc/passwd. So we need to iterate through all users to find those of them who have group id equal to the id of the given group.

The following code illustrates this approach. Please note that it is a sample only. In the real project you will need to check for duplicates because some users may be listed twice.

#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <stdio.h>

void list_all_users(const char *groupname) {
  struct group *grp = getgrnam(groupname);

  if (grp) {
    unsigned int i = 0;
    struct passwd *user_info;

    printf("group %s has the following members:\n", groupname);

     /* iterate through groups database */
    while (grp->gr_mem[i]) {
      printf("  %s\n", grp->gr_mem[i]);
    }

    for (user_info = getpwent(); user_info; user_info = getpwent()) {
      if (user_info->pw_gid == grp->gr_gid) {
        printf("  %s\n", user_info->pw_name);
      }
    }

    endpwent();
  } else {
    printf("group %s not found", groupname);
  }

}

How to list all users / groups programmatically (Linux)

In my previous post I described how to list all users / groups on Windows machine.

This post describes how to list all users / groups of Linux server.

Use functions  getpwent for users and  getgrent() for groups (type man getpwent or man getgreent for details).

The sample code looks like:

#include <sys/types.h>
#include <pwd.h>
#include <stdio.h>

void list_users(void) {
  struct passwd *p = getpwent();

  for (; p; p = getpwent()) {
    puts(p->pw_name);
  }

  endpwent();
}

void list_groups(void) {
  struct group *p = getgrent();

  for (; p; p = getgrent()) {
    puts(p->gr_name);
  }

  endgrent();
}

Wednesday, December 7, 2011

How to check password expiration date programmatically (Windows, Linux, Solaris, AIX)

Many operating systems allow you to set maximum password age. After it is reached, user gets the message like “Your password has expired and must be changed”. For instance, in case of Windows 7 you can set maximum password age in the following way:

1. Run “secpol.msc”
2. In the left pane, expand “Account Policies”, and click on “Password Policy”. Edit the values in the right pane.
3. Make sure that user account has password expiration enabled: run lusrmgr.msc, find the required user account, click proiperties, ensure that “Password never expires” is uchecked.

(see http://www.sevenforums.com/tutorials/7539-local-users-groups-manager-open.html, http://www.sevenforums.com/tutorials/73210-password-expiration-enable-disable.html for details).

The post describes the API that allows you to find password expiration date for a specified user account.

1. Windows: use NetUserGetInfo function. For a given domain controller name, user name and information level it returns user information. In our case we need information level 2 (and probably higher). In this case information is returned in USER_INFO_2 which has a field called usri2_password_age (the number of seconds that have elapsed since the password was last changed).

Now check the NetUserModalsGet fuction. For a given domain controller name it returns global information about users (see struct USER_MODALS_INFO_0, which has a usrmod0_max_passwd_age member). Now just subtract usri2_password_age from usrmod0_max_passwd_age and divide by 60*60*24 (the number of seconds in a day) to get count of days left.

To get the domain contoller you may use NetGetAnyDCName fuction (for instance, call NetGetAnyDCName(null, L“MYDOMAIN”, &controller) to get the domain controller of MYDOMAIN).

All of the functions mentioned above allocate memory, so do not forget to free it using the NetApiBufferFree function.

Samples can be found in MSDN.

2. Linux and Solaris provide a set of shadow fuctions (#include <shadow.h>).
We are interested in getspnam function.
For a given user name It returns a pointer to struct spwd. Interesting members are sp_lstchg (days since Jan 1, 1970 password was last changed) and sp_max (days after which password must be changed). So (spwd.sp_lstchg + spwd.sp_max) is a date when user’s password must be changed.
More information is available in manual.

3. AIX. I haven’t found a reliable way to find password expiration date. A possible solution is to call passwdexpired function. For a given user name it returns a character string like “Your password will expire: Wed Nov 2 10:30:35 EDT 2011”. Now it is possible to parse the string. However I am not sure in the format of message and hence I dislike this solution.
If you know any way to get the password expiration date, please let me know!

Wednesday, November 30, 2011

How to get process full name programmatically (Linux)

In the previous post I described Windows API that can be used to get command line and full path of the EXE file of the process.
This post describes how to get the same information on Linux.

There is a  pseudo-filesystem directory called “/proc/[PROCESS-ID]”,  which contains a set of useful files that describe the process with PROCESS-ID. In our case we may use files “/proc/[PROCESS-ID]/cmdline” and “/proc/[PROCESS-ID]/exe”.

/proc/[PROCESS-ID]/cmdline” is a text file which contains the command line. Note that arguments are separated by 0 character, so if you just fgets / puts you see program name only.
/proc/[PROCESS-ID]/exe” is a symbolic link to executed command. To read the value of symbolic link you may use readlink (note that readlink may not append 0 character to the string!).

So the code may look like:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

void get_command_line() {
 FILE *f;
 char file[256], cmdline[256] = {0};
 sprintf(file, "/proc/%d/cmdline", getpid());

 f = fopen(file, "r");
 if (f) {
    char *p = cmdline;
    fgets(cmdline, sizeof(cmdline) / sizeof(*cmdline), f);
    fclose(f);

    while (*p) {
     p += strlen(p);
     if (*(p + 1)) {
       *p = ' ';
     }
     p++;
    }
    puts(cmdline);
 } else {
    printf("unable to open file %s\n", file);
 }
}

void get_full_process_name() {
 size_t linknamelen;
 char file[256], cmdline[256] = {0};

 sprintf(file, "/proc/%d/exe", getpid());
 linknamelen = readlink(file, cmdline, sizeof(cmdline) / sizeof(*cmdline) - 1);
 cmdline[linknamelen + 1] = 0;

 printf("Full name is %s\n", cmdline);
}

To get more information:

man proc
man 2 getpid
man 2 readlink

And now a few notes about links. Suppose that you compile the source to “a.out” file and created a soft link called “aaa” to it:
ln -s ./a.out aaa

Now if you run
./aaa
the result is:
Command line: aaa
Full name: /home/ivbel/my_tests/a.out

And if you create a hard link like
link ./a.out hard_a

The result of running hard_a is
Command line: hard_a
Full name: /home/ivbel/my_tests/hard_a 

Thursday, November 17, 2011

Useful GVIM Tips

The things that I didn't know about GVIM editor.

How to prepare _vimrc file (i.e. the file with the default settings)

Windows:
1. Copy "C:\Program Files (x86)\Vim\_vimrc" to $HOME/_vimrc.
If you don't have $HOME variable, you may see it in Gvim with the help
:e $HOME/_vimrc

2. Edit $HOME/_vimrc, add commands there.

Linux:
vim $HOME/.vimrc
add commands there.

For instance, my favorite tab stop options:
:set tabstop=2
:set shiftwidth=2
:set expandtab
:set backspace=indent,eol,start

How to make the 'Backsapce' key work properly in Edit mode:
:set backspace=indent,eol,start
(more info here: http://vim.wikia.com/wiki/Backspace_and_delete_problems)


How to start Gvim maximized under Windows:
(taken from http://vim.wikia.com/wiki/Maximize_or_set_initial_window_size)
Add the following line to _vimrc:
au GUIEnter * simalt ~x "x on an English Windows version. n on a French one

It is possible to have only one Gvim running:

Edit "file.txt" in server "FILES" if it exists, become server "FILES"
otherwise:
    gvim --servername FILES --remote-silent file.txt

This means that you'll have only one Gvim running. New files will be opened in already running Gvim.

More information here:
http://vimdoc.sourceforge.net/htmldoc/remote.html

Hidden characters in GVIM

Display hidden characters: :set invlist
(taken from http://dinomite.net/2007/vim-tip-show-hidden-characters) 

Learn the code of symbol under the cursor: ga

Find the symbol with code (for instance, Tab symbol with hex code 09):
/\%x09
Replace: the same, for instance :s/\%x09/  /gc
(taken from http://durgaprasad.wordpress.com/2007/09/25/find-replace-non-printable-characters-in-vim/)

How to show line numbers:
To turn line numbers on  :set nu
To turn line numbers off :set nu!  

How to convert the file from Windows to Unix format using GVIM
(i.e. replace \r\n to just \n)
1. Open file in GVIM.
2. :set ff=unix
3. Save the file and exit


How to remove empty lines in GVIM

:,$s/^\s*\n/
(more tips here: http://www.rayninfo.co.uk/vimtips.html, great source of GVIM info) 

How to make arrow keys work properly in edit mode in Vi on Linux term

Problem: It seems that when I am using VI through putty when I am in insert mode I get escape characters, instead of the cursor moving when I use the arrow keys.

Solution: 1. use vim.
2. Create a .vimrc file in your home directory:
echo syntax enable > ~/.vimrc

Read here: http://www.bluehostforum.com/archive/index.php/t-6700.html


To be continued...