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