andre@302: #ifndef WIN32 andre@302: andre@302: #include andre@302: #include andre@302: #include andre@302: #include andre@302: #include andre@302: #include andre@302: #include andre@302: andre@302: #include "nssstore.h" andre@302: #include "logging.h" andre@302: #include "strhelp.h" andre@302: andre@302: /**@brief Start the process to install / remove andre@302: * andre@302: * This forks the process and executes the NSS installation andre@302: * process. It also writes the Instructions to that process. andre@302: * andre@302: * @param [in] to_install strv of DER encoded certificates to be added. andre@302: * @param [in] to_remove strv of DER encoded certificates to be remvoed. andre@302: * @param [in] uid_t uid of the user to install certificates for. andre@302: * @param [in] gid_t the gid of the user to install certificates for. andre@302: * @param [in] homedir the homedir of the user. andre@302: * andre@302: * @returns childs pid on success. -1 on failure andre@302: */ andre@302: static int andre@302: start_procces_for_user (char **to_install, char **to_remove, andre@302: uid_t uid, gid_t gid, char *homedir) andre@302: { andre@302: int pipe_fd[2]; andre@302: pid_t pid = 0; andre@302: char *argv[] = {"mozilla", NULL}, andre@302: *envp[2]; andre@302: size_t homedir_len = 0; andre@302: int ret = -1, andre@302: i = 0; andre@302: FILE *stream = NULL; andre@302: bool success = false; andre@302: andre@302: if (homedir == NULL) andre@302: { andre@302: ERRORPRINTF ("Invalid call to start_process_for_user\n"); andre@302: return -1; andre@302: } andre@302: andre@302: homedir_len = strlen (homedir); andre@302: andre@302: /* Allocate space for HOME=homedir\0 */ andre@302: envp[0] = xmalloc (homedir_len + 6); andre@302: envp[1] = NULL; andre@302: andre@302: ret = snprintf (envp[0], homedir_len + 6, "HOME=%s", homedir); andre@302: andre@302: if (ret < 0 || (size_t) ret != homedir_len + 5) andre@302: { andre@302: ERRORPRINTF ("Error setting home env variable.\n"); andre@302: xfree (envp[0]); andre@302: return -1; andre@302: } andre@302: andre@302: DEBUGPRINTF ("Home: %s \n", envp[0]); andre@302: andre@302: if (pipe (pipe_fd)) andre@302: { andre@302: ERRORPRINTF ("Failed to create pipe.\n"); andre@302: return -1; andre@302: } andre@302: andre@302: pid = fork(); andre@302: andre@302: if (pid == (pid_t) -1) andre@302: { andre@302: ERRORPRINTF ("Failed to fork child.\n"); andre@302: return -1; andre@302: } andre@302: andre@302: if (pid == (pid_t) 0) andre@302: { andre@302: /* Drop privileges */ andre@302: if (setuid (uid) || setgid (gid)) andre@302: { andre@302: exit(-1); andre@302: } andre@302: andre@302: close (pipe_fd[1]); andre@302: dup2 (pipe_fd[0], 0); andre@302: close (pipe_fd[0]); andre@302: /* TODO find path based on current executable */ andre@302: execve ("mozilla", argv, envp); andre@302: exit (127); andre@302: } andre@302: andre@302: close (pipe_fd[0]); andre@302: stream = fdopen(pipe_fd[1], "w"); andre@302: if (stream == NULL) andre@302: { andre@302: ERRORPRINTF ("Failed to open pipe for writing\n"); andre@302: goto done; andre@302: } andre@302: andre@302: /* Send the instructions */ andre@302: for (i = 0; to_install && to_install[i]; i++) andre@302: { andre@302: if (fprintf (stream, "I:%s\n", to_install[i]) <= 3) andre@302: { andre@302: ERRORPRINTF ("Write failed \n"); andre@302: goto done; andre@302: } andre@302: } andre@302: andre@302: for (i = 0; to_remove && to_remove[i]; i++) andre@302: { andre@302: if (fprintf (stream, "R:%s\n", to_remove[i]) <= 3) andre@302: { andre@302: ERRORPRINTF ("Write failed \n"); andre@302: goto done; andre@302: } andre@302: } andre@302: andre@302: success = true; andre@302: andre@302: done: andre@302: if (stream) { andre@302: fclose (stream); andre@302: } andre@302: xfree (envp[0]); andre@302: close(pipe_fd[0]); andre@302: close(pipe_fd[1]); andre@302: andre@302: if (success) andre@302: { andre@302: return pid; andre@302: } andre@302: return -1; andre@302: } andre@302: andre@302: int andre@302: write_stores_nss (char **to_install, char **to_remove) andre@302: { andre@302: uid_t my_uid = getuid(); andre@302: andre@302: if (my_uid != 0) andre@302: { andre@302: /* Running as a user */ andre@302: char *homedir = getenv ("HOME"); andre@302: pid_t childprocess = -1; /* Only one child for single user installation */ andre@302: int status = -1; andre@302: if (!homedir) andre@302: { andre@302: ERRORPRINTF ("Failed to find home directory\n"); andre@302: } andre@302: andre@302: childprocess = start_procces_for_user (to_install, to_remove, andre@302: my_uid, getgid(), homedir); andre@302: andre@302: if (childprocess == -1) andre@302: { andre@302: ERRORPRINTF ("Failed to start childprocess!\n"); andre@302: return -1; andre@302: } andre@302: andre@302: childprocess = waitpid (childprocess, &status, 0); andre@302: if (childprocess == -1 || !WIFEXITED(status)) andre@302: { andre@302: ERRORPRINTF ("Waitpid failed.\n"); andre@302: return -1; andre@302: } andre@302: DEBUGPRINTF ("Child returned status: %i", WEXITSTATUS(status)); andre@302: andre@302: return 0; andre@302: } andre@302: printf ("Installation as root is not yet implemented\n"); andre@302: /* TODO root parse /etc/passwd for users with a home directory */ andre@302: return 0; andre@302: } andre@302: #endif