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