1 /**************************************************
2 OpengateM - MAC address authentication system
3 module for Authentication of User
5 this file includes the code for main control and pop3/ftp auth.
6 other authentication protocols are coded in other files.
8 Copyright (C) 1999 Opengate Project Team
9 Written by Yoshiaki Watanabe
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 Email: watanaby@is.saga-u.ac.jp
25 **************************************************/
27 #include "opengatemmng.h"
29 void onAuthReplyAlarm(int signo);
30 int authFtp(char *userid, char *passwd);
31 int AuthFtp(char *userid, char *passwd);
32 int authPop3(char *userid, char *passwd);
33 int AuthPop3(char *userid, char *passwd);
34 int authPam(char *userid, char *passwd);
35 int AuthPam(char *userid, char *passwd);
36 int authRadius(char *userid, char *passwd);
37 int AuthRadius(char *userid, char *passwd);
38 int authPop3s(char *userid, char *passwd);
39 int AuthPop3s(char *userid, char *passwd);
40 int authFtpse(char *userid, char *passwd);
41 int AuthFtpse(char *userid, char *passwd);
42 int authFtpsi(char *userid, char *passwd);
43 int AuthFtpsi(char *userid, char *passwd);
44 int authLdap(char *userid, char *passwd);
45 int AuthLdap(char *userid, char *passwd);
47 /****************************************
48 get userid from anywhere (cookie/env/postdata)
49 if not get, send back auth page.
50 language indicates the one for web description
52 return value: TRUE(1)=sccess/FALSE(0)=fail
53 requestStr: (input) string sended with http-POST
54 userId,extraId: (output) entered as 'userId@extraId'
55 language: (input) html description language(ja/en/..)
56 userType: (input) auth as ADMINUSER(1) or NORMALUSER(0)
57 cgiName: (input) the cgi to which the auth page sends data
58 mailDefault: (output) initial value of user mail address
59 redirectedUrl: (input) url before redirection (return to this after processing)
60 ****************************************/
61 int getUserId(char* requestStr, char* userId, char* extraId, char* language, int userType, char* cgiName, char* mailDefault, char* redirectedUrl){
63 char useridfull[USERMAXLN]; /* userid@extraid */
64 char cookie[SIDMAXLN];
65 char password[USERMAXLN];
68 /* default mail address is null */
71 /***** try to get userid from db corresponding to http cookie *****/
74 if(GetHttpCookie(cookie, GetConfValue("AuthUserCookie"))){
75 if(IsCookieFoundInWorkDb(cookie, userId, extraId, NORMALUSER)){
76 ConcatUserId(useridfull, userId, extraId);
77 GetMailDefaultFromWorkDb(cookie, mailDefault);
83 if(GetHttpCookie(cookie, GetConfValue("AuthAdminCookie"))){
84 if(IsCookieFoundInWorkDb(cookie, userId, extraId, ADMINUSER)){
85 ConcatUserId(useridfull, userId, extraId);
92 /***** try to get uid from environment variables(shibboleth/httpbasic) *****/
95 /* search shibboleth / httpbasic auth settings in conf */
96 ResetAuthServerPointer();
97 while(SelectNextAuthServer()){
99 /* if server setting is not matched to the required usertype, skip it */
100 if( (strcmp(GetConfValue("AuthServer/UserType"), "admin")==0)
101 && (userType!=ADMINUSER) ) continue;
102 if( (strcmp(GetConfValue("AuthServer/UserType"), "admin")!=0)
103 && (userType==ADMINUSER) ) continue;
105 /* if the server setting is not shibboleth and not httpbasic, skip it */
106 if(strcmp(GetConfValue("AuthServer/Protocol"), "shibboleth")!=0
107 && strcmp(GetConfValue("AuthServer/Protocol"), "httpbasic")!=0) continue;
109 /* if reached to this line(=shibboleth/httpbasic), get userid from env var */
110 if(GetUserIdFromEnv(useridfull)){
112 /* split user@extra to user and extra. then search conf extra set */
113 SplitId(useridfull, userId, extraId);
114 SetupConfExtra(userId, extraId);
116 /* if the user is found in accept user list, accept user, else deny */
117 /* the user list (defined in conf file) restricts users (if accept all, remove the list) */
118 if(IsUserIdFoundInAcceptUsersList(userId)){
120 MakeMailDefault(userId, extraId, mailDefault);
123 SetMessage(NoInfoInDb);
124 PutDenyToClient(language);
125 err_msg("DENY: user %s", useridfull);
133 /***** try to get userid from request string *****/
134 if(authResult==DENY){
136 /* if not get, in request string, send back auth page */
137 if(!GetUserIdFromPostData(requestStr, useridfull, password)){
139 /* split user@extra to user and extra, then search conf extra set */
140 SplitId(useridfull, userId, extraId);
141 SetupConfExtra(userId, extraId);
143 /* select document content */
144 if(userType==ADMINUSER) docName=GetConfValue("AuthAdminDoc");
145 else docName=GetConfValue("AuthDoc");
147 /* put page and exit */
148 PutAuthRequestPageToClient(language, cgiName, docName, redirectedUrl);
152 /* reaching this line means that userid is found in request string */
153 /* split user@extra to user and extra. then search conf extra set */
154 SplitId(useridfull, userId, extraId);
155 SetupConfExtra(userId, extraId);
157 /* check user by authenticate servers */
158 ResetAuthServerPointer();
159 while(SelectNextAuthServer()){
161 /* if check normal user and admin auth server, skip the server */
162 /* if check admin user and not admin auth server, skip the server */
163 if(userType==NORMALUSER
164 && strcmp(GetConfValue("AuthServer/UserType"), "admin")==0) continue;
165 if(userType==ADMINUSER
166 && strcmp(GetConfValue("AuthServer/UserType"), "admin")!=0) continue;
168 /* authenticate the user with auth server. if deny, goto next server */
169 if((authResult=AuthenticateUser(userId, password))==DENY) continue;
171 /* if userid is not found in the user list in conf, goto next server */
172 /* the user list (defined in conf file) restricts users (if accept all, remove the list) */
173 if(!IsUserIdFoundInAcceptUsersList(userId)){
178 /* if accepted, set mail default(used for warning mail) and exit loop */
179 if(authResult==ACCEPT){
180 MakeMailDefault(userId, extraId, mailDefault);
185 /* if all check is failed, put error */
186 if(authResult==DENY){
187 SetMessage(NoInfoInDb);
188 PutDenyToClient(language);
189 err_msg("DENY: user %s", useridfull);
192 if(authResult==ACCEPT) return TRUE;
196 /**************************************
197 if accept users are listed in conf file,
198 find the userid in the list
199 if no list is indicated, return true
200 **************************************/
201 int isUserIdFoundInAcceptUsersList(char* userId){
202 char usersList[BUFFMAXLN];
203 char userIdPattern[WORDMAXLN];
205 /* get accept users list. if not exist, return true(accept all users) */
206 strlcpy(usersList,GetConfValue("AuthServer/AcceptUsers"),BUFFMAXLN);
207 if(isNull(usersList)) return TRUE;
209 /* if userid is found in the usersList, return true */
210 /* example of usersList is [user1 user2 user3 user4] */
212 /* regular expression matched to "(^| )userid( |$)" */
213 /* it means that [(head or space) userid-string (space or tail)] */
214 /* last-arg 0 of RegExMatch means ignore-case */
215 strlcpy(userIdPattern, "(^| )", WORDMAXLN);
216 strlcat(userIdPattern, userId, WORDMAXLN);
217 strlcat(userIdPattern, "( |$)", WORDMAXLN);
218 return RegExMatch(usersList, userIdPattern, 0);
222 /*******************************************************/
223 /* Authenticate user by accessing to ftp server */
224 /* userid : user to auth (short form(omit @extraid)) */
225 /* password : password for the user */
226 /*******************************************************/
227 int authenticateUser(char *userid, char *passwd)
233 /* get timeout value of authserver reply from conf */
234 timeout=atoi(GetConfValue("AuthServer/Timeout"));
236 /* set auth server reply timeout */
238 AddAlarm("AuthReplyAlarm", timeout, TRUE, onAuthReplyAlarm);
242 /* get authentication protocol from conf */
243 proto=GetConfValue("AuthServer/Protocol");
245 /* authenticate by ftp access */
246 if(strcmp(proto, "ftp")==0){
247 authResult=AuthFtp(userid, passwd);
250 /* authenticate by pop3 access */
251 else if(strcmp(proto, "pop3")==0){
252 authResult=AuthPop3(userid, passwd);
255 /* authenticate by pam */
256 else if(strcmp(proto, "pam")==0){
257 authResult=AuthPam(userid, passwd);
260 /* authenticate by radius */
261 else if(strcmp(proto, "radius")==0){
262 authResult=AuthRadius(userid, passwd);
265 /* authenticate by pop3s */
266 else if(strcmp(proto, "pop3s")==0){
267 authResult=AuthPop3s(userid, passwd);
270 /* authenticate by ldap */
271 else if(strcmp(proto, "ldap")==0){
272 authResult=AuthLdap(userid, passwd);
275 /* authenticate by ftps-explicit */
276 else if(strcmp(proto, "ftpse")==0){
277 authResult=AuthFtpse(userid, passwd);
280 /* authenticate by ftps-implicit */
281 else if(strcmp(proto, "ftpsi")==0){
282 authResult=AuthFtpsi(userid, passwd);
285 /* authenticate by shibboleth */
286 /* in this case, auth request cannot reach to this line */
287 else if(strcmp(proto, "shibboleth")==0){
291 /* authenticate by httpbasic */
292 /* in this case, auth request cannot reach to this line */
293 else if(strcmp(proto, "httpbasic")==0){
298 else if(strcmp(proto, "deny")==0){
302 /* accept all users */
303 else if(strcmp(proto, "accept")==0){
307 /* show splash page and auth is passed */
308 else if(strcmp(proto, "splash")==0){
312 /* unknown request */
314 err_msg("ERR at %s#%d: Unknown protocol:%s",__FILE__,__LINE__,proto);
318 /* stop the auth reply timeout */
319 if(timeout>0) RemoveAlarm("AuthReplyAlarm");
323 /*****************************/
324 /* split userid and extraId */
325 /*****************************/
326 void splitId(char* useridfull, char* userId, char* extraId)
328 char useridSave[USERMAXLN];
332 strlcpy(useridSave, useridfull, USERMAXLN);
334 /* separate extraId from userid (UserIdSeparator is '@') */
335 markPnt=strchr(useridSave, *GetConfValue("UserIdSeparator"));
337 /* separator mark is not found. no extraId */
338 strlcpy(extraId,"",USERMAXLN);
339 strlcpy(userId,useridSave,USERMAXLN);
341 /* separator is found. pick up extraId */
343 strlcpy(extraId,markPnt+1,USERMAXLN);
344 strlcpy(userId,useridSave,USERMAXLN);
348 /*************************
349 concatinate userid and extraid
350 *************************/
351 char* concatUserId(char* useridfull, char* userId, char* extraId){
353 /* set full userid */
354 strlcpy(useridfull, userId,USERMAXLN);
355 if(!isNull(extraId)){
356 strlcat(useridfull, GetConfValue("UserIdSeparator"), USERMAXLN);
357 strlcat(useridfull, extraId, USERMAXLN);
362 /***********************/
363 /* Authenticate by FTP */
364 /***********************/
365 int authFtp(char *userid, char *passwd)
368 char recvline[BUFFMAXLN];
370 char* serverAddr; /* auth server address */
371 char* port; /* auth server port */
373 /* get auth server address */
374 serverAddr=GetConfValue("AuthServer/Address");
376 if(isNull(serverAddr)){
377 err_msg("ERR at %s#%d: Missing address for FTP server in config",
382 /* get auth server port */
383 port=GetConfValue("AuthServer/Port");
385 /* FTP server connect (if port is not defined in conf, default is used) */
387 sockfd = Tcp_connect(serverAddr, "ftp");
389 sockfd = Tcp_connect(serverAddr, port);
392 err_msg("ERR at %s#%d: Ftp server is not normal 0",__FILE__,__LINE__);
396 /* get [220 <host> FTP server ..] */
397 if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
398 err_msg("ERR at %s#%d: Ftp server is not normal 1",__FILE__,__LINE__);
402 if(strstr(recvline,"220")!=recvline){
403 err_msg("ERR at %s#%d: Ftp server is not normal 2",__FILE__,__LINE__);
408 /* put [user <userid>] */
409 Writefmt(sockfd, "user %s\r\n", userid);
411 /* get [331 Password required ..] (greeting lines might exist before 331 request) */
412 if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
413 err_msg("ERR at %s#%d: Ftp server is not normal 3",__FILE__,__LINE__);
418 /* if multi-line greeting [220 ...] exist, skip them. */
419 while(strstr(recvline,"220")==recvline){
420 if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
421 err_msg("ERR at %s#%d: Ftp server is not normal 3",__FILE__,__LINE__);
427 /* check [331 Password required ..] */
428 if(strstr(recvline,"331")!=recvline){
429 err_msg("ERR at %s#%d: Ftp server is not normal 4",__FILE__,__LINE__);
434 /* put [pass <password>] */
435 Writefmt(sockfd, "pass %s\r\n", passwd);
437 /* get [230 User <userid> logged in] (the string means correct userid/passwd) */
438 if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
439 err_msg("ERR at %s#%d: Ftp server is not normal 5",__FILE__,__LINE__);
443 if(strstr(recvline,"230")==recvline){
450 Writefmt(sockfd,"quit\r\n");
456 /************************/
457 /* Authenticate by POP3 */
458 /************************/
459 int authPop3(char *userid, char *passwd)
462 char recvline[BUFFMAXLN];
467 /* get auth server address */
468 serverAddr=GetConfValue("AuthServer/Address");
470 if(isNull(serverAddr)){
471 err_msg("ERR at %s#%d: Missing address for POP3 server in config",
476 /* get auth server port */
477 port=GetConfValue("AuthServer/Port");
479 /* POP3 server connect */
481 sockfd = Tcp_connect(serverAddr, "pop3");
483 sockfd = Tcp_connect(serverAddr, port);
486 err_msg("ERR at %s#%d: Pop3 server is not normal 0",__FILE__,__LINE__);
490 /* get [+OK POP3 <host> <ver> server ready]*/
491 if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
492 err_msg("ERR at %s#%d: Pop3 server is not normal 1",__FILE__,__LINE__);
496 if(strstr(recvline,"+OK")!=recvline){
497 err_msg("ERR at %s#%d: Pop3 server is not normal 2",__FILE__,__LINE__);
502 /* put [user <userid>] */
503 Writefmt(sockfd, "user %s\r\n", userid);
505 /* get [+OK User name accepted, password please] */
506 if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
507 err_msg("ERR at %s#%d: Pop3 server is not normal 3",__FILE__,__LINE__);
511 if(strstr(recvline,"+OK")!=recvline){
512 err_msg("ERR at %s#%d: Pop3 server is not normal 4",__FILE__,__LINE__);
517 /* put [pass <password>] */
518 Writefmt(sockfd, "pass %s\r\n", passwd);
520 /* get [+OK Mailbox open, <count> messages] */
521 if((n = readln(sockfd, recvline, BUFFMAXLN)) < 0) {
522 err_msg("ERR at %s#%d: Pop3 server is not normal 5",__FILE__,__LINE__);
526 if(strstr(recvline,"+OK")==recvline){
533 Writefmt(sockfd,"quit\r\n");
539 /***************************************/
540 /* called at auth reply timeout */
541 /* on timeout, read wait is cleared */
542 /***************************************/
543 void onAuthReplyAlarm(int signo)
548 /***********************************
549 check duplication of shibboleth / httpbasic auth server
550 shibboleth/httpbasic cannot be used for both usertype (admin and normal)
551 ***********************************/
552 int isShibOrBasicAuthDuplicated(void){
556 /* scan config file to count shibboleth/httpbasic auth server setting */
557 ResetAuthServerPointer();
558 while(SelectNextAuthServer()){
559 if(strcmp(GetConfValue("AuthServer/Protocol"), "shibboleth")==0) nShib++;
560 if(strcmp(GetConfValue("AuthServer/Protocol"), "httpbasic")==0) nBasic++;
562 ResetAuthServerPointer();
564 /* if duplicated, put error */
565 if(nShib>1 || nBasic>1){
566 err_msg("ERR at %s#%d: Shibboleth or HttpBasic auth cannot duplicate",__FILE__,__LINE__);
573 /**************************************
574 setup default mail address
575 made from conf value at MailAttribute or MailDomain
576 **************************************/
577 int makeMailDefault(char* userId, char* extraId, char* mailDefault){
579 char* pMailAttribute=NULL;
580 char* pMailDomain=NULL;
581 char* pMailAddr=NULL;
583 /* set default null */
586 /* get conf values for mail domain */
587 pMailAttribute=GetConfValue("AuthServer/MailAttribute");
588 pMailDomain=GetConfValue("AuthServer/MailDomain");
589 if(isNull(pMailAttribute) && isNull(pMailDomain)){
590 err_msg("ERR at %s#%d: Can't get mail attibute/domain setting from conf file.",__FILE__,__LINE__);
594 /* if set MailAttribute, mail from the env variable set in MailAttribute */
595 /* (Shibboleth puts the user mail address into an env variable) */
596 if(!isNull(pMailAttribute)){
597 pMailAddr=getenvEx(pMailAttribute,TRUE,FALSE); /* var list is permitted */
598 if(!isNull(pMailAddr)){
599 strlcpy(mailDefault, pMailAddr, BUFFMAXLN);
602 err_msg("ERR at %s#%d: Can't get mail attibute from environment variable.",__FILE__,__LINE__);
607 /* if set MailDomain, mail from userid+@+MailDomain */
608 if(!isNull(pMailDomain)){
609 strlcpy(mailDefault, userId, BUFFMAXLN);
610 strlcat(mailDefault, "@", BUFFMAXLN);
611 strlcat(mailDefault, pMailDomain, BUFFMAXLN);
614 err_msg("ERR at %s#%d: Can't get mail domain string from conf file.",__FILE__,__LINE__);
618 err_msg("ERR at %s#%d: Can't set mail. Check AuthServer/MailAttribute or AuthServer/MailDomain in conf.",__FILE__,__LINE__);
622 /**********************************
623 is AuthServer setting for normal user 'splash'
624 **********************************/
625 int isSplashOnlyManagement(void){
628 /* search AuthServer setting having Protocol=splash and UserType!=admin */
629 ResetAuthServerPointer();
630 while(SelectNextAuthServer()){
631 if((strcmp(GetConfValue("AuthServer/Protocol"), "splash")==0)&&
632 (strcmp(GetConfValue("AuthServer/UserType"), "admin")!=0) ){
637 ResetAuthServerPointer();
641 /**********************************/
642 /**********************************/
643 int GetUserId(char* requestStr, char* userId, char* extraId, char* language, int userType, char* cgiName, char* mailDefault, char* redirectedUrl){
645 if(debug>1) err_msg("DEBUG:=>getUserId(..,%s,%d)",language,userType);
646 ret=getUserId(requestStr, userId, extraId, language, userType, cgiName, mailDefault, redirectedUrl);
647 if(debug>1) err_msg("DEBUG:(%d)<=getUserId(%s,%s,%s)",ret,userId,extraId,mailDefault);
651 int AuthFtp(char *userid, char *passwd)
655 if(debug>1) err_msg("DEBUG:=>authFtp(%s,passwd)",userid);
656 ret=authFtp(userid,passwd);
657 if(debug>1) err_msg("DEBUG:(%d)<=authFtp( )",ret);
663 int AuthPop3(char *userid, char *passwd)
667 if(debug>1) err_msg("DEBUG:=>authPop3(%s,passwd)",userid);
668 ret=authPop3(userid,passwd);
669 if(debug>1) err_msg("DEBUG:(%d)<=authPop3( )",ret);
674 int AuthenticateUser(char *userid, char *password)
678 if(debug>1) err_msg("DEBUG:=>authenticateUser(%s,passwd)",userid);
679 ret=authenticateUser(userid,password);
680 if(debug>1) err_msg("DEBUG:(%d)<=authenticateUser( )",ret);
685 void SplitId(char* userid, char* useridshort, char* extraId)
687 if(debug>1) err_msg("DEBUG:=>splitId(%s,,)",userid);
688 splitId(userid,useridshort,extraId);
689 if(debug>1) err_msg("DEBUG:<=splitId(,%s,%s)",useridshort,extraId);
692 char* ConcatUserId(char* useridfull, char* userId, char* extraId)
695 if(debug>1) err_msg("DEBUG:=>concatUserId(,%s,%s)",userId,extraId);
696 ret=concatUserId(useridfull, userId, extraId);
697 if(debug>1) err_msg("DEBUG:<=concatUserId(%s,,)",useridfull);
701 int IsUserIdFoundInAcceptUsersList(char* userId){
704 if(debug>1) err_msg("DEBUG:=>isUserIdFoundInAcceptUsersList(%s)",userId);
705 ret=isUserIdFoundInAcceptUsersList(userId);
706 if(debug>1) err_msg("DEBUG:(%d)<=isUserIdFoundInAcceptUsersList( )",ret);
711 int IsShibOrBasicAuthDuplicated(void){
714 if(debug>1) err_msg("DEBUG:=>isShibOrBasicAuthDuplicated( )");
715 ret=isShibOrBasicAuthDuplicated();
716 if(debug>1) err_msg("DEBUG:(%d)<=isShibOrBasicAuthDuplicated( )",ret);
721 int MakeMailDefault(char* userId, char* extraId, char* mailDefault){
724 if(debug>1) err_msg("DEBUG:=>makeMailDefault(%s,%s,)",userId, extraId);
725 ret=makeMailDefault(userId, extraId,mailDefault);
726 if(debug>1) err_msg("DEBUG:(%d)<=makeMailDefault(,,%s)",ret,mailDefault);
731 int IsSplashOnlyManagement(void){
734 if(debug>1) err_msg("DEBUG:=>isSplashOnlyManagement()");
735 ret=isSplashOnlyManagement();
736 if(debug>1) err_msg("DEBUG:(%d)<=isSplashOnlyManagement",ret);