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