ctm_pass2.c revision 29526
1/*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@login.dknet.dk> 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 * $Id: ctm_pass2.c,v 1.15 1997/02/22 16:05:26 peter Exp $
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;
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
35    if(Verbose>3)
36	printf("Pass2 -- Checking if CTM-patch will apply\n");
37    MD5Init (&ctx);
38
39    GETFIELD(p,' '); if(strcmp("CTM_BEGIN",p)) WRONG
40    GETFIELD(p,' '); if(strcmp(Version,p)) WRONG
41    GETFIELD(p,' '); if(strcmp(Name,p)) WRONG
42    /* XXX Lookup name in /etc/ctm,conf, read stuff */
43    GETFIELD(p,' '); if(strcmp(Nbr,p)) WRONG
44    /* XXX Verify that this is the next patch to apply */
45    GETFIELD(p,' '); if(strcmp(TimeStamp,p)) WRONG
46    GETFIELD(p,'\n'); if(strcmp(Prefix,p)) WRONG
47    /* XXX drop or use ? */
48
49    for(;;) {
50	Delete(trash);
51	Delete(name);
52	Delete(md5);
53	cnt = -1;
54
55	/* if a filter list was specified, check file name against
56	   the filters specified
57	   if no filter was given operate on all files. */
58	match = (FilterList ?
59		    !(FilterList->Action) : CTM_FILTER_ENABLE);
60
61	GETFIELD(p,' ');
62
63	if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG
64
65	if(!strcmp(p+3,"_END"))
66	    break;
67
68	for(sp=Syntax;sp->Key;sp++)
69	    if(!strcmp(p+3,sp->Key))
70		goto found;
71	WRONG
72    found:
73	for(i=0;(j = sp->List[i]);i++) {
74	    if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
75		sep = ' ';
76	    else
77		sep = '\n';
78
79	    switch (j & CTM_F_MASK) {
80		case CTM_F_Name:
81		    GETNAMECOPY(name,sep,j,0);
82		    /* If `keep' was specified, we won't remove any files,
83		       so don't check if the file exists */
84		    if (KeepIt &&
85			(!strcmp(sp->Key,"FR") || !strcmp(sp->Key,"DR"))) {
86			match = CTM_FILTER_DISABLE;
87			break;
88		    }
89
90		    for (filter = FilterList; filter; filter = filter->Next)				if (0 == regexec(&filter->CompiledRegex, name,
91				    0, 0, 0)) {
92				    match = filter->Action;
93			    }
94
95		    if (CTM_FILTER_DISABLE == match)
96			    break;	/* should ignore this file */
97
98		    /* XXX Check DR DM rec's for parent-dir */
99		    if(j & CTM_Q_Name_New) {
100			/* XXX Check DR FR rec's for item */
101			if(-1 != stat(name,&st)) {
102			    fprintf(stderr,"  %s: %s exists.\n",
103				sp->Key,name);
104			    ret |= Exit_Forcible;
105			}
106			break;
107		    }
108		    if(-1 == stat(name,&st)) {
109			fprintf(stderr,"  %s: %s doesn't exist.\n",
110			    sp->Key,name);
111		        if (sp->Key[1] == 'R')
112			    ret |= Exit_Forcible;
113			else
114			    ret |= Exit_NotOK;
115			break;
116		    }
117		    if (SetTime && getuid() && (getuid() != st.st_uid)) {
118			    fprintf(stderr,
119				"  %s: %s not mine, cannot set time.\n",
120				sp->Key,name);
121			    ret |= Exit_NotOK;
122		    }
123		    if (j & CTM_Q_Name_Dir) {
124			if((st.st_mode & S_IFMT) != S_IFDIR) {
125			    fprintf(stderr,
126				"  %s: %s exist, but isn't dir.\n",
127				sp->Key,name);
128			    ret |= Exit_NotOK;
129			}
130			break;
131		    }
132		    if (j & CTM_Q_Name_File) {
133			if((st.st_mode & S_IFMT) != S_IFREG) {
134			    fprintf(stderr,
135				"  %s: %s exist, but isn't file.\n",
136				sp->Key,name);
137			    ret |= Exit_NotOK;
138			}
139			break;
140		    }
141		    break;
142		case CTM_F_Uid:
143		case CTM_F_Gid:
144		case CTM_F_Mode:
145		    GETFIELD(p,sep);
146		    break;
147		case CTM_F_MD5:
148		    if(!name) WRONG
149		    if(j & CTM_Q_MD5_Before) {
150		        char *tmp;
151			GETFIELD(p,sep);
152			if(match && (st.st_mode & S_IFMT) == S_IFREG &&
153			  (tmp = MD5File(name,md5_1)) != NULL &&
154			  strcmp(tmp,p)) {
155			    fprintf(stderr,"  %s: %s md5 mismatch.\n",
156				sp->Key,name);
157			    if(j & CTM_Q_MD5_Force) {
158				if(Force)
159				    fprintf(stderr,"  Can and will force.\n");
160				else
161				    fprintf(stderr,"  Could have forced.\n");
162				ret |= Exit_Forcible;
163			    } else {
164				ret |= Exit_NotOK;
165			    }
166			}
167			break;
168		    }
169		    if(j & CTM_Q_MD5_After) {
170			GETFIELDCOPY(md5,sep);
171			break;
172		    }
173		    /* Unqualified MD5 */
174		    WRONG
175		    break;
176		case CTM_F_Count:
177		    GETBYTECNT(cnt,sep);
178		    break;
179		case CTM_F_Bytes:
180		    if(cnt < 0) WRONG
181		    GETDATA(trash,cnt);
182		    if (!match)
183			break;
184		    if(!strcmp(sp->Key,"FN")) {
185			p = tempnam(TmpDir,"CTMclient");
186			j = ctm_edit(trash,cnt,name,p);
187			if(j) {
188			    fprintf(stderr,"  %s: %s edit returned %d.\n",
189				sp->Key,name,j);
190			    ret |= j;
191			    unlink(p);
192			    Free(p);
193			    return ret;
194			} else if(strcmp(md5,MD5File(p,md5_1))) {
195			    fprintf(stderr,"  %s: %s edit fails.\n",
196				sp->Key,name);
197			    ret |= Exit_Mess;
198			    unlink(p);
199			    Free(p);
200			    return ret;
201			}
202		        unlink(p);
203			Free(p);
204		    } else if (!strcmp(sp->Key,"FE")) {
205			p = tempnam(TmpDir,"CTMclient");
206			ed = popen("ed","w");
207			if (!ed) {
208			    WRONG
209			}
210			fprintf(ed,"e %s\n", name);
211			if (cnt != fwrite(trash,1,cnt,ed)) {
212			    warn("%s", name);
213			    pclose(ed);
214			    WRONG
215			}
216			fprintf(ed,"w %s\n",p);
217			if (pclose(ed)) {
218			    warn("%s", p);
219			    WRONG
220			}
221			if(strcmp(md5,MD5File(p,md5_1))) {
222			    fprintf(stderr,"%s %s MD5 didn't come out right\n",
223				sp->Key, name);
224			    WRONG
225			}
226		        unlink(p);
227			Free(p);
228		    }
229
230		    break;
231		default: WRONG
232	    }
233        }
234    }
235
236    Delete(trash);
237    Delete(name);
238    Delete(md5);
239
240    q = MD5End (&ctx,md5_1);
241    GETFIELD(p,'\n');			/* <MD5> */
242    if(strcmp(q,p)) WRONG
243    if (-1 != getc(fd)) WRONG
244    return ret;
245}
246