Exemplo n.º 1
0
/* --- Object methods */
static JSBool
rpmdc_Init(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    void * ptr = JS_GetInstancePrivate(cx, obj, &rpmdcClass, NULL);
    rpmdc dc = ptr;
    JSBool ok = JS_FALSE;
    unsigned int _dalgo = PGPHASHALGO_NONE;
    unsigned int _flags = RPMDIGEST_NONE;

_METHOD_DEBUG_ENTRY(_debug);

    if (!(ok = JS_ConvertArguments(cx, argc, argv, "/uu", &_dalgo, &_flags)))
        goto exit;

    if (dc) {
	if (_dalgo == PGPHASHALGO_NONE) _dalgo = rpmDigestAlgo(dc);
	(void) rpmDigestFinal(dc, NULL, NULL, 0);
	(void) JS_SetPrivate(cx, obj, (void *)NULL);
    }
    if (_dalgo == PGPHASHALGO_NONE) _dalgo = _dalgo_default;
    dc = rpmDigestInit(_dalgo, _flags);
    (void) JS_SetPrivate(cx, obj, (void *)dc);

    *rval = JSVAL_TRUE;
    ok = JS_TRUE;
exit:
    return ok;
}
Exemplo n.º 2
0
Arquivo: pack.c Projeto: nforro/rpm
static void *nullDigest(int algo, int ascii)
{
    void *d = NULL;
    DIGEST_CTX ctx = rpmDigestInit(algo, 0);
    rpmDigestFinal(ctx, &d, NULL, ascii);
    return d;
}
Exemplo n.º 3
0
static int hBlobDigest(Header h, pgpDig dig, pgpHashAlgo hash_algo,
		DIGEST_CTX * ctxp)
{
    HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
    rpmop op = NULL;
    unsigned char * hmagic = NULL;
    size_t nmagic = 0;
    int xx;

    he->tag = RPMTAG_HEADERIMMUTABLE;
    xx = headerGet(h, he, 0);
    if (!xx)
	goto exit;
    (void) headerGetMagic(NULL, &hmagic, &nmagic);
    op = (rpmop) pgpStatsAccumulator(dig, 10);	/* RPMTS_OP_DIGEST */
    (void) rpmswEnter(op, 0);
    *ctxp = rpmDigestInit(hash_algo, RPMDIGEST_NONE);
    if (hmagic && nmagic > 0) {
	(void) rpmDigestUpdate(*ctxp, hmagic, nmagic);
	dig->nbytes += nmagic;
    }
    (void) rpmDigestUpdate(*ctxp, he->p.ptr, he->c);
    dig->nbytes += he->c;
    (void) rpmswExit(op, dig->nbytes);
    op->count--;	/* XXX one too many */

exit:
    he->p.ptr = _free(he->p.ptr);
    return xx;
}
Exemplo n.º 4
0
static int makeHDRDigest(Header sigh, const char * file, rpmTagVal sigTag)
{
    Header h = NULL;
    FD_t fd = NULL;
    char * SHA1 = NULL;
    int ret = -1;	/* assume failure. */

    switch (sigTag) {
    case RPMSIGTAG_SHA1:
	fd = Fopen(file, "r.fdio");
	if (fd == NULL || Ferror(fd))
	    goto exit;
	h = headerRead(fd, HEADER_MAGIC_YES);
	if (h == NULL)
	    goto exit;

	if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
	    DIGEST_CTX ctx;
	    struct rpmtd_s utd;
	
	    if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, HEADERGET_DEFAULT)
	     	||  utd.data == NULL)
	    {
		rpmlog(RPMLOG_ERR, 
				_("Immutable header region could not be read. "
				"Corrupted package?\n"));
		goto exit;
	    }
	    ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
	    (void) rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
	    (void) rpmDigestUpdate(ctx, utd.data, utd.count);
	    (void) rpmDigestFinal(ctx, (void **)&SHA1, NULL, 1);
	    rpmtdFreeData(&utd);
	} else {
	    rpmlog(RPMLOG_ERR, _("Cannot sign RPM v3 packages\n"));
	    goto exit;
	}

	if (SHA1 == NULL)
	    goto exit;
	if (!sighdrPut(sigh, RPMSIGTAG_SHA1, RPM_STRING_TYPE, SHA1, 1))
	    goto exit;
	ret = 0;
	break;
    default:
	break;
    }

