Saturday 16 September 2017

Using pyperclip for working with the clipboard

In this article I'll walk you through using a nice python module named pyperclip. It's really easy to use. I'll be working on a Centos 7 system with gnome GUI interface.

So, let's install the pyperclip module via pip.



Now that the module is isntalled let's write a quick script to demonstrate its usage.

[root@still ~]# cat clip.py 
#!/usr/bin/python

import pyperclip

pyperclip.copy('Hello World')

print pyperclip.paste()
[root@still ~]#


This script when executed gives the below output:

[root@still ~]# ./clip.py 
Hello World
[root@still ~]# 


To use the module we first import it into our script.
Next we copy the strings 'Hello World' to the clipboard via pyperclip's copy function and then print out the contents of the clipboard with pyperclip paste function.

As another example I've jus copied the output of the ls command to the clipboard as shown below:



I've commented out the pyperclip copy function and just left the paste function as it is. Let's execute the script:



As you can see the pyperclip.paste function dumps the content of the clipboard to the screen.

I tried doing the same thing using the command line but it didn't work and kept getting a "You don't have a copy/paste utility" error.
The cause of this error appears to be the fact that when we are working on the Linux command line via an ssh session then we have access to the Windows clipboard and our Linux server computers which generally will not have a GUI wouldn't really have a clipboard.

Monday 11 September 2017

Fixing "key type ssh-dss not in PubkeyAcceptedKeyTypes" in Ubuntu

I recently came across the following error in the auth.log file of an ubuntu server.


Sep 11 11:44:34 unix sshd[5877]: userauth_pubkey: key type ssh-dss not in PubkeyAcceptedKeyTypes [preauth]

I had configured passwordless ssh from a solaris machine to this server using DSA keys.
I later came to know that ubuntu allows passwordless ssh configuration for RSA keys only by default.

The fix for this is adding the following line /etc/ssh/sshd_config file and restarting the ssh service:

PubkeyAcceptedKeyTypes=+ssh-dss


I know this is a very short article but I found it a point worth sharing.

Sunday 10 September 2017

Get result of two or more commands in the same line and redirect the result to a file

Forgive me for the long title of the post but titles should be descriptive of the content that follows and I just wanted to make sure of it for this article.

Generally when we chain commands by using semicolons, the output of each distinct command follows on a new line as shown below:

[root@pbox ~]# uname -a;date
Linux pbox 3.10.0-514.el7.x86_64 #1 SMP Tue Nov 22 16:42:41 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
Sun Sep 10 13:46:26 IST 2017


But what if we have a scenario in which we require the resulting output of the commands we execute to be on the same line. A scenario where I've had this requirement was to interpolate multiple variable names into a csv file. A quick and easy way would be:

[root@pbox ~]# echo "$UID, $PWD" > text.csv
[root@pbox ~]# cat text.csv
0, /root
[root@pbox ~]#


For some odd reason which I can't recall this simple redirect wasn't working for me so I had to come up with something fancier.

I decided to use a subshell, enclose the commands within that subshell and redirect them to the required file. Here's an example:

[root@pbox ~]# ( echo -n "Logged into `hostname`"; echo ", on `date`" ) > text
[root@pbox ~]# cat text
Logged into pbox, on Sun Sep 10 13:57:47 IST 2017
[root@pbox ~]#

The -n flag with the echo removes the new line it add at the end of it's output.

We could do something similar without invoking a subshell and that is by using curly braces {}.
Here's an example:

[root@pbox ~]# { echo -n "This is a `uname -s` box "; echo ", btw Today is `date`" ;} > text
[root@pbox ~]# cat text
This is a Linux box , btw Today is Sun Sep 10 14:01:37 IST 2017
[root@pbox ~]#

Fixing "[Errno 17] File exists" for CA Certificates Service in Solaris 11

Recently I encountered an issue wherein the CA Certificates Service was in maintenance state.

sudo svcs -xv
svc:/system/ca-certificates:default (CA Certificates Service)
 State: maintenance since September  7, 2017 01:24:17 AM UTC
Reason: Start method failed repeatedly, last exited with status 1.
   See: http://support.oracle.com/msg/SMF-8000-KS
   See: man -M /usr/share/man -s 5 openssl
   See: /var/svc/log/system-ca-certificates:default.log
Impact: This service is not running.

I tried to clear the maintenance state manually a couple of times but with no success.

