rpms/slim/F-7 slim-1.2.6-pam.patch,NONE,1.1 slim.spec,1.2,1.3

Anders F Björklund (afb) fedora-extras-commits at redhat.com
Mon Sep 24 19:53:30 UTC 2007


Author: afb

Update of /cvs/pkgs/rpms/slim/F-7
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv10287

Modified Files:
	slim.spec 
Added Files:
	slim-1.2.6-pam.patch 
Log Message:
backport PAM support

slim-1.2.6-pam.patch:

--- NEW FILE slim-1.2.6-pam.patch ---
diff -uNbr --exclude=.svn release-1.2.6/Makefile slim-pam/Makefile
--- release-1.2.6/Makefile	2006-09-15 23:00:28.000000000 +0200
+++ slim-pam/Makefile	2007-06-05 12:57:54.000000000 +0200
@@ -8,6 +8,10 @@
 CFLAGS=-I. -I/usr/X11R6/include -I/usr/include/freetype2 -I/usr/include/freetype2/config -I/usr/include/libpng12 -I/usr/include
 LDFLAGS=-L/usr/X11R6/lib -lXft -lX11 -lfreetype -lXrender -lfontconfig -lpng12 -lz -lm -lcrypt -lXmu -lpng -ljpeg
 CUSTOM=-DHAVE_SHADOW
+ifdef USE_PAM
+LDFLAGS+= -lpam
+CUSTOM+= -DUSE_PAM
+endif
 PREFIX=/usr
 CFGDIR=/etc
 MANDIR=/usr/man
@@ -20,7 +24,10 @@
 DEFINES=-DPACKAGE=\"$(NAME)\" -DVERSION=\"$(VERSION)\" \
 		-DPKGDATADIR=\"$(PREFIX)/share/slim\" -DSYSCONFDIR=\"$(CFGDIR)\"
 
-OBJECTS=jpeg.o png.o main.o image.o numlock.o cfg.o switchuser.o input.o app.o panel.o
+OBJECTS=jpeg.o png.o main.o image.o numlock.o cfg.o switchuser.o app.o panel.o
+ifdef USE_PAM
+OBJECTS+=PAM.o
+endif
 
 all: slim
 
diff -uNbr --exclude=.svn release-1.2.6/Makefile.freebsd slim-pam/Makefile.freebsd
--- release-1.2.6/Makefile.freebsd	2006-09-15 23:00:28.000000000 +0200
+++ slim-pam/Makefile.freebsd	2007-06-11 13:00:09.000000000 +0200
@@ -8,6 +8,10 @@
 CFLAGS=-I. -I/usr/X11R6/include -I/usr/local/include/freetype2 -I/usr/local/include/freetype2/config -I/usr/local/include/libpng -I/usr/local/include -I/usr/include
 LDFLAGS=-L/usr/X11R6/lib -L/usr/local/lib -lXft -lX11 -lfreetype -lXrender -lfontconfig -lpng -lz -lm -lcrypt -lXmu -lpng -ljpeg
 CUSTOM=-DNEEDS_BASENAME
+.ifdef(USE_PAM)
+  LDFLAGS+= -lpam
+  CUSTOM+= -DUSE_PAM
+.endif
 PREFIX=/usr
 CFGDIR=/etc
 MANDIR=/usr/share/man
@@ -20,7 +24,10 @@
 DEFINES=-DPACKAGE=\"$(NAME)\" -DVERSION=\"$(VERSION)\" \
 		-DPKGDATADIR=\"$(PREFIX)/share/slim\" -DSYSCONFDIR=\"$(CFGDIR)\"
 
-OBJECTS=jpeg.o png.o main.o image.o numlock.o cfg.o switchuser.o input.o app.o panel.o
+OBJECTS=jpeg.o png.o main.o image.o numlock.o cfg.o switchuser.o app.o panel.o
+.ifdef USE_PAM
+  OBJECTS+=PAM.o 
+.endif
 
 all: slim
 
diff -uNbr --exclude=.svn release-1.2.6/Makefile.netbsd slim-pam/Makefile.netbsd
--- release-1.2.6/Makefile.netbsd	2006-09-15 23:00:28.000000000 +0200
+++ slim-pam/Makefile.netbsd	2007-06-07 04:15:03.000000000 +0200
@@ -8,6 +8,10 @@
 CFLAGS=-I. -I/usr/X11R6/include -I/usr/X11R6/include/freetype2 -I/usr/X11R6/include/freetype2/config -I/usr/pkg/include -I/usr/include
 LDFLAGS=-L/usr/X11R6/lib -L/usr/pkg/lib -lXft -lX11 -lfreetype -lXrender -lfontconfig -lpng -lz -lm -lcrypt -lXmu -lpng -ljpeg
 CUSTOM=-DNEEDS_BASENAME
+.ifdef(USE_PAM)
+  LDFLAGS+= -lpam
+  CUSTOM+= -DUSE_PAM
+.endif
 PREFIX=/usr
 CFGDIR=/etc
 MANDIR=/usr/share/man
@@ -20,7 +24,10 @@
 DEFINES=-DPACKAGE=\"$(NAME)\" -DVERSION=\"$(VERSION)\" \
 		-DPKGDATADIR=\"$(PREFIX)/share/slim\" -DSYSCONFDIR=\"$(CFGDIR)\"
 
-OBJECTS=jpeg.o png.o main.o image.o numlock.o cfg.o switchuser.o input.o app.o panel.o
+OBJECTS=jpeg.o png.o main.o image.o numlock.o cfg.o switchuser.o app.o panel.o
+.ifdef USE_PAM
+  OBJECTS+=PAM.o 
+.endif
 
 all: slim
 
diff -uNbr --exclude=.svn release-1.2.6/Makefile.openbsd slim-pam/Makefile.openbsd
--- release-1.2.6/Makefile.openbsd	2006-09-15 23:00:28.000000000 +0200
+++ slim-pam/Makefile.openbsd	2007-06-05 12:57:54.000000000 +0200
@@ -20,7 +20,7 @@
 DEFINES=-DPACKAGE=\"$(NAME)\" -DVERSION=\"$(VERSION)\" \
 		-DPKGDATADIR=\"$(PREFIX)/share/slim\" -DSYSCONFDIR=\"$(CFGDIR)\"
 
-OBJECTS=jpeg.o png.o main.o image.o numlock.o cfg.o switchuser.o input.o app.o panel.o
+OBJECTS=jpeg.o png.o main.o image.o numlock.o cfg.o switchuser.o app.o panel.o
 
 .SUFFIXES: .c.o .cpp.o
 
@@ -44,9 +44,6 @@
 switchuser.o:
 	$(CXX) $(CFLAGS) $(DEFINES) $(CUSTOM) -c switchuser.cpp -o $@
 
-input.o:
-	$(CXX) $(CFLAGS) $(DEFINES) $(CUSTOM) -c input.cpp -o $@
-
 app.o:
 	$(CXX) $(CFLAGS) $(DEFINES) $(CUSTOM) -c app.cpp -o $@
 
