source: trunk/third/moira/server/qsetup.pc @ 25455

Revision 25455, 41.1 KB checked in by jdreed, 12 years ago (diff)
In moira: * Re-snapshot moira at r4073 to pick up new changes to clients; the eunice issue described in the previous entry is no longer relevant
Line 
1/* $Id: qsetup.pc 4063 2012-01-04 17:37:23Z zacheiss $
2 *
3 * Query setup 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 <arpa/inet.h>
16#include <netinet/in.h>
17
18#include <ctype.h>
19#include <stdlib.h>
20#include <string.h>
21
22EXEC SQL INCLUDE sqlca;
23
24RCSID("$HeadURL: svn+ssh://svn.mit.edu/moira/trunk/moira/server/qsetup.pc $ $Id: qsetup.pc 4063 2012-01-04 17:37:23Z zacheiss $");
25
26extern char *whoami;
27extern int dbms_errno, mr_errcode;
28
29EXEC SQL BEGIN DECLARE SECTION;
30extern char stmt_buf[];
31EXEC SQL END DECLARE SECTION;
32
33EXEC SQL WHENEVER SQLERROR DO dbmserr();
34
35int hostname_check(char *name);
36int hostinfo_check(char *name, int num);
37int prefetch_value(struct query *q, char **argv, client *cl);
38int check_nfs(int mach_idx, char *name, char *access);
39int check_mailman_listname(char *name, const char *suffix);
40
41/* Setup Routines */
42
43/* Setup routine for add_user
44 *
45 * Inputs: argv[0] - login
46 *         argv[1] - uid
47 *
48 * Description:
49 *
50 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
51 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
52 */
53
54int setup_ausr(struct query *q, char *argv[], client *cl)
55{
56  int row, err;
57  EXEC SQL BEGIN DECLARE SECTION;
58  int nuid;
59  EXEC SQL END DECLARE SECTION;
60
61  if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
62    row = 2;
63  else
64    row = 1;
65
66  if (q->version > 2)
67    {
68      if (strlen(argv[row + 3]) + strlen(argv[row + 4]) +
69          strlen(argv[row + 5]) + 2 > USERS_FULLNAME_SIZE)
70        return MR_ARG_TOO_LONG;
71    }
72  else
73    {
74      if (strlen(argv[row + 2]) + strlen(argv[row + 3]) +
75          strlen(argv[row + 4]) + 2 > USERS_FULLNAME_SIZE)
76        return MR_ARG_TOO_LONG;
77    }
78
79  if (q->version > 10)
80    {
81      /* For both winhomedir and winprofiledir, we allow values of the
82       * following forms:
83       *
84       * [AFS] - Magic token for AFS home directory.
85       * [LOCAL] - Magic token for AD default local values, i.e. C:\<mumble>
86       * [DFS] - Magic token for DFS home directory
87       * UNC pathname - \\<something>
88       * local pathname - <drive letter>:<something>
89       */
90
91      if ((strcasecmp(argv[row + 12], "[AFS]")) &&
92          (strcasecmp(argv[row + 12], "[LOCAL]")) &&
93          (strcasecmp(argv[row + 12], "[DFS]")) &&
94          (!(argv[row + 12][0] == '\\' && argv[row + 12][1] == '\\')) &&
95          (!(isalpha(*argv[row + 12]) && (argv[row + 12][1] == ':'))))
96        return MR_BAD_CHAR;
97     
98      if ((strcasecmp(argv[row + 13], "[AFS]")) &&
99          (strcasecmp(argv[row + 13], "[LOCAL]")) &&
100          (strcasecmp(argv[row + 13], "[DFS]")) &&
101          (!(argv[row + 13][0] == '\\' && argv[row + 13][1] == '\\')) &&
102          (!(isalpha(*argv[row + 13]) && (argv[row + 13][1] == ':'))))
103        return MR_BAD_CHAR;
104    }
105
106  if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1)
107    {
108      if ((err = set_next_object_id("unix_uid", USERS_TABLE, 1)))
109        return err;
110      EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'unix_uid';
111      if (sqlca.sqlerrd[2] != 1)
112        return MR_INTERNAL;
113      sprintf(argv[row], "%d", nuid);
114    }
115
116  if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1)
117    sprintf(argv[0], "#%s", argv[row]);
118
119  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
120    return mr_errcode;
121
122  /* If this is an MR_Q_UPDATE query, we're done. */
123  if (row == 2)
124    return MR_SUCCESS;
125
126  /* For an add query, we need to fill in the creator id. */
127  sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
128  return MR_SUCCESS;
129}
130
131
132/* setup_dusr - verify that the user is no longer being referenced
133 * and may safely be deleted.
134 */
135
136int setup_dusr(struct query *q, char *argv[], client *cl)
137{
138  EXEC SQL BEGIN DECLARE SECTION;
139  int flag, id, cnt;
140  char resv[USERS_RESERVATIONS_SIZE];
141  EXEC SQL END DECLARE SECTION;
142
143  id = *(int *)argv[0];
144
145  /* For now, only allow users to be deleted if their status is
146   * one of 0, 4, or 8 (the various registerable statuses)
147   * and we have no reservations about deleting them.
148   */
149  EXEC SQL SELECT status, reservations INTO :flag, :resv
150    FROM users WHERE users_id = :id;
151  if ((flag != 0 && flag != 4 && flag != 8) || *resv)
152    return MR_IN_USE;
153
154  EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
155    WHERE member_id = :id AND member_type = 'USER';
156  if (cnt > 0)
157    return MR_IN_USE;
158  EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
159    WHERE owner = :id;
160  if (cnt > 0)
161    return MR_IN_USE;
162  EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
163    WHERE acl_id = :id AND acl_type = 'USER';
164  if (cnt > 0)
165    return MR_IN_USE;
166  EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
167    WHERE acl_id = :id AND acl_type = 'USER';
168  if (cnt > 0)
169    return MR_IN_USE;
170  EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
171    WHERE acl_id = :id AND acl_type = 'USER';
172  if (cnt > 0)
173    return MR_IN_USE;
174  if (dbms_errno)
175    return mr_errcode;
176
177  EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
178  EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
179  return MR_SUCCESS;
180}
181
182
183/* setup_dpob:  Take care of keeping track of the post office usage.
184 */
185int setup_dpob(struct query *q, char *argv[], client *cl)
186{
187  EXEC SQL BEGIN DECLARE SECTION;
188  int id, user;
189  char type[USERS_POTYPE_SIZE];
190  EXEC SQL END DECLARE SECTION;
191
192  user = *(int *)argv[0];
193  EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
194    WHERE users_id = :user;
195  if (dbms_errno)
196    return mr_errcode;
197
198  if (!strcmp(strtrim(type), "POP"))
199    set_pop_usage(id, -1);
200  return MR_SUCCESS;
201}
202
203
204/* setup_dmac - verify that the machine is no longer being referenced
205 * and may safely be deleted.
206 */
207
208int setup_dmac(struct query *q, char *argv[], client *cl)
209{
210  EXEC SQL BEGIN DECLARE SECTION;
211  int flag, id, cnt;
212  EXEC SQL END DECLARE SECTION;
213
214  id = *(int *)argv[0];
215
216  EXEC SQL SELECT status INTO :flag FROM machine
217    WHERE mach_id = :id;
218  if (flag != 3)
219    return MR_IN_USE;
220  EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
221    WHERE potype = 'POP' AND pop_id = :id;
222  if (cnt > 0)
223    return MR_IN_USE;
224  EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
225    WHERE potype = 'EXCHANGE' and exchange_id = :id;
226  if (cnt > 0)
227    return MR_IN_USE;
228  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
229    WHERE mach_id = :id;
230  if (cnt > 0)
231    return MR_IN_USE;
232  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
233    WHERE mach_id = :id;
234  if (cnt > 0)
235    return MR_IN_USE;
236  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
237    WHERE mach_id = :id;
238  if (cnt > 0)
239    return MR_IN_USE;
240  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
241    WHERE mach_id = :id;
242  if (cnt > 0)
243    return MR_IN_USE;
244  EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
245    WHERE rm = :id;
246  if (cnt > 0)
247    return MR_IN_USE;
248  EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
249    WHERE rq = :id;
250  if (cnt > 0)
251    return MR_IN_USE;
252  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
253    WHERE mach_id = :id;
254  if (cnt > 0)
255    return MR_IN_USE;
256  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
257    WHERE mach_id = :id;
258  if (cnt > 0)
259    return MR_IN_USE;
260  EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
261    WHERE member_type = 'MACHINE' and member_id = :id;
262  if (cnt > 0)
263    return MR_IN_USE;
264
265  EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
266  if (dbms_errno)
267    return mr_errcode;
268
269  EXEC SQL DELETE FROM mcntmap WHERE mach_id = :id;
270  if (dbms_errno)
271    return mr_errcode;
272  return MR_SUCCESS;
273}
274
275/* setup_asnt - verify that the data entered for the subnet is sane.
276 * In particular, make sure that the "low" and "high" addresses are
277 * correctly ordered, i.e., high > low.
278 */
279
280int setup_asnt(struct query *q, char *argv[], client *cl)
281{
282  int high, low, row, status;
283  char *account_number;
284
285  /* Check for asnt or usnt. */
286  if (q->type == MR_Q_APPEND)
287    row = 0;
288  else
289    row = 1;
290
291  low = atoi(argv[row + 7]);
292  high = atoi(argv[row + 8]);
293  status = atoi(argv[row + 2]);
294  account_number = argv[row + 4];
295 
296  /* Don't allow Private subnets to be created without a valid billing
297   * number.
298   */
299  if (status == SNET_STATUS_PRIVATE_10MBPS ||
300      status == SNET_STATUS_PRIVATE_100MBPS ||
301      status == SNET_STATUS_PRIVATE_1000MBPS)
302    {
303      EXEC SQL SELECT account_number FROM accountnumbers
304        WHERE account_number = :account_number;
305      if (sqlca.sqlcode == SQL_NO_MATCH)
306        return MR_ACCOUNT_NUMBER;
307    }
308     
309  /* Special case 0.0.0.0 and 255.255.255.255 */
310  if (!(low == 0 || low == -1 || high == 0 || high == -1))
311    if (low > high)
312      return MR_ADDRESS;
313
314  /* If this is update_subnet, we're done. */
315  if (row == 1)
316    return MR_SUCCESS;
317
318  /* For an add_subnet query, allocate and fill in a new snet_id */
319  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
320    return mr_errcode;
321
322  return MR_SUCCESS;
323}
324
325/* setup_dsnt - verify that the subnet is no longer being referenced
326 * and may safely be deleted.
327 */
328
329int setup_dsnt(struct query *q, char *argv[], client *cl)
330{
331  EXEC SQL BEGIN DECLARE SECTION;
332  int id, cnt = 0;
333  EXEC SQL END DECLARE SECTION;
334
335  id = *(int *)argv[0];
336  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
337    WHERE snet_id = :id;
338  if (cnt > 0)
339    return MR_IN_USE;
340  return MR_SUCCESS;
341}
342
343
344/* setup_dclu - verify that the cluster is no longer being referenced
345 * and may safely be deleted.
346 */
347
348int setup_dclu(struct query *q, char *argv[], client *cl)
349{
350  EXEC SQL BEGIN DECLARE SECTION;
351  int id, cnt;
352  EXEC SQL END DECLARE SECTION;
353
354  id = *(int *)argv[0];
355  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
356    WHERE clu_id = :id;
357  if (cnt > 0)
358    return MR_IN_USE;
359  EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
360    WHERE clu_id = :id;
361  if (cnt > 0)
362    return MR_IN_USE;
363  if (dbms_errno)
364    return mr_errcode;
365  return MR_SUCCESS;
366}
367
368
369/* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
370 * a new gid and put it in argv[6].  Otherwise if argv[6] is UNIQUE_ID but
371 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
372 * a -1 there.  Remember that this is also used for ulis, with the indexes
373 * at 6 & 7.  Also check that the list name does not contain uppercase
374 * characters, control characters, @, or :.
375 *
376 *  Newlines in list descriptions do bad things to the aliases file
377 *  moira generates, so make sure the description doesn't contain any, too.
378 */
379
380static int badlistchars[] = {
381  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
382  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
383  1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
384  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
385  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
386  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
387  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
388  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
389  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
390  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
391  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
392  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
393  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
394  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
395  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
396  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
397};
398
399static const char *mailman_suffixes[] = { "-admin", "-owner", "-request",
400                                          "-bounces", "-confirm", "-join",
401                                          "-leave", "-subscribe",
402                                          "-unsubscribe", NULL };
403
404int setup_alis(struct query *q, char *argv[], client *cl)
405{
406  EXEC SQL BEGIN DECLARE SECTION;
407  int ngid, cnt, mailman, mailman_id, lid;
408  char *name, *desc;
409  EXEC SQL END DECLARE SECTION;
410  unsigned char *p;
411  int idx, err, best = -1, usage, i;
412
413  if (!strcmp(q->shortname, "alis"))
414    idx = 0;
415  else if (!strcmp(q->shortname, "ulis"))
416    idx = 1;
417  name = argv[idx];
418
419  if (q->version == 2)
420    desc = argv[9 + idx];
421  else if (q->version == 3)
422    desc = argv[10 + idx];
423  else if (q->version == 4)
424    desc = argv[12 + idx];
425  else if (q->version >= 10)
426    desc = argv[14 + idx];
427
428  if (idx == 1)
429    {
430      lid = *(int *)argv[0];
431
432      if (acl_access_check(lid, cl))
433        return MR_PERM;
434    }
435
436  for (p = (unsigned char *) name; *p; p++)
437    {
438      if (badlistchars[*p])
439        return MR_BAD_CHAR;
440    }
441
442  for (p = (unsigned char *) desc; *p; p++)
443    {
444      if (*p == '\n')
445        return MR_BAD_CHAR;
446    }
447
448  /* Check that it doesn't conflict with a pre-existing weirdly-cased
449   * name. */
450  EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
451    WHERE LOWER(name) = :name AND name != :name;
452  if (cnt)
453    return MR_EXISTS;
454
455  if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
456    {
457      if (atoi(argv[5 + idx]))
458        {
459          if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
460            return err;
461          EXEC SQL SELECT value INTO :ngid FROM numvalues
462            WHERE name = 'gid';
463          if (dbms_errno)
464            return mr_errcode;
465          sprintf(argv[6 + idx], "%d", ngid);
466        }
467      else
468        strcpy(argv[6 + idx], "-1");
469    }
470
471  /* Don't let someone rename a list to one of the magic mailman names
472   * (foo-admin, etc) if foo already exists as a mailman list.
473   */
474  for (i = 0; mailman_suffixes[i]; i++)
475    {
476      if ((err = check_mailman_listname(name, mailman_suffixes[i]))
477          != MR_SUCCESS)
478        return err;
479    }
480
481  if (q->version >= 10)
482    {
483      /* Don't let them take this name for a mailman list if we can't
484       * reserve the -admin, -owner, and -request names.
485       */
486      if (atoi(argv[8 + idx]))
487        {
488          EXEC SQL SELECT  COUNT(name) INTO :cnt FROM list
489            WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
490                   name = :name || '-request');
491          if (cnt)
492            return MR_EXISTS;
493        }
494
495      /* Handle the [ANY] case for mailman server. */
496      mailman_id = *(int *)argv[9 + idx];
497      if (mailman_id == -1)
498        {
499          EXEC SQL DECLARE csr_mailman CURSOR FOR
500            SELECT mach_id FROM serverhosts WHERE service = 'MAILMAN'
501            AND enable = 1;
502          if (dbms_errno)
503            return mr_errcode;
504          EXEC SQL OPEN csr_mailman;
505          if (dbms_errno)
506            return mr_errcode;
507
508          while (1)
509            {
510              EXEC SQL FETCH csr_mailman INTO :mailman_id;
511              if (sqlca.sqlcode)
512                break;
513             
514              EXEC SQL SELECT COUNT(name) INTO :usage FROM list
515                WHERE mailman_id = :mailman_id;
516
517              if (best < 0 || usage < best)
518                {
519                  best = usage;
520                  *(int *)argv[9 + idx] = mailman_id;
521                  break;
522                }
523            }
524          EXEC SQL CLOSE csr_mailman;
525          if (dbms_errno)
526            return mr_errcode;
527
528          if (best == -1)
529            return MR_SERVICE;
530        }
531    }
532  else
533    {
534      /* Client too old to know about the mailman code.
535       * Use existing value of mailman boolean in the table.
536       * Don't do this for add_list from an old client, since the row
537       * they're creating won't exist yet, and there's no way for them to
538       * create a list with the mailman bit set, anyway.
539       */
540      if (idx == 1)
541        {
542          EXEC SQL SELECT mailman INTO :mailman FROM list WHERE list_id = :lid;
543          if (mailman)
544            {
545              EXEC SQL SELECT  COUNT(name) INTO :cnt FROM list
546                WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
547                       name = :name || '-request');
548              if (cnt)
549                return MR_EXISTS;
550            }
551        }
552    }
553
554  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
555    return mr_errcode;
556
557  return MR_SUCCESS;
558}
559
560
561/* setup_dlis - verify that the list is no longer being referenced
562 * and may safely be deleted.
563 */
564
565int setup_dlis(struct query *q, char *argv[], client *cl)
566{
567  int id;
568  EXEC SQL BEGIN DECLARE SECTION;
569  int cnt;
570  EXEC SQL END DECLARE SECTION;
571
572  id = *(int *)argv[0];
573
574  EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
575    WHERE member_id = :id AND member_type = 'LIST';
576  if (cnt > 0)
577    return MR_IN_USE;
578
579  EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
580    WHERE member_id = :id AND member_type = 'LIST';
581  if (cnt > 0)
582    return MR_IN_USE;
583
584  EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
585    WHERE list_id = :id;
586  if (cnt > 0)
587    return MR_IN_USE;
588
589  EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
590  if (cnt > 0)
591    return MR_IN_USE;
592
593  EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
594  if (cnt > 0)
595    return MR_IN_USE;
596
597  EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
598    WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
599  if (cnt > 0)
600    return MR_IN_USE;
601
602  EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
603    WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
604  if (cnt > 0)
605    return MR_IN_USE;
606
607  EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
608    WHERE acl_id = :id AND acl_type = 'LIST';
609  if (cnt > 0)
610    return MR_IN_USE;
611
612  EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
613    WHERE entity_id = :id AND type = 'GROUP';
614  if (cnt > 0)
615    return MR_IN_USE;
616
617  EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
618    WHERE acl_id = :id AND acl_type = 'LIST';
619  if (cnt > 0)
620    return MR_IN_USE;
621
622  EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
623    WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
624    OR z.sub_type = 'LIST' AND z.sub_id = :id
625    OR z.iws_type = 'LIST' AND z.iws_id = :id
626    OR z.iui_type = 'LIST' AND z.iui_id = :id
627    OR z.owner_type = 'LIST' and z.owner_id = :id;
628  if (cnt > 0)
629    return MR_IN_USE;
630
631  EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
632    WHERE lpc_acl = :id OR ac = :id;
633  if (cnt > 0)
634    return MR_IN_USE;
635
636  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
637    WHERE owner_type = 'LIST' AND owner_id = :id
638    OR lpc_acl = :id;
639  if (cnt > 0)
640    return MR_IN_USE;
641
642  EXEC SQL SELECT count(name) INTO :cnt FROM containers
643    WHERE acl_id = :id AND acl_type = 'LIST';
644  if (cnt > 0)
645    return MR_IN_USE;
646
647  EXEC SQL SELECT count(name) INTO :cnt FROM containers
648    WHERE memacl_id = :id AND memacl_type = 'LIST';
649  if (cnt > 0)
650    return MR_IN_USE;
651
652  return MR_SUCCESS;
653}
654
655
656/* setup_dsin - verify that the service is no longer being referenced
657 * and may safely be deleted.
658 */
659
660int setup_dsin(struct query *q, char *argv[], client *cl)
661{
662  EXEC SQL BEGIN DECLARE SECTION;
663  int ec, cnt;
664  char *svrname;
665  EXEC SQL END DECLARE SECTION;
666
667  svrname = argv[0];
668  EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
669    WHERE service = UPPER(:svrname);
670  if (cnt > 0)
671    return MR_IN_USE;
672
673  EXEC SQL SELECT inprogress INTO :ec FROM servers
674    WHERE name = UPPER(:svrname);
675  if (dbms_errno)
676    return mr_errcode;
677  if (ec)
678    return MR_IN_USE;
679
680  return MR_SUCCESS;
681}
682
683
684/* setup_dshi - verify that the service-host is no longer being referenced
685 * and may safely be deleted.
686 */
687
688int setup_dshi(struct query *q, char *argv[], client *cl)
689{
690  EXEC SQL BEGIN DECLARE SECTION;
691  int id, ec;
692  char *svrname;
693  EXEC SQL END DECLARE SECTION;
694
695  svrname = argv[0];
696  id = *(int *)argv[1];
697
698  EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
699    WHERE service = UPPER(:svrname) AND mach_id = :id;
700  if (dbms_errno)
701    return mr_errcode;
702  if (ec)
703    return MR_IN_USE;
704
705  return MR_SUCCESS;
706}
707
708
709/**
710 ** setup_add_filesys - verify existance of referenced file systems
711 **
712 ** Inputs:     Add
713 **   argv[1] - type
714 **   argv[2] - mach_id
715 **   argv[3] - name
716 **   argv[5] - rwaccess
717 **
718 ** Description:
719 **   - for type = RVD:
720 **        * allow anything
721 **   - for type = NFS/IMAP:
722 **        * extract directory prefix from name
723 **        * verify mach_id/dir in nfsphys
724 **        * verify rwaccess in {r, w, R, W}
725 **
726 **  Side effect: sets variable _var_phys_id to the ID of the physical
727 **     filesystem (nfsphys_id for NFS, 0 for RVD)
728 **
729 ** Errors:
730 **   MR_NFS - specified directory not exported
731 **   MR_FILESYS_ACCESS - invalid filesys access
732 **
733 **/
734
735EXEC SQL BEGIN DECLARE SECTION;
736int _var_phys_id;
737EXEC SQL END DECLARE SECTION;
738
739int setup_afil(struct query *q, char *argv[], client *cl)
740{
741  char *type, *name;
742  int mach_id;
743  EXEC SQL BEGIN DECLARE SECTION;
744  int ok;
745  char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
746  EXEC SQL END DECLARE SECTION;
747
748  type = argv[1];
749  mach_id = *(int *)argv[2];
750  name = argv[3];
751  rwaccess = argv[5];
752  _var_phys_id = 0;
753
754  sprintf(ftype, "fs_access_%s", type);
755  EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
756    WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
757  if (dbms_errno)
758    return mr_errcode;
759  if (ok == 0)
760    return MR_FILESYS_ACCESS;
761
762  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
763    return mr_errcode;
764
765  if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
766    return check_nfs(mach_id, name, rwaccess);
767
768  return MR_SUCCESS;
769}
770
771
772/* Verify the arguments, depending on the FStype.  Also, if this is an
773 * NFS filesystem, then update any quotas for that filesystem to reflect
774 * the new phys_id.
775 */
776
777int setup_ufil(struct query *q, char *argv[], client *cl)
778{
779  int mach_id, status;
780  char *type, *name;
781  EXEC SQL BEGIN DECLARE SECTION;
782  int fid, total, who, ok;
783  char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
784  short int total_null;
785  EXEC SQL END DECLARE SECTION;
786
787  _var_phys_id = 0;
788  type = argv[2];
789  mach_id = *(int *)argv[3];
790  name = argv[4];
791  access = argv[6];
792  fid = *(int *)argv[0];
793  who = cl->client_id;
794  entity = cl->entity;
795
796  sprintf(ftype, "fs_access_%s", type);
797  EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
798    WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
799  if (dbms_errno)
800    return mr_errcode;
801  if (ok == 0)
802    return MR_FILESYS_ACCESS;
803
804  EXEC SQL SELECT type INTO :ftype FROM filesys
805    WHERE filsys_id = :fid;
806  if (dbms_errno)
807    return mr_errcode;
808
809  if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
810    {
811      status = check_nfs(mach_id, name, access);
812      EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
813        WHERE filsys_id = :fid;
814      if (dbms_errno)
815        return mr_errcode;
816      return status;
817    }
818  else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
819           && strcmp(strtrim(ftype), "ERR"))
820    {
821      total = 0;
822      EXEC SQL DELETE FROM quota
823        WHERE type = 'ANY' AND filsys_id = :fid;
824      EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
825        WHERE filsys_id = :fid AND phys_id != 0;
826      if (dbms_errno)
827        return mr_errcode;
828      if (!total_null && (total != 0))
829        {
830          EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
831                                      type, modtime, modby, modwith)
832            VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
833          if (dbms_errno)
834            return mr_errcode;
835        }
836    }
837  else
838    {
839      EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
840      if (dbms_errno)
841        return mr_errcode;
842    }
843  return MR_SUCCESS;
844}
845
846
847/* Find the NFS physical partition that the named directory is on.
848 * This is done by comparing the dir against the mount point of the
849 * partition.  To make sure we get the correct match when there is
850 * more than one, we sort the query in reverse order by dir name.
851 */
852
853int check_nfs(int mach_id, char *name, char *access)
854{
855  EXEC SQL BEGIN DECLARE SECTION;
856  char dir[NFSPHYS_DIR_SIZE];
857  int mid = mach_id;
858  EXEC SQL END DECLARE SECTION;
859  int status;
860  char *cp1;
861  char *cp2;
862
863  status = MR_NFS;
864  EXEC SQL DECLARE csr101 CURSOR FOR
865    SELECT nfsphys_id, dir FROM nfsphys
866    WHERE mach_id = :mid
867    ORDER BY 2 DESC;
868  if (dbms_errno)
869    return mr_errcode;
870  EXEC SQL OPEN csr101;
871  if (dbms_errno)
872    return mr_errcode;
873  while (1)
874    {
875      EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
876      if (sqlca.sqlcode)
877        break;
878      cp1 = name;
879      cp2 = strtrim(dir);
880      while (*cp2)
881        {
882          if (*cp1++ != *cp2)
883            break;
884          cp2++;
885        }
886      if (!*cp2)
887        {
888          status = MR_SUCCESS;
889          break;
890        }
891    }
892  EXEC SQL CLOSE csr101;
893  if (dbms_errno)
894    return mr_errcode;
895  return status;
896}
897
898
899/* setup_dfil: free any quota records and fsgroup info associated with
900 * a filesystem when it is deleted.  Also adjust the allocation numbers.
901 */
902
903int setup_dfil(struct query *q, char **argv, client *cl)
904{
905  EXEC SQL BEGIN DECLARE SECTION;
906  int id, total, phys_id;
907  short int none;
908  EXEC SQL END DECLARE SECTION;
909
910  id = *(int *)argv[0];
911  EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
912    WHERE filsys_id = :id;
913
914  if (none)
915    total = 0;
916
917  /** What if there are multiple phys_id's per f/s? (bad data) **/
918  EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
919    WHERE filsys_id = :id;
920  EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
921    WHERE nfsphys_id = :phys_id;
922
923  if (!none)
924    EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
925  EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
926  EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
927  if (dbms_errno)
928    return mr_errcode;
929  return MR_SUCCESS;
930}
931
932
933/* setup_dnfp: check to see that the nfs physical partition does not have
934 * any filesystems assigned to it before allowing it to be deleted.
935 */
936
937int setup_dnfp(struct query *q, char **argv, client *cl)
938{
939  EXEC SQL BEGIN DECLARE SECTION;
940  int id, cnt;
941  char *dir;
942  EXEC SQL END DECLARE SECTION;
943
944  id = *(int *)argv[0];
945  dir = argv[1];
946  EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
947    WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
948    AND np.mach_id = :id AND np.dir = :dir;
949  if (cnt > 0)
950    return MR_IN_USE;
951  if (dbms_errno)
952    return mr_errcode;
953  return MR_SUCCESS;
954}
955
956
957/* setup_dqot: Remove allocation from nfsphys before deleting quota.
958 *   argv[0] = filsys_id
959 *   argv[1] = type if "update_quota" or "delete_quota"
960 *   argv[2 or 1] = users_id or list_id
961 */
962
963int setup_dqot(struct query *q, char **argv, client *cl)
964{
965  EXEC SQL BEGIN DECLARE SECTION;
966  int quota, fs, id, physid;
967  char *qtype;
968  EXEC SQL END DECLARE SECTION;
969
970  fs = *(int *)argv[0];
971  if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
972    {
973      qtype = argv[1];
974      id = *(int *)argv[2];
975    }
976  else
977    {
978      qtype = "USER";
979      id = *(int *)argv[1];
980    }
981
982  EXEC SQL SELECT quota INTO :quota FROM quota
983    WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
984  EXEC SQL SELECT phys_id INTO :physid FROM filesys
985    WHERE filsys_id = :fs;
986  EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
987    WHERE nfsphys_id = :physid;
988
989  if (dbms_errno)
990    return mr_errcode;
991  return MR_SUCCESS;
992}
993
994
995/* prefetch_value():
996 * This routine fetches an appropriate value from the numvalues table.
997 * It is a little hack to get around the fact that SQL doesn't let you
998 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
999 *
1000 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
1001 * from within a setup_...() routine with the appropriate arguments.
1002 *
1003 * Correct functioning of this routine may depend on the assumption
1004 * that this query is an MR_Q_APPEND.
1005 */
1006
1007int prefetch_value(struct query *q, char **argv, client *cl)
1008{
1009  EXEC SQL BEGIN DECLARE SECTION;
1010  char *name = q->validate->object_id;
1011  int value;
1012  EXEC SQL END DECLARE SECTION;
1013  int status, limit, argc;
1014
1015  /* set next object id, limiting it if necessary */
1016  if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
1017    limit = 1; /* So far as I know, this isn't needed.  Just CMA. */
1018  else
1019    limit = 0;
1020  if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
1021    return status;
1022
1023  /* fetch object id */
1024  EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
1025  if (dbms_errno)
1026    return mr_errcode;
1027  if (sqlca.sqlerrd[2] != 1)
1028    return MR_INTERNAL;
1029
1030  argc = q->argc + q->vcnt;   /* end of Argv for MR_Q_APPENDs */
1031  sprintf(argv[argc], "%d", value);
1032
1033  return MR_SUCCESS;
1034}
1035
1036/* prefetch_filesys():
1037 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
1038 * Appends the filsys_id and the phys_id to the argv so they can be
1039 * referenced in an INSERT into a table other than filesys.  Also
1040 * see comments at prefetch_value().
1041 *
1042 * Assumes the existence of a row where filsys_id = argv[0], since a
1043 * filesys label has already been resolved to a filsys_id.
1044 */
1045int prefetch_filesys(struct query *q, char **argv, client *cl)
1046{
1047  EXEC SQL BEGIN DECLARE SECTION;
1048  int fid, phid;
1049  EXEC SQL END DECLARE SECTION;
1050  int argc;
1051
1052  fid = *(int *)argv[0];
1053  EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
1054  if (dbms_errno)
1055    return mr_errcode;
1056
1057  argc = q->argc + q->vcnt;
1058  sprintf(argv[argc++], "%d", phid);
1059  sprintf(argv[argc], "%d", fid);
1060
1061  return MR_SUCCESS;
1062}
1063
1064
1065/* setup_ghst():
1066 */
1067
1068int setup_ghst(struct query *q, char **argv, client *cl)
1069{
1070  if (strcmp(argv[0], "*") || strcmp(argv[1], "*") ||
1071      strcmp(argv[2], "*") || strcmp(argv[3], "*"))
1072    return MR_SUCCESS;
1073  else
1074    return MR_PERM;
1075}
1076
1077/* setup_ahst():
1078 */
1079
1080int setup_ahst(struct query *q, char **argv, client *cl)
1081{
1082  EXEC SQL BEGIN DECLARE SECTION;
1083  char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
1084  char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
1085  int value, id, ssaddr, smask, shigh, slow, cnt;
1086  unsigned int saddr, mask, high, low;
1087  EXEC SQL END DECLARE SECTION;
1088  int row, idx;
1089  struct in_addr addr;
1090
1091  id = *(int *)argv[0];
1092
1093  if (!strcmp(q->shortname, "uhst"))
1094    {
1095      row = 1;
1096      EXEC SQL SELECT name, vendor, model, os
1097        INTO :oldname, :vendor, :model, :os
1098        FROM machine WHERE mach_id = :id;
1099    }
1100  else
1101    row = 0;
1102
1103  if (q->version < 6)
1104    idx = 0;
1105  else if (q->version >= 6 && q->version < 8)
1106    idx = 1;
1107  else
1108    idx = 2;
1109
1110  /* Sanity check name, vendor, model, and os. */
1111  if ((row == 0 || strcasecmp(argv[1], oldname)) &&
1112      !hostname_check(argv[row]))
1113    return MR_BAD_CHAR;
1114  if ((row == 0 || strcasecmp(argv[2], vendor)) &&
1115      !hostinfo_check(argv[row + 1], 0))
1116    return MR_BAD_CHAR;
1117  if ((row == 0 || strcasecmp(argv[3], model)) &&
1118      !hostinfo_check(argv[row + 2], 1))
1119    return MR_BAD_CHAR;
1120  if ((row == 0 || strcasecmp(argv[4], os)) &&
1121      !hostinfo_check(argv[row + 3], 0))
1122    return MR_BAD_CHAR;
1123
1124  /* check for duplicate name */
1125  name = argv[row];
1126  EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
1127    WHERE name = UPPER(:name);
1128  if (dbms_errno)
1129    return mr_errcode;
1130  if (cnt != 0)
1131    return MR_EXISTS;
1132
1133  /* check address */
1134  if (!strcmp(argv[9 + row + idx], "unassigned"))
1135    value = -1;
1136  else if (!strcmp(argv[9 + row + idx], "unique"))
1137    {
1138      if (*(int *)argv[8 + row + idx] == 0)
1139        value = -1;
1140      else
1141        value = -2;
1142    }
1143  else
1144    {
1145      value = ntohl(inet_addr(argv[9 + row + idx]));
1146      if (value == -1)
1147        return MR_ADDRESS;
1148    }
1149  if (value == 0)
1150    return MR_ADDRESS;
1151  if (value != -1)
1152    {
1153      /*
1154       * an address or unique was specified.
1155       */
1156      id = *(int *)argv[8 + row + idx];
1157      EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
1158        :shigh, :slow FROM subnet WHERE snet_id = :id;
1159      if (dbms_errno)
1160        return mr_errcode;
1161      saddr = (unsigned) ssaddr;
1162      mask = (unsigned) smask;
1163      high = (unsigned) shigh;
1164      low = (unsigned) slow;
1165      if (value != -2)
1166        {
1167          /*
1168           * someone specified an IP address for the host record
1169           */
1170          if ((value & mask) != saddr || value < low || value > high)
1171            return MR_ADDRESS;
1172          /*
1173           * run the address argument through inet_addr(). This
1174           * has the effect that any out of bounds host addrs will
1175           * be converted to a valid host addr. We do this now
1176           * so that the uniqueness check works. We should also
1177           * link in an inet_addr() that returns an error for
1178           * this case.
1179           */
1180          addr.s_addr = inet_addr(argv[9 + row + idx]);
1181          name = inet_ntoa(addr);
1182          EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1183            WHERE address = :name;
1184          if (dbms_errno)
1185            return mr_errcode;
1186          if (cnt > 0)
1187            {
1188              /*
1189               * make IP address is unique. If this a modify request
1190               * (row == 1), then we expect one record to exist.
1191               */
1192              if (row == 0 || (row == 1 && cnt > 1))
1193                return MR_ADDRESS;
1194              if (row == 1 && cnt == 1)
1195                {
1196                  EXEC SQL SELECT mach_id INTO :id FROM machine
1197                    WHERE address = :name;
1198                  if (id != *(int *)argv[0])
1199                    return MR_ADDRESS;
1200                }
1201            }
1202        }
1203      else
1204        {
1205          /*
1206           * a "unique" address was specified. Walk through the
1207           * range specified in the network record, return
1208           * error if no room left.
1209           */
1210          for (id = low; id <= high; id++)
1211            {
1212              if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1213                continue;
1214              addr.s_addr = htonl(id);
1215              name = inet_ntoa(addr);
1216              EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1217                WHERE address = :name;
1218              if (dbms_errno)
1219                return mr_errcode;
1220              if (cnt == 0)
1221                break;
1222            }
1223          if (cnt != 0)
1224            return MR_NO_ID;
1225          else
1226            value = htonl(id);
1227        }
1228      strcpy(argv[9 + row + idx], name);
1229    }
1230  else
1231    strcpy(argv[9 + row + idx], "unassigned");
1232
1233  /* status checking */
1234  value = atoi(argv[7 + row + idx]);
1235  if (row == 0 && !(value == 1 || value == 0))
1236    return MR_TYPE;
1237  if (row == 1)
1238    {
1239      id = *(int *)argv[0];
1240      EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1241      if (dbms_errno)
1242        return mr_errcode;
1243      if (value != cnt)
1244        {
1245          EXEC SQL UPDATE machine SET statuschange = SYSDATE
1246            WHERE mach_id = :id;
1247        }
1248    }
1249
1250  /*
1251   * If this is an update_host query, we're done.
1252   */
1253  if (row == 1)
1254    return MR_SUCCESS;
1255
1256  /*
1257   * For an add_host query, allocate and fill in a new machine id,
1258   * and then insert the creator id.
1259   */
1260  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1261    return mr_errcode;
1262
1263  sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1264  return MR_SUCCESS;
1265}
1266
1267
1268/* setup_ahal():
1269 */
1270
1271int setup_ahal(struct query *q, char **argv, client *cl)
1272{
1273  EXEC SQL BEGIN DECLARE SECTION;
1274  char *name;
1275  int cnt;
1276  EXEC SQL END DECLARE SECTION;
1277  char *p;
1278
1279  name = argv[0];
1280  if (!hostname_check(argv[0]))
1281    return MR_BAD_CHAR;
1282
1283  EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1284    name = UPPER(:name);
1285  if (dbms_errno)
1286    return mr_errcode;
1287  if (cnt > 0)
1288    return MR_EXISTS;
1289
1290  return MR_SUCCESS;
1291}
1292
1293/* setup_ahha(): Check characters in hwaddr, and make sure it's not
1294 * a duplicate.
1295 */
1296int setup_ahha(struct query *q, char **argv, client *cl)
1297{
1298  EXEC SQL BEGIN DECLARE SECTION;
1299  char *hwaddr = argv[1];
1300  int count;
1301  EXEC SQL END DECLARE SECTION;
1302  char *p;
1303
1304  if (strlen(hwaddr) == 0)
1305    return MR_BAD_CHAR;
1306
1307  if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1308    {
1309      for (p = hwaddr; *p; p++)
1310        {
1311          if (isupper(*p))
1312            *p = tolower(*p);
1313          if (!isxdigit(*p))
1314            return MR_BAD_CHAR;
1315        }
1316      if (p != hwaddr + 12)
1317        return MR_ADDRESS;
1318
1319      EXEC SQL SELECT COUNT(hwaddr) INTO :count
1320        FROM hwaddrmap WHERE hwaddr = :hwaddr;
1321      if (count)
1322        return MR_NOT_UNIQUE;
1323    }
1324
1325  return MR_SUCCESS;
1326}
1327
1328/* setup_aprn(): Make sure name/duplexname don't conflict with
1329 * anything. If [ANY] was specified for the spooling host, pick the
1330 * least loaded print server that serves this kind of printer.
1331 */
1332int setup_aprn(struct query *q, char **argv, client *cl)
1333{
1334  int best = -1, row, idx = 0;
1335  char *p;
1336  EXEC SQL BEGIN DECLARE SECTION;
1337  int mid, usage, count;
1338  char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1339  char *service;
1340  EXEC SQL END DECLARE SECTION;
1341
1342  /* Check for aprn or uprn. */
1343  if (q->type == MR_Q_APPEND)
1344    row = 0;
1345  else
1346    row = 1;
1347
1348  if (q->version >= 13)
1349    idx = 3;
1350
1351  name = argv[PRN_NAME + row];
1352  duplexname = argv[PRN_DUPLEXNAME + row];
1353  oldname = argv[0];
1354
1355  if (!*name)
1356    return MR_BAD_CHAR;
1357  else
1358    {
1359      if (q->type == MR_Q_APPEND)
1360        {
1361          EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1362            WHERE name = :name OR duplexname = :name;
1363        }
1364      else
1365        {
1366          EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1367            WHERE ( name = :name OR duplexname = :name )
1368            AND name != :oldname;
1369        }
1370      if (dbms_errno)
1371        return mr_errcode;
1372      if (count)
1373        return MR_NOT_UNIQUE;
1374    }
1375
1376  if (*duplexname)
1377    {
1378      if (q->type == MR_Q_APPEND)
1379        {
1380          EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1381            WHERE name = :duplexname OR duplexname = :duplexname;
1382        }
1383      else
1384        {
1385          EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1386            WHERE ( name = :duplexname OR duplexname = :duplexname )
1387            AND name != :oldname;
1388        }
1389
1390      if (dbms_errno)
1391        return mr_errcode;
1392      if (count)
1393        return MR_NOT_UNIQUE;
1394    }
1395
1396  if (!strcmp(name, duplexname))
1397    return MR_NOT_UNIQUE;
1398
1399  mid = *(int *)argv[6 + row + idx];
1400  if (mid == -1)
1401    {
1402      if (!strcasecmp(argv[PRN_TYPE + row], "DORM") ||
1403          !strcasecmp(argv[PRN_TYPE + row], "CLUSTER"))
1404        service = "CUPS-CLUSTER";
1405      else
1406        service = "CUPS-PRINT";
1407
1408      EXEC SQL DECLARE csr_rm CURSOR FOR
1409        SELECT ps.mach_id, s.string FROM printservers ps, strings s
1410        WHERE ps.mach_id IN
1411        ( SELECT mach_id FROM serverhosts WHERE service = :service
1412          AND enable = 1 )
1413        AND ps.printer_types = s.string_id;
1414
1415      if (dbms_errno)
1416        return mr_errcode;
1417      EXEC SQL OPEN csr_rm;
1418      if (dbms_errno)
1419        return mr_errcode;
1420
1421      while (1)
1422        {
1423          EXEC SQL FETCH csr_rm INTO :mid, :types;
1424          if (sqlca.sqlcode)
1425            break;
1426
1427          for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1428            {
1429              if (!strcasecmp(argv[PRN_TYPE + row], p))
1430                {
1431                  EXEC SQL SELECT COUNT(name) INTO :usage
1432                    FROM printers WHERE rm = :mid;
1433
1434                  if (best < 0 || usage < best)
1435                    {
1436                      best = usage;
1437                      *(int *)argv[6 + row + idx] = mid;
1438                      break;
1439                    }
1440                }
1441            }
1442        }
1443      EXEC SQL CLOSE csr_rm;
1444      if (dbms_errno)
1445        return mr_errcode;
1446
1447      if (best == -1)
1448        return MR_SERVICE;
1449    }
1450  else
1451    {
1452      EXEC SQL SELECT mach_id INTO :mid FROM printservers
1453        WHERE mach_id = :mid;
1454      if (sqlca.sqlcode)
1455        return MR_SERVICE;
1456    }
1457
1458  return MR_SUCCESS;
1459}
1460
1461int setup_dpsv(struct query *q, char **argv, client *cl)
1462{
1463  int id;
1464  EXEC SQL BEGIN DECLARE SECTION;
1465  int cnt;
1466  EXEC SQL END DECLARE SECTION;
1467
1468  id = *(int *)argv[0];
1469
1470  EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1471    WHERE rm = :id;
1472  if (cnt > 0)
1473    return MR_IN_USE;
1474
1475  return MR_SUCCESS;
1476}
1477
1478int setup_dcon(struct query *q, char *argv[], client *cl)
1479{
1480  EXEC SQL BEGIN DECLARE SECTION;
1481  int id, cnt;
1482  char containername[CONTAINERS_NAME_SIZE];
1483  EXEC SQL END DECLARE SECTION;
1484
1485  id = *(int *)argv[0];
1486  /* check to see if there are machines in this container */
1487  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1488    WHERE cnt_id = :id;
1489  if (cnt > 0)
1490    return MR_IN_USE;
1491
1492  /* check to see if there are subcontainers in this container */
1493
1494  /* get the container name */
1495 
1496  EXEC SQL SELECT name INTO :containername
1497    FROM containers
1498    WHERE cnt_id = :id;
1499
1500  /* trim off the trailing spaces */
1501   strcpy(containername, strtrim(containername));
1502
1503  EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1504    WHERE LOWER(name) LIKE LOWER(:containername || '/' || '%');
1505
1506  if (cnt > 0)
1507    return MR_IN_USE;
1508
1509  if (dbms_errno)
1510    return mr_errcode;
1511  return MR_SUCCESS;
1512}
1513
1514int setup_scli(struct query *q, char *argv[], client *cl)
1515{
1516  EXEC SQL BEGIN DECLARE SECTION;
1517  int cnt_id, list_id;
1518  EXEC SQL END DECLARE SECTION;
1519
1520  cnt_id = *(int *)argv[0];
1521  /* Check if someone has already set the list for this container */
1522  EXEC SQL SELECT list_id INTO :list_id FROM containers
1523    WHERE cnt_id = :cnt_id;
1524  if (list_id != 0)
1525    return MR_EXISTS;
1526
1527  if (dbms_errno)
1528    return mr_errcode;
1529
1530  return MR_SUCCESS;
1531}
1532
1533/* hostname_check()
1534 * validate the rfc1035/rfc1123-ness of a hostname
1535 */
1536
1537int hostname_check(char *name)
1538{
1539  char *p;
1540  int count;
1541
1542  /* Sanity check name: must contain only letters, numerals, and
1543   * hyphen, and not start or end with a hyphen. Also make sure no
1544   * label (the thing the .s seperate) is longer than 63 characters,
1545   * or empty.
1546   */
1547
1548  for (p = name, count = 0; *p; p++)
1549    {
1550      count++;
1551      if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1552          (*p == '-' && p[1] == '.'))
1553        return 0;
1554      if (*p == '.')
1555        {
1556          if (count == 1)
1557            return 0;
1558          count = 0;
1559        }
1560      if (count == 64)
1561        return 0;
1562    }
1563  if (*(p - 1) == '-')
1564    return 0;
1565  return 1;
1566}
1567
1568int hostinfo_check(char *info, int num)
1569{
1570  char *p;
1571
1572  if (!*info)
1573    return 1;
1574
1575  /* Sanity check host hostinfo: must start with a letter (or number
1576   * if num is true), contain only letters, numerals, and hyphen, and
1577   * not end with a hyphen.
1578   */
1579
1580  if (!isalpha(*info) && (!num || !isdigit(*info)))
1581    return 0;
1582  for (p = info; *p; p++)
1583    {
1584      if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1585          (*p == '-' && p[1] == '.'))
1586        return 0;
1587    }
1588  if (!isalnum(*(p - 1)))
1589    return 1;
1590
1591  return 1;
1592}
1593
1594int setup_aali(struct query *q, char *argv[], client *cl)
1595{
1596  EXEC SQL BEGIN DECLARE SECTION;
1597  int cnt;
1598  char *name, *type, *trans;
1599  EXEC SQL END DECLARE SECTION;
1600  name = argv[0];
1601  type = argv[1];
1602  trans = argv[2];
1603
1604  if (strcmp(strtrim(type), "FILESYS"))
1605    return MR_SUCCESS;
1606
1607  EXEC SQL SELECT count(label) INTO :cnt FROM filesys WHERE
1608    label = :name;
1609  if (cnt > 0)
1610    return MR_EXISTS;
1611
1612  return MR_SUCCESS;
1613}
1614
1615int setup_acon(struct query *q, char *argv[], client *cl)
1616{
1617  EXEC SQL BEGIN DECLARE SECTION;
1618  char containername[CONTAINERS_NAME_SIZE];
1619  EXEC SQL END DECLARE SECTION;
1620 
1621  char* ptr;
1622 
1623  memset(containername, 0, sizeof(containername));
1624  strcpy(containername, argv[0]);
1625  ptr = strrchr(containername, '/');
1626  /* sub container, check for parents */
1627  if (ptr)
1628    {
1629      *ptr = '\0';
1630      EXEC SQL SELECT * FROM containers
1631        WHERE lower(name) = lower(:containername);     
1632      if (sqlca.sqlerrd[2] != 1)
1633        return MR_CONTAINER_NO_PARENT;
1634    }
1635 
1636  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1637    return mr_errcode;
1638 
1639  return MR_SUCCESS;
1640}
1641
1642int check_mailman_listname(char *name, const char *suffix)
1643{
1644  char *p;
1645  EXEC SQL BEGIN DECLARE SECTION;
1646  int i, cnt;
1647  EXEC SQL END DECLARE SECTION;
1648
1649  p = strstr(name, suffix);
1650  if (p)
1651    {
1652      if (strlen(name) == (p - name + strlen(suffix)))
1653        {
1654          /* list is of the form "name-suffix" */
1655          i = (p - name);
1656          EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
1657            WHERE name = SUBSTR(:name, 1, :i) AND mailman = 1;
1658          if (cnt > 0)
1659            return MR_EXISTS;
1660        }
1661    }
1662
1663  return MR_SUCCESS;
1664}
Note: See TracBrowser for help on using the repository browser.