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