]> andersk Git - moira.git/blame - server/qvalidate.pc
Command line printer manipulation client, and build goo.
[moira.git] / server / qvalidate.pc
CommitLineData
7ac48069 1/* $Id$
73cf66ba 2 *
7ac48069 3 * Argument validation routines
73cf66ba 4 *
7ac48069 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>.
73cf66ba 8 */
9
73cf66ba 10#include <mit-copyright.h>
73cf66ba 11#include "mr_server.h"
03c05291 12#include "query.h"
7ac48069 13#include "qrtn.h"
14
73cf66ba 15#include <ctype.h>
7ac48069 16#include <stdlib.h>
03c05291 17#include <string.h>
7ac48069 18#include <unistd.h>
19
73cf66ba 20EXEC SQL INCLUDE sqlca;
21EXEC SQL INCLUDE sqlda;
7ac48069 22
23RCSID("$Header$");
73cf66ba 24
03c05291 25extern char *whoami, *table_name[], *sqlbuffer[QMAXARGS];
26extern int dbms_errno, mr_errcode;
73cf66ba 27
28EXEC SQL BEGIN DECLARE SECTION;
29extern char stmt_buf[];
30EXEC SQL END DECLARE SECTION;
31
03c05291 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);
f802fd0d 39int validate_num(char *argv[], struct valobj *vo);
73cf66ba 40
5eaef520 41extern SQLDA *sqlald(int, int, int);
7ac48069 42SQLDA *mr_alloc_sqlda(void);
960b073b 43
03c05291 44EXEC SQL WHENEVER SQLERROR DO dbmserr();
73cf66ba 45
46/* Validation Routines */
47
44d12d58 48int validate_row(struct query *q, char *argv[], struct validate *v)
73cf66ba 49{
5eaef520 50 EXEC SQL BEGIN DECLARE SECTION;
5eaef520 51 int rowcount;
52 EXEC SQL END DECLARE SECTION;
263a36d4 53 char *qual;
5eaef520 54
55 /* build where clause */
263a36d4 56 qual = build_qual(v->qual, v->argc, argv);
5eaef520 57
5eaef520 58 /* look for the record */
59 sprintf(stmt_buf, "SELECT COUNT (*) FROM %s WHERE %s",
60 table_name[q->rtable], qual);
61 dosql(sqlbuffer);
263a36d4 62 free(qual);
5eaef520 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;
73cf66ba 72}
73
44d12d58 74int validate_fields(struct query *q, char *argv[], struct valobj *vo, int n)
73cf66ba 75{
44d12d58 76 int status;
73cf66ba 77
5eaef520 78 while (--n >= 0)
79 {
80 switch (vo->type)
81 {
73cf66ba 82 case V_NAME:
5eaef520 83 status = validate_name(argv, vo);
84 break;
73cf66ba 85
86 case V_ID:
5eaef520 87 status = validate_id(q, argv, vo);
88 break;
73cf66ba 89
90 case V_TYPE:
5eaef520 91 status = validate_type(argv, vo);
92 break;
73cf66ba 93
94 case V_TYPEDATA:
5eaef520 95 status = validate_typedata(q, argv, vo);
96 break;
73cf66ba 97
98 case V_RENAME:
5eaef520 99 status = validate_rename(argv, vo);
100 break;
73cf66ba 101
102 case V_CHAR:
5eaef520 103 status = validate_chars(argv, vo);
104 break;
03c05291 105
106 case V_LEN:
5eaef520 107 status = validate_len(argv, vo);
108 break;
73cf66ba 109
f802fd0d 110 case V_NUM:
111 status = validate_num(argv, vo);
112 break;
73cf66ba 113 }
114
5eaef520 115 if (status != MR_EXISTS)
116 return status;
117 vo++;
73cf66ba 118 }
119
5eaef520 120 if (dbms_errno)
121 return mr_errcode;
122 return MR_SUCCESS;
73cf66ba 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[] = {
5eaef520 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,
73cf66ba 147};
148
44d12d58 149int validate_chars(char *argv[], struct valobj *vo)
73cf66ba 150{
5eaef520 151 char *s = argv[vo->index];
5eaef520 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 {
7ac48069 160 if (illegalchars[(int)*s++])
5eaef520 161 return MR_BAD_CHAR;
162 }
03c05291 163
5eaef520 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);
03c05291 169
5eaef520 170 if ((strlen(argv[vo->index]) > len) &&
171 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
64798e00 172 return MR_ARG_TOO_LONG;
03c05291 173
5eaef520 174 return MR_EXISTS;
73cf66ba 175}
176
177
44d12d58 178int validate_id(struct query *q, char *argv[], struct valobj *vo)
73cf66ba 179{
5eaef520 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;
44d12d58 185 char *c;
5eaef520 186
187 name = argv[vo->index];
188 tbl = vo->table;
189 namefield = vo->namefield;
190 idfield = vo->idfield;
191
8bf97744 192 if (tbl == MACHINE_TABLE || tbl == SUBNET_TABLE)
5eaef520 193 {
8bf97744 194 for (c = name; *c; c++)
5eaef520 195 {
8bf97744 196 if (islower(*c))
197 *c = toupper(*c);
5eaef520 198 }
5eaef520 199 }
8bf97744 200 status = name_to_id(name, tbl, &id);
201 if (status == 0)
5eaef520 202 {
03c05291 203 *(int *)argv[vo->index] = id;
5eaef520 204 return MR_EXISTS;
73cf66ba 205 }
8bf97744 206 else if (status == MR_NO_MATCH && tbl == STRINGS_TABLE &&
b9f9ab1c 207 (q->type == MR_Q_APPEND || q->type == MR_Q_UPDATE))
8bf97744 208 {
4cad12bc 209 if (strlen(name) >= STRINGS_STRING_SIZE)
210 return MR_ARG_TOO_LONG;
8bf97744 211 id = add_string(name);
8bf97744 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;
73cf66ba 219}
220
44d12d58 221int validate_name(char *argv[], struct valobj *vo)
73cf66ba 222{
5eaef520 223 char *name, *namefield;
44d12d58 224 char *c;
5eaef520 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 {
73cf66ba 232 if (islower(*c))
233 *c = toupper(*c);
5eaef520 234 }
73cf66ba 235 }
7a37b7c5 236 if (!*name)
237 return MR_RESERVED;
5eaef520 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);
03c05291 241
5eaef520 242 if (dbms_errno)
243 return mr_errcode;
244 return (atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error;
73cf66ba 245}
246
5eaef520 247int validate_rename(char *argv[], struct valobj *vo)
73cf66ba 248{
5eaef520 249 EXEC SQL BEGIN DECLARE SECTION;
250 char *name, *namefield, *idfield;
251 int id;
252 EXEC SQL END DECLARE SECTION;
253 int status;
44d12d58 254 char *c;
5eaef520 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 }
7a37b7c5 269 if (!*name)
270 return MR_RESERVED;
5eaef520 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;
73cf66ba 288 }
5eaef520 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;
73cf66ba 294}
295
296
44d12d58 297int validate_type(char *argv[], struct valobj *vo)
73cf66ba 298{
5eaef520 299 EXEC SQL BEGIN DECLARE SECTION;
300 char *typename;
301 char *val;
302 int cnt;
303 EXEC SQL END DECLARE SECTION;
44d12d58 304 char *c;
5eaef520 305
306 typename = vo->namefield;
307 c = val = argv[vo->index];
308 while (*c)
309 {
7ac48069 310 if (illegalchars[(int)*c++])
5eaef520 311 return MR_BAD_CHAR;
73cf66ba 312 }
313
5eaef520 314 /* uppercase type fields */
315 for (c = val; *c; c++)
316 {
317 if (islower(*c))
318 *c = toupper(*c);
319 }
73cf66ba 320
5eaef520 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;
73cf66ba 326}
327
328/* validate member or type-specific data field */
329
44d12d58 330int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
73cf66ba 331{
5eaef520 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;
44d12d58 339 char *c;
5eaef520 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 */
a59f007b 381 if (vo->idfield && (*(int *)argv[0] == *(int *)argv[vo->index]))
5eaef520 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 {
b9f9ab1c 418 if (q->type != MR_Q_APPEND && q->type != MR_Q_UPDATE)
5eaef520 419 return MR_STRING;
4cad12bc 420 if (strlen(name) >= STRINGS_STRING_SIZE)
421 return MR_ARG_TOO_LONG;
5eaef520 422 id = add_string(name);
5eaef520 423 }
424 else if (status)
425 return status;
73cf66ba 426 }
46b6f1f6 427 else if (!strcmp(data_type, "none") || !strcmp(data_type, "all"))
5eaef520 428 id = 0;
429 else
430 return MR_TYPE;
73cf66ba 431
5eaef520 432 /* now set value in argv */
433 *(int *)argv[vo->index] = id;
73cf66ba 434
5eaef520 435 return MR_EXISTS;
73cf66ba 436}
437
438
03c05291 439/* Make sure the data fits in the field */
44d12d58 440int validate_len(char *argv[], struct valobj *vo)
03c05291 441{
5eaef520 442 EXEC SQL BEGIN DECLARE SECTION;
443 int len;
444 char *tname, *cname;
445 EXEC SQL END DECLARE SECTION;
03c05291 446
5eaef520 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);
03c05291 451
5eaef520 452 if ((strlen(argv[vo->index]) > len) &&
453 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
64798e00 454 return MR_ARG_TOO_LONG;
03c05291 455
5eaef520 456 return MR_EXISTS;
03c05291 457}
458
f802fd0d 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++;
6bd10afd 472 if (!*p)
473 return MR_INTEGER;
474
f802fd0d 475 for (; *p; p++)
476 {
477 if (*p < '0' || *p > '9')
478 return MR_INTEGER;
479 }
480
481 return MR_EXISTS;
482}
483
695afd0d 484/* Check the database at startup time. */
03c05291 485
486void sanity_check_database(void)
487{
5eaef520 488 EXEC SQL BEGIN DECLARE SECTION;
489 int oid, id;
490 EXEC SQL END DECLARE SECTION;
695afd0d 491
5eaef520 492 /* Sometimes a crash can leave strings_id in numvalues in an
493 incorrect state. Check for that and fix it. */
695afd0d 494
5eaef520 495 EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name = 'strings_id';
695afd0d 496
5eaef520 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 }
695afd0d 502
5eaef520 503 if (id != oid + 1)
504 EXEC SQL UPDATE numvalues SET value = :id - 1 WHERE name = 'strings_id';
03c05291 505}
506
507
508char *sqlbuffer[QMAXARGS];
73cf66ba 509
510/* Dynamic SQL support routines */
7ac48069 511SQLDA *mr_alloc_sqlda(void)
73cf66ba 512{
5eaef520 513 SQLDA *it;
44d12d58 514 int j;
5eaef520 515
516 it = sqlald(QMAXARGS, ARGLEN, 0);
517 if (!it)
518 {
519 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
520 exit(1);
73cf66ba 521 }
522
5eaef520 523 for (j = 0; j < QMAXARGS; j++)
524 {
e688520a 525 it->V[j] = sqlbuffer[j] = xmalloc(ARGLEN);
5eaef520 526 it->T[j] = 97; /* 97 = CHARZ = null-terminated string */
527 it->L[j] = ARGLEN;
73cf66ba 528 }
03c05291 529
5eaef520 530 return it;
73cf66ba 531}
532
73cf66ba 533/* Adds a string to the string table. Returns the id number.
5eaef520 534 *
73cf66ba 535 */
5eaef520 536int add_string(char *nm)
73cf66ba 537{
5eaef520 538 EXEC SQL BEGIN DECLARE SECTION;
7ac48069 539 char *name = nm;
5eaef520 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
7ac48069 547 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
5eaef520 548
549 return id;
73cf66ba 550}
This page took 0.396322 seconds and 5 git commands to generate.