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