3 * Check access to queries
5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
10 #include <mit-copyright.h>
11 #include "mr_server.h"
18 EXEC SQL INCLUDE sqlca;
23 extern int dbms_errno, mr_errcode;
25 EXEC SQL WHENEVER SQLERROR DO dbmserr();
28 /* Specialized Access Routines */
30 /* access_user - verify that client name equals specified login name
32 * - since field validation routines are called first, a users_id is
33 * now in argv[0] instead of the login name.
36 int access_user(struct query *q, char *argv[], client *cl)
38 if (cl->users_id != *(int *)argv[0])
46 /* access_login - verify that client name equals specified login name
48 * argv[0...n] contain search info. q->
51 int access_login(struct query *q, char *argv[], client *cl)
53 EXEC SQL BEGIN DECLARE SECTION;
55 EXEC SQL END DECLARE SECTION;
60 if (!strcmp(q->shortname, "gual"))
62 EXEC SQL SELECT users_id INTO :id FROM users
63 WHERE login = :argv[0] AND users_id != 0;
65 else if (!strcmp(q->shortname, "gubl"))
67 EXEC SQL SELECT users_id INTO :id FROM users u
68 WHERE u.login = :argv[0] AND u.users_id != 0;
70 else if (!strcmp(q->shortname, "guau"))
72 EXEC SQL SELECT users_id INTO :id FROM users
73 WHERE unix_uid = :argv[0] AND users_id != 0;
75 else if (!strcmp(q->shortname, "gubu"))
77 EXEC SQL SELECT users_id INTO :id FROM users u
78 WHERE u.unix_uid = :argv[0] AND u.users_id != 0;
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)
91 /* access_spob - check access for set_pobox */
93 int access_spob(struct query *q, char *argv[], client *cl)
95 EXEC SQL BEGIN DECLARE SECTION;
97 EXEC SQL END DECLARE SECTION;
99 if (!strcmp(argv[1], "IMAP"))
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)
107 if (cl->users_id != *(int *)argv[0])
114 /* access_list - check access for most list operations
116 * Inputs: argv[0] - list_id
118 * argv[2] - member ID (only for queries "amtl" and "dmfl")
119 * argv[7] - group ID (only for query "ulis")
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
127 int access_list(struct query *q, char *argv[], client *cl)
129 EXEC SQL BEGIN DECLARE SECTION;
130 int list_id, acl_id, flags, gid, users_id, member_id, member_acl_id;
132 char acl_type[LIST_ACL_TYPE_SIZE], name[LIST_NAME_SIZE], *newname;
133 char member_acl_type[LIST_ACL_TYPE_SIZE], memacl_type[LIST_ACL_TYPE_SIZE];
134 EXEC SQL END DECLARE SECTION;
137 list_id = *(int *)argv[0];
138 member_id = *(int *)argv[2];
139 EXEC SQL SELECT acl_id, acl_type, memacl_id, memacl_type,
141 INTO :acl_id, :acl_type, :memacl_id, :memacl_type,
144 WHERE list_id = :list_id;
146 if (sqlca.sqlerrd[2] != 1)
149 /* if update_list, don't allow them to change the GID or rename to a
150 username other than their own */
151 if (!strcmp("ulis", q->shortname))
153 if (!strcmp(argv[7], UNIQUE_GID))
160 if (gid != atoi(argv[7]))
166 if (!strcmp("ulis", q->shortname))
168 /* Check that it doesn't conflict with the Grouper namespace. */
169 if (strlen(newname) > 4 && isdigit(newname[2]) &&
170 isdigit(newname[3]) && newname[4] == '-')
172 if (!strncasecmp(newname, "fa", 2) ||
173 !strncasecmp(newname, "sp", 2) ||
174 !strncasecmp(newname, "su", 2) ||
175 !strncasecmp(newname, "ja", 2))
179 /* Don't let anyone take owner-foo list names. They interact
180 * weirdly with the aliases automatically generated by
183 if (!strncasecmp(newname, "owner-", 6))
187 EXEC SQL SELECT users_id INTO :users_id FROM users
188 WHERE login = :newname;
189 if ((sqlca.sqlcode != SQL_NO_MATCH) && strcmp(strtrim(name), newname) &&
190 (users_id != cl->users_id))
194 /* check for client in access control list and return success right
195 * away if it's there. */
196 if (find_member(acl_type, acl_id, cl))
199 /* If not amtl, atml, or dmfl, we lose. */
200 if (strcmp(q->shortname, "amtl") && strcmp(q->shortname, "atml") &&
201 strcmp(q->shortname, "dmfl") && strcmp(q->shortname, "tmol"))
204 if (find_member(memacl_type, memacl_id, cl))
207 if (flags || q->type == DELETE)
209 if (!strcmp("USER", argv[1]) && *(int *)argv[2] == cl->users_id)
211 if (!strcmp("KERBEROS", argv[1]) && *(int *)argv[2] == -cl->client_id)
213 if (!strcmp("LIST", argv[1]) && !strcmp("dmfl", q->shortname))
215 EXEC SQL SELECT acl_id, acl_type INTO :member_acl_id,
218 WHERE list_id = :member_id;
220 if (find_member(member_acl_type, member_acl_id, cl))
225 /* Otherwise fail. */
230 /* access_visible_list - allow access to list only if it is not hidden,
231 * or if the client is on the ACL
233 * Inputs: argv[0] - list_id
234 * cl - client identifier
237 int access_visible_list(struct query *q, char *argv[], client *cl)
239 EXEC SQL BEGIN DECLARE SECTION;
240 int list_id, acl_id, memacl_id, flags ;
241 char acl_type[LIST_ACL_TYPE_SIZE], memacl_type[LIST_ACL_TYPE_SIZE];
242 EXEC SQL END DECLARE SECTION;
245 list_id = *(int *)argv[0];
246 EXEC SQL SELECT hidden, acl_id, acl_type, memacl_id, memacl_type
247 INTO :flags, :acl_id, :acl_type, :memacl_id, :memacl_type
249 WHERE list_id = :list_id;
250 if (sqlca.sqlerrd[2] != 1)
255 /* check for client in access control list */
256 status = find_member(acl_type, acl_id, cl);
259 status = find_member(memacl_type, memacl_id, cl);
267 /* access_vis_list_by_name - allow access to list only if it is not hidden,
268 * or if the client is on the ACL
270 * Inputs: argv[0] - list name
271 * cl - client identifier
274 int access_vis_list_by_name(struct query *q, char *argv[], client *cl)
276 EXEC SQL BEGIN DECLARE SECTION;
277 int acl_id, memacl_id, flags, rowcount, list_id;
278 char acl_type[LIST_ACL_TYPE_SIZE], memacl_type[LIST_ACL_TYPE_SIZE];
280 EXEC SQL END DECLARE SECTION;
284 EXEC SQL SELECT hidden, acl_id, acl_type, memacl_id, memacl_type, list_id
285 INTO :flags, :acl_id, :acl_type, :memacl_id, :memacl_type, :list_id
287 WHERE name = :listname;
289 rowcount = sqlca.sqlerrd[2];
297 /* If the user is a member of the acl, memacl, or the list itself,
300 status = find_member(acl_type, acl_id, cl);
302 status = find_member(memacl_type, memacl_id, cl);
304 status = find_member("LIST", list_id, cl);
312 /* access_member - allow user to access member of type "USER" and name matches
313 * username, or to access member of type "KERBEROS" and the principal matches
314 * the user, or to access member of type "LIST" and list is one that user is
315 * on the acl of, or the list is visible. Allow anyone to look up list
316 * memberships of MACHINEs.
319 int access_member(struct query *q, char *argv[], client *cl)
321 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
322 return access_visible_list(q, &argv[1], cl);
324 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER"))
326 if (cl->users_id == *(int *)argv[1])
330 if (!strcmp(argv[0], "KERBEROS") || !strcmp(argv[0], "RKERBEROS"))
332 if (cl->client_id == -*(int *)argv[1])
336 if (!strcmp(argv[0], "MACHINE") || !strcmp(argv[0], "RMACHINE"))
343 /* access_qgli - special access routine for Qualified_get_lists. Allows
344 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
347 int access_qgli(struct query *q, char *argv[], client *cl)
349 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
355 /* access_service - allow access if user is on ACL of service. Don't
356 * allow access if a wildcard is used.
359 int access_service(struct query *q, char *argv[], client *cl)
361 EXEC SQL BEGIN DECLARE SECTION;
363 char *name, acl_type[LIST_ACL_TYPE_SIZE];
364 EXEC SQL END DECLARE SECTION;
369 for (c = name; *c; c++)
374 EXEC SQL SELECT acl_id, acl_type INTO :acl_id, :acl_type FROM servers
376 if (sqlca.sqlerrd[2] > 1)
379 /* check for client in access control list */
380 status = find_member(acl_type, acl_id, cl);
388 /* access_filesys - verify that client is owner or on owners list of filesystem
392 int access_filesys(struct query *q, char *argv[], client *cl)
394 EXEC SQL BEGIN DECLARE SECTION;
395 int users_id, list_id;
397 EXEC SQL END DECLARE SECTION;
401 EXEC SQL SELECT owner, owners INTO :users_id, :list_id FROM filesys
404 if (sqlca.sqlerrd[2] != 1)
406 if (users_id == cl->users_id)
408 status = find_member("LIST", list_id, cl);
416 /* access_host - successful if owner of host, or subnet containing host
419 int access_host(struct query *q, char *argv[], client *cl)
421 EXEC SQL BEGIN DECLARE SECTION;
422 int mid, sid, id, subnet_status;
423 char mtype[MACHINE_OWNER_TYPE_SIZE], stype[SUBNET_OWNER_TYPE_SIZE];
424 char *account_number;
425 EXEC SQL END DECLARE SECTION;
430 else if (q->version >= 6 && q->version < 8)
435 if (q->type == RETRIEVE)
437 if (strcmp(argv[0], "*") || strcmp(argv[1], "*") ||
438 strcmp(argv[2], "*") || strcmp(argv[3], "*"))
444 if (q->type == APPEND)
446 /* Non-query owner must set use to zero */
447 if (atoi(argv[6 + idx]) != 0)
450 /* ... and start the hostname with a letter */
451 if (isdigit(argv[0][0]))
454 id = *(int *)argv[8 + idx];
455 EXEC SQL SELECT s.owner_type, s.owner_id, s.status
456 INTO :stype, :sid, :subnet_status FROM subnet s
457 WHERE s.snet_id = :id;
460 /* Non query owner must provide valid billing information. */
463 if (subnet_status == SNET_STATUS_BILLABLE)
465 account_number = argv[7];
466 EXEC SQL SELECT account_number FROM accountnumbers
467 WHERE account_number = :account_number;
468 if (sqlca.sqlcode == SQL_NO_MATCH)
469 return MR_ACCOUNT_NUMBER;
473 if (find_member(stype, sid, cl))
478 else /* q-type == UPDATE */
480 EXEC SQL BEGIN DECLARE SECTION;
481 int status, acomment, use, ocomment, snid;
482 char contact[MACHINE_CONTACT_SIZE], address[MACHINE_ADDRESS_SIZE];
483 char name[MACHINE_NAME_SIZE];
484 char billing_contact[MACHINE_BILLING_CONTACT_SIZE];
485 EXEC SQL END DECLARE SECTION;
487 id = *(int *)argv[0];
488 EXEC SQL SELECT m.name, m.use, m.contact, m.billing_contact, m.status,
489 m.address, m.owner_type, m.owner_id, m.acomment, m.ocomment, m.snet_id,
490 s.owner_type, s.owner_id, s.status INTO :name, :use, :contact,
491 :billing_contact, :status, :address, :mtype, :mid, :acomment,
492 :ocomment, :snid, :stype, :sid, :subnet_status
493 FROM machine m, subnet s
494 WHERE m.mach_id = :id AND s.snet_id = m.snet_id;
498 /* Non query owner must provide valid billing information. */
501 if ((subnet_status == SNET_STATUS_BILLABLE) &&
502 (atoi(argv[10]) != 3))
504 account_number = argv[8];
505 EXEC SQL SELECT account_number FROM accountnumbers
506 WHERE account_number = :account_number;
507 if (sqlca.sqlcode == SQL_NO_MATCH)
508 return MR_ACCOUNT_NUMBER;
512 /* non-query-owner cannot change use or ocomment */
513 if ((use != atoi(argv[7 + idx])) || (ocomment != *(int *)argv[14 + idx]))
516 /* or rename to start with digit */
517 if (isdigit(argv[1][0]) && strcmp(strtrim(name), argv[1]))
520 if (!find_member(stype, sid, cl))
522 if (find_member(mtype, mid, cl))
524 /* host owner also cannot change contact, status, address,
525 owner, or acomment */
526 if (strcmp(argv[6], strtrim(contact)) ||
527 (status != atoi(argv[8 + idx])) ||
528 strcmp(argv[10 + idx], strtrim(address)) ||
529 strcmp(argv[11 + idx], strtrim(mtype)) ||
530 (mid != *(int *)argv[12 + idx]) ||
531 (acomment != *(int *)argv[13 + idx]))
533 /* Billing contact field didn't appear until version 6 */
535 if (strcmp(argv[7], strtrim(billing_contact)))
542 /* If moving to a new subnet, make sure user is on acl there */
543 id = *(int *)argv[9 + idx];
546 EXEC SQL SELECT owner_type, owner_id INTO :stype, :sid
547 FROM subnet WHERE snet_id=:id;
548 if (!find_member(stype, sid, cl))
557 /* access_ahal - check for adding a host alias.
558 * successful if host has less then 2 aliases and (client is owner of
560 * If deleting an alias, any owner will do.
563 int access_ahal(struct query *q, char *argv[], client *cl)
565 EXEC SQL BEGIN DECLARE SECTION;
566 int cnt, id, mid, sid;
567 char mtype[MACHINE_OWNER_TYPE_SIZE], stype[SUBNET_OWNER_TYPE_SIZE];
568 EXEC SQL END DECLARE SECTION;
571 if (q->type == RETRIEVE)
574 id = *(int *)argv[1];
576 if (q->type == APPEND && isdigit(argv[0][0]))
579 EXEC SQL SELECT count(name) INTO :cnt from hostalias WHERE mach_id = :id;
582 /* if the type is APPEND, this is ahal and we need to make sure there
583 * will be no more than 2 aliases. If it's not, it must be dhal and
586 if (q->type == APPEND && cnt >= 2)
588 EXEC SQL SELECT m.owner_type, m.owner_id, s.owner_type, s.owner_id
589 INTO :mtype, :mid, :stype, :sid FROM machine m, subnet s
590 WHERE m.mach_id = :id and s.snet_id = m.snet_id;
591 status = find_member(mtype, mid, cl);
594 status = find_member(stype, sid, cl);
602 /* access_snt - check for retrieving network structure
605 int access_snt(struct query *q, char *argv[], client *cl)
607 if (q->type == RETRIEVE)
615 int access_printer(struct query *q, char *argv[], client *cl)
617 EXEC SQL BEGIN DECLARE SECTION;
618 char type[PRINTSERVERS_OWNER_TYPE_SIZE];
620 EXEC SQL END DECLARE SECTION;
623 mach_id = *(int *)argv[PRN_RM];
624 EXEC SQL SELECT owner_type, owner_id INTO :type, :id
625 FROM printservers WHERE mach_id = :mach_id;
629 status = find_member(type, id, cl);
637 int access_zephyr(struct query *q, char *argv[], client *cl)
639 EXEC SQL BEGIN DECLARE SECTION;
640 char type[ZEPHYR_OWNER_TYPE_SIZE];
643 EXEC SQL END DECLARE SECTION;
646 class = argv[ZA_CLASS];
647 EXEC SQL SELECT owner_type, owner_id INTO :type, :id
648 FROM zephyr WHERE class = :class;
652 status = find_member(type, id, cl);
659 /* access_container - check access for most container operations
661 * Inputs: argv[0] - cnt_id
665 * - check if that client is a member of the access control list
666 * - OR, if the query is add_machine_to_container or delete_machine_from_container
667 * check if the client is a memeber of the mem_acl list
668 * - if the query is update_container and the container is to be renamed and
669 * it is a top-level container, only priviledged users can do it
672 int access_container(struct query *q, char *argv[], client *cl)
674 EXEC SQL BEGIN DECLARE SECTION;
675 int cnt_id, acl_id, memacl_id, mach_id, machine_owner_id, flag;
676 char acl_type[CONTAINERS_ACL_TYPE_SIZE], memacl_type[CONTAINERS_ACL_TYPE_SIZE];
677 char name[CONTAINERS_NAME_SIZE], *newname;
678 char machine_owner_type[MACHINE_OWNER_TYPE_SIZE];
679 EXEC SQL END DECLARE SECTION;
682 cnt_id = *(int *)argv[0];
684 /* if amcn or dmcn, container id is the second argument */
685 if (strcmp(q->shortname, "amcn") == 0 || strcmp(q->shortname, "dmcn") == 0)
687 mach_id = *(int *)argv[0];
688 cnt_id = *(int *)argv[1];
691 EXEC SQL SELECT acl_id, acl_type, memacl_id, memacl_type, name, publicflg
692 INTO :acl_id, :acl_type, :memacl_id, :memacl_type, :name, :flag
694 WHERE cnt_id = :cnt_id;
696 if (sqlca.sqlerrd[2] != 1)
699 /* trim off the trailing spaces */
700 strcpy(name, strtrim(name));
702 /* if the query is update_container and the containers is to be renamed
703 * and it is a top-level container, only dbadmin can do it */
704 if (!strcmp(q->shortname, "ucon"))
707 if (strcmp(name, newname) && strchr(name, '/') == NULL)
711 /* check for client in access control list and return success right
712 * away if it's there. */
713 if (find_member(acl_type, acl_id, cl))
716 /* If not amcn, dmcn, we lose. */
717 if (strcmp(q->shortname, "amcn") && strcmp(q->shortname, "dmcn"))
720 if (find_member(memacl_type, memacl_id, cl))
723 /* if the container is public or the query is delete, grant access if client
724 * is on owner list */
725 if (flag || q->type == DELETE)
727 EXEC SQL SELECT owner_type, owner_id INTO :machine_owner_type,
730 WHERE mach_id = :mach_id;
732 if (sqlca.sqlerrd[2] == 1 && strcmp("NONE", machine_owner_type) &&
733 find_member(machine_owner_type, machine_owner_id, cl))
736 /* Otherwise fail. */