]> andersk Git - moira.git/blob - server/qaccess.pc
add tag_member_of_list() function so we don't get broken incrementals
[moira.git] / server / qaccess.pc
1 /* $Id$
2  *
3  * Check access to queries
4  *
5  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  */
9
10 #include <mit-copyright.h>
11 #include "mr_server.h"
12 #include "qrtn.h"
13 #include "query.h"
14
15 #include <ctype.h>
16 #include <stdlib.h>
17
18 EXEC SQL INCLUDE sqlca;
19
20 RCSID("$Header$");
21
22 extern char *whoami;
23 extern int dbms_errno, mr_errcode;
24
25 EXEC SQL WHENEVER SQLERROR DO dbmserr();
26
27
28 /* Specialized Access Routines */
29
30 /* access_user - verify that client name equals specified login name
31  *
32  *  - since field validation routines are called first, a users_id is
33  *    now in argv[0] instead of the login name.
34  */
35
36 int access_user(struct query *q, char *argv[], client *cl)
37 {
38   if (cl->users_id != *(int *)argv[0])
39     return MR_PERM;
40   else
41     return MR_SUCCESS;
42 }
43
44
45
46 /* access_login - verify that client name equals specified login name
47  *
48  *   argv[0...n] contain search info.  q->
49  */
50
51 int access_login(struct query *q, char *argv[], client *cl)
52 {
53   EXEC SQL BEGIN DECLARE SECTION;
54   int id;
55   EXEC SQL END DECLARE SECTION;
56
57   if (q->argc != 1)
58     return MR_ARGS;
59
60   if (!strcmp(q->shortname, "gual"))
61     {
62       EXEC SQL SELECT users_id INTO :id FROM users
63         WHERE login = :argv[0] AND users_id != 0;
64     }
65   else if (!strcmp(q->shortname, "gubl"))
66     {
67       EXEC SQL SELECT users_id INTO :id FROM users u
68         WHERE u.login = :argv[0] AND u.users_id != 0;
69     }
70   else if (!strcmp(q->shortname, "guau"))
71     {
72       EXEC SQL SELECT users_id INTO :id FROM users
73         WHERE unix_uid = :argv[0] AND users_id != 0;
74     }
75   else if (!strcmp(q->shortname, "gubu"))
76     {
77       EXEC SQL SELECT users_id INTO :id FROM users u
78         WHERE u.unix_uid = :argv[0] AND u.users_id != 0;
79     }
80
81   if (sqlca.sqlcode == SQL_NO_MATCH)
82     return MR_NO_MATCH; /* ought to be MR_USER, but this is what
83                            gual returns, so we have to be consistent */
84   else if (sqlca.sqlerrd[2] != 1 || id != cl->users_id)
85     return MR_PERM;
86   else
87     return MR_SUCCESS;
88 }
89
90
91 /* access_spob - check access for set_pobox */
92
93 int access_spob(struct query *q, char *argv[], client *cl)
94 {
95   EXEC SQL BEGIN DECLARE SECTION;
96   int id;
97   EXEC SQL END DECLARE SECTION;
98
99   if (!strcmp(argv[1], "IMAP"))
100       {
101         EXEC SQL SELECT owner INTO :id FROM filesys f 
102           WHERE f.label = :argv[2] AND f.type = 'IMAP' AND
103           f.lockertype = 'USER';
104         if (cl->users_id != id)
105           return MR_PERM;
106       }
107   if (cl->users_id != *(int *)argv[0])
108     return MR_PERM;
109   else
110     return MR_SUCCESS;
111 }
112
113
114 /* access_list - check access for most list operations
115  *
116  * Inputs: argv[0] - list_id
117  *          q - query name
118  *          argv[2] - member ID (only for queries "amtl" and  "dmfl")
119  *          argv[7] - group ID (only for query "ulis")
120  *          cl - client name
121  *
122  * - check that client is a member of the access control list
123  * - OR, if the query is add_member_to_list or delete_member_from_list
124  *      and the list is public, allow access if client = member
125  */
126
127 int access_list(struct query *q, char *argv[], client *cl)
128 {
129   EXEC SQL BEGIN DECLARE SECTION;
130   int list_id, acl_id, flags, gid, users_id;
131   char acl_type[LIST_ACL_TYPE_SIZE], name[LIST_NAME_SIZE], *newname;
132   EXEC SQL END DECLARE SECTION;
133   int status;
134
135   list_id = *(int *)argv[0];
136   EXEC SQL SELECT acl_id, acl_type, gid, publicflg, name
137     INTO :acl_id, :acl_type, :gid, :flags, :name
138     FROM list
139     WHERE list_id = :list_id;
140
141   if (sqlca.sqlerrd[2] != 1)
142     return MR_INTERNAL;
143
144   /* Allow client to add self to public list or delete self from any
145    * list.
146    */
147   if ((((!strcmp("amtl", q->shortname) ||
148          !strcmp("atml", q->shortname)) && flags) ||
149        (!strcmp("dmfl", q->shortname))))
150     {
151       if (!strcmp("USER", argv[1]) && *(int *)argv[2] == cl->users_id)
152         return MR_SUCCESS;
153       if (!strcmp("KERBEROS", argv[1]) && *(int *)argv[2] == -cl->client_id)
154         return MR_SUCCESS;
155     } /* if update_list, don't allow them to change the GID or rename to
156          a username other than their own */
157   else if (!strcmp("ulis", q->shortname))
158     {
159       if (!strcmp(argv[7], UNIQUE_GID))
160         {
161           if (gid != -1)
162             return MR_PERM;
163         }
164       else
165         {
166           if (gid != atoi(argv[7]))
167             return MR_PERM;
168         }
169
170       newname = argv[1];
171
172       if (!strcmp("ulis", q->shortname))
173           {
174             /* Check that it doesn't conflict with the Grouper namespace. */
175             if (strlen(newname) > 4 && isdigit(newname[2]) && 
176                 isdigit(newname[3]) && newname[4] == '-')
177               {
178                 if (!strncasecmp(newname, "fa", 2) ||
179                     !strncasecmp(newname, "sp", 2) ||
180                     !strncasecmp(newname, "su", 2) ||
181                     !strncasecmp(newname, "ja", 2))
182                   return MR_RESERVED;
183               }
184
185             /* Don't let anyone take owner-foo list names.  They interact 
186              * weirdly with the aliases automatically generated by 
187              * mailhub.gen.
188              */
189             if (!strncasecmp(newname, "owner-", 6))
190               return MR_RESERVED;
191           }
192
193       EXEC SQL SELECT users_id INTO :users_id FROM users
194         WHERE login = :newname;
195       if ((sqlca.sqlcode != SQL_NO_MATCH) && strcmp(strtrim(name), newname) &&
196           (users_id != cl->users_id))
197         return MR_PERM;
198     }
199
200   /* check for client in access control list */
201   status = find_member(acl_type, acl_id, cl);
202   if (!status)
203     return MR_PERM;
204
205   return MR_SUCCESS;
206 }
207
208
209 /* access_visible_list - allow access to list only if it is not hidden,
210  *      or if the client is on the ACL
211  *
212  * Inputs: argv[0] - list_id
213  *         cl - client identifier
214  */
215
216 int access_visible_list(struct query *q, char *argv[], client *cl)
217 {
218   EXEC SQL BEGIN DECLARE SECTION;
219   int list_id, acl_id, flags ;
220   char acl_type[LIST_ACL_TYPE_SIZE];
221   EXEC SQL END DECLARE SECTION;
222   int status;
223
224   list_id = *(int *)argv[0];
225   EXEC SQL SELECT hidden, acl_id, acl_type
226     INTO :flags, :acl_id, :acl_type
227     FROM list
228     WHERE list_id = :list_id;
229   if (sqlca.sqlerrd[2] != 1)
230     return MR_INTERNAL;
231   if (!flags)
232     return MR_SUCCESS;
233
234   /* check for client in access control list */
235   status = find_member(acl_type, acl_id, cl);
236   if (!status)
237     return MR_PERM;
238
239   return MR_SUCCESS;
240 }
241
242
243 /* access_vis_list_by_name - allow access to list only if it is not hidden,
244  *      or if the client is on the ACL
245  *
246  * Inputs: argv[0] - list name
247  *         cl - client identifier
248  */
249
250 int access_vis_list_by_name(struct query *q, char *argv[], client *cl)
251 {
252   EXEC SQL BEGIN DECLARE SECTION;
253   int acl_id, flags, rowcount;
254   char acl_type[LIST_ACL_TYPE_SIZE], *listname;
255   EXEC SQL END DECLARE SECTION;
256   int status;
257
258   listname = argv[0];
259   EXEC SQL SELECT hidden, acl_id, acl_type INTO :flags, :acl_id, :acl_type
260     FROM list WHERE name = :listname;
261
262   rowcount = sqlca.sqlerrd[2];
263   if (rowcount > 1)
264     return MR_WILDCARD;
265   if (rowcount == 0)
266     return MR_NO_MATCH;
267   if (!flags)
268     return MR_SUCCESS;
269
270   /* check for client in access control list */
271   status = find_member(acl_type, acl_id, cl);
272   if (!status)
273     return MR_PERM;
274
275   return MR_SUCCESS;
276 }
277
278
279 /* access_member - allow user to access member of type "USER" and name matches
280  * username, or to access member of type "KERBEROS" and the principal matches
281  * the user, or to access member of type "LIST" and list is one that user is
282  * on the acl of, or the list is visible.
283  */
284
285 int access_member(struct query *q, char *argv[], client *cl)
286 {
287   if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
288     return access_visible_list(q, &argv[1], cl);
289
290   if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER"))
291     {
292       if (cl->users_id == *(int *)argv[1])
293         return MR_SUCCESS;
294     }
295
296   if (!strcmp(argv[0], "KERBEROS") || !strcmp(argv[0], "RKERBEROS"))
297     {
298       if (cl->client_id == -*(int *)argv[1])
299         return MR_SUCCESS;
300     }
301
302   return MR_PERM;
303 }
304
305
306 /* access_qgli - special access routine for Qualified_get_lists.  Allows
307  * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
308  */
309
310 int access_qgli(struct query *q, char *argv[], client *cl)
311 {
312   if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
313     return MR_SUCCESS;
314   return MR_PERM;
315 }
316
317
318 /* access_service - allow access if user is on ACL of service.  Don't
319  * allow access if a wildcard is used.
320  */
321
322 int access_service(struct query *q, char *argv[], client *cl)
323 {
324   EXEC SQL BEGIN DECLARE SECTION;
325   int acl_id;
326   char *name, acl_type[LIST_ACL_TYPE_SIZE];
327   EXEC SQL END DECLARE SECTION;
328   int status;
329   char *c;
330
331   name = argv[0];
332   for (c = name; *c; c++)
333     {
334       if (islower(*c))
335         *c = toupper(*c);
336     }
337   EXEC SQL SELECT acl_id, acl_type INTO :acl_id, :acl_type FROM servers
338     WHERE name = :name;
339   if (sqlca.sqlerrd[2] > 1)
340     return MR_PERM;
341
342   /* check for client in access control list */
343   status = find_member(acl_type, acl_id, cl);
344   if (!status)
345     return MR_PERM;
346
347   return MR_SUCCESS;
348 }
349
350
351 /* access_filesys - verify that client is owner or on owners list of filesystem
352  *      named by argv[0]
353  */
354
355 int access_filesys(struct query *q, char *argv[], client *cl)
356 {
357   EXEC SQL BEGIN DECLARE SECTION;
358   int users_id, list_id;
359   char *name;
360   EXEC SQL END DECLARE SECTION;
361   int status;
362
363   name = argv[0];
364   EXEC SQL SELECT owner, owners INTO :users_id, :list_id FROM filesys
365     WHERE label = :name;
366
367   if (sqlca.sqlerrd[2] != 1)
368     return MR_PERM;
369   if (users_id == cl->users_id)
370     return MR_SUCCESS;
371   status = find_member("LIST", list_id, cl);
372   if (status)
373     return MR_SUCCESS;
374   else
375     return MR_PERM;
376 }
377
378
379 /* access_host - successful if owner of host, or subnet containing host
380  */
381
382 int access_host(struct query *q, char *argv[], client *cl)
383 {
384   EXEC SQL BEGIN DECLARE SECTION;
385   int mid, sid, id;
386   char mtype[MACHINE_OWNER_TYPE_SIZE], stype[SUBNET_OWNER_TYPE_SIZE];
387   EXEC SQL END DECLARE SECTION;
388   int status;
389
390   if (q->type == RETRIEVE)
391     {
392       if (strcmp(argv[0], "*") || strcmp(argv[1], "*") ||
393           strcmp(argv[2], "*") || strcmp(argv[3], "*"))
394         return MR_SUCCESS;
395       else
396         return MR_PERM;
397     }
398
399   if (q->type == APPEND)
400     {
401       /* Non-query owner must set use to zero */
402       if (atoi(argv[6]) != 0)
403         return MR_PERM;
404
405       /* ... and start the hostname with a letter */
406       if (isdigit(argv[0][0]))
407         return MR_BAD_CHAR;
408
409       id = *(int *)argv[8];
410       EXEC SQL SELECT s.owner_type, s.owner_id
411         INTO :stype, :sid FROM subnet s
412         WHERE s.snet_id = :id;
413       mid = 0;
414
415       if (find_member(stype, sid, cl))
416         return MR_SUCCESS;
417       else
418         return MR_PERM;
419     }
420   else /* q-type == UPDATE */
421     {
422       EXEC SQL BEGIN DECLARE SECTION;
423       int status, acomment, use, ocomment, snid;
424       char contact[MACHINE_CONTACT_SIZE], address[MACHINE_ADDRESS_SIZE];
425       char name[MACHINE_NAME_SIZE];
426       EXEC SQL END DECLARE SECTION;
427
428       id = *(int *)argv[0];
429       EXEC SQL SELECT m.name, m.use, m.contact, m.status, m.address,
430         m.owner_type, m.owner_id, m.acomment, m.ocomment, m.snet_id,
431         s.owner_type, s.owner_id INTO :name, :use, :contact, :status,
432         :address, :mtype, :mid, :acomment, :ocomment, :snid, :stype, :sid
433         FROM machine m, subnet s
434         WHERE m.mach_id = :id AND s.snet_id = m.snet_id;
435       if (dbms_errno)
436         return mr_errcode;
437
438       /* non-query-owner cannot change use or ocomment */
439       if ((use != atoi(argv[7])) || (ocomment != *(int *)argv[14]))
440         return MR_PERM;
441
442       /* or rename to start with digit */
443       if (isdigit(argv[1][0]) && strcmp(strtrim(name), argv[1]))
444         return MR_BAD_CHAR;
445
446       if (!find_member(stype, sid, cl))
447         {
448           if (find_member(mtype, mid, cl))
449             {
450               /* host owner also cannot change contact, status, address,
451                  owner, or acomment */
452               if (strcmp(argv[6], strtrim(contact)) ||
453                   (status != atoi(argv[8])) ||
454                   strcmp(argv[10], strtrim(address)) ||
455                   strcmp(argv[11], strtrim(mtype)) ||
456                   (mid != *(int *)argv[12]) || (acomment != *(int *)argv[13]))
457                 return MR_PERM;
458             }
459           else
460             return MR_PERM;
461         }
462
463       /* If moving to a new subnet, make sure user is on acl there */
464       id = *(int *)argv[9];
465       if (id != snid)
466         {
467           EXEC SQL SELECT owner_type, owner_id INTO :stype, :sid
468             FROM subnet WHERE snet_id=:id;
469           if (!find_member(stype, sid, cl))
470             return MR_PERM;
471         }
472
473       return MR_SUCCESS;
474     }
475 }
476
477
478 /* access_ahal - check for adding a host alias.
479  * successful if host has less then 2 aliases and (client is owner of
480  * host or subnet).
481  * If deleting an alias, any owner will do.
482  */
483
484 int access_ahal(struct query *q, char *argv[], client *cl)
485 {
486   EXEC SQL BEGIN DECLARE SECTION;
487   int cnt, id, mid, sid;
488   char mtype[MACHINE_OWNER_TYPE_SIZE], stype[SUBNET_OWNER_TYPE_SIZE];
489   EXEC SQL END DECLARE SECTION;
490   int status;
491
492   if (q->type == RETRIEVE)
493     return MR_SUCCESS;
494
495   id = *(int *)argv[1];
496
497   if (q->type == APPEND && isdigit(argv[0][0]))
498     return MR_BAD_CHAR;
499
500   EXEC SQL SELECT count(name) INTO :cnt from hostalias WHERE mach_id = :id;
501   if (dbms_errno)
502     return mr_errcode;
503   /* if the type is APPEND, this is ahal and we need to make sure there
504    * will be no more than 2 aliases.  If it's not, it must be dhal and
505    * any owner will do.
506    */
507   if (q->type == APPEND && cnt >= 2)
508     return MR_PERM;
509   EXEC SQL SELECT m.owner_type, m.owner_id, s.owner_type, s.owner_id
510     INTO :mtype, :mid, :stype, :sid FROM machine m, subnet s
511     WHERE m.mach_id = :id and s.snet_id = m.snet_id;
512   status = find_member(mtype, mid, cl);
513   if (status)
514     return MR_SUCCESS;
515   status = find_member(stype, sid, cl);
516   if (status)
517     return MR_SUCCESS;
518   else
519     return MR_PERM;
520 }
521
522
523 /* access_snt - check for retrieving network structure
524  */
525
526 int access_snt(struct query *q, char *argv[], client *cl)
527 {
528   if (q->type == RETRIEVE)
529     return MR_SUCCESS;
530
531   return MR_PERM;
532 }
533
534
535 /* access_printer */
536 int access_printer(struct query *q, char *argv[], client *cl)
537 {
538   EXEC SQL BEGIN DECLARE SECTION;
539   char type[PRINTSERVERS_OWNER_TYPE_SIZE];
540   int id, mach_id;
541   EXEC SQL END DECLARE SECTION;
542   int status;
543
544   mach_id = *(int *)argv[PRN_RM];
545   EXEC SQL SELECT owner_type, owner_id INTO :type, :id
546     FROM printservers WHERE mach_id = :mach_id;
547   if (sqlca.sqlcode)
548     return MR_PERM;
549
550   status = find_member(type, id, cl);
551   if (status)
552     return MR_SUCCESS;
553   else
554     return MR_PERM;
555 }
This page took 0.196167 seconds and 5 git commands to generate.