📄 cachemgr.c
字号:
/* substitute '\t' */ buf_copy = x = xstrdup(buf); if ((p = strchr(x, '\n'))) *p = '\0'; while (x && strlen(x)) { int column_span = 1; const char *cell = xstrtok(&x, '\t'); while (x && *x == '\t') { column_span++; x++; } l += snprintf(html + l, sizeof(html) - l, "<%s colspan=%d align=\"%s\">%s</%s>", ttag, column_span, is_header ? "center" : is_number(cell) ? "right" : "left", cell, ttag); } xfree(buf_copy); /* record ends */ l += snprintf(html + l, sizeof(html) - l, "</tr>\n"); next_is_header = is_header && strstr(buf, "\t\t"); table_line_num++; return html;}static intread_reply(int s, cachemgr_request * req){ char buf[4 * 1024]; FILE *fp = fdopen(s, "r"); /* interpretation states */ enum { isStatusLine, isHeaders, isBodyStart, isBody, isForward, isEof, isForwardEof, isSuccess, isError } istate = isStatusLine; int parse_menu = 0; const char *action = req->action; const char *statusStr = NULL; int status = -1; if (0 == strlen(req->action)) parse_menu = 1; else if (0 == strcasecmp(req->action, "menu")) parse_menu = 1; if (fp == NULL) { perror("fdopen"); return 1; } if (parse_menu) action = "menu"; /* read reply interpreting one line at a time depending on state */ while (istate < isEof) { if (!fgets(buf, sizeof(buf), fp)) istate = istate == isForward ? isForwardEof : isEof; switch (istate) { case isStatusLine: /* get HTTP status */ /* uncomment the following if you want to debug headers */ /* fputs("\r\n\r\n", stdout); */ status = parse_status_line(buf, &statusStr); istate = status == 200 ? isHeaders : isForward; /* if cache asks for authentication, we have to reset our info */ if (status == 401 || status == 407) { reset_auth(req); status = 403; /* Forbiden, see comments in case isForward: */ } /* this is a way to pass HTTP status to the Web server */ if (statusStr) printf("Status: %d %s", status, statusStr); /* statusStr has '\n' */ break; case isHeaders: /* forward header field */ if (!strcmp(buf, "\r\n")) { /* end of headers */ fputs("Content-Type: text/html\r\n", stdout); /* add our type */ istate = isBodyStart; } if (strncasecmp(buf, "Content-Type:", 13)) /* filter out their type */ fputs(buf, stdout); break; case isBodyStart: printf("<HTML><HEAD><TITLE>CacheMgr@%s: %s</TITLE></HEAD><BODY>\n", req->hostname, action); if (parse_menu) { printf("<H2><a href=\"%s\">Cache Manager</a> menu for %s:</H2>", menu_url(req, "authenticate"), req->hostname); printf("<UL>\n"); } else { printf("<P><A HREF=\"%s\">%s</A>\n<HR>\n", menu_url(req, "menu"), "Cache Manager menu"); printf("<PRE>\n"); } istate = isBody; /* yes, fall through, we do not want to loose the first line */ case isBody: /* interpret [and reformat] cache response */ if (parse_menu) fputs(munge_menu_line(buf, req), stdout); else fputs(munge_other_line(buf, req), stdout); break; case isForward: /* forward: no modifications allowed */ /* * Note: we currently do not know any way to get browser.reply to * 401 to .cgi because web server filters out all auth info. Thus we * disable authentication headers for now. */ if (!strncasecmp(buf, "WWW-Authenticate:", 17) || !strncasecmp(buf, "Proxy-Authenticate:", 19)); /* skip */ else fputs(buf, stdout); break; case isEof: /* print trailers */ if (parse_menu) printf("</UL>\n"); else printf("</table></PRE>\n"); print_trailer(); istate = isSuccess; break; case isForwardEof: /* indicate that we finished processing an "error" sequence */ istate = isError; break; default: printf("%s: internal bug: invalid state reached: %d", script_name, istate); istate = isError; } } close(s); return 0;}static intprocess_request(cachemgr_request * req){ const struct hostent *hp; static struct sockaddr_in S; int s; int l; static char buf[2 * 1024]; if (req == NULL) { auth_html(CACHEMGR_HOSTNAME, CACHE_HTTP_PORT, ""); return 1; } if (req->hostname == NULL) { req->hostname = xstrdup(CACHEMGR_HOSTNAME); } if (req->port == 0) { req->port = CACHE_HTTP_PORT; } if (req->action == NULL) { req->action = xstrdup(""); } if (!strcmp(req->action, "authenticate")) { auth_html(req->hostname, req->port, req->user_name); return 0; } if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { snprintf(buf, 1024, "socket: %s\n", xstrerror()); error_html(buf); return 1; } memset(&S, '\0', sizeof(struct sockaddr_in)); S.sin_family = AF_INET; if ((hp = gethostbyname(req->hostname)) != NULL) xmemcpy(&S.sin_addr.s_addr, hp->h_addr, hp->h_length); else if (safe_inet_addr(req->hostname, &S.sin_addr)) (void) 0; else { snprintf(buf, 1024, "Unknown host: %s\n", req->hostname); error_html(buf); return 1; } S.sin_port = htons(req->port); if (connect(s, (struct sockaddr *) &S, sizeof(struct sockaddr_in)) < 0) { snprintf(buf, 1024, "connect: %s\n", xstrerror()); error_html(buf); return 1; } l = snprintf(buf, sizeof(buf), "GET cache_object://%s/%s HTTP/1.0\r\n" "Accept: */*\r\n" "%s" /* Authentication info or nothing */ "\r\n", req->hostname, req->action, make_auth_header(req)); write(s, buf, l); debug(1) fprintf(stderr, "wrote request: '%s'\n", buf); return read_reply(s, req);}intmain(int argc, char *argv[]){ char *s; cachemgr_request *req; safe_inet_addr("255.255.255.255", &no_addr); now = time(NULL); if ((s = strrchr(argv[0], '/'))) progname = xstrdup(s + 1); else progname = xstrdup(argv[0]); if ((s = getenv("SCRIPT_NAME")) != NULL) script_name = xstrdup(s); req = read_request(); return process_request(req);}static char *read_post_request(void){ char *s; char *buf; int len; if ((s = getenv("REQUEST_METHOD")) == NULL) return NULL; if (0 != strcasecmp(s, "POST")) return NULL; if ((s = getenv("CONTENT_LENGTH")) == NULL) return NULL; if ((len = atoi(s)) <= 0) return NULL; buf = xmalloc(len + 1); fread(buf, len, 1, stdin); buf[len] = '\0'; return buf;}static char *read_get_request(void){ char *s; if ((s = getenv("QUERY_STRING")) == NULL) return NULL; return xstrdup(s);}static cachemgr_request *read_request(void){ char *buf; cachemgr_request *req; char *s; char *t; char *q; if ((buf = read_post_request()) != NULL) (void) 0; else if ((buf = read_get_request()) != NULL) (void) 0; else return NULL; if (strlen(buf) == 0) return NULL; req = xcalloc(1, sizeof(cachemgr_request)); for (s = strtok(buf, "&"); s != NULL; s = strtok(NULL, "&")) { t = xstrdup(s); if ((q = strchr(t, '=')) == NULL) continue; *q++ = '\0'; if (0 == strcasecmp(t, "host") && strlen(q)) req->hostname = xstrdup(q); else if (0 == strcasecmp(t, "port") && strlen(q)) req->port = atoi(q); else if (0 == strcasecmp(t, "user_name") && strlen(q)) req->user_name = xstrdup(q); else if (0 == strcasecmp(t, "passwd") && strlen(q)) req->passwd = xstrdup(q); else if (0 == strcasecmp(t, "auth") && strlen(q)) req->pub_auth = xstrdup(q), decode_pub_auth(req); else if (0 == strcasecmp(t, "operation")) req->action = xstrdup(q); } make_pub_auth(req); debug(1) fprintf(stderr, "cmgr: got req: host: '%s' port: %d uname: '%s' passwd: '%s' auth: '%s' oper: '%s'\n", safe_str(req->hostname), req->port, safe_str(req->user_name), safe_str(req->passwd), safe_str(req->pub_auth), safe_str(req->action)); return req;}/* Routines to support authentication *//* * Encodes auth info into a "public" form. * Currently no powerful encryption is used. */static voidmake_pub_auth(cachemgr_request * req){ static char buf[1024]; safe_free(req->pub_auth); debug(3) fprintf(stderr, "cmgr: encoding for pub...\n"); if (!req->passwd || !strlen(req->passwd)) return; /* host | time | user | passwd */ snprintf(buf, sizeof(buf), "%s|%d|%s|%s", req->hostname, (int) now, req->user_name ? req->user_name : "", req->passwd); debug(3) fprintf(stderr, "cmgr: pre-encoded for pub: %s\n", buf); debug(3) fprintf(stderr, "cmgr: encoded: '%s'\n", base64_encode(buf)); req->pub_auth = xstrdup(base64_encode(buf));}static voiddecode_pub_auth(cachemgr_request * req){ char *buf; const char *host_name; const char *time_str; const char *user_name; const char *passwd; debug(2) fprintf(stderr, "cmgr: decoding pub: '%s'\n", safe_str(req->pub_auth)); safe_free(req->passwd); if (!req->pub_auth || strlen(req->pub_auth) < 4 + strlen(safe_str(req->hostname))) return; buf = xstrdup(base64_decode(req->pub_auth)); debug(3) fprintf(stderr, "cmgr: length ok\n"); /* parse ( a lot of memory leaks, but that is cachemgr style :) */ if ((host_name = strtok(buf, "|")) == NULL) return; debug(3) fprintf(stderr, "cmgr: decoded host: '%s'\n", host_name); if ((time_str = strtok(NULL, "|")) == NULL) return; debug(3) fprintf(stderr, "cmgr: decoded time: '%s' (now: %d)\n", time_str, (int) now); if ((user_name = strtok(NULL, "|")) == NULL) return; debug(3) fprintf(stderr, "cmgr: decoded uname: '%s'\n", user_name); if ((passwd = strtok(NULL, "|")) == NULL) return; debug(2) fprintf(stderr, "cmgr: decoded passwd: '%s'\n", passwd); /* verify freshness and validity */ if (atoi(time_str) + passwd_ttl < now) return; if (strcasecmp(host_name, req->hostname)) return; debug(1) fprintf(stderr, "cmgr: verified auth. info.\n"); /* ok, accept */ xfree(req->user_name); req->user_name = xstrdup(user_name); req->passwd = xstrdup(passwd); xfree(buf);}static voidreset_auth(cachemgr_request * req){ safe_free(req->passwd); safe_free(req->pub_auth);}static const char *make_auth_header(const cachemgr_request * req){ static char buf[1024]; off_t l = 0; const char *str64; if (!req->passwd) return ""; snprintf(buf, sizeof(buf), "%s:%s", req->user_name ? req->user_name : "", req->passwd); str64 = base64_encode(buf); l += snprintf(buf, sizeof(buf), "Authorization: Basic %s\r\n", str64); l += snprintf(&buf[l], sizeof(buf) - l, "Proxy-Authorization: Basic %s\r\n", str64); return buf;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -