merge with master
[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
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 * privileges, int privilegesSize)
223 {
224         cookie_list *current = (cookie_list *)c_list, *retval = NULL;
225         int i, j;
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 (root process created it)
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             if((privileges == NULL) || (privilegesSize == 0))
251             {
252                 SEC_SVR_DBG("%s", "No privileges to search in cookie!");
253             }
254             else if(current->permissions == NULL)
255             {
256                 SEC_SVR_DBG("%s", "Cookie has no privileges inside!");
257             }
258             else
259             {
260                 SEC_SVR_DBG("%s", "Searching for privileges");
261                 SEC_SVR_DBG("%s %d", "Privileges in cookie:", current->permission_len);
262                 SEC_SVR_DBG("%s %d", "Privileges to search:", privilegesSize);
263
264                 for(j = 0; j < privilegesSize; j++)
265                 {
266                     for(i = 0; i < current->permission_len; i++)
267                     {
268                         if(privileges[j] == current->permissions[i])
269                         {
270                             SEC_SVR_DBG("Found privilege %d", privileges[j]);
271                             retval = current;
272                             goto finish;
273                         }
274                     }
275                 }
276             }
277                 }
278                 current = current->next;
279         }
280 finish:
281         return retval;
282 }
283
284
285 cookie_list *search_cookie_new(const cookie_list *c_list,
286                                const unsigned char *cookie,
287                                const char *object,
288                                const char *access_rights)
289 {
290         cookie_list *current = (cookie_list *)c_list, *retval = NULL;
291         int ret;
292         int i;
293
294         /* Search from the list */
295         while(current != NULL)
296         {
297                 /* print_cookie(current);*/
298                 /* PID must be same */
299                 current = garbage_collection(current);
300                 if(current == NULL)
301                         break;
302
303                 if(memcmp(current->cookie, cookie, SECURITY_SERVER_COOKIE_LEN) == 0)
304                 {
305                         SEC_SVR_DBG("%s", "cookie has been found");
306
307                                 ret = smack_have_access(current->smack_label, object, access_rights);
308           SEC_SVR_DBG("smack_have_access, subject >%s< object >%s< access >%s< ===> %d",
309                     current->smack_label, object, access_rights, ret);
310                                 if (ret == 1)
311                                 {
312                                         retval = current;
313                                         goto finish;
314                                 }
315                 }
316                 current = current->next;
317         }
318 finish:
319         return retval;
320 }
321
322
323 /* Generage a random stream value of size to cookie *
324  * by reading /dev/uranddom file */
325 int generate_random_cookie(unsigned char *cookie, int size)
326 {
327         int fd, ret;
328
329     if (cookie == NULL) {
330         SEC_SVR_DBG("%s", "Null pointer passed to function");
331         return SECURITY_SERVER_ERROR_UNKNOWN;
332     }
333         fd = open("/dev/urandom", O_RDONLY);
334         if(fd < 0)
335         {
336                 SEC_SVR_DBG("%s", "Cannot open /dev/urandom");
337                 return SECURITY_SERVER_ERROR_FILE_OPERATION;
338         }
339         ret = read(fd, cookie, size);
340         if(ret < size)
341         {
342                 SEC_SVR_DBG("Cannot read /dev/urandom: %d", ret);
343                 ret = SECURITY_SERVER_ERROR_FILE_OPERATION;
344                 goto error;
345         }
346         ret = SECURITY_SERVER_SUCCESS;
347 error:
348         if(fd >= 0)
349                 close(fd);
350         return ret;
351 }
352
353 /* Create a cookie item from PID */
354 cookie_list *create_cookie_item(int pid, int sockfd, cookie_list *c_list)
355 {
356         int ret, tempint;
357         cookie_list *added = NULL, *current = NULL;
358         char path[24], *cmdline = NULL;
359         char *buf = NULL, inputed, *tempptr = NULL;
360         char delim[] = ": ", *token = NULL;
361         int *permissions = NULL, perm_num = 1, cnt, i, *tempperm = NULL;
362         char *smack_label = NULL;
363         FILE *fp = NULL;
364
365         current = search_existing_cookie(pid, c_list);
366         if(current != NULL)
367         {
368                 /* There is a cookie for this process already */
369                 added = current;
370                 SEC_SVR_DBG("%s", "Existing cookie found");
371                 goto error;
372         }
373
374         /* Read command line of the PID from proc fs */
375         cmdline = (char *)read_cmdline_from_proc(pid);
376         if(cmdline == NULL)
377         {
378                 SEC_SVR_DBG("Error on reading /proc/%d/cmdline", pid);
379                 goto error;
380         }
381
382         /*
383          * modified by security part
384          *  - get gid from /etc/group
385          */
386         /* Read group info of the PID from proc fs - /proc/[PID]/status */
387         snprintf(path, sizeof(path), "/proc/%d/status", pid);
388         fp = fopen(path, "r");
389
390         /* Find the line which starts with 'Groups:' */
391         i = 0;
392         
393         while(1)
394         {
395                 buf = (char*)malloc(sizeof(char) * 128);
396                 if(buf == NULL)
397                 {
398                         SEC_SVR_DBG("%s", "Error on malloc()");
399                         goto error;
400                 }
401                 memset(buf, 0x00, 128);
402                 cnt = 128;
403
404                 /* get one line from /proc/[PID]/status */
405                 while(1)
406                 {
407                         tempint = fgetc(fp);
408                         inputed = (char)tempint;
409                         if(tempint == EOF)
410                                 goto out_of_while;
411                         else if(inputed == '\n')
412                         {
413                                 buf[i] = '\0';
414                                 break;
415                         }
416                         else if((i == cnt) && (inputed != '\n'))
417                         {
418                                 tempptr = (char*)realloc(buf, sizeof(char) * (i + 128));
419                                 if(tempptr == NULL)
420                                 {
421                                         SEC_SVR_DBG("%s", "Error on realloc()");
422                                         goto error;
423                                 }
424                                 buf = tempptr;
425                                 buf[i++] = inputed;
426                                 cnt = i + 128;
427                         }
428                         else
429                                 buf[i++] = inputed;
430                 }
431                 i = 0;
432
433                 /* find 'Groups:' */
434                 if(strncmp(buf, "Groups:", 7) == 0)
435                 {
436                         /* get gid from the line and insert to 'permissions' array */
437                         token = strtok(buf, delim); // first string is "Groups"
438                         while((token = strtok(NULL, delim)))
439                         {
440                                 tempperm = realloc(permissions, sizeof(int) * perm_num);
441                                 if(tempperm == NULL)
442                                 {
443                                         SEC_SVR_DBG("%s", "Error on realloc()");
444                                         goto error;
445                                 }
446                                 permissions = tempperm;
447                                 errno = 0;
448                                 permissions[perm_num - 1] = strtoul(token, 0, 10);
449                                 if (errno != 0)
450                                 {
451                                         SEC_SVR_DBG("cannot change string to integer [%s]", token);
452                                         ret = SECURITY_SERVER_ERROR_SERVER_ERROR;
453                                         goto error;
454                                 }
455                                 perm_num++;
456                         }
457                         perm_num--;
458
459                         /* goto out of while loop */
460                         break;
461                 }
462                 if(buf != NULL)
463                 {
464                         free(buf);
465                         buf = NULL;
466                 }
467         }
468 out_of_while:
469                 
470         /* Each group ID is stored in each line of the file */
471 //      while(fgets(permline, sizeof(permline), fp) != NULL)
472 //      {
473 //              permissions = realloc(permissions, sizeof(int) * perm_num);
474 //              if(permissions == NULL)
475 //              {
476 //                      SEC_SVR_DBG("%s", "Error on realloc()");
477 //                      goto error;
478 //              }
479 //              permissions[perm_num -1] = strtoul(permline, 0, 10);
480 //              perm_num++;
481 //      }
482 //      perm_num--;
483         /*
484          * modifying end
485          */
486
487         /* Go to last cookie from the list */
488         current = c_list;
489         while(current->next != NULL)
490         {
491                 current = current->next;
492         }
493
494         /* Create a new one and assign values */
495         added = malloc(sizeof(cookie_list));
496         if(added == NULL)
497                 goto error;
498
499         ret = generate_random_cookie(added->cookie, SECURITY_SERVER_COOKIE_LEN);
500         if(ret != SECURITY_SERVER_SUCCESS)
501         {
502                 SEC_SVR_DBG("Error on making random cookie: %d", ret);
503                 free(added);
504                 added = NULL;
505                 goto error;
506         }
507
508         /* Check SMACK label */
509         ret = smack_new_label_from_socket(sockfd, &smack_label);
510         if (ret != 0)
511         {
512                 SEC_SVR_DBG("Error checking peer label: %d", ret);
513                 free(added);
514                 added = NULL;
515                 goto error;
516         }
517
518         added->path_len = strlen(cmdline);
519         added->path = calloc(1, strlen(cmdline));
520         memcpy(added->path, cmdline, strlen(cmdline));
521
522         added->permission_len = perm_num;
523         added->pid = pid;
524         added->permissions = permissions;
525         added->smack_label = smack_label;
526         added->prev = current;
527         current->next = added;
528         added->next = NULL;
529
530 error:
531         if(cmdline != NULL)
532                 free(cmdline);
533         if(fp != NULL)
534                 fclose(fp);
535         if(buf != NULL)
536                 free(buf);
537
538         if(added == NULL && permissions != NULL)
539                 free(permissions);
540
541         return added;
542 }
543
544 /* Check stored default cookie, if it's not exist make a new one and store it */
545 int check_stored_cookie(unsigned char *cookie, int size)
546 {
547         int fd, ret;
548
549         /* First, check the default cookie is stored */
550         fd = open(SECURITY_SERVER_DEFAULT_COOKIE_PATH, O_RDONLY);
551         if(fd < 0)
552         {
553                 if(errno != ENOENT)
554                 {
555                         SEC_SVR_DBG("Cannot open default cookie. errno=%d", errno);
556                         ret = SECURITY_SERVER_ERROR_FILE_OPERATION;
557                         unlink(SECURITY_SERVER_DEFAULT_COOKIE_PATH);
558                 }
559
560                 ret = generate_random_cookie(cookie, size);
561
562                 /* Save cookie to disk */
563                 fd = open(SECURITY_SERVER_DEFAULT_COOKIE_PATH, O_WRONLY | O_CREAT, 0600);
564                 if (fd < 0)
565                 {
566                         SEC_SVR_DBG("Cannot open default cookie errno=%d", errno);
567                         ret = SECURITY_SERVER_ERROR_FILE_OPERATION;
568                         goto error;
569                 }
570                 ret = write(fd, cookie, size);
571                 if(ret < size)
572                 {
573                         SEC_SVR_DBG("%s", "Cannot save default cookie");
574                         ret = SECURITY_SERVER_ERROR_FILE_OPERATION;
575                         goto error;
576                 }
577
578                 close(fd);
579                 return SECURITY_SERVER_SUCCESS;
580         }
581
582         ret = read (fd, cookie, size);
583         if(ret < size)
584         {
585                 SEC_SVR_DBG("Cannot read default cookie errno=%d", errno);
586                 ret = SECURITY_SERVER_ERROR_FILE_OPERATION;
587                 goto error;
588         }
589         ret = SECURITY_SERVER_SUCCESS;
590
591 error:
592         if(fd >= 0)
593                 close(fd);
594         return ret;
595 }
596 /* Create a cookie item from PID */
597
598 /* Create a default cookie when security server is executed *
599  * Default cookie is for root processes that needs cookie */
600 cookie_list *create_default_cookie(void)
601 {
602         cookie_list *first = NULL;
603         int ret;
604
605         first = malloc(sizeof(cookie_list));
606
607         ret = check_stored_cookie(first->cookie, SECURITY_SERVER_COOKIE_LEN);
608         if(ret != SECURITY_SERVER_SUCCESS)
609         {
610                 SEC_SVR_DBG("Error on making random cookie: %d", ret);
611                 free(first);
612                 return NULL;
613         }
614
615         first->path_len = 0;
616         first->permission_len = 0;
617         first->pid = 0;
618         first->path = NULL;
619         first->permissions = NULL;
620         first->smack_label = NULL;
621         first->prev = NULL;
622         first->next = NULL;
623         return first;
624 }