1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  *                    Ryan Eatmon, Robert Norris
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #include "sm.h"
22 
23 /** @file sm/mod_privacy.c
24   * @brief XEP-0016 Privacy Lists and XEP-0191 Simple Comunications Blocking
25   * @author Robert Norris
26   * $Date: 2005/08/17 07:48:28 $
27   * $Revision: 1.32 $
28   */
29 
30 static int ns_PRIVACY = 0;
31 static int ns_BLOCKING = 0;
32 
33 typedef struct zebra_st         *zebra_t;
34 typedef struct zebra_list_st    *zebra_list_t;
35 typedef struct zebra_item_st    *zebra_item_t;
36 
37 typedef enum {
38     zebra_NONE,
39     zebra_JID,
40     zebra_GROUP,
41     zebra_S10N
42 } zebra_item_type_t;
43 
44 typedef enum {
45     block_NONE = 0x00,
46     block_MESSAGE = 0x01,
47     block_PRES_IN = 0x02,
48     block_PRES_OUT = 0x04,
49     block_IQ = 0x08
50 } zebra_block_type_t;
51 
52 /** zebra data for a single user */
53 struct zebra_st {
54     xht             lists;
55 
56     zebra_list_t    def;
57 };
58 
59 struct zebra_list_st {
60     pool_t          p;
61 
62     char            *name;
63 
64     zebra_item_t    items, last;
65 };
66 
67 struct zebra_item_st {
68     zebra_item_type_t   type;
69 
70     jid_t               jid;
71 
72     char                *group;
73 
74     int                 to;
75     int                 from;
76 
77     int                 deny;       /* 0 = allow, 1 = deny */
78 
79     int                 order;
80 
81     zebra_block_type_t  block;
82 
83     zebra_item_t        next, prev;
84 };
85 
86 typedef struct privacy_st {
87     /* currently active list */
88     zebra_list_t        active;
89 
90     /* was blocklist requested */
91     int                 blocklist;
92 } *privacy_t;
93 
94 /* union for xhash_iter_get to comply with strict-alias rules for gcc3 */
95 union xhashv
96 {
97   void **val;
98   zebra_list_t *z_val;
99 };
100 
_privacy_free_z(zebra_t z)101 static void _privacy_free_z(zebra_t z) {
102     zebra_list_t zlist;
103     union xhashv xhv;
104 
105     log_debug(ZONE, "freeing zebra ctx");
106 
107     if(xhash_iter_first(z->lists))
108         do {
109             xhv.z_val = &zlist;
110             xhash_iter_get(z->lists, NULL, NULL, xhv.val);
111             pool_free(zlist->p);
112         } while(xhash_iter_next(z->lists));
113 
114     xhash_free(z->lists);
115     free(z);
116 }
117 
_privacy_user_free(zebra_t * z)118 static void _privacy_user_free(zebra_t *z) {
119     if(*z != NULL)
120         _privacy_free_z(*z);
121 }
122 
_privacy_user_load(mod_instance_t mi,user_t user)123 static int _privacy_user_load(mod_instance_t mi, user_t user) {
124     module_t mod = mi->mod;
125     zebra_t z;
126     os_t os;
127     os_object_t o;
128     zebra_list_t zlist;
129     pool_t p;
130     zebra_item_t zitem, scan;
131     char *str;
132 
133     log_debug(ZONE, "loading privacy lists for %s", jid_user(user->jid));
134 
135     /* free if necessary */
136     z = user->module_data[mod->index];
137     if(z != NULL)
138         _privacy_free_z(z);
139 
140     z = (zebra_t) calloc(1, sizeof(struct zebra_st));
141 
142     z->lists = xhash_new(101);
143 
144     user->module_data[mod->index] = z;
145 
146     pool_cleanup(user->p, (void (*))(void *) _privacy_user_free, &(user->module_data[mod->index]));
147 
148     /* pull the whole lot */
149     if(storage_get(user->sm->st, "privacy-items", jid_user(user->jid), NULL, &os) == st_SUCCESS) {
150         if(os_iter_first(os))
151             do {
152                 o = os_iter_object(os);
153 
154                 /* list name */
155                 if(!os_object_get_str(os, o, "list", &str)) {
156                     log_debug(ZONE, "item with no list field, skipping");
157                     continue;
158                 }
159 
160                 log_debug(ZONE, "got item for list %s", str);
161 
162                 zlist = xhash_get(z->lists, str);
163 
164                 /* new list */
165                 if(zlist == NULL) {
166                     log_debug(ZONE, "creating list %s", str);
167 
168                     p = pool_new();
169 
170                     zlist = (zebra_list_t) pmalloco(p, sizeof(struct zebra_list_st));
171 
172                     zlist->p = p;
173                     zlist->name = pstrdup(p, str);
174 
175                     xhash_put(z->lists, zlist->name, (void *) zlist);
176                 }
177 
178                 /* new item */
179                 zitem = (zebra_item_t) pmalloco(zlist->p, sizeof(struct zebra_item_st));
180 
181                 /* item type */
182                 if(os_object_get_str(os, o, "type", &str))
183                     switch(str[0]) {
184                         case 'j':
185                             zitem->type = zebra_JID;
186                             break;
187 
188                         case 'g':
189                             zitem->type = zebra_GROUP;
190                             break;
191 
192                         case 's':
193                             zitem->type = zebra_S10N;
194                             break;
195                     }
196 
197                 /* item value, according to type */
198                 if(zitem->type != zebra_NONE) {
199                     if(!os_object_get_str(os, o, "value", &str)) {
200                         log_debug(ZONE, "no value on non-fall-through item, dropping this item");
201                         continue;
202                     }
203 
204                     switch(zitem->type) {
205 
206                         case zebra_JID:
207                             zitem->jid = jid_new(str, strlen(str));
208                             if(zitem->jid == NULL) {
209                                 log_debug(ZONE, "invalid jid '%s' on item, dropping this item", str);
210                                 continue;
211                             }
212 
213                             pool_cleanup(zlist->p, (void *) jid_free, zitem->jid);
214 
215                             log_debug(ZONE, "jid item with value '%s'", jid_full(zitem->jid));
216 
217                             break;
218 
219                         case zebra_GROUP:
220                             zitem->group = pstrdup(zlist->p, str);
221 
222                             log_debug(ZONE, "group item with value '%s'", zitem->group);
223 
224                             break;
225 
226                         case zebra_S10N:
227                             if(strcmp(str, "to") == 0)
228                                 zitem->to = 1;
229                             else if(strcmp(str, "from") == 0)
230                                 zitem->from = 1;
231                             else if(strcmp(str, "both") == 0)
232                                 zitem->to = zitem->from = 1;
233                             else if(strcmp(str, "none") != 0) {
234                                 log_debug(ZONE, "invalid value '%s' on s10n item, dropping this item", str);
235                                 continue;
236                             }
237 
238                             log_debug(ZONE, "s10n item with value '%s' (to %d from %d)", str, zitem->to, zitem->from);
239 
240                             break;
241 
242                         case zebra_NONE:
243                             /* can't get here */
244                             break;
245                     }
246                 }
247 
248                 /* action */
249                 os_object_get_bool(os, o, "deny", &zitem->deny);
250                 if(zitem->deny) {
251                     log_debug(ZONE, "deny rule");
252                 } else {
253                     log_debug(ZONE, "accept rule");
254                 }
255 
256                 os_object_get_int(os, o, "order", &(zitem->order));
257                 log_debug(ZONE, "order %d", zitem->order);
258 
259                 os_object_get_int(os, o, "block", (int*) &(zitem->block));
260                 log_debug(ZONE, "block 0x%x", zitem->block);
261 
262                 /* insert it */
263                 for(scan = zlist->items; scan != NULL; scan = scan->next)
264                     if(zitem->order < scan->order)
265                         break;
266 
267                 /* we're >= everyone, add us to the end */
268                 if(scan == NULL) {
269                     if(zlist->last == NULL)
270                         zlist->items = zlist->last = zitem;
271                     else {
272                         zlist->last->next = zitem;
273                         zitem->prev = zlist->last;
274                         zlist->last = zitem;
275                     }
276                 }
277 
278                 /* insert just before scan */
279                 else {
280                     if(zlist->items == scan) {
281                         zitem->next = zlist->items;
282                         zlist->items = zitem;
283                         scan->prev = zitem;
284                     } else {
285                         zitem->next = scan;
286                         zitem->prev = scan->prev;
287                         scan->prev->next = zitem;
288                         scan->prev = zitem;
289                     }
290                 }
291             } while(os_iter_next(os));
292 
293         os_free(os);
294     }
295 
296     /* default list */
297     if(storage_get(user->sm->st, "privacy-default", jid_user(user->jid), NULL, &os) == st_SUCCESS) {
298         if(os_iter_first(os))
299             do {
300                 o = os_iter_object(os);
301 
302                 if(os_object_get_str(os, o, "default", &str)) {
303                     z->def = (zebra_list_t) xhash_get(z->lists, str);
304                     if(z->def == NULL) {
305                         log_debug(ZONE, "storage says the default list for %s is %s, but it doesn't exist!", jid_user(user->jid), str);
306                     } else {
307                         log_debug(ZONE, "user %s has default list %s", jid_user(user->jid), str);
308                     }
309                 }
310             } while(os_iter_next(os));
311 
312         os_free(os);
313     }
314 
315     return 0;
316 }
317 
318 /** returns 0 if the packet should be allowed, otherwise 1 */
_privacy_action(user_t user,zebra_list_t zlist,jid_t jid,pkt_type_t ptype,int in)319 static int _privacy_action(user_t user, zebra_list_t zlist, jid_t jid, pkt_type_t ptype, int in) {
320     zebra_item_t scan;
321     int match, i;
322     item_t ritem;
323     char domres[2048];
324 
325     log_debug(ZONE, "running match on list %s for %s (packet type 0x%x) (%s)", zlist->name, jid_full(jid), ptype, in ? "incoming" : "outgoing");
326 
327     /* loop over the list, trying to find a match */
328     for(scan = zlist->items; scan != NULL; scan = scan->next) {
329         match = 0;
330 
331         switch(scan->type) {
332             case zebra_NONE:
333                 /* fall through, all packets match this */
334                 match = 1;
335                 break;
336 
337             case zebra_JID:
338                 snprintf(domres, sizeof(domres) / sizeof(domres[0]), "%s/%s", jid->domain, jid->resource);
339 
340                 /* jid check - match node@dom/res, then node@dom, then dom/resource, then dom */
341                 if(jid_compare_full(scan->jid, jid) == 0 ||
342                    strcmp(jid_full(scan->jid), jid_user(jid)) == 0 ||
343                    strcmp(jid_full(scan->jid), domres) == 0 ||
344                    strcmp(jid_full(scan->jid), jid->domain) == 0)
345                     match = 1;
346 
347                 break;
348 
349             case zebra_GROUP:
350                 /* roster group check - get the roster item, node@dom/res, then node@dom, then dom */
351                 ritem = xhash_get(user->roster, jid_full(jid));
352                 if(ritem == NULL) ritem = xhash_get(user->roster, jid_user(jid));
353                 if(ritem == NULL) ritem = xhash_get(user->roster, jid->domain);
354 
355                 /* got it, do the check */
356                 if(ritem != NULL)
357                     for(i = 0; i < ritem->ngroups; i++)
358                         if(strcmp(scan->group, ritem->groups[i]) == 0)
359                             match = 1;
360 
361                 break;
362 
363             case zebra_S10N:
364                 /* roster item check - get the roster item, node@dom/res, then node@dom, then dom */
365                 ritem = xhash_get(user->roster, jid_full(jid));
366                 if(ritem == NULL) ritem = xhash_get(user->roster, jid_user(jid));
367                 if(ritem == NULL) ritem = xhash_get(user->roster, jid->domain);
368 
369                 /* got it, do the check */
370                 if(ritem != NULL)
371                     if(scan->to == ritem->to && scan->from == ritem->from)
372                         match = 1;
373 
374                 break;
375         }
376 
377         /* if we matched a rule, we have to do packet block matching */
378         if(match) {
379             /* no packet blocking, matching done */
380             if(scan->block == block_NONE)
381                 return scan->deny;
382 
383             /* incoming checks block_MESSAGE, block_PRES_IN and block_IQ */
384             if(in) {
385                 if(ptype & pkt_MESSAGE && scan->block & block_MESSAGE)
386                     return scan->deny;
387                 if(ptype & pkt_PRESENCE && scan->block & block_PRES_IN)
388                     return scan->deny;
389                 if(ptype & pkt_IQ && scan->block & block_IQ)
390                     return scan->deny;
391             } else if((ptype & pkt_PRESENCE && scan->block & block_PRES_OUT && ptype != pkt_PRESENCE_PROBE) ||
392                       (ptype & pkt_MESSAGE && scan->block & block_MESSAGE)) {
393                 /* outgoing check, block_PRES_OUT */
394                 /* XXX and block_MESSAGE for XEP-0191 while it violates XEP-0016 */
395                 return scan->deny;
396             }
397         }
398     }
399 
400     /* didn't match the list, so allow */
401     return 0;
402 }
403 
404 /** check incoming packets */
_privacy_in_router(mod_instance_t mi,pkt_t pkt)405 static mod_ret_t _privacy_in_router(mod_instance_t mi, pkt_t pkt) {
406     module_t mod = mi->mod;
407     user_t user;
408     zebra_t z;
409     sess_t sess = NULL;
410     zebra_list_t zlist = NULL;
411 
412     /* if its coming to the sm, let it in */
413     if(pkt->to == NULL || pkt->to->node[0] == '\0')
414         return mod_PASS;
415 
416     /* get the user */
417     user = user_load(mod->mm->sm, pkt->to);
418     if(user == NULL) {
419         log_debug(ZONE, "no user %s, passing packet", jid_user(pkt->to));
420         return mod_PASS;
421     }
422 
423     /* get our lists */
424     z = (zebra_t) user->module_data[mod->index];
425 
426     /* find a session */
427     if(*pkt->to->resource != '\0')
428         sess = sess_match(user, pkt->to->resource);
429 
430     /* didn't match a session, so use the top session */
431     if(sess == NULL)
432         sess = user->top;
433 
434     /* get the active list for the session */
435     if(sess != NULL && sess->module_data[mod->index] != NULL)
436         zlist = ((privacy_t) sess->module_data[mod->index])->active;
437 
438     /* no active list, so use the default list */
439     if(zlist == NULL)
440         zlist = z->def;
441 
442     /* no list, so allow everything */
443     if(zlist == NULL)
444         return mod_PASS;
445 
446     /* figure out the action */
447     if(_privacy_action(user, zlist, pkt->from, pkt->type, 1) == 0)
448         return mod_PASS;
449 
450     /* deny */
451     log_debug(ZONE, "denying incoming packet based on privacy policy");
452 
453     /* iqs get special treatment */
454     if(pkt->type == pkt_IQ || pkt->type == pkt_IQ_SET)
455         return -stanza_err_FEATURE_NOT_IMPLEMENTED;
456 
457     /* drop it */
458     pkt_free(pkt);
459     return mod_HANDLED;
460 }
461 
462 /** check outgoing packets */
_privacy_out_router(mod_instance_t mi,pkt_t pkt)463 static mod_ret_t _privacy_out_router(mod_instance_t mi, pkt_t pkt) {
464     module_t mod = mi->mod;
465     user_t user;
466     zebra_t z;
467     sess_t sess = NULL;
468     zebra_list_t zlist = NULL;
469     int err, ns;
470 
471     /* if its coming from the sm, let it go */
472     if(pkt->from == NULL || pkt->from->node[0] == '\0')
473         return mod_PASS;
474 
475     /* get the user */
476     user = user_load(mod->mm->sm, pkt->from);
477     if(user == NULL) {
478         log_debug(ZONE, "no user %s, passing packet", jid_user(pkt->to));
479         return mod_PASS;
480     }
481 
482     /* get our lists */
483     z = (zebra_t) user->module_data[mod->index];
484 
485     /* find a session */
486     if(*pkt->from->resource != '\0')
487         sess = sess_match(user, pkt->from->resource);
488 
489     /* get the active list for the session */
490     if(sess != NULL && sess->module_data[mod->index] != NULL)
491         zlist = ((privacy_t) sess->module_data[mod->index])->active;
492 
493     /* no active list, so use the default list */
494     if(zlist == NULL)
495         zlist = z->def;
496 
497     /* no list, so allow everything */
498     if(zlist == NULL)
499         return mod_PASS;
500 
501     /* figure out the action */
502     if(_privacy_action(user, zlist, pkt->to, pkt->type, 0) == 0)
503         return mod_PASS;
504 
505     /* deny */
506     log_debug(ZONE, "denying outgoing packet based on privacy policy");
507 
508     /* messages get special treatment */
509     if(pkt->type & pkt_MESSAGE) {
510         /* hack the XEP-0191 error in */
511         pkt_error(pkt, stanza_err_NOT_ACCEPTABLE);
512         err = nad_find_elem(pkt->nad, 1, -1, "error", 1);
513         ns = nad_add_namespace(pkt->nad, urn_BLOCKING_ERR, NULL);
514         nad_insert_elem(pkt->nad, err, ns, "blocked", NULL);
515         pkt_sess(pkt, sess);
516         return mod_HANDLED;
517     }
518 
519     /* drop it */
520     pkt_free(pkt);
521     return mod_HANDLED;
522 }
523 
524 /** add a list to the return packet */
_privacy_result_builder(xht zhash,const char * name,void * val,void * arg)525 static void _privacy_result_builder(xht zhash, const char *name, void *val, void *arg) {
526     zebra_list_t zlist = (zebra_list_t) val;
527     pkt_t pkt = (pkt_t) arg;
528     int ns, query, list, item;
529     zebra_item_t zitem;
530     char order[14];
531 
532     ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVACY, NULL);
533     query = nad_find_elem(pkt->nad, 1, ns, "query", 1);
534 
535     list = nad_insert_elem(pkt->nad, query, ns, "list", NULL);
536     nad_set_attr(pkt->nad, list, -1, "name", zlist->name, 0);
537 
538     /* run through the items and build the nad */
539     for(zitem = zlist->items; zitem != NULL; zitem = zitem->next) {
540         item = nad_insert_elem(pkt->nad, list, ns, "item", NULL);
541 
542         switch(zitem->type) {
543             case zebra_JID:
544                 nad_set_attr(pkt->nad, item, -1, "type", "jid", 0);
545                 nad_set_attr(pkt->nad, item, -1, "value", jid_full(zitem->jid), 0);
546                 break;
547 
548             case zebra_GROUP:
549                 nad_set_attr(pkt->nad, item, -1, "type", "group", 0);
550                 nad_set_attr(pkt->nad, item, -1, "value", zitem->group, 0);
551                 break;
552 
553             case zebra_S10N:
554                 nad_set_attr(pkt->nad, item, -1, "type", "subscription", 0);
555 
556                 if(zitem->to == 1 && zitem->from == 1)
557                     nad_set_attr(pkt->nad, item, -1, "value", "both", 4);
558                 else if(zitem->to == 1)
559                     nad_set_attr(pkt->nad, item, -1, "value", "to", 2);
560                 else if(zitem->from == 1)
561                     nad_set_attr(pkt->nad, item, -1, "value", "from", 4);
562                 else
563                     nad_set_attr(pkt->nad, item, -1, "value", "none", 4);
564 
565                 break;
566 
567             case zebra_NONE:
568                 break;
569         }
570 
571         if(zitem->deny)
572             nad_set_attr(pkt->nad, item, -1, "action", "deny", 4);
573         else
574             nad_set_attr(pkt->nad, item, -1, "action", "allow", 5);
575 
576         snprintf(order, 14, "%d", zitem->order);
577         order[13] = '\0';
578 
579         nad_set_attr(pkt->nad, item, -1, "order", order, 0);
580 
581         if(zitem->block & block_MESSAGE)
582             nad_insert_elem(pkt->nad, item, ns, "message", NULL);
583         if(zitem->block & block_PRES_IN)
584             nad_insert_elem(pkt->nad, item, ns, "presence-in", NULL);
585         if(zitem->block & block_PRES_OUT)
586             nad_insert_elem(pkt->nad, item, ns, "presence-out", NULL);
587         if(zitem->block & block_IQ)
588             nad_insert_elem(pkt->nad, item, ns, "iq", NULL);
589     }
590 }
591 
592 /** add a list to the return packet */
_privacy_lists_result_builder(const char * name,int namelen,void * val,void * arg)593 static void _privacy_lists_result_builder(const char *name, int namelen, void *val, void *arg) {
594     zebra_list_t zlist = (zebra_list_t) val;
595     pkt_t pkt = (pkt_t) arg;
596     int ns, query, list;
597 
598     ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVACY, NULL);
599     query = nad_find_elem(pkt->nad, 1, ns, "query", 1);
600 
601     list = nad_insert_elem(pkt->nad, query, ns, "list", NULL);
602     nad_set_attr(pkt->nad, list, -1, "name", zlist->name, 0);
603 }
604 
605 /** remove jid deny ocurrences from the privacy list,
606     unblock all if no jid given to match,
607     then update unblocked contact with presence information */
_unblock_jid(user_t user,storage_t st,zebra_list_t zlist,jid_t jid)608 static void _unblock_jid(user_t user, storage_t st, zebra_list_t zlist, jid_t jid) {
609     char filter[1024];
610     zebra_item_t scan;
611     sess_t sscan;
612     jid_t notify_jid = NULL;
613 
614     for(scan = zlist->items; scan != NULL; scan = scan->next) {
615         if(scan->type == zebra_JID && scan->deny && (jid == NULL || jid_compare_full(scan->jid, jid) == 0)) {
616             if(zlist->items == scan) {
617                 zlist->items = scan->next;
618                 if(zlist->items != NULL)
619                     zlist->items->prev = NULL;
620             } else {
621                 assert(scan->prev != NULL);
622                 scan->prev->next = scan->next;
623                 if(scan->next != NULL)
624                     scan->next->prev = scan->prev;
625             }
626 
627             if (zlist->last == scan)
628                 zlist->last = scan->prev;
629 
630             /* and from the storage */
631             sprintf(filter, "(&(list=%zu:%s)(type=3:jid)(value=%zu:%s))",
632                     strlen(urn_BLOCKING), urn_BLOCKING, strlen(jid_full(scan->jid)), jid_full(scan->jid));
633             storage_delete(st, "privacy-items", jid_user(user->jid), filter);
634 
635             /* set jid for notify */
636             notify_jid = scan->jid;
637         }
638 
639         /* update unblocked contact with presence information of all sessions */
640 
641         /* XXX NOTE !!! There is a possibility that we notify more than once
642          * if user edited the privacy list manually, not with XEP-0191.
643          * Well... We're going to live with it. ;-) */
644         if(notify_jid != NULL && pres_trust(user, notify_jid))
645             for(sscan = user->sessions; sscan != NULL; sscan = sscan->next) {
646                 /* do not update if session is not available,
647                  * we sent presence direct or got error bounce */
648                 if(!sscan->available || jid_search(sscan->A, notify_jid) || jid_search(sscan->E, notify_jid))
649                     continue;
650 
651                 log_debug(ZONE, "updating unblocked %s with presence from %s", jid_full(notify_jid), jid_full(sscan->jid));
652                 pkt_router(pkt_dup(sscan->pres, jid_full(notify_jid), jid_full(sscan->jid)));
653             }
654     }
655 }
656 
657 /** list management requests */
_privacy_in_sess(mod_instance_t mi,sess_t sess,pkt_t pkt)658 static mod_ret_t _privacy_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) {
659     module_t mod = mi->mod;
660     int ns, query, list, name, active, def, item, type, value, action, order, blocking, jid, push = 0;
661     char corder[14], str[256], filter[1024];
662     zebra_t z;
663     zebra_list_t zlist, old;
664     pool_t p;
665     zebra_item_t zitem, scan;
666     sess_t sscan;
667     jid_t jidt;
668     pkt_t result;
669     os_t os;
670     os_object_t o;
671     st_ret_t ret;
672 
673     /* we only want to play with iq:privacy and urn:xmpp:blocking packets */
674     if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || (pkt->ns != ns_PRIVACY && pkt->ns != ns_BLOCKING))
675         return mod_PASS;
676 
677     /* if it has a to, throw it out */
678     if(pkt->to != NULL)
679         return -stanza_err_BAD_REQUEST;
680 
681     /* get our lists */
682     z = (zebra_t) sess->user->module_data[mod->index];
683 
684     /* create session privacy description */
685     if(sess->module_data[mod->index] == NULL)
686         sess->module_data[mod->index] = (void *) pmalloco(sess->p, sizeof(struct privacy_st));
687 
688     /* handle XEP-0191: Simple Communications Blocking
689      * as simplified frontend to default privacy list */
690     if(pkt->ns == ns_BLOCKING) {
691         if(pkt->type == pkt_IQ_SET) {
692             /* find out what to do */
693             int block;
694             ns = nad_find_scoped_namespace(pkt->nad, urn_BLOCKING, NULL);
695             blocking = nad_find_elem(pkt->nad, 1, ns, "block", 1);
696             if(blocking >= 0)
697                 block = 1;
698             else {
699                 blocking = nad_find_elem(pkt->nad, 1, ns, "unblock", 1);
700                 if(blocking >= 0)
701                     block = 0;
702                 else
703                     return -stanza_err_BAD_REQUEST;
704             }
705 
706             /* if there is no default list, create one */
707             if(!z->def) {
708                 /* remove any previous one */
709                 if((zlist = xhash_get(z->lists, urn_BLOCKING))) {
710                     pool_free(zlist->p);
711                     sprintf(filter, "(list=%zu:%s)", strlen(urn_BLOCKING), urn_BLOCKING);
712                     storage_delete(mod->mm->sm->st, "privacy-items", jid_user(sess->user->jid), filter);
713                 }
714 
715                 /* create new zebra list with name 'urn:xmpp:blocking' */
716                 p = pool_new();
717                 zlist = (zebra_list_t) pmalloco(p, sizeof(struct zebra_list_st));
718                 zlist->p = p;
719                 zlist->name = pstrdup(p, urn_BLOCKING);
720                 xhash_put(z->lists, zlist->name, (void *) zlist);
721 
722                 /* make it default */
723                 z->def = zlist;
724 
725                 /* and in the storage */
726                 os = os_new();
727                 o = os_object_new(os);
728                 os_object_put(o, "default", zlist->name, os_type_STRING);
729                 ret = storage_replace(mod->mm->sm->st, "privacy-default", jid_user(sess->user->jid), NULL, os);
730                 os_free(os);
731                 if(ret != st_SUCCESS)
732                     return -stanza_err_INTERNAL_SERVER_ERROR;
733 
734                 log_debug(ZONE, "blocking created '%s' privacy list and set it default", zlist->name);
735             } else {
736                 /* use the default one */
737                 zlist = z->def;
738             }
739             /* activate this list */
740             ((privacy_t) sess->module_data[mod->index])->active = zlist;
741             log_debug(ZONE, "session '%s' has now active list '%s'", jid_full(sess->jid), zlist->name);
742 
743             item = nad_find_elem(pkt->nad, blocking, ns, "item", 1);
744             if(item < 0) {
745                 if(block) {
746                     /* cannot block unknown */
747                     return -stanza_err_BAD_REQUEST;
748                 } else {
749                     /* unblock all */
750                     _unblock_jid(sess->user, mod->mm->sm->st, zlist, NULL);
751 
752                     /* mark to send blocklist push */
753                     push = 1;
754                 }
755             }
756 
757             /* loop over the items */
758             while(item >= 0) {
759                 /* extract jid */
760                 jid = nad_find_attr(pkt->nad, item, -1, "jid", 0);
761                 if(jid < 0)
762                     return -stanza_err_BAD_REQUEST;
763 
764                 jidt = jid_new(NAD_AVAL(pkt->nad, jid), NAD_AVAL_L(pkt->nad, jid));
765                 if(jidt == NULL)
766                     return -stanza_err_BAD_REQUEST;
767 
768                 /* find blockitem in the list */
769                 for(scan = zlist->items; scan != NULL; scan = scan->next)
770                     if(scan->type == zebra_JID && jid_compare_full(scan->jid, jidt) == 0)
771                         break;
772 
773                 /* take action */
774                 if(block) {
775                     if(scan != NULL && scan->deny && scan->block == block_NONE) {
776                             push = 0;
777                     } else {
778                         /* first make us unavailable if user is on roster */
779                         if(pres_trust(sess->user, jidt))
780                             for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) {
781                                 /* do not update if session is not available,
782                                  * we sent presence direct or got error bounce */
783                                 if(!sscan->available || jid_search(sscan->A, jidt) || jid_search(sscan->E, jidt))
784                                     continue;
785 
786                                 log_debug(ZONE, "forcing unavailable to %s from %s after block", jid_full(jidt), jid_full(sscan->jid));
787                                 pkt_router(pkt_create(sess->user->sm, "presence", "unavailable", jid_full(jidt), jid_full(sscan->jid)));
788                             }
789 
790                         /* new item */
791                         zitem = (zebra_item_t) pmalloco(zlist->p, sizeof(struct zebra_item_st));
792                         zitem->type = zebra_JID;
793 
794                         zitem->jid = jid_new(NAD_AVAL(pkt->nad, jid), NAD_AVAL_L(pkt->nad, jid));
795                         pool_cleanup(zlist->p, (void *) jid_free, zitem->jid);
796                         zitem->deny = 1;
797                         zitem->block = block_NONE;
798 
799                         /* insert it in front of list */
800                         zitem->order = 0;
801                         if(zlist->last == NULL) {
802                             zlist->items = zlist->last = zitem;
803                         } else {
804                             zitem->next = zlist->items;
805                             zlist->items->prev = zitem;
806                             zlist->items = zitem;
807                         }
808 
809                         /* and into the storage backend */
810                         os = os_new();
811                         o = os_object_new(os);
812                         os_object_put(o, "list", zlist->name, os_type_STRING);
813                         os_object_put(o, "type", "jid", os_type_STRING);
814                         os_object_put(o, "value", jid_full(zitem->jid), os_type_STRING);
815                         os_object_put(o, "deny", &zitem->deny, os_type_BOOLEAN);
816                         os_object_put(o, "order", &zitem->order, os_type_INTEGER);
817                         os_object_put(o, "block", &zitem->block, os_type_INTEGER);
818                         ret = storage_put(mod->mm->sm->st, "privacy-items", jid_user(sess->user->jid), os);
819                         os_free(os);
820                         if(ret != st_SUCCESS) {
821                             jid_free(jidt);
822                             return -stanza_err_INTERNAL_SERVER_ERROR;
823                         }
824 
825                         /* mark to send blocklist push */
826                         push = 1;
827                     }
828                 } else {
829                     /* unblock action */
830                     if(scan != NULL && scan->deny) {
831                         /* remove all jid deny ocurrences from the privacy list */
832                         _unblock_jid(sess->user, mod->mm->sm->st, zlist, jidt);
833 
834                         /* mark to send blocklist push */
835                         push = 1;
836                     } else {
837                         jid_free(jidt);
838                         return -stanza_err_ITEM_NOT_FOUND;
839                     }
840                 }
841 
842                 jid_free(jidt);
843 
844                 /* next item */
845                 item = nad_find_elem(pkt->nad, item, ns, "item", 0);
846             }
847 
848             /* return empty result */
849             result = pkt_create(pkt->sm, "iq", "result", NULL, NULL);
850             pkt_id(pkt, result);
851             pkt_sess(result, sess);
852 
853             /* blocklist push */
854             if(push) {
855                 for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) {
856                     /* don't push to us or to anyone who hasn't requested blocklist */
857                     if(sscan == sess || sscan->module_data[mod->index] == NULL || ((privacy_t) sscan->module_data[mod->index])->blocklist == 0)
858                         continue;
859 
860                     result = pkt_dup(pkt, jid_full(sscan->jid), NULL);
861                     if(result->from != NULL) {
862                         jid_free(result->from);
863                         nad_set_attr(result->nad, 1, -1, "from", NULL, 0);
864                         result->from = NULL;
865                     }
866                     pkt_id_new(result);
867                     pkt_sess(result, sscan);
868                 }
869             }
870 
871             /* and done with request */
872             pkt_free(pkt);
873             return mod_HANDLED;
874         }
875 
876         /* it's a get */
877         ns = nad_find_scoped_namespace(pkt->nad, urn_BLOCKING, NULL);
878         blocking = nad_find_elem(pkt->nad, 1, ns, "blocklist", 1);
879         if(blocking < 0)
880             return -stanza_err_BAD_REQUEST;
881 
882         result = pkt_create(pkt->sm, "iq", "result", NULL, NULL);
883         pkt_id(pkt, result);
884         ns = nad_add_namespace(result->nad, urn_BLOCKING, NULL);
885         blocking = nad_insert_elem(result->nad, 1, ns, "blocklist", NULL);
886 
887         /* insert items only from the default list */
888         if(z->def != NULL) {
889             log_debug(ZONE, "blocking list is '%s'", z->def->name);
890             zlist = xhash_get(z->lists, z->def->name);
891             /* run through the items and build the nad */
892             for(zitem = zlist->items; zitem != NULL; zitem = zitem->next) {
893                 /* we're interested in items type 'jid' with action 'deny' only */
894                 if(zitem->type == zebra_JID && zitem->deny) {
895                     item = nad_insert_elem(result->nad, blocking, -1, "item", NULL);
896                     nad_set_attr(result->nad, item, -1, "jid", jid_full(zitem->jid), 0);
897                 }
898             }
899 
900             /* mark that the blocklist was requested */
901             ((privacy_t) sess->module_data[mod->index])->blocklist = 1;
902         }
903 
904         /* give it to the session */
905         pkt_sess(result, sess);
906         pkt_free(pkt);
907         return mod_HANDLED;
908     }
909 
910     /* else handle XEP-0016: Privacy Lists */
911 
912     /* find the query */
913     ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVACY, NULL);
914     query = nad_find_elem(pkt->nad, 1, ns, "query", 1);
915     if(query < 0)
916         return -stanza_err_BAD_REQUEST;
917 
918     /* update lists or set the active list */
919     if(pkt->type == pkt_IQ_SET) {
920         /* find out what we're doing */
921         list = nad_find_elem(pkt->nad, query, ns, "list", 1);
922         active = nad_find_elem(pkt->nad, query, ns, "active", 1);
923         def = nad_find_elem(pkt->nad, query, ns, "default", 1);
924 
925         /* we need something to do, but we can't do it all at once */
926         if((list < 0 && active < 0 && def < 0) || (list >= 0 && (active >=0 || def >= 0)))
927             return -stanza_err_BAD_REQUEST;
928 
929         /* loop over any/all lists and store them */
930         if(list >= 0) {
931             /* only allowed to change one list at a time */
932             if(nad_find_elem(pkt->nad, list, ns, "list", 0) >= 0)
933                 return -stanza_err_BAD_REQUEST;
934 
935             /* get the list name */
936             name = nad_find_attr(pkt->nad, list, -1, "name", NULL);
937             if(name < 0) {
938                 log_debug(ZONE, "no list name specified, failing request");
939                 return -stanza_err_BAD_REQUEST;
940             }
941 
942             snprintf(str, 256, "%.*s", NAD_AVAL_L(pkt->nad, name), NAD_AVAL(pkt->nad, name));
943             str[255] = '\0';
944 
945             log_debug(ZONE, "updating list %s", str);
946 
947             /* make a new one */
948             p = pool_new();
949 
950             zlist = (zebra_list_t) pmalloco(p, sizeof(struct zebra_list_st));
951 
952             zlist->p = p;
953             zlist->name = pstrdup(p, str);
954 
955             os = os_new();
956 
957             /* loop over the items */
958             item = nad_find_elem(pkt->nad, list, ns, "item", 1);
959             while(item >= 0) {
960                 /* extract things */
961                 type = nad_find_attr(pkt->nad, item, -1, "type", 0);
962                 value = nad_find_attr(pkt->nad, item, -1, "value", 0);
963                 action = nad_find_attr(pkt->nad, item, -1, "action", 0);
964                 order = nad_find_attr(pkt->nad, item, -1, "order", 0);
965 
966                 /* sanity */
967                 if(action < 0 || order < 0 || (type >= 0 && value < 0)) {
968                     pool_free(p);
969                     os_free(os);
970                     return -stanza_err_BAD_REQUEST;
971                 }
972 
973                 /* new item */
974                 zitem = (zebra_item_t) pmalloco(p, sizeof(struct zebra_item_st));
975 
976                 /* have to store it too */
977                 o = os_object_new(os);
978                 os_object_put(o, "list", zlist->name, os_type_STRING);
979 
980                 /* type & value */
981                 if(type >= 0) {
982                     if(NAD_AVAL_L(pkt->nad, type) == 3 && strncmp("jid", NAD_AVAL(pkt->nad, type), 3) == 0) {
983                         zitem->type = zebra_JID;
984 
985                         zitem->jid = jid_new(NAD_AVAL(pkt->nad, value), NAD_AVAL_L(pkt->nad, value));
986                         if(zitem->jid == NULL) {
987                             log_debug(ZONE, "invalid jid '%.*s', failing request", NAD_AVAL_L(pkt->nad, value), NAD_AVAL(pkt->nad, value));
988                             pool_free(p);
989                             os_free(os);
990                             return -stanza_err_BAD_REQUEST;
991                         }
992 
993                         pool_cleanup(p, (void *) jid_free, zitem->jid);
994 
995                         log_debug(ZONE, "jid item with value '%s'", jid_full(zitem->jid));
996 
997                         os_object_put(o, "type", "jid", os_type_STRING);
998                         os_object_put(o, "value", jid_full(zitem->jid), os_type_STRING);
999                     }
1000 
1001                     else if(NAD_AVAL_L(pkt->nad, type) == 5 && strncmp("group", NAD_AVAL(pkt->nad, type), 5) == 0) {
1002                         zitem->type = zebra_GROUP;
1003 
1004                         zitem->group = pstrdupx(zlist->p, NAD_AVAL(pkt->nad, value), NAD_AVAL_L(pkt->nad, value));
1005 
1006                         /* !!! check if the group exists */
1007 
1008                         log_debug(ZONE, "group item with value '%s'", zitem->group);
1009 
1010                         os_object_put(o, "type", "group", os_type_STRING);
1011                         os_object_put(o, "value", zitem->group, os_type_STRING);
1012                     }
1013 
1014                     else if(NAD_AVAL_L(pkt->nad, type) == 12 && strncmp("subscription", NAD_AVAL(pkt->nad, type), 12) == 0) {
1015                         zitem->type = zebra_S10N;
1016 
1017                         os_object_put(o, "type", "subscription", os_type_STRING);
1018 
1019                         if(NAD_AVAL_L(pkt->nad, value) == 2 && strncmp("to", NAD_AVAL(pkt->nad, value), 2) == 0) {
1020                             zitem->to = 1;
1021                             os_object_put(o, "value", "to", os_type_STRING);
1022                         } else if(NAD_AVAL_L(pkt->nad, value) == 4 && strncmp("from", NAD_AVAL(pkt->nad, value), 4) == 0) {
1023                             zitem->from = 1;
1024                             os_object_put(o, "value", "from", os_type_STRING);
1025                         } else if(NAD_AVAL_L(pkt->nad, value) == 4 && strncmp("both", NAD_AVAL(pkt->nad, value), 4) == 0) {
1026                             zitem->to = zitem->from = 1;
1027                             os_object_put(o, "value", "both", os_type_STRING);
1028                         } else if(NAD_AVAL_L(pkt->nad, value) == 4 && strncmp("none", NAD_AVAL(pkt->nad, value), 4) == 0)
1029                             os_object_put(o, "value", "none", os_type_STRING);
1030                         else {
1031                             log_debug(ZONE, "invalid value '%.*s' on s10n item, failing request", NAD_AVAL_L(pkt->nad, value), NAD_AVAL(pkt->nad, value));
1032                             pool_free(p);
1033                             os_free(os);
1034                             return -stanza_err_BAD_REQUEST;
1035                         }
1036 
1037                         log_debug(ZONE, "s10n item with value '%.*s' (to %d from %d)", NAD_AVAL_L(pkt->nad, value), NAD_AVAL(pkt->nad, value), zitem->to, zitem->from);
1038                     }
1039                 }
1040 
1041                 /* action */
1042                 if(NAD_AVAL_L(pkt->nad, action) == 4 && strncmp("deny", NAD_AVAL(pkt->nad, action), 4) == 0) {
1043                     zitem->deny = 1;
1044                     log_debug(ZONE, "deny rule");
1045                 } else if(NAD_AVAL_L(pkt->nad, action) == 5 && strncmp("allow", NAD_AVAL(pkt->nad, action), 5) == 0) {
1046                     zitem->deny = 0;
1047                     log_debug(ZONE, "allow rule");
1048                 } else {
1049                     log_debug(ZONE, "unknown action '%.*s', failing request", NAD_AVAL_L(pkt->nad, action), NAD_AVAL(pkt->nad, action));
1050                     pool_free(p);
1051                     os_free(os);
1052                     return -stanza_err_BAD_REQUEST;
1053                 }
1054 
1055                 os_object_put(o, "deny", &zitem->deny, os_type_BOOLEAN);
1056 
1057                 /* order */
1058                 snprintf(corder, 14, "%.*s", NAD_AVAL_L(pkt->nad, order), NAD_AVAL(pkt->nad, order));
1059                 corder[13] = '\0';
1060                 zitem->order = atoi(corder);
1061 
1062                 os_object_put(o, "order", &zitem->order, os_type_INTEGER);
1063 
1064                 /* block types */
1065                 if(nad_find_elem(pkt->nad, item, ns, "message", 1) >= 0)
1066                     zitem->block |= block_MESSAGE;
1067                 if(nad_find_elem(pkt->nad, item, ns, "presence-in", 1) >= 0)
1068                     zitem->block |= block_PRES_IN;
1069                 if(nad_find_elem(pkt->nad, item, ns, "presence-out", 1) >= 0)
1070                     zitem->block |= block_PRES_OUT;
1071                 if(nad_find_elem(pkt->nad, item, ns, "iq", 1) >= 0)
1072                     zitem->block |= block_IQ;
1073 
1074                 /* merge block all */
1075                 if(zitem->block & block_MESSAGE &&
1076                    zitem->block & block_PRES_IN &&
1077                    zitem->block & block_PRES_OUT &&
1078                    zitem->block & block_IQ)
1079                     zitem->block = block_NONE;
1080 
1081                 os_object_put(o, "block", &zitem->block, os_type_INTEGER);
1082 
1083                 /* insert it */
1084                 for(scan = zlist->items; scan != NULL; scan = scan->next)
1085                     if(zitem->order < scan->order)
1086                         break;
1087 
1088                 /* we're >= everyone, add us to the end */
1089                 if(scan == NULL) {
1090                     if(zlist->last == NULL)
1091                         zlist->items = zlist->last = zitem;
1092                     else {
1093                         zlist->last->next = zitem;
1094                         zitem->prev = zlist->last;
1095                         zlist->last = zitem;
1096                     }
1097                 }
1098 
1099                 /* insert just before scan */
1100                 else {
1101                     if(zlist->items == scan) {
1102                         zitem->next = zlist->items;
1103                         zlist->items = zitem;
1104                         scan->prev = zitem;
1105                     } else {
1106                         zitem->next = scan;
1107                         zitem->prev = scan->prev;
1108                         scan->prev->next = zitem;
1109                         scan->prev = zitem;
1110                     }
1111                 }
1112 
1113                 /* next item */
1114                 item = nad_find_elem(pkt->nad, item, ns, "item", 0);
1115             }
1116 
1117             /* write the whole list out */
1118             sprintf(filter, "(list=%zu:%s)", strlen(zlist->name), zlist->name);
1119 
1120             ret = storage_replace(mod->mm->sm->st, "privacy-items", jid_user(sess->user->jid), filter, os);
1121             os_free(os);
1122 
1123             /* failed! */
1124             if(ret != st_SUCCESS) {
1125                 pool_free(zlist->p);
1126                 return -stanza_err_INTERNAL_SERVER_ERROR;
1127             }
1128 
1129             /* old list pointer */
1130             old = xhash_get(z->lists, zlist->name);
1131 
1132             /* removed list */
1133             if(zlist->items == NULL) {
1134                 log_debug(ZONE, "removed list %s", zlist->name);
1135                 xhash_zap(z->lists, zlist->name);
1136                 pool_free(zlist->p);
1137                 if(old != NULL) pool_free(old->p);
1138                 zlist = NULL;
1139             } else {
1140                 log_debug(ZONE, "updated list %s", zlist->name);
1141                 xhash_put(z->lists, zlist->name, (void *) zlist);
1142                 if(old != NULL) pool_free(old->p);
1143             }
1144 
1145             /* if this was a new list, then noone has it active yet */
1146             if(old != NULL) {
1147 
1148                 /* relink */
1149                 log_debug(ZONE, "relinking sessions");
1150 
1151                 /* loop through sessions, relink */
1152                 for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next)
1153                     if(sscan->module_data[mod->index] != NULL && ((privacy_t) sscan->module_data[mod->index])->active == old) {
1154                         ((privacy_t) sscan->module_data[mod->index])->active = zlist;
1155                         log_debug(ZONE, "session '%s' now has active list '%s'", jid_full(sscan->jid), (zlist != NULL) ? zlist->name : "(NONE)");
1156                     }
1157 
1158                 /* default list */
1159                 if(z->def == old) {
1160                     z->def = zlist;
1161 
1162                     if(zlist == NULL) {
1163                         storage_delete(mod->mm->sm->st, "privacy-default", jid_user(sess->user->jid), NULL);
1164                         log_debug(ZONE, "removed default list");
1165                     }
1166                     else {
1167                         os = os_new();
1168                         o = os_object_new(os);
1169 
1170                         os_object_put(o, "default", zlist->name, os_type_STRING);
1171 
1172                         storage_replace(mod->mm->sm->st, "privacy-default", jid_user(sess->user->jid), NULL, os);
1173 
1174                         os_free(os);
1175 
1176                         log_debug(ZONE, "default list is now '%s'", zlist->name);
1177                     }
1178                 }
1179             }
1180         }
1181 
1182         /* set the active list */
1183         if(active >= 0) {
1184             name = nad_find_attr(pkt->nad, active, -1, "name", NULL);
1185             if(name < 0) {
1186                 /* no name, no active list */
1187                 log_debug(ZONE, "clearing active list for session '%s'", jid_full(sess->jid));
1188                 ((privacy_t) sess->module_data[mod->index])->active = NULL;
1189             }
1190             else {
1191                 snprintf(str, 256, "%.*s", NAD_AVAL_L(pkt->nad, name), NAD_AVAL(pkt->nad, name));
1192                 str[255] = '\0';
1193 
1194                 zlist = xhash_get(z->lists, str);
1195                 if(zlist == NULL) {
1196                     log_debug(ZONE, "request to make list '%s' active, but there's no such list", str);
1197                     return -stanza_err_ITEM_NOT_FOUND;
1198                 }
1199 
1200                 ((privacy_t) sess->module_data[mod->index])->active = zlist;
1201 
1202                 log_debug(ZONE, "session '%s' now has active list '%s'", jid_full(sess->jid), str);
1203             }
1204         }
1205 
1206         /* set the default list */
1207         if(def >= 0) {
1208             name = nad_find_attr(pkt->nad, def, -1, "name", NULL);
1209             if(name < 0) {
1210                 /* no name, no default list */
1211                 log_debug(ZONE, "clearing default list for '%s'", jid_user(sess->user->jid));
1212                 z->def = NULL;
1213             }
1214             else {
1215                 snprintf(str, 256, "%.*s", NAD_AVAL_L(pkt->nad, name), NAD_AVAL(pkt->nad, name));
1216                 str[255] = '\0';
1217 
1218                 zlist = xhash_get(z->lists, str);
1219                 if(zlist == NULL) {
1220                     log_debug(ZONE, "request to make list '%s' default, but there's no such list");
1221                     return -stanza_err_ITEM_NOT_FOUND;
1222                 }
1223 
1224                 z->def = zlist;
1225 
1226                 os = os_new();
1227                 o = os_object_new(os);
1228 
1229                 os_object_put(o, "default", zlist->name, os_type_STRING);
1230 
1231                 storage_replace(mod->mm->sm->st, "privacy-default", jid_user(sess->user->jid), NULL, os);
1232 
1233                 os_free(os);
1234 
1235                 log_debug(ZONE, "'%s' now has default list '%s'", jid_user(sess->user->jid), str);
1236             }
1237         }
1238 
1239         /* done, let them know */
1240         result = pkt_create(pkt->sm, "iq", "result", NULL, NULL);
1241 
1242         pkt_id(pkt, result);
1243 
1244         /* done with this */
1245         pkt_free(pkt);
1246 
1247         /* give it to the session */
1248         pkt_sess(result, sess);
1249 
1250         /* all done */
1251         return mod_HANDLED;
1252     }
1253 
1254     /* its a get */
1255 
1256     /* only allowed to request one list, if any */
1257     list = nad_find_elem(pkt->nad, query, ns, "list", 1);
1258     if(list >= 0 && nad_find_elem(pkt->nad, list, ns, "list", 0) >= 0)
1259         return -stanza_err_BAD_REQUEST;
1260 
1261     result = pkt_create(pkt->sm, "iq", "result", NULL, NULL);
1262 
1263     pkt_id(pkt, result);
1264 
1265     ns = nad_add_namespace(result->nad, uri_PRIVACY, NULL);
1266     query = nad_insert_elem(result->nad, 1, ns, "query", NULL);
1267 
1268     /* just do one */
1269     if(list >= 0) {
1270         name = nad_find_attr(pkt->nad, list, -1, "name", NULL);
1271 
1272         zlist = xhash_getx(z->lists, NAD_AVAL(pkt->nad, name), NAD_AVAL_L(pkt->nad, name));
1273         if(zlist == NULL)
1274             return -stanza_err_ITEM_NOT_FOUND;
1275 
1276         _privacy_result_builder(z->lists, zlist->name, (void *) zlist, (void *) result);
1277     }
1278 
1279     else {
1280         /* walk the list hash and add the lists in */
1281         xhash_walk(z->lists, _privacy_lists_result_builder, (void *) result);
1282     }
1283 
1284     /* tell them about current active and default list if they asked for everything */
1285     if(list < 0) {
1286         /* active */
1287         if(((privacy_t) sess->module_data[mod->index])->active != NULL) {
1288             active = nad_insert_elem(result->nad, query, ns, "active", NULL);
1289             nad_set_attr(result->nad, active, -1, "name", ((privacy_t) sess->module_data[mod->index])->active->name, 0);
1290         }
1291 
1292         /* and the default list */
1293         if(z->def != NULL) {
1294             def = nad_insert_elem(result->nad, query, ns, "default", NULL);
1295             nad_set_attr(result->nad, def, -1, "name", z->def->name, 0);
1296         }
1297     }
1298 
1299     /* give it to the session */
1300     pkt_sess(result, sess);
1301 
1302     /* done with this */
1303     pkt_free(pkt);
1304 
1305     /* all done */
1306     return mod_HANDLED;
1307 }
1308 
_privacy_user_delete(mod_instance_t mi,jid_t jid)1309 static void _privacy_user_delete(mod_instance_t mi, jid_t jid) {
1310     log_debug(ZONE, "deleting privacy data for %s", jid_user(jid));
1311 
1312     storage_delete(mi->sm->st, "privacy-items", jid_user(jid), NULL);
1313     storage_delete(mi->sm->st, "privacy-default", jid_user(jid), NULL);
1314 }
1315 
_privacy_free(module_t mod)1316 static void _privacy_free(module_t mod) {
1317      sm_unregister_ns(mod->mm->sm, uri_PRIVACY);
1318      feature_unregister(mod->mm->sm, uri_PRIVACY);
1319 }
1320 
module_init(mod_instance_t mi,const char * arg)1321 DLLEXPORT int module_init(mod_instance_t mi, const char *arg) {
1322     module_t mod = mi->mod;
1323 
1324     if (mod->init) return 0;
1325 
1326     mod->user_load = _privacy_user_load;
1327     mod->in_router = _privacy_in_router;
1328     mod->out_router = _privacy_out_router;
1329     mod->in_sess = _privacy_in_sess;
1330     mod->user_delete = _privacy_user_delete;
1331     mod->free = _privacy_free;
1332 
1333     ns_PRIVACY = sm_register_ns(mod->mm->sm, uri_PRIVACY);
1334     feature_register(mod->mm->sm, uri_PRIVACY);
1335     ns_BLOCKING = sm_register_ns(mod->mm->sm, urn_BLOCKING);
1336     feature_register(mod->mm->sm, urn_BLOCKING);
1337 
1338     return 0;
1339 }
1340