cachemgr.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:20k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: cachemgr.c,v 1.84.2.2 1999/02/12 19:38:23 wessels Exp $
  3.  *
  4.  * DEBUG: section 0     CGI Cache Manager
  5.  * AUTHOR: Duane Wessels
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #include "config.h"
  35. #if HAVE_UNISTD_H
  36. #include <unistd.h>
  37. #endif
  38. #if HAVE_STDLIB_H
  39. #include <stdlib.h>
  40. #endif
  41. #if HAVE_STDIO_H
  42. #include <stdio.h>
  43. #endif
  44. #if HAVE_SYS_TYPES_H
  45. #include <sys/types.h>
  46. #endif
  47. #if HAVE_CTYPE_H
  48. #include <ctype.h>
  49. #endif
  50. #if HAVE_ERRNO_H
  51. #include <errno.h>
  52. #endif
  53. #if HAVE_FCNTL_H
  54. #include <fcntl.h>
  55. #endif
  56. #if HAVE_GRP_H
  57. #include <grp.h>
  58. #endif
  59. #if HAVE_GNUMALLOC_H
  60. #include <gnumalloc.h>
  61. #elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
  62. #include <malloc.h>
  63. #endif
  64. #if HAVE_MEMORY_H
  65. #include <memory.h>
  66. #endif
  67. #if HAVE_NETDB_H && !defined(_SQUID_NETDB_H_) /* protect NEXTSTEP */
  68. #define _SQUID_NETDB_H_
  69. #include <netdb.h>
  70. #endif
  71. #if HAVE_PWD_H
  72. #include <pwd.h>
  73. #endif
  74. #if HAVE_SIGNAL_H
  75. #include <signal.h>
  76. #endif
  77. #if HAVE_TIME_H
  78. #include <time.h>
  79. #endif
  80. #if HAVE_SYS_PARAM_H
  81. #include <sys/param.h>
  82. #endif
  83. #if HAVE_SYS_TIME_H
  84. #include <sys/time.h>
  85. #endif
  86. #if HAVE_SYS_RESOURCE_H
  87. #include <sys/resource.h> /* needs sys/time.h above it */
  88. #endif
  89. #if HAVE_SYS_SOCKET_H
  90. #include <sys/socket.h>
  91. #endif
  92. #if HAVE_NETINET_IN_H
  93. #include <netinet/in.h>
  94. #endif
  95. #if HAVE_ARPA_INET_H
  96. #include <arpa/inet.h>
  97. #endif
  98. #if HAVE_SYS_STAT_H
  99. #include <sys/stat.h>
  100. #endif
  101. #if HAVE_SYS_UN_H
  102. #include <sys/un.h>
  103. #endif
  104. #if HAVE_SYS_WAIT_H
  105. #include <sys/wait.h>
  106. #endif
  107. #if HAVE_LIBC_H
  108. #include <libc.h>
  109. #endif
  110. #if HAVE_STRING_H
  111. #include <string.h>
  112. #endif
  113. #if HAVE_STRINGS_H
  114. #include <strings.h>
  115. #endif
  116. #if HAVE_BSTRING_H
  117. #include <bstring.h>
  118. #endif
  119. #if HAVE_CRYPT_H
  120. #include <crypt.h>
  121. #endif
  122. #if HAVE_SYS_SELECT_H
  123. #include <sys/select.h>
  124. #endif
  125. #include "util.h"
  126. #include "snprintf.h"
  127. typedef struct {
  128.     char *hostname;
  129.     int port;
  130.     char *action;
  131.     char *user_name;
  132.     char *passwd;
  133.     char *pub_auth;
  134. } cachemgr_request;
  135. /*
  136.  * Debugging macros (info goes to error_log on your web server)
  137.  * Note: do not run cache manager with non zero debugging level 
  138.  *       if you do not debug, it may write a lot of [sensitive]
  139.  *       information to your error log.
  140.  */
  141. /* debugging level 0 (disabled) - 3 (max) */
  142. #define DEBUG_LEVEL 0
  143. #define debug(level) if ((level) <= DEBUG_LEVEL && DEBUG_LEVEL > 0)
  144. /*
  145.  * Static variables and constants
  146.  */
  147. static const time_t passwd_ttl = 60 * 60 * 3; /* in sec */
  148. static const char *script_name = "/cgi-bin/cachemgr.cgi";
  149. static const char *progname = NULL;
  150. static time_t now;
  151. static struct in_addr no_addr;
  152. /*
  153.  * Function prototypes
  154.  */
  155. #define safe_free(str) { if (str) { xfree(str); (str) = NULL; } }
  156. static const char *safe_str(const char *str);
  157. static char *xstrtok(char **str, char del);
  158. static void print_trailer(void);
  159. static void auth_html(char *host, int port, const char *user_name);
  160. static void error_html(const char *msg);
  161. static char *menu_url(cachemgr_request * req, const char *action);
  162. static int parse_status_line(const char *sline, const char **statusStr);
  163. static cachemgr_request *read_request(void);
  164. static char *read_get_request(void);
  165. static char *read_post_request(void);
  166. static void make_pub_auth(cachemgr_request * req);
  167. static void decode_pub_auth(cachemgr_request * req);
  168. static void reset_auth(cachemgr_request * req);
  169. static const char *make_auth_header(const cachemgr_request * req);
  170. static const char *
  171. safe_str(const char *str)
  172. {
  173.     return str ? str : "";
  174. }
  175. /* relaxed number format */
  176. static int
  177. is_number(const char *str)
  178. {
  179.     return strspn(str, "t -+01234567890./n") == strlen(str);
  180. }
  181. static char *
  182. xstrtok(char **str, char del)
  183. {
  184.     if (*str) {
  185. char *p = strchr(*str, del);
  186. char *tok = *str;
  187. int len;
  188. if (p) {
  189.     *str = p + 1;
  190.     *p = '';
  191. } else
  192.     *str = NULL;
  193. /* trim */
  194. len = strlen(tok);
  195. while (len && xisspace(tok[len - 1]))
  196.     tok[--len] = '';
  197. while (xisspace(*tok))
  198.     tok++;
  199. return tok;
  200.     } else
  201. return "";
  202. }
  203. static void
  204. print_trailer(void)
  205. {
  206.     printf("<HR>n");
  207.     printf("<ADDRESS>n");
  208.     printf("Generated %s, by %s/%s@%sn",
  209. mkrfc1123(now), progname, SQUID_VERSION, getfullhostname());
  210.     printf("</ADDRESS></BODY></HTML>n");
  211. }
  212. static void
  213. auth_html(char *host, int port, const char *user_name)
  214. {
  215.     if (!user_name)
  216. user_name = "";
  217.     if (!host || !strlen(host))
  218. host = "localhost";
  219.     printf("Content-type: text/htmlrnrn");
  220.     printf("<HTML><HEAD><TITLE>Cache Manager Interface</TITLE></HEAD>n");
  221.     printf("<BODY><H1>Cache Manager Interface</H1>n");
  222.     printf("<P>This is a WWW interface to the instrumentation interfacen");
  223.     printf("for the Squid object cache.</P>n");
  224.     printf("<HR>n");
  225.     printf("<FORM METHOD="GET" ACTION="%s">n", script_name);
  226.     printf("<TABLE BORDER=0>n");
  227.     printf("<TR><TH ALIGN="left">Cache Host:</TH><TD><INPUT NAME="host" ");
  228.     printf("SIZE=30 VALUE="%s"></TD></TR>n", host);
  229.     printf("<TR><TH ALIGN="left">Cache Port:</TH><TD><INPUT NAME="port" ");
  230.     printf("SIZE=30 VALUE="%d"></TD></TR>n", port);
  231.     printf("<TR><TH ALIGN="left">Manager name:</TH><TD><INPUT NAME="user_name" ");
  232.     printf("SIZE=30 VALUE="%s"></TD></TR>n", user_name);
  233.     printf("<TR><TH ALIGN="left">Password:</TH><TD><INPUT TYPE="password" NAME="passwd" ");
  234.     printf("SIZE=30 VALUE=""></TD></TR>n");
  235.     printf("</TABLE><BR CLEAR="all">n");
  236.     printf("<INPUT TYPE="submit" VALUE="Continue...">n");
  237.     printf("</FORM>n");
  238.     print_trailer();
  239. }
  240. static void
  241. error_html(const char *msg)
  242. {
  243.     printf("Content-type: text/htmlrnrn");
  244.     printf("<HTML><HEAD><TITLE>Cache Manager Error</TITLE></HEAD>n");
  245.     printf("<BODY><H1>Cache Manager Error</H1>n");
  246.     printf("<P>n%s</P>n", msg);
  247.     print_trailer();
  248. }
  249. /* returns http status extracted from status line or -1 on parsing failure */
  250. static int
  251. parse_status_line(const char *sline, const char **statusStr)
  252. {
  253.     const char *sp = strchr(sline, ' ');
  254.     if (statusStr)
  255. *statusStr = NULL;
  256.     if (strncasecmp(sline, "HTTP/", 5) || !sp)
  257. return -1;
  258.     while (xisspace(*++sp));
  259.     if (!xisdigit(*sp))
  260. return -1;
  261.     if (statusStr)
  262. *statusStr = sp;
  263.     return atoi(sp);
  264. }
  265. static char *
  266. menu_url(cachemgr_request * req, const char *action)
  267. {
  268.     static char url[1024];
  269.     snprintf(url, sizeof(url), "%s?host=%s&port=%d&user_name=%s&operation=%s&auth=%s",
  270. script_name,
  271. req->hostname,
  272. req->port,
  273. safe_str(req->user_name),
  274. action,
  275. safe_str(req->pub_auth));
  276.     return url;
  277. }
  278. static const char *
  279. munge_menu_line(const char *buf, cachemgr_request * req)
  280. {
  281.     char *x;
  282.     const char *a;
  283.     const char *d;
  284.     const char *p;
  285.     char *a_url;
  286.     char *buf_copy;
  287.     static char html[2 * 1024];
  288.     if (strlen(buf) < 1)
  289. return buf;
  290.     if (*buf != ' ')
  291. return buf;
  292.     buf_copy = x = xstrdup(buf);
  293.     a = xstrtok(&x, 't');
  294.     d = xstrtok(&x, 't');
  295.     p = xstrtok(&x, 't');
  296.     a_url = xstrdup(menu_url(req, a));
  297.     /* no reason to give a url for a disabled action */
  298.     if (!strcmp(p, "disabled"))
  299. snprintf(html, sizeof(html), "<LI type="circle">%s (disabled)<A HREF="%s">.</A>n", d, a_url);
  300.     else
  301. /* disable a hidden action (requires a password, but password is not in squid.conf) */
  302.     if (!strcmp(p, "hidden"))
  303. snprintf(html, sizeof(html), "<LI type="circle">%s (hidden)<A HREF="%s">.</A>n", d, a_url);
  304.     else
  305. /* disable link if authentication is required and we have no password */
  306.     if (!strcmp(p, "protected") && !req->passwd)
  307. snprintf(html, sizeof(html), "<LI type="circle">%s (requires <a href="%s">authentication</a>)<A HREF="%s">.</A>n",
  308.     d, menu_url(req, "authenticate"), a_url);
  309.     else
  310. /* highlight protected but probably available entries */
  311.     if (!strcmp(p, "protected"))
  312. snprintf(html, sizeof(html), "<LI type="square"><A HREF="%s"><font color="#FF0000">%s</font></A>n",
  313.     a_url, d);
  314.     /* public entry or unknown type of protection */
  315.     else
  316. snprintf(html, sizeof(html), "<LI type="disk"><A HREF="%s">%s</A>n", a_url, d);
  317.     xfree(a_url);
  318.     xfree(buf_copy);
  319.     return html;
  320. }
  321. static const char *
  322. munge_other_line(const char *buf, cachemgr_request * req)
  323. {
  324.     static const char *ttags[] =
  325.     {"td", "th"};
  326.     static char html[4096];
  327.     static int table_line_num = 0;
  328.     static int next_is_header = 0;
  329.     int is_header = 0;
  330.     const char *ttag;
  331.     char *buf_copy;
  332.     char *x, *p;
  333.     int l = 0;
  334.     /* does it look like a table? */
  335.     if (!strchr(buf, 't') || *buf == 't') {
  336. /* nope, just text */
  337. snprintf(html, sizeof(html), "%s%s",
  338.     table_line_num ? "</table>n<pre>" : "", buf);
  339. table_line_num = 0;
  340. return html;
  341.     }
  342.     /* start html table */
  343.     if (!table_line_num) {
  344. l += snprintf(html + l, sizeof(html) - l, "</pre><table border=1 cellpadding=2 cellspacing=1>n");
  345. next_is_header = 0;
  346.     }
  347.     /* remove 'n' */
  348.     is_header = (!table_line_num || next_is_header) && !strchr(buf, ':') && !is_number(buf);
  349.     ttag = ttags[is_header];
  350.     /* record starts */
  351.     l += snprintf(html + l, sizeof(html) - l, "<tr>");
  352.     /* substitute 't' */
  353.     buf_copy = x = xstrdup(buf);
  354.     if ((p = strchr(x, 'n')))
  355. *p = '';
  356.     while (x && strlen(x)) {
  357. int column_span = 1;
  358. const char *cell = xstrtok(&x, 't');
  359. while (x && *x == 't') {
  360.     column_span++;
  361.     x++;
  362. }
  363. l += snprintf(html + l, sizeof(html) - l, "<%s colspan=%d align="%s">%s</%s>",
  364.     ttag, column_span,
  365.     is_header ? "center" : is_number(cell) ? "right" : "left",
  366.     cell, ttag);
  367.     }
  368.     xfree(buf_copy);
  369.     /* record ends */
  370.     l += snprintf(html + l, sizeof(html) - l, "</tr>n");
  371.     next_is_header = is_header && strstr(buf, "tt");
  372.     table_line_num++;
  373.     return html;
  374. }
  375. static int
  376. read_reply(int s, cachemgr_request * req)
  377. {
  378.     char buf[4 * 1024];
  379.     FILE *fp = fdopen(s, "r");
  380.     /* interpretation states */
  381.     enum {
  382. isStatusLine, isHeaders, isBodyStart, isBody, isForward, isEof, isForwardEof, isSuccess, isError
  383.     } istate = isStatusLine;
  384.     int parse_menu = 0;
  385.     const char *action = req->action;
  386.     const char *statusStr = NULL;
  387.     int status = -1;
  388.     if (0 == strlen(req->action))
  389. parse_menu = 1;
  390.     else if (0 == strcasecmp(req->action, "menu"))
  391. parse_menu = 1;
  392.     if (fp == NULL) {
  393. perror("fdopen");
  394. return 1;
  395.     }
  396.     if (parse_menu)
  397. action = "menu";
  398.     /* read reply interpreting one line at a time depending on state */
  399.     while (istate < isEof) {
  400. if (!fgets(buf, sizeof(buf), fp))
  401.     istate = istate == isForward ? isForwardEof : isEof;
  402. switch (istate) {
  403. case isStatusLine:
  404.     /* get HTTP status */
  405.     /* uncomment the following if you want to debug headers */
  406.     /* fputs("rnrn", stdout); */
  407.     status = parse_status_line(buf, &statusStr);
  408.     istate = status == 200 ? isHeaders : isForward;
  409.     /* if cache asks for authentication, we have to reset our info */
  410.     if (status == 401 || status == 407) {
  411. reset_auth(req);
  412. status = 403; /* Forbiden, see comments in case isForward: */
  413.     }
  414.     /* this is a way to pass HTTP status to the Web server */
  415.     if (statusStr)
  416. printf("Status: %d %s", status, statusStr); /* statusStr has 'n' */
  417.     break;
  418. case isHeaders:
  419.     /* forward header field */
  420.     if (!strcmp(buf, "rn")) { /* end of headers */
  421. fputs("Content-Type: text/htmlrn", stdout); /* add our type */
  422. istate = isBodyStart;
  423.     }
  424.     if (strncasecmp(buf, "Content-Type:", 13)) /* filter out their type */
  425. fputs(buf, stdout);
  426.     break;
  427. case isBodyStart:
  428.     printf("<HTML><HEAD><TITLE>CacheMgr@%s: %s</TITLE></HEAD><BODY>n",
  429. req->hostname, action);
  430.     if (parse_menu) {
  431. printf("<H2><a href="%s">Cache Manager</a> menu for %s:</H2>",
  432.     menu_url(req, "authenticate"), req->hostname);
  433. printf("<UL>n");
  434.     } else {
  435. printf("<P><A HREF="%s">%s</A>n<HR>n",
  436.     menu_url(req, "menu"), "Cache Manager menu");
  437. printf("<PRE>n");
  438.     }
  439.     istate = isBody;
  440.     /* yes, fall through, we do not want to loose the first line */
  441. case isBody:
  442.     /* interpret [and reformat] cache response */
  443.     if (parse_menu)
  444. fputs(munge_menu_line(buf, req), stdout);
  445.     else
  446. fputs(munge_other_line(buf, req), stdout);
  447.     break;
  448. case isForward:
  449.     /* forward: no modifications allowed */
  450.     /*
  451.      * Note: we currently do not know any way to get browser.reply to
  452.      * 401 to .cgi because web server filters out all auth info. Thus we
  453.      * disable authentication headers for now.
  454.      */
  455.     if (!strncasecmp(buf, "WWW-Authenticate:", 17) || !strncasecmp(buf, "Proxy-Authenticate:", 19)); /* skip */
  456.     else
  457. fputs(buf, stdout);
  458.     break;
  459. case isEof:
  460.     /* print trailers */
  461.     if (parse_menu)
  462. printf("</UL>n");
  463.     else
  464. printf("</table></PRE>n");
  465.     print_trailer();
  466.     istate = isSuccess;
  467.     break;
  468. case isForwardEof:
  469.     /* indicate that we finished processing an "error" sequence */
  470.     istate = isError;
  471.     break;
  472. default:
  473.     printf("%s: internal bug: invalid state reached: %d", script_name, istate);
  474.     istate = isError;
  475. }
  476.     }
  477.     close(s);
  478.     return 0;
  479. }
  480. static int
  481. process_request(cachemgr_request * req)
  482. {
  483.     const struct hostent *hp;
  484.     static struct sockaddr_in S;
  485.     int s;
  486.     int l;
  487.     static char buf[2 * 1024];
  488.     if (req == NULL) {
  489. auth_html(CACHEMGR_HOSTNAME, CACHE_HTTP_PORT, "");
  490. return 1;
  491.     }
  492.     if (req->hostname == NULL) {
  493. req->hostname = xstrdup(CACHEMGR_HOSTNAME);
  494.     }
  495.     if (req->port == 0) {
  496. req->port = CACHE_HTTP_PORT;
  497.     }
  498.     if (req->action == NULL) {
  499. req->action = xstrdup("");
  500.     }
  501.     if (!strcmp(req->action, "authenticate")) {
  502. auth_html(req->hostname, req->port, req->user_name);
  503. return 0;
  504.     }
  505.     if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
  506. snprintf(buf, 1024, "socket: %sn", xstrerror());
  507. error_html(buf);
  508. return 1;
  509.     }
  510.     memset(&S, '', sizeof(struct sockaddr_in));
  511.     S.sin_family = AF_INET;
  512.     if ((hp = gethostbyname(req->hostname)) != NULL)
  513. xmemcpy(&S.sin_addr.s_addr, hp->h_addr, hp->h_length);
  514.     else if (safe_inet_addr(req->hostname, &S.sin_addr))
  515. (void) 0;
  516.     else {
  517. snprintf(buf, 1024, "Unknown host: %sn", req->hostname);
  518. error_html(buf);
  519. return 1;
  520.     }
  521.     S.sin_port = htons(req->port);
  522.     if (connect(s, (struct sockaddr *) &S, sizeof(struct sockaddr_in)) < 0) {
  523. snprintf(buf, 1024, "connect: %sn", xstrerror());
  524. error_html(buf);
  525. return 1;
  526.     }
  527.     l = snprintf(buf, sizeof(buf),
  528. "GET cache_object://%s/%s HTTP/1.0rn"
  529. "Accept: */*rn"
  530. "%s" /* Authentication info or nothing */
  531. "rn",
  532. req->hostname,
  533. req->action,
  534. make_auth_header(req));
  535.     write(s, buf, l);
  536.     debug(1) fprintf(stderr, "wrote request: '%s'n", buf);
  537.     return read_reply(s, req);
  538. }
  539. int
  540. main(int argc, char *argv[])
  541. {
  542.     char *s;
  543.     cachemgr_request *req;
  544.     safe_inet_addr("255.255.255.255", &no_addr);
  545.     now = time(NULL);
  546.     if ((s = strrchr(argv[0], '/')))
  547. progname = xstrdup(s + 1);
  548.     else
  549. progname = xstrdup(argv[0]);
  550.     if ((s = getenv("SCRIPT_NAME")) != NULL)
  551. script_name = xstrdup(s);
  552.     req = read_request();
  553.     return process_request(req);
  554. }
  555. static char *
  556. read_post_request(void)
  557. {
  558.     char *s;
  559.     char *buf;
  560.     int len;
  561.     if ((s = getenv("REQUEST_METHOD")) == NULL)
  562. return NULL;
  563.     if (0 != strcasecmp(s, "POST"))
  564. return NULL;
  565.     if ((s = getenv("CONTENT_LENGTH")) == NULL)
  566. return NULL;
  567.     if ((len = atoi(s)) <= 0)
  568. return NULL;
  569.     buf = xmalloc(len + 1);
  570.     fread(buf, len, 1, stdin);
  571.     buf[len] = '';
  572.     return buf;
  573. }
  574. static char *
  575. read_get_request(void)
  576. {
  577.     char *s;
  578.     if ((s = getenv("QUERY_STRING")) == NULL)
  579. return NULL;
  580.     return xstrdup(s);
  581. }
  582. static cachemgr_request *
  583. read_request(void)
  584. {
  585.     char *buf;
  586.     cachemgr_request *req;
  587.     char *s;
  588.     char *t;
  589.     char *q;
  590.     if ((buf = read_post_request()) != NULL)
  591. (void) 0;
  592.     else if ((buf = read_get_request()) != NULL)
  593. (void) 0;
  594.     else
  595. return NULL;
  596.     if (strlen(buf) == 0)
  597. return NULL;
  598.     req = xcalloc(1, sizeof(cachemgr_request));
  599.     for (s = strtok(buf, "&"); s != NULL; s = strtok(NULL, "&")) {
  600. t = xstrdup(s);
  601. if ((q = strchr(t, '=')) == NULL)
  602.     continue;
  603. *q++ = '';
  604. if (0 == strcasecmp(t, "host") && strlen(q))
  605.     req->hostname = xstrdup(q);
  606. else if (0 == strcasecmp(t, "port") && strlen(q))
  607.     req->port = atoi(q);
  608. else if (0 == strcasecmp(t, "user_name") && strlen(q))
  609.     req->user_name = xstrdup(q);
  610. else if (0 == strcasecmp(t, "passwd") && strlen(q))
  611.     req->passwd = xstrdup(q);
  612. else if (0 == strcasecmp(t, "auth") && strlen(q))
  613.     req->pub_auth = xstrdup(q), decode_pub_auth(req);
  614. else if (0 == strcasecmp(t, "operation"))
  615.     req->action = xstrdup(q);
  616.     }
  617.     make_pub_auth(req);
  618.     debug(1) fprintf(stderr, "cmgr: got req: host: '%s' port: %d uname: '%s' passwd: '%s' auth: '%s' oper: '%s'n",
  619. safe_str(req->hostname), req->port, safe_str(req->user_name), safe_str(req->passwd), safe_str(req->pub_auth), safe_str(req->action));
  620.     return req;
  621. }
  622. /* Routines to support authentication */
  623. /*
  624.  * Encodes auth info into a "public" form. 
  625.  * Currently no powerful encryption is used.
  626.  */
  627. static void
  628. make_pub_auth(cachemgr_request * req)
  629. {
  630.     static char buf[1024];
  631.     safe_free(req->pub_auth);
  632.     debug(3) fprintf(stderr, "cmgr: encoding for pub...n");
  633.     if (!req->passwd || !strlen(req->passwd))
  634. return;
  635.     /* host | time | user | passwd */
  636.     snprintf(buf, sizeof(buf), "%s|%d|%s|%s",
  637. req->hostname,
  638. (int) now,
  639. req->user_name ? req->user_name : "",
  640. req->passwd);
  641.     debug(3) fprintf(stderr, "cmgr: pre-encoded for pub: %sn", buf);
  642.     debug(3) fprintf(stderr, "cmgr: encoded: '%s'n", base64_encode(buf));
  643.     req->pub_auth = xstrdup(base64_encode(buf));
  644. }
  645. static void
  646. decode_pub_auth(cachemgr_request * req)
  647. {
  648.     char *buf;
  649.     const char *host_name;
  650.     const char *time_str;
  651.     const char *user_name;
  652.     const char *passwd;
  653.     debug(2) fprintf(stderr, "cmgr: decoding pub: '%s'n", safe_str(req->pub_auth));
  654.     safe_free(req->passwd);
  655.     if (!req->pub_auth || strlen(req->pub_auth) < 4 + strlen(safe_str(req->hostname)))
  656. return;
  657.     buf = xstrdup(base64_decode(req->pub_auth));
  658.     debug(3) fprintf(stderr, "cmgr: length okn");
  659.     /* parse ( a lot of memory leaks, but that is cachemgr style :) */
  660.     if ((host_name = strtok(buf, "|")) == NULL)
  661. return;
  662.     debug(3) fprintf(stderr, "cmgr: decoded host: '%s'n", host_name);
  663.     if ((time_str = strtok(NULL, "|")) == NULL)
  664. return;
  665.     debug(3) fprintf(stderr, "cmgr: decoded time: '%s' (now: %d)n", time_str, (int) now);
  666.     if ((user_name = strtok(NULL, "|")) == NULL)
  667. return;
  668.     debug(3) fprintf(stderr, "cmgr: decoded uname: '%s'n", user_name);
  669.     if ((passwd = strtok(NULL, "|")) == NULL)
  670. return;
  671.     debug(2) fprintf(stderr, "cmgr: decoded passwd: '%s'n", passwd);
  672.     /* verify freshness and validity */
  673.     if (atoi(time_str) + passwd_ttl < now)
  674. return;
  675.     if (strcasecmp(host_name, req->hostname))
  676. return;
  677.     debug(1) fprintf(stderr, "cmgr: verified auth. info.n");
  678.     /* ok, accept */
  679.     xfree(req->user_name);
  680.     req->user_name = xstrdup(user_name);
  681.     req->passwd = xstrdup(passwd);
  682.     xfree(buf);
  683. }
  684. static void
  685. reset_auth(cachemgr_request * req)
  686. {
  687.     safe_free(req->passwd);
  688.     safe_free(req->pub_auth);
  689. }
  690. static const char *
  691. make_auth_header(const cachemgr_request * req)
  692. {
  693.     static char buf[1024];
  694.     off_t l = 0;
  695.     const char *str64;
  696.     if (!req->passwd)
  697. return "";
  698.     snprintf(buf, sizeof(buf), "%s:%s",
  699. req->user_name ? req->user_name : "",
  700. req->passwd);
  701.     str64 = base64_encode(buf);
  702.     l += snprintf(buf, sizeof(buf), "Authorization: Basic %srn", str64);
  703.     l += snprintf(&buf[l], sizeof(buf) - l,
  704. "Proxy-Authorization: Basic %srn", str64);
  705.     return buf;
  706. }