/* * * uncdownload.c * * * * Utility for downloading files from SMB shares using libsmbclient * * * * Copyright(C) 2006 Sophos Plc, Oxford, England. * * * * This program is free software; you can redistribute it and/or modify it under the terms of the * * GNU General Public License Version 2 as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License along with this program; if not, * * write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * */
#include <sys/types.h> #include <sys/time.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <strings.h>
#include <libsmbclient.h>
/* * * * */ static const char *def_workgroup = "WORKGROUP";
/* * * Global variables holding parsed command line options * */ static char *opt_workgroup; static char *opt_username; static char *opt_password; static int opt_stdinpwd; static int opt_stdoutdata = 1; static char *opt_outfile; static int opt_outfd; static char *opt_downloadurl;
/* * * Parse command line options * */ static int parseopts(int argc, char *argv[]) { int arg; char *nonoption = NULL; char option = 0; int param = 0;
for ( arg = 1; arg < argc; arg++ ) { if ( param ) { /* Previous arg was an option */ param = 0; switch ( option ) { case 'w': opt_workgroup = argv[arg]; break; case 'u': opt_username = argv[arg]; break; case 'p': opt_password = argv[arg]; if ( !strcmp(opt_password, "-") ) opt_stdinpwd = 1; break; case 'o': opt_outfile = argv[arg]; opt_stdoutdata = 0; break; case 'd': opt_outfd = atoi(argv[arg]); opt_stdoutdata = 0; break; } } else { /* Look for an option */ if ( argv[arg][0] == '-' ) { option = argv[arg][1]; switch ( option ) { case 'w': case 'u': case 'p': case 'o': case 'd': param = 1; break; default: fprintf(stderr, "Unknown option: %c\n", option); } /* If not an option, store as a non-option argument */ } else { if ( nonoption ) fprintf(stderr, "Only first non-option argument considered as download URL!"); else nonoption = argv[arg]; } } }
if ( param ) { fprintf(stderr, "No argument for -%c!\n", option); return -1; }
if ( !nonoption ) { fprintf(stderr, "No UNC path given!\n"); return -1; }
opt_downloadurl = nonoption;
return 0; }
/* * * libsmbclient callback function * */ static void get_auth_data_fn(const char *pServer, const char *pShare, char *pWorkgroup, int maxLenWorkgroup, char *pUsername, int maxLenUsername, char *pPassword, int maxLenPassword ) { (void)pServer; (void)pShare;
if ( opt_workgroup && opt_workgroup[0] != '\0' ) strncpy(pWorkgroup, opt_workgroup, maxLenWorkgroup - 1);
if ( opt_username && opt_username[0] != '\0' ) strncpy(pUsername, opt_username, maxLenUsername - 1);
if ( opt_password && opt_password[0] != '\0' ) strncpy(pPassword, opt_password, maxLenPassword - 1); }
/* * * Convert backslashes to slashes * */ static char *bstos(char *str) { char *p = str;
while ( *p ) { if ( *p == '\\' ) *p = '/'; p++; }
return str; }
/* * * Creates a nice file URL which libsmbclient understands * */ static char *mkurl(char *uncpath) { unsigned int len = strlen(uncpath) + 1; char *url; int prepend = 0;
if ( strncasecmp(uncpath, "smb:", 4) ) { len += 4; prepend = 1; }
if ( !(url = malloc(len)) ) return NULL; else *url = 0; /* So that strcat below is safe if not prepending */
if ( prepend ) strcpy(url, "smb:");
strcat(url, uncpath);
return bstos(url); }
/* * * Null-terminate string on first newline * */ static char *ntonl(char *str) { char *p = str;
while ( *p ) { if ( *p == '\n' ) { *p = 0; break; } p++; }
return str; }
/* * @return codes: * 0 success * 1 failed to parse arguments * 2 failed mkurl * 3 failed to read password * 4 failed to open output file * 5 failed to open remote file (not permission or existence) * 6 failed reading or writing * 7 bad authentication * 8 no such file * 9 invalid argument from smbc_open - may mean missing directory component * */ int main(int argc, char * argv[]) { char *smbpath; char pwdbuf[128]; int outfd; int smbdebug = 0; int smbfd; int ret; char buffer[2048];
if ( parseopts(argc, argv) ) { fprintf(stderr, "Usage:\n\ \t%s [OPTIONS] DOWNLOAD-URL\n\ Options:\n\ \t-w\tworkgroup (default: %s)\n\ \t-u\tusername\n\ \t-p\tpassword (if - then read from stdin)\n\ \t-o\toutput (if omitted then written to stdout)\n\ \t-d\tdescriptor (if omitted then written to stdout, overrides output file)\n", argv[0], def_workgroup); return 1; }
if ( !(smbpath = mkurl(opt_downloadurl)) ) { fprintf(stderr, "Failed to create SMB URL!\n"); return 2; }
if ( opt_stdinpwd ) { if ( !fgets(pwdbuf, sizeof(pwdbuf), stdin) ) { fprintf(stderr, "Failed to read password from stdin!\n"); return 3; } opt_password = ntonl(pwdbuf); }
if ( opt_outfd ) { outfd = opt_outfd; } else if ( !opt_stdoutdata ) { if ( (outfd = open(opt_outfile, O_WRONLY | O_CREAT | O_TRUNC)) <= 0 ) { fprintf(stderr, "Failed to open output file! - %s\n", strerror(errno)); return 4; } } else { outfd = STDOUT_FILENO; }
smbc_init(get_auth_data_fn, smbdebug);
if ( (smbfd = smbc_open(smbpath, O_RDONLY, 0)) < 0 ) { fprintf(stderr, "Failed to open remote location! - %s(%d)\n", strerror(errno),errno); switch(errno) { case EACCES: return 7; /* Bad permissions */ case ENOENT: /* No such file or directory */ case EISDIR: /* Is a directory */ case ENODEV: /* No such share */ case ENOTDIR: /* Perhaps a directory in the path is in fact a file? */ return 8; /* Implies: No such file */ case EINVAL: /* May mean a directory in the path doesn't exist */ return 9; /* Implies: No such file */ } /* default */ return 5; }
/* Main loop */ do { ret = smbc_read(smbfd, buffer, sizeof(buffer)); if ( ret > 0 ) { ret = write(outfd, buffer, ret); if ( ret < 0 ) break; } } while ( ret > 0 );
if ( ret < 0 ) { fprintf(stderr, "Error reading or writting! - %s\n", strerror(errno)); return 6; }
smbc_close(smbfd); free(smbpath); /* Allocated with mkurl */
return 0; }
|