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