fixed ssl.c bug when ssl backend returns IO_BLOCKED but IO engine doesn't get informe...
[ircu2.10.12-pk.git] / ircd / m_svsnick.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_svsnick.c
3  * Written by David Herrmann.
4  */
5
6 /*
7  * m_functions execute protocol messages on this server:
8  *
9  *    cptr    is always NON-NULL, pointing to a *LOCAL* client
10  *            structure (with an open socket connected!). This
11  *            identifies the physical socket where the message
12  *            originated (or which caused the m_function to be
13  *            executed--some m_functions may call others...).
14  *
15  *    sptr    is the source of the message, defined by the
16  *            prefix part of the message if present. If not
17  *            or prefix not found, then sptr==cptr.
18  *
19  *            (!IsServer(cptr)) => (cptr == sptr), because
20  *            prefixes are taken *only* from servers...
21  *
22  *            (IsServer(cptr))
23  *                    (sptr == cptr) => the message didn't
24  *                    have the prefix.
25  *
26  *                    (sptr != cptr && IsServer(sptr) means
27  *                    the prefix specified servername. (?)
28  *
29  *                    (sptr != cptr && !IsServer(sptr) means
30  *                    that message originated from a remote
31  *                    user (not local).
32  *
33  *            combining
34  *
35  *            (!IsServer(sptr)) means that, sptr can safely
36  *            taken as defining the target structure of the
37  *            message in this server.
38  *
39  *    *Always* true (if 'parse' and others are working correct):
40  *
41  *    1)      sptr->from == cptr  (note: cptr->from == cptr)
42  *
43  *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
44  *            *cannot* be a local connection, unless it's
45  *            actually cptr!). [MyConnect(x) should probably
46  *            be defined as (x == x->from) --msa ]
47  *
48  *    parc    number of variable parameter strings (if zero,
49  *            parv is allowed to be NULL)
50  *
51  *    parv    a NULL terminated list of parameter pointers,
52  *
53  *                    parv[0], sender (prefix string), if not present
54  *                            this points to an empty string.
55  *                    parv[1]...parv[parc-1]
56  *                            pointers to additional parameters
57  *                    parv[parc] == NULL, *always*
58  *
59  *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
60  *                    non-NULL pointers.
61  */
62 #include "config.h"
63
64 #include "client.h"
65 #include "hash.h"
66 #include "ircd.h"
67 #include "ircd_features.h"
68 #include "ircd_log.h"
69 #include "ircd_reply.h"
70 #include "ircd_string.h"
71 #include "msg.h"
72 #include "numeric.h"
73 #include "numnicks.h"
74 #include "s_conf.h"
75 #include "s_misc.h"
76 #include "s_user.h"
77 #include "send.h"
78 #include "sys.h"
79
80 #include <stdlib.h>
81 #include <string.h>
82
83 /* Copied from m_nick.c.
84  *
85  * do_nick_name checks the nickname. WARNING: It MAY modify the nickname
86  * RETURNS the length of the final NICKNAME (0, if nickname is invalid)
87  *
88  * Nickname characters are in range 'A'..'}', '_', '-', '0'..'9'
89  *  anything outside the above set will terminate nickname.
90  * In addition, the first character cannot be '-' or a Digit.
91  */
92 static int do_nick_name(char* nick) {
93     char *ch  = nick;
94     char *end = ch + NICKLEN;
95     assert(0 != ch);
96
97     /* first character in [0..9-] */
98     if(*ch == '-' || IsDigit(*ch)) return 0;
99     for( ; (ch < end) && *ch; ++ch) {
100         if(!IsNickChar(*ch)) break;
101     }
102     *ch = '\0';
103     return (ch - nick);
104 }
105
106 /** SVSNICK
107  * SVSNICK is forwarded to the users server, hence, it can be called
108  * from any server.
109  */
110 int m_svsnick(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) {
111 struct Client *acptr = NULL;
112     char nick[NICKLEN + 2];
113     char *arg;
114     char *s;
115         if (!IsNetServ(sptr) || !HasFlag(sptr, FLAG_SECURITY_SERV))
116     return send_reply(sptr, ERR_NOPRIVILEGES);
117         
118     if(parc < 3) {
119         return protocol_violation(cptr, "Too few arguments for SVSNICK");
120     }
121
122     if(!(acptr = FindUser(parv[1]))) {
123         return 0; /* Ignore SVSNICK for a user that has quit */
124     }
125
126     /* Limit the nicklen to NICKLEN. */
127     arg = parv[2];
128     if(strlen(arg) > IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))) {
129         arg[IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))] = '\0';
130     }
131     strcpy(nick, arg);
132
133     if(!do_nick_name(nick)) {
134         /* Invalid nickname. */
135         return 0;
136     }
137
138     /* Check whether nickname is already set. */
139     if(ircd_strcmp(cli_name(acptr), parv[2]) == 0) {
140         return 0;
141     }
142
143     /* Check whether the nick is already used. */
144     s = nick;
145     if(FindClient(s)) {
146         return 0;
147     }
148
149     /* Forward the message to the server where the user is connected to. */
150     if(!MyConnect(acptr)) {
151             const struct User* user = cli_user(acptr);
152                 struct Client *server = user->server; 
153         sendcmdto_one(sptr, CMD_SVSNICK, acptr, "%s%s %s", cli_yxx(server), cli_yxx(acptr), nick);
154         return 0;
155     }
156
157     /* Set nickname. */
158     set_nick_name(acptr, acptr, nick, parc, parv, 1);
159
160     return 1;
161 }
162
163 /* ms_svsnick - server message handler
164  * parv[0] = sender prefix
165  * parv[1] = target numeric
166  * parv[2] = new nickname
167  */
168 signed int ms_svsnick(struct Client* cptr, struct Client* sptr, signed int parc, char* parv[]) {
169     struct Client *acptr = NULL;
170     char nick[NICKLEN + 2];
171     char *arg;
172     char *s;
173
174     if(parc < 3) {
175         return protocol_violation(cptr, "Too few arguments for SVSNICK");
176     }
177
178     if(!(acptr = findNUser(parv[1]))) {
179         return 0; /* Ignore SVSNICK for a user that has quit */
180     }
181
182     /* Limit the nicklen to NICKLEN. */
183     arg = parv[2];
184     if(strlen(arg) > IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))) {
185         arg[IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))] = '\0';
186     }
187     strcpy(nick, arg);
188
189     if(!do_nick_name(nick)) {
190         /* Invalid nickname. */
191         return 0;
192     }
193
194     /* Check whether nickname is already set. */
195     if(ircd_strcmp(cli_name(acptr), parv[2]) == 0) {
196         return 0;
197     }
198
199     /* Check whether the nick is already used. */
200     s = nick;
201     if(FindClient(s)) {
202         return 0;
203     }
204
205     /* Forward the message to the server where the user is connected to. */
206     if(!MyConnect(acptr)) {
207         sendcmdto_one(sptr, CMD_SVSNICK, acptr, "%s %s", parv[1], nick);
208         return 0;
209     }
210
211     #ifndef UNRESTRICTED_SERV
212     /* Set nickname. */
213     set_nick_name(acptr, acptr, nick, parc, parv, 1);
214     #endif
215     return 1;
216 }
217
218 /*
219  * ms_svsnick_old - server message handler
220  * parv[0] = sender prefix
221  * parv[1] = Target numeric
222  * parv[2] = New nickname
223  */
224 int ms_svsnick_old(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) {
225     struct Client* acptr = NULL;
226     char nick[NICKLEN + 2];
227     char* arg;
228     char* s;
229
230     if(parc < 3)
231         return(need_more_params(sptr, "SVSNICK"));
232
233     if(!(acptr = findNUser(parv[1])))
234         return 0; /* Ignore SVSNICK for a user that has quit */
235
236     if(!find_conf_byhost(cli_confs(cptr), cli_name(sptr), CONF_UWORLD)) {
237         return protocol_violation(cptr, "Non-U:lined server %s sets svsnick on user %s", cli_name(sptr), cli_name(acptr));
238     }
239
240     /*
241      * Don't let them send make us send back a really long string of
242      * garbage
243      */
244     arg = parv[2];
245     if(strlen(arg) > IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN)))
246         arg[IRCD_MIN(NICKLEN, feature_int(FEAT_NICKLEN))] = '\0';
247
248     if((s = strchr(arg, '~')))
249         *s = '\0';
250
251     strcpy(nick, arg);
252
253     /*
254      * If do_nick_name() returns a null name then reject it.
255      */
256     if(0 == do_nick_name(nick))
257         return 0;
258
259     if(ircd_strcmp(cli_name(acptr), nick) == 0)
260         return 0; /* Nick already set to what SVSNICK wants, ignoring... */
261
262     if(FindClient(nick))
263         return 0; /* Target nick is in use */
264     
265     set_nick_name(acptr, acptr, nick, parc, parv, 1);
266     sendcmdto_serv_butone(sptr, CMD_SVSNICK_OLD, cptr, "%s %s", parv[1], nick);
267     return 0;
268 }
269