Beispiel #1
0
/* Add a service program to the callout list.
   The dispatch routine will be called when a rpc request for this
   program number comes in. */
bool_t
svc_register (SVCXPRT * xprt, rpcprog_t prog, rpcvers_t vers,
	      void (*dispatch) (struct svc_req *, SVCXPRT *),
	      rpcproc_t protocol)
{
  struct svc_callout *prev;
  register struct svc_callout *s;

  if ((s = svc_find (prog, vers, &prev)) != NULL_SVC)
    {
      if (s->sc_dispatch == dispatch)
	goto pmap_it;		/* he is registering another xptr */
      return FALSE;
    }
  s = (struct svc_callout *) mem_alloc (sizeof (struct svc_callout));
  if (s == (struct svc_callout *) 0)
    return FALSE;

  s->sc_prog = prog;
  s->sc_vers = vers;
  s->sc_dispatch = dispatch;
  s->sc_next = svc_head;
  svc_head = s;

pmap_it:
  /* now register the information with the local binder service */
  if (protocol)
    return pmap_set (prog, vers, protocol, xprt->xp_port);

  return TRUE;
}
Beispiel #2
0
/*
 * Add a service program to the callout list.
 * The dispatch routine will be called when a rpc request for this
 * program number comes in.
 */
bool
svc_register(SVCXPRT *xprt, u_long prog, u_long vers,
	     void (*dispatch) (struct svc_req *req, SVCXPRT *xprt),
	     int protocol)
{
	struct svc_callout *prev;
	struct svc_callout *s;

	assert(xprt != NULL);
	assert(dispatch != NULL);

	s = svc_find((rpcprog_t) prog, (rpcvers_t) vers, &prev, NULL);
	if (s) {
		if (s->rec.sc_dispatch == dispatch)
			goto pmap_it;	/* he is registering another xprt */
		return (false);
	}
	s = mem_alloc(sizeof(struct svc_callout));
	s->rec.sc_prog = (rpcprog_t) prog;
	s->rec.sc_vers = (rpcvers_t) vers;
	s->rec.sc_dispatch = dispatch;
	s->sc_next = svc_head;
	svc_head = s;

 pmap_it:
	/* now register the information with the local binder service */
	if (protocol)
		return (pmap_set(prog, vers, protocol, xprt->xp_port));

	return (true);
}
Beispiel #3
0
/*
 * Add a service program to the callout list.
 * The dispatch routine will be called when a rpc request for this
 * program number comes in.
 */
bool_t
svc_register(SVCXPRT *xprt, u_long prog, u_long vers, void (*dispatch)(),
    int protocol)
{
	struct svc_callout *prev;
	struct svc_callout *s;

	if ((s = svc_find(prog, vers, &prev)) != NULL) {
		if (s->sc_dispatch == dispatch)
			goto pmap_it;  /* he is registering another xptr */
		return (FALSE);
	}
	s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout));
	if (s == NULL) {
		return (FALSE);
	}
	s->sc_prog = prog;
	s->sc_vers = vers;
	s->sc_dispatch = dispatch;
	s->sc_next = svc_head;
	svc_head = s;
pmap_it:
	/* now register the information with the local binder service */
	if (protocol) {
		return (pmap_set(prog, vers, protocol, xprt->xp_port));
	}
	return (TRUE);
}
Beispiel #4
0
static bool_t
svc_is_mapped (rpcprog_t prog, rpcvers_t vers)
{
  struct svc_callout *prev;
  register struct svc_callout *s;
  s = svc_find (prog, vers, &prev);
  return s!= NULL_SVC && s->sc_mapped;
}
Beispiel #5
0
int svc_start_by_name(char *name)
{
	svc_t *svc = svc_find(name);

	if (svc && svc_enabled(svc, 0, NULL))
		return svc_start(svc);

	return 1;
}
Beispiel #6
0
int plugin_unregister(plugin_t *plugin)
{
	TAILQ_REMOVE(&plugins, plugin, link);

	if (plugin->svc.cb) {
		svc_t *svc = svc_find(plugin->name);

		if (svc) {
			svc->cb      = NULL;
			svc->dynamic = 0;
		}
	}

	/* XXX: Unfinished, add cleanup code here! */

	return 0;
}
Beispiel #7
0
/*
 * Remove a service program from the callout list.
 */
