]> andersk Git - moira.git/blob - server/qsetup.pc
oops, wrong argument.
[moira.git] / server / qsetup.pc
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
22 EXEC SQL INCLUDE sqlca;
23
24 RCSID("$Header$");
25
26 extern char *whoami;
27 extern int dbms_errno, mr_errcode;
28
29 EXEC SQL BEGIN DECLARE SECTION;
30 extern char stmt_buf[];
31 EXEC SQL END DECLARE SECTION;
32
33 EXEC SQL WHENEVER SQLERROR DO dbmserr();
34
35 int hostname_check(char *name);
36 int hostinfo_check(char *name, int num);
37 int prefetch_value(struct query *q, char **argv, client *cl);
38 int check_nfs(int mach_idx, char *name, char *access);
39 int 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
54 int 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
136 int 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  */
185 int 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
208 int 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
280 int 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
329 int 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
348 int 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
380 static 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
399 static const char *mailman_suffixes[] = { "-admin", "-owner", "-request",
400                                           "-bounces", "-confirm", "-join",
401                                           "-leave", "-subscribe",
402                                           "-unsubscribe", NULL };
403
404 int 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
565 int 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
660 int 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
688 int 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
735 EXEC SQL BEGIN DECLARE SECTION;
736 int _var_phys_id;
737 EXEC SQL END DECLARE SECTION;
738
739 int 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
777 int 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
853 int 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
903 int 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
937 int 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
963 int 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
1007 int 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  */
1045 int 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
1068 int 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
1080 int 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
1275 int 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  */
1300 int 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  */
1333 int 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
1451 int 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
1468 int 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
1504 int 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
1527 int 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
1558 int 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
1582 int setup_aali(struct query *q, char *argv[], client *cl)
1583 {
1584   EXEC SQL BEGIN DECLARE SECTION;
1585   int cnt;
1586   char *name, *type, *trans;
1587   EXEC SQL END DECLARE SECTION;
1588   name = argv[0];
1589   type = argv[1];
1590   trans = argv[2];
1591
1592   if (strcmp(strtrim(type), "FILESYS"))
1593     return MR_SUCCESS;
1594
1595   EXEC SQL SELECT count(label) INTO :cnt FROM filesys WHERE
1596     label = :name;
1597   if (cnt > 0)
1598     return MR_EXISTS;
1599
1600   return MR_SUCCESS;
1601 }
1602
1603 int setup_acon(struct query *q, char *argv[], client *cl)
1604 {
1605   EXEC SQL BEGIN DECLARE SECTION;
1606   char containername[CONTAINERS_NAME_SIZE];
1607   EXEC SQL END DECLARE SECTION;
1608   
1609   char* ptr;
1610   
1611   memset(containername, 0, sizeof(containername));
1612   strcpy(containername, argv[0]);
1613   ptr = strrchr(containername, '/');
1614   /* sub container, check for parents */
1615   if (ptr)
1616     {
1617       *ptr = '\0';
1618       EXEC SQL SELECT * FROM containers
1619         WHERE lower(name) = lower(:containername);      
1620       if (sqlca.sqlerrd[2] != 1)
1621         return MR_CONTAINER_NO_PARENT;
1622     }
1623   
1624   if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1625     return mr_errcode;
1626   
1627   return MR_SUCCESS;
1628 }
1629
1630 int check_mailman_listname(char *name, const char *suffix)
1631 {
1632   char *p;
1633   EXEC SQL BEGIN DECLARE SECTION;
1634   int i, cnt;
1635   EXEC SQL END DECLARE SECTION;
1636
1637   p = strstr(name, suffix);
1638   if (p)
1639     {
1640       if (strlen(name) == (p - name + strlen(suffix)))
1641         {
1642           /* list is of the form "name-suffix" */
1643           i = (p - name);
1644           EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
1645             WHERE name = SUBSTR(:name, 1, :i) AND mailman = 1;
1646           if (cnt > 0)
1647             return MR_EXISTS;
1648         }
1649     }
1650
1651   return MR_SUCCESS;
1652 }
This page took 0.190498 seconds and 5 git commands to generate.