Beispiel #1
0
void *events_clientize(void *param) {
	logprintf(LOG_STACK, "%s(...)", __FUNCTION__);

	unsigned int failures = 0;
	while(loop && failures <= 5) {
		struct ssdp_list_t *ssdp_list = NULL;
		int standalone = 0;
		settings_find_number("standalone", &standalone);
		if(ssdp_seek(&ssdp_list) == -1 || standalone == 1) {
			logprintf(LOG_DEBUG, "no pilight ssdp connections found");
			char server[16] = "127.0.0.1";
			if((sockfd = socket_connect(server, (unsigned short)socket_get_port())) == -1) {
				logprintf(LOG_DEBUG, "could not connect to pilight-daemon");
				failures++;
				continue;
			}
		} else {
			if((sockfd = socket_connect(ssdp_list->ip, ssdp_list->port)) == -1) {
				logprintf(LOG_DEBUG, "could not connect to pilight-daemon");
				failures++;
				continue;
			}
		}
		if(ssdp_list) {
			ssdp_free(ssdp_list);
		}

		struct JsonNode *jclient = json_mkobject();
		struct JsonNode *joptions = json_mkobject();
		json_append_member(jclient, "action", json_mkstring("identify"));
		json_append_member(joptions, "config", json_mknumber(1, 0));
		json_append_member(jclient, "options", joptions);
		json_append_member(jclient, "media", json_mkstring("all"));
		char *out = json_stringify(jclient, NULL);
		socket_write(sockfd, out);
		json_free(out);
		json_delete(jclient);

		if(socket_read(sockfd, &recvBuff, 0) != 0
			 || strcmp(recvBuff, "{\"status\":\"success\"}") != 0) {
				failures++;
			continue;
		}
		failures = 0;
		while(loop) {
			if(socket_read(sockfd, &recvBuff, 0) != 0) {
				break;
			} else {
				events_queue(recvBuff);
			}
		}
	}

	if(recvBuff) {
		FREE(recvBuff);
		recvBuff = NULL;
	}
	socket_close(sockfd);
	return 0;
}
Beispiel #2
0
static void
doit (const char *nodename, const char *servname)
{
    struct addrinfo hints;
    struct addrinfo *res, *r;
    int ret;

    if (verbose_counter)
	printf ("(%s,%s)... ", nodename ? nodename : "null", servname);

    memset (&hints, 0, sizeof(hints));
    hints.ai_flags    = flags;
    hints.ai_family   = family;
    hints.ai_socktype = socktype;

    ret = getaddrinfo (nodename, servname, &hints, &res);
    if (ret)
	errx(1, "error: %s\n", gai_strerror(ret));

    if (verbose_counter)
	printf ("\n");

    for (r = res; r != NULL; r = r->ai_next) {
	char addrstr[256];

	if (inet_ntop (r->ai_family,
		       socket_get_address (r->ai_addr),
		       addrstr, sizeof(addrstr)) == NULL) {
	    if (verbose_counter)
		printf ("\tbad address?\n");
	    continue;
	}
	if (verbose_counter) {
	    printf ("\tfamily = %d, socktype = %d, protocol = %d, "
		    "address = \"%s\", port = %d",
		    r->ai_family, r->ai_socktype, r->ai_protocol,
		    addrstr,
		    ntohs(socket_get_port (r->ai_addr)));
	    if (r->ai_canonname)
		printf (", canonname = \"%s\"", r->ai_canonname);
	    printf ("\n");
	}
    }
    freeaddrinfo (res);
}
Beispiel #3
0
static krb5_error_code
add_locate(void *ctx, int type, struct sockaddr *addr)
{
    struct krb5_krbhst_data *kd = ctx;
    char host[NI_MAXHOST], port[NI_MAXSERV];
    socklen_t socklen;
    krb5_error_code ret;
    int proto, portnum;

    socklen = socket_sockaddr_size(addr);
    portnum = socket_get_port(addr);

    ret = getnameinfo(addr, socklen, host, sizeof(host), port, sizeof(port),
		      NI_NUMERICHOST|NI_NUMERICSERV);
    if (ret != 0)
	return 0;

    if (kd->port)
	snprintf(port, sizeof(port), "%d", kd->port);
    else if (atoi(port) == 0)
	snprintf(port, sizeof(port), "%d", krbhst_get_default_port(kd));

    proto = krbhst_get_default_proto(kd);

    ret = add_plugin_host(kd, host, port, portnum, proto);
    if (ret)
	return ret;

    /*
     * This is really kind of broken and should be solved a different
     * way, some sites block UDP, and we don't, in the general case,
     * fall back to TCP, that should also be done. But since that
     * should require us to invert the whole "find kdc" stack, let put
     * this in for now. 
     */

    if (proto == KRB5_KRBHST_UDP) {
	ret = add_plugin_host(kd, host, port, portnum, KRB5_KRBHST_TCP);
	if (ret)
	    return ret;
    }

    return 0;
}
Beispiel #4
0
static int
wait_log(struct client *c)
{
    int32_t port;
    struct sockaddr_storage sast;
    socklen_t salen = sizeof(sast);
    int fd, fd2, ret;

    memset(&sast, 0, sizeof(sast));

    assert(sizeof(sast) >= c->salen);

    fd = socket(c->sa->sa_family, SOCK_STREAM, 0);
    if (fd < 0)
	err(1, "failed to build socket for %s's logging port", c->moniker);

    ((struct sockaddr *)&sast)->sa_family = c->sa->sa_family;
    ret = bind(fd, (struct sockaddr *)&sast, c->salen);
    if (ret < 0)
	err(1, "failed to bind %s's logging port", c->moniker);

    if (listen(fd, SOMAXCONN) < 0)
	err(1, "failed to listen %s's logging port", c->moniker);

    salen = sizeof(sast);
    ret = getsockname(fd, (struct sockaddr *)&sast, &salen);
    if (ret < 0)
	err(1, "failed to get address of local socket for %s", c->moniker);

    port = socket_get_port((struct sockaddr *)&sast);

    put32(c, eSetLoggingSocket);
    put32(c, ntohs(port));

    salen = sizeof(sast);
    fd2 = accept(fd, (struct sockaddr *)&sast, &salen);
    if (fd2 < 0)
	err(1, "failed to accept local socket for %s", c->moniker);
    close(fd);

    return fd2;
}
static krb5_error_code 
add_locate(void *ctx, int type, struct sockaddr *addr)
{
    struct krb5_krbhst_info *hi;
    struct krb5_krbhst_data *kd = ctx;
    char host[NI_MAXHOST], port[NI_MAXSERV];
    struct addrinfo hints, *ai;
    socklen_t socklen;
    size_t hostlen;
    int ret;

    socklen = socket_sockaddr_size(addr);

    ret = getnameinfo(addr, socklen, host, sizeof(host), port, sizeof(port),
		      NI_NUMERICHOST|NI_NUMERICSERV);
    if (ret != 0)
	return 0;

    memset(&hints, 0, sizeof(hints));
    ret = getaddrinfo(host, port, &hints, &ai);
    if (ret)
	return 0;

    hostlen = strlen(host);

    hi = calloc(1, sizeof(*hi) + hostlen);
    if(hi == NULL) {
	return ENOMEM;
    }
    
    hi->proto = krbhst_get_default_proto(kd);
    hi->port  = hi->def_port = socket_get_port(addr);
    hi->ai    = ai;
    memmove(hi->hostname, host, hostlen);
    hi->hostname[hostlen] = '\0';
    append_host_hostinfo(kd, hi);

    return 0;
}
Beispiel #6
0
static void
doit (void)
{
    u_char buf[BUFSIZ];
    u_char *p;
    struct sockaddr_storage thisaddr_ss;
    struct sockaddr *thisaddr = (struct sockaddr *)&thisaddr_ss;
    struct sockaddr_storage thataddr_ss;
    struct sockaddr *thataddr = (struct sockaddr *)&thataddr_ss;
    struct sockaddr_storage erraddr_ss;
    struct sockaddr *erraddr = (struct sockaddr *)&erraddr_ss;
    socklen_t thisaddr_len, thataddr_len;
    int port;
    int errsock = -1;
    char *client_user = NULL, *server_user = NULL, *cmd = NULL;
    struct passwd *pwd;
    int s = STDIN_FILENO;
    char **env;
    int ret;
    char that_host[NI_MAXHOST];

    thisaddr_len = sizeof(thisaddr_ss);
    if (getsockname (s, thisaddr, &thisaddr_len) < 0)
	syslog_and_die("getsockname: %s", strerror(errno));
    thataddr_len = sizeof(thataddr_ss);
    if (getpeername (s, thataddr, &thataddr_len) < 0)
	syslog_and_die ("getpeername: %s", strerror(errno));

    /* check for V4MAPPED addresses? */

    if (do_kerberos == 0 && !is_reserved(socket_get_port(thataddr)))
	fatal(s, NULL, "Permission denied.");

    p = buf;
    port = 0;
    for(;;) {
	if (net_read (s, p, 1) != 1)
	    syslog_and_die ("reading port number: %s", strerror(errno));
	if (*p == '\0')
	    break;
	else if (isdigit(*p))
	    port = port * 10 + *p - '0';
	else
	    syslog_and_die ("non-digit in port number: %c", *p);
    }

    if (do_kerberos  == 0 && !is_reserved(htons(port)))
	fatal(s, NULL, "Permission denied.");

    if (port) {
	int priv_port = IPPORT_RESERVED - 1;

	/*
	 * There's no reason to require a ``privileged'' port number
	 * here, but for some reason the brain dead rsh clients
	 * do... :-(
	 */

	erraddr->sa_family = thataddr->sa_family;
	socket_set_address_and_port (erraddr,
				     socket_get_address (thataddr),
				     htons(port));

	/*
	 * we only do reserved port for IPv4
	 */

	if (erraddr->sa_family == AF_INET)
	    errsock = rresvport (&priv_port);
	else
	    errsock = socket (erraddr->sa_family, SOCK_STREAM, 0);
	if (errsock < 0)
	    syslog_and_die ("socket: %s", strerror(errno));
	if (connect (errsock,
		     erraddr,
		     socket_sockaddr_size (erraddr)) < 0) {
	    syslog (LOG_WARNING, "connect: %s", strerror(errno));
	    close (errsock);
	}
    }

    if(do_kerberos) {
	if (net_read (s, buf, 4) != 4)
	    syslog_and_die ("reading auth info: %s", strerror(errno));

#ifdef KRB5
	    if((do_kerberos & DO_KRB5) &&
	       recv_krb5_auth (s, buf, thisaddr, thataddr,
			       &client_user,
			       &server_user,
			       &cmd) == 0)
		auth_method = AUTH_KRB5;
	    else
#endif /* KRB5 */
		syslog_and_die ("unrecognized auth protocol: %x %x %x %x",
				buf[0], buf[1], buf[2], buf[3]);
    } else {
	if(recv_bsd_auth (s, buf,
			  (struct sockaddr_in *)thisaddr,
			  (struct sockaddr_in *)thataddr,
			  &client_user,
			  &server_user,
			  &cmd) == 0) {
	    auth_method = AUTH_BROKEN;
	    if(do_vacuous) {
		printf("Remote host requires Kerberos authentication\n");
		exit(0);
	    }
	} else
	    syslog_and_die("recv_bsd_auth failed");
    }

    if (client_user == NULL || server_user == NULL || cmd == NULL)
	syslog_and_die("mising client/server/cmd");

    pwd = getpwnam (server_user);
    if (pwd == NULL)
	fatal (s, NULL, "Login incorrect.");

    if (*pwd->pw_shell == '\0')
	pwd->pw_shell = _PATH_BSHELL;

    if (pwd->pw_uid != 0 && access (_PATH_NOLOGIN, F_OK) == 0)
	fatal (s, NULL, "Login disabled.");


    ret = getnameinfo_verified (thataddr, thataddr_len,
				that_host, sizeof(that_host),
				NULL, 0, 0);
    if (ret)
	fatal (s, NULL, "getnameinfo: %s", gai_strerror(ret));

    if (login_access(pwd, that_host) == 0) {
	syslog(LOG_NOTICE, "Kerberos rsh denied to %s from %s",
	       server_user, that_host);
	fatal(s, NULL, "Permission denied.");
    }

#ifdef HAVE_GETSPNAM
    {
	struct spwd *sp;
	long    today;

	sp = getspnam(server_user);
	if (sp != NULL) {
	    today = time(0)/(24L * 60 * 60);
	    if (sp->sp_expire > 0)
		if (today > sp->sp_expire)
		    fatal(s, NULL, "Account has expired.");
	}
    }
#endif


#ifdef HAVE_SETLOGIN
    if (setlogin(pwd->pw_name) < 0)
	syslog(LOG_ERR, "setlogin() failed: %s", strerror(errno));
#endif

#ifdef HAVE_SETPCRED
    if (setpcred (pwd->pw_name, NULL) == -1)
	syslog(LOG_ERR, "setpcred() failure: %s", strerror(errno));
#endif /* HAVE_SETPCRED */

    /* Apply limits if not root */
    if(pwd->pw_uid != 0) {
	 const char *file = _PATH_LIMITS_CONF;
	 read_limits_conf(file, pwd);
    }

    if (initgroups (pwd->pw_name, pwd->pw_gid) < 0)
	fatal (s, "initgroups", "Login incorrect.");

    if (setgid(pwd->pw_gid) < 0)
	fatal (s, "setgid", "Login incorrect.");

    if (setuid (pwd->pw_uid) < 0)
	fatal (s, "setuid", "Login incorrect.");

    if (chdir (pwd->pw_dir) < 0)
	fatal (s, "chdir", "Remote directory.");

    if (errsock >= 0) {
	if (dup2 (errsock, STDERR_FILENO) < 0)
	    fatal (s, "dup2", "Cannot dup stderr.");
	close (errsock);
    } else {
	if (dup2 (STDOUT_FILENO, STDERR_FILENO) < 0)
	    fatal (s, "dup2", "Cannot dup stderr.");
    }

#ifdef KRB5
    {
	int fd;

	if (!do_unique_tkfile)
	    snprintf(tkfile,sizeof(tkfile),"FILE:/tmp/krb5cc_%lu",
		     (unsigned long)pwd->pw_uid);
	else if (*tkfile=='\0') {
	    snprintf(tkfile,sizeof(tkfile),"FILE:/tmp/krb5cc_XXXXXX");
	    fd = mkstemp(tkfile+5);
	    close(fd);
	    unlink(tkfile+5);
	}

	if (kerberos_status)
	    krb5_start_session();
    }
#endif

    setup_environment (&env, pwd);

    if (do_encrypt) {
	setup_copier (errsock >= 0);
    } else {
	if (net_write (s, "", 1) != 1)
	    fatal (s, "net_write", "write failed");
    }

#if defined(KRB5)
    if(k_hasafs()) {
	char cell[64];

	if(do_newpag)
	    k_setpag();

	/* XXX */
       if (kerberos_status) {
	   krb5_ccache ccache;
	   krb5_error_code status;

	   status = krb5_cc_resolve (context, tkfile, &ccache);
	   if (!status) {
	       if (k_afs_cell_of_file (pwd->pw_dir, cell, sizeof(cell)) == 0)
		   krb5_afslog_uid_home(context, ccache, cell, NULL,
					pwd->pw_uid, pwd->pw_dir);
	       krb5_afslog_uid_home(context, ccache, NULL, NULL,
				    pwd->pw_uid, pwd->pw_dir);
	       krb5_cc_close (context, ccache);
	   }
       }
    }
#endif /* KRB5 */
    execle (pwd->pw_shell, pwd->pw_shell, "-c", cmd, NULL, env);
    err(1, "exec %s", pwd->pw_shell);
}
Beispiel #7
0
static int
recv_krb5_auth (int s, u_char *buf,
		struct sockaddr *thisaddr,
		struct sockaddr *thataddr,
		char **client_username,
		char **server_username,
		char **cmd)
{
    uint32_t len;
    krb5_auth_context auth_context = NULL;
    krb5_ticket *ticket;
    krb5_error_code status;
    krb5_data cksum_data;
    krb5_principal server;
    char *str;

    if (memcmp (buf, "\x00\x00\x00\x13", 4) != 0)
	return -1;
    len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]);

    if (net_read(s, buf, len) != len)
	syslog_and_die ("reading auth info: %s", strerror(errno));
    if (len != sizeof(KRB5_SENDAUTH_VERSION)
	|| memcmp (buf, KRB5_SENDAUTH_VERSION, len) != 0)
	syslog_and_die ("bad sendauth version: %.8s", buf);

    status = krb5_sock_to_principal (context,
				     s,
				     "host",
				     KRB5_NT_SRV_HST,
				     &server);
    if (status)
	syslog_and_die ("krb5_sock_to_principal: %s",
			krb5_get_err_text(context, status));

    status = krb5_recvauth_match_version(context,
					 &auth_context,
					 &s,
					 match_kcmd_version,
					 NULL,
					 server,
					 KRB5_RECVAUTH_IGNORE_VERSION,
					 NULL,
					 &ticket);
    krb5_free_principal (context, server);
    if (status)
	syslog_and_die ("krb5_recvauth: %s",
			krb5_get_err_text(context, status));

    *server_username = read_str (s, USERNAME_SZ, "remote username");
    *cmd = read_str (s, ARG_MAX + 1, "command");
    *client_username = read_str (s, ARG_MAX + 1, "local username");

    if(protocol_version == 2) {
	status = krb5_auth_con_getremotesubkey(context, auth_context,
					       &keyblock);
	if(status != 0 || keyblock == NULL)
	    syslog_and_die("failed to get remote subkey");
    } else if(protocol_version == 1) {
	status = krb5_auth_con_getkey (context, auth_context, &keyblock);
	if(status != 0 || keyblock == NULL)
	    syslog_and_die("failed to get key");
    }
    if (status != 0 || keyblock == NULL)
       syslog_and_die ("krb5_auth_con_getkey: %s",
                       krb5_get_err_text(context, status));

    status = krb5_crypto_init(context, keyblock, 0, &crypto);
    if(status)
	syslog_and_die("krb5_crypto_init: %s",
		       krb5_get_err_text(context, status));


    cksum_data.length = asprintf (&str,
				  "%u:%s%s",
				  ntohs(socket_get_port (thisaddr)),
				  *cmd,
				  *server_username);
    if (str == NULL)
	syslog_and_die ("asprintf: out of memory");
    cksum_data.data = str;

    status = krb5_verify_authenticator_checksum(context,
						auth_context,
						cksum_data.data,
						cksum_data.length);

    if (status)
	syslog_and_die ("krb5_verify_authenticator_checksum: %s",
			krb5_get_err_text(context, status));

    free (cksum_data.data);

    if (strncmp (*client_username, "-u ", 3) == 0) {
	do_unique_tkfile = 1;
	memmove (*client_username, *client_username + 3,
		 strlen(*client_username) - 2);
    }

    if (strncmp (*client_username, "-U ", 3) == 0) {
	char *end, *temp_tkfile;

	do_unique_tkfile = 1;
	if (strncmp (*client_username + 3, "FILE:", 5) == 0) {
	    temp_tkfile = tkfile;
	} else {
	    strlcpy (tkfile, "FILE:", sizeof(tkfile));
	    temp_tkfile = tkfile + 5;
	}
	end = strchr(*client_username + 3,' ');
	if (end == NULL)
	    syslog_and_die("missing argument after -U");
	snprintf(temp_tkfile, sizeof(tkfile) - (temp_tkfile - tkfile),
		 "%.*s",
		 (int)(end - *client_username - 3),
		 *client_username + 3);
	memmove (*client_username, end + 1, strlen(end+1)+1);
    }

    kerberos_status = save_krb5_creds (s, auth_context, ticket->client);

    if(!krb5_kuserok (context,
		      ticket->client,
		      *server_username))
	fatal (s, NULL, "Permission denied.");

    if (strncmp (*cmd, "-x ", 3) == 0) {
	do_encrypt = 1;
	memmove (*cmd, *cmd + 3, strlen(*cmd) - 2);
    } else {
	if(do_encrypt)
	    fatal (s, NULL, "Encryption is required.");
	do_encrypt = 0;
    }

    {
	char *name;

	if (krb5_unparse_name (context, ticket->client, &name) == 0) {
	    char addr_str[256];

	    if (inet_ntop (thataddr->sa_family,
			   socket_get_address (thataddr),
			   addr_str, sizeof(addr_str)) == NULL)
		strlcpy (addr_str, "unknown address",
				 sizeof(addr_str));

	    syslog(LOG_INFO|LOG_AUTH,
		   "kerberos v5 shell from %s on %s as %s, cmd '%.80s'",
		   name,
		   addr_str,
		   *server_username,
		   *cmd);
	    free (name);
	}
    }

    krb5_auth_con_free(context, auth_context);

    return 0;
}
Beispiel #8
0
static int
send_krb5_auth(int s,
	       struct sockaddr *thisaddr,
	       struct sockaddr *thataddr,
	       const char *hostname,
	       const char *remote_user,
	       const char *local_user,
	       size_t cmd_len,
	       const char *cmd)
{
    krb5_principal server;
    krb5_data cksum_data;
    int status;
    size_t len;
    krb5_auth_context auth_context = NULL;
    const char *protocol_string = NULL;
    krb5_flags ap_opts;
    char *str;

    status = krb5_sname_to_principal(context,
				     hostname,
				     "host",
				     KRB5_NT_SRV_HST,
				     &server);
    if (status) {
	warnx ("%s: %s", hostname, krb5_get_err_text(context, status));
	return 1;
    }

    if(do_encrypt == -1) {
	krb5_appdefault_boolean(context, NULL,
				krb5_principal_get_realm(context, server),
				"encrypt",
				FALSE,
				&do_encrypt);
    }

    cksum_data.length = asprintf (&str,
				  "%u:%s%s%s",
				  ntohs(socket_get_port(thataddr)),
				  do_encrypt ? "-x " : "",
				  cmd,
				  remote_user);
    if (str == NULL) {
	warnx ("%s: failed to allocate command", hostname);
	return 1;
    }
    cksum_data.data = str;

    ap_opts = 0;

    if(do_encrypt)
	ap_opts |= AP_OPTS_MUTUAL_REQUIRED;

    switch(protocol_version) {
    case 2:
	ap_opts |= AP_OPTS_USE_SUBKEY;
	protocol_string = KCMD_NEW_VERSION;
	break;
    case 1:
	protocol_string = KCMD_OLD_VERSION;
	key_usage = KRB5_KU_OTHER_ENCRYPTED;
	break;
    default:
	abort();
    }
	
    status = krb5_sendauth (context,
			    &auth_context,
			    &s,
			    protocol_string,
			    NULL,
			    server,
			    ap_opts,
			    &cksum_data,
			    NULL,
			    NULL,
			    NULL,
			    NULL,
			    NULL);

    /* do this while we have a principal */
    if(do_forward == -1 || do_forwardable == -1) {
	krb5_const_realm realm = krb5_principal_get_realm(context, server);
	if (do_forwardable == -1)
	    krb5_appdefault_boolean(context, NULL, realm,
				    "forwardable", FALSE,
				    &do_forwardable);
	if (do_forward == -1)
	    krb5_appdefault_boolean(context, NULL, realm,
				    "forward", FALSE,
				    &do_forward);
    }

    krb5_free_principal(context, server);
    krb5_data_free(&cksum_data);

    if (status) {
	if(status == KRB5_SENDAUTH_REJECTED &&
	   protocol_version == 2 && protocol_version_str == NULL)
	    sendauth_version_error = 1;
	else
	    krb5_warn(context, status, "%s", hostname);
	return 1;
    }

    status = krb5_auth_con_getlocalsubkey (context, auth_context, &keyblock);
    if(keyblock == NULL)
	status = krb5_auth_con_getkey (context, auth_context, &keyblock);
    if (status) {
	warnx ("krb5_auth_con_getkey: %s", krb5_get_err_text(context, status));
	return 1;
    }

    status = krb5_auth_con_setaddrs_from_fd (context,
					     auth_context,
					     &s);
    if (status) {
        warnx("krb5_auth_con_setaddrs_from_fd: %s",
	      krb5_get_err_text(context, status));
        return(1);
    }

    status = krb5_crypto_init(context, keyblock, 0, &crypto);
    if(status) {
	warnx ("krb5_crypto_init: %s", krb5_get_err_text(context, status));
	return 1;
    }

    len = strlen(remote_user) + 1;
    if (net_write (s, remote_user, len) != len) {
	warn ("write");
	return 1;
    }
    if (do_encrypt && net_write (s, "-x ", 3) != 3) {
	warn ("write");
	return 1;
    }
    if (net_write (s, cmd, cmd_len) != cmd_len) {
	warn ("write");
	return 1;
    }

    if (do_unique_tkfile) {
	if (net_write (s, tkfile, strlen(tkfile)) != strlen(tkfile)) {
	    warn ("write");
	    return 1;
	}
    }
    len = strlen(local_user) + 1;
    if (net_write (s, local_user, len) != len) {
	warn ("write");
	return 1;
    }

    if (!do_forward
	|| krb5_forward_cred (auth_context, s, hostname, do_forwardable)) {
	/* Empty forwarding info */

	u_char zero[4] = {0, 0, 0, 0};
	write (s, &zero, 4);
    }
    krb5_auth_con_free (context, auth_context);
    return 0;
}