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 20int 21Pass1(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", ¤t); 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} 251