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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 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 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 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 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