8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / fs.d / nfs / nfsmapid / nfsmapid_server.c
blob3fde3ce099b7ef407a69238eefeb231e77b98c17
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 if (pwd_buf)
319 free(pwd_buf);
320 if (idmap_buf)
321 idmap_free(idmap_buf);
322 resp->status = NFSMAPID_OK;
324 done:
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;
332 resp->u_res.len = 0;
333 (void) door_return((char *)&result, sizeof (struct mapid_res),
334 NULL, 0);
338 void
339 nfsmapid_str_gid(struct mapid_arg *argp, size_t arg_size)
341 struct mapid_res result;
342 struct group grp;
343 struct group *grp_ptr;
344 int grp_rc;
345 char *grp_buf;
346 char *group;
347 char *domain;
348 idmap_stat rc;
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;
354 goto done;
357 if (!extract_domain(argp->str, &group, &domain)) {
358 unsigned long id;
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;
369 goto done;
372 errno = 0;
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;
381 goto done;
384 result.u_res.gid = (gid_t)id;
385 result.status = NFSMAPID_NUMSTR;
386 goto done;
390 * String properly constructed. Now we check for domain and
391 * group validity.
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
397 * idmap service.
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;
403 goto done;
405 result.status = NFSMAPID_OK;
406 goto done;
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;
415 else {
417 * Not a valid group
419 result.status = NFSMAPID_NOTFOUND;
420 free(grp_buf);
422 result.u_res.gid = GID_NOBODY;
423 goto done;
427 * Valid group entry
429 result.status = NFSMAPID_OK;
430 result.u_res.gid = grp.gr_gid;
431 free(grp_buf);
432 done:
433 (void) door_return((char *)&result, sizeof (struct mapid_res), NULL, 0);
436 /* ARGSUSED1 */
437 void
438 nfsmapid_gid_str(struct mapid_arg *argp, size_t arg_size)
440 struct mapid_res result;
441 struct mapid_res *resp;
442 struct group grp;
443 struct group *grp_ptr;
444 char *grp_buf = NULL;
445 char *idmap_buf = NULL;
446 idmap_stat rc;
447 gid_t gid = argp->u_arg.gid;
448 size_t gid_str_len;
449 char *gr_str;
450 size_t gr_str_len;
451 char *at_str;
452 size_t at_str_len;
453 char dom_str[DNAMEMAX];
454 size_t dom_str_len;
456 if (gid == (gid_t)-1) {
458 * Sentinel gid is not a valid id
460 resp = &result;
461 resp->status = NFSMAPID_BADID;
462 resp->u_res.len = 0;
463 goto done;
467 * Make local copy of domain for further manipuation
468 * NOTE: mapid_get_domain() returns a ptr to TSD.
470 if (cur_domain_null()) {
471 dom_str_len = 0;
472 dom_str[0] = '\0';
473 } else {
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
482 if (gid > UID_MAX) {
483 rc = idmap_getwinnamebygid(gid, 0, &idmap_buf, NULL);
484 if (rc != IDMAP_SUCCESS) {
486 * We don't put stringified ephemeral gids on
487 * the wire.
489 resp = &result;
490 resp->status = NFSMAPID_UNMAPPABLE;
491 resp->u_res.len = 0;
492 goto done;
496 * idmap_buf is already in the desired form i.e. name@domain
498 gr_str = idmap_buf;
499 gr_str_len = strlen(gr_str);
500 at_str_len = dom_str_len = 0;
501 at_str = "";
502 dom_str[0] = '\0';
503 goto gen_result;
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 ||
517 grp_ptr == NULL) {
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) {
525 resp = &result;
526 resp->status = NFSMAPID_INTERNAL;
527 resp->u_res.len = 0;
528 goto done;
532 * Constructing literal string without '@' so that
533 * we'll know that it's not a group, but rather a
534 * gid encoded string.
536 gr_str = grp_buf;
537 (void) sprintf(gr_str, "%u", gid);
538 gr_str_len = strlen(gr_str);
539 at_str_len = dom_str_len = 0;
540 at_str = "";
541 dom_str[0] = '\0';
542 } else {
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) {
550 at_str = "@";
551 at_str_len = 1;
552 } else {
553 at_str_len = dom_str_len = 0;
554 at_str = "";
555 dom_str[0] = '\0';
559 gen_result:
560 gid_str_len = gr_str_len + at_str_len + dom_str_len;
561 if ((resp = alloca(MAPID_RES_LEN(gid_str_len))) == NULL) {
562 resp = &result;
563 resp->status = NFSMAPID_INTERNAL;
564 resp->u_res.len = 0;
565 goto done;
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;
570 if (grp_buf)
571 free(grp_buf);
572 if (idmap_buf)
573 idmap_free(idmap_buf);
574 resp->status = NFSMAPID_OK;
576 done:
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;
584 resp->u_res.len = 0;
585 (void) door_return((char *)&result, sizeof (struct mapid_res),
586 NULL, 0);
590 void
591 nfsmapid_server_netinfo(refd_door_args_t *referral_args, size_t arg_size)
593 char *res;
594 int res_size;
595 int error;
596 int srsz = 0;
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);
607 syslog(LOG_ERR,
608 "nfsmapid_server_netinfo failed: Invalid data\n");
609 goto send_response;
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);
619 goto send_response;
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);
628 goto send_response;
631 snprintf(host, nfsfsloc_args->utf8string_len + 1,
632 "%s", nfsfsloc_args->utf8string_val);
634 nfs_fsloc_res =
635 get_nfs4ref_info(host, NFS_PORT, NFS_V4);
637 xdr_free(xdr_utf8string, (char *)&nfsfsloc_args);
639 if (nfs_fsloc_res) {
640 error = 0;
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);
644 if (error != 0) {
645 syslog(LOG_ERR,
646 "error allocating fs_locations "
647 "results buffer");
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);
652 } else {
653 door_res->res_status = 0;
654 res = (caddr_t)door_res;
656 } else {
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);
663 send_response:
664 srsz = res_size;
665 errno = 0;
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);
673 } else {
674 res = NULL;
675 res_size = 0;
678 door_return(res, res_size, NULL, 0);
681 /* ARGSUSED */
682 void
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),
697 NULL, 0);
698 return;
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);
707 return;
708 case NFSMAPID_UID_STR:
709 nfsmapid_uid_str(mapargp, arg_size);
710 return;
711 case NFSMAPID_STR_GID:
712 nfsmapid_str_gid(mapargp, arg_size);
713 return;
714 case NFSMAPID_GID_STR:
715 nfsmapid_gid_str(mapargp, arg_size);
716 return;
717 case NFSMAPID_SRV_NETINFO:
718 nfsmapid_server_netinfo(referral_args, arg_size);
719 default:
720 break;
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)
735 char *p;
737 if ((p = mapid_get_domain()) == NULL)
738 return (1);
740 return (p[0] == '\0');
744 extract_domain(char *cp, char **upp, char **dpp)
747 * Caller must insure that the string is valid
749 *upp = cp;
751 if ((*dpp = strchr(cp, '@')) == NULL)
752 return (0);
753 *(*dpp)++ = '\0';
754 return (1);
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."),
764 whoami, dom);
765 return (0);
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)
777 while (*id) {
778 if (!isdigit(*id++))
779 return (0);
781 return (1);
784 void
785 idmap_kcall(int door_id)
787 struct nfsidmap_args args;
789 if (door_id >= 0) {
790 args.state = 1;
791 args.did = door_id;
792 } else {
793 args.state = 0;
794 args.did = 0;
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.
805 void
806 check_domain(int sighup)
808 const char *whoami = "check_domain";
809 static int setup_done = 0;
810 static cb_t cb;
813 * Construct the arguments to be passed to libmapid interface
814 * If called in response to a SIGHUP, reset any cached DNS TXT
815 * RR state.
817 cb.fcn = cb_update_domain;
818 cb.signal = sighup;
819 mapid_reeval_domain(&cb);
822 * Restart the signal handler thread if we're still setting up
824 if (!setup_done) {
825 setup_done = 1;
826 if (thr_continue(sig_thread)) {
827 syslog(LOG_ERR, gettext("%s: Fatal error: signal "
828 "handler thread could not be restarted."), whoami);
829 exit(6);
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.
839 void
840 open_diag_file()
842 static int msg_done = 0;
844 if ((n4_fp = fopen(DIAG_FILE, "w+")) != NULL) {
845 n4_fd = fileno(n4_fp);
846 return;
849 if (msg_done)
850 return;
852 syslog(LOG_ERR, "Failed to create %s. Enable syslog "
853 "daemon.debug for more info", DIAG_FILE);
854 msg_done = 1;
858 * When a new domain name is configured, save to DIAG_FILE
859 * and log to syslog, with LOG_DEBUG level (if configured).
861 void
862 update_diag_file(char *new)
864 char buf[DNAMEMAX];
865 ssize_t n;
866 size_t len;
868 (void) lseek(n4_fd, (off_t)0, SEEK_SET);
869 (void) ftruncate(n4_fd, 0);
870 (void) snprintf(buf, DNAMEMAX, "%s\n", new);
872 len = strlen(buf);
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);
876 (void) fsync(n4_fd);
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.
885 void *
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);
894 return (NULL);
897 bool_t
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));
903 return (TRUE);
908 decode_args(xdrproc_t xdrfunc, refd_door_args_t *argp, caddr_t *xdrargs,
909 int size)
911 XDR xdrs;
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");
921 return (ENOMEM);
924 if (!(*xdrfunc)(&xdrs, *xdrargs)) {
925 free(*xdrargs);
926 *xdrargs = NULL;
927 syslog(LOG_ERR, "error decoding arguments");
928 return (EINVAL);
931 return (0);
935 encode_res(
936 xdrproc_t xdrfunc,
937 refd_door_res_t **results,
938 caddr_t resp,
939 int *size)
941 XDR xdrs;
943 *size = xdr_sizeof((*xdrfunc), resp);
944 *results = malloc(sizeof (refd_door_res_t) + *size);
945 if (*results == NULL) {
946 return (ENOMEM);
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);
962 bool_t
963 xdr_knetconfig(XDR *xdrs, struct knetconfig *objp)
965 rpc_inline_t *buf;
966 int i;
967 u_longlong_t dev64;
968 #if !defined(_LP64)
969 uint32_t major, minor;
970 #endif
972 if (!xdr_u_int(xdrs, &objp->knc_semantics))
973 return (FALSE);
974 if (!xdr_opaque(xdrs, objp->knc_protofmly, KNC_STRSIZE))
975 return (FALSE);
976 if (!xdr_opaque(xdrs, objp->knc_proto, KNC_STRSIZE))
977 return (FALSE);
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) {
990 #if defined(_LP64)
991 dev64 = objp->knc_rdev;
992 #else
993 major = (objp->knc_rdev >> NBITSMINOR32) & MAXMAJ32;
994 minor = objp->knc_rdev & MAXMIN32;
995 dev64 = (((unsigned long long)major) << NBITSMINOR64) | minor;
996 #endif
997 if (!xdr_u_longlong_t(xdrs, &dev64))
998 return (FALSE);
1000 if (xdrs->x_op == XDR_DECODE) {
1001 #if defined(_LP64)
1002 if (!xdr_u_longlong_t(xdrs, (u_longlong_t *)&objp->knc_rdev))
1003 return (FALSE);
1004 #else
1005 if (!xdr_u_longlong_t(xdrs, &dev64))
1006 return (FALSE);
1008 major = (dev64 >> NBITSMINOR64) & L_MAXMAJ32;
1009 minor = dev64 & L_MAXMIN32;
1010 objp->knc_rdev = (major << L_BITSMINOR32) | minor;
1011 #endif
1014 if (xdrs->x_op == XDR_ENCODE) {
1015 buf = XDR_INLINE(xdrs, (8) * BYTES_PER_XDR_UNIT);
1016 if (buf == NULL) {
1017 if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
1018 sizeof (uint_t), (xdrproc_t)xdr_u_int))
1019 return (FALSE);
1020 } else {
1021 uint_t *genp;
1023 for (i = 0, genp = objp->knc_unused;
1024 i < 8; i++) {
1025 #if defined(_LP64) || defined(_KERNEL)
1026 IXDR_PUT_U_INT32(buf, *genp++);
1027 #else
1028 IXDR_PUT_U_LONG(buf, *genp++);
1029 #endif
1032 return (TRUE);
1033 } else if (xdrs->x_op == XDR_DECODE) {
1034 buf = XDR_INLINE(xdrs, (8) * BYTES_PER_XDR_UNIT);
1035 if (buf == NULL) {
1036 if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
1037 sizeof (uint_t), (xdrproc_t)xdr_u_int))
1038 return (FALSE);
1039 } else {
1040 uint_t *genp;
1042 for (i = 0, genp = objp->knc_unused;
1043 i < 8; i++) {
1044 #if defined(_LP64) || defined(_KERNEL)
1045 *genp++ = IXDR_GET_U_INT32(buf);
1046 #else
1047 *genp++ = IXDR_GET_U_LONG(buf);
1048 #endif
1051 return (TRUE);
1054 if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
1055 sizeof (uint_t), (xdrproc_t)xdr_u_int))
1056 return (FALSE);
1057 return (TRUE);
1061 * used by NFSv4 referrals to get info needed for NFSv4 referral mount.
1063 bool_t
1064 xdr_nfs_fsl_info(XDR *xdrs, struct nfs_fsl_info *objp)
1067 if (!xdr_u_int(xdrs, &objp->netbuf_len))
1068 return (FALSE);
1069 if (!xdr_u_int(xdrs, &objp->netnm_len))
1070 return (FALSE);
1071 if (!xdr_u_int(xdrs, &objp->knconf_len))
1072 return (FALSE);
1073 if (!xdr_string(xdrs, &objp->netname, ~0))
1074 return (FALSE);
1075 if (!xdr_pointer(xdrs, (char **)&objp->addr, objp->netbuf_len,
1076 (xdrproc_t)xdr_netbuf))
1077 return (FALSE);
1078 if (!xdr_pointer(xdrs, (char **)&objp->knconf,
1079 objp->knconf_len, (xdrproc_t)xdr_knetconfig))
1080 return (FALSE);
1081 return (TRUE);