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

Revision 8596, 31.2 KB (checked in by shuangy, 3 years ago)

1. fix two memory leaks in fee_object_attr and decode_release. 2. clean sys-mkdir and acache.

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