exit:
    free(SHA1);
    headerFree(h);
    if (fd != NULL) (void) Fclose(fd);
    return ret;
}
Exemplo n.º 5
0
/* --- Object ctors/dtors */
static rpmdc
rpmdc_init(JSContext *cx, JSObject *obj, unsigned int _dalgo,
		unsigned int _flags)
{
    rpmdc dc = (_dalgo > 0 ? rpmDigestInit(_dalgo, _flags) : NULL);

if (_debug)
fprintf(stderr, "==> %s(%p,%p,%u,%u) dc %p\n", __FUNCTION__, cx, obj, _dalgo, _flags, dc);

    if (!JS_SetPrivate(cx, obj, (void *)dc)) {
	/* XXX error msg */
	return NULL;
    }
    return dc;
}
Exemplo n.º 6
0
int rpmDigestBundleAdd(rpmDigestBundle bundle, int algo,
			rpmDigestFlags flags)
{
    DIGEST_CTX ctx = NULL;
    if (bundle && algo > 0 && algo < DIGESTS_MAX) {
	if (bundle->digests[algo] == NULL) {
	    ctx = rpmDigestInit(algo, flags);
	    if (ctx) {
		bundle->digests[algo] = ctx;
		if (algo < bundle->index_min) {
		    bundle->index_min = algo;
		}
		if (algo > bundle->index_max) {
		    bundle->index_max = algo;
		}
	    }
	}
    }
    return (ctx != NULL);
}
Exemplo n.º 7
0
static
void test_gridfile( gridfs *gfs, char *data_before, int64_t length, char *filename, char *content_type )
{
    gridfile gfile[1];
    FILE *stream;
#ifdef	DYING
    mongo_md5_state_t pms[1];
    mongo_md5_byte_t digest[16];
#endif
    char hex_digest[33];
    int64_t i = length;
    int n;
    char *data_after = (char*)bson_malloc( LARGE );
    int truncBytes;
    char* lowerName;

    ASSERT(gridfs_find_filename( gfs, filename, gfile ) == MONGO_OK);
    ASSERT( gridfile_exists( gfile ) );

    stream = fopen( "output", "w+" );
    gridfile_write_file( gfile, stream );
    fseek( stream, 0, SEEK_SET );
    ASSERT( fread( data_after, (size_t)length, sizeof( char ), stream ) );
    fclose( stream );
    ASSERT( memcmp( data_before, data_after, (size_t)length ) == 0 );

    gridfile_read_buffer( gfile, data_after, length );
    ASSERT( memcmp( data_before, data_after, (size_t)length ) == 0 );

    lowerName = (char*) bson_malloc( (int)strlen( filename ) + 1);    
    strcpy( lowerName, filename );
    _strlwr( lowerName );
    
    ASSERT( strcmp( gridfile_get_filename( gfile ), lowerName ) == 0 );
    bson_free( lowerName );

    ASSERT( gridfile_get_contentlength( gfile ) == (size_t)length );

    ASSERT( gridfile_get_chunksize( gfile ) == DEFAULT_CHUNK_SIZE );

    ASSERT( strcmp( gridfile_get_contenttype( gfile ), content_type ) == 0 ) ;

    ASSERT( memcmp( data_before, data_after, (size_t)length ) == 0 );

    if( !( gfile->flags & GRIDFILE_COMPRESS ) ) {
#ifdef	DYING
      mongo_md5_init( pms );

      n = 0;
      while( i > INT_MAX  ) {
          mongo_md5_append( pms, ( const mongo_md5_byte_t * )data_before + ( n * INT_MAX ), INT_MAX );
          i -= INT_MAX;
          n += 1;
      }
      if( i > 0 )
          mongo_md5_append( pms, ( const mongo_md5_byte_t * )data_before + ( n * INT_MAX ), (int)i );

      mongo_md5_finish( pms, digest );
      digest2hex( digest, hex_digest );
#else
      { DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_MD5, RPMDIGEST_NONE);
        const char * _digest = NULL;
        int xx;
        while( i > INT_MAX  ) {
          xx = rpmDigestUpdate(ctx, (char *)data_before + (n*INT_MAX), INT_MAX);
          i -= INT_MAX;
          n += 1;
	}
        xx = rpmDigestFinal(ctx, &_digest, NULL, 1);
        strncpy(hex_digest, _digest, 32+1);
	hex_digest[32] = '\0';
        _digest = _free(_digest);
      }
#endif

      ASSERT( strcmp( gridfile_get_md5( gfile ), hex_digest ) == 0 );
    }

    truncBytes = (int) (length > DEFAULT_CHUNK_SIZE * 4 ? length - DEFAULT_CHUNK_SIZE * 2 - 13 : 23); 
    gridfile_writer_init( gfile, gfs, filename, content_type, GRIDFILE_DEFAULT);
    ASSERT( gridfile_truncate(gfile, (size_t)(length - truncBytes)) == (size_t)(length - truncBytes));
    gridfile_writer_done( gfile );

    gridfile_seek(gfile, 0);
    ASSERT( gridfile_get_contentlength( gfile ) == (size_t)(length - truncBytes) );
    ASSERT( gridfile_read_buffer( gfile, data_after, length ) ==  (size_t)(length - truncBytes));
    ASSERT( memcmp( data_before, data_after, (size_t)(length - truncBytes) ) == 0 );

    gridfile_writer_init( gfile, gfs, filename, content_type, GRIDFILE_DEFAULT);
    gridfile_truncate(gfile, 0);
    gridfile_writer_done( gfile );

    ASSERT( gridfile_get_contentlength( gfile ) == 0 );
    ASSERT( gridfile_read_buffer( gfile, data_after, length ) == 0 );

    gridfile_destroy( gfile );
    ASSERT( gridfs_remove_filename( gfs, filename ) == MONGO_OK );
    free( data_after );
    gridfs_test_unlink( "output" );
}
Exemplo n.º 8
0
static rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags vsflags, 
			FD_t fd,
			Header * hdrp, unsigned int *keyidp, char **msg)
{
    pgpDigParams sig = NULL;
    Header sigh = NULL;
    rpmTagVal sigtag;
    struct rpmtd_s sigtd;
    struct sigtInfo_s sinfo;
    Header h = NULL;
    rpmRC rc = RPMRC_FAIL;	/* assume failure */
    int leadtype = -1;
    headerGetFlags hgeflags = HEADERGET_DEFAULT;

    if (hdrp) *hdrp = NULL;

    rpmtdReset(&sigtd);

    if ((rc = rpmLeadRead(fd, &leadtype, msg)) != RPMRC_OK) {
	/* Avoid message spew on manifests */
	if (rc == RPMRC_NOTFOUND) {
	    *msg = _free(*msg);
	}
	goto exit;
    }

    /* Read the signature header. */
    rc = rpmReadSignature(fd, &sigh, msg);

    if (rc != RPMRC_OK) {
	goto exit;
    }

#define	_chk(_mask, _tag) \
	(sigtag == 0 && !(vsflags & (_mask)) && headerIsEntry(sigh, (_tag)))

    /*
     * Figger the most effective means of verification available, prefer
     * signatures over digests. Legacy header+payload entries are not used.
     * DSA will be preferred over RSA if both exist because tested first.
     */
    sigtag = 0;
    if (_chk(RPMVSF_NODSAHEADER, RPMSIGTAG_DSA)) {
	sigtag = RPMSIGTAG_DSA;
    } else if (_chk(RPMVSF_NORSAHEADER, RPMSIGTAG_RSA)) {
	sigtag = RPMSIGTAG_RSA;
    } else if (_chk(RPMVSF_NOSHA1HEADER, RPMSIGTAG_SHA1)) {
	sigtag = RPMSIGTAG_SHA1;
    }

    /* Read the metadata, computing digest(s) on the fly. */
    h = NULL;

    rc = rpmpkgReadHeader(fd, &h, msg);

    if (rc != RPMRC_OK || h == NULL) {
	goto exit;
    }

    /* Any digests or signatures to check? */
    if (sigtag == 0) {
	rc = RPMRC_OK;
	goto exit;
    }

    /* Free up any previous "ok" message before signature/digest check */
    *msg = _free(*msg);

    /* Retrieve the tag parameters from the signature header. */
    if (!headerGet(sigh, sigtag, &sigtd, hgeflags)) {
	rc = RPMRC_FAIL;
	goto exit;
    }

    if (rpmSigInfoParse(&sigtd, "package", &sinfo, &sig, msg) == RPMRC_OK) {
	struct rpmtd_s utd;
	DIGEST_CTX ctx = rpmDigestInit(sinfo.hashalgo, RPMDIGEST_NONE);

	if (headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, hgeflags)) {
	    rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
	    rpmDigestUpdate(ctx, utd.data, utd.count);
	    rpmtdFreeData(&utd);
	}
	/** @todo Implement disable/enable/warn/error/anal policy. */
	rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, msg);

	rpmDigestFinal(ctx, NULL, NULL, 0);
    } else {
	rc = RPMRC_FAIL;
    }

