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