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

Revision 23178, 40.4 KB checked in by broder, 16 years ago (diff)
Take a new snapshot from CVS for Moira, and add a debathena-moira-update-server package
Line 
1/* $Id$
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("$Header$");
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, 0, 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      /*
1229       * we have an address in value. Convert it to a string and store it.
1230       */
1231      addr.s_addr = htonl(value);
1232      strcpy(argv[9 + row + idx], inet_ntoa(addr));
1233    }
1234  else
1235    strcpy(argv[9 + row + idx], "unassigned");
1236
1237  /* status checking */
1238  value = atoi(argv[7 + row + idx]);
1239  if (row == 0 && !(value == 1 || value == 0))
1240    return MR_TYPE;
1241  if (row == 1)
1242    {
1243      id = *(int *)argv[0];
1244      EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1245      if (dbms_errno)
1246        return mr_errcode;
1247      if (value != cnt)
1248        {
1249          EXEC SQL UPDATE machine SET statuschange = SYSDATE
1250            WHERE mach_id = :id;
1251        }
1252    }
1253
1254  /*
1255   * If this is an update_host query, we're done.
1256   */
1257  if (row == 1)
1258    return MR_SUCCESS;
1259
1260  /*
1261   * For an add_host query, allocate and fill in a new machine id,
1262   * and then insert the creator id.
1263   */
1264  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1265    return mr_errcode;
1266
1267  sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1268  return MR_SUCCESS;
1269}
1270
1271
1272/* setup_ahal():
1273 */
1274
1275int setup_ahal(struct query *q, char **argv, client *cl)
1276{
1277  EXEC SQL BEGIN DECLARE SECTION;
1278  char *name;
1279  int cnt;
1280  EXEC SQL END DECLARE SECTION;
1281  char *p;
1282
1283  name = argv[0];
1284  if (!hostname_check(argv[0]))
1285    return MR_BAD_CHAR;
1286
1287  EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1288    name = UPPER(:name);
1289  if (dbms_errno)
1290    return mr_errcode;
1291  if (cnt > 0)
1292    return MR_EXISTS;
1293
1294  return MR_SUCCESS;
1295}
1296
1297/* setup_uhha(): Check characters in hwaddr, and make sure it's not
1298 * a duplicate.
1299 */
1300int setup_uhha(struct query *q, char **argv, client *cl)
1301{
1302  EXEC SQL BEGIN DECLARE SECTION;
1303  char *hwaddr = argv[1];
1304  int count;
1305  EXEC SQL END DECLARE SECTION;
1306  char *p;
1307
1308  if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1309    {
1310      for (p = hwaddr; *p; p++)
1311        {
1312          if (isupper(*p))
1313            *p = tolower(*p);
1314          if (!isxdigit(*p))
1315            return MR_BAD_CHAR;
1316        }
1317      if (p != hwaddr + 12)
1318        return MR_ADDRESS;
1319
1320      EXEC SQL SELECT COUNT(hwaddr) INTO :count
1321        FROM machine WHERE hwaddr = :hwaddr;
1322      if (count)
1323        return MR_NOT_UNIQUE;
1324    }
1325
1326  return MR_SUCCESS;
1327}
1328
1329/* setup_aprn(): Make sure name/duplexname don't conflict with
1330 * anything. If [ANY] was specified for the spooling host, pick the
1331 * least loaded print server that serves this kind of printer.
1332 */
1333int setup_aprn(struct query *q, char **argv, client *cl)
1334{
1335  int best = -1, row;
1336  char *p;
1337  EXEC SQL BEGIN DECLARE SECTION;
1338  int mid, usage, count;
1339  char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
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  name = argv[PRN_NAME + row];
1349  duplexname = argv[PRN_DUPLEXNAME + row];
1350  oldname = argv[0];
1351
1352  if (!*name)
1353    return MR_BAD_CHAR;
1354  else
1355    {
1356      if (q->type == MR_Q_APPEND)
1357        {
1358          EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1359            WHERE name = :name OR duplexname = :name;
1360        }
1361      else
1362        {
1363          EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1364            WHERE ( name = :name OR duplexname = :name )
1365            AND name != :oldname;
1366        }
1367      if (dbms_errno)
1368        return mr_errcode;
1369      if (count)
1370        return MR_NOT_UNIQUE;
1371    }
1372
1373  if (*duplexname)
1374    {
1375      if (q->type == MR_Q_APPEND)
1376        {
1377          EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1378            WHERE name = :duplexname OR duplexname = :duplexname;
1379        }
1380      else
1381        {
1382          EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1383            WHERE ( name = :duplexname OR duplexname = :duplexname )
1384            AND name != :oldname;
1385        }
1386
1387      if (dbms_errno)
1388        return mr_errcode;
1389      if (count)
1390        return MR_NOT_UNIQUE;
1391    }
1392
1393  if (!strcmp(name, duplexname))
1394    return MR_NOT_UNIQUE;
1395
1396  mid = *(int *)argv[PRN_RM + row];
1397  if (mid == -1)
1398    {
1399      EXEC SQL DECLARE csr_rm CURSOR FOR
1400        SELECT ps.mach_id, s.string FROM printservers ps, strings s
1401        WHERE ps.mach_id IN
1402        ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1403          AND enable = 1 )
1404        AND ps.printer_types = s.string_id;
1405      if (dbms_errno)
1406        return mr_errcode;
1407      EXEC SQL OPEN csr_rm;
1408      if (dbms_errno)
1409        return mr_errcode;
1410
1411      while (1)
1412        {
1413          EXEC SQL FETCH csr_rm INTO :mid, :types;
1414          if (sqlca.sqlcode)
1415            break;
1416
1417          for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1418            {
1419              if (!strcasecmp(argv[PRN_TYPE + row], p))
1420                {
1421                  EXEC SQL SELECT COUNT(name) INTO :usage
1422                    FROM printers WHERE rm = :mid;
1423
1424                  if (best < 0 || usage < best)
1425                    {
1426                      best = usage;
1427                      *(int *)argv[PRN_RM + row] = mid;
1428                      break;
1429                    }
1430                }
1431            }
1432        }
1433      EXEC SQL CLOSE csr_rm;
1434      if (dbms_errno)
1435        return mr_errcode;
1436
1437      if (best == -1)
1438        return MR_SERVICE;
1439    }
1440  else
1441    {
1442      EXEC SQL SELECT mach_id INTO :mid FROM printservers
1443        WHERE mach_id = :mid;
1444      if (sqlca.sqlcode)
1445        return MR_SERVICE;
1446    }
1447
1448  return MR_SUCCESS;
1449}
1450
1451int setup_dpsv(struct query *q, char **argv, client *cl)
1452{
1453  int id;
1454  EXEC SQL BEGIN DECLARE SECTION;
1455  int cnt;
1456  EXEC SQL END DECLARE SECTION;
1457
1458  id = *(int *)argv[0];
1459
1460  EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1461    WHERE rm = :id;
1462  if (cnt > 0)
1463    return MR_IN_USE;
1464
1465  return MR_SUCCESS;
1466}
1467
1468int setup_dcon(struct query *q, char *argv[], client *cl)
1469{
1470  EXEC SQL BEGIN DECLARE SECTION;
1471  int id, cnt;
1472  char containername[CONTAINERS_NAME_SIZE];
1473  EXEC SQL END DECLARE SECTION;
1474
1475  id = *(int *)argv[0];
1476  /* check to see if there are machines in this container */
1477  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1478    WHERE cnt_id = :id;
1479  if (cnt > 0)
1480    return MR_IN_USE;
1481
1482  /* check to see if there are subcontainers in this container */
1483
1484  /* get the container name */
1485 
1486  EXEC SQL SELECT name INTO :containername
1487    FROM containers
1488    WHERE cnt_id = :id;
1489
1490  /* trim off the trailing spaces */
1491   strcpy(containername, strtrim(containername));
1492
1493  EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1494    WHERE LOWER(name) LIKE LOWER(:containername || '/' || '%');
1495
1496  if (cnt > 0)
1497    return MR_IN_USE;
1498
1499  if (dbms_errno)
1500    return mr_errcode;
1501  return MR_SUCCESS;
1502}
1503
1504int setup_scli(struct query *q, char *argv[], client *cl)
1505{
1506  EXEC SQL BEGIN DECLARE SECTION;
1507  int cnt_id, list_id;
1508  EXEC SQL END DECLARE SECTION;
1509
1510  cnt_id = *(int *)argv[0];
1511  /* Check if someone has already set the list for this container */
1512  EXEC SQL SELECT list_id INTO :list_id FROM containers
1513    WHERE cnt_id = :cnt_id;
1514  if (list_id != 0)
1515    return MR_EXISTS;
1516
1517  if (dbms_errno)
1518    return mr_errcode;
1519
1520  return MR_SUCCESS;
1521}
1522
1523/* hostname_check()
1524 * validate the rfc1035/rfc1123-ness of a hostname
1525 */
1526
1527int hostname_check(char *name)
1528{
1529  char *p;
1530  int count;
1531
1532  /* Sanity check name: must contain only letters, numerals, and
1533   * hyphen, and not start or end with a hyphen. Also make sure no
1534   * label (the thing the .s seperate) is longer than 63 characters,
1535   * or empty.
1536   */
1537
1538  for (p = name, count = 0; *p; p++)
1539    {
1540      count++;
1541      if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1542          (*p == '-' && p[1] == '.'))
1543        return 0;
1544      if (*p == '.')
1545        {
1546          if (count == 1)
1547            return 0;
1548          count = 0;
1549        }
1550      if (count == 64)
1551        return 0;
1552    }
1553  if (*(p - 1) == '-')
1554    return 0;
1555  return 1;
1556}
1557
1558int hostinfo_check(char *info, int num)
1559{
1560  char *p;
1561
1562  if (!*info)
1563    return 1;
1564
1565  /* Sanity check host hostinfo: must start with a letter (or number
1566   * if num is true), contain only letters, numerals, and hyphen, and
1567   * not end with a hyphen.
1568   */
1569
1570  if (!isalpha(*info) && (!num || !isdigit(*info)))
1571    return 0;
1572  for (p = info; *p; p++)
1573    {
1574      if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1575          (*p == '-' && p[1] == '.'))
1576        return 0;
1577    }
1578  if (!isalnum(*(p - 1)))
1579    return 1;
1580}
1581
1582int setup_acon(struct query *q, char *argv[], client *cl)
1583{
1584  EXEC SQL BEGIN DECLARE SECTION;
1585  char containername[CONTAINERS_NAME_SIZE];
1586  EXEC SQL END DECLARE SECTION;
1587 
1588  char* ptr;
1589 
1590  memset(containername, 0, sizeof(containername));
1591  strcpy(containername, argv[0]);
1592  ptr = strrchr(containername, '/');
1593  /* sub container, check for parents */
1594  if (ptr)
1595    {
1596      *ptr = '\0';
1597      EXEC SQL SELECT * FROM containers
1598        WHERE lower(name) = lower(:containername);     
1599      if (sqlca.sqlerrd[2] != 1)
1600        return MR_CONTAINER_NO_PARENT;
1601    }
1602 
1603  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1604    return mr_errcode;
1605 
1606  return MR_SUCCESS;
1607}
1608
1609int check_mailman_listname(char *name, const char *suffix)
1610{
1611  char *p;
1612  EXEC SQL BEGIN DECLARE SECTION;
1613  int i, cnt;
1614  EXEC SQL END DECLARE SECTION;
1615
1616  p = strstr(name, suffix);
1617  if (p)
1618    {
1619      if (strlen(name) == (p - name + strlen(suffix)))
1620        {
1621          /* list is of the form "name-suffix" */
1622          i = (p - name);
1623          EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
1624            WHERE name = SUBSTR(:name, 1, :i) AND mailman = 1;
1625          if (cnt > 0)
1626            return MR_EXISTS;
1627        }
1628    }
1629
1630  return MR_SUCCESS;
1631}
Note: See TracBrowser for help on using the repository browser.