]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_sslinfo.cpp
Replace some C-isms with C++-isms.
[user/henk/code/inspircd.git] / src / modules / m_sslinfo.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
5  *
6  * This file is part of InspIRCd.  InspIRCd is free software: you can
7  * redistribute it and/or modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation, version 2.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
13  * details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19
20 #include "inspircd.h"
21 #include "modules/ssl.h"
22
23 /* $ModDesc: Provides SSL metadata, including /WHOIS information and /SSLINFO command */
24
25 class SSLCertExt : public ExtensionItem {
26  public:
27         SSLCertExt(Module* parent) : ExtensionItem("ssl_cert", parent) {}
28         ssl_cert* get(const Extensible* item) const
29         {
30                 return static_cast<ssl_cert*>(get_raw(item));
31         }
32         void set(Extensible* item, ssl_cert* value)
33         {
34                 value->refcount_inc();
35                 ssl_cert* old = static_cast<ssl_cert*>(set_raw(item, value));
36                 if (old && old->refcount_dec())
37                         delete old;
38         }
39
40         std::string serialize(SerializeFormat format, const Extensible* container, void* item) const
41         {
42                 return static_cast<ssl_cert*>(item)->GetMetaLine();
43         }
44
45         void unserialize(SerializeFormat format, Extensible* container, const std::string& value)
46         {
47                 ssl_cert* cert = new ssl_cert;
48                 set(container, cert);
49
50                 std::stringstream s(value);
51                 std::string v;
52                 getline(s,v,' ');
53
54                 cert->invalid = (v.find('v') != std::string::npos);
55                 cert->trusted = (v.find('T') != std::string::npos);
56                 cert->revoked = (v.find('R') != std::string::npos);
57                 cert->unknownsigner = (v.find('s') != std::string::npos);
58                 if (v.find('E') != std::string::npos)
59                 {
60                         getline(s,cert->error,'\n');
61                 }
62                 else
63                 {
64                         getline(s,cert->fingerprint,' ');
65                         getline(s,cert->dn,' ');
66                         getline(s,cert->issuer,'\n');
67                 }
68         }
69
70         void free(void* item)
71         {
72                 ssl_cert* old = static_cast<ssl_cert*>(item);
73                 if (old && old->refcount_dec())
74                         delete old;
75         }
76 };
77
78 /** Handle /SSLINFO
79  */
80 class CommandSSLInfo : public Command
81 {
82  public:
83         SSLCertExt CertExt;
84
85         CommandSSLInfo(Module* Creator) : Command(Creator, "SSLINFO", 1), CertExt(Creator)
86         {
87                 this->syntax = "<nick>";
88         }
89
90         CmdResult Handle (const std::vector<std::string> &parameters, User *user)
91         {
92                 User* target = ServerInstance->FindNickOnly(parameters[0]);
93
94                 if ((!target) || (target->registered != REG_ALL))
95                 {
96                         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nickname", user->nick.c_str(), parameters[0].c_str());
97                         return CMD_FAILURE;
98                 }
99                 bool operonlyfp = ServerInstance->Config->ConfValue("sslinfo")->getBool("operonly");
100                 if (operonlyfp && !user->IsOper() && target != user)
101                 {
102                         user->WriteNotice("*** You cannot view SSL certificate information for other users");
103                         return CMD_FAILURE;
104                 }
105                 ssl_cert* cert = CertExt.get(target);
106                 if (!cert)
107                 {
108                         user->WriteNotice("*** No SSL certificate for this user");
109                 }
110                 else if (cert->GetError().length())
111                 {
112                         user->WriteNotice("*** No SSL certificate information for this user (" + cert->GetError() + ").");
113                 }
114                 else
115                 {
116                         user->WriteNotice("*** Distinguished Name: " + cert->GetDN());
117                         user->WriteNotice("*** Issuer:             " + cert->GetIssuer());
118                         user->WriteNotice("*** Key Fingerprint:    " + cert->GetFingerprint());
119                 }
120                 return CMD_SUCCESS;
121         }
122 };
123
124 class ModuleSSLInfo : public Module
125 {
126         CommandSSLInfo cmd;
127
128  public:
129         ModuleSSLInfo() : cmd(this)
130         {
131         }
132
133         void init()
134         {
135                 ServerInstance->Modules->AddService(cmd);
136
137                 ServerInstance->Modules->AddService(cmd.CertExt);
138
139                 Implementation eventlist[] = { I_OnWhois, I_OnPreCommand, I_OnSetConnectClass, I_OnUserConnect, I_OnPostConnect };
140                 ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
141         }
142
143         Version GetVersion()
144         {
145                 return Version("SSL Certificate Utilities", VF_VENDOR);
146         }
147
148         void OnWhois(User* source, User* dest)
149         {
150                 ssl_cert* cert = cmd.CertExt.get(dest);
151                 if (cert)
152                 {
153                         ServerInstance->SendWhoisLine(source, dest, 671, "%s %s :is using a secure connection", source->nick.c_str(), dest->nick.c_str());
154                         bool operonlyfp = ServerInstance->Config->ConfValue("sslinfo")->getBool("operonly");
155                         if ((!operonlyfp || source == dest || source->IsOper()) && !cert->fingerprint.empty())
156                                 ServerInstance->SendWhoisLine(source, dest, 276, "%s %s :has client certificate fingerprint %s",
157                                         source->nick.c_str(), dest->nick.c_str(), cert->fingerprint.c_str());
158                 }
159         }
160
161         ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line)
162         {
163                 if ((command == "OPER") && (validated))
164                 {
165                         OperIndex::iterator i = ServerInstance->Config->oper_blocks.find(parameters[0]);
166                         if (i != ServerInstance->Config->oper_blocks.end())
167                         {
168                                 OperInfo* ifo = i->second;
169                                 ssl_cert* cert = cmd.CertExt.get(user);
170
171                                 if (ifo->oper_block->getBool("sslonly") && !cert)
172                                 {
173                                         user->WriteNumeric(491, "%s :This oper login requires an SSL connection.", user->nick.c_str());
174                                         user->CommandFloodPenalty += 10000;
175                                         return MOD_RES_DENY;
176                                 }
177
178                                 std::string fingerprint;
179                                 if (ifo->oper_block->readString("fingerprint", fingerprint) && (!cert || cert->GetFingerprint() != fingerprint))
180                                 {
181                                         user->WriteNumeric(491, "%s :This oper login requires a matching SSL fingerprint.",user->nick.c_str());
182                                         user->CommandFloodPenalty += 10000;
183                                         return MOD_RES_DENY;
184                                 }
185                         }
186                 }
187
188                 // Let core handle it for extra stuff
189                 return MOD_RES_PASSTHRU;
190         }
191
192         void OnUserConnect(LocalUser* user)
193         {
194                 SocketCertificateRequest req(&user->eh, this);
195                 if (!req.cert)
196                         return;
197                 cmd.CertExt.set(user, req.cert);
198         }
199
200         void OnPostConnect(User* user)
201         {
202                 ssl_cert *cert = cmd.CertExt.get(user);
203                 if (!cert || cert->fingerprint.empty())
204                         return;
205                 // find an auto-oper block for this user
206                 for(OperIndex::iterator i = ServerInstance->Config->oper_blocks.begin(); i != ServerInstance->Config->oper_blocks.end(); i++)
207                 {
208                         OperInfo* ifo = i->second;
209                         std::string fp = ifo->oper_block->getString("fingerprint");
210                         if (fp == cert->fingerprint && ifo->oper_block->getBool("autologin"))
211                                 user->Oper(ifo);
212                 }
213         }
214
215         ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass)
216         {
217                 SocketCertificateRequest req(&user->eh, this);
218                 bool ok = true;
219                 if (myclass->config->getString("requiressl") == "trusted")
220                 {
221                         ok = (req.cert && req.cert->IsCAVerified());
222                 }
223                 else if (myclass->config->getBool("requiressl"))
224                 {
225                         ok = (req.cert != NULL);
226                 }
227
228                 if (!ok)
229                         return MOD_RES_DENY;
230                 return MOD_RES_PASSTHRU;
231         }
232
233         void OnRequest(Request& request)
234         {
235                 if (strcmp("GET_USER_CERT", request.id) == 0)
236                 {
237                         UserCertificateRequest& req = static_cast<UserCertificateRequest&>(request);
238                         req.cert = cmd.CertExt.get(req.user);
239                 }
240         }
241 };
242
243 MODULE_INIT(ModuleSSLInfo)