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
;
320 idmap_free(idmap_buf
);
321 resp
->status
= NFSMAPID_OK
;
325 * There is a chance that the door_return will fail because the
326 * resulting string is too large, try to indicate that if possible
328 if (door_return((char *)resp
,
329 MAPID_RES_LEN(resp
->u_res
.len
), NULL
, 0) == -1) {
330 resp
->status
= NFSMAPID_INTERNAL
;
332 (void) door_return((char *)&result
, sizeof (struct mapid_res
),
338 nfsmapid_str_gid(struct mapid_arg
*argp
, size_t arg_size
)
340 struct mapid_res result
;
342 struct group
*grp_ptr
;
349 if (argp
->u_arg
.len
<= 0 ||
350 arg_size
< MAPID_ARG_LEN(argp
->u_arg
.len
)) {
351 result
.status
= NFSMAPID_INVALID
;
352 result
.u_res
.gid
= GID_NOBODY
;
356 if (!extract_domain(argp
->str
, &group
, &domain
)) {
360 * Invalid "group@domain" string. Still, the
361 * group part might be an encoded gid, so do a
362 * final check. Remember, domain part of string
363 * was not set since not a valid string.
365 if (!validate_id_str(group
)) {
366 result
.status
= NFSMAPID_UNMAPPABLE
;
367 result
.u_res
.gid
= GID_NOBODY
;
372 id
= strtoul(group
, (char **)NULL
, 10);
375 * We don't accept ephemeral ids from the wire.
377 if (errno
|| id
> UID_MAX
) {
378 result
.status
= NFSMAPID_UNMAPPABLE
;
379 result
.u_res
.gid
= GID_NOBODY
;
383 result
.u_res
.gid
= (gid_t
)id
;
384 result
.status
= NFSMAPID_NUMSTR
;
389 * String properly constructed. Now we check for domain and
392 if (!cur_domain_null() && !valid_domain(domain
)) {
394 * If the domain part of the string does not
395 * match the NFS domain, try to map it using
398 rc
= idmap_getgidbywinname(group
, domain
, 0, &result
.u_res
.gid
);
399 if (rc
!= IDMAP_SUCCESS
) {
400 result
.status
= NFSMAPID_BADDOMAIN
;
401 result
.u_res
.gid
= GID_NOBODY
;
404 result
.status
= NFSMAPID_OK
;
408 if ((grp_buf
= malloc(grp_buflen
)) == NULL
||
409 (grp_rc
= getgrnam_r(group
, &grp
, grp_buf
, grp_buflen
, &grp_ptr
))
410 != 0 || grp_ptr
== NULL
) {
412 if (grp_buf
== NULL
|| grp_rc
!= 0)
413 result
.status
= NFSMAPID_INTERNAL
;
418 result
.status
= NFSMAPID_NOTFOUND
;
421 result
.u_res
.gid
= GID_NOBODY
;
428 result
.status
= NFSMAPID_OK
;
429 result
.u_res
.gid
= grp
.gr_gid
;
432 (void) door_return((char *)&result
, sizeof (struct mapid_res
), NULL
, 0);
437 nfsmapid_gid_str(struct mapid_arg
*argp
, size_t arg_size
)
439 struct mapid_res result
;
440 struct mapid_res
*resp
;
442 struct group
*grp_ptr
;
443 char *grp_buf
= NULL
;
444 char *idmap_buf
= NULL
;
446 gid_t gid
= argp
->u_arg
.gid
;
452 char dom_str
[DNAMEMAX
];
455 if (gid
== (gid_t
)-1) {
457 * Sentinel gid is not a valid id
460 resp
->status
= NFSMAPID_BADID
;
466 * Make local copy of domain for further manipuation
467 * NOTE: mapid_get_domain() returns a ptr to TSD.
469 if (cur_domain_null()) {
473 dom_str_len
= strlen(mapid_get_domain());
474 bcopy(mapid_get_domain(), dom_str
, dom_str_len
);
475 dom_str
[dom_str_len
] = '\0';
479 * If gid is ephemeral then resolve it using idmap service
482 rc
= idmap_getwinnamebygid(gid
, 0, &idmap_buf
, NULL
);
483 if (rc
!= IDMAP_SUCCESS
) {
485 * We don't put stringified ephemeral gids on
489 resp
->status
= NFSMAPID_UNMAPPABLE
;
495 * idmap_buf is already in the desired form i.e. name@domain
498 gr_str_len
= strlen(gr_str
);
499 at_str_len
= dom_str_len
= 0;
506 * Handling non-ephemeral gids
508 * We want to encode the gid into a literal string... :
510 * - upon failure to allocate space from the heap
511 * - if there is no current domain configured
512 * - if there is no such gid in the group DB's
514 if ((grp_buf
= malloc(grp_buflen
)) == NULL
|| dom_str_len
== 0 ||
515 getgrgid_r(gid
, &grp
, grp_buf
, grp_buflen
, &grp_ptr
) != 0 ||
519 * If we could not allocate from the heap, try
520 * allocating from the stack as a last resort.
522 if (grp_buf
== NULL
&& (grp_buf
=
523 alloca(MAPID_RES_LEN(UID_MAX_STR_LEN
))) == NULL
) {
525 resp
->status
= NFSMAPID_INTERNAL
;
531 * Constructing literal string without '@' so that
532 * we'll know that it's not a group, but rather a
533 * gid encoded string.
536 (void) sprintf(gr_str
, "%u", gid
);
537 gr_str_len
= strlen(gr_str
);
538 at_str_len
= dom_str_len
= 0;
543 * Otherwise, we construct the "group@domain" string if
544 * it's not already in that form.
546 gr_str
= grp
.gr_name
;
547 gr_str_len
= strlen(gr_str
);
548 if (strchr(gr_str
, '@') == NULL
) {
552 at_str_len
= dom_str_len
= 0;
559 gid_str_len
= gr_str_len
+ at_str_len
+ dom_str_len
;
560 if ((resp
= alloca(MAPID_RES_LEN(gid_str_len
))) == NULL
) {
562 resp
->status
= NFSMAPID_INTERNAL
;
566 /* LINTED format argument to sprintf */
567 (void) sprintf(resp
->str
, "%s%s%s", gr_str
, at_str
, dom_str
);
568 resp
->u_res
.len
= gid_str_len
;
571 idmap_free(idmap_buf
);
572 resp
->status
= NFSMAPID_OK
;
576 * There is a chance that the door_return will fail because the
577 * resulting string is too large, try to indicate that if possible
579 if (door_return((char *)resp
,
580 MAPID_RES_LEN(resp
->u_res
.len
), NULL
, 0) == -1) {
581 resp
->status
= NFSMAPID_INTERNAL
;
583 (void) door_return((char *)&result
, sizeof (struct mapid_res
),
589 nfsmapid_server_netinfo(refd_door_args_t
*referral_args
, size_t arg_size
)
595 char host
[MAXHOSTNAMELEN
];
596 utf8string
*nfsfsloc_args
;
597 refd_door_res_t
*door_res
;
598 refd_door_res_t failed_res
;
599 struct nfs_fsl_info
*nfs_fsloc_res
;
601 if (arg_size
< sizeof (refd_door_args_t
)) {
602 failed_res
.res_status
= EINVAL
;
603 res
= (char *)&failed_res
;
604 res_size
= sizeof (refd_door_res_t
);
606 "nfsmapid_server_netinfo failed: Invalid data\n");
610 if (decode_args(xdr_utf8string
, (refd_door_args_t
*)referral_args
,
611 (caddr_t
*)&nfsfsloc_args
, sizeof (utf8string
))) {
612 syslog(LOG_ERR
, "cannot allocate memory");
613 failed_res
.res_status
= ENOMEM
;
614 failed_res
.xdr_len
= 0;
615 res
= (caddr_t
)&failed_res
;
616 res_size
= sizeof (refd_door_res_t
);
620 if (nfsfsloc_args
->utf8string_len
>= MAXHOSTNAMELEN
) {
621 syslog(LOG_ERR
, "argument too large");
622 failed_res
.res_status
= EOVERFLOW
;
623 failed_res
.xdr_len
= 0;
624 res
= (caddr_t
)&failed_res
;
625 res_size
= sizeof (refd_door_res_t
);
629 snprintf(host
, nfsfsloc_args
->utf8string_len
+ 1,
630 "%s", nfsfsloc_args
->utf8string_val
);
633 get_nfs4ref_info(host
, NFS_PORT
, NFS_V4
);
635 xdr_free(xdr_utf8string
, (char *)&nfsfsloc_args
);
639 error
= encode_res(xdr_nfs_fsl_info
, &door_res
,
640 (caddr_t
)nfs_fsloc_res
, &res_size
);
641 free_nfs4ref_info(nfs_fsloc_res
);
644 "error allocating fs_locations "
646 failed_res
.res_status
= error
;
647 failed_res
.xdr_len
= srsz
;
648 res
= (caddr_t
)&failed_res
;
649 res_size
= sizeof (refd_door_res_t
);
651 door_res
->res_status
= 0;
652 res
= (caddr_t
)door_res
;
655 failed_res
.res_status
= EINVAL
;
656 failed_res
.xdr_len
= 0;
657 res
= (caddr_t
)&failed_res
;
658 res_size
= sizeof (refd_door_res_t
);
665 error
= door_return(res
, res_size
, NULL
, 0);
666 if (errno
== E2BIG
) {
667 failed_res
.res_status
= EOVERFLOW
;
668 failed_res
.xdr_len
= srsz
;
669 res
= (caddr_t
)&failed_res
;
670 res_size
= sizeof (refd_door_res_t
);
676 door_return(res
, res_size
, NULL
, 0);
681 nfsmapid_func(void *cookie
, char *argp
, size_t arg_size
,
682 door_desc_t
*dp
, uint_t n_desc
)
684 struct mapid_arg
*mapargp
;
685 struct mapid_res mapres
;
686 refd_door_args_t
*referral_args
;
689 * Make sure we have a valid argument
691 if (arg_size
< sizeof (struct mapid_arg
)) {
692 mapres
.status
= NFSMAPID_INVALID
;
693 mapres
.u_res
.len
= 0;
694 (void) door_return((char *)&mapres
, sizeof (struct mapid_res
),
699 /* LINTED pointer cast */
700 mapargp
= (struct mapid_arg
*)argp
;
701 referral_args
= (refd_door_args_t
*)argp
;
702 switch (mapargp
->cmd
) {
703 case NFSMAPID_STR_UID
:
704 nfsmapid_str_uid(mapargp
, arg_size
);
706 case NFSMAPID_UID_STR
:
707 nfsmapid_uid_str(mapargp
, arg_size
);
709 case NFSMAPID_STR_GID
:
710 nfsmapid_str_gid(mapargp
, arg_size
);
712 case NFSMAPID_GID_STR
:
713 nfsmapid_gid_str(mapargp
, arg_size
);
715 case NFSMAPID_SRV_NETINFO
:
716 nfsmapid_server_netinfo(referral_args
, arg_size
);
720 mapres
.status
= NFSMAPID_INVALID
;
721 mapres
.u_res
.len
= 0;
722 (void) door_return((char *)&mapres
, sizeof (struct mapid_res
), NULL
, 0);
726 * mapid_get_domain() always returns a ptr to TSD, so the
727 * check for a NULL domain is not a simple comparison with
728 * NULL but we need to check the contents of the TSD data.
731 cur_domain_null(void)
735 if ((p
= mapid_get_domain()) == NULL
)
738 return (p
[0] == '\0');
742 extract_domain(char *cp
, char **upp
, char **dpp
)
745 * Caller must insure that the string is valid
749 if ((*dpp
= strchr(cp
, '@')) == NULL
)
756 valid_domain(const char *dom
)
758 const char *whoami
= "valid_domain";
760 if (!mapid_stdchk_domain(dom
)) {
761 syslog(LOG_ERR
, gettext("%s: Invalid inbound domain name %s."),
767 * NOTE: mapid_get_domain() returns a ptr to TSD.
769 return (strcasecmp(dom
, mapid_get_domain()) == 0);
773 validate_id_str(const char *id
)
783 idmap_kcall(int door_id
)
785 struct nfsidmap_args args
;
794 (void) _nfssys(NFS_IDMAP
, &args
);
798 * Get the current NFS domain.
800 * If nfsmapid_domain is set in NFS SMF, then it is the NFS domain;
801 * otherwise, the DNS domain is used.
804 check_domain(int sighup
)
806 const char *whoami
= "check_domain";
807 static int setup_done
= 0;
811 * Construct the arguments to be passed to libmapid interface
812 * If called in response to a SIGHUP, reset any cached DNS TXT
815 cb
.fcn
= cb_update_domain
;
817 mapid_reeval_domain(&cb
);
820 * Restart the signal handler thread if we're still setting up
824 if (thr_continue(sig_thread
)) {
825 syslog(LOG_ERR
, gettext("%s: Fatal error: signal "
826 "handler thread could not be restarted."), whoami
);
833 * Need to be able to open the DIAG_FILE before nfsmapid(1m)
834 * releases it's root priviledges. The DIAG_FILE then remains
835 * open for the duration of this nfsmapid instance via n4_fd.
840 static int msg_done
= 0;
842 if ((n4_fp
= fopen(DIAG_FILE
, "w+")) != NULL
) {
843 n4_fd
= fileno(n4_fp
);
850 syslog(LOG_ERR
, "Failed to create %s. Enable syslog "
851 "daemon.debug for more info", DIAG_FILE
);
856 * When a new domain name is configured, save to DIAG_FILE
857 * and log to syslog, with LOG_DEBUG level (if configured).
860 update_diag_file(char *new)
866 (void) lseek(n4_fd
, (off_t
)0, SEEK_SET
);
867 (void) ftruncate(n4_fd
, 0);
868 (void) snprintf(buf
, DNAMEMAX
, "%s\n", new);
871 n
= write(n4_fd
, buf
, len
);
872 if (n
< 0 || n
< len
)
873 syslog(LOG_DEBUG
, "Could not write %s to diag file", new);
876 syslog(LOG_DEBUG
, "nfsmapid domain = %s", new);
880 * Callback function for libmapid. This will be called
881 * by the lib, everytime the nfsmapid(1m) domain changes.
884 cb_update_domain(void *arg
)
886 char *new_dname
= (char *)arg
;
888 DTRACE_PROBE1(nfsmapid
, daemon__domain
, new_dname
);
889 update_diag_file(new_dname
);
890 idmap_kcall(FLUSH_KCACHES_ONLY
);
896 xdr_utf8string(XDR
*xdrs
, utf8string
*objp
)
898 if (xdrs
->x_op
!= XDR_FREE
)
899 return (xdr_bytes(xdrs
, (char **)&objp
->utf8string_val
,
900 (uint_t
*)&objp
->utf8string_len
, NFS4_MAX_UTF8STRING
));
906 decode_args(xdrproc_t xdrfunc
, refd_door_args_t
*argp
, caddr_t
*xdrargs
,
911 caddr_t tmpargs
= (caddr_t
)&((refd_door_args_t
*)argp
)->xdr_arg
;
912 size_t arg_size
= ((refd_door_args_t
*)argp
)->xdr_len
;
914 xdrmem_create(&xdrs
, tmpargs
, arg_size
, XDR_DECODE
);
916 *xdrargs
= calloc(1, size
);
917 if (*xdrargs
== NULL
) {
918 syslog(LOG_ERR
, "error allocating arguments buffer");
922 if (!(*xdrfunc
)(&xdrs
, *xdrargs
)) {
925 syslog(LOG_ERR
, "error decoding arguments");
935 refd_door_res_t
**results
,
941 *size
= xdr_sizeof((*xdrfunc
), resp
);
942 *results
= malloc(sizeof (refd_door_res_t
) + *size
);
943 if (*results
== NULL
) {
946 (*results
)->xdr_len
= *size
;
947 *size
= sizeof (refd_door_res_t
) + (*results
)->xdr_len
;
948 xdrmem_create(&xdrs
, (caddr_t
)((*results
)->xdr_res
),
949 (*results
)->xdr_len
, XDR_ENCODE
);
950 if (!(*xdrfunc
)(&xdrs
, resp
)) {
951 (*results
)->res_status
= EINVAL
;
952 syslog(LOG_ERR
, "error encoding results");
953 return ((*results
)->res_status
);
955 (*results
)->res_status
= 0;
956 return ((*results
)->res_status
);
961 xdr_knetconfig(XDR
*xdrs
, struct knetconfig
*objp
)
967 uint32_t major
, minor
;
970 if (!xdr_u_int(xdrs
, &objp
->knc_semantics
))
972 if (!xdr_opaque(xdrs
, objp
->knc_protofmly
, KNC_STRSIZE
))
974 if (!xdr_opaque(xdrs
, objp
->knc_proto
, KNC_STRSIZE
))
978 * For interoperability between 32-bit daemon and 64-bit kernel,
979 * we always treat dev_t as 64-bit number and do the expanding
980 * or compression of dev_t as needed.
981 * We have to hand craft the conversion since there is no available
982 * function in ddi.c. Besides ddi.c is available only in the kernel
983 * and we want to keep both user and kernel of xdr_knetconfig() the
984 * same for consistency.
987 if (xdrs
->x_op
== XDR_ENCODE
) {
989 dev64
= objp
->knc_rdev
;
991 major
= (objp
->knc_rdev
>> NBITSMINOR32
) & MAXMAJ32
;
992 minor
= objp
->knc_rdev
& MAXMIN32
;
993 dev64
= (((unsigned long long)major
) << NBITSMINOR64
) | minor
;
995 if (!xdr_u_longlong_t(xdrs
, &dev64
))
998 if (xdrs
->x_op
== XDR_DECODE
) {
1000 if (!xdr_u_longlong_t(xdrs
, (u_longlong_t
*)&objp
->knc_rdev
))
1003 if (!xdr_u_longlong_t(xdrs
, &dev64
))
1006 major
= (dev64
>> NBITSMINOR64
) & L_MAXMAJ32
;
1007 minor
= dev64
& L_MAXMIN32
;
1008 objp
->knc_rdev
= (major
<< L_BITSMINOR32
) | minor
;
1012 if (xdrs
->x_op
== XDR_ENCODE
) {
1013 buf
= XDR_INLINE(xdrs
, (8) * BYTES_PER_XDR_UNIT
);
1015 if (!xdr_vector(xdrs
, (char *)objp
->knc_unused
, 8,
1016 sizeof (uint_t
), (xdrproc_t
)xdr_u_int
))
1021 for (i
= 0, genp
= objp
->knc_unused
;
1023 #if defined(_LP64) || defined(_KERNEL)
1024 IXDR_PUT_U_INT32(buf
, *genp
++);
1026 IXDR_PUT_U_LONG(buf
, *genp
++);
1031 } else if (xdrs
->x_op
== XDR_DECODE
) {
1032 buf
= XDR_INLINE(xdrs
, (8) * BYTES_PER_XDR_UNIT
);
1034 if (!xdr_vector(xdrs
, (char *)objp
->knc_unused
, 8,
1035 sizeof (uint_t
), (xdrproc_t
)xdr_u_int
))
1040 for (i
= 0, genp
= objp
->knc_unused
;
1042 #if defined(_LP64) || defined(_KERNEL)
1043 *genp
++ = IXDR_GET_U_INT32(buf
);
1045 *genp
++ = IXDR_GET_U_LONG(buf
);
1052 if (!xdr_vector(xdrs
, (char *)objp
->knc_unused
, 8,
1053 sizeof (uint_t
), (xdrproc_t
)xdr_u_int
))
1059 * used by NFSv4 referrals to get info needed for NFSv4 referral mount.
1062 xdr_nfs_fsl_info(XDR
*xdrs
, struct nfs_fsl_info
*objp
)
1065 if (!xdr_u_int(xdrs
, &objp
->netbuf_len
))
1067 if (!xdr_u_int(xdrs
, &objp
->netnm_len
))
1069 if (!xdr_u_int(xdrs
, &objp
->knconf_len
))
1071 if (!xdr_string(xdrs
, &objp
->netname
, ~0))
1073 if (!xdr_pointer(xdrs
, (char **)&objp
->addr
, objp
->netbuf_len
,
1074 (xdrproc_t
)xdr_netbuf
))
1076 if (!xdr_pointer(xdrs
, (char **)&objp
->knconf
,
1077 objp
->knconf_len
, (xdrproc_t
)xdr_knetconfig
))