patch 014152c41803dc37a9c8e8151cad5ea37b3f4281 Author: E. Bosch Date: Mon Dec 13 21:31:17 CET 2021 * irc: Add authentication (including users allowed) via local configuration and PAM diff -rN -u old-irgramd/irc.py new-irgramd/irc.py --- old-irgramd/irc.py 2024-11-22 21:49:40.129551877 +0100 +++ new-irgramd/irc.py 2024-11-22 21:49:40.133551871 +0100 @@ -50,6 +50,7 @@ self.logger = logging.getLogger() self.ioloop = tornado.ioloop.IOLoop.current() self.hostname = socket.gethostname() + self.conf = settings self.users = {} # Initialize IRC @@ -153,7 +154,8 @@ await self.reply_code(user, 'ERR_ERRONEUSNICKNAME', (nick,), '*') elif ni in self.users.keys(): await self.reply_code(user, 'ERR_NICKNAMEINUSE', (nick,), '*') - elif user.password == user.recv_pass: + elif user.pam_auth(nick, self.conf['pam'], self.conf['pam_group'], user.recv_pass) \ + or user.local_auth(nick, self.conf['irc_nicks'], user.recv_pass, self.conf['irc_password']): if user.registered: # rename current = user.irc_nick.lower() @@ -540,3 +542,46 @@ irc.irc_channels[chan].discard(self.irc_nick) irc.irc_channels_ops[chan].discard(self.irc_nick) irc.irc_channels_founder[chan].discard(self.irc_nick) + + def pam_auth(self, nick, pam, pam_group, recv_pass): + if not pam: return False + + # Check if user is in groups (main or others) + if pam_group: + import pwd + import grp + try: + user_group_id = pwd.getpwnam(nick).pw_gid + group_data = grp.getgrnam(pam_group) + pam_group_id = group_data.gr_gid + group_members = group_data.gr_mem + check_group = user_group_id == pam_group_id \ + or nick in group_members + except: + check_group = False + if not check_group: return False + else: + check_group = True + + # Check user authentication (via PAM) + import PAM + def pam_conv(auth, query_list, userData): + resp = [] + resp.append((recv_pass, 0)) + return resp + p = PAM.pam() + p.start('passwd') + p.set_item(PAM.PAM_USER, nick) + p.set_item(PAM.PAM_CONV, pam_conv) + try: + p.authenticate() + p.acct_mgmt() + except: + return False + else: + return True + + def local_auth(self, nick, nicks, recv_pass, irc_pass): + return ( nick in nicks + and recv_pass == irc_pass + ) diff -rN -u old-irgramd/irgramd new-irgramd/irgramd --- old-irgramd/irgramd 2024-11-22 21:49:40.133551871 +0100 +++ new-irgramd/irgramd 2024-11-22 21:49:40.133551871 +0100 @@ -65,6 +65,10 @@ tornado.options.define('tls', default=False, help='Use TLS/SSL encrypted connection for IRC server') tornado.options.define('tls_cert', default=None, metavar='CERTFILE', help='IRC server certificate chain for TLS/SSL, also can contain private key if not defined with `tls_key`') tornado.options.define('tls_key', default=None, metavar='KEYFILE', help='IRC server private key for TLS/SSL') + tornado.options.define('pam', default=False, help='Use PAM for IRC authentication, if not set you should set `irc_password`') + tornado.options.define('pam_group', default=None, metavar='GROUP', help='Unix group allowed if `pam` enabled, if empty any user is allowed') + tornado.options.define('irc_nicks', type=str, multiple=True, metavar='nick,..', help='List of nicks allowed for IRC, if `pam` and optionally `pam_group` are set, PAM authentication will be used instead') + tornado.options.define('irc_password', default='', metavar='PASSWORD', help='Password for IRC authentication, if `pam` is set, PAM authentication will be used instead') # parse cmd line first time to get --config and --config_dir tornado.options.parse_command_line() config_file = os.path.expanduser(tornado.options.options.config)