#!/usr/bin/env python

import xml.parsers.expat as expat
import os
import gobject
import dbus
import sys
import logging

logging.basicConfig (level=logging.ERROR, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', stream=sys.stderr)
log = logging.getLogger ("nx-session-launcher")
log.debug ("Starting nx-session-launcher")

# Getting the system dbus
bus = dbus.SystemBus ()

USE_PK_CREDENTIALS = False

# ------------------- ConsoleKit integration ------------------------

# Getting the ConsoleKit object
ck_manager_obj = bus.get_object ('org.freedesktop.ConsoleKit', '/org/freedesktop/ConsoleKit/Manager')
ck_manager = dbus.Interface (ck_manager_obj, 'org.freedesktop.ConsoleKit.Manager')
objs = ck_manager.GetSeats ()

nx_create_session = os.getenv('NX_CREATE_CK_SESSION')
create_session = True
if nx_create_session == "false":
    create_session = False

nx_session_type = os.getenv('NX_SESSION_TYPE')
if nx_session_type == None:
    nx_session_type = "nx"
display = os.getenv('DISPLAY')

# Get the current session
current_cookie = os.getenv('XDG_SESSION_COOKIE')
current_session = None
if current_cookie != None:
    current_session = ck_manager.GetSessionForCookie (current_cookie)

def takeOwnership():
    log.debug ("NX_CREATE_CK_SESSION = " + current_cookie)
    log.debug ("Not creating a CK session")
    
    session_obj = bus.get_object ('org.freedesktop.ConsoleKit', current_session)
    session = dbus.Interface (session_obj, 'org.freedesktop.ConsoleKit.Session')
    
    properties = dbus.Interface (session_obj, 'org.freedesktop.DBus.Properties')
    try:
        properties.Set ("org.freedesktop.DBus.Properties", "active", dbus.Boolean (True, variant_level=1))
        properties.Set ("org.freedesktop.DBus.Properties", "is-local", dbus.Boolean (True, variant_level=1))
        properties.Set ("org.freedesktop.DBus.Properties", "session-type", dbus.String (nx_session_type, variant_level=1))
        if display != None:
            properties.Set ("org.freedesktop.DBus.Properties", "x11-display", dbus.String (display, variant_level=1))
        log.debug ("Ownership taken")
        return True
    except expat.ExpatError, e:
        error_string = str(e)
        log.error ("Error: " + error_string)
        log.error ("Falling back to create a new session")
        return False
    except dbus.DBusException, e:
        error_string = str(e)
        log.error ("Error: " + error_string)
        log.error ("Falling back to create a new session")
        return False
    except Exception, e:
        error_string = str(e)
        log.error ("Error: " + error_string)
        log.error ("Falling back to create a new session")
        return False

def createSession():
    try:
        # Defining the session attributes
        params = dbus.Array ([], signature = "(sv)")
        params.append (("unix-user", dbus.Int32 (os.getuid(), variant_level=1)))
        params.append (("session-type", dbus.String (nx_session_type, variant_level=1)))
        if display != None:
            params.append (("x11-display", dbus.String (display, variant_level=1)))
        params.append (("is-local", dbus.Boolean (True, variant_level=1)))
        
        # Create the ConsoleKit session
        cookie = ck_manager.OpenSessionWithParameters (params)
        log.debug ("Session " + cookie + " created")
        
        # Exporting the XDG_SESSION_COOKIE variable
        os.environ['XDG_SESSION_COOKIE'] = cookie
        
        # Getting the ConsoleKit session
        current_session = ck_manager.GetSessionForCookie (cookie)
        session_obj = bus.get_object ('org.freedesktop.ConsoleKit', current_session)
        session = dbus.Interface (session_obj, 'org.freedesktop.ConsoleKit.Session')
        
        # Setting the session as active
        properties = dbus.Interface (session_obj, 'org.freedesktop.DBus.Properties')
        properties.Set ("org.freedesktop.DBus.Properties", "active", dbus.Boolean (True, variant_level=1))
         
    except dbus.DBusException, e:
        # Dbus error problably you don't have the dbus rule installed or your launcher is not suid nx
        # Open session without the parameters
        log.error ("Failed to create a CK session using parameters")
        
        error_string = str(e)
        log.error ("Error: " + error_string)
        
        # Create the ConsoleKit session
        cookie = ck_manager.OpenSession ()
        log.debug ("Session " + cookie + " created")
        
        # Exporting the XDG_SESSION_COOKIE variable
        os.environ['XDG_SESSION_COOKIE'] = cookie

def checkPermission ():
    if USE_PK_CREDENTIALS == False:
        return True
    
    policykit = bus.get_object ('org.freedesktop.PolicyKit', '/', "org/freedesktop/PolicyKit")
    
    if(policykit == None):
        log.error ("Error: Could not get PolicyKit D-Bus Interface\n")
    else:
        polkit_interface = dbus.Interface (policykit, 'org.freedesktop.PolicyKit')
        
        try:
            granted = polkit_interface.IsProcessAuthorized ("freenx.session.create", os.getpid(), "false")
            
            if granted == "yes":
                return True
            else:
                return False
            
        except dbus.DBusException, e :
            # Dbus error problably you don't have the PolicyKit rule installed
            error_string = str(e)
            log.error ("Error: " + error_string)


if create_session and ( current_session == None or not takeOwnership () ):
     log.debug("Creating a new session")
     createSession ()
     pid = os.fork ()
     if pid == -1:
         log.rrror ("error forking child")
     elif pid == 0:
         log.debug ("Forked")
     else:
         # Parent
         status = os.waitpid (pid, 0)
         os._exit (0)

if os.geteuid () != os.getuid ():
    # Drop setuid privilege
    os.setreuid(os.getuid(), os.getuid())
    
    os.environ ['NX_CREATE_CK_SESSION'] = "false"
    
    # Reexecute this script to really drop euid privilege
#    os.spawnvp (os.P_WAIT, sys.argv[0], sys.argv)
#    sys.exit()

args = sys.argv
args.pop(0)
log.info ("Launching the program\n")
if checkPermission ():
    os.execvp(args[0], args)
else:
    log.error ("You don't have permission to execute the action\n")

