"Fossies" - the Fresh Open Source Software Archive

Member "mod_fastcgi-2.4.7-0910052141/fcgi_util.c" (10 Apr 2012, 14775 Bytes) of package /linux/www/apache_httpd_modules/old/mod_fastcgi-2.4.7-0910052141.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.

    1 /*
    2  * $Id: fcgi_util.c,v 1.32 2007/09/23 16:33:29 robs Exp $
    3  */
    4 
    5 #include "fcgi.h"
    6 
    7 #ifdef WIN32
    8 #pragma warning( disable : 4100 )
    9 #elif defined(APACHE2)
   10 #include <netdb.h>
   11 #include <unistd.h>
   12 #include <grp.h>
   13 #include <pwd.h>
   14 
   15 #if APR_HAVE_ARPA_INET_H
   16 #include <arpa/inet.h>
   17 #endif
   18 
   19 #include "unixd.h"
   20 #endif
   21 
   22 uid_t 
   23 fcgi_util_get_server_uid(const server_rec * const s)
   24 {
   25 #if defined(WIN32) 
   26     return (uid_t) 0;
   27 #elif defined(APACHE2)
   28     /* the main server's uid */
   29     return ap_user_id;
   30 #else
   31     /* the vhost's uid */
   32     return s->server_uid;
   33 #endif
   34 }
   35 
   36 uid_t 
   37 fcgi_util_get_server_gid(const server_rec * const s)
   38 {
   39 #if defined(WIN32) 
   40     return (uid_t) 0;
   41 #elif defined(APACHE2)
   42     /* the main server's gid */
   43     return ap_group_id;
   44 #else
   45     /* the vhost's gid */
   46     return s->server_gid;
   47 #endif
   48 }
   49  
   50 /*******************************************************************************
   51  * Compute printable MD5 hash. Pool p is used for scratch as well as for
   52  * allocating the hash - use temp storage, and dup it if you need to keep it.
   53  */
   54 char *
   55 fcgi_util_socket_hash_filename(pool *p, const char *path,
   56         const char *user, const char *group)
   57 {
   58     char *buf = ap_pstrcat(p, path, user, group, NULL);
   59 
   60     /* Canonicalize the path (remove "//", ".", "..") */
   61     ap_getparents(buf);
   62 
   63     return ap_md5(p, (unsigned char *)buf);
   64 }
   65 
   66 
   67  /*******************************************************************************
   68   * Concat src1 and src2 using the approprate path seperator for the platform. 
   69   */
   70 static char * make_full_path(pool *a, const char *src1, const char *src2)
   71 {
   72 #ifdef WIN32
   73     register int x;
   74     char * p ;
   75     char * q ;
   76 
   77     x = strlen(src1);
   78 
   79     if (x == 0) {
   80         p = ap_pstrcat(a, "\\", src2, NULL);
   81     }
   82     else if (src1[x - 1] != '\\' && src1[x - 1] != '/') {
   83         p = ap_pstrcat(a, src1, "\\", src2, NULL);
   84     }
   85     else {
   86         p = ap_pstrcat(a, src1, src2, NULL);
   87     }
   88 
   89     q = p ;
   90     while (*q)
   91     {
   92         if (*q == '/') {
   93             *q = '\\' ;
   94         }
   95         ++q;
   96     }
   97 
   98     return p ;
   99 #else
  100     return ap_make_full_path(a, src1, src2);
  101 #endif
  102 }
  103 
  104 /*******************************************************************************
  105  * Return absolute path to file in either "regular" FCGI socket directory or
  106  * the dynamic directory.  Result is allocated in pool p.
  107  */
  108 const char *
  109 fcgi_util_socket_make_path_absolute(pool * const p, 
  110         const char *const file, const int dynamic)
  111 {
  112 #ifdef APACHE2
  113     if (ap_os_is_path_absolute(p, (char *) file))
  114 #else
  115     if (ap_os_is_path_absolute(file))
  116 #endif
  117     {
  118         return file;
  119     }
  120     else
  121     {
  122         const char * parent_dir = dynamic ? fcgi_dynamic_dir : fcgi_socket_dir;
  123         return (const char *) make_full_path(p, parent_dir, file);
  124     }
  125 }
  126 
  127 #ifndef WIN32
  128 /*******************************************************************************
  129  * Build a Domain Socket Address structure, and calculate its size.
  130  * The error message is allocated from the pool p.  If you don't want the
  131  * struct sockaddr_un also allocated from p, pass it preallocated (!=NULL).
  132  */
  133 const char *
  134 fcgi_util_socket_make_domain_addr(pool *p, struct sockaddr_un **socket_addr,
  135         int *socket_addr_len, const char *socket_path)
  136 {
  137     int socket_pathLen = strlen(socket_path);
  138 
  139     if (socket_pathLen >= sizeof((*socket_addr)->sun_path)) {
  140         return ap_pstrcat(p, "path \"", socket_path,
  141                        "\" is too long for a Domain socket", NULL);
  142     }
  143 
  144     if (*socket_addr == NULL)
  145         *socket_addr = ap_pcalloc(p, sizeof(struct sockaddr_un));
  146     else
  147         memset(*socket_addr, 0, sizeof(struct sockaddr_un));
  148 
  149     (*socket_addr)->sun_family = AF_UNIX;
  150     strcpy((*socket_addr)->sun_path, socket_path);
  151 
  152     *socket_addr_len = SUN_LEN(*socket_addr);
  153     return NULL;
  154 }
  155 #endif
  156 
  157 /*******************************************************************************
  158  * Convert a hostname or IP address string to an in_addr struct.
  159  */
  160 static int 
  161 convert_string_to_in_addr(const char * const hostname, struct in_addr * const addr)
  162 {
  163     struct hostent *hp;
  164     int count;
  165 
  166     addr->s_addr = inet_addr((char *)hostname);
  167 
  168 #if !defined(INADDR_NONE) && defined(APACHE2)
  169 #define INADDR_NONE APR_INADDR_NONE
  170 #endif
  171     
  172     if (addr->s_addr == INADDR_NONE) {
  173         if ((hp = gethostbyname((char *)hostname)) == NULL)
  174             return -1;
  175 
  176         memcpy((char *) addr, hp->h_addr, hp->h_length);
  177         count = 0;
  178         while (hp->h_addr_list[count] != 0)
  179             count++;
  180 
  181         return count;
  182     }
  183     return 1;
  184 }
  185 
  186 
  187 /*******************************************************************************
  188  * Build an Inet Socket Address structure, and calculate its size.
  189  * The error message is allocated from the pool p. If you don't want the
  190  * struct sockaddr_in also allocated from p, pass it preallocated (!=NULL).
  191  */
  192 const char *
  193 fcgi_util_socket_make_inet_addr(pool *p, struct sockaddr_in **socket_addr,
  194         int *socket_addr_len, const char *host, unsigned short port)
  195 {
  196     if (*socket_addr == NULL)
  197         *socket_addr = ap_pcalloc(p, sizeof(struct sockaddr_in));
  198     else
  199         memset(*socket_addr, 0, sizeof(struct sockaddr_in));
  200 
  201     (*socket_addr)->sin_family = AF_INET;
  202     (*socket_addr)->sin_port = htons(port);
  203 
  204     /* Get an in_addr represention of the host */
  205     if (host != NULL) {
  206         if (convert_string_to_in_addr(host, &(*socket_addr)->sin_addr) != 1) {
  207             return ap_pstrcat(p, "failed to resolve \"", host,
  208                            "\" to exactly one IP address", NULL);
  209         }
  210     } else {
  211       (*socket_addr)->sin_addr.s_addr = htonl(INADDR_ANY);
  212     }
  213 
  214     *socket_addr_len = sizeof(struct sockaddr_in);
  215     return NULL;
  216 }
  217 
  218 /*******************************************************************************
  219  * Determine if a process with uid/gid can access a file with mode permissions.
  220  */
  221 const char *
  222 fcgi_util_check_access(pool *tp, 
  223         const char * const path, const struct stat *statBuf, 
  224         const int mode, const uid_t uid, const gid_t gid)
  225 {
  226     struct stat myStatBuf;
  227 
  228     if (statBuf == NULL) {    
  229         if (stat(path, &myStatBuf) < 0)
  230             return ap_psprintf(tp, "stat(%s) failed: %s", path, strerror(errno));
  231         statBuf = &myStatBuf;
  232     }
  233     
  234 #ifndef WIN32    
  235     /* If the uid owns the file, check the owner bits */
  236     if (uid == statBuf->st_uid) {
  237         if (mode & R_OK && !(statBuf->st_mode & S_IRUSR))
  238             return "read not allowed by owner";
  239         if (mode & W_OK && !(statBuf->st_mode & S_IWUSR))
  240             return "write not allowed by owner";
  241         if (mode & X_OK && !(statBuf->st_mode & S_IXUSR))
  242             return "execute not allowed by owner";
  243         return NULL;
  244     }
  245 #else
  246     if (mode & _S_IREAD && !(statBuf->st_mode & _S_IREAD))
  247         return "read not allowed";
  248     if (mode & _S_IWRITE && !(statBuf->st_mode & _S_IWRITE))
  249         return "write not allowed";
  250     
  251     /* I don't think this works on FAT, but since I don't know how to check..
  252      * if (mode & _S_IEXEC && !(statBuf->st_mode & _S_IEXEC))
  253      *     return "execute not allowed"; */
  254 #endif
  255 
  256 #if  !defined(__EMX__) && !defined(WIN32)
  257     /* If the gid is same as the file's group, check the group bits */
  258     if (gid == statBuf->st_gid) {
  259         if (mode & R_OK && !(statBuf->st_mode & S_IRGRP))
  260             return "read not allowed by group";
  261         if (mode & W_OK && !(statBuf->st_mode & S_IWGRP))
  262             return "write not allowed by group";
  263         if (mode & X_OK && !(statBuf->st_mode & S_IXGRP))
  264             return "execute not allowed by group";
  265         return NULL;
  266     }
  267 
  268     /* Get the user membership for the file's group.  If the
  269      * uid is a member, check the group bits. */
  270     {
  271         const struct group * const gr = getgrgid(statBuf->st_gid);
  272         const struct passwd * const pw = getpwuid(uid);
  273 
  274         if (gr != NULL && pw != NULL) {
  275             char **user = gr->gr_mem;
  276             for ( ; *user != NULL; user++) {
  277                 if (strcmp(*user, pw->pw_name) == 0) {
  278                     if (mode & R_OK && !(statBuf->st_mode & S_IRGRP))
  279                         return "read not allowed by group";
  280                     if (mode & W_OK && !(statBuf->st_mode & S_IWGRP))
  281                         return "write not allowed by group";
  282                     if (mode & X_OK && !(statBuf->st_mode & S_IXGRP))
  283                         return "execute not allowed by group";
  284                     return NULL;
  285                 }
  286             }
  287         }
  288     }
  289     
  290     /* That just leaves the other bits.. */
  291     if (mode & R_OK && !(statBuf->st_mode & S_IROTH))
  292         return "read not allowed";
  293     if (mode & W_OK && !(statBuf->st_mode & S_IWOTH))
  294         return "write not allowed";
  295     if (mode & X_OK && !(statBuf->st_mode & S_IXOTH))
  296         return "execute not allowed";
  297 #endif
  298 
  299     return NULL;
  300 }
  301 
  302 
  303 /*******************************************************************************
  304  * Find a FastCGI server with a matching fs_path, and if fcgi_wrapper is
  305  * enabled with matching uid and gid.
  306  */
  307 fcgi_server *
  308 fcgi_util_fs_get_by_id(const char *ePath, uid_t uid, gid_t gid)
  309 {
  310     char path[FCGI_MAXPATH];
  311     fcgi_server *s;
  312 
  313     /* @@@ This should now be done in the loop below */
  314     ap_cpystrn(path, ePath, FCGI_MAXPATH);
  315     ap_no2slash(path);
  316 
  317     for (s = fcgi_servers; s != NULL; s = s->next) {
  318         int i;
  319         const char *fs_path = s->fs_path;
  320         for (i = 0; fs_path[i] && path[i]; ++i) {
  321             if (fs_path[i] != path[i]) {
  322                 break;
  323             }
  324         }
  325         if (fs_path[i]) {
  326             continue;
  327         }
  328         if (path[i] == '\0' || path[i] == '/') {
  329         if (fcgi_wrapper == NULL || (uid == s->uid && gid == s->gid))
  330             return s;
  331         }
  332     }
  333     return NULL;
  334 }
  335 
  336 /*******************************************************************************
  337  * Find a FastCGI server with a matching fs_path, and if fcgi_wrapper is
  338  * enabled with matching user and group.
  339  */
  340 fcgi_server *
  341 fcgi_util_fs_get(const char *ePath, const char *user, const char *group)
  342 {
  343     char path[FCGI_MAXPATH];
  344     fcgi_server *s;
  345 
  346     ap_cpystrn(path, ePath, FCGI_MAXPATH);
  347     ap_no2slash(path);
  348     
  349     for (s = fcgi_servers; s != NULL; s = s->next) {
  350         if (strcmp(s->fs_path, path) == 0) {
  351             if (fcgi_wrapper == NULL)
  352                 return s;
  353 
  354             if (strcmp(user, s->user) == 0 
  355                 && (user[0] == '~' || strcmp(group, s->group) == 0))
  356             {
  357                 return s;
  358             }
  359         }
  360     }
  361     return NULL;
  362 }
  363 
  364 const char *
  365 fcgi_util_fs_is_path_ok(pool * const p, const char * const fs_path, struct stat *finfo)
  366 {
  367     const char *err;
  368 
  369     if (finfo == NULL) {
  370         finfo = (struct stat *)ap_palloc(p, sizeof(struct stat));           
  371         if (stat(fs_path, finfo) < 0)
  372             return ap_psprintf(p, "stat(%s) failed: %s", fs_path, strerror(errno));
  373     }
  374     
  375     if (finfo->st_mode == 0) 
  376         return ap_psprintf(p, "script not found or unable to stat()");
  377 
  378     if (S_ISDIR(finfo->st_mode)) 
  379         return ap_psprintf(p, "script is a directory!");
  380     
  381     /* Let the wrapper determine what it can and can't execute */
  382     if (! fcgi_wrapper)
  383     {
  384 #ifdef WIN32
  385         err = fcgi_util_check_access(p, fs_path, finfo, _S_IEXEC, fcgi_user_id, fcgi_group_id);
  386 #else
  387         err = fcgi_util_check_access(p, fs_path, finfo, X_OK, fcgi_user_id, fcgi_group_id);
  388 #endif
  389         if (err) {
  390             return ap_psprintf(p,
  391                 "access for server (uid %ld, gid %ld) not allowed: %s",
  392                 (long)fcgi_user_id, (long)fcgi_group_id, err);
  393         }
  394     }
  395     
  396     return NULL;
  397 }
  398 
  399 
  400 
  401 /*******************************************************************************
  402  * Allocate a new FastCGI server record from pool p with default values.
  403  */
  404 fcgi_server *
  405 fcgi_util_fs_new(pool *p)
  406 {
  407     fcgi_server *s = (fcgi_server *) ap_pcalloc(p, sizeof(fcgi_server));
  408 
  409     /* Initialize anything who's init state is not zeroizzzzed */
  410     s->listenQueueDepth = FCGI_DEFAULT_LISTEN_Q;
  411     s->appConnectTimeout = FCGI_DEFAULT_APP_CONN_TIMEOUT;
  412     s->idle_timeout = FCGI_DEFAULT_IDLE_TIMEOUT;
  413     s->initStartDelay = DEFAULT_INIT_START_DELAY;
  414     s->restartDelay = FCGI_DEFAULT_RESTART_DELAY;
  415     s->minServerLife = FCGI_DEFAULT_MIN_SERVER_LIFE;
  416     s->restartOnExit = FALSE;
  417     s->directive = APP_CLASS_UNKNOWN;
  418     s->processPriority = FCGI_DEFAULT_PRIORITY;
  419     s->envp = &fcgi_empty_env;
  420     
  421 #ifdef WIN32
  422     s->listenFd = (int) INVALID_HANDLE_VALUE;
  423 #else
  424     s->listenFd = -2;
  425 #endif
  426 
  427     return s;
  428 }
  429 
  430 /*******************************************************************************
  431  * Add the server to the linked list of FastCGI servers.
  432  */
  433 void 
  434 fcgi_util_fs_add(fcgi_server *s)
  435 {
  436     s->next = fcgi_servers;
  437     fcgi_servers = s;
  438 }
  439 
  440 /*******************************************************************************
  441  * Configure uid, gid, user, group, username for wrapper.
  442  */
  443 const char *
  444 fcgi_util_fs_set_uid_n_gid(pool *p, fcgi_server *s, uid_t uid, gid_t gid)
  445 {
  446 #ifndef WIN32
  447 
  448     struct passwd *pw;
  449     struct group  *gr;
  450 
  451     if (fcgi_wrapper == NULL)
  452         return NULL;
  453 
  454     if (uid == 0 || gid == 0) {
  455         return "invalid uid or gid, see the -user and -group options";
  456     }
  457 
  458     s->uid = uid;
  459     pw = getpwuid(uid);
  460     if (pw == NULL) {
  461         return ap_psprintf(p,
  462             "getpwuid() couldn't determine the username for uid '%ld', "
  463             "you probably need to modify the User directive: %s",
  464             (long)uid, strerror(errno));
  465     }
  466     s->user = ap_pstrdup(p, pw->pw_name);
  467     s->username = s->user;
  468 
  469     s->gid = gid;
  470     gr = getgrgid(gid);
  471     if (gr == NULL) {
  472         return ap_psprintf(p,
  473             "getgrgid() couldn't determine the group name for gid '%ld', "
  474             "you probably need to modify the Group directive: %s",
  475             (long)gid, strerror(errno));
  476     }
  477     s->group = ap_pstrdup(p, gr->gr_name);
  478 
  479 #endif /* !WIN32 */
  480 
  481     return NULL;
  482 }
  483 
  484 /*******************************************************************************
  485  * Allocate an array of ServerProcess records.
  486  */
  487 ServerProcess *
  488 fcgi_util_fs_create_procs(pool *p, int num)
  489 {
  490     int i;
  491     ServerProcess *proc = (ServerProcess *)ap_pcalloc(p, sizeof(ServerProcess) * num);
  492 
  493     for (i = 0; i < num; i++) {
  494 #ifdef WIN32
  495         proc[i].handle = INVALID_HANDLE_VALUE;
  496         proc[i].terminationEvent = INVALID_HANDLE_VALUE;
  497 #endif
  498         proc[i].pid = 0;
  499         proc[i].state = FCGI_READY_STATE;
  500     }
  501     return proc;
  502 }
  503 
  504 int fcgi_util_ticks(struct timeval * tv) 
  505 {
  506 #ifdef WIN32
  507     /* millisecs is sufficent granularity */
  508     DWORD millis = GetTickCount();
  509 
  510     tv->tv_sec = millis / 1000;
  511     tv->tv_usec = (millis % 1000) * 1000;
  512 
  513     return 0;
  514 #else
  515     return gettimeofday(tv, NULL);
  516 #endif
  517 }
  518 
  519