git
/
connect.c
1526 строк · 37.5 Кб
1#define USE_THE_REPOSITORY_VARIABLE2
3#include "git-compat-util.h"4#include "config.h"5#include "environment.h"6#include "gettext.h"7#include "hex.h"8#include "pkt-line.h"9#include "quote.h"10#include "refs.h"11#include "run-command.h"12#include "remote.h"13#include "connect.h"14#include "url.h"15#include "string-list.h"16#include "oid-array.h"17#include "path.h"18#include "transport.h"19#include "trace2.h"20#include "strbuf.h"21#include "version.h"22#include "protocol.h"23#include "alias.h"24#include "bundle-uri.h"25
26static char *server_capabilities_v1;27static struct strvec server_capabilities_v2 = STRVEC_INIT;28static const char *next_server_feature_value(const char *feature, size_t *len, size_t *offset);29
30static int check_ref(const char *name, unsigned int flags)31{
32if (!flags)33return 1;34
35if (!skip_prefix(name, "refs/", &name))36return 0;37
38/* REF_NORMAL means that we don't want the magic fake tag refs */39if ((flags & REF_NORMAL) && check_refname_format(name,40REFNAME_ALLOW_ONELEVEL))41return 0;42
43/* REF_BRANCHES means that we want regular branch heads */44if ((flags & REF_BRANCHES) && starts_with(name, "heads/"))45return 1;46
47/* REF_TAGS means that we want tags */48if ((flags & REF_TAGS) && starts_with(name, "tags/"))49return 1;50
51/* All type bits clear means that we are ok with anything */52return !(flags & ~REF_NORMAL);53}
54
55int check_ref_type(const struct ref *ref, int flags)56{
57return check_ref(ref->name, flags);58}
59
60static NORETURN void die_initial_contact(int unexpected)61{
62/*63* A hang-up after seeing some response from the other end
64* means that it is unexpected, as we know the other end is
65* willing to talk to us. A hang-up before seeing any
66* response does not necessarily mean an ACL problem, though.
67*/
68if (unexpected)69die(_("the remote end hung up upon initial contact"));70else71die(_("Could not read from remote repository.\n\n"72"Please make sure you have the correct access rights\n"73"and the repository exists."));74}
75
76/* Checks if the server supports the capability 'c' */
77int server_supports_v2(const char *c)78{
79int i;80
81for (i = 0; i < server_capabilities_v2.nr; i++) {82const char *out;83if (skip_prefix(server_capabilities_v2.v[i], c, &out) &&84(!*out || *out == '='))85return 1;86}87return 0;88}
89
90void ensure_server_supports_v2(const char *c)91{
92if (!server_supports_v2(c))93die(_("server doesn't support '%s'"), c);94}
95
96int server_feature_v2(const char *c, const char **v)97{
98int i;99
100for (i = 0; i < server_capabilities_v2.nr; i++) {101const char *out;102if (skip_prefix(server_capabilities_v2.v[i], c, &out) &&103(*out == '=')) {104*v = out + 1;105return 1;106}107}108return 0;109}
110
111int server_supports_feature(const char *c, const char *feature,112int die_on_error)113{
114int i;115
116for (i = 0; i < server_capabilities_v2.nr; i++) {117const char *out;118if (skip_prefix(server_capabilities_v2.v[i], c, &out) &&119(!*out || *(out++) == '=')) {120if (parse_feature_request(out, feature))121return 1;122else123break;124}125}126
127if (die_on_error)128die(_("server doesn't support feature '%s'"), feature);129
130return 0;131}
132
133static void process_capabilities_v2(struct packet_reader *reader)134{
135while (packet_reader_read(reader) == PACKET_READ_NORMAL)136strvec_push(&server_capabilities_v2, reader->line);137
138if (reader->status != PACKET_READ_FLUSH)139die(_("expected flush after capabilities"));140}
141
142enum protocol_version discover_version(struct packet_reader *reader)143{
144enum protocol_version version = protocol_unknown_version;145
146/*147* Peek the first line of the server's response to
148* determine the protocol version the server is speaking.
149*/
150switch (packet_reader_peek(reader)) {151case PACKET_READ_EOF:152die_initial_contact(0);153case PACKET_READ_FLUSH:154case PACKET_READ_DELIM:155case PACKET_READ_RESPONSE_END:156version = protocol_v0;157break;158case PACKET_READ_NORMAL:159version = determine_protocol_version_client(reader->line);160break;161}162
163switch (version) {164case protocol_v2:165process_capabilities_v2(reader);166break;167case protocol_v1:168/* Read the peeked version line */169packet_reader_read(reader);170break;171case protocol_v0:172break;173case protocol_unknown_version:174BUG("unknown protocol version");175}176
177trace2_data_intmax("transfer", NULL, "negotiated-version", version);178
179return version;180}
181
182static void parse_one_symref_info(struct string_list *symref, const char *val, int len)183{
184char *sym, *target;185struct string_list_item *item;186
187if (!len)188return; /* just "symref" */189/* e.g. "symref=HEAD:refs/heads/master" */190sym = xmemdupz(val, len);191target = strchr(sym, ':');192if (!target)193/* just "symref=something" */194goto reject;195*(target++) = '\0';196if (check_refname_format(sym, REFNAME_ALLOW_ONELEVEL) ||197check_refname_format(target, REFNAME_ALLOW_ONELEVEL))198/* "symref=bogus:pair */199goto reject;200item = string_list_append_nodup(symref, sym);201item->util = target;202return;203reject:204free(sym);205return;206}
207
208static void annotate_refs_with_symref_info(struct ref *ref)209{
210struct string_list symref = STRING_LIST_INIT_DUP;211size_t offset = 0;212
213while (1) {214size_t len;215const char *val;216
217val = next_server_feature_value("symref", &len, &offset);218if (!val)219break;220parse_one_symref_info(&symref, val, len);221}222string_list_sort(&symref);223
224for (; ref; ref = ref->next) {225struct string_list_item *item;226item = string_list_lookup(&symref, ref->name);227if (!item)228continue;229ref->symref = xstrdup((char *)item->util);230}231string_list_clear(&symref, 0);232}
233
234static void process_capabilities(struct packet_reader *reader, int *linelen)235{
236const char *feat_val;237size_t feat_len;238const char *line = reader->line;239int nul_location = strlen(line);240if (nul_location == *linelen)241return;242server_capabilities_v1 = xstrdup(line + nul_location + 1);243*linelen = nul_location;244
245feat_val = server_feature_value("object-format", &feat_len);246if (feat_val) {247char *hash_name = xstrndup(feat_val, feat_len);248int hash_algo = hash_algo_by_name(hash_name);249if (hash_algo != GIT_HASH_UNKNOWN)250reader->hash_algo = &hash_algos[hash_algo];251free(hash_name);252} else {253reader->hash_algo = &hash_algos[GIT_HASH_SHA1];254}255}
256
257static int process_dummy_ref(const struct packet_reader *reader)258{
259const char *line = reader->line;260struct object_id oid;261const char *name;262
263if (parse_oid_hex_algop(line, &oid, &name, reader->hash_algo))264return 0;265if (*name != ' ')266return 0;267name++;268
269return oideq(reader->hash_algo->null_oid, &oid) &&270!strcmp(name, "capabilities^{}");271}
272
273static void check_no_capabilities(const char *line, int len)274{
275if (strlen(line) != len)276warning(_("ignoring capabilities after first line '%s'"),277line + strlen(line));278}
279
280static int process_ref(const struct packet_reader *reader, int len,281struct ref ***list, unsigned int flags,282struct oid_array *extra_have)283{
284const char *line = reader->line;285struct object_id old_oid;286const char *name;287
288if (parse_oid_hex_algop(line, &old_oid, &name, reader->hash_algo))289return 0;290if (*name != ' ')291return 0;292name++;293
294if (extra_have && !strcmp(name, ".have")) {295oid_array_append(extra_have, &old_oid);296} else if (!strcmp(name, "capabilities^{}")) {297die(_("protocol error: unexpected capabilities^{}"));298} else if (check_ref(name, flags)) {299struct ref *ref = alloc_ref(name);300oidcpy(&ref->old_oid, &old_oid);301**list = ref;302*list = &ref->next;303}304check_no_capabilities(line, len);305return 1;306}
307
308static int process_shallow(const struct packet_reader *reader, int len,309struct oid_array *shallow_points)310{
311const char *line = reader->line;312const char *arg;313struct object_id old_oid;314
315if (!skip_prefix(line, "shallow ", &arg))316return 0;317
318if (get_oid_hex_algop(arg, &old_oid, reader->hash_algo))319die(_("protocol error: expected shallow sha-1, got '%s'"), arg);320if (!shallow_points)321die(_("repository on the other end cannot be shallow"));322oid_array_append(shallow_points, &old_oid);323check_no_capabilities(line, len);324return 1;325}
326
327enum get_remote_heads_state {328EXPECTING_FIRST_REF = 0,329EXPECTING_REF,330EXPECTING_SHALLOW,331EXPECTING_DONE,332};333
334/*
335* Read all the refs from the other end
336*/
337struct ref **get_remote_heads(struct packet_reader *reader,338struct ref **list, unsigned int flags,339struct oid_array *extra_have,340struct oid_array *shallow_points)341{
342struct ref **orig_list = list;343int len = 0;344enum get_remote_heads_state state = EXPECTING_FIRST_REF;345
346*list = NULL;347
348while (state != EXPECTING_DONE) {349switch (packet_reader_read(reader)) {350case PACKET_READ_EOF:351die_initial_contact(1);352case PACKET_READ_NORMAL:353len = reader->pktlen;354break;355case PACKET_READ_FLUSH:356state = EXPECTING_DONE;357break;358case PACKET_READ_DELIM:359case PACKET_READ_RESPONSE_END:360die(_("invalid packet"));361}362
363switch (state) {364case EXPECTING_FIRST_REF:365process_capabilities(reader, &len);366if (process_dummy_ref(reader)) {367state = EXPECTING_SHALLOW;368break;369}370state = EXPECTING_REF;371/* fallthrough */372case EXPECTING_REF:373if (process_ref(reader, len, &list, flags, extra_have))374break;375state = EXPECTING_SHALLOW;376/* fallthrough */377case EXPECTING_SHALLOW:378if (process_shallow(reader, len, shallow_points))379break;380die(_("protocol error: unexpected '%s'"), reader->line);381case EXPECTING_DONE:382break;383}384}385
386annotate_refs_with_symref_info(*orig_list);387
388return list;389}
390
391/* Returns 1 when a valid ref has been added to `list`, 0 otherwise */
392static int process_ref_v2(struct packet_reader *reader, struct ref ***list,393const char **unborn_head_target)394{
395int ret = 1;396int i = 0;397struct object_id old_oid;398struct ref *ref;399struct string_list line_sections = STRING_LIST_INIT_DUP;400const char *end;401const char *line = reader->line;402
403/*404* Ref lines have a number of fields which are space deliminated. The
405* first field is the OID of the ref. The second field is the ref
406* name. Subsequent fields (symref-target and peeled) are optional and
407* don't have a particular order.
408*/
409if (string_list_split(&line_sections, line, ' ', -1) < 2) {410ret = 0;411goto out;412}413
414if (!strcmp("unborn", line_sections.items[i].string)) {415i++;416if (unborn_head_target &&417!strcmp("HEAD", line_sections.items[i++].string)) {418/*419* Look for the symref target (if any). If found,
420* return it to the caller.
421*/
422for (; i < line_sections.nr; i++) {423const char *arg = line_sections.items[i].string;424
425if (skip_prefix(arg, "symref-target:", &arg)) {426*unborn_head_target = xstrdup(arg);427break;428}429}430}431goto out;432}433if (parse_oid_hex_algop(line_sections.items[i++].string, &old_oid, &end, reader->hash_algo) ||434*end) {435ret = 0;436goto out;437}438
439ref = alloc_ref(line_sections.items[i++].string);440
441memcpy(ref->old_oid.hash, old_oid.hash, reader->hash_algo->rawsz);442**list = ref;443*list = &ref->next;444
445for (; i < line_sections.nr; i++) {446const char *arg = line_sections.items[i].string;447if (skip_prefix(arg, "symref-target:", &arg))448ref->symref = xstrdup(arg);449
450if (skip_prefix(arg, "peeled:", &arg)) {451struct object_id peeled_oid;452char *peeled_name;453struct ref *peeled;454if (parse_oid_hex_algop(arg, &peeled_oid, &end,455reader->hash_algo) || *end) {456ret = 0;457goto out;458}459
460peeled_name = xstrfmt("%s^{}", ref->name);461peeled = alloc_ref(peeled_name);462
463memcpy(peeled->old_oid.hash, peeled_oid.hash,464reader->hash_algo->rawsz);465**list = peeled;466*list = &peeled->next;467
468free(peeled_name);469}470}471
472out:473string_list_clear(&line_sections, 0);474return ret;475}
476
477void check_stateless_delimiter(int stateless_rpc,478struct packet_reader *reader,479const char *error)480{
481if (!stateless_rpc)482return; /* not in stateless mode, no delimiter expected */483if (packet_reader_read(reader) != PACKET_READ_RESPONSE_END)484die("%s", error);485}
486
487static void send_capabilities(int fd_out, struct packet_reader *reader)488{
489const char *hash_name;490
491if (server_supports_v2("agent"))492packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized());493
494if (server_feature_v2("object-format", &hash_name)) {495int hash_algo = hash_algo_by_name(hash_name);496if (hash_algo == GIT_HASH_UNKNOWN)497die(_("unknown object format '%s' specified by server"), hash_name);498reader->hash_algo = &hash_algos[hash_algo];499packet_write_fmt(fd_out, "object-format=%s", reader->hash_algo->name);500} else {501reader->hash_algo = &hash_algos[GIT_HASH_SHA1];502}503}
504
505int get_remote_bundle_uri(int fd_out, struct packet_reader *reader,506struct bundle_list *bundles, int stateless_rpc)507{
508int line_nr = 1;509
510/* Assert bundle-uri support */511ensure_server_supports_v2("bundle-uri");512
513/* (Re-)send capabilities */514send_capabilities(fd_out, reader);515
516/* Send command */517packet_write_fmt(fd_out, "command=bundle-uri\n");518packet_delim(fd_out);519
520packet_flush(fd_out);521
522/* Process response from server */523while (packet_reader_read(reader) == PACKET_READ_NORMAL) {524const char *line = reader->line;525line_nr++;526
527if (!bundle_uri_parse_line(bundles, line))528continue;529
530return error(_("error on bundle-uri response line %d: %s"),531line_nr, line);532}533
534if (reader->status != PACKET_READ_FLUSH)535return error(_("expected flush after bundle-uri listing"));536
537/*538* Might die(), but obscure enough that that's OK, e.g. in
539* serve.c we'll call BUG() on its equivalent (the
540* PACKET_READ_RESPONSE_END check).
541*/
542check_stateless_delimiter(stateless_rpc, reader,543_("expected response end packet after ref listing"));544
545return 0;546}
547
548struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,549struct ref **list, int for_push,550struct transport_ls_refs_options *transport_options,551const struct string_list *server_options,552int stateless_rpc)553{
554int i;555struct strvec *ref_prefixes = transport_options ?556&transport_options->ref_prefixes : NULL;557const char **unborn_head_target = transport_options ?558&transport_options->unborn_head_target : NULL;559*list = NULL;560
561ensure_server_supports_v2("ls-refs");562packet_write_fmt(fd_out, "command=ls-refs\n");563
564/* Send capabilities */565send_capabilities(fd_out, reader);566
567if (server_options && server_options->nr) {568ensure_server_supports_v2("server-option");569for (i = 0; i < server_options->nr; i++)570packet_write_fmt(fd_out, "server-option=%s",571server_options->items[i].string);572}573
574packet_delim(fd_out);575/* When pushing we don't want to request the peeled tags */576if (!for_push)577packet_write_fmt(fd_out, "peel\n");578packet_write_fmt(fd_out, "symrefs\n");579if (server_supports_feature("ls-refs", "unborn", 0))580packet_write_fmt(fd_out, "unborn\n");581for (i = 0; ref_prefixes && i < ref_prefixes->nr; i++) {582packet_write_fmt(fd_out, "ref-prefix %s\n",583ref_prefixes->v[i]);584}585packet_flush(fd_out);586
587/* Process response from server */588while (packet_reader_read(reader) == PACKET_READ_NORMAL) {589if (!process_ref_v2(reader, &list, unborn_head_target))590die(_("invalid ls-refs response: %s"), reader->line);591}592
593if (reader->status != PACKET_READ_FLUSH)594die(_("expected flush after ref listing"));595
596check_stateless_delimiter(stateless_rpc, reader,597_("expected response end packet after ref listing"));598
599return list;600}
601
602const char *parse_feature_value(const char *feature_list, const char *feature, size_t *lenp, size_t *offset)603{
604const char *orig_start = feature_list;605size_t len;606
607if (!feature_list)608return NULL;609
610len = strlen(feature);611if (offset)612feature_list += *offset;613while (*feature_list) {614const char *found = strstr(feature_list, feature);615if (!found)616return NULL;617if (feature_list == found || isspace(found[-1])) {618const char *value = found + len;619/* feature with no value (e.g., "thin-pack") */620if (!*value || isspace(*value)) {621if (lenp)622*lenp = 0;623if (offset)624*offset = found + len - orig_start;625return value;626}627/* feature with a value (e.g., "agent=git/1.2.3") */628else if (*value == '=') {629size_t end;630
631value++;632end = strcspn(value, " \t\n");633if (lenp)634*lenp = end;635if (offset)636*offset = value + end - orig_start;637return value;638}639/*640* otherwise we matched a substring of another feature;
641* keep looking
642*/
643}644feature_list = found + 1;645}646return NULL;647}
648
649int server_supports_hash(const char *desired, int *feature_supported)650{
651size_t offset = 0;652size_t len;653const char *hash;654
655hash = next_server_feature_value("object-format", &len, &offset);656if (feature_supported)657*feature_supported = !!hash;658if (!hash) {659hash = hash_algos[GIT_HASH_SHA1].name;660len = strlen(hash);661}662while (hash) {663if (!xstrncmpz(desired, hash, len))664return 1;665
666hash = next_server_feature_value("object-format", &len, &offset);667}668return 0;669}
670
671int parse_feature_request(const char *feature_list, const char *feature)672{
673return !!parse_feature_value(feature_list, feature, NULL, NULL);674}
675
676static const char *next_server_feature_value(const char *feature, size_t *len, size_t *offset)677{
678return parse_feature_value(server_capabilities_v1, feature, len, offset);679}
680
681const char *server_feature_value(const char *feature, size_t *len)682{
683return parse_feature_value(server_capabilities_v1, feature, len, NULL);684}
685
686int server_supports(const char *feature)687{
688return !!server_feature_value(feature, NULL);689}
690
691enum protocol {692PROTO_LOCAL = 1,693PROTO_FILE,694PROTO_SSH,695PROTO_GIT
696};697
698int url_is_local_not_ssh(const char *url)699{
700const char *colon = strchr(url, ':');701const char *slash = strchr(url, '/');702return !colon || (slash && slash < colon) ||703(has_dos_drive_prefix(url) && is_valid_path(url));704}
705
706static const char *prot_name(enum protocol protocol)707{
708switch (protocol) {709case PROTO_LOCAL:710case PROTO_FILE:711return "file";712case PROTO_SSH:713return "ssh";714case PROTO_GIT:715return "git";716default:717return "unknown protocol";718}719}
720
721static enum protocol get_protocol(const char *name)722{
723if (!strcmp(name, "ssh"))724return PROTO_SSH;725if (!strcmp(name, "git"))726return PROTO_GIT;727if (!strcmp(name, "git+ssh")) /* deprecated - do not use */728return PROTO_SSH;729if (!strcmp(name, "ssh+git")) /* deprecated - do not use */730return PROTO_SSH;731if (!strcmp(name, "file"))732return PROTO_FILE;733die(_("protocol '%s' is not supported"), name);734}
735
736static char *host_end(char **hoststart, int removebrackets)737{
738char *host = *hoststart;739char *end;740char *start = strstr(host, "@[");741if (start)742start++; /* Jump over '@' */743else744start = host;745if (start[0] == '[') {746end = strchr(start + 1, ']');747if (end) {748if (removebrackets) {749*end = 0;750memmove(start, start + 1, end - start);751end++;752}753} else754end = host;755} else756end = host;757return end;758}
759
760#define STR_(s) # s761#define STR(s) STR_(s)762
763static void get_host_and_port(char **host, const char **port)764{
765char *colon, *end;766end = host_end(host, 1);767colon = strchr(end, ':');768if (colon) {769long portnr = strtol(colon + 1, &end, 10);770if (end != colon + 1 && *end == '\0' && 0 <= portnr && portnr < 65536) {771*colon = 0;772*port = colon + 1;773} else if (!colon[1]) {774*colon = 0;775}776}777}
778
779static void enable_keepalive(int sockfd)780{
781int ka = 1;782
783if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka)) < 0)784error_errno(_("unable to set SO_KEEPALIVE on socket"));785}
786
787#ifndef NO_IPV6788
789static const char *ai_name(const struct addrinfo *ai)790{
791static char addr[NI_MAXHOST];792if (getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, sizeof(addr), NULL, 0,793NI_NUMERICHOST) != 0)794xsnprintf(addr, sizeof(addr), "(unknown)");795
796return addr;797}
798
799/*
800* Returns a connected socket() fd, or else die()s.
801*/
802static int git_tcp_connect_sock(char *host, int flags)803{
804struct strbuf error_message = STRBUF_INIT;805int sockfd = -1;806const char *port = STR(DEFAULT_GIT_PORT);807struct addrinfo hints, *ai0, *ai;808int gai;809int cnt = 0;810
811get_host_and_port(&host, &port);812if (!*port)813port = "<none>";814
815memset(&hints, 0, sizeof(hints));816if (flags & CONNECT_IPV4)817hints.ai_family = AF_INET;818else if (flags & CONNECT_IPV6)819hints.ai_family = AF_INET6;820hints.ai_socktype = SOCK_STREAM;821hints.ai_protocol = IPPROTO_TCP;822
823if (flags & CONNECT_VERBOSE)824fprintf(stderr, _("Looking up %s ... "), host);825
826gai = getaddrinfo(host, port, &hints, &ai);827if (gai)828die(_("unable to look up %s (port %s) (%s)"), host, port, gai_strerror(gai));829
830if (flags & CONNECT_VERBOSE)831/* TRANSLATORS: this is the end of "Looking up %s ... " */832fprintf(stderr, _("done.\nConnecting to %s (port %s) ... "), host, port);833
834for (ai0 = ai; ai; ai = ai->ai_next, cnt++) {835sockfd = socket(ai->ai_family,836ai->ai_socktype, ai->ai_protocol);837if ((sockfd < 0) ||838(connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0)) {839strbuf_addf(&error_message, "%s[%d: %s]: errno=%s\n",840host, cnt, ai_name(ai), strerror(errno));841if (0 <= sockfd)842close(sockfd);843sockfd = -1;844continue;845}846if (flags & CONNECT_VERBOSE)847fprintf(stderr, "%s ", ai_name(ai));848break;849}850
851freeaddrinfo(ai0);852
853if (sockfd < 0)854die(_("unable to connect to %s:\n%s"), host, error_message.buf);855
856enable_keepalive(sockfd);857
858if (flags & CONNECT_VERBOSE)859/* TRANSLATORS: this is the end of "Connecting to %s (port %s) ... " */860fprintf_ln(stderr, _("done."));861
862strbuf_release(&error_message);863
864return sockfd;865}
866
867#else /* NO_IPV6 */868
869/*
870* Returns a connected socket() fd, or else die()s.
871*/
872static int git_tcp_connect_sock(char *host, int flags)873{
874struct strbuf error_message = STRBUF_INIT;875int sockfd = -1;876const char *port = STR(DEFAULT_GIT_PORT);877char *ep;878struct hostent *he;879struct sockaddr_in sa;880char **ap;881unsigned int nport;882int cnt;883
884get_host_and_port(&host, &port);885
886if (flags & CONNECT_VERBOSE)887fprintf(stderr, _("Looking up %s ... "), host);888
889he = gethostbyname(host);890if (!he)891die(_("unable to look up %s (%s)"), host, hstrerror(h_errno));892nport = strtoul(port, &ep, 10);893if ( ep == port || *ep ) {894/* Not numeric */895struct servent *se = getservbyname(port,"tcp");896if ( !se )897die(_("unknown port %s"), port);898nport = se->s_port;899}900
901if (flags & CONNECT_VERBOSE)902/* TRANSLATORS: this is the end of "Looking up %s ... " */903fprintf(stderr, _("done.\nConnecting to %s (port %s) ... "), host, port);904
905for (cnt = 0, ap = he->h_addr_list; *ap; ap++, cnt++) {906memset(&sa, 0, sizeof sa);907sa.sin_family = he->h_addrtype;908sa.sin_port = htons(nport);909memcpy(&sa.sin_addr, *ap, he->h_length);910
911sockfd = socket(he->h_addrtype, SOCK_STREAM, 0);912if ((sockfd < 0) ||913connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {914strbuf_addf(&error_message, "%s[%d: %s]: errno=%s\n",915host,916cnt,917inet_ntoa(*(struct in_addr *)&sa.sin_addr),918strerror(errno));919if (0 <= sockfd)920close(sockfd);921sockfd = -1;922continue;923}924if (flags & CONNECT_VERBOSE)925fprintf(stderr, "%s ",926inet_ntoa(*(struct in_addr *)&sa.sin_addr));927break;928}929
930if (sockfd < 0)931die(_("unable to connect to %s:\n%s"), host, error_message.buf);932
933enable_keepalive(sockfd);934
935if (flags & CONNECT_VERBOSE)936/* TRANSLATORS: this is the end of "Connecting to %s (port %s) ... " */937fprintf_ln(stderr, _("done."));938
939return sockfd;940}
941
942#endif /* NO_IPV6 */943
944
945/*
946* Dummy child_process returned by git_connect() if the transport protocol
947* does not need fork(2).
948*/
949static struct child_process no_fork = CHILD_PROCESS_INIT;950
951int git_connection_is_socket(struct child_process *conn)952{
953return conn == &no_fork;954}
955
956static struct child_process *git_tcp_connect(int fd[2], char *host, int flags)957{
958int sockfd = git_tcp_connect_sock(host, flags);959
960fd[0] = sockfd;961fd[1] = dup(sockfd);962
963return &no_fork;964}
965
966
967static char *git_proxy_command;968
969static int git_proxy_command_options(const char *var, const char *value,970const struct config_context *ctx, void *cb)971{
972if (!strcmp(var, "core.gitproxy")) {973const char *for_pos;974int matchlen = -1;975int hostlen;976const char *rhost_name = cb;977int rhost_len = strlen(rhost_name);978
979if (git_proxy_command)980return 0;981if (!value)982return config_error_nonbool(var);983/* [core]984* ;# matches www.kernel.org as well
985* gitproxy = netcatter-1 for kernel.org
986* gitproxy = netcatter-2 for sample.xz
987* gitproxy = netcatter-default
988*/
989for_pos = strstr(value, " for ");990if (!for_pos)991/* matches everybody */992matchlen = strlen(value);993else {994hostlen = strlen(for_pos + 5);995if (rhost_len < hostlen)996matchlen = -1;997else if (!strncmp(for_pos + 5,998rhost_name + rhost_len - hostlen,999hostlen) &&1000((rhost_len == hostlen) ||1001rhost_name[rhost_len - hostlen -1] == '.'))1002matchlen = for_pos - value;1003else1004matchlen = -1;1005}1006if (0 <= matchlen) {1007/* core.gitproxy = none for kernel.org */1008if (matchlen == 4 &&1009!memcmp(value, "none", 4))1010matchlen = 0;1011git_proxy_command = xmemdupz(value, matchlen);1012}1013return 0;1014}1015
1016return git_default_config(var, value, ctx, cb);1017}
1018
1019static int git_use_proxy(const char *host)1020{
1021git_proxy_command = getenv("GIT_PROXY_COMMAND");1022git_config(git_proxy_command_options, (void*)host);1023return (git_proxy_command && *git_proxy_command);1024}
1025
1026static struct child_process *git_proxy_connect(int fd[2], char *host)1027{
1028const char *port = STR(DEFAULT_GIT_PORT);1029struct child_process *proxy;1030
1031get_host_and_port(&host, &port);1032
1033if (looks_like_command_line_option(host))1034die(_("strange hostname '%s' blocked"), host);1035if (looks_like_command_line_option(port))1036die(_("strange port '%s' blocked"), port);1037
1038proxy = xmalloc(sizeof(*proxy));1039child_process_init(proxy);1040strvec_push(&proxy->args, git_proxy_command);1041strvec_push(&proxy->args, host);1042strvec_push(&proxy->args, port);1043proxy->in = -1;1044proxy->out = -1;1045if (start_command(proxy))1046die(_("cannot start proxy %s"), git_proxy_command);1047fd[0] = proxy->out; /* read from proxy stdout */1048fd[1] = proxy->in; /* write to proxy stdin */1049return proxy;1050}
1051
1052static char *get_port(char *host)1053{
1054char *end;1055char *p = strchr(host, ':');1056
1057if (p) {1058long port = strtol(p + 1, &end, 10);1059if (end != p + 1 && *end == '\0' && 0 <= port && port < 65536) {1060*p = '\0';1061return p+1;1062}1063}1064
1065return NULL;1066}
1067
1068/*
1069* Extract protocol and relevant parts from the specified connection URL.
1070* The caller must free() the returned strings.
1071*/
1072static enum protocol parse_connect_url(const char *url_orig, char **ret_host,1073char **ret_path)1074{
1075char *url;1076char *host, *path;1077char *end;1078int separator = '/';1079enum protocol protocol = PROTO_LOCAL;1080
1081if (is_url(url_orig))1082url = url_decode(url_orig);1083else1084url = xstrdup(url_orig);1085
1086host = strstr(url, "://");1087if (host) {1088*host = '\0';1089protocol = get_protocol(url);1090host += 3;1091} else {1092host = url;1093if (!url_is_local_not_ssh(url)) {1094protocol = PROTO_SSH;1095separator = ':';1096}1097}1098
1099/*1100* Don't do destructive transforms as protocol code does
1101* '[]' unwrapping in get_host_and_port()
1102*/
1103end = host_end(&host, 0);1104
1105if (protocol == PROTO_LOCAL)1106path = end;1107else if (protocol == PROTO_FILE && *host != '/' &&1108!has_dos_drive_prefix(host) &&1109offset_1st_component(host - 2) > 1)1110path = host - 2; /* include the leading "//" */1111else if (protocol == PROTO_FILE && has_dos_drive_prefix(end))1112path = end; /* "file://$(pwd)" may be "file://C:/projects/repo" */1113else1114path = strchr(end, separator);1115
1116if (!path || !*path)1117die(_("no path specified; see 'git help pull' for valid url syntax"));1118
1119/*1120* null-terminate hostname and point path to ~ for URL's like this:
1121* ssh://host.xz/~user/repo
1122*/
1123
1124end = path; /* Need to \0 terminate host here */1125if (separator == ':')1126path++; /* path starts after ':' */1127if (protocol == PROTO_GIT || protocol == PROTO_SSH) {1128if (path[1] == '~')1129path++;1130}1131
1132path = xstrdup(path);1133*end = '\0';1134
1135*ret_host = xstrdup(host);1136*ret_path = path;1137free(url);1138return protocol;1139}
1140
1141static const char *get_ssh_command(void)1142{
1143const char *ssh;1144
1145if ((ssh = getenv("GIT_SSH_COMMAND")))1146return ssh;1147
1148if (!git_config_get_string_tmp("core.sshcommand", &ssh))1149return ssh;1150
1151return NULL;1152}
1153
1154enum ssh_variant {1155VARIANT_AUTO,1156VARIANT_SIMPLE,1157VARIANT_SSH,1158VARIANT_PLINK,1159VARIANT_PUTTY,1160VARIANT_TORTOISEPLINK,1161};1162
1163static void override_ssh_variant(enum ssh_variant *ssh_variant)1164{
1165const char *variant = getenv("GIT_SSH_VARIANT");1166
1167if (!variant && git_config_get_string_tmp("ssh.variant", &variant))1168return;1169
1170if (!strcmp(variant, "auto"))1171*ssh_variant = VARIANT_AUTO;1172else if (!strcmp(variant, "plink"))1173*ssh_variant = VARIANT_PLINK;1174else if (!strcmp(variant, "putty"))1175*ssh_variant = VARIANT_PUTTY;1176else if (!strcmp(variant, "tortoiseplink"))1177*ssh_variant = VARIANT_TORTOISEPLINK;1178else if (!strcmp(variant, "simple"))1179*ssh_variant = VARIANT_SIMPLE;1180else1181*ssh_variant = VARIANT_SSH;1182}
1183
1184static enum ssh_variant determine_ssh_variant(const char *ssh_command,1185int is_cmdline)1186{
1187enum ssh_variant ssh_variant = VARIANT_AUTO;1188const char *variant;1189char *p = NULL;1190
1191override_ssh_variant(&ssh_variant);1192
1193if (ssh_variant != VARIANT_AUTO)1194return ssh_variant;1195
1196if (!is_cmdline) {1197p = xstrdup(ssh_command);1198variant = basename(p);1199} else {1200const char **ssh_argv;1201
1202p = xstrdup(ssh_command);1203if (split_cmdline(p, &ssh_argv) > 0) {1204variant = basename((char *)ssh_argv[0]);1205/*1206* At this point, variant points into the buffer
1207* referenced by p, hence we do not need ssh_argv
1208* any longer.
1209*/
1210free(ssh_argv);1211} else {1212free(p);1213return ssh_variant;1214}1215}1216
1217if (!strcasecmp(variant, "ssh") ||1218!strcasecmp(variant, "ssh.exe"))1219ssh_variant = VARIANT_SSH;1220else if (!strcasecmp(variant, "plink") ||1221!strcasecmp(variant, "plink.exe"))1222ssh_variant = VARIANT_PLINK;1223else if (!strcasecmp(variant, "tortoiseplink") ||1224!strcasecmp(variant, "tortoiseplink.exe"))1225ssh_variant = VARIANT_TORTOISEPLINK;1226
1227free(p);1228return ssh_variant;1229}
1230
1231/*
1232* Open a connection using Git's native protocol.
1233*
1234* The caller is responsible for freeing hostandport, but this function may
1235* modify it (for example, to truncate it to remove the port part).
1236*/
1237static struct child_process *git_connect_git(int fd[2], char *hostandport,1238const char *path, const char *prog,1239enum protocol_version version,1240int flags)1241{
1242struct child_process *conn;1243struct strbuf request = STRBUF_INIT;1244/*1245* Set up virtual host information based on where we will
1246* connect, unless the user has overridden us in
1247* the environment.
1248*/
1249char *target_host = getenv("GIT_OVERRIDE_VIRTUAL_HOST");1250if (target_host)1251target_host = xstrdup(target_host);1252else1253target_host = xstrdup(hostandport);1254
1255transport_check_allowed("git");1256if (strchr(target_host, '\n') || strchr(path, '\n'))1257die(_("newline is forbidden in git:// hosts and repo paths"));1258
1259/*1260* These underlying connection commands die() if they
1261* cannot connect.
1262*/
1263if (git_use_proxy(hostandport))1264conn = git_proxy_connect(fd, hostandport);1265else1266conn = git_tcp_connect(fd, hostandport, flags);1267/*1268* Separate original protocol components prog and path
1269* from extended host header with a NUL byte.
1270*
1271* Note: Do not add any other headers here! Doing so
1272* will cause older git-daemon servers to crash.
1273*/
1274strbuf_addf(&request,1275"%s %s%chost=%s%c",1276prog, path, 0,1277target_host, 0);1278
1279/* If using a new version put that stuff here after a second null byte */1280if (version > 0) {1281strbuf_addch(&request, '\0');1282strbuf_addf(&request, "version=%d%c",1283version, '\0');1284}1285
1286packet_write(fd[1], request.buf, request.len);1287
1288free(target_host);1289strbuf_release(&request);1290return conn;1291}
1292
1293/*
1294* Append the appropriate environment variables to `env` and options to
1295* `args` for running ssh in Git's SSH-tunneled transport.
1296*/
1297static void push_ssh_options(struct strvec *args, struct strvec *env,1298enum ssh_variant variant, const char *port,1299enum protocol_version version, int flags)1300{
1301if (variant == VARIANT_SSH &&1302version > 0) {1303strvec_push(args, "-o");1304strvec_push(args, "SendEnv=" GIT_PROTOCOL_ENVIRONMENT);1305strvec_pushf(env, GIT_PROTOCOL_ENVIRONMENT "=version=%d",1306version);1307}1308
1309if (flags & CONNECT_IPV4) {1310switch (variant) {1311case VARIANT_AUTO:1312BUG("VARIANT_AUTO passed to push_ssh_options");1313case VARIANT_SIMPLE:1314die(_("ssh variant 'simple' does not support -4"));1315case VARIANT_SSH:1316case VARIANT_PLINK:1317case VARIANT_PUTTY:1318case VARIANT_TORTOISEPLINK:1319strvec_push(args, "-4");1320}1321} else if (flags & CONNECT_IPV6) {1322switch (variant) {1323case VARIANT_AUTO:1324BUG("VARIANT_AUTO passed to push_ssh_options");1325case VARIANT_SIMPLE:1326die(_("ssh variant 'simple' does not support -6"));1327case VARIANT_SSH:1328case VARIANT_PLINK:1329case VARIANT_PUTTY:1330case VARIANT_TORTOISEPLINK:1331strvec_push(args, "-6");1332}1333}1334
1335if (variant == VARIANT_TORTOISEPLINK)1336strvec_push(args, "-batch");1337
1338if (port) {1339switch (variant) {1340case VARIANT_AUTO:1341BUG("VARIANT_AUTO passed to push_ssh_options");1342case VARIANT_SIMPLE:1343die(_("ssh variant 'simple' does not support setting port"));1344case VARIANT_SSH:1345strvec_push(args, "-p");1346break;1347case VARIANT_PLINK:1348case VARIANT_PUTTY:1349case VARIANT_TORTOISEPLINK:1350strvec_push(args, "-P");1351}1352
1353strvec_push(args, port);1354}1355}
1356
1357/* Prepare a child_process for use by Git's SSH-tunneled transport. */
1358static void fill_ssh_args(struct child_process *conn, const char *ssh_host,1359const char *port, enum protocol_version version,1360int flags)1361{
1362const char *ssh;1363enum ssh_variant variant;1364
1365if (looks_like_command_line_option(ssh_host))1366die(_("strange hostname '%s' blocked"), ssh_host);1367
1368ssh = get_ssh_command();1369if (ssh) {1370variant = determine_ssh_variant(ssh, 1);1371} else {1372/*1373* GIT_SSH is the no-shell version of
1374* GIT_SSH_COMMAND (and must remain so for
1375* historical compatibility).
1376*/
1377conn->use_shell = 0;1378
1379ssh = getenv("GIT_SSH");1380if (!ssh)1381ssh = "ssh";1382variant = determine_ssh_variant(ssh, 0);1383}1384
1385if (variant == VARIANT_AUTO) {1386struct child_process detect = CHILD_PROCESS_INIT;1387
1388detect.use_shell = conn->use_shell;1389detect.no_stdin = detect.no_stdout = detect.no_stderr = 1;1390
1391strvec_push(&detect.args, ssh);1392strvec_push(&detect.args, "-G");1393push_ssh_options(&detect.args, &detect.env,1394VARIANT_SSH, port, version, flags);1395strvec_push(&detect.args, ssh_host);1396
1397variant = run_command(&detect) ? VARIANT_SIMPLE : VARIANT_SSH;1398}1399
1400strvec_push(&conn->args, ssh);1401push_ssh_options(&conn->args, &conn->env, variant, port, version,1402flags);1403strvec_push(&conn->args, ssh_host);1404}
1405
1406/*
1407* This returns the dummy child_process `no_fork` if the transport protocol
1408* does not need fork(2), or a struct child_process object if it does. Once
1409* done, finish the connection with finish_connect() with the value returned
1410* from this function (it is safe to call finish_connect() with NULL to
1411* support the former case).
1412*
1413* If it returns, the connect is successful; it just dies on errors (this
1414* will hopefully be changed in a libification effort, to return NULL when
1415* the connection failed).
1416*/
1417struct child_process *git_connect(int fd[2], const char *url,1418const char *name,1419const char *prog, int flags)1420{
1421char *hostandport, *path;1422struct child_process *conn;1423enum protocol protocol;1424enum protocol_version version = get_protocol_version_config();1425
1426/*1427* NEEDSWORK: If we are trying to use protocol v2 and we are planning
1428* to perform any operation that doesn't involve upload-pack (i.e., a
1429* fetch, ls-remote, etc), then fallback to v0 since we don't know how
1430* to do anything else (like push or remote archive) via v2.
1431*/
1432if (version == protocol_v2 && strcmp("git-upload-pack", name))1433version = protocol_v0;1434
1435/* Without this we cannot rely on waitpid() to tell1436* what happened to our children.
1437*/
1438signal(SIGCHLD, SIG_DFL);1439
1440protocol = parse_connect_url(url, &hostandport, &path);1441if ((flags & CONNECT_DIAG_URL) && (protocol != PROTO_SSH)) {1442printf("Diag: url=%s\n", url ? url : "NULL");1443printf("Diag: protocol=%s\n", prot_name(protocol));1444printf("Diag: hostandport=%s\n", hostandport ? hostandport : "NULL");1445printf("Diag: path=%s\n", path ? path : "NULL");1446conn = NULL;1447} else if (protocol == PROTO_GIT) {1448conn = git_connect_git(fd, hostandport, path, prog, version, flags);1449conn->trace2_child_class = "transport/git";1450} else {1451struct strbuf cmd = STRBUF_INIT;1452const char *const *var;1453
1454conn = xmalloc(sizeof(*conn));1455child_process_init(conn);1456
1457if (looks_like_command_line_option(path))1458die(_("strange pathname '%s' blocked"), path);1459
1460strbuf_addstr(&cmd, prog);1461strbuf_addch(&cmd, ' ');1462sq_quote_buf(&cmd, path);1463
1464/* remove repo-local variables from the environment */1465for (var = local_repo_env; *var; var++)1466strvec_push(&conn->env, *var);1467
1468conn->use_shell = 1;1469conn->in = conn->out = -1;1470if (protocol == PROTO_SSH) {1471char *ssh_host = hostandport;1472const char *port = NULL;1473transport_check_allowed("ssh");1474get_host_and_port(&ssh_host, &port);1475
1476if (!port)1477port = get_port(ssh_host);1478
1479if (flags & CONNECT_DIAG_URL) {1480printf("Diag: url=%s\n", url ? url : "NULL");1481printf("Diag: protocol=%s\n", prot_name(protocol));1482printf("Diag: userandhost=%s\n", ssh_host ? ssh_host : "NULL");1483printf("Diag: port=%s\n", port ? port : "NONE");1484printf("Diag: path=%s\n", path ? path : "NULL");1485
1486free(hostandport);1487free(path);1488free(conn);1489strbuf_release(&cmd);1490return NULL;1491}1492conn->trace2_child_class = "transport/ssh";1493fill_ssh_args(conn, ssh_host, port, version, flags);1494} else {1495transport_check_allowed("file");1496conn->trace2_child_class = "transport/file";1497if (version > 0) {1498strvec_pushf(&conn->env,1499GIT_PROTOCOL_ENVIRONMENT "=version=%d",1500version);1501}1502}1503strvec_push(&conn->args, cmd.buf);1504
1505if (start_command(conn))1506die(_("unable to fork"));1507
1508fd[0] = conn->out; /* read from child's stdout */1509fd[1] = conn->in; /* write to child's stdin */1510strbuf_release(&cmd);1511}1512free(hostandport);1513free(path);1514return conn;1515}
1516
1517int finish_connect(struct child_process *conn)1518{
1519int code;1520if (!conn || git_connection_is_socket(conn))1521return 0;1522
1523code = finish_command(conn);1524free(conn);1525return code;1526}
1527