void
svc_unregister(u_long prog, u_long vers)
{
	struct svc_callout *prev;
	struct svc_callout *s;

	if ((s = svc_find(prog, vers, &prev)) == NULL)
		return;
	if (prev == NULL) {
		svc_head = s->sc_next;
	} else {
		prev->sc_next = s->sc_next;
	}
	s->sc_next = NULL;
	mem_free((char *) s, (u_int) sizeof(struct svc_callout));
	/* now unregister the information with the local binder service */
	(void)pmap_unset(prog, vers);
}
Beispiel #8
0
/*
 * Remove a service program from the callout list.
 */
void
svc_unregister(u_long prog, u_long vers)
{
	struct svc_callout *prev;
	struct svc_callout *s;

	s = svc_find((rpcprog_t) prog, (rpcvers_t) vers, &prev, NULL);
	if (!s)
		return;
	if (prev == NULL)
		svc_head = s->sc_next;
	else
		prev->sc_next = s->sc_next;
	s->sc_next = NULL;
	mem_free(s, sizeof(struct svc_callout));
	/* now unregister the information with the local binder service */
	(void)pmap_unset(prog, vers);
}
Beispiel #9
0
/* Remove a service program from the callout list. */
void
svc_unregister (rpcprog_t prog, rpcvers_t vers)
{
  struct svc_callout *prev;
  register struct svc_callout *s;

  if ((s = svc_find (prog, vers, &prev)) == NULL_SVC)
    return;

  if (prev == NULL_SVC)
    svc_head = s->sc_next;
  else
    prev->sc_next = s->sc_next;

  s->sc_next = NULL_SVC;
  mem_free ((char *) s, (u_int) sizeof (struct svc_callout));
  /* now unregister the information with the local binder service */
  pmap_unset (prog, vers);
}
Beispiel #10
0
/*
 * Remove a service program from the callout list.
 */
