📄 rpc.prog.ms
字号:
SVCXPRT *transp;{ char *s = NULL; switch (rqstp->rq_proc) { case NULLPROC: if (!svc_sendreply(transp, xdr_void, 0)) fprintf(stderr, "can't reply to RPC call\en"); return; case RENDERSTRING: if (!svc_getargs(transp, xdr_wrapstring, &s)) { fprintf(stderr, "can't decode arguments\en");.ft I /* * Tell caller he screwed up */.ft CW svcerr_decode(transp); break; }.ft I /* * Code here to render the string \fIs\fP */.ft CW if (!svc_sendreply(transp, xdr_void, NULL)) fprintf(stderr, "can't reply to RPC call\en"); break; case RENDERSTRING_BATCHED: if (!svc_getargs(transp, xdr_wrapstring, &s)) { fprintf(stderr, "can't decode arguments\en");.ft I /* * We are silent in the face of protocol errors */.ft CW break; }.ft I /* * Code here to render string s, but send no reply! */.ft CW break; default: svcerr_noproc(transp); return; }.ft I /* * Now free string allocated while decoding arguments */.ft CW svc_freeargs(transp, xdr_wrapstring, &s);}.DEOf course the service could have one procedurethat takes the string and a booleanto indicate whether or not the procedure should respond..LPIn order for a client to take advantage of batching,the client must perform RPC calls on a TCP-based transportand the actual calls must have the following attributes:1) the result's XDR routine must be zero.I NULL ),and 2) the RPC call's timeout must be zero..KS.LPHere is an example of a client that uses batching to render abunch of strings; the batching is flushed when the client getsa null string (EOF):.ie t .DS.el .DS L.ft CW.vs 11#include <stdio.h>#include <rpc/rpc.h>#include <sys/socket.h>#include <sys/time.h>#include <netdb.h>#include <suntool/windows.h>main(argc, argv) int argc; char **argv;{ struct hostent *hp; struct timeval pertry_timeout, total_timeout; struct sockaddr_in server_addr; int sock = RPC_ANYSOCK; register CLIENT *client; enum clnt_stat clnt_stat; char buf[1000], *s = buf; if ((client = clnttcp_create(&server_addr, WINDOWPROG, WINDOWVERS, &sock, 0, 0)) == NULL) { perror("clnttcp_create"); exit(-1); } total_timeout.tv_sec = 0; total_timeout.tv_usec = 0; while (scanf("%s", s) != EOF) { clnt_stat = clnt_call(client, RENDERSTRING_BATCHED, xdr_wrapstring, &s, NULL, NULL, total_timeout); if (clnt_stat != RPC_SUCCESS) { clnt_perror(client, "batched rpc"); exit(-1); } } /* \fINow flush the pipeline\fP */ total_timeout.tv_sec = 20; clnt_stat = clnt_call(client, NULLPROC, xdr_void, NULL, xdr_void, NULL, total_timeout); if (clnt_stat != RPC_SUCCESS) { clnt_perror(client, "rpc"); exit(-1); } clnt_destroy(client); exit(0);}.vs.DE.KESince the server sends no message,the clients cannot be notified of any of the failures that may occur.Therefore, clients are on their own when it comes to handling errors..LPThe above example was completed to renderall of the (2000) lines in the file.I /etc/termcap .The rendering service did nothing but throw the lines away.The example was run in the following four configurations:1) machine to itself, regular RPC;2) machine to itself, batched RPC;3) machine to another, regular RPC; and4) machine to another, batched RPC.The results are as follows:1) 50 seconds;2) 16 seconds;3) 52 seconds;4) 10 seconds.Running.I fscanf()on.I /etc/termcaponly requires six seconds.These timings show the advantage of protocolsthat allow for overlapped execution,though these protocols are often hard to design..NH 2\&Authentication.IX "authentication".IX "RPC" "authentication".LPIn the examples presented so far,the caller never identified itself to the server,and the server never required an ID from the caller.Clearly, some network services, such as a network filesystem,require stronger security than what has been presented so far..LPIn reality, every RPC call is authenticated bythe RPC package on the server, and similarly,the RPC client package generates and sends authentication parameters.Just as different transports (TCP/IP or UDP/IP)can be used when creating RPC clients and servers,different forms of authentication can be associated with RPC clients;the default authentication type used as a default is type.I none ..LPThe authentication subsystem of the RPC package is open ended.That is, numerous types of authentication are easy to support..NH 3\&UNIX Authentication.IX "UNIX Authentication".IP "\fIThe Client Side\fP".LPWhen a caller creates a new RPC client handle as in:.DS.ft CWclnt = clntudp_create(address, prognum, versnum, wait, sockp).DEthe appropriate transport instance defaultsthe associate authentication handle to be.DS.ft CWclnt->cl_auth = authnone_create();.DEThe RPC client can choose to use.I UNIXstyle authentication by setting.I clnt\->cl_authafter creating the RPC client handle:.DS.ft CWclnt->cl_auth = authunix_create_default();.DEThis causes each RPC call associated with.I clntto carry with it the following authentication credentials structure:.ie t .DS.el .DS L.ft I/* * UNIX style credentials. */.ft CWstruct authunix_parms { u_long aup_time; /* \fIcredentials creation time\fP */ char *aup_machname; /* \fIhost name where client is\fP */ int aup_uid; /* \fIclient's UNIX effective uid\fP */ int aup_gid; /* \fIclient's current group id\fP */ u_int aup_len; /* \fIelement length of aup_gids\fP */ int *aup_gids; /* \fIarray of groups user is in\fP */};.DEThese fields are set by.I authunix_create_default()by invoking the appropriate system calls.Since the RPC user created this new style of authentication,the user is responsible for destroying it with:.DS.ft CWauth_destroy(clnt->cl_auth);.DEThis should be done in all cases, to conserve memory..sp.IP "\fIThe Server Side\fP".LPService implementors have a harder time dealing with authentication issuessince the RPC package passes the service dispatch routine a requestthat has an arbitrary authentication style associated with it.Consider the fields of a request handle passed to a service dispatch routine:.ie t .DS.el .DS L.ft I/* * An RPC Service request */.ft CWstruct svc_req { u_long rq_prog; /* \fIservice program number\fP */ u_long rq_vers; /* \fIservice protocol vers num\fP */ u_long rq_proc; /* \fIdesired procedure number\fP */ struct opaque_auth rq_cred; /* \fIraw credentials from wire\fP */ caddr_t rq_clntcred; /* \fIcredentials (read only)\fP */};.DEThe.I rq_credis mostly opaque, except for one field of interest:the style or flavor of authentication credentials:.ie t .DS.el .DS L.ft I/* * Authentication info. Mostly opaque to the programmer. */.ft CWstruct opaque_auth { enum_t oa_flavor; /* \fIstyle of credentials\fP */ caddr_t oa_base; /* \fIaddress of more auth stuff\fP */ u_int oa_length; /* \fInot to exceed \fIMAX_AUTH_BYTES */};.DE.IX RPC guaranteesThe RPC package guarantees the followingto the service dispatch routine:.IP 1.That the request's.I rq_credis well formed. Thus the service implementor may inspect the request's.I rq_cred.oa_flavorto determine which style of authentication the caller used.The service implementor may also wish to inspect the other fields of.I rq_credif the style is not one of the styles supported by the RPC package..IP 2.That the request's.I rq_clntcredfield is either.I NULL or points to a well formed structurethat corresponds to a supported style of authentication credentials.Remember that only.I unixstyle is currently supported, so (currently).I rq_clntcredcould be cast to a pointer to an.I authunix_parmsstructure. If.I rq_clntcredis.I NULL ,the service implementor may wish to inspect the other (opaque) fields of.I rq_credin case the service knows about a new type of authenticationthat the RPC package does not know about..LPOur remote users service example can be extended so thatit computes results for all users except UID 16:.ie t .DS.el .DS L.ft CW.vs 11nuser(rqstp, transp) struct svc_req *rqstp; SVCXPRT *transp;{ struct authunix_parms *unix_cred; int uid; unsigned long nusers;.ft I /* * we don't care about authentication for null proc */.ft CW if (rqstp->rq_proc == NULLPROC) { if (!svc_sendreply(transp, xdr_void, 0)) { fprintf(stderr, "can't reply to RPC call\en"); return (1); } return; }.ft I /* * now get the uid */.ft CW switch (rqstp->rq_cred.oa_flavor) { case AUTH_UNIX: unix_cred = (struct authunix_parms *)rqstp->rq_clntcred; uid = unix_cred->aup_uid; break; case AUTH_NULL: default: svcerr_weakauth(transp); return; } switch (rqstp->rq_proc) { case RUSERSPROC_NUM:.ft I /* * make sure caller is allowed to call this proc */.ft CW if (uid == 16) { svcerr_systemerr(transp); return; }.ft I /* * Code here to compute the number of users * and assign it to the variable \fInusers\fP */.ft CW if (!svc_sendreply(transp, xdr_u_long, &nusers)) { fprintf(stderr, "can't reply to RPC call\en"); return (1); } return; default: svcerr_noproc(transp); return; }}.vs.DEA few things should be noted here.First, it is customary not to checkthe authentication parameters associated with the.I NULLPROC(procedure number zero).Second, if the authentication parameter's type is not suitablefor your service, you should call.I svcerr_weakauth() .And finally, the service protocol itself should return statusfor access denied; in the case of our example, the protocoldoes not have such a status, so we call the service primitive.I svcerr_systemerr()instead..LPThe last point underscores the relation betweenthe RPC authentication package and the services;RPC deals only with .I authentication and not with individual services' .I "access control" .The services themselves must implement their own access control policiesand reflect these policies as return statuses in their protocols..NH 2\&DES Authentication.IX RPC DES.IX RPC authentication.LPUNIX authentication is quite easy to defeat. Instead of using.I authunix_create_default (),one can call.I authunix_create() and then modify the RPC authentication handle it returns by filling inwhatever user ID and hostname they wish the server to think they have.DES authentication is thus recommended for people who want more securitythan UNIX authentication offers..LPThe details of the DES authentication protocol are complicated andare not explained here. See.I "Remote Procedure Calls: Protocol Specification"for the details..LPIn order for DES authentication to work, the.I keyserv(8c) daemon must be running on both the server and client machines. Theusers on these machines need public keys assigned by the networkadministrator in the.I publickey(5) database. And, they need to have decrypted their secret keysusing their login password. This automatically happens when onelogs in using.I login(1) ,or can be done manually using.I keylogin(1) .The.I "Network Services"chapter./" XXXexplains more how to setup secure networking..sp.IP "\fIClient Side\fP".LPIf a client wishes to use DES authentication, it must set itsauthentication handle appropriately. Here is an example:.DScl->cl_auth = authdes_create(servername, 60, &server_addr, NULL);.DEThe first argument is the network name or \*Qnetname\*U of the owner ofthe server process. Typically, server processes are root processesand their netname can be derived using the following call:.DSchar servername[MAXNETNAMELEN];host2netname(servername, rhostname, NULL);.DEHere,.I rhostnameis the hostname of the machine the server process is running on..I host2netname() fills in.I servernameto contain this root process's netname. If theserver process was run by a regular user, one could use the call.I user2netname() instead. Here is an example for a server process with the same userID as the client:.DSchar servername[MAXNETNAMELEN];user2netname(servername, getuid(), NULL);.DEThe last argument to both of these calls,.I user2netname() and.I host2netname (),is the name of the naming domain where the server is located. The.I NULL used here means \*Quse the local domain name.\*U.LPThe second argument to.I authdes_create() is a lifetime for the credential. Here it is set to sixtyseconds. What that means is that the credential will expire 60seconds from now. If some mischievous user tries to reuse thecredential, the server RPC subsystem will recognize that it hasexpired and not grant any requests. If the same mischievous usertries to reuse the credential within the sixty second lifetime,he will still be rejected because the server RPC subsystemremembers which credentials it has already seen in the near past,and will not grant requests to duplicates..LPThe third argument to.I authdes_create() is the address of the host to synchronize with. In order for DESauthentication to work, the server and client must agree upon thetime. Here we pass the address of the server itself, so theclient and server will both be using the same time: the server'stime. The argument can be.I NULL ,which means \*Qdon't bother synchronizing.\*U You should only do thisif you are sure the client and server are already synchronized..LPThe final argument to.I authdes_create() is the address of a DES encryption key to use for encryptingtimestamps and data. If this argument is.I NULL ,as it is in this example, a random key will be chosen. The clientmay find out the encryption key being used by consulting the.I ah_key field of the authentication handle.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -