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