dtcm: Resolve CID 87562
[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 librararies 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 %u\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
366 extern uint
367 _DtCmsClassToChangeAccess(cms_entry *entry)
368 {
369         cms_attribute_value *val;
370
371         val = entry->attrs[CSA_ENTRY_ATTR_CLASSIFICATION_I].value;
372
373         switch (val->item.uint32_value) {
374         case CSA_CLASS_PUBLIC:
375                 return (CSA_CHANGE_PUBLIC_ENTRIES);
376         case CSA_CLASS_PRIVATE:
377                 return (CSA_CHANGE_PRIVATE_ENTRIES);
378         case CSA_CLASS_CONFIDENTIAL:
379                 return (CSA_CHANGE_CONFIDENTIAL_ENTRIES);
380         }
381 }
382
383 /*****************************************************************************
384  * static functions used within the file
385  *****************************************************************************/
386
387 static Uname_cache *
388 in_u_cache(uid_t uid)
389 {
390         int     cache = NUM_CACHE;
391         Uname_cache *p_prev;
392         Uname_cache *p_cache;
393
394         p_prev = NULL;
395         p_cache = ucache_list;
396         while (p_cache != NULL)
397         {
398                 if (p_cache->uid == uid)
399                         return (p_cache);
400                 if (--cache < 0)
401                 {
402                         /* Assume that the cache size is at least 1 */
403                         p_prev->next = p_cache->next;
404                         free (p_cache->name);
405                         free (p_cache);
406                         p_cache = p_prev->next;
407                 }
408                 else
409                 {
410                         p_prev = p_cache;
411                         p_cache = p_cache->next;
412                 }
413         }
414         return (NULL);
415 }
416
417 static char *
418 get_uname(uid_t uid)
419 {
420         struct passwd *pw;
421         char buff[16];
422         Uname_cache *ucache, *prev;
423
424         if ((ucache = in_u_cache(uid)) == NULL)
425         {
426                 if ((pw = getpwuid (uid)) == NULL) {
427                         /* Can't map uid to name.  Don't cache the uid. */
428                         sprintf (buff, "%ld", (long)uid);
429                         return (strdup(buff));
430                 }
431
432                 if ((ucache = (Uname_cache *)malloc(sizeof(Uname_cache)))
433                     == NULL)
434                         return (NULL);
435
436                 if ((ucache->name = strdup(pw->pw_name)) == NULL) {
437                         free(ucache);
438                         return (NULL);
439                 }
440                 ucache->uid = uid;
441                 ucache->next = ucache_list;
442                 ucache_list = ucache;
443         }
444
445         return (strdup(ucache->name));
446 }
447
448 static Access_Entry_4 *
449 in_access_list(Access_Entry_4 *l, char *s)
450 {
451         char    *name;
452
453         if (l==NULL || s==NULL) return(NULL);
454         while(l != NULL) {
455                 /* only for combining lists, not for authentication */
456                 if (strcmp(l->who, s) == 0)
457                         break;
458                 l = l->next;
459         }
460         return(l);
461 }
462
463 static Access_Entry_4 *
464 combine_access_list(
465         Access_Entry_4 *p_list, 
466         Access_Entry_4 *p_head, 
467         int type, 
468         int *p_world)
469 {
470         Access_Entry_4  *a;
471         Access_Entry_4  *h = p_head;
472
473         while (p_list != NULL)
474         {
475                 /* Delay to put the WORLD into the combined list because 
476                  * in_access_list() may return wrong result.
477                  */
478                 if (strcmp (p_list->who, WORLD) == 0)
479                         *p_world |= type;
480                 else
481                 {
482                         /* The user is not in the combined list, add to list. */
483                         if ((a = in_access_list (h, p_list->who)) == NULL)
484                         {
485                                 a = _DtCm_make_access_entry4(p_list->who, type);
486                                 a->next = p_head;
487                                 p_head = a;
488                         }
489                         a->access_type |= type;
490                 }
491                 p_list = p_list->next;
492         }
493         return (p_head);
494 }
495
496 static CSA_return_code
497 _GetV4AccessRights(
498         _DtCmsCalendar  *cal,
499         char            *target,
500         char            *sender,
501         uint            *access)
502 {
503         int             worldaccess = 0, useraccess = 0;
504         Access_Entry_4  *alist;
505
506         /* first check to see if the user is the owner of the calendar */
507         if (_DtCmsIsFileOwner(cal->owner, sender, target)) {
508                 *access = CSA_OWNER_RIGHTS;
509                 return (CSA_SUCCESS);
510         }
511
512         for (alist = cal->alist; alist != NULL; alist = alist->next) {
513                 if (strcmp(alist->who, WORLD) == 0)
514                         worldaccess = alist->access_type;
515                 else if (_DtCmIsSameUser(sender, alist->who)) {
516                         useraccess = alist->access_type;
517                         break;
518                 }
519         }
520
521         *access = worldaccess | useraccess;
522         return (CSA_SUCCESS);
523 }
524
525 static CSA_return_code
526 _GetV5AccessRights(
527         _DtCmsCalendar  *cal,
528         char            *target,
529         char            *sender,
530         uint            *access)
531 {
532         cms_access_entry        *alist;
533         cms_attribute_value     *owner;
534         int                     worldaccess = 0, useraccess = 0;
535         boolean_t               isowner;
536
537         /* first check to see if the user is the owner of the calendar */
538         owner = cal->attrs[CSA_CAL_ATTR_CALENDAR_OWNER_I].value;
539         isowner = _DtCmsIsFileOwner(owner->item.calendar_user_value, sender,
540                         target);
541
542         if (isowner && cal->checkowner == B_FALSE) {
543                 *access = CSA_OWNER_RIGHTS;
544                 return (CSA_SUCCESS);
545         }
546
547         alist = cal->attrs[CSA_CAL_ATTR_ACCESS_LIST_I].value->\
548                         item.access_list_value;
549
550         if (alist == NULL) {
551                 *access = worldaccess | useraccess;
552                 return (CSA_E_NO_AUTHORITY);
553         }
554
555         for (; alist != NULL; alist = alist->next) {
556                 if (strcmp(alist->user, WORLD) == 0)
557                         worldaccess = alist->rights;
558                 else if (_DtCmIsSameUser(sender, alist->user)) {
559                         useraccess = alist->rights;
560                         break;
561                 }
562         }
563
564         *access = worldaccess | useraccess;
565         return (CSA_SUCCESS);
566 }
567