12926Sphk/* 22926Sphk * ---------------------------------------------------------------------------- 32926Sphk * "THE BEER-WARE LICENSE" (Revision 42): 493150Sphk * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 52926Sphk * can do whatever you want with this stuff. If we meet some day, and you think 62926Sphk * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 72926Sphk * ---------------------------------------------------------------------------- 82926Sphk * 950479Speter * $FreeBSD$ 102926Sphk * 112926Sphk */ 122926Sphk 132886Sphk#include "ctm.h" 142926Sphk#define BADREAD 1 152886Sphk 162886Sphk/*---------------------------------------------------------------------------*/ 174816Sphk/* Pass1 -- Validate the incoming CTM-file. 182886Sphk */ 192886Sphk 202886Sphkint 216889SphkPass1(FILE *fd, unsigned applied) 222886Sphk{ 232886Sphk u_char *p,*q; 242886Sphk MD5_CTX ctx; 252886Sphk int i,j,sep,cnt; 2617946Sphk u_char *md5=0,*name=0,*trash=0; 272886Sphk struct CTM_Syntax *sp; 2817946Sphk int slashwarn=0, match=0, total_matches=0; 296889Sphk unsigned current; 309491Sphk char md5_1[33]; 318857Srgrimes 328857Srgrimes if(Verbose>3) 334816Sphk printf("Pass1 -- Checking integrity of incoming CTM-patch\n"); 342886Sphk MD5Init (&ctx); 352886Sphk 362886Sphk GETFIELD(p,' '); /* CTM_BEGIN */ 372886Sphk if(strcmp(p,"CTM_BEGIN")) { 382886Sphk Fatal("Probably not a CTM-patch at all."); 398857Srgrimes if(Verbose>3) 402886Sphk fprintf(stderr,"Expected \"CTM_BEGIN\" got \"%s\".\n",p); 412886Sphk return 1; 422886Sphk } 432886Sphk 442886Sphk GETFIELDCOPY(Version,' '); /* <Version> */ 452886Sphk if(strcmp(Version,VERSION)) { 462886Sphk Fatal("CTM-patch is wrong version."); 478857Srgrimes if(Verbose>3) 482886Sphk fprintf(stderr,"Expected \"%s\" got \"%s\".\n",VERSION,p); 492886Sphk return 1; 502886Sphk } 512886Sphk 522886Sphk GETFIELDCOPY(Name,' '); /* <Name> */ 532886Sphk GETFIELDCOPY(Nbr,' '); /* <Nbr> */ 542886Sphk GETFIELDCOPY(TimeStamp,' '); /* <TimeStamp> */ 552886Sphk GETFIELDCOPY(Prefix,'\n'); /* <Prefix> */ 562886Sphk 576889Sphk sscanf(Nbr, "%u", ¤t); 5817946Sphk if (FilterList || ListIt) 5917946Sphk current = 0; /* ignore if -l or if filters are present */ 607395Sphk if(current && current <= applied) { 6117946Sphk if(Verbose > 0) 626889Sphk fprintf(stderr,"Delta number %u is already applied; ignoring.\n", 636889Sphk current); 646889Sphk return Exit_Version; 656889Sphk } 668857Srgrimes 672886Sphk for(;;) { 6813917Sphk Delete(md5); 6917946Sphk Delete(name); 7013917Sphk Delete(trash); 712886Sphk cnt = -1; 7217946Sphk /* if a filter list is defined we assume that all pathnames require 7317946Sphk an action opposite to that requested by the first filter in the 7417946Sphk list. 7517946Sphk If no filter is defined, all pathnames are assumed to match. */ 7617946Sphk match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE); 772886Sphk 782886Sphk GETFIELD(p,' '); /* CTM_something */ 792886Sphk 802886Sphk if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') { 812886Sphk Fatal("Expected CTM keyword."); 822886Sphk fprintf(stderr,"Got [%s]\n",p); 832886Sphk return 1; 842886Sphk } 852886Sphk 862886Sphk if(!strcmp(p+3,"_END")) 872886Sphk break; 882886Sphk 892886Sphk for(sp=Syntax;sp->Key;sp++) 902886Sphk if(!strcmp(p+3,sp->Key)) 912886Sphk goto found; 922886Sphk Fatal("Expected CTM keyword."); 932886Sphk fprintf(stderr,"Got [%s]\n",p); 942886Sphk return 1; 952886Sphk found: 962886Sphk if(Verbose > 5) 972886Sphk fprintf(stderr,"%s ",sp->Key); 982886Sphk for(i=0;(j = sp->List[i]);i++) { 992886Sphk if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes) 1002886Sphk sep = ' '; 1012886Sphk else 1022886Sphk sep = '\n'; 1032886Sphk 10417946Sphk if(Verbose > 5) 10517946Sphk fprintf(stderr," %x(%d)",sp->List[i],sep); 10617946Sphk 1072886Sphk switch (j & CTM_F_MASK) { 1082886Sphk case CTM_F_Name: /* XXX check for garbage and .. */ 10917946Sphk GETFIELDCOPY(name,sep); 11017946Sphk j = strlen(name); 11117946Sphk if(name[j-1] == '/' && !slashwarn) { 1122948Sphk fprintf(stderr,"Warning: contains trailing slash\n"); 1132948Sphk slashwarn++; 1142948Sphk } 11517946Sphk if (name[0] == '/') { 1166181Sphk Fatal("Absolute paths are illegal."); 1176181Sphk return Exit_Mess; 1186181Sphk } 11917946Sphk q = name; 1206694Sphk for (;;) { 12117946Sphk if (q[0] == '.' && q[1] == '.') 12217946Sphk if (q[2] == '/' || q[2] == '\0') { 1236694Sphk Fatal("Paths containing '..' are illegal."); 1246694Sphk return Exit_Mess; 1256694Sphk } 12617946Sphk if ((q = strchr(q, '/')) == NULL) 1276694Sphk break; 12817946Sphk q++; 1296694Sphk } 13017946Sphk 13117946Sphk /* if we have been asked to `keep' files then skip 13217946Sphk removes; i.e. we don't match these entries at 13317946Sphk all. */ 13417946Sphk if (KeepIt && 13517946Sphk (!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"FR"))) { 13617946Sphk match = CTM_FILTER_DISABLE; 13717946Sphk break; 13817946Sphk } 13917946Sphk 14017946Sphk /* If filter expression have been defined, match the 14117946Sphk path name against the expression list. */ 14217946Sphk 14317946Sphk if (FilterList) { 14417946Sphk struct CTM_Filter *filter; 14517946Sphk 14617946Sphk for (filter = FilterList; filter; 14717946Sphk filter = filter->Next) { 14817946Sphk if (0 == regexec(&filter->CompiledRegex, name, 14917946Sphk 0, 0, 0)) 15017946Sphk /* if the name matches, adopt the 15117946Sphk action */ 15217946Sphk match = filter->Action; 15317946Sphk } 15417946Sphk } 15517946Sphk 15617946Sphk /* Add up the total number of matches */ 15717946Sphk total_matches += match; 1582886Sphk break; 1592948Sphk case CTM_F_Uid: 1602948Sphk GETFIELD(p,sep); 1612948Sphk while(*p) { 1622948Sphk if(!isdigit(*p)) { 1632948Sphk Fatal("Non-digit in uid."); 1642948Sphk return 32; 1652948Sphk } 1662948Sphk p++; 1672948Sphk } 1682948Sphk break; 1692948Sphk case CTM_F_Gid: 1702948Sphk GETFIELD(p,sep); 1712948Sphk while(*p) { 1722948Sphk if(!isdigit(*p)) { 1732948Sphk Fatal("Non-digit in gid."); 1742948Sphk return 32; 1752948Sphk } 1762948Sphk p++; 1772948Sphk } 1782948Sphk break; 1792948Sphk case CTM_F_Mode: 1802948Sphk GETFIELD(p,sep); 1812948Sphk while(*p) { 1822948Sphk if(!isdigit(*p)) { 1832948Sphk Fatal("Non-digit in mode."); 1842948Sphk return 32; 1852948Sphk } 1862948Sphk p++; 1872948Sphk } 1882948Sphk break; 1892886Sphk case CTM_F_MD5: 1902948Sphk if(j & CTM_Q_MD5_Chunk) { 1912886Sphk GETFIELDCOPY(md5,sep); /* XXX check for garbage */ 1922948Sphk } else if(j & CTM_Q_MD5_Before) { 1932886Sphk GETFIELD(p,sep); /* XXX check for garbage */ 1942948Sphk } else if(j & CTM_Q_MD5_After) { 1952948Sphk GETFIELD(p,sep); /* XXX check for garbage */ 1962948Sphk } else { 1972948Sphk fprintf(stderr,"List = 0x%x\n",j); 1982948Sphk Fatal("Unqualified MD5."); 1992948Sphk return 32; 2002948Sphk } 2012886Sphk break; 2022886Sphk case CTM_F_Count: 2032948Sphk GETBYTECNT(cnt,sep); 2042886Sphk break; 2052886Sphk case CTM_F_Bytes: 2062886Sphk if(cnt < 0) WRONG 2072886Sphk GETDATA(trash,cnt); 2089491Sphk p = MD5Data(trash,cnt,md5_1); 2092886Sphk if(md5 && strcmp(md5,p)) { 2102886Sphk Fatal("Internal MD5 failed."); 21117946Sphk return Exit_Garbage; 2122886Sphk default: 2132886Sphk fprintf(stderr,"List = 0x%x\n",j); 2142886Sphk Fatal("List had garbage."); 21517946Sphk return Exit_Garbage; 2162886Sphk } 2172886Sphk } 21817946Sphk } 2192886Sphk if(Verbose > 5) 2202886Sphk putc('\n',stderr); 22117946Sphk if(ListIt && match) 22217946Sphk printf("> %s %s\n", sp->Key, name); 2232886Sphk } 22413917Sphk 22513917Sphk Delete(md5); 22617946Sphk Delete(name); 22713917Sphk Delete(trash); 22813917Sphk 2299491Sphk q = MD5End (&ctx,md5_1); 2302886Sphk if(Verbose > 2) 2312886Sphk printf("Expecting Global MD5 <%s>\n",q); 2322886Sphk GETFIELD(p,'\n'); /* <MD5> */ 2332886Sphk if(Verbose > 2) 2342886Sphk printf("Reference Global MD5 <%s>\n",p); 2352886Sphk if(strcmp(q,p)) { 2362886Sphk Fatal("MD5 sum doesn't match."); 2372886Sphk fprintf(stderr,"\tI have:<%s>\n",q); 2382886Sphk fprintf(stderr,"\tShould have been:<%s>\n",p); 23917946Sphk return Exit_Garbage; 2402886Sphk } 2412886Sphk if (-1 != getc(fd)) { 2422926Sphk if(!Force) { 2432926Sphk Fatal("Trailing junk in CTM-file. Can Force with -F."); 2442926Sphk return 16; 2452926Sphk } 2462886Sphk } 24717946Sphk if ((Verbose > 1) && (0 == total_matches)) 24817946Sphk printf("No matches in \"%s\"\n", FileName); 24917946Sphk return (total_matches ? Exit_OK : Exit_NoMatch); 2502886Sphk} 251