util.c 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. /* util.c -- utility functions -- functions available form libslapd */
  13. #include <sys/socket.h>
  14. #include <sys/param.h>
  15. #include <unistd.h>
  16. #include <pwd.h>
  17. #include <stdint.h>
  18. #include <fcntl.h>
  19. #include <libgen.h>
  20. #include <pk11func.h>
  21. #include "slap.h"
  22. #include "prtime.h"
  23. #include "prinrval.h"
  24. #include "snmp_collator.h"
  25. #include <sys/time.h>
  26. #include <sys/resource.h>
  27. #define UTIL_ESCAPE_NONE 0
  28. #define UTIL_ESCAPE_HEX 1
  29. #define UTIL_ESCAPE_BACKSLASH 2
  30. #define _PSEP "/"
  31. #define _PSEP2 "//"
  32. #define _CSEP '/'
  33. /* slapi_filter_sprintf macros */
  34. #define ATTRSIZE 256 /* size allowed for an attr name */
  35. #define FILTER_BUF 128 /* initial buffer size for attr value */
  36. #define BUF_INCR 16 /* the amount to increase the FILTER_BUF once it fills up */
  37. /* Used by our util_info_sys_pages function
  38. *
  39. * platforms supported so far:
  40. * Solaris, Linux, Windows
  41. */
  42. #ifdef OS_solaris
  43. #include <sys/procfs.h>
  44. #endif
  45. #ifdef LINUX
  46. #include <linux/kernel.h>
  47. #endif
  48. #if defined ( hpux )
  49. #include <sys/pstat.h>
  50. #endif
  51. static int special_filename(unsigned char c)
  52. {
  53. if ((c < 45) || (c == '/') || ((c > 57) && (c < 65)) ||
  54. ((c > 90) && (c < 95)) || (c == 96) ||(c > 122) ) {
  55. return UTIL_ESCAPE_HEX;
  56. }
  57. return UTIL_ESCAPE_NONE;
  58. }
  59. static int special_np(unsigned char c)
  60. {
  61. if (c == '\\') {
  62. return UTIL_ESCAPE_BACKSLASH;
  63. }
  64. if (c < 32 || c > 126 || c == '"') {
  65. return UTIL_ESCAPE_HEX;
  66. }
  67. return UTIL_ESCAPE_NONE;
  68. }
  69. static int special_np_and_punct(unsigned char c)
  70. {
  71. if (c == '\\') {
  72. return UTIL_ESCAPE_BACKSLASH;
  73. }
  74. if (c < 32 || c > 126 || c == '"' || c == '*') {
  75. return UTIL_ESCAPE_HEX;
  76. }
  77. return UTIL_ESCAPE_NONE;
  78. }
  79. #ifndef USE_OPENLDAP
  80. static int special_filter(unsigned char c)
  81. {
  82. /*
  83. * Escape all non-printing chars and double-quotes in addition
  84. * to those required by RFC 2254 so that we can use the string
  85. * in log files.
  86. */
  87. return (c < 32 ||
  88. c > 126 ||
  89. c == '*' ||
  90. c == '(' ||
  91. c == ')' ||
  92. c == '\\' ||
  93. c == '"') ? UTIL_ESCAPE_HEX : UTIL_ESCAPE_NONE;
  94. }
  95. #endif
  96. /*
  97. * Used by filter_stuff_func to help extract an attribute so we know
  98. * how to normalize the value.
  99. */
  100. static int
  101. special_attr_char(unsigned char c)
  102. {
  103. return (c < 32 ||
  104. c > 126 ||
  105. c == '*' ||
  106. c == '|' ||
  107. c == '&' ||
  108. c == '!' ||
  109. c == '(' ||
  110. c == ')' ||
  111. c == '\\' ||
  112. c == '=' ||
  113. c == '"');
  114. }
  115. /* No '\\' */
  116. #define DOESCAPE_FLAGS_HEX_NOESC 0x1
  117. static const char*
  118. do_escape_string (
  119. const char* str,
  120. int len, /* -1 means str is nul-terminated */
  121. char buf[BUFSIZ],
  122. int (*special)(unsigned char),
  123. int flags
  124. )
  125. {
  126. const char* s;
  127. const char* last;
  128. int esc;
  129. if (str == NULL) {
  130. *buf = '\0';
  131. return buf;
  132. }
  133. if (len == -1) len = strlen (str);
  134. if (len == 0) return str;
  135. last = str + len - 1;
  136. for (s = str; s <= last; ++s) {
  137. if ( (esc = (*special)((unsigned char)*s))) {
  138. const char* first = str;
  139. char* bufNext = buf;
  140. int bufSpace = BUFSIZ - 4;
  141. while (1) {
  142. if (bufSpace < (s - first)) s = first + bufSpace - 1;
  143. if (s > first) {
  144. memcpy (bufNext, first, s - first);
  145. bufNext += (s - first);
  146. bufSpace -= (s - first);
  147. }
  148. if (s > last) {
  149. break;
  150. }
  151. do {
  152. if (esc == UTIL_ESCAPE_BACKSLASH) {
  153. /* *s is '\\' */
  154. /* If *(s+1) and *(s+2) are both hex digits,
  155. * the char is already escaped. */
  156. if (isxdigit(*(s+1)) && isxdigit(*(s+2))) {
  157. memcpy(bufNext, s, 3);
  158. bufNext += 3;
  159. bufSpace -= 3;
  160. s += 2;
  161. } else {
  162. *bufNext++ = *s; --bufSpace;
  163. }
  164. } else { /* UTIL_ESCAPE_HEX */
  165. if (!(flags & DOESCAPE_FLAGS_HEX_NOESC)) {
  166. *bufNext++ = '\\'; --bufSpace;
  167. }
  168. if (bufSpace < 3) {
  169. memcpy(bufNext, "..", 2);
  170. bufNext += 2;
  171. goto bail;
  172. }
  173. PR_snprintf(bufNext, 3, "%02x", *(unsigned char*)s);
  174. bufNext += 2; bufSpace -= 2;
  175. }
  176. } while (++s <= last &&
  177. (esc = (*special)((unsigned char)*s)));
  178. if (s > last) break;
  179. first = s;
  180. while ( (esc = (*special)((unsigned char)*s)) == UTIL_ESCAPE_NONE && s <= last) ++s;
  181. }
  182. bail:
  183. *bufNext = '\0';
  184. return buf;
  185. }
  186. } /* for */
  187. return str;
  188. }
  189. /*
  190. * Function: escape_string
  191. * Arguments: str: string
  192. * buf: a char array of BUFSIZ length, in which the escaped string will
  193. * be returned.
  194. * Returns: a pointer to buf, if str==NULL or it needed to be escaped, or
  195. * str itself otherwise.
  196. *
  197. * This function should only be used for generating loggable strings.
  198. */
  199. const char*
  200. escape_string (const char* str, char buf[BUFSIZ])
  201. {
  202. return do_escape_string(str,-1,buf,special_np, 0);
  203. }
  204. const char*
  205. escape_string_with_punctuation(const char* str, char buf[BUFSIZ])
  206. {
  207. return do_escape_string(str,-1,buf,special_np_and_punct, 0);
  208. }
  209. const char*
  210. escape_string_for_filename(const char *str, char buf[BUFSIZ])
  211. {
  212. return do_escape_string(str,-1,buf,special_filename, DOESCAPE_FLAGS_HEX_NOESC);
  213. }
  214. #define ESCAPE_FILTER 1
  215. #define NORM_FILTER 2
  216. struct filter_ctx {
  217. char *buf;
  218. char attr[ATTRSIZE];
  219. int attr_position;
  220. int attr_found;
  221. int buf_size;
  222. int buf_len;
  223. int next_arg_needs_esc_norm;
  224. int skip_escape;
  225. };
  226. /*
  227. * This function is called by slapi_filter_sprintf to escape/normalize certain values
  228. */
  229. static PRIntn
  230. filter_stuff_func(void *arg, const char *val, PRUint32 slen)
  231. {
  232. struct filter_ctx *ctx = (struct filter_ctx *)arg;
  233. #if defined (USE_OPENLDAP)
  234. struct berval escaped_filter;
  235. struct berval raw_filter;
  236. #endif
  237. char *buf = (char *)val;
  238. int extra_space;
  239. int filter_len = slen;
  240. /* look at val - if val is one of our special keywords, and make a note of it for the next pass */
  241. if (strcmp(val, ESC_NEXT_VAL) == 0){
  242. ctx->next_arg_needs_esc_norm |= ESCAPE_FILTER;
  243. return 0;
  244. }
  245. if (strcmp(val, NORM_NEXT_VAL) == 0){
  246. ctx->next_arg_needs_esc_norm |= NORM_FILTER;
  247. return 0;
  248. }
  249. if (strcmp(val, ESC_AND_NORM_NEXT_VAL) == 0){
  250. ctx->next_arg_needs_esc_norm = NORM_FILTER | ESCAPE_FILTER;
  251. return 0;
  252. }
  253. /*
  254. * Start collecting the attribute name so we can use the correct
  255. * syntax normalization func.
  256. */
  257. if(ctx->attr_found == 0 && ctx->attr_position < (ATTRSIZE - 1)){
  258. if(ctx->attr[0] == '\0'){
  259. if(strstr(val,"=")){
  260. /* we have an attr we need to record */
  261. if(!special_attr_char(val[0])){
  262. memcpy(ctx->attr, val, 1);
  263. ctx->attr_position++;
  264. }
  265. } else {
  266. /*
  267. * We have passed in an attribute as a arg - so we can just set the
  268. * attr with val. The next pass should be '=', otherwise we will
  269. * reset it.
  270. */
  271. memcpy(ctx->attr, val, slen);
  272. ctx->attr_position = slen;
  273. }
  274. } else {
  275. if(val[0] == '='){ /* hit the end of the attribute name */
  276. ctx->attr_found = 1;
  277. } else {
  278. if(special_attr_char(val[0])){
  279. /* this is not an attribute, we should not be collecting this, reset everything */
  280. memset(ctx->attr, '\0', ATTRSIZE);
  281. ctx->attr_position = 0;
  282. } else {
  283. memcpy(ctx->attr + ctx->attr_position, val, 1);
  284. ctx->attr_position++;
  285. }
  286. }
  287. }
  288. }
  289. if (ctx->next_arg_needs_esc_norm && !ctx->skip_escape){
  290. /*
  291. * Normalize the filter value first
  292. */
  293. if(ctx->next_arg_needs_esc_norm & NORM_FILTER){
  294. char *norm_val = NULL;
  295. if(ctx->attr_found){
  296. slapi_attr_value_normalize(NULL, NULL, ctx->attr , buf, 1, &norm_val );
  297. if(norm_val){
  298. buf = norm_val;
  299. filter_len = strlen(buf);
  300. }
  301. }
  302. }
  303. /*
  304. * Escape the filter value
  305. */
  306. if(ctx->next_arg_needs_esc_norm & ESCAPE_FILTER){
  307. #if defined (USE_OPENLDAP)
  308. raw_filter.bv_val = (char *)buf;
  309. raw_filter.bv_len = filter_len;
  310. if(ldap_bv2escaped_filter_value(&raw_filter, &escaped_filter) != 0){
  311. LDAPDebug(LDAP_DEBUG_TRACE, "slapi_filter_sprintf: failed to escape filter value(%s)\n",val,0,0);
  312. ctx->next_arg_needs_esc_norm = 0;
  313. return -1;
  314. } else {
  315. filter_len = escaped_filter.bv_len;
  316. buf = escaped_filter.bv_val;
  317. }
  318. #else
  319. char *val2 = NULL;
  320. buf = slapi_ch_calloc(sizeof(char), filter_len*3 + 1);
  321. val2 = (char *)do_escape_string(val, filter_len, buf, special_filter);
  322. if(val2 == NULL){
  323. LDAPDebug(LDAP_DEBUG_TRACE, "slapi_filter_sprintf: failed to escape filter value(%s)\n",val,0,0);
  324. ctx->next_arg_needs_esc_norm = 0;
  325. slapi_ch_free_string(&buf);
  326. return -1;
  327. } else if (val == val2) { /* value did not need escaping and was just returned */
  328. strcpy(buf, val); /* just use value as-is - len did not change */
  329. } else {
  330. filter_len = strlen(buf);
  331. }
  332. #endif
  333. }
  334. /*
  335. * Now add the new value to the buffer, and allocate more memory if needed
  336. */
  337. if (ctx->buf_size + filter_len >= ctx->buf_len){
  338. /* increase buffer for this filter */
  339. extra_space = (ctx->buf_len + filter_len + BUF_INCR);
  340. ctx->buf = slapi_ch_realloc(ctx->buf, sizeof(char) * extra_space);
  341. ctx->buf_len = extra_space;
  342. }
  343. /* append the escaped value */
  344. memcpy(ctx->buf + ctx->buf_size, buf, filter_len);
  345. ctx->buf_size += filter_len;
  346. /* done with the value, reset everything */
  347. ctx->next_arg_needs_esc_norm = 0;
  348. ctx->attr_found = 0;
  349. ctx->attr_position = 0;
  350. memset(ctx->attr, '\0', ATTRSIZE);
  351. slapi_ch_free_string(&buf);
  352. return filter_len;
  353. } else { /* process arg as is */
  354. /* check if we have enough room in our buffer */
  355. if (ctx->buf_size + slen >= ctx->buf_len){
  356. /* increase buffer for this filter */
  357. extra_space = (ctx->buf_len + slen + BUF_INCR);
  358. ctx->buf = slapi_ch_realloc((char *)ctx->buf, sizeof(char) * extra_space);
  359. ctx->buf_len = extra_space;
  360. }
  361. memcpy(ctx->buf + ctx->buf_size, buf, slen);
  362. ctx->buf_size += slen;
  363. return slen;
  364. }
  365. }
  366. /*
  367. * This is basically like slapi_ch_smprintf() except it can handle special
  368. * keywords that will cause the next value to be escaped and/or normalized.
  369. *
  370. * ESC_NEXT_VAL - escape the next value
  371. * NORM_NEXT_VAL - normalize the next value
  372. * ESC_AND_NORM_NEXT_VAL - escape and normalize the next value
  373. *
  374. * Example:
  375. *
  376. * slapi_filter_sprintf("cn=%s%s", ESC_NEXT_VAL, value);
  377. * slapi_filter_sprintf("(|(cn=%s%s)(sn=%s%s))", ESC_NEXT_VAL, value, NORM_NEXT_VAL, value);
  378. *
  379. * Note: you need a string format specifier(%s) for each keyword
  380. */
  381. char*
  382. slapi_filter_sprintf(const char *fmt, ...)
  383. {
  384. struct filter_ctx ctx;
  385. va_list args;
  386. char *buf;
  387. int rc;
  388. buf = slapi_ch_calloc(sizeof(char), FILTER_BUF + 1);
  389. ctx.buf = buf;
  390. memset(ctx.attr,'\0', ATTRSIZE);
  391. ctx.attr_position = 0;
  392. ctx.attr_found = 0;
  393. ctx.buf_len = FILTER_BUF;
  394. ctx.buf_size = 0;
  395. ctx.next_arg_needs_esc_norm = 0;
  396. ctx.skip_escape = 0;
  397. va_start(args, fmt);
  398. rc = PR_vsxprintf(filter_stuff_func, &ctx, fmt, args);
  399. if(rc == -1){
  400. /* transformation failed, just return non-normalized/escaped string */
  401. ctx.skip_escape = 1;
  402. PR_vsxprintf(filter_stuff_func, &ctx, fmt, args);
  403. }
  404. va_end(args);
  405. return ctx.buf;
  406. }
  407. /*
  408. * escape special characters in values used in search filters
  409. *
  410. * caller must free the returned value
  411. */
  412. char*
  413. slapi_escape_filter_value(char* filter_str, int len)
  414. {
  415. #if defined (USE_OPENLDAP)
  416. struct berval escaped_filter;
  417. struct berval raw_filter;
  418. #endif
  419. int filter_len;
  420. /*
  421. * Check the length for special cases
  422. */
  423. if(len == -1){
  424. /* filter str is null terminated */
  425. filter_len = strlen(filter_str);
  426. } else if (len == 0){
  427. /* return the filter as is */
  428. return slapi_ch_strdup(filter_str);
  429. } else {
  430. /* the len is the length */
  431. filter_len = len;
  432. }
  433. #if defined (USE_OPENLDAP)
  434. /*
  435. * Construct the berval and escape it
  436. */
  437. raw_filter.bv_val = filter_str;
  438. raw_filter.bv_len = filter_len;
  439. if(ldap_bv2escaped_filter_value(&raw_filter, &escaped_filter) != 0){
  440. LDAPDebug(LDAP_DEBUG_TRACE, "slapi_escape_filter_value: failed to escape filter value(%s)\n",filter_str,0,0);
  441. return NULL;
  442. } else {
  443. return escaped_filter.bv_val;
  444. }
  445. #else
  446. char *buf = slapi_ch_calloc(sizeof(char), filter_len*3+1);
  447. char *esc_str = (char *)do_escape_string(filter_str, filter_len, buf, special_filter);
  448. if(esc_str != buf){
  449. slapi_ch_free_string(&buf);
  450. return slapi_ch_strdup(esc_str);
  451. } else {
  452. return buf;
  453. }
  454. #endif
  455. }
  456. /*
  457. ** This function takes a quoted attribute value of the form "abc",
  458. ** and strips off the enclosing quotes. It also deals with quoted
  459. ** characters by removing the preceeding '\' character.
  460. **
  461. */
  462. void
  463. strcpy_unescape_value( char *d, const char *s )
  464. {
  465. int gotesc = 0;
  466. const char *end = s + strlen(s);
  467. for ( ; *s; s++ )
  468. {
  469. switch ( *s )
  470. {
  471. case '"':
  472. break;
  473. case '\\':
  474. gotesc = 1;
  475. if ( s+2 < end ) {
  476. int n = slapi_hexchar2int( s[1] );
  477. if ( n >= 0 && n < 16 ) {
  478. int n2 = slapi_hexchar2int( s[2] );
  479. if ( n2 >= 0 ) {
  480. n = (n << 4) + n2;
  481. if (n == 0) { /* don't change \00 */
  482. *d++ = *s++;
  483. *d++ = *s++;
  484. *d++ = *s;
  485. } else { /* change \xx to a single char */
  486. *d++ = (char)n;
  487. s += 2;
  488. }
  489. gotesc = 0;
  490. }
  491. }
  492. }
  493. /* This is an escaped single character (like \"), so
  494. * just copy the special character and not the escape.
  495. * We need to be careful to not go past the end of
  496. * the string when the loop increments s. */
  497. if (gotesc && (s+1 < end)) {
  498. s++;
  499. *d++ = *s;
  500. gotesc = 0;
  501. }
  502. break;
  503. default:
  504. *d++ = *s;
  505. break;
  506. }
  507. }
  508. *d = '\0';
  509. }
  510. /* functions to convert between an entry and a set of mods */
  511. int slapi_mods2entry (Slapi_Entry **e, const char *idn, LDAPMod **iattrs)
  512. {
  513. int i, rc = LDAP_SUCCESS;
  514. LDAPMod **attrs= NULL;
  515. PR_ASSERT (idn);
  516. PR_ASSERT (iattrs);
  517. PR_ASSERT (e);
  518. attrs = normalize_mods2bvals((const LDAPMod **)iattrs);
  519. PR_ASSERT (attrs);
  520. /* Construct an entry */
  521. *e = slapi_entry_alloc();
  522. PR_ASSERT (*e);
  523. slapi_entry_init(*e, slapi_ch_strdup(idn), NULL);
  524. for (i = 0; rc==LDAP_SUCCESS && attrs[ i ]!=NULL; i++)
  525. {
  526. char *normtype;
  527. Slapi_Value **vals;
  528. /*
  529. * slapi_entry_apply_mod_extension applys mod and stores
  530. * the result in the extension
  531. * return value: 1 - mod is applied and stored in extension
  532. * -1 - mod is applied and failed
  533. * 0 - mod is nothing to do with extension
  534. */
  535. rc = slapi_entry_apply_mod_extension(*e, attrs[i], -1);
  536. if (rc) {
  537. if (1 == rc) {
  538. rc = LDAP_SUCCESS;
  539. } else {
  540. rc = LDAP_OPERATIONS_ERROR;
  541. }
  542. #if !defined(USE_OLD_UNHASHED)
  543. /* In case USE_OLD_UNHASHED,
  544. * unhashed pw needs to be in attr, too. */
  545. continue;
  546. #endif
  547. }
  548. normtype = slapi_attr_syntax_normalize(attrs[ i ]->mod_type);
  549. valuearray_init_bervalarray(attrs[ i ]->mod_bvalues, &vals);
  550. if (strcasecmp(normtype, SLAPI_USERPWD_ATTR) == 0)
  551. {
  552. pw_encodevals(vals);
  553. }
  554. /* set entry uniqueid - also adds attribute to the list */
  555. if (strcasecmp(normtype, SLAPI_ATTR_UNIQUEID) == 0) {
  556. if (vals) {
  557. slapi_entry_set_uniqueid (*e,
  558. slapi_ch_strdup (slapi_value_get_string(vals[0])));
  559. } else {
  560. rc = LDAP_NO_SUCH_ATTRIBUTE;
  561. }
  562. } else {
  563. rc = slapi_entry_add_values_sv(*e, normtype, vals);
  564. }
  565. valuearray_free(&vals);
  566. if (rc != LDAP_SUCCESS)
  567. {
  568. LDAPDebug2Args(LDAP_DEBUG_ANY,
  569. "slapi_mods2entry: add_values for type %s failed (rc: %d)\n",
  570. normtype, rc );
  571. slapi_entry_free (*e);
  572. *e = NULL;
  573. }
  574. slapi_ch_free((void **) &normtype);
  575. }
  576. freepmods(attrs);
  577. return rc;
  578. }
  579. int
  580. slapi_entry2mods (const Slapi_Entry *e, char **dn, LDAPMod ***attrs)
  581. {
  582. Slapi_Mods smods;
  583. Slapi_Attr *attr;
  584. Slapi_Value **va;
  585. char *type;
  586. int rc;
  587. PR_ASSERT (e && attrs);
  588. if (dn)
  589. *dn = slapi_ch_strdup (slapi_entry_get_dn ((Slapi_Entry *)e));
  590. slapi_mods_init (&smods, 0);
  591. rc = slapi_entry_first_attr(e, &attr);
  592. while (rc == 0)
  593. {
  594. if ( NULL != ( va = attr_get_present_values( attr ))) {
  595. slapi_attr_get_type(attr, &type);
  596. slapi_mods_add_mod_values(&smods, LDAP_MOD_ADD, type, va );
  597. }
  598. rc = slapi_entry_next_attr(e, attr, &attr);
  599. }
  600. #if !defined(USE_OLD_UNHASHED)
  601. if (SLAPD_UNHASHED_PW_ON == config_get_unhashed_pw_switch()) {
  602. /* store unhashed passwd is enabled */
  603. /* In case USE_OLD_UNHASHED, unhashed pw is already in mods */
  604. /* add extension to mods */
  605. rc = slapi_pw_get_entry_ext((Slapi_Entry *)e, &va);
  606. if (LDAP_SUCCESS == rc) {
  607. /* va is copied and set to smods */
  608. slapi_mods_add_mod_values(&smods, LDAP_MOD_ADD,
  609. PSEUDO_ATTR_UNHASHEDUSERPASSWORD, va);
  610. }
  611. }
  612. #endif
  613. *attrs = slapi_mods_get_ldapmods_passout (&smods);
  614. slapi_mods_done (&smods);
  615. return 0;
  616. }
  617. /******************************************************************************
  618. *
  619. * normalize_mods2bvals
  620. *
  621. * Return value: normalized mods
  622. * The values/bvals are all duplicated in this function since
  623. * the normalized mods are freed with ldap_mods_free by the caller.
  624. *
  625. *******************************************************************************/
  626. LDAPMod **
  627. normalize_mods2bvals(const LDAPMod **mods)
  628. {
  629. int w, x, vlen, num_values, num_mods;
  630. LDAPMod **normalized_mods;
  631. if (mods == NULL)
  632. {
  633. return NULL;
  634. }
  635. /* first normalize the mods so they are bvalues */
  636. /* count the number of mods -- sucks but should be small */
  637. num_mods = 1;
  638. for (w=0; mods[w] != NULL; w++) num_mods++;
  639. normalized_mods = (LDAPMod **) slapi_ch_calloc(num_mods, sizeof(LDAPMod *));
  640. for (w = 0; mods[w] != NULL; w++)
  641. {
  642. Slapi_Attr a = {0};
  643. slapi_attr_init(&a, mods[w]->mod_type);
  644. int is_dn_syntax = 0;
  645. struct berval **normmbvp = NULL;
  646. /* Check if the type of the to-be-added values has DN syntax
  647. * or not. */
  648. if (slapi_attr_is_dn_syntax_attr(&a)) {
  649. is_dn_syntax = 1;
  650. }
  651. attr_done(&a);
  652. /* copy each mod into a normalized modbvalue */
  653. normalized_mods[w] = (LDAPMod *) slapi_ch_calloc(1, sizeof(LDAPMod));
  654. normalized_mods[w]->mod_op = mods[w]->mod_op | LDAP_MOD_BVALUES;
  655. normalized_mods[w]->mod_type = slapi_ch_strdup(mods[w]->mod_type);
  656. /*
  657. * count the number of values -- kinda sucks but probably
  658. * less expensive then reallocing, and num_values
  659. * should typically be very small
  660. */
  661. num_values = 0;
  662. if (mods[w]->mod_op & LDAP_MOD_BVALUES)
  663. {
  664. for (x = 0; mods[w]->mod_bvalues != NULL &&
  665. mods[w]->mod_bvalues[x] != NULL; x++)
  666. {
  667. num_values++;
  668. }
  669. } else {
  670. for (x = 0; mods[w]->mod_values != NULL &&
  671. mods[w]->mod_values[x] != NULL; x++)
  672. {
  673. num_values++;
  674. }
  675. }
  676. if (num_values > 0)
  677. {
  678. normalized_mods[w]->mod_bvalues = (struct berval **)
  679. slapi_ch_calloc(num_values + 1, sizeof(struct berval *));
  680. } else {
  681. normalized_mods[w]->mod_bvalues = NULL;
  682. }
  683. if (mods[w]->mod_op & LDAP_MOD_BVALUES)
  684. {
  685. struct berval **mbvp = NULL;
  686. for (mbvp = mods[w]->mod_bvalues,
  687. normmbvp = normalized_mods[w]->mod_bvalues;
  688. mbvp && *mbvp; mbvp++, normmbvp++)
  689. {
  690. if (is_dn_syntax) {
  691. Slapi_DN *sdn = slapi_sdn_new_dn_byref((*mbvp)->bv_val);
  692. if (slapi_sdn_get_dn(sdn)) {
  693. *normmbvp =
  694. (struct berval *)slapi_ch_malloc(sizeof(struct berval));
  695. (*normmbvp)->bv_val =
  696. slapi_ch_strdup(slapi_sdn_get_dn(sdn));
  697. (*normmbvp)->bv_len = slapi_sdn_get_ndn_len(sdn);
  698. } else {
  699. /* normalization failed; use the original */
  700. *normmbvp = ber_bvdup(*mbvp);
  701. }
  702. slapi_sdn_free(&sdn);
  703. } else {
  704. *normmbvp = ber_bvdup(*mbvp);
  705. }
  706. }
  707. } else {
  708. char **mvp = NULL;
  709. for (mvp = mods[w]->mod_values,
  710. normmbvp = normalized_mods[w]->mod_bvalues;
  711. mvp && *mvp; mvp++, normmbvp++)
  712. {
  713. vlen = strlen(*mvp);
  714. *normmbvp =
  715. (struct berval *)slapi_ch_malloc(sizeof(struct berval));
  716. if (is_dn_syntax) {
  717. Slapi_DN *sdn = slapi_sdn_new_dn_byref(*mvp);
  718. if (slapi_sdn_get_dn(sdn)) {
  719. (*normmbvp)->bv_val =
  720. slapi_ch_strdup(slapi_sdn_get_dn(sdn));
  721. (*normmbvp)->bv_len = slapi_sdn_get_ndn_len(sdn);
  722. } else {
  723. /* normalization failed; use the original */
  724. (*normmbvp)->bv_val = slapi_ch_malloc(vlen + 1);
  725. memcpy((*normmbvp)->bv_val, *mvp, vlen);
  726. (*normmbvp)->bv_val[vlen] = '\0';
  727. (*normmbvp)->bv_len = vlen;
  728. }
  729. slapi_sdn_free(&sdn);
  730. } else {
  731. (*normmbvp)->bv_val = slapi_ch_malloc(vlen + 1);
  732. memcpy((*normmbvp)->bv_val, *mvp, vlen);
  733. (*normmbvp)->bv_val[vlen] = '\0';
  734. (*normmbvp)->bv_len = vlen;
  735. }
  736. }
  737. }
  738. PR_ASSERT(normmbvp - normalized_mods[w]->mod_bvalues <= num_values);
  739. /* don't forget to null terminate it */
  740. if (num_values > 0)
  741. {
  742. *normmbvp = NULL;
  743. }
  744. }
  745. /* don't forget to null terminate the normalize list of mods */
  746. normalized_mods[w] = NULL;
  747. return(normalized_mods);
  748. }
  749. /*
  750. * Return true if the given path is an absolute path, false otherwise
  751. */
  752. int
  753. is_abspath(const char *path)
  754. {
  755. if (path == NULL || *path == '\0') {
  756. return 0; /* empty path is not absolute? */
  757. }
  758. if (path[0] == '/') {
  759. return 1; /* unix abs path */
  760. }
  761. return 0; /* not an abs path */
  762. }
  763. static void
  764. clean_path(char **norm_path)
  765. {
  766. char **np;
  767. for (np = norm_path; np && *np; np++)
  768. slapi_ch_free_string(np);
  769. slapi_ch_free((void **)&norm_path);
  770. }
  771. static char **
  772. normalize_path(char *path)
  773. {
  774. char *dname = NULL;
  775. char *dnamep = NULL;
  776. char **dirs = NULL;
  777. char **rdirs = NULL;
  778. char **dp = NULL;
  779. char **rdp;
  780. int elimdots = 0;
  781. if (NULL == path || '\0' == *path) {
  782. return NULL;
  783. }
  784. dirs = (char **)slapi_ch_calloc(strlen(path), sizeof(char *));
  785. rdirs = (char **)slapi_ch_calloc(strlen(path), sizeof(char *));
  786. dp = dirs;
  787. dname = slapi_ch_strdup(path);
  788. do {
  789. dnamep = strrchr(dname, _CSEP);
  790. if (NULL == dnamep) {
  791. dnamep = dname;
  792. } else {
  793. *dnamep = '\0';
  794. dnamep++;
  795. }
  796. if (0 != strcmp(dnamep, ".") && strlen(dnamep) > 0) {
  797. *dp++ = slapi_ch_strdup(dnamep); /* rm "/./" and "//" in the path */
  798. }
  799. } while ( dnamep > dname /* == -> no more _CSEP */ );
  800. slapi_ch_free_string(&dname);
  801. /* remove "xxx/.." in the path */
  802. for (dp = dirs, rdp = rdirs; dp && *dp; dp++) {
  803. while (*dp && 0 == strcmp(*dp, "..")) {
  804. dp++;
  805. elimdots++;
  806. }
  807. if (elimdots > 0) {
  808. elimdots--;
  809. } else if (*dp) {
  810. *rdp++ = slapi_ch_strdup(*dp);
  811. }
  812. }
  813. /* reverse */
  814. for (--rdp, dp = rdirs; rdp >= dp && rdp >= rdirs; --rdp, dp++) {
  815. char *tmpp = *dp;
  816. *dp = *rdp;
  817. *rdp = tmpp;
  818. }
  819. clean_path(dirs);
  820. return rdirs;
  821. }
  822. /*
  823. * Take "relpath" and prepend the current working directory to it
  824. * if it isn't an absolute pathname already. The caller is responsible
  825. * for freeing the returned string.
  826. */
  827. char *
  828. rel2abspath( char *relpath )
  829. {
  830. return rel2abspath_ext( relpath, NULL );
  831. }
  832. char *
  833. rel2abspath_ext( char *relpath, char *cwd )
  834. {
  835. char abspath[ MAXPATHLEN + 1 ];
  836. char *retpath = NULL;
  837. if ( relpath == NULL ) {
  838. return NULL;
  839. }
  840. if ( relpath[ 0 ] == _CSEP ) { /* absolute path */
  841. PR_snprintf(abspath, sizeof(abspath), "%s", relpath);
  842. } else { /* relative path */
  843. if ( NULL == cwd ) {
  844. if ( getcwd( abspath, MAXPATHLEN ) == NULL ) {
  845. perror( "getcwd" );
  846. LDAPDebug( LDAP_DEBUG_ANY, "Cannot determine current directory\n",
  847. 0, 0, 0 );
  848. exit( 1 );
  849. }
  850. } else {
  851. PR_snprintf(abspath, sizeof(abspath), "%s", cwd);
  852. }
  853. if ( strlen( relpath ) + strlen( abspath ) + 1 > MAXPATHLEN ) {
  854. LDAPDebug( LDAP_DEBUG_ANY, "Pathname \"%s" _PSEP "%s\" too long\n",
  855. abspath, relpath, 0 );
  856. exit( 1 );
  857. }
  858. if ( strcmp( relpath, "." )) {
  859. if ( abspath[ 0 ] != '\0' &&
  860. abspath[ strlen( abspath ) - 1 ] != _CSEP )
  861. {
  862. PL_strcatn( abspath, sizeof(abspath), _PSEP );
  863. }
  864. PL_strcatn( abspath, sizeof(abspath), relpath );
  865. }
  866. }
  867. retpath = slapi_ch_strdup(abspath);
  868. /* if there's no '.' or separators, no need to call normalize_path */
  869. if (NULL != strchr(abspath, '.') || NULL != strstr(abspath, _PSEP))
  870. {
  871. char **norm_path = normalize_path(abspath);
  872. char **np, *rp;
  873. int pathlen = strlen(abspath) + 1;
  874. int usedlen = 0;
  875. for (np = norm_path, rp = retpath; np && *np; np++) {
  876. int thislen = strlen(*np) + 1;
  877. if (0 != strcmp(*np, _PSEP))
  878. PR_snprintf(rp, pathlen - usedlen, "%c%s", _CSEP, *np);
  879. rp += thislen;
  880. usedlen += thislen;
  881. }
  882. clean_path(norm_path);
  883. }
  884. return retpath;
  885. }
  886. /*
  887. * Allocate a buffer large enough to hold a berval's
  888. * value and a terminating null byte. The returned buffer
  889. * is null-terminated. Returns NULL if bval is NULL or if
  890. * bval->bv_val is NULL.
  891. */
  892. char *
  893. slapi_berval_get_string_copy(const struct berval *bval)
  894. {
  895. char *return_value = NULL;
  896. if (NULL != bval && NULL != bval->bv_val)
  897. {
  898. return_value = slapi_ch_malloc(bval->bv_len + 1);
  899. memcpy(return_value, bval->bv_val, bval->bv_len);
  900. return_value[bval->bv_len] = '\0';
  901. }
  902. return return_value;
  903. }
  904. /* Takes a return code supposed to be errno or from a plugin
  905. which we don't expect to see and prints a handy log message */
  906. void slapd_nasty(char* str, int c, int err)
  907. {
  908. char *msg = NULL;
  909. char buffer[100];
  910. PR_snprintf(buffer,sizeof(buffer), "%s BAD %d",str,c);
  911. LDAPDebug(LDAP_DEBUG_ANY,"%s, err=%d %s\n",buffer,err,(msg = strerror( err )) ? msg : "");
  912. }
  913. /* ***************************************************
  914. Random function (very similar to rand_r())
  915. *************************************************** */
  916. int
  917. slapi_rand_r(unsigned int *randx)
  918. {
  919. if (*randx)
  920. {
  921. PK11_RandomUpdate(randx, sizeof(*randx));
  922. }
  923. PK11_GenerateRandom((unsigned char *)randx, (int)sizeof(*randx));
  924. return (int)(*randx & 0x7FFFFFFF);
  925. }
  926. /* ***************************************************
  927. Random function (very similar to rand_r() but takes and returns an array)
  928. Note: there is an identical function in plugins/pwdstorage/ssha_pwd.c.
  929. That module can't use a libslapd function because the module is included
  930. in libds_admin, which doesn't link to libslapd. Eventually, shared
  931. functions should be moved to a shared library.
  932. *************************************************** */
  933. void
  934. slapi_rand_array(void *randx, size_t len)
  935. {
  936. PK11_RandomUpdate(randx, len);
  937. PK11_GenerateRandom((unsigned char *)randx, (int)len);
  938. }
  939. /* ***************************************************
  940. Random function (very similar to rand()...)
  941. *************************************************** */
  942. int
  943. slapi_rand()
  944. {
  945. unsigned int randx = 0;
  946. return slapi_rand_r(&randx);
  947. }
  948. /************************************************************************
  949. Function: DS_Sleep(PRIntervalTime ticks)
  950. Purpose: To replace PR_Sleep()
  951. Author: Scott Hopson <[email protected]>
  952. Description:
  953. Causes the current thread to wait for ticks number of intervals.
  954. In UNIX this is accomplished by using select()
  955. which should be supported across all UNIX platforms.
  956. ************************************************************************/
  957. void
  958. DS_Sleep(PRIntervalTime ticks)
  959. {
  960. long mSecs = PR_IntervalToMilliseconds(ticks);
  961. struct timeval tm;
  962. tm.tv_sec = mSecs / 1000;
  963. tm.tv_usec = (mSecs % 1000) * 1000;
  964. select(0,NULL,NULL,NULL,&tm);
  965. }
  966. /*****************************************************************************
  967. * strarray2str(): convert the array of strings in "a" into a single
  968. * space-separated string like:
  969. * str1 str2 str3
  970. * If buf is too small, the result will be truncated and end with "...".
  971. * If include_quotes is non-zero, double quote marks are included around
  972. * the string, e.g.,
  973. * "str2 str2 str3"
  974. *
  975. * Returns: 0 if completely successful and -1 if result is truncated.
  976. */
  977. int
  978. strarray2str( char **a, char *buf, size_t buflen, int include_quotes )
  979. {
  980. int rc = 0; /* optimistic */
  981. char *p = buf;
  982. size_t totlen = 0;
  983. if ( include_quotes ) {
  984. if ( buflen < 3 ) {
  985. return -1; /* not enough room for the quote marks! */
  986. }
  987. *p++ = '"';
  988. ++totlen;
  989. }
  990. if ( NULL != a ) {
  991. int ii;
  992. size_t len = 0;
  993. for ( ii = 0; a[ ii ] != NULL; ii++ ) {
  994. if ( ii > 0 ) {
  995. *p++ = ' ';
  996. totlen++;
  997. }
  998. len = strlen( a[ ii ]);
  999. if ( totlen + len > buflen - 5 ) {
  1000. strcpy ( p, "..." );
  1001. p += 3;
  1002. totlen += 3;
  1003. rc = -1;
  1004. break; /* result truncated */
  1005. } else {
  1006. strcpy( p, a[ ii ]);
  1007. p += len;
  1008. totlen += len;
  1009. }
  1010. }
  1011. }
  1012. if ( include_quotes ) {
  1013. *p++ = '"';
  1014. ++totlen;
  1015. }
  1016. buf[ totlen ] = '\0';
  1017. return( rc );
  1018. }
  1019. /*****************************************************************************/
  1020. /* Changes the ownership of the given file/directory if not
  1021. already the owner
  1022. Returns 0 upon success or non-zero otherwise, usually -1 if
  1023. some system error occurred
  1024. */
  1025. int
  1026. slapd_chown_if_not_owner(const char *filename, uid_t uid, gid_t gid)
  1027. {
  1028. int fd = -1;
  1029. struct stat statbuf;
  1030. int result = 1;
  1031. if (!filename)
  1032. return result;
  1033. fd = open(filename, O_RDONLY);
  1034. if (fd == -1) {
  1035. return result;
  1036. }
  1037. memset(&statbuf, '\0', sizeof(statbuf));
  1038. if (!(result = fstat(fd, &statbuf)))
  1039. {
  1040. if (((uid != -1) && (uid != statbuf.st_uid)) ||
  1041. ((gid != -1) && (gid != statbuf.st_gid)))
  1042. {
  1043. result = fchown(fd, uid, gid);
  1044. }
  1045. }
  1046. close(fd);
  1047. return result;
  1048. }
  1049. /*
  1050. * Compare 2 pathes
  1051. * Paths could contain ".", "..", "//" in the path, thus normalize them first.
  1052. * One or two of the paths could be a relative path.
  1053. */
  1054. int
  1055. slapd_comp_path(char *p0, char *p1)
  1056. {
  1057. int rval = 0;
  1058. char *norm_p0 = rel2abspath(p0);
  1059. char *norm_p1 = rel2abspath(p1);
  1060. rval = strcmp(norm_p0, norm_p1);
  1061. slapi_ch_free_string(&norm_p0);
  1062. slapi_ch_free_string(&norm_p1);
  1063. return rval;
  1064. }
  1065. /*
  1066. Takes an unsigned char value and converts it to a hex string.
  1067. The string s is written, and the caller must ensure s has enough
  1068. space. For hex numbers, the upper argument says to use a-f or A-F.
  1069. The return value is the address of the next char after the last one written.
  1070. */
  1071. char *
  1072. slapi_u8_to_hex(uint8_t val, char *s, uint8_t upper) {
  1073. static char ldigits[] = "0123456789abcdef";
  1074. static char udigits[] = "0123456789ABCDEF";
  1075. char *digits;
  1076. if (upper) {
  1077. digits = udigits;
  1078. } else {
  1079. digits = ldigits;
  1080. }
  1081. s[0] = digits[val >> 4];
  1082. s[1] = digits[val & 0xf];
  1083. return &s[2];
  1084. }
  1085. char *
  1086. slapi_u16_to_hex(uint16_t val, char *s, uint8_t upper) {
  1087. static char ldigits[] = "0123456789abcdef";
  1088. static char udigits[] = "0123456789ABCDEF";
  1089. char *digits;
  1090. if (upper) {
  1091. digits = udigits;
  1092. } else {
  1093. digits = ldigits;
  1094. }
  1095. s[0] = digits[val >> 12];
  1096. s[1] = digits[(val >> 8) & 0xf];
  1097. s[2] = digits[(val >> 4) & 0xf];
  1098. s[3] = digits[val & 0xf];
  1099. return &s[4];
  1100. }
  1101. char *
  1102. slapi_u32_to_hex(uint32_t val, char *s, uint8_t upper) {
  1103. static char ldigits[] = "0123456789abcdef";
  1104. static char udigits[] = "0123456789ABCDEF";
  1105. char *digits;
  1106. if (upper) {
  1107. digits = udigits;
  1108. } else {
  1109. digits = ldigits;
  1110. }
  1111. s[0] = digits[val >> 28];
  1112. s[1] = digits[(val >> 24) & 0xf];
  1113. s[2] = digits[(val >> 20) & 0xf];
  1114. s[3] = digits[(val >> 16) & 0xf];
  1115. s[4] = digits[(val >> 12) & 0xf];
  1116. s[5] = digits[(val >> 8) & 0xf];
  1117. s[6] = digits[(val >> 4) & 0xf];
  1118. s[7] = digits[val & 0xf];
  1119. return &s[8];
  1120. }
  1121. char *
  1122. slapi_u64_to_hex(uint64_t val, char *s, uint8_t upper) {
  1123. static char ldigits[] = "0123456789abcdef";
  1124. static char udigits[] = "0123456789ABCDEF";
  1125. char *digits;
  1126. if (upper) {
  1127. digits = udigits;
  1128. } else {
  1129. digits = ldigits;
  1130. }
  1131. s[0] = digits[val >> 60];
  1132. s[1] = digits[(val >> 56) & 0xf];
  1133. s[2] = digits[(val >> 52) & 0xf];
  1134. s[3] = digits[(val >> 48) & 0xf];
  1135. s[4] = digits[(val >> 44) & 0xf];
  1136. s[5] = digits[(val >> 40) & 0xf];
  1137. s[6] = digits[(val >> 36) & 0xf];
  1138. s[7] = digits[(val >> 32) & 0xf];
  1139. s[8] = digits[(val >> 28) & 0xf];
  1140. s[9] = digits[(val >> 24) & 0xf];
  1141. s[10] = digits[(val >> 20) & 0xf];
  1142. s[11] = digits[(val >> 16) & 0xf];
  1143. s[12] = digits[(val >> 12) & 0xf];
  1144. s[13] = digits[(val >> 8) & 0xf];
  1145. s[14] = digits[(val >> 4) & 0xf];
  1146. s[15] = digits[val & 0xf];
  1147. return &s[16];
  1148. }
  1149. static const int char2intarray[] = {
  1150. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  1151. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  1152. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  1153. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
  1154. -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  1155. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  1156. -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  1157. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  1158. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  1159. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  1160. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  1161. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  1162. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  1163. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  1164. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  1165. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
  1166. };
  1167. int
  1168. slapi_hexchar2int(char c)
  1169. {
  1170. return char2intarray[(unsigned char)c];
  1171. }
  1172. uint8_t
  1173. slapi_str_to_u8(const char *s)
  1174. {
  1175. uint8_t v0 = (uint8_t)slapi_hexchar2int(s[0]);
  1176. uint8_t v1 = (uint8_t)slapi_hexchar2int(s[1]);
  1177. return (v0 << 4) | v1;
  1178. }
  1179. uint16_t
  1180. slapi_str_to_u16(const char *s)
  1181. {
  1182. uint16_t v0 = (uint16_t)slapi_hexchar2int(s[0]);
  1183. uint16_t v1 = (uint16_t)slapi_hexchar2int(s[1]);
  1184. uint16_t v2 = (uint16_t)slapi_hexchar2int(s[2]);
  1185. uint16_t v3 = (uint16_t)slapi_hexchar2int(s[3]);
  1186. return (v0 << 12) | (v1 << 8) | (v2 << 4) | v3;
  1187. }
  1188. uint32_t
  1189. slapi_str_to_u32(const char *s)
  1190. {
  1191. uint32_t v0 = (uint32_t)slapi_hexchar2int(s[0]);
  1192. uint32_t v1 = (uint32_t)slapi_hexchar2int(s[1]);
  1193. uint32_t v2 = (uint32_t)slapi_hexchar2int(s[2]);
  1194. uint32_t v3 = (uint32_t)slapi_hexchar2int(s[3]);
  1195. uint32_t v4 = (uint32_t)slapi_hexchar2int(s[4]);
  1196. uint32_t v5 = (uint32_t)slapi_hexchar2int(s[5]);
  1197. uint32_t v6 = (uint32_t)slapi_hexchar2int(s[6]);
  1198. uint32_t v7 = (uint32_t)slapi_hexchar2int(s[7]);
  1199. return (v0 << 28) | (v1 << 24) | (v2 << 20) | (v3 << 16) | (v4 << 12) | (v5 << 8) | (v6 << 4) | v7;
  1200. }
  1201. uint64_t
  1202. slapi_str_to_u64(const char *s)
  1203. {
  1204. uint64_t v0 = (uint64_t)slapi_hexchar2int(s[0]);
  1205. uint64_t v1 = (uint64_t)slapi_hexchar2int(s[1]);
  1206. uint64_t v2 = (uint64_t)slapi_hexchar2int(s[2]);
  1207. uint64_t v3 = (uint64_t)slapi_hexchar2int(s[3]);
  1208. uint64_t v4 = (uint64_t)slapi_hexchar2int(s[4]);
  1209. uint64_t v5 = (uint64_t)slapi_hexchar2int(s[5]);
  1210. uint64_t v6 = (uint64_t)slapi_hexchar2int(s[6]);
  1211. uint64_t v7 = (uint64_t)slapi_hexchar2int(s[7]);
  1212. uint64_t v8 = (uint64_t)slapi_hexchar2int(s[8]);
  1213. uint64_t v9 = (uint64_t)slapi_hexchar2int(s[9]);
  1214. uint64_t v10 = (uint64_t)slapi_hexchar2int(s[10]);
  1215. uint64_t v11 = (uint64_t)slapi_hexchar2int(s[11]);
  1216. uint64_t v12 = (uint64_t)slapi_hexchar2int(s[12]);
  1217. uint64_t v13 = (uint64_t)slapi_hexchar2int(s[13]);
  1218. uint64_t v14 = (uint64_t)slapi_hexchar2int(s[14]);
  1219. uint64_t v15 = (uint64_t)slapi_hexchar2int(s[15]);
  1220. return (v0 << 60) | (v1 << 56) | (v2 << 52) | (v3 << 48) | (v4 << 44) | (v5 << 40) |
  1221. (v6 << 36) | (v7 << 32) | (v8 << 28) | (v9 << 24) | (v10 << 20) | (v11 << 16) |
  1222. (v12 << 12) | (v13 << 8) | (v14 << 4) | v15;
  1223. }
  1224. /* PR_GetLibraryName does almost everything we need, and unfortunately
  1225. a little bit more - it adds "lib" to be beginning of the library
  1226. name if the library name does not end with the current platform
  1227. DLL suffix - so
  1228. foo.so -> /path/foo.so
  1229. libfoo.so -> /path/libfoo.so
  1230. BUT
  1231. foo -> /path/libfoo.so
  1232. libfoo -> /path/liblibfoo.so
  1233. /path/libfoo -> lib/path/libfoo.so
  1234. */
  1235. char *
  1236. slapi_get_plugin_name(const char *path, const char *lib)
  1237. {
  1238. const char *libstr = "/lib";
  1239. size_t libstrlen = 4;
  1240. char *fullname = PR_GetLibraryName(path, lib);
  1241. char *ptr = PL_strrstr(fullname, lib);
  1242. /* see if /lib was added */
  1243. if (ptr && ((ptr - fullname) >= libstrlen)) {
  1244. /* ptr is at the libname in fullname, and there is something before it */
  1245. ptr -= libstrlen; /* ptr now points at the "/" in "/lib" if it is there */
  1246. if (0 == PL_strncmp(ptr, libstr, libstrlen)) {
  1247. /* just copy the remainder of the string on top of here */
  1248. ptr++; /* ptr now points at the "l" in "/lib" - keep the "/" */
  1249. memmove(ptr, ptr+3, strlen(ptr+3)+1);
  1250. }
  1251. } else if ((NULL == path) && (0 == strncmp(fullname, "lib", 3))) {
  1252. /*
  1253. * case: /path/libfoo -> lib/path/libfoo.so
  1254. * remove "lib".
  1255. */
  1256. memmove(fullname, fullname+3, strlen(fullname)-2);
  1257. }
  1258. return fullname;
  1259. }
  1260. /*
  1261. * Check if rdn is a slecial rdn/dn or not.
  1262. * If flag is IS_TOMBSTONE, returns 1 if rdn is a tombstone rdn/dn.
  1263. * If flag is IS_CONFLICT, returns 1 if rdn is a conflict rdn/dn.
  1264. * Otherwise returns 0.
  1265. */
  1266. static int util_uniqueidlen = 0;
  1267. int
  1268. slapi_is_special_rdn(const char *rdn, int flag)
  1269. {
  1270. char *rp;
  1271. int plus = 0;
  1272. if (!util_uniqueidlen) {
  1273. util_uniqueidlen = SLAPI_ATTR_UNIQUEID_LENGTH + slapi_uniqueIDSize() + 1/*=*/;
  1274. }
  1275. if ((RDN_IS_TOMBSTONE != flag) && (RDN_IS_CONFLICT != flag)) {
  1276. LDAPDebug1Arg(LDAP_DEBUG_ANY, "slapi_is_special_rdn: invalid flag %d\n", flag);
  1277. return 0; /* not a special rdn/dn */
  1278. }
  1279. if (!rdn) {
  1280. LDAPDebug0Args(LDAP_DEBUG_ANY, "slapi_is_special_rdn: NULL rdn\n");
  1281. return 0; /* not a special rdn/dn */
  1282. }
  1283. if (strlen(rdn) < util_uniqueidlen) {
  1284. return 0; /* not a special rdn/dn */
  1285. }
  1286. rp = (char *)rdn;
  1287. while (rp) {
  1288. char *endp = NULL;
  1289. if (!PL_strncasecmp(rp, SLAPI_ATTR_UNIQUEID, SLAPI_ATTR_UNIQUEID_LENGTH) &&
  1290. (*(rp + SLAPI_ATTR_UNIQUEID_LENGTH) == '=')) {
  1291. if (RDN_IS_TOMBSTONE == flag) {
  1292. if ((*(rp + util_uniqueidlen) == ',') ||
  1293. (*(rp + util_uniqueidlen) == '\0')) {
  1294. return 1;
  1295. } else {
  1296. return 0;
  1297. }
  1298. } else {
  1299. if ((*(rp + util_uniqueidlen) == '+') ||
  1300. (plus && ((*(rp + util_uniqueidlen) == ',') ||
  1301. (*(rp + util_uniqueidlen) == '\0')))) {
  1302. return 1;
  1303. }
  1304. }
  1305. } else if (RDN_IS_TOMBSTONE == flag) {
  1306. /* If the first part of rdn does not start with SLAPI_ATTR_UNIQUEID,
  1307. * it's not a tombstone RDN. */
  1308. return 0;
  1309. }
  1310. endp = PL_strchr(rp, ',');
  1311. if (!endp) {
  1312. endp = rp + strlen(rp);
  1313. }
  1314. rp = PL_strchr(rp, '+');
  1315. if (rp && (rp < endp)) {
  1316. plus = 1;
  1317. rp++;
  1318. }
  1319. }
  1320. return 0;
  1321. }
  1322. int
  1323. slapi_uniqueIDRdnSize()
  1324. {
  1325. if (!util_uniqueidlen) {
  1326. util_uniqueidlen = SLAPI_ATTR_UNIQUEID_LENGTH + slapi_uniqueIDSize() + 1/*=*/;
  1327. }
  1328. return util_uniqueidlen;
  1329. }
  1330. /**
  1331. * Get the virtual memory size as defined by system rlimits.
  1332. *
  1333. * \return size_t bytes available
  1334. */
  1335. static size_t util_getvirtualmemsize()
  1336. {
  1337. struct rlimit rl;
  1338. /* the maximum size of a process's total available memory, in bytes */
  1339. if (getrlimit(RLIMIT_AS, &rl) != 0) {
  1340. /* We received an error condition. There are a number of possible
  1341. * reasons we have have gotten here, but most likely is EINVAL, where
  1342. * rlim->rlim_cur was greater than rlim->rlim_max.
  1343. * As a result, we should return a 0, to tell the system we can't alloc
  1344. * memory.
  1345. */
  1346. int errsrv = errno;
  1347. slapi_log_error(SLAPI_LOG_FATAL,"util_getvirtualmemsize", "ERROR: getrlimit returned non-zero. errno=%u\n", errsrv);
  1348. return 0;
  1349. }
  1350. return rl.rlim_cur;
  1351. }
  1352. /* pages = number of pages of physical ram on the machine (corrected for 32-bit build on 64-bit machine).
  1353. * procpages = pages currently used by this process (or working set size, sometimes)
  1354. * availpages = some notion of the number of pages 'free'. Typically this number is not useful.
  1355. */
  1356. int util_info_sys_pages(size_t *pagesize, size_t *pages, size_t *procpages, size_t *availpages)
  1357. {
  1358. *pagesize = 0;
  1359. *pages = 0;
  1360. *availpages = 0;
  1361. if (procpages)
  1362. *procpages = 0;
  1363. #ifdef OS_solaris
  1364. *pagesize = (int)sysconf(_SC_PAGESIZE);
  1365. *pages = (int)sysconf(_SC_PHYS_PAGES);
  1366. *availpages = util_getvirtualmemsize() / *pagesize;
  1367. /* solaris has THE most annoying way to get this info */
  1368. if (procpages) {
  1369. struct prpsinfo psi;
  1370. char fn[40];
  1371. int fd;
  1372. sprintf(fn, "/proc/%d", getpid());
  1373. fd = open(fn, O_RDONLY);
  1374. if (fd >= 0) {
  1375. memset(&psi, 0, sizeof(psi));
  1376. if (ioctl(fd, PIOCPSINFO, (void *)&psi) == 0)
  1377. *procpages = psi.pr_size;
  1378. close(fd);
  1379. }
  1380. }
  1381. #endif
  1382. #ifdef LINUX
  1383. {
  1384. /*
  1385. * On linux because of the way that the virtual memory system works, we
  1386. * don't really need to think about other processes, or fighting them.
  1387. * But that's not without quirks.
  1388. *
  1389. * We are given a virtual memory space, represented by vsize (man 5 proc)
  1390. * This space is a "funny number". It's a best effort based system
  1391. * where linux instead of telling us how much memory *actually* exists
  1392. * for us to use, gives us a virtual memory allocation which is the
  1393. * value of ram + swap.
  1394. *
  1395. * But none of these pages even exist or belong to us on the real system
  1396. * until will malloc them AND write a non-zero to them.
  1397. *
  1398. * The biggest issue with this is that vsize does NOT consider the
  1399. * effect other processes have on the system. So a process can malloc
  1400. * 2 Gig from the host, and our vsize doesn't reflect that until we
  1401. * suddenly can't malloc anything.
  1402. *
  1403. * We can see exactly what we are using inside of the vmm by
  1404. * looking at rss (man 5 proc). This shows us the current actual
  1405. * allocation of memory we are using. This is a good thing.
  1406. *
  1407. * We obviously don't want to have any pages in swap, but sometimes we
  1408. * can't help that: And there is also no guarantee that while we have
  1409. * X bytes in vsize, that we can even allocate any of them. Plus, we
  1410. * don't know if we are about to allocate to swap or not .... or get us
  1411. * killed in a blaze of oom glory.
  1412. *
  1413. * So there are now two strategies avaliable in this function.
  1414. * The first is to blindly accept what the VMM tells us about vsize
  1415. * while we hope and pray that we don't get nailed because we used
  1416. * too much.
  1417. *
  1418. * The other is a more conservative approach: We check vsize from
  1419. * proc/pid/status, and we check /proc/meminfo for freemem
  1420. * Which ever value is "lower" is the upper bound on pages we could
  1421. * potentially allocate: generally, this will be MemAvailable.
  1422. */
  1423. size_t vmsize = 0;
  1424. size_t freesize = 0;
  1425. size_t rlimsize = 0;
  1426. *pagesize = getpagesize();
  1427. /* Get the amount of freeram, rss, and the vmsize */
  1428. FILE *f;
  1429. char fn[40], s[80];
  1430. sprintf(fn, "/proc/%d/status", getpid());
  1431. f = fopen(fn, "r");
  1432. if (!f) { /* fopen failed */
  1433. /* We should probably make noise here! */
  1434. int errsrv = errno;
  1435. slapi_log_error(SLAPI_LOG_FATAL,"util_info_sys_pages", "ERROR: Unable to open file /proc/%d/status. errno=%u\n", getpid(), errsrv);
  1436. return 1;
  1437. }
  1438. while (! feof(f)) {
  1439. fgets(s, 79, f);
  1440. if (feof(f)) {
  1441. break;
  1442. }
  1443. /* VmRSS shows us what we are ACTUALLY using for proc pages
  1444. * Rather than "funny" pages.
  1445. */
  1446. if (strncmp(s, "VmSize:", 7) == 0) {
  1447. sscanf(s+7, "%lu", (long unsigned int *)&vmsize);
  1448. }
  1449. if (strncmp(s, "VmRSS:", 6) == 0) {
  1450. sscanf(s+6, "%lu", (long unsigned int *)procpages);
  1451. }
  1452. }
  1453. fclose(f);
  1454. FILE *fm;
  1455. char *fmn = "/proc/meminfo";
  1456. fm = fopen(fmn, "r");
  1457. if (!fm) {
  1458. int errsrv = errno;
  1459. slapi_log_error(SLAPI_LOG_FATAL,"util_info_sys_pages", "ERROR: Unable to open file /proc/meminfo. errno=%u\n", errsrv);
  1460. return 1;
  1461. }
  1462. while (! feof(fm)) {
  1463. fgets(s, 79, fm);
  1464. /* Is this really needed? */
  1465. if (feof(fm)) {
  1466. break;
  1467. }
  1468. if (strncmp(s, "MemTotal:", 9) == 0) {
  1469. sscanf(s+9, "%lu", (long unsigned int *)pages);
  1470. }
  1471. if (strncmp(s, "MemAvailable:", 13) == 0) {
  1472. sscanf(s+13, "%lu", (long unsigned int *)&freesize);
  1473. }
  1474. }
  1475. fclose(fm);
  1476. *pages /= (*pagesize / 1024);
  1477. freesize /= (*pagesize / 1024);
  1478. /* procpages is now in kb not pages... */
  1479. *procpages /= (*pagesize / 1024);
  1480. rlimsize = util_getvirtualmemsize();
  1481. /* On a 64 bit system, this is uint64 max, but on 32 it's -1 */
  1482. /* Either way, we should be ignoring it at this point if it's infinite */
  1483. if (rlimsize != RLIM_INFINITY) {
  1484. /* This is in bytes, make it pages */
  1485. rlimsize = rlimsize / *pagesize;
  1486. }
  1487. /* Now we have vmsize, the availpages from getrlimit, our freesize */
  1488. vmsize /= (*pagesize / 1024);
  1489. /* Pages is the total ram on the system. We should smaller of:
  1490. * - vmsize
  1491. * - pages
  1492. */
  1493. LDAPDebug(LDAP_DEBUG_TRACE,"util_info_sys_pages pages=%lu, vmsize=%lu, \n",
  1494. (unsigned long) *pages, (unsigned long) vmsize,0);
  1495. if (vmsize < *pages) {
  1496. LDAPDebug(LDAP_DEBUG_TRACE,"util_info_sys_pages using vmsize for pages \n",0,0,0);
  1497. *pages = vmsize;
  1498. } else {
  1499. LDAPDebug(LDAP_DEBUG_TRACE,"util_info_sys_pages using pages for pages \n",0,0,0);
  1500. }
  1501. /* Availpages is how much we *could* alloc. We should take the smallest:
  1502. * - pages
  1503. * - getrlimit (availpages)
  1504. * - freesize
  1505. */
  1506. if (rlimsize == RLIM_INFINITY) {
  1507. LDAPDebug(LDAP_DEBUG_TRACE,"util_info_sys_pages pages=%lu, getrlim=RLIM_INFINITY, freesize=%lu\n",
  1508. (unsigned long)*pages, (unsigned long)freesize, 0);
  1509. } else {
  1510. LDAPDebug(LDAP_DEBUG_TRACE,"util_info_sys_pages pages=%lu, getrlim=%lu, freesize=%lu\n",
  1511. (unsigned long)*pages, (unsigned long)*availpages, (unsigned long)freesize);
  1512. }
  1513. if (rlimsize != RLIM_INFINITY && rlimsize < freesize && rlimsize < *pages) {
  1514. LDAPDebug(LDAP_DEBUG_TRACE,"util_info_sys_pages using getrlim for availpages \n",0,0,0);
  1515. *availpages = rlimsize;
  1516. } else if (*pages < freesize) {
  1517. LDAPDebug(LDAP_DEBUG_TRACE,"util_info_sys_pages using pages for availpages \n",0,0,0);
  1518. *availpages = *pages;
  1519. } else {
  1520. LDAPDebug(LDAP_DEBUG_TRACE,"util_info_sys_pages using freesize for availpages \n",0,0,0);
  1521. *availpages = freesize;
  1522. }
  1523. }
  1524. #endif /* linux */
  1525. #if defined ( hpux )
  1526. {
  1527. struct pst_static pst;
  1528. int rval = pstat_getstatic(&pst, sizeof(pst), (size_t)1, 0);
  1529. if (rval < 0) { /* pstat_getstatic failed */
  1530. return 1;
  1531. }
  1532. *pagesize = pst.page_size;
  1533. *pages = pst.physical_memory;
  1534. *availpages = util_getvirtualmemsize() / *pagesize;
  1535. if (procpages)
  1536. {
  1537. #define BURST (size_t)32 /* get BURST proc info at one time... */
  1538. struct pst_status psts[BURST];
  1539. int i, count;
  1540. int idx = 0; /* index within the context */
  1541. int mypid = getpid();
  1542. *procpages = 0;
  1543. /* loop until count == 0, will occur all have been returned */
  1544. while ((count = pstat_getproc(psts, sizeof(psts[0]), BURST, idx)) > 0) {
  1545. /* got count (max of BURST) this time. process them */
  1546. for (i = 0; i < count; i++) {
  1547. if (psts[i].pst_pid == mypid)
  1548. {
  1549. *procpages = (size_t)(psts[i].pst_dsize + psts[i].pst_tsize + psts[i].pst_ssize);
  1550. break;
  1551. }
  1552. }
  1553. if (i < count)
  1554. break;
  1555. /*
  1556. * now go back and do it again, using the next index after
  1557. * the current 'burst'
  1558. */
  1559. idx = psts[count-1].pst_idx + 1;
  1560. }
  1561. }
  1562. }
  1563. #endif
  1564. /* If this is a 32-bit build, it might be running on a 64-bit machine,
  1565. * in which case, if the box has tons of ram, we can end up telling
  1566. * the auto cache code to use more memory than the process can address.
  1567. * so we cap the number returned here.
  1568. */
  1569. #if defined(__LP64__) || defined (_LP64)
  1570. #else
  1571. {
  1572. #define GIGABYTE (1024*1024*1024)
  1573. size_t one_gig_pages = GIGABYTE / *pagesize;
  1574. if (*pages > (2 * one_gig_pages) ) {
  1575. LDAPDebug(LDAP_DEBUG_TRACE,"More than 2Gbytes physical memory detected. Since this is a 32-bit process, truncating memory size used for auto cache calculations to 2Gbytes\n",
  1576. 0, 0, 0);
  1577. *pages = (2 * one_gig_pages);
  1578. }
  1579. }
  1580. #endif
  1581. /* This is stupid. If you set %u to %zu to print a size_t, you get literal %zu in your logs
  1582. * So do the filthy cast instead.
  1583. */
  1584. slapi_log_error(SLAPI_LOG_TRACE,"util_info_sys_pages", "USING pages=%lu, procpages=%lu, availpages=%lu \n",
  1585. (unsigned long)*pages, (unsigned long)*procpages, (unsigned long)*availpages);
  1586. return 0;
  1587. }
  1588. int util_is_cachesize_sane(size_t *cachesize)
  1589. {
  1590. size_t pages = 0;
  1591. size_t pagesize = 0;
  1592. size_t procpages = 0;
  1593. size_t availpages = 0;
  1594. size_t cachepages = 0;
  1595. int issane = 1;
  1596. if (util_info_sys_pages(&pagesize, &pages, &procpages, &availpages) != 0) {
  1597. goto out;
  1598. }
  1599. #ifdef LINUX
  1600. /* Linux we calculate availpages correctly, so USE IT */
  1601. if (!pagesize || !availpages) {
  1602. goto out;
  1603. }
  1604. #else
  1605. if (!pagesize || !pages) {
  1606. goto out;
  1607. }
  1608. #endif
  1609. /* do nothing when we can't get the avail mem */
  1610. /* If the requested cache size is larger than the remaining physical memory
  1611. * after the current working set size for this process has been subtracted,
  1612. * then we say that's insane and try to correct.
  1613. */
  1614. cachepages = *cachesize / pagesize;
  1615. LDAPDebug(LDAP_DEBUG_TRACE,"util_is_cachesize_sane cachesize=%lu / pagesize=%lu \n",
  1616. (unsigned long)*cachesize,(unsigned long)pagesize,0);
  1617. #ifdef LINUX
  1618. /* Linux we calculate availpages correctly, so USE IT */
  1619. issane = (int)(cachepages <= availpages);
  1620. LDAPDebug(LDAP_DEBUG_TRACE,"util_is_cachesize_sane cachepages=%lu <= availpages=%lu\n",
  1621. (unsigned long)cachepages,(unsigned long)availpages,0);
  1622. if (!issane) {
  1623. /* Since we are ask for more than what's available, we give 3/4 of the remaining.
  1624. * the remaining system mem to the cachesize instead, and log a warning
  1625. */
  1626. *cachesize = (size_t)((availpages * 0.75 ) * pagesize);
  1627. slapi_log_error(SLAPI_LOG_FATAL, "util_is_cachesize_sane", "WARNING adjusted cachesize to %lu\n", (unsigned long)*cachesize);
  1628. }
  1629. #else
  1630. size_t freepages = 0;
  1631. freepages = pages - procpages;
  1632. LDAPDebug(LDAP_DEBUG_TRACE,"util_is_cachesize_sane pages=%lu - procpages=%lu\n",
  1633. (unsigned long)pages,(unsigned long)procpages,0);
  1634. issane = (int)(cachepages <= freepages);
  1635. LDAPDebug(LDAP_DEBUG_TRACE,"util_is_cachesize_sane cachepages=%lu <= freepages=%lu\n",
  1636. (unsigned long)cachepages,(unsigned long)freepages,0);
  1637. if (!issane) {
  1638. *cachesize = (size_t)((pages - procpages) * pagesize);
  1639. slapi_log_error(SLAPI_LOG_FATAL, "util_is_cachesize_sane", "util_is_cachesize_sane WARNING adjusted cachesize to %lu\n",
  1640. (unsigned long )*cachesize);
  1641. }
  1642. #endif
  1643. out:
  1644. if (!issane) {
  1645. slapi_log_error(SLAPI_LOG_FATAL,"util_is_cachesize_sane", "WARNING: Cachesize not sane \n");
  1646. }
  1647. return issane;
  1648. }
  1649. void
  1650. slapi_create_errormsg(
  1651. char *errorbuf,
  1652. size_t len,
  1653. const char *fmt,
  1654. ...
  1655. )
  1656. {
  1657. if (errorbuf) {
  1658. va_list ap;
  1659. va_start(ap, fmt);
  1660. (void)PR_vsnprintf(errorbuf, len?len-1:sizeof(errorbuf)-1, fmt, ap);
  1661. va_end( ap );
  1662. }
  1663. }