+#include <arpa/inet.h>
+#include <syslog.h>
+#include "pkt-line.h"
+#include "cache.h"
+
+static int log_syslog;
+static int verbose;
+
+static const char daemon_usage[] =
+"git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n"
+" [--timeout=n] [--init-timeout=n] [--strict-paths] [directory...]";
+
+/* List of acceptable pathname prefixes */
+static char **ok_paths = NULL;
+static int strict_paths = 0;
+
+/* If this is set, git-daemon-export-ok is not required */
+static int export_all_trees = 0;
+
+/* Timeout, and initial timeout */
+static unsigned int timeout = 0;
+static unsigned int init_timeout = 0;
+
+static void logreport(int priority, const char *err, va_list params)
+{
+ /* We should do a single write so that it is atomic and output
+ * of several processes do not get intermingled. */
+ char buf[1024];
+ int buflen;
+ int maxlen, msglen;
+
+ /* sizeof(buf) should be big enough for "[pid] \n" */
+ buflen = snprintf(buf, sizeof(buf), "[%ld] ", (long) getpid());
+
+ maxlen = sizeof(buf) - buflen - 1; /* -1 for our own LF */
+ msglen = vsnprintf(buf + buflen, maxlen, err, params);
+
+ if (log_syslog) {
+ syslog(priority, "%s", buf);
+ return;
+ }
+
+ /* maxlen counted our own LF but also counts space given to
+ * vsnprintf for the terminating NUL. We want to make sure that
+ * we have space for our own LF and NUL after the "meat" of the
+ * message, so truncate it at maxlen - 1.
+ */
+ if (msglen > maxlen - 1)
+ msglen = maxlen - 1;
+ else if (msglen < 0)
+ msglen = 0; /* Protect against weird return values. */
+ buflen += msglen;
+
+ buf[buflen++] = '\n';
+ buf[buflen] = '\0';
+
+ write(2, buf, buflen);
+}
+
+static void logerror(const char *err, ...)
+{
+ va_list params;
+ va_start(params, err);
+ logreport(LOG_ERR, err, params);
+ va_end(params);
+}
+
+static void loginfo(const char *err, ...)
+{
+ va_list params;
+ if (!verbose)
+ return;
+ va_start(params, err);
+ logreport(LOG_INFO, err, params);
+ va_end(params);
+}
+
+static int avoid_alias(char *p)
+{
+ int sl, ndot;
+
+ /*
+ * This resurrects the belts and suspenders paranoia check by HPA
+ * done in <435560F7.4080006@zytor.com> thread, now enter_repo()
+ * does not do getcwd() based path canonicalizations.
+ *
+ * sl becomes true immediately after seeing '/' and continues to
+ * be true as long as dots continue after that without intervening
+ * non-dot character.
+ */
+ if (!p || (*p != '/' && *p != '~'))
+ return -1;
+ sl = 1; ndot = 0;
+ p++;
+
+ while (1) {
+ char ch = *p++;
+ if (sl) {
+ if (ch == '.')
+ ndot++;
+ else if (ch == '/') {
+ if (ndot < 3)
+ /* reject //, /./ and /../ */
+ return -1;
+ ndot = 0;
+ }
+ else if (ch == 0) {
+ if (0 < ndot && ndot < 3)
+ /* reject /.$ and /..$ */
+ return -1;
+ return 0;
+ }
+ else
+ sl = ndot = 0;
+ }
+ else if (ch == 0)
+ return 0;
+ else if (ch == '/') {
+ sl = 1;
+ ndot = 0;
+ }
+ }
+}
+
+static char *path_ok(char *dir)
+{
+ char *path;
+
+ if (avoid_alias(dir)) {
+ logerror("'%s': aliased", dir);
+ return NULL;
+ }
+
+ path = enter_repo(dir, strict_paths);
+
+ if (!path) {
+ logerror("'%s': unable to chdir or not a git archive", dir);
+ return NULL;
+ }
+
+ if ( ok_paths && *ok_paths ) {
+ char **pp;
+ int pathlen = strlen(path);
+
+ /* The validation is done on the paths after enter_repo
+ * appends optional {.git,.git/.git} and friends, but
+ * it does not use getcwd(). So if your /pub is
+ * a symlink to /mnt/pub, you can whitelist /pub and
+ * do not have to say /mnt/pub.
+ * Do not say /pub/.
+ */
+ for ( pp = ok_paths ; *pp ; pp++ ) {
+ int len = strlen(*pp);
+ if (len <= pathlen &&
+ !memcmp(*pp, path, len) &&
+ (path[len] == '\0' ||
+ (!strict_paths && path[len] == '/')))
+ return path;
+ }
+ }
+ else {
+ /* be backwards compatible */
+ if (!strict_paths)
+ return path;
+ }