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