]> andersk Git - moira.git/blob - server/qsetup.pc
afd73bbb783ae0c7fe8dc41258d6a2568495ed13
[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 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(mach_id) INTO :cnt FROM serverhosts
225     WHERE mach_id = :id;
226   if (cnt > 0)
227     return MR_IN_USE;
228   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
229     WHERE mach_id = :id;
230   if (cnt > 0)
231     return MR_IN_USE;
232   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
233     WHERE mach_id = :id;
234   if (cnt > 0)
235     return MR_IN_USE;
236   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
237     WHERE mach_id = :id;
238   if (cnt > 0)
239     return MR_IN_USE;
240   EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
241     WHERE rm = :id;
242   if (cnt > 0)
243     return MR_IN_USE;
244   EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
245     WHERE rq = :id;
246   if (cnt > 0)
247     return MR_IN_USE;
248   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
249     WHERE mach_id = :id;
250   if (cnt > 0)
251     return MR_IN_USE;
252   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
253     WHERE mach_id = :id;
254   if (cnt > 0)
255     return MR_IN_USE;
256   EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
257     WHERE member_type = 'MACHINE' and member_id = :id;
258   if (cnt > 0)
259     return MR_IN_USE;
260
261   EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
262   if (dbms_errno)
263     return mr_errcode;
264
265   EXEC SQL DELETE FROM mcntmap WHERE mach_id = :id;
266   if (dbms_errno)
267     return mr_errcode;
268   return MR_SUCCESS;
269 }
270
271 /* setup_asnt - verify that the data entered for the subnet is sane.
272  * In particular, make sure that the "low" and "high" addresses are
273  * correctly ordered, i.e., high > low.
274  */
275
276 int setup_asnt(struct query *q, char *argv[], client *cl)
277 {
278   int high, low, row, status;
279   char *account_number;
280
281   /* Check for asnt or usnt. */
282   if (q->type == APPEND)
283     row = 0;
284   else
285     row = 1;
286
287   low = atoi(argv[row + 7]);
288   high = atoi(argv[row + 8]);
289   status = atoi(argv[row + 2]);
290   account_number = argv[row + 4];
291   
292   /* Don't allow Private subnets to be created without a valid billing
293    * number.
294    */
295   if (status == SNET_STATUS_PRIVATE_10MBPS || 
296       status == SNET_STATUS_PRIVATE_100MBPS ||
297       status == SNET_STATUS_PRIVATE_1000MBPS)
298     {
299       EXEC SQL SELECT account_number FROM accountnumbers
300         WHERE account_number = :account_number;
301       if (sqlca.sqlcode == SQL_NO_MATCH)
302         return MR_ACCOUNT_NUMBER;
303     }
304       
305   /* Special case 0.0.0.0 and 255.255.255.255 */
306   if (!(low == 0 || low == -1 || high == 0 || high == -1))
307     if (low > high)
308       return MR_ADDRESS;
309
310   /* If this is update_subnet, we're done. */
311   if (row == 1)
312     return MR_SUCCESS;
313
314   /* For an add_subnet query, allocate and fill in a new snet_id */
315   if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
316     return mr_errcode;
317
318   return MR_SUCCESS;
319 }
320
321 /* setup_dsnt - verify that the subnet is no longer being referenced
322  * and may safely be deleted.
323  */
324
325 int setup_dsnt(struct query *q, char *argv[], client *cl)
326 {
327   EXEC SQL BEGIN DECLARE SECTION;
328   int id, cnt = 0;
329   EXEC SQL END DECLARE SECTION;
330
331   id = *(int *)argv[0];
332   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
333     WHERE snet_id = :id;
334   if (cnt > 0)
335     return MR_IN_USE;
336   return MR_SUCCESS;
337 }
338
339
340 /* setup_dclu - verify that the cluster is no longer being referenced
341  * and may safely be deleted.
342  */
343
344 int setup_dclu(struct query *q, char *argv[], client *cl)
345 {
346   EXEC SQL BEGIN DECLARE SECTION;
347   int id, cnt;
348   EXEC SQL END DECLARE SECTION;
349
350   id = *(int *)argv[0];
351   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
352     WHERE clu_id = :id;
353   if (cnt > 0)
354     return MR_IN_USE;
355   EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
356     WHERE clu_id = :id;
357   if (cnt > 0)
358     return MR_IN_USE;
359   if (dbms_errno)
360     return mr_errcode;
361   return MR_SUCCESS;
362 }
363
364
365 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
366  * a new gid and put it in argv[6].  Otherwise if argv[6] is UNIQUE_ID but
367  * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
368  * a -1 there.  Remember that this is also used for ulis, with the indexes
369  * at 6 & 7.  Also check that the list name does not contain uppercase
370  * characters, control characters, @, or :.
371  *
372  *  Newlines in list descriptions do bad things to the aliases file
373  *  moira generates, so make sure the description doesn't contain any, too.
374  */
375
376 static int badlistchars[] = {
377   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
378   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
379   1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
380   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
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, 0, /* P - _ */
383   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
384   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
385   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
386   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
387   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
388   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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 };
394
395 static const char *mailman_suffixes[] = { "-admin", "-owner", "-request",
396                                           "-bounces", "-confirm", "-join",
397                                           "-leave", "-subscribe",
398                                           "-unsubscribe", NULL };
399
400 int setup_alis(struct query *q, char *argv[], client *cl)
401 {
402   EXEC SQL BEGIN DECLARE SECTION;
403   int ngid, cnt, mailman, mailman_id, lid;
404   char *name, *desc;
405   EXEC SQL END DECLARE SECTION;
406   unsigned char *p;
407   int idx, err, best = -1, usage, i;
408
409   if (!strcmp(q->shortname, "alis"))
410     idx = 0;
411   else if (!strcmp(q->shortname, "ulis"))
412     idx = 1;
413   name = argv[idx];
414
415   if (q->version == 2)
416     desc = argv[9 + idx];
417   else if (q->version == 3)
418     desc = argv[10 + idx];
419   else if (q->version == 4)
420     desc = argv[12 + idx];
421   else if (q->version >= 10)
422     desc = argv[14 + idx];
423
424   if (idx == 1)
425     {
426       lid = *(int *)argv[0];
427
428       if (acl_access_check(lid, cl))
429         return MR_PERM;
430     }
431
432   for (p = (unsigned char *) name; *p; p++)
433     {
434       if (badlistchars[*p])
435         return MR_BAD_CHAR;
436     }
437
438   for (p = (unsigned char *) desc; *p; p++)
439     {
440       if (*p == '\n')
441         return MR_BAD_CHAR;
442     }
443
444   /* Check that it doesn't conflict with a pre-existing weirdly-cased
445    * name. */
446   EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
447     WHERE LOWER(name) = :name AND name != :name;
448   if (cnt)
449     return MR_EXISTS;
450
451   if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
452     {
453       if (atoi(argv[5 + idx]))
454         {
455           if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
456             return err;
457           EXEC SQL SELECT value INTO :ngid FROM numvalues
458             WHERE name = 'gid';
459           if (dbms_errno)
460             return mr_errcode;
461           sprintf(argv[6 + idx], "%d", ngid);
462         }
463       else
464         strcpy(argv[6 + idx], "-1");
465     }
466
467   /* Don't let someone rename a list to one of the magic mailman names
468    * (foo-admin, etc) if foo already exists as a mailman list.
469    */
470   for (i = 0; mailman_suffixes[i]; i++)
471     {
472       if ((err = check_mailman_listname(name, mailman_suffixes[i])) 
473           != MR_SUCCESS)
474         return err;
475     }
476
477   if (q->version >= 10)
478     {
479       /* Don't let them take this name for a mailman list if we can't
480        * reserve the -admin, -owner, and -request names.
481        */
482       if (atoi(argv[8 + idx]))
483         {
484           EXEC SQL SELECT  COUNT(name) INTO :cnt FROM list
485             WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
486                    name = :name || '-request');
487           if (cnt)
488             return MR_EXISTS;
489         }
490
491       /* Handle the [ANY] case for mailman server. */
492       mailman_id = *(int *)argv[9 + idx];
493       if (mailman_id == -1)
494         {
495           EXEC SQL DECLARE csr_mailman CURSOR FOR
496             SELECT mach_id FROM serverhosts WHERE service = 'MAILMAN'
497             AND enable = 1;
498           if (dbms_errno)
499             return mr_errcode;
500           EXEC SQL OPEN csr_mailman;
501           if (dbms_errno)
502             return mr_errcode;
503
504           while (1)
505             {
506               EXEC SQL FETCH csr_mailman INTO :mailman_id;
507               if (sqlca.sqlcode)
508                 break;
509               
510               EXEC SQL SELECT COUNT(name) INTO :usage FROM list
511                 WHERE mailman_id = :mailman_id;
512
513               if (best < 0 || usage < best)
514                 {
515                   best = usage;
516                   *(int *)argv[9 + idx] = mailman_id;
517                   break;
518                 }
519             }
520           EXEC SQL CLOSE csr_mailman;
521           if (dbms_errno)
522             return mr_errcode;
523
524           if (best == -1)
525             return MR_SERVICE;
526         }
527     }
528   else
529     {
530       /* Client too old to know about the mailman code.
531        * Use existing value of mailman boolean in the table.
532        * Don't do this for add_list from an old client, since the row
533        * they're creating won't exist yet, and there's no way for them to
534        * create a list with the mailman bit set, anyway.
535        */
536       if (idx == 1)
537         {
538           EXEC SQL SELECT mailman INTO :mailman FROM list WHERE list_id = :lid;
539           if (mailman)
540             {
541               EXEC SQL SELECT  COUNT(name) INTO :cnt FROM list
542                 WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
543                        name = :name || '-request');
544               if (cnt)
545                 return MR_EXISTS;
546             }
547         }
548     }
549
550   if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
551     return mr_errcode;
552
553   return MR_SUCCESS;
554 }
555
556
557 /* setup_dlis - verify that the list is no longer being referenced
558  * and may safely be deleted.
559  */
560
561 int setup_dlis(struct query *q, char *argv[], client *cl)
562 {
563   int id;
564   EXEC SQL BEGIN DECLARE SECTION;
565   int cnt;
566   EXEC SQL END DECLARE SECTION;
567
568   id = *(int *)argv[0];
569
570   EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
571     WHERE member_id = :id AND member_type = 'LIST';
572   if (cnt > 0)
573     return MR_IN_USE;
574
575   EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
576     WHERE member_id = :id AND member_type = 'LIST';
577   if (cnt > 0)
578     return MR_IN_USE;
579
580   EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
581     WHERE list_id = :id;
582   if (cnt > 0)
583     return MR_IN_USE;
584
585   EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
586   if (cnt > 0)
587     return MR_IN_USE;
588
589   EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
590   if (cnt > 0)
591     return MR_IN_USE;
592
593   EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
594     WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
595   if (cnt > 0)
596     return MR_IN_USE;
597
598   EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
599     WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
600   if (cnt > 0)
601     return MR_IN_USE;
602
603   EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
604     WHERE acl_id = :id AND acl_type = 'LIST';
605   if (cnt > 0)
606     return MR_IN_USE;
607
608   EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
609     WHERE entity_id = :id AND type = 'GROUP';
610   if (cnt > 0)
611     return MR_IN_USE;
612
613   EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
614     WHERE acl_id = :id AND acl_type = 'LIST';
615   if (cnt > 0)
616     return MR_IN_USE;
617
618   EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
619     WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
620     OR z.sub_type = 'LIST' AND z.sub_id = :id
621     OR z.iws_type = 'LIST' AND z.iws_id = :id
622     OR z.iui_type = 'LIST' AND z.iui_id = :id
623     OR z.owner_type = 'LIST' and z.owner_id = :id;
624   if (cnt > 0)
625     return MR_IN_USE;
626
627   EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
628     WHERE lpc_acl = :id OR ac = :id;
629   if (cnt > 0)
630     return MR_IN_USE;
631
632   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
633     WHERE owner_type = 'LIST' AND owner_id = :id
634     OR lpc_acl = :id;
635   if (cnt > 0)
636     return MR_IN_USE;
637
638   EXEC SQL SELECT count(name) INTO :cnt FROM containers
639     WHERE acl_id = :id AND acl_type = 'LIST';
640   if (cnt > 0)
641     return MR_IN_USE;
642
643   EXEC SQL SELECT count(name) INTO :cnt FROM containers
644     WHERE memacl_id = :id AND memacl_type = 'LIST';
645   if (cnt > 0)
646     return MR_IN_USE;
647
648   return MR_SUCCESS;
649 }
650
651
652 /* setup_dsin - verify that the service is no longer being referenced
653  * and may safely be deleted.
654  */
655
656 int setup_dsin(struct query *q, char *argv[], client *cl)
657 {
658   EXEC SQL BEGIN DECLARE SECTION;
659   int ec, cnt;
660   char *svrname;
661   EXEC SQL END DECLARE SECTION;
662
663   svrname = argv[0];
664   EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
665     WHERE service = UPPER(:svrname);
666   if (cnt > 0)
667     return MR_IN_USE;
668
669   EXEC SQL SELECT inprogress INTO :ec FROM servers
670     WHERE name = UPPER(:svrname);
671   if (dbms_errno)
672     return mr_errcode;
673   if (ec)
674     return MR_IN_USE;
675
676   return MR_SUCCESS;
677 }
678
679
680 /* setup_dshi - verify that the service-host is no longer being referenced
681  * and may safely be deleted.
682  */
683
684 int setup_dshi(struct query *q, char *argv[], client *cl)
685 {
686   EXEC SQL BEGIN DECLARE SECTION;
687   int id, ec;
688   char *svrname;
689   EXEC SQL END DECLARE SECTION;
690
691   svrname = argv[0];
692   id = *(int *)argv[1];
693
694   EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
695     WHERE service = UPPER(:svrname) AND mach_id = :id;
696   if (dbms_errno)
697     return mr_errcode;
698   if (ec)
699     return MR_IN_USE;
700
701   return MR_SUCCESS;
702 }
703
704
705 /**
706  ** setup_add_filesys - verify existance of referenced file systems
707  **
708  ** Inputs:     Add
709  **   argv[1] - type
710  **   argv[2] - mach_id
711  **   argv[3] - name
712  **   argv[5] - rwaccess
713  **
714  ** Description:
715  **   - for type = RVD:
716  **        * allow anything
717  **   - for type = NFS/IMAP:
718  **        * extract directory prefix from name
719  **        * verify mach_id/dir in nfsphys
720  **        * verify rwaccess in {r, w, R, W}
721  **
722  **  Side effect: sets variable _var_phys_id to the ID of the physical
723  **     filesystem (nfsphys_id for NFS, 0 for RVD)
724  **
725  ** Errors:
726  **   MR_NFS - specified directory not exported
727  **   MR_FILESYS_ACCESS - invalid filesys access
728  **
729  **/
730
731 EXEC SQL BEGIN DECLARE SECTION;
732 int _var_phys_id;
733 EXEC SQL END DECLARE SECTION;
734
735 int setup_afil(struct query *q, char *argv[], client *cl)
736 {
737   char *type, *name;
738   int mach_id;
739   EXEC SQL BEGIN DECLARE SECTION;
740   int ok;
741   char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
742   EXEC SQL END DECLARE SECTION;
743
744   type = argv[1];
745   mach_id = *(int *)argv[2];
746   name = argv[3];
747   rwaccess = argv[5];
748   _var_phys_id = 0;
749
750   sprintf(ftype, "fs_access_%s", type);
751   EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
752     WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
753   if (dbms_errno)
754     return mr_errcode;
755   if (ok == 0)
756     return MR_FILESYS_ACCESS;
757
758   if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
759     return mr_errcode;
760
761   if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
762     return check_nfs(mach_id, name, rwaccess);
763
764   return MR_SUCCESS;
765 }
766
767
768 /* Verify the arguments, depending on the FStype.  Also, if this is an
769  * NFS filesystem, then update any quotas for that filesystem to reflect
770  * the new phys_id.
771  */
772
773 int setup_ufil(struct query *q, char *argv[], client *cl)
774 {
775   int mach_id, status;
776   char *type, *name;
777   EXEC SQL BEGIN DECLARE SECTION;
778   int fid, total, who, ok;
779   char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
780   short int total_null;
781   EXEC SQL END DECLARE SECTION;
782
783   _var_phys_id = 0;
784   type = argv[2];
785   mach_id = *(int *)argv[3];
786   name = argv[4];
787   access = argv[6];
788   fid = *(int *)argv[0];
789   who = cl->client_id;
790   entity = cl->entity;
791
792   sprintf(ftype, "fs_access_%s", type);
793   EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
794     WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
795   if (dbms_errno)
796     return mr_errcode;
797   if (ok == 0)
798     return MR_FILESYS_ACCESS;
799
800   EXEC SQL SELECT type INTO :ftype FROM filesys
801     WHERE filsys_id = :fid;
802   if (dbms_errno)
803     return mr_errcode;
804
805   if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
806     {
807       status = check_nfs(mach_id, name, access);
808       EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
809         WHERE filsys_id = :fid;
810       if (dbms_errno)
811         return mr_errcode;
812       return status;
813     }
814   else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
815            && strcmp(strtrim(ftype), "ERR"))
816     {
817       total = 0;
818       EXEC SQL DELETE FROM quota
819         WHERE type = 'ANY' AND filsys_id = :fid;
820       EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
821         WHERE filsys_id = :fid AND phys_id != 0;
822       if (dbms_errno)
823         return mr_errcode;
824       if (!total_null && (total != 0))
825         {
826           EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
827                                       type, modtime, modby, modwith)
828             VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
829           if (dbms_errno)
830             return mr_errcode;
831         }
832     }
833   else
834     {
835       EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
836       if (dbms_errno)
837         return mr_errcode;
838     }
839   return MR_SUCCESS;
840 }
841
842
843 /* Find the NFS physical partition that the named directory is on.
844  * This is done by comparing the dir against the mount point of the
845  * partition.  To make sure we get the correct match when there is
846  * more than one, we sort the query in reverse order by dir name.
847  */
848
849 int check_nfs(int mach_id, char *name, char *access)
850 {
851   EXEC SQL BEGIN DECLARE SECTION;
852   char dir[NFSPHYS_DIR_SIZE];
853   int mid = mach_id;
854   EXEC SQL END DECLARE SECTION;
855   int status;
856   char *cp1;
857   char *cp2;
858
859   status = MR_NFS;
860   EXEC SQL DECLARE csr101 CURSOR FOR
861     SELECT nfsphys_id, dir FROM nfsphys
862     WHERE mach_id = :mid
863     ORDER BY 2 DESC;
864   if (dbms_errno)
865     return mr_errcode;
866   EXEC SQL OPEN csr101;
867   if (dbms_errno)
868     return mr_errcode;
869   while (1)
870     {
871       EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
872       if (sqlca.sqlcode)
873         break;
874       cp1 = name;
875       cp2 = strtrim(dir);
876       while (*cp2)
877         {
878           if (*cp1++ != *cp2)
879             break;
880           cp2++;
881         }
882       if (!*cp2)
883         {
884           status = MR_SUCCESS;
885           break;
886         }
887     }
888   EXEC SQL CLOSE csr101;
889   if (dbms_errno)
890     return mr_errcode;
891   return status;
892 }
893
894
895 /* setup_dfil: free any quota records and fsgroup info associated with
896  * a filesystem when it is deleted.  Also adjust the allocation numbers.
897  */
898
899 int setup_dfil(struct query *q, char **argv, client *cl)
900 {
901   EXEC SQL BEGIN DECLARE SECTION;
902   int id, total, phys_id;
903   short int none;
904   EXEC SQL END DECLARE SECTION;
905
906   id = *(int *)argv[0];
907   EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
908     WHERE filsys_id = :id;
909
910   if (none)
911     total = 0;
912
913   /** What if there are multiple phys_id's per f/s? (bad data) **/
914   EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
915     WHERE filsys_id = :id;
916   EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
917     WHERE nfsphys_id = :phys_id;
918
919   if (!none)
920     EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
921   EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
922   EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
923   if (dbms_errno)
924     return mr_errcode;
925   return MR_SUCCESS;
926 }
927
928
929 /* setup_dnfp: check to see that the nfs physical partition does not have
930  * any filesystems assigned to it before allowing it to be deleted.
931  */
932
933 int setup_dnfp(struct query *q, char **argv, client *cl)
934 {
935   EXEC SQL BEGIN DECLARE SECTION;
936   int id, cnt;
937   char *dir;
938   EXEC SQL END DECLARE SECTION;
939
940   id = *(int *)argv[0];
941   dir = argv[1];
942   EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
943     WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
944     AND np.mach_id = :id AND np.dir = :dir;
945   if (cnt > 0)
946     return MR_IN_USE;
947   if (dbms_errno)
948     return mr_errcode;
949   return MR_SUCCESS;
950 }
951
952
953 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
954  *   argv[0] = filsys_id
955  *   argv[1] = type if "update_quota" or "delete_quota"
956  *   argv[2 or 1] = users_id or list_id
957  */
958
959 int setup_dqot(struct query *q, char **argv, client *cl)
960 {
961   EXEC SQL BEGIN DECLARE SECTION;
962   int quota, fs, id, physid;
963   char *qtype;
964   EXEC SQL END DECLARE SECTION;
965
966   fs = *(int *)argv[0];
967   if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
968     {
969       qtype = argv[1];
970       id = *(int *)argv[2];
971     }
972   else
973     {
974       qtype = "USER";
975       id = *(int *)argv[1];
976     }
977
978   EXEC SQL SELECT quota INTO :quota FROM quota
979     WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
980   EXEC SQL SELECT phys_id INTO :physid FROM filesys
981     WHERE filsys_id = :fs;
982   EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
983     WHERE nfsphys_id = :physid;
984
985   if (dbms_errno)
986     return mr_errcode;
987   return MR_SUCCESS;
988 }
989
990
991 /* prefetch_value():
992  * This routine fetches an appropriate value from the numvalues table.
993  * It is a little hack to get around the fact that SQL doesn't let you
994  * do something like INSERT INTO table (foo) VALUES (other_table.bar).
995  *
996  * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
997  * from within a setup_...() routine with the appropriate arguments.
998  *
999  * Correct functioning of this routine may depend on the assumption
1000  * that this query is an APPEND.
1001  */
1002
1003 int prefetch_value(struct query *q, char **argv, client *cl)
1004 {
1005   EXEC SQL BEGIN DECLARE SECTION;
1006   char *name = q->validate->object_id;
1007   int value;
1008   EXEC SQL END DECLARE SECTION;
1009   int status, limit, argc;
1010
1011   /* set next object id, limiting it if necessary */
1012   if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
1013     limit = 1; /* So far as I know, this isn't needed.  Just CMA. */
1014   else
1015     limit = 0;
1016   if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
1017     return status;
1018
1019   /* fetch object id */
1020   EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
1021   if (dbms_errno)
1022     return mr_errcode;
1023   if (sqlca.sqlerrd[2] != 1)
1024     return MR_INTERNAL;
1025
1026   argc = q->argc + q->vcnt;   /* end of Argv for APPENDs */
1027   sprintf(argv[argc], "%d", value);
1028
1029   return MR_SUCCESS;
1030 }
1031
1032 /* prefetch_filesys():
1033  * Fetches the phys_id from filesys based on the filsys_id in argv[0].
1034  * Appends the filsys_id and the phys_id to the argv so they can be
1035  * referenced in an INSERT into a table other than filesys.  Also
1036  * see comments at prefetch_value().
1037  *
1038  * Assumes the existence of a row where filsys_id = argv[0], since a
1039  * filesys label has already been resolved to a filsys_id.
1040  */
1041 int prefetch_filesys(struct query *q, char **argv, client *cl)
1042 {
1043   EXEC SQL BEGIN DECLARE SECTION;
1044   int fid, phid;
1045   EXEC SQL END DECLARE SECTION;
1046   int argc;
1047
1048   fid = *(int *)argv[0];
1049   EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
1050   if (dbms_errno)
1051     return mr_errcode;
1052
1053   argc = q->argc + q->vcnt;
1054   sprintf(argv[argc++], "%d", phid);
1055   sprintf(argv[argc], "%d", fid);
1056
1057   return MR_SUCCESS;
1058 }
1059
1060
1061 /* setup_ghst():
1062  */
1063
1064 int setup_ghst(struct query *q, char **argv, client *cl)
1065 {
1066   if (strcmp(argv[0], "*") || strcmp(argv[1], "*") ||
1067       strcmp(argv[2], "*") || strcmp(argv[3], "*"))
1068     return MR_SUCCESS;
1069   else
1070     return MR_PERM;
1071 }
1072
1073 /* setup_ahst():
1074  */
1075
1076 int setup_ahst(struct query *q, char **argv, client *cl)
1077 {
1078   EXEC SQL BEGIN DECLARE SECTION;
1079   char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
1080   char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
1081   int value, id, ssaddr, smask, shigh, slow, cnt;
1082   unsigned int saddr, mask, high, low;
1083   EXEC SQL END DECLARE SECTION;
1084   int row, idx;
1085   struct in_addr addr;
1086
1087   id = *(int *)argv[0];
1088
1089   if (!strcmp(q->shortname, "uhst"))
1090     {
1091       row = 1;
1092       EXEC SQL SELECT name, vendor, model, os
1093         INTO :oldname, :vendor, :model, :os
1094         FROM machine WHERE mach_id = :id;
1095     }
1096   else
1097     row = 0;
1098
1099   if (q->version < 6)
1100     idx = 0;
1101   else if (q->version >= 6 && q->version < 8)
1102     idx = 1;
1103   else
1104     idx = 2;
1105
1106   /* Sanity check name, vendor, model, and os. */
1107   if ((row == 0 || strcasecmp(argv[1], oldname)) &&
1108       !hostname_check(argv[row]))
1109     return MR_BAD_CHAR;
1110   if ((row == 0 || strcasecmp(argv[2], vendor)) &&
1111       !hostinfo_check(argv[row + 1], 0))
1112     return MR_BAD_CHAR;
1113   if ((row == 0 || strcasecmp(argv[3], model)) &&
1114       !hostinfo_check(argv[row + 2], 1))
1115     return MR_BAD_CHAR;
1116   if ((row == 0 || strcasecmp(argv[4], os)) &&
1117       !hostinfo_check(argv[row + 3], 0))
1118     return MR_BAD_CHAR;
1119
1120   /* check for duplicate name */
1121   name = argv[row];
1122   EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
1123     WHERE name = UPPER(:name);
1124   if (dbms_errno)
1125     return mr_errcode;
1126   if (cnt != 0)
1127     return MR_EXISTS;
1128
1129   /* check address */
1130   if (!strcmp(argv[9 + row + idx], "unassigned"))
1131     value = -1;
1132   else if (!strcmp(argv[9 + row + idx], "unique"))
1133     {
1134       if (*(int *)argv[8 + row + idx] == 0)
1135         value = -1;
1136       else
1137         value = -2;
1138     }
1139   else
1140     {
1141       value = ntohl(inet_addr(argv[9 + row + idx]));
1142       if (value == -1)
1143         return MR_ADDRESS;
1144     }
1145   if (value == 0)
1146     return MR_ADDRESS;
1147   if (value != -1)
1148     {
1149       /*
1150        * an address or unique was specified.
1151        */
1152       id = *(int *)argv[8 + row + idx];
1153       EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
1154         :shigh, :slow FROM subnet WHERE snet_id = :id;
1155       if (dbms_errno)
1156         return mr_errcode;
1157       saddr = (unsigned) ssaddr;
1158       mask = (unsigned) smask;
1159       high = (unsigned) shigh;
1160       low = (unsigned) slow;
1161       if (value != -2)
1162         {
1163           /*
1164            * someone specified an IP address for the host record
1165            */
1166           if ((value & mask) != saddr || value < low || value > high)
1167             return MR_ADDRESS;
1168           /*
1169            * run the address argument through inet_addr(). This
1170            * has the effect that any out of bounds host addrs will
1171            * be converted to a valid host addr. We do this now
1172            * so that the uniqueness check works. We should also
1173            * link in an inet_addr() that returns an error for
1174            * this case.
1175            */
1176           addr.s_addr = inet_addr(argv[9 + row + idx]);
1177           name = inet_ntoa(addr);
1178           EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1179             WHERE address = :name;
1180           if (dbms_errno)
1181             return mr_errcode;
1182           if (cnt > 0)
1183             {
1184               /*
1185                * make IP address is unique. If this a modify request
1186                * (row == 1), then we expect one record to exist.
1187                */
1188               if (row == 0 || (row == 1 && cnt > 1))
1189                 return MR_ADDRESS;
1190               if (row == 1 && cnt == 1)
1191                 {
1192                   EXEC SQL SELECT mach_id INTO :id FROM machine
1193                     WHERE address = :name;
1194                   if (id != *(int *)argv[0])
1195                     return MR_ADDRESS;
1196                 }
1197             }
1198         }
1199       else
1200         {
1201           /*
1202            * a "unique" address was specified. Walk through the
1203            * range specified in the network record, return
1204            * error if no room left.
1205            */
1206           for (id = low; id <= high; id++)
1207             {
1208               if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1209                 continue;
1210               addr.s_addr = htonl(id);
1211               name = inet_ntoa(addr);
1212               EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1213                 WHERE address = :name;
1214               if (dbms_errno)
1215                 return mr_errcode;
1216               if (cnt == 0)
1217                 break;
1218             }
1219           if (cnt != 0)
1220             return MR_NO_ID;
1221           else
1222             value = htonl(id);
1223         }
1224       /*
1225        * we have an address in value. Convert it to a string and store it.
1226        */
1227       addr.s_addr = htonl(value);
1228       strcpy(argv[9 + row + idx], inet_ntoa(addr));
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
1271 int 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  */
1296 int 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  */
1329 int setup_aprn(struct query *q, char **argv, client *cl)
1330 {
1331   int best = -1, row;
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   EXEC SQL END DECLARE SECTION;
1337
1338   /* Check for aprn or uprn. */
1339   if (q->type == APPEND)
1340     row = 0;
1341   else
1342     row = 1;
1343
1344   name = argv[PRN_NAME + row];
1345   duplexname = argv[PRN_DUPLEXNAME + row];
1346   oldname = argv[0];
1347
1348   if (!*name)
1349     return MR_BAD_CHAR;
1350   else
1351     {
1352       if (q->type == APPEND)
1353         {
1354           EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1355             WHERE name = :name OR duplexname = :name;
1356         }
1357       else
1358         {
1359           EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1360             WHERE ( name = :name OR duplexname = :name )
1361             AND name != :oldname;
1362         }
1363       if (dbms_errno)
1364         return mr_errcode;
1365       if (count)
1366         return MR_NOT_UNIQUE;
1367     }
1368
1369   if (*duplexname)
1370     {
1371       if (q->type == APPEND)
1372         {
1373           EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1374             WHERE name = :duplexname OR duplexname = :duplexname;
1375         }
1376       else
1377         {
1378           EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1379             WHERE ( name = :duplexname OR duplexname = :duplexname )
1380             AND name != :oldname;
1381         }
1382
1383       if (dbms_errno)
1384         return mr_errcode;
1385       if (count)
1386         return MR_NOT_UNIQUE;
1387     }
1388
1389   if (!strcmp(name, duplexname))
1390     return MR_NOT_UNIQUE;
1391
1392   mid = *(int *)argv[PRN_RM + row];
1393   if (mid == -1)
1394     {
1395       EXEC SQL DECLARE csr_rm CURSOR FOR
1396         SELECT ps.mach_id, s.string FROM printservers ps, strings s
1397         WHERE ps.mach_id IN
1398         ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1399           AND enable = 1 )
1400         AND ps.printer_types = s.string_id;
1401       if (dbms_errno)
1402         return mr_errcode;
1403       EXEC SQL OPEN csr_rm;
1404       if (dbms_errno)
1405         return mr_errcode;
1406
1407       while (1)
1408         {
1409           EXEC SQL FETCH csr_rm INTO :mid, :types;
1410           if (sqlca.sqlcode)
1411             break;
1412
1413           for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1414             {
1415               if (!strcasecmp(argv[PRN_TYPE + row], p))
1416                 {
1417                   EXEC SQL SELECT COUNT(name) INTO :usage
1418                     FROM printers WHERE rm = :mid;
1419
1420                   if (best < 0 || usage < best)
1421                     {
1422                       best = usage;
1423                       *(int *)argv[PRN_RM + row] = mid;
1424                       break;
1425                     }
1426                 }
1427             }
1428         }
1429       EXEC SQL CLOSE csr_rm;
1430       if (dbms_errno)
1431         return mr_errcode;
1432
1433       if (best == -1)
1434         return MR_SERVICE;
1435     }
1436   else
1437     {
1438       EXEC SQL SELECT mach_id INTO :mid FROM printservers
1439         WHERE mach_id = :mid;
1440       if (sqlca.sqlcode)
1441         return MR_SERVICE;
1442     }
1443
1444   return MR_SUCCESS;
1445 }
1446
1447 int setup_dpsv(struct query *q, char **argv, client *cl)
1448 {
1449   int id;
1450   EXEC SQL BEGIN DECLARE SECTION;
1451   int cnt;
1452   EXEC SQL END DECLARE SECTION;
1453
1454   id = *(int *)argv[0];
1455
1456   EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1457     WHERE rm = :id;
1458   if (cnt > 0)
1459     return MR_IN_USE;
1460
1461   return MR_SUCCESS;
1462 }
1463
1464 int setup_dcon(struct query *q, char *argv[], client *cl)
1465 {
1466   EXEC SQL BEGIN DECLARE SECTION;
1467   int id, cnt;
1468   char containername[CONTAINERS_NAME_SIZE];
1469   EXEC SQL END DECLARE SECTION;
1470
1471   id = *(int *)argv[0];
1472   /* check to see if there are machines in this container */
1473   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1474     WHERE cnt_id = :id;
1475   if (cnt > 0)
1476     return MR_IN_USE;
1477
1478   /* check to see if there are subcontainers in this container */
1479
1480   /* get the container name */
1481   
1482   EXEC SQL SELECT name INTO :containername
1483     FROM containers
1484     WHERE cnt_id = :id; 
1485
1486   /* trim off the trailing spaces */
1487    strcpy(containername, strtrim(containername));
1488
1489   EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1490     WHERE LOWER(name) LIKE LOWER(:containername || '/' || '%');
1491
1492   if (cnt > 0)
1493     return MR_IN_USE;
1494
1495   if (dbms_errno)
1496     return mr_errcode;
1497   return MR_SUCCESS;
1498 }
1499
1500 int setup_scli(struct query *q, char *argv[], client *cl)
1501 {
1502   EXEC SQL BEGIN DECLARE SECTION;
1503   int cnt_id, list_id;
1504   EXEC SQL END DECLARE SECTION;
1505
1506   cnt_id = *(int *)argv[0];
1507   /* Check if someone has already set the list for this container */
1508   EXEC SQL SELECT list_id INTO :list_id FROM containers
1509     WHERE cnt_id = :cnt_id;
1510   if (list_id != 0)
1511     return MR_EXISTS;
1512
1513   if (dbms_errno)
1514     return mr_errcode;
1515
1516   return MR_SUCCESS;
1517 }
1518
1519 /* hostname_check()
1520  * validate the rfc1035/rfc1123-ness of a hostname
1521  */
1522
1523 int hostname_check(char *name)
1524 {
1525   char *p;
1526   int count;
1527
1528   /* Sanity check name: must contain only letters, numerals, and
1529    * hyphen, and not start or end with a hyphen. Also make sure no
1530    * label (the thing the .s seperate) is longer than 63 characters,
1531    * or empty.
1532    */
1533
1534   for (p = name, count = 0; *p; p++)
1535     {
1536       count++;
1537       if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1538           (*p == '-' && p[1] == '.'))
1539         return 0;
1540       if (*p == '.')
1541         {
1542           if (count == 1)
1543             return 0;
1544           count = 0;
1545         }
1546       if (count == 64)
1547         return 0;
1548     }
1549   if (*(p - 1) == '-')
1550     return 0;
1551   return 1;
1552 }
1553
1554 int hostinfo_check(char *info, int num)
1555 {
1556   char *p;
1557
1558   if (!*info)
1559     return 1;
1560
1561   /* Sanity check host hostinfo: must start with a letter (or number
1562    * if num is true), contain only letters, numerals, and hyphen, and
1563    * not end with a hyphen.
1564    */
1565
1566   if (!isalpha(*info) && (!num || !isdigit(*info)))
1567     return 0;
1568   for (p = info; *p; p++)
1569     {
1570       if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1571           (*p == '-' && p[1] == '.'))
1572         return 0;
1573     }
1574   if (!isalnum(*(p - 1)))
1575     return 1;
1576 }
1577
1578 int setup_acon(struct query *q, char *argv[], client *cl)
1579 {
1580   EXEC SQL BEGIN DECLARE SECTION;
1581   char containername[CONTAINERS_NAME_SIZE];
1582   EXEC SQL END DECLARE SECTION;
1583   
1584   char* ptr;
1585   
1586   memset(containername, 0, sizeof(containername));
1587   strcpy(containername, argv[0]);
1588   ptr = strrchr(containername, '/');
1589   /* sub container, check for parents */
1590   if (ptr)
1591     {
1592       *ptr = '\0';
1593       EXEC SQL SELECT * FROM containers
1594         WHERE lower(name) = lower(:containername);      
1595       if (sqlca.sqlerrd[2] != 1)
1596         return MR_CONTAINER_NO_PARENT;
1597     }
1598   
1599   if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1600     return mr_errcode;
1601   
1602   return MR_SUCCESS;
1603 }
1604
1605 int check_mailman_listname(char *name, const char *suffix)
1606 {
1607   char *p;
1608   EXEC SQL BEGIN DECLARE SECTION;
1609   int i, cnt;
1610   EXEC SQL END DECLARE SECTION;
1611
1612   p = strstr(name, suffix);
1613   if (p)
1614     {
1615       if (strlen(name) == (p - name + strlen(suffix)))
1616         {
1617           /* list is of the form "name-suffix" */
1618           i = (p - name);
1619           EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
1620             WHERE name = SUBSTR(:name, 1, :i) AND mailman = 1;
1621           if (cnt > 0)
1622             return MR_EXISTS;
1623         }
1624     }
1625
1626   return MR_SUCCESS;
1627 }
This page took 0.338172 seconds and 3 git commands to generate.