ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/nickserv/identify.C
Revision: 1.7
Committed: Wed Sep 5 11:23:13 2007 UTC (19 years, 1 month ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.6: +4 -4 lines
Log Message:
removed GPLed code and put license back to BSD

File Contents

# User Rev Content
1 pippijn 1.1 /*
2 pippijn 1.4 * Copyright © 2005-2006 William Pitcock, et al.
3 pippijn 1.2 * Rights to this code are as documented in doc/pod/license.pod.
4 pippijn 1.1 *
5     * This file contains code for the NickServ IDENTIFY and LOGIN functions.
6     *
7 pippijn 1.7 * $Id: identify.C,v 1.6 2007-08-30 19:56:23 pippijn Exp $
8 pippijn 1.1 */
9    
10     #include "atheme.h"
11 pippijn 1.4 #include <ermyth/module.h>
12 pippijn 1.1 #include <account/mychan.h>
13     #include <account/chanacs.h>
14     #include <account/mynick.h>
15     #include <account/myuser.h>
16    
17     /* Check whether we are compiling IDENTIFY or LOGIN */
18     #ifdef NICKSERV_LOGIN
19     #define COMMAND_UC "LOGIN"
20     #define COMMAND_LC "login"
21     #else
22     #define COMMAND_UC "IDENTIFY"
23     #define COMMAND_LC "identify"
24     #endif
25    
26 pippijn 1.7 static char const rcsid[] = "$Id: identify.C,v 1.6 2007-08-30 19:56:23 pippijn Exp $";
27 pippijn 1.1
28 pippijn 1.4 REGISTER_MODULE ("nickserv/" COMMAND_LC, false, "The Ermyth Team <http://ermyth.schmorp.de>");
29 pippijn 1.1
30     static void ns_cmd_login (sourceinfo_t *si, int parc, char *parv[]);
31    
32     #ifdef NICKSERV_LOGIN
33 pippijn 1.4 command_t const ns_login = { "LOGIN", N_("Authenticates to a services account."), AC_NONE, 2, ns_cmd_login };
34 pippijn 1.1 #else
35 pippijn 1.4 command_t const ns_identify = { "IDENTIFY", N_("Identifies to services for a nickname."), AC_NONE, 2, ns_cmd_login };
36     command_t const ns_id = { "ID", N_("Alias for IDENTIFY"), AC_NONE, 2, ns_cmd_login };
37 pippijn 1.1 #endif
38    
39 pippijn 1.4 E cmdvec ns_cmdtree;
40     E helpvec ns_helptree;
41 pippijn 1.1
42 pippijn 1.4 bool
43     _modinit (module *m)
44 pippijn 1.1 {
45     #ifdef NICKSERV_LOGIN
46     ns_cmdtree << ns_login;
47     help_addentry (ns_helptree, "LOGIN", "help/nickserv/login", NULL);
48     #else
49     ns_cmdtree << ns_identify;
50     ns_cmdtree << ns_id;
51     help_addentry (ns_helptree, "IDENTIFY", "help/nickserv/identify", NULL);
52     help_addentry (ns_helptree, "ID", "help/nickserv/identify", NULL);
53     #endif
54 pippijn 1.4
55     return true;
56 pippijn 1.1 }
57    
58     void
59     _moddeinit ()
60     {
61     #ifdef NICKSERV_LOGIN
62     ns_cmdtree >> ns_login;
63     help_delentry (ns_helptree, "LOGIN");
64     #else
65     ns_cmdtree >> ns_identify;
66     ns_cmdtree >> ns_id;
67     help_delentry (ns_helptree, "IDENTIFY");
68     help_delentry (ns_helptree, "ID");
69     #endif
70     }
71    
72     static void
73     ns_cmd_login (sourceinfo_t *si, int parc, char *parv[])
74     {
75     user_t *u = si->su;
76     myuser_t *mu;
77     mynick_t *mn;
78     chanuser_t *cu;
79     chanacs_t *ca;
80     node_t *n;
81     char *target = parv[0];
82     char *password = parv[1];
83     char buf[BUFSIZE], strfbuf[32];
84     char lau[BUFSIZE], lao[BUFSIZE];
85     struct tm tm;
86 pippijn 1.7 metadata *md_failnum;
87 pippijn 1.1
88     if (si->su == NULL)
89     {
90 pippijn 1.6 command_fail (si, fault::noprivs, _("\2%s\2 can only be executed via IRC."), COMMAND_UC);
91 pippijn 1.1 return;
92     }
93    
94     #ifndef NICKSERV_LOGIN
95     if (!nicksvs.no_nick_ownership && target && !password)
96     {
97     password = target;
98     target = si->su->nick;
99     }
100     #endif
101    
102     if (!target || !password)
103     {
104 pippijn 1.6 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, COMMAND_UC);
105     command_fail (si, fault::needmoreparams, nicksvs.no_nick_ownership ? "Syntax: " COMMAND_UC " <account> <password>" : "Syntax: " COMMAND_UC " [nick] <password>");
106 pippijn 1.1 return;
107     }
108    
109     if (nicksvs.no_nick_ownership)
110 pippijn 1.5 mu = myuser_t::find (target);
111 pippijn 1.1 else
112     {
113     mn = mynick_find (target);
114     mu = mn != NULL ? mn->owner : NULL;
115     }
116    
117     if (!mu)
118     {
119 pippijn 1.6 command_fail (si, fault::nosuch_target, _("\2%s\2 is not a registered nickname."), target);
120 pippijn 1.1 return;
121     }
122    
123     if (mu->find_metadata ("private:freeze:freezer"))
124     {
125 pippijn 1.6 command_fail (si, fault::authfail, nicksvs.no_nick_ownership ? "You cannot login as \2%s\2 because the account has been frozen." : "You cannot identify to \2%s\2 because the nickname has been frozen.", mu->name);
126 pippijn 1.1 logcommand (si, CMDLOG_LOGIN, "failed " COMMAND_UC " to %s (frozen)", mu->name);
127     return;
128     }
129    
130     if (u->myuser == mu)
131     {
132 pippijn 1.6 command_fail (si, fault::nochange, _("You are already logged in as \2%s\2."), u->myuser->name);
133 pippijn 1.1 return;
134     }
135     else if (u->myuser != NULL && !si->service->cmdtree->find ("LOGOUT"))
136     {
137 pippijn 1.6 command_fail (si, fault::alreadyexists, _("You are already logged in as \2%s\2."), u->myuser->name);
138 pippijn 1.1 return;
139     }
140 pippijn 1.4 else if (u->myuser != NULL && phandler->ircd_on_logout (u->nick, u->myuser->name, NULL))
141 pippijn 1.1 /* logout killed the user... */
142     return;
143    
144     /* we use this in both cases, so set it up here. may be NULL. */
145     md_failnum = mu->find_metadata ("private:loginfail:failnum");
146    
147 pippijn 1.4 if (mu->verify_password (password))
148 pippijn 1.1 {
149     if (mu->logins.size () >= me.maxlogins)
150     {
151 pippijn 1.6 command_fail (si, fault::toomany, _("There are already \2%d\2 sessions logged in to \2%s\2 (maximum allowed: %d)."), mu->logins.size (), mu->name, me.maxlogins);
152 pippijn 1.1 logcommand (si, CMDLOG_LOGIN, "failed " COMMAND_UC " to %s (too many logins)", mu->name);
153     return;
154     }
155    
156     /* if they are identified to another account, nuke their session first */
157     if (u->myuser)
158     {
159     myuser_t::login_vector::iterator it, it_end;
160     u->myuser->lastlogin = NOW;
161     for (it = u->myuser->logins.begin (), it_end = u->myuser->logins.end (); it != it_end; ++it)
162     {
163     if (*it == u)
164     {
165     u->myuser->logins.erase (u);
166     break;
167     }
168     }
169     u->myuser = NULL;
170     }
171    
172     if (is_soper (mu))
173     snoop ("SOPER: \2%s\2 as \2%s\2", u->nick, mu->name);
174    
175 pippijn 1.4 mu->notice (nicksvs.nick, "%s!%s@%s has just authenticated as you (%s)", u->nick, u->user, u->vhost, mu->name);
176 pippijn 1.1
177     u->myuser = mu;
178     mu->logins.insert (u);
179    
180     /* keep track of login address for users */
181     strlcpy (lau, u->user, BUFSIZE);
182     strlcat (lau, "@", BUFSIZE);
183     strlcat (lau, u->vhost, BUFSIZE);
184     mu->add_metadata ("private:host:vhost", lau);
185    
186     /* and for opers */
187     strlcpy (lao, u->user, BUFSIZE);
188     strlcat (lao, "@", BUFSIZE);
189     strlcat (lao, u->host, BUFSIZE);
190     mu->add_metadata ("private:host:actual", lao);
191    
192     logcommand (si, CMDLOG_LOGIN, COMMAND_UC);
193    
194     command_success_nodata (si, nicksvs.no_nick_ownership ? "You are now logged in as \2%s\2." : "You are now identified for \2%s\2.", u->myuser->name);
195    
196     /* check for failed attempts and let them know */
197     if (md_failnum && (atoi (md_failnum->value) > 0))
198     {
199 pippijn 1.7 metadata *md_failtime, *md_failaddr;
200 pippijn 1.1 time_t ts;
201    
202     tm = *localtime (&mu->lastlogin);
203     strftime (strfbuf, sizeof (strfbuf) - 1, "%b %d %H:%M:%S %Y", &tm);
204    
205     command_success_nodata (si, _("\2%d\2 failed %s since %s."), atoi (md_failnum->value), (atoi (md_failnum->value) == 1) ? "login" : "logins", strfbuf);
206    
207     md_failtime = mu->find_metadata ("private:loginfail:lastfailtime");
208     ts = atol (md_failtime->value);
209     md_failaddr = mu->find_metadata ("private:loginfail:lastfailaddr");
210    
211     tm = *localtime (&ts);
212     strftime (strfbuf, sizeof (strfbuf) - 1, "%b %d %H:%M:%S %Y", &tm);
213    
214     command_success_nodata (si, _("Last failed attempt from: \2%s\2 on %s."), md_failaddr->value, strfbuf);
215    
216     mu->del_metadata ("private:loginfail:failnum"); /* md_failnum now invalid */
217     mu->del_metadata ("private:loginfail:lastfailtime");
218     mu->del_metadata ("private:loginfail:lastfailaddr");
219     }
220    
221     mu->lastlogin = NOW;
222     mn = mynick_find (u->nick);
223     if (mn != NULL && mn->owner == mu)
224     mn->lastseen = NOW;
225    
226     /* XXX: ircd_on_login supports hostmasking, we just dont have it yet. */
227     /* don't allow them to join regonly chans until their
228     * email is verified */
229     if (!(mu->flags & MU_WAITAUTH))
230 pippijn 1.4 phandler->ircd_on_login (si->su->nick, mu->name, NULL);
231 pippijn 1.1
232 pippijn 1.4 u->callback.identify (u);
233 pippijn 1.1
234     /* now we get to check for xOP */
235     /* we don't check for host access yet (could match different
236     * entries because of services cloaks) */
237     LIST_FOREACH (n, mu->chanacs.head)
238     {
239     ca = (chanacs_t *) n->data;
240    
241     cu = chanuser_find (ca->mychan->chan, u);
242     if (cu && chansvs.me != NULL)
243     {
244     if (ca->level & CA_AKICK && !(ca->level & CA_REMOVE))
245     {
246     /* Stay on channel if this would empty it -- jilles */
247     if (ca->mychan->chan->nummembers <= (ca->mychan->flags & MC_GUARD ? 2 : 1))
248     {
249     ca->mychan->flags |= MC_INHABIT;
250     if (!(ca->mychan->flags & MC_GUARD))
251     join (cu->chan->name, chansvs.nick);
252     }
253     ban (chansvs.me->me, ca->mychan->chan, u);
254     remove_ban_exceptions (chansvs.me->me, ca->mychan->chan, u);
255 pippijn 1.4 phandler->kick (chansvs.nick, ca->mychan->name, u->nick, "User is banned from this channel");
256 pippijn 1.1 continue;
257     }
258    
259     if (ca->level & CA_USEDUPDATE)
260     ca->mychan->used = NOW;
261    
262     if (ca->mychan->flags & MC_NOOP || mu->flags & MU_NOOP)
263     continue;
264    
265 pippijn 1.4 if (ircd->uses_owner && !(cu->modes & ircd->owner_mode) && ca->level & CA_AUTOOP && ca->myuser->should_owner (ca->mychan))
266 pippijn 1.1 {
267     modestack_mode_param (chansvs.nick, ca->mychan->chan, MTYPE_ADD, ircd->owner_mchar[1], CLIENT_NAME (u));
268     cu->modes |= ircd->owner_mode;
269     }
270    
271 pippijn 1.4 if (ircd->uses_protect && !(cu->modes & ircd->protect_mode) && ca->level & CA_AUTOOP && ca->myuser->should_protect (ca->mychan))
272 pippijn 1.1 {
273     modestack_mode_param (chansvs.nick, ca->mychan->chan, MTYPE_ADD, ircd->protect_mchar[1], CLIENT_NAME (u));
274     cu->modes |= ircd->protect_mode;
275     }
276    
277     if (!(cu->modes & CMODE_OP) && ca->level & CA_AUTOOP)
278     {
279     modestack_mode_param (chansvs.nick, ca->mychan->chan, MTYPE_ADD, 'o', CLIENT_NAME (u));
280     cu->modes |= CMODE_OP;
281     }
282    
283     if (ircd->uses_halfops && !(cu->modes & (CMODE_OP | ircd->halfops_mode)) && ca->level & CA_AUTOHALFOP)
284     {
285     modestack_mode_param (chansvs.nick, ca->mychan->chan, MTYPE_ADD, 'h', CLIENT_NAME (u));
286     cu->modes |= ircd->halfops_mode;
287     }
288    
289     if (!(cu->modes & (CMODE_OP | ircd->halfops_mode | CMODE_VOICE)) && ca->level & CA_AUTOVOICE)
290     {
291     modestack_mode_param (chansvs.nick, ca->mychan->chan, MTYPE_ADD, 'v', CLIENT_NAME (u));
292     cu->modes |= CMODE_VOICE;
293     }
294     }
295     }
296    
297     return;
298     }
299    
300     logcommand (si, CMDLOG_LOGIN, "failed " COMMAND_UC " to %s (bad password)", mu->name);
301    
302 pippijn 1.6 command_fail (si, fault::authfail, _("Invalid password for \2%s\2."), mu->name);
303 pippijn 1.1
304     /* record the failed attempts */
305     /* note that we reuse this buffer later when warning opers about failed logins */
306     snprintf (buf, sizeof buf, "%s!%s@%s", u->nick, u->user, u->vhost);
307    
308     /* increment fail count */
309     if (md_failnum && (atoi (md_failnum->value) > 0))
310     md_failnum = mu->add_metadata ("private:loginfail:failnum", itoa (atoi (md_failnum->value) + 1));
311     else
312     md_failnum = mu->add_metadata ("private:loginfail:failnum", "1");
313     mu->add_metadata ("private:loginfail:lastfailaddr", buf);
314     mu->add_metadata ("private:loginfail:lastfailtime", itoa (NOW));
315    
316     if (atoi (md_failnum->value) == 10)
317     {
318     time_t ts = NOW;
319     tm = *localtime (&ts);
320     strftime (strfbuf, sizeof (strfbuf) - 1, "%b %d %H:%M:%S %Y", &tm);
321    
322     wallops ("Warning: Numerous failed login attempts to \2%s\2. Last attempt received from \2%s\2 on %s.", mu->name, buf, strfbuf);
323     }
324     }