diff -uNbr --exclude=.svn release-1.2.6/PAM.cpp slim-pam/PAM.cpp
--- release-1.2.6/PAM.cpp	1970-01-01 01:00:00.000000000 +0100
+++ slim-pam/PAM.cpp	2007-05-29 19:10:51.000000000 +0200
@@ -0,0 +1,275 @@
+/* SLiM - Simple Login Manager
+   Copyright (C) 2007 Martin Parm
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+*/
+#include <PAM.h>
+#include <string>
+#include <iostream>
+
+namespace PAM {
+    Exception::Exception(pam_handle_t* _pam_handle,
+               const std::string& _func_name,
+               int _errnum):
+        errnum(_errnum),
+        errstr(pam_strerror(_pam_handle, _errnum)),
+        func_name(_func_name)
+        {}
+
+    Exception::~Exception(void){}
+
+    Auth_Exception::Auth_Exception(pam_handle_t* _pam_handle,
+                                   const std::string& _func_name,
+                                   int _errnum):
+        Exception(_pam_handle, _func_name, _errnum){}
+
+    Cred_Exception::Cred_Exception(pam_handle_t* _pam_handle,
+                                   const std::string& _func_name,
+                                   int _errnum):
+        Exception(_pam_handle, _func_name, _errnum){}
+
+    int Authenticator::_end(void){
+        int result=pam_end(pam_handle, last_result);
+        pam_handle=0;
+        return result;
+    }
+
+    Authenticator::Authenticator(conversation* conv, void* data):
+        pam_handle(0),
+        last_result(PAM_SUCCESS)
+    {
+        pam_conversation.conv=conv;
+        pam_conversation.appdata_ptr=data;
+    }
+
+    Authenticator::~Authenticator(void){
+        if (pam_handle) _end();
+    }
+
+    void Authenticator::start(const std::string& service){
+        switch((last_result=pam_start(service.c_str(), NULL, &pam_conversation, &pam_handle))){
+            default:
+                throw Exception(pam_handle, "pam_start()", last_result);
+
+            case PAM_SUCCESS:
+                break;
+        }
+        return;
+    }
+
+    void Authenticator::end(void){
+        switch((last_result=_end())){
+            default:
+                throw Exception(pam_handle, "pam_end()", last_result);
+
+            case PAM_SUCCESS:
+                break;
+
+        }
+        return;
+    }
+
+    void Authenticator::set_item(const Authenticator::ItemType item, const void* value){
+        switch((last_result=pam_set_item(pam_handle, item, value))){
+            default:
+            _end();
+                throw Exception(pam_handle, "pam_set_item()", last_result);
+
+            case PAM_SUCCESS:
+                break;
+        }
+        return;
+    }
+
+    const void* Authenticator::get_item(const Authenticator::ItemType item){
+        const void* data;
+        switch ((last_result=pam_get_item(pam_handle, item, &data))){
+            default:
+            case PAM_SYSTEM_ERR:
+#ifdef __LIBPAM_VERSION
+            case PAM_BAD_ITEM:
+#endif
+                _end();
+                throw Exception(pam_handle, "pam_get_item()", last_result);
+
+            case PAM_PERM_DENIED: // The value of item was NULL
+            case PAM_SUCCESS:
+                break;
+        }
+        return data;
+    }
+
+#ifdef __LIBPAM_VERSION
+    void Authenticator::fail_delay(const unsigned int micro_sec){
+        switch((last_result=pam_fail_delay(pam_handle, micro_sec))){
+            default:
+                _end();
+                throw Exception(pam_handle, "fail_delay()", last_result);
+
+            case PAM_SUCCESS:
+                break;
+        }
+        return;
+    }
+#endif
+
+    void Authenticator::authenticate(void){
+        switch((last_result=pam_authenticate(pam_handle, 0))){
+            default:
+            case PAM_ABORT:
+            case PAM_AUTHINFO_UNAVAIL:
+                _end();
+                throw Exception(pam_handle, "pam_authenticate()", last_result);
+
+            case PAM_USER_UNKNOWN:
+            case PAM_MAXTRIES:
+            case PAM_CRED_INSUFFICIENT:
+            case PAM_AUTH_ERR:
+                throw Auth_Exception(pam_handle, "pam_authentication()", last_result);
+
+            case PAM_SUCCESS:
+                break;
+        }
+
+        switch((last_result=pam_acct_mgmt(pam_handle, PAM_SILENT))){
+            // The documentation and implementation of Linux PAM differs:
+            // PAM_NEW_AUTHTOKEN_REQD is described in the documentation but
+            // don't exists in the actual implementation. This issue needs
+            // to be fixes at some point.
+
+            default:
+            //case PAM_NEW_AUTHTOKEN_REQD:
+            case PAM_ACCT_EXPIRED:
+            case PAM_USER_UNKNOWN:
+                _end();
+                throw Exception(pam_handle, "pam_acct_mgmt()", last_result);
+                
+            case PAM_AUTH_ERR:
+            case PAM_PERM_DENIED:
+                throw Auth_Exception(pam_handle, "pam_acct_mgmt()", last_result);
+
+            case PAM_SUCCESS:
+                break;
+        };
+        return;
+    }
+
+    void Authenticator::open_session(void){
+        switch((last_result=pam_setcred(pam_handle, PAM_ESTABLISH_CRED))){
+            default:
+            case PAM_CRED_ERR:
+            case PAM_CRED_UNAVAIL:
+                _end();
+                throw Exception(pam_handle, "pam_setcred()", last_result);
+
+            case PAM_CRED_EXPIRED:
+            case PAM_USER_UNKNOWN:
+                throw Cred_Exception(pam_handle, "pam_setcred()", last_result);
+
+            case PAM_SUCCESS:
+                break;
+        }
+
+        switch((last_result=pam_open_session(pam_handle, 0))){
+            // The documentation and implementation of Linux PAM differs:
+            // PAM_SESSION_ERROR is described in the documentation but
+            // don't exists in the actual implementation. This issue needs
+            // to be fixes at some point.
+
+            default:
+            //case PAM_SESSION_ERROR:
+                pam_setcred(pam_handle, PAM_DELETE_CRED);
+                _end();
+                throw Exception(pam_handle, "pam_open_session()", last_result);
+
+            case PAM_SUCCESS:
+                break;
+        };
+        return;
+    }
+
+    void Authenticator::close_session(void){
+        switch((last_result=pam_close_session(pam_handle, 0))){
+            // The documentation and implementation of Linux PAM differs:
+            // PAM_SESSION_ERROR is described in the documentation but
+            // don't exists in the actual implementation. This issue needs
+            // to be fixes at some point.
+
+            default:
+            //case PAM_SESSION_ERROR:
+                pam_setcred(pam_handle, PAM_DELETE_CRED);
+                _end();
+                throw Exception(pam_handle, "pam_close_session", last_result);
+
+            case PAM_SUCCESS:
+                break;
+        };
+        switch((last_result=pam_setcred(pam_handle, PAM_DELETE_CRED))){
+            default:
+            case PAM_CRED_ERR:
+            case PAM_CRED_UNAVAIL:
+            case PAM_CRED_EXPIRED:
+            case PAM_USER_UNKNOWN:
+                _end();
+                throw Exception(pam_handle, "pam_setcred()", last_result);
+
+            case PAM_SUCCESS:
+                break;
+        }
+        return;
+    }
+
+    void Authenticator::setenv(const std::string& key, const std::string& value){
+        std::string name_value = key+"="+value;
+        switch((last_result=pam_putenv(pam_handle, name_value.c_str()))){
+            default:
+            case PAM_PERM_DENIED:
+            case PAM_ABORT:
+            case PAM_BUF_ERR:
+#ifdef __LIBPAM_VERSION
+            case PAM_BAD_ITEM:
+#endif
+                _end();
+                throw Exception(pam_handle, "pam_putenv()", last_result);
+
+            case PAM_SUCCESS:
+                break;
+        };
+        return;
+    }
+
+    void Authenticator::delenv(const std::string& key){
+        switch((last_result=pam_putenv(pam_handle, key.c_str()))){
+            default:
+            case PAM_PERM_DENIED:
+            case PAM_ABORT:
+            case PAM_BUF_ERR:
+#ifdef __LIBPAM_VERSION
+            case PAM_BAD_ITEM:
+#endif
+                _end();
+                throw Exception(pam_handle, "pam_putenv()", last_result);
+
+            case PAM_SUCCESS:
+                break;
+        };
+        return;
+    }
+
+    const char* Authenticator::getenv(const std::string& key){
+        return pam_getenv(pam_handle, key.c_str());
+    }
+
+    char** Authenticator::getenvlist(void){
+        return pam_getenvlist(pam_handle);
+    }
+
+};
+
+std::ostream& operator<<( std::ostream& os, const PAM::Exception& e){
+    os << e.func_name << ": " << e.errstr;
+    return os;
+}
diff -uNbr --exclude=.svn release-1.2.6/PAM.h slim-pam/PAM.h
--- release-1.2.6/PAM.h	1970-01-01 01:00:00.000000000 +0100
+++ slim-pam/PAM.h	2007-06-07 04:16:01.000000000 +0200
@@ -0,0 +1,99 @@
+/* SLiM - Simple Login Manager
+   Copyright (C) 2007 Martin Parm
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+*/
+
+#ifndef _PAM_H_
+#define _PAM_H_
+#include <string>
+#include <security/pam_appl.h>
+
+#ifdef __LIBPAM_VERSION
+#include <security/pam_misc.h>
+#endif
+
+namespace PAM {
+    class Exception{
+    public:
+        int errnum;
+        std::string errstr;
+        std::string func_name;
+        Exception(pam_handle_t* _pam_handle,
+                  const std::string& _func_name,
+                  int _errnum);
+        virtual ~Exception(void);
+    };
+
+    class Auth_Exception: public Exception{
+    public:
+        Auth_Exception(pam_handle_t* _pam_handle,
+                       const std::string& _func_name,
+                       int _errnum);
+    };
+
+    class Cred_Exception: public Exception{
+    public:
+        Cred_Exception(pam_handle_t* _pam_handle,
+                       const std::string& _func_name,
+                       int _errnum);
+    };
+
+
+    class Authenticator{
+    private:
+        struct pam_conv pam_conversation;
+        pam_handle_t* pam_handle;
+        int last_result;
+
+        int _end(void);
+    public:
+        typedef int (conversation)(int num_msg,
+                           const struct pam_message **msg,
+                           struct pam_response **resp,
+                           void *appdata_ptr);
+
+        enum ItemType {
+            Service     = PAM_SERVICE,
+            User        = PAM_USER,
+            User_Prompt = PAM_USER_PROMPT,
+            TTY         = PAM_TTY,
+            Requestor   = PAM_RUSER,
+            Host        = PAM_RHOST,
+            Conv        = PAM_CONV,
+#ifdef __LIBPAM_VERSION
+            //Fail_Delay  = PAM_FAIL_DELAY
+#endif
+        };
+
+    public:
+        Authenticator(conversation* conv, void* data=0);
+        ~Authenticator(void);
+        
+        void start(const std::string& service);
+        void end(void);
+        void set_item(const ItemType item, const void* value);
+        const void* get_item(const ItemType item);
+#ifdef __LIBPAM_VERSION
+        void fail_delay(const unsigned int micro_sec);
+#endif
+        void authenticate(void);
+        void open_session(void);
+        void close_session(void);
+        void setenv(const std::string& key, const std::string& value);
+        void delenv(const std::string& key);
+        const char* getenv(const std::string& key);
+        char** getenvlist(void);
+
+    private:
+        // Explicitly disable copy constructor and copy assignment
+        Authenticator(const PAM::Authenticator&);
+        Authenticator& operator=(const PAM::Authenticator&);
+    };
+};
+
+std::ostream& operator<<( std::ostream& os, const PAM::Exception& e);
+#endif
diff -uNbr --exclude=.svn release-1.2.6/app.cpp slim-pam/app.cpp
--- release-1.2.6/app.cpp	2006-09-10 22:10:40.000000000 +0200
+++ slim-pam/app.cpp	2007-06-07 04:18:21.000000000 +0200
@@ -26,6 +26,78 @@
 #include "numlock.h"
 
 
