static void my_make_nmb_name( struct nmb_name *n, const char *name, int type) { fstring unix_name; memset( (char *)n, '\0', sizeof(struct nmb_name) ); fstrcpy(unix_name, name); strupper_m(unix_name); push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE); n->name_type = (unsigned int)type & 0xFF; push_ascii(n->scope, lp_netbios_scope(), 64, STR_TERMINATE); }
size_t push_string_fn(const char *function, unsigned int line, const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags) { #ifdef DEVELOPER /* We really need to zero fill here, not clobber * region, as we want to ensure that valgrind thinks * all of the outgoing buffer has been written to * so a send() or write() won't trap an error. * JRA. */ #if 0 if (dest_len != (size_t)-1) clobber_region(function, line, dest, dest_len); #else if (dest_len != (size_t)-1) memset(dest, '\0', dest_len); #endif #endif if (!(flags & STR_ASCII) && \ ((flags & STR_UNICODE || \ (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) { return push_ucs2(base_ptr, dest, src, dest_len, flags); } return push_ascii(dest, src, dest_len, flags); }
static void send_election_dgram(struct subnet_record *subrec, const char *workgroup_name, uint32 criterion, int timeup,const char *server_name) { char outbuf[1024]; unstring srv_name; char *p; DEBUG(2,("send_election_dgram: Sending election packet for workgroup %s on subnet %s\n", workgroup_name, subrec->subnet_name )); memset(outbuf,'\0',sizeof(outbuf)); p = outbuf; SCVAL(p,0,ANN_Election); /* Election opcode. */ p++; SCVAL(p,0,((criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION)); SIVAL(p,1,criterion); SIVAL(p,5,timeup*1000); /* ms - Despite what the spec says. */ p += 13; unstrcpy(srv_name, server_name); if (!strupper_m(srv_name)) { DEBUG(2,("strupper_m failed for %s\n", srv_name)); return; } /* The following call does UNIX -> DOS charset conversion. */ push_ascii(p, srv_name, sizeof(outbuf)-PTR_DIFF(p,outbuf)-1, STR_TERMINATE); p = skip_string(outbuf,sizeof(outbuf),p); send_mailslot(False, BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf), lp_netbios_name(), 0, workgroup_name, 0x1e, subrec->bcast_ip, subrec->myip, DGRAM_PORT); }
static void announce_local_master_browser_to_domain_master_browser( struct work_record *work) { char outbuf[1024]; unstring myname; unstring dmb_name; char *p; if(ismyip_v4(work->dmb_addr)) { if( DEBUGLVL( 2 ) ) { dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" ); dbgtext( "We are both a domain and a local master browser for " ); dbgtext( "workgroup %s. ", work->work_group ); dbgtext( "Do not announce to ourselves.\n" ); } return; } memset(outbuf,'\0',sizeof(outbuf)); p = outbuf; SCVAL(p,0,ANN_MasterAnnouncement); p++; unstrcpy(myname, lp_netbios_name()); if (!strupper_m(myname)) { DEBUG(2,("strupper_m %s failed\n", myname)); return; } myname[15]='\0'; /* The call below does CH_UNIX -> CH_DOS conversion. JRA */ push_ascii(p, myname, sizeof(outbuf)-PTR_DIFF(p,outbuf)-1, STR_TERMINATE); p = skip_string(outbuf,sizeof(outbuf),p); if( DEBUGLVL( 4 ) ) { dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" ); dbgtext( "Sending local master announce to " ); dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name), work->work_group ); } /* Target name for send_mailslot must be in UNIX charset. */ pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name); send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf), lp_netbios_name(), 0x0, dmb_name, 0x0, work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT); }
BOOL E_deshash(const char *passwd, uchar p16[16]) { BOOL ret = True; fstring dospwd; ZERO_STRUCT(dospwd); /* Password must be converted to DOS charset - null terminated, uppercase. */ push_ascii(dospwd, passwd, sizeof(dospwd), STR_UPPER|STR_TERMINATE); /* Only the fisrt 14 chars are considered, password need not be null terminated. */ E_P16((const unsigned char *)dospwd, p16); if (strlen(dospwd) > 14) { ret = False; } ZERO_STRUCT(dospwd); return ret; }
size_t push_ascii_pstring(void *dest, const char *src) { return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE); }
bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32_t stype, void (*fn)(const char *, uint32_t, const char *, void *), void *state) { char *rparam = NULL; char *rdata = NULL; char *rdata_end = NULL; unsigned int rdrcnt,rprcnt; char *p; char param[1024]; int uLevel = 1; size_t len; uint32_t func = RAP_NetServerEnum2; char *last_entry = NULL; int total_cnt = 0; int return_cnt = 0; int res; errno = 0; /* reset */ /* * This may take more than one transaction, so we should loop until * we no longer get a more data to process or we have all of the * items. */ do { /* send a SMBtrans command with api NetServerEnum */ p = param; SIVAL(p,0,func); /* api number */ p += 2; if (func == RAP_NetServerEnum3) { strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param)); } else { strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param)); } p = skip_string(param, sizeof(param), p); strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param)); p = skip_string(param, sizeof(param), p); SSVAL(p,0,uLevel); SSVAL(p,2,CLI_BUFFER_SIZE); p += 4; SIVAL(p,0,stype); p += 4; /* If we have more data, tell the server where * to continue from. */ len = push_ascii(p, workgroup, sizeof(param) - PTR_DIFF(p,param) - 1, STR_TERMINATE|STR_UPPER); if (len == 0) { SAFE_FREE(last_entry); return false; } p += len; if (func == RAP_NetServerEnum3) { len = push_ascii(p, last_entry ? last_entry : "", sizeof(param) - PTR_DIFF(p,param) - 1, STR_TERMINATE); if (len == 0) { SAFE_FREE(last_entry); return false; } p += len; } /* Next time through we need to use the continue api */ func = RAP_NetServerEnum3; if (!cli_api(cli, param, PTR_DIFF(p,param), 8, /* params, length, max */ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */ &rparam, &rprcnt, /* return params, return size */ &rdata, &rdrcnt)) { /* return data, return size */ /* break out of the loop on error */ res = -1; break; } rdata_end = rdata + rdrcnt; res = rparam ? SVAL(rparam,0) : -1; if (res == 0 || res == ERRmoredata || (res != -1 && cli_errno(cli) == 0)) { char *sname = NULL; int i, count; int converter=SVAL(rparam,2); /* Get the number of items returned in this buffer */ count = SVAL(rparam, 4); /* The next field contains the number of items left, * including those returned in this buffer. So the * first time through this should contain all of the * entries. */ if (total_cnt == 0) { total_cnt = SVAL(rparam, 6); } /* Keep track of how many we have read */ return_cnt += count; p = rdata; /* The last name in the previous NetServerEnum reply is * sent back to server in the NetServerEnum3 request * (last_entry). The next reply should repeat this entry * as the first element. We have no proof that this is * always true, but from traces that seems to be the * behavior from Window Servers. So first lets do a lot * of checking, just being paranoid. If the string * matches then we already saw this entry so skip it. * * NOTE: sv1_name field must be null terminated and has * a max size of 16 (NetBIOS Name). */ if (last_entry && count && p && (strncmp(last_entry, p, 16) == 0)) { count -= 1; /* Skip this entry */ return_cnt = -1; /* Not part of total, so don't count. */ p = rdata + 26; /* Skip the whole record */ } for (i = 0; i < count; i++, p += 26) { int comment_offset; const char *cmnt; const char *p1; char *s1, *s2; TALLOC_CTX *frame = talloc_stackframe(); uint32_t entry_stype; if (p + 26 > rdata_end) { TALLOC_FREE(frame); break; } sname = p; comment_offset = (IVAL(p,22) & 0xFFFF)-converter; cmnt = comment_offset?(rdata+comment_offset):""; if (comment_offset < 0 || comment_offset >= (int)rdrcnt) { TALLOC_FREE(frame); continue; } /* Work out the comment length. */ for (p1 = cmnt, len = 0; *p1 && p1 < rdata_end; len++) p1++; if (!*p1) { len++; } entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY; pull_string_talloc(frame,rdata,0, &s1,sname,16,STR_ASCII); pull_string_talloc(frame,rdata,0, &s2,cmnt,len,STR_ASCII); if (!s1 || !s2) { TALLOC_FREE(frame); continue; } fn(s1, entry_stype, s2, state); TALLOC_FREE(frame); } /* We are done with the old last entry, so now we can free it */ if (last_entry) { SAFE_FREE(last_entry); /* This will set it to null */ } /* We always make a copy of the last entry if we have one */ if (sname) { last_entry = smb_xstrdup(sname); } /* If we have more data, but no last entry then error out */ if (!last_entry && (res == ERRmoredata)) { errno = EINVAL; res = 0; } } SAFE_FREE(rparam); SAFE_FREE(rdata); } while ((res == ERRmoredata) && (total_cnt > return_cnt)); SAFE_FREE(rparam); SAFE_FREE(rdata); SAFE_FREE(last_entry); if (res == -1) { errno = cli_errno(cli); } else { if (!return_cnt) { /* this is a very special case, when the domain master for the work group isn't part of the work group itself, there is something wild going on */ errno = ENOENT; } } return(return_cnt > 0); }
/**************************************************************************** call a NetServerEnum for the specified workgroup and servertype mask. This function then calls the specified callback function for each name returned. The callback function takes 4 arguments: the machine name, the server type, the comment and a state pointer. ****************************************************************************/ BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype, void (*fn)(const char *, uint32, const char *, void *), void *state) { char *rparam = NULL; char *rdata = NULL; unsigned int rdrcnt,rprcnt; char *p; pstring param; int uLevel = 1; int count = -1; errno = 0; /* reset */ /* send a SMBtrans command with api NetServerEnum */ p = param; SSVAL(p,0,0x68); /* api number */ p += 2; pstrcpy_base(p,"WrLehDz", param); p = skip_string(p,1); pstrcpy_base(p,"B16BBDz", param); p = skip_string(p,1); SSVAL(p,0,uLevel); SSVAL(p,2,CLI_BUFFER_SIZE); p += 4; SIVAL(p,0,stype); p += 4; p += push_ascii(p, workgroup, sizeof(pstring)-PTR_DIFF(p,param)-1, STR_TERMINATE|STR_UPPER); if (cli_api(cli, param, PTR_DIFF(p,param), 8, /* params, length, max */ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */ &rparam, &rprcnt, /* return params, return size */ &rdata, &rdrcnt /* return data, return size */ )) { int res = rparam? SVAL(rparam,0) : -1; if (res == 0 || res == ERRmoredata) { int i; int converter=SVAL(rparam,2); count=SVAL(rparam,4); p = rdata; for (i = 0;i < count;i++, p += 26) { char *sname = p; int comment_offset = (IVAL(p,22) & 0xFFFF)-converter; const char *cmnt = comment_offset?(rdata+comment_offset):""; pstring s1, s2; if (comment_offset < 0 || comment_offset > (int)rdrcnt) continue; stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY; pull_ascii_pstring(s1, sname); pull_ascii_pstring(s2, cmnt); fn(s1, stype, s2, state); } } } SAFE_FREE(rparam); SAFE_FREE(rdata); if (count < 0) { errno = cli_errno(cli); } else { if (!count) { /* this is a very special case, when the domain master for the work group isn't part of the work group itself, there is something wild going on */ errno = ENOENT; } } return(count > 0); }
static bool do_winbind_offline(struct tevent_context *ev_ctx, struct messaging_context *msg_ctx, const struct server_id pid, const int argc, const char **argv) { TDB_CONTEXT *tdb; bool ret = False; int retry = 0; char *db_path; if (argc != 1) { fprintf(stderr, "Usage: smbcontrol winbindd offline\n"); return False; } db_path = state_path("winbindd_cache.tdb"); if (db_path == NULL) { return false; } /* Create an entry in the winbindd_cache tdb to tell a later starting winbindd that we're offline. We may actually create it here... */ tdb = tdb_open_log(db_path, WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, TDB_DEFAULT|TDB_INCOMPATIBLE_HASH /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600); if (!tdb) { fprintf(stderr, "Cannot open the tdb %s for writing.\n", db_path); TALLOC_FREE(db_path); return False; } TALLOC_FREE(db_path); /* There's a potential race condition that if a child winbindd detects a domain is online at the same time we're trying to tell it to go offline that it might delete the record we add between us adding it and sending the message. Minimize this by retrying up to 5 times. */ for (retry = 0; retry < 5; retry++) { uint8_t buf[4]; TDB_DATA d = { .dptr = buf, .dsize = sizeof(buf) }; SIVAL(buf, 0, time(NULL)); tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT); ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE, NULL, 0); /* Check that the entry "WINBINDD_OFFLINE" still exists. */ d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" ); if (!d.dptr || d.dsize != 4) { SAFE_FREE(d.dptr); DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n")); } else { SAFE_FREE(d.dptr); break; } } tdb_close(tdb); return ret; } static bool do_winbind_onlinestatus(struct tevent_context *ev_ctx, struct messaging_context *msg_ctx, const struct server_id pid, const int argc, const char **argv) { struct server_id myid; myid = messaging_server_id(msg_ctx); if (argc != 1) { fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n"); return False; } messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS, print_pid_string_cb); if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid, sizeof(myid))) return False; wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0); /* No replies were received within the timeout period */ if (num_replies == 0) printf("No replies received\n"); messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL); return num_replies; } static bool do_dump_event_list(struct tevent_context *ev_ctx, struct messaging_context *msg_ctx, const struct server_id pid, const int argc, const char **argv) { if (argc != 1) { fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n"); return False; } return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0); } static bool do_winbind_dump_domain_list(struct tevent_context *ev_ctx, struct messaging_context *msg_ctx, const struct server_id pid, const int argc, const char **argv) { const char *domain = NULL; int domain_len = 0; struct server_id myid; uint8_t *buf = NULL; int buf_len = 0; myid = messaging_server_id(msg_ctx); if (argc < 1 || argc > 2) { fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list " "<domain>\n"); return false; } if (argc == 2) { domain = argv[1]; domain_len = strlen(argv[1]) + 1; } messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST, print_pid_string_cb); buf_len = sizeof(myid)+domain_len; buf = SMB_MALLOC_ARRAY(uint8_t, buf_len); if (!buf) { return false; } memcpy(buf, &myid, sizeof(myid)); memcpy(&buf[sizeof(myid)], domain, domain_len); if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST, buf, buf_len)) { SAFE_FREE(buf); return false; } wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0); /* No replies were received within the timeout period */ SAFE_FREE(buf); if (num_replies == 0) { printf("No replies received\n"); } messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL); return num_replies; } static void winbind_validate_cache_cb(struct messaging_context *msg, void *private_data, uint32_t msg_type, struct server_id pid, DATA_BLOB *data) { struct server_id_buf src_string; printf("Winbindd cache is %svalid. (answer from pid %s)\n", (*(data->data) == 0 ? "" : "NOT "), server_id_str_buf(pid, &src_string)); num_replies++; } static bool do_winbind_validate_cache(struct tevent_context *ev_ctx, struct messaging_context *msg_ctx, const struct server_id pid, const int argc, const char **argv) { struct server_id myid; myid = messaging_server_id(msg_ctx); if (argc != 1) { fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n"); return False; } messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE, winbind_validate_cache_cb); if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid, sizeof(myid))) { return False; } wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0); if (num_replies == 0) { printf("No replies received\n"); } messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL); return num_replies; } static bool do_reload_config(struct tevent_context *ev_ctx, struct messaging_context *msg_ctx, const struct server_id pid, const int argc, const char **argv) { if (argc != 1) { fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n"); return False; } return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0); } static bool do_reload_printers(struct tevent_context *ev_ctx, struct messaging_context *msg_ctx, const struct server_id pid, const int argc, const char **argv) { if (argc != 1) { fprintf(stderr, "Usage: smbcontrol <dest> reload-printers\n"); return False; } return send_message(msg_ctx, pid, MSG_PRINTER_PCAP, NULL, 0); } static void my_make_nmb_name( struct nmb_name *n, const char *name, int type) { fstring unix_name; memset( (char *)n, '\0', sizeof(struct nmb_name) ); fstrcpy(unix_name, name); (void)strupper_m(unix_name); push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE); n->name_type = (unsigned int)type & 0xFF; push_ascii(n->scope, lp_netbios_scope(), 64, STR_TERMINATE); }