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