From sources-request@genrad.UUCP Fri Apr 12 17:28:51 1985 Relay-Version: version B 2.10.3 alpha 4/3/85; site seismo.UUCP Posting-Version: version B 2.10.2 9/3/84; site genrad.UUCP Path: seismo!harvard!talcott!panda!genrad!sources-request From: sources-request@genrad.UUCP Newsgroups: mod.sources Subject: Sun RPC part 1 of 10 Message-ID: <750@genrad.UUCP> Date: 12 Apr 85 22:28:51 GMT Date-Received: 13 Apr 85 05:21:19 GMT Sender: john@genrad.UUCP Lines: 1404 Approved: john@genrad.UUCP From: blyon@sun (Bob Lyon) ----------------- cut here -------------------- # run this script through "sh" to extract files mkdir profiled echo x - Makefile sed 's/^X//' >Makefile <<'!Funky!Stuff!' # # Makefile 1.3 85/02/08 # DESTDIR= SRC= auth_none.c auth_unix.c authunix_prot.c \ clnt_perror.c clnt_raw.c clnt_simple.c clnt_tcp.c clnt_udp.c \ pmap_clnt.c pmap_getmaps.c pmap_getport.c pmap_prot.c pmap_rmt.c \ rpc_prot.c \ svc.c svc_auth.c svc_auth_unix.c svc_raw.c svc_simple.c \ svc_tcp.c svc_udp.c xdr.c xdr_array.c xdr_float.c xdr_mem.c xdr_rec.c \ xdr_reference.c xdr_stdio.c OBJ= auth_none.o auth_unix.o authunix_prot.o clnt_perror.o clnt_raw.o\ clnt_simple.o clnt_tcp.o clnt_udp.o \ pmap_clnt.o pmap_getmaps.o pmap_getport.o pmap_prot.o pmap_rmt.o \ rpc_prot.o \ svc.o svc_auth.o svc_auth_unix.o svc_raw.o svc_simple.o \ svc_tcp.o svc_udp.o xdr.o xdr_array.o xdr_float.o xdr_mem.o xdr_rec.o \ xdr_reference.o xdr_stdio.o INC= auth.h auth_unix.h clnt.h pmap_clnt.h\ pmap_prot.h rpc.h rpc_msg.h svc.h svc_auth.h types.h xdr.h CFLAGS= -O X.c.o: ${CC} -p -c ${CFLAGS} $*.c -ld -X -r $*.o mv a.out profiled/$*.o ${CC} ${CFLAGS} -c $*.c -ld -x -r $*.o mv a.out $*.o all: rpclib portmap rpcinfo portmap: portmap.o cc $(CFLAGS) portmap.o rpclib -o portmap rpcinfo: rpcinfo.o cc $(CFLAGS) rpcinfo.o rpclib -o rpcinfo rpclib rpclib_p: ${OBJ} @echo "building profiled rpclib" @cd profiled; ar cru ../rpclib_p ${OBJ} @echo "building normal rpclib" @ar cru rpclib ${OBJ} ranlib rpclib install: -mkdir ${DESTDIR}/usr/include/rpc && \ chown bin ${DESTDIR}/usr/include/rpc && \ chmod 755 ${DESTDIR}/usr/include/rpc -for i in *.h; do \ (install -c -m 644 $$i ${DESTDIR}/usr/include/rpc) done tags: $(SRC) $(KSRC) $(INC) ctags -tw $(SRC) $(KSRC) $(INC) ref: tags sed 's, /.*,,' tags | \ awk ' { printf("%-26s%-16s%s\n", $$1, $$2, $$3) }' > ref lint: lint -bnuvx $(SRC) print: pr $(INC) $(SRC) $(KSRC) | lpr -Pvp clean: rm -f $(OBJ) librpc.a linted made profiled/*.o depend: @-grep '^#include' $(SRC) | grep -v '<' | grep -v '../' | \ sed 's/:[^"]*"\([^"]*\)".*/: \1/' | sed 's/\.[cs]:/.o:/' | \ awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \ else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \ else rec = rec " " $$2 } } \ END { print rec } ' >> makedep @echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep @echo '$$r makedep' >>eddep @echo 'w' >>eddep @cp Makefile makefile.bak @ed - Makefile < eddep @rm eddep makedep makefile.bak # DO NOT DELETE THIS LINE auth_none.o: types.h xdr.h auth.h auth_unix.o: types.h xdr.h auth.h auth_unix.h authunix_prot.o: types.h xdr.h auth.h auth_unix.h clnt_perror.o: types.h xdr.h auth.h clnt.h rpc_msg.h clnt_raw.o: types.h xdr.h auth.h clnt.h rpc_msg.h clnt_tcp.o: types.h xdr.h auth.h clnt.h rpc_msg.h pmap_clnt.h clnt_udp.o: types.h xdr.h auth.h clnt.h rpc_msg.h pmap_clnt.h pmap_clnt.o: types.h xdr.h auth.h clnt.h rpc_msg.h pmap_prot.h pmap_clnt.h pmap_getmaps.o: types.h xdr.h auth.h clnt.h rpc_msg.h pmap_prot.h pmap_clnt.h pmap_getport.o: types.h xdr.h auth.h clnt.h rpc_msg.h pmap_prot.h pmap_clnt.h pmap_prot.o: types.h xdr.h pmap_prot.h pmap_rmt.o: types.h xdr.h auth.h clnt.h rpc_msg.h pmap_prot.h pmap_clnt.h rpc_prot.o: types.h xdr.h auth.h clnt.h rpc_msg.h svc.o: types.h xdr.h auth.h clnt.h rpc_msg.h svc.h svc_auth.h svc_auth.o: types.h xdr.h auth.h clnt.h rpc_msg.h svc.h svc_auth.h svc_auth_unix.o: types.h xdr.h auth.h clnt.h rpc_msg.h svc.h auth_unix.h svc_auth_unix.o: svc_auth.h svc_raw.o: types.h xdr.h auth.h clnt.h rpc_msg.h svc.h svc_tcp.o: types.h xdr.h auth.h clnt.h rpc_msg.h svc.h svc_udp.o: types.h xdr.h auth.h clnt.h rpc_msg.h svc.h xdr.o: types.h xdr.h xdr_array.o: types.h xdr.h xdr_float.o: types.h xdr.h xdr_mem.o: types.h xdr.h xdr_rec.o: types.h xdr.h xdr_reference.o: types.h xdr.h xdr_stdio.o: types.h xdr.h !Funky!Stuff! echo x - README sed 's/^X//' >README <<'!Funky!Stuff!' Things that you should be aware of: 1. At Sun, RPC is part of the C library. This makefile will make a library called rpclib. 2. I have added two other files - portmap.c and rcpinfo.c; they usually do not live in this directory. Also, both files assume that the rpc dot h files have been installed in /usr/include. portmap.c is the source to /etc/portmap, the rpc deamon which must be started by root before any other rpc based servers or clients. rpcinfo.c dumps the information that the portmap keeps; at Sun, it lives in /usr/etc/rpcinfo. 3. The rpc library was built with a post-1.1 Sun release of the compiler. Old compilers complain about valid C. You can make old compilers happy by changing some voids to ints. However, the fix to the 4.2 VAX compiler is as follows: trees.c: removed spurious type mismatch errors in expressions involving pointers to void functions, e.g., void foo(){...} void (*f)() = foo; 1250c1264,1266 < else if( mt12 == 0 ) break; --- > /* if right is TVOID and looks like a CALL, is not ok */ > else if (mt2 == 0 && (p->in.right->in.op == CALL || p->in.right->in.op == UNARY CALL)) > break; 4. The documentation is in ditroff form in subdirectory doc. It depends on a Sun macro package (/usr/lib/tmac/tmac.sun) which I have included. Bob Lyon Sun Microsystems, Inc sun!blyon Thu Mar 28 1985 !Funky!Stuff! echo x - portmap.c sed 's/^X//' >portmap.c <<'!Funky!Stuff!' #ifndef lint static char sccsid[] = "@(#)portmap.c 1.2 85/03/13 Copyr 1984 Sun Micro"; #endif /* * Copyright (c) 1984 by Sun Microsystems, Inc. */ /* * portmap.c, Implements the program,version to port number mapping for * rpc. */ /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify Sun RPC without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. * * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun RPC is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ #include #include #include #include #include #include #include char *malloc(); int reg_service(); static int debugging = 0; main() { SVCXPRT *xprt; int sock, pid, t; struct sockaddr_in addr; int len = sizeof(struct sockaddr_in); #ifndef DEBUG pid = fork(); if (pid < 0) { perror("portmap: fork"); exit(1); } if (pid != 0) exit(0); for (t = 0; t < 20; t++) close(t); open("/", 0); dup2(0, 1); dup2(0, 2); t = open("/dev/tty", 2); if (t >= 0) { ioctl(t, TIOCNOTTY, (char *)0); close(t); } #endif if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("portmap cannot create socket"); exit(1); } addr.sin_addr.S_un.S_addr = 0; addr.sin_family = AF_INET; addr.sin_port = htons(PMAPPORT); if (bind(sock, (struct sockaddr *)&addr, len) != 0) { perror("portmap cannot bind"); exit(1); } if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) { fprintf(stderr, "couldn't do udp_create\n"); exit(1); } if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror("portmap cannot create socket"); exit(1); } if (bind(sock, (struct sockaddr *)&addr, len) != 0) { perror("portmap cannot bind"); exit(1); } if ((xprt = svctcp_create(sock, 0, 0)) == (SVCXPRT *)NULL) { fprintf(stderr, "couldn't do tcp_create\n"); exit(1); } (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE); svc_run(); fprintf(stderr, "run_svc returned unexpectedly\n"); abort(); } struct pmaplist *pmaplist; static struct pmaplist * find_service(prog, vers, prot) u_long prog; u_long vers; { register struct pmaplist *hit = NULL; register struct pmaplist *pml; for (pml = pmaplist; pml != NULL; pml = pml->pml_next) { if ((pml->pml_map.pm_prog != prog) || (pml->pml_map.pm_prot != prot)) continue; hit = pml; if (pml->pml_map.pm_vers == vers) break; } return (hit); } /* * 1 OK, 0 not */ reg_service(rqstp, xprt) struct svc_req *rqstp; SVCXPRT *xprt; { struct pmap reg; struct pmaplist *pml, *prevpml, *fnd; int ans, port; caddr_t t; #ifdef DEBUG fprintf(stderr, "server: about do a switch\n"); #endif switch (rqstp->rq_proc) { case PMAPPROC_NULL: /* * Null proc call */ if ((!svc_sendreply(xprt, xdr_void, NULL)) && debugging) { abort(); } break; case PMAPPROC_SET: /* * Set a program,version to port mapping */ if (!svc_getargs(xprt, xdr_pmap, ®)) svcerr_decode(xprt); else { /* * check to see if already used * find_service returns a hit even if * the versions don't match, so check for it */ fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) { if (fnd->pml_map.pm_port == reg.pm_port) { ans = 1; goto done; } else { ans = 0; goto done; } } else { /* * add to list */ pml = (struct pmaplist *) malloc((u_int)sizeof(struct pmaplist)); pml->pml_map = reg; pml->pml_next = pmaplist; pmaplist = pml; ans = 1; } done: if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && debugging) { fprintf(stderr, "svc_sendreply\n"); abort(); } } break; case PMAPPROC_UNSET: /* * Remove a program,version to port mapping. */ if (!svc_getargs(xprt, xdr_pmap, ®)) svcerr_decode(xprt); else { ans = 0; for (prevpml = NULL, pml = pmaplist; pml != NULL; ) { if ((pml->pml_map.pm_prog != reg.pm_prog) || (pml->pml_map.pm_vers != reg.pm_vers)) { /* both pml & prevpml move forwards */ prevpml = pml; pml = pml->pml_next; continue; } /* found it; pml moves forward, prevpml stays */ ans = 1; t = (caddr_t)pml; pml = pml->pml_next; if (prevpml == NULL) pmaplist = pml; else prevpml->pml_next = pml; free(t); } if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) && debugging) { fprintf(stderr, "svc_sendreply\n"); abort(); } } break; case PMAPPROC_GETPORT: /* * Lookup the mapping for a program,version and return its port */ if (!svc_getargs(xprt, xdr_pmap, ®)) svcerr_decode(xprt); else { fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot); if (fnd) port = fnd->pml_map.pm_port; else port = 0; if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) && debugging) { fprintf(stderr, "svc_sendreply\n"); abort(); } } break; case PMAPPROC_DUMP: /* * Return the current set of mapped program,version */ if (!svc_getargs(xprt, xdr_void, NULL)) svcerr_decode(xprt); else { if ((!svc_sendreply(xprt, xdr_pmaplist, (caddr_t)&pmaplist)) && debugging) { fprintf(stderr, "svc_sendreply\n"); abort(); } } break; case PMAPPROC_CALLIT: /* * Calls a procedure on the local machine. If the requested * procedure is not registered this procedure does not return * error information!! * This procedure is only supported on rpc/udp and calls via * rpc/udp. It passes null authentication parameters. */ callit(rqstp, xprt); break; default: svcerr_noproc(xprt); break; } } /* * Stuff for the rmtcall service */ #define ARGSIZE 9000 typedef struct encap_parms { u_long arglen; char *args; }; static bool_t xdr_encap_parms(xdrs, epp) XDR *xdrs; struct encap_parms *epp; { return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE)); } typedef struct rmtcallargs { u_long rmt_prog; u_long rmt_vers; u_long rmt_port; u_long rmt_proc; struct encap_parms rmt_args; }; static bool_t xdr_rmtcall_args(xdrs, cap) register XDR *xdrs; register struct rmtcallargs *cap; { /* does not get a port number */ if (xdr_u_long(xdrs, &(cap->rmt_prog)) && xdr_u_long(xdrs, &(cap->rmt_vers)) && xdr_u_long(xdrs, &(cap->rmt_proc))) { return (xdr_encap_parms(xdrs, &(cap->rmt_args))); } return (FALSE); } static bool_t xdr_rmtcall_result(xdrs, cap) register XDR *xdrs; register struct rmtcallargs *cap; { if (xdr_u_long(xdrs, &(cap->rmt_port))) return (xdr_encap_parms(xdrs, &(cap->rmt_args))); return (FALSE); } /* * only worries about the struct encap_parms part of struct rmtcallargs. * The arglen must already be set!! */ static bool_t xdr_opaque_parms(xdrs, cap) XDR *xdrs; struct rmtcallargs *cap; { return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen)); } /* * This routine finds and sets the length of incoming opaque paraters * and then calls xdr_opaque_parms. */ static bool_t xdr_len_opaque_parms(xdrs, cap) register XDR *xdrs; struct rmtcallargs *cap; { register u_int beginpos, lowpos, highpos, currpos, pos; beginpos = lowpos = pos = xdr_getpos(xdrs); highpos = lowpos + ARGSIZE; while ((int)(highpos - lowpos) >= 0) { currpos = (lowpos + highpos) / 2; if (xdr_setpos(xdrs, currpos)) { pos = currpos; lowpos = currpos + 1; } else { highpos = currpos - 1; } } xdr_setpos(xdrs, beginpos); cap->rmt_args.arglen = pos - beginpos; return (xdr_opaque_parms(xdrs, cap)); } /* * Call a remote procedure service * This procedure is very quiet when things go wrong. * The proc is written to support broadcast rpc. In the broadcast case, * a machine should shut-up instead of complain, less the requestor be * overrun with complaints at the expense of not hearing a valid reply ... */ static callit(rqstp, xprt) struct svc_req *rqstp; SVCXPRT *xprt; { char buf[2000]; struct rmtcallargs a; struct pmaplist *pml; u_short port; struct sockaddr_in me; int socket = -1; CLIENT *client; struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred; struct timeval timeout; timeout.tv_sec = 5; timeout.tv_usec = 0; a.rmt_args.args = buf; if (!svc_getargs(xprt, xdr_rmtcall_args, &a)) return; if ((pml = find_service(a.rmt_prog, a.rmt_vers, IPPROTO_UDP)) == NULL) return; port = pml->pml_map.pm_port; get_myaddress(&me); me.sin_port = htons(port); client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &socket); if (client != (CLIENT *)NULL) { if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) { client->cl_auth = authunix_create(au->aup_machname, au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids); } a.rmt_port = (u_long)port; if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a, xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) { svc_sendreply(xprt, xdr_rmtcall_result, &a); } AUTH_DESTROY(client->cl_auth); clnt_destroy(client); } (void)close(socket); } !Funky!Stuff! echo x - rpc.h sed 's/^X//' >rpc.h <<'!Funky!Stuff!' /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify Sun RPC without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. * * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun RPC is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ /* @(#)rpc.h 1.2 85/02/08 SMI */ /* * rpc.h, Just includes the billions of rpc header files necessary to * do remote procedure calling. * * Copyright (C) 1984, Sun Microsystems, Inc. */ #include /* some typedefs */ #include /* external data representation interfaces */ #include /* generic (de)serializer */ /* Client side only authentication */ #include /* generic authenticator (client side) */ /* Client side (mostly) remote procedure call */ #include /* generic rpc stuff */ /* semi-private protocol headers */ #include /* protocol for rpc messages */ #include /* protocol for unix style cred */ /* Server side only remote procedure callee */ #include /* service manager and multiplexer */ #include /* service side authenticator */ !Funky!Stuff! echo x - rpc_msg.h sed 's/^X//' >rpc_msg.h <<'!Funky!Stuff!' /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify Sun RPC without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. * * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun RPC is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ /* @(#)rpc_msg.h 1.3 85/03/14 SMI */ /* * rpc_msg.h * rpc message definition * * Copyright (C) 1984, Sun Microsystems, Inc. */ #define RPC_MSG_VERSION ((u_long) 2) #define RPC_SERVICE_PORT ((u_short) 2048) /* * Bottom up definition of an rpc message. * NOTE: call and reply use the same overall stuct but * different parts of unions within it. */ enum msg_type { CALL=0, REPLY=1 }; enum reply_stat { MSG_ACCEPTED=0, MSG_DENIED=1 }; enum accept_stat { SUCCESS=0, PROG_UNAVAIL=1, PROG_MISMATCH=2, PROC_UNAVAIL=3, GARBAGE_ARGS=4, SYSTEM_ERR=5 }; enum reject_stat { RPC_MISMATCH=0, AUTH_ERROR=1 }; /* * Reply part of an rpc exchange */ /* * Reply to an rpc request that was accepted by the server. * Note: there could be an error even though the request was * accepted. */ struct accepted_reply { struct opaque_auth ar_verf; enum accept_stat ar_stat; union { struct { u_long low; u_long high; } AR_versions; struct { caddr_t where; xdrproc_t proc; } AR_results; /* and many other null cases */ } ru; #define ar_results ru.AR_results #define ar_vers ru.AR_versions }; /* * Reply to an rpc request that was rejected by the server. */ struct rejected_reply { enum reject_stat rj_stat; union { struct { u_long low; u_long high; } RJ_versions; enum auth_stat RJ_why; /* why authentication did not work */ } ru; #define rj_vers ru.RJ_versions #define rj_why ru.RJ_why }; /* * Body of a reply to an rpc request. */ struct reply_body { enum reply_stat rp_stat; union { struct accepted_reply RP_ar; struct rejected_reply RP_dr; } ru; #define rp_acpt ru.RP_ar #define rp_rjct ru.RP_dr }; /* * Body of an rpc request call. */ struct call_body { u_long cb_rpcvers; /* must be equal to two */ u_long cb_prog; u_long cb_vers; u_long cb_proc; struct opaque_auth cb_cred; struct opaque_auth cb_verf; /* protocol specific - provided by client */ }; /* * The rpc message */ struct rpc_msg { u_long rm_xid; enum msg_type rm_direction; union { struct call_body RM_cmb; struct reply_body RM_rmb; } ru; #define rm_call ru.RM_cmb #define rm_reply ru.RM_rmb }; #define acpted_rply ru.RM_rmb.ru.RP_ar #define rjcted_rply ru.RM_rmb.ru.RP_dr /* * XDR routine to handle a rpc message. * xdr_callmsg(xdrs, cmsg) * XDR *xdrs; * struct rpc_msg *cmsg; */ extern bool_t xdr_callmsg(); /* * XDR routine to pre-serialize the static part of a rpc message. * xdr_callhdr(xdrs, cmsg) * XDR *xdrs; * struct rpc_msg *cmsg; */ extern bool_t xdr_callhdr(); /* * XDR routine to handle a rpc reply. * xdr_replymsg(xdrs, rmsg) * XDR *xdrs; * struct rpc_msg *rmsg; */ extern bool_t xdr_replymsg(); /* * Fills in the error part of a reply message. * _seterr_reply(msg, error) * struct rpc_msg *msg; * struct rpc_err *error; */ extern void _seterr_reply(); !Funky!Stuff! echo x - rpc_prot.c sed 's/^X//' >rpc_prot.c <<'!Funky!Stuff!' /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify Sun RPC without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. * * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun RPC is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ #ifndef lint static char sccsid[] = "@(#)rpc_prot.c 1.5 85/03/20 Copyr 1984 Sun Micro"; #endif /* * rpc_prot.c * * Copyright (C) 1984, Sun Microsystems, Inc. * * This set of routines implements the rpc message definition, * its serializer and some common rpc utility routines. * The routines are meant for various implementations of rpc - * they are NOT for the rpc client or rpc service implementations! * Because authentication stuff is easy and is part of rpc, the opaque * routines are also in this program. */ #include "types.h" #include "xdr.h" #include "auth.h" #include "clnt.h" #include "rpc_msg.h" /* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */ struct opaque_auth _null_auth; /* * XDR an opaque authentication struct * (see auth.h) */ bool_t xdr_opaque_auth(xdrs, ap) register XDR *xdrs; register struct opaque_auth *ap; { if (xdr_enum(xdrs, &(ap->oa_flavor))) return (xdr_bytes(xdrs, &ap->oa_base, &ap->oa_length, MAX_AUTH_BYTES)); return (FALSE); } /* * XDR a DES key. */ bool_t xdr_deskey(xdrs, blkp) register XDR *xdrs; register union des_block *blkp; { if (! xdr_u_long(xdrs, &(blkp->key.high))) return (FALSE); return (xdr_u_long(xdrs, &(blkp->key.low))); } /* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */ /* * XDR the MSG_ACCEPTED part of a reply message union */ bool_t xdr_accepted_reply(xdrs, ar) register XDR *xdrs; register struct accepted_reply *ar; { /* personalized union, rather than calling xdr_union */ if (! xdr_opaque_auth(xdrs, &(ar->ar_verf))) return (FALSE); if (! xdr_enum(xdrs, (enum_t *)&(ar->ar_stat))) return (FALSE); switch (ar->ar_stat) { case SUCCESS: return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where)); case PROG_MISMATCH: if (! xdr_u_long(xdrs, &(ar->ar_vers.low))) return (FALSE); return (xdr_u_long(xdrs, &(ar->ar_vers.high))); } return (TRUE); /* TRUE => open ended set of problems */ } /* * XDR the MSG_DENIED part of a reply message union */ bool_t xdr_rejected_reply(xdrs, rr) register XDR *xdrs; register struct rejected_reply *rr; { /* personalized union, rather than calling xdr_union */ if (! xdr_enum(xdrs, (enum_t *)&(rr->rj_stat))) return (FALSE); switch (rr->rj_stat) { case RPC_MISMATCH: if (! xdr_u_long(xdrs, &(rr->rj_vers.low))) return (FALSE); return (xdr_u_long(xdrs, &(rr->rj_vers.high))); case AUTH_ERROR: return (xdr_enum(xdrs, (enum_t *)&(rr->rj_why))); } return (FALSE); } static struct xdr_discrim reply_dscrm[3] = { { (int)MSG_ACCEPTED, xdr_accepted_reply }, { (int)MSG_DENIED, xdr_rejected_reply }, { __dontcare__, NULL_xdrproc_t } }; /* * XDR a reply message */ bool_t xdr_replymsg(xdrs, rmsg) register XDR *xdrs; register struct rpc_msg *rmsg; { if ( xdr_u_long(xdrs, &(rmsg->rm_xid)) && xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction)) && (rmsg->rm_direction == REPLY) ) return (xdr_union(xdrs, (enum_t *)&(rmsg->rm_reply.rp_stat), (caddr_t)&(rmsg->rm_reply.ru), reply_dscrm, NULL_xdrproc_t)); return (FALSE); } /* * XDR a call message */ bool_t xdr_callmsg(xdrs, cmsg) register XDR *xdrs; register struct rpc_msg *cmsg; { if ( xdr_u_long(xdrs, &(cmsg->rm_xid)) && xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) && (cmsg->rm_direction == CALL) && xdr_u_long(xdrs, &(cmsg->rm_call.cb_rpcvers)) && (cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) && xdr_u_long(xdrs, &(cmsg->rm_call.cb_prog)) && xdr_u_long(xdrs, &(cmsg->rm_call.cb_vers)) && xdr_u_long(xdrs, &(cmsg->rm_call.cb_proc)) && xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_cred)) ) return (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf))); return (FALSE); } /* * Serializes the "static part" of a call message header. * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers. * The rm_xid is not really static, but the user can easily munge on the fly. */ bool_t xdr_callhdr(xdrs, cmsg) register XDR *xdrs; register struct rpc_msg *cmsg; { cmsg->rm_direction = CALL; cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION; if ( (xdrs->x_op == XDR_ENCODE) && xdr_u_long(xdrs, &(cmsg->rm_xid)) && xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) && xdr_u_long(xdrs, &(cmsg->rm_call.cb_rpcvers)) && xdr_u_long(xdrs, &(cmsg->rm_call.cb_prog)) ) return (xdr_u_long(xdrs, &(cmsg->rm_call.cb_vers))); return (FALSE); } /* ************************** Client utility routine ************* */ static void accepted(acpt_stat, error) register enum accept_stat acpt_stat; register struct rpc_err *error; { switch (acpt_stat) { case PROG_UNAVAIL: error->re_status = RPC_PROGUNAVAIL; return; case PROG_MISMATCH: error->re_status = RPC_PROGVERSMISMATCH; return; case PROC_UNAVAIL: error->re_status = RPC_PROCUNAVAIL; return; case GARBAGE_ARGS: error->re_status = RPC_CANTDECODEARGS; return; case SYSTEM_ERR: error->re_status = RPC_SYSTEMERROR; return; case SUCCESS: error->re_status = RPC_SUCCESS; return; } /* something's wrong, but we don't know what ... */ error->re_status = RPC_FAILED; error->re_lb.s1 = (long)MSG_ACCEPTED; error->re_lb.s2 = (long)acpt_stat; } static void rejected(rjct_stat, error) register enum reject_stat rjct_stat; register struct rpc_err *error; { switch (rjct_stat) { case RPC_VERSMISMATCH: error->re_status = RPC_VERSMISMATCH; return; case AUTH_ERROR: error->re_status = RPC_AUTHERROR; return; } /* something's wrong, but we don't know what ... */ error->re_status = RPC_FAILED; error->re_lb.s1 = (long)MSG_DENIED; error->re_lb.s2 = (long)rjct_stat; } /* * given a reply message, fills in the error */ void _seterr_reply(msg, error) register struct rpc_msg *msg; register struct rpc_err *error; { /* optimized for normal, SUCCESSful case */ switch (msg->rm_reply.rp_stat) { case MSG_ACCEPTED: if (msg->acpted_rply.ar_stat == SUCCESS) { error->re_status = RPC_SUCCESS; return; }; accepted(msg->acpted_rply.ar_stat, error); break; case MSG_DENIED: rejected(msg->rjcted_rply.rj_stat, error); break; default: error->re_status = RPC_FAILED; error->re_lb.s1 = (long)(msg->rm_reply.rp_stat); break; } switch (error->re_status) { case RPC_VERSMISMATCH: error->re_vers.low = msg->rjcted_rply.rj_vers.low; error->re_vers.high = msg->rjcted_rply.rj_vers.high; break; case RPC_AUTHERROR: error->re_why = msg->rjcted_rply.rj_why; break; case RPC_PROGVERSMISMATCH: error->re_vers.low = msg->acpted_rply.ar_vers.low; error->re_vers.high = msg->acpted_rply.ar_vers.high; break; } } !Funky!Stuff! echo x - rpcinfo.c sed 's/^X//' >rpcinfo.c <<'!Funky!Stuff!' /* rpcinfo.c 1.2 85/01/15 */ /* * Copyright (C) 1984, Sun Microsystems, Inc. */ /* * rpcinfo: ping a particular rpc program * or dump the portmapper */ #include #include #include #include #include #include #include #define MAXHOSTLEN 256 main(argc, argv) char **argv; { int ans; if (argc < 2) { usage(); exit(1); } if (argv[1][0] == '-') { switch(argv[1][1]) { case 't': tcpping(argc-1, argv+1); break; case 'p': pmapdump(argc-1, argv+1); break; case 'u': udpping(argc-1, argv+1); break; default: usage(); exit(1); break; } } else usage(); } udpping(argc, argv) char **argv; { int ans; if (argc != 4) { usage(); exit(1); } ans = callrpc(argv[1], atoi(argv[2]), atoi(argv[3]), NULLPROC, xdr_void, 0, xdr_void, 0); if (ans != 0) { clnt_perrno(ans); fprintf(stderr, "\n"); printf("proc %d vers %d is not available\n", atoi(argv[2]), atoi(argv[3])); } else printf("proc %d vers %d ready and waiting\n", atoi(argv[2]), atoi(argv[3])); } tcpping(argc, argv) int argc; char **argv; { struct timeval to; struct sockaddr_in addr; enum clnt_stat rpc_stat; CLIENT *client; int sock = -1; struct hostent *hp; if (argc != 4) { usage(); exit(1); } if ((hp = gethostbyname(argv[1])) == NULL) { fprintf(stderr, "can't find %s\n", argv[1]); exit(1); } addr.sin_family = AF_INET; addr.sin_port = 0; addr.sin_addr.s_addr = *(int *)hp->h_addr; if ((client = clnttcp_create(&addr, atoi(argv[2]), atoi(argv[3]), &sock, 0, 0)) == NULL) { clnt_pcreateerror(""); printf("proc %d vers %d is not available\n", atoi(argv[2]), atoi(argv[3])); exit(1); } to.tv_usec = 0; to.tv_sec = 10; rpc_stat = clnt_call(client, 0, xdr_void, NULL, xdr_void, NULL, to); if (rpc_stat != RPC_SUCCESS) { clnt_perrno(rpc_stat); fprintf(stderr, "\n"); printf("proc %d vers %d is not available\n", atoi(argv[2]), atoi(argv[3])); } else printf("proc %d vers %d ready and waiting\n", atoi(argv[2]), atoi(argv[3])); } pmapdump(argc, argv) int argc; char **argv; { struct sockaddr_in server_addr; struct hostent *hp; struct pmaplist *head; char hoststr[MAXHOSTLEN]; int socket = -1; struct timeval minutetimeout; char *hostnm; register CLIENT *client; enum clnt_stat rpc_stat; if (argc > 2) { usage(); exit(1); } if (argc == 2) { hostnm = argv[1]; } else { gethostname(hoststr, sizeof(hoststr)); hostnm = hoststr; } if ((hp = gethostbyname(hostnm)) == NULL) { fprintf(stderr, "cannot get addr for '%s'\n", hostnm); exit(0); } bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr, hp->h_length); server_addr.sin_family = AF_INET; minutetimeout.tv_sec = 60; minutetimeout.tv_usec = 0; server_addr.sin_port = htons(PMAPPORT); if ((client = clnttcp_create(&server_addr, PMAPPROG, PMAPVERS, &socket, 50, 500)) == NULL) { clnt_pcreateerror("rpcinfo: can't contact portmapper"); exit(1); } if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL, xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) { fprintf(stderr, "rpcinfo: can't contact portmapper"); clnt_perrno(rpc_stat); fprintf(stderr, "\n"); exit(1); } if (head == NULL) { printf("No remote programs registered.\n"); } else { printf("[program, version, protocol, port]:\n\n"); for (; head != (struct pmaplist *)NULL; head = head->pml_next) { printf("[%ld, %ld, %ld, %ld]\n", head->pml_map.pm_prog, head->pml_map.pm_vers, head->pml_map.pm_prot, head->pml_map.pm_port); } } } usage() { fprintf(stderr, "Usage: rpcinfo -u host prognum versnum\n"); fprintf(stderr, " rpcinfo -t host prognum versnum\n"); fprintf(stderr, " rpcinfo -p [host]\n"); } !Funky!Stuff! echo x - types.h sed 's/^X//' >types.h <<'!Funky!Stuff!' /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify Sun RPC without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. * * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun RPC is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ /* @(#)types.h 1.2 85/02/08 SMI */ /* * Rpc additions to */ #define bool_t int #define enum_t int #define FALSE (0==1) #define TRUE (1==1) #define __dontcare__ -1 #define mem_alloc(bsize) malloc(bsize) #define mem_free(ptr, bsize) free(ptr) #ifndef major /* ouch! */ #include #endif !Funky!Stuff! exit