4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Door server routines for nfsmapid daemon
28 * Translate NFSv4 users and groups between numeric and string values
37 #include <sys/types.h>
49 #include <nfs/nfssys.h>
50 #include <nfs/nfsid_map.h>
51 #include <nfs/mapid.h>
53 #include <sys/idmap.h>
55 #include <sys/fs/autofs.h>
56 #include <sys/mkdev.h>
57 #include "nfs_resolve.h"
59 #define UID_MAX_STR_LEN 11 /* Digits in UID_MAX + 1 */
60 #define DIAG_FILE "/var/run/nfs4_domain"
63 * idmap_kcall() takes a door descriptor as it's argument when we
64 * need to (re)establish the in-kernel door handles. When we only
65 * want to flush the id kernel caches, we don't redo the door setup.
67 #define FLUSH_KCACHES_ONLY (int)-1
72 extern size_t pwd_buflen
;
73 extern size_t grp_buflen
;
74 extern thread_t sig_thread
;
79 extern void check_domain(int);
80 extern void idmap_kcall(int);
81 extern int _nfssys(int, void *);
82 extern int valid_domain(const char *);
83 extern int validate_id_str(const char *);
84 extern int extract_domain(char *, char **, char **);
85 extern void update_diag_file(char *);
86 extern void *cb_update_domain(void *);
87 extern int cur_domain_null(void);
90 nfsmapid_str_uid(struct mapid_arg
*argp
, size_t arg_size
)
92 struct mapid_res result
;
94 struct passwd
*pwd_ptr
;
101 if (argp
->u_arg
.len
<= 0 || arg_size
< MAPID_ARG_LEN(argp
->u_arg
.len
)) {
102 result
.status
= NFSMAPID_INVALID
;
103 result
.u_res
.uid
= UID_NOBODY
;
107 if (!extract_domain(argp
->str
, &user
, &domain
)) {
111 * Invalid "user@domain" string. Still, the user
112 * part might be an encoded uid, so do a final check.
113 * Remember, domain part of string was not set since
114 * not a valid string.
116 if (!validate_id_str(user
)) {
117 result
.status
= NFSMAPID_UNMAPPABLE
;
118 result
.u_res
.uid
= UID_NOBODY
;
123 id
= strtoul(user
, (char **)NULL
, 10);
126 * We don't accept ephemeral ids from the wire.
128 if (errno
|| id
> UID_MAX
) {
129 result
.status
= NFSMAPID_UNMAPPABLE
;
130 result
.u_res
.uid
= UID_NOBODY
;
134 result
.u_res
.uid
= (uid_t
)id
;
135 result
.status
= NFSMAPID_NUMSTR
;
140 * String properly constructed. Now we check for domain and
143 if (!cur_domain_null() && !valid_domain(domain
)) {
145 * If the domain part of the string does not
146 * match the NFS domain, try to map it using
149 rc
= idmap_getuidbywinname(user
, domain
, 0, &result
.u_res
.uid
);
150 if (rc
!= IDMAP_SUCCESS
) {
151 result
.status
= NFSMAPID_BADDOMAIN
;
152 result
.u_res
.uid
= UID_NOBODY
;
155 result
.status
= NFSMAPID_OK
;
159 if ((pwd_buf
= malloc(pwd_buflen
)) == NULL
||
160 (pwd_rc
= getpwnam_r(user
, &pwd
, pwd_buf
, pwd_buflen
, &pwd_ptr
))
161 != 0 || pwd_ptr
== NULL
) {
163 if (pwd_buf
== NULL
|| pwd_rc
!= 0)
164 result
.status
= NFSMAPID_INTERNAL
;
169 result
.status
= NFSMAPID_NOTFOUND
;
172 result
.u_res
.uid
= UID_NOBODY
;
179 result
.u_res
.uid
= pwd
.pw_uid
;
180 result
.status
= NFSMAPID_OK
;
183 (void) door_return((char *)&result
, sizeof (struct mapid_res
), NULL
, 0);
188 nfsmapid_uid_str(struct mapid_arg
*argp
, size_t arg_size
)
190 struct mapid_res result
;
191 struct mapid_res
*resp
;
193 struct passwd
*pwd_ptr
;
194 char *pwd_buf
= NULL
;
195 char *idmap_buf
= NULL
;
196 uid_t uid
= argp
->u_arg
.uid
;
202 char dom_str
[DNAMEMAX
];
206 if (uid
== (uid_t
)-1) {
208 * Sentinel uid is not a valid id
211 resp
->status
= NFSMAPID_BADID
;
217 * Make local copy of domain for further manipuation
218 * NOTE: mapid_get_domain() returns a ptr to TSD.
220 if (cur_domain_null()) {
224 dom_str_len
= strlcpy(dom_str
, mapid_get_domain(), DNAMEMAX
);
228 * If uid is ephemeral then resolve it using idmap service
231 rc
= idmap_getwinnamebyuid(uid
, 0, &idmap_buf
, NULL
);
232 if (rc
!= IDMAP_SUCCESS
) {
234 * We don't put stringified ephemeral uids on
238 resp
->status
= NFSMAPID_UNMAPPABLE
;
244 * idmap_buf is already in the desired form i.e. name@domain
247 pw_str_len
= strlen(pw_str
);
248 at_str_len
= dom_str_len
= 0;
255 * Handling non-ephemeral uids
257 * We want to encode the uid into a literal string... :
259 * - upon failure to allocate space from the heap
260 * - if there is no current domain configured
261 * - if there is no such uid in the passwd DB's
263 if ((pwd_buf
= malloc(pwd_buflen
)) == NULL
|| dom_str_len
== 0 ||
264 getpwuid_r(uid
, &pwd
, pwd_buf
, pwd_buflen
, &pwd_ptr
) != 0 ||
268 * If we could not allocate from the heap, try
269 * allocating from the stack as a last resort.
271 if (pwd_buf
== NULL
&& (pwd_buf
=
272 alloca(MAPID_RES_LEN(UID_MAX_STR_LEN
))) == NULL
) {
274 resp
->status
= NFSMAPID_INTERNAL
;
280 * Constructing literal string without '@' so that
281 * we'll know that it's not a user, but rather a
282 * uid encoded string.
285 (void) sprintf(pw_str
, "%u", uid
);
286 pw_str_len
= strlen(pw_str
);
287 at_str_len
= dom_str_len
= 0;
292 * Otherwise, we construct the "user@domain" string if
293 * it's not already in that form.
295 pw_str
= pwd
.pw_name
;
296 pw_str_len
= strlen(pw_str
);
297 if (strchr(pw_str
, '@') == NULL
) {
301 at_str_len
= dom_str_len
= 0;
308 uid_str_len
= pw_str_len
+ at_str_len
+ dom_str_len
;
309 if ((resp
= alloca(MAPID_RES_LEN(uid_str_len
))) == NULL
) {
311 resp
->status
= NFSMAPID_INTERNAL
;
315 /* LINTED format argument to sprintf */
316 (void) sprintf(resp
->str
, "%s%s%s", pw_str
, at_str
, dom_str
);
317 resp
->u_res
.len
= uid_str_len
;
321 idmap_free(idmap_buf
);
322 resp
->status
= NFSMAPID_OK
;
326 * There is a chance that the door_return will fail because the
327 * resulting string is too large, try to indicate that if possible
329 if (door_return((char *)resp
,
330 MAPID_RES_LEN(resp
->u_res
.len
), NULL
, 0) == -1) {
331 resp
->status
= NFSMAPID_INTERNAL
;
333 (void) door_return((char *)&result
, sizeof (struct mapid_res
),
339 nfsmapid_str_gid(struct mapid_arg
*argp
, size_t arg_size
)
341 struct mapid_res result
;
343 struct group
*grp_ptr
;
350 if (argp
->u_arg
.len
<= 0 ||
351 arg_size
< MAPID_ARG_LEN(argp
->u_arg
.len
)) {
352 result
.status
= NFSMAPID_INVALID
;
353 result
.u_res
.gid
= GID_NOBODY
;
357 if (!extract_domain(argp
->str
, &group
, &domain
)) {
361 * Invalid "group@domain" string. Still, the
362 * group part might be an encoded gid, so do a
363 * final check. Remember, domain part of string
364 * was not set since not a valid string.
366 if (!validate_id_str(group
)) {
367 result
.status
= NFSMAPID_UNMAPPABLE
;
368 result
.u_res
.gid
= GID_NOBODY
;
373 id
= strtoul(group
, (char **)NULL
, 10);
376 * We don't accept ephemeral ids from the wire.
378 if (errno
|| id
> UID_MAX
) {
379 result
.status
= NFSMAPID_UNMAPPABLE
;
380 result
.u_res
.gid
= GID_NOBODY
;
384 result
.u_res
.gid
= (gid_t
)id
;
385 result
.status
= NFSMAPID_NUMSTR
;
390 * String properly constructed. Now we check for domain and
393 if (!cur_domain_null() && !valid_domain(domain
)) {
395 * If the domain part of the string does not
396 * match the NFS domain, try to map it using
399 rc
= idmap_getgidbywinname(group
, domain
, 0, &result
.u_res
.gid
);
400 if (rc
!= IDMAP_SUCCESS
) {
401 result
.status
= NFSMAPID_BADDOMAIN
;
402 result
.u_res
.gid
= GID_NOBODY
;
405 result
.status
= NFSMAPID_OK
;
409 if ((grp_buf
= malloc(grp_buflen
)) == NULL
||
410 (grp_rc
= getgrnam_r(group
, &grp
, grp_buf
, grp_buflen
, &grp_ptr
))
411 != 0 || grp_ptr
== NULL
) {
413 if (grp_buf
== NULL
|| grp_rc
!= 0)
414 result
.status
= NFSMAPID_INTERNAL
;
419 result
.status
= NFSMAPID_NOTFOUND
;
422 result
.u_res
.gid
= GID_NOBODY
;
429 result
.status
= NFSMAPID_OK
;
430 result
.u_res
.gid
= grp
.gr_gid
;
433 (void) door_return((char *)&result
, sizeof (struct mapid_res
), NULL
, 0);
438 nfsmapid_gid_str(struct mapid_arg
*argp
, size_t arg_size
)
440 struct mapid_res result
;
441 struct mapid_res
*resp
;
443 struct group
*grp_ptr
;
444 char *grp_buf
= NULL
;
445 char *idmap_buf
= NULL
;
447 gid_t gid
= argp
->u_arg
.gid
;
453 char dom_str
[DNAMEMAX
];
456 if (gid
== (gid_t
)-1) {
458 * Sentinel gid is not a valid id
461 resp
->status
= NFSMAPID_BADID
;
467 * Make local copy of domain for further manipuation
468 * NOTE: mapid_get_domain() returns a ptr to TSD.
470 if (cur_domain_null()) {
474 dom_str_len
= strlen(mapid_get_domain());
475 bcopy(mapid_get_domain(), dom_str
, dom_str_len
);
476 dom_str
[dom_str_len
] = '\0';
480 * If gid is ephemeral then resolve it using idmap service
483 rc
= idmap_getwinnamebygid(gid
, 0, &idmap_buf
, NULL
);
484 if (rc
!= IDMAP_SUCCESS
) {
486 * We don't put stringified ephemeral gids on
490 resp
->status
= NFSMAPID_UNMAPPABLE
;
496 * idmap_buf is already in the desired form i.e. name@domain
499 gr_str_len
= strlen(gr_str
);
500 at_str_len
= dom_str_len
= 0;
507 * Handling non-ephemeral gids
509 * We want to encode the gid into a literal string... :
511 * - upon failure to allocate space from the heap
512 * - if there is no current domain configured
513 * - if there is no such gid in the group DB's
515 if ((grp_buf
= malloc(grp_buflen
)) == NULL
|| dom_str_len
== 0 ||
516 getgrgid_r(gid
, &grp
, grp_buf
, grp_buflen
, &grp_ptr
) != 0 ||
520 * If we could not allocate from the heap, try
521 * allocating from the stack as a last resort.
523 if (grp_buf
== NULL
&& (grp_buf
=
524 alloca(MAPID_RES_LEN(UID_MAX_STR_LEN
))) == NULL
) {
526 resp
->status
= NFSMAPID_INTERNAL
;
532 * Constructing literal string without '@' so that
533 * we'll know that it's not a group, but rather a
534 * gid encoded string.
537 (void) sprintf(gr_str
, "%u", gid
);
538 gr_str_len
= strlen(gr_str
);
539 at_str_len
= dom_str_len
= 0;
544 * Otherwise, we construct the "group@domain" string if
545 * it's not already in that form.
547 gr_str
= grp
.gr_name
;
548 gr_str_len
= strlen(gr_str
);
549 if (strchr(gr_str
, '@') == NULL
) {
553 at_str_len
= dom_str_len
= 0;
560 gid_str_len
= gr_str_len
+ at_str_len
+ dom_str_len
;
561 if ((resp
= alloca(MAPID_RES_LEN(gid_str_len
))) == NULL
) {
563 resp
->status
= NFSMAPID_INTERNAL
;
567 /* LINTED format argument to sprintf */
568 (void) sprintf(resp
->str
, "%s%s%s", gr_str
, at_str
, dom_str
);
569 resp
->u_res
.len
= gid_str_len
;
573 idmap_free(idmap_buf
);
574 resp
->status
= NFSMAPID_OK
;
578 * There is a chance that the door_return will fail because the
579 * resulting string is too large, try to indicate that if possible
581 if (door_return((char *)resp
,
582 MAPID_RES_LEN(resp
->u_res
.len
), NULL
, 0) == -1) {
583 resp
->status
= NFSMAPID_INTERNAL
;
585 (void) door_return((char *)&result
, sizeof (struct mapid_res
),
591 nfsmapid_server_netinfo(refd_door_args_t
*referral_args
, size_t arg_size
)
597 char host
[MAXHOSTNAMELEN
];
598 utf8string
*nfsfsloc_args
;
599 refd_door_res_t
*door_res
;
600 refd_door_res_t failed_res
;
601 struct nfs_fsl_info
*nfs_fsloc_res
;
603 if (arg_size
< sizeof (refd_door_args_t
)) {
604 failed_res
.res_status
= EINVAL
;
605 res
= (char *)&failed_res
;
606 res_size
= sizeof (refd_door_res_t
);
608 "nfsmapid_server_netinfo failed: Invalid data\n");
612 if (decode_args(xdr_utf8string
, (refd_door_args_t
*)referral_args
,
613 (caddr_t
*)&nfsfsloc_args
, sizeof (utf8string
))) {
614 syslog(LOG_ERR
, "cannot allocate memory");
615 failed_res
.res_status
= ENOMEM
;
616 failed_res
.xdr_len
= 0;
617 res
= (caddr_t
)&failed_res
;
618 res_size
= sizeof (refd_door_res_t
);
622 if (nfsfsloc_args
->utf8string_len
>= MAXHOSTNAMELEN
) {
623 syslog(LOG_ERR
, "argument too large");
624 failed_res
.res_status
= EOVERFLOW
;
625 failed_res
.xdr_len
= 0;
626 res
= (caddr_t
)&failed_res
;
627 res_size
= sizeof (refd_door_res_t
);
631 snprintf(host
, nfsfsloc_args
->utf8string_len
+ 1,
632 "%s", nfsfsloc_args
->utf8string_val
);
635 get_nfs4ref_info(host
, NFS_PORT
, NFS_V4
);
637 xdr_free(xdr_utf8string
, (char *)&nfsfsloc_args
);
641 error
= encode_res(xdr_nfs_fsl_info
, &door_res
,
642 (caddr_t
)nfs_fsloc_res
, &res_size
);
643 free_nfs4ref_info(nfs_fsloc_res
);
646 "error allocating fs_locations "
648 failed_res
.res_status
= error
;
649 failed_res
.xdr_len
= srsz
;
650 res
= (caddr_t
)&failed_res
;
651 res_size
= sizeof (refd_door_res_t
);
653 door_res
->res_status
= 0;
654 res
= (caddr_t
)door_res
;
657 failed_res
.res_status
= EINVAL
;
658 failed_res
.xdr_len
= 0;
659 res
= (caddr_t
)&failed_res
;
660 res_size
= sizeof (refd_door_res_t
);
667 error
= door_return(res
, res_size
, NULL
, 0);
668 if (errno
== E2BIG
) {
669 failed_res
.res_status
= EOVERFLOW
;
670 failed_res
.xdr_len
= srsz
;
671 res
= (caddr_t
)&failed_res
;
672 res_size
= sizeof (refd_door_res_t
);
678 door_return(res
, res_size
, NULL
, 0);
683 nfsmapid_func(void *cookie
, char *argp
, size_t arg_size
,
684 door_desc_t
*dp
, uint_t n_desc
)
686 struct mapid_arg
*mapargp
;
687 struct mapid_res mapres
;
688 refd_door_args_t
*referral_args
;
691 * Make sure we have a valid argument
693 if (arg_size
< sizeof (struct mapid_arg
)) {
694 mapres
.status
= NFSMAPID_INVALID
;
695 mapres
.u_res
.len
= 0;
696 (void) door_return((char *)&mapres
, sizeof (struct mapid_res
),
701 /* LINTED pointer cast */
702 mapargp
= (struct mapid_arg
*)argp
;
703 referral_args
= (refd_door_args_t
*)argp
;
704 switch (mapargp
->cmd
) {
705 case NFSMAPID_STR_UID
:
706 nfsmapid_str_uid(mapargp
, arg_size
);
708 case NFSMAPID_UID_STR
:
709 nfsmapid_uid_str(mapargp
, arg_size
);
711 case NFSMAPID_STR_GID
:
712 nfsmapid_str_gid(mapargp
, arg_size
);
714 case NFSMAPID_GID_STR
:
715 nfsmapid_gid_str(mapargp
, arg_size
);
717 case NFSMAPID_SRV_NETINFO
:
718 nfsmapid_server_netinfo(referral_args
, arg_size
);
722 mapres
.status
= NFSMAPID_INVALID
;
723 mapres
.u_res
.len
= 0;
724 (void) door_return((char *)&mapres
, sizeof (struct mapid_res
), NULL
, 0);
728 * mapid_get_domain() always returns a ptr to TSD, so the
729 * check for a NULL domain is not a simple comparison with
730 * NULL but we need to check the contents of the TSD data.
733 cur_domain_null(void)
737 if ((p
= mapid_get_domain()) == NULL
)
740 return (p
[0] == '\0');
744 extract_domain(char *cp
, char **upp
, char **dpp
)
747 * Caller must insure that the string is valid
751 if ((*dpp
= strchr(cp
, '@')) == NULL
)
758 valid_domain(const char *dom
)
760 const char *whoami
= "valid_domain";
762 if (!mapid_stdchk_domain(dom
)) {
763 syslog(LOG_ERR
, gettext("%s: Invalid inbound domain name %s."),
769 * NOTE: mapid_get_domain() returns a ptr to TSD.
771 return (strcasecmp(dom
, mapid_get_domain()) == 0);
775 validate_id_str(const char *id
)
785 idmap_kcall(int door_id
)
787 struct nfsidmap_args args
;
796 (void) _nfssys(NFS_IDMAP
, &args
);
800 * Get the current NFS domain.
802 * If nfsmapid_domain is set in NFS SMF, then it is the NFS domain;
803 * otherwise, the DNS domain is used.
806 check_domain(int sighup
)
808 const char *whoami
= "check_domain";
809 static int setup_done
= 0;
813 * Construct the arguments to be passed to libmapid interface
814 * If called in response to a SIGHUP, reset any cached DNS TXT
817 cb
.fcn
= cb_update_domain
;
819 mapid_reeval_domain(&cb
);
822 * Restart the signal handler thread if we're still setting up
826 if (thr_continue(sig_thread
)) {
827 syslog(LOG_ERR
, gettext("%s: Fatal error: signal "
828 "handler thread could not be restarted."), whoami
);
835 * Need to be able to open the DIAG_FILE before nfsmapid(1m)
836 * releases it's root priviledges. The DIAG_FILE then remains
837 * open for the duration of this nfsmapid instance via n4_fd.
842 static int msg_done
= 0;
844 if ((n4_fp
= fopen(DIAG_FILE
, "w+")) != NULL
) {
845 n4_fd
= fileno(n4_fp
);
852 syslog(LOG_ERR
, "Failed to create %s. Enable syslog "
853 "daemon.debug for more info", DIAG_FILE
);
858 * When a new domain name is configured, save to DIAG_FILE
859 * and log to syslog, with LOG_DEBUG level (if configured).
862 update_diag_file(char *new)
868 (void) lseek(n4_fd
, (off_t
)0, SEEK_SET
);
869 (void) ftruncate(n4_fd
, 0);
870 (void) snprintf(buf
, DNAMEMAX
, "%s\n", new);
873 n
= write(n4_fd
, buf
, len
);
874 if (n
< 0 || n
< len
)
875 syslog(LOG_DEBUG
, "Could not write %s to diag file", new);
878 syslog(LOG_DEBUG
, "nfsmapid domain = %s", new);
882 * Callback function for libmapid. This will be called
883 * by the lib, everytime the nfsmapid(1m) domain changes.
886 cb_update_domain(void *arg
)
888 char *new_dname
= (char *)arg
;
890 DTRACE_PROBE1(nfsmapid
, daemon__domain
, new_dname
);
891 update_diag_file(new_dname
);
892 idmap_kcall(FLUSH_KCACHES_ONLY
);
898 xdr_utf8string(XDR
*xdrs
, utf8string
*objp
)
900 if (xdrs
->x_op
!= XDR_FREE
)
901 return (xdr_bytes(xdrs
, (char **)&objp
->utf8string_val
,
902 (uint_t
*)&objp
->utf8string_len
, NFS4_MAX_UTF8STRING
));
908 decode_args(xdrproc_t xdrfunc
, refd_door_args_t
*argp
, caddr_t
*xdrargs
,
913 caddr_t tmpargs
= (caddr_t
)&((refd_door_args_t
*)argp
)->xdr_arg
;
914 size_t arg_size
= ((refd_door_args_t
*)argp
)->xdr_len
;
916 xdrmem_create(&xdrs
, tmpargs
, arg_size
, XDR_DECODE
);
918 *xdrargs
= calloc(1, size
);
919 if (*xdrargs
== NULL
) {
920 syslog(LOG_ERR
, "error allocating arguments buffer");
924 if (!(*xdrfunc
)(&xdrs
, *xdrargs
)) {
927 syslog(LOG_ERR
, "error decoding arguments");
937 refd_door_res_t
**results
,
943 *size
= xdr_sizeof((*xdrfunc
), resp
);
944 *results
= malloc(sizeof (refd_door_res_t
) + *size
);
945 if (*results
== NULL
) {
948 (*results
)->xdr_len
= *size
;
949 *size
= sizeof (refd_door_res_t
) + (*results
)->xdr_len
;
950 xdrmem_create(&xdrs
, (caddr_t
)((*results
)->xdr_res
),
951 (*results
)->xdr_len
, XDR_ENCODE
);
952 if (!(*xdrfunc
)(&xdrs
, resp
)) {
953 (*results
)->res_status
= EINVAL
;
954 syslog(LOG_ERR
, "error encoding results");
955 return ((*results
)->res_status
);
957 (*results
)->res_status
= 0;
958 return ((*results
)->res_status
);
963 xdr_knetconfig(XDR
*xdrs
, struct knetconfig
*objp
)
969 uint32_t major
, minor
;
972 if (!xdr_u_int(xdrs
, &objp
->knc_semantics
))
974 if (!xdr_opaque(xdrs
, objp
->knc_protofmly
, KNC_STRSIZE
))
976 if (!xdr_opaque(xdrs
, objp
->knc_proto
, KNC_STRSIZE
))
980 * For interoperability between 32-bit daemon and 64-bit kernel,
981 * we always treat dev_t as 64-bit number and do the expanding
982 * or compression of dev_t as needed.
983 * We have to hand craft the conversion since there is no available
984 * function in ddi.c. Besides ddi.c is available only in the kernel
985 * and we want to keep both user and kernel of xdr_knetconfig() the
986 * same for consistency.
989 if (xdrs
->x_op
== XDR_ENCODE
) {
991 dev64
= objp
->knc_rdev
;
993 major
= (objp
->knc_rdev
>> NBITSMINOR32
) & MAXMAJ32
;
994 minor
= objp
->knc_rdev
& MAXMIN32
;
995 dev64
= (((unsigned long long)major
) << NBITSMINOR64
) | minor
;
997 if (!xdr_u_longlong_t(xdrs
, &dev64
))
1000 if (xdrs
->x_op
== XDR_DECODE
) {
1002 if (!xdr_u_longlong_t(xdrs
, (u_longlong_t
*)&objp
->knc_rdev
))
1005 if (!xdr_u_longlong_t(xdrs
, &dev64
))
1008 major
= (dev64
>> NBITSMINOR64
) & L_MAXMAJ32
;
1009 minor
= dev64
& L_MAXMIN32
;
1010 objp
->knc_rdev
= (major
<< L_BITSMINOR32
) | minor
;
1014 if (xdrs
->x_op
== XDR_ENCODE
) {
1015 buf
= XDR_INLINE(xdrs
, (8) * BYTES_PER_XDR_UNIT
);
1017 if (!xdr_vector(xdrs
, (char *)objp
->knc_unused
, 8,
1018 sizeof (uint_t
), (xdrproc_t
)xdr_u_int
))
1023 for (i
= 0, genp
= objp
->knc_unused
;
1025 #if defined(_LP64) || defined(_KERNEL)
1026 IXDR_PUT_U_INT32(buf
, *genp
++);
1028 IXDR_PUT_U_LONG(buf
, *genp
++);
1033 } else if (xdrs
->x_op
== XDR_DECODE
) {
1034 buf
= XDR_INLINE(xdrs
, (8) * BYTES_PER_XDR_UNIT
);
1036 if (!xdr_vector(xdrs
, (char *)objp
->knc_unused
, 8,
1037 sizeof (uint_t
), (xdrproc_t
)xdr_u_int
))
1042 for (i
= 0, genp
= objp
->knc_unused
;
1044 #if defined(_LP64) || defined(_KERNEL)
1045 *genp
++ = IXDR_GET_U_INT32(buf
);
1047 *genp
++ = IXDR_GET_U_LONG(buf
);
1054 if (!xdr_vector(xdrs
, (char *)objp
->knc_unused
, 8,
1055 sizeof (uint_t
), (xdrproc_t
)xdr_u_int
))
1061 * used by NFSv4 referrals to get info needed for NFSv4 referral mount.
1064 xdr_nfs_fsl_info(XDR
*xdrs
, struct nfs_fsl_info
*objp
)
1067 if (!xdr_u_int(xdrs
, &objp
->netbuf_len
))
1069 if (!xdr_u_int(xdrs
, &objp
->netnm_len
))
1071 if (!xdr_u_int(xdrs
, &objp
->knconf_len
))
1073 if (!xdr_string(xdrs
, &objp
->netname
, ~0))
1075 if (!xdr_pointer(xdrs
, (char **)&objp
->addr
, objp
->netbuf_len
,
1076 (xdrproc_t
)xdr_netbuf
))
1078 if (!xdr_pointer(xdrs
, (char **)&objp
->knconf
,
1079 objp
->knconf_len
, (xdrproc_t
)xdr_knetconfig
))