Commit Diff


commit - f9d09706c26867a700fc666e9809f029520f5848
commit + 0d6b67e271d1f497a862858fce73c5a9b430ef11
blob - 80fc725d32a21c67dbac7e260514e2a352c549cd
blob + 8aab8d4e3b63b817ca0ccd4dcfbf8160525c18f5
--- gotsh/gotsh.c
+++ gotsh/gotsh.c
@@ -72,31 +72,25 @@ apply_unveil(const char *unix_socket_path)
 
 /* Read session URL from gotwebd's auth socket and send it to the client. */
 static const struct got_error *
-weblogin(int outfd, int sock, const char *hostname)
+weblogin(FILE *out, int sock, const char *hostname)
 {
 	const struct got_error *err = NULL;
-	char *url = NULL, *greeting = NULL;
-	char buf[_POSIX_HOST_NAME_MAX + 2];
-	size_t size, remain;
+	FILE *fp;
 	int ret;
+	char *line = NULL;
+	size_t linesize;
+	ssize_t linelen;
 
-	if (hostname) {
-		/*
-		 * Send the desired hostname to gotwebd.
-		 * gotwebd reads up to _POSIX_HOST_NAME_MAX + 1 bytes, terminated
-		 * by a linefeed, \n.
-		 */
-		ret = snprintf(buf, sizeof(buf), "login %s\n", hostname);
-	} else
-		ret = snprintf(buf, sizeof(buf), "login\n");
-	if (ret == -1)
-		return got_error_from_errno("snprintf");
-	if ((size_t)ret >= sizeof(buf))
-		return got_error(GOT_ERR_NO_SPACE);
+	fp = fdopen(sock, "w+");
+	if (fp == NULL)
+		return got_error_from_errno("fdopen");
 
-	err = got_poll_write_full(sock, buf, ret);
-	if (err)
-		return err;
+	ret = fprintf(fp, "login%s%s\n", hostname != NULL ? " " : "",
+	    hostname != NULL ? hostname : "");
+	if (ret < 0) {
+		err = got_error_from_errno("fprintf");
+		goto done;
+	}
 
 	/*
 	 * gotwebd will return "ok URL", likewise terminated by \n,
@@ -105,83 +99,32 @@ weblogin(int outfd, int sock, const char *hostname)
 	 * in chunks until we have read all of it.
 	 * For forward compatibilty, ignore any trailing lines received.
 	 */
-	url = calloc(1, sizeof(buf));
-	if (url == NULL)
-		return got_error_from_errno("calloc");
+	linelen = getline(&line, &linesize, fp);
+	if (linelen == -1) {
+		err = got_error(GOT_ERR_EOF);
+		if (ferror(fp))
+			err = got_error_from_errno("getline");
+		goto done;
+	}
 
-	size = sizeof(buf);
-	remain = size;
-
-	memset(buf, 0, sizeof(buf)); /* reusing buf with strlcat below */
-
-	for (;;) {
-		size_t len;
-		char *eol;
-
-		err = got_poll_read_full(sock, &len, buf, sizeof(buf) - 1, 1);
-		if (err)
-			goto done;
-
-		if (len == 0) {
-			err = got_error(GOT_ERR_EOF);
-			goto done;
-		} else if (len >= remain) { /* should not happen */
-			err = got_error(GOT_ERR_NO_SPACE);
-			goto done;
-		}
-
-		buf[len] = '\0';
+	if (strncmp(line, "ok ", 3) == 0) {
+		fprintf(out, "Login successful.  Please visit the following "
+		    "URL within the next %d minutes: %s\n",
+		    GOTWEBD_AUTH_TIMEOUT / 60, line + 3);
+		goto done;
+	}
 
-		eol = memchr(buf, '\n', len);
-		if (eol)
-			*eol = '\0';
-
-		if (strlcat(url, buf, size) >= size) {
-			err = got_error(GOT_ERR_NO_SPACE);
-			goto done;
-		}
-
-		if (eol)
-			break;
-
-		remain -= len;
-		if (remain < sizeof(buf)) {
-			size_t newsize = size + sizeof(buf);
-			char *p;
-
-			p = realloc(url, newsize);
-			if (p == NULL) {
-				err = got_error_from_errno("realloc");
-				goto done;
-			}
-			url = p;
-			size = newsize;
-			remain += sizeof(buf);
-		}
+	if (strncmp(line, "err ", 4) == 0) {
+		err = got_error_fmt(GOT_ERR_AUTH_FAILED, "%s", line + 4);
+		goto done;
 	}
 
-	if (strncmp(url, "ok ", 3) == 0) {
-		if (asprintf(&greeting, "Login successful. Please visit the "
-		    "following URL within the next %d minutes: ",
-		    GOTWEBD_AUTH_TIMEOUT / 60) == -1) {
-			err = got_error_from_errno("asprintf");
-			goto done;
-		}
-		err = got_poll_write_full(outfd, greeting, strlen(greeting));
-		if (err)
-			goto done;
-		err = got_poll_write_full(outfd, url + 3, strlen(url) - 3);
-	} else
-		err = got_poll_write_full(outfd, url, strlen(url));
+	err = got_error(GOT_ERR_UNKNOWN_COMMAND);
 done:
-	if (err && err->code != GOT_ERR_EOF) {
-		const struct got_error *err2;
-
-		err2 = got_error_fmt(err->code, "%s", getprogname());
-		got_poll_write_full(outfd, err2->msg, strlen(err2->msg));
-	}
-	free(url);
-	free(greeting);
+	if (line != NULL)
+		free(line);
+	if (fp != NULL && fclose(fp) == EOF && err == NULL)
+		err = got_error_from_errno("fclose");
 	return err;
 }
 
@@ -344,7 +287,7 @@ main(int argc, char *argv[])
 		if (pledge("stdio", NULL) == -1)
 			err(1, "pledge");
 #endif
-		error = weblogin(STDOUT_FILENO, sock, hostname);
+		error = weblogin(stdout, sock, hostname);
 	} else {
 #ifndef PROFILE
 		if (pledge("stdio recvfd", NULL) == -1)
blob - 870e76a6fec7cb1fd96cdd2f47457c6ab86988d8
blob + 5f07c0e62e56e9d031e63207e86c09c7d8370d3e
--- include/got_error.h
+++ include/got_error.h
@@ -196,6 +196,8 @@
 #define GOT_ERR_GROUP_EXISTS	179
 #define GOT_ERR_AUTHORIZED_KEY	180
 #define GOT_ERR_CONNECTION_LIMIT 190
+#define GOT_ERR_AUTH_FAILED	191
+#define GOT_ERR_UNKNOWN_COMMAND	192
 
 struct got_error {
         int code;
blob - 922cdad6e22538c24d67ad78bf152e9edef33f49
blob + d08ece89944ab437a2407f75eb9b3513f6b34eaa
--- lib/error.c
+++ lib/error.c
@@ -247,6 +247,8 @@ static const struct got_error got_errors[] = {
 	{ GOT_ERR_GROUP_EXISTS, "group already exists" },
 	{ GOT_ERR_AUTHORIZED_KEY, "no authorized key found" },
 	{ GOT_ERR_CONNECTION_LIMIT, "connection limit exceeded" },
+	{ GOT_ERR_AUTH_FAILED, "authentication failed" },
+	{ GOT_ERR_UNKNOWN_COMMAND, "unknown command" },
 };
 
 static struct got_custom_error {