예제 #1
0
파일: rsgtutil.c 프로젝트: ebroder/rsyslog
/* VERIFY Function using KSI API
 * We handle both verify and extend with the same function as they
 * are very similiar.
 *
 * note: here we need to have the LOG file name, not signature!
 */
static int
verifyKSI(char *name, char *errbuf, char *sigfname, char *oldsigfname, char *nsigfname, FILE *logfp, FILE *sigfp, FILE *nsigfp)
{
    block_sig_t *bs = NULL;
    block_hdr_t *bh = NULL;
    ksifile ksi;
    uint8_t bHasRecHashes, bHasIntermedHashes;
    uint8_t bInBlock;
    int r = 0;
    int bInitDone = 0;
    ksierrctx_t ectx;
    rsksi_errctxInit(&ectx);

    rsksiInit("rsyslog rsksiutil " VERSION);
    bInitDone = 1;
    ectx.verbose = verbose;
    ectx.fp = stderr;
    ectx.filename = strdup(sigfname);

    if((r = rsksi_chkFileHdr(sigfp, "LOGSIG11")) != 0) {
        if (debug)
            fprintf(stderr, "error %d in rsksi_chkFileHdr\n", r);
        goto done;
    }
    if(mode == MD_EXTEND) {
        if(fwrite("LOGSIG11", 8, 1, nsigfp) != 1) {
            perror(nsigfname);
            r = RSGTE_IO;
            goto done;
        }
    }
    ksi = rsksi_vrfyConstruct_gf();
    if(ksi == NULL) {
        fprintf(stderr, "error initializing signature file structure\n");
        goto done;
    }

    bInBlock = 0;
    ectx.blkNum = 0;
    ectx.recNumInFile = 0;

    while(!feof(logfp)) {
        if(bInBlock == 0) {
            if(bs != NULL)
                rsksi_objfree(0x0904, bs);
            if (bh != NULL)
                rsksi_objfree(0x0901, bh);
            if((r = rsksi_getBlockParams(sigfp, 1, &bs, &bh, &bHasRecHashes,
                                         &bHasIntermedHashes)) != 0) {
                if(ectx.blkNum == 0) {
                    fprintf(stderr, "Error %d before finding any signature block - "
                            "is the file still open and being written to?\n", r);
                } else {
                    if(verbose)
                        fprintf(stderr, "EOF after signature block %lld\n",
                                (long long unsigned) ectx.blkNum);
                }
                goto done;
            }
            /* Copy block header */
            if ((r = verifyBLOCK_HDRKSI(sigfp, nsigfp)) != 0) goto done;

            rsksi_vrfyBlkInit(ksi, bh, bHasRecHashes, bHasIntermedHashes);
            ectx.recNum = 0;
            ++ectx.blkNum;
        }
        ++ectx.recNum, ++ectx.recNumInFile;
        if((r = doVerifyRecKSI(logfp, sigfp, nsigfp, /*bs,*/ ksi, &ectx, bInBlock)) != 0)
            goto done;
        if(ectx.recNum == bs->recCount) {
            if((r = verifyBLOCK_SIGKSI(bs, ksi, sigfp, nsigfp,
                                       (mode == MD_EXTEND) ? 1 : 0, &ectx)) != 0)
                goto done;
            bInBlock = 0;
        } else	bInBlock = 1;
    }
done:
    if(r != RSGTE_EOF)
        goto err;

    /* Make sure we've reached the end of file in both log and signature file */
    if (fgetc(logfp) != EOF) {
        fprintf(stderr, "There are unsigned records in the end of log.\n");
        fprintf(stderr, "Last signed record: %s\n", ectx.errRec);
        r = RSGTE_END_OF_SIG;
        goto err;
    }
    if (fgetc(sigfp) != EOF) {
        fprintf(stderr, "There are records missing from the end of the log file.\n");
        r = RSGTE_END_OF_LOG;
        goto err;
    }


    fclose(logfp);
    logfp = NULL;
    fclose(sigfp);
    sigfp = NULL;
    if(nsigfp != NULL) {
        fclose(nsigfp);
        nsigfp = NULL;
    }

    /* everything went fine, so we rename files if we updated them */
    if(mode == MD_EXTEND) {
        if(unlink(oldsigfname) != 0) {
            if(errno != ENOENT) {
                perror("unlink oldsig");
                r = RSGTE_IO;
                goto err;
            }
        }
        if(link(sigfname, oldsigfname) != 0) {
            perror("link oldsig");
            r = RSGTE_IO;
            goto err;
        }
        if(unlink(sigfname) != 0) {
            perror("unlink cursig");
            r = RSGTE_IO;
            goto err;
        }
        if(link(nsigfname, sigfname) != 0) {
            perror("link  newsig");
            fprintf(stderr, "WARNING: current sig file has been "
                    "renamed to %s - you need to manually recover "
                    "it.\n", oldsigfname);
            r = RSGTE_IO;
            goto err;
        }
        if(unlink(nsigfname) != 0) {
            perror("unlink newsig");
            fprintf(stderr, "WARNING: current sig file has been "
                    "renamed to %s - you need to manually recover "
                    "it.\n", oldsigfname);
            r = RSGTE_IO;
            goto err;
        }
    }
    /* OLDCODE rsksiExit();*/
    rsksi_errctxExit(&ectx);
    return 1;

err:
    if(r != 0)
        sprintf(errbuf, "error %d (%s) processing file %s\n",
                r, RSKSIE2String(r), name);
    else
        errbuf[0] = '\0';
    if(logfp != NULL)
        fclose(logfp);
    if(sigfp != NULL)
        fclose(sigfp);
    if(nsigfp != NULL) {
        fclose(nsigfp);
        unlink(nsigfname);
    }
    if(bInitDone) {
        /* OLDCODE rsksiExit();*/
        rsksi_errctxExit(&ectx);
    }
    return 0;
}
예제 #2
0
파일: rsgtutil.c 프로젝트: manu844/rsyslog
/* VERIFY Function using KSI API 
 * We handle both verify and extend with the same function as they
 * are very similiar.
 *
 * note: here we need to have the LOG file name, not signature!
 */
