The Community Forums

Interact with an entire community of cPanel & WHM users!
  1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Setting Group ID of FTP account via API ?

Discussion in 'cPanel Developers' started by PhilGlau, Nov 17, 2010.

  1. PhilGlau

    PhilGlau Active Member

    Joined:
    Nov 3, 2010
    Messages:
    27
    Likes Received:
    0
    Trophy Points:
    1
    We want to set the group id of ftp users we add via an API call.

    Is that possible? The documentation for the FTP module doesn't indicate any parameters for this.
     
  2. cPanelDavidN

    cPanelDavidN Integration Developer
    Staff Member

    Joined:
    Dec 17, 2009
    Messages:
    571
    Likes Received:
    1
    Trophy Points:
    18
    Location:
    Houston, TX
    cPanel Access Level:
    Root Administrator
    Hi PhilGlau,

    Unfortunately, the FTP API calls do not support specifying the group id as you desire.

    The only way I can think to programmatically accomplish this would be to alter the auth files. I'm not sure of your setup, but this is basically what would need to happen

    1) create new ftp user via API call
    2) alter the group id in /etc/proftpd/$cpanel_user file for the new ftp account
    3) run /usr/local/cpanel/bin/updateftp $cpanel_user

    Both ProFTPd and PureFTP use the files in /etc/proftpd/ for authentication on cPanel systems.

    Steps 2 and 3 would obviously need to happen as root. So, I'm not sure how reasonable it would be in your setup. Even if the group id is altered, I'm not sure what files would be accessible, ie, if you're trying to share resources across multiple cPanel accounts; never tried it.

    I suppose you could implement a function hook for the addftp API call that would perform the alterations under specific conditions. Say, have it look at some ACL list you keep in a secure location (root can only read/write) and if the cPanel user performing the addftp call is in the list, let the alteration occur. However, in the end, I'm not sure how 'smart' you can make the function hook. That is, it may be that not every ftp account created by that particular cPanel user makes needs to have the group id changes <shrug/>. Maybe the new ftp account name has a prefix? The prefix would serve as a trigger in your function hook logic, indicating this new account needs to have the group altered, and then based on the prefix name you'd know what group id to set.

    I'm not certain about all of that, but it should give you some ground work to start checking it out ;)

    -- CAVEAT EMPTOR: I have not tested this and am unsure of the consequences --

    Best Regards,
    -DavidN
     
  3. PhilGlau

    PhilGlau Active Member

    Joined:
    Nov 3, 2010
    Messages:
    27
    Likes Received:
    0
    Trophy Points:
    1
    Thanks for the tips.

    Do you think using the "GroupOwner" directive in ProFTPd might be a work around?

    For example, we really need to only set Group permissions on files uploaded by our clients.

    /public_html/clientarea/ftp/CLIENT1
    /public_html/clientarea/ftp/CLIENT2
    etc...

    I tried setting the proftpd directive in the virtual container area with the following, but it didn't seem to work for me. (I know very little about proftpd directives, so I suspect I'm doing something wrong)

    <Directory /public_html/clientarea/ftp/>
    GroupOwner SpecialGroupName​
    </Directory>

    ???

    On an Ensim box, which we're transitioning from, I had to also work around this same problem. What ended up working the best was setting a trigger and cronjob to accomplish what you refer to.

    In my case, when we added a ftp account on our front end site, it would set a mySQL database table with the relevant info that needed to be modified.

    A cronjob running as root every 3 minutes would then check the database and see if something had been added and then modify the equivalent of the /etc/proftpd/$cpanel_user file.

    I'll probably do the same thing this time now that I know it can't (yet??) be set via an API call unless I can get the proftpd directive to work.
     
  4. PhilGlau

    PhilGlau Active Member

    Joined:
    Nov 3, 2010
    Messages:
    27
    Likes Received:
    0
    Trophy Points:
    1
    Running 'ftpupdate $cpanel_user' seems to reset the GID back to it's default???

    I modify the /etc/proftpd/$cpanel_user file as follows, setting the group ID to 99:

    user_login:$1$LY_JpassHashjf3FryfGK0:508:99:product:/home/product/public_html/clientarea/ftp/USER_HOME:/bin/ftpsh

    Seems to work. But!! after I run ftpupdate $cpane_user and then look at the file again, it's reverted back to 504, which is the default group for this particular cpanel:

    user_login:$1$LY_JpassHashjf3FryfGK0:508:504:product:/home/product/public_html/clientarea/ftp/USER_HOME:/bin/ftpsh

    Even worse, when I use the API to add another user, it resets all the accounts back to group 504 ??
     
  5. PhilGlau

    PhilGlau Active Member

    Joined:
    Nov 3, 2010
    Messages:
    27
    Likes Received:
    0
    Trophy Points:
    1
    There's definitely something going on in the perl ftpupdate script that seems to be pulling the default setting for a cpanel and then wiping out any manual changes to the /etc/proftpd/$cpanel_user file.

    My Perl is a little rusty, but at one point it executes the following:

    my @ENT = Cpanel::PwCache::getpwnam($updateuser);

    Which I suspect are the defaults for the particular cpanel user. The values stored in the ENT array are later used in the processuser() function to 'rebuild' the passwd.vhosts & $cpanel_user file.

    ENT[3] is the GID.

    Code:
        foreach my $line (@PASSFILE) {
            next if ( $line =~ m/^ftp:/ || $line =~ m/^anonymous:/ || $line =~ m/^\Q$system_user\E:/ || $line =~ m/^\Q$system_user\E_logs:/ );
            chomp $line;
            my @PLINE = split( /:/, $line );
            next if ( $#PLINE < 6 || !$PLINE[0] );
            if ( $entry->[1] eq '*' ) { $PLINE[1] = '*'; }
            $PLINE[2] = $entry->[2];
       [COLOR="DarkRed"][B]     $PLINE[3] = $entry->[3];[/B][/COLOR]
            print FTPASS join( ':', @PLINE ) . "\n";
            $vhosts->{ $PLINE[0] . '@' . $domain } = join( ':', $PLINE[0] . '@' . $domain, $PLINE[1], $PLINE[2], $PLINE[3], $PLINE[4], $PLINE$
            $vhosts->{ $PLINE[0] . '+' . $domain } = join( ':', $PLINE[0] . '+' . $domain, $PLINE[1], $PLINE[2], $PLINE[3], $PLINE[4], $PLINE$
        }
    I've commented out the code in bold RED above to get around this and it seems to work. Now when ftpupdate runs it preserves the hand modified values. This allow the API to add new users and my cron job to manually modify the /etc/proftpd/$cpanel_user file to change the GID.

    Any thoughts as to if I'm breaking something important?
     
  6. cPanelDavidN

    cPanelDavidN Integration Developer
    Staff Member

    Joined:
    Dec 17, 2009
    Messages:
    571
    Likes Received:
    1
    Trophy Points:
    18
    Location:
    Houston, TX
    cPanel Access Level:
    Root Administrator
    Looking at the code more closely, it does in fact re-assert values in /etc/proftpd/$cpanel_user. I only suggested running updateftp because I thought it's sole purpose was updating passwd.vhosts and I wanted to cut down on the amount of custom code you'd have to write/modify; I was wrong, sorry. So, you're correct an all noted points.

    I too am unfamiliar with the directives for ProFTPd, so I really could speak to how best to handle it in that method.

    I'd caution against modifying updateftp since it will likely get synced back to the default script during updates (may not initially, but eventually). If you wanted to do it that way, though, you could setup a postupcp script hook that would replace/alter our default with your changes after each update. This would ensure your version is always the right one in place. That said, I don't know of any mechanisms that would directly suffer from modifying that script in that fashion. The only caveat is the obvious one, that applies more generally to the whole topic, and that is security of user data (both the shared data and access to non-public data). For now, I think it's safe to assume that you know what you're doing since you've had a similar setup in the past, so we don't need to go into detail about this (unless you have something specific you wish to discuss/investigate). ;)

    Since we know, from your tests, that simply modifying the $cpanel_user file works I'd consider just altering that file programmaticaly (in a manor similar to the one I described earlier). However, instead of a function hook, which runs as a separate process, use a CustomEventHandler and don't run updateftp (instead update the passwd.vhosts manually and maybe remove the passwd.vhosts.cache).

    With a CustomEventHandler, you have all the same fine grain control you need with a few benefits, namely it runs 'inline' with the API process. A CustomEventHandler handler runs twice for each API call: once before the API call is performed and once after. If you hook into the post event cycle, then you can just modify the $cpanel_user file to the desired state. Essentially, your addftp call would do all the things that normally occur (cPanel system is happy) then the CustomEventHandler would adjust the ftp auth file (and your scenario is honored) afterwards.

    I created an ftp account with our API Tracer CustomEventHandler (in Dev Downloads) to grok the info that will be available in the post cycle of the handler:
    Code:
    --------------------
    /usr/local/cpanel/bin/ftpadmin : Syncing Ftp Databases....
    ftp:addftp
    $apiv = 2
    $type = post
    -----
    $cfgref
    
    $VAR1 = {
              'quota' => 0,
              'cache_fix' => '1290178131533',
              'user' => 'showme',
              'pass' => 'S3cr3t!',
              'homedir' => 'public_html/showme'
            };
    
    -----
    
    With that, we know only that 'user' or ftp account name is available, which should be enough to do what we need. Here's the beginning of a CustomEventHandler for doing stuff on FTP::addftp
    Code:
    package Cpanel::CustomEventHandler;
    
    # THIS IS SAMPLE CODE AND NOT INTENDED FOR PRODUCTION USE!!!       
    # Sample of how one might go about modifying ftp user groups dynamically
    #  based on certain criteria and ACL in a way that not all ftp users are 
    # affected only those with are explicitly determine to have 'sharing' access
    
    use strict;
    use Cpanel::Logger ();
    
    # apiv = apiversion
    # type = pre,post
    # module = Cpanel::<modname>
    # event = the event ie addpop
    # cfg ref is a hash of the conf variables passed to the event. If its a legacy event, the hash keys are numbered, newer events have names.
    # dataref = the data returned from the event (post events only)
    
    sub event {
        my ( $apiv, $type, $module, $event, $cfgref, $dataref ) = @_;
        return 1 if $module ne "ftp" || $event ne "addftp";    # Filter out non-ftp:addftp requests
    
        if ( $module eq 'ftp' && $event eq 'addpop' && $type eq 'post' && ref $apiv == 2 && defined $cfref->{'user'})
        {    # determines that the event is the correct & there's info we can use
                                                                                            
            my $ftp_user = $cfref->{'user'};
            # grep out domain info from /etc/proftpd/passwd.vhosts as necessary here
            # might need some fuzzy logic also, like look as mtime of $cpanel_user file to verify that we've got the right domain
    		
            # enforce your ACL check here with user/domain info
    		
            # do stuff here with /etc/proftpd/$cpanel_user and passwd.vhosts
    
        }
        return 1; # in every other case, allow the event to proceed
    }
    1;
    
    Regards,
    -DavidN
     
  7. PhilGlau

    PhilGlau Active Member

    Joined:
    Nov 3, 2010
    Messages:
    27
    Likes Received:
    0
    Trophy Points:
    1
    This appears to be a problem. Every time I modify the script, cpanel reverts it back at 11 PM:
    Code:
    Broadcast message from root (Fri Nov 19 21:06:29 2010):
    
    cPanel Layer 2 Update Commencing
    
    Broadcast message from root (Fri Nov 19 21:07:00 2010):
    
    cPanel Layer 2 Install Complete
    
    While I'm interested in implementing your CustomEventHandler, I'd also like to either stop or 'modify' the original file that cPanel is restoring from. I'm assuming it must be doing some sort of hash comparison and replacing any modified files with the original source. It it from a local source or remote?

    The CustomEventHandler will probably take quite a bit of work (more than just commenting out 1 line...) as it will need to do both pre and post processing. It appears that making an API call to add an FTP account at some point runs the ftpudate script as part of it's call.

    When I make and FTP:add call without the ftpudate script 'commented' out on the appropriate line, it adds the account and then resets all the GIDs. With it commented out appropriately, the same call doesn't reset the GIDs.

    Thus is seems like I'm going to have to do some pre process to 'preserve' the original /etc/proftpd/$cpanel_user file, then allow the API call to run, then also do a post-process to restore the 'preserved' file and add the changes from the ftp API add call. Seems like a lot of 'working around'

    This is why I'm more excited about just commenting out the 1 line than building a pretty extensive script to override the default behavior... :D

    So I guess what I'm asking is "Where can I find the default script that cpanel is using to reset the file every night at 11 PM so I can also comment out the one line of code that is affecting me..." All the normal caveats accepted such as "I understand I might break something if I do so..." and "upgrading cPanel from our current version will probably 'break' this fix", etc. (We do not host any third party or external sites on our box, just our own corporate domains, so I don't have to worry about resellers or third party users of cpanel/WHM.)
     
  8. PhilGlau

    PhilGlau Active Member

    Joined:
    Nov 3, 2010
    Messages:
    27
    Likes Received:
    0
    Trophy Points:
    1
    Think I found my answer in the logs. It appears that the update is pulled from a remote server, which will definitely foil my fiendish plan to just use a simple comment... doh...

    As a self-serving aside, is there really a good reason that the ftpupdate script is blasting over changes to the ftp config files? Perhaps this can be reviewed by cPanels developer during the next round of software updates.
     
  9. cPanelDavidN

    cPanelDavidN Integration Developer
    Staff Member

    Joined:
    Dec 17, 2009
    Messages:
    571
    Likes Received:
    1
    Trophy Points:
    18
    Location:
    Houston, TX
    cPanel Access Level:
    Root Administrator
    I believe the update you're refering to is /scripts/upcp. This is main update script for cPanel. Depending on your update settings, this script will update various files on your system. You could make a postupcp script hook that always over-writes ftpupdate to your specification.

    The postupcp hook can be as simple `cp /root/myftpupdate /scripts/ftpupdate` or it could be more complex. Maybe it could apply a patch file (so as to try and honor any other incidental changes that come with the synced version of the script) and send an email if the synced file has a different checksum. This way, your changes should apply cleanly and you're notified anytime cPanel alters the contents of the file (so that you can manually inspect it; a sanity check).

    -DavidN
     
  10. PhilGlau

    PhilGlau Active Member

    Joined:
    Nov 3, 2010
    Messages:
    27
    Likes Received:
    0
    Trophy Points:
    1
    Add ftp user to group

    Okay, so I use the API to add a ftp user.

    What I need now is for that user to be a member of a particular group.

    in /etc/passwd I see the domain administrator user, lets call him 'admin_user'
    in /etc/group I can add the 'admin_user' to a new group and everything works. Let call that 'my_custom_group'

    I add a secondary user to the same domain and find him in /etc/proftpd/mysite_conf, lets call him 'site_user'

    Now, if I try to add 'site_user' to 'my_custom_group' in /etc/group, it does not seem to work. If I log in via ftp as 'site_user' and then attempt to download a file with the correct permission for 'my_custom_group' I get a permissions error.

    As mentioned above, if instead I log in as 'admin_user' who is also a member of 'my_custom_group', I can access the files as expected ??

    The cPanel box has Proftpd running.

    So the question is "How do I add a 'site_level' FTP user to a Group file that will allow work as expected?"
     
Loading...

Share This Page