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