读书人

[转载] Apache模块开发/用C语言扩充ap

发布时间: 2012-07-01 13:15:00 作者: rapoo

[转载] Apache模块开发/用C语言扩展apache(4:一个生产环境使用的apache module viewvc权限控制)

?

? ? ? ? 下面公布一个目前在我们公司使用的apache module的源代码。

? ? ? ? 我们公司开发人员很多,使用了SVN和viewvc来进行版本控制和查看,通过web界面,SVN能够根据每个用户的权限来控制能够浏览某个项目下的代码,但是viewvc只要你在SVN中有用户,你就可以看当前SVN中所有项目的代码。这个风险比较大,因此,我们开发了一个apache module,用来读取SVN的权限配置文件,把相应的权限集成到VIEWVC中。

?

? ? 源代码:

?

?

#include “apr_strings.h”#include “apr_hash.h”#include “apr_tables.h”#include “apr_md5.h”            #include “apr_lib.h”            #include “apr_base64.h”         #define APR_WANT_STRFUNC        #include “apr_want.h”#include “ap_config.h”#include “httpd.h”#include “http_config.h”#include “http_core.h”#include “http_log.h”#include “http_protocol.h”#include “http_request.h”#include “ap_provider.h”#include#define ENABLED        1#define DISABLED       0typedef struct{    short    enabled;    short    debug;    char     *dir;    // the starting path    char     *prefixPath;    // the stop url pattern    char     *stopPattern;    // the svn access file    char     *accessFile;} authSVN_rec;struct access_rec{   // 0: group   // 1: user   // 2: all   short              type;   // the group or user name   char              *name;   // 0: don’t have read access   // 1: have read access   short             access;   // the next access record   struct access_rec *next;};module AP_MODULE_DECLARE_DATA authSVN_module;// src starts with startstatic short start_with(const char *src, const char *start){int i = 0;if(strlen(src) < strlen(start))     return 0;i = strlen(start) - 1;while(i >= 0){  if(src[i] != start[i])      return 0;  i;}return 1;}// parse the SVN access filestatic short parse_access_file(request_rec *r, const char* file,                                     const authSVN_rec *conf,                                     apr_hash_t* ugMap,                                     apr_hash_t* accessMap){    ap_configfile_t *f = NULL;    apr_status_t status;    char l[MAX_STRING_LEN], dir[256];    status = ap_pcfg_openfile(&f, r->pool, file);    short flag = 0;       if (status != APR_SUCCESS)        return 0;       while(!(ap_cfg_getline(l, MAX_STRING_LEN, f)))    {        const char *w = NULL;        char *last = NULL;        apr_table_t *apt  = NULL;        struct access_rec  *arec = NULL, *arecp = NULL;              if ((l[0] == ‘#’) || (!l[0])) {            continue;        }              if(start_with(l, “[groups]”)) {            flag = 1;            continue;        }              if(l[0] == ‘[’) {            flag = 2;            w = apr_strtok(l, “[]:\n”, &last);                       if(w && w[0] == ‘/’) {                // the root directory                snprintf(dir, sizeof(dir), “%s”, conf->prefixPath);                dir[strlen(dir) - 1] = ‘\0′;            }            else if(w && w[0] != ‘/’)            {                const char *project = w;                w = apr_strtok(NULL, “[]:\n”, &last);                if(w)                {                    snprintf(dir, sizeof(dir), “%s%s%s”, conf->prefixPath, project, w);                    // make sure the dir is not end with /                    int len = strlen(dir);                    if(dir[len - 1] == ‘/’) dir[len - 1] = ‘\0′;                }                else                    dir[0] = ‘\0′;            }            else            {                dir[0] = ‘\0′;            }                       continue;        }              if(flag == 1) {            // this is the groups and users definition            w = apr_strtok(l, “=, \n”, &last);            if(w == NULL)                // group name not found                continue;                           apt = (apr_table_t *)apr_hash_get(ugMap, (const void *)w, APR_HASH_KEY_STRING);            if(apt == NULL) {                apt = apr_table_make(r->pool, 10);                apr_hash_set(ugMap, (const void *)apr_pstrdup(r->pool, w),                             APR_HASH_KEY_STRING, (const void *)apt);            }                       while((w = apr_strtok(NULL, “=, \n”, &last)) != NULL) {                // this is group name or user name                if(w[0] == ‘@’) {                    w++;                if(w) {                    apr_table_setn(apt, apr_pstrdup(r->pool, w), “0″);                }                }                else                {                    // this is user name                    apr_table_setn(apt, apr_pstrdup(r->pool, w), “1″);                }            }                   }              if(flag == 2) {            if(dir[0] == ‘\0′) continue;            w = apr_strtok(l, “= \n”, &last);            if(w)            {                arec = (struct access_rec *)apr_pcalloc(r->pool, sizeof(struct access_rec));                arec->access = 0;                               if(w[0] == ‘@’) {                    w++;                    if(w) {                        arec->name = apr_pstrdup(r->pool, w);                        arec->type = 0;                    }                    else continue;                }                else if(w[0] == ‘*’)                {                    arec->name = apr_pstrdup(r->pool, “*”);                    // this is all                    arec->type = 2;                }                else                {                    arec->name = apr_pstrdup(r->pool, w);                    // this is user name                    arec->type = 1;                }            }            else continue;                       w = apr_strtok(NULL, “= \n”, &last);            if(!w)            {                arec->access = 0;            }            else            {                arec->access = 1;            }                       arecp = (struct access_rec *)apr_hash_get(accessMap, (const void *)dir, APR_HASH_KEY_STRING);            if(arecp == NULL) {                arec->next = NULL;                apr_hash_set(accessMap, (const void *)apr_pstrdup(r->pool, dir),                             APR_HASH_KEY_STRING, (const void *)arec);            }            else            {                while(arecp->next != NULL) arecp = arecp->next;                arecp->next = arec;            }                   }          }       ap_cfg_closefile(f);       return 1;}static void *create_authSVN_dir_config(apr_pool_t *p, char *d){    authSVN_rec *conf = (authSVN_rec *)apr_pcalloc(p, sizeof(*conf));    if(conf == NULL) return NULL;          conf->enabled     = DISABLED;    conf->debug       = DISABLED;    conf->dir         = d;    conf->prefixPath  = NULL;    conf->stopPattern = NULL;    conf->accessFile  = NULL;    return conf;}static char hex2int(char c){if( c>=’0′ && c<='9' ) return (c - '0');return (c - 'A' + 10);}static void url_decode(char *url){char *p  = url;char *p1 = NULL;while(*p){  if(*p == '+') *p = ' ';      if(*p=='%' && *(p+1) && *(p+2))  {   *p = hex2int(toupper(*(p+1))) * 16 + hex2int(toupper(*(p+ 2)));   strcpy(p + 1, p + 3);  }    if(*p=='\\' && *(p+1) && *(p+2) && *(p+3))       {              p1 = p + 1;              if(*p1 && *p1=='x')              {                   *p = hex2int(toupper(*(p+2))) * 16 + hex2int(toupper(*(p+3)));                   strcpy(p+1, p+4);              }        }  p++;}return;}

