]> andersk Git - moira.git/blob - server/qrtn.pc
Make sure acl_type is LIST before using the object id as a list_id.
[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 char stmt_buf[MR_STMTBUF_LEN];
28 int proxy_acl;
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 extern int QueryCount, max_version;
44 extern struct query Queries[];
45
46 /* Put this in a variable so that we can patch it if necessary */
47 int max_row_count = 8192;
48
49 int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[]);
50 int do_retrieve(struct query *q, char *pqual,
51                 int (*action)(int, char *[], void *), void *actarg);
52 int do_update(struct query *q, char *argv[], char *qual,
53               int (*action)(int, char *[], void *), void *actarg);
54 int do_append(struct query *q, char *argv[], char *pqual,
55               int (*action)(int, char *[], void *), void *actarg);
56 int do_delete(struct query *q, char *qual,
57               int (*action)(int, char *[], void *), void *actarg);
58 void build_sql_stmt(char *result_buf, char *cmd, char *targetlist,
59                     char *argv[], char *qual);
60
61 SQLDA *mr_alloc_sqlda(void);
62 void sqlglm(char *, int *, int *);
63
64 /*
65  * dbmserr: Called when the DBMS indicates an error.
66  */
67
68 void 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. */
86 EXEC SQL WHENEVER SQLERROR DO dbmserr();
87
88 int 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
123 void mr_close_database(void)
124 {
125   EXEC SQL COMMIT RELEASE;
126 }
127
128 int 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
142 int 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
359 out:
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
410 char *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
534 int privileged;
535
536 int 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
594 int 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
632 int 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
662 int 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
675 void 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
726 int 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
736 int 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
746 int 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
769 int 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
817 int 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
863 void 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
886 void 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
922 int 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
972 int 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
1040 int 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.123777 seconds and 5 git commands to generate.