]>
Commit | Line | Data |
---|---|---|
189935b1 | 1 | /* |
2 | * IRC - Internet Relay Chat, ircd/client.c | |
3 | * Copyright (C) 1990 Darren Reed | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 1, or (at your option) | |
8 | * any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 | */ | |
19 | /** @file | |
20 | * @brief Implementation of functions for handling local clients. | |
21 | * @version $Id: client.c,v 1.31.2.1 2005/10/12 23:50:04 entrope Exp $ | |
22 | */ | |
23 | #include "config.h" | |
24 | ||
25 | #include "client.h" | |
26 | #include "class.h" | |
27 | #include "ircd.h" | |
28 | #include "ircd_features.h" | |
29 | #include "ircd_log.h" | |
30 | #include "ircd_reply.h" | |
31 | #include "list.h" | |
32 | #include "msgq.h" | |
33 | #include "numeric.h" | |
34 | #include "s_conf.h" | |
35 | #include "s_debug.h" | |
36 | #include "send.h" | |
37 | #include "struct.h" | |
38 | ||
39 | /* #include <assert.h> -- Now using assert in ircd_log.h */ | |
40 | #include <string.h> | |
41 | ||
42 | /** Find the shortest non-zero ping time attached to a client. | |
43 | * If all attached ping times are zero, return the value for | |
44 | * FEAT_PINGFREQUENCY. | |
45 | * @param[in] acptr Client to find ping time for. | |
46 | * @return Ping time in seconds. | |
47 | */ | |
48 | int client_get_ping(const struct Client* acptr) | |
49 | { | |
50 | int ping = 0; | |
51 | struct ConfItem* aconf; | |
52 | struct SLink* link; | |
53 | ||
54 | assert(cli_verify(acptr)); | |
55 | ||
56 | for (link = cli_confs(acptr); link; link = link->next) { | |
57 | aconf = link->value.aconf; | |
58 | if (aconf->status & (CONF_CLIENT | CONF_SERVER)) { | |
59 | int tmp = get_conf_ping(aconf); | |
60 | if (0 < tmp && (ping > tmp || !ping)) | |
61 | ping = tmp; | |
62 | } | |
63 | } | |
64 | if (0 == ping) | |
65 | ping = feature_int(FEAT_PINGFREQUENCY); | |
66 | ||
67 | Debug((DEBUG_DEBUG, "Client %s Ping %d", cli_name(acptr), ping)); | |
68 | ||
69 | return ping; | |
70 | } | |
71 | ||
72 | /** Find the default usermode for a client. | |
73 | * @param[in] sptr Client to find default usermode for. | |
74 | * @return Pointer to usermode string (or NULL, if there is no default). | |
75 | */ | |
76 | const char* client_get_default_umode(const struct Client* sptr) | |
77 | { | |
78 | struct ConfItem* aconf; | |
79 | struct SLink* link; | |
80 | ||
81 | assert(cli_verify(sptr)); | |
82 | ||
83 | for (link = cli_confs(sptr); link; link = link->next) { | |
84 | aconf = link->value.aconf; | |
85 | if ((aconf->status & CONF_CLIENT) && ConfUmode(aconf)) | |
86 | return ConfUmode(aconf); | |
87 | } | |
88 | return NULL; | |
89 | } | |
90 | ||
91 | /** Remove a connection from the list of connections with queued data. | |
92 | * @param[in] con Connection with no queued data. | |
93 | */ | |
94 | void client_drop_sendq(struct Connection* con) | |
95 | { | |
96 | if (con_prev_p(con)) { /* on the queued data list... */ | |
97 | if (con_next(con)) | |
98 | con_prev_p(con_next(con)) = con_prev_p(con); | |
99 | *(con_prev_p(con)) = con_next(con); | |
100 | ||
101 | con_next(con) = 0; | |
102 | con_prev_p(con) = 0; | |
103 | } | |
104 | } | |
105 | ||
106 | /** Add a connection to the list of connections with queued data. | |
107 | * @param[in] con Connection with queued data. | |
108 | * @param[in,out] con_p Previous pointer to next connection. | |
109 | */ | |
110 | void client_add_sendq(struct Connection* con, struct Connection** con_p) | |
111 | { | |
112 | if (!con_prev_p(con)) { /* not on the queued data list yet... */ | |
113 | con_prev_p(con) = con_p; | |
114 | con_next(con) = *con_p; | |
115 | ||
116 | if (*con_p) | |
117 | con_prev_p(*con_p) = &(con_next(con)); | |
118 | *con_p = con; | |
119 | } | |
120 | } | |
121 | ||
122 | /** Default privilege set for global operators. */ | |
123 | static struct Privs privs_global; | |
124 | /** Default privilege set for local operators. */ | |
125 | static struct Privs privs_local; | |
126 | /** Non-zero if #privs_global and #privs_local have been initialized. */ | |
127 | static int privs_defaults_set; | |
128 | ||
129 | /* client_set_privs(struct Client* client) | |
130 | * | |
131 | * Sets the privileges for opers. | |
132 | */ | |
133 | /** Set the privileges for a client. | |
134 | * @param[in] client Client who has become an operator. | |
135 | * @param[in] oper Configuration item describing oper's privileges. | |
136 | */ | |
137 | void | |
138 | client_set_privs(struct Client *client, struct ConfItem *oper) | |
139 | { | |
140 | struct Privs *source, *defaults; | |
141 | enum Priv priv; | |
142 | ||
143 | if (!MyConnect(client)) | |
144 | return; | |
145 | ||
146 | /* Clear out client's privileges. */ | |
147 | memset(cli_privs(client), 0, sizeof(struct Privs)); | |
148 | ||
149 | if (!IsAnOper(client) || !oper) | |
150 | return; | |
151 | ||
152 | if (!privs_defaults_set) | |
153 | { | |
154 | memset(&privs_global, -1, sizeof(privs_global)); | |
155 | FlagClr(&privs_global, PRIV_WALK_LCHAN); | |
156 | FlagClr(&privs_global, PRIV_UNLIMIT_QUERY); | |
157 | FlagClr(&privs_global, PRIV_SET); | |
158 | FlagClr(&privs_global, PRIV_BADCHAN); | |
159 | FlagClr(&privs_global, PRIV_LOCAL_BADCHAN); | |
160 | FlagClr(&privs_global, PRIV_APASS_OPMODE); | |
161 | ||
162 | memset(&privs_local, 0, sizeof(privs_local)); | |
163 | FlagSet(&privs_local, PRIV_CHAN_LIMIT); | |
164 | FlagSet(&privs_local, PRIV_MODE_LCHAN); | |
165 | FlagSet(&privs_local, PRIV_SHOW_INVIS); | |
166 | FlagSet(&privs_local, PRIV_SHOW_ALL_INVIS); | |
167 | FlagSet(&privs_local, PRIV_LOCAL_KILL); | |
168 | FlagSet(&privs_local, PRIV_REHASH); | |
169 | FlagSet(&privs_local, PRIV_LOCAL_GLINE); | |
170 | FlagSet(&privs_local, PRIV_LOCAL_JUPE); | |
171 | FlagSet(&privs_local, PRIV_LOCAL_OPMODE); | |
172 | FlagSet(&privs_local, PRIV_WHOX); | |
173 | FlagSet(&privs_local, PRIV_DISPLAY); | |
174 | FlagSet(&privs_local, PRIV_FORCE_LOCAL_OPMODE); | |
175 | ||
176 | privs_defaults_set = 1; | |
177 | } | |
178 | ||
179 | /* Decide whether to use global or local oper defaults. */ | |
180 | if (FlagHas(&oper->privs_dirty, PRIV_PROPAGATE)) | |
181 | defaults = FlagHas(&oper->privs, PRIV_PROPAGATE) ? &privs_global : &privs_local; | |
182 | else if (FlagHas(&oper->conn_class->privs_dirty, PRIV_PROPAGATE)) | |
183 | defaults = FlagHas(&oper->conn_class->privs, PRIV_PROPAGATE) ? &privs_global : &privs_local; | |
184 | else { | |
185 | assert(0 && "Oper has no propagation and neither does connection class"); | |
186 | return; | |
187 | } | |
188 | ||
189 | /* For each feature, figure out whether it comes from the operator | |
190 | * conf, the connection class conf, or the defaults, then apply it. | |
191 | */ | |
192 | for (priv = 0; priv < PRIV_LAST_PRIV; ++priv) | |
193 | { | |
194 | /* Figure out most applicable definition for the privilege. */ | |
195 | if (FlagHas(&oper->privs_dirty, priv)) | |
196 | source = &oper->privs; | |
197 | else if (FlagHas(&oper->conn_class->privs_dirty, priv)) | |
198 | source = &oper->conn_class->privs; | |
199 | else | |
200 | source = defaults; | |
201 | ||
202 | /* Set it if necessary (privileges were already cleared). */ | |
203 | if (FlagHas(source, priv)) | |
204 | SetPriv(client, priv); | |
205 | } | |
206 | ||
207 | /* This should be handled in the config, but lets be sure... */ | |
208 | if (HasPriv(client, PRIV_PROPAGATE)) | |
209 | { | |
210 | /* force propagating opers to display */ | |
211 | SetPriv(client, PRIV_DISPLAY); | |
212 | } | |
213 | else | |
214 | { | |
215 | /* if they don't propagate oper status, prevent desyncs */ | |
216 | ClrPriv(client, PRIV_KILL); | |
217 | ClrPriv(client, PRIV_GLINE); | |
218 | ClrPriv(client, PRIV_JUPE); | |
219 | ClrPriv(client, PRIV_OPMODE); | |
220 | ClrPriv(client, PRIV_BADCHAN); | |
221 | } | |
222 | } | |
223 | ||
224 | /** Array mapping privilege values to names and vice versa. */ | |
225 | static struct { | |
226 | char *name; /**< Name of privilege. */ | |
227 | unsigned int priv; /**< Enumeration value of privilege */ | |
228 | } privtab[] = { | |
229 | /** Helper macro to define an array entry for a privilege. */ | |
230 | #define P(priv) { #priv, PRIV_ ## priv } | |
231 | P(CHAN_LIMIT), P(MODE_LCHAN), P(WALK_LCHAN), P(DEOP_LCHAN), | |
232 | P(SHOW_INVIS), P(SHOW_ALL_INVIS), P(UNLIMIT_QUERY), P(KILL), | |
233 | P(LOCAL_KILL), P(REHASH), P(RESTART), P(DIE), | |
234 | P(GLINE), P(LOCAL_GLINE), P(JUPE), P(LOCAL_JUPE), | |
235 | P(OPMODE), P(LOCAL_OPMODE), P(SET), P(WHOX), | |
236 | P(BADCHAN), P(LOCAL_BADCHAN), P(SEE_CHAN), P(PROPAGATE), | |
237 | P(DISPLAY), P(SEE_OPERS), P(WIDE_GLINE), P(LIST_CHAN), | |
238 | P(FORCE_OPMODE), P(FORCE_LOCAL_OPMODE), P(APASS_OPMODE), | |
239 | #undef P | |
240 | { 0, 0 } | |
241 | }; | |
242 | ||
243 | /** Report privileges of \a client to \a to. | |
244 | * @param[in] to Client requesting privilege list. | |
245 | * @param[in] client Client whos privileges should be listed. | |
246 | * @return Zero. | |
247 | */ | |
248 | int | |
249 | client_report_privs(struct Client *to, struct Client *client) | |
250 | { | |
251 | struct MsgBuf *mb; | |
252 | int found1 = 0; | |
253 | int i; | |
254 | ||
255 | mb = msgq_make(to, rpl_str(RPL_PRIVS), cli_name(&me), cli_name(to), | |
256 | cli_name(client)); | |
257 | ||
258 | for (i = 0; privtab[i].name; i++) | |
259 | if (HasPriv(client, privtab[i].priv)) | |
260 | msgq_append(0, mb, "%s%s", found1++ ? " " : "", privtab[i].name); | |
261 | ||
262 | send_buffer(to, mb, 0); /* send response */ | |
263 | msgq_clean(mb); | |
264 | ||
265 | return 0; | |
266 | } |