Merge branch 'jk/git-prompt'
* jk/git-prompt: contrib: add credential helper for OS X Keychain Makefile: OS X has /dev/tty Makefile: linux has /dev/tty credential: use git_prompt instead of git_getpass prompt: use git_terminal_prompt add generic terminal prompt function refactor git_getpass into generic prompt function move git_getpass to its own source file imap-send: don't check return value of git_getpass imap-send: avoid buffer overflow Conflicts: Makefilemaint
						commit
						ded408fd20
					
				
							
								
								
									
										13
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										13
									
								
								Makefile
								
								
								
								
							|  | @ -245,6 +245,9 @@ all:: | ||||||
| # | # | ||||||
| # Define NO_REGEX if you have no or inferior regex support in your C library. | # Define NO_REGEX if you have no or inferior regex support in your C library. | ||||||
| # | # | ||||||
|  | # Define HAVE_DEV_TTY if your system can open /dev/tty to interact with the | ||||||
|  | # user. | ||||||
|  | # | ||||||
| # Define GETTEXT_POISON if you are debugging the choice of strings marked | # Define GETTEXT_POISON if you are debugging the choice of strings marked | ||||||
| # for translation.  In a GETTEXT_POISON build, you can turn all strings marked | # for translation.  In a GETTEXT_POISON build, you can turn all strings marked | ||||||
| # for translation into gibberish by setting the GIT_GETTEXT_POISON variable | # for translation into gibberish by setting the GIT_GETTEXT_POISON variable | ||||||
|  | @ -543,6 +546,7 @@ LIB_H += compat/bswap.h | ||||||
| LIB_H += compat/cygwin.h | LIB_H += compat/cygwin.h | ||||||
| LIB_H += compat/mingw.h | LIB_H += compat/mingw.h | ||||||
| LIB_H += compat/obstack.h | LIB_H += compat/obstack.h | ||||||
|  | LIB_H += compat/terminal.h | ||||||
| LIB_H += compat/win32/pthread.h | LIB_H += compat/win32/pthread.h | ||||||
| LIB_H += compat/win32/syslog.h | LIB_H += compat/win32/syslog.h | ||||||
| LIB_H += compat/win32/poll.h | LIB_H += compat/win32/poll.h | ||||||
|  | @ -585,6 +589,7 @@ LIB_H += parse-options.h | ||||||
| LIB_H += patch-ids.h | LIB_H += patch-ids.h | ||||||
| LIB_H += pkt-line.h | LIB_H += pkt-line.h | ||||||
| LIB_H += progress.h | LIB_H += progress.h | ||||||
|  | LIB_H += prompt.h | ||||||
| LIB_H += quote.h | LIB_H += quote.h | ||||||
| LIB_H += reflog-walk.h | LIB_H += reflog-walk.h | ||||||
| LIB_H += refs.h | LIB_H += refs.h | ||||||
|  | @ -632,6 +637,7 @@ LIB_OBJS += color.o | ||||||
| LIB_OBJS += combine-diff.o | LIB_OBJS += combine-diff.o | ||||||
| LIB_OBJS += commit.o | LIB_OBJS += commit.o | ||||||
| LIB_OBJS += compat/obstack.o | LIB_OBJS += compat/obstack.o | ||||||
|  | LIB_OBJS += compat/terminal.o | ||||||
| LIB_OBJS += config.o | LIB_OBJS += config.o | ||||||
| LIB_OBJS += connect.o | LIB_OBJS += connect.o | ||||||
| LIB_OBJS += connected.o | LIB_OBJS += connected.o | ||||||
|  | @ -694,6 +700,7 @@ LIB_OBJS += pkt-line.o | ||||||
| LIB_OBJS += preload-index.o | LIB_OBJS += preload-index.o | ||||||
| LIB_OBJS += pretty.o | LIB_OBJS += pretty.o | ||||||
| LIB_OBJS += progress.o | LIB_OBJS += progress.o | ||||||
|  | LIB_OBJS += prompt.o | ||||||
| LIB_OBJS += quote.o | LIB_OBJS += quote.o | ||||||
| LIB_OBJS += reachable.o | LIB_OBJS += reachable.o | ||||||
| LIB_OBJS += read-cache.o | LIB_OBJS += read-cache.o | ||||||
|  | @ -856,6 +863,7 @@ ifeq ($(uname_S),Linux) | ||||||
| 	NO_MKSTEMPS = YesPlease | 	NO_MKSTEMPS = YesPlease | ||||||
| 	HAVE_PATHS_H = YesPlease | 	HAVE_PATHS_H = YesPlease | ||||||
| 	LIBC_CONTAINS_LIBINTL = YesPlease | 	LIBC_CONTAINS_LIBINTL = YesPlease | ||||||
|  | 	HAVE_DEV_TTY = YesPlease | ||||||
| endif | endif | ||||||
| ifeq ($(uname_S),GNU/kFreeBSD) | ifeq ($(uname_S),GNU/kFreeBSD) | ||||||
| 	NO_STRLCPY = YesPlease | 	NO_STRLCPY = YesPlease | ||||||
|  | @ -917,6 +925,7 @@ ifeq ($(uname_S),Darwin) | ||||||
| 	endif | 	endif | ||||||
| 	NO_MEMMEM = YesPlease | 	NO_MEMMEM = YesPlease | ||||||
| 	USE_ST_TIMESPEC = YesPlease | 	USE_ST_TIMESPEC = YesPlease | ||||||
|  | 	HAVE_DEV_TTY = YesPlease | ||||||
| endif | endif | ||||||
| ifeq ($(uname_S),SunOS) | ifeq ($(uname_S),SunOS) | ||||||
| 	NEEDS_SOCKET = YesPlease | 	NEEDS_SOCKET = YesPlease | ||||||
|  | @ -1685,6 +1694,10 @@ ifdef HAVE_LIBCHARSET_H | ||||||
| 	BASIC_CFLAGS += -DHAVE_LIBCHARSET_H | 	BASIC_CFLAGS += -DHAVE_LIBCHARSET_H | ||||||
| endif | endif | ||||||
|  |  | ||||||
|  | ifdef HAVE_DEV_TTY | ||||||
|  | 	BASIC_CFLAGS += -DHAVE_DEV_TTY | ||||||
|  | endif | ||||||
|  |  | ||||||
| ifdef DIR_HAS_BSD_GROUP_SEMANTICS | ifdef DIR_HAS_BSD_GROUP_SEMANTICS | ||||||
| 	COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS | 	COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS | ||||||
| endif | endif | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								cache.h
								
								
								
								
							
							
						
						
									
										1
									
								
								cache.h
								
								
								
								
							|  | @ -1028,7 +1028,6 @@ struct ref { | ||||||
| extern struct ref *find_ref_by_name(const struct ref *list, const char *name); | extern struct ref *find_ref_by_name(const struct ref *list, const char *name); | ||||||
|  |  | ||||||
| #define CONNECT_VERBOSE       (1u << 0) | #define CONNECT_VERBOSE       (1u << 0) | ||||||
| extern char *git_getpass(const char *prompt); |  | ||||||
| extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags); | extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags); | ||||||
| extern int finish_connect(struct child_process *conn); | extern int finish_connect(struct child_process *conn); | ||||||
| extern int git_connection_is_socket(struct child_process *conn); | extern int git_connection_is_socket(struct child_process *conn); | ||||||
|  |  | ||||||
|  | @ -0,0 +1,81 @@ | ||||||
|  | #include "git-compat-util.h" | ||||||
|  | #include "compat/terminal.h" | ||||||
|  | #include "sigchain.h" | ||||||
|  | #include "strbuf.h" | ||||||
|  |  | ||||||
|  | #ifdef HAVE_DEV_TTY | ||||||
|  |  | ||||||
|  | static int term_fd = -1; | ||||||
|  | static struct termios old_term; | ||||||
|  |  | ||||||
|  | static void restore_term(void) | ||||||
|  | { | ||||||
|  | 	if (term_fd < 0) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	tcsetattr(term_fd, TCSAFLUSH, &old_term); | ||||||
|  | 	term_fd = -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void restore_term_on_signal(int sig) | ||||||
|  | { | ||||||
|  | 	restore_term(); | ||||||
|  | 	sigchain_pop(sig); | ||||||
|  | 	raise(sig); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | char *git_terminal_prompt(const char *prompt, int echo) | ||||||
|  | { | ||||||
|  | 	static struct strbuf buf = STRBUF_INIT; | ||||||
|  | 	int r; | ||||||
|  | 	FILE *fh; | ||||||
|  |  | ||||||
|  | 	fh = fopen("/dev/tty", "w+"); | ||||||
|  | 	if (!fh) | ||||||
|  | 		return NULL; | ||||||
|  |  | ||||||
|  | 	if (!echo) { | ||||||
|  | 		struct termios t; | ||||||
|  |  | ||||||
|  | 		if (tcgetattr(fileno(fh), &t) < 0) { | ||||||
|  | 			fclose(fh); | ||||||
|  | 			return NULL; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		old_term = t; | ||||||
|  | 		term_fd = fileno(fh); | ||||||
|  | 		sigchain_push_common(restore_term_on_signal); | ||||||
|  |  | ||||||
|  | 		t.c_lflag &= ~ECHO; | ||||||
|  | 		if (tcsetattr(fileno(fh), TCSAFLUSH, &t) < 0) { | ||||||
|  | 			term_fd = -1; | ||||||
|  | 			fclose(fh); | ||||||
|  | 			return NULL; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	fputs(prompt, fh); | ||||||
|  | 	fflush(fh); | ||||||
|  |  | ||||||
|  | 	r = strbuf_getline(&buf, fh, '\n'); | ||||||
|  | 	if (!echo) { | ||||||
|  | 		putc('\n', fh); | ||||||
|  | 		fflush(fh); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	restore_term(); | ||||||
|  | 	fclose(fh); | ||||||
|  |  | ||||||
|  | 	if (r == EOF) | ||||||
|  | 		return NULL; | ||||||
|  | 	return buf.buf; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #else | ||||||
|  |  | ||||||
|  | char *git_terminal_prompt(const char *prompt, int echo) | ||||||
|  | { | ||||||
|  | 	return getpass(prompt); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | #ifndef COMPAT_TERMINAL_H | ||||||
|  | #define COMPAT_TERMINAL_H | ||||||
|  |  | ||||||
|  | char *git_terminal_prompt(const char *prompt, int echo); | ||||||
|  |  | ||||||
|  | #endif /* COMPAT_TERMINAL_H */ | ||||||
							
								
								
									
										44
									
								
								connect.c
								
								
								
								
							
							
						
						
									
										44
									
								
								connect.c
								
								
								
								
							|  | @ -608,47 +608,3 @@ int finish_connect(struct child_process *conn) | ||||||
| 	free(conn); | 	free(conn); | ||||||
| 	return code; | 	return code; | ||||||
| } | } | ||||||
|  |  | ||||||
| char *git_getpass(const char *prompt) |  | ||||||
| { |  | ||||||
| 	const char *askpass; |  | ||||||
| 	struct child_process pass; |  | ||||||
| 	const char *args[3]; |  | ||||||
| 	static struct strbuf buffer = STRBUF_INIT; |  | ||||||
|  |  | ||||||
| 	askpass = getenv("GIT_ASKPASS"); |  | ||||||
| 	if (!askpass) |  | ||||||
| 		askpass = askpass_program; |  | ||||||
| 	if (!askpass) |  | ||||||
| 		askpass = getenv("SSH_ASKPASS"); |  | ||||||
| 	if (!askpass || !(*askpass)) { |  | ||||||
| 		char *result = getpass(prompt); |  | ||||||
| 		if (!result) |  | ||||||
| 			die_errno("Could not read password"); |  | ||||||
| 		return result; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	args[0] = askpass; |  | ||||||
| 	args[1]	= prompt; |  | ||||||
| 	args[2] = NULL; |  | ||||||
|  |  | ||||||
| 	memset(&pass, 0, sizeof(pass)); |  | ||||||
| 	pass.argv = args; |  | ||||||
| 	pass.out = -1; |  | ||||||
|  |  | ||||||
| 	if (start_command(&pass)) |  | ||||||
| 		exit(1); |  | ||||||
|  |  | ||||||
| 	strbuf_reset(&buffer); |  | ||||||
| 	if (strbuf_read(&buffer, pass.out, 20) < 0) |  | ||||||
| 		die("failed to read password from %s\n", askpass); |  | ||||||
|  |  | ||||||
| 	close(pass.out); |  | ||||||
|  |  | ||||||
| 	if (finish_command(&pass)) |  | ||||||
| 		exit(1); |  | ||||||
|  |  | ||||||
| 	strbuf_setlen(&buffer, strcspn(buffer.buf, "\r\n")); |  | ||||||
|  |  | ||||||
| 	return buffer.buf; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | git-credential-osxkeychain | ||||||
|  | @ -0,0 +1,14 @@ | ||||||
|  | all:: git-credential-osxkeychain | ||||||
|  |  | ||||||
|  | CC = gcc | ||||||
|  | RM = rm -f | ||||||
|  | CFLAGS = -g -Wall | ||||||
|  |  | ||||||
|  | git-credential-osxkeychain: git-credential-osxkeychain.o | ||||||
|  | 	$(CC) -o $@ $< -Wl,-framework -Wl,Security | ||||||
|  |  | ||||||
|  | git-credential-osxkeychain.o: git-credential-osxkeychain.c | ||||||
|  | 	$(CC) -c $(CFLAGS) $< | ||||||
|  |  | ||||||
|  | clean: | ||||||
|  | 	$(RM) git-credential-osxkeychain git-credential-osxkeychain.o | ||||||
|  | @ -0,0 +1,173 @@ | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <Security/Security.h> | ||||||
|  |  | ||||||
|  | static SecProtocolType protocol; | ||||||
|  | static char *host; | ||||||
|  | static char *path; | ||||||
|  | static char *username; | ||||||
|  | static char *password; | ||||||
|  | static UInt16 port; | ||||||
|  |  | ||||||
|  | static void die(const char *err, ...) | ||||||
|  | { | ||||||
|  | 	char msg[4096]; | ||||||
|  | 	va_list params; | ||||||
|  | 	va_start(params, err); | ||||||
|  | 	vsnprintf(msg, sizeof(msg), err, params); | ||||||
|  | 	fprintf(stderr, "%s\n", msg); | ||||||
|  | 	va_end(params); | ||||||
|  | 	exit(1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void *xstrdup(const char *s1) | ||||||
|  | { | ||||||
|  | 	void *ret = strdup(s1); | ||||||
|  | 	if (!ret) | ||||||
|  | 		die("Out of memory"); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #define KEYCHAIN_ITEM(x) (x ? strlen(x) : 0), x | ||||||
|  | #define KEYCHAIN_ARGS \ | ||||||
|  | 	NULL, /* default keychain */ \ | ||||||
|  | 	KEYCHAIN_ITEM(host), \ | ||||||
|  | 	0, NULL, /* account domain */ \ | ||||||
|  | 	KEYCHAIN_ITEM(username), \ | ||||||
|  | 	KEYCHAIN_ITEM(path), \ | ||||||
|  | 	port, \ | ||||||
|  | 	protocol, \ | ||||||
|  | 	kSecAuthenticationTypeDefault | ||||||
|  |  | ||||||
|  | static void write_item(const char *what, const char *buf, int len) | ||||||
|  | { | ||||||
|  | 	printf("%s=", what); | ||||||
|  | 	fwrite(buf, 1, len, stdout); | ||||||
|  | 	putchar('\n'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void find_username_in_item(SecKeychainItemRef item) | ||||||
|  | { | ||||||
|  | 	SecKeychainAttributeList list; | ||||||
|  | 	SecKeychainAttribute attr; | ||||||
|  |  | ||||||
|  | 	list.count = 1; | ||||||
|  | 	list.attr = &attr; | ||||||
|  | 	attr.tag = kSecAccountItemAttr; | ||||||
|  |  | ||||||
|  | 	if (SecKeychainItemCopyContent(item, NULL, &list, NULL, NULL)) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	write_item("username", attr.data, attr.length); | ||||||
|  | 	SecKeychainItemFreeContent(&list, NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void find_internet_password(void) | ||||||
|  | { | ||||||
|  | 	void *buf; | ||||||
|  | 	UInt32 len; | ||||||
|  | 	SecKeychainItemRef item; | ||||||
|  |  | ||||||
|  | 	if (SecKeychainFindInternetPassword(KEYCHAIN_ARGS, &len, &buf, &item)) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	write_item("password", buf, len); | ||||||
|  | 	if (!username) | ||||||
|  | 		find_username_in_item(item); | ||||||
|  |  | ||||||
|  | 	SecKeychainItemFreeContent(NULL, buf); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void delete_internet_password(void) | ||||||
|  | { | ||||||
|  | 	SecKeychainItemRef item; | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 	 * Require at least a protocol and host for removal, which is what git | ||||||
|  | 	 * will give us; if you want to do something more fancy, use the | ||||||
|  | 	 * Keychain manager. | ||||||
|  | 	 */ | ||||||
|  | 	if (!protocol || !host) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	if (SecKeychainFindInternetPassword(KEYCHAIN_ARGS, 0, NULL, &item)) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	SecKeychainItemDelete(item); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void add_internet_password(void) | ||||||
|  | { | ||||||
|  | 	/* Only store complete credentials */ | ||||||
|  | 	if (!protocol || !host || !username || !password) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	if (SecKeychainAddInternetPassword( | ||||||
|  | 	      KEYCHAIN_ARGS, | ||||||
|  | 	      KEYCHAIN_ITEM(password), | ||||||
|  | 	      NULL)) | ||||||
|  | 		return; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void read_credential(void) | ||||||
|  | { | ||||||
|  | 	char buf[1024]; | ||||||
|  |  | ||||||
|  | 	while (fgets(buf, sizeof(buf), stdin)) { | ||||||
|  | 		char *v; | ||||||
|  |  | ||||||
|  | 		if (!strcmp(buf, "\n")) | ||||||
|  | 			break; | ||||||
|  | 		buf[strlen(buf)-1] = '\0'; | ||||||
|  |  | ||||||
|  | 		v = strchr(buf, '='); | ||||||
|  | 		if (!v) | ||||||
|  | 			die("bad input: %s", buf); | ||||||
|  | 		*v++ = '\0'; | ||||||
|  |  | ||||||
|  | 		if (!strcmp(buf, "protocol")) { | ||||||
|  | 			if (!strcmp(v, "https")) | ||||||
|  | 				protocol = kSecProtocolTypeHTTPS; | ||||||
|  | 			else if (!strcmp(v, "http")) | ||||||
|  | 				protocol = kSecProtocolTypeHTTP; | ||||||
|  | 			else /* we don't yet handle other protocols */ | ||||||
|  | 				exit(0); | ||||||
|  | 		} | ||||||
|  | 		else if (!strcmp(buf, "host")) { | ||||||
|  | 			char *colon = strchr(v, ':'); | ||||||
|  | 			if (colon) { | ||||||
|  | 				*colon++ = '\0'; | ||||||
|  | 				port = atoi(colon); | ||||||
|  | 			} | ||||||
|  | 			host = xstrdup(v); | ||||||
|  | 		} | ||||||
|  | 		else if (!strcmp(buf, "path")) | ||||||
|  | 			path = xstrdup(v); | ||||||
|  | 		else if (!strcmp(buf, "username")) | ||||||
|  | 			username = xstrdup(v); | ||||||
|  | 		else if (!strcmp(buf, "password")) | ||||||
|  | 			password = xstrdup(v); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int main(int argc, const char **argv) | ||||||
|  | { | ||||||
|  | 	const char *usage = | ||||||
|  | 		"Usage: git credential-osxkeychain <get|store|erase>"; | ||||||
|  |  | ||||||
|  | 	if (!argv[1]) | ||||||
|  | 		die(usage); | ||||||
|  |  | ||||||
|  | 	read_credential(); | ||||||
|  |  | ||||||
|  | 	if (!strcmp(argv[1], "get")) | ||||||
|  | 		find_internet_password(); | ||||||
|  | 	else if (!strcmp(argv[1], "store")) | ||||||
|  | 		add_internet_password(); | ||||||
|  | 	else if (!strcmp(argv[1], "erase")) | ||||||
|  | 		delete_internet_password(); | ||||||
|  | 	/* otherwise, ignore unknown action */ | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								credential.c
								
								
								
								
							
							
						
						
									
										16
									
								
								credential.c
								
								
								
								
							|  | @ -3,6 +3,7 @@ | ||||||
| #include "string-list.h" | #include "string-list.h" | ||||||
| #include "run-command.h" | #include "run-command.h" | ||||||
| #include "url.h" | #include "url.h" | ||||||
|  | #include "prompt.h" | ||||||
|  |  | ||||||
| void credential_init(struct credential *c) | void credential_init(struct credential *c) | ||||||
| { | { | ||||||
|  | @ -108,7 +109,8 @@ static void credential_describe(struct credential *c, struct strbuf *out) | ||||||
| 		strbuf_addf(out, "/%s", c->path); | 		strbuf_addf(out, "/%s", c->path); | ||||||
| } | } | ||||||
|  |  | ||||||
| static char *credential_ask_one(const char *what, struct credential *c) | static char *credential_ask_one(const char *what, struct credential *c, | ||||||
|  | 				int flags) | ||||||
| { | { | ||||||
| 	struct strbuf desc = STRBUF_INIT; | 	struct strbuf desc = STRBUF_INIT; | ||||||
| 	struct strbuf prompt = STRBUF_INIT; | 	struct strbuf prompt = STRBUF_INIT; | ||||||
|  | @ -120,11 +122,7 @@ static char *credential_ask_one(const char *what, struct credential *c) | ||||||
| 	else | 	else | ||||||
| 		strbuf_addf(&prompt, "%s: ", what); | 		strbuf_addf(&prompt, "%s: ", what); | ||||||
|  |  | ||||||
| 	/* FIXME: for usernames, we should do something less magical that | 	r = git_prompt(prompt.buf, flags); | ||||||
| 	 * actually echoes the characters. However, we need to read from |  | ||||||
| 	 * /dev/tty and not stdio, which is not portable (but getpass will do |  | ||||||
| 	 * it for us). http.c uses the same workaround. */ |  | ||||||
| 	r = git_getpass(prompt.buf); |  | ||||||
|  |  | ||||||
| 	strbuf_release(&desc); | 	strbuf_release(&desc); | ||||||
| 	strbuf_release(&prompt); | 	strbuf_release(&prompt); | ||||||
|  | @ -134,9 +132,11 @@ static char *credential_ask_one(const char *what, struct credential *c) | ||||||
| static void credential_getpass(struct credential *c) | static void credential_getpass(struct credential *c) | ||||||
| { | { | ||||||
| 	if (!c->username) | 	if (!c->username) | ||||||
| 		c->username = credential_ask_one("Username", c); | 		c->username = credential_ask_one("Username", c, | ||||||
|  | 						 PROMPT_ASKPASS|PROMPT_ECHO); | ||||||
| 	if (!c->password) | 	if (!c->password) | ||||||
| 		c->password = credential_ask_one("Password", c); | 		c->password = credential_ask_one("Password", c, | ||||||
|  | 						 PROMPT_ASKPASS); | ||||||
| } | } | ||||||
|  |  | ||||||
| int credential_read(struct credential *c, FILE *fp) | int credential_read(struct credential *c, FILE *fp) | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								imap-send.c
								
								
								
								
							
							
						
						
									
										12
									
								
								imap-send.c
								
								
								
								
							|  | @ -25,6 +25,7 @@ | ||||||
| #include "cache.h" | #include "cache.h" | ||||||
| #include "exec_cmd.h" | #include "exec_cmd.h" | ||||||
| #include "run-command.h" | #include "run-command.h" | ||||||
|  | #include "prompt.h" | ||||||
| #ifdef NO_OPENSSL | #ifdef NO_OPENSSL | ||||||
| typedef void *SSL; | typedef void *SSL; | ||||||
| #else | #else | ||||||
|  | @ -1208,13 +1209,10 @@ static struct store *imap_open_store(struct imap_server_conf *srvc) | ||||||
| 			goto bail; | 			goto bail; | ||||||
| 		} | 		} | ||||||
| 		if (!srvc->pass) { | 		if (!srvc->pass) { | ||||||
| 			char prompt[80]; | 			struct strbuf prompt = STRBUF_INIT; | ||||||
| 			sprintf(prompt, "Password (%s@%s): ", srvc->user, srvc->host); | 			strbuf_addf(&prompt, "Password (%s@%s): ", srvc->user, srvc->host); | ||||||
| 			arg = git_getpass(prompt); | 			arg = git_getpass(prompt.buf); | ||||||
| 			if (!arg) { | 			strbuf_release(&prompt); | ||||||
| 				perror("getpass"); |  | ||||||
| 				exit(1); |  | ||||||
| 			} |  | ||||||
| 			if (!*arg) { | 			if (!*arg) { | ||||||
| 				fprintf(stderr, "Skipping account %s@%s, no password\n", srvc->user, srvc->host); | 				fprintf(stderr, "Skipping account %s@%s, no password\n", srvc->user, srvc->host); | ||||||
| 				goto bail; | 				goto bail; | ||||||
|  |  | ||||||
|  | @ -0,0 +1,63 @@ | ||||||
|  | #include "cache.h" | ||||||
|  | #include "run-command.h" | ||||||
|  | #include "strbuf.h" | ||||||
|  | #include "prompt.h" | ||||||
|  | #include "compat/terminal.h" | ||||||
|  |  | ||||||
|  | static char *do_askpass(const char *cmd, const char *prompt) | ||||||
|  | { | ||||||
|  | 	struct child_process pass; | ||||||
|  | 	const char *args[3]; | ||||||
|  | 	static struct strbuf buffer = STRBUF_INIT; | ||||||
|  |  | ||||||
|  | 	args[0] = cmd; | ||||||
|  | 	args[1]	= prompt; | ||||||
|  | 	args[2] = NULL; | ||||||
|  |  | ||||||
|  | 	memset(&pass, 0, sizeof(pass)); | ||||||
|  | 	pass.argv = args; | ||||||
|  | 	pass.out = -1; | ||||||
|  |  | ||||||
|  | 	if (start_command(&pass)) | ||||||
|  | 		exit(1); | ||||||
|  |  | ||||||
|  | 	strbuf_reset(&buffer); | ||||||
|  | 	if (strbuf_read(&buffer, pass.out, 20) < 0) | ||||||
|  | 		die("failed to get '%s' from %s\n", prompt, cmd); | ||||||
|  |  | ||||||
|  | 	close(pass.out); | ||||||
|  |  | ||||||
|  | 	if (finish_command(&pass)) | ||||||
|  | 		exit(1); | ||||||
|  |  | ||||||
|  | 	strbuf_setlen(&buffer, strcspn(buffer.buf, "\r\n")); | ||||||
|  |  | ||||||
|  | 	return buffer.buf; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | char *git_prompt(const char *prompt, int flags) | ||||||
|  | { | ||||||
|  | 	char *r; | ||||||
|  |  | ||||||
|  | 	if (flags & PROMPT_ASKPASS) { | ||||||
|  | 		const char *askpass; | ||||||
|  |  | ||||||
|  | 		askpass = getenv("GIT_ASKPASS"); | ||||||
|  | 		if (!askpass) | ||||||
|  | 			askpass = askpass_program; | ||||||
|  | 		if (!askpass) | ||||||
|  | 			askpass = getenv("SSH_ASKPASS"); | ||||||
|  | 		if (askpass && *askpass) | ||||||
|  | 			return do_askpass(askpass, prompt); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	r = git_terminal_prompt(prompt, flags & PROMPT_ECHO); | ||||||
|  | 	if (!r) | ||||||
|  | 		die_errno("could not read '%s'", prompt); | ||||||
|  | 	return r; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | char *git_getpass(const char *prompt) | ||||||
|  | { | ||||||
|  | 	return git_prompt(prompt, PROMPT_ASKPASS); | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano