]> andersk Git - moira.git/blob - server/qvalidate.pc
oracle doesn't do [ and ] in its pseudo-regexps, so don't treat them
[moira.git] / server / qvalidate.pc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *      For copying and distribution information, please see the file
8  *      <mit-copyright.h>.
9  *
10  */
11
12 #ifndef lint
13 static char *rcsid_qsupport_dc = "$Header$";
14 #endif lint
15
16 #include <mit-copyright.h>
17 #include <unistd.h>
18 #include "mr_server.h"
19 #include "query.h"
20 #include <ctype.h>
21 #include <string.h>
22 EXEC SQL INCLUDE sqlca;
23 EXEC SQL INCLUDE sqlda;
24 #include "qrtn.h"
25
26 extern char *whoami, *table_name[], *sqlbuffer[QMAXARGS];
27 extern int dbms_errno, mr_errcode;
28
29 EXEC SQL BEGIN DECLARE SECTION;
30 extern char stmt_buf[];
31 EXEC SQL END DECLARE SECTION;
32
33 int validate_chars(char *argv[], struct valobj *vo);
34 int validate_id(struct query *, char *argv[], struct valobj *vo);
35 int validate_name(char *argv[], struct valobj *vo);
36 int validate_rename(char *argv[], struct valobj *vo);
37 int validate_type(char *argv[], struct valobj *vo);
38 int validate_typedata(struct query *, char *argv[], struct valobj *vo);
39 int validate_len(char *argv[], struct valobj *vo);
40 int lock_table(struct valobj *vo);
41 int readlock_table(struct valobj *vo);
42 int convert_wildcards_uppercase(char *arg);
43
44 extern SQLDA *sqlald(int,int,int);
45
46 EXEC SQL WHENEVER SQLERROR DO dbmserr();
47
48 /* Validation Routines */
49
50 int validate_row(q, argv, v)
51     register struct query *q;
52     char *argv[];
53     register struct validate *v;
54 {
55     EXEC SQL BEGIN DECLARE SECTION;
56     char qual[128];
57     int rowcount;
58     EXEC SQL END DECLARE SECTION;
59
60     /* build where clause */
61     build_qual(v->qual, v->argc, argv, qual);
62
63     if (log_flags & LOG_VALID)
64         /* tell the logfile what we're doing */
65         com_err(whoami, 0, "validating row: %s", qual);
66
67     /* look for the record */
68     sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",
69             table_name[q->rtable],qual);
70     dosql(sqlbuffer);
71     if (dbms_errno) return(mr_errcode);
72
73     rowcount = atoi(sqlbuffer[0]);
74     if (rowcount == 0) return(MR_NO_MATCH);
75     if (rowcount > 1) return(MR_NOT_UNIQUE);
76     return(MR_EXISTS);
77 }
78
79 int validate_fields(q, argv, vo, n)
80     struct query *q;
81     register char *argv[];
82     register struct valobj *vo;
83     register int n;
84 {
85     register int status;
86
87     while (--n >= 0) {
88         switch (vo->type) {
89         case V_NAME:
90             if (log_flags & LOG_VALID)
91                 com_err(whoami, 0, "validating %s in %s: %s",
92                     vo->namefield, table_name[vo->table], argv[vo->index]);
93             status = validate_name(argv, vo);
94             break;
95
96         case V_ID:
97             if (log_flags & LOG_VALID)
98                 com_err(whoami, 0, "validating %s in %s: %s",
99                     vo->idfield, table_name[vo->table], argv[vo->index]);
100             status = validate_id(q, argv, vo);
101             break;
102
103             /*
104         case V_DATE:
105             if (log_flags & LOG_VALID)
106                 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
107             status = validate_date(argv, vo);
108             break;
109             */
110
111         case V_TYPE:
112             if (log_flags & LOG_VALID)
113                 com_err(whoami, 0, "validating %s type: %s",
114                     table_name[vo->table], argv[vo->index]);
115             status = validate_type(argv, vo);
116             break;
117
118         case V_TYPEDATA:
119             if (log_flags & LOG_VALID)
120                 com_err(whoami, 0, "validating typed data (%s): %s",
121                     argv[vo->index - 1], argv[vo->index]);
122             status = validate_typedata(q, argv, vo);
123             break;
124
125         case V_RENAME:
126             if (log_flags & LOG_VALID)
127                 com_err(whoami, 0, "validating rename %s in %s",
128                         argv[vo->index], table_name[vo->table]);
129             status = validate_rename(argv, vo);
130             break;
131
132         case V_CHAR:
133             if (log_flags & LOG_VALID)
134               com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
135             status = validate_chars(argv, vo);
136             break;
137
138         case V_LEN:
139             if (log_flags & LOG_VALID)
140               com_err(whoami, 0, "validating length: %s", argv[vo->index]);
141             status = validate_len(argv, vo);
142             break;
143
144         case V_SORT:
145             status = MR_EXISTS;
146             break;
147
148         case V_LOCK:
149             status = lock_table(vo);
150             break;
151
152         case V_RLOCK:
153             status = readlock_table(vo);
154             break;
155
156         case V_WILD:
157             status = convert_wildcards(argv[vo->index]);
158             break;
159
160         case V_UPWILD:
161             status = convert_wildcards_uppercase(argv[vo->index]);
162             break;
163
164         }
165
166         if (status != MR_EXISTS) return(status);
167         vo++;
168     }
169
170     if (dbms_errno) return(mr_errcode);
171     return(MR_SUCCESS);
172 }
173
174
175 /* validate_chars: verify that there are no illegal characters in
176  * the string.  Legal characters are printing chars other than
177  * ", *, ?, \, [ and ].
178  */
179 static int illegalchars[] = {
180     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
181     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
182     0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
183     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
184     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
185     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
186     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
187     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
188     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
189     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
190     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
191     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
192     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
193     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
194     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
195     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
196 };
197
198 int validate_chars(argv, vo)
199     char *argv[];
200     register struct valobj *vo;
201 {
202     char *s=argv[vo->index];
203     int arg;
204     EXEC SQL BEGIN DECLARE SECTION;
205     int len;
206     char *tname, *cname;
207     EXEC SQL END DECLARE SECTION;
208
209
210     /* check for bad characters */
211     while (*s)
212       if (illegalchars[*s++])
213         return(MR_BAD_CHAR);
214
215     /* check for length */
216     tname = table_name[vo->table];
217     cname = vo->namefield;
218     EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
219       WHERE table_name=UPPER(:tname) AND column_name=UPPER(:cname);
220
221     if((strlen(argv[vo->index]) > len) &&
222        strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
223       argv[vo->index][len]='\0'; /* truncate */
224
225     return MR_EXISTS;
226 }
227
228
229 int validate_id(q, argv, vo)
230     struct query *q;
231     char *argv[];
232     register struct valobj *vo;
233 {
234     EXEC SQL BEGIN DECLARE SECTION;
235     char *name, *namefield, *idfield;
236     int id, rowcount, tbl;
237     EXEC SQL END DECLARE SECTION;
238     int status;
239     register char *c;
240
241     name = argv[vo->index];
242     tbl = vo->table;
243     namefield = vo->namefield;
244     idfield = vo->idfield;
245
246     if ((tbl==USERS_TABLE && !strcmp(namefield, "login")) ||
247         tbl==MACHINE_TABLE || tbl==SUBNET_TABLE || tbl==FILESYS_TABLE ||
248         tbl==LIST_TABLE || tbl==CLUSTER_TABLE || tbl==STRINGS_TABLE) {
249       if (tbl==MACHINE_TABLE || tbl==SUBNET_TABLE)
250         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
251       status = name_to_id(name, tbl, &id);
252       if (status == 0) {
253         *(int *)argv[vo->index] = id;
254         return(MR_EXISTS);
255       } else if (status == MR_NO_MATCH && tbl==STRINGS_TABLE &&
256                  (q->type == APPEND || q->type == UPDATE)) {
257         id=add_string(name);
258         cache_entry(name, STRINGS_TABLE, id);
259         *(int *)argv[vo->index] = id;
260         return(MR_EXISTS);
261       } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
262         return(vo->error);
263       else
264         return(status);
265     } else {
266       /* else, it's `dubu', which uses unix_uid from users */
267       EXEC SQL SELECT COUNT(*) INTO :rowcount FROM users
268         WHERE unix_uid = :name;
269       if (dbms_errno) return(mr_errcode);
270       if (rowcount != 1) return(vo->error);
271       EXEC SQL SELECT users_id INTO :id FROM users
272         WHERE unix_uid = :name;
273       *(int *)argv[vo->index] = id;
274       return(MR_EXISTS);
275     }
276 }
277
278 int validate_name(argv, vo)
279     char *argv[];
280     register struct valobj *vo;
281 {
282     char *name, *namefield;
283     register char *c;
284
285     name = argv[vo->index];
286     namefield = vo->namefield;
287     if (vo->table==SERVERS_TABLE && !strcmp(namefield, "name")) {
288         for (c = name; *c; c++)
289           if (islower(*c))
290             *c = toupper(*c);
291     }
292     sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
293             table_name[vo->table],table_name[vo->table],namefield,name);
294     dosql(sqlbuffer);
295
296     if (dbms_errno) return(mr_errcode);
297     return ((atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error);
298 }
299
300 /*
301 validate_date(argv, vo)
302     char *argv[];
303     struct valobj *vo;
304 {
305     EXEC SQL BEGIN DECLARE SECTION;
306     char *idate;
307     double dd;
308     int errorno;
309     EXEC SQL END DECLARE SECTION;
310
311     idate = argv[vo->index];
312     EXEC SQL SELECT interval('years',date(:idate)-date('today')) INTO :dd;
313     if (sqlca.sqlcode != 0 || dd > 5.0) return(MR_DATE);
314     return(MR_EXISTS);
315 }
316 */
317
318 int validate_rename(argv, vo)
319      char *argv[];
320      struct valobj *vo;
321 {
322     EXEC SQL BEGIN DECLARE SECTION;
323     char *name, *namefield, *idfield;
324     int id;
325     EXEC SQL END DECLARE SECTION;
326     int status;
327     register char *c;
328
329     status = validate_chars(argv, vo);
330     if(status != MR_EXISTS) return status;
331     name=argv[vo->index];
332     /* minor kludge to upcasify machine names */
333     if (vo->table == MACHINE_TABLE)
334         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
335     namefield = vo->namefield;
336     idfield = vo->idfield;
337     id = -1;
338     if (idfield == 0) {
339         if (!strcmp(argv[vo->index], argv[vo->index - 1]))
340           return(MR_EXISTS);
341         sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",
342                 namefield,table_name[vo->table],namefield,name);
343         dosql(sqlbuffer);
344
345         if (dbms_errno) return(mr_errcode);
346         if (sqlca.sqlcode==SQL_NO_MATCH)
347           return(MR_EXISTS); /* how's _that_ for intuitive? */
348         else
349           return(vo->error);
350     }
351     status = name_to_id(name, vo->table, &id);
352     if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
353       return(MR_EXISTS);
354     else
355       return(vo->error);
356 }
357
358
359 int validate_type(argv, vo)
360     char *argv[];
361     register struct valobj *vo;
362 {
363     EXEC SQL BEGIN DECLARE SECTION;
364     char *typename;
365     char *val;
366     int cnt;
367     EXEC SQL END DECLARE SECTION;
368     register char *c;
369
370     typename = vo->namefield;
371     c = val = argv[vo->index];
372     while (*c) {
373         if (illegalchars[*c++])
374           return(MR_BAD_CHAR);
375     }
376
377     /* uppercase type fields */
378     for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
379
380     EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
381       WHERE name = :typename AND type='TYPE' AND trans = :val;
382     if (dbms_errno) return(mr_errcode);
383     return (cnt ? MR_EXISTS : vo->error);
384 }
385
386 /* validate member or type-specific data field */
387
388 int validate_typedata(q, argv, vo)
389     register struct query *q;
390     register char *argv[];
391     register struct valobj *vo;
392 {
393     EXEC SQL BEGIN DECLARE SECTION;
394     char *name;
395     char *field_type;
396     char data_type[129];
397     int id;
398     EXEC SQL END DECLARE SECTION;
399     int status;
400     register char *c;
401
402     /* get named object */
403     name = argv[vo->index];
404
405     /* get field type string (known to be at index-1) */
406     field_type = argv[vo->index-1];
407
408     /* get corresponding data type associated with field type name */
409     EXEC SQL SELECT trans INTO :data_type FROM alias
410       WHERE name = :field_type AND type='TYPEDATA';
411     if (dbms_errno) return(mr_errcode);
412     if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
413
414     /* now retrieve the record id corresponding to the named object */
415     if (strchr(data_type, ' '))
416         *strchr(data_type, ' ') = 0;
417     if (!strcmp(data_type, "user")) {
418         /* USER */
419         if (strchr(name, '@'))
420           return(MR_USER);
421         status = name_to_id(name, USERS_TABLE, &id);
422         if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
423           return(MR_USER);
424         if (status) return(status);
425     } else if (!strcmp(data_type, "list")) {
426         /* LIST */
427         status = name_to_id(name, LIST_TABLE, &id);
428         if (status && status == MR_NOT_UNIQUE)
429           return(MR_LIST);
430         if (status == MR_NO_MATCH) {
431             /* if idfield is non-zero, then if argv[0] matches the string
432              * that we're trying to resolve, we should get the value of
433              * numvalues.[idfield] for the id.
434              */
435             if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
436                 set_next_object_id(q->validate->object_id, q->rtable, 0);
437                 name = vo->idfield;
438                 EXEC SQL SELECT value INTO :id FROM numvalues
439                   WHERE name = :name;
440                 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
441             } else
442               return(MR_LIST);
443         } else if (status) return(status);
444     } else if (!strcmp(data_type, "machine")) {
445         /* MACHINE */
446         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
447         status = name_to_id(name, MACHINE_TABLE, &id);
448         if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
449           return(MR_MACHINE);
450         if (status) return(status);
451     } else if (!strcmp(data_type, "string")) {
452         /* STRING */
453         status = name_to_id(name, STRINGS_TABLE, &id);
454         if (status && status == MR_NOT_UNIQUE)
455           return(MR_STRING);
456         if (status == MR_NO_MATCH) {
457             if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
458             id=add_string(name);
459             cache_entry(name, STRINGS_TABLE, id);
460         } else if (status) return(status);
461     } else if (!strcmp(data_type, "none")) {
462         id = 0;
463     } else {
464         return(MR_TYPE);
465     }
466
467     /* now set value in argv */
468     *(int *)argv[vo->index] = id;
469
470     return (MR_EXISTS);
471 }
472
473
474 /* Make sure the data fits in the field */
475 int validate_len(argv, vo)
476     register char *argv[];
477     register struct valobj *vo;
478 {
479     EXEC SQL BEGIN DECLARE SECTION;
480     int len;
481     char *tname, *cname;
482     EXEC SQL END DECLARE SECTION;
483
484     tname = table_name[vo->table];
485     cname = vo->namefield;
486     EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
487       WHERE table_name=UPPER(:tname) AND column_name=UPPER(:cname);
488
489     if((strlen(argv[vo->index]) > len) &&
490        strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
491       argv[vo->index][len]='\0'; /* truncate */
492
493     return MR_EXISTS;
494 }
495
496 /* Lock the table named by the validation object */
497
498 int lock_table(vo)
499      struct valobj *vo;
500 {
501 #ifdef DO_LOCKING
502     sprintf(stmt_buf, "LOCK TABLE %s IN EXCLUSIVE MODE", table_name[vo->table]);
503     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
504     if (dbms_errno) 
505         return(mr_errcode);
506     else
507 #endif
508       return(MR_EXISTS);
509 }
510
511 /*
512  * Get a read lock on the table by accessing the magic lock
513  * record.  Certain tables are constructed so that they contain
514  * an id field whose value is zero and a modtime field.  We 
515  * manipulate the modtime field of the id 0 record to effect 
516  * locking of the table
517  */
518
519 int readlock_table(vo)
520     struct valobj *vo;
521 {
522 #ifdef DO_LOCKING
523     sprintf(stmt_buf, "LOCK TABLE %s IN SHARE MODE", table_name[vo->table]);
524     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
525
526     if (dbms_errno)
527         return(mr_errcode);
528     if (sqlca.sqlcode)
529         return(vo->error);
530 #endif
531     return(MR_EXISTS);  /* validate_fields expects us to return
532                            * this value if everything went okay
533                            */
534 }
535
536 /* Check the database at startup time. NOT! */
537
538 void sanity_check_database(void)
539 {
540 }
541
542
543 char *sqlbuffer[QMAXARGS];
544
545 /* Dynamic SQL support routines */
546 SQLDA *mr_alloc_sqlda()
547 {
548     SQLDA *it;
549     register int j;
550
551     it=sqlald(QMAXARGS, ARGLEN, 0);
552     if(it==NULL) {
553         com_err(whoami, MR_NO_MEM, "setting up SQLDA");
554         exit(1);
555     }
556
557     for(j=0; j<QMAXARGS; j++) {
558         it->V[j]=sqlbuffer[j]=malloc(ARGLEN);
559         it->T[j]=97; /* 97 = CHARZ = null-terminated string */
560         it->L[j]=ARGLEN;
561     }
562
563     return it;
564 }
565
566
567 /* Convert normal Unix-style wildcards to SQL voodoo */
568 int convert_wildcards(arg)
569     char *arg;
570 {
571     static char buffer[ARGLEN];
572     register char *s, *d;
573
574     for(d=buffer,s=arg;*s;s++) {
575         switch(*s) {
576           case '*': *d++='%'; *d++='%'; break;
577           case '?': *d++='_'; break;
578           case '_': *d++='*'; *d++ = *s; break;
579           case '%': *d++='*'; *d++='%'; *d++='%'; break;
580           default: *d++ = *s; break;
581         }
582     }
583     *d='\0';
584
585     /* Copy back into argv */
586     strcpy(arg,buffer);
587
588     return(MR_EXISTS);
589 }
590
591 /* This version includes uppercase conversion, for things like gmac.
592  * This is necessary because "LIKE" doesn't work with "uppercase()".
593  * Including it in a wildcard routine saves making two passes over
594  * the argument string.
595  */
596 int convert_wildcards_uppercase(arg)
597     char *arg;
598 {
599     static char buffer[ARGLEN];
600     register char *s, *d;
601
602     for(d=buffer,s=arg;*s;s++) {
603         switch(*s) {
604           case '*': *d++='%'; *d++='%'; break;
605           case '?': *d++='_'; break;
606           case '_': *d++='*'; *d++ = *s; break;
607           case '%': *d++='*'; *d++='%'; *d++='%'; break;
608           default: *d++=toupper(*s); break;       /* This is the only diff. */
609         }
610     }
611     *d='\0';
612
613     /* Copy back into argv */
614     strcpy(arg,buffer);
615
616     return(MR_EXISTS);
617 }
618
619
620 /*  Adds a string to the string table.  Returns the id number.
621  * 
622  */
623 int add_string(name)
624     EXEC SQL BEGIN DECLARE SECTION; 
625     char *name;
626     EXEC SQL END DECLARE SECTION;
627 {
628     EXEC SQL BEGIN DECLARE SECTION;
629     char buf[256];
630     int id;
631     EXEC SQL END DECLARE SECTION; 
632
633     EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
634     id++;
635     EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
636     
637     EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
638  
639     return(id);
640 }
This page took 0.25809 seconds and 5 git commands to generate.