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 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  */
27 
28 /* $Id: service.c 172 2006-05-24 20:54:00Z njacobs $ */
29 
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <stdarg.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <libintl.h>
37 #include <papi_impl.h>
38 #include <config-site.h>
39 
40 static int
interposed_auth_callback(papi_service_t handle,void * app_data)41 interposed_auth_callback(papi_service_t handle, void *app_data)
42 {
43 	int result = -1;
44 	service_t *svc = app_data;
45 
46 	if (svc != NULL)
47 		result = svc->authCB(svc, svc->app_data);
48 
49 	return (result);
50 }
51 
52 static char *
default_service_uri(char * fallback)53 default_service_uri(char *fallback)
54 {
55 	char *result = NULL;
56 
57 	if (getuid() == geteuid())
58 		result = getenv("PAPI_SERVICE_URI");
59 
60 	if (result == NULL) {
61 		char *cups;
62 
63 		if ((cups = getenv("CUPS_SERVER")) != NULL) {
64 			char buf[BUFSIZ];
65 
66 			snprintf(buf, sizeof (buf), "ipp://%s/printers/", cups);
67 			result = strdup(buf);
68 		}
69 	}
70 
71 	if (result == NULL)
72 		result = fallback;
73 
74 	return (result);
75 }
76 
77 static char *
default_print_service()78 default_print_service()
79 {
80 	static char *result = NULL;
81 
82 	if (result == NULL) {
83 		char *service_uri = default_service_uri(DEFAULT_SERVICE_URI);
84 		uri_t *uri = NULL;
85 
86 		if (uri_from_string(service_uri, &uri) != -1)
87 			result = strdup(uri->scheme);
88 
89 		if (uri != NULL)
90 			uri_free(uri);
91 	}
92 
93 	return (result);
94 }
95 
96 static papi_status_t
service_load(service_t * svc,char * name)97 service_load(service_t *svc, char *name)
98 {
99 	papi_status_t result;
100 	char *scheme = default_print_service();
101 
102 	if (svc->so_handle != NULL)	/* already loaded */
103 		return (PAPI_OK);
104 
105 	if (name == NULL)		/* no info, can't load yet */
106 		return (PAPI_OK);
107 
108 	/* Lookup the printer in the configuration DB */
109 	svc->attributes = getprinterbyname((char *)name, NULL);
110 
111 	if (svc->attributes != NULL) {
112 		char *tmp = NULL;
113 
114 		/* Printer found (or was a URI), use the attribute data */
115 		papiAttributeListGetString(svc->attributes, NULL,
116 					"printer-uri-supported", &tmp);
117 		if (tmp != NULL)
118 			svc->name = strdup(tmp);
119 
120 		/* parse the URI and set the scheme(print service) */
121 		if (uri_from_string(svc->name, &svc->uri) != -1)
122 			scheme = (svc->uri)->scheme;
123 
124 		/* override the scheme if it was in the attributes */
125 		papiAttributeListGetString(svc->attributes, NULL,
126 					"print-service-module", &scheme);
127 
128 	} else	/* not found, assume it is the actual print service name */
129 		scheme = name;
130 
131 	result = psm_open(svc, scheme);
132 	switch (result) {
133 	case PAPI_OK:
134 		break;	/* no error */
135 	case PAPI_URI_SCHEME:
136 		result = PAPI_NOT_FOUND;
137 #ifdef DEBUG
138 		detailed_error(svc, "Unable to load service for: %s", name);
139 #endif
140 		break;
141 	default:	/* set the detailed message */
142 		detailed_error(svc, "Unable to load service (%s) for: %s",
143 				scheme, name);
144 	}
145 
146 	return (result);
147 }
148 
149 static papi_status_t
service_send_peer(service_t * svc)150 service_send_peer(service_t *svc)
151 {
152 	papi_status_t result = PAPI_OK;
153 
154 	if ((svc->peer_fd != -1) && (svc->so_handle != NULL) &&
155 	    (svc->svc_handle != NULL)) {
156 		papi_status_t (*f)();
157 
158 		f = (papi_status_t (*)())psm_sym(svc, "papiServiceSetPeer");
159 
160 		if (f != NULL)
161 			result = f(svc->svc_handle, svc->peer_fd);
162 	}
163 
164 	return (result);
165 }
166 
167 papi_status_t
service_connect(service_t * svc,char * name)168 service_connect(service_t *svc, char *name)
169 {
170 	papi_status_t result = PAPI_NOT_POSSIBLE;
171 
172 	/* if there is no print service module loaded, try and load one. */
173 	if (svc->so_handle == NULL)
174 		result = service_load(svc, name);
175 	else if ((svc->name == NULL) && (name != NULL))
176 		svc->name = strdup(name);
177 
178 	/*
179 	 * the print service module is loaded, but we don't have a service
180 	 * handle.
181 	 */
182 	if (svc->so_handle != NULL) {
183 		papi_status_t (*f)();
184 
185 		if (svc->svc_handle != NULL)	/* already connected? */
186 			return (PAPI_OK);
187 
188 		f = (papi_status_t (*)())psm_sym(svc, "papiServiceCreate");
189 
190 		if (f != NULL) {
191 			char *user = svc->user;
192 			char *password = svc->password;
193 
194 			/* if no API user, try the URI user */
195 			if ((user == NULL) && (svc->uri != NULL))
196 				user = (svc->uri)->user;
197 			/* if no API password, try the URI password */
198 			if ((password == NULL) && (svc->uri != NULL))
199 				password = (svc->uri)->password;
200 
201 			result = f(&svc->svc_handle, svc->name, user, password,
202 					(svc->authCB ? interposed_auth_callback
203 						: NULL),
204 					svc->encryption, svc);
205 			(void) service_send_peer(svc);
206 		}
207 	}
208 
209 	return (result);
210 }
211 
212 papi_status_t
papiServiceCreate(papi_service_t * handle,char * service_name,char * user_name,char * password,int (* authCB)(papi_service_t svc,void * app_data),papi_encryption_t encryption,void * app_data)213 papiServiceCreate(papi_service_t *handle, char *service_name, char *user_name,
214 		char *password,
215 		int (*authCB)(papi_service_t svc, void *app_data),
216 		papi_encryption_t encryption, void *app_data)
217 {
218 	papi_status_t result = PAPI_NOT_POSSIBLE;
219 	service_t *svc = NULL;
220 	uri_t *u = NULL;
221 
222 	if (handle == NULL)
223 		return (PAPI_BAD_ARGUMENT);
224 
225 	if ((*handle = svc = calloc(1, sizeof (*svc))) == NULL)
226 		return (PAPI_TEMPORARY_ERROR);
227 
228 	svc->peer_fd = -1;
229 
230 	if (user_name != NULL)
231 		svc->user = strdup(user_name);
232 
233 	if (password != NULL)
234 		svc->password = strdup(password);
235 
236 	svc->encryption = encryption;
237 
238 	if (authCB != NULL)
239 		svc->authCB = authCB;
240 
241 	if (app_data != NULL)
242 		svc->app_data = app_data;
243 
244 	/* If not specified, get a "default" service from the environment */
245 	if (service_name == NULL)
246 		service_name = default_service_uri(NULL);
247 
248 	if (service_name != NULL) {
249 		result = service_load(svc, service_name);
250 		/* if the psm loaded and the svc contains a URI, connect */
251 		if ((result == PAPI_OK) && (svc->uri != NULL))
252 			result = service_connect(svc, service_name);
253 	} else
254 		result = PAPI_OK;
255 
256 	return (result);
257 }
258 
259 void
papiServiceDestroy(papi_service_t handle)260 papiServiceDestroy(papi_service_t handle)
261 {
262 	if (handle != NULL) {
263 		service_t *svc = handle;
264 
265 		if (svc->so_handle != NULL) {
266 			if (svc->svc_handle != NULL) {
267 				void (*f)();
268 
269 				f = (void (*)())psm_sym(svc,
270 							"papiServiceDestroy");
271 				f(svc->svc_handle);
272 			}
273 			psm_close(svc->so_handle);
274 		}
275 		if (svc->attributes != NULL)
276 			papiAttributeListFree(svc->attributes);
277 		if (svc->name != NULL)
278 			free(svc->name);
279 		if (svc->user != NULL)
280 			free(svc->user);
281 		if (svc->password != NULL)
282 			free(svc->password);
283 		if (svc->uri != NULL)
284 			uri_free(svc->uri);
285 
286 		free(handle);
287 	}
288 }
289 
290 papi_status_t
papiServiceSetPeer(papi_service_t handle,int fd)291 papiServiceSetPeer(papi_service_t handle, int fd)
292 {
293 	papi_status_t result = PAPI_OK;
294 
295 	if (handle != NULL) {
296 		service_t *svc = handle;
297 
298 		svc->peer_fd = fd;
299 		result = service_send_peer(svc);
300 	} else
301 		result = PAPI_BAD_ARGUMENT;
302 
303 	return (result);
304 }
305 
306 papi_status_t
papiServiceSetUserName(papi_service_t handle,char * user_name)307 papiServiceSetUserName(papi_service_t handle, char *user_name)
308 {
309 	papi_status_t result = PAPI_OK;
310 
311 	if (handle != NULL) {
312 		service_t *svc = handle;
313 		papi_status_t (*f)();
314 
315 		if (svc->user != NULL)
316 			free(svc->user);
317 		if (user_name != NULL)
318 			svc->user = strdup(user_name);
319 		f = (papi_status_t (*)())psm_sym(svc, "papiServiceSetUserName");
320 		if (f != NULL)
321 			result = f(svc->svc_handle, user_name);
322 	} else
323 		result = PAPI_BAD_ARGUMENT;
324 
325 	return (result);
326 }
327 
328 papi_status_t
papiServiceSetPassword(papi_service_t handle,char * password)329 papiServiceSetPassword(papi_service_t handle, char *password)
330 {
331 	papi_status_t result = PAPI_OK;
332 
333 	if (handle != NULL) {
334 		service_t *svc = handle;
335 		papi_status_t (*f)();
336 
337 		if (svc->password != NULL)
338 			free(svc->password);
339 		if (password != NULL)
340 			svc->password = strdup(password);
341 		f = (papi_status_t (*)())psm_sym(svc, "papiServiceSetPassword");
342 		if (f != NULL)
343 			result = f(svc->svc_handle, password);
344 	} else
345 		result = PAPI_BAD_ARGUMENT;
346 
347 	return (result);
348 }
349 
350 papi_status_t
papiServiceSetEncryption(papi_service_t handle,papi_encryption_t encryption)351 papiServiceSetEncryption(papi_service_t handle, papi_encryption_t encryption)
352 {
353 	papi_status_t result = PAPI_OK;
354 
355 	if (handle != NULL) {
356 		service_t *svc = handle;
357 		papi_status_t (*f)();
358 
359 		svc->encryption = encryption;
360 		f = (papi_status_t (*)())psm_sym(svc,
361 						"papiServiceSetEncryption");
362 		if (f != NULL)
363 			result = f(svc->svc_handle, encryption);
364 	} else
365 		result = PAPI_BAD_ARGUMENT;
366 
367 	return (result);
368 }
369 
370 papi_status_t
papiServiceSetAuthCB(papi_service_t handle,int (* authCB)(papi_service_t svc,void * app_data))371 papiServiceSetAuthCB(papi_service_t handle,
372 		int (*authCB)(papi_service_t svc, void *app_data))
373 {
374 	papi_status_t result = PAPI_OK;
375 
376 	if (handle != NULL) {
377 		service_t *svc = handle;
378 		papi_status_t (*f)();
379 
380 		svc->authCB = authCB;
381 		f = (papi_status_t (*)())psm_sym(svc, "papiServiceSetAuthCB");
382 		if (f != NULL)
383 			result = f(svc->svc_handle, interposed_auth_callback);
384 	} else
385 		result = PAPI_BAD_ARGUMENT;
386 
387 	return (result);
388 }
389 
390 
391 papi_status_t
papiServiceSetAppData(papi_service_t handle,void * app_data)392 papiServiceSetAppData(papi_service_t handle, void *app_data)
393 {
394 	papi_status_t result = PAPI_OK;
395 
396 	if (handle != NULL) {
397 		service_t *svc = handle;
398 		papi_status_t (*f)();
399 
400 		svc->app_data = (void *)app_data;
401 	} else
402 		result = PAPI_BAD_ARGUMENT;
403 
404 	return (result);
405 }
406 
407 char *
papiServiceGetServiceName(papi_service_t handle)408 papiServiceGetServiceName(papi_service_t handle)
409 {
410 	char *result = NULL;
411 
412 	if (handle != NULL) {
413 		service_t *svc = handle;
414 		char *(*f)();
415 
416 		f = (char *(*)())psm_sym(svc, "papiServiceGetServiceName");
417 		if (f != NULL)
418 			result = f(svc->svc_handle);
419 		if (result == NULL)
420 			result = svc->name;
421 	}
422 
423 	return (result);
424 }
425 
426 char *
papiServiceGetUserName(papi_service_t handle)427 papiServiceGetUserName(papi_service_t handle)
428 {
429 	char *result = NULL;
430 
431 	if (handle != NULL) {
432 		service_t *svc = handle;
433 		char *(*f)();
434 
435 		f = (char *(*)())psm_sym(svc, "papiServiceGetUserName");
436 		if (f != NULL)
437 			result = f(svc->svc_handle);
438 		if (result == NULL)
439 			result = svc->user;
440 	}
441 
442 	return (result);
443 }
444 
445 char *
papiServiceGetPassword(papi_service_t handle)446 papiServiceGetPassword(papi_service_t handle)
447 {
448 	char *result = NULL;
449 
450 	if (handle != NULL) {
451 		service_t *svc = handle;
452 		char *(*f)();
453 
454 		f = (char *(*)())psm_sym(svc, "papiServiceGetPassword");
455 		if (f != NULL)
456 			result = f(svc->svc_handle);
457 		if (result == NULL)
458 			result = svc->password;
459 	}
460 
461 	return (result);
462 }
463 
464 papi_encryption_t
papiServiceGetEncryption(papi_service_t handle)465 papiServiceGetEncryption(papi_service_t handle)
466 {
467 	papi_encryption_t result = PAPI_ENCRYPT_NEVER;
468 
469 	if (handle != NULL) {
470 		service_t *svc = handle;
471 		papi_encryption_t (*f)();
472 
473 		f = (papi_encryption_t (*)())psm_sym(svc,
474 						"papiServiceGetEncryption");
475 		if (f != NULL)
476 			result = f(svc->svc_handle);
477 		if (result == PAPI_ENCRYPT_NEVER)
478 			result = svc->encryption;
479 	}
480 
481 	return (result);
482 }
483 
484 void *
papiServiceGetAppData(papi_service_t handle)485 papiServiceGetAppData(papi_service_t handle)
486 {
487 	void *result = NULL;
488 	service_t *svc = handle;
489 
490 	if (handle != NULL)
491 		result = svc->app_data;
492 
493 	return (result);
494 }
495 
496 papi_attribute_t **
papiServiceGetAttributeList(papi_service_t handle)497 papiServiceGetAttributeList(papi_service_t handle)
498 {
499 	papi_attribute_t **result = NULL;
500 	service_t *svc = handle;
501 
502 	if (handle != NULL) {
503 		papi_attribute_t **(*f)();
504 
505 		if (svc->so_handle == NULL) {
506 			char *uri = default_service_uri(DEFAULT_SERVICE_URI);
507 
508 			if (service_connect(svc, uri) != PAPI_OK)
509 				return (NULL);
510 		}
511 
512 		f = (papi_attribute_t **(*)())psm_sym(svc,
513 					"papiServiceGetAttributeList");
514 		if (f != NULL)
515 			result = f(svc->svc_handle);
516 	} else
517 		result = svc->attributes;
518 
519 	return (result);
520 }
521 
522 char *
papiServiceGetStatusMessage(papi_service_t handle)523 papiServiceGetStatusMessage(papi_service_t handle)
524 {
525 	char *result = NULL;
526 	service_t *svc = handle;
527 
528 	if (handle != NULL) {
529 		char *(*f)();
530 
531 		f = (char *(*)())psm_sym(svc, "papiServiceGetStatusMessage");
532 		if (f != NULL)
533 			result = f(svc->svc_handle);
534 	}
535 	if (result == NULL) {
536 		papiAttributeListGetString(svc->attributes, NULL,
537 					"detailed-status-message", &result);
538 	}
539 
540 	return (result);
541 }
542 
543 void
detailed_error(service_t * svc,char * fmt,...)544 detailed_error(service_t *svc, char *fmt, ...)
545 {
546 	if ((svc != NULL) && (fmt != NULL)) {
547 		va_list ap;
548 		char *message;
549 		int rv;
550 
551 		va_start(ap, fmt);
552 		rv = vasprintf(&message, fmt, ap);
553 		va_end(ap);
554 
555 		if (rv >= 0) {
556 			papiAttributeListAddString(&svc->attributes,
557 			    PAPI_ATTR_APPEND, "detailed-status-message",
558 			    message);
559 #ifdef DEBUG
560 			fprintf(stderr, "detailed_error(%s)\n", message);
561 #endif
562 			free(message);
563 		}
564 	}
565 }
566