]> andersk Git - moira.git/blob - server/qaccess.pc
Allow hostname to start with a digit in hostname_check, but disallow it
[moira.git] / server / qaccess.pc
1 /* $Id$
2  *
3  * Check access to queries
4  *
5  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  */
9
10 #include <mit-copyright.h>
11 #include "mr_server.h"
12 #include "qrtn.h"
13 #include "query.h"
14
15 #include <ctype.h>
16 #include <stdlib.h>
17
18 EXEC SQL INCLUDE sqlca;
19
20 RCSID("$Header$");
21
22 extern char *whoami;
23 extern int dbms_errno, mr_errcode;
24
25 EXEC SQL WHENEVER SQLERROR DO dbmserr();
26
27
28 /* Specialized Access Routines */
29
30 /* access_user - verify that client name equals specified login name
31  *
32  *  - since field validation routines are called first, a users_id is
33  *    now in argv[0] instead of the login name.
34  */
35
36 int access_user(struct query *q, char *argv[], client *cl)
37 {
38   if (cl->users_id != *(int *)argv[0])
39     return MR_PERM;
40   else
41     return MR_SUCCESS;
42 }
43
44
45
46 /* access_login - verify that client name equals specified login name
47  *
48  *   argv[0...n] contain search info.  q->
49  */
50
51 int access_login(struct query *q, char *argv[], client *cl)
52 {
53   EXEC SQL BEGIN DECLARE SECTION;
54   int id;
55   EXEC SQL END DECLARE SECTION;
56
57   if (q->argc != 1)
58     return MR_ARGS;
59
60   if (!strcmp(q->shortname, "gual"))
61     {
62       EXEC SQL SELECT users_id INTO :id FROM users
63         WHERE login = :argv[0] AND users_id != 0;
64     }
65   else if (!strcmp(q->shortname, "gubl"))
66     {
67       EXEC SQL SELECT users_id INTO :id FROM users u
68         WHERE u.login = :argv[0] AND u.users_id != 0;
69     }
70   else if (!strcmp(q->shortname, "guau"))
71     {
72       EXEC SQL SELECT users_id INTO :id FROM users
73         WHERE unix_uid = :argv[0] AND users_id != 0;
74     }
75   else if (!strcmp(q->shortname, "gubu"))
76     {
77       EXEC SQL SELECT users_id INTO :id FROM users u
78         WHERE u.unix_uid = :argv[0] AND u.users_id != 0;
79     }
80
81   if (sqlca.sqlcode == SQL_NO_MATCH)
82     return MR_NO_MATCH; /* ought to be MR_USER, but this is what
83                            gual returns, so we have to be consistent */
84   else if (sqlca.sqlerrd[2] != 1 || id != cl->users_id)
85     return MR_PERM;
86   else
87     return MR_SUCCESS;
88 }
89
90
91
92 /* access_list - check access for most list operations
93  *
94  * Inputs: argv[0] - list_id
95  *          q - query name
96  *          argv[2] - member ID (only for queries "amtl" and  "dmfl")
97  *          argv[7] - group ID (only for query "ulis")
98  *          cl - client name
99  *
100  * - check that client is a member of the access control list
101  * - OR, if the query is add_member_to_list or delete_member_from_list
102  *      and the list is public, allow access if client = member
103  */
104
105 int access_list(struct query *q, char *argv[], client *cl)
106 {
107   EXEC SQL BEGIN DECLARE SECTION;
108   int list_id, acl_id, flags, gid, users_id;
109   char acl_type[LIST_ACL_TYPE_SIZE], name[LIST_NAME_SIZE], *newname;
110   EXEC SQL END DECLARE SECTION;
111   int status;
112
113   list_id = *(int *)argv[0];
114   EXEC SQL SELECT acl_id, acl_type, gid, publicflg, name
115     INTO :acl_id, :acl_type, :gid, :flags, :name
116     FROM list
117     WHERE list_id = :list_id;
118
119   if (sqlca.sqlerrd[2] != 1)
120     return MR_INTERNAL;
121
122   /* if amtl or dmfl and list is public allow client to add or delete self */
123   if (((!strcmp("amtl", q->shortname) && flags) ||
124        (!strcmp("dmfl", q->shortname))))
125     {
126       if (!strcmp("USER", argv[1]) && *(int *)argv[2] == cl->users_id)
127         return MR_SUCCESS;
128       if (!strcmp("KERBEROS", argv[1]) && *(int *)argv[2] == -cl->client_id)
129         return MR_SUCCESS;
130     } /* if update_list, don't allow them to change the GID or rename to
131          a username other than their own */
132   else if (!strcmp("ulis", q->shortname))
133     {
134       if (!strcmp(argv[7], UNIQUE_GID))
135         {
136           if (gid != -1)
137             return MR_PERM;
138         }
139       else
140         {
141           if (gid != atoi(argv[7]))
142             return MR_PERM;
143         }
144       newname = argv[1];
145       EXEC SQL SELECT users_id INTO :users_id FROM users
146         WHERE login = :newname;
147       if ((sqlca.sqlcode != SQL_NO_MATCH) && strcmp(strtrim(name), newname) &&
148           (users_id != cl->users_id))
149         return MR_PERM;
150     }
151
152   /* check for client in access control list */
153   status = find_member(acl_type, acl_id, cl);
154   if (!status)
155     return MR_PERM;
156
157   return MR_SUCCESS;
158 }
159
160
161 /* access_visible_list - allow access to list only if it is not hidden,
162  *      or if the client is on the ACL
163  *
164  * Inputs: argv[0] - list_id
165  *         cl - client identifier
166  */
167
168 int access_visible_list(struct query *q, char *argv[], client *cl)
169 {
170   EXEC SQL BEGIN DECLARE SECTION;
171   int list_id, acl_id, flags ;
172   char acl_type[LIST_ACL_TYPE_SIZE];
173   EXEC SQL END DECLARE SECTION;
174   int status;
175
176   list_id = *(int *)argv[0];
177   EXEC SQL SELECT hidden, acl_id, acl_type
178     INTO :flags, :acl_id, :acl_type
179     FROM list
180     WHERE list_id = :list_id;
181   if (sqlca.sqlerrd[2] != 1)
182     return MR_INTERNAL;
183   if (!flags)
184     return MR_SUCCESS;
185
186   /* check for client in access control list */
187   status = find_member(acl_type, acl_id, cl);
188   if (!status)
189     return MR_PERM;
190
191   return MR_SUCCESS;
192 }
193
194
195 /* access_vis_list_by_name - allow access to list only if it is not hidden,
196  *      or if the client is on the ACL
197  *
198  * Inputs: argv[0] - list name
199  *         cl - client identifier
200  */
201
202 int access_vis_list_by_name(struct query *q, char *argv[], client *cl)
203 {
204   EXEC SQL BEGIN DECLARE SECTION;
205   int acl_id, flags, rowcount;
206   char acl_type[LIST_ACL_TYPE_SIZE], *listname;
207   EXEC SQL END DECLARE SECTION;
208   int status;
209
210   listname = argv[0];
211   EXEC SQL SELECT hidden, acl_id, acl_type INTO :flags, :acl_id, :acl_type
212     FROM list WHERE name = :listname;
213
214   rowcount = sqlca.sqlerrd[2];
215   if (rowcount > 1)
216     return MR_WILDCARD;
217   if (rowcount == 0)
218     return MR_NO_MATCH;
219   if (!flags)
220     return MR_SUCCESS;
221
222   /* check for client in access control list */
223   status = find_member(acl_type, acl_id, cl);
224   if (!status)
225     return MR_PERM;
226
227   return MR_SUCCESS;
228 }
229
230
231 /* access_member - allow user to access member of type "USER" and name matches
232  * username, or to access member of type "KERBEROS" and the principal matches
233  * the user, or to access member of type "LIST" and list is one that user is
234  * on the acl of, or the list is visible.
235  */
236
237 int access_member(struct query *q, char *argv[], client *cl)
238 {
239   if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
240     return access_visible_list(q, &argv[1], cl);
241
242   if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER"))
243     {
244       if (cl->users_id == *(int *)argv[1])
245         return MR_SUCCESS;
246     }
247
248   if (!strcmp(argv[0], "KERBEROS") || !strcmp(argv[0], "RKERBEROS"))
249     {
250       if (cl->client_id == -*(int *)argv[1])
251         return MR_SUCCESS;
252     }
253
254   return MR_PERM;
255 }
256
257
258 /* access_qgli - special access routine for Qualified_get_lists.  Allows
259  * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
260  */
261
262 int access_qgli(struct query *q, char *argv[], client *cl)
263 {
264   if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
265     return MR_SUCCESS;
266   return MR_PERM;
267 }
268
269
270 /* access_service - allow access if user is on ACL of service.  Don't
271  * allow access if a wildcard is used.
272  */
273
274 int access_service(struct query *q, char *argv[], client *cl)
275 {
276   EXEC SQL BEGIN DECLARE SECTION;
277   int acl_id;
278   char *name, acl_type[LIST_ACL_TYPE_SIZE];
279   EXEC SQL END DECLARE SECTION;
280   int status;
281   char *c;
282
283   name = argv[0];
284   for (c = name; *c; c++)
285     {
286       if (islower(*c))
287         *c = toupper(*c);
288     }
289   EXEC SQL SELECT acl_id, acl_type INTO :acl_id, :acl_type FROM servers
290     WHERE name = :name;
291   if (sqlca.sqlerrd[2] > 1)
292     return MR_PERM;
293
294   /* check for client in access control list */
295   status = find_member(acl_type, acl_id, cl);
296   if (!status)
297     return MR_PERM;
298
299   return MR_SUCCESS;
300 }
301
302
303 /* access_filesys - verify that client is owner or on owners list of filesystem
304  *      named by argv[0]
305  */
306
307 int access_filesys(struct query *q, char *argv[], client *cl)
308 {
309   EXEC SQL BEGIN DECLARE SECTION;
310   int users_id, list_id;
311   char *name;
312   EXEC SQL END DECLARE SECTION;
313   int status;
314
315   name = argv[0];
316   EXEC SQL SELECT owner, owners INTO :users_id, :list_id FROM filesys
317     WHERE label = :name;
318
319   if (sqlca.sqlerrd[2] != 1)
320     return MR_PERM;
321   if (users_id == cl->users_id)
322     return MR_SUCCESS;
323   status = find_member("LIST", list_id, cl);
324   if (status)
325     return MR_SUCCESS;
326   else
327     return MR_PERM;
328 }
329
330
331 /* access_host - successful if owner of host, or subnet containing host
332  */
333
334 int access_host(struct query *q, char *argv[], client *cl)
335 {
336   EXEC SQL BEGIN DECLARE SECTION;
337   int mid, sid, id;
338   char mtype[MACHINE_OWNER_TYPE_SIZE], stype[SUBNET_OWNER_TYPE_SIZE];
339   EXEC SQL END DECLARE SECTION;
340   int status;
341
342   if (q->type == RETRIEVE)
343     {
344       if (strcmp(argv[0], "*") || strcmp(argv[1], "*") ||
345           strcmp(argv[2], "*") || strcmp(argv[3], "*"))
346         return MR_SUCCESS;
347       else
348         return MR_PERM;
349     }
350
351   if (q->type == APPEND)
352     {
353       /* Non-query owner must set use to zero */
354       if (atoi(argv[6]) != 0)
355         return MR_PERM;
356
357       /* ... and start the hostname with a letter */
358       if (isdigit(argv[0][0]))
359         return MR_BAD_CHAR;
360
361       id = *(int *)argv[8];
362       EXEC SQL SELECT s.owner_type, s.owner_id
363         INTO :stype, :sid FROM subnet s
364         WHERE s.snet_id = :id;
365       mid = 0;
366
367       if (find_member(stype, sid, cl))
368         return MR_SUCCESS;
369       else
370         return MR_PERM;
371     }
372   else /* q-type == UPDATE */
373     {
374       EXEC SQL BEGIN DECLARE SECTION;
375       int status, acomment, use, ocomment, snid;
376       char contact[MACHINE_CONTACT_SIZE], address[MACHINE_ADDRESS_SIZE];
377       char name[MACHINE_NAME_SIZE];
378       EXEC SQL END DECLARE SECTION;
379
380       id = *(int *)argv[0];
381       EXEC SQL SELECT m.name, m.use, m.contact, m.status, m.address,
382         m.owner_type, m.owner_id, m.acomment, m.ocomment, m.snet_id,
383         s.owner_type, s.owner_id INTO :name, :use, :contact, :status,
384         :address, :mtype, :mid, :acomment, :ocomment, :snid, :stype, :sid
385         FROM machine m, subnet s
386         WHERE m.mach_id = :id AND s.snet_id = m.snet_id;
387       if (dbms_errno)
388         return mr_errcode;
389
390       /* non-query-owner cannot change use or ocomment */
391       if ((use != atoi(argv[7])) || (ocomment != *(int *)argv[14]))
392         return MR_PERM;
393
394       /* or rename to start with digit */
395       if (isdigit(argv[1][0]) && strcmp(strtrim(name), argv[1]))
396         return MR_BAD_CHAR;
397
398       if (!find_member(stype, sid, cl))
399         {
400           if (find_member(mtype, mid, cl))
401             {
402               /* host owner also cannot change contact, status, address,
403                  owner, or acomment */
404               if (strcmp(argv[6], strtrim(contact)) ||
405                   (status != atoi(argv[8])) ||
406                   strcmp(argv[10], strtrim(address)) ||
407                   strcmp(argv[11], strtrim(mtype)) ||
408                   (mid != *(int *)argv[12]) || (acomment != *(int *)argv[13]))
409                 return MR_PERM;
410             }
411           else
412             return MR_PERM;
413         }
414
415       /* If moving to a new subnet, make sure user is on acl there */
416       id = *(int *)argv[9];
417       if (id != snid)
418         {
419           EXEC SQL SELECT owner_type, owner_id INTO :stype, :sid
420             FROM subnet WHERE snet_id=:id;
421           if (!find_member(stype, sid, cl))
422             return MR_PERM;
423         }
424
425       return MR_SUCCESS;
426     }
427 }
428
429
430 /* access_ahal - check for adding a host alias.
431  * successful if host has less then 2 aliases and (client is owner of
432  * host or subnet).
433  * If deleting an alias, any owner will do.
434  */
435
436 int access_ahal(struct query *q, char *argv[], client *cl)
437 {
438   EXEC SQL BEGIN DECLARE SECTION;
439   int cnt, id, mid, sid;
440   char mtype[MACHINE_OWNER_TYPE_SIZE], stype[SUBNET_OWNER_TYPE_SIZE];
441   EXEC SQL END DECLARE SECTION;
442   int status;
443
444   if (q->type == RETRIEVE)
445     return MR_SUCCESS;
446
447   id = *(int *)argv[1];
448
449   if (q->type == APPEND && isdigit(argv[0][0]))
450     return MR_BAD_CHAR;
451
452   EXEC SQL SELECT count(name) INTO :cnt from hostalias WHERE mach_id = :id;
453   if (dbms_errno)
454     return mr_errcode;
455   /* if the type is APPEND, this is ahal and we need to make sure there
456    * will be no more than 2 aliases.  If it's not, it must be dhal and
457    * any owner will do.
458    */
459   if (q->type == APPEND && cnt >= 2)
460     return MR_PERM;
461   EXEC SQL SELECT m.owner_type, m.owner_id, s.owner_type, s.owner_id
462     INTO :mtype, :mid, :stype, :sid FROM machine m, subnet s
463     WHERE m.mach_id = :id and s.snet_id = m.snet_id;
464   status = find_member(mtype, mid, cl);
465   if (status)
466     return MR_SUCCESS;
467   status = find_member(stype, sid, cl);
468   if (status)
469     return MR_SUCCESS;
470   else
471     return MR_PERM;
472 }
473
474
475
476 /* access_snt - check for retrieving network structure
477  */
478
479 int access_snt(struct query *q, char *argv[], client *cl)
480 {
481   if (q->type == RETRIEVE)
482     return MR_SUCCESS;
483
484   return MR_PERM;
485 }
This page took 0.115977 seconds and 5 git commands to generate.