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 8350 : bool server_id_same_process(const struct server_id *p1,
28 : const struct server_id *p2)
29 : {
30 8350 : return ((p1->pid == p2->pid) && (p1->vnn == p2->vnn));
31 : }
32 :
33 351338 : int server_id_cmp(const struct server_id *p1, const struct server_id *p2)
34 : {
35 351338 : if (p1->vnn != p2->vnn) {
36 52 : return (p1->vnn < p2->vnn) ? -1 : 1;
37 : }
38 351286 : if (p1->pid != p2->pid) {
39 266476 : return (p1->pid < p2->pid) ? -1 : 1;
40 : }
41 84810 : if (p1->task_id != p2->task_id) {
42 0 : return (p1->task_id < p2->task_id) ? -1 : 1;
43 : }
44 84810 : if (p1->unique_id != p2->unique_id) {
45 0 : return (p1->unique_id < p2->unique_id) ? -1 : 1;
46 : }
47 84810 : return 0;
48 : }
49 :
50 332839 : bool server_id_equal(const struct server_id *p1, const struct server_id *p2)
51 : {
52 332839 : int cmp = server_id_cmp(p1, p2);
53 332839 : return (cmp == 0);
54 : }
55 :
56 192067 : char *server_id_str_buf(struct server_id id, struct server_id_buf *dst)
57 : {
58 192067 : if (server_id_is_disconnected(&id)) {
59 0 : strlcpy(dst->buf, "disconnected", sizeof(dst->buf));
60 192067 : } else if ((id.vnn == NONCLUSTER_VNN) && (id.task_id == 0)) {
61 68638 : snprintf(dst->buf, sizeof(dst->buf), "%llu",
62 68638 : (unsigned long long)id.pid);
63 123429 : } else if (id.vnn == NONCLUSTER_VNN) {
64 123429 : snprintf(dst->buf, sizeof(dst->buf), "%llu.%u",
65 123429 : (unsigned long long)id.pid, (unsigned)id.task_id);
66 0 : } else if (id.task_id == 0) {
67 0 : snprintf(dst->buf, sizeof(dst->buf), "%u:%llu",
68 0 : (unsigned)id.vnn, (unsigned long long)id.pid);
69 : } else {
70 0 : 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 192067 : return dst->buf;
76 : }
77 :
78 97752 : size_t server_id_str_buf_unique(struct server_id id, char *buf, size_t buflen)
79 : {
80 : struct server_id_buf idbuf;
81 : char unique_buf[21]; /* 2^64 is 18446744073709551616, 20 chars */
82 : size_t idlen, unique_len, needed;
83 :
84 97752 : server_id_str_buf(id, &idbuf);
85 :
86 97752 : idlen = strlen(idbuf.buf);
87 97752 : unique_len = snprintf(unique_buf, sizeof(unique_buf), "%"PRIu64,
88 : id.unique_id);
89 97752 : needed = idlen + unique_len + 2;
90 :
91 97752 : if (buflen >= needed) {
92 48876 : memcpy(buf, idbuf.buf, idlen);
93 48876 : buf[idlen] = '/';
94 48876 : memcpy(buf + idlen + 1, unique_buf, unique_len+1);
95 : }
96 :
97 97752 : return needed;
98 : }
99 :
100 31645 : struct server_id server_id_from_string(uint32_t local_vnn,
101 : const char *pid_string)
102 : {
103 31645 : struct server_id templ = {
104 : .vnn = NONCLUSTER_VNN, .pid = UINT64_MAX
105 : };
106 : struct server_id result;
107 : 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 31645 : result = templ;
117 31645 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32"/%"SCNu64,
118 : &result.vnn, &result.pid, &result.task_id,
119 : &result.unique_id);
120 31645 : if (ret == 4) {
121 0 : return result;
122 : }
123 :
124 31645 : result = templ;
125 31645 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32,
126 : &result.vnn, &result.pid, &result.task_id);
127 31645 : if (ret == 3) {
128 0 : return result;
129 : }
130 :
131 31645 : result = templ;
132 31645 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64"/%"SCNu64,
133 : &result.vnn, &result.pid, &result.unique_id);
134 31645 : if (ret == 3) {
135 0 : return result;
136 : }
137 :
138 31645 : result = templ;
139 31645 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64,
140 : &result.vnn, &result.pid);
141 31645 : if (ret == 2) {
142 0 : return result;
143 : }
144 :
145 31645 : result = templ;
146 31645 : ret = sscanf(pid_string, "%"SCNu64".%"SCNu32"/%"SCNu64,
147 : &result.pid, &result.task_id, &result.unique_id);
148 31645 : if (ret == 3) {
149 1982 : result.vnn = local_vnn;
150 1982 : return result;
151 : }
152 :
153 29663 : result = templ;
154 29663 : ret = sscanf(pid_string, "%"SCNu64".%"SCNu32,
155 : &result.pid, &result.task_id);
156 29663 : if (ret == 2) {
157 0 : result.vnn = local_vnn;
158 0 : return result;
159 : }
160 :
161 29663 : result = templ;
162 29663 : ret = sscanf(pid_string, "%"SCNu64"/%"SCNu64,
163 : &result.pid, &result.unique_id);
164 29663 : if (ret == 2) {
165 29561 : result.vnn = local_vnn;
166 29561 : return result;
167 : }
168 :
169 102 : result = templ;
170 102 : ret = sscanf(pid_string, "%"SCNu64, &result.pid);
171 102 : if (ret == 1) {
172 84 : result.vnn = local_vnn;
173 84 : return result;
174 : }
175 :
176 18 : if (strcmp(pid_string, "disconnected") == 0) {
177 0 : server_id_set_disconnected(&result);
178 0 : return result;
179 : }
180 :
181 18 : 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 249724 : void server_id_set_disconnected(struct server_id *id)
189 : {
190 249724 : *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 249724 : }
197 :
198 : /**
199 : * check whether a serverid is the special placeholder for
200 : * a disconnected client
201 : */
202 228337 : bool server_id_is_disconnected(const struct server_id *id)
203 : {
204 : struct server_id dis;
205 :
206 228337 : SMB_ASSERT(id != NULL);
207 :
208 228337 : server_id_set_disconnected(&dis);
209 :
210 228337 : return server_id_equal(id, &dis);
211 : }
212 :
213 180866 : void server_id_put(uint8_t buf[SERVER_ID_BUF_LENGTH],
214 : const struct server_id id)
215 : {
216 180866 : SBVAL(buf, 0, id.pid);
217 180866 : SIVAL(buf, 8, id.task_id);
218 180866 : SIVAL(buf, 12, id.vnn);
219 180866 : SBVAL(buf, 16, id.unique_id);
220 180866 : }
221 :
222 502979 : void server_id_get(struct server_id *id,
223 : const uint8_t buf[SERVER_ID_BUF_LENGTH])
224 : {
225 502979 : id->pid = BVAL(buf, 0);
226 502979 : id->task_id = IVAL(buf, 8);
227 502979 : id->vnn = IVAL(buf, 12);
228 502979 : id->unique_id = BVAL(buf, 16);
229 502979 : }
|