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!

Friday, December 2, 2011

How to get process full name programmatically (Solaris)

In the previous post I described how to get the command line and the full name of process executable file on Linux. However, the described solution does not work on Solaris.

Solaris has the /proc pseudo-filesystem directory as well, but it’s structure is different.

On Solaris 10 there is a link /proc/PID/path/a.out which points to the executable file. So it’s enough to call readlink function.
Prior to Solaris 10, things are more complex. I haven’t found a reliable way to get a full name of the executable file. But the following notes may be useful.

There is a binary /proc/<PID>/psinfo file, which stores data as in struct psinfo (#include <procfs.h>). This struct has pr_fname and pr_psargs fields. But it seems that pr_fname usually holds the file name of executable only, without the absolute path. The second problem is that both pr_fname and pr_psargs can be truncated.

There is a function called getexecname(), which returns file name of the executable. But it has the same problem: it may hold the file name part only, without the absolute path. Manual recommends getcwd function which returns the current working directory. However, current working directory may differ from the starting directory so this solution is not reliable.

So the following program illustrates all of these approaches:

#include <stdio.h>
#include <unistd.h>
#include <procfs.h>
#include <stdlib.h>

int main() {
ssize_t linknamelen;
FILE *f;
char linkname[256], filename[256];
pid_t pid = getpid();

/* try to readlink the file /proc/PID/path/a.out */
sprintf(linkname, "/proc/%d/path/a.out", pid);
linknamelen = readlink(linkname, filename, sizeof(filename) / sizeof(*filename) - 1);
if (linknamelen > 0) {
 filename[linknamelen] = 0;
 printf("Full name is %s\n", filename);
} else {
 getcwd(filename, sizeof(filename) / sizeof(*filename) - 1);
 printf("Current directory is %s. Name is %s\n", filename, getexecname());
}

/* read the command line from /proc/PID/psinfo */
sprintf(filename, "/proc/%d/psinfo", pid);

f = fopen(filename, "r");
if (f) {
psinfo_t info;
if (fread(&info, sizeof(info), 1, f) > 0) {
    printf("fname=%s, args=%s\n", info.pr_fname, info.pr_psargs);
}
fclose(f);
}

return 0;
}

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 

Monday, November 21, 2011

How to get process full name programmatically (Windows)

This post describes the Windows API that can be used to get the command line and the full process name.


To get command line, use the function GetCommandLine. Of course we could use the arguments of the functions main (in case of console app) or WinMain (in case of GUI app) instead, but this code makes things a bit easier (for instance, in cases when we need to add command line parsing to large existing project or when we just want to print command line for debug purposes etc).
To get the path of the executable file of the current process, use GetModuleFileName.

So the code may look like:

char s[MAX_PATH];
printf("GetCommandLine=%s\n", GetCommandLine());

if (GetModuleFileName(NULL, s, sizeof(s) / sizeof(*s)) > 0)
  printf("GetModuleFileName=%s\n", s);

To illustrate the difference between these two functions let's compile the program to "c:\t\testtesttest.exe" and run several tests from the command line:

c:\t>testtesttest.exe 1 2 3
GetCommandLine=testtesttest.exe  1 2 3
GetModuleFileName=c:\t\testtesttest.exe

c:\t>testte~1.exe    1
GetCommandLine=testte~1.exe     1
GetModuleFileName=c:\t\testtesttest.exe

c:\t>testtesttest arg1
GetCommandLine=testtesttest  arg1
GetModuleFileName=c:\t\testtesttest.exe

c:\t>c:\t\testtesttest.exe
GetCommandLine=c:\t\testtesttest.exe
GetModuleFileName=c:\t\testtesttest.exe

Friday, November 18, 2011

MS Visual Studio: debugging tips

How to cause a debug break of a Windows process.

Sometimes it's impossible to start a process under debugger. Instead, I want the debugger to be started when a process reaches some point.

To cause a debug break from the code, choose any of the following:
  1. Call DebugBreak() API.
  2. Call the built-in function __debugbreak().
  3. __asm int 3;
When any of this instruction is reached, a special window is usually displayed with a possibility to start debugger.

Why it is not working:

1. If you have Windows 7, go to Control Panel->Action Center->Change Action Center Settings->Problem Report Settings and make sure "Each time a problem occurs, ask me before checking for solutions" is checked (thanks to http://stackoverflow.com/questions/890890/debug-program-option-in-windows-7). Actually this is very important option. If it is not selected, the program crash can be silent, which is terrible for developers and testers.
2. In fact, all these commands cause breakpoint exception. So it is possible to ignore these exceptions with the help of Structured Exception Handling (SEH). For instance, the following code ignores debug break:

_try {
    DebugBreak();
} _except(EXCEPTION_EXECUTE_HANDLER) {
}

(of course, _except block can be located anywhere in call stack).

How to launch the Debugger Automatically when the application with the specified name starts.

It is possible to automatically debug an application of the specified name (for instance make "my_test.exe" always run under debugger). For details, see http://msdn.microsoft.com/en-us/library/a329t4ed%28v=vs.80%29.aspx

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...