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