emacs function to send password to minibuffer when asked for - emacs

I usually connect to a machine through SSH and using ssh.el. I defined a command so I can do this quickly:
(defun ssh-me()
(interactive)
(ssh "myuser#myhost"))
After that, the mini-buffer asks me for the password and everything works fine. I am wondering if there is a way to set my password in my function so I don't have to write it every time I want to connect to that machine, so I would have something like:
(defun ssh-me()
(interactive)
(ssh "myuser#myhost")
(send-password-to-minibuffer "mypasswd"))
Is that possible?

Here is an example using a small custom file that is not encrypted. In this example, the filename is .authinfo_iphone and it contains just one line -- I use it to connect to my jailbroken iphone via ssh:
machine localhost login root password alpine port ssh
Then, I use a small function to connect:
(defun lawlist-remote-iphone-data ()
(interactive)
(let ((auth-sources '("/Users/HOME/.0.data/.0.emacs/.authinfo_iphone")))
(find-file "/ssh:root#localhost#2222:/private/var/mobile/.0.data/")))
You could also use an external utility such as sshpass and then write-up a function -- the command-line looks like:
/usr/bin/sshpass -p 'my-password' ssh my-username#12.34.56.789
And here is an example function that incorporates that command line to log-in to the iPhone over ssh. It contemplates there is already an open shell-mode buffer with the process named *shell*.
(defun shell-iphone ()
"From an existing shell buffer with a process named `*shell*`,
log-in to the iPhone using sshpass."
(interactive)
(let* (
(password "alpine")
(port "2222")
(username "root")
(host "localhost")
(sshpass "/Users/HOME/.0.data/.0.emacs/bin/sshpass")
(ssh "/usr/bin/ssh")
(dir "/private/var/mobile/.0.data"))
(comint-send-string "*shell*"
(mapconcat 'identity `(
,sshpass
"-p"
,password
,ssh
"-p"
,port
"-l"
,username
,host
"-t"
"\"cd " ,dir " && bash --login\"") " "))
(comint-send-input)))

Related

Locate and open remote files

In emacs, the locate command provides a way to run unix's locate and open files on the local filesystem.
I'm using TRAMP to access remote files - is it possible to use emacs' locate to find and open remote files?
Likely, it is not possible. locate uses call-process, which does not run remote processes.
I don't know if you can use Emacs's locate function with TRAMP per se, but you could connect to a host remotely and run locate on that system via M-x shell or M-x eshell. I have some wrapper functions which make this task easier (although I mostly got them from elsewhere):
(defun remote-eshell (host)
(interactive "sHost: ")
(let ((default-directory (concat "/ssh:" (format "%s:" host))))
(eshell host)))
(defun remote-shell (host)
(interactive "sHost: ")
(let ((default-directory (concat "/ssh:" (format "%s:" host))))
(shell)))
After locating the desired files on the remote host, you can then open them via TRAMP using C-x C-f /ssh:remotehost
Also, if you're connecting via TRAMP to a remote host, you should make sure that said host is not sending any weird prompts since TRAMP doesn't handle those well. See more about that here.

How to execute sudo command with filter in elisp

I would like to use elisp to execute a privileged command, then use a filter to do further processing when certain output is seen.
It's my understanding, after exhaustive RTFM'ing, that I can:
Set default-directory to a path that begins with "/sudo::/".
Call start-file-process to start a process that will be run under sudo.
Here is a function I wrote that tries to do this:
(defun start-vpn (config-file password-file callback)
"Starts the VPN connection, waits for a DHCP address,
then invokes callback with the address it got."
(let* ((default-directory "/sudo::/tmp")
(buff (get-buffer-create "*openvpn*"))
(proc (start-file-process "openvpn" "*openvpn*"
"/usr/local/sbin/openvpn"
(concat "--config " config-file)
(concat "--auth-user-pass " password-file))))
(set-process-filter proc
(lambda (proc output)
(message "Got output: " output)
(let ((ip (get-vpn-ip-address output)))
(when ip
(callback ip)))))))
When I run this, I see the following output in the *Messages* buffer:
start-vpn
Tramp: Opening connection for root#localhost using sudo...
Tramp: Sending command `exec sudo -u root -s -H -p Password:'
Tramp: Waiting for prompts from remote shell
Tramp: Sending command `exec sudo -u root -s -H -p Password:'
Tramp: Found remote shell prompt on `localhost'
Tramp: Opening connection for root#localhost using sudo...done
(lambda (proc output) (message "Got output: " output) (let ((ip ...)) (if ip (progn ...))))
Got output:
...and no output in the *openvpn* buffer the function creates.
I am not an expert at elisp, so I suspect there is some stupid mistake I am making. I am also really curious about the "(lambda (proc ..." in the *Messages* buffer.
Any advice, criticism, or tips appreciated. Thanks!
First of all, the reason for seeing (lambda ... in the message buffer is that set-process-filter returns the filter function, so therefore start-vpn does too.
Your message call needs to contain a format specifier to actually show the output:
(message "Got output: %s" output)
And (callback ip) won't work for two reasons:
Emacs Lisp has separate namespaces for functions and variables, so (callback ip) will call the function callback (which doesn't exist), while you need (funcall callback ip) to call the function stored in the variable callback.
Once you're past that, since Emacs Lisp uses dynamic scope by default, by the time your lambda function gets called the binding for callback is already gone.
In Emacs 24, you can set lexical-binding to t, and the code above should work. In any case, you can explicitly use the lexical-let macro:
(lexical-let ((callback callback))
(lambda (proc output)
(message "Got output: " output)
(let ((ip (get-vpn-ip-address output)))
(when ip
(funcall callback ip))))
This macro uses black magic to preserve the value of callback inside the lambda function.

Remote ssh connection from within Emacs

Several questions, including this one, discuss aspects relating to ssh connections from within Emacs. I haven't found an answer to my question though: How can I ssh into a remote machine from within Emacs?
I do not wish to edit a file on the remote machine from within Emacs. I am aware of M-x shell which opens a shell on my local machine and I am aware of using TRAMP to edit a file over ssh on the remote machine. However, neither of these relate to this question.
(Instead of voting to close, maybe migrate the question to another site.)
Edit: Related discussion here.
Firstly, I am unaware of a native elisp ssh client (and do not imagine there is a great deal of motivation for writing one), so you will certainly need to interact with an external ssh client process.
As you wish to use ssh interactively, the ssh process requires a terminal on the local side of the connection.
The question therefore becomes: Does Emacs implement a terminal to which an ssh process can be attached?
The answer is: yes -- term.el provides a robust terminal implementation, through which ssh can be run directly, without the requirement for a shell.
If you run M-x term RET you will be prompted for a program. (It defaults to a shell, but that is certainly not the only type of process you can run.)
For reasons unknown, the interactive term (and ansi-term) functions do not support passing arguments to the specified program, which renders them less useful if you wished to run something like ssh user#host. You could instead specify a script which handled the arguments, but we can manage that in elisp as well:
The term function is actually a simple wrapper which calls make-term to start the program and then sets the appropriate modes. As make-term does accept program arguments, it is quite straightforward to copy-and-modify the definition of term to suit your own purposes.
Here is a very simple implementation:
(defun my-ssh (user host port)
"Connect to a remote host by SSH."
(interactive "sUser: \nsHost: \nsPort (default 22): ")
(let* ((port (if (equal port "") "22" port))
(switches (list host "-l" user "-p" port)))
(set-buffer (apply 'make-term "ssh" "ssh" nil switches))
(term-mode)
(term-char-mode)
(switch-to-buffer "*ssh*")))
or perhaps this is preferable:
(defun my-ssh (args)
"Connect to a remote host by SSH."
(interactive "sssh ")
(let ((switches (split-string-and-unquote args)))
(set-buffer (apply 'make-term "ssh" "ssh" nil switches))
(term-mode)
(term-char-mode)
(switch-to-buffer "*ssh*")))
Obviously there is scope for improvements, but I think that's fairly useful as-is.
You should ensure that you are familiar with the quirks of term-mode. See:
M-: (info "(emacs) Terminal emulator") RET
M-: (info "(emacs) Terminal Mode") RET
C-hf term-mode RET
It turns out, there is what you want:
(setq rlogin-program "ssh")
(setq rlogin-process-connection-type t)
and then M-x rlogin RET <myhost> RET will do that.
Maybe ssh.el is what you are looking for. The ssh command provides a single-step way to create remote shells in Emacs via ssh, including specifying the user name in a natural way, and enabling tramp directory tracking if desired.
I'm not sure I understand. Open up M-x ansi-term and run ssh user#host there?

Replace isql with sqsh in emacs (Ubuntu)

Using emacs on Ubuntu 11.10. I want to connect to a SQL Server database using sqsh instead of isql. I added the following to my initi.el
(set 'sql-sybase-program "sqsh")
(set 'sql-ms-program "sqsh")
It recompiles and loads successfully. However, when I use sql-ms and try to connect to the database, I am getting errors because emacs is using lower-case command parameters when it should be using upper-case command parameters. Furthermore, I can successfully connect to the database server using sqsh from the command line. When I try to run things within emacs, I get the following error:
sqsh: -d: Invalid integer expression
Process SQL exited abnormally with code 255
I did a pretty extensive Google search and I can't find much on how to do this (which makes me think it may not be possible). Obviously, I can run sqsh from within a shell, but then I lose the SQL mode integration. I'm not sure what I can / need to do to my init.el file to make this possible.
I think all I really need to do is figure out how to get emacs to send a -D not a -d to sqsh. Apparently isql doesn't care, but sqsh cares deeply about the difference.
As you say, the real answer is to get Emacs to use -D instead of -d. However, as a workaround, running sql-sybase instead of sql-ms seems to work fine for me.
Update: Try this code, it removes the -n option from sql-ms-options and redefines sql-ms-options to use -D instead of -d as the option to select the database:
(setq sql-ms-options (remove "-n" sql-ms-options))
(defun sql-comint-ms (product options)
"Create comint buffer and connect to Microsoft SQL Server."
;; Put all parameters to the program (if defined) in a list and call
;; make-comint.
(let ((params options))
(if (not (string= "" sql-server))
(setq params (append (list "-S" sql-server) params)))
(if (not (string= "" sql-database))
(setq params (append (list "-D" sql-database) params)))
(if (not (string= "" sql-user))
(setq params (append (list "-U" sql-user) params)))
(if (not (string= "" sql-password))
(setq params (append (list "-P" sql-password) params))
(if (string= "" sql-user)
;; if neither user nor password is provided, use system
;; credentials.
(setq params (append (list "-E") params))
;; If -P is passed to ISQL as the last argument without a
;; password, it's considered null.
(setq params (append params (list "-P")))))
(sql-comint product params)))

Emacs + tramp + plink

I'm trying to get emacs tramp running under Windows XP to work over putty plink on an Amazon EC2 instance. The documentation for doing this is sparse. I can find partial documentation, but none that addresses all the steps required to get this working.
Can anyone provide a walk through, or a pointer to a walk through?
(add-to-list 'load-path
(expand-file-name "C:/tools/emacsw32/emacs/lisp/tramp/lisp"))
(require 'tramp)
;(setq tramp-chunksize "500")
(setq tramp-default-method "plink")
from my dot-emacs file. If I find more notes, I shall add them here.
I'll assume you have a GNU/Linux server you want to access, a username and a .ppk file. Also, Emacs 24.4+.
First set up server in PuTTY Configuration
In section Session, specify Host Name, for example username#server.
Go to section Connection > SSH > Auth and Browse for your "Private key file for authentication".
Back to section Session, name your Saved Sessions, for example putty-test, and click Save button.
Check your connection by clicking the Open button. If it works, you can close these now.
Next, head to your Emacs.
Make sure Emacs knows where your plink.exe is. One way is to just inform Emacs directly in your .emacs, for instance I have at the moment,
(setenv "PATH" (concat "c:/Users/Brady/Documents/putty/;" (getenv "PATH")))
Simply type C-x C-f //plink:putty-test:/ RET. Wait a moment while it connects, and window will open to dired buffer on the remote ~/ directory.
This worked for me on :
Windows 10
Emacs found at https://sourceforge.net/projects/emacsbinw64/files/release/.
cygwin64
Putty.
https://github.com/d5884/fakecygpty
The changes from the original tramp-sh.el is
for cygwin, use fakecygpty with ssh and change the prompt to ##
for plink, remove -ssh option
I have also renamed these method with w to differentiate it.
(when (string-equal system-type "windows-nt")
(add-to-list 'tramp-methods
`("sshw"
(tramp-login-program "fakecygpty ssh")
;; ("%h") must be a single element, see `tramp-compute-multi-hops'.
(tramp-login-args (("-l" "%u" "-o \"StrictHostKeyChecking=no\"") ("-P" "%p") ("-t")
("%h") ("\"")
(,(format
"env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=%s'"
tramp-terminal-type
"##"))
("/bin/sh") ("\"")))
(tramp-remote-shell "/bin/sh")
(tramp-remote-shell-login ("-l"))
(tramp-remote-shell-args ("-c"))
(tramp-default-port 22))
)
(add-to-list 'tramp-methods
`("plinkw"
(tramp-login-program "plink")
;; ("%h") must be a single element, see `tramp-compute-multi-hops'.
(tramp-login-args (("-l" "%u") ("-P" "%p") ("-t")
("%h") ("\"")
(,(format
"env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=%s'"
tramp-terminal-type
"$"))
("/bin/sh") ("\"")))
(tramp-remote-shell "/bin/sh")
(tramp-remote-shell-login ("-l"))
(tramp-remote-shell-args ("-c"))
(tramp-default-port 22))
)
)