The svcs log file /var/svc/log/system-ca-certificates:default.log for the service showed the following error:

 [ Sep  7 09:27:46 Executing start method ("/lib/svc/method/svc-ca-certificates start"). ]
 Re-generating OpenSSL hash Links
 Traceback (most recent call last):
   File "/lib/svc/method/svc-ca-certificates", line 108, in <module>
     smf_include.smf_main()
   File "/usr/lib/python2.7/vendor-packages/smf_include.py", line 115, in smf_main
     
   File "/lib/svc/method/svc-ca-certificates", line 91, in start
     generate_links()
   File "/lib/svc/method/svc-ca-certificates", line 43, in generate_links
     os.symlink(os.path.join(RELCDIR, cfile), os.path.join(LINKDIR, shash))
 OSError: [Errno 17] File exists
 [ Sep  7 09:27:46 Method "start" exited with status 1. ]

The error log explained two things. The first being that the service startup method was apparently written in python and it was unable to start because some file that was supposed to be created by the startup method was already in existence.

After some investigation I found out that the /etc/openssl/certs directory should be empty to allow the service to startup correctly. So I emptied the directory while keeping a backup handy with me.

 [ssuri@:~] $ ls -l /etc/openssl/certs
 total 118
 lrwxrwxrwx   1 root     root          44 Sep  7 09:52 024dc131.0 -> ../../certs/CA/Microsec_e-Szigno_Root_CA.pem
 lrwxrwxrwx   1 root     root          51 Sep  7 09:52 03179a64.0 -> ../../certs/CA/Staat_der_Nederlanden_EV_Root_CA.pem
 lrwxrwxrwx   1 root     root          65 Sep  7 09:52 039c618a.0 -> ../../certs/CA/TURKTRUST_Certificate_Services_Provider_Root_2.pem
 lrwxrwxrwx   1 root     root          38 Sep  7 09:52 03f0efa4.0 -> ../../certs/CA/Wells_Fargo_Root_CA.pem
 lrwxrwxrwx   1 root     root          42 Sep  7 09:52 062cdee6.0 -> ../../certs/CA/GlobalSign_Root_CA_-_R3.pem
 lrwxrwxrwx   1 root     root          34 Sep  7 09:52 0750887b.0 -> ../../certs/CA/IPS_CLASE3_root.pem
 lrwxrwxrwx   1 root     root          35 Sep  7 09:52 080911ac.0 -> ../../certs/CA/QuoVadis_Root_CA.pem
 lrwxrwxrwx   1 root     root          49 Sep  7 09:52 0810ba98.0 -> ../../certs/CA/Root_CA_Generalitat_Valenciana.pem
 lrwxrwxrwx   1 root     root          39 Sep  7 09:52 0a8f0c78.0 -> ../../certs/CA/IPS_Chained_CAs_root.pem
 lrwxrwxrwx   1 root     root          32 Sep  7 09:52 0ac62cd9.0 -> ../../certs/CA/SUNWSolarisCA.pem



 [ssuri@:~] $ sudo ls -ld /etc/openssl/certs
 drwxr-xr-x   2 root     sys          120 Sep  7 09:52 /etc/openssl/certs
 [ssuri@:~] $ sudo mv /etc/openssl/certs /etc/openssl/certs.old
 [ssuri@:~] $ sudo mkdir /etc/openssl/certs
 [ssuri@:~] $ sudo chown root:sys /etc/openssl/certs

I tried to restart the service now but was still receiving the same error in the log files.

I did some more digging and read a few articles and they suggested to look in the /etc/certs/CA directory for any files that shouldn't actually be there.

[ssuri@usny-infrasi049-p:~] $ sudo ls -ltr /etc/certs/CA| tail
-rw-r--r--   1 root     sys         1545 Apr  3 08:20 SUNWSolarisCA.pem
-rw-r--r--   1 root     sys         1249 Apr  3 08:20 SecureSign_RootCA11.pem
-rw-r--r--   1 root     sys         1261 Apr  3 08:20 Security_Communication_RootCA2.pem
-rw-r--r--   1 root     sys         1948 Apr  3 08:20 Staat_der_Nederlanden_EV_Root_CA.pem
-rw-r--r--   1 root     sys         2069 Apr  3 08:20 Staat_der_Nederlanden_Root_CA_-_G2.pem
-rw-r--r--   1 root     sys         1952 Apr  3 08:20 Staat_der_Nederlanden_Root_CA_-_G3.pem
-rw-r--r--   1 root     sys         1399 Apr  3 08:20 Starfield_Root_Certificate_Authority_-_G2.pem
lrwxrwxrwx   1 root     root          45 Jun 26 16:37 usny-infrasi041-p.pem -> /var/opt/SUNWldm/trust/usny-infrasi041-p.pem
lrwxrwxrwx   1 root     root          45 Jun 26 16:37 usny-infrasi043-p.pem -> /var/opt/SUNWldm/trust/usny-infrasi043-p.pem
lrwxrwxrwx   1 root     root          45 Sep  5 13:52 usny-infrasi042-p.pem -> /var/opt/SUNWldm/trust/usny-infrasi042-p.pem


