root/branches/Orange-Elaine-Distr-Dir-Branch/src/common/misc/pint-util.c @ 8544

Revision 8544, 31.6 KB (checked in by elaine, 3 years ago)

Merged in changes from Orange-Branch. There were a number of bugs fixed there since this branch was created.

Line 
1/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * Changes by Acxiom Corporation to add PINT_check_mode() helper function
5 * as a replacement for check_mode() in permission checking, also added
6 * PINT_check_group() for supplimental group support
7 * Copyright © Acxiom Corporation, 2005.
8 *
9 * See COPYING in top-level directory.
10 */
11
12/* This file includes definitions of common internal utility functions */
13#include <string.h>
14#include <assert.h>
15
16#include <sys/time.h>
17#include <sys/resource.h>
18#include <unistd.h>
19
20#include <grp.h>
21#include <pwd.h>
22#include <sys/types.h>
23
24#define __PINT_REQPROTO_ENCODE_FUNCS_C
25#include "gen-locks.h"
26#include "pint-util.h"
27#include "bmi.h"
28#include "gossip.h"
29#include "pvfs2-debug.h"
30#include <src/common/misc/pvfs2-internal.h>  /* lld(), llu() */
31#include "pvfs2-req-proto.h"
32#include "dist-dir-utils.h"
33
34#include "pvfs2-debug.h"
35#include "bmi-byteswap.h"
36
37#ifdef HAVE_GETPWUID
38static gen_mutex_t check_group_mutex = GEN_MUTEX_INITIALIZER;
39static int pw_buf_size = 1024;      // 1 KB
40static int gr_buf_size = 1024*1024; // 1 MB
41static char* check_group_pw_buffer = NULL;
42static char* check_group_gr_buffer = NULL;
43#endif
44static int PINT_check_group(uid_t uid, gid_t gid);
45
46void PINT_time_mark(PINT_time_marker *out_marker)
47{
48    struct rusage usage;
49
50    gettimeofday(&out_marker->wtime, NULL);
51    getrusage(RUSAGE_SELF, &usage);
52    out_marker->utime = usage.ru_utime;
53    out_marker->stime = usage.ru_stime;
54}
55
56void PINT_time_diff(PINT_time_marker mark1,
57                    PINT_time_marker mark2,
58                    double *out_wtime_sec,
59                    double *out_utime_sec,
60                    double *out_stime_sec)
61{
62    *out_wtime_sec =
63        ((double)mark2.wtime.tv_sec +
64         (double)(mark2.wtime.tv_usec) / 1000000) -
65        ((double)mark1.wtime.tv_sec +
66         (double)(mark1.wtime.tv_usec) / 1000000);
67
68    *out_stime_sec =
69        ((double)mark2.stime.tv_sec +
70         (double)(mark2.stime.tv_usec) / 1000000) -
71        ((double)mark1.stime.tv_sec +
72         (double)(mark1.stime.tv_usec) / 1000000);
73
74    *out_utime_sec =
75        ((double)mark2.utime.tv_sec +
76         (double)(mark2.utime.tv_usec) / 1000000) -
77        ((double)mark1.utime.tv_sec +
78         (double)(mark1.utime.tv_usec) / 1000000);
79}
80
81static int current_tag = 1;
82static gen_mutex_t current_tag_lock = GEN_MUTEX_INITIALIZER;
83
84PVFS_msg_tag_t PINT_util_get_next_tag(void)
85{
86    PVFS_msg_tag_t ret;
87
88    gen_mutex_lock(&current_tag_lock);
89    ret = current_tag;
90
91    /* increment the tag, don't use zero */
92    if (current_tag + 1 == PINT_MSG_TAG_INVALID)
93    {
94        current_tag = 1;
95    }
96    else
97    {
98        current_tag++;
99    }
100    gen_mutex_unlock(&current_tag_lock);
101
102    return ret;
103}
104
105int PINT_copy_object_attr(PVFS_object_attr *dest, PVFS_object_attr *src)
106{
107    int ret = -PVFS_ENOMEM;
108
109    if (dest && src)
110    {
111        if (src->mask & PVFS_ATTR_COMMON_UID)
112        {
113            dest->owner = src->owner;
114        }
115        if (src->mask & PVFS_ATTR_COMMON_GID)
116        {
117            dest->group = src->group;
118        }
119        if (src->mask & PVFS_ATTR_COMMON_PERM)
120        {
121            dest->perms = src->perms;
122        }
123        if (src->mask & PVFS_ATTR_COMMON_ATIME)
124        {
125            dest->atime = src->atime;
126        }
127        if (src->mask & PVFS_ATTR_COMMON_CTIME)
128        {
129            dest->ctime = src->ctime;
130        }
131        if (src->mask & PVFS_ATTR_COMMON_MTIME)
132        {
133            dest->mtime = src->mtime;
134        }
135        if (src->mask & PVFS_ATTR_COMMON_TYPE)
136        {
137            dest->objtype = src->objtype;
138        }
139
140        if (src->mask & PVFS_ATTR_DIR_DIRENT_COUNT)
141        {
142            dest->u.dir.dirent_count =
143                src->u.dir.dirent_count;
144        }
145
146        if (src->mask & PVFS_ATTR_DIR_DISTDIR_ATTR)
147        {
148            PINT_dist_dir_attr_copyto(dest->u.dir.dist_dir_attr, src->u.dir.dist_dir_attr);
149
150            PVFS_size dist_dir_bitmap_size = src->u.dir.dist_dir_attr.bitmap_size *
151                sizeof(PVFS_dist_dir_bitmap_basetype);
152            if (dist_dir_bitmap_size)
153            {
154                if (dest->mask & PVFS_ATTR_DIR_DISTDIR_ATTR)
155                {
156                    if (dest->u.dir.dist_dir_bitmap)
157                    {
158                        free(dest->u.dir.dist_dir_bitmap);
159                        dest->u.dir.dist_dir_bitmap = NULL;
160                    }
161                }
162                dest->u.dir.dist_dir_bitmap = malloc(dist_dir_bitmap_size);
163                if (!dest->u.dir.dist_dir_bitmap)
164                {
165                    return ret;
166                }
167                memcpy(dest->u.dir.dist_dir_bitmap,
168                       src->u.dir.dist_dir_bitmap, dist_dir_bitmap_size);
169            }
170            else
171            {
172                dest->u.dir.dist_dir_bitmap = NULL;
173            }
174
175            PVFS_size dirent_handles_array_size = src->u.dir.dist_dir_attr.num_servers *
176                sizeof(PVFS_handle);
177
178            if (dirent_handles_array_size)
179            {
180                if ((dest->mask & PVFS_ATTR_DIR_DISTDIR_ATTR) &&
181                    dest->u.dir.dist_dir_attr.num_servers > 0)
182                {
183                    if (dest->u.dir.dirdata_handles)
184                    {
185                        free(dest->u.dir.dirdata_handles);
186                        dest->u.dir.dirdata_handles = NULL;
187                    }
188                }
189                dest->u.dir.dirdata_handles = malloc(dirent_handles_array_size);
190                if (!dest->u.dir.dirdata_handles)
191                {
192                    return ret;
193                }
194                memcpy(dest->u.dir.dirdata_handles,
195                       src->u.dir.dirdata_handles, dirent_handles_array_size);
196            }
197            else
198            {
199                dest->u.dir.dirdata_handles = NULL;
200            }
201            dest->u.dir.dist_dir_attr.num_servers = src->u.dir.dist_dir_attr.num_servers;
202        }
203
204        if((src->objtype == PVFS_TYPE_METAFILE) &&
205            (!(src->mask & PVFS_ATTR_META_UNSTUFFED)))
206        {
207            /* if this is a metafile, and does _not_ appear to be stuffed,
208             * then we should propigate the stuffed_size
209             */
210            dest->u.meta.stuffed_size =
211                src->u.meta.stuffed_size;
212        }
213
214        if (src->mask & PVFS_ATTR_DIR_HINT)
215        {
216            dest->u.dir.hint.dfile_count =
217                src->u.dir.hint.dfile_count;
218            dest->u.dir.hint.dist_name_len =
219                src->u.dir.hint.dist_name_len;
220            if (dest->u.dir.hint.dist_name_len > 0)
221            {
222                dest->u.dir.hint.dist_name = strdup(src->u.dir.hint.dist_name);
223                if (dest->u.dir.hint.dist_name == NULL)
224                {
225                    return ret;
226                }
227            }
228            dest->u.dir.hint.dist_params_len =
229                src->u.dir.hint.dist_params_len;
230            if (dest->u.dir.hint.dist_params_len > 0)
231            {
232                dest->u.dir.hint.dist_params
233                        = strdup(src->u.dir.hint.dist_params);
234                if (dest->u.dir.hint.dist_params == NULL)
235                {
236                    free(dest->u.dir.hint.dist_name);
237                    return ret;
238                }
239            }
240        }
241
242        /*
243          NOTE:
244          we only copy the size out if we're actually a
245          datafile object.  sometimes the size field is
246          valid when the objtype is a metafile because
247          of different uses of the acache.  In this case
248          (namely, getattr), the size is stored in the
249          acache before this deep copy, so it's okay
250          that we're not copying here even though the
251          size mask bit is set.
252
253          if we don't do this trick, the metafile that
254          caches the size will have it's union data
255          overwritten with a bunk size.
256        */
257        if ((src->mask & PVFS_ATTR_DATA_SIZE) &&
258            (src->mask & PVFS_ATTR_COMMON_TYPE) &&
259            (src->objtype == PVFS_TYPE_DATAFILE))
260        {
261            dest->u.data.size = src->u.data.size;
262        }
263
264        if ((src->mask & PVFS_ATTR_COMMON_TYPE) &&
265            (src->objtype == PVFS_TYPE_METAFILE))
266        {     
267            if(src->mask & PVFS_ATTR_META_DFILES)
268            {
269                PVFS_size df_array_size = src->u.meta.dfile_count *
270                    sizeof(PVFS_handle);
271
272                if (df_array_size)
273                {
274                    if ((dest->mask & PVFS_ATTR_META_DFILES) &&
275                        dest->u.meta.dfile_count > 0)
276                    {
277                        if (dest->u.meta.dfile_array)
278                        {
279                            free(dest->u.meta.dfile_array);
280                            dest->u.meta.dfile_array = NULL;
281                        }
282                    }
283                    dest->u.meta.dfile_array = malloc(df_array_size);
284                    if (!dest->u.meta.dfile_array)
285                    {
286                        return ret;
287                    }
288                    memcpy(dest->u.meta.dfile_array,
289                           src->u.meta.dfile_array, df_array_size);
290                }
291                else
292                {
293                    dest->u.meta.dfile_array = NULL;
294                }
295                dest->u.meta.dfile_count = src->u.meta.dfile_count;
296            }
297
298          if(src->mask & PVFS_ATTR_META_MIRROR_DFILES)
299            {
300                PVFS_size df_array_size = src->u.meta.dfile_count         *
301                                          src->u.meta.mirror_copies_count *
302                                          sizeof(PVFS_handle);
303
304                if (df_array_size)
305                {
306                    if (   (dest->mask & PVFS_ATTR_META_MIRROR_DFILES)
307                        && (dest->u.meta.dfile_count > 0)
308                        && (dest->u.meta.mirror_copies_count > 0) )
309                    {
310                        if (dest->u.meta.mirror_dfile_array)
311                        {
312                            free(dest->u.meta.mirror_dfile_array);
313                            dest->u.meta.mirror_dfile_array = NULL;
314                        }
315                    }
316                    dest->u.meta.mirror_dfile_array = malloc(df_array_size);
317                    if (!dest->u.meta.mirror_dfile_array)
318                    {
319                        return ret;
320                    }
321                    memcpy(dest->u.meta.mirror_dfile_array,
322                           src->u.meta.mirror_dfile_array, df_array_size);
323                }
324                else
325                {
326                    dest->u.meta.mirror_dfile_array = NULL;
327                }
328                dest->u.meta.mirror_copies_count
329                   = src->u.meta.mirror_copies_count;
330            }
331
332
333            if(src->mask & PVFS_ATTR_META_DIST)
334            {
335                assert(src->u.meta.dist_size > 0);
336
337                if ((dest->mask & PVFS_ATTR_META_DIST) && dest->u.meta.dist)
338                {
339                    PINT_dist_free(dest->u.meta.dist);
340                }
341                dest->u.meta.dist = PINT_dist_copy(src->u.meta.dist);
342                if (dest->u.meta.dist == NULL)
343                {
344                    return ret;
345                }
346                dest->u.meta.dist_size = src->u.meta.dist_size;
347            }
348            memcpy(&dest->u.meta.hint, &src->u.meta.hint, sizeof(dest->u.meta.hint));
349        }
350
351        if (src->mask & PVFS_ATTR_SYMLNK_TARGET)
352        {
353            dest->u.sym.target_path_len = src->u.sym.target_path_len;
354            dest->u.sym.target_path = strdup(src->u.sym.target_path);
355            if (dest->u.sym.target_path == NULL)
356            {
357                return ret;
358            }
359        }
360
361        dest->mask = src->mask;
362        ret = 0;
363    }
364    return ret;
365}
366
367void PINT_free_object_attr(PVFS_object_attr *attr)
368{
369    if (attr)
370    {
371        if (attr->objtype == PVFS_TYPE_METAFILE)
372        {
373            if (attr->mask & PVFS_ATTR_META_DFILES)
374            {
375                if (attr->u.meta.dfile_array)
376                {
377                    free(attr->u.meta.dfile_array);
378                    attr->u.meta.dfile_array = NULL;
379                }
380            }
381            if (attr->mask & PVFS_ATTR_META_MIRROR_DFILES)
382            {
383                if (attr->u.meta.mirror_dfile_array)
384                {
385                    free(attr->u.meta.mirror_dfile_array);
386                    attr->u.meta.mirror_dfile_array = NULL;
387                }
388            }
389            if (attr->mask & PVFS_ATTR_META_DIST)
390            {
391                if (attr->u.meta.dist)
392                {
393                    PINT_dist_free(attr->u.meta.dist);
394                    attr->u.meta.dist = NULL;
395                }
396            }
397        }
398        else if (attr->objtype == PVFS_TYPE_SYMLINK)
399        {
400            if (attr->mask & PVFS_ATTR_SYMLNK_TARGET)
401            {
402                if ((attr->u.sym.target_path_len > 0) &&
403                    attr->u.sym.target_path)
404                {
405                    free(attr->u.sym.target_path);
406                    attr->u.sym.target_path = NULL;
407                }
408            }
409        }
410        else if (attr->objtype == PVFS_TYPE_DIRECTORY)
411        {
412            if (attr->mask & PVFS_ATTR_DIR_HINT)
413            {
414                if (attr->u.dir.hint.dist_name)
415                {
416                    free(attr->u.dir.hint.dist_name);
417                    attr->u.dir.hint.dist_name = NULL;
418                }
419                if (attr->u.dir.hint.dist_params)
420                {
421                    free(attr->u.dir.hint.dist_params);
422                    attr->u.dir.hint.dist_params = NULL;
423                }
424            }
425            if (attr->mask & PVFS_ATTR_DIR_DISTDIR_ATTR)
426            {
427                if (attr->u.dir.dist_dir_bitmap)
428                {
429                    free(attr->u.dir.dist_dir_bitmap);
430                    attr->u.dir.dist_dir_bitmap = NULL;
431                }
432                if (attr->u.dir.dirdata_handles)
433                {
434                    free(attr->u.dir.dirdata_handles);
435                    attr->u.dir.dirdata_handles = NULL;
436                }
437            }
438        }
439    }
440}
441
442char *PINT_util_get_object_type(int objtype)
443{
444    static char *obj_types[] =
445    {
446         "NONE", "METAFILE", "DATAFILE",
447         "DIRECTORY", "SYMLINK", "DIRDATA", "UNKNOWN"
448    };
449    switch(objtype)
450    {
451    case PVFS_TYPE_NONE:
452         return obj_types[0];
453    case PVFS_TYPE_METAFILE:
454         return obj_types[1];
455    case PVFS_TYPE_DATAFILE:
456         return obj_types[2];
457    case PVFS_TYPE_DIRECTORY:
458         return obj_types[3];
459    case PVFS_TYPE_SYMLINK:
460         return obj_types[4];
461    case PVFS_TYPE_DIRDATA:
462         return obj_types[5];
463    }
464    return obj_types[6];
465}
466
467void PINT_util_get_current_timeval(struct timeval *tv)
468{
469    gettimeofday(tv, NULL);
470}
471
472int PINT_util_get_timeval_diff(struct timeval *tv_start, struct timeval *tv_end)
473{
474    return (tv_end->tv_sec * 1e6 + tv_end->tv_usec) -
475        (tv_start->tv_sec * 1e6 + tv_start->tv_usec);
476}
477
478
479PVFS_time PINT_util_get_current_time(void)
480{
481    struct timeval t = {0,0};
482    PVFS_time current_time = 0;
483
484    gettimeofday(&t, NULL);
485    current_time = (PVFS_time)t.tv_sec;
486    return current_time;
487}
488
489PVFS_time PINT_util_mktime_version(PVFS_time time)
490{
491    struct timeval t = {0,0};
492    PVFS_time version = (time << 32);
493
494    gettimeofday(&t, NULL);
495    version |= (PVFS_time)t.tv_usec;
496    return version;
497}
498
499PVFS_time PINT_util_mkversion_time(PVFS_time version)
500{
501    return (PVFS_time)(version >> 32);
502}
503
504struct timespec PINT_util_get_abs_timespec(int microsecs)
505{
506    struct timeval now, add, result;
507    struct timespec tv;
508
509    gettimeofday(&now, NULL);
510    add.tv_sec = (microsecs / 1e6);
511    add.tv_usec = (microsecs % 1000000);
512    timeradd(&now, &add, &result);
513    tv.tv_sec = result.tv_sec;
514    tv.tv_nsec = result.tv_usec * 1e3;
515    return tv;
516}
517
518void PINT_util_gen_credentials(
519    PVFS_credentials *credentials)
520{
521    assert(credentials);
522
523    memset(credentials, 0, sizeof(PVFS_credentials));
524    credentials->uid = geteuid();
525    credentials->gid = getegid();
526}
527
528inline void encode_PVFS_BMI_addr_t(char **pptr, const PVFS_BMI_addr_t *x)
529{
530    const char *addr_str;
531
532    addr_str = BMI_addr_rev_lookup(*x);
533    encode_string(pptr, &addr_str);
534}
535
536/* determines how much protocol space a BMI_addr_t encoding will consume */
537inline int encode_PVFS_BMI_addr_t_size_check(const PVFS_BMI_addr_t *x)
538{
539    const char *addr_str;
540    addr_str = BMI_addr_rev_lookup(*x);
541    return(encode_string_size_check(&addr_str));
542}
543
544inline void decode_PVFS_BMI_addr_t(char **pptr, PVFS_BMI_addr_t *x)
545{
546    char *addr_string;
547    decode_string(pptr, &addr_string);
548    BMI_addr_lookup(x, addr_string);
549}
550
551inline void encode_PVFS_sys_layout(char **pptr, const struct PVFS_sys_layout_s *x)
552{
553    int tmp_size;
554    int i;
555
556    /* figure out how big this encoding will be first */
557
558    tmp_size = 16; /* enumeration and list count */
559    for(i=0 ; i<x->server_list.count; i++)
560    {
561        /* room for each server encoding */
562        tmp_size += encode_PVFS_BMI_addr_t_size_check(&(x)->server_list.servers[i]);
563    }
564
565    if(tmp_size > PVFS_REQ_LIMIT_LAYOUT)
566    {
567        /* don't try to encode everything.  Just set pptr too high so that
568         * we hit error condition in encode function
569         */
570        gossip_err("Error: layout too large to encode in request protocol.\n");
571        *(pptr) += extra_size_PVFS_servreq_create + 1;
572        return;
573    }
574
575    /* otherwise we are in business */
576    encode_enum(pptr, &x->algorithm);
577    encode_skip4(pptr, NULL);
578    encode_int32_t(pptr, &x->server_list.count);
579    encode_skip4(pptr, NULL);
580    for(i=0 ; i<x->server_list.count; i++)
581    {
582        encode_PVFS_BMI_addr_t(pptr, &(x)->server_list.servers[i]);
583    }
584}
585
586inline void decode_PVFS_sys_layout(char **pptr, struct PVFS_sys_layout_s *x)
587{
588    int i;
589
590    decode_enum(pptr, &x->algorithm);
591    decode_skip4(pptr, NULL);
592    decode_int32_t(pptr, &x->server_list.count);
593    decode_skip4(pptr, NULL);
594    if(x->server_list.count)
595    {
596        x->server_list.servers = malloc(x->server_list.count*sizeof(*(x->server_list.servers)));
597        assert(x->server_list.servers);
598    }
599    for(i=0 ; i<x->server_list.count; i++)
600    {
601        decode_PVFS_BMI_addr_t(pptr, &(x)->server_list.servers[i]);
602    }
603}
604
605char *PINT_util_guess_alias(void)
606{
607    char tmp_alias[1024];
608    char *tmpstr;
609    char *alias;
610    int ret;
611
612    /* hmm...failed to find alias as part of the server config filename,
613     * use the hostname to guess
614     */
615    ret = gethostname(tmp_alias, 1024);
616    if(ret != 0)
617    {
618        gossip_err("Failed to get hostname while attempting to guess "
619                   "alias.  Use -a to specify the alias for this server "
620                   "process directly\n");
621        return NULL;
622    }
623    alias = tmp_alias;
624
625    tmpstr = strstr(tmp_alias, ".");
626    if(tmpstr)
627    {
628        *tmpstr = 0;
629    }
630    return strdup(tmp_alias);
631}
632
633/* PINT_check_mode()
634 *
635 * checks to see if the type of access described by "access_type" is permitted
636 * for user "uid" of group "gid" on the object with attributes "attr"
637 *
638 * returns 0 on success, -PVFS_EACCES if permission is not granted
639 */
640int PINT_check_mode(
641    PVFS_object_attr *attr,
642    PVFS_uid uid, PVFS_gid gid,
643    enum PINT_access_type access_type)
644{
645    int in_group_flag = 0;
646    int ret = 0;
647
648    /* if we don't have masks for the permission information that we
649     * need, then the system is broken
650     */
651    assert(attr->mask & PVFS_ATTR_COMMON_UID &&
652           attr->mask & PVFS_ATTR_COMMON_GID &&
653           attr->mask & PVFS_ATTR_COMMON_PERM);
654    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - check_mode called --- "
655                 "(uid=%d,gid=%d,access_type=%d)\n", uid, gid, access_type);
656    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - object attributes --- "
657                 "(uid=%d,gid=%d,mode=%d)\n", attr->owner, attr->group,
658                 attr->perms);
659
660    /* give root permission, no matter what */
661    gossip_debug(GOSSIP_PERMISSIONS_DEBUG,
662                 " - checking if uid (%d) is root ...\n", uid);
663    if (uid == 0)
664    {
665        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
666        return 0;
667    }
668    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
669
670    /* see if uid matches object owner */
671    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if owner (%d) "
672        "matches uid (%d)...\n", attr->owner, uid);
673    if(attr->owner == uid)
674    {
675        /* see if object user permissions match access type */
676        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
677        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if permissions "
678            "(%d) allows access type (%d) for user...\n", attr->perms, access_type);
679        if(access_type == PINT_ACCESS_READABLE && (attr->perms &
680            PVFS_U_READ))
681        {
682            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
683            return(0);
684        }
685        if(access_type == PINT_ACCESS_WRITABLE && (attr->perms &
686            PVFS_U_WRITE))
687        {
688            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
689            return(0);
690        }
691        if(access_type == PINT_ACCESS_EXECUTABLE && (attr->perms &
692            PVFS_U_EXECUTE))
693        {
694            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
695            return(0);
696        }
697        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
698    }
699    else
700    {
701        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
702    }
703
704    /* see if other bits allow access */
705    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if permissions "
706        "(%d) allows access type (%d) by others...\n", attr->perms, access_type);
707    if(access_type == PINT_ACCESS_READABLE && (attr->perms &
708        PVFS_O_READ))
709    {
710        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
711        return(0);
712    }
713    if(access_type == PINT_ACCESS_WRITABLE && (attr->perms &
714        PVFS_O_WRITE))
715    {
716        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
717        return(0);
718    }
719    if(access_type == PINT_ACCESS_EXECUTABLE && (attr->perms &
720        PVFS_O_EXECUTE))
721    {
722        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
723        return(0);
724    }
725    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
726
727    /* see if gid matches object group */
728    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if group (%d) "
729        "matches gid (%d)...\n", attr->group, gid);
730    if(attr->group == gid)
731    {
732        /* default group match */
733        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
734        in_group_flag = 1;
735    }
736    else
737    {
738        /* no default group match, check supplementary groups */
739        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
740        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking for"
741            " supplementary group match...\n");
742        ret = PINT_check_group(uid, attr->group);
743        if(ret == 0)
744        {
745            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
746            in_group_flag = 1;
747        }
748        else
749        {
750            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
751            if(ret != -PVFS_ENOENT)
752            {
753                /* system error; not just failed match */
754                return(ret);
755            }
756        }
757    }
758
759    if(in_group_flag)
760    {
761        /* see if object group permissions match access type */
762        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - checking if permissions "
763            "(%d) allows access type (%d) for group...\n", attr->perms, access_type);
764        if(access_type == PINT_ACCESS_READABLE && (attr->perms &
765            PVFS_G_READ))
766        {
767            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
768            return(0);
769        }
770        if(access_type == PINT_ACCESS_WRITABLE && (attr->perms &
771            PVFS_G_WRITE))
772        {
773            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
774            return(0);
775        }
776        if(access_type == PINT_ACCESS_EXECUTABLE && (attr->perms &
777            PVFS_G_EXECUTE))
778        {
779            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - yes\n");
780            return(0);
781        }
782        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, " - no\n");
783    }
784 
785    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "******PINT_check_mode: denying access\n");
786    /* default case: access denied */
787    return -PVFS_EACCES;
788}
789
790/* PINT_check_group()
791 *
792 * checks to see if uid is a member of gid
793 *
794 * returns 0 on success, -PVFS_ENOENT if not a member, other PVFS error codes
795 * on system failure
796 */
797static int PINT_check_group(uid_t uid, gid_t gid)
798{
799#ifdef HAVE_GETPWUID
800    struct passwd pwd;
801    struct passwd* pwd_p = NULL;
802    struct group grp;
803    struct group* grp_p = NULL;
804    int i = 0;
805    int ret = -1;
806
807    /* Explanation:
808     *
809     * We use the _r variants of getpwuid and getgrgid in order to insure
810     * thread safety; particularly if this function ever gets called in a
811     * client side situation in which we can't prevent the application from
812     * making conflicting calls.
813     *
814     * These _r functions require that a buffer be supplied for the user and
815     * group information, however.  These buffers may be unconfortably large
816     * for the stack, so we malloc them on a static pointer and then mutex
817     * lock this function so that it can still be reentrant.
818     */
819
820    gen_mutex_lock(&check_group_mutex);
821
822    if(!check_group_pw_buffer)
823    {
824        check_group_pw_buffer = (char*)malloc(pw_buf_size);
825        check_group_gr_buffer = (char*)malloc(gr_buf_size);
826        if(!check_group_pw_buffer || !check_group_gr_buffer)
827        {
828            if(check_group_pw_buffer)
829            {
830                free(check_group_pw_buffer);
831                check_group_pw_buffer = NULL;
832            }
833            if(check_group_gr_buffer)
834            {
835                free(check_group_gr_buffer);
836                check_group_gr_buffer = NULL;
837            }
838            gen_mutex_unlock(&check_group_mutex);
839            return(-PVFS_ENOMEM);
840        }
841    }
842
843    /* get user information */
844    ret = getpwuid_r(uid, &pwd, check_group_pw_buffer, pw_buf_size, &pwd_p);
845    if(ret != 0 || pwd_p == NULL)
846    {
847        gen_mutex_unlock(&check_group_mutex);
848        gossip_err("Get user info for (uid=%d) failed."
849                   "errno [%d] error_msg [%s]\n",
850                   uid, ret, strerror(ret));
851        return(-PVFS_EINVAL);
852    }
853
854    /* check primary group */
855    if(pwd.pw_gid == gid)
856    {
857        gen_mutex_unlock(&check_group_mutex);
858        return 0;
859    }
860
861    /* get the members of the group */
862    ret = getgrgid_r(gid, &grp, check_group_gr_buffer, gr_buf_size, &grp_p);
863    if(ret != 0 || grp_p == NULL)
864    {
865      gen_mutex_unlock(&check_group_mutex);
866      gossip_err("Get members for group (gid=%d) failed."
867                 "errno [%d] error_msg [%s]\n",
868                 gid, ret, strerror(ret));
869      return(-PVFS_EINVAL);
870    }
871
872    for(i = 0; grp.gr_mem[i] != NULL; i++)
873    {
874        if(0 == strcmp(pwd.pw_name, grp.gr_mem[i]))
875        {
876            gen_mutex_unlock(&check_group_mutex);
877            return 0;
878        }
879    }
880
881    gen_mutex_unlock(&check_group_mutex);
882    return(-PVFS_ENOENT);
883#else
884    return 0;
885#endif
886}
887
888/* Checks if a given user is part of any groups that matches the file gid */
889static int in_group_p(PVFS_uid uid, PVFS_gid gid, PVFS_gid attr_group)
890{
891    if (attr_group == gid)
892        return 1;
893    if (PINT_check_group(uid, attr_group) == 0)
894        return 1;
895    return 0;
896}
897
898/*
899 * Return 0 if requesting clients is granted want access to the object
900 * by the acl. Returns -PVFS_E... otherwise.
901 */
902int PINT_check_acls(void *acl_buf, size_t acl_size,
903    PVFS_object_attr *attr,
904    PVFS_uid uid, PVFS_gid gid, int want)
905{
906    pvfs2_acl_entry pe, *pa;
907    int i = 0, found = 0, count = 0;
908    assert(attr->mask & PVFS_ATTR_COMMON_UID &&
909           attr->mask & PVFS_ATTR_COMMON_GID &&
910           attr->mask & PVFS_ATTR_COMMON_PERM);
911
912    if (acl_size == 0)
913    {
914        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "no acl's present.. denying access\n");
915        return -PVFS_EACCES;
916    }
917
918    /* keyval for ACLs includes a \0. so subtract the thingie */
919    acl_size--;
920    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "PINT_check_acls: read keyval size "
921    " %d (%d acl entries)\n",
922        (int) acl_size,
923        (int) (acl_size / sizeof(pvfs2_acl_entry)));
924    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "uid = %d, gid = %d, want = %d\n",
925        uid, gid, want);
926
927    assert(acl_buf);
928    /* if the acl format doesn't look valid, then return an error rather than
929     * asserting; we don't want the server to crash due to an invalid keyval
930     */
931    if((acl_size % sizeof(pvfs2_acl_entry)) != 0)
932    {
933        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "invalid acls on object\n");
934        return(-PVFS_EACCES);
935    }
936    count = acl_size / sizeof(pvfs2_acl_entry);
937
938    for (i = 0; i < count; i++)
939    {
940        pa = (pvfs2_acl_entry *) acl_buf + i;
941        /*
942           NOTE: Remember that keyval is encoded as lebf, so convert it
943           to host representation
944        */
945        pe.p_tag  = bmitoh32(pa->p_tag);
946        pe.p_perm = bmitoh32(pa->p_perm);
947        pe.p_id   = bmitoh32(pa->p_id);
948        pa = &pe;
949        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "Decoded ACL entry %d "
950            "(p_tag %d, p_perm %d, p_id %d)\n",
951            i, pa->p_tag, pa->p_perm, pa->p_id);
952        switch(pa->p_tag)
953        {
954            case PVFS2_ACL_USER_OBJ:
955                /* (May have been checked already) */
956                if (attr->owner == uid)
957                    goto check_perm;
958                break;
959            case PVFS2_ACL_USER:
960                if (pa->p_id == uid)
961                    goto mask;
962                break;
963            case PVFS2_ACL_GROUP_OBJ:
964                if (in_group_p(uid, gid, attr->group))
965                {
966                    found = 1;
967                    if ((pa->p_perm & want) == want)
968                        goto mask;
969                }
970                break;
971            case PVFS2_ACL_GROUP:
972                if (in_group_p(uid, gid, pa->p_id)) {
973                    found = 1;
974                    if ((pa->p_perm & want) == want)
975                        goto mask;
976                }
977                break;
978            case PVFS2_ACL_MASK:
979                break;
980            case PVFS2_ACL_OTHER:
981                if (found)
982                {
983                    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "(1) PINT_check_acls:"
984                        "returning access denied\n");
985                    return -PVFS_EACCES;
986                }
987                else
988                    goto check_perm;
989            default:
990                gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "(2) PINT_check_acls: "
991                        "returning EIO\n");
992                return -PVFS_EIO;
993        }
994    }
995    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "(3) PINT_check_acls: returning EIO\n");
996    return -PVFS_EIO;
997mask:
998    /* search the remaining entries */
999    i = i + 1;
1000    for (; i < count; i++)
1001    {
1002        pvfs2_acl_entry me, *mask_obj = (pvfs2_acl_entry *) acl_buf + i;
1003       
1004        /*
1005          NOTE: Again, since pvfs2_acl_entry is in lebf, we need to
1006          convert it to host endian format
1007         */
1008        me.p_tag  = bmitoh32(mask_obj->p_tag);
1009        me.p_perm = bmitoh32(mask_obj->p_perm);
1010        me.p_id   = bmitoh32(mask_obj->p_id);
1011        mask_obj = &me;
1012        gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "Decoded (mask) ACL entry %d "
1013            "(p_tag %d, p_perm %d, p_id %d)\n",
1014            i, mask_obj->p_tag, mask_obj->p_perm, mask_obj->p_id);
1015        if (mask_obj->p_tag == PVFS2_ACL_MASK)
1016        {
1017            if ((pa->p_perm & mask_obj->p_perm & want) == want)
1018                return 0;
1019            gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "(4) PINT_check_acls:"
1020                "returning access denied (mask)\n");
1021            return -PVFS_EACCES;
1022        }
1023    }
1024
1025check_perm:
1026    if ((pa->p_perm & want) == want)
1027        return 0;
1028    gossip_debug(GOSSIP_PERMISSIONS_DEBUG, "(5) PINT_check_acls: returning"
1029            "access denied\n");
1030    return -PVFS_EACCES;
1031}
1032
1033/*
1034 * Local variables:
1035 *  c-indent-level: 4
1036 *  c-basic-offset: 4
1037 * End:
1038 *
1039 * vim: ts=8 sts=4 sw=4 expandtab
1040 */
Note: See TracBrowser for help on using the browser.