+#ifdef HAVE_SHADOW
+#include <shadow.h>
+#endif
+
+#ifdef USE_PAM
+#include <string>
+
+int conv(int num_msg, const struct pam_message **msg,
+         struct pam_response **resp, void *appdata_ptr){
+    *resp = (struct pam_response *) calloc(num_msg, sizeof(struct pam_response));
+    Panel* panel = *static_cast<Panel**>(appdata_ptr);
+    int result = PAM_SUCCESS;
+    for (int i=0; i<num_msg; i++){
+        resp[i]->resp=0;
+        resp[i]->resp_retcode=0;
+        switch(msg[i]->msg_style){
+            case PAM_PROMPT_ECHO_ON:
+                // We assume PAM is asking for the username
+                panel->EventHandler(Panel::Get_Name);
+                switch(panel->getAction()){
+                    case Panel::Suspend:
+                    case Panel::Halt:
+                    case Panel::Reboot:
+                        resp[i]->resp=strdup("root");
+                        break;
+
+                    case Panel::Console:
+                    case Panel::Exit:
+                    case Panel::Login:
+                        resp[i]->resp=strdup(panel->GetName().c_str());
+                        break;
+                }
+                break;
+
+            case PAM_PROMPT_ECHO_OFF:
+                // We assume PAM is asking for the password
+                switch(panel->getAction()){
+                    case Panel::Console:
+                    case Panel::Exit:
+                        // We should leave now!
+                        result=PAM_CONV_ERR;
+                        break;
+
+                    default:
+                        panel->EventHandler(Panel::Get_Passwd);
+                        resp[i]->resp=strdup(panel->GetPasswd().c_str());
+                        break;
+                }
+                break;
+
+            case PAM_ERROR_MSG:
+            case PAM_TEXT_INFO:
+                // We simply write these to the log
+                // TODO: Maybe we should simply ignore them
+                cerr << APPNAME << ": " << msg[i]->msg << endl;
+                break;
+        }
+        if (result!=PAM_SUCCESS) break;
+    }
+    if (result!=PAM_SUCCESS){
+        for (int i=0; i<num_msg; i++){
+            if (resp[i]->resp==0) continue;
+            free(resp[i]->resp);
+            resp[i]->resp=0;
+        };
+        free(*resp);
+        *resp=0;
+    };
+    return result;
+}
+#endif
+
 extern App* LoginApp;
 
 void CatchSignal(int sig) {
@@ -53,8 +125,12 @@
 }
 
 
