1 /* groupserv - group services.
2  * Copyright (C) 2010 Atheme Development Group
3  */
4 
5 #include "groupserv_main.h"
6 
mygroup_expire(void * unused)7 static void mygroup_expire(void *unused)
8 {
9 	myentity_t *mt;
10 	myentity_iteration_state_t state;
11 
12 	MYENTITY_FOREACH_T(mt, &state, ENT_GROUP)
13 	{
14 		mygroup_t *mg = group(mt);
15 
16 		continue_if_fail(mt != NULL);
17 		continue_if_fail(mg != NULL);
18 
19 		if (!mygroup_count_flag(mg, GA_FOUNDER))
20 		{
21 			remove_group_chanacs(mg);
22 			object_unref(mg);
23 		}
24 	}
25 }
26 
grant_channel_access_hook(user_t * u)27 static void grant_channel_access_hook(user_t *u)
28 {
29 	mowgli_node_t *n, *tn;
30 	mowgli_list_t *l;
31 
32 	return_if_fail(u->myuser != NULL);
33 
34 	l = myentity_get_membership_list(entity(u->myuser));
35 
36 	MOWGLI_ITER_FOREACH_SAFE(n, tn, l->head)
37 	{
38 		groupacs_t *ga = n->data;
39 
40 		if (!(ga->flags & GA_CHANACS))
41 			continue;
42 
43 		MOWGLI_ITER_FOREACH(n, entity(ga->mg)->chanacs.head)
44 		{
45 			chanacs_t *ca;
46 			chanuser_t *cu;
47 
48 			ca = (chanacs_t *)n->data;
49 
50 			if (ca->mychan->chan == NULL)
51 				continue;
52 
53 			cu = chanuser_find(ca->mychan->chan, u);
54 			if (cu && chansvs.me != NULL)
55 			{
56 				if (ca->level & CA_AKICK && !(ca->level & CA_EXEMPT))
57 				{
58 					/* Stay on channel if this would empty it -- jilles */
59 					if (ca->mychan->chan->nummembers - ca->mychan->chan->numsvcmembers == 1)
60 					{
61 						ca->mychan->flags |= MC_INHABIT;
62 						if (ca->mychan->chan->numsvcmembers == 0)
63 							join(cu->chan->name, chansvs.nick);
64 					}
65 					ban(chansvs.me->me, ca->mychan->chan, u);
66 					remove_ban_exceptions(chansvs.me->me, ca->mychan->chan, u);
67 					kick(chansvs.me->me, ca->mychan->chan, u, "User is banned from this channel");
68 					continue;
69 				}
70 
71 				if (ca->level & CA_USEDUPDATE)
72 					ca->mychan->used = CURRTIME;
73 
74 				if (ca->mychan->flags & MC_NOOP || u->myuser->flags & MU_NOOP)
75 					continue;
76 
77 				if (ircd->uses_owner && !(cu->modes & ircd->owner_mode) && ca->level & CA_AUTOOP && ca->level & CA_USEOWNER)
78 				{
79 					modestack_mode_param(chansvs.nick, ca->mychan->chan, MTYPE_ADD, ircd->owner_mchar[1], CLIENT_NAME(u));
80 					cu->modes |= ircd->owner_mode;
81 				}
82 
83 				if (ircd->uses_protect && !(cu->modes & ircd->protect_mode) && !(ircd->uses_owner && cu->modes & ircd->owner_mode) && ca->level & CA_AUTOOP && ca->level & CA_USEPROTECT)
84 				{
85 					modestack_mode_param(chansvs.nick, ca->mychan->chan, MTYPE_ADD, ircd->protect_mchar[1], CLIENT_NAME(u));
86 					cu->modes |= ircd->protect_mode;
87 				}
88 
89 				if (!(cu->modes & CSTATUS_OP) && ca->level & CA_AUTOOP)
90 				{
91 					modestack_mode_param(chansvs.nick, ca->mychan->chan, MTYPE_ADD, 'o', CLIENT_NAME(u));
92 					cu->modes |= CSTATUS_OP;
93 				}
94 
95 				if (ircd->uses_halfops && !(cu->modes & (CSTATUS_OP | ircd->halfops_mode)) && ca->level & CA_AUTOHALFOP)
96 				{
97 					modestack_mode_param(chansvs.nick, ca->mychan->chan, MTYPE_ADD, 'h', CLIENT_NAME(u));
98 					cu->modes |= ircd->halfops_mode;
99 				}
100 
101 				if (!(cu->modes & (CSTATUS_OP | ircd->halfops_mode | CSTATUS_VOICE)) && ca->level & CA_AUTOVOICE)
102 				{
103 					modestack_mode_param(chansvs.nick, ca->mychan->chan, MTYPE_ADD, 'v', CLIENT_NAME(u));
104 					cu->modes |= CSTATUS_VOICE;
105 				}
106 			}
107 		}
108 	}
109 }
110 
user_info_hook(hook_user_req_t * req)111 static void user_info_hook(hook_user_req_t *req)
112 {
113 	static char buf[BUFSIZE];
114 	mowgli_node_t *n;
115 	mowgli_list_t *l;
116 
117 	*buf = 0;
118 
119 	l = myentity_get_membership_list(entity(req->mu));
120 
121 	MOWGLI_ITER_FOREACH(n, l->head)
122 	{
123 		groupacs_t *ga = n->data;
124 
125 		if (ga->flags & GA_BAN)
126 			continue;
127 
128 		if ((ga->mg->flags & MG_PUBLIC) || (req->si->smu == req->mu || has_priv(req->si, PRIV_GROUP_AUSPEX)))
129 		{
130 			if (*buf != 0)
131 				mowgli_strlcat(buf, ", ", BUFSIZE);
132 
133 			mowgli_strlcat(buf, entity(ga->mg)->name, BUFSIZE);
134 		}
135 	}
136 
137 	if (*buf != 0)
138 		command_success_nodata(req->si, _("Groups     : %s"), buf);
139 }
140 
sasl_may_impersonate_hook(hook_sasl_may_impersonate_t * req)141 static void sasl_may_impersonate_hook(hook_sasl_may_impersonate_t *req)
142 {
143 	char priv[BUFSIZE];
144 	mowgli_list_t *l;
145 	mowgli_node_t *n;
146 
147 	/* if the request is already granted, don't bother doing any of this. */
148 	if (req->allowed)
149 		return;
150 
151 	l = myentity_get_membership_list(entity(req->target_mu));
152 
153 	MOWGLI_ITER_FOREACH(n, l->head)
154 	{
155 		groupacs_t *ga = n->data;
156 
157 		snprintf(priv, sizeof(priv), PRIV_IMPERSONATE_ENTITY_FMT, entity(ga->mg)->name);
158 
159 		if (has_priv_myuser(req->source_mu, priv))
160 		{
161 			req->allowed = true;
162 			return;
163 		}
164 	}
165 }
166 
myuser_delete_hook(myuser_t * mu)167 static void myuser_delete_hook(myuser_t *mu)
168 {
169 	mowgli_node_t *n, *tn;
170 	mowgli_list_t *l;
171 
172 	l = myentity_get_membership_list(entity(mu));
173 
174 	MOWGLI_ITER_FOREACH_SAFE(n, tn, l->head)
175 	{
176 		groupacs_t *ga = n->data;
177 
178 		groupacs_delete(ga->mg, ga->mt);
179 	}
180 
181 	mowgli_list_free(l);
182 }
183 
osinfo_hook(sourceinfo_t * si)184 static void osinfo_hook(sourceinfo_t *si)
185 {
186 	return_if_fail(si != NULL);
187 
188 	command_success_nodata(si, "Maximum number of groups one user can own: %u", gs_config.maxgroups);
189 	command_success_nodata(si, "Maximum number of ACL entries allowed for one group: %u", gs_config.maxgroupacs);
190 	command_success_nodata(si, "Are open groups allowed: %s", gs_config.enable_open_groups ? "Yes" : "No");
191 	command_success_nodata(si, "Default joinflags for open groups: %s", gs_config.join_flags);
192 }
193 
194 static mowgli_eventloop_timer_t *mygroup_expire_timer = NULL;
195 
gs_hooks_init(void)196 void gs_hooks_init(void)
197 {
198 	mygroup_expire_timer = mowgli_timer_add(base_eventloop, "mygroup_expire", mygroup_expire, NULL, 3600);
199 
200 	hook_add_event("myuser_delete");
201 	hook_add_event("user_info");
202 	hook_add_event("grant_channel_access");
203 	hook_add_event("operserv_info");
204 	hook_add_event("sasl_may_impersonate");
205 
206 	hook_add_user_info(user_info_hook);
207 	hook_add_myuser_delete(myuser_delete_hook);
208 	hook_add_grant_channel_access(grant_channel_access_hook);
209 	hook_add_operserv_info(osinfo_hook);
210 	hook_add_sasl_may_impersonate(sasl_may_impersonate_hook);
211 }
212 
gs_hooks_deinit(void)213 void gs_hooks_deinit(void)
214 {
215 	mowgli_timer_destroy(base_eventloop, mygroup_expire_timer);
216 
217 	hook_del_user_info(user_info_hook);
218 	hook_del_myuser_delete(myuser_delete_hook);
219 	hook_del_grant_channel_access(grant_channel_access_hook);
220 	hook_del_operserv_info(osinfo_hook);
221 	hook_del_sasl_may_impersonate(sasl_may_impersonate_hook);
222 }
223