6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
9 * Revision 1.13 1988-01-04 12:02:13 mar
10 * moved transaction start before pre-routines (wesommer)
12 * Revision 1.13 87/11/12 18:13:12 wesommer
13 * Move transaction boundary to include the pre routine.
15 * Revision 1.12 87/09/12 20:42:11 wesommer
16 * Clean up after Gretzinger: cl->kname is not valid unless cl->clname is
19 * Revision 1.12 87/09/12 20:06:46 wesommer
20 * Fix security hole/null dereference bug: if clname is NULL, return
21 * permission denied in get_client.
23 * Revision 1.11 87/09/01 16:10:01 wesommer
24 * This change was made by Mike, who didn't feel like checking it in.
25 * Temp hack: ignore instances.
27 * Revision 1.10 87/08/28 14:57:51 mike
28 * Modified sms_query to not enclose RETRIEVE queries in begin/end transaction.
29 * This was necessary to allow get_all_poboxes and get_groups_of_all_users
30 * to temporarily change the Ingres lockmode.
32 * Revision 1.9 87/08/22 17:47:38 wesommer
33 * Cleanup (these changes were by Mike).
35 * Revision 1.8 87/08/10 16:22:26 mike
36 * wesommer modified error reporting.
38 * Revision 1.7 87/08/04 01:49:20 wesommer
39 * Rearranged messages.
41 * Revision 1.6 87/08/04 01:30:54 wesommer
42 * Mike's changes; checked in prior to working over messages.
44 * Revision 1.5 87/06/21 16:37:58 wesommer
45 * Changed include files, reindented things.
48 * Revision 1.4 87/06/08 05:03:27 wesommer
49 * Reindented; added header and trailer.
54 static char *rcsid_qrtn_qc = "$Header$";
58 #include "sms_server.h"
64 static int ingres_errno = 0;
68 * ingerr: (supposedly) called when Ingres indicates an error.
69 * I have not yet been able to get this to work to intercept a
70 * database open error.
73 static int ingerr(num)
76 ingres_errno = SMS_INGRES_ERR;
77 com_err(whoami, SMS_INGRES_ERR, " code %d\n", ingres_errno);
81 int sms_open_database()
85 /* initialize local argv */
86 for (i = 0; i < 16; i++)
87 Argv[i] = (char *)malloc(128);
93 /* open the database */
98 int sms_close_database()
103 sms_check_access(cl, name, argc, argv_ro)
109 register struct query *q;
112 register struct validate *v;
114 register int privileged;
115 struct query *get_query_by_name();
120 q = get_query_by_name(name);
121 if (q == (struct query *)0) return(SMS_NO_HANDLE);
124 /* copy the arguments into a local argv that we can modify */
125 for (i = 0; i < argc; i++)
126 strcpy(Argv[i], argv_ro[i]);
128 /* check initial query access */
129 status = check_query_access(q, Argv, cl);
130 privileged = (status == SMS_SUCCESS) ? 1 : 0;
131 if (status != SMS_SUCCESS && !(v && (v->pre_rtn == access_user ||
132 v->pre_rtn == access_pop ||
133 v->pre_rtn == access_list)))
136 /* check argument count */
138 if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
139 if (argc != argreq) return(SMS_ARGS);
141 /* validate arguments */
142 if (v && v->valobj) {
143 status = validate_fields(q, Argv, v->valobj, v->objcnt);
144 if (status != SMS_SUCCESS) return(status);
147 /* perform special query access check */
148 if (v && v->pre_rtn) {
149 status = (*v->pre_rtn)(q, Argv, cl, 1);
150 if (status != SMS_SUCCESS && (status != SMS_PERM || !privileged))
157 sms_process_query(cl, name, argc, argv_ro, action, actarg)
165 register struct query *q;
169 register struct validate *v;
176 struct save_queue *sq;
177 struct query *get_query_by_name();
179 struct save_queue *sq_create();
185 /* copy the arguments into a local argv that we can modify */
186 for (i = 0; i < argc; i++)
187 strcpy(Argv[i], argv_ro[i]);
189 /* list queries command */
190 if (!strcmp(name, "_list_queries")) {
191 list_queries(action, actarg);
195 /* help query command */
196 if (!strcmp(name, "_help")) {
197 q = get_query_by_name(Argv[0]);
198 if (q == (struct query *)0) return(SMS_NO_HANDLE);
199 help_query(q, action, actarg);
203 /* get query structure, return error if named query does not exist */
204 q = get_query_by_name(name);
205 if (q == (struct query *)0) return(SMS_NO_HANDLE);
208 if (q->type != RETRIEVE)
211 /* check query access */
212 status = check_query_access(q, Argv, cl);
213 privileged = (status == SMS_SUCCESS) ? 1 : 0;
214 if (!privileged && !(status == SMS_PERM &&
215 (v && (v->pre_rtn == access_user ||
216 v->pre_rtn == access_pop ||
217 v->pre_rtn == access_list))))
220 /* check argument count */
222 if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
223 if (argc != argreq) {
229 /* validate arguments */
230 if (v && v->valobj) {
231 status = validate_fields(q, Argv, v->valobj, v->objcnt);
232 if (status != SMS_SUCCESS) goto out;
235 /* perform any special query pre-processing */
236 if (v && v->pre_rtn) {
237 status = (*v->pre_rtn)(q, Argv, cl, 0);
238 if (status != SMS_SUCCESS && (status != SMS_PERM || !privileged))
244 /* for queries that do not permit wildcarding, check if row
247 status = validate_row(q, Argv, v);
248 if (status != SMS_EXISTS) break;
251 /* build "where" clause if needed */
253 build_qual(q->qual, q->argc, Argv, qual);
259 /* build "sort" clause if needed */
260 if (v && v->valobj) {
261 psort = build_sort(v, sort);
266 /* if there is a followup routine, then we must save the results */
267 /* of the first query for use by the followup routine */
268 /* if q->rvar = NULL, perform post_rtn only */
270 if (v && v->post_rtn) {
272 status = do_retrieve(q, pqual, psort, sq_save_args, sq);
273 if (status != SMS_SUCCESS) {
277 status = (*v->post_rtn)(q, sq, v, action, actarg);
279 /* normal retrieve */
280 status = do_retrieve(q, pqual, psort, action, actarg);
282 if (status != SMS_SUCCESS) break;
284 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
285 ## where tblstats.#table = @table
287 status = (*v->post_rtn)(q, Argv, action, actarg);
293 /* see if row already exists */
295 status = validate_row(q, Argv, v);
296 if (status != SMS_EXISTS) break;
299 /* build "where" clause and perform update */
300 /* if q->rvar = NULL, perform post_rtn only */
302 build_qual(q->qual, q->argc, Argv, qual);
303 status = do_update(q, &Argv[q->argc], qual, action, actarg);
304 if (status != SMS_SUCCESS) break;
306 ## repeat replace tblstats (updates = tblstats.updates + 1,
308 ## where tblstats.#table = @table
311 /* execute followup routine (if any) */
312 if (v->post_rtn) status = (*v->post_rtn)(q, Argv);
317 /* see if row already exists */
319 status = validate_row(q, Argv, v);
320 if (status != SMS_NO_MATCH) break;
323 /* increment id number if necessary */
325 status = set_next_object_id(v->object_id);
326 if (status != SMS_SUCCESS) break;
329 /* build "where" clause if needed */
331 build_qual(q->qual, q->argc, Argv, qual);
337 /* perform the append */
338 /* if q->rvar = NULL, perform post_rtn only */
340 status = do_append(q, &Argv[q->argc], pqual, action, actarg);
341 if (status != SMS_SUCCESS) break;
343 ## repeat replace tblstats (appends = tblstats.appends + 1,
345 ## where tblstats.#table = @table
348 /* execute followup routine */
349 if (v->post_rtn) status = (*v->post_rtn)(q, Argv);
353 /* see if row already exists */
355 status = validate_row(q, Argv, v);
356 if (status != SMS_EXISTS) break;
359 /* build "where" clause and perform delete */
360 /* if q->rvar = NULL, perform post_rtn only */
362 build_qual(q->qual, q->argc, Argv, qual);
363 status = do_delete(q, qual, action, actarg);
364 if (status != SMS_SUCCESS) break;
366 ## repeat replace tblstats (deletes = tblstats.deletes + 1,
368 ## where tblstats.#table = @table
371 /* execute followup routine */
372 if (v->post_rtn) status = (*v->post_rtn)(q, Argv);
378 if (q->type != RETRIEVE) {
379 if (status == SMS_SUCCESS) {
380 ## end transaction /* commit to this */
382 ## abort /* it never happened */
386 if (status != SMS_SUCCESS && log_flags & LOG_RES)
387 com_err(whoami, status, " (Query failed)");
391 build_qual(fmt, argc, argv, qual)
402 for (i = 0; i < argc; i++) {
403 c = (char *)index(c, '%');
404 if (c++ == (char *)0) return(SMS_ARGS);
408 *(int *)&args[i] = *(int *)argv[i]; /* sigh */
410 return(SMS_INGRES_ERR);
419 sprintf(qual, fmt, args[0]);
423 sprintf(qual, fmt, args[0], args[1]);
427 sprintf(qual, fmt, args[0], args[1], args[2]);
431 sprintf(qual, fmt, args[0], args[1], args[2], args[3]);
438 register struct validate *v;
441 register struct valobj *vo;
450 if (vo->type == V_SORT) {
451 sprintf(elem, "RET_VAR%d", vo->index + 1);
452 if (*sort) strcat(sort, ", ");
458 return ((*sort) ? sort : 0);
461 check_query_access(q, argv, cl)
471 ## static int def_uid;
476 /* get query access control list */
478 ## repeat retrieve (acl_id = capacls.list_id) where capacls.tag = @name
479 ## inquire_equel (rowcount = "rowcount", errorno = "errorno")
480 if (errorno != 0) return(SMS_INGRES_ERR);
481 if (rowcount == 0) return(SMS_PERM);
483 /* initialize default uid */
485 ## retrieve (def_uid = users.users_id) where users.login = "default"
488 /* check for default access */
489 ## range of m is members
490 ## repeat retrieve (exists = any(m.#member_id where m.list_id = @acl_id and
491 ## m.member_type = "USER" and m.#member_id = def_uid))
492 if (exists) return(SMS_SUCCESS);
494 /* parse client name */
495 status = get_client(cl, &client_type, &client_id);
496 if (status != SMS_SUCCESS) return(status);
498 /* see if client is in the list (or any of its sub-lists) */
499 exists = find_member(acl_id, client_type, client_id, 0);
500 return ((exists) ? SMS_SUCCESS : SMS_PERM);
503 get_client(cl, client_type, client_id)
513 if (cl->clname == NULL)
516 /* for now ignore instances */
519 /* if client is from local realm, get users_id */
520 if (!strcmp(krb->realm, krb_realm)) {
522 ## repeat retrieve (member_id = users.users_id) where users.login = @name
523 *client_type = "USER";
525 /* otherwise use string_id */
527 ## repeat retrieve (member_id = strings.string_id)
528 ## where strings.string = @name
529 *client_type = "STRING";
532 /* make sure we found a users or string id */
533 ## inquire_equel (rowcount = "rowcount")
534 if (rowcount == 0) return(SMS_PERM);
536 *client_id = member_id;
540 ##find_member(list_id, member_type, member_id, sq)
542 ## char *member_type;
544 struct save_queue *sq;
549 struct save_queue *sq_create();
551 /* see if client is a direct member of list */
552 ## repeat retrieve (exists = any(m.#member_id where
553 ## m.#list_id = @list_id and
554 ## m.#member_type = @member_type and
555 ## m.#member_id = @member_id))
556 if (exists) return(1);
558 /* are there any sub-lists? */
559 ## repeat retrieve (exists = any(m.#member_id where m.#list_id = @list_id and
560 ## m.#member_type = "LIST"))
561 if (!exists) return(0);
563 /* yes; now recurse through sublists */
565 /* create a save queue */
566 if (sq == (struct save_queue *)0) {
573 /* save all sublist ids */
574 ## range of m is members
575 ## retrieve (sublist = m.#member_id)
576 ## where m.#list_id = list_id and m.#member_type = "LIST"
578 sq_save_unique_data(sq, sublist);
583 /* at top-level, check sub-lists for client (breadth-first search) */
584 while (sq_get_data(sq, &sublist)) {
585 exists = find_member(sublist, member_type, member_id, sq);
593 do_retrieve(q, pqual, psort, action, actarg)
594 register struct query *q;
610 ## range of rvar is rtable
617 ## retrieve unique (param (q->tlist, q->vaddr)) where cqual
620 (*action)(q->vcnt, q->vaddr, actarg);
623 ## retrieve unique (param (q->tlist, q->vaddr))
626 (*action)(q->vcnt, q->vaddr, actarg);
633 ## retrieve unique (param (q->tlist, q->vaddr)) where cqual
635 (*action)(q->vcnt, q->vaddr, actarg);
638 ## retrieve unique (param (q->tlist, q->vaddr))
640 (*action)(q->vcnt, q->vaddr, actarg);
645 ## inquire_equel (rowcount = "rowcount", errorno = "errorno")
646 if (errorno != 0) return(SMS_INGRES_ERR);
647 return ((rowcount == 0) ? SMS_NO_MATCH : SMS_SUCCESS);
650 do_update(q, argv, qual, action, actarg)
651 register struct query *q;
665 ## range of rvar is rtable
668 ## replace rvar (param (q->tlist, argv))
671 ## inquire_equel (errorno = "errorno")
672 if (errorno != 0) return(SMS_INGRES_ERR);
676 do_append(q, argv, pqual, action, actarg)
677 register struct query *q;
690 ## range of rvar is rtable
694 ## append to rtable (param (q->tlist, argv)) where cqual
696 ## append to rtable (param (q->tlist, argv))
699 ## inquire_equel (errorno = "errorno")
700 if (errorno != 0) return(SMS_INGRES_ERR);
704 do_delete(q, qual, action, actarg)
705 register struct query *q;
717 ## range of rvar is rtable
720 ## delete rvar where cqual
722 ## inquire_equel (errorno = "errorno")
723 if (errorno != 0) return(SMS_INGRES_ERR);
732 * c-continued-statement-offset: 4
734 * c-argdecl-indent: 4