-App::App(int argc, char** argv) {
-
+#ifdef USE_PAM
+App::App(int argc, char** argv):
+    pam(conv, static_cast<void*>(&LoginPanel)){
+#else
+App::App(int argc, char** argv){
+#endif
     int tmp;
     ServerPID = -1;
     testing = false;
@@ -133,6 +209,20 @@
         }
     }
 
+#ifdef USE_PAM
+    try{
+        pam.start("slim");
+        pam.set_item(PAM::Authenticator::TTY, DisplayName);
+        pam.set_item(PAM::Authenticator::Requestor, "root");
+        pam.set_item(PAM::Authenticator::Host, "localhost");
+
+    }
+    catch(PAM::Exception& e){
+        cerr << APPNAME << ": " << e << endl;
+        exit(ERR_EXIT);
+    };
+#endif
+
     bool loaded = false;
     while (!loaded) {
         themedir =  themebase + themeName;
@@ -219,9 +308,8 @@
     LoginPanel = new Panel(Dpy, Scr, Root, cfg, themedir);
 
     // Start looping
-    XEvent event;
     int panelclosed = 1;
-    int Action;
+    Panel::ActionType Action;
     bool firstloop = true; // 1st time panel is shown (for automatic username)
 
     while(1) {
@@ -239,53 +327,124 @@
             LoginPanel->OpenPanel();
         }
 
-        Action = WAIT;
-        LoginPanel->GetInput()->Reset();
+        LoginPanel->Reset();
         if (firstloop && cfg->getOption("default_user") != "") {
-            LoginPanel->GetInput()->SetName(cfg->getOption("default_user") );
+            LoginPanel->SetName(cfg->getOption("default_user") );
             firstloop = false;
         }
 
-        while(Action == WAIT) {
-            XNextEvent(Dpy, &event);
-            Action = LoginPanel->EventHandler(&event);
-        }
 
-        if(Action == FAIL) {
+        if (!AuthenticateUser()){
             panelclosed = 0;
             LoginPanel->ClearPanel();
             XBell(Dpy, 100);
-        } else {
+            continue;
+        }
+        
+
+        Action = LoginPanel->getAction();
             // for themes test we just quit
             if (testing) {
-                Action = EXIT;
+            Action = Panel::Exit;
             }
             panelclosed = 1;
             LoginPanel->ClosePanel();
 
             switch(Action) {
-                case LOGIN:
+            case Panel::Login:
                     Login();
                     break;
-                case CONSOLE:
+            case Panel::Console:
                     Console();
                     break;
-                case REBOOT:
+            case Panel::Reboot:
                     Reboot();
                     break;
-                case HALT:
+            case Panel::Halt:
                     Halt();
                     break;
-                case SUSPEND:
+            case Panel::Suspend:
                     Suspend();
                     break;
-                case EXIT:
+            case Panel::Exit:
                     Exit();
                     break;
             }
         }
+}
+
+#ifdef USE_PAM
+bool App::AuthenticateUser(void){
+    // Reset the username
+    try{
+        pam.set_item(PAM::Authenticator::User, 0);
+        pam.authenticate();
+    }
+    catch(PAM::Auth_Exception& e){
+        switch(LoginPanel->getAction()){
+            case Panel::Exit:
+            case Panel::Console:
+                return true; // <--- This is simply fake!
+            default:
+                break;
+        };
+        cerr << APPNAME << ": " << e << endl;
+        return false;
+    }
+    catch(PAM::Exception& e){
+        cerr << APPNAME << ": " << e << endl;
+        exit(ERR_EXIT);
+    };
+    return true;
+}
+#else
+bool App::AuthenticateUser(void){
+    LoginPanel->EventHandler(Panel::Get_Name);
+    switch(LoginPanel->getAction()){
+        case Panel::Exit:
+        case Panel::Console:
+            cerr << APPNAME << ": Got a special command (" << LoginPanel->GetName() << ")" << endl;
+            return true; // <--- This is simply fake!
+        default:
+            break;
+    };
+    LoginPanel->EventHandler(Panel::Get_Passwd);
+    
+    char *encrypted, *correct;
+    struct passwd *pw;
+
+    switch(LoginPanel->getAction()){
+        case Panel::Suspend:
+        case Panel::Halt:
+        case Panel::Reboot:
+            pw = getpwnam("root");
+            break;
+        case Panel::Console:
+        case Panel::Exit:
+        case Panel::Login:
+            pw = getpwnam(LoginPanel->GetName().c_str());
+            break;
     }
+    endpwent();
+    if(pw == 0)
+        return false;
+
+#ifdef HAVE_SHADOW
+    struct spwd *sp = getspnam(pw->pw_name);    
+    endspent();
+    if(sp)
+        correct = sp->sp_pwdp;
+    else
+#endif        // HAVE_SHADOW
+        correct = pw->pw_passwd;
+
+    if(correct == 0 || correct[0] == '\0')
+        return true;
+
+    encrypted = crypt(LoginPanel->GetPasswd().c_str(), correct);
+    return ((strcmp(encrypted, correct) == 0) ? true : false);
 }
+#endif
 
 
 int App::GetServerPID() {
@@ -313,15 +472,85 @@
     struct passwd *pw;
     pid_t pid;
 
-    pw = LoginPanel->GetInput()->GetPasswdStruct();
+#ifdef USE_PAM
+    try{
+        pam.open_session();
+        pw = getpwnam(static_cast<const char*>(pam.get_item(PAM::Authenticator::User)));
+    }
+    catch(PAM::Cred_Exception& e){
+        // Credentials couldn't be established
+        cerr << APPNAME << ": " << e << endl;
+        return;
+    }
+    catch(PAM::Exception& e){
+        cerr << APPNAME << ": " << e << endl;
+        exit(ERR_EXIT);
+    };
+#else
+    pw = getpwnam(LoginPanel->GetName().c_str());
+#endif
+    endpwent();
     if(pw == 0)
         return;
+    if (pw->pw_shell[0] == '\0') {
+        setusershell();
+        strcpy(pw->pw_shell, getusershell());
+        endusershell();
+    }
+
+    // Setup the environment
+    char* term = getenv("TERM");
+    string maildir = _PATH_MAILDIR;
+    maildir.append("/");
+    maildir.append(pw->pw_name);
+    string xauthority = pw->pw_dir;
+    xauthority.append("/.Xauthority");
+    
+#ifdef USE_PAM
+    // Setup the PAM environment
+    try{
+        if(term) pam.setenv("TERM", term);
+        pam.setenv("HOME", pw->pw_dir);
+        pam.setenv("SHELL", pw->pw_shell);
+        pam.setenv("USER", pw->pw_name);
+        pam.setenv("LOGNAME", pw->pw_name);
+        pam.setenv("PATH", cfg->getOption("default_path").c_str());
+        pam.setenv("DISPLAY", DisplayName);
+        pam.setenv("MAIL", maildir.c_str());
+        pam.setenv("XAUTHORITY", xauthority.c_str());
+    }
+    catch(PAM::Exception& e){
+        cerr << APPNAME << ": " << e << endl;
+        exit(ERR_EXIT);
+    }
+#endif
 
     // Create new process
     pid = fork();
     if(pid == 0) {
+#ifdef USE_PAM
+        // Get a copy of the environment and close the child's copy
+        // of the PAM-handle.
+        char** child_env = pam.getenvlist();
+        pam.end();
+#else
+        const int Num_Of_Variables = 10; // Number of env. variables + 1
+        char** child_env = static_cast<char**>(malloc(sizeof(char*)*Num_Of_Variables));
+        int n = 0;
+        if(term) child_env[n++]=StrConcat("TERM=", term);
+        child_env[n++]=StrConcat("HOME=", pw->pw_dir);
+        child_env[n++]=StrConcat("SHELL=", pw->pw_shell);
+        child_env[n++]=StrConcat("USER=", pw->pw_name);
+        child_env[n++]=StrConcat("LOGNAME=", pw->pw_name);
+        child_env[n++]=StrConcat("PATH=", cfg->getOption("default_path").c_str());
+        child_env[n++]=StrConcat("DISPLAY=", DisplayName);
+        child_env[n++]=StrConcat("MAIL=", maildir.c_str());
+        child_env[n++]=StrConcat("XAUTHORITY=", xauthority.c_str());
+        child_env[n++]=0;
+#endif
+
         // Login process starts here
-        SwitchUser Su(pw, cfg, DisplayName);
+        SwitchUser Su(pw, cfg, DisplayName, child_env);
         string session = LoginPanel->getSession();
         string loginCommand = cfg->getOption("login_cmd");
         replaceVariables(loginCommand, SESSION_VAR, session);
@@ -332,7 +561,7 @@
             system(sessStart.c_str());
         }
         Su.Login(loginCommand.c_str(), mcookie.c_str());
-        exit(OK_EXIT);
+        _exit(OK_EXIT);
     }
 
 #ifndef XNEST_DEBUG
@@ -347,6 +576,7 @@
     }
     if (WIFEXITED(status) && WEXITSTATUS(status)) {
         LoginPanel->Message("Failed to execute login command");
+        sleep(3);
     } else {
          string sessStop = cfg->getOption("sessionstop_cmd");
          if (sessStop != "") {
@@ -355,7 +585,16 @@
         }
     }
 
-    // Close all clients
+#ifdef USE_PAM
+    try{
+        pam.close_session();
+    }
+    catch(PAM::Exception& e){
+        cerr << APPNAME << ": " << e << endl;
+    };
+#endif
+
+// Close all clients
     KillAllClients(False);
     KillAllClients(True);
 
@@ -382,6 +621,15 @@
     // Stop alarm clock
     alarm(0);
 
+#ifdef USE_PAM
+    try{
+        pam.end();
+    }
+    catch(PAM::Exception& e){
+        cerr << APPNAME << ": " << e << endl;
+    };
+#endif
+
     // Write message
     LoginPanel->Message((char*)cfg->getOption("reboot_msg").c_str());
     sleep(3);
@@ -398,6 +646,15 @@
     // Stop alarm clock
     alarm(0);
 
+#ifdef USE_PAM
+    try{
+        pam.end();
+    }
+    catch(PAM::Exception& e){
+        cerr << APPNAME << ": " << e << endl;
+    };
+#endif
+
     // Write message
     LoginPanel->Message((char*)cfg->getOption("shutdown_msg").c_str());
     sleep(3);