The last three files .pem files were for different servers. I'm not sure as to how they got there.
I removed those soft links and emptied the /etc/openssl/certs directory again.

sudo unlink usny-infrasi042-p.pem
sudo unlink usny-infrasi043-p.pem
sudo unlink usny-infrasi041-p.pem


I followed this up with a disable/enable operation on the service and it finally came online.

[ssuri@usny-infrasi049-p:~] $ sudo svcadm disable svc:/system/ca-certificates:default^C
[ssuri@usny-infrasi049-p:~] $ svcs -xv
[ssuri@usny-infrasi049-p:~] $ svcs -xvudo svcadm disable svc:/system/ca-certificates:defaulten
[ssuri@usny-infrasi049-p:~] $ svcs -xv
[ssuri@usny-infrasi049-p:~] $ sudo svcs -l svc:/system/ca-certificates:default
fmri         svc:/system/ca-certificates:default
name         CA Certificates Service
enabled      true
state        online
next_state   none
state_time   September  7, 2017 10:11:16 AM UTC
logfile      /var/svc/log/system-ca-certificates:default.log
restarter    svc:/system/svc/restarter:default
manifest     /lib/svc/manifest/system/ca-certificates.xml
dependency   require_all/none svc:/system/filesystem/minimal (online)
[ssuri@usny-infrasi049-p:~] $ sudo svcs -l svc:/system/ca-certificates:default
fmri         svc:/system/ca-certificates:default
name         CA Certificates Service
enabled      true
state        online
next_state   none
state_time   September  7, 2017 10:11:16 AM UTC
logfile      /var/svc/log/system-ca-certificates:default.log
restarter    svc:/system/svc/restarter:default
manifest     /lib/svc/manifest/system/ca-certificates.xml
dependency   require_all/none svc:/system/filesystem/minimal (online)


Since I was unsure of how the .pem files for the other servers got into /etc/certs/CA directory, I re-created the soft links again.

 [ssuri@usny-infrasi049-p:/etc/certs/CA] $ sudo ln -s /var/opt/SUNWldm/trust/usny-infrasi041-p.pem usny-infrasi041-p.pem
 [ssuri@usny-infrasi049-p:/etc/certs/CA] $ sudo ln -s /var/opt/SUNWldm/trust/usny-infrasi043-p.pem usny-infrasi043-p.pem
 [ssuri@usny-infrasi049-p:/etc/certs/CA] $ sudo ln -s /var/opt/SUNWldm/trust/usny-infrasi042-p.pem usny-infrasi042-p.pem

Thursday 7 September 2017

A useful sample .exrc file for vi

In this article I'd like to share a sample .exrc file which I've begun to use while working with the vi text editor on UNIX systems. It lacks the extreme level of customization available with vim and is more of a minimal vim version.

The .exrc file is to be placed within the users' home directory and the mentioned settings will get loaded every time the user uses vi to edit a file.

So, here's the file:

[ssuri@myserver:~] $ cat .exrc
" Show whitespace and EOL characters
" set list
" Show line numbers
set nu
" Hide Line Numbers
" set nonu
" Show matching brackets
set showmatch
" Show current mode in status line
"show current editor mode
set showmode
"set autoindentation in scripts
set autoindent
"map S to :wq! key combination
map S :wq!
"set searches to case insensitive
set ignorecase
"set shell env for ! commands
set shell=/bin/bash
"show matching braces
set showmatch


