Merge branch 'vendor/FILE'
[dragonfly.git] / contrib / bind / lib / bind / irs / irpmarshall.c
1 /*
2  * Copyright(c) 1989, 1993, 1995
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 /*
35  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
36  * Portions Copyright (c) 1996 by Internet Software Consortium.
37  *
38  * Permission to use, copy, modify, and distribute this software for any
39  * purpose with or without fee is hereby granted, provided that the above
40  * copyright notice and this permission notice appear in all copies.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
43  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
44  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
45  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
46  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
47  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
48  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49  */
50
51 #if defined(LIBC_SCCS) && !defined(lint)
52 static const char rcsid[] = "$Id: irpmarshall.c,v 1.7 2006/03/09 23:57:56 marka Exp $";
53 #endif /* LIBC_SCCS and not lint */
54
55 #if 0
56
57 Check values are in approrpriate endian order.
58
59 Double check memory allocations on unmarhsalling
60
61 #endif
62
63
64 /* Extern */
65
66 #include "port_before.h"
67
68 #include <sys/types.h>
69 #include <sys/socket.h>
70
71 #include <netinet/in.h>
72 #include <arpa/inet.h>
73 #include <arpa/nameser.h>
74
75 #include <stdio.h>
76 #include <ctype.h>
77 #include <pwd.h>
78 #include <stdlib.h>
79 #include <string.h>
80 #include <syslog.h>
81 #include <utmp.h>
82 #include <unistd.h>
83 #include <assert.h>
84 #include <errno.h>
85
86 #include <irs.h>
87 #include <isc/memcluster.h>
88 #include <isc/irpmarshall.h>
89
90 #include "port_after.h"
91
92
93 #ifndef HAVE_STRNDUP
94 static char    *strndup(const char *str, size_t len);
95 #endif
96
97 static char   **splitarray(const char *buffer, const char *buffend, char delim);
98 static int      joinarray(char * const * argv, char *buffer, char delim);
99 static char    *getfield(char **res, size_t reslen, char **buffer, char delim);
100 static size_t   joinlength(char * const *argv);
101 static void     free_array(char **argv, size_t entries);
102
103 #define ADDR_T_STR(x) (x == AF_INET ? "AF_INET" :\
104                        (x == AF_INET6 ? "AF_INET6" : "UNKNOWN"))
105
106 #define MAXPADDRSIZE (sizeof "255.255.255.255" + 1)
107
108 static char COMMA = ',';
109
110 static const char *COMMASTR = ",";
111 static const char *COLONSTR = ":";
112
113
114
115 /* See big comment at bottom of irpmarshall.h for description. */
116
117
118 #ifdef WANT_IRS_PW
119 /* +++++++++++++++++++++++++ struct passwd +++++++++++++++++++++++++ */
120
121 /*%
122  * int irp_marshall_pw(const struct passwd *pw, char **buffer, size_t *len)
123  *
124  * notes: \li
125  *
126  *      See irpmarshall.h
127  *
128  * return: \li
129  *
130  *      0 on sucess, -1 on failure.
131  *
132  */
133
134 int
135 irp_marshall_pw(const struct passwd *pw, char **buffer, size_t *len) {
136         size_t need = 1 ;               /*%< for null byte */
137         char pwUid[24];
138         char pwGid[24];
139         char pwChange[24];
140         char pwExpire[24];
141         const char *pwClass;
142         const char *fieldsep = COLONSTR;
143
144         if (pw == NULL || len == NULL) {
145                 errno = EINVAL;
146                 return (-1);
147         }
148
149         sprintf(pwUid, "%ld", (long)pw->pw_uid);
150         sprintf(pwGid, "%ld", (long)pw->pw_gid);
151
152 #ifdef HAVE_PW_CHANGE
153         sprintf(pwChange, "%ld", (long)pw->pw_change);
154 #else
155         pwChange[0] = '0';
156         pwChange[1] = '\0';
157 #endif
158
159 #ifdef HAVE_PW_EXPIRE
160         sprintf(pwExpire, "%ld", (long)pw->pw_expire);
161 #else
162         pwExpire[0] = '0';
163         pwExpire[1] = '\0';
164 #endif
165
166 #ifdef HAVE_PW_CLASS
167         pwClass = pw->pw_class;
168 #else
169         pwClass = "";
170 #endif
171
172         need += strlen(pw->pw_name)     + 1; /*%< one for fieldsep */
173         need += strlen(pw->pw_passwd)   + 1;
174         need += strlen(pwUid)           + 1;
175         need += strlen(pwGid)           + 1;
176         need += strlen(pwClass)         + 1;
177         need += strlen(pwChange)        + 1;
178         need += strlen(pwExpire)        + 1;
179         need += strlen(pw->pw_gecos)    + 1;
180         need += strlen(pw->pw_dir)      + 1;
181         need += strlen(pw->pw_shell)    + 1;
182
183         if (buffer == NULL) {
184                 *len = need;
185                 return (0);
186         }
187
188         if (*buffer != NULL && need > *len) {
189                 errno = EINVAL;
190                 return (-1);
191         }
192
193         if (*buffer == NULL) {
194                 need += 2;              /*%< for CRLF */
195                 *buffer = memget(need);
196                 if (*buffer == NULL) {
197                         errno = ENOMEM;
198                         return (-1);
199                 }
200
201                 *len = need;
202         }
203
204         strcpy(*buffer, pw->pw_name);           strcat(*buffer, fieldsep);
205         strcat(*buffer, pw->pw_passwd);         strcat(*buffer, fieldsep);
206         strcat(*buffer, pwUid);                 strcat(*buffer, fieldsep);
207         strcat(*buffer, pwGid);                 strcat(*buffer, fieldsep);
208         strcat(*buffer, pwClass);               strcat(*buffer, fieldsep);
209         strcat(*buffer, pwChange);              strcat(*buffer, fieldsep);
210         strcat(*buffer, pwExpire);              strcat(*buffer, fieldsep);
211         strcat(*buffer, pw->pw_gecos);          strcat(*buffer, fieldsep);
212         strcat(*buffer, pw->pw_dir);            strcat(*buffer, fieldsep);
213         strcat(*buffer, pw->pw_shell);          strcat(*buffer, fieldsep);
214
215         return (0);
216 }
217
218 /*%
219  * int irp_unmarshall_pw(struct passwd *pw, char *buffer)
220  *
221  * notes: \li
222  *
223  *      See irpmarshall.h
224  *
225  * return: \li
226  *
227  *      0 on success, -1 on failure
228  *
229  */
230
231 int
232 irp_unmarshall_pw(struct passwd *pw, char *buffer) {
233         char *name, *pass, *class, *gecos, *dir, *shell;
234         uid_t pwuid;
235         gid_t pwgid;
236         time_t pwchange;
237         time_t pwexpire;
238         char *p;
239         long t;
240         char tmpbuf[24];
241         char *tb = &tmpbuf[0];
242         char fieldsep = ':';
243         int myerrno = EINVAL;
244
245         name = pass = class = gecos = dir = shell = NULL;
246         p = buffer;
247
248         /* pw_name field */
249         name = NULL;
250         if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0) {
251                 goto error;
252         }
253
254         /* pw_passwd field */
255         pass = NULL;
256         if (getfield(&pass, 0, &p, fieldsep) == NULL) { /*%< field can be empty */
257                 goto error;
258         }
259
260
261         /* pw_uid field */
262         tb = tmpbuf;
263         if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
264             strlen(tb) == 0) {
265                 goto error;
266         }
267         t = strtol(tmpbuf, &tb, 10);
268         if (*tb) {
269                 goto error;     /*%< junk in value */
270         }
271         pwuid = (uid_t)t;
272         if ((long) pwuid != t) {        /*%< value must have been too big. */
273                 goto error;
274         }
275
276
277
278         /* pw_gid field */
279         tb = tmpbuf;
280         if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
281             strlen(tb) == 0) {
282                 goto error;
283         }
284         t = strtol(tmpbuf, &tb, 10);
285         if (*tb) {
286                 goto error;     /*%< junk in value */
287         }
288         pwgid = (gid_t)t;
289         if ((long)pwgid != t) { /*%< value must have been too big. */
290                 goto error;
291         }
292
293
294
295         /* pw_class field */
296         class = NULL;
297         if (getfield(&class, 0, &p, fieldsep) == NULL) {
298                 goto error;
299         }
300
301
302
303         /* pw_change field */
304         tb = tmpbuf;
305         if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
306             strlen(tb) == 0) {
307                 goto error;
308         }
309         t = strtol(tmpbuf, &tb, 10);
310         if (*tb) {
311                 goto error;     /*%< junk in value */
312         }
313         pwchange = (time_t)t;
314         if ((long)pwchange != t) {      /*%< value must have been too big. */
315                 goto error;
316         }
317
318
319
320         /* pw_expire field */
321         tb = tmpbuf;
322         if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
323             strlen(tb) == 0) {
324                 goto error;
325         }
326         t = strtol(tmpbuf, &tb, 10);
327         if (*tb) {
328                 goto error;     /*%< junk in value */
329         }
330         pwexpire = (time_t)t;
331         if ((long) pwexpire != t) {     /*%< value must have been too big. */
332                 goto error;
333         }
334
335
336
337         /* pw_gecos field */
338         gecos = NULL;
339         if (getfield(&gecos, 0, &p, fieldsep) == NULL) {
340                 goto error;
341         }
342
343
344
345         /* pw_dir field */
346         dir = NULL;
347         if (getfield(&dir, 0, &p, fieldsep) == NULL) {
348                 goto error;
349         }
350
351
352
353         /* pw_shell field */
354         shell = NULL;
355         if (getfield(&shell, 0, &p, fieldsep) == NULL) {
356                 goto error;
357         }
358
359
360
361         pw->pw_name = name;
362         pw->pw_passwd = pass;
363         pw->pw_uid = pwuid;
364         pw->pw_gid = pwgid;
365         pw->pw_gecos = gecos;
366         pw->pw_dir = dir;
367         pw->pw_shell = shell;
368
369 #ifdef HAVE_PW_CHANGE
370         pw->pw_change = pwchange;
371 #endif
372 #ifdef HAVE_PW_CLASS
373         pw->pw_class = class;
374 #endif
375 #ifdef HAVE_PW_EXPIRE
376         pw->pw_expire = pwexpire;
377 #endif
378
379         return (0);
380
381  error:
382         errno = myerrno;
383
384         if (name != NULL) free(name);
385         if (pass != NULL) free(pass);
386         if (gecos != NULL) free(gecos);
387         if (dir != NULL) free(dir);
388         if (shell != NULL) free(shell);
389
390         return (-1);
391 }
392
393 /* ------------------------- struct passwd ------------------------- */
394 #endif /* WANT_IRS_PW */
395 /* +++++++++++++++++++++++++ struct group +++++++++++++++++++++++++ */
396
397 /*%
398  * int irp_marshall_gr(const struct group *gr, char **buffer, size_t *len)
399  *
400  * notes: \li
401  *
402  *      See irpmarshall.h.
403  *
404  * return: \li
405  *
406  *      0 on success, -1 on failure
407  */
408
409 int
410 irp_marshall_gr(const struct group *gr, char **buffer, size_t *len) {
411         size_t need = 1;        /*%< for null byte */
412         char grGid[24];
413         const char *fieldsep = COLONSTR;
414
415         if (gr == NULL || len == NULL) {
416                 errno = EINVAL;
417                 return (-1);
418         }
419
420         sprintf(grGid, "%ld", (long)gr->gr_gid);
421
422         need += strlen(gr->gr_name) + 1;
423 #ifndef MISSING_GR_PASSWD
424         need += strlen(gr->gr_passwd) + 1;
425 #else
426         need++;
427 #endif
428         need += strlen(grGid) + 1;
429         need += joinlength(gr->gr_mem) + 1;
430
431         if (buffer == NULL) {
432                 *len = need;
433                 return (0);
434         }
435
436         if (*buffer != NULL && need > *len) {
437                 errno = EINVAL;
438                 return (-1);
439         }
440
441         if (*buffer == NULL) {
442                 need += 2;              /*%< for CRLF */
443                 *buffer = memget(need);
444                 if (*buffer == NULL) {
445                         errno = ENOMEM;
446                         return (-1);
447                 }
448
449                 *len = need;
450         }
451
452         strcpy(*buffer, gr->gr_name);           strcat(*buffer, fieldsep);
453 #ifndef MISSING_GR_PASSWD
454         strcat(*buffer, gr->gr_passwd);
455 #endif
456         strcat(*buffer, fieldsep);
457         strcat(*buffer, grGid);                 strcat(*buffer, fieldsep);
458         joinarray(gr->gr_mem, *buffer, COMMA) ; strcat(*buffer, fieldsep);
459
460         return (0);
461 }
462
463 /*%
464  * int irp_unmarshall_gr(struct group *gr, char *buffer)
465  *
466  * notes: \li
467  *
468  *      See irpmarshall.h
469  *
470  * return: \li
471  *
472  *      0 on success and -1 on failure.
473  *
474  */
475
476 int
477 irp_unmarshall_gr(struct group *gr, char *buffer) {
478         char *p, *q;
479         gid_t grgid;
480         long t;
481         char *name = NULL;
482         char *pass = NULL;
483         char **members = NULL;
484         char tmpbuf[24];
485         char *tb;
486         char fieldsep = ':';
487         int myerrno = EINVAL;
488
489         if (gr == NULL || buffer == NULL) {
490                 errno = EINVAL;
491                 return (-1);
492         }
493
494         p = buffer;
495
496         /* gr_name field */
497         name = NULL;
498         if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
499                 goto error;
500         }
501
502
503         /* gr_passwd field */
504         pass = NULL;
505         if (getfield(&pass, 0, &p, fieldsep) == NULL) {
506                 goto error;
507         }
508
509
510         /* gr_gid field */
511         tb = tmpbuf;
512         if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
513             strlen(tb) == 0U) {
514                 goto error;
515         }
516         t = strtol(tmpbuf, &tb, 10);
517         if (*tb) {
518                 goto error;     /*%< junk in value */
519         }
520         grgid = (gid_t)t;
521         if ((long) grgid != t) {        /*%< value must have been too big. */
522                 goto error;
523         }
524
525
526         /* gr_mem field. Member names are separated by commas */
527         q = strchr(p, fieldsep);
528         if (q == NULL) {
529                 goto error;
530         }
531         members = splitarray(p, q, COMMA);
532         if (members == NULL) {
533                 myerrno = errno;
534                 goto error;
535         }
536         p = q + 1;
537
538
539         gr->gr_name = name;
540 #ifndef MISSING_GR_PASSWD
541         gr->gr_passwd = pass;
542 #endif
543         gr->gr_gid = grgid;
544         gr->gr_mem = members;
545
546         return (0);
547
548  error:
549         errno = myerrno;
550
551         if (name != NULL) free(name);
552         if (pass != NULL) free(pass);
553
554         return (-1);
555 }
556
557
558 /* ------------------------- struct group ------------------------- */
559
560
561
562
563 /* +++++++++++++++++++++++++ struct servent +++++++++++++++++++++++++ */
564
565 /*%
566  * int irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len)
567  *
568  * notes: \li
569  *
570  *      See irpmarshall.h
571  *
572  * return: \li
573  *
574  *      0 on success, -1 on failure.
575  *
576  */
577
578 int
579 irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len) {
580         size_t need = 1;        /*%< for null byte */
581         char svPort[24];
582         const char *fieldsep = COLONSTR;
583         short realport;
584
585         if (sv == NULL || len == NULL) {
586                 errno = EINVAL;
587                 return (-1);
588         }
589
590         /* the int s_port field is actually a short in network order. We
591            want host order to make the marshalled data look correct */
592         realport = ntohs((short)sv->s_port);
593         sprintf(svPort, "%d", realport);
594
595         need += strlen(sv->s_name) + 1;
596         need += joinlength(sv->s_aliases) + 1;
597         need += strlen(svPort) + 1;
598         need += strlen(sv->s_proto) + 1;
599
600         if (buffer == NULL) {
601                 *len = need;
602                 return (0);
603         }
604
605         if (*buffer != NULL && need > *len) {
606                 errno = EINVAL;
607                 return (-1);
608         }
609
610         if (*buffer == NULL) {
611                 need += 2;              /*%< for CRLF */
612                 *buffer = memget(need);
613                 if (*buffer == NULL) {
614                         errno = ENOMEM;
615                         return (-1);
616                 }
617
618                 *len = need;
619         }
620
621         strcpy(*buffer, sv->s_name);            strcat(*buffer, fieldsep);
622         joinarray(sv->s_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
623         strcat(*buffer, svPort);                strcat(*buffer, fieldsep);
624         strcat(*buffer, sv->s_proto);           strcat(*buffer, fieldsep);
625
626         return (0);
627 }
628
629 /*%
630  * int irp_unmarshall_sv(struct servent *sv, char *buffer)
631  *
632  * notes: \li
633  *
634  *      See irpmarshall.h
635  *
636  * return: \li
637  *
638  *      0 on success, -1 on failure.
639  *
640  */
641
642 int
643 irp_unmarshall_sv(struct servent *sv, char *buffer) {
644         char *p, *q;
645         short svport;
646         long t;
647         char *name = NULL;
648         char *proto = NULL;
649         char **aliases = NULL;
650         char tmpbuf[24];
651         char *tb;
652         char fieldsep = ':';
653         int myerrno = EINVAL;
654
655         if (sv == NULL || buffer == NULL)
656                 return (-1);
657
658         p = buffer;
659
660
661         /* s_name field */
662         name = NULL;
663         if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
664                 goto error;
665         }
666
667
668         /* s_aliases field */
669         q = strchr(p, fieldsep);
670         if (q == NULL) {
671                 goto error;
672         }
673         aliases = splitarray(p, q, COMMA);
674         if (aliases == NULL) {
675                 myerrno = errno;
676                 goto error;
677         }
678         p = q + 1;
679
680
681         /* s_port field */
682         tb = tmpbuf;
683         if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
684             strlen(tb) == 0U) {
685                 goto error;
686         }
687         t = strtol(tmpbuf, &tb, 10);
688         if (*tb) {
689                 goto error;     /*%< junk in value */
690         }
691         svport = (short)t;
692         if ((long) svport != t) {       /*%< value must have been too big. */
693                 goto error;
694         }
695         svport = htons(svport);
696
697         /* s_proto field */
698         proto = NULL;
699         if (getfield(&proto, 0, &p, fieldsep) == NULL) {
700                 goto error;
701         }
702
703         sv->s_name = name;
704         sv->s_aliases = aliases;
705         sv->s_port = svport;
706         sv->s_proto = proto;
707
708         return (0);
709
710  error:
711         errno = myerrno;
712
713         if (name != NULL) free(name);
714         if (proto != NULL) free(proto);
715         free_array(aliases, 0);
716
717         return (-1);
718 }
719
720
721 /* ------------------------- struct servent ------------------------- */
722
723 /* +++++++++++++++++++++++++ struct protoent +++++++++++++++++++++++++ */
724
725 /*%
726  * int irp_marshall_pr(struct protoent *pr, char **buffer, size_t *len)
727  *
728  * notes: \li
729  *
730  *      See irpmarshall.h
731  *
732  * return: \li
733  *
734  *      0 on success and -1 on failure.
735  *
736  */
737
738 int
739 irp_marshall_pr(struct protoent *pr, char **buffer, size_t *len) {
740         size_t need = 1;        /*%< for null byte */
741         char prProto[24];
742         const char *fieldsep = COLONSTR;
743
744         if (pr == NULL || len == NULL) {
745                 errno = EINVAL;
746                 return (-1);
747         }
748
749         sprintf(prProto, "%d", (int)pr->p_proto);
750
751         need += strlen(pr->p_name) + 1;
752         need += joinlength(pr->p_aliases) + 1;
753         need += strlen(prProto) + 1;
754
755         if (buffer == NULL) {
756                 *len = need;
757                 return (0);
758         }
759
760         if (*buffer != NULL && need > *len) {
761                 errno = EINVAL;
762                 return (-1);
763         }
764
765         if (*buffer == NULL) {
766                 need += 2;              /*%< for CRLF */
767                 *buffer = memget(need);
768                 if (*buffer == NULL) {
769                         errno = ENOMEM;
770                         return (-1);
771                 }
772
773                 *len = need;
774         }
775
776         strcpy(*buffer, pr->p_name);            strcat(*buffer, fieldsep);
777         joinarray(pr->p_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
778         strcat(*buffer, prProto);               strcat(*buffer, fieldsep);
779
780         return (0);
781
782 }
783
784 /*%
785  * int irp_unmarshall_pr(struct protoent *pr, char *buffer)
786  *
787  * notes: \li
788  *
789  *      See irpmarshall.h
790  *
791  * return: \li
792  *
793  *      0 on success, -1 on failure
794  *
795  */
796
797 int irp_unmarshall_pr(struct protoent *pr, char *buffer) {
798         char *p, *q;
799         int prproto;
800         long t;
801         char *name = NULL;
802         char **aliases = NULL;
803         char tmpbuf[24];
804         char *tb;
805         char fieldsep = ':';
806         int myerrno = EINVAL;
807
808         if (pr == NULL || buffer == NULL) {
809                 errno = EINVAL;
810                 return (-1);
811         }
812
813         p = buffer;
814
815         /* p_name field */
816         name = NULL;
817         if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
818                 goto error;
819         }
820
821
822         /* p_aliases field */
823         q = strchr(p, fieldsep);
824         if (q == NULL) {
825                 goto error;
826         }
827         aliases = splitarray(p, q, COMMA);
828         if (aliases == NULL) {
829                 myerrno = errno;
830                 goto error;
831         }
832         p = q + 1;
833
834
835         /* p_proto field */
836         tb = tmpbuf;
837         if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
838             strlen(tb) == 0U) {
839                 goto error;
840         }
841         t = strtol(tmpbuf, &tb, 10);
842         if (*tb) {
843                 goto error;     /*%< junk in value */
844         }
845         prproto = (int)t;
846         if ((long) prproto != t) {      /*%< value must have been too big. */
847                 goto error;
848         }
849
850         pr->p_name = name;
851         pr->p_aliases = aliases;
852         pr->p_proto = prproto;
853
854         return (0);
855
856  error:
857         errno = myerrno;
858
859         if (name != NULL) free(name);
860         free_array(aliases, 0);
861
862         return (-1);
863 }
864
865 /* ------------------------- struct protoent ------------------------- */
866
867
868
869 /* +++++++++++++++++++++++++ struct hostent +++++++++++++++++++++++++ */
870
871 /*%
872  * int irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len)
873  *
874  * notes: \li
875  *
876  *      See irpmarshall.h.
877  *
878  * return: \li
879  *
880  *      0 on success, -1 on failure.
881  *
882  */
883
884 int
885 irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len) {
886         size_t need = 1;        /*%< for null byte */
887         char hoaddrtype[24];
888         char holength[24];
889         char **av;
890         char *p;
891         int addrlen;
892         int malloced = 0;
893         size_t remlen;
894         const char *fieldsep = "@";
895
896         if (ho == NULL || len == NULL) {
897                 errno = EINVAL;
898                 return (-1);
899         }
900
901         switch(ho->h_addrtype) {
902         case AF_INET:
903                 strcpy(hoaddrtype, "AF_INET");
904                 break;
905
906         case AF_INET6:
907                 strcpy(hoaddrtype, "AF_INET6");
908                 break;
909
910         default:
911                 errno = EINVAL;
912                 return (-1);
913         }
914
915         sprintf(holength, "%d", ho->h_length);
916
917         need += strlen(ho->h_name) + 1;
918         need += joinlength(ho->h_aliases) + 1;
919         need += strlen(hoaddrtype) + 1;
920         need += strlen(holength) + 1;
921
922         /* we determine an upper bound on the string length needed, not an
923            exact length. */
924         addrlen = (ho->h_addrtype == AF_INET ? 16 : 46) ; /*%< XX other AF's?? */
925         for (av = ho->h_addr_list; av != NULL && *av != NULL ; av++)
926                 need += addrlen;
927
928         if (buffer == NULL) {
929                 *len = need;
930                 return (0);
931         }
932
933         if (*buffer != NULL && need > *len) {
934                 errno = EINVAL;
935                 return (-1);
936         }
937
938         if (*buffer == NULL) {
939                 need += 2;              /*%< for CRLF */
940                 *buffer = memget(need);
941                 if (*buffer == NULL) {
942                         errno = ENOMEM;
943                         return (-1);
944                 }
945
946                 *len = need;
947                 malloced = 1;
948         }
949
950         strcpy(*buffer, ho->h_name);            strcat(*buffer, fieldsep);
951         joinarray(ho->h_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
952         strcat(*buffer, hoaddrtype);            strcat(*buffer, fieldsep);
953         strcat(*buffer, holength);              strcat(*buffer, fieldsep);
954
955         p = *buffer + strlen(*buffer);
956         remlen = need - strlen(*buffer);
957         for (av = ho->h_addr_list ; av != NULL && *av != NULL ; av++) {
958                 if (inet_ntop(ho->h_addrtype, *av, p, remlen) == NULL) {
959                         goto error;
960                 }
961                 if (*(av + 1) != NULL)
962                         strcat(p, COMMASTR);
963                 remlen -= strlen(p);
964                 p += strlen(p);
965         }
966         strcat(*buffer, fieldsep);
967
968         return (0);
969
970  error:
971         if (malloced) {
972                 memput(*buffer, need);
973         }
974
975         return (-1);
976 }
977
978 /*%
979  * int irp_unmarshall_ho(struct hostent *ho, char *buffer)
980  *
981  * notes: \li
982  *
983  *      See irpmarshall.h.
984  *
985  * return: \li
986  *
987  *      0 on success, -1 on failure.
988  *
989  */
990
991 int
992 irp_unmarshall_ho(struct hostent *ho, char *buffer) {
993         char *p, *q, *r;
994         int hoaddrtype;
995         int holength;
996         long t;
997         char *name;
998         char **aliases = NULL;
999         char **hohaddrlist = NULL;
1000         size_t hoaddrsize;
1001         char tmpbuf[24];
1002         char *tb;
1003         char **alist;
1004         int addrcount;
1005         char fieldsep = '@';
1006         int myerrno = EINVAL;
1007
1008         if (ho == NULL || buffer == NULL) {
1009                 errno = EINVAL;
1010                 return (-1);
1011         }
1012
1013         p = buffer;
1014
1015         /* h_name field */
1016         name = NULL;
1017         if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
1018                 goto error;
1019         }
1020
1021
1022         /* h_aliases field */
1023         q = strchr(p, fieldsep);
1024         if (q == NULL) {
1025                 goto error;
1026         }
1027         aliases = splitarray(p, q, COMMA);
1028         if (aliases == NULL) {
1029                 myerrno = errno;
1030                 goto error;
1031         }
1032         p = q + 1;
1033
1034
1035         /* h_addrtype field */
1036         tb = tmpbuf;
1037         if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
1038             strlen(tb) == 0U) {
1039                 goto error;
1040         }
1041         if (strcmp(tmpbuf, "AF_INET") == 0)
1042                 hoaddrtype = AF_INET;
1043         else if (strcmp(tmpbuf, "AF_INET6") == 0)
1044                 hoaddrtype = AF_INET6;
1045         else
1046                 goto error;
1047
1048
1049         /* h_length field */
1050         tb = tmpbuf;
1051         if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
1052             strlen(tb) == 0U) {
1053                 goto error;
1054         }
1055         t = strtol(tmpbuf, &tb, 10);
1056         if (*tb) {
1057                 goto error;     /*%< junk in value */
1058         }
1059         holength = (int)t;
1060         if ((long) holength != t) {     /*%< value must have been too big. */
1061                 goto error;
1062         }
1063
1064
1065         /* h_addr_list field */
1066         q = strchr(p, fieldsep);
1067         if (q == NULL)
1068                 goto error;
1069
1070         /* count how many addresss are in there */
1071         if (q > p + 1) {
1072                 for (addrcount = 1, r = p ; r != q ; r++) {
1073                         if (*r == COMMA)
1074                                 addrcount++;
1075                 }
1076         } else {
1077                 addrcount = 0;
1078         }
1079
1080         hoaddrsize = (addrcount + 1) * sizeof (char *);
1081         hohaddrlist = malloc(hoaddrsize);
1082         if (hohaddrlist == NULL) {
1083                 myerrno = ENOMEM;
1084                 goto error;
1085         }
1086
1087         memset(hohaddrlist, 0x0, hoaddrsize);
1088
1089         alist = hohaddrlist;
1090         for (t = 0, r = p ; r != q ; p = r + 1, t++) {
1091                 char saved;
1092                 while (r != q && *r != COMMA) r++;
1093                 saved = *r;
1094                 *r = 0x0;
1095
1096                 alist[t] = malloc(hoaddrtype == AF_INET ? 4 : 16);
1097                 if (alist[t] == NULL) {
1098                         myerrno = ENOMEM;
1099                         goto error;
1100                 }
1101
1102                 if (inet_pton(hoaddrtype, p, alist[t]) == -1)
1103                         goto error;
1104                 *r = saved;
1105         }
1106         alist[t] = NULL;
1107
1108         ho->h_name = name;
1109         ho->h_aliases = aliases;
1110         ho->h_addrtype = hoaddrtype;
1111         ho->h_length = holength;
1112         ho->h_addr_list = hohaddrlist;
1113
1114         return (0);
1115
1116  error:
1117         errno = myerrno;
1118
1119         if (name != NULL) free(name);
1120         free_array(hohaddrlist, 0);
1121         free_array(aliases, 0);
1122
1123         return (-1);
1124 }
1125
1126 /* ------------------------- struct hostent------------------------- */
1127
1128
1129
1130 /* +++++++++++++++++++++++++ struct netgrp +++++++++++++++++++++++++ */
1131
1132 /*%
1133  * int irp_marshall_ng(const char *host, const char *user,
1134  *                     const char *domain, char *buffer, size_t *len)
1135  *
1136  * notes: \li
1137  *
1138  *      See note for irp_marshall_ng_start
1139  *
1140  * return: \li
1141  *
1142  *      0 on success, 0 on failure.
1143  *
1144  */
1145
1146 int
1147 irp_marshall_ng(const char *host, const char *user, const char *domain,
1148                 char **buffer, size_t *len) {
1149         size_t need = 1; /*%< for nul byte */
1150         const char *fieldsep = ",";
1151
1152         if (len == NULL) {
1153                 errno = EINVAL;
1154                 return (-1);
1155         }
1156
1157         need += 4;                     /*%< two parens and two commas */
1158         need += (host == NULL ? 0 : strlen(host));
1159         need += (user == NULL ? 0 : strlen(user));
1160         need += (domain == NULL ? 0 : strlen(domain));
1161
1162         if (buffer == NULL) {
1163                 *len = need;
1164                 return (0);
1165         } else if (*buffer != NULL && need > *len) {
1166                 errno = EINVAL;
1167                 return (-1);
1168         }
1169
1170         if (*buffer == NULL) {
1171                 need += 2;              /*%< for CRLF */
1172                 *buffer = memget(need);
1173                 if (*buffer == NULL) {
1174                         errno = ENOMEM;
1175                         return (-1);
1176                 }
1177
1178                 *len = need;
1179         }
1180
1181         (*buffer)[0] = '(';
1182         (*buffer)[1] = '\0';
1183
1184         if (host != NULL)
1185                 strcat(*buffer, host);
1186         strcat(*buffer, fieldsep);
1187
1188         if (user != NULL)
1189                 strcat(*buffer, user);
1190         strcat(*buffer, fieldsep);
1191
1192         if (domain != NULL)
1193                 strcat(*buffer, domain);
1194         strcat(*buffer, ")");
1195
1196         return (0);
1197 }
1198
1199
1200
1201 /* ---------- */
1202
1203 /*%
1204  * int irp_unmarshall_ng(const char **host, const char **user,
1205  *                       const char **domain, char *buffer)
1206  *
1207  * notes: \li
1208  *
1209  *      Unpacks the BUFFER into 3 character arrays it allocates and assigns
1210  *      to *HOST, *USER and *DOMAIN. If any field of the value is empty,
1211  *      then the corresponding paramater value will be set to NULL.
1212  *
1213  * return: \li
1214  *
1215  *      0 on success and -1 on failure.
1216  */
1217
1218 int
1219 irp_unmarshall_ng(const char **hostp, const char **userp, const char **domainp,
1220                   char *buffer)
1221 {
1222         char *p, *q;
1223         char fieldsep = ',';
1224         int myerrno = EINVAL;
1225         char *host, *user, *domain;
1226
1227         if (userp == NULL || hostp == NULL ||
1228             domainp == NULL || buffer == NULL) {
1229                 errno = EINVAL;
1230                 return (-1);
1231         }
1232
1233         host = user = domain = NULL;
1234
1235         p = buffer;
1236         while (isspace((unsigned char)*p)) {
1237                 p++;
1238         }
1239         if (*p != '(') {
1240                 goto error;
1241         }
1242
1243         q = p + 1;
1244         while (*q && *q != fieldsep)
1245                 q++;
1246         if (!*q) {
1247                 goto error;
1248         } else if (q > p + 1) {
1249                 host = strndup(p, q - p);
1250         }
1251
1252         p = q + 1;
1253         if (!*p) {
1254                 goto error;
1255         } else if (*p != fieldsep) {
1256                 q = p + 1;
1257                 while (*q && *q != fieldsep)
1258                         q++;
1259                 if (!*q) {
1260                         goto error;
1261                 }
1262                 user = strndup(p, q - p);
1263         } else {
1264                 p++;
1265         }
1266
1267         if (!*p) {
1268                 goto error;
1269         } else if (*p != ')') {
1270                 q = p + 1;
1271                 while (*q && *q != ')')
1272                         q++;
1273                 if (!*q) {
1274                         goto error;
1275                 }
1276                 domain = strndup(p, q - p);
1277         }
1278         *hostp = host;
1279         *userp = user;
1280         *domainp = domain;
1281
1282         return (0);
1283
1284  error:
1285         errno = myerrno;
1286
1287         if (host != NULL) free(host);
1288         if (user != NULL) free(user);
1289
1290         return (-1);
1291 }
1292
1293 /* ------------------------- struct netgrp ------------------------- */
1294
1295
1296
1297
1298 /* +++++++++++++++++++++++++ struct nwent +++++++++++++++++++++++++ */
1299
1300 /*%
1301  * int irp_marshall_nw(struct nwent *ne, char **buffer, size_t *len)
1302  *
1303  * notes: \li
1304  *
1305  *      See at top.
1306  *
1307  * return: \li
1308  *
1309  *      0 on success and -1 on failure.
1310  *
1311  */
1312
1313 int
1314 irp_marshall_nw(struct nwent *ne, char **buffer, size_t *len) {
1315         size_t need = 1;        /*%< for null byte */
1316         char nAddrType[24];
1317         char nNet[MAXPADDRSIZE];
1318         const char *fieldsep = COLONSTR;
1319
1320         if (ne == NULL || len == NULL) {
1321                 return (-1);
1322         }
1323
1324         strcpy(nAddrType, ADDR_T_STR(ne->n_addrtype));
1325
1326         if (inet_net_ntop(ne->n_addrtype, ne->n_addr, ne->n_length,
1327                           nNet, sizeof nNet) == NULL) {
1328                 return (-1);
1329         }
1330
1331
1332         need += strlen(ne->n_name) + 1;
1333         need += joinlength(ne->n_aliases) + 1;
1334         need += strlen(nAddrType) + 1;
1335         need += strlen(nNet) + 1;
1336
1337         if (buffer == NULL) {
1338                 *len = need;
1339                 return (0);
1340         }
1341
1342         if (*buffer != NULL && need > *len) {
1343                 errno = EINVAL;
1344                 return (-1);
1345         }
1346
1347         if (*buffer == NULL) {
1348                 need += 2;              /*%< for CRLF */
1349                 *buffer = memget(need);
1350                 if (*buffer == NULL) {
1351                         errno = ENOMEM;
1352                         return (-1);
1353                 }
1354
1355                 *len = need;
1356         }
1357
1358         strcpy(*buffer, ne->n_name);            strcat(*buffer, fieldsep);
1359         joinarray(ne->n_aliases, *buffer, COMMA) ; strcat(*buffer, fieldsep);
1360         strcat(*buffer, nAddrType);             strcat(*buffer, fieldsep);
1361         strcat(*buffer, nNet);                  strcat(*buffer, fieldsep);
1362
1363         return (0);
1364 }
1365
1366 /*%
1367  * int irp_unmarshall_nw(struct nwent *ne, char *buffer)
1368  *
1369  * notes: \li
1370  *
1371  *      See note up top.
1372  *
1373  * return: \li
1374  *
1375  *      0 on success and -1 on failure.
1376  *
1377  */
1378
1379 int
1380 irp_unmarshall_nw(struct nwent *ne, char *buffer) {
1381         char *p, *q;
1382         int naddrtype;
1383         long nnet;
1384         int bits;
1385         char *name = NULL;
1386         char **aliases = NULL;
1387         char tmpbuf[24];
1388         char *tb;
1389         char fieldsep = ':';
1390         int myerrno = EINVAL;
1391
1392         if (ne == NULL || buffer == NULL) {
1393                 goto error;
1394         }
1395
1396         p = buffer;
1397
1398         /* n_name field */
1399         name = NULL;
1400         if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
1401                 goto error;
1402         }
1403
1404
1405         /* n_aliases field. Aliases are separated by commas */
1406         q = strchr(p, fieldsep);
1407         if (q == NULL) {
1408                 goto error;
1409         }
1410         aliases = splitarray(p, q, COMMA);
1411         if (aliases == NULL) {
1412                 myerrno = errno;
1413                 goto error;
1414         }
1415         p = q + 1;
1416
1417
1418         /* h_addrtype field */
1419         tb = tmpbuf;
1420         if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
1421             strlen(tb) == 0U) {
1422                 goto error;
1423         }
1424         if (strcmp(tmpbuf, "AF_INET") == 0)
1425                 naddrtype = AF_INET;
1426         else if (strcmp(tmpbuf, "AF_INET6") == 0)
1427                 naddrtype = AF_INET6;
1428         else
1429                 goto error;
1430
1431
1432         /* n_net field */
1433         tb = tmpbuf;
1434         if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
1435             strlen(tb) == 0U) {
1436                 goto error;
1437         }
1438         nnet = 0;
1439         bits = inet_net_pton(naddrtype, tmpbuf, &nnet, sizeof nnet);
1440         if (bits < 0) {
1441                 goto error;
1442         }
1443
1444         /* nnet = ntohl(nnet); */ /* keep in network order for nwent */
1445
1446         ne->n_name = name;
1447         ne->n_aliases = aliases;
1448         ne->n_addrtype = naddrtype;
1449         ne->n_length = bits;
1450         ne->n_addr = malloc(sizeof nnet);
1451         if (ne->n_addr == NULL) {
1452                 goto error;
1453         }
1454
1455         memcpy(ne->n_addr, &nnet, sizeof nnet);
1456
1457         return (0);
1458
1459  error:
1460         errno = myerrno;
1461
1462         if (name != NULL) free(name);
1463         free_array(aliases, 0);
1464
1465         return (-1);
1466 }
1467
1468
1469 /* ------------------------- struct nwent ------------------------- */
1470
1471
1472 /* +++++++++++++++++++++++++ struct netent +++++++++++++++++++++++++ */
1473
1474 /*%
1475  * int irp_marshall_ne(struct netent *ne, char **buffer, size_t *len)
1476  *
1477  * notes: \li
1478  *
1479  *      See at top.
1480  *
1481  * return: \li
1482  *
1483  *      0 on success and -1 on failure.
1484  *
1485  */
1486
1487 int
1488 irp_marshall_ne(struct netent *ne, char **buffer, size_t *len) {
1489         size_t need = 1;        /*%< for null byte */
1490         char nAddrType[24];
1491         char nNet[MAXPADDRSIZE];
1492         const char *fieldsep = COLONSTR;
1493         long nval;
1494
1495         if (ne == NULL || len == NULL) {
1496                 return (-1);
1497         }
1498
1499         strcpy(nAddrType, ADDR_T_STR(ne->n_addrtype));
1500
1501         nval = htonl(ne->n_net);
1502         if (inet_ntop(ne->n_addrtype, &nval, nNet, sizeof nNet) == NULL) {
1503                 return (-1);
1504         }
1505
1506         need += strlen(ne->n_name) + 1;
1507         need += joinlength(ne->n_aliases) + 1;
1508         need += strlen(nAddrType) + 1;
1509         need += strlen(nNet) + 1;
1510
1511         if (buffer == NULL) {
1512                 *len = need;
1513                 return (0);
1514         }
1515
1516         if (*buffer != NULL && need > *len) {
1517                 errno = EINVAL;
1518                 return (-1);
1519         }
1520
1521         if (*buffer == NULL) {
1522                 need += 2;              /*%< for CRLF */
1523                 *buffer = memget(need);
1524                 if (*buffer == NULL) {
1525                         errno = ENOMEM;
1526                         return (-1);
1527                 }
1528
1529                 *len = need;
1530         }
1531
1532         strcpy(*buffer, ne->n_name);            strcat(*buffer, fieldsep);
1533         joinarray(ne->n_aliases, *buffer, COMMA) ; strcat(*buffer, fieldsep);
1534         strcat(*buffer, nAddrType);             strcat(*buffer, fieldsep);
1535         strcat(*buffer, nNet);                  strcat(*buffer, fieldsep);
1536
1537         return (0);
1538 }
1539
1540 /*%
1541  * int irp_unmarshall_ne(struct netent *ne, char *buffer)
1542  *
1543  * notes: \li
1544  *
1545  *      See note up top.
1546  *
1547  * return: \li
1548  *
1549  *      0 on success and -1 on failure.
1550  *
1551  */
1552
1553 int
1554 irp_unmarshall_ne(struct netent *ne, char *buffer) {
1555         char *p, *q;
1556         int naddrtype;
1557         long nnet;
1558         int bits;
1559         char *name = NULL;
1560         char **aliases = NULL;
1561         char tmpbuf[24];
1562         char *tb;
1563         char fieldsep = ':';
1564         int myerrno = EINVAL;
1565
1566         if (ne == NULL || buffer == NULL) {
1567                 goto error;
1568         }
1569
1570         p = buffer;
1571
1572         /* n_name field */
1573         name = NULL;
1574         if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
1575                 goto error;
1576         }
1577
1578
1579         /* n_aliases field. Aliases are separated by commas */
1580         q = strchr(p, fieldsep);
1581         if (q == NULL) {
1582                 goto error;
1583         }
1584         aliases = splitarray(p, q, COMMA);
1585         if (aliases == NULL) {
1586                 myerrno = errno;
1587                 goto error;
1588         }
1589         p = q + 1;
1590
1591
1592         /* h_addrtype field */
1593         tb = tmpbuf;
1594         if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
1595             strlen(tb) == 0U) {
1596                 goto error;
1597         }
1598         if (strcmp(tmpbuf, "AF_INET") == 0)
1599                 naddrtype = AF_INET;
1600         else if (strcmp(tmpbuf, "AF_INET6") == 0)
1601                 naddrtype = AF_INET6;
1602         else
1603                 goto error;
1604
1605
1606         /* n_net field */
1607         tb = tmpbuf;
1608         if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
1609             strlen(tb) == 0U) {
1610                 goto error;
1611         }
1612         bits = inet_net_pton(naddrtype, tmpbuf, &nnet, sizeof nnet);
1613         if (bits < 0) {
1614                 goto error;
1615         }
1616         nnet = ntohl(nnet);
1617
1618         ne->n_name = name;
1619         ne->n_aliases = aliases;
1620         ne->n_addrtype = naddrtype;
1621         ne->n_net = nnet;
1622
1623         return (0);
1624
1625  error:
1626         errno = myerrno;
1627
1628         if (name != NULL) free(name);
1629         free_array(aliases, 0);
1630
1631         return (-1);
1632 }
1633
1634
1635 /* ------------------------- struct netent ------------------------- */
1636
1637
1638 /* =========================================================================== */
1639
1640 /*%
1641  * static char ** splitarray(const char *buffer, const char *buffend, char delim)
1642  *
1643  * notes: \li
1644  *
1645  *      Split a delim separated astring. Not allowed
1646  *      to have two delims next to each other. BUFFER points to begining of
1647  *      string, BUFFEND points to one past the end of the string
1648  *      (i.e. points at where the null byte would be if null
1649  *      terminated).
1650  *
1651  * return: \li
1652  *
1653  *      Returns a malloced array of pointers, each pointer pointing to a
1654  *      malloced string. If BUFEER is an empty string, then return values is
1655  *      array of 1 pointer that is NULL. Returns NULL on failure.
1656  *
1657  */
1658
1659 static char **
1660 splitarray(const char *buffer, const char *buffend, char delim) {
1661         const char *p, *q;
1662         int count = 0;
1663         char **arr = NULL;
1664         char **aptr;
1665
1666         if (buffend < buffer)
1667                 return (NULL);
1668         else if (buffend > buffer && *buffer == delim)
1669                 return (NULL);
1670         else if (buffend > buffer && *(buffend - 1) == delim)
1671                 return (NULL);
1672
1673         /* count the number of field and make sure none are empty */
1674         if (buffend > buffer + 1) {
1675                 for (count = 1, q = buffer ; q != buffend ; q++) {
1676                         if (*q == delim) {
1677                                 if (q > buffer && (*(q - 1) == delim)) {
1678                                         errno = EINVAL;
1679                                         return (NULL);
1680                                 }
1681                                 count++;
1682                         }
1683                 }
1684         }
1685
1686         if (count > 0) {
1687                 count++ ;               /*%< for NULL at end */
1688                 aptr = arr = malloc(count * sizeof (char *));
1689                 if (aptr == NULL) {
1690                          errno = ENOMEM;
1691                          return (NULL);
1692                  }
1693
1694                 memset(arr, 0x0, count * sizeof (char *));
1695                 for (p = buffer ; p < buffend ; p++) {
1696                         for (q = p ; *q != delim && q != buffend ; q++)
1697                                 /* nothing */;
1698                         *aptr = strndup(p, q - p);
1699
1700                         p = q;
1701                         aptr++;
1702                 }
1703                 *aptr = NULL;
1704         } else {
1705                 arr = malloc(sizeof (char *));
1706                 if (arr == NULL) {
1707                         errno = ENOMEM;
1708                         return (NULL);
1709                 }
1710
1711                 *arr = NULL;
1712         }
1713
1714         return (arr);
1715 }
1716
1717 /*%
1718  * static size_t joinlength(char * const *argv)
1719  *
1720  * return: \li
1721  *
1722  *      the number of bytes in all the arrays pointed at
1723  *      by argv, including their null bytes(which will usually be turned
1724  *      into commas).
1725  *
1726  *
1727  */
1728
1729 static size_t
1730 joinlength(char * const *argv) {
1731         int len = 0;
1732
1733         while (argv && *argv) {
1734                 len += (strlen(*argv) + 1);
1735                 argv++;
1736         }
1737
1738         return (len);
1739 }
1740
1741 /*%
1742  * int joinarray(char * const *argv, char *buffer, char delim)
1743  *
1744  * notes: \li
1745  *
1746  *      Copy all the ARGV strings into the end of BUFFER
1747  *      separating them with DELIM.  BUFFER is assumed to have
1748  *      enough space to hold everything and to be already null-terminated.
1749  *
1750  * return: \li
1751  *
1752  *      0 unless argv or buffer is NULL.
1753  *
1754  *
1755  */
1756
1757 static int
1758 joinarray(char * const *argv, char *buffer, char delim) {
1759         char * const *p;
1760         char sep[2];
1761
1762         if (argv == NULL || buffer == NULL) {
1763                 errno = EINVAL;
1764                 return (-1);
1765         }
1766
1767         sep[0] = delim;
1768         sep[1] = 0x0;
1769
1770         for (p = argv ; *p != NULL ; p++) {
1771                 strcat(buffer, *p);
1772                 if (*(p + 1) != NULL) {
1773                         strcat(buffer, sep);
1774                 }
1775         }
1776
1777         return (0);
1778 }
1779
1780 /*%
1781  * static char * getfield(char **res, size_t reslen, char **ptr, char delim)
1782  *
1783  * notes: \li
1784  *
1785  *      Stores in *RES, which is a buffer of length RESLEN, a
1786  *      copy of the bytes from *PTR up to and including the first
1787  *      instance of DELIM. If *RES is NULL, then it will be
1788  *      assigned a malloced buffer to hold the copy. *PTR is
1789  *      modified to point at the found delimiter.
1790  *
1791  * return: \li
1792  *
1793  *      If there was no delimiter, then NULL is returned,
1794  *      otherewise *RES is returned.
1795  *
1796  */
1797
1798 static char *
1799 getfield(char **res, size_t reslen, char **ptr, char delim) {
1800         char *q;
1801
1802         if (res == NULL || ptr == NULL || *ptr == NULL) {
1803                 errno = EINVAL;
1804                 return (NULL);
1805         }
1806
1807         q = strchr(*ptr, delim);
1808
1809         if (q == NULL) {
1810                 errno = EINVAL;
1811                 return (NULL);
1812         } else {
1813                 if (*res == NULL) {
1814                         *res = strndup(*ptr, q - *ptr);
1815                 } else {
1816                         if ((size_t)(q - *ptr + 1) > reslen) { /*%< to big for res */
1817                                 errno = EINVAL;
1818                                 return (NULL);
1819                         } else {
1820                                 strncpy(*res, *ptr, q - *ptr);
1821                                 (*res)[q - *ptr] = 0x0;
1822                         }
1823                 }
1824                 *ptr = q + 1;
1825         }
1826
1827         return (*res);
1828 }
1829
1830
1831
1832
1833
1834 #ifndef HAVE_STRNDUP
1835 /*
1836  * static char * strndup(const char *str, size_t len)
1837  *
1838  * notes: \li
1839  *
1840  *      like strdup, except do len bytes instead of the whole string. Always
1841  *      null-terminates.
1842  *
1843  * return: \li
1844  *
1845  *      The newly malloced string.
1846  *
1847  */
1848
1849 static char *
1850 strndup(const char *str, size_t len) {
1851         char *p = malloc(len + 1);
1852
1853         if (p == NULL)
1854                 return (NULL);
1855         strncpy(p, str, len);
1856         p[len] = 0x0;
1857         return (p);
1858 }
1859 #endif
1860
1861 #if WANT_MAIN
1862
1863 /*%
1864  * static int strcmp_nws(const char *a, const char *b)
1865  *
1866  * notes: \li
1867  *
1868  *      do a strcmp, except uneven lengths of whitespace compare the same
1869  *
1870  * return: \li
1871  *
1872  */
1873
1874 static int
1875 strcmp_nws(const char *a, const char *b) {
1876         while (*a && *b) {
1877                 if (isspace(*a) && isspace(*b)) {
1878                         do {
1879                                 a++;
1880                         } while (isspace(*a));
1881                         do {
1882                                 b++;
1883                         } while (isspace(*b));
1884                 }
1885                 if (*a < *b)
1886                         return (-1);
1887                 else if (*a > *b)
1888                         return (1);
1889
1890                 a++;
1891                 b++;;
1892         }
1893
1894         if (*a == *b)
1895                 return (0);
1896         else if (*a > *b)
1897                 return (1);
1898         else
1899                 return (-1);
1900 }
1901
1902 #endif
1903
1904 /*%
1905  * static void free_array(char **argv, size_t entries)
1906  *
1907  * notes: \li
1908  *
1909  *      Free argv and each of the pointers inside it. The end of
1910  *      the array is when a NULL pointer is found inside. If
1911  *      entries is > 0, then NULL pointers inside the array do
1912  *      not indicate the end of the array.
1913  *
1914  */
1915
1916 static void
1917 free_array(char **argv, size_t entries) {
1918         char **p = argv;
1919         int useEntries = (entries > 0U);
1920
1921         if (argv == NULL)
1922                 return;
1923
1924         while ((useEntries && entries > 0U) || *p) {
1925                 if (*p)
1926                         free(*p);
1927                 p++;
1928                 if (useEntries)
1929                         entries--;
1930         }
1931         free(argv);
1932 }
1933
1934
1935
1936
1937
1938 /* ************************************************** */
1939
1940 #if WANT_MAIN
1941
1942 /*% takes an option to indicate what sort of marshalling(read the code) and
1943    an argument. If the argument looks like a marshalled buffer(has a ':'
1944    embedded) then it's unmarshalled and the remarshalled and the new string
1945    is compared to the old one.
1946 */
1947
1948 int
1949 main(int argc, char **argv) {
1950         char buffer[1024];
1951         char *b = &buffer[0];
1952         size_t len = sizeof buffer;
1953         char option;
1954
1955         if (argc < 2 || argv[1][0] != '-')
1956                 exit(1);
1957
1958         option = argv[1][1];
1959         argv++;
1960         argc--;
1961
1962
1963 #if 0
1964         {
1965                 char buff[10];
1966                 char *p = argv[1], *q = &buff[0];
1967
1968                 while (getfield(&q, sizeof buff, &p, ':') != NULL) {
1969                         printf("field: \"%s\"\n", q);
1970                         p++;
1971                 }
1972                 printf("p is now \"%s\"\n", p);
1973         }
1974 #endif
1975
1976 #if 0
1977         {
1978                 char **x = splitarray(argv[1], argv[1] + strlen(argv[1]),
1979                                       argv[2][0]);
1980                 char **p;
1981
1982                 if (x == NULL)
1983                         printf("split failed\n");
1984
1985                 for (p = x ; p != NULL && *p != NULL ; p++) {
1986                         printf("\"%s\"\n", *p);
1987                 }
1988         }
1989 #endif
1990
1991 #if 1
1992         switch(option) {
1993         case 'n': {
1994                 struct nwent ne;
1995                 int i;
1996
1997                 if (strchr(argv[1], ':') != NULL) {
1998                         if (irp_unmarshall_nw(&ne, argv[1]) != 0) {
1999                                 printf("Unmarhsalling failed\n");
2000                                 exit(1);
2001                         }
2002
2003                         printf("Name: \"%s\"\n", ne.n_name);
2004                         printf("Aliases:");
2005                         for (i = 0 ; ne.n_aliases[i] != NULL ; i++)
2006                                 printf("\n\t\"%s\"", ne.n_aliases[i]);
2007                         printf("\nAddrtype: %s\n", ADDR_T_STR(ne.n_addrtype));
2008                         inet_net_ntop(ne.n_addrtype, ne.n_addr, ne.n_length,
2009                                       buffer, sizeof buffer);
2010                         printf("Net: \"%s\"\n", buffer);
2011                         *((long*)ne.n_addr) = htonl(*((long*)ne.n_addr));
2012                         inet_net_ntop(ne.n_addrtype, ne.n_addr, ne.n_length,
2013                                       buffer, sizeof buffer);
2014                         printf("Corrected Net: \"%s\"\n", buffer);
2015                 } else {
2016                         struct netent *np1 = getnetbyname(argv[1]);
2017                         ne.n_name = np1->n_name;
2018                         ne.n_aliases = np1->n_aliases;
2019                         ne.n_addrtype = np1->n_addrtype;
2020                         ne.n_addr = &np1->n_net;
2021                         ne.n_length = (IN_CLASSA(np1->n_net) ?
2022                                        8 :
2023                                        (IN_CLASSB(np1->n_net) ?
2024                                         16 :
2025                                         (IN_CLASSC(np1->n_net) ?
2026                                          24 : -1)));
2027                         np1->n_net = htonl(np1->n_net);
2028                         if (irp_marshall_nw(&ne, &b, &len) != 0) {
2029                                 printf("Marshalling failed\n");
2030                         }
2031                         printf("%s\n", b);
2032                 }
2033                 break;
2034         }
2035
2036
2037         case 'r': {
2038                 char **hosts, **users, **domains;
2039                 size_t entries;
2040                 int i;
2041                 char *buff;
2042                 size_t size;
2043                 char *ngname;
2044
2045                 if (strchr(argv[1], '(') != NULL) {
2046                         if (irp_unmarshall_ng(&ngname, &entries,
2047                                               &hosts, &users, &domains,
2048                                               argv[1]) != 0) {
2049                                 printf("unmarshall failed\n");
2050                                 exit(1);
2051                         }
2052
2053 #define STRVAL(x) (x == NULL ? "*" : x)
2054
2055                         printf("%s {\n", ngname);
2056                         for (i = 0 ; i < entries ; i++)
2057                                 printf("\t\"%s\" : \"%s\" : \"%s\"\n",
2058                                        STRVAL(hosts[i]),
2059                                        STRVAL(users[i]),
2060                                        STRVAL(domains[i]));
2061                         printf("}\n\n\n");
2062
2063
2064                         irp_marshall_ng_start(ngname, NULL, &size);
2065                         for (i = 0 ; i < entries ; i++)
2066                                 irp_marshall_ng_next(hosts[i], users[i],
2067                                                      domains[i], NULL, &size);
2068                         irp_marshall_ng_end(NULL, &size);
2069
2070                         buff = malloc(size);
2071
2072                         irp_marshall_ng_start(ngname, buff, &size);
2073                         for (i = 0 ; i < entries ; i++) {
2074                                 if (irp_marshall_ng_next(hosts[i], users[i],
2075                                                          domains[i], buff,
2076                                                          &size) != 0)
2077                                         printf("next marshalling failed.\n");
2078                         }
2079                         irp_marshall_ng_end(buff, &size);
2080
2081                         if (strcmp_nws(argv[1], buff) != 0) {
2082                                 printf("compare failed:\n\t%s\n\t%s\n",
2083                                        buffer, argv[1]);
2084                         } else {
2085                                 printf("compare ok\n");
2086                         }
2087                 } else {
2088                         char *h, *u, *d, *buff;
2089                         size_t size;
2090
2091                         /* run through two times. First to figure out how
2092                            much of a buffer we need. Second to do the
2093                            actual marshalling */
2094
2095                         setnetgrent(argv[1]);
2096                         irp_marshall_ng_start(argv[1], NULL, &size);
2097                         while (getnetgrent(&h, &u, &d) == 1)
2098                                 irp_marshall_ng_next(h, u, d, NULL, &size);
2099                         irp_marshall_ng_end(NULL, &size);
2100                         endnetgrent(argv[1]);
2101
2102                         buff = malloc(size);
2103
2104                         setnetgrent(argv[1]);
2105                         if (irp_marshall_ng_start(argv[1], buff, &size) != 0)
2106                                 printf("Marshalling start failed\n");
2107
2108                         while (getnetgrent(&h, &u, &d) == 1) {
2109                                 if (irp_marshall_ng_next(h, u, d, buff, &size)
2110                                     != 0) {
2111                                         printf("Marshalling failed\n");
2112                                 }
2113                         }
2114
2115                         irp_marshall_ng_end(buff, &size);
2116                         endnetgrent();
2117
2118                         printf("success: %s\n", buff);
2119                 }
2120                 break;
2121         }
2122
2123
2124
2125         case 'h': {
2126                 struct hostent he, *hp;
2127                 int i;
2128
2129
2130                 if (strchr(argv[1], '@') != NULL) {
2131                         if (irp_unmarshall_ho(&he, argv[1]) != 0) {
2132                                 printf("unmarshall failed\n");
2133                                 exit(1);
2134                         }
2135
2136                         printf("Host: \"%s\"\nAliases:", he.h_name);
2137                         for (i = 0 ; he.h_aliases[i] != NULL ; i++)
2138                                 printf("\n\t\t\"%s\"", he.h_aliases[i]);
2139                         printf("\nAddr Type: \"%s\"\n",
2140                                ADDR_T_STR(he.h_addrtype));
2141                         printf("Length: %d\nAddresses:", he.h_length);
2142                         for (i = 0 ; he.h_addr_list[i] != 0 ; i++) {
2143                                 inet_ntop(he.h_addrtype, he.h_addr_list[i],
2144                                           buffer, sizeof buffer);
2145                                 printf("\n\t\"%s\"\n", buffer);
2146                         }
2147                         printf("\n\n");
2148
2149                         irp_marshall_ho(&he, &b, &len);
2150                         if (strcmp(argv[1], buffer) != 0) {
2151                                 printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
2152                                        buffer, argv[1]);
2153                         } else {
2154                                 printf("compare ok\n");
2155                         }
2156                 } else {
2157                         if ((hp = gethostbyname(argv[1])) == NULL) {
2158                                 perror("gethostbyname");
2159                                 printf("\"%s\"\n", argv[1]);
2160                                 exit(1);
2161                         }
2162
2163                         if (irp_marshall_ho(hp, &b, &len) != 0) {
2164                                 printf("irp_marshall_ho failed\n");
2165                                 exit(1);
2166                         }
2167
2168                         printf("success: \"%s\"\n", buffer);
2169                 }
2170                 break;
2171         }
2172
2173
2174         case 's': {
2175                 struct servent *sv;
2176                 struct servent sv1;
2177
2178                 if (strchr(argv[1], ':') != NULL) {
2179                         sv = &sv1;
2180                         memset(sv, 0xef, sizeof (struct servent));
2181                         if (irp_unmarshall_sv(sv, argv[1]) != 0) {
2182                                 printf("unmarshall failed\n");
2183
2184                         }
2185
2186                         irp_marshall_sv(sv, &b, &len);
2187                         if (strcmp(argv[1], buffer) != 0) {
2188                                 printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
2189                                        buffer, argv[1]);
2190                         } else {
2191                                 printf("compare ok\n");
2192                         }
2193                 } else {
2194                         if ((sv = getservbyname(argv[1], argv[2])) == NULL) {
2195                                 perror("getservent");
2196                                 exit(1);
2197                         }
2198
2199                         if (irp_marshall_sv(sv, &b, &len) != 0) {
2200                                 printf("irp_marshall_sv failed\n");
2201                                 exit(1);
2202                         }
2203
2204                         printf("success: \"%s\"\n", buffer);
2205                 }
2206                 break;
2207         }
2208
2209         case 'g': {
2210                 struct group *gr;
2211                 struct group gr1;
2212
2213                 if (strchr(argv[1], ':') != NULL) {
2214                         gr = &gr1;
2215                         memset(gr, 0xef, sizeof (struct group));
2216                         if (irp_unmarshall_gr(gr, argv[1]) != 0) {
2217                                 printf("unmarshall failed\n");
2218
2219                         }
2220
2221                         irp_marshall_gr(gr, &b, &len);
2222                         if (strcmp(argv[1], buffer) != 0) {
2223                                 printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
2224                                        buffer, argv[1]);
2225                         } else {
2226                                 printf("compare ok\n");
2227                         }
2228                 } else {
2229                         if ((gr = getgrnam(argv[1])) == NULL) {
2230                                 perror("getgrnam");
2231                                 exit(1);
2232                         }
2233
2234                         if (irp_marshall_gr(gr, &b, &len) != 0) {
2235                                 printf("irp_marshall_gr failed\n");
2236                                 exit(1);
2237                         }
2238
2239                         printf("success: \"%s\"\n", buffer);
2240                 }
2241                 break;
2242         }
2243
2244
2245         case 'p': {
2246                 struct passwd *pw;
2247                 struct passwd pw1;
2248
2249                 if (strchr(argv[1], ':') != NULL) {
2250                         pw = &pw1;
2251                         memset(pw, 0xef, sizeof (*pw));
2252                         if (irp_unmarshall_pw(pw, argv[1]) != 0) {
2253                                 printf("unmarshall failed\n");
2254                                 exit(1);
2255                         }
2256
2257                         printf("User: \"%s\"\nPasswd: \"%s\"\nUid: %ld\nGid: %ld\n",
2258                                pw->pw_name, pw->pw_passwd, (long)pw->pw_uid,
2259                                (long)pw->pw_gid);
2260                         printf("Class: \"%s\"\nChange: %ld\nGecos: \"%s\"\n",
2261                                pw->pw_class, (long)pw->pw_change, pw->pw_gecos);
2262                         printf("Shell: \"%s\"\nDirectory: \"%s\"\n",
2263                                pw->pw_shell, pw->pw_dir);
2264
2265                         pw = getpwnam(pw->pw_name);
2266                         irp_marshall_pw(pw, &b, &len);
2267                         if (strcmp(argv[1], buffer) != 0) {
2268                                 printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
2269                                        buffer, argv[1]);
2270                         } else {
2271                                 printf("compare ok\n");
2272                         }
2273                 } else {
2274                         if ((pw = getpwnam(argv[1])) == NULL) {
2275                                 perror("getpwnam");
2276                                 exit(1);
2277                         }
2278
2279                         if (irp_marshall_pw(pw, &b, &len) != 0) {
2280                                 printf("irp_marshall_pw failed\n");
2281                                 exit(1);
2282                         }
2283
2284                         printf("success: \"%s\"\n", buffer);
2285                 }
2286                 break;
2287         }
2288
2289         default:
2290                 printf("Wrong option: %c\n", option);
2291                 break;
2292         }
2293
2294 #endif
2295
2296         return (0);
2297 }
2298
2299 #endif
2300
2301 /*! \file */