]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/idmapd/idmapd.c
*** empty log message ***
[nfs-utils.git] / utils / idmapd / idmapd.c
1 /*
2  *  idmapd.c
3  *
4  *  Userland daemon for idmap.
5  *
6  *  Copyright (c) 2002 The Regents of the University of Michigan.
7  *  All rights reserved.
8  *
9  *  Marius Aamodt Eriksen <marius@umich.edu>
10  *
11  *  Redistribution and use in source and binary forms, with or without
12  *  modification, are permitted provided that the following conditions
13  *  are met:
14  *
15  *  1. Redistributions of source code must retain the above copyright
16  *     notice, this list of conditions and the following disclaimer.
17  *  2. Redistributions in binary form must reproduce the above copyright
18  *     notice, this list of conditions and the following disclaimer in the
19  *     documentation and/or other materials provided with the distribution.
20  *  3. Neither the name of the University nor the names of its
21  *     contributors may be used to endorse or promote products derived
22  *     from this software without specific prior written permission.
23  *
24  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36
37 #include <sys/types.h>
38 #include <sys/time.h>
39 #include <sys/poll.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <time.h>
43
44 #include "nfs_idmap.h"
45
46 #include <err.h>
47 #include <errno.h>
48 #include <event.h>
49 #include <fcntl.h>
50 #include <dirent.h>
51 #include <unistd.h>
52 #include <netdb.h>
53 #include <signal.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <pwd.h>
58 #include <grp.h>
59 #include <limits.h>
60 #include <ctype.h>
61 #include <nfsidmap.h>
62
63 #ifdef HAVE_CONFIG_H
64 #include "config.h"
65 #endif /* HAVE_CONFIG_H */
66
67 #include "cfg.h"
68 #include "queue.h"
69 #include "nfslib.h"
70
71 #ifndef PIPEFS_DIR
72 #define PIPEFS_DIR  "/var/lib/nfs/rpc_pipefs/"
73 #endif
74
75 #ifndef NFSD_DIR
76 #define NFSD_DIR  "/proc/net/rpc"
77 #endif
78
79 #ifndef NFS4NOBODY_USER
80 #define NFS4NOBODY_USER "nobody"
81 #endif
82
83 #ifndef NFS4NOBODY_GROUP
84 #define NFS4NOBODY_GROUP "nobody"
85 #endif
86
87 /* From Niels */
88 #define CONF_SAVE(w, f) do {                    \
89         char *p = f;                            \
90         if (p != NULL)                          \
91                 (w) = p;                        \
92 } while (0)
93
94 #define IC_IDNAME 1
95 #define IC_NAMEID 2
96 struct idmap_client {
97         int                        ic_fd;
98         int                        ic_dirfd;
99         char                       ic_clid[30];
100         char                       ic_path[PATH_MAX];
101         int                        ic_scanned;
102         struct event               ic_event;
103         char                      *ic_id;
104         short                      ic_which;
105         TAILQ_ENTRY(idmap_client)  ic_next;
106 };
107
108 TAILQ_HEAD(idmap_clientq, idmap_client);
109
110 static void dirscancb(int, short, void *);
111 static void clntscancb(int, short, void *);
112 static void svrreopen(int, short, void *);
113 static int  nfsopen(struct idmap_client *);
114 static void nfscb(int, short, void *);
115 static void nfsdcb(int, short, void *);
116 static int  validateascii(char *, u_int32_t);
117 static int  addfield(char **, ssize_t *, char *);
118 static int  getfield(char **, char *, size_t);
119
120 static void imconv(struct idmap_client *, struct idmap_msg *);
121 static void idtonameres(struct idmap_msg *);
122 static void nametoidres(struct idmap_msg *);
123
124 static int nfsdopen(char *);
125 static int nfsdopenone(struct idmap_client *, short, char *);
126 static void nfsdreopen(void);
127
128 size_t  strlcat(char *, const char *, size_t);
129 size_t  strlcpy(char *, const char *, size_t);
130 ssize_t atomicio(ssize_t (*)(), int, void *, size_t);
131 void    mydaemon(int, int);
132 void    release_parent();
133
134 static int verbose = 0;
135 static char pipefsdir[PATH_MAX];
136 static char *nobodyuser, *nobodygroup;
137 static uid_t nobodyuid;
138 static gid_t nobodygid;
139 static struct idmap_client nfsd_ic[2];
140
141 /* Used by cfg.c */
142 char *conf_path;
143
144 int
145 main(int argc, char **argv)
146 {
147         int fd = 0, opt, fg = 0, nfsdret = -1;
148         struct idmap_clientq icq;
149         struct event rootdirev, clntdirev, svrdirev;
150         struct event initialize;
151         struct passwd *pw;
152         struct group *gr;
153         struct stat sb;
154         char *xpipefsdir = NULL;
155         int serverstart = 1, clientstart = 1;
156
157         conf_path = _PATH_IDMAPDCONF;
158         nobodyuser = NFS4NOBODY_USER;
159         nobodygroup = NFS4NOBODY_GROUP;
160         strlcpy(pipefsdir, PIPEFS_DIR, sizeof(pipefsdir));
161
162 #define GETOPTSTR "vfd:p:U:G:c:CS"
163         opterr=0; /* Turn off error messages */
164         while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) {
165                 if (opt == 'c')
166                         conf_path = optarg;
167                 if (opt == '?') {
168                         if (strchr(GETOPTSTR, optopt))
169                                 errx(1, "'-%c' option requires an argument.", optopt);
170                         else
171                                 errx(1, "'-%c' is an invalid argument.", optopt);
172                 }
173         }
174         optind = 1;
175
176         if (stat(conf_path, &sb) == -1 && (errno == ENOENT || errno == EACCES)) {
177                 warn("Skipping configuration file \"%s\"", conf_path);
178         } else {
179                 conf_init();
180                 verbose = conf_get_num("General", "Verbosity", 0);
181                 CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory"));
182                 if (xpipefsdir != NULL)
183                         strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir));
184                 CONF_SAVE(nobodyuser, conf_get_str("Mapping", "Nobody-User"));
185                 CONF_SAVE(nobodygroup, conf_get_str("Mapping", "Nobody-Group"));
186                 nfs4_init_name_mapping(conf_path);
187         }
188
189         while ((opt = getopt(argc, argv, GETOPTSTR)) != -1)
190                 switch (opt) {
191                 case 'v':
192                         verbose++;
193                         break;
194                 case 'f':
195                         fg = 1;
196                         break;
197                 case 'p':
198                         strlcpy(pipefsdir, optarg, sizeof(pipefsdir));
199                         break;
200                 case 'd':
201                 case 'U':
202                 case 'G':
203                         errx(1, "the -d, -U, and -G options have been removed;"
204                                 " please use the configuration file instead.");
205                 case 'C':
206                         serverstart = 0;
207                         break;
208                 case 'S':
209                         clientstart = 0;
210                         break;
211                 default:
212                         break;
213                 }
214
215         if (!serverstart && !clientstart)
216                 errx(1, "it is illegal to specify both -C and -S");
217
218         strncat(pipefsdir, "/nfs", sizeof(pipefsdir));
219
220         if ((pw = getpwnam(nobodyuser)) == NULL)
221                 errx(1, "Could not find user \"%s\"", nobodyuser);
222         nobodyuid = pw->pw_uid;
223
224         if ((gr = getgrnam(nobodygroup)) == NULL)
225                 errx(1, "Could not find group \"%s\"", nobodygroup);
226         nobodygid = gr->gr_gid;
227
228         if (!fg)
229                 mydaemon(0, 0);
230
231         event_init();
232
233         if (serverstart)
234                 nfsdret = nfsdopen(NFSD_DIR);
235
236         if (clientstart) {
237                 struct timeval now = {
238                         .tv_sec = 0,
239                         .tv_usec = 0,
240                 };
241
242                 if ((fd = open(pipefsdir, O_RDONLY)) == -1)
243                         err(1, "open(%s)", pipefsdir);
244
245                 if (fcntl(fd, F_SETSIG, SIGUSR1) == -1)
246                         err(1, "fcntl(%s)", pipefsdir);
247                 if (fcntl(fd, F_NOTIFY,
248                         DN_CREATE | DN_DELETE | DN_MODIFY | DN_MULTISHOT) == -1)
249                         err(1, "fcntl(%s)", pipefsdir);
250
251                 TAILQ_INIT(&icq);
252
253                 /* These events are persistent */
254                 signal_set(&rootdirev, SIGUSR1, dirscancb, &icq);
255                 signal_add(&rootdirev, NULL);
256                 signal_set(&clntdirev, SIGUSR2, clntscancb, &icq);
257                 signal_add(&clntdirev, NULL);
258                 signal_set(&svrdirev, SIGHUP, svrreopen, NULL);
259                 signal_add(&svrdirev, NULL);
260
261                 /* Fetch current state */
262                 /* (Delay till start of event_dispatch to avoid possibly losing
263                  * a SIGUSR1 between here and the call to event_dispatch().) */
264                 evtimer_set(&initialize, dirscancb, &icq);
265                 evtimer_add(&initialize, &now);
266         }
267
268         if (nfsdret != 0 && fd == 0)
269                 errx(1, "Neither NFS client nor NFSd found");
270
271         release_parent();
272
273         if (event_dispatch() < 0)
274                 errx(1, "event_dispatch: returns errno %d (%s)", errno, strerror(errno));
275         /* NOTREACHED */
276         return 1;
277 }
278
279 static void
280 dirscancb(int fd, short which, void *data)
281 {
282         int nent, i;
283         struct dirent **ents;
284         struct idmap_client *ic;
285         char path[PATH_MAX];
286         struct idmap_clientq *icq = data;
287
288         nent = scandir(pipefsdir, &ents, NULL, alphasort);
289         if (nent == -1) {
290                 warn("scandir(%s)", pipefsdir);
291                 return;
292         }
293
294         for (i = 0;  i < nent; i++) {
295                 if (ents[i]->d_reclen > 4 &&
296                     strncmp(ents[i]->d_name, "clnt", 4) == 0) {
297                         TAILQ_FOREACH(ic, icq, ic_next)
298                             if (strcmp(ents[i]->d_name + 4, ic->ic_clid) == 0)
299                                     break;
300                         if (ic != NULL)
301                                 goto next;
302
303                         if ((ic = calloc(1, sizeof(*ic))) == NULL)
304                                 return;
305                         strlcpy(ic->ic_clid, ents[i]->d_name + 4,
306                             sizeof(ic->ic_clid));
307                         path[0] = '\0';
308                         snprintf(path, sizeof(path), "%s/%s",
309                             pipefsdir, ents[i]->d_name);
310
311                         if ((ic->ic_dirfd = open(path, O_RDONLY, 0)) == -1) {
312                                 warn("open(%s)", path);
313                                 free(ic);
314                                 return;
315                         }
316
317                         strlcat(path, "/idmap", sizeof(path));
318                         strlcpy(ic->ic_path, path, sizeof(ic->ic_path));
319
320                         if (verbose > 0)
321                                 warnx("New client: %s", ic->ic_clid);
322
323                         if (nfsopen(ic) == -1) {
324                                 close(ic->ic_dirfd);
325                                 free(ic);
326                                 return;
327                         }
328
329                         ic->ic_id = "Client";
330
331                         TAILQ_INSERT_TAIL(icq, ic, ic_next);
332
333                 next:
334                         ic->ic_scanned = 1;
335                 }
336         }
337
338         TAILQ_FOREACH(ic, icq, ic_next) {
339                 if (!ic->ic_scanned) {
340                         event_del(&ic->ic_event);
341                         close(ic->ic_fd);
342                         close(ic->ic_dirfd);
343                         TAILQ_REMOVE(icq, ic, ic_next);
344                         if (verbose > 0) {
345                                 warnx("Stale client: %s", ic->ic_clid);
346                                 warnx("\t-> closed %s", ic->ic_path);
347                         }
348                         free(ic);
349                 } else
350                         ic->ic_scanned = 0;
351         }
352         return;
353 }
354
355 static void
356 svrreopen(int fd, short which, void *data)
357 {
358         nfsdreopen();
359 }
360
361 static void
362 clntscancb(int fd, short which, void *data)
363 {
364         struct idmap_clientq *icq = data;
365         struct idmap_client *ic;
366
367         TAILQ_FOREACH(ic, icq, ic_next)
368                 if (ic->ic_fd == -1 && nfsopen(ic) == -1) {
369                         close(ic->ic_dirfd);
370                         TAILQ_REMOVE(icq, ic, ic_next);
371                         free(ic);
372                 }
373 }
374
375 static void
376 nfsdcb(int fd, short which, void *data)
377 {
378         struct idmap_client *ic = data;
379         struct idmap_msg im;
380         u_char buf[IDMAP_MAXMSGSZ + 1];
381         size_t len, bsiz;
382         char *bp, typebuf[IDMAP_MAXMSGSZ],
383                 buf1[IDMAP_MAXMSGSZ], authbuf[IDMAP_MAXMSGSZ], *p;
384
385         if (which != EV_READ)
386                 goto out;
387
388         if ((len = read(ic->ic_fd, buf, sizeof(buf))) == -1) {
389                 warnx("nfsdcb: read(%s) failed: errno %d (%s)",
390                         ic->ic_path, errno, strerror(errno));
391                 goto out;
392         }
393
394         /* Get rid of newline and terminate buffer*/
395         buf[len - 1] = '\0';
396         bp = buf;
397
398         memset(&im, 0, sizeof(im));
399
400         /* Authentication name -- ignored for now*/
401         if (getfield(&bp, authbuf, sizeof(authbuf)) == -1) {
402                 warnx("nfsdcb: bad authentication name in upcall\n");
403                 return;
404         }
405         if (getfield(&bp, typebuf, sizeof(typebuf)) == -1) {
406                 warnx("nfsdcb: bad type in upcall\n");
407                 return;
408         }
409         if (verbose > 0)
410                 warnx("nfsdcb: authbuf=%s authtype=%s", authbuf, typebuf);
411
412         im.im_type = strcmp(typebuf, "user") == 0 ?
413                 IDMAP_TYPE_USER : IDMAP_TYPE_GROUP;
414
415         switch (ic->ic_which) {
416         case IC_NAMEID:
417                 im.im_conv = IDMAP_CONV_NAMETOID;
418                 if (getfield(&bp, im.im_name, sizeof(im.im_name)) == -1) {
419                         warnx("nfsdcb: bad name in upcall\n");
420                         return;
421                 }
422                 break;
423         case IC_IDNAME:
424                 im.im_conv = IDMAP_CONV_IDTONAME;
425                 if (getfield(&bp, buf1, sizeof(buf1)) == -1) {
426                         warnx("nfsdcb: bad id in upcall\n");
427                         return;
428                 }
429                 if ((im.im_id = strtoul(buf1, (char **)NULL, 10)) == ULONG_MAX &&
430                     errno == ERANGE) {
431                         warnx("nfsdcb: id '%s' too big!\n", buf1);
432                         return;
433                 }
434
435                 break;
436         default:
437                 warnx("Unknown which type %d", ic->ic_which);
438                 return;
439         }
440
441         imconv(ic, &im);
442
443         buf[0] = '\0';
444         bp = buf;
445         bsiz = sizeof(buf);
446
447         /* Authentication name */
448         addfield(&bp, &bsiz, authbuf);
449
450         switch (ic->ic_which) {
451         case IC_NAMEID:
452                 /* Type */
453                 p = im.im_type == IDMAP_TYPE_USER ? "user" : "group";
454                 addfield(&bp, &bsiz, p);
455                 /* Name */
456                 addfield(&bp, &bsiz, im.im_name);
457 #define NFSD_EXPIRY 300 /* seconds */
458                 /* expiry */
459                 snprintf(buf1, sizeof(buf1), "%lu", time(NULL) + NFSD_EXPIRY);
460                 addfield(&bp, &bsiz, buf1);
461                 /* ID */
462                 snprintf(buf1, sizeof(buf1), "%u", im.im_id);
463                 addfield(&bp, &bsiz, buf1);
464
465                 //if (bsiz == sizeof(buf)) /* XXX */
466
467                 bp[-1] = '\n';
468
469                 break;
470         case IC_IDNAME:
471                 /* Type */
472                 p = im.im_type == IDMAP_TYPE_USER ? "user" : "group";
473                 addfield(&bp, &bsiz, p);
474                 /* ID */
475                 snprintf(buf1, sizeof(buf1), "%u", im.im_id);
476                 addfield(&bp, &bsiz, buf1);
477                 /* expiry */
478                 snprintf(buf1, sizeof(buf1), "%lu", time(NULL) + NFSD_EXPIRY);
479                 addfield(&bp, &bsiz, buf1);
480                 /* Name */
481                 addfield(&bp, &bsiz, im.im_name);
482
483                 bp[-1] = '\n';
484
485                 break;
486         default:
487                 warnx("Unknown which type %d", ic->ic_which);
488                 return;
489         }
490
491         bsiz = sizeof(buf) - bsiz;
492
493         if (atomicio(write, ic->ic_fd, buf, bsiz) != bsiz)
494                 warnx("nfsdcb: write(%s) failed: errno %d (%s)",
495                         ic->ic_path, errno, strerror(errno));
496
497 out:
498         event_add(&ic->ic_event, NULL);
499 }
500
501 static void
502 imconv(struct idmap_client *ic, struct idmap_msg *im)
503 {
504         switch (im->im_conv) {
505         case IDMAP_CONV_IDTONAME:
506                 idtonameres(im);
507                 if (verbose > 1)
508                         warnx("%s %s: (%s) id \"%d\" -> name \"%s\"",
509                             ic->ic_id, ic->ic_clid,
510                             im->im_type == IDMAP_TYPE_USER ? "user" : "group",
511                             im->im_id, im->im_name);
512                 break;
513         case IDMAP_CONV_NAMETOID:
514                 if (validateascii(im->im_name, sizeof(im->im_name)) == -1) {
515                         im->im_status |= IDMAP_STATUS_INVALIDMSG;
516                         return;
517                 }
518                 nametoidres(im);
519                 if (verbose > 1)
520                         warnx("%s %s: (%s) name \"%s\" -> id \"%d\"",
521                             ic->ic_id, ic->ic_clid,
522                             im->im_type == IDMAP_TYPE_USER ? "user" : "group",
523                             im->im_name, im->im_id);
524                 break;
525         default:
526                 warnx("Invalid conversion type (%d) in message", im->im_conv);
527                 im->im_status |= IDMAP_STATUS_INVALIDMSG;
528                 break;
529         }
530 }
531
532 static void
533 nfscb(int fd, short which, void *data)
534 {
535         struct idmap_client *ic = data;
536         struct idmap_msg im;
537
538         if (which != EV_READ)
539                 goto out;
540
541         if (atomicio(read, ic->ic_fd, &im, sizeof(im)) != sizeof(im)) {
542                 if (verbose > 0)
543                         warn("read(%s)", ic->ic_path);
544                 if (errno == EPIPE)
545                         return;
546                 goto out;
547         }
548
549         imconv(ic, &im);
550
551         if (atomicio(write, ic->ic_fd, &im, sizeof(im)) != sizeof(im))
552                 warn("write(%s)", ic->ic_path);
553 out:
554         event_add(&ic->ic_event, NULL);
555 }
556
557 static void
558 nfsdreopen_one(struct idmap_client *ic)
559 {
560         int fd;
561
562         if (verbose > 0)
563                 warnx("ReOpening %s", ic->ic_path);
564         if ((fd = open(ic->ic_path, O_RDWR, 0)) != -1) {
565                 if (ic->ic_fd != -1)
566                         close(ic->ic_fd);
567                 ic->ic_event.ev_fd = ic->ic_fd = fd;
568                 if ((ic->ic_event.ev_flags & EVLIST_INIT) == 0) {
569                         event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfsdcb, ic);
570                         event_add(&ic->ic_event, NULL);
571                 }
572         } else {
573                 warnx("nfsdreopen: Opening '%s' failed: errno %d (%s)",
574                         ic->ic_path, errno, strerror(errno));
575         }
576 }
577
578 /*
579  * Note: nfsdreopen assumes nfsdopen has already been called
580  */
581 static void
582 nfsdreopen()
583 {
584         nfsdreopen_one(&nfsd_ic[IC_NAMEID]);
585         nfsdreopen_one(&nfsd_ic[IC_IDNAME]);
586         return;
587 }
588
589 static int
590 nfsdopen(char *path)
591 {
592         return ((nfsdopenone(&nfsd_ic[0], IC_NAMEID, path) == 0 &&
593                     nfsdopenone(&nfsd_ic[1], IC_IDNAME, path) == 0) ? 0 : -1);
594 }
595
596 static int
597 nfsdopenone(struct idmap_client *ic, short which, char *path)
598 {
599         char *whichstr;
600
601         whichstr = which == IC_IDNAME ? "idtoname" : "nametoid";
602         snprintf(ic->ic_path, sizeof(ic->ic_path),
603                 "%s/nfs4.%s/channel", path, whichstr);
604         if ((ic->ic_fd = open(ic->ic_path, O_RDWR, 0)) == -1) {
605                 if (verbose > 0)
606                         warnx("Opening %s failed: errno %d (%s)",
607                                 ic->ic_path, errno, strerror(errno));
608                 return (-1);
609         }
610
611         event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfsdcb, ic);
612         event_add(&ic->ic_event, NULL);
613
614         ic->ic_which = which;
615         ic->ic_id = "Server";
616         strlcpy(ic->ic_clid, "Server", strlen("Server"));
617
618         if (verbose > 0)
619                 warnx("Opened %s", ic->ic_path);
620
621         return (0);
622 }
623
624 static int
625 nfsopen(struct idmap_client *ic)
626 {
627         if ((ic->ic_fd = open(ic->ic_path, O_RDWR, 0)) == -1) {
628                 switch (errno) {
629                 case ENOENT:
630                         fcntl(ic->ic_dirfd, F_SETSIG, SIGUSR2);
631                         fcntl(ic->ic_dirfd, F_NOTIFY,
632                             DN_CREATE | DN_DELETE | DN_MULTISHOT);
633                         break;
634                 default:
635                         warn("open(%s)", ic->ic_path);
636                         return (-1);
637                 }
638         } else {
639                 event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfscb, ic);
640                 event_add(&ic->ic_event, NULL);
641                 fcntl(ic->ic_dirfd, F_SETSIG, 0);
642                 fcntl(ic->ic_dirfd, F_NOTIFY, 0);
643                 if (verbose > 0)
644                         warnx("Opened %s", ic->ic_path);
645         }
646
647         return (0);
648 }
649
650 static int write_name(char *dest, char *localname, char *domain, size_t len)
651 {
652         if (strlen(localname) + 1 + strlen(domain) + 1 > len) {
653                 return -ENOMEM; /* XXX: Is there an -ETOOLONG? */
654         }
655         strcpy(dest, localname);
656         strcat(dest, "@");
657         strcat(dest, domain);
658         return 0;
659 }
660
661 static void
662 idtonameres(struct idmap_msg *im)
663 {
664         char domain[NFS4_MAX_DOMAIN_LEN];
665         int ret = 0;
666
667         ret = nfs4_get_default_domain(NULL, domain, sizeof(domain));
668         switch (im->im_type) {
669         case IDMAP_TYPE_USER:
670                 ret = nfs4_uid_to_name(im->im_id, domain, im->im_name,
671                                 sizeof(im->im_name));
672                 if (ret)
673                         write_name(im->im_name, nobodyuser, domain,
674                                         sizeof(im->im_name));
675                 break;
676         case IDMAP_TYPE_GROUP:
677                 ret = nfs4_gid_to_name(im->im_id, domain, im->im_name,
678                                 sizeof(im->im_name));
679                 if (ret)
680                         write_name(im->im_name, nobodygroup, domain,
681                                         sizeof(im->im_name));
682                 break;
683         }
684         /* XXX Hack? would rather return failure instead of writing nobody
685          * as above, but kernel seems not to deal well with that as of
686          * 2.6.8-rc3. */
687         im->im_status = IDMAP_STATUS_SUCCESS;
688 }
689
690 static void
691 nametoidres(struct idmap_msg *im)
692 {
693         int ret = 0;
694
695         switch (im->im_type) {
696         case IDMAP_TYPE_USER:
697                 ret = nfs4_name_to_uid(im->im_name, &im->im_id);
698                 if (ret)
699                         im->im_id = nobodyuid;
700                 break;
701         case IDMAP_TYPE_GROUP:
702                 ret = nfs4_name_to_gid(im->im_name, &im->im_id);
703                 if (ret)
704                         im->im_id = nobodygid;
705                 break;
706         }
707         /* XXX Hack? would rather return failure instead of writing nobody
708          * as above, but kernel seems not to deal well with that as of
709          * 2.6.8-rc3. */
710         im->im_status = IDMAP_STATUS_SUCCESS;
711 }
712
713 static int
714 validateascii(char *string, u_int32_t len)
715 {
716         int i;
717
718         for (i = 0; i < len; i++) {
719                 if (string[i] == '\0')
720                         break;
721
722                 if (string[i] & 0x80)
723                         return (-1);
724         }
725
726         if (string[i] != '\0')
727                 return (-1);
728
729         return (i + 1);
730 }
731
732 static int
733 addfield(char **bpp, ssize_t *bsizp, char *fld)
734 {
735         char ch, *bp = *bpp;
736         ssize_t bsiz = *bsizp;
737
738         while ((ch = *fld++) != '\0' && bsiz > 0) {
739                 switch(ch) {
740                 case ' ':
741                 case '\t':
742                 case '\n':
743                 case '\\':
744                         if (bsiz >= 4) {
745                                 bp += snprintf(bp, bsiz, "\\%03o", ch);
746                                 bsiz -= 4;
747                         }
748                         break;
749                 default:
750                         *bp++ = ch;
751                         bsiz--;
752                         break;
753                 }
754         }
755
756         if (bsiz < 1 || ch != '\0')
757                 return (-1);
758
759         *bp++ = ' ';
760         bsiz--;
761
762         *bpp = bp;
763         *bsizp = bsiz;
764
765         return (0);
766 }
767
768 static int
769 getfield(char **bpp, char *fld, size_t fldsz)
770 {
771         char *bp;
772         u_int val, n;
773
774         while ((bp = strsep(bpp, " ")) != NULL && bp[0] == '\0')
775                 ;
776
777         if (bp == NULL || bp[0] == '\0' || bp[0] == '\n')
778                 return (-1);
779
780         while (*bp != '\0' && fldsz > 1) {
781                 if (*bp == '\\') {
782                         if ((n = sscanf(bp, "\\%03o", &val)) != 1)
783                                 return (-1);
784                         if (val > (char)-1)
785                                 return (-1);
786                         *fld++ = (char)val;
787                         bp += 4;
788                 } else {
789                         *fld++ = *bp;
790                         bp++;
791                 }
792                 fldsz--;
793         }
794
795         if (*bp != '\0')
796                 return (-1);
797         *fld = '\0';
798
799         return (0);
800 }
801 /*
802  * mydaemon creates a pipe between the partent and child
803  * process. The parent process will wait until the
804  * child dies or writes a '1' on the pipe signaling
805  * that it started successfully.
806  */
807 int pipefds[2] = { -1, -1};
808
809 void
810 mydaemon(int nochdir, int noclose)
811 {
812         int pid, status, tempfd, fdmax, filedes;
813
814         if (pipe(pipefds) < 0)
815                 err(1, "mydaemon: pipe() failed: errno %d (%s)\n", errno, strerror(errno));
816
817         if ((pid = fork ()) < 0)
818                 err(1, "mydaemon: fork() failed: errno %d (%s)\n", errno, strerror(errno));
819
820         if (pid != 0) {
821                 /*
822                  * Parent. Wait for status from child.
823                  */
824                 close(pipefds[1]);
825                 if (read(pipefds[0], &status, 1) != 1)
826                         exit(1);
827                 exit (0);
828         }
829         /* Child.       */
830         close(pipefds[0]);
831         setsid ();
832         if (nochdir == 0) {
833                 if (chdir ("/") == -1)
834                         err(1, "mydaemon: chdir() failed: errno %d (%s)\n", errno, strerror(errno));
835         }
836
837         while (pipefds[1] <= 2) {
838                 pipefds[1] = dup(pipefds[1]);
839                 if (pipefds[1] < 0)
840                         err(1, "mydaemon: dup() failed: errno %d (%s)\n", errno, strerror(errno));
841         }
842
843         if (noclose == 0) {
844                 tempfd = open("/dev/null", O_RDWR);
845                 close(0); dup2(tempfd, 0);
846                 close(1); dup2(tempfd, 1);
847                 close(2); dup2(tempfd, 2);
848                 fdmax = sysconf (_SC_OPEN_MAX);
849                 for (filedes = 3; filedes < fdmax; filedes++)
850                         if (filedes != pipefds[1])
851                                 close (filedes);
852         }
853
854         return;
855 }
856 void
857 release_parent()
858 {
859         int status;
860
861         if (pipefds[1] > 0) {
862                 write(pipefds[1], &status, 1);
863                 close(pipefds[1]);
864                 pipefds[1] = -1;
865         }
866 }