1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <ctype.h>
29 #include <netdb.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <nss_dbdefs.h>
33 
34 int str2protoent(const char *, int, void *,
35 		char *, int);
36 
37 static int proto_stayopen;
38 /*
39  * Unsynchronized, but it affects only
40  * efficiency, not correctness
41  */
42 
43 static DEFINE_NSS_DB_ROOT(db_root);
44 static DEFINE_NSS_GETENT(context);
45 
46 void
47 _nss_initf_proto(nss_db_params_t *p)
48 {
49 	p->name	= NSS_DBNAM_PROTOCOLS;
50 	p->default_config = NSS_DEFCONF_PROTOCOLS;
51 }
52 
53 struct protoent *
54 getprotobyname_r(const char *name, struct protoent *result,
55 	char *buffer, int buflen)
56 {
57 	nss_XbyY_args_t arg;
58 	nss_status_t	res;
59 
60 	if (name == (const char *)NULL) {
61 		errno = ERANGE;
62 		return (NULL);
63 	}
64 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2protoent);
65 	arg.key.name	= name;
66 	arg.stayopen	= proto_stayopen;
67 	res = nss_search(&db_root, _nss_initf_proto,
68 		NSS_DBOP_PROTOCOLS_BYNAME, &arg);
69 	arg.status = res;
70 	(void) NSS_XbyY_FINI(&arg);
71 	return ((struct protoent *)arg.returnval);
72 }
73 
74 struct protoent *
75 getprotobynumber_r(int proto, struct protoent *result, char *buffer, int buflen)
76 {
77 	nss_XbyY_args_t arg;
78 	nss_status_t	res;
79 
80 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2protoent);
81 	arg.key.number = proto;
82 	arg.stayopen	= proto_stayopen;
83 	res = nss_search(&db_root, _nss_initf_proto,
84 		NSS_DBOP_PROTOCOLS_BYNUMBER, &arg);
85 	arg.status = res;
86 	(void) NSS_XbyY_FINI(&arg);
87 	return ((struct protoent *)arg.returnval);
88 }
89 
90 int
91 setprotoent(int stay)
92 {
93 	proto_stayopen = stay;
94 	nss_setent(&db_root, _nss_initf_proto, &context);
95 	return (0);
96 }
97 
98 int
99 endprotoent()
100 {
101 	proto_stayopen = 0;
102 	nss_endent(&db_root, _nss_initf_proto, &context);
103 	nss_delete(&db_root);
104 	return (0);
105 }
106 
107 struct protoent *
108 getprotoent_r(struct protoent *result, char *buffer, int buflen)
109 {
110 	nss_XbyY_args_t arg;
111 	nss_status_t	res;
112 
113 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2protoent);
114 	/* No stayopen flag;  of course you stay open for iteration */
115 	res = nss_getent(&db_root, _nss_initf_proto, &context, &arg);
116 	arg.status = res;
117 	(void) NSS_XbyY_FINI(&arg);
118 	return ((struct protoent *)arg.returnval);
119 }
120 
121 /*
122  * Return values: 0 = success, 1 = parse error, 2 = erange ...
123  * The structure pointer passed in is a structure in the caller's space
124  * wherein the field pointers would be set to areas in the buffer if
125  * need be. instring and buffer should be separate areas. Let's not
126  * fight over crumbs.
127  */
128 int
129 str2protoent(const char *instr, int lenstr,
130 	void *ent /* it is really (struct protoent *) */,
131 	char *buffer, int buflen)
132 {
133 	struct	protoent *proto = (struct protoent *)ent;
134 	const char	*p, *numstart, *namestart, *limit;
135 	int		numlen, namelen = 0;
136 	char		numbuf[16];
137 	char		*numend;
138 
139 	if ((instr >= buffer && (buffer + buflen) > instr) ||
140 	    (buffer >= instr && (instr + lenstr) > buffer)) {
141 		return (NSS_STR_PARSE_PARSE);
142 	}
143 
144 	p = instr;
145 	limit = p + lenstr;
146 
147 	while (p < limit && isspace(*p)) {
148 		p++;
149 	}
150 	namestart = p;
151 	while (p < limit && !isspace(*p)) {
152 		p++;		/* Skip over the canonical name */
153 	}
154 	namelen = (int)(p - namestart);
155 
156 	if (buflen <= namelen) { /* not enough buffer */
157 		return (NSS_STR_PARSE_ERANGE);
158 	}
159 	(void) memcpy(buffer, namestart, namelen);
160 	buffer[namelen] = '\0';
161 	proto->p_name = buffer;
162 
163 	while (p < limit && isspace(*p)) {
164 		p++;
165 	}
166 	if (p >= limit) {
167 		/* Syntax error -- no proto number */
168 		return (NSS_STR_PARSE_PARSE);
169 	}
170 	numstart = p;
171 	do {
172 		p++;		/* Find the end of the proto number */
173 	} while (p < limit && !isspace(*p));
174 	numlen = (int)(p - numstart);
175 	if (numlen >= (int)sizeof (numbuf)) {
176 		/* Syntax error -- supposed number is too long */
177 		return (NSS_STR_PARSE_PARSE);
178 	}
179 	(void) memcpy(numbuf, numstart, (size_t)numlen);
180 	numbuf[numlen] = '\0';
181 	proto->p_proto = (int)strtol(numbuf, &numend, 10);
182 	if (*numend != '\0') {
183 		/* Syntax error -- protocol number isn't a number */
184 		return (NSS_STR_PARSE_PARSE);
185 	}
186 
187 	while (p < limit && isspace(*p)) {
188 		p++;
189 	}
190 	/*
191 	 * Although nss_files_XY_all calls us with # stripped,
192 	 * we should be able to deal with it here in order to
193 	 * be more useful.
194 	 */
195 	if (p >= limit || *p == '#') { /* no aliases, no problem */
196 		char **ptr;
197 
198 		ptr = (char **)ROUND_UP(buffer + namelen + 1,
199 							sizeof (char *));
200 		if ((char *)ptr >= buffer + buflen) {
201 			/* hope they don't try to peek in */
202 			proto->p_aliases = 0;
203 			return (NSS_STR_PARSE_ERANGE);
204 		} else {
205 			*ptr = 0;
206 			proto->p_aliases = ptr;
207 			return (NSS_STR_PARSE_SUCCESS);
208 		}
209 	}
210 	proto->p_aliases = _nss_netdb_aliases(p, lenstr - (int)(p - instr),
211 				buffer + namelen + 1, buflen - namelen - 1);
212 	return (NSS_STR_PARSE_SUCCESS);
213 }
214