exit:
    if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {
	/* Retrofit RPMTAG_SOURCEPACKAGE to srpms for compatibility */
	if (leadtype == RPMLEAD_SOURCE && headerIsSource(h)) {
	    if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) {
		uint32_t one = 1;
		headerPutUint32(h, RPMTAG_SOURCEPACKAGE, &one, 1);
	    }
	}
	/*
 	 * Try to make sure binary rpms have RPMTAG_SOURCERPM set as that's
 	 * what we use for differentiating binary vs source elsewhere.
 	 */
	if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE) && headerIsSource(h)) {
	    headerPutString(h, RPMTAG_SOURCERPM, "(none)");
	}
	/* 
         * Convert legacy headers on the fly. Not having immutable region
         * equals a truly ancient package, do full retrofit. OTOH newer
         * packages might have been built with --nodirtokens, test and handle
         * the non-compressed filelist case separately.
         */
	if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE))
	    headerConvert(h, HEADERCONV_RETROFIT_V3);
	else if (headerIsEntry(h, RPMTAG_OLDFILENAMES))
	    headerConvert(h, HEADERCONV_COMPRESSFILELIST);
	
	/* Append (and remap) signature tags to the metadata. */
	headerMergeLegacySigs(h, sigh);

	/* Bump reference count for return. */
	*hdrp = headerLink(h);

	if (keyidp)
	    *keyidp = getKeyid(sig);
    }
    rpmtdFreeData(&sigtd);
    h = headerFree(h);
    pgpDigParamsFree(sig);
    sigh = headerFree(sigh);
    return rc;
}
Exemplo n.º 9
0
/*
 * Argument monster to verify header-only signature/digest if there is
 * one, otherwisereturn RPMRC_NOTFOUND to signal for plain sanity check.
 */
static rpmRC headerSigVerify(rpmKeyring keyring, rpmVSFlags vsflags,
			     hdrblob blob, char **buf)
{
    rpmRC rc = RPMRC_FAIL;
    pgpDigParams sig = NULL;
    struct rpmtd_s sigtd;
    struct entryInfo_s einfo;
    struct sigtInfo_s sinfo;

    rpmtdReset(&sigtd);
    memset(&einfo, 0, sizeof(einfo));

    /* Find a header-only digest/signature tag. */
    for (int i = blob->ril; i < blob->il; i++) {
	ei2h(blob->pe+i, &einfo);

	switch (einfo.tag) {
	case RPMTAG_SHA1HEADER:
	    if (vsflags & RPMVSF_NOSHA1HEADER)
		break;
	    if (sigtd.tag == 0)
		ei2td(&einfo, blob->dataStart, 0, &sigtd);
	    break;
	case RPMTAG_RSAHEADER:
	    if (vsflags & RPMVSF_NORSAHEADER)
		break;
	    ei2td(&einfo, blob->dataStart, einfo.count, &sigtd);
	    break;
	case RPMTAG_DSAHEADER:
	    if (vsflags & RPMVSF_NODSAHEADER)
		break;
	    ei2td(&einfo, blob->dataStart, einfo.count, &sigtd);
	    break;
	default:
	    break;
	}
    }

    /* No header-only digest/signature found, get outta here */
    if (sigtd.tag == 0) {
	rc = RPMRC_NOTFOUND;
	goto exit;
    }

    if (rpmSigInfoParse(&sigtd, "header", &sinfo, &sig, buf))
	goto exit;

    if (sinfo.hashalgo) {
	DIGEST_CTX ctx = rpmDigestInit(sinfo.hashalgo, RPMDIGEST_NONE);
	int32_t ildl[2] = { htonl(blob->ril), htonl(blob->rdl) };

	rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
	rpmDigestUpdate(ctx, ildl, sizeof(ildl));
	rpmDigestUpdate(ctx, blob->pe, (blob->ril * sizeof(*blob->pe)));
	rpmDigestUpdate(ctx, blob->dataStart, blob->rdl);

	rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, buf);

    	rpmDigestFinal(ctx, NULL, NULL, 0);
    }

