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