static void cups_set_ssl_options( _cups_client_conf_t *cc, /* I - client.conf values */ const char *value) /* I - Value */ { /* * SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyTLS1.0] [None] */ int options = _HTTP_TLS_NONE; /* SSL/TLS options */ char temp[256], /* Copy of value */ *start, /* Start of option */ *end; /* End of option */ strlcpy(temp, value, sizeof(temp)); for (start = temp; *start; start = end) { /* * Find end of keyword... */ end = start; while (*end && !_cups_isspace(*end)) end ++; if (*end) *end++ = '\0'; /* * Compare... */ if (!_cups_strcasecmp(start, "AllowRC4")) options |= _HTTP_TLS_ALLOW_RC4; else if (!_cups_strcasecmp(start, "AllowSSL3")) options |= _HTTP_TLS_ALLOW_SSL3; else if (!_cups_strcasecmp(start, "AllowDH")) options |= _HTTP_TLS_ALLOW_DH; else if (!_cups_strcasecmp(start, "DenyTLS1.0")) options |= _HTTP_TLS_DENY_TLS10; else if (!_cups_strcasecmp(start, "None")) options = _HTTP_TLS_NONE; } cc->ssl_options = options; DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x", cc, value, options)); }
int /* O - Number of options found */ cupsParseOptions( const char *arg, /* I - Argument to parse */ int num_options, /* I - Number of options */ cups_option_t **options) /* O - Options found */ { char *copyarg, /* Copy of input string */ *ptr, /* Pointer into string */ *name, /* Pointer to name */ *value, /* Pointer to value */ sep, /* Separator character */ quote; /* Quote character */ DEBUG_printf(("cupsParseOptions(arg=\"%s\", num_options=%d, options=%p)", arg, num_options, (void *)options)); /* * Range check input... */ if (!arg) { DEBUG_printf(("1cupsParseOptions: Returning %d", num_options)); return (num_options); } if (!options || num_options < 0) { DEBUG_puts("1cupsParseOptions: Returning 0"); return (0); } /* * Make a copy of the argument string and then divide it up... */ if ((copyarg = strdup(arg)) == NULL) { DEBUG_puts("1cupsParseOptions: Unable to copy arg string"); DEBUG_printf(("1cupsParseOptions: Returning %d", num_options)); return (num_options); } if (*copyarg == '{') { /* * Remove surrounding {} so we can parse "{name=value ... name=value}"... */ if ((ptr = copyarg + strlen(copyarg) - 1) > copyarg && *ptr == '}') { *ptr = '\0'; ptr = copyarg + 1; } else ptr = copyarg; } else ptr = copyarg; /* * Skip leading spaces... */ while (_cups_isspace(*ptr)) ptr ++; /* * Loop through the string... */ while (*ptr != '\0') { /* * Get the name up to a SPACE, =, or end-of-string... */ name = ptr; while (!strchr("\f\n\r\t\v =", *ptr) && *ptr) ptr ++; /* * Avoid an empty name... */ if (ptr == name) break; /* * Skip trailing spaces... */ while (_cups_isspace(*ptr)) *ptr++ = '\0'; if ((sep = *ptr) == '=') *ptr++ = '\0'; DEBUG_printf(("2cupsParseOptions: name=\"%s\"", name)); if (sep != '=') { /* * Boolean option... */ if (!_cups_strncasecmp(name, "no", 2)) num_options = cupsAddOption(name + 2, "false", num_options, options); else num_options = cupsAddOption(name, "true", num_options, options); continue; } /* * Remove = and parse the value... */ value = ptr; while (*ptr && !_cups_isspace(*ptr)) { if (*ptr == ',') ptr ++; else if (*ptr == '\'' || *ptr == '\"') { /* * Quoted string constant... */ quote = *ptr; _cups_strcpy(ptr, ptr + 1); while (*ptr != quote && *ptr) { if (*ptr == '\\' && ptr[1]) _cups_strcpy(ptr, ptr + 1); ptr ++; } if (*ptr) _cups_strcpy(ptr, ptr + 1); } else if (*ptr == '{') { /* * Collection value... */ int depth; for (depth = 0; *ptr; ptr ++) { if (*ptr == '{') depth ++; else if (*ptr == '}') { depth --; if (!depth) { ptr ++; break; } } else if (*ptr == '\\' && ptr[1]) _cups_strcpy(ptr, ptr + 1); } } else { /* * Normal space-delimited string... */ while (*ptr && !_cups_isspace(*ptr)) { if (*ptr == '\\' && ptr[1]) _cups_strcpy(ptr, ptr + 1); ptr ++; } } } if (*ptr != '\0') *ptr++ = '\0'; DEBUG_printf(("2cupsParseOptions: value=\"%s\"", value)); /* * Skip trailing whitespace... */ while (_cups_isspace(*ptr)) ptr ++; /* * Add the string value... */ num_options = cupsAddOption(name, value, num_options, options); } /* * Free the copy of the argument we made and return the number of options * found. */ free(copyarg); DEBUG_printf(("1cupsParseOptions: Returning %d", num_options)); return (num_options); }
double /* O - Number */ _cupsStrScand(const char *buf, /* I - Pointer to number */ char **bufptr, /* O - New pointer or NULL on error */ struct lconv *loc) /* I - Locale data */ { char temp[1024], /* Temporary buffer */ *tempptr; /* Pointer into temporary buffer */ /* * Range check input... */ if (!buf) return (0.0); /* * Skip leading whitespace... */ while (_cups_isspace(*buf)) buf ++; /* * Copy leading sign, numbers, period, and then numbers... */ tempptr = temp; if (*buf == '-' || *buf == '+') *tempptr++ = *buf++; while (isdigit(*buf & 255)) if (tempptr < (temp + sizeof(temp) - 1)) *tempptr++ = *buf++; else { if (bufptr) *bufptr = NULL; return (0.0); } if (*buf == '.') { /* * Read fractional portion of number... */ buf ++; if (loc && loc->decimal_point) { strlcpy(tempptr, loc->decimal_point, sizeof(temp) - (size_t)(tempptr - temp)); tempptr += strlen(tempptr); } else if (tempptr < (temp + sizeof(temp) - 1)) *tempptr++ = '.'; else { if (bufptr) *bufptr = NULL; return (0.0); } while (isdigit(*buf & 255)) if (tempptr < (temp + sizeof(temp) - 1)) *tempptr++ = *buf++; else { if (bufptr) *bufptr = NULL; return (0.0); } } if (*buf == 'e' || *buf == 'E') { /* * Read exponent... */ if (tempptr < (temp + sizeof(temp) - 1)) *tempptr++ = *buf++; else { if (bufptr) *bufptr = NULL; return (0.0); } if (*buf == '+' || *buf == '-') { if (tempptr < (temp + sizeof(temp) - 1)) *tempptr++ = *buf++; else { if (bufptr) *bufptr = NULL; return (0.0); } } while (isdigit(*buf & 255)) if (tempptr < (temp + sizeof(temp) - 1)) *tempptr++ = *buf++; else { if (bufptr) *bufptr = NULL; return (0.0); } } /* * Nul-terminate the temporary string and return the value... */ if (bufptr) *bufptr = (char *)buf; *tempptr = '\0'; return (strtod(temp, NULL)); }
static void ppd_load_constraints(ppd_file_t *ppd) /* I - PPD file */ { int i; /* Looping var */ ppd_const_t *oldconst; /* Current UIConstraints data */ ppd_attr_t *constattr; /* Current cupsUIConstraints attribute */ _ppd_cups_uiconsts_t *consts; /* Current cupsUIConstraints data */ _ppd_cups_uiconst_t *constptr; /* Current constraint */ ppd_group_t *installable; /* Installable options group */ const char *vptr; /* Pointer into constraint value */ char option[PPD_MAX_NAME], /* Option name/MainKeyword */ choice[PPD_MAX_NAME], /* Choice/OptionKeyword */ *ptr; /* Pointer into option or choice */ DEBUG_printf(("7ppd_load_constraints(ppd=%p)", ppd)); /* * Create an array to hold the constraint data... */ ppd->cups_uiconstraints = cupsArrayNew(NULL, NULL); /* * Find the installable options group if it exists... */ for (i = ppd->num_groups, installable = ppd->groups; i > 0; i --, installable ++) if (!_cups_strcasecmp(installable->name, "InstallableOptions")) break; if (i <= 0) installable = NULL; /* * Load old-style [Non]UIConstraints data... */ for (i = ppd->num_consts, oldconst = ppd->consts; i > 0; i --, oldconst ++) { /* * Weed out nearby duplicates, since the PPD spec requires that you * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"... */ if (i > 1 && !_cups_strcasecmp(oldconst[0].option1, oldconst[1].option2) && !_cups_strcasecmp(oldconst[0].choice1, oldconst[1].choice2) && !_cups_strcasecmp(oldconst[0].option2, oldconst[1].option1) && !_cups_strcasecmp(oldconst[0].choice2, oldconst[1].choice1)) continue; /* * Allocate memory... */ if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL) { DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " "UIConstraints!"); return; } if ((constptr = calloc(2, sizeof(_ppd_cups_uiconst_t))) == NULL) { free(consts); DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " "UIConstraints!"); return; } /* * Fill in the information... */ consts->num_constraints = 2; consts->constraints = constptr; if (!_cups_strncasecmp(oldconst->option1, "Custom", 6) && !_cups_strcasecmp(oldconst->choice1, "True")) { constptr[0].option = ppdFindOption(ppd, oldconst->option1 + 6); constptr[0].choice = ppdFindChoice(constptr[0].option, "Custom"); constptr[0].installable = 0; } else { constptr[0].option = ppdFindOption(ppd, oldconst->option1); constptr[0].choice = ppdFindChoice(constptr[0].option, oldconst->choice1); constptr[0].installable = ppd_is_installable(installable, oldconst->option1); } if (!constptr[0].option || (!constptr[0].choice && oldconst->choice1[0])) { DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", oldconst->option1, oldconst->choice1)); free(consts->constraints); free(consts); continue; } if (!_cups_strncasecmp(oldconst->option2, "Custom", 6) && !_cups_strcasecmp(oldconst->choice2, "True")) { constptr[1].option = ppdFindOption(ppd, oldconst->option2 + 6); constptr[1].choice = ppdFindChoice(constptr[1].option, "Custom"); constptr[1].installable = 0; } else { constptr[1].option = ppdFindOption(ppd, oldconst->option2); constptr[1].choice = ppdFindChoice(constptr[1].option, oldconst->choice2); constptr[1].installable = ppd_is_installable(installable, oldconst->option2); } if (!constptr[1].option || (!constptr[1].choice && oldconst->choice2[0])) { DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", oldconst->option2, oldconst->choice2)); free(consts->constraints); free(consts); continue; } consts->installable = constptr[0].installable || constptr[1].installable; /* * Add it to the constraints array... */ cupsArrayAdd(ppd->cups_uiconstraints, consts); } /* * Then load new-style constraints... */ for (constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL); constattr; constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL)) { if (!constattr->value) { DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!"); continue; } for (i = 0, vptr = strchr(constattr->value, '*'); vptr; i ++, vptr = strchr(vptr + 1, '*')); if (i == 0) { DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!"); continue; } if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL) { DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " "cupsUIConstraints!"); return; } if ((constptr = calloc((size_t)i, sizeof(_ppd_cups_uiconst_t))) == NULL) { free(consts); DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " "cupsUIConstraints!"); return; } consts->num_constraints = i; consts->constraints = constptr; strlcpy(consts->resolver, constattr->spec, sizeof(consts->resolver)); for (i = 0, vptr = strchr(constattr->value, '*'); vptr; i ++, vptr = strchr(vptr, '*'), constptr ++) { /* * Extract "*Option Choice" or just "*Option"... */ for (vptr ++, ptr = option; *vptr && !_cups_isspace(*vptr); vptr ++) if (ptr < (option + sizeof(option) - 1)) *ptr++ = *vptr; *ptr = '\0'; while (_cups_isspace(*vptr)) vptr ++; if (*vptr == '*') choice[0] = '\0'; else { for (ptr = choice; *vptr && !_cups_isspace(*vptr); vptr ++) if (ptr < (choice + sizeof(choice) - 1)) *ptr++ = *vptr; *ptr = '\0'; } if (!_cups_strncasecmp(option, "Custom", 6) && !_cups_strcasecmp(choice, "True")) { _cups_strcpy(option, option + 6); strlcpy(choice, "Custom", sizeof(choice)); } constptr->option = ppdFindOption(ppd, option); constptr->choice = ppdFindChoice(constptr->option, choice); constptr->installable = ppd_is_installable(installable, option); consts->installable |= constptr->installable; if (!constptr->option || (!constptr->choice && choice[0])) { DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", option, choice)); break; } } if (!vptr) cupsArrayAdd(ppd->cups_uiconstraints, consts); else { free(consts->constraints); free(consts); } } }
int /* O - 1 on success, 0 on failure */ cupsResolveConflicts( ppd_file_t *ppd, /* I - PPD file */ const char *option, /* I - Newly selected option or @code NULL@ for none */ const char *choice, /* I - Newly selected choice or @code NULL@ for none */ int *num_options, /* IO - Number of additional selected options */ cups_option_t **options) /* IO - Additional selected options */ { int i, /* Looping var */ tries, /* Number of tries */ num_newopts; /* Number of new options */ cups_option_t *newopts; /* New options */ cups_array_t *active = NULL, /* Active constraints */ *pass, /* Resolvers for this pass */ *resolvers, /* Resolvers we have used */ *test; /* Test array for conflicts */ _ppd_cups_uiconsts_t *consts; /* Current constraints */ _ppd_cups_uiconst_t *constptr; /* Current constraint */ ppd_attr_t *resolver; /* Current resolver */ const char *resval; /* Pointer into resolver value */ char resoption[PPD_MAX_NAME], /* Current resolver option */ reschoice[PPD_MAX_NAME], /* Current resolver choice */ *resptr, /* Pointer into option/choice */ firstpage[255]; /* AP_FIRSTPAGE_Keyword string */ const char *value; /* Selected option value */ int changed; /* Did we change anything? */ ppd_choice_t *marked; /* Marked choice */ /* * Range check input... */ if (!ppd || !num_options || !options || (option == NULL) != (choice == NULL)) return (0); /* * Build a shadow option array... */ num_newopts = 0; newopts = NULL; for (i = 0; i < *num_options; i ++) num_newopts = cupsAddOption((*options)[i].name, (*options)[i].value, num_newopts, &newopts); if (option && _cups_strcasecmp(option, "Collate")) num_newopts = cupsAddOption(option, choice, num_newopts, &newopts); /* * Loop until we have no conflicts... */ cupsArraySave(ppd->sorted_attrs); resolvers = NULL; pass = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL); tries = 0; while (tries < 100 && (active = ppd_test_constraints(ppd, NULL, NULL, num_newopts, newopts, _PPD_ALL_CONSTRAINTS)) != NULL) { tries ++; if (!resolvers) resolvers = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL); for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active), changed = 0; consts; consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(active)) { if (consts->resolver[0]) { /* * Look up the resolver... */ if (cupsArrayFind(pass, consts->resolver)) continue; /* Already applied this resolver... */ if (cupsArrayFind(resolvers, consts->resolver)) { /* * Resolver loop! */ DEBUG_printf(("1cupsResolveConflicts: Resolver loop with %s!", consts->resolver)); goto error; } if ((resolver = ppdFindAttr(ppd, "cupsUIResolver", consts->resolver)) == NULL) { DEBUG_printf(("1cupsResolveConflicts: Resolver %s not found!", consts->resolver)); goto error; } if (!resolver->value) { DEBUG_printf(("1cupsResolveConflicts: Resolver %s has no value!", consts->resolver)); goto error; } /* * Add the options from the resolver... */ cupsArrayAdd(pass, consts->resolver); cupsArrayAdd(resolvers, consts->resolver); for (resval = resolver->value; *resval && !changed;) { while (_cups_isspace(*resval)) resval ++; if (*resval != '*') break; for (resval ++, resptr = resoption; *resval && !_cups_isspace(*resval); resval ++) if (resptr < (resoption + sizeof(resoption) - 1)) *resptr++ = *resval; *resptr = '\0'; while (_cups_isspace(*resval)) resval ++; for (resptr = reschoice; *resval && !_cups_isspace(*resval); resval ++) if (resptr < (reschoice + sizeof(reschoice) - 1)) *resptr++ = *resval; *resptr = '\0'; if (!resoption[0] || !reschoice[0]) break; /* * Is this the option we are changing? */ snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s", resoption); if (option && (!_cups_strcasecmp(resoption, option) || !_cups_strcasecmp(firstpage, option) || (!_cups_strcasecmp(option, "PageSize") && !_cups_strcasecmp(resoption, "PageRegion")) || (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") && !_cups_strcasecmp(resoption, "PageSize")) || (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") && !_cups_strcasecmp(resoption, "PageRegion")) || (!_cups_strcasecmp(option, "PageRegion") && !_cups_strcasecmp(resoption, "PageSize")) || (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion") && !_cups_strcasecmp(resoption, "PageSize")) || (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion") && !_cups_strcasecmp(resoption, "PageRegion")))) continue; /* * Try this choice... */ if ((test = ppd_test_constraints(ppd, resoption, reschoice, num_newopts, newopts, _PPD_ALL_CONSTRAINTS)) == NULL) { /* * That worked... */ changed = 1; } else cupsArrayDelete(test); /* * Add the option/choice from the resolver regardless of whether it * worked; this makes sure that we can cascade several changes to * make things resolve... */ num_newopts = cupsAddOption(resoption, reschoice, num_newopts, &newopts); } } else { /* * Try resolving by choosing the default values for non-installable * options, then by iterating through the possible choices... */ int j; /* Looping var */ ppd_choice_t *cptr; /* Current choice */ ppd_size_t *size; /* Current page size */ for (i = consts->num_constraints, constptr = consts->constraints; i > 0 && !changed; i --, constptr ++) { /* * Can't resolve by changing an installable option... */ if (constptr->installable) continue; /* * Is this the option we are changing? */ if (option && (!_cups_strcasecmp(constptr->option->keyword, option) || (!_cups_strcasecmp(option, "PageSize") && !_cups_strcasecmp(constptr->option->keyword, "PageRegion")) || (!_cups_strcasecmp(option, "PageRegion") && !_cups_strcasecmp(constptr->option->keyword, "PageSize")))) continue; /* * Get the current option choice... */ if ((value = cupsGetOption(constptr->option->keyword, num_newopts, newopts)) == NULL) { if (!_cups_strcasecmp(constptr->option->keyword, "PageSize") || !_cups_strcasecmp(constptr->option->keyword, "PageRegion")) { if ((value = cupsGetOption("PageSize", num_newopts, newopts)) == NULL) value = cupsGetOption("PageRegion", num_newopts, newopts); if (!value) { if ((size = ppdPageSize(ppd, NULL)) != NULL) value = size->name; else value = ""; } } else { marked = ppdFindMarkedChoice(ppd, constptr->option->keyword); value = marked ? marked->choice : ""; } } if (!_cups_strncasecmp(value, "Custom.", 7)) value = "Custom"; /* * Try the default choice... */ test = NULL; if (_cups_strcasecmp(value, constptr->option->defchoice) && (test = ppd_test_constraints(ppd, constptr->option->keyword, constptr->option->defchoice, num_newopts, newopts, _PPD_OPTION_CONSTRAINTS)) == NULL) { /* * That worked... */ num_newopts = cupsAddOption(constptr->option->keyword, constptr->option->defchoice, num_newopts, &newopts); changed = 1; } else { /* * Try each choice instead... */ for (j = constptr->option->num_choices, cptr = constptr->option->choices; j > 0; j --, cptr ++) { cupsArrayDelete(test); test = NULL; if (_cups_strcasecmp(value, cptr->choice) && _cups_strcasecmp(constptr->option->defchoice, cptr->choice) && _cups_strcasecmp("Custom", cptr->choice) && (test = ppd_test_constraints(ppd, constptr->option->keyword, cptr->choice, num_newopts, newopts, _PPD_OPTION_CONSTRAINTS)) == NULL) { /* * This choice works... */ num_newopts = cupsAddOption(constptr->option->keyword, cptr->choice, num_newopts, &newopts); changed = 1; break; } } cupsArrayDelete(test); } } } } if (!changed) { DEBUG_puts("1cupsResolveConflicts: Unable to automatically resolve " "constraint!"); goto error; } cupsArrayClear(pass); cupsArrayDelete(active); active = NULL; } if (tries >= 100) goto error; /* * Free the caller's option array... */ cupsFreeOptions(*num_options, *options); /* * If Collate is the option we are testing, add it here. Otherwise, remove * any Collate option from the resolve list since the filters automatically * handle manual collation... */ if (option && !_cups_strcasecmp(option, "Collate")) num_newopts = cupsAddOption(option, choice, num_newopts, &newopts); else num_newopts = cupsRemoveOption("Collate", num_newopts, &newopts); /* * Return the new list of options to the caller... */ *num_options = num_newopts; *options = newopts; cupsArrayDelete(pass); cupsArrayDelete(resolvers); cupsArrayRestore(ppd->sorted_attrs); DEBUG_printf(("1cupsResolveConflicts: Returning %d options:", num_newopts)); #ifdef DEBUG for (i = 0; i < num_newopts; i ++) DEBUG_printf(("1cupsResolveConflicts: options[%d]: %s=%s", i, newopts[i].name, newopts[i].value)); #endif /* DEBUG */ return (1); /* * If we get here, we failed to resolve... */ error: cupsFreeOptions(num_newopts, newopts); cupsArrayDelete(active); cupsArrayDelete(pass); cupsArrayDelete(resolvers); cupsArrayRestore(ppd->sorted_attrs); DEBUG_puts("1cupsResolveConflicts: Unable to resolve conflicts!"); return (0); }
char * /* O - Normalized make-and-model string or NULL on error */ _ppdNormalizeMakeAndModel( const char *make_and_model, /* I - Original make-and-model string */ char *buffer, /* I - String buffer */ size_t bufsize) /* I - Size of string buffer */ { char *bufptr; /* Pointer into buffer */ if (!make_and_model || !buffer || bufsize < 1) { if (buffer) *buffer = '\0'; return (NULL); } /* * Skip leading whitespace... */ while (_cups_isspace(*make_and_model)) make_and_model ++; /* * Remove parenthesis and add manufacturers as needed... */ if (make_and_model[0] == '(') { strlcpy(buffer, make_and_model + 1, bufsize); if ((bufptr = strrchr(buffer, ')')) != NULL) *bufptr = '\0'; } else if (!_cups_strncasecmp(make_and_model, "XPrint", 6)) { /* * Xerox XPrint... */ snprintf(buffer, bufsize, "Xerox %s", make_and_model); } else if (!_cups_strncasecmp(make_and_model, "Eastman", 7)) { /* * Kodak... */ snprintf(buffer, bufsize, "Kodak %s", make_and_model + 7); } else if (!_cups_strncasecmp(make_and_model, "laserwriter", 11)) { /* * Apple LaserWriter... */ snprintf(buffer, bufsize, "Apple LaserWriter%s", make_and_model + 11); } else if (!_cups_strncasecmp(make_and_model, "colorpoint", 10)) { /* * Seiko... */ snprintf(buffer, bufsize, "Seiko %s", make_and_model); } else if (!_cups_strncasecmp(make_and_model, "fiery", 5)) { /* * EFI... */ snprintf(buffer, bufsize, "EFI %s", make_and_model); } else if (!_cups_strncasecmp(make_and_model, "ps ", 3) || !_cups_strncasecmp(make_and_model, "colorpass", 9)) { /* * Canon... */ snprintf(buffer, bufsize, "Canon %s", make_and_model); } else if (!_cups_strncasecmp(make_and_model, "primera", 7)) { /* * Fargo... */ snprintf(buffer, bufsize, "Fargo %s", make_and_model); } else if (!_cups_strncasecmp(make_and_model, "designjet", 9) || !_cups_strncasecmp(make_and_model, "deskjet", 7)) { /* * HP... */ snprintf(buffer, bufsize, "HP %s", make_and_model); } else strlcpy(buffer, make_and_model, bufsize); /* * Clean up the make... */ if (!_cups_strncasecmp(buffer, "agfa", 4)) { /* * Replace with AGFA (all uppercase)... */ buffer[0] = 'A'; buffer[1] = 'G'; buffer[2] = 'F'; buffer[3] = 'A'; } else if (!_cups_strncasecmp(buffer, "Hewlett-Packard hp ", 19)) { /* * Just put "HP" on the front... */ buffer[0] = 'H'; buffer[1] = 'P'; _cups_strcpy(buffer + 2, buffer + 18); } else if (!_cups_strncasecmp(buffer, "Hewlett-Packard ", 16)) { /* * Just put "HP" on the front... */ buffer[0] = 'H'; buffer[1] = 'P'; _cups_strcpy(buffer + 2, buffer + 15); } else if (!_cups_strncasecmp(buffer, "Lexmark International", 21)) { /* * Strip "International"... */ _cups_strcpy(buffer + 8, buffer + 21); } else if (!_cups_strncasecmp(buffer, "herk", 4)) { /* * Replace with LHAG... */ buffer[0] = 'L'; buffer[1] = 'H'; buffer[2] = 'A'; buffer[3] = 'G'; } else if (!_cups_strncasecmp(buffer, "linotype", 8)) { /* * Replace with LHAG... */ buffer[0] = 'L'; buffer[1] = 'H'; buffer[2] = 'A'; buffer[3] = 'G'; _cups_strcpy(buffer + 4, buffer + 8); } /* * Remove trailing whitespace and return... */ for (bufptr = buffer + strlen(buffer) - 1; bufptr >= buffer && _cups_isspace(*bufptr); bufptr --); bufptr[1] = '\0'; return (buffer[0] ? buffer : NULL); }
static void add_ppd_filter(mime_t *mime, /* I - MIME database */ mime_type_t *filtertype, /* I - Filter or prefilter MIME type */ const char *filter) /* I - Filter to add */ { char super[MIME_MAX_SUPER], /* Super-type for filter */ type[MIME_MAX_TYPE], /* Type for filter */ dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */ dtype[MIME_MAX_TYPE], /* Destination type for filter */ dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2], /* Destination super/type */ program[1024]; /* Program/filter name */ int cost; /* Cost of filter */ size_t maxsize = 0; /* Maximum supported file size */ mime_type_t *temptype, /* MIME type looping var */ *desttype; /* Destination MIME type */ mime_filter_t *filterptr; /* MIME filter */ DEBUG_printf(("add_ppd_filter(mime=%p, filtertype=%p(%s/%s), filter=\"%s\")", mime, filtertype, filtertype->super, filtertype->type, filter)); /* * Parse the filter string; it should be in one of the following formats: * * source/type cost program * source/type cost maxsize(nnnn) program * source/type dest/type cost program * source/type dest/type cost maxsize(nnnn) program */ if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, dsuper, dtype, &cost, program) == 6) { snprintf(dest, sizeof(dest), "test/%s/%s", dsuper, dtype); if ((desttype = mimeType(mime, "printer", dest)) == NULL) desttype = mimeAddType(mime, "printer", dest); } else { if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost, program) == 4) { desttype = filtertype; } else { printf("testmime: Invalid filter string \"%s\".\n", filter); return; } } if (!strncmp(program, "maxsize(", 8)) { char *ptr; /* Pointer into maxsize(nnnn) program */ maxsize = strtoll(program + 8, &ptr, 10); if (*ptr != ')') { printf("testmime: Invalid filter string \"%s\".\n", filter); return; } ptr ++; while (_cups_isspace(*ptr)) ptr ++; _cups_strcpy(program, ptr); } /* * Add the filter to the MIME database, supporting wildcards as needed... */ for (temptype = mimeFirstType(mime); temptype; temptype = mimeNextType(mime)) if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) || !_cups_strcasecmp(temptype->super, super)) && (type[0] == '*' || !_cups_strcasecmp(temptype->type, type))) { if (desttype != filtertype) { DEBUG_printf(("add_ppd_filter: Adding filter %s/%s %s/%s %d %s", temptype->super, temptype->type, desttype->super, desttype->type, cost, program)); filterptr = mimeAddFilter(mime, temptype, desttype, cost, program); if (!mimeFilterLookup(mime, desttype, filtertype)) { DEBUG_printf(("add_printer_filter: Adding filter %s/%s %s/%s 0 -", desttype->super, desttype->type, filtertype->super, filtertype->type)); mimeAddFilter(mime, desttype, filtertype, 0, "-"); } } else { DEBUG_printf(("add_printer_filter: Adding filter %s/%s %s/%s %d %s", temptype->super, temptype->type, filtertype->super, filtertype->type, cost, program)); filterptr = mimeAddFilter(mime, temptype, filtertype, cost, program); } if (filterptr) filterptr->maxsize = maxsize; } }
cups_array_t * /* O - Languages array */ _ppdGetLanguages(ppd_file_t *ppd) /* I - PPD file */ { cups_array_t *languages; /* Languages array */ ppd_attr_t *attr; /* cupsLanguages attribute */ char *value, /* Copy of attribute value */ *start, /* Start of current language */ *ptr; /* Pointer into languages */ /* * See if we have a cupsLanguages attribute... */ if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) == NULL || !attr->value) return (NULL); /* * Yes, load the list... */ if ((languages = cupsArrayNew((cups_array_func_t)strcmp, NULL)) == NULL) return (NULL); if ((value = strdup(attr->value)) == NULL) { cupsArrayDelete(languages); return (NULL); } for (ptr = value; *ptr;) { /* * Skip leading whitespace... */ while (_cups_isspace(*ptr)) ptr ++; if (!*ptr) break; /* * Find the end of this language name... */ for (start = ptr; *ptr && !_cups_isspace(*ptr); ptr ++); if (*ptr) *ptr++ = '\0'; if (!strcmp(start, "en")) continue; cupsArrayAdd(languages, strdup(start)); } /* * Free the temporary string and return either an array with one or more * values or a NULL pointer... */ free(value); if (cupsArrayCount(languages) == 0) { cupsArrayDelete(languages); return (NULL); } else return (languages); }
size_t /* O - Number of bytes less nul */ _ippAttrString(ipp_attribute_t *attr, /* I - Attribute */ char *buffer, /* I - String buffer or NULL */ size_t bufsize) /* I - Size of string buffer */ { int i; /* Looping var */ char *bufptr, /* Pointer into buffer */ *bufend, /* End of buffer */ temp[256]; /* Temporary string */ const char *ptr; /* Pointer into string */ ipp_value_t *val; /* Current value */ if (!attr || !attr->name) { if (buffer) *buffer = '\0'; return (0); } bufptr = buffer; if (buffer) bufend = buffer + bufsize - 1; else bufend = NULL; for (i = attr->num_values, val = attr->values; i > 0; i --, val ++) { if (val > attr->values) { if (buffer && bufptr < bufend) *bufptr++ = ','; else bufptr ++; } switch (attr->value_tag & ~IPP_TAG_COPY) { case IPP_TAG_ENUM : if (!strcmp(attr->name, "printer-state") && val->integer >= IPP_PRINTER_IDLE && val->integer <= IPP_PRINTER_STOPPED) { ptr = printer_states[val->integer - IPP_PRINTER_IDLE]; if (buffer && bufptr < bufend) strlcpy(bufptr, ptr, bufend - bufptr + 1); bufptr += strlen(ptr); break; } else if (!strcmp(attr->name, "job-state") && val->integer >= IPP_JOB_PENDING && val->integer <= IPP_JOB_COMPLETED) { ptr = job_states[val->integer - IPP_JOB_PENDING]; if (buffer && bufptr < bufend) strlcpy(bufptr, ptr, bufend - bufptr + 1); bufptr += strlen(ptr); break; } else if (!strcmp(attr->name, "operations-supported")) { ptr = ippOpString(val->integer); if (buffer && bufptr < bufend) strlcpy(bufptr, ptr, bufend - bufptr + 1); bufptr += strlen(ptr); break; } case IPP_TAG_INTEGER : if (buffer && bufptr < bufend) bufptr += snprintf(bufptr, bufend - bufptr + 1, "%d", val->integer); else bufptr += snprintf(temp, sizeof(temp), "%d", val->integer); break; case IPP_TAG_BOOLEAN : if (buffer && bufptr < bufend) strlcpy(bufptr, val->boolean ? "true" : "false", bufend - bufptr + 1); bufptr += val->boolean ? 4 : 5; break; case IPP_TAG_RANGE : if (buffer && bufptr < bufend) bufptr += snprintf(bufptr, bufend - bufptr + 1, "%d-%d", val->range.lower, val->range.upper); else bufptr += snprintf(temp, sizeof(temp), "%d-%d", val->range.lower, val->range.upper); break; case IPP_TAG_RESOLUTION : if (buffer && bufptr < bufend) bufptr += snprintf(bufptr, bufend - bufptr + 1, "%dx%d%s", val->resolution.xres, val->resolution.yres, val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpc"); else bufptr += snprintf(temp, sizeof(temp), "%dx%d%s", val->resolution.xres, val->resolution.yres, val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpc"); break; case IPP_TAG_DATE : { unsigned year; /* Year */ year = (val->date[0] << 8) + val->date[1]; if (val->date[9] == 0 && val->date[10] == 0) snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02uZ", year, val->date[2], val->date[3], val->date[4], val->date[5], val->date[6]); else snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u", year, val->date[2], val->date[3], val->date[4], val->date[5], val->date[6], val->date[8], val->date[9], val->date[10]); if (buffer && bufptr < bufend) strlcpy(bufptr, temp, bufend - bufptr + 1); bufptr += strlen(temp); } break; case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_CHARSET : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_MIMETYPE : case IPP_TAG_LANGUAGE : case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : if (!val->string.text) break; for (ptr = val->string.text; *ptr; ptr ++) { if (*ptr == '\\' || *ptr == '\"') { if (buffer && bufptr < bufend) *bufptr = '\\'; bufptr ++; } if (buffer && bufptr < bufend) *bufptr = *ptr; bufptr ++; } break; case IPP_TAG_BEGIN_COLLECTION : if (buffer && bufptr < bufend) bufptr += ipp_col_string(val->collection, bufptr, bufend - bufptr + 1); else bufptr += ipp_col_string(val->collection, NULL, 0); break; case IPP_TAG_STRING : for (ptr = val->string.text; *ptr; ptr ++) { if (*ptr == '\\' || _cups_isspace(*ptr)) { if (buffer && bufptr < bufend) *bufptr = '\\'; bufptr ++; if (buffer && bufptr < bufend) *bufptr = *ptr; bufptr ++; } else if (!isprint(*ptr & 255)) { if (buffer && bufptr < bufend) bufptr += snprintf(bufptr, bufend - bufptr + 1, "\\%03o", *ptr & 255); else bufptr += snprintf(temp, sizeof(temp), "\\%03o", *ptr & 255); } else { if (buffer && bufptr < bufend) *bufptr = *ptr; bufptr ++; } } break; default : ptr = ippTagString(attr->value_tag); if (buffer && bufptr < bufend) strlcpy(bufptr, ptr, bufend - bufptr + 1); bufptr += strlen(ptr); break; } } if (buffer && bufptr < bufend) *bufptr = '\0'; else if (bufend) *bufend = '\0'; return (bufptr - buffer); }
char * /* O - Line read or @code NULL@ on end of file or error */ cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */ char *buf, /* O - String buffer */ size_t buflen, /* I - Size of string buffer */ char **value, /* O - Pointer to value */ int *linenum) /* IO - Current line number */ { char *ptr; /* Pointer into line */ /* * Range check input... */ DEBUG_printf(("2cupsFileGetConf(fp=%p, buf=%p, buflen=" CUPS_LLFMT ", value=%p, linenum=%p)", fp, buf, CUPS_LLCAST buflen, value, linenum)); if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2 || !value) { if (value) *value = NULL; return (NULL); } /* * Read the next non-comment line... */ *value = NULL; while (cupsFileGets(fp, buf, buflen)) { (*linenum) ++; /* * Strip any comments... */ if ((ptr = strchr(buf, '#')) != NULL) { if (ptr > buf && ptr[-1] == '\\') { // Unquote the #... _cups_strcpy(ptr - 1, ptr); } else { // Strip the comment and any trailing whitespace... while (ptr > buf) { if (!_cups_isspace(ptr[-1])) break; ptr --; } *ptr = '\0'; } } /* * Strip leading whitespace... */ for (ptr = buf; _cups_isspace(*ptr); ptr ++); if (ptr > buf) _cups_strcpy(buf, ptr); /* * See if there is anything left... */ if (buf[0]) { /* * Yes, grab any value and return... */ for (ptr = buf; *ptr; ptr ++) if (_cups_isspace(*ptr)) break; if (*ptr) { /* * Have a value, skip any other spaces... */ while (_cups_isspace(*ptr)) *ptr++ = '\0'; if (*ptr) *value = ptr; /* * Strip trailing whitespace and > for lines that begin with <... */ ptr += strlen(ptr) - 1; if (buf[0] == '<' && *ptr == '>') *ptr-- = '\0'; else if (buf[0] == '<' && *ptr != '>') { /* * Syntax error... */ *value = NULL; return (buf); } while (ptr > *value && _cups_isspace(*ptr)) *ptr-- = '\0'; } /* * Return the line... */ return (buf); } } return (NULL); }
int /* O - 1 on success, 0 on failure */ cupsAdminGetServerSettings( http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ int *num_settings, /* O - Number of settings */ cups_option_t **settings) /* O - Settings */ { int i; /* Looping var */ cups_file_t *cupsd; /* cupsd.conf file */ char cupsdconf[1024]; /* cupsd.conf filename */ int remote; /* Remote cupsd.conf file? */ http_status_t status; /* Status of getting cupsd.conf */ char line[1024], /* Line from cupsd.conf file */ *value; /* Value on line */ cups_option_t *setting; /* Current setting */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ /* * Range check input... */ if (!http) { /* * See if we are connected to the same server... */ if (cg->http) { /* * Compare the connection hostname, port, and encryption settings to * the cached defaults; these were initialized the first time we * connected... */ if (strcmp(cg->http->hostname, cg->server) || cg->ipp_port != httpAddrPort(cg->http->hostaddr) || (cg->http->encryption != cg->encryption && cg->http->encryption == HTTP_ENCRYPTION_NEVER)) { /* * Need to close the current connection because something has changed... */ httpClose(cg->http); cg->http = NULL; } } /* * (Re)connect as needed... */ if (!cg->http) { if ((cg->http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 0, NULL)) == NULL) { if (errno) _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, NULL, 0); else _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, _("Unable to connect to host."), 1); if (num_settings) *num_settings = 0; if (settings) *settings = NULL; return (0); } } http = cg->http; } if (!http || !num_settings || !settings) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); if (num_settings) *num_settings = 0; if (settings) *settings = NULL; return (0); } *num_settings = 0; *settings = NULL; /* * Get the cupsd.conf file... */ if ((status = get_cupsd_conf(http, cg, cg->cupsd_update, cupsdconf, sizeof(cupsdconf), &remote)) == HTTP_STATUS_OK) { if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL) { char message[1024]; /* Message string */ snprintf(message, sizeof(message), _cupsLangString(cupsLangDefault(), _("Open of %s failed: %s")), cupsdconf, strerror(errno)); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0); } } else cupsd = NULL; if (cupsd) { /* * Read the file, keeping track of what settings are enabled... */ int remote_access = 0, /* Remote access allowed? */ remote_admin = 0, /* Remote administration allowed? */ remote_any = 0, /* Remote access from anywhere allowed? */ browsing = 1, /* Browsing enabled? */ cancel_policy = 1, /* Cancel-job policy set? */ debug_logging = 0; /* LogLevel debug set? */ int linenum = 0, /* Line number in file */ in_location = 0, /* In a location section? */ in_policy = 0, /* In a policy section? */ in_cancel_job = 0, /* In a cancel-job section? */ in_admin_location = 0; /* In the /admin location? */ invalidate_cupsd_cache(cg); cg->cupsd_update = time(NULL); httpGetHostname(http, cg->cupsd_hostname, sizeof(cg->cupsd_hostname)); while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum)) { if (!value && strncmp(line, "</", 2)) value = line + strlen(line); if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")) && value) { char *port; /* Pointer to port number, if any */ if ((port = strrchr(value, ':')) != NULL) *port = '\0'; else if (isdigit(*value & 255)) { /* * Listen on a port number implies remote access... */ remote_access = 1; continue; } if (_cups_strcasecmp(value, "localhost") && strcmp(value, "127.0.0.1") #ifdef AF_LOCAL && *value != '/' #endif /* AF_LOCAL */ #ifdef AF_INET6 && strcmp(value, "[::1]") #endif /* AF_INET6 */ ) remote_access = 1; } else if (!_cups_strcasecmp(line, "Browsing")) { browsing = !_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "on") || !_cups_strcasecmp(value, "true"); } else if (!_cups_strcasecmp(line, "LogLevel")) { debug_logging = !_cups_strncasecmp(value, "debug", 5); } else if (!_cups_strcasecmp(line, "<Policy") && !_cups_strcasecmp(value, "default")) { in_policy = 1; } else if (!_cups_strcasecmp(line, "</Policy>")) { in_policy = 0; } else if (!_cups_strcasecmp(line, "<Limit") && in_policy && value) { /* * See if the policy limit is for the Cancel-Job operation... */ char *valptr; /* Pointer into value */ while (*value) { for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++); if (*valptr) *valptr++ = '\0'; if (!_cups_strcasecmp(value, "cancel-job") || !_cups_strcasecmp(value, "all")) { in_cancel_job = 1; break; } for (value = valptr; _cups_isspace(*value); value ++); } } else if (!_cups_strcasecmp(line, "</Limit>")) { in_cancel_job = 0; } else if (!_cups_strcasecmp(line, "Require") && in_cancel_job) { cancel_policy = 0; } else if (!_cups_strcasecmp(line, "<Location") && value) { in_admin_location = !_cups_strcasecmp(value, "/admin"); in_location = 1; } else if (!_cups_strcasecmp(line, "</Location>")) { in_admin_location = 0; in_location = 0; } else if (!_cups_strcasecmp(line, "Allow") && value && _cups_strcasecmp(value, "localhost") && _cups_strcasecmp(value, "127.0.0.1") #ifdef AF_LOCAL && *value != '/' #endif /* AF_LOCAL */ #ifdef AF_INET6 && strcmp(value, "::1") #endif /* AF_INET6 */ ) { if (in_admin_location) remote_admin = 1; else if (!_cups_strcasecmp(value, "all")) remote_any = 1; } else if (line[0] != '<' && !in_location && !in_policy && _cups_strcasecmp(line, "Allow") && _cups_strcasecmp(line, "AuthType") && _cups_strcasecmp(line, "Deny") && _cups_strcasecmp(line, "Order") && _cups_strcasecmp(line, "Require") && _cups_strcasecmp(line, "Satisfy")) cg->cupsd_num_settings = cupsAddOption(line, value, cg->cupsd_num_settings, &(cg->cupsd_settings)); } cupsFileClose(cupsd); cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, debug_logging ? "1" : "0", cg->cupsd_num_settings, &(cg->cupsd_settings)); cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, (remote_access && remote_admin) ? "1" : "0", cg->cupsd_num_settings, &(cg->cupsd_settings)); cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY, remote_any ? "1" : "0", cg->cupsd_num_settings, &(cg->cupsd_settings)); cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, (remote_access && browsing) ? "1" : "0", cg->cupsd_num_settings, &(cg->cupsd_settings)); cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, cancel_policy ? "1" : "0", cg->cupsd_num_settings, &(cg->cupsd_settings)); } else if (status != HTTP_STATUS_NOT_MODIFIED) invalidate_cupsd_cache(cg); /* * Remove any temporary files and copy the settings array... */ if (remote) unlink(cupsdconf); for (i = cg->cupsd_num_settings, setting = cg->cupsd_settings; i > 0; i --, setting ++) *num_settings = cupsAddOption(setting->name, setting->value, *num_settings, settings); return (cg->cupsd_num_settings > 0); }
int /* O - 1 on success, 0 on failure */ cupsAdminSetServerSettings( http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ int num_settings, /* I - Number of settings */ cups_option_t *settings) /* I - Settings */ { int i; /* Looping var */ http_status_t status; /* GET/PUT status */ const char *server_port_env; /* SERVER_PORT env var */ int server_port; /* IPP port for server */ cups_file_t *cupsd; /* cupsd.conf file */ char cupsdconf[1024]; /* cupsd.conf filename */ int remote; /* Remote cupsd.conf file? */ char tempfile[1024]; /* Temporary new cupsd.conf */ cups_file_t *temp; /* Temporary file */ char line[1024], /* Line from cupsd.conf file */ *value; /* Value on line */ int linenum, /* Line number in file */ in_location, /* In a location section? */ in_policy, /* In a policy section? */ in_default_policy, /* In the default policy section? */ in_cancel_job, /* In a cancel-job section? */ in_admin_location, /* In the /admin location? */ in_conf_location, /* In the /admin/conf location? */ in_log_location, /* In the /admin/log location? */ in_root_location; /* In the / location? */ const char *val; /* Setting value */ int share_printers, /* Share local printers */ remote_admin, /* Remote administration allowed? */ remote_any, /* Remote access from anywhere? */ user_cancel_any, /* Cancel-job policy set? */ debug_logging; /* LogLevel debug set? */ int wrote_port_listen, /* Wrote the port/listen lines? */ wrote_browsing, /* Wrote the browsing lines? */ wrote_policy, /* Wrote the policy? */ wrote_loglevel, /* Wrote the LogLevel line? */ wrote_admin_location, /* Wrote the /admin location? */ wrote_conf_location, /* Wrote the /admin/conf location? */ wrote_log_location, /* Wrote the /admin/log location? */ wrote_root_location; /* Wrote the / location? */ int indent; /* Indentation */ int cupsd_num_settings; /* New number of settings */ int old_share_printers, /* Share local printers */ old_remote_admin, /* Remote administration allowed? */ old_remote_any, /* Remote access from anywhere? */ old_user_cancel_any, /* Cancel-job policy set? */ old_debug_logging; /* LogLevel debug set? */ cups_option_t *cupsd_settings, /* New settings */ *setting; /* Current setting */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ /* * Range check input... */ if (!http) http = _cupsConnect(); if (!http || !num_settings || !settings) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } /* * Get the cupsd.conf file... */ if (get_cupsd_conf(http, cg, 0, cupsdconf, sizeof(cupsdconf), &remote) == HTTP_STATUS_OK) { if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0); return (0); } } else return (0); /* * Get current settings... */ if (!cupsAdminGetServerSettings(http, &cupsd_num_settings, &cupsd_settings)) return (0); if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, cupsd_num_settings, cupsd_settings)) != NULL) old_debug_logging = atoi(val); else old_debug_logging = 0; DEBUG_printf(("1cupsAdminSetServerSettings: old debug_logging=%d", old_debug_logging)); if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, cupsd_num_settings, cupsd_settings)) != NULL) old_remote_admin = atoi(val); else old_remote_admin = 0; DEBUG_printf(("1cupsAdminSetServerSettings: old remote_admin=%d", old_remote_admin)); if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, cupsd_num_settings, cupsd_settings)) != NULL) old_remote_any = atoi(val); else old_remote_any = 0; DEBUG_printf(("1cupsAdminSetServerSettings: old remote_any=%d", old_remote_any)); if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, cupsd_num_settings, cupsd_settings)) != NULL) old_share_printers = atoi(val); else old_share_printers = 0; DEBUG_printf(("1cupsAdminSetServerSettings: old share_printers=%d", old_share_printers)); if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, cupsd_num_settings, cupsd_settings)) != NULL) old_user_cancel_any = atoi(val); else old_user_cancel_any = 0; DEBUG_printf(("1cupsAdminSetServerSettings: old user_cancel_any=%d", old_user_cancel_any)); cupsFreeOptions(cupsd_num_settings, cupsd_settings); /* * Get basic settings... */ if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings, settings)) != NULL) { debug_logging = atoi(val); if (debug_logging == old_debug_logging) { /* * No change to this setting... */ debug_logging = -1; } } else debug_logging = -1; DEBUG_printf(("1cupsAdminSetServerSettings: debug_logging=%d", debug_logging)); if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings, settings)) != NULL) { remote_any = atoi(val); if (remote_any == old_remote_any) { /* * No change to this setting... */ remote_any = -1; } } else remote_any = -1; DEBUG_printf(("1cupsAdminSetServerSettings: remote_any=%d", remote_any)); if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings, settings)) != NULL) { remote_admin = atoi(val); if (remote_admin == old_remote_admin) { /* * No change to this setting... */ remote_admin = -1; } } else remote_admin = -1; DEBUG_printf(("1cupsAdminSetServerSettings: remote_admin=%d", remote_admin)); if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings, settings)) != NULL) { share_printers = atoi(val); if (share_printers == old_share_printers) { /* * No change to this setting... */ share_printers = -1; } } else share_printers = -1; DEBUG_printf(("1cupsAdminSetServerSettings: share_printers=%d", share_printers)); if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings, settings)) != NULL) { user_cancel_any = atoi(val); if (user_cancel_any == old_user_cancel_any) { /* * No change to this setting... */ user_cancel_any = -1; } } else user_cancel_any = -1; DEBUG_printf(("1cupsAdminSetServerSettings: user_cancel_any=%d", user_cancel_any)); /* * Create a temporary file for the new cupsd.conf file... */ if ((temp = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL) { cupsFileClose(cupsd); if (remote) unlink(cupsdconf); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0); return (0); } /* * Copy the old file to the new, making changes along the way... */ cupsd_num_settings = 0; in_admin_location = 0; in_cancel_job = 0; in_conf_location = 0; in_default_policy = 0; in_location = 0; in_log_location = 0; in_policy = 0; in_root_location = 0; linenum = 0; wrote_admin_location = 0; wrote_browsing = 0; wrote_conf_location = 0; wrote_log_location = 0; wrote_loglevel = 0; wrote_policy = 0; wrote_port_listen = 0; wrote_root_location = 0; indent = 0; if ((server_port_env = getenv("SERVER_PORT")) != NULL) { if ((server_port = atoi(server_port_env)) <= 0) server_port = ippPort(); } else server_port = ippPort(); if (server_port <= 0) server_port = IPP_PORT; while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum)) { if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")) && (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0)) { if (!wrote_port_listen) { wrote_port_listen = 1; if (remote_admin > 0 || remote_any > 0 || share_printers > 0) { cupsFilePuts(temp, "# Allow remote access\n"); cupsFilePrintf(temp, "Port %d\n", server_port); } else { cupsFilePuts(temp, "# Only listen for connections from the local " "machine.\n"); cupsFilePrintf(temp, "Listen localhost:%d\n", server_port); } #ifdef CUPS_DEFAULT_DOMAINSOCKET if ((!value || strcmp(CUPS_DEFAULT_DOMAINSOCKET, value)) && !access(CUPS_DEFAULT_DOMAINSOCKET, 0)) cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n"); #endif /* CUPS_DEFAULT_DOMAINSOCKET */ } else if (value && value[0] == '/' #ifdef CUPS_DEFAULT_DOMAINSOCKET && strcmp(CUPS_DEFAULT_DOMAINSOCKET, value) #endif /* CUPS_DEFAULT_DOMAINSOCKET */ ) cupsFilePrintf(temp, "Listen %s\n", value); } else if ((!_cups_strcasecmp(line, "Browsing") || !_cups_strcasecmp(line, "BrowseLocalProtocols")) && share_printers >= 0) { if (!wrote_browsing) { int new_share_printers = (share_printers > 0 || (share_printers == -1 && old_share_printers > 0)); wrote_browsing = 1; if (new_share_printers) { const char *localp = cupsGetOption("BrowseLocalProtocols", num_settings, settings); if (!localp || !localp[0]) localp = cupsGetOption("BrowseLocalProtocols", cupsd_num_settings, cupsd_settings); cupsFilePuts(temp, "# Share local printers on the local network.\n"); cupsFilePuts(temp, "Browsing On\n"); if (!localp) localp = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS; cupsFilePrintf(temp, "BrowseLocalProtocols %s\n", localp); cupsd_num_settings = cupsAddOption("BrowseLocalProtocols", localp, cupsd_num_settings, &cupsd_settings); } else { cupsFilePuts(temp, "# Disable printer sharing.\n"); cupsFilePuts(temp, "Browsing Off\n"); } } } else if (!_cups_strcasecmp(line, "LogLevel") && debug_logging >= 0) { wrote_loglevel = 1; if (debug_logging) { cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n"); cupsFilePuts(temp, "LogLevel debug\n"); } else { cupsFilePuts(temp, "# Show general information in error_log.\n"); cupsFilePuts(temp, "LogLevel " CUPS_DEFAULT_LOG_LEVEL "\n"); } } else if (!_cups_strcasecmp(line, "<Policy")) { in_default_policy = !_cups_strcasecmp(value, "default"); in_policy = 1; cupsFilePrintf(temp, "%s %s>\n", line, value); indent += 2; } else if (!_cups_strcasecmp(line, "</Policy>")) { indent -= 2; if (!wrote_policy && in_default_policy) { wrote_policy = 1; if (!user_cancel_any) cupsFilePuts(temp, " # Only the owner or an administrator can " "cancel a job...\n" " <Limit Cancel-Job>\n" " Order deny,allow\n" " Require user @OWNER " CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n" " </Limit>\n"); } in_policy = 0; in_default_policy = 0; cupsFilePuts(temp, "</Policy>\n"); } else if (!_cups_strcasecmp(line, "<Location")) { in_location = 1; indent += 2; if (!strcmp(value, "/admin")) in_admin_location = 1; else if (!strcmp(value, "/admin/conf")) in_conf_location = 1; else if (!strcmp(value, "/admin/log")) in_log_location = 1; else if (!strcmp(value, "/")) in_root_location = 1; cupsFilePrintf(temp, "%s %s>\n", line, value); } else if (!_cups_strcasecmp(line, "</Location>")) { in_location = 0; indent -= 2; if (in_admin_location && remote_admin >= 0) { wrote_admin_location = 1; if (remote_admin) cupsFilePuts(temp, " # Allow remote administration...\n"); else if (remote_admin == 0) cupsFilePuts(temp, " # Restrict access to the admin pages...\n"); cupsFilePuts(temp, " Order allow,deny\n"); if (remote_admin) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); } else if (in_conf_location && remote_admin >= 0) { wrote_conf_location = 1; if (remote_admin) cupsFilePuts(temp, " # Allow remote access to the configuration " "files...\n"); else cupsFilePuts(temp, " # Restrict access to the configuration " "files...\n"); cupsFilePuts(temp, " Order allow,deny\n"); if (remote_admin) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); } else if (in_log_location && remote_admin >= 0) { wrote_log_location = 1; if (remote_admin) cupsFilePuts(temp, " # Allow remote access to the log " "files...\n"); else cupsFilePuts(temp, " # Restrict access to the log " "files...\n"); cupsFilePuts(temp, " Order allow,deny\n"); if (remote_admin) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); } else if (in_root_location && (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0)) { wrote_root_location = 1; if (remote_admin > 0 && share_printers > 0) cupsFilePuts(temp, " # Allow shared printing and remote " "administration...\n"); else if (remote_admin > 0) cupsFilePuts(temp, " # Allow remote administration...\n"); else if (share_printers > 0) cupsFilePuts(temp, " # Allow shared printing...\n"); else if (remote_any > 0) cupsFilePuts(temp, " # Allow remote access...\n"); else cupsFilePuts(temp, " # Restrict access to the server...\n"); cupsFilePuts(temp, " Order allow,deny\n"); if (remote_admin > 0 || remote_any > 0 || share_printers > 0) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); } in_admin_location = 0; in_conf_location = 0; in_log_location = 0; in_root_location = 0; cupsFilePuts(temp, "</Location>\n"); } else if (!_cups_strcasecmp(line, "<Limit")) { if (in_default_policy) { /* * See if the policy limit is for the Cancel-Job operation... */ char *valptr; /* Pointer into value */ if (!_cups_strcasecmp(value, "cancel-job") && user_cancel_any >= 0) { /* * Don't write anything for this limit section... */ in_cancel_job = 2; } else { cupsFilePrintf(temp, "%*s%s", indent, "", line); while (*value) { for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++); if (*valptr) *valptr++ = '\0'; if (!_cups_strcasecmp(value, "cancel-job") && user_cancel_any >= 0) { /* * Write everything except for this definition... */ in_cancel_job = 1; } else cupsFilePrintf(temp, " %s", value); for (value = valptr; _cups_isspace(*value); value ++); } cupsFilePuts(temp, ">\n"); } } else cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value); indent += 2; } else if (!_cups_strcasecmp(line, "</Limit>") && in_cancel_job) { indent -= 2; if (in_cancel_job == 1) cupsFilePuts(temp, " </Limit>\n"); wrote_policy = 1; if (!user_cancel_any) cupsFilePuts(temp, " # Only the owner or an administrator can cancel " "a job...\n" " <Limit Cancel-Job>\n" " Order deny,allow\n" " Require user @OWNER " CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n" " </Limit>\n"); in_cancel_job = 0; } else if ((((in_admin_location || in_conf_location || in_root_location) && (remote_admin >= 0 || remote_any >= 0)) || (in_root_location && share_printers >= 0)) && (!_cups_strcasecmp(line, "Allow") || !_cups_strcasecmp(line, "Deny") || !_cups_strcasecmp(line, "Order"))) continue; else if (in_cancel_job == 2) continue; else if (line[0] == '<') { if (value) { cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value); indent += 2; } else { if (line[1] == '/') indent -= 2; cupsFilePrintf(temp, "%*s%s\n", indent, "", line); } } else if (!in_policy && !in_location && (val = cupsGetOption(line, num_settings, settings)) != NULL) { /* * Replace this directive's value with the new one... */ cupsd_num_settings = cupsAddOption(line, val, cupsd_num_settings, &cupsd_settings); /* * Write the new value in its place, without indentation since we * only support setting root directives, not in sections... */ cupsFilePrintf(temp, "%s %s\n", line, val); } else if (value) { if (!in_policy && !in_location) { /* * Record the non-policy, non-location directives that we find * in the server settings, since we cache this info and record it * in cupsAdminGetServerSettings()... */ cupsd_num_settings = cupsAddOption(line, value, cupsd_num_settings, &cupsd_settings); } cupsFilePrintf(temp, "%*s%s %s\n", indent, "", line, value); } else cupsFilePrintf(temp, "%*s%s\n", indent, "", line); } /* * Write any missing info... */ if (!wrote_browsing && share_printers >= 0) { if (share_printers > 0) { cupsFilePuts(temp, "# Share local printers on the local network.\n"); cupsFilePuts(temp, "Browsing On\n"); } else { cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n"); cupsFilePuts(temp, "Browsing Off\n"); } } if (!wrote_loglevel && debug_logging >= 0) { if (debug_logging) { cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n"); cupsFilePuts(temp, "LogLevel debug\n"); } else { cupsFilePuts(temp, "# Show general information in error_log.\n"); cupsFilePuts(temp, "LogLevel " CUPS_DEFAULT_LOG_LEVEL "\n"); } } if (!wrote_port_listen && (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0)) { if (remote_admin > 0 || remote_any > 0 || share_printers > 0) { cupsFilePuts(temp, "# Allow remote access\n"); cupsFilePrintf(temp, "Port %d\n", ippPort()); } else { cupsFilePuts(temp, "# Only listen for connections from the local machine.\n"); cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort()); } #ifdef CUPS_DEFAULT_DOMAINSOCKET if (!access(CUPS_DEFAULT_DOMAINSOCKET, 0)) cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n"); #endif /* CUPS_DEFAULT_DOMAINSOCKET */ } if (!wrote_root_location && (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0)) { if (remote_admin > 0 && share_printers > 0) cupsFilePuts(temp, "# Allow shared printing and remote administration...\n"); else if (remote_admin > 0) cupsFilePuts(temp, "# Allow remote administration...\n"); else if (share_printers > 0) cupsFilePuts(temp, "# Allow shared printing...\n"); else if (remote_any > 0) cupsFilePuts(temp, "# Allow remote access...\n"); else cupsFilePuts(temp, "# Restrict access to the server...\n"); cupsFilePuts(temp, "<Location />\n" " Order allow,deny\n"); if (remote_admin > 0 || remote_any > 0 || share_printers > 0) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); cupsFilePuts(temp, "</Location>\n"); } if (!wrote_admin_location && remote_admin >= 0) { if (remote_admin) cupsFilePuts(temp, "# Allow remote administration...\n"); else cupsFilePuts(temp, "# Restrict access to the admin pages...\n"); cupsFilePuts(temp, "<Location /admin>\n" " Order allow,deny\n"); if (remote_admin) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); cupsFilePuts(temp, "</Location>\n"); } if (!wrote_conf_location && remote_admin >= 0) { if (remote_admin) cupsFilePuts(temp, "# Allow remote access to the configuration files...\n"); else cupsFilePuts(temp, "# Restrict access to the configuration files...\n"); cupsFilePuts(temp, "<Location /admin/conf>\n" " AuthType Default\n" " Require user @SYSTEM\n" " Order allow,deny\n"); if (remote_admin) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); cupsFilePuts(temp, "</Location>\n"); } if (!wrote_log_location && remote_admin >= 0) { if (remote_admin) cupsFilePuts(temp, "# Allow remote access to the log files...\n"); else cupsFilePuts(temp, "# Restrict access to the log files...\n"); cupsFilePuts(temp, "<Location /admin/log>\n" " AuthType Default\n" " Require user @SYSTEM\n" " Order allow,deny\n"); if (remote_admin) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); cupsFilePuts(temp, "</Location>\n"); } if (!wrote_policy && user_cancel_any >= 0) { cupsFilePuts(temp, "<Policy default>\n" " # Job-related operations must be done by the owner " "or an administrator...\n" " <Limit Send-Document Send-URI Hold-Job Release-Job " "Restart-Job Purge-Jobs Set-Job-Attributes " "Create-Job-Subscription Renew-Subscription " "Cancel-Subscription Get-Notifications Reprocess-Job " "Cancel-Current-Job Suspend-Current-Job Resume-Job " "CUPS-Move-Job>\n" " Require user @OWNER @SYSTEM\n" " Order deny,allow\n" " </Limit>\n" " # All administration operations require an " "administrator to authenticate...\n" " <Limit Pause-Printer Resume-Printer " "Set-Printer-Attributes Enable-Printer " "Disable-Printer Pause-Printer-After-Current-Job " "Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer " "Activate-Printer Restart-Printer Shutdown-Printer " "Startup-Printer Promote-Job Schedule-Job-After " "CUPS-Add-Printer CUPS-Delete-Printer " "CUPS-Add-Class CUPS-Delete-Class " "CUPS-Accept-Jobs CUPS-Reject-Jobs " "CUPS-Set-Default CUPS-Add-Device CUPS-Delete-Device>\n" " AuthType Default\n" " Require user @SYSTEM\n" " Order deny,allow\n" "</Limit>\n"); if (!user_cancel_any) cupsFilePuts(temp, " # Only the owner or an administrator can cancel " "a job...\n" " <Limit Cancel-Job>\n" " Order deny,allow\n" " Require user @OWNER " CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n" " </Limit>\n"); cupsFilePuts(temp, " <Limit All>\n" " Order deny,allow\n" " </Limit>\n" "</Policy>\n"); } for (i = num_settings, setting = settings; i > 0; i --, setting ++) if (setting->name[0] != '_' && _cups_strcasecmp(setting->name, "Listen") && _cups_strcasecmp(setting->name, "Port") && !cupsGetOption(setting->name, cupsd_num_settings, cupsd_settings)) { /* * Add this directive to the list of directives we have written... */ cupsd_num_settings = cupsAddOption(setting->name, setting->value, cupsd_num_settings, &cupsd_settings); /* * Write the new value, without indentation since we only support * setting root directives, not in sections... */ cupsFilePrintf(temp, "%s %s\n", setting->name, setting->value); } cupsFileClose(cupsd); cupsFileClose(temp); /* * Upload the configuration file to the server... */ status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile); if (status == HTTP_STATUS_CREATED) { /* * Updated OK, add the basic settings... */ if (debug_logging >= 0) cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, debug_logging ? "1" : "0", cupsd_num_settings, &cupsd_settings); else cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, old_debug_logging ? "1" : "0", cupsd_num_settings, &cupsd_settings); if (remote_admin >= 0) cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, remote_admin ? "1" : "0", cupsd_num_settings, &cupsd_settings); else cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, old_remote_admin ? "1" : "0", cupsd_num_settings, &cupsd_settings); if (remote_any >= 0) cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY, remote_any ? "1" : "0", cupsd_num_settings, &cupsd_settings); else cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY, old_remote_any ? "1" : "0", cupsd_num_settings, &cupsd_settings); if (share_printers >= 0) cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, share_printers ? "1" : "0", cupsd_num_settings, &cupsd_settings); else cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, old_share_printers ? "1" : "0", cupsd_num_settings, &cupsd_settings); if (user_cancel_any >= 0) cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, user_cancel_any ? "1" : "0", cupsd_num_settings, &cupsd_settings); else cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, old_user_cancel_any ? "1" : "0", cupsd_num_settings, &cupsd_settings); /* * Save the new values... */ invalidate_cupsd_cache(cg); cg->cupsd_num_settings = cupsd_num_settings; cg->cupsd_settings = cupsd_settings; cg->cupsd_update = time(NULL); httpGetHostname(http, cg->cupsd_hostname, sizeof(cg->cupsd_hostname)); } else cupsFreeOptions(cupsd_num_settings, cupsd_settings); /* * Remote our temp files and return... */ if (remote) unlink(cupsdconf); unlink(tempfile); return (status == HTTP_STATUS_CREATED); }
static void add_printer_filter( const char *command, /* I - Command name */ mime_t *mime, /* I - MIME database */ mime_type_t *filtertype, /* I - Printer or prefilter MIME type */ const char *filter) /* I - Filter to add */ { char super[MIME_MAX_SUPER], /* Super-type for filter */ type[MIME_MAX_TYPE], /* Type for filter */ dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */ dtype[MIME_MAX_TYPE], /* Destination type for filter */ dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2], /* Destination super/type */ program[1024]; /* Program/filter name */ int cost; /* Cost of filter */ size_t maxsize = 0; /* Maximum supported file size */ mime_type_t *temptype, /* MIME type looping var */ *desttype; /* Destination MIME type */ mime_filter_t *filterptr; /* MIME filter */ /* * Parse the filter string; it should be in one of the following formats: * * source/type cost program * source/type cost maxsize(nnnn) program * source/type dest/type cost program * source/type dest/type cost maxsize(nnnn) program */ if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, dsuper, dtype, &cost, program) == 6) { snprintf(dest, sizeof(dest), "%s/%s/%s", filtertype->type, dsuper, dtype); if ((desttype = mimeType(mime, "printer", dest)) == NULL) desttype = mimeAddType(mime, "printer", dest); } else { if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost, program) == 4) { desttype = filtertype; } else { _cupsLangPrintf(stderr, _("%s: Invalid filter string \"%s\"."), command, filter); return; } } if (!strncmp(program, "maxsize(", 8)) { char *ptr; /* Pointer into maxsize(nnnn) program */ maxsize = (size_t)strtoll(program + 8, &ptr, 10); if (*ptr != ')') { printf("testmime: Invalid filter string \"%s\".\n", filter); return; } ptr ++; while (_cups_isspace(*ptr)) ptr ++; _cups_strcpy(program, ptr); } /* * See if the filter program exists; if not, stop the printer and flag * the error! */ if (strcmp(program, "-")) { char filename[1024]; /* Full path to program */ if (program[0] == '/') strlcpy(filename, program, sizeof(filename)); else snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program); if (_cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !geteuid(), check_cb, (void *)command)) return; } /* * Add the filter to the MIME database, supporting wildcards as needed... */ for (temptype = mimeFirstType(mime); temptype; temptype = mimeNextType(mime)) if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) || !_cups_strcasecmp(temptype->super, super)) && (type[0] == '*' || !_cups_strcasecmp(temptype->type, type))) { if (desttype != filtertype) { filterptr = mimeAddFilter(mime, temptype, desttype, cost, program); if (!mimeFilterLookup(mime, desttype, filtertype)) mimeAddFilter(mime, desttype, filtertype, 0, "-"); } else filterptr = mimeAddFilter(mime, temptype, filtertype, cost, program); if (filterptr) filterptr->maxsize = maxsize; } }
int /* O - 0 on success, -1 on failure */ backendGetDeviceID( int fd, /* I - File descriptor */ char *device_id, /* O - 1284 device ID */ int device_id_size, /* I - Size of buffer */ char *make_model, /* O - Make/model */ int make_model_size, /* I - Size of buffer */ const char *scheme, /* I - URI scheme */ char *uri, /* O - Device URI */ int uri_size) /* I - Size of buffer */ { #ifdef __APPLE__ /* This function is a no-op */ (void)fd; (void)device_id; (void)device_id_size; (void)make_model; (void)make_model_size; (void)scheme; (void)uri; (void)uri_size; return (-1); #else /* Get the device ID from the specified file descriptor... */ # ifdef __linux int length; /* Length of device ID info */ int got_id = 0; # endif /* __linux */ # if defined(__sun) && defined(ECPPIOC_GETDEVID) struct ecpp_device_id did; /* Device ID buffer */ # endif /* __sun && ECPPIOC_GETDEVID */ char *ptr; /* Pointer into device ID */ DEBUG_printf(("backendGetDeviceID(fd=%d, device_id=%p, device_id_size=%d, " "make_model=%p, make_model_size=%d, scheme=\"%s\", " "uri=%p, uri_size=%d)\n", fd, device_id, device_id_size, make_model, make_model_size, scheme ? scheme : "(null)", uri, uri_size)); /* * Range check input... */ if (!device_id || device_id_size < 32) { DEBUG_puts("backendGetDeviceID: Bad args!"); return (-1); } if (make_model) *make_model = '\0'; if (fd >= 0) { /* * Get the device ID string... */ *device_id = '\0'; # ifdef __linux if (ioctl(fd, LPIOC_GET_DEVICE_ID(device_id_size), device_id)) { /* * Linux has to implement things differently for every device it seems. * Since the standard parallel port driver does not provide a simple * ioctl() to get the 1284 device ID, we have to open the "raw" parallel * device corresponding to this port and do some negotiation trickery * to get the current device ID. */ if (uri && !strncmp(uri, "parallel:/dev/", 14)) { char devparport[16]; /* /dev/parportN */ int devparportfd, /* File descriptor for raw device */ mode; /* Port mode */ /* * Since the Linux parallel backend only supports 4 parallel port * devices, just grab the trailing digit and use it to construct a * /dev/parportN filename... */ snprintf(devparport, sizeof(devparport), "/dev/parport%s", uri + strlen(uri) - 1); if ((devparportfd = open(devparport, O_RDWR | O_NOCTTY)) != -1) { /* * Claim the device... */ if (!ioctl(devparportfd, PPCLAIM)) { fcntl(devparportfd, F_SETFL, fcntl(devparportfd, F_GETFL) | O_NONBLOCK); mode = IEEE1284_MODE_COMPAT; if (!ioctl(devparportfd, PPNEGOT, &mode)) { /* * Put the device into Device ID mode... */ mode = IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID; if (!ioctl(devparportfd, PPNEGOT, &mode)) { /* * Read the 1284 device ID... */ if ((length = read(devparportfd, device_id, (size_t)device_id_size - 1)) >= 2) { device_id[length] = '\0'; got_id = 1; } } } /* * Release the device... */ ioctl(devparportfd, PPRELEASE); } close(devparportfd); } } } else got_id = 1; if (got_id) { /* * Extract the length of the device ID string from the first two * bytes. The 1284 spec says the length is stored MSB first... */ length = (int)((((unsigned)device_id[0] & 255) << 8) + ((unsigned)device_id[1] & 255)); /* * Check to see if the length is larger than our buffer; first * assume that the vendor incorrectly implemented the 1284 spec, * and then limit the length to the size of our buffer... */ if (length > device_id_size || length < 14) length = (int)((((unsigned)device_id[1] & 255) << 8) + ((unsigned)device_id[0] & 255)); if (length > device_id_size) length = device_id_size; /* * The length field counts the number of bytes in the string * including the length field itself (2 bytes). The minimum * length for a valid/usable device ID is 14 bytes: * * <LENGTH> MFG: <MFG> ;MDL: <MDL> ; * 2 + 4 + 1 + 5 + 1 + 1 */ if (length < 14) { /* * Can't use this device ID, so don't try to copy it... */ device_id[0] = '\0'; got_id = 0; } else { /* * Copy the device ID text to the beginning of the buffer and * nul-terminate. */ length -= 2; memmove(device_id, device_id + 2, (size_t)length); device_id[length] = '\0'; } } else { DEBUG_printf(("backendGetDeviceID: ioctl failed - %s\n", strerror(errno))); *device_id = '\0'; } # endif /* __linux */ # if defined(__sun) && defined(ECPPIOC_GETDEVID) did.mode = ECPP_CENTRONICS; did.len = device_id_size - 1; did.rlen = 0; did.addr = device_id; if (!ioctl(fd, ECPPIOC_GETDEVID, &did)) { /* * Nul-terminate the device ID text. */ if (did.rlen < (device_id_size - 1)) device_id[did.rlen] = '\0'; else device_id[device_id_size - 1] = '\0'; } # ifdef DEBUG else DEBUG_printf(("backendGetDeviceID: ioctl failed - %s\n", strerror(errno))); # endif /* DEBUG */ # endif /* __sun && ECPPIOC_GETDEVID */ } /* * Check whether device ID is valid. Turn line breaks and tabs to spaces and * reject device IDs with non-printable characters. */ for (ptr = device_id; *ptr; ptr ++) if (_cups_isspace(*ptr)) *ptr = ' '; else if ((*ptr & 255) < ' ' || *ptr == 127) { DEBUG_printf(("backendGetDeviceID: Bad device_id character %d.", *ptr & 255)); *device_id = '\0'; break; } DEBUG_printf(("backendGetDeviceID: device_id=\"%s\"\n", device_id)); if (scheme && uri) *uri = '\0'; if (!*device_id) return (-1); /* * Get the make and model... */ if (make_model) backendGetMakeModel(device_id, make_model, (size_t)make_model_size); /* * Then generate a device URI... */ if (scheme && uri && uri_size > 32) { int num_values; /* Number of keys and values */ cups_option_t *values; /* Keys and values in device ID */ const char *mfg, /* Manufacturer */ *mdl, /* Model */ *sern; /* Serial number */ char temp[256], /* Temporary manufacturer string */ *tempptr; /* Pointer into temp string */ /* * Get the make, model, and serial numbers... */ num_values = _cupsGet1284Values(device_id, &values); if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL) if ((sern = cupsGetOption("SERN", num_values, values)) == NULL) sern = cupsGetOption("SN", num_values, values); if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL) mfg = cupsGetOption("MFG", num_values, values); if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL) mdl = cupsGetOption("MDL", num_values, values); if (mfg) { if (!_cups_strcasecmp(mfg, "Hewlett-Packard")) mfg = "HP"; else if (!_cups_strcasecmp(mfg, "Lexmark International")) mfg = "Lexmark"; } else { strlcpy(temp, make_model, sizeof(temp)); if ((tempptr = strchr(temp, ' ')) != NULL) *tempptr = '\0'; mfg = temp; } if (!mdl) mdl = ""; if (!_cups_strncasecmp(mdl, mfg, strlen(mfg))) { mdl += strlen(mfg); while (isspace(*mdl & 255)) mdl ++; } /* * Generate the device URI from the manufacturer, make_model, and * serial number strings. */ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, uri_size, scheme, NULL, mfg, 0, "/%s%s%s", mdl, sern ? "?serial=" : "", sern ? sern : ""); cupsFreeOptions(num_values, values); } return (0); #endif /* __APPLE__ */ }
int /* O - Number of key/value pairs */ _cupsGet1284Values( const char *device_id, /* I - IEEE-1284 device ID string */ cups_option_t **values) /* O - Array of key/value pairs */ { int num_values; /* Number of values */ char key[256], /* Key string */ value[256], /* Value string */ *ptr; /* Pointer into key/value */ /* * Range check input... */ if (values) *values = NULL; if (!device_id || !values) return (0); /* * Parse the 1284 device ID value into keys and values. The format is * repeating sequences of: * * [whitespace]key:value[whitespace]; */ num_values = 0; while (*device_id) { while (_cups_isspace(*device_id)) device_id ++; if (!*device_id) break; for (ptr = key; *device_id && *device_id != ':'; device_id ++) if (ptr < (key + sizeof(key) - 1)) *ptr++ = *device_id; if (!*device_id) break; while (ptr > key && _cups_isspace(ptr[-1])) ptr --; *ptr = '\0'; device_id ++; while (_cups_isspace(*device_id)) device_id ++; if (!*device_id) break; for (ptr = value; *device_id && *device_id != ';'; device_id ++) if (ptr < (value + sizeof(value) - 1)) *ptr++ = *device_id; if (!*device_id) break; while (ptr > value && _cups_isspace(ptr[-1])) ptr --; *ptr = '\0'; device_id ++; num_values = cupsAddOption(key, value, num_values, values); } return (num_values); }
const char * /* O - Value or NULL if not found */ ppdLocalizeIPPReason( ppd_file_t *ppd, /* I - PPD file */ const char *reason, /* I - IPP reason keyword to look up */ const char *scheme, /* I - URI scheme or NULL for text */ char *buffer, /* I - Value buffer */ size_t bufsize) /* I - Size of value buffer */ { cups_lang_t *lang; /* Current language */ ppd_attr_t *locattr; /* Localized attribute */ char ll_CC[6], /* Language + country locale */ *bufptr, /* Pointer into buffer */ *bufend, /* Pointer to end of buffer */ *valptr; /* Pointer into value */ int ch; /* Hex-encoded character */ size_t schemelen; /* Length of scheme name */ /* * Range check input... */ if (buffer) *buffer = '\0'; if (!ppd || !reason || (scheme && !*scheme) || !buffer || bufsize < PPD_MAX_TEXT) return (NULL); /* * Get the default language... */ lang = ppd_ll_CC(ll_CC, sizeof(ll_CC)); /* * Find the localized attribute... */ if ((locattr = _ppdLocalizedAttr(ppd, "cupsIPPReason", reason, ll_CC)) == NULL) locattr = ppdFindAttr(ppd, "cupsIPPReason", reason); if (!locattr) { if (lang && (!scheme || !strcmp(scheme, "text"))) { /* * Try to localize a standard printer-state-reason keyword... */ const char *message = NULL; /* Localized message */ if (!strncmp(reason, "media-needed", 12)) message = _("Load paper."); else if (!strncmp(reason, "media-jam", 9)) message = _("Paper jam."); else if (!strncmp(reason, "offline", 7) || !strncmp(reason, "shutdown", 8)) message = _("The printer is not connected."); else if (!strncmp(reason, "toner-low", 9)) message = _("The printer is low on toner."); else if (!strncmp(reason, "toner-empty", 11)) message = _("The printer may be out of toner."); else if (!strncmp(reason, "cover-open", 10)) message = _("The printer's cover is open."); else if (!strncmp(reason, "interlock-open", 14)) message = _("The printer's interlock is open."); else if (!strncmp(reason, "door-open", 9)) message = _("The printer's door is open."); else if (!strncmp(reason, "input-tray-missing", 18)) message = _("Paper tray is missing."); else if (!strncmp(reason, "media-low", 9)) message = _("Paper tray is almost empty."); else if (!strncmp(reason, "media-empty", 11)) message = _("Paper tray is empty."); else if (!strncmp(reason, "output-tray-missing", 19)) message = _("Output bin is missing."); else if (!strncmp(reason, "output-area-almost-full", 23)) message = _("Output bin is almost full."); else if (!strncmp(reason, "output-area-full", 16)) message = _("Output bin is full."); else if (!strncmp(reason, "marker-supply-low", 17)) message = _("The printer is low on ink."); else if (!strncmp(reason, "marker-supply-empty", 19)) message = _("The printer may be out of ink."); else if (!strncmp(reason, "marker-waste-almost-full", 24)) message = _("The printer's waste bin is almost full."); else if (!strncmp(reason, "marker-waste-full", 17)) message = _("The printer's waste bin is full."); else if (!strncmp(reason, "fuser-over-temp", 15)) message = _("The fuser's temperature is high."); else if (!strncmp(reason, "fuser-under-temp", 16)) message = _("The fuser's temperature is low."); else if (!strncmp(reason, "opc-near-eol", 12)) message = _("The optical photoconductor will need to be replaced soon."); else if (!strncmp(reason, "opc-life-over", 13)) message = _("The optical photoconductor needs to be replaced."); else if (!strncmp(reason, "developer-low", 13)) message = _("The developer unit will need to be replaced soon."); else if (!strncmp(reason, "developer-empty", 15)) message = _("The developer unit needs to be replaced."); if (message) { strlcpy(buffer, _cupsLangString(lang, message), bufsize); return (buffer); } } return (NULL); } /* * Now find the value we need... */ bufend = buffer + bufsize - 1; if (!scheme || !strcmp(scheme, "text")) { /* * Copy a text value (either the translation text or text:... URIs from * the value... */ strlcpy(buffer, locattr->text, bufsize); for (valptr = locattr->value, bufptr = buffer; *valptr && bufptr < bufend;) { if (!strncmp(valptr, "text:", 5)) { /* * Decode text: URI and add to the buffer... */ valptr += 5; while (*valptr && !_cups_isspace(*valptr) && bufptr < bufend) { if (*valptr == '%' && isxdigit(valptr[1] & 255) && isxdigit(valptr[2] & 255)) { /* * Pull a hex-encoded character from the URI... */ valptr ++; if (isdigit(*valptr & 255)) ch = (*valptr - '0') << 4; else ch = (tolower(*valptr) - 'a' + 10) << 4; valptr ++; if (isdigit(*valptr & 255)) *bufptr++ = (char)(ch | (*valptr - '0')); else *bufptr++ = (char)(ch | (tolower(*valptr) - 'a' + 10)); valptr ++; } else if (*valptr == '+') { *bufptr++ = ' '; valptr ++; } else *bufptr++ = *valptr++; } } else { /* * Skip this URI... */ while (*valptr && !_cups_isspace(*valptr)) valptr++; } /* * Skip whitespace... */ while (_cups_isspace(*valptr)) valptr ++; } if (bufptr > buffer) *bufptr = '\0'; return (buffer); } else { /* * Copy a URI... */ schemelen = strlen(scheme); if (scheme[schemelen - 1] == ':') /* Force scheme to be just the name */ schemelen --; for (valptr = locattr->value, bufptr = buffer; *valptr && bufptr < bufend;) { if ((!strncmp(valptr, scheme, schemelen) && valptr[schemelen] == ':') || (*valptr == '/' && !strcmp(scheme, "file"))) { /* * Copy URI... */ while (*valptr && !_cups_isspace(*valptr) && bufptr < bufend) *bufptr++ = *valptr++; *bufptr = '\0'; return (buffer); } else { /* * Skip this URI... */ while (*valptr && !_cups_isspace(*valptr)) valptr++; } /* * Skip whitespace... */ while (_cups_isspace(*valptr)) valptr ++; } return (NULL); } }
int /* O - 0 on success, -1 on failure */ ppdEmitJCL(ppd_file_t *ppd, /* I - PPD file record */ FILE *fp, /* I - File to write to */ int job_id, /* I - Job ID */ const char *user, /* I - Username */ const char *title) /* I - Title */ { char *ptr; /* Pointer into JCL string */ char temp[65], /* Local title string */ displaymsg[33]; /* Local display string */ /* * Range check the input... */ if (!ppd || !ppd->jcl_begin || !ppd->jcl_ps) return (0); /* * See if the printer supports HP PJL... */ if (!strncmp(ppd->jcl_begin, "\033%-12345X@", 10)) { /* * This printer uses HP PJL commands for output; filter the output * so that we only have a single "@PJL JOB" command in the header... * * To avoid bugs in the PJL implementation of certain vendors' products * (Xerox in particular), we add a dummy "@PJL" command at the beginning * of the PJL commands to initialize PJL processing. */ ppd_attr_t *charset; /* PJL charset */ ppd_attr_t *display; /* PJL display command */ if ((charset = ppdFindAttr(ppd, "cupsPJLCharset", NULL)) != NULL) { if (!charset->value || _cups_strcasecmp(charset->value, "UTF-8")) charset = NULL; } if ((display = ppdFindAttr(ppd, "cupsPJLDisplay", NULL)) != NULL) { if (!display->value) display = NULL; } fputs("\033%-12345X@PJL\n", fp); for (ptr = ppd->jcl_begin + 9; *ptr;) if (!strncmp(ptr, "@PJL JOB", 8)) { /* * Skip job command... */ for (;*ptr; ptr ++) if (*ptr == '\n') break; if (*ptr) ptr ++; } else { /* * Copy line... */ for (;*ptr; ptr ++) { putc(*ptr, fp); if (*ptr == '\n') break; } if (*ptr) ptr ++; } /* * Clean up the job title... */ if ((ptr = strrchr(title, '/')) != NULL) { /* * Only show basename of file path... */ title = ptr + 1; } if (!strncmp(title, "smbprn.", 7)) { /* * Skip leading smbprn.######## from Samba jobs... */ for (title += 7; *title && isdigit(*title & 255); title ++); while (_cups_isspace(*title)) title ++; if ((ptr = strstr(title, " - ")) != NULL) { /* * Skip application name in "Some Application - Title of job"... */ title = ptr + 3; } } /* * Replace double quotes with single quotes and UTF-8 characters with * question marks so that the title does not cause a PJL syntax error. */ strlcpy(temp, title, sizeof(temp)); for (ptr = temp; *ptr; ptr ++) if (*ptr == '\"') *ptr = '\''; else if (!charset && (*ptr & 128)) *ptr = '?'; /* * CUPS STR #3125: Long PJL JOB NAME causes problems with some printers * * Generate the display message, truncating at 32 characters + nul to avoid * issues with some printer's PJL implementations... */ snprintf(displaymsg, sizeof(displaymsg), "%d %s %s", job_id, user, temp); /* * Send PJL JOB and PJL RDYMSG commands before we enter PostScript mode... */ if (display && strcmp(display->value, "job")) fprintf(fp, "@PJL JOB NAME = \"%s\"\n", temp); else if (display && !strcmp(display->value, "rdymsg")) fprintf(fp, "@PJL RDYMSG DISPLAY = \"%s\"\n", displaymsg); else fprintf(fp, "@PJL JOB NAME = \"%s\" DISPLAY = \"%s\"\n", temp, displaymsg); /* * Replace double quotes with single quotes and UTF-8 characters with * question marks so that the user does not cause a PJL syntax error. */ strlcpy(temp, user, sizeof(temp)); for (ptr = temp; *ptr; ptr ++) if (*ptr == '\"') *ptr = '\''; else if (!charset && (*ptr & 128)) *ptr = '?'; fprintf(fp, "@PJL SET USERNAME = \"%s\"\n", temp); } else fputs(ppd->jcl_begin, fp); ppdEmit(ppd, fp, PPD_ORDER_JCL); fputs(ppd->jcl_ps, fp); return (0); }
int /* O - Number of options */ _ppdParseOptions( const char *s, /* I - String to parse */ int num_options, /* I - Number of options */ cups_option_t **options, /* IO - Options */ _ppd_parse_t which) /* I - What to parse */ { char option[PPD_MAX_NAME * 2 + 1], /* Current option/property */ choice[PPD_MAX_NAME], /* Current choice/value */ *ptr; /* Pointer into option or choice */ if (!s) return (num_options); /* * Read all of the "*Option Choice" and "property value" pairs from the * string, add them to an options array as we go... */ while (*s) { /* * Skip leading whitespace... */ while (_cups_isspace(*s)) s ++; /* * Get the option/property name... */ ptr = option; while (*s && !_cups_isspace(*s) && ptr < (option + sizeof(option) - 1)) *ptr++ = *s++; if (ptr == s || !_cups_isspace(*s)) break; *ptr = '\0'; /* * Get the choice... */ while (_cups_isspace(*s)) s ++; if (!*s) break; ptr = choice; while (*s && !_cups_isspace(*s) && ptr < (choice + sizeof(choice) - 1)) *ptr++ = *s++; if (*s && !_cups_isspace(*s)) break; *ptr = '\0'; /* * Add it to the options array... */ if (option[0] == '*' && which != _PPD_PARSE_PROPERTIES) num_options = cupsAddOption(option + 1, choice, num_options, options); else if (option[0] != '*' && which != _PPD_PARSE_OPTIONS) num_options = cupsAddOption(option, choice, num_options, options); } return (num_options); }
static void cups_set_ssl_options( _cups_client_conf_t *cc, /* I - client.conf values */ const char *value) /* I - Value */ { /* * SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyTLS1.0] [None] */ int options = _HTTP_TLS_NONE, /* SSL/TLS options */ min_version = _HTTP_TLS_1_0, /* Minimum SSL/TLS version */ max_version = _HTTP_TLS_MAX; /* Maximum SSL/TLS version */ char temp[256], /* Copy of value */ *start, /* Start of option */ *end; /* End of option */ strlcpy(temp, value, sizeof(temp)); for (start = temp; *start; start = end) { /* * Find end of keyword... */ end = start; while (*end && !_cups_isspace(*end)) end ++; if (*end) *end++ = '\0'; /* * Compare... */ if (!_cups_strcasecmp(start, "AllowRC4")) options |= _HTTP_TLS_ALLOW_RC4; else if (!_cups_strcasecmp(start, "AllowSSL3")) min_version = _HTTP_TLS_SSL3; else if (!_cups_strcasecmp(start, "AllowDH")) options |= _HTTP_TLS_ALLOW_DH; else if (!_cups_strcasecmp(start, "DenyCBC")) options |= _HTTP_TLS_DENY_CBC; else if (!_cups_strcasecmp(start, "DenyTLS1.0")) min_version = _HTTP_TLS_1_1; else if (!_cups_strcasecmp(start, "MaxTLS1.0")) max_version = _HTTP_TLS_1_0; else if (!_cups_strcasecmp(start, "MaxTLS1.1")) max_version = _HTTP_TLS_1_1; else if (!_cups_strcasecmp(start, "MaxTLS1.2")) max_version = _HTTP_TLS_1_2; else if (!_cups_strcasecmp(start, "MaxTLS1.3")) max_version = _HTTP_TLS_1_3; else if (!_cups_strcasecmp(start, "MinTLS1.0")) min_version = _HTTP_TLS_1_0; else if (!_cups_strcasecmp(start, "MinTLS1.1")) min_version = _HTTP_TLS_1_1; else if (!_cups_strcasecmp(start, "MinTLS1.2")) min_version = _HTTP_TLS_1_2; else if (!_cups_strcasecmp(start, "MinTLS1.3")) min_version = _HTTP_TLS_1_3; else if (!_cups_strcasecmp(start, "None")) options = _HTTP_TLS_NONE; } cc->ssl_options = options; cc->ssl_max_version = max_version; cc->ssl_min_version = min_version; DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x, min_version=%d, max_version=%d", (void *)cc, value, options, min_version, max_version)); }