mirror of
https://github.com/osmarks/ngircd.git
synced 2024-12-12 09:50:29 +00:00
Merge branch 'master' of /srv/git/ngircd
* 'master' of /srv/git/ngircd: "multi-prefix" capability 2/2: adjust NAME and WHO handlers "multi-prefix" capability 1/2: implement complete CAP infrastructure IRC_Send_NAMES(): Code cleanup New function Client_CapSet() in addition to Client_Cap{Add|Del} "CAP REQ" starts capability negotiation and delays user registration Xcode: update project file for Xcode 4.3 Correctly handle "CAP END", new client type CLIENT_WAITCAPEND Implement core IRC capability handling and "CAP" command New "login" source file Introduce_Client() => Client_Introduce(), and move it to client.c
This commit is contained in:
commit
110be707c3
@ -41,6 +41,9 @@
|
|||||||
FAA3D27B0F139CDC00B2447E /* conn-ssl.c in Sources */ = {isa = PBXBuildFile; fileRef = FAA3D2790F139CDC00B2447E /* conn-ssl.c */; };
|
FAA3D27B0F139CDC00B2447E /* conn-ssl.c in Sources */ = {isa = PBXBuildFile; fileRef = FAA3D2790F139CDC00B2447E /* conn-ssl.c */; };
|
||||||
FAA97C57124A271400D5BBA9 /* sighandlers.c in Sources */ = {isa = PBXBuildFile; fileRef = FAA97C55124A271400D5BBA9 /* sighandlers.c */; };
|
FAA97C57124A271400D5BBA9 /* sighandlers.c in Sources */ = {isa = PBXBuildFile; fileRef = FAA97C55124A271400D5BBA9 /* sighandlers.c */; };
|
||||||
FAACD5F514A6099C006ED74F /* class.c in Sources */ = {isa = PBXBuildFile; fileRef = FAACD5F314A6099C006ED74F /* class.c */; };
|
FAACD5F514A6099C006ED74F /* class.c in Sources */ = {isa = PBXBuildFile; fileRef = FAACD5F314A6099C006ED74F /* class.c */; };
|
||||||
|
FAD5853215271AAB00328741 /* client-cap.c in Sources */ = {isa = PBXBuildFile; fileRef = FAD5853015271AAB00328741 /* client-cap.c */; };
|
||||||
|
FAD5853515271AB800328741 /* irc-cap.c in Sources */ = {isa = PBXBuildFile; fileRef = FAD5853315271AB800328741 /* irc-cap.c */; };
|
||||||
|
FAD5853815272C2600328741 /* login.c in Sources */ = {isa = PBXBuildFile; fileRef = FAD5853615272C2500328741 /* login.c */; };
|
||||||
FAE5CC2E0CF2308A007D69B6 /* numeric.c in Sources */ = {isa = PBXBuildFile; fileRef = FAE5CC2D0CF2308A007D69B6 /* numeric.c */; };
|
FAE5CC2E0CF2308A007D69B6 /* numeric.c in Sources */ = {isa = PBXBuildFile; fileRef = FAE5CC2D0CF2308A007D69B6 /* numeric.c */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
@ -231,6 +234,13 @@
|
|||||||
FAA97C56124A271400D5BBA9 /* sighandlers.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = sighandlers.h; sourceTree = "<group>"; };
|
FAA97C56124A271400D5BBA9 /* sighandlers.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = sighandlers.h; sourceTree = "<group>"; };
|
||||||
FAACD5F314A6099C006ED74F /* class.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = class.c; sourceTree = "<group>"; };
|
FAACD5F314A6099C006ED74F /* class.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = class.c; sourceTree = "<group>"; };
|
||||||
FAACD5F414A6099C006ED74F /* class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = class.h; sourceTree = "<group>"; };
|
FAACD5F414A6099C006ED74F /* class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = class.h; sourceTree = "<group>"; };
|
||||||
|
FAD5852F15271A7800328741 /* Capabilities.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Capabilities.txt; sourceTree = "<group>"; };
|
||||||
|
FAD5853015271AAB00328741 /* client-cap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "client-cap.c"; sourceTree = "<group>"; };
|
||||||
|
FAD5853115271AAB00328741 /* client-cap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "client-cap.h"; sourceTree = "<group>"; };
|
||||||
|
FAD5853315271AB800328741 /* irc-cap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "irc-cap.c"; sourceTree = "<group>"; };
|
||||||
|
FAD5853415271AB800328741 /* irc-cap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "irc-cap.h"; sourceTree = "<group>"; };
|
||||||
|
FAD5853615272C2500328741 /* login.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = login.c; sourceTree = "<group>"; };
|
||||||
|
FAD5853715272C2500328741 /* login.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = login.h; sourceTree = "<group>"; };
|
||||||
FAE22BD215270EA300F1A5AB /* Bopm.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bopm.txt; sourceTree = "<group>"; };
|
FAE22BD215270EA300F1A5AB /* Bopm.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bopm.txt; sourceTree = "<group>"; };
|
||||||
FAE22BD415270EA300F1A5AB /* Contributing.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Contributing.txt; sourceTree = "<group>"; };
|
FAE22BD415270EA300F1A5AB /* Contributing.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Contributing.txt; sourceTree = "<group>"; };
|
||||||
FAE22BD515270EB500F1A5AB /* HowToRelease.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = HowToRelease.txt; sourceTree = "<group>"; };
|
FAE22BD515270EB500F1A5AB /* HowToRelease.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = HowToRelease.txt; sourceTree = "<group>"; };
|
||||||
@ -313,6 +323,8 @@
|
|||||||
FAACD5F414A6099C006ED74F /* class.h */,
|
FAACD5F414A6099C006ED74F /* class.h */,
|
||||||
FA322CDD0CEF74B1001761B3 /* client.c */,
|
FA322CDD0CEF74B1001761B3 /* client.c */,
|
||||||
FA322CDE0CEF74B1001761B3 /* client.h */,
|
FA322CDE0CEF74B1001761B3 /* client.h */,
|
||||||
|
FAD5853015271AAB00328741 /* client-cap.c */,
|
||||||
|
FAD5853115271AAB00328741 /* client-cap.h */,
|
||||||
FA322CDF0CEF74B1001761B3 /* conf.c */,
|
FA322CDF0CEF74B1001761B3 /* conf.c */,
|
||||||
FA322CE00CEF74B1001761B3 /* conf.h */,
|
FA322CE00CEF74B1001761B3 /* conf.h */,
|
||||||
FAA3D2780F139CDC00B2447E /* conf-ssl.h */,
|
FAA3D2780F139CDC00B2447E /* conf-ssl.h */,
|
||||||
@ -329,6 +341,8 @@
|
|||||||
FA322CE90CEF74B1001761B3 /* hash.h */,
|
FA322CE90CEF74B1001761B3 /* hash.h */,
|
||||||
FA322CEA0CEF74B1001761B3 /* io.c */,
|
FA322CEA0CEF74B1001761B3 /* io.c */,
|
||||||
FA322CEB0CEF74B1001761B3 /* io.h */,
|
FA322CEB0CEF74B1001761B3 /* io.h */,
|
||||||
|
FAD5853315271AB800328741 /* irc-cap.c */,
|
||||||
|
FAD5853415271AB800328741 /* irc-cap.h */,
|
||||||
FA322CEC0CEF74B1001761B3 /* irc-channel.c */,
|
FA322CEC0CEF74B1001761B3 /* irc-channel.c */,
|
||||||
FA322CED0CEF74B1001761B3 /* irc-channel.h */,
|
FA322CED0CEF74B1001761B3 /* irc-channel.h */,
|
||||||
FA322CEE0CEF74B1001761B3 /* irc-info.c */,
|
FA322CEE0CEF74B1001761B3 /* irc-info.c */,
|
||||||
@ -351,6 +365,8 @@
|
|||||||
FA322CFF0CEF74B1001761B3 /* lists.h */,
|
FA322CFF0CEF74B1001761B3 /* lists.h */,
|
||||||
FA322D000CEF74B1001761B3 /* log.c */,
|
FA322D000CEF74B1001761B3 /* log.c */,
|
||||||
FA322D010CEF74B1001761B3 /* log.h */,
|
FA322D010CEF74B1001761B3 /* log.h */,
|
||||||
|
FAD5853615272C2500328741 /* login.c */,
|
||||||
|
FAD5853715272C2500328741 /* login.h */,
|
||||||
FA322D030CEF74B1001761B3 /* match.c */,
|
FA322D030CEF74B1001761B3 /* match.c */,
|
||||||
FA322D040CEF74B1001761B3 /* match.h */,
|
FA322D040CEF74B1001761B3 /* match.h */,
|
||||||
FA322D050CEF74B1001761B3 /* messages.h */,
|
FA322D050CEF74B1001761B3 /* messages.h */,
|
||||||
@ -571,6 +587,7 @@
|
|||||||
children = (
|
children = (
|
||||||
FA322D9B0CEF752C001761B3 /* Makefile.am */,
|
FA322D9B0CEF752C001761B3 /* Makefile.am */,
|
||||||
FAE22BD215270EA300F1A5AB /* Bopm.txt */,
|
FAE22BD215270EA300F1A5AB /* Bopm.txt */,
|
||||||
|
FAD5852F15271A7800328741 /* Capabilities.txt */,
|
||||||
FAE22BD415270EA300F1A5AB /* Contributing.txt */,
|
FAE22BD415270EA300F1A5AB /* Contributing.txt */,
|
||||||
FA322D9A0CEF752C001761B3 /* FAQ.txt */,
|
FA322D9A0CEF752C001761B3 /* FAQ.txt */,
|
||||||
FA407F380DB15AC700271AF1 /* GIT.txt */,
|
FA407F380DB15AC700271AF1 /* GIT.txt */,
|
||||||
@ -665,7 +682,7 @@
|
|||||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 0420;
|
LastUpgradeCheck = 0430;
|
||||||
};
|
};
|
||||||
buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "ngIRCd" */;
|
buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "ngIRCd" */;
|
||||||
compatibilityVersion = "Xcode 3.2";
|
compatibilityVersion = "Xcode 3.2";
|
||||||
@ -730,6 +747,9 @@
|
|||||||
FA2D564A11EA158B00D37A35 /* pam.c in Sources */,
|
FA2D564A11EA158B00D37A35 /* pam.c in Sources */,
|
||||||
FAA97C57124A271400D5BBA9 /* sighandlers.c in Sources */,
|
FAA97C57124A271400D5BBA9 /* sighandlers.c in Sources */,
|
||||||
FAACD5F514A6099C006ED74F /* class.c in Sources */,
|
FAACD5F514A6099C006ED74F /* class.c in Sources */,
|
||||||
|
FAD5853215271AAB00328741 /* client-cap.c in Sources */,
|
||||||
|
FAD5853515271AB800328741 /* irc-cap.c in Sources */,
|
||||||
|
FAD5853815272C2600328741 /* login.c in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
23
doc/Capabilities.txt
Normal file
23
doc/Capabilities.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
ngIRCd - Next Generation IRC Server
|
||||||
|
http://ngircd.barton.de/
|
||||||
|
|
||||||
|
(c)2001-2012 Alexander Barton and Contributors.
|
||||||
|
ngIRCd is free software and published under the
|
||||||
|
terms of the GNU General Public License.
|
||||||
|
|
||||||
|
-- Capabilities.txt --
|
||||||
|
|
||||||
|
|
||||||
|
This document lists and describes the "IRC capabilities" that ngIRCd supports
|
||||||
|
and can be requested by a IRC/IRCv3 client that supports the "CAP" command.
|
||||||
|
|
||||||
|
ngIRCd implements the "IRC Client Capabilities Extension" as described here:
|
||||||
|
<http://www.leeh.co.uk/draft-mitchell-irc-capabilities-02.html>
|
||||||
|
|
||||||
|
|
||||||
|
I. Supported Capabilities
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
None. At the moment, ngIRCd supports the "CAP" command and its sub-commands
|
||||||
|
but offers no capabilities that could be requested by a client.
|
@ -18,6 +18,7 @@ SUFFIXES = .tmpl
|
|||||||
|
|
||||||
static_docs = \
|
static_docs = \
|
||||||
Bopm.txt \
|
Bopm.txt \
|
||||||
|
Capabilities.txt \
|
||||||
FAQ.txt \
|
FAQ.txt \
|
||||||
GIT.txt \
|
GIT.txt \
|
||||||
HowToRelease.txt \
|
HowToRelease.txt \
|
||||||
|
@ -24,6 +24,7 @@ ngircd_SOURCES = \
|
|||||||
channel.c \
|
channel.c \
|
||||||
class.c \
|
class.c \
|
||||||
client.c \
|
client.c \
|
||||||
|
client-cap.c \
|
||||||
conf.c \
|
conf.c \
|
||||||
conn.c \
|
conn.c \
|
||||||
conn-func.c \
|
conn-func.c \
|
||||||
@ -32,6 +33,7 @@ ngircd_SOURCES = \
|
|||||||
hash.c \
|
hash.c \
|
||||||
io.c \
|
io.c \
|
||||||
irc.c \
|
irc.c \
|
||||||
|
irc-cap.c \
|
||||||
irc-channel.c \
|
irc-channel.c \
|
||||||
irc-info.c \
|
irc-info.c \
|
||||||
irc-login.c \
|
irc-login.c \
|
||||||
@ -42,6 +44,7 @@ ngircd_SOURCES = \
|
|||||||
irc-write.c \
|
irc-write.c \
|
||||||
lists.c \
|
lists.c \
|
||||||
log.c \
|
log.c \
|
||||||
|
login.c \
|
||||||
match.c \
|
match.c \
|
||||||
numeric.c \
|
numeric.c \
|
||||||
op.c \
|
op.c \
|
||||||
@ -61,6 +64,7 @@ noinst_HEADERS = \
|
|||||||
channel.h \
|
channel.h \
|
||||||
class.h \
|
class.h \
|
||||||
client.h \
|
client.h \
|
||||||
|
client-cap.h \
|
||||||
conf.h \
|
conf.h \
|
||||||
conf-ssl.h \
|
conf-ssl.h \
|
||||||
conn.h \
|
conn.h \
|
||||||
@ -71,6 +75,7 @@ noinst_HEADERS = \
|
|||||||
hash.h \
|
hash.h \
|
||||||
io.h \
|
io.h \
|
||||||
irc.h \
|
irc.h \
|
||||||
|
irc-cap.h \
|
||||||
irc-channel.h \
|
irc-channel.h \
|
||||||
irc-info.h \
|
irc-info.h \
|
||||||
irc-login.h \
|
irc-login.h \
|
||||||
@ -81,6 +86,7 @@ noinst_HEADERS = \
|
|||||||
irc-write.h \
|
irc-write.h \
|
||||||
lists.h \
|
lists.h \
|
||||||
log.h \
|
log.h \
|
||||||
|
login.h \
|
||||||
match.h \
|
match.h \
|
||||||
messages.h \
|
messages.h \
|
||||||
numeric.h \
|
numeric.h \
|
||||||
|
73
src/ngircd/client-cap.c
Normal file
73
src/ngircd/client-cap.c
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* ngIRCd -- The Next Generation IRC Daemon
|
||||||
|
* Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* Please read the file COPYING, README and AUTHORS for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __client_cap_c__
|
||||||
|
|
||||||
|
#include "portab.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Functions to deal with IRC Capabilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "imp.h"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
#include "conn.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include "exp.h"
|
||||||
|
#include "client-cap.h"
|
||||||
|
|
||||||
|
GLOBAL int
|
||||||
|
Client_Cap(CLIENT *Client)
|
||||||
|
{
|
||||||
|
assert (Client != NULL);
|
||||||
|
|
||||||
|
return Client->capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLOBAL void
|
||||||
|
Client_CapSet(CLIENT *Client, int Cap)
|
||||||
|
{
|
||||||
|
assert(Client != NULL);
|
||||||
|
assert(Cap >= 0);
|
||||||
|
|
||||||
|
Client->capabilities = Cap;
|
||||||
|
LogDebug("Set new capability of \"%s\" to %d.",
|
||||||
|
Client_ID(Client), Client->capabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLOBAL void
|
||||||
|
Client_CapAdd(CLIENT *Client, int Cap)
|
||||||
|
{
|
||||||
|
assert(Client != NULL);
|
||||||
|
assert(Cap > 0);
|
||||||
|
|
||||||
|
Client->capabilities |= Cap;
|
||||||
|
LogDebug("Add capability %d, new capability of \"%s\" is %d.",
|
||||||
|
Cap, Client_ID(Client), Client->capabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLOBAL void
|
||||||
|
Client_CapDel(CLIENT *Client, int Cap)
|
||||||
|
{
|
||||||
|
assert(Client != NULL);
|
||||||
|
assert(Cap > 0);
|
||||||
|
|
||||||
|
Client->capabilities &= ~Cap;
|
||||||
|
LogDebug("Delete capability %d, new capability of \"%s\" is %d.",
|
||||||
|
Cap, Client_ID(Client), Client->capabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -eof- */
|
31
src/ngircd/client-cap.h
Normal file
31
src/ngircd/client-cap.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* ngIRCd -- The Next Generation IRC Daemon
|
||||||
|
* Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* Please read the file COPYING, README and AUTHORS for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __client_cap_h__
|
||||||
|
#define __client_cap_h__
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Functions to deal with IRC Capabilities (header)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CLIENT_CAP_PENDING 1 /* Capability negotiation pending */
|
||||||
|
#define CLIENT_CAP_SUPPORTED 2 /* Client supports IRC capabilities */
|
||||||
|
|
||||||
|
#define CLIENT_CAP_MULTI_PREFIX 4 /* multi-prefix */
|
||||||
|
|
||||||
|
GLOBAL int Client_Cap PARAMS((CLIENT *Client));
|
||||||
|
|
||||||
|
GLOBAL void Client_CapSet PARAMS((CLIENT *Client, int Cap));
|
||||||
|
GLOBAL void Client_CapAdd PARAMS((CLIENT *Client, int Cap));
|
||||||
|
GLOBAL void Client_CapDel PARAMS((CLIENT *Client, int Cap));
|
||||||
|
|
||||||
|
#endif
|
@ -37,6 +37,7 @@
|
|||||||
#include "ngircd.h"
|
#include "ngircd.h"
|
||||||
#include "channel.h"
|
#include "channel.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
#include "conn-func.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "irc-write.h"
|
#include "irc-write.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -69,6 +70,8 @@ static CLIENT *Init_New_Client PARAMS((CONN_ID Idx, CLIENT *Introducer,
|
|||||||
static void Destroy_UserOrService PARAMS((CLIENT *Client,const char *Txt, const char *FwdMsg,
|
static void Destroy_UserOrService PARAMS((CLIENT *Client,const char *Txt, const char *FwdMsg,
|
||||||
bool SendQuit));
|
bool SendQuit));
|
||||||
|
|
||||||
|
static void cb_introduceClient PARAMS((CLIENT *Client, CLIENT *Prefix,
|
||||||
|
void *i));
|
||||||
|
|
||||||
GLOBAL void
|
GLOBAL void
|
||||||
Client_Init( void )
|
Client_Init( void )
|
||||||
@ -1142,6 +1145,46 @@ Client_Reject(CLIENT *Client, const char *Reason, bool InformClient)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Introduce a new user or service client in the network.
|
||||||
|
*
|
||||||
|
* @param From Remote server introducing the client or NULL (local).
|
||||||
|
* @param Client New client.
|
||||||
|
* @param Type Type of the client (CLIENT_USER or CLIENT_SERVICE).
|
||||||
|
*/
|
||||||
|
GLOBAL void
|
||||||
|
Client_Introduce(CLIENT *From, CLIENT *Client, int Type)
|
||||||
|
{
|
||||||
|
/* Set client type (user or service) */
|
||||||
|
Client_SetType(Client, Type);
|
||||||
|
|
||||||
|
if (From) {
|
||||||
|
if (Conf_IsService(Conf_GetServer(Client_Conn(From)),
|
||||||
|
Client_ID(Client)))
|
||||||
|
Client_SetType(Client, CLIENT_SERVICE);
|
||||||
|
LogDebug("%s \"%s\" (+%s) registered (via %s, on %s, %d hop%s).",
|
||||||
|
Client_TypeText(Client), Client_Mask(Client),
|
||||||
|
Client_Modes(Client), Client_ID(From),
|
||||||
|
Client_ID(Client_Introducer(Client)),
|
||||||
|
Client_Hops(Client), Client_Hops(Client) > 1 ? "s": "");
|
||||||
|
} else {
|
||||||
|
Log(LOG_NOTICE, "%s \"%s\" registered (connection %d).",
|
||||||
|
Client_TypeText(Client), Client_Mask(Client),
|
||||||
|
Client_Conn(Client));
|
||||||
|
Log_ServerNotice('c', "Client connecting: %s (%s@%s) [%s] - %s",
|
||||||
|
Client_ID(Client), Client_User(Client),
|
||||||
|
Client_Hostname(Client),
|
||||||
|
Conn_IPA(Client_Conn(Client)),
|
||||||
|
Client_TypeText(Client));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inform other servers */
|
||||||
|
IRC_WriteStrServersPrefixFlag_CB(From,
|
||||||
|
From != NULL ? From : Client_ThisServer(),
|
||||||
|
'\0', cb_introduceClient, (void *)Client);
|
||||||
|
} /* Client_Introduce */
|
||||||
|
|
||||||
|
|
||||||
static unsigned long
|
static unsigned long
|
||||||
Count( CLIENT_TYPE Type )
|
Count( CLIENT_TYPE Type )
|
||||||
{
|
{
|
||||||
@ -1361,6 +1404,59 @@ Destroy_UserOrService(CLIENT *Client, const char *Txt, const char *FwdMsg, bool
|
|||||||
} /* Destroy_UserOrService */
|
} /* Destroy_UserOrService */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Introduce a new user or service client to a remote server.
|
||||||
|
*
|
||||||
|
* This function differentiates between RFC1459 and RFC2813 server links and
|
||||||
|
* generates the appropriate commands to register the new user or service.
|
||||||
|
*
|
||||||
|
* @param To The remote server to inform.
|
||||||
|
* @param Prefix Prefix for the generated commands.
|
||||||
|
* @param data CLIENT structure of the new client.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
cb_introduceClient(CLIENT *To, CLIENT *Prefix, void *data)
|
||||||
|
{
|
||||||
|
CLIENT *c = (CLIENT *)data;
|
||||||
|
CONN_ID conn;
|
||||||
|
char *modes, *user, *host;
|
||||||
|
|
||||||
|
modes = Client_Modes(c);
|
||||||
|
user = Client_User(c) ? Client_User(c) : "-";
|
||||||
|
host = Client_Hostname(c) ? Client_Hostname(c) : "-";
|
||||||
|
|
||||||
|
conn = Client_Conn(To);
|
||||||
|
if (Conn_Options(conn) & CONN_RFC1459) {
|
||||||
|
/* RFC 1459 mode: separate NICK and USER commands */
|
||||||
|
Conn_WriteStr(conn, "NICK %s :%d", Client_ID(c),
|
||||||
|
Client_Hops(c) + 1);
|
||||||
|
Conn_WriteStr(conn, ":%s USER %s %s %s :%s",
|
||||||
|
Client_ID(c), user, host,
|
||||||
|
Client_ID(Client_Introducer(c)), Client_Info(c));
|
||||||
|
if (modes[0])
|
||||||
|
Conn_WriteStr(conn, ":%s MODE %s +%s",
|
||||||
|
Client_ID(c), Client_ID(c), modes);
|
||||||
|
} else {
|
||||||
|
/* RFC 2813 mode: one combined NICK or SERVICE command */
|
||||||
|
if (Client_Type(c) == CLIENT_SERVICE
|
||||||
|
&& strchr(Client_Flags(To), 'S'))
|
||||||
|
IRC_WriteStrClientPrefix(To, Prefix,
|
||||||
|
"SERVICE %s %d * +%s %d :%s",
|
||||||
|
Client_Mask(c),
|
||||||
|
Client_MyToken(Client_Introducer(c)),
|
||||||
|
Client_Modes(c), Client_Hops(c) + 1,
|
||||||
|
Client_Info(c));
|
||||||
|
else
|
||||||
|
IRC_WriteStrClientPrefix(To, Prefix,
|
||||||
|
"NICK %s %d %s %s %d +%s :%s",
|
||||||
|
Client_ID(c), Client_Hops(c) + 1,
|
||||||
|
user, host,
|
||||||
|
Client_MyToken(Client_Introducer(c)),
|
||||||
|
modes, Client_Info(c));
|
||||||
|
}
|
||||||
|
} /* cb_introduceClient */
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
||||||
GLOBAL void
|
GLOBAL void
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ngIRCd -- The Next Generation IRC Daemon
|
* ngIRCd -- The Next Generation IRC Daemon
|
||||||
* Copyright (c)2001-2008 Alexander Barton (alex@barton.de)
|
* Copyright (c)2001-2012 Alexander Barton (alex@barton.de)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -29,12 +29,13 @@
|
|||||||
#ifndef STRICT_RFC
|
#ifndef STRICT_RFC
|
||||||
# define CLIENT_WAITAUTHPING 512 /* waiting for AUTH PONG from client */
|
# define CLIENT_WAITAUTHPING 512 /* waiting for AUTH PONG from client */
|
||||||
#endif
|
#endif
|
||||||
|
#define CLIENT_WAITCAPEND 1024 /* waiting for "CAP END" command */
|
||||||
|
|
||||||
#define CLIENT_TYPE int
|
#define CLIENT_TYPE int
|
||||||
|
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
|
||||||
#if defined(__client_c__) | defined(S_SPLINT_S)
|
#if defined(__client_c__) | defined(__client_cap_c__) | defined(S_SPLINT_S)
|
||||||
|
|
||||||
typedef struct _CLIENT
|
typedef struct _CLIENT
|
||||||
{
|
{
|
||||||
@ -58,6 +59,7 @@ typedef struct _CLIENT
|
|||||||
bool oper_by_me; /* client is local IRC operator on this server? */
|
bool oper_by_me; /* client is local IRC operator on this server? */
|
||||||
char away[CLIENT_AWAY_LEN]; /* AWAY text (valid if mode 'a' is set) */
|
char away[CLIENT_AWAY_LEN]; /* AWAY text (valid if mode 'a' is set) */
|
||||||
char flags[CLIENT_FLAGS_LEN]; /* flags of the client */
|
char flags[CLIENT_FLAGS_LEN]; /* flags of the client */
|
||||||
|
int capabilities; /* enabled IRC capabilities */
|
||||||
} CLIENT;
|
} CLIENT;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -165,6 +167,8 @@ GLOBAL const char *Client_TypeText PARAMS((CLIENT *Client));
|
|||||||
|
|
||||||
GLOBAL void Client_Reject PARAMS((CLIENT *Client, const char *Reason,
|
GLOBAL void Client_Reject PARAMS((CLIENT *Client, const char *Reason,
|
||||||
bool InformClient));
|
bool InformClient));
|
||||||
|
GLOBAL void Client_Introduce PARAMS((CLIENT *From, CLIENT *Client, int Type));
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
GLOBAL void Client_DebugDump PARAMS((void));
|
GLOBAL void Client_DebugDump PARAMS((void));
|
||||||
|
291
src/ngircd/irc-cap.c
Normal file
291
src/ngircd/irc-cap.c
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
/*
|
||||||
|
* ngIRCd -- The Next Generation IRC Daemon
|
||||||
|
* Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* Please read the file COPYING, README and AUTHORS for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "portab.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Handler for IRC capability ("CAP") commands
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "imp.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
#include "conn.h"
|
||||||
|
#include "channel.h"
|
||||||
|
#include "client-cap.h"
|
||||||
|
#include "irc-write.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "login.h"
|
||||||
|
#include "messages.h"
|
||||||
|
#include "parse.h"
|
||||||
|
|
||||||
|
#include "exp.h"
|
||||||
|
#include "irc-cap.h"
|
||||||
|
|
||||||
|
bool Handle_CAP_LS PARAMS((CLIENT *Client, char *Arg));
|
||||||
|
bool Handle_CAP_LIST PARAMS((CLIENT *Client, char *Arg));
|
||||||
|
bool Handle_CAP_REQ PARAMS((CLIENT *Client, char *Arg));
|
||||||
|
bool Handle_CAP_ACK PARAMS((CLIENT *Client, char *Arg));
|
||||||
|
bool Handle_CAP_CLEAR PARAMS((CLIENT *Client));
|
||||||
|
bool Handle_CAP_END PARAMS((CLIENT *Client));
|
||||||
|
|
||||||
|
void Set_CAP_Negotiation PARAMS((CLIENT *Client));
|
||||||
|
|
||||||
|
int Parse_CAP PARAMS((int Capabilities, char *Args));
|
||||||
|
char *Get_CAP_String PARAMS((int Capabilities));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the IRCv3 "CAP" command.
|
||||||
|
*
|
||||||
|
* @param Client The client from which this command has been received.
|
||||||
|
* @param Req Request structure with prefix and all parameters.
|
||||||
|
* @returns CONNECTED or DISCONNECTED.
|
||||||
|
*/
|
||||||
|
GLOBAL bool
|
||||||
|
IRC_CAP(CLIENT *Client, REQUEST *Req)
|
||||||
|
{
|
||||||
|
assert(Client != NULL);
|
||||||
|
assert(Req != NULL);
|
||||||
|
|
||||||
|
/* Bad number of prameters? */
|
||||||
|
if (Req->argc < 1 || Req->argc > 2)
|
||||||
|
return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
|
||||||
|
Client_ID(Client), Req->command);
|
||||||
|
|
||||||
|
LogDebug("Got \"%s %s\" command from \"%s\" ...",
|
||||||
|
Req->command, Req->argv[0], Client_ID(Client));
|
||||||
|
|
||||||
|
if (Req->argc == 1) {
|
||||||
|
if (strcasecmp(Req->argv[0], "CLEAR") == 0)
|
||||||
|
return Handle_CAP_CLEAR(Client);
|
||||||
|
if (strcasecmp(Req->argv[0], "END") == 0)
|
||||||
|
return Handle_CAP_END(Client);
|
||||||
|
}
|
||||||
|
if (Req->argc >= 1 && Req->argc <= 2) {
|
||||||
|
if (strcasecmp(Req->argv[0], "LS") == 0)
|
||||||
|
return Handle_CAP_LS(Client, Req->argv[1]);
|
||||||
|
if (strcasecmp(Req->argv[0], "LIST") == 0)
|
||||||
|
return Handle_CAP_LIST(Client, Req->argv[1]);
|
||||||
|
}
|
||||||
|
if (Req->argc == 2) {
|
||||||
|
if (strcasecmp(Req->argv[0], "REQ") == 0)
|
||||||
|
return Handle_CAP_REQ(Client, Req->argv[1]);
|
||||||
|
if (strcasecmp(Req->argv[0], "ACK") == 0)
|
||||||
|
return Handle_CAP_ACK(Client, Req->argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IRC_WriteStrClient(Client, ERR_INVALIDCAP_MSG,
|
||||||
|
Client_ID(Client), Req->argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the "CAP LS" command.
|
||||||
|
*
|
||||||
|
* @param Client The client from which this command has been received.
|
||||||
|
* @param Arg Command argument or NULL.
|
||||||
|
* @returns CONNECTED or DISCONNECTED.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
Handle_CAP_LS(CLIENT *Client, UNUSED char *Arg)
|
||||||
|
{
|
||||||
|
assert(Client != NULL);
|
||||||
|
|
||||||
|
Set_CAP_Negotiation(Client);
|
||||||
|
|
||||||
|
return IRC_WriteStrClient(Client,
|
||||||
|
"CAP %s LS :multi-prefix",
|
||||||
|
Client_ID(Client));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the "CAP LIST" command.
|
||||||
|
*
|
||||||
|
* @param Client The client from which this command has been received.
|
||||||
|
* @param Arg Command argument or NULL.
|
||||||
|
* @returns CONNECTED or DISCONNECTED.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
Handle_CAP_LIST(CLIENT *Client, UNUSED char *Arg)
|
||||||
|
{
|
||||||
|
assert(Client != NULL);
|
||||||
|
|
||||||
|
return IRC_WriteStrClient(Client, "CAP %s LIST :%s", Client_ID(Client),
|
||||||
|
Get_CAP_String(Client_Cap(Client)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the "CAP REQ" command.
|
||||||
|
*
|
||||||
|
* @param Client The client from which this command has been received.
|
||||||
|
* @param Arg Command argument.
|
||||||
|
* @returns CONNECTED or DISCONNECTED.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
Handle_CAP_REQ(CLIENT *Client, char *Arg)
|
||||||
|
{
|
||||||
|
int new_cap;
|
||||||
|
|
||||||
|
assert(Client != NULL);
|
||||||
|
assert(Arg != NULL);
|
||||||
|
|
||||||
|
Set_CAP_Negotiation(Client);
|
||||||
|
|
||||||
|
new_cap = Parse_CAP(Client_Cap(Client), Arg);
|
||||||
|
|
||||||
|
if (new_cap < 0)
|
||||||
|
return IRC_WriteStrClient(Client, "CAP %s NAK :%s",
|
||||||
|
Client_ID(Client), Arg);
|
||||||
|
|
||||||
|
Client_CapSet(Client, new_cap);
|
||||||
|
return IRC_WriteStrClient(Client, "CAP %s ACK :%s",
|
||||||
|
Client_ID(Client), Arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the "CAP ACK" command.
|
||||||
|
*
|
||||||
|
* @param Client The client from which this command has been received.
|
||||||
|
* @param Arg Command argument.
|
||||||
|
* @returns CONNECTED or DISCONNECTED.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
Handle_CAP_ACK(CLIENT *Client, char *Arg)
|
||||||
|
{
|
||||||
|
assert(Client != NULL);
|
||||||
|
assert(Arg != NULL);
|
||||||
|
|
||||||
|
return CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the "CAP CLEAR" command.
|
||||||
|
*
|
||||||
|
* @param Client The client from which this command has been received.
|
||||||
|
* @returns CONNECTED or DISCONNECTED.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
Handle_CAP_CLEAR(CLIENT *Client)
|
||||||
|
{
|
||||||
|
int cap_old;
|
||||||
|
|
||||||
|
assert(Client != NULL);
|
||||||
|
|
||||||
|
cap_old = Client_Cap(Client);
|
||||||
|
if (cap_old & CLIENT_CAP_MULTI_PREFIX)
|
||||||
|
Client_CapDel(Client, CLIENT_CAP_MULTI_PREFIX);
|
||||||
|
|
||||||
|
return IRC_WriteStrClient(Client, "CAP %s ACK :%s", Client_ID(Client),
|
||||||
|
Get_CAP_String(cap_old));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the "CAP END" command.
|
||||||
|
*
|
||||||
|
* @param Client The client from which this command has been received.
|
||||||
|
* @returns CONNECTED or DISCONNECTED.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
Handle_CAP_END(CLIENT *Client)
|
||||||
|
{
|
||||||
|
assert(Client != NULL);
|
||||||
|
|
||||||
|
if (Client_Type(Client) != CLIENT_USER) {
|
||||||
|
/* User is still logging in ... */
|
||||||
|
Client_CapDel(Client, CLIENT_CAP_PENDING);
|
||||||
|
|
||||||
|
if (Client_Type(Client) == CLIENT_WAITCAPEND) {
|
||||||
|
/* Only "CAP END" was missing: log in! */
|
||||||
|
return Login_User(Client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set CAP negotiation status and mark client as "supports capabilities".
|
||||||
|
*
|
||||||
|
* @param Client The client to handle.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
Set_CAP_Negotiation(CLIENT *Client)
|
||||||
|
{
|
||||||
|
assert(Client != NULL);
|
||||||
|
|
||||||
|
if (Client_Type(Client) != CLIENT_USER)
|
||||||
|
Client_CapAdd(Client, CLIENT_CAP_PENDING);
|
||||||
|
Client_CapAdd(Client, CLIENT_CAP_SUPPORTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse capability string and return numeric flag value.
|
||||||
|
*
|
||||||
|
* @param Args The string containing space-separated capability names.
|
||||||
|
* @return Changed capability flags or 0 on error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
Parse_CAP(int Capabilities, char *Args)
|
||||||
|
{
|
||||||
|
static char tmp[COMMAND_LEN];
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
assert(Args != NULL);
|
||||||
|
|
||||||
|
strlcpy(tmp, Args, sizeof(tmp));
|
||||||
|
|
||||||
|
ptr = strtok(tmp, " ");
|
||||||
|
while (ptr) {
|
||||||
|
if (*ptr == '-') {
|
||||||
|
/* drop capabilities */
|
||||||
|
ptr++;
|
||||||
|
if (strcmp(ptr, "multi-prefix") == 0)
|
||||||
|
Capabilities &= ~CLIENT_CAP_MULTI_PREFIX;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
/* request capabilities */
|
||||||
|
if (strcmp(ptr, "multi-prefix") == 0)
|
||||||
|
Capabilities |= CLIENT_CAP_MULTI_PREFIX;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ptr = strtok(NULL, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return textual representation of capability flags.
|
||||||
|
*
|
||||||
|
* Please note: this function returns a pointer to a global buffer and
|
||||||
|
* therefore isn't thread safe!
|
||||||
|
*
|
||||||
|
* @param Capabilities Capability flags (bitmask).
|
||||||
|
* @return Pointer to textual representation.
|
||||||
|
*/
|
||||||
|
char
|
||||||
|
*Get_CAP_String(int Capabilities)
|
||||||
|
{
|
||||||
|
static char txt[COMMAND_LEN];
|
||||||
|
|
||||||
|
txt[0] = '\0';
|
||||||
|
|
||||||
|
if (Capabilities & CLIENT_CAP_MULTI_PREFIX)
|
||||||
|
strlcat(txt, "multi-prefix ", sizeof(txt));
|
||||||
|
|
||||||
|
return txt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -eof- */
|
24
src/ngircd/irc-cap.h
Normal file
24
src/ngircd/irc-cap.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* ngIRCd -- The Next Generation IRC Daemon
|
||||||
|
* Copyright (c)2001-2010 Alexander Barton (alex@barton.de).
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* Please read the file COPYING, README and AUTHORS for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __irc_cap_h__
|
||||||
|
#define __irc_cap_h__
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Handler for IRC capability ("CAP") commands (header)
|
||||||
|
*/
|
||||||
|
|
||||||
|
GLOBAL bool IRC_CAP PARAMS((CLIENT *Client, REQUEST *Req));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* -eof- */
|
@ -39,6 +39,7 @@
|
|||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
#include "irc.h"
|
#include "irc.h"
|
||||||
#include "irc-write.h"
|
#include "irc-write.h"
|
||||||
|
#include "client-cap.h"
|
||||||
|
|
||||||
#include "exp.h"
|
#include "exp.h"
|
||||||
#include "irc-info.h"
|
#include "irc-info.h"
|
||||||
@ -807,8 +808,16 @@ who_flags_status(const char *client_modes)
|
|||||||
|
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
who_flags_qualifier(const char *chan_user_modes)
|
who_flags_qualifier(CLIENT *Client, const char *chan_user_modes)
|
||||||
{
|
{
|
||||||
|
assert(Client != NULL);
|
||||||
|
|
||||||
|
if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX) {
|
||||||
|
if (strchr(chan_user_modes, 'o') &&
|
||||||
|
strchr(chan_user_modes, 'v'))
|
||||||
|
return "@+";
|
||||||
|
}
|
||||||
|
|
||||||
if (strchr(chan_user_modes, 'o'))
|
if (strchr(chan_user_modes, 'o'))
|
||||||
return "@";
|
return "@";
|
||||||
else if (strchr(chan_user_modes, 'v'))
|
else if (strchr(chan_user_modes, 'v'))
|
||||||
@ -865,7 +874,7 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
|
|||||||
strlcat(flags, "*", sizeof(flags));
|
strlcat(flags, "*", sizeof(flags));
|
||||||
|
|
||||||
chan_user_modes = Channel_UserModes(Chan, c);
|
chan_user_modes = Channel_UserModes(Chan, c);
|
||||||
strlcat(flags, who_flags_qualifier(chan_user_modes),
|
strlcat(flags, who_flags_qualifier(c, chan_user_modes),
|
||||||
sizeof(flags));
|
sizeof(flags));
|
||||||
|
|
||||||
if (!write_whoreply(Client, c, Channel_Name(Chan),
|
if (!write_whoreply(Client, c, Channel_Name(Chan),
|
||||||
@ -1078,7 +1087,7 @@ IRC_WHOIS_SendReply(CLIENT *Client, CLIENT *from, CLIENT *c)
|
|||||||
if (str[strlen(str) - 1] != ':')
|
if (str[strlen(str) - 1] != ':')
|
||||||
strlcat(str, " ", sizeof(str));
|
strlcat(str, " ", sizeof(str));
|
||||||
|
|
||||||
strlcat(str, who_flags_qualifier(Channel_UserModes(chan, c)),
|
strlcat(str, who_flags_qualifier(c, Channel_UserModes(chan, c)),
|
||||||
sizeof(str));
|
sizeof(str));
|
||||||
strlcat(str, Channel_Name(chan), sizeof(str));
|
strlcat(str, Channel_Name(chan), sizeof(str));
|
||||||
|
|
||||||
@ -1524,60 +1533,77 @@ IRC_Show_MOTD( CLIENT *Client )
|
|||||||
} /* IRC_Show_MOTD */
|
} /* IRC_Show_MOTD */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send NAMES reply for a specific client and channel.
|
||||||
|
*
|
||||||
|
* @param Client The client requesting the NAMES information.
|
||||||
|
* @param Chan The channel
|
||||||
|
* @return CONNECTED or DISCONNECTED.
|
||||||
|
*/
|
||||||
GLOBAL bool
|
GLOBAL bool
|
||||||
IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan )
|
IRC_Send_NAMES(CLIENT * Client, CHANNEL * Chan)
|
||||||
{
|
{
|
||||||
bool is_visible, is_member;
|
bool is_visible, is_member;
|
||||||
char str[LINE_LEN + 1];
|
char str[LINE_LEN + 1];
|
||||||
CL2CHAN *cl2chan;
|
CL2CHAN *cl2chan;
|
||||||
CLIENT *cl;
|
CLIENT *cl;
|
||||||
|
|
||||||
assert( Client != NULL );
|
assert(Client != NULL);
|
||||||
assert( Chan != NULL );
|
assert(Chan != NULL);
|
||||||
|
|
||||||
if( Channel_IsMemberOf( Chan, Client )) is_member = true;
|
if (Channel_IsMemberOf(Chan, Client))
|
||||||
else is_member = false;
|
is_member = true;
|
||||||
|
else
|
||||||
|
is_member = false;
|
||||||
|
|
||||||
/* Do not print info on channel memberships to anyone that is not member? */
|
/* Do not print info on channel memberships to anyone that is not member? */
|
||||||
if (Conf_MorePrivacy && !is_member)
|
if (Conf_MorePrivacy && !is_member)
|
||||||
return CONNECTED;
|
return CONNECTED;
|
||||||
|
|
||||||
/* Secret channel? */
|
/* Secret channel? */
|
||||||
if( ! is_member && strchr( Channel_Modes( Chan ), 's' )) return CONNECTED;
|
if (!is_member && strchr(Channel_Modes(Chan), 's'))
|
||||||
|
return CONNECTED;
|
||||||
|
|
||||||
/* Alle Mitglieder suchen */
|
snprintf(str, sizeof(str), RPL_NAMREPLY_MSG, Client_ID(Client), "=",
|
||||||
snprintf( str, sizeof( str ), RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
|
Channel_Name(Chan));
|
||||||
cl2chan = Channel_FirstMember( Chan );
|
cl2chan = Channel_FirstMember(Chan);
|
||||||
while( cl2chan )
|
while (cl2chan) {
|
||||||
{
|
cl = Channel_GetClient(cl2chan);
|
||||||
cl = Channel_GetClient( cl2chan );
|
|
||||||
|
|
||||||
if( strchr( Client_Modes( cl ), 'i' )) is_visible = false;
|
if (strchr(Client_Modes(cl), 'i'))
|
||||||
else is_visible = true;
|
is_visible = false;
|
||||||
|
else
|
||||||
|
is_visible = true;
|
||||||
|
|
||||||
if( is_member || is_visible )
|
if (is_member || is_visible) {
|
||||||
{
|
if (str[strlen(str) - 1] != ':')
|
||||||
/* Nick anhaengen */
|
strlcat(str, " ", sizeof(str));
|
||||||
if( str[strlen( str ) - 1] != ':' ) strlcat( str, " ", sizeof( str ));
|
if (Client_Cap(cl) & CLIENT_CAP_MULTI_PREFIX) {
|
||||||
if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strlcat( str, "@", sizeof( str ));
|
if (strchr(Channel_UserModes(Chan, cl), 'o') &&
|
||||||
else if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strlcat( str, "+", sizeof( str ));
|
strchr(Channel_UserModes(Chan, cl), 'v'))
|
||||||
strlcat( str, Client_ID( cl ), sizeof( str ));
|
strlcat(str, "@+", sizeof(str));
|
||||||
|
} else {
|
||||||
|
if (strchr(Channel_UserModes(Chan, cl), 'o'))
|
||||||
|
strlcat(str, "@", sizeof(str));
|
||||||
|
else if (strchr(Channel_UserModes(Chan, cl), 'v'))
|
||||||
|
strlcat(str, "+", sizeof(str));
|
||||||
|
}
|
||||||
|
strlcat(str, Client_ID(cl), sizeof(str));
|
||||||
|
|
||||||
if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
|
if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 4)) {
|
||||||
{
|
if (!IRC_WriteStrClient(Client, "%s", str))
|
||||||
/* Zeile wird zu lang: senden! */
|
return DISCONNECTED;
|
||||||
if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
|
snprintf(str, sizeof(str), RPL_NAMREPLY_MSG,
|
||||||
snprintf( str, sizeof( str ), RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
|
Client_ID(Client), "=",
|
||||||
|
Channel_Name(Chan));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* naechstes Mitglied suchen */
|
cl2chan = Channel_NextMember(Chan, cl2chan);
|
||||||
cl2chan = Channel_NextMember( Chan, cl2chan );
|
|
||||||
}
|
}
|
||||||
if( str[strlen( str ) - 1] != ':')
|
if (str[strlen(str) - 1] != ':') {
|
||||||
{
|
if (!IRC_WriteStrClient(Client, "%s", str))
|
||||||
/* Es sind noch Daten da, die gesendet werden muessen */
|
return DISCONNECTED;
|
||||||
if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return CONNECTED;
|
return CONNECTED;
|
||||||
|
@ -18,22 +18,16 @@
|
|||||||
|
|
||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <signal.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "ngircd.h"
|
|
||||||
#include "conn-func.h"
|
#include "conn-func.h"
|
||||||
#include "class.h"
|
#include "class.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "channel.h"
|
#include "channel.h"
|
||||||
#include "io.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "login.h"
|
||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
#include "pam.h"
|
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
#include "irc.h"
|
#include "irc.h"
|
||||||
#include "irc-info.h"
|
#include "irc-info.h"
|
||||||
@ -42,18 +36,7 @@
|
|||||||
#include "exp.h"
|
#include "exp.h"
|
||||||
#include "irc-login.h"
|
#include "irc-login.h"
|
||||||
|
|
||||||
|
|
||||||
static bool Hello_User PARAMS(( CLIENT *Client ));
|
|
||||||
static bool Hello_User_PostAuth PARAMS(( CLIENT *Client ));
|
|
||||||
static void Kill_Nick PARAMS(( char *Nick, char *Reason ));
|
static void Kill_Nick PARAMS(( char *Nick, char *Reason ));
|
||||||
static void Introduce_Client PARAMS((CLIENT *To, CLIENT *Client, int Type));
|
|
||||||
|
|
||||||
static void cb_introduceClient PARAMS((CLIENT *Client, CLIENT *Prefix,
|
|
||||||
void *i));
|
|
||||||
|
|
||||||
#ifdef PAM
|
|
||||||
static void cb_Read_Auth_Result PARAMS((int r_fd, UNUSED short events));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for the IRC "PASS" command.
|
* Handler for the IRC "PASS" command.
|
||||||
@ -285,7 +268,7 @@ IRC_NICK( CLIENT *Client, REQUEST *Req )
|
|||||||
/* If we received a valid USER command already then
|
/* If we received a valid USER command already then
|
||||||
* register the new client! */
|
* register the new client! */
|
||||||
if( Client_Type( Client ) == CLIENT_GOTUSER )
|
if( Client_Type( Client ) == CLIENT_GOTUSER )
|
||||||
return Hello_User( Client );
|
return Login_User( Client );
|
||||||
else
|
else
|
||||||
Client_SetType( Client, CLIENT_GOTNICK );
|
Client_SetType( Client, CLIENT_GOTNICK );
|
||||||
} else {
|
} else {
|
||||||
@ -395,7 +378,7 @@ IRC_NICK( CLIENT *Client, REQUEST *Req )
|
|||||||
Client_Mask(c));
|
Client_Mask(c));
|
||||||
Client_SetType(c, CLIENT_GOTNICK);
|
Client_SetType(c, CLIENT_GOTNICK);
|
||||||
} else
|
} else
|
||||||
Introduce_Client(Client, c, CLIENT_USER);
|
Client_Introduce(Client, c, CLIENT_USER);
|
||||||
|
|
||||||
return CONNECTED;
|
return CONNECTED;
|
||||||
}
|
}
|
||||||
@ -457,7 +440,7 @@ IRC_USER(CLIENT * Client, REQUEST * Req)
|
|||||||
LogDebug("Connection %d: got valid USER command ...",
|
LogDebug("Connection %d: got valid USER command ...",
|
||||||
Client_Conn(Client));
|
Client_Conn(Client));
|
||||||
if (Client_Type(Client) == CLIENT_GOTNICK)
|
if (Client_Type(Client) == CLIENT_GOTNICK)
|
||||||
return Hello_User(Client);
|
return Login_User(Client);
|
||||||
else
|
else
|
||||||
Client_SetType(Client, CLIENT_GOTUSER);
|
Client_SetType(Client, CLIENT_GOTUSER);
|
||||||
return CONNECTED;
|
return CONNECTED;
|
||||||
@ -487,7 +470,7 @@ IRC_USER(CLIENT * Client, REQUEST * Req)
|
|||||||
/* RFC 1459 style user registration?
|
/* RFC 1459 style user registration?
|
||||||
* Introduce client to network: */
|
* Introduce client to network: */
|
||||||
if (Client_Type(c) == CLIENT_GOTNICK)
|
if (Client_Type(c) == CLIENT_GOTNICK)
|
||||||
Introduce_Client(Client, c, CLIENT_USER);
|
Client_Introduce(Client, c, CLIENT_USER);
|
||||||
|
|
||||||
return CONNECTED;
|
return CONNECTED;
|
||||||
} else if (Client_Type(Client) == CLIENT_USER) {
|
} else if (Client_Type(Client) == CLIENT_USER) {
|
||||||
@ -601,7 +584,7 @@ IRC_SERVICE(CLIENT *Client, REQUEST *Req)
|
|||||||
return CONNECTED;
|
return CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
Introduce_Client(Client, c, CLIENT_SERVICE);
|
Client_Introduce(Client, c, CLIENT_SERVICE);
|
||||||
return CONNECTED;
|
return CONNECTED;
|
||||||
} /* IRC_SERVICE */
|
} /* IRC_SERVICE */
|
||||||
|
|
||||||
@ -880,7 +863,7 @@ IRC_PONG(CLIENT *Client, REQUEST *Req)
|
|||||||
if (auth_ping == atoi(Req->argv[0])) {
|
if (auth_ping == atoi(Req->argv[0])) {
|
||||||
Conn_SetAuthPing(conn, 0);
|
Conn_SetAuthPing(conn, 0);
|
||||||
if (Client_Type(Client) == CLIENT_WAITAUTHPING)
|
if (Client_Type(Client) == CLIENT_WAITAUTHPING)
|
||||||
Hello_User(Client);
|
Login_User(Client);
|
||||||
} else
|
} else
|
||||||
if (!IRC_WriteStrClient(Client,
|
if (!IRC_WriteStrClient(Client,
|
||||||
"To connect, type /QUOTE PONG %ld",
|
"To connect, type /QUOTE PONG %ld",
|
||||||
@ -903,196 +886,6 @@ IRC_PONG(CLIENT *Client, REQUEST *Req)
|
|||||||
} /* IRC_PONG */
|
} /* IRC_PONG */
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initiate client registration.
|
|
||||||
*
|
|
||||||
* This function is called after the daemon received the required NICK and
|
|
||||||
* USER commands of a new client. If the daemon is compiled with support for
|
|
||||||
* PAM, the authentication sub-processs is forked; otherwise the global server
|
|
||||||
* password is checked.
|
|
||||||
*
|
|
||||||
* @param Client The client logging in.
|
|
||||||
* @returns CONNECTED or DISCONNECTED.
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
Hello_User(CLIENT * Client)
|
|
||||||
{
|
|
||||||
#ifdef PAM
|
|
||||||
int pipefd[2], result;
|
|
||||||
pid_t pid;
|
|
||||||
#endif
|
|
||||||
CONN_ID conn;
|
|
||||||
|
|
||||||
assert(Client != NULL);
|
|
||||||
conn = Client_Conn(Client);
|
|
||||||
|
|
||||||
#ifndef STRICT_RFC
|
|
||||||
if (Conf_AuthPing) {
|
|
||||||
/* Did we receive the "auth PONG" already? */
|
|
||||||
if (Conn_GetAuthPing(conn)) {
|
|
||||||
Client_SetType(Client, CLIENT_WAITAUTHPING);
|
|
||||||
LogDebug("Connection %d: Waiting for AUTH PONG ...", conn);
|
|
||||||
return CONNECTED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PAM
|
|
||||||
if (!Conf_PAM) {
|
|
||||||
/* Don't do any PAM authentication at all, instead emulate
|
|
||||||
* the beahiour of the daemon compiled without PAM support:
|
|
||||||
* because there can't be any "server password", all
|
|
||||||
* passwords supplied are classified as "wrong". */
|
|
||||||
if(Client_Password(Client)[0] == '\0')
|
|
||||||
return Hello_User_PostAuth(Client);
|
|
||||||
Client_Reject(Client, "Non-empty password", false);
|
|
||||||
return DISCONNECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Conf_PAMIsOptional && strcmp(Client_Password(Client), "") == 0) {
|
|
||||||
/* Clients are not required to send a password and to be PAM-
|
|
||||||
* authenticated at all. If not, they won't become "identified"
|
|
||||||
* and keep the "~" in their supplied user name.
|
|
||||||
* Therefore it is sensible to either set Conf_PAMisOptional or
|
|
||||||
* to enable IDENT lookups -- not both. */
|
|
||||||
return Hello_User_PostAuth(Client);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fork child process for PAM authentication; and make sure that the
|
|
||||||
* process timeout is set higher than the login timeout! */
|
|
||||||
pid = Proc_Fork(Conn_GetProcStat(conn), pipefd,
|
|
||||||
cb_Read_Auth_Result, Conf_PongTimeout + 1);
|
|
||||||
if (pid > 0) {
|
|
||||||
LogDebug("Authenticator for connection %d created (PID %d).",
|
|
||||||
conn, pid);
|
|
||||||
return CONNECTED;
|
|
||||||
} else {
|
|
||||||
/* Sub process */
|
|
||||||
Log_Init_Subprocess("Auth");
|
|
||||||
Conn_CloseAllSockets(NONE);
|
|
||||||
result = PAM_Authenticate(Client);
|
|
||||||
if (write(pipefd[1], &result, sizeof(result)) != sizeof(result))
|
|
||||||
Log_Subprocess(LOG_ERR,
|
|
||||||
"Failed to pipe result to parent!");
|
|
||||||
Log_Exit_Subprocess("Auth");
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* Check global server password ... */
|
|
||||||
if (strcmp(Client_Password(Client), Conf_ServerPwd) != 0) {
|
|
||||||
/* Bad password! */
|
|
||||||
Client_Reject(Client, "Bad server password", false);
|
|
||||||
return DISCONNECTED;
|
|
||||||
}
|
|
||||||
return Hello_User_PostAuth(Client);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef PAM
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read result of the authenticatior sub-process from pipe
|
|
||||||
*
|
|
||||||
* @param r_fd File descriptor of the pipe.
|
|
||||||
* @param events (ignored IO specification)
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
cb_Read_Auth_Result(int r_fd, UNUSED short events)
|
|
||||||
{
|
|
||||||
CONN_ID conn;
|
|
||||||
CLIENT *client;
|
|
||||||
int result;
|
|
||||||
size_t len;
|
|
||||||
PROC_STAT *proc;
|
|
||||||
|
|
||||||
LogDebug("Auth: Got callback on fd %d, events %d", r_fd, events);
|
|
||||||
conn = Conn_GetFromProc(r_fd);
|
|
||||||
if (conn == NONE) {
|
|
||||||
/* Ops, none found? Probably the connection has already
|
|
||||||
* been closed!? We'll ignore that ... */
|
|
||||||
io_close(r_fd);
|
|
||||||
LogDebug("Auth: Got callback for unknown connection!?");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
proc = Conn_GetProcStat(conn);
|
|
||||||
client = Conn_GetClient(conn);
|
|
||||||
|
|
||||||
/* Read result from pipe */
|
|
||||||
len = Proc_Read(proc, &result, sizeof(result));
|
|
||||||
Proc_Close(proc);
|
|
||||||
if (len == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (len != sizeof(result)) {
|
|
||||||
Log(LOG_CRIT, "Auth: Got malformed result!");
|
|
||||||
Client_Reject(client, "Internal error", false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == true) {
|
|
||||||
Client_SetUser(client, Client_OrigUser(client), true);
|
|
||||||
(void)Hello_User_PostAuth(client);
|
|
||||||
} else
|
|
||||||
Client_Reject(client, "Bad password", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finish client registration.
|
|
||||||
*
|
|
||||||
* Introduce the new client to the network and send all "hello messages"
|
|
||||||
* to it after authentication has been succeeded.
|
|
||||||
*
|
|
||||||
* @param Client The client logging in.
|
|
||||||
* @returns CONNECTED or DISCONNECTED.
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
Hello_User_PostAuth(CLIENT *Client)
|
|
||||||
{
|
|
||||||
assert(Client != NULL);
|
|
||||||
|
|
||||||
if (Class_HandleServerBans(Client) != CONNECTED)
|
|
||||||
return DISCONNECTED;
|
|
||||||
|
|
||||||
Introduce_Client(NULL, Client, CLIENT_USER);
|
|
||||||
|
|
||||||
if (!IRC_WriteStrClient
|
|
||||||
(Client, RPL_WELCOME_MSG, Client_ID(Client), Client_Mask(Client)))
|
|
||||||
return false;
|
|
||||||
if (!IRC_WriteStrClient
|
|
||||||
(Client, RPL_YOURHOST_MSG, Client_ID(Client),
|
|
||||||
Client_ID(Client_ThisServer()), PACKAGE_VERSION, TARGET_CPU,
|
|
||||||
TARGET_VENDOR, TARGET_OS))
|
|
||||||
return false;
|
|
||||||
if (!IRC_WriteStrClient
|
|
||||||
(Client, RPL_CREATED_MSG, Client_ID(Client), NGIRCd_StartStr))
|
|
||||||
return false;
|
|
||||||
if (!IRC_WriteStrClient
|
|
||||||
(Client, RPL_MYINFO_MSG, Client_ID(Client),
|
|
||||||
Client_ID(Client_ThisServer()), PACKAGE_VERSION, USERMODES,
|
|
||||||
CHANMODES))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Features supported by this server (005 numeric, ISUPPORT),
|
|
||||||
* see <http://www.irc.org/tech_docs/005.html> for details. */
|
|
||||||
if (!IRC_Send_ISUPPORT(Client))
|
|
||||||
return DISCONNECTED;
|
|
||||||
|
|
||||||
if (!IRC_Send_LUSERS(Client))
|
|
||||||
return DISCONNECTED;
|
|
||||||
if (!IRC_Show_MOTD(Client))
|
|
||||||
return DISCONNECTED;
|
|
||||||
|
|
||||||
/* Suspend the client for a second ... */
|
|
||||||
IRC_SetPenalty(Client, 1);
|
|
||||||
|
|
||||||
return CONNECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kill all users with a specific nick name in the network.
|
* Kill all users with a specific nick name in the network.
|
||||||
*
|
*
|
||||||
@ -1119,97 +912,4 @@ Kill_Nick(char *Nick, char *Reason)
|
|||||||
} /* Kill_Nick */
|
} /* Kill_Nick */
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Introduce a new user or service client in the network.
|
|
||||||
*
|
|
||||||
* @param From Remote server introducing the client or NULL (local).
|
|
||||||
* @param Client New client.
|
|
||||||
* @param Type Type of the client (CLIENT_USER or CLIENT_SERVICE).
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
Introduce_Client(CLIENT *From, CLIENT *Client, int Type)
|
|
||||||
{
|
|
||||||
/* Set client type (user or service) */
|
|
||||||
Client_SetType(Client, Type);
|
|
||||||
|
|
||||||
if (From) {
|
|
||||||
if (Conf_IsService(Conf_GetServer(Client_Conn(From)),
|
|
||||||
Client_ID(Client)))
|
|
||||||
Client_SetType(Client, CLIENT_SERVICE);
|
|
||||||
LogDebug("%s \"%s\" (+%s) registered (via %s, on %s, %d hop%s).",
|
|
||||||
Client_TypeText(Client), Client_Mask(Client),
|
|
||||||
Client_Modes(Client), Client_ID(From),
|
|
||||||
Client_ID(Client_Introducer(Client)),
|
|
||||||
Client_Hops(Client), Client_Hops(Client) > 1 ? "s": "");
|
|
||||||
} else {
|
|
||||||
Log(LOG_NOTICE, "%s \"%s\" registered (connection %d).",
|
|
||||||
Client_TypeText(Client), Client_Mask(Client),
|
|
||||||
Client_Conn(Client));
|
|
||||||
Log_ServerNotice('c', "Client connecting: %s (%s@%s) [%s] - %s",
|
|
||||||
Client_ID(Client), Client_User(Client),
|
|
||||||
Client_Hostname(Client),
|
|
||||||
Conn_IPA(Client_Conn(Client)),
|
|
||||||
Client_TypeText(Client));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Inform other servers */
|
|
||||||
IRC_WriteStrServersPrefixFlag_CB(From,
|
|
||||||
From != NULL ? From : Client_ThisServer(),
|
|
||||||
'\0', cb_introduceClient, (void *)Client);
|
|
||||||
} /* Introduce_Client */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Introduce a new user or service client to a remote server.
|
|
||||||
*
|
|
||||||
* This function differentiates between RFC1459 and RFC2813 server links and
|
|
||||||
* generates the appropriate commands to register the new user or service.
|
|
||||||
*
|
|
||||||
* @param To The remote server to inform.
|
|
||||||
* @param Prefix Prefix for the generated commands.
|
|
||||||
* @param data CLIENT structure of the new client.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
cb_introduceClient(CLIENT *To, CLIENT *Prefix, void *data)
|
|
||||||
{
|
|
||||||
CLIENT *c = (CLIENT *)data;
|
|
||||||
CONN_ID conn;
|
|
||||||
char *modes, *user, *host;
|
|
||||||
|
|
||||||
modes = Client_Modes(c);
|
|
||||||
user = Client_User(c) ? Client_User(c) : "-";
|
|
||||||
host = Client_Hostname(c) ? Client_Hostname(c) : "-";
|
|
||||||
|
|
||||||
conn = Client_Conn(To);
|
|
||||||
if (Conn_Options(conn) & CONN_RFC1459) {
|
|
||||||
/* RFC 1459 mode: separate NICK and USER commands */
|
|
||||||
Conn_WriteStr(conn, "NICK %s :%d", Client_ID(c),
|
|
||||||
Client_Hops(c) + 1);
|
|
||||||
Conn_WriteStr(conn, ":%s USER %s %s %s :%s",
|
|
||||||
Client_ID(c), user, host,
|
|
||||||
Client_ID(Client_Introducer(c)), Client_Info(c));
|
|
||||||
if (modes[0])
|
|
||||||
Conn_WriteStr(conn, ":%s MODE %s +%s",
|
|
||||||
Client_ID(c), Client_ID(c), modes);
|
|
||||||
} else {
|
|
||||||
/* RFC 2813 mode: one combined NICK or SERVICE command */
|
|
||||||
if (Client_Type(c) == CLIENT_SERVICE
|
|
||||||
&& strchr(Client_Flags(To), 'S'))
|
|
||||||
IRC_WriteStrClientPrefix(To, Prefix,
|
|
||||||
"SERVICE %s %d * +%s %d :%s",
|
|
||||||
Client_Mask(c),
|
|
||||||
Client_MyToken(Client_Introducer(c)),
|
|
||||||
Client_Modes(c), Client_Hops(c) + 1,
|
|
||||||
Client_Info(c));
|
|
||||||
else
|
|
||||||
IRC_WriteStrClientPrefix(To, Prefix,
|
|
||||||
"NICK %s %d %s %s %d +%s :%s",
|
|
||||||
Client_ID(c), Client_Hops(c) + 1,
|
|
||||||
user, host,
|
|
||||||
Client_MyToken(Client_Introducer(c)),
|
|
||||||
modes, Client_Info(c));
|
|
||||||
}
|
|
||||||
} /* cb_introduceClient */
|
|
||||||
|
|
||||||
|
|
||||||
/* -eof- */
|
/* -eof- */
|
||||||
|
242
src/ngircd/login.c
Normal file
242
src/ngircd/login.c
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
/*
|
||||||
|
* ngIRCd -- The Next Generation IRC Daemon
|
||||||
|
* Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* Please read the file COPYING, README and AUTHORS for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "portab.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Functions to deal with client logins
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "imp.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
#include "conn.h"
|
||||||
|
#include "class.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "client-cap.h"
|
||||||
|
#include "channel.h"
|
||||||
|
#include "conf.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "parse.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "messages.h"
|
||||||
|
#include "ngircd.h"
|
||||||
|
#include "pam.h"
|
||||||
|
#include "irc-info.h"
|
||||||
|
#include "irc-write.h"
|
||||||
|
|
||||||
|
#include "exp.h"
|
||||||
|
#include "login.h"
|
||||||
|
|
||||||
|
#ifdef PAM
|
||||||
|
static void cb_Read_Auth_Result PARAMS((int r_fd, UNUSED short events));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiate client login.
|
||||||
|
*
|
||||||
|
* This function is called after the daemon received the required NICK and
|
||||||
|
* USER commands of a new client. If the daemon is compiled with support for
|
||||||
|
* PAM, the authentication sub-processs is forked; otherwise the global server
|
||||||
|
* password is checked.
|
||||||
|
*
|
||||||
|
* @param Client The client logging in.
|
||||||
|
* @returns CONNECTED or DISCONNECTED.
|
||||||
|
*/
|
||||||
|
GLOBAL bool
|
||||||
|
Login_User(CLIENT * Client)
|
||||||
|
{
|
||||||
|
#ifdef PAM
|
||||||
|
int pipefd[2], result;
|
||||||
|
pid_t pid;
|
||||||
|
#endif
|
||||||
|
CONN_ID conn;
|
||||||
|
|
||||||
|
assert(Client != NULL);
|
||||||
|
conn = Client_Conn(Client);
|
||||||
|
|
||||||
|
#ifndef STRICT_RFC
|
||||||
|
if (Conf_AuthPing) {
|
||||||
|
/* Did we receive the "auth PONG" already? */
|
||||||
|
if (Conn_GetAuthPing(conn)) {
|
||||||
|
Client_SetType(Client, CLIENT_WAITAUTHPING);
|
||||||
|
LogDebug("Connection %d: Waiting for AUTH PONG ...", conn);
|
||||||
|
return CONNECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Still waiting for "CAP END" command? */
|
||||||
|
if (Client_Cap(Client) & CLIENT_CAP_PENDING) {
|
||||||
|
Client_SetType(Client, CLIENT_WAITCAPEND);
|
||||||
|
LogDebug("Connection %d: Waiting for CAP END ...", conn);
|
||||||
|
return CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PAM
|
||||||
|
if (!Conf_PAM) {
|
||||||
|
/* Don't do any PAM authentication at all, instead emulate
|
||||||
|
* the beahiour of the daemon compiled without PAM support:
|
||||||
|
* because there can't be any "server password", all
|
||||||
|
* passwords supplied are classified as "wrong". */
|
||||||
|
if(Client_Password(Client)[0] == '\0')
|
||||||
|
return Login_User_PostAuth(Client);
|
||||||
|
Client_Reject(Client, "Non-empty password", false);
|
||||||
|
return DISCONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Conf_PAMIsOptional && strcmp(Client_Password(Client), "") == 0) {
|
||||||
|
/* Clients are not required to send a password and to be PAM-
|
||||||
|
* authenticated at all. If not, they won't become "identified"
|
||||||
|
* and keep the "~" in their supplied user name.
|
||||||
|
* Therefore it is sensible to either set Conf_PAMisOptional or
|
||||||
|
* to enable IDENT lookups -- not both. */
|
||||||
|
return Login_User_PostAuth(Client);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fork child process for PAM authentication; and make sure that the
|
||||||
|
* process timeout is set higher than the login timeout! */
|
||||||
|
pid = Proc_Fork(Conn_GetProcStat(conn), pipefd,
|
||||||
|
cb_Read_Auth_Result, Conf_PongTimeout + 1);
|
||||||
|
if (pid > 0) {
|
||||||
|
LogDebug("Authenticator for connection %d created (PID %d).",
|
||||||
|
conn, pid);
|
||||||
|
return CONNECTED;
|
||||||
|
} else {
|
||||||
|
/* Sub process */
|
||||||
|
Log_Init_Subprocess("Auth");
|
||||||
|
Conn_CloseAllSockets(NONE);
|
||||||
|
result = PAM_Authenticate(Client);
|
||||||
|
if (write(pipefd[1], &result, sizeof(result)) != sizeof(result))
|
||||||
|
Log_Subprocess(LOG_ERR,
|
||||||
|
"Failed to pipe result to parent!");
|
||||||
|
Log_Exit_Subprocess("Auth");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* Check global server password ... */
|
||||||
|
if (strcmp(Client_Password(Client), Conf_ServerPwd) != 0) {
|
||||||
|
/* Bad password! */
|
||||||
|
Client_Reject(Client, "Bad server password", false);
|
||||||
|
return DISCONNECTED;
|
||||||
|
}
|
||||||
|
return Login_User_PostAuth(Client);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish client registration.
|
||||||
|
*
|
||||||
|
* Introduce the new client to the network and send all "hello messages"
|
||||||
|
* to it after authentication has been succeeded.
|
||||||
|
*
|
||||||
|
* @param Client The client logging in.
|
||||||
|
* @return CONNECTED or DISCONNECTED.
|
||||||
|
*/
|
||||||
|
GLOBAL bool
|
||||||
|
Login_User_PostAuth(CLIENT *Client)
|
||||||
|
{
|
||||||
|
assert(Client != NULL);
|
||||||
|
|
||||||
|
if (Class_HandleServerBans(Client) != CONNECTED)
|
||||||
|
return DISCONNECTED;
|
||||||
|
|
||||||
|
Client_Introduce(NULL, Client, CLIENT_USER);
|
||||||
|
|
||||||
|
if (!IRC_WriteStrClient
|
||||||
|
(Client, RPL_WELCOME_MSG, Client_ID(Client), Client_Mask(Client)))
|
||||||
|
return false;
|
||||||
|
if (!IRC_WriteStrClient
|
||||||
|
(Client, RPL_YOURHOST_MSG, Client_ID(Client),
|
||||||
|
Client_ID(Client_ThisServer()), PACKAGE_VERSION, TARGET_CPU,
|
||||||
|
TARGET_VENDOR, TARGET_OS))
|
||||||
|
return false;
|
||||||
|
if (!IRC_WriteStrClient
|
||||||
|
(Client, RPL_CREATED_MSG, Client_ID(Client), NGIRCd_StartStr))
|
||||||
|
return false;
|
||||||
|
if (!IRC_WriteStrClient
|
||||||
|
(Client, RPL_MYINFO_MSG, Client_ID(Client),
|
||||||
|
Client_ID(Client_ThisServer()), PACKAGE_VERSION, USERMODES,
|
||||||
|
CHANMODES))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Features supported by this server (005 numeric, ISUPPORT),
|
||||||
|
* see <http://www.irc.org/tech_docs/005.html> for details. */
|
||||||
|
if (!IRC_Send_ISUPPORT(Client))
|
||||||
|
return DISCONNECTED;
|
||||||
|
|
||||||
|
if (!IRC_Send_LUSERS(Client))
|
||||||
|
return DISCONNECTED;
|
||||||
|
if (!IRC_Show_MOTD(Client))
|
||||||
|
return DISCONNECTED;
|
||||||
|
|
||||||
|
/* Suspend the client for a second ... */
|
||||||
|
IRC_SetPenalty(Client, 1);
|
||||||
|
|
||||||
|
return CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PAM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read result of the authenticatior sub-process from pipe
|
||||||
|
*
|
||||||
|
* @param r_fd File descriptor of the pipe.
|
||||||
|
* @param events (ignored IO specification)
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
cb_Read_Auth_Result(int r_fd, UNUSED short events)
|
||||||
|
{
|
||||||
|
CONN_ID conn;
|
||||||
|
CLIENT *client;
|
||||||
|
int result;
|
||||||
|
size_t len;
|
||||||
|
PROC_STAT *proc;
|
||||||
|
|
||||||
|
LogDebug("Auth: Got callback on fd %d, events %d", r_fd, events);
|
||||||
|
conn = Conn_GetFromProc(r_fd);
|
||||||
|
if (conn == NONE) {
|
||||||
|
/* Ops, none found? Probably the connection has already
|
||||||
|
* been closed!? We'll ignore that ... */
|
||||||
|
io_close(r_fd);
|
||||||
|
LogDebug("Auth: Got callback for unknown connection!?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
proc = Conn_GetProcStat(conn);
|
||||||
|
client = Conn_GetClient(conn);
|
||||||
|
|
||||||
|
/* Read result from pipe */
|
||||||
|
len = Proc_Read(proc, &result, sizeof(result));
|
||||||
|
Proc_Close(proc);
|
||||||
|
if (len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (len != sizeof(result)) {
|
||||||
|
Log(LOG_CRIT, "Auth: Got malformed result!");
|
||||||
|
Client_Reject(client, "Internal error", false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == true) {
|
||||||
|
Client_SetUser(client, Client_OrigUser(client), true);
|
||||||
|
(void)Login_User_PostAuth(client);
|
||||||
|
} else
|
||||||
|
Client_Reject(client, "Bad password", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* -eof- */
|
25
src/ngircd/login.h
Normal file
25
src/ngircd/login.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* ngIRCd -- The Next Generation IRC Daemon
|
||||||
|
* Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
* Please read the file COPYING, README and AUTHORS for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __login_h__
|
||||||
|
#define __login_h__
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Functions to deal with client logins (header)
|
||||||
|
*/
|
||||||
|
|
||||||
|
GLOBAL bool Login_User PARAMS((CLIENT * Client));
|
||||||
|
GLOBAL bool Login_User_PostAuth PARAMS((CLIENT *Client));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* -eof- */
|
@ -103,6 +103,7 @@
|
|||||||
#define ERR_TOOMANYCHANNELS_MSG "405 %s %s :You have joined too many channels"
|
#define ERR_TOOMANYCHANNELS_MSG "405 %s %s :You have joined too many channels"
|
||||||
#define ERR_WASNOSUCHNICK_MSG "406 %s %s :There was no such nickname"
|
#define ERR_WASNOSUCHNICK_MSG "406 %s %s :There was no such nickname"
|
||||||
#define ERR_NOORIGIN_MSG "409 %s :No origin specified"
|
#define ERR_NOORIGIN_MSG "409 %s :No origin specified"
|
||||||
|
#define ERR_INVALIDCAP_MSG "410 %s %s :Invalid CAP subcommand"
|
||||||
#define ERR_NORECIPIENT_MSG "411 %s :No recipient given (%s)"
|
#define ERR_NORECIPIENT_MSG "411 %s :No recipient given (%s)"
|
||||||
#define ERR_NOTEXTTOSEND_MSG "412 %s :No text to send"
|
#define ERR_NOTEXTTOSEND_MSG "412 %s :No text to send"
|
||||||
#define ERR_WILDTOPLEVEL "414 %s :Wildcard in toplevel domain"
|
#define ERR_WILDTOPLEVEL "414 %s :Wildcard in toplevel domain"
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
#include "irc.h"
|
#include "irc.h"
|
||||||
|
#include "irc-cap.h"
|
||||||
#include "irc-channel.h"
|
#include "irc-channel.h"
|
||||||
#include "irc-info.h"
|
#include "irc-info.h"
|
||||||
#include "irc-login.h"
|
#include "irc-login.h"
|
||||||
@ -113,6 +114,7 @@ static COMMAND My_Commands[] =
|
|||||||
{ "CHANINFO", IRC_CHANINFO, CLIENT_SERVER, 0, 0, 0 },
|
{ "CHANINFO", IRC_CHANINFO, CLIENT_SERVER, 0, 0, 0 },
|
||||||
#endif
|
#endif
|
||||||
#ifndef STRICT_RFC
|
#ifndef STRICT_RFC
|
||||||
|
{ "CAP", IRC_CAP, 0xFFFF, 0, 0, 0 },
|
||||||
{ "GET", IRC_QUIT_HTTP, CLIENT_UNKNOWN, 0, 0, 0 },
|
{ "GET", IRC_QUIT_HTTP, CLIENT_UNKNOWN, 0, 0, 0 },
|
||||||
{ "POST", IRC_QUIT_HTTP, CLIENT_UNKNOWN, 0, 0, 0 },
|
{ "POST", IRC_QUIT_HTTP, CLIENT_UNKNOWN, 0, 0, 0 },
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user