]> andersk Git - moira.git/blame_incremental - server/qrtn.pc
Make sure acl_type is LIST before using the object id as a list_id.
[moira.git] / server / qrtn.pc
... / ...
CommitLineData
1/* $Id$
2 *
3 * Query-processing routines
4 *
5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
8 *
9 */
10
11#include <mit-copyright.h>
12#include "mr_server.h"
13#include "qrtn.h"
14#include "query.h"
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19
20EXEC SQL INCLUDE sqlca; /* SQL Communications Area */
21EXEC SQL INCLUDE sqlda; /* SQL Descriptor Area */
22
23RCSID("$Header$");
24
25SQLDA *mr_sqlda;
26EXEC SQL BEGIN DECLARE SECTION;
27char stmt_buf[MR_STMTBUF_LEN];
28int proxy_acl;
29EXEC SQL END DECLARE SECTION;
30
31char *Argv[QMAXARGS];
32extern char *table_name[];
33extern char *sqlbuffer[QMAXARGS];
34
35int dbms_errno = 0;
36int mr_errcode = 0;
37EXEC SQL BEGIN DECLARE SECTION;
38int query_timeout = 30;
39char *database = "moira";
40EXEC SQL END DECLARE SECTION;
41extern char *whoami;
42extern FILE *journal;
43extern int QueryCount, max_version;
44extern struct query Queries[];
45
46/* Put this in a variable so that we can patch it if necessary */
47int max_row_count = 8192;
48
49int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[]);
50int do_retrieve(struct query *q, char *pqual,
51 int (*action)(int, char *[], void *), void *actarg);
52int do_update(struct query *q, char *argv[], char *qual,
53 int (*action)(int, char *[], void *), void *actarg);
54int do_append(struct query *q, char *argv[], char *pqual,
55 int (*action)(int, char *[], void *), void *actarg);
56int do_delete(struct query *q, char *qual,
57 int (*action)(int, char *[], void *), void *actarg);
58void build_sql_stmt(char *result_buf, char *cmd, char *targetlist,
59 char *argv[], char *qual);
60
61SQLDA *mr_alloc_sqlda(void);
62void sqlglm(char *, int *, int *);
63
64/*
65 * dbmserr: Called when the DBMS indicates an error.
66 */
67
68void dbmserr(void)
69{
70 EXEC SQL BEGIN DECLARE SECTION;
71 char err_msg[256];
72 EXEC SQL END DECLARE SECTION;
73 int bufsize = 256, msglength = 0;
74
75 dbms_errno = -sqlca.sqlcode;
76 mr_errcode = MR_DBMS_ERR;
77 com_err(whoami, MR_DBMS_ERR, " code %d\n", dbms_errno);
78 sqlglm(err_msg, &bufsize, &msglength);
79 err_msg[msglength] = 0;
80 com_err(whoami, 0, "SQL error text = %s", err_msg);
81 critical_alert(whoami, "MOIRA", "Moira server encountered DBMS ERROR %d\n%s",
82 dbms_errno, err_msg);
83}
84
85/* This is declarative, not executed. Applies from here on, in this file. */
86EXEC SQL WHENEVER SQLERROR DO dbmserr();
87
88int mr_open_database(void)
89{
90 int i;
91 static int first_open = 1;
92
93 if (first_open)
94 {
95 first_open = 0;
96
97 /* initialize local argv */
98 for (i = 0; i < QMAXARGS; i++)
99 Argv[i] = xmalloc(MAX_FIELD_WIDTH);
100
101 mr_sqlda = mr_alloc_sqlda();
102
103 incremental_init();
104 }
105
106 dbms_errno = 0;
107 mr_errcode = 0;
108
109 /* open the database */
110 EXEC SQL CONNECT :database IDENTIFIED BY :database;
111
112 if (dbms_errno)
113 return mr_errcode;
114
115 EXEC SQL SELECT list_id INTO :proxy_acl FROM capacls
116 WHERE capability = 'proxy';
117 if (dbms_errno)
118 return mr_errcode;
119
120 return MR_SUCCESS;
121}
122
123void mr_close_database(void)
124{
125 EXEC SQL COMMIT RELEASE;
126}
127
128int mr_check_access(client *cl, char *name, int argc, char *argv_ro[])
129{
130 struct query *q;
131
132 dbms_errno = 0;
133 mr_errcode = 0;
134
135 q = get_query_by_name(name, cl->version);
136 if (!q)
137 return MR_NO_HANDLE;
138
139 return mr_verify_query(cl, q, argc, argv_ro);
140}
141
142int mr_process_query(client *cl, char *name, int argc, char *argv_ro[],
143 int (*action)(int, char *[], void *), void *actarg)
144{
145 struct query *q;
146 int status;
147 struct validate *v;
148 char *qual = NULL;
149 EXEC SQL BEGIN DECLARE SECTION;
150 char *table;
151 EXEC SQL END DECLARE SECTION;
152 struct save_queue *sq;
153
154 dbms_errno = 0;
155 mr_errcode = 0;
156
157 /* list queries command */
158 if (!strcmp(name, "_list_queries"))
159 {
160 list_queries(cl, action, actarg);
161 return MR_SUCCESS;
162 }
163
164 /* help query command */
165 if (!strcmp(name, "_help"))
166 {
167 if (argc < 1)
168 return MR_ARGS;
169 q = get_query_by_name(argv_ro[0], cl->version);
170 if (!q)
171 return MR_NO_HANDLE;
172 help_query(q, action, actarg);
173 return MR_SUCCESS;
174 }
175
176 /* get query structure, return error if named query does not exist */
177 q = get_query_by_name(name, cl->version);
178 if (!q)
179 return MR_NO_HANDLE;
180 v = q->validate;
181
182 /* setup argument vector, verify access and arguments */
183 if ((status = mr_verify_query(cl, q, argc, argv_ro)) != MR_SUCCESS)
184 goto out;
185
186 /* perform any special query pre-processing */
187 if (v && v->pre_rtn)
188 {
189 status = (*v->pre_rtn)(q, Argv, cl);
190 if (status != MR_SUCCESS)
191 goto out;
192 }
193
194 switch (q->type)
195 {
196 case MR_Q_RETRIEVE:
197 /* for queries that do not permit wildcarding, check if row
198 uniquely exists */
199 if (v && v->field)
200 {
201 status = validate_row(q, Argv, v);
202 if (status != MR_EXISTS)
203 break;
204 }
205
206 /* build "where" clause if needed */
207 if (q->qual)
208 qual = build_qual(q->qual, q->argc, Argv);
209
210 /* if there is a followup routine, then we must save the results */
211 /* of the first query for use by the followup routine */
212 /* if q->rvar = NULL, perform post_rtn only */
213 if (q->rvar)
214 {
215 if (v && v->post_rtn)
216 {
217 sq = sq_create();
218 status = do_retrieve(q, qual, sq_save_args, sq);
219 if (status != MR_SUCCESS)
220 {
221 char **argv;
222 int i;
223
224 while (sq_get_data(sq, &argv))
225 {
226 for (i = 0; i < q->vcnt; i++)
227 free(argv[i]);
228 free(argv);
229 }
230 sq_destroy(sq);
231 break;
232 }
233 status = (*v->post_rtn)(q, sq, v, action, actarg, cl);
234 }
235 else
236 {
237 /* normal retrieve */
238 status = do_retrieve(q, qual, action, actarg);
239 }
240 if (status != MR_SUCCESS)
241 break;
242 }
243 else
244 status = (*v->post_rtn)(q, Argv, cl, action, actarg);
245
246 break;
247
248 case MR_Q_UPDATE:
249 /* see if row already exists */
250 if (v->field)
251 {
252 status = validate_row(q, Argv, v);
253 if (status != MR_EXISTS)
254 break;
255 }
256
257 /* build "where" clause and perform update */
258 /* if q->rvar = NULL, perform post_rtn only */
259 if (q->rvar)
260 {
261 qual = build_qual(q->qual, q->argc, Argv);
262 incremental_before(q->rtable, qual, argv_ro);
263 status = do_update(q, &Argv[q->argc], qual, action, actarg);
264 incremental_after(q->rtable, qual, argv_ro);
265 if (status != MR_SUCCESS)
266 break;
267 table = table_name[q->rtable];
268 if (strcmp(q->shortname, "sshi") && strcmp(q->shortname, "ssif"))
269 {
270 EXEC SQL UPDATE tblstats
271 SET updates = updates + 1, modtime = SYSDATE
272 WHERE table_name = :table;
273 }
274 }
275
276 /* execute followup routine (if any) */
277 if (v->post_rtn)
278 status = (*v->post_rtn)(q, Argv, cl);
279
280 break;
281
282 case MR_Q_APPEND:
283 /* see if row already exists */
284 if (v->field)
285 {
286 status = validate_row(q, Argv, v);
287 if (status != MR_NO_MATCH)
288 break;
289 }
290
291 /* build "where" clause if needed */
292 if (q->qual)
293 qual = build_qual(q->qual, q->argc, Argv);
294
295 /* perform the append */
296 /* if q->rvar = NULL, perform post_rtn only */
297 if (q->rvar)
298 {
299 incremental_clear_before();
300 status = do_append(q, &Argv[q->argc], qual, action, actarg);
301 if (status != MR_SUCCESS)
302 break;
303 if (v && v->object_id)
304 {
305 qual = realloc(qual, 15 + strlen(q->rvar) +
306 strlen(Argv[q->argc + q->vcnt]));
307 sprintf(qual, "%s.%s = %s", q->rvar, v->object_id,
308 Argv[q->argc + q->vcnt]);
309 incremental_after(q->rtable, qual, argv_ro);
310 }
311 else
312 incremental_after(q->rtable, qual, argv_ro);
313
314 table = table_name[q->rtable];
315 EXEC SQL UPDATE tblstats
316 SET appends = appends + 1, modtime = SYSDATE
317 WHERE table_name = :table;
318 }
319
320 /* execute followup routine */
321 if (v->post_rtn)
322 status = (*v->post_rtn)(q, Argv, cl);
323 break;
324
325 case MR_Q_DELETE:
326 /* see if row already exists */
327 if (v->field)
328 {
329 status = validate_row(q, Argv, v);
330 if (status != MR_EXISTS)
331 break;
332 }
333
334 /* build "where" clause and perform delete */
335 /* if q->rvar = NULL, perform post_rtn only */
336 if (q->rvar)
337 {
338 qual = build_qual(q->qual, q->argc, Argv);
339 table = table_name[q->rtable];
340 incremental_before(q->rtable, qual, argv_ro);
341 status = do_delete(q, qual, action, actarg);
342 incremental_clear_after();
343 if (status != MR_SUCCESS)
344 break;
345 EXEC SQL UPDATE tblstats
346 SET deletes = deletes + 1, modtime = SYSDATE
347 WHERE table_name = :table;
348 }
349
350 /* execute followup routine */
351 if (v->post_rtn)
352 status = (*v->post_rtn)(q, Argv, cl);
353 break;
354
355 case MR_Q_SPECIAL:
356 break;
357 }
358
359out:
360 free(qual);
361
362 if (status == MR_SUCCESS && dbms_errno != 0)
363 {
364 com_err(whoami, MR_INTERNAL, "Server didn't notice DBMS ERROR %d",
365 dbms_errno);
366 status = mr_errcode;
367 }
368
369 if (q->type == MR_Q_RETRIEVE)
370 EXEC SQL COMMIT WORK;
371 else
372 {
373 if (status == MR_SUCCESS)
374 {
375 EXEC SQL COMMIT WORK;
376 if (journal)
377 {
378 char *buf;
379 int i;
380 extern time_t now;
381
382 fprintf(journal, "%% %s %s %s",
383 cl->clname, cl->entity, ctime(&now));
384 fprintf(journal, "%s ", q->name);
385 for (i = 0; i < argc; i++)
386 {
387 if (i != 0)
388 putc(' ', journal);
389 buf = requote(argv_ro[i]);
390 fputs(buf, journal);
391 free(buf);
392 }
393 putc('\n', journal);
394 fflush(journal);
395 }
396 incremental_update();
397 }
398 else
399 {
400 EXEC SQL ROLLBACK WORK;
401 incremental_flush();
402 }
403 }
404
405 if (status != MR_SUCCESS)
406 com_err(whoami, status, " (Query failed)");
407 return status;
408}
409
410char *build_qual(char *fmt_buf, int argc, char *argv[])
411{
412 char *res, *result_buf, *fmt, *arg, *like, *p;
413
414 result_buf = xmalloc(2 * (strlen(fmt_buf) + argc * ARGLEN));
415
416 res = result_buf;
417 fmt = fmt_buf;
418
419 like = strstr(fmt, "LIKE");
420 arg = strchr(fmt, '%');
421
422 /* Look through the format for LIKE expressions and arguments.
423 Substitute in the arguments, simplify the `LIKE's to `='s
424 where possible, and insert ESCAPE clauses where needed */
425
426 while (*fmt)
427 {
428
429 if ((!like && !arg) || argc == 0)
430 {
431 /* only plain text remains */
432 strcpy(res, fmt);
433 res = strchr(res, '\0');
434 break;
435 }
436 else if (!like || arg < like)
437 {
438 /* regular arg: copy up to arg, then substitute */
439 strncpy(res, fmt, arg - fmt);
440 res += arg - fmt;
441 if (*++arg)
442 {
443 switch (*arg++)
444 {
445 case '%':
446 *res++ = '%';
447 break;
448
449 case 's':
450 p = *argv;
451 /* copy string, doubling single quotes */
452 while (*p)
453 {
454 if (*p == '\'')
455 *res++ = '\'';
456 *res++ = *p++;
457 }
458 argv++;
459 break;
460
461 case 'd':
462 res += sprintf(res, "%d", *(int *)*argv++);
463 break;
464 }
465 }
466 fmt = arg;
467 arg = strchr(fmt, '%');
468 } else {
469 /* LIKE arg: copy over up to the arg, then copy and convert arg */
470 int escape = 0, pattern = 0;
471 char *likepos = res + (like - fmt);
472
473 strncpy(res, fmt, arg - fmt);
474 res += arg - fmt;
475
476 /* copy arg, converting UNIX globs to `SQL voodoo', and noting
477 if we'll need an ESCAPE clause */
478 for (p = *argv++; *p; p++)
479 {
480 switch (*p)
481 {
482 case '*':
483 *res++ = '%';
484 *res++ = '%'; /* need to double for build_sql_stmt */
485 pattern = 1;
486 break;
487
488 case '?':
489 *res++ = '_';
490 pattern = 1;
491 break;
492
493 case '%':
494 case '_':
495 *res++ = '*';
496 *res++ = *p;
497 if (*p == '%')
498 *res++ = *p;
499 escape = 1;
500 break;
501
502 case '\'':
503 *res++ = '\'';
504 /* fall through */
505
506 default:
507 *res++ = *p;
508 }
509 }
510
511 /* if no pattern characters, write over "LIKE" with " = " */
512 if (!pattern && !escape)
513 memcpy(likepos, " = ", 4);
514
515 fmt = arg + 2;
516 while (*fmt && *fmt != ' ')
517 *res++ = *fmt++;
518
519 if (escape)
520 res += sprintf(res, " ESCAPE '*'");
521
522 arg = strchr(fmt, '%');
523 like = strstr(fmt, "LIKE");
524 }
525 }
526
527 *res = '\0';
528 result_buf = realloc(result_buf, strlen(result_buf) + 1);
529 return result_buf;
530}
531
532/* Build arguement vector, verify query and arguments */
533
534int privileged;
535
536int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[])
537{
538 int argreq;
539 int status;
540 struct validate *v = q->validate;
541 int i;
542 char *to, *fr, *stop;
543
544 privileged = 0;
545
546 /* check argument count */
547 argreq = q->argc;
548 if (q->type == MR_Q_UPDATE || q->type == MR_Q_APPEND)
549 argreq += q->vcnt;
550 if (argc != argreq)
551 return MR_ARGS;
552
553 /* copy the arguments into a local argv that we can modify */
554 for (i = 0; i < argc; i++)
555 {
556 for (to = Argv[i], fr = argv_ro[i], stop = to + MAX_FIELD_WIDTH; (*fr) && (to < stop);)
557 *to++ = *fr++;
558
559 if (*fr)
560 return MR_ARG_TOO_LONG;
561 *to = '\0';
562 }
563
564 /* Check initial query access. If we're acting as a proxy, only allow
565 * access if the query has "default" as a capacl.
566 */
567 status = check_query_access(q, Argv, cl);
568 if (status != MR_SUCCESS && status != MR_PERM)
569 return status;
570 if (status == MR_SUCCESS && (!cl->proxy_id || q->everybody))
571 privileged++;
572
573 /* validate arguments */
574 if (v && v->valobj)
575 {
576 status = validate_fields(q, Argv, v->valobj, v->objcnt);
577 if (status != MR_SUCCESS)
578 return status;
579 }
580
581 /* perform special query access check */
582 if (!privileged && v && v->acs_rtn)
583 {
584 status = (*v->acs_rtn)(q, Argv, cl);
585 if (status != MR_SUCCESS && status != MR_PERM)
586 return status;
587 if (status == MR_SUCCESS)
588 return MR_SUCCESS;
589 }
590
591 return privileged ? MR_SUCCESS : MR_PERM;
592}
593
594int check_query_access(struct query *q, char *argv[], client *cl)
595{
596 EXEC SQL BEGIN DECLARE SECTION;
597 char *name;
598 int acl_id;
599 static int def_uid;
600 EXEC SQL END DECLARE SECTION;
601
602 /* initialize default uid */
603 if (def_uid == 0)
604 EXEC SQL SELECT users_id INTO :def_uid FROM users WHERE login = 'default';
605
606 name = q->shortname;
607 EXEC SQL SELECT list_id INTO :acl_id FROM capacls WHERE tag = :name;
608 if (sqlca.sqlcode < 0)
609 return MR_DBMS_ERR;
610 if (sqlca.sqlcode == SQL_NO_MATCH)
611 return MR_PERM;
612 q->acl = acl_id;
613
614 /* check for default access */
615 EXEC SQL SELECT member_id INTO :acl_id FROM imembers
616 WHERE list_id = :acl_id AND member_type = 'USER'
617 AND member_id = :def_uid;
618 if (sqlca.sqlerrd[2] == 0)
619 q->everybody = 0;
620 else
621 q->everybody = 1;
622
623 if (q->everybody)
624 return MR_SUCCESS;
625
626 if (find_member("LIST", acl_id, cl))
627 return MR_SUCCESS;
628 else
629 return MR_PERM;
630}
631
632int find_member(char *list_type, int list_id, client *cl)
633{
634 EXEC SQL BEGIN DECLARE SECTION;
635 int flag, users_id, client_id;
636 EXEC SQL END DECLARE SECTION;
637
638 if (!strcmp(strtrim(list_type), "USER") && list_id == cl->users_id)
639 return 1;
640
641 if (!strcmp(strtrim(list_type), "KERBEROS") && list_id == -cl->client_id)
642 return 1;
643
644 if (!strcmp(strtrim(list_type), "LIST"))
645 {
646 /* see if client is a member of list */
647 flag = 0;
648 users_id = cl->users_id;
649 client_id = -cl->client_id;
650 EXEC SQL SELECT COUNT(member_id) INTO :flag FROM imembers
651 WHERE list_id = :list_id
652 AND ( ( member_type = 'USER' AND member_id = :users_id )
653 OR (member_type = 'KERBEROS' AND member_id = :client_id ) );
654 if (sqlca.sqlcode == 0)
655 return flag;
656 }
657
658 return 0;
659}
660
661
662int do_retrieve(struct query *q, char *pqual,
663 int (*action)(int, char *[], void *), void *actarg)
664{
665 build_sql_stmt(stmt_buf, "SELECT", q->tlist, NULL, pqual);
666 if (q->sort)
667 {
668 strcat(stmt_buf, " ORDER BY ");
669 strcat(stmt_buf, q->sort);
670 }
671
672 return do_for_all_rows(stmt_buf, q->vcnt, action, actarg);
673}
674
675void build_sql_stmt(char *result_buf, char *cmd, char *targetlist,
676 char *argv[], char *qual)
677{
678 char fmt_buf[MR_STMTBUF_LEN];
679 char *res, *fmt;
680
681 if (qual)
682 sprintf(fmt_buf, "%s %s WHERE %s", cmd, targetlist, qual);
683 else
684 sprintf(fmt_buf, "%s %s", cmd, targetlist);
685
686 for (res = result_buf, fmt = fmt_buf; *fmt; fmt++)
687 {
688 if (*fmt == '%')
689 {
690 if (*++fmt)
691 {
692 switch (*fmt)
693 {
694 case '%': /* %% -> % */
695 *res++ = *fmt;
696 break;
697 case 's':
698 if (*argv[0])
699 {
700 char *p = *argv;
701 while (*p)
702 {
703 if (*p == '\'')
704 *res++ = '\''; /* double the ' */
705 *res++ = *p++;
706 }
707 }
708 argv++;
709 break;
710 case 'd':
711 res += sprintf(res, "%d", *(int *)*argv++);
712 break;
713 default: /* Swallow other %? pairs */
714 break;
715 }
716 }
717 else
718 break;
719 }
720 else
721 *res++ = *fmt; /* text -> result buffer */
722 }
723 *res = '\0';
724}
725
726int do_update(struct query *q, char *argv[], char *qual,
727 int (*action)(int, char *[], void *), void *actarg)
728{
729 build_sql_stmt(stmt_buf, "UPDATE", q->tlist, argv, qual);
730 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
731 if (mr_errcode)
732 return mr_errcode;
733 return MR_SUCCESS;
734}
735
736int do_append(struct query *q, char *argv[], char *pqual,
737 int (*action)(int, char *[], void *), void *actarg)
738{
739 build_sql_stmt(stmt_buf, "INSERT", q->tlist, argv, pqual);
740 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
741 if (mr_errcode)
742 return mr_errcode;
743 return MR_SUCCESS;
744}
745
746int do_delete(struct query *q, char *qual,
747 int (*action)(int, char *[], void *), void *actarg)
748{
749 sprintf(stmt_buf, "DELETE FROM %s WHERE %s", table_name[q->rtable], qual);
750 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
751 if (mr_errcode)
752 return mr_errcode;
753 return MR_SUCCESS;
754}
755
756
757/**
758 ** set_next_object_id - set next object id in values table
759 **
760 ** Inputs: object - object name in values table and in objects
761 ** table - name of table objects are found in
762 ** limit - should the ID be range limited
763 **
764 ** - called before an MR_Q_APPEND operation to set the next object id to
765 ** be used for the new record to the next free value
766 **
767 **/
768
769int set_next_object_id(char *object, enum tables table, int limit)
770{
771 EXEC SQL BEGIN DECLARE SECTION;
772 int value;
773 char *obj = object;
774 EXEC SQL END DECLARE SECTION;
775 int starting_value;
776
777 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :obj;
778 if (sqlca.sqlerrd[2] != 1)
779 return MR_NO_ID;
780
781 starting_value = value;
782 while (1)
783 {
784#ifdef ULTRIX_ID_HOLE
785 if (limit && value > 31999 && value < 32768)
786 value = 32768;
787#endif
788 if (limit && value > MAX_ID_VALUE)
789 value = MIN_ID_VALUE;
790
791 sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = %d",
792 object, table_name[table], object, value);
793 dosql(sqlbuffer);
794 if (sqlca.sqlcode < 0)
795 return mr_errcode;
796 if (sqlca.sqlcode == SQL_NO_MATCH)
797 break;
798
799 value++;
800 if (limit && value == starting_value)
801 {
802 com_err(whoami, 0, "All id values have been used");
803 return MR_NO_ID;
804 }
805 }
806
807 com_err(whoami, 0, "setting ID %s to %d", object, value);
808 EXEC SQL UPDATE numvalues SET value = :value WHERE name = :obj;
809 return MR_SUCCESS;
810}
811
812
813/* Turn a kerberos name into the user's ID of the account that principal
814 * owns. Sets the kerberos ID and user ID.
815 */
816
817int set_krb_mapping(char *name, char *login, int ok, int *kid, int *uid)
818{
819 EXEC SQL BEGIN DECLARE SECTION;
820 int u_id, k_id;
821 char *krbname;
822 EXEC SQL END DECLARE SECTION;
823
824 krbname = name;
825 *kid = 0;
826 *uid = 0;
827
828 EXEC SQL SELECT km.users_id, km.string_id INTO :u_id, :k_id
829 FROM krbmap km, strings str
830 WHERE km.string_id = str.string_id AND str.string = :krbname;
831 EXEC SQL COMMIT WORK;
832
833 if (dbms_errno)
834 return mr_errcode;
835
836 if (sqlca.sqlerrd[2] == 1)
837 {
838 *kid = -k_id;
839 *uid = u_id;
840 return MR_SUCCESS;
841 }
842
843 if (name_to_id(name, STRINGS_TABLE, &k_id) == MR_SUCCESS)
844 *kid = -k_id;
845
846 if (!ok)
847 {
848 *uid = *kid;
849 return MR_SUCCESS;
850 }
851
852 if (name_to_id(login, USERS_TABLE, uid) != MR_SUCCESS)
853 *uid = 0;
854
855 if (*kid == 0)
856 *kid = *uid;
857 if (dbms_errno)
858 return mr_errcode;
859 return MR_SUCCESS;
860}
861
862
863void sanity_check_queries(void)
864{
865 int i;
866 int maxv = 0, maxa = 0;
867
868#define MAX(x, y) ((x) > (y) ? (x) : (y))
869
870 for (i = 0; i < QueryCount; i++)
871 {
872 maxv = MAX(maxv, Queries[i].vcnt);
873 maxa = MAX(maxa, Queries[i].argc);
874 max_version = MAX(max_version, Queries[i].version);
875 }
876 if (MAX(maxv, maxa) > QMAXARGS)
877 {
878 com_err(whoami, 0, "A query has more args than QMAXARGS");
879 exit(1);
880 }
881}
882
883
884/* Generically do a SELECT, storing the results in the provided buffers */
885
886void dosql(char *buffers[])
887{
888 int i, errcode = 0, errlen;
889
890 EXEC SQL PREPARE inc_stmt FROM :stmt_buf;
891 if (sqlca.sqlcode)
892 return;
893 EXEC SQL DECLARE inc_crs CURSOR FOR inc_stmt;
894 EXEC SQL OPEN inc_crs;
895 mr_sqlda->N = QMAXARGS;
896 EXEC SQL DESCRIBE SELECT LIST FOR inc_stmt INTO mr_sqlda;
897 mr_sqlda->N = mr_sqlda->F;
898 for (i = 0; i < mr_sqlda->N; i++)
899 {
900 mr_sqlda->V[i] = buffers[i];
901 mr_sqlda->T[i] = 97;
902 mr_sqlda->L[i] = MAX_FIELD_WIDTH;
903 }
904 EXEC SQL FETCH inc_crs USING DESCRIPTOR mr_sqlda;
905
906 /* if we got an error from the FETCH, we have to preserve it or the
907 close will reset it and the caller will think nothing happened */
908 if (sqlca.sqlcode)
909 {
910 errcode = sqlca.sqlcode;
911 errlen = sqlca.sqlerrm.sqlerrml;
912 }
913
914 EXEC SQL CLOSE inc_crs;
915 if (errcode)
916 {
917 sqlca.sqlcode = errcode;
918 sqlca.sqlerrm.sqlerrml = errlen;
919 }
920}
921
922int do_for_all_rows(char *query, int count,
923 int (*action)(int, char *[], void *), void *actarg)
924{
925 int i, rowcount = 0;
926 EXEC SQL BEGIN DECLARE SECTION;
927 char *q = query;
928 EXEC SQL END DECLARE SECTION;
929
930 EXEC SQL PREPARE stmt FROM :q;
931 if (sqlca.sqlcode)
932 return MR_INTERNAL;
933 EXEC SQL DECLARE curs CURSOR FOR stmt;
934 EXEC SQL OPEN curs;
935 mr_sqlda->N = count;
936 EXEC SQL DESCRIBE SELECT LIST FOR stmt INTO mr_sqlda;
937 mr_sqlda->N = mr_sqlda->F;
938 for (i = 0; i < mr_sqlda->N; i++)
939 {
940 mr_sqlda->V[i] = sqlbuffer[i];
941 mr_sqlda->T[i] = 97;
942 mr_sqlda->L[i] = MAX_FIELD_WIDTH;
943 }
944
945 while (rowcount < max_row_count)
946 {
947 EXEC SQL FETCH curs USING DESCRIPTOR mr_sqlda;
948 if (sqlca.sqlcode)
949 break;
950 (*action)(count, sqlbuffer, actarg);
951 rowcount++;
952 }
953 EXEC SQL CLOSE curs;
954
955 if (mr_errcode)
956 return mr_errcode;
957 if (rowcount == max_row_count)
958 {
959 critical_alert(whoami, "moirad", "attempted query with too many rows");
960 return MR_NO_MEM;
961 }
962 else if (rowcount == 0)
963 return MR_NO_MATCH;
964 else
965 return MR_SUCCESS;
966}
967
968/* Do a name to ID translation. Moved from cache.pc because we did away
969 * with the cache, but what this function does is still useful to us.
970 */
971
972int name_to_id(char *name, enum tables type, int *id)
973{
974 EXEC SQL BEGIN DECLARE SECTION;
975 char *iname;
976 int j;
977 EXEC SQL END DECLARE SECTION;
978
979 iname = name;
980
981 switch (type)
982 {
983 case USERS_TABLE:
984 if (strchr(iname, '@') || (strlen(iname) > 8))
985 {
986 sqlca.sqlcode = SQL_NO_MATCH;
987 break;
988 }
989 EXEC SQL SELECT users_id INTO :j FROM users WHERE login = :iname;
990 break;
991 case LIST_TABLE:
992 EXEC SQL SELECT list_id INTO :j FROM list WHERE name = :iname;
993 break;
994 case MACHINE_TABLE:
995 EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name = UPPER(:iname);
996 break;
997 case SUBNET_TABLE:
998 EXEC SQL SELECT snet_id INTO :j FROM subnet WHERE name = UPPER(:iname);
999 break;
1000 case CLUSTERS_TABLE:
1001 EXEC SQL SELECT clu_id INTO :j FROM clusters WHERE name = :iname;
1002 break;
1003 case FILESYS_TABLE:
1004 EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label = :iname;
1005 break;
1006 case STRINGS_TABLE:
1007 if (!iname[0]) /* special-case empty string */
1008 {
1009 *id = 0;
1010 return MR_SUCCESS;
1011 }
1012 EXEC SQL SELECT string_id INTO :j FROM strings WHERE string = :iname;
1013 break;
1014 case CONTAINERS_TABLE:
1015 EXEC SQL SELECT cnt_id INTO :j FROM containers WHERE LOWER(name) =
1016 LOWER(:iname);
1017 break;
1018 default:
1019 return MR_INTERNAL;
1020 }
1021 if (sqlca.sqlcode == SQL_NO_MATCH)
1022 return MR_NO_MATCH;
1023 if (sqlca.sqlerrd[2] > 1)
1024 return MR_NOT_UNIQUE;
1025 if (sqlca.sqlcode)
1026 return MR_DBMS_ERR;
1027 *id = j;
1028
1029 return MR_SUCCESS;
1030}
1031
1032/* Perform an ID to name mapping. name should be a pointer to a pointer to
1033 * malloc'ed data. The buffer it refers to will be freed, and a new buffer
1034 * allocated with the answer.
1035 *
1036 * This used to be in cache.pc, but we've removed the cache, and this function
1037 * is still useful to us.
1038 */
1039
1040int id_to_name(int id, enum tables type, char **name)
1041{
1042 EXEC SQL BEGIN DECLARE SECTION;
1043 char iname[MAX_FIELD_WIDTH];
1044 int j;
1045 EXEC SQL END DECLARE SECTION;
1046
1047 j = id;
1048
1049 switch (type)
1050 {
1051 case USERS_TABLE:
1052 EXEC SQL SELECT login INTO :iname FROM users WHERE users_id = :j;
1053 break;
1054 case LIST_TABLE:
1055 EXEC SQL SELECT name INTO :iname FROM list WHERE list_id = :j;
1056 break;
1057 case MACHINE_TABLE:
1058 EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id = :j;
1059 break;
1060 case SUBNET_TABLE:
1061 EXEC SQL SELECT name INTO :iname FROM subnet WHERE snet_id = :j;
1062 break;
1063 case CLUSTERS_TABLE:
1064 EXEC SQL SELECT name INTO :iname FROM clusters WHERE clu_id = :j;
1065 break;
1066 case FILESYS_TABLE:
1067 EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id = :j;
1068 break;
1069 case STRINGS_TABLE:
1070 EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id = :j;
1071 break;
1072 case CONTAINERS_TABLE:
1073 EXEC SQL SELECT name INTO :iname FROM containers WHERE cnt_id = :j;
1074 break;
1075 default:
1076 return MR_INTERNAL;
1077 }
1078 if (sqlca.sqlcode == SQL_NO_MATCH)
1079 {
1080 free(*name);
1081 sprintf(iname, "#%d", j);
1082 *name = xstrdup(iname);
1083 return MR_NO_MATCH;
1084 }
1085 if (sqlca.sqlerrd[2] > 1)
1086 return MR_INTERNAL;
1087 if (sqlca.sqlcode)
1088 return MR_DBMS_ERR;
1089 free(*name);
1090 *name = xstrdup(strtrim(iname));
1091
1092 return MR_SUCCESS;
1093}
1094
1095/* eof:qrtn.dc */
This page took 0.041381 seconds and 5 git commands to generate.