/* * http_auth: authentication * * This is a module for Apache 1.2.4, based on mod_auth.c * * User authentication is done by calling an external program. We are * passing login:password to that program on standard input, and expect * `true' on its standard output in case of a successful authentication. * * An example for such an external program is checkpw, which uses the * system password file to perform that authentication. * * Use by adding something like the following lines to .htaccess * * AuthName: Whatever * AuthType: Basic * require valid-user * AuthUserProg: /where/ever/is/checkpw * * (c) Frank Pilhofer 1999, fp@fpx.de. */ #include "httpd.h" #include "http_config.h" #include "http_core.h" #include "http_log.h" #include "http_protocol.h" #include #include typedef struct fp_auth_config_struct { char *auth_pwprog; } fp_auth_config_rec; static void * fp_create_auth_dir_config (pool *p, char *d) { fp_auth_config_rec *sec = (fp_auth_config_rec *) pcalloc (p, sizeof(fp_auth_config_rec)); sec->auth_pwprog = NULL; /* just to illustrate the default really */ return sec; } static const char * fp_set_auth_slot (cmd_parms *cmd, void *offset, char *f) { return set_string_slot(cmd, offset, f); } static command_rec fp_auth_cmds[] = { { "AuthUserProg", fp_set_auth_slot, (void*)XtOffsetOf(fp_auth_config_rec,auth_pwprog), OR_AUTHCFG, TAKE1, NULL }, { NULL } }; module auth_prog_module; static int fp_check_pw (request_rec * r, const char * user, const char * pw, const char * prog) { char errstr[MAX_STRING_LEN]; char result[256]; int in[2], out[2]; pid_t pid; int tot, cnt, ok=0, status; if (pipe(in) != 0) { log_reason ("Could not connect to auth prog", prog, r); return 0; } if (pipe(out) != 0) { log_reason ("Could not connect to auth prog", prog, r); close (in[0]); close (in[1]); return 0; } if ((pid = fork()) == (pid_t) -1) { log_reason ("Could not fork auth prog", prog, r); close (in[0]); close (out[0]); close (in[1]); close (out[1]); return 0; } if (pid == 0) { /* * Child */ close (in[1]); close (out[0]); // close (0); // close (1); dup2 (in[0], 0); dup2 (out[1], 1); execl (prog, prog, NULL); _exit (1); } /* * Parent */ close (in[0]); close (out[1]); write (in[1], user, strlen(user)); write (in[1], ":", 1); write (in[1], pw, strlen(pw)); write (in[1], "\n", 1); close (in[1]); for (tot=0; tot<255;) { if ((cnt = read (out[0], result+tot, 255-tot)) <= 0) { if (errno == EINTR) continue; break; } tot += cnt; } if (tot > 0) { if (tot > 4 && result[0] == 't' && result[1] == 'r' && result[2] == 'u' && result[3] == 'e') { ok = 1; } } close (out[0]); if (waitpid (pid, &status, 0) == pid) { if (WIFEXITED(status) == 0) { log_reason ("pw checker terminated abnormally", prog, r); ok = 0; } else if (WEXITSTATUS(status) != 0) { log_reason ("pw checker terminated abnormally", prog, r); ok = 0; } } return ok; } /* These functions return 0 if client is OK, and proper error status * if not... either AUTH_REQUIRED, if we made a check, and it failed, or * SERVER_ERROR, if things are so totally confused that we couldn't * figure out how to tell if the client is authorized or not. * * If they return DECLINED, and all other modules also decline, that's * treated by the server core as a configuration error, logged and * reported as such. */ /* Determine user ID, and check if it really is that user, for HTTP * basic authentication... */ static int fp_authenticate_basic_user (request_rec *r) { fp_auth_config_rec *sec = (fp_auth_config_rec *) get_module_config (r->per_dir_config, &auth_prog_module); conn_rec *c = r->connection; char *sent_pw, *real_pw; char errstr[MAX_STRING_LEN]; int res; if ((res = get_basic_auth_pw (r, &sent_pw))) return res; if (!sec->auth_pwprog) return DECLINED; if (!fp_check_pw (r, c->user, sent_pw, sec->auth_pwprog)) { ap_snprintf(errstr, sizeof(errstr), "user %s could not be verified", c->user); log_reason (errstr, r->uri, r); note_basic_auth_failure (r); return AUTH_REQUIRED; } return OK; } /* Checking ID */ int fp_check_user_access (request_rec *r) { fp_auth_config_rec *sec = (fp_auth_config_rec *) get_module_config (r->per_dir_config, &auth_prog_module); char *user = r->connection->user; int m = r->method_number; int method_restricted = 0; register int x; const char *t, *w; array_header *reqs_arr = requires (r); require_line *reqs; /* BUG FIX: tadc, 11-Nov-1995. If there is no "requires" directive, * then any user will do. */ if (!reqs_arr) return (OK); reqs = (require_line *)reqs_arr->elts; for(x=0; x < reqs_arr->nelts; x++) { if (! (reqs[x].method_mask & (1 << m))) continue; method_restricted = 1; t = reqs[x].requirement; w = getword(r->pool, &t, ' '); if(!strcmp(w,"valid-user")) return OK; if(!strcmp(w,"user")) { while(t[0]) { w = getword_conf (r->pool, &t); if(!strcmp(user,w)) return OK; } } else if(!strcmp(w,"group")) { return DECLINED; } } if (!method_restricted) return OK; note_basic_auth_failure (r); return AUTH_REQUIRED; } module auth_prog_module = { STANDARD_MODULE_STUFF, NULL, /* initializer */ fp_create_auth_dir_config, /* dir config creater */ NULL, /* dir merger --- default is to override */ NULL, /* server config */ NULL, /* merge server config */ fp_auth_cmds, /* command table */ NULL, /* handlers */ NULL, /* filename translation */ fp_authenticate_basic_user, /* check_user_id */ fp_check_user_access, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ NULL, /* logger */ NULL /* header parser */ };