Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# This file is part of Xpra. 

2# Copyright (C) 2017-2020 Antoine Martin <antoine@xpra.org> 

3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any 

4# later version. See the file COPYING for details. 

5 

6import os 

7from subprocess import Popen 

8from gi.repository import GLib 

9 

10from xpra.util import envint, typedict 

11from xpra.os_util import OSX 

12from xpra.child_reaper import getChildReaper 

13from xpra.server.auth.sys_auth_base import SysAuthenticator, log 

14from xpra.platform.features import EXECUTABLE_EXTENSION 

15 

16TIMEOUT = envint("XPRA_EXEC_AUTH_TIMEOUT", 600) 

17 

18 

19class Authenticator(SysAuthenticator): 

20 

21 def __init__(self, username, **kwargs): 

22 log("exec.Authenticator(%s, %s)", username, kwargs) 

23 self.command = kwargs.pop("command", "") 

24 self.timeout = kwargs.pop("timeout", TIMEOUT) 

25 self.timer = None 

26 self.proc = None 

27 self.timeout_event = False 

28 if not self.command: 

29 #try to find the default auth_dialog executable: 

30 from xpra.platform.paths import get_libexec_dir 

31 libexec = get_libexec_dir() 

32 xpralibexec = os.path.join(libexec, "xpra") 

33 log("libexec=%s, xpralibexec=%s", libexec, xpralibexec) 

34 if os.path.exists(xpralibexec) and os.path.isdir(xpralibexec): 

35 libexec = xpralibexec 

36 auth_dialog = os.path.join(libexec, "auth_dialog") 

37 if EXECUTABLE_EXTENSION: 

38 #ie: add ".exe" on MS Windows 

39 auth_dialog += ".%s" % EXECUTABLE_EXTENSION 

40 log("auth_dialog=%s", auth_dialog) 

41 if os.path.exists(auth_dialog): 

42 self.command = auth_dialog 

43 assert self.command, "exec authentication module is not configured correctly: no command specified" 

44 connection = kwargs.get("connection") 

45 log("exec connection info: %s", connection) 

46 assert connection, "connection object is missing" 

47 self.connection_str = str(connection) 

48 super().__init__(username, **kwargs) 

49 

50 def requires_challenge(self) -> bool: 

51 return False 

52 

53 def authenticate(self, caps : typedict) -> bool: 

54 info = "Connection request from %s" % self.connection_str 

55 cmd = [self.command, info, str(self.timeout)] 

56 proc = Popen(cmd) 

57 self.proc = proc 

58 log("authenticate(..) Popen(%s)=%s", cmd, proc) 

59 #if required, make sure we kill the command when it times out: 

60 if self.timeout>0: 

61 self.timer = GLib.timeout_add(self.timeout*1000, self.command_timedout) 

62 if not OSX: 

63 #python on macos may set a 0 returncode when we use poll() 

64 #so we cannot use the ChildReaper on macos, 

65 #and we can't cancel the timer 

66 getChildReaper().add_process(proc, "exec auth", cmd, True, True, self.command_ended) 

67 v = proc.wait() 

68 log("authenticate(..) returncode(%s)=%s", cmd, v) 

69 if self.timeout_event: 

70 return False 

71 return v==0 

72 

73 def command_ended(self, *args): 

74 t = self.timer 

75 log("exec auth.command_ended%s timer=%s", args, t) 

76 if t: 

77 self.timer = None 

78 GLib.source_remove(t) 

79 

80 def command_timedout(self): 

81 proc = self.proc 

82 log("exec auth.command_timedout() proc=%s", proc) 

83 self.timeout_event = True 

84 self.timer = None 

85 if proc: 

86 try: 

87 proc.terminate() 

88 except: 

89 log("error trying to terminate exec auth process %s", proc, exc_info=True) 

90 

91 def __repr__(self): 

92 return "exec"