irc: Add authentication (including users allowed) via local configuration and PAM
patch 014152c41803dc37a9c8e8151cad5ea37b3f4281
Author: E. Bosch <presidev@AT@gmail.com>
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 16:19:30.016980025 +0100
+++ new-irgramd/irc.py 2024-11-22 16:19:30.020980018 +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 16:19:30.020980018 +0100
+++ new-irgramd/irgramd 2024-11-22 16:19:30.020980018 +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)