1#include"builtin.h" 2#include"tag.h" 3#include"replace-object.h" 4#include"object-store.h" 5 6/* 7 * A signature file has a very simple fixed format: four lines 8 * of "object <sha1>" + "type <typename>" + "tag <tagname>" + 9 * "tagger <committer>", followed by a blank line, a free-form tag 10 * message and a signature block that git itself doesn't care about, 11 * but that can be verified with gpg or similar. 12 * 13 * The first four lines are guaranteed to be at least 83 bytes: 14 * "object <sha1>\n" is 48 bytes, "type tag\n" at 9 bytes is the 15 * shortest possible type-line, "tag .\n" at 6 bytes is the shortest 16 * single-character-tag line, and "tagger . <> 0 +0000\n" at 20 bytes is 17 * the shortest possible tagger-line. 18 */ 19 20/* 21 * We refuse to tag something we can't verify. Just because. 22 */ 23static intverify_object(const struct object_id *oid,const char*expected_type) 24{ 25int ret = -1; 26enum object_type type; 27unsigned long size; 28void*buffer =read_object_file(oid, &type, &size); 29const struct object_id *repl =lookup_replace_object(the_repository, oid); 30 31if(buffer) { 32if(type ==type_from_string(expected_type)) 33 ret =check_object_signature(repl, buffer, size, expected_type); 34free(buffer); 35} 36return ret; 37} 38 39static intverify_tag(char*buffer,unsigned long size) 40{ 41int typelen; 42char type[20]; 43struct object_id oid; 44const char*object, *type_line, *tag_line, *tagger_line, *lb, *rb, *p; 45size_t len; 46 47if(size <84) 48returnerror("wanna fool me ? you obviously got the size wrong !"); 49 50 buffer[size] =0; 51 52/* Verify object line */ 53 object = buffer; 54if(memcmp(object,"object ",7)) 55returnerror("char%d: does not start with\"object\"",0); 56 57if(parse_oid_hex(object +7, &oid, &p)) 58returnerror("char%d: could not get SHA1 hash",7); 59 60/* Verify type line */ 61 type_line = p +1; 62if(memcmp(type_line -1,"\ntype ",6)) 63returnerror("char%d: could not find\"\\ntype\"",47); 64 65/* Verify tag-line */ 66 tag_line =strchr(type_line,'\n'); 67if(!tag_line) 68returnerror("char%"PRIuMAX": could not find next\"\\n\"", 69(uintmax_t) (type_line - buffer)); 70 tag_line++; 71if(memcmp(tag_line,"tag ",4) || tag_line[4] =='\n') 72returnerror("char%"PRIuMAX": no\"tag\"found", 73(uintmax_t) (tag_line - buffer)); 74 75/* Get the actual type */ 76 typelen = tag_line - type_line -strlen("type\n"); 77if(typelen >=sizeof(type)) 78returnerror("char%"PRIuMAX": type too long", 79(uintmax_t) (type_line+5- buffer)); 80 81memcpy(type, type_line+5, typelen); 82 type[typelen] =0; 83 84/* Verify that the object matches */ 85if(verify_object(&oid, type)) 86returnerror("char%d: could not verify object%s",7,oid_to_hex(&oid)); 87 88/* Verify the tag-name: we don't allow control characters or spaces in it */ 89 tag_line +=4; 90for(;;) { 91unsigned char c = *tag_line++; 92if(c =='\n') 93break; 94if(c >' ') 95continue; 96returnerror("char%"PRIuMAX": could not verify tag name", 97(uintmax_t) (tag_line - buffer)); 98} 99 100/* Verify the tagger line */ 101 tagger_line = tag_line; 102 103if(memcmp(tagger_line,"tagger ",7)) 104returnerror("char%"PRIuMAX": could not find\"tagger\"", 105(uintmax_t) (tagger_line - buffer)); 106 107/* 108 * Check for correct form for name and email 109 * i.e. " <" followed by "> " on _this_ line 110 * No angle brackets within the name or email address fields. 111 * No spaces within the email address field. 112 */ 113 tagger_line +=7; 114if(!(lb =strstr(tagger_line," <")) || !(rb =strstr(lb+2,"> ")) || 115strpbrk(tagger_line,"<>\n") != lb+1|| 116strpbrk(lb+2,"><\n") != rb) 117returnerror("char%"PRIuMAX": malformed tagger field", 118(uintmax_t) (tagger_line - buffer)); 119 120/* Check for author name, at least one character, space is acceptable */ 121if(lb == tagger_line) 122returnerror("char%"PRIuMAX": missing tagger name", 123(uintmax_t) (tagger_line - buffer)); 124 125/* timestamp, 1 or more digits followed by space */ 126 tagger_line = rb +2; 127if(!(len =strspn(tagger_line,"0123456789"))) 128returnerror("char%"PRIuMAX": missing tag timestamp", 129(uintmax_t) (tagger_line - buffer)); 130 tagger_line += len; 131if(*tagger_line !=' ') 132returnerror("char%"PRIuMAX": malformed tag timestamp", 133(uintmax_t) (tagger_line - buffer)); 134 tagger_line++; 135 136/* timezone, 5 digits [+-]hhmm, max. 1400 */ 137if(!((tagger_line[0] =='+'|| tagger_line[0] =='-') && 138strspn(tagger_line+1,"0123456789") ==4&& 139 tagger_line[5] =='\n'&&atoi(tagger_line+1) <=1400)) 140returnerror("char%"PRIuMAX": malformed tag timezone", 141(uintmax_t) (tagger_line - buffer)); 142 tagger_line +=6; 143 144/* Verify the blank line separating the header from the body */ 145if(*tagger_line !='\n') 146returnerror("char%"PRIuMAX": trailing garbage in tag header", 147(uintmax_t) (tagger_line - buffer)); 148 149/* The actual stuff afterwards we don't care about.. */ 150return0; 151} 152 153intcmd_mktag(int argc,const char**argv,const char*prefix) 154{ 155struct strbuf buf = STRBUF_INIT; 156struct object_id result; 157 158if(argc !=1) 159usage("git mktag"); 160 161if(strbuf_read(&buf,0,4096) <0) { 162die_errno("could not read from stdin"); 163} 164 165/* Verify it for some basic sanity: it needs to start with 166 "object <sha1>\ntype\ntagger " */ 167if(verify_tag(buf.buf, buf.len) <0) 168die("invalid tag signature file"); 169 170if(write_object_file(buf.buf, buf.len, tag_type, &result) <0) 171die("unable to write tag file"); 172 173strbuf_release(&buf); 174printf("%s\n",oid_to_hex(&result)); 175return0; 176}