Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Samba utility functions
4 : Copyright (C) Andrew Bartlett 2011
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "replace.h"
21 : #include "lib/util/debug.h"
22 : #include "lib/util/fault.h"
23 : #include "lib/util/server_id.h"
24 : #include "lib/util/byteorder.h"
25 : #include "librpc/gen_ndr/server_id.h"
26 :
27 99148 : bool server_id_same_process(const struct server_id *p1,
28 : const struct server_id *p2)
29 : {
30 99148 : return ((p1->pid == p2->pid) && (p1->vnn == p2->vnn));
31 : }
32 :
33 3008935 : int server_id_cmp(const struct server_id *p1, const struct server_id *p2)
34 : {
35 3008935 : if (p1->vnn != p2->vnn) {
36 1214 : return (p1->vnn < p2->vnn) ? -1 : 1;
37 : }
38 3007721 : if (p1->pid != p2->pid) {
39 1432522 : return (p1->pid < p2->pid) ? -1 : 1;
40 : }
41 1575199 : if (p1->task_id != p2->task_id) {
42 0 : return (p1->task_id < p2->task_id) ? -1 : 1;
43 : }
44 1575199 : if (p1->unique_id != p2->unique_id) {
45 0 : return (p1->unique_id < p2->unique_id) ? -1 : 1;
46 : }
47 1571945 : return 0;
48 : }
49 :
50 2513292 : bool server_id_equal(const struct server_id *p1, const struct server_id *p2)
51 : {
52 2513292 : int cmp = server_id_cmp(p1, p2);
53 2513292 : return (cmp == 0);
54 : }
55 :
56 258096 : char *server_id_str_buf(struct server_id id, struct server_id_buf *dst)
57 : {
58 258096 : if (server_id_is_disconnected(&id)) {
59 0 : strlcpy(dst->buf, "disconnected", sizeof(dst->buf));
60 258096 : } else if ((id.vnn == NONCLUSTER_VNN) && (id.task_id == 0)) {
61 88020 : snprintf(dst->buf, sizeof(dst->buf), "%llu",
62 83752 : (unsigned long long)id.pid);
63 174344 : } else if (id.vnn == NONCLUSTER_VNN) {
64 178612 : snprintf(dst->buf, sizeof(dst->buf), "%llu.%u",
65 174344 : (unsigned long long)id.pid, (unsigned)id.task_id);
66 0 : } else if (id.task_id == 0) {
67 4268 : snprintf(dst->buf, sizeof(dst->buf), "%u:%llu",
68 0 : (unsigned)id.vnn, (unsigned long long)id.pid);
69 : } else {
70 4268 : snprintf(dst->buf, sizeof(dst->buf), "%u:%llu.%u",
71 0 : (unsigned)id.vnn,
72 0 : (unsigned long long)id.pid,
73 0 : (unsigned)id.task_id);
74 : }
75 258096 : return dst->buf;
76 : }
77 :
78 128164 : size_t server_id_str_buf_unique(struct server_id id, char *buf, size_t buflen)
79 : {
80 920 : struct server_id_buf idbuf;
81 920 : char unique_buf[21]; /* 2^64 is 18446744073709551616, 20 chars */
82 920 : size_t idlen, unique_len, needed;
83 :
84 128164 : server_id_str_buf(id, &idbuf);
85 :
86 128164 : idlen = strlen(idbuf.buf);
87 128164 : unique_len = snprintf(unique_buf, sizeof(unique_buf), "%"PRIu64,
88 : id.unique_id);
89 128164 : needed = idlen + unique_len + 2;
90 :
91 128164 : if (buflen >= needed) {
92 64082 : memcpy(buf, idbuf.buf, idlen);
93 64082 : buf[idlen] = '/';
94 64082 : memcpy(buf + idlen + 1, unique_buf, unique_len+1);
95 : }
96 :
97 128164 : return needed;
98 : }
99 :
100 58863 : struct server_id server_id_from_string(uint32_t local_vnn,
101 : const char *pid_string)
102 : {
103 58863 : struct server_id templ = {
104 : .vnn = NONCLUSTER_VNN, .pid = UINT64_MAX
105 : };
106 1774 : struct server_id result;
107 1774 : int ret;
108 :
109 : /*
110 : * We accept various forms with 1, 2 or 3 component forms
111 : * because the server_id_str_buf() can print different forms, and
112 : * we want backwards compatibility for scripts that may call
113 : * smbclient.
114 : */
115 :
116 58863 : result = templ;
117 58863 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32"/%"SCNu64,
118 : &result.vnn, &result.pid, &result.task_id,
119 : &result.unique_id);
120 58863 : if (ret == 4) {
121 0 : return result;
122 : }
123 :
124 58863 : result = templ;
125 58863 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32,
126 : &result.vnn, &result.pid, &result.task_id);
127 58863 : if (ret == 3) {
128 0 : return result;
129 : }
130 :
131 58863 : result = templ;
132 58863 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64"/%"SCNu64,
133 : &result.vnn, &result.pid, &result.unique_id);
134 58863 : if (ret == 3) {
135 0 : return result;
136 : }
137 :
138 58863 : result = templ;
139 58863 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64,
140 : &result.vnn, &result.pid);
141 58863 : if (ret == 2) {
142 4 : return result;
143 : }
144 :
145 58859 : result = templ;
146 58859 : ret = sscanf(pid_string, "%"SCNu64".%"SCNu32"/%"SCNu64,
147 : &result.pid, &result.task_id, &result.unique_id);
148 58859 : if (ret == 3) {
149 4159 : result.vnn = local_vnn;
150 4159 : return result;
151 : }
152 :
153 54700 : result = templ;
154 54700 : ret = sscanf(pid_string, "%"SCNu64".%"SCNu32,
155 : &result.pid, &result.task_id);
156 54700 : if (ret == 2) {
157 0 : result.vnn = local_vnn;
158 0 : return result;
159 : }
160 :
161 54700 : result = templ;
162 54700 : ret = sscanf(pid_string, "%"SCNu64"/%"SCNu64,
163 : &result.pid, &result.unique_id);
164 54700 : if (ret == 2) {
165 54500 : result.vnn = local_vnn;
166 54500 : return result;
167 : }
168 :
169 200 : result = templ;
170 200 : ret = sscanf(pid_string, "%"SCNu64, &result.pid);
171 200 : if (ret == 1) {
172 154 : result.vnn = local_vnn;
173 154 : return result;
174 : }
175 :
176 46 : if (strcmp(pid_string, "disconnected") == 0) {
177 0 : server_id_set_disconnected(&result);
178 0 : return result;
179 : }
180 :
181 46 : return templ;
182 : }
183 :
184 : /**
185 : * Set the serverid to the special value that represents a disconnected
186 : * client for (e.g.) durable handles.
187 : */
188 1461873 : void server_id_set_disconnected(struct server_id *id)
189 : {
190 1461873 : *id = (struct server_id) {
191 : .pid = UINT64_MAX,
192 : .task_id = UINT32_MAX,
193 : .vnn = NONCLUSTER_VNN,
194 : .unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY,
195 : };
196 1461873 : }
197 :
198 : /**
199 : * check whether a serverid is the special placeholder for
200 : * a disconnected client
201 : */
202 869644 : bool server_id_is_disconnected(const struct server_id *id)
203 : {
204 6004 : struct server_id dis;
205 :
206 869644 : SMB_ASSERT(id != NULL);
207 :
208 869644 : server_id_set_disconnected(&dis);
209 :
210 869644 : return server_id_equal(id, &dis);
211 : }
212 :
213 2188363 : void server_id_put(uint8_t buf[SERVER_ID_BUF_LENGTH],
214 : const struct server_id id)
215 : {
216 2188363 : SBVAL(buf, 0, id.pid);
217 2188363 : SIVAL(buf, 8, id.task_id);
218 2188363 : SIVAL(buf, 12, id.vnn);
219 2188363 : SBVAL(buf, 16, id.unique_id);
220 2188363 : }
221 :
222 2319251 : void server_id_get(struct server_id *id,
223 : const uint8_t buf[SERVER_ID_BUF_LENGTH])
224 : {
225 2319251 : id->pid = BVAL(buf, 0);
226 2319251 : id->task_id = IVAL(buf, 8);
227 2319251 : id->vnn = IVAL(buf, 12);
228 2319251 : id->unique_id = BVAL(buf, 16);
229 2319251 : }
|