void
svc_unreg(const rpcprog_t prog, const rpcvers_t vers)
{
	struct svc_callout *prev;
	struct svc_callout *s;

	/* unregister the information anyway */
	(void)rpcb_unset(prog, vers, NULL);
	rwlock_wrlock(&svc_lock);
	while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) {
		if (prev == NULL)
			svc_head = s->sc_next;
		else
			prev->sc_next = s->sc_next;
		s->sc_next = NULL;
		if (s->rec.sc_netid)
			mem_free(s->rec.sc_netid, sizeof(s->rec.sc_netid) + 1);
		mem_free(s, sizeof(struct svc_callout));
	}
	rwlock_unlock(&svc_lock);
}
Beispiel #11
0
/**
 * service_register - Register service, task or run commands
 * @type:     %SVC_TYPE_SERVICE(0), %SVC_TYPE_TASK(1), %SVC_TYPE_RUN(2)
 * @line:     A complete command line with -- separated description text
 * @mtime:    The modification time if service is loaded from /etc/finit.d
 * @username: Optional username to run service as, or %NULL to run as root
 *
 * This function is used to register commands to be run on different
 * system runlevels with optional username.  The @type argument details
 * if it's service to bo monitored/respawned (daemon), a one-shot task
 * or a command that must run in sequence and not in parallell, like
 * service and task commands do.
 *
 * The @line can optionally start with a username, denoted by an @
 * character. Like this:
 *
 *     service @username [!0-6,S] <!EV> /path/to/daemon arg -- Description
 *     task @username [!0-6,S] /path/to/task arg            -- Description
 *     run  @username [!0-6,S] /path/to/cmd arg             -- Description
 *     inetd tcp/ssh nowait [2345] @root:root /sbin/sshd -i -- Description
 *
 * If the username is left out the command is started as root.  The []
 * brackets denote the allowed runlevels, if left out the default for a
 * service is set to [2-5].  Allowed runlevels mimic that of SysV init
 * with the addition of the 'S' runlevel, which is only run once at
 * startup.  It can be seen as the system bootstrap.  If a task or run
 * command is listed in more than the [S] runlevel they will be called
 * when changing runlevel.
 *
 * Services (daemons, not inetd services) also support an optional <!EV>
 * argument.  This is for services that, e.g., require a system gateway
 * or interface to be up before they are started.  Or restarted, or even
 * SIGHUP'ed, when the gateway changes or interfaces come and go.  The
 * special case when a service is declared with <!> means it does not
 * support SIGHUP but must be STOP/START'ed at system reconfiguration.
 *
 * Supported service events are: GW, IFUP[:ifname], IFDN[:ifname], where
 * the interface name (:ifname) is optional.  Actully, the check with a
 * service event declaration is string based, so 'IFUP:ppp' will match
 * any of "IFUP:ppp0" or "IFUP:pppoe1" sent by the netlink.so plugin.
 *
 * For multiple instances of the same command, e.g. multiple DHCP
 * clients, the user must enter an ID, using the :ID syntax.
 *
 *     service :1 /sbin/udhcpc -i eth1
 *     service :2 /sbin/udhcpc -i eth2
 *
 * Without the :ID syntax Finit will overwrite the first service line
 * with the contents of the second.  The :ID must be [1,MAXINT].
 *
 * Returns:
 * POSIX OK(0) on success, or non-zero errno exit status on failure.
 */
