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 weak _nss_ldap__printers_constr = _nss_ldap_printers_constr
27 
28 #include "ldap_common.h"
29 
30 static void append_attr(char *buf, char *attr);
31 
32 /* printer attributes filters */
33 #define	_F_GETPRINTERBYNAME	\
34 	"(&(objectClass=sunPrinter)(|(printer-name=%s)(printer-aliases=%s)))"
35 
36 #define	PRINTER_PREFIX	"printer-"
37 #define	SUNWPR_PREFIX	"sunwpr-"
38 
39 /*
40  * Attributes from the following classes:
41  * 	printerService
42  * 	printerAbstact
43  * 	sunPrinter
44  */
45 
46 /*
47  * Get all attributes.
48  */
49 static const char **printer_attrs = NULL;
50 
51 
52 /*
53  * _nss_ldap_printers2str is the data marshaling method for the printers
54  * getXbyY backend processes. This method is called after a successful
55  * ldap search has been performed. This method will parse the ldap search
56  * values into argp->buf.buffer. Three error conditions are expected and
57  * returned to nsswitch.
58  * In order to be compatible with old data output, the code is commented out
59  * with NSS_LDAP_PRINTERS. The NSS_LDAP_PRINTERS section is for future
60  * refrences if it's decided to fix the output format.
61  */
62 
63 static int
64 _nss_ldap_printers2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
65 {
66 	int			i, j;
67 	int			nss_result;
68 	int			buflen = 0, len;
69 	char			*buffer = NULL;
70 	char			**name, *attrname;
71 	ns_ldap_attr_t		*attr;
72 	ns_ldap_result_t	*result = be->result;
73 #ifdef	NSS_LDAP_PRINTERS
74 	int			slen, plen;
75 #endif
76 
77 	if (result == NULL)
78 		return (NSS_STR_PARSE_PARSE);
79 
80 	buflen = argp->buf.buflen;
81 	if (argp->buf.result != NULL) {
82 		be->buffer = calloc(1, buflen);
83 		if (be->buffer == NULL)
84 			return (NSS_STR_PARSE_PARSE);
85 		be->buflen = buflen;
86 		buffer = be->buffer;
87 	} else {
88 		buffer = argp->buf.buffer;
89 		(void) memset(argp->buf.buffer, 0, buflen);
90 	}
91 
92 	nss_result = NSS_STR_PARSE_SUCCESS;
93 
94 #ifdef	NSS_LDAP_PRINTERS
95 	slen = strlen(SUNWPR_PREFIX);
96 	plen = strlen(PRINTER_PREFIX);
97 #endif
98 
99 	/*
100 	 * Pick out the printer name and aliases
101 	 */
102 	name = __ns_ldap_getAttr(result->entry, "printer-name");
103 	if (name == NULL || name[0] == NULL) {
104 		nss_result = NSS_STR_PARSE_PARSE;
105 		goto result_printers2str;
106 	}
107 	len = snprintf(buffer, buflen, "%s", name[0]);
108 	TEST_AND_ADJUST(len, buffer, buflen, result_printers2str);
109 
110 #ifdef	NSS_LDAP_PRINTERS
111 	attr = __ns_ldap_getAttrStruct(result->entry, "printer-aliases");
112 	if (attr != NULL && attr->attrvalue != NULL) {
113 		for (i = 0; i < attr->value_count; i++) {
114 			len = snprintf(buffer, buflen, "|%s",
115 					attr->attrvalue[i]);
116 			TEST_AND_ADJUST(len, buffer, buflen,
117 					result_printers2str);
118 		}
119 	}
120 #endif
121 	/*
122 	 * Add the rest of the attributes
123 	 */
124 	for (i = 0; i < result->entry->attr_count; i++) {
125 		attr = getattr(result, i);
126 		if (attr == NULL) {
127 			nss_result = NSS_STR_PARSE_PARSE;
128 			goto result_printers2str;
129 		}
130 		/*
131 		 * The attribute contains key=value
132 		 */
133 		if (strcasecmp(attr->attrname, "sun-printer-kvp") == 0) {
134 			for (j = 0; j < attr->value_count; j++) {
135 				len = strlen(attr->attrvalue[j]);
136 				if (len < 1 ) {
137 					*buffer = '\0';
138 					nss_result = (int)NSS_STR_PARSE_PARSE;
139 					goto result_printers2str;
140 				}
141 				len =  snprintf(buffer, buflen, ":%s",
142 						attr->attrvalue[j]);
143 				TEST_AND_ADJUST(len, buffer, buflen,
144 						result_printers2str);
145 			}
146 		} else {
147 			/*
148 			 * Skip some attr names
149 			 */
150 #ifdef	NSS_LDAP_PRINTERS
151 			if (strcasecmp(attr->attrname, "printer-name") == 0 ||
152 				strcasecmp(attr->attrname, "dn") == 0 ||
153 				strcasecmp(attr->attrname,
154 					"objectclass") == 0 ||
155 				strcasecmp(attr->attrname,
156 					"printer-uri") == 0 ||
157 				strcasecmp(attr->attrname,
158 					"printer-aliases") == 0)
159 #else
160 			if (strcasecmp(attr->attrname, "printer-name") == 0)
161 #endif
162 				continue;
163 			}
164 			/*
165 			 * Translate attr name ->key name
166 			 */
167 			if (strcmp(attr->attrname, "sun-printer-bsdaddr")
168 					== 0)
169 				attrname = "bsdaddr";
170 #ifdef	NSS_LDAP_PRINTERS
171 			else if (strcmp(attr->attrname, "printer-info")
172 					== 0)
173 				attrname = "description";
174 			else if (strcmp(attr->attrname, "sunwpr-support")
175 					== 0)
176 				attrname = "itopssupported";
177 			else if (strncmp(attr->attrname, PRINTER_PREFIX, plen)
178 					== 0)
179 				attrname = attr->attrname + plen;
180 			else if (strncmp(attr->attrname, SUNWPR_PREFIX, slen)
181 					== 0)
182 				attrname = attr->attrname + slen;
183 #endif
184 			else
185 				attrname = attr->attrname;
186 
187 			/*
188 			 * The attrname is the key. The attribute
189 			 * data is the value.
190 			 */
191 			len = snprintf(buffer, buflen, ":%s=", attrname);
192 			TEST_AND_ADJUST(len, buffer, buflen,
193 					result_printers2str);
194 
195 			for (j = 0; j < attr->value_count; j++) {
196 				int k;
197 				char *kp;
198 
199 				if (attr->attrvalue[j] == NULL) {
200 					*buffer = 0;
201 					nss_result = NSS_STR_PARSE_PARSE;
202 					goto result_printers2str;
203 				}
204 				len = strlen(attr->attrvalue[j]);
205 				if (len < 1) {
206 					*buffer = 0;
207 					nss_result = NSS_STR_PARSE_PARSE;
208 					goto result_printers2str;
209 				}
210 				/*
211 				 * Add extra for any colons which need to
212 				 * be backslashed plus ending ':' or ','.
213 				 */
214 				k = 0;
215 				for (kp = attr->attrvalue[j]; *kp != '\0'; kp++)
216 					if (*kp == ':')
217 						/* count ':' in value */
218 						k++;
219 				if (j == 0)
220 					/* first time */
221 					len += k;
222 				else
223 					/* add ',' */
224 					len += k + 1;
225 
226 				if (len > buflen) {
227 					nss_result = NSS_STR_PARSE_ERANGE;
228 					goto result_printers2str;
229 				}
230 				if (j > 0)
231 					*buffer++ = ',';
232 
233 				(void) append_attr(buffer,
234 					    attr->attrvalue[j]);
235 				buffer += strlen(attr->attrvalue[j]) + k;
236 				buflen -= len;
237 			}
238 	}
239 
240 	if (argp->buf.result != NULL)
241 		be->buflen = strlen(be->buffer);
242 
243 result_printers2str:
244 	(void) __ns_ldap_freeResult(&be->result);
245 	return ((int)nss_result);
246 }
247 
248 /*
249  * Attributes which contain colons must be backslashed.
250  */
251 static void
252 append_attr(char *buf, char *attr)
253 {
254 	char *cp, *bp;
255 
256 	if (strchr(attr, ':') == NULL) {
257 		(void) strcat(buf, attr);
258 		return;
259 	}
260 	bp = buf;
261 	cp = attr;
262 	while (*cp != '\0') {
263 		if (*cp == ':') {
264 			*bp++ = '\\';
265 		}
266 		*bp++ = *cp++;
267 	}
268 }
269 
270 /*
271  * getbyname gets printer attributes by printer name. This function
272  * constructs an ldap search filter using the printer name invocation
273  * parameter and the getprinterbyname search filter defined. Once the
274  * filter is constructed, we search for matching entries and marshal
275  * the data results into argp->buf.buffer for the frontend process.
276  * The function _nss_ldap_printers2str performs the data marshaling.
277  */
278 
279 static nss_status_t
280 getbyname(ldap_backend_ptr be, void *a)
281 {
282 	char		printername[BUFSIZ];
283 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
284 	char		searchfilter[SEARCHFILTERLEN];
285 
286 	(void) strncpy(printername, argp->key.name, BUFSIZ);
287 	if (snprintf(searchfilter, SEARCHFILTERLEN,
288 		_F_GETPRINTERBYNAME, printername, printername) < 0)
289 		return ((nss_status_t)NSS_NOTFOUND);
290 
291 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
292 		_PRINTERS, searchfilter, NULL, NULL, NULL));
293 }
294 
295 static ldap_backend_op_t printers_ops[] = {
296 	_nss_ldap_destr,
297 	_nss_ldap_endent,
298 	_nss_ldap_setent,
299 	_nss_ldap_getent,
300 	getbyname,
301 };
302 
303 
304 /*
305  * _nss_ldap_printers_constr is where life begins. This function calls
306  * the generic ldap constructor function to define and build the abstract
307  * data types required to support ldap operations.
308  */
309 
310 /*ARGSUSED0*/
311 nss_backend_t *
312 _nss_ldap_printers_constr(const char *dummy1, const char *dummy2,
313 			const char *dummy3)
314 {
315 
316 	return ((nss_backend_t *)_nss_ldap_constr(printers_ops,
317 		sizeof (printers_ops)/sizeof (printers_ops[0]), _PRINTERS,
318 		printer_attrs, _nss_ldap_printers2str));
319 }
320