///// // // File : mod_absec.c // Author : Jean-Luc Cyr // Date : 2018-10 // // Description: apache module for authentification and autorisation management // /* ** mod_absec.c -- Apache absec module ** [base Autogenerated via ``apxs -n absec -g''] ** ** To play with this sample module first compile it into a ** DSO file and install it into Apache's modules directory ** by running: ** ** $ apxs -lpam -lpam_misc -c -i mod_absec.c ** ** Then activate it in Apache's httpd.conf file for instance ** for the URL /absec in as follows: ** ** # httpd.conf ** LoadModule absec_module modules/mod_absec.so ** ** SetHandler absec ** ** ** Then after restarting Apache via ** ** $ apachectl restart ** */ /* TEST URL http://10.211.55.15/absec/ INFORMATION SOURCES https://apr.apache.org/docs/apr/1.5/group__apr__strings.html https://apr.apache.org/docs/apr-util/1.6/files.html https://httpd.apache.org/docs/2.4/developer/modguide.html http://www.ziviani.net/2011/how-to-create-an-apache-module https://en.wikipedia.org/wiki/Basic_access_authentication */ #include "httpd.h" #include "http_config.h" #include "http_core.h" #include "http_protocol.h" #include "http_request.h" #include "http_log.h" #include "ap_config.h" #include "apr_base64.h" #include "apr_strings.h" #include "apr_portable.h" #include "apr_user.h" #include "ap_provider.h" #include "mod_auth.h" #include #include #include #include #include #include "apr_want.h" #include #include #include "absec_authen.h" #include "absec_auto.h" //////////////////////////////////////////////////////////////// // Macro declaration du module module AP_MODULE_DECLARE_DATA absec_module; //////////////////////////////////////////////////////////////// // structure de configuration du module typedef struct { int default_uid; int default_gid; int default_perms; } authnz_config_rec; static void *authnz_absec_config(apr_pool_t *pool, char *x) { return apr_pcalloc(pool, sizeof(authnz_config_rec)); } static const char* set_default_perms(cmd_parms* cmd, void* cfg, const char* val) { int octal, decimal; octal = atoi(val); decimal = 0; int i=0; while (octal != 0) { decimal = decimal +(octal % 10)* pow(8, i++); octal = octal / 10; } ((authnz_config_rec*)cfg)->default_perms = decimal; return NULL; } static const char* set_default_uid(cmd_parms* cmd, void* cfg, const char* val) { ((authnz_config_rec*)cfg)->default_uid = atoi(val); return NULL; } static const char* set_default_gid(cmd_parms* cmd, void* cfg, const char* val) { ((authnz_config_rec*)cfg)->default_gid = atoi(val); return NULL; } //////////////////////////////////////////////////////////////// static const command_rec absec_auth_basic_cmds[] = { /* AP_INIT_ITERATE("AuthBasicProvider", add_authn_provider, NULL, OR_AUTHCFG, "specify the auth providers for a directory or location"),*/ AP_INIT_TAKE1("ABSECDefaultPerms", set_default_perms, NULL, OR_AUTHCFG, "Set to default octal value of perms "), AP_INIT_TAKE1("ABSECDefaultUID", set_default_uid, NULL, OR_AUTHCFG, "Set to default octal value of perms "), AP_INIT_TAKE1("ABSECDefaultGID", set_default_gid, NULL, OR_AUTHCFG, "Set to default octal value of perms "), /* AP_INIT_TAKE12("AuthBasicFake", add_basic_fake, NULL, OR_AUTHCFG, "Fake basic authentication using the given expressions for " "username and password, 'off' to disable. Password defaults " "to 'password' if missing."), AP_INIT_TAKE1("AuthBasicUseDigestAlgorithm", set_use_digest_algorithm, NULL, OR_AUTHCFG, "Set to 'MD5' to use the auth provider's authentication " "check for digest auth, using a hash of 'user:realm:pass'"),*/ {NULL} }; //////////////////////////////////////////////////////////////// // Validate authentification (user/pass) static authn_status authn_check_absec(request_rec *r, const char* user, const char* password) { ap_log_rerror("mod_absec.c", 269, 1, APLOG_ERR, APR_SUCCESS, r, "authn_check_absec : user : %s, pass : %s", user, password); int pam_result = check_user(user, password); if ( (pam_result==PAM_ERROR_START) || (pam_result==PAM_ERROR_STOP) ) { return HTTP_INTERNAL_SERVER_ERROR; } if (pam_result==PAM_ERROR_INVALID_CRED) { ap_log_rerror("mod_absec.c", 269, 1, APLOG_ERR, APR_SUCCESS, r, "authn_check_absec : DENIED"); return AUTH_DENIED; } ap_log_rerror("mod_absec.c", 269, 1, APLOG_ERR, APR_SUCCESS, r, "authn_check_absec : GRANTED"); return AUTH_GRANTED; // Example code /* if (strcmp(user, "joe")) { return AUTH_USER_NOT_FOUND; } else { if (strcmp(password, "poi")) { return AUTH_DENIED; } else { return AUTH_GRANTED; } } */ // Possible return status // AUTH_GENERAL_ERROR // AUTH_USER_NOT_FOUND // AUTH_USER_FOUND // AUTH_DENIED // AUTH_GRANTED } //////////////////////////////////////////////////////////////// // Validate autorisation (ressource access) // request_rec contain user/pass if basic auth // it could also contain cookies if cookies based auth static authz_status authz_check_absec(request_rec *r, const char *require_args, const void *parsed_require_args) { char *user = r->user; ap_log_rerror("mod_absec.c", 342, 1, APLOG_ERR, APR_SUCCESS, r, "authz_check_absec : user : %s", user); //////// /* http method validate the perm asked (r/w vs get/post,put) */ //ap_rprintf(r, "Before Method: %s
\r\n", r->method); int permmask = 0; if (strcmp(r->method,"GET")==0) permmask=0444; // r if (strcmp(r->method,"PUT")==0) permmask=0222; // w if (strcmp(r->method,"POST")==0) permmask=0222; // w if (strcmp(r->method,"DELETE")==0) permmask=0111; // x authnz_config_rec *cfg = ap_get_module_config(r->per_dir_config, &absec_module); struct stat fperm; fperm.st_mode = cfg->default_perms; ap_log_rerror("mod_absec.c", 329, 1, APLOG_ERR, APR_SUCCESS, r, "authz_check_absec : default perms : %o", cfg->default_perms); fperm.st_uid = cfg->default_uid; ap_log_rerror("mod_absec.c", 329, 1, APLOG_ERR, APR_SUCCESS, r, "authz_check_absec : default uid : %o", cfg->default_uid); fperm.st_gid = cfg->default_gid; ap_log_rerror("mod_absec.c", 329, 1, APLOG_ERR, APR_SUCCESS, r, "authz_check_absec : default gid : %o", cfg->default_gid); //////// /* check file permission on filesystem */ /* should include */ int status; //status = stat(r->filename, &fperm); status = perms_lookup(r, &fperm); //ap_rprintf(r, "Result mysql: %d
\r\n", ); if (status==-1) { ap_rprintf(r, "stat erreur %d", errno); ap_log_rerror("mod_absec.c", 282, 1, APLOG_ERR, APR_SUCCESS, r, "authz_check_absec : stat erreur %d", errno); return (OK); } //ap_rprintf(r, "File perms %o, owner %d, group %d (status %d)
\r\n", fperm.st_mode, fperm.st_uid, fperm.st_gid, status); /* check if any permission (ogw) match method (get r, put/post w, delete x) */ if ((fperm.st_mode & permmask)==0) { /* no permission match, return don't even have to check user perms */ ap_rprintf(r, "Aucune permission pour la methode %s (%o, %o)", r->method, fperm.st_mode, permmask); ap_log_rerror("mod_absec.c", 282, 1, APLOG_ERR, APR_SUCCESS, r, "authz_check_absec : Aucune permission pour la methode %s (%o, %o)", r->method, fperm.st_mode, permmask); return AUTHZ_DENIED; } // If file is world accessible for asked method return content if (fperm.st_mode & 0x7 & permmask) { /* if so, return, no need to check user perms */ //ap_rprintf(r, "Fichier public
\r\n"); ap_log_rerror("mod_absec.c", 282, 1, APLOG_ERR, APR_SUCCESS, r, "authz_check_absec : Fichier accessible a tous"); return AUTHZ_GRANTED; } if (!user) { ap_log_rerror("mod_absec.c", 282, 1, APLOG_ERR, APR_SUCCESS, r, "authz_check_absec : No user"); return AUTHZ_DENIED_NO_USER; } struct passwd *pw; pw = getpwnam(user); // If file is user readable and user match return content if ((fperm.st_uid==pw->pw_uid) && (fperm.st_mode & 0700 & permmask)) { //ap_rprintf(r, "Fichier propriƩtaire
\r\n"); ap_log_rerror("mod_absec.c", 282, 1, APLOG_ERR, APR_SUCCESS, r, "authz_check_absec : Fichier propriƩtaire
\r\n"); return AUTHZ_GRANTED; } else { ap_log_rerror("mod_absec.c", 282, 1, APLOG_ERR, APR_SUCCESS, r, "authz_check_absec : No user access %d", pw->pw_uid); } // If file is group readable and primary group match return content if ((fperm.st_gid==pw->pw_gid) && (fperm.st_mode & 0070 & permmask)) { //ap_rprintf(r, "Fichier groupe
\r\n"); ap_log_rerror("mod_absec.c", 282, 1, APLOG_ERR, APR_SUCCESS, r, "authz_check_absec : Fichier groupe
\r\n"); return AUTHZ_GRANTED; } else { ap_log_rerror("mod_absec.c", 282, 1, APLOG_ERR, APR_SUCCESS, r, "authz_check_absec : No group access %d", pw->pw_gid); } // check supplemental groups gid_t grouplist[16]; int grouplistsize = 16; int groupreturn; groupreturn = getgrouplist(user, pw->pw_gid, grouplist, &grouplistsize); if (groupreturn >= 0) { ap_log_rerror("mod_absec.c", 282, 1, APLOG_ERR, APR_SUCCESS, r, "authz_check_absec : liste groups (%d)", grouplistsize); for (int i=0; i\r\n"); return AUTHZ_DENIED; if (r->user==NULL) { return AUTHZ_DENIED; } return AUTHZ_GRANTED; } //////////////////////////////////////////////////////////////// static const authn_provider authn_absec_provider = { &authn_check_absec, NULL }; //////////////////////////////////////////////////////////////// static const authz_provider authz_absec_provider = { &authz_check_absec, NULL }; //////////////////////////////////////////////////////////////// static void absec_register_hooks(apr_pool_t *p) { ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "absec", "0", &authn_absec_provider, AP_AUTH_INTERNAL_PER_CONF); ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "absec", "0", &authz_absec_provider, AP_AUTH_INTERNAL_PER_CONF); } //////////////////////////////////////////////////////////////// /* Dispatch list for API hooks */ AP_DECLARE_MODULE(absec) = { STANDARD20_MODULE_STUFF, authnz_absec_config, /* create per-dir config structures */ NULL, /* merge per-dir config structures */ NULL, /* create per-server config structures */ NULL, /* merge per-server config structures */ absec_auth_basic_cmds, /* table of config file commands */ absec_register_hooks /* register hooks */ };