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