@@ -433,6 +690,15 @@
 
 
 void App::Exit() {
+#ifdef USE_PAM
+    try{
+        pam.end();
+    }
+    catch(PAM::Exception& e){
+        cerr << APPNAME << ": " << e << endl;
+    };
+#endif
+
     if (testing) {
         char* testmsg = "This is a test message :-)";
         LoginPanel->Message(testmsg);
@@ -453,6 +720,15 @@
 }
 
 void App::RestartServer() {
+#ifdef USE_PAM
+    try{
+        pam.end();
+    }
+    catch(PAM::Exception& e){
+        cerr << APPNAME << ": " << e << endl;
+    };
+#endif
+
         StopServer(); 
         RemoveLock();
         Run();
diff -uNbr --exclude=.svn release-1.2.6/app.h slim-pam/app.h
--- release-1.2.6/app.h	2006-09-10 12:05:34.000000000 +0200
+++ slim-pam/app.h	2007-05-19 21:26:29.000000000 +0200
@@ -24,6 +24,10 @@
 #include "cfg.h"
 #include "image.h"
 
+#ifdef USE_PAM
+#include "PAM.h"
+#endif
+
 class App {
 public:
     App(int argc, char** argv);
@@ -53,6 +57,8 @@
     char* StrConcat(const char* str1, const char* str2);
     void UpdatePid();
  
+    bool AuthenticateUser(void);
+ 
     static std::string findValidRandomTheme(const std::string& set);
     static void replaceVariables(std::string& input,
                                  const std::string& var,
@@ -71,6 +77,10 @@
     int ServerPID;
     char* DisplayName;
 
+#ifdef USE_PAM
+	PAM::Authenticator pam;
+#endif
+
     // Options
     char* DispName;
 
diff -uNbr --exclude=.svn release-1.2.6/cfg.cpp slim-pam/cfg.cpp
--- release-1.2.6/cfg.cpp	2006-09-10 12:05:34.000000000 +0200
+++ slim-pam/cfg.cpp	2007-05-27 15:44:12.000000000 +0200
@@ -19,7 +19,9 @@
 
 typedef pair<string,string> option;
 
-Cfg::Cfg() {
+Cfg::Cfg() 
+    : currentSession(-1)
+{
     // Configuration options
     options.insert(option("default_path","./:/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin"));
     options.insert(option("default_xserver","/usr/X11R6/bin/X"));
@@ -34,7 +36,7 @@
     options.insert(option("sessionstart_cmd",""));
     options.insert(option("sessionstop_cmd",""));
     options.insert(option("console_cmd","/usr/X11R6/bin/xterm -C -fg white -bg black +sb -g %dx%d+%d+%d -fn %dx%d -T ""Console login"" -e /bin/sh -c ""/bin/cat /etc/issue; exec /bin/login"""));
-    options.insert(option("screenshot_cmd","import -window root /login.app.png"));
+    options.insert(option("screenshot_cmd","import -window root /slim.png"));
     options.insert(option("welcome_msg","Welcome to %host"));
     options.insert(option("default_user",""));
     options.insert(option("current_theme","default"));
@@ -129,6 +131,7 @@
             }
         }
         cfgfile.close();
+        split(sessions, getOption("sessions"), ',', false);
         return true;
     } else {
         error = "Cannot read configuration file: " + configfile;
@@ -211,8 +214,7 @@
     int n = -1;
     n = position.find("%");
     if (n>0) { // X Position expressed in percentage
-        const char* tmp =  position.substr(0, n).c_str();
-        int result = (max*string2int(tmp)/100) - (width / 2);
+        int result = (max*string2int(position.substr(0, n).c_str())/100) - (width / 2);
         return result < 0 ? 0 : result ;
     } else { // Absolute X position
         return string2int(position.c_str());
@@ -220,17 +222,21 @@
 }
 
 // split a comma separated string into a vector of strings
-void Cfg::split(vector<string>& v, const string& str, char c) {
+void Cfg::split(vector<string>& v, const string& str, char c, bool useEmpty) {
     v.clear();
     string::const_iterator s = str.begin();
+    string tmp;
     while (true) {
         string::const_iterator begin = s;
         while (*s != c && s != str.end()) { ++s; }
-        v.push_back(string(begin, s));
+    tmp = string(begin, s);
+    if (useEmpty || tmp.size() > 0)
+            v.push_back(tmp);
         if (s == str.end()) {
             break;
         }
         if (++s == str.end()) {
+        if (useEmpty)
             v.push_back("");
             break;
         }
@@ -238,15 +244,9 @@
 }
 
 string Cfg::nextSession(string current) {
-    vector<string> sessions;
-    split(sessions, getOption("sessions"), ',');
-    if (sessions.size() <= 1)
+    if (sessions.size() < 1)
         return current;
 
-    for (int i=0; i<(int)sessions.size()-1; i++) {
-        if (current == sessions[i]) {
-            return sessions[i+1];
-        }
-    }
-    return sessions[0];
+    currentSession = (currentSession + 1) % sessions.size();
+    return sessions[currentSession];
 }
diff -uNbr --exclude=.svn release-1.2.6/cfg.h slim-pam/cfg.h
--- release-1.2.6/cfg.h	2006-09-10 12:05:34.000000000 +0200
+++ slim-pam/cfg.h	2007-05-17 16:38:53.000000000 +0200
@@ -37,13 +37,16 @@
 
     static int absolutepos(const string& position, int max, int width);
     static int string2int(const char* string, bool* ok = 0);
-    static void split(vector<string>& v, const string& str, char c);
+    static void split(vector<string>& v, const string& str, 
+                      char c, bool useEmpty=true);
     static string Trim(const string& s);
 
     string nextSession(string current);
 
 private:
     map<string,string> options;
+    vector<string> sessions;
+    int currentSession;
     string error;
 
 };
diff -uNbr --exclude=.svn release-1.2.6/const.h slim-pam/const.h
--- release-1.2.6/const.h	2006-01-08 15:35:03.000000000 +0100
+++ slim-pam/const.h	2007-05-17 16:38:53.000000000 +0200
@@ -26,15 +26,6 @@
 #define HIDE		0
 #define SHOW		1
 
-#define WAIT		0
-#define LOGIN		1
-#define FAIL		2
-#define CONSOLE		3
-#define REBOOT		4
-#define HALT		5
-#define EXIT		6
-#define SUSPEND		7
-
 #define GET_NAME    0
 #define GET_PASSWD	1
 
diff -uNbr --exclude=.svn release-1.2.6/panel.cpp slim-pam/panel.cpp
--- release-1.2.6/panel.cpp	2006-09-10 12:05:34.000000000 +0200
+++ slim-pam/panel.cpp	2007-05-19 21:26:29.000000000 +0200
@@ -76,7 +76,8 @@
         panelpng = themedir + "/panel.jpg";
         loaded = image->Read(panelpng.c_str());
         if (!loaded) {
-            cerr << APPNAME << ": could not load panel image for theme '"
+            cerr << APPNAME
+                 << ": could not load panel image for theme '"
 		 << basename((char*)themedir.c_str()) << "'"
 		 << endl;
             exit(ERR_EXIT);
@@ -92,7 +93,8 @@
             panelpng = themedir + "/background.jpg";
             loaded = bg->Read(panelpng.c_str());
             if (!loaded){
-                cerr << APPNAME << ": could not load background image for theme '"
+                cerr << APPNAME
+                     << ": could not load background image for theme '"
 		        << basename((char*)themedir.c_str()) << "'"
 		        << endl;
                 exit(ERR_EXIT);
@@ -106,12 +108,14 @@
     } else if (bgstyle == "center") {
  	    string hexvalue = cfg->getOption("background_color");
         hexvalue = hexvalue.substr(1,6);
-  	    bg->Center(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)),
+        bg->Center(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),
+                   XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)),
        			    hexvalue.c_str());
     } else { // plain color or error
 	    string hexvalue = cfg->getOption("background_color");
         hexvalue = hexvalue.substr(1,6);
-  	    bg->Center(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)),
+        bg->Center(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),
+                   XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)),
     			    hexvalue.c_str());
     }
 
@@ -128,9 +132,6 @@
     // Read (and substitute vars in) the welcome message
     welcome_message = cfg->getWelcomeMessage();
     intro_message = cfg->getOption("intro_msg");
-
-    // Init In
-    In = new Input(cfg);
 }
 
 Panel::~Panel() {
@@ -144,7 +145,6 @@
     XftFontClose(Dpy, introfont);
     XftFontClose(Dpy, welcomefont);
     XftFontClose(Dpy, enterfont);
-    delete In;
     delete image;
 
 }
@@ -182,7 +182,7 @@
 
 void Panel::ClearPanel() {
     session = "";
-    In->Reset();
+    Reset();
     XClearWindow(Dpy, Root);
     XClearWindow(Dpy, Win);
     Cursor(SHOW);
@@ -190,13 +190,13 @@
     XFlush(Dpy);
 }
 
