]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.sbin/ctm/ctm/ctm_pass1.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / usr.sbin / ctm / ctm / ctm_pass1.c
1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5  * can do whatever you want with this stuff. If we meet some day, and you think
6  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7  * ----------------------------------------------------------------------------
8  *
9  * $FreeBSD$
10  *
11  */
12
13 #include "ctm.h"
14 #define BADREAD 1
15
16 /*---------------------------------------------------------------------------*/
17 /* Pass1 -- Validate the incoming CTM-file.
18  */
19
20 int
21 Pass1(FILE *fd, unsigned applied)
22 {
23     u_char *p,*q;
24     MD5_CTX ctx;
25     int i,j,sep,cnt;
26     u_char *md5=0,*name=0,*trash=0;
27     struct CTM_Syntax *sp;
28     int slashwarn=0, match=0, total_matches=0;
29     unsigned current;
30     char md5_1[33];
31
32     if(Verbose>3)
33         printf("Pass1 -- Checking integrity of incoming CTM-patch\n");
34     MD5Init (&ctx);
35
36     GETFIELD(p,' ');                            /* CTM_BEGIN */
37     if(strcmp(p,"CTM_BEGIN")) {
38         Fatal("Probably not a CTM-patch at all.");
39         if(Verbose>3)
40             fprintf(stderr,"Expected \"CTM_BEGIN\" got \"%s\".\n",p);
41         return 1;
42     }
43
44     GETFIELDCOPY(Version,' ');                          /* <Version> */
45     if(strcmp(Version,VERSION)) {
46         Fatal("CTM-patch is wrong version.");
47         if(Verbose>3)
48             fprintf(stderr,"Expected \"%s\" got \"%s\".\n",VERSION,p);
49         return 1;
50     }
51
52     GETFIELDCOPY(Name,' ');                             /* <Name> */
53     GETFIELDCOPY(Nbr,' ');                              /* <Nbr> */
54     GETFIELDCOPY(TimeStamp,' ');                        /* <TimeStamp> */
55     GETFIELDCOPY(Prefix,'\n');                          /* <Prefix> */
56
57     sscanf(Nbr, "%u", &current);
58     if (FilterList || ListIt)
59         current = 0;    /* ignore if -l or if filters are present */
60     if(current && current <= applied) {
61         if(Verbose > 0)
62             fprintf(stderr,"Delta number %u is already applied; ignoring.\n",
63                     current);
64         return Exit_Version;
65     }
66
67     for(;;) {
68         Delete(md5);
69         Delete(name);
70         Delete(trash);
71         cnt = -1;
72         /* if a filter list is defined we assume that all pathnames require
73            an action opposite to that requested by the first filter in the
74            list.
75            If no filter is defined, all pathnames are assumed to match. */
76         match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE);
77
78         GETFIELD(p,' ');                        /* CTM_something */
79
80         if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') {
81             Fatal("Expected CTM keyword.");
82             fprintf(stderr,"Got [%s]\n",p);
83             return 1;
84         }
85
86         if(!strcmp(p+3,"_END"))
87             break;
88
89         for(sp=Syntax;sp->Key;sp++)
90             if(!strcmp(p+3,sp->Key))
91                 goto found;
92         Fatal("Expected CTM keyword.");
93         fprintf(stderr,"Got [%s]\n",p);
94         return 1;
95     found:
96         if(Verbose > 5)
97             fprintf(stderr,"%s ",sp->Key);
98         for(i=0;(j = sp->List[i]);i++) {
99             if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
100                 sep = ' ';
101             else
102                 sep = '\n';
103
104             if(Verbose > 5)
105                 fprintf(stderr," %x(%d)",sp->List[i],sep);
106
107             switch (j & CTM_F_MASK) {
108                 case CTM_F_Name: /* XXX check for garbage and .. */
109                     GETFIELDCOPY(name,sep);
110                     j = strlen(name);
111                     if(name[j-1] == '/' && !slashwarn)  {
112                         fprintf(stderr,"Warning: contains trailing slash\n");
113                         slashwarn++;
114                     }
115                     if (name[0] == '/') {
116                         Fatal("Absolute paths are illegal.");
117                         return Exit_Mess;
118                     }
119                     q = name;
120                     for (;;) {
121                         if (q[0] == '.' && q[1] == '.')
122                             if (q[2] == '/' || q[2] == '\0') {
123                                 Fatal("Paths containing '..' are illegal.");
124                                 return Exit_Mess;
125                             }
126                         if ((q = strchr(q, '/')) == NULL)
127                             break;
128                         q++;
129                     }
130
131                     /* if we have been asked to `keep' files then skip
132                        removes; i.e. we don't match these entries at
133                        all. */
134                     if (KeepIt &&
135                         (!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"FR"))) {
136                         match = CTM_FILTER_DISABLE;
137                         break;
138                     }
139
140                     /* If filter expression have been defined, match the
141                        path name against the expression list.  */
142                     
143                     if (FilterList) {
144                         struct CTM_Filter *filter;
145
146                         for (filter = FilterList; filter; 
147                              filter = filter->Next) {
148                                 if (0 == regexec(&filter->CompiledRegex, name,
149                                         0, 0, 0))
150                                         /* if the name matches, adopt the 
151                                            action */
152                                         match = filter->Action;
153                         }
154                     }
155
156                     /* Add up the total number of matches */
157                     total_matches += match;
158                     break;
159                 case CTM_F_Uid:
160                     GETFIELD(p,sep);
161                     while(*p) {
162                         if(!isdigit(*p)) {
163                             Fatal("Non-digit in uid.");
164                             return 32;
165                         }
166                         p++;
167                     }
168                     break;
169                 case CTM_F_Gid:
170                     GETFIELD(p,sep);
171                     while(*p) {
172                         if(!isdigit(*p)) {
173                             Fatal("Non-digit in gid.");
174                             return 32;
175                         }
176                         p++;
177                     }
178                     break;
179                 case CTM_F_Mode:
180                     GETFIELD(p,sep);
181                     while(*p) {
182                         if(!isdigit(*p)) {
183                             Fatal("Non-digit in mode.");
184                             return 32;
185                         }
186                         p++;
187                     }
188                     break;
189                 case CTM_F_MD5:
190                     if(j & CTM_Q_MD5_Chunk) {
191                         GETFIELDCOPY(md5,sep);  /* XXX check for garbage */
192                     } else if(j & CTM_Q_MD5_Before) {
193                         GETFIELD(p,sep);  /* XXX check for garbage */
194                     } else if(j & CTM_Q_MD5_After) {
195                         GETFIELD(p,sep);  /* XXX check for garbage */
196                     } else {
197                         fprintf(stderr,"List = 0x%x\n",j);
198                         Fatal("Unqualified MD5.");
199                         return 32;
200                     }
201                     break;
202                 case CTM_F_Count:
203                     GETBYTECNT(cnt,sep);
204                     break;
205                 case CTM_F_Bytes:
206                     if(cnt < 0) WRONG
207                     GETDATA(trash,cnt);
208                     p = MD5Data(trash,cnt,md5_1);
209                     if(md5 && strcmp(md5,p)) {
210                         Fatal("Internal MD5 failed.");
211                         return Exit_Garbage;
212                 default:
213                         fprintf(stderr,"List = 0x%x\n",j);
214                         Fatal("List had garbage.");
215                         return Exit_Garbage;
216                     }
217             }
218         }
219         if(Verbose > 5)
220             putc('\n',stderr);
221         if(ListIt && match)
222             printf("> %s %s\n", sp->Key, name);
223     }
224
225     Delete(md5);
226     Delete(name);
227     Delete(trash);
228
229     q = MD5End (&ctx,md5_1);
230     if(Verbose > 2)
231         printf("Expecting Global MD5 <%s>\n",q);
232     GETFIELD(p,'\n');                   /* <MD5> */
233     if(Verbose > 2)
234         printf("Reference Global MD5 <%s>\n",p);
235     if(strcmp(q,p)) {
236         Fatal("MD5 sum doesn't match.");
237         fprintf(stderr,"\tI have:<%s>\n",q);
238         fprintf(stderr,"\tShould have been:<%s>\n",p);
239         return Exit_Garbage;
240     }
241     if (-1 != getc(fd)) {
242         if(!Force) {
243             Fatal("Trailing junk in CTM-file.  Can Force with -F.");
244             return 16;
245         }
246     }
247     if ((Verbose > 1) && (0 == total_matches))
248         printf("No matches in \"%s\"\n", FileName);
249     return (total_matches ? Exit_OK : Exit_NoMatch);
250 }