source: trunk/third/moira/server/qaccess.pc @ 24250

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