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

Revision 8397, 18.0 KB (checked in by nlmills, 3 years ago)

initial merge with Orange-Branch. much will be broken

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\t"
333        "handle = %llu | S = %p | mask = %d]\n",
334        dspace_a_p->owner, dspace_a_p->group, dspace_a_p->perms,
335        dspace_a_p->objtype, llu(dspace_a_p->atime),
336        llu(PINT_util_mkversion_time(dspace_a_p->mtime)), llu(dspace_a_p->ctime),
337        (int)dspace_a_p->u.meta.dfile_count,
338        (int)dspace_a_p->u.meta.dist_size,
339        llu(s_op->req->u.setattr.handle), s_op, a_p->mask);
340
341    /* translate attrs to storage attr format */
342    ds_attr = &(s_op->ds_attr);
343    PVFS_object_attr_to_ds_attr(dspace_a_p, ds_attr);
344
345    ret = job_trove_dspace_setattr(
346        s_op->req->u.setattr.fs_id, s_op->req->u.setattr.handle,
347        ds_attr,
348        TROVE_SYNC,
349        smcb, 0, js_p, &j_id, server_job_context, s_op->req->hints);
350
351    return ret;
352}
353
354static PINT_sm_action setattr_write_metafile_datafile_handles_if_required(
355        struct PINT_smcb *smcb, job_status_s *js_p)
356{
357    struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
358    int ret = 0, dfile_count = 0;
359    job_id_t j_id;
360
361    /* reset from jump to here with STATE_METAFILE */
362    js_p->error_code = 0;
363
364    gossip_debug(GOSSIP_SETATTR_DEBUG,
365                 " request has dfile_count of %d | dspace has %d\n",
366                 s_op->req->u.setattr.attr.u.meta.dfile_count,
367                 s_op->attr.u.meta.dfile_count);
368
369    /* verify that the requested dfile count is sane */
370    dfile_count = s_op->req->u.setattr.attr.u.meta.dfile_count;
371    if ((dfile_count < 1) || (dfile_count > PVFS_REQ_LIMIT_DFILE_COUNT))
372    {
373        gossip_err("The requested dfile count of %d is invalid; "
374                   "aborting operation.\n", dfile_count);
375        js_p->error_code = -PVFS_EOVERFLOW;
376        return SM_ACTION_COMPLETE;
377    }
378
379    /* set up key and value structure for keyval write */
380    s_op->key.buffer = Trove_Common_Keys[METAFILE_HANDLES_KEY].key;
381    s_op->key.buffer_sz = Trove_Common_Keys[METAFILE_HANDLES_KEY].size;
382
383    gossip_debug(GOSSIP_SETATTR_DEBUG,
384                 "  metafile has %d datafiles associated with it\n",
385                 s_op->req->u.setattr.attr.u.meta.dfile_count);
386
387    s_op->val.buffer = s_op->req->u.setattr.attr.u.meta.dfile_array;
388    s_op->val.buffer_sz = dfile_count * sizeof(PVFS_handle);
389
390    gossip_debug(
391        GOSSIP_SETATTR_DEBUG, "  writing %s [%llu,%d,"
392        "len %d]\n", (char *)s_op->key.buffer,
393        llu(s_op->req->u.setattr.handle), s_op->req->u.setattr.fs_id,
394        s_op->val.buffer_sz);
395
396    /* we don't sync here since we're going to do it anyway in
397     * write_metafile_distribution
398     */
399    ret = job_trove_keyval_write(
400        s_op->req->u.setattr.fs_id, s_op->req->u.setattr.handle,
401        &(s_op->key), &(s_op->val),
402        0,
403        NULL, smcb, 0, js_p, &j_id, server_job_context, s_op->req->hints);
404
405    return ret;
406}
407
408static PINT_sm_action setattr_write_metafile_distribution_if_required(
409        struct PINT_smcb *smcb, job_status_s *js_p)
410{
411    struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
412    int ret = 0;
413    job_id_t j_id;
414
415    /* if we don't need to fill in the distribution, skip it */
416    if (!(s_op->req->u.setattr.attr.mask & PVFS_ATTR_META_DIST))
417    {
418        gossip_debug(GOSSIP_SETATTR_DEBUG,
419                     "skipping distribution write\n");
420        js_p->error_code = 0;
421        return SM_ACTION_COMPLETE;
422    }
423
424    /* set up key and value structure for keyval write */
425    s_op->key.buffer = Trove_Common_Keys[METAFILE_DIST_KEY].key;
426    s_op->key.buffer_sz = Trove_Common_Keys[METAFILE_DIST_KEY].size;
427
428    gossip_debug(GOSSIP_SETATTR_DEBUG,
429                 "  metafile distribution size = %d\n",
430                 (int)s_op->req->u.setattr.attr.u.meta.dist_size);
431
432    s_op->val.buffer_sz = s_op->req->u.setattr.attr.u.meta.dist_size;
433
434    s_op->val.buffer = malloc(s_op->val.buffer_sz);
435    if(!s_op->val.buffer)
436    {
437        js_p->error_code = -PVFS_ENOMEM;
438        return SM_ACTION_COMPLETE;
439    }
440    s_op->free_val = 1;
441   
442    PINT_dist_encode(s_op->val.buffer,
443                     s_op->req->u.setattr.attr.u.meta.dist);
444    gossip_debug(
445        GOSSIP_SERVER_DEBUG, "  writing %s [%llu,%d,"
446        "len %d]\n", (char *)s_op->key.buffer,
447        llu(s_op->req->u.setattr.handle), s_op->req->u.setattr.fs_id,
448        s_op->val.buffer_sz);
449
450    ret = job_trove_keyval_write(
451        s_op->req->u.setattr.fs_id, s_op->req->u.setattr.handle,
452        &(s_op->key), &(s_op->val),
453        TROVE_SYNC,
454        NULL, smcb, 0, js_p, &j_id, server_job_context, s_op->req->hints);
455
456    return ret;
457}
458
459static PINT_sm_action setattr_write_symlink_target_if_required(
460        struct PINT_smcb *smcb, job_status_s *js_p)
461{
462    struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
463    int ret = 0;
464    job_id_t j_id;
465
466    /* if we don't need to fill in the symlink target, skip it */
467    if (!(s_op->req->u.setattr.attr.mask & PVFS_ATTR_SYMLNK_TARGET))
468    {
469        gossip_debug(GOSSIP_SETATTR_DEBUG,
470                     "skipping symlink target write\n");
471        js_p->error_code = 0;
472        return SM_ACTION_COMPLETE;
473    }
474
475    assert(s_op->req->u.setattr.attr.u.sym.target_path_len > 0);
476    assert(s_op->req->u.setattr.attr.u.sym.target_path);
477
478    /* set up key and value structure for keyval write */
479    s_op->key.buffer = Trove_Common_Keys[SYMLINK_TARGET_KEY].key;
480    s_op->key.buffer_sz = Trove_Common_Keys[SYMLINK_TARGET_KEY].size;
481
482    gossip_debug(GOSSIP_SETATTR_DEBUG,
483                 "  symlink target_path_len = %d\n",
484                 s_op->req->u.setattr.attr.u.sym.target_path_len);
485
486    s_op->val.buffer = s_op->req->u.setattr.attr.u.sym.target_path;
487    s_op->val.buffer_sz = s_op->req->u.setattr.attr.u.sym.target_path_len;
488
489    gossip_debug(GOSSIP_SETATTR_DEBUG, "  writing %s [%llu,%d,"
490                 "len %d]\n", (char *)s_op->key.buffer,
491                 llu(s_op->req->u.setattr.handle),
492                 s_op->req->u.setattr.fs_id,
493                 s_op->val.buffer_sz);
494
495    ret = job_trove_keyval_write(
496        s_op->req->u.setattr.fs_id, s_op->req->u.setattr.handle,
497        &(s_op->key), &(s_op->val),
498        TROVE_SYNC,
499        NULL, smcb, 0, js_p, &j_id, server_job_context, s_op->req->hints);
500
501    return ret;
502}
503
504/*
505 * Function: setattr_cleanup
506 *
507 * Params:   server_op *b,
508 *           job_status_s *js_p
509 *
510 * Returns:  int
511 *
512 * Synopsis: free memory and return
513 *           
514 */
515static PINT_sm_action setattr_cleanup(
516        struct PINT_smcb *smcb, job_status_s *js_p)
517{
518    struct PINT_server_op *s_op = PINT_sm_frame(smcb, PINT_FRAME_CURRENT);
519    if(s_op->free_val)
520    {
521        free(s_op->val.buffer);
522    }
523    return(server_state_machine_complete(smcb));
524}
525
526static int perm_setattr(PINT_server_op *s_op)
527{
528    int ret;
529
530    if (s_op->req->capability.op_mask & PINT_CAP_SETATTR)
531    {
532        ret = 0;
533    }
534    else
535    {
536        ret = -PVFS_EACCES;
537    }
538
539    return ret;
540}
541
542PINT_GET_OBJECT_REF_DEFINE(setattr);
543PINT_GET_CREDENTIAL_DEFINE(setattr);
544
545struct PINT_server_req_params pvfs2_set_attr_params =
546{
547    .string_name = "setattr",
548    .perm = perm_setattr,
549    .access_type = PINT_server_req_modify,
550    .sched_policy = PINT_SERVER_REQ_SCHEDULE,
551    .get_object_ref = PINT_get_object_ref_setattr,
552    .get_credential = PINT_get_credential_setattr,
553    .state_machine = &pvfs2_set_attr_sm
554};
555
556/*
557 * Local variables:
558 *  mode: c
559 *  c-indent-level: 4
560 *  c-basic-offset: 4
561 * End:
562 *
563 * vim: ft=c ts=8 sts=4 sw=4 expandtab
564 */
565
Note: See TracBrowser for help on using the browser.