root/branches/cu-security-branch/src/server/set-attr.sm @ 8362

Revision 8362, 17.9 KB (checked in by nlmills, 3 years ago)

cleaned up credential verification

Line 
1/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * See COPYING in top-level directory.
5 */
6
7#include <string.h>
8#include <assert.h>
9
10#include "server-config.h"
11#include "pvfs2-server.h"
12#include "pvfs2-attr.h"
13#include "pvfs2-util.h"
14#include "pvfs2-internal.h"
15#include "pint-util.h"
16#include "pint-security.h"
17
18enum
19{
20    STATE_METAFILE = 7,
21    STATE_SYMLINK = 8
22};
23
24%%
25
26machine pvfs2_set_attr_sm
27{
28    state prelude
29    {
30        jump pvfs2_prelude_sm;
31        success => verify_attribs;
32        default => final_response;
33    }
34
35    state verify_attribs
36    {
37        run setattr_verify_attribs;
38        STATE_METAFILE => write_metafile_datafile_handles_if_required;
39        STATE_SYMLINK => write_symlink_target_if_required;
40        success => setobj_attrib;
41        default => final_response;
42    }
43
44    state write_metafile_datafile_handles_if_required
45    {
46        run setattr_write_metafile_datafile_handles_if_required;
47        success => write_metafile_distribution_if_required;
48        default => final_response;
49    }
50
51    state write_metafile_distribution_if_required
52    {
53        run setattr_write_metafile_distribution_if_required;
54        success => setobj_attrib;
55        default => final_response;
56    }
57
58    state write_symlink_target_if_required
59    {
60        run setattr_write_symlink_target_if_required;
61        success => setobj_attrib;
62        default => final_response;
63    }
64
65    state setobj_attrib
66    {
67        run setattr_setobj_attribs;
68        default => final_response;
69    }
70
71    state final_response
72    {
73        jump pvfs2_final_response_sm;
74        default => cleanup;
75    }
76
77    state cleanup
78    {
79        run setattr_cleanup;
80        default => terminate;
81    }
82}
83
84%%
85
86static PINT_sm_action setattr_verify_attribs(
87        struct PINT_smcb *smcb, job_status_s *js_p)
88{
89    struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
90    PVFS_object_attr *a_p = NULL, *req_a_p = NULL;
91
92    a_p = &s_op->attr;
93    req_a_p = &s_op->req->u.setattr.attr;
94
95    gossip_debug(GOSSIP_SETATTR_DEBUG, "  attrs read from dspace:\n\t"
96                 "[owner = %d, group = %d, perms = %o, type = %d]\n",
97                 a_p->owner, a_p->group, a_p->perms, a_p->objtype);
98
99    gossip_debug(GOSSIP_SETATTR_DEBUG, "  attrs read from request:\n\t"
100                 "[owner = %d, group = %d, perms = %o, type = %d]\n",
101                 (req_a_p->mask & PVFS_ATTR_COMMON_UID)  ? req_a_p->owner : -1,
102                 (req_a_p->mask & PVFS_ATTR_COMMON_GID)  ? req_a_p->group : -1,
103                 (req_a_p->mask & PVFS_ATTR_COMMON_PERM) ? req_a_p->perms : -1,
104                 (req_a_p->mask & PVFS_ATTR_COMMON_TYPE) ? req_a_p->objtype : -1);
105    /*
106      here we're enforcing that no one can change the type of the
107      handle/object already stored once it's been set to a non-zero
108      value.  (zero is not a valid object type meaning that it hasn't
109      been assigned yet)
110    */
111    if (a_p->objtype && req_a_p->objtype &&
112        (a_p->objtype != req_a_p->objtype))
113    {
114        gossip_debug(GOSSIP_SETATTR_DEBUG, "  handle %llu is of type %d "
115                     "and cannot be changed to type %d\n",
116                     llu(s_op->req->u.setattr.handle),
117                     a_p->objtype, s_op->req->u.setattr.attr.objtype);
118
119        /* set an error to bail out of set-attr processing */
120        js_p->error_code = -PVFS_EACCES;
121        return SM_ACTION_COMPLETE;
122    }
123    else if (req_a_p->objtype == PVFS_TYPE_NONE)
124    {
125        /* if the requested object type is PVFS_TYPE_NONE, then the
126         * setattr is only on the common attributes, so we use the
127         * actual object type
128         */
129        req_a_p->objtype = a_p->objtype;
130    }
131
132    js_p->error_code = 0;
133
134    if ((req_a_p->objtype == PVFS_TYPE_METAFILE) ||
135        (a_p->objtype == PVFS_TYPE_METAFILE))
136    {
137        gossip_debug(GOSSIP_SETATTR_DEBUG,
138                     "  handle %llu refers to a metafile\n",
139                     llu(s_op->req->u.setattr.handle));
140
141        gossip_debug(
142            GOSSIP_SETATTR_DEBUG, " *** dspace has dfile count %d and "
143            "req has dfile count %d\n",
144            a_p->u.meta.dfile_count, req_a_p->u.meta.dfile_count);
145        gossip_debug(
146            GOSSIP_SETATTR_DEBUG, " *** dspace has dist size %d and "
147            "req has dist size %d\n",
148            a_p->u.meta.dist_size, req_a_p->u.meta.dist_size);
149
150        /* copy the dfile count before writing this object */
151        if (req_a_p->mask & PVFS_ATTR_META_DFILES)
152        {
153            gossip_debug(
154                GOSSIP_SETATTR_DEBUG," *** using dfile_count of %d\n",
155                req_a_p->u.meta.dfile_count);
156            a_p->u.meta.dfile_count = req_a_p->u.meta.dfile_count;
157            js_p->error_code = STATE_METAFILE;
158        }
159        else
160        {
161            gossip_debug(GOSSIP_SETATTR_DEBUG,
162                         " *** ignoring dfile_count of %d\n",
163                         req_a_p->u.meta.dfile_count);
164        }
165
166        /* copy the dist size before writing this object */
167        if (req_a_p->mask & PVFS_ATTR_META_DIST)
168        {
169            gossip_debug(GOSSIP_SETATTR_DEBUG,
170                         " *** using dist_size of %d\n",
171                         req_a_p->u.meta.dist_size);
172            a_p->u.meta.dist_size = req_a_p->u.meta.dist_size;
173            js_p->error_code = STATE_METAFILE;
174        }
175        else
176        {
177            gossip_debug(GOSSIP_SETATTR_DEBUG,
178                         " *** ignoring dist_size of %d\n",
179                         req_a_p->u.meta.dist_size);
180        }
181    }
182    else if ((req_a_p->objtype == PVFS_TYPE_DATAFILE) ||
183             (a_p->objtype == PVFS_TYPE_DATAFILE))
184    {
185        gossip_debug(GOSSIP_SETATTR_DEBUG,
186                     "  handle %llu refers to a datafile\n",
187                     llu(s_op->req->u.setattr.handle));
188    }
189    else if ((req_a_p->objtype == PVFS_TYPE_DIRECTORY) ||
190             (a_p->objtype == PVFS_TYPE_DIRECTORY))
191    {
192        gossip_debug(GOSSIP_SETATTR_DEBUG,
193                     "  handle %llu refers to a directory\n",
194                     llu(s_op->req->u.setattr.handle));
195    }
196    else if ((req_a_p->objtype == PVFS_TYPE_SYMLINK) ||
197             (a_p->objtype == PVFS_TYPE_SYMLINK))
198    {
199        gossip_debug(GOSSIP_SETATTR_DEBUG,
200                     "  handle %llu refers to a symlink\n",
201                     llu(s_op->req->u.setattr.handle));
202
203        if (req_a_p->mask & PVFS_ATTR_SYMLNK_ALL)
204        {
205            assert(req_a_p->u.sym.target_path_len > 0);
206            assert(req_a_p->u.sym.target_path);
207
208            gossip_debug(GOSSIP_SETATTR_DEBUG,
209                         " symlink links handle %llu to %s\n",
210                         llu(s_op->req->u.setattr.handle),
211                         req_a_p->u.sym.target_path);
212
213            a_p->u.sym.target_path_len = req_a_p->u.sym.target_path_len;
214            a_p->u.sym.target_path = req_a_p->u.sym.target_path;
215        }
216        js_p->error_code = STATE_SYMLINK;
217    }
218    else if ((req_a_p->objtype == PVFS_TYPE_DIRDATA) ||
219             (a_p->objtype == PVFS_TYPE_DIRDATA))
220    {
221        gossip_debug(GOSSIP_SETATTR_DEBUG,
222                     "  handle %llu refers to a dirdata object\n",
223                     llu(s_op->req->u.setattr.handle));
224    }
225    else
226    {
227        gossip_debug(GOSSIP_SETATTR_DEBUG,
228                     "  handle %llu refers to something unknown\n",
229                     llu(s_op->req->u.setattr.handle));
230
231        js_p->error_code = -PVFS_EACCES;
232    }
233
234    /* verify that the user has permission to change the file's owner */
235    if (req_a_p->mask & PVFS_ATTR_COMMON_UID)
236    {
237        if (!(s_op->req->capability.op_mask & PINT_CAP_ADMIN) &&
238            (s_op->req->u.setattr.credential.userid != req_a_p->owner))
239        {
240            js_p->error_code = -PVFS_EPERM;
241        }
242    }
243
244    /* verify that the user has permission to change the file's group */
245    if (req_a_p->mask & PVFS_ATTR_COMMON_GID)
246    {
247        PVFS_credential *cred = &s_op->req->u.setattr.credential;
248        int i;
249
250        if (!(s_op->req->capability.op_mask & PINT_CAP_ADMIN))
251        {
252            for (i = 0; i < cred->num_groups; i++)
253            {
254                if (cred->group_array[i] == req_a_p->group)
255                {
256                    break;
257                }
258            }
259            /* no group matches */
260            if (i >= cred->num_groups)
261            {
262                js_p->error_code = -PVFS_EPERM;
263            }
264        }
265    }
266
267    return SM_ACTION_COMPLETE;
268}
269
270static PINT_sm_action setattr_setobj_attribs(
271        struct PINT_smcb *smcb, job_status_s *js_p)
272{
273    struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
274    int ret = -1;
275    job_id_t j_id;
276    PVFS_object_attr *a_p = NULL;
277    PVFS_object_attr *dspace_a_p = NULL;
278    PVFS_ds_attributes *ds_attr = NULL;
279
280    dspace_a_p = &s_op->attr;
281    a_p = &s_op->req->u.setattr.attr;
282
283    if (a_p->mask & PVFS_ATTR_META_DFILES)
284    {
285        gossip_debug(GOSSIP_SETATTR_DEBUG, " request has dfile_count of "
286                     "%d | dspace has %d\n",
287                     s_op->req->u.setattr.attr.u.meta.dfile_count,
288                     s_op->attr.u.meta.dfile_count);
289
290        gossip_debug(GOSSIP_SETATTR_DEBUG, " writing count of %d to "
291                     "disk\n", dspace_a_p->u.meta.dfile_count);
292    }
293    /*
294     * Remember that mtime is versioned on disk! so convert it here..
295     * It is better to do it here than change the PVFS_object_attr_overwrite_setable
296     * macro, since there are many more users of it, I think.
297     */
298     if (a_p->mask & PVFS_ATTR_COMMON_MTIME_SET)
299     {
300         PVFS_time orig_mtime = a_p->mtime;
301         a_p->mtime = PINT_util_mktime_version(orig_mtime);
302         gossip_debug(GOSSIP_SETATTR_DEBUG, "setting version "
303                 "to %llu\n\tmtime is %llu\n",
304                 llu(a_p->mtime), llu(orig_mtime));
305     }
306
307    /* if the object is a symbolic link, check to make sure that the request
308     * is not attempting to change the permissions
309     */
310    if(dspace_a_p->objtype == PVFS_TYPE_SYMLINK)
311    {
312        if (dspace_a_p->perms != 0 && ((a_p->mask & PVFS_ATTR_COMMON_PERM) && (dspace_a_p->perms != a_p->perms)))
313        {
314            gossip_debug(GOSSIP_SETATTR_DEBUG, "Cannot change perms of symlink: Permission denied\n");
315            js_p->error_code = -PVFS_EPERM;
316            return SM_ACTION_COMPLETE;
317        }
318    }
319
320    /*
321      we have the attribs stored in the dspace, as well as the
322      requested attribs to store.  overwrite the ones that are setable
323      and specified by the mask value in the request; macro defined in
324      pvfs2-storage.h
325    */
326    PVFS_object_attr_overwrite_setable(dspace_a_p, a_p);
327
328    gossip_debug(
329        GOSSIP_SETATTR_DEBUG,
330        "  WRITING attrs: [owner = %d, group = %d\n\t"
331        "perms = %o, type = %d, atime = %llu, mtime = %llu\n\t"
332        "ctime = %llu | dfile_count = %d | dist_size = %d]\n",
333        dspace_a_p->owner, dspace_a_p->group, dspace_a_p->perms,
334        dspace_a_p->objtype, llu(dspace_a_p->atime),
335        llu(PINT_util_mkversion_time(dspace_a_p->mtime)), llu(dspace_a_p->ctime),
336        (int)dspace_a_p->u.meta.dfile_count,
337        (int)dspace_a_p->u.meta.dist_size);
338
339    /* translate attrs to storage attr format */
340    ds_attr = &(s_op->ds_attr);
341    PVFS_object_attr_to_ds_attr(dspace_a_p, ds_attr);
342
343    ret = job_trove_dspace_setattr(
344        s_op->req->u.setattr.fs_id, s_op->req->u.setattr.handle,
345        ds_attr,
346        TROVE_SYNC,
347        smcb, 0, js_p, &j_id, server_job_context, s_op->req->hints);
348
349    return ret;
350}
351
352static PINT_sm_action setattr_write_metafile_datafile_handles_if_required(
353        struct PINT_smcb *smcb, job_status_s *js_p)
354{
355    struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
356    int ret = 0, dfile_count = 0;
357    job_id_t j_id;
358
359    /* reset from jump to here with STATE_METAFILE */
360    js_p->error_code = 0;
361
362    gossip_debug(GOSSIP_SETATTR_DEBUG,
363                 " request has dfile_count of %d | dspace has %d\n",
364                 s_op->req->u.setattr.attr.u.meta.dfile_count,
365                 s_op->attr.u.meta.dfile_count);
366
367    /* verify that the requested dfile count is sane */
368    dfile_count = s_op->req->u.setattr.attr.u.meta.dfile_count;
369    if ((dfile_count < 1) || (dfile_count > PVFS_REQ_LIMIT_DFILE_COUNT))
370    {
371        gossip_err("The requested dfile count of %d is invalid; "
372                   "aborting operation.\n", dfile_count);
373        js_p->error_code = -PVFS_EOVERFLOW;
374        return SM_ACTION_COMPLETE;
375    }
376
377    /* set up key and value structure for keyval write */
378    s_op->key.buffer = Trove_Common_Keys[METAFILE_HANDLES_KEY].key;
379    s_op->key.buffer_sz = Trove_Common_Keys[METAFILE_HANDLES_KEY].size;
380
381    gossip_debug(GOSSIP_SETATTR_DEBUG,
382                 "  metafile has %d datafiles associated with it\n",
383                 s_op->req->u.setattr.attr.u.meta.dfile_count);
384
385    s_op->val.buffer = s_op->req->u.setattr.attr.u.meta.dfile_array;
386    s_op->val.buffer_sz = dfile_count * sizeof(PVFS_handle);
387
388    gossip_debug(
389        GOSSIP_SETATTR_DEBUG, "  writing %s [%llu,%d,"
390        "len %d]\n", (char *)s_op->key.buffer,
391        llu(s_op->req->u.setattr.handle), s_op->req->u.setattr.fs_id,
392        s_op->val.buffer_sz);
393
394    /* we don't sync here since we're going to do it anyway in
395     * write_metafile_distribution
396     */
397    ret = job_trove_keyval_write(
398        s_op->req->u.setattr.fs_id, s_op->req->u.setattr.handle,
399        &(s_op->key), &(s_op->val),
400        0,
401        NULL, smcb, 0, js_p, &j_id, server_job_context, s_op->req->hints);
402
403    return ret;
404}
405
406static PINT_sm_action setattr_write_metafile_distribution_if_required(
407        struct PINT_smcb *smcb, job_status_s *js_p)
408{
409    struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
410    int ret = 0;
411    job_id_t j_id;
412
413    /* if we don't need to fill in the distribution, skip it */
414    if (!(s_op->req->u.setattr.attr.mask & PVFS_ATTR_META_DIST))
415    {
416        gossip_debug(GOSSIP_SETATTR_DEBUG,
417                     "skipping distribution write\n");
418        js_p->error_code = 0;
419        return SM_ACTION_COMPLETE;
420    }
421
422    /* set up key and value structure for keyval write */
423    s_op->key.buffer = Trove_Common_Keys[METAFILE_DIST_KEY].key;
424    s_op->key.buffer_sz = Trove_Common_Keys[METAFILE_DIST_KEY].size;
425
426    gossip_debug(GOSSIP_SETATTR_DEBUG,
427                 "  metafile distribution size = %d\n",
428                 (int)s_op->req->u.setattr.attr.u.meta.dist_size);
429
430    s_op->val.buffer_sz = s_op->req->u.setattr.attr.u.meta.dist_size;
431
432    s_op->val.buffer = malloc(s_op->val.buffer_sz);
433    if(!s_op->val.buffer)
434    {
435        js_p->error_code = -PVFS_ENOMEM;
436        return SM_ACTION_COMPLETE;
437    }
438    s_op->free_val = 1;
439   
440    PINT_dist_encode(s_op->val.buffer,
441                     s_op->req->u.setattr.attr.u.meta.dist);
442    gossip_debug(
443        GOSSIP_SERVER_DEBUG, "  writing %s [%llu,%d,"
444        "len %d]\n", (char *)s_op->key.buffer,
445        llu(s_op->req->u.setattr.handle), s_op->req->u.setattr.fs_id,
446        s_op->val.buffer_sz);
447
448    ret = job_trove_keyval_write(
449        s_op->req->u.setattr.fs_id, s_op->req->u.setattr.handle,
450        &(s_op->key), &(s_op->val),
451        TROVE_SYNC,
452        NULL, smcb, 0, js_p, &j_id, server_job_context, s_op->req->hints);
453
454    return ret;
455}
456
457static PINT_sm_action setattr_write_symlink_target_if_required(
458        struct PINT_smcb *smcb, job_status_s *js_p)
459{
460    struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
461    int ret = 0;
462    job_id_t j_id;
463
464    /* if we don't need to fill in the symlink target, skip it */
465    if (!(s_op->req->u.setattr.attr.mask & PVFS_ATTR_SYMLNK_TARGET))
466    {
467        gossip_debug(GOSSIP_SETATTR_DEBUG,
468                     "skipping symlink target write\n");
469        js_p->error_code = 0;
470        return SM_ACTION_COMPLETE;
471    }
472
473    assert(s_op->req->u.setattr.attr.u.sym.target_path_len > 0);
474    assert(s_op->req->u.setattr.attr.u.sym.target_path);
475
476    /* set up key and value structure for keyval write */
477    s_op->key.buffer = Trove_Common_Keys[SYMLINK_TARGET_KEY].key;
478    s_op->key.buffer_sz = Trove_Common_Keys[SYMLINK_TARGET_KEY].size;
479
480    gossip_debug(GOSSIP_SETATTR_DEBUG,
481                 "  symlink target_path_len = %d\n",
482                 s_op->req->u.setattr.attr.u.sym.target_path_len);
483
484    s_op->val.buffer = s_op->req->u.setattr.attr.u.sym.target_path;
485    s_op->val.buffer_sz = s_op->req->u.setattr.attr.u.sym.target_path_len;
486
487    gossip_debug(GOSSIP_SETATTR_DEBUG, "  writing %s [%llu,%d,"
488                 "len %d]\n", (char *)s_op->key.buffer,
489                 llu(s_op->req->u.setattr.handle),
490                 s_op->req->u.setattr.fs_id,
491                 s_op->val.buffer_sz);
492
493    ret = job_trove_keyval_write(
494        s_op->req->u.setattr.fs_id, s_op->req->u.setattr.handle,
495        &(s_op->key), &(s_op->val),
496        TROVE_SYNC,
497        NULL, smcb, 0, js_p, &j_id, server_job_context, s_op->req->hints);
498
499    return ret;
500}
501
502/*
503 * Function: setattr_cleanup
504 *
505 * Params:   server_op *b,
506 *           job_status_s *js_p
507 *
508 * Returns:  int
509 *
510 * Synopsis: free memory and return
511 *           
512 */
513static PINT_sm_action setattr_cleanup(
514        struct PINT_smcb *smcb, job_status_s *js_p)
515{
516    struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
517    if(s_op->free_val)
518    {
519        free(s_op->val.buffer);
520    }
521    return(server_state_machine_complete(smcb));
522}
523
524static int perm_setattr(PINT_server_op *s_op)
525{
526    int ret;
527
528    if (s_op->req->capability.op_mask & PINT_CAP_SETATTR)
529    {
530        ret = 0;
531    }
532    else
533    {
534        ret = -PVFS_EACCES;
535    }
536
537    return ret;
538}
539
540PINT_GET_OBJECT_REF_DEFINE(setattr);
541PINT_GET_CREDENTIAL_DEFINE(setattr);
542
543struct PINT_server_req_params pvfs2_set_attr_params =
544{
545    .string_name = "setattr",
546    .perm = perm_setattr,
547    .access_type = PINT_server_req_modify,
548    .sched_policy = PINT_SERVER_REQ_SCHEDULE,
549    .get_object_ref = PINT_get_object_ref_setattr,
550    .get_credential = PINT_get_credential_setattr,
551    .state_machine = &pvfs2_set_attr_sm
552};
553
554/*
555 * Local variables:
556 *  mode: c
557 *  c-indent-level: 4
558 *  c-basic-offset: 4
559 * End:
560 *
561 * vim: ft=c ts=8 sts=4 sw=4 expandtab
562 */
563
Note: See TracBrowser for help on using the browser.