/* * This the routine has the same definition as clnt_create_vers(), * except it takes an additional timeout parameter - a pointer to * a timeval structure. A NULL value for the pointer indicates * that the default timeout value should be used. */ CLIENT * clnt_create_vers_timed(const char *hostname, const rpcprog_t prog, rpcvers_t *vers_out, const rpcvers_t vers_low_in, const rpcvers_t vers_high_in, const char *nettype, const struct timeval *tp) { CLIENT *clnt; struct timeval to; enum clnt_stat rpc_stat; struct rpc_err rpcerr; rpcvers_t vers_high = vers_high_in; rpcvers_t vers_low = vers_low_in; clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp); if (clnt == NULL) { return (NULL); } to.tv_sec = 10; to.tv_usec = 0; rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, (char *)NULL, (xdrproc_t)xdr_void, (char *)NULL, to); if (rpc_stat == RPC_SUCCESS) { *vers_out = vers_high; return (clnt); } while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) { unsigned int minvers, maxvers; clnt_geterr(clnt, &rpcerr); minvers = rpcerr.re_vers.low; maxvers = rpcerr.re_vers.high; if (maxvers < vers_high) vers_high = maxvers; else vers_high--; if (minvers > vers_low) vers_low = minvers; if (vers_low > vers_high) { goto error; } CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high); rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, (char *)NULL, (xdrproc_t)xdr_void, (char *)NULL, to); if (rpc_stat == RPC_SUCCESS) { *vers_out = vers_high; return (clnt); } } clnt_geterr(clnt, &rpcerr); error: rpc_createerr.cf_stat = rpc_stat; rpc_createerr.cf_error = rpcerr; clnt_destroy(clnt); return (NULL); }
/**************************************************************************************** * * PUBLIC FUNCTION: gettunnelinfo * ***************************************************************************************/ int CCHacontroller::gettunnelinfo( TGetTunnelRequest aArgs, THaTunnelInfo *rv ) { struct rpc_err rerr; // check the rv pointer if( rv == NULL ) { return ERR_INVALID_RV_POINTER; } // check that we have a connection if( cl == NULL ) { return ERR_STUB_NOT_CONNECTED; } // do the call *rv = *gettunnelinfo_8( &aArgs, cl ); // check for rpc errors and return the result clnt_geterr( cl, &rerr ); if( rerr.re_status != RPC_SUCCESS ) { iLastRPCError = rerr; return ERR_RPC_ERROR; } return ERR_NONE; }
/**************************************************************************************** * * PUBLIC FUNCTION: removelistoption * ***************************************************************************************/ int CCHacontroller::removelistoption( TOptionDesc aArgs, TResult *rv ) { struct rpc_err rerr; // check the rv pointer if( rv == NULL ) { return ERR_INVALID_RV_POINTER; } // check that we have a connection if( cl == NULL ) { return ERR_STUB_NOT_CONNECTED; } // do the call *rv = *removelistoption_8( &aArgs, cl ); // check for rpc errors and return the result clnt_geterr( cl, &rerr ); if( rerr.re_status != RPC_SUCCESS ) { iLastRPCError = rerr; return ERR_RPC_ERROR; } return ERR_NONE; }
int main(int argn, char *argc[]) { //Program parameters : argc[1] : HostName or Host IP // argc[2] : Server Program Number // other arguments depend on test case //run_mode can switch into stand alone program or program launch by shell script //1 : stand alone, debug mode, more screen information //0 : launch by shell script as test case, only one printf -> result status int run_mode = 0; int test_status = 1; //Default test result set to FAILED int progNum = atoi(argc[2]); char proto[8] = "udp"; CLIENT *clnt = NULL; struct rpc_err err; //First of all, create a client clnt = clnt_create(argc[1], progNum, VERSNUM, proto); if (run_mode == 1) { printf("CLIENT : %d\n", clnt); } //Call tested routine clnt_geterr(clnt, &err); //If we are here, macro call was successful test_status = !(err.re_status == RPC_SUCCESS); //This last printf gives the result status to the tests suite //normally should be 0: test has passed or 1: test has failed printf("%d\n", test_status); return test_status; }
static ErrorObj* ldm_clnt_nullproc(CLIENT* const clnt) { struct timeval timeout; ErrorObj* error; log_assert(NULL != clnt); timeout.tv_sec = 25; /* RPC default */ timeout.tv_usec = 0; if (clnt_call(clnt, NULLPROC, xdr_void, NULL, xdr_void, NULL, timeout) == 0) { error = NULL; } else { struct rpc_err rpcErr; clnt_geterr(clnt, &rpcErr); error = ERR_NEW(rpcErr.re_status, NULL, clnt_errmsg(clnt)); } return error; }
/**************************************************************************************** * * PUBLIC FUNCTION: getppplog * ***************************************************************************************/ int CCPppcontroller::getppplog( int aArgs, TVarData *rv ) { struct rpc_err rerr; // check the rv pointer if( rv == NULL ) { return ERR_INVALID_RV_POINTER; } // check that we have a connection if( cl == NULL ) { return ERR_STUB_NOT_CONNECTED; } // do the call *rv = *getppplog_4( &aArgs, cl ); // check for rpc errors and return the result clnt_geterr( cl, &rerr ); if( rerr.re_status != RPC_SUCCESS ) { iLastRPCError = rerr; return ERR_RPC_ERROR; } return ERR_NONE; }
/* * Find the mapped port for program,version. * Calls the pmap service remotely to do the lookup. * Returns 0 if no map exists. */ u_short pmap_getport(struct sockaddr_in *address, u_long program, u_long version, u_int protocol) { u_short port = 0; int sock = -1; CLIENT *client; struct pmap parms; assert(address != NULL); address->sin_port = htons(PMAPPORT); client = clntudp_bufcreate(address, PMAPPROG, PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); if (client != NULL) { parms.pm_prog = program; parms.pm_vers = version; parms.pm_prot = protocol; parms.pm_port = 0; /* not needed or used */ if (CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, (xdrproc_t)xdr_pmap, &parms, (xdrproc_t)xdr_u_short, &port, tottimeout) != RPC_SUCCESS){ rpc_createerr.cf_stat = RPC_PMAPFAILURE; clnt_geterr(client, &rpc_createerr.cf_error); } else if (port == 0) { rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; } CLNT_DESTROY(client); } address->sin_port = 0; return (port); }
/* * Find the mapped port for program,version. * Calls the pmap service remotely to do the lookup. * Returns 0 if no map exists. */ u_short pmap_getport( struct sockaddr_in *address, rpcprog_t program, rpcvers_t version, rpcprot_t protocol) { unsigned short port = 0; int sock = -1; register CLIENT *client; struct pmap parms; address->sin_port = htons(PMAPPORT); client = clntudp_bufcreate(address, PMAPPROG, PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); if (client != (CLIENT *)NULL) { parms.pm_prog = program; parms.pm_vers = version; parms.pm_prot = protocol; parms.pm_port = 0; /* not needed or used */ if (CLNT_CALL(client, PMAPPROC_GETPORT, xdr_pmap, &parms, xdr_u_short, &port, tottimeout) != RPC_SUCCESS) { rpc_createerr.cf_stat = RPC_PMAPFAILURE; clnt_geterr(client, &rpc_createerr.cf_error); } else if (port == 0) { rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; } CLNT_DESTROY(client); } (void)close(sock); address->sin_port = 0; return (port); }
/**************************************************************************************** * * PUBLIC FUNCTION: list_devices * ***************************************************************************************/ int CCHacontroller::list_devices( TComponentList *rv ) { struct rpc_err rerr; int aArgs = 0; // check the rv pointer if( rv == NULL ) { return ERR_INVALID_RV_POINTER; } // check that we have a connection if( cl == NULL ) { return ERR_STUB_NOT_CONNECTED; } // do the call *rv = *list_devices_8( &aArgs, cl ); // check for rpc errors and return the result clnt_geterr( cl, &rerr ); if( rerr.re_status != RPC_SUCCESS ) { iLastRPCError = rerr; return ERR_RPC_ERROR; } return ERR_NONE; }
/* * Returns the LDM proxy status for a given client failure. Logs the failure. * * Arguments: * proxy The LDM proxy data-structure. * name The name of the failed message or NULL. * info Metadata on the data-product that couldn't be sent or * NULL. * Returns: * 0 Success. * LP_TIMEDOUT The failure was due to an RPC timeout. "log_start()" * called iff "name" isn't NULL. * LP_RPC_ERROR RPC error. "log_start()" called iff "name" isn't NULL. */ static LdmProxyStatus getStatus( LdmProxy* const proxy, const char* const name, prod_info* const info) { LdmProxyStatus status; struct rpc_err rpcErr; clnt_geterr(proxy->clnt, &rpcErr); if (0 == rpcErr.re_status) { status = 0; } else { if (NULL != name) { LOG_START3("%s failure to host \"%s\": %s", name, proxy->host, clnt_errmsg(proxy->clnt)); if (NULL != info) { LOG_ADD1("Couldn't send product: %s", s_prod_info(NULL, 0, info, ulogIsDebug())); } } status = RPC_TIMEDOUT == rpcErr.re_status ? LP_TIMEDOUT : LP_RPC_ERROR; } return status; }
/**************************************************************************************** * * PUBLIC FUNCTION: ss_startuprpcservice * ***************************************************************************************/ int CCHacontroller::ss_startuprpcservice( TStartupInfo aArgs, int *rv ) { struct rpc_err rerr; // check the rv pointer if( rv == NULL ) { return ERR_INVALID_RV_POINTER; } // check that we have a connection if( cl == NULL ) { return ERR_STUB_NOT_CONNECTED; } // do the call *rv = *ss_startuprpcservice_8( &aArgs, cl ); // check for rpc errors and return the result clnt_geterr( cl, &rerr ); if( rerr.re_status != RPC_SUCCESS ) { iLastRPCError = rerr; return ERR_RPC_ERROR; } return ERR_NONE; }
char * clnt_sperror(struct client *clnt, const char *msg) { /* FIXME should use snprintf instead sprintf */ static char buff[ERROR_STR_MAX_SZ]; struct rpc_err err; char *curr, *auth_msg; assert((clnt != NULL) && (msg != NULL)); clnt_geterr(clnt, &err); curr = buff; curr += sprintf(curr, "%s: %s", msg, clnt_sperrno(err.status)); switch (err.status) { default: curr += sprintf(curr, "; s1 = %u, s2 = %u", err.extra.mminfo.low, err.extra.mminfo.high); break; case RPC_SUCCESS: case RPC_CANTENCODEARGS: case RPC_CANTDECODERES: case RPC_TIMEDOUT: case RPC_PROGUNAVAIL: case RPC_PROCUNAVAIL: case RPC_CANTDECODEARGS: case RPC_SYSTEMERROR: case RPC_UNKNOWNHOST: case RPC_PMAPFAILURE: case RPC_PROGNOTREGISTERED: case RPC_FAILED: case RPC_UNKNOWNPROTO: break; case RPC_CANTSEND: case RPC_CANTRECV: curr += sprintf(curr, "; errno = %s", strerror(err.extra.error)); break; case RPC_VERSMISMATCH: curr += sprintf(curr, "; low version = %u, high version = %u", err.extra.mminfo.low, err.extra.mminfo.high); break; case RPC_AUTHERROR: auth_msg = get_auth_msg(err.extra.reason); if (auth_msg != NULL) { curr += sprintf(curr, "; why = %s", auth_msg); } else { curr += sprintf(curr, "; why = (unknown authentication error - %d)", err.extra.reason); } break; case RPC_PROGVERSMISMATCH: curr += sprintf(curr, "; low version = %u, high version = %u", err.extra.mminfo.low, err.extra.mminfo.high); break; } assert(curr < buff + sizeof buff); // TODO remove this return buff; }
char *CCPppcontroller::GetLastRPCError( int *aIntErr ) { struct rpc_err rpcerr; // check that the handle is valid if( cl == NULL ) { return NULL; } // pass the aIntErr if( aIntErr != NULL ) { clnt_geterr( cl, &rpcerr ); *aIntErr = rpcerr.re_status; } // return the errorstring return clnt_sperror( cl, NULL ); }
/**************************************************************************************** * * PUBLIC FUNCTION: settimeout * ***************************************************************************************/ int CCHacontroller::settimeout( TTimeoutRequest aArgs ) { struct rpc_err rerr; // check that we have a connection if( cl == NULL ) { return ERR_STUB_NOT_CONNECTED; } // do the call settimeout_8( &aArgs, cl ); // check for rpc errors and return the result clnt_geterr( cl, &rerr ); if( rerr.re_status != RPC_SUCCESS ) { iLastRPCError = rerr; return ERR_RPC_ERROR; } return ERR_NONE; }
static int nfs_call_mount(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server, mntarg_t *mntarg, mntres_t *mntres) { CLIENT *clnt; enum clnt_stat stat; int msock; if (!probe_bothports(mnt_server, nfs_server)) goto out_bad; clnt = mnt_openclnt(mnt_server, &msock); if (!clnt) goto out_bad; /* make pointers in xdr_mountres3 NULL so * that xdr_array allocates memory for us */ memset(mntres, 0, sizeof(*mntres)); switch (mnt_server->pmap.pm_vers) { case 3: stat = nfs3_mount(clnt, mntarg, &mntres->nfsv3); break; case 2: case 1: stat = nfs2_mount(clnt, mntarg, &mntres->nfsv2); break; default: goto out_bad; } if (stat != RPC_SUCCESS) { clnt_geterr(clnt, &rpc_createerr.cf_error); rpc_createerr.cf_stat = stat; } mnt_closeclnt(clnt, msock); if (stat == RPC_SUCCESS) return 1; out_bad: return 0; }
/* * If the server (fmd) is restarted, this will cause all future door calls to * fail. Unfortunately, once the server comes back up, we have no way of * reestablishing the connection. To get around this, if the error indicates * that the RPC call failed, we reopen the client handle and try again. For * simplicity we only deal with the door case, as it's unclear whether the * remote case suffers from the same pathology. */ boolean_t fmd_adm_retry(fmd_adm_t *ap, enum clnt_stat cs, uint_t *retries) { CLIENT *c; struct rpc_err err; if (cs == RPC_SUCCESS || *retries == ap->adm_maxretries) return (B_FALSE); clnt_geterr(ap->adm_clnt, &err); if (err.re_status != RPC_CANTSEND) return (B_FALSE); if ((c = clnt_door_create(ap->adm_prog, FMD_ADM_VERSION_1, _fmd_adm_bufsize)) == NULL) return (B_FALSE); (*retries)++; clnt_destroy(ap->adm_clnt); ap->adm_clnt = c; return (B_TRUE); }
/* * Print reply error info * * This is derived from RPC 4.0 source. It's here because at least one * implementation of the RPC function clnt_sperror() results in a segmentation * violation (SunOS 5.8). */ char* clnt_errmsg(CLIENT* clnt) { struct rpc_err e; static char buf[512]; char *str = buf; clnt_geterr(clnt, &e); (void) strncpy(str, clnt_sperrno(e.re_status), sizeof(buf)); str[sizeof(buf)-1] = 0; str += strlen(str); switch (e.re_status) { case RPC_SUCCESS: case RPC_CANTENCODEARGS: case RPC_CANTDECODERES: case RPC_TIMEDOUT: case RPC_PROGUNAVAIL: case RPC_PROCUNAVAIL: case RPC_CANTDECODEARGS: case RPC_SYSTEMERROR: case RPC_UNKNOWNHOST: case RPC_UNKNOWNPROTO: case RPC_PMAPFAILURE: case RPC_PROGNOTREGISTERED: case RPC_FAILED: break; case RPC_CANTSEND: case RPC_CANTRECV: (void) sprintf(str, "; errno = %s", strerror(e.re_errno)); str += strlen(str); break; case RPC_VERSMISMATCH: (void) sprintf(str, "; low version = %lu, high version = %lu", e.re_vers.low, e.re_vers.high); str += strlen(str); break; case RPC_AUTHERROR: (void) sprintf(str,"; why = "); str += strlen(str); (void) sprintf(str, "(authentication error %d)", (int) e.re_why); str += strlen(str); break; case RPC_PROGVERSMISMATCH: (void) sprintf(str, "; low version = %lu, high version = %lu", e.re_vers.low, e.re_vers.high); str += strlen(str); break; default: /* unknown */ (void) sprintf(str, "; s1 = %lu, s2 = %lu", e.re_lb.s1, e.re_lb.s2); str += strlen(str); break; } (void) sprintf(str, "\n"); return buf; }
/* * Function: auth_gssapi_create * * Purpose: Create a GSS-API style authenticator, with all the * options, and return the handle. * * Effects: See design document, section XXX. */ AUTH *auth_gssapi_create( CLIENT *clnt, OM_uint32 *gssstat, OM_uint32 *minor_stat, gss_cred_id_t claimant_cred_handle, gss_name_t target_name, gss_OID mech_type, OM_uint32 req_flags, OM_uint32 time_req, gss_OID *actual_mech_type, OM_uint32 *ret_flags, OM_uint32 *time_rec) { AUTH *auth, *save_auth; struct auth_gssapi_data *pdata; struct gss_channel_bindings_struct bindings, *bindp; struct sockaddr_in laddr, raddr; enum clnt_stat callstat; struct timeval timeout; int bindings_failed; rpcproc_t init_func; auth_gssapi_init_arg call_arg; auth_gssapi_init_res call_res; gss_buffer_desc *input_token, isn_buf; memset(&rpc_createerr, 0, sizeof(rpc_createerr)); /* this timeout is only used if clnt_control(clnt, CLSET_TIMEOUT) */ /* has not already been called.. therefore, we can just pick */ /* something reasonable-sounding.. */ timeout.tv_sec = 30; timeout.tv_usec = 0; auth = NULL; pdata = NULL; /* don't assume the caller will want to change clnt->cl_auth */ save_auth = clnt->cl_auth; auth = (AUTH *) malloc(sizeof(*auth)); pdata = (struct auth_gssapi_data *) malloc(sizeof(*pdata)); if (auth == NULL || pdata == NULL) { /* They needn't both have failed; clean up. */ free(auth); free(pdata); auth = NULL; pdata = NULL; rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = ENOMEM; goto cleanup; } memset((char *) auth, 0, sizeof(*auth)); memset((char *) pdata, 0, sizeof(*pdata)); auth->ah_ops = &auth_gssapi_ops; auth->ah_private = (caddr_t) pdata; /* initial creds are auth_msg TRUE and no handle */ marshall_new_creds(auth, TRUE, NULL); /* initial verifier is empty */ auth->ah_verf.oa_flavor = AUTH_GSSAPI; auth->ah_verf.oa_base = NULL; auth->ah_verf.oa_length = 0; AUTH_PRIVATE(auth)->established = FALSE; AUTH_PRIVATE(auth)->clnt = clnt; AUTH_PRIVATE(auth)->def_cred = (claimant_cred_handle == GSS_C_NO_CREDENTIAL); clnt->cl_auth = auth; /* start by trying latest version */ call_arg.version = 4; bindings_failed = 0; try_new_version: /* set state for initial call to init_sec_context */ input_token = GSS_C_NO_BUFFER; AUTH_PRIVATE(auth)->context = GSS_C_NO_CONTEXT; init_func = AUTH_GSSAPI_INIT; #ifdef GSSAPI_KRB5 /* * OV servers up to version 3 used the old mech id. Beta 7 * servers used version 3 with the new mech id; however, the beta * 7 gss-api accept_sec_context accepts either mech id. Thus, if * any server rejects version 4, we fall back to version 3 with * the old mech id; for the OV server it will be right, and for * the beta 7 server it will be accepted. Not ideal, but it * works. */ if (call_arg.version < 4 && (mech_type == gss_mech_krb5 || mech_type == GSS_C_NULL_OID)) mech_type = (gss_OID) gss_mech_krb5_old; #endif if (!bindings_failed && call_arg.version >= 3) { if (clnt_control(clnt, CLGET_LOCAL_ADDR, &laddr) == FALSE) { PRINTF(("gssapi_create: CLGET_LOCAL_ADDR failed")); goto cleanup; } if (clnt_control(clnt, CLGET_SERVER_ADDR, &raddr) == FALSE) { PRINTF(("gssapi_create: CLGET_SERVER_ADDR failed")); goto cleanup; } memset(&bindings, 0, sizeof(bindings)); bindings.application_data.length = 0; bindings.initiator_addrtype = GSS_C_AF_INET; bindings.initiator_address.length = 4; bindings.initiator_address.value = &laddr.sin_addr.s_addr; bindings.acceptor_addrtype = GSS_C_AF_INET; bindings.acceptor_address.length = 4; bindings.acceptor_address.value = &raddr.sin_addr.s_addr; bindp = &bindings; } else { bindp = NULL; } memset((char *) &call_res, 0, sizeof(call_res)); next_token: *gssstat = gss_init_sec_context(minor_stat, claimant_cred_handle, &AUTH_PRIVATE(auth)->context, target_name, mech_type, req_flags, time_req, bindp, input_token, actual_mech_type, &call_arg.token, ret_flags, time_rec); if (*gssstat != GSS_S_COMPLETE && *gssstat != GSS_S_CONTINUE_NEEDED) { AUTH_GSSAPI_DISPLAY_STATUS(("initializing context", *gssstat, *minor_stat)); goto cleanup; } /* if we got a token, pass it on */ if (call_arg.token.length != 0) { /* * sanity check: if we received a signed isn in the last * response then there *cannot* be another token to send */ if (call_res.signed_isn.length != 0) { PRINTF(("gssapi_create: unexpected token from init_sec\n")); goto cleanup; } PRINTF(("gssapi_create: calling GSSAPI_INIT (%d)\n", init_func)); memset((char *) &call_res, 0, sizeof(call_res)); callstat = clnt_call(clnt, init_func, xdr_authgssapi_init_arg, &call_arg, xdr_authgssapi_init_res, &call_res, timeout); gss_release_buffer(minor_stat, &call_arg.token); if (callstat != RPC_SUCCESS) { struct rpc_err err; clnt_geterr(clnt, &err); if (callstat == RPC_AUTHERROR && (err.re_why == AUTH_BADCRED || err.re_why == AUTH_FAILED) && call_arg.version >= 1) { L_PRINTF(1, ("call_arg protocol version %d rejected, trying %d.\n", call_arg.version, call_arg.version-1)); call_arg.version--; goto try_new_version; } else { PRINTF(("gssapi_create: GSSAPI_INIT (%d) failed, stat %d\n", init_func, callstat)); } goto cleanup; } else if (call_res.version != call_arg.version && !(call_arg.version == 2 && call_res.version == 1)) { /* * The Secure 1.1 servers always respond with version * 1. Thus, if we just tried a version >=3, fall all * the way back to version 1 since that is all they * understand */ if (call_arg.version > 2 && call_res.version == 1) { L_PRINTF(1, ("Talking to Secure 1.1 server, using version 1.\n")); call_arg.version = 1; goto try_new_version; } PRINTF(("gssapi_create: invalid call_res vers %d\n", call_res.version)); goto cleanup; } else if (call_res.gss_major != GSS_S_COMPLETE) { AUTH_GSSAPI_DISPLAY_STATUS(("in response from server", call_res.gss_major, call_res.gss_minor)); goto cleanup; } PRINTF(("gssapi_create: GSSAPI_INIT (%d) succeeded\n", init_func)); init_func = AUTH_GSSAPI_CONTINUE_INIT; /* check for client_handle */ if (AUTH_PRIVATE(auth)->client_handle.length == 0) { if (call_res.client_handle.length == 0) { PRINTF(("gssapi_create: expected client_handle\n")); goto cleanup; } else { PRINTF(("gssapi_create: got client_handle %d\n", *((uint32_t *)call_res.client_handle.value))); GSS_DUP_BUFFER(AUTH_PRIVATE(auth)->client_handle, call_res.client_handle); /* auth_msg is TRUE; there may be more tokens */ marshall_new_creds(auth, TRUE, &AUTH_PRIVATE(auth)->client_handle); } } else if (!GSS_BUFFERS_EQUAL(AUTH_PRIVATE(auth)->client_handle, call_res.client_handle)) { PRINTF(("gssapi_create: got different client_handle\n")); goto cleanup; } /* check for token */ if (call_res.token.length==0 && *gssstat==GSS_S_CONTINUE_NEEDED) { PRINTF(("gssapi_create: expected token\n")); goto cleanup; } else if (call_res.token.length != 0) { if (*gssstat == GSS_S_COMPLETE) { PRINTF(("gssapi_create: got unexpected token\n")); goto cleanup; } else { /* assumes call_res is safe until init_sec_context */ input_token = &call_res.token; PRINTF(("gssapi_create: got new token\n")); } } } /* check for isn */ if (*gssstat == GSS_S_COMPLETE) { if (call_res.signed_isn.length == 0) { PRINTF(("gssapi_created: expected signed isn\n")); goto cleanup; } else { PRINTF(("gssapi_create: processing signed isn\n")); /* don't check conf (integ only) or qop (accpet default) */ *gssstat = gss_unseal(minor_stat, AUTH_PRIVATE(auth)->context, &call_res.signed_isn, &isn_buf, NULL, NULL); if (*gssstat != GSS_S_COMPLETE) { AUTH_GSSAPI_DISPLAY_STATUS(("unsealing isn", *gssstat, *minor_stat)); goto cleanup; } else if (isn_buf.length != sizeof(uint32_t)) { PRINTF(("gssapi_create: gss_unseal gave %d bytes\n", (int) isn_buf.length)); goto cleanup; } AUTH_PRIVATE(auth)->seq_num = (uint32_t) ntohl(*((uint32_t*)isn_buf.value)); *gssstat = gss_release_buffer(minor_stat, &isn_buf); if (*gssstat != GSS_S_COMPLETE) { AUTH_GSSAPI_DISPLAY_STATUS(("releasing unsealed isn", *gssstat, *minor_stat)); goto cleanup; } PRINTF(("gssapi_create: isn is %d\n", AUTH_PRIVATE(auth)->seq_num)); /* we no longer need these results.. */ xdr_free(xdr_authgssapi_init_res, &call_res); } } else if (call_res.signed_isn.length != 0) { PRINTF(("gssapi_create: got signed isn, can't check yet\n")); } /* results were okay.. continue if necessary */ if (*gssstat == GSS_S_CONTINUE_NEEDED) { PRINTF(("gssapi_create: not done, continuing\n")); goto next_token; } /* * Done! Context is established, we have client_handle and isn. */ AUTH_PRIVATE(auth)->established = TRUE; marshall_new_creds(auth, FALSE, &AUTH_PRIVATE(auth)->client_handle); PRINTF(("gssapi_create: done. client_handle %#x, isn %d\n\n", *((uint32_t *)AUTH_PRIVATE(auth)->client_handle.value), AUTH_PRIVATE(auth)->seq_num)); /* don't assume the caller will want to change clnt->cl_auth */ clnt->cl_auth = save_auth; return auth; /******************************************************************/ cleanup: PRINTF(("gssapi_create: bailing\n\n")); if (auth) { if (AUTH_PRIVATE(auth)) auth_gssapi_destroy(auth); else free(auth); auth = NULL; } /* don't assume the caller will want to change clnt->cl_auth */ clnt->cl_auth = save_auth; if (rpc_createerr.cf_stat == 0) rpc_createerr.cf_stat = RPC_AUTHERROR; return auth; }
/* get the best possible NFS version for a host and transport */ static CLIENT * amu_clnt_create_best_vers(const char *hostname, u_long program, u_long *out_version, u_long low_version, u_long high_version, const char *nettype) { CLIENT *clnt; enum clnt_stat rpc_stat; struct rpc_err rpcerr; struct timeval tv; u_long lo, hi; /* 3 seconds is more than enough for a LAN */ tv.tv_sec = 3; tv.tv_usec = 0; #ifdef HAVE_CLNT_CREATE_TIMED clnt = clnt_create_timed(hostname, program, high_version, nettype, &tv); if (!clnt) { plog(XLOG_INFO, "failed to create RPC client to \"%s\" after %d seconds", hostname, (int) tv.tv_sec); return NULL; } #else /* not HAVE_CLNT_CREATE_TIMED */ /* Solaris 2.3 and earlier didn't have clnt_create_timed() */ clnt = clnt_create(hostname, program, high_version, nettype); if (!clnt) { plog(XLOG_INFO, "failed to create RPC client to \"%s\"", hostname); return NULL; } #endif /* not HAVE_CLNT_CREATE_TIMED */ rpc_stat = clnt_call(clnt, NULLPROC, (XDRPROC_T_TYPE) xdr_void, NULL, (XDRPROC_T_TYPE) xdr_void, NULL, tv); if (rpc_stat == RPC_SUCCESS) { *out_version = high_version; return clnt; } while (low_version < high_version) { if (rpc_stat != RPC_PROGVERSMISMATCH) break; clnt_geterr(clnt, &rpcerr); lo = rpcerr.re_vers.low; hi = rpcerr.re_vers.high; if (hi < high_version) high_version = hi; else high_version--; if (lo > low_version) low_version = lo; if (low_version > high_version) goto out; CLNT_CONTROL(clnt, CLSET_VERS, (char *)&high_version); rpc_stat = clnt_call(clnt, NULLPROC, (XDRPROC_T_TYPE) xdr_void, NULL, (XDRPROC_T_TYPE) xdr_void, NULL, tv); if (rpc_stat == RPC_SUCCESS) { *out_version = high_version; return clnt; } } clnt_geterr(clnt, &rpcerr); out: rpc_createerr.cf_stat = rpc_stat; rpc_createerr.cf_error = rpcerr; clnt_destroy(clnt); return NULL; }
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; }
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); }
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); }