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