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