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 #include <ctype.h>
27 #include <netdb.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <nss_dbdefs.h>
31 
32 int str2protoent(const char *, int, void *,
33 		char *, int);
34 
35 static int proto_stayopen;
36 /*
37  * Unsynchronized, but it affects only
38  * efficiency, not correctness
39  */
40 
41 static DEFINE_NSS_DB_ROOT(db_root);
42 static DEFINE_NSS_GETENT(context);
43 
44 void
45 _nss_initf_proto(nss_db_params_t *p)
46 {
47 	p->name	= NSS_DBNAM_PROTOCOLS;
48 	p->default_config = NSS_DEFCONF_PROTOCOLS;
49 }
50 
51 struct protoent *
52 getprotobyname_r(const char *name, struct protoent *result,
53 	char *buffer, int buflen)
54 {
55 	nss_XbyY_args_t arg;
56 	nss_status_t	res;
57 
58 	if (name == (const char *)NULL) {
59 		errno = ERANGE;
60 		return (NULL);
61 	}
62 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2protoent);
63 	arg.key.name	= name;
64 	arg.stayopen	= proto_stayopen;
65 	res = nss_search(&db_root, _nss_initf_proto,
66 		NSS_DBOP_PROTOCOLS_BYNAME, &arg);
67 	arg.status = res;
68 	(void) NSS_XbyY_FINI(&arg);
69 	return ((struct protoent *)arg.returnval);
70 }
71 
72 struct protoent *
73 getprotobynumber_r(int proto, struct protoent *result, char *buffer, int buflen)
74 {
75 	nss_XbyY_args_t arg;
76 	nss_status_t	res;
77 
78 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2protoent);
79 	arg.key.number = proto;
80 	arg.stayopen	= proto_stayopen;
81 	res = nss_search(&db_root, _nss_initf_proto,
82 		NSS_DBOP_PROTOCOLS_BYNUMBER, &arg);
83 	arg.status = res;
84 	(void) NSS_XbyY_FINI(&arg);
85 	return ((struct protoent *)arg.returnval);
86 }
87 
88 int
89 setprotoent(int stay)
90 {
91 	proto_stayopen = stay;
92 	nss_setent(&db_root, _nss_initf_proto, &context);
93 	return (0);
94 }
95 
96 int
97 endprotoent()
98 {
99 	proto_stayopen = 0;
100 	nss_endent(&db_root, _nss_initf_proto, &context);
101 	nss_delete(&db_root);
102 	return (0);
103 }
104 
105 struct protoent *
106 getprotoent_r(struct protoent *result, char *buffer, int buflen)
107 {
108 	nss_XbyY_args_t arg;
109 	nss_status_t	res;
110 
111 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2protoent);
112 	/* No stayopen flag;  of course you stay open for iteration */
113 	res = nss_getent(&db_root, _nss_initf_proto, &context, &arg);
114 	arg.status = res;
115 	(void) NSS_XbyY_FINI(&arg);
116 	return ((struct protoent *)arg.returnval);
117 }
118 
119 /*
120  * Return values: 0 = success, 1 = parse error, 2 = erange ...
121  * The structure pointer passed in is a structure in the caller's space
122  * wherein the field pointers would be set to areas in the buffer if
123  * need be. instring and buffer should be separate areas. Let's not
124  * fight over crumbs.
125  */
126 int
127 str2protoent(const char *instr, int lenstr,
128 	void *ent /* it is really (struct protoent *) */,
129 	char *buffer, int buflen)
130 {
131 	struct	protoent *proto = (struct protoent *)ent;
132 	const char	*p, *numstart, *namestart, *limit;
133 	int		numlen, namelen = 0;
134 	char		numbuf[16];
135 	char		*numend;
136 
137 	if ((instr >= buffer && (buffer + buflen) > instr) ||
138 	    (buffer >= instr && (instr + lenstr) > buffer)) {
139 		return (NSS_STR_PARSE_PARSE);
140 	}
141 
142 	p = instr;
143 	limit = p + lenstr;
144 
145 	while (p < limit && isspace(*p)) {
146 		p++;
147 	}
148 	namestart = p;
149 	while (p < limit && !isspace(*p)) {
150 		p++;		/* Skip over the canonical name */
151 	}
152 	namelen = (int)(p - namestart);
153 
154 	if (buflen <= namelen) { /* not enough buffer */
155 		return (NSS_STR_PARSE_ERANGE);
156 	}
157 	(void) memcpy(buffer, namestart, namelen);
158 	buffer[namelen] = '\0';
159 	proto->p_name = buffer;
160 
161 	while (p < limit && isspace(*p)) {
162 		p++;
163 	}
164 	if (p >= limit) {
165 		/* Syntax error -- no proto number */
166 		return (NSS_STR_PARSE_PARSE);
167 	}
168 	numstart = p;
169 	do {
170 		p++;		/* Find the end of the proto number */
171 	} while (p < limit && !isspace(*p));
172 	numlen = (int)(p - numstart);
173 	if (numlen >= (int)sizeof (numbuf)) {
174 		/* Syntax error -- supposed number is too long */
175 		return (NSS_STR_PARSE_PARSE);
176 	}
177 	(void) memcpy(numbuf, numstart, (size_t)numlen);
178 	numbuf[numlen] = '\0';
179 	proto->p_proto = (int)strtol(numbuf, &numend, 10);
180 	if (*numend != '\0') {
181 		/* Syntax error -- protocol number isn't a number */
182 		return (NSS_STR_PARSE_PARSE);
183 	}
184 
185 	while (p < limit && isspace(*p)) {
186 		p++;
187 	}
188 	/*
189 	 * Although nss_files_XY_all calls us with # stripped,
190 	 * we should be able to deal with it here in order to
191 	 * be more useful.
192 	 */
193 	if (p >= limit || *p == '#') { /* no aliases, no problem */
194 		char **ptr;
195 
196 		ptr = (char **)ROUND_UP(buffer + namelen + 1,
197 							sizeof (char *));
198 		if ((char *)ptr >= buffer + buflen) {
199 			/* hope they don't try to peek in */
200 			proto->p_aliases = 0;
201 			return (NSS_STR_PARSE_ERANGE);
202 		} else {
203 			*ptr = 0;
204 			proto->p_aliases = ptr;
205 			return (NSS_STR_PARSE_SUCCESS);
206 		}
207 	}
208 	proto->p_aliases = _nss_netdb_aliases(p, lenstr - (int)(p - instr),
209 				buffer + namelen + 1, buflen - namelen - 1);
210 	return (NSS_STR_PARSE_SUCCESS);
211 }
212