void gencache_iterate(void (*fn)(const char* key, const char *value, time_t timeout, void* dptr), void* data, const char* keystr_pattern) { TDB_LIST_NODE *node, *first_node; TDB_DATA databuf; char *keystr = NULL, *valstr = NULL, *entry = NULL; time_t timeout = 0; /* fail completely if get null pointers passed */ SMB_ASSERT(fn && keystr_pattern); if (!gencache_init()) return; DEBUG(5, ("Searching cache keys with pattern %s\n", keystr_pattern)); node = tdb_search_keys(cache, keystr_pattern); first_node = node; while (node) { /* ensure null termination of the key string */ keystr = SMB_STRNDUP(node->node_key.dptr, node->node_key.dsize); /* * We don't use gencache_get function, because we need to iterate through * all of the entries. Validity verification is up to fn routine. */ databuf = tdb_fetch(cache, node->node_key); if (!databuf.dptr || databuf.dsize <= TIMEOUT_LEN) { SAFE_FREE(databuf.dptr); SAFE_FREE(keystr); node = node->next; continue; } entry = SMB_STRNDUP(databuf.dptr, databuf.dsize); SAFE_FREE(databuf.dptr); valstr = SMB_MALLOC(databuf.dsize - TIMEOUT_LEN); sscanf(entry, CACHE_DATA_FMT, (int*)(&timeout), valstr); DEBUG(10, ("Calling function with arguments (key = %s, value = %s, timeout = %s)\n", keystr, valstr, ctime(&timeout))); fn(keystr, valstr, timeout, data); SAFE_FREE(valstr); SAFE_FREE(entry); SAFE_FREE(keystr); node = node->next; } tdb_search_list_free(first_node); }
BOOL gencache_get(const char *keystr, char **valstr, time_t *timeout) { TDB_DATA keybuf, databuf; /* fail completely if get null pointers passed */ SMB_ASSERT(keystr); if (!gencache_init()) return False; keybuf.dptr = SMB_STRDUP(keystr); keybuf.dsize = strlen(keystr)+1; databuf = tdb_fetch(cache, keybuf); SAFE_FREE(keybuf.dptr); if (databuf.dptr && databuf.dsize > TIMEOUT_LEN) { char* entry_buf = SMB_STRNDUP(databuf.dptr, databuf.dsize); char *v; time_t t; v = SMB_MALLOC(databuf.dsize - TIMEOUT_LEN); SAFE_FREE(databuf.dptr); sscanf(entry_buf, CACHE_DATA_FMT, (int*)&t, v); SAFE_FREE(entry_buf); DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, " "timeout = %s\n", t > time(NULL) ? "valid" : "expired", keystr, v, ctime(&t))); if (valstr) *valstr = v; else SAFE_FREE(v); if (timeout) *timeout = t; return t > time(NULL); } else { SAFE_FREE(databuf.dptr); if (valstr) *valstr = NULL; if (timeout) timeout = NULL; DEBUG(10, ("Cache entry with key = %s couldn't be found\n", keystr)); return False; } }
/* insert an entry into the prefix cache. The string might not be null terminated */ static void cache_insert(const char *prefix, int length, u32 hash) { int i = hash % MANGLE_CACHE_SIZE; if (prefix_cache[i]) { free(prefix_cache[i]); } prefix_cache[i] = SMB_STRNDUP(prefix, length); prefix_cache_hashes[i] = hash; }
/* insert an entry into the prefix cache. The string might not be null terminated */ static void cache_insert(const char *prefix, int length, unsigned int hash) { char *str = SMB_STRNDUP(prefix, length); if (str == NULL) { return; } memcache_add(smbd_memcache(), MANGLE_HASH2_CACHE, data_blob_const(&hash, sizeof(hash)), data_blob_const(str, length+1)); SAFE_FREE(str); }
static void get_auth_data(const char *srv, const char *shr, char *wg, int wglen, char *un, int unlen, char *pw, int pwlen) { static char hasasked = 0; char *wgtmp, *usertmp; char tmp[128]; if(hasasked) return; hasasked = 1; if(!nonprompt && !username) { printf("Username for %s at %s [guest] ", shr, srv); if (fgets(tmp, sizeof(tmp), stdin) == NULL) { return; } if ((strlen(tmp) > 0) && (tmp[strlen(tmp)-1] == '\n')) { tmp[strlen(tmp)-1] = '\0'; } strncpy(un, tmp, unlen-1); } else if(username) strncpy(un, username, unlen-1); if(!nonprompt && !password) { char *prompt, *pass; if (asprintf(&prompt, "Password for %s at %s: ", shr, srv) == -1) { return; } pass = getpass(prompt); free(prompt); strncpy(pw, pass, pwlen-1); } else if(password) strncpy(pw, password, pwlen-1); if(workgroup)strncpy(wg, workgroup, wglen-1); wgtmp = SMB_STRNDUP(wg, wglen); usertmp = SMB_STRNDUP(un, unlen); if(!quiet)printf("Using workgroup %s, %s%s\n", wgtmp, *usertmp?"user ":"******", usertmp); free(wgtmp); free(usertmp); }
/** * Parse text representation of timeout value * * @param timeout_str string containing text representation of the timeout * @return numeric timeout of time_t type **/ static time_t parse_timeout(const char* timeout_str) { char sign = '\0', *number = NULL, unit = '\0'; int len, number_begin, number_end; time_t timeout; /* sign detection */ if (timeout_str[0] == '!' || timeout_str[0] == '+') { sign = timeout_str[0]; number_begin = 1; } else { number_begin = 0; } /* unit detection */ len = strlen(timeout_str); switch (timeout_str[len - 1]) { case 's': case 'm': case 'h': case 'd': case 'w': unit = timeout_str[len - 1]; } /* number detection */ len = (sign) ? strlen(&timeout_str[number_begin]) : len; number_end = (unit) ? len - 1 : len; number = SMB_STRNDUP(&timeout_str[number_begin], number_end); /* calculate actual timeout value */ timeout = (time_t)atoi(number); switch (unit) { case 'm': timeout *= 60; break; case 'h': timeout *= 60*60; break; case 'd': timeout *= 60*60*24; break; case 'w': timeout *= 60*60*24*7; break; /* that's fair enough, I think :) */ } switch (sign) { case '!': timeout = time(NULL) - timeout; break; case '+': default: timeout += time(NULL); break; } if (number) SAFE_FREE(number); return timeout; }
static bool set_my_netbios_names(const char *name, int i) { SAFE_FREE(smb_my_netbios_names[i]); /* * Don't include space for terminating '\0' in strndup, * it is automatically added. This screws up if the name * is greater than MAX_NETBIOSNAME_LEN-1 in the unix * charset, but less than or equal to MAX_NETBIOSNAME_LEN-1 * in the DOS charset, but this is so old we have to live * with that. */ smb_my_netbios_names[i] = SMB_STRNDUP(name, MAX_NETBIOSNAME_LEN-1); if (!smb_my_netbios_names[i]) return False; return strupper_m(smb_my_netbios_names[i]); }
static void print_progress(const char *name, time_t start, time_t now, off_t start_pos, off_t pos, off_t total) { double avg = 0.0; long eta = -1; double prcnt = 0.0; char hpos[20], htotal[20], havg[20]; char *status, *filename; int len; if(now - start)avg = 1.0 * (pos - start_pos) / (now - start); eta = (total - pos) / avg; if(total)prcnt = 100.0 * pos / total; human_readable(pos, hpos, sizeof(hpos)); human_readable(total, htotal, sizeof(htotal)); human_readable(avg, havg, sizeof(havg)); len = asprintf(&status, "%s of %s (%.2f%%) at %s/s ETA: %s", hpos, htotal, prcnt, havg, print_time(eta)); if (len == -1) { return; } if(columns) { int required = strlen(name), available = columns - len - strlen("[] "); if(required > available) { if (asprintf(&filename, "...%s", name + required - available + 3) == -1) { return; } } else { filename = SMB_STRNDUP(name, available); } } else filename = SMB_STRDUP(name); fprintf(stderr, "\r[%s] %s", filename, status); free(filename); free(status); }
static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode, char *buf, int length) { static NTLMSSP_STATE *ntlmssp_state = NULL; DATA_BLOB request, reply; NTSTATUS nt_status; BOOL first = False; if (strlen(buf) < 2) { DEBUG(1, ("NTLMSSP query [%s] invalid", buf)); x_fprintf(x_stdout, "BH\n"); return; } if (strlen(buf) > 3) { request = base64_decode_data_blob(buf + 3); } else { request = data_blob(NULL, 0); } if (strncmp(buf, "PW ", 3) == 0) { /* We asked for a password and obviously got it :-) */ opt_password = SMB_STRNDUP((const char *)request.data, request.length); if (opt_password == NULL) { DEBUG(1, ("Out of memory\n")); x_fprintf(x_stdout, "BH\n"); data_blob_free(&request); return; } x_fprintf(x_stdout, "OK\n"); data_blob_free(&request); return; } if (opt_password == NULL) { /* Request a password from the calling process. After sending it, the calling process should retry asking for the negotiate. */ DEBUG(10, ("Requesting password\n")); x_fprintf(x_stdout, "PW\n"); return; } if (strncmp(buf, "YR", 2) == 0) { if (ntlmssp_state) ntlmssp_end(&ntlmssp_state); } else if (strncmp(buf, "TT", 2) == 0) { } else { DEBUG(1, ("NTLMSSP query [%s] invalid", buf)); x_fprintf(x_stdout, "BH\n"); return; } if (!ntlmssp_state) { if (!NT_STATUS_IS_OK(nt_status = ntlm_auth_start_ntlmssp_client(&ntlmssp_state))) { x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status)); return; } first = True; } DEBUG(10, ("got NTLMSSP packet:\n")); dump_data(10, (const char *)request.data, request.length); nt_status = ntlmssp_update(ntlmssp_state, request, &reply); if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { char *reply_base64 = base64_encode_data_blob(reply); if (first) { x_fprintf(x_stdout, "YR %s\n", reply_base64); } else { x_fprintf(x_stdout, "KK %s\n", reply_base64); } SAFE_FREE(reply_base64); data_blob_free(&reply); DEBUG(10, ("NTLMSSP challenge\n")); } else if (NT_STATUS_IS_OK(nt_status)) { char *reply_base64 = base64_encode_data_blob(reply); x_fprintf(x_stdout, "AF %s\n", reply_base64); SAFE_FREE(reply_base64); DEBUG(10, ("NTLMSSP OK!\n")); if (ntlmssp_state) ntlmssp_end(&ntlmssp_state); } else { x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status)); DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status))); if (ntlmssp_state) ntlmssp_end(&ntlmssp_state); } data_blob_free(&request); }
static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode, char *buf, int length) { static NTLMSSP_STATE *ntlmssp_state = NULL; DATA_BLOB request, reply; NTSTATUS nt_status; if (strlen(buf) < 2) { DEBUG(1, ("NTLMSSP query [%s] invalid", buf)); x_fprintf(x_stdout, "BH\n"); return; } if (strlen(buf) > 3) { request = base64_decode_data_blob(buf + 3); } else { request = data_blob(NULL, 0); } if ((strncmp(buf, "PW ", 3) == 0)) { /* The calling application wants us to use a local password (rather than winbindd) */ opt_password = SMB_STRNDUP((const char *)request.data, request.length); if (opt_password == NULL) { DEBUG(1, ("Out of memory\n")); x_fprintf(x_stdout, "BH\n"); data_blob_free(&request); return; } x_fprintf(x_stdout, "OK\n"); data_blob_free(&request); return; } if (strncmp(buf, "YR", 2) == 0) { if (ntlmssp_state) ntlmssp_end(&ntlmssp_state); } else if (strncmp(buf, "KK", 2) == 0) { } else { DEBUG(1, ("NTLMSSP query [%s] invalid", buf)); x_fprintf(x_stdout, "BH\n"); return; } if (!ntlmssp_state) { if (!NT_STATUS_IS_OK(nt_status = ntlm_auth_start_ntlmssp_server(&ntlmssp_state))) { x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status)); return; } } DEBUG(10, ("got NTLMSSP packet:\n")); dump_data(10, (const char *)request.data, request.length); nt_status = ntlmssp_update(ntlmssp_state, request, &reply); if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { char *reply_base64 = base64_encode_data_blob(reply); x_fprintf(x_stdout, "TT %s\n", reply_base64); SAFE_FREE(reply_base64); data_blob_free(&reply); DEBUG(10, ("NTLMSSP challenge\n")); } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) { x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status)); DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status))); ntlmssp_end(&ntlmssp_state); } else if (!NT_STATUS_IS_OK(nt_status)) { x_fprintf(x_stdout, "NA %s\n", nt_errstr(nt_status)); DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status))); } else { x_fprintf(x_stdout, "AF %s\n", (char *)ntlmssp_state->auth_context); DEBUG(10, ("NTLMSSP OK!\n")); } data_blob_free(&request); }
static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode, char *buf, int length) { DATA_BLOB request; SPNEGO_DATA spnego; ssize_t len; if (strlen(buf) <= 3) { DEBUG(1, ("SPNEGO query [%s] too short\n", buf)); x_fprintf(x_stdout, "BH\n"); return; } request = base64_decode_data_blob(buf+3); if (strncmp(buf, "PW ", 3) == 0) { /* We asked for a password and obviously got it :-) */ opt_password = SMB_STRNDUP((const char *)request.data, request.length); if (opt_password == NULL) { DEBUG(1, ("Out of memory\n")); x_fprintf(x_stdout, "BH\n"); data_blob_free(&request); return; } x_fprintf(x_stdout, "OK\n"); data_blob_free(&request); return; } if ( (strncmp(buf, "TT ", 3) != 0) && (strncmp(buf, "AF ", 3) != 0) && (strncmp(buf, "NA ", 3) != 0) ) { DEBUG(1, ("SPNEGO request [%s] invalid\n", buf)); x_fprintf(x_stdout, "BH\n"); data_blob_free(&request); return; } /* So we got a server challenge to generate a SPNEGO client-to-server request... */ len = read_spnego_data(request, &spnego); data_blob_free(&request); if (len == -1) { DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf)); x_fprintf(x_stdout, "BH\n"); return; } if (spnego.type == SPNEGO_NEG_TOKEN_INIT) { /* The server offers a list of mechanisms */ const char **mechType = (const char **)spnego.negTokenInit.mechTypes; while (*mechType != NULL) { #ifdef HAVE_KRB5 if ( (strcmp(*mechType, OID_KERBEROS5_OLD) == 0) || (strcmp(*mechType, OID_KERBEROS5) == 0) ) { if (manage_client_krb5_init(spnego)) goto out; } #endif if (strcmp(*mechType, OID_NTLMSSP) == 0) { if (manage_client_ntlmssp_init(spnego)) goto out; } mechType++; } DEBUG(1, ("Server offered no compatible mechanism\n")); x_fprintf(x_stdout, "BH\n"); return; } if (spnego.type == SPNEGO_NEG_TOKEN_TARG) { if (spnego.negTokenTarg.supportedMech == NULL) { /* On accept/reject Windows does not send the mechanism anymore. Handle that here and shut down the mechanisms. */ switch (spnego.negTokenTarg.negResult) { case SPNEGO_ACCEPT_COMPLETED: x_fprintf(x_stdout, "AF\n"); break; case SPNEGO_REJECT: x_fprintf(x_stdout, "NA\n"); break; default: DEBUG(1, ("Got a negTokenTarg with no mech and an " "unknown negResult: %d\n", spnego.negTokenTarg.negResult)); x_fprintf(x_stdout, "BH\n"); } ntlmssp_end(&client_ntlmssp_state); goto out; } if (strcmp(spnego.negTokenTarg.supportedMech, OID_NTLMSSP) == 0) { manage_client_ntlmssp_targ(spnego); goto out; } #if HAVE_KRB5 if (strcmp(spnego.negTokenTarg.supportedMech, OID_KERBEROS5_OLD) == 0) { manage_client_krb5_targ(spnego); goto out; } #endif } DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf)); x_fprintf(x_stdout, "BH\n"); return; out: free_spnego_data(&spnego); return; }
/* search for a credcache that looks like a likely candidate */ static char * find_krb5_cc(const char *dirname, uid_t uid) { struct dirent **namelist; struct stat sbuf; char ccname[MAX_CCNAME_LEN], *credpath, *best_cache = NULL; int i, n; time_t cred_time, best_time = 0; n = scandir(dirname, &namelist, krb5cc_filter, NULL); if (n < 0) { syslog(LOG_DEBUG, "%s: scandir error on directory '%s': %s", __func__, dirname, strerror(errno)); return NULL; } for (i = 0; i < n; i++) { snprintf(ccname, sizeof(ccname), "FILE:%s/%s", dirname, namelist[i]->d_name); credpath = ccname + 5; syslog(LOG_DEBUG, "%s: considering %s", __func__, credpath); if (lstat(credpath, &sbuf)) { syslog(LOG_DEBUG, "%s: stat error on '%s': %s", __func__, credpath, strerror(errno)); free(namelist[i]); continue; } if (sbuf.st_uid != uid) { syslog(LOG_DEBUG, "%s: %s is owned by %u, not %u", __func__, credpath, sbuf.st_uid, uid); free(namelist[i]); continue; } if (!S_ISREG(sbuf.st_mode)) { syslog(LOG_DEBUG, "%s: %s is not a regular file", __func__, credpath); free(namelist[i]); continue; } if (!(cred_time = get_tgt_time(ccname))) { syslog(LOG_DEBUG, "%s: %s is not a valid credcache.", __func__, ccname); free(namelist[i]); continue; } if (cred_time <= best_time) { syslog(LOG_DEBUG, "%s: %s expires sooner than current " "best.", __func__, ccname); free(namelist[i]); continue; } syslog(LOG_DEBUG, "%s: %s is valid ccache", __func__, ccname); free(best_cache); best_cache = SMB_STRNDUP(ccname, MAX_CCNAME_LEN); best_time = cred_time; free(namelist[i]); } free(namelist); return best_cache; }