herm1t LIVE!ng room - Меняем MD5 файла в базе RPM [entries|archive|friends|userinfo]
herm1t

[ website | twilight corner in the herm1t's cave ]
[ userinfo | ljr userinfo ]
[ archive | journal archive ]

Меняем MD5 файла в базе RPM [Dec. 23rd, 2010|05:13 pm]
Previous Entry Add to Memories Tell A Friend Next Entry
[Tags|, , , ]
[Current Mood |geeky]

Иногда очень хочется поменять что-нибудь в базе RPM, и так, чтобы rpm -V заткнулся. Делается это так:
int update_file(char *fn, char *new_md5, int new_len)
{
        int r = 1;
        Header h;

        rpmts ts = rpmtsCreate();
        rpmtsOpenDB(ts, O_RDWR);
        rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, fn, 0);
        rpmdbSetIteratorRewrite(mi, 1);
        while ((h = (Header)rpmdbNextIterator(mi)) != NULL) {
                int_32 count, *sizes, *diri;
                char **name, **md5s, **dirs;    
                headerGetEntry(h, RPMTAG_BASENAMES, NULL, (void**)&name, &count);
                headerGetEntry(h, RPMTAG_FILEMD5S,  NULL, (void**)&md5s, NULL);
                headerGetEntry(h, RPMTAG_FILESIZES, NULL, (void**)&sizes, NULL);
                headerGetEntry(h, RPMTAG_DIRNAMES, NULL, (void**)&dirs, NULL);
                headerGetEntry(h, RPMTAG_DIRINDEXES, NULL, (void**)&diri, NULL);
                int i;
                for (i = 0; i < count; i++) {
                        char *file = malloc(strlen(dirs[diri[i]]) + strlen(name[i]) + 1);
                        strcpy(file, dirs[diri[i]]);
                        strcat(file, name[i]);
                        if (! strcmp(file, fn)) {                               
                                sizes[i] = new_len;
                                strcpy(md5s[i], new_md5);
                                headerModifyEntry(h, RPMTAG_FILEMD5S,  RPM_STRING_ARRAY_TYPE, (void**)md5s, count);
                                headerModifyEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE, (void**)sizes, count);
                                if (headerIsEntry(h, RPMTAG_SHA1HEADER)) {
                                        DIGEST_CTX ctx;
                                        void *uh;
                                        int_32 uhc;
                                        char *digest = NULL, *p;
                                        uint32_t header_magic[2];
                                        
                                        header_magic[0] = 0x01e8ad8e;
                                        header_magic[1] = 0;
                                
                                        headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, NULL, &uh, &uhc);
                                        ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
                                        rpmDigestUpdate(ctx, header_magic, sizeof(header_magic));
                                        rpmDigestUpdate(ctx, uh, uhc);
                                        rpmDigestFinal(ctx, (void*)&digest, NULL, 1);
                                        headerGetEntryMinMemory(h, RPMTAG_SHA1HEADER, NULL, (void*)&p, NULL);
                                        strcpy(p, digest);
                                }
                                free(file);
                                rpmdbSetIteratorModified(mi, 1);
                                r = 0;
                                break;
                        }
                        free(file);
                }
        }
        rpmdbFreeIterator(mi);
        rpmtsFree(ts);
        return r;
}
Скачать RiPM (форум, регистрация)
Основная проблема была с SHA1 заголовка. rpmlib суровая штука - ни документации, ни примеров, ни проверки ошибок: шаг влево, шаг вправо - SIGSEGV (например, если заменить headerGetEntryMinMemory на headerModifyEntry ;-) А "right thing" - это сделать на headerCopy/Unload/Reload/Unload, вообщем я так и не понял, что с ним нужно сделать, чтобы "закомитить" все изменения и не оторвать его от transaction set. А так работает.
rpm -Uvh /usr/src/redhat/RPMS/i386/foobar-0.1-1.i386.rpm
Preparing...                ########################################### [100%]
   1:foobar                 ########################################### [100%]
rpm -Vf /bin/foobar
sleep 1
echo "xxx" >> /bin/foobar
rpm -Vf /bin/foobar
S.5....T    /bin/foobar
make: [all] Error 1 (ignored)
gcc -Wall -ggdb -lrpm ripm.c
./a.out /bin/foobar
RPMDB patched
rpm -Vf /bin/foobar
.......T    /bin/foobar
make: [all] Error 1 (ignored)
"T", то есть mod. time лучше править не в базе RPM, восстанавливать на самом файле.

Кстати, если кто пользуется integrity check, то базу полагается хранить на ro-носителе.

P.S. Это я к чему. Вот есть у меня звери, которые используют libc, но раз есть libc, значит есть и все остальное ;-) Типа того.

LinkLeave a comment