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