exit:
    rpmtdFreeData(&sigtd);
    pgpDigParamsFree(sig);

    return rc;
}
Exemplo n.º 10
0
static rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags vsflags, 
			FD_t fd, const char * fn, Header * hdrp)
{
    pgpDig dig = NULL;
    char buf[8*BUFSIZ];
    ssize_t count;
    rpmlead l = NULL;
    Header sigh = NULL;
    rpmSigTag sigtag;
    struct rpmtd_s sigtd;
    Header h = NULL;
    char * msg;
    rpmRC rc = RPMRC_FAIL;	/* assume failure */
    int leadtype = -1;
    headerGetFlags hgeflags = HEADERGET_DEFAULT;
    DIGEST_CTX ctx = NULL;

    if (hdrp) *hdrp = NULL;

    rpmtdReset(&sigtd);
    l = rpmLeadNew();

    if ((rc = rpmLeadRead(fd, l)) == RPMRC_OK) {
	const char * err = NULL;
	if ((rc = rpmLeadCheck(l, &err)) == RPMRC_FAIL) {
	    rpmlog(RPMLOG_ERR, "%s: %s\n", fn, err);
	}
	leadtype = rpmLeadType(l);
    }
    l = rpmLeadFree(l);

    if (rc != RPMRC_OK)
	goto exit;

    /* Read the signature header. */
    msg = NULL;
    rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg);
    switch (rc) {
    default:
	rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), fn,
		(msg && *msg ? msg : "\n"));
	msg = _free(msg);
	goto exit;
	break;
    case RPMRC_OK:
	if (sigh == NULL) {
	    rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
	    rc = RPMRC_FAIL;
	    goto exit;
	}
	break;
    }
    msg = _free(msg);

#define	_chk(_mask, _tag) \
	(sigtag == 0 && !(vsflags & (_mask)) && headerIsEntry(sigh, (_tag)))

    /*
     * Figger the most effective available signature.
     * Prefer signatures over digests, then header-only over header+payload.
     * DSA will be preferred over RSA if both exist because tested first.
     * Note that NEEDPAYLOAD prevents header+payload signatures and digests.
     */
    sigtag = 0;
    if (_chk(RPMVSF_NODSAHEADER, RPMSIGTAG_DSA)) {
	sigtag = RPMSIGTAG_DSA;
    } else if (_chk(RPMVSF_NORSAHEADER, RPMSIGTAG_RSA)) {
	sigtag = RPMSIGTAG_RSA;
    } else if (_chk(RPMVSF_NODSA|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_GPG)) {
	sigtag = RPMSIGTAG_GPG;
	fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
    } else if (_chk(RPMVSF_NORSA|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_PGP)) {
	sigtag = RPMSIGTAG_PGP;
	fdInitDigest(fd, PGPHASHALGO_MD5, 0);
    } else if (_chk(RPMVSF_NOSHA1HEADER, RPMSIGTAG_SHA1)) {
	sigtag = RPMSIGTAG_SHA1;
    } else if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_MD5)) {
	sigtag = RPMSIGTAG_MD5;
	fdInitDigest(fd, PGPHASHALGO_MD5, 0);
    }

    /* Read the metadata, computing digest(s) on the fly. */
    h = NULL;
    msg = NULL;

    rc = rpmpkgReadHeader(keyring, vsflags, fd, &h, &msg);

    if (rc != RPMRC_OK || h == NULL) {
	rpmlog(RPMLOG_ERR, _("%s: headerRead failed: %s"), fn,
		(msg && *msg ? msg : "\n"));
	msg = _free(msg);
	goto exit;
    }
    msg = _free(msg);

    /* Any digests or signatures to check? */
    if (sigtag == 0) {
	rc = RPMRC_OK;
	goto exit;
    }

    dig = pgpNewDig();
    if (dig == NULL) {
	rc = RPMRC_FAIL;
	goto exit;
    }

    /* Retrieve the tag parameters from the signature header. */
    if (!headerGet(sigh, sigtag, &sigtd, hgeflags)) {
	rc = RPMRC_FAIL;
	goto exit;
    }

    switch (sigtag) {
    case RPMSIGTAG_RSA:
    case RPMSIGTAG_DSA:
	if ((rc = parsePGP(&sigtd, "package", dig)) != RPMRC_OK) {
	    goto exit;
	}
	/* fallthrough */
    case RPMSIGTAG_SHA1:
    {	struct rpmtd_s utd;
	pgpHashAlgo hashalgo = (sigtag == RPMSIGTAG_SHA1) ?
			    PGPHASHALGO_SHA1 : dig->signature.hash_algo;

	if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, hgeflags))
	    break;
	ctx = rpmDigestInit(hashalgo, RPMDIGEST_NONE);
	(void) rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
	(void) rpmDigestUpdate(ctx, utd.data, utd.count);
	rpmtdFreeData(&utd);
    }	break;
    case RPMSIGTAG_GPG:
    case RPMSIGTAG_PGP5:	/* XXX legacy */
    case RPMSIGTAG_PGP:
	if ((rc = parsePGP(&sigtd, "package", dig)) != RPMRC_OK) {
	    goto exit;
	}
	/* fallthrough */
    case RPMSIGTAG_MD5:
	/* Legacy signatures need the compressed payload in the digest too. */
	while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) {}
	if (count < 0) {
	    rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"),
					fn, Fstrerror(fd));
	    rc = RPMRC_FAIL;
	    goto exit;
	}

	ctx = rpmDigestBundleDupCtx(fdGetBundle(fd), (sigtag == RPMSIGTAG_MD5) ?
				    PGPHASHALGO_MD5 : dig->signature.hash_algo);
	break;
    default:
	break;
    }

    /** @todo Implement disable/enable/warn/error/anal policy. */
    rc = rpmVerifySignature(keyring, &sigtd, dig, ctx, &msg);
	
    switch (rc) {
    case RPMRC_OK:		/* Signature is OK. */
	rpmlog(RPMLOG_DEBUG, "%s: %s", fn, msg);
	break;
    case RPMRC_NOTTRUSTED:	/* Signature is OK, but key is not trusted. */
    case RPMRC_NOKEY:		/* Public key is unavailable. */
	/* XXX Print NOKEY/NOTTRUSTED warning only once. */
    {	int lvl = (stashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING);
	rpmlog(lvl, "%s: %s", fn, msg);
    }	break;
    case RPMRC_NOTFOUND:	/* Signature is unknown type. */
	rpmlog(RPMLOG_WARNING, "%s: %s", fn, msg);
	break;
    default:
    case RPMRC_FAIL:		/* Signature does not verify. */
	rpmlog(RPMLOG_ERR, "%s: %s", fn, msg);
	break;
    }
    free(msg);

