Fixing bug with searching cookie and privileges in security-server.
[framework/security/security-server.git] / src / security-srv / server / security-server-cookie.c
1 /*
2  *  security-server
3  *  Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd All Rights Reserved
4  *
5  *  Contact: Bumjin Im <bj.im@samsung.com>
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License");
8  *  you may not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS,
15  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License
18  *
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/stat.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <fcntl.h>
29 #include <sys/smack.h>
30
31 #include "security-server-cookie.h"
32
33 /* Delete useless cookie item *
34  * then connect prev and next */
35 int free_cookie_item(cookie_list *cookie)
36 {
37         if(cookie->path != NULL)
38                 free(cookie->path);
39         if(cookie->permissions != NULL)
40                 free(cookie->permissions);
41         if(cookie->smack_label != NULL)
42                 free(cookie->smack_label);
43         if(cookie->prev != NULL)
44                 cookie->prev->next = cookie->next;
45         if(cookie->next != NULL)
46                 cookie->next->prev = cookie->prev;
47         free(cookie);
48         cookie = NULL;
49         return 0;
50 }
51
52 /* Cut the link of the current cookie item and connect previous link and next line *
53  * That is remove a cookie item *
54  * Returns next cookie item  if exist, NULL for no more cookie item */
55 cookie_list *delete_cookie_item(cookie_list *cookie)
56 {
57         cookie_list *retval = NULL;
58         if(cookie == NULL)
59         {
60                 SEC_SVR_DBG("%s", "Cannot delete null cookie");
61                 return retval;
62         }
63
64         /* Reconnect cookie item */
65         if(cookie->next != NULL)
66         {
67                 cookie->prev->next = cookie->next;
68                 cookie->next->prev = cookie->prev;
69                 retval = cookie->next;
70         }
71         else
72         {
73                 cookie->prev->next = NULL;
74         }
75         
76         free_cookie_item(cookie);
77         return retval;
78 }
79
80 cookie_list * garbage_collection(cookie_list *cookie)
81 {
82         char path[17];
83         cookie_list *retval = NULL;
84         struct stat statbuf;
85         int ret;
86
87         while(cookie != NULL)
88         {
89                 /* Skip default cookie */
90                 if(cookie->pid ==0)
91                         return cookie;
92
93                 /* Try to find the PID directory from proc fs */
94                 snprintf(path, sizeof(path), "/proc/%d", cookie->pid);
95                 path[16] = 0;
96                 ret = stat(path, &statbuf);
97                 if(ret != 0)
98                 {
99                         /* If it's not exist, delete the cookie */
100                         if(errno == ENOENT)
101                         {
102                                 SEC_SVR_DBG("Garbage found. PID:%d, deleting...", cookie->pid);
103                                 cookie = delete_cookie_item(cookie);
104                                 continue;
105                         }
106                         else
107                         {
108                                 /* Some error occurred */
109                                 SEC_SVR_DBG("Error occurred on stat: errno = %d", errno);
110                                 return cookie;
111                         }
112                 }
113                 else
114                 {
115                         /* This is not a garbage. returning */
116                         return cookie;
117                 }
118         }
119         return retval;
120 }
121
122 /* Search existing cookie from the cookie list for the client process *
123  * At the same time, it collects garbage cookie which PID is no longer exist and delete them */
124 cookie_list *search_existing_cookie(int pid, const cookie_list *c_list)
125 {
126         cookie_list *current =(cookie_list *)c_list, *cookie = NULL;
127         char *cmdline = NULL, *debug_cmdline = NULL;
128
129         /* Search from the list */
130         while(current != NULL)
131         {
132                 /* print_cookie(current);*/
133                 current = garbage_collection(current);
134                 if(current == NULL)
135                         break;
136
137                 /* PID must be same */
138                 if(current->pid == pid)
139                 {
140                         /* Found cookie for the pid. Check the cookie is reused by dirrent executable */
141                         /* Check the path of the process */
142                         cmdline = (char*)read_cmdline_from_proc(pid);
143                         if(cmdline == NULL)
144                         {
145                                 SEC_SVR_DBG("%s", "cannot read cmdline");
146                                 return NULL;
147                         }
148                         /* Check the path is different */
149                         if(strncmp(cmdline, current->path, current->path_len) != 0 || strlen(cmdline) != current->path_len)
150                         {
151                                 SEC_SVR_DBG("pid [%d] has been reused by %s. deleting the old cookie.", pid, cmdline);
152                                 debug_cmdline = malloc(current->path_len + 1);
153                                 if(debug_cmdline == NULL)
154                                 {
155                                         SEC_SVR_DBG("%s", "out of memory error");
156                                         free(cmdline);
157                                         return NULL;
158                                 }
159                                 strncpy(debug_cmdline, current->path, current->path_len);
160                                 debug_cmdline[current->path_len] = 0;
161                                 SEC_SVR_DBG("[%s] --> [%s]", cmdline, debug_cmdline);
162                                 if(debug_cmdline != NULL)
163                                 {
164                                         free(debug_cmdline);
165                                         debug_cmdline = NULL;
166                                 }
167                                 /* Okay. delete current cookie */
168                                 current = delete_cookie_item(current);
169                                 if(cmdline != NULL)
170                                 {
171                                         free(cmdline);
172                                         cmdline = NULL;
173                                 }
174                                 continue;
175                         }
176                         else
177                         {
178                                 SEC_SVR_DBG("%s", "cookie found");
179                                 cookie = current;
180                         }
181
182                         if(cmdline != NULL)
183                         {
184                                 free(cmdline);
185                                 cmdline = NULL;
186                         }
187                 }
188                 current = current->next;
189         }
190         return cookie;
191 }
192
193 /* Search existing cookie from the cookie list for matching pid *
194  * Default cookie (meaning PID 0) is not allowed in here */
195 cookie_list *search_cookie_from_pid(cookie_list *c_list, int pid)
196 {
197         cookie_list *current = (cookie_list *)c_list, *retval = NULL;
198
199         /* Search from the list */
200         while(current != NULL)
201         {
202                 /* print_cookie(current);*/
203                 /* PID must be same */
204                 current = garbage_collection(current);
205                 if(current == NULL)
206                         break;
207
208                 if(current->pid == pid)
209                 {
210                         SEC_SVR_DBG("%s", "cookie has been found");
211                         retval = current;
212                         goto finish;
213                 }
214                 current = current->next;
215         }
216 finish:
217         return retval;
218 }
219
220 /* Search existing cookie from the cookie list for matching cookie and privilege */
221 /* If privilege is 0, just search cookie exists or not */
222 cookie_list *search_cookie(const cookie_list *c_list, const unsigned char *cookie, int privilege)
223 {
224         cookie_list *current = (cookie_list *)c_list, *retval = NULL;
225         int i;
226
227         /* Search from the list */
228         while(current != NULL)
229         {
230                 /* print_cookie(current);*/
231                 /* PID must be same */
232                 current = garbage_collection(current);
233                 if(current == NULL)
234                         break;
235
236         //searching for cookie
237                 if(memcmp(current->cookie, cookie, SECURITY_SERVER_COOKIE_LEN) == 0)
238                 {
239                         SEC_SVR_DBG("%s", "cookie has been found");
240
241             //check if this cookie belongs to root process
242             if(current->is_roots_process == 1)
243             {
244                 SEC_SVR_DBG("%s", "Root process cookie, special privileges");
245                 //we can skip privilege checking
246                 retval = current;
247                 goto finish;
248             }
249
250                         for(i=0 ; i < current->permission_len ; i++)
251                         {
252                                 if(privilege == current->permissions[i])
253                                 {
254                                         SEC_SVR_DBG("Found privilege %d", privilege);
255                                         retval = current;
256                                         goto finish;
257                                 }
258                         }
259                 }
260                 current = current->next;
261         }
262 finish:
263         return retval;
264 }
265
266
267 cookie_list *search_cookie_new(const cookie_list *c_list,
268                                const unsigned char *cookie,
269                                const char *object,
270                                const char *access_rights)
271 {
272         cookie_list *current = (cookie_list *)c_list, *retval = NULL;
273         int ret;
274         int i;
275
276         /* Search from the list */
277         while(current != NULL)
278         {
279                 /* print_cookie(current);*/
280                 /* PID must be same */
281                 current = garbage_collection(current);
282                 if(current == NULL)
283                         break;
284
285                 if(memcmp(current->cookie, cookie, SECURITY_SERVER_COOKIE_LEN) == 0)
286                 {
287                         SEC_SVR_DBG("%s", "cookie has been found");
288
289                                 ret = smack_have_access(current->smack_label, object, access_rights);
290           SEC_SVR_DBG("smack_have_access, subject >%s< object >%s< access >%s< ===> %d",
291                     current->smack_label, object, access_rights, ret);
292                                 if (ret == 1)
293                                 {
294                                         retval = current;
295                                         goto finish;
296                                 }
297                 }
298                 current = current->next;
299         }
300 finish:
301         return retval;
302 }
303
304
305 /* Generage a random stream value of size to cookie *
306  * by reading /dev/uranddom file */
307 int generate_random_cookie(unsigned char *cookie, int size)
308 {
309         int fd, ret;
310
311     if (cookie == NULL) {
312         SEC_SVR_DBG("%s", "Null pointer passed to function");
313         return SECURITY_SERVER_ERROR_UNKNOWN;
314     }
315         fd = open("/dev/urandom", O_RDONLY);
316         if(fd < 0)
317         {
318                 SEC_SVR_DBG("%s", "Cannot open /dev/urandom");
319                 return SECURITY_SERVER_ERROR_FILE_OPERATION;
320         }
321         ret = read(fd, cookie, size);
322         if(ret < size)
323         {
324                 SEC_SVR_DBG("Cannot read /dev/urandom: %d", ret);
325                 ret = SECURITY_SERVER_ERROR_FILE_OPERATION;
326                 goto error;
327         }
328         close(fd);
329         ret = SECURITY_SERVER_SUCCESS;
330 error:
331         if(fd >= 0)
332                 close(fd);
333         return ret;
334 }
335
336 /* Create a cookie item from PID */
337 cookie_list *create_cookie_item(int pid, int sockfd, cookie_list *c_list)
338 {
339         int ret, tempint;
340         cookie_list *added = NULL, *current = NULL;
341         char path[24], *cmdline = NULL;
342         char *buf = NULL, inputed, *tempptr = NULL;
343         char delim[] = ": ", *token = NULL;
344         int *permissions = NULL, perm_num = 1, cnt, i, *tempperm = NULL;
345         char *smack_label = NULL;
346         FILE *fp = NULL;
347
348         current = search_existing_cookie(pid, c_list);
349         if(current != NULL)
350         {
351                 /* There is a cookie for this process already */
352                 added = current;
353                 SEC_SVR_DBG("%s", "Existing cookie found");
354                 goto error;
355         }
356
357         /* Read command line of the PID from proc fs */
358         cmdline = (char *)read_cmdline_from_proc(pid);
359         if(cmdline == NULL)
360         {
361                 SEC_SVR_DBG("Error on reading /proc/%d/cmdline", pid);
362                 goto error;
363         }
364
365         /*
366          * modified by security part
367          *  - get gid from /etc/group
368          */
369         /* Read group info of the PID from proc fs - /proc/[PID]/status */
370         snprintf(path, sizeof(path), "/proc/%d/status", pid);
371         fp = fopen(path, "r");
372
373         /* Find the line which starts with 'Groups:' */
374         i = 0;
375         
376         while(1)
377         {
378                 buf = (char*)malloc(sizeof(char) * 128);
379                 if(buf == NULL)
380                 {
381                         SEC_SVR_DBG("%s", "Error on malloc()");
382                         goto error;
383                 }
384                 memset(buf, 0x00, 128);
385                 cnt = 128;
386
387                 /* get one line from /proc/[PID]/status */
388                 while(1)
389                 {
390                         tempint = fgetc(fp);
391                         inputed = (char)tempint;
392                         if(tempint == EOF)
393                                 goto out_of_while;
394                         else if(inputed == '\n')
395                         {
396                                 buf[i] = '\0';
397                                 break;
398                         }
399                         else if((i == cnt) && (inputed != '\n'))
400                         {
401                                 tempptr = (char*)realloc(buf, sizeof(char) * (i + 128));
402                                 if(tempptr == NULL)
403                                 {
404                                         SEC_SVR_DBG("%s", "Error on realloc()");
405                                         goto error;
406                                 }
407                                 buf = tempptr;
408                                 buf[i++] = inputed;
409                                 cnt = i + 128;
410                         }
411                         else
412                                 buf[i++] = inputed;
413                 }
414                 i = 0;
415
416                 /* find 'Groups:' */
417                 if(strncmp(buf, "Groups:", 7) == 0)
418                 {
419                         /* get gid from the line and insert to 'permissions' array */
420                         token = strtok(buf, delim); // first string is "Groups"
421                         while((token = strtok(NULL, delim)))
422                         {
423                                 tempperm = realloc(permissions, sizeof(int) * perm_num);
424                                 if(tempperm == NULL)
425                                 {
426                                         SEC_SVR_DBG("%s", "Error on realloc()");
427                                         goto error;
428                                 }
429                                 permissions = tempperm;
430                                 errno = 0;
431                                 permissions[perm_num - 1] = strtoul(token, 0, 10);
432                                 if (errno != 0)
433                                 {
434                                         SEC_SVR_DBG("cannot change string to integer [%s]", token);
435                                         ret = SECURITY_SERVER_ERROR_SERVER_ERROR;
436                                         goto error;
437                                 }
438                                 perm_num++;
439                         }
440                         perm_num--;
441
442                         /* goto out of while loop */
443                         break;
444                 }
445                 if(buf != NULL)
446                 {
447                         free(buf);
448                         buf = NULL;
449                 }
450         }
451 out_of_while:
452                 
453         /* Each group ID is stored in each line of the file */
454 //      while(fgets(permline, sizeof(permline), fp) != NULL)
455 //      {
456 //              permissions = realloc(permissions, sizeof(int) * perm_num);
457 //              if(permissions == NULL)
458 //              {
459 //                      SEC_SVR_DBG("%s", "Error on realloc()");
460 //                      goto error;
461 //              }
462 //              permissions[perm_num -1] = strtoul(permline, 0, 10);
463 //              perm_num++;
464 //      }
465 //      perm_num--;
466         /*
467          * modifying end
468          */
469
470         /* Go to last cookie from the list */
471         current = c_list;
472         while(current->next != NULL)
473         {
474                 current = current->next;
475         }
476
477         /* Create a new one and assign values */
478         added = malloc(sizeof(cookie_list));
479         if(added == NULL)
480                 goto error;
481
482         ret = generate_random_cookie(added->cookie, SECURITY_SERVER_COOKIE_LEN);
483         if(ret != SECURITY_SERVER_SUCCESS)
484         {
485                 SEC_SVR_DBG("Error on making random cookie: %d", ret);
486                 free(added);
487                 added = NULL;
488                 goto error;
489         }
490
491         /* Check SMACK label */
492         ret = smack_new_label_from_socket(sockfd, &smack_label);
493         if (ret != 0)
494         {
495                 SEC_SVR_DBG("Error checking peer label: %d", ret);
496                 free(added);
497                 added = NULL;
498                 goto error;
499         }
500
501         added->path_len = strlen(cmdline);
502         added->path = calloc(1, strlen(cmdline));
503         memcpy(added->path, cmdline, strlen(cmdline));
504
505         added->permission_len = perm_num;
506         added->pid = pid;
507         added->permissions = permissions;
508         added->smack_label = smack_label;
509         added->prev = current;
510         current->next = added;
511         added->next = NULL;
512
513 error:
514         if(cmdline != NULL)
515                 free(cmdline);
516         if(fp != NULL)
517                 fclose(fp);
518         if(buf != NULL)
519                 free(buf);
520
521         if(added == NULL && permissions != NULL)
522                 free(permissions);
523
524         return added;
525 }
526
527 /* Check stored default cookie, if it's not exist make a new one and store it */
528 int check_stored_cookie(unsigned char *cookie, int size)
529 {
530         int fd, ret;
531
532         /* First, check the default cookie is stored */
533         fd = open(SECURITY_SERVER_DEFAULT_COOKIE_PATH, O_RDONLY);
534         if(fd < 0)
535         {
536                 if(errno != ENOENT)
537                 {
538                         SEC_SVR_DBG("Cannot open default cookie. errno=%d", errno);
539                         ret = SECURITY_SERVER_ERROR_FILE_OPERATION;
540                         unlink(SECURITY_SERVER_DEFAULT_COOKIE_PATH);
541                 }
542
543                 ret = generate_random_cookie(cookie, size);
544
545                 /* Save cookie to disk */
546                 fd = open(SECURITY_SERVER_DEFAULT_COOKIE_PATH, O_WRONLY | O_CREAT, 0600);
547                 if (fd < 0)
548                 {
549                         SEC_SVR_DBG("Cannot open default cookie errno=%d", errno);
550                         ret = SECURITY_SERVER_ERROR_FILE_OPERATION;
551                         goto error;
552                 }
553                 ret = write(fd, cookie, size);
554                 if(ret < size)
555                 {
556                         SEC_SVR_DBG("%s", "Cannot save default cookie");
557                         ret = SECURITY_SERVER_ERROR_FILE_OPERATION;
558                         goto error;
559                 }
560
561                 close(fd);
562                 return SECURITY_SERVER_SUCCESS;
563         }
564
565         ret = read (fd, cookie, size);
566         if(ret < size)
567         {
568                 SEC_SVR_DBG("Cannot read default cookie errno=%d", errno);
569                 ret = SECURITY_SERVER_ERROR_FILE_OPERATION;
570                 goto error;
571         }
572         ret = SECURITY_SERVER_SUCCESS;
573
574 error:
575         if(fd >= 0)
576                 close(fd);
577         return ret;
578 }
579 /* Create a cookie item from PID */
580
581 /* Create a default cookie when security server is executed *
582  * Default cookie is for root processes that needs cookie */
583 cookie_list *create_default_cookie(void)
584 {
585         cookie_list *first = NULL;
586         int ret;
587
588         first = malloc(sizeof(cookie_list));
589
590         ret = check_stored_cookie(first->cookie, SECURITY_SERVER_COOKIE_LEN);
591         if(ret != SECURITY_SERVER_SUCCESS)
592         {
593                 SEC_SVR_DBG("Error on making random cookie: %d", ret);
594                 free(first);
595                 return NULL;
596         }
597
598         first->path_len = 0;
599         first->permission_len = 0;
600         first->pid = 0;
601         first->path = NULL;
602         first->permissions = NULL;
603         first->smack_label = NULL;
604         first->prev = NULL;
605         first->next = NULL;
606         return first;
607 }