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

Revision 24319, 41.2 KB checked in by broder, 15 years ago (diff)
New Moira snapshot from SVN.
Line 
1/* $Id: qsetup.pc 3985 2010-02-23 21:00:36Z 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 3985 2010-02-23 21:00:36Z 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, 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      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_uhha(): Check characters in hwaddr, and make sure it's not
1294 * a duplicate.
1295 */
1296int setup_uhha(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 (*hwaddr && strcasecmp(hwaddr, "unknown"))
1305    {
1306      for (p = hwaddr; *p; p++)
1307        {
1308          if (isupper(*p))
1309            *p = tolower(*p);
1310          if (!isxdigit(*p))
1311            return MR_BAD_CHAR;
1312        }
1313      if (p != hwaddr + 12)
1314        return MR_ADDRESS;
1315
1316      EXEC SQL SELECT COUNT(hwaddr) INTO :count
1317        FROM machine WHERE hwaddr = :hwaddr;
1318      if (count)
1319        return MR_NOT_UNIQUE;
1320    }
1321
1322  return MR_SUCCESS;
1323}
1324
1325/* setup_aprn(): Make sure name/duplexname don't conflict with
1326 * anything. If [ANY] was specified for the spooling host, pick the
1327 * least loaded print server that serves this kind of printer.
1328 */
1329int setup_aprn(struct query *q, char **argv, client *cl)
1330{
1331  int best = -1, row, idx = 0;
1332  char *p;
1333  EXEC SQL BEGIN DECLARE SECTION;
1334  int mid, usage, count;
1335  char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1336  char *service;
1337  EXEC SQL END DECLARE SECTION;
1338
1339  /* Check for aprn or uprn. */
1340  if (q->type == MR_Q_APPEND)
1341    row = 0;
1342  else
1343    row = 1;
1344
1345  if (q->version >= 13)
1346    idx = 3;
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[6 + row + idx];
1397  if (mid == -1)
1398    {
1399      if (!strcasecmp(argv[PRN_TYPE + row], "SAP"))
1400        service = "PRINT";
1401      else if (!strcasecmp(argv[PRN_TYPE + row], "DORM") ||
1402               !strcasecmp(argv[PRN_TYPE + row], "CLUSTER"))
1403        service = "CUPS-CLUSTER";
1404      else
1405        service = "CUPS-PRINT";
1406
1407      EXEC SQL DECLARE csr_rm CURSOR FOR
1408        SELECT ps.mach_id, s.string FROM printservers ps, strings s
1409        WHERE ps.mach_id IN
1410        ( SELECT mach_id FROM serverhosts WHERE service = :service
1411          AND enable = 1 )
1412        AND ps.printer_types = s.string_id;
1413
1414      if (dbms_errno)
1415        return mr_errcode;
1416      EXEC SQL OPEN csr_rm;
1417      if (dbms_errno)
1418        return mr_errcode;
1419
1420      while (1)
1421        {
1422          EXEC SQL FETCH csr_rm INTO :mid, :types;
1423          if (sqlca.sqlcode)
1424            break;
1425
1426          for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1427            {
1428              if (!strcasecmp(argv[PRN_TYPE + row], p))
1429                {
1430                  EXEC SQL SELECT COUNT(name) INTO :usage
1431                    FROM printers WHERE rm = :mid;
1432
1433                  if (best < 0 || usage < best)
1434                    {
1435                      best = usage;
1436                      *(int *)argv[6 + row + idx] = mid;
1437                      break;
1438                    }
1439                }
1440            }
1441        }
1442      EXEC SQL CLOSE csr_rm;
1443      if (dbms_errno)
1444        return mr_errcode;
1445
1446      if (best == -1)
1447        return MR_SERVICE;
1448    }
1449  else
1450    {
1451      EXEC SQL SELECT mach_id INTO :mid FROM printservers
1452        WHERE mach_id = :mid;
1453      if (sqlca.sqlcode)
1454        return MR_SERVICE;
1455    }
1456
1457  return MR_SUCCESS;
1458}
1459
1460int setup_dpsv(struct query *q, char **argv, client *cl)
1461{
1462  int id;
1463  EXEC SQL BEGIN DECLARE SECTION;
1464  int cnt;
1465  EXEC SQL END DECLARE SECTION;
1466
1467  id = *(int *)argv[0];
1468
1469  EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1470    WHERE rm = :id;
1471  if (cnt > 0)
1472    return MR_IN_USE;
1473
1474  return MR_SUCCESS;
1475}
1476
1477int setup_dcon(struct query *q, char *argv[], client *cl)
1478{
1479  EXEC SQL BEGIN DECLARE SECTION;
1480  int id, cnt;
1481  char containername[CONTAINERS_NAME_SIZE];
1482  EXEC SQL END DECLARE SECTION;
1483
1484  id = *(int *)argv[0];
1485  /* check to see if there are machines in this container */
1486  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1487    WHERE cnt_id = :id;
1488  if (cnt > 0)
1489    return MR_IN_USE;
1490
1491  /* check to see if there are subcontainers in this container */
1492
1493  /* get the container name */
1494 
1495  EXEC SQL SELECT name INTO :containername
1496    FROM containers
1497    WHERE cnt_id = :id;
1498
1499  /* trim off the trailing spaces */
1500   strcpy(containername, strtrim(containername));
1501
1502  EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1503    WHERE LOWER(name) LIKE LOWER(:containername || '/' || '%');
1504
1505  if (cnt > 0)
1506    return MR_IN_USE;
1507
1508  if (dbms_errno)
1509    return mr_errcode;
1510  return MR_SUCCESS;
1511}
1512
1513int setup_scli(struct query *q, char *argv[], client *cl)
1514{
1515  EXEC SQL BEGIN DECLARE SECTION;
1516  int cnt_id, list_id;
1517  EXEC SQL END DECLARE SECTION;
1518
1519  cnt_id = *(int *)argv[0];
1520  /* Check if someone has already set the list for this container */
1521  EXEC SQL SELECT list_id INTO :list_id FROM containers
1522    WHERE cnt_id = :cnt_id;
1523  if (list_id != 0)
1524    return MR_EXISTS;
1525
1526  if (dbms_errno)
1527    return mr_errcode;
1528
1529  return MR_SUCCESS;
1530}
1531
1532/* hostname_check()
1533 * validate the rfc1035/rfc1123-ness of a hostname
1534 */
1535
1536int hostname_check(char *name)
1537{
1538  char *p;
1539  int count;
1540
1541  /* Sanity check name: must contain only letters, numerals, and
1542   * hyphen, and not start or end with a hyphen. Also make sure no
1543   * label (the thing the .s seperate) is longer than 63 characters,
1544   * or empty.
1545   */
1546
1547  for (p = name, count = 0; *p; p++)
1548    {
1549      count++;
1550      if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1551          (*p == '-' && p[1] == '.'))
1552        return 0;
1553      if (*p == '.')
1554        {
1555          if (count == 1)
1556            return 0;
1557          count = 0;
1558        }
1559      if (count == 64)
1560        return 0;
1561    }
1562  if (*(p - 1) == '-')
1563    return 0;
1564  return 1;
1565}
1566
1567int hostinfo_check(char *info, int num)
1568{
1569  char *p;
1570
1571  if (!*info)
1572    return 1;
1573
1574  /* Sanity check host hostinfo: must start with a letter (or number
1575   * if num is true), contain only letters, numerals, and hyphen, and
1576   * not end with a hyphen.
1577   */
1578
1579  if (!isalpha(*info) && (!num || !isdigit(*info)))
1580    return 0;
1581  for (p = info; *p; p++)
1582    {
1583      if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1584          (*p == '-' && p[1] == '.'))
1585        return 0;
1586    }
1587  if (!isalnum(*(p - 1)))
1588    return 1;
1589
1590  return 1;
1591}
1592
1593int setup_aali(struct query *q, char *argv[], client *cl)
1594{
1595  EXEC SQL BEGIN DECLARE SECTION;
1596  int cnt;
1597  char *name, *type, *trans;
1598  EXEC SQL END DECLARE SECTION;
1599  name = argv[0];
1600  type = argv[1];
1601  trans = argv[2];
1602
1603  if (strcmp(strtrim(type), "FILESYS"))
1604    return MR_SUCCESS;
1605
1606  EXEC SQL SELECT count(label) INTO :cnt FROM filesys WHERE
1607    label = :name;
1608  if (cnt > 0)
1609    return MR_EXISTS;
1610
1611  return MR_SUCCESS;
1612}
1613
1614int setup_acon(struct query *q, char *argv[], client *cl)
1615{
1616  EXEC SQL BEGIN DECLARE SECTION;
1617  char containername[CONTAINERS_NAME_SIZE];
1618  EXEC SQL END DECLARE SECTION;
1619 
1620  char* ptr;
1621 
1622  memset(containername, 0, sizeof(containername));
1623  strcpy(containername, argv[0]);
1624  ptr = strrchr(containername, '/');
1625  /* sub container, check for parents */
1626  if (ptr)
1627    {
1628      *ptr = '\0';
1629      EXEC SQL SELECT * FROM containers
1630        WHERE lower(name) = lower(:containername);     
1631      if (sqlca.sqlerrd[2] != 1)
1632        return MR_CONTAINER_NO_PARENT;
1633    }
1634 
1635  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1636    return mr_errcode;
1637 
1638  return MR_SUCCESS;
1639}
1640
1641int check_mailman_listname(char *name, const char *suffix)
1642{
1643  char *p;
1644  EXEC SQL BEGIN DECLARE SECTION;
1645  int i, cnt;
1646  EXEC SQL END DECLARE SECTION;
1647
1648  p = strstr(name, suffix);
1649  if (p)
1650    {
1651      if (strlen(name) == (p - name + strlen(suffix)))
1652        {
1653          /* list is of the form "name-suffix" */
1654          i = (p - name);
1655          EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
1656            WHERE name = SUBSTR(:name, 1, :i) AND mailman = 1;
1657          if (cnt > 0)
1658            return MR_EXISTS;
1659        }
1660    }
1661
1662  return MR_SUCCESS;
1663}
Note: See TracBrowser for help on using the repository browser.