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