?

? ? 接上段

?

static void parent_path(char *url){    char *p = url + strlen(url) - 1;       while(p != url && *p != '/') { *p = '\0'; p--; }    if(p != url && *p=='/') *p = '\0';       return;}// return// 0: the user don't belong to this group// 1: the user belong to this groupstatic short find_user_in_group(const char* user, const char *group, apr_hash_t* ugMap){    apr_table_t *apt = (apr_table_t *)apr_hash_get(ugMap,                                                 (const void *)group,                                                 APR_HASH_KEY_STRING);    if(apt == NULL) return 0;    apr_array_header_t *arr;    apr_table_entry_t  *elts;    int i;    arr  = (apr_array_header_t *)apr_table_elts(apt);    elts = (apr_table_entry_t *)arr->elts;       for(i=0; inelts; i++)    {        if(elts[i].key == NULL || elts[i].val == NULL) continue;                          if(elts[i].val[0] == ‘1′ && strcmp(elts[i].key, user) == 0)        {            return 1;        }              if(elts[i].val[0] == ‘0′)        {            if(find_user_in_group(user, elts[i].key, ugMap))                return 1;        }    }       return 0;}// return//  0:don’t have access//  1:have read access//  2:access not foundstatic short find_access(const char* user, const char* url,                         apr_hash_t* ugMap, apr_hash_t* accessMap){    struct access_rec *arec= (struct access_rec *)apr_hash_get(accessMap,                             (const void *)url, APR_HASH_KEY_STRING);       short access = 2;       while(arec != NULL)    {        if(strcmp(arec->name, “*”) == 0)        {            // specified access to all users and groups on this url            access = arec->access;        }              if(arec->type == 1 && strcmp(arec->name, user) == 0)        {            // specified user access on this url            access = arec->access;        }              if(arec->type == 0)        {            // this is group access            if(find_user_in_group(user, arec->name, ugMap))                access = arec->access;        }              // if this user have access, we return        if(access == 1) return access;                arec = arec->next;    }       return access;}static short estimate_access( request_rec *r, const authSVN_rec* conf,                              char* url, apr_hash_t* ugMap,                              apr_hash_t* accessMap ){    const char* user = r->user;    // unauthorized    if(!user || !user[0]) return 0;       short access = find_access(user, url, ugMap, accessMap);    if(access < 2) return access;       if(url[0] == '/' && url[1] == '\0') return 0;       parent_path(url);       return estimate_access(r, conf, url, ugMap, accessMap);}// do regexp matchingstatic short regexp_match(char *str, char *pattern){    regex_t      reg;   regmatch_t   pm[1];   const size_t nmatch = 1;   int res = 0;short r = 0;   char ebuf[MAX_STRING_LEN];   res = regcomp(&reg, pattern, REG_EXTENDED);   if(res != 0)   {     regfree(&reg);    return 0;   }      res = regexec(&reg, str, nmatch, pm, 0);      if(res == REG_NOMATCH)       r = 0;   else       r = 1;   regfree(&reg);return r;}static int authSVN_handler(request_rec *r){        authSVN_rec *conf = ap_get_module_config(r->per_dir_config,                                                 &authSVN_module);        if(!conf || !conf->enabled)             return DECLINED;              if(conf->prefixPath == NULL || !start_with(r->uri, conf->prefixPath))            return DECLINED;              if(conf->stopPattern !=NULL && regexp_match(r->uri, conf->stopPattern))            return DECLINED;              apr_hash_t* ugMap     = apr_hash_make(r->pool);        apr_hash_t* accessMap = apr_hash_make(r->pool);              if(!parse_access_file(r, conf->accessFile, conf, ugMap, accessMap))            return 403;              if(conf->debug)        {            // run in debug mode            // print all users/groups and access information            apr_hash_index_t* hi;            char *key;            apr_table_t *val;            struct access_rec *arec;            apr_array_header_t *arr;            apr_table_entry_t  *elts;            int i;                       r->content_type=”text/plain”;            ap_rprintf(r, “Parsed Users and Groups:\n”);                       hi = apr_hash_first(r->pool, ugMap);            while(hi != NULL)            {                apr_hash_this(hi, (void *)&key, NULL, (void *)&val);                               ap_rprintf(r, “%s: “, key);                arr  = (apr_array_header_t *)apr_table_elts(val);                elts = (apr_table_entry_t *)arr->elts;                for(i=0; inelts; i++)                {                    if(elts[i].key == NULL || elts[i].val == NULL) continue;                    if(elts[i].val[0] == ‘0′)                    {                        ap_rprintf(r, “@”);                    }                    ap_rprintf(r, “%s “, elts[i].key);                }                               ap_rprintf(r, “\n”);                               hi = apr_hash_next(hi);            }                       ap_rprintf(r, “Parsed Path Access:\n”);            hi = apr_hash_first(r->pool, accessMap);            while(hi != NULL)            {                apr_hash_this(hi, (void *)&key, NULL, (void *)&arec);                ap_rprintf(r, “%s:\n”, key);                while(arec != NULL)                {                    if(arec->type == 0)                        ap_rprintf(r, “group:%s “, arec->name);                    else if(arec->type == 1)                        ap_rprintf(r, “user:%s “, arec->name);                    else                        ap_rprintf(r, “all “);                                      ap_rprintf(r, “access:%d “, arec->access);                    ap_rprintf(r, “\n”);                    arec = arec->next;                }                               ap_rprintf(r, “\n”);                hi = apr_hash_next(hi);            }        }              char *url = apr_pstrdup(r->pool, r->uri);        // decode the url for some chinese characters        url_decode(url);              // analyze the access        if(estimate_access(r, conf, url, ugMap, accessMap))        {            if(conf->debug)            {                ap_rprintf(r, “%s have access on:%s\n”, r->user, r->uri);                return OK;            }            return DECLINED;        }        else        {            if(conf->debug)            {                ap_rprintf(r, “%s don’t have access on:%s\n”, r->user, r->uri);                return OK;            }        }              return 403;}static const char *set_authSVN_enable(cmd_parms *cmd,                                      void *mconfig,                                      int arg){    authSVN_rec *conf = (authSVN_rec *) mconfig;    conf->enabled = arg;    return NULL;}static const char *set_authSVN_debug( cmd_parms *cmd,                                      void *mconfig,                                      int arg){    authSVN_rec *conf = (authSVN_rec *) mconfig;    conf->debug = arg;    return NULL;}static const char *set_prefix_path(cmd_parms *cmd,                                   void *mconfig,                                   const char *name){    authSVN_rec *conf = (authSVN_rec *) mconfig;       if(strlen(name) <= 0)        return "AuthSVNPrefixPath can not be null.";       if(name[0] != '/' || name[strlen(name) - 1] != '/')        return "AuthSVNPrefixPath must start and end with '/'.";       conf->prefixPath = apr_pstrdup(cmd->pool, name);       return NULL;}static const char *set_stop_pattern(cmd_parms *cmd,                                    void *mconfig,                                   const char *name){    authSVN_rec *conf = (authSVN_rec *) mconfig;       if(strlen(name) <= 0)        return "AuthSVNStopPattern can not be null.";       conf->stopPattern = apr_pstrdup(cmd->pool, name);       return NULL;}static const char *set_authSVN_accessFile(cmd_parms *cmd,                                          void *mconfig,                                          const char *name){    authSVN_rec *conf = (authSVN_rec *) mconfig;    ap_configfile_t *f = NULL;    apr_status_t status;       if(strlen(name) <= 0)        return "SVNAccessFile can not be null.";       status = ap_pcfg_openfile(&f, cmd->pool, name);    if (status != APR_SUCCESS) {        return “Can not open given SVN access file.”;    }    ap_cfg_closefile(f);       conf->accessFile = apr_pstrdup(cmd->pool, name);       return NULL;}static const command_rec auth_cmds[] ={    AP_INIT_FLAG(”EnableAuthSVN”, set_authSVN_enable, NULL, OR_FILEINFO,     “enable authSVN or not.”),    AP_INIT_FLAG(”DebugAuthSVN”,  set_authSVN_debug, NULL, OR_FILEINFO,     “debug authSVN or not.”),    AP_INIT_TAKE1(”AuthSVNPrefixPath”,   set_prefix_path,   NULL, OR_FILEINFO,     “set prefix path.”),    AP_INIT_TAKE1(”AuthSVNStopPattern”,  set_stop_pattern,   NULL, OR_FILEINFO,     “the url pattern we do not do the access checking.”),    AP_INIT_TAKE1(”SVNAccessFile”, set_authSVN_accessFile, NULL, OR_FILEINFO,     “set SVN access file.”),    { NULL }};static void register_hooks(apr_pool_t *p){    ap_hook_handler(authSVN_handler, NULL, NULL, APR_HOOK_FIRST);}module AP_MODULE_DECLARE_DATA authSVN_module ={    STANDARD20_MODULE_STUFF,    create_authSVN_dir_config,         NULL,                              NULL,                              NULL,                              auth_cmds,                         register_hooks                 };
?

读书人网 >C语言

热点推荐