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