static int
verifyKSI(char *name, char *errbuf, char *sigfname, char *oldsigfname, char *nsigfname, FILE *logfp, FILE *sigfp, FILE *nsigfp)
{
	int FILEMODE = FILEMODE_LOGSIG; /* Default FileMode */ 
	block_sig_t *bs = NULL;
	block_hdr_t *bh = NULL;
	ksifile ksi = NULL;
	uint8_t bHasRecHashes, bHasIntermedHashes;
	uint8_t bInBlock;
	int r = 0;
	int bInitDone = 0;
	tlvrecord_t tlvrec; 
	ksierrctx_t ectx;

	/* Helpers for extract verify */
	int iCurrentLine = 0; 
	int iMaxLine = 0; 
	char* lineRec = NULL; 
	size_t stlen = 0;
	ssize_t ssread;

	/* Init KSI related variables */
	rsksi_errctxInit(&ectx);
	rsksiInit("rsyslog rsksiutil " VERSION);
	bInitDone = 1;
	ectx.verbose = verbose;
	ectx.fp = stderr;
	ectx.filename = strdup(sigfname);
	ksi = rsksi_vrfyConstruct_gf();
	if(ksi == NULL) {
		fprintf(stderr, "verifyKSI:\t\t\t Error initializing signature file structure\n");
		goto done;
	}

	/* Check if we have a logsignature file */
	if((r = rsksi_chkFileHdr(sigfp, "LOGSIG11", 0)) == 0) {
		/* Verify Log signature */
		if(debug) printf("debug: verifyKSI:\t\t\t Found log signature file ... \n");
		if(mode == MD_EXTEND) {
			if(fwrite("LOGSIG11", 8, 1, nsigfp) != 1) {
				perror(nsigfname);
				r = RSGTE_IO;
				goto done;
			}
		}

		bInBlock = 0;
		ectx.blkNum = 0;
		ectx.recNumInFile = 0;

		while(!feof(logfp)) {
			if(bInBlock == 0) {
				if (bs != NULL) rsksi_objfree(0x0904, bs);
				if (bh != NULL) rsksi_objfree(0x0901, bh);
				if((r = rsksi_getBlockParams(ksi, sigfp, 1, &bs, &bh, &bHasRecHashes,
								&bHasIntermedHashes)) != 0) {
					if(ectx.blkNum == 0) {
						fprintf(stderr, "verifyKSI:\t\t\t Error %d before finding any signature block - is the file still open and being written to?\n", r);
					} else {
						if(verbose) fprintf(stderr, "verifyKSI:\t\t\t EOF after signature block %lld\n", (long long unsigned) ectx.blkNum);
					}
					goto done;
				}
				/* Copy block header */
				if ((r = verifyBLOCK_HDRKSI(ksi, sigfp, nsigfp, &tlvrec)) != 0) goto done;

				rsksi_vrfyBlkInit(ksi, bh, bHasRecHashes, bHasIntermedHashes);
				ectx.recNum = 0;
				++ectx.blkNum;
			}
			++ectx.recNum, ++ectx.recNumInFile;
			if((r = doVerifyRecKSI(logfp, sigfp, nsigfp, ksi, &ectx, bInBlock)) != 0)
				goto done;
			if(ectx.recNum == bs->recCount) {
				/* And Verify Block signature */
				if((r = verifyBLOCK_SIGKSI(bs, ksi, sigfp, nsigfp, (mode == MD_EXTEND) ? 1 : 0, NULL, &ectx)) != 0)
					goto done;
				bInBlock = 0;
			} else	bInBlock = 1;
		}
	} else if((r = rsksi_chkFileHdr(sigfp, "RECSIG11", verbose)) == 0) {
		/* Verify Log Excerpts */
		if(debug) printf("verifyKSI:\t\t\t Found record integrity proof file ... \n");
		FILEMODE = FILEMODE_RECSIG; 

		ectx.blkNum = 0;
		ectx.recNumInFile = 0;

		while(	!feof(logfp) && 
				!feof(sigfp)) {
			/* Free memory */
			if (bs != NULL) rsksi_objfree(0x0905, bs);
			if (bh != NULL) rsksi_objfree(0x0901, bh);

			/* Get/Verify Block Paramaters */
			if((r = rsksi_getExcerptBlockParams(ksi, sigfp, 1, &bs, &bh)) != 0) {
				if(ectx.blkNum == 0) {
					fprintf(stderr, "verifyKSI:\t\t\t Error %d before finding any signature block\n", r);
				} else {
					if(verbose) fprintf(stderr, "verifyKSI:\t\t\t EOF after signature block %lld\n", (long long unsigned) ectx.blkNum);
				}
				goto done;
			}
			ectx.recNum = 0;
			++ectx.blkNum;
// NEEDED ???			++ectx.recNum, ++ectx.recNumInFile;

			/* Verify if records were found */
			if (bs->recCount <= 0) {
				r = RSGTE_INVLD_RECCNT; 
				if(verbose) fprintf(stderr, "verifyKSI:\t\t\t Either signature block or hash chains are missing.\n");
				goto done;
			}

			/* Init Minimal KSI Helper */
			rsksi_vrfyBlkInit(ksi, bh, 1, 0);

			if(debug) printf("debug: verifyKSI:\t\t\t Verifying %lld hashchains ... \n", (long long unsigned) bs->recCount);

			/* Set new MAXLINE */
			iMaxLine = iCurrentLine + bs->recCount; 

			do
			{
if (debug) printf("debug: verifyKSI:\t\t\t NEXT IN LOOP .\n"); 
				/* Free memory from last lineRec first*/
				if (lineRec != NULL) {
					free(lineRec);
					lineRec = NULL; 
				}

				/* Get next line from file! */
				ssread = getline(&lineRec, &stlen, logfp); 
				if (ssread != -1) {
					iCurrentLine++; /* Increment Current Line */

					/* Remove Linefeed for verification */
					if( *(lineRec+ssread-1) == '\n') {
						*(lineRec+ssread-1) = '\0';
						--ssread;
						rsksi_errctxSetErrRec(&ectx, lineRec);
					}
				} else {
					/* END of file reached */
					if (debug) printf("debug: verifyKSI:\t\t\t End of file reached.\n"); 
					r = RSGTE_EOF;
					break; 
				}

				/* we need to preserve the first line (record) of each block for error-reporting purposes */
				rsksi_errctxFrstRecInBlk(&ectx, lineRec);
				if (debug) printf("debug: verifyKSI:\t\t\t Processing line '%d': %.64s... \n", iCurrentLine, lineRec); 

				/* Verify logline record against hash chain */
				if ((r = rsksi_vrfy_nextHashChain(ksi, bs, sigfp, (unsigned char*)lineRec, ssread, &ectx)) != RSGTE_SUCCESS) {
					fprintf(stderr, "verifyKSI:\t\t\t error %d while verifiying hash chain record for logline (%d): '%.64s...'\n", r, iCurrentLine, lineRec);
					goto done;
				}
			} while (iCurrentLine > iMaxLine && r != RSGTE_EOF); 
if (debug) printf("debug: verifyKSI:\t\t\t DONE with LOOP iCurrentLine=%d > iMaxLine=%d r=%d\n", iCurrentLine, iMaxLine, r); 
		}
	} else {
		fprintf(stderr, "verifyKSI:\t\t\t Error %d invalid file header found \n", r); 
	}
done:
	/* Free mem first */
	if (lineRec != NULL) {
		free(lineRec);
		lineRec = NULL; 
	}

	if(r != RSGTE_EOF)
		goto err;

	/* Make sure we've reached the end of file in both log and signature file */
	if (fgetc(logfp) != EOF) {
		fprintf(stderr, "There are unsigned records in the end of log.\n");
		fprintf(stderr, "Last signed record: %s\n", ectx.errRec);
		r = RSGTE_END_OF_SIG;
		goto err;
	}
	if (fgetc(sigfp) != EOF) {
		fprintf(stderr, "There are records missing from the end of the log file.\n");
		r = RSGTE_END_OF_LOG;
		goto err;
	}

	/* Close File handles */
	fclose(logfp); logfp = NULL;
	fclose(sigfp); sigfp = NULL;
	if(nsigfp != NULL) { fclose(nsigfp); nsigfp = NULL; }

	/* Check for Extend in LogSig Mode: Everything went fine, so we rename files if we updated them */
	if(FILEMODE == FILEMODE_LOGSIG && mode == MD_EXTEND) {
		if(unlink(oldsigfname) != 0) {
			if(errno != ENOENT) {
				perror("unlink oldsig");
				r = RSGTE_IO;
				goto err;
			}
		}
		if(link(sigfname, oldsigfname) != 0) {
			perror("link oldsig");
			r = RSGTE_IO;
			goto err;
		}
		if(unlink(sigfname) != 0) {
			perror("unlink cursig");
			r = RSGTE_IO;
			goto err;
		}
		if(link(nsigfname, sigfname) != 0) {
			perror("link  newsig");
			fprintf(stderr, "WARNING: current sig file has been "
			        "renamed to %s - you need to manually recover "
				"it.\n", oldsigfname);
			r = RSGTE_IO;
			goto err;
		}
		if(unlink(nsigfname) != 0) {
			perror("unlink newsig");
			fprintf(stderr, "WARNING: current sig file has been "
			        "renamed to %s - you need to manually recover "
				"it.\n", oldsigfname);
			r = RSGTE_IO;
			goto err;
		}
	}

	rsksi_errctxExit(&ectx);
	return 1;
err:
	if(r != 0)
		sprintf(errbuf, "error %d (%s) processing file %s\n", r, RSKSIE2String(r), name);
	else
		errbuf[0] = '\0';
	/* Close File handles */
	if(logfp != NULL) fclose(logfp);
	if(sigfp != NULL) fclose(sigfp);
	if(nsigfp != NULL) { fclose(nsigfp); unlink(nsigfname); }

	if(bInitDone) { rsksi_errctxExit(&ectx); }
	return 0; 
}