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