/** * nfs_svc_create - start up RPC svc listeners * @name: C string containing name of new service * @program: RPC program number to register * @version: RPC version number to register * @dispatch: address of function that handles incoming RPC requests * @port: if not zero, transport listens on this port * * Sets up network transports for receiving RPC requests, and starts * the RPC dispatcher. Returns the number of started network transports. */ unsigned int nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version, void (*dispatch)(struct svc_req *, SVCXPRT *), const uint16_t port) { const struct sigaction create_sigaction = { .sa_handler = SIG_IGN, }; unsigned int visible, up, servport; struct netconfig *nconf; void *handlep; /* * Ignore SIGPIPE to avoid exiting sideways when peers * close their TCP connection while we're trying to reply * to them. */ (void)sigaction(SIGPIPE, &create_sigaction, NULL); handlep = setnetconfig(); if (handlep == NULL) { xlog(L_ERROR, "Failed to access local netconfig database: %s", nc_sperror()); return 0; } visible = 0; up = 0; while ((nconf = getnetconfig(handlep)) != NULL) { if (!(nconf->nc_flag & NC_VISIBLE)) continue; visible++; if (port == 0) servport = getservport(program, nconf->nc_proto); else servport = port; up += svc_create_nconf(name, program, version, dispatch, servport, nconf); } if (visible == 0) xlog(L_ERROR, "Failed to find any visible netconfig entries"); if (endnetconfig(handlep) == -1) xlog(L_ERROR, "Failed to close local netconfig database: %s", nc_sperror()); return up; }
/* Unregister all the registrations done by register_rpc_service */ void unregister_rpc_service(const char *fmri, const rpc_info_t *rpc) { int ver; struct netconfig *nconf; debug_msg("Entering unregister_rpc_service, instance: %s", fmri); if ((nconf = getnetconfigent(rpc->netid)) == NULL) { /* * Don't output an error message if getnetconfigent() fails for * a v6 netid when an IPv6 interface isn't configured. */ if (!(is_v6_netid(rpc->netid) && !can_use_af(AF_INET6))) { error_msg(gettext( "Failed to lookup netid '%s' for instance %s: %s"), rpc->netid, fmri, nc_sperror()); } return; } for (ver = rpc->lowver; ver <= rpc->highver; ver++) (void) rpcb_unset(rpc->prognum, ver, nconf); freenetconfigent(nconf); }
int _des_crypt_call(char *buf, int len, struct desparams *dparms) { CLIENT *clnt; desresp *result_1; desargs des_crypt_1_arg; struct netconfig *nconf; void *localhandle; int stat; nconf = NULL; localhandle = setnetconfig(); while ((nconf = getnetconfig(localhandle)) != NULL) { if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) break; } if (nconf == NULL) { warnx("getnetconfig: %s", nc_sperror()); endnetconfig(localhandle); return(DESERR_HWERROR); } clnt = clnt_tp_create(NULL, CRYPT_PROG, CRYPT_VERS, nconf); if (clnt == (CLIENT *) NULL) { endnetconfig(localhandle); return(DESERR_HWERROR); } endnetconfig(localhandle); des_crypt_1_arg.desbuf.desbuf_len = len; des_crypt_1_arg.desbuf.desbuf_val = buf; des_crypt_1_arg.des_dir = (dparms->des_dir == ENCRYPT) ? ENCRYPT_DES : DECRYPT_DES; des_crypt_1_arg.des_mode = (dparms->des_mode == CBC) ? CBC_DES : ECB_DES; bcopy(dparms->des_ivec, des_crypt_1_arg.des_ivec, 8); bcopy(dparms->des_key, des_crypt_1_arg.des_key, 8); result_1 = des_crypt_1(&des_crypt_1_arg, clnt); if (result_1 == (desresp *) NULL) { clnt_destroy(clnt); return(DESERR_HWERROR); } stat = result_1->stat; if (result_1->stat == DESERR_NONE || result_1->stat == DESERR_NOHWDEVICE) { bcopy(result_1->desbuf.desbuf_val, buf, len); bcopy(result_1->des_ivec, dparms->des_ivec, 8); } clnt_freeres(clnt, (xdrproc_t)xdr_desresp, result_1); clnt_destroy(clnt); return(stat); }
/* * Determines the availability of rpc.yppasswdd. Returns -1 for not * available (or unable to determine), 0 for available, 1 for available in * master mode. */ int ypclnt_havepasswdd(ypclnt_t *ypclnt) { struct netconfig *nc = NULL; void *localhandle = 0; CLIENT *clnt = NULL; int ret; /* check if rpc.yppasswdd is running */ if (getrpcport(ypclnt->server, YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP) == 0) { ypclnt_error(ypclnt, __func__, "no rpc.yppasswdd on server"); return (-1); } /* if we're not root, use remote method */ if (getuid() != 0) return (0); /* try to connect to rpc.yppasswdd */ localhandle = setnetconfig(); while ((nc = getnetconfig(localhandle)) != NULL) { if (nc->nc_protofmly != NULL && strcmp(nc->nc_protofmly, NC_LOOPBACK) == 0) break; } if (nc == NULL) { ypclnt_error(ypclnt, __func__, "getnetconfig: %s", nc_sperror()); ret = 0; goto done; } if ((clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS, nc)) == NULL) { ypclnt_error(ypclnt, __func__, "failed to connect to rpc.yppasswdd: %s", clnt_spcreateerror(ypclnt->server)); ret = 0; goto done; } else ret = 1; done: if (clnt != NULL) { clnt_destroy(clnt); } endnetconfig(localhandle); return (ret); }
/* * Registers with rpcbind the program number with all versions, from low to * high, with the netid, all specified in 'rpc'. If registration fails, * returns -1, else 0. */ int register_rpc_service(const char *fmri, const rpc_info_t *rpc) { struct netconfig *nconf; int ver; debug_msg("Entering register_rpc_service: instance: %s", fmri); if ((nconf = getnetconfigent(rpc->netid)) == NULL) { /* * Check whether getnetconfigent() failed as a result of * having no IPv6 interfaces configured for a v6 netid, or * as a result of a 'real' error, and output an appropriate * message with an appropriate severity. */ if (is_v6_netid(rpc->netid) && !can_use_af(AF_INET6)) { warn_msg(gettext( "Couldn't register netid %s for RPC instance %s " "because no IPv6 interfaces are plumbed"), rpc->netid, fmri); } else { error_msg(gettext( "Failed to lookup netid '%s' for instance %s: %s"), rpc->netid, fmri, nc_sperror()); } return (-1); } for (ver = rpc->lowver; ver <= rpc->highver; ver++) { if (!rpcb_set(rpc->prognum, ver, nconf, &(rpc->netbuf))) { error_msg(gettext("Failed to register version %d " "of RPC service instance %s, netid %s"), ver, fmri, rpc->netid); for (ver--; ver >= rpc->lowver; ver--) (void) rpcb_unset(rpc->prognum, ver, nconf); freenetconfigent(nconf); return (-1); } } freenetconfigent(nconf); return (0); }
static int yppasswd_local(ypclnt_t *ypclnt, const struct passwd *pwd) { struct master_yppasswd yppwd; struct rpc_err rpcerr; struct netconfig *nc = NULL; void *localhandle = 0; CLIENT *clnt = NULL; int ret, *result; /* fill the master_yppasswd structure */ memset(&yppwd, 0, sizeof yppwd); yppwd.newpw.pw_uid = pwd->pw_uid; yppwd.newpw.pw_gid = pwd->pw_gid; yppwd.newpw.pw_change = pwd->pw_change; yppwd.newpw.pw_expire = pwd->pw_expire; yppwd.newpw.pw_fields = pwd->pw_fields; yppwd.oldpass = strdup(""); yppwd.domain = strdup(ypclnt->domain); if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL || (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == NULL || (yppwd.newpw.pw_class = strdup(pwd->pw_class)) == NULL || (yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos)) == NULL || (yppwd.newpw.pw_dir = strdup(pwd->pw_dir)) == NULL || (yppwd.newpw.pw_shell = strdup(pwd->pw_shell)) == NULL) { ypclnt_error(ypclnt, __func__, strerror(errno)); ret = -1; goto done; } /* connect to rpc.yppasswdd */ localhandle = setnetconfig(); while ((nc = getnetconfig(localhandle)) != NULL) { if (nc->nc_protofmly != NULL && strcmp(nc->nc_protofmly, NC_LOOPBACK) == 0) break; } if (nc == NULL) { ypclnt_error(ypclnt, __func__, "getnetconfig: %s", nc_sperror()); ret = -1; goto done; } if ((clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS, nc)) == NULL) { ypclnt_error(ypclnt, __func__, "failed to connect to rpc.yppasswdd: %s", clnt_spcreateerror(ypclnt->server)); ret = -1; goto done; } clnt->cl_auth = authunix_create_default(); /* request the update */ result = yppasswdproc_update_master_1(&yppwd, clnt); /* check for RPC errors */ clnt_geterr(clnt, &rpcerr); if (rpcerr.re_status != RPC_SUCCESS) { ypclnt_error(ypclnt, __func__, "NIS password update failed: %s", clnt_sperror(clnt, ypclnt->server)); ret = -1; goto done; } /* check the result of the update */ if (result == NULL || *result != 0) { ypclnt_error(ypclnt, __func__, "NIS password update failed"); /* XXX how do we get more details? */ ret = -1; goto done; } ypclnt_error(ypclnt, NULL, NULL); ret = 0; done: if (clnt != NULL) { auth_destroy(clnt->cl_auth); clnt_destroy(clnt); } endnetconfig(localhandle); free(yppwd.newpw.pw_name); if (yppwd.newpw.pw_passwd != NULL) { memset(yppwd.newpw.pw_passwd, 0, strlen(yppwd.newpw.pw_passwd)); free(yppwd.newpw.pw_passwd); } free(yppwd.newpw.pw_class); free(yppwd.newpw.pw_gecos); free(yppwd.newpw.pw_dir); free(yppwd.newpw.pw_shell); if (yppwd.oldpass != NULL) { memset(yppwd.oldpass, 0, strlen(yppwd.oldpass)); free(yppwd.oldpass); } return (ret); }
int main(int argc, char **argv) { int nflag = 0; int c; int warn = 0; char *path = NULL; void *localhandle; SVCXPRT *transp; struct netconfig *nconf = NULL; __key_encryptsession_pk_LOCAL = &key_encrypt_pk_2_svc_prog; __key_decryptsession_pk_LOCAL = &key_decrypt_pk_2_svc_prog; __key_gendes_LOCAL = &key_gen_1_svc_prog; while ((c = getopt(argc, argv, "ndDvp:")) != -1) switch (c) { case 'n': nflag++; break; case 'd': pk_nodefaultkeys(); break; case 'D': debugging = 1; break; case 'v': warn = 1; break; case 'p': path = optarg; break; default: usage(); } load_des(warn, path); __des_crypt_LOCAL = _my_crypt; if (svc_auth_reg(AUTH_DES, _svcauth_des) == -1) errx(1, "failed to register AUTH_DES authenticator"); if (optind != argc) { usage(); } /* * Initialize */ umask(S_IXUSR|S_IXGRP|S_IXOTH); if (geteuid() != 0) errx(1, "keyserv must be run as root"); setmodulus(HEXMODULUS); getrootkey(&masterkey, nflag); rpcb_unset(KEY_PROG, KEY_VERS, NULL); rpcb_unset(KEY_PROG, KEY_VERS2, NULL); if (svc_create(keyprogram, KEY_PROG, KEY_VERS, "netpath") == 0) { fprintf(stderr, "%s: unable to create service\n", argv[0]); exit(1); } if (svc_create(keyprogram, KEY_PROG, KEY_VERS2, "netpath") == 0) { fprintf(stderr, "%s: unable to create service\n", argv[0]); exit(1); } localhandle = setnetconfig(); while ((nconf = getnetconfig(localhandle)) != NULL) { if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) break; } if (nconf == NULL) errx(1, "getnetconfig: %s", nc_sperror()); unlink(KEYSERVSOCK); rpcb_unset(CRYPT_PROG, CRYPT_VERS, nconf); transp = svcunix_create(RPC_ANYSOCK, 0, 0, KEYSERVSOCK); if (transp == NULL) errx(1, "cannot create AF_LOCAL service"); if (!svc_reg(transp, KEY_PROG, KEY_VERS, keyprogram, nconf)) errx(1, "unable to register (KEY_PROG, KEY_VERS, unix)"); if (!svc_reg(transp, KEY_PROG, KEY_VERS2, keyprogram, nconf)) errx(1, "unable to register (KEY_PROG, KEY_VERS2, unix)"); if (!svc_reg(transp, CRYPT_PROG, CRYPT_VERS, crypt_prog_1, nconf)) errx(1, "unable to register (CRYPT_PROG, CRYPT_VERS, unix)"); endnetconfig(localhandle); umask(066); /* paranoia */ if (!debugging) { daemon(0,0); } signal(SIGPIPE, SIG_IGN); svc_run(); abort(); /* NOTREACHED */ }
/* * Prints a message onto standard error describing the reason for failure. */ void nc_perror(const char *s) { fprintf(stderr, "%s: %s\n", s, nc_sperror()); }
/* * Create an rpc client attached to the mount daemon. */ CLIENT * get_mount_client(char *host, struct sockaddr_in *unused_sin, struct timeval *tv, int *sock, u_long mnt_version) { CLIENT *client; struct netbuf nb; struct netconfig *nc = NULL; struct sockaddr_in sin; nb.maxlen = sizeof(sin); nb.buf = (char *) &sin; /* * First try a TCP handler */ /* * Find mountd address on TCP */ if ((nc = getnetconfigent(NC_TCP)) == NULL) { plog(XLOG_ERROR, "getnetconfig for tcp failed: %s", nc_sperror()); goto tryudp; } if (!rpcb_getaddr(MOUNTPROG, mnt_version, nc, &nb, host)) { /* * don't print error messages here, since mountd might legitimately * serve udp only */ goto tryudp; } /* * Create privileged TCP socket */ *sock = t_open(nc->nc_device, O_RDWR, 0); if (*sock < 0) { plog(XLOG_ERROR, "t_open %s: %m", nc->nc_device); goto tryudp; } if (bind_resv_port(*sock, (u_short *) 0) < 0) plog(XLOG_ERROR, "couldn't bind mountd socket to privileged port"); if ((client = clnt_vc_create(*sock, &nb, MOUNTPROG, mnt_version, 0, 0)) == (CLIENT *) NULL) { plog(XLOG_ERROR, "clnt_vc_create failed"); t_close(*sock); goto tryudp; } /* tcp succeeded */ dlog("get_mount_client: using tcp, port %d", sin.sin_port); if (nc) freenetconfigent(nc); return client; tryudp: /* first free possibly previously allocated netconfig entry */ if (nc) freenetconfigent(nc); /* * TCP failed so try UDP */ /* * Find mountd address on UDP */ if ((nc = getnetconfigent(NC_UDP)) == NULL) { plog(XLOG_ERROR, "getnetconfig for udp failed: %s", nc_sperror()); goto badout; } if (!rpcb_getaddr(MOUNTPROG, mnt_version, nc, &nb, host)) { plog(XLOG_ERROR, "%s", clnt_spcreateerror("couldn't get mountd address on udp")); goto badout; } /* * Create privileged UDP socket */ *sock = t_open(nc->nc_device, O_RDWR, 0); if (*sock < 0) { plog(XLOG_ERROR, "t_open %s: %m", nc->nc_device); goto badout; /* neither tcp not udp succeeded */ } if (bind_resv_port(*sock, (u_short *) 0) < 0) plog(XLOG_ERROR, "couldn't bind mountd socket to privileged port"); if ((client = clnt_dg_create(*sock, &nb, MOUNTPROG, mnt_version, 0, 0)) == (CLIENT *) NULL) { plog(XLOG_ERROR, "clnt_dg_create failed"); t_close(*sock); goto badout; /* neither tcp not udp succeeded */ } if (clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) tv) == FALSE) { plog(XLOG_ERROR, "clnt_control CLSET_RETRY_TIMEOUT for udp failed"); clnt_destroy(client); goto badout; /* neither tcp not udp succeeded */ } /* udp succeeded */ dlog("get_mount_client: using udp, port %d", sin.sin_port); return client; badout: /* failed */ if (nc) freenetconfigent(nc); return NULL; }
/* * How to bind to reserved ports. * (port-only) version. */ int bind_resv_port2(u_short *pp) { int td, rc = -1, port; struct t_bind *treq, *tret; struct sockaddr_in *sin; extern char *t_errlist[]; extern int t_errno; struct netconfig *nc = (struct netconfig *) NULL; voidp nc_handle; if ((nc_handle = setnetconfig()) == (voidp) NULL) { plog(XLOG_ERROR, "Cannot rewind netconfig: %s", nc_sperror()); return -1; } /* * Search the netconfig table for INET/UDP. * This loop will terminate if there was an error in the /etc/netconfig * file or if you reached the end of the file without finding the udp * device. Either way your machine has probably far more problems (for * example, you cannot have nfs v2 w/o UDP). */ while (1) { if ((nc = getnetconfig(nc_handle)) == (struct netconfig *) NULL) { plog(XLOG_ERROR, "Error accessing getnetconfig: %s", nc_sperror()); endnetconfig(nc_handle); return -1; } if (STREQ(nc->nc_protofmly, NC_INET) && STREQ(nc->nc_proto, NC_UDP)) break; } /* * This is the primary reason for the getnetconfig code above: to get the * correct device name to udp, and t_open a descriptor to be used in * t_bind below. */ td = t_open(nc->nc_device, O_RDWR, (struct t_info *) 0); endnetconfig(nc_handle); if (td < 0) { plog(XLOG_ERROR, "t_open failed: %d: %s", t_errno, t_errlist[t_errno]); return -1; } treq = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR); if (!treq) { plog(XLOG_ERROR, "t_alloc req"); return -1; } tret = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR); if (!tret) { t_free((char *) treq, T_BIND); plog(XLOG_ERROR, "t_alloc ret"); return -1; } memset((char *) treq->addr.buf, 0, treq->addr.len); sin = (struct sockaddr_in *) treq->addr.buf; sin->sin_family = AF_INET; treq->qlen = 0; treq->addr.len = treq->addr.maxlen; errno = EADDRINUSE; port = IPPORT_RESERVED; do { --port; sin->sin_port = htons(port); rc = t_bind(td, treq, tret); if (rc < 0) { plog(XLOG_ERROR, "t_bind for port %d: %s", port, t_errlist[t_errno]); } else { if (memcmp(treq->addr.buf, tret->addr.buf, tret->addr.len) == 0) break; else t_unbind(td); } } while ((rc < 0 || errno == EADDRINUSE) && (int) port > IPPORT_RESERVED / 2); if (pp && rc == 0) *pp = port; t_free((char *) tret, T_BIND); t_free((char *) treq, T_BIND); return rc; }
/* * We use our own private version of svc_create() which registers our services * only on loopback transports and enables an option whereby Solaris ucreds * are associated with each connection, permitting us to check privilege bits. */ static int fmd_rpc_svc_create_local(void (*disp)(struct svc_req *, SVCXPRT *), rpcprog_t prog, rpcvers_t vers, uint_t ssz, uint_t rsz, int force) { struct netconfig *ncp; struct netbuf buf; SVCXPRT *xprt; void *hdl; int fd, n = 0; char door[PATH_MAX]; time_t tm; if ((hdl = setnetconfig()) == NULL) { fmd_error(EFMD_RPC_REG, "failed to iterate over " "netconfig database: %s\n", nc_sperror()); return (fmd_set_errno(EFMD_RPC_REG)); } if (force) svc_unreg(prog, vers); /* clear stale rpcbind registrations */ buf.buf = alloca(_SS_MAXSIZE); buf.maxlen = _SS_MAXSIZE; buf.len = 0; while ((ncp = getnetconfig(hdl)) != NULL) { if (strcmp(ncp->nc_protofmly, NC_LOOPBACK) != 0) continue; if (!force && rpcb_getaddr(prog, vers, ncp, &buf, HOST_SELF)) { (void) endnetconfig(hdl); return (fmd_set_errno(EFMD_RPC_BOUND)); } if ((fd = t_open(ncp->nc_device, O_RDWR, NULL)) == -1) { fmd_error(EFMD_RPC_REG, "failed to open %s: %s\n", ncp->nc_device, t_strerror(t_errno)); continue; } svc_fd_negotiate_ucred(fd); /* enable ucred option on xprt */ if ((xprt = svc_tli_create(fd, ncp, NULL, ssz, rsz)) == NULL) { (void) t_close(fd); continue; } if (svc_reg(xprt, prog, vers, disp, ncp) == FALSE) { fmd_error(EFMD_RPC_REG, "failed to register " "rpc service on %s\n", ncp->nc_netid); svc_destroy(xprt); continue; } n++; } (void) endnetconfig(hdl); /* * If we failed to register services (n == 0) because rpcbind is down, * then check to see if the RPC door file exists before attempting an * svc_door_create(), which cleverly destroys any existing door file. * The RPC APIs have no stable errnos, so we use rpcb_gettime() as a * hack to determine if rpcbind itself is down. */ if (!force && n == 0 && rpcb_gettime(HOST_SELF, &tm) == FALSE && snprintf(door, sizeof (door), RPC_DOOR_RENDEZVOUS, prog, vers) > 0 && access(door, F_OK) == 0) return (fmd_set_errno(EFMD_RPC_BOUND)); /* * Attempt to create a door server for the RPC program as well. Limit * the maximum request size for the door transport to the receive size. */ if ((xprt = svc_door_create(disp, prog, vers, ssz)) == NULL) { fmd_error(EFMD_RPC_REG, "failed to create door for " "rpc service 0x%lx/0x%lx\n", prog, vers); } else { (void) svc_control(xprt, SVCSET_CONNMAXREC, &rsz); n++; } return (n); }