-void Panel::Message(const char* text) {
+void Panel::Message(const string& text) {
     string cfgX, cfgY;
     XGlyphInfo extents;
     XftDraw *draw = XftDrawCreate(Dpy, Root,
                                   DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
-    XftTextExtents8(Dpy, msgfont, (XftChar8*)text,
-                    strlen(text), &extents);
+    XftTextExtents8(Dpy, msgfont, reinterpret_cast<const XftChar8*>(text.c_str()),
+                    text.length(), &extents);
     cfgX = cfg->getOption("msg_x");
     cfgY = cfg->getOption("msg_y");
     int shadowXOffset =
@@ -208,14 +208,14 @@
     int msg_y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height);
 
     SlimDrawString8 (draw, &msgcolor, msgfont, msg_x, msg_y,
-                     (XftChar8*)text, strlen(text),
+                     text,
                      &msgshadowcolor,
                      shadowXOffset, shadowYOffset);
     XFlush(Dpy);
     XftDrawDestroy(draw);
 }
 
-void Panel::Error(const char* text) {
+void Panel::Error(const string& text) {
     ClosePanel();
     Message(text);
     sleep(ERROR_DURATION);
@@ -224,10 +224,6 @@
 }
 
 
-Input* Panel::GetInput() {
-    return In;
-}
-
 unsigned long Panel::GetColor(const char* colorname) {
     XColor color;
     XWindowAttributes attributes;
@@ -244,31 +240,24 @@
 }
 
 void Panel::Cursor(int visible) {
-    char* text;
+    const char* text;
     int xx, yy, y2, cheight;
     char* txth = "Wj"; // used to get cursor height
 
-    switch(In->GetField()) {
-        case GET_PASSWD:
-            text = In->GetHiddenPasswd();
+    switch(field) {
+        case Get_Passwd:
+            text = HiddenPasswdBuffer.c_str();
             xx = input_pass_x;
             yy = input_pass_y;
             break;
 
-        case GET_NAME:
-            text = In->GetName();
+        case Get_Name:
+            text = NameBuffer.c_str();
             xx = input_name_x;
             yy = input_name_y;
             break;
-
-		default: /* Origin & NULL string as default values. */
-			text = (char *)NULL;
-			xx = (int)0;
-			yy = (int)0;
-			break;
     }
 
-
     XGlyphInfo extents;
     XftTextExtents8(Dpy, font, (XftChar8*)txth, strlen(txth), &extents);
     cheight = extents.height;
@@ -288,49 +277,53 @@
     }
 }
 
-int Panel::EventHandler(XEvent* event) {
-    Action = WAIT;
-
-    switch(event->type) {
+void Panel::EventHandler(const Panel::FieldType& curfield) {
+    XEvent event;
+    field=curfield;
+    bool loop = true;
+    OnExpose();
+    while(loop) {
+        XNextEvent(Dpy, &event);
+        switch(event.type) {
     case Expose:
-        OnExpose(event);
+                OnExpose();
         break;
 
     case KeyPress:
-        OnKeyPress(event);
+                loop=OnKeyPress(event);
         break;
     }
+    }
 
-    return Action;
+    return;
 }
 
-void Panel::OnExpose(XEvent* event) {
-    char* name = In->GetName();
-    char* passwd = In->GetHiddenPasswd();
+void Panel::OnExpose(void) {
     XftDraw *draw = XftDrawCreate(Dpy, Win,
                         DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
+    XClearWindow(Dpy, Win);
     if (input_pass_x != input_name_x || input_pass_y != input_name_y){
         SlimDrawString8 (draw, &inputcolor, font, input_name_x, input_name_y,
-                         (XftChar8*)name, strlen(name),
+                         NameBuffer,
                          &inputshadowcolor,
                          inputShadowXOffset, inputShadowYOffset);
         SlimDrawString8 (draw, &inputcolor, font, input_pass_x, input_pass_y,
-                         (XftChar8*)passwd, strlen(passwd),
+                         HiddenPasswdBuffer,
                          &inputshadowcolor,
                          inputShadowXOffset, inputShadowYOffset);
     } else { //single input mode
-        switch(In->GetField()) {
-            case GET_PASSWD:
+        switch(field) {
+            case Get_Passwd:
                 SlimDrawString8 (draw, &inputcolor, font,
                                  input_pass_x, input_pass_y,
-                                 (XftChar8*)passwd, strlen(passwd),
+                                 HiddenPasswdBuffer,
                                  &inputshadowcolor,
                                  inputShadowXOffset, inputShadowYOffset);
                 break;
-            case GET_NAME:
+            case Get_Name:
                 SlimDrawString8 (draw, &inputcolor, font,
                                  input_name_x, input_name_y,
-                                 (XftChar8*)name, strlen(name),
+                                 NameBuffer,
                                  &inputshadowcolor,
                                  inputShadowXOffset, inputShadowYOffset);
                 break;
@@ -342,108 +335,153 @@
     ShowText();
 }
 
-void Panel::OnKeyPress(XEvent* event) {
-    char del;
-    char buffer;
+bool Panel::OnKeyPress(XEvent& event) {
+    char ascii;
     KeySym keysym;
     XComposeStatus compstatus;
     int xx;
     int yy;
-    char* text;
-
-    bool singleInputMode =
-        input_name_x == input_pass_x &&
-        input_name_y == input_pass_y;
-    Cursor(HIDE);
-    XLookupString(&event->xkey, &buffer, 1, &keysym, &compstatus);
-    del = In->Key(buffer, keysym, singleInputMode);
-    Action = In->GetAction();
-
-    XGlyphInfo extents;
-    XftDraw *draw = XftDrawCreate(Dpy, Win,
-                                  DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
+    string text;
+    string formerString = "";
 
-    if (keysym == XK_F1) {
+    XLookupString(&event.xkey, &ascii, 1, &keysym, &compstatus);
+    switch(keysym){
+        case XK_F1:
         SwitchSession();
-    }
+            return true;
 
-    bool clearField = false;
-    string formerString = "";
-    if ((((XKeyEvent*)event)->state & ControlMask)) {
-        if (keysym == XK_w || keysym == XK_u) {
-            clearField = true;
-        }
-    }
+        case XK_F11:
+            // Take a screenshot
+            system(cfg->getOption("screenshot_cmd").c_str());
+            return true;
+
+        case XK_Return:
+        case XK_KP_Enter:
+            if (field==Get_Name){
+                // Don't allow an empty username
+                if (NameBuffer.empty()) return true;
+
+                if (NameBuffer==CONSOLE_STR){
+                    action = Console;
+                } else if (NameBuffer==HALT_STR){
+                    action = Halt;
+                } else if (NameBuffer==REBOOT_STR){
+                    action = Reboot;
+                } else if (NameBuffer==SUSPEND_STR){
+                    action = Suspend;
+                } else if (NameBuffer==EXIT_STR){
+                    action = Exit;
+                } else{
+                    action = Login;
+                }
+            };
+            return false;
+        default:
+            break;
+    };
 
-    switch(In->GetField()) {
+    Cursor(HIDE);
+    switch(keysym){
+        case XK_Delete:
+        case XK_BackSpace:
+            switch(field) {
+                case GET_NAME:
+                    if (! NameBuffer.empty()){
+                        formerString=NameBuffer;
+                        NameBuffer.erase(--NameBuffer.end());
+                    };
+                    break;
         case GET_PASSWD:
-            if (strlen(In->GetHiddenPasswd()) == 0){
-                // clear name and welcome label if we just entered the
-                // password field
-                if (singleInputMode) {
-                    xx = input_name_x;
-                    yy = input_name_y;
-                    text = In->GetName();
-                    XftTextExtents8(Dpy, font, (XftChar8*)text,
-                                    strlen(text), &extents);
-                    XClearWindow(Dpy, Win);
-                    ShowText();
-                }
-            }
+                    if (! PasswdBuffer.empty()){
+                        formerString=HiddenPasswdBuffer;
+                        PasswdBuffer.erase(--PasswdBuffer.end());
+                        HiddenPasswdBuffer.erase(--HiddenPasswdBuffer.end());
+                    };
+                    break;
+            };
+            break;
 
-            if (clearField) {
-                formerString = In->GetHiddenPasswd();
-                In->ResetPassword();
-            }
-            text = In->GetHiddenPasswd();
-            xx = input_pass_x;
-            yy = input_pass_y;
+        case XK_w:
+        case XK_u:
+            if (reinterpret_cast<XKeyEvent&>(event).state & ControlMask) {
+                switch(field) {
+                    case Get_Passwd:
+                        formerString = HiddenPasswdBuffer;
+                        HiddenPasswdBuffer.clear();
+                        PasswdBuffer.clear();
             break;
 
-        case GET_NAME:
-            if (clearField) {
-                formerString = In->GetName();
-                In->ResetName();
+                    case Get_Name:
+                        formerString = NameBuffer;
+                        NameBuffer.clear();
+                        break;
+                };
+                break;
             }
-            text = In->GetName();
+            // Deliberate fall-through
+        
+        default:
+            if (isprint(ascii) && (keysym < XK_Shift_L || keysym > XK_Hyper_R)){
+                switch(field) {
+                    case GET_NAME:
+                        formerString=NameBuffer;
+                        if (NameBuffer.length() < INPUT_MAXLENGTH_NAME-1){
+                            NameBuffer.append(&ascii,1);
+                        };
+                        break;
+                    case GET_PASSWD:
+                        formerString=HiddenPasswdBuffer;
+                        if (PasswdBuffer.length() < INPUT_MAXLENGTH_NAME-1){
+                            PasswdBuffer.append(&ascii,1);
+                            HiddenPasswdBuffer.append("*");
+                        };
+                    break;
+                };
+            };
+            break;
+    };
+
+    XGlyphInfo extents;
+    XftDraw *draw = XftDrawCreate(Dpy, Win,
+                                  DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
+
+   switch(field) {
+        case Get_Name:
+            text = NameBuffer;
             xx = input_name_x;
             yy = input_name_y;
             break;
 
-		default: /* Origin & NULL string as default values. */
-			text = (char *)NULL;
-			xx = (int)0;
-			yy = (int)0;
+        case Get_Passwd:
+            text = HiddenPasswdBuffer;
+            xx = input_pass_x;
+            yy = input_pass_y;
 			break;
     }
 
+    if (!formerString.empty()){
     char* txth = "Wj"; // get proper maximum height ?
-    XftTextExtents8(Dpy, font, (XftChar8*)txth, strlen(txth), &extents);
+        XftTextExtents8(Dpy, font, reinterpret_cast<const XftChar8*>(txth), strlen(txth), &extents);
     int maxHeight = extents.height;
 
-    string tmp = "";
-    if (clearField) {
-        tmp = formerString;
-    } else {
-        tmp = text;
-        tmp = tmp + del;
-    }
-    XftTextExtents8(Dpy, font, (XftChar8*)tmp.c_str(),
-                    strlen(tmp.c_str()), &extents);
+        XftTextExtents8(Dpy, font, reinterpret_cast<const XftChar8*>(formerString.c_str()),
+                        formerString.length(), &extents);
     int maxLength = extents.width;
 
     XClearArea(Dpy, Win, xx-3, yy-maxHeight-3,
                maxLength+6, maxHeight+6, false);
+    }
 
-    if (!clearField) {
+    if (!text.empty()) {
         SlimDrawString8 (draw, &inputcolor, font, xx, yy,
-                         (XftChar8*)text, strlen(text),
+                         text,
                          &inputshadowcolor,
                          inputShadowXOffset, inputShadowYOffset);
     }
 
     XftDrawDestroy (draw);
     Cursor(SHOW);
+    return true;
 }
 
 // Draw welcome and "enter username" message
@@ -471,14 +509,13 @@
     if (welcome_x >= 0 && welcome_y >= 0) {
         SlimDrawString8 (draw, &welcomecolor, welcomefont,
                          welcome_x, welcome_y,
-                         (XftChar8*)welcome_message.c_str(),
-                         strlen(welcome_message.c_str()),
+                         welcome_message,
                          &welcomeshadowcolor, shadowXOffset, shadowYOffset);
     }
 
     /* Enter username-password message */
     string msg;
-    if (!singleInputMode|| In->GetField() == GET_PASSWD ) {
+    if (!singleInputMode|| field == Get_Passwd ) {
         msg = cfg->getOption("password_msg");
         XftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(),
                         strlen(msg.c_str()), &extents);
@@ -492,11 +529,10 @@
         password_y = Cfg::absolutepos(cfgY, image->Height(), extents.height);
         if (password_x >= 0 && password_y >= 0){
             SlimDrawString8 (draw, &entercolor, enterfont, password_x, password_y,
-                             (XftChar8*)msg.c_str(), strlen(msg.c_str()),
-                             &entershadowcolor, shadowXOffset, shadowYOffset);
+                             msg, &entershadowcolor, shadowXOffset, shadowYOffset);
         }
     }
-    if (!singleInputMode|| In->GetField() == GET_NAME ) {
+    if (!singleInputMode|| field == Get_Name ) {
         msg = cfg->getOption("username_msg");
         XftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(),
                         strlen(msg.c_str()), &extents);
@@ -510,8 +546,7 @@
         username_y = Cfg::absolutepos(cfgY, image->Height(), extents.height);
         if (username_x >= 0 && username_y >= 0){
             SlimDrawString8 (draw, &entercolor, enterfont, username_x, username_y,
-                             (XftChar8*)msg.c_str(), strlen(msg.c_str()),
-                             &entershadowcolor, shadowXOffset, shadowYOffset);
+                             msg, &entershadowcolor, shadowXOffset, shadowYOffset);
         }
     }
     XftDrawDestroy(draw);
@@ -524,29 +559,29 @@
 // choose next available session type
 void Panel::SwitchSession() {
     session = cfg->nextSession(session);
-    //TODO: get sessions from cfg and cycle to the next one
+    if (session.size() > 0) {
     ShowSession();
+    }
 }
 
 // Display session type on the screen
 void Panel::ShowSession() {
     XClearWindow(Dpy, Root);
     string currsession = "Session: " + session;
-    char* text = (char*) currsession.c_str();
     XGlyphInfo extents;
     XftDraw *draw = XftDrawCreate(Dpy, Root,
                                   DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
-    XftTextExtents8(Dpy, msgfont, (XftChar8*)text,
-                    strlen(text), &extents);
+    XftTextExtents8(Dpy, msgfont, reinterpret_cast<const XftChar8*>(currsession.c_str()),
+                    currsession.length(), &extents);
     int msg_x = Cfg::absolutepos("50%", XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.width);
     int msg_y = XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)) - extents.height -100;
     int shadowXOffset =
-        Cfg::string2int(cfg->getOption("welcome_shadow_xoffset").c_str());
+        Cfg::string2int(cfg->getOption("msg_shadow_xoffset").c_str());
     int shadowYOffset =
-        Cfg::string2int(cfg->getOption("welcome_shadow_yoffset").c_str());
+        Cfg::string2int(cfg->getOption("msg_shadow_yoffset").c_str());
 
     SlimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y,
-                    (XftChar8*)text, strlen(text),
+                    currsession, 
                     &msgshadowcolor,
                     shadowXOffset, shadowYOffset);
     XFlush(Dpy);
@@ -555,13 +590,44 @@
 
 
 void Panel::SlimDrawString8(XftDraw *d, XftColor *color, XftFont *font,
-                            int x, int y, XftChar8 *string, int len,
+                            int x, int y, const string& str,
                             XftColor* shadowColor,
                             int xOffset, int yOffset)
 {
     if (xOffset && yOffset) {
         XftDrawString8(d, shadowColor, font, x+xOffset, y+yOffset,
-                       string, len);
+                       reinterpret_cast<const FcChar8*>(str.c_str()), str.length());
     }
-    XftDrawString8(d, color, font, x, y, string, len);
+    XftDrawString8(d, color, font, x, y, reinterpret_cast<const FcChar8*>(str.c_str()), str.length());
 }
+
+
+Panel::ActionType Panel::getAction(void) const{
+    return action;
+};
+
+
+void Panel::Reset(void){
+    ResetName();
+    ResetPasswd();
+};
+
+void Panel::ResetName(void){
+    NameBuffer.clear();
+};
+
+void Panel::ResetPasswd(void){
+    PasswdBuffer.clear();
+    HiddenPasswdBuffer.clear();
+};
+
+void Panel::SetName(const string& name){
+    NameBuffer=name;
+    return;
+};
+const string& Panel::GetName(void) const{
+    return NameBuffer;
+};
+const string& Panel::GetPasswd(void) const{
+    return PasswdBuffer;
+};
diff -uNbr --exclude=.svn release-1.2.6/panel.h slim-pam/panel.h
--- release-1.2.6/panel.h	2006-08-18 19:21:59.000000000 +0200
+++ slim-pam/panel.h	2007-05-17 16:38:53.000000000 +0200
@@ -13,49 +13,71 @@
 #define _PANEL_H_
 
 #include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/Xft/Xft.h>
 #include <X11/cursorfont.h>
 #include <X11/Xmu/WinUtil.h>
 #include <sys/wait.h>
 #include <stdlib.h>
 #include <signal.h>
 #include <iostream>
+#include <string>
 
 #ifdef NEEDS_BASENAME
 #include <libgen.h>
 #endif
 
 #include "switchuser.h"
-#include "input.h"
 #include "const.h"
 #include "image.h"
 
 
 class Panel {
 public:
+    enum ActionType {
+        Login,
+        Console,
+        Reboot,
+        Halt,
+        Exit,
+        Suspend
+    };
+    enum FieldType {
+        Get_Name,
+        Get_Passwd
+    };
+
+
     Panel(Display* dpy, int scr, Window root, Cfg* config,
           const string& themed);
     ~Panel();
     void OpenPanel();
     void ClosePanel();
     void ClearPanel();
-    void Message(const char* text);
-    void Error(const char* text);
-    Input* GetInput();
-    int EventHandler(XEvent* event);
+    void Message(const string& text);
+    void Error(const string& text);
+    void EventHandler(const FieldType& curfield);
     string getSession();
+    ActionType getAction(void) const;
 
+    void Reset(void);
+    void ResetName(void);
+    void ResetPasswd(void);
+    void SetName(const string& name);
+    const string& GetName(void) const;
+    const string& GetPasswd(void) const;
 private:
     Panel();
     void Cursor(int visible);
     unsigned long GetColor(const char* colorname);
-    void OnExpose(XEvent* event);
-    void OnKeyPress(XEvent* event);
+    void OnExpose(void);
+    bool OnKeyPress(XEvent& event);
     void ShowText();
     void SwitchSession();
     void ShowSession();
 
-    void SlimDrawString8(XftDraw* d, XftColor* color, XftFont* font,
-                         int x, int y, XftChar8 *string, int len,
+    void SlimDrawString8(XftDraw *d, XftColor *color, XftFont *font,
+                            int x, int y, const string& str,
                          XftColor* shadowColor,
                          int xOffset, int yOffset);
 
@@ -82,7 +104,13 @@
     XftFont* enterfont;
     XftColor entercolor;
     XftColor entershadowcolor;
-    int Action;
+    ActionType action;
+    FieldType field;
+    
+    // Username/Password
+    string NameBuffer;
+    string PasswdBuffer;
+    string HiddenPasswdBuffer;
 
     // Configuration
     int input_name_x;
@@ -110,9 +138,6 @@
     // Pixmap data
     Pixmap PanelPixmap;
 
-    // Name/Passwd handler
-    Input* In;
-
     Image* image;
 
     // For thesting themes
diff -uNbr --exclude=.svn release-1.2.6/switchuser.cpp slim-pam/switchuser.cpp
--- release-1.2.6/switchuser.cpp	2006-08-18 19:10:29.000000000 +0200
+++ slim-pam/switchuser.cpp	2007-05-19 21:26:29.000000000 +0200
@@ -13,10 +13,12 @@
 
 using namespace std;
 
-SwitchUser::SwitchUser(struct passwd *pw, Cfg *c, const string& display)
+SwitchUser::SwitchUser(struct passwd *pw, Cfg *c, const string& display,
+                       char** _env)
     : cfg(c),
       Pw(pw),
-      displayName(display)
+      displayName(display),
+      env(_env)
 {
 }
 
@@ -27,33 +29,12 @@
 
 
 void SwitchUser::Login(const char* cmd, const char* mcookie) {
-    SetEnvironment();
     SetUserId();
     SetClientAuth(mcookie);
     Execute(cmd);
 }
 
 
-void SwitchUser::SetEnvironment() {
-    char *term = getenv("TERM");
-    char** environ;
-    environ = (char **) new char*[2];
-    environ[0] = 0;
-    if(term)
-        putenv(StrConcat("TERM=", term));
-    putenv(StrConcat("HOME=", Pw->pw_dir));
-    putenv(StrConcat("SHELL=", Pw->pw_shell));
-    putenv(StrConcat("USER=", Pw->pw_name));
-    putenv(StrConcat("LOGNAME=", Pw->pw_name));
-    putenv(StrConcat("PATH=", cfg->getOption("default_path").c_str()));
-    putenv(StrConcat("DISPLAY=", displayName.c_str()));
-    putenv(StrConcat("MAIL="_PATH_MAILDIR"/", Pw->pw_name));
-    putenv(StrConcat("XAUTHORITY=", StrConcat(Pw->pw_dir,"/.Xauthority")));
-    /* putenv("XAUTHORITY=/tmp/serverauth"); */
-    chdir(Pw->pw_dir);
-}
-
-
 void SwitchUser::SetUserId() {
     if( (Pw == 0) ||
             (initgroups(Pw->pw_name, Pw->pw_gid) != 0) ||
@@ -66,42 +47,11 @@
 
 
 void SwitchUser::Execute(const char* cmd) {
-    char *args[4];
-    char* shell = strdup(Pw->pw_shell);
-    char *shell_basename = BaseName(shell);
-
-    args[0] = new char[strlen(shell_basename) + 2];
-    strcpy(args[0], "-");
-    strcat(args[0], shell_basename);
-    args[1] = "-c";
-    args[2] = (char*)cmd;
-    args[3] = 0;
-
-    execv(shell, args);
+    chdir(Pw->pw_dir);
+    execle(Pw->pw_shell, Pw->pw_shell, "-c", cmd, NULL, env);
     cerr << APPNAME << ": could not execute login command" << endl;
 }
 
-
-char* SwitchUser::BaseName(const char* name) {
-    const char *base = name;
-
-    while(*name) {
-        if(*name == '/')
-            base = name + 1;
-        ++name;
-    }
-
-    return (char*) base;
-}
-
-
-char* SwitchUser::StrConcat(const char* str1, const char* str2) {
-    char* tmp = new char[strlen(str1) + strlen(str2) + 1];
-    strcpy(tmp, str1);
-    strcat(tmp, str2);
-    return tmp;
-}
-
 void SwitchUser::SetClientAuth(const char* mcookie) {
     int r;
     string home = string(Pw->pw_dir);
diff -uNbr --exclude=.svn release-1.2.6/switchuser.h slim-pam/switchuser.h
--- release-1.2.6/switchuser.h	2006-07-15 02:33:52.000000000 +0200
+++ slim-pam/switchuser.h	2007-05-19 21:26:29.000000000 +0200
@@ -25,7 +25,8 @@
 
 class SwitchUser {
 public:
-    SwitchUser(struct passwd *pw, Cfg *c, const std::string& display);
+    SwitchUser(struct passwd *pw, Cfg *c, const std::string& display,
+               char** _env);
     ~SwitchUser();
     void Login(const char* cmd, const char* mcookie);
 
@@ -34,13 +35,12 @@
     void SetEnvironment();
     void SetUserId();
     void Execute(const char* cmd);
-    char* BaseName(const char* name);
-    char* StrConcat(const char* str1, const char* str2);
     void SetClientAuth(const char* mcookie);
     Cfg* cfg;
     struct passwd *Pw;
 
     std::string displayName;
+    char** env;
 };
 
 


Index: slim.spec
===================================================================
RCS file: /cvs/pkgs/rpms/slim/F-7/slim.spec,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- slim.spec	3 Sep 2007 19:37:32 -0000	1.2
+++ slim.spec	24 Sep 2007 19:52:58 -0000	1.3
@@ -1,6 +1,6 @@
 Name:           slim
 Version:        1.2.6
-Release:        6%{?dist}
+Release:        7%{?dist}
 Summary:        Simple Login Manager
 
 Group:          User Interface/X
@@ -17,6 +17,7 @@
 Patch0:         slim-1.2.6-make.patch
 Patch1:         slim-1.2.6-usexwd.patch
 Patch2:         slim-1.2.6-fedora.patch
+Patch3:         slim-1.2.6-pam.patch
 
 BuildRequires:  libXmu-devel libXft-devel libXrender-devel
 BuildRequires:  libpng-devel libjpeg-devel freetype-devel fontconfig-devel
@@ -46,9 +47,10 @@
 %patch2 -p1 -b .fedora
 sed -e 's@/usr/X11R6/bin@%{_bindir}@g' -i.orig slim.conf
 cp -p %{SOURCE3} README.Fedora
+%patch3 -p1 -b .pam
 
 %build
-make %{?_smp_mflags} OPTFLAGS="$RPM_OPT_FLAGS"
+make %{?_smp_mflags} OPTFLAGS="$RPM_OPT_FLAGS" USE_PAM=1
 
 %install
 rm -rf $RPM_BUILD_ROOT
@@ -96,6 +98,10 @@
 
 
 %changelog
+* Mon Sep 24 2007 Anders F Bjorklund <afb at users.sourceforge.net> 1.2.6-7
+- backport PAM support from "slim-pam" branch, USE_PAM=1
+- backport fix for segfault on exit when testing themes.
+
 * Mon Aug  6 2007 Anders F Bjorklund <afb at users.sourceforge.net> 1.2.6-6
 - require system-logos instead of fedora-logos (#250365)
 




More information about the fedora-extras-commits mailing list