int service_register(int type, char *line, time_t mtime, char *username)
{
	int i = 0;
	int id = 1;		/* Default to ID:1 */
#ifndef INETD_DISABLED
	int forking = 0;
#endif
	char *service = NULL, *proto = NULL, *ifaces = NULL;
	char *cmd, *desc, *runlevels = NULL, *events = NULL;
	svc_t *svc;
	plugin_t *plugin = NULL;

	if (!line) {
		_e("Invalid input argument.");
		return errno = EINVAL;
	}

	desc = strstr(line, "-- ");
	if (desc)
		*desc = 0;

	cmd = strtok(line, " ");
	if (!cmd) {
	incomplete:
		_e("Incomplete service, cannot register.");
		return errno = ENOENT;
	}

	while (cmd) {
		if (cmd[0] != '/' && strchr(cmd, '/'))
			service = cmd;   /* inetd service/proto */
#ifndef INETD_DISABLED
		else if (!strncasecmp(cmd, "nowait", 6))
			forking = 1;
		else if (!strncasecmp(cmd, "wait", 4))
			forking = 0;
#endif
		else if (cmd[0] == '@')	/* @username[:group] */
			username = &cmd[1];
		else if (cmd[0] == '[')	/* [runlevels] */
			runlevels = &cmd[0];
		else if (cmd[0] == '<')	/* [!ev] */
			events = &cmd[1];
		else if (cmd[0] == ':')	/* :ID */
			id = atoi(&cmd[1]);
		else
			break;

		/* Check if valid command follows... */
		cmd = strtok(NULL, " ");
		if (!cmd)
			goto incomplete;
	}

	/* Example: inetd ssh/tcp@eth0,eth1 or 222/tcp@eth2 */
	if (service) {
		ifaces = strchr(service, '@');
		if (ifaces)
			*ifaces++ = 0;

		proto = strchr(service, '/');
		if (!proto)
			goto incomplete;
		*proto++ = 0;
	}

#ifndef INETD_DISABLED
	/* Find plugin that provides a callback for this inetd service */
	if (type == SVC_TYPE_INETD) {
		if (!strncasecmp(cmd, "internal", 8)) {
			char *ptr, *ps = service;

			/* internal.service */
			ptr = strchr(cmd, '.');
			if (ptr) {
				*ptr++ = 0;
				ps = ptr;
			}

			plugin = plugin_find(ps);
			if (!plugin || !plugin->inetd.cmd) {
				_e("Inetd service %s has no internal plugin, skipping.", service);
				return errno = ENOENT;
			}
		}

		/* Check if known inetd, then add ifnames for filtering only. */
		svc = find_inetd_svc(cmd, service, proto);
		if (svc)
			goto inetd_setup;

		id = svc_next_id(cmd);
	}
#endif

	svc = svc_find(cmd, id);
	if (!svc) {
		_d("Creating new svc for %s id #%d type %d", cmd, id, type);
		svc = svc_new(cmd, id, type);
		if (!svc) {
			_e("Out of memory, cannot register service %s", cmd);
			return errno = ENOMEM;
		}
	}

	/* New, recently modified or unchanged ... used on reload. */
	svc_check_dirty(svc, mtime);

	if (desc)
		strlcpy(svc->desc, desc + 3, sizeof(svc->desc));

	if (username) {
		char *ptr = strchr(username, ':');

		if (ptr) {
			*ptr++ = 0;
			strlcpy(svc->group, ptr, sizeof(svc->group));
		}
		strlcpy(svc->username, username, sizeof(svc->username));
	}

	if (plugin) {
		/* Internal plugin provides this service */
		svc->inetd.cmd = plugin->inetd.cmd;
	} else {
		strlcpy(svc->args[i++], cmd, sizeof(svc->args[0]));
		while ((cmd = strtok(NULL, " ")))
			strlcpy(svc->args[i++], cmd, sizeof(svc->args[0]));
		svc->args[i][0] = 0;

		plugin = plugin_find(svc->cmd);
		if (plugin && plugin->svc.cb) {
			svc->cb           = plugin->svc.cb;
			svc->dynamic      = plugin->svc.dynamic;
			svc->dynamic_stop = plugin->svc.dynamic_stop;
		}
	}

	svc->runlevels = conf_parse_runlevels(runlevels);
	_d("Service %s runlevel 0x%2x", svc->cmd, svc->runlevels);

	if (type == SVC_TYPE_SERVICE)
		conf_parse_events(svc, events);

#ifndef INETD_DISABLED
	if (svc_is_inetd(svc)) {
		char *iface, *name = service;

		if (svc->inetd.cmd && plugin)
			name = plugin->name;

		if (inetd_new(&svc->inetd, name, service, proto, forking, svc)) {
			_e("Failed registering new inetd service %s.", service);
			inetd_del(&svc->inetd);
			return svc_del(svc);
		}

	inetd_setup:
		if (!ifaces) {
			_d("No specific iface listed for %s, allowing ANY.", service);
			return inetd_allow(&svc->inetd, NULL);
		}

		for (iface = strtok(ifaces, ","); iface; iface = strtok(NULL, ",")) {
			if (iface[0] == '!')
				inetd_deny(&svc->inetd, &iface[1]);
			else
				inetd_allow(&svc->inetd, iface);
		}
	}
#endif

	return 0;
}
Beispiel #12
0
/*
 * Add a service program to the callout list.
 * The dispatch routine will be called when a rpc request for this
 * program number comes in.
 */
