linux26-defer-cred-changing-20090511
[openafs.git] / src / afs / LINUX / osi_cred.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * osi_cred.c - Linux cred handling routines.
12  *
13  */
14 #include <afsconfig.h>
15 #include "afs/param.h"
16
17 RCSID
18     ("$Header$");
19
20 #include "afs/sysincludes.h"
21 #include "afsincludes.h"
22
23 cred_t *
24 crget(void)
25 {
26     cred_t *tmp;
27     
28 #if !defined(GFP_NOFS)
29 #define GFP_NOFS GFP_KERNEL
30 #endif
31     tmp = kmalloc(sizeof(cred_t), GFP_NOFS);
32     if (!tmp)
33         osi_Panic("crget: No more memory for creds!\n");
34     
35     tmp->cr_ref = 1;
36     return tmp;
37 }
38
39 void
40 crfree(cred_t * cr)
41 {
42     if (cr->cr_ref > 1) {
43         cr->cr_ref--;
44         return;
45     }
46
47 #if defined(AFS_LINUX26_ENV)
48     put_group_info(cr->cr_group_info);
49 #endif
50
51     kfree(cr);
52 }
53
54
55 /* Return a duplicate of the cred. */
56 cred_t *
57 crdup(cred_t * cr)
58 {
59     cred_t *tmp = crget();
60
61     tmp->cr_uid = cr->cr_uid;
62     tmp->cr_ruid = cr->cr_ruid;
63     tmp->cr_gid = cr->cr_gid;
64     tmp->cr_rgid = cr->cr_rgid;
65
66 #if defined(AFS_LINUX26_ENV)
67     get_group_info(cr->cr_group_info);
68     tmp->cr_group_info = cr->cr_group_info;
69 #else
70     memcpy(tmp->cr_groups, cr->cr_groups, NGROUPS * sizeof(gid_t));
71     tmp->cr_ngroups = cr->cr_ngroups;
72 #endif
73
74     return tmp;
75 }
76
77 cred_t *
78 crref(void)
79 {
80     cred_t *cr = crget();
81
82     cr->cr_uid = current_fsuid();
83     cr->cr_ruid = current_uid();
84     cr->cr_gid = current_fsgid();
85     cr->cr_rgid = current_gid();
86
87 #if defined(AFS_LINUX26_ENV)
88     task_lock(current);
89     get_group_info(current_group_info());
90     cr->cr_group_info = current_group_info();
91     task_unlock(current);
92 #else
93     memcpy(cr->cr_groups, current->groups, NGROUPS * sizeof(gid_t));
94     cr->cr_ngroups = current->ngroups;
95 #endif
96     return cr;
97 }
98
99
100 /* Set the cred info into the current task */
101 void
102 crset(cred_t * cr)
103 {
104 #if defined(STRUCT_TASK_HAS_CRED)
105     struct cred *new_creds;
106
107     /* If our current task doesn't have identical real and effective
108      * credentials, commit_cred won't let us change them, so we just
109      * bail here.
110      */
111     if (current->cred != current->real_cred)
112         return;
113     new_creds = prepare_creds();
114     new_creds->fsuid = cr->cr_uid;
115     new_creds->uid = cr->cr_ruid;
116     new_creds->fsgid = cr->cr_gid;
117     new_creds->gid = cr->cr_rgid;
118 #else
119     current->fsuid = cr->cr_uid;
120     current->uid = cr->cr_ruid;
121     current->fsgid = cr->cr_gid;
122     current->gid = cr->cr_rgid;
123 #endif
124 #if defined(AFS_LINUX26_ENV)
125 {
126     struct group_info *old_info;
127
128     /* using set_current_groups() will sort the groups */
129     get_group_info(cr->cr_group_info);
130
131     task_lock(current);
132 #if defined(STRUCT_TASK_HAS_CRED)
133     old_info = current->cred->group_info;
134     new_creds->group_info = cr->cr_group_info;
135     commit_creds(new_creds);
136 #else
137     old_info = current->group_info;
138     current->group_info = cr->cr_group_info;
139 #endif
140     task_unlock(current);
141
142     put_group_info(old_info);
143 }
144 #else
145     memcpy(current->groups, cr->cr_groups, NGROUPS * sizeof(gid_t));
146     current->ngroups = cr->cr_ngroups;
147 #endif
148 }