]> andersk Git - moira.git/blob - server/qsetup.pc
First cut at support for winhomedir and winprofiledir support.
[moira.git] / server / qsetup.pc
1 /* $Id$
2  *
3  * Query setup routines
4  *
5  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  */
9
10 #include <mit-copyright.h>
11 #include "mr_server.h"
12 #include "query.h"
13 #include "qrtn.h"
14
15 #include <arpa/inet.h>
16 #include <netinet/in.h>
17
18 #include <ctype.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 EXEC SQL INCLUDE sqlca;
23
24 RCSID("$Header$");
25
26 extern char *whoami;
27 extern int dbms_errno, mr_errcode;
28
29 EXEC SQL BEGIN DECLARE SECTION;
30 extern char stmt_buf[];
31 EXEC SQL END DECLARE SECTION;
32
33 EXEC SQL WHENEVER SQLERROR DO dbmserr();
34
35 int hostname_check(char *name);
36 int hostinfo_check(char *name, int num);
37 int prefetch_value(struct query *q, char **argv, client *cl);
38 int check_nfs(int mach_idx, char *name, char *access);
39 int check_mailman_listname(char *name, const char *suffix);
40
41 /* Setup Routines */
42
43 /* Setup routine for add_user
44  *
45  * Inputs: argv[0] - login
46  *         argv[1] - uid
47  *
48  * Description:
49  *
50  * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
51  * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
52  */
53
54 int setup_ausr(struct query *q, char *argv[], client *cl)
55 {
56   int row, err;
57   EXEC SQL BEGIN DECLARE SECTION;
58   int nuid;
59   EXEC SQL END DECLARE SECTION;
60
61   if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
62     row = 2;
63   else
64     row = 1;
65
66   if (q->version > 2)
67     {
68       if (strlen(argv[row + 3]) + strlen(argv[row + 4]) +
69           strlen(argv[row + 5]) + 2 > USERS_FULLNAME_SIZE)
70         return MR_ARG_TOO_LONG;
71     }
72   else
73     {
74       if (strlen(argv[row + 2]) + strlen(argv[row + 3]) +
75           strlen(argv[row + 4]) + 2 > USERS_FULLNAME_SIZE)
76         return MR_ARG_TOO_LONG;
77     }
78
79   if (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_ahst():
1059  */
1060
1061 int setup_ahst(struct query *q, char **argv, client *cl)
1062 {
1063   EXEC SQL BEGIN DECLARE SECTION;
1064   char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
1065   char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
1066   int value, id, ssaddr, smask, shigh, slow, cnt;
1067   unsigned int saddr, mask, high, low;
1068   EXEC SQL END DECLARE SECTION;
1069   int row, idx;
1070   struct in_addr addr;
1071
1072   id = *(int *)argv[0];
1073
1074   if (!strcmp(q->shortname, "uhst"))
1075     {
1076       row = 1;
1077       EXEC SQL SELECT name, vendor, model, os
1078         INTO :oldname, :vendor, :model, :os
1079         FROM machine WHERE mach_id = :id;
1080     }
1081   else
1082     row = 0;
1083
1084   if (q->version < 6)
1085     idx = 0;
1086   else if (q->version >= 6 && q->version < 8)
1087     idx = 1;
1088   else
1089     idx = 2;
1090
1091   /* Sanity check name, vendor, model, and os. */
1092   if ((row == 0 || strcasecmp(argv[1], oldname)) &&
1093       !hostname_check(argv[row]))
1094     return MR_BAD_CHAR;
1095   if ((row == 0 || strcasecmp(argv[2], vendor)) &&
1096       !hostinfo_check(argv[row + 1], 0))
1097     return MR_BAD_CHAR;
1098   if ((row == 0 || strcasecmp(argv[3], model)) &&
1099       !hostinfo_check(argv[row + 2], 1))
1100     return MR_BAD_CHAR;
1101   if ((row == 0 || strcasecmp(argv[4], os)) &&
1102       !hostinfo_check(argv[row + 3], 0))
1103     return MR_BAD_CHAR;
1104
1105   /* check for duplicate name */
1106   name = argv[row];
1107   EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
1108     WHERE name = UPPER(:name);
1109   if (dbms_errno)
1110     return mr_errcode;
1111   if (cnt != 0)
1112     return MR_EXISTS;
1113
1114   /* check address */
1115   if (!strcmp(argv[9 + row + idx], "unassigned"))
1116     value = -1;
1117   else if (!strcmp(argv[9 + row + idx], "unique"))
1118     {
1119       if (*(int *)argv[8 + row + idx] == 0)
1120         value = -1;
1121       else
1122         value = -2;
1123     }
1124   else
1125     {
1126       value = ntohl(inet_addr(argv[9 + row + idx]));
1127       if (value == -1)
1128         return MR_ADDRESS;
1129     }
1130   if (value == 0)
1131     return MR_ADDRESS;
1132   if (value != -1)
1133     {
1134       /*
1135        * an address or unique was specified.
1136        */
1137       id = *(int *)argv[8 + row + idx];
1138       EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
1139         :shigh, :slow FROM subnet WHERE snet_id = :id;
1140       if (dbms_errno)
1141         return mr_errcode;
1142       saddr = (unsigned) ssaddr;
1143       mask = (unsigned) smask;
1144       high = (unsigned) shigh;
1145       low = (unsigned) slow;
1146       if (value != -2)
1147         {
1148           /*
1149            * someone specified an IP address for the host record
1150            */
1151           if ((value & mask) != saddr || value < low || value > high)
1152             return MR_ADDRESS;
1153           /*
1154            * run the address argument through inet_addr(). This
1155            * has the effect that any out of bounds host addrs will
1156            * be converted to a valid host addr. We do this now
1157            * so that the uniqueness check works. We should also
1158            * link in an inet_addr() that returns an error for
1159            * this case.
1160            */
1161           addr.s_addr = inet_addr(argv[9 + row + idx]);
1162           name = inet_ntoa(addr);
1163           EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1164             WHERE address = :name;
1165           if (dbms_errno)
1166             return mr_errcode;
1167           if (cnt > 0)
1168             {
1169               /*
1170                * make IP address is unique. If this a modify request
1171                * (row == 1), then we expect one record to exist.
1172                */
1173               if (row == 0 || (row == 1 && cnt > 1))
1174                 return MR_ADDRESS;
1175               if (row == 1 && cnt == 1)
1176                 {
1177                   EXEC SQL SELECT mach_id INTO :id FROM machine
1178                     WHERE address = :name;
1179                   if (id != *(int *)argv[0])
1180                     return MR_ADDRESS;
1181                 }
1182             }
1183         }
1184       else
1185         {
1186           /*
1187            * a "unique" address was specified. Walk through the
1188            * range specified in the network record, return
1189            * error if no room left.
1190            */
1191           for (id = low; id <= high; id++)
1192             {
1193               if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1194                 continue;
1195               addr.s_addr = htonl(id);
1196               name = inet_ntoa(addr);
1197               EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1198                 WHERE address = :name;
1199               if (dbms_errno)
1200                 return mr_errcode;
1201               if (cnt == 0)
1202                 break;
1203             }
1204           if (cnt != 0)
1205             return MR_NO_ID;
1206           else
1207             value = htonl(id);
1208         }
1209       /*
1210        * we have an address in value. Convert it to a string and store it.
1211        */
1212       addr.s_addr = htonl(value);
1213       strcpy(argv[9 + row + idx], inet_ntoa(addr));
1214     }
1215   else
1216     strcpy(argv[9 + row + idx], "unassigned");
1217
1218   /* status checking */
1219   value = atoi(argv[7 + row + idx]);
1220   if (row == 0 && !(value == 1 || value == 0))
1221     return MR_TYPE;
1222   if (row == 1)
1223     {
1224       id = *(int *)argv[0];
1225       EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1226       if (dbms_errno)
1227         return mr_errcode;
1228       if (value != cnt)
1229         {
1230           EXEC SQL UPDATE machine SET statuschange = SYSDATE
1231             WHERE mach_id = :id;
1232         }
1233     }
1234
1235   /*
1236    * If this is an update_host query, we're done.
1237    */
1238   if (row == 1)
1239     return MR_SUCCESS;
1240
1241   /*
1242    * For an add_host query, allocate and fill in a new machine id,
1243    * and then insert the creator id.
1244    */
1245   if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1246     return mr_errcode;
1247
1248   sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1249   return MR_SUCCESS;
1250 }
1251
1252
1253 /* setup_ahal():
1254  */
1255
1256 int setup_ahal(struct query *q, char **argv, client *cl)
1257 {
1258   EXEC SQL BEGIN DECLARE SECTION;
1259   char *name;
1260   int cnt;
1261   EXEC SQL END DECLARE SECTION;
1262   char *p;
1263
1264   name = argv[0];
1265   if (!hostname_check(argv[0]))
1266     return MR_BAD_CHAR;
1267
1268   EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1269     name = UPPER(:name);
1270   if (dbms_errno)
1271     return mr_errcode;
1272   if (cnt > 0)
1273     return MR_EXISTS;
1274
1275   return MR_SUCCESS;
1276 }
1277
1278 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1279  * a duplicate.
1280  */
1281 int setup_uhha(struct query *q, char **argv, client *cl)
1282 {
1283   EXEC SQL BEGIN DECLARE SECTION;
1284   char *hwaddr = argv[1];
1285   int count;
1286   EXEC SQL END DECLARE SECTION;
1287   char *p;
1288
1289   if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1290     {
1291       for (p = hwaddr; *p; p++)
1292         {
1293           if (isupper(*p))
1294             *p = tolower(*p);
1295           if (!isxdigit(*p))
1296             return MR_BAD_CHAR;
1297         }
1298       if (p != hwaddr + 12)
1299         return MR_ADDRESS;
1300
1301       EXEC SQL SELECT COUNT(hwaddr) INTO :count
1302         FROM machine WHERE hwaddr = :hwaddr;
1303       if (count)
1304         return MR_NOT_UNIQUE;
1305     }
1306
1307   return MR_SUCCESS;
1308 }
1309
1310 /* setup_aprn(): Make sure name/duplexname don't conflict with
1311  * anything. If [ANY] was specified for the spooling host, pick the
1312  * least loaded print server that serves this kind of printer.
1313  */
1314 int setup_aprn(struct query *q, char **argv, client *cl)
1315 {
1316   int best = -1, row;
1317   char *p;
1318   EXEC SQL BEGIN DECLARE SECTION;
1319   int mid, usage, count;
1320   char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1321   EXEC SQL END DECLARE SECTION;
1322
1323   /* Check for aprn or uprn. */
1324   if (q->type == APPEND)
1325     row = 0;
1326   else
1327     row = 1;
1328
1329   name = argv[PRN_NAME + row];
1330   duplexname = argv[PRN_DUPLEXNAME + row];
1331   oldname = argv[0];
1332
1333   if (!*name)
1334     return MR_BAD_CHAR;
1335   else
1336     {
1337       if (q->type == APPEND)
1338         {
1339           EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1340             WHERE name = :name OR duplexname = :name;
1341         }
1342       else
1343         {
1344           EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1345             WHERE ( name = :name OR duplexname = :name )
1346             AND name != :oldname;
1347         }
1348       if (dbms_errno)
1349         return mr_errcode;
1350       if (count)
1351         return MR_NOT_UNIQUE;
1352     }
1353
1354   if (*duplexname)
1355     {
1356       if (q->type == APPEND)
1357         {
1358           EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1359             WHERE name = :duplexname OR duplexname = :duplexname;
1360         }
1361       else
1362         {
1363           EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1364             WHERE ( name = :duplexname OR duplexname = :duplexname )
1365             AND name != :oldname;
1366         }
1367
1368       if (dbms_errno)
1369         return mr_errcode;
1370       if (count)
1371         return MR_NOT_UNIQUE;
1372     }
1373
1374   if (!strcmp(name, duplexname))
1375     return MR_NOT_UNIQUE;
1376
1377   mid = *(int *)argv[PRN_RM + row];
1378   if (mid == -1)
1379     {
1380       EXEC SQL DECLARE csr_rm CURSOR FOR
1381         SELECT ps.mach_id, s.string FROM printservers ps, strings s
1382         WHERE ps.mach_id IN
1383         ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1384           AND enable = 1 )
1385         AND ps.printer_types = s.string_id;
1386       if (dbms_errno)
1387         return mr_errcode;
1388       EXEC SQL OPEN csr_rm;
1389       if (dbms_errno)
1390         return mr_errcode;
1391
1392       while (1)
1393         {
1394           EXEC SQL FETCH csr_rm INTO :mid, :types;
1395           if (sqlca.sqlcode)
1396             break;
1397
1398           for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1399             {
1400               if (!strcasecmp(argv[PRN_TYPE + row], p))
1401                 {
1402                   EXEC SQL SELECT COUNT(name) INTO :usage
1403                     FROM printers WHERE rm = :mid;
1404
1405                   if (best < 0 || usage < best)
1406                     {
1407                       best = usage;
1408                       *(int *)argv[PRN_RM + row] = mid;
1409                       break;
1410                     }
1411                 }
1412             }
1413         }
1414       EXEC SQL CLOSE csr_rm;
1415       if (dbms_errno)
1416         return mr_errcode;
1417
1418       if (best == -1)
1419         return MR_SERVICE;
1420     }
1421   else
1422     {
1423       EXEC SQL SELECT mach_id INTO :mid FROM printservers
1424         WHERE mach_id = :mid;
1425       if (sqlca.sqlcode)
1426         return MR_SERVICE;
1427     }
1428
1429   return MR_SUCCESS;
1430 }
1431
1432 int setup_dpsv(struct query *q, char **argv, client *cl)
1433 {
1434   int id;
1435   EXEC SQL BEGIN DECLARE SECTION;
1436   int cnt;
1437   EXEC SQL END DECLARE SECTION;
1438
1439   id = *(int *)argv[0];
1440
1441   EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1442     WHERE rm = :id;
1443   if (cnt > 0)
1444     return MR_IN_USE;
1445
1446   return MR_SUCCESS;
1447 }
1448
1449 int setup_dcon(struct query *q, char *argv[], client *cl)
1450 {
1451   EXEC SQL BEGIN DECLARE SECTION;
1452   int id, cnt;
1453   char containername[CONTAINERS_NAME_SIZE];
1454   EXEC SQL END DECLARE SECTION;
1455
1456   id = *(int *)argv[0];
1457   /* check to see if there are machines in this container */
1458   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1459     WHERE cnt_id = :id;
1460   if (cnt > 0)
1461     return MR_IN_USE;
1462
1463   /* check to see if there are subcontainers in this container */
1464
1465   /* get the container name */
1466   
1467   EXEC SQL SELECT name INTO :containername
1468     FROM containers
1469     WHERE cnt_id = :id; 
1470
1471   /* trim off the trailing spaces */
1472    strcpy(containername, strtrim(containername));
1473
1474   EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1475     WHERE LOWER(name) LIKE LOWER(:containername || '/' || '%');
1476
1477   if (cnt > 0)
1478     return MR_IN_USE;
1479
1480   if (dbms_errno)
1481     return mr_errcode;
1482   return MR_SUCCESS;
1483 }
1484
1485 int setup_scli(struct query *q, char *argv[], client *cl)
1486 {
1487   EXEC SQL BEGIN DECLARE SECTION;
1488   int cnt_id, list_id;
1489   EXEC SQL END DECLARE SECTION;
1490
1491   cnt_id = *(int *)argv[0];
1492   /* Check if someone has already set the list for this container */
1493   EXEC SQL SELECT list_id INTO :list_id FROM containers
1494     WHERE cnt_id = :cnt_id;
1495   if (list_id != 0)
1496     return MR_EXISTS;
1497
1498   if (dbms_errno)
1499     return mr_errcode;
1500
1501   return MR_SUCCESS;
1502 }
1503
1504 /* hostname_check()
1505  * validate the rfc1035/rfc1123-ness of a hostname
1506  */
1507
1508 int hostname_check(char *name)
1509 {
1510   char *p;
1511   int count;
1512
1513   /* Sanity check name: must contain only letters, numerals, and
1514    * hyphen, and not start or end with a hyphen. Also make sure no
1515    * label (the thing the .s seperate) is longer than 63 characters,
1516    * or empty.
1517    */
1518
1519   for (p = name, count = 0; *p; p++)
1520     {
1521       count++;
1522       if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1523           (*p == '-' && p[1] == '.'))
1524         return 0;
1525       if (*p == '.')
1526         {
1527           if (count == 1)
1528             return 0;
1529           count = 0;
1530         }
1531       if (count == 64)
1532         return 0;
1533     }
1534   if (*(p - 1) == '-')
1535     return 0;
1536   return 1;
1537 }
1538
1539 int hostinfo_check(char *info, int num)
1540 {
1541   char *p;
1542
1543   if (!*info)
1544     return 1;
1545
1546   /* Sanity check host hostinfo: must start with a letter (or number
1547    * if num is true), contain only letters, numerals, and hyphen, and
1548    * not end with a hyphen.
1549    */
1550
1551   if (!isalpha(*info) && (!num || !isdigit(*info)))
1552     return 0;
1553   for (p = info; *p; p++)
1554     {
1555       if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1556           (*p == '-' && p[1] == '.'))
1557         return 0;
1558     }
1559   if (!isalnum(*(p - 1)))
1560     return 1;
1561 }
1562
1563 int setup_acon(struct query *q, char *argv[], client *cl)
1564 {
1565   EXEC SQL BEGIN DECLARE SECTION;
1566   char containername[CONTAINERS_NAME_SIZE];
1567   EXEC SQL END DECLARE SECTION;
1568   
1569   char* ptr;
1570   
1571   memset(containername, 0, sizeof(containername));
1572   strcpy(containername, argv[0]);
1573   ptr = strrchr(containername, '/');
1574   /* sub container, check for parents */
1575   if (ptr)
1576     {
1577       *ptr = '\0';
1578       EXEC SQL SELECT * FROM containers
1579         WHERE lower(name) = lower(:containername);      
1580       if (sqlca.sqlerrd[2] != 1)
1581         return MR_CONTAINER_NO_PARENT;
1582     }
1583   
1584   if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1585     return mr_errcode;
1586   
1587   return MR_SUCCESS;
1588 }
1589
1590 int check_mailman_listname(char *name, const char *suffix)
1591 {
1592   char *p;
1593   EXEC SQL BEGIN DECLARE SECTION;
1594   int i, cnt;
1595   EXEC SQL END DECLARE SECTION;
1596
1597   p = strstr(name, suffix);
1598   if (p)
1599     {
1600       if (strlen(name) == (p - name + strlen(suffix)))
1601         {
1602           /* list is of the form "name-suffix" */
1603           i = (p - name);
1604           EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
1605             WHERE name = SUBSTR(:name, 1, :i) AND mailman = 1;
1606           if (cnt > 0)
1607             return MR_EXISTS;
1608         }
1609     }
1610
1611   return MR_SUCCESS;
1612 }
This page took 1.959696 seconds and 5 git commands to generate.