450d5ebf218864a0abd64a1c2d97edb052134621
[citadel.git] / citadel / modules / imap / imap_acl.c
1 /*
2  * Functions which implement RFC2086 (and maybe RFC4314) (IMAP ACL extension)
3  *
4  * Copyright (c) 2007-2017 by the citadel.org team
5  *
6  *  This program is open source 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 3 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, MA  02111-1307  USA
19  */
20
21 #include "sysdep.h"
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <fcntl.h>
26 #include <signal.h>
27 #include <pwd.h>
28 #include <errno.h>
29 #include <sys/types.h>
30
31 #if TIME_WITH_SYS_TIME
32 # include <sys/time.h>
33 # include <time.h>
34 #else
35 # if HAVE_SYS_TIME_H
36 #  include <sys/time.h>
37 # else
38 #  include <time.h>
39 # endif
40 #endif
41
42 #include <sys/wait.h>
43 #include <ctype.h>
44 #include <string.h>
45 #include <limits.h>
46 #include <libcitadel.h>
47 #include "citadel.h"
48 #include "server.h"
49 #include "sysdep_decls.h"
50 #include "citserver.h"
51 #include "support.h"
52 #include "config.h"
53 #include "user_ops.h"
54 #include "database.h"
55 #include "msgbase.h"
56 #include "internet_addressing.h"
57 #include "serv_imap.h"
58 #include "imap_tools.h"
59 #include "imap_fetch.h"
60 #include "imap_misc.h"
61 #include "genstamp.h"
62 #include "ctdl_module.h"
63
64
65 /*
66  * Implements the SETACL command.
67  */
68 void imap_setacl(int num_parms, ConstStr *Params) {
69
70         IReply("BAD not yet implemented FIXME");
71         return;
72 }
73
74
75 /*
76  * Implements the DELETEACL command.
77  */
78 void imap_deleteacl(int num_parms, ConstStr *Params) {
79
80         IReply("BAD not yet implemented FIXME");
81         return;
82 }
83
84
85 /*
86  * Given the bits returned by CtdlRoomAccess(), populate a string buffer
87  * with IMAP ACL format flags.   This code is common to GETACL and MYRIGHTS.
88  */
89 void imap_acl_flags(StrBuf *rights, int ra)
90 {
91         FlushStrBuf(rights);
92
93         /* l - lookup (mailbox is visible to LIST/LSUB commands)
94          * r - read (SELECT the mailbox, perform STATUS et al)
95          * s - keep seen/unseen information across sessions (STORE SEEN flag)
96          */
97         if (    (ra & UA_KNOWN)                                 /* known rooms */
98            ||   ((ra & UA_GOTOALLOWED) && (ra & UA_ZAPPED))     /* zapped rooms */
99         ) {
100                 StrBufAppendBufPlain(rights, HKEY("l"), 0);
101                 StrBufAppendBufPlain(rights, HKEY("r"), 0);
102                 StrBufAppendBufPlain(rights, HKEY("s"), 0);
103
104                 /* Only output the remaining flags if the room is known */
105
106                 /* w - write (set or clear flags other than SEEN or DELETED, not supported in Citadel */
107
108                 /* i - insert (perform APPEND, COPY into mailbox) */
109                 /* p - post (send mail to submission address for mailbox - not enforced) */
110                 /* c - create (CREATE new sub-mailboxes) */
111                 if (ra & UA_POSTALLOWED) {
112                         StrBufAppendBufPlain(rights, HKEY("i"), 0);
113                         StrBufAppendBufPlain(rights, HKEY("p"), 0);
114                         StrBufAppendBufPlain(rights, HKEY("c"), 0);
115                 }
116
117                 /* d - delete messages (STORE DELETED flag, perform EXPUNGE) */
118                 if (ra & UA_DELETEALLOWED) {
119                         StrBufAppendBufPlain(rights, HKEY("d"), 0);
120                 }
121
122                 /* a - administer (perform SETACL/DELETEACL/GETACL/LISTRIGHTS) */
123                 if (ra & UA_ADMINALLOWED) {
124                         /*
125                          * This is the correct place to put the "a" flag.  We are leaving
126                          * it commented out for now, because it implies that we could
127                          * perform any of SETACL/DELETEACL/GETACL/LISTRIGHTS.  Since these
128                          * commands are not yet implemented, omitting the flag should
129                          * theoretically prevent compliant clients from attempting to
130                          * perform them.
131                          *
132                          * StrBufAppendBufPlain(rights, HKEY("a"), 0);
133                          */
134                 }
135         }
136 }
137
138
139 /*
140  * Implements the GETACL command.
141  */
142 void imap_getacl(int num_parms, ConstStr *Params) {
143         char roomname[ROOMNAMELEN];
144         char savedroom[ROOMNAMELEN];
145         int msgs, new;
146         int ret;
147         struct ctdluser temp;
148         struct cdbdata *cdbus;
149         int ra;
150         StrBuf *rights;
151
152         if (num_parms != 3) {
153                 IReply("BAD usage error");
154                 return;
155         }
156
157         /*
158          * Search for the specified room or folder
159          */
160         ret = imap_grabroom(roomname, Params[2].Key, 1);
161         if (ret != 0) {
162                 IReply("NO Invalid mailbox name or access denied");
163                 return;
164         }
165
166         /*
167          * CtdlUserGoto() formally takes us to the desired room.  (If another
168          * folder is selected, save its name so we can return there!!!!!)
169          */
170         if (IMAP->selected) {
171                 strcpy(savedroom, CC->room.QRname);
172         }
173         CtdlUserGoto(roomname, 0, 0, &msgs, &new, NULL, NULL);
174
175         IAPuts("* ACL ");
176         IPutCParamStr(2);
177
178         /*
179          * Traverse the userlist
180          */
181         rights = NewStrBuf();
182         cdb_rewind(CDB_USERS);
183         while (cdbus = cdb_next_item(CDB_USERS), cdbus != NULL) 
184         {
185                 memset(&temp, 0, sizeof temp);
186                 memcpy(&temp, cdbus->ptr, sizeof temp);
187                 cdb_free(cdbus);
188
189                 CtdlRoomAccess(&CC->room, &temp, &ra, NULL);
190                 if (!IsEmptyStr(temp.fullname)) {
191                         imap_acl_flags(rights, ra);
192                         if (StrLength(rights) > 0) {
193                                 IAPuts(" ");
194                                 IPutStr(temp.fullname, strlen(temp.fullname));
195                                 IAPuts(" ");
196                                 iaputs(SKEY( rights));
197                         }
198                 }
199         }
200         FreeStrBuf(&rights);
201         IAPuts("\r\n");
202
203         /*
204          * If another folder is selected, go back to that room so we can resume
205          * our happy day without violent explosions.
206          */
207         if (IMAP->selected) {
208                 CtdlUserGoto(savedroom, 0, 0, &msgs, &new, NULL, NULL);
209         }
210
211         IReply("OK GETACL completed");
212 }
213
214
215 /*
216  * Implements the LISTRIGHTS command.
217  */
218 void imap_listrights(int num_parms, ConstStr *Params) {
219         char roomname[ROOMNAMELEN];
220         char savedroom[ROOMNAMELEN];
221         int msgs, new;
222         int ret;
223         recptypes *valid;
224         struct ctdluser temp;
225
226         if (num_parms != 4) {
227                 IReply("BAD usage error");
228                 return;
229         }
230
231         /*
232          * Search for the specified room/folder
233          */
234         ret = imap_grabroom(roomname, Params[2].Key, 1);
235         if (ret != 0) {
236                 IReply("NO Invalid mailbox name or access denied");
237                 return;
238         }
239
240         /*
241          * Search for the specified user
242          */
243         ret = (-1);
244         valid = validate_recipients(Params[3].Key, NULL, 0);
245         if (valid != NULL) {
246                 if (valid->num_local == 1) {
247                         ret = CtdlGetUser(&temp, valid->recp_local);
248                 }
249                 free_recipients(valid);
250         }
251         if (ret != 0) {
252                 IReply("NO Invalid user name or access denied");
253                 return;
254         }
255
256         /*
257          * CtdlUserGoto() formally takes us to the desired room.  (If another
258          * folder is selected, save its name so we can return there!!!!!)
259          */
260         if (IMAP->selected) {
261                 strcpy(savedroom, CC->room.QRname);
262         }
263         CtdlUserGoto(roomname, 0, 0, &msgs, &new, NULL, NULL);
264
265         /*
266          * Now output the list of rights
267          */
268         IAPuts("* LISTRIGHTS ");
269         IPutCParamStr(2);
270         IAPuts(" ");
271         IPutCParamStr(3);
272         IAPuts(" ");
273         IPutStr(HKEY(""));              /* FIXME ... do something here */
274         IAPuts("\r\n");
275
276         /*
277          * If another folder is selected, go back to that room so we can resume
278          * our happy day without violent explosions.
279          */
280         if (IMAP->selected) {
281                 CtdlUserGoto(savedroom, 0, 0, &msgs, &new, NULL, NULL);
282         }
283
284         IReply("OK LISTRIGHTS completed");
285         return;
286 }
287
288
289 /*
290  * Implements the MYRIGHTS command.
291  */
292 void imap_myrights(int num_parms, ConstStr *Params) {
293         char roomname[ROOMNAMELEN];
294         char savedroom[ROOMNAMELEN];
295         int msgs, new;
296         int ret;
297         int ra;
298         StrBuf *rights;
299
300         if (num_parms != 3) {
301                 IReply("BAD usage error");
302                 return;
303         }
304
305         ret = imap_grabroom(roomname, Params[2].Key, 1);
306         if (ret != 0) {
307                 IReply("NO Invalid mailbox name or access denied");
308                 return;
309         }
310
311         /*
312          * CtdlUserGoto() formally takes us to the desired room.  (If another
313          * folder is selected, save its name so we can return there!!!!!)
314          */
315         if (IMAP->selected) {
316                 strcpy(savedroom, CC->room.QRname);
317         }
318         CtdlUserGoto(roomname, 0, 0, &msgs, &new, NULL, NULL);
319
320         CtdlRoomAccess(&CC->room, &CC->user, &ra, NULL);
321         rights = NewStrBuf();
322         imap_acl_flags(rights, ra);
323
324         IAPuts("* MYRIGHTS ");
325         IPutCParamStr(2);
326         IAPuts(" ");
327         IPutStr(SKEY(rights));
328         IAPuts("\r\n");
329
330         FreeStrBuf(&rights);
331
332         /*
333          * If a different folder was previously selected, return there now.
334          */
335         if ( (IMAP->selected) && (strcasecmp(roomname, savedroom)) ) {
336                 CtdlUserGoto(savedroom, 0, 0, &msgs, &new, NULL, NULL);
337         }
338
339         IReply("OK MYRIGHTS completed");
340         return;
341 }