Merge ~epics-core/epics-base/+git/asLib:as-groups into ~epics-core/epics-base/+git/epics-base:7.0

Proposed by mdavidsaver
Status: Rejected
Rejected by: mdavidsaver
Proposed branch: ~epics-core/epics-base/+git/asLib:as-groups
Merge into: ~epics-core/epics-base/+git/epics-base:7.0
Diff against target: 295 lines (+139/-27)
3 files modified
modules/libcom/src/as/asLib.h (+19/-2)
modules/libcom/src/as/asLibRoutines.c (+67/-22)
modules/libcom/test/aslibtest.c (+53/-3)
Reviewer Review Type Date Requested Status
mdavidsaver Needs Fixing
Review via email: mp+358821@code.launchpad.net

Description of the change

First attempt to add the notion of groups (in the unix getgrent() sense) to asLib. As I want to preserve acf file compatibility with previous Base releases I'm not changing the parser, instead a "group" appears in a UAG() with a magic prefix "group:".

This branch changes only the core asLib. It won't be possible to use w/ CA. My intended user is PVA, which has the potential to transport a list of group names.

The main API change is the introduction of variants of asAddClient()and asChangeClient() which move most of the argument list to a structure. I also place an arbitrary limit of 16 groups to keep the API simple.

To post a comment you must log in.
Revision history for this message
mdavidsaver (mdavidsaver) wrote :

I'll be pushing changes to github as well, so CI build results are available. Look for "as-groups" at https://travis-ci.org/mdavidsaver/epics-base/branches

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

Georg Weiss says:

> ... limit of 16, but this might be a bit too conservative in my opinion ...

https://github.com/epics-base/pvAccessCPP/pull/136#issuecomment-453932984

Which I agree with. So this proposed API will need to change.

I'd still like to get some comment on the idea...

review: Needs Fixing
Revision history for this message
mdavidsaver (mdavidsaver) wrote :

Rather then try to use asLib in the PVA gateway, I've written my own parser. This will use 'UAG(BLAH){role:...}'.

Unmerged commits

a6ccaf3... by mdavidsaver

asLib test user groups

9e30bc7... by mdavidsaver

as: add user groups

Allow clients to provide a user name and list of group names.
user and group names appear in the same namespace, but
group names are required to start with "group:".

A rule matches if a UAG contain the client user name,
or any of the client's group names.

ef45f3f... by mdavidsaver

