Back to index

nordugrid-arc-nox  1.1.0~rc6
GlobusSigningPolicy.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <iostream>
00006 #include <fstream>
00007 #include <string>
00008 #include <list>
00009 
00010 #include <arc/Logger.h>
00011 #include <arc/ArcRegex.h>
00012 
00013 #include <openssl/x509.h>
00014 
00015 #include "GlobusSigningPolicy.h"
00016 
00017 namespace Arc {
00018 
00019 static Logger& logger = Logger::getRootLogger();
00020 
00021 const char access_id[]       = "access_id_";
00022 const char positive_rights[] = "pos_rights";
00023 const char negative_rights[] = "neg_rights";
00024 const char globus_id[]       = "globus";
00025 const char sign_id[]         = "CA:sign";
00026 const char conditions_id[]   = "cond_";
00027 const char policy_suffix[]   = ".signing_policy";
00028 
00029 static void get_line(std::istream& in,std::string& s) {
00030   for(;;) {
00031     s.resize(0);
00032     if(in.fail() || in.eof()) return;
00033     getline(in,s);
00034     std::string::size_type p;
00035     p=s.find_first_not_of(" \t");
00036     if(p != std::string::npos) s=s.substr(p);
00037     if((!s.empty()) && (s[0] != '#')) break;
00038   };
00039   return;
00040 }
00041 
00042 static void get_word(std::string& s,std::string& word) {
00043   std::string::size_type w_s;
00044   std::string::size_type w_e;
00045   word.resize(0);
00046   w_s=s.find_first_not_of(" \t");
00047   if(w_s == std::string::npos) { s.resize(0); return; };
00048   if(s[w_s] == '\'') {
00049     w_e=s.find('\'',++w_s);
00050   } else if(s[w_s] == '"') {
00051     w_e=s.find('"',++w_s);
00052   } else {
00053     w_e=s.find_first_of(" \t",w_s);
00054   };
00055   if(w_e == std::string::npos) w_e=s.length();
00056   word=s.substr(w_s,w_e-w_s);
00057   if((s[w_e] == '\'') || (s[w_e] == '"')) ++w_e;
00058   w_s=s.find_first_not_of(" \t",w_e);
00059   if(w_s == std::string::npos) w_s=w_e;
00060   s=s.substr(w_s);
00061   return;
00062 }
00063 
00064 static bool get_id(std::string& s,std::string& ca_subject) {
00065   std::string id;
00066   ca_subject.resize(0);
00067   get_word(s,id);
00068   if(id.empty()) return true;
00069   if(id.compare(0,strlen(access_id),access_id) != 0) {
00070     logger.msg(WARNING,"Was expecting %s at the beginning of \"%s\"",access_id,id);
00071     return false;
00072   };
00073   id=id.substr(strlen(access_id));
00074   if(id != "CA") { 
00075     logger.msg(WARNING,"We only support CAs in Globus signing policy - %s is not supported",id);
00076     return false;
00077   };
00078   get_word(s,id);
00079   if(id != "X509") {
00080     logger.msg(WARNING,"We only support X509 CAs in Globus signing policy - %s is not supported",id);
00081     return false;
00082   };
00083   get_word(s,ca_subject);
00084   if(ca_subject.empty()) {
00085     logger.msg(WARNING,"Missing CA subject in Globus signing policy");
00086     return false;
00087   };
00088   return true;
00089 }
00090 
00091 static bool get_rights(std::string& s) {
00092   std::string id;
00093   get_word(s,id);
00094   if(id == negative_rights) {
00095     logger.msg(WARNING,"Negative rights are not supported in Globus signing policy");
00096     return false;
00097   };
00098   if(id != positive_rights) {
00099     logger.msg(WARNING,"Unknown rights in Globus signing policy - %s",id);
00100     return false;
00101   };
00102   get_word(s,id);
00103   if(id != globus_id) {
00104     logger.msg(WARNING,"Only globus rights are supported in Globus signing policy - %s is not supported",id);
00105     return false;
00106   };
00107   get_word(s,id);
00108   if(id != sign_id) {
00109     logger.msg(WARNING,"Only signing rights are supported in Globus signing policy - %s is not supported",id);
00110     return false;
00111   };
00112   return true;
00113 }
00114 
00115 static bool get_conditions(std::string s,std::list<std::string>& patterns) {
00116   std::string id;
00117   patterns.resize(0);
00118   get_word(s,id);
00119   if(id.empty()) return true;
00120   if(id.compare(0,strlen(conditions_id),conditions_id) != 0) {
00121     logger.msg(WARNING,"Was expecting %s at the beginning of \"%s\"",conditions_id,id);
00122     return false;
00123   };
00124   id=id.substr(strlen(conditions_id));
00125   if(id != "subjects") {
00126     logger.msg(WARNING,"We only support subjects conditions in Globus signing policy - %s is not supported",id);
00127     return false;
00128   };
00129   get_word(s,id);
00130   if(id != globus_id) {
00131     logger.msg(WARNING,"We only support globus conditions in Globus signing policy - %s is not supported",id);
00132     return false;
00133   };
00134   std::string subjects;
00135   get_word(s,subjects);
00136   if(subjects.empty()) {
00137     logger.msg(WARNING,"Missing condition subjects in Globus signing policy");
00138     return false;
00139   };
00140   std::string subject;
00141   for(;;) {
00142     get_word(subjects,subject);
00143     if(subject.empty()) break;
00144     patterns.push_back(subject);
00145   };
00146   return true;
00147 }
00148 
00149 static bool match_all(const std::string& issuer_subject,const std::string& subject,const std::string policy_ca_subject,std::list<std::string> policy_patterns) {
00150   if(issuer_subject == policy_ca_subject) {
00151     std::list<std::string>::iterator pattern = policy_patterns.begin();
00152     for(;pattern!=policy_patterns.end();++pattern) {
00153       std::string::size_type p = 0;
00154       for(;;) {
00155         p=pattern->find('*',p);
00156         if(p == std::string::npos) break;
00157         pattern->insert(p,"."); p+=2;
00158       };
00159       (*pattern)="^"+(*pattern)+"$";
00160       RegularExpression re(*pattern);
00161       bool r = re.match(subject);
00162       if(r) return true;
00163     };
00164   };
00165   return false;
00166 }
00167 
00168 static void X509_NAME_to_string(std::string& str,const X509_NAME* name) {
00169   str.resize(0);
00170   if(name == NULL) return;
00171   char* s = X509_NAME_oneline((X509_NAME*)name,NULL,0);
00172   if(s) {
00173     str=s;
00174     OPENSSL_free(s);
00175   };
00176   return;
00177 }
00178 
00179 bool match_globus_policy(std::istream& in,const X509_NAME* issuer_subject,const X509_NAME* subject) {
00180   std::string issuer_subject_str;
00181   std::string subject_str;
00182   std::string s;
00183   std::string policy_ca_subject;
00184   std::list<std::string> policy_patterns;
00185   bool rights_defined = false;
00186   bool failure = false;
00187   X509_NAME_to_string(issuer_subject_str,issuer_subject);
00188   X509_NAME_to_string(subject_str,subject);
00189   for(;;) {
00190     get_line(in,s);
00191     if(s.empty()) break;
00192     if(s.compare(0,strlen(access_id),access_id) == 0) {
00193       if((!policy_ca_subject.empty()) && (rights_defined) && (!failure)) {
00194         bool r = match_all(issuer_subject_str,subject_str,policy_ca_subject,policy_patterns);
00195         if(r) return true;
00196       };
00197       policy_ca_subject.resize(0);
00198       policy_patterns.resize(0);
00199       failure=false; rights_defined=false;
00200       if(!get_id(s,policy_ca_subject)) failure=true;
00201     } else if((s.compare(0,strlen(positive_rights),positive_rights) == 0) ||
00202               (s.compare(0,strlen(positive_rights),negative_rights) == 0)) {
00203       if(!get_rights(s)) {
00204         failure=true;
00205       } else {
00206         rights_defined=true;
00207       };
00208     } else if(s.compare(0,strlen(conditions_id),conditions_id) == 0) {
00209       if(!get_conditions(s,policy_patterns)) failure=true;
00210     } else {
00211       logger.msg(WARNING,"Unknown element in Globus signing policy");
00212       failure=true;
00213     };
00214   };
00215   if((!policy_ca_subject.empty()) && (rights_defined) && (!failure)) {
00216     bool r = match_all(issuer_subject_str,subject_str,policy_ca_subject,policy_patterns);
00217     if(r) return true;
00218   };
00219   return false;
00220 }
00221 
00222 std::istream* open_globus_policy(const X509_NAME* issuer_subject,const std::string& ca_path) {
00223   std::string issuer_subject_str;
00224   X509_NAME_to_string(issuer_subject_str,issuer_subject);
00225   unsigned long hash = X509_NAME_hash((X509_NAME*)issuer_subject);
00226   char hash_str[32];
00227   snprintf(hash_str,sizeof(hash_str)-1,"%08lx",hash);
00228   hash_str[sizeof(hash_str)-1]=0;
00229   std::string fname = ca_path+"/"+hash_str+policy_suffix;
00230   std::ifstream* f = new std::ifstream(fname.c_str());
00231   if(!(*f)) { delete f; return NULL; };
00232   return f;
00233 }
00234 
00235 }
00236