Using Secrets API with dbus-send - dbus

I'm trying to figure out how to get a password from the keyring using dbus-send, but I'm struggling to understand what the session parameter is.
Here's where I've got to:
#!/bin/bash
# Find key path
KEY_PATH=$(dbus-send --dest=org.freedesktop.secrets --print-reply=literal /org/freedesktop/secrets org.freedesktop.Secret.Service.SearchItems dict:string:string:"mount-point","/home/s/.mozilla/firefox" | grep -Eo '/\S+')
# Unlock keyring
RESULT=$(dbus-send --dest=org.freedesktop.secrets --print-reply=literal /org/freedesktop/secrets org.freedesktop.Secret.Service.Unlock array:objpath:$KEY_PATH | grep -Eo '/\S+')
# If unlocked...
if [ "$RESULT" = "$KEY_PATH" ]; then
# Get password
PASSWORD=$(dbus-send --dest=org.freedesktop.secrets --print-reply=literal /org/freedesktop/secrets org.freedesktop.Secret.Service.GetSecrets array:objpath:$KEY_PATH objpath:<WHAT IS SESSION?>)
# Mount ecryptfs firefox directory
echo $PASSWORD | ecryptfs-simple -o key=passphrase,ecryptfs_cipher=aes,ecryptfs_key_bytes=32,ecryptfs_passthrough=no,ecryptfs_enable_filename_crypto=yes,no_sig_cache=yes /home/s/.mozilla/.firefox-ecryptfs /home/s/.mozilla/firefox
firefox $#
fi
I'm lost as to how to get a session to fetch the password.

The session needs to be created using:
org.freedesktop.Secret.Service.OpenSession (
IN String algorithm,
IN Variant input,
OUT Variant output,
OUT ObjectPath result);
https://specifications.freedesktop.org/secret-service/latest/re01.html
Here is an example of creating a non-encrypted session. Be aware the password returned by GetSecret will be a plain text as it uses a non-encrypted session:
dbus-send --dest=org.freedesktop.secrets --print-reply=literal /org/freedesktop/secrets org.freedesktop.Secret.Service.OpenSession string:plain variant:string:''
The output is the objpath to the created session:
variant /org/freedesktop/secrets/session/s31
Then, theoretically, you can pass the session to GetSecrets. For example:
dbus-send --dest=org.freedesktop.secrets --print-reply=literal /org/freedesktop/secrets org.freedesktop.Secret.Service.GetSecrets array:objpath:/org/freedesktop/secrets/collection/login/6 objpath:/org/freedesktop/secrets/session/s31
Note: /org/freedesktop/secrets/collection/login/6 is the object path returned by SearchItems.
However, this does not work with dbus-send. I think this is because the session is likely closed as soon as dbus-send returns.
If you use d-feet, the session is retained until the d-feet window is closed. So, you will be able to get the password using d-feet though. But, I understood that you want to automate it.
I suggest you use python3's keyring which offers to get a password using an encrypted session.

Related

Why does quoting password-variable in curl lead to authorization failure? (Bash)

