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 32 15 16/*---------------------------------------------------------------------------*/ 17/* Pass2 -- Validate the incoming CTM-file. 18 */ 19 20int 21Pass2(FILE *fd) 22{ 23 u_char *p,*q,*md5=0; 24 MD5_CTX ctx; 25 int i,j,sep,cnt,fdesc; 26 u_char *trash=0,*name=0; 27 struct CTM_Syntax *sp; 28 struct stat st; 29 int ret = 0; 30 int match = 0; 31 char md5_1[33]; 32 struct CTM_Filter *filter; 33 FILE *ed = NULL; 34 static char *template = NULL; 35 36 if(Verbose>3) 37 printf("Pass2 -- Checking if CTM-patch will apply\n"); 38 MD5Init (&ctx); 39 40 GETFIELD(p,' '); if(strcmp("CTM_BEGIN",p)) WRONG 41 GETFIELD(p,' '); if(strcmp(Version,p)) WRONG 42 GETFIELD(p,' '); if(strcmp(Name,p)) WRONG 43 /* XXX Lookup name in /etc/ctm,conf, read stuff */ 44 GETFIELD(p,' '); if(strcmp(Nbr,p)) WRONG 45 /* XXX Verify that this is the next patch to apply */ 46 GETFIELD(p,' '); if(strcmp(TimeStamp,p)) WRONG 47 GETFIELD(p,'\n'); if(strcmp(Prefix,p)) WRONG 48 /* XXX drop or use ? */ 49 50 for(;;) { 51 Delete(trash); 52 Delete(name); 53 Delete(md5); 54 cnt = -1; 55 56 /* if a filter list was specified, check file name against 57 the filters specified 58 if no filter was given operate on all files. */ 59 match = (FilterList ? 60 !(FilterList->Action) : CTM_FILTER_ENABLE); 61 62 GETFIELD(p,' '); 63 64 if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG 65 66 if(!strcmp(p+3,"_END")) 67 break; 68 69 for(sp=Syntax;sp->Key;sp++) 70 if(!strcmp(p+3,sp->Key)) 71 goto found; 72 WRONG 73 found: 74 for(i=0;(j = sp->List[i]);i++) { 75 if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes) 76 sep = ' '; 77 else 78 sep = '\n'; 79 80 switch (j & CTM_F_MASK) { 81 case CTM_F_Name: 82 GETNAMECOPY(name,sep,j,0); 83 /* If `keep' was specified, we won't remove any files, 84 so don't check if the file exists */ 85 if (KeepIt && 86 (!strcmp(sp->Key,"FR") || !strcmp(sp->Key,"DR"))) { 87 match = CTM_FILTER_DISABLE; 88 break; 89 } 90 91 for (filter = FilterList; filter; filter = filter->Next) if (0 == regexec(&filter->CompiledRegex, name, 92 0, 0, 0)) { 93 match = filter->Action; 94 } 95 96 if (CTM_FILTER_DISABLE == match) 97 break; /* should ignore this file */ 98 99 /* XXX Check DR DM rec's for parent-dir */ 100 if(j & CTM_Q_Name_New) { 101 /* XXX Check DR FR rec's for item */ 102 if(-1 != stat(name,&st)) { 103 fprintf(stderr," %s: %s exists.\n", 104 sp->Key,name); 105 ret |= Exit_Forcible; 106 } 107 break; 108 } 109 if(-1 == stat(name,&st)) { 110 fprintf(stderr," %s: %s doesn't exist.\n", 111 sp->Key,name); 112 if (sp->Key[1] == 'R') 113 ret |= Exit_Forcible; 114 else 115 ret |= Exit_NotOK; 116 break; 117 } 118 if (SetTime && getuid() && (getuid() != st.st_uid)) { 119 fprintf(stderr, 120 " %s: %s not mine, cannot set time.\n", 121 sp->Key,name); 122 ret |= Exit_NotOK; 123 } 124 if (j & CTM_Q_Name_Dir) { 125 if((st.st_mode & S_IFMT) != S_IFDIR) { 126 fprintf(stderr, 127 " %s: %s exist, but isn't dir.\n", 128 sp->Key,name); 129 ret |= Exit_NotOK; 130 } 131 break; 132 } 133 if (j & CTM_Q_Name_File) { 134 if((st.st_mode & S_IFMT) != S_IFREG) { 135 fprintf(stderr, 136 " %s: %s exist, but isn't file.\n", 137 sp->Key,name); 138 ret |= Exit_NotOK; 139 } 140 break; 141 } 142 break; 143 case CTM_F_Uid: 144 case CTM_F_Gid: 145 case CTM_F_Mode: 146 GETFIELD(p,sep); 147 break; 148 case CTM_F_MD5: 149 if(!name) WRONG 150 if(j & CTM_Q_MD5_Before) { 151 char *tmp; 152 GETFIELD(p,sep); 153 if(match && (st.st_mode & S_IFMT) == S_IFREG && 154 (tmp = MD5File(name,md5_1)) != NULL && 155 strcmp(tmp,p)) { 156 fprintf(stderr," %s: %s md5 mismatch.\n", 157 sp->Key,name); 158 GETFIELDCOPY(md5,sep); 159 if(md5 != NULL && strcmp(tmp,md5) == 0) { 160 fprintf(stderr," %s: %s already applied.\n", 161 sp->Key,name); 162 match = CTM_FILTER_DISABLE; 163 } else if(j & CTM_Q_MD5_Force) { 164 if(Force) 165 fprintf(stderr," Can and will force.\n"); 166 else 167 fprintf(stderr," Could have forced.\n"); 168 ret |= Exit_Forcible; 169 } else { 170 ret |= Exit_NotOK; 171 } 172 } 173 break; 174 } else if(j & CTM_Q_MD5_After) { 175 if(md5 == NULL) { 176 GETFIELDCOPY(md5,sep); 177 } 178 break; 179 } 180 /* Unqualified MD5 */ 181 WRONG 182 break; 183 case CTM_F_Count: 184 GETBYTECNT(cnt,sep); 185 break; 186 case CTM_F_Bytes: 187 if(cnt < 0) WRONG 188 GETDATA(trash,cnt); 189 if (!match) 190 break; 191 if (!template) { 192 if (asprintf(&template, "%s/CTMclientXXXXXX", 193 TmpDir) == -1) { 194 fprintf(stderr, " %s: malloc failed.\n", 195 sp->Key); 196 ret |= Exit_Mess; 197 return ret; 198 } 199 } 200 if(!strcmp(sp->Key,"FN")) { 201 if ((p = strdup(template)) == NULL) { 202 fprintf(stderr, " %s: malloc failed.\n", 203 sp->Key); 204 ret |= Exit_Mess; 205 return ret; 206 } 207 if ((fdesc = mkstemp(p)) == -1) { 208 fprintf(stderr, " %s: mkstemp failed.\n", 209 sp->Key); 210 ret |= Exit_Mess; 211 Free(p); 212 return ret; 213 } 214 if (close(fdesc) == -1) { 215 fprintf(stderr, " %s: close failed.\n", 216 sp->Key); 217 ret |= Exit_Mess; 218 unlink(p); 219 Free(p); 220 return ret; 221 } 222 j = ctm_edit(trash,cnt,name,p); 223 if(j) { 224 fprintf(stderr," %s: %s edit returned %d.\n", 225 sp->Key,name,j); 226 ret |= j; 227 unlink(p); 228 Free(p); 229 return ret; 230 } else if(strcmp(md5,MD5File(p,md5_1))) { 231 fprintf(stderr," %s: %s edit fails.\n", 232 sp->Key,name); 233 ret |= Exit_Mess; 234 unlink(p); 235 Free(p); 236 return ret; 237 } 238 unlink(p); 239 Free(p); 240 } else if (!strcmp(sp->Key,"FE")) { 241 if ((p = strdup(template)) == NULL) { 242 fprintf(stderr, " %s: malloc failed.\n", 243 sp->Key); 244 ret |= Exit_Mess; 245 return ret; 246 } 247 if ((fdesc = mkstemp(p)) == -1) { 248 fprintf(stderr, " %s: mkstemp failed.\n", 249 sp->Key); 250 ret |= Exit_Mess; 251 Free(p); 252 return ret; 253 } 254 if (close(fdesc) == -1) { 255 fprintf(stderr, " %s: close failed.\n", 256 sp->Key); 257 ret |= Exit_Mess; 258 unlink(p); 259 Free(p); 260 return ret; 261 } 262 ed = popen("ed","w"); 263 if (!ed) { 264 WRONG 265 } 266 fprintf(ed,"e %s\n", name); 267 if (cnt != fwrite(trash,1,cnt,ed)) { 268 warn("%s", name); 269 pclose(ed); 270 WRONG 271 } 272 fprintf(ed,"w %s\n",p); 273 if (pclose(ed)) { 274 warn("%s", p); 275 WRONG 276 } 277 if(strcmp(md5,MD5File(p,md5_1))) { 278 fprintf(stderr,"%s %s MD5 didn't come out right\n", 279 sp->Key, name); 280 WRONG 281 } 282 unlink(p); 283 Free(p); 284 } 285 286 break; 287 default: WRONG 288 } 289 } 290 } 291 292 Delete(trash); 293 Delete(name); 294 Delete(md5); 295 296 q = MD5End (&ctx,md5_1); 297 GETFIELD(p,'\n'); /* <MD5> */ 298 if(strcmp(q,p)) WRONG 299 if (-1 != getc(fd)) WRONG 300 return ret; 301} 302