void FAST_FUNC print_login_prompt(void) { char *hostname = safe_gethostname(); fputs(hostname, stdout); fputs(LOGIN, stdout); fflush_all(); free(hostname); }
/* Open a unique file in the 'tmp' sub-directory of dir. * Returns the file descriptor on success, or -1 on failure. * On success, file paths for the message in the 'tmp' and 'new' * directories are returned via tmppath and newpath, * and the path of the 'new' directory itself in newdir. */ static int maildir_open_tmp_file (void *ctx, const char *dir, char **tmppath, char **newpath, char **newdir) { pid_t pid; char hostname[256]; struct timeval tv; char *filename; int fd = -1; /* We follow the Dovecot file name generation algorithm. */ pid = getpid (); safe_gethostname (hostname, sizeof (hostname)); do { gettimeofday (&tv, NULL); filename = talloc_asprintf (ctx, "%ld.M%ldP%d.%s", tv.tv_sec, tv.tv_usec, pid, hostname); if (! filename) { fprintf (stderr, "Out of memory\n"); return -1; } *tmppath = talloc_asprintf (ctx, "%s/tmp/%s", dir, filename); if (! *tmppath) { fprintf (stderr, "Out of memory\n"); return -1; } fd = open (*tmppath, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600); } while (fd == -1 && errno == EEXIST); if (fd == -1) { fprintf (stderr, "Error: opening %s: %s\n", *tmppath, strerror (errno)); return -1; } *newdir = talloc_asprintf (ctx, "%s/new", dir); *newpath = talloc_asprintf (ctx, "%s/new/%s", dir, filename); if (! *newdir || ! *newpath) { fprintf (stderr, "Out of memory\n"); close (fd); unlink (*tmppath); return -1; } talloc_free (filename); return fd; }
/* * Generate a temporary file basename, no path, do not create an * actual file. Return the basename, or NULL on errors. */ static char * tempfilename (const void *ctx) { char *filename; char hostname[256]; struct timeval tv; pid_t pid; /* We follow the Dovecot file name generation algorithm. */ pid = getpid (); safe_gethostname (hostname, sizeof (hostname)); gettimeofday (&tv, NULL); filename = talloc_asprintf (ctx, "%ld.M%ldP%d.%s", (long) tv.tv_sec, (long) tv.tv_usec, pid, hostname); if (! filename) fprintf (stderr, "Error: %s\n", strerror (ENOMEM)); return filename; }
void FAST_FUNC print_login_prompt(void) { char buf[MAXHOSTNAMELEN+1]; /* Login Prompt by BrainSlayer */ FILE *fp = fopen ("/tmp/loginprompt", "rb"); if (fp) { int d; while ((d=getc(fp))!=EOF) { putc (d, stdout); } fclose (fp); } fprintf(stdout,"\n"); char *hostname = safe_gethostname(); fputs(hostname, stdout); fputs(LOGIN, stdout); fflush_all(); free(hostname); }
int hostname_main(int argc UNUSED_PARAM, char **argv) { enum { OPT_d = 0x1, OPT_f = 0x2, OPT_i = 0x4, OPT_s = 0x8, OPT_F = 0x10, OPT_dfi = 0x7, }; unsigned opts; char *buf; char *hostname_str; #if ENABLE_LONG_OPTS applet_long_options = "domain\0" No_argument "d" "fqdn\0" No_argument "f" //Enable if seen in active use in some distro: // "long\0" No_argument "f" // "ip-address\0" No_argument "i" // "short\0" No_argument "s" // "verbose\0" No_argument "v" "file\0" No_argument "F" ; #endif /* dnsdomainname from net-tools 1.60, hostname 1.100 (2001-04-14), * supports hostname's options too (not just -v as manpage says) */ opts = getopt32(argv, "dfisF:v", &hostname_str); argv += optind; buf = safe_gethostname(); if (applet_name[0] == 'd') /* dnsdomainname? */ opts = OPT_d; if (opts & OPT_dfi) { /* Cases when we need full hostname (or its part) */ struct hostent *hp; char *p; hp = xgethostbyname(buf); p = strchrnul(hp->h_name, '.'); if (opts & OPT_f) { puts(hp->h_name); } else if (opts & OPT_s) { *p = '\0'; puts(hp->h_name); } else if (opts & OPT_d) { if (*p) puts(p + 1); } else /*if (opts & OPT_i)*/ { if (hp->h_length == sizeof(struct in_addr)) { struct in_addr **h_addr_list = (struct in_addr **)hp->h_addr_list; while (*h_addr_list) { printf(h_addr_list[1] ? "%s " : "%s", inet_ntoa(**h_addr_list)); h_addr_list++; } bb_putchar('\n'); } } } else if (opts & OPT_s) { strchrnul(buf, '.')[0] = '\0'; puts(buf); } else if (opts & OPT_F) { /* Set the hostname */ do_sethostname(hostname_str, 1); } else if (argv[0]) { /* Set the hostname */ do_sethostname(argv[0], 0); } else { /* Just print the current hostname */ puts(buf); } if (ENABLE_FEATURE_CLEAN_UP) free(buf); return EXIT_SUCCESS; }
int sendmail_main(int argc UNUSED_PARAM, char **argv) { char *opt_connect = opt_connect; char *opt_from = NULL; char *s; llist_t *list = NULL; char *host = sane_address(safe_gethostname()); unsigned nheaders = 0; int code; enum { HDR_OTHER = 0, HDR_TOCC, HDR_BCC, } last_hdr = 0; int check_hdr; int has_to = 0; enum { //--- standard options OPT_t = 1 << 0, // read message for recipients, append them to those on cmdline OPT_f = 1 << 1, // sender address OPT_o = 1 << 2, // various options. -oi IMPLIED! others are IGNORED! OPT_i = 1 << 3, // IMPLIED! //--- BB specific options OPT_w = 1 << 4, // network timeout OPT_H = 1 << 5, // use external connection helper OPT_S = 1 << 6, // specify connection string OPT_a = 1 << 7, // authentication tokens OPT_v = 1 << 8, // verbosity }; // init global variables INIT_G(); // save initial stdin since body is piped! xdup2(STDIN_FILENO, 3); G.fp0 = xfdopen_for_read(3); // parse options // -v is a counter, -H and -S are mutually exclusive, -a is a list opt_complementary = "vv:w+:H--S:S--H:a::"; // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility, // it is still under development. opts = getopt32(argv, "tf:o:iw:H:S:a::v", &opt_from, NULL, &timeout, &opt_connect, &opt_connect, &list, &verbose); //argc -= optind; argv += optind; // process -a[upm]<token> options if ((opts & OPT_a) && !list) bb_show_usage(); while (list) { char *a = (char *) llist_pop(&list); if ('u' == a[0]) G.user = xstrdup(a+1); if ('p' == a[0]) G.pass = xstrdup(a+1); // N.B. we support only AUTH LOGIN so far //if ('m' == a[0]) // G.method = xstrdup(a+1); } // N.B. list == NULL here //bb_info_msg("OPT[%x] AU[%s], AP[%s], AM[%s], ARGV[%s]", opts, au, ap, am, *argv); // connect to server // connection helper ordered? -> if (opts & OPT_H) { const char *args[] = { "sh", "-c", opt_connect, NULL }; // plug it in launch_helper(args); // Now: // our stdout will go to helper's stdin, // helper's stdout will be available on our stdin. // Wait for initial server message. // If helper (such as openssl) invokes STARTTLS, the initial 220 // is swallowed by helper (and not repeated after TLS is initiated). // We will send NOOP cmd to server and check the response. // We should get 220+250 on plain connection, 250 on STARTTLSed session. // // The problem here is some servers delay initial 220 message, // and consider client to be a spammer if it starts sending cmds // before 220 reached it. The code below is unsafe in this regard: // in non-STARTTLSed case, we potentially send NOOP before 220 // is sent by server. // Ideas? (--delay SECS opt? --assume-starttls-helper opt?) code = smtp_check("NOOP", -1); if (code == 220) // we got 220 - this is not STARTTLSed connection, // eat 250 response to our NOOP smtp_check(NULL, 250); else if (code != 250) bb_error_msg_and_die("SMTP init failed"); } else { // vanilla connection int fd; // host[:port] not explicitly specified? -> use $SMTPHOST // no $SMTPHOST? -> use localhost if (!(opts & OPT_S)) { opt_connect = getenv("SMTPHOST"); if (!opt_connect) opt_connect = (char *)"127.0.0.1"; } // do connect fd = create_and_connect_stream_or_die(opt_connect, 25); // and make ourselves a simple IO filter xmove_fd(fd, STDIN_FILENO); xdup2(STDIN_FILENO, STDOUT_FILENO); // Wait for initial server 220 message smtp_check(NULL, 220); } // we should start with modern EHLO if (250 != smtp_checkp("EHLO %s", host, -1)) smtp_checkp("HELO %s", host, 250); // perform authentication if (opts & OPT_a) { smtp_check("AUTH LOGIN", 334); // we must read credentials unless they are given via -a[up] options if (!G.user || !G.pass) get_cred_or_die(4); encode_base64(NULL, G.user, NULL); smtp_check("", 334); encode_base64(NULL, G.pass, NULL); smtp_check("", 235); } // set sender // N.B. we have here a very loosely defined algorythm // since sendmail historically offers no means to specify secrets on cmdline. // 1) server can require no authentication -> // we must just provide a (possibly fake) reply address. // 2) server can require AUTH -> // we must provide valid username and password along with a (possibly fake) reply address. // For the sake of security username and password are to be read either from console or from a secured file. // Since reading from console may defeat usability, the solution is either to read from a predefined // file descriptor (e.g. 4), or again from a secured file. // got no sender address? use auth name, then UID username as a last resort if (!opt_from) { opt_from = xasprintf("%s@%s", G.user ? G.user : xuid2uname(getuid()), xgethostbyname(host)->h_name); } free(host); smtp_checkp("MAIL FROM:<%s>", opt_from, 250); // process message // read recipients from message and add them to those given on cmdline. // this means we scan stdin for To:, Cc:, Bcc: lines until an empty line // and then use the rest of stdin as message body code = 0; // set "analyze headers" mode while ((s = xmalloc_fgetline(G.fp0)) != NULL) { dump: // put message lines doubling leading dots if (code) { // escape leading dots // N.B. this feature is implied even if no -i (-oi) switch given // N.B. we need to escape the leading dot regardless of // whether it is single or not character on the line if ('.' == s[0] /*&& '\0' == s[1] */) bb_putchar('.'); // dump read line send_r_n(s); free(s); continue; } // analyze headers // To: or Cc: headers add recipients check_hdr = (0 == strncasecmp("To:", s, 3)); has_to |= check_hdr; if (opts & OPT_t) { if (check_hdr || 0 == strncasecmp("Bcc:" + 1, s, 3)) { rcptto_list(s+3); last_hdr = HDR_TOCC; goto addheader; } // Bcc: header adds blind copy (hidden) recipient if (0 == strncasecmp("Bcc:", s, 4)) { rcptto_list(s+4); free(s); last_hdr = HDR_BCC; continue; // N.B. Bcc: vanishes from headers! } } check_hdr = (list && isspace(s[0])); if (strchr(s, ':') || check_hdr) { // other headers go verbatim // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. // Continuation is denoted by prefixing additional lines with whitespace(s). // Thanks (stefan.seyfried at googlemail.com) for pointing this out. if (check_hdr && last_hdr != HDR_OTHER) { rcptto_list(s+1); if (last_hdr == HDR_BCC) continue; // N.B. Bcc: vanishes from headers! } else { last_hdr = HDR_OTHER; } addheader: // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) goto bail; llist_add_to_end(&list, s); } else { // a line without ":" (an empty line too, by definition) doesn't look like a valid header // so stop "analyze headers" mode reenter: // put recipients specified on cmdline check_hdr = 1; while (*argv) { char *t = sane_address(*argv); rcptto(t); //if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) // goto bail; if (!has_to) { const char *hdr; if (check_hdr && argv[1]) hdr = "To: %s,"; else if (check_hdr) hdr = "To: %s"; else if (argv[1]) hdr = "To: %s," + 3; else hdr = "To: %s" + 3; llist_add_to_end(&list, xasprintf(hdr, t)); check_hdr = 0; } argv++; } // enter "put message" mode // N.B. DATA fails iff no recipients were accepted (or even provided) // in this case just bail out gracefully if (354 != smtp_check("DATA", -1)) goto bail; // dump the headers while (list) { send_r_n((char *) llist_pop(&list)); } // stop analyzing headers code++; // N.B. !s means: we read nothing, and nothing to be read in the future. // just dump empty line and break the loop if (!s) { send_r_n(""); break; } // go dump message body // N.B. "s" already contains the first non-header line, so pretend we read it from input goto dump; } } // odd case: we didn't stop "analyze headers" mode -> message body is empty. Reenter the loop // N.B. after reenter code will be > 0 if (!code) goto reenter; // finalize the message smtp_check(".", 250); bail: // ... and say goodbye smtp_check("QUIT", 221); // cleanup if (ENABLE_FEATURE_CLEAN_UP) fclose(G.fp0); return EXIT_SUCCESS; }
static int parse(const char *boundary, char **argv) { char *line, *s, *p; const char *type; int boundary_len = strlen(boundary); const char *delims = " ;\"\t\r\n"; const char *uniq; int ntokens; const char *tokens[32]; // 32 is enough // prepare unique string pattern uniq = xasprintf("%%llu.%u.%s", (unsigned)getpid(), safe_gethostname()); //bb_info_msg("PARSE[%s]", terminator); while ((line = xmalloc_fgets_str(stdin, "\r\n\r\n")) != NULL) { // seek to start of MIME section // N.B. to avoid false positives let us seek to the _last_ occurance p = NULL; s = line; while ((s=strcasestr(s, "Content-Type:")) != NULL) p = s++; if (!p) goto next; //bb_info_msg("L[%s]", p); // split to tokens // TODO: strip of comments which are of form: (comment-text) ntokens = 0; tokens[ntokens] = NULL; for (s = strtok(p, delims); s; s = strtok(NULL, delims)) { tokens[ntokens] = s; if (ntokens < ARRAY_SIZE(tokens) - 1) ntokens++; //bb_info_msg("L[%d][%s]", ntokens, s); } tokens[ntokens] = NULL; //bb_info_msg("N[%d]", ntokens); // analyse tokens type = find_token(tokens, "Content-Type:", "text/plain"); //bb_info_msg("T[%s]", type); if (0 == strncasecmp(type, "multipart/", 10)) { if (0 == strcasecmp(type+10, "mixed")) { parse(xfind_token(tokens, "boundary="), argv); } else bb_error_msg_and_die("no support of content type '%s'", type); } else { pid_t pid = pid; int rc; FILE *fp; // fetch charset const char *charset = find_token(tokens, "charset=", CONFIG_FEATURE_MIME_CHARSET); // fetch encoding const char *encoding = find_token(tokens, "Content-Transfer-Encoding:", "7bit"); // compose target filename char *filename = (char *)find_token(tokens, "filename=", NULL); if (!filename) filename = xasprintf(uniq, monotonic_us()); else filename = bb_get_last_path_component_strip(xstrdup(filename)); // start external helper, if any if (opts & OPT_X) { int fd[2]; xpipe(fd); pid = vfork(); if (0 == pid) { // child reads from fd[0] xdup2(fd[0], STDIN_FILENO); close(fd[0]); close(fd[1]); xsetenv("CONTENT_TYPE", type); xsetenv("CHARSET", charset); xsetenv("ENCODING", encoding); xsetenv("FILENAME", filename); BB_EXECVP(*argv, argv); _exit(EXIT_FAILURE); } // parent dumps to fd[1] close(fd[0]); fp = fdopen(fd[1], "w"); signal(SIGPIPE, SIG_IGN); // ignore EPIPE // or create a file for dump } else { char *fname = xasprintf("%s%s", *argv, filename); fp = xfopen_for_write(fname); free(fname); } // housekeeping free(filename); // dump to fp if (0 == strcasecmp(encoding, "base64")) { decode_base64(stdin, fp); } else if (0 != strcasecmp(encoding, "7bit") && 0 != strcasecmp(encoding, "8bit")) { // quoted-printable, binary, user-defined are unsupported so far bb_error_msg_and_die("no support of encoding '%s'", encoding); } else { // N.B. we have written redundant \n. so truncate the file // The following weird 2-tacts reading technique is due to // we have to not write extra \n at the end of the file // In case of -x option we could truncate the resulting file as // fseek(fp, -1, SEEK_END); // if (ftruncate(fileno(fp), ftell(fp))) // bb_perror_msg("ftruncate"); // But in case of -X we have to be much more careful. There is // no means to truncate what we already have sent to the helper. p = xmalloc_fgets_str(stdin, "\r\n"); while (p) { if ((s = xmalloc_fgets_str(stdin, "\r\n")) == NULL) break; if ('-' == s[0] && '-' == s[1] && 0 == strncmp(s+2, boundary, boundary_len)) break; fputs(p, fp); p = s; } /* while ((s = xmalloc_fgetline_str(stdin, "\r\n")) != NULL) { if ('-' == s[0] && '-' == s[1] && 0 == strncmp(s+2, boundary, boundary_len)) break; fprintf(fp, "%s\n", s); } // N.B. we have written redundant \n. so truncate the file fseek(fp, -1, SEEK_END); if (ftruncate(fileno(fp), ftell(fp))) bb_perror_msg("ftruncate"); */ } fclose(fp); // finalize helper if (opts & OPT_X) { signal(SIGPIPE, SIG_DFL); // exit if helper exited >0 rc = wait4pid(pid); if (rc) return rc+20; } // check multipart finalized if (s && '-' == s[2+boundary_len] && '-' == s[2+boundary_len+1]) { free(line); break; } } next: free(line); } //bb_info_msg("ENDPARSE[%s]", boundary); return EXIT_SUCCESS; }
int popmaildir_main(int argc UNUSED_PARAM, char **argv) { char *buf; unsigned nmsg; char *hostname; pid_t pid; const char *retr; #if ENABLE_FEATURE_POPMAILDIR_DELIVERY const char *delivery; #endif unsigned opt_nlines = 0; enum { OPT_b = 1 << 0, // -b binary mode. Ignored OPT_d = 1 << 1, // -d,-dd,-ddd debug. Ignored OPT_m = 1 << 2, // -m show ugsed memory. Ignored OPT_V = 1 << 3, // -V version. Ignored OPT_c = 1 << 4, // -c use tcpclient. Ignored OPT_a = 1 << 5, // -a use APOP protocol OPT_s = 1 << 6, // -s skip authorization OPT_T = 1 << 7, // -T get messages with TOP instead with RETR OPT_k = 1 << 8, // -k keep retrieved messages on the server OPT_t = 1 << 9, // -t90 set timeout to 90 sec OPT_R = 1 << 10, // -R20000 remove old messages on the server >= 20000 bytes (requires -k). Ignored OPT_Z = 1 << 11, // -Z11-23 remove messages from 11 to 23 (dangerous). Ignored OPT_L = 1 << 12, // -L50000 not retrieve new messages >= 50000 bytes. Ignored OPT_H = 1 << 13, // -H30 type first 30 lines of a message; (-L12000 -H30). Ignored OPT_M = 1 << 14, // -M\"program arg1 arg2 ...\"; deliver by program. Treated like -F OPT_F = 1 << 15, // -F\"program arg1 arg2 ...\"; filter by program. Treated like -M }; // init global variables INIT_G(); // parse options opt_complementary = "-1:dd:t+:R+:L+:H+"; opts = getopt32(argv, "bdmVcasTkt:" "R:Z:L:H:" IF_FEATURE_POPMAILDIR_DELIVERY("M:F:"), &timeout, NULL, NULL, NULL, &opt_nlines IF_FEATURE_POPMAILDIR_DELIVERY(, &delivery, &delivery) // we treat -M and -F the same ); //argc -= optind; argv += optind; // get auth info if (!(opts & OPT_s)) get_cred_or_die(STDIN_FILENO); // goto maildir xchdir(*argv++); // launch connect helper, if any if (*argv) launch_helper((const char **)argv); // get server greeting pop3_checkr(NULL, NULL, &buf); // authenticate (if no -s given) if (!(opts & OPT_s)) { // server supports APOP and we want it? if ('<' == buf[0] && (opts & OPT_a)) { union { // save a bit of stack md5_ctx_t ctx; char hex[16 * 2 + 1]; } md5; uint32_t res[16 / 4]; char *s = strchr(buf, '>'); if (s) s[1] = '\0'; // get md5 sum of "<stamp>password" string md5_begin(&md5.ctx); md5_hash(&md5.ctx, buf, strlen(buf)); md5_hash(&md5.ctx, G.pass, strlen(G.pass)); md5_end(&md5.ctx, res); *bin2hex(md5.hex, (char*)res, 16) = '\0'; // APOP s = xasprintf("%s %s", G.user, md5.hex); pop3_check("APOP %s", s); free(s); free(buf); // server ignores APOP -> use simple text authentication } else { // USER pop3_check("USER %s", G.user); // PASS pop3_check("PASS %s", G.pass); } } // get mailbox statistics pop3_checkr("STAT", NULL, &buf); // prepare message filename suffix hostname = safe_gethostname(); pid = getpid(); // get messages counter // NOTE: we don't use xatou(buf) since buf is "nmsg nbytes" // we only need nmsg and atoi is just exactly what we need // if atoi fails to convert buf into number it returns 0 // in this case the following loop simply will not be executed nmsg = atoi(buf); free(buf); // loop through messages retr = (opts & OPT_T) ? xasprintf("TOP %%u %u", opt_nlines) : "RETR %u"; for (; nmsg; nmsg--) { char *filename; char *target; char *answer; FILE *fp; #if ENABLE_FEATURE_POPMAILDIR_DELIVERY int rc; #endif // generate unique filename filename = xasprintf("tmp/%llu.%u.%s", monotonic_us(), (unsigned)pid, hostname); // retrieve message in ./tmp/ unless filter is specified pop3_check(retr, (const char *)(ptrdiff_t)nmsg); #if ENABLE_FEATURE_POPMAILDIR_DELIVERY // delivery helper ordered? -> setup pipe if (opts & (OPT_F|OPT_M)) { // helper will have $FILENAME set to filename xsetenv("FILENAME", filename); fp = popen(delivery, "w"); unsetenv("FILENAME"); if (!fp) { bb_perror_msg("delivery helper"); break; } } else #endif // create and open file filename fp = xfopen_for_write(filename); // copy stdin to fp (either filename or delivery helper) while ((answer = xmalloc_fgets_str(stdin, "\r\n")) != NULL) { char *s = answer; if ('.' == answer[0]) { if ('.' == answer[1]) s++; else if ('\r' == answer[1] && '\n' == answer[2] && '\0' == answer[3]) break; } //*strchrnul(s, '\r') = '\n'; fputs(s, fp); free(answer); } #if ENABLE_FEATURE_POPMAILDIR_DELIVERY // analyse delivery status if (opts & (OPT_F|OPT_M)) { rc = pclose(fp); if (99 == rc) // 99 means bail out break; // if (rc) // !0 means skip to the next message goto skip; // // 0 means continue } else { // close filename fclose(fp); } #endif // delete message from server if (!(opts & OPT_k)) pop3_check("DELE %u", (const char*)(ptrdiff_t)nmsg); // atomically move message to ./new/ target = xstrdup(filename); strncpy(target, "new", 3); // ... or just stop receiving on failure if (rename_or_warn(filename, target)) break; free(target); #if ENABLE_FEATURE_POPMAILDIR_DELIVERY skip: #endif free(filename); } // Bye pop3_check("QUIT", NULL); if (ENABLE_FEATURE_CLEAN_UP) { free(G.user); free(G.pass); } return EXIT_SUCCESS; }
static const char *obscure_msg(const char *old_p, const char *new_p, const struct passwd *pw) { unsigned length; unsigned size; unsigned mixed; unsigned c; unsigned i; const char *p; char *hostname; /* size */ if (!new_p || (length = strlen(new_p)) < CONFIG_PASSWORD_MINLEN) return "too short"; /* no username as-is, as sub-string, reversed, capitalized, doubled */ if (string_checker(new_p, pw->pw_name)) { return "similar to username"; } #ifndef __BIONIC__ /* no gecos as-is, as sub-string, reversed, capitalized, doubled */ if (pw->pw_gecos[0] && string_checker(new_p, pw->pw_gecos)) { return "similar to gecos"; } #endif /* hostname as-is, as sub-string, reversed, capitalized, doubled */ hostname = safe_gethostname(); i = string_checker(new_p, hostname); free(hostname); if (i) return "similar to hostname"; /* Should / Must contain a mix of: */ mixed = 0; for (i = 0; i < length; i++) { if (islower(new_p[i])) { /* a-z */ mixed |= LOWERCASE; } else if (isupper(new_p[i])) { /* A-Z */ mixed |= UPPERCASE; } else if (isdigit(new_p[i])) { /* 0-9 */ mixed |= NUMBERS; } else { /* special characters */ mixed |= SPECIAL; } /* Count i'th char */ c = 0; p = new_p; while (1) { p = strchr(p, new_p[i]); if (p == NULL) { break; } c++; p++; if (!*p) { break; } } /* More than 50% similar characters ? */ if (c*2 >= length) { return "too many similar characters"; } } size = CONFIG_PASSWORD_MINLEN + 2*CATEGORIES; for (i = 1; i <= LAST_CAT; i <<= 1) if (mixed & i) size -= 2; if (length < size) return "too weak"; if (old_p && old_p[0]) { /* check vs. old password */ if (string_checker(new_p, old_p)) { return "similar to old password"; } } return NULL; }
int lpqr_main(int argc UNUSED_PARAM, char *argv[]) { enum { OPT_P = 1 << 0, // -P queue[@host[:port]]. If no -P is given use $PRINTER, then "lp@localhost:515" OPT_U = 1 << 1, // -U username LPR_V = 1 << 2, // -V: be verbose LPR_h = 1 << 3, // -h: want banner printed LPR_C = 1 << 4, // -C class: job "class" (? supposedly printed on banner) LPR_J = 1 << 5, // -J title: the job title for the banner page LPR_m = 1 << 6, // -m: send mail back to user LPQ_SHORT_FMT = 1 << 2, // -s: short listing format LPQ_DELETE = 1 << 3, // -d: delete job(s) LPQ_FORCE = 1 << 4, // -f: force waiting job(s) to be printed }; char tempfile[sizeof("/tmp/lprXXXXXX")]; const char *job_title; const char *printer_class = ""; // printer class, max 32 char const char *queue; // name of printer queue const char *server = "localhost"; // server[:port] of printer queue char *hostname; // N.B. IMHO getenv("USER") can be way easily spoofed! const char *user = xuid2uname(getuid()); unsigned job; unsigned opts; int fd; queue = getenv("PRINTER"); if (!queue) queue = "lp"; // parse options // TODO: set opt_complementary: s,d,f are mutually exclusive opts = getopt32(argv, (/*lp*/'r' == applet_name[2]) ? "P:U:VhC:J:m" : "P:U:sdf" , &queue, &user , &printer_class, &job_title ); argv += optind; { // queue name is to the left of '@' char *s = strchr(queue, '@'); if (s) { // server name is to the right of '@' *s = '\0'; server = s + 1; } } // do connect fd = create_and_connect_stream_or_die(server, 515); // // LPQ ------------------------ // if (/*lp*/'q' == applet_name[2]) { char cmd; // force printing of every job still in queue if (opts & LPQ_FORCE) { cmd = 1; goto command; // delete job(s) } else if (opts & LPQ_DELETE) { fdprintf(fd, "\x5" "%s %s", queue, user); while (*argv) { fdprintf(fd, " %s", *argv++); } bb_putchar('\n'); // dump current jobs status // N.B. periodical polling should be achieved // via "watch -n delay lpq" // They say it's the UNIX-way :) } else { cmd = (opts & LPQ_SHORT_FMT) ? 3 : 4; command: fdprintf(fd, "%c" "%s\n", cmd, queue); bb_copyfd_eof(fd, STDOUT_FILENO); } return EXIT_SUCCESS; } // // LPR ------------------------ // if (opts & LPR_V) bb_error_msg("connected to server"); job = getpid() % 1000; hostname = safe_gethostname(); // no files given on command line? -> use stdin if (!*argv) *--argv = (char *)"-"; fdprintf(fd, "\x2" "%s\n", queue); get_response_or_say_and_die(fd, "setting queue"); // process files do { unsigned cflen; int dfd; struct stat st; char *c; char *remote_filename; char *controlfile; // if data file is stdin, we need to dump it first if (LONE_DASH(*argv)) { strcpy(tempfile, "/tmp/lprXXXXXX"); dfd = xmkstemp(tempfile); bb_copyfd_eof(STDIN_FILENO, dfd); xlseek(dfd, 0, SEEK_SET); *argv = (char*)bb_msg_standard_input; } else { dfd = xopen(*argv, O_RDONLY); } st.st_size = 0; /* paranoia: fstat may theoretically fail */ fstat(dfd, &st); /* Apparently, some servers are buggy and won't accept 0-sized jobs. * Standard lpr works around it by refusing to send such jobs: */ if (st.st_size == 0) { bb_error_msg("nothing to print"); continue; } /* "The name ... should start with ASCII "cfA", * followed by a three digit job number, followed * by the host name which has constructed the file." * We supply 'c' or 'd' as needed for control/data file. */ remote_filename = xasprintf("fA%03u%s", job, hostname); // create control file // TODO: all lines but 2 last are constants! How we can use this fact? controlfile = xasprintf( "H" "%.32s\n" "P" "%.32s\n" /* H HOST, P USER */ "C" "%.32s\n" /* C CLASS - printed on banner page (if L cmd is also given) */ "J" "%.99s\n" /* J JOBNAME */ /* "class name for banner page and job name * for banner page commands must precede L command" */ "L" "%.32s\n" /* L USER - print banner page, with given user's name */ "M" "%.32s\n" /* M WHOM_TO_MAIL */ "l" "d%.31s\n" /* l DATA_FILE_NAME ("dfAxxx") */ , hostname, user , printer_class /* can be "" */ , ((opts & LPR_J) ? job_title : *argv) , (opts & LPR_h) ? user : "" , (opts & LPR_m) ? user : "" , remote_filename ); // delete possible "\nX\n" (that is, one-char) patterns c = controlfile; while ((c = strchr(c, '\n')) != NULL) { if (c[1] && c[2] == '\n') { overlapping_strcpy(c, c+2); } else { c++; } } // send control file if (opts & LPR_V) bb_error_msg("sending control file"); /* "Acknowledgement processing must occur as usual * after the command is sent." */ cflen = (unsigned)strlen(controlfile); fdprintf(fd, "\x2" "%u c%s\n", cflen, remote_filename); get_response_or_say_and_die(fd, "sending control file"); /* "Once all of the contents have * been delivered, an octet of zero bits is sent as * an indication that the file being sent is complete. * A second level of acknowledgement processing * must occur at this point." */ full_write(fd, controlfile, cflen + 1); /* writes NUL byte too */ get_response_or_say_and_die(fd, "sending control file"); // send data file, with name "dfaXXX" if (opts & LPR_V) bb_error_msg("sending data file"); fdprintf(fd, "\x3" "%"FILESIZE_FMT"u d%s\n", st.st_size, remote_filename); get_response_or_say_and_die(fd, "sending data file"); if (bb_copyfd_size(dfd, fd, st.st_size) != st.st_size) { // We're screwed. We sent less bytes than we advertised. bb_error_msg_and_die("local file changed size?!"); } write(fd, "", 1); // send ACK get_response_or_say_and_die(fd, "sending data file"); // delete temporary file if we dumped stdin if (*argv == (char*)bb_msg_standard_input) unlink(tempfile); // cleanup close(fd); free(remote_filename); free(controlfile); // say job accepted if (opts & LPR_V) bb_error_msg("job accepted"); // next, please! job = (job + 1) % 1000; } while (*++argv); return EXIT_SUCCESS; }
bool check_hostname(file_header* header) { char saved_host[HOST_LEN], current_host[HOST_LEN]; strncpy(saved_host, header->host, strlen(header->host)); safe_gethostname(current_host, HOST_LEN); return strcmp(saved_host, current_host) == 0; }