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