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