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 32
152886Sphk
162886Sphk/*---------------------------------------------------------------------------*/
174816Sphk/* Pass2 -- Validate the incoming CTM-file.
182886Sphk */
192886Sphk
202886Sphkint
212886SphkPass2(FILE *fd)
222886Sphk{
232926Sphk    u_char *p,*q,*md5=0;
242886Sphk    MD5_CTX ctx;
2576300Skris    int i,j,sep,cnt,fdesc;
262886Sphk    u_char *trash=0,*name=0;
272886Sphk    struct CTM_Syntax *sp;
282886Sphk    struct stat st;
292926Sphk    int ret = 0;
3017946Sphk    int match = 0;
319491Sphk    char md5_1[33];
3217946Sphk    struct CTM_Filter *filter;
3317946Sphk    FILE *ed = NULL;
3476300Skris    static char *template = NULL;
352886Sphk
368857Srgrimes    if(Verbose>3)
372886Sphk	printf("Pass2 -- Checking if CTM-patch will apply\n");
382886Sphk    MD5Init (&ctx);
392886Sphk
402886Sphk    GETFIELD(p,' '); if(strcmp("CTM_BEGIN",p)) WRONG
412886Sphk    GETFIELD(p,' '); if(strcmp(Version,p)) WRONG
422886Sphk    GETFIELD(p,' '); if(strcmp(Name,p)) WRONG
432886Sphk    /* XXX Lookup name in /etc/ctm,conf, read stuff */
442886Sphk    GETFIELD(p,' '); if(strcmp(Nbr,p)) WRONG
452886Sphk    /* XXX Verify that this is the next patch to apply */
462886Sphk    GETFIELD(p,' '); if(strcmp(TimeStamp,p)) WRONG
472886Sphk    GETFIELD(p,'\n'); if(strcmp(Prefix,p)) WRONG
482886Sphk    /* XXX drop or use ? */
492886Sphk
502886Sphk    for(;;) {
5113917Sphk	Delete(trash);
5213917Sphk	Delete(name);
5313917Sphk	Delete(md5);
542886Sphk	cnt = -1;
552886Sphk
5617946Sphk	/* if a filter list was specified, check file name against
5717946Sphk	   the filters specified
5817946Sphk	   if no filter was given operate on all files. */
5917946Sphk	match = (FilterList ?
6017946Sphk		    !(FilterList->Action) : CTM_FILTER_ENABLE);
6117946Sphk
622886Sphk	GETFIELD(p,' ');
632886Sphk
642886Sphk	if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG
652886Sphk
662886Sphk	if(!strcmp(p+3,"_END"))
672886Sphk	    break;
682886Sphk
692886Sphk	for(sp=Syntax;sp->Key;sp++)
702886Sphk	    if(!strcmp(p+3,sp->Key))
712886Sphk		goto found;
722886Sphk	WRONG
732886Sphk    found:
742886Sphk	for(i=0;(j = sp->List[i]);i++) {
752886Sphk	    if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
762886Sphk		sep = ' ';
772886Sphk	    else
782886Sphk		sep = '\n';
792886Sphk
802886Sphk	    switch (j & CTM_F_MASK) {
812886Sphk		case CTM_F_Name:
8213917Sphk		    GETNAMECOPY(name,sep,j,0);
8317946Sphk		    /* If `keep' was specified, we won't remove any files,
8417946Sphk		       so don't check if the file exists */
8517946Sphk		    if (KeepIt &&
8617946Sphk			(!strcmp(sp->Key,"FR") || !strcmp(sp->Key,"DR"))) {
8717946Sphk			match = CTM_FILTER_DISABLE;
8817946Sphk			break;
8917946Sphk		    }
9017946Sphk
9117946Sphk		    for (filter = FilterList; filter; filter = filter->Next)				if (0 == regexec(&filter->CompiledRegex, name,
9217946Sphk				    0, 0, 0)) {
9317946Sphk				    match = filter->Action;
9417946Sphk			    }
9517946Sphk
9617946Sphk		    if (CTM_FILTER_DISABLE == match)
9717946Sphk			    break;	/* should ignore this file */
9817946Sphk
992886Sphk		    /* XXX Check DR DM rec's for parent-dir */
1002886Sphk		    if(j & CTM_Q_Name_New) {
1012886Sphk			/* XXX Check DR FR rec's for item */
1022886Sphk			if(-1 != stat(name,&st)) {
1032926Sphk			    fprintf(stderr,"  %s: %s exists.\n",
1042926Sphk				sp->Key,name);
1052971Sphk			    ret |= Exit_Forcible;
1062886Sphk			}
1072886Sphk			break;
1082886Sphk		    }
1092886Sphk		    if(-1 == stat(name,&st)) {
1106181Sphk			fprintf(stderr,"  %s: %s doesn't exist.\n",
1112886Sphk			    sp->Key,name);
1126181Sphk		        if (sp->Key[1] == 'R')
1136181Sphk			    ret |= Exit_Forcible;
1146181Sphk			else
1156181Sphk			    ret |= Exit_NotOK;
1162886Sphk			break;
1178857Srgrimes		    }
11815456Sphk		    if (SetTime && getuid() && (getuid() != st.st_uid)) {
11915456Sphk			    fprintf(stderr,
12015456Sphk				"  %s: %s not mine, cannot set time.\n",
12115456Sphk				sp->Key,name);
12215456Sphk			    ret |= Exit_NotOK;
12315456Sphk		    }
1242886Sphk		    if (j & CTM_Q_Name_Dir) {
1252926Sphk			if((st.st_mode & S_IFMT) != S_IFDIR) {
1262886Sphk			    fprintf(stderr,
1272886Sphk				"  %s: %s exist, but isn't dir.\n",
1282886Sphk				sp->Key,name);
1292971Sphk			    ret |= Exit_NotOK;
1302926Sphk			}
1312886Sphk			break;
1328857Srgrimes		    }
1332886Sphk		    if (j & CTM_Q_Name_File) {
1342926Sphk			if((st.st_mode & S_IFMT) != S_IFREG) {
1352886Sphk			    fprintf(stderr,
1362886Sphk				"  %s: %s exist, but isn't file.\n",
1372886Sphk				sp->Key,name);
1382971Sphk			    ret |= Exit_NotOK;
1392926Sphk			}
1402886Sphk			break;
1412886Sphk		    }
1422886Sphk		    break;
1432886Sphk		case CTM_F_Uid:
1442886Sphk		case CTM_F_Gid:
1452886Sphk		case CTM_F_Mode:
1462886Sphk		    GETFIELD(p,sep);
1472886Sphk		    break;
1482886Sphk		case CTM_F_MD5:
1492886Sphk		    if(!name) WRONG
1502926Sphk		    if(j & CTM_Q_MD5_Before) {
15112190Sphk		        char *tmp;
1522926Sphk			GETFIELD(p,sep);
15317946Sphk			if(match && (st.st_mode & S_IFMT) == S_IFREG &&
15412190Sphk			  (tmp = MD5File(name,md5_1)) != NULL &&
15512190Sphk			  strcmp(tmp,p)) {
1562926Sphk			    fprintf(stderr,"  %s: %s md5 mismatch.\n",
1572926Sphk				sp->Key,name);
15856056Sphk			    GETFIELDCOPY(md5,sep);
15956056Sphk			    if(md5 != NULL && strcmp(tmp,md5) == 0) {
16056056Sphk				fprintf(stderr,"  %s: %s already applied.\n",
16156056Sphk					sp->Key,name);
16256056Sphk				match = CTM_FILTER_DISABLE;
16356056Sphk			    } else if(j & CTM_Q_MD5_Force) {
1642971Sphk				if(Force)
1652971Sphk				    fprintf(stderr,"  Can and will force.\n");
1662971Sphk				else
1677159Sroberto				    fprintf(stderr,"  Could have forced.\n");
1682971Sphk				ret |= Exit_Forcible;
1692971Sphk			    } else {
1702971Sphk				ret |= Exit_NotOK;
1712971Sphk			    }
1722886Sphk			}
1732926Sphk			break;
17456056Sphk		    } else if(j & CTM_Q_MD5_After) {
17556056Sphk			if(md5 == NULL) {
17656056Sphk			    GETFIELDCOPY(md5,sep);
17756056Sphk			}
1782926Sphk			break;
1792926Sphk		    }
1802926Sphk		    /* Unqualified MD5 */
1812971Sphk		    WRONG
1822886Sphk		    break;
1832886Sphk		case CTM_F_Count:
1842886Sphk		    GETBYTECNT(cnt,sep);
1852886Sphk		    break;
1862886Sphk		case CTM_F_Bytes:
1872886Sphk		    if(cnt < 0) WRONG
1882886Sphk		    GETDATA(trash,cnt);
18917946Sphk		    if (!match)
19017946Sphk			break;
19176300Skris		    if (!template) {
19276300Skris			if (asprintf(&template, "%s/CTMclientXXXXXX",
19376300Skris				TmpDir) == -1) {
19476300Skris			    fprintf(stderr, "  %s: malloc failed.\n",
19576300Skris				sp->Key);
19676300Skris			    ret |= Exit_Mess;
19776300Skris			    return ret;
19876300Skris		        }
19976300Skris		    }
2002926Sphk		    if(!strcmp(sp->Key,"FN")) {
20176300Skris			if ((p = strdup(template)) == NULL) {
20276300Skris			    fprintf(stderr, "  %s: malloc failed.\n",
20376300Skris				sp->Key);
20476300Skris			    ret |= Exit_Mess;
20576300Skris			    return ret;
20676300Skris			}
20776300Skris			if ((fdesc = mkstemp(p)) == -1) {
20876300Skris			    fprintf(stderr, "  %s: mkstemp failed.\n",
20976300Skris				sp->Key);
21076300Skris			    ret |= Exit_Mess;
21176300Skris			    Free(p);
21276300Skris			    return ret;
21376300Skris			}
21476300Skris			if (close(fdesc) == -1) {
21576300Skris			    fprintf(stderr, "  %s: close failed.\n",
21676300Skris				sp->Key);
21776300Skris			    ret |= Exit_Mess;
21876300Skris			    unlink(p);
21976300Skris			    Free(p);
22076300Skris			    return ret;
22176300Skris			}
2222948Sphk			j = ctm_edit(trash,cnt,name,p);
2232948Sphk			if(j) {
2242948Sphk			    fprintf(stderr,"  %s: %s edit returned %d.\n",
2252948Sphk				sp->Key,name,j);
2262948Sphk			    ret |= j;
22715456Sphk			    unlink(p);
22815456Sphk			    Free(p);
2292948Sphk			    return ret;
2309491Sphk			} else if(strcmp(md5,MD5File(p,md5_1))) {
2312926Sphk			    fprintf(stderr,"  %s: %s edit fails.\n",
2322926Sphk				sp->Key,name);
2332971Sphk			    ret |= Exit_Mess;
23415456Sphk			    unlink(p);
23515456Sphk			    Free(p);
2362948Sphk			    return ret;
2372926Sphk			}
23815456Sphk		        unlink(p);
23913917Sphk			Free(p);
24017946Sphk		    } else if (!strcmp(sp->Key,"FE")) {
24176300Skris			if ((p = strdup(template)) == NULL) {
24276300Skris			    fprintf(stderr, "  %s: malloc failed.\n",
24376300Skris				sp->Key);
24476300Skris			    ret |= Exit_Mess;
24576300Skris			    return ret;
24676300Skris			}
24776300Skris			if ((fdesc = mkstemp(p)) == -1) {
24876300Skris			    fprintf(stderr, "  %s: mkstemp failed.\n",
24976300Skris				sp->Key);
25076300Skris			    ret |= Exit_Mess;
25176300Skris			    Free(p);
25276300Skris			    return ret;
25376300Skris			}
25476300Skris			if (close(fdesc) == -1) {
25576300Skris			    fprintf(stderr, "  %s: close failed.\n",
25676300Skris				sp->Key);
25776300Skris			    ret |= Exit_Mess;
25876300Skris			    unlink(p);
25976300Skris			    Free(p);
26076300Skris			    return ret;
26176300Skris			}
26217946Sphk			ed = popen("ed","w");
26317946Sphk			if (!ed) {
26417946Sphk			    WRONG
26517946Sphk			}
26617946Sphk			fprintf(ed,"e %s\n", name);
26717946Sphk			if (cnt != fwrite(trash,1,cnt,ed)) {
26829526Scharnier			    warn("%s", name);
26917946Sphk			    pclose(ed);
27017946Sphk			    WRONG
27117946Sphk			}
27217946Sphk			fprintf(ed,"w %s\n",p);
27317946Sphk			if (pclose(ed)) {
27429526Scharnier			    warn("%s", p);
27517946Sphk			    WRONG
27617946Sphk			}
27717946Sphk			if(strcmp(md5,MD5File(p,md5_1))) {
27817946Sphk			    fprintf(stderr,"%s %s MD5 didn't come out right\n",
27917946Sphk				sp->Key, name);
28017946Sphk			    WRONG
28117946Sphk			}
28217946Sphk		        unlink(p);
28317946Sphk			Free(p);
2842926Sphk		    }
2858857Srgrimes
2862886Sphk		    break;
2872886Sphk		default: WRONG
2882886Sphk	    }
2892886Sphk        }
2902886Sphk    }
29113917Sphk
29213917Sphk    Delete(trash);
29313917Sphk    Delete(name);
29413917Sphk    Delete(md5);
29513917Sphk
2969491Sphk    q = MD5End (&ctx,md5_1);
2972886Sphk    GETFIELD(p,'\n');			/* <MD5> */
2982886Sphk    if(strcmp(q,p)) WRONG
2992886Sphk    if (-1 != getc(fd)) WRONG
3002926Sphk    return ret;
3012886Sphk}
302