1 /* NickServ core functions
2  *
3  * (C) 2003-2020 Anope Team
4  * Contact us at team@anope.org
5  *
6  * Please read COPYING and README for further details.
7  *
8  * Based on the original code of Epona by Lara.
9  * Based on the original code of Services by Andy Church.
10  */
11 
12 #include "module.h"
13 
14 class CommandNSAccess : public Command
15 {
16  private:
DoAdd(CommandSource & source,NickCore * nc,const Anope::string & mask)17 	void DoAdd(CommandSource &source, NickCore *nc, const Anope::string &mask)
18 	{
19 		if (mask.empty())
20 		{
21 			this->OnSyntaxError(source, "ADD");
22 			return;
23 		}
24 
25 		if (Anope::ReadOnly)
26 		{
27 			source.Reply(READ_ONLY_MODE);
28 			return;
29 		}
30 
31 		if (nc->access.size() >= Config->GetModule(this->owner)->Get<unsigned>("accessmax", "32"))
32 		{
33 			source.Reply(_("Sorry, the maximum of %d access entries has been reached."), Config->GetModule(this->owner)->Get<unsigned>("accessmax"));
34 			return;
35 		}
36 
37 		if (nc->FindAccess(mask))
38 		{
39 			source.Reply(_("Mask \002%s\002 already present on %s's access list."), mask.c_str(), nc->display.c_str());
40 			return;
41 		}
42 
43 		nc->AddAccess(mask);
44 		Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to ADD mask " << mask << " to " << nc->display;
45 		source.Reply(_("\002%s\002 added to %s's access list."), mask.c_str(), nc->display.c_str());
46 
47 		return;
48 	}
49 
DoDel(CommandSource & source,NickCore * nc,const Anope::string & mask)50 	void DoDel(CommandSource &source, NickCore *nc, const Anope::string &mask)
51 	{
52 		if (mask.empty())
53 		{
54 			this->OnSyntaxError(source, "DEL");
55 			return;
56 		}
57 
58 		if (Anope::ReadOnly)
59 		{
60 			source.Reply(READ_ONLY_MODE);
61 			return;
62 		}
63 
64 		if (!nc->FindAccess(mask))
65 		{
66 			source.Reply(_("\002%s\002 not found on %s's access list."), mask.c_str(), nc->display.c_str());
67 			return;
68 		}
69 
70 		nc->EraseAccess(mask);
71 		Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to DELETE mask " << mask << " from " << nc->display;
72 		source.Reply(_("\002%s\002 deleted from %s's access list."), mask.c_str(), nc->display.c_str());
73 
74 		return;
75 	}
76 
DoList(CommandSource & source,NickCore * nc,const Anope::string & mask)77 	void DoList(CommandSource &source, NickCore *nc, const Anope::string &mask)
78 	{
79 		unsigned i, end;
80 
81 		if (nc->access.empty())
82 		{
83 			source.Reply(_("%s's access list is empty."), nc->display.c_str());
84 			return;
85 		}
86 
87 		source.Reply(_("Access list for %s:"), nc->display.c_str());
88 		for (i = 0, end = nc->access.size(); i < end; ++i)
89 		{
90 			Anope::string access = nc->GetAccess(i);
91 			if (!mask.empty() && !Anope::Match(access, mask))
92 				continue;
93 			source.Reply("    %s", access.c_str());
94 		}
95 
96 		return;
97 	}
98  public:
CommandNSAccess(Module * creator)99 	CommandNSAccess(Module *creator) : Command(creator, "nickserv/access", 1, 3)
100 	{
101 		this->SetDesc(_("Modify the list of authorized addresses"));
102 		this->SetSyntax(_("ADD [\037nickname\037] \037mask\037"));
103 		this->SetSyntax(_("DEL [\037nickname\037] \037mask\037"));
104 		this->SetSyntax(_("LIST [\037nickname\037]"));
105 	}
106 
Execute(CommandSource & source,const std::vector<Anope::string> & params)107 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
108 	{
109 		const Anope::string &cmd = params[0];
110 		Anope::string nick, mask;
111 
112 		if (cmd.equals_ci("LIST"))
113 			nick = params.size() > 1 ? params[1] : "";
114 		else
115 		{
116 			nick = params.size() == 3 ? params[1] : "";
117 			mask = params.size() > 1 ? params[params.size() - 1] : "";
118 		}
119 
120 		NickCore *nc;
121 		if (!nick.empty())
122 		{
123 			const NickAlias *na = NickAlias::Find(nick);
124 			if (na == NULL)
125 			{
126 				source.Reply(NICK_X_NOT_REGISTERED, nick.c_str());
127 				return;
128 			}
129 			else if (na->nc != source.GetAccount() && !source.HasPriv("nickserv/access"))
130 			{
131 				source.Reply(ACCESS_DENIED);
132 				return;
133 			}
134 			else if (Config->GetModule("nickserv")->Get<bool>("secureadmins", "yes") && source.GetAccount() != na->nc && na->nc->IsServicesOper() && !cmd.equals_ci("LIST"))
135 			{
136 				source.Reply(_("You may view but not modify the access list of other Services Operators."));
137 				return;
138 			}
139 
140 			nc = na->nc;
141 		}
142 		else
143 			nc = source.nc;
144 
145 		if (!mask.empty() && (mask.find('@') == Anope::string::npos || mask.find('!') != Anope::string::npos))
146 		{
147 			source.Reply(BAD_USERHOST_MASK);
148 			source.Reply(MORE_INFO, Config->StrictPrivmsg.c_str(), source.service->nick.c_str(), source.command.c_str());
149 		}
150 		else if (cmd.equals_ci("LIST"))
151 			return this->DoList(source, nc, mask);
152 		else if (nc->HasExt("NS_SUSPENDED"))
153 			source.Reply(NICK_X_SUSPENDED, nc->display.c_str());
154 		else if (cmd.equals_ci("ADD"))
155 			return this->DoAdd(source, nc, mask);
156 		else if (cmd.equals_ci("DEL"))
157 			return this->DoDel(source, nc, mask);
158 		else
159 			this->OnSyntaxError(source, "");
160 	}
161 
OnHelp(CommandSource & source,const Anope::string & subcommand)162 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
163 	{
164 		this->SendSyntax(source);
165 		source.Reply(" ");
166 		source.Reply(_("Modifies or displays the access list for your nick.  This\n"
167 					"is the list of addresses which will be automatically\n"
168 					"recognized by %s as allowed to use the nick.  If\n"
169 					"you want to use the nick from a different address, you\n"
170 					"need to send an \002IDENTIFY\002 command to make %s\n"
171 					"recognize you. Services Operators may provide a nick\n"
172 					"to modify other users' access lists.\n"
173 					" \n"
174 					"Examples:\n"
175 					" \n"
176 					"    \002ACCESS ADD anyone@*.bepeg.com\002\n"
177 					"        Allows access to user \002anyone\002 from any machine in\n"
178 					"        the \002bepeg.com\002 domain.\n"
179 					" \n"
180 					"    \002ACCESS DEL anyone@*.bepeg.com\002\n"
181 					"        Reverses the previous command.\n"
182 					" \n"
183 					"    \002ACCESS LIST\002\n"
184 					"        Displays the current access list."), source.service->nick.c_str(), source.service->nick.c_str());
185 		return true;
186 	}
187 };
188 
189 class NSAccess : public Module
190 {
191 	CommandNSAccess commandnsaccess;
192 
193  public:
NSAccess(const Anope::string & modname,const Anope::string & creator)194 	NSAccess(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
195 		commandnsaccess(this)
196 	{
197 	}
198 
OnNickRegister(User * u,NickAlias * na,const Anope::string &)199 	void OnNickRegister(User *u, NickAlias *na, const Anope::string &) anope_override
200 	{
201 		if (u && Config->GetModule(this)->Get<bool>("addaccessonreg"))
202 			na->nc->AddAccess(u->Mask());
203 	}
204 };
205 
206 MODULE_INIT(NSAccess)
207