Comments are indicated y double quotes ("). 
Note: I've observed that this file does not tolerate blank lines. So if you'd like to keep some blank lines in the file to make it more readable, be sure to place " at the start of the line.

Tuesday 5 September 2017

Using ternary operator in perl

Today I'd like to share a quick script with 2 examples on using the ternary operator in perl and another quick trick to get file size in perl.

Here's the script:

#!/usr/bin/perl -w

my $dir="/root" ;
my $script="ternary.pl";

if (-e $dir) {
if (-d _ ) {  print "$dir exists \n"; }

if (-s $script ) { $size= -s $script; print "$script is not empty and size is $size bytes \n";}

}


print $dir?"file exits\n":"File does not exist \n";

$a=10;$b=20;
$c = $a < $b ? $a:$b;

print "$c \n";


If I assign the -s <file_name> expression which returns true if a file is not empty to an scalar variable then that variable will have the size in bytes of the file being tested.

Moving out of the nested if statements we move to the ternary operator whose syntax is:

expressions?statement1:statement2

So this executes statement1 if expression is true and it executes statement2 if expression is not true.

From experience I've observed that the ternary operator expression tests hold good for numeric tests and does not work with file related tests.

The ternary operator is useful when you'd like to replace simple and short if-else statements with a single statement.

Executing the script gives the following result:

[root@pbox scripts_pl]# ./ternary.pl
/root exists
ternary.pl is not empty and size is 323 bytes
file exits
10

Using the _ variable in a nested if-else statement in Perl

Recently I found out that while using a nested if-else statement in perl we could substitute the variable name with underscore (_) in the substituent if conditional statements.

Here is a an example script:

#!/usr/bin/perl

my $file = "/tmp/file1.txt";
my (@description, $size);
if (-e $file)
{
push @description, 'binary' if (-B _);
push @description, 'a socket' if (-S _);
push @description, 'a text file' if (-T _);
push @description, 'a block special file' if (-b _);
push @description, 'a character special file' if (-c _);
push @description, 'a directory' if (-d _);
push @description, 'executable' if (-x _);
push @description, (($size = -s _)) ? "$size bytes" : 'empty';

print "$file is ". join(', ',@description)."\n";
}

The first if condition checks if the file exists with the -e flag. Notice that after using the variable name in the outer if statement, I was able to substitute it with _ for the inner if condition tests.
The nested if statements test for various attributes of the file and append a string at the end of an array named description if the attribute being tested for returns true.
Finally we modify the array being used into a string using the join function and print it out.

The file being used here exists so executing the script yields the following results:

[root@pbox scripts_pl]# ls -l /tmp/file1.txt
-rw-r--r--. 1 root root 16 Sep  5 06:51 /tmp/file1.txt
[root@pbox scripts_pl]#

[root@pbox scripts_pl]# ./describe.pl
/tmp/file1.txt is a text file, 16 bytes

Monday 4 September 2017

Getting user input using <> and running the script in Strawberry Perl

In a previous article I demonstrated how we could get user input in a perl script using the <STDIN> operator. In this article we'll use <> instead of <STDIN> and run the script using Strawberry Perl on Windows Platform and share couple of other things.

#!/usr/bin/perl -w

$|=1; #turn on autoflush

print "Enter your name: ";
chomp(my $name=<>); #remove new line from input

print 'You entered '.$name.' as your name'."\n"; #A difficult way to interpolate a scaler.
#Don't use this

print "Are you sure that $name is correct? \n"; #The easy way to interpolate a scalar.
#Use this.


Given below is a sample execution:

Enter your name: sahil
You entered sahil as your name
Are you sure that sahil is correct?


When running and without turning on autoflush the output seemed to be getting buffered i.e. When I ran the script I got a blank prompt and when I typed a string and pressed enter I saw all the print statements being printed in one go. This generally does not happen in UNIX and to prevent this behavior in UNIX or Windows we turn on autoflush by setting the value $| to 1.

The other thing I wanted to show you here is the use of the concatenation (.) operator while writing a print statement using single quotes. Variables don't get interpolated in single quotes but do get interpolated if left unquoted as shown. the new line (\n) escape sequence does not come into affect unless placed within double quotes. That is an exhausting way to write a print statement with variables in it.
I wanted to show it because it's possible but strongly advise against its usage.

Using the each operator in Perl

The each operator can be used on array and hash variables in perl. The ability to use each on an array has been added to perl after version 5.12 and is not available in earlier versions.

Hash context:
When we use each on a hash, it returns a 2 element list containing the key and value pair in the hash.

Array context:
When used with an array, the each function returns a 2 element list containing the element value and it's corresponding index value within the array.

Given below is a small script to demonstrate this:

#!/usr/bin/perl -w

use 5.012;

my @array=qw/unix linux solaris/;

my %hash=("oracle" => "solaris", "redhat" => "RHEL");

while (my ($index, $element) = each @array) {
 say "$element is at index $index";
}

while (my ($key,$value) = each %hash) {
 say "$key has the value $value";
}


The output of the script is as follows:

unix is at index 0
linux is at index 1
solaris is at index 2
redhat has the value RHEL
oracle has the value solaris

Using perl version 5.12 allows us to use say in our script instead of print and its advantage is that say automatically inserts a newline in it's output unlike print where we have insert a \n manually.

Sunday 3 September 2017

Getting user input in perl

The ability to gather, modify and update supplied user input is an important feature for any programming language and perl is no different in this regard.

In perl we use <STDIN> to prompt user for the input. The <> here is the line input operator working on the STDIN filehandle.

Whenever you use <STDIN> in a script, perl will expect a scalar value in it's place. Perl reads a line from STDIN and uses it as the value for <STDIN>.

The input we supply this way is often accompanied by a trailing new line (\n) character. For scripting purposes we need to remove this new line character because letting the new line persist within <STDIN> may lead to unexpected results in scripts.

Here is a sample script which prompts the user to input whether he wants to perform an addition or a subtraction operation. The user is then prompted to enter the numbers to be subtracted.
We could've asked the user to add numbers one after the other and store the numbers in separate scalar variables but I find using the list followed by split to be more convenient and more awesome.

Notice the use of chomp on both occasions while parsing input from the user. The script won't work without using the chomp() function at those instances. 

[root@pbox perl_programs]# cat elsif.pl
#!/usr/bin/perl -w
#
use strict;

print "Enter choice of operation add or sub: \n" ;
chomp (my $op =<STDIN>) ;

print "enter numbers separated by spaces \n" ;

chomp (my $input = <STDIN> ) ;
my @numbers =(split ' ', $input) ;

print "you entered the numbers: @numbers \n";

if ($op eq "add") { my $a = $numbers[0] + $numbers[1] ; print "$a \n"; }
elsif ($op eq "sub") { my $s = $numbers[0] - $numbers[1] ; print "$s \n"; }
else { print "You entered an invalid operation \n" ; }


Here's a sample run of the script:

./elsif.pl
Enter choice of operation add or sub:
add
enter numbers separated by spaces
10 200
you entered the numbers: 10 200
210

Switching to a user having /sbin/nologin as a login shell

Generally for ftp/sftp accounts created on UNIX servers the users' login shell is set to /sbin/nologin to make sure that the users can't login to the system and get a shell session. It's a conventional security feature implemented at the system level.
There might be instances where in we require to login to the server as the said user probably to perform some troubleshooting or diagnostics. We usually do this by temporarily changing the login shell to something else.
Today I'll demonstrate a work around for that.

I have a user called ftpuser and it's shell is set to /sbin/nologin.

[root@pbox ~]# perl -nle 'print if (/ftpuser/)' /etc/passwd
ftpuser:x:1001:1001::/home/ftpuser:/sbin/nologin
[root@pbox ~]#

If i try to switch to this user, I find that I'm unable to do so 

[root@pbox ~]# sudo su - ftpuser
Last login: Sun Sep  3 10:30:16 IST 2017 on pts/2
This account is currently not available.
[root@pbox ~]#

The workaround is to use the -p option with the su command while logging in.

[root@pbox ~]# sudo su -p ftpuser
bash: /root/.bashrc: Permission denied
bash-4.2$ id
uid=1001(ftpuser) gid=1001(ftpuser) groups=1001(ftpuser) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
bash-4.2$ pwd
/root
bash-4.2$ cd /home/ftpuser/
bash-4.2$ mkdir in out
bash-4.2$ ls -l
total 0
drwxr-xr-x. 2 ftpuser ftpuser 6 Sep  3 10:39 in
drwxr-xr-x. 2 ftpuser ftpuser 6 Sep  3 10:39 out
bash-4.2$

Notice that after switching to ftpuser I'm still in /root which was my home directory when logged in as the root user.
This is because the -p flag actually preserves the environment of the previously logged in user.

Here's what the manpage for su said about -p :

 -m, -p, --preserve-environment
              Preserves  the  whole  environment,  ie  does not set HOME, SHELL, USER nor LOGNAME.  The option is ignored if the
              option --login is specified.


I hope you find this trick useful and thank you for reading.

Using capture groups in grep in Linux

Introduction Let me start by saying that this article isn't about capture groups in grep per se. What we are going to do here with gr...