bool
svc_reg(SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers,
	void (*dispatch) (struct svc_req *req, SVCXPRT *xprt),
	const struct netconfig *nconf)
{
	bool dummy;
	struct svc_callout *prev;
	struct svc_callout *s;
	struct netconfig *tnconf;
	char *netid = NULL;
	int flag = 0;

	/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
	if (xprt->xp_netid) {
		netid = mem_strdup(xprt->xp_netid);
		flag = 1;
	} else if (nconf) {
		netid = mem_strdup(nconf->nc_netid);
		flag = 1;
	} else {
		tnconf = __rpcgettp(xprt->xp_fd);
		if (tnconf) {
			netid = mem_strdup(tnconf->nc_netid);
			flag = 1;
			freenetconfigent(tnconf);
		}
	} /* must have been created with svc_raw_create */
	if ((netid == NULL) && (flag == 1))
		return (false);

	rwlock_wrlock(&svc_lock);
	s = svc_find(prog, vers, &prev, netid);
	if (s) {
		if (netid)
			mem_free(netid, 0);
		if (s->rec.sc_dispatch == dispatch)
			goto rpcb_it;	/* he is registering another xptr */
		rwlock_unlock(&svc_lock);
		return (false);
	}
	s = mem_alloc(sizeof(struct svc_callout));
	s->rec.sc_prog = prog;
	s->rec.sc_vers = vers;
	s->rec.sc_dispatch = dispatch;
	s->rec.sc_netid = netid;
	s->sc_next = svc_head;
	svc_head = s;

	if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
		((SVCXPRT *) xprt)->xp_netid = mem_strdup(netid);

 rpcb_it:
	rwlock_unlock(&svc_lock);
	/* now register the information with the local binder service */
	if (nconf) {
		/*LINTED const castaway */
		dummy =
		    rpcb_set(prog, vers, (struct netconfig *)nconf,
			     &((SVCXPRT *) xprt)->xp_local.nb);
		return (dummy);
	}
	return (true);
}
Beispiel #13
0
int plugin_register(plugin_t *plugin)
{
	int i, inuse = 0;

	if (!plugin) {
		errno = EINVAL;
		return 1;
	}

	if (!plugin->name) {
		Dl_info info;

		if (!dladdr(plugin, &info) || !info.dli_fname)
			plugin->name = "unknown";
		else
			plugin->name = (char *)info.dli_fname;
	}

	/* Already registered? */
	if (plugin_find(plugin->name)) {
		_d("... %s already loaded.", plugin->name);
		return 0;
	}

	check_plugin_depends(plugin);

	if (is_io_plugin(plugin)) {
		if (num_fds + 1 >= MAX_NUM_FDS) {
			num_fds = MAX_NUM_SVC;
			errno = ENOMEM;
			return 1;
		}
		num_fds++;
		inuse++;
	}

	if (plugin->svc.cb) {
		svc_t *svc = svc_find(plugin->name);

		if (svc) {
			inuse++;
			svc->cb           = plugin->svc.cb;
			svc->dynamic      = plugin->svc.dynamic;
			svc->dynamic_stop = plugin->svc.dynamic_stop;
		}
	}

	for (i = 0; i < HOOK_MAX_NUM; i++) {
		if (plugin->hook[i].cb)
			inuse++;
	}

	if (!inuse) {
		_d("No service \"%s\" loaded, and no I/O or finit hooks, skipping plugin.", basename(plugin->name));
		return 1;
	}

	TAILQ_INSERT_TAIL(&plugins, plugin, link);

	return 0;
}
Beispiel #14
0
/* There's one of these for each RPC client which has received an RPC call. */
static void *cb_context(void *__u)
{
    CLIENT *client = (CLIENT *)__u;
    D("RPC-callback thread for %08x:%08x starting.\n",
      (client->xdr->x_prog | 0x01000000),
      client->xdr->x_vers);
    pthread_mutex_lock(&client->wait_cb_lock);
    while (client->cb_stop == 0) {
        if (!client->got_cb)
            pthread_cond_wait(&client->wait_cb,
                              &client->wait_cb_lock);
        /* We tell the thread it's time to exit by setting cb_stop to nonzero
           and signalling the conditional variable.  When there's no data, we
           skip to the top of the loop and exit. 
        */
        if (!client->got_cb) {
            D("RPC-callback thread for %08x:%08x: signalled but no data.\n",
              (client->xdr->x_prog | 0x01000000),
              client->xdr->x_vers);
            continue;
        }
        client->got_cb = 0;

        /* We dispatch the message to the server representing the callback
         * client.
         */
        if (the_xprt) {
            void *svc;
            rpcprog_t prog =
                ntohl(((uint32 *)(client->xdr->in_msg))[RPC_OFFSET+3]);
            rpcvers_t vers =
                ntohl(((uint32 *)(client->xdr->in_msg))[RPC_OFFSET+4]);
            
            svc = svc_find(the_xprt, prog, vers);
            if (svc) {
                XDR **svc_xdr = (XDR **)svc;
                D("%08x:%08x dispatching RPC call (XID %d, xdr %p) for "
                  "callback client %08x:%08x.\n",
                  client->xdr->x_prog,
                  client->xdr->x_vers,
                  ntohl(((uint32 *)(client->xdr->in_msg))[RPC_OFFSET]),
                  client->xdr,
                  (uint32_t)prog, (int)vers);
                /* We transplant the xdr of the client into the entry 
                   representing the callback client in the list of servers.
                   Note that since we hold the wait_cb_lock for this client,
                   if another call for this callback client arrives before
                   we've finished processing this call, that will block until
                   we're done with this one.  If this happens, it would be
                   most likely a bug in the arm9 rpc router.
                */
                if (*svc_xdr) {
                    D("%08x:%08x expecting XDR == NULL"
                      "callback client %08x:%08x!\n",
                      client->xdr->x_prog,
                      client->xdr->x_vers,
                      (uint32_t)prog, (int)vers);
                    xdr_destroy_common(*svc_xdr);
                }
                

                /* Do these checks before the clone */
                if (client->xdr->in_len < 0) {
                    E("%08x:%08x xdr->in_len = %i error %s (%d)",
                        client->xdr->in_len,
                        client->xdr->x_prog, client->xdr->x_vers,
                        strerror(errno), errno);
                    continue;
                }
                if (client->xdr->out_next < 0) {
                    E("%08x:%08x xdr->out_next = %i error %s (%d)",
                        client->xdr->out_next,
                        client->xdr->x_prog, client->xdr->x_vers,
                    strerror(errno), errno);
                    continue;
                }

                D("%08x:%08x cloning XDR for "
                  "callback client %08x:%08x.\n",
                  client->xdr->x_prog,
                  client->xdr->x_vers,
                  (uint32_t)prog, (int)vers);
                *svc_xdr = xdr_clone(client->xdr);
                
                (*svc_xdr)->x_prog = prog;
                (*svc_xdr)->x_vers = vers;
                memcpy((*svc_xdr)->in_msg,
                       client->xdr->in_msg, client->xdr->in_len);
                memcpy((*svc_xdr)->out_msg,
                       client->xdr->out_msg, client->xdr->out_next);
                (*svc_xdr)->in_len = client->xdr->in_len;
                (*svc_xdr)->out_next = client->xdr->out_next;

                pthread_mutex_lock(&client->input_xdr_lock);
                D("%08x:%08x marking input buffer as free.\n",
                  client->xdr->x_prog, client->xdr->x_vers);
                client->input_xdr_busy = 0;
                pthread_cond_signal(&client->input_xdr_wait);
                pthread_mutex_unlock(&client->input_xdr_lock);

                svc_dispatch(svc, the_xprt);
                xdr_destroy_common(*svc_xdr);
                *svc_xdr = NULL;
            }
            else E("%08x:%08x call packet arrived, but there's no "
                   "RPC server registered for %08x:%08x.\n",
                   client->xdr->x_prog,
                   client->xdr->x_vers,                   
                   (uint32_t)prog, (int)vers);                           
        }
        else E("%08x:%08x call packet arrived, but there's "
               "no RPC transport!\n",
               client->xdr->x_prog,
               client->xdr->x_vers);

        releaseWakeLock();
    }
    pthread_mutex_unlock(&client->wait_cb_lock);


    D("RPC-callback thread for %08x:%08x terminating.\n",
      (client->xdr->x_prog | 0x01000000),
      client->xdr->x_vers);
    return NULL;
}