add asAddClient2() pass args in struct

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/modules/libcom/src/as/asLib.h b/modules/libcom/src/as/asLib.h
2index 261e5ed..ba290aa 100644
3--- a/modules/libcom/src/as/asLib.h
4+++ b/modules/libcom/src/as/asLib.h
5@@ -21,6 +21,8 @@
6 extern "C" {
7 #endif
8
9+#define ASMAXGROUPS 16
10+
11 typedef struct asgMember *ASMEMBERPVT;
12 typedef struct asgClient *ASCLIENTPVT;
13 typedef int (*ASINPUTFUNCPTR)(char *buf,int max_size);
14@@ -29,6 +31,13 @@ typedef enum{
15 /*For now this is all*/
16 } asClientStatus;
17
18+typedef struct asClientInfo {
19+ int asl;
20+ char *user;
21+ char *host;
22+ char *groups[ASMAXGROUPS]; /* unused must be NULL */
23+} asClientInfo;
24+
25 typedef void (*ASCLIENTCALLBACK) (ASCLIENTPVT,asClientStatus);
26
27 /* The following routines are macros with the following syntax
28@@ -77,13 +86,20 @@ epicsShareFunc long epicsShareAPI asChangeGroup(
29 epicsShareFunc void * epicsShareAPI asGetMemberPvt(ASMEMBERPVT asMemberPvt);
30 epicsShareFunc void epicsShareAPI asPutMemberPvt(
31 ASMEMBERPVT asMemberPvt,void *userPvt);
32-/*client must provide permanent storage for user and host*/
33+/* user and host must remain valid until asRemoveClient(). host is modified (normalized)*/
34 epicsShareFunc long epicsShareAPI asAddClient(
35 ASCLIENTPVT *asClientPvt,ASMEMBERPVT asMemberPvt,
36 int asl,const char *user,char *host);
37-/*client must provide permanent storage for user and host*/
38+/* info->user and info->host must remain valid until asRemoveClient(). info->host is modified (normalized)*/
39+epicsShareFunc long epicsShareAPI asAddClient2(
40+ ASCLIENTPVT *asClientPvt,ASMEMBERPVT asMemberPvt,
41+ asClientInfo *info);
42+/* user and host must remain valid until asRemoveClient(). host is modified (normalized)*/
43 epicsShareFunc long epicsShareAPI asChangeClient(
44 ASCLIENTPVT asClientPvt,int asl,const char *user,char *host);
45+/* info->user and info->host must remain valid until asRemoveClient(). info->host is modified (normalized)*/
46+epicsShareFunc long epicsShareAPI asChangeClient2(
47+ ASCLIENTPVT asClientPvt,asClientInfo *info);
48 epicsShareFunc long epicsShareAPI asRemoveClient(ASCLIENTPVT *asClientPvt);
49 epicsShareFunc void * epicsShareAPI asGetClientPvt(ASCLIENTPVT asClientPvt);
50 epicsShareFunc void epicsShareAPI asPutClientPvt(
51@@ -226,6 +242,7 @@ typedef struct asgClient {
52 ASGMEMBER *pasgMember;
53 const char *user;
54 char *host;
55+ char *groups[ASMAXGROUPS];
56 void *userPvt;
57 ASCLIENTCALLBACK pcallback;
58 int level;
59diff --git a/modules/libcom/src/as/asLibRoutines.c b/modules/libcom/src/as/asLibRoutines.c
60index 3f5713e..0ebc14e 100644
61--- a/modules/libcom/src/as/asLibRoutines.c
62+++ b/modules/libcom/src/as/asLibRoutines.c
63@@ -354,9 +354,33 @@ void epicsShareAPI asPutMemberPvt(ASMEMBERPVT asMemberPvt,void *userPvt)
64 pasgmember->userPvt = userPvt;
65 return;
66 }
67-
68
69-long epicsShareAPI asAddClient(ASCLIENTPVT *pasClientPvt,ASMEMBERPVT asMemberPvt,
70- int asl,const char *user,char *host)
71+
72+static int asCheckGroupNames(const asClientInfo *info)
73+{
74+ unsigned i;
75+ int seennull=0;
76+ for(i=0; i<ASMAXGROUPS; i++) {
77+ if(!info->groups[i]) {
78+ seennull = 1;
79+
80+ } else {
81+ size_t len = strlen(info->groups[i]);
82+ if(seennull) {
83+ errlogPrintf("as API error: asClientInfo::groups[] must be contigious\n");
84+ return 1;
85+ } else if(len<=6 || strncmp("group:", info->groups[i], 6)!=0) {
86+ errlogPrintf("as API error: group names must begin with \"group:\" and at least one charactor, not '%s'",
87+ info->groups[i]);
88+ return 1;
89+ }
90+ }
91+ }
92+ return 0;
93+}
94+
95+epicsShareFunc long epicsShareAPI asAddClient2(
96+ ASCLIENTPVT *pasClientPvt,ASMEMBERPVT asMemberPvt,
97+ asClientInfo *info)
98 {
99 ASGMEMBER *pasgmember = asMemberPvt;
100 ASGCLIENT *pasgclient;
101@@ -364,18 +388,20 @@ long epicsShareAPI asAddClient(ASCLIENTPVT *pasClientPvt,ASMEMBERPVT asMemberPvt
102
103 long status;
104 if(!asActive) return(S_asLib_asNotActive);
105- if(!pasgmember) return(S_asLib_badMember);
106+ if(!pasgmember || !info || asCheckGroupNames(info)) return(S_asLib_badMember);
107 pasgclient = freeListCalloc(freeListPvt);
108 if(!pasgclient) return(S_asLib_noMemory);
109- len = strlen(host);
110+ len = strlen(info->host);
111 for (i = 0; i < len; i++) {
112- host[i] = (char)tolower((int)host[i]);
113+ info->host[i] = (char)tolower((int)info->host[i]);
114 }
115 *pasClientPvt = pasgclient;
116 pasgclient->pasgMember = asMemberPvt;
117- pasgclient->level = asl;
118- pasgclient->user = user;
119- pasgclient->host = host;
120+ pasgclient->level = info->asl;
121+ pasgclient->user = info->user;
122+ pasgclient->host = info->host;
123+ STATIC_ASSERT(sizeof(pasgclient->groups)==sizeof(info->groups));
124+ memcpy(pasgclient->groups, info->groups, sizeof(info->groups));
125 LOCK;
126 ellAdd(&pasgmember->clientList,&pasgclient->node);
127 status = asComputePvt(pasgclient);
128@@ -383,28 +409,43 @@ long epicsShareAPI asAddClient(ASCLIENTPVT *pasClientPvt,ASMEMBERPVT asMemberPvt
129 return(status);
130 }
131
132-long epicsShareAPI asChangeClient(
133- ASCLIENTPVT asClientPvt,int asl,const char *user,char *host)
134+long epicsShareAPI asAddClient(ASCLIENTPVT *pasClientPvt,ASMEMBERPVT asMemberPvt,
135+ int asl,const char *user,char *host)
136+{
137+ asClientInfo info = {asl, (char*)user, host};
138+ return asAddClient2(pasClientPvt, asMemberPvt, &info);
139+}
140+
141+long epicsShareAPI asChangeClient2(
142+ ASCLIENTPVT asClientPvt,asClientInfo *info)
143 {
144 ASGCLIENT *pasgclient = asClientPvt;
145 long status;
146 int len, i;
147
148 if(!asActive) return(S_asLib_asNotActive);
149- if(!pasgclient) return(S_asLib_badClient);
150- len = strlen(host);
151+ if(!pasgclient || asCheckGroupNames(info)) return(S_asLib_badClient);
152+ len = strlen(info->host);
153 for (i = 0; i < len; i++) {
154- host[i] = (char)tolower((int)host[i]);
155+ info->host[i] = (char)tolower((int)info->host[i]);
156 }
157 LOCK;
158- pasgclient->level = asl;
159- pasgclient->user = user;
160- pasgclient->host = host;
161+ pasgclient->level = info->asl;
162+ pasgclient->user = info->user;
163+ pasgclient->host = info->host;
164+ memcpy(pasgclient->groups, info->groups, sizeof(info->groups));
165 status = asComputePvt(pasgclient);
166 UNLOCK;
167 return(status);
168 }
169
170+long epicsShareAPI asChangeClient(
171+ ASCLIENTPVT asClientPvt,int asl,const char *user,char *host)
172+{
173+ asClientInfo info = {asl, (char*)user, host};
174+ return asChangeClient2(asClientPvt, &info);
175+}
176+
177 long epicsShareAPI asRemoveClient(ASCLIENTPVT *asClientPvt)
178 {
179 ASGCLIENT *pasgclient = *asClientPvt;
180@@ -999,11 +1040,15 @@ static long asComputePvt(ASCLIENTPVT asClientPvt)
181
182 pasguag = (ASGUAG *)ellFirst(&pasgrule->uagList);
183 while(pasguag) {
184- if((puag = pasguag->puag)) {
185- pgphentry = gphFind(pasbase->phash,pasgclient->user,puag);
186- if(pgphentry) goto check_hag;
187- }
188- pasguag = (ASGUAG *)ellNext(&pasguag->node);
189+ if((puag = pasguag->puag)) {
190+ unsigned i;
191+ int match = gphFind(pasbase->phash,pasgclient->user,puag)!=NULL;
192+ for(i=0; !match && i<ASMAXGROUPS && pasgclient->groups[i]; i++) {
193+ match = gphFind(pasbase->phash,pasgclient->groups[i],puag)!=NULL;
194+ }
195+ if(match) goto check_hag;
196+ }
197+ pasguag = (ASGUAG *)ellNext(&pasguag->node);
198 }
199 goto next_rule;
200 }
201diff --git a/modules/libcom/test/aslibtest.c b/modules/libcom/test/aslibtest.c
202index 875aa56..34bd4d1 100644
203--- a/modules/libcom/test/aslibtest.c
204+++ b/modules/libcom/test/aslibtest.c
205@@ -18,7 +18,8 @@
206 #include <asLib.h>
207
208 static char *asUser,
209- *asHost;
210+ *asHost,
211+ *asGroup;
212 static int asAsl;
213
214 static void setUser(const char *name)
215@@ -33,18 +34,31 @@ static void setHost(const char *name)
216 asHost = epicsStrDup(name);
217 }
218
219+static void setGroup(const char *name)
220+{
221+ free(asGroup);
222+ asGroup = name ? epicsStrDup(name) : NULL;
223+}
224+
225 static void testAccess(const char *asg, unsigned mask)
226 {
227 ASMEMBERPVT asp = 0; /* aka dbCommon::asp */
228 ASCLIENTPVT client = 0;
229+ asClientInfo info;
230 long ret;
231
232+ memset(&info, 0, sizeof(info));
233+ info.asl = asAsl;
234+ info.user = asUser;
235+ info.host = asHost;
236+ info.groups[0] = asGroup;
237+
238 ret = asAddMember(&asp, asg);
239 if(ret) {
240 testFail("testAccess(ASG:%s, USER:%s, HOST:%s, ASL:%d) -> asAddMember error: %s",
241 asg, asUser, asHost, asAsl, errSymMsg(ret));
242 } else {
243- ret = asAddClient(&client, asp, asAsl, asUser, asHost);
244+ ret = asAddClient2(&client, asp, &info);
245 }
246 if(ret) {
247 testFail("testAccess(ASG:%s, USER:%s, HOST:%s, ASL:%d) -> asAddClient error: %s",
248@@ -109,11 +123,47 @@ static void testHostNames(void)
249 testAccess("ro", 0);
250 testAccess("rw", 0);
251 }
252+static void testGroup(void)
253+{
254+ static const char config[] = ""
255+ "UAG(foo) {theuser}"
256+ "UAG(bar) {group:thegroup}"
257+ "ASG(DEFAULT) {RULE(0, NONE)}"
258+ "ASG(ro) {RULE(0, NONE)RULE(1, READ) {UAG(foo)}}"
259+ "ASG(rw) {RULE(1, WRITE) {UAG(bar)}}"
260+ ;
261+ testDiag("testGroup()");
262+
263+ testOk1(asInitMem(config, NULL)==0);
264+
265+ setHost("localhost");
266+ asAsl = 0;
267+
268+ setUser("theuser");
269+ setGroup(NULL);
270+
271+ testAccess("ro", 1);
272+ testAccess("rw", 0);
273+
274+ setUser("random");
275+ setGroup("group:thegroup");
276+
277+ testAccess("ro", 0);
278+ testAccess("rw", 3);
279+
280+ setUser("theuser");
281+ setGroup("group:thegroup");
282+
283+ testAccess("ro", 1);
284+ testAccess("rw", 3);
285+}
286+
287 MAIN(aslibtest)
288 {
289- testPlan(14);
290+ testPlan(21);
291 testSyntaxErrors();
292 testHostNames();
293+ testGroup();
294 errlogFlush();
295 return testDone();
296 }

Subscribers

People subscribed via source and target branches