1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2017 Peter Tribble.
24 */
25
26 /*
27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
32 /* All Rights Reserved */
33
34
35
36 #include <stdio.h>
37 #include <limits.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <fcntl.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <errno.h>
46 #include "pkgstrct.h"
47 #include "pkglib.h"
48 #include "pkglibmsgs.h"
49 #include "pkglocale.h"
50
51 #define ERR_CANT_READ_LCLPATH "unable to read local pathname"
52 #define ERR_BAD_VOLUME_NUMBER "bad volume number"
53 #define ERR_CANNOT_READ_PATHNAME_FIELD "unable to read pathname field"
54 #define ERR_CANNOT_READ_CONTENT_INFO "unable to read content info"
55 #define ERR_EXTRA_TOKENS_PRESENT "extra tokens on input line"
56 #define ERR_CANNOT_READ_CLASS_TOKEN "unable to read class token"
57 #define ERR_BAD_LINK_SPEC "missing or invalid link specification"
58 #define ERR_UNKNOWN_FTYPE "unknown ftype"
59 #define ERR_NO_LINKSOURCE "no link source specified"
60 #define ERR_CANNOT_READ_MM_DEVNUMS "unable to read major/minor "\
61 "device numbers"
62 static int eatwhite(FILE *fp);
63 static int getend(FILE *fp);
64 static int getstr(FILE *fp, char *sep, int n, char *str);
65 static int getnum(FILE *fp, int base, long *d, long bad);
66 static int getlnum(FILE *fp, int base, fsblkcnt_t *d, long bad);
67 static int getvalmode(FILE *fp, mode_t *d, long bad, int map);
68
69 static int getendvfp(char **cp);
70 static void findendvfp(char **cp);
71 static int getstrvfp(char **cp, char *sep, int n, char *str);
72 static int getvalmodevfp(char **cp, mode_t *d, long bad, int map);
73 int getnumvfp(char **cp, int base, long *d, long bad);
74 int getlnumvfp(char **cp, int base, fsblkcnt_t *d, long bad);
75
76 static char mypath[PATH_MAX];
77 static char mylocal[PATH_MAX];
78 static int mapmode = MAPNONE;
79 static char *maptype = "";
80 static mode_t d_mode = BADMODE;
81 static char *d_owner = BADOWNER;
82 static char *d_group = BADGROUP;
83
84 /*
85 * These determine how gpkgmap() deals with mode, owner and group defaults.
86 * It is assumed that the owner and group arguments represent static fields
87 * which will persist until attrdefault() is called.
88 */
89 void
attrpreset(int mode,char * owner,char * group)90 attrpreset(int mode, char *owner, char *group)
91 {
92 d_mode = mode;
93 d_owner = owner;
94 d_group = group;
95 }
96
97 void
attrdefault()98 attrdefault()
99 {
100 d_mode = NOMODE;
101 d_owner = NOOWNER;
102 d_group = NOGROUP;
103 }
104
105 /*
106 * This determines how gpkgmap() deals with environment variables in the
107 * mode, owner and group. Path is evaluated at a higher level based upon
108 * other circumstances.
109 */
110 void
setmapmode(int mode)111 setmapmode(int mode)
112 {
113 if (mode >= 0 || mode <= 3) {
114 mapmode = mode;
115 if (mode == MAPBUILD)
116 maptype = " build";
117 else if (mode == MAPINSTALL)
118 maptype = " install";
119 else
120 maptype = "";
121 }
122 }
123
124 /* This is the external query interface for mapmode. */
125 int
getmapmode(void)126 getmapmode(void)
127 {
128 return (mapmode);
129 }
130
131 /*
132 * Unpack the pkgmap or the contents file or whatever file is in that format.
133 * Based upon mapmode, environment parameters will be resolved for mode,
134 * owner and group.
135 */
136
137 int
gpkgmap(struct cfent * ept,FILE * fp)138 gpkgmap(struct cfent *ept, FILE *fp)
139 {
140 int c;
141 boolean_t first_char = B_TRUE;
142
143 setErrstr(NULL);
144 ept->volno = 0;
145 ept->ftype = BADFTYPE;
146 (void) strcpy(ept->pkg_class, BADCLASS);
147 ept->pkg_class_idx = -1;
148 ept->path = NULL;
149 ept->ainfo.local = NULL;
150 /* default attributes were supplied, so don't reset */
151 ept->ainfo.mode = d_mode;
152 (void) strcpy(ept->ainfo.owner, d_owner);
153 (void) strcpy(ept->ainfo.group, d_group);
154 ept->ainfo.major = BADMAJOR;
155 ept->ainfo.minor = BADMINOR;
156 ept->cinfo.cksum = -1L;
157 ept->cinfo.modtime = -1L;
158 ept->cinfo.size = -1L;
159
160 ept->npkgs = 0;
161
162 if (!fp)
163 return (-1);
164 readline:
165 c = eatwhite(fp);
166
167 /*
168 * If the first character is not a digit, we assume that the
169 * volume number is 1.
170 */
171 if (first_char && !isdigit(c)) {
172 ept->volno = 1;
173 }
174 first_char = B_FALSE;
175
176 switch (c) {
177 case EOF:
178 return (0);
179
180 case '0':
181 case '1':
182 case '2':
183 case '3':
184 case '4':
185 case '5':
186 case '6':
187 case '7':
188 case '8':
189 case '9':
190 if (ept->volno) {
191 setErrstr(pkg_gt(ERR_BAD_VOLUME_NUMBER));
192 goto error;
193 }
194 do {
195 ept->volno = (ept->volno*10)+c-'0';
196 c = getc(fp);
197 } while (isdigit(c));
198 if (ept->volno == 0)
199 ept->volno = 1;
200
201 goto readline;
202
203 case ':':
204 case '#':
205 (void) getend(fp);
206 /*FALLTHRU*/
207 case '\n':
208 /*
209 * Since we are going to scan the next line,
210 * we need to reset volume number and first_char.
211 */
212 ept->volno = 0;
213 first_char = B_TRUE;
214 goto readline;
215
216 case 'i':
217 ept->ftype = (char)c;
218 c = eatwhite(fp);
219 /*FALLTHRU*/
220 case '.':
221 case '/':
222 (void) ungetc(c, fp);
223
224 if (getstr(fp, "=", PATH_MAX, mypath)) {
225 setErrstr(pkg_gt(ERR_CANNOT_READ_PATHNAME_FIELD));
226 goto error;
227 }
228 ept->path = mypath;
229 c = getc(fp);
230 if (c == '=') {
231 if (getstr(fp, NULL, PATH_MAX, mylocal)) {
232 setErrstr(pkg_gt(ERR_CANT_READ_LCLPATH));
233 goto error;
234 }
235 ept->ainfo.local = mylocal;
236 } else
237 (void) ungetc(c, fp);
238
239 if (ept->ftype == 'i') {
240 /* content info might exist */
241 if (!getlnum(fp, 10, (fsblkcnt_t *)&ept->cinfo.size,
242 BADCONT) &&
243 (getnum(fp, 10, (long *)&ept->cinfo.cksum,
244 BADCONT) ||
245 getnum(fp, 10, (long *)&ept->cinfo.modtime,
246 BADCONT))) {
247 setErrstr(pkg_gt(ERR_CANNOT_READ_CONTENT_INFO));
248 goto error;
249 }
250 }
251 if (getend(fp)) {
252 setErrstr(pkg_gt(ERR_EXTRA_TOKENS_PRESENT));
253 return (-1);
254 }
255 return (1);
256
257 case '?':
258 case 'f':
259 case 'v':
260 case 'e':
261 case 'l':
262 case 's':
263 case 'p':
264 case 'c':
265 case 'b':
266 case 'd':
267 case 'x':
268 ept->ftype = (char)c;
269 if (getstr(fp, NULL, CLSSIZ, ept->pkg_class)) {
270 setErrstr(pkg_gt(ERR_CANNOT_READ_CLASS_TOKEN));
271 goto error;
272 }
273 if (getstr(fp, "=", PATH_MAX, mypath)) {
274 setErrstr(pkg_gt(ERR_CANNOT_READ_PATHNAME_FIELD));
275 goto error;
276 }
277 ept->path = mypath;
278
279 c = getc(fp);
280 if (c == '=') {
281 /* local path */
282 if (getstr(fp, NULL, PATH_MAX, mylocal)) {
283 if (ept->ftype == 's' || ept->ftype == 'l') {
284 setErrstr(pkg_gt(ERR_READLINK));
285 } else {
286 setErrstr(
287 pkg_gt(ERR_CANT_READ_LCLPATH));
288 }
289 goto error;
290 }
291 ept->ainfo.local = mylocal;
292 } else if (strchr("sl", ept->ftype)) {
293 if ((c != EOF) && (c != '\n'))
294 (void) getend(fp);
295 setErrstr(pkg_gt(ERR_BAD_LINK_SPEC));
296 return (-1);
297 } else
298 (void) ungetc(c, fp);
299 break;
300
301 default:
302 setErrstr(pkg_gt(ERR_UNKNOWN_FTYPE));
303 error:
304 (void) getend(fp);
305 return (-1);
306 }
307
308 if (strchr("sl", ept->ftype) && (ept->ainfo.local == NULL)) {
309 setErrstr(pkg_gt(ERR_NO_LINKSOURCE));
310 goto error;
311 }
312
313 if (strchr("cb", ept->ftype)) {
314 ept->ainfo.major = BADMAJOR;
315 ept->ainfo.minor = BADMINOR;
316 if (getnum(fp, 10, (long *)&ept->ainfo.major, BADMAJOR) ||
317 getnum(fp, 10, (long *)&ept->ainfo.minor, BADMINOR)) {
318 setErrstr(pkg_gt(ERR_CANNOT_READ_MM_DEVNUMS));
319 goto error;
320 }
321 }
322
323 /*
324 * Links and information files don't have attributes associated with
325 * them. The following either resolves potential variables or passes
326 * them through. Mode is tested for validity to some degree. BAD???
327 * is returned to indicate that no meaningful mode was provided. A
328 * higher authority will decide if that's OK or not. CUR??? means that
329 * the prototype file specifically requires a wildcard ('?') for
330 * that entry. We issue an error if attributes were entered wrong.
331 * We just return BAD??? if there was no entry at all.
332 */
333 if (strchr("cbdxpfve", ept->ftype)) {
334 int retval;
335
336 if ((retval = getvalmode(fp, &(ept->ainfo.mode), CURMODE,
337 (mapmode != MAPNONE))) == 1)
338 goto end; /* nothing else on the line */
339 else if (retval == 2)
340 goto error; /* mode is too no good */
341
342 /* owner & group should be here */
343 if ((retval = getstr(fp, NULL, ATRSIZ,
344 ept->ainfo.owner)) == 1)
345 goto end; /* no owner or group - warning */
346 if (retval == -1) {
347 setErrstr(pkg_gt(ERR_OWNTOOLONG));
348 goto error;
349 }
350
351 if ((retval = getstr(fp, NULL, ATRSIZ,
352 ept->ainfo.group)) == 1)
353 goto end; /* no group - warning */
354 if (retval == -1) {
355 setErrstr(pkg_gt(ERR_GRPTOOLONG));
356 goto error;
357 }
358
359 /* Resolve the parameters if required. */
360 if (mapmode != MAPNONE) {
361 if (mapvar(mapmode, ept->ainfo.owner)) {
362 (void) snprintf(getErrbufAddr(),
363 getErrbufSize(),
364 pkg_gt(ERR_NOVAR),
365 maptype, ept->ainfo.owner);
366 setErrstr(getErrbufAddr());
367 goto error;
368 }
369 if (mapvar(mapmode, ept->ainfo.group)) {
370 (void) snprintf(getErrbufAddr(),
371 getErrbufSize(), pkg_gt(ERR_NOVAR),
372 maptype, ept->ainfo.group);
373 setErrstr(getErrbufAddr());
374 goto error;
375 }
376 }
377 }
378
379 if (strchr("ifve", ept->ftype)) {
380 /* look for content description */
381 if (!getlnum(fp, 10, (fsblkcnt_t *)&ept->cinfo.size, BADCONT) &&
382 (getnum(fp, 10, (long *)&ept->cinfo.cksum, BADCONT) ||
383 getnum(fp, 10, (long *)&ept->cinfo.modtime, BADCONT))) {
384 setErrstr(pkg_gt(ERR_CANNOT_READ_CONTENT_INFO));
385 goto error;
386 }
387 }
388
389 if (ept->ftype == 'i')
390 goto end;
391
392 end:
393 if (getend(fp) && ept->pinfo) {
394 setErrstr(pkg_gt(ERR_EXTRA_TOKENS_PRESENT));
395 return (-1);
396 }
397
398 return (1);
399 }
400
401 /*
402 * Get and validate the mode attribute. This returns an error if
403 * 1. the mode string is too long
404 * 2. the mode string includes alpha characters
405 * 3. the mode string is not octal
406 * 4. mode string is an install parameter
407 * 5. mode is an unresolved build parameter and MAPBUILD is
408 * in effect.
409 * If the mode is a build parameter, it is
410 * 1. returned as is if MAPNONE is in effect
411 * 2. evaluated if MAPBUILD is in effect
412 *
413 * NOTE : We use "mapmode!=MAPBUILD" to gather that it is install
414 * time. At install time we just fix a mode with bad bits set by
415 * setting it to CURMODE. This should be an error in a few releases
416 * (2.8 maybe) but faulty modes are so common in existing packages
417 * that this is a reasonable exception. -- JST 1994-11-9
418 *
419 * RETURNS
420 * 0 if mode is being returned as a valid value
421 * 1 if no attributes are present on the line
422 * 2 if there was a fundamental error
423 */
424 static int
getvalmode(FILE * fp,mode_t * d,long bad,int map)425 getvalmode(FILE *fp, mode_t *d, long bad, int map)
426 {
427 char tempmode[20];
428 mode_t tempmode_t;
429 int retval;
430
431 if ((retval = getstr(fp, NULL, ATRSIZ, tempmode)) == 1)
432 return (1);
433 else if (retval == -1) {
434 setErrstr(pkg_gt(ERR_MODELONG));
435 return (2);
436 } else {
437 /*
438 * If it isn't a '?' (meaning go with whatever mode is
439 * there), validate the mode and convert it to a mode_t. The
440 * "bad" variable here is a misnomer. It doesn't necessarily
441 * mean bad.
442 */
443 if (tempmode[0] == '?') {
444 *d = WILDCARD;
445 } else {
446 /*
447 * Mode may not be an install parameter or a
448 * non-build parameter.
449 */
450 if (tempmode[0] == '$' &&
451 (isupper(tempmode[1]) || !islower(tempmode[1]))) {
452 setErrstr(pkg_gt(ERR_IMODE));
453 return (2);
454 }
455
456 if ((map) && (mapvar(mapmode, tempmode))) {
457 (void) snprintf(getErrbufAddr(),
458 getErrbufSize(),
459 pkg_gt(ERR_NOVAR),
460 maptype, tempmode);
461 setErrstr(getErrbufAddr());
462 return (2);
463 }
464
465
466 if (tempmode[0] == '$') {
467 *d = BADMODE; /* may be a problem */
468 } else {
469 /*
470 * At this point it's supposed to be
471 * something we can convert to a number.
472 */
473 int n = 0;
474
475 /*
476 * We reject it if it contains nonnumbers or
477 * it's not octal.
478 */
479 while (tempmode[n] && !isspace(tempmode[n])) {
480 if (!isdigit(tempmode[n])) {
481 setErrstr(
482 pkg_gt(ERR_MODEALPHA));
483 return (2);
484 }
485
486 if (strchr("89abcdefABCDEF",
487 tempmode[n])) {
488 setErrstr(
489 pkg_gt(ERR_BASEINVAL));
490 return (2);
491 }
492 n++;
493 }
494
495 tempmode_t = strtol(tempmode, NULL, 8);
496
497 /*
498 * We reject it if it contains inappropriate
499 * bits.
500 */
501 if (tempmode_t & ~(S_IAMB |
502 S_ISUID | S_ISGID | S_ISVTX)) {
503 if (mapmode != MAPBUILD) {
504 tempmode_t = bad;
505 } else {
506 setErrstr(pkg_gt(ERR_MODEBITS));
507 return (2);
508 }
509 }
510 *d = tempmode_t;
511 }
512 }
513 return (0);
514 }
515 }
516
517 static int
getnum(FILE * fp,int base,long * d,long bad)518 getnum(FILE *fp, int base, long *d, long bad)
519 {
520 int c, b;
521
522 /* leading white space ignored */
523 c = eatwhite(fp);
524 if (c == '?') {
525 *d = bad;
526 return (0);
527 }
528
529 if ((c == EOF) || (c == '\n') || !isdigit(c)) {
530 (void) ungetc(c, fp);
531 return (1);
532 }
533
534 *d = 0;
535 while (isdigit(c)) {
536 b = (c & 017);
537 if (b >= base)
538 return (2);
539 *d = (*d * base) + b;
540 c = getc(fp);
541 }
542 (void) ungetc(c, fp);
543 return (0);
544 }
545
546 static int
getlnum(FILE * fp,int base,fsblkcnt_t * d,long bad)547 getlnum(FILE *fp, int base, fsblkcnt_t *d, long bad)
548 {
549 int c, b;
550
551 /* leading white space ignored */
552 c = eatwhite(fp);
553 if (c == '?') {
554 *d = bad;
555 return (0);
556 }
557
558 if ((c == EOF) || (c == '\n') || !isdigit(c)) {
559 (void) ungetc(c, fp);
560 return (1);
561 }
562
563 *d = 0;
564 while (isdigit(c)) {
565 b = (c & 017);
566 if (b >= base)
567 return (2);
568 *d = (*d * base) + b;
569 c = getc(fp);
570 }
571 (void) ungetc(c, fp);
572 return (0);
573 }
574
575 /*
576 * Get a string from the file. Returns
577 * 0 if all OK
578 * 1 if nothing there
579 * -1 if string is too long
580 */
581 static int
getstr(FILE * fp,char * sep,int n,char * str)582 getstr(FILE *fp, char *sep, int n, char *str)
583 {
584 int c;
585
586 /* leading white space ignored */
587 c = eatwhite(fp);
588 if ((c == EOF) || (c == '\n')) {
589 (void) ungetc(c, fp);
590 return (1); /* nothing there */
591 }
592
593 /* fill up string until space, tab, or separator */
594 while (!strchr(" \t", c) && (!sep || !strchr(sep, c))) {
595 if (n-- < 1) {
596 *str = '\0';
597 return (-1); /* too long */
598 }
599 *str++ = (char)c;
600 c = getc(fp);
601 if ((c == EOF) || (c == '\n'))
602 break; /* no more on this line */
603 }
604 *str = '\0';
605 (void) ungetc(c, fp);
606
607 return (0);
608 }
609
610 static int
getend(FILE * fp)611 getend(FILE *fp)
612 {
613 int c;
614 int n;
615
616 n = 0;
617 do {
618 if ((c = getc(fp)) == EOF)
619 return (n);
620 if (!isspace(c))
621 n++;
622 } while (c != '\n');
623 return (n);
624 }
625
626 static int
eatwhite(FILE * fp)627 eatwhite(FILE *fp)
628 {
629 int c;
630
631 /* this test works around a side effect of getc() */
632 if (feof(fp))
633 return (EOF);
634 do {
635 c = getc(fp);
636 } while ((c == ' ') || (c == '\t'));
637 return (c);
638 }
639
640 int
gpkgmapvfp(struct cfent * ept,VFP_T * vfp)641 gpkgmapvfp(struct cfent *ept, VFP_T *vfp)
642 {
643 int c;
644 boolean_t first_char = B_TRUE;
645 (void) strlcpy(ept->pkg_class, BADCLASS, sizeof (ept->pkg_class));
646 (void) strlcpy(ept->ainfo.owner, d_owner, sizeof (ept->ainfo.owner));
647 (void) strlcpy(ept->ainfo.group, d_group, sizeof (ept->ainfo.group));
648
649 setErrstr(NULL);
650 ept->volno = 0;
651 ept->ftype = BADFTYPE;
652 ept->pkg_class_idx = -1;
653 ept->path = NULL;
654 ept->ainfo.local = NULL;
655 ept->ainfo.mode = d_mode;
656 ept->ainfo.major = BADMAJOR;
657 ept->ainfo.minor = BADMINOR;
658 ept->cinfo.cksum = (-1L);
659 ept->cinfo.modtime = (-1L);
660 ept->cinfo.size = (-1L);
661
662 ept->npkgs = 0;
663
664 /* return error if no vfp specified */
665
666 if (vfp == (VFP_T *)NULL) {
667 return (-1);
668 }
669
670 readline:
671 while (((c = vfpGetcNoInc(vfp)) != '\0') && (isspace(vfpGetc(vfp))))
672 ;
673
674 /*
675 * If the first character is not a digit, we assume that the
676 * volume number is 1.
677 */
678 if (first_char && !isdigit(c)) {
679 ept->volno = 1;
680 }
681 first_char = B_FALSE;
682
683 /*
684 * In case of hsfs the zero-padding of partial pages
685 * returned by mmap is not done properly. A separate bug has been filed
686 * on this.
687 */
688
689 if (vfp->_vfpCurr && (vfp->_vfpCurr > vfp->_vfpEnd)) {
690 return (0);
691 }
692
693 switch (c) {
694 case '\0':
695 return (0);
696
697 case '0':
698 case '1':
699 case '2':
700 case '3':
701 case '4':
702 case '5':
703 case '6':
704 case '7':
705 case '8':
706 case '9':
707 if (ept->volno) {
708 setErrstr(pkg_gt(ERR_BAD_VOLUME_NUMBER));
709 goto error;
710 }
711 do {
712 ept->volno = (ept->volno*10)+c-'0';
713 c = vfpGetc(vfp);
714 } while (isdigit(c));
715 if (ept->volno == 0) {
716 ept->volno = 1;
717 }
718
719 goto readline;
720
721 case ':':
722 case '#':
723 (void) findendvfp(&vfpGetCurrCharPtr(vfp));
724 /*FALLTHRU*/
725 case '\n':
726 /*
727 * Since we are going to scan the next line,
728 * we need to reset volume number and first_char.
729 */
730 ept->volno = 0;
731 first_char = B_TRUE;
732 goto readline;
733
734 case 'i':
735 ept->ftype = (char)c;
736 while (((c = vfpGetcNoInc(vfp)) != '\0') &&
737 (isspace(vfpGetc(vfp))))
738 ;
739 /*FALLTHRU*/
740 case '.':
741 case '/':
742 vfpDecCurrPtr(vfp);
743
744 if (getstrvfp(&vfpGetCurrCharPtr(vfp), "=", PATH_MAX, mypath)) {
745 setErrstr(pkg_gt(ERR_CANNOT_READ_PATHNAME_FIELD));
746 goto error;
747 }
748 ept->path = mypath;
749 c = vfpGetc(vfp);
750 if (c == '=') {
751 if (getstrvfp(&vfpGetCurrCharPtr(vfp), NULL, PATH_MAX,
752 mylocal)) {
753 setErrstr(pkg_gt(ERR_CANT_READ_LCLPATH));
754 goto error;
755 }
756 ept->ainfo.local = mylocal;
757 } else {
758 vfpDecCurrPtr(vfp);
759 }
760
761 if (ept->ftype == 'i') {
762 /* content info might exist */
763 if (!getlnumvfp(&vfpGetCurrCharPtr(vfp), 10,
764 (fsblkcnt_t *)&ept->cinfo.size, BADCONT) &&
765 (getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
766 (long *)&ept->cinfo.cksum, BADCONT) ||
767 getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
768 (long *)&ept->cinfo.modtime, BADCONT))) {
769 setErrstr(pkg_gt(ERR_CANNOT_READ_CONTENT_INFO));
770 goto error;
771 }
772 }
773
774 if (getendvfp(&vfpGetCurrCharPtr(vfp))) {
775 setErrstr(pkg_gt(ERR_EXTRA_TOKENS_PRESENT));
776 return (-1);
777 }
778 return (1);
779
780 case '?':
781 case 'f':
782 case 'v':
783 case 'e':
784 case 'l':
785 case 's':
786 case 'p':
787 case 'c':
788 case 'b':
789 case 'd':
790 case 'x':
791 ept->ftype = (char)c;
792 if (getstrvfp(&vfpGetCurrCharPtr(vfp), NULL,
793 CLSSIZ, ept->pkg_class)) {
794 setErrstr(pkg_gt(ERR_CANNOT_READ_CLASS_TOKEN));
795 goto error;
796 }
797 if (getstrvfp(&vfpGetCurrCharPtr(vfp), "=", PATH_MAX, mypath)) {
798 setErrstr(pkg_gt(ERR_CANNOT_READ_PATHNAME_FIELD));
799 goto error;
800 }
801 ept->path = mypath;
802
803 c = vfpGetc(vfp);
804 if (c == '=') {
805 /* local path */
806 if (getstrvfp(&vfpGetCurrCharPtr(vfp), NULL,
807 PATH_MAX, mylocal)) {
808 if (ept->ftype == 's' || ept->ftype == 'l') {
809 setErrstr(pkg_gt(ERR_READLINK));
810 } else {
811 setErrstr(
812 pkg_gt(ERR_CANT_READ_LCLPATH));
813 }
814 goto error;
815 }
816 ept->ainfo.local = mylocal;
817 } else if ((ept->ftype == 's') || (ept->ftype == 'l')) {
818 if ((c != '\0') && (c != '\n'))
819 (void) findendvfp(&vfpGetCurrCharPtr(vfp));
820 setErrstr(pkg_gt(ERR_BAD_LINK_SPEC));
821 return (-1);
822 } else {
823 vfpDecCurrPtr(vfp);
824 }
825 break;
826
827 default:
828 setErrstr(pkg_gt(ERR_UNKNOWN_FTYPE));
829 error:
830 (void) findendvfp(&vfpGetCurrCharPtr(vfp));
831 return (-1);
832 }
833
834 if (((ept->ftype == 's') || (ept->ftype == 'l')) &&
835 (ept->ainfo.local == NULL)) {
836 setErrstr(pkg_gt(ERR_NO_LINKSOURCE));
837 goto error;
838 }
839
840 if (((ept->ftype == 'c') || (ept->ftype == 'b'))) {
841 ept->ainfo.major = BADMAJOR;
842 ept->ainfo.minor = BADMINOR;
843
844 if (getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
845 (long *)&ept->ainfo.major, BADMAJOR) ||
846 getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
847 (long *)&ept->ainfo.minor, BADMINOR)) {
848 setErrstr(pkg_gt(ERR_CANNOT_READ_MM_DEVNUMS));
849 goto error;
850 }
851 }
852
853 /*
854 * Links and information files don't have attributes associated with
855 * them. The following either resolves potential variables or passes
856 * them through. Mode is tested for validity to some degree. BAD???
857 * is returned to indicate that no meaningful mode was provided. A
858 * higher authority will decide if that's OK or not. CUR??? means that
859 * the prototype file specifically requires a wildcard ('?') for
860 * that entry. We issue an error if attributes were entered wrong.
861 * We just return BAD??? if there was no entry at all.
862 */
863 if ((ept->ftype == 'd') || (ept->ftype == 'x') || (ept->ftype == 'c') ||
864 (ept->ftype == 'b') || (ept->ftype == 'p') ||
865 (ept->ftype == 'f') || (ept->ftype == 'v') ||
866 (ept->ftype == 'e')) {
867 int retval;
868
869 retval = getvalmodevfp(&vfpGetCurrCharPtr(vfp),
870 &(ept->ainfo.mode), CURMODE, (mapmode != MAPNONE));
871
872 if (retval == 1) {
873 goto end; /* nothing else on the line */
874 } else if (retval == 2) {
875 goto error; /* mode is too no good */
876 }
877
878 /* owner & group should be here */
879 if ((retval = getstrvfp(&vfpGetCurrCharPtr(vfp), NULL, ATRSIZ,
880 ept->ainfo.owner)) == 1)
881 goto end; /* no owner or group - warning */
882 if (retval == -1) {
883 setErrstr(pkg_gt(ERR_OWNTOOLONG));
884 goto error;
885 }
886
887 if ((retval = getstrvfp(&vfpGetCurrCharPtr(vfp), NULL, ATRSIZ,
888 ept->ainfo.group)) == 1)
889 goto end; /* no group - warning */
890 if (retval == -1) {
891 setErrstr(pkg_gt(ERR_GRPTOOLONG));
892 goto error;
893 }
894
895 /* Resolve the parameters if required. */
896 if (mapmode != MAPNONE) {
897 if (mapvar(mapmode, ept->ainfo.owner)) {
898 (void) snprintf(getErrbufAddr(),
899 getErrbufSize(), pkg_gt(ERR_NOVAR),
900 maptype, ept->ainfo.owner);
901 setErrstr(getErrbufAddr());
902 goto error;
903 }
904 if (mapvar(mapmode, ept->ainfo.group)) {
905 (void) snprintf(getErrbufAddr(),
906 getErrbufSize(), pkg_gt(ERR_NOVAR),
907 maptype, ept->ainfo.group);
908 setErrstr(getErrbufAddr());
909 goto error;
910 }
911 }
912 }
913
914 if ((ept->ftype == 'i') || (ept->ftype == 'f') ||
915 (ept->ftype == 'v') || (ept->ftype == 'e')) {
916 /* look for content description */
917 if (!getlnumvfp(&vfpGetCurrCharPtr(vfp), 10,
918 (fsblkcnt_t *)&ept->cinfo.size, BADCONT) &&
919 (getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
920 (long *)&ept->cinfo.cksum, BADCONT) ||
921 getnumvfp(&vfpGetCurrCharPtr(vfp), 10,
922 (long *)&ept->cinfo.modtime, BADCONT))) {
923 setErrstr(pkg_gt(ERR_CANNOT_READ_CONTENT_INFO));
924 goto error;
925 }
926 }
927
928 if (ept->ftype == 'i')
929 goto end;
930
931 end:
932 if (getendvfp(&vfpGetCurrCharPtr(vfp)) && ept->pinfo) {
933 setErrstr(pkg_gt(ERR_EXTRA_TOKENS_PRESENT));
934 return (-1);
935 }
936
937 return (1);
938 }
939
940 /*
941 * Get and validate the mode attribute. This returns an error if
942 * 1. the mode string is too long
943 * 2. the mode string includes alpha characters
944 * 3. the mode string is not octal
945 * 4. mode string is an install parameter
946 * 5. mode is an unresolved build parameter and MAPBUILD is
947 * in effect.
948 * If the mode is a build parameter, it is
949 * 1. returned as is if MAPNONE is in effect
950 * 2. evaluated if MAPBUILD is in effect
951 *
952 * NOTE : We use "mapmode!=MAPBUILD" to gather that it is install
953 * time. At install time we just fix a mode with bad bits set by
954 * setting it to CURMODE. This should be an error in a few releases
955 * (2.8 maybe) but faulty modes are so common in existing packages
956 * that this is a reasonable exception. -- JST 1994-11-9
957 *
958 * RETURNS
959 * 0 if mode is being returned as a valid value
960 * 1 if no attributes are present on the line
961 * 2 if there was a fundamental error
962 */
963 static int
getvalmodevfp(char ** cp,mode_t * d,long bad,int map)964 getvalmodevfp(char **cp, mode_t *d, long bad, int map)
965 {
966 char tempmode[ATRSIZ+1];
967 mode_t tempmode_t;
968 int retval;
969 int n;
970
971 if ((retval = getstrvfp(cp, NULL, sizeof (tempmode), tempmode)) == 1) {
972 return (1);
973 } else if (retval == -1) {
974 setErrstr(pkg_gt(ERR_MODELONG));
975 return (2);
976 }
977
978 /*
979 * If it isn't a '?' (meaning go with whatever mode is
980 * there), validate the mode and convert it to a mode_t. The
981 * "bad" variable here is a misnomer. It doesn't necessarily
982 * mean bad.
983 */
984 if (tempmode[0] == '?') {
985 *d = WILDCARD;
986 return (0);
987 }
988
989 /*
990 * Mode may not be an install parameter or a
991 * non-build parameter.
992 */
993
994 if (tempmode[0] == '$' &&
995 (isupper(tempmode[1]) || !islower(tempmode[1]))) {
996 setErrstr(pkg_gt(ERR_IMODE));
997 return (2);
998 }
999
1000 if ((map) && (mapvar(mapmode, tempmode))) {
1001 (void) snprintf(getErrbufAddr(), getErrbufSize(),
1002 pkg_gt(ERR_NOVAR), maptype, tempmode);
1003 setErrstr(getErrbufAddr());
1004 return (2);
1005 }
1006
1007 if (tempmode[0] == '$') {
1008 *d = BADMODE; /* may be a problem */
1009 return (0);
1010 }
1011
1012 /* it's supposed to be something we can convert to a number */
1013
1014 n = 0;
1015
1016 /* reject it if it contains nonnumbers or it's not octal */
1017
1018 while (tempmode[n] && !isspace(tempmode[n])) {
1019 if (!isdigit(tempmode[n])) {
1020 setErrstr(pkg_gt(ERR_MODEALPHA));
1021 return (2);
1022 }
1023
1024 if (strchr("89abcdefABCDEF", tempmode[n])) {
1025 setErrstr(pkg_gt(ERR_BASEINVAL));
1026 return (2);
1027 }
1028 n++;
1029 }
1030
1031 tempmode_t = strtol(tempmode, NULL, 8);
1032
1033 /*
1034 * We reject it if it contains inappropriate
1035 * bits.
1036 */
1037 if (tempmode_t & (~(S_IAMB | S_ISUID | S_ISGID | S_ISVTX))) {
1038 if (mapmode == MAPBUILD) {
1039 setErrstr(pkg_gt(ERR_MODEBITS));
1040 return (2);
1041 }
1042 tempmode_t = bad;
1043 }
1044
1045 *d = tempmode_t;
1046
1047 return (0);
1048 }
1049
1050 int
getnumvfp(char ** cp,int base,long * d,long bad)1051 getnumvfp(char **cp, int base, long *d, long bad)
1052 {
1053 int c;
1054 char *p = *cp;
1055
1056 if (*p == '\0') {
1057 return (0);
1058 }
1059
1060 /* leading white space ignored */
1061 while (((c = *p) != '\0') && (isspace(*p++)))
1062 ;
1063 if (c == '?') {
1064 *d = bad;
1065 *cp = p;
1066 return (0);
1067 }
1068
1069 if ((c == '\0') || (c == '\n') || !isdigit(c)) {
1070 p--;
1071 *cp = p;
1072 return (1);
1073 }
1074
1075 *d = 0;
1076 while (isdigit(c)) {
1077 *d = (*d * base) + (c & 017);
1078 c = *p++;
1079 }
1080 p--;
1081 *cp = p;
1082 return (0);
1083 }
1084
1085 int
getlnumvfp(char ** cp,int base,fsblkcnt_t * d,long bad)1086 getlnumvfp(char **cp, int base, fsblkcnt_t *d, long bad)
1087 {
1088 int c;
1089 char *p = *cp;
1090
1091 if (*p == '\0') {
1092 return (0);
1093 }
1094
1095 /* leading white space ignored */
1096 while (((c = *p) != '\0') && (isspace(*p++)))
1097 ;
1098 if (c == '?') {
1099 *d = bad;
1100 *cp = p;
1101 return (0);
1102 }
1103
1104 if ((c == '\0') || (c == '\n') || !isdigit(c)) {
1105 p--;
1106 *cp = p;
1107 return (1);
1108 }
1109
1110 *d = 0;
1111 while (isdigit(c)) {
1112 *d = (*d * base) + (c & 017);
1113 c = *p++;
1114 }
1115 p--;
1116 *cp = p;
1117 return (0);
1118 }
1119
1120 static int
getstrvfp(char ** cp,char * sep,int n,char * str)1121 getstrvfp(char **cp, char *sep, int n, char *str)
1122 {
1123 char delims[256];
1124 int c;
1125 char *p = *cp;
1126 char *p1;
1127 size_t len;
1128
1129 if (*p == '\0') {
1130 return (1);
1131 }
1132
1133 /* leading white space ignored */
1134
1135 while (((c = *p) != '\0') && (isspace(*p++)))
1136 ;
1137 if ((c == '\0') || (c == '\n')) {
1138 p--;
1139 *cp = p;
1140 return (1); /* nothing there */
1141 }
1142
1143 p--;
1144
1145 /* generate complete list of delimiters to scan for */
1146
1147 (void) strlcpy(delims, " \t\n", sizeof (delims));
1148 if ((sep != (char *)NULL) && (*sep != '\0')) {
1149 (void) strlcat(delims, sep, sizeof (delims));
1150 }
1151
1152 /* compute length based on delimiter found or not */
1153
1154 p1 = strpbrk(p, delims);
1155 if (p1 == (char *)NULL) {
1156 len = strlen(p);
1157 } else {
1158 len = (ptrdiff_t)p1 - (ptrdiff_t)p;
1159 }
1160
1161 /* if string will fit in result buffer copy string and return success */
1162
1163 if (len < n) {
1164 (void) memcpy(str, p, len);
1165 str[len] = '\0';
1166 p += len;
1167 *cp = p;
1168 return (0);
1169 }
1170
1171 /* result buffer too small; copy partial string, return error */
1172 (void) memcpy(str, p, n-1);
1173 str[n-1] = '\0';
1174 p += n;
1175 *cp = p;
1176 return (-1);
1177 }
1178
1179 /*
1180 * Name: getendvfp
1181 * Description: Locate the end of the current line given a pointer into a buffer
1182 * containing characters that is null terminated.
1183 * Arguments: char **cp - pointer to pointer to null-terminated string buffer
1184 * Returns: int == 0 -- no non-space characters preceeded the newline
1185 * != 0 -- one or more non-space characters preceeded newline
1186 * Effects: cp is updated to point to the first character PAST the first new
1187 * line character found. If no newline character is found, cp is
1188 * updated to point to the '\0' at the end of the buffer.
1189 */
1190
1191 static int
getendvfp(char ** cp)1192 getendvfp(char **cp)
1193 {
1194 int n;
1195 char *p = *cp;
1196
1197 n = 0;
1198
1199 /* if at end of buffer return no more characters left */
1200
1201 if (*p == '\0') {
1202 return (0);
1203 }
1204
1205 /* find the first null or end of line character */
1206
1207 while ((*p != '\0') && (*p != '\n')) {
1208 if (n == 0) {
1209 if (!isspace(*p)) {
1210 n++;
1211 }
1212 }
1213 p++;
1214 }
1215
1216 /* if at newline, increment pointer to first character past newline */
1217
1218 if (*p == '\n') {
1219 p++;
1220 }
1221
1222 /* set return pointer to null or first character past newline */
1223
1224 *cp = p;
1225
1226 /* return space/nospace indicator */
1227
1228 return (n);
1229 }
1230
1231 /*
1232 * Name: findendvfp
1233 * Description: Locate the end of the current line given a pointer into a buffer
1234 * containing characters that is null terminated.
1235 * Arguments: char **cp - pointer to pointer to null-terminated string buffer
1236 * Returns: none
1237 * Effects: cp is updated to point to the first character PAST the first new
1238 * line character found. If no newline character is found, cp is
1239 * updated to point to the '\0' at the end of the buffer.
1240 */
1241
1242 static void
findendvfp(char ** cp)1243 findendvfp(char **cp)
1244 {
1245 char *p1;
1246 char *p = *cp;
1247
1248 /* if at end of buffer return no more characters left */
1249
1250 if (*p == '\0') {
1251 return;
1252 }
1253
1254 /* find the end of the line */
1255
1256 p1 = strchr(p, '\n');
1257 if (p1 != (char *)NULL) {
1258 *cp = ++p1;
1259 return;
1260 }
1261
1262 /* no newline found - point to null terminator */
1263
1264 *cp = strchr(p, '\0');
1265 }
1266