exit:
    if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {
	/* Retrofit RPMTAG_SOURCEPACKAGE to srpms for compatibility */
	if (leadtype == RPMLEAD_SOURCE && headerIsSource(h)) {
	    if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) {
		uint32_t one = 1;
		headerPutUint32(h, RPMTAG_SOURCEPACKAGE, &one, 1);
	    }
	}
	/*
 	 * Try to make sure binary rpms have RPMTAG_SOURCERPM set as that's
 	 * what we use for differentiating binary vs source elsewhere.
 	 */
	if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE) && headerIsSource(h)) {
	    headerPutString(h, RPMTAG_SOURCERPM, "(none)");
	}
	/* 
         * Convert legacy headers on the fly. Not having "new" style compressed
         * filenames is close enough estimate for legacy indication... 
         */
	if (!headerIsEntry(h, RPMTAG_DIRNAMES)) {
	    headerConvert(h, HEADERCONV_RETROFIT_V3);
	}
	
	/* Append (and remap) signature tags to the metadata. */
	headerMergeLegacySigs(h, sigh);

	/* Bump reference count for return. */
	*hdrp = headerLink(h);
    }
    rpmtdFreeData(&sigtd);
    rpmDigestFinal(ctx, NULL, NULL, 0);
    h = headerFree(h);
    pgpFreeDig(dig);
    sigh = rpmFreeSignature(sigh);
    return rc;
}
Exemplo n.º 11
0
static rpmRC headerVerify(rpmKeyring keyring, rpmVSFlags vsflags,
			  const void * uh, size_t uc, char ** msg)
{
    pgpDig dig = NULL;
    char *buf = NULL;
    int32_t * ei = (int32_t *) uh;
    int32_t il = ntohl(ei[0]);
    int32_t dl = ntohl(ei[1]);
    entryInfo pe = (entryInfo) &ei[2];
    int32_t ildl[2];
    int32_t pvlen = sizeof(ildl) + (il * sizeof(*pe)) + dl;
    unsigned char * dataStart = (unsigned char *) (pe + il);
    struct indexEntry_s entry;
    struct entryInfo_s info;
    unsigned const char * b;
    size_t siglen = 0;
    size_t blen;
    size_t nb;
    int32_t ril = 0;
    unsigned char * regionEnd = NULL;
    rpmRC rc = RPMRC_FAIL;	/* assume failure */
    int xx;
    int i;
    struct rpmtd_s sigtd;
    DIGEST_CTX ctx = NULL;

    /* Is the blob the right size? */
    if (uc > 0 && pvlen != uc) {
	rasprintf(&buf, _("blob size(%d): BAD, 8 + 16 * il(%d) + dl(%d)\n"),
		(int)uc, (int)il, (int)dl);
	goto exit;
    }

    memset(&entry, 0, sizeof(entry));
    memset(&info, 0, sizeof(info));

    /* Check (and convert) the 1st tag element. */
    xx = headerVerifyInfo(1, dl, pe, &entry.info, 0);
    if (xx != -1) {
	rasprintf(&buf, _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
		0, entry.info.tag, entry.info.type,
		entry.info.offset, entry.info.count);
	goto exit;
    }

    /* Is there an immutable header region tag? */
    if (!(entry.info.tag == RPMTAG_HEADERIMMUTABLE
       && entry.info.type == RPM_BIN_TYPE
       && entry.info.count == REGION_TAG_COUNT))
    {
	rc = RPMRC_NOTFOUND;
	goto exit;
    }

    /* Is the offset within the data area? */
    if (entry.info.offset >= dl) {
	rasprintf(&buf, 
		_("region offset: BAD, tag %d type %d offset %d count %d\n"),
		entry.info.tag, entry.info.type,
		entry.info.offset, entry.info.count);
	goto exit;
    }

    /* Is there an immutable header region tag trailer? */
    regionEnd = dataStart + entry.info.offset;
    (void) memcpy(&info, regionEnd, REGION_TAG_COUNT);
    regionEnd += REGION_TAG_COUNT;

    xx = headerVerifyInfo(1, dl, &info, &entry.info, 1);
    if (xx != -1 ||
	!(entry.info.tag == RPMTAG_HEADERIMMUTABLE
       && entry.info.type == RPM_BIN_TYPE
       && entry.info.count == REGION_TAG_COUNT))
    {
	rasprintf(&buf, 
		_("region trailer: BAD, tag %d type %d offset %d count %d\n"),
		entry.info.tag, entry.info.type,
		entry.info.offset, entry.info.count);
	goto exit;
    }
    memset(&info, 0, sizeof(info));

    /* Is the no. of tags in the region less than the total no. of tags? */
    ril = entry.info.offset/sizeof(*pe);
    if ((entry.info.offset % sizeof(*pe)) || ril > il) {
	rasprintf(&buf, _("region size: BAD, ril(%d) > il(%d)\n"), ril, il);
	goto exit;
    }

    /* Find a header-only digest/signature tag. */
    for (i = ril; i < il; i++) {
	xx = headerVerifyInfo(1, dl, pe+i, &entry.info, 0);
	if (xx != -1) {
	    rasprintf(&buf,
		_("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
		i, entry.info.tag, entry.info.type,
		entry.info.offset, entry.info.count);
	    goto exit;
	}

	switch (entry.info.tag) {
	case RPMTAG_SHA1HEADER:
	    if (vsflags & RPMVSF_NOSHA1HEADER)
		break;
	    blen = 0;
	    for (b = dataStart + entry.info.offset; *b != '\0'; b++) {
		if (strchr("0123456789abcdefABCDEF", *b) == NULL)
		    break;
		blen++;
	    }
	    if (entry.info.type != RPM_STRING_TYPE || *b != '\0' || blen != 40)
	    {
		rasprintf(&buf, _("hdr SHA1: BAD, not hex\n"));
		goto exit;
	    }
	    if (info.tag == 0) {
		info = entry.info;	/* structure assignment */
		siglen = blen + 1;
	    }
	    break;
	case RPMTAG_RSAHEADER:
	    if (vsflags & RPMVSF_NORSAHEADER)
		break;
	    if (entry.info.type != RPM_BIN_TYPE) {
		rasprintf(&buf, _("hdr RSA: BAD, not binary\n"));
		goto exit;
	    }
	    info = entry.info;	/* structure assignment */
	    siglen = info.count;
	    break;
	case RPMTAG_DSAHEADER:
	    if (vsflags & RPMVSF_NODSAHEADER)
		break;
	    if (entry.info.type != RPM_BIN_TYPE) {
		rasprintf(&buf, _("hdr DSA: BAD, not binary\n"));
		goto exit;
	    }
	    info = entry.info;	/* structure assignment */
	    siglen = info.count;
	    break;
	default:
	    break;
	}
    }
    rc = RPMRC_NOTFOUND;

exit:
    /* Return determined RPMRC_OK/RPMRC_FAIL conditions. */
    if (rc != RPMRC_NOTFOUND) {
	if (msg) 
	    *msg = buf;
	else
	    free(buf);
	return rc;
    }

    /* If no header-only digest/signature, then do simple sanity check. */
    if (info.tag == 0) {
verifyinfo_exit:
	xx = headerVerifyInfo(ril-1, dl, pe+1, &entry.info, 0);
	if (xx != -1) {
	    rasprintf(&buf,
		_("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
		xx+1, entry.info.tag, entry.info.type,
		entry.info.offset, entry.info.count);
	    rc = RPMRC_FAIL;
	} else {
	    rasprintf(&buf, "Header sanity check: OK\n");
	    rc = RPMRC_OK;
	}
	if (msg) 
	    *msg = buf;
	else
	    free(buf);
	return rc;
    }

    /* Verify header-only digest/signature. */
    dig = pgpNewDig();
    if (dig == NULL)
	goto verifyinfo_exit;

    sigtd.tag = info.tag;
    sigtd.type = info.type;
    sigtd.count = info.count;
    sigtd.data = memcpy(xmalloc(siglen), dataStart + info.offset, siglen);
    sigtd.flags = RPMTD_ALLOCED;

    switch (info.tag) {
    case RPMTAG_RSAHEADER:
    case RPMTAG_DSAHEADER:
	if ((rc = parsePGP(&sigtd, "header", dig)) != RPMRC_OK) {
	    pgpFreeDig(dig);
	    goto exit;
	}
	/* fallthrough */
    case RPMTAG_SHA1HEADER: {
	pgpHashAlgo hashalgo = (info.tag == RPMTAG_SHA1HEADER) ?
				PGPHASHALGO_SHA1 : dig->signature.hash_algo;
	ildl[0] = htonl(ril);
	ildl[1] = (regionEnd - dataStart);
	ildl[1] = htonl(ildl[1]);

	ctx = rpmDigestInit(hashalgo, RPMDIGEST_NONE);

	b = (unsigned char *) rpm_header_magic;
	nb = sizeof(rpm_header_magic);
        (void) rpmDigestUpdate(ctx, b, nb);

	b = (unsigned char *) ildl;
	nb = sizeof(ildl);
        (void) rpmDigestUpdate(ctx, b, nb);

	b = (unsigned char *) pe;
	nb = (htonl(ildl[0]) * sizeof(*pe));
        (void) rpmDigestUpdate(ctx, b, nb);

	b = (unsigned char *) dataStart;
	nb = htonl(ildl[1]);
        (void) rpmDigestUpdate(ctx, b, nb);
	} break;
    default:
	sigtd.data = _free(sigtd.data); /* Hmm...? */
	break;
    }

    rc = rpmVerifySignature(keyring, &sigtd, dig, ctx, &buf);

    if (msg) 
	*msg = buf;
    else
	free(buf);

    rpmtdFreeData(&sigtd);
    pgpFreeDig(dig);
    rpmDigestFinal(ctx, NULL, NULL, 0);
    return rc;
}
Exemplo n.º 12
0
/*
 * Argument monster to verify header-only signature/digest if there is
 * one, otherwisereturn RPMRC_NOTFOUND to signal for plain sanity check.
 */
static rpmRC headerSigVerify(rpmKeyring keyring, rpmVSFlags vsflags,
			     int il, int dl, int ril, int rdl,
			     entryInfo pe, unsigned char * dataStart,
			     char **buf)
{
    size_t siglen = 0;
    rpmRC rc = RPMRC_FAIL;
    pgpDigParams sig = NULL;
    struct rpmtd_s sigtd;
    struct entryInfo_s info, einfo;
    unsigned int hashalgo = 0;

    rpmtdReset(&sigtd);
    memset(&info, 0, sizeof(info));
    memset(&einfo, 0, sizeof(einfo));

    /* Find a header-only digest/signature tag. */
    for (int i = ril; i < il; i++) {
	if (headerVerifyInfo(1, dl, pe+i, &einfo, 0) != -1) {
	    rasprintf(buf,
		_("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
		i, einfo.tag, einfo.type,
		einfo.offset, einfo.count);
	    goto exit;
	}

	switch (einfo.tag) {
	case RPMTAG_SHA1HEADER: {
	    size_t blen = 0;
	    unsigned const char * b;
	    if (vsflags & RPMVSF_NOSHA1HEADER)
		break;
	    for (b = dataStart + einfo.offset; *b != '\0'; b++) {
		if (strchr("0123456789abcdefABCDEF", *b) == NULL)
		    break;
		blen++;
	    }
	    if (einfo.type != RPM_STRING_TYPE || *b != '\0' || blen != 40)
	    {
		rasprintf(buf, _("hdr SHA1: BAD, not hex\n"));
		goto exit;
	    }
	    if (info.tag == 0) {
		info = einfo;	/* structure assignment */
		siglen = blen + 1;
	    }
	    } break;
	case RPMTAG_RSAHEADER:
	    if (vsflags & RPMVSF_NORSAHEADER)
		break;
	    if (einfo.type != RPM_BIN_TYPE) {
		rasprintf(buf, _("hdr RSA: BAD, not binary\n"));
		goto exit;
	    }
	    info = einfo;	/* structure assignment */
	    siglen = info.count;
	    break;
	case RPMTAG_DSAHEADER:
	    if (vsflags & RPMVSF_NODSAHEADER)
		break;
	    if (einfo.type != RPM_BIN_TYPE) {
		rasprintf(buf, _("hdr DSA: BAD, not binary\n"));
		goto exit;
	    }
	    info = einfo;	/* structure assignment */
	    siglen = info.count;
	    break;
	default:
	    break;
	}
    }

    /* No header-only digest/signature found, get outta here */
    if (info.tag == 0) {
	rc = RPMRC_NOTFOUND;
	goto exit;
    }

    sigtd.tag = info.tag;
    sigtd.type = info.type;
    sigtd.count = info.count;
    sigtd.data = memcpy(xmalloc(siglen), dataStart + info.offset, siglen);
    sigtd.flags = RPMTD_ALLOCED;

    switch (info.tag) {
    case RPMTAG_RSAHEADER:
    case RPMTAG_DSAHEADER:
	if (parsePGPSig(&sigtd, "header", NULL, &sig))
	    goto exit;
	hashalgo = pgpDigParamsAlgo(sig, PGPVAL_HASHALGO);
	break;
    case RPMTAG_SHA1HEADER:
	hashalgo = PGPHASHALGO_SHA1;
	break;
    default:
	break;
    }

    if (hashalgo) {
	DIGEST_CTX ctx = rpmDigestInit(hashalgo, RPMDIGEST_NONE);
	int32_t ildl[2] = { htonl(ril), htonl(rdl) };

	rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
	rpmDigestUpdate(ctx, ildl, sizeof(ildl));
	rpmDigestUpdate(ctx, pe, (ril * sizeof(*pe)));
	rpmDigestUpdate(ctx, dataStart, rdl);

	rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, buf);

    	rpmDigestFinal(ctx, NULL, NULL, 0);
    }

exit:
    rpmtdFreeData(&sigtd);
    pgpDigParamsFree(sig);

    return rc;
}
Exemplo n.º 13
0
/* Build pubkey header. */
static int makePubkeyHeader(rpmts ts, rpmPubkey key, Header * hdrp)
{
    Header h = headerNew();
    const char * afmt = "%{pubkeys:armor}";
    const char * group = "Public Keys";
    const char * license = "pubkey";
    const char * buildhost = "localhost";
    const char * userid;
    rpmsenseFlags pflags = (RPMSENSE_KEYRING|RPMSENSE_EQUAL);
    uint32_t zero = 0;
    uint32_t keytime = 0;
    pgpDig dig = NULL;
    pgpDigParams pubp = NULL;
    char * d = NULL;
    char * enc = NULL;
    char * n = NULL;
    char * u = NULL;
    char * v = NULL;
    char * r = NULL;
    char * evr = NULL;
    int rc = -1;

    if ((enc = rpmPubkeyBase64(key)) == NULL)
	goto exit;
    if ((dig = rpmPubkeyDig(key)) == NULL)
	goto exit;
    if ((pubp = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY)) == NULL)
	goto exit;

    /* Build header elements. */
    v = pgpHexStr(pubp->signid, sizeof(pubp->signid)); 
    r = pgpHexStr(pubp->time, sizeof(pubp->time));
    userid = pubp->userid ? pubp->userid : "none";
    keytime = pgpGrab(pubp->time, sizeof(pubp->time));

    rasprintf(&n, "gpg(%s)", v+8);
    rasprintf(&u, "gpg(%s)", userid);
    rasprintf(&evr, "%d:%s-%s", pubp->version, v, r);

    headerPutString(h, RPMTAG_PUBKEYS, enc);

    if ((d = headerFormat(h, afmt, NULL)) == NULL)
	goto exit;

    headerPutString(h, RPMTAG_NAME, "gpg-pubkey");
    headerPutString(h, RPMTAG_VERSION, v+8);
    headerPutString(h, RPMTAG_RELEASE, r);
    headerPutString(h, RPMTAG_DESCRIPTION, d);
    headerPutString(h, RPMTAG_GROUP, group);
    headerPutString(h, RPMTAG_LICENSE, license);
    headerPutString(h, RPMTAG_SUMMARY, u);
    headerPutString(h, RPMTAG_PACKAGER, userid);

    headerPutUint32(h, RPMTAG_SIZE, &zero, 1);

    headerPutString(h, RPMTAG_PROVIDENAME, u);
    headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
    headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1);
	
    headerPutString(h, RPMTAG_PROVIDENAME, n);
    headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
    headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1);

    headerPutString(h, RPMTAG_RPMVERSION, RPMVERSION);
    headerPutString(h, RPMTAG_BUILDHOST, buildhost);
    headerPutUint32(h, RPMTAG_BUILDTIME, &keytime, 1);
    headerPutString(h, RPMTAG_SOURCERPM, "(none)");

    /* Reload the lot to immutable region and stomp sha1 digest on it */
    h = headerReload(h, RPMTAG_HEADERIMMUTABLE);
    if (h != NULL) {
	char *sha1 = NULL;
	unsigned int blen = 0;
	const void *blob = headerExport(h, &blen);

	/* XXX FIXME: bah, this code is repeated in way too many places */
	DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
	rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
	rpmDigestUpdate(ctx, blob, blen);
	rpmDigestFinal(ctx, (void **)&sha1, NULL, 1);

	if (sha1) {
	    headerPutString(h, RPMTAG_SHA1HEADER, sha1);
	    *hdrp = headerLink(h);
	    rc = 0;
	}
	free(sha1);
    }

