]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blob - staffpriv.patch
Update patchset for latest ircu changes
[irc/quakenet/snircd-patchqueue.git] / staffpriv.patch
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,