]>
Commit | Line | Data |
---|---|---|
1 | staffpriv | |
2 | ||
3 | give staff certain privs | |
4 | usermode +S (internally +S <staffname> just like usermode +o) | |
5 | add /STAFF command, mirrored after /OPER | |
6 | add priv STAFF used to determine whether the client becomes an OPER or STAFF | |
7 | ||
8 | add privs | |
9 | CLAIM_NICK allows staff to use /KILL staffname to free their own staffnick? (not implemented yet) | |
10 | GLINE_LOOKUP allows staff to lookup gline info using /GLINE | |
11 | HIDE_CHANS allows staff/oper to set usermode +n | |
12 | CHECK_CHANNEL allows staff to use /CHECK #channel (staff version respects hiddenhost, sethost, viewable topic, visible key, etc.) | |
13 | ||
14 | by default, staff gets all of the above privs + CHAN_LIMIT (no channel limit) and NOIDLE (set usermode +I) | |
15 | ||
16 | shows staff member count in /lusers | |
17 | shows staff in /trace, /stats l, /who <query> o, | |
18 | shows staff status in /WHOIS - show to IRC Operators the staffname | |
19 | staff can do /PRIVS to view their own privs - cannot view other user's privs | |
20 | allow staff to set usermode -h (remove sethost) | |
21 | allow staff to see through usermode +I (so they can see idle/signon time on fellow staff/opers) | |
22 | ||
23 | TODO: treat staff a bit more favourable with regards to excess flood? add feature STAFF_CLIENT_FLOOD? | |
24 | TODO: allow staff to access oper configured spoof blocks with /SETHOST? | |
25 | TODO: set default staff spoof host in feature STAFF_SETHOST to e.g. staff.quakenet.org - set upon login | |
26 | TODO: allow staff free'ing their nick? or else allow /NICK even when hit by a gline (that way we can reserve nicks using a nick!*@* gline) | |
27 | TODO: allow a search in /GLINE instead of requiring a perfect match? | |
28 | TODO: logging of /CHECK (for all) | |
29 | ||
30 | diff -r b6cf63c513c5 include/check.h | |
31 | --- a/include/check.h Thu Feb 12 14:05:21 2009 +0100 | |
32 | +++ b/include/check.h Thu Feb 12 14:18:31 2009 +0100 | |
33 | @@ -45,5 +45,6 @@ | |
34 | extern void checkClient(struct Client *sptr, struct Client *acptr); | |
35 | extern void checkServer(struct Client *sptr, struct Client *acptr); | |
36 | extern signed int checkHostmask(struct Client *sptr, char *hoststr, int flags); | |
37 | +extern int client_can_check_channel(struct Client *sptr, struct Channel *chptr); | |
38 | ||
39 | #endif /* INCLUDED_check_h */ | |
40 | diff -r b6cf63c513c5 include/client.h | |
41 | --- a/include/client.h Thu Feb 12 14:05:21 2009 +0100 | |
42 | +++ b/include/client.h Thu Feb 12 14:18:31 2009 +0100 | |
43 | @@ -90,7 +90,7 @@ | |
44 | #define FlagClr(set,flag) ((set)->bits[FLAGSET_INDEX(flag)] &= ~FLAGSET_MASK(flag)) | |
45 | ||
46 | /** String containing valid user modes, in no particular order. */ | |
47 | -#define infousermodes "dioOswkgxRXInPq" | |
48 | +#define infousermodes "dioOswkgxRXInPqS" | |
49 | ||
50 | /** Character to indicate no oper name available */ | |
51 | #define NOOPERNAMECHARACTER '-' | |
52 | @@ -144,6 +144,11 @@ | |
53 | PRIV_USER_PRIVACY, /* oper can bypass user privacy +x etc gives i.e. see real ip's */ | |
54 | PRIV_CHANNEL_PRIVACY, /* oper can bypass channel privacy i.e. can see modes on channels they are not on and channel keys */ | |
55 | PRIV_SERVERINFO, /* oper can use /get, /stats, /hash, retrieve remote information */ | |
56 | + PRIV_STAFF, /* staff */ | |
57 | + PRIV_CLAIM_NICK, /* staff can /KILL staffname to free own nick */ | |
58 | + PRIV_GLINE_LOOKUP, /* staff can use /GLINE to lookup a gline */ | |
59 | + PRIV_HIDE_CHANS, /* oper can set usermode +n */ | |
60 | + PRIV_CHECK_CHANNEL, /* staff can /CHECK #channel */ | |
61 | PRIV_LAST_PRIV /**< number of privileges */ | |
62 | }; | |
63 | ||
64 | @@ -178,6 +183,7 @@ | |
65 | FLAG_LOCOP, /**< Local operator -- SRB */ | |
66 | FLAG_SERVNOTICE, /**< server notices such as kill */ | |
67 | FLAG_OPER, /**< Operator */ | |
68 | + FLAG_STAFF, /**< snircd: Staff - mode +S */ | |
69 | FLAG_INVISIBLE, /**< makes user invisible */ | |
70 | FLAG_WALLOP, /**< send wallops to them */ | |
71 | FLAG_DEAF, /**< Makes user deaf */ | |
72 | @@ -591,6 +597,10 @@ | |
73 | #define IsLocOp(x) (MyUser(x) && HasFlag(x, FLAG_LOCOP)) | |
74 | /** Return non-zero if the client has set mode +o (global operator). */ | |
75 | #define IsOper(x) HasFlag(x, FLAG_OPER) | |
76 | +/** Return non-zero if the client has set mode +S (staff). */ | |
77 | +#define IsStaff(x) HasFlag(x, FLAG_STAFF) | |
78 | +/** Return non-zero if the client has set mode +S, +O or +o.*/ | |
79 | +#define IsStaffOrAnOper(x) (IsStaff(x) || IsAnOper(x)) | |
80 | /** Return non-zero if the client has an active UDP ping request. */ | |
81 | #define IsUPing(x) HasFlag(x, FLAG_UPING) | |
82 | /** Return non-zero if the client has no '\n' in its buffer. */ | |
83 | @@ -660,6 +670,8 @@ | |
84 | #define SetLocOp(x) SetFlag(x, FLAG_LOCOP) | |
85 | /** Mark a client as having mode +o (global operator). */ | |
86 | #define SetOper(x) SetFlag(x, FLAG_OPER) | |
87 | +/** Mark a client as having mode +S (staff). */ | |
88 | +#define SetStaff(x) SetFlag(x, FLAG_STAFF) | |
89 | /** Mark a client as having a pending UDP ping. */ | |
90 | #define SetUPing(x) SetFlag(x, FLAG_UPING) | |
91 | /** Mark a client as having mode +w (wallops). */ | |
92 | @@ -717,6 +729,8 @@ | |
93 | #define ClearLocOp(x) ClrFlag(x, FLAG_LOCOP) | |
94 | /** Remove mode +o (global operator) from the client. */ | |
95 | #define ClearOper(x) ClrFlag(x, FLAG_OPER) | |
96 | +/** Remove mode +S (staff) from the client. */ | |
97 | +#define ClearStaff(x) ClrFlag(x, FLAG_STAFF) | |
98 | /** Clear the client's pending UDP ping flag. */ | |
99 | #define ClearUPing(x) ClrFlag(x, FLAG_UPING) | |
100 | /** Remove mode +w (wallops) from the client. */ | |
101 | diff -r b6cf63c513c5 include/handlers.h | |
102 | --- a/include/handlers.h Thu Feb 12 14:05:21 2009 +0100 | |
103 | +++ b/include/handlers.h Thu Feb 12 14:18:31 2009 +0100 | |
104 | @@ -100,6 +100,7 @@ | |
105 | */ | |
106 | ||
107 | extern int m_check(struct Client *cptr, struct Client *sptr, int parc, char *parv[]); | |
108 | +extern int mo_check(struct Client *cptr, struct Client *sptr, int parc, char *parv[]); | |
109 | ||
110 | extern int m_cap(struct Client*, struct Client*, int, char*[]); | |
111 | extern int m_cnotice(struct Client*, struct Client*, int, char*[]); | |
112 | @@ -133,12 +134,14 @@ | |
113 | extern int m_pong(struct Client*, struct Client*, int, char*[]); | |
114 | extern int m_private(struct Client*, struct Client*, int, char*[]); | |
115 | extern int m_privmsg(struct Client*, struct Client*, int, char*[]); | |
116 | +extern int m_privs(struct Client*, struct Client*, int, char*[]); | |
117 | extern int m_proto(struct Client*, struct Client*, int, char*[]); | |
118 | extern int m_pseudo(struct Client*, struct Client*, int, char*[]); | |
119 | extern int m_quit(struct Client*, struct Client*, int, char*[]); | |
120 | extern int m_registered(struct Client*, struct Client*, int, char*[]); | |
121 | extern int m_sethost(struct Client*, struct Client*, int, char*[]); | |
122 | extern int m_silence(struct Client*, struct Client*, int, char*[]); | |
123 | +extern int m_staff(struct Client*, struct Client*, int, char*[]); | |
124 | extern int m_stats(struct Client*, struct Client*, int, char*[]); | |
125 | extern int m_time(struct Client*, struct Client*, int, char*[]); | |
126 | extern int m_topic(struct Client*, struct Client*, int, char*[]); | |
127 | @@ -179,6 +182,7 @@ | |
128 | extern int mo_set(struct Client*, struct Client*, int, char*[]); | |
129 | extern int mo_settime(struct Client*, struct Client*, int, char*[]); | |
130 | extern int mo_squit(struct Client*, struct Client*, int, char*[]); | |
131 | +extern int mo_staff(struct Client*, struct Client*, int, char*[]); | |
132 | extern int mo_stats(struct Client*, struct Client*, int, char*[]); | |
133 | extern int mo_trace(struct Client*, struct Client*, int, char*[]); | |
134 | extern int mo_uping(struct Client*, struct Client*, int, char*[]); | |
135 | @@ -233,6 +237,7 @@ | |
136 | extern int ms_settime(struct Client*, struct Client*, int, char*[]); | |
137 | extern int ms_silence(struct Client*, struct Client*, int, char*[]); | |
138 | extern int ms_squit(struct Client*, struct Client*, int, char*[]); | |
139 | +extern int ms_staff(struct Client*, struct Client*, int, char*[]); | |
140 | extern int ms_stats(struct Client*, struct Client*, int, char*[]); | |
141 | extern int ms_topic(struct Client*, struct Client*, int, char*[]); | |
142 | extern int ms_trace(struct Client*, struct Client*, int, char*[]); | |
143 | diff -r b6cf63c513c5 include/msg.h | |
144 | --- a/include/msg.h Thu Feb 12 14:05:21 2009 +0100 | |
145 | +++ b/include/msg.h Thu Feb 12 14:18:31 2009 +0100 | |
146 | @@ -116,6 +116,10 @@ | |
147 | #define TOK_STATS "R" | |
148 | #define CMD_STATS MSG_STATS, TOK_STATS | |
149 | ||
150 | +#define MSG_STAFF "STAFF" /* STAF */ | |
151 | +#define TOK_STAFF "STAFF" | |
152 | +#define CMD_STAFF MSG_STAFF, TOK_STAFF | |
153 | + | |
154 | #define MSG_HELP "HELP" /* HELP */ | |
155 | #define TOK_HELP "HELP" | |
156 | #define CMD_HELP MSG_HELP, TOK_HELP | |
157 | diff -r b6cf63c513c5 include/querycmds.h | |
158 | --- a/include/querycmds.h Thu Feb 12 14:05:21 2009 +0100 | |
159 | +++ b/include/querycmds.h Thu Feb 12 14:18:31 2009 +0100 | |
160 | @@ -29,6 +29,7 @@ | |
161 | /* Global user mode changes: */ | |
162 | unsigned int inv_clients; /**< Registered invisible users. */ | |
163 | unsigned int opers; /**< Registered IRC operators. */ | |
164 | + unsigned int staff; /**< Registered Staff members. */ | |
165 | ||
166 | /* Misc: */ | |
167 | unsigned int channels; /**< Existing channels. */ | |
168 | diff -r b6cf63c513c5 include/struct.h | |
169 | --- a/include/struct.h Thu Feb 12 14:05:21 2009 +0100 | |
170 | +++ b/include/struct.h Thu Feb 12 14:18:31 2009 +0100 | |
171 | @@ -95,6 +95,7 @@ | |
172 | unsigned long acc_id; /**< IRC account unique id */ | |
173 | uint64_t acc_flags; /**< IRC account flags */ | |
174 | char* opername; /**< IRC Oper Account name */ | |
175 | + char* staffname; /**< IRC Staff Account name */ | |
176 | }; | |
177 | ||
178 | #endif /* INCLUDED_struct_h */ | |
179 | diff -r b6cf63c513c5 ircd/Makefile.in | |
180 | --- a/ircd/Makefile.in Thu Feb 12 14:05:21 2009 +0100 | |
181 | +++ b/ircd/Makefile.in Thu Feb 12 14:18:31 2009 +0100 | |
182 | @@ -174,6 +174,7 @@ | |
183 | m_settime.c \ | |
184 | m_silence.c \ | |
185 | m_squit.c \ | |
186 | + m_staff.c \ | |
187 | m_stats.c \ | |
188 | m_time.c \ | |
189 | m_topic.c \ | |
190 | @@ -1060,6 +1061,17 @@ | |
191 | ../include/ircd_reply.h ../include/ircd_string.h ../include/numeric.h \ | |
192 | ../include/numnicks.h ../include/match.h ../include/s_debug.h \ | |
193 | ../include/s_misc.h ../include/s_user.h ../include/send.h | |
194 | +m_staff.o: m_staff.c ../config.h ../include/client.h ../include/ircd_defs.h \ | |
195 | + ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \ | |
196 | + ../config.h ../include/ircd_handler.h ../include/res.h \ | |
197 | + ../include/capab.h ../include/hash.h ../include/ircd.h \ | |
198 | + ../include/struct.h ../include/ircd_alloc.h ../include/ircd_features.h \ | |
199 | + ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \ | |
200 | + ../include/ircd_chattr.h ../include/ircd_crypt.h ../include/msg.h \ | |
201 | + ../include/numeric.h ../include/numnicks.h ../include/querycmds.h \ | |
202 | + ../include/ircd_features.h ../include/s_conf.h ../include/client.h \ | |
203 | + ../include/s_debug.h ../include/s_user.h ../include/s_misc.h \ | |
204 | + ../include/send.h | |
205 | m_stats.o: m_stats.c ../config.h ../include/client.h \ | |
206 | ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \ | |
207 | ../include/ircd_events.h ../config.h ../include/ircd_handler.h \ | |
208 | diff -r b6cf63c513c5 ircd/client.c | |
209 | --- a/ircd/client.c Thu Feb 12 14:05:21 2009 +0100 | |
210 | +++ b/ircd/client.c Thu Feb 12 14:18:31 2009 +0100 | |
211 | @@ -123,6 +123,8 @@ | |
212 | static struct Privs privs_global; | |
213 | /** Default privilege set for local operators. */ | |
214 | static struct Privs privs_local; | |
215 | +/** Default privilege set for staff. */ | |
216 | +static struct Privs privs_staff; | |
217 | /** Non-zero if #privs_global and #privs_local have been initialized. */ | |
218 | static int privs_defaults_set; | |
219 | ||
220 | @@ -146,7 +148,7 @@ | |
221 | /* Clear out client's privileges. */ | |
222 | memset(cli_privs(client), 0, sizeof(struct Privs)); | |
223 | ||
224 | - if (!IsAnOper(client) || !oper) | |
225 | + if (!IsStaffOrAnOper(client) || !oper) | |
226 | return; | |
227 | ||
228 | if (!privs_defaults_set) | |
229 | @@ -163,6 +165,10 @@ | |
230 | FlagClr(&privs_global, PRIV_DIE); | |
231 | FlagClr(&privs_global, PRIV_RESTART); | |
232 | FlagClr(&privs_global, PRIV_JUPE); | |
233 | + FlagClr(&privs_global, PRIV_STAFF); | |
234 | + FlagClr(&privs_global, PRIV_CLAIM_NICK); | |
235 | + FlagClr(&privs_global, PRIV_GLINE_LOOKUP); | |
236 | + FlagClr(&privs_global, PRIV_CHECK_CHANNEL); | |
237 | ||
238 | memset(&privs_local, 0, sizeof(privs_local)); | |
239 | FlagSet(&privs_local, PRIV_CHAN_LIMIT); | |
240 | @@ -178,17 +184,33 @@ | |
241 | FlagSet(&privs_local, PRIV_WHOX); | |
242 | FlagSet(&privs_local, PRIV_DISPLAY); | |
243 | FlagSet(&privs_local, PRIV_FORCE_LOCAL_OPMODE); | |
244 | + FlagClr(&privs_local, PRIV_STAFF); | |
245 | + FlagClr(&privs_local, PRIV_CLAIM_NICK); | |
246 | + FlagClr(&privs_local, PRIV_GLINE_LOOKUP); | |
247 | + FlagClr(&privs_local, PRIV_CHECK_CHANNEL); | |
248 | + | |
249 | + /* set the default for privs for staff */ | |
250 | + memset(&privs_staff, 0, sizeof(privs_staff)); | |
251 | + FlagSet(&privs_staff, PRIV_CHAN_LIMIT); | |
252 | + FlagSet(&privs_staff, PRIV_CLAIM_NICK); | |
253 | + FlagSet(&privs_staff, PRIV_GLINE_LOOKUP); | |
254 | + FlagSet(&privs_staff, PRIV_NOIDLE); | |
255 | + FlagSet(&privs_staff, PRIV_HIDE_CHANS); | |
256 | + FlagSet(&privs_staff, PRIV_CHECK_CHANNEL); | |
257 | ||
258 | privs_defaults_set = 1; | |
259 | } | |
260 | ||
261 | - /* Decide whether to use global or local oper defaults. */ | |
262 | - if (FlagHas(&oper->privs_dirty, PRIV_PROPAGATE)) | |
263 | + /* Decide whether to use staff, global or local oper defaults. */ | |
264 | + if (FlagHas(&oper->privs_dirty, PRIV_STAFF) || | |
265 | + FlagHas(&oper->conn_class->privs_dirty, PRIV_STAFF)) | |
266 | + defaults = &privs_staff; | |
267 | + else if (FlagHas(&oper->privs_dirty, PRIV_PROPAGATE)) | |
268 | defaults = FlagHas(&oper->privs, PRIV_PROPAGATE) ? &privs_global : &privs_local; | |
269 | else if (FlagHas(&oper->conn_class->privs_dirty, PRIV_PROPAGATE)) | |
270 | defaults = FlagHas(&oper->conn_class->privs, PRIV_PROPAGATE) ? &privs_global : &privs_local; | |
271 | else { | |
272 | - assert(0 && "Oper has no propagation and neither does connection class"); | |
273 | + assert(0 && "Oper has no propagation/staff and neither does connection class"); | |
274 | return; | |
275 | } | |
276 | ||
277 | @@ -226,6 +248,17 @@ | |
278 | ClrPriv(client, PRIV_OPKICK); | |
279 | ClrPriv(client, PRIV_BADCHAN); | |
280 | } | |
281 | + /* TODO: better way than this? */ | |
282 | + /* do not let staff have privs they should not have */ | |
283 | + if (HasPriv(client, PRIV_STAFF)) { | |
284 | + for (priv = 0; priv < PRIV_LAST_PRIV; ++priv) { | |
285 | + if (priv == PRIV_STAFF || priv == PRIV_CHAN_LIMIT || priv == PRIV_CLAIM_NICK || | |
286 | + priv == PRIV_GLINE_LOOKUP || priv == PRIV_NOIDLE || priv == PRIV_HIDE_CHANS || | |
287 | + priv == PRIV_CHECK_CHANNEL) | |
288 | + continue; | |
289 | + ClrPriv(client, priv); | |
290 | + } | |
291 | + } | |
292 | } | |
293 | ||
294 | /** Array mapping privilege values to names and vice versa. */ | |
295 | @@ -248,6 +281,8 @@ | |
296 | P(PARANOID), P(CHECK), P(WALL), P(CLOSE), | |
297 | P(ROUTE), P(ROUTEINFO), P(SERVERINFO), P(CHANNEL_PRIVACY), | |
298 | P(USER_PRIVACY), | |
299 | + P(STAFF), P(CLAIM_NICK), P(GLINE_LOOKUP), P(HIDE_CHANS), | |
300 | + P(CHECK_CHANNEL), | |
301 | #undef P | |
302 | { 0, 0 } | |
303 | }; | |
304 | diff -r b6cf63c513c5 ircd/ircd_lexer.l | |
305 | --- a/ircd/ircd_lexer.l Thu Feb 12 14:05:21 2009 +0100 | |
306 | +++ b/ircd/ircd_lexer.l Thu Feb 12 14:18:31 2009 +0100 | |
307 | @@ -168,6 +168,11 @@ | |
308 | { "serverinfo", TPRIV_SERVERINFO }, | |
309 | { "user_privacy", TPRIV_USER_PRIVACY }, | |
310 | { "channel_privacy", TPRIV_CHANNEL_PRIVACY }, | |
311 | + { "staff", TPRIV_STAFF }, | |
312 | + { "claim_nick", TPRIV_CLAIM_NICK }, | |
313 | + { "gline_lookup", TPRIV_GLINE_LOOKUP }, | |
314 | + { "hide_chans", TPRIV_HIDE_CHANS }, | |
315 | + { "check_channel", TPRIV_CHECK_CHANNEL }, | |
316 | { NULL, 0 } | |
317 | }; | |
318 | static int ntokens; | |
319 | diff -r b6cf63c513c5 ircd/ircd_parser.y | |
320 | --- a/ircd/ircd_parser.y Thu Feb 12 14:05:21 2009 +0100 | |
321 | +++ b/ircd/ircd_parser.y Thu Feb 12 14:18:31 2009 +0100 | |
322 | @@ -189,7 +189,9 @@ | |
323 | %token TPRIV_FORCE_OPMODE TPRIV_FORCE_LOCAL_OPMODE TPRIV_APASS_OPMODE | |
324 | %token TPRIV_CHANSERV TPRIV_XTRA_OPER TPRIV_NOIDLE TPRIV_FREEFORM TPRIV_PARANOID | |
325 | %token TPRIV_CHECK TPRIV_WALL TPRIV_CLOSE TPRIV_ROUTE TPRIV_ROUTEINFO TPRIV_SERVERINFO | |
326 | -%token TPRIV_CHANNEL_PRIVACY TPRIV_USER_PRIVACY TPRIV_LIST_CHAN | |
327 | +%token TPRIV_CHANNEL_PRIVACY TPRIV_USER_PRIVACY TPRIV_LIST_CHAN | |
328 | +%token TPRIV_STAFF TPRIV_CLAIM_NICK TPRIV_GLINE_LOOKUP TPRIV_HIDE_CHANS | |
329 | +%token TPRIV_CHECK_CHANNEL | |
330 | /* and some types... */ | |
331 | %type <num> sizespec | |
332 | %type <num> timespec timefactor factoredtimes factoredtime | |
333 | @@ -593,8 +595,10 @@ | |
334 | else if (c_class == NULL) | |
335 | parse_error("Invalid or missing class in operator block"); | |
336 | else if (!FlagHas(&privs_dirty, PRIV_PROPAGATE) | |
337 | - && !FlagHas(&c_class->privs_dirty, PRIV_PROPAGATE)) | |
338 | - parse_error("Operator block for %s and class %s have no LOCAL setting", name, c_class->cc_name); | |
339 | + && !FlagHas(&c_class->privs_dirty, PRIV_PROPAGATE) | |
340 | + && !FlagHas(&privs_dirty, PRIV_STAFF) | |
341 | + && !FlagHas(&c_class->privs_dirty, PRIV_STAFF)) | |
342 | + parse_error("Operator block for %s and class %s have no LOCAL or STAFF setting", name, c_class->cc_name); | |
343 | else for (link = hosts; link != NULL; link = link->next) { | |
344 | aconf = make_conf(CONF_OPERATOR); | |
345 | DupString(aconf->name, name); | |
346 | @@ -704,6 +708,11 @@ | |
347 | TPRIV_SERVERINFO { $$ = PRIV_SERVERINFO ; } | | |
348 | TPRIV_CHANNEL_PRIVACY { $$ = PRIV_CHANNEL_PRIVACY ; } | | |
349 | TPRIV_USER_PRIVACY { $$ = PRIV_USER_PRIVACY ; } | | |
350 | + TPRIV_STAFF { $$ = PRIV_STAFF; } | | |
351 | + TPRIV_CLAIM_NICK { $$ = PRIV_CLAIM_NICK; } | | |
352 | + TPRIV_GLINE_LOOKUP { $$ = PRIV_GLINE_LOOKUP; } | | |
353 | + TPRIV_CHECK_CHANNEL { $$ = PRIV_CHECK_CHANNEL; } | | |
354 | + TPRIV_HIDE_CHANS { $$ = PRIV_HIDE_CHANS; } | | |
355 | TPRIV_PARANOID { $$ = PRIV_PARANOID; } ; | |
356 | yesorno: YES { $$ = 1; } | NO { $$ = 0; }; | |
357 | ||
358 | diff -r b6cf63c513c5 ircd/m_check.c | |
359 | --- a/ircd/m_check.c Thu Feb 12 14:05:21 2009 +0100 | |
360 | +++ b/ircd/m_check.c Thu Feb 12 14:18:31 2009 +0100 | |
361 | @@ -94,7 +94,12 @@ | |
362 | struct Client *acptr; | |
363 | int flags = CHECK_SHOWUSERS, i; | |
364 | ||
365 | - if (!HasPriv(sptr, PRIV_CHECK)) | |
366 | + /* not an oper or staff */ | |
367 | + if (!IsAnOper(sptr) && !IsStaff(sptr)) | |
368 | + return send_reply(sptr, ERR_NOPRIVILEGES); | |
369 | + | |
370 | + /* no privs */ | |
371 | + if (!HasPriv(sptr, PRIV_CHECK) && !HasPriv(sptr, PRIV_CHECK_CHANNEL)) | |
372 | return send_reply(sptr, ERR_NOPRIVILEGES); | |
373 | ||
374 | if (parc < 2) { | |
375 | @@ -104,7 +109,9 @@ | |
376 | ||
377 | if ( parc>=4 || | |
378 | (parc==3 && parv[2][0] != '-')) { | |
379 | - /* remote query */ | |
380 | + /* remote query - no need to restrict staff, | |
381 | + * hunt_server_cmd is told here that sptr needs to be an oper | |
382 | + */ | |
383 | if (hunt_server_cmd(sptr, CMD_CHECK, cptr, 0, parc==4 ? "%C %s %s" : "%C %s", 1, parc, parv) != HUNTED_ISME) | |
384 | return 0; | |
385 | parv++; parc--; | |
386 | @@ -152,11 +159,20 @@ | |
387 | if (IsChannelName(parv[1])) { /* channel */ | |
388 | if ((chptr = FindChannel(parv[1]))) { | |
389 | checkChannel(sptr, chptr); | |
390 | - checkUsers(sptr, chptr, flags); | |
391 | + if (client_can_check_channel(sptr, chptr)) | |
392 | + checkUsers(sptr, chptr, flags); | |
393 | + else { | |
394 | + send_reply(sptr, SND_EXPLICIT | RPL_DATASTR, | |
395 | + ":Aborting - Channel %s has an IRC Operator on it.", chptr->chname); | |
396 | + send_reply(sptr, RPL_ENDOFCHECK, " "); | |
397 | + } | |
398 | } | |
399 | else | |
400 | send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]); | |
401 | } | |
402 | + /* staff can only check channel - stop here */ | |
403 | + else if (IsStaff(sptr)) | |
404 | + return send_reply(sptr, ERR_NOPRIVILEGES); | |
405 | else if ((acptr = FindClient(parv[1])) && !(FindServer(parv[1]))) { /* client and not a server */ | |
406 | if (!IsRegistered(acptr)) { | |
407 | send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]); | |
408 | @@ -177,6 +193,36 @@ | |
409 | } | |
410 | ||
411 | ||
412 | +/* test if a client can CHECK a channel | |
413 | + * return 1 when allowed, else 0 | |
414 | + */ | |
415 | +int client_can_check_channel(struct Client *sptr, struct Channel *chptr) { | |
416 | + struct Membership *lp; | |
417 | + | |
418 | + /* opers can */ | |
419 | + if (IsAnOper(sptr)) | |
420 | + return 1; | |
421 | + | |
422 | + /* look at the channel modes | |
423 | + * channel is not secret, private, invite only, or keyed | |
424 | + */ | |
425 | + if (!(chptr->mode.mode & (MODE_SECRET | MODE_PRIVATE | MODE_INVITEONLY)) && (!*chptr->mode.key)) | |
426 | + return 1; | |
427 | + | |
428 | + /* the client is on the channel */ | |
429 | + if (find_channel_member(sptr, chptr)) | |
430 | + return 1; | |
431 | + | |
432 | + /* look for opers on the channel - ignore channel services */ | |
433 | + for (lp = chptr->members; lp; lp = lp->next_member) { | |
434 | + if (IsAnOper(lp->user) && !IsRealChannelService(lp->user)) | |
435 | + return 0; | |
436 | + } | |
437 | + | |
438 | + /* we made it, so it is allowed */ | |
439 | + return 1; | |
440 | +} | |
441 | + | |
442 | ||
443 | /* return number of clients from same IP on the channel */ | |
444 | static int checkClones(struct Channel *chptr, struct Client *cptr) { | |
445 | @@ -313,10 +359,33 @@ | |
446 | ||
447 | if ((flags & CHECK_SHOWUSERS) || ((flags & CHECK_OPSONLY) && opped)) { | |
448 | ircd_snprintf(0, outbuf, sizeof(outbuf), "%s%c", acptr->cli_info, COLOR_OFF); | |
449 | + | |
450 | + /* show IPs and hostnames */ | |
451 | if (flags & CHECK_SHOWHOSTIP) { | |
452 | - ircd_snprintf(0, outbuf2, sizeof(outbuf2), " [%s]", ircd_ntoa(&(cli_ip(acptr)))); | |
453 | + /* staff - do not show real IPs*/ | |
454 | + if (IsStaff(sptr)) | |
455 | + ircd_snprintf(0, outbuf2, sizeof(outbuf2), " [%s]", | |
456 | + (HasHiddenHost(acptr) || HasSetHost(acptr)) ? | |
457 | + feature_str(FEAT_HIDDEN_IP) : ircd_ntoa(&(cli_ip(acptr)))); | |
458 | + else | |
459 | + ircd_snprintf(0, outbuf2, sizeof(outbuf2), " [%s]", ircd_ntoa(&(cli_ip(acptr)))); | |
460 | } | |
461 | - send_reply(sptr, RPL_CHANUSER, ustat, acptr->cli_name, cli_user(acptr)->realusername, | |
462 | + /* staff - do not show real hostnames or IPs */ | |
463 | + if (IsStaff(sptr)) | |
464 | + send_reply(sptr, RPL_CHANUSER, ustat, acptr->cli_name, cli_user(acptr)->username, | |
465 | + /* show IPs instead of hostnames - respect hiddenhost and sethost */ | |
466 | + ((flags & CHECK_SHOWIPS) ? | |
467 | + ((HasHiddenHost(acptr) || HasSetHost(acptr)) ? | |
468 | + feature_str(FEAT_HIDDEN_IP) : ircd_ntoa(&(cli_ip(acptr)))) : cli_user(acptr)->host), | |
469 | + /* show IPs too - set above */ | |
470 | + (flags & CHECK_SHOWHOSTIP) ? outbuf2 : "", | |
471 | + /* show servernames instead of realnames - respect HIS */ | |
472 | + ((flags & CHECK_SHOWSERVER) && !feature_bool(FEAT_HIS_WHO_SERVERNAME)) ? | |
473 | + cli_name(cli_user(acptr)->server) : outbuf, | |
474 | + /* show account */ | |
475 | + (c ? cli_user(acptr)->account : "")); | |
476 | + else | |
477 | + send_reply(sptr, RPL_CHANUSER, ustat, acptr->cli_name, cli_user(acptr)->realusername, | |
478 | ((flags & CHECK_SHOWIPS) ? ircd_ntoa(&(cli_ip(acptr))) : cli_user(acptr)->realhost), (flags & CHECK_SHOWHOSTIP) ? outbuf2 : "", (flags & CHECK_SHOWSERVER) ? cli_name(cli_user(acptr)->server) : outbuf, | |
479 | (c ? cli_user(acptr)->account : "")); | |
480 | } | |
481 | @@ -379,6 +448,11 @@ | |
482 | /* Topic */ | |
483 | if (strlen(chptr->topic) <= 0) | |
484 | send_reply(sptr, RPL_DATASTR, " Topic:: <none>"); | |
485 | + | |
486 | + /* channel is +s - do not show the topic to staff, unless they are there */ | |
487 | + else if (SecretChannel(chptr) && IsStaff(sptr) && !find_channel_member(sptr, chptr)) | |
488 | + send_reply(sptr, RPL_DATASTR, " Topic:: <hidden>"); | |
489 | + | |
490 | else { | |
491 | ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Topic:: %s", chptr->topic); | |
492 | send_reply(sptr, RPL_DATASTR, outbuf); | |
493 | @@ -401,6 +475,7 @@ | |
494 | modebuf[0] = '\0'; | |
495 | parabuf[0] = '\0'; | |
496 | ||
497 | + /* no need to check modes - this will hide the key from non-opers */ | |
498 | channel_modes(sptr, modebuf, parabuf, sizeof(modebuf), chptr, NULL); | |
499 | ||
500 | if(modebuf[1] == '\0') | |
501 | @@ -464,6 +539,9 @@ | |
502 | } else if (IsAnOper(acptr)) { | |
503 | ircd_snprintf(0, outbuf, sizeof(outbuf), " Status:: IRC Operator (ID: %s)", cli_user(acptr)->opername ? cli_user(acptr)->opername : "<unknown>"); | |
504 | send_reply(sptr, RPL_DATASTR, outbuf); | |
505 | + } else if (IsStaff(acptr)) { | |
506 | + ircd_snprintf(0, outbuf, sizeof(outbuf), " Status:: IRC Staff (ID: %s)", cli_user(acptr)->staffname ? cli_user(acptr)->staffname : "<unknown>"); | |
507 | + send_reply(sptr, RPL_DATASTR, outbuf); | |
508 | } else | |
509 | send_reply(sptr, RPL_DATASTR, " Status:: Client"); | |
510 | ||
511 | diff -r b6cf63c513c5 ircd/m_gline.c | |
512 | --- a/ircd/m_gline.c Thu Feb 12 14:05:21 2009 +0100 | |
513 | +++ b/ircd/m_gline.c Thu Feb 12 14:18:31 2009 +0100 | |
514 | @@ -669,11 +669,13 @@ | |
515 | int | |
516 | m_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) | |
517 | { | |
518 | - if (feature_bool(FEAT_HIS_USERGLINE)) | |
519 | - return send_reply(sptr, ERR_DISABLED, "GLINE"); | |
520 | + | |
521 | + /* check feature HIS_USERGLINE, Staff and priv GLINE_LOOKUP */ | |
522 | + if (feature_bool(FEAT_HIS_USERGLINE) && (!IsStaff(sptr) || !HasPriv(sptr, PRIV_GLINE_LOOKUP))) | |
523 | + return send_reply(sptr, ERR_NOPRIVILEGES); | |
524 | ||
525 | if (parc < 2) | |
526 | - return send_reply(sptr, ERR_NOSUCHGLINE, ""); | |
527 | + return send_reply(sptr, ERR_NOSUCHGLINE, "*"); | |
528 | ||
529 | return gline_list(sptr, parv[1]); | |
530 | } | |
531 | diff -r b6cf63c513c5 ircd/m_lusers.c | |
532 | --- a/ircd/m_lusers.c Thu Feb 12 14:05:21 2009 +0100 | |
533 | +++ b/ircd/m_lusers.c Thu Feb 12 14:18:31 2009 +0100 | |
534 | @@ -120,6 +120,8 @@ | |
535 | UserStats.inv_clients, UserStats.servers); | |
536 | if (longoutput && UserStats.opers) | |
537 | send_reply(sptr, RPL_LUSEROP, UserStats.opers); | |
538 | + if (longoutput && UserStats.staff) | |
539 | + send_reply(sptr, SND_EXPLICIT | RPL_LUSEROP, "%d :staff member(s) online", UserStats.staff); | |
540 | if (UserStats.unknowns > 0) | |
541 | send_reply(sptr, RPL_LUSERUNKNOWN, UserStats.unknowns); | |
542 | if (longoutput && UserStats.channels > 0) | |
543 | @@ -154,6 +156,8 @@ | |
544 | UserStats.inv_clients, UserStats.servers); | |
545 | if (longoutput && UserStats.opers) | |
546 | send_reply(sptr, RPL_LUSEROP, UserStats.opers); | |
547 | + if (longoutput && UserStats.staff) | |
548 | + send_reply(sptr, SND_EXPLICIT | RPL_LUSEROP, "%d :staff member(s) online", UserStats.staff); | |
549 | if (UserStats.unknowns > 0) | |
550 | send_reply(sptr, RPL_LUSERUNKNOWN, UserStats.unknowns); | |
551 | if (longoutput && UserStats.channels > 0) | |
552 | diff -r b6cf63c513c5 ircd/m_oper.c | |
553 | --- a/ircd/m_oper.c Thu Feb 12 14:05:21 2009 +0100 | |
554 | +++ b/ircd/m_oper.c Thu Feb 12 14:18:31 2009 +0100 | |
555 | @@ -143,6 +143,10 @@ | |
556 | name = parc > 1 ? parv[1] : 0; | |
557 | password = parc > 2 ? parv[2] : 0; | |
558 | ||
559 | + /* staff doing OPER */ | |
560 | + if (IsStaff(sptr)) | |
561 | + return send_reply(sptr, SND_EXPLICIT | RPL_YOUREOPER, ":You are now IRC Staff"); | |
562 | + | |
563 | if (EmptyString(name) || EmptyString(password)) | |
564 | return need_more_params(sptr, "OPER"); | |
565 | ||
566 | @@ -169,6 +173,18 @@ | |
567 | } | |
568 | SetLocOp(sptr); | |
569 | client_set_privs(sptr, aconf); | |
570 | + | |
571 | + /* staff - clear flag and privs, and reject it */ | |
572 | + if (HasPriv(sptr, PRIV_STAFF)) { | |
573 | + ClearLocOp(sptr); | |
574 | + client_set_privs(sptr, NULL); | |
575 | + send_reply(sptr, ERR_NOOPERHOST); | |
576 | + sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) as %s", | |
577 | + parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr), name); | |
578 | + return 0; | |
579 | + } | |
580 | + | |
581 | + /* oper */ | |
582 | if (HasPriv(sptr, PRIV_PROPAGATE)) | |
583 | { | |
584 | ClearLocOp(sptr); | |
585 | diff -r b6cf63c513c5 ircd/m_privs.c | |
586 | --- a/ircd/m_privs.c Thu Feb 12 14:05:21 2009 +0100 | |
587 | +++ b/ircd/m_privs.c Thu Feb 12 14:18:31 2009 +0100 | |
588 | @@ -38,6 +38,27 @@ | |
589 | #include "numnicks.h" | |
590 | #include "send.h" | |
591 | ||
592 | +/** Handle a local staff's privilege query. | |
593 | + * @param[in] cptr Client that sent us the message. | |
594 | + * @param[in] sptr Original source of message. | |
595 | + * @param[in] parc Number of arguments. | |
596 | + * @param[in] parv Argument vector. | |
597 | + * @see \ref m_functions | |
598 | + */ | |
599 | +int m_privs(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) | |
600 | +{ | |
601 | + /* not staff */ | |
602 | + if (!IsStaff(sptr)) | |
603 | + return send_reply(sptr, ERR_NOPRIVILEGES); | |
604 | + | |
605 | + /* no parameters given, show own privs */ | |
606 | + if (parc < 2) | |
607 | + return client_report_privs(sptr, sptr); | |
608 | + | |
609 | + /* staff not allowed to view privs on other users */ | |
610 | + return send_reply(sptr, ERR_NOPRIVILEGES); | |
611 | +} | |
612 | + | |
613 | /** Handle a local operator's privilege query. | |
614 | * @param[in] cptr Client that sent us the message. | |
615 | * @param[in] sptr Original source of message. | |
616 | diff -r b6cf63c513c5 ircd/m_staff.c | |
617 | --- /dev/null Thu Jan 01 00:00:00 1970 +0000 | |
618 | +++ b/ircd/m_staff.c Thu Feb 12 14:18:31 2009 +0100 | |
619 | @@ -0,0 +1,252 @@ | |
620 | +/* | |
621 | + * IRC - Internet Relay Chat, ircd/m_oper.c | |
622 | + * Copyright (C) 1990 Jarkko Oikarinen and | |
623 | + * University of Oulu, Computing Center | |
624 | + * | |
625 | + * See file AUTHORS in IRC package for additional names of | |
626 | + * the programmers. | |
627 | + * | |
628 | + * This program is free software; you can redistribute it and/or modify | |
629 | + * it under the terms of the GNU General Public License as published by | |
630 | + * the Free Software Foundation; either version 1, or (at your option) | |
631 | + * any later version. | |
632 | + * | |
633 | + * This program is distributed in the hope that it will be useful, | |
634 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
635 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
636 | + * GNU General Public License for more details. | |
637 | + * | |
638 | + * You should have received a copy of the GNU General Public License | |
639 | + * along with this program; if not, write to the Free Software | |
640 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
641 | + * | |
642 | + * $Id: m_oper.c 1327 2005-03-19 22:52:33Z entrope $ | |
643 | + */ | |
644 | + | |
645 | +/* | |
646 | + * m_functions execute protocol messages on this server: | |
647 | + * | |
648 | + * cptr is always NON-NULL, pointing to a *LOCAL* client | |
649 | + * structure (with an open socket connected!). This | |
650 | + * identifies the physical socket where the message | |
651 | + * originated (or which caused the m_function to be | |
652 | + * executed--some m_functions may call others...). | |
653 | + * | |
654 | + * sptr is the source of the message, defined by the | |
655 | + * prefix part of the message if present. If not | |
656 | + * or prefix not found, then sptr==cptr. | |
657 | + * | |
658 | + * (!IsServer(cptr)) => (cptr == sptr), because | |
659 | + * prefixes are taken *only* from servers... | |
660 | + * | |
661 | + * (IsServer(cptr)) | |
662 | + * (sptr == cptr) => the message didn't | |
663 | + * have the prefix. | |
664 | + * | |
665 | + * (sptr != cptr && IsServer(sptr) means | |
666 | + * the prefix specified servername. (?) | |
667 | + * | |
668 | + * (sptr != cptr && !IsServer(sptr) means | |
669 | + * that message originated from a remote | |
670 | + * user (not local). | |
671 | + * | |
672 | + * combining | |
673 | + * | |
674 | + * (!IsServer(sptr)) means that, sptr can safely | |
675 | + * taken as defining the target structure of the | |
676 | + * message in this server. | |
677 | + * | |
678 | + * *Always* true (if 'parse' and others are working correct): | |
679 | + * | |
680 | + * 1) sptr->from == cptr (note: cptr->from == cptr) | |
681 | + * | |
682 | + * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr | |
683 | + * *cannot* be a local connection, unless it's | |
684 | + * actually cptr!). [MyConnect(x) should probably | |
685 | + * be defined as (x == x->from) --msa ] | |
686 | + * | |
687 | + * parc number of variable parameter strings (if zero, | |
688 | + * parv is allowed to be NULL) | |
689 | + * | |
690 | + * parv a NULL terminated list of parameter pointers, | |
691 | + * | |
692 | + * parv[0], sender (prefix string), if not present | |
693 | + * this points to an empty string. | |
694 | + * parv[1]...parv[parc-1] | |
695 | + * pointers to additional parameters | |
696 | + * parv[parc] == NULL, *always* | |
697 | + * | |
698 | + * note: it is guaranteed that parv[0]..parv[parc-1] are all | |
699 | + * non-NULL pointers. | |
700 | + */ | |
701 | +#include "config.h" | |
702 | + | |
703 | +#include "client.h" | |
704 | +#include "hash.h" | |
705 | +#include "ircd.h" | |
706 | +#include "ircd_alloc.h" | |
707 | +#include "ircd_features.h" | |
708 | +#include "ircd_log.h" | |
709 | +#include "ircd_reply.h" | |
710 | +#include "ircd_string.h" | |
711 | +#include "ircd_crypt.h" | |
712 | +#include "msg.h" | |
713 | +#include "numeric.h" | |
714 | +#include "numnicks.h" | |
715 | +#include "querycmds.h" | |
716 | +#include "s_conf.h" | |
717 | +#include "s_debug.h" | |
718 | +#include "s_user.h" | |
719 | +#include "s_misc.h" | |
720 | +#include "send.h" | |
721 | + | |
722 | +/* #include <assert.h> -- Now using assert in ircd_log.h */ | |
723 | +#include <stdlib.h> | |
724 | +#include <string.h> | |
725 | + | |
726 | + | |
727 | +/* TODO: from m_oper.c - use it from there? and not have a copy here? */ | |
728 | +int staff_password_match(const char* to_match, const char* passwd) | |
729 | +{ | |
730 | + char *crypted; | |
731 | + int res; | |
732 | + /* | |
733 | + * use first two chars of the password they send in as salt | |
734 | + * | |
735 | + * passwd may be NULL. Head it off at the pass... | |
736 | + */ | |
737 | + if (!to_match || !passwd) | |
738 | + return 0; | |
739 | + | |
740 | + /* we no longer do a CRYPT_OPER_PASSWORD check because a clear | |
741 | + text passwords just handled by a fallback mechanism called | |
742 | + crypt_clear if it's enabled -- hikari */ | |
743 | + crypted = ircd_crypt(to_match, passwd); | |
744 | + | |
745 | + if (!crypted) | |
746 | + return 0; | |
747 | + res = strcmp(crypted, passwd); | |
748 | + MyFree(crypted); | |
749 | + return 0 == res; | |
750 | +} | |
751 | + | |
752 | + | |
753 | +/* | |
754 | + * m_staff - generic message handler | |
755 | + */ | |
756 | +int m_staff(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) | |
757 | +{ | |
758 | + struct ConfItem* aconf; | |
759 | + char* name; | |
760 | + char* password; | |
761 | + | |
762 | + assert(0 != cptr); | |
763 | + assert(cptr == sptr); | |
764 | + | |
765 | + name = parc > 1 ? parv[1] : 0; | |
766 | + password = parc > 2 ? parv[2] : 0; | |
767 | + | |
768 | + /* staff doing STAFF */ | |
769 | + if (IsStaff(sptr)) | |
770 | + return send_reply(sptr, SND_EXPLICIT | RPL_YOUREOPER, ":You are now IRC Staff"); | |
771 | + | |
772 | + /* check input */ | |
773 | + if (EmptyString(name) || EmptyString(password)) | |
774 | + return need_more_params(sptr, "STAFF"); | |
775 | + | |
776 | + /* attempt to find the operator block */ | |
777 | + aconf = find_conf_exact(name, sptr, CONF_OPERATOR); | |
778 | + if (!aconf || IsIllegal(aconf)) { | |
779 | + send_reply(sptr, ERR_NOOPERHOST); | |
780 | + sendto_opmask_butone(0, SNO_OLDREALOP, "Failed STAFF attempt by %s (%s@%s) as %s", | |
781 | + parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr), name); | |
782 | + return 0; | |
783 | + } | |
784 | + | |
785 | + /* we should have it by now */ | |
786 | + assert(0 != (aconf->status & CONF_OPERATOR)); | |
787 | + | |
788 | + /* compare passwords */ | |
789 | + if (staff_password_match(password, aconf->passwd)) { | |
790 | + struct Flags old_mode = cli_flags(sptr); | |
791 | + | |
792 | + /* mismatch */ | |
793 | + if (ACR_OK != attach_conf(sptr, aconf)) { | |
794 | + send_reply(sptr, ERR_NOOPERHOST); | |
795 | + sendto_opmask_butone(0, SNO_OLDREALOP, "Failed STAFF attempt by %s " | |
796 | + "(%s@%s) as %s", parv[0], cli_user(sptr)->realusername, | |
797 | + cli_sockhost(sptr), aconf->name); | |
798 | + return 0; | |
799 | + } | |
800 | + | |
801 | + /* set privs */ | |
802 | + SetStaff(sptr); | |
803 | + client_set_privs(sptr, aconf); | |
804 | + | |
805 | + /* are they staff? */ | |
806 | + if (HasPriv(sptr, PRIV_STAFF)) { | |
807 | + ++UserStats.staff; | |
808 | + | |
809 | + /* set staffname */ | |
810 | + if (cli_user(sptr)->staffname) | |
811 | + MyFree(cli_user(sptr)->staffname); | |
812 | + cli_user(sptr)->staffname = (char*) MyMalloc(strlen(name) + 1); | |
813 | + assert(0 != cli_user(sptr)->staffname); | |
814 | + ircd_strncpy(cli_user(sptr)->staffname, aconf->name, ACCOUNTLEN); | |
815 | + | |
816 | + /* TODO: check sendQ */ | |
817 | + /* send out the mode and confirmation */ | |
818 | + cli_max_sendq(sptr) = 0; /* Get the sendq from the oper's class */ | |
819 | + send_umode_out(cptr, sptr, &old_mode, 0); | |
820 | + /* TODO: create own numeric for this? */ | |
821 | + send_reply(sptr, SND_EXPLICIT | RPL_YOUREOPER, ":You are now IRC Staff"); | |
822 | + | |
823 | + /* inform ops and log it */ | |
824 | + sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is now staff (S) as %s", | |
825 | + parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr), | |
826 | + cli_user(sptr)->staffname); | |
827 | + log_write(LS_OPER, L_INFO, 0, "STAFF (%s) by (%#R)", name, sptr); | |
828 | + | |
829 | + /* not staff - clear flag and privs, and reject */ | |
830 | + } else { | |
831 | + client_set_privs(sptr, NULL); | |
832 | + ClearStaff(sptr); | |
833 | + send_reply(sptr, ERR_NOOPERHOST); | |
834 | + sendto_opmask_butone(0, SNO_OLDREALOP, "Failed STAFF attempt by %s (%s@%s) as %s", | |
835 | + parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr), name); | |
836 | + return 0; | |
837 | + } | |
838 | + | |
839 | + /* failed */ | |
840 | + } else { | |
841 | + send_reply(sptr, ERR_PASSWDMISMATCH); | |
842 | + sendto_opmask_butone(0, SNO_OLDREALOP, "Failed STAFF attempt by %s (%s@%s) as %s", | |
843 | + parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr), aconf->name); | |
844 | + } | |
845 | + return 0; | |
846 | +} | |
847 | + | |
848 | + | |
849 | +/* | |
850 | + * ms_staff - server message handler | |
851 | + */ | |
852 | +int ms_staff(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) | |
853 | +{ | |
854 | + assert(0 != cptr); | |
855 | + assert(IsServer(cptr)); | |
856 | + /* TODO: KILL sptr (if user KILL, if server SQUIT?) */ | |
857 | + protocol_violation(sptr, "Received STAFF message from %C", sptr); | |
858 | + return 0; | |
859 | +} | |
860 | + | |
861 | + | |
862 | +/* | |
863 | + * mo_staff - oper message handler | |
864 | + */ | |
865 | +int mo_staff(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) | |
866 | +{ | |
867 | + assert(0 != cptr); | |
868 | + assert(cptr == sptr); | |
869 | + send_reply(sptr, RPL_YOUREOPER); | |
870 | + return 0; | |
871 | +} | |
872 | diff -r b6cf63c513c5 ircd/m_trace.c | |
873 | --- a/ircd/m_trace.c Thu Feb 12 14:05:21 2009 +0100 | |
874 | +++ b/ircd/m_trace.c Thu Feb 12 14:18:31 2009 +0100 | |
875 | @@ -198,7 +198,7 @@ | |
876 | if (!(acptr = LocalClientArray[i])) /* Local Connection? */ | |
877 | continue; | |
878 | if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) && | |
879 | - !IsAnOper(acptr) && (acptr != sptr)) | |
880 | + !IsStaffOrAnOper(acptr) && (acptr != sptr)) | |
881 | continue; | |
882 | if (!doall && wilds && match(tname, cli_name(acptr))) | |
883 | continue; | |
884 | @@ -232,11 +232,15 @@ | |
885 | /* Only opers see users if there is a wildcard | |
886 | but anyone can see all the opers. */ | |
887 | if ((IsAnOper(sptr) && (MyUser(sptr) || | |
888 | - !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr)) { | |
889 | + !(dow && IsInvisible(acptr)))) || !dow || IsStaffOrAnOper(acptr)) { | |
890 | if (IsAnOper(acptr)) | |
891 | send_reply(sptr, RPL_TRACEOPERATOR, conClass, | |
892 | get_client_name(acptr, SHOW_IP), | |
893 | CurrentTime - cli_lasttime(acptr)); | |
894 | + else if (IsStaff(acptr)) | |
895 | + send_reply(sptr, SND_EXPLICIT | RPL_TRACEOPERATOR, "Staff %s %s %ld ", conClass, | |
896 | + get_client_name(acptr, SHOW_IP), | |
897 | + CurrentTime - cli_lasttime(acptr)); | |
898 | else | |
899 | send_reply(sptr, RPL_TRACEUSER, conClass, | |
900 | get_client_name(acptr, SHOW_IP), | |
901 | diff -r b6cf63c513c5 ircd/m_who.c | |
902 | --- a/ircd/m_who.c Thu Feb 12 14:05:21 2009 +0100 | |
903 | +++ b/ircd/m_who.c Thu Feb 12 14:18:31 2009 +0100 | |
904 | @@ -319,7 +319,7 @@ | |
905 | for (member = chptr->members; member; member = member->next_member) | |
906 | { | |
907 | acptr = member->user; | |
908 | - if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr)) | |
909 | + if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr) && !IsStaff(acptr)) | |
910 | continue; | |
911 | if ((acptr != sptr) | |
912 | && ((member->status & CHFL_ZOMBIE) | |
913 | @@ -341,7 +341,7 @@ | |
914 | else | |
915 | { | |
916 | if ((acptr = FindUser(nick)) && | |
917 | - ((!(bitsel & WHOSELECT_OPER)) || SeeOper(sptr,acptr)) && | |
918 | + ((!(bitsel & WHOSELECT_OPER)) || SeeOper(sptr,acptr) || IsStaff(acptr)) && | |
919 | Process(acptr) && SHOW_MORE(sptr, counter)) | |
920 | { | |
921 | do_who(sptr, acptr, 0, fields, qrt); | |
922 | @@ -389,7 +389,7 @@ | |
923 | if (!(IsUser(acptr) && Process(acptr))) | |
924 | continue; /* Now Process() is at the beginning, if we fail | |
925 | we'll never have to show this acptr in this query */ | |
926 | - if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr)) | |
927 | + if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr) && !IsStaff(acptr)) | |
928 | continue; | |
929 | if ((mask) && | |
930 | ((!(matchsel & WHO_FIELD_NIC)) | |
931 | @@ -426,7 +426,7 @@ | |
932 | { | |
933 | if (!(IsUser(acptr) && Process(acptr))) | |
934 | continue; | |
935 | - if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr)) | |
936 | + if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr) && !IsStaff(acptr)) | |
937 | continue; | |
938 | if (!(SEE_USER(sptr, acptr, bitsel))) | |
939 | continue; | |
940 | diff -r b6cf63c513c5 ircd/m_whois.c | |
941 | --- a/ircd/m_whois.c Thu Feb 12 14:05:21 2009 +0100 | |
942 | +++ b/ircd/m_whois.c Thu Feb 12 14:18:31 2009 +0100 | |
943 | @@ -216,6 +216,20 @@ | |
944 | send_reply(sptr, RPL_WHOISOPERNAME, name, user->opername); | |
945 | } | |
946 | ||
947 | + /* user is staff */ | |
948 | + if (IsStaff(acptr)) { | |
949 | + /* TODO: use new numeric for this? | |
950 | + */ | |
951 | + send_reply(sptr, SND_EXPLICIT | RPL_WHOISOPERATOR, "%s :is %s Staff", | |
952 | + name, feature_str(FEAT_NETWORK)); | |
953 | + /* TODO: allow staff to see eachother's staffname? IsStaffOrAnOper() | |
954 | + * TODO: is user->staffname not always set? | |
955 | + * TODO: "is staff as" ..? | |
956 | + */ | |
957 | + if (IsAnOper(sptr) && user->staffname) | |
958 | + send_reply(sptr, SND_EXPLICIT | RPL_WHOISOPERNAME, "%s %s :is staff as", name, user->staffname); | |
959 | + } | |
960 | + | |
961 | if (IsAccount(acptr)) | |
962 | send_reply(sptr, RPL_WHOISACCOUNT, name, user->account); | |
963 | ||
964 | @@ -223,16 +237,24 @@ | |
965 | send_reply(sptr, RPL_WHOISACTUALLY, name, user->realusername, | |
966 | user->realhost, ircd_ntoa(&cli_ip(acptr))); | |
967 | ||
968 | - if (!IsAnOper(sptr) && IsParanoid(acptr) && IsAnOper(acptr)) | |
969 | + /* TODO: exclude staff from paranoia? */ | |
970 | + if (!IsStaffOrAnOper(sptr) && IsParanoid(acptr) && IsAnOper(acptr)) | |
971 | sendcmdto_one(&me, CMD_NOTICE, acptr, "%C :whois: %s performed a /WHOIS on you.", acptr, cli_name(sptr)); | |
972 | ||
973 | /* Hint: if your looking to add more flags to a user, eg +h, here's | |
974 | * probably a good place to add them :) | |
975 | */ | |
976 | - | |
977 | + /* TODO: allow staff to see through +I? | |
978 | + * (this is priv stuff is getting out of hand, | |
979 | + * oper needs priv USER_PRIVACY to see through +I ???) | |
980 | + * remove that priv requirement for opers to keep things consistent | |
981 | + * also 'user_privacy' makes not much sense here, +I is for privileged users | |
982 | + * opers and staff, to hide idle time from ordinary users | |
983 | + * not from eachother | |
984 | + */ | |
985 | if (MyConnect(acptr) && | |
986 | ((IsAnOper(sptr) && HasPriv(sptr, PRIV_USER_PRIVACY)) || | |
987 | - (!IsNoIdle(acptr) && (!feature_bool(FEAT_HIS_WHOIS_IDLETIME) || | |
988 | + ((!IsNoIdle(acptr) || IsStaff(sptr)) && (!feature_bool(FEAT_HIS_WHOIS_IDLETIME) || | |
989 | sptr == acptr || parc >= 3)))) | |
990 | send_reply(sptr, RPL_WHOISIDLE, name, CurrentTime - user->last, | |
991 | cli_firsttime(acptr)); | |
992 | diff -r b6cf63c513c5 ircd/parse.c | |
993 | --- a/ircd/parse.c Thu Feb 12 14:05:21 2009 +0100 | |
994 | +++ b/ircd/parse.c Thu Feb 12 14:18:31 2009 +0100 | |
995 | @@ -443,6 +443,13 @@ | |
996 | { m_unregistered, m_stats, m_stats, m_stats, m_ignore, mh_stats } | |
997 | }, | |
998 | { | |
999 | + MSG_STAFF, | |
1000 | + TOK_STAFF, | |
1001 | + 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
1002 | + /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */ | |
1003 | + { m_unregistered, m_staff, ms_staff, mo_staff, m_ignore, mh_nohelp } | |
1004 | + }, | |
1005 | + { | |
1006 | MSG_LINKS, | |
1007 | TOK_LINKS, | |
1008 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
1009 | @@ -608,7 +615,7 @@ | |
1010 | TOK_PRIVS, | |
1011 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
1012 | /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */ | |
1013 | - { m_unregistered, m_not_oper, ms_privs, mo_privs, m_ignore, mh_privs } | |
1014 | + { m_unregistered, m_privs, ms_privs, mo_privs, m_ignore, mh_privs } | |
1015 | }, | |
1016 | { | |
1017 | MSG_ACCOUNT, | |
1018 | @@ -654,7 +661,7 @@ | |
1019 | MSG_CHECK, | |
1020 | TOK_CHECK, | |
1021 | 0, MAXPARA, MFLG_SLOW, 0, NULL, | |
1022 | - { m_unregistered, m_not_oper, m_check, m_check, m_ignore, mh_check } | |
1023 | + { m_unregistered, m_check, m_check, m_check, m_ignore, mh_check } | |
1024 | }, | |
1025 | ||
1026 | /* | |
1027 | diff -r b6cf63c513c5 ircd/s_misc.c | |
1028 | --- a/ircd/s_misc.c Thu Feb 12 14:05:21 2009 +0100 | |
1029 | +++ b/ircd/s_misc.c Thu Feb 12 14:18:31 2009 +0100 | |
1030 | @@ -245,6 +245,10 @@ | |
1031 | assert(UserStats.opers > 0); | |
1032 | --UserStats.opers; | |
1033 | } | |
1034 | + if (IsStaff(bcptr)) { | |
1035 | + assert(UserStats.staff > 0); | |
1036 | + --UserStats.staff; | |
1037 | + } | |
1038 | if (MyConnect(bcptr)) | |
1039 | Count_clientdisconnects(bcptr, UserStats); | |
1040 | else | |
1041 | diff -r b6cf63c513c5 ircd/s_stats.c | |
1042 | --- a/ircd/s_stats.c Thu Feb 12 14:05:21 2009 +0100 | |
1043 | +++ b/ircd/s_stats.c Thu Feb 12 14:18:31 2009 +0100 | |
1044 | @@ -339,7 +339,7 @@ | |
1045 | if (!name && IsUser(acptr)) | |
1046 | continue; | |
1047 | /* Don't show invisible people to non opers unless they know the nick */ | |
1048 | - if (IsInvisible(acptr) && (!name || wilds) && !IsAnOper(acptr) && | |
1049 | + if (IsInvisible(acptr) && (!name || wilds) && !IsStaffOrAnOper(acptr) && | |
1050 | (acptr != sptr)) | |
1051 | continue; | |
1052 | /* Only show the ones that match the given mask - if any */ | |
1053 | diff -r b6cf63c513c5 ircd/s_user.c | |
1054 | --- a/ircd/s_user.c Thu Feb 12 14:05:21 2009 +0100 | |
1055 | +++ b/ircd/s_user.c Thu Feb 12 14:18:31 2009 +0100 | |
1056 | @@ -115,6 +115,8 @@ | |
1057 | MyFree(user->away); | |
1058 | if (user->opername) | |
1059 | MyFree(user->opername); | |
1060 | + if (user->staffname) | |
1061 | + MyFree(user->staffname); | |
1062 | /* | |
1063 | * sanity check | |
1064 | */ | |
1065 | @@ -460,6 +462,8 @@ | |
1066 | ++UserStats.inv_clients; | |
1067 | if (IsOper(sptr)) | |
1068 | ++UserStats.opers; | |
1069 | + if (IsStaff(sptr)) | |
1070 | + ++UserStats.staff; | |
1071 | ||
1072 | tmpstr = umode_str(sptr, UMODE_ALL_PARAMS_BUT_OPERID); | |
1073 | ||
1074 | @@ -547,7 +551,8 @@ | |
1075 | { FLAG_NOIDLE, 'I' }, | |
1076 | { FLAG_SETHOST, 'h' }, | |
1077 | { FLAG_PARANOID, 'P' }, | |
1078 | - { FLAG_COMMONCHANSONLY, 'q' } | |
1079 | + { FLAG_COMMONCHANSONLY, 'q' }, | |
1080 | + { FLAG_STAFF, 'S' } | |
1081 | }; | |
1082 | ||
1083 | /** Length of #userModeList. */ | |
1084 | @@ -1024,15 +1029,15 @@ | |
1085 | } | |
1086 | ||
1087 | /* sethost enabled for users? */ | |
1088 | - if (MyConnect(cptr) && !IsAnOper(cptr) && !feature_bool(FEAT_SETHOST_USER)) { | |
1089 | + if (MyConnect(cptr) && !IsStaffOrAnOper(cptr) && !feature_bool(FEAT_SETHOST_USER)) { | |
1090 | send_reply(cptr, ERR_NOPRIVILEGES); | |
1091 | return 0; | |
1092 | } | |
1093 | ||
1094 | /* MODE_DEL: restore original hostmask */ | |
1095 | if (EmptyString(hostmask)) { | |
1096 | - /* is already sethost'ed? and only opers can remove a sethost */ | |
1097 | - if (IsSetHost(cptr) && IsAnOper(cptr)) { | |
1098 | + /* is already sethost'ed? and only opers and staff can remove a sethost */ | |
1099 | + if (IsSetHost(cptr) && IsStaffOrAnOper(cptr)) { | |
1100 | restore = 1; | |
1101 | sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change"); | |
1102 | /* If they are +rx, we need to return to their +x host, not their "real" host */ | |
1103 | @@ -1228,8 +1233,8 @@ | |
1104 | int prop = 0; | |
1105 | int do_host_hiding = 0; | |
1106 | int do_set_host = 0; | |
1107 | - size_t opernamelen; | |
1108 | - char *opername = 0; | |
1109 | + size_t opernamelen, staffnamelen; | |
1110 | + char *opername = 0, *staffname = 0; | |
1111 | char* account = NULL; | |
1112 | ||
1113 | hostmask = password = NULL; | |
1114 | @@ -1445,6 +1450,35 @@ | |
1115 | } | |
1116 | /* There is no -r */ | |
1117 | break; | |
1118 | + | |
1119 | + /* Staff - +S mode */ | |
1120 | + case 'S': | |
1121 | + if (what == MODE_ADD) { | |
1122 | + SetStaff(sptr); | |
1123 | + if (IsServer(cptr)) { | |
1124 | + if (*(p + 1)) { | |
1125 | + staffname = *++p; | |
1126 | + if (cli_user(sptr)->staffname) | |
1127 | + MyFree(cli_user(sptr)->staffname); | |
1128 | + staffnamelen = strlen(staffname); | |
1129 | + if (staffnamelen > ACCOUNTLEN) { | |
1130 | + protocol_violation(cptr, "Received staffname (%s) longer than %d for %s; ignoring.", staffname, ACCOUNTLEN, cli_name(sptr)); | |
1131 | + cli_user(sptr)->staffname = NULL; | |
1132 | + } else { | |
1133 | + cli_user(sptr)->staffname = (char*) MyMalloc(staffnamelen + 1); | |
1134 | + assert(0 != cli_user(sptr)->staffname); | |
1135 | + ircd_strncpy(cli_user(sptr)->staffname, staffname, ACCOUNTLEN); | |
1136 | + } | |
1137 | + } else { | |
1138 | + /* TODO: KILL sptr to resolve desynch? */ | |
1139 | + protocol_violation(cptr, "Received usermode +S for %C but no staffname parameter; ignoring.", sptr); | |
1140 | + ClearStaff(sptr); | |
1141 | + } | |
1142 | + } | |
1143 | + } else | |
1144 | + ClearStaff(sptr); | |
1145 | + break; | |
1146 | + | |
1147 | default: | |
1148 | send_reply(sptr, ERR_UMODEUNKNOWNFLAG, *m); | |
1149 | break; | |
1150 | @@ -1461,6 +1495,8 @@ | |
1151 | ClearOper(sptr); | |
1152 | if (!FlagHas(&setflags, FLAG_LOCOP) && IsLocOp(sptr)) | |
1153 | ClearLocOp(sptr); | |
1154 | + if (!FlagHas(&setflags, FLAG_STAFF) && IsStaff(sptr)) | |
1155 | + ClearStaff(sptr); | |
1156 | if (!FlagHas(&setflags, FLAG_ACCOUNT) && IsAccount(sptr)) | |
1157 | ClrFlag(sptr, FLAG_ACCOUNT); | |
1158 | /* | |
1159 | @@ -1471,9 +1507,9 @@ | |
1160 | ClearChannelService(sptr); | |
1161 | if (!FlagHas(&setflags, FLAG_XTRAOP) && !(IsOper(sptr) && HasPriv(sptr, PRIV_XTRA_OPER))) | |
1162 | ClearXtraOp(sptr); | |
1163 | - if (!FlagHas(&setflags, FLAG_NOCHAN) && !(IsOper(sptr) || feature_bool(FEAT_USER_HIDECHANS))) | |
1164 | + if (!FlagHas(&setflags, FLAG_NOCHAN) && !((IsStaffOrAnOper(sptr) && HasPriv(sptr, PRIV_HIDE_CHANS)) || feature_bool(FEAT_USER_HIDECHANS))) | |
1165 | ClearNoChan(sptr); | |
1166 | - if (!FlagHas(&setflags, FLAG_NOIDLE) && !((IsOper(sptr) && HasPriv(sptr, PRIV_NOIDLE)) || feature_bool(FEAT_USER_HIDEIDLETIME))) | |
1167 | + if (!FlagHas(&setflags, FLAG_NOIDLE) && !((IsStaffOrAnOper(sptr) && HasPriv(sptr, PRIV_NOIDLE)) || feature_bool(FEAT_USER_HIDEIDLETIME))) | |
1168 | ClearNoIdle(sptr); | |
1169 | if (!FlagHas(&setflags, FLAG_PARANOID) && !(IsOper(sptr) && HasPriv(sptr, PRIV_PARANOID))) | |
1170 | ClearParanoid(sptr); | |
1171 | @@ -1496,8 +1532,8 @@ | |
1172 | } | |
1173 | if (MyConnect(sptr)) | |
1174 | { | |
1175 | - if ((FlagHas(&setflags, FLAG_OPER) || FlagHas(&setflags, FLAG_LOCOP)) && | |
1176 | - !IsAnOper(sptr)) | |
1177 | + if ((FlagHas(&setflags, FLAG_OPER) || FlagHas(&setflags, FLAG_LOCOP) || FlagHas(&setflags, FLAG_STAFF)) && | |
1178 | + !IsStaffOrAnOper(sptr)) | |
1179 | det_confs_butmask(sptr, CONF_CLIENT & ~CONF_OPERATOR); | |
1180 | ||
1181 | if (SendServNotice(sptr)) | |
1182 | @@ -1578,6 +1614,43 @@ | |
1183 | cli_user(sptr)->opername = NULL; | |
1184 | } | |
1185 | } | |
1186 | + | |
1187 | + | |
1188 | + /* user becomes staff */ | |
1189 | + if (!FlagHas(&setflags, FLAG_STAFF) && IsStaff(sptr)) { | |
1190 | + ++UserStats.staff; | |
1191 | + client_set_privs(sptr, NULL); /* may set propagate privilege */ | |
1192 | + | |
1193 | + /* notify my operators a user has STAFFed on a remote server */ | |
1194 | + if (!MyConnect(sptr)) | |
1195 | + sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is now staff (S) as %s on %s", | |
1196 | + cli_name(sptr), cli_user(sptr)->realusername, cli_user(sptr)->realhost, | |
1197 | + cli_user(sptr)->staffname, cli_name(cli_user(sptr)->server)); | |
1198 | + } | |
1199 | + | |
1200 | + /* no longer staff */ | |
1201 | + if (FlagHas(&setflags, FLAG_STAFF) && !IsStaff(sptr)) { | |
1202 | + assert(UserStats.staff > 0); | |
1203 | + --UserStats.staff; | |
1204 | + | |
1205 | + /* notify my operators an staff member has deSTAFFed on the network */ | |
1206 | + if (MyConnect(sptr)) | |
1207 | + sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is no longer staff (S) as %s", | |
1208 | + cli_name(sptr), cli_user(sptr)->realusername, cli_user(sptr)->realhost, | |
1209 | + cli_user(sptr)->staffname); | |
1210 | + else | |
1211 | + sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is no longer staff (S) as %s on %s", | |
1212 | + cli_name(sptr), cli_user(sptr)->realusername, cli_user(sptr)->realhost, | |
1213 | + cli_user(sptr)->staffname, cli_name(cli_user(sptr)->server)); | |
1214 | + | |
1215 | + client_set_privs(sptr, NULL); /* will clear propagate privilege */ | |
1216 | + if (cli_user(sptr)->staffname) { | |
1217 | + MyFree(cli_user(sptr)->staffname); | |
1218 | + cli_user(sptr)->staffname = NULL; | |
1219 | + } | |
1220 | + } | |
1221 | + | |
1222 | + | |
1223 | if (FlagHas(&setflags, FLAG_INVISIBLE) && !IsInvisible(sptr)) { | |
1224 | assert(UserStats.inv_clients > 0); | |
1225 | --UserStats.inv_clients; | |
1226 | @@ -1586,6 +1659,7 @@ | |
1227 | ++UserStats.inv_clients; | |
1228 | } | |
1229 | assert(UserStats.opers <= UserStats.clients + UserStats.unknowns); | |
1230 | + assert(UserStats.staff <= UserStats.clients + UserStats.unknowns); | |
1231 | assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns); | |
1232 | send_umode_out(cptr, sptr, &setflags, prop); | |
1233 | } | |
1234 | @@ -1628,6 +1702,19 @@ | |
1235 | } | |
1236 | } | |
1237 | ||
1238 | + /* staffname is wanted */ | |
1239 | + if ((type != UMODE_AND_ACCOUNT && type != UMODE_AND_ACCOUNT_SHORT) && IsStaff(cptr)) { | |
1240 | + *m++ = ' '; | |
1241 | + if (cli_user(cptr)->staffname) { | |
1242 | + char* t = cli_user(cptr)->staffname; | |
1243 | + while ((*m++ = *t++)) | |
1244 | + ; /* Empty loop */ | |
1245 | + m--; /* Step back over the '\0' */ | |
1246 | + } else { | |
1247 | + *m++ = NOOPERNAMECHARACTER; | |
1248 | + } | |
1249 | + } | |
1250 | + | |
1251 | if (IsAccount(cptr)) | |
1252 | { | |
1253 | char *t, nbuf[64+ACCOUNTLEN]; | |
1254 | @@ -1670,6 +1757,7 @@ | |
1255 | int flag; | |
1256 | int needhost = 0; | |
1257 | int needoper = 0; | |
1258 | + int needstaff = 0; | |
1259 | char *m; | |
1260 | int what = MODE_NULL; | |
1261 | ||
1262 | @@ -1705,6 +1793,12 @@ | |
1263 | if (!FlagHas(old, flag)) | |
1264 | needoper++; | |
1265 | } | |
1266 | + /* Special case for STAFF.. */ | |
1267 | + if (flag == FLAG_STAFF) { | |
1268 | + /* If we're setting +S, add the staffname later */ | |
1269 | + if (!FlagHas(old, flag)) | |
1270 | + needstaff++; | |
1271 | + } | |
1272 | /* Special case for SETHOST.. */ | |
1273 | if (flag == FLAG_SETHOST) { | |
1274 | /* Don't send to users */ | |
1275 | @@ -1749,6 +1843,17 @@ | |
1276 | *m++ = NOOPERNAMECHARACTER; | |
1277 | } | |
1278 | } | |
1279 | + if (sptr != cptr && needstaff) { | |
1280 | + *m++ = ' '; | |
1281 | + if (cli_user(sptr)->staffname) { | |
1282 | + char* t = cli_user(sptr)->staffname; | |
1283 | + while ((*m++ = *t++)) | |
1284 | + ; /* Empty loop */ | |
1285 | + m--; /* Step back over the '\0' */ | |
1286 | + } else { | |
1287 | + *m++ = NOOPERNAMECHARACTER; | |
1288 | + } | |
1289 | + } | |
1290 | if (needhost) { | |
1291 | *m++ = ' '; | |
1292 | ircd_snprintf(0, m, USERLEN + HOSTLEN + 1, "%s@%s", cli_user(sptr)->username, |