Ignore:
Timestamp:
01/07/14 14:18:31 (12 months ago)
Author:
Kris Moore <kris@…>
Branches:
master, releng/10.0, releng/10.0.1, releng/10.0.2, releng/10.0.3, releng/10.1
Children:
aa7ba66
Parents:
7004a51
Message:

Add a cool new system callback function to PBIs on 10.x and beyond

This allows PBIs, which run in a container, to use the pbisyscmd, openwith
or xdg-open, and "talk" to applications on the outside of the container.

The use-case for this would be a application like Thunderbird, which may
want to use the "xdg-open" command to open a PDF file with something else
on the system.

It could be used by other apps, such as terminal emulators to run a shell on the system,
even though the GUI is run in the container

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src-sh/pbi-manager/pbime/pbime.c

    rb3e939a ra7429d5  
    22 * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org> 
    33 * Copyright (c) 2007 Bill Moran/Collaborative Fusion 
    4  * Copyright (c) 2013 Kris Moore/PC-BSD Software <kris@pcbsd.org> 
     4 * Copyright (c) 2014 Kris Moore/PC-BSD Software <kris@pcbsd.org> 
    55 * All rights reserved. 
    66 * 
     
    3131#include <sys/jail.h> 
    3232#include <sys/types.h> 
     33#include <sys/wait.h> 
    3334 
    3435#include <err.h> 
     
    4344static void     usage(void); 
    4445 
    45 int 
    46 main(int argc, char *argv[]) 
     46void ch_user(void); 
     47 
     48void ch_user(void) 
    4749{ 
    48         char newchroot[2048]; 
    49         char mountscript[4096]; 
    5050        int jid, ngroups; 
    51         int argoffset; 
    5251        uid_t huid; 
    5352        struct passwd *husername, *jusername; 
     
    5554        login_cap_t *lcap; 
    5655 
    57         /* Is this a request to unmount? */ 
    58         if ( argc == 3 ) { 
    59                 if ( strcmp(argv[1], "umount") == 0 ) { 
    60                         strcpy(mountscript, "/usr/pbi/.pbimount umount "); 
    61                         strcat(mountscript, argv[2]); 
    62                         return system(mountscript); 
    63                 } 
    64         } 
    65  
    66         if (argc < 4) 
    67                 usage(); 
    68  
    6956        /* Get the current user ID and user name in the host system */ 
    7057        huid = getuid(); 
    7158        husername = getpwuid(huid); 
    72  
    73         /* Run the mount script */ 
    74         if ( (strlen("/usr/pbi/.pbimount") + strlen(argv[1]) + strlen(argv[2])) > 4090) 
    75                 err(1, "Max length exceeded for pbidir / mntdir"); 
    76  
    77         if ( strlen("argv[2]") + strlen("/virtbase") > 2040) 
    78                 err(1, "Max length exceeded for virtbase"); 
    79         strcpy(newchroot, argv[1]); 
    80         strcat(newchroot, "/virtbase"); 
    81          
    82         strcpy(mountscript, "/usr/pbi/.pbimount "); 
    83         strcat(mountscript, argv[1]); 
    84         strcat(mountscript, " "); 
    85         strcat(mountscript, argv[2]); 
    86         //printf( "mountscript: %s \n", mountscript); 
    87         if ( system(mountscript) != 0 ) 
    88                 err(1, "Failed mounting PBI"); 
    89  
    90         if (chdir(newchroot) == -1 || chroot(".") == -1) 
    91                 err(1, "Could not chroot to: %s", newchroot); 
    92  
    93         argoffset=4; 
    94         if (chdir(argv[4]) == -1 ) { 
    95                 // Running with old pbi wrapper 
    96                 argoffset=3; 
    97         } 
    9859 
    9960        /* Get the user name in the jail */ 
     
    10162        if (jusername == NULL || strcmp(husername->pw_name, jusername->pw_name) != 0) 
    10263                err(1, "Username mapping failed"); 
    103         //if (chdir("/") == -1) 
    104         //      err(1, "chdir(): /"); 
    10564        lcap = login_getpwclass(jusername); 
    10665        if (lcap == NULL) { 
     
    11877                err(1, "setusercontext"); 
    11978        login_close(lcap); 
    120         if (execvp(argv[3], argv + argoffset) == -1) 
    121                 err(1, "execvp(): %s", argv[3]); 
     79} 
     80 
     81int 
     82main(int argc, char *argv[]) 
     83{ 
     84        char newchroot[2048]; 
     85        char mountscript[4096]; 
     86        char pipetemplate[] = "/tmp/.pbi-callback-XXXXXXXXXXXXXXXX"; 
     87        char *pipedir; 
     88        char fifoin[MAXPATHLEN];  
     89        int argoffset; 
     90 
     91        pid_t listen_pid; 
     92        pid_t app_pid; 
     93        int listen_status; 
     94        int app_status; 
     95 
     96        /* Is this a request to unmount? */ 
     97        if ( argc == 3 ) { 
     98                if ( strcmp(argv[1], "umount") == 0 ) { 
     99                        strcpy(mountscript, "/usr/pbi/.pbimount umount "); 
     100                        strcat(mountscript, argv[2]); 
     101                        return system(mountscript); 
     102                } 
     103        } 
     104 
     105        if (argc < 4) 
     106                usage(); 
     107 
     108 
     109        /* Run the mount script */ 
     110        if ( (strlen("/usr/pbi/.pbimount") + strlen(argv[1]) + strlen(argv[2])) > 4090) 
     111                err(1, "Max length exceeded for pbidir / mntdir"); 
     112 
     113        if ( strlen("argv[2]") + strlen("/virtbase") > 2040) 
     114                err(1, "Max length exceeded for virtbase"); 
     115        strcpy(newchroot, argv[1]); 
     116        strcat(newchroot, "/virtbase"); 
     117         
     118        strcpy(mountscript, "/usr/pbi/.pbimount "); 
     119        strcat(mountscript, argv[1]); 
     120        strcat(mountscript, " "); 
     121        strcat(mountscript, argv[2]); 
     122        //printf( "mountscript: %s \n", mountscript); 
     123        if ( system(mountscript) != 0 ) 
     124                err(1, "Failed mounting PBI"); 
     125 
     126        // Lets get our template directory 
     127        pipedir = mktemp(pipetemplate); 
     128 
     129        // Set the environment variable 
     130        setenv("PBI_SYSPIPE", pipedir, 1); 
     131         
     132        // Fork off a listener for system commands 
     133        listen_pid = fork(); 
     134        if(listen_pid == 0) { 
     135                /* This is done by the child process. */ 
     136                // drop priv 
     137                ch_user(); 
     138 
     139                // Create the pipe file 
     140                strcpy(fifoin, "mkfifo "); 
     141                strcat(fifoin, pipedir); 
     142                if ( system(fifoin) == 0 ) { 
     143                        // Start the listen process only if mkfifo is successful 
     144                        exit(system("sh /usr/pbi/.pbisyslisten")); 
     145                } 
     146        } else { 
     147 
     148                // Do the chroot 
     149                if (chdir(newchroot) == -1 || chroot(".") == -1) 
     150                        err(1, "Could not chroot to: %s", newchroot); 
     151 
     152                // drop priv 
     153                ch_user(); 
     154 
     155                // Backwards compat check for old PBIs 
     156                argoffset=4; 
     157                if (chdir(argv[4]) == -1 ) { 
     158                        // Running with old pbi wrapper 
     159                        argoffset=3; 
     160                } 
     161 
     162 
     163                // Fork off the PBI process, and have the parent wait for it to finish 
     164                app_pid = fork(); 
     165                if(app_pid == 0) { 
     166                        // Execute the PBI now 
     167                        if (execvp(argv[3], argv + argoffset) == -1) 
     168                                err(1, "execvp(): %s", argv[3]); 
     169                        exit(0); 
     170                } else { 
     171                        /* This is run by the parent.  Wait for the child to terminate. */ 
     172                        pid_t tpid; 
     173                        do { 
     174                                tpid = wait(&app_status); 
     175                        } while(tpid != app_pid); 
     176 
     177                        // Stop the listener 
     178                        strcpy(fifoin, "echo 'CLOSE:' > "); 
     179                        strcat(fifoin, pipedir); 
     180                        system(fifoin); 
     181 
     182                        // Remove the old pipefile 
     183                        strcpy(fifoin, "rm "); 
     184                        strcat(fifoin, pipedir); 
     185                        system(fifoin); 
     186 
     187                        return app_status; 
     188                } 
     189 
     190        } 
     191 
    122192        exit(0); 
    123193} 
     
    127197{ 
    128198 
    129         fprintf(stderr, "usage: pbime mntdir pbidir command [...]\n"); 
     199        fprintf(stderr, "usage: pbime mntdir pbidir command cwd [...]\n"); 
    130200        exit(1);  
    131201} 
Note: See TracChangeset for help on using the changeset viewer.