I have a very specific problem with bash and curl.
What we do is:
reading a password from jenkins and paste it to a config-file (i don't have access to the password)
read parameters from config-file in bash (host, user, password, etc.) and store it in variables
post something with curl to a database and store the result in a variable
Recently we added shellcheck to our deploy-scripts and therefore we need to put the variables in quotes.
That's the request we want to send (shellcheck-approved):
result=$(curl -s -XPOST "${dbURL}" --header "Authorization: Basic $(echo -n "${dbUser}:${dbPwd}" | base64)" --data-binary "blabla")
And here's the error message we get in return:
{"error":"authorization failed"}
It does work, when I unquote the password-variable ("${dbUser}":${dbPwd}). But then spellcheck complains, that I need to put all variables in quotes. Also it does work on another machine with different password (which I have no access to either).
It is the same, when I use --user username:password. So it seems like the problem lies within the password.
Using google and testing the procedure (without the curl) with different special characters couldn't solve it either.
Has anyone experienced something like this?
Edit1:
This is an extract from jenkins-deploy-file ..
stage('config files') {
withCredentials([string(credentialsId: "${env_params.db_password}", variable: 'db_pw')]) {
sshagent(credentials: ["${env_params.user}"]) {
sh "echo \"dbPwd=${db_pw}\" >> environment_variables/config.properties"
This is how the shell script stores the password ..
dbPwd=$(grep ^"$dbPwd" <PATH>/config.properties | cut -d "=" -f2)
thanks for your support.
It seems like there are trailing whitespaces in the password-storage.
I removed them using sed and now it works.
dbPwd=$(grep ^"$dbPwd" <PATH>/config.properties | cut -d "=" -f2 | sed -e 's/[[:space:]]*$//')
You can just set the password in another file and use the content of the file as your password variable.

Substitute user mid-Bash-script & continue running commands (Mac OSX)

I'm building two scripts which combined will fully uninstall a program (Microsoft Lync) on Mac OS X. I need to be able to swap from an account with root access (this account initially executes the first script) to the user whom is currently logged in.
This is necessary because the second script needs to be executed not only by the logged-in user, but from said user's shell. The two scripts are name Uninstall1.sh and Uninstall2.sh in this example.
Uninstall1.sh (executed by root user):
#!/bin/bash
#commands ran by root user
function rootCMDs () {
pkill Lync
rm -rf /Applications/Microsoft\ Lync.app
killall cfprefsd
swapUser
}
function swapUser () {
currentUser=$(who | grep console | grep -v _mbsetupuser | grep -v root | awk '{print $1}' | head -n 1)
cp /<directory>/Uninstall2.sh${currentUser}
su -l ${currentUser} -c "<directory>/{currentUser}/testScript.sh";
<directory> actually declared in the scripts, but for the sake of privacy I've excluded it.
In the above script, I run some basic commands as the root user to remove the app to the trash, and kill cfprefsd to prevent having to reboot the machine. I then call the swapUser function, which dynamically identifies the current user account signed into and assigns this to the variable currentUser (in this case within our environment, it's safe to assume only one user is logged into the computer at a time). I'm not sure whether or not I'll need the cp directory/Uninstall2.sh portion yet, but this is intended to solve a different problem.
The main problem is getting the script to properly handle the su command. I use the -l flag to simulate a user login, which is necessary because this not only substitutes to the user account which is logged into, but it launches a new shell as said user. I need to use -l because OS X doesn't allow modifying another user's keychain from an admin account (the admin account in question has root access, but isn't nor does it switch to root). -c is intended to execute the copied script, which is as follows:
Uninstall2.sh (needs to be executed by the locally logged-in user):
#!/bin/bash
function rmFiles () {
# rm -rf commands
# rm -rf commands
certHandler1
}
function certHandler1 () {
myCert=($(security dump-keychain | grep <string> | grep alis | sed -e 's/"alis"<blob>="//' | sed -e 's/"//'))
cLen=${#myCert[#]} # Count the amount of items in the array; there are usually duplicates
for ((i = 0;
i < ${cLen};
i++));
do security delete-certificate -c ${myCert[$i]};
done
certHandler2
}
function certHandler2 () {
# Derive the name of, and delete Keychain items related to Microsoft Lync.
myAccount=$(security dump-keychain | grep KeyContainer | grep acct | sed -e 's/"acct"<blob>="//' | sed -e 's/"//')
security delete-generic-password -a ${myAccount}
lyncPW=$(security dump-keychain | grep Microsoft\ Lync | sed -e 's/<blob>="//' | awk '{print $2, $3}' | sed -e 's/"//')
security delete-generic-password -l "${lyncPW}"
}
rmFiles
In the above script, rmFiles kicks the script off by removing some files and directories from the user's ~/Library directory. This works without a problem, assuming the su from Uninstall1.sh properly executes this second script using the local user's shell.
I then use security dump-keychain to dump the local user's shell, find a specific certificate, then assign all results to the cLen array (because there may be duplicates of this item in a user's keychain). Each item in the array is then deleted, after which a few more keychain items are dynamically found and deleted.
What I've been finding is that the first script will either properly su to the logged-in user which it finds, at which point the second script doesn't run at all. Or, the second script is ran as the root user and thus doesn't properly delete the keychain items from the logged-in user it's supposed to su to.
Sorry for the long post, thanks for reading, and I look forward to some light shed on this situation!
Revision
I managed to find a way to achieve all that I am trying to do in a single bash script, rather than two. I did this by having the main script create another bash script in /tmp, then executing that as the local user. I'll provide it below to help anybody else whom may need this functionality:
Credit to the following source for the code on how to create another bash script within a bash script:
http://tldp.org/LDP/abs/html/here-docs.html - Example 19.8
#!/bin/bash
# Declare the desired directory and file name of the script to be created. I chose /tmp because I want this file to be removed upon next start-up.
OUTFILE=/tmp/fileName.sh
(
cat <<'EOF'
#!/bin/bash
# Remove user-local Microsoft Lync files and/or directories
function rmFiles () {
rm -rf ~/Library/Caches/com.microsoft.Lync
rm -f ~/Library/Preferences/com.microsoft.Lync.plist
rm -rf ~/Library/Preferences/ByHost/MicrosoftLync*
rm -rf ~/Library/Logs/Microsoft-Lync*
rm -rf ~/Documents/Microsoft\ User\ Data/Microsoft\ Lync\ Data
rm -rf ~/Documents/Microsoft\ User\ Data/Microsoft\ Lync\ History
rm -f ~/Library/Keychains/OC_KeyContainer*
certHandler1
}
# Need to build in a loop that determines the count of the output to determine whether or not we need to build an array or use a simple variable.
# Some people have more than one 'PRIVATE_STRING' certificate items in their keychain - this will loop through and delete each one. This may or may not be necessary for other applications of this script.
function certHandler1 () {
# Replace 'PRIVATE_STRING' with whatever you're searching for in Keychain
myCert=($(security dump-keychain | grep PRIVATE_STRING | grep alis | sed -e 's/"alis"<blob>="//' | sed -e 's/"//'))
cLen=${#myCert[#]} # Count the amount of items in the array
for ((i = 0;
i < ${cLen};
i++));
do security delete-certificate -c ${myCert[$i]};
done
certHandler2
}
function certHandler2 () {
# Derive the name of, then delete Keychain items related to Microsoft Lync.
myAccount=$(security dump-keychain | grep KeyContainer | grep acct | sed -e 's/"acct"<blob>="//' | sed -e 's/"//')
security delete-generic-password -a ${myAccount}
lyncPW=$(security dump-keychain | grep Microsoft\ Lync | sed -e 's/<blob>="//' | awk '{print $2, $3}' | sed -e 's/"//')
security delete-generic-password -l "${lyncPW}"
}
rmFiles
exit 0
EOF
) > $OUTFILE
# -----------------------------------------------------------
# Commands to be ran as root
function rootCMDs () {
pkill Lync
rm -rf /Applications/Microsoft\ Lync.app
killall cfprefsd # killing cfprefsd mitigates the necessity to reboot the machine to clear cache.
chainScript
}
function chainScript () {
if [ -f "$OUTFILE" ]
then
# Make the file in /tmp executable. This is necessary for /tmp as a non-root user cannot access files in this directory.
chmod 755 $OUTFILE
# Dynamically identify the user currently logged in. This may need some tweaking if multiple User Accounts are logged into the same computer at once.
currentUser=$(who | grep console | grep -v _mbsetupuser | grep -v root | awk '{print $1}' | head -n 1);
su -l ${currentUser} -c "bash /tmp/UninstallLync2.sh"
else
echo "Problem in creating file: \"$OUTFILE\""
fi
}
# This method also works for generating
#+ C programs, Perl programs, Python programs, Makefiles,
#+ and the like.
# Commence the domino effect.
rootCMDs
exit 0
# -----------------------------------------------------------
Cheers!

Programmatically get web request initiator

The Chrome Dev Tools network tab has an initiator column that will show you exactly what code initiated the network request.
I'd like to be able to get network request initiator information programmatically, so I could run a script with a url and request search string argument, and it would return details about where every request with a url matching request search string came from on the page at url. So given the arguments www.stackoverflow.com and google the output might look something like this (showing requesting url, line number, and requested url):
/ 19 http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js
/ 4291 http://www.google-analytics.com/analytics.js
I looked into PhantomJS, but its onResourceRequested callback doesn't provide any initiator information, or context from which it can be derived, according to the documentation: http://phantomjs.org/api/webpage/handler/on-resource-requested.html
Is it possible to do with with PhantomJS at all, or some other tool or service such as selenium?
UPDATE
From the comments and answers so far it seems as though this isn't currently supported by Phantom, Selenium or anything else. So here's an alternative approach that might work: Load the page, and all of the assets, and then find any occurrences of request search string in all of the files. How could I do that?
You should file a feature request in the issue tracker against the DevTools. The initiator information is not exported in the HAR, so getting it out of there isn't going to work. As far as I know, no existing API allows for this either.
I've been able to implement a solution that uses PhantomJS to get all of the URLs loaded by a page, and then use a combination of xargs, curl and grep to find the search string at those URLs.
The first piece is this PhantomJS script, which simply outputs every URL requested by a page:
system = require('system');
var page = require('webpage').create();
page.onResourceRequested= function(req) {
console.log(req.url);
};
page.open(system.args[1], function(status) {
phantom.exit(1);
});
Here it is in action:
$ phantomjs urls.js http://www.stackoverflow.com | head -n6
http://www.stackoverflow.com/
http://stackoverflow.com/
http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js
http://cdn.sstatic.net/Js/stub.en.js?v=06bb9dbfaca7
http://cdn.sstatic.net/stackoverflow/all.css?v=af4b547e0e9f
http://cdn.sstatic.net/img/share-sprite-new.svg?v=d09c08f3cb07
For my problem I'm not interested in images, and those can be fitlered out by adding the phantomjs arg --load-images=no.
The second piece is taking all of the URLs and searching them. It's not enough to just output the match, I also need the context around which URL was matched, and ideally which line number too. Here's how to do that:
$ cat urls | xargs -I% sh -c "curl -s % | grep -E -n -o '(.{0,30})SEARCH_TERM(.{0,30})' | sed 's#^#% #'"
We can wrap this all up in a little script, where we'll pipe the output back through grep to get color highlighting on the search string:
#!/bin/bash
phantomjs --load-images=no urls.js $1 | xargs -I% sh -c "curl -s % | grep -E -n -o '(.{0,30})$2(.{0,30})' | sed 's#^#% #' | grep $2 --color=always"
We can then use it to search for any term on any site. Here we're looking for adzerk.net on stackoverflow.com:
So you can see that the adzerk.net request gets initiated somewhere around line 4158 of the main stackoverflow page. It's not a perfect solution because the invocation might be somewhere completely different from where the URL is defined, but it's probably a close, and certainly a good point to start tracking down the exact invocation site.
There might be a better way to search the contents of each URL. It doesn't look like PhantonJS's onResourceReceived handler currently exposes the resource content, but there is ongoing work to address that, and once that's available all of this will be much simpler.
You can use Chrome's debugger protocol from a process external to Chrome or use the chrome.debugger API in a Chrome extension (see How to retrieve the Initiator of a request when extending Chrome DevTool?).

Net User in PowerShell

I am in the middle of moving to the cloud, migrating from SBS 2003 Active Directory, to 2008 R2.
I configured a new user, and noticed that the user was unable to reset their password.
My Server Admin showed me how to use net user.
I noticed that I can obtain information from some accounts and not others. With over 100 accounts to process, I thought I'd try PowerShell.
In this post (Use powershell to look up 'net user' on other domains?) Lorenzo recommends using Get-ADUser (and this applies to polling from another domain). When I run Get-ADUser from my PowerShell prompt, I receive a message stating that the commandlet is not recognized.
I am reading the user IDs from a text file, and sending the output to a log file so that I can send to the server admin for further analysis.
Here is my code so far (please note that I am completely new to PowerShell):
# Get our list of user names from the local staff.txt file
$users = get-content 'C:\Scripts\staff.txt'
# Create log file of output:
$LogTime = Get-Date -Format 'MM-dd-yyyy_hh-mm-ss'
$CompPath = "C:\Scripts\"
$CompLog = $CompPath + "NetUserInfo" + $LogTime + ".txt"
New-Item -path $CompLog -type File
foreach ($user in $users) {
#Testing user:
"Testing user: $user" | out-file $CompLog -Append
# Obtain user information using net user:
net user $user /domain >> $CompLog
# Pause to let system gather information:
Start-Sleep -Second 15
}
As the script runs currently, my log file will have two or three user names followed by the response "The request will be processed at a domain controller for domain (domain)"
If net user, from CMD, would return "System error 5 has occurred, Access is denied." This is not logged in the output file. IF net user, from CMD, would return user information, this is logged to the output file. I am currently receiving output for only a couple users, but when I run the command from CMD, I am able to retrieve information for at least ten.
My first thought was that I needed to wait for the net user command to complete (hence the Start-Sleep command) but that has not had any effect on the output.
Any assistance would be greatly appreciated.
Sorry, I don't have enough reputation to add a comment.
When you run programs in Powershell (such as net user... or ping) it should be running exactly the same as it would in the normal command prompt (cmd).
If I understand correctly you're getting different results when you (effectively) run the same thing in Powershell or Command Prompt. Is that right?
Are you using the ISE to build your script? If so you can set Breakpoints that will pause the script and allow you to see what the variables are. It could be that the $user variable isn't holding what you think it should be, or that the value doesn't match the name for a domain user account.
EDIT:
What happens when you run the net user ... command interactively (e.g. not as a script, but manually) in Powershell? Do you get an error? If so, what does the error say?
Additional related stuff:
You shouldn't need the Start-Sleep as the commands are run in order, and the next line shouldn't execute until the previous on has completed.
Also, which version of Powershell are you using?
(You can check by running $host.version.Major)
The Get-ADUser cmdlet requires version 3 (I believe) and also needs to import the Active Directory module.
The reason the error output is not being appended to the log file is because you are only redirecting the STDOUT (standard output stream). To also redirect the STDERR (standard error stream) change
net user $user /domain >> $CompLog
to
net user $user /domain 2>&1 $CompLog
This explains it a bit more:
http://www.techotopia.com/index.php/Windows_PowerShell_1.0_Pipes_and_Redirection#Windows_PowerShell_Redirection_Operators

SQLPLUS BAT File

I have a BAT file that runs a script on oracle :
sqlplus myuser/mypassword#mydatabase #C:\runthisfile.sql
I want to distribute this to other users (that don't necessarily know how to modify a BAT file).
I want the dos prompt to ask the user to enter their user and password (obviously I don't want to give them my connection details). Have tried all types of combination but all that happens is that I end up with SQL>......
Am stumped!
You can use the SET command with the /P argument in order to prompt the user for text during a batch file run, for example:
SET /P variable=Please enter text
This will then fill variable with whatever they type before hitting return.
#ECHO OFF
SET /P uname=Username:
SET /P pass=password:
This is a simple program which will prompt the first for a username, then a password.
You should then be able to pass this as an argument to sqlplus:
sqlplus %uname%/%pass%#mydatabase #C:\runthisfile.sql
Regarding with SQLPlus stop, doing nothing:
Sometimes SQLPlus finish with ... meaning that is waiting for something more.
Try to add "/" (without quotes) in the end of your SQL file to execute it.
I hope it will help...
It is the very simple code for opening SQLPLUS without entering usename and password manually.
sqlplus -L UserName/Password
For example : sqlplus -L Rak4ak#sun64/rk4
For Understanding :
sqlplus [ [] [{logon | /nolog}] [] ]
is: [-C ] [-L] [-M ""] [-NOLOGINTIME] [-R ]
[-S]
-C <version> Sets the compatibility of affected commands to the
version specified by <version>. The version has
the form "x.y[.z]". For example, -C 10.2.0
-L Attempts to log on just once, instead of
reprompting on error.
-M "<options>" Sets automatic HTML markup of output. The options
have the form:
HTML [ON|OFF] [HEAD text] [BODY text] [TABLE text]
[ENTMAP {ON|OFF}] [SPOOL {ON|OFF}] [PRE[FORMAT] {ON|OFF}]
-NOLOGINTIME Don't display Last Successful Login Time.
-R <level> Sets restricted mode to disable SQL*Plus commands
that interact with the file system. The level can
be 1, 2 or 3. The most restrictive is -R 3 which
disables all user commands interacting with the
file system.
-S Sets silent mode which suppresses the display of
the SQL*Plus banner, prompts, and echoing of
commands.
is: {[/][#] | / }
[AS {SYSDBA | SYSOPER | SYSASM | SYSBACKUP | SYSDG | SYSKM}] [EDITION=value]
Specifies the database account username, password and connect
identifier for the database connection. Without a connect
identifier, SQL*Plus connects to the default database.
The AS SYSDBA, AS SYSOPER, AS SYSASM, AS SYSBACKUP, AS SYSDG,
and AS SYSKM options are database administration privileges.

Resources