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