/*
* Copyright(c) 1989, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Portions Copyright (c) 1996 by Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "Id: irpmarshall.c,v 1.7 2006/03/09 23:57:56 marka Exp ";
#endif /* LIBC_SCCS and not lint */
need += strlen(pw->pw_name) + 1; /*%< one for fieldsep */
need += strlen(pw->pw_passwd) + 1;
need += strlen(pwUid) + 1;
need += strlen(pwGid) + 1;
need += strlen(pwClass) + 1;
need += strlen(pwChange) + 1;
need += strlen(pwExpire) + 1;
need += strlen(pw->pw_gecos) + 1;
need += strlen(pw->pw_dir) + 1;
need += strlen(pw->pw_shell) + 1;
if (buffer == NULL) {
*len = need;
return (0);
}
if (*buffer != NULL && need > *len) {
errno = EINVAL;
return (-1);
}
if (*buffer == NULL) {
need += 2; /*%< for CRLF */
*buffer = memget(need);
if (*buffer == NULL) {
errno = ENOMEM;
return (-1);
}
name = pass = class = gecos = dir = shell = NULL;
p = buffer;
/* pw_name field */
name = NULL;
if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0) {
goto error;
}
/* pw_passwd field */
pass = NULL;
if (getfield(&pass, 0, &p, fieldsep) == NULL) { /*%< field can be empty */
goto error;
}
/* pw_uid field */
tb = tmpbuf;
if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
strlen(tb) == 0) {
goto error;
}
t = strtol(tmpbuf, &tb, 10);
if (*tb) {
goto error; /*%< junk in value */
}
pwuid = (uid_t)t;
if ((long) pwuid != t) { /*%< value must have been too big. */
goto error;
}
/* pw_gid field */
tb = tmpbuf;
if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
strlen(tb) == 0) {
goto error;
}
t = strtol(tmpbuf, &tb, 10);
if (*tb) {
goto error; /*%< junk in value */
}
pwgid = (gid_t)t;
if ((long)pwgid != t) { /*%< value must have been too big. */
goto error;
}
/* pw_class field */
class = NULL;
if (getfield(&class, 0, &p, fieldsep) == NULL) {
goto error;
}
/* pw_change field */
tb = tmpbuf;
if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
strlen(tb) == 0) {
goto error;
}
t = strtol(tmpbuf, &tb, 10);
if (*tb) {
goto error; /*%< junk in value */
}
pwchange = (time_t)t;
if ((long)pwchange != t) { /*%< value must have been too big. */
goto error;
}
/* pw_expire field */
tb = tmpbuf;
if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
strlen(tb) == 0) {
goto error;
}
t = strtol(tmpbuf, &tb, 10);
if (*tb) {
goto error; /*%< junk in value */
}
pwexpire = (time_t)t;
if ((long) pwexpire != t) { /*%< value must have been too big. */
goto error;
}
/* pw_gecos field */
gecos = NULL;
if (getfield(&gecos, 0, &p, fieldsep) == NULL) {
goto error;
}
/* pw_dir field */
dir = NULL;
if (getfield(&dir, 0, &p, fieldsep) == NULL) {
goto error;
}
/* pw_shell field */
shell = NULL;
if (getfield(&shell, 0, &p, fieldsep) == NULL) {
goto error;
}
if (name != NULL) free(name);
if (pass != NULL) free(pass);
if (gecos != NULL) free(gecos);
if (dir != NULL) free(dir);
if (shell != NULL) free(shell);
/* gr_name field */
name = NULL;
if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
goto error;
}
/* gr_passwd field */
pass = NULL;
if (getfield(&pass, 0, &p, fieldsep) == NULL) {
goto error;
}
/* gr_gid field */
tb = tmpbuf;
if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
strlen(tb) == 0U) {
goto error;
}
t = strtol(tmpbuf, &tb, 10);
if (*tb) {
goto error; /*%< junk in value */
}
grgid = (gid_t)t;
if ((long) grgid != t) { /*%< value must have been too big. */
goto error;
}
/* gr_mem field. Member names are separated by commas */
q = strchr(p, fieldsep);
if (q == NULL) {
goto error;
}
members = splitarray(p, q, COMMA);
if (members == NULL) {
myerrno = errno;
goto error;
}
p = q + 1;
/*%
* int irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len)
*
* notes: \li
*
* See irpmarshall.h
*
* return: \li
*
* 0 on success, -1 on failure.
*
*/
int
irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len) {
size_t need = 1; /*%< for null byte */
char svPort[24];
const char *fieldsep = COLONSTR;
short realport;
if (sv == NULL || len == NULL) {
errno = EINVAL;
return (-1);
}
/* the int s_port field is actually a short in network order. We
want host order to make the marshalled data look correct */
realport = ntohs((short)sv->s_port);
sprintf(svPort, "%d", realport);
need += strlen(sv->s_name) + 1;
need += joinlength(sv->s_aliases) + 1;
need += strlen(svPort) + 1;
need += strlen(sv->s_proto) + 1;
if (buffer == NULL) {
*len = need;
return (0);
}
if (*buffer != NULL && need > *len) {
errno = EINVAL;
return (-1);
}
if (*buffer == NULL) {
need += 2; /*%< for CRLF */
*buffer = memget(need);
if (*buffer == NULL) {
errno = ENOMEM;
return (-1);
}
/* p_name field */
name = NULL;
if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
goto error;
}
/* p_aliases field */
q = strchr(p, fieldsep);
if (q == NULL) {
goto error;
}
aliases = splitarray(p, q, COMMA);
if (aliases == NULL) {
myerrno = errno;
goto error;
}
p = q + 1;
/* p_proto field */
tb = tmpbuf;
if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
strlen(tb) == 0U) {
goto error;
}
t = strtol(tmpbuf, &tb, 10);
if (*tb) {
goto error; /*%< junk in value */
}
prproto = (int)t;
if ((long) prproto != t) { /*%< value must have been too big. */
goto error;
}
/*%
* int irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len)
*
* notes: \li
*
* See irpmarshall.h.
*
* return: \li
*
* 0 on success, -1 on failure.
*
*/
int
irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len) {
size_t need = 1; /*%< for null byte */
char hoaddrtype[24];
char holength[24];
char **av;
char *p;
int addrlen;
int malloced = 0;
size_t remlen;
const char *fieldsep = "@";
if (ho == NULL || len == NULL) {
errno = EINVAL;
return (-1);
}
switch(ho->h_addrtype) {
case AF_INET:
strcpy(hoaddrtype, "AF_INET");
break;
case AF_INET6:
strcpy(hoaddrtype, "AF_INET6");
break;
default:
errno = EINVAL;
return (-1);
}
sprintf(holength, "%d", ho->h_length);
need += strlen(ho->h_name) + 1;
need += joinlength(ho->h_aliases) + 1;
need += strlen(hoaddrtype) + 1;
need += strlen(holength) + 1;
/* we determine an upper bound on the string length needed, not an
exact length. */
addrlen = (ho->h_addrtype == AF_INET ? 16 : 46) ; /*%< XX other AF's?? */
for (av = ho->h_addr_list; av != NULL && *av != NULL ; av++)
need += addrlen;
if (buffer == NULL) {
*len = need;
return (0);
}
if (*buffer != NULL && need > *len) {
errno = EINVAL;
return (-1);
}
if (*buffer == NULL) {
need += 2; /*%< for CRLF */
*buffer = memget(need);
if (*buffer == NULL) {
errno = ENOMEM;
return (-1);
}
/* h_length field */
tb = tmpbuf;
if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
strlen(tb) == 0U) {
goto error;
}
t = strtol(tmpbuf, &tb, 10);
if (*tb) {
goto error; /*%< junk in value */
}
holength = (int)t;
if ((long) holength != t) { /*%< value must have been too big. */
goto error;
}
/* h_addr_list field */
q = strchr(p, fieldsep);
if (q == NULL)
goto error;
/* count how many addresss are in there */
if (q > p + 1) {
for (addrcount = 1, r = p ; r != q ; r++) {
if (*r == COMMA)
addrcount++;
}
} else {
addrcount = 0;
}
/*%
* int irp_marshall_ng(const char *host, const char *user,
* const char *domain, char *buffer, size_t *len)
*
* notes: \li
*
* See note for irp_marshall_ng_start
*
* return: \li
*
* 0 on success, 0 on failure.
*
*/
int
irp_marshall_ng(const char *host, const char *user, const char *domain,
char **buffer, size_t *len) {
size_t need = 1; /*%< for nul byte */
const char *fieldsep = ",";
if (len == NULL) {
errno = EINVAL;
return (-1);
}
need += 4; /*%< two parens and two commas */
need += (host == NULL ? 0 : strlen(host));
need += (user == NULL ? 0 : strlen(user));
need += (domain == NULL ? 0 : strlen(domain));
if (buffer == NULL) {
*len = need;
return (0);
} else if (*buffer != NULL && need > *len) {
errno = EINVAL;
return (-1);
}
if (*buffer == NULL) {
need += 2; /*%< for CRLF */
*buffer = memget(need);
if (*buffer == NULL) {
errno = ENOMEM;
return (-1);
}
*len = need;
}
(*buffer)[0] = '(';
(*buffer)[1] = '\0';
if (host != NULL)
strcat(*buffer, host);
strcat(*buffer, fieldsep);
if (user != NULL)
strcat(*buffer, user);
strcat(*buffer, fieldsep);
if (domain != NULL)
strcat(*buffer, domain);
strcat(*buffer, ")");
return (0);
}
/* ---------- */
/*%
* int irp_unmarshall_ng(const char **host, const char **user,
* const char **domain, char *buffer)
*
* notes: \li
*
* Unpacks the BUFFER into 3 character arrays it allocates and assigns
* to *HOST, *USER and *DOMAIN. If any field of the value is empty,
* then the corresponding paramater value will be set to NULL.
*
* return: \li
*
* 0 on success and -1 on failure.
*/
/*%
* static char ** splitarray(const char *buffer, const char *buffend, char delim)
*
* notes: \li
*
* Split a delim separated astring. Not allowed
* to have two delims next to each other. BUFFER points to begining of
* string, BUFFEND points to one past the end of the string
* (i.e. points at where the null byte would be if null
* terminated).
*
* return: \li
*
* Returns a malloced array of pointers, each pointer pointing to a
* malloced string. If BUFEER is an empty string, then return values is
* array of 1 pointer that is NULL. Returns NULL on failure.
*
*/
/*%
* static size_t joinlength(char * const *argv)
*
* return: \li
*
* the number of bytes in all the arrays pointed at
* by argv, including their null bytes(which will usually be turned
* into commas).
*
*
*/
static size_t
joinlength(char * const *argv) {
int len = 0;
while (argv && *argv) {
len += (strlen(*argv) + 1);
argv++;
}
return (len);
}
/*%
* int joinarray(char * const *argv, char *buffer, char delim)
*
* notes: \li
*
* Copy all the ARGV strings into the end of BUFFER
* separating them with DELIM. BUFFER is assumed to have
* enough space to hold everything and to be already null-terminated.
*
* return: \li
*
* 0 unless argv or buffer is NULL.
*
*
*/
/*%
* static char * getfield(char **res, size_t reslen, char **ptr, char delim)
*
* notes: \li
*
* Stores in *RES, which is a buffer of length RESLEN, a
* copy of the bytes from *PTR up to and including the first
* instance of DELIM. If *RES is NULL, then it will be
* assigned a malloced buffer to hold the copy. *PTR is
* modified to point at the found delimiter.
*
* return: \li
*
* If there was no delimiter, then NULL is returned,
* otherewise *RES is returned.
*
*/
/*%
* static int strcmp_nws(const char *a, const char *b)
*
* notes: \li
*
* do a strcmp, except uneven lengths of whitespace compare the same
*
* return: \li
*
*/
static int
strcmp_nws(const char *a, const char *b) {
while (*a && *b) {
if (isspace(*a) && isspace(*b)) {
do {
a++;
} while (isspace(*a));
do {
b++;
} while (isspace(*b));
}
if (*a < *b)
return (-1);
else if (*a > *b)
return (1);
a++;
b++;;
}
if (*a == *b)
return (0);
else if (*a > *b)
return (1);
else
return (-1);
}
#endif
/*%
* static void free_array(char **argv, size_t entries)
*
* notes: \li
*
* Free argv and each of the pointers inside it. The end of
* the array is when a NULL pointer is found inside. If
* entries is > 0, then NULL pointers inside the array do
* not indicate the end of the array.
*
*/
/*% takes an option to indicate what sort of marshalling(read the code) and
an argument. If the argument looks like a marshalled buffer(has a ':'
embedded) then it's unmarshalled and the remarshalled and the new string
is compared to the old one.
*/
int
main(int argc, char **argv) {
char buffer[1024];
char *b = &buffer[0];
size_t len = sizeof buffer;
char option;