| 1 | /* | 
|---|
| 2 | Unix SMB/CIFS implementation. | 
|---|
| 3 | Utility functions for Samba | 
|---|
| 4 | Copyright (C) Andrew Tridgell 1992-1999 | 
|---|
| 5 | Copyright (C) Jelmer Vernooij 2005 | 
|---|
| 6 |  | 
|---|
| 7 | This program is free software; you can redistribute it and/or modify | 
|---|
| 8 | it under the terms of the GNU General Public License as published by | 
|---|
| 9 | the Free Software Foundation; either version 3 of the License, or | 
|---|
| 10 | (at your option) any later version. | 
|---|
| 11 |  | 
|---|
| 12 | This program is distributed in the hope that it will be useful, | 
|---|
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
| 15 | GNU General Public License for more details. | 
|---|
| 16 |  | 
|---|
| 17 | You should have received a copy of the GNU General Public License | 
|---|
| 18 | along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
|---|
| 19 | */ | 
|---|
| 20 |  | 
|---|
| 21 | #ifndef _SAMBA_UTIL_H_ | 
|---|
| 22 | #define _SAMBA_UTIL_H_ | 
|---|
| 23 |  | 
|---|
| 24 | #if _SAMBA_BUILD_ == 4 | 
|---|
| 25 | #include "../lib/util/charset/charset.h" | 
|---|
| 26 | #endif | 
|---|
| 27 | #include "../lib/util/attr.h" | 
|---|
| 28 |  | 
|---|
| 29 | /* for TALLOC_CTX */ | 
|---|
| 30 | #include <talloc.h> | 
|---|
| 31 |  | 
|---|
| 32 | /** | 
|---|
| 33 | * @file | 
|---|
| 34 | * @brief Helpful macros | 
|---|
| 35 | */ | 
|---|
| 36 |  | 
|---|
| 37 | struct smbsrv_tcon; | 
|---|
| 38 |  | 
|---|
| 39 | extern const char *logfile; | 
|---|
| 40 | extern const char *panic_action; | 
|---|
| 41 |  | 
|---|
| 42 | #include "../lib/util/time.h" | 
|---|
| 43 | #include "../lib/util/data_blob.h" | 
|---|
| 44 | #include "../lib/util/xfile.h" | 
|---|
| 45 | #include "../lib/util/mutex.h" | 
|---|
| 46 | #include "../lib/util/byteorder.h" | 
|---|
| 47 | #include "../lib/util/talloc_stack.h" | 
|---|
| 48 |  | 
|---|
| 49 | /** | 
|---|
| 50 | * assert macros | 
|---|
| 51 | */ | 
|---|
| 52 | #ifdef DEVELOPER | 
|---|
| 53 | #define SMB_ASSERT(b) do { if (!(b)) { \ | 
|---|
| 54 | DEBUG(0,("PANIC: assert failed at %s(%d): %s\n", \ | 
|---|
| 55 | __FILE__, __LINE__, #b)); smb_panic("assert failed: " #b); }} while(0) | 
|---|
| 56 | #else | 
|---|
| 57 | /* redefine the assert macro for non-developer builds */ | 
|---|
| 58 | #define SMB_ASSERT(b) do { if (!(b)) { \ | 
|---|
| 59 | DEBUG(0,("PANIC: assert failed at %s(%d): %s\n", \ | 
|---|
| 60 | __FILE__, __LINE__, #b)); }} while (0) | 
|---|
| 61 | #endif | 
|---|
| 62 |  | 
|---|
| 63 | #if _SAMBA_BUILD_ == 4 | 
|---|
| 64 | #ifdef VALGRIND | 
|---|
| 65 | #define strlen(x) valgrind_strlen(x) | 
|---|
| 66 | size_t valgrind_strlen(const char *s); | 
|---|
| 67 | #endif | 
|---|
| 68 | #endif | 
|---|
| 69 |  | 
|---|
| 70 | #ifndef ABS | 
|---|
| 71 | #define ABS(a) ((a)>0?(a):(-(a))) | 
|---|
| 72 | #endif | 
|---|
| 73 |  | 
|---|
| 74 | #include "../lib/util/memory.h" | 
|---|
| 75 |  | 
|---|
| 76 | /** | 
|---|
| 77 | * Write backtrace to debug log | 
|---|
| 78 | */ | 
|---|
| 79 | _PUBLIC_ void call_backtrace(void); | 
|---|
| 80 |  | 
|---|
| 81 | /** | 
|---|
| 82 | Something really nasty happened - panic ! | 
|---|
| 83 | **/ | 
|---|
| 84 | _PUBLIC_ _NORETURN_ void smb_panic(const char *why); | 
|---|
| 85 |  | 
|---|
| 86 | #if _SAMBA_BUILD_ == 4 | 
|---|
| 87 | /** | 
|---|
| 88 | setup our fault handlers | 
|---|
| 89 | **/ | 
|---|
| 90 | _PUBLIC_ void fault_setup(const char *pname); | 
|---|
| 91 | #endif | 
|---|
| 92 |  | 
|---|
| 93 | /** | 
|---|
| 94 | register a fault handler. | 
|---|
| 95 | Should only be called once in the execution of smbd. | 
|---|
| 96 | */ | 
|---|
| 97 | _PUBLIC_ bool register_fault_handler(const char *name, void (*fault_handler)(int sig)); | 
|---|
| 98 |  | 
|---|
| 99 | /* The following definitions come from lib/util/signal.c  */ | 
|---|
| 100 |  | 
|---|
| 101 |  | 
|---|
| 102 | /** | 
|---|
| 103 | Block sigs. | 
|---|
| 104 | **/ | 
|---|
| 105 | void BlockSignals(bool block, int signum); | 
|---|
| 106 |  | 
|---|
| 107 | /** | 
|---|
| 108 | Catch a signal. This should implement the following semantics: | 
|---|
| 109 |  | 
|---|
| 110 | 1) The handler remains installed after being called. | 
|---|
| 111 | 2) The signal should be blocked during handler execution. | 
|---|
| 112 | **/ | 
|---|
| 113 | void (*CatchSignal(int signum,void (*handler)(int )))(int); | 
|---|
| 114 |  | 
|---|
| 115 | /** | 
|---|
| 116 | Ignore SIGCLD via whatever means is necessary for this OS. | 
|---|
| 117 | **/ | 
|---|
| 118 | void CatchChild(void); | 
|---|
| 119 |  | 
|---|
| 120 | /** | 
|---|
| 121 | Catch SIGCLD but leave the child around so it's status can be reaped. | 
|---|
| 122 | **/ | 
|---|
| 123 | void CatchChildLeaveStatus(void); | 
|---|
| 124 |  | 
|---|
| 125 | /* The following definitions come from lib/util/system.c  */ | 
|---|
| 126 |  | 
|---|
| 127 | /************************************************************************** | 
|---|
| 128 | A wrapper for gethostbyname() that tries avoids looking up hostnames | 
|---|
| 129 | in the root domain, which can cause dial-on-demand links to come up for no | 
|---|
| 130 | apparent reason. | 
|---|
| 131 | ****************************************************************************/ | 
|---|
| 132 | _PUBLIC_ struct hostent *sys_gethostbyname(const char *name); | 
|---|
| 133 | _PUBLIC_ struct in_addr sys_inet_makeaddr(int net, int host); | 
|---|
| 134 |  | 
|---|
| 135 | /** | 
|---|
| 136 | * Wrapper for fork used to invalid pid cache. | 
|---|
| 137 | **/ | 
|---|
| 138 | _PUBLIC_ pid_t sys_fork(void); | 
|---|
| 139 |  | 
|---|
| 140 | /** | 
|---|
| 141 | * Wrapper for getpid. Ensures we only do a system call *once*. | 
|---|
| 142 | **/ | 
|---|
| 143 | _PUBLIC_ pid_t sys_getpid(void); | 
|---|
| 144 |  | 
|---|
| 145 | /* The following definitions come from lib/util/genrand.c  */ | 
|---|
| 146 |  | 
|---|
| 147 | /** | 
|---|
| 148 | Copy any user given reseed data. | 
|---|
| 149 | **/ | 
|---|
| 150 | _PUBLIC_ void set_rand_reseed_callback(void (*fn)(void *, int *), void *); | 
|---|
| 151 |  | 
|---|
| 152 | /** | 
|---|
| 153 | * Tell the random number generator it needs to reseed. | 
|---|
| 154 | */ | 
|---|
| 155 | _PUBLIC_ void set_need_random_reseed(void); | 
|---|
| 156 |  | 
|---|
| 157 | /** | 
|---|
| 158 | Interface to the (hopefully) good crypto random number generator. | 
|---|
| 159 | Will use our internal PRNG if more than 40 bytes of random generation | 
|---|
| 160 | has been requested, otherwise tries to read from /dev/random | 
|---|
| 161 | **/ | 
|---|
| 162 | _PUBLIC_ void generate_random_buffer(uint8_t *out, int len); | 
|---|
| 163 |  | 
|---|
| 164 | /** | 
|---|
| 165 | Interface to the (hopefully) good crypto random number generator. | 
|---|
| 166 | Will always use /dev/urandom if available. | 
|---|
| 167 | **/ | 
|---|
| 168 | _PUBLIC_ void generate_secret_buffer(uint8_t *out, int len); | 
|---|
| 169 |  | 
|---|
| 170 | /** | 
|---|
| 171 | generate a single random uint32_t | 
|---|
| 172 | **/ | 
|---|
| 173 | _PUBLIC_ uint32_t generate_random(void); | 
|---|
| 174 |  | 
|---|
| 175 | /** | 
|---|
| 176 | very basic password quality checker | 
|---|
| 177 | **/ | 
|---|
| 178 | _PUBLIC_ bool check_password_quality(const char *s); | 
|---|
| 179 |  | 
|---|
| 180 | /** | 
|---|
| 181 | Use the random number generator to generate a random string. | 
|---|
| 182 | **/ | 
|---|
| 183 | _PUBLIC_ char *generate_random_str_list(TALLOC_CTX *mem_ctx, size_t len, const char *list); | 
|---|
| 184 |  | 
|---|
| 185 | /** | 
|---|
| 186 | * Generate a random text string consisting of the specified length. | 
|---|
| 187 | * The returned string will be allocated. | 
|---|
| 188 | * | 
|---|
| 189 | * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#., | 
|---|
| 190 | */ | 
|---|
| 191 | _PUBLIC_ char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len); | 
|---|
| 192 |  | 
|---|
| 193 | /** | 
|---|
| 194 | * Generate an array of unique text strings all of the same length. | 
|---|
| 195 | * The returned strings will be allocated. | 
|---|
| 196 | * Returns NULL if the number of unique combinations cannot be created. | 
|---|
| 197 | * | 
|---|
| 198 | * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#., | 
|---|
| 199 | */ | 
|---|
| 200 | _PUBLIC_ char** generate_unique_strs(TALLOC_CTX *mem_ctx, size_t len, | 
|---|
| 201 | uint32_t num); | 
|---|
| 202 |  | 
|---|
| 203 | /* The following definitions come from lib/util/dprintf.c  */ | 
|---|
| 204 | #if _SAMBA_BUILD_ == 4 | 
|---|
| 205 |  | 
|---|
| 206 | _PUBLIC_ void d_set_iconv(smb_iconv_t); | 
|---|
| 207 | _PUBLIC_ int d_vfprintf(FILE *f, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0); | 
|---|
| 208 | _PUBLIC_ int d_fprintf(FILE *f, const char *format, ...) PRINTF_ATTRIBUTE(2,3); | 
|---|
| 209 | _PUBLIC_ int d_printf(const char *format, ...) PRINTF_ATTRIBUTE(1,2); | 
|---|
| 210 | _PUBLIC_ void display_set_stderr(void); | 
|---|
| 211 | #endif | 
|---|
| 212 |  | 
|---|
| 213 | /* The following definitions come from lib/util/util_str.c  */ | 
|---|
| 214 |  | 
|---|
| 215 | bool next_token_talloc(TALLOC_CTX *ctx, | 
|---|
| 216 | const char **ptr, | 
|---|
| 217 | char **pp_buff, | 
|---|
| 218 | const char *sep); | 
|---|
| 219 |  | 
|---|
| 220 | /** | 
|---|
| 221 | * Get the next token from a string, return false if none found.  Handles | 
|---|
| 222 | * double-quotes.  This version does not trim leading separator characters | 
|---|
| 223 | * before looking for a token. | 
|---|
| 224 | */ | 
|---|
| 225 | bool next_token_no_ltrim_talloc(TALLOC_CTX *ctx, | 
|---|
| 226 | const char **ptr, | 
|---|
| 227 | char **pp_buff, | 
|---|
| 228 | const char *sep); | 
|---|
| 229 |  | 
|---|
| 230 |  | 
|---|
| 231 | /** | 
|---|
| 232 | Trim the specified elements off the front and back of a string. | 
|---|
| 233 | **/ | 
|---|
| 234 | _PUBLIC_ bool trim_string(char *s, const char *front, const char *back); | 
|---|
| 235 |  | 
|---|
| 236 | /** | 
|---|
| 237 | Find the number of 'c' chars in a string | 
|---|
| 238 | **/ | 
|---|
| 239 | _PUBLIC_ _PURE_ size_t count_chars(const char *s, char c); | 
|---|
| 240 |  | 
|---|
| 241 | /** | 
|---|
| 242 | Safe string copy into a known length string. maxlength does not | 
|---|
| 243 | include the terminating zero. | 
|---|
| 244 | **/ | 
|---|
| 245 | _PUBLIC_ char *safe_strcpy(char *dest,const char *src, size_t maxlength); | 
|---|
| 246 |  | 
|---|
| 247 | /** | 
|---|
| 248 | Safe string cat into a string. maxlength does not | 
|---|
| 249 | include the terminating zero. | 
|---|
| 250 | **/ | 
|---|
| 251 | _PUBLIC_ char *safe_strcat(char *dest, const char *src, size_t maxlength); | 
|---|
| 252 |  | 
|---|
| 253 | /** | 
|---|
| 254 | Routine to get hex characters and turn them into a 16 byte array. | 
|---|
| 255 | the array can be variable length, and any non-hex-numeric | 
|---|
| 256 | characters are skipped.  "0xnn" or "0Xnn" is specially catered | 
|---|
| 257 | for. | 
|---|
| 258 |  | 
|---|
| 259 | valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n" | 
|---|
| 260 |  | 
|---|
| 261 |  | 
|---|
| 262 | **/ | 
|---|
| 263 | _PUBLIC_ size_t strhex_to_str(char *p, size_t p_len, const char *strhex, size_t strhex_len); | 
|---|
| 264 |  | 
|---|
| 265 | /** | 
|---|
| 266 | * Parse a hex string and return a data blob. | 
|---|
| 267 | */ | 
|---|
| 268 | _PUBLIC_ _PURE_ DATA_BLOB strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *strhex) ; | 
|---|
| 269 |  | 
|---|
| 270 | /** | 
|---|
| 271 | * Routine to print a buffer as HEX digits, into an allocated string. | 
|---|
| 272 | */ | 
|---|
| 273 | _PUBLIC_ void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer); | 
|---|
| 274 |  | 
|---|
| 275 | /** | 
|---|
| 276 | * talloc version of hex_encode() | 
|---|
| 277 | */ | 
|---|
| 278 | _PUBLIC_ char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len); | 
|---|
| 279 |  | 
|---|
| 280 | /** | 
|---|
| 281 | Substitute a string for a pattern in another string. Make sure there is | 
|---|
| 282 | enough room! | 
|---|
| 283 |  | 
|---|
| 284 | This routine looks for pattern in s and replaces it with | 
|---|
| 285 | insert. It may do multiple replacements. | 
|---|
| 286 |  | 
|---|
| 287 | Any of " ; ' $ or ` in the insert string are replaced with _ | 
|---|
| 288 | if len==0 then the string cannot be extended. This is different from the old | 
|---|
| 289 | use of len==0 which was for no length checks to be done. | 
|---|
| 290 | **/ | 
|---|
| 291 | _PUBLIC_ void string_sub(char *s,const char *pattern, const char *insert, size_t len); | 
|---|
| 292 |  | 
|---|
| 293 |  | 
|---|
| 294 | _PUBLIC_ char *string_sub_talloc(TALLOC_CTX *mem_ctx, const char *s, | 
|---|
| 295 | const char *pattern, const char *insert); | 
|---|
| 296 |  | 
|---|
| 297 | /** | 
|---|
| 298 | Similar to string_sub() but allows for any character to be substituted. | 
|---|
| 299 | Use with caution! | 
|---|
| 300 | if len==0 then the string cannot be extended. This is different from the old | 
|---|
| 301 | use of len==0 which was for no length checks to be done. | 
|---|
| 302 | **/ | 
|---|
| 303 | _PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len); | 
|---|
| 304 |  | 
|---|
| 305 | /** | 
|---|
| 306 | Unescape a URL encoded string, in place. | 
|---|
| 307 | **/ | 
|---|
| 308 | _PUBLIC_ void rfc1738_unescape(char *buf); | 
|---|
| 309 |  | 
|---|
| 310 |  | 
|---|
| 311 | /** | 
|---|
| 312 | * rfc1738_escape | 
|---|
| 313 | * Returns a static buffer that contains the RFC | 
|---|
| 314 | * 1738 compliant, escaped version of the given url. (escapes unsafe and % characters) | 
|---|
| 315 | **/ | 
|---|
| 316 | _PUBLIC_ char *rfc1738_escape(TALLOC_CTX *mem_ctx, const char *url); | 
|---|
| 317 |  | 
|---|
| 318 | /** | 
|---|
| 319 | * rfc1738_escape_unescaped | 
|---|
| 320 | * | 
|---|
| 321 | * Returns a static buffer that contains | 
|---|
| 322 | * the RFC 1738 compliant, escaped version of the given url (escapes unsafe chars only) | 
|---|
| 323 | **/ | 
|---|
| 324 | _PUBLIC_ char *rfc1738_escape_unescaped(TALLOC_CTX *mem_ctx, const char *url); | 
|---|
| 325 |  | 
|---|
| 326 | /** | 
|---|
| 327 | * rfc1738_escape_part | 
|---|
| 328 | * Returns a static buffer that contains the RFC | 
|---|
| 329 | * 1738 compliant, escaped version of the given url segment. (escapes | 
|---|
| 330 | * unsafe, reserved and % chars) It would mangle the :// in http://, | 
|---|
| 331 | * and mangle paths (because of /). | 
|---|
| 332 | **/ | 
|---|
| 333 | _PUBLIC_ char *rfc1738_escape_part(TALLOC_CTX *mem_ctx, const char *url); | 
|---|
| 334 |  | 
|---|
| 335 | /** | 
|---|
| 336 | format a string into length-prefixed dotted domain format, as used in NBT | 
|---|
| 337 | and in some ADS structures | 
|---|
| 338 | **/ | 
|---|
| 339 | _PUBLIC_ const char *str_format_nbt_domain(TALLOC_CTX *mem_ctx, const char *s); | 
|---|
| 340 |  | 
|---|
| 341 | /** | 
|---|
| 342 | * Add a string to an array of strings. | 
|---|
| 343 | * | 
|---|
| 344 | * num should be a pointer to an integer that holds the current | 
|---|
| 345 | * number of elements in strings. It will be updated by this function. | 
|---|
| 346 | */ | 
|---|
| 347 | _PUBLIC_ bool add_string_to_array(TALLOC_CTX *mem_ctx, | 
|---|
| 348 | const char *str, const char ***strings, int *num); | 
|---|
| 349 |  | 
|---|
| 350 | /** | 
|---|
| 351 | varient of strcmp() that handles NULL ptrs | 
|---|
| 352 | **/ | 
|---|
| 353 | _PUBLIC_ int strcmp_safe(const char *s1, const char *s2); | 
|---|
| 354 |  | 
|---|
| 355 | /** | 
|---|
| 356 | return the number of bytes occupied by a buffer in ASCII format | 
|---|
| 357 | the result includes the null termination | 
|---|
| 358 | limited by 'n' bytes | 
|---|
| 359 | **/ | 
|---|
| 360 | _PUBLIC_ size_t ascii_len_n(const char *src, size_t n); | 
|---|
| 361 |  | 
|---|
| 362 | /** | 
|---|
| 363 | Set a boolean variable from the text value stored in the passed string. | 
|---|
| 364 | Returns true in success, false if the passed string does not correctly | 
|---|
| 365 | represent a boolean. | 
|---|
| 366 | **/ | 
|---|
| 367 | _PUBLIC_ bool set_boolean(const char *boolean_string, bool *boolean); | 
|---|
| 368 |  | 
|---|
| 369 | /** | 
|---|
| 370 | * Parse a string containing a boolean value. | 
|---|
| 371 | * | 
|---|
| 372 | * val will be set to the read value. | 
|---|
| 373 | * | 
|---|
| 374 | * @retval true if a boolean value was parsed, false otherwise. | 
|---|
| 375 | */ | 
|---|
| 376 | _PUBLIC_ bool conv_str_bool(const char * str, bool * val); | 
|---|
| 377 |  | 
|---|
| 378 | #if _SAMBA_BUILD_ == 4 | 
|---|
| 379 | /** | 
|---|
| 380 | * Convert a size specification like 16K into an integral number of bytes. | 
|---|
| 381 | **/ | 
|---|
| 382 | _PUBLIC_ bool conv_str_size(const char * str, uint64_t * val); | 
|---|
| 383 | #endif | 
|---|
| 384 |  | 
|---|
| 385 | /** | 
|---|
| 386 | * Parse a uint64_t value from a string | 
|---|
| 387 | * | 
|---|
| 388 | * val will be set to the value read. | 
|---|
| 389 | * | 
|---|
| 390 | * @retval true if parsing was successful, false otherwise | 
|---|
| 391 | */ | 
|---|
| 392 | _PUBLIC_ bool conv_str_u64(const char * str, uint64_t * val); | 
|---|
| 393 |  | 
|---|
| 394 | /** | 
|---|
| 395 | return the number of bytes occupied by a buffer in CH_UTF16 format | 
|---|
| 396 | the result includes the null termination | 
|---|
| 397 | **/ | 
|---|
| 398 | _PUBLIC_ size_t utf16_len(const void *buf); | 
|---|
| 399 |  | 
|---|
| 400 | /** | 
|---|
| 401 | return the number of bytes occupied by a buffer in CH_UTF16 format | 
|---|
| 402 | the result includes the null termination | 
|---|
| 403 | limited by 'n' bytes | 
|---|
| 404 | **/ | 
|---|
| 405 | _PUBLIC_ size_t utf16_len_n(const void *src, size_t n); | 
|---|
| 406 | _PUBLIC_ size_t ucs2_align(const void *base_ptr, const void *p, int flags); | 
|---|
| 407 |  | 
|---|
| 408 | /** | 
|---|
| 409 | Do a case-insensitive, whitespace-ignoring string compare. | 
|---|
| 410 | **/ | 
|---|
| 411 | _PUBLIC_ int strwicmp(const char *psz1, const char *psz2); | 
|---|
| 412 |  | 
|---|
| 413 | /** | 
|---|
| 414 | String replace. | 
|---|
| 415 | **/ | 
|---|
| 416 | _PUBLIC_ void string_replace(char *s, char oldc, char newc); | 
|---|
| 417 |  | 
|---|
| 418 | /** | 
|---|
| 419 | * Compare 2 strings. | 
|---|
| 420 | * | 
|---|
| 421 | * @note The comparison is case-insensitive. | 
|---|
| 422 | **/ | 
|---|
| 423 | _PUBLIC_ bool strequal(const char *s1, const char *s2); | 
|---|
| 424 |  | 
|---|
| 425 | /* The following definitions come from lib/util/util_strlist.c  */ | 
|---|
| 426 |  | 
|---|
| 427 | /* separators for lists */ | 
|---|
| 428 | #ifndef LIST_SEP | 
|---|
| 429 | #define LIST_SEP " \t,\n\r" | 
|---|
| 430 | #endif | 
|---|
| 431 |  | 
|---|
| 432 | /** | 
|---|
| 433 | build an empty (only NULL terminated) list of strings (for expansion with str_list_add() etc) | 
|---|
| 434 | */ | 
|---|
| 435 | _PUBLIC_ char **str_list_make_empty(TALLOC_CTX *mem_ctx); | 
|---|
| 436 |  | 
|---|
| 437 | /** | 
|---|
| 438 | place the only element 'entry' into a new, NULL terminated string list | 
|---|
| 439 | */ | 
|---|
| 440 | _PUBLIC_ char **str_list_make_single(TALLOC_CTX *mem_ctx, | 
|---|
| 441 | const char *entry); | 
|---|
| 442 |  | 
|---|
| 443 | /** | 
|---|
| 444 | build a null terminated list of strings from a input string and a | 
|---|
| 445 | separator list. The separator list must contain characters less than | 
|---|
| 446 | or equal to 0x2f for this to work correctly on multi-byte strings | 
|---|
| 447 | */ | 
|---|
| 448 | _PUBLIC_ char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, | 
|---|
| 449 | const char *sep); | 
|---|
| 450 |  | 
|---|
| 451 | /** | 
|---|
| 452 | * build a null terminated list of strings from an argv-like input string | 
|---|
| 453 | * Entries are seperated by spaces and can be enclosed by quotes. | 
|---|
| 454 | * Does NOT support escaping | 
|---|
| 455 | */ | 
|---|
| 456 | _PUBLIC_ char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep); | 
|---|
| 457 |  | 
|---|
| 458 | /** | 
|---|
| 459 | * join a list back to one string | 
|---|
| 460 | */ | 
|---|
| 461 | _PUBLIC_ char *str_list_join(TALLOC_CTX *mem_ctx, const char **list, char seperator); | 
|---|
| 462 |  | 
|---|
| 463 | /** join a list back to one (shell-like) string; entries | 
|---|
| 464 | * seperated by spaces, using quotes where necessary */ | 
|---|
| 465 | _PUBLIC_ char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char sep); | 
|---|
| 466 |  | 
|---|
| 467 | /** | 
|---|
| 468 | return the number of elements in a string list | 
|---|
| 469 | */ | 
|---|
| 470 | _PUBLIC_ size_t str_list_length(const char * const *list); | 
|---|
| 471 |  | 
|---|
| 472 | /** | 
|---|
| 473 | copy a string list | 
|---|
| 474 | */ | 
|---|
| 475 | _PUBLIC_ char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list); | 
|---|
| 476 |  | 
|---|
| 477 | /** | 
|---|
| 478 | Return true if all the elements of the list match exactly. | 
|---|
| 479 | */ | 
|---|
| 480 | _PUBLIC_ bool str_list_equal(const char **list1, const char **list2); | 
|---|
| 481 |  | 
|---|
| 482 | /** | 
|---|
| 483 | add an entry to a string list | 
|---|
| 484 | */ | 
|---|
| 485 | _PUBLIC_ const char **str_list_add(const char **list, const char *s); | 
|---|
| 486 |  | 
|---|
| 487 | /** | 
|---|
| 488 | remove an entry from a string list | 
|---|
| 489 | */ | 
|---|
| 490 | _PUBLIC_ void str_list_remove(const char **list, const char *s); | 
|---|
| 491 |  | 
|---|
| 492 | /** | 
|---|
| 493 | return true if a string is in a list | 
|---|
| 494 | */ | 
|---|
| 495 | _PUBLIC_ bool str_list_check(const char **list, const char *s); | 
|---|
| 496 |  | 
|---|
| 497 | /** | 
|---|
| 498 | return true if a string is in a list, case insensitively | 
|---|
| 499 | */ | 
|---|
| 500 | _PUBLIC_ bool str_list_check_ci(const char **list, const char *s); | 
|---|
| 501 | /** | 
|---|
| 502 | append one list to another - expanding list1 | 
|---|
| 503 | */ | 
|---|
| 504 | _PUBLIC_ const char **str_list_append(const char **list1, | 
|---|
| 505 | const char * const *list2); | 
|---|
| 506 |  | 
|---|
| 507 | /** | 
|---|
| 508 | remove duplicate elements from a list | 
|---|
| 509 | */ | 
|---|
| 510 | _PUBLIC_ const char **str_list_unique(const char **list); | 
|---|
| 511 |  | 
|---|
| 512 | /* | 
|---|
| 513 | very useful when debugging complex list related code | 
|---|
| 514 | */ | 
|---|
| 515 | _PUBLIC_ void str_list_show(const char **list); | 
|---|
| 516 |  | 
|---|
| 517 |  | 
|---|
| 518 | /** | 
|---|
| 519 | append one list to another - expanding list1 | 
|---|
| 520 | this assumes the elements of list2 are const pointers, so we can re-use them | 
|---|
| 521 | */ | 
|---|
| 522 | _PUBLIC_ const char **str_list_append_const(const char **list1, | 
|---|
| 523 | const char **list2); | 
|---|
| 524 |  | 
|---|
| 525 | /** | 
|---|
| 526 | add an entry to a string list | 
|---|
| 527 | this assumes s will not change | 
|---|
| 528 | */ | 
|---|
| 529 | _PUBLIC_ const char **str_list_add_const(const char **list, const char *s); | 
|---|
| 530 |  | 
|---|
| 531 | /** | 
|---|
| 532 | copy a string list | 
|---|
| 533 | this assumes list will not change | 
|---|
| 534 | */ | 
|---|
| 535 | _PUBLIC_ const char **str_list_copy_const(TALLOC_CTX *mem_ctx, | 
|---|
| 536 | const char **list); | 
|---|
| 537 |  | 
|---|
| 538 |  | 
|---|
| 539 | /* The following definitions come from lib/util/util_file.c  */ | 
|---|
| 540 |  | 
|---|
| 541 |  | 
|---|
| 542 | /** | 
|---|
| 543 | read a line from a file with possible \ continuation chars. | 
|---|
| 544 | Blanks at the start or end of a line are stripped. | 
|---|
| 545 | The string will be allocated if s2 is NULL | 
|---|
| 546 | **/ | 
|---|
| 547 | _PUBLIC_ char *fgets_slash(char *s2,int maxlen,XFILE *f); | 
|---|
| 548 |  | 
|---|
| 549 | /** | 
|---|
| 550 | * Read one line (data until next newline or eof) and allocate it | 
|---|
| 551 | */ | 
|---|
| 552 | _PUBLIC_ char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint); | 
|---|
| 553 |  | 
|---|
| 554 | /** | 
|---|
| 555 | load a file into memory from a fd. | 
|---|
| 556 | **/ | 
|---|
| 557 | _PUBLIC_ char *fd_load(int fd, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx); | 
|---|
| 558 |  | 
|---|
| 559 |  | 
|---|
| 560 | char **file_lines_parse(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx); | 
|---|
| 561 |  | 
|---|
| 562 | /** | 
|---|
| 563 | load a file into memory | 
|---|
| 564 | **/ | 
|---|
| 565 | _PUBLIC_ char *file_load(const char *fname, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx); | 
|---|
| 566 |  | 
|---|
| 567 | /** | 
|---|
| 568 | mmap (if possible) or read a file | 
|---|
| 569 | **/ | 
|---|
| 570 | _PUBLIC_ void *map_file(const char *fname, size_t size); | 
|---|
| 571 |  | 
|---|
| 572 | /** | 
|---|
| 573 | load a file into memory and return an array of pointers to lines in the file | 
|---|
| 574 | must be freed with talloc_free(). | 
|---|
| 575 | **/ | 
|---|
| 576 | _PUBLIC_ char **file_lines_load(const char *fname, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx); | 
|---|
| 577 |  | 
|---|
| 578 | /** | 
|---|
| 579 | load a fd into memory and return an array of pointers to lines in the file | 
|---|
| 580 | must be freed with talloc_free(). If convert is true calls unix_to_dos on | 
|---|
| 581 | the list. | 
|---|
| 582 | **/ | 
|---|
| 583 | _PUBLIC_ char **fd_lines_load(int fd, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx); | 
|---|
| 584 |  | 
|---|
| 585 | /** | 
|---|
| 586 | take a list of lines and modify them to produce a list where \ continues | 
|---|
| 587 | a line | 
|---|
| 588 | **/ | 
|---|
| 589 | _PUBLIC_ void file_lines_slashcont(char **lines); | 
|---|
| 590 |  | 
|---|
| 591 | /** | 
|---|
| 592 | save a lump of data into a file. Mostly used for debugging | 
|---|
| 593 | */ | 
|---|
| 594 | _PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length); | 
|---|
| 595 | _PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0); | 
|---|
| 596 | _PUBLIC_ int fdprintf(int fd, const char *format, ...) PRINTF_ATTRIBUTE(2,3); | 
|---|
| 597 | _PUBLIC_ bool large_file_support(const char *path); | 
|---|
| 598 |  | 
|---|
| 599 | /* The following definitions come from lib/util/util.c  */ | 
|---|
| 600 |  | 
|---|
| 601 |  | 
|---|
| 602 | /** | 
|---|
| 603 | Find a suitable temporary directory. The result should be copied immediately | 
|---|
| 604 | as it may be overwritten by a subsequent call. | 
|---|
| 605 | **/ | 
|---|
| 606 | _PUBLIC_ const char *tmpdir(void); | 
|---|
| 607 |  | 
|---|
| 608 | /** | 
|---|
| 609 | Check if a file exists - call vfs_file_exist for samba files. | 
|---|
| 610 | **/ | 
|---|
| 611 | _PUBLIC_ bool file_exist(const char *fname); | 
|---|
| 612 |  | 
|---|
| 613 | /** | 
|---|
| 614 | Check a files mod time. | 
|---|
| 615 | **/ | 
|---|
| 616 | _PUBLIC_ time_t file_modtime(const char *fname); | 
|---|
| 617 |  | 
|---|
| 618 | /** | 
|---|
| 619 | Check if a directory exists. | 
|---|
| 620 | **/ | 
|---|
| 621 | _PUBLIC_ bool directory_exist(const char *dname); | 
|---|
| 622 |  | 
|---|
| 623 | /** | 
|---|
| 624 | * Try to create the specified directory if it didn't exist. | 
|---|
| 625 | * | 
|---|
| 626 | * @retval true if the directory already existed and has the right permissions | 
|---|
| 627 | * or was successfully created. | 
|---|
| 628 | */ | 
|---|
| 629 | _PUBLIC_ bool directory_create_or_exist(const char *dname, uid_t uid, | 
|---|
| 630 | mode_t dir_perms); | 
|---|
| 631 |  | 
|---|
| 632 | /** | 
|---|
| 633 | Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, | 
|---|
| 634 | else | 
|---|
| 635 | if SYSV use O_NDELAY | 
|---|
| 636 | if BSD use FNDELAY | 
|---|
| 637 | **/ | 
|---|
| 638 | _PUBLIC_ int set_blocking(int fd, bool set); | 
|---|
| 639 |  | 
|---|
| 640 | /** | 
|---|
| 641 | Sleep for a specified number of milliseconds. | 
|---|
| 642 | **/ | 
|---|
| 643 | _PUBLIC_ void msleep(unsigned int t); | 
|---|
| 644 |  | 
|---|
| 645 | /** | 
|---|
| 646 | Get my own name, return in talloc'ed storage. | 
|---|
| 647 | **/ | 
|---|
| 648 | _PUBLIC_ char* get_myname(TALLOC_CTX *mem_ctx); | 
|---|
| 649 |  | 
|---|
| 650 | /** | 
|---|
| 651 | Return true if a string could be a pure IP address. | 
|---|
| 652 | **/ | 
|---|
| 653 | _PUBLIC_ bool is_ipaddress(const char *str); | 
|---|
| 654 |  | 
|---|
| 655 | /** | 
|---|
| 656 | Interpret an internet address or name into an IP address in 4 byte form. | 
|---|
| 657 | **/ | 
|---|
| 658 | _PUBLIC_ uint32_t interpret_addr(const char *str); | 
|---|
| 659 |  | 
|---|
| 660 | /** | 
|---|
| 661 | A convenient addition to interpret_addr(). | 
|---|
| 662 | **/ | 
|---|
| 663 | _PUBLIC_ struct in_addr interpret_addr2(const char *str); | 
|---|
| 664 |  | 
|---|
| 665 | /** | 
|---|
| 666 | Check if an IP is the 0.0.0.0. | 
|---|
| 667 | **/ | 
|---|
| 668 | _PUBLIC_ bool is_zero_ip_v4(struct in_addr ip); | 
|---|
| 669 |  | 
|---|
| 670 | /** | 
|---|
| 671 | Are two IPs on the same subnet? | 
|---|
| 672 | **/ | 
|---|
| 673 | _PUBLIC_ bool same_net_v4(struct in_addr ip1,struct in_addr ip2,struct in_addr mask); | 
|---|
| 674 |  | 
|---|
| 675 | _PUBLIC_ bool is_ipaddress_v4(const char *str); | 
|---|
| 676 |  | 
|---|
| 677 | /** | 
|---|
| 678 | Check if a process exists. Does this work on all unixes? | 
|---|
| 679 | **/ | 
|---|
| 680 | _PUBLIC_ bool process_exists_by_pid(pid_t pid); | 
|---|
| 681 |  | 
|---|
| 682 | /** | 
|---|
| 683 | Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping | 
|---|
| 684 | is dealt with in posix.c | 
|---|
| 685 | **/ | 
|---|
| 686 | _PUBLIC_ bool fcntl_lock(int fd, int op, off_t offset, off_t count, int type); | 
|---|
| 687 |  | 
|---|
| 688 | /** | 
|---|
| 689 | * Write dump of binary data to the log file. | 
|---|
| 690 | * | 
|---|
| 691 | * The data is only written if the log level is at least level. | 
|---|
| 692 | */ | 
|---|
| 693 | _PUBLIC_ void dump_data(int level, const uint8_t *buf,int len); | 
|---|
| 694 |  | 
|---|
| 695 | /** | 
|---|
| 696 | * Write dump of binary data to the log file. | 
|---|
| 697 | * | 
|---|
| 698 | * The data is only written if the log level is at least level. | 
|---|
| 699 | * 16 zero bytes in a row are ommited | 
|---|
| 700 | */ | 
|---|
| 701 | _PUBLIC_ void dump_data_skip_zeros(int level, const uint8_t *buf, int len); | 
|---|
| 702 |  | 
|---|
| 703 | /** | 
|---|
| 704 | malloc that aborts with smb_panic on fail or zero size. | 
|---|
| 705 | **/ | 
|---|
| 706 | _PUBLIC_ void *smb_xmalloc(size_t size); | 
|---|
| 707 |  | 
|---|
| 708 | /** | 
|---|
| 709 | Memdup with smb_panic on fail. | 
|---|
| 710 | **/ | 
|---|
| 711 | _PUBLIC_ void *smb_xmemdup(const void *p, size_t size); | 
|---|
| 712 |  | 
|---|
| 713 | /** | 
|---|
| 714 | strdup that aborts on malloc fail. | 
|---|
| 715 | **/ | 
|---|
| 716 | _PUBLIC_ char *smb_xstrdup(const char *s); | 
|---|
| 717 |  | 
|---|
| 718 | char *smb_xstrndup(const char *s, size_t n); | 
|---|
| 719 |  | 
|---|
| 720 | /** | 
|---|
| 721 | Like strdup but for memory. | 
|---|
| 722 | **/ | 
|---|
| 723 | _PUBLIC_ void *memdup(const void *p, size_t size); | 
|---|
| 724 |  | 
|---|
| 725 | /** | 
|---|
| 726 | * Write a password to the log file. | 
|---|
| 727 | * | 
|---|
| 728 | * @note Only actually does something if DEBUG_PASSWORD was defined during | 
|---|
| 729 | * compile-time. | 
|---|
| 730 | */ | 
|---|
| 731 | _PUBLIC_ void dump_data_pw(const char *msg, const uint8_t * data, size_t len); | 
|---|
| 732 |  | 
|---|
| 733 | /** | 
|---|
| 734 | * see if a range of memory is all zero. A NULL pointer is considered | 
|---|
| 735 | * to be all zero | 
|---|
| 736 | */ | 
|---|
| 737 | _PUBLIC_ bool all_zero(const uint8_t *ptr, size_t size); | 
|---|
| 738 |  | 
|---|
| 739 | /** | 
|---|
| 740 | realloc an array, checking for integer overflow in the array size | 
|---|
| 741 | */ | 
|---|
| 742 | _PUBLIC_ void *realloc_array(void *ptr, size_t el_size, unsigned count, bool free_on_fail); | 
|---|
| 743 |  | 
|---|
| 744 | void *malloc_array(size_t el_size, unsigned int count); | 
|---|
| 745 |  | 
|---|
| 746 | /* The following definitions come from lib/util/fsusage.c  */ | 
|---|
| 747 |  | 
|---|
| 748 |  | 
|---|
| 749 | /** | 
|---|
| 750 | * Retrieve amount of free disk space. | 
|---|
| 751 | * this does all of the system specific guff to get the free disk space. | 
|---|
| 752 | * It is derived from code in the GNU fileutils package, but has been | 
|---|
| 753 | * considerably mangled for use here | 
|---|
| 754 | * | 
|---|
| 755 | * results are returned in *dfree and *dsize, in 512 byte units | 
|---|
| 756 | */ | 
|---|
| 757 | _PUBLIC_ int sys_fsusage(const char *path, uint64_t *dfree, uint64_t *dsize); | 
|---|
| 758 |  | 
|---|
| 759 | /* The following definitions come from lib/util/ms_fnmatch.c  */ | 
|---|
| 760 |  | 
|---|
| 761 |  | 
|---|
| 762 | /** | 
|---|
| 763 | * @file | 
|---|
| 764 | * @brief MS-style Filename matching | 
|---|
| 765 | */ | 
|---|
| 766 |  | 
|---|
| 767 | #if _SAMBA_BUILD_ == 4 | 
|---|
| 768 | /* protocol types. It assumes that higher protocols include lower protocols | 
|---|
| 769 | as subsets. FIXME: Move to one of the smb-specific headers */ | 
|---|
| 770 | enum protocol_types { | 
|---|
| 771 | PROTOCOL_NONE, | 
|---|
| 772 | PROTOCOL_CORE, | 
|---|
| 773 | PROTOCOL_COREPLUS, | 
|---|
| 774 | PROTOCOL_LANMAN1, | 
|---|
| 775 | PROTOCOL_LANMAN2, | 
|---|
| 776 | PROTOCOL_NT1, | 
|---|
| 777 | PROTOCOL_SMB2 | 
|---|
| 778 | }; | 
|---|
| 779 |  | 
|---|
| 780 | int ms_fnmatch(const char *pattern, const char *string, enum protocol_types protocol); | 
|---|
| 781 |  | 
|---|
| 782 | /** a generic fnmatch function - uses for non-CIFS pattern matching */ | 
|---|
| 783 | int gen_fnmatch(const char *pattern, const char *string); | 
|---|
| 784 | #endif | 
|---|
| 785 |  | 
|---|
| 786 | /* The following definitions come from lib/util/mutex.c  */ | 
|---|
| 787 |  | 
|---|
| 788 |  | 
|---|
| 789 | /** | 
|---|
| 790 | register a set of mutex/rwlock handlers. | 
|---|
| 791 | Should only be called once in the execution of smbd. | 
|---|
| 792 | */ | 
|---|
| 793 | _PUBLIC_ bool register_mutex_handlers(const char *name, struct mutex_ops *ops); | 
|---|
| 794 |  | 
|---|
| 795 | /* The following definitions come from lib/util/idtree.c  */ | 
|---|
| 796 |  | 
|---|
| 797 |  | 
|---|
| 798 | /** | 
|---|
| 799 | initialise a idr tree. The context return value must be passed to | 
|---|
| 800 | all subsequent idr calls. To destroy the idr tree use talloc_free() | 
|---|
| 801 | on this context | 
|---|
| 802 | */ | 
|---|
| 803 | _PUBLIC_ struct idr_context *idr_init(TALLOC_CTX *mem_ctx); | 
|---|
| 804 |  | 
|---|
| 805 | /** | 
|---|
| 806 | allocate the next available id, and assign 'ptr' into its slot. | 
|---|
| 807 | you can retrieve later this pointer using idr_find() | 
|---|
| 808 | */ | 
|---|
| 809 | _PUBLIC_ int idr_get_new(struct idr_context *idp, void *ptr, int limit); | 
|---|
| 810 |  | 
|---|
| 811 | /** | 
|---|
| 812 | allocate a new id, giving the first available value greater than or | 
|---|
| 813 | equal to the given starting id | 
|---|
| 814 | */ | 
|---|
| 815 | _PUBLIC_ int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit); | 
|---|
| 816 |  | 
|---|
| 817 | /** | 
|---|
| 818 | allocate a new id randomly in the given range | 
|---|
| 819 | */ | 
|---|
| 820 | _PUBLIC_ int idr_get_new_random(struct idr_context *idp, void *ptr, int limit); | 
|---|
| 821 |  | 
|---|
| 822 | /** | 
|---|
| 823 | find a pointer value previously set with idr_get_new given an id | 
|---|
| 824 | */ | 
|---|
| 825 | _PUBLIC_ void *idr_find(struct idr_context *idp, int id); | 
|---|
| 826 |  | 
|---|
| 827 | /** | 
|---|
| 828 | remove an id from the idr tree | 
|---|
| 829 | */ | 
|---|
| 830 | _PUBLIC_ int idr_remove(struct idr_context *idp, int id); | 
|---|
| 831 |  | 
|---|
| 832 | /* The following definitions come from lib/util/become_daemon.c  */ | 
|---|
| 833 |  | 
|---|
| 834 | /** | 
|---|
| 835 | Close the low 3 fd's and open dev/null in their place | 
|---|
| 836 | **/ | 
|---|
| 837 | _PUBLIC_ void close_low_fds(bool stderr_too); | 
|---|
| 838 |  | 
|---|
| 839 | /** | 
|---|
| 840 | Become a daemon, discarding the controlling terminal. | 
|---|
| 841 | **/ | 
|---|
| 842 | _PUBLIC_ void become_daemon(bool do_fork, bool no_process_group); | 
|---|
| 843 |  | 
|---|
| 844 | /** | 
|---|
| 845 | * Load a ini-style file. | 
|---|
| 846 | */ | 
|---|
| 847 | bool pm_process( const char *fileName, | 
|---|
| 848 | bool (*sfunc)(const char *, void *), | 
|---|
| 849 | bool (*pfunc)(const char *, const char *, void *), | 
|---|
| 850 | void *userdata); | 
|---|
| 851 |  | 
|---|
| 852 | bool unmap_file(void *start, size_t size); | 
|---|
| 853 |  | 
|---|
| 854 | void print_asc(int level, const uint8_t *buf,int len); | 
|---|
| 855 |  | 
|---|
| 856 | /** | 
|---|
| 857 | * Add an id to an array of ids. | 
|---|
| 858 | * | 
|---|
| 859 | * num should be a pointer to an integer that holds the current | 
|---|
| 860 | * number of elements in ids. It will be updated by this function. | 
|---|
| 861 | */ | 
|---|
| 862 |  | 
|---|
| 863 | bool add_uid_to_array_unique(TALLOC_CTX *mem_ctx, uid_t uid, | 
|---|
| 864 | uid_t **uids, size_t *num_uids); | 
|---|
| 865 | bool add_gid_to_array_unique(TALLOC_CTX *mem_ctx, gid_t gid, | 
|---|
| 866 | gid_t **gids, size_t *num_gids); | 
|---|
| 867 |  | 
|---|
| 868 |  | 
|---|
| 869 | #endif /* _SAMBA_UTIL_H_ */ | 
|---|