Compare commits

..

30 commits

Author SHA1 Message Date
Aaron Jones
a6b99c07d1
serv_connect(): ensure both sa_bind[]/sa_connect[] are always populated (#352)
Due to [1], linking with SCTP sometimes does not multi-home correctly.
This is triggered by the rand() on the lines immediately above these.

The connect{} blocks already support an `aftype` parameter to instruct
IRCd to prefer IPv4 or IPv6. This commit additionally ensures that the
other structure is always populated with the other address (if any) if
this parameter is specified.

This will allow SCTP server-linking users to work around the bug and
ensure that it always multi-homes by setting `connect::aftype` to IPv4.
Without this commit, that would cause Solanum to not include the IPv6
addresses (if any) in the connect block in its SCTP setup.

If there isn't a valid IP address in the other sockaddr, this should be
of no consequence, because it will not be used by rb_connect_tcp(), and
both rb_connect_sctp() and rb_sctp_bindx_only() already verify that
there is a valid IP address in the sockaddr before making use of it.

[1] https://marc.info/?l=linux-sctp&m=165684809726472&w=2
2022-07-05 06:01:26 +00:00
Matthew Martin
5c01fc8bd7 Cast time_t to long long when printing 2022-07-01 03:43:36 -04:00
Jess Porter
12cee8ab78
global masktrace doesn't need to be an operspy action 2022-07-01 00:07:02 +01:00
Jess Porter
9d2e66c08d
ERROR instead of NOTICE for failed WEBIRC 2022-07-01 00:02:53 +01:00
Jess Porter
5a3e99829a
refuse opers setting an invalidly long k-line reason 2022-06-30 23:59:17 +01:00
Aaron Jones
3fdf26aa19 ircd/listener: return a TLS record layer alert to D-Lined TLS clients 2022-06-30 18:55:41 -04:00
Matthew Martin
c0d93064a6 chmode: Use original string when removing a mask 2022-06-30 21:00:46 +01:00
JailBird
62f6351d90 Illumos fixes
- getexecname(3) returns const char *
- pid_t is long
2022-06-29 20:28:11 -04:00
Matthew Martin
57aa79acb8 Normalize snprintf size to use sizeof where possible 2022-06-24 01:42:08 -04:00
Matthew Martin
e239ac8785 chmode: Fix snprintf size 2022-06-24 01:42:08 -04:00
Doug Freed
fae8f2517c valid_temp_time: more simplification and test fixes 2022-06-20 16:35:03 +01:00
Ed Kellett
4f46809305 valid_temp_time: simplify/correct overflow check
the logic for trying to detect the maximum value of time_t was broken;
since we target a lower maximum time anyway, just use that for the
overflow check
2022-06-20 16:35:03 +01:00
Jess Porter
8e239de831
don't truncate operspy WHO 2022-06-10 18:15:56 +01:00
jailbird777
e73eade529
Remove stray semicolons (#339) 2022-06-10 18:07:25 +01:00
Bernhard M. Wiedemann
2681c7d2e4 Normalize generation for reproducible builds
While working on reproducible builds for openSUSE, I found that
our package varied even when building in clean VMs
with as little non-determinism as possible.
This was because of

+++ solanum-0~ch560/ircd/version.c.last
@@ -25,7 +25,7 @@
 #include "serno.h"
 #include "stdinc.h"

-const char *generation = "6";
+const char *generation = "5";
 const char *creation = "1653004800";
 const char *ircd_version = PATCHLEVEL;
 const char *serno = SERNO;
2022-05-29 10:16:00 +01:00
Eric Mertens
48a06ae3d7
Add description parameter to auth blocks (#327) 2022-04-14 14:39:45 -07:00
Eric Mertens
b2fa28dd95
Apply cmode C to replies (#328) 2022-04-14 13:14:12 -07:00
Ed Kellett
ba95896969 Make valid_temp_time overflow-resistant 2022-04-13 01:09:27 +01:00
Ed Kellett
1fcdacb424 Test some edge cases of valid_temp_time 2022-04-13 01:09:27 +01:00
Stephen Bennett
2f596395fa
Make opers talking through +g controllable by user mode +M (#275)
Times out after 30 minutes, and adds oper:always_message privilege for
bots and services to always talk through +g
2022-04-12 17:54:58 -04:00
Jess Porter
099d470763
show IPs in remote /stats i (#312)
Co-authored-by: Eric Mertens <emertens@galois.com>
2022-04-08 10:06:43 -07:00
Aaron Jones
80d71456cf
authd/providers/opm.c: include <netinet/tcp.h> (#318)
This header defines the TCP_NODELAY flag, which this compilation
unit uses.

Other C libraries implicitly include this header from some other
header we are using (I have not investigated which), but musl's
system headers do not, which breaks building on musl.

Reported-by: 0x5c <dev@0x5c.io>
2022-04-08 09:47:18 -07:00
David Schultz
9dd98618d0
whowas.c: store account name in whowas (#323)
Co-authored-by: Eric Mertens <emertens@galois.com>
2022-04-01 14:58:43 -07:00
Ed Kellett
c2fdb023a9 Remove the subset ban restriction
I think this was always pretty questionable. You can set redundant bans
in various ways anyway, and preventing all of them would only make the
situation worse, as wide temporary bans would destroy narrow permanent
ones, for example.
2022-04-01 22:49:54 +01:00
Ed Kellett
492d560ee1 valid_temp_time: style fixes 2022-03-06 22:51:19 +00:00
Ed Kellett
2644dcd166 Add tests for valid_temp_time 2022-03-06 22:51:19 +00:00
Ed Kellett
7a246575e5 remove some header dependencies on client.h 2022-03-06 22:51:19 +00:00
David Schultz
93035e75d9 Support more human friendly k/d/x-line duration format 2022-03-06 22:51:19 +00:00
Eric Mertens
22ebfd257e Fix comment in example configuration 2022-02-03 09:23:42 -08:00
Valentin Lorentz
18ac52f017 Remove ambiguity in descriptions +u
The old descriptions might be interpreted as meaning that +u enables
server-side filtering.
2022-01-31 00:02:07 +00:00
45 changed files with 480 additions and 170 deletions

View file

@ -26,6 +26,8 @@
#include "notice.h"
#include "provider.h"
#include <netinet/tcp.h> // TCP_NODELAY
#define SELF_PID (opm_provider.id)
#define OPM_READSIZE 128

View file

@ -514,7 +514,7 @@ static void do_query_number(struct DNSQuery *query, const struct rb_sockaddr_sto
request->name = (char *)rb_malloc(IRCD_RES_HOSTLEN + 1);
}
build_rdns(request->queryname, IRCD_RES_HOSTLEN + 1, addr, NULL);
build_rdns(request->queryname, sizeof request->queryname, addr, NULL);
request->type = T_PTR;
query_name(request);

View file

@ -306,7 +306,7 @@ operator "god" {
privset = "admin";
};
// See connecting-servers.rst for an introduction to using these files.
/* See connecting-servers.rst for an introduction to using these files. */
connect "irc.uplink.com" {
host = "203.0.113.3";

View file

@ -344,6 +344,11 @@ listen {
/* auth {}: allow users to connect to the ircd (OLD I:) */
auth {
/* description: descriptive text to help recognize this auth block in
* stats i output.
*/
description = "example oper";
/* user: the user@host allowed to connect. Multiple IPv4/IPv6 user
* lines are permitted per auth block. This is matched against the
* hostname and IP address (using :: shortening for IPv6 and

View file

@ -41,7 +41,7 @@ static int eb_extended(const char *data, struct Client *client_p,
if (data == NULL)
return EXTBAN_INVALID;
snprintf(buf, BUFSIZE, "%s!%s@%s#%s",
snprintf(buf, sizeof buf, "%s!%s@%s#%s",
client_p->name, client_p->username, client_p->host, client_p->info);
return match(data, buf) ? EXTBAN_MATCH : EXTBAN_NOMATCH;

View file

@ -134,7 +134,7 @@ mo_ojoin(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
sendto_one(source_p, form_str(RPL_TOPIC), me.name,
source_p->name, chptr->chname, chptr->topic);
sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name,
source_p->name, chptr->chname, chptr->topic_info, chptr->topic_time);
source_p->name, chptr->chname, chptr->topic_info, (long long)chptr->topic_time);
}
source_p->localClient->last_join_time = rb_current_time();

View file

@ -106,17 +106,17 @@ mr_webirc(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sourc
if (!IsConfDoSpoofIp(aconf) || irccmp(aconf->info.name, "webirc."))
{
/* XXX */
sendto_one(source_p, "NOTICE * :Not a CGI:IRC auth block");
exit_client(client_p, source_p, &me, "Not a CGI:IRC auth block");
return;
}
if (EmptyString(aconf->passwd))
{
sendto_one(source_p, "NOTICE * :CGI:IRC auth blocks must have a password");
exit_client(client_p, source_p, &me, "CGI:IRC auth blocks must have a password");
return;
}
if (!IsSecure(source_p) && aconf->flags & CONF_FLAGS_NEED_SSL)
{
sendto_one(source_p, "NOTICE * :Your CGI:IRC block requires TLS");
exit_client(client_p, source_p, &me, "Your CGI:IRC block requires TLS");
return;
}
@ -129,13 +129,13 @@ mr_webirc(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sourc
if (encr == NULL || strcmp(encr, aconf->passwd))
{
sendto_one(source_p, "NOTICE * :CGI:IRC password incorrect");
exit_client(client_p, source_p, &me, "CGI:IRC password incorrect");
return;
}
if (rb_inet_pton_sock(parv[4], &addr) <= 0)
{
sendto_one(source_p, "NOTICE * :Invalid IP");
exit_client(client_p, source_p, &me, "Invalid IP");
return;
}

View file

@ -20,8 +20,8 @@ NO PARAMETERS:
messages is stripped.
+g - Free invite. Everyone may invite users. Significantly
weakens +i control.
? +u - Unfiltered. Receive messages that are filtered server side based
on content
? +u - Unfiltered. Receive messages that would otherwise be filtered
server side based on content.
+z - Op moderated. Messages blocked by +m, +b and +q are instead
sent to ops.
+L - Large ban list. Increase maximum number of +beIq entries.

View file

@ -16,8 +16,8 @@ User modes: (* designates that the umode is oper only)
* +a - Is marked as a server admin in whois.
* +l - Can see oper locops (local wallops).
* +s - Can see server notices (see /quote help snomask).
? +u - Receive messages that are filtered server side based
on content
? +u - Receive messages that would otherwise be filtered server side
based on content.
* +z - Can see operwalls.
? +C - Prevents you from receiving CTCPs other than ACTION.
+D - Deaf - ignores all channel messages.

View file

@ -11,8 +11,8 @@ User modes: (? designates that the umode is provided by an extension
? +h - Has a cloaked host. May be +x depending on cloaking module
+g - Deny users not on your /ACCEPT list from messaging you and
inviting you to channels.
? +u - Receive messages that are filtered server side based
on content.
? +u - Receive messages that would otherwise be filtered server side
based on content.
+w - Can see oper wallops.
? +C - Prevents you from receiving CTCPs other than ACTION.
+D - Deaf - ignores all channel messages.

View file

@ -49,7 +49,7 @@
#define NUMERIC_STR_209 "Class %s %d"
#define NUMERIC_STR_212 "%s %u %lu :%u"
#define NUMERIC_STR_213 "C %s %s %s %d %s %s"
#define NUMERIC_STR_215 "I %s %s %s@%s %d %s"
#define NUMERIC_STR_215 "I %s %s %s@%s %d %s :%s"
#define NUMERIC_STR_216 "%c %s * %s :%s%s%s"
#define NUMERIC_STR_217 "%c %d %s :%s"
#define NUMERIC_STR_218 "Y %s %d %d %d %u %d.%d %d.%d %u"
@ -101,11 +101,11 @@
#define NUMERIC_STR_323 ":%s 323 %s :End of /LIST"
#define NUMERIC_STR_324 ":%s 324 %s %s %s"
#define NUMERIC_STR_325 ":%s 325 %s %s %s :is the current channel mode-lock"
#define NUMERIC_STR_329 ":%s 329 %s %s %lu"
#define NUMERIC_STR_329 ":%s 329 %s %s %lld"
#define NUMERIC_STR_330 "%s %s :is logged in as"
#define NUMERIC_STR_331 ":%s 331 %s %s :No topic is set."
#define NUMERIC_STR_332 ":%s 332 %s %s :%s"
#define NUMERIC_STR_333 ":%s 333 %s %s %s %lu"
#define NUMERIC_STR_333 ":%s 333 %s %s %s %lld"
#define NUMERIC_STR_337 "%s :%s"
#define NUMERIC_STR_338 "%s %s :actually using host"
#define NUMERIC_STR_341 ":%s 341 %s %s %s"

View file

@ -43,6 +43,8 @@
#include "stdinc.h"
struct Client;
enum {
PRIV_NEEDOPER = 1
};

View file

@ -65,6 +65,7 @@ struct ConfItem
char *passwd; /* doubles as kline reason *ugh* */
char *spasswd; /* Password to send. */
char *user; /* user part of user@host */
char *desc; /* description */
int port;
time_t hold; /* Hold action until this time (calendar time) */
time_t created; /* Creation time (for klines etc) */
@ -384,7 +385,7 @@ extern int detach_conf(struct Client *);
extern struct ConfItem *find_tkline(const char *, const char *, struct sockaddr *);
extern char *show_iline_prefix(struct Client *, struct ConfItem *, char *);
extern void get_printable_conf(struct ConfItem *,
char **, char **, const char **, char **, int *, char **);
char **, char **, const char **, char **, int *, char **, char **);
extern char *get_user_ban_reason(struct ConfItem *aconf);
extern void get_printable_kline(struct Client *, struct ConfItem *,
char **, char **, char **, char **);

View file

@ -40,6 +40,9 @@
#include <openssl/rsa.h>
#endif
#define MAX_TEMP_TIME (52 * 7 * 24 * 60 * 60)
struct Client;
struct ConfItem;
extern rb_dlink_list cluster_conf_list;

View file

@ -249,9 +249,7 @@ add_id(struct Client *source_p, struct Channel *chptr, const char *banid, const
char *realban = LOCAL_COPY(banid);
rb_dlink_node *ptr;
/* dont let local clients overflow the banlist, or set redundant
* bans
*/
/* dont let local clients overflow the banlist */
if(MyClient(source_p))
{
if((rb_dlink_list_length(&chptr->banlist) + rb_dlink_list_length(&chptr->exceptlist) + rb_dlink_list_length(&chptr->invexlist) + rb_dlink_list_length(&chptr->quietlist)) >= (unsigned long)((chptr->mode.mode & MODE_EXLIMIT) ? ConfigChannel.max_bans_large : ConfigChannel.max_bans))
@ -260,26 +258,16 @@ add_id(struct Client *source_p, struct Channel *chptr, const char *banid, const
me.name, source_p->name, chptr->chname, realban);
return false;
}
RB_DLINK_FOREACH(ptr, list->head)
{
actualBan = ptr->data;
if(mask_match(actualBan->banstr, realban))
return false;
}
}
/* dont let remotes set duplicates */
else
/* don't let anyone set duplicate bans */
RB_DLINK_FOREACH(ptr, list->head)
{
RB_DLINK_FOREACH(ptr, list->head)
{
actualBan = ptr->data;
if(!irccmp(actualBan->banstr, realban))
return false;
}
actualBan = ptr->data;
if(!irccmp(actualBan->banstr, realban))
return false;
}
if(IsPerson(source_p))
sprintf(who, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
else
@ -937,9 +925,9 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
}
if (removed && removed->forward)
removed_mask_pos += snprintf(buf + old_removed_mask_pos, sizeof(buf), "%s$%s", removed->banstr, removed->forward) + 1;
removed_mask_pos += snprintf(buf + old_removed_mask_pos, sizeof(buf) - old_removed_mask_pos, "%s$%s", removed->banstr, removed->forward) + 1;
else
removed_mask_pos += rb_strlcpy(buf + old_removed_mask_pos, mask, sizeof(buf)) + 1;
removed_mask_pos += rb_strlcpy(buf + old_removed_mask_pos, removed ? removed->banstr : mask, sizeof(buf)) + 1;
if (removed)
{
free_ban(removed);

View file

@ -1573,11 +1573,11 @@ exit_local_server(struct Client *client_p, struct Client *source_p, struct Clien
remove_dependents(client_p, source_p, from, IsPerson(from) ? newcomment : comment, comment1);
sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s was connected"
" for %ld seconds. %d/%d sendK/recvK.",
source_p->name, (long) rb_current_time() - source_p->localClient->firsttime, sendk, recvk);
" for %lld seconds. %d/%d sendK/recvK.",
source_p->name, (long long)(rb_current_time() - source_p->localClient->firsttime), sendk, recvk);
ilog(L_SERVER, "%s was connected for %ld seconds. %d/%d sendK/recvK.",
source_p->name, (long) rb_current_time() - source_p->localClient->firsttime, sendk, recvk);
ilog(L_SERVER, "%s was connected for %lld seconds. %d/%d sendK/recvK.",
source_p->name, (long long)(rb_current_time() - source_p->localClient->firsttime), sendk, recvk);
if(has_id(source_p))
del_from_id_hash(source_p->id, source_p);
@ -1844,7 +1844,7 @@ show_ip_conf(struct ConfItem *aconf, struct Client *source_p)
{
if(IsConfDoSpoofIp(aconf))
{
if(!ConfigFileEntry.hide_spoof_ips && MyOper(source_p))
if(!ConfigFileEntry.hide_spoof_ips && IsOper(source_p))
return 1;
return 0;
@ -1857,7 +1857,7 @@ int
show_ip_whowas(struct Whowas *whowas, struct Client *source_p)
{
if(whowas->flags & WHOWAS_IP_SPOOFING)
if(ConfigFileEntry.hide_spoof_ips || !MyOper(source_p))
if(ConfigFileEntry.hide_spoof_ips || !IsOper(source_p))
return 0;
if(whowas->flags & WHOWAS_DYNSPOOF)
if(!IsOper(source_p))

View file

@ -723,7 +723,7 @@ show_iline_prefix(struct Client *sptr, struct ConfItem *aconf, char *name)
void
report_auth(struct Client *client_p)
{
char *name, *host, *user, *classname;
char *name, *host, *user, *classname, *desc;
const char *pass;
struct AddressRec *arec;
struct ConfItem *aconf;
@ -739,7 +739,7 @@ report_auth(struct Client *client_p)
continue;
get_printable_conf(aconf, &name, &host, &pass, &user, &port,
&classname);
&classname, &desc);
if(!EmptyString(aconf->spasswd))
pass = aconf->spasswd;
@ -748,7 +748,7 @@ report_auth(struct Client *client_p)
form_str(RPL_STATSILINE),
name, pass, show_iline_prefix(client_p, aconf, user),
show_ip_conf(aconf, client_p) ? host : "255.255.255.255",
port, classname);
port, classname, desc);
}
}

View file

@ -756,8 +756,8 @@ solanum_main(int argc, char * const argv[])
check_splitmode_ev = rb_event_add("check_splitmode", check_splitmode, NULL, 5);
if(server_state_foreground)
inotice("now running in foreground mode from %s as pid %d ...",
ConfigFileEntry.dpath, getpid());
inotice("now running in foreground mode from %s as pid %ld ...",
ConfigFileEntry.dpath, (long)getpid());
rb_lib_loop(0);

View file

@ -572,8 +572,6 @@ accept_sslcallback(struct Client *client_p, int status)
return 0; /* use default handler if status != RB_OK */
}
static const char *toofast = "ERROR :Reconnecting too fast, throttled.\r\n";
static int
accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, void *data)
{
@ -583,6 +581,13 @@ accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, voi
static time_t last_oper_notice = 0;
int len;
static const char *toofast = "ERROR :Reconnecting too fast, throttled.\r\n";
static const unsigned char sslerrcode[] = {
// SSLv3.0 Fatal Alert: Access Denied
0x15, 0x03, 0x00, 0x00, 0x02, 0x02, 0x31
};
if(listener->ssl && (!ircd_ssl_ok || !get_ssld_count()))
{
rb_close(F);
@ -618,7 +623,11 @@ accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, voi
{
ServerStats.is_ref++;
if(ConfigFileEntry.dline_with_reason)
if(listener->ssl)
{
rb_write(F, sslerrcode, sizeof(sslerrcode));
}
else if(ConfigFileEntry.dline_with_reason)
{
len = snprintf(buf, sizeof(buf), "ERROR :*** Banned: %s\r\n", get_user_ban_reason(aconf));
if (len >= (int)(sizeof(buf)-1))
@ -627,11 +636,14 @@ accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, voi
buf[sizeof(buf) - 2] = '\n';
buf[sizeof(buf) - 1] = '\0';
}
rb_write(F, buf, strlen(buf));
}
else
{
strcpy(buf, "ERROR :You have been D-lined.\r\n");
rb_write(F, buf, strlen(buf));
}
rb_write(F, buf, strlen(buf));
rb_close(F);
return 0;
}

View file

@ -1037,6 +1037,9 @@ conf_end_auth(struct TopConf *tc)
if(yy_aconf->className)
yy_tmp->className = rb_strdup(yy_aconf->className);
if(yy_aconf->desc)
yy_tmp->desc = rb_strdup(yy_aconf->desc);
yy_tmp->flags = yy_aconf->flags;
yy_tmp->port = yy_aconf->port;
@ -1172,6 +1175,13 @@ conf_set_auth_spoof(void *data)
yy_aconf->flags |= CONF_FLAGS_SPOOF_IP;
}
static void
conf_set_auth_desc(void *data)
{
rb_free(yy_aconf->desc);
yy_aconf->desc = rb_strdup(data);
}
static void
conf_set_auth_flags(void *data)
{
@ -2318,7 +2328,7 @@ conf_report_error(const char *fmt, ...)
char msg[BUFSIZE + 1] = { 0 };
va_start(ap, fmt);
vsnprintf(msg, BUFSIZE, fmt, ap);
vsnprintf(msg, sizeof msg, fmt, ap);
va_end(ap);
if (testing_conf)
@ -2338,7 +2348,7 @@ conf_report_warning(const char *fmt, ...)
char msg[BUFSIZE + 1] = { 0 };
va_start(ap, fmt);
vsnprintf(msg, BUFSIZE, fmt, ap);
vsnprintf(msg, sizeof msg, fmt, ap);
va_end(ap);
if (testing_conf)
@ -2640,6 +2650,7 @@ static struct ConfEntry conf_auth_table[] =
{ "redirport", CF_INT, conf_set_auth_redir_port, 0, NULL },
{ "flags", CF_STRING | CF_FLIST, conf_set_auth_flags, 0, NULL },
{ "umodes", CF_QSTRING, conf_set_auth_umodes, 0, NULL},
{ "description",CF_QSTRING, conf_set_auth_desc, 0, NULL},
{ "\0", 0, NULL, 0, NULL }
};

View file

@ -100,7 +100,7 @@ reject_exit(void *unused)
if (ddata->aconf)
{
snprintf(dynamic_reason, BUFSIZE, form_str(ERR_YOUREBANNEDCREEP) "\r\n",
snprintf(dynamic_reason, sizeof dynamic_reason, form_str(ERR_YOUREBANNEDCREEP) "\r\n",
me.name, "*", get_user_ban_reason(ddata->aconf));
rb_write(ddata->F, dynamic_reason, strlen(dynamic_reason));
@ -108,7 +108,7 @@ reject_exit(void *unused)
}
else if (ddata->reason)
{
snprintf(dynamic_reason, BUFSIZE, ":%s 465 %s :%s\r\n",
snprintf(dynamic_reason, sizeof dynamic_reason, ":%s 465 %s :%s\r\n",
me.name, "*", ddata->reason);
rb_write(ddata->F, dynamic_reason, strlen(dynamic_reason));
}

View file

@ -154,6 +154,7 @@ free_conf(struct ConfItem *aconf)
rb_free(aconf->className);
rb_free(aconf->user);
rb_free(aconf->host);
rb_free(aconf->desc);
if(IsConfBan(aconf))
operhash_delete(aconf->info.oper);
@ -1346,7 +1347,8 @@ get_oper_name(struct Client *client_p)
*/
void
get_printable_conf(struct ConfItem *aconf, char **name, char **host,
const char **pass, char **user, int *port, char **classname)
const char **pass, char **user, int *port,
char **classname, char **desc)
{
static char null[] = "<NULL>";
static char zero[] = "default";
@ -1356,6 +1358,7 @@ get_printable_conf(struct ConfItem *aconf, char **name, char **host,
*pass = EmptyString(aconf->passwd) ? null : aconf->passwd;
*user = EmptyString(aconf->user) ? null : aconf->user;
*classname = EmptyString(aconf->className) ? zero : aconf->className;
*desc = CheckEmpty(aconf->desc);
*port = (int) aconf->port;
}

View file

@ -685,23 +685,55 @@ time_t
valid_temp_time(const char *p)
{
time_t result = 0;
long current = 0;
while(*p)
{
if(IsDigit(*p))
{
result *= 10;
result += ((*p) & 0xF);
p++;
}
else
while (*p) {
char *endp;
int mul;
errno = 0;
current = strtol(p, &endp, 10);
if (endp == p)
return -1;
if (current < 0)
return -1;
switch (*endp) {
case '\0': /* No unit was given so send it back as minutes */
case 'm':
mul = 60;
break;
case 'h':
mul = 3600;
break;
case 'd':
mul = 86400;
break;
case 'w':
mul = 604800;
break;
default:
return -1;
}
if (current > LONG_MAX / mul)
return MAX_TEMP_TIME;
current *= mul;
if (current > MAX_TEMP_TIME - result)
return MAX_TEMP_TIME;
result += current;
if (*endp == '\0')
break;
p = endp + 1;
}
if(result > (60 * 24 * 7 * 52))
result = (60 * 24 * 7 * 52);
return(result * 60);
return MIN(result, MAX_TEMP_TIME);
}
/* Propagated bans are expired elsewhere. */

View file

@ -1017,12 +1017,16 @@ serv_connect(struct server_conf *server_p, struct Client *by)
else if(server_p->aftype == AF_INET || GET_SS_FAMILY(&server_p->connect4) == AF_INET)
{
sa_connect[0] = server_p->connect4;
sa_connect[1] = server_p->connect6;
sa_bind[0] = server_p->bind4;
sa_bind[1] = server_p->bind6;
}
else if(server_p->aftype == AF_INET6 || GET_SS_FAMILY(&server_p->connect6) == AF_INET6)
{
sa_connect[0] = server_p->connect6;
sa_connect[1] = server_p->connect4;
sa_bind[0] = server_p->bind6;
sa_bind[1] = server_p->bind4;
}
/* log */

View file

@ -1640,7 +1640,7 @@ change_nick_user_host(struct Client *target_p, const char *nick, const char *use
if(do_qjm)
{
va_start(ap, format);
vsnprintf(reason, 255, format, ap);
vsnprintf(reason, sizeof reason, format, ap);
va_end(ap);
sendto_common_channels_local_butone(target_p, NOCAPS, CLICAP_CHGHOST, ":%s!%s@%s QUIT :%s",

View file

@ -26,6 +26,7 @@ else \
{ print $1 " " $2 " " $3 " " $7 " at " $4 " " $5 " " $6 }}'`
else
creation="$EXTERNAL_BUILD_TIMESTAMP"
generation=1
fi
$spitshell >version.c <<!SUB!THIS!

View file

@ -112,6 +112,7 @@ whowas_add_history(struct Client *client_p, int online)
rb_strlcpy(who->hostname, client_p->host, sizeof(who->hostname));
rb_strlcpy(who->realname, client_p->info, sizeof(who->realname));
rb_strlcpy(who->sockhost, client_p->sockhost, sizeof(who->sockhost));
rb_strlcpy(who->suser, client_p->user->suser, sizeof(who->suser));
who->flags = (IsIPSpoof(client_p) ? WHOWAS_IP_SPOOFING : 0) |
(IsDynSpoof(client_p) ? WHOWAS_DYNSPOOF : 0);

View file

@ -52,7 +52,7 @@ rb_crypt(const char *key, const char *salt)
return rb_sha512_crypt(key, salt);
default:
return NULL;
};
}
}
else
return rb_des_crypt(key, salt);

View file

@ -294,23 +294,21 @@ rb_event_init(void)
void
rb_dump_events(void (*func) (char *, void *), void *ptr)
{
int len;
char buf[512];
rb_dlink_node *dptr;
struct ev_entry *ev;
len = sizeof(buf);
snprintf(buf, len, "Last event to run: %s", last_event_ran);
snprintf(buf, sizeof buf, "Last event to run: %s", last_event_ran);
func(buf, ptr);
rb_strlcpy(buf, "Operation Next Execution", len);
rb_strlcpy(buf, "Operation Next Execution", sizeof buf);
func(buf, ptr);
RB_DLINK_FOREACH(dptr, event_list.head)
{
ev = dptr->data;
snprintf(buf, len, "%-28s %-4ld seconds (frequency=%d)", ev->name,
ev->when - (long)rb_current_time(), (int)ev->frequency);
snprintf(buf, sizeof buf, "%-28s %-4lld seconds (frequency=%d)", ev->name,
(long long)(ev->when - rb_current_time()), (int)ev->frequency);
func(buf, ptr);
}
}

View file

@ -172,7 +172,7 @@ int
rb_ports_supports_event(void)
{
return 1;
};
}
void
rb_ports_init_event(void)

View file

@ -162,7 +162,7 @@ rb_path_to_self(void)
{
static char path_buf[4096];
#if defined(HAVE_GETEXECNAME)
char *s = getexecname();
const char *s = getexecname();
if (s == NULL)
return NULL;
realpath(s, path_buf);

View file

@ -51,10 +51,12 @@ chm_noctcp_process(void *data_)
{
hook_data_privmsg_channel *data = data_;
/* don't waste CPU if message is already blocked */
if (data->approved || data->msgtype == MESSAGE_TYPE_NOTICE)
if (data->approved)
return;
if (*data->text == '\001' && rb_strncasecmp(data->text + 1, "ACTION ", 7) && data->chptr->mode.mode & mode_noctcp)
if (*data->text == '\001' &&
data->chptr->mode.mode & mode_noctcp &&
!(data->msgtype == MESSAGE_TYPE_PRIVMSG && !rb_strncasecmp(data->text + 1, "ACTION ", 7)))
{
sendto_one_numeric(data->source_p, ERR_CANNOTSENDTOCHAN, form_str(ERR_CANNOTSENDTOCHAN), data->chptr->chname);
data->approved = ERR_CANNOTSENDTOCHAN;

View file

@ -374,7 +374,7 @@ m_join(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p
sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
me.name, source_p->name, chptr->chname,
chptr->topic_info,
(unsigned long)chptr->topic_time);
(long long)chptr->topic_time);
}
channel_member_names(chptr, source_p, 1);

View file

@ -132,7 +132,7 @@ m_mode(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p
operspy ? channel_modes(chptr, &me) : channel_modes(chptr, source_p));
sendto_one(source_p, form_str(RPL_CREATIONTIME),
me.name, source_p->name, parv[1], chptr->channelts);
me.name, source_p->name, parv[1], (long long)chptr->channelts);
}
else
{

View file

@ -340,20 +340,10 @@ mo_masktrace(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *so
const char *parv[])
{
char *name, *username, *hostname, *gecos;
const char *mask;
int operspy = 0;
mask = parv[1];
name = LOCAL_COPY(parv[1]);
collapse(name);
if(IsOperSpy(source_p) && parv[1][0] == '!')
{
name++;
mask++;
operspy = 1;
}
if(parc > 2 && !EmptyString(parv[2]))
{
gecos = LOCAL_COPY(parv[2]);
@ -383,21 +373,6 @@ mo_masktrace(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *so
return;
}
if(operspy) {
if (!ConfigFileEntry.operspy_dont_care_user_info)
{
char buf[512];
rb_strlcpy(buf, mask, sizeof(buf));
if(!EmptyString(gecos)) {
rb_strlcat(buf, " ", sizeof(buf));
rb_strlcat(buf, gecos, sizeof(buf));
}
report_operspy(source_p, "MASKTRACE", buf);
}
match_masktrace(source_p, &global_client_list, username, hostname, name, gecos);
} else
match_masktrace(source_p, &lclient_list, username, hostname, name, gecos);
match_masktrace(source_p, &global_client_list, username, hostname, name, gecos);
sendto_one_numeric(source_p, RPL_ENDOFTRACE, form_str(RPL_ENDOFTRACE), me.name);
}

View file

@ -165,6 +165,11 @@ mo_kline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
}
reason = LOCAL_COPY(parv[loc]);
if(strlen(reason) > BANREASONLEN)
{
sendto_one_notice(source_p, ":K-Line reason exceeds %d characters", BANREASONLEN);
return;
}
if(parse_netmask_strict(host, NULL, NULL) == HM_ERROR)
{
@ -234,9 +239,6 @@ mo_kline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
aconf->port = 0;
aconf->info.oper = operhash_add(get_oper_name(source_p));
if(strlen(reason) > BANREASONLEN)
reason[BANREASONLEN] = '\0';
/* Look for an oper reason */
if((oper_reason = strchr(reason, '|')) != NULL)
{

View file

@ -108,7 +108,7 @@ dump_map(struct Client *client_p, struct Client *root_p, char *pbuf)
}
frac = (1000 * rb_dlink_list_length(&root_p->serv->users) + Count.total / 2) / Count.total;
snprintf(buf + USER_COL, BUFSIZE - USER_COL,
snprintf(buf + USER_COL, sizeof buf - USER_COL,
" | Users: %5lu (%2d.%1d%%)", rb_dlink_list_length(&root_p->serv->users),
frac / 10, frac % 10);
@ -172,7 +172,7 @@ flattened_map(struct Client *client_p)
}
}
snprintf(buf + USER_COL, BUFSIZE - USER_COL,
snprintf(buf + USER_COL, sizeof buf - USER_COL,
" | Users: %5lu (%4.1f%%)", rb_dlink_list_length(&me.serv->users),
100 * (float) rb_dlink_list_length(&me.serv->users) / (float) Count.total);
@ -210,7 +210,7 @@ flattened_map(struct Client *client_p)
}
}
snprintf(buf + USER_COL, BUFSIZE - USER_COL,
snprintf(buf + USER_COL, sizeof buf - USER_COL,
" | Users: %5lu (%4.1f%%)", rb_dlink_list_length(&target_p->serv->users),
100 * (float) rb_dlink_list_length(&target_p->serv->users) / (float) Count.total);

View file

@ -237,7 +237,7 @@ scan_umodes(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sou
if (mask != NULL)
{
snprintf(maskbuf, BUFSIZE, "%s!%s@%s",
snprintf(maskbuf, sizeof maskbuf, "%s!%s@%s",
target_p->name, target_p->username, target_p->host);
if (!match(mask, maskbuf))

View file

@ -453,7 +453,7 @@ stats_deny (struct Client *source_p)
static void
stats_exempt(struct Client *source_p)
{
char *name, *host, *user, *classname;
char *name, *host, *user, *classname, *desc;
const char *pass;
struct AddressRec *arec;
struct ConfItem *aconf;
@ -474,7 +474,7 @@ stats_exempt(struct Client *source_p)
{
aconf = arec->aconf;
get_printable_conf (aconf, &name, &host, &pass,
&user, &port, &classname);
&user, &port, &classname, &desc);
sendto_one_numeric(source_p, RPL_STATSDLINE,
form_str(RPL_STATSDLINE),
@ -533,7 +533,7 @@ stats_auth (struct Client *source_p)
else if((ConfigFileEntry.stats_i_oper_only == 1) && !IsOperGeneral (source_p))
{
struct ConfItem *aconf;
char *name, *host, *user, *classname;
char *name, *host, *user, *classname, *desc;
const char *pass = "*";
int port;
@ -550,13 +550,13 @@ stats_auth (struct Client *source_p)
if(aconf == NULL)
return;
get_printable_conf (aconf, &name, &host, &pass, &user, &port, &classname);
get_printable_conf (aconf, &name, &host, &pass, &user, &port, &classname, &desc);
if(!EmptyString(aconf->spasswd))
pass = aconf->spasswd;
sendto_one_numeric(source_p, RPL_STATSILINE, form_str(RPL_STATSILINE),
name, pass, show_iline_prefix(source_p, aconf, user),
host, port, classname);
host, port, classname, desc);
}
/* Theyre opered, or allowed to see all auth blocks */
@ -908,8 +908,8 @@ stats_ssld_foreach(void *data, pid_t pid, int cli_count, enum ssld_status status
struct Client *source_p = data;
sendto_one_numeric(source_p, RPL_STATSDEBUG,
"S :%u %c %u :%s",
pid,
"S :%ld %c %u :%s",
(long)pid,
status == SSLD_DEAD ? 'D' : (status == SSLD_SHUTDOWN ? 'S' : 'A'),
cli_count,
version);
@ -960,8 +960,8 @@ stats_usage (struct Client *source_p)
(int) (rus.ru_stime.tv_sec % 60));
sendto_one_numeric(source_p, RPL_STATSDEBUG,
"R :RSS %ld ShMem %ld Data %ld Stack %ld",
rus.ru_maxrss, (rus.ru_ixrss / rup),
(rus.ru_idrss / rup), (rus.ru_isrss / rup));
rus.ru_maxrss, (long)(rus.ru_ixrss / rup),
(long)(rus.ru_idrss / rup), (long)(rus.ru_isrss / rup));
sendto_one_numeric(source_p, RPL_STATSDEBUG,
"R :Swaps %d Reclaims %d Faults %d",
(int) rus.ru_nswap, (int) rus.ru_minflt, (int) rus.ru_majflt);

View file

@ -235,7 +235,8 @@ mo_testline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sou
sendto_one_numeric(source_p, RPL_STATSILINE, form_str(RPL_STATSILINE),
aconf->info.name, EmptyString(aconf->spasswd) ? "<NULL>" : aconf->spasswd,
show_iline_prefix(source_p, aconf, aconf->user),
aconf->host, aconf->port, aconf->className);
aconf->host, aconf->port, aconf->className,
CheckEmpty(aconf->desc));
return;
}

View file

@ -173,7 +173,7 @@ m_topic(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_
sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
me.name, source_p->name, chptr->chname,
chptr->topic_info,
(unsigned long)chptr->topic_time);
(long long)chptr->topic_time);
}
}
}

View file

@ -367,8 +367,12 @@ who_global(struct Client *source_p, const char *mask, int server_oper, int opers
who_common_channel(source_p, msptr->chptr, mask, server_oper, &maxmatches, fmt);
}
}
else if (!ConfigFileEntry.operspy_dont_care_user_info)
report_operspy(source_p, "WHO", mask);
else
{
maxmatches = INT_MAX;
if (!ConfigFileEntry.operspy_dont_care_user_info)
report_operspy(source_p, "WHO", mask);
}
/* second, list all matching visible clients and clear all marks
* on invisible clients

View file

@ -44,49 +44,78 @@
#include "supported.h"
#include "logger.h"
static int
um_callerid_modinit(void)
{
user_modes['g'] = find_umode_slot();
if (!user_modes['g'])
{
ierror("um_callerid: unable to allocate usermode slot for +g; unloading module.");
return -1;
}
user_modes['G'] = find_umode_slot();
if (!user_modes['G'])
{
user_modes['g'] = 0;
ierror("um_callerid: unable to allocate usermode slot for +G; unloading module.");
return -1;
}
construct_umodebuf();
add_isupport("CALLERID", isupport_umode, "g");
return 0;
}
static void
um_callerid_moddeinit(void)
{
user_modes['g'] = 0;
user_modes['G'] = 0;
construct_umodebuf();
delete_isupport("CALLERID");
}
#define IsSetStrictCallerID(c) ((c->umodes & user_modes['g']) == user_modes['g'])
#define IsSetRelaxedCallerID(c) ((c->umodes & user_modes['G']) == user_modes['G'])
#define IsSetAnyCallerID(c) (IsSetStrictCallerID(c) || IsSetRelaxedCallerID(c))
#define IsSetTalkThroughCallerID(c) ((c->umodes & user_modes['M']) == user_modes['M'])
static const char um_callerid_desc[] =
"Provides usermodes +g and +G which restrict messages from unauthorized users.";
struct CallerIDOverrideSession {
rb_dlink_node node;
struct Client *client;
time_t deadline;
};
static rb_dlink_list callerid_overriding_opers = { NULL, NULL, 0 };
struct ev_entry *expire_callerid_override_deadlines_ev = NULL;
static void
update_session_deadline(struct Client *source_p)
{
struct CallerIDOverrideSession *session_p = NULL;
rb_dlink_node *n;
RB_DLINK_FOREACH(n, callerid_overriding_opers.head)
{
struct CallerIDOverrideSession *s = n->data;
if (s->client == source_p)
{
session_p = s;
break;
}
}
if (session_p != NULL)
{
rb_dlinkDelete(&session_p->node, &callerid_overriding_opers);
}
else
{
session_p = rb_malloc(sizeof(struct CallerIDOverrideSession));
session_p->client = source_p;
}
session_p->deadline = rb_current_time() + 1800;
rb_dlinkAddTail(session_p, &session_p->node, &callerid_overriding_opers);
}
static void
expire_callerid_override_deadlines(void *unused)
{
rb_dlink_node *n, *tn;
RB_DLINK_FOREACH_SAFE(n, tn, callerid_overriding_opers.head)
{
struct CallerIDOverrideSession *session_p = n->data;
if (session_p->deadline >= rb_current_time())
{
break;
}
else
{
const char *parv[4] = {session_p->client->name, session_p->client->name, "-M", NULL};
user_mode(session_p->client, session_p->client, 3, parv);
}
}
}
static bool
allow_message(struct Client *source_p, struct Client *target_p)
{
@ -105,7 +134,7 @@ allow_message(struct Client *source_p, struct Client *target_p)
return true;
/* XXX: controversial? allow opers to send through +g */
if (MayHavePrivilege(source_p, "oper:message"))
if (IsSetTalkThroughCallerID(source_p) || MayHavePrivilege(source_p, "oper:always_message"))
return true;
if (accept_message(source_p, target_p))
@ -227,11 +256,156 @@ h_hdl_privmsg_user(void *vdata)
data->approved = ERR_TARGUMODEG;
}
static void
check_umode_change(void *vdata)
{
hook_data_umode_changed *data = (hook_data_umode_changed *)vdata;
bool changed = false;
struct Client *source_p = data->client;
if (!MyClient(source_p))
return;
if (data->oldumodes & UMODE_OPER && !IsOper(source_p))
source_p->umodes &= ~user_modes['M'];
changed = ((data->oldumodes ^ source_p->umodes) & user_modes['M']);
if (changed && source_p->umodes & user_modes['M'])
{
if (!HasPrivilege(source_p, "oper:message"))
{
sendto_one_notice(source_p, ":*** You need oper:message privilege for +M");
source_p->umodes &= ~user_modes['M'];
return;
}
update_session_deadline(source_p);
}
else if (changed)
{
// Unsetting +M; remove the timeout session
rb_dlink_node *n, *tn;
RB_DLINK_FOREACH_SAFE(n, tn, callerid_overriding_opers.head)
{
struct CallerIDOverrideSession *session_p = n->data;
if (session_p->client != source_p)
continue;
rb_dlinkDelete(n, &callerid_overriding_opers);
rb_free(session_p);
}
}
}
static void check_priv_change(void *vdata)
{
hook_data_priv_change *data = (hook_data_priv_change*)vdata;
struct Client *source_p = data->client;
const char *fakeparv[4];
if (!MyClient(source_p))
return;
if (source_p->umodes & user_modes['M'] && !HasPrivilege(source_p, "oper:message"))
{
sendto_one_notice(source_p, ":*** You need oper:message privilege for +M");
fakeparv[0] = fakeparv[1] = source_p->name;
fakeparv[2] = "-M";
fakeparv[3] = NULL;
user_mode(source_p, source_p, 3, fakeparv);
}
}
static void
handle_client_exit(void *vdata)
{
hook_data_client_exit *data = (hook_data_client_exit *) vdata;
rb_dlink_node *n, *tn;
struct Client *source_p = data->target;
RB_DLINK_FOREACH_SAFE(n, tn, callerid_overriding_opers.head)
{
struct CallerIDOverrideSession *session_p = n->data;
if (session_p->client != source_p)
continue;
rb_dlinkDelete(n, &callerid_overriding_opers);
rb_free(session_p);
}
}
static mapi_hfn_list_av1 um_callerid_hfnlist[] = {
{ "umode_changed", check_umode_change },
{ "priv_change", check_priv_change },
{ "invite", h_hdl_invite },
{ "privmsg_user", h_hdl_privmsg_user },
{ "client_exit", handle_client_exit },
{ NULL, NULL }
};
static int
um_callerid_modinit(void)
{
rb_dlink_node *ptr;
user_modes['g'] = find_umode_slot();
if (!user_modes['g'])
{
ierror("um_callerid: unable to allocate usermode slot for +g; unloading module.");
return -1;
}
user_modes['G'] = find_umode_slot();
if (!user_modes['G'])
{
user_modes['g'] = 0;
ierror("um_callerid: unable to allocate usermode slot for +G; unloading module.");
return -1;
}
user_modes['M'] = find_umode_slot();
if (!user_modes['M'])
{
user_modes['g'] = 0;
user_modes['G'] = 0;
ierror("um_callerid: unable to allocate usermode slot for +M; unloading module.");
return -1;
}
construct_umodebuf();
add_isupport("CALLERID", isupport_umode, "g");
RB_DLINK_FOREACH(ptr, lclient_list.head)
{
struct Client *client_p = ptr->data;
if (IsPerson(client_p) && (client_p->umodes & user_modes['M']))
update_session_deadline(client_p);
}
expire_callerid_override_deadlines_ev = rb_event_add("expire_callerid_override_deadlines", expire_callerid_override_deadlines, NULL, 60);
return 0;
}
static void
um_callerid_moddeinit(void)
{
user_modes['g'] = 0;
user_modes['G'] = 0;
user_modes['M'] = 0;
construct_umodebuf();
delete_isupport("CALLERID");
rb_event_delete(expire_callerid_override_deadlines_ev);
}
DECLARE_MODULE_AV2(um_callerid, um_callerid_modinit, um_callerid_moddeinit,
NULL, NULL, um_callerid_hfnlist, NULL, NULL, um_callerid_desc);

View file

@ -1,6 +1,7 @@
check_PROGRAMS = runtests \
chmode1 \
match1 \
misc \
msgbuf_parse1 \
msgbuf_unparse1 \
hostmask1 \

88
tests/misc.c Normal file
View file

@ -0,0 +1,88 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "tap/basic.h"
#include "s_newconf.h"
#define MSG "%s:%d (%s)", __FILE__, __LINE__, __FUNCTION__
#define MINUTE (60)
#define HOUR (MINUTE * 60)
#define DAY (HOUR * 24)
#define WEEK (DAY * 7)
static void valid_temp_time1(void)
{
time_t t;
t = valid_temp_time("1");
is_int(MINUTE, t, MSG);
t = valid_temp_time("1m");
is_int(MINUTE, t, MSG);
t = valid_temp_time("1h");
is_int(HOUR, t, MSG);
t = valid_temp_time("1d");
is_int(DAY, t, MSG);
t = valid_temp_time("1w");
is_int(WEEK, t, MSG);
t = valid_temp_time("2d");
is_int(2 * DAY, t, MSG);
t = valid_temp_time("1w2d3h4m");
is_int(1 * WEEK + 2 * DAY + 3 * HOUR + 4 * MINUTE, t, MSG);
t = valid_temp_time("1w2d3h4");
is_int(1 * WEEK + 2 * DAY + 3 * HOUR + 4 * MINUTE, t, MSG);
t = valid_temp_time("4m3h2d1w");
is_int(1 * WEEK + 2 * DAY + 3 * HOUR + 4 * MINUTE, t, MSG);
t = valid_temp_time("7000w");
is_int(52 * WEEK, t, MSG);
}
static void valid_temp_time_invalid(void)
{
time_t t;
t = valid_temp_time("-2w");
is_int(-1, t, MSG);
t = valid_temp_time("hello");
is_int(-1, t, MSG);
t = valid_temp_time("m");
is_int(-1, t, MSG);
t = valid_temp_time("1w-1w");
is_int(-1, t, MSG);
}
static void valid_temp_time_overflow(void)
{
char s[100];
time_t t;
snprintf(s, sizeof s, "%" PRIuMAX "m", UINTMAX_MAX / 60 + 2);
t = valid_temp_time(s);
is_int(52 * WEEK, t, MSG);
snprintf(s, sizeof s, "%ldm", LONG_MAX / 60 + 2);
t = valid_temp_time(s);
is_int(52 * WEEK, t, MSG);
snprintf(s, sizeof s, "%ldm%ldm", LONG_MAX / 60 - 1, LONG_MAX / 60 - 1);
t = valid_temp_time(s);
is_int(52 * WEEK, t, MSG);
}
int main(int argc, char *argv[])
{
plan_lazy();
valid_temp_time1();
valid_temp_time_invalid();
valid_temp_time_overflow();
return 0;
}