source: trunk/third/moira/server/qvalidate.pc @ 24319

Revision 24319, 12.9 KB checked in by broder, 14 years ago (diff)
New Moira snapshot from SVN.
Line 
1/* $Id: qvalidate.pc 3956 2010-01-05 20:56:56Z zacheiss $
2 *
3 * Argument validation 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#include <mit-copyright.h>
11#include "mr_server.h"
12#include "query.h"
13#include "qrtn.h"
14
15#include <ctype.h>
16#include <stdlib.h>
17#include <string.h>
18#include <unistd.h>
19
20EXEC SQL INCLUDE sqlca;
21EXEC SQL INCLUDE sqlda;
22
23RCSID("$HeadURL: svn+ssh://svn.mit.edu/moira/trunk/moira/server/qvalidate.pc $ $Id: qvalidate.pc 3956 2010-01-05 20:56:56Z zacheiss $");
24
25extern char *whoami, *table_name[], *sqlbuffer[QMAXARGS];
26extern int dbms_errno, mr_errcode;
27
28EXEC SQL BEGIN DECLARE SECTION;
29extern char stmt_buf[];
30EXEC SQL END DECLARE SECTION;
31
32int validate_chars(char *argv[], struct valobj *vo);
33int validate_id(struct query *, char *argv[], struct valobj *vo);
34int validate_name(char *argv[], struct valobj *vo);
35int validate_rename(char *argv[], struct valobj *vo);
36int validate_type(char *argv[], struct valobj *vo);
37int validate_typedata(struct query *, char *argv[], struct valobj *vo);
38int validate_len(char *argv[], struct valobj *vo);
39int validate_num(char *argv[], struct valobj *vo);
40
41extern SQLDA *sqlald(int, int, int);
42SQLDA *mr_alloc_sqlda(void);
43
44EXEC SQL WHENEVER SQLERROR DO dbmserr();
45
46/* Validation Routines */
47
48int validate_row(struct query *q, char *argv[], struct validate *v)
49{
50  EXEC SQL BEGIN DECLARE SECTION;
51  int rowcount;
52  EXEC SQL END DECLARE SECTION;
53  char *qual;
54
55  /* build where clause */
56  qual = build_qual(v->qual, v->argc, argv);
57
58  /* look for the record */
59  sprintf(stmt_buf, "SELECT COUNT (*) FROM %s WHERE %s",
60          table_name[q->rtable], qual);
61  dosql(sqlbuffer);
62  free(qual);
63  if (dbms_errno)
64    return mr_errcode;
65
66  rowcount = atoi(sqlbuffer[0]);
67  if (rowcount == 0)
68    return MR_NO_MATCH;
69  if (rowcount > 1)
70    return MR_NOT_UNIQUE;
71  return MR_EXISTS;
72}
73
74int validate_fields(struct query *q, char *argv[], struct valobj *vo, int n)
75{
76  int status;
77
78  while (--n >= 0)
79    {
80      switch (vo->type)
81        {
82        case V_NAME:
83          status = validate_name(argv, vo);
84          break;
85
86        case V_ID:
87          status = validate_id(q, argv, vo);
88          break;
89
90        case V_TYPE:
91          status = validate_type(argv, vo);
92          break;
93
94        case V_TYPEDATA:
95          status = validate_typedata(q, argv, vo);
96          break;
97
98        case V_RENAME:
99          status = validate_rename(argv, vo);
100          break;
101
102        case V_CHAR:
103          status = validate_chars(argv, vo);
104          break;
105
106        case V_LEN:
107          status = validate_len(argv, vo);
108          break;
109
110        case V_NUM:
111          status = validate_num(argv, vo);
112          break;
113        }
114
115      if (status != MR_EXISTS)
116        return status;
117      vo++;
118    }
119
120  if (dbms_errno)
121    return mr_errcode;
122  return MR_SUCCESS;
123}
124
125
126/* validate_chars: verify that there are no illegal characters in
127 * the string.  Legal characters are printing chars other than
128 * ", *, ?, \, [ and ].
129 */
130static int illegalchars[] = {
131  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
132  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
133  0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
134  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
135  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
136  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
137  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
138  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
139  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
140  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
141  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
142  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
143  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
144  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
145  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
146  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
147};
148
149int validate_chars(char *argv[], struct valobj *vo)
150{
151  char *s = argv[vo->index];
152  EXEC SQL BEGIN DECLARE SECTION;
153  int len;
154  char *tname, *cname;
155  EXEC SQL END DECLARE SECTION;
156
157  /* check for bad characters */
158  while (*s)
159    {
160      if (illegalchars[(int)*s++])
161        return MR_BAD_CHAR;
162    }
163
164  /* check for length */
165  tname = table_name[vo->table];
166  cname = vo->namefield;
167  EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
168    WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
169
170  if ((strlen(argv[vo->index]) > len) &&
171      strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
172    return MR_ARG_TOO_LONG;
173
174  return MR_EXISTS;
175}
176
177
178int validate_id(struct query *q, char *argv[], struct valobj *vo)
179{
180  EXEC SQL BEGIN DECLARE SECTION;
181  char *name, *namefield, *idfield;
182  int id, rowcount, tbl;
183  EXEC SQL END DECLARE SECTION;
184  int status;
185  char *c;
186
187  name = argv[vo->index];
188  tbl = vo->table;
189  namefield = vo->namefield;
190  idfield = vo->idfield;
191
192  if (tbl == MACHINE_TABLE || tbl == SUBNET_TABLE)
193    {
194      for (c = name; *c; c++)
195        {
196          if (islower(*c))
197            *c = toupper(*c);
198        }
199    }
200  status = name_to_id(name, tbl, &id);
201  if (status == 0)
202    {
203      *(int *)argv[vo->index] = id;
204      return MR_EXISTS;
205    }
206  else if (status == MR_NO_MATCH && tbl == STRINGS_TABLE &&
207           (q->type == MR_Q_APPEND || q->type == MR_Q_UPDATE))
208    {
209      if (strlen(name) >= STRINGS_STRING_SIZE)
210        return MR_ARG_TOO_LONG;
211      id = add_string(name);
212      *(int *)argv[vo->index] = id;
213      return MR_EXISTS;
214    }
215  else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
216    return vo->error;
217  else
218    return status;
219}
220
221int validate_name(char *argv[], struct valobj *vo)
222{
223  char *name, *namefield;
224  char *c;
225
226  name = argv[vo->index];
227  namefield = vo->namefield;
228  if (vo->table == SERVERS_TABLE && !strcmp(namefield, "name"))
229    {
230      for (c = name; *c; c++)
231        {
232          if (islower(*c))
233            *c = toupper(*c);
234        }
235    }
236  if (!*name)
237    return MR_RESERVED;
238  sprintf(stmt_buf, "SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
239          table_name[vo->table], table_name[vo->table], namefield, name);
240  dosql(sqlbuffer);
241
242  if (dbms_errno)
243    return mr_errcode;
244  return (atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error;
245}
246
247int validate_rename(char *argv[], struct valobj *vo)
248{
249  EXEC SQL BEGIN DECLARE SECTION;
250  char *name, *namefield, *idfield;
251  int id;
252  EXEC SQL END DECLARE SECTION;
253  int status;
254  char *c;
255
256  status = validate_chars(argv, vo);
257  if (status != MR_EXISTS)
258    return status;
259  name = argv[vo->index];
260  /* minor kludge to upcasify machine names */
261  if (vo->table == MACHINE_TABLE)
262    {
263      for (c = name; *c; c++)
264        {
265          if (islower(*c))
266            *c = toupper(*c);
267        }
268    }
269  if (!*name)
270    return MR_RESERVED;
271  namefield = vo->namefield;
272  idfield = vo->idfield;
273  id = -1;
274  if (idfield == 0)
275    {
276      if (!strcmp(argv[vo->index], argv[vo->index - 1]))
277        return MR_EXISTS;
278      sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = '%s'",
279              namefield, table_name[vo->table], namefield, name);
280      dosql(sqlbuffer);
281
282      if (dbms_errno)
283        return mr_errcode;
284      if (sqlca.sqlcode == SQL_NO_MATCH)
285        return MR_EXISTS; /* how's _that_ for intuitive? */
286      else
287        return vo->error;
288    }
289  status = name_to_id(name, vo->table, &id);
290  if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
291    return MR_EXISTS;
292  else
293    return vo->error;
294}
295
296
297int validate_type(char *argv[], struct valobj *vo)
298{
299  EXEC SQL BEGIN DECLARE SECTION;
300  char *typename;
301  char *val;
302  int cnt;
303  EXEC SQL END DECLARE SECTION;
304  char *c;
305
306  typename = vo->namefield;
307  c = val = argv[vo->index];
308  while (*c)
309    {
310      if (illegalchars[(int)*c++])
311        return MR_BAD_CHAR;
312    }
313
314  /* uppercase type fields */
315  for (c = val; *c; c++)
316    {
317      if (islower(*c))
318        *c = toupper(*c);
319    }
320
321  EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
322    WHERE name = :typename AND type = 'TYPE' AND trans = :val;
323  if (dbms_errno)
324    return mr_errcode;
325  return cnt ? MR_EXISTS : vo->error;
326}
327
328/* validate member or type-specific data field */
329
330int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
331{
332  EXEC SQL BEGIN DECLARE SECTION;
333  char *name;
334  char *field_type;
335  char data_type[129];
336  int id;
337  EXEC SQL END DECLARE SECTION;
338  int status;
339  char *c;
340
341  /* get named object */
342  name = argv[vo->index];
343
344  /* get field type string (known to be at index-1) */
345  field_type = argv[vo->index - 1];
346
347  /* get corresponding data type associated with field type name */
348  EXEC SQL SELECT trans INTO :data_type FROM alias
349    WHERE name = :field_type AND type = 'TYPEDATA';
350  if (dbms_errno)
351    return mr_errcode;
352  if (sqlca.sqlerrd[2] != 1)
353    return MR_TYPE;
354
355  /* now retrieve the record id corresponding to the named object */
356  if (strchr(data_type, ' '))
357    *strchr(data_type, ' ') = '\0';
358  if (!strcmp(data_type, "user"))
359    {
360      /* USER */
361      if (strchr(name, '@'))
362        return MR_USER;
363      status = name_to_id(name, USERS_TABLE, &id);
364      if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
365        return MR_USER;
366      if (status)
367        return status;
368    }
369  else if (!strcmp(data_type, "list"))
370    {
371      /* LIST */
372      status = name_to_id(name, LIST_TABLE, &id);
373      if (status && status == MR_NOT_UNIQUE)
374        return MR_LIST;
375      if (status == MR_NO_MATCH)
376        {
377          /* if idfield is non-zero, then if argv[0] matches the string
378           * that we're trying to resolve, we should get the value of
379           * numvalues.[idfield] for the id.
380           */
381          if (vo->idfield && (*(int *)argv[0] == *(int *)argv[vo->index]))
382            {
383              set_next_object_id(q->validate->object_id, q->rtable, 0);
384              name = vo->idfield;
385              EXEC SQL SELECT value INTO :id FROM numvalues
386                WHERE name = :name;
387              if (sqlca.sqlerrd[2] != 1)
388                return MR_LIST;
389            }
390          else
391            return MR_LIST;
392        }
393      else if (status)
394        return status;
395    }
396  else if (!strcmp(data_type, "machine"))
397    {
398      /* MACHINE */
399      for (c = name; *c; c++)
400        {
401          if (islower(*c))
402            *c = toupper(*c);
403        }
404      status = name_to_id(name, MACHINE_TABLE, &id);
405      if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
406        return MR_MACHINE;
407      if (status)
408        return status;
409    }
410  else if (!strcmp(data_type, "string"))
411    {
412      /* STRING */
413      status = name_to_id(name, STRINGS_TABLE, &id);
414      if (status && status == MR_NOT_UNIQUE)
415        return MR_STRING;
416      if (status == MR_NO_MATCH)
417        {
418          if (q->type != MR_Q_APPEND && q->type != MR_Q_UPDATE)
419            return MR_STRING;
420          if (strlen(name) >= STRINGS_STRING_SIZE)
421            return MR_ARG_TOO_LONG;
422          id = add_string(name);
423        }
424      else if (status)
425        return status;
426    }
427  else if (!strcmp(data_type, "none") || !strcmp(data_type, "all"))
428    id = 0;
429  else
430    return MR_TYPE;
431
432  /* now set value in argv */
433  *(int *)argv[vo->index] = id;
434
435  return MR_EXISTS;
436}
437
438
439/* Make sure the data fits in the field */
440int validate_len(char *argv[], struct valobj *vo)
441{
442  EXEC SQL BEGIN DECLARE SECTION;
443  int len;
444  char *tname, *cname;
445  EXEC SQL END DECLARE SECTION;
446
447  tname = table_name[vo->table];
448  cname = vo->namefield;
449  EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
450    WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
451
452  if ((strlen(argv[vo->index]) > len) &&
453      strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
454    return MR_ARG_TOO_LONG;
455
456  return MR_EXISTS;
457}
458
459/* Make sure the data is numeric */
460int validate_num(char *argv[], struct valobj *vo)
461{
462  char *p = argv[vo->index];
463
464  if (!strcmp(p, UNIQUE_GID) || !strcmp(p, UNIQUE_UID))
465    {
466      strcpy(p, "-1");
467      return MR_EXISTS;
468    }
469
470  if (*p == '-')
471    p++;
472  if (!*p)
473    return MR_INTEGER;
474
475  for (; *p; p++)
476    {
477      if (*p < '0' || *p > '9')
478        return MR_INTEGER;
479    }
480
481  return MR_EXISTS;
482}
483
484/* Check the database at startup time. */
485
486void sanity_check_database(void)
487{
488  EXEC SQL BEGIN DECLARE SECTION;
489  int oid, id;
490  EXEC SQL END DECLARE SECTION;
491
492  /* Sometimes a crash can leave strings_id in numvalues in an
493     incorrect state. Check for that and fix it. */
494
495  EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name = 'strings_id';
496
497  for (id = oid + 1; sqlca.sqlcode == 0; id++)
498    {
499      EXEC SQL SELECT string_id INTO :id FROM strings
500        WHERE string_id = :id;
501    }
502
503  if (id != oid + 1)
504    EXEC SQL UPDATE numvalues SET value = :id - 1 WHERE name = 'strings_id';
505}
506
507
508char *sqlbuffer[QMAXARGS];
509
510/* Dynamic SQL support routines */
511SQLDA *mr_alloc_sqlda(void)
512{
513  SQLDA *it;
514  int j;
515
516  it = sqlald(QMAXARGS, ARGLEN, 0);
517  if (!it)
518    {
519      com_err(whoami, MR_NO_MEM, "setting up SQLDA");
520      exit(1);
521    }
522
523  for (j = 0; j < QMAXARGS; j++)
524    {
525      it->V[j] = sqlbuffer[j] = xmalloc(ARGLEN);
526      it->T[j] = 97; /* 97 = CHARZ = null-terminated string */
527      it->L[j] = ARGLEN;
528    }
529
530  return it;
531}
532
533/*  Adds a string to the string table.  Returns the id number.
534 *
535 */
536int add_string(char *nm)
537{
538  EXEC SQL BEGIN DECLARE SECTION;
539  char *name = nm;
540  int id;
541  EXEC SQL END DECLARE SECTION;
542
543  EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
544  id++;
545  EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
546
547  EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
548
549  return id;
550}
Note: See TracBrowser for help on using the repository browser.