Move /var/svc/log to /var/log/svc
[unleashed/lotheac.git] / usr / src / cmd / fs.d / nfs / nfsmapid / nfsmapid_server.c
blob932106089cb2cb113c1f900812b4586bf8168b40
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <alloca.h>
33 #include <signal.h>
34 #include <libintl.h>
35 #include <limits.h>
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <string.h>
39 #include <memory.h>
40 #include <pwd.h>
41 #include <grp.h>
42 #include <door.h>
43 #include <syslog.h>
44 #include <fcntl.h>
45 #include <unistd.h>
46 #include <assert.h>
47 #include <deflt.h>
48 #include <nfs/nfs4.h>
49 #include <nfs/nfssys.h>
50 #include <nfs/nfsid_map.h>
51 #include <nfs/mapid.h>
52 #include <sys/sdt.h>
53 #include <sys/idmap.h>
54 #include <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
69 FILE *n4_fp;
70 int n4_fd;
72 extern size_t pwd_buflen;
73 extern size_t grp_buflen;
74 extern thread_t sig_thread;
77 * Prototypes
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);
89 void
90 nfsmapid_str_uid(struct mapid_arg *argp, size_t arg_size)
92 struct mapid_res result;
93 struct passwd pwd;
94 struct passwd *pwd_ptr;
95 int pwd_rc;
96 char *pwd_buf;
97 char *user;
98 char *domain;
99 idmap_stat rc;
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;
104 goto done;
107 if (!extract_domain(argp->str, &user, &domain)) {
108 unsigned long id;
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;
119 goto done;
122 errno = 0;
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;
131 goto done;
134 result.u_res.uid = (uid_t)id;
135 result.status = NFSMAPID_NUMSTR;
136 goto done;
140 * String properly constructed. Now we check for domain and
141 * group validity.
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
147 * idmap service.
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;
153 goto done;
155 result.status = NFSMAPID_OK;
156 goto done;
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;
165 else {
167 * Not a valid user
169 result.status = NFSMAPID_NOTFOUND;
170 free(pwd_buf);
172 result.u_res.uid = UID_NOBODY;
173 goto done;
177 * Valid user entry
179 result.u_res.uid = pwd.pw_uid;
180 result.status = NFSMAPID_OK;
181 free(pwd_buf);
182 done:
183 (void) door_return((char *)&result, sizeof (struct mapid_res), NULL, 0);
186 /* ARGSUSED1 */
187 void
188 nfsmapid_uid_str(struct mapid_arg *argp, size_t arg_size)
190 struct mapid_res result;
191 struct mapid_res *resp;
192 struct passwd pwd;
193 struct passwd *pwd_ptr;
194 char *pwd_buf = NULL;
195 char *idmap_buf = NULL;
196 uid_t uid = argp->u_arg.uid;
197 size_t uid_str_len;
198 char *pw_str;
199 size_t pw_str_len;
200 char *at_str;
201 size_t at_str_len;
202 char dom_str[DNAMEMAX];
203 size_t dom_str_len;
204 idmap_stat rc;
206 if (uid == (uid_t)-1) {
208 * Sentinel uid is not a valid id
210 resp = &result;
211 resp->status = NFSMAPID_BADID;
212 resp->u_res.len = 0;
213 goto done;
217 * Make local copy of domain for further manipuation
218 * NOTE: mapid_get_domain() returns a ptr to TSD.
220 if (cur_domain_null()) {
221 dom_str_len = 0;
222 dom_str[0] = '\0';
223 } else {
224 dom_str_len = strlcpy(dom_str, mapid_get_domain(), DNAMEMAX);
228 * If uid is ephemeral then resolve it using idmap service
230 if (uid > UID_MAX) {
231 rc = idmap_getwinnamebyuid(uid, 0, &idmap_buf, NULL);
232 if (rc != IDMAP_SUCCESS) {
234 * We don't put stringified ephemeral uids on
235 * the wire.
237 resp = &result;
238 resp->status = NFSMAPID_UNMAPPABLE;
239 resp->u_res.len = 0;
240 goto done;
244 * idmap_buf is already in the desired form i.e. name@domain
246 pw_str = idmap_buf;
247 pw_str_len = strlen(pw_str);
248 at_str_len = dom_str_len = 0;
249 at_str = "";
250 dom_str[0] = '\0';
251 goto gen_result;
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 ||
265 pwd_ptr == NULL) {
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) {
273 resp = &result;
274 resp->status = NFSMAPID_INTERNAL;
275 resp->u_res.len = 0;
276 goto done;
280 * Constructing literal string without '@' so that
281 * we'll know that it's not a user, but rather a
282 * uid encoded string.
284 pw_str = pwd_buf;
285 (void) sprintf(pw_str, "%u", uid);
286 pw_str_len = strlen(pw_str);
287 at_str_len = dom_str_len = 0;
288 at_str = "";
289 dom_str[0] = '\0';
290 } else {
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) {
298 at_str = "@";
299 at_str_len = 1;
300 } else {
301 at_str_len = dom_str_len = 0;
302 at_str = "";
303 dom_str[0] = '\0';
307 gen_result:
308 uid_str_len = pw_str_len + at_str_len + dom_str_len;
309 if ((resp = alloca(MAPID_RES_LEN(uid_str_len))) == NULL) {
310 resp = &result;
311 resp->status = NFSMAPID_INTERNAL;
312 resp->u_res.len = 0;
313 goto done;
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;
318 free(pwd_buf);
319 if (idmap_buf)
320 idmap_free(idmap_buf);
321 resp->status = NFSMAPID_OK;
323 done:
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;
331 resp->u_res.len = 0;
332 (void) door_return((char *)&result, sizeof (struct mapid_res),
333 NULL, 0);
337 void
338 nfsmapid_str_gid(struct mapid_arg *argp, size_t arg_size)
340 struct mapid_res result;
341 struct group grp;
342 struct group *grp_ptr;
343 int grp_rc;
344 char *grp_buf;
345 char *group;
346 char *domain;
347 idmap_stat rc;
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;
353 goto done;
356 if (!extract_domain(argp->str, &group, &domain)) {
357 unsigned long id;
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;
368 goto done;
371 errno = 0;
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;
380 goto done;
383 result.u_res.gid = (gid_t)id;
384 result.status = NFSMAPID_NUMSTR;
385 goto done;
389 * String properly constructed. Now we check for domain and
390 * group validity.
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
396 * idmap service.
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;
402 goto done;
404 result.status = NFSMAPID_OK;
405 goto done;
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;
414 else {
416 * Not a valid group
418 result.status = NFSMAPID_NOTFOUND;
419 free(grp_buf);
421 result.u_res.gid = GID_NOBODY;
422 goto done;
426 * Valid group entry
428 result.status = NFSMAPID_OK;
429 result.u_res.gid = grp.gr_gid;
430 free(grp_buf);
431 done:
432 (void) door_return((char *)&result, sizeof (struct mapid_res), NULL, 0);
435 /* ARGSUSED1 */
436 void
437 nfsmapid_gid_str(struct mapid_arg *argp, size_t arg_size)
439 struct mapid_res result;
440 struct mapid_res *resp;
441 struct group grp;
442 struct group *grp_ptr;
443 char *grp_buf = NULL;
444 char *idmap_buf = NULL;
445 idmap_stat rc;
446 gid_t gid = argp->u_arg.gid;
447 size_t gid_str_len;
448 char *gr_str;
449 size_t gr_str_len;
450 char *at_str;
451 size_t at_str_len;
452 char dom_str[DNAMEMAX];
453 size_t dom_str_len;
455 if (gid == (gid_t)-1) {
457 * Sentinel gid is not a valid id
459 resp = &result;
460 resp->status = NFSMAPID_BADID;
461 resp->u_res.len = 0;
462 goto done;
466 * Make local copy of domain for further manipuation
467 * NOTE: mapid_get_domain() returns a ptr to TSD.
469 if (cur_domain_null()) {
470 dom_str_len = 0;
471 dom_str[0] = '\0';
472 } else {
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
481 if (gid > UID_MAX) {
482 rc = idmap_getwinnamebygid(gid, 0, &idmap_buf, NULL);
483 if (rc != IDMAP_SUCCESS) {
485 * We don't put stringified ephemeral gids on
486 * the wire.
488 resp = &result;
489 resp->status = NFSMAPID_UNMAPPABLE;
490 resp->u_res.len = 0;
491 goto done;
495 * idmap_buf is already in the desired form i.e. name@domain
497 gr_str = idmap_buf;
498 gr_str_len = strlen(gr_str);
499 at_str_len = dom_str_len = 0;
500 at_str = "";
501 dom_str[0] = '\0';
502 goto gen_result;
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 ||
516 grp_ptr == NULL) {
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) {
524 resp = &result;
525 resp->status = NFSMAPID_INTERNAL;
526 resp->u_res.len = 0;
527 goto done;
531 * Constructing literal string without '@' so that
532 * we'll know that it's not a group, but rather a
533 * gid encoded string.
535 gr_str = grp_buf;
536 (void) sprintf(gr_str, "%u", gid);
537 gr_str_len = strlen(gr_str);
538 at_str_len = dom_str_len = 0;
539 at_str = "";
540 dom_str[0] = '\0';
541 } else {
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) {
549 at_str = "@";
550 at_str_len = 1;
551 } else {
552 at_str_len = dom_str_len = 0;
553 at_str = "";
554 dom_str[0] = '\0';
558 gen_result:
559 gid_str_len = gr_str_len + at_str_len + dom_str_len;
560 if ((resp = alloca(MAPID_RES_LEN(gid_str_len))) == NULL) {
561 resp = &result;
562 resp->status = NFSMAPID_INTERNAL;
563 resp->u_res.len = 0;
564 goto done;
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;
569 free(grp_buf);
570 if (idmap_buf)
571 idmap_free(idmap_buf);
572 resp->status = NFSMAPID_OK;
574 done:
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;
582 resp->u_res.len = 0;
583 (void) door_return((char *)&result, sizeof (struct mapid_res),
584 NULL, 0);
588 void
589 nfsmapid_server_netinfo(refd_door_args_t *referral_args, size_t arg_size)
591 char *res;
592 int res_size;
593 int error;
594 int srsz = 0;
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);
605 syslog(LOG_ERR,
606 "nfsmapid_server_netinfo failed: Invalid data\n");
607 goto send_response;
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);
617 goto send_response;
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);
626 goto send_response;
629 snprintf(host, nfsfsloc_args->utf8string_len + 1,
630 "%s", nfsfsloc_args->utf8string_val);
632 nfs_fsloc_res =
633 get_nfs4ref_info(host, NFS_PORT, NFS_V4);
635 xdr_free(xdr_utf8string, (char *)&nfsfsloc_args);
637 if (nfs_fsloc_res) {
638 error = 0;
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);
642 if (error != 0) {
643 syslog(LOG_ERR,
644 "error allocating fs_locations "
645 "results buffer");
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);
650 } else {
651 door_res->res_status = 0;
652 res = (caddr_t)door_res;
654 } else {
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);
661 send_response:
662 srsz = res_size;
663 errno = 0;
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);
671 } else {
672 res = NULL;
673 res_size = 0;
676 door_return(res, res_size, NULL, 0);
679 /* ARGSUSED */
680 void
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),
695 NULL, 0);
696 return;
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);
705 return;
706 case NFSMAPID_UID_STR:
707 nfsmapid_uid_str(mapargp, arg_size);
708 return;
709 case NFSMAPID_STR_GID:
710 nfsmapid_str_gid(mapargp, arg_size);
711 return;
712 case NFSMAPID_GID_STR:
713 nfsmapid_gid_str(mapargp, arg_size);
714 return;
715 case NFSMAPID_SRV_NETINFO:
716 nfsmapid_server_netinfo(referral_args, arg_size);
717 default:
718 break;
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)
733 char *p;
735 if ((p = mapid_get_domain()) == NULL)
736 return (1);
738 return (p[0] == '\0');
742 extract_domain(char *cp, char **upp, char **dpp)
745 * Caller must insure that the string is valid
747 *upp = cp;
749 if ((*dpp = strchr(cp, '@')) == NULL)
750 return (0);
751 *(*dpp)++ = '\0';
752 return (1);
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."),
762 whoami, dom);
763 return (0);
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)
775 while (*id) {
776 if (!isdigit(*id++))
777 return (0);
779 return (1);
782 void
783 idmap_kcall(int door_id)
785 struct nfsidmap_args args;
787 if (door_id >= 0) {
788 args.state = 1;
789 args.did = door_id;
790 } else {
791 args.state = 0;
792 args.did = 0;
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.
803 void
804 check_domain(int sighup)
806 const char *whoami = "check_domain";
807 static int setup_done = 0;
808 static cb_t cb;
811 * Construct the arguments to be passed to libmapid interface
812 * If called in response to a SIGHUP, reset any cached DNS TXT
813 * RR state.
815 cb.fcn = cb_update_domain;
816 cb.signal = sighup;
817 mapid_reeval_domain(&cb);
820 * Restart the signal handler thread if we're still setting up
822 if (!setup_done) {
823 setup_done = 1;
824 if (thr_continue(sig_thread)) {
825 syslog(LOG_ERR, gettext("%s: Fatal error: signal "
826 "handler thread could not be restarted."), whoami);
827 exit(6);
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.
837 void
838 open_diag_file()
840 static int msg_done = 0;
842 if ((n4_fp = fopen(DIAG_FILE, "w+")) != NULL) {
843 n4_fd = fileno(n4_fp);
844 return;
847 if (msg_done)
848 return;
850 syslog(LOG_ERR, "Failed to create %s. Enable syslog "
851 "daemon.debug for more info", DIAG_FILE);
852 msg_done = 1;
856 * When a new domain name is configured, save to DIAG_FILE
857 * and log to syslog, with LOG_DEBUG level (if configured).
859 void
860 update_diag_file(char *new)
862 char buf[DNAMEMAX];
863 ssize_t n;
864 size_t len;
866 (void) lseek(n4_fd, (off_t)0, SEEK_SET);
867 (void) ftruncate(n4_fd, 0);
868 (void) snprintf(buf, DNAMEMAX, "%s\n", new);
870 len = strlen(buf);
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);
874 (void) fsync(n4_fd);
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.
883 void *
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);
892 return (NULL);
895 bool_t
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));
901 return (TRUE);
906 decode_args(xdrproc_t xdrfunc, refd_door_args_t *argp, caddr_t *xdrargs,
907 int size)
909 XDR xdrs;
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");
919 return (ENOMEM);
922 if (!(*xdrfunc)(&xdrs, *xdrargs)) {
923 free(*xdrargs);
924 *xdrargs = NULL;
925 syslog(LOG_ERR, "error decoding arguments");
926 return (EINVAL);
929 return (0);
933 encode_res(
934 xdrproc_t xdrfunc,
935 refd_door_res_t **results,
936 caddr_t resp,
937 int *size)
939 XDR xdrs;
941 *size = xdr_sizeof((*xdrfunc), resp);
942 *results = malloc(sizeof (refd_door_res_t) + *size);
943 if (*results == NULL) {
944 return (ENOMEM);
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);
960 bool_t
961 xdr_knetconfig(XDR *xdrs, struct knetconfig *objp)
963 rpc_inline_t *buf;
964 int i;
965 u_longlong_t dev64;
966 #if !defined(_LP64)
967 uint32_t major, minor;
968 #endif
970 if (!xdr_u_int(xdrs, &objp->knc_semantics))
971 return (FALSE);
972 if (!xdr_opaque(xdrs, objp->knc_protofmly, KNC_STRSIZE))
973 return (FALSE);
974 if (!xdr_opaque(xdrs, objp->knc_proto, KNC_STRSIZE))
975 return (FALSE);
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) {
988 #if defined(_LP64)
989 dev64 = objp->knc_rdev;
990 #else
991 major = (objp->knc_rdev >> NBITSMINOR32) & MAXMAJ32;
992 minor = objp->knc_rdev & MAXMIN32;
993 dev64 = (((unsigned long long)major) << NBITSMINOR64) | minor;
994 #endif
995 if (!xdr_u_longlong_t(xdrs, &dev64))
996 return (FALSE);
998 if (xdrs->x_op == XDR_DECODE) {
999 #if defined(_LP64)
1000 if (!xdr_u_longlong_t(xdrs, (u_longlong_t *)&objp->knc_rdev))
1001 return (FALSE);
1002 #else
1003 if (!xdr_u_longlong_t(xdrs, &dev64))
1004 return (FALSE);
1006 major = (dev64 >> NBITSMINOR64) & L_MAXMAJ32;
1007 minor = dev64 & L_MAXMIN32;
1008 objp->knc_rdev = (major << L_BITSMINOR32) | minor;
1009 #endif
1012 if (xdrs->x_op == XDR_ENCODE) {
1013 buf = XDR_INLINE(xdrs, (8) * BYTES_PER_XDR_UNIT);
1014 if (buf == NULL) {
1015 if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
1016 sizeof (uint_t), (xdrproc_t)xdr_u_int))
1017 return (FALSE);
1018 } else {
1019 uint_t *genp;
1021 for (i = 0, genp = objp->knc_unused;
1022 i < 8; i++) {
1023 #if defined(_LP64) || defined(_KERNEL)
1024 IXDR_PUT_U_INT32(buf, *genp++);
1025 #else
1026 IXDR_PUT_U_LONG(buf, *genp++);
1027 #endif
1030 return (TRUE);
1031 } else if (xdrs->x_op == XDR_DECODE) {
1032 buf = XDR_INLINE(xdrs, (8) * BYTES_PER_XDR_UNIT);
1033 if (buf == NULL) {
1034 if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
1035 sizeof (uint_t), (xdrproc_t)xdr_u_int))
1036 return (FALSE);
1037 } else {
1038 uint_t *genp;
1040 for (i = 0, genp = objp->knc_unused;
1041 i < 8; i++) {
1042 #if defined(_LP64) || defined(_KERNEL)
1043 *genp++ = IXDR_GET_U_INT32(buf);
1044 #else
1045 *genp++ = IXDR_GET_U_LONG(buf);
1046 #endif
1049 return (TRUE);
1052 if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
1053 sizeof (uint_t), (xdrproc_t)xdr_u_int))
1054 return (FALSE);
1055 return (TRUE);
1059 * used by NFSv4 referrals to get info needed for NFSv4 referral mount.
1061 bool_t
1062 xdr_nfs_fsl_info(XDR *xdrs, struct nfs_fsl_info *objp)
1065 if (!xdr_u_int(xdrs, &objp->netbuf_len))
1066 return (FALSE);
1067 if (!xdr_u_int(xdrs, &objp->netnm_len))
1068 return (FALSE);
1069 if (!xdr_u_int(xdrs, &objp->knconf_len))
1070 return (FALSE);
1071 if (!xdr_string(xdrs, &objp->netname, ~0))
1072 return (FALSE);
1073 if (!xdr_pointer(xdrs, (char **)&objp->addr, objp->netbuf_len,
1074 (xdrproc_t)xdr_netbuf))
1075 return (FALSE);
1076 if (!xdr_pointer(xdrs, (char **)&objp->knconf,
1077 objp->knconf_len, (xdrproc_t)xdr_knetconfig))
1078 return (FALSE);
1079 return (TRUE);