]> andersk Git - moira.git/blame_incremental - server/qrtn.qc
added definition of ARGLEN
[moira.git] / server / qrtn.qc
... / ...
CommitLineData
1/*
2 * $Source$
3 * $Author$
4 * $Header$
5 *
6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
7 *
8 * $Log$
9 * Revision 1.13 1988-01-04 12:02:13 mar
10 * moved transaction start before pre-routines (wesommer)
11 *
12 * Revision 1.13 87/11/12 18:13:12 wesommer
13 * Move transaction boundary to include the pre routine.
14 *
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
17 * non-NULL.
18 *
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.
22 *
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.
26 *
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.
31 *
32 * Revision 1.9 87/08/22 17:47:38 wesommer
33 * Cleanup (these changes were by Mike).
34 *
35 * Revision 1.8 87/08/10 16:22:26 mike
36 * wesommer modified error reporting.
37 *
38 * Revision 1.7 87/08/04 01:49:20 wesommer
39 * Rearranged messages.
40 *
41 * Revision 1.6 87/08/04 01:30:54 wesommer
42 * Mike's changes; checked in prior to working over messages.
43 *
44 * Revision 1.5 87/06/21 16:37:58 wesommer
45 * Changed include files, reindented things.
46 *
47 *
48 * Revision 1.4 87/06/08 05:03:27 wesommer
49 * Reindented; added header and trailer.
50 *
51 */
52
53#ifndef lint
54static char *rcsid_qrtn_qc = "$Header$";
55#endif lint
56
57#include "query.h"
58#include "sms_server.h"
59
60#define SMS_SUCCESS 0
61
62char *Argv[16];
63
64static int ingres_errno = 0;
65extern char *whoami;
66
67/*
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.
71 */
72
73static int ingerr(num)
74 int *num;
75{
76 ingres_errno = SMS_INGRES_ERR;
77 com_err(whoami, SMS_INGRES_ERR, " code %d\n", ingres_errno);
78 return *num;
79}
80
81int sms_open_database()
82{
83 register int i;
84
85 /* initialize local argv */
86 for (i = 0; i < 16; i++)
87 Argv[i] = (char *)malloc(128);
88
89 IIseterr(ingerr);
90
91 ingres_errno = 0;
92
93 /* open the database */
94## ingres sms
95 return ingres_errno;
96}
97
98int sms_close_database()
99{
100## exit
101}
102
103sms_check_access(cl, name, argc, argv_ro)
104 client *cl;
105 char *name;
106 int argc;
107 char *argv_ro[];
108{
109 register struct query *q;
110 register int argreq;
111 register int status;
112 register struct validate *v;
113 register int i;
114 register int privileged;
115 struct query *get_query_by_name();
116 int access_user();
117 int access_pop();
118 int access_list();
119
120 q = get_query_by_name(name);
121 if (q == (struct query *)0) return(SMS_NO_HANDLE);
122 v = q->validate;
123
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]);
127
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)))
134 return(status);
135
136 /* check argument count */
137 argreq = q->argc;
138 if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
139 if (argc != argreq) return(SMS_ARGS);
140
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);
145 }
146
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))
151 return(status);
152 }
153
154 return(SMS_SUCCESS);
155}
156
157sms_process_query(cl, name, argc, argv_ro, action, actarg)
158 client *cl;
159 char *name;
160 int argc;
161 char *argv_ro[];
162 int (*action)();
163 char *actarg;
164{
165 register struct query *q;
166 register int i;
167 register int status;
168 register int argreq;
169 register struct validate *v;
170 int privileged;
171 char qual[256];
172 char sort[32];
173 char *pqual;
174 char *psort;
175## char *table;
176 struct save_queue *sq;
177 struct query *get_query_by_name();
178 int sq_save_args();
179 struct save_queue *sq_create();
180 char *build_sort();
181 int access_user();
182 int access_pop();
183 int access_list();
184
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]);
188
189 /* list queries command */
190 if (!strcmp(name, "_list_queries")) {
191 list_queries(action, actarg);
192 return(SMS_SUCCESS);
193 }
194
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);
200 return(SMS_SUCCESS);
201 }
202
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);
206 v = q->validate;
207
208 if (q->type != RETRIEVE)
209## begin transaction
210
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))))
218 goto out;
219
220 /* check argument count */
221 argreq = q->argc;
222 if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
223 if (argc != argreq) {
224 status = SMS_ARGS;
225 goto out;
226 }
227
228
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;
233 }
234
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))
239 goto out;
240 }
241
242 switch (q->type) {
243 case RETRIEVE:
244 /* for queries that do not permit wildcarding, check if row
245 uniquely exists */
246 if (v && v->field) {
247 status = validate_row(q, Argv, v);
248 if (status != SMS_EXISTS) break;
249 }
250
251 /* build "where" clause if needed */
252 if (q->qual) {
253 build_qual(q->qual, q->argc, Argv, qual);
254 pqual = qual;
255 } else {
256 pqual = 0;
257 }
258
259 /* build "sort" clause if needed */
260 if (v && v->valobj) {
261 psort = build_sort(v, sort);
262 } else {
263 psort = 0;
264 }
265
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 */
269 if (q->rvar) {
270 if (v && v->post_rtn) {
271 sq = sq_create();
272 status = do_retrieve(q, pqual, psort, sq_save_args, sq);
273 if (status != SMS_SUCCESS) {
274 sq_destroy(sq);
275 break;
276 }
277 status = (*v->post_rtn)(q, sq, v, action, actarg);
278 } else {
279 /* normal retrieve */
280 status = do_retrieve(q, pqual, psort, action, actarg);
281 }
282 if (status != SMS_SUCCESS) break;
283 table = q->rtable;
284## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
285## where tblstats.#table = @table
286 } else {
287 status = (*v->post_rtn)(q, Argv, action, actarg);
288 }
289
290 break;
291
292 case UPDATE:
293 /* see if row already exists */
294 if (v->field) {
295 status = validate_row(q, Argv, v);
296 if (status != SMS_EXISTS) break;
297 }
298
299 /* build "where" clause and perform update */
300 /* if q->rvar = NULL, perform post_rtn only */
301 if (q->rvar) {
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;
305 table = q->rtable;
306## repeat replace tblstats (updates = tblstats.updates + 1,
307## modtime = "now")
308## where tblstats.#table = @table
309 }
310
311 /* execute followup routine (if any) */
312 if (v->post_rtn) status = (*v->post_rtn)(q, Argv);
313
314 break;
315
316 case APPEND:
317 /* see if row already exists */
318 if (v->field) {
319 status = validate_row(q, Argv, v);
320 if (status != SMS_NO_MATCH) break;
321 }
322
323 /* increment id number if necessary */
324 if (v->object_id) {
325 status = set_next_object_id(v->object_id);
326 if (status != SMS_SUCCESS) break;
327 }
328
329 /* build "where" clause if needed */
330 if (q->qual) {
331 build_qual(q->qual, q->argc, Argv, qual);
332 pqual = qual;
333 } else {
334 pqual = 0;
335 }
336
337 /* perform the append */
338 /* if q->rvar = NULL, perform post_rtn only */
339 if (q->rvar) {
340 status = do_append(q, &Argv[q->argc], pqual, action, actarg);
341 if (status != SMS_SUCCESS) break;
342 table = q->rtable;
343## repeat replace tblstats (appends = tblstats.appends + 1,
344## modtime = "now")
345## where tblstats.#table = @table
346 }
347
348 /* execute followup routine */
349 if (v->post_rtn) status = (*v->post_rtn)(q, Argv);
350 break;
351
352 case DELETE:
353 /* see if row already exists */
354 if (v->field) {
355 status = validate_row(q, Argv, v);
356 if (status != SMS_EXISTS) break;
357 }
358
359 /* build "where" clause and perform delete */
360 /* if q->rvar = NULL, perform post_rtn only */
361 if (q->rvar) {
362 build_qual(q->qual, q->argc, Argv, qual);
363 status = do_delete(q, qual, action, actarg);
364 if (status != SMS_SUCCESS) break;
365 table = q->rtable;
366## repeat replace tblstats (deletes = tblstats.deletes + 1,
367## modtime = "now")
368## where tblstats.#table = @table
369 }
370
371 /* execute followup routine */
372 if (v->post_rtn) status = (*v->post_rtn)(q, Argv);
373 break;
374
375 }
376
377out:
378 if (q->type != RETRIEVE) {
379 if (status == SMS_SUCCESS) {
380## end transaction /* commit to this */
381 } else {
382## abort /* it never happened */
383 }
384 }
385
386 if (status != SMS_SUCCESS && log_flags & LOG_RES)
387 com_err(whoami, status, " (Query failed)");
388 return(status);
389}
390
391build_qual(fmt, argc, argv, qual)
392 char *fmt;
393 int argc;
394 char *argv[];
395 char *qual;
396{
397 register char *c;
398 register int i;
399 char *args[4];
400
401 c = fmt;
402 for (i = 0; i < argc; i++) {
403 c = (char *)index(c, '%');
404 if (c++ == (char *)0) return(SMS_ARGS);
405 if (*c == 's')
406 args[i] = argv[i];
407 else if (*c == 'd')
408 *(int *)&args[i] = *(int *)argv[i]; /* sigh */
409 else
410 return(SMS_INGRES_ERR);
411 }
412
413 switch (argc) {
414 case 0:
415 strcpy(qual, fmt);
416 break;
417
418 case 1:
419 sprintf(qual, fmt, args[0]);
420 break;
421
422 case 2:
423 sprintf(qual, fmt, args[0], args[1]);
424 break;
425
426 case 3:
427 sprintf(qual, fmt, args[0], args[1], args[2]);
428 break;
429
430 case 4:
431 sprintf(qual, fmt, args[0], args[1], args[2], args[3]);
432 break;
433 }
434}
435
436char *
437build_sort(v, sort)
438 register struct validate *v;
439 char *sort;
440{
441 register struct valobj *vo;
442 register int n;
443 char elem[16];
444
445 n = v->objcnt;
446 vo = v->valobj;
447 *sort = 0;
448
449 while (--n >= 0) {
450 if (vo->type == V_SORT) {
451 sprintf(elem, "RET_VAR%d", vo->index + 1);
452 if (*sort) strcat(sort, ", ");
453 strcat(sort, elem);
454 }
455 vo++;
456 }
457
458 return ((*sort) ? sort : 0);
459}
460
461check_query_access(q, argv, cl)
462 struct query *q;
463 char *argv[];
464 client *cl;
465##{
466## char *name;
467## int acl_id;
468## int exists;
469## int rowcount;
470## int errorno;
471## static int def_uid;
472 int status;
473 int client_id;
474 char *client_type;
475
476 /* get query access control list */
477 name = q->shortname;
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);
482
483 /* initialize default uid */
484 if (def_uid == 0) {
485## retrieve (def_uid = users.users_id) where users.login = "default"
486 }
487
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);
493
494 /* parse client name */
495 status = get_client(cl, &client_type, &client_id);
496 if (status != SMS_SUCCESS) return(status);
497
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);
501##}
502
503get_client(cl, client_type, client_id)
504 client *cl;
505 char **client_type;
506 int *client_id;
507##{
508 struct krbname *krb;
509## int member_id;
510## char *name;
511## int rowcount;
512
513 if (cl->clname == NULL)
514 return SMS_PERM;
515
516 /* for now ignore instances */
517 krb = &cl->kname;
518
519 /* if client is from local realm, get users_id */
520 if (!strcmp(krb->realm, krb_realm)) {
521 name = krb->name;
522## repeat retrieve (member_id = users.users_id) where users.login = @name
523 *client_type = "USER";
524 } else {
525 /* otherwise use string_id */
526 name = cl->clname;
527## repeat retrieve (member_id = strings.string_id)
528## where strings.string = @name
529 *client_type = "STRING";
530 }
531
532 /* make sure we found a users or string id */
533## inquire_equel (rowcount = "rowcount")
534 if (rowcount == 0) return(SMS_PERM);
535
536 *client_id = member_id;
537 return(SMS_SUCCESS);
538##}
539
540##find_member(list_id, member_type, member_id, sq)
541## int list_id;
542## char *member_type;
543## int member_id;
544 struct save_queue *sq;
545##{
546## int exists;
547## int sublist;
548 int child;
549 struct save_queue *sq_create();
550
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);
557
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);
562
563 /* yes; now recurse through sublists */
564
565 /* create a save queue */
566 if (sq == (struct save_queue *)0) {
567 sq = sq_create();
568 child = 0;
569 } else {
570 child = 1;
571 }
572
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"
577## {
578 sq_save_unique_data(sq, sublist);
579## }
580
581 if (child) return;
582
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);
586 if (exists) {
587 sq_destroy(sq);
588 return(1);
589 }
590 }
591##}
592
593do_retrieve(q, pqual, psort, action, actarg)
594 register struct query *q;
595 char *pqual;
596 char *psort;
597 int (*action)();
598 char *actarg;
599##{
600## char *rvar;
601## char *rtable;
602## char *cqual;
603## char *csort;
604## int rowcount;
605## int errorno;
606
607 if (q->rvar) {
608 rvar = q->rvar;
609 rtable = q->rtable;
610## range of rvar is rtable
611 }
612
613 if (psort) {
614 csort = psort;
615 if (pqual) {
616 cqual = pqual;
617## retrieve unique (param (q->tlist, q->vaddr)) where cqual
618## sort by csort
619## {
620 (*action)(q->vcnt, q->vaddr, actarg);
621## }
622 } else {
623## retrieve unique (param (q->tlist, q->vaddr))
624## sort by csort
625## {
626 (*action)(q->vcnt, q->vaddr, actarg);
627## }
628 }
629
630 } else {
631 if (pqual) {
632 cqual = pqual;
633## retrieve unique (param (q->tlist, q->vaddr)) where cqual
634## {
635 (*action)(q->vcnt, q->vaddr, actarg);
636## }
637 } else {
638## retrieve unique (param (q->tlist, q->vaddr))
639## {
640 (*action)(q->vcnt, q->vaddr, actarg);
641## }
642 }
643 }
644
645## inquire_equel (rowcount = "rowcount", errorno = "errorno")
646 if (errorno != 0) return(SMS_INGRES_ERR);
647 return ((rowcount == 0) ? SMS_NO_MATCH : SMS_SUCCESS);
648##}
649
650do_update(q, argv, qual, action, actarg)
651 register struct query *q;
652 char *argv[];
653 char *qual;
654 int (*action)();
655 char *actarg;
656##{
657## char *rvar;
658## char *rtable;
659## char *cqual;
660## int rowcount;
661## int errorno;
662
663 rvar = q->rvar;
664 rtable = q->rtable;
665## range of rvar is rtable
666
667 cqual = qual;
668## replace rvar (param (q->tlist, argv))
669## where cqual
670
671## inquire_equel (errorno = "errorno")
672 if (errorno != 0) return(SMS_INGRES_ERR);
673 return(SMS_SUCCESS);
674##}
675
676do_append(q, argv, pqual, action, actarg)
677 register struct query *q;
678 char *argv[];
679 char *pqual;
680 int (*action)();
681 char *actarg;
682##{
683## char *rvar;
684## char *rtable;
685## char *cqual;
686## int errorno;
687
688 rvar = q->rvar;
689 rtable = q->rtable;
690## range of rvar is rtable
691
692 if (pqual) {
693 cqual = pqual;
694## append to rtable (param (q->tlist, argv)) where cqual
695 } else {
696## append to rtable (param (q->tlist, argv))
697 }
698
699## inquire_equel (errorno = "errorno")
700 if (errorno != 0) return(SMS_INGRES_ERR);
701 return(SMS_SUCCESS);
702##}
703
704do_delete(q, qual, action, actarg)
705 register struct query *q;
706 char *qual;
707 int (*action)();
708 char *actarg;
709##{
710## char *rvar;
711## char *rtable;
712## char *cqual;
713## int errorno;
714
715 rvar = q->rvar;
716 rtable = q->rtable;
717## range of rvar is rtable
718
719 cqual = qual;
720## delete rvar where cqual
721
722## inquire_equel (errorno = "errorno")
723 if (errorno != 0) return(SMS_INGRES_ERR);
724 return(SMS_SUCCESS);
725##}
726
727
728/*
729 * Local Variables:
730 * mode: c
731 * c-indent-level: 4
732 * c-continued-statement-offset: 4
733 * c-brace-offset: -4
734 * c-argdecl-indent: 4
735 * c-label-offset: -4
736 * End:
737 */
738
This page took 0.04434 seconds and 5 git commands to generate.