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