dsgwutil.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349
  1. /** --- BEGIN COPYRIGHT BLOCK ---
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. --- END COPYRIGHT BLOCK --- */
  38. /*
  39. * dsgwutil.c -- misc. utility functions -- HTTP gateway
  40. */
  41. #include <limits.h> /* PATH_MAX */
  42. #include "dsgw.h"
  43. #include "dbtdsgw.h"
  44. #ifdef NS_DS
  45. #include "../lib/libsi18n/gsslapd.h"
  46. #else /* Admin Server */
  47. #include "../lib/libsi18n/gsadmserv.h"
  48. #endif
  49. #ifdef DSGW_DEBUG
  50. #include <time.h>
  51. #include <stdarg.h>
  52. #endif /* DSGW_DEBUG */
  53. static char **vpmap = NULL;
  54. extern char *Versionstr; /* from Versiongw.c */
  55. char *progname; /* set by dsgw_init() */
  56. dsgwconfig *gc; /* set by dsgw_init() */
  57. int http_hdr_sent = 0; /* non-zero if header has been sent */
  58. char **header_lines = NULL; /* null-terminated array of hdr lines */
  59. char *dsgw_html_body_colors = ""; /* reset by dsgw_init() */
  60. /*Global context variable, telling the CGI's where to look for the config file*/
  61. char *context = NULL; /* Gotten from the QUERY_STRING */
  62. char *langwich = NULL; /* The language that libsi18n
  63. picks from acceptlang*/
  64. char *countri = NULL; /* The country that libsi18n
  65. picks from acceptlang*/
  66. static void figure_out_langwich(void);
  67. /*
  68. * dsgw_init -- initialize a dsgw CGI program:
  69. * set "progname" global based on "progpath" (normally argv[0])
  70. * check that REQUEST_METHOD is in "methods_handled" mask
  71. * if request method is "POST", read HTML form variables from stdin
  72. * handles the context variable if the CGI was called with a post.
  73. * The context variable tells dsgw_read_config what config file
  74. * to read.
  75. *
  76. * If an fatal error occurs, -1 is returned.
  77. * If all goes well, returns either DSGW_METHOD_GET or DSGW_METHOD_POST
  78. */
  79. int
  80. dsgw_init( int argc, char **argv, int methods_handled )
  81. {
  82. char *m, *s;
  83. int method;
  84. int c, err;
  85. (void)ADM_Init();
  86. /* initialize the string database */
  87. XP_InitStringDatabase(
  88. #ifdef NS_DS
  89. SERVER_ROOT_PATH "/bin/slapd/property" /* Directory Server Gateway */
  90. #else
  91. SERVER_ROOT_PATH "/admin" /* Admin Server */
  92. #endif
  93. , DATABASE_NAME);
  94. /* set default default languages for string database */
  95. SetLanguage(CLIENT_LANGUAGE, "");
  96. SetLanguage(ADMIN_LANGUAGE, "");
  97. SetLanguage(DEFAULT_LANGUAGE, "");
  98. if (( progname = strchr( argv[0], '/' )) == NULL ) {
  99. progname = dsgw_ch_strdup( argv[0] );
  100. #ifdef _WIN32
  101. if (( s = strrchr( progname, '.' )) != NULL
  102. && strcasecmp( s, ".EXE" ) == 0 ) {
  103. *s = '\0';
  104. }
  105. #endif /* _WIN32 */
  106. } else {
  107. ++progname;
  108. }
  109. while (( c = getopt( argc, argv, "v" )) != EOF ) {
  110. if ( c == 'v' ) {
  111. printf( "%s\n", Versionstr );
  112. }
  113. exit( 0 );
  114. }
  115. #ifdef DSGW_DEBUG
  116. dsgw_log( "%s started\n", Versionstr );
  117. #endif
  118. err = method = 0;
  119. /*Have to get the context before we read the config file.*/
  120. if (( m = getenv( "REQUEST_METHOD" )) != NULL ) {
  121. if ( strcasecmp( m, "GET" ) == 0 || strcasecmp( m, "HEAD" ) == 0 ) {
  122. method = DSGW_METHOD_GET;
  123. } else if ( strcasecmp( m, "POST" ) == 0 ) {
  124. method = DSGW_METHOD_POST;
  125. if (( err = dsgw_post_begin( stdin )) == 0 ) {
  126. context = dsgw_get_cgi_var( "context", DSGW_CGIVAR_OPTIONAL );
  127. }
  128. }
  129. }
  130. if ( method == 0 || ( methods_handled & method ) == 0 ) {
  131. dsgw_error( DSGW_ERR_BADMETHOD, NULL, DSGW_ERROPT_EXIT, 0, NULL );
  132. }
  133. /*If no context was given, try default.conf.*/
  134. if (context == NULL) {
  135. context = dsgw_ch_strdup("default");
  136. }
  137. /* If this is a LIte installation: dsgw is not enabled */
  138. /* this assumes the current dir is <server root>/dsgw/bin; under http servers
  139. other than admin server, we have to rely on relative paths to find the
  140. key file */
  141. if ( is_directory_lite (SERVER_ROOT_PATH)) {
  142. dsgw_error( DSGW_ERR_BADCONFIG, XP_GetClientStr(DBT_NotWillingToExecute_),
  143. DSGW_ERROPT_EXIT, 0, NULL );
  144. }
  145. gc = dsgw_read_config();
  146. gc->gc_charset = dsgw_emit_converts_to (gc->gc_charset);
  147. {
  148. /* eliminate elements of gc_changeHTML that don't apply to gc_charset: */
  149. auto dsgwsubst **s = &(gc->gc_changeHTML);
  150. auto char *charset = gc->gc_charset;
  151. if ( charset == NULL ) charset = ""; /* Latin-1, implicitly */
  152. while ( *s ) {
  153. auto char **c = (*s)->dsgwsubst_charsets;
  154. if ( c && *c ) {
  155. for ( ; *c; ++c ) {
  156. if ( strcasecmp( *c, charset ) == 0 ) {
  157. break;
  158. }
  159. }
  160. if ( *c == NULL ) {
  161. *s = (*s)->dsgwsubst_next; /* eliminate **s */
  162. /* This is quick and dirty: we just created garbage. */
  163. continue;
  164. }
  165. }
  166. s = &((*s)->dsgwsubst_next);
  167. }
  168. }
  169. /* set languages for string database */
  170. SetLanguage(CLIENT_LANGUAGE,gc->gc_ClientLanguage);
  171. SetLanguage(ADMIN_LANGUAGE,gc->gc_AdminLanguage);
  172. SetLanguage(DEFAULT_LANGUAGE,gc->gc_DefaultLanguage);
  173. /* Figure out the language that libsi18n is using */
  174. figure_out_langwich();
  175. /* Get the port and servername */
  176. if (method == DSGW_METHOD_POST) {
  177. if (( s = dsgw_get_cgi_var( "ldapport", DSGW_CGIVAR_OPTIONAL )) != NULL ) {
  178. gc->gc_ldapport = atoi( s );
  179. free( s );
  180. }
  181. if (( s = dsgw_get_cgi_var( "ldapserver", DSGW_CGIVAR_OPTIONAL )) != NULL ) {
  182. gc->gc_ldapserver = s;
  183. }
  184. }
  185. if (( s = getenv( "HTTPS" )) == NULL || strcasecmp( s, "on" ) == 0 ||
  186. ( s = getenv( "HTTPS_KEYSIZE" )) == NULL ) {
  187. gc->gc_httpskeysize = 0;
  188. } else {
  189. gc->gc_httpskeysize = atoi( s );
  190. }
  191. /* set default color scheme */
  192. if ( method == DSGW_METHOD_POST && ( s = dsgw_get_cgi_var( "colors",
  193. DSGW_CGIVAR_OPTIONAL )) != NULL ) {
  194. dsgw_html_body_colors = s;
  195. } else if ( gc->gc_admserv ) { /* use same color scheme as libadmin */
  196. dsgw_html_body_colors = "BGCOLOR=\"#C0C0C0\" LINK=\"#0000EE\" "
  197. "VLINK=\"#551A8B\" ALINK=\"#FF0000\"";
  198. } else {
  199. dsgw_html_body_colors = "BGCOLOR=\"white\"";
  200. }
  201. return( method );
  202. }
  203. /*
  204. * function called back by dsgw_parse_line() to evaluate IF directives.
  205. * return non-zero for true, zero for false.
  206. */
  207. int
  208. dsgw_simple_cond_is_true( int argc, char **argv, void *arg /* UNUSED */ )
  209. {
  210. if ( strcasecmp( argv[0], DSGW_COND_ADMSERV ) == 0 ) {
  211. return( gc->gc_admserv );
  212. }
  213. if ( strcasecmp( argv[0], DSGW_COND_LOCALDB ) == 0 ) {
  214. return( gc->gc_localdbconf != NULL );
  215. }
  216. if ( strcasecmp( argv[0], DSGW_COND_POSTEDFORMVALUE ) == 0 ) {
  217. /*
  218. * format of IF statment is:
  219. * <-- IF "PostedFormValue" "VARNAME" "VALUE" -->
  220. * where VARNAME is the name of a POSTed CGI variable to look for and
  221. * VALUE is an optional value to test it against. If VALUE is omitted,
  222. * the test is just for the presence of a variable named VARNAME.
  223. */
  224. char *postedvalue;
  225. if ( argc < 2 || ( postedvalue = dsgw_get_cgi_var( argv[1],
  226. DSGW_CGIVAR_OPTIONAL )) == NULL ) {
  227. return( 0 ); /* VARNAME is missing or not posted */
  228. } else if ( argc < 3 ) {
  229. return( 1 ); /* VALUE is missing, so return true */
  230. } else {
  231. return( strcasecmp( postedvalue, argv[ 2 ] ) == 0 );
  232. }
  233. }
  234. return( 0 );
  235. }
  236. /*
  237. * return a pointer to a malloc'd string containing the path to
  238. * config. file "filename", based on the DSGW_CONFIGDIR define.
  239. * If "filename" contains "..", or "//" this is treated as a fatal
  240. * error. If "prefix" is not NULL, it is pre-pended to "filename"
  241. */
  242. char *
  243. dsgw_file2path( char *prefix, char *filename )
  244. {
  245. char *path, *pattern;
  246. int len;
  247. if ( strstr( filename, "//" ) != NULL ||
  248. strstr( filename, ".." ) != NULL ) {
  249. dsgw_error( DSGW_ERR_BADFILEPATH, filename, DSGW_ERROPT_EXIT, 0, NULL );
  250. }
  251. if ( prefix == NULL ) {
  252. prefix = "";
  253. }
  254. /* allocate buffers with enough extra room to fit "$$LANGDIR/" */
  255. len = strlen( prefix ) + strlen( filename ) + 11;
  256. if ( NULL != gc->gc_ClientLanguage ) {
  257. len += strlen( gc->gc_ClientLanguage );
  258. }
  259. path = dsgw_ch_malloc( len );
  260. pattern = dsgw_ch_malloc( len );
  261. /* call GetFileForLanguage() to do its I18n magic */
  262. sprintf( pattern, "%s$$LANGDIR/%s", prefix, filename );
  263. if ( GetFileForLanguage( pattern, gc->gc_ClientLanguage, path ) < 0 ) {
  264. sprintf( path, "%s%s", prefix, filename ); /* fallback */
  265. }
  266. free( pattern );
  267. return( path );
  268. }
  269. /*
  270. * return a pointer to a malloc'd string containing the path to
  271. * config. file "filename", based on the DSGW_HTMLDIR define.
  272. * If "filename" contains "..", or "//" this is treated as a fatal
  273. * error. If "prefix" is not NULL, it is pre-pended to "filename"
  274. */
  275. char *
  276. dsgw_file2htmlpath( char *prefix, char *filename )
  277. {
  278. char *path, *pattern;
  279. int len;
  280. if ( strstr( filename, "//" ) != NULL ||
  281. strstr( filename, ".." ) != NULL ) {
  282. dsgw_error( DSGW_ERR_BADFILEPATH, filename, DSGW_ERROPT_EXIT, 0, NULL );
  283. }
  284. if ( prefix == NULL ) {
  285. prefix = "";
  286. }
  287. /* allocate buffers with enough extra room to fit "$$LANGDIR/" */
  288. /*len = strlen( DSGW_HTMLDIR ) + strlen( prefix ) + strlen( filename ) + 11;*/
  289. len = strlen( gc->gc_docdir ) + strlen( prefix ) + strlen( filename ) + 11;
  290. if ( NULL != gc->gc_ClientLanguage ) {
  291. len += strlen( gc->gc_ClientLanguage );
  292. }
  293. path = dsgw_ch_malloc( len );
  294. pattern = dsgw_ch_malloc( len );
  295. /* call GetFileForLanguage() to do its I18n magic */
  296. sprintf( pattern, "%s%s$$LANGDIR/%s", gc->gc_docdir, prefix, filename );
  297. if ( GetFileForLanguage( pattern, gc->gc_ClientLanguage, path ) < 0 ) {
  298. /* use fallback */
  299. sprintf( path, "%s/%s%s", gc->gc_docdir, prefix, filename );
  300. }
  301. free( pattern );
  302. return( path );
  303. }
  304. /*
  305. * malloc that checks for NULL return value and exits upon failure
  306. */
  307. void *
  308. dsgw_ch_malloc( size_t n )
  309. {
  310. void *p;
  311. if (( p = malloc( n )) == NULL ) {
  312. dsgw_error( DSGW_ERR_NOMEMORY, NULL, DSGW_ERROPT_EXIT, 0, NULL );
  313. }
  314. return( p );
  315. }
  316. void *
  317. dsgw_ch_calloc( size_t nelem, size_t elsize )
  318. {
  319. register void *p = calloc( nelem, elsize );
  320. if ( p == NULL ) {
  321. dsgw_error( DSGW_ERR_NOMEMORY, NULL, DSGW_ERROPT_EXIT, 0, NULL );
  322. }
  323. return( p );
  324. }
  325. /*
  326. * realloc that checks for NULL return value and exits upon failure
  327. * we also handle p == NULL by doing a malloc
  328. */
  329. void *
  330. dsgw_ch_realloc( void *p, size_t n )
  331. {
  332. if ( p == NULL ) {
  333. p = malloc( n );
  334. } else {
  335. p = realloc( p, n );
  336. }
  337. if ( p == NULL ) {
  338. dsgw_error( DSGW_ERR_NOMEMORY, NULL, DSGW_ERROPT_EXIT, 0, NULL );
  339. }
  340. return( p );
  341. }
  342. /*
  343. * strdup that checks for NULL return value and exits upon failure
  344. */
  345. char *
  346. dsgw_ch_strdup( const char *s )
  347. {
  348. int len;
  349. char *p;
  350. len = strlen( s ) + 1;
  351. p = dsgw_ch_malloc( len );
  352. memcpy( p, s, len );
  353. return( p );
  354. }
  355. /*
  356. * Escape any single- or double-quotes with a '\'. Used when generating
  357. * JavaScript code. Returns a malloc'd string which the caller is
  358. * responsible for freeing.
  359. */
  360. char *
  361. dsgw_escape_quotes( char *in )
  362. {
  363. char *out;
  364. char *p, *t;
  365. int nq = 0;
  366. if ( in == NULL ) {
  367. return NULL;
  368. }
  369. /* count number of quotes */
  370. for ( p = in; *p != '\0'; p++ ) {
  371. if ( *p == '\'' || *p == '"' ) {
  372. nq++;
  373. }
  374. }
  375. out = dsgw_ch_malloc(( p - in ) + nq + 1 );
  376. for ( p = in, t = out; *p != '\0'; p++ ) {
  377. if ( *p == '\'' || *p == '"' ) {
  378. *t++ = '\\';
  379. }
  380. *t++ = *p;
  381. }
  382. *t = '\0';
  383. return out;
  384. }
  385. char *
  386. dsgw_get_translation( char *in )
  387. {
  388. dsgwsubst *p;
  389. #ifdef DSGW_DEBUG
  390. dsgw_log( "L10n map table:\n" );
  391. for ( p = gc->gc_l10nsets; p ; p = p->dsgwsubst_next ) {
  392. dsgw_log( "%s -> %s\n", p->dsgwsubst_from, p->dsgwsubst_to );
  393. }
  394. #endif
  395. for ( p = gc->gc_l10nsets; p ; p = p->dsgwsubst_next ) {
  396. if ( !strcasecmp( in, p->dsgwsubst_from ))
  397. return p->dsgwsubst_to;
  398. }
  399. return in;
  400. }
  401. static void
  402. dsgw_puts (const char* s)
  403. {
  404. dsgw_fputn (stdout, s, strlen(s));
  405. }
  406. #define CONTENT_TYPE "Content-type"
  407. #define TYPE_HTML "text/html"
  408. #define VARY "Vary"
  409. #define VARYLIST "Accept-Language,Accept-Charset,User-Agent"
  410. static const char* ct_prefix = CONTENT_TYPE ": " TYPE_HTML;
  411. static const char* cs_prefix = ";charset=";
  412. static const char* vr_prefix = VARY ": ";
  413. /*
  414. * Send the headers we've accumulated.
  415. */
  416. void
  417. dsgw_send_header()
  418. {
  419. int i;
  420. if ( http_hdr_sent ) {
  421. return;
  422. }
  423. if ( header_lines == NULL ) {
  424. dsgw_puts (ct_prefix);
  425. if ( gc != NULL && gc->gc_charset != NULL && *gc->gc_charset != '\0' ) {
  426. dsgw_puts (cs_prefix); dsgw_puts (gc->gc_charset );
  427. }
  428. dsgw_puts ("\n");
  429. /* send Vary tag if HTTP/1.1 or greater */
  430. if ( NULL != gc && gc->gc_httpversion >= 1.1 ) {
  431. dsgw_puts (vr_prefix); dsgw_puts (VARYLIST); dsgw_puts ("\n");
  432. }
  433. } else for ( i = 0; header_lines[ i ] != NULL; i++ ) {
  434. dsgw_puts (header_lines[ i ]);
  435. dsgw_puts ("\n");
  436. }
  437. dsgw_puts ("\n");
  438. http_hdr_sent = 1;
  439. }
  440. /*
  441. * Add a line to the array of header lines.
  442. */
  443. void
  444. dsgw_add_header( char *line )
  445. {
  446. int i;
  447. if ( header_lines == NULL ) {
  448. header_lines = ( char ** ) dsgw_ch_malloc( 3 * sizeof( char * ));
  449. if ( gc != NULL && gc->gc_charset != NULL && *gc->gc_charset != '\0' ) {
  450. header_lines[ 0 ] = dsgw_ch_malloc( strlen( ct_prefix ) +
  451. strlen( cs_prefix ) + strlen( gc->gc_charset ) + 1 );
  452. sprintf( header_lines[ 0 ], "%s%s%s", ct_prefix, cs_prefix,
  453. gc->gc_charset );
  454. } else {
  455. header_lines[ 0 ] = dsgw_ch_strdup( ct_prefix );
  456. }
  457. /* send Vary tag if HTTP/1.1 or greater */
  458. if ( gc->gc_httpversion >= 1.1 ) {
  459. header_lines[ 1 ] =
  460. dsgw_ch_malloc( strlen( vr_prefix ) + sizeof( VARYLIST ) );
  461. /* (char *) */ /* string literal */
  462. sprintf( header_lines[ 1 ], "%s%s", vr_prefix, VARYLIST );
  463. header_lines[ 2 ] = NULL;
  464. } else {
  465. header_lines[ 1 ] = NULL;
  466. }
  467. }
  468. for ( i = 0; header_lines[ i ] != NULL; i++ );
  469. header_lines = (char **) dsgw_ch_realloc( header_lines,
  470. ( i + 2 ) * sizeof( char * ));
  471. header_lines[ i ] = dsgw_ch_strdup( line );
  472. header_lines[ i + 1 ] = NULL;
  473. }
  474. /*
  475. * Check the environment for an authentication cookie. Returns the
  476. * entire auth cookie if present, or returns NULL if no such cookie
  477. * exists. The returned string must be freed by the caller.
  478. */
  479. char *
  480. dsgw_get_auth_cookie()
  481. {
  482. char *p, *e, *ckhdr;
  483. ckhdr = getenv( "HTTP_COOKIE" );
  484. if ( ckhdr == NULL ) {
  485. return NULL;
  486. } else {
  487. ckhdr = strdup( ckhdr );
  488. }
  489. if (( p = strstr( ckhdr, DSGW_AUTHCKNAME )) == NULL ) {
  490. free( ckhdr );
  491. return NULL;
  492. }
  493. if (( e = strchr( p, ';' )) != NULL ) {
  494. *e = '\0';
  495. }
  496. p = strdup( p );
  497. free( ckhdr );
  498. return p;
  499. }
  500. /*
  501. * Break a cookie into its random string and DN parts. The DN is returned
  502. * unescaped. The caller is responsible for freeing the returned DN
  503. * and random string. Returns 0 on success, -1 on error. If the
  504. * cookie has the value "[unauthenticated]", then 0 is returned and
  505. * dn is set to NULL;
  506. */
  507. int
  508. dsgw_parse_cookie( char *cookie, char **rndstr, char **dn )
  509. {
  510. char *p, *r;
  511. int rlen;
  512. if ( cookie == NULL ) {
  513. *rndstr = *dn = NULL;
  514. return -1;
  515. }
  516. /* Make sure cookie starts with "nsdsgwauth" */
  517. if ( strncmp( cookie, DSGW_AUTHCKNAME, strlen( DSGW_AUTHCKNAME ))) {
  518. /* Cookie didn't start with "nsdsgwauth" */
  519. *rndstr = *dn = NULL;
  520. return -1;
  521. }
  522. r = cookie + strlen( DSGW_AUTHCKNAME );
  523. if ( *r == '=' ) {
  524. r++;
  525. }
  526. /* Is cookie value "[unauthenticated]" ? */
  527. if ( !strncmp( r, DSGW_UNAUTHSTR, strlen( DSGW_UNAUTHSTR ))) {
  528. *rndstr = strdup( DSGW_UNAUTHSTR );
  529. *dn = NULL;
  530. return 0;
  531. }
  532. /* find start of DN */
  533. if (( p = strrchr( cookie, ':' )) == NULL ) {
  534. *rndstr = *dn = NULL;
  535. return -1;
  536. }
  537. rlen = p - r + 1;
  538. *(rndstr) = dsgw_ch_malloc( rlen );
  539. *(rndstr)[ 0 ] = '\0';
  540. strncat( *rndstr, r, rlen-1 );
  541. (*rndstr)[ rlen - 1 ] = '\0';
  542. p++;
  543. *dn = strdup( p );
  544. dsgw_form_unescape( *dn );
  545. return 0;
  546. }
  547. /*
  548. * Generate a "go home" button with a link to the main entry point for
  549. * the gateway. The caller is responsible for any surrounding
  550. * HTML, e.g. <FORM> and <TABLE> tags.
  551. */
  552. void
  553. dsgw_emit_homebutton()
  554. {
  555. dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" "
  556. "onClick=\"top.location.href='%s'\">", XP_GetClientStr(DBT_returnToMain_), gc->gc_urlpfxmain /*DSGW_URLPREFIX_MAIN*/ );
  557. }
  558. /*
  559. * Generate a help button with a link to the tutor program for
  560. * the given help topic. The caller is responsible for any surrounding
  561. * HTML, e.g. <FORM> and <TABLE> tags.
  562. */
  563. void
  564. dsgw_emit_helpbutton( char *topic )
  565. {
  566. if ( topic == NULL ) {
  567. return;
  568. }
  569. if ( gc->gc_admserv ) {
  570. char *jscript;
  571. if (( jscript = helpJavaScriptForTopic( topic )) == NULL ) {
  572. return;
  573. }
  574. dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" onClick=\"%s\">",
  575. #define LABEL_HELP "ヘルプ"
  576. /*LABEL_HELP*/ XP_GetClientStr(DBT_help_), jscript );
  577. } else {
  578. char *tutorvp;
  579. tutorvp = dsgw_getvp( DSGW_CGINUM_TUTOR );
  580. /*
  581. * the following is based on code that was found in
  582. * ldapserver/lib/libadmin/template.c inside the
  583. * helpJavaScriptForTopic() function. We need our own copy because
  584. * we use a different tutor CGI. Sigh.
  585. */
  586. dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" onClick=\""
  587. "if ( top.helpwin ) {"
  588. " top.helpwin.focus();"
  589. " top.helpwin.infotopic.location='%s?!%s&context=%s';"
  590. "} else {"
  591. " window.open('%s?%s&context=%s', 'infowin_dsgw', "
  592. " 'resizable=1,width=400,height=500');"
  593. "}\">\n",
  594. XP_GetClientStr(DBT_help_1),tutorvp, topic, context,
  595. tutorvp, topic, context );
  596. }
  597. }
  598. /*
  599. * Return malloc'd URL prefix that consists of:
  600. * prefix + '/' + HOST:PORT + '/' (not anymore - RJP)
  601. * prefix + ? + context=CONTEXT&hp=HOST:PORT&dn=
  602. */
  603. char *
  604. dsgw_build_urlprefix()
  605. {
  606. char *prefix = dsgw_getvp( DSGW_CGINUM_DOSEARCH );
  607. char *p, *urlprefix;
  608. p = ( gc->gc_ldapserver == NULL ? "" : gc->gc_ldapserver );
  609. urlprefix = dsgw_ch_malloc( 16 /* room for "?:port#&dn=" + zero-term. */
  610. + strlen( prefix ) + strlen( p ) +strlen(context) + 9);
  611. sprintf( urlprefix, "%s?context=%s&hp=%s", prefix, context, p );
  612. if ( gc->gc_ldapport != 0 && gc->gc_ldapport != LDAP_PORT ) {
  613. sprintf( urlprefix + strlen( urlprefix ), ":%d", gc->gc_ldapport );
  614. }
  615. strcat( urlprefix,"&dn=" );
  616. return( urlprefix );
  617. }
  618. void
  619. dsgw_addtemplate( dsgwtmpl **tlpp, char *template, int count, char **ocvals )
  620. {
  621. int i;
  622. dsgwtmpl *prevtp, *tp;
  623. tp = (dsgwtmpl *)dsgw_ch_malloc( sizeof( dsgwtmpl ));
  624. memset( tp, 0, sizeof( dsgwtmpl ));
  625. tp->dstmpl_name = dsgw_ch_strdup( template );
  626. /* each argument is one objectClass */
  627. tp->dstmpl_ocvals = dsgw_ch_malloc(( count + 1 ) * sizeof( char * ));
  628. for ( i = 0; i < count; ++i ) {
  629. tp->dstmpl_ocvals[ i ] = dsgw_ch_strdup( ocvals[ i ] );
  630. }
  631. tp->dstmpl_ocvals[ count ] = NULL;
  632. if ( *tlpp == NULL ) {
  633. *tlpp = tp;
  634. } else {
  635. for ( prevtp = *tlpp; prevtp->dstmpl_next != NULL;
  636. prevtp = prevtp->dstmpl_next ) {
  637. ;
  638. }
  639. prevtp->dstmpl_next = tp;
  640. }
  641. }
  642. dsgwtmpl *
  643. dsgw_oc2template( char **ocvals )
  644. {
  645. int i, j, needcnt, matchcnt;
  646. dsgwtmpl *tp;
  647. for ( tp = gc->gc_templates; tp != NULL; tp = tp->dstmpl_next ) {
  648. needcnt = matchcnt = 0;
  649. for ( i = 0; tp->dstmpl_ocvals[ i ] != NULL; ++i ) {
  650. for ( j = 0; ocvals[ j ] != NULL; ++j ) {
  651. if ( strcasecmp( ocvals[ j ], tp->dstmpl_ocvals[ i ] ) == 0 ) {
  652. ++matchcnt;
  653. }
  654. }
  655. ++needcnt;
  656. }
  657. if ( matchcnt == needcnt ) {
  658. return( tp );
  659. }
  660. }
  661. return( NULL );
  662. }
  663. void
  664. dsgw_init_searchprefs( struct ldap_searchobj **solistp )
  665. {
  666. char *path;
  667. path = dsgw_file2path( gc->gc_configdir, DSGW_SEARCHPREFSFILE );
  668. if ( ldap_init_searchprefs( path, solistp ) != 0 ) {
  669. dsgw_error( DSGW_ERR_BADCONFIG, path, DSGW_ERROPT_EXIT, 0, NULL );
  670. }
  671. free( path );
  672. }
  673. void
  674. dsgw_remove_leading_and_trailing_spaces( char **sp )
  675. {
  676. auto char *s, *p;
  677. if ( sp == NULL || *sp == NULL ) {
  678. return;
  679. }
  680. s = *sp;
  681. /* skip past any leading spaces */
  682. while ( ldap_utf8isspace( s )) {
  683. LDAP_UTF8INC (s);
  684. }
  685. /* truncate to remove any trailing spaces */
  686. if ( *s != '\0' ) {
  687. p = s + strlen( s );
  688. LDAP_UTF8DEC (p);
  689. while (ldap_utf8isspace( p )) {
  690. LDAP_UTF8DEC (p);
  691. }
  692. *LDAP_UTF8INC(p) = '\0';
  693. }
  694. *sp = s;
  695. }
  696. /*
  697. * Return the virtual path prefix for the CGI program specified by
  698. * cginum.
  699. */
  700. char *
  701. dsgw_getvp( int cginum )
  702. {
  703. char *cginame;
  704. char *surl;
  705. /*char *extpath;*/
  706. int i;
  707. if ( cginum < 1 || cginum > DSGW_MODE_NUMMODES ) {
  708. return "";
  709. }
  710. if ( vpmap == NULL ) {
  711. /* note: slot zero of vpmap isn't used */
  712. vpmap = dsgw_ch_malloc(( DSGW_MODE_NUMMODES + 1 ) * sizeof( char * ));
  713. for ( i = 0; i <= DSGW_MODE_NUMMODES; i++ ) {
  714. vpmap[ i ] = NULL;
  715. }
  716. }
  717. if ( vpmap[ cginum ] == NULL ) {
  718. switch ( cginum ) {
  719. case DSGW_CGINUM_DOSEARCH:
  720. cginame = DSGW_CGINAME_DOSEARCH;
  721. break;
  722. case DSGW_CGINUM_BROWSE:
  723. cginame = DSGW_CGINAME_BROWSE;
  724. break;
  725. case DSGW_CGINUM_SEARCH:
  726. cginame = DSGW_CGINAME_SEARCH;
  727. break;
  728. case DSGW_CGINUM_CSEARCH:
  729. cginame = DSGW_CGINAME_CSEARCH;
  730. break;
  731. case DSGW_CGINUM_AUTH:
  732. cginame = DSGW_CGINAME_AUTH;
  733. break;
  734. case DSGW_CGINUM_EDIT:
  735. cginame = DSGW_CGINAME_EDIT;
  736. break;
  737. case DSGW_CGINUM_DOMODIFY:
  738. cginame = DSGW_CGINAME_DOMODIFY;
  739. break;
  740. case DSGW_CGINUM_DNEDIT:
  741. cginame = DSGW_CGINAME_DNEDIT;
  742. break;
  743. case DSGW_CGINUM_TUTOR:
  744. cginame = DSGW_CGINAME_TUTOR;
  745. break;
  746. case DSGW_CGINUM_LANG:
  747. cginame = DSGW_CGINAME_LANG;
  748. break;
  749. default:
  750. return "";
  751. }
  752. if (( surl = getenv( "SERVER_URL" )) == NULL ) {
  753. surl = "";
  754. }
  755. /*if ( gc->gc_admserv ) {
  756. *
  757. * include "/admin-serv/" or "/user-environment/" if appropriate
  758. *
  759. * if ( gc->gc_enduser ) {
  760. * extpath = DSGW_USER_ADM_BINDIR;
  761. * } else {
  762. * extpath = DSGW_ADMSERV_BINDIR;
  763. * }
  764. * } else {
  765. * extpath = "";
  766. * }
  767. */
  768. vpmap[ cginum ] = dsgw_ch_malloc( strlen( gc->gc_urlpfxcgi ) + strlen( surl )
  769. /*+ strlen( extpath ) */
  770. + strlen( cginame ) + 2 );
  771. sprintf( vpmap[ cginum ], "%s%s%s", surl,
  772. /*extpath, */
  773. gc->gc_urlpfxcgi, cginame );
  774. /*sprintf( vpmap[ cginum ], "%s%s%s", extpath, gc->gc_urlpfxcgi, cginame );*/
  775. }
  776. return( vpmap[ cginum ]);
  777. }
  778. #ifdef DSGW_DEBUG
  779. #include <stdio.h> /* FILE */
  780. /* Returns a directory path used for tmp log files. */
  781. char *
  782. dsgw_get_tmp_log_dir()
  783. {
  784. static char tmp_log[MAXPATHLEN];
  785. char *install_dir = NULL;
  786. #if defined( XP_WIN32 )
  787. int ilen;
  788. char *pch;
  789. char tmp_dir[_MAX_PATH];
  790. #endif
  791. install_dir = getenv("NETSITE_ROOT");
  792. if (install_dir != NULL) {
  793. sprintf(tmp_log, "%s/tmp/dsgw", install_dir);
  794. #if defined( XP_WIN32 )
  795. for(ilen=0; ilen < strlen(tmp_log); ilen++)
  796. {
  797. if(tmp_log[ilen]=='/')
  798. tmp_log[ilen]='\\';
  799. }
  800. #endif /* XP_WIN32 */
  801. } else {
  802. #if defined( XP_WIN32 )
  803. ilen = strlen(tmp_dir);
  804. GetTempPath( ilen+1, tmp_dir );
  805. /* Remove trailing slash. */
  806. pch = tmp_dir[ilen-1];
  807. if( pch == '\\' || pch == '/' )
  808. tmp_dir[ilen-1] = '\0';
  809. sprintf(tmp_log, "%s\\DSGW", tmp_dir);
  810. #else
  811. sprintf(tmp_log, "/tmp/dsgw");
  812. #endif
  813. }
  814. return tmp_log;
  815. }
  816. static FILE* log_out_fp = NULL;
  817. void
  818. dsgw_log_out (const char* s, size_t n)
  819. {
  820. if ( log_out_fp == NULL ) {
  821. char fname[ 256 ];
  822. char* format =
  823. #if defined( XP_WIN32 )
  824. "%s\\log%.50s.out";
  825. #else
  826. "%s/%.50s.out";
  827. #endif
  828. PR_snprintf( fname, 256, format, dsgw_get_tmp_log_dir(), progname );
  829. log_out_fp = fopen( fname, "w" );
  830. }
  831. if (log_out_fp != NULL) {
  832. fwrite (s, sizeof(char), n, log_out_fp);
  833. fflush (log_out_fp);
  834. }
  835. }
  836. /*
  837. * logging function -- called like printf(); syslog-like output is written
  838. * to a file called /tmp/progname where progname is derived from argv[0]
  839. */
  840. static FILE* logfp = NULL;
  841. void
  842. dsgw_log( char *fmt, ... )
  843. {
  844. time_t t;
  845. char timebuf[ 20 ];
  846. va_list ap;
  847. t = time( NULL );
  848. if ( logfp == NULL ) {
  849. char fname[ 256 ];
  850. char* format =
  851. #if defined( XP_WIN32 )
  852. "%s\\log%.50s";
  853. #else
  854. "%s/%.50s";
  855. #endif
  856. PR_snprintf( fname, 256, format, dsgw_get_tmp_log_dir(), progname );
  857. if (( logfp = fopen( fname, "a+" )) == NULL ) {
  858. return;
  859. }
  860. }
  861. memcpy( timebuf, ctime( &t ), 19 );
  862. timebuf[ 19 ] = '\0';
  863. fprintf( logfp, "%s %s: ", timebuf, progname );
  864. va_start( ap, fmt );
  865. (void)vfprintf( logfp, fmt, ap );
  866. va_end( ap );
  867. fflush( logfp );
  868. }
  869. /*
  870. * log the contents of a NULL-terminated array of character strings
  871. */
  872. void
  873. dsgw_logstringarray( char *arrayname, char **strs )
  874. {
  875. int i;
  876. if ( strs == NULL || strs[ 0 ] == NULL ) {
  877. dsgw_log( "Array %s: empty\n", arrayname );
  878. } else {
  879. dsgw_log( "Array %s:\n", arrayname );
  880. for ( i = 0; strs[ i ] != NULL; ++i ) {
  881. dsgw_log( "\t%2d: \"%s\"\n", i, strs[ i ] );
  882. }
  883. }
  884. }
  885. #endif /* DSGW_DEBUG */
  886. void
  887. dsgw_head_begin()
  888. {
  889. dsgw_emits ("<HEAD>");
  890. if ( gc != NULL && gc->gc_charset != NULL && *gc->gc_charset != '\0' ) {
  891. dsgw_emitf ("<META HTTP-EQUIV=\"%s\" CONTENT=\"%s%s%s\">",
  892. CONTENT_TYPE, TYPE_HTML, cs_prefix, gc->gc_charset);
  893. }
  894. }
  895. void
  896. dsgw_quote_emptyFrame()
  897. {
  898. dsgw_quotation_begin( QUOTATION_JAVASCRIPT_MULTILINE );
  899. dsgw_emits( "<HTML>" );
  900. dsgw_emitf( "<BODY %s></BODY></HTML>", dsgw_html_body_colors );
  901. dsgw_quotation_end();
  902. }
  903. /* This function contains code to alert the user that their password has
  904. already expired. It gives them an opportunity to change it. */
  905. void
  906. dsgw_password_expired_alert( char *dn )
  907. {
  908. #ifdef NOTFORNOW
  909. char *ufn;
  910. #endif
  911. char *encodeddn = dsgw_strdup_escaped( dn );
  912. dsgw_send_header();
  913. dsgw_emits( "<HTML>" );
  914. dsgw_head_begin();
  915. dsgw_emits( "\n"
  916. "<TITLE>Password Expired</TITLE>\n"
  917. "<SCRIPT LANGUAGE=\"JavaScript\">\n"
  918. "<!-- Hide from non-JavaScript browsers\n" );
  919. if ( encodeddn != NULL && strlen( encodeddn ) > 0 ) {
  920. dsgw_emitf( "var editdesturl = '%s?passwd&dn=%s&context=%s';\n",
  921. dsgw_getvp( DSGW_CGINUM_EDIT ), encodeddn, context );
  922. } else {
  923. dsgw_emitf( "var editdesturl=null;\n" );
  924. }
  925. dsgw_emits( "function EditPassword()\n"
  926. "{\n"
  927. " if ( editdesturl != null ) {\n"
  928. " top.location.href = editdesturl;\n"
  929. " } else {\n"
  930. " top.close();\n"
  931. " }\n"
  932. "}\n"
  933. "var contButtons = ");
  934. dsgw_quotation_begin (QUOTATION_JAVASCRIPT_MULTILINE);
  935. dsgw_form_begin ("bForm", NULL);
  936. dsgw_emits(
  937. "\n<TABLE BORDER=2 WIDTH=100%>\n"
  938. "<TD ALIGN=CENTER WIDTH=50%>\n"
  939. "<INPUT TYPE=BUTTON NAME=\"contButton\""
  940. "VALUE=\"");
  941. dsgw_emits( XP_GetClientStr( DBT_EditPassword_ ));
  942. dsgw_emits(
  943. "\" onClick=\"EditPassword();\">\n"
  944. "<TD ALIGN=CENTER WIDTH=50%%>" );
  945. dsgw_emit_helpbutton( "AUTHSUCCESS" );
  946. dsgw_emits(
  947. "\n</TABLE></FORM>");
  948. dsgw_quotation_end(); dsgw_emits(";\n");
  949. dsgw_emits(
  950. "var noContButtons = ");
  951. dsgw_quotation_begin (QUOTATION_JAVASCRIPT_MULTILINE);
  952. dsgw_emits( XP_GetClientStr( DBT_ToContinue_ ));
  953. dsgw_form_begin( "bForm", NULL );
  954. dsgw_emits(
  955. "\n<TABLE BORDER=2 WIDTH=100%>"
  956. "\n<TD ALIGN=CENTER WIDTH=50%>" );
  957. dsgw_emit_homebutton();
  958. dsgw_emits( "\n<TD ALIGN=CENTER WIDTH=50%%>" );
  959. dsgw_emit_helpbutton( "AUTHPROBLEM" );
  960. dsgw_emits(
  961. "\n</TABLE></FORM>\n");
  962. dsgw_quotation_end(); dsgw_emits(";\n");
  963. #ifdef NOTFORNOW
  964. /* ldap_dn2ufn currently gobbles up 'dc' so don't use it for */
  965. /* now */
  966. ufn = ldap_dn2ufn( dn );
  967. #endif
  968. dsgw_emitf(
  969. "// End hiding -->\n"
  970. "</SCRIPT>\n"
  971. "</HEAD>\n<BODY %s>\n"
  972. "<CENTER>\n",
  973. dsgw_html_body_colors );
  974. dsgw_emitf( XP_GetClientStr( DBT_PasswordExpiredFor_ ), dn );
  975. dsgw_emits( "</CENTER>\n" );
  976. dsgw_emits( XP_GetClientStr( DBT_YourPasswordHasExpired_ ));
  977. dsgw_emits( XP_GetClientStr( DBT_YouMustChangeYourPasswd_ ));
  978. dsgw_emits( "<P>\n"
  979. "<TR>\n"
  980. "<SCRIPT LANGUAGE=\"JavaScript\">\n"
  981. "<!-- Hide from non-JavaScript browsers\n"
  982. "if ( editdesturl != null ) {\n"
  983. " document.write( contButtons );\n"
  984. "} else {\n"
  985. " document.write( noContButtons );\n"
  986. "}\n"
  987. "// End hiding -->\n"
  988. "</SCRIPT>\n"
  989. "</BODY>\n</HTML>\n" );
  990. }
  991. /* Pulled from ldapserver/ldap/servers/slapd/time.c */
  992. time_t
  993. dsgw_current_time()
  994. {
  995. return( time( (time_t *)0 ));
  996. }
  997. #define mktime_r(from) mktime (from)
  998. time_t
  999. dsgw_time_plus_sec (time_t l, long r)
  1000. /* return the point in time 'r' seconds after 'l'. */
  1001. {
  1002. /* On many (but not all) platforms this is simply l + r;
  1003. perhaps it would be better to implement it that way. */
  1004. struct tm t;
  1005. if (r == 0) return l; /* performance optimization */
  1006. #ifdef _WIN32
  1007. {
  1008. struct tm *pt = localtime( &l );
  1009. memcpy(&t, pt, sizeof(struct tm) );
  1010. }
  1011. #else
  1012. localtime_r (&l, &t);
  1013. #endif
  1014. /* Conceptually, we want to do: t.tm_sec += r;
  1015. but to avoid overflowing fields: */
  1016. r += t.tm_sec; t.tm_sec = r % 60; r /= 60;
  1017. r += t.tm_min; t.tm_min = r % 60; r /= 60;
  1018. r += t.tm_hour; t.tm_hour = r % 24; r /= 24;
  1019. t.tm_mday += r; /* may be > 31; mktime_r() must handle this */
  1020. /* These constants are chosen to work when the maximum
  1021. field values are 127 (the worst case) or more.
  1022. Perhaps this is excessively conservative. */
  1023. return mktime_r (&t);
  1024. }
  1025. /*
  1026. * Function: figure_out_langwich
  1027. *
  1028. * Returns: nothing
  1029. *
  1030. * Description: figures out the language/locale that libsi18n will
  1031. * use. This is so that non libsi18n functions can display
  1032. * stuff in the same language.
  1033. *
  1034. * Author: RJP
  1035. *
  1036. */
  1037. static void
  1038. figure_out_langwich(void)
  1039. {
  1040. char *path = NULL;
  1041. char *iter = NULL;
  1042. char *p = NULL;
  1043. char *before = NULL;
  1044. /* Get a path to the html directory */
  1045. path = dsgw_file2path( gc->gc_configdir, "dsgwfilter.conf");
  1046. before = path;
  1047. /* Find the lang subdirectory part */
  1048. for ( p = ldap_utf8strtok_r( path, DSGW_PATHSEP_STR, &iter );
  1049. p != NULL && *p != '\0' && strcmp(p, "dsgwfilter.conf") != 0;
  1050. p = ldap_utf8strtok_r( NULL, DSGW_PATHSEP_STR, &iter )){
  1051. before = p;
  1052. }
  1053. /* If there is one, copy it. */
  1054. if (before != NULL && *before != '\0') {
  1055. langwich = dsgw_ch_strdup(before);
  1056. }
  1057. iter = NULL;
  1058. /* split off any country specification */
  1059. ldap_utf8strtok_r( langwich, "-", &iter );
  1060. countri = iter;
  1061. free (path);
  1062. }
  1063. /*
  1064. * Accept-Language = "Accept-Language" ":"
  1065. * 1#( language-range [ ";" "q" "=" qvalue ] )
  1066. * language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
  1067. *
  1068. * NLS_AccLangList() assumes that "Accept-Language:" has already
  1069. * been stripped off. It takes as input
  1070. *
  1071. * 1#( ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" ) [ ";" "q" "=" qvalue ] )
  1072. *
  1073. * and returns a list of languages, ordered by qvalues, in
  1074. * the array NLS_ACCEPT_LANGUAGE_LIST.
  1075. *
  1076. * If there are to many languages (>NLS_MAX_ACCEPT_LANGUAGE) the excess
  1077. * is ignored. If the language-range is too long (>NLS_MAX_ACCEPT_LENGTH),
  1078. * the language-range is ignored. In these cases, NLS_AccLangList()
  1079. * will quietly return, perhaps with numLang = 0. numLang is
  1080. * returned by the function.
  1081. */
  1082. size_t
  1083. AcceptLangList(const char* AcceptLanguage,
  1084. ACCEPT_LANGUAGE_LIST AcceptLanguageList)
  1085. {
  1086. char* input;
  1087. char* cPtr;
  1088. char* cPtr1;
  1089. char* cPtr2;
  1090. int i;
  1091. int j;
  1092. int countLang = 0;
  1093. input = dsgw_ch_strdup(AcceptLanguage);
  1094. if (input == (char*)NULL){
  1095. return 0;
  1096. }
  1097. cPtr1 = input-1;
  1098. cPtr2 = input;
  1099. /* put in standard form */
  1100. while (*(++cPtr1)) {
  1101. if (isalpha(*cPtr1)) *cPtr2++ = tolower(*cPtr1); /* force lower case */
  1102. else if (isspace(*cPtr1)); /* ignore any space */
  1103. else if (*cPtr1=='-') *cPtr2++ = '_'; /* "-" -> "_" */
  1104. else if (*cPtr1=='*'); /* ignore "*" */
  1105. else *cPtr2++ = *cPtr1; /* else unchanged */
  1106. }
  1107. *cPtr2 = '\0';
  1108. countLang = 0;
  1109. if (strchr(input,';')) {
  1110. /* deal with the quality values */
  1111. float qvalue[MAX_ACCEPT_LANGUAGE];
  1112. float qSwap;
  1113. float bias = 0.0f;
  1114. char* ptrLanguage[MAX_ACCEPT_LANGUAGE];
  1115. char* ptrSwap;
  1116. cPtr = strtok(input,",");
  1117. while (cPtr) {
  1118. qvalue[countLang] = 1.0f;
  1119. if ((cPtr1 = strchr(cPtr,';'))) {
  1120. sscanf(cPtr1,";q=%f",&qvalue[countLang]);
  1121. *cPtr1 = '\0';
  1122. }
  1123. if (strlen(cPtr)<MAX_ACCEPT_LENGTH) { /* ignore if too long */
  1124. qvalue[countLang] -= (bias += 0.0001f); /* to insure original order */
  1125. ptrLanguage[countLang++] = cPtr;
  1126. if (countLang>=MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
  1127. }
  1128. cPtr = strtok(NULL,",");
  1129. }
  1130. /* sort according to decending qvalue */
  1131. /* not a very good algorithm, but count is not likely large */
  1132. for ( i=0 ; i<countLang-1 ; i++ ) {
  1133. for ( j=i+1 ; j<countLang ; j++ ) {
  1134. if (qvalue[i]<qvalue[j]) {
  1135. qSwap = qvalue[i];
  1136. qvalue[i] = qvalue[j];
  1137. qvalue[j] = qSwap;
  1138. ptrSwap = ptrLanguage[i];
  1139. ptrLanguage[i] = ptrLanguage[j];
  1140. ptrLanguage[j] = ptrSwap;
  1141. }
  1142. }
  1143. }
  1144. for ( i=0 ; i<countLang ; i++ ) {
  1145. strcpy(AcceptLanguageList[i],ptrLanguage[i]);
  1146. }
  1147. } else {
  1148. /* simple case: no quality values */
  1149. cPtr = strtok(input,",");
  1150. while (cPtr) {
  1151. if (strlen(cPtr)<MAX_ACCEPT_LENGTH) { /* ignore if too long */
  1152. strcpy(AcceptLanguageList[countLang++],cPtr);
  1153. if (countLang>=MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
  1154. }
  1155. cPtr = strtok(NULL,",");
  1156. }
  1157. }
  1158. free(input);
  1159. return countLang;
  1160. }