"Fossies" - the Fresh Open Source Software Archive

Member "delegate9.9.13/src/dgauth.c" (15 Jun 2014, 51517 Bytes) of package /linux/misc/old/delegate9.9.13.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dgauth.c" see the Fossies "Dox" file reference documentation.

    1 /*////////////////////////////////////////////////////////////////////////
    2 Copyright (c) 2003-2006 National Institute of Advanced Industrial Science and Technology (AIST)
    3 
    4 Permission to use this material for noncommercial and/or evaluation
    5 purpose, copy this material for your own use, and distribute the copies
    6 via publicly accessible on-line media, without fee, is hereby granted
    7 provided that the above copyright notice and this permission notice
    8 appear in all copies.
    9 AIST MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY OF THIS
   10 MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS", WITHOUT ANY EXPRESS
   11 OR IMPLIED WARRANTIES.
   12 /////////////////////////////////////////////////////////////////////////
   13 Content-Type:   program/C; charset=US-ASCII
   14 Program:        dgauth.c
   15 Author:         Yutaka Sato <ysato@delegate.org>
   16 Description:
   17 History:
   18         031115  extracted from delegated.c, access.c, ...
   19 //////////////////////////////////////////////////////////////////////#*/
   20 #include "file.h" /* 9.9.7 should be included first with -DSTAT64 */
   21 #include <sys/types.h>
   22 #include <sys/stat.h>
   23 #include "delegate.h"
   24 #include "param.h"
   25 #include "credhy.h"
   26 #include "auth.h"
   27 int serverPid();
   28 
   29 extern const char *MAP_AUTHSERV;
   30 char DGAUTHpro[] = "dgauth";
   31 char DGAUTHdom[] = "-dgauth";
   32 char DGAUTHadmdom[] = "-dgauth@admin";
   33 const char *DGAuthDFLT_realm = "-";
   34 int NONCE_TIMEOUT = 60;
   35 
   36 static const char *DGAuthHost;
   37 static int DGAuthPort;
   38 static struct { MStr(e_nonceKey,64); } nonceKey;
   39 #define nonceKey nonceKey.e_nonceKey
   40 static int xgetpass(PCStr(passspec),PVStr(pass))
   41 {   CStr(what,32);
   42     CStr(data,64);
   43     FILE *kfp;
   44 
   45     scan_field1(passspec,AVStr(what),sizeof(what),AVStr(data),sizeof(data));
   46     if( streq(what,"pass") ){
   47         strcpy(pass,data);
   48     }else
   49     if( streq(what,"file") ){
   50         if( kfp = fopen(data,"r") ){
   51             fgets(data,sizeof(data),kfp);
   52             fclose(kfp);
   53             linescanX(data,AVStr(pass),64);
   54         }else{
   55         }
   56     }else
   57     if( streq(what,"serv") ){
   58         DGAuthHost = "127.0.0.1";
   59         DGAuthPort = atoi(data);
   60     }else{
   61         return -1;
   62     }
   63     return 0;
   64 }
   65 
   66 /*
   67  * make the key reloadable on restart (by reboot, in an hour)
   68  * ignore it if something modified (DeleGate binary, the file, or the directory)
   69  */
   70 /*
   71 static void dumpCKeyKey(PCStr(path),PVStr(skey),int prev)
   72 */
   73 static void dumpCKeyKeyX(PCStr(opts),PCStr(param),PCStr(path),PVStr(skey),int prev)
   74 {   CStr(dir,1024);
   75     const char *dp;
   76     CStr(date,64);
   77     int now;
   78     CStr(cwd,1024);
   79 
   80     lineScan(path,dir);
   81     if( (dp = strrchr(dir,'/')) && dp != dir )
   82         truncVStr(dp);
   83     if( strchr(opts,'M') ){
   84         now = time(0) - prev*60;
   85         StrftimeLocal(AVStr(date),sizeof(date),"%y%m%d%H%M",now,0);
   86     }else{
   87     now = time(0) - prev*60*60;
   88     StrftimeLocal(AVStr(date),sizeof(date),"%y%m%d%H",now,0);
   89     }
   90     /*
   91     sprintf(skey,"%s.%x.%x",date,File_ctime(dir),(int)dumpCKeyKey);
   92     */
   93     /*
   94     sprintf(skey,"%s.%x.%lx",date,0,dumpCKeyKey);
   95     */
   96     if( streq(param,P_CRYPT) ){
   97     sprintf(skey,"%s.%x.%llx",date,0,p2llu(dumpCKeyKeyX));
   98     }else{
   99         IStr(xkey,1024);
  100         IStr(md5,64);
  101         sprintf(skey,"%s.%llx",date,p2llu(dumpCKeyKeyX));
  102         if( strchr(opts,'e') ){
  103             extern int environCRC;
  104             Xsprintf(TVStr(xkey),".%X",environCRC);
  105         }
  106         if( strchr(opts,'p') ){
  107             Xsprintf(TVStr(xkey),".%d",getppid());
  108         }
  109         if( strchr(opts,'t') ){
  110             Xsprintf(TVStr(xkey),".%d",file_ino(0));
  111         }
  112         if( strchr(opts,'w') ){
  113             CStr(cwd,1024);
  114             IGNRETS getcwd(cwd,sizeof(cwd));
  115             Xsprintf(TVStr(xkey),".%s",cwd);
  116         }
  117         if( xkey[0] ){
  118             toMD5(xkey,(char*)md5);
  119             Xsprintf(TVStr(skey),".%s",md5);
  120         }
  121     }
  122 }
  123 int getCKeySec(PCStr(param),PCStr(dom),PCStr(user),PVStr(ekey),int ksiz);
  124 /*
  125 void dumpCKeyPath(PVStr(path));
  126 */
  127 void dumpCKeyX(PCStr(opts),PCStr(param),PCStr(dom),PCStr(user),int force);
  128 void dumpCKey(int force)
  129 {
  130     dumpCKeyX("",P_CRYPT,"master","",force);
  131     dumpCKeyX("",P_PASSWD,"imp","",force);
  132     dumpCKeyX("",P_PASSWD,"ext","",force);
  133     dumpCKeyX("",P_PASSWD,"sudo","",force);
  134     dumpCKeyX("",P_PASSWD,"exec","",force);
  135 }
  136 void dumpCKeyPathX(PCStr(opts),PCStr(param),PCStr(dom),PCStr(user),PVStr(path));
  137 void dumpCKeyX(PCStr(opts),PCStr(param),PCStr(dom),PCStr(user),int force)
  138 {   CStr(path,256);
  139     CStr(ekey,256);
  140     CStr(cc,64);
  141     CStr(md5,64);
  142     CStr(skey,64);
  143     CStr(xpass,256);
  144     int elen,xlen;
  145     FILE *fp;
  146 
  147     if( force || getpid() == serverPid() )
  148     /*
  149     if( 0 < (elen = getCKey(AVStr(ekey),sizeof(ekey))) )
  150     */
  151     if( 0 < (elen = getCKeySec(param,dom,user,AVStr(ekey),sizeof(ekey))) )
  152     {
  153         /*
  154         dumpCKeyPath(AVStr(path));
  155         */
  156         dumpCKeyPathX(opts,param,dom,user,AVStr(path));
  157         if( !force /* not create_service() nor SIGHUP */
  158          && File_is(path)
  159          && File_mtime(path) == 1 /* set by set_utimes() bellow */
  160         ){
  161             /* don't overwrite new data by old one on TERMINATE */
  162             daemonlog("E","#### KEY DONT OVERWRITE %s\n",path);
  163         }else
  164         if( fp = dirfopen("CKey",AVStr(path),"w") ){
  165             chmod(path,0600);
  166             /*
  167             dumpCKeyKey(path,AVStr(skey),0);
  168             */
  169             dumpCKeyKeyX(opts,param,path,AVStr(skey),0);
  170             sprintf(cc,"%s.%s",skey,ekey);
  171             toMD5(cc,md5);
  172             xlen = aencrypty(skey,strlen(skey),ekey,elen,xpass);
  173             fprintf(fp,"%s %s\n",md5,xpass);
  174 /*
  175 fprintf(stderr,"#### DUMPED %s %d[%s %s] to %s\n",skey,elen,md5,xpass,path);
  176 */
  177             daemonlog("E","#### KEY %s=%s DUMPED %X TO %s\n",
  178                 param,dom,strCRC32(skey,strlen(skey)),path);
  179             fclose(fp);
  180             set_utimes(path,-1,1);
  181         }
  182         else{ /* new-140514a */
  183             int strls_unix(PCStr(path),PVStr(ls),int size);
  184             IStr(ls,1024);
  185 
  186             strls_unix(path,AVStr(ls),sizeof(ls));
  187             daemonlog("F","#### FATAL: cannot save CRYPT: %s\n",path);
  188             sv1log("#### CRYPT file: %s\n",ls);
  189         }
  190         bzero(ekey,sizeof(ekey));
  191     }
  192 }
  193 /*
  194 static int restoreCKey(PVStr(ekey),int esiz)
  195 */
  196 int restoreCKeyX(PCStr(opts),PCStr(param),PCStr(dom),PCStr(user),PVStr(ekey),int esiz)
  197 {   CStr(path,256);
  198     CStr(key,256);
  199     CStr(cc,64);
  200     CStr(md5,64);
  201     CStr(epass,256);
  202     CStr(xmd5,64);
  203     ACStr(skeys,2,64);
  204     int si,elen;
  205     FILE *fp;
  206 
  207     /*
  208     dumpCKeyPath(AVStr(path));
  209     */
  210     dumpCKeyPathX(opts,param,dom,user,AVStr(path));
  211     if( fp = fopen(path,"r") ){
  212         for( si = 0; si < 2; si++ )
  213             dumpCKeyKeyX(opts,param,path,EVStr(skeys[si]),si);
  214             /*
  215             dumpCKeyKey(path,EVStr(skeys[si]),si);
  216             */
  217         key[0] = 0;
  218         fgets(key,sizeof(key),fp);
  219         fclose(fp);
  220         if( strchr(opts,'L') == 0 )
  221         unlink(path);
  222 
  223         md5[0] = epass[0] = 0;
  224         Xsscanf(key,"%s %s",AVStr(md5),AVStr(epass));
  225 
  226         for( si = 0; si < 2; si++ ){
  227             const char *skey; /**/
  228             skey = skeys[si];
  229             elen = adecrypty(skey,strlen(skey),epass,strlen(epass),
  230                 (char*)ekey);
  231             sprintf(cc,"%s.%s",skey,ekey);
  232             toMD5(cc,xmd5);
  233 
  234 /*
  235 if( elen <= 0 )
  236 fprintf(stderr,"#### RESTORED %s %d[%s %s]\n",skey,elen,md5,epass);
  237 */
  238 
  239             /*
  240             sv1log("#### KEY RESTORED FROM %s\n",path);
  241             */
  242             daemonlog("E","#### KEY RESTORED %X FROM %s\n",
  243                 strCRC32(skey,strlen(skey)),path);
  244             if( streq(md5,xmd5) ){
  245                 return elen;
  246             }
  247         }
  248     }
  249     return 0;
  250 }
  251 
  252 /*
  253  * should be CRYPT=pass:word[:realm] ...
  254  */
  255 void setCKey(PCStr(ekey),int elen);
  256 void setCKeyP(PCStr(param),PCStr(dom),PCStr(user),PCStr(ekey),int elen);
  257 
  258 void scan_CRYPTX(Connection *Conn,int clnt,PCStr(opts),PCStr(param),PCStr(dom),PCStr(user));
  259 void scan_CRYPT(Connection *Conn,int clnt)
  260 {
  261     scan_CRYPTX(Conn,clnt,"",P_CRYPT,"master","");
  262 }
  263 
  264 typedef struct {
  265     const char *fcp_param;
  266     const char *fcp_dom;
  267     const char *fcp_user;
  268     const char *fcp_spec;
  269 } FcpArg;
  270 static FcpArg fcp1;
  271 static void fcp(Connection *Conn,PCStr(spec)){
  272     const char *sp;
  273 
  274     if( streq(fcp1.fcp_param,P_CRYPT) ){
  275         fcp1.fcp_spec = spec;
  276     }
  277     if( fcp1.fcp_dom && (sp = strheadstrX(spec,fcp1.fcp_dom,0)) ){
  278         if( strneq(sp,"::pass:",7) ){
  279             fcp1.fcp_spec = sp+2;
  280         }
  281         if( strneq(sp,":::",3) ){
  282             fcp1.fcp_spec = sp+2;
  283         }
  284     }
  285 }
  286 const char *getCKeyMainArg(Connection *Conn,PCStr(param),PCStr(dom),PCStr(user)){
  287     int ai;
  288     const char *dp;
  289 
  290     fcp1.fcp_param = param;
  291     fcp1.fcp_dom   = dom;
  292     fcp1.fcp_user  = user;
  293     fcp1.fcp_spec  = 0;
  294     for( ai = 1; ai < main_argc; ai++ ){
  295         if( dp = strheadstrX(main_argv[ai],param,0) )
  296         if( *dp == '=' ){
  297             fcp(Conn,dp+1);
  298             if( fcp1.fcp_spec != 0 )
  299                 return fcp1.fcp_spec;
  300         }
  301     }
  302     return 0;
  303 }
  304 int getCryptKeyMainArg(PCStr(param),PCStr(dom),PCStr(user),PVStr(ckey),int csiz){
  305     const char *ck;
  306     if( ck = getCKeyMainArg(MainConn(),param,dom,user) ){
  307         if( strneq(ck,":",1) ){
  308             strcpy(ckey,ck+1);
  309             return strlen(ckey);
  310         }
  311         if( strneq(ck,"pass:",5) ){
  312             strcpy(ckey,ck+5);
  313             return strlen(ckey);
  314         }
  315     }
  316     return -1;
  317 }
  318 
  319 const char *getCKeyArg(Connection *Conn,PCStr(param),PCStr(dom),PCStr(user)){
  320     fcp1.fcp_param = param;
  321     fcp1.fcp_dom   = dom;
  322     fcp1.fcp_user  = user;
  323     fcp1.fcp_spec  = 0;
  324     DELEGATE_scanEnv(Conn,param,fcp);
  325     if( fcp1.fcp_spec != 0 ){
  326         return fcp1.fcp_spec;
  327     }
  328     return 0;
  329 }
  330 int getCryptKeyTty(PCStr(param),PCStr(dom),PCStr(user),PVStr(ekey),int esiz){
  331     FILE *keyin = 0;
  332     const char *dp;
  333 
  334     if( !isatty(fileno(stdin)) ){
  335         if( isWindows() )
  336             /* should popup window ? */
  337             keyin = fopen("con","r");
  338         else    keyin = fopen("/dev/tty","r");
  339     }
  340     if( keyin == NULL ){
  341         if( !isatty(fileno(stdin)) && !isatty(fileno(stderr)) ){
  342             sv1log("ERROR: cannot get CRYPT value\n");
  343             return -1;
  344         }
  345         keyin = fdopen(fileno(stdin),"r");
  346     }
  347     setbuf(keyin,NULL);
  348 
  349     if( streq(param,P_CRYPT) ){
  350         fprintf(stderr,
  351         "**** Specify the key of encryption for '%s'\r\n",DGAUTHpro);
  352         fprintf(stderr,"**** CRYPT=pass:");
  353     }else{
  354         /*
  355         fprintf(stderr,"**** %s=%s:%s:pass:",param,dom,user);
  356         */
  357         fprintf(stderr,"**** %s=%s:%s::",param,dom,user);
  358     }
  359     fflush(stderr);
  360 
  361     strcpy(ekey,"");
  362     fgetsTimeout(BVStr(ekey),esiz,keyin,60);
  363 
  364     if( dp = strpbrk(ekey,"\r\n") )
  365         truncVStr(dp);
  366     /*
  367     fprintf(stderr,"\r\n");
  368     */
  369     return strlen(ekey);
  370 }
  371 
  372 void scan_CRYPTX(Connection *Conn,int clnt,PCStr(opts),PCStr(param),PCStr(dom),PCStr(user))
  373 {   const char *cryptspec;
  374     CStr(ekey,32);
  375     const char *dp;
  376     int elen,reset;
  377 
  378     reset = 0;
  379     /*
  380     if( cryptspec = DELEGATE_getEnv(P_CRYPT) ){
  381     */
  382     if( cryptspec = getCKeyArg(Conn,param,dom,user) ){
  383         if( cryptspec[0] == 0 ){
  384             /* maybe after "erestart" */
  385         }else
  386         if( strcmp(cryptspec,"pass:") == 0 ){
  387             reset = 1;
  388         }else{
  389             if( xgetpass(cryptspec,AVStr(ekey)) != 0 )
  390                 return;
  391             if( *ekey == 0 )
  392                 return;
  393             for( dp = cryptspec; *dp; dp++ )
  394             {
  395                 truncVStr(dp); /* hide commandline arg. */
  396             }
  397             goto GOT;
  398         }
  399     }
  400 
  401     /*
  402     elen = restoreCKey(AVStr(ekey),sizeof(ekey));
  403     */
  404     elen = restoreCKeyX(opts,param,dom,user,AVStr(ekey),sizeof(ekey));
  405     if( 0 < elen && !reset )
  406         goto GOT;
  407 
  408     if( clnt ){
  409         int sock,port;
  410         CStr(host,MaxHostNameLen);
  411         sock = DGAuth_port(0,AVStr(host),&port);
  412         if( 0 <= sock ){
  413             close(sock);
  414             return;
  415         }
  416     }
  417     if( getCryptKeyTty(param,dom,user,AVStr(ekey),sizeof(ekey)) < 0 )
  418         return;
  419 GOT:
  420     /*
  421     setCKey(ekey,strlen(ekey));
  422     */
  423     setCKeyP(param,dom,user,ekey,strlen(ekey));
  424     for( dp = ekey; *dp; dp++ )
  425         truncVStr(dp);
  426 }
  427 int getCryptKeyX(Connection *Conn,int which,PCStr(param),PCStr(dom),PCStr(user),PVStr(key),int siz){
  428     int len = -1;
  429 
  430     if( which & (1|4) ){
  431         const char *spec;
  432         if( spec = getCKeyMainArg(Conn,param,dom,user) ){
  433             if( strneq(spec,"pass:",5) && spec[5] != 0 ){
  434                 strcpy(key,spec+5);
  435                 len = strlen(key);
  436                 setCKeyP(param,dom,user,key,strlen(key));
  437         sv1log("{K}#a getCryptKeyX(%s=%s:%s)=%d\n",param,dom,user,len);
  438                 return len;
  439             }
  440         }
  441         len = getCryptKeyMainArg(param,dom,user,AVStr(key),siz);
  442         if( 0 <= len ){
  443         sv1log("{K}#a2 getCryptKeyX(%s=%s:%s)=%d\n",param,dom,user,len);
  444             setCKeyP(param,dom,user,key,strlen(key));
  445             return len;
  446         }
  447     }
  448     if( len <= 0 )
  449     if( which & 1 ){
  450         len = getCKeySec(param,dom,user,BVStr(key),siz);
  451         sv1log("{K}#A getCryptKeyX(%s=%s:%s)=%d\n",param,dom,user,len);
  452     }
  453     if( len <= 0 )
  454     if( which & 2 ){
  455         scan_CRYPTX(Conn,1,"",param,dom,user);
  456         len = getCKeySec(param,dom,user,BVStr(key),siz);
  457         sv1log("{K}#B getCryptKeyX(%s=%s:%s)=%d\n",param,dom,user,len);
  458     }
  459     if( len <= 0 )
  460     if( which & 4 ){
  461         len = getCryptKeyTty(param,dom,user,BVStr(key),siz);
  462         if( 0 < len ){
  463             setCKeyP(param,dom,user,key,strlen(key));
  464         }
  465     }
  466     return len;
  467 }
  468 
  469 #define EMSG(msg) { \
  470     daemonlog("F","!!!! FATAL: %s\n",msg); \
  471     fprintf(stderr,"!!!! FATAL: %s\n",msg); \
  472 }
  473 
  474 int scanAuthServPort(PCStr(domain),PVStr(serv));
  475 int checkEkey(Connection *Conn,int store,PCStr(proto),PCStr(host),int port,PCStr(ekey));
  476 
  477 int checkDGAuthConfig()
  478 {   int mx;
  479     const char *authservp;
  480     CStr(domain,MaxHostNameLen);
  481     CStr(msg,512);
  482     const char *dp;
  483     CStr(serv,64);
  484     CStr(ekey,64);
  485     int port,elen,rcode,ecode;
  486 
  487     rcode = 0;
  488     for( mx = 0; ; mx++ ){
  489         mx = scan_CMAPi(MAP_AUTHSERV,mx,&authservp);
  490         if( mx < 0 )
  491             break;
  492         if( strstr(authservp,DGAUTHdom) != authservp )
  493             continue;
  494         lineScan(authservp,domain);
  495         if( dp = strchr(domain,',') )
  496             truncVStr(dp);
  497         if( dp = strchr(domain,'@') )
  498             truncVStr(dp);
  499         if( dp = strchr(domain,'(') ){
  500             /* 9.8.2 -dgauth(userOrOptions) */
  501             truncVStr(dp);
  502         }
  503 
  504         port = scanAuthServPort(domain,AVStr(serv));
  505         if( serv[0] ){
  506             /* check connectivity */
  507             continue;
  508         }
  509         if( (dp = strchr(domain,'{')) && strtailchr(dp) == '}' ){
  510             /* v9.9.9 fix-140615e literal list -dgauth{user:pass} */
  511             /* is not in file. don't put error, don't erase CKey */
  512             continue;
  513         }
  514         elen = getCKey(AVStr(ekey),sizeof(ekey));
  515         if( elen <= 0 ){
  516             sprintf(msg,"CRYPT=pass:... is not specified.");
  517             EMSG(msg);
  518             rcode = -1;
  519             continue;
  520         }
  521         ecode = checkEkey(MainConn(),0,DGAUTHpro,domain,0,ekey);
  522         bzero(ekey,sizeof(ekey));
  523         if( ecode != 0 ){
  524             if( ecode == -AUTH_EBADDOMAIN )
  525                 sprintf(msg,"bad domain AUTHORIZER=%s",domain);
  526             else    sprintf(msg,"CRYPT=pass:... is wrong.");
  527             setCKey("",0);
  528             EMSG(msg);
  529             rcode = -1;
  530         }
  531     }
  532     return rcode;
  533 }
  534 int withAuthDigest(Connection *Conn,PVStr(authserv))
  535 {
  536     if( 0 <= find_CMAP(Conn,MAP_AUTHSERV,AVStr(authserv)) ){
  537         if( strncmp(authserv,DGAUTHdom,7) == 0 )
  538             return 1;
  539     }
  540     return 0;
  541 }
  542 
  543 static int found;
  544 int static isDGAdom(Connection *Conn,PCStr(dom))
  545 {
  546     if( strstr(dom,DGAUTHdom) == dom )
  547     if( dom[strlen(DGAUTHdom)] != '{' )
  548         /* with DGAuth which requires CRYPT passphrase */
  549         found = 1;
  550     return 0;
  551 }
  552 int withDGAuth(Connection *Conn)
  553 {
  554     found = 0;
  555     DELEGATE_scanEnv(Conn,P_AUTHORIZER,(scanPFUNCP)isDGAdom);
  556     if( found == 0 ){
  557         CStr(asv,256);
  558         if( getAdminAuthorizer(Conn,AVStr(asv),sizeof(asv),0) ){
  559             if( isinList(asv,DGAUTHdom) ){
  560                 found = 1;
  561             }
  562             /* asv might be like -dgauth.realm ... */
  563         }
  564     }
  565     if( found == 0 ){
  566         /* should check AUTHORIZER in MOUNTs ... */
  567     }
  568     return found;
  569 }
  570 
  571 FILE *fopen_DGAuth()
  572 {   int sock;
  573 
  574     if( DGAuthPort == 0 )
  575         return NULL;
  576     sock = client_open(DGAUTHpro,DGAUTHpro,DGAuthHost,DGAuthPort);
  577     if( 0 <= sock )
  578         return fdopen(sock,"r+");
  579     else    return NULL;
  580 }
  581 int DGAuth_port(int create,PVStr(host),int *portp)
  582 {   CStr(path,1024);
  583     CStr(lpath,1024);
  584     const char *dp;
  585     FILE *fp,*lfp;
  586     int sock,port;
  587 
  588     sprintf(path,"${ADMDIR}/authorizer/%s/port",DGAUTHdom);
  589     DELEGATE_substfile(AVStr(path),"",VStrNULL,VStrNULL,VStrNULL);
  590     sprintf(lpath,"%s.lock",path);
  591 
  592     if( create ){
  593         lfp = fopen(lpath,"w+");
  594         if( lfp == NULL || lock_exclusiveTO(fileno(lfp),1,NULL) != 0 ){
  595             if( lfp ) fclose(lfp);
  596             return -1;
  597         }
  598         fp = fopen(path,"w+");
  599         if( fp == NULL ){
  600             fp = dirfopen("DGAuth_port",AVStr(path),"w");
  601             if( fp == NULL ){
  602                 fclose(lfp);
  603                 return -1;
  604             }
  605         }
  606         sock = server_open(DGAUTHpro,CVStr("127.0.0.1"),0,10);
  607         if( sock < 0 ){
  608             fclose(lfp);
  609             fclose(fp);
  610             return -1;
  611         }
  612         strcpy(host,"127.0.0.1");
  613         *portp = port = sockPort(sock);
  614         fseek(fp,0,0);
  615         fprintf(fp,"%s:%d\n","127.0.0.1",port);
  616         fclose(fp);
  617         chmod(path,0600);
  618         fcloseFILE(lfp);
  619     }else{
  620         if( !File_is(lpath) ){
  621             /* no server */
  622             return -1;
  623         }
  624         lfp = fopen(lpath,"r");
  625         if( lfp == NULL || lock_sharedTO(fileno(lfp),1,NULL)==0 ){
  626             /* no active server locking it. */
  627             if( lfp ) fclose(lfp);
  628             return -1;
  629         }
  630         fclose(lfp);
  631 
  632         fp = fopen(path,"r");
  633         if( fp == NULL )
  634             return -1;
  635 
  636         setVStrEnd(host,0);
  637         fgets(host,256,fp);
  638         port = 0;
  639         if( dp = strchr(host,':') ){
  640             truncVStr(dp); dp++;
  641             port = atoi(dp);
  642         }
  643         sock = client_open(DGAUTHpro,DGAUTHpro,host,port);
  644         *portp = port;
  645         DGAuthHost = stralloc(host);
  646         DGAuthPort = port;
  647         fclose(fp);
  648     }
  649     return sock;
  650 }
  651 int connectDGAuth(PCStr(domain),FILE *sv[2])
  652 {   int sock,port;
  653     CStr(dom,MaxHostNameLen);
  654     CStr(host,MaxHostNameLen);
  655 
  656     lineScan(domain,dom);
  657     if( port = scanAuthServPort(dom,AVStr(host)) )
  658         sock = client_open(DGAUTHpro,DGAUTHpro,host,port);
  659     else    sock = DGAuth_port(0,AVStr(host),&port);
  660 
  661     if( 0 <= sock ){
  662         sv[0] = fdopen(sock,"r");
  663         sv[1] = fdopen(sock,"w");
  664         return 0;
  665     }
  666     return -1;
  667 }
  668 int remoteEditDGAuthUser(int com,PCStr(domain),PCStr(user),PCStr(pass))
  669 {   int sock;
  670     CStr(epass,64);
  671     CStr(resp,256);
  672     CStr(req,256);
  673     CStr(ereq,256);
  674     FILE *sv[2],*tc,*fc;
  675     Credhy K[1]; /**/
  676     int qlen;
  677 
  678     if( connectDGAuth(domain,sv) == 0 ){
  679         if( CredhyClientStart("CREDHY",K,sv[1],sv[0],200) < 0 ){
  680             fclose(sv[1]);
  681             fclose(sv[0]);
  682             return -AUTH_ENOSERV;
  683         }
  684         tc = sv[1];
  685         fc = sv[0];
  686         if( com == 'a' )
  687             sprintf(req,"ADD %s %s",user,pass);
  688         else    sprintf(req,"DEL %s %s",user,pass);
  689 
  690         CredhyAencrypt(K,req,AVStr(ereq),sizeof(ereq));
  691         fprintf(tc,"%s\r\n",ereq);
  692         fflush(tc);
  693         *resp = 0;
  694         fgets(resp,sizeof(resp),fc);
  695         fclose(fc);
  696         fclose(tc);
  697 
  698         fprintf(stderr,"%s\n",resp);
  699         if( strncmp(resp,"+OK ",4) == 0 )
  700             return 0;
  701         if( atoi(resp) == 200 )
  702             return 0;
  703         else    return -AUTH_ENOUSER;
  704     }
  705     return -AUTH_ENOSERV;
  706 }
  707 int remoteGetDigestPass(PCStr(host),PCStr(user),PVStr(spass))
  708 {   FILE *sv[2],*ts,*fs;
  709     CStr(req,256);
  710     CStr(ereq,256);
  711     CStr(resp,512);
  712     CStr(code,32);
  713     CStr(epass,512);
  714     int qlen,plen,len;
  715     Credhy K[1]; /**/
  716 
  717     plen = -1;
  718     if( connectDGAuth(host,sv) == 0 ){
  719         fs = sv[0];
  720         ts = sv[1];
  721         CredhyClientStart("CREDHY",K,sv[1],sv[0],200);
  722         sprintf(req,"GETPASS %s",user);
  723         CredhyAencrypt(K,req,AVStr(ereq),sizeof(ereq));
  724 
  725         fprintf(ts,"%s\r\n",ereq);
  726         fflush(ts);
  727         if( fgets(resp,sizeof(resp),fs) != NULL ){
  728             lineScan(wordScan(resp,code),epass);
  729             if( atoi(code) == 200 ){
  730             plen = CredhyAdecrypt(K,epass,AVStr(spass),sizeof(epass));
  731             }
  732         }
  733         fclose(ts);
  734         fclose(fs);
  735     }
  736     return plen;
  737 }
  738 
  739 /*
  740  * for -Fauth ... -dgauth
  741  */
  742 int getCRYPTkey(Connection *Conn,int clnt,PVStr(ckey),int ksiz)
  743 { 
  744     scan_CRYPT(Conn,clnt);
  745     return getCKey(AVStr(ckey),ksiz);
  746 }
  747 int getEKey(Connection *ctx,FILE *tc,int com,PCStr(proto),PCStr(host),PCStr(port),PCStr(user),PCStr(pass),PVStr(ekey))
  748 {   int elen;
  749 
  750     if( remoteEditDGAuthUser(com,host,user,pass) != -AUTH_ENOSERV )
  751         return 0;
  752     elen = getCRYPTkey(ctx,1,AVStr(ekey),128); /*ERR_sizeof(ekey));*/
  753     if( elen == 0 ){
  754         fprintf(tc,"-ERROR No Encryption Key\n");
  755         return 0;
  756     }
  757     if( checkEkey(ctx,1,proto,host,atoi(port),ekey) != 0 ){
  758         fprintf(tc,"-ERROR Bad Encryption Key\n");
  759         return 0;
  760     }
  761     return elen;
  762 }
  763 void showPass(Connection *Conn,FILE *out,PCStr(tmp),int com,PCStr(host),PCStr(user),PCStr(pass)){
  764     IStr(md5,128);
  765     IStr(epass,128);
  766     IStr(spass,128);
  767     int plen;
  768     int elen;
  769     IStr(ekey,128);
  770 
  771     Xsscanf(tmp,"%s %s",AVStr(md5),AVStr(epass));
  772     elen = getCRYPTkey(Conn,1,AVStr(ekey),sizeof(ekey));
  773     plen = adecrypty(ekey,elen,epass,strlen(epass),(char*)spass);
  774     fprintf(out,"Password: %s [%s]\n",epass,spass);
  775 }
  776 
  777 static int clockencdec(int enc,int clock)
  778 {   int crc,xclock;
  779 
  780     return clock;
  781 /*
  782     crc = NonceKeyCRC32();
  783     if( enc )
  784         xclock = (clock + crc) ^ crc;
  785     else    xclock = (clock ^ crc) - crc;
  786     if( crc & 1 )
  787         xclock = ~xclock;
  788     return xclock;
  789 */
  790 }
  791 
  792 void NonceKey(PVStr(key));
  793 void genNonce(Connection *Conn,PCStr(uri),PVStr(nonce),int clock)
  794 {   CStr(key,64);
  795     CStr(eclocks,64);
  796     CStr(nonce1,64);
  797     CStr(nonce2,64);
  798     CStr(nonce3,64);
  799     const char *dp;
  800     int eclock,crc;
  801 
  802     NonceKey(AVStr(key));
  803     sprintf(nonce1,"%x:%s",clock,key);
  804     toMD5(nonce1,nonce2);
  805     eclock = clockencdec(1,clock);
  806     sprintf(eclocks,"%x",eclock);
  807     crc = strCRC8(0,eclocks,strlen(eclocks));
  808     strreverse(eclocks);
  809     sprintf(nonce3,"%x.%s.%s",crc,eclocks,nonce2);
  810     str_to64(nonce3,strlen(nonce3),AVStr(nonce),64,1);
  811     if( dp = strpbrk(nonce,"\r\n") )
  812         truncVStr(dp);
  813 }
  814 static int scanNonceDate(PCStr(qnonce))
  815 {   int nlen,xcrc,crc,xclock;
  816     CStr(dqnonce,64);
  817     CStr(eclocks,64);
  818 
  819     nlen = str_from64(qnonce,strlen(qnonce),AVStr(dqnonce),sizeof(dqnonce));
  820     if( nlen < 32 ){
  821         sv1log("## DGAuth: Invalid Nonce Format: %s [%s]\n",
  822             qnonce,dqnonce);
  823         return -1;
  824     }
  825     xcrc = -1;
  826     eclocks[0] = 0;
  827     Xsscanf(dqnonce,"%x.%[^.]",&xcrc,AVStr(eclocks));
  828     strreverse(eclocks);
  829     crc = strCRC8(0,eclocks,strlen(eclocks));
  830     if( xcrc != crc ){
  831         sv1log("## DGAuth: Invalid Nonce Clock: %X %X %s %s\n",
  832             crc,xcrc,eclocks,qnonce);
  833         return -1;
  834     }
  835     xclock = 0;
  836     sscanf(eclocks,"%x",&xclock);
  837     return xclock;
  838 }
  839 
  840 int genDigestNonce(Connection *Conn,AuthInfo *ident,PCStr(uri),PVStr(nonce))
  841 {
  842     genNonce(Conn,uri,AVStr(nonce),time(0));
  843     return 1;
  844 }
  845 int genDigestResp(Connection *Conn,AuthInfo *ident,PVStr(xrealm),PCStr(uri),PVStr(nonce))
  846 {
  847     CStr(authserv,MaxAuthServLen);
  848 /*
  849 {   CStr(authserv,128);
  850 */
  851     const char *dp;
  852 
  853     /*
  854     if( getAdminAuthorizer(Conn,AVStr(authserv),sizeof(authserv),0) ){
  855     */
  856     if( (ClientFlags & PF_ADMIN_ON)
  857      && getAdminAuthorizer(Conn,AVStr(authserv),sizeof(authserv),0) ){
  858     }else
  859     if( getMountAuthorizer(Conn,AVStr(authserv),sizeof(authserv)) ){
  860     }else
  861     if( find_CMAP(Conn,MAP_AUTHSERV,AVStr(authserv)) < 0 )
  862         return 0;
  863     if( !strneq(authserv,DGAUTHdom,7) )
  864         return 0;
  865 
  866     setVStrEnd(xrealm,0);
  867     if( dp = strchr(authserv,'@') ){
  868         linescanX(dp+1,AVStr(ident->i_realm),sizeof(ident->i_realm));
  869         strcpy(xrealm,ident->i_realm);
  870     }
  871 
  872     if( dp = strchr(authserv,',') )
  873         truncVStr(dp);
  874 
  875     if( dp = strstr(authserv,"//") )
  876         truncVStr(dp);
  877 
  878     if( xrealm[0] == 0 )
  879     if( authserv[7] == '.' )
  880         strcpy(xrealm,authserv+8);
  881     else
  882     if( ClientFlags & PF_MITM_DO ){
  883         strcpy(xrealm,"MITM-proxy");
  884     }
  885     else    strcpy(xrealm,DGAuthDFLT_realm);
  886 
  887     genDigestNonce(Conn,ident,uri,AVStr(nonce));
  888     return 1;
  889 }
  890 
  891 void genDigestReq(AuthInfo *ident,PCStr(Method),PCStr(uri),PCStr(user),PCStr(pass),PCStr(realm),PCStr(nonce),PVStr(digest))
  892 {   CStr(HA1,64);
  893     CStr(HA2,64);
  894     CStr(digestr,64);
  895     MD5 *md5;
  896 
  897     md5 = newMD5();
  898     addMD5(md5,user,strlen(user));
  899     addMD5(md5,":",1);
  900     addMD5(md5,realm,strlen(realm));
  901     addMD5(md5,":",1);
  902     addMD5(md5,pass,strlen(pass));
  903     endMD5(md5,digestr);
  904     MD5toa(digestr,HA1);
  905 
  906     md5 = newMD5();
  907     addMD5(md5,Method,strlen(Method));
  908     addMD5(md5,":",1);
  909     addMD5(md5,uri,strlen(uri));
  910     endMD5(md5,digestr);
  911     MD5toa(digestr,HA2);
  912 
  913     md5 = newMD5();
  914     addMD5(md5,HA1,strlen(HA1));
  915     addMD5(md5,":",1);
  916 
  917     addMD5(md5,nonce,strlen(nonce));
  918     if( ident && streq(ident->i_qop,"auth") ){
  919     addMD5(md5,":",1);
  920     addMD5(md5,ident->i_nc,strlen(ident->i_nc));
  921     addMD5(md5,":",1);
  922     addMD5(md5,ident->i_cnonce,strlen(ident->i_cnonce));
  923     addMD5(md5,":",1);
  924     addMD5(md5,ident->i_qop,strlen(ident->i_qop));
  925     }
  926     addMD5(md5,":",1);
  927     addMD5(md5,HA2,strlen(HA2));
  928     endMD5(md5,digestr);
  929     MD5toa(digestr,(char*)digest);
  930 }
  931 
  932 int localGetDigestPass(Connection *Conn,PCStr(host),PCStr(user),PVStr(spass));
  933 int remoteHTTPreqDigest(FILE *afp,PCStr(user),PCStr(method),PCStr(uri),PCStr(realm),PCStr(nonce),PVStr(digest),AuthInfo *au);
  934 
  935 int getPassFromList(Connection *Conn,PCStr(list),PCStr(user),PVStr(pass)){
  936     char *uplist;
  937     const char *up;
  938     const char *pp;
  939     int igncase = 0;
  940 
  941     if( (uplist = strchr((char*)list,'{')) == 0 )
  942         return -1;
  943     if( strchr(uplist+1,'}') == 0 )
  944         return -1;
  945     for( up = uplist+1; *up; up++ ){
  946         if( pp = strheadstrX(user,up,igncase) ){
  947             if( *pp == ':' ){
  948                 wordscanY(pp+1,BVStr(pass),128,"^,}");
  949                 return strlen(pass);
  950             }
  951         }
  952         up = strpbrk(up,",}");
  953         if( *up != ',' )
  954             break;
  955     }
  956     return -1;
  957 }
  958 static scanListFunc fup(PCStr(userpass),PCStr(user),int ulen,PVStr(pass)){
  959     if( strncmp(userpass,user,ulen) == 0 ){
  960         if( userpass[ulen] == ':' ){
  961             strcpy(pass,userpass+ulen+1);
  962             return 1;
  963         }
  964     }
  965     return 0;
  966 }
  967 int getListPass(PCStr(dom),PCStr(user),PVStr(spass)){
  968     const char *dp;
  969     CStr(list,1024);
  970     int ulen;
  971 
  972     if( (dp = strchr(dom,'{')) == 0 )
  973         return 0;
  974     strcpy(list,dp+1);
  975     if( dp = strchr(list,'}') )
  976         truncVStr(dp);
  977     ulen = strlen(user);
  978     if( scan_commaListL(list,0,scanListCall fup,user,ulen,AVStr(spass)) ){
  979         return 1;
  980     }
  981     return 0;
  982 }
  983 
  984 /*
  985 int UpdateSession(AuthInfo *ident,int expire);
  986 */
  987 int UpdateSession(Connection *Conn,AuthInfo *ident,int expire);
  988 int HTTP_authorize_Digest(Connection *Conn,AuthInfo *ident,PCStr(dom),PCStr(user),PCStr(dpass),PVStr(serv),int port)
  989 {   int sock,xclock,clock,now,age,plen,rcode;
  990     FILE *tsfs;
  991     CStr(spass,128);
  992     CStr(nonce,64);
  993     CStr(digest,64);
  994     const char *uri = ident->i_path;
  995     const char *realm = ident->i_realm;
  996     const char *Method = ident->i_meth;
  997     const char *qnonce = ident->i_nonce;
  998     const char *xrealm;
  999     const char *vrealm;
 1000 
 1001     if( uri == 0 ){
 1002         uri = "";
 1003         porting_dbg("## DGAuth: authrize_Digest: no URI set");
 1004         /* it might be Proxy-Authorization for CONNECT */
 1005     }
 1006 
 1007     if( vrealm = strchr(dom,'@') ){ /* -dgauth[.realm]@vrealm */
 1008         truncVStr(vrealm);
 1009         vrealm++;
 1010         xrealm = vrealm;
 1011     }else
 1012     if( xrealm = strchr(dom,'.') )
 1013         xrealm++;
 1014     else    xrealm = DGAuthDFLT_realm;
 1015     if( ident->i_xrealm ){
 1016         xrealm = ident->i_xrealm;
 1017     }
 1018     if( strcmp(xrealm,realm) != 0 ){
 1019         sv1log("## DGAuth: Invalid Realm: %s / %s\n",realm,xrealm);
 1020         if( ClientFlags & PF_MITM_DO ){
 1021             /* mixed HTTP proxy / HTTPS mitm proxy */
 1022         }else
 1023         return -1;
 1024     }
 1025 
 1026     xclock = scanNonceDate(qnonce);
 1027     if( xclock == -1 )
 1028         return -1;
 1029 
 1030     clock = clockencdec(0,xclock);
 1031     now = time(0);
 1032     age = now - clock;
 1033 
 1034     genNonce(Conn,uri,AVStr(nonce),clock);
 1035     if( strcmp(qnonce,nonce) != 0 ){
 1036         sv1log("## DGAuth: Invalid Nonce: Q=%s G=%s\n",qnonce,nonce);
 1037         return -1;
 1038     }
 1039 
 1040     if( strchr(dom,'{') && strchr(dom,'}') )
 1041     if( getListPass(dom,user,AVStr(spass)) ){
 1042         plen = strlen(spass);
 1043         genDigestReq(ident,Method,uri,user,spass,realm,nonce,AVStr(digest));
 1044         goto VALIDATE;
 1045     }
 1046 
 1047     if( serv[0] != 0 && port != 0 )
 1048     /* explicit remote server */
 1049     {
 1050         sock = client_open(DGAUTHpro,DGAUTHpro,serv,port);
 1051         if( sock < 0 ){
 1052             sv1log("## DGAuth: Cannot Connext %s server [%s:%d]\n",
 1053                 DGAUTHpro,serv,port);
 1054             ident->i_error |= AUTH_ENOSERV;
 1055             return -1;
 1056         }
 1057         tsfs = fdopen(sock,"r+");
 1058         goto REMOTE;
 1059     }
 1060 
 1061     plen = localGetDigestPass(Conn,dom,user,AVStr(spass));
 1062     if( 0 < plen )
 1063     /* self */
 1064     {
 1065         genDigestReq(ident,Method,uri,user,spass,realm,nonce,AVStr(digest));
 1066         bzero(spass,sizeof(spass));
 1067         goto VALIDATE;
 1068     }
 1069 
 1070     /* find implicit local sever */
 1071     if( plen <= 0 )
 1072     {
 1073         tsfs = fopen_DGAuth();
 1074         if( tsfs == NULL ){
 1075             sock = DGAuth_port(0,AVStr(serv),&port);
 1076             if( 0 <= sock ){
 1077                 tsfs = fdopen(sock,"r+");
 1078             }
 1079         }
 1080         if( tsfs != NULL )
 1081             goto REMOTE;
 1082 
 1083         if( plen == -AUTH_ENOUSER )
 1084             ident->i_error |= AUTH_ENOUSER;
 1085         else{
 1086             ident->i_error |= AUTH_ENOSERV;
 1087             sv1log("## DGAuth: No server\n");
 1088         }
 1089         return -1;
 1090     }
 1091 
 1092 REMOTE:
 1093     rcode = remoteHTTPreqDigest(tsfs,user,Method,uri,realm,nonce,AVStr(digest),ident);
 1094     fclose(tsfs);
 1095     if( rcode != 0 ){
 1096         sv1log("## DGAuth: Error from Server\n");
 1097         return -1;
 1098     }
 1099 
 1100 VALIDATE:
 1101 /*
 1102  fprintf(stderr,"#Q nonce=%s age=%d realm=[%s][%s]\n",nonce,age,realm,xrealm);
 1103 */
 1104     if( strcmp(digest,dpass) != 0 ){
 1105         sv1log("## DGAuth: Invalid Nonce (%s)\n",dom);
 1106         if( strcmp(dom,"-dgauth.-crypt") == 0 ){
 1107             ident->i_stat |= AUTH_GEN;
 1108         }
 1109         return -1;
 1110     }
 1111     if( age < 0 ){
 1112         sv1log("## DGAuth: Valid bad Future Nonce: age=%d %s\n",
 1113             age,nonce);
 1114         return -1;
 1115     }
 1116     if( NONCE_TIMEOUT < age ){
 1117         sv1log("## DGAuth: Valid bad Stale Nonce: age=%d %s\n",
 1118             age,nonce);
 1119         ident->i_error |= AUTH_ESTALE;
 1120         return -1;
 1121     }
 1122 
 1123     /*
 1124     if( UpdateSession(ident,AuthTimeout(Conn)) < 0 ){
 1125     */
 1126     if( UpdateSession(Conn,ident,AuthTimeout(Conn)) < 0 ){
 1127         return -1;
 1128     }
 1129 
 1130     sv1log("## DGAuth: Valid Digest, age=%d %s\n",age,nonce);
 1131     return 0;
 1132 }
 1133 int authAPOP(Connection *Conn,PCStr(domain),PCStr(user),PCStr(seed),PVStr(mpass))
 1134 {   CStr(digest,64);
 1135     CStr(pass,256);
 1136     const char *pp;
 1137     int plen;
 1138     MD5 *md5;
 1139 
 1140     plen = getDigestPass(domain,user,AVStr(pass));
 1141     sv1log("authAPOP(%s,%s) len=%d\n",user,seed,plen);
 1142     if( plen < 0 ){
 1143         sv1log("cannot get password for %s\n",user);
 1144         return -1;
 1145     }
 1146 
 1147     md5 = newMD5();
 1148     addMD5(md5,seed,strlen(seed));
 1149     addMD5(md5,pass,strlen(pass));
 1150     endMD5(md5,digest);
 1151     MD5toa(digest,(char*)mpass);
 1152 
 1153     for( pp = pass; *pp; pp++ )
 1154         *(char*)pp = 0;
 1155     return 0;
 1156 }
 1157 
 1158 /*
 1159  * check the correctness of encryption key
 1160  * store the encryption key at the first store
 1161  */
 1162 int authEdit(Connection *Conn,int detail,FILE *tc,int com,PCStr(proto),PCStr(host),int port,PCStr(user),PCStr(pass),PCStr(ekey),int expire);
 1163 void DGAuth_file(PVStr(path),PVStr(uh),PCStr(proto),PCStr(user),PCStr(host),int port);
 1164 
 1165 int checkEkey(Connection *Conn,int store,PCStr(proto),PCStr(host),int port,PCStr(ekey))
 1166 {   CStr(path,1024);
 1167     CStr(uh,1024);
 1168     CStr(pw_md5,256);
 1169     CStr(md5,64);
 1170     CStr(amd5,64);
 1171     FILE *fp;
 1172 
 1173     DGAuth_file(AVStr(path),AVStr(uh),proto,"-ADMIN-",host,port);
 1174     if( fp = fopen(path,"r") ){
 1175         *pw_md5 = 0;
 1176         fgets(pw_md5,sizeof(pw_md5),fp);
 1177         fclose(fp);
 1178         wordScan(pw_md5,md5);
 1179         toMD5(ekey,amd5);
 1180         if( streq(md5,amd5) )
 1181             return 0;
 1182         else    return -AUTH_EBADCRYPT;
 1183     }
 1184     if( !store ){
 1185         return -AUTH_EBADDOMAIN;
 1186     }
 1187     authEdit(Conn,1,stderr,'a',proto,host,port,"-ADMIN-",ekey,"",0);
 1188     return 0;
 1189 }
 1190 int putDigestPass(FILE *fp,PCStr(fmt),PCStr(host),PCStr(user))
 1191 {   CStr(pass,64);
 1192 
 1193     if( getDigestPass(host,user,AVStr(pass)) < 0 )
 1194         return -1;
 1195     fprintf(fp,fmt,pass);
 1196     bzero(pass,sizeof(pass));
 1197     return 0;
 1198 }
 1199 int getDigestPassX(Connection *Conn,PCStr(host),PCStr(user),PVStr(spass))
 1200 {   int plen;
 1201 
 1202     /*
 1203     if( plen = remoteGetDigestPass(host,user,AVStr(spass)) )
 1204     */
 1205     if( 0 < (plen = remoteGetDigestPass(host,user,AVStr(spass))) )
 1206         return plen;
 1207     else    return localGetDigestPass(Conn,host,user,AVStr(spass));
 1208 }
 1209 static int getCKeyX(Connection *Conn,PCStr(host),PVStr(ekey),int size)
 1210 {   int elen;
 1211 
 1212     elen = getCKey(AVStr(ekey),size);
 1213     if( elen <= 0 ){
 1214         sv1log("## DGAuth: Decryption key is not available.\n");
 1215         return -AUTH_ENOSERV;
 1216     }
 1217     if( checkEkey(Conn,0,DGAUTHpro,host,0,ekey) != 0 ){
 1218         sv1log("## DGAuth: Decryption key is not correct.\n");
 1219         sv1log("## DGAuth: disable the Decryption key.\n");
 1220         setCKey("",0);
 1221         return -AUTH_ENOSERV;
 1222     }
 1223     return elen;
 1224 }
 1225 
 1226 /* the pass is encrypted string of user */
 1227 int genPass(Connection *Conn,PCStr(host),PCStr(user),PVStr(pass))
 1228 {   int elen,plen;
 1229     CStr(ekey,64);
 1230 
 1231     elen = getCKeyX(Conn,host,AVStr(ekey),sizeof(ekey));
 1232     if( elen < 0 ){
 1233         sv1log("### genPass: CANT GET CKey\n");
 1234         setVStrEnd(pass,0);
 1235         return elen;
 1236     }
 1237     plen = aencrypty(ekey,elen,user,strlen(user),pass);
 1238     setVStrEnd(pass,4);
 1239     bzero(ekey,sizeof(ekey));
 1240     return plen;
 1241 }
 1242 
 1243 int localGetDigestPass(Connection *Conn,PCStr(host),PCStr(user),PVStr(spass))
 1244 {   CStr(uh,256);
 1245     CStr(epath,1024);
 1246     const char *dp;
 1247     CStr(dpass,64);
 1248     CStr(epass,128);
 1249     CStr(xpass,256);
 1250     CStr(pass_md5,64);
 1251     CStr(ekey,128);
 1252     FILE *afp;
 1253     int elen,plen,ki;
 1254     IStr(xhost,1024);
 1255 
 1256     if( 0 <= (plen = getPassFromList(Conn,host,user,BVStr(spass))) ){
 1257         return plen;
 1258     }
 1259 
 1260     setVStrEnd(spass,0);
 1261     if( host == 0 || *host == 0 )
 1262         host = DGAUTHdom;
 1263 
 1264     if( strncmp(host,"-dgauth.-crypt",14) == 0 ){
 1265         plen = genPass(Conn,host,user,AVStr(spass));
 1266         sv1log("#### -dgauth.-crypt: user=%s pass=%s\n",user,spass);
 1267         return plen;
 1268     }
 1269 
 1270     DGAuth_file(AVStr(epath),AVStr(uh),DGAUTHpro,user,host,0);
 1271 
 1272     afp = fopen(epath,"r");
 1273     if( afp == NULL ){
 1274         sv1log("## DGAuth: No such user [%s] in %s auth.\n",user,host);
 1275         return -AUTH_ENOUSER;
 1276     }
 1277     fgets(xpass,sizeof(xpass),afp);
 1278     fclose(afp);
 1279     dp = wordScan(xpass,dpass);
 1280     dp = wordScan(dp,epass);
 1281 
 1282     /*
 1283     elen = getCKey(AVStr(ekey),sizeof(ekey));
 1284     if( elen <= 0 ){
 1285         sv1log("## DGAuth: Decryption key is not available.\n");
 1286         return -AUTH_ENOSERV;
 1287     }
 1288     if( checkEkey(Conn,0,DGAUTHpro,host,0,ekey) != 0 ){
 1289         sv1log("## DGAuth: Decryption key is not correct.\n");
 1290         sv1log("## DGAuth: disable the Decryption key.\n");
 1291         setCKey("",0);
 1292         return -AUTH_ENOSERV;
 1293     }
 1294     */
 1295     elen = getCKeyX(Conn,host,AVStr(ekey),sizeof(ekey));
 1296     if( elen < 0 )
 1297         return elen;
 1298 
 1299     plen = adecrypty(ekey,elen,epass,strlen(epass),(char*)spass);
 1300     for( ki = 0; ki < elen; ki++ )
 1301         setVStrEnd(ekey,ki);
 1302     toMD5(spass,pass_md5);
 1303     if( strcmp(dpass,pass_md5) != 0 ){
 1304         sv1log("## DGAuth: Decryption key is wrong.\n");
 1305         return -AUTH_ENOSERV;
 1306     }
 1307     return plen;
 1308 }
 1309 
 1310 /*
 1311  * HTTP user method uri realm nonce
 1312  */
 1313 int remoteHTTPreqDigest(FILE *afp,PCStr(user),PCStr(method),PCStr(uri),PCStr(realm),PCStr(nonce),PVStr(digest),AuthInfo *au)
 1314 {   CStr(resp,256);
 1315     CStr(code,32);
 1316     const char *dp;
 1317     const char *proto;
 1318     CStr(erealm,256);
 1319 
 1320     if( streq(au->i_qop,"auth") )
 1321         proto = "HTTPX";
 1322     else    proto = "HTTP";
 1323 
 1324     url_escapeX(realm,AVStr(erealm),sizeof(erealm)," \t\r\n","");
 1325     sv1log("DGAuth-CL: %s %s %s %s %s [%s %s %s] %s\r\n",
 1326         proto,user,nonce,erealm,method,
 1327         au->i_qop,au->i_cnonce,au->i_nc,uri);
 1328     fprintf(afp,"%s %s %s %s %s ",proto,user,nonce,erealm,method);
 1329     if( streq(au->i_qop,"auth") ){
 1330         fprintf(afp,"%s %s %s ",au->i_qop,au->i_cnonce,au->i_nc);
 1331     }
 1332     fprintf(afp,"%s\r\n",uri);
 1333     fflush(afp);
 1334     if( fgets(resp,sizeof(resp),afp) != NULL ){
 1335         dp = wordScan(resp,code);
 1336         if( atoi(code) == 200 ){
 1337             wordscanX(dp,AVStr(digest),64);
 1338             return 0;
 1339         }
 1340     }
 1341     return -1;
 1342 }
 1343 static int servHTTPreqDigest(Connection *Conn,FILE *tc,PCStr(com),PCStr(arg),PVStr(digest))
 1344 {   const char *av[16]; /**/
 1345     const char *user;
 1346     const char *method;
 1347     const char *uri;
 1348     const char *realm;
 1349     const char *nonce;
 1350     CStr(spass,128);
 1351     int nac,ac,ai,plen;
 1352     AuthInfo au;
 1353 
 1354     sv1log("DGAuth-SV: HTTP %s\r\n",arg);
 1355     if( streq(com,"HTTPX") )
 1356         nac = 8;
 1357     else    nac = 5;
 1358     ac = list2vect(arg,' ',nac,av);
 1359 
 1360     if( ac != nac ){
 1361         fprintf(tc,"501 BAD arg. count(%d/%d)\r\n",ac,nac);
 1362         return -1;
 1363     }
 1364     ai = 0;
 1365     user = av[ai++];
 1366     nonce = av[ai++];
 1367     realm = av[ai++];
 1368     method = av[ai++];
 1369 
 1370     bzero(&au,sizeof(AuthInfo));
 1371     if( 5 < ac ){
 1372         wordScan(av[ai++],au.i_qop);
 1373         wordScan(av[ai++],au.i_cnonce);
 1374         wordScan(av[ai++],au.i_nc);
 1375     }
 1376 
 1377     uri = av[ai++];
 1378 
 1379     plen = localGetDigestPass(Conn,"",user,AVStr(spass));
 1380     if( plen <= 0 ){
 1381         fprintf(tc,"502 BAD user\r\n");
 1382         return -1;
 1383     }
 1384     genDigestReq(&au,method,uri,user,spass,realm,nonce,AVStr(digest));
 1385     bzero(spass,sizeof(spass));
 1386     return 0;
 1387 }
 1388 
 1389 int service_DGAuth(Connection *Conn)
 1390 {   int elen,olen;
 1391     CStr(req,1024);
 1392     CStr(com,64);
 1393     CStr(arg,1024);
 1394     CStr(ekey,64);
 1395     CStr(md5,64);
 1396     const char *dp;
 1397     CStr(out,256);
 1398     FILE *fc,*tc;
 1399     const char *av[8]; /**/
 1400     int ac;
 1401     CStr(digest,128);
 1402     int rcode;
 1403     Credhy K[1]; /**/
 1404     int xskey;
 1405 
 1406     if( !source_permitted(Conn) ){
 1407         CStr(shost,MaxHostNameLen);
 1408         getClientHostPort(Conn,AVStr(shost));
 1409         daemonlog("F","E-P: No permission: \"%s\" is not allowed (%s)\n",
 1410             shost,Conn->reject_reason);
 1411         return -1;
 1412     }
 1413 
 1414     fc = fdopen(FromC,"r");
 1415     tc = fdopen(ToC,"w");
 1416     elen = getCKey(AVStr(ekey),sizeof(ekey));
 1417     if( elen == 1 && *ekey == '\n' ){
 1418         *ekey = 0;
 1419         elen = 0;
 1420     }
 1421 
 1422     xskey = 0;
 1423     for(;;){
 1424         fflush(tc);
 1425         if( fgets(req,sizeof(req),fc) == NULL ){
 1426             break;
 1427         }
 1428         if( dp = strpbrk(req,"\r\n") )
 1429             truncVStr(dp);
 1430         if( xskey ){
 1431             olen = CredhyAdecrypt(K,req,AVStr(req),sizeof(req));
 1432             if( olen < 0 ){
 1433                 continue;
 1434             }
 1435         }
 1436         dp = wordScan(req,com);
 1437         dp = lineScan(dp,arg);
 1438         sv1log("[%s] elen=%d\n",com,elen);
 1439 
 1440         if( strcaseeq(com,"CREDHY") ){
 1441             CredhyServerStart(com,K,tc,fc,arg,200,500);
 1442             xskey = 1;
 1443             continue;
 1444         }
 1445         if( strcaseeq(com,"END") ){
 1446             fprintf(tc,"200 bye.\r\n");
 1447             break;
 1448         }
 1449 
 1450         if( elen == 0 ){
 1451             fprintf(tc,"500 encryption key is not set\n");
 1452             continue;
 1453         }
 1454         if( strcaseeq(com,"HTTP") || strcaseeq(com,"HTTPX") ){
 1455             rcode = servHTTPreqDigest(Conn,tc,com,arg,AVStr(digest));
 1456             if( rcode == 0 )
 1457                 fprintf(tc,"200 %s\r\n",digest);
 1458             continue;
 1459         }
 1460         if( strcaseeq(com,"APOP") ){
 1461             /* APOP user seed */
 1462             const char *user;
 1463             const char *seed;
 1464             ac = list2vect(arg,' ',2,av);
 1465             if( ac != 2 ){
 1466                 fprintf(tc,"501 BAD arg. count(%d)\r\n",ac);
 1467                 continue;
 1468             }
 1469             user = av[0];
 1470             seed = av[1];
 1471             rcode = authAPOP(NULL,"",user,seed,AVStr(digest));
 1472             if( rcode == 0 )
 1473                 fprintf(tc,"200 %s\r\n",digest);
 1474             else    fprintf(tc,"500 internal error.\r\n");
 1475             continue;
 1476         }
 1477 
 1478 
 1479         if( xskey == 0 ){
 1480             fprintf(tc,"500 communication is not encrypted.\r\n");
 1481             continue;
 1482         }
 1483         if( strcaseeq(com,"CLR") ){
 1484             if( streq(arg,ekey) ){
 1485                 *ekey = 0;
 1486                 elen = 0;
 1487                 fprintf(tc,"200 OK, reset.\r\n");
 1488             }else{
 1489                 fprintf(tc,"500 BAD, unmatch.\r\n");
 1490             }
 1491         }
 1492         else
 1493         if( strcaseeq(com,"KEY") ){
 1494             if( elen != 0 ){
 1495                 fprintf(tc,"400 set already.\r\n");
 1496                 continue;
 1497             }
 1498             toMD5(arg,md5);
 1499             /*
 1500             if( !streq(md5,) ){
 1501                 fprintf(tc,"400\r\n");
 1502                 continue;
 1503             }
 1504             */
 1505             setCKey(arg,strlen(arg));
 1506             elen = getCKey(AVStr(ekey),sizeof(ekey));
 1507             fprintf(tc,"200 OK, set(%d).\r\n",elen);
 1508         }
 1509         else
 1510         if( strcaseeq(com,"DEL") ){
 1511             const char *user;
 1512             const char *pass;
 1513             ac = list2vect(arg,' ',2,av);
 1514             if( ac != 2 ){
 1515                 fprintf(tc,"501 BAD arg. count(%d)\r\n",ac);
 1516                 continue;
 1517             }
 1518             user = av[0];
 1519             pass = av[1];
 1520             authEdit(Conn,0,tc,'d',DGAUTHpro,DGAUTHdom,0,user,pass,ekey,0);
 1521             fprintf(tc,"200 removed\r\n");
 1522         }
 1523         else
 1524         if( strcaseeq(com,"ADD") ){
 1525             /* ADD user pass [dom] */
 1526             const char *user;
 1527             const char *pass;
 1528             const char *realm;
 1529             ac = list2vect(arg,' ',3,av);
 1530             if( ac < 2 ){
 1531                 fprintf(tc,"501 BAD arg. count(%d)\r\n",ac);
 1532                 continue;
 1533             }
 1534             user = av[0];
 1535             pass = av[1];
 1536             if( 2 < ac )
 1537                 realm = av[2];
 1538             else    realm = DGAUTHdom;
 1539             sv1log("## DGAuth: %s %s *** %s\n",com,user,realm);
 1540 
 1541             rcode =
 1542             authEdit(Conn,0,tc,'a',DGAUTHpro,realm,0,user,pass,ekey,0);
 1543             if( rcode == 0 )
 1544                 fprintf(tc,"200 added\r\n");
 1545             else    fprintf(tc,"500 error\r\n");
 1546         }
 1547         else
 1548         if( strcaseeq(com,"AUTH") ){
 1549             /* AUTH dom user pass */
 1550         }
 1551         else
 1552         if( strcaseeq(com,"GETPASS") ){
 1553             /* GETPASS user [dom] */
 1554             const char *user;
 1555             const char *dom;
 1556             CStr(spass,256);
 1557 
 1558             ac = list2vect(arg,' ',2,av);
 1559             if( ac == 0 ){
 1560                 fprintf(tc,"500 GETPASS user [domain]\r\n");
 1561                 continue;
 1562             }
 1563             user = av[0];
 1564             if( 1 < ac )
 1565                 dom = av[1];
 1566             else    dom = "";
 1567             olen = localGetDigestPass(Conn,dom,arg,AVStr(spass));
 1568             CredhyAencrypt(K,spass,AVStr(arg),sizeof(arg));
 1569             bzero(spass,sizeof(spass));
 1570             fprintf(tc,"200 %s\r\n",arg);
 1571             sv1log("## 200 %s\n",arg);
 1572         }
 1573         else
 1574         if( strcaseeq(com,"ENC") ){
 1575             olen = aencrypty(ekey,elen,arg,strlen(arg),out);
 1576             fprintf(tc,"200 %d %s\r\n",olen,out);
 1577         }
 1578         else
 1579         if( strcaseeq(com,"DEC") ){
 1580             if( 0 ){
 1581                 olen = adecrypty(ekey,elen,arg,strlen(arg),out);
 1582                 fprintf(tc,"200 %d %s\r\n",olen,out);
 1583             }else{
 1584                 fprintf(tc,"403 Forbidden\r\n");
 1585             }
 1586         }
 1587         else
 1588         {
 1589             break;
 1590         }
 1591     }
 1592     fclose(tc);
 1593     fclose(fc);
 1594     return 0;
 1595 }
 1596 
 1597 /*
 1598  *
 1599  */
 1600 typedef struct {
 1601  unsigned int   o_start;
 1602  unsigned short o_count;
 1603  unsigned short o_realmCRC; /* CRC32&0xFFFF of the realm */
 1604  unsigned short o_pid;
 1605  unsigned short o_serno;
 1606 } Opaque;
 1607 #define OPQSIZE (sizeof(Opaque)+2)
 1608 #define o_serno_multi(Op)   ((char*)(&Op[1]))[0]
 1609 #define o_reqserno(Op)      ((char*)(&Op[1]))[1]
 1610 
 1611 void printOpaque(PVStr(opqs),Opaque *Op)
 1612 {   CStr(st,64);
 1613     CStr(ser,32);
 1614 
 1615     StrftimeLocal(AVStr(st),sizeof(st),"%y%m%d-%H%M%S",Op->o_start,0);
 1616     sprintf(ser,"%d+%d",Op->o_serno,o_serno_multi(Op));
 1617     if( o_reqserno(Op) )
 1618         Xsprintf(TVStr(ser),"+%d",o_reqserno(Op));
 1619     sprintf(opqs,"%s.%d.%s.%d",st,Op->o_pid,ser,Op->o_count);
 1620 }
 1621 extern int CHILD_SERNO;
 1622 extern int CHILD_SERNO_MULTI;
 1623 void genSessionID(Connection *Conn,PVStr(opaque),int inc)
 1624 {   CStr(opq,128);
 1625     CStr(opqs,128);
 1626     CStr(key,64);
 1627     const char *op;
 1628     int olen,startu;
 1629     Opaque Ops[2],*Op = &Ops[0];
 1630     const char *realm = ClientAuth.i_realm;
 1631     int realmcrc;
 1632 
 1633     NonceKey(AVStr(key));
 1634     bzero(Op,OPQSIZE);
 1635     if( opaque[0] ){
 1636         olen = adecrypty(key,strlen(key),opaque,strlen(opaque),opq);
 1637         if( olen == OPQSIZE ){
 1638             bcopy(opq,Op,OPQSIZE);
 1639         }
 1640         if( Op->o_pid != 0 && Op->o_start != 0 ){
 1641 /*
 1642             printOpaque(AVStr(opqs),Op);
 1643 fprintf(stderr,"#### GET OPAQ %s %s\n",opqs,opaque);
 1644 */
 1645         }
 1646     }
 1647     realmcrc = 0xFFFF & strCRC32(realm,strlen(realm));
 1648     Op->o_realmCRC = realmcrc;
 1649     if( Op->o_pid == 0 || Op->o_start == 0 ){
 1650         Op->o_pid = serverPid();
 1651         Op->o_start = time(0);
 1652         Op->o_serno = CHILD_SERNO;
 1653         o_serno_multi(Op) = CHILD_SERNO_MULTI;
 1654         o_reqserno(Op) = RequestSerno;
 1655     }
 1656     Op->o_count += inc;
 1657 
 1658     olen = aencrypty(key,strlen(key),(char*)Op,OPQSIZE,opaque);
 1659     printOpaque(AVStr(opqs),Op);
 1660     if( Op->o_count == 0 ){
 1661         daemonlog("F","NewSession %s\n",opqs);
 1662     }
 1663 /*
 1664 fprintf(stderr,"#### NEW OPAQ %s %s\n",opqs,opaque);
 1665 */
 1666 }
 1667 int UpdateSession(Connection *Conn,AuthInfo *ident,int expire){
 1668 /*
 1669 int UpdateSession(AuthInfo *ident,int expire){
 1670     Opaque Op;
 1671     */
 1672     Opaque Ops[2],*Op = &Ops[0]; /* v9.9.9 fix-140613b */
 1673     CStr(opq,128);
 1674     refQStr(iopq,ident->i_opaque);
 1675     const char *realm = ident->i_realm;
 1676     int olen;
 1677     CStr(key,64);
 1678     int now;
 1679     int age;
 1680     int realmCRC;
 1681 
 1682     NonceKey(AVStr(key));
 1683     olen = adecrypty(key,strlen(key),iopq,strlen(iopq),opq);
 1684     if( olen == OPQSIZE ){
 1685         bcopy(opq,Op,OPQSIZE);
 1686         now = time(0);
 1687         realmCRC = 0xFFFF&strCRC32(realm,strlen(realm));
 1688         sv1log("Session: age=%d/%d cnt=%d pid=%d.%d %X/%X\n",
 1689             now-Op->o_start,expire,Op->o_count,Op->o_pid,Op->o_serno,
 1690             Op->o_realmCRC,realmCRC);
 1691         if( expire <= 0 ){
 1692             return 0;
 1693         }
 1694         age = now - Op->o_start;
 1695         if( realmCRC == Op->o_realmCRC ){
 1696             if( age <= expire ){
 1697                 return 0;
 1698             }
 1699         }
 1700         Op->o_start = now;
 1701         Op->o_pid = serverPid();
 1702         Op->o_serno = CHILD_SERNO;
 1703         Op->o_count += 1;
 1704         Op->o_realmCRC = realmCRC;
 1705         o_serno_multi(Op) = CHILD_SERNO_MULTI;
 1706         o_reqserno(Op) = RequestSerno;
 1707         aencrypty(key,strlen(key),(char*)Op,OPQSIZE,iopq);
 1708 
 1709         /*
 1710         bcopy(opq,&Op,OPQSIZE);
 1711         now = time(0);
 1712         realmCRC = 0xFFFF&strCRC32(realm,strlen(realm));
 1713         sv1log("Session: age=%d/%d cnt=%d pid=%d.%d %X/%X\n",
 1714             now-Op.o_start,expire,Op.o_count,Op.o_pid,Op.o_serno,
 1715             Op.o_realmCRC,realmCRC);
 1716         if( expire <= 0 ){
 1717             return 0;
 1718         }
 1719         age = now - Op.o_start;
 1720         if( realmCRC == Op.o_realmCRC ){
 1721             if( age <= expire ){
 1722                 return 0;
 1723             }
 1724         }
 1725         Op.o_start = now;
 1726         Op.o_pid = serverPid();
 1727         Op.o_serno = CHILD_SERNO;
 1728         Op.o_count += 1;
 1729         Op.o_realmCRC = realmCRC;
 1730         aencrypty(key,strlen(key),(char*)&Op,OPQSIZE,iopq);
 1731         */
 1732         return -1;
 1733     }
 1734     clearVStr(ident->i_opaque);
 1735     return -1;
 1736 }
 1737 int decrypt_opaque(PCStr(opaque),PVStr(opqs))
 1738 {   CStr(opq,128);
 1739     CStr(key,64);
 1740     int olen;
 1741     Opaque Ops[2],*Op = &Ops[0];
 1742 
 1743     NonceKey(AVStr(key));
 1744     olen = adecrypty(key,strlen(key),opaque,strlen(opaque),opq);
 1745     if( olen == OPQSIZE ){
 1746         bcopy(opq,Op,OPQSIZE);
 1747         printOpaque(AVStr(opqs),Op);
 1748         return olen;
 1749     }else{
 1750         setVStrEnd(opqs,0);
 1751         return 0;
 1752     }
 1753 }
 1754 
 1755 
 1756 /*
 1757  * a key to encrypt opaque or session-Id
 1758  */
 1759 void NonceKey(PVStr(key))
 1760 {   CStr(dir,1024);
 1761     CStr(path,1024);
 1762     CStr(skey,256);
 1763     FILE *fp;
 1764 
 1765     if( nonceKey[0] ){
 1766         strcpy(key,nonceKey);
 1767         return;
 1768     }
 1769 
 1770     strcpy(dir,"${ADMDIR}/secret");
 1771     DELEGATE_substfile(AVStr(dir),"",VStrNULL,VStrNULL,VStrNULL);
 1772     sprintf(path,"%s/%s",dir,"noncekey");
 1773 
 1774     if( !File_is(path) ){
 1775         if( fp = dirfopen("NonceKey",AVStr(path),"w") ){
 1776             sv1log("#### NonceKey created: %s\n",path);
 1777             fprintf(fp,"%d%d",getpid(),itime(0));
 1778             fclose(fp); 
 1779             chmod(dir,0700);
 1780             chmod(path,0400);
 1781         }
 1782     }
 1783     skey[0] = 0;
 1784     if( fp = fopen(path,"r") ){
 1785         sprintf(skey,"%d.%d.",File_ctime(dir),File_mtime(path));
 1786         Xfgets(TVStr(skey),sizeof(skey)-strlen(skey),fp);
 1787         fclose(fp);
 1788     }
 1789     toMD5(skey,(char*)key);
 1790     strcpy(nonceKey,key);
 1791 }
 1792 int NonceKeyCRC32()
 1793 {   CStr(key,64);
 1794     int crc;
 1795 
 1796     NonceKey(AVStr(key));
 1797     crc = strCRC32(key,strlen(key));
 1798     return crc;
 1799 }
 1800 int NonceKeyCRC8()
 1801 {   CStr(key,64);
 1802     int crc;
 1803 
 1804     NonceKey(AVStr(key));
 1805     crc = strCRC8(0,key,strlen(key));
 1806     return crc;
 1807 }
 1808 
 1809 int getCreySalt(PVStr(str));
 1810 int creyInt32(int val,int dec){
 1811     CStr(b,8);
 1812     const unsigned char *u = (const unsigned char*)b;
 1813     int xval;
 1814     CStr(saltstr,128);
 1815 
 1816     getCreySalt(AVStr(saltstr));
 1817     setVStrElem(b,0,val>>24);
 1818     setVStrElem(b,1,val>>16);
 1819     setVStrElem(b,2,val>>8);
 1820     setVStrElem(b,3,val);
 1821     if( dec )
 1822         CreyDecrypts(saltstr,strlen(saltstr),AVStr(b),4);
 1823     else    CreyEncrypts(saltstr,strlen(saltstr),AVStr(b),4);
 1824     xval = (u[0]<<24) | (u[1]<<16) | (u[2]<<8) | u[3];
 1825     return xval;
 1826 }
 1827 
 1828 int enBase32(PCStr(src),int sbits,PVStr(dst),int dsiz);
 1829 int deBase32(PCStr(src),int slen,PVStr(dst),int dsiz);
 1830 
 1831 int makeAdminKey(PCStr(from),PVStr(key),int siz){
 1832     CStr(addr,1024);
 1833     MD5 *md5;
 1834     CStr(md5b,32);
 1835 
 1836     CStr(saltstr,128);
 1837     getCreySalt(AVStr(saltstr));
 1838 
 1839     RFC822_addresspartX(from,AVStr(addr),sizeof(addr));
 1840     strtolower(addr,addr);
 1841     md5 = newMD5();
 1842     addMD5(md5,saltstr,strlen(saltstr));
 1843     addMD5(md5,"",1);
 1844     addMD5(md5,addr,strlen(addr));
 1845     endMD5(md5,md5b);
 1846     enBase32(md5b,8*16,AVStr(key),siz);
 1847     return 0;
 1848 }
 1849 int (*MIME_makeAdminKey)(PCStr(from),PVStr(key),int siz) = makeAdminKey;
 1850 
 1851 /* Finger print of an Email address */
 1852 int makeEmailFP(PVStr(ocrc),PCStr(addr)){
 1853     int crc;
 1854     CStr(bi,8);
 1855     CStr(ba,16);
 1856     int icrc;
 1857 
 1858     crc = creyInt32(strCRC32(addr,strlen(addr)),0);
 1859     setVStrElem(bi,0,crc>>24);
 1860     setVStrElem(bi,1,crc>>16);
 1861     setVStrElem(bi,2,crc>>8);
 1862     setVStrElem(bi,3,crc);
 1863     icrc = creyInt32(strCRC32(bi,4),0);
 1864     setVStrElem(bi,4,(0x7 & icrc) << 5);
 1865     enBase32(bi,35,AVStr(ba),sizeof(ba));
 1866     strcpy(ocrc,ba);
 1867     return 0;
 1868 }
 1869 int (*MIME_makeEmailFP)(PVStr(ocrc),PCStr(addr)) = makeEmailFP;
 1870 
 1871 int makeEmailCX(PVStr(ocrc),PCStr(wf),PCStr(addr)){
 1872     CStr(fmt,128);
 1873     int crc;
 1874     int len;
 1875 
 1876     sprintf(fmt,"%%%sX",wf);
 1877     crc = creyInt32(strCRC32(addr,strlen(addr)),0);
 1878     sprintf(ocrc,fmt,crc);
 1879     if( len = atoi(wf) ){
 1880         if( len < strlen(ocrc) ) 
 1881             setVStrEnd(ocrc,len);
 1882     }
 1883     return 0;
 1884 }
 1885 int (*MIME_makeEmailCX)(PVStr(ocrc),PCStr(wf),PCStr(addr)) = makeEmailCX;
 1886 
 1887 /*########################################################################
 1888  *
 1889  * HTTPCONF=cryptCookie[:listOfDomAttrs[/cryptOptions][:cryptKey[:CMAP]]]
 1890  * cryptKey %P -- the password for AUTHORIZER
 1891  * cryptOptions: prefix, expire, host-match, port-match,
 1892  *               proxy-match, client-host-match, ...
 1893  *
 1894  * listOfDomAttrs = key1@dom1,{key21,key22}@{dom21,dom22}
 1895  * host-match={exact|domain|any}
 1896  */
 1897 int getParamX(PVStr(params),PCStr(name),PVStr(val),int siz,int del,int cookie);
 1898 /*
 1899 static const char *rewcPfx = "DG_";
 1900 */
 1901 static const char *rewcPfx = "";
 1902 static const char *rewcAttrs;
 1903 static const char *rewcEKey;
 1904 static int rewcHosts;
 1905 static const char *delcAttrs;
 1906 
 1907 void setupDeleteCookie(PCStr(value)){
 1908     delcAttrs = stralloc(value);
 1909 }
 1910 void setupCryptCookie(PCStr(value)){
 1911     CStr(attrs,1024);
 1912     CStr(ckey,1024);
 1913     CStr(cmap,1024);
 1914 
 1915     truncVStr(attrs);
 1916     truncVStr(cmap);
 1917     truncVStr(ckey);
 1918 
 1919     Xsscanf(value,"%[^:]:%[^:]:%s",AVStr(attrs),AVStr(ckey),AVStr(cmap));
 1920     rewcAttrs = stralloc(attrs);
 1921     rewcEKey = stralloc(ckey);
 1922 }
 1923 
 1924 static scanListFunc dommatch1(PCStr(dom1),PCStr(host),int port){
 1925     const char *dp;
 1926     if( dom1[0] == '.' ){
 1927         if( strcaseeq(host,dom1+1) ){
 1928             return 2;
 1929         }
 1930         if( dp = strcasestr(host,dom1) ){
 1931             if( dp[strlen(dom1)] == 0 ){
 1932                 return 3;
 1933             }
 1934         }
 1935     }else{
 1936         if( strcaseeq(dom1,host) ){
 1937             return 4;
 1938         }
 1939     }
 1940     return 0;
 1941 }
 1942 static int dommatch(Connection *Conn,PCStr(rdom),PCStr(attrn)){
 1943     int isin;
 1944     if( rdom[0] == 0 ){
 1945         return 1;
 1946     }
 1947     isin=scan_commaListL(rdom,0,scanListCall dommatch1,DST_HOST,DST_PORT);
 1948 
 1949 if( lSECRET() )
 1950 fprintf(stderr,"--[%s:%d] [%s]@[%s] ISIN=%d\n",
 1951 DST_HOST,DST_PORT,attrn,rdom,isin);
 1952 
 1953     return isin;
 1954 }
 1955 
 1956 int getrewCookie(Connection *Conn,PCStr(rewcAttrs),PCStr(pfx),PVStr(cookie),PVStr(attrv),int size,PVStr(attrn),PVStr(rdom),PVStr(ekey),int esiz){
 1957     const char *alist;
 1958     refQStr(dp,attrn);
 1959     int off;
 1960     const char *a1;
 1961     CStr(an,128);
 1962 
 1963     if( rewcAttrs == 0 )
 1964         return 0;
 1965 
 1966     alist = rewcAttrs;
 1967     if( pfx && *pfx ){
 1968         strcpy(attrn,pfx);
 1969         off = strlen(pfx);
 1970     }else   off = 0;
 1971 
 1972     while( alist && *alist ){
 1973         alist = scan_ListElem1(alist,',',DVStr(attrn,off));
 1974         if( attrn[0] == 0 )
 1975             break;
 1976         if( dp = strchr(attrn,'@') ){
 1977             setVStrEnd(dp,0);
 1978             strcpy(rdom,dp+1);
 1979             if( lSECRET() ){
 1980  fprintf(stderr,"--[%s:%d] [%s]@[%s]\n",DST_HOST,DST_PORT,attrn,rdom);
 1981             }
 1982             if( !dommatch(Conn,rdom,attrn) ){
 1983                 continue;
 1984             }
 1985         }else{
 1986             setVStrEnd(rdom,0);
 1987         }
 1988 
 1989         /* should be replaced with scan_ListElem1L() ... */
 1990         if( attrn[0] == '{' && strtailchr(attrn) == '}' ){
 1991             ovstrcpy((char*)attrn,attrn+1);
 1992             setVStrEnd(attrn,strlen(attrn)-1);
 1993         }
 1994         a1 = attrn;
 1995         strcpy(an,attrn);
 1996         while( *a1 ){
 1997             a1 = scan_ListElem1(a1,',',DVStr(an,off));
 1998             if( an[0] == 0 )
 1999                 break;
 2000             if(getParamX(BVStr(cookie),an,BVStr(attrv),size,1,1)){
 2001                 strcpy(attrn,an);
 2002                 strfConnX(Conn,rewcEKey,AVStr(ekey),esiz);
 2003                 return 1;
 2004             }
 2005         }
 2006     }
 2007     return 0;
 2008 }
 2009 
 2010 void encryptCookie1(Connection *Conn,PVStr(cookie),PCStr(oattr),PCStr(attrn),PCStr(ekey)){
 2011     CStr(nattr,4096);
 2012     CStr(oa,4096);
 2013     CStr(xa,4096);
 2014     int oalen;
 2015     int crc;
 2016     CStr(dom,MaxHostNameLen);
 2017     CStr(path,1024);
 2018 
 2019     getParamX(BVStr(cookie),"domain",AVStr(dom),sizeof(dom),0,1);
 2020     if( dom[0] == 0 )
 2021         strcpy(dom,"=");
 2022     strcpy(path,"/");
 2023     sprintf(oa,"%s:%s:%s:%d:%s",dom,path,DST_HOST,DST_PORT,oattr);
 2024     oalen = strlen(oa);
 2025 
 2026     crc = CreyEncrypts(ekey,strlen(ekey),AVStr(oa),strlen(oa));
 2027     strtoHex(oa,oalen,AVStr(xa),sizeof(xa));
 2028     sprintf(nattr,"%s%s=%X.%s;",rewcPfx,attrn,crc,xa);
 2029     Strins(AVStr(cookie),nattr);
 2030     sv1log("#### Encrypt-Cookie: %s\n",attrn);
 2031 }
 2032 void encryptCookie(Connection *Conn,PVStr(cookie)){
 2033     CStr(oa,4096);
 2034     CStr(an,128);
 2035     CStr(dom,256);
 2036     CStr(ek,128);
 2037     int na;
 2038 
 2039     if( lSECRET() )
 2040     fprintf(stderr,"<<<<<<<<< %s\nSet-Cookie: %s\n",DST_HOST,cookie);
 2041 
 2042     for( na = 0; na < 10; na++ ){
 2043         if( getrewCookie(Conn,rewcAttrs,"",BVStr(cookie),AVStr(oa),sizeof(oa),AVStr(an),AVStr(dom),AVStr(ek),sizeof(ek)) == 0 )
 2044             break;
 2045         encryptCookie1(Conn,BVStr(cookie),oa,an,ek);
 2046         if( strlen(rewcPfx) == 0 ){
 2047             break;
 2048         }
 2049     }
 2050 
 2051     if( lSECRET() )
 2052     fprintf(stderr,">>>>>>>>> %s\nSet-Cookie: %s\n",DST_HOST,cookie);
 2053 }
 2054 
 2055 int hextoStr(PCStr(hex),PVStr(bin),int siz);
 2056 void decryptCookie1(Connection *Conn,PVStr(cookie),PCStr(oattr),PCStr(attrn),PCStr(rdom),PCStr(ekey)){
 2057     CStr(chost,MaxHostNameLen);
 2058     int cport;
 2059     CStr(oa,4096);
 2060     CStr(nattr,4096);
 2061     CStr(xa,4096);
 2062     int xalen;
 2063     int ocrc;
 2064     int crc;
 2065     const char *dattrn = attrn+strlen(rewcPfx);
 2066     CStr(dom,MaxHostNameLen);
 2067     CStr(path,256);
 2068 
 2069     ocrc = -1;
 2070     truncVStr(oa);
 2071     Xsscanf(oattr,"%X.%s",&ocrc,AVStr(oa));
 2072 
 2073     xalen = hextoStr(oa,AVStr(xa),sizeof(xa));
 2074     setVStrEnd(xa,xalen);
 2075     crc = CreyDecrypts(ekey,strlen(ekey),AVStr(xa),xalen);
 2076 
 2077     if( crc != ocrc ){
 2078         daemonlog("F","## Decrypt-Cookie: CRC error: %X %X [%s]\n",
 2079             ocrc,crc,attrn);
 2080         return;
 2081     }
 2082     if( Xsscanf(xa,"%[^:]:%[^:]:%[^:]:%d:%[^\n]",AVStr(dom),AVStr(path),AVStr(chost),&cport,AVStr(oa)) == 5 ){
 2083         if( dom[0] ){
 2084             if( streq(dom,"=") ){
 2085                 strcpy(dom,chost);
 2086             }
 2087             if( !dommatch(Conn,dom,attrn) ){
 2088                 LSEC("## Decrypt-Cookie: domain[%s] != %s:%d\n",
 2089                     dom,DST_HOST,DST_PORT);
 2090  fprintf(stderr,"## Decrypt-Cookie: ERROR %s:%d != %s@%s:%d(%s)\n",
 2091     DST_HOST,DST_PORT,attrn,chost,cport,dom);
 2092                 return;
 2093             }
 2094         }
 2095         if( !strcaseeq(DST_HOST,chost) ){
 2096             if( dommatch(Conn,rdom,attrn) ){
 2097                 LSEC("## Decrypt-Cookie: %s <= %s ALLOW\n",
 2098                     chost,dom);
 2099             }else{
 2100  fprintf(stderr,"## Decrypt-Cookie: ERROR %s:%d != %s@%s:%d(%s)[%s]\n",
 2101     DST_HOST,DST_PORT,attrn,chost,cport,dom,rdom);
 2102                 LSEC("## Decrypt-Cookie: [%s][%s] != %s:%d\n",
 2103                     chost,rdom,DST_HOST,DST_PORT);
 2104                 return;
 2105             }
 2106         }
 2107         LSEC("## Decrypt-Cookie: %s[%s] %s\n",chost,DST_HOST,attrn);
 2108         if( lSECRET() ){
 2109  fprintf(stderr,"## Decrypt-Cookie: OK %s:%d == %s@%s:%d(%s)[%s]\n",
 2110             DST_HOST,DST_PORT,attrn,chost,cport,dom,rdom);
 2111         }
 2112         sprintf(nattr,"%s=%s;",dattrn,oa);
 2113         Strins(AVStr(cookie),nattr);
 2114     }
 2115     else{
 2116         daemonlog("F","## Decrypt-Cookie: BAD FORM[%s]=%s\n",attrn,xa);
 2117     }
 2118 }
 2119 void decryptCookie(Connection *Conn,PVStr(cookie)){
 2120     CStr(oa,4096);
 2121     CStr(an,128);
 2122     CStr(dom,256);
 2123     CStr(ek,128);
 2124     int na;
 2125 
 2126     if( lSECRET() )
 2127     fprintf(stderr,"<<<<<<<<< %s\nCookie: %s\n",DST_HOST,cookie);
 2128 
 2129     if( strlen(rewcPfx) )
 2130     for( na = 0; na < 10; na++ ){
 2131         const char *dattrn;
 2132         CStr(da,4096);
 2133         dattrn = an + strlen(rewcPfx);
 2134         if( getParamX(BVStr(cookie),dattrn,AVStr(da),sizeof(da),1,1) ){
 2135         }
 2136     }
 2137     for( na = 0; na < 10; na++ ){
 2138         if( getrewCookie(Conn,rewcAttrs,rewcPfx,AVStr(cookie),AVStr(oa),sizeof(oa),AVStr(an),AVStr(dom),AVStr(ek),sizeof(ek)) == 0 ){
 2139             break;
 2140         }
 2141         decryptCookie1(Conn,BVStr(cookie),oa,an,dom,ek);
 2142         if( strlen(rewcPfx) == 0 ){
 2143             break;
 2144         }
 2145     }
 2146     for( na = 0; na < 10; na++ ){
 2147         if( getrewCookie(Conn,delcAttrs,"",AVStr(cookie),AVStr(oa),sizeof(oa),AVStr(an),AVStr(dom),AVStr(ek),sizeof(ek)) == 0 ){
 2148             break;
 2149         }
 2150     }
 2151     if( lSECRET() )
 2152     fprintf(stderr,">>>>>>>>> %s\nCookie: %s\n",DST_HOST,cookie);
 2153 }