[Xmonad] Re: slock issue

Andrea Rossato mailing_list at istitutocolli.org
Tue Aug 21 19:00:55 EDT 2007


On Tue, Aug 21, 2007 at 10:26:25AM +0200, Andrea Rossato wrote:
> As you see it is suggested to use some other alternatives till slock
> will get fixed.[1]

I wrote an alternative myself, in Haskell. Actually because I wanted
to familiarize with the FFI infrastructure (it took me far more to
understand how to pass an option to the linker then importing the C
function...;-_).

It is not slock, thought: since I didn't find a way to hide the
pointer I found a nice font for it.

To run must be set suid root (as slock). In the headers instruction on
how to build. Works only with shadow passwords.

Well, guess what? It has the same slock problem. The very same issue.
Interesting I would say!

At least now I have some code that I can understand and may be I can
even find where the problem is. I doubt though.

Andrea

PS: Dons, I know you won't like the code. But I'm sure that someone
wrote that Haskell is the best imperative language ever. And I'm
trying to provide scientific evidence of that!
-------------- next part --------------
{-# INCLUDE "shadow.h" #-}
{-# OPTIONS_GHC -optc-D_XOPEN_SOURCE #-}
{-# INCLUDE "unistd.h" #-}
{-# LINE 1 "hslock.hsc" #-}
-----------------------------------------------------------------------------
{-# LINE 2 "hslock.hsc" #-}
-- |
-- Module      :  hslock
-- Copyright   :  (C) 2007 Andrea Rossato
-- License     :  BSD3
-- 
-- Maintainer  :  andrea.rossato at unibz.it
-- Stability   :  unstable
-- Portability :  unportable
--
-- A simple screen locker in Haskell
--
-- Works only with shadow passords and if set suid root
--
-- Compile with:
--
-- hsc2hs hslock.hsc
-- ghc --make hslock.hs -fglasgow-exts -lcrypt
-----------------------------------------------------------------------------

module Main where

import Control.Monad
import Data.IORef
import Data.Maybe
import Foreign.C
import Foreign
import System.Environment

import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras

data Spwd = 
    Spwd { sp_namp :: CString
         , sp_pwdp :: CString
         }


{-# LINE 39 "hslock.hsc" #-}

{-# LINE 40 "hslock.hsc" #-}

{-# LINE 41 "hslock.hsc" #-}

foreign import ccall unsafe "shodow.h getspnam"
    getspan :: CString -> IO (Ptr Spwd)

instance Storable Spwd where
    sizeOf    _ = (36)
{-# LINE 47 "hslock.hsc" #-}
    alignment _ = alignment (undefined :: CInt)
    peek p = Spwd `fmap` (\hsc_ptr -> peekByteOff hsc_ptr 0) p
{-# LINE 49 "hslock.hsc" #-}
                  `ap`   (\hsc_ptr -> peekByteOff hsc_ptr 4) p
{-# LINE 50 "hslock.hsc" #-}
    poke p (Spwd n pw) = do
        (\hsc_ptr -> pokeByteOff hsc_ptr 0) p n
{-# LINE 52 "hslock.hsc" #-}
        (\hsc_ptr -> pokeByteOff hsc_ptr 4) p pw
{-# LINE 53 "hslock.hsc" #-}

getpass :: String -> IO Spwd
getpass name = 
  withCString name $ \ c_name -> do
    s <- throwIfNull "No user entry" $ getspan c_name
    peek s

foreign import ccall unsafe "unistd.h crypt"
  hcrypt :: CString -> CString -> IO CString

encrypt_pass :: String -> String -> IO String
encrypt_pass key salt = do
  withCString key $ \k -> 
      withCString salt $ \s -> do
          e <- hcrypt k s
          peekCString e

verifyPWD :: String -> String -> IO Bool
verifyPWD name pass = do
  u <- getpass name
  pw <- peekCString (sp_pwdp u)
  e <- encrypt_pass pass pw
  return (pw == e)

main :: IO ()
main = do
  s <- newIORef []
  d <- catch (getEnv "DISPLAY") ( const $ return [])
  dpy <- openDisplay d
  let dflt = defaultScreen dpy
      scr  = defaultScreenOfDisplay dpy
  rootw <- rootWindow dpy dflt
  win <- mkUnmanagedWindow dpy scr rootw 0 0 (widthOfScreen scr) (heightOfScreen scr)
  selectInput dpy win keyPress
  mapWindow dpy win
  sync dpy False
  ks <- grabKeyboard dpy win True grabModeAsync grabModeAsync currentTime
  cursor <- createFontCursor dpy 88
  ps <- grabPointer dpy win False noEventMask grabModeAsync grabModeAsync win cursor currentTime
  when (ks == grabSuccess && ps == grabSuccess) $ do
          eventLoop dpy s
          ungrabKeyboard dpy currentTime
          ungrabPointer dpy currentTime
  destroyWindow dpy win
  sync dpy False

eventLoop :: Display -> IORef String -> IO ()
eventLoop d i = do
  (keysym,string,event) <- 
      allocaXEvent $ \e -> do 
          maskEvent d keyPressMask e
          ev <- getEvent e
          (ks,s) <- if ev_event_type ev == keyPress
                    then lookupString $ asKeyEvent e
                    else return (Nothing, "")
          return (ks,s,ev)
  handle d i (fromMaybe xK_VoidSymbol keysym,string) event

type KeyStroke = (KeySym, String)

handle :: Display -> IORef String -> KeyStroke -> Event -> IO ()
handle d i (ks,str) (KeyEvent {ev_event_type = t}) 
-- Return: check password
    | t == keyPress && ks == xK_Return = do
  u <- getEnv "USER"
  p <- readIORef i
  b <- verifyPWD u p
  if b then return ()
     else modifyIORef i (\_ -> []) >> eventLoop d i
-- Escape: restart
    | t == keyPress && ks == xK_Escape = do
  modifyIORef i (\_ -> [])
  eventLoop d i
    | t == keyPress &&  str == "" = eventLoop d i
    | otherwise = do
  modifyIORef i (\s -> s ++ str)
  eventLoop d i
handle d i _ _ = eventLoop d i

mkUnmanagedWindow :: Display -> Screen -> Window -> Position
                  -> Position -> Dimension -> Dimension  -> IO Window
mkUnmanagedWindow dpy scr rw x y w h = do
  let visual = defaultVisualOfScreen scr
      attrmask = cWOverrideRedirect .|. cWBackPixel
  allocaSetWindowAttributes $
         \attributes -> do
           set_override_redirect attributes True
           set_background_pixel attributes $ blackPixel dpy (defaultScreen dpy)
           createWindow dpy rw x y w h 0 (defaultDepthOfScreen scr)
                        inputOutput visual attrmask attributes

initColor :: Display -> String -> IO Pixel
initColor dpy color = do
  let colormap = defaultColormap dpy (defaultScreen dpy)
  (apros,_) <- allocNamedColor dpy colormap color
  return $ color_pixel apros


More information about the Xmonad mailing list