1 /**************************************************
3 module for Communication through CGI
5 Copyright (C) 1999 Opengate Project Team
6 Written by Yoshiaki Watanabe
7 Modified Katsuhiko Eguchi, 2005
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 Email: watanaby@is.saga-u.ac.jp
25 Programmed by Yoshiaki WATANABE
26 Modified by Shin-ichi TADAKI
27 Modified by Katsuhiko Eguchi
28 Modified by Makoto Otani
29 **************************************************/
31 #include "opengatesrv.h"
33 /* convert two-char-hex "aa" to one-number 0Xaa */
34 #define hex2num(x) ((x)>='A' ? ((x) & 0XDF) - 'A' +10 : ((x) - '0'))
36 int isHttpWatchEnableClient(void);
37 void split(char content[], char *name[], char *value[], char *next[]);
38 void decode(char *string);
40 /*******************************/
41 /* get the client addr */
42 /*******************************/
43 void getClientAddr(char *clientAddr)
45 strncpy(clientAddr, getenv("REMOTE_ADDR"), ADDRMAXLN);
48 /********************************************/
49 /* get Post data from the client */
50 /********************************************/
51 int getPostData(char *userid, char *password, char *clientAddr4, int *durationPtr, int *durationEntered, char *language, char *redirectedUrl)
55 char content[BUFFMAXLN]="";
56 char queryStr[BUFFMAXLN]="";
61 char durationStr[WORDMAXLN]="";
62 char langList[BUFFMAXLN]="";
63 char encodeAddr4[ADDRMAXLN]="";
64 char accessAddr[ADDRMAXLN]="";
66 /* get content sent from web input */
67 if(getenv("CONTENT_LENGTH")!=NULL
68 &&(contentLen=atoi(getenv("CONTENT_LENGTH")))!=0){
70 contentLen++; /* for terminate ch */
71 if(contentLen > BUFFMAXLN) contentLen=BUFFMAXLN;
72 if(fgets(content, contentLen, stdin) == NULL){
76 /* get items from string */
82 redirectedUrl[0]='\0';
87 split(ptr, name, value, next);
89 if(strstr(name[0], "userid")!=NULL){
90 strncpy(userid, value[0], USERMAXLN);
91 }else if(strstr(name[0], "password")!=NULL){
92 strncpy(password, value[0], PASSMAXLN);
93 }else if(strstr(name[0],"remote_addr")!=NULL){
94 strncpy(encodeAddr4,value[0],ADDRMAXLN);
95 }else if(strstr(name[0], "language")!=NULL){
96 strncpy(language, value[0], WORDMAXLN);
97 }else if(strstr(name[0], "duration")!=NULL){
98 strncpy(durationStr, value[0], WORDMAXLN);
99 }else if(strstr(name[0], "redirected_url")!=NULL){
100 strncpy(redirectedUrl, value[0], BUFFMAXLN);
106 /* get paremeters from query string (not post but in url) */
107 if(getenv("QUERY_STRING")!=NULL
108 &&(queryStrLen=strlen(getenv("QUERY_STRING")))!=0){
110 /* get html access parameter string */
111 strncpy(queryStr, getenv("QUERY_STRING"), BUFFMAXLN);
113 /* split language and address in content
114 [addr=0-0-0&lang=ja&redirectedurl=xxxx] */
117 split(ptr, name, value, next);
118 if(strstr(name[0], "addr")!=NULL){
119 strncpy(encodeAddr4,value[0],ADDRMAXLN);
120 }else if(strstr(name[0], "lang")!=NULL){
121 strncpy(language, value[0], WORDMAXLN);
122 }else if(strstr(name[0], "redirectedurl")!=NULL){
123 strncpy(redirectedUrl, value[0], BUFFMAXLN);
129 /* no content and no query string */
130 if(contentLen==0 && queryStrLen==0){
131 err_msg("ERR at %s#%d: no parameter is aquired",__FILE__,__LINE__);
135 /* decode the HTTP encoding */
141 decode(redirectedUrl);
143 /* if not available language, use first lang */
144 strncpy(langList, GetConfValue("HtmlLangs"), BUFFMAXLN); /* list of available languages */
145 if(strstr(langList,language)==NULL){
146 sscanf(langList,"%s",language);
149 /* convert duration string to interger and minutes to seconds */
150 *durationPtr = atoi(durationStr)*60;
151 *durationEntered = TRUE;
153 /* usage duration is restricted to permitted range */
154 if(*durationPtr <= 0){
155 *durationEntered = FALSE;
156 *durationPtr= atoi(GetConfValue("Duration/Default"));
158 int durmax=atoi(GetConfValue("Duration/Max"));
159 if(*durationPtr > durmax) *durationPtr=durmax;
162 /* encoded address starting as "0-0-0" means no addr info */
163 /* it indicates needless to get dual stack addresses */
164 /* and only use getenv("REMOTE_ADDR") address */
165 if(strnstr(encodeAddr4, "0-0-0", ADDRMAXLN)==encodeAddr4){
169 /* decode client address to dot separated form */
170 else if(AddrDecode(clientAddr4, encodeAddr4)==1){
171 /* if can't decode, retry */
172 err_msg("ERR at %s#%d: Cannot decode client address",__FILE__,__LINE__);
176 /* if the decoded IPv4 addr is not same as access IPv4 addr, use later */
177 strncpy(accessAddr, getenv("REMOTE_ADDR"), ADDRMAXLN);
178 if((strnstr(accessAddr, ".", ADDRMAXLN)!=NULL) /* access is IPv4 */
179 && strncmp(accessAddr, clientAddr4, ADDRMAXLN)!=0){ /* and not same */
180 strncpy(clientAddr4, accessAddr, ADDRMAXLN);
183 /* if no userid, set useid="?" */
193 /********************************************/
194 /* get userid from environment variable */
195 /********************************************/
196 int getUserIdFromEnv(char *userid){
201 /* if shibboleth or httpbasic, get uid from environment var */
203 if(strcmp(GetConfValue("AuthServer/Protocol"), "shibboleth")==0){
204 pEnv=getenvEx(GetConfValue("AuthServer/UidAttribute"));
206 strncpy(userid, pEnv, USERMAXLN);
208 /* if idp string can be get from env variable, concatinate it as uid@idp */
209 pEnv=getenvEx(GetConfValue("AuthServer/OrgAttribute"));
211 strncat(userid, GetConfValue("UserIdSeparator"), USERMAXLN);
212 strncat(userid, pEnv, USERMAXLN);
216 err_msg("ERR at %s#%d: Cannot get user info from shibboleth",__FILE__,__LINE__);
218 PutClientMsg("Cannot get user info from shibboleth<br>Check shibboleth setting in .htaccess and other");
224 else if(strcmp(GetConfValue("AuthServer/Protocol"), "httpbasic")==0){
225 if(!isNull(getenv("REMOTE_USER"))){
226 strncpy(userid,getenv("REMOTE_USER"),USERMAXLN);
229 err_msg("ERR at %s#%d: Cannot get user info from httpbasic",__FILE__,__LINE__);
231 PutClientMsg("Cannot get user info from http basic<br>Check http basic setting in .htaccess and other");
238 /********************************************/
239 /* get data related to cookie from client */
240 /********************************************/
241 int getCookieData(char *userid, char *clientAddr4, int *duration, int *durationEntered, char *language, char* closeTime)
243 char cookie[SIDMAXLN]=""; /* md5 session key from cookie */
244 char useridInCookie[USERMAXLN]=""; /* userid from cookie */
245 char macAddr[ADDRMAXLN]=""; /* mac address from arp */
246 char macAddrInDb[ADDRMAXLN]=""; /* mac address in DB */
248 /* get cookie values */
249 if(!GetAuthCookie(cookie,useridInCookie)) return FALSE;
251 /* get related info from DB */
252 if(!GetSessionInfoFromDb(cookie, userid, clientAddr4, macAddrInDb,
253 duration, durationEntered, language, closeTime)) return FALSE;
255 /* if userid is changed, cookie auth is failed */
256 if(strcmp(useridInCookie, userid)!=0) return FALSE;
258 /* if mac addr is changed, cookie auth is failed */
259 GetMacAddrFromArp(clientAddr4, macAddr);
260 if(strcmp(macAddr, macAddrInDb)!=0) return FALSE;
265 /*********************************************/
266 /* get HTTP-Cookie for OpengateAuth */
267 /*********************************************/
268 /* cookie string examples
269 "OpengateAuth=de..ac1&Userid=user1"
270 "OpengateAuth=de..ac1&Userid=user1; xxx=..; yyy=.."
271 "xxx=..; yyy=..; OpengateAuth=de..ac1&Userid=user1"
273 int getAuthCookie(char *cookie, char *userid){
274 char content[BUFFMAXLN];
285 /* if exist cookie, copy it to work area */
286 if(isNull(getenv("HTTP_COOKIE"))) return FALSE;
287 strncpy(content, getenv("HTTP_COOKIE"), BUFFMAXLN);
290 /* search 'OpengateAuth' cookie string (terminated by ; or \0) */
292 if((ptrNext=strstr(ptr, "; "))==NULL) break; /* search "; " */
293 *ptrNext='\0'; /* overwrite string end */
294 ptrNext++; /* pointer to next string */
295 while(!isNull(ptrNext)&&*ptrNext==' ') ptrNext++; /* skip spaces */
296 if(strstr(ptr, COOKIENAME)==ptr) break; /* exit at matching */
297 ptr=ptrNext; /* check next string */
300 /* get valuses of cookie from "OpengateAuth=de..ac1&Userid=user1" */
302 split(ptr, name, value, next);
304 if(strstr(name[0], COOKIENAME)!=NULL){
305 strncpy(cookie, value[0], SIDMAXLN);
306 }else if(strstr(name[0], "Userid")!=NULL){
307 strncpy(userid, value[0], USERMAXLN);
312 if(isNull(cookie)) return FALSE;
316 /*********************************************/
317 /* deny message to the client */
318 /*********************************************/
319 void putClientDeny(char *clientAddr4, char *language)
321 char denydoc[BUFFMAXLN]="";
322 char authCgiUrl[BUFFMAXLN]="";
323 char encodeAddr[ADDRMAXLN]="";
324 char opengateDir[BUFFMAXLN]="";
325 char protocol[WORDMAXLN]="";
328 /* the left key is replaced by the right value */
329 struct html_key keys[]=
331 {"%%OPENGATEDIR%%", opengateDir},
332 {"%%AUTHCGIURL%%", authCgiUrl},
333 {"%%ADDR4%%", encodeAddr},
334 {"%%LANGUAGE%%", language},
335 {"%%PROTOCOL%%", protocol},
336 {"",""} /* DON'T REMOVE THIS LINE */
339 /* create authcgi URL string */
340 snprintf(authCgiUrl, BUFFMAXLN, "%s%s%s/%s",
341 GetConfValue("OpengateServerName"),
342 GetConfValue("CgiDir"),
343 GetConfValue("OpengateDir"),
344 GetConfValue("AuthCgi"));
346 /* create opengate dir */
347 snprintf(opengateDir, BUFFMAXLN, GetConfValue("OpengateDir"));
349 /* create encoded addr4 */
350 if(AddrEncode(encodeAddr, clientAddr4)==1){
354 /* protocol is ssl or non-ssl */
355 if(strcmp(getenv("SERVER_PORT"),GetServicePortStr("https"))==0){
356 strncpy(protocol, "https",WORDMAXLN);
358 strncpy(protocol, "http",WORDMAXLN);
361 /* document path to deny doc */
362 snprintf(denydoc, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
363 GetConfValue("OpengateDir"),language,GetConfValue("DenyDoc"));
365 /* replace keyword and send out the file */
366 printf("Content-type: text/html\r\n\r\n");
367 HtmlTemplate(denydoc, keys);
371 /*********************************************/
372 /* deny message to the client */
373 /*********************************************/
374 void putClientRetry(char *language)
376 char retrydoc[BUFFMAXLN];
377 char externalUrl[BUFFMAXLN];
378 char authCgiUrl[BUFFMAXLN];
379 char opengateDir[BUFFMAXLN];
382 /* the left key is replaced by the right value */
383 struct html_key keys[]=
385 {"%%OPENGATEDIR%%", opengateDir},
386 {"%%EXTERNALURL%%", externalUrl},
387 {"%%AUTHCGIURL%%", authCgiUrl},
388 {"%%LANGUAGE%%", language},
389 {"",""} /* DON'T REMOVE THIS LINE */
392 /* create opengate Dir */
393 snprintf(opengateDir, BUFFMAXLN, GetConfValue("OpengateDir"));
395 /* create external URL string */
396 strncpy(externalUrl, GetConfValue("ExternalUrl"), BUFFMAXLN);
398 /* create authcgi URL string */
399 snprintf(authCgiUrl, BUFFMAXLN, "%s%s%s/%s",
400 GetConfValue("OpengateServerName"),
401 GetConfValue("CgiDir"),
403 GetConfValue("AuthCgi"));
405 /* make read in path to the retry document */
406 snprintf(retrydoc, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
407 opengateDir,language,GetConfValue("RetryDoc"));
409 /* replace keyword and send out the file */
410 printf("Content-type: text/html\r\n\r\n\r\n");
411 HtmlTemplate(retrydoc, keys);
416 /*********************************************/
417 /* put some message to the client */
418 /*********************************************/
419 void putClientMsg(char *message)
421 printf("Content-type: text/html\r\n\r\n");
422 printf("<HTML><HEAD><TITLE>OpengateMsg</TITLE></HEAD> \r\n");
423 printf("<BODY> \r\n");
424 printf("%s\r\n", message);
425 printf("</BODY></HTML> \r\n\r\n");
430 /*********************************************/
431 /* put accept message and javascript to the client */
432 /* httpkeep page is sent in watch-client.c */
433 /*********************************************/
434 void putClientAccept(char *userid, char *sessionId, int port, int pid, char *clientAddr4, char *clientAddr6, int ipStatus, int duration, int durationEntered, char *language, char *cookie, int cookieAuth, char *redirectedUrl)
438 char buff[BUFFMAXLN];
439 char acceptDocPath[BUFFMAXLN];
440 char acceptDoc2Url[BUFFMAXLN];
441 char terminateUrl[BUFFMAXLN];
442 char httpkeepUrl[BUFFMAXLN];
443 char portStr[WORDMAXLN];
444 char durationStr[WORDMAXLN];
445 char *startPageUrl="";
447 char *opengateDir=GetConfValue("OpengateDir");
448 char *opengateServerName=GetConfValue("OpengateServerName");
449 int startPageType=atoi(GetConfValue("StartPage/Type"));
450 char useridshort[USERMAXLN];
451 char extraId[USERMAXLN];
453 /* select proper accept doc */
454 switch(toupper(*GetConfValue("WatchMode"))){
456 /* HTTP watch mode */
459 if(isHttpWatchEnableClient()){
460 pAcceptDoc=GetConfValue("AcceptDocHttp");
462 pAcceptDoc=GetConfValue("AcceptDocTime");
466 /* TIMEOUT watch mode */
468 pAcceptDoc=GetConfValue("AcceptDocTime");
472 /* split id to display short format of userid */
473 SplitId(userid, useridshort, extraId);
475 /* if positive value is set in duration, TIME watch mode is selected */
476 if(durationEntered) pAcceptDoc=GetConfValue("AcceptDocTime");
478 /* create path to acceptdoc */
479 snprintf(acceptDocPath, BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
480 GetConfValue("OpengateDir"),language,pAcceptDoc);
483 snprintf(acceptDoc2Url, BUFFMAXLN,
484 "http://%s%s/%s/%s",GetConfValue("OpengateServerName"),
485 GetConfValue("OpengateDir"),language,GetConfValue("AcceptDoc2"));
487 /* create terminate url [http://<servaddr>:<port>/terminate-<pid>] */
488 snprintf(terminateUrl, BUFFMAXLN, "http://%s:%d/terminate-%d",
489 GetConfValue("OpengateServerName"), port, getpid());
491 /* create httpkeep page url
492 ['http://<servaddr>:<port>/httpkeep-<userid>'] */
493 snprintf(httpkeepUrl, BUFFMAXLN,
494 "'http://%s:%d/httpkeep-%s-%s'",
495 GetConfValue("OpengateServerName"), port, userid,sessionId);
497 /* create port string */
498 snprintf(portStr, WORDMAXLN, "%d", port);
500 /* create duration string (duration=sec, display value=min) */
501 snprintf(durationStr, WORDMAXLN, "%d", duration/60);
504 if((fp=fopen(acceptDocPath, "r"))==NULL){
505 err_msg("ERR at %s#%d: cannot open %s",__FILE__,__LINE__,acceptDocPath);
506 PutClientMsg("Cannot find html document");
510 /* if redirect page is not set, use other setting */
511 if(isNull(redirectedUrl)){
512 if(isNull(GetConfValue("StartPage/Url"))) redirectedUrl=acceptDoc2Url;
513 else redirectedUrl=GetConfValue("StartPage/Url");
516 /* create start page url to put information */
517 if(cookieAuth==1) startPageUrl=redirectedUrl;
518 else if(startPageType==0) startPageUrl=acceptDoc2Url;
519 else if(startPageType==1) startPageUrl=GetConfValue("StartPage/Url");
520 else if(startPageType==2) startPageUrl=redirectedUrl;
521 else startPageUrl=acceptDoc2Url;
523 /* write out html headers */
524 printf("Content-type: text/html\r\n");
525 printf("Set-Cookie: %s=%s&Userid=%s;path=/;\r\n\r\n", COOKIENAME, cookie, userid);
527 /* read html document from file and send to web */
528 while(fgets(buff, BUFFMAXLN, fp)!=NULL){
531 if(strlen(buff)>=BUFFMAXLN-1){
532 err_msg("ERR at %s#%d: too long line in %s",__FILE__,__LINE__,acceptDocPath);
536 htmlReplace(buff, "%%OPENGATESERVERNAME%%", opengateServerName);
537 htmlReplace(buff, "%%OPENGATEDIR%%", opengateDir);
538 htmlReplace(buff, "%%OPENGATEPORT%%", portStr);
539 htmlReplace(buff, "%%DURATION%%", durationStr);
540 htmlReplace(buff, "%%USERID%%", useridshort);
541 htmlReplace(buff, "%%SESSIONID%%", sessionId);
542 htmlReplace(buff, "%%LANGUAGE%%", language);
543 htmlReplace(buff, "%%TERMINATEURL%%", terminateUrl);
544 htmlReplace(buff, "%%HTTPKEEPURL%%", httpkeepUrl);
545 htmlReplace(buff, "%%STARTURL%%", startPageUrl);
546 htmlReplace(buff, "%%REDIRECTEDURL%%", redirectedUrl);
553 fputs("\r\n\r\n",stdout);
559 /*****************************************************/
560 /* is the client enable to keep long http connection */
561 /*****************************************************/
562 int isHttpWatchEnableClient(void)
564 /* HTTP Keep-Alive is not standard in http/1.0 */
565 if(strcmp(getenv("SERVER_PROTOCOL"),"HTTP/1.0")==0) return FALSE;
567 /* some user agent does not support long HTTP Keep-Alive */
568 if(RegExMatch(getenv("HTTP_USER_AGENT"),
569 GetConfValue("HttpWatch/SkipAgentPattern"))) return FALSE;
574 /************************************/
575 /* split value for indicated name */
576 /* in content "name=value&..." */
577 /************************************/
578 void split(char content[], char *name[], char *value[], char *next[])
584 value[0]=content+strlen(content);
588 if((pstr=strchr(name[0],(int)'='))==NULL){
594 /* set value start */
599 if((pstr=strchr(value[0],'&'))==NULL){
612 /**********************************/
613 /* decode text coding in web post */
614 /**********************************/
615 void decode(char *string)
617 char *pcheck, *pinsert;
619 pcheck=pinsert=string;
620 while(*pcheck != '\0'){
623 }else if(*pcheck == '%'){
624 *pinsert=(char)(hex2num(*(pcheck+1))*16 + hex2num(*(pcheck+2)));
635 /***************************************/
636 /* get HTTP_REFERER and check true url */
637 /***************************************/
638 int checkReferer(void)
640 char url[BUFFMAXLN]="";
641 if(getenv("HTTP_REFERER")!=NULL){
642 strncpy(url,getenv("HTTP_REFERER"),BUFFMAXLN);
643 if(strstr(url,GetConfValue("OpengateServerName"))==NULL){
650 /*******************************/
651 /*******************************/
652 void GetClientAddr(char *clientAddr)
654 if(debug>1) err_msg("DEBUG:=>getClientAddr( )");
655 getClientAddr(clientAddr);
656 if(debug>1) err_msg("DEBUG:<=getClientAddr(%s)",clientAddr);
660 int GetPostData(char *userid, char *password, char *clientAddr4, int *durationPtr, int *durationEntered, char *language, char *redirectedUrl)
664 if(debug>1) err_msg("DEBUG:=>getPostData( )");
665 ret=getPostData(userid,password,clientAddr4,durationPtr,durationEntered,language,redirectedUrl);
666 if(debug>1) err_msg("DEBUG:%d<=getPostData(%s,%s,%d,%d,%s)",ret,userid,clientAddr4,*durationPtr,durationEntered,language,redirectedUrl);
670 int GetUserIdFromEnv(char *userid){
672 if(debug>1) err_msg("DEBUG:=>getUserIdFromEnv(%s)",userid);
673 ret=getUserIdFromEnv(userid);
674 if(debug>1) err_msg("DEBUG:%d<=getUserIdFromEnv(%s)",ret,userid);
678 void PutClientAccept(char *userid, char *sessionId, int port, int pid, char *clientAddr4, char *clientAddr6, int ipStatus, int duration, int durationEntered, char *language, char *cookie, int cookieAuth, char *redirectedUrl)
680 if(debug>1) err_msg("DEBUG:=>putClientAccept(%s,%s,%d,%d,%s,%s,%d,%d,%d,%s,%s,%d,%s)",userid,sessionId,port,pid,clientAddr4,clientAddr6,ipStatus, duration, durationEntered, language, cookie, cookieAuth, redirectedUrl);
681 putClientAccept(userid,sessionId,port,pid,clientAddr4,clientAddr6,ipStatus,duration, durationEntered, language, cookie, cookieAuth,redirectedUrl);
682 if(debug>1) err_msg("DEBUG:<=putClientAccept( )");
685 void PutClientDeny(char *clientAddr4, char *language)
687 if(debug>1) err_msg("DEBUG:=>putClientDeny(%s,%s)",clientAddr4,language);
688 putClientDeny(clientAddr4,language);
689 if(debug>1) err_msg("DEBUG:<=putClientDeny( )");
692 void PutClientRetry(char *lang)
694 if(debug>1) err_msg("DEBUG:=>putClientRetry(%s)",lang);
695 putClientRetry(lang);
696 if(debug>1) err_msg("DEBUG:<=putClientRetry( )");
699 void PutClientMsg(char *message)
701 if(debug>1) err_msg("DEBUG:=>putClientMsg( %s )",message);
702 putClientMsg(message);
703 if(debug>1) err_msg("DEBUG:<=putClientMsg( )");
706 int CheckReferer(void)
709 if(debug>1) err_msg("DEBUG:=>checkReferer( )");
710 ret = checkReferer();
711 if(debug>1) err_msg("DEBUG:(%d)<=checkReferer( )",ret);
715 int GetAuthCookie(char *cookie, char *userid){
718 if(debug>1) err_msg("DEBUG:=>getAuthCookie( )");
719 ret=getAuthCookie(cookie, userid);
720 if(debug>1) err_msg("DEBUG:%d<=getAuthCookie(%s,%s)",
725 int GetCookieData(char *userid, char *clientAddr4, int *duration, int *durationEntered, char *language, char* closeTime){
728 if(debug>1) err_msg("DEBUG:=>getCookieData( )");
729 ret=getCookieData(userid,clientAddr4,duration,durationEntered,
731 if(debug>1) err_msg("DEBUG:%d<=getCookieData(%s,passwd,%s,%d,%d,%s,%s)",ret,userid,clientAddr4,*duration,*durationEntered,language,closeTime);