def cbLoggedIn(e, config): mail = only(e, config.getLDAPAttributeMailbox()) username = mail.split('@', 1)[0] hostname = mail.split('@', 1)[1] username = quot(username) hostname = quot(hostname) userpad = (username+'__')[:2] mailhost = only(e, config.getLDAPAttributeMailHost()) userdir = os.path.join( config.getSpool(), hostname, mailhost, userpad) switchUID(uid=pwd.getpwnam('scalemail')[2], gid=grp.getgrnam('scalemail')[2]) if not os.path.isdir(userdir): os.mkdir(userdir, 0700) os.chdir(userdir) if not os.path.isdir(username): initializeMaildir(username) os.chdir(username) os.execlp(sys.argv[1], *sys.argv[1:]) print >>sys.stderr, "scalemail-courier-login: Cannot exec command." sys.exit(2)
def _execChild(self, path, settingUID, uid, gid, command, args, environment): if path: os.chdir(path) # set the UID before I actually exec the process if settingUID: switchUID(uid, gid) os.execvpe(command, args, environment)
def _execChild(self, path, settingUID, uid, gid, command, args, environment): if path: os.chdir(path) if settingUID: switchUID(uid, gid) os.execvpe(command, args, environment)
def test_uid(self): """ L{util.switchUID} calls L{util.initgroups} and then C{os.setuid} with the given uid. """ util.switchUID(12000, None) self.assertEqual(self.initgroupsCalls, [(12000, None)]) self.assertEqual(self.mockos.actions, [("setuid", 12000)])
def test_euid(self): """ L{util.switchUID} calls L{util.initgroups} and then C{os.seteuid} with the given uid if the C{euid} parameter is set to C{True}. """ util.switchUID(12000, None, True) self.assertEqual(self.initgroupsCalls, [(12000, None)]) self.assertEqual(self.mockos.seteuidCalls, [12000])
def main(): usage = "%prog [options] ACTION" epilog = """ ACTION is one of add|modify|remove|print add: add a user record modify: modify a user record remove: remove a user record """ description = "Tool to manipulate CalendarServer augments XML file" version = "%prog v1.0" parser = OptionParser(usage=usage, description=description, version=version) parser.epilog = epilog parser.format_epilog = lambda _:epilog parser.add_option("-f", "--file", dest="configfilename", help="caldavd.plist defining Augment Service", metavar="FILE") parser.add_option("-u", "--uid", dest="uid", help="OD GUID to manipulate", metavar="UID") parser.add_option("-i", "--uidfile", dest="uidfile", help="File containing a list of GUIDs to manipulate", metavar="UIDFILE") parser.add_option("-n", "--node", dest="node", help="Partition node to assign to UID", metavar="NODE") parser.add_option("-c", "--enable-calendar", action="store_true", dest="enable_calendar", default=True, help="Enable calendaring for this UID: %default") parser.add_option("-a", "--enable-addressbooks", action="store_true", dest="enable_addressbook", default=True, help="Enable calendaring for this UID: %default") parser.add_option("-s", "--auto-schedule", action="store_true", dest="auto_schedule", default=False, help="Enable auto-schedule for this UID: %default") (options, args) = parser.parse_args() if len(args) != 1: parser.error("incorrect number of arguments") observer = StandardIOObserver() observer.start() # # Get configuration # try: loadConfig(options.configfilename) setLogLevelForNamespace(None, "warn") # Shed privileges if config.UserName and config.GroupName and os.getuid() == 0: uid = getpwnam(config.UserName).pw_uid gid = getgrnam(config.GroupName).gr_gid switchUID(uid, uid, gid) os.umask(config.umask) config.directory = getDirectory() autoDisableMemcached(config) except ConfigurationError, e: usage("Unable to start: %s" % (e,))
def switchUID(uid, gid): """ Switch uid and gid to what the user has specified on the command line. """ if uid: uid = util.uidFromString(uid) if gid: gid = util.gidFromString(gid) util.switchUID(uid, gid)
def _execChild(self, path, settingUID, uid, gid, executable, args, environment): """ The exec() which is done in the forked child. """ if path: os.chdir(path) # set the UID before I actually exec the process if settingUID: switchUID(uid, gid) os.execvpe(executable, args, environment)
def run(): import traceback from twisted.trial import util try: cfg = config.ScalemailConfig() authfile = os.fdopen(3, 'r') service = authfile.readline().rstrip() authtype = authfile.readline().rstrip() authdata = authfile.read() authfile.close() try: d = main(config=cfg, argv=sys.argv, env=os.environ, service=service, authtype=authtype, authdata=authdata) r = util.wait(d, timeout=60.0) userdir, username = r switchUID(uid=pwd.getpwnam('scalemail')[2], gid=grp.getgrnam('scalemail')[2]) if not os.path.isdir(userdir): os.mkdir(userdir, 0700) os.chdir(userdir) if not os.path.isdir(username): initializeMaildir(username) os.chdir(username) os.execlp(sys.argv[1], *sys.argv[1:]) die("Something is very wrong") except (error.UnauthorizedLogin, ChainLogin): # TODO pass on authinfo os.execlp(sys.argv[1], *sys.argv[1:]) die("Something is very wrong") except RetryLogin: # TODO pass on authinfo l = [] argc = int(os.environ['AUTHARGC']) for i in range(argc): l.append(os.environ['AUTHARGV%d' % i]) os.execlp(*l) die("Something is very wrong") except SystemExit: raise except: try: traceback.print_exc(file=sys.stderr) finally: sys.exit(EX_TEMPFAIL)
def test_currentEUID(self): """ If the current euid is the same as the euid passed to L{util.switchUID}, then initgroups does not get called, but a warning is issued. """ euid = self.mockos.geteuid() util.switchUID(euid, None, True) self.assertEqual(self.initgroupsCalls, []) self.assertEqual(self.mockos.seteuidCalls, []) warnings = self.flushWarnings([util.switchUID]) self.assertEqual(len(warnings), 1) self.assertIn("tried to drop privileges and seteuid %i" % euid, warnings[0]["message"]) self.assertIn("but euid is already %i" % euid, warnings[0]["message"])
def test_currentUID(self): """ If the current uid is the same as the uid passed to L{util.switchUID}, then initgroups does not get called, but a warning is issued. """ uid = self.mockos.getuid() util.switchUID(uid, None) self.assertEqual(self.initgroupsCalls, []) self.assertEqual(self.mockos.actions, []) warnings = self.flushWarnings([util.switchUID]) self.assertEqual(len(warnings), 1) self.assertIn('tried to drop privileges and setuid %i' % uid, warnings[0]['message']) self.assertIn('but uid is already %i' % uid, warnings[0]['message'])
def test_currentEUID(self): """ If the current euid is the same as the euid passed to L{util.switchUID}, then initgroups does not get called, but a warning is issued. """ euid = self.mockos.geteuid() util.switchUID(euid, None, True) self.assertEqual(self.initgroupsCalls, []) self.assertEqual(self.mockos.seteuidCalls, []) warnings = self.flushWarnings([util.switchUID]) self.assertEqual(len(warnings), 1) self.assertIn('tried to drop privileges and seteuid %i' % euid, warnings[0]['message']) self.assertIn('but euid is already %i' % euid, warnings[0]['message'])
def test_currentUID(self): """ If the current uid is the same as the uid passed to L{util.switchUID}, then initgroups does not get called, but a warning is issued. """ uid = self.mockos.getuid() util.switchUID(uid, None) self.assertEqual(self.initgroupsCalls, []) self.assertEqual(self.mockos.actions, []) currentWarnings = self.flushWarnings([util.switchUID]) self.assertEqual(len(currentWarnings), 1) self.assertIn( "tried to drop privileges and setuid %i" % uid, currentWarnings[0]["message"], ) self.assertIn("but uid is already %i" % uid, currentWarnings[0]["message"])
def _execChild(self, path, uid, gid, executable, args, environment): """ The exec() which is done in the forked child. """ if path: os.chdir(path) if uid is not None or gid is not None: if uid is None: uid = os.geteuid() if gid is None: gid = os.getegid() # set the UID before I actually exec the process os.setuid(0) os.setgid(0) switchUID(uid, gid) os.execvpe(executable, args, environment)
def shedPrivileges(self, euid, uid, gid): """ Change the UID and GID or the EUID and EGID of this process. @type euid: C{bool} @param euid: A flag which, if set, indicates that only the I{effective} UID and GID should be set. @type uid: C{int} or C{NoneType} @param uid: If not C{None}, the UID to which to switch. @type gid: C{int} or C{NoneType} @param gid: If not C{None}, the GID to which to switch. """ if uid is not None or gid is not None: switchUID(uid, gid, euid) extra = euid and 'e' or '' log.msg('set %suid/%sgid %s/%s' % (extra, extra, uid, gid))
def shared_main(configFileName, method, *args, **kwds): try: loadConfig(configFileName) # Shed privileges if config.UserName and config.GroupName and os.getuid() == 0: uid = getpwnam(config.UserName).pw_uid gid = getgrnam(config.GroupName).gr_gid switchUID(uid, uid, gid) os.umask(config.umask) try: rootResource = getRootResource(config) directory = rootResource.getDirectory() except DirectoryError, e: print "Error: %s" % (e,) return setupMemcached(config) setupNotifications(config)
def shedPrivileges(self, euid, uid, gid): """ Change the UID and GID or the EUID and EGID of this process. @type euid: C{bool} @param euid: A flag which, if set, indicates that only the I{effective} UID and GID should be set. @type uid: C{int} or C{NoneType} @param uid: If not C{None}, the UID to which to switch. @type gid: C{int} or C{NoneType} @param gid: If not C{None}, the GID to which to switch. """ if uid is not None or gid is not None: extra = euid and 'e' or '' desc = '%suid/%sgid %s/%s' % (extra, extra, uid, gid) try: switchUID(uid, gid, euid) except OSError: log.msg('failed to set %s (are you root?) -- exiting.' % desc) sys.exit(1) else: log.msg('set %s' % desc)
observer = StandardIOObserver() observer.start() # # Get configuration # try: loadConfig(configFileName) setLogLevelForNamespace(None, "warn") # Shed privileges if config.UserName and config.GroupName and os.getuid() == 0: uid = getpwnam(config.UserName).pw_uid gid = getgrnam(config.GroupName).gr_gid switchUID(uid, uid, gid) os.umask(config.umask) config.directory = getDirectory() autoDisableMemcached(config) except ConfigurationError, e: usage("Unable to start: %s" % (e,)) try: dbxml = AugmentXMLDB((xmlFileName,)) if not remove else None except IOError, e: usage("Could not read XML augment file: %s" % (e,)) # # Start the reactor
def __init__(self, reactor, command, args, environment, path, proto, uid=None, gid=None, usePTY=None): """Spawn an operating-system process. This is where the hard work of disconnecting all currently open files / forking / executing the new process happens. (This is executed automatically when a Process is instantiated.) This will also run the subprocess as a given user ID and group ID, if specified. (Implementation Note: this doesn't support all the arcane nuances of setXXuid on UNIX: it will assume that either your effective or real UID is 0.) """ if not pty and type(usePTY) not in (types.ListType, types.TupleType): raise NotImplementedError, "cannot use PTYProcess on platforms without the pty module." abstract.FileDescriptor.__init__(self, reactor) settingUID = (uid is not None) or (gid is not None) if settingUID: curegid = os.getegid() currgid = os.getgid() cureuid = os.geteuid() curruid = os.getuid() if uid is None: uid = cureuid if gid is None: gid = curegid os.setuid(0) os.setgid(0) if type(usePTY) in (types.TupleType, types.ListType): masterfd, slavefd, ttyname = usePTY else: masterfd, slavefd = pty.openpty() ttyname = os.ttyname(slavefd) pid = os.fork() self.pid = pid if pid == 0: # pid is 0 in the child process try: sys.settrace(None) os.close(masterfd) if hasattr(termios, 'TIOCNOTTY'): try: fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY) except OSError: pass else: try: fcntl.ioctl(fd, termios.TIOCNOTTY, '') except: pass os.close(fd) os.setsid() if hasattr(termios, 'TIOCSCTTY'): fcntl.ioctl(slavefd, termios.TIOCSCTTY, '') for fd in range(3): if fd != slavefd: os.close(fd) os.dup2(slavefd, 0) # stdin os.dup2(slavefd, 1) # stdout os.dup2(slavefd, 2) # stderr if path: os.chdir(path) for fd in range(3, 256): try: os.close(fd) except: pass if settingUID: switchUID(uid, gid) os.execvpe(command, args, environment) except: stderr = os.fdopen(1, 'w') stderr.write("Upon execvpe %s %s in environment %s:\n" % (command, str(args), "id %s" % id(environment))) traceback.print_exc(file=stderr) stderr.flush() os._exit(1) assert pid!=0 os.close(slavefd) fdesc.setNonBlocking(masterfd) self.fd=masterfd self.startReading() self.connected = 1 self.proto = proto self.lostProcess = 0 self.status = -1 try: self.proto.makeConnection(self) except: log.err() registerReapProcessHandler(self.pid, self)
def shedPrivileges(euid, uid, gid): if uid is not None or gid is not None: switchUID(uid, gid, euid) extra = euid and 'e' or '' log.msg('set %suid/%sgid %s/%s' % (extra, extra, uid, gid))
def shedPrivileges(euid, uid, gid): if uid is not None or gid is not None: switchUID(uid, gid, euid) extra = euid and "e" or "" log.msg("set %suid/%sgid %s/%s" % (extra, extra, uid, gid))
def __init__(self, reactor, command, args, environment, path, proto, uid=None, gid=None, usePTY=None): """Spawn an operating-system process. This is where the hard work of disconnecting all currently open files / forking / executing the new process happens. (This is executed automatically when a Process is instantiated.) This will also run the subprocess as a given user ID and group ID, if specified. (Implementation Note: this doesn't support all the arcane nuances of setXXuid on UNIX: it will assume that either your effective or real UID is 0.) """ if not pty and type(usePTY) not in (types.ListType, types.TupleType): # no pty module and we didn't get a pty to use raise NotImplementedError, "cannot use PTYProcess on platforms without the pty module." abstract.FileDescriptor.__init__(self, reactor) settingUID = (uid is not None) or (gid is not None) if settingUID: curegid = os.getegid() currgid = os.getgid() cureuid = os.geteuid() curruid = os.getuid() if uid is None: uid = cureuid if gid is None: gid = curegid # prepare to change UID in subprocess os.setuid(0) os.setgid(0) if type(usePTY) in (types.TupleType, types.ListType): masterfd, slavefd, ttyname = usePTY else: masterfd, slavefd = pty.openpty() ttyname = os.ttyname(slavefd) pid = os.fork() self.pid = pid if pid == 0: # pid is 0 in the child process try: sys.settrace(None) os.close(masterfd) if hasattr(termios, 'TIOCNOTTY'): try: fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY) except OSError: pass else: try: fcntl.ioctl(fd, termios.TIOCNOTTY, '') except: pass os.close(fd) os.setsid() if hasattr(termios, 'TIOCSCTTY'): fcntl.ioctl(slavefd, termios.TIOCSCTTY, '') for fd in range(3): if fd != slavefd: os.close(fd) os.dup2(slavefd, 0) # stdin os.dup2(slavefd, 1) # stdout os.dup2(slavefd, 2) # stderr if path: os.chdir(path) for fd in range(3, 256): try: os.close(fd) except: pass # set the UID before I actually exec the process if settingUID: switchUID(uid, gid) os.execvpe(command, args, environment) except: stderr = os.fdopen(1, 'w') stderr.write("Upon execvpe %s %s in environment %s:\n" % (command, str(args), "id %s" % id(environment))) traceback.print_exc(file=stderr) stderr.flush() os._exit(1) assert pid != 0 os.close(slavefd) fdesc.setNonBlocking(masterfd) self.fd = masterfd self.startReading() self.connected = 1 self.proto = proto self.lostProcess = 0 self.status = -1 try: self.proto.makeConnection(self) except: log.err() registerReapProcessHandler(self.pid, self)
def daemon( username = None, groupname = None, use_syslog = None, log_file = None, logfile = None, # HACK for backwards compat. verbose = False, capture_output = True, twisted_error_log_level = ERROR, twisted_info_log_level = INFO, capture_stderr_log_level = ERROR, capture_stdout_log_level = INFO, capture_stderr_name = 'stderr', capture_stdout_name = 'stdout', log_level = DEBUG, log_twisted = True, pidfile = None, use_localtime=False): """When this function returns, you are a daemon. If use_syslog or a log_file is specified then this installs a logger. Iff capture_output is specified then stdout and stderr are also directed to syslog. If use_syslog is None then it defaults to True if no log_file is provided and the platform is not Darwin. The following arguments are passed through to BTL.log.injectLogger. use_syslog, log_file, verbose, capture_output, twisted_error_log_level, twisted_info_log_level, capture_stderr_log_level, capture_stdout_log_level, capture_stderr_name, capture_stdout_name, log_level, log_twisted daemon no longer removes pid file. Ex: If a monitor sees that a pidfile exists and the process is not running then the monitor restarts the process. If you want the process to REALLY die then the pid file should be removed external to the program, e.g., by an init.d script that is passed "stop". """ assert log_file is None or logfile is None, "logfile was provided for backwards " \ "compatibility. You cannot specify both log_file and logfile." if log_file is None: log_file = logfile try: if os.name == 'mac': raise NotImplementedError( "Daemonization doesn't work on macs." ) if noisy: print "in daemon" uid = os.getuid() gid = os.getgid() if uid == 0 and username is None: raise Exception( "If you start with root privileges you need to " "provide a username argument so that daemon() can shed those " "privileges before returning." ) if username: uid = getuid_from_username(username) if noisy: print "setting username to uid of '%s', which is %d." % ( username, uid ) if uid != os.getuid() and os.getuid() != 0: raise Exception( "When specifying a uid other than your own " "you must be running as root for setuid to work. " "Your uid is %d, while the specified user '%s' has uid %d." % ( os.getuid(), username, uid ) ) gid = getgid_from_username(username) # uses this user's group if groupname: if noisy: print "setting groupname to gid of '%s', which is %d." % (groupname,gid) gid = getgid_from_groupname(groupname) pid_dir = os.path.split(pidfile)[0] if pid_dir and not os.path.exists(pid_dir): os.mkdir(pid_dir) os.chown(pid_dir,uid,gid) checkPID(pidfile) if use_syslog is None: use_syslog = sys.platform != 'darwin' and not log_file if log_file: if use_syslog: raise Exception( "You have specified both a log_file and " "that the daemon should use_syslog. Specify one or " "the other." ) print "Calling injectLogger" injectLogger(use_syslog=False, log_file = log_file, log_level = log_level, capture_output = capture_output, verbose = verbose, capture_stdout_name = capture_stdout_name, capture_stderr_name = capture_stderr_name, twisted_info_log_level = twisted_info_log_level, twisted_error_log_level = twisted_error_log_level, capture_stdout_log_level = capture_stdout_log_level, capture_stderr_log_level = capture_stderr_log_level, use_localtime = use_localtime ) elif use_syslog: injectLogger(use_syslog=True, log_level = log_level, verbose = verbose, capture_output = capture_output, capture_stdout_name = capture_stdout_name, capture_stderr_name = capture_stderr_name, twisted_info_log_level = twisted_info_log_level, twisted_error_log_level = twisted_error_log_level, capture_stdout_log_level = capture_stdout_log_level, capture_stderr_log_level = capture_stderr_log_level ) else: raise Exception( "You are attempting to daemonize without a log file," "and with use_syslog set to false. A daemon must " "output to syslog, a logfile, or both." ) if pidfile is None: pid_dir = os.path.join("/var/run/", app_name ) pidfile = os.path.join( pid_dir, app_name + ".pid") daemonize() # forks, moves into its own process group, forks again, # middle process exits with status 0. Redirects stdout, # stderr to /dev/null. # I should now be a daemon. open(pidfile,'wb').write(str(os.getpid())) if not os.path.exists(pidfile): raise Exception( "pidfile %s does not exist" % pidfile ) os.chmod(pidfile, stat.S_IRUSR|stat.S_IWUSR|stat.S_IROTH|stat.S_IRGRP) if os.getuid() == 0: if uid is not None or gid is not None: switchUID(uid, gid) if os.getuid() != uid: raise Exception( "failed to setuid to uid %d" % uid ) if os.getgid() != gid: raise Exception( "failed to setgid to gid %d" % gid ) except: log.exception("daemonizing may have failed") import traceback traceback.print_exc() raise
def drop_privileges(self): ent = pwd.getpwnam(self.conf['user']) switchUID(ent.pw_uid, ent.pw_gid)