Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[oweals/cde.git] / cde / programs / dtcm / server / access.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: access.c /main/5 1996/10/08 16:41:05 barstow $ */
24 /*
25  *  (c) Copyright 1993, 1994 Hewlett-Packard Company
26  *  (c) Copyright 1993, 1994 International Business Machines Corp.
27  *  (c) Copyright 1993, 1994 Novell, Inc.
28  *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
29  */
30
31
32 #include <EUSCompat.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <pwd.h>
37 #ifdef SunOS
38 #include <sys/systeminfo.h>
39 #endif
40 #include "access.h"
41 #include "appt4.h"
42 #include "utility.h"
43 #include "log.h"
44 #include "lutil.h"
45 #include "laccess.h"
46
47 #define NUM_CACHE               50      /* cache for unix user name */
48
49 extern int debug;
50
51 typedef struct uname_cache {
52         uid_t   uid;                    /* unix user id */
53         char    *name;                  /* user name */
54         struct  uname_cache *next;
55 } Uname_cache;
56
57 static  Uname_cache     *ucache_list = NULL;
58
59 /******************************************************************************
60  * forward declaration of static functions used within the file
61  ******************************************************************************/
62 static Uname_cache * in_u_cache(uid_t uid);
63 static char * get_uname(uid_t uid);
64 static Access_Entry_4 * in_access_list(Access_Entry_4 *l, char *s);
65 static Access_Entry_4 * combine_access_list(Access_Entry_4 *p_list, 
66                                 Access_Entry_4 *p_head, int type, int *p_world);
67 static CSA_return_code _GetV4AccessRights(_DtCmsCalendar *cal, char *target,
68                                 char *sender, uint *access);
69 static CSA_return_code _GetV5AccessRights(_DtCmsCalendar *cal, char *target,
70                                 char *sender, uint *access);
71
72 /*****************************************************************************
73  * extern functions used in the library
74  *****************************************************************************/
75
76 /*
77  * If the requester is the owner, "*sender" will be set to NULL.
78  */
79 extern CSA_return_code
80 _DtCmsV4LoadAndCheckAccess(
81         struct svc_req  *svcrq,
82         char            *target,
83         char            **sender,
84         uint            *access,
85         _DtCmsCalendar  **cal)
86 {
87         CSA_return_code stat;
88
89         if (target == NULL || sender == NULL || cal == NULL)
90                 return (CSA_E_INVALID_PARAMETER);
91
92         if ((stat = _DtCmsGetClientInfo(svcrq, sender)) != CSA_SUCCESS)
93                 return (stat);
94
95         if ((stat = _DtCmsGetCalendarByName(target, B_TRUE, cal))
96             != CSA_SUCCESS)
97                 return (stat);
98
99         if ((*cal)->fversion == _DtCMS_VERSION1)
100                 return (_GetV4AccessRights(*cal, target, *sender, access));
101         else
102                 return (_GetV5AccessRights(*cal, target, *sender, access));
103
104 }
105
106 /*
107  * If the requester is the owner, "*p_src" will be set to NULL.
108  */
109 extern CSA_return_code
110 _DtCmsV5LoadAndCheckAccess(
111         struct svc_req  *svcrq,
112         char            *target,
113         char            **sender,
114         uint            *access,
115         _DtCmsCalendar  **cal)
116 {
117         CSA_return_code         stat;
118         cms_access_entry        *alist;
119         cms_attribute_value     *owner;
120         int                     worldaccess = 0, useraccess = 0;
121         boolean_t               isowner;
122
123
124         if (target == NULL || sender == NULL || cal == NULL)
125                 return (CSA_E_INVALID_PARAMETER);
126
127         if ((stat = _DtCmsGetClientInfo(svcrq, sender)) != CSA_SUCCESS)
128                 return (stat);
129
130         if ((stat = _DtCmsGetCalendarByName(target, B_TRUE, cal))
131             != CSA_SUCCESS)
132                 return (stat);
133
134         if ((*cal)->fversion == _DtCMS_VERSION1)
135                 return (_GetV4AccessRights(*cal, target, *sender, access));
136         else
137                 return (_GetV5AccessRights(*cal, target, *sender, access));
138 }
139
140 extern CSA_return_code
141 _DtCmsGetClientInfo(struct svc_req *svcrq, char **source)
142 {
143         char *name;
144         char *uname;
145         struct authunix_parms *unix_cred;
146
147         if (source == NULL)
148         {
149                 return (CSA_E_INVALID_PARAMETER);
150         }
151
152         switch (svcrq->rq_cred.oa_flavor) {
153         case AUTH_UNIX:
154                 unix_cred = (struct authunix_parms *) svcrq->rq_clntcred;
155                 if (unix_cred == NULL)
156                         return (CSA_E_NO_AUTHORITY);
157                 if ((name = get_uname (unix_cred->aup_uid)) == NULL)
158                         return (CSA_E_INSUFFICIENT_MEMORY);
159                 if ((uname = malloc(strlen(name) +
160                     strlen(unix_cred->aup_machname) + 2)) == NULL)
161                         return (CSA_E_INSUFFICIENT_MEMORY);
162                 else {
163                         sprintf(uname, "%s@%s", name, unix_cred->aup_machname);
164                         *source = uname;
165                         return (CSA_SUCCESS);
166                 }
167
168         case AUTH_NULL:
169         default:
170                 svcerr_weakauth(svcrq->rq_xprt);
171                 return (CSA_E_NO_AUTHORITY);
172         }
173 }
174
175 /*
176  * good format of owner and user assumed:
177  * owner: user[@host[.domain]]
178  * user: user@host[.domain]
179  * target: name@host[.domain]
180  */
181 extern boolean_t
182 _DtCmsIsFileOwner(char *owner, char *user, char *target)
183 {
184         char *ptr1, *ptr2, *ptr3;
185
186         if (debug) {
187                 fprintf(stderr, "rpc.cmsd: %s, %s = %s, %s = %s, %s = %s\n",
188                         "check file owner",
189                         "owner", ((owner == NULL) ? "NULL" : owner),
190                         "user", ((user == NULL) ? "NULL" : user),
191                         "target", ((target == NULL) ? "NULL" : target));
192         }
193
194         if (owner == NULL || user == NULL || target == NULL)
195                 return (B_FALSE);
196
197         ptr1 = _DtCmGetPrefix(owner, '@');
198         ptr2 = _DtCmGetPrefix(user, '@');
199         if (strcmp(ptr1, ptr2)) {
200                 free(ptr1);
201                 free(ptr2);
202                 return(B_FALSE);
203         }
204         free(ptr1);
205         free(ptr2);
206
207         /* check domain if domain info is available */
208
209         ptr1 = strchr(user, '.');
210         ptr2 = strchr(target, '@');
211         if (ptr2)
212                 ptr3 = strchr(ptr2, '.');
213         else
214                 ptr3 = NULL;
215
216         if (ptr1 == NULL || ptr3 == NULL)
217                 /* assume that user is in the local domain */
218                 return B_TRUE;
219         else
220                 return(_DtCmIsSamePath(++ptr1, ++ptr3));
221 }
222
223 extern void
224 _DtCmsShowAccessList(Access_Entry_4 *l)
225 {
226         while (l!=NULL) {
227                 fprintf(stderr, "Access: %s(%c%c%c)\n", l->who,
228                         l->access_type & access_read_4   ? 'r' : '_',
229                         l->access_type & access_write_4  ? 'w' : '_',
230                         l->access_type & access_delete_4 ? 'd' : '_');
231                 l = l->next;
232         }
233 }
234
235 extern Access_Entry_4 *
236 _DtCmsCalendarAccessList(_DtCmsCalendar *cal)
237 {
238         int             world = access_none_4;
239         Access_Entry_4  *a;
240         Access_Entry_4  *l = NULL;
241
242         l = combine_access_list(GET_R_ACCESS(cal), l, access_read_4, &world);
243         l = combine_access_list(GET_W_ACCESS(cal), l, access_write_4, &world);
244         l = combine_access_list(GET_D_ACCESS(cal), l, access_delete_4, &world);
245         l = combine_access_list(GET_X_ACCESS(cal), l, access_exec_4, &world);
246
247         /* WORLD exists in one of the lists, add her to the combined list. */
248         if (world != access_none_4)
249         {
250                 a = _DtCm_make_access_entry4(WORLD, world);
251                 a->next = l;
252                 l = a;
253         }
254         return (l);
255 }
256
257 extern Privacy_Level_4
258 _DtCmCheckPrivacyLevel(char **p_src, Appt_4 *p_appt)
259 {
260         if (*p_src == NULL)
261                 return(public_4);
262
263         if (p_appt != NULL) {
264                 /*
265                  * if p_src is the author of the appointment,
266                  * it should see everything.
267                  */
268                 if (_DtCmIsSameUser(*p_src, p_appt->author)) {
269                         *p_src = NULL;
270                         return(public_4);
271                 } else
272                         return(p_appt->privacy);
273         } else
274                 return(private_4);
275 }
276
277 /*
278  * the user can view the entry if it has OWNER rights,
279  * the appropriate VIEW rights or he is the organizer of
280  * the entry and has ORGANIZER rights.
281  */
282 extern CSA_return_code
283 _DtCmsCheckViewAccess(char *user, uint access, cms_entry *eptr)
284 {
285         uint    need;
286         cms_attribute_value *oval, *sval;
287
288         need = (_DtCmsClassToViewAccess(eptr)) | CSA_OWNER_RIGHTS;
289         if (access & need) {
290                 return (CSA_SUCCESS);
291         } else {
292                 oval = eptr->attrs[CSA_ENTRY_ATTR_ORGANIZER_I].value;
293                 sval = eptr->attrs[CSA_ENTRY_ATTR_SPONSOR_I].value;
294                 if (((access & CSA_ORGANIZER_RIGHTS) &&
295                     _DtCmIsSameUser(user, oval->item.calendar_user_value)) ||
296                     ((access & CSA_SPONSOR_RIGHTS) && sval &&
297                     _DtCmIsSameUser(user, sval->item.calendar_user_value)))
298                         return (CSA_SUCCESS);
299                 else if ( (need & ~CSA_OWNER_RIGHTS) == (CSA_VIEW_CONFIDENTIAL_ENTRIES) ) {
300                         return (CSA_E_TIME_ONLY);
301                 } else
302                         return (CSA_E_NO_AUTHORITY);
303         }
304 }
305
306 extern CSA_return_code
307 _DtCmsCheckChangeAccess(char *user, uint access, cms_entry *eptr)
308 {
309         uint    need;
310         cms_attribute_value *oval, *sval;
311
312         need = (_DtCmsClassToChangeAccess(eptr)) | CSA_OWNER_RIGHTS;
313
314         if (access & need) {
315                 return (CSA_SUCCESS);
316         } else {
317                 oval = eptr->attrs[CSA_ENTRY_ATTR_ORGANIZER_I].value;
318                 sval = eptr->attrs[CSA_ENTRY_ATTR_SPONSOR_I].value;
319                 if (((access & CSA_ORGANIZER_RIGHTS) &&
320                     _DtCmIsSameUser(user, oval->item.calendar_user_value)) ||
321                     ((access & CSA_SPONSOR_RIGHTS) && sval &&
322                     _DtCmIsSameUser(user, sval->item.calendar_user_value)))
323                         return (CSA_SUCCESS);
324                 else
325                         return (CSA_E_NO_AUTHORITY);
326         }
327 }
328
329 extern uint
330 _DtCmsClassToViewAccess(cms_entry *entry)
331 {
332         cms_attribute_value *val;
333
334         val = entry->attrs[CSA_ENTRY_ATTR_CLASSIFICATION_I].value;
335
336         switch (val->item.uint32_value) {
337         case CSA_CLASS_PUBLIC:
338                 return (CSA_VIEW_PUBLIC_ENTRIES);
339         case CSA_CLASS_PRIVATE:
340                 return (CSA_VIEW_PRIVATE_ENTRIES);
341         case CSA_CLASS_CONFIDENTIAL:
342                 return (CSA_VIEW_CONFIDENTIAL_ENTRIES);
343         }
344         
345         fprintf(stderr, "_DtCmsClassToInsertAccess: Unsupported Class %lu\n", val->item.uint32_value);
346         exit(EXIT_FAILURE);
347 }
348
349 extern uint
350 _DtCmsClassToInsertAccess(cms_entry *entry)
351 {
352         cms_attribute_value *val;
353
354         val = entry->attrs[CSA_ENTRY_ATTR_CLASSIFICATION_I].value;
355
356         switch (val->item.uint32_value) {
357         case CSA_CLASS_PUBLIC:
358                 return (CSA_INSERT_PUBLIC_ENTRIES);
359         case CSA_CLASS_PRIVATE:
360                 return (CSA_INSERT_PRIVATE_ENTRIES);
361         case CSA_CLASS_CONFIDENTIAL:
362                 return (CSA_INSERT_CONFIDENTIAL_ENTRIES);
363         }
364
365         fprintf(stderr, "_DtCmsClassToInsertAccess: Unsupported Class %lu\n", val->item.uint32_value);
366         exit(EXIT_FAILURE);
367 }
368
369 extern uint
370 _DtCmsClassToChangeAccess(cms_entry *entry)
371 {
372         cms_attribute_value *val;
373
374         val = entry->attrs[CSA_ENTRY_ATTR_CLASSIFICATION_I].value;
375
376         switch (val->item.uint32_value) {
377         case CSA_CLASS_PUBLIC:
378                 return (CSA_CHANGE_PUBLIC_ENTRIES);
379         case CSA_CLASS_PRIVATE:
380                 return (CSA_CHANGE_PRIVATE_ENTRIES);
381         case CSA_CLASS_CONFIDENTIAL:
382                 return (CSA_CHANGE_CONFIDENTIAL_ENTRIES);
383         }
384
385         fprintf(stderr, "_DtCmsClassToChangeAccess: Unsupported Class %lu\n", val->item.uint32_value);
386         exit(EXIT_FAILURE);
387 }
388
389 /*****************************************************************************
390  * static functions used within the file
391  *****************************************************************************/
392
393 static Uname_cache *
394 in_u_cache(uid_t uid)
395 {
396         int     cache = NUM_CACHE;
397         Uname_cache *p_prev;
398         Uname_cache *p_cache;
399
400         p_prev = NULL;
401         p_cache = ucache_list;
402         while (p_cache != NULL)
403         {
404                 if (p_cache->uid == uid)
405                         return (p_cache);
406                 if (--cache < 0)
407                 {
408                         /* Assume that the cache size is at least 1 */
409                         p_prev->next = p_cache->next;
410                         free (p_cache->name);
411                         free (p_cache);
412                         p_cache = p_prev->next;
413                 }
414                 else
415                 {
416                         p_prev = p_cache;
417                         p_cache = p_cache->next;
418                 }
419         }
420         return (NULL);
421 }
422
423 static char *
424 get_uname(uid_t uid)
425 {
426         struct passwd *pw;
427         char buff[16];
428         Uname_cache *ucache, *prev;
429
430         if ((ucache = in_u_cache(uid)) == NULL)
431         {
432                 if ((pw = getpwuid (uid)) == NULL) {
433                         /* Can't map uid to name.  Don't cache the uid. */
434                         sprintf (buff, "%ld", (long)uid);
435                         return (strdup(buff));
436                 }
437
438                 if ((ucache = (Uname_cache *)malloc(sizeof(Uname_cache)))
439                     == NULL)
440                         return (NULL);
441
442                 if ((ucache->name = strdup(pw->pw_name)) == NULL) {
443                         free(ucache);
444                         return (NULL);
445                 }
446                 ucache->uid = uid;
447                 ucache->next = ucache_list;
448                 ucache_list = ucache;
449         }
450
451         return (strdup(ucache->name));
452 }
453
454 static Access_Entry_4 *
455 in_access_list(Access_Entry_4 *l, char *s)
456 {
457         char    *name;
458
459         if (l==NULL || s==NULL) return(NULL);
460         while(l != NULL) {
461                 /* only for combining lists, not for authentication */
462                 if (strcmp(l->who, s) == 0)
463                         break;
464                 l = l->next;
465         }
466         return(l);
467 }
468
469 static Access_Entry_4 *
470 combine_access_list(
471         Access_Entry_4 *p_list, 
472         Access_Entry_4 *p_head, 
473         int type, 
474         int *p_world)
475 {
476         Access_Entry_4  *a;
477         Access_Entry_4  *h = p_head;
478
479         while (p_list != NULL)
480         {
481                 /* Delay to put the WORLD into the combined list because 
482                  * in_access_list() may return wrong result.
483                  */
484                 if (strcmp (p_list->who, WORLD) == 0)
485                         *p_world |= type;
486                 else
487                 {
488                         /* The user is not in the combined list, add to list. */
489                         if ((a = in_access_list (h, p_list->who)) == NULL)
490                         {
491                                 a = _DtCm_make_access_entry4(p_list->who, type);
492                                 a->next = p_head;
493                                 p_head = a;
494                         }
495                         a->access_type |= type;
496                 }
497                 p_list = p_list->next;
498         }
499         return (p_head);
500 }
501
502 static CSA_return_code
503 _GetV4AccessRights(
504         _DtCmsCalendar  *cal,
505         char            *target,
506         char            *sender,
507         uint            *access)
508 {
509         int             worldaccess = 0, useraccess = 0;
510         Access_Entry_4  *alist;
511
512         /* first check to see if the user is the owner of the calendar */
513         if (_DtCmsIsFileOwner(cal->owner, sender, target)) {
514                 *access = CSA_OWNER_RIGHTS;
515                 return (CSA_SUCCESS);
516         }
517
518         for (alist = cal->alist; alist != NULL; alist = alist->next) {
519                 if (strcmp(alist->who, WORLD) == 0)
520                         worldaccess = alist->access_type;
521                 else if (_DtCmIsSameUser(sender, alist->who)) {
522                         useraccess = alist->access_type;
523                         break;
524                 }
525         }
526
527         *access = worldaccess | useraccess;
528         return (CSA_SUCCESS);
529 }
530
531 static CSA_return_code
532 _GetV5AccessRights(
533         _DtCmsCalendar  *cal,
534         char            *target,
535         char            *sender,
536         uint            *access)
537 {
538         cms_access_entry        *alist;
539         cms_attribute_value     *owner;
540         int                     worldaccess = 0, useraccess = 0;
541         boolean_t               isowner;
542
543         /* first check to see if the user is the owner of the calendar */
544         owner = cal->attrs[CSA_CAL_ATTR_CALENDAR_OWNER_I].value;
545         isowner = _DtCmsIsFileOwner(owner->item.calendar_user_value, sender,
546                         target);
547
548         if (isowner && cal->checkowner == B_FALSE) {
549                 *access = CSA_OWNER_RIGHTS;
550                 return (CSA_SUCCESS);
551         }
552
553         alist = cal->attrs[CSA_CAL_ATTR_ACCESS_LIST_I].value->\
554                         item.access_list_value;
555
556         if (alist == NULL) {
557                 *access = worldaccess | useraccess;
558                 return (CSA_E_NO_AUTHORITY);
559         }
560
561         for (; alist != NULL; alist = alist->next) {
562                 if (strcmp(alist->user, WORLD) == 0)
563                         worldaccess = alist->rights;
564                 else if (_DtCmIsSameUser(sender, alist->user)) {
565                         useraccess = alist->rights;
566                         break;
567                 }
568         }
569
570         *access = worldaccess | useraccess;
571         return (CSA_SUCCESS);
572 }
573