]> andersk Git - moira.git/blob - server/qaccess.pc
Goo for persistently disabling queues.
[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 #include <netdb.h>
18 #include <sys/types.h>
19 #include <netinet/in.h>
20 #include <arpa/nameser.h>
21
22 EXEC SQL INCLUDE sqlca;
23
24 RCSID("$Header$");
25
26 extern char *whoami;
27 extern int dbms_errno, mr_errcode;
28
29 EXEC SQL WHENEVER SQLERROR DO dbmserr();
30
31
32 /* Specialized Access Routines */
33
34 /* access_user - verify that client name equals specified login name
35  *
36  *  - since field validation routines are called first, a users_id is
37  *    now in argv[0] instead of the login name.
38  */
39
40 int access_user(struct query *q, char *argv[], client *cl)
41 {
42   if (cl->users_id != *(int *)argv[0])
43     return MR_PERM;
44   else
45     return MR_SUCCESS;
46 }
47
48 int access_update_user(struct query *q, char *argv[], client *cl)
49 {
50   EXEC SQL BEGIN DECLARE SECTION;
51   int users_id, unix_uid, status, comments, secure;
52   char login[USERS_LOGIN_SIZE], shell[USERS_SHELL_SIZE];
53   char winconsoleshell[USERS_WINCONSOLESHELL_SIZE], last[USERS_LAST_SIZE];
54   char first[USERS_FIRST_SIZE], middle[USERS_MIDDLE_SIZE];
55   char clearid[USERS_CLEARID_SIZE], type[USERS_TYPE_SIZE];
56   char signature[USERS_SIGNATURE_SIZE];
57   EXEC SQL END DECLARE SECTION;
58
59   /* The two fields we let users update themselves didn't appear until
60    * version 11.
61    */
62   if (q->version < 11)
63     return MR_PERM;
64
65   if (cl->users_id != *(int *)argv[0])
66     return MR_PERM;
67
68   users_id = *(int *)argv[0];
69
70   EXEC SQL SELECT u.login, u.unix_uid, u.shell, u.winconsoleshell, u.last,
71     u.first, u.middle, u.status, u.clearid, u.type, u.comments, u.signature,
72     u.secure INTO :login, :unix_uid, :shell, :winconsoleshell, :last, :first,
73     :middle, :status, :clearid, :type, :comments, :signature, :secure
74     FROM USERS u WHERE u.users_id = :users_id;
75
76   /* None of these things can have changed. */
77   if (strcmp(argv[1], strtrim(login)) ||
78       (unix_uid != atoi(argv[2])) ||
79       strcmp(argv[3], strtrim(shell)) ||
80       strcmp(argv[4], strtrim(winconsoleshell)) ||
81       strcmp(argv[5], strtrim(last)) ||
82       strcmp(argv[6], strtrim(first)) ||
83       strcmp(argv[7], strtrim(middle)) ||
84       (status != atoi(argv[8])) ||
85       strcmp(argv[9], strtrim(clearid)) ||
86       strcmp(argv[10], strtrim(type)) ||
87       (comments != *(int *)argv[11]) ||
88       strcmp(argv[12], strtrim(signature)) ||
89       (secure != atoi(argv[13])))
90     return MR_PERM;
91
92   return MR_SUCCESS;
93 }
94
95 /* access_login - verify that client name equals specified login name
96  *
97  *   argv[0...n] contain search info.  q->
98  */
99
100 int access_login(struct query *q, char *argv[], client *cl)
101 {
102   EXEC SQL BEGIN DECLARE SECTION;
103   int id;
104   EXEC SQL END DECLARE SECTION;
105
106   if (q->argc != 1)
107     return MR_ARGS;
108
109   if (!strcmp(q->shortname, "gual"))
110     {
111       EXEC SQL SELECT users_id INTO :id FROM users
112         WHERE login = :argv[0] AND users_id != 0;
113     }
114   else if (!strcmp(q->shortname, "gubl"))
115     {
116       EXEC SQL SELECT users_id INTO :id FROM users u
117         WHERE u.login = :argv[0] AND u.users_id != 0;
118     }
119   else if (!strcmp(q->shortname, "guau"))
120     {
121       EXEC SQL SELECT users_id INTO :id FROM users
122         WHERE unix_uid = :argv[0] AND users_id != 0;
123     }
124   else if (!strcmp(q->shortname, "gubu"))
125     {
126       EXEC SQL SELECT users_id INTO :id FROM users u
127         WHERE u.unix_uid = :argv[0] AND u.users_id != 0;
128     }
129
130   if (sqlca.sqlcode == SQL_NO_MATCH)
131     return MR_NO_MATCH; /* ought to be MR_USER, but this is what
132                            gual returns, so we have to be consistent */
133   else if (sqlca.sqlerrd[2] != 1 || id != cl->users_id)
134     return MR_PERM;
135   else
136     return MR_SUCCESS;
137 }
138
139
140 /* access_spob - check access for set_pobox */
141
142 int access_spob(struct query *q, char *argv[], client *cl)
143 {
144   EXEC SQL BEGIN DECLARE SECTION;
145   int id;
146   EXEC SQL END DECLARE SECTION;
147   int status;
148
149   if (!strcmp(argv[1], "IMAP"))
150     {
151       EXEC SQL SELECT owner INTO :id FROM filesys f 
152         WHERE f.label = :argv[2] AND f.type = 'IMAP' AND
153         f.lockertype = 'USER';
154       if (cl->users_id != id)
155         return MR_PERM;
156     }
157
158   /* Non-query owners can't forward mail to a POSTOFFICE or MAILHUB server,
159    * nor to a nonresolving domain.
160    */
161   if (!strcmp(argv[1], "SMTP") || !strcmp(argv[1], "SPLIT"))
162     {
163       status = check_mail_string(argv[2]);
164       if (status)
165         return status;
166     }
167   
168   if (cl->users_id != *(int *)argv[0])
169     return MR_PERM;
170   else
171     return MR_SUCCESS;
172 }
173
174
175 /* access_list - check access for most list operations
176  *
177  * Inputs: argv[0] - list_id
178  *          q - query name
179  *          argv[2] - member ID (only for queries "amtl" and  "dmfl")
180  *          argv[7] - group ID (only for query "ulis")
181  *          cl - client name
182  *
183  * - check that client is a member of the access control list
184  * - OR, if the query is add_member_to_list or delete_member_from_list
185  *      and the list is public, allow access if client = member
186  */
187
188 int access_list(struct query *q, char *argv[], client *cl)
189 {
190   EXEC SQL BEGIN DECLARE SECTION;
191   int list_id, acl_id, flags, gid, users_id, member_id, member_acl_id;
192   int memacl_id, mailman, mailman_id;
193   char acl_type[LIST_ACL_TYPE_SIZE], name[LIST_NAME_SIZE], *newname;
194   char member_acl_type[LIST_ACL_TYPE_SIZE], memacl_type[LIST_ACL_TYPE_SIZE];
195   EXEC SQL END DECLARE SECTION;
196   int status, cnt;
197   char *buf;
198
199   list_id = *(int *)argv[0];
200   member_id = *(int *)argv[2];
201   EXEC SQL SELECT acl_id, acl_type, memacl_id, memacl_type,
202     gid, publicflg, name, mailman, mailman_id
203     INTO :acl_id, :acl_type, :memacl_id, :memacl_type, 
204     :gid, :flags, :name, :mailman, :mailman_id
205     FROM list
206     WHERE list_id = :list_id;
207
208   if (sqlca.sqlerrd[2] != 1)
209     return MR_INTERNAL;
210
211   /* if update_list, don't allow them to change the GID or rename to a
212          username other than their own */
213   if (!strcmp("ulis", q->shortname))
214     {
215       if (!strcmp(argv[7], UNIQUE_GID))
216         {
217           if (gid != -1)
218             return MR_PERM;
219         }
220       else
221         {
222           if (gid != atoi(argv[7]))
223             return MR_PERM;
224         }
225
226       newname = argv[1];
227
228       /* Check that it doesn't conflict with the Grouper namespace. */
229       if (strlen(newname) > 4 && isdigit(newname[2]) && 
230           isdigit(newname[3]) && newname[4] == '-')
231         {
232           if (!strncasecmp(newname, "fa", 2) ||
233               !strncasecmp(newname, "sp", 2) ||
234               !strncasecmp(newname, "su", 2) ||
235               !strncasecmp(newname, "ja", 2))
236             return MR_RESERVED;
237         }
238       
239       /* Don't let anyone take owner-foo list names.  They interact 
240        * weirdly with the aliases automatically generated by 
241        * mailhub.gen.
242        */
243       if (!strncasecmp(newname, "owner-", 6))
244         return MR_RESERVED;
245       
246       EXEC SQL SELECT users_id INTO :users_id FROM users
247         WHERE login = :newname;
248       if ((sqlca.sqlcode != SQL_NO_MATCH) && strcmp(strtrim(name), newname) &&
249           (users_id != cl->users_id))
250         return MR_PERM;
251
252       /* For modern enough clients, don't allow ordinary users to toggle
253        * the mailman bit or change the server.
254        */
255       if (q->version >= 10)
256         {
257           if (mailman != atoi(argv[9]))
258             return MR_PERM;
259
260           if (mailman_id != *(int *)argv[10])
261             return MR_PERM;
262         }
263     }
264
265   /* Don't allow non-query owners to add STRINGs to lists if they end
266    * in a domain that's MIT.EDU or one of the hosts that provide the
267    * MAILHUB or POSTOFFICE services.
268    */
269   if (!strcmp(q->shortname, "amtl") || !strcmp(q->shortname, "atml"))
270     {
271       if (!strcmp("STRING", argv[1]))
272         {
273           buf = malloc(0);
274           status = id_to_name(*(int *)argv[2], STRINGS_TABLE, &buf);
275           if (status)
276             return status;
277
278           status = check_mail_string(buf);
279           free(buf);
280           if (status)
281             return status;
282         }
283     }
284
285   /* check for client in access control list and return success right 
286    * away if it's there. */
287   if (find_member(acl_type, acl_id, cl))
288     return MR_SUCCESS;
289
290   /* If not amtl, atml, or dmfl, we lose. */
291   if (strcmp(q->shortname, "amtl") && strcmp(q->shortname, "atml") &&
292       strcmp(q->shortname, "dmfl") && strcmp(q->shortname, "tmol"))
293     return MR_PERM;
294
295   if (find_member(memacl_type, memacl_id, cl))
296     return MR_SUCCESS;
297
298   if (flags || q->type == MR_Q_DELETE)
299     {
300       if (!strcmp("USER", argv[1]) && *(int *)argv[2] == cl->users_id)
301         return MR_SUCCESS;
302       if (!strcmp("KERBEROS", argv[1]) && *(int *)argv[2] == -cl->client_id)
303         return MR_SUCCESS;
304       if (!strcmp("LIST", argv[1]) && !strcmp("dmfl", q->shortname))
305         {
306           EXEC SQL SELECT acl_id, acl_type INTO :member_acl_id, 
307             :member_acl_type 
308             FROM list
309             WHERE list_id = :member_id; 
310           
311           if (find_member(member_acl_type, member_acl_id, cl))
312             return MR_SUCCESS;
313         }
314     }
315
316   /* Otherwise fail. */
317   return MR_PERM;
318 }
319
320
321 /* access_visible_list - allow access to list only if it is not hidden,
322  *      or if the client is on the ACL
323  *
324  * Inputs: argv[0] - list_id
325  *         cl - client identifier
326  */
327
328 int access_visible_list(struct query *q, char *argv[], client *cl)
329 {
330   EXEC SQL BEGIN DECLARE SECTION;
331   int list_id, acl_id, memacl_id, flags ;
332   char acl_type[LIST_ACL_TYPE_SIZE], memacl_type[LIST_ACL_TYPE_SIZE];
333   EXEC SQL END DECLARE SECTION;
334   int status;
335
336   list_id = *(int *)argv[0];
337   EXEC SQL SELECT hidden, acl_id, acl_type, memacl_id, memacl_type
338     INTO :flags, :acl_id, :acl_type, :memacl_id, :memacl_type
339     FROM list
340     WHERE list_id = :list_id;
341   if (sqlca.sqlerrd[2] != 1)
342     return MR_INTERNAL;
343   if (!flags)
344     return MR_SUCCESS;
345
346   /* check for client in access control list */
347   status = find_member(acl_type, acl_id, cl);
348   if (!status)
349     {
350       status = find_member(memacl_type, memacl_id, cl);
351       if (!status)
352         return MR_PERM;
353     }
354   return MR_SUCCESS;
355 }
356
357
358 /* access_vis_list_by_name - allow access to list only if it is not hidden,
359  *      or if the client is on the ACL
360  *
361  * Inputs: argv[0] - list name
362  *         cl - client identifier
363  */
364
365 int access_vis_list_by_name(struct query *q, char *argv[], client *cl)
366 {
367   EXEC SQL BEGIN DECLARE SECTION;
368   int acl_id, memacl_id, flags, rowcount, list_id;
369   char acl_type[LIST_ACL_TYPE_SIZE], memacl_type[LIST_ACL_TYPE_SIZE];
370   char *listname;
371   EXEC SQL END DECLARE SECTION;
372   int status;
373
374   listname = argv[0];
375   EXEC SQL SELECT hidden, acl_id, acl_type, memacl_id, memacl_type, list_id 
376     INTO :flags, :acl_id, :acl_type, :memacl_id, :memacl_type, :list_id
377     FROM list 
378     WHERE name = :listname;
379
380   rowcount = sqlca.sqlerrd[2];
381   if (rowcount > 1)
382     return MR_WILDCARD;
383   if (rowcount == 0)
384     return MR_NO_MATCH;
385   if (!flags)
386     return MR_SUCCESS;
387
388   /* If the user is a member of the acl, memacl, or the list itself,
389    * accept them.
390    */
391   status = find_member(acl_type, acl_id, cl);
392   if (!status)
393     status = find_member(memacl_type, memacl_id, cl);
394   if (!status)
395     status = find_member("LIST", list_id, cl);
396   if (!status)
397     return MR_PERM;
398
399   return MR_SUCCESS;
400 }
401
402
403 /* access_member - allow user to access member of type "USER" and name matches
404  * username, or to access member of type "KERBEROS" and the principal matches
405  * the user, or to access member of type "LIST" and list is one that user is
406  * on the acl of, or the list is visible.  Allow anyone to look up list
407  * memberships of MACHINEs.
408  */
409
410 int access_member(struct query *q, char *argv[], client *cl)
411 {
412   if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
413     return access_visible_list(q, &argv[1], cl);
414
415   if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER"))
416     {
417       if (cl->users_id == *(int *)argv[1])
418         return MR_SUCCESS;
419     }
420
421   if (!strcmp(argv[0], "KERBEROS") || !strcmp(argv[0], "RKERBEROS"))
422     {
423       if (cl->client_id == -*(int *)argv[1])
424         return MR_SUCCESS;
425     }
426
427   if (!strcmp(argv[0], "MACHINE") || !strcmp(argv[0], "RMACHINE"))
428     return MR_SUCCESS;   
429
430   return MR_PERM;
431 }
432
433
434 /* access_qgli - special access routine for Qualified_get_lists.  Allows
435  * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
436  */
437
438 int access_qgli(struct query *q, char *argv[], client *cl)
439 {
440   if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
441     return MR_SUCCESS;
442   return MR_PERM;
443 }
444
445
446 /* access_service - allow access if user is on ACL of service.  Don't
447  * allow access if a wildcard is used.
448  */
449
450 int access_service(struct query *q, char *argv[], client *cl)
451 {
452   EXEC SQL BEGIN DECLARE SECTION;
453   int acl_id;
454   char *name, acl_type[LIST_ACL_TYPE_SIZE];
455   EXEC SQL END DECLARE SECTION;
456   int status;
457   char *c;
458
459   name = argv[0];
460   for (c = name; *c; c++)
461     {
462       if (islower(*c))
463         *c = toupper(*c);
464     }
465   EXEC SQL SELECT acl_id, acl_type INTO :acl_id, :acl_type FROM servers
466     WHERE name = :name;
467   if (sqlca.sqlerrd[2] > 1)
468     return MR_PERM;
469
470   /* check for client in access control list */
471   status = find_member(acl_type, acl_id, cl);
472   if (!status)
473     return MR_PERM;
474
475   return MR_SUCCESS;
476 }
477
478
479 /* access_filesys - verify that client is owner or on owners list of filesystem
480  *      named by argv[0]
481  */
482
483 int access_filesys(struct query *q, char *argv[], client *cl)
484 {
485   EXEC SQL BEGIN DECLARE SECTION;
486   int users_id, list_id;
487   char *name;
488   EXEC SQL END DECLARE SECTION;
489   int status;
490
491   name = argv[0];
492   EXEC SQL SELECT owner, owners INTO :users_id, :list_id FROM filesys
493     WHERE label = :name;
494
495   if (sqlca.sqlerrd[2] != 1)
496     return MR_PERM;
497   if (users_id == cl->users_id)
498     return MR_SUCCESS;
499   status = find_member("LIST", list_id, cl);
500   if (status)
501     return MR_SUCCESS;
502   else
503     return MR_PERM;
504 }
505
506
507 /* access_host - successful if owner of host, or subnet containing host
508  */
509
510 int access_host(struct query *q, char *argv[], client *cl)
511 {
512   EXEC SQL BEGIN DECLARE SECTION;
513   int mid, sid, id, subnet_status;
514   char mtype[MACHINE_OWNER_TYPE_SIZE], stype[SUBNET_OWNER_TYPE_SIZE];
515   char *account_number;
516   EXEC SQL END DECLARE SECTION;
517   int status, idx;
518
519   if (q->version < 6)
520     idx = 0;
521   else if (q->version >= 6 && q->version < 8)
522     idx = 1;
523   else
524     idx = 2;
525   
526   if (q->type == MR_Q_APPEND)
527     {
528       /* Non-query owner must set use to zero */
529       if (atoi(argv[6 + idx]) != 0)
530         return MR_PERM;
531
532       /* ... and start the hostname with a letter */
533       if (isdigit(argv[0][0]))
534         return MR_BAD_CHAR;
535
536       id = *(int *)argv[8 + idx];
537       EXEC SQL SELECT s.owner_type, s.owner_id, s.status
538         INTO :stype, :sid, :subnet_status FROM subnet s
539         WHERE s.snet_id = :id;
540       mid = 0;
541
542       /* Non query owner must provide valid billing information. */
543       if (q->version >= 8)
544         {
545           if (subnet_status == SNET_STATUS_BILLABLE)
546             {
547               account_number = argv[7];
548               EXEC SQL SELECT account_number FROM accountnumbers 
549                 WHERE account_number = :account_number;
550               if (sqlca.sqlcode == SQL_NO_MATCH)
551                 return MR_ACCOUNT_NUMBER;
552             }
553         }
554
555       if (find_member(stype, sid, cl))
556         return MR_SUCCESS;
557       else
558         return MR_PERM;
559     }
560   else /* q-type == MR_Q_UPDATE */
561     {
562       EXEC SQL BEGIN DECLARE SECTION;
563       int status, acomment, use, ocomment, snid;
564       char contact[MACHINE_CONTACT_SIZE], address[MACHINE_ADDRESS_SIZE];
565       char name[MACHINE_NAME_SIZE];
566       char billing_contact[MACHINE_BILLING_CONTACT_SIZE];
567       EXEC SQL END DECLARE SECTION;
568
569       id = *(int *)argv[0];
570       EXEC SQL SELECT m.name, m.use, m.contact, m.billing_contact, m.status, 
571         m.address, m.owner_type, m.owner_id, m.acomment, m.ocomment, m.snet_id,
572         s.owner_type, s.owner_id, s.status INTO :name, :use, :contact, 
573         :billing_contact, :status, :address, :mtype, :mid, :acomment, 
574         :ocomment, :snid, :stype, :sid, :subnet_status
575         FROM machine m, subnet s
576         WHERE m.mach_id = :id AND s.snet_id = m.snet_id;
577       if (dbms_errno)
578         return mr_errcode;
579
580       /* Non query owner must provide valid billing information. */
581       if (q->version >= 8)
582         {
583           if ((subnet_status == SNET_STATUS_BILLABLE) &&
584               (atoi(argv[10]) != 3))
585             {
586               account_number = argv[8];
587               EXEC SQL SELECT account_number FROM accountnumbers 
588                 WHERE account_number = :account_number;
589               if (sqlca.sqlcode == SQL_NO_MATCH)
590                 return MR_ACCOUNT_NUMBER;
591             }
592         }
593
594       /* non-query-owner cannot change use or ocomment */
595       if ((use != atoi(argv[7 + idx])) || (ocomment != *(int *)argv[14 + idx]))
596         return MR_PERM;
597
598       /* or rename to start with digit */
599       if (isdigit(argv[1][0]) && strcmp(strtrim(name), argv[1]))
600         return MR_BAD_CHAR;
601
602       if (!find_member(stype, sid, cl))
603         {
604           if (find_member(mtype, mid, cl))
605             {
606               /* host owner also cannot change contact, status, address,
607                  owner, or acomment */
608               if (strcmp(argv[6], strtrim(contact)) ||
609                   (status != atoi(argv[8 + idx])) ||
610                   strcmp(argv[10 + idx], strtrim(address)) ||
611                   strcmp(argv[11 + idx], strtrim(mtype)) ||
612                   (mid != *(int *)argv[12 + idx]) || 
613                   (acomment != *(int *)argv[13 + idx]))
614                 return MR_PERM;
615               /* Billing contact field didn't appear until version 6 */
616               if (q->version >= 6)
617                 if (strcmp(argv[7], strtrim(billing_contact)))
618                     return MR_PERM;
619             }
620           else
621             return MR_PERM;
622         }
623
624       /* If moving to a new subnet, make sure user is on acl there */
625       id = *(int *)argv[9 + idx];
626       if (id != snid)
627         {
628           EXEC SQL SELECT owner_type, owner_id INTO :stype, :sid
629             FROM subnet WHERE snet_id=:id;
630           if (!find_member(stype, sid, cl))
631             return MR_PERM;
632         }
633
634       return MR_SUCCESS;
635     }
636 }
637
638
639 /* access_ahal - check for adding a host alias.
640  * successful if host has less then 2 aliases and (client is owner of
641  * host or subnet).
642  * If deleting an alias, any owner will do.
643  */
644
645 int access_ahal(struct query *q, char *argv[], client *cl)
646 {
647   EXEC SQL BEGIN DECLARE SECTION;
648   int cnt, id, mid, sid;
649   char mtype[MACHINE_OWNER_TYPE_SIZE], stype[SUBNET_OWNER_TYPE_SIZE];
650   EXEC SQL END DECLARE SECTION;
651   int status;
652
653   if (q->type == MR_Q_RETRIEVE)
654     return MR_SUCCESS;
655
656   id = *(int *)argv[1];
657
658   if (q->type == MR_Q_APPEND && isdigit(argv[0][0]))
659     return MR_BAD_CHAR;
660
661   EXEC SQL SELECT count(name) INTO :cnt from hostalias WHERE mach_id = :id;
662   if (dbms_errno)
663     return mr_errcode;
664   /* if the type is MR_Q_APPEND, this is ahal and we need to make sure there
665    * will be no more than 2 aliases.  If it's not, it must be dhal and
666    * any owner will do.
667    */
668   if (q->type == MR_Q_APPEND && cnt >= 2)
669     return MR_PERM;
670   EXEC SQL SELECT m.owner_type, m.owner_id, s.owner_type, s.owner_id
671     INTO :mtype, :mid, :stype, :sid FROM machine m, subnet s
672     WHERE m.mach_id = :id and s.snet_id = m.snet_id;
673   status = find_member(mtype, mid, cl);
674   if (status)
675     return MR_SUCCESS;
676   status = find_member(stype, sid, cl);
677   if (status)
678     return MR_SUCCESS;
679   else
680     return MR_PERM;
681 }
682
683
684 /* access_snt - check for retrieving network structure
685  */
686
687 int access_snt(struct query *q, char *argv[], client *cl)
688 {
689   if (q->type == MR_Q_RETRIEVE)
690     return MR_SUCCESS;
691
692   return MR_PERM;
693 }
694
695
696 /* access_printer */
697 int access_printer(struct query *q, char *argv[], client *cl)
698 {
699   EXEC SQL BEGIN DECLARE SECTION;
700   char type[PRINTSERVERS_OWNER_TYPE_SIZE];
701   int id, mach_id;
702   EXEC SQL END DECLARE SECTION;
703   int status;
704
705   mach_id = *(int *)argv[PRN_RM];
706   EXEC SQL SELECT owner_type, owner_id INTO :type, :id
707     FROM printservers WHERE mach_id = :mach_id;
708   if (sqlca.sqlcode)
709     return MR_PERM;
710
711   status = find_member(type, id, cl);
712   if (status)
713     return MR_SUCCESS;
714   else
715     return MR_PERM;
716 }
717
718 /* access_zephyr */
719 int access_zephyr(struct query *q, char *argv[], client *cl)
720 {
721   EXEC SQL BEGIN DECLARE SECTION;
722   char type[ZEPHYR_OWNER_TYPE_SIZE];
723   char *class;
724   int id;
725   EXEC SQL END DECLARE SECTION;
726   int status;
727
728   class = argv[ZA_CLASS];
729   EXEC SQL SELECT owner_type, owner_id INTO :type, :id
730       FROM zephyr WHERE class = :class;
731   if (sqlca.sqlcode)
732     return MR_PERM;
733
734   status = find_member(type, id, cl);
735   if (status)
736     return MR_SUCCESS;
737   else
738     return MR_PERM;
739 }
740
741 /* access_container - check access for most container operations
742  *
743  * Inputs: argv[0] - cnt_id
744  *          q - query name        
745  *          cl - client name
746  *
747  * - check if that client is a member of the access control list
748  * - OR, if the query is add_machine_to_container or delete_machine_from_container
749  *      check if the client is a memeber of the mem_acl list
750  * - if the query is update_container and the container is to be renamed and
751  *   it is a top-level container, only priviledged users can do it
752  */
753
754 int access_container(struct query *q, char *argv[], client *cl)
755 {
756   EXEC SQL BEGIN DECLARE SECTION;
757   int cnt_id, acl_id, memacl_id, mach_id, machine_owner_id, flag;
758   char acl_type[CONTAINERS_ACL_TYPE_SIZE], memacl_type[CONTAINERS_ACL_TYPE_SIZE];
759   char name[CONTAINERS_NAME_SIZE], *newname;
760   char machine_owner_type[MACHINE_OWNER_TYPE_SIZE];
761   EXEC SQL END DECLARE SECTION;
762   int status;
763
764   cnt_id = *(int *)argv[0];
765   
766   /* if amcn or dmcn, container id is the second argument */
767   if (strcmp(q->shortname, "amcn") == 0 || strcmp(q->shortname, "dmcn") == 0)
768   {
769         mach_id = *(int *)argv[0];
770         cnt_id = *(int *)argv[1];
771   }
772
773   EXEC SQL SELECT acl_id, acl_type, memacl_id, memacl_type, name, publicflg
774     INTO :acl_id, :acl_type, :memacl_id, :memacl_type, :name, :flag
775     FROM containers
776     WHERE cnt_id = :cnt_id;
777
778   if (sqlca.sqlerrd[2] != 1)
779     return MR_INTERNAL;
780
781    /* trim off the trailing spaces */
782    strcpy(name, strtrim(name));
783
784   /* Only dbadmin can rename containers. */
785   if (!strcmp(q->shortname, "ucon"))
786   {
787     newname = argv[1];
788     if (strcmp(name, newname))
789       return MR_PERM;
790   }
791
792   /* check for client in access control list and return success right 
793    * away if it's there. */
794   if (find_member(acl_type, acl_id, cl))
795     return MR_SUCCESS;
796
797   /* If not amcn, dmcn, we lose. */
798   if (strcmp(q->shortname, "amcn") && strcmp(q->shortname, "dmcn"))
799     return MR_PERM;
800
801   if (find_member(memacl_type, memacl_id, cl))
802     return MR_SUCCESS;
803
804   /* if the container is public or the query is delete, grant access if client
805    * is on owner list */
806   if (flag || q->type == MR_Q_DELETE)
807     {
808           EXEC SQL SELECT owner_type, owner_id INTO :machine_owner_type,
809             :machine_owner_id
810             FROM machine
811             WHERE mach_id = :mach_id;
812
813           if (sqlca.sqlerrd[2] == 1 && strcmp("NONE", machine_owner_type) &&
814                 find_member(machine_owner_type, machine_owner_id, cl))
815             return MR_SUCCESS;
816     }
817   /* Otherwise fail. */
818   return MR_PERM;
819 }
820
821 int check_mail_string(char *mailstring)
822 {
823   EXEC SQL BEGIN DECLARE SECTION;
824   char mname[MACHINE_NAME_SIZE];
825   EXEC SQL END DECLARE SECTION;
826   char *p, *host, *hostdomain;
827   struct hostent *hp;
828   struct mxentry *mxrecords = NULL;
829   int index;
830
831   p = strchr(mailstring, '@');
832   if (p)
833     {
834       host = strdup(++p);
835       
836       /* Replace .LOCAL at end of host with .MIT.EDU if needed. */
837       hostdomain = strrchr(host, '.');
838       if (hostdomain && !strcasecmp(hostdomain, ".LOCAL"))
839         {
840           index = hostdomain - host;
841           host[index] = '\0';
842           host = realloc(host, strlen(host) + strlen(".MIT.EDU") + 1);
843           strcat(host, ".MIT.EDU");
844         }
845       
846       hp = gethostbyname(host);
847       if (hp)
848         {
849           host = realloc(host, strlen(hp->h_name) + 1);
850           if (host)
851             strcpy(host, hp->h_name);
852         }
853       else
854         {
855           /* Possibly a host with no A record but MX records.  Check. */
856           mxrecords = getmxrecords(host);
857           if (!mxrecords)
858             return MR_BAD_MAIL_STRING;
859           else
860             return MR_SUCCESS;
861         }
862       
863       if (!strcasecmp(host, "MIT.EDU"))
864         {
865           free(host);
866           return MR_BAD_MAIL_STRING;
867         }
868       
869       EXEC SQL DECLARE csr_listmem CURSOR FOR
870         SELECT UNIQUE m.name FROM machine m, serverhosts sh
871         WHERE m.mach_id = sh.mach_id
872         AND (sh.service = 'MAILHUB' or sh.service = 'POSTOFFICE');
873       if (dbms_errno)
874         {
875           free(host);
876           return mr_errcode;
877         }
878       EXEC SQL OPEN csr_listmem;
879       if (dbms_errno)
880         {
881           free(host);
882           return mr_errcode;
883         }
884       while (1)
885         {
886           EXEC SQL FETCH csr_listmem INTO :mname;
887           if (sqlca.sqlcode)
888             break;
889           
890           if (!strcasecmp(host, strtrim(mname)))
891             {
892               free(host);
893               return MR_BAD_MAIL_STRING;
894             }
895         }
896       free(host);
897     }
898
899   return MR_SUCCESS;
900 }
901
902 /*
903  * This ought to be in the bind library.  It's adapted from sendmail.
904  */
905
906 /*
907  * These are defined in RFC833. Some bind interface headers don't declare them.
908  * Ghod help us if they're ever actually incompatible with what's in 
909  * the arpa/nameser.h header.
910  */
911 #ifndef PACKETSZ
912 #define PACKETSZ        512             /* maximum packet size */
913 #endif
914 #ifndef HFIXEDSZ
915 #define HFIXEDSZ        12              /* #/bytes of fixed data in header */
916 #endif
917 #ifndef INT32SZ
918 #define INT32SZ         4               /* for systems without 32-bit ints */
919 #endif
920 #ifndef INT16SZ
921 #define INT16SZ         2               /* for systems without 16-bit ints */
922 #endif
923
924 /* minimum possible size of MX record in packet */
925 #define MIN_MX_SIZE     8       /* corresp to "a.com 0" w/ terminating space */
926
927 struct mxentry *getmxrecords(const char *name)
928 {
929   char answer[PACKETSZ], *eom, *cp, *bp;
930   int n, ancount, qdcount, buflen, type, pref, ind;
931   static struct mxentry pmx[(PACKETSZ - HFIXEDSZ) / MIN_MX_SIZE];
932   static char MXHostBuf[PACKETSZ - HFIXEDSZ]; 
933   HEADER *hp;
934   
935   pmx->name = (char *)NULL;
936   pmx->pref = -1;
937   n = res_search(name, C_IN,T_MX, (unsigned char *)&answer, sizeof(answer));
938   if (n == -1)
939     return((struct mxentry *)NULL);
940   if ((size_t)n > sizeof(answer))
941     n = sizeof(answer);         
942   
943   hp = (HEADER *)&answer;
944   cp = answer + HFIXEDSZ;
945   eom = answer + n;
946   h_errno = 0;
947   for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
948     if ((n = dn_skipname((unsigned char *)cp, (unsigned char *)eom)) < 0)
949       return((struct mxentry *)NULL);
950   buflen = sizeof(MXHostBuf) - 1;
951   bp = MXHostBuf;
952   ind = 0;
953   ancount = ntohs(hp->ancount);
954   while (--ancount >= 0 && cp < eom)
955     {
956       if ((n = dn_expand((unsigned char *)answer, (unsigned char *)eom,
957                          (unsigned char *)cp, bp, buflen)) < 0)
958         break;
959       cp += n;
960       GETSHORT(type, cp);
961       cp += INT16SZ + INT32SZ;
962       GETSHORT(n, cp);
963       if (type != T_MX)
964         {
965           cp += n;
966           continue;
967         }
968       GETSHORT(pref, cp);
969       if ((n = dn_expand((unsigned char *)answer, (unsigned char *)eom,
970                          (unsigned char *)cp, bp, buflen)) < 0)
971         break;
972       cp += n;
973       
974       pmx[ind].name = bp;
975       pmx[ind].pref = pref;
976       ++ind;
977       
978       n = strlen((const char *)bp);
979       bp += n;
980       *bp++ = '\0';
981       
982       buflen -= n + 1;
983     }
984   
985   pmx[ind].name = (char *)NULL;
986   pmx[ind].pref = -1;
987   return(pmx);
988 }
This page took 0.725579 seconds and 5 git commands to generate.