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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * Miscellaneous Utilities
31 *
32 * slp_err: Error and information message dispatch, i18n'd
33 * slp_start_call: Marks a SLP handle as in-use
34 * slp_end_call: Marks a SLP handle as available
35 * slp_map_err: protocol to API error mapping
36 * slp_onlist: determines if a token is on a list
37 * slp_add2list: adds a token to a list
38 * slp_list_subtract: removes a token from a list
39 * slp_add_header: creates a SLP message header
40 * slp_get_length: gets the length field from a SLP header
41 * slp_set_length: sets the length field in a SLP header
42 * slp_header_get_sht: gets a 16 bit integer from a SLP header
43 * slp_header_set_sht: sets a 16 bit interger in a SLP header
44 * slp_header_length: calculates the length of a header, including the
45 * language tag
46 * slp_get_errcode: returns the error code from a SLP message
47 * slp_add_byte: encodes a byte into the given buffer
48 * slp_add_sht: encodes a 16-bit integer into the given buffer
49 * slp_add_string: encodes the given string into the given buffer
50 * slp_get_byte: decodes a byte from the given buffer
51 * slp_get_sht: decodes a 16-bit integer from the given buffer
52 * slp_get_string: decodes a string from the given buffer
53 */
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <stdarg.h>
58 #include <syslog.h>
59 #include <string.h>
60 #include <thread.h>
61 #include <synch.h>
62 #include <errno.h>
63 #include <unistd.h>
64 #include <limits.h>
65 #include <arpa/inet.h>
66 #include <libintl.h>
67 #include <slp-internal.h>
68
69 #define SLP_ERR_BUF_LEN 1024UL
70
71 /*
72 * Outputs an error message. priority is a syslog(3) priority.
73 */
74 /*ARGSUSED1*/
75 /* PRINTFLIKE4 */
slp_err(int priority,int id,char * func,char * inmsg,...)76 void slp_err(int priority, int id, char *func, char *inmsg, ...) {
77 static char buf[SLP_ERR_BUF_LEN];
78 char *p, *msg;
79 size_t len;
80 va_list ap;
81 static mutex_t loglock = DEFAULTMUTEX;
82 va_start(ap, inmsg);
83
84 (void) mutex_lock(&loglock);
85
86 /* i18n mapping */
87 msg = dgettext("libslp", inmsg);
88
89 (void) snprintf(buf, sizeof (buf), "libslp: %s: ", func);
90 len = strlen(buf);
91 p = &(buf[len]);
92 (void) vsnprintf(p, SLP_ERR_BUF_LEN - len, msg, ap);
93 va_end(ap);
94 syslog(priority, buf);
95 (void) mutex_unlock(&loglock);
96 }
97
98 /*
99 * Start and end slp calls
100 * slp_start_call returns SLP_HANDLE_IN_USE if the handle is already
101 * being used, otherwise SLP_OK.
102 */
slp_start_call(slp_handle_impl_t * hp)103 SLPError slp_start_call(slp_handle_impl_t *hp) {
104 (void) mutex_lock(&(hp->outcall_lock));
105 if (hp->pending_outcall) {
106 (void) mutex_unlock(&(hp->outcall_lock));
107 return (SLP_HANDLE_IN_USE);
108 }
109 hp->pending_outcall = SLP_TRUE;
110 (void) mutex_unlock(&(hp->outcall_lock));
111
112 hp->cancel = 0;
113 return (SLP_OK);
114 }
115
slp_end_call(slp_handle_impl_t * hp)116 void slp_end_call(slp_handle_impl_t *hp) {
117 (void) mutex_lock(&(hp->outcall_lock));
118 if (hp->close_on_end) {
119 /* SLPClose() called from callback */
120 (void) mutex_unlock(&(hp->outcall_lock));
121 slp_cleanup_handle(hp);
122 return;
123 }
124
125 hp->pending_outcall = SLP_FALSE;
126 (void) cond_signal(&(hp->outcall_cv));
127 (void) mutex_unlock(&(hp->outcall_lock));
128 }
129
130 /*
131 * Map a protocol error code to an API error code.
132 */
slp_map_err(unsigned short proto_err)133 SLPError slp_map_err(unsigned short proto_err) {
134 switch (proto_err) {
135 case 0: return (SLP_OK);
136 case 1: return (SLP_LANGUAGE_NOT_SUPPORTED);
137 case 2: return (SLP_PARSE_ERROR);
138 case 3: return (SLP_INVALID_REGISTRATION);
139 case 4: return (SLP_SCOPE_NOT_SUPPORTED);
140 case 6: return (SLP_AUTHENTICATION_ABSENT);
141 case 7: return (SLP_AUTHENTICATION_FAILED);
142 case 13: return (SLP_INVALID_UPDATE);
143 /*
144 * 9 (VER_NOT_SUPPORTED), 10 (INTERNAL_ERROR),
145 * 11 (DA_BUSY_NOW), 12 (OPTION_NOT_UNDERSTOOD),
146 * and 14 (RQST_NOT_SUPPORTED)
147 * should be handled internally by the API.
148 */
149 default: return (SLP_INTERNAL_SYSTEM_ERROR);
150 }
151 }
152
153 /*
154 * SLP List Management:
155 * SLP lists are comma separated lists of tokens. The following routines
156 * manage SLP lists, ensuring proper UTF-8 parsing.
157 */
158
159 /*
160 * If 'item' is on 'list', returns 1, otherwise 0.
161 */
slp_onlist(const char * item,const char * list)162 int slp_onlist(const char *item, const char *list) {
163 char *p;
164 for (p = (char *)list; p; p++) {
165 char *s;
166 size_t span;
167
168 s = p;
169 p = slp_utf_strchr(p, ',');
170 span = (p ? (size_t)(p - s): strlen(s));
171
172 if (strlen(item) != span) {
173 if (!p)
174 break;
175 else
176 continue;
177 }
178
179 if (strncasecmp(item, s, span) == 0)
180 return (1);
181 if (!p)
182 break;
183 }
184 return (0);
185 }
186
187 /*
188 * Adds item to *list if it is not already on it. If *list == NULL,
189 * creates a new list. When it grows the list, it will free *list,
190 * so *list must not be on the caller's stack. 'check_onlist' specifies
191 * whether to look to item on the current list. This is a small
192 * optimization for callers which are that item is not on *list, or
193 * which don't care about duplicates.
194 */
slp_add2list(const char * item,char ** list,SLPBoolean check_onlist)195 void slp_add2list(const char *item, char **list, SLPBoolean check_onlist) {
196 if (!(*list)) {
197 if (!(*list = strdup(item)))
198 slp_err(LOG_CRIT, 0, "slp_add2list", "out of memory");
199 return;
200 }
201
202 if (check_onlist)
203 /* no duplicates */
204 if (slp_onlist(item, *list))
205 return;
206
207 if (!(*list = realloc(*list, strlen(*list) + strlen(item) + 2))) {
208 slp_err(LOG_CRIT, 0, "slp_add2list", "out of memory");
209 return;
210 }
211 (void) strcat(*list, ",");
212 (void) strcat(*list, item);
213 }
214
215 /*
216 * Removes the first instance of item from *list.
217 * When it shrinks the list, it may free *list, so *list must not be on
218 * the caller's stack.
219 */
slp_list_subtract(const char * item,char ** list)220 void slp_list_subtract(const char *item, char **list) {
221 char *p, *s;
222
223 if (!*list || !slp_onlist(item, *list))
224 return;
225 /* find item's location on the list */
226 for (p = *list; p; p++) {
227 size_t span;
228
229 s = p;
230 p = slp_utf_strchr(p, ',');
231 span = (p ? (size_t)(p - s) : strlen(s));
232 if (strlen(item) != span)
233 continue;
234 if (strncasecmp(item, s, span) == 0)
235 break;
236 if (!p)
237 break;
238 }
239 if (!p && s == *list) {
240 /* item is only one on list */
241 free(*list);
242 *list = NULL;
243 return;
244 }
245 if (!p) {
246 /* last one on list; just chop it off */
247 s--;
248 *s = 0;
249 return;
250 }
251 /* either first on list, or somewhere in the middle */
252 (void) strcpy(s, p + 1);
253 }
254
255 /* SLPv2 header management */
256
257 /*
258 * Lays a SLP header into pcSendBuf, performing byte-ordering and bounds
259 * checking where necessary.
260 * pcLangTag: Language tag
261 * pcSendBuf: a buffer into which to write the composed header
262 * iSendBufSz: the size of pcSendBuf in bytes
263 * iFun: SLP V2 function number
264 * iLen: The length of the whole SLP message, in bytes
265 * piLen: a pointer to an int into which will be written the size of the
266 * header + the language tag (i.e. the offset at which the rest of
267 * the message should be written into pcSendBuf).
268 */
slp_add_header(const char * pcLangTag,char * pcSendBuf,size_t iSendBufSz,int iFun,size_t iLen,size_t * piLen)269 SLPError slp_add_header(const char *pcLangTag, char *pcSendBuf,
270 size_t iSendBufSz, int iFun,
271 size_t iLen, size_t *piLen) {
272 unsigned short us, xid;
273 static unsigned short xid_seeded = 0;
274
275 if (!xid_seeded) {
276 static mutex_t lock = DEFAULTMUTEX;
277 (void) mutex_lock(&lock);
278 if (!xid_seeded) {
279 /* generate a seed based on our PID */
280 long long pid = getpid();
281 pid *= UINT_MAX;
282 (void) seed48((unsigned short *) &pid);
283 xid_seeded = 1;
284 }
285 (void) mutex_unlock(&lock);
286 }
287 /* squish the random value into an unsigned short */
288 xid = (unsigned short) (lrand48() % USHRT_MAX);
289 xid = xid ? xid : 1; /* 0 is for DAs only */
290
291 us = (unsigned short) strlen(pcLangTag);
292 if ((SLP_HDRLEN + us) > iSendBufSz)
293 return (SLP_PARAMETER_BAD);
294
295 (void) memset(pcSendBuf, 0, SLP_HDRLEN);
296
297 slp_set_version(pcSendBuf, SLP_VERSION);
298 slp_set_function(pcSendBuf, (char)iFun);
299 slp_set_length(pcSendBuf, iLen);
300 slp_set_xid(pcSendBuf, xid);
301 slp_set_langlen(pcSendBuf, us);
302 (void) memcpy(&pcSendBuf[SLP_HDRLEN], pcLangTag, us);
303
304 *piLen = SLP_HDRLEN + us;
305 return (SLP_OK);
306 }
307
308 /*
309 * Retrieves the 24 bit int stored at 'off' offset into 'header'.
310 * Assumes 'header' is a valid SLP message header.
311 */
slp_header_get_int24(const char * header,size_t off)312 unsigned int slp_header_get_int24(const char *header, size_t off) {
313 unsigned int len;
314
315 len = ((unsigned int)(header[off] & 0xff)) << 16;
316 len += ((unsigned int)(header[off + 1] & 0xff)) << 8;
317 len += ((unsigned int)(header[off + 2] & 0xff));
318
319 return (len);
320 }
321
322 /*
323 * Sets a 24 bit int at the location in 'header' 'off' bytes
324 * offset into the header.
325 * Assumes 'header' is a valid SLP message header.
326 */
slp_header_set_int24(char * header,unsigned int len,size_t off)327 void slp_header_set_int24(char *header, unsigned int len, size_t off) {
328 header[off] = (unsigned char) ((len & 0xff0000) >> 16);
329 header[off + 1] = (unsigned char) ((len & 0xff00) >> 8);
330 header[off + 2] = (unsigned char) (len & 0xff);
331 }
332
333 /*
334 * Retrieves the 16 bit integer stored at 'off' offset into 'header'.
335 * Assumes 'header' is a valid SLP message header.
336 */
slp_header_get_sht(const char * header,size_t off)337 unsigned short slp_header_get_sht(const char *header, size_t off) {
338 unsigned short answer = 0;
339 (void) slp_get_sht(header, SLP_HDRLEN, &off, &answer);
340 return (answer);
341 }
342
343 /*
344 * Sets a 16 bit interger at the location in 'header' 'off' bytes
345 * offset into the header.
346 * Assumes 'header' is a valid SLP message header.
347 */
slp_header_set_sht(char * header,unsigned short len,size_t off)348 void slp_header_set_sht(char *header, unsigned short len, size_t off) {
349 (void) slp_add_sht(header, SLP_HDRLEN, len, &off);
350 }
351
352 /*
353 * Returns the total length of a SLP header associated with the SLP
354 * handle 'hp', including the language tag.
355 */
slp_header_length(slp_handle_impl_t * hp)356 size_t slp_header_length(slp_handle_impl_t *hp) {
357 return (SLP_HDRLEN + strlen(hp->locale));
358 }
359
360 /*
361 * Retrieves the error code for UA replies -- the errcode is always
362 * the first short after the header for these functions. 'msg' points to
363 * the beginning of a SLP header.
364 */
slp_get_errcode(char * msg)365 slp_proto_err slp_get_errcode(char *msg) {
366 unsigned short langlen, errcode;
367 size_t off, msglen;
368
369 /* make sure the reply is long enough */
370 msglen = slp_get_length(msg);
371 if (msglen < (SLP_LANGLEN + 2))
372 return (SLP_MSG_PARSE_ERROR);
373 langlen = slp_get_langlen(msg);
374 off = SLP_HDRLEN + langlen;
375
376 if (slp_get_sht(msg, msglen, &off, &errcode) != SLP_OK)
377 return (SLP_MSG_PARSE_ERROR);
378
379 return (errcode);
380 }
381
382 /*
383 * Primitive Encoding and Decoding Routines.
384 * All perform byte-ordering coversions and bounds checking.
385 */
386
slp_add_byte(char * pcBuf,size_t iBufSz,int iVal,size_t * piLen)387 SLPError slp_add_byte(char *pcBuf, size_t iBufSz, int iVal,
388 size_t *piLen) {
389 if ((*piLen + 1) > iBufSz)
390 return (SLP_PARAMETER_BAD);
391
392 pcBuf[(*piLen)++] = (unsigned char) iVal;
393 return (SLP_OK);
394 }
395
slp_add_sht(char * pcBuf,size_t iBufSz,unsigned short iVal,size_t * piLen)396 SLPError slp_add_sht(char *pcBuf, size_t iBufSz, unsigned short iVal,
397 size_t *piLen) {
398 if ((*piLen + 2) > iBufSz)
399 return (SLP_PARAMETER_BAD);
400
401 pcBuf[(*piLen)++] = (unsigned char) ((iVal & 0xFF00) >> 8);
402 pcBuf[(*piLen)++] = (unsigned char) (iVal & 0xFF);
403 return (SLP_OK);
404 }
405
slp_add_int32(char * pcBuf,size_t iBufSz,unsigned int iVal,size_t * piLen)406 SLPError slp_add_int32(char *pcBuf, size_t iBufSz, unsigned int iVal,
407 size_t *piLen) {
408 if ((*piLen + 4) > iBufSz)
409 return (SLP_PARAMETER_BAD);
410
411 pcBuf[(*piLen)++] = (unsigned char) ((iVal & 0xFF000000) >> 24);
412 pcBuf[(*piLen)++] = (unsigned char) ((iVal & 0xFF0000) >> 16);
413 pcBuf[(*piLen)++] = (unsigned char) ((iVal & 0xFF00) >> 8);
414 pcBuf[(*piLen)++] = (unsigned char) (iVal & 0xFF);
415
416 return (SLP_OK);
417 }
418
slp_add_string(char * pcBuf,size_t iBufSz,const char * pcStr,size_t * piLen)419 SLPError slp_add_string(char *pcBuf, size_t iBufSz, const char *pcStr,
420 size_t *piLen) {
421 size_t iStrLen = strlen(pcStr);
422 SLPError err = 0;
423
424 if (iStrLen > USHRT_MAX)
425 /* SLP strings are limited to 16-bit len */
426 return (SLP_PARAMETER_BAD);
427 if ((iStrLen + *piLen + 2) > iBufSz)
428 return (SLP_PARAMETER_BAD);
429
430 if ((err = slp_add_sht(pcBuf, iBufSz, (unsigned short)iStrLen, piLen))
431 != SLP_OK)
432 return (err);
433
434 (void) memcpy(&(pcBuf[*piLen]), pcStr, iStrLen);
435 *piLen += iStrLen;
436 return (SLP_OK);
437 }
438
slp_get_byte(const char * pcBuf,size_t maxlen,size_t * piOffset,int * piByte)439 SLPError slp_get_byte(const char *pcBuf, size_t maxlen,
440 size_t *piOffset, int *piByte) {
441 size_t offset = 0;
442
443 if (piOffset != NULL) {
444 if ((*piOffset+1) > maxlen)
445 return (SLP_PARSE_ERROR);
446 offset = *piOffset;
447 *piOffset += 1;
448 }
449
450 *piByte = (int)pcBuf[offset];
451 return (SLP_OK);
452 }
453
slp_get_sht(const char * pcBuf,size_t maxlen,size_t * piOffset,unsigned short * piSht)454 SLPError slp_get_sht(const char *pcBuf, size_t maxlen,
455 size_t *piOffset, unsigned short *piSht) {
456 size_t offset = 0;
457
458 if (piOffset != NULL) {
459 if ((*piOffset+2) > maxlen)
460 return (SLP_PARSE_ERROR);
461 offset = *piOffset;
462 *piOffset += 2;
463 }
464
465 *piSht = (unsigned short)
466 ((unsigned char)pcBuf[offset] & (unsigned char)0xFF);
467 *piSht <<= 8;
468 *piSht += (unsigned short)
469 ((unsigned char)pcBuf[offset+1] & (unsigned char)0xFF);
470
471 return (SLP_OK);
472 }
473
slp_get_int32(const char * pcBuf,size_t maxlen,size_t * piOffset,unsigned int * piInt)474 SLPError slp_get_int32(const char *pcBuf, size_t maxlen,
475 size_t *piOffset, unsigned int *piInt) {
476 size_t offset = 0;
477
478 if (piOffset != NULL) {
479 if ((*piOffset+4) > maxlen)
480 return (SLP_PARSE_ERROR);
481 offset = *piOffset;
482 *piOffset += 4;
483 }
484
485 *piInt = ((unsigned int)(pcBuf[offset] & 0xff)) << 24;
486 *piInt += ((unsigned int)(pcBuf[offset+1] & 0xff)) << 16;
487 *piInt += ((unsigned int)(pcBuf[offset+2] & 0xff)) << 8;
488 *piInt += ((unsigned int)(pcBuf[offset+3] & 0xff));
489
490 return (SLP_OK);
491 }
492
slp_get_string(const char * pcBuf,size_t iMaxLen,size_t * piOffset,char ** ppcString)493 SLPError slp_get_string(const char *pcBuf, size_t iMaxLen,
494 size_t *piOffset, char **ppcString) {
495 SLPError err;
496 unsigned short iLen;
497
498 *ppcString = NULL;
499 err = slp_get_sht(pcBuf, iMaxLen, piOffset, &iLen);
500 if (err)
501 return (err);
502 if ((iLen+*piOffset) > iMaxLen)
503 return (SLP_PARSE_ERROR);
504
505 if (!(*ppcString = malloc(iLen + 1))) {
506 slp_err(LOG_CRIT, 0, "slp_get_string", "out of memory");
507 return (SLP_MEMORY_ALLOC_FAILED);
508 }
509 (void) memcpy(*ppcString, pcBuf + *piOffset, iLen);
510 (*ppcString)[iLen] = 0;
511 *piOffset += iLen;
512 return (SLP_OK);
513 }
514