exit:
    headerFree(h);
    pgpFreeDig(dig);
    free(n);
    free(u);
    free(v);
    free(r);
    free(evr);
    free(enc);
    free(d);

    return rc;
}
Exemplo n.º 14
0
Arquivo: tkey.c Projeto: avokhmin/RPM5
int
main(int argc, char *argv[])
{
    pgpImplVecs_t * testImplVecs = &rpmnssImplVecs;
    pgpDig dig;
pgpDigParams pubp;
    rpmbc bc;
    int printing = -1;
    int rc;

    pgpImplVecs = &rpmbcImplVecs;

    dig = pgpDigNew(RPMVSF_DEFAULT, 0);
pubp = pgpGetPubkey(dig);
    bc = dig->impl;

    mpbzero(&bc->p);	mpbsethex(&bc->p, fips_p);
    mpbzero(&bc->q);	mpbsethex(&bc->q, fips_q);
    mpnzero(&bc->g);	mpnsethex(&bc->g, fips_g);
    mpnzero(&bc->y);	mpnsethex(&bc->y, fips_y);
    mpnzero(&bc->r);	mpnsethex(&bc->r, fips_r);
    mpnzero(&bc->s);	mpnsethex(&bc->s, fips_s);
    mpnzero(&bc->hm);	mpnsethex(&bc->hm, fips_hm);

pubp->pubkey_algo = PGPPUBKEYALGO_DSA;	/* XXX assert? */
    rc = pgpImplVerify(dig);

fprintf(stderr, "=============================== DSA FIPS-186-1: rc %d\n", rc);

    dig = pgpDigFree(dig);

    pgpImplVecs = testImplVecs;

    dig = pgpDigNew(RPMVSF_DEFAULT, 0);
pubp = pgpGetPubkey(dig);
_pgp_debug = 1;
_pgp_print = 1;

fprintf(stderr, "=============================== DSA Public Key\n");
    if ((rc = doit(DSApub, dig, printing)) != 0)
	fprintf(stderr, "==> FAILED: rc %d\n", rc);

fprintf(stderr, "=============================== DSA Signature of \"%s\"\n", str);
    if ((rc = doit(DSAsig, dig, printing)) != 0)
	fprintf(stderr, "==> FAILED: rc %d\n", rc);

    {	DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
	pgpDigParams dsig = pgpGetSignature(dig);
	
	rpmDigestUpdate(ctx, str, strlen(str));
	rpmDigestUpdate(ctx, dsig->hash, dsig->hashlen);

	(void) pgpImplSetDSA(ctx, dig, dsig);
    }

pubp->pubkey_algo = PGPPUBKEYALGO_DSA;	/* XXX assert? */
    rc = pgpImplVerify(dig);
    
fprintf(stderr, "=============================== DSA verify: rc %d\n", rc);

    dig = pgpDigFree(dig);

    pgpImplVecs = testImplVecs;

    dig = pgpDigNew(RPMVSF_DEFAULT, 0);
pubp = pgpGetPubkey(dig);
_pgp_debug = 1;
_pgp_print = 1;

fprintf(stderr, "=============================== RSA Public Key\n");
    if ((rc = doit(RSApub, dig, printing)) != 0)
	fprintf(stderr, "==> FAILED: rc %d\n", rc);

fprintf(stderr, "=============================== RSA Signature of \"%s\"\n", str);
    if ((rc = doit(RSAsig, dig, printing)) != 0)
	fprintf(stderr, "==> FAILED: rc %d\n", rc);

    {	DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
	pgpDigParams dsig = pgpGetSignature(dig);
	
	rpmDigestUpdate(ctx, str, strlen(str));
	rpmDigestUpdate(ctx, dsig->hash, dsig->hashlen);

	(void) pgpImplSetRSA(ctx, dig, dsig);
    }

pubp->pubkey_algo = PGPPUBKEYALGO_RSA;	/* XXX assert? */
    rc = pgpImplVerify(dig);
    
fprintf(stderr, "=============================== RSA verify: rc %d\n", rc);

    dig = pgpDigFree(dig);

    pgpImplVecs = testImplVecs;

    dig = pgpDigNew(RPMVSF_DEFAULT, 0);
pubp = pgpGetPubkey(dig);
_pgp_debug = 1;
_pgp_print = 1;

fprintf(stderr, "=============================== ECDSA Public Key\n");
    if ((rc = doit(ECDSApub, dig, printing)) != 0)
	fprintf(stderr, "==> FAILED: rc %d\n", rc);

fprintf(stderr, "=============================== ECDSA Signature of \"%s\"\n", str);
    if ((rc = doit(ECDSAsig, dig, printing)) != 0)
	fprintf(stderr, "==> FAILED: rc %d\n", rc);

    {	DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA256, RPMDIGEST_NONE);
	pgpDigParams dsig = pgpGetSignature(dig);
	
	rpmDigestUpdate(ctx, str, strlen(str));
	rpmDigestUpdate(ctx, dsig->hash, dsig->hashlen);

	(void) pgpImplSetECDSA(ctx, dig, dsig);
    }

pubp->pubkey_algo = PGPPUBKEYALGO_ECDSA;	/* XXX assert? */
    rc = pgpImplVerify(dig);
    
fprintf(stderr, "=============================== ECDSA verify: rc %d\n", rc);

    dig = pgpDigFree(dig);

    if (pgpImplVecs == &rpmsslImplVecs)
	NSS_Shutdown();

    return rc;
}