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