]> andersk Git - moira.git/blame - server/qrtn.qc
added definition of ARGLEN
[moira.git] / server / qrtn.qc
CommitLineData
d26cae4e 1/*
2 * $Source$
3 * $Author$
4 * $Header$
5 *
6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
7 *
8 * $Log$
d353058b 9 * Revision 1.13 1988-01-04 12:02:13 mar
10 * moved transaction start before pre-routines (wesommer)
faad6f39 11 *
d353058b 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 *
6ec81cbf 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 *
19bf23eb 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 *
3df9e21e 32 * Revision 1.9 87/08/22 17:47:38 wesommer
33 * Cleanup (these changes were by Mike).
34 *
cc1231a1 35 * Revision 1.8 87/08/10 16:22:26 mike
36 * wesommer modified error reporting.
37 *
1bf7f927 38 * Revision 1.7 87/08/04 01:49:20 wesommer
39 * Rearranged messages.
40 *
b4182127 41 * Revision 1.6 87/08/04 01:30:54 wesommer
42 * Mike's changes; checked in prior to working over messages.
43 *
7536027d 44 * Revision 1.5 87/06/21 16:37:58 wesommer
45 * Changed include files, reindented things.
46 *
47 *
faad6f39 48 * Revision 1.4 87/06/08 05:03:27 wesommer
49 * Reindented; added header and trailer.
50 *
d26cae4e 51 */
52
53#ifndef lint
54static char *rcsid_qrtn_qc = "$Header$";
55#endif lint
56
97479f6f 57#include "query.h"
97479f6f 58#include "sms_server.h"
59
7536027d 60#define SMS_SUCCESS 0
61
97479f6f 62char *Argv[16];
63
64static int ingres_errno = 0;
7536027d 65extern char *whoami;
97479f6f 66
d26cae4e 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;
97479f6f 75{
d26cae4e 76 ingres_errno = SMS_INGRES_ERR;
1bf7f927 77 com_err(whoami, SMS_INGRES_ERR, " code %d\n", ingres_errno);
d26cae4e 78 return *num;
97479f6f 79}
80
d26cae4e 81int sms_open_database()
97479f6f 82{
d26cae4e 83 register int i;
97479f6f 84
d26cae4e 85 /* initialize local argv */
86 for (i = 0; i < 16; i++)
87 Argv[i] = (char *)malloc(128);
97479f6f 88
d26cae4e 89 IIseterr(ingerr);
97479f6f 90
d26cae4e 91 ingres_errno = 0;
97479f6f 92
d26cae4e 93 /* open the database */
94## ingres sms
95 return ingres_errno;
97479f6f 96}
97
d26cae4e 98int sms_close_database()
97479f6f 99{
d26cae4e 100## exit
97479f6f 101}
102
7536027d 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();
cc1231a1 118 int access_list();
7536027d 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 ||
cc1231a1 132 v->pre_rtn == access_pop ||
133 v->pre_rtn == access_list)))
7536027d 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;
d26cae4e 159 char *name;
160 int argc;
161 char *argv_ro[];
162 int (*action)();
163 char *actarg;
97479f6f 164{
d26cae4e 165 register struct query *q;
166 register int i;
7536027d 167 register int status;
168 register int argreq;
169 register struct validate *v;
170 int privileged;
171 char qual[256];
cc1231a1 172 char sort[32];
7536027d 173 char *pqual;
cc1231a1 174 char *psort;
7536027d 175## char *table;
176 struct save_queue *sq;
d26cae4e 177 struct query *get_query_by_name();
7536027d 178 int sq_save_args();
179 struct save_queue *sq_create();
cc1231a1 180 char *build_sort();
7536027d 181 int access_user();
cc1231a1 182 int access_pop();
183 int access_list();
d26cae4e 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
7536027d 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 */
d26cae4e 204 q = get_query_by_name(name);
7536027d 205 if (q == (struct query *)0) return(SMS_NO_HANDLE);
206 v = q->validate;
207
d353058b 208 if (q->type != RETRIEVE)
209## begin transaction
210
211 /* check query access */
7536027d 212 status = check_query_access(q, Argv, cl);
213 privileged = (status == SMS_SUCCESS) ? 1 : 0;
cc1231a1 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))))
d353058b 218 goto out;
7536027d 219
220 /* check argument count */
221 argreq = q->argc;
222 if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
d353058b 223 if (argc != argreq) {
224 status = SMS_ARGS;
225 goto out;
226 }
227
7536027d 228
229 /* validate arguments */
230 if (v && v->valobj) {
231 status = validate_fields(q, Argv, v->valobj, v->objcnt);
d353058b 232 if (status != SMS_SUCCESS) goto out;
7536027d 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))
d353058b 239 goto out;
7536027d 240 }
241
d26cae4e 242 switch (q->type) {
faad6f39 243 case RETRIEVE:
7536027d 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 */
d26cae4e 252 if (q->qual) {
253 build_qual(q->qual, q->argc, Argv, qual);
7536027d 254 pqual = qual;
255 } else {
256 pqual = 0;
257 }
258
cc1231a1 259 /* build "sort" clause if needed */
260 if (v && v->valobj) {
261 psort = build_sort(v, sort);
262 } else {
263 psort = 0;
264 }
265
7536027d 266 /* if there is a followup routine, then we must save the results */
267 /* of the first query for use by the followup routine */
cc1231a1 268 /* if q->rvar = NULL, perform post_rtn only */
269 if (q->rvar) {
7536027d 270 if (v && v->post_rtn) {
271 sq = sq_create();
cc1231a1 272 status = do_retrieve(q, pqual, psort, sq_save_args, sq);
7536027d 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 */
cc1231a1 280 status = do_retrieve(q, pqual, psort, action, actarg);
7536027d 281 }
282 if (status != SMS_SUCCESS) break;
cc1231a1 283 table = q->rtable;
7536027d 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
d26cae4e 290 break;
291
faad6f39 292 case UPDATE:
7536027d 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 */
cc1231a1 300 /* if q->rvar = NULL, perform post_rtn only */
301 if (q->rvar) {
7536027d 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;
cc1231a1 305 table = q->rtable;
7536027d 306## repeat replace tblstats (updates = tblstats.updates + 1,
307## modtime = "now")
308## where tblstats.#table = @table
d26cae4e 309 }
7536027d 310
311 /* execute followup routine (if any) */
312 if (v->post_rtn) status = (*v->post_rtn)(q, Argv);
313
d26cae4e 314 break;
97479f6f 315
faad6f39 316 case APPEND:
7536027d 317 /* see if row already exists */
318 if (v->field) {
319 status = validate_row(q, Argv, v);
320 if (status != SMS_NO_MATCH) break;
d26cae4e 321 }
7536027d 322
323 /* increment id number if necessary */
d353058b 324 if (v->object_id) {
325 status = set_next_object_id(v->object_id);
326 if (status != SMS_SUCCESS) break;
327 }
7536027d 328
cc1231a1 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
7536027d 337 /* perform the append */
cc1231a1 338 /* if q->rvar = NULL, perform post_rtn only */
339 if (q->rvar) {
340 status = do_append(q, &Argv[q->argc], pqual, action, actarg);
7536027d 341 if (status != SMS_SUCCESS) break;
cc1231a1 342 table = q->rtable;
7536027d 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);
d26cae4e 350 break;
97479f6f 351
faad6f39 352 case DELETE:
7536027d 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 */
cc1231a1 360 /* if q->rvar = NULL, perform post_rtn only */
361 if (q->rvar) {
7536027d 362 build_qual(q->qual, q->argc, Argv, qual);
363 status = do_delete(q, qual, action, actarg);
364 if (status != SMS_SUCCESS) break;
cc1231a1 365 table = q->rtable;
7536027d 366## repeat replace tblstats (deletes = tblstats.deletes + 1,
367## modtime = "now")
368## where tblstats.#table = @table
97479f6f 369 }
7536027d 370
371 /* execute followup routine */
372 if (v->post_rtn) status = (*v->post_rtn)(q, Argv);
d26cae4e 373 break;
7536027d 374
d26cae4e 375 }
7536027d 376
d353058b 377out:
3df9e21e 378 if (q->type != RETRIEVE) {
379 if (status == SMS_SUCCESS) {
d353058b 380## end transaction /* commit to this */
3df9e21e 381 } else {
d353058b 382## abort /* it never happened */
3df9e21e 383 }
384 }
7536027d 385
1bf7f927 386 if (status != SMS_SUCCESS && log_flags & LOG_RES)
387 com_err(whoami, status, " (Query failed)");
7536027d 388 return(status);
97479f6f 389}
390
391build_qual(fmt, argc, argv, qual)
392 char *fmt;
393 int argc;
394 char *argv[];
395 char *qual;
396{
7536027d 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
d26cae4e 413 switch (argc) {
414 case 0:
415 strcpy(qual, fmt);
416 break;
417
418 case 1:
7536027d 419 sprintf(qual, fmt, args[0]);
d26cae4e 420 break;
421
422 case 2:
7536027d 423 sprintf(qual, fmt, args[0], args[1]);
d26cae4e 424 break;
425
426 case 3:
7536027d 427 sprintf(qual, fmt, args[0], args[1], args[2]);
d26cae4e 428 break;
429
430 case 4:
7536027d 431 sprintf(qual, fmt, args[0], args[1], args[2], args[3]);
d26cae4e 432 break;
433 }
97479f6f 434}
435
cc1231a1 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
7536027d 461check_query_access(q, argv, cl)
462 struct query *q;
463 char *argv[];
464 client *cl;
d26cae4e 465##{
7536027d 466## char *name;
467## int acl_id;
468## int exists;
d26cae4e 469## int rowcount;
cc1231a1 470## int errorno;
7536027d 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
cc1231a1 479## inquire_equel (rowcount = "rowcount", errorno = "errorno")
480 if (errorno != 0) return(SMS_INGRES_ERR);
7536027d 481 if (rowcount == 0) return(SMS_PERM);
d26cae4e 482
7536027d 483 /* initialize default uid */
484 if (def_uid == 0) {
485## retrieve (def_uid = users.users_id) where users.login = "default"
d26cae4e 486 }
97479f6f 487
7536027d 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
7536027d 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##}
97479f6f 502
7536027d 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
6ec81cbf 513 if (cl->clname == NULL)
514 return SMS_PERM;
515
19bf23eb 516 /* for now ignore instances */
7536027d 517 krb = &cl->kname;
7536027d 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 */
d26cae4e 533## inquire_equel (rowcount = "rowcount")
7536027d 534 if (rowcount == 0) return(SMS_PERM);
535
536 *client_id = member_id;
537 return(SMS_SUCCESS);
538##}
97479f6f 539
7536027d 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? */
7536027d 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;
d26cae4e 571 }
97479f6f 572
7536027d 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
7536027d 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 }
d26cae4e 591##}
97479f6f 592
cc1231a1 593do_retrieve(q, pqual, psort, action, actarg)
d26cae4e 594 register struct query *q;
cc1231a1 595 char *pqual;
596 char *psort;
d26cae4e 597 int (*action)();
598 char *actarg;
599##{
600## char *rvar;
601## char *rtable;
602## char *cqual;
cc1231a1 603## char *csort;
d26cae4e 604## int rowcount;
cc1231a1 605## int errorno;
7536027d 606
d26cae4e 607 if (q->rvar) {
608 rvar = q->rvar;
609 rtable = q->rtable;
610## range of rvar is rtable
611 }
97479f6f 612
cc1231a1 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
7536027d 630 } else {
cc1231a1 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 }
7536027d 643 }
97479f6f 644
cc1231a1 645## inquire_equel (rowcount = "rowcount", errorno = "errorno")
646 if (errorno != 0) return(SMS_INGRES_ERR);
7536027d 647 return ((rowcount == 0) ? SMS_NO_MATCH : SMS_SUCCESS);
d26cae4e 648##}
97479f6f 649
e38c941b 650do_update(q, argv, qual, action, actarg)
d26cae4e 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;
cc1231a1 661## int errorno;
97479f6f 662
d26cae4e 663 rvar = q->rvar;
664 rtable = q->rtable;
665## range of rvar is rtable
97479f6f 666
d26cae4e 667 cqual = qual;
668## replace rvar (param (q->tlist, argv))
669## where cqual
97479f6f 670
cc1231a1 671## inquire_equel (errorno = "errorno")
672 if (errorno != 0) return(SMS_INGRES_ERR);
7536027d 673 return(SMS_SUCCESS);
d26cae4e 674##}
97479f6f 675
cc1231a1 676do_append(q, argv, pqual, action, actarg)
d26cae4e 677 register struct query *q;
678 char *argv[];
cc1231a1 679 char *pqual;
d26cae4e 680 int (*action)();
681 char *actarg;
682##{
683## char *rvar;
684## char *rtable;
7536027d 685## char *cqual;
cc1231a1 686## int errorno;
97479f6f 687
d26cae4e 688 rvar = q->rvar;
689 rtable = q->rtable;
690## range of rvar is rtable
97479f6f 691
cc1231a1 692 if (pqual) {
693 cqual = pqual;
7536027d 694## append to rtable (param (q->tlist, argv)) where cqual
695 } else {
696## append to rtable (param (q->tlist, argv))
697 }
97479f6f 698
cc1231a1 699## inquire_equel (errorno = "errorno")
700 if (errorno != 0) return(SMS_INGRES_ERR);
7536027d 701 return(SMS_SUCCESS);
d26cae4e 702##}
97479f6f 703
e38c941b 704do_delete(q, qual, action, actarg)
d26cae4e 705 register struct query *q;
706 char *qual;
707 int (*action)();
708 char *actarg;
709##{
710## char *rvar;
711## char *rtable;
712## char *cqual;
cc1231a1 713## int errorno;
97479f6f 714
d26cae4e 715 rvar = q->rvar;
716 rtable = q->rtable;
717## range of rvar is rtable
97479f6f 718
d26cae4e 719 cqual = qual;
720## delete rvar where cqual
97479f6f 721
cc1231a1 722## inquire_equel (errorno = "errorno")
723 if (errorno != 0) return(SMS_INGRES_ERR);
7536027d 724 return(SMS_SUCCESS);
d26cae4e 725##}
97479f6f 726
d26cae4e